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

cmodfix.cpp File Reference

#include <celengine/modelfile.h>
#include <celengine/tokenizer.h>
#include <celengine/texmanager.h>
#include <cel3ds/3dsread.h>
#include <celmath/mathlib.h>
#include <cstring>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <algorithm>
#include <vector>

Include dependency graph for cmodfix.cpp:

Go to the source code of this file.

Typedefs

typedef public std::binary_function<
const Vertex &, const Vertex &,
bool > 
VertexComparator

Functions

void addGroupWithOffset (Mesh &mesh, const Mesh::PrimitiveGroup &group, uint32 offset)
void augmentVertexDescription (Mesh::VertexDescription &desc, Mesh::VertexAttributeSemantic semantic, Mesh::VertexAttributeFormat format)
Vec3f averageFaceVectors (const vector< Face > &faces, uint32 thisFace, uint32 *vertexFaces, uint32 vertexFaceCount, float cosSmoothingAngle)
void copyVertex (void *newVertexData, const Mesh::VertexDescription &newDesc, const void *oldVertexData, const Mesh::VertexDescription &oldDesc, uint32 oldIndex, const uint32 fromOffsets[])
bool equal (const Vertex &a, const Vertex &b, uint32 vertexSize)
bool equalPoint (const Vertex &a, const Vertex &b)
MeshgenerateNormals (Mesh &mesh, float smoothAngle, bool weld)
MeshgenerateTangents (Mesh &mesh, bool weld)
Point2f getTexCoord (const void *vertexData, int texCoordOffset, uint32 stride, uint32 index)
Point3f getVertex (const void *vertexData, int positionOffset, uint32 stride, uint32 index)
template<typename T>
void joinVertices (vector< Face > &faces, const void *vertexData, const Mesh::VertexDescription &desc, T &comparator)
int main (int argc, char *argv[])
ModelmergeModelMeshes (const Model &model)
bool operator< (const Mesh::VertexDescription &a, const Mesh::VertexDescription &b)
bool operator< (const Mesh::VertexAttribute &a, const Mesh::VertexAttribute &b)
bool operator== (const Mesh::VertexDescription &a, const Mesh::VertexDescription &b)
bool operator== (const Mesh::VertexAttribute &a, const Mesh::VertexAttribute &b)
bool parseCommandLine (int argc, char *argv[])
bool uniquifyVertices (Mesh &mesh)
void usage ()

Variables

bool genNormals = false
bool genTangents = false
string inputFilename
bool mergeMeshes = false
bool outputBinary = false
string outputFilename
float smoothAngle = 60.0f
bool stripify = false
bool uniquify = false
unsigned int vertexCacheSize = 16
bool weldVertices = false


Typedef Documentation

typedef public std::binary_function<const Vertex&, const Vertex&, bool> VertexComparator
 

Definition at line 80 of file cmodfix.cpp.


Function Documentation

void addGroupWithOffset Mesh mesh,
const Mesh::PrimitiveGroup group,
uint32  offset
 

Definition at line 1113 of file cmodfix.cpp.

References Mesh::addGroup().

Referenced by mergeModelMeshes().

01116 {
01117     if (group.nIndices == 0)
01118         return;
01119 
01120     uint32* newIndices = new uint32[group.nIndices];
01121     for (uint32 i = 0; i < group.nIndices; i++)
01122         newIndices[i] = group.indices[i] + offset;
01123 
01124     mesh.addGroup(group.prim, group.materialIndex,
01125                   group.nIndices, newIndices);
01126 }

void augmentVertexDescription Mesh::VertexDescription desc,
Mesh::VertexAttributeSemantic  semantic,
Mesh::VertexAttributeFormat  format
 

Definition at line 471 of file cmodfix.cpp.

References Mesh::getVertexAttributeSize(), and Mesh::VertexAttribute::offset.

Referenced by generateNormals(), and generateTangents().

00474 {
00475     Mesh::VertexAttribute* attributes = new Mesh::VertexAttribute[desc.nAttributes + 1];
00476     uint32 stride = 0;
00477     uint32 nAttributes = 0;
00478     bool foundMatch = false;
00479     
00480     for (uint32 i = 0; i < desc.nAttributes; i++)
00481     {
00482         if (semantic == desc.attributes[i].semantic &&
00483             format != desc.attributes[i].format)
00484         {
00485             // The semantic matches, but the format does not; skip this
00486             // item.
00487         }
00488         else
00489         {
00490             if (semantic == desc.attributes[i].semantic)
00491                 foundMatch = true;
00492 
00493             attributes[nAttributes] = desc.attributes[i];
00494             attributes[nAttributes].offset = stride;
00495             stride += Mesh::getVertexAttributeSize(desc.attributes[i].format);
00496             nAttributes++;
00497         }
00498     }
00499 
00500     if (!foundMatch)
00501     {
00502         attributes[nAttributes++] = Mesh::VertexAttribute(semantic,
00503                                                           format,
00504                                                           stride);
00505         stride += Mesh::getVertexAttributeSize(format);
00506     }
00507 
00508     delete[] desc.attributes;
00509     desc.attributes = attributes;
00510     desc.nAttributes = nAttributes;
00511     desc.stride = stride;
00512 }

Vec3f averageFaceVectors const vector< Face > &  faces,
uint32  thisFace,
uint32 vertexFaces,
uint32  vertexFaceCount,
float  cosSmoothingAngle
 

Definition at line 420 of file cmodfix.cpp.

References Face::normal, and Vector3< T >::normalize().

Referenced by generateNormals(), and generateTangents().

00425 {
00426     const Face& face = faces[thisFace];
00427 
00428     Vec3f v = Vec3f(0, 0, 0);
00429     for (uint32 i = 0; i < vertexFaceCount; i++)
00430     {
00431         uint32 f = vertexFaces[i];
00432         float cosAngle = face.normal * faces[f].normal;
00433         if (f == thisFace || cosAngle > cosSmoothingAngle)
00434             v += faces[f].normal;
00435     }
00436 
00437     if (v * v == 0.0f)
00438         v = Vec3f(1.0f, 0.0f, 0.0f);
00439     else
00440         v.normalize();
00441 
00442     return v;
00443 }

void copyVertex void *  newVertexData,
const Mesh::VertexDescription newDesc,
const void *  oldVertexData,
const Mesh::VertexDescription oldDesc,
uint32  oldIndex,
const uint32  fromOffsets[]
 

