Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members

3dstocmod.cpp

Go to the documentation of this file.
00001 // 3dstocmod.cpp
00002 //
00003 // Copyright (C) 2004, Chris Laurel <claurel@shatters.net>
00004 //
00005 // This program is free software; you can redistribute it and/or
00006 // modify it under the terms of the GNU General Public License
00007 // as published by the Free Software Foundation; either version 2
00008 // of the License, or (at your option) any later version.
00009 //
00010 // Convert a 3DS file to a Celestia mesh (.cmod) file
00011 
00012 #include <celengine/modelfile.h>
00013 #include <celengine/tokenizer.h>
00014 #include <celengine/texmanager.h>
00015 #include <cel3ds/3dsread.h>
00016 #include <cstring>
00017 #include <cassert>
00018 #include <cmath>
00019 #include <cstdio>
00020 
00021 
00022 static Model* Convert3DSModel(const M3DScene& scene, const string& texPath);
00023 
00024 
00025 void usage()
00026 {
00027     cerr << "Usage: 3dstocmod <input 3ds file>\n";
00028 }
00029 
00030 
00031 int main(int argc, char* argv[])
00032 {
00033     if (argc != 2)
00034     {
00035         usage();
00036         return 1;
00037     }
00038 
00039     string inputFileName = argv[1];
00040 
00041     M3DScene* scene = Read3DSFile(inputFileName);
00042     if (scene == NULL)
00043     {
00044         cerr << "Error reading 3DS file '" << inputFileName << "'\n";
00045         return 1;
00046     }
00047 
00048     Model* model = Convert3DSModel(*scene, ".");
00049     if (!model)
00050     {
00051         cerr << "Error converting 3DS file to Celestia model\n";
00052         return 1;
00053     }
00054 
00055     for (uint32 i = 0; model->getMesh(i); i++)
00056     {
00057         const Mesh* mesh = model->getMesh(i);
00058         for (uint32 j = 0; mesh->getGroup(j); j++)
00059         {
00060             const Mesh::PrimitiveGroup* group = mesh->getGroup(j);
00061             cerr << "Group: #" << i << ", indices=" << group->nIndices << '\n';
00062         }
00063     }
00064 
00065     SaveModelAscii(model, cout);
00066 
00067     return 0;
00068 }
00069 
00070 
00071 void
00072 Convert3DSMesh(Model& model,
00073                M3DTriangleMesh& mesh3ds,
00074                const M3DScene& scene,
00075                const string& meshName)
00076 {
00077     int nFaces = mesh3ds.getFaceCount();
00078     int nVertices = mesh3ds.getVertexCount();
00079     int nTexCoords = mesh3ds.getTexCoordCount();
00080     bool smooth = (mesh3ds.getSmoothingGroupCount() == nFaces);
00081     bool hasTexCoords = (nTexCoords == nVertices);
00082     int vertexSize = hasTexCoords ? 8 : 6;
00083     int i;
00084 
00085     Vec3f* faceNormals = new Vec3f[nFaces];
00086     Vec3f* vertexNormals = new Vec3f[nFaces * 3];
00087     int* faceCounts = new int[nVertices];
00088     int** vertexFaces = new int*[nVertices];
00089 
00090     int nOutputVertices = nFaces * 3;
00091     float* vertices = new float[nOutputVertices * vertexSize];
00092     
00093 
00094     for (i = 0; i < nVertices; i++)
00095     {
00096         faceCounts[i] = 0;
00097         vertexFaces[i] = NULL;
00098     }
00099 
00100     // generate face normals
00101     for (i = 0; i < nFaces; i++)
00102     {
00103         uint16 v0, v1, v2;
00104         mesh3ds.getFace(i, v0, v1, v2);
00105 
00106         faceCounts[v0]++;
00107         faceCounts[v1]++;
00108         faceCounts[v2]++;
00109 
00110         Point3f p0 = mesh3ds.getVertex(v0);
00111         Point3f p1 = mesh3ds.getVertex(v1);
00112         Point3f p2 = mesh3ds.getVertex(v2);
00113         faceNormals[i] = cross(p1 - p0, p2 - p1);
00114         faceNormals[i].normalize();
00115     }
00116 
00117     if (!smooth && 0)
00118     {
00119         for (i = 0; i < nFaces; i++)
00120         {
00121             vertexNormals[i * 3] = faceNormals[i];
00122             vertexNormals[i * 3 + 1] = faceNormals[i];
00123             vertexNormals[i * 3 + 2] = faceNormals[i];
00124         }
00125     }
00126     else
00127     {
00128         // allocate space for vertex face indices
00129         for (i = 0; i < nVertices; i++)
00130         {
00131             vertexFaces[i] = new int[faceCounts[i] + 1];
00132             vertexFaces[i][0] = faceCounts[i];
00133         }
00134 
00135         for (i = 0; i < nFaces; i++)
00136         {
00137             uint16 v0, v1, v2;
00138             mesh3ds.getFace(i, v0, v1, v2);
00139             vertexFaces[v0][faceCounts[v0]--] = i;
00140             vertexFaces[v1][faceCounts[v1]--] = i;
00141             vertexFaces[v2][faceCounts[v2]--] = i;
00142         }
00143 
00144         // average face normals to compute the vertex normals
00145         for (i = 0; i < nFaces; i++)
00146         {
00147             uint16 v0, v1, v2;
00148             mesh3ds.getFace(i, v0, v1, v2);
00149             // uint32 smoothingGroups = mesh3ds.getSmoothingGroups(i);
00150 
00151             int j;
00152             Vec3f v = Vec3f(0, 0, 0);
00153             for (j = 1; j <= vertexFaces[v0][0]; j++)
00154             {
00155                 int k = vertexFaces[v0][j];
00156                 // if (k == i || (smoothingGroups & mesh3ds.getSmoothingGroups(k)) != 0)
00157                 if (faceNormals[i] * faceNormals[k] > 0.5f)
00158                     v += faceNormals[k];
00159             }
00160             if (v * v == 0.0f)
00161                 v = Vec3f(1.0f, 0.0f, 0.0f);
00162             v.normalize();
00163             vertexNormals[i * 3] = v;
00164 
00165             v = Vec3f(0, 0, 0);
00166             for (j = 1; j <= vertexFaces[v1][0]; j++)
00167             {
00168                 int k = vertexFaces[v1][j];
00169                 // if (k == i || (smoothingGroups & mesh3ds.getSmoothingGroups(k)) != 0)
00170                 if (faceNormals[i] * faceNormals[k] > 0.5f)
00171                     v += faceNormals[k];
00172             }
00173             if (v * v == 0.0f)
00174                 v = Vec3f(1.0f, 0.0f, 0.0f);
00175             v.normalize();
00176             vertexNormals[i * 3 + 1] = v;
00177 
00178             v = Vec3f(0, 0, 0);
00179             for (j = 1; j <= vertexFaces[v2][0]; j++)
00180             {
00181                 int k = vertexFaces[v2][j];
00182                 // if (k == i || (smoothingGroups & mesh3ds.getSmoothingGroups(k)) != 0)
00183                 if (faceNormals[i] * faceNormals[k] > 0.5f)
00184                     v += faceNormals[k];
00185             }
00186             if (v * v == 0.0f)
00187                 v = Vec3f(1.0f, 0.0f, 0.0f);
00188             v.normalize();
00189             vertexNormals[i * 3 + 2] = v;
00190         }
00191     }
00192 
00193     // build the triangle list
00194     for (i = 0; i < nFaces; i++)
00195     {
00196         uint16 triVert[3];
00197         mesh3ds.getFace(i, triVert[0], triVert[1], triVert[2]);
00198 
00199         for (int j = 0; j < 3; j++)
00200         {
00201             Point3f pos = mesh3ds.getVertex(triVert[j]);
00202             Vec3f norm = vertexNormals[i * 3 + j];
00203             int k = (i * 3 + j) * vertexSize;
00204 
00205             vertices[k + 0] = pos.x;
00206             vertices[k + 1] = pos.y;
00207             vertices[k + 2] = pos.z;
00208             vertices[k + 3] = norm.x;
00209             vertices[k + 4] = norm.y;
00210             vertices[k + 5] = norm.z;
00211             if (hasTexCoords)
00212             {
00213                 vertices[k + 6] = mesh3ds.getTexCoord(triVert[j]).x;
00214                 vertices[k + 7] = mesh3ds.getTexCoord(triVert[j]).y;
00215             }
00216         }
00217     }
00218 
00219     // clean up
00220     if (faceNormals != NULL)
00221         delete[] faceNormals;
00222     if (vertexNormals != NULL)
00223         delete[] vertexNormals;
00224     if (faceCounts != NULL)
00225         delete[] faceCounts;
00226     if (vertexFaces != NULL)
00227     {
00228         for (i = 0; i < nVertices; i++)
00229         {
00230             if (vertexFaces[i] != NULL)
00231                 delete[] vertexFaces[i];
00232         }
00233         delete[] vertexFaces;
00234     }
00235 
00236 
00237     Mesh::VertexAttribute attributes[8];
00238     uint32 nAttributes = 0;
00239     uint32 offset = 0;
00240 
00241     // Position attribute is always present
00242     attributes[nAttributes] = Mesh::VertexAttribute(Mesh::Position, Mesh::Float3, 0);
00243     nAttributes++;
00244     offset += 12;
00245 
00246     // Normal attribute is always present
00247     attributes[nAttributes] = Mesh::VertexAttribute(Mesh::Normal, Mesh::Float3, offset);
00248     nAttributes++;
00249     offset += 12;
00250 
00251     if (hasTexCoords)
00252     {
00253         attributes[nAttributes] = Mesh::VertexAttribute(Mesh::Texture0, Mesh::Float2, offset);
00254         nAttributes++;
00255         offset += 8;
00256     }
00257 
00258     // Create the Celestia mesh
00259     Mesh* mesh = new Mesh();
00260     mesh->setVertexDescription(Mesh::VertexDescription(offset, nAttributes, attributes));
00261     mesh->setVertices(nOutputVertices, vertices);
00262 
00263     mesh->setName(meshName);
00264 
00265     // Vertex lists are not indexed, so the conversion to an indexed format is
00266     // trivial (although much space is wasted storing unnecessary indices.)
00267     uint32* indices = new uint32[nOutputVertices];
00268     for (int i = 0; i < nOutputVertices; i++)
00269         indices[i] = i;
00270 
00271     // Convert the 3DS mesh's material
00272     Mesh::Material* material = new Mesh::Material();
00273 
00274     string material3dsName = mesh3ds.getMaterialName();
00275     if (material3dsName.length() > 0)
00276     {
00277         int nMaterials = scene.getMaterialCount();
00278         for (int i = 0; i < nMaterials; i++)
00279         {
00280             M3DMaterial* material3ds = scene.getMaterial(i);
00281             if (material3dsName == material3ds->getName())
00282             {
00283                 M3DColor diffuse = material3ds->getDiffuseColor();
00284                 material->diffuse = Color(diffuse.red, diffuse.green, diffuse.blue);
00285                 M3DColor specular = material3ds->getSpecularColor();
00286                 material->specular = Color(specular.red, specular.green, specular.blue);
00287                 // Map the shininess from the 3DS file into the 0-128
00288                 // range that OpenGL uses for the specular exponent.
00289                 float specPow = (float) pow(2, 10.0 * material3ds->getShininess());
00290                 if (specPow > 128.0f)
00291                     specPow = 128.0f;
00292                 material->specularPower = specPow;
00293 
00294                 material->opacity = material3ds->getOpacity();
00295                 if (material3ds->getTextureMap() != "")
00296                 {
00297                     material->maps[Mesh::DiffuseMap] = GetTextureManager()->getHandle(TextureInfo(material3ds->getTextureMap(), ".", TextureInfo::WrapTexture));
00298                 }
00299             }
00300         }
00301     }
00302 
00303     uint32 materialIndex = model.addMaterial(material) - 1;
00304     mesh->addGroup(Mesh::TriList, materialIndex, nOutputVertices, indices);
00305     model.addMesh(mesh);
00306 }
00307 
00308 
00309 static Model*
00310 Convert3DSModel(const M3DScene& scene, const string& texPath)
00311 {
00312     Model* model = new Model();
00313     uint32 materialIndex = 0;
00314 
00315     for (unsigned int i = 0; i < scene.getModelCount(); i++)
00316     {
00317         M3DModel* model3ds = scene.getModel(i);
00318         if (model3ds != NULL)
00319         {
00320             for (unsigned int j = 0; j < model3ds->getTriMeshCount(); j++)
00321             {
00322                 M3DTriangleMesh* mesh = model3ds->getTriMesh(j);
00323 
00324                 if (mesh != NULL && mesh->getFaceCount() > 0)
00325                 {
00326                     Convert3DSMesh(*model, *mesh, scene, model3ds->getName());
00327                 }
00328             }
00329         }
00330     }
00331 
00332     return model;
00333 #if 0
00334     // Sort the vertex lists to make sure that the transparent ones are
00335     // rendered after the opaque ones and material state changes are minimized.
00336     sort(vertexLists.begin(), vertexLists.end(), compareVertexLists);
00337 #endif
00338 }
00339 

Generated on Sat Jan 14 22:30:32 2006 for Celestia by  doxygen 1.4.1