1 // cmodfix.cpp
2 //
3 // Copyright (C) 2004, Chris Laurel <claurel@shatters.net>
4 //
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
9 //
10 // Perform various adjustments to a cmod file
11
12 #include <celengine/modelfile.h>
13 #include <celengine/tokenizer.h>
14 #include <celengine/texmanager.h>
15 #include <cel3ds/3dsread.h>
16 #include <celmath/mathlib.h>
17 #include <cstring>
18 #include <cassert>
19 #include <cmath>
20 #include <cstdio>
21 #include <algorithm>
22 #include <vector>
23 #ifdef TRISTRIP
24 #include <NvTriStrip.h>
25 #endif
26
27 using namespace std;
28
29 string inputFilename;
30 string outputFilename;
31 bool outputBinary = false;
32 bool uniquify = false;
33 bool genNormals = false;
34 bool genTangents = false;
35 bool weldVertices = false;
36 bool mergeMeshes = false;
37 bool stripify = false;
38 unsigned int vertexCacheSize = 16;
39 float smoothAngle = 60.0f;
40
41
usage()42 void usage()
43 {
44 cerr << "Usage: cmodfix [options] [input cmod file [output cmod file]]\n";
45 cerr << " --binary (or -b) : output a binary .cmod file\n";
46 cerr << " --ascii (or -a) : output an ASCII .cmod file\n";
47 cerr << " --uniquify (or -u) : eliminate duplicate vertices\n";
48 cerr << " --tangents (or -t) : generate tangents\n";
49 cerr << " --normals (or -n) : generate normals\n";
50 cerr << " --smooth (or -s) <angle> : smoothing angle for normal generation\n";
51 cerr << " --weld (or -w) : join identical vertices before normal generation\n";
52 cerr << " --merge (or -m) : merge submeshes to improve rendering performance\n";
53 #ifdef TRISTRIP
54 cerr << " --optimize (or -o) : optimize by converting triangle lists to strips\n";
55 #endif
56 }
57
58
59 struct Vertex
60 {
VertexVertex61 Vertex() :
62 index(0), attributes(NULL) {};
63
VertexVertex64 Vertex(uint32 _index, const void* _attributes) :
65 index(_index), attributes(_attributes) {};
66
67 uint32 index;
68 const void* attributes;
69 };
70
71
72 struct Face
73 {
74 Vec3f normal;
75 uint32 i[3]; // vertex attribute indices
76 uint32 vi[3]; // vertex point indices -- same as above unless welding
77 };
78
79
80 typedef std::binary_function<const Vertex&, const Vertex&, bool> VertexComparator;
81
82
83 class FullComparator : public VertexComparator
84 {
85 public:
FullComparator(int _vertexSize)86 FullComparator(int _vertexSize) :
87 vertexSize(_vertexSize)
88 {
89 }
90
operator ()(const Vertex & a,const Vertex & b) const91 bool operator()(const Vertex& a, const Vertex& b) const
92 {
93 const char* s0 = reinterpret_cast<const char*>(a.attributes);
94 const char* s1 = reinterpret_cast<const char*>(b.attributes);
95 for (int i = 0; i < vertexSize; i++)
96 {
97 if (s0[i] < s1[i])
98 return true;
99 else if (s0[i] > s1[i])
100 return false;
101 }
102
103 return false;
104 }
105
106 private:
107 int vertexSize;
108 };
109
110
111 class PointComparator : public VertexComparator
112 {
113 public:
PointComparator()114 PointComparator()
115 {
116 }
117
operator ()(const Vertex & a,const Vertex & b) const118 bool operator()(const Vertex& a, const Vertex& b) const
119 {
120 const Point3f* p0 = reinterpret_cast<const Point3f*>(a.attributes);
121 const Point3f* p1 = reinterpret_cast<const Point3f*>(b.attributes);
122
123 if (p0->x < p1->x)
124 {
125 return true;
126 }
127 else if (p0->x > p1->x)
128 {
129 return false;
130 }
131 else
132 {
133 if (p0->y < p1->y)
134 return true;
135 else if (p0->y > p1->y)
136 return false;
137 else
138 return p0->z < p1->z;
139 }
140 }
141
142 private:
143 int ignore;
144 };
145
146
147 class PointTexCoordComparator : public VertexComparator
148 {
149 public:
PointTexCoordComparator(uint32 _posOffset,uint32 _texCoordOffset,bool _wrap)150 PointTexCoordComparator(uint32 _posOffset,
151 uint32 _texCoordOffset,
152 bool _wrap) :
153 posOffset(_posOffset),
154 texCoordOffset(_texCoordOffset),
155 wrap(_wrap)
156 {
157 }
158
operator ()(const Vertex & a,const Vertex & b) const159 bool operator()(const Vertex& a, const Vertex& b) const
160 {
161 const char* adata = reinterpret_cast<const char*>(a.attributes);
162 const char* bdata = reinterpret_cast<const char*>(b.attributes);
163 const Point3f* p0 = reinterpret_cast<const Point3f*>(adata + posOffset);
164 const Point3f* p1 = reinterpret_cast<const Point3f*>(bdata + posOffset);
165 const Point2f* tc0 = reinterpret_cast<const Point2f*>(adata + posOffset);
166 const Point2f* tc1 = reinterpret_cast<const Point2f*>(bdata + posOffset);
167 if (p0->x < p1->x)
168 {
169 return true;
170 }
171 else if (p0->x > p1->x)
172 {
173 return false;
174 }
175 else
176 {
177 if (p0->y < p1->y)
178 {
179 return true;
180 }
181 else if (p0->y > p1->y)
182 {
183 return false;
184 }
185 else
186 {
187 if (p0->z < p1->z)
188 {
189 return true;
190 }
191 else if (p0->z > p1->z)
192 {
193 return false;
194 }
195 else
196 {
197 if (tc0->x < tc1->x)
198 return true;
199 else if (tc0->x > tc1->x)
200 return false;
201 else
202 return tc0->y < tc1->y;
203 }
204 }
205 }
206 }
207
208 private:
209 uint32 posOffset;
210 uint32 texCoordOffset;
211 bool wrap;
212 };
213
214
equal(const Vertex & a,const Vertex & b,uint32 vertexSize)215 bool equal(const Vertex& a, const Vertex& b, uint32 vertexSize)
216 {
217 const char* s0 = reinterpret_cast<const char*>(a.attributes);
218 const char* s1 = reinterpret_cast<const char*>(b.attributes);
219
220 for (uint32 i = 0; i < vertexSize; i++)
221 {
222 if (s0[i] != s1[i])
223 return false;
224 }
225
226 return true;
227 }
228
229
equalPoint(const Vertex & a,const Vertex & b)230 bool equalPoint(const Vertex& a, const Vertex& b)
231 {
232 const Point3f* p0 = reinterpret_cast<const Point3f*>(a.attributes);
233 const Point3f* p1 = reinterpret_cast<const Point3f*>(b.attributes);
234
235 return *p0 == *p1;
236 }
237
238
operator ==(const Mesh::VertexAttribute & a,const Mesh::VertexAttribute & b)239 bool operator==(const Mesh::VertexAttribute& a,
240 const Mesh::VertexAttribute& b)
241 {
242 return (a.semantic == b.semantic &&
243 a.format == b.format &&
244 a.offset == b.offset);
245 }
246
247
operator <(const Mesh::VertexAttribute & a,const Mesh::VertexAttribute & b)248 bool operator<(const Mesh::VertexAttribute& a,
249 const Mesh::VertexAttribute& b)
250 {
251 if (a.semantic < b.semantic)
252 {
253 return true;
254 }
255 else if (b.semantic < a.semantic)
256 {
257 return false;
258 }
259 else
260 {
261 if (a.format < b.format)
262 return true;
263 else if (b.format < a.format)
264 return false;
265 else
266 return a.offset < b.offset;
267 }
268 }
269
270
operator ==(const Mesh::VertexDescription & a,const Mesh::VertexDescription & b)271 bool operator==(const Mesh::VertexDescription& a,
272 const Mesh::VertexDescription& b)
273 {
274 if (a.stride != b.stride || a.nAttributes != b.nAttributes)
275 return false;
276
277 for (uint32 i = 0; i < a.nAttributes; i++)
278 {
279 if (!(a.attributes[i] == b.attributes[i]))
280 return false;
281 }
282
283 return true;
284 }
285
286
operator <(const Mesh::VertexDescription & a,const Mesh::VertexDescription & b)287 bool operator<(const Mesh::VertexDescription& a,
288 const Mesh::VertexDescription& b)
289 {
290 if (a.stride < b.stride)
291 return true;
292 else if (b.stride < a.stride)
293 return false;
294
295 if (a.nAttributes < b.nAttributes)
296 return true;
297 else if (b.nAttributes < b.nAttributes)
298 return false;
299
300 for (uint32 i = 0; i < a.nAttributes; i++)
301 {
302 if (a.attributes[i] < b.attributes[i])
303 return true;
304 else if (b.attributes[i] < a.attributes[i])
305 return false;
306 }
307
308 return false;
309 }
310
311
312 class MeshVertexDescComparator :
313 public std::binary_function<const Mesh*, const Mesh*, bool>
314 {
315 public:
MeshVertexDescComparator()316 MeshVertexDescComparator()
317 {
318 }
319
operator ()(const Mesh * a,const Mesh * b) const320 bool operator()(const Mesh* a, const Mesh* b) const
321 {
322 return a->getVertexDescription() < b->getVertexDescription();
323 }
324
325 private:
326 int ignore;
327 };
328
329
330
uniquifyVertices(Mesh & mesh)331 bool uniquifyVertices(Mesh& mesh)
332 {
333 uint32 nVertices = mesh.getVertexCount();
334 const Mesh::VertexDescription& desc = mesh.getVertexDescription();
335
336 if (nVertices == 0)
337 return false;
338
339 const char* vertexData = reinterpret_cast<const char*>(mesh.getVertexData());
340 if (vertexData == NULL)
341 return false;
342
343 // Initialize the array of vertices
344 vector<Vertex> vertices(nVertices);
345 uint32 i;
346 for (i = 0; i < nVertices; i++)
347 {
348 vertices[i] = Vertex(i, vertexData + i * desc.stride);
349 }
350
351 // Sort the vertices so that identical ones will be ordered consecutively
352 sort(vertices.begin(), vertices.end(), FullComparator(desc.stride));
353
354 // Count the number of unique vertices
355 uint32 uniqueVertexCount = 0;
356 for (i = 0; i < nVertices; i++)
357 {
358 if (i == 0 || !equal(vertices[i - 1], vertices[i], desc.stride))
359 uniqueVertexCount++;
360 }
361
362 // No work left to do if we couldn't eliminate any vertices
363 if (uniqueVertexCount == nVertices)
364 return true;
365
366 // Build the vertex map and the uniquified vertex data
367 vector<uint32> vertexMap(nVertices);
368 char* newVertexData = new char[uniqueVertexCount * desc.stride];
369 const char* oldVertexData = reinterpret_cast<const char*>(mesh.getVertexData());
370 uint32 j = 0;
371 for (i = 0; i < nVertices; i++)
372 {
373 if (i == 0 || !equal(vertices[i - 1], vertices[i], desc.stride))
374 {
375 if (i != 0)
376 j++;
377 assert(j < uniqueVertexCount);
378 memcpy(newVertexData + j * desc.stride,
379 oldVertexData + vertices[i].index * desc.stride,
380 desc.stride);
381 }
382 vertexMap[vertices[i].index] = j;
383 }
384
385 // Replace the vertex data with the compacted data
386 delete mesh.getVertexData();
387 mesh.setVertices(uniqueVertexCount, newVertexData);
388
389 mesh.remapIndices(vertexMap);
390
391 return true;
392 }
393
394
395 Point3f
getVertex(const void * vertexData,int positionOffset,uint32 stride,uint32 index)396 getVertex(const void* vertexData,
397 int positionOffset,
398 uint32 stride,
399 uint32 index)
400 {
401 const float* fdata = reinterpret_cast<const float*>(reinterpret_cast<const char*>(vertexData) + stride * index + positionOffset);
402
403 return Point3f(fdata[0], fdata[1], fdata[2]);
404 }
405
406
407 Point2f
getTexCoord(const void * vertexData,int texCoordOffset,uint32 stride,uint32 index)408 getTexCoord(const void* vertexData,
409 int texCoordOffset,
410 uint32 stride,
411 uint32 index)
412 {
413 const float* fdata = reinterpret_cast<const float*>(reinterpret_cast<const char*>(vertexData) + stride * index + texCoordOffset);
414
415 return Point2f(fdata[0], fdata[1]);
416 }
417
418
419 Vec3f
averageFaceVectors(const vector<Face> & faces,uint32 thisFace,uint32 * vertexFaces,uint32 vertexFaceCount,float cosSmoothingAngle)420 averageFaceVectors(const vector<Face>& faces,
421 uint32 thisFace,
422 uint32* vertexFaces,
423 uint32 vertexFaceCount,
424 float cosSmoothingAngle)
425 {
426 const Face& face = faces[thisFace];
427
428 Vec3f v = Vec3f(0, 0, 0);
429 for (uint32 i = 0; i < vertexFaceCount; i++)
430 {
431 uint32 f = vertexFaces[i];
432 float cosAngle = face.normal * faces[f].normal;
433 if (f == thisFace || cosAngle > cosSmoothingAngle)
434 v += faces[f].normal;
435 }
436
437 if (v * v == 0.0f)
438 v = Vec3f(1.0f, 0.0f, 0.0f);
439 else
440 v.normalize();
441
442 return v;
443 }
444
445
446 void
copyVertex(void * newVertexData,const Mesh::VertexDescription & newDesc,const void * oldVertexData,const Mesh::VertexDescription & oldDesc,uint32 oldIndex,const uint32 fromOffsets[])447 copyVertex(void* newVertexData,
448 const Mesh::VertexDescription& newDesc,
449 const void* oldVertexData,
450 const Mesh::VertexDescription& oldDesc,
451 uint32 oldIndex,
452 const uint32 fromOffsets[])
453 {
454 const char* oldVertex = reinterpret_cast<const char*>(oldVertexData) +
455 oldDesc.stride * oldIndex;
456 char* newVertex = reinterpret_cast<char*>(newVertexData);
457
458 for (uint32 i = 0; i < newDesc.nAttributes; i++)
459 {
460 if (fromOffsets[i] != ~0)
461 {
462 memcpy(newVertex + newDesc.attributes[i].offset,
463 oldVertex + fromOffsets[i],
464 Mesh::getVertexAttributeSize(newDesc.attributes[i].format));
465 }
466 }
467 }
468
469
470 void
augmentVertexDescription(Mesh::VertexDescription & desc,Mesh::VertexAttributeSemantic semantic,Mesh::VertexAttributeFormat format)471 augmentVertexDescription(Mesh::VertexDescription& desc,
472 Mesh::VertexAttributeSemantic semantic,
473 Mesh::VertexAttributeFormat format)
474 {
475 Mesh::VertexAttribute* attributes = new Mesh::VertexAttribute[desc.nAttributes + 1];
476 uint32 stride = 0;
477 uint32 nAttributes = 0;
478 bool foundMatch = false;
479
480 for (uint32 i = 0; i < desc.nAttributes; i++)
481 {
482 if (semantic == desc.attributes[i].semantic &&
483 format != desc.attributes[i].format)
484 {
485 // The semantic matches, but the format does not; skip this
486 // item.
487 }
488 else
489 {
490 if (semantic == desc.attributes[i].semantic)
491 foundMatch = true;
492
493 attributes[nAttributes] = desc.attributes[i];
494 attributes[nAttributes].offset = stride;
495 stride += Mesh::getVertexAttributeSize(desc.attributes[i].format);
496 nAttributes++;
497 }
498 }
499
500 if (!foundMatch)
501 {
502 attributes[nAttributes++] = Mesh::VertexAttribute(semantic,
503 format,
504 stride);
505 stride += Mesh::getVertexAttributeSize(format);
506 }
507
508 delete[] desc.attributes;
509 desc.attributes = attributes;
510 desc.nAttributes = nAttributes;
511 desc.stride = stride;
512 }
513
514
515 template <typename T> void
joinVertices(vector<Face> & faces,const void * vertexData,const Mesh::VertexDescription & desc,const T & comparator)516 joinVertices(vector<Face>& faces,
517 const void* vertexData,
518 const Mesh::VertexDescription& desc,
519 const T& comparator)
520 {
521 // Don't do anything if we're given no data
522 if (faces.size() == 0)
523 return;
524
525 // Must have a position
526 assert(desc.getAttribute(Mesh::Position).format == Mesh::Float3);
527
528 uint32 posOffset = desc.getAttribute(Mesh::Position).offset;
529 const char* vertexPoints = reinterpret_cast<const char*>(vertexData) +
530 posOffset;
531 uint32 nVertices = faces.size() * 3;
532
533 // Initialize the array of vertices
534 vector<Vertex> vertices(nVertices);
535 uint32 f;
536 for (f = 0; f < faces.size(); f++)
537 {
538 for (uint32 j = 0; j < 3; j++)
539 {
540 uint32 index = faces[f].i[j];
541 vertices[f * 3 + j] = Vertex(index,
542 vertexPoints + desc.stride * index);
543
544 }
545 }
546
547 // Sort the vertices so that identical ones will be ordered consecutively
548 sort(vertices.begin(), vertices.end(), comparator);
549
550 // Build the vertex merge map
551 vector<uint32> mergeMap(nVertices);
552 uint32 lastUnique = 0;
553 for (uint32 i = 0; i < nVertices; i++)
554 {
555 if (i == 0 ||
556 comparator.operator()(vertices[i - 1], vertices[i]) ||
557 comparator.operator()(vertices[i], vertices[i - 1]))
558 {
559 lastUnique = i;
560 }
561 mergeMap[vertices[i].index] = vertices[lastUnique].index;
562 }
563
564 // Remap the vertex indices
565 for (f = 0; f < faces.size(); f++)
566 {
567 for (uint32 k= 0; k < 3; k++)
568 faces[f].vi[k] = mergeMap[faces[f].i[k]];
569 }
570 }
571
572
573 Mesh*
generateNormals(Mesh & mesh,float smoothAngle,bool weld)574 generateNormals(Mesh& mesh,
575 float smoothAngle,
576 bool weld)
577 {
578 uint32 nVertices = mesh.getVertexCount();
579 float cosSmoothAngle = (float) cos(smoothAngle);
580
581 const Mesh::VertexDescription& desc = mesh.getVertexDescription();
582
583 if (desc.getAttribute(Mesh::Position).format != Mesh::Float3)
584 {
585 cerr << "Vertex position must be a float3\n";
586 return NULL;
587 }
588 uint32 posOffset = desc.getAttribute(Mesh::Position).offset;
589
590 uint32 nFaces = 0;
591 uint32 i;
592 for (i = 0; mesh.getGroup(i) != NULL; i++)
593 {
594 const Mesh::PrimitiveGroup* group = mesh.getGroup(i);
595
596 switch (group->prim)
597 {
598 case Mesh::TriList:
599 if (group->nIndices < 3 || group->nIndices % 3 != 0)
600 {
601 cerr << "Triangle list has invalid number of indices\n";
602 return NULL;
603 }
604 nFaces += group->nIndices / 3;
605 break;
606
607 case Mesh::TriStrip:
608 case Mesh::TriFan:
609 if (group->nIndices < 3)
610 {
611 cerr << "Error: tri strip or fan has less than three indices\n";
612 return NULL;
613 }
614 nFaces += group->nIndices - 2;
615 break;
616
617 default:
618 cerr << "Cannot generate normals for non-triangle primitives\n";
619 return NULL;
620 }
621 }
622
623 // Build the array of faces; this may require decomposing triangle strips
624 // and fans into triangle lists.
625 vector<Face> faces(nFaces);
626
627 uint32 f = 0;
628 for (i = 0; mesh.getGroup(i) != NULL; i++)
629 {
630 const Mesh::PrimitiveGroup* group = mesh.getGroup(i);
631
632 switch (group->prim)
633 {
634 case Mesh::TriList:
635 {
636 for (uint32 j = 0; j < group->nIndices / 3; j++)
637 {
638 assert(f < nFaces);
639 faces[f].i[0] = group->indices[j * 3];
640 faces[f].i[1] = group->indices[j * 3 + 1];
641 faces[f].i[2] = group->indices[j * 3 + 2];
642 f++;
643 }
644 }
645 break;
646
647 case Mesh::TriStrip:
648 {
649 for (uint32 j = 2; j < group->nIndices; j++)
650 {
651 assert(f < nFaces);
652 if (j % 2 == 0)
653 {
654 faces[f].i[0] = group->indices[j - 2];
655 faces[f].i[1] = group->indices[j - 1];
656 faces[f].i[2] = group->indices[j];
657 }
658 else
659 {
660 faces[f].i[0] = group->indices[j - 1];
661 faces[f].i[1] = group->indices[j - 2];
662 faces[f].i[2] = group->indices[j];
663 }
664 f++;
665 }
666 }
667 break;
668
669 case Mesh::TriFan:
670 {
671 for (uint32 j = 2; j < group->nIndices; j++)
672 {
673 assert(f < nFaces);
674 faces[f].i[0] = group->indices[0];
675 faces[f].i[1] = group->indices[j - 1];
676 faces[f].i[2] = group->indices[j];
677 f++;
678 }
679 }
680 break;
681
682 default:
683 assert(0);
684 break;
685 }
686 }
687 assert(f == nFaces);
688
689 const void* vertexData = mesh.getVertexData();
690
691 // Compute normals for the faces
692 for (f = 0; f < nFaces; f++)
693 {
694 Face& face = faces[f];
695 Point3f p0 = getVertex(vertexData, posOffset, desc.stride, face.i[0]);
696 Point3f p1 = getVertex(vertexData, posOffset, desc.stride, face.i[1]);
697 Point3f p2 = getVertex(vertexData, posOffset, desc.stride, face.i[2]);
698 face.normal = cross(p1 - p0, p2 - p1);
699 if (face.normal * face.normal > 0.0f)
700 face.normal.normalize();
701 }
702
703 // For each vertex, create a list of faces that contain it
704 uint32* faceCounts = new uint32[nVertices];
705 uint32** vertexFaces = new uint32*[nVertices];
706
707 // Initialize the lists
708 for (i = 0; i < nVertices; i++)
709 {
710 faceCounts[i] = 0;
711 vertexFaces[i] = NULL;
712 }
713
714 // If we're welding vertices before generating normals, find identical
715 // points and merge them. Otherwise, the point indices will be the same
716 // as the attribute indices.
717 if (weld)
718 {
719 joinVertices(faces, vertexData, desc, PointComparator());
720 }
721 else
722 {
723 for (f = 0; f < nFaces; f++)
724 {
725 faces[f].vi[0] = faces[f].i[0];
726 faces[f].vi[1] = faces[f].i[1];
727 faces[f].vi[2] = faces[f].i[2];
728 }
729 }
730
731 // Count the number of faces in which each vertex appears
732 for (f = 0; f < nFaces; f++)
733 {
734 Face& face = faces[f];
735 faceCounts[face.vi[0]]++;
736 faceCounts[face.vi[1]]++;
737 faceCounts[face.vi[2]]++;
738 }
739
740 // Allocate space for the per-vertex face lists
741 for (i = 0; i < nVertices; i++)
742 {
743 if (faceCounts[i] > 0)
744 {
745 vertexFaces[i] = new uint32[faceCounts[i] + 1];
746 vertexFaces[i][0] = faceCounts[i];
747 }
748 }
749
750 // Fill in the vertex/face lists
751 for (f = 0; f < nFaces; f++)
752 {
753 Face& face = faces[f];
754 vertexFaces[face.vi[0]][faceCounts[face.vi[0]]--] = f;
755 vertexFaces[face.vi[1]][faceCounts[face.vi[1]]--] = f;
756 vertexFaces[face.vi[2]][faceCounts[face.vi[2]]--] = f;
757 }
758
759 // Compute the vertex normals by averaging
760 vector<Vec3f> vertexNormals(nFaces * 3);
761 for (f = 0; f < nFaces; f++)
762 {
763 Face& face = faces[f];
764 for (uint32 j = 0; j < 3; j++)
765 {
766 vertexNormals[f * 3 + j] =
767 averageFaceVectors(faces, f,
768 &vertexFaces[face.vi[j]][1],
769 vertexFaces[face.vi[j]][0],
770 cosSmoothAngle);
771 }
772 }
773
774 // Finally, create a new mesh with normals included
775
776 // Create the new vertex description
777 Mesh::VertexDescription newDesc(desc);
778 augmentVertexDescription(newDesc, Mesh::Normal, Mesh::Float3);
779
780 // We need to convert the copy the old vertex attributes to the new
781 // mesh. In order to do this, we need the old offset of each attribute
782 // in the new vertex description. The fromOffsets array will contain
783 // this mapping.
784 uint32 normalOffset = 0;
785 uint32 fromOffsets[16];
786 for (i = 0; i < newDesc.nAttributes; i++)
787 {
788 fromOffsets[i] = ~0;
789
790 if (newDesc.attributes[i].semantic == Mesh::Normal)
791 {
792 normalOffset = newDesc.attributes[i].offset;
793 }
794 else
795 {
796 for (uint32 j = 0; j < desc.nAttributes; j++)
797 {
798 if (desc.attributes[j].semantic == newDesc.attributes[i].semantic)
799 {
800 assert(desc.attributes[j].format == newDesc.attributes[i].format);
801 fromOffsets[i] = desc.attributes[j].offset;
802 break;
803 }
804 }
805 }
806 }
807
808 // Copy the old vertex data along with the generated normals to the
809 // new vertex data buffer.
810 void* newVertexData = new char[newDesc.stride * nFaces * 3];
811 for (f = 0; f < nFaces; f++)
812 {
813 Face& face = faces[f];
814
815 for (uint32 j = 0; j < 3; j++)
816 {
817 char* newVertex = reinterpret_cast<char*>(newVertexData) +
818 (f * 3 + j) * newDesc.stride;
819 copyVertex(newVertex, newDesc,
820 vertexData, desc,
821 face.i[j],
822 fromOffsets);
823 memcpy(newVertex + normalOffset, &vertexNormals[f * 3 + j],
824 Mesh::getVertexAttributeSize(Mesh::Float3));
825 }
826 }
827
828 // Create the Celestia mesh
829 Mesh* newMesh = new Mesh();
830 newMesh->setVertexDescription(newDesc);
831 newMesh->setVertices(nFaces * 3, newVertexData);
832
833 // Create a trivial index list
834 uint32* indices = new uint32[nFaces * 3];
835 for (i = 0; i < nFaces * 3; i++)
836 indices[i] = i;
837
838 // TODO: This assumes that the mesh uses only one material. Normal
839 // generation should really be done one primitive group at a time.
840 uint32 materialIndex = mesh.getGroup(0)->materialIndex;
841 newMesh->addGroup(Mesh::TriList, materialIndex, nFaces * 3, indices);
842
843 // Clean up
844 delete[] faceCounts;
845 for (i = 0; i < nVertices; i++)
846 {
847 if (vertexFaces[i] != NULL)
848 delete[] vertexFaces[i];
849 }
850 delete[] vertexFaces;
851
852 return newMesh;
853 }
854
855
856 Mesh*
generateTangents(Mesh & mesh,bool weld)857 generateTangents(Mesh& mesh,
858 bool weld)
859 {
860 uint32 nVertices = mesh.getVertexCount();
861
862 // In order to generate tangents, we require positions, normals, and
863 // 2D texture coordinates in the vertex description.
864 const Mesh::VertexDescription& desc = mesh.getVertexDescription();
865 if (desc.getAttribute(Mesh::Position).format != Mesh::Float3)
866 {
867 cerr << "Vertex position must be a float3\n";
868 return NULL;
869 }
870
871 if (desc.getAttribute(Mesh::Normal).format != Mesh::Float3)
872 {
873 cerr << "float3 format vertex normal required\n";
874 return NULL;
875 }
876
877 if (desc.getAttribute(Mesh::Texture0).format == Mesh::InvalidFormat)
878 {
879 cerr << "Texture coordinates must be present in mesh to generate tangents\n";
880 return NULL;
881 }
882
883 if (desc.getAttribute(Mesh::Texture0).format != Mesh::Float2)
884 {
885 cerr << "Texture coordinate must be a float2\n";
886 return NULL;
887 }
888
889 // Count the number of faces in the mesh.
890 // (All geometry should already converted to triangle lists)
891 uint32 i;
892 uint32 nFaces = 0;
893 for (i = 0; mesh.getGroup(i) != NULL; i++)
894 {
895 const Mesh::PrimitiveGroup* group = mesh.getGroup(i);
896 if (group->prim == Mesh::TriList)
897 {
898 assert(group->nIndices % 3 == 0);
899 nFaces += group->nIndices / 3;
900 }
901 else
902 {
903 cerr << "Mesh should contain just triangle lists\n";
904 return NULL;
905 }
906 }
907
908 // Build the array of faces; this may require decomposing triangle strips
909 // and fans into triangle lists.
910 vector<Face> faces(nFaces);
911
912 uint32 f = 0;
913 for (i = 0; mesh.getGroup(i) != NULL; i++)
914 {
915 const Mesh::PrimitiveGroup* group = mesh.getGroup(i);
916
917 switch (group->prim)
918 {
919 case Mesh::TriList:
920 {
921 for (uint32 j = 0; j < group->nIndices / 3; j++)
922 {
923 assert(f < nFaces);
924 faces[f].i[0] = group->indices[j * 3];
925 faces[f].i[1] = group->indices[j * 3 + 1];
926 faces[f].i[2] = group->indices[j * 3 + 2];
927 f++;
928 }
929 }
930 break;
931 }
932 }
933
934 uint32 posOffset = desc.getAttribute(Mesh::Position).offset;
935 uint32 normOffset = desc.getAttribute(Mesh::Normal).offset;
936 uint32 texCoordOffset = desc.getAttribute(Mesh::Texture0).offset;
937
938 const void* vertexData = mesh.getVertexData();
939
940 // Compute tangents for faces
941 for (f = 0; f < nFaces; f++)
942 {
943 Face& face = faces[f];
944 Point3f p0 = getVertex(vertexData, posOffset, desc.stride, face.i[0]);
945 Point3f p1 = getVertex(vertexData, posOffset, desc.stride, face.i[1]);
946 Point3f p2 = getVertex(vertexData, posOffset, desc.stride, face.i[2]);
947 Point2f tc0 = getTexCoord(vertexData, texCoordOffset, desc.stride, face.i[0]);
948 Point2f tc1 = getTexCoord(vertexData, texCoordOffset, desc.stride, face.i[1]);
949 Point2f tc2 = getTexCoord(vertexData, texCoordOffset, desc.stride, face.i[2]);
950 float s1 = tc1.x - tc0.x;
951 float s2 = tc2.x - tc0.x;
952 float t1 = tc1.y - tc0.y;
953 float t2 = tc2.y - tc0.y;
954 float a = s1 * t2 - s2 * t1;
955 if (a != 0.0f)
956 face.normal = (t2 * (p1 - p0) - t1 * (p2 - p0)) * (1.0f / a);
957 else
958 face.normal = Vec3f(0.0f, 0.0f, 0.0f);
959 }
960
961 // For each vertex, create a list of faces that contain it
962 uint32* faceCounts = new uint32[nVertices];
963 uint32** vertexFaces = new uint32*[nVertices];
964
965 // Initialize the lists
966 for (i = 0; i < nVertices; i++)
967 {
968 faceCounts[i] = 0;
969 vertexFaces[i] = NULL;
970 }
971
972 // If we're welding vertices before generating normals, find identical
973 // points and merge them. Otherwise, the point indices will be the same
974 // as the attribute indices.
975 if (weld)
976 {
977 joinVertices(faces, vertexData, desc, PointTexCoordComparator(0, 0, true));
978 }
979 else
980 {
981 for (f = 0; f < nFaces; f++)
982 {
983 faces[f].vi[0] = faces[f].i[0];
984 faces[f].vi[1] = faces[f].i[1];
985 faces[f].vi[2] = faces[f].i[2];
986 }
987 }
988
989 // Count the number of faces in which each vertex appears
990 for (f = 0; f < nFaces; f++)
991 {
992 Face& face = faces[f];
993 faceCounts[face.vi[0]]++;
994 faceCounts[face.vi[1]]++;
995 faceCounts[face.vi[2]]++;
996 }
997
998 // Allocate space for the per-vertex face lists
999 for (i = 0; i < nVertices; i++)
1000 {
1001 if (faceCounts[i] > 0)
1002 {
1003 vertexFaces[i] = new uint32[faceCounts[i] + 1];
1004 vertexFaces[i][0] = faceCounts[i];
1005 }
1006 }
1007
1008 // Fill in the vertex/face lists
1009 for (f = 0; f < nFaces; f++)
1010 {
1011 Face& face = faces[f];
1012 vertexFaces[face.vi[0]][faceCounts[face.vi[0]]--] = f;
1013 vertexFaces[face.vi[1]][faceCounts[face.vi[1]]--] = f;
1014 vertexFaces[face.vi[2]][faceCounts[face.vi[2]]--] = f;
1015 }
1016
1017 // Compute the vertex tangents by averaging
1018 vector<Vec3f> vertexTangents(nFaces * 3);
1019 for (f = 0; f < nFaces; f++)
1020 {
1021 Face& face = faces[f];
1022 for (uint32 j = 0; j < 3; j++)
1023 {
1024 vertexTangents[f * 3 + j] =
1025 averageFaceVectors(faces, f,
1026 &vertexFaces[face.vi[j]][1],
1027 vertexFaces[face.vi[j]][0],
1028 0.0f);
1029 }
1030 }
1031
1032 // Create the new vertex description
1033 Mesh::VertexDescription newDesc(desc);
1034 augmentVertexDescription(newDesc, Mesh::Tangent, Mesh::Float3);
1035
1036 // We need to convert the copy the old vertex attributes to the new
1037 // mesh. In order to do this, we need the old offset of each attribute
1038 // in the new vertex description. The fromOffsets array will contain
1039 // this mapping.
1040 uint32 tangentOffset = 0;
1041 uint32 fromOffsets[16];
1042 for (i = 0; i < newDesc.nAttributes; i++)
1043 {
1044 fromOffsets[i] = ~0;
1045
1046 if (newDesc.attributes[i].semantic == Mesh::Tangent)
1047 {
1048 tangentOffset = newDesc.attributes[i].offset;
1049 }
1050 else
1051 {
1052 for (uint32 j = 0; j < desc.nAttributes; j++)
1053 {
1054 if (desc.attributes[j].semantic == newDesc.attributes[i].semantic)
1055 {
1056 assert(desc.attributes[j].format == newDesc.attributes[i].format);
1057 fromOffsets[i] = desc.attributes[j].offset;
1058 break;
1059 }
1060 }
1061 }
1062 }
1063
1064 // Copy the old vertex data along with the generated tangents to the
1065 // new vertex data buffer.
1066 void* newVertexData = new char[newDesc.stride * nFaces * 3];
1067 for (f = 0; f < nFaces; f++)
1068 {
1069 Face& face = faces[f];
1070
1071 for (uint32 j = 0; j < 3; j++)
1072 {
1073 char* newVertex = reinterpret_cast<char*>(newVertexData) +
1074 (f * 3 + j) * newDesc.stride;
1075 copyVertex(newVertex, newDesc,
1076 vertexData, desc,
1077 face.i[j],
1078 fromOffsets);
1079 memcpy(newVertex + tangentOffset, &vertexTangents[f * 3 + j],
1080 Mesh::getVertexAttributeSize(Mesh::Float3));
1081 }
1082 }
1083
1084 // Create the Celestia mesh
1085 Mesh* newMesh = new Mesh();
1086 newMesh->setVertexDescription(newDesc);
1087 newMesh->setVertices(nFaces * 3, newVertexData);
1088
1089 // Create a trivial index list
1090 uint32* indices = new uint32[nFaces * 3];
1091 for (i = 0; i < nFaces * 3; i++)
1092 indices[i] = i;
1093
1094 // TODO: This assumes that the mesh uses only one material. Tangent
1095 // generation should really be done one primitive group at a time.
1096 uint32 materialIndex = mesh.getGroup(0)->materialIndex;
1097 newMesh->addGroup(Mesh::TriList, materialIndex, nFaces * 3, indices);
1098
1099 // Clean up
1100 delete[] faceCounts;
1101 for (i = 0; i < nVertices; i++)
1102 {
1103 if (vertexFaces[i] != NULL)
1104 delete[] vertexFaces[i];
1105 }
1106 delete[] vertexFaces;
1107
1108 return newMesh;
1109 }
1110
1111
1112 void
addGroupWithOffset(Mesh & mesh,const Mesh::PrimitiveGroup & group,uint32 offset)1113 addGroupWithOffset(Mesh& mesh,
1114 const Mesh::PrimitiveGroup& group,
1115 uint32 offset)
1116 {
1117 if (group.nIndices == 0)
1118 return;
1119
1120 uint32* newIndices = new uint32[group.nIndices];
1121 for (uint32 i = 0; i < group.nIndices; i++)
1122 newIndices[i] = group.indices[i] + offset;
1123
1124 mesh.addGroup(group.prim, group.materialIndex,
1125 group.nIndices, newIndices);
1126 }
1127
1128
1129 // Merge all meshes that share the same vertex description
1130 Model*
mergeModelMeshes(const Model & model)1131 mergeModelMeshes(const Model& model)
1132 {
1133 vector<Mesh*> meshes;
1134
1135 uint32 i;
1136 for (i = 0; model.getMesh(i) != NULL; i++)
1137 {
1138 meshes.push_back(model.getMesh(i));
1139 }
1140
1141 // Sort the meshes by vertex description
1142 sort(meshes.begin(), meshes.end(), MeshVertexDescComparator());
1143
1144 Model* newModel = new Model();
1145
1146 // Copy materials into the new model
1147 for (i = 0; model.getMaterial(i) != NULL; i++)
1148 {
1149 newModel->addMaterial(model.getMaterial(i));
1150 }
1151
1152 uint32 meshIndex = 0;
1153 while (meshIndex < meshes.size())
1154 {
1155 const Mesh::VertexDescription& desc =
1156 meshes[meshIndex]->getVertexDescription();
1157
1158 // Count the number of matching meshes
1159 uint32 nMatchingMeshes;
1160 for (nMatchingMeshes = 1;
1161 meshIndex + nMatchingMeshes < meshes.size();
1162 nMatchingMeshes++)
1163 {
1164 if (!(meshes[meshIndex + nMatchingMeshes]->getVertexDescription() == desc))
1165 {
1166 break;
1167 }
1168 }
1169
1170 // Count the number of vertices in all matching meshes
1171 uint32 totalVertices = 0;
1172 uint32 j;
1173 for (j = meshIndex; j < meshIndex + nMatchingMeshes; j++)
1174 {
1175 totalVertices += meshes[j]->getVertexCount();
1176 }
1177
1178 char* vertexData = new char[totalVertices * desc.stride];
1179
1180 // Create the new empty mesh
1181 Mesh* mergedMesh = new Mesh();
1182 mergedMesh->setVertexDescription(desc);
1183 mergedMesh->setVertices(totalVertices, vertexData);
1184
1185 // Copy the vertex data and reindex and add primitive groups
1186 uint32 vertexCount = 0;
1187 for (j = meshIndex; j < meshIndex + nMatchingMeshes; j++)
1188 {
1189 const Mesh* mesh = meshes[j];
1190 memcpy(vertexData + vertexCount * desc.stride,
1191 mesh->getVertexData(),
1192 mesh->getVertexCount() * desc.stride);
1193
1194 for (uint32 k = 0; mesh->getGroup(k) != NULL; k++)
1195 {
1196 addGroupWithOffset(*mergedMesh, *mesh->getGroup(k),
1197 vertexCount);
1198 }
1199
1200 vertexCount += mesh->getVertexCount();
1201 }
1202 assert(vertexCount == totalVertices);
1203
1204 newModel->addMesh(mergedMesh);
1205
1206 meshIndex += nMatchingMeshes;
1207 }
1208
1209 return newModel;
1210 }
1211
1212
1213 #ifdef TRISTRIP
1214 bool
convertToStrips(Mesh & mesh)1215 convertToStrips(Mesh& mesh)
1216 {
1217 vector<Mesh::PrimitiveGroup*> groups;
1218
1219 // NvTriStrip library can only handle 16-bit indices
1220 if (mesh.getVertexCount() >= 0x10000)
1221 {
1222 return true;
1223 }
1224
1225 // Verify that the mesh contains just tri strips
1226 uint32 i;
1227 for (i = 0; mesh.getGroup(i) != NULL; i++)
1228 {
1229 if (mesh.getGroup(i)->prim != Mesh::TriList)
1230 return true;
1231 }
1232
1233 // Convert the existing groups to triangle strips
1234 for (i = 0; mesh.getGroup(i) != NULL; i++)
1235 {
1236 const Mesh::PrimitiveGroup* group = mesh.getGroup(i);
1237
1238 // Convert the vertex indices to shorts for the TriStrip library
1239 unsigned short* indices = new unsigned short[group->nIndices];
1240 uint32 j;
1241 for (j = 0; j < group->nIndices; j++)
1242 {
1243 indices[j] = (unsigned short) group->indices[j];
1244 }
1245
1246 PrimitiveGroup* strips = NULL;
1247 unsigned short nGroups;
1248 bool r = GenerateStrips(indices,
1249 group->nIndices,
1250 &strips,
1251 &nGroups,
1252 false);
1253 if (!r || strips == NULL)
1254 {
1255 cerr << "Generate tri strips failed\n";
1256 return false;
1257 }
1258
1259 // Call the tristrip library to convert the lists to strips. Then,
1260 // convert from the NvTriStrip's primitive group structure to the
1261 // CMOD one and add it to the collection that will be added once
1262 // the mesh's original primitive groups are cleared.
1263 for (j = 0; j < nGroups; j++)
1264 {
1265 Mesh::PrimitiveGroupType prim = Mesh::InvalidPrimitiveGroupType;
1266 switch (strips[j].type)
1267 {
1268 case PT_LIST:
1269 prim = Mesh::TriList;
1270 break;
1271 case PT_STRIP:
1272 prim = Mesh::TriStrip;
1273 break;
1274 case PT_FAN:
1275 prim = Mesh::TriFan;
1276 break;
1277 }
1278
1279 if (prim != Mesh::InvalidPrimitiveGroupType &&
1280 strips[j].numIndices != 0)
1281 {
1282 Mesh::PrimitiveGroup* newGroup = new Mesh::PrimitiveGroup();
1283 newGroup->prim = prim;
1284 newGroup->materialIndex = group->materialIndex;
1285 newGroup->nIndices = strips[j].numIndices;
1286 newGroup->indices = new uint32[newGroup->nIndices];
1287 for (uint32 k = 0; k < newGroup->nIndices; k++)
1288 newGroup->indices[k] = strips[j].indices[k];
1289
1290 groups.push_back(newGroup);
1291 }
1292 }
1293
1294 delete[] strips;
1295 }
1296
1297 mesh.clearGroups();
1298
1299 // Add the stripified groups to the mesh
1300 for (vector<Mesh::PrimitiveGroup*>::const_iterator iter = groups.begin();
1301 iter != groups.end(); iter++)
1302 {
1303 mesh.addGroup(*iter);
1304 }
1305
1306 return true;
1307 }
1308 #endif
1309
1310
parseCommandLine(int argc,char * argv[])1311 bool parseCommandLine(int argc, char* argv[])
1312 {
1313 int i = 1;
1314 int fileCount = 0;
1315
1316 while (i < argc)
1317 {
1318 if (argv[i][0] == '-')
1319 {
1320 if (!strcmp(argv[i], "-b") || !strcmp(argv[i], "--binary"))
1321 {
1322 outputBinary = true;
1323 }
1324 else if (!strcmp(argv[i], "-a") || !strcmp(argv[i], "--ascii"))
1325 {
1326 outputBinary = false;
1327 }
1328 else if (!strcmp(argv[i], "-u") || !strcmp(argv[i], "--uniquify"))
1329 {
1330 uniquify = true;
1331 }
1332 else if (!strcmp(argv[i], "-n") || !strcmp(argv[i], "--normals"))
1333 {
1334 genNormals = true;
1335 }
1336 else if (!strcmp(argv[i], "-t") || !strcmp(argv[i], "--tangents"))
1337 {
1338 genTangents = true;
1339 }
1340 else if (!strcmp(argv[i], "-w") || !strcmp(argv[i], "--weld"))
1341 {
1342 weldVertices = true;
1343 }
1344 else if (!strcmp(argv[i], "-m") || !strcmp(argv[i], "--merge"))
1345 {
1346 mergeMeshes = true;
1347 }
1348 else if (!strcmp(argv[i], "-o") || !strcmp(argv[i], "--optimize"))
1349 {
1350 stripify = true;
1351 }
1352 else if (!strcmp(argv[i], "-s") || !strcmp(argv[i], "--smooth"))
1353 {
1354 if (i == argc - 1)
1355 {
1356 return false;
1357 }
1358 else
1359 {
1360 if (sscanf(argv[i + 1], " %f", &smoothAngle) != 1)
1361 return false;
1362 i++;
1363 }
1364 }
1365 else
1366 {
1367 return false;
1368 }
1369 i++;
1370 }
1371 else
1372 {
1373 if (fileCount == 0)
1374 {
1375 // input filename first
1376 inputFilename = string(argv[i]);
1377 fileCount++;
1378 }
1379 else if (fileCount == 1)
1380 {
1381 // output filename second
1382 outputFilename = string(argv[i]);
1383 fileCount++;
1384 }
1385 else
1386 {
1387 // more than two filenames on the command line is an error
1388 return false;
1389 }
1390 i++;
1391 }
1392 }
1393
1394 return true;
1395 }
1396
1397
main(int argc,char * argv[])1398 int main(int argc, char* argv[])
1399 {
1400 if (!parseCommandLine(argc, argv))
1401 {
1402 usage();
1403 return 1;
1404 }
1405
1406 Model* model = NULL;
1407 if (!inputFilename.empty())
1408 {
1409 ifstream in(inputFilename.c_str(), ios::in | ios::binary);
1410 if (!in.good())
1411 {
1412 cerr << "Error opening " << inputFilename << "\n";
1413 return 1;
1414 }
1415 model = LoadModel(in);
1416 }
1417 else
1418 {
1419 model = LoadModel(cin);
1420 }
1421
1422 if (model == NULL)
1423 return 1;
1424
1425 if (genNormals || genTangents)
1426 {
1427 Model* newModel = new Model();
1428 uint32 i;
1429
1430 // Copy materials
1431 for (i = 0; model->getMaterial(i) != NULL; i++)
1432 {
1433 newModel->addMaterial(model->getMaterial(i));
1434 }
1435
1436 // Generate normals and/or tangents for each model in the mesh
1437 for (i = 0; model->getMesh(i) != NULL; i++)
1438 {
1439 Mesh* mesh = model->getMesh(i);
1440 Mesh* newMesh = NULL;
1441
1442 if (genNormals)
1443 {
1444 newMesh = generateNormals(*mesh,
1445 degToRad(smoothAngle),
1446 weldVertices);
1447 if (newMesh == NULL)
1448 {
1449 cerr << "Error generating normals!\n";
1450 return 1;
1451 }
1452 // TODO: clean up old mesh
1453 mesh = newMesh;
1454 }
1455
1456 if (genTangents)
1457 {
1458 newMesh = generateTangents(*mesh, weldVertices);
1459 if (newMesh == NULL)
1460 {
1461 cerr << "Error generating tangents!\n";
1462 return 1;
1463 }
1464 // TODO: clean up old mesh
1465 mesh = newMesh;
1466 }
1467
1468 newModel->addMesh(mesh);
1469 }
1470
1471 // delete model;
1472 model = newModel;
1473 }
1474
1475 if (mergeMeshes)
1476 {
1477 model = mergeModelMeshes(*model);
1478 }
1479
1480 if (uniquify)
1481 {
1482 for (uint32 i = 0; model->getMesh(i) != NULL; i++)
1483 {
1484 Mesh* mesh = model->getMesh(i);
1485 uniquifyVertices(*mesh);
1486 }
1487 }
1488
1489 #ifdef TRISTRIP
1490 if (stripify)
1491 {
1492 SetCacheSize(vertexCacheSize);
1493 for (uint32 i = 0; model->getMesh(i) != NULL; i++)
1494 {
1495 Mesh* mesh = model->getMesh(i);
1496 convertToStrips(*mesh);
1497 }
1498 }
1499 #endif
1500
1501 if (outputFilename.empty())
1502 {
1503 if (outputBinary)
1504 SaveModelBinary(model, cout);
1505 else
1506 SaveModelAscii(model, cout);
1507 }
1508 else
1509 {
1510 ofstream out(outputFilename.c_str(),
1511 outputBinary ? (ios::binary|ios::out) : ios::out);
1512 if (!out.good())
1513 {
1514 cerr << "Error opening output file " << outputFilename << "\n";
1515 return 1;
1516 }
1517
1518 if (outputBinary)
1519 SaveModelBinary(model, out);
1520 else
1521 SaveModelAscii(model, out);
1522 }
1523
1524 return 0;
1525 }
1526