Definition at line 447 of file cmodfix.cpp.

Referenced by generateNormals(), and generateTangents().

00453 {
00454     const char* oldVertex = reinterpret_cast<const char*>(oldVertexData) +
00455         oldDesc.stride * oldIndex;
00456     char* newVertex = reinterpret_cast<char*>(newVertexData);
00457 
00458     for (uint32 i = 0; i < newDesc.nAttributes; i++)
00459     {
00460         if (fromOffsets[i] != ~0)
00461         {
00462             memcpy(newVertex + newDesc.attributes[i].offset,
00463                    oldVertex + fromOffsets[i],
00464                    Mesh::getVertexAttributeSize(newDesc.attributes[i].format));
00465         }
00466     }
00467 }

bool equal const Vertex a,
const Vertex b,
uint32  vertexSize
 

Definition at line 215 of file cmodfix.cpp.

Referenced by uniquifyVertices().

00216 {
00217     const char* s0 = reinterpret_cast<const char*>(a.attributes);
00218     const char* s1 = reinterpret_cast<const char*>(b.attributes);
00219 
00220     for (uint32 i = 0; i < vertexSize; i++)
00221     {
00222         if (s0[i] != s1[i])
00223             return false;
00224     }
00225 
00226     return true;
00227 }

bool equalPoint const Vertex a,
const Vertex b
 

Definition at line 230 of file cmodfix.cpp.

00231 {
00232     const Point3f* p0 = reinterpret_cast<const Point3f*>(a.attributes);
00233     const Point3f* p1 = reinterpret_cast<const Point3f*>(b.attributes);
00234 
00235     return *p0 == *p1;
00236 }

Mesh* generateNormals Mesh mesh,
float  smoothAngle,
bool  weld
 

Definition at line 574 of file cmodfix.cpp.

References Mesh::addGroup(), Mesh::VertexDescription::attributes, augmentVertexDescription(), averageFaceVectors(), copyVertex(), cos(), cross(), VertexAttribute::format, Mesh::VertexDescription::getAttribute(), Mesh::getGroup(), getVertex(), Mesh::getVertexCount(), Mesh::getVertexDescription(), Face::i, Mesh::PrimitiveGroup::indices, joinVertices(), Mesh::VertexDescription::nAttributes, Mesh::PrimitiveGroup::nIndices, Face::normal, Vector3< T >::normalize(), VertexAttribute::offset, Mesh::PrimitiveGroup::prim, Mesh::setVertexDescription(), Mesh::setVertices(), smoothAngle, Mesh::VertexDescription::stride, and Face::vi.

Referenced by main().

