Home | API | File List | Examples | Download

3ds2obj.c

00001 /*
00002     Copyright (C) 2008 by Jan Eric Kyprianidis <www.kyprianidis.com>
00003     All rights reserved.
00004     
00005     This program is free  software: you can redistribute it and/or modify 
00006     it under the terms of the GNU Lesser General Public License as published 
00007     by the Free Software Foundation, either version 2.1 of the License, or 
00008     (at your option) any later version.
00009 
00010     Thisprogram  is  distributed in the hope that it will be useful, 
00011     but WITHOUT ANY WARRANTY; without even the implied warranty of 
00012     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
00013     GNU Lesser General Public License for more details.
00014     
00015     You should  have received a copy of the GNU Lesser General Public License
00016     along with  this program; If not, see <http://www.gnu.org/licenses/>. 
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 }