#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) |
| Mesh * | generateNormals (Mesh &mesh, float smoothAngle, bool weld) |
| Mesh * | generateTangents (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[]) |
| Model * | mergeModelMeshes (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 |
|
|
Definition at line 80 of file cmodfix.cpp. |
|
||||||||||||||||
|
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 }
|
|
||||||||||||||||
|
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 }
|
|
||||||||||||||||||||||||
|
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 }
|
|
||||||||||||||||||||||||||||
|
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 }
|
|
||||||||||||||||
|
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 }
|
|
||||||||||||
|
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 }
|
|
||||||||||||||||
|
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 }
|
|
||||||||||||
|
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 }
|
|
||||||||||||||||||||
|
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 }
|
|
||||||||||||||||||||
|
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 }
|
|
||||||||||||||||||||||||
|
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 }
|
|
||||||||||||
|
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 }
|
|
|
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 }
|
|
||||||||||||
|
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 }
|
|
||||||||||||
|
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 }
|
|
||||||||||||
|
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 }
|
|
||||||||||||
|
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 }
|
|
||||||||||||
|
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 }
|
|
|
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 }
|
|
|
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 }
|
|
|
Definition at line 33 of file cmodfix.cpp. Referenced by main(), and parseCommandLine(). |
|
|
Definition at line 34 of file cmodfix.cpp. Referenced by main(), and parseCommandLine(). |
|
|
Definition at line 29 of file cmodfix.cpp. Referenced by main(), parseCommandLine(), and WinMain(). |
|
|
Definition at line 36 of file cmodfix.cpp. Referenced by main(), and parseCommandLine(). |
|
|
Definition at line 31 of file cmodfix.cpp. Referenced by main(), and parseCommandLine(). |
|
|
Definition at line 30 of file cmodfix.cpp. Referenced by main(), parseCommandLine(), and WinMain(). |
|
|
Definition at line 39 of file cmodfix.cpp. Referenced by generateNormals(), main(), and parseCommandLine(). |
|
|
Definition at line 37 of file cmodfix.cpp. Referenced by main(), and parseCommandLine(). |
|
|
Definition at line 32 of file cmodfix.cpp. Referenced by main(), and parseCommandLine(). |
|
|
Definition at line 38 of file cmodfix.cpp. Referenced by main(). |
|
|
Definition at line 35 of file cmodfix.cpp. Referenced by main(), and parseCommandLine(). |
1.4.1