00577 {
00578     uint32 nVertices = mesh.getVertexCount();
00579     float cosSmoothAngle = (float) cos(smoothAngle);
00580 
00581     const Mesh::VertexDescription& desc = mesh.getVertexDescription();
00582 
00583     if (desc.getAttribute(Mesh::Position).format != Mesh::Float3)
00584     {
00585         cerr << "Vertex position must be a float3\n";
00586         return NULL;
00587     }
00588     uint32 posOffset = desc.getAttribute(Mesh::Position).offset;
00589  
00590     uint32 nFaces = 0;
00591     uint32 i;
00592     for (i = 0; mesh.getGroup(i) != NULL; i++)
00593     {
00594         const Mesh::PrimitiveGroup* group = mesh.getGroup(i);
00595         
00596         switch (group->prim)
00597         {
00598         case Mesh::TriList:
00599             if (group->nIndices < 3 || group->nIndices % 3 != 0)
00600             {
00601                 cerr << "Triangle list has invalid number of indices\n";
00602                 return NULL;
00603             }
00604             nFaces += group->nIndices / 3;
00605             break;
00606 
00607         case Mesh::TriStrip:
00608         case Mesh::TriFan:
00609             if (group->nIndices < 3)
00610             {
00611                 cerr << "Error: tri strip or fan has less than three indices\n";
00612                 return NULL;
00613             }
00614             nFaces += group->nIndices - 2;
00615             break;
00616 
00617         default:
00618             cerr << "Cannot generate normals for non-triangle primitives\n";
00619             return NULL;
00620         }
00621     }
00622 
00623     // Build the array of faces; this may require decomposing triangle strips
00624     // and fans into triangle lists.
00625     vector<Face> faces(nFaces);
00626 
00627     uint32 f = 0;
00628     for (i = 0; mesh.getGroup(i) != NULL; i++)
00629     {
00630         const Mesh::PrimitiveGroup* group = mesh.getGroup(i);
00631         
00632         switch (group->prim)
00633         {
00634         case Mesh::TriList:
00635             {
00636                 for (uint32 j = 0; j < group->nIndices / 3; j++)
00637                 {
00638                     assert(f < nFaces);
00639                     faces[f].i[0] = group->indices[j * 3];
00640                     faces[f].i[1] = group->indices[j * 3 + 1];
00641                     faces[f].i[2] = group->indices[j * 3 + 2];
00642                     f++;
00643                 }
00644             }
00645             break;
00646 
00647         case Mesh::TriStrip:
00648             {
00649                 for (uint32 j = 2; j < group->nIndices; j++)
00650                 {
00651                     assert(f < nFaces);
00652                     if (j % 2 == 0)
00653                     {
00654                         faces[f].i[0] = group->indices[j - 2];
00655                         faces[f].i[1] = group->indices[j - 1];
00656                         faces[f].i[2] = group->indices[j];
00657                     }
00658                     else
00659                     {
00660                         faces[f].i[0] = group->indices[j - 1];
00661                         faces[f].i[1] = group->indices[j - 2];
00662                         faces[f].i[2] = group->indices[j];
00663                     }
00664                     f++;
00665                 }
00666             }
00667             break;
00668 
00669         case Mesh::TriFan:
00670             {
00671                 for (uint32 j = 2; j < group->nIndices; j++)
00672                 {
00673                     assert(f < nFaces);
00674                     faces[f].i[0] = group->indices[0];
00675                     faces[f].i[1] = group->indices[j - 1];
00676                     faces[f].i[2] = group->indices[j];
00677                     f++;
00678                 }
00679             }
00680             break;
00681 
00682         default:
00683             assert(0);
00684             break;
00685         }
00686     }
00687     assert(f == nFaces);
00688 
00689     const void* vertexData = mesh.getVertexData();
00690 
00691     // Compute normals for the faces
00692     for (f = 0; f < nFaces; f++)
00693     {
00694         Face& face = faces[f];
00695         Point3f p0 = getVertex(vertexData, posOffset, desc.stride, face.i[0]);
00696         Point3f p1 = getVertex(vertexData, posOffset, desc.stride, face.i[1]);
00697         Point3f p2 = getVertex(vertexData, posOffset, desc.stride, face.i[2]);
00698         face.normal = cross(p1 - p0, p2 - p1);
00699         if (face.normal * face.normal > 0.0f)
00700             face.normal.normalize();
00701     }
00702 
00703     // For each vertex, create a list of faces that contain it
00704     uint32* faceCounts = new uint32[nVertices];
00705     uint32** vertexFaces = new uint32*[nVertices];
00706 
00707     // Initialize the lists
00708     for (i = 0; i < nVertices; i++)
00709     {
00710         faceCounts[i] = 0;
00711         vertexFaces[i] = NULL;
00712     }
00713 
00714     // If we're welding vertices before generating normals, find identical
00715     // points and merge them.  Otherwise, the point indices will be the same
00716     // as the attribute indices.
00717     if (weld)
00718     {
00719         joinVertices(faces, vertexData, desc, PointComparator());
00720     }
00721     else
00722     {
00723         for (f = 0; f < nFaces; f++)
00724         {
00725             faces[f].vi[0] = faces[f].i[0];
00726             faces[f].vi[1] = faces[f].i[1];
00727             faces[f].vi[2] = faces[f].i[2];
00728         }
00729     }
00730 
00731     // Count the number of faces in which each vertex appears
00732     for (f = 0; f < nFaces; f++)
00733     {
00734         Face& face = faces[f];
00735         faceCounts[face.vi[0]]++;
00736         faceCounts[face.vi[1]]++;
00737         faceCounts[face.vi[2]]++;
00738     }
00739 
00740     // Allocate space for the per-vertex face lists
00741     for (i = 0; i < nVertices; i++)
00742     {
00743         if (faceCounts[i] > 0)
00744         {
00745             vertexFaces[i] = new uint32[faceCounts[i] + 1];
00746             vertexFaces[i][0] = faceCounts[i];
00747         }
00748     }
00749 
00750     // Fill in the vertex/face lists
00751     for (f = 0; f < nFaces; f++)
00752     {
00753         Face& face = faces[f];
00754         vertexFaces[face.vi[0]][faceCounts[face.vi[0]]--] = f;
00755         vertexFaces[face.vi[1]][faceCounts[face.vi[1]]--] = f;
00756         vertexFaces[face.vi[2]][faceCounts[face.vi[2]]--] = f;
00757     }
00758 
00759     // Compute the vertex normals by averaging
00760     vector<Vec3f> vertexNormals(nFaces * 3);
00761     for (f = 0; f < nFaces; f++)
00762     {
00763         Face& face = faces[f];
00764         for (uint32 j = 0; j < 3; j++)
00765         {
00766             vertexNormals[f * 3 + j] =
00767                 averageFaceVectors(faces, f,
00768                                    &vertexFaces[face.vi[j]][1],
00769                                    vertexFaces[face.vi[j]][0],
00770                                    cosSmoothAngle);
00771         }
00772     }
00773 
00774     // Finally, create a new mesh with normals included
00775 
00776     // Create the new vertex description
00777     Mesh::VertexDescription newDesc(desc);
00778     augmentVertexDescription(newDesc, Mesh::Normal, Mesh::Float3);
00779 
00780     // We need to convert the copy the old vertex attributes to the new
00781     // mesh.  In order to do this, we need the old offset of each attribute
00782     // in the new vertex description.  The fromOffsets array will contain
00783     // this mapping.
00784     uint32 normalOffset = 0;
00785     uint32 fromOffsets[16];
00786     for (i = 0; i < newDesc.nAttributes; i++)
00787     {
00788         fromOffsets[i] = ~0;
00789 
00790         if (newDesc.attributes[i].semantic == Mesh::Normal)
00791         {
00792             normalOffset = newDesc.attributes[i].offset;
00793         }
00794         else
00795         {
00796             for (uint32 j = 0; j < desc.nAttributes; j++)
00797             {
00798                 if (desc.attributes[j].semantic == newDesc.attributes[i].semantic)
00799                 {
00800                     assert(desc.attributes[j].format == newDesc.attributes[i].format);
00801                     fromOffsets[i] = desc.attributes[j].offset;
00802                     break;
00803                 }
00804             }
00805         }
00806     }
00807 
00808     // Copy the old vertex data along with the generated normals to the
00809     // new vertex data buffer.
00810     void* newVertexData = new char[newDesc.stride * nFaces * 3];
00811     for (f = 0; f < nFaces; f++)
00812     {
00813         Face& face = faces[f];
00814 
00815         for (uint32 j = 0; j < 3; j++)
00816         {
00817             char* newVertex = reinterpret_cast<char*>(newVertexData) +
00818                 (f * 3 + j) * newDesc.stride;
00819             copyVertex(newVertex, newDesc,
00820                        vertexData, desc,
00821                        face.i[j],
00822                        fromOffsets);
00823             memcpy(newVertex + normalOffset, &vertexNormals[f * 3 + j],
00824                    Mesh::getVertexAttributeSize(Mesh::Float3));
00825         }
00826     }
00827 
00828     // Create the Celestia mesh
00829     Mesh* newMesh = new Mesh();
00830     newMesh->setVertexDescription(newDesc);
00831     newMesh->setVertices(nFaces * 3, newVertexData);
00832 
00833     // Create a trivial index list
00834     uint32* indices = new uint32[nFaces * 3];
00835     for (i = 0; i < nFaces * 3; i++)
00836         indices[i] = i;
00837 
00838     // TODO: This assumes that the mesh uses only one material.  Normal
00839     // generation should really be done one primitive group at a time.
00840     uint32 materialIndex = mesh.getGroup(0)->materialIndex;
00841     newMesh->addGroup(Mesh::TriList, materialIndex, nFaces * 3, indices);
00842 
00843     // Clean up
00844     delete[] faceCounts;
00845     for (i = 0; i < nVertices; i++)
00846     {
00847         if (vertexFaces[i] != NULL)
00848             delete[] vertexFaces[i];
00849     }
00850     delete[] vertexFaces;
00851 
00852     return newMesh;
00853 }

