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

meshmanager.cpp

Go to the documentation of this file.
00001 // meshmanager.cpp
00002 //
00003 // Copyright (C) 2001 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 #include <iostream>
00011 #include <fstream>
00012 #include <cassert>
00013 
00014 #include "celestia.h"
00015 #include <celutil/debug.h>
00016 #include <celutil/filetype.h>
00017 #include <celutil/util.h>
00018 #include <celmath/mathlib.h>
00019 #include <celmath/perlin.h>
00020 #include <cel3ds/3dsread.h>
00021 
00022 //#include "3dsmesh.h"
00023 #include "modelfile.h"
00024 #include "vertexlist.h"
00025 #include "parser.h"
00026 #include "spheremesh.h"
00027 #include "texmanager.h"
00028 #include "meshmanager.h"
00029 
00030 using namespace std;
00031 
00032 
00033 static Model* LoadCelestiaMesh(const string& filename);
00034 static Model* Convert3DSModel(const M3DScene& scene, const string& texPath);
00035 
00036 static ModelManager* modelManager = NULL;
00037 
00038 
00039 ModelManager* GetModelManager()
00040 {
00041     if (modelManager == NULL)
00042         modelManager = new ModelManager("models");
00043     return modelManager;
00044 }
00045 
00046 
00047 string ModelInfo::resolve(const string& baseDir)
00048 {
00049     if (!path.empty())
00050     {
00051         string filename = path + "/models/" + source;
00052         ifstream in(filename.c_str());
00053         if (in.good())
00054         {
00055             resolvedToPath = true;
00056             return filename;
00057         }
00058     }
00059 
00060     return baseDir + "/" + source;
00061 }
00062 
00063 
00064 Model* ModelInfo::load(const string& filename)
00065 {
00066     clog << _("Loading model: ") << filename << '\n';
00067     Model* model = NULL;
00068     ContentType fileType = DetermineFileType(filename);
00069 
00070     if (fileType == Content_3DStudio)
00071     {
00072         M3DScene* scene = Read3DSFile(filename);
00073         if (scene != NULL)
00074         {
00075             if (resolvedToPath)
00076                 model = Convert3DSModel(*scene, path);
00077             else
00078                 model = Convert3DSModel(*scene, "");
00079             model->normalize(center);
00080 
00081             delete scene;
00082         }
00083     }
00084     else if (fileType == Content_CelestiaModel)
00085     {
00086         ifstream in(filename.c_str(), ios::binary);
00087         if (in.good())
00088         {
00089             model = LoadModel(in, path);
00090             if (model != NULL)
00091                 model->normalize(center);
00092         }
00093     }
00094     else if (fileType == Content_CelestiaMesh)
00095     {
00096         model = LoadCelestiaMesh(filename);
00097     }
00098 
00099     if (model != NULL)
00100     {
00101         // Sort the submeshes roughly by opacity.  This will eliminate a
00102         // good number of the errors caused when translucent triangles are
00103         // rendered before geometry that they cover.
00104         model->sortMeshes(Model::OpacityComparator(*model));
00105     }
00106     else
00107     {
00108         cerr << _("Error loading model '") << filename << "'\n";
00109     }
00110  
00111     return model;
00112 }
00113 
00114 
00115 struct NoiseMeshParameters
00116 {
00117     Vec3f size;
00118     Vec3f offset;
00119     float featureHeight;
00120     float octaves;
00121     float slices;
00122     float rings;
00123 };
00124 
00125 
00126 static float NoiseDisplacementFunc(float u, float v, void* info)
00127 {
00128     float theta = u * (float) PI * 2;
00129     float phi = (v - 0.5f) * (float) PI;
00130     float x = (float) (cos(phi) * cos(theta));
00131     float y = (float) sin(phi);
00132     float z = (float) (cos(phi) * sin(theta));
00133 
00134     // assert(info != NULL);
00135     NoiseMeshParameters* params = (NoiseMeshParameters*) info;
00136 
00137     return fractalsum(Point3f(x, y, z) + params->offset,
00138                       params->octaves) * params->featureHeight;
00139 }
00140 
00141 
00142 Model* LoadCelestiaMesh(const string& filename)
00143 {
00144     ifstream meshFile(filename.c_str(), ios::in);
00145     if (!meshFile.good())
00146     {
00147         DPRINTF(0, "Error opening mesh file: %s\n", filename.c_str());
00148         return NULL;
00149     }
00150 
00151     Tokenizer tokenizer(&meshFile);
00152     Parser parser(&tokenizer);
00153 
00154     if (tokenizer.nextToken() != Tokenizer::TokenName)
00155     {
00156         DPRINTF(0, "Mesh file %s is invalid.\n", filename.c_str());
00157         return NULL;
00158     }
00159 
00160     if (tokenizer.getStringValue() != "SphereDisplacementMesh")
00161     {
00162         DPRINTF(0, "%s: Unrecognized mesh type %s.\n",
00163                 filename.c_str(),
00164                 tokenizer.getStringValue().c_str());
00165         return NULL;
00166     }
00167 
00168     Value* meshDefValue = parser.readValue();
00169     if (meshDefValue == NULL)
00170     {
00171         DPRINTF(0, "%s: Bad mesh file.\n", filename.c_str());
00172         return NULL;
00173     }
00174 
00175     if (meshDefValue->getType() != Value::HashType)
00176     {
00177         DPRINTF(0, "%s: Bad mesh file.\n", filename.c_str());
00178         delete meshDefValue;
00179         return NULL;
00180     }
00181 
00182     Hash* meshDef = meshDefValue->getHash();
00183     
00184     NoiseMeshParameters params;
00185     
00186     params.size = Vec3f(1, 1, 1);
00187     params.offset = Vec3f(10, 10, 10);
00188     params.featureHeight = 0.0f;
00189     params.octaves = 1;
00190     params.slices = 20;
00191     params.rings = 20;
00192 
00193     meshDef->getVector("Size", params.size);
00194     meshDef->getVector("NoiseOffset", params.offset);
00195     meshDef->getNumber("FeatureHeight", params.featureHeight);
00196     meshDef->getNumber("Octaves", params.octaves);
00197     meshDef->getNumber("Slices", params.slices);
00198     meshDef->getNumber("Rings", params.rings);
00199 
00200     delete meshDefValue;
00201 
00202     Model* model = new Model();
00203     SphereMesh* sphereMesh = new SphereMesh(params.size,
00204                                             (int) params.rings, (int) params.slices,
00205                                             NoiseDisplacementFunc,
00206                                             (void*) &params);
00207     if (sphereMesh != NULL)
00208     {
00209         Mesh* mesh = sphereMesh->convertToMesh();
00210         model->addMesh(mesh);
00211         delete sphereMesh;
00212     }
00213 
00214     return model;
00215 }
00216 
00217 
00218 static VertexList* ConvertToVertexList(M3DTriangleMesh& mesh,
00219                                        const M3DScene& scene,
00220                                        const string& texturePath)
00221 {
00222     int nFaces = mesh.getFaceCount();
00223     int nVertices = mesh.getVertexCount();
00224     int nTexCoords = mesh.getTexCoordCount();
00225     bool smooth = (mesh.getSmoothingGroupCount() == nFaces);
00226     int i;
00227 
00228     uint32 parts = VertexList::VertexNormal;
00229     if (nTexCoords == nVertices)
00230         parts |= VertexList::TexCoord0;
00231     VertexList* vl = new VertexList(parts);
00232     
00233     Vec3f* faceNormals = new Vec3f[nFaces];
00234     Vec3f* vertexNormals = new Vec3f[nFaces * 3];
00235     int* faceCounts = new int[nVertices];
00236     int** vertexFaces = new int*[nVertices];
00237 
00238     for (i = 0; i < nVertices; i++)
00239     {
00240         faceCounts[i] = 0;
00241         vertexFaces[i] = NULL;
00242     }
00243 
00244     // generate face normals
00245     for (i = 0; i < nFaces; i++)
00246     {
00247         uint16 v0, v1, v2;
00248         mesh.getFace(i, v0, v1, v2);
00249 
00250         faceCounts[v0]++;
00251         faceCounts[v1]++;
00252         faceCounts[v2]++;
00253 
00254         Point3f p0 = mesh.getVertex(v0);
00255         Point3f p1 = mesh.getVertex(v1);
00256         Point3f p2 = mesh.getVertex(v2);
00257         faceNormals[i] = cross(p1 - p0, p2 - p1);
00258         faceNormals[i].normalize();
00259     }
00260 
00261     if (!smooth && 0)
00262     {
00263         for (i = 0; i < nFaces; i++)
00264         {
00265             vertexNormals[i * 3] = faceNormals[i];
00266             vertexNormals[i * 3 + 1] = faceNormals[i];
00267             vertexNormals[i * 3 + 2] = faceNormals[i];
00268         }
00269     }
00270     else
00271     {
00272         // allocate space for vertex face indices
00273         for (i = 0; i < nVertices; i++)
00274         {
00275             vertexFaces[i] = new int[faceCounts[i] + 1];
00276             vertexFaces[i][0] = faceCounts[i];
00277         }
00278 
00279         for (i = 0; i < nFaces; i++)
00280         {
00281             uint16 v0, v1, v2;
00282             mesh.getFace(i, v0, v1, v2);
00283             vertexFaces[v0][faceCounts[v0]--] = i;
00284             vertexFaces[v1][faceCounts[v1]--] = i;
00285             vertexFaces[v2][faceCounts[v2]--] = i;
00286         }
00287 
00288         // average face normals to compute the vertex normals
00289         for (i = 0; i < nFaces; i++)
00290         {
00291             uint16 v0, v1, v2;
00292             mesh.getFace(i, v0, v1, v2);
00293             // uint32 smoothingGroups = mesh.getSmoothingGroups(i);
00294 
00295             int j;
00296             Vec3f v = Vec3f(0, 0, 0);
00297             for (j = 1; j <= vertexFaces[v0][0]; j++)
00298             {
00299                 int k = vertexFaces[v0][j];
00300                 // if (k == i || (smoothingGroups & mesh.getSmoothingGroups(k)) != 0)
00301                 if (faceNormals[i] * faceNormals[k] > 0.5f)
00302                     v += faceNormals[k];
00303             }
00304             v.normalize();
00305             vertexNormals[i * 3] = v;
00306 
00307             v = Vec3f(0, 0, 0);
00308             for (j = 1; j <= vertexFaces[v1][0]; j++)
00309             {
00310                 int k = vertexFaces[v1][j];
00311                 // if (k == i || (smoothingGroups & mesh.getSmoothingGroups(k)) != 0)
00312                 if (faceNormals[i] * faceNormals[k] > 0.5f)
00313                     v += faceNormals[k];
00314             }
00315             v.normalize();
00316             vertexNormals[i * 3 + 1] = v;
00317 
00318             v = Vec3f(0, 0, 0);
00319             for (j = 1; j <= vertexFaces[v2][0]; j++)
00320             {
00321                 int k = vertexFaces[v2][j];
00322                 // if (k == i || (smoothingGroups & mesh.getSmoothingGroups(k)) != 0)
00323                 if (faceNormals[i] * faceNormals[k] > 0.5f)
00324                     v += faceNormals[k];
00325             }
00326             v.normalize();
00327             vertexNormals[i * 3 + 2] = v;
00328         }
00329     }
00330 
00331     // build the triangle list
00332     for (i = 0; i < nFaces; i++)
00333     {
00334         uint16 triVert[3];
00335         mesh.getFace(i, triVert[0], triVert[1], triVert[2]);
00336 
00337         for (int j = 0; j < 3; j++)
00338         {
00339             VertexList::Vertex v;
00340             v.point = mesh.getVertex(triVert[j]);
00341             v.normal = vertexNormals[i * 3 + j];
00342             if ((parts & VertexList::TexCoord0) != 0)
00343                 v.texCoords[0] = mesh.getTexCoord(triVert[j]);
00344             vl->addVertex(v);
00345         }
00346     }
00347 
00348     // Set the material properties
00349     {
00350         string materialName = mesh.getMaterialName();
00351         if (materialName.length() > 0)
00352         {
00353             int nMaterials = scene.getMaterialCount();
00354             for (i = 0; i < nMaterials; i++)
00355             {
00356                 M3DMaterial* material = scene.getMaterial(i);
00357                 if (materialName == material->getName())
00358                 {
00359                     M3DColor diffuse = material->getDiffuseColor();
00360                     vl->setDiffuseColor(Color(diffuse.red, diffuse.green, diffuse.blue, material->getOpacity()));
00361                     M3DColor specular = material->getSpecularColor();
00362                     vl->setSpecularColor(Color(specular.red, specular.green, specular.blue));
00363                     float shininess = material->getShininess();
00364                     
00365                     // Map the shininess from the 3DS file into the 0-128
00366                     // range that OpenGL uses for the specular exponent.
00367                     shininess = (float) pow(2.0, 10.0 * shininess);
00368                     if (shininess > 128.0f)
00369                         shininess = 128.0f;
00370                     vl->setShininess(128.0f);
00371 
00372                     if (material->getTextureMap() != "")
00373                     {
00374                         ResourceHandle tex = GetTextureManager()->getHandle(TextureInfo(material->getTextureMap(), texturePath, TextureInfo::WrapTexture));
00375                         vl->setTexture(tex);
00376                     }
00377 
00378                     break;
00379                 }
00380             }
00381         }
00382     }
00383 
00384     // clean up
00385     if (faceNormals != NULL)
00386         delete[] faceNormals;
00387     if (vertexNormals != NULL)
00388         delete[] vertexNormals;
00389     if (faceCounts != NULL)
00390         delete[] faceCounts;
00391     if (vertexFaces != NULL)
00392     {
00393         for (i = 0; i < nVertices; i++)
00394         {
00395             if (vertexFaces[i] != NULL)
00396                 delete[] vertexFaces[i];
00397         }
00398         delete[] vertexFaces;
00399     }
00400 
00401     return vl;
00402 }
00403 
00404 
00405 static Mesh*
00406 ConvertVertexListToMesh(VertexList* vlist, const string& texPath, uint32 material)
00407 {
00408     Mesh::VertexAttribute attributes[8];
00409     uint32 nAttributes = 0;
00410     uint32 offset = 0;
00411 
00412     uint32 parts = vlist->getVertexParts();
00413 
00414     // Position attribute is always present in a vertex list
00415     attributes[nAttributes] = Mesh::VertexAttribute(Mesh::Position, Mesh::Float3, 0);
00416     nAttributes++;
00417     offset += 12;
00418 
00419     if ((parts & VertexList::VertexNormal) != 0)
00420     {
00421         attributes[nAttributes] = Mesh::VertexAttribute(Mesh::Normal, Mesh::Float3, offset);
00422         nAttributes++;
00423         offset += 12;
00424     }
00425 
00426     if ((parts & VertexList::VertexColor0) != 0)
00427     {
00428         attributes[nAttributes] = Mesh::VertexAttribute(Mesh::Color0, Mesh::UByte4, offset);
00429         nAttributes++;
00430         offset += 4;
00431     }
00432 
00433     if ((parts & VertexList::TexCoord0) != 0)
00434     {
00435         attributes[nAttributes] = Mesh::VertexAttribute(Mesh::Texture0, Mesh::Float2, offset);
00436         nAttributes++;
00437         offset += 8;
00438     }
00439 
00440     if ((parts & VertexList::TexCoord1) != 0)
00441     {
00442         attributes[nAttributes] = Mesh::VertexAttribute(Mesh::Texture1, Mesh::Float2, offset);
00443         nAttributes++;
00444         offset += 8;
00445     }
00446 
00447     uint32 nVertices = vlist->getVertexCount();
00448 
00449     Mesh* mesh = new Mesh();
00450     mesh->setVertexDescription(Mesh::VertexDescription(offset, nAttributes, attributes));
00451     mesh->setVertices(nVertices, vlist->getVertexData());
00452 
00453     // Vertex lists are not indexed, so the conversion to an indexed format is
00454     // trivial (although much space is wasted storing unnecessary indices.)
00455     uint32* indices = new uint32[nVertices];
00456     for (uint32 i = 0; i < nVertices; i++)
00457         indices[i] = i;
00458 
00459     mesh->addGroup(Mesh::TriList, material, nVertices, indices);
00460 
00461     return mesh;
00462 }
00463 
00464 
00465 static Model*
00466 Convert3DSModel(const M3DScene& scene, const string& texPath)
00467 {
00468     Model* model = new Model();
00469     uint32 materialIndex = 0;
00470 
00471     for (unsigned int i = 0; i < scene.getModelCount(); i++)
00472     {
00473         M3DModel* model3ds = scene.getModel(i);
00474         if (model3ds != NULL)
00475         {
00476             for (unsigned int j = 0; j < model3ds->getTriMeshCount(); j++)
00477             {
00478                 M3DTriangleMesh* mesh = model3ds->getTriMesh(j);
00479                 if (mesh != NULL)
00480                 {
00481                     // The vertex list is just an intermediate stage in conversion
00482                     // to a Celestia model structure.  Eventually, we should handle
00483                     // the conversion in a single step.
00484                     VertexList* vlist = ConvertToVertexList(*mesh, scene, texPath);
00485                     Mesh* mesh = ConvertVertexListToMesh(vlist, texPath, materialIndex);
00486 
00487                     // Convert the vertex list material
00488                     Mesh::Material* material = new Mesh::Material();
00489                     material->diffuse = vlist->getDiffuseColor();
00490                     material->specular = vlist->getSpecularColor();
00491                     material->specularPower = vlist->getShininess();
00492                     material->opacity = vlist->getDiffuseColor().alpha();
00493                     material->maps[Mesh::DiffuseMap] = vlist->getTexture();
00494                     model->addMaterial(material);
00495                     materialIndex++;
00496 
00497                     model->addMesh(mesh);
00498 
00499                     delete vlist;
00500                 }
00501             }
00502         }
00503     }
00504 
00505     return model;
00506 #if 0
00507     // Sort the vertex lists to make sure that the transparent ones are
00508     // rendered after the opaque ones and material state changes are minimized.
00509     sort(vertexLists.begin(), vertexLists.end(), compareVertexLists);
00510 #endif
00511 }

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