00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00024 #include <lib3ds.h>
00025 #include <stdio.h>
00026 #include <stdlib.h>
00027 #include <string.h>
00028 #include <assert.h>
00029 #include <math.h>
00030 #include <ctype.h>
00031 #include <string.h>
00032
00033 #ifdef _MSC_VER
00034 #pragma warning ( disable : 4996 )
00035 #endif
00036
00037
00038 static void
00039 help() {
00040 fprintf(stderr,
00041 "Syntax: 3ds2obj 3ds-file [obj-file] [mtl-file]\n"
00042 );
00043 exit(1);
00044 }
00045
00046
00047 static const char* input = 0;
00048 static char* obj_file = 0;
00049 static char* mtl_file = 0;
00050 static int max_vertices = 0;
00051 static int max_texcos = 0;
00052 static int max_normals = 0;
00053
00054
00055 void parse_args(int argc, char **argv) {
00056 int i;
00057
00058 for (i = 1; i < argc; ++i) {
00059 if (argv[i][0] == '-') {
00060 if ((strcmp(argv[i], "-h") == 0) || (strcmp(argv[i], "--help") == 0)) {
00061 help();
00062 } else {
00063 help();
00064 }
00065 } else {
00066 if (!input) {
00067 input = argv[i];
00068 } else if (!obj_file) {
00069 obj_file = argv[i];
00070 } else if (!mtl_file) {
00071 mtl_file = argv[i];
00072 } else {
00073 help();
00074 }
00075 }
00076 }
00077
00078 if (input) {
00079 size_t input_len = strlen(input);
00080 if ((input_len > 4) && (strcmp(input + input_len - 4, ".3ds") == 0)) {
00081 if (!obj_file) {
00082 obj_file = (char*)malloc(sizeof(char*) * (input_len + 1));
00083 strcpy(obj_file, input);
00084 strcpy(obj_file + input_len - 4, ".obj");
00085 }
00086 if (!mtl_file) {
00087 mtl_file = (char*)malloc(sizeof(char*) * (input_len + 1));
00088 strcpy(mtl_file, input);
00089 strcpy(mtl_file + input_len - 4, ".mtl");
00090 }
00091 }
00092 }
00093
00094 if (!input || !obj_file) {
00095 help();
00096 }
00097 }
00098
00099
00100 void write_mtl(FILE *mtl, Lib3dsFile *f) {
00101 int i, j;
00102
00103 fprintf(mtl, "# Wavefront material file\n");
00104 fprintf(mtl, "# Converted by 3ds2obj\n");
00105 fprintf(mtl, "# http://www.lib3ds.org\n\n");
00106
00107 {
00108 int unique = 1;
00109 for (i = 0; i < f->nmaterials; ++i) {
00110 char *p;
00111 for (p = f->materials[i]->name; *p; ++p) {
00112 if (!isalnum(*p) && (*p != '_')) *p = '_';
00113 }
00114
00115 for (j = 0; j < i; ++j) {
00116 if (strcmp(f->materials[i]->name, f->materials[j]->name) == 0) {
00117 unique = 0;
00118 break;
00119 }
00120 }
00121 if (!unique)
00122 break;
00123 }
00124 if (!unique) {
00125 for (i = 0; i < f->nmaterials; ++i) {
00126 sprintf(f->materials[i]->name, "mat_%d", i);
00127 }
00128 }
00129 }
00130
00131 for (i = 0; i < f->nmaterials; ++i) {
00132 Lib3dsMaterial *m = f->materials[i];
00133 fprintf(mtl, "newmtl %s\n", m->name);
00134 fprintf(mtl, "Ka %f %f %f\n", m->ambient[0], m->ambient[1], m->ambient[2]);
00135 fprintf(mtl, "Kd %f %f %f\n", m->diffuse[0], m->diffuse[1], m->diffuse[2]);
00136 fprintf(mtl, "Ks %f %f %f\n", m->specular[0], m->specular[1], m->specular[2]);
00137 fprintf(mtl, "illum 2\n");
00138 fprintf(mtl, "Ns %f\n", pow(2, 10 * m->shininess + 1));
00139 fprintf(mtl, "d %f\n", 1.0 - m->transparency);
00140 fprintf(mtl, "map_Kd %s\n", m->texture1_map.name);
00141 fprintf(mtl, "map_bump %s\n", m->bump_map.name);
00142 fprintf(mtl, "map_d %s\n", m->opacity_map.name);
00143 fprintf(mtl, "refl %s\n", m->reflection_map.name);
00144 fprintf(mtl, "map_KS %s\n", m->specular_map.name);
00145 fprintf(mtl, "\n");
00146 }
00147 }
00148
00149
00150 void write_mesh(FILE *o, Lib3dsFile *f, Lib3dsMeshInstanceNode *node) {
00151 float (*orig_vertices)[3];
00152 int export_texcos;
00153 int export_normals;
00154 int i, j;
00155 Lib3dsMesh *mesh;
00156
00157 mesh = lib3ds_file_mesh_for_node(f, (Lib3dsNode*)node);
00158 if (!mesh || !mesh->vertices) return;
00159
00160 fprintf(o, "# object %s\n", node->base.name);
00161 fprintf(o, "g %s\n", node->instance_name[0]? node->instance_name : node->base.name);
00162
00163 orig_vertices = (float(*)[3])malloc(sizeof(float) * 3 * mesh->nvertices);
00164 memcpy(orig_vertices, mesh->vertices, sizeof(float) * 3 * mesh->nvertices);
00165 {
00166 float inv_matrix[4][4], M[4][4];
00167 float tmp[3];
00168 int i;
00169
00170 lib3ds_matrix_copy(M, node->base.matrix);
00171 lib3ds_matrix_translate(M, -node->pivot[0], -node->pivot[1], -node->pivot[2]);
00172 lib3ds_matrix_copy(inv_matrix, mesh->matrix);
00173 lib3ds_matrix_inv(inv_matrix);
00174 lib3ds_matrix_mult(M, M, inv_matrix);
00175
00176 for (i = 0; i < mesh->nvertices; ++i) {
00177 lib3ds_vector_transform(tmp, M, mesh->vertices[i]);
00178 lib3ds_vector_copy(mesh->vertices[i], tmp);
00179 }
00180 }
00181
00182 export_texcos = (mesh->texcos != 0);
00183 export_normals = (mesh->faces != 0);
00184
00185 for (i = 0; i < mesh->nvertices; ++i) {
00186 fprintf(o, "v %f %f %f\n", mesh->vertices[i][0],
00187 mesh->vertices[i][1],
00188 mesh->vertices[i][2]);
00189 }
00190 fprintf(o, "# %d vertices\n", mesh->nvertices);
00191
00192 if (export_texcos) {
00193 for (i = 0; i < mesh->nvertices; ++i) {
00194 fprintf(o, "vt %f %f\n", mesh->texcos[i][0],
00195 mesh->texcos[i][1]);
00196 }
00197 fprintf(o, "# %d texture vertices\n", mesh->nvertices);
00198 }
00199
00200 if (export_normals) {
00201 float (*normals)[3] = (float(*)[3])malloc(sizeof(float) * 9 * mesh->nfaces);
00202 lib3ds_mesh_calculate_vertex_normals(mesh, normals);
00203 for (i = 0; i < 3 * mesh->nfaces; ++i) {
00204 fprintf(o, "vn %f %f %f\n", normals[i][0],
00205 normals[i][1],
00206 normals[i][2]);
00207 }
00208 free(normals);
00209 fprintf(o, "# %d normals\n", 3 * mesh->nfaces);
00210 }
00211
00212 {
00213 int mat_index = -1;
00214 for (i = 0; i < mesh->nfaces; ++i) {
00215 if (mat_index != mesh->faces[i].material) {
00216 mat_index = mesh->faces[i].material;
00217 if (mat_index != -1) {
00218 fprintf(o, "usemtl %s\n", f->materials[mat_index]->name);
00219 }
00220 }
00221
00222 fprintf(o, "f ");
00223 for (j = 0; j < 3; ++j) {
00224 fprintf(o, "%d", mesh->faces[i].index[j] + max_vertices + 1);
00225 if (export_texcos) {
00226 fprintf(o, "/%d", mesh->faces[i].index[j] + max_texcos + 1);
00227 } else if (export_normals) {
00228 fprintf(o, "/");
00229 }
00230 if (export_normals) {
00231 fprintf(o, "/%d", 3 * i + j + max_normals + 1);
00232 }
00233 if (j < 3) {
00234 fprintf(o, " ");
00235 }
00236 }
00237 fprintf(o, "\n");
00238 }
00239 }
00240
00241 max_vertices += mesh->nvertices;
00242 if (export_texcos)
00243 max_texcos += mesh->nvertices;
00244 if (export_normals)
00245 max_normals += 3 * mesh->nfaces;
00246
00247 memcpy(mesh->vertices, orig_vertices, sizeof(float) * 3 * mesh->nvertices);
00248 free(orig_vertices);
00249 }
00250
00251
00252 void write_nodes(FILE *o, Lib3dsFile *f, Lib3dsNode *first_node) {
00253 Lib3dsNode *p;
00254 for (p = first_node; p; p = p->next) {
00255 if (p->type == LIB3DS_NODE_MESH_INSTANCE) {
00256 write_mesh(o, f, (Lib3dsMeshInstanceNode*)p);
00257 write_nodes(o, f, p->childs);
00258 }
00259 }
00260 }
00261
00262
00263 int main(int argc, char **argv) {
00264 Lib3dsFile *f;
00265 parse_args(argc, argv);
00266
00267 f = lib3ds_file_open(input);
00268 if (!f) {
00269 fprintf(stderr, "***ERROR***\nLoading file failed: %s\n", input);
00270 exit(1);
00271 }
00272
00273 if (mtl_file) {
00274 FILE *mtl = fopen(mtl_file, "wt");
00275 if (!mtl) {
00276 fprintf(stderr, "***ERROR***\nCreating output file failed: %s\n", mtl_file);
00277 exit(1);
00278 }
00279 write_mtl(mtl, f);
00280 fclose(mtl);
00281 }
00282
00283 {
00284 FILE *obj = fopen(obj_file, "wt");
00285 if (!obj) {
00286 fprintf(stderr, "***ERROR***\nCreating output file failed: %s\n", obj_file);
00287 exit(1);
00288 }
00289
00290 if (!f->nodes)
00291 lib3ds_file_create_nodes_for_meshes(f);
00292 lib3ds_file_eval(f, 0);
00293
00294 fprintf(obj, "# Wavefront OBJ file\n");
00295 fprintf(obj, "# Converted by 3ds2obj\n");
00296 fprintf(obj, "# http://www.lib3ds.org\n\n");
00297 if (mtl_file) {
00298 fprintf(obj, "mtllib %s\n", mtl_file);
00299 }
00300
00301 write_nodes(obj, f, f->nodes);
00302 fclose(obj);
00303 }
00304
00305 lib3ds_file_free(f);
00306 return 0;
00307 }