Mesh* generateTangents Mesh mesh,
bool  weld
 

Definition at line 857 of file cmodfix.cpp.

References Mesh::addGroup(), Mesh::VertexDescription::attributes, augmentVertexDescription(), averageFaceVectors(), copyVertex(), VertexAttribute::format, Mesh::VertexDescription::getAttribute(), Mesh::getGroup(), getTexCoord(), getVertex(), Mesh::getVertexCount(), Mesh::getVertexDescription(), Face::i, Mesh::PrimitiveGroup::indices, joinVertices(), Mesh::VertexDescription::nAttributes, Mesh::PrimitiveGroup::nIndices, Face::normal, VertexAttribute::offset, Mesh::PrimitiveGroup::prim, Mesh::setVertexDescription(), Mesh::setVertices(), Mesh::VertexDescription::stride, Face::vi, Point2< T >::x, and Point2< T >::y.

Referenced by main().

00859 {
00860     uint32 nVertices = mesh.getVertexCount();
00861 
00862     // In order to generate tangents, we require positions, normals, and
00863     // 2D texture coordinates in the vertex description.
00864     const Mesh::VertexDescription& desc = mesh.getVertexDescription();
00865     if (desc.getAttribute(Mesh::Position).format != Mesh::Float3)
00866     {
00867         cerr << "Vertex position must be a float3\n";
00868         return NULL;
00869     }
00870 
00871     if (desc.getAttribute(Mesh::Normal).format != Mesh::Float3)
00872     {
00873         cerr << "float3 format vertex normal required\n";
00874         return NULL;
00875     }
00876 
00877     if (desc.getAttribute(Mesh::Texture0).format == Mesh::InvalidFormat)
00878     {
00879         cerr << "Texture coordinates must be present in mesh to generate tangents\n";
00880         return NULL;
00881     }
00882 
00883     if (desc.getAttribute(Mesh::Texture0).format != Mesh::Float2)
00884     {
00885         cerr << "Texture coordinate must be a float2\n";
00886         return NULL;
00887     }
00888 
00889     // Count the number of faces in the mesh.
00890     // (All geometry should already converted to triangle lists)
00891     uint32 i;
00892     uint32 nFaces = 0;
00893     for (i = 0; mesh.getGroup(i) != NULL; i++)
00894     {
00895         const Mesh::PrimitiveGroup* group = mesh.getGroup(i);
00896         if (group->prim == Mesh::TriList)
00897         {
00898             assert(group->nIndices % 3 == 0);
00899             nFaces += group->nIndices / 3;
00900         }
00901         else
00902         {
00903             cerr << "Mesh should contain just triangle lists\n";
00904             return NULL;
00905         }
00906     }
00907     
00908     // Build the array of faces; this may require decomposing triangle strips
00909     // and fans into triangle lists.
00910     vector<Face> faces(nFaces);
00911 
00912     uint32 f = 0;
00913     for (i = 0; mesh.getGroup(i) != NULL; i++)
00914     {
00915         const Mesh::PrimitiveGroup* group = mesh.getGroup(i);
00916         
00917         switch (group->prim)
00918         {
00919         case Mesh::TriList:
00920             {
00921                 for (uint32 j = 0; j < group->nIndices / 3; j++)
00922                 {
00923                     assert(f < nFaces);
00924                     faces[f].i[0] = group->indices[j * 3];
00925                     faces[f].i[1] = group->indices[j * 3 + 1];
00926                     faces[f].i[2] = group->indices[j * 3 + 2];
00927                     f++;
00928                 }
00929             }
00930             break;
00931         }
00932     }
00933 
00934     uint32 posOffset = desc.getAttribute(Mesh::Position).offset;
00935     uint32 normOffset = desc.getAttribute(Mesh::Normal).offset;
00936     uint32 texCoordOffset = desc.getAttribute(Mesh::Texture0).offset;
00937 
00938     const void* vertexData = mesh.getVertexData();
00939     
00940     // Compute tangents for faces
00941     for (f = 0; f < nFaces; f++)
00942     {
00943         Face& face = faces[f];
00944         Point3f p0 = getVertex(vertexData, posOffset, desc.stride, face.i[0]);
00945         Point3f p1 = getVertex(vertexData, posOffset, desc.stride, face.i[1]);
00946         Point3f p2 = getVertex(vertexData, posOffset, desc.stride, face.i[2]);
00947         Point2f tc0 = getTexCoord(vertexData, texCoordOffset, desc.stride, face.i[0]);
00948         Point2f tc1 = getTexCoord(vertexData, texCoordOffset, desc.stride, face.i[1]);
00949         Point2f tc2 = getTexCoord(vertexData, texCoordOffset, desc.stride, face.i[2]);
00950         float s1 = tc1.x - tc0.x;
00951         float s2 = tc2.x - tc0.x;
00952         float t1 = tc1.y - tc0.y;
00953         float t2 = tc2.y - tc0.y;
00954         float a = s1 * t2 - s2 * t1;
00955         if (a != 0.0f)
00956             face.normal = (t2 * (p1 - p0) - t1 * (p2 - p0)) * (1.0f / a);
00957         else
00958             face.normal = Vec3f(0.0f, 0.0f, 0.0f);
00959     }
00960 
00961     // For each vertex, create a list of faces that contain it
00962     uint32* faceCounts = new uint32[nVertices];
00963     uint32** vertexFaces = new uint32*[nVertices];
00964 
00965     // Initialize the lists
00966     for (i = 0; i < nVertices; i++)
00967     {
00968         faceCounts[i] = 0;
00969         vertexFaces[i] = NULL;
00970     }
00971 
00972     // If we're welding vertices before generating normals, find identical
00973     // points and merge them.  Otherwise, the point indices will be the same
00974     // as the attribute indices.
00975     if (weld)
00976     {
00977         joinVertices(faces, vertexData, desc, PointTexCoordComparator(0, 0, true));
00978     }
00979     else
00980     {
00981         for (f = 0; f < nFaces; f++)
00982         {
00983             faces[f].vi[0] = faces[f].i[0];
00984             faces[f].vi[1] = faces[f].i[1];
00985             faces[f].vi[2] = faces[f].i[2];
00986         }
00987     }
00988 
00989     // Count the number of faces in which each vertex appears
00990     for (f = 0; f < nFaces; f++)
00991     {
00992         Face& face = faces[f];
00993         faceCounts[face.vi[0]]++;
00994         faceCounts[face.vi[1]]++;
00995         faceCounts[face.vi[2]]++;
00996     }
00997 
00998     // Allocate space for the per-vertex face lists
00999     for (i = 0; i < nVertices; i++)
01000     {
01001         if (faceCounts[i] > 0)
01002         {
01003             vertexFaces[i] = new uint32[faceCounts[i] + 1];
01004             vertexFaces[i][0] = faceCounts[i];
01005         }
01006     }
01007 
01008     // Fill in the vertex/face lists
01009     for (f = 0; f < nFaces; f++)
01010     {
01011         Face& face = faces[f];
01012         vertexFaces[face.vi[0]][faceCounts[face.vi[0]]--] = f;
01013         vertexFaces[face.vi[1]][faceCounts[face.vi[1]]--] = f;
01014         vertexFaces[face.vi[2]][faceCounts[face.vi[2]]--] = f;
01015     }
01016 
01017     // Compute the vertex tangents by averaging
01018     vector<Vec3f> vertexTangents(nFaces * 3);
01019     for (f = 0; f < nFaces; f++)
01020     {
01021         Face& face = faces[f];
01022         for (uint32 j = 0; j < 3; j++)
01023         {
01024             vertexTangents[f * 3 + j] =
01025                 averageFaceVectors(faces, f,
01026                                    &vertexFaces[face.vi[j]][1],
01027                                    vertexFaces[face.vi[j]][0],
01028                                    0.0f);
01029         }
01030     }
01031 
01032     // Create the new vertex description
01033     Mesh::VertexDescription newDesc(desc);
01034     augmentVertexDescription(newDesc, Mesh::Tangent, Mesh::Float3);
01035 
01036     // We need to convert the copy the old vertex attributes to the new
01037     // mesh.  In order to do this, we need the old offset of each attribute
01038     // in the new vertex description.  The fromOffsets array will contain
01039     // this mapping.
01040     uint32 tangentOffset = 0;
01041     uint32 fromOffsets[16];
01042     for (i = 0; i < newDesc.nAttributes; i++)
01043     {
01044         fromOffsets[i] = ~0;
01045 
01046         if (newDesc.attributes[i].semantic == Mesh::Tangent)
01047         {
01048             tangentOffset = newDesc.attributes[i].offset;
01049         }
01050         else
01051         {
01052             for (uint32 j = 0; j < desc.nAttributes; j++)
01053             {
01054                 if (desc.attributes[j].semantic == newDesc.attributes[i].semantic)
01055                 {
01056                     assert(desc.attributes[j].format == newDesc.attributes[i].format);
01057                     fromOffsets[i] = desc.attributes[j].offset;
01058                     break;
01059                 }
01060             }
01061         }
01062     }
01063 
01064     // Copy the old vertex data along with the generated tangents to the
01065     // new vertex data buffer.
01066     void* newVertexData = new char[newDesc.stride * nFaces * 3];
01067     for (f = 0; f < nFaces; f++)
01068     {
01069         Face& face = faces[f];
01070 
01071         for (uint32 j = 0; j < 3; j++)
01072         {
01073             char* newVertex = reinterpret_cast<char*>(newVertexData) +
01074                 (f * 3 + j) * newDesc.stride;
01075             copyVertex(newVertex, newDesc,
01076                        vertexData, desc,
01077                        face.i[j],
01078                        fromOffsets);
01079             memcpy(newVertex + tangentOffset, &vertexTangents[f * 3 + j],
01080                    Mesh::getVertexAttributeSize(Mesh::Float3));
01081         }
01082     }
01083 
01084     // Create the Celestia mesh
01085     Mesh* newMesh = new Mesh();
01086     newMesh->setVertexDescription(newDesc);
01087     newMesh->setVertices(nFaces * 3, newVertexData);
01088 
01089     // Create a trivial index list
01090     uint32* indices = new uint32[nFaces * 3];
01091     for (i = 0; i < nFaces * 3; i++)
01092         indices[i] = i;
01093 
01094     // TODO: This assumes that the mesh uses only one material.  Tangent
01095     // generation should really be done one primitive group at a time.
01096     uint32 materialIndex = mesh.getGroup(0)->materialIndex;
01097     newMesh->addGroup(Mesh::TriList, materialIndex, nFaces * 3, indices);
01098 
01099     // Clean up
01100     delete[] faceCounts;
01101     for (i = 0; i < nVertices; i++)
01102     {
01103         if (vertexFaces[i] != NULL)
01104             delete[] vertexFaces[i];
01105     }
01106     delete[] vertexFaces;
01107 
01108     return newMesh;
01109 }

Point2f getTexCoord const void *  vertexData,
int  texCoordOffset,
uint32  stride,
uint32  index
 

Definition at line 408 of file cmodfix.cpp.

Referenced by generateTangents().

00412 {
00413     const float* fdata = reinterpret_cast<const float*>(reinterpret_cast<const char*>(vertexData) + stride * index + texCoordOffset);
00414     
00415     return Point2f(fdata[0], fdata[1]);
00416 }

Point3f getVertex const void *  vertexData,
int  positionOffset,
uint32  stride,
uint32  index
 

Definition at line 396 of file cmodfix.cpp.

Referenced by generateNormals(), and generateTangents().

00400 {
00401     const float* fdata = reinterpret_cast<const float*>(reinterpret_cast<const char*>(vertexData) + stride * index + positionOffset);
00402     
00403     return Point3f(fdata[0], fdata[1], fdata[2]);
00404 }

template<typename T>
void joinVertices vector< Face > &  faces,
const void *  vertexData,
const Mesh::VertexDescription desc,
T &  comparator
 

Definition at line 516 of file cmodfix.cpp.

References Mesh::VertexAttribute::offset.

Referenced by generateNormals(), and generateTangents().

00520 {
00521     // Don't do anything if we're given no data
00522     if (faces.size() == 0)
00523         return;
00524 
00525     // Must have a position
00526     assert(desc.getAttribute(Mesh::Position).format == Mesh::Float3);
00527 
00528     uint32 posOffset = desc.getAttribute(Mesh::Position).offset;
00529     const char* vertexPoints = reinterpret_cast<const char*>(vertexData) +
00530         posOffset;
00531     uint32 nVertices = faces.size() * 3;
00532 
00533     // Initialize the array of vertices
00534     vector<Vertex> vertices(nVertices);
00535     uint32 f;
00536     for (f = 0; f < faces.size(); f++)
00537     {
00538         for (uint32 j = 0; j < 3; j++)
00539         {
00540             uint32 index = faces[f].i[j];
00541             vertices[f * 3 + j] = Vertex(index,
00542                                          vertexPoints + desc.stride * index);
00543                                          
00544         }
00545     }
00546 
00547     // Sort the vertices so that identical ones will be ordered consecutively
00548     sort(vertices.begin(), vertices.end(), comparator);
00549 
00550     // Build the vertex merge map
00551     vector<uint32> mergeMap(nVertices);
00552     uint32 lastUnique = 0;
00553     for (uint32 i = 0; i < nVertices; i++)
00554     {
00555         if (i == 0 ||
00556             comparator.operator()(vertices[i - 1], vertices[i]) ||
00557             comparator.operator()(vertices[i], vertices[i - 1]))
00558         {
00559             lastUnique = i;
00560         }
00561         mergeMap[vertices[i].index] = vertices[lastUnique].index;
00562     }
00563 
00564     // Remap the vertex indices
00565     for (f = 0; f < faces.size(); f++)
00566     {
00567         for (uint32 k= 0; k < 3; k++)
00568             faces[f].vi[k] = mergeMap[faces[f].i[k]];
00569     }
00570 }

int main int  argc,
char *  argv[]
 

Definition at line 1397 of file cmodfix.cpp.

References Model::addMaterial(), Model::addMesh(), degToRad(), generateNormals(), generateTangents(), genNormals, genTangents, Model::getMaterial(), Model::getMesh(), inputFilename, LoadModel(), mergeMeshes, mergeModelMeshes(), outputBinary, outputFilename, parseCommandLine(), SaveModelAscii(), SaveModelBinary(), smoothAngle, stripify, uniquify, uniquifyVertices(), vertexCacheSize, and weldVertices.

01398 {
01399     if (!parseCommandLine(argc, argv))
01400     {
01401         usage();
01402         return 1;
01403     }
01404 
01405     Model* model = NULL;
01406     if (!inputFilename.empty())
01407     {
01408         ifstream in(inputFilename.c_str(), ios::in | ios::binary);
01409         if (!in.good())
01410         {
01411             cerr << "Error opening " << inputFilename << "\n";
01412             return 1;
01413         }
01414         model = LoadModel(in);
01415     }
01416     else
01417     {
01418         model = LoadModel(cin);
01419     }
01420     
01421     if (model == NULL)
01422         return 1;
01423     
01424     if (genNormals || genTangents)
01425     {
01426         Model* newModel = new Model();
01427         uint32 i;
01428 
01429         // Copy materials
01430         for (i = 0; model->getMaterial(i) != NULL; i++)
01431         {
01432             newModel->addMaterial(model->getMaterial(i));
01433         }
01434 
01435         // Generate normals and/or tangents for each model in the mesh
01436         for (i = 0; model->getMesh(i) != NULL; i++)
01437         {
01438             Mesh* mesh = model->getMesh(i);
01439             Mesh* newMesh = NULL;
01440 
01441             if (genNormals)
01442             {
01443                 newMesh = generateNormals(*mesh,
01444                                           degToRad(smoothAngle),
01445                                           weldVertices);
01446                 if (newMesh == NULL)
01447                 {
01448                     cerr << "Error generating normals!\n";
01449                     return 1;
01450                 }
01451                 // TODO: clean up old mesh
01452                 mesh = newMesh;
01453             }
01454 
01455             if (genTangents)
01456             {
01457                 newMesh = generateTangents(*mesh, weldVertices);
01458                 if (newMesh == NULL)
01459                 {
01460                     cerr << "Error generating tangents!\n";
01461                     return 1;
01462                 }
01463                 // TODO: clean up old mesh
01464                 mesh = newMesh;
01465             }
01466 
01467             newModel->addMesh(mesh);
01468         }
01469 
01470         // delete model;
01471         model = newModel;
01472     }
01473 
01474     if (mergeMeshes)
01475     {
01476         model = mergeModelMeshes(*model);
01477     }
01478 
01479     if (uniquify)
01480     {
01481         for (uint32 i = 0; model->getMesh(i) != NULL; i++)
01482         {
01483             Mesh* mesh = model->getMesh(i);
01484             uniquifyVertices(*mesh);
01485         }
01486     }
01487 
01488 #ifdef TRISTRIP
01489     if (stripify)
01490     {
01491         SetCacheSize(vertexCacheSize);
01492         for (uint32 i = 0; model->getMesh(i) != NULL; i++)
01493         {
01494             Mesh* mesh = model->getMesh(i);
01495             convertToStrips(*mesh);
01496         }
01497     }
01498 #endif
01499 
01500     if (outputFilename.empty())
01501     {
01502         if (outputBinary)
01503             SaveModelBinary(model, cout);
01504         else
01505             SaveModelAscii(model, cout);
01506     }
01507     else
01508     {
01509         ofstream out(outputFilename.c_str(),
01510                      ios::out | (outputBinary ? ios::binary : 0));
01511         if (!out.good())
01512         {
01513             cerr << "Error opening output file " << outputFilename << "\n";
01514             return 1;
01515         }
01516 
01517         if (outputBinary)
01518             SaveModelBinary(model, out);
01519         else
01520             SaveModelAscii(model, out);
01521     }
01522 
01523     return 0;
01524 }

Model* mergeModelMeshes const Model model  ) 
 

Definition at line 1131 of file cmodfix.cpp.

References addGroupWithOffset(), Model::addMaterial(), Model::addMesh(), Mesh::getGroup(), Mesh::getVertexCount(), Mesh::getVertexData(), Mesh::setVertexDescription(), Mesh::setVertices(), and Mesh::VertexDescription::stride.

Referenced by main().

01132 {
01133     vector<Mesh*> meshes;
01134 
01135     for (uint32 i = 0; model.getMesh(i) != NULL; i++)
01136     {
01137         meshes.push_back(model.getMesh(i));
01138     }
01139 
01140     // Sort the meshes by vertex description
01141     sort(meshes.begin(), meshes.end(), MeshVertexDescComparator());
01142 
01143     Model* newModel = new Model();
01144 
01145     // Copy materials into the new model
01146     for (i = 0; model.getMaterial(i) != NULL; i++)
01147     {
01148         newModel->addMaterial(model.getMaterial(i));
01149     }
01150 
01151     uint32 meshIndex = 0;
01152     while (meshIndex < meshes.size())
01153     {
01154         const Mesh::VertexDescription& desc =
01155             meshes[meshIndex]->getVertexDescription();
01156         
01157         // Count the number of matching meshes
01158         uint32 nMatchingMeshes;
01159         for (nMatchingMeshes = 1;
01160              meshIndex + nMatchingMeshes < meshes.size();
01161              nMatchingMeshes++)
01162         {
01163             if (!(meshes[meshIndex + nMatchingMeshes]->getVertexDescription() == desc))
01164             {
01165                 break;
01166             }
01167         }
01168 
01169         // Count the number of vertices in all matching meshes
01170         uint32 totalVertices = 0;
01171         uint32 j;
01172         for (j = meshIndex; j < meshIndex + nMatchingMeshes; j++)
01173         {
01174             totalVertices += meshes[j]->getVertexCount();
01175         }
01176 
01177         char* vertexData = new char[totalVertices * desc.stride];
01178 
01179         // Create the new empty mesh
01180         Mesh* mergedMesh = new Mesh();
01181         mergedMesh->setVertexDescription(desc);
01182         mergedMesh->setVertices(totalVertices, vertexData);
01183         
01184         // Copy the vertex data and reindex and add primitive groups
01185         uint32 vertexCount = 0;
01186         for (j = meshIndex; j < meshIndex + nMatchingMeshes; j++)
01187         {
01188             const Mesh* mesh = meshes[j];
01189             memcpy(vertexData + vertexCount * desc.stride,
01190                    mesh->getVertexData(),
01191                    mesh->getVertexCount() * desc.stride);
01192 
01193             for (uint32 k = 0; mesh->getGroup(k) != NULL; k++)
01194             {
01195                 addGroupWithOffset(*mergedMesh, *mesh->getGroup(k),
01196                                    vertexCount);
01197             }
01198 
01199             vertexCount += mesh->getVertexCount();
01200         }
01201         assert(vertexCount == totalVertices);
01202 
01203         newModel->addMesh(mergedMesh);
01204 
01205         meshIndex += nMatchingMeshes;
01206     }
01207 
01208     return newModel;
01209 }

bool operator< const Mesh::VertexDescription a,
const Mesh::VertexDescription b
 

Definition at line 287 of file cmodfix.cpp.

00289 {
00290     if (a.stride < b.stride)
00291         return true;
00292     else if (b.stride < a.stride)
00293         return false;
00294 
00295     if (a.nAttributes < b.nAttributes)
00296         return true;
00297     else if (b.nAttributes < b.nAttributes)
00298         return false;
00299 
00300     for (uint32 i = 0; i < a.nAttributes; i++)
00301     {
00302         if (a.attributes[i] < b.attributes[i])
00303             return true;
00304         else if (b.attributes[i] < a.attributes[i])
00305             return false;
00306     }
00307 
00308     return false;
00309 }

bool operator< const Mesh::VertexAttribute a,
const Mesh::VertexAttribute b
 

Definition at line 248 of file cmodfix.cpp.

00250 {
00251     if (a.semantic < b.semantic)
00252     {
00253         return true;
00254     }
00255     else if (b.semantic < a.semantic)
00256     {
00257         return false;
00258     }
00259     else
00260     {
00261         if (a.format < b.format)
00262             return true;
00263         else if (b.format < a.format)
00264             return false;
00265         else
00266             return a.offset < b.offset;
00267     }
00268 }

bool operator== const Mesh::VertexDescription a,
const Mesh::VertexDescription b
 

Definition at line 271 of file cmodfix.cpp.

00273 {
00274     if (a.stride != b.stride || a.nAttributes != b.nAttributes)
00275         return false;
00276 
00277     for (uint32 i = 0; i < a.nAttributes; i++)
00278     {
00279         if (!(a.attributes[i] == b.attributes[i]))
00280             return false;
00281     }
00282 
00283     return true;
00284 }

bool operator== const Mesh::VertexAttribute a,
const Mesh::VertexAttribute b
 

Definition at line 239 of file cmodfix.cpp.

00241 {
00242     return (a.semantic == b.semantic &&
00243             a.format   == b.format &&
00244             a.offset   == b.offset);
00245 }

bool parseCommandLine int  argc,
char *  argv[]
 

Definition at line 1310 of file cmodfix.cpp.

References genNormals, genTangents, inputFilename, mergeMeshes, outputBinary, outputFilename, smoothAngle, stripify, uniquify, and weldVertices.

01311 {
01312     int i = 1;
01313     int fileCount = 0;
01314 
01315     while (i < argc)
01316     {
01317         if (argv[i][0] == '-')
01318         {
01319             if (!strcmp(argv[i], "-b") || !strcmp(argv[i], "--binary"))
01320             {
01321                 outputBinary = true;
01322             }
01323             else if (!strcmp(argv[i], "-a") || !strcmp(argv[i], "--ascii"))
01324             {
01325                 outputBinary = false;
01326             }
01327             else if (!strcmp(argv[i], "-u") || !strcmp(argv[i], "--uniquify"))
01328             {
01329                 uniquify = true;
01330             }
01331             else if (!strcmp(argv[i], "-n") || !strcmp(argv[i], "--normals"))
01332             {
01333                 genNormals = true;
01334             }
01335             else if (!strcmp(argv[i], "-t") || !strcmp(argv[i], "--tangents"))
01336             {
01337                 genTangents = true;
01338             }
01339             else if (!strcmp(argv[i], "-w") || !strcmp(argv[i], "--weld"))
01340             {
01341                 weldVertices = true;
01342             }
01343             else if (!strcmp(argv[i], "-m") || !strcmp(argv[i], "--merge"))
01344             {
01345                 mergeMeshes = true;
01346             }
01347             else if (!strcmp(argv[i], "-o") || !strcmp(argv[i], "--optimize"))
01348             {
01349                 stripify = true;
01350             }
01351             else if (!strcmp(argv[i], "-s") || !strcmp(argv[i], "--smooth"))
01352             {
01353                 if (i == argc - 1)
01354                 {
01355                     return false;
01356                 }
01357                 else
01358                 {
01359                     if (sscanf(argv[i + 1], " %f", &smoothAngle) != 1)
01360                         return false;
01361                     i++;
01362                 }
01363             }
01364             else
01365             {
01366                 return false;
01367             }
01368             i++;
01369         }
01370         else
01371         {
01372             if (fileCount == 0)
01373             {
01374                 // input filename first
01375                 inputFilename = string(argv[i]);
01376                 fileCount++;
01377             }
01378             else if (fileCount == 1)
01379             {
01380                 // output filename second
01381                 outputFilename = string(argv[i]);
01382                 fileCount++;
01383             }
01384             else
01385             {
01386                 // more than two filenames on the command line is an error
01387                 return false;
01388             }
01389             i++;
01390         }
01391     }
01392 
01393     return true;
01394 }

bool uniquifyVertices Mesh mesh  ) 
 

Definition at line 331 of file cmodfix.cpp.

References equal(), and Mesh::VertexDescription::stride.

Referenced by main().

00332 {
00333     uint32 nVertices = mesh.getVertexCount();
00334     const Mesh::VertexDescription& desc = mesh.getVertexDescription();
00335 
00336     if (nVertices == 0)
00337         return false;
00338 
00339     const char* vertexData = reinterpret_cast<const char*>(mesh.getVertexData());
00340     if (vertexData == NULL)
00341         return false;
00342 
00343     // Initialize the array of vertices
00344     vector<Vertex> vertices(nVertices);
00345     uint32 i;
00346     for (i = 0; i < nVertices; i++)
00347     {
00348         vertices[i] = Vertex(i, vertexData + i * desc.stride);
00349     }
00350 
00351     // Sort the vertices so that identical ones will be ordered consecutively
00352     sort(vertices.begin(), vertices.end(), FullComparator(desc.stride));
00353 
00354     // Count the number of unique vertices
00355     uint32 uniqueVertexCount = 0;
00356     for (i = 0; i < nVertices; i++)
00357     {
00358         if (i == 0 || !equal(vertices[i - 1], vertices[i], desc.stride))
00359             uniqueVertexCount++;
00360     }
00361 
00362     // No work left to do if we couldn't eliminate any vertices
00363     if (uniqueVertexCount == nVertices)
00364         return true;
00365 
00366     // Build the vertex map and the uniquified vertex data
00367     vector<uint32> vertexMap(nVertices);
00368     char* newVertexData = new char[uniqueVertexCount * desc.stride];
00369     const char* oldVertexData = reinterpret_cast<const char*>(mesh.getVertexData());
00370     uint32 j = 0;
00371     for (i = 0; i < nVertices; i++)
00372     {
00373         if (i == 0 || !equal(vertices[i - 1], vertices[i], desc.stride))
00374         {
00375             if (i != 0)
00376                 j++;
00377             assert(j < uniqueVertexCount);
00378             memcpy(newVertexData + j * desc.stride,
00379                    oldVertexData + vertices[i].index * desc.stride,
00380                    desc.stride);
00381         }
00382         vertexMap[vertices[i].index] = j;
00383     }
00384 
00385     // Replace the vertex data with the compacted data
00386     delete mesh.getVertexData();
00387     mesh.setVertices(uniqueVertexCount, newVertexData);
00388 
00389     mesh.remapIndices(vertexMap);
00390 
00391     return true;
00392 }

void usage  ) 
 

Definition at line 42 of file cmodfix.cpp.

00043 {
00044     cerr << "Usage: cmodfix [options] [input cmod file [output cmod file]]\n";
00045     cerr << "   --binary (or -b)      : output a binary .cmod file\n";
00046     cerr << "   --ascii (or -a)       : output an ASCII .cmod file\n";
00047     cerr << "   --uniquify (or -u)    : eliminate duplicate vertices\n";
00048     cerr << "   --tangents (or -t)    : generate tangents\n";
00049     cerr << "   --normals (or -n)     : generate normals\n";
00050     cerr << "   --smooth (or -s) <angle> : smoothing angle for normal generation\n";
00051     cerr << "   --weld (or -w)        : join identical vertices before normal generation\n";
00052     cerr << "   --merge (or -m)       : merge submeshes to improve rendering performance\n";
00053 #ifdef TRISTRIP
00054     cerr << "   --optimize (or -o)    : optimize by converting triangle lists to strips\n";
00055 #endif
00056 }


Variable Documentation

bool genNormals = false
 

Definition at line 33 of file cmodfix.cpp.

Referenced by main(), and parseCommandLine().

bool genTangents = false
 

Definition at line 34 of file cmodfix.cpp.

Referenced by main(), and parseCommandLine().

string inputFilename
 

Definition at line 29 of file cmodfix.cpp.

Referenced by main(), parseCommandLine(), and WinMain().

bool mergeMeshes = false
 

Definition at line 36 of file cmodfix.cpp.

Referenced by main(), and parseCommandLine().

bool outputBinary = false
 

Definition at line 31 of file cmodfix.cpp.

Referenced by main(), and parseCommandLine().

string outputFilename
 

Definition at line 30 of file cmodfix.cpp.

Referenced by main(), parseCommandLine(), and WinMain().

float smoothAngle = 60.0f
 

Definition at line 39 of file cmodfix.cpp.

Referenced by generateNormals(), main(), and parseCommandLine().

bool stripify = false
 

Definition at line 37 of file cmodfix.cpp.

Referenced by main(), and parseCommandLine().

bool uniquify = false
 

Definition at line 32 of file cmodfix.cpp.

Referenced by main(), and parseCommandLine().

unsigned int vertexCacheSize = 16
 

Definition at line 38 of file cmodfix.cpp.

Referenced by main().

bool weldVertices = false
 

Definition at line 35 of file cmodfix.cpp.

Referenced by main(), and parseCommandLine().


Generated on Sat Jan 14 22:33:04 2006 for Celestia by  doxygen 1.4.1