Developer Documentation

- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
MeshCompiler.cc
1 /*===========================================================================*\
2 * *
3 * OpenFlipper *
4 * Copyright (c) 2001-2015, RWTH-Aachen University *
5 * Department of Computer Graphics and Multimedia *
6 * All rights reserved. *
7 * www.openflipper.org *
8 * *
9 *---------------------------------------------------------------------------*
10 * This file is part of OpenFlipper. *
11 *---------------------------------------------------------------------------*
12 * *
13 * Redistribution and use in source and binary forms, with or without *
14 * modification, are permitted provided that the following conditions *
15 * are met: *
16 * *
17 * 1. Redistributions of source code must retain the above copyright notice, *
18 * this list of conditions and the following disclaimer. *
19 * *
20 * 2. Redistributions in binary form must reproduce the above copyright *
21 * notice, this list of conditions and the following disclaimer in the *
22 * documentation and/or other materials provided with the distribution. *
23 * *
24 * 3. Neither the name of the copyright holder nor the names of its *
25 * contributors may be used to endorse or promote products derived from *
26 * this software without specific prior written permission. *
27 * *
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
30 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
31 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
32 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
33 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
34 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
35 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
36 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
37 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
38 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
39 * *
40 \*===========================================================================*/
41
42 /*===========================================================================*\
43 * *
44 * $Revision$ *
45 * $LastChangedBy$ *
46 * $Date$ *
47 * *
48 \*===========================================================================*/
49
50
51 #include "MeshCompiler.hh"
52
53 #include <iostream>
54 #include <sstream>
55
56 #ifdef USE_OPENMP
57 #endif
58
59 #ifdef ACG_MC_USE_STL_HASH
60 #include <unordered_map> // requires c++0x
61 #else
62 #include <QHash> // alternative to unordered_map
63 #endif // ACG_MC_USE_STL_HASH
64
65 #include <ACG/Geometry/GPUCacheOptimizer.hh>
66 #include <ACG/Geometry/Triangulator.hh>
67
68 namespace ACG{
69
70 /*
71 use case
72
73
74 mesh with float3 pos, float2 uv, float3 n:
75
76 VertexElement elements[] = {{..}, ..};
77 VertexDeclaration decl;
78
79 decl.addElement(..float3 position..)
80 decl.addElement(..float2 uv..)
81 decl.addElement(..float3 normal..)
82
83 MeshCompiler mesh(decl);
84
85 mesh.setVertices(..)
86 mesh.setNormals(..)
87 mesh.setTexCoords(..)
88
89
90 mesh.setNumFaces(333);
91 mesh.setTriangles(indexBuffer);
92 for each face i
93 mesh.setFaceMaterial(i, matID)
94
95 mesh.compile(FLAG_OPTIMIZE | FLAG_COMPUTE_TANGENTS | FLAG_STATIC)
96 */
97
98
99 /* TODO
100 - default declaration (declaration can not be changed afterwards)
101 float3 pos, float2 uv, float3 normal
102
103 - option to set triangle input buffer
104
105 - compile function with options
106 FLAG_OPTIMIZE : optimize for better gpu cache usage
107 FLAG_COMPUTE_TANGENTS : compute tangent vectors if tangent slots are available in buffer layout
108 FLAG_STATIC : no update needed in future
109 */
110
111
112 MeshCompilerVertexCompare MeshCompiler::defaultVertexCompare;
113
114 void MeshCompiler::AdjacencyList::init( int n )
115 {
116 delete [] start;
117 delete [] buf;
118 delete [] count;
119
120 num = n;
121 start = new int[n];
122 count = new unsigned char[n];
123
124 buf = 0; // unknown buffer length
125
126 // invalidate start indices
127 memset(start, -1, n * sizeof(int));
128
129 // reset count
130 memset(count, 0, n * sizeof(unsigned char));
131 }
132
133 int MeshCompiler::AdjacencyList::getAdj( const int i, const int k ) const
134 {
135 assert(k < count[i]);
136 assert(k > -1);
137
138 int st = start[i];
139 assert(st > -1);
140
141 return buf[st + k];
142 }
143
144 int MeshCompiler::AdjacencyList::getCount( const int i ) const
145 {
146 return count[i];
147 }
148
149 void MeshCompiler::AdjacencyList::clear()
150 {
151 num = 0;
152 delete [] start; start = 0;
153 delete [] buf; buf = 0;
154 delete [] count; count = 0;
155 bufSize = 0;
156 }
157
158
159
160 void MeshCompiler::computeAdjacency()
161 {
162 const int numVerts = input_[inputIDPos_].count;
163
164 // ==============================================================
165 // compute vertex -> face adjacency
166
167 // count total number of adjacency entries
168 // store adj entries in a single tightly packed buffer
169
170 // check if user provided adjacency information
171 if (faceInput_->getVertexAdjCount(0) < 0 && adjacencyVert_.bufSize <= 0)
172 {
173 adjacencyVert_.init(numVerts);
174
175 // count # adjacent faces per vertex
176 for (int i = 0; i < numFaces_; ++i)
177 {
178 int nCorners = getFaceSize(i);
179
180 for (int k = 0; k < nCorners; ++k)
181 {
182 // int vertex = faceInput_->getSingleFaceAttr(i, k, inputIDPos_);
183 int vertex = getInputIndex(i, k, inputIDPos_);
184
185 adjacencyVert_.count[vertex]++;
186 }
187 }
188
189
190 // count num of needed entries
191 int nCounter = 0;
192
193 for (int i = 0; i < numVerts; ++i)
194 {
195 adjacencyVert_.start[i] = nCounter; // save start indices
196
197 nCounter += adjacencyVert_.count[i];
198
199 adjacencyVert_.count[i] = 0; // count gets recomputed in next step
200 }
201
202 // alloc memory
203 adjacencyVert_.buf = new int[nCounter];
204 adjacencyVert_.bufSize = nCounter;
205
206 // build adjacency list
207 for (int i = 0; i < numFaces_; ++i)
208 {
209 int nCorners = getFaceSize(i);
210
211 for (int k = 0; k < nCorners; ++k)
212 {
213 // int vertex = faceInput_->getSingleFaceAttr(i, k, inputIDPos_);
214 int vertex = getInputIndex(i, k, inputIDPos_);
215 int adjIdx = adjacencyVert_.start[vertex] + adjacencyVert_.count[vertex]++;
216
217 adjacencyVert_.buf[ adjIdx ] = i;
218 }
219 }
220
222 // debug version:
223 // dump computed and external adjacency for comparison
224 // dbgdumpAdjList("dbg_adjacency_mc.txt");
225 //
226 // if (faceInput_->getVertexAdjCount(0) >= 0)
227 // {
228 // FILE* file = 0;
229 // file = fopen("dbg_adjacency_ext.txt", "wt");
230 //
231 // if (file)
232 // {
233 // fprintf(file, "vertex-adjacency: \n");
234 // for (int i = 0; i < input_[inputIDPos_].count; ++i)
235 // {
236 // // sorting the adjacency list for easy comparison of adjacency input
237 // int count = faceInput_->getVertexAdjCount(i);
238 //
239 // std::vector<int> sortedList(count);
240 // for (int k = 0; k < count; ++k)
241 // sortedList[k] = faceInput_->getVertexAdjFace(i, k);
242 //
243 // std::sort(sortedList.begin(), sortedList.end());
244 //
245 // for (int k = 0; k < count; ++k)
246 // fprintf(file, "adj[%d][%d] = %d\n", i, k, sortedList[k]);
247 // }
248 //
249 //
250 // fclose(file);
251 // }
252 // }
253
254 }
255
256 }
257
258
259 void MeshCompiler::setVertices( int _num, const void* _data, int _stride, bool _internalCopy /*= false*/, GLuint _fmt, int _elementSize )
260 {
261 setAttribVec(inputIDPos_, _num, _data, _stride, _internalCopy, _fmt, _elementSize);
262 }
263
264 void MeshCompiler::setNormals( int _num, const void* _data, int _stride, bool _internalCopy /*= false*/, GLuint _fmt, int _elementSize )
265 {
266 setAttribVec(inputIDNorm_, _num, _data, _stride, _internalCopy, _fmt, _elementSize);
267 }
268
269 void MeshCompiler::setTexCoords( int _num, const void* _data, int _stride, bool _internalCopy /*= false*/, GLuint _fmt, int _elementSize )
270 {
271 setAttribVec(inputIDTexC_, _num, _data, _stride, _internalCopy, _fmt, _elementSize);
272 }
273
274
275 void MeshCompiler::setAttribVec(int _attrIdx, int _num, const void* _data, int _stride, bool _internalCopy /*= false*/, GLuint _fmt, int _elementSize)
276 {
277 // sets vertex data for each attribute individually
278 // Example:
279 // Format: float3 pos, float2 uv, float3 normal has 3 attribute vectors, that store all positions, texcoords etc. of the mesh
280 // - positions: float3[n1] n1: number of positions
281 // - texcoords: float2[n2] n2: number of texcoords
282 // - normals: float3[n3] n3: number of normals
283 // the vector sizes n1, n2, n3 do not have to be equal!
284
285 if (_attrIdx < 0)
286 return;
287
288 assert(_attrIdx < (int)decl_.getNumElements());
289
290 VertexElementInput* inbuf = input_ + _attrIdx;
291
292 inbuf->count = _num;
293
294 // size in bytes of one vertex element (eg. 12 for float3 element)
295 int size = inbuf->attrSize = (int)VertexDeclaration::getElementSize(decl_.getElement(_attrIdx));
296
297
298 // make an internal copy of the input if the user can not guarantee, that the data address is permanently valid
299 if (_internalCopy)
300 {
301 delete [] inbuf->internalBuf;
302 inbuf->internalBuf = new char[size * _num];
303 inbuf->data = inbuf->internalBuf;
304
305 inbuf->stride = size;
306
307 if (_data)
308 {
309 // copy elementwise because of striding
310 for (int i = 0; i < _num; ++i)
311 {
312 memcpy(inbuf->internalBuf + (size_t)(size * i),
313 (const char*)_data + (size_t)(_stride * i),
314 size);
315 }
316 }
317 }
318 else
319 {
320 // store data address only without making a copy
321 inbuf->data = (const char*)_data;
322 inbuf->stride = _stride ? _stride : size;
323
324 delete [] inbuf->internalBuf;
325 inbuf->internalBuf = 0;
326 }
327
328
329 inbuf->fmt = _fmt;
330 inbuf->elementSize = _elementSize;
331 }
332
333 void MeshCompiler::WeldList::add(const int _face, const int _corner)
334 {
335 const int stride = meshComp->getVertexDeclaration()->getVertexStride();
336
337 // pointer address to vertex data
338 char* vtx0 = workBuf + stride * list.size();
339 char* vtx1 = workBuf;
340
341 // query vertex data
342 meshComp->getInputFaceVertexData(_face, _corner, vtx0);
343
344 bool matched = false;
345
346 // search for same vertex that is referenced already
347 for (size_t i = 0; i < list.size() && !matched; ++i)
348 {
349 WeldListEntry* it = &list[i];
350 // query referenced vertex data
351
352 // compare vertices
353 if (cmpFunc->equalVertex(vtx0, vtx1, meshComp->getVertexDeclaration()))
354 {
355 // found duplicate vertex
356 // -> remap index data s.t. only one these two vertices is referenced
357
358 WeldListEntry e;
359 e.faceId = _face; e.cornerId = _corner;
360 e.refFaceId = it->refFaceId; e.refCornerId = it->refCornerId;
361
362 list.push_back(e);
363
364 matched = true;
365 }
366
367 vtx1 += stride;
368 }
369
370 // unreferenced vertex
371 if (!matched)
372 {
373 WeldListEntry e;
374 e.faceId = _face; e.cornerId = _corner;
375 e.refFaceId = _face; e.refCornerId = _corner;
376
377 list.push_back(e);
378 }
379
380 }
381
382 void MeshCompiler::weldVertices()
383 {
384 const int numVerts = input_[inputIDPos_].count;
385
386 // clear weld map
387 vertexWeldMapFace_.resize(numIndices_, -1);
388 vertexWeldMapCorner_.resize(numIndices_, -1);
389
390 // alloc buffer to query vertex data
391 int maxAdjCount = 0;
392 for (int i = 0; i < numVerts; ++i)
393 {
394 const int n = getAdjVertexFaceCount(i);
395 maxAdjCount = std::max(n, maxAdjCount);
396 }
397
398 // OPTIMIZATION: Now the vertex compare buffer works as a vertex cache, storing interpreted vertex data.
399 // Thus, each vertex has to be interpreted only once ( when it gets inserted into the welding list )
400 char* vtxCompBuf = new char[decl_.getVertexStride() * (maxAdjCount + 1)];
401
402 WeldList weldList;
403 weldList.meshComp = this;
404 weldList.cmpFunc = vertexCompare_;
405 weldList.workBuf = vtxCompBuf;
406
407 weldList.list.reserve(maxAdjCount);
408
409 for (int i = 0; i < numVerts; ++i)
410 {
411 // OPTIMIZATION: Moved constructor/destructor of WeldList out of for-loop
412 // Create welding list for each vertex.
413 weldList.list.clear();
414
415 // Search for candidates in adjacent faces
416 for (int k = 0; k < getAdjVertexFaceCount(i); ++k)
417 {
418 const int adjFace = getAdjVertexFace(i, k);
419
420 // find corner id of adj face
421 int adjCornerId = -1;
422 for (int m = 0; m < getFaceSize(adjFace); ++m)
423 {
424 const int adjVertex = getInputIndex(adjFace, m, inputIDPos_);
425
426 if (adjVertex == i)
427 {
428 adjCornerId = m;
429 break;
430 }
431 }
432
433 assert(adjCornerId != -1);
434
435
436 // check for existing entry
437 const int weldMapOffset = getInputFaceOffset(adjFace) + adjCornerId;
438
439 if (vertexWeldMapFace_[weldMapOffset] >= 0)
440 continue; // skip
441
442 weldList.add(adjFace, adjCornerId);
443 }
444
445
446 // apply local WeldList of a vertex to global weld map
447
448 for (size_t e = 0; e < weldList.list.size(); ++e)
449 {
450 const WeldListEntry* it = &weldList.list[e];
451 const int weldMapOffset = getInputFaceOffset(it->faceId) + it->cornerId;
452
453 if (vertexWeldMapFace_[weldMapOffset] >= 0)
454 continue; // skip
455
456 // store in map
457 vertexWeldMapFace_[weldMapOffset] = it->refFaceId;
458 vertexWeldMapCorner_[weldMapOffset] = it->refCornerId;
459 }
460 }
461
462
463 // -------------------------------------------------------------
464 // Alternative method that avoids iterating over adjacency list at cost of higher memory load
465 // Could not measure any noticeable difference in run-time performance.
466 //
467 // std::vector< std::vector< std::pair<int,int> > > VertexColMap;
468 // VertexColMap.resize(numVerts);
469 //
470 // for (int i = 0; i < numVerts; ++i)
471 // VertexColMap[i].reserve( getAdjVertexFaceCount(i) );
472 //
473 // for (int i = 0; i < numFaces_; ++i)
474 // {
475 // for (int k = 0; k < getFaceSize(i); ++k)
476 // {
477 // int v = faceInput_->getSingleFaceAttr(i, k, inputIDPos_);
478 //
479 // VertexColMap[v].push_back( std::pair<int,int>(i,k) );
480 // }
481 // }
482 //
483 // for (int i = 0; i < numVerts; ++i)
484 // {
485 // // Create welding list for each vertex.
486 // WeldList weldList;
487 // weldList.meshComp = this;
488 // weldList.cmpFunc = vertexCompare_;
489 // weldList.workBuf = vtxCompBuf;
490 //
491 // for (int k = 0; k < VertexColMap[i].size(); ++k)
492 // weldList.add(VertexColMap[i][k].first, VertexColMap[i][k].second);
493 //
494 // // apply local WeldList of a vertex to global weld map
495 //
496 // // for (std::list< WeldListEntry >::iterator it = weldList.list.begin();
497 // // it != weldList.list.end(); ++ it)
498 // for (size_t e = 0; e < weldList.list.size(); ++e)
499 // {
500 // const WeldListEntry* it = &weldList.list[e];
501 // const int weldMapOffset = getInputFaceOffset(it->faceId) + it->cornerId;
502 //
503 // // if (vertexWeldMap_[weldMapOffset].first >= 0)
504 // if (vertexWeldMapFace_[weldMapOffset] >= 0)
505 // continue; // skip
506 //
507 // // store in map
508 // // vertexWeldMap_[weldMapOffset] = std::pair<int, int> ( it->refFaceId, it->refCornerId );
509 // vertexWeldMapFace_[weldMapOffset] = it->refFaceId;
510 // vertexWeldMapCorner_[weldMapOffset] = it->refCornerId;
511 // }
512 // }
513 // // -------------------------------------------------------------
514
515
516 // fix incomplete welding map (isolated vertices)
517 fixWeldMap();
518
519 delete [] vtxCompBuf;
520 }
521
522 void MeshCompiler::fixWeldMap()
523 {
524 for (int i = 0; i < numFaces_; ++i)
525 {
526 const int fsize = getFaceSize(i);
527 for (int k = 0; k < fsize; ++k)
528 {
529 const int weldMapOffset = getInputFaceOffset(i) + k;
530
531 // if a (face,corner) pair is mapped to an invalid value, make it valid by mapping to itself
532 // invalid value is caused by isolated vertices
533 if (vertexWeldMapFace_[weldMapOffset] < 0)
534 {
535 vertexWeldMapFace_[weldMapOffset] = i;
536 vertexWeldMapCorner_[weldMapOffset] = k;
537 }
538 }
539 }
540 }
541
542 void MeshCompiler::findIsolatedVertices()
543 {
544 const int nVerts = input_[inputIDPos_].count;
545
546 numIsolatedVerts_ = 0;
547 // For each vertex check if there exists a reference in the splitting list. We have found an isolated vertex if there is no reference.
548 // Checking the vertex-face adjacency count is also possible to detect isolated vertices.
549
550 for (int i = 0; i < nVerts; ++i)
551 {
552 if (splitter_->isIsolated(i))
553 ++numIsolatedVerts_;
554 }
555
556 isolatedVertices_.clear();
557 isolatedVertices_.reserve(numIsolatedVerts_);
558 for (int i = 0; i < nVerts; ++i)
559 {
560 if (splitter_->isIsolated(i))
561 isolatedVertices_.push_back(i);
562 }
563 }
564
565 void MeshCompiler::splitVertices()
566 {
567 /* algorithm overview
568
569 we split by indices only,
570 actual vertex data will not be taken into account.
571
572 thus if the input contains two vertices with the same value,
573 they still are treated as different vertices since they have different indices
574
575
576 a shared vertex gets split whenever at least one attribute
577 changes with respect to the face.
578 i.e. one face wants to combine vertex i with attribute j
579 while another face needs it with attribute k
580
581 example:
582
583 face 0 and 5 share vertex v3
584
585 face 0 uses v3 combined with normal n0,
586 but face 5 wants to have v3 with normal n1
587
588
589 we look up if v3 has been split up already and search
590 for a v3-n0 combination
591 eventually this combination is added to the splitting list
592
593 repeat for the v3-n1 combination
594
595 */
596
597 const int numPositions = input_[inputIDPos_].count;
598
599 // estimate number of splits to avoid resizing too often
600 int estimatedSplitCount = 0;
601 int numDifferentInputCounts = 0;
602
603 // simple heuristic:
604 // if the number of elements of an arbitrary attribute is larger than the number of positions, add the difference to the number of splits
605 // the actual number of splits may be larger, in which case the array has to be resized.
606 for (int i = 0; i < numAttributes_; ++i)
607 {
608 if (i != inputIDPos_)
609 {
610 if (input_[i].count > numPositions)
611 {
612 const int diff = input_[i].count - numPositions;
613
614 if (diff > 0)
615 {
616 estimatedSplitCount = std::max(diff, estimatedSplitCount);
617 ++numDifferentInputCounts;
618 }
619 }
620 }
621 }
622
623 if (numDifferentInputCounts > 1)
624 {
625 // estimation probably too small, increase by 20 %
626 estimatedSplitCount = int(float(estimatedSplitCount) * 1.2f);
627 }
628
629 assert(estimatedSplitCount >= 0);
630
631 // worst case: each vertex can be used by only one face
632 // clamp estimation-count accordingly
633
634 int maxSplitCount = 0;
635
636 if (numIndices_ > 0)
637 {
638 if (numIndices_ > numPositions)
639 maxSplitCount = numIndices_ - numPositions;
640 }
641 else
642 {
643 // numIndices_ is unknown
644 int sumFaceSize = 0;
645
646 if (constantFaceSize_)
647 sumFaceSize = numFaces_ * maxFaceSize_;
648 else
649 {
650 for (int i = 0; i < numFaces_; ++i)
651 sumFaceSize += getFaceSize(i);
652 }
653
654 if (sumFaceSize > numPositions)
655 maxSplitCount = sumFaceSize - numPositions;
656 }
657
658 estimatedSplitCount = std::min(estimatedSplitCount, maxSplitCount);
659
660 // std::cout << "estimated split count: " << estimatedSplitCount << std::endl;
661
662 // split vertices such that each index combination of a face corner (i_pos, i_uv, i_attr..) has a unique vertex id and the number of vertices is minimal
663 delete splitter_;
664 splitter_ = new VertexSplitter(decl_.getNumElements(),
665 numPositions,
666 numPositions + estimatedSplitCount,
667 0.0f);
668
669 faceBufSplit_.resize(numIndices_, -1);
670
671 // count # vertices after splitting
672 numDrawVerts_ = 0;
673
674 for (int i = 0; i < numFaces_; ++i)
675 {
676 const int fsize = getFaceSize(i);
677 for (int k = 0; k < fsize; ++k)
678 {
679 // indices of the face vertex into the attribute vectors
680 int vertex[16]; // {i_pos, i_attr1, i_attr2 ..}
681
682
683 // get indices of a face corner after welding
684 getInputFaceVertex_Welded(i, k, vertex);
685
686 // split vertices by index data only
687 // value of position, normal etc. are not considered
688 const int idx = splitter_->split(vertex);
689
690 // handle index storage
691 setInputIndexSplit(i, k, idx);
692 }
693 }
694
695
696 // std::cout << "actual split count: " << (numDrawVerts_ - numPositions) << std::endl;
697
698
699
700 // Fix splitting list if there are isolated vertices in between.
701 // Isolated vertices currently occupy spots in in the interleaved vertex buffer.
702 // -> Remove them from the vbo.
703 findIsolatedVertices();
704
705 if (numIsolatedVerts_ > 0)
706 {
707 // create table that stores how many isolated vertices have been encountered up to each vertex
708 // this is done in the index domain after splitting
709 std::vector<int> IsoFix(splitter_->numVerts, 0);
710
711 int fixIndex = 0;
712 for (int i = 0; i < splitter_->numVerts; ++i)
713 {
714 if (splitter_->isIsolated(i))
715 fixIndex--;
716
717 IsoFix[i] = fixIndex;
718 }
719
720 // IsoFix[] array contains offsets <= 0 for each split vertex id.
721 // It maps from such an id to the vbo index, which does not contain any isolates.
722 // Isolates may be appended later to the vbo if the user wants that.
723
724 numDrawVerts_ = 0;
725
726 // apply index fixing table to current vertex ids
727 for (int i = 0; i < numFaces_; ++i)
728 {
729 const int fsize = getFaceSize(i);
730 for (int k = 0; k < fsize; ++k)
731 {
732 // get interleaved vertex id for (i, k) after splitting
733 int idx = getInputIndexSplit(i, k);
734
735 // idx is the split vertex id of (i, k)
736 // IsoFix[idx] is the offset that has to be applied to that
737 idx += IsoFix[idx];
738
739 // store fixed vertex id
740 setInputIndexSplit(i, k, idx);
741 }
742 }
743 }
744 }
745
746
747 bool MeshCompiler_forceUnsharedFaceVertex_InnerValenceSorter( const std::pair<int, int>& a, const std::pair<int, int>& b )
748 {
749 return a.second > b.second;
750 }
751
752 void MeshCompiler::forceUnsharedFaceVertex()
753 {
754 // ==============================================
755 // face normal fix
756 // make sure that each triangle has at least one unique unshared vertex
757 // this vertex can store per face attributes when needed
758
759
760 // sharedVertex[i] = 1 iff the vertex id of corner i is shared with any neighboring face
761 // sharedVertex is computed on-the-fly for each face
762 std::vector<int> sharedVertices;
763 sharedVertices.resize(maxFaceSize_);
764
765 // temporary copy of the vertex ids of a face
766 std::vector<int> tmpFaceVerts; // used for face rotation-swap
767 tmpFaceVerts.resize(maxFaceSize_);
768
769 int numInitialVerts = numDrawVerts_;
770 std::vector<int> VertexUsed(numDrawVerts_, -1); // marks vertices which are not shared with any neighboring face
771
772
773 // process all n-polygons first
774
775 /*
776 new and better algorithm: O(n * m^2) where n = numFaces, m = faceSize
777
778 for each face:
779
780 trisCovered = 0;
781
782 while (trisCovered < faceSize)
783 {
784 compute inner valence of all corners in the remaining polygon
785
786 add 'best' corner: - highest inner valence and unused by other tris
787
788 for each triangle affected by this corner
789 rotate triIndexBuffer entries of the tri
790 remove tri from the remaining triangle list
791 ++ trisCovered
792 }
793 */
794 int triCounter = 0;
795
796
797 for (int sortFaceID = 0; sortFaceID < numFaces_; ++sortFaceID)
798 {
799 // get original face id
800 const int faceID = faceSortMap_.empty() ? sortFaceID : faceSortMap_[sortFaceID];
801
802 const int faceSize = getFaceSize(faceID);
803
804 if (faceSize > 3)
805 {
806 // vertexPriorities[priority] = pair(cornerID, valence)
807 std::vector< std::pair<int, int> > vertexPriorities(faceSize);
808
809 // linked ring list for all the triangles in the uncovered triangulation
810 // ie. nextTri = remainingTris[currentTri];
811 const int faceTris = faceSize - 2;
812
813 std::vector<RingTriangle> remainingTris(faceTris);
814 for (int i = 0; i < faceTris; ++i)
815 remainingTris[i] = RingTriangle(i, &remainingTris[(i + faceTris - 1) % faceTris], &remainingTris[(i + 1) % faceTris]);
816
817
818 RingTriangle* currentTri = &remainingTris[0];
819 int numTrisCovered = 0;
820
821 while (numTrisCovered < faceTris)
822 {
823 // compute valence of vertices within the remaining triangulation
824 for (int k = 0; k < faceSize; ++k)
825 vertexPriorities[k] = std::pair<int, int>(k, 0);
826
827 RingTriangle* startTri = currentTri;
828 int numRemainingTris = faceTris - numTrisCovered;
829 for (int t = 0; t < numRemainingTris; ++t)
830 {
831 for (int k = 0; k < 3; ++k)
832 {
833 int cornerID = -1 - triIndexBuffer_[(triCounter + currentTri->id) * 3 + k];
834 ++vertexPriorities[cornerID].second;
835 }
836 currentTri = currentTri->next;
837 }
838 assert(currentTri == startTri);
839
840 // sort by valence
841 std::sort(vertexPriorities.begin(), vertexPriorities.end(), MeshCompiler_forceUnsharedFaceVertex_InnerValenceSorter);
842
843 // find a good corner
844 int goodCorner = -1;
845 int goodVertexID = -1;
846 int bestValence = -1;
847 for (int k = 0; k < faceSize && vertexPriorities[k].second; ++k)
848 {
849 int cornerID = vertexPriorities[k].first;
850 int vertexID = getInputIndexSplit(faceID, cornerID);
851
852 int valence = vertexPriorities[k].second;
853
854 if (vertexID >= numInitialVerts || (VertexUsed[vertexID] == faceID))
855 {
856 // best case, this vertex is already owned by the polygon
857 // stop the search
858 goodCorner = cornerID;
859 goodVertexID = vertexID;
860 bestValence = valence;
861 break;
862 }
863 else if (VertexUsed[vertexID] < 0 && bestValence < valence)
864 {
865 goodCorner = cornerID; // best for now, but continue the search
866 goodVertexID = vertexID;
867 bestValence = valence;
868 }
869 }
870
871
872 // maybe add a new vertex
873 if (goodCorner < 0)
874 {
875 // have to add a new vertex
876 // use the one with highest inner valence
877
878 goodCorner = vertexPriorities[0].first; // polygon corner
879
880 // add new vertex at the end of the buffer
881 goodVertexID = numDrawVerts_;
882 setInputIndexSplit(faceID, goodCorner, goodVertexID);
883 }
884 else
885 {
886 // mark the polygon as owner of the vertex
887 VertexUsed[goodVertexID] = faceID;
888 }
889
890 // process tris
891 for (int t = 0; t < numRemainingTris; ++t)
892 {
893 // check if the triangle references the good corner by testing the 3 vertices of the triangulation
894 for (int k = 0; k < 3; ++k)
895 {
896 int cornerID = -1 - triIndexBuffer_[(triCounter + currentTri->id) * 3 + k];
897
898 if (cornerID == goodCorner)
899 {
900 // rotate the triangle such that the first corner of the triangle references the good corner
901 int rotCount = 3 - k;
902
903 // make a temp copy of current triangle
904 int tmpTriVerts[3] =
905 {
906 triIndexBuffer_[(triCounter + currentTri->id) * 3],
907 triIndexBuffer_[(triCounter + currentTri->id) * 3 + 1],
908 triIndexBuffer_[(triCounter + currentTri->id) * 3 + 2],
909 };
910
911 // apply rotation
912 for (int i = 0; i < 3; ++i)
913 triIndexBuffer_[(triCounter + currentTri->id) * 3 + (i + rotCount) % 3] = tmpTriVerts[i];
914
915
916 ++numTrisCovered;
917
918 // remove triangle from the ring list
919 currentTri->prev->next = currentTri->next;
920 currentTri->next->prev = currentTri->prev;
921 break;
922 }
923 }
924
925 currentTri = currentTri->next;
926 }
927 }
928
929 }
930
931 triCounter += faceSize - 2;
932 }
933
934 // process all triangles now
935 numInitialVerts = VertexUsed.size();
936 triCounter = 0;
937
938 for (int sortFaceID = 0; sortFaceID < numFaces_; ++sortFaceID)
939 {
940 int faceID = faceSortMap_.empty() ? sortFaceID : faceSortMap_[sortFaceID];
941 const int numCorners = getFaceSize(faceID);
942
943 if (numCorners == 3)
944 {
945 // reset shared list
946 memset(&sharedVertices[0], 0, sizeof(int) * maxFaceSize_);
947 int numShared = 0;
948
949 // find shared list (corners of this face, that are shared with the neighbors)
950 for (int v0 = 0; v0 < numCorners && numShared < numCorners; ++v0)
951 {
952 if (sharedVertices[v0])
953 continue;
954
955 const int vertexID0 = getInputIndexSplit(faceID, v0);
956
957 // EDIT:
958 // vertexID0 >= numInitialVerts || (...) seemed wrong
959 if (vertexID0 < numInitialVerts && (VertexUsed[vertexID0] >= 0 && VertexUsed[vertexID0] != faceID))
960 {
961 sharedVertices[v0] = true;
962 ++numShared;
963 }
964 }
965
966 int rotCount = 0;
967
968 if (numShared == numCorners)
969 {
970 // worst-case: all vertices shared with neighbors
971
972 // add split vertex to end of vertex buffer, which is used exclusively by the current face
973 // current vertex count is stored in numDrawVerts_
974
975 setInputIndexSplit(faceID, 0, numDrawVerts_);
976 }
977 else if (sharedVertices[0])
978 {
979 // validation code
980 int x = 0;
981 for (int i = 0; i < numCorners; ++i)
982 x += sharedVertices[i];
983 assert(x < numCorners);
984
985 // we have to make sure that an unshared vertex is the first referenced face vertex
986 // this is currently not the case, so rotate the face indices until this is true
987
988 // make copy of current face splitVertexID
989 for (int i = 0; i < numCorners; ++i)
990 tmpFaceVerts[i] = getInputIndexSplit(faceID, i);
991
992 // rotation order: i -> i+1
993 // find # rotations needed
994 rotCount = 1;
995 for (; rotCount < numCorners; ++rotCount)
996 {
997 if (!sharedVertices[rotCount % numCorners])
998 {
999 if (tmpFaceVerts[rotCount] < numInitialVerts)
1000 VertexUsed[tmpFaceVerts[rotCount]] = faceID;
1001 break;
1002 }
1003 }
1004
1005 assert(rotCount < numCorners);
1006
1007 // rotate: i -> i+rotCount
1008 rotCount = numCorners - rotCount;
1009
1010 for (int i = 0; i < numCorners; ++i)
1011 {
1012 // setInputIndexSplit(faceID, i, tmpFaceVerts[(i + numCorners - rotCount) % numCorners]);
1013
1014 triIndexBuffer_[triCounter * 3 + i] = tmpFaceVerts[(i + numCorners - rotCount) % numCorners];
1015 }
1016 }
1017 else
1018 {
1019 // best-case: unshared vertex at corner 0
1020 const int idx = getInputIndexSplit(faceID, 0);
1021 if (idx < numInitialVerts)
1022 VertexUsed[idx] = faceID;
1023 }
1024 }
1025
1026 triCounter += numCorners - 2;
1027 }
1028
1029 // std::cout << "force unshared num added: " << (numDrawVerts_ - numInitialVerts) << std::endl;
1030 }
1031
1032 void MeshCompiler::getInputFaceVertex( const int _face, const int _corner, int* _out ) const
1033 {
1034 for (unsigned int k = 0; k < decl_.getNumElements(); ++k)
1035 _out[k] = getInputIndex(_face, _corner, k);
1036 }
1037
1038 void MeshCompiler::getInputFaceVertex_Welded( const int i, const int j, int* _out ) const
1039 {
1040 int face = i;
1041 int corner = j;
1042
1043 // apply welding map if available
1044 if (!vertexWeldMapFace_.empty())
1045 {
1046 const int offset = getInputFaceOffset(i);
1047
1048 face = vertexWeldMapFace_[offset + j];
1049 corner = vertexWeldMapCorner_[offset + j];
1050 }
1051
1052 for (unsigned int k = 0; k < decl_.getNumElements(); ++k)
1053 _out[k] = getInputIndex(face, corner, k);
1054 }
1055
1056 void MeshCompiler::getInputFaceVertexData( const int _faceId, const int _corner, void* _out ) const
1057 {
1058 for (int i = 0; i < numAttributes_; ++i)
1059 {
1060 const VertexElement* el = decl_.getElement(i);
1061
1062 const int idx = getInputIndex(_faceId, _corner, i);
1063
1064 input_[i].getElementData(idx, (char*)_out + (size_t)el->pointer_, el);
1065 }
1066 }
1067
1068
1069
1070
1071 MeshCompiler::MeshCompiler(const VertexDeclaration& _decl)
1072 : decl_(_decl)
1073 {
1074 faceInput_ = 0;
1075 deleteFaceInputeData_ = false;
1076
1077 splitter_ = 0;
1078 numSubsets_ = 0;
1079 numIndices_ = 0;
1080 numTris_ = 0;
1081
1082 numFaces_ = 0;
1083 curFaceInputPos_ = 0;
1084
1085 numDrawVerts_ = 0;
1086 numIsolatedVerts_ = 0;
1087
1088 maxFaceSize_ = 0;
1089 constantFaceSize_ = false;
1090
1091 provokingVertex_ = -1;
1092 provokingVertexSetByUser_ = false;
1093
1094 // search for convenient attribute indices
1095 numAttributes_ = decl_.getNumElements();
1096 inputIDNorm_ = inputIDPos_ = inputIDTexC_ = -1;
1097
1098 for (int i = 0; i < (int)decl_.getNumElements(); ++i)
1099 {
1100 const VertexElement* e = decl_.getElement(i);
1101
1102 switch (e->usage_)
1103 {
1104 case VERTEX_USAGE_POSITION: inputIDPos_ = i; break;
1105 case VERTEX_USAGE_NORMAL: inputIDNorm_ = i; break;
1106 case VERTEX_USAGE_TEXCOORD: inputIDTexC_ = i; break;
1107 default: break;
1108 }
1109 }
1110
1111
1112 vertexCompare_ = &defaultVertexCompare;
1113
1114 }
1115
1116 MeshCompiler::~MeshCompiler()
1117 {
1118 if (deleteFaceInputeData_)
1119 delete faceInput_;
1120
1121 delete splitter_;
1122 }
1123
1124
1125 int MeshCompiler::getInputIndexOffset( const int _face, const int _corner ) const
1126 {
1127 assert(_face >= 0);
1128 assert(_face < numFaces_);
1129
1130 // baseIdx: offset to first index of the (face, corner) pair
1131 const int baseIdx = int(faceStart_.empty() ? maxFaceSize_ * _face : faceStart_[_face]);
1132 return baseIdx + _corner;
1133 }
1134
1135
1136 void MeshCompiler::setInputIndexSplit( const int _face, const int _corner, const int _val )
1137 {
1138 const int offset = getInputIndexOffset(_face, _corner);
1139
1140 // keep track of number of vertices after splitting process
1141 if (_val >= numDrawVerts_)
1142 numDrawVerts_ = _val + 1;
1143
1144 faceBufSplit_[offset] = _val;
1145 }
1146
1147 int MeshCompiler::getInputIndexSplit( const int _face, const int _corner ) const
1148 {
1149 const int offset = getInputIndexOffset(_face, _corner);
1150
1151 return faceBufSplit_[offset];
1152 }
1153
1154
1155
1156
1157 MeshCompilerDefaultFaceInput::MeshCompilerDefaultFaceInput(int _numFaces, int _numIndices)
1158 : numFaces_(_numFaces), numIndices_(_numIndices)
1159 {
1160 faceOffset_.resize(numFaces_, -1);
1161 faceSize_.resize(numFaces_, 0);
1162 faceData_[0].reserve(_numIndices);
1163 }
1164
1165
1166 void MeshCompiler::setNumFaces( const int _numFaces, const int _numIndices )
1167 {
1168 if (faceInput_)
1169 return;
1170
1171 MeshCompilerDefaultFaceInput* internalInput = new MeshCompilerDefaultFaceInput(_numFaces, _numIndices);
1172
1173 numFaces_ = _numFaces;
1174
1175 faceInput_ = internalInput;
1176 deleteFaceInputeData_ = true;
1177
1178 }
1179
1180
1181 void MeshCompiler::setFaceAttrib( int _i, int _numEdges, int* _v, int _attrID )
1182 {
1183 if (!_v || _attrID < 0) return;
1184
1185 if (!faceInput_)
1186 faceInput_ = new MeshCompilerDefaultFaceInput(0, 0);
1187
1188 MeshCompilerDefaultFaceInput* input = dynamic_cast<MeshCompilerDefaultFaceInput*>(faceInput_);
1189 if (input)
1190 {
1191 input->setFaceData(_i, _numEdges, _v, _attrID);
1192 }
1193 }
1194
1195 void MeshCompiler::setFaceAttrib( int _i, int _v0, int _v1, int _v2, int _attrID )
1196 {
1197 int tmp[3] = {_v0, _v1, _v2};
1198 setFaceAttrib(_i, 3, tmp, _attrID);
1199 }
1200
1201
1202
1203 MeshCompiler::VertexSplitter::VertexSplitter(int _numAttribs,
1204 int _numVerts,
1205 int _numWorstCase,
1206 float _estBufferIncrease)
1207 : numAttribs(_numAttribs), numVerts(_numVerts), numBaseVerts(_numVerts)
1208 {
1209 if (_numWorstCase <= 0)
1210 _numWorstCase = int(float(_numVerts) * (_estBufferIncrease + 1.0f));
1211
1212 const int maxCount = (_numAttribs + 1) * (_numWorstCase + 1);
1213
1214 // alloc split list and invalidate
1215 splits.resize(maxCount, -1);
1216
1217 dbg_numResizes = 0;
1218 dbg_numSplits = 0;
1219 }
1220
1221
1222
1223 MeshCompiler::VertexSplitter::~VertexSplitter()
1224 {
1225 }
1226
1227
1228 int MeshCompiler::VertexSplitter::split(int* vertex)
1229 {
1230 int pos = vertex[0];
1231 int next = getNext(pos);
1232
1233 if (next < 0)
1234 {
1235 // 1st time reference
1236
1237 // store attributes
1238 setAttribs(pos, vertex);
1239
1240 // mark as referenced (next = this)
1241 setNext(pos, pos);
1242 }
1243 else
1244 {
1245 // already referenced
1246
1247 int bSearchSplit = 1;
1248
1249 // search vertex in split list
1250 while (pos >= 0 && bSearchSplit)
1251 {
1252 // is vertex already in split list?
1253 if (!memcmp(vertex, getAttribs(pos), numAttribs * sizeof(int)))
1254 {
1255 // found! reuse index
1256 return pos;
1257 }
1258 else
1259 {
1260 next = getNext(pos);
1261
1262 if (next < 0) break; // end of list
1263 if (next == pos) break; // avoid loop
1264
1265 pos = next; // go to next entry
1266 }
1267 }
1268
1269 // combination not found -> add new vertex
1270
1271 int newID = numVerts++;
1272
1273 setNext(pos, newID);
1274 setAttribs(newID, vertex);
1275
1276 pos = newID;
1277
1278 ++dbg_numSplits;
1279 }
1280
1281 return pos;
1282 }
1283
1284
1285
1286 int MeshCompiler::VertexSplitter::getNext(const int id)
1287 {
1288 assert(id >= 0);
1289
1290 const int entryIdx = id * (1 + numAttribs);
1291
1292 // need more space?
1293 if (entryIdx >= (int)splits.size())
1294 {
1295 splits.resize(entryIdx + numAttribs * 100, -1);
1296 ++dbg_numResizes;
1297 }
1298
1299 return splits[entryIdx];
1300 }
1301
1302 void MeshCompiler::VertexSplitter::setNext(const int id, const int next)
1303 {
1304 assert(id >= 0);
1305
1306 const int entryIdx = id * (1 + numAttribs);
1307
1308 // need more space?
1309 if (entryIdx >= (int)splits.size())
1310 {
1311 splits.resize(entryIdx + numAttribs * 100, -1);
1312 ++dbg_numResizes;
1313 }
1314
1315 splits[entryIdx] = next;
1316 }
1317
1318 int* MeshCompiler::VertexSplitter::getAttribs(const int id)
1319 {
1320 assert(id >= 0);
1321
1322 const int entryIdx = id * (1 + numAttribs) + 1;
1323
1324 // need more space?
1325 if (entryIdx + numAttribs >= (int)splits.size())
1326 {
1327 splits.resize(entryIdx + numAttribs * 100, -1);
1328 ++dbg_numResizes;
1329 }
1330
1331 return &splits[0] + entryIdx;
1332 }
1333
1334 void MeshCompiler::VertexSplitter::setAttribs( const int id, int* attr )
1335 {
1336 memcpy(getAttribs(id), attr, numAttribs * sizeof(int));
1337 }
1338
1339 bool MeshCompiler::VertexSplitter::isIsolated( const int vertexPosID )
1340 {
1341 return (vertexPosID < numBaseVerts) && (getNext(vertexPosID) < 0);
1342 }
1343
1344
1345
1346 MeshCompiler::VertexElementInput::VertexElementInput()
1347 : internalBuf(0), data(0),
1348 count(0), stride(0), attrSize(0),
1349 fmt(0), elementSize(-1)
1350 {
1351 }
1352
1353 MeshCompiler::VertexElementInput::~VertexElementInput()
1354 {
1355 delete [] internalBuf;
1356 }
1357
1358
1359
1360
1361
1362
1363
1364
1365 void MeshCompiler::triangulate()
1366 {
1367 // count no. of triangles
1368
1369 int numTris = 0;
1370
1371 for (int i = 0; i < numFaces_; ++i)
1372 numTris += getFaceSize(i) - 2;
1373
1374 numTris_ = numTris;
1375
1376 triIndexBuffer_.resize(numTris * 3);
1377 triToSortFaceMap_.resize(numTris);
1378
1379 // - find mapping (triToFaceMap): triangle id -> sorted face id
1380 // - build triangle index buffer: triIndexBuffer_
1381
1382 // NOTE: triIndexBuffer_ contains local indices for each face, that is indices in the range [0, .. faceSize-1]
1383 // these are encoded as a negative value starting at -1: (-1 - localID)
1384 // this change is necessary to implement the forceUnsharedVertices() function for complex polygons
1385 // the negative values are resolved later in the function resolveTriangulation()
1386
1387 int triCounter = 0;
1388 int indexCounter = 0;
1389
1390 for (int sortFaceID = 0; sortFaceID < numFaces_; ++sortFaceID)
1391 {
1392 // get original face id
1393 const int faceID = faceSortMap_.empty() ? sortFaceID : faceSortMap_[sortFaceID];
1394
1395 const int faceSize = getFaceSize(faceID);
1396
1397 if (faceSize < 4)
1398 {
1399 // save face index mapping
1400 triToSortFaceMap_[triCounter++] = sortFaceID;
1401
1402 for (int k = 0; k < 3; ++k)
1403 triIndexBuffer_[indexCounter++] = -1 - k; // getInputIndexSplit(faceID, k);
1404 }
1405 else
1406 {
1407 // use ACG::Triangulator to process complex polygons
1408 std::vector<Vec3f> poly(faceSize);
1409 for (int k = 0; k < faceSize; ++k)
1410 {
1411 VertexElement posElement;
1412 posElement.type_ = GL_FLOAT;
1413 posElement.numElements_ = 3;
1414 posElement.usage_ = VERTEX_USAGE_POSITION;
1415 posElement.pointer_ = 0;
1416 posElement.shaderInputName_ = 0;
1417 posElement.divisor_ = 0;
1418 posElement.vbo_ = 0;
1419 int posID = getInputIndexSplit(faceID, k);
1420 input_[inputIDPos_].getElementData(posID, &poly[k], &posElement);
1421 }
1422 Triangulator tris(poly);
1423
1424 if (tris.convex())
1425 {
1426 // best case: convert polygon into triangle fan
1427 // NOTE: all triangles must use the first face-vertex here!
1428 triToSortFaceMap_[triCounter++] = sortFaceID;
1429 for (int k = 0; k < 3; ++k)
1430 triIndexBuffer_[indexCounter++] = -1 - k;
1431
1432 for (int k = 3; k < faceSize; ++k)
1433 {
1434 // added tri belongs to current face
1435 triToSortFaceMap_[triCounter++] = sortFaceID;
1436
1437 triIndexBuffer_[indexCounter++] = -1; // getInputIndexSplit(faceID, 0);
1438 triIndexBuffer_[indexCounter++] = -1 - (k - 1); // getInputIndexSplit(faceID, k - 1);
1439 triIndexBuffer_[indexCounter++] = -1 - k; // getInputIndexSplit(faceID, k);
1440 }
1441 }
1442 else
1443 {
1444 // concave polygon
1445 // enforcing an unshared vertex gets ugly now
1446
1447 for (int i = 0; i < tris.numTriangles(); ++i)
1448 {
1449 triToSortFaceMap_[triCounter++] = sortFaceID;
1450 for (int k = 0; k < 3; ++k)
1451 {
1452 int cornerID = tris.index(i * 3 + k);
1453
1454 triIndexBuffer_[indexCounter++] = -1 - cornerID; // getInputIndexSplit(faceID, cornerID);
1455 }
1456 }
1457 }
1458 }
1459 }
1460
1461 // ---------------
1462 // fill out missing subset info:
1463
1464 for (int i = 0; i < numSubsets_; ++i)
1465 {
1466 subsets_[i].startIndex = 0xffffffff;
1467 subsets_[i].numTris = 0;
1468 }
1469
1470 // triangle count per subset
1471
1472 for (int i = 0; i < numTris; ++i)
1473 {
1474 const int faceID = mapTriToInputFace(i);
1475
1476 const int faceGroup = getFaceGroup(faceID);
1477 Subset* sub = &subsets_[findGroupSubset(faceGroup)];
1478
1479 ++sub->numTris;
1480 }
1481
1482 // start index
1483
1484 for (int i = 0; i < numSubsets_; ++i)
1485 {
1486 if (i > 0)
1487 subsets_[i].startIndex = subsets_[i-1].startIndex + subsets_[i-1].numTris * 3;
1488 else
1489 subsets_[i].startIndex = 0;
1490 }
1491
1492 }
1493
1494
1495 void MeshCompiler::resolveTriangulation()
1496 {
1497 // rotate tris such that the unshared face vertex is at the wanted provoking position of each triangle
1498
1499 if (provokingVertex_ >= 0)
1500 {
1501 for (int i = 0; i < numTris_; ++i)
1502 {
1503 for (int k = 0; k < 3 - provokingVertex_; ++k)
1504 {
1505 const int tmp = triIndexBuffer_[i*3];
1506 triIndexBuffer_[i*3] = triIndexBuffer_[i*3 + 1];
1507 triIndexBuffer_[i*3 + 1] = triIndexBuffer_[i*3 + 2];
1508 triIndexBuffer_[i*3 + 2] = tmp;
1509 }
1510 }
1511 }
1512
1513 // resolve triangulation to indices
1514 for (int drawTriID = 0; drawTriID < numTris_; ++drawTriID)
1515 {
1516 if (triIndexBuffer_[drawTriID * 3] < 0)
1517 {
1518 // triIndexBuffer stores the corner ids of the triangulations as:
1519 // triIndexBuffer[idx] = -cornerID - 1
1520
1521 // get original face id
1522 const int sortFaceID = triToSortFaceMap_[drawTriID];
1523 const int faceID = faceSortMap_.empty() ? sortFaceID : faceSortMap_[sortFaceID];
1524
1525 for (int k = 0; k < 3; ++k)
1526 {
1527 int negCornerID = triIndexBuffer_[drawTriID * 3 + k];
1528 int cornerID = -1 - negCornerID;
1529 triIndexBuffer_[drawTriID * 3 + k] = getInputIndexSplit(faceID, cornerID);
1530 }
1531 }
1532 }
1533 }
1534
1535 void MeshCompiler::sortFacesByGroup()
1536 {
1537 // sort faces based on their group id
1538 // faces within the same group can be rendered in one batch
1539
1540 numSubsets_ = 0;
1541
1542 std::map<int, unsigned int> GroupIDs; // map[groupID] = first face
1543
1544 // initialize GroupIDs map
1545 for (int face = 0; face < numFaces_; ++face)
1546 {
1547 const int texID = getFaceGroup(face);
1548
1549 if (GroupIDs.find(texID) == GroupIDs.end())
1550 GroupIDs[texID] = face;
1551 }
1552
1553 // alloc subset array
1554 numSubsets_ = int(GroupIDs.size());
1555 subsets_.resize(numSubsets_);
1556
1557 if (numSubsets_ > 1)
1558 faceSortMap_.resize(numFaces_, -1);
1559
1560 // initialize subsets and face sorting map
1561
1562 std::map<int, unsigned int>::const_iterator it = GroupIDs.begin();
1563 unsigned int numSortedFaces = 0;
1564
1565 for (unsigned int i = 0; it != GroupIDs.end(); ++i, ++it)
1566 {
1567 // subset id = group id
1568 subsets_[i].id = it->first;
1569
1570 // store id mapping (optimization)
1571 subsetIDMap_[it->first] = i;
1572
1573 // rearrange by subset chunks, face offset = # processed faces
1574 subsets_[i].numFaces = 0;
1575 subsets_[i].startFace = numSortedFaces;
1576
1577 // triangle information is computed later
1578 subsets_[i].startIndex = 0;
1579 subsets_[i].numTris = 0;
1580
1581 if (numSubsets_ == 1)
1582 {
1583 subsets_[i].numFaces = numFaces_;
1584 }
1585 else
1586 {
1587 // - find # faces in this subset
1588 // - create face sorting map: map[sortFaceID] = faceID
1589 for (int k = it->second; k < numFaces_; ++k)
1590 {
1591 const int texID = getFaceGroup(k);
1592
1593 if (texID == subsets_[i].id)
1594 {
1595 subsets_[i].numFaces++;
1596
1597 faceSortMap_[numSortedFaces++] = k;
1598 }
1599 }
1600 }
1601 }
1602
1603 }
1604
1605
1606 void MeshCompiler::optimize()
1607 {
1608 indices_.resize(numTris_ * 3);
1609 triOptMap_.resize(numTris_, -1);
1610
1611 for (int i = 0; i < numSubsets_; ++i)
1612 {
1613 Subset* pSubset = &subsets_[i];
1614
1615 const int vcacheSize = 24;
1616 GPUCacheOptimizerTipsify copt(vcacheSize, pSubset->numTris, numDrawVerts_, 4, &triIndexBuffer_[0] + pSubset->startIndex);
1617 copt.WriteIndexBuffer(4, &indices_[pSubset->startIndex]);
1618
1619
1620 // apply changes to trimap
1621 const unsigned int StartTri = pSubset->startIndex/3;
1622 for (unsigned int k = 0; k < pSubset->numTris; ++k)
1623 {
1624 const unsigned int SrcTri = copt.GetTriangleMap()[k];
1625 triOptMap_[k + StartTri] = SrcTri + StartTri;
1626 }
1627
1628 }
1629
1630 // call to GPUCacheOptimizer::OptimizeVertices!
1631
1632 unsigned int* vertexOptMap = new unsigned int[numDrawVerts_];
1633
1634 GPUCacheOptimizer::OptimizeVertices(numTris_, numDrawVerts_, 4, indices_.data(), vertexOptMap);
1635
1636 // apply vertexOptMap to index buffer
1637
1638 for (int i = 0; i < numTris_ * 3; ++i)
1639 indices_[i] = vertexOptMap[indices_[i]];
1640
1641
1642 // apply opt-map to current vertex-map
1643
1644 for (int i = 0; i < numFaces_; ++i)
1645 {
1646 const int fsize = getFaceSize(i);
1647
1648 for (int k = 0; k < fsize; ++k)
1649 {
1650 int oldVertex = getInputIndexSplit(i, k);
1651
1652 int newVertex = vertexOptMap[oldVertex];
1653
1654 setInputIndexSplit(i, k, newVertex);
1655 }
1656 }
1657
1658 delete [] vertexOptMap;
1659 }
1660
1661
1662
1663 void MeshCompiler::build(bool _weldVertices, bool _optimizeVCache, bool _needPerFaceAttribute, bool _keepIsolatedVertices)
1664 {
1665 // track memory report for profiling/debugging
1666 const bool dbg_MemProfiling = false;
1667
1668 // array allocation/copy data/validation checks etc.
1669 prepareData();
1670
1671 /*
1672 1. step
1673 Split vertices s.t. we can create an interleaved vertex buffer.
1674 Neighboring faces may share a vertex with different normals,
1675 which gets resolved here.
1676
1677 output:
1678 faceBufSplit_
1679
1680 faceBufSplit_ reroutes the original index buffer to their unique
1681 vertex indices. So the orig. indices (faceBuf_) are still needed
1682 to know how to compose each vertex and faceBufSplit_ gives them
1683 a new index.
1684
1685 faceBufSplit_ should not be used directly,
1686 use get/setInputIndexSplit for the mapping between interleaved indices and face vertices.
1687 */
1688
1689 if (_weldVertices)
1690 {
1691 if (dbg_MemProfiling)
1692 std::cout << "computing adjacency.., memusage = " << (getMemoryUsage() /(1024 * 1024)) << std::endl;
1693
1694 computeAdjacency();
1695
1696 if (dbg_MemProfiling)
1697 std::cout << "vertex welding.., memusage = " << (getMemoryUsage() /(1024 * 1024)) << std::endl;
1698
1699 weldVertices();
1700
1701 // delete adjacency list (high memory cost)
1702 adjacencyVert_.clear();
1703 }
1704
1705 if (dbg_MemProfiling)
1706 std::cout << "vertex splitting.., memusage = " << (getMemoryUsage() /(1024 * 1024)) << std::endl;
1707
1708 splitVertices();
1709
1710 if (dbg_MemProfiling)
1711 std::cout << "splitting done.., memusage = " << (getMemoryUsage() /(1024 * 1024)) << std::endl;
1712
1713 // delete splitting and welding map ( high mem cost and is no longer needed after splitting )
1714 {
1715 delete splitter_; splitter_ = 0;
1716
1717 {
1718 std::vector< int > emptyVec;
1719 vertexWeldMapFace_.swap(emptyVec);
1720 } {
1721 std::vector< int > emptyVec;
1722 vertexWeldMapCorner_.swap(emptyVec);
1723 }
1724 }
1725
1726 /*
1727 2. step
1728
1729 Sort faces by materials, grouping faces with the same material together.
1730
1731 output:
1732 subsets_ (tri group offsets for each mat-id)
1733 triIndexBuffer_ (updated)
1734 triToSortFaceMap_ (updated)
1735 */
1736 if (dbg_MemProfiling)
1737 std::cout << "sorting by mat.., memusage = " << (getMemoryUsage() /(1024 * 1024)) << std::endl;
1738 sortFacesByGroup();
1739
1740
1741
1742
1743 /*
1744 3. step
1745
1746 Triangulate any n-polys and unfold triangles to a new index buffer.
1747
1748 output:
1749 numTris_
1750 triIndexBuffer_ (tri index buffer)
1751 triToSortFaceMap_ (map triangle id -> face id)
1752
1753 From this point on we have to keep track of triToSortFaceMap_
1754 to compose vertices.
1755
1756 Assembling the vertex for corner "k" of triangle "tri" works as followed.
1757 int dstID = triIndexBuffer_[tri * 3 + k];
1758 int srcFace = triToSortFaceMap_[tri];
1759
1760 int vertexAttribs[16];
1761 getInputFaceVertex(srcFace, k, vertexAttribs);
1762
1763 vertexBuffer[dstID].pos = inputVerts_[vertexAttribs[POS]];
1764 vertexBuffer[dstID].normal = inputVerts_[vertexAttribs[NORMAL]];
1765 ...
1766 */
1767 if (dbg_MemProfiling)
1768 std::cout << "triangulate.., memusage = " << (getMemoryUsage() /(1024 * 1024)) << std::endl;
1769 triangulate();
1770
1771
1772
1773 if (_needPerFaceAttribute)
1774 {
1775 if (dbg_MemProfiling)
1776 std::cout << "force unshared vertex.., memusage = " << (getMemoryUsage() / (1024 * 1024)) << std::endl;
1777
1778 // The provoking vertex of each face shall not be referenced by any other face.
1779 // This vertex can then be used to store per-face data
1780
1781 // default provoking position 2
1782 if (provokingVertex_ < 0)
1783 provokingVertex_ = 2;
1784
1785 provokingVertex_ = provokingVertex_ % 3;
1786
1787 // Adjacency info needed here
1788 forceUnsharedFaceVertex();
1789 }
1790
1791 resolveTriangulation();
1792
1793 /*
1794 4. step
1795
1796 Optimize indices for efficient gpu vcache usage.
1797 This is done within the boundaries of each subset.
1798 Also, this operates on triangles instead of single indices,
1799 which means only complete triangles are reordered and
1800 will not be rotated afterwards.
1801
1802 Additionally reorders vertex indices in increasing order.
1803
1804 output:
1805 triIndexBuffer_ (updated)
1806 triOptMap
1807 */
1808 if (_optimizeVCache)
1809 {
1810 if (dbg_MemProfiling)
1811 std::cout << "optimizing.., memusage = " << (getMemoryUsage() /(1024 * 1024)) << std::endl;
1812
1813 optimize();
1814 }
1815 else if (!triIndexBuffer_.empty())
1816 triIndexBuffer_.swap(indices_);
1817
1818 if (dbg_MemProfiling)
1819 std::cout << "creating maps.., memusage = " << (getMemoryUsage() /(1024 * 1024)) << std::endl;
1820
1821 // delete temporary tri index buffer (use indices_ instead)
1822 {
1823 std::vector< int > emptyVec;
1824 triIndexBuffer_.swap(emptyVec);
1825 }
1826
1827 createVertexMap(_keepIsolatedVertices);
1828 createFaceMap();
1829
1830 // delete intermediate mappings
1831 {
1832 std::vector< int > emptyVec;
1833 triToSortFaceMap_.swap(emptyVec);
1834 } {
1835 std::vector< int > emptyVec;
1836 triOptMap_.swap(emptyVec);
1837 } {
1838 std::vector< int > emptyVec;
1839 faceSortMap_.swap(emptyVec);
1840 }
1841
1842 if (dbg_MemProfiling)
1843 std::cout << "finished.., memusage = " << (getMemoryUsage() /(1024 * 1024)) << std::endl;
1844
1845
1846 // debugging
1847 // dbgdumpInputObj("../../../dbg_meshcompinput.obj");
1848 // dbgdump("../../../dbg_meshcomp.txt");
1849 // dbgdumpObj("../../../dbg_meshcomp.obj");
1850 // dbgVerify("../../../dbg_maps.txt");
1851 }
1852
1853
1854
1855
1856
1857
1858 void MeshCompiler::setAttrib( int _attrIdx, int _v, const void* _data )
1859 {
1860 VertexElementInput* inbuf = input_ + _attrIdx;
1861
1862 if (!inbuf->internalBuf)
1863 {
1864 std::cerr << "setAttrib failed: please allocate internal input buffer before using setAttrib" << std::endl;
1865 return;
1866 }
1867
1868 assert(inbuf->count > _v);
1869
1870 memcpy(inbuf->internalBuf + (size_t)(_v * inbuf->stride), _data, inbuf->attrSize);
1871 }
1872
1873 int MeshCompiler::getNumInputAttributes( int _attrIdx ) const
1874 {
1875 assert (_attrIdx >= 0);
1876 assert(_attrIdx < int(decl_.getNumElements()));
1877
1878 return input_[_attrIdx].count;
1879 }
1880
1881
1882 int MeshCompiler::mapTriToInputFace( const int _tri ) const
1883 {
1884 assert(_tri >= 0);
1885 assert(_tri < numTris_);
1886
1887 int sortFaceID = triToSortFaceMap_[_tri];
1888 assert(sortFaceID >= 0);
1889 assert(sortFaceID < numFaces_);
1890
1891 int faceID = faceSortMap_.empty() ? sortFaceID : faceSortMap_[sortFaceID];
1892 assert(faceID >= 0);
1893 assert(faceID < numFaces_);
1894
1895 return faceID;
1896 }
1897
1898 int MeshCompiler::getFaceGroup( int _faceID ) const
1899 {
1900 if (faceGroupIDs_.empty())
1901 return -1;
1902
1903 return (int)faceGroupIDs_[_faceID];
1904 }
1905
1906 int MeshCompiler::findGroupSubset( int _groupID )
1907 {
1908 return subsetIDMap_[_groupID];
1909 }
1910
1911 const MeshCompiler::Subset* MeshCompiler::getSubset( int _i ) const
1912 {
1913 return &subsets_[_i];
1914 }
1915
1916 std::string MeshCompiler::vertexToString( const void* v ) const
1917 {
1918 std::stringstream str;
1919
1920 for (int i = 0; i < (int)decl_.getNumElements(); ++i)
1921 {
1922 const VertexElement* el = decl_.getElement(i);
1923
1924 str << el->shaderInputName_ << " [";
1925
1926 const void* data = static_cast<const char*>(v) + (size_t)el->pointer_;
1927
1928 switch ( el->type_ )
1929 {
1930 case GL_DOUBLE:
1931 {
1932 const double* d0 = static_cast<const double*>(data);
1933
1934 for (int k = 0; k < (int)el->numElements_; ++k)
1935 str << d0[k] << ", ";
1936 } break;
1937
1938
1939 case GL_FLOAT:
1940 {
1941 const float* f0 = static_cast<const float*>(data);
1942
1943 for (int k = 0; k < (int)el->numElements_; ++k)
1944 str << f0[k] << ", ";
1945 } break;
1946
1947 case GL_INT:
1948 case GL_UNSIGNED_INT:
1949 {
1950 const int* i0 = static_cast<const int*>(data);
1951
1952 for (int k = 0; k < (int)el->numElements_; ++k)
1953 str << i0[k] << ", ";
1954 } break;
1955
1956 case GL_SHORT:
1957 case GL_UNSIGNED_SHORT:
1958 {
1959 const short* i0 = static_cast<const short*>(data);
1960
1961 for (int k = 0; k < (int)el->numElements_; ++k)
1962 str << i0[k] << ", ";
1963 } break;
1964
1965 case GL_BYTE:
1966 case GL_UNSIGNED_BYTE:
1967 {
1968 const char* i0 = static_cast<const char*>(data);
1969
1970 for (int k = 0; k < (int)el->numElements_; ++k)
1971 str << ((int)i0[k]) << ", ";
1972 } break;
1973
1974 default: std::cerr << "MeshCompiler: vertexToString() unknown type: " << el->type_ << std::endl;
1975 }
1976
1977
1978 str << "] ";
1979
1980 }
1981
1982 return str.str();
1983 }
1984
1985 bool MeshCompiler::dbgVerify(const char* _filename) const
1986 {
1987 int numTotalErrors = 0;
1988
1989 std::ofstream file;
1990
1991 if (_filename)
1992 file.open(_filename);
1993
1994 if (file || !_filename)
1995 {
1996
1997 // ---------------------------------------------------------------------------------------
1998
1999 int numErrors = 0;
2000
2001 // check draw_tri <-> face (triangulation)
2002 if (file.is_open())
2003 file << "checking draw_tri <-> face mapping ..\n";
2004
2005 for (int face = 0; face < getNumFaces(); ++face)
2006 {
2007 int numTrisOfFace = 0;
2008 mapToDrawTriID(face, 0, &numTrisOfFace);
2009
2010 for (int k = 0; k < numTrisOfFace; ++k)
2011 {
2012 // triangle id of the k'th triangle of face
2013 int tri = mapToDrawTriID(face, k, 0);
2014
2015 // the corresponding face of that triangle (inverse map)
2016 int dbg_face = mapToOriginalFaceID(tri);
2017 if (face != dbg_face)
2018 {
2019 if (file.is_open())
2020 file << "error: face " << face << " -> (numTris: " << numTrisOfFace << ", tri " << tri << " -> face " << dbg_face << ")\n";
2021 ++numErrors;
2022 }
2023 }
2024 }
2025
2026 if (file.is_open())
2027 file << numErrors << " errors found\n\n";
2028 numTotalErrors += numErrors;
2029
2030 // ---------------------------------------------------------------------------------------
2031
2032 // check input (face, corner) -> vertex id
2033 if (file.is_open())
2034 file << "checking (face, corner) -> vbo by comparing vertex data ..\n";
2035 numErrors = 0;
2036
2037 char* vtxCmpData = new char[decl_.getVertexStride() * 2];
2038
2039 for (int face = 0; face < getNumFaces(); ++face)
2040 {
2041 int fsize = getFaceSize(face);
2042
2043 for (int k = 0; k < fsize; ++k)
2044 {
2045 char* v0 = vtxCmpData;
2046 char* v1 = vtxCmpData + decl_.getVertexStride();
2047
2048 memset(v0, 0, decl_.getVertexStride());
2049 memset(v1, 0, decl_.getVertexStride());
2050
2051 // get input vertex
2052 getInputFaceVertexData(face, k, v0);
2053
2054 // get output vertex
2055 int vertex = mapToDrawVertexID(face, k);
2056 getVertex(vertex, v1);
2057
2058 // allow slightly larger errors
2059 MeshCompilerVertexCompare verifyCmp(1e-3, 1e-3f);
2060
2061 if (!verifyCmp.equalVertex(v0, v1, &decl_))
2062 {
2063 std::string vertexData0 = vertexToString(v0);
2064 std::string vertexData1 = vertexToString(v1);
2065
2066 if (file)
2067 file << "error: (face " << face << ", corner " << k << ") -> vertex " << vertex << ": " << vertexData0.c_str() << " != "<< vertexData1.c_str() << "\n";
2068
2069 ++numErrors;
2070 }
2071 }
2072 }
2073
2074 if (file.is_open())
2075 file << numErrors << " errors found\n\n";
2076 numTotalErrors += numErrors;
2077
2078 numErrors = 0;
2079
2080 // ---------------------------------------------------------------------------------------
2081
2082 // check vertex id -> input (face, corner)
2083 if (file.is_open())
2084 file << "checking vbo -> (face, corner) by comparing vertex data ..\n";
2085
2086 for (int vertex = 0; vertex < getNumVertices(); ++vertex)
2087 {
2088 // map from vbo vertex id back to (face, corner)
2089 int face = 0, corner = 0;
2090 int posID = mapToOriginalVertexID(vertex, face, corner);
2091
2092 char* v0 = vtxCmpData;
2093 char* v1 = vtxCmpData + decl_.getVertexStride();
2094
2095 memset(v0, 0, decl_.getVertexStride());
2096 memset(v1, 0, decl_.getVertexStride());
2097
2098 // compare vbo data at [vertex] with the input data at (face, corner)
2099
2100 // get output vertex
2101 getVertex(vertex, v0);
2102
2103 // get input vertex
2104 if (face >= 0)
2105 getInputFaceVertexData(face, corner, v1);
2106 else
2107 {
2108 // isolated vertex
2109 for (unsigned int i = 0; i < decl_.getNumElements(); ++i)
2110 {
2111 const VertexElement* el = decl_.getElement(i);
2112 input_[i].getElementData(posID, (char*)v1 + (size_t)el->pointer_, el);
2113 }
2114 }
2115
2116 if (!vertexCompare_->equalVertex(v0, v1, &decl_))
2117 {
2118 std::string vertexData0 = vertexToString(v0);
2119 std::string vertexData1 = vertexToString(v1);
2120
2121 if (file)
2122 file << "error: vertex " << vertex << " -> (face " << face << ", corner " << corner << "): " << vertexData0.c_str() << " != " << vertexData1.c_str() << "\n";
2123 ++numErrors;
2124 }
2125 }
2126
2127 if (file.is_open())
2128 file << numErrors << " errors found\n\n";
2129 numTotalErrors += numErrors;
2130
2131 numErrors = 0;
2132
2133 delete [] vtxCmpData;
2134
2135
2136 // -----------------------------------------------------------
2137
2138 // check unshared vertex
2139 if (provokingVertex_ >= 0)
2140 {
2141 if (file.is_open())
2142 file << "checking unshared per face vertices ..\n";
2143
2144 // count number of references for each vertex
2145 std::vector< std::map<int, int> > VertexRefs;
2146 VertexRefs.resize(getNumVertices());
2147
2148 for (int face = 0; face < numFaces_; ++face)
2149 {
2150 int nTris = 0;
2151 mapToDrawTriID(face, 0, &nTris);
2152
2153 for (int k = 0; k < nTris; ++k)
2154 {
2155 int tri = mapToDrawTriID(face, k, 0);
2156
2157 int faceVertex = getIndex(tri * 3 + provokingVertex_);
2158
2159 VertexRefs[faceVertex][face] = 1;
2160 }
2161
2162 }
2163
2164 // the first vertex of each face should not be referenced by more than one face
2165
2166 for (int i = 0; i < getNumVertices(); ++i)
2167 {
2168 if (VertexRefs[i].size() > 1)
2169 {
2170 if (file)
2171 {
2172 file << "error : vertex " << i << " is referenced by " << VertexRefs[i].size() << " faces: ";
2173
2174 for (std::map<int, int>::iterator it = VertexRefs[i].begin(); it != VertexRefs[i].end(); ++it)
2175 file << it->first << ", ";
2176
2177 file << "\n";
2178 }
2179 ++numErrors;
2180 }
2181 }
2182
2183 if (file.is_open())
2184 file << numErrors << " errors found\n\n";
2185 numTotalErrors += numErrors;
2186
2187 numErrors = 0;
2188
2189
2190 // -----------------------------------------------------------
2191 // check face group sorting
2192
2193 if (file.is_open())
2194 file << "checking face group sorting ..\n";
2195
2196 for (int i = 0; i < getNumSubsets(); ++i)
2197 {
2198 const ACG::MeshCompiler::Subset* sub = getSubset(i);
2199
2200 for (int k = 0; k < (int)sub->numTris; ++k)
2201 {
2202 int faceID = mapToOriginalFaceID(sub->startIndex/3 + k);
2203 int grID = getFaceGroup(faceID);
2204
2205 // input face group should match the subsets
2206
2207 if (grID != sub->id)
2208 {
2209 if (file.is_open())
2210 file << "error: face " << faceID << " with group-id " << grID << " was mapped to subset-group " << sub->id << "\n";
2211
2212 ++numErrors;
2213 }
2214
2215 }
2216 }
2217
2218 if (file.is_open())
2219 file << numErrors << " errors found\n\n";
2220 numTotalErrors += numErrors;
2221
2222 numErrors = 0;
2223 }
2224
2225 // -----------------------------------------------------------
2226 // check triangulation
2227
2228 if (file.is_open())
2229 file << "checking triangulation ..\n";
2230
2231 for (int i = 0; i < numFaces_; ++i)
2232 {
2233 int faceSize = getFaceSize(i);
2234
2235 std::vector<int> facePositions(faceSize, -1);
2236
2237 for (int k = 0; k < faceSize; ++k)
2238 facePositions[k] = getInputIndex(i, k, inputIDPos_);
2239
2240 int numFaceTris = 0;
2241 mapToDrawTriID(i, 0, &numFaceTris);
2242
2243 for (int t = 0; t < numFaceTris; ++t)
2244 {
2245 int triID = mapToDrawTriID(i, t);
2246
2247 int triPosOccurrence[3] = {-1, -1, -1};
2248
2249 for (int k = 0; k < 3; ++k)
2250 {
2251 int vertexID = getIndex(triID * 3 + k);
2252
2253 int originalFace = -1, originalCorner = -1;
2254 int posID = mapToOriginalVertexID(vertexID, originalFace, originalCorner);
2255
2256 // check if the triangle positions make a subset of the polygon positions
2257 for (int m = 0; m < faceSize; ++m)
2258 {
2259 if (posID == facePositions[m])
2260 {
2261 triPosOccurrence[k] = m;
2262 break;
2263 }
2264 }
2265
2266 if (triPosOccurrence[k] < 0)
2267 {
2268 if (file.is_open())
2269 file << "error: vertex at triangulated face " << i << " at triangle " << t << " at corner " << k << "is not even part of the original face!\n";
2270
2271 ++numErrors;
2272 }
2273 }
2274
2275 // check face winding of triangulation
2276 int numInversions = 0;
2277
2278 for (int k = 0; k < 3; ++k)
2279 {
2280 int p1 = triPosOccurrence[k];
2281 int p2 = triPosOccurrence[(k + 1) % 3];
2282
2283 if (p1 > p2)
2284 ++numInversions;
2285 }
2286
2287 if (numInversions > 1)
2288 {
2289 if (file.is_open())
2290 file << "error: triangulation of face " << i << " at triangle " << t << " has flipped winding order!\n";
2291
2292 ++numErrors;
2293 }
2294 }
2295 }
2296
2297 if (file.is_open())
2298 file << numErrors << " errors found\n\n";
2299 numTotalErrors += numErrors;
2300
2301 if (file.is_open())
2302 file.close();
2303 }
2304
2305 return numTotalErrors == 0;
2306 }
2307
2308 void MeshCompiler::dbgdump(const char* _filename) const
2309 {
2310 // dump all the internal arrays to text
2311
2312 std::ofstream file;
2313 file.open(_filename);
2314
2315 if (file.is_open())
2316 {
2317 for (int i = 0; i < numAttributes_; ++i)
2318 {
2319 const VertexElementInput* inp = input_ + i;
2320
2321 file << "attribute[" << i << "]: internalbuf " << ((const void*)inp->internalBuf) << ", data " << ((const void*)inp->data) << ", count " << inp->count << ", stride " << inp->stride << ", attrSize " << inp->attrSize << "\n";
2322 }
2323
2324 file << "\n\n";
2325 file << "faces " << numFaces_ << "\nindices " << numIndices_ << "\n";
2326
2327 if (!vertexWeldMapFace_.empty())
2328 {
2329 for (int i = 0; i < numFaces_; ++i)
2330 {
2331 for (int k = 0; k < getFaceSize(i); ++k)
2332 {
2333 int face = vertexWeldMapFace_[getInputFaceOffset(i) + k];
2334 int corner = vertexWeldMapCorner_[getInputFaceOffset(i) + k];
2335 file << "vertexWeldMap_[" << i <<", "<<k<<"] = ["<<face<<", "<<corner<<"]\n";
2336 }
2337 }
2338 }
2339
2340 for (size_t i = 0; i < faceBufSplit_.size(); ++i)
2341 file << "faceBufSplit_["<<i<<"] = "<<faceBufSplit_[i]<<"\n";
2342
2343 file << "\n\n";
2344
2345 for (size_t i = 0; i < faceGroupIDs_.size(); ++i)
2346 file << "faceGroupIDs_["<<i<<"] = "<<faceGroupIDs_[i]<<"\n";
2347
2348 file << "\n\n";
2349
2350 for (size_t i = 0; i < faceSortMap_.size(); ++i)
2351 file << "faceSortMap_["<<i<<"] = "<<faceSortMap_[i]<<"\n";
2352
2353 file << "\n\n";
2354
2355 for (size_t i = 0; i < triIndexBuffer_.size()/3; ++i)
2356 file << "tri["<<i<<"] = "<<triIndexBuffer_[i*3+1]<<" "<<triIndexBuffer_[i*3+1]<<" "<<triIndexBuffer_[i*3+2]<<"\n";
2357
2358 file << "\n\n";
2359
2360 for (size_t i = 0; i < subsets_.size(); ++i)
2361 {
2362 const Subset* sub = &subsets_[i];
2363 file <<"subset["<<i<<"]: id "<<sub->id<<", startIndex "<<sub->startIndex<<", numTris "<<sub->numTris<<", numFaces "<<sub->numFaces<<", startFace "<<sub->startFace<<"\n";
2364 }
2365
2366 file << "\n\n";
2367
2368 for (std::map<int, int>::const_iterator it = subsetIDMap_.begin();
2369 it != subsetIDMap_.end(); ++it)
2370 file << "subsetIDMap["<<it->first<<"] = "<<it->second<<"\n";
2371
2372 file << "\n\n";
2373
2374 for (int i = 0; i < numFaces_; ++i)
2375 {
2376 for (int k = 0; k < getFaceSize(i); ++k)
2377 file <<"mapToDrawVertexID["<<i<<", "<<k<<"] = "<<mapToDrawVertexID(i, k)<<"\n";
2378 }
2379
2380 file << "\n\n";
2381
2382 for (int i = 0; i < getNumVertices(); ++i)
2383 {
2384 int f, c;
2385 mapToOriginalVertexID(i, f, c);
2386 file <<"mapToOriginalVertexID["<<i<<"] = ["<<f<<", "<<c<<"]\n";
2387 }
2388
2389 file << "\n\nadjacencyVert\n";
2390 adjacencyVert_.dbgdump(file);
2391
2392 file << "\n\n";
2393
2394 file << "\n\n";
2395
2396
2397 for (int i = 0; i < numFaces_; ++i)
2398 {
2399 for (int k = 0; k < getFaceSize(i); ++k)
2400 {
2401 float vtx[32];
2402 getInputFaceVertexData(i, k, vtx);
2403
2404 // pos[0] pos[1] pos[2] uv[0] uv[1] n[0] n[1] n[2]
2405 file << "data["<<i<<", "<<k<<"] = ("<<vtx[0]<<" "<<vtx[1]<<" "<<vtx[2]<<") ("<<vtx[3]<<" "<<vtx[4]<<") ("<<vtx[5]<<" "<<vtx[6]<<" "<<vtx[7]<<")\n";
2406 }
2407 }
2408
2409 file.close();
2410 }
2411 }
2412
2413
2414 void MeshCompiler::AdjacencyList::dbgdump(std::ofstream& file) const
2415 {
2416 if (file.is_open())
2417 {
2418 for (int i = 0; i < num; ++i)
2419 {
2420 for (int k = 0; k < getCount(i); ++k)
2421 file << "adj["<<i<<"]["<<k<<"] = "<<getAdj(i,k)<<"\n";
2422 }
2423 }
2424 }
2425
2426 void MeshCompiler::VertexElementInput::getElementData(int _idx, void* _dst, const VertexElement* _desc) const
2427 {
2428 // attribute data not set by user, skip
2429 if (count == 0 || !data)
2430 {
2431 memset(_dst, 0, attrSize);
2432 return;
2433 }
2434
2435 // assert(_idx >= 0);
2436 // assert(_idx < count);
2437
2438 if (_idx < 0 || _idx >= count)
2439 {
2440 memset(_dst, 0, attrSize);
2441 return;
2442 }
2443
2444 const void* dataAdr = static_cast<const char*>(data) + (size_t)(_idx * stride);
2445
2446 if (fmt == 0 || elementSize == -1 || fmt == _desc->type_)
2447 memcpy(_dst, dataAdr, attrSize);
2448 else
2449 {
2450 // typecast data to format in vertex buffer
2451 int data_i[4] = {0,0,0,0}; // data in integer fmt
2452 double data_d[4] = {0.0, 0.0, 0.0, 0.0}; // data in floating point
2453
2454 // read data
2455 for (int i = 0; i < elementSize; ++i)
2456 {
2457 switch (fmt)
2458 {
2459 case GL_FLOAT: data_d[i] = (static_cast<const float*>(dataAdr))[i]; break;
2460 case GL_DOUBLE: data_d[i] = (static_cast<const double*>(dataAdr))[i]; break;
2461
2462 case GL_UNSIGNED_INT:
2463 case GL_INT: data_i[i] = (static_cast<const int*>(dataAdr))[i]; break;
2464
2465 case GL_UNSIGNED_SHORT:
2466 case GL_SHORT: data_i[i] = (static_cast<const short*>(dataAdr))[i]; break;
2467
2468 case GL_UNSIGNED_BYTE:
2469 case GL_BYTE: data_i[i] = (static_cast<const short*>(dataAdr))[i]; break;
2470
2471 default: std::cerr << "MeshCompiler: unknown data format - " << fmt << std::endl; break;
2472 }
2473 }
2474
2475
2476 // zero mem
2477 memset(_dst, 0, attrSize);
2478
2479 // typecast data
2480 if (fmt == GL_FLOAT || fmt == GL_DOUBLE)
2481 {
2482 for (int i = 0; i < (int)_desc->numElements_ && i < (int)elementSize; ++i)
2483 {
2484 switch (_desc->type_)
2485 {
2486 case GL_FLOAT: ((float*)_dst)[i] = (float)data_d[i]; break;
2487 case GL_DOUBLE: ((double*)_dst)[i] = (double)data_d[i]; break;
2488
2489 case GL_UNSIGNED_INT:
2490 case GL_INT: ((int*)_dst)[i] = (int)data_d[i]; break;
2491
2492 case GL_UNSIGNED_BYTE:
2493 case GL_BYTE: ((char*)_dst)[i] = (char)data_d[i]; break;
2494
2495 case GL_UNSIGNED_SHORT:
2496 case GL_SHORT: ((short*)_dst)[i] = (short)data_d[i]; break;
2497
2498 default: break;
2499 }
2500 }
2501 }
2502 else
2503 {
2504 for (int i = 0; i < (int)_desc->numElements_ && i < (int)elementSize; ++i)
2505 {
2506 switch (_desc->type_)
2507 {
2508 case GL_FLOAT: ((float*)_dst)[i] = (float)data_i[i]; break;
2509 case GL_DOUBLE: ((double*)_dst)[i] = (double)data_i[i]; break;
2510
2511 case GL_UNSIGNED_INT:
2512 case GL_INT: ((int*)_dst)[i] = (int)data_i[i]; break;
2513
2514 case GL_UNSIGNED_BYTE:
2515 case GL_BYTE: ((char*)_dst)[i] = (char)data_i[i]; break;
2516
2517 case GL_UNSIGNED_SHORT:
2518 case GL_SHORT: ((short*)_dst)[i] = (short)data_i[i]; break;
2519
2520 default: break;
2521 }
2522 }
2523 }
2524
2525
2526 }
2527 }
2528
2529
2530 void MeshCompiler::dbgdumpObj(const char* _filename) const
2531 {
2532 // dump resulting mesh to obj file
2533
2534 std::ofstream file;
2535 file.open(_filename);
2536
2537 if (file.is_open())
2538 {
2539 for (int i = 0; i < numDrawVerts_; ++i)
2540 {
2541 float vertex[64];
2542
2543 getVertex(i, vertex);
2544
2545 if (inputIDPos_ >= 0)
2546 {
2547 float* pos = vertex + (size_t)decl_.getElement(inputIDPos_)->pointer_ / 4;
2548 file << "v "<<pos[0]<<" "<<pos[1]<<" "<<pos[2]<<"\n";
2549 }
2550
2551 if (inputIDNorm_ >= 0)
2552 {
2553 float* pos = vertex + (size_t)decl_.getElement(inputIDNorm_)->pointer_ / 4;
2554 file << "vn "<<pos[0]<<" "<<pos[1]<<" "<<pos[2]<<"\n";
2555 }
2556
2557 if (inputIDTexC_ >= 0)
2558 {
2559 float* pos = vertex + (size_t)decl_.getElement(inputIDTexC_)->pointer_ / 4;
2560 file << "vt "<<pos[0]<<" "<<pos[1]<<"\n";
2561 }
2562 }
2563
2564
2565 for (int i = 0; i < numTris_; ++i)
2566 {
2567 if (!inputIDTexC_ && !inputIDNorm_)
2568 file << "f "<<indices_[i*3]+1<<" "<<indices_[i*3+1]+1<<" "<<indices_[i*3+2]+1<<"\n";
2569
2570 else if (!inputIDTexC_)
2571 file << "f "<<indices_[i*3]+1<<"/"<<indices_[i*3]+1<<" "<<indices_[i*3+1]+1<<"/"<<indices_[i*3+1]+1<<" "<<indices_[i*3+2]+1<<"/"<<indices_[i*3+2]+1<<"\n";
2572
2573 else
2574 file << "f "<<indices_[i*3]+1<<"/"<<indices_[i*3]+1<<"/"<<indices_[i*3]+1<<" "<<indices_[i*3+1]+1<<"/"<<indices_[i*3+1]+1<<"/"<<indices_[i*3+1]+1<<" "<<indices_[i*3+2]+1<<"/"<<indices_[i*3+2]+1<<"/"<<indices_[i*3+2]+1<<"\n";
2575 }
2576
2577
2578 file.close();
2579 }
2580 }
2581
2582
2583 void MeshCompiler::dbgdumpInputObj( const char* _filename ) const
2584 {
2585 // dump input mesh to obj file
2586
2587 const int nVerts = (inputIDPos_ >= 0) ? input_[inputIDPos_].count : 0;
2588 // const int nNormals = (inputIDNorm_ >= 0) ? input_[inputIDNorm_].count : 0;
2589 // const int nTexC = (inputIDTexC_ >= 0) ? input_[inputIDTexC_].count : 0;
2590
2591
2592 std::ofstream file;
2593 file.open(_filename);
2594
2595 if (file.is_open())
2596 {
2597 // write vertex data
2598
2599 for (int i = 0; i < nVerts; ++i)
2600 {
2601 float pos[16];
2602 const VertexElement* el = decl_.getElement(inputIDPos_);
2603 input_[inputIDPos_].getElementData(i, pos, el);
2604
2605 file << "v "<<pos[0]<<" "<<pos[1]<<" "<<pos[2]<<"\n";
2606 }
2607
2608 if (inputIDTexC_ >= 0)
2609 {
2610 float pos[16];
2611 const VertexElementInput* vei = &input_[inputIDTexC_];
2612 const VertexElement* el = decl_.getElement(inputIDTexC_);
2613
2614 for (int i = 0; i < vei->count; ++i)
2615 {
2616 vei->getElementData(i, pos, el);
2617 file << "vt "<<pos[0]<<" "<<pos[1]<<"\n";
2618 }
2619 }
2620
2621
2622 if (inputIDNorm_ >= 0)
2623 {
2624 float pos[16];
2625 const VertexElementInput* vei = &input_[inputIDNorm_];
2626 const VertexElement* el = decl_.getElement(inputIDNorm_);
2627
2628 for (int i = 0; i < vei->count; ++i)
2629 {
2630 vei->getElementData(i, pos, el);
2631 file << "vn "<<pos[0]<<" "<<pos[1]<<" "<<pos[2]<<"\n";
2632 }
2633 }
2634
2635
2636 // write face data
2637
2638 for (int i = 0; i < faceInput_->getNumFaces(); ++i)
2639 {
2640 std::string strLine = "f ";
2641
2642 int size = faceInput_->getFaceSize(i);
2643
2644 char tmp[0xff];
2645 for (int k = 0; k < size; ++k)
2646 {
2647 if (inputIDNorm_>=0 && inputIDTexC_>=0)
2648 sprintf(tmp, "%d/%d/%d ", faceInput_->getSingleFaceAttr(i, k, inputIDPos_) + 1,
2649 faceInput_->getSingleFaceAttr(i, k, inputIDTexC_) + 1,
2650 faceInput_->getSingleFaceAttr(i, k, inputIDNorm_) + 1);
2651 else if (inputIDNorm_ >= 0)
2652 sprintf(tmp, "%d//%d ", faceInput_->getSingleFaceAttr(i, k, inputIDPos_) + 1, faceInput_->getSingleFaceAttr(i, k, inputIDNorm_) + 1);
2653 else if (inputIDTexC_ >= 0)
2654 sprintf(tmp, "%d/%d ", faceInput_->getSingleFaceAttr(i, k, inputIDPos_) + 1, faceInput_->getSingleFaceAttr(i, k, inputIDTexC_) + 1);
2655 else
2656 sprintf(tmp, "%d ", faceInput_->getSingleFaceAttr(i, k, inputIDPos_) + 1);
2657
2658 strLine += tmp;
2659 }
2660
2661 file << strLine.c_str() << "\n";
2662 }
2663
2664 file.close();
2665 }
2666
2667 }
2668
2669
2670 void MeshCompiler::dbgdumpInputBin( const char* _filename, bool _seperateFiles ) const
2671 {
2672 // dump input mesh to custom binary format (for debugging/profiling purposes)
2673
2674 const int nVerts = (inputIDPos_ >= 0) ? input_[inputIDPos_].count : 0;
2675 const int nNormals = (inputIDNorm_ >= 0) ? input_[inputIDNorm_].count : 0;
2676 const int nTexC = (inputIDTexC_ >= 0) ? input_[inputIDTexC_].count : 0;
2677
2678 if (!_seperateFiles)
2679 {
2680 /*
2681 simple binary format (can be used for profiling and testing with large meshes):
2682
2683 int numFaces,
2684 numVerts,
2685 numNormals,
2686 numTexCoords,
2687 faceBufSize
2688
2689 -------------------------
2690
2691 int faceSize[numFaces];
2692 int faceData[attribute][faceBufSize];
2693
2694 -------------------------
2695
2696 float3 verts[numVerts];
2697 float2 texc[numTexCoords];
2698 float3 normals[numNormals];
2699
2700 -------------------------
2701
2702 adjacency chunks: vertex + face
2703
2704 int num, bufsize;
2705 int* offset[num];
2706 uchar* count[num];
2707 int* buf[bufsize];
2708
2709 */
2710
2711
2712 FILE* file = 0;
2713
2714 file = fopen(_filename, "wb");
2715
2716 if (file)
2717 {
2718 const int nFaces = faceInput_->getNumFaces();
2719 fwrite(&nFaces, 4, 1, file);
2720
2721 fwrite(&nVerts, 4, 1, file);
2722 fwrite(&nNormals, 4, 1, file);
2723 fwrite(&nTexC, 4, 1, file);
2724
2725 int faceBufSize = 0;
2726
2727 for (int i = 0; i < faceInput_->getNumFaces(); ++i)
2728 faceBufSize += faceInput_->getFaceSize(i);
2729
2730 fwrite(&faceBufSize, 4, 1, file);
2731
2732 // write face data
2733
2734 for (int i = 0; i < faceInput_->getNumFaces(); ++i)
2735 {
2736 int fsize = faceInput_->getFaceSize(i);
2737 fwrite(&fsize, 4, 1, file);
2738 }
2739
2740 for (int i = 0; i < faceInput_->getNumFaces(); ++i)
2741 {
2742 for (int k = 0; k < faceInput_->getFaceSize(i); ++k)
2743 {
2744 int idx = faceInput_->getSingleFaceAttr(i, k, inputIDPos_);
2745 fwrite(&idx, 4, 1, file);
2746 }
2747 }
2748
2749 if (inputIDTexC_ >= 0)
2750 {
2751 for (int i = 0; i < faceInput_->getNumFaces(); ++i)
2752 {
2753 for (int k = 0; k < faceInput_->getFaceSize(i); ++k)
2754 {
2755 int idx = faceInput_->getSingleFaceAttr(i, k, inputIDTexC_);
2756 fwrite(&idx, 4, 1, file);
2757 }
2758 }
2759 }
2760
2761 if (inputIDNorm_ >= 0)
2762 {
2763 for (int i = 0; i < faceInput_->getNumFaces(); ++i)
2764 {
2765 for (int k = 0; k < faceInput_->getFaceSize(i); ++k)
2766 {
2767 int idx = faceInput_->getSingleFaceAttr(i, k, inputIDNorm_);
2768 fwrite(&idx, 4, 1, file);
2769 }
2770 }
2771 }
2772
2773 // write vertex data
2774
2775
2776 for (int i = 0; i < nVerts; ++i)
2777 {
2778 float pos[16];
2779 const VertexElement* el = decl_.getElement(inputIDPos_);
2780 input_[inputIDPos_].getElementData(i, pos, el);
2781
2782 fwrite(pos, 4, 3, file);
2783 }
2784
2785 if (inputIDTexC_ >= 0)
2786 {
2787 float pos[16];
2788 const VertexElementInput* vei = &input_[inputIDTexC_];
2789 const VertexElement* el = decl_.getElement(inputIDTexC_);
2790
2791 for (int i = 0; i < vei->count; ++i)
2792 {
2793 vei->getElementData(i, pos, el);
2794 fwrite(pos, 4, 2, file);
2795 }
2796 }
2797
2798
2799 if (inputIDNorm_ >= 0)
2800 {
2801 float pos[16];
2802 const VertexElementInput* vei = &input_[inputIDNorm_];
2803 const VertexElement* el = decl_.getElement(inputIDNorm_);
2804
2805 for (int i = 0; i < vei->count; ++i)
2806 {
2807 vei->getElementData(i, pos, el);
2808 fwrite(pos, 4, 3, file);
2809 }
2810 }
2811
2812
2813 // write adjacency
2814
2815 fwrite(&adjacencyVert_.num, 4, 1, file);
2816 fwrite(&adjacencyVert_.bufSize, 4, 1, file);
2817
2818 fwrite(adjacencyVert_.start, 4, adjacencyVert_.num, file);
2819 fwrite(adjacencyVert_.count, 1, adjacencyVert_.num, file);
2820 fwrite(adjacencyVert_.buf, 4, adjacencyVert_.bufSize, file);
2821
2822 fclose(file);
2823 }
2824
2825 }
2826 else
2827 {
2828 // dump data to separate files
2829 FILE* file = fopen("../mesh_fsize.bin", "wb");
2830
2831 for (int i = 0; i < numFaces_; ++i)
2832 {
2833 unsigned char fsize = (unsigned char)faceInput_->getFaceSize(i);
2834 fwrite(&fsize, 1, 1, file);
2835 }
2836
2837 fclose(file);
2838
2839 file = fopen("../mesh_fdata_pos.bin", "wb");
2840
2841 for (int i = 0; i < numFaces_; ++i)
2842 {
2843 for (int k = 0; k < faceInput_->getFaceSize(i); ++k)
2844 {
2845 int idx = faceInput_->getSingleFaceAttr(i, k, inputIDPos_);
2846 fwrite(&idx, 4, 1, file);
2847 }
2848 }
2849
2850 fclose(file);
2851
2852 if (inputIDTexC_ >= 0)
2853 {
2854 file = fopen("../mesh_fdata_texc.bin", "wb");
2855
2856 for (int i = 0; i < numFaces_; ++i)
2857 {
2858 for (int k = 0; k < faceInput_->getFaceSize(i); ++k)
2859 {
2860 int idx = faceInput_->getSingleFaceAttr(i, k, inputIDTexC_);
2861 fwrite(&idx, 4, 1, file);
2862 }
2863 }
2864
2865 fclose(file);
2866 }
2867
2868 if (inputIDNorm_ >= 0)
2869 {
2870 file = fopen("../mesh_fdata_norm.bin", "wb");
2871
2872 for (int i = 0; i < numFaces_; ++i)
2873 {
2874 for (int k = 0; k < faceInput_->getFaceSize(i); ++k)
2875 {
2876 int idx = faceInput_->getSingleFaceAttr(i, k, inputIDNorm_);
2877 fwrite(&idx, 4, 1, file);
2878 }
2879 }
2880
2881 fclose(file);
2882 }
2883
2884 // write vertex data
2885
2886 file = fopen("../mesh_vdata_pos.bin", "wb");
2887 for (int i = 0; i < nVerts; ++i)
2888 {
2889 float pos[16];
2890 const VertexElement* el = decl_.getElement(inputIDPos_);
2891 input_[inputIDPos_].getElementData(i, pos, el);
2892
2893 fwrite(pos, 4, 3, file);
2894 }
2895 fclose(file);
2896
2897 if (inputIDTexC_ >= 0)
2898 {
2899 file = fopen("../mesh_vdata_texc.bin", "wb");
2900
2901 float pos[16];
2902 const VertexElementInput* vei = &input_[inputIDTexC_];
2903 const VertexElement* el = decl_.getElement(inputIDTexC_);
2904
2905 for (int i = 0; i < vei->count; ++i)
2906 {
2907 vei->getElementData(i, pos, el);
2908 fwrite(pos, 4, 2, file);
2909 }
2910
2911 fclose(file);
2912 }
2913
2914
2915 if (inputIDNorm_ >= 0)
2916 {
2917 file = fopen("../mesh_vdata_norm.bin", "wb");
2918
2919 float pos[16];
2920 const VertexElementInput* vei = &input_[inputIDNorm_];
2921 const VertexElement* el = decl_.getElement(inputIDNorm_);
2922
2923 for (int i = 0; i < vei->count; ++i)
2924 {
2925 vei->getElementData(i, pos, el);
2926 fwrite(pos, 4, 3, file);
2927 }
2928
2929 fclose(file);
2930 }
2931 }
2932
2933 }
2934
2935
2936 void MeshCompiler::setFaceVerts( int _i, int _numEdges, int* _v )
2937 {
2938 setFaceAttrib(_i, _numEdges, _v, inputIDPos_);
2939 }
2940
2941 void MeshCompiler::setFaceVerts( int _i, int _v0, int _v1, int _v2 )
2942 {
2943 int tmp[] = {_v0, _v1, _v2};
2944 setFaceAttrib(_i, 3, tmp, inputIDPos_);
2945 }
2946
2947 void MeshCompiler::setFaceNormals( int _i, int _numEdges, int* _v )
2948 {
2949 setFaceAttrib(_i, _numEdges, _v, inputIDNorm_);
2950 }
2951
2952 void MeshCompiler::setFaceNormals( int _i, int _v0, int _v1, int _v2 )
2953 {
2954 int tmp[] = {_v0, _v1, _v2};
2955 setFaceAttrib(_i, 3, tmp, inputIDNorm_);
2956 }
2957
2958
2959 void MeshCompiler::setFaceTexCoords( int _i, int _numEdges, int* _v )
2960 {
2961 setFaceAttrib(_i, _numEdges, _v, inputIDTexC_);
2962 }
2963
2964 void MeshCompiler::setFaceTexCoords( int _i, int _v0, int _v1, int _v2 )
2965 {
2966 int tmp[] = {_v0, _v1, _v2};
2967 setFaceAttrib(_i, 3, tmp, inputIDTexC_);
2968 }
2969
2970 void MeshCompiler::getVertex( int _id, void* _out ) const
2971 {
2972 int faceID, cornerID;
2973 int posID = mapToOriginalVertexID(_id, faceID, cornerID);
2974
2975 if (faceID >= 0)
2976 {
2977 // read connnected vertex
2978 for (int i = 0; i < numAttributes_; ++i)
2979 {
2980 const VertexElement* el = decl_.getElement(i);
2981
2982 int idx = getInputIndex(faceID, cornerID, i);
2983
2984 input_[i].getElementData(idx, (char*)_out + (size_t)el->pointer_, el);
2985 }
2986 }
2987 else
2988 {
2989 // isolated vertex
2990
2991 for (int i = 0; i < numAttributes_; ++i)
2992 {
2993 const VertexElement* el = decl_.getElement(i);
2994 input_[i].getElementData(posID, (char*)_out + (size_t)el->pointer_, el);
2995 }
2996 }
2997 }
2998
2999 int MeshCompiler::getIndex( int _i ) const
3000 {
3001 assert(_i >= 0);
3002 assert(_i < numTris_ * 3);
3003 return indices_[_i];
3004 }
3005
3006 void MeshCompiler::createVertexMap(bool _keepIsolatedVerts)
3007 {
3008 // vertexMap: vertex id -> (face, corner)
3009
3010 // the current vertex buffer does not contain any isolated vertices
3011 // -> add them to end of buffer if required
3012 const int offsetIso = numDrawVerts_;
3013 if (_keepIsolatedVerts)
3014 numDrawVerts_ += numIsolatedVerts_; // keep
3015 else
3016 numIsolatedVerts_ = 0; // delete isolated vertices
3017
3018 vertexMapFace_.resize(numDrawVerts_, -1);
3019 vertexMapCorner_.resize(numDrawVerts_, -1);
3020
3021 for (int i = 0; i < numFaces_; ++i)
3022 {
3023 const int fsize = getFaceSize(i);
3024 for (int k = 0; k < fsize; ++k)
3025 {
3026 // map from (face, corner) -> vertex id is given by getInputIndexSplit(), so create the inverse
3027 int vertexID = getInputIndexSplit(i, k);
3028 vertexMapFace_[vertexID] = i;
3029 vertexMapCorner_[vertexID] = k;
3030 }
3031 }
3032
3033 if (_keepIsolatedVerts)
3034 {
3035 // add isolated verts to end of map
3036 for (int i = 0; i < numIsolatedVerts_; ++i)
3037 {
3038 assert(vertexMapFace_[offsetIso + i] < 0);
3039 vertexMapFace_[offsetIso + i] = isolatedVertices_[i];
3040 }
3041 }
3042
3043 // validate
3044 #ifdef _DEBUG
3045 for (int i = 0; i < numDrawVerts_; ++i)
3046 {
3047 if (i < offsetIso)
3048 {
3049 if (vertexMapFace_[i] < 0 ||
3050 vertexMapCorner_[i] < 0)
3051 std::cerr << "mesh-assembler: vertexMap error at index: " << i << std::endl;
3052 }
3053 else if (vertexMapFace_[i] < 0)
3054 std::cerr << "mesh-assembler: vertexMap error at index: " << i << std::endl;
3055 }
3056 #endif // _DEBUG
3057
3058 }
3059
3060
3061 void MeshCompiler::createFaceMap()
3062 {
3063 // -------------------------------
3064 // create tri -> face map
3065
3066 triToFaceMap_.clear();
3067 triToFaceMap_.resize(numTris_, -1);
3068 for (int i = 0; i < numTris_; ++i)
3069 {
3070 int faceID = i;
3071 if (!triOptMap_.empty())
3072 faceID = triOptMap_[faceID];
3073
3074 if (!triToSortFaceMap_.empty())
3075 faceID = triToSortFaceMap_[faceID];
3076
3077 if (!faceSortMap_.empty())
3078 faceID = faceSortMap_[faceID];
3079
3080 triToFaceMap_[i] = faceID;
3081 }
3082
3083
3084 // -------------------------------
3085 // create face -> tri map
3086
3087 // offset table is necessary for variable polygon face sizes, because the map is stored in a single array
3088
3089 // create offset table
3090 faceToTriMapOffset_.clear();
3091 if (!constantFaceSize_)
3092 {
3093 faceToTriMapOffset_.resize(numTris_, -1);
3094
3095 int offset = 0;
3096 for (int i = 0; i < numFaces_; ++i)
3097 {
3098 faceToTriMapOffset_[i] = offset;
3099
3100 // # tris of face
3101 int fsize = getFaceSize(i);
3102 offset += fsize - 2;
3103 }
3104 }
3105
3106 // create face -> tri map
3107 faceToTriMap_.clear();
3108 faceToTriMap_.resize(numTris_, -1);
3109
3110 for (int i = 0; i < numTris_; ++i)
3111 {
3112 // face -> tri map is the inverse of tri -> face map, which is already given by mapToOriginalFaceID()
3113 int faceID = mapToOriginalFaceID(i);
3114
3115 // offset into lookup table
3116 int offset = constantFaceSize_ ? (faceID * (maxFaceSize_ - 2)) : faceToTriMapOffset_[faceID];
3117
3118 int triNo = 0;
3119
3120 // search for free entry
3121 while (faceToTriMap_[offset + triNo] != -1 && triNo + offset < numTris_)
3122 ++triNo;
3123
3124 assert(triNo < getFaceSize(faceID) - 2);
3125
3126 faceToTriMap_[offset + triNo] = i;
3127 }
3128 }
3129
3130
3131
3132 void MeshCompiler::dbgdumpAdjList( const char* _filename ) const
3133 {
3134 // dump adjacency list to text file: vertex -> adjacent faces
3135
3136 FILE* file = 0;
3137
3138 file = fopen(_filename, "wt");
3139
3140 if (file)
3141 {
3142 fprintf(file, "vertex-adjacency: \n");
3143 for (int i = 0; i < input_[inputIDPos_].count; ++i)
3144 {
3145 // sorting the adjacency list for easy comparison of adjacency input
3146 int count = getAdjVertexFaceCount(i);
3147
3148 std::vector<int> sortedList(count);
3149 for (int k = 0; k < count; ++k)
3150 sortedList[k] = getAdjVertexFace(i, k);
3151
3152 std::sort(sortedList.begin(), sortedList.end());
3153
3154 for (int k = 0; k < count; ++k)
3155 fprintf(file, "adj[%d][%d] = %d\n", i, k, sortedList[k]);
3156 }
3157
3158
3159 fclose(file);
3160 }
3161 }
3162
3163 void MeshCompiler::setFaceGroup( int _i, short _groupID )
3164 {
3165 if ((int)faceGroupIDs_.size() <= std::max(numFaces_,_i))
3166 faceGroupIDs_.resize(std::max(numFaces_,_i+1), -1);
3167
3168 faceGroupIDs_[_i] = _groupID;
3169 }
3170
3171 void MeshCompiler::getVertexBuffer( void* _dst, const int _offset /*= 0*/, const int _range /*= -1*/ )
3172 {
3173 // the final vertex buffer is not explicitly stored (save memory)
3174 // so it is created by reading the input data and placing it at the right position in the vbo
3175
3176 int batchSize = _range;
3177
3178 // clamp batch size
3179 if ((_range < 0) || (_offset + batchSize > numDrawVerts_))
3180 batchSize = numDrawVerts_ - _offset;
3181
3182 char* bdst = (char*)_dst;
3183
3184 for (int i = 0; i < batchSize; ++i)
3185 {
3186 getVertex(i + _offset, bdst + decl_.getVertexStride() * i);
3187 }
3188 }
3189
3190 struct MeshCompiler_EdgeTriMapKey
3191 {
3192 // ordered vertex ids of the edge: e0 < e1
3193 int e0, e1;
3194
3195 MeshCompiler_EdgeTriMapKey(int a, int b)
3196 : e0(std::min(a,b)), e1(std::max(a,b)) {}
3197
3198 bool operator ==(const MeshCompiler_EdgeTriMapKey& k) const
3199 {
3200 return e0 == k.e0 && e1 == k.e1;
3201 }
3202
3203 bool operator <(const MeshCompiler_EdgeTriMapKey& k) const
3204 {
3205 if (e0 < k.e0)
3206 return true;
3207
3208 if (e0 > k.e0)
3209 return false;
3210
3211 return e1 < k.e1;
3212 }
3213 };
3214
3215
3216 #ifdef ACG_MC_USE_STL_HASH
3217 // requires c++0x
3218 struct MeshCompiler_EdgeTriMapKey_Hash
3219 {
3220 std::size_t operator()(const MeshCompiler_EdgeTriMapKey& k) const
3221 {
3222 return ((std::hash<int>()(k.e0) << 1) ^ std::hash<int>()(k.e1)) >> 1;
3223 }
3224 };
3225 #else
3226 uint qHash(const MeshCompiler_EdgeTriMapKey& k)
3227 {
3228 return ((::qHash(k.e0) << 1) ^ ::qHash(k.e1)) >> 1;
3229 }
3230 #endif // ACG_MC_USE_STL_HASH
3231
3232
3233 void MeshCompiler::getIndexAdjBuffer(void* _dst, const int _borderIndex /* = -1 */)
3234 {
3235 int* idst = (int*)_dst;
3236
3237 for (int i = 0; i < numTris_; ++i)
3238 {
3239 // initialize all triangles
3240 idst[i*6] = getIndex(i*3);
3241 idst[i*6+2] = getIndex(i*3+1);
3242 idst[i*6+4] = getIndex(i*3+2);
3243
3244 idst[i*6+1] = _borderIndex;
3245 idst[i*6+3] = _borderIndex;
3246 idst[i*6+5] = _borderIndex;
3247 }
3248
3249 // map from edge -> adjacent tris
3250 QHash<MeshCompiler_EdgeTriMapKey, std::pair<int, int> > EdgeAdjMap;
3251
3252 for (int i = 0; i < numTris_; ++i)
3253 {
3254 // get input positions of triangle
3255 int PosIdx[3];
3256
3257 for (int k = 0; k < 3; ++k)
3258 {
3259 int faceId, cornerId;
3260 PosIdx[k] = mapToOriginalVertexID(getIndex(i*3+k), faceId, cornerId);
3261 }
3262
3263 // build edge->triangle adjacency map
3264 for (int e = 0; e < 3; ++e)
3265 {
3266 MeshCompiler_EdgeTriMapKey edge( PosIdx[e], PosIdx[(e+1)%3] );
3267
3268 QHash< MeshCompiler_EdgeTriMapKey, std::pair<int, int> >::iterator itKey;
3269
3270 itKey = EdgeAdjMap.find(edge);
3271
3272 if (itKey == EdgeAdjMap.end())
3273 EdgeAdjMap[edge] = std::pair<int, int>(i, -1);
3274 else
3275 itKey.value().second = i;
3276 }
3277
3278 }
3279
3280 // use edge->triangle adjacency map to build index buffer with adjacency
3281 for (QHash< MeshCompiler_EdgeTriMapKey, std::pair<int, int> >::iterator it = EdgeAdjMap.begin(); it != EdgeAdjMap.end(); ++it)
3282 {
3283 // two adjacent tris of current edge
3284 int Tris[2] = {it.value().first, it.value().second};
3285
3286 // get input positions of triangles
3287 int PosIdx[6];
3288
3289 for (int k = 0; k < 3; ++k)
3290 {
3291 int faceId, cornerId;
3292
3293 PosIdx[k] = mapToOriginalVertexID(getIndex(Tris[0]*3+k), faceId, cornerId);
3294
3295 if (Tris[1] >= 0)
3296 PosIdx[3+k] = mapToOriginalVertexID(getIndex(Tris[1]*3+k), faceId, cornerId);
3297 }
3298
3299
3300 // find edge and opposite corner wrt. to adjacent tris
3301
3302 int TriEdges[2] = {-1,-1};
3303 int TriOppositeVerts[2] = {-1,-1};
3304
3305 for (int e = 0; e < 3; ++e)
3306 {
3307 MeshCompiler_EdgeTriMapKey edge0( PosIdx[e], PosIdx[(e+1)%3] );
3308
3309 if (edge0 == it.key())
3310 {
3311 TriEdges[0] = e;
3312 TriOppositeVerts[1] = (e+2)%3;
3313 }
3314 }
3315
3316 if (Tris[1] >= 0)
3317 {
3318 for (int e = 0; e < 3; ++e)
3319 {
3320 MeshCompiler_EdgeTriMapKey edge1( PosIdx[3 + e], PosIdx[3 + ((e+1)%3)] );
3321
3322 if (edge1 == it.key())
3323 {
3324 TriEdges[1] = e;
3325 TriOppositeVerts[0] = (e+2)%3;
3326 }
3327 }
3328 }
3329
3330 // store adjacency in buffer
3331
3332 for (int i = 0; i < 2; ++i)
3333 {
3334 if (Tris[i] >= 0)
3335 {
3336 int e = TriEdges[i];
3337
3338 // opposite vertex
3339 int ov = _borderIndex;
3340
3341 if (TriOppositeVerts[i] >= 0 && Tris[(i+1)%2] >= 0)
3342 ov = getIndex(Tris[(i+1)%2]*3 + TriOppositeVerts[i]);
3343
3344 idst[Tris[i] * 6 + e*2 + 1] = ov;
3345 }
3346 }
3347
3348 }
3349
3350 return;
3351
3352 /*
3353
3354 // alternative algorithm without hashing with multi threading
3355 // in case hashing method is too slow, the following unfinished implementation can be completed
3356
3357 // requires vertex-face adjacency
3358
3359 computeAdjacency();
3360
3361 #ifdef USE_OPENMP
3362 #pragma omp parallel for
3363 #endif
3364 for (int i = 0; i < numFaces_; ++i)
3365 {
3366 const int fsize = getFaceSize(i);
3367
3368 // for each edge of current face
3369 for (int e = 0; e < fsize; ++e)
3370 {
3371 int vertexId = getInputIndex(i, e, inputIDPos_);
3372
3373 MeshCompiler_EdgeTriMapKey edge( getInputIndex(i, e, inputIDPos_),
3374 getInputIndex(i, (e+1)%fsize, inputIDPos_) );
3375
3376
3377 int numAdjFaces = adjacencyVert_.getCount(vertexId);
3378
3379 // search for adjacent tri with shared edge
3380 for (int a = 0; a < numAdjFaces; ++a)
3381 {
3382 int adjFaceID = adjacencyVert_.getAdj(vertexId, a);
3383
3384 const int adjFaceSize = getFaceSize(adjFaceID);
3385
3386 // for each edge of adjacent face
3387 for (int ae = 0; ae < adjFaceSize; ++ae)
3388 {
3389 // get start/end indices of adjacent half-edge
3390 MeshCompiler_EdgeTriMapKey adjEdge( getInputIndex(adjFaceID, ae, inputIDPos_),
3391 getInputIndex(adjFaceID, (ae+1)%adjFaceSize, inputIDPos_) );
3392
3393 // check whether this is the same edge
3394 if (adjEdge == edge)
3395 {
3396 // find these half-edges in output mesh
3397
3398
3399
3400
3401 }
3402 }
3403 }
3404
3405 }
3406
3407
3408 // add adjacency for newly inserted edges (triangulation of n-polys)
3409
3410 }
3411
3412 // delete adjacency list since its no longer needed
3413 adjacencyVert_.clear();
3414
3415 */
3416 }
3417
3418 void MeshCompiler::getIndexAdjBuffer_MT(void* _dst, const int _borderIndex /* = -1 */)
3419 {
3420 // alternative algorithm without hashing, but with multi-threading support
3421
3422 // compute vertex-position -> triangle adjacency
3423 // vertex-position: unsplit position IDs of input mesh
3424 // triangles: triangles in output mesh after build()
3425
3426 const int numVerts = input_[inputIDPos_].count;
3427 AdjacencyList outputVertexTriAdj;
3428
3429 outputVertexTriAdj.init(numVerts);
3430
3431 // count # adjacent tris per vertex
3432 for (int i = 0; i < numTris_; ++i)
3433 {
3434 int faceID, cornerID;
3435
3436 for (int k = 0; k < 3; ++k)
3437 {
3438 int vertex = getIndex(i * 3 + k);
3439 int posID = mapToOriginalVertexID(vertex, faceID, cornerID);
3440
3441 outputVertexTriAdj.count[posID]++;
3442 }
3443 }
3444
3445 // count num of needed entries
3446 int nCounter = 0;
3447
3448 for (int i = 0; i < numVerts; ++i)
3449 {
3450 outputVertexTriAdj.start[i] = nCounter; // save start indices
3451
3452 nCounter += outputVertexTriAdj.count[i];
3453
3454 outputVertexTriAdj.count[i] = 0; // count gets recomputed in next step
3455 }
3456
3457 // alloc memory
3458 outputVertexTriAdj.buf = new int[nCounter];
3459 outputVertexTriAdj.bufSize = nCounter;
3460
3461 // build adjacency list
3462 for (int i = 0; i < numTris_; ++i)
3463 {
3464 int faceID, cornerID;
3465
3466 for (int k = 0; k < 3; ++k)
3467 {
3468 int vertex = getIndex(i * 3 + k);
3469 int posID = mapToOriginalVertexID(vertex, faceID, cornerID);
3470
3471 int adjIdx = outputVertexTriAdj.start[posID] + outputVertexTriAdj.count[posID]++;
3472
3473 outputVertexTriAdj.buf[ adjIdx ] = i;
3474 }
3475 }
3476
3477
3478 // assemble index buffer
3479
3480 int* idst = (int*)_dst;
3481
3482 for (int i = 0; i < numTris_; ++i)
3483 {
3484 // initialize all triangles
3485 idst[i*6] = getIndex(i*3);
3486 idst[i*6+2] = getIndex(i*3+1);
3487 idst[i*6+4] = getIndex(i*3+2);
3488
3489 idst[i*6+1] = _borderIndex;
3490 idst[i*6+3] = _borderIndex;
3491 idst[i*6+5] = _borderIndex;
3492 }
3493
3494 #ifdef USE_OPENMP
3495 #pragma omp parallel for
3496 #endif
3497 for (int vertexID = 0; vertexID < numVerts; ++vertexID)
3498 {
3499 const int numAdjTris = outputVertexTriAdj.getCount(vertexID);
3500
3501
3502 for (int adjID0 = 0; adjID0 < numAdjTris; ++adjID0)
3503 {
3504 const int triID0 = outputVertexTriAdj.getAdj(vertexID, adjID0);
3505
3506 int TriPos0[3];
3507 for (int k = 0; k < 3; ++k)
3508 {
3509 int faceid, cornerid;
3510 TriPos0[k] = mapToOriginalVertexID( getIndex(triID0*3+k), faceid, cornerid );
3511 }
3512
3513 for (int adjID1 = adjID0+1; adjID1 < numAdjTris; ++adjID1) //for (int triID1 = 0; triID1 < numTris_; ++triID1)
3514 {
3515 const int triID1 = outputVertexTriAdj.getAdj(vertexID, adjID1);
3516
3517 int TriPos1[3];
3518 for (int k = 0; k < 3; ++k)
3519 {
3520 int faceid, cornerid;
3521 TriPos1[k] = mapToOriginalVertexID( getIndex(triID1*3+k), faceid, cornerid );
3522 }
3523
3524 // find shared edge
3525 for (int e0 = 0; e0 < 3; ++e0)
3526 {
3527 MeshCompiler_EdgeTriMapKey edge0(TriPos0[e0], TriPos0[(e0+1)%3]);
3528
3529 for (int e1 = 0; e1 < 3; ++e1)
3530 {
3531 MeshCompiler_EdgeTriMapKey edge1(TriPos1[e1], TriPos1[(e1+1)%3]);
3532
3533 if (edge0 == edge1)
3534 {
3535 // found shared edge
3536
3537 int oppVertex0 = getIndex( triID1*3 + ((e1+2)%3) );
3538 int oppVertex1 = getIndex( triID0*3 + ((e0+2)%3) );
3539
3540 idst[triID0*6 + e0*2 +1] = oppVertex0;
3541 idst[triID1*6 + e1*2 + 1] = oppVertex1;
3542 }
3543 }
3544
3545 }
3546
3547 }
3548
3549 }
3550
3551 }
3552 }
3553
3554 void MeshCompiler::getIndexAdjBuffer_BruteForce( void* _dst, const int _borderIndex /*= -1*/ )
3555 {
3556 // simple, but slow algorithm for creating a reference and testing the improved implementations (getIndexAdjBuffer and getIndexAdjBuffer_MT)
3557
3558 int* idst = (int*)_dst;
3559
3560 for (int i = 0; i < numTris_; ++i)
3561 {
3562 // initialize all triangles
3563 idst[i*6] = getIndex(i*3);
3564 idst[i*6+2] = getIndex(i*3+1);
3565 idst[i*6+4] = getIndex(i*3+2);
3566
3567 idst[i*6+1] = _borderIndex;
3568 idst[i*6+3] = _borderIndex;
3569 idst[i*6+5] = _borderIndex;
3570 }
3571
3572 // build brute-force adjacency list and compare -- O(n^2)
3573 #ifdef USE_OPENMP
3574 #pragma omp parallel for
3575 #endif
3576 for (int triID0 = 0; triID0 < numTris_; ++triID0)
3577 {
3578 int TriPos0[3];
3579 for (int k = 0; k < 3; ++k)
3580 {
3581 int faceid, cornerid;
3582 TriPos0[k] = mapToOriginalVertexID( getIndex(triID0*3+k), faceid, cornerid );
3583 }
3584
3585 for (int triID1 = triID0 + 1; triID1 < numTris_; ++triID1)
3586 {
3587 int TriPos1[3];
3588 for (int k = 0; k < 3; ++k)
3589 {
3590 int faceid, cornerid;
3591 TriPos1[k] = mapToOriginalVertexID( getIndex(triID1*3+k), faceid, cornerid );
3592 }
3593
3594 // find shared edge
3595 for (int e0 = 0; e0 < 3; ++e0)
3596 {
3597 MeshCompiler_EdgeTriMapKey edge0(TriPos0[e0], TriPos0[(e0+1)%3]);
3598
3599 for (int e1 = 0; e1 < 3; ++e1)
3600 {
3601 MeshCompiler_EdgeTriMapKey edge1(TriPos1[e1], TriPos1[(e1+1)%3]);
3602
3603 if (edge0 == edge1)
3604 {
3605 // found shared edge
3606
3607 int oppVertex0 = getIndex( triID1*3 + ((e1+2)%3) );
3608 int oppVertex1 = getIndex( triID0*3 + ((e0+2)%3) );
3609
3610 idst[triID0*6 + e0*2 +1] = oppVertex0;
3611 idst[triID1*6 + e1*2 + 1] = oppVertex1;
3612 }
3613 }
3614
3615 }
3616
3617 }
3618
3619 }
3620
3621 }
3622
3623
3624 int MeshCompiler::mapToOriginalFaceID( const int _i ) const
3625 {
3626 // int faceID = _i;
3627 // if (!triOptMap_.empty())
3628 // faceID = triOptMap_[faceID];
3629 //
3630 // if (!triToSortFaceMap_.empty())
3631 // faceID = triToSortFaceMap_[faceID];
3632 //
3633 // if (!faceSortMap_.empty())
3634 // faceID = faceSortMap_[faceID];
3635 //
3636 // return faceID;
3637
3638 return triToFaceMap_[_i];
3639 }
3640
3641 const int* MeshCompiler::mapToOriginalFaceIDPtr() const
3642 {
3643 if (triToFaceMap_.empty())
3644 return 0;
3645 else
3646 return &triToFaceMap_[0];
3647 }
3648
3649
3650
3651 int MeshCompiler::mapToOriginalVertexID( const int _i, int& _faceID, int& _cornerID ) const
3652 {
3653 int positionID = -1;
3654
3655 if (_i < numDrawVerts_ - numIsolatedVerts_)
3656 {
3657 // connected vertex
3658 _faceID = vertexMapFace_[_i];
3659 _cornerID = vertexMapCorner_[_i];
3660
3661 positionID = getInputIndex(_faceID, _cornerID, inputIDPos_);
3662 }
3663 else
3664 {
3665 // isolated vertex: vertexMap stores input position id instead of face
3666 positionID = vertexMapFace_[_i];
3667
3668 _faceID = -1;
3669 _cornerID = -1;
3670 }
3671
3672 return positionID;
3673 }
3674
3675 int MeshCompiler::mapToDrawVertexID( const int _faceID, const int _cornerID ) const
3676 {
3677 return getInputIndexSplit(_faceID, _cornerID);
3678 }
3679
3680 int MeshCompiler::mapToDrawTriID( const int _faceID, const int _k /*= 0*/, int* _numTrisOut /*= 0*/ ) const
3681 {
3682 const int fsize = getFaceSize(_faceID);
3683 assert(_k < fsize - 2);
3684
3685 if (_numTrisOut)
3686 *_numTrisOut = fsize - 2;
3687
3688 int offset = constantFaceSize_ ? (_faceID * (maxFaceSize_ - 2)) : faceToTriMapOffset_[_faceID];
3689
3690 return faceToTriMap_[offset + _k];
3691 }
3692
3693 size_t MeshCompiler::getMemoryUsage(bool _printConsole) const
3694 {
3695 /*
3696 Short evaluation of memory footprint (version at 27.12.13)
3697
3698 Memory consumption was measured with xyzrgb_dragon.ply from the Stanford repository (7.2 mil tris, 3.6 mil verts).
3699 Options used for build(): welding - true, optimize - true, require per face attributes - true,
3700 Adjacency information was generated by MeshCompiler.
3701 Input data by user: 275 mb (indices, float3 positions, float3 normals)
3702
3703 Breakdown of memory footprint in build():
3704 1. 467 mb - adjacency lists ( vertex-face list 98 mb, face-face list 369 mb)
3705 2. 103 mb - vertex weld map
3706 3. 82 mb - each of: faceBufSplit_, indices_
3707 4. 51 mb - vertexMap
3708 5. 41 mb - splitter_
3709 6. 27 mb - each of: faceToTriMap_, triToFaceMap_, faceSortMap_, ... ie. any per face map
3710 7. 13 mb - faceGroupIds
3711 8. 6 mb - faceRotCount
3712
3713 Peak memory load: 563 mb after computing face-face adjacency for forceUnsharedVertex() (adjacency lists and faceBufSplit_ were allocated at that time)
3714 Final memory load: 292 mb measured after build(), mem allocations: [faceGroupIds, faceBufSplit, vertexMap, faceToTriMap, triToFaceMap, indices]
3715
3716 Update: (12.01.14)
3717 forceUnsharedVertex() has been modified and no longer requires a face-face adjacency list, which was the biggest memory buffer allocated by build()
3718 */
3719
3720
3721 size_t usage = faceStart_.size() * 4;
3722 usage += faceSize_.size() * 1;
3723 usage += faceData_.size() * 4;
3724 usage += faceGroupIDs_.size() * 2;
3725 usage += faceBufSplit_.size() * 4;
3726 usage += faceSortMap_.size() * 4;
3727
3728 usage += triIndexBuffer_.size() * 4;
3729
3730 usage += subsetIDMap_.size() * sizeof(Subset);
3731
3732 usage += vertexWeldMapFace_.size() * 5;
3733
3734 usage += adjacencyVert_.bufSize * 4; // buf
3735 usage += adjacencyVert_.num * 4; // start
3736 usage += adjacencyVert_.num * 1; // count
3737
3738
3739 if (splitter_)
3740 usage += splitter_->splits.size() * 4;
3741
3742 usage += triToSortFaceMap_.size() * 4;
3743 usage += triOptMap_.size() * 4;
3744 usage += vertexMapFace_.size() * 5;
3745 usage += faceToTriMap_.size() * 4;
3746 usage += faceToTriMapOffset_.size() * 4;
3747 usage += triToFaceMap_.size() * 4;
3748
3749 usage += indices_.size() * 4; // indices_
3750
3751
3752
3753 if (_printConsole)
3754 {
3755 const int byteToMB = 1024 * 1024;
3756
3757 std::cout << "faceStart_: " << sizeof(std::pair<int, unsigned char>) << std::endl;
3758
3759 std::cout << "faceStart_: " << faceStart_.size() * 4 / byteToMB << std::endl;
3760 std::cout << "faceSize_: " << faceSize_.size() * 1 / byteToMB << std::endl;
3761 std::cout << "faceData_: " << faceData_.size() * 4 / byteToMB << std::endl;
3762 std::cout << "faceGroupIDs_: " << faceGroupIDs_.size() * 2 / byteToMB << std::endl;
3763 std::cout << "faceBufSplit_: " << faceBufSplit_.size() * 4 / byteToMB << std::endl;
3764
3765 std::cout << "faceSortMap_: " << faceSortMap_.size() * 4 / byteToMB << std::endl;
3766
3767 std::cout << "triIndexBuffer_: " << triIndexBuffer_.size() * 4 / byteToMB << std::endl;
3768
3769 std::cout << "vertexWeldMap_: " << vertexWeldMapFace_.size() * 5 / byteToMB << std::endl;
3770
3771 std::cout << "adjacencyVert_: buf = " << adjacencyVert_.bufSize * 4 / byteToMB <<
3772 ", offset = " << adjacencyVert_.num * 4 / byteToMB <<
3773 ", count = " << adjacencyVert_.num * 1 / byteToMB << std::endl;
3774
3775 if (splitter_)
3776 std::cout << "splitter_: " << splitter_->splits.size() * 4 / byteToMB << std::endl;
3777
3778 std::cout << "triToSortFaceMap_: " << triToSortFaceMap_.size() * 4 / byteToMB << std::endl;
3779 std::cout << "triOptMap_: " << triOptMap_.size() * 4 / byteToMB << std::endl;
3780 std::cout << "vertexMap_: " << vertexMapFace_.size() * 5 / byteToMB << std::endl;
3781 std::cout << "faceToTriMapOffset_: " << faceToTriMapOffset_.size() * 4 / byteToMB << std::endl;
3782 std::cout << "faceToTriMap_: " << faceToTriMap_.size() * 4 / byteToMB << std::endl;
3783 std::cout << "triToFaceMap_: " << triToFaceMap_.size() * 4 / byteToMB << std::endl;
3784
3785
3786 std::cout << "indices_: " << 3 * numTris_ * 4 / byteToMB << std::endl;
3787
3788 }
3789
3790
3791 return usage;
3792 }
3793
3794 std::string MeshCompiler::checkInputData() const
3795 {
3796 // find common errors and give a short description on what needs to be fixed for the given input
3797
3798 if (!faceInput_)
3799 return "Error: no face input data present\n";
3800
3801 std::stringstream strm;
3802
3803 int faceV[16];
3804
3805 for (int a = 0; a < numAttributes_; ++a)
3806 {
3807 if (input_[a].count <= 0)
3808 strm << "Warning: input buffer is not initialized: buffer id " << a << "\n";
3809 }
3810
3811 for (int i = 0; i < faceInput_->getNumFaces(); ++i)
3812 {
3813 if (faceInput_->getFaceSize(i) < 3)
3814 strm << "Error: face size too small: face " << i << ", size " << faceInput_->getFaceSize(i) << " must be at least 3\n";
3815
3816 std::map<int, int> facePositions;
3817
3818 for (int k = 0; k < faceInput_->getFaceSize(i); ++k)
3819 {
3820 getInputFaceVertex(i, k, faceV);
3821
3822 for (int a = 0; a < numAttributes_; ++a)
3823 {
3824 if (input_[a].count > 0)
3825 {
3826 // index boundary check
3827 if (faceV[a] >= input_[a].count)
3828 strm << "Error: input index (face/corner/attribute: " << i << "/" << k << "/" << a << ") invalid: " << faceV[a] << " >= buffer size (" << input_[a].count << ")\n";
3829 if (faceV[a] < 0)
3830 strm << "Error: input index (face/corner/attribute: " << i << "/" << k << "/" << a << ") invalid: " << faceV[a] << "\n";
3831 }
3832 }
3833
3834 if (numAttributes_)
3835 facePositions[faceV[0]] = k;
3836 }
3837
3838 // degenerate check
3839 if ((int)facePositions.size() != faceInput_->getFaceSize(i))
3840 strm << "Warning: degenerate face " << i << "\n";
3841
3842 // empty face
3843 if (!faceInput_->getFaceSize(i))
3844 strm << "Warning: empty face " << i << "\n";
3845 }
3846
3847 return strm.str();
3848 }
3849
3850 void MeshCompiler::prepareData()
3851 {
3852 // update face count, in case not provided by user
3853 numFaces_ = faceInput_->getNumFaces();
3854 numIndices_ = faceInput_->getNumIndices();
3855
3856 // clip empty faces from the end (user estimated too many faces)
3857 for (int i = numFaces_-1; i >= 0 && !faceInput_->getFaceSize(i); --i)
3858 --numFaces_;
3859
3860 // update size of each attribute (necessary for correct handling of missing input buffers)
3861 for (unsigned int i = 0; i < decl_.getNumElements(); ++i)
3862 {
3863 int attrSize = (int)VertexDeclaration::getElementSize(decl_.getElement(i));
3864 assert(input_[i].attrSize <= 0 || input_[i].attrSize == attrSize);
3865 input_[i].attrSize = attrSize;
3866 }
3867
3868 // build internal face-offset table for storing interleaved index buffer
3869
3870 int minFaceSize = 99999999;
3871 for (int i = 0; i < numFaces_; ++i)
3872 {
3873 const int fsize = faceInput_->getFaceSize(i);
3874
3875 maxFaceSize_ = std::max((int)maxFaceSize_, fsize);
3876 minFaceSize = std::min(minFaceSize, fsize);
3877 }
3878
3879 // faces with less than 3 vertices (lines or points) shouldn't be included in the first place
3880 // these parts should be handled separately, as they don't need all the costly preprocessing of MeshCompiler
3881 if (minFaceSize < 3)
3882 std::cout << "error: input contains faces with less than 3 vertices! MeshCompiler only works for pure surface meshes!" << std::endl;
3883
3884 assert(minFaceSize >= 3);
3885
3886 if (minFaceSize < (int)maxFaceSize_)
3887 {
3888 int curOffset = 0;
3889
3890 // internal face-offset buffer required for mesh processing
3891 faceStart_.resize(numFaces_, -1);
3892 faceSize_.resize(numFaces_, 0);
3893
3894 for (int i = 0; i < numFaces_; ++i)
3895 {
3896 faceSize_[i] = (unsigned char)faceInput_->getFaceSize(i);
3897 faceStart_[i] = curOffset;
3898 curOffset += faceSize_[i];
3899 }
3900
3901 if (numIndices_ <= 0)
3902 numIndices_ = curOffset;
3903 }
3904 else
3905 {
3906 constantFaceSize_ = true;
3907 numIndices_ = maxFaceSize_ * numFaces_;
3908 }
3909
3910
3911 // reset mappings from previous builds()
3912 triOptMap_.clear();
3913 triToSortFaceMap_.clear();
3914 faceSortMap_.clear();
3915
3916 faceToTriMap_.clear();
3917 faceToTriMapOffset_.clear();
3918
3919 triToFaceMap_.clear();
3920 vertexMapFace_.clear();
3921 vertexMapCorner_.clear();
3922
3923 faceBufSplit_.clear();
3924
3925 isolatedVertices_.clear();
3926 numIsolatedVerts_ = 0;
3927
3928 if (!provokingVertexSetByUser_)
3929 provokingVertex_ = -1;
3930
3931
3932 #ifdef _DEBUG
3933 for (int i = 0; i < numFaces_; ++i)
3934 {
3935 for (int k = 0; k < getFaceSize(i); ++k)
3936 {
3937 int v0 = faceInput_->getSingleFaceAttr(i, k, inputIDPos_);
3938 int v1 = getInputIndex(i, k, inputIDPos_);
3939
3940 assert(v0 == v1);
3941 }
3942 }
3943 #endif // _DEBUG
3944 }
3945
3946 void MeshCompiler::setFaceInput( MeshCompilerFaceInput* _faceInput )
3947 {
3948 faceInput_ = _faceInput;
3949 }
3950
3951 void MeshCompiler::setIndexBufferInterleaved( int _numTris, int _indexSize, const void* _indices )
3952 {
3953 assert(_indices);
3954 assert(_indexSize);
3955
3956 setNumFaces(_numTris, _numTris * 3);
3957
3958 for (int i = 0; i < _numTris; ++i)
3959 {
3960 int tri[3] = {-1, -1, -1};
3961
3962 for (int k = 0; k < 3; ++k)
3963 {
3964 int offs = i * 3 + k;
3965
3966 switch(_indexSize)
3967 {
3968 case 1: tri[k] = ((char*)_indices)[offs]; break;
3969 case 2: tri[k] = ((short*)_indices)[offs]; break;
3970 case 4: tri[k] = ((int*)_indices)[offs]; break;
3971 case 8: tri[k] = (int)((long long*)_indices)[offs]; break;
3972 default: break;
3973 }
3974 }
3975
3976 setFaceVerts(i, 3, tri);
3977 }
3978 }
3979
3980 int MeshCompiler::getNumFaces() const
3981 {
3982 return numFaces_;
3983 }
3984
3985 void MeshCompiler::setProvokingVertex( int _v )
3986 {
3987 provokingVertex_ = _v;
3988 provokingVertexSetByUser_ = true;
3989 }
3990
3991 int MeshCompiler::getAdjVertexFaceCount( int _vertexID ) const
3992 {
3993 return adjacencyVert_.num ? adjacencyVert_.getCount(_vertexID) : faceInput_->getVertexAdjCount(_vertexID);
3994 }
3995
3996 int MeshCompiler::getAdjVertexFace( int _vertexID, int _k ) const
3997 {
3998 return adjacencyVert_.num ? adjacencyVert_.getAdj(_vertexID, _k) : faceInput_->getVertexAdjFace(_vertexID, _k);
3999 }
4000
4001 bool MeshCompiler::isTriangleMesh() const
4002 {
4003 return maxFaceSize_ == 3;
4004 }
4005
4006 bool MeshCompiler::isFaceEdge( const int _triID, const int _edge ) const
4007 {
4008 assert(_edge >= 0);
4009 assert(_edge < 3);
4010
4011 if (maxFaceSize_ <= 3) return true;
4012
4013 // brute force: search for triangle edge in input face
4014
4015 const int faceID = mapToOriginalFaceID(_triID);
4016 const int fsize = getFaceSize(faceID);
4017
4018 // get all draw vertices of face
4019 std::vector<int> FaceVerts(fsize);
4020
4021 for (int i = 0; i < fsize; ++i)
4022 FaceVerts[i] = mapToDrawVertexID(faceID, i);
4023
4024 int edgeStart = -1;
4025 int edgeEnd = -1;
4026
4027 switch (_edge)
4028 {
4029 case 0: edgeStart = 0; edgeEnd = 1; break;
4030 case 1: edgeStart = 1; edgeEnd = 2; break;
4031 case 2: edgeStart = 2; edgeEnd = 0; break;
4032 default: break;
4033 }
4034
4035 // access index buffer of triangle
4036 edgeStart = getIndex(_triID * 3 + edgeStart);
4037 edgeEnd = getIndex(_triID * 3 + edgeEnd);
4038
4039 // search for edge in face vertices
4040 for (int e = 0; e < fsize; ++e)
4041 {
4042 if (FaceVerts[e] == edgeStart && FaceVerts[(e+1)%fsize] == edgeEnd)
4043 return true;
4044 if (FaceVerts[e] == edgeEnd && FaceVerts[(e+1)%fsize] == edgeStart)
4045 return true;
4046 }
4047
4048 return false;
4049 }
4050
4051 void MeshCompilerDefaultFaceInput::dbgWriteToObjFile(FILE* _file, int _posAttrID, int _normalAttrID, int _texcAttrID)
4052 {
4053 for (int i = 0; i < numFaces_; ++i)
4054 {
4055 std::string strLine = "f ";
4056
4057 int offset = faceOffset_[i];
4058 int size = faceSize_[i];
4059
4060 char tmp[0xff];
4061 for (int k = 0; k < size; ++k)
4062 {
4063 if (_normalAttrID>=0 && _texcAttrID>=0)
4064 sprintf(tmp, "%d/%d/%d ", faceData_[_posAttrID][offset+k]+1,
4065 faceData_[_texcAttrID][offset+k]+1,
4066 faceData_[_normalAttrID][offset+k]+1);
4067 else if (_normalAttrID >= 0)
4068 sprintf(tmp, "%d//%d ", faceData_[_posAttrID][offset + k]+1, faceData_[_normalAttrID][offset+k]+1);
4069 else if (_texcAttrID >= 0)
4070 sprintf(tmp, "%d/%d ", faceData_[_posAttrID][offset + k]+1, faceData_[_texcAttrID][offset+k]+1);
4071 else
4072 sprintf(tmp, "%d ", faceData_[_posAttrID][offset + k]+1);
4073
4074 strLine += tmp;
4075 }
4076
4077 fprintf(_file, "%s\n", strLine.c_str());
4078 }
4079 }
4080
4081 bool MeshCompilerDefaultFaceInput::getFaceAttr( int _faceID, int _attrID, int* _out ) const
4082 {
4083 int offset = faceOffset_[_faceID];
4084 int fsize = faceSize_[_faceID];
4085
4086 for (int i = 0; i < fsize; ++i)
4087 _out[i] = faceData_[_attrID][offset+i];
4088
4089 return true;
4090 }
4091
4092 int MeshCompilerDefaultFaceInput::getSingleFaceAttr( const int _faceID, const int _faceCorner, const int _attrID ) const
4093 {
4094 // Offset + _faceCorner
4095 const int pos = faceOffset_[_faceID] + _faceCorner;
4096 assert(_faceCorner < getFaceSize(_faceID));
4097
4098
4099 if (faceData_[_attrID].empty() || pos >= int(faceData_[_attrID].size()))
4100 return -1;
4101
4102 return faceData_[_attrID][pos];
4103 }
4104
4105 void MeshCompilerDefaultFaceInput::setFaceData( int _faceID, int _size, int* _data, int _attrID /*= 0*/ )
4106 {
4107 // update face count
4108 if (numFaces_ <= _faceID)
4109 numFaces_ = _faceID + 1;
4110
4111 // reserve mem
4112 if (faceData_[_attrID].capacity() == 0)
4113 faceData_[_attrID].reserve(numIndices_);
4114
4115 if ((int)faceOffset_.size() <= _faceID)
4116 faceOffset_.resize(_faceID+1, -1);
4117
4118 if ((int)faceSize_.size() <= _faceID)
4119 faceSize_.resize(_faceID+1, -1);
4120
4121 faceSize_[_faceID] = _size;
4122
4123 if (faceOffset_[_faceID] < 0)
4124 {
4125 // append new face data to stream
4126 faceOffset_[_faceID] = faceData_[_attrID].size();
4127 for (int i = 0; i < _size; ++i)
4128 faceData_[_attrID].push_back(_data[i]);
4129 }
4130 else
4131 {
4132 int offs = faceOffset_[_faceID];
4133
4134 if ((int)faceData_[_attrID].size() == offs)
4135 {
4136 for (int i = 0; i < _size; ++i)
4137 faceData_[_attrID].push_back(_data[i]);
4138 }
4139 else
4140 {
4141 // resize array
4142 if ((int)faceData_[_attrID].size() < offs + _size + 1)
4143 faceData_[_attrID].resize(offs + _size + 1, -1);
4144
4145 // update existing face data
4146 for (int i = 0; i < _size; ++i)
4147 faceData_[_attrID][offs + i] = _data[i];
4148 }
4149 }
4150 }
4151
4152 int MeshCompilerFaceInput::getSingleFaceAttr( const int _faceID, const int _faceCorner, const int _attrID ) const
4153 {
4154 const int fsize = getFaceSize(_faceID);
4155
4156 assert(_faceID < getNumFaces());
4157 assert(_faceID >= 0);
4158 assert(_faceCorner >= 0);
4159 assert(_faceCorner < fsize);
4160
4161 int retVal = -1;
4162
4163 int* tmpPtr = getFaceAttr(_faceID, _attrID);
4164
4165 if (tmpPtr)
4166 retVal = tmpPtr[_faceCorner];
4167 else
4168 {
4169 tmpPtr = new int[fsize];
4170 if (getFaceAttr(_faceID, _attrID, tmpPtr))
4171 retVal = tmpPtr[_faceCorner];
4172 delete [] tmpPtr;
4173 }
4174
4175 return retVal;
4176 }
4177
4178
4179 bool MeshCompilerVertexCompare::equalVertex( const void* v0, const void* v1, const VertexDeclaration* _decl )
4180 {
4181 // compare vertex data of two vertices
4182
4183 assert(_decl);
4184 assert(v0);
4185 assert(v1);
4186
4187 const int nElements = (int)_decl->getNumElements();
4188 for (int i = 0; i < nElements; ++i)
4189 {
4190 const VertexElement* el = _decl->getElement(i);
4191
4192 // pointer to element data
4193 const void* el_0 = static_cast<const char*>(v0) + (size_t)el->pointer_;
4194 const void* el_1 = static_cast<const char*>(v1) + (size_t)el->pointer_;
4195
4196 // interpret element based on declaration
4197 switch ( el->type_ )
4198 {
4199 case GL_DOUBLE:
4200 {
4201 const double* d0 = static_cast<const double*>(el_0);
4202 const double* d1 = static_cast<const double*>(el_1);
4203
4204 double diff = 0.0;
4205
4206 for (int k = 0; k < (int)el->numElements_; ++k)
4207 diff += fabs(d0[k] - d1[k]);
4208
4209 if (diff > d_eps_)
4210 return false;
4211
4212 } break;
4213
4214
4215 case GL_FLOAT:
4216 {
4217 const float* f0 = static_cast<const float*>(el_0);
4218 const float* f1 = static_cast<const float*>(el_1);
4219
4220 float diff = 0.0;
4221
4222 for (int k = 0; k < (int)el->numElements_; ++k)
4223 {
4224 // sign-bit manipulation vs. fabsf - no significant performance difference
4225 // float e = f0[k] - f1[k];
4226 // int e_abs = *((int*)(&e)) & 0x7FFFFFFF;
4227 // diff += *((float*)&e_abs);
4228
4229 diff += fabsf(f0[k] - f1[k]);
4230 }
4231
4232 if (diff > f_eps_)
4233 return false;
4234 } break;
4235
4236 case GL_INT:
4237 case GL_UNSIGNED_INT:
4238 {
4239 const int* i0 = static_cast<const int*>(el_0);
4240 const int* i1 = static_cast<const int*>(el_1);
4241
4242 for (int k = 0; k < (int)el->numElements_; ++k)
4243 {
4244 if (i0[k] != i1[k])
4245 return false;
4246 }
4247 } break;
4248
4249 case GL_SHORT:
4250 case GL_UNSIGNED_SHORT:
4251 {
4252 const short* i0 = static_cast<const short*>(el_0);
4253 const short* i1 = static_cast<const short*>(el_1);
4254
4255 for (int k = 0; k < (int)el->numElements_; ++k)
4256 {
4257 if (i0[k] != i1[k])
4258 return false;
4259 }
4260 } break;
4261
4262 case GL_BYTE:
4263 case GL_UNSIGNED_BYTE:
4264 {
4265 const char* i0 = static_cast<const char*>(el_0);
4266 const char* i1 = static_cast<const char*>(el_1);
4267
4268 for (int k = 0; k < (int)el->numElements_; ++k)
4269 {
4270 if (i0[k] != i1[k])
4271 return false;
4272 }
4273 } break;
4274
4275 default: std::cerr << "MeshCompiler: equalVertex() comparision not implemented for type: " << el->type_ << std::endl;
4276 }
4277 }
4278
4279 return true;
4280 }
4281
4282
4283
4284
4285 }
ACG::MeshCompiler::getIndexAdjBuffer
void getIndexAdjBuffer(void *_dst, const int _borderIndex=-1)
Get index buffer with adjacency information ready for rendering.
Definition: MeshCompiler.cc:3233
ACG::MeshCompiler::VertexElementInput::attrSize
int attrSize
size in bytes of one attribute
Definition: MeshCompiler.hh:768
ACG::MeshCompiler::build
void build(bool _weldVertices=false, bool _optimizeVCache=true, bool _needPerFaceAttribute=false, bool _keepIsolatedVertices=false)
Build vertex + index buffer.
Definition: MeshCompiler.cc:1663
ACG::MeshCompiler::getNumVertices
int getNumVertices() const
Definition: MeshCompiler.hh:518
ACG::MeshCompiler::faceToTriMap_
std::vector< int > faceToTriMap_
input face index -> output tri index
Definition: MeshCompiler.hh:963
ACG::MeshCompiler::getFaceGroup
int getFaceGroup(int _faceID) const
Get Face Group of the given face.
Definition: MeshCompiler.cc:1898
ACG
Namespace providing different geometric functions concerning angles.
Definition: DBSCANT.cc:51
ACG::MeshCompiler::setNormals
void setNormals(int _num, const void *_data, int _stride=0, bool _internalCopy=false, GLuint _fmt=0, int _elementSize=-1)
Definition: MeshCompiler.cc:264
ACG::MeshCompiler::getNumSubsets
int getNumSubsets() const
Get the number of subsets.
Definition: MeshCompiler.hh:489
ACG::MeshCompiler::dbgdumpObj
void dbgdumpObj(const char *_filename) const
dump mesh in wavefront obj format
Definition: MeshCompiler.cc:2530
ACG::VERTEX_USAGE_NORMAL
"inNormal"
Definition: VertexDeclaration.hh:72
ACG::MeshCompiler::setAttrib
void setAttrib(int _attrIdx, int _v, const void *_data)
Definition: MeshCompiler.cc:1858
ACG::MeshCompiler::isTriangleMesh
bool isTriangleMesh() const
Definition: MeshCompiler.cc:4001
ACG::MeshCompiler::setTexCoords
void setTexCoords(int _num, const void *_data, int _stride=0, bool _internalCopy=false, GLuint _fmt=0, int _elementSize=-1)
Definition: MeshCompiler.cc:269
ACG::MeshCompiler::VertexElementInput::stride
int stride
offset in bytes from one element to the next
Definition: MeshCompiler.hh:765
ACG::MeshCompiler::numIsolatedVerts_
int numIsolatedVerts_
isolated vertices
Definition: MeshCompiler.hh:977
ACG::MeshCompiler::setFaceNormals
void setFaceNormals(int _i, int _v0, int _v1, int _v2)
Set normal ids per triangle.
Definition: MeshCompiler.cc:2952
ACG::VERTEX_USAGE_TEXCOORD
"inTexCoord"
Definition: VertexDeclaration.hh:73
ACG::MeshCompiler::findGroupSubset
int findGroupSubset(int _groupID)
get subset ID of a group
Definition: MeshCompiler.cc:1906
ACG::MeshCompiler::setIndexBufferInterleaved
void setIndexBufferInterleaved(int _numTris, int _indexSize, const void *_indices)
Set index buffer for a triangle mesh.
Definition: MeshCompiler.cc:3951
ACG::MeshCompilerVertexCompare
Definition: MeshCompiler.hh:235
ACG::MeshCompiler::setFaceAttrib
void setFaceAttrib(int _i, int _v0, int _v1, int _v2, int _attrID)
Set attribute ids per triangle.
Definition: MeshCompiler.cc:1195
ACG::MeshCompiler::getNumFaces
int getNumFaces() const
Definition: MeshCompiler.cc:3980
ACG::MeshCompiler::getInputFaceVertexData
void getInputFaceVertexData(const int _face, const int _corner, void *_out) const
Definition: MeshCompiler.cc:1056
ACG::MeshCompiler::dbgdumpAdjList
void dbgdumpAdjList(const char *_filename) const
dump adjacency list to text file
Definition: MeshCompiler.cc:3132
ACG::MeshCompiler::vertexMapFace_
std::vector< int > vertexMapFace_
vertex index in vbo -> input (face id, corner id) pair , also inverse of faceBufSplit_ ...
Definition: MeshCompiler.hh:959
ACG::MeshCompilerDefaultFaceInput::getSingleFaceAttr
int getSingleFaceAttr(const int _faceID, const int _faceCorner, const int _attrID) const
Definition: MeshCompiler.cc:4092
ACG::MeshCompilerDefaultFaceInput
Definition: MeshCompiler.hh:199
ACG::MeshCompiler::VertexSplitter::isIsolated
bool isIsolated(const int vertexPosID)
check if vertex is isolated with a complete splitting list
Definition: MeshCompiler.cc:1339
ACG::VertexDeclaration::getElement
const VertexElement * getElement(unsigned int i) const
Definition: VertexDeclaration.cc:504
ACG::MeshCompiler::checkInputData
std::string checkInputData() const
check for errors in input data
Definition: MeshCompiler.cc:3794
ACG::MeshCompiler::setFaceInput
void setFaceInput(MeshCompilerFaceInput *_faceInput)
Definition: MeshCompiler.cc:3946
ACG::MeshCompiler::setFaceVerts
void setFaceVerts(int _i, int _v0, int _v1, int _v2)
Set vertex ids per triangle.
Definition: MeshCompiler.cc:2941
ACG::GPUCacheOptimizer::OptimizeVertices
static void OptimizeVertices(unsigned int NumTris, unsigned int NumVerts, unsigned int IndexSize, const void *pIndices, unsigned int *pVertMap)
Reorders vertex buffer to minimize memory address jumps.
Definition: GPUCacheOptimizer.cc:189
ACG::MeshCompiler::setFaceGroup
void setFaceGroup(int _i, short _groupID)
Specify face groups.
Definition: MeshCompiler.cc:3163
ACG::MeshCompiler::VertexElementInput
Definition: MeshCompiler.hh:748
ACG::MeshCompiler::VertexElementInput::internalBuf
char * internalBuf
mem alloc if attribute buffer managed by this class
Definition: MeshCompiler.hh:754
ACG::MeshCompiler::dbgdumpInputObj
void dbgdumpInputObj(const char *_filename) const
dump input mesh to wavefront obj format
Definition: MeshCompiler.cc:2583
ACG::VertexElement
Description of one vertex element.
Definition: VertexDeclaration.hh:84
ACG::MeshCompiler::getInputFaceVertex_Welded
void getInputFaceVertex_Welded(const int _face, const int _corner, int *_out) const
Definition: MeshCompiler.cc:1038
ACG::MeshCompiler::getVertexBuffer
void getVertexBuffer(void *_dst, const int _offset=0, const int _range=-1)
Get vertex buffer ready for rendering.
Definition: MeshCompiler.cc:3171
ACG::VertexDeclaration::getVertexStride
unsigned int getVertexStride(unsigned int i=0) const
Definition: VertexDeclaration.cc:530
ACG::MeshCompiler::setAttribVec
void setAttribVec(int _attrIdx, int _num, const void *_data, int _stride=0, bool _internalCopy=false, GLuint _fmt=0, int _elementSize=-1)
Definition: MeshCompiler.cc:275
ACG::MeshCompiler::mapToOriginalFaceIDPtr
const int * mapToOriginalFaceIDPtr() const
Definition: MeshCompiler.cc:3641
ACG::MeshCompiler::numDrawVerts_
int numDrawVerts_
vertices in vbo
Definition: MeshCompiler.hh:974
ACG::VertexDeclaration::getElementSize
static unsigned int getElementSize(const VertexElement *_pElement)
Definition: VertexDeclaration.cc:344
ACG::MeshCompiler::VertexSplitter::splits
std::vector< int > splits
Definition: MeshCompiler.hh:932
ACG::MeshCompiler::VertexElementInput::data
const char * data
Definition: MeshCompiler.hh:759
ACG::MeshCompiler::getMemoryUsage
size_t getMemoryUsage(bool _printConsole=true) const
Definition: MeshCompiler.cc:3693
ACG::MeshCompilerFaceInput::getVertexAdjFace
virtual int getVertexAdjFace(const int _vertexID, const int _k) const
Definition: MeshCompiler.hh:195
ACG::MeshCompiler::getIndexAdjBuffer_MT
void getIndexAdjBuffer_MT(void *_dst, const int _borderIndex=-1)
Multi-threaded version of getIndexAdjBuffer.
Definition: MeshCompiler.cc:3418
ACG::VertexDeclaration::getNumElements
unsigned int getNumElements() const
Definition: VertexDeclaration.cc:304
ACG::MeshCompiler::indices_
std::vector< int > indices_
index buffer
Definition: MeshCompiler.hh:980
ACG::MeshCompilerFaceInput::getFaceSize
virtual int getFaceSize(const int _faceID) const =0
ACG::MeshCompiler::getInputFaceVertex
void getInputFaceVertex(const int _face, const int _corner, int *_out) const
Definition: MeshCompiler.cc:1032
ACG::MeshCompiler::setVertices
void setVertices(int _num, const void *_data, int _stride=0, bool _internalCopy=false, GLuint _fmt=0, int _elementSize=-1)
Definition: MeshCompiler.cc:259
ACG::MeshCompiler::VertexElementInput::count
int count
elements in buffer
Definition: MeshCompiler.hh:762
ACG::MeshCompiler::vertexToString
std::string vertexToString(const void *v) const
interpret vertex data according declaration and write to string
Definition: MeshCompiler.cc:1916
ACG::MeshCompiler::mapToOriginalVertexID
int mapToOriginalVertexID(const int _i, int &_faceID, int &_cornerID) const
Definition: MeshCompiler.cc:3651
ACG::MeshCompiler::AdjacencyList
Definition: MeshCompiler.hh:829
ACG::MeshCompiler::Subset
Definition: MeshCompiler.hh:454
ACG::MeshCompiler::VertexElementInput::getElementData
void getElementData(int _idx, void *_dst, const VertexElement *_desc) const
read a vertex element
Definition: MeshCompiler.cc:2426
ACG::VERTEX_USAGE_POSITION
"inPosition"
Definition: VertexDeclaration.hh:71
ACG::MeshCompiler::VertexSplitter::split
int split(int *vertex)
returns a unique index for a vertex-attribute combination
Definition: MeshCompiler.cc:1228
ACG::MeshCompiler::getSubset
const Subset * getSubset(int _i) const
get a specific subset
Definition: MeshCompiler.cc:1911
ACG::MeshCompilerFaceInput
Definition: MeshCompiler.hh:134
ACG::MeshCompiler::dbgVerify
bool dbgVerify(const char *_filename) const
test correctness of input <-> output id mappings, unshared per face vertex.. logs errors in file ...
Definition: MeshCompiler.cc:1985
ACG::MeshCompilerFaceInput::getNumIndices
virtual int getNumIndices() const =0
ACG::MeshCompiler::mapToOriginalFaceID
int mapToOriginalFaceID(const int _triID) const
Definition: MeshCompiler.cc:3624
ACG::VertexDeclaration
Class to define the vertex input layout.
Definition: VertexDeclaration.hh:266
ACG::MeshCompiler::VertexSplitter::numVerts
int numVerts
number of vertex combinations currently in use
Definition: MeshCompiler.hh:915
ACG::MeshCompiler::isFaceEdge
bool isFaceEdge(const int _triID, const int _edge) const
Definition: MeshCompiler.cc:4006
ACG::VertexElement::type_
unsigned int type_
GL_FLOAT, GL_UNSIGNED_BYTE, GL_INT, ...
Definition: VertexDeclaration.hh:88
ACG::MeshCompiler::triToSortFaceMap_
std::vector< int > triToSortFaceMap_
maps from triangle ID to sorted face ID
Definition: MeshCompiler.hh:952
ACG::MeshCompiler::mapToDrawTriID
int mapToDrawTriID(const int _faceID, const int _k=0, int *_numTrisOut=0) const
Definition: MeshCompiler.cc:3680
ACG::VertexElement::numElements_
unsigned int numElements_
how many elements of type_
Definition: VertexDeclaration.hh:89
ACG::MeshCompiler::mapToDrawVertexID
int mapToDrawVertexID(const int _faceID, const int _cornerID) const
Definition: MeshCompiler.cc:3675
ACG::MeshCompiler::triToFaceMap_
std::vector< int > triToFaceMap_
output tri index -> input face index
Definition: MeshCompiler.hh:967
ACG::MeshCompiler::triOptMap_
std::vector< int > triOptMap_
maps from optimized tri ID to unoptimized tri ID
Definition: MeshCompiler.hh:955
ACG::MeshCompiler::getFaceSize
int getFaceSize(const int _i) const
Get size of input face.
Definition: MeshCompiler.hh:604
ACG::MeshCompiler::dbgdumpInputBin
void dbgdumpInputBin(const char *_filename, bool _seperateFiles=false) const
dump input mesh to binary file format
Definition: MeshCompiler.cc:2670
ACG::VertexElement::usage_
VERTEX_USAGE usage_
position, normal, shader input ..
Definition: VertexDeclaration.hh:90
ACG::VertexElement::shaderInputName_
const char * shaderInputName_
set shader input name, if usage_ = VERTEX_USAGE_USER_DEFINED otherwise this is set automatically...
Definition: VertexDeclaration.hh:91
ACG::MeshCompiler::prepareData
void prepareData()
build() preparation
Definition: MeshCompiler.cc:3850
ACG::MeshCompiler::setProvokingVertex
void setProvokingVertex(int _v)
Definition: MeshCompiler.cc:3985
ACG::MeshCompiler::setFaceTexCoords
void setFaceTexCoords(int _i, int _v0, int _v1, int _v2)
Set texcoord ids per triangle.
Definition: MeshCompiler.cc:2964
ACG::VertexElement::pointer_
const void * pointer_
Offset in bytes to the first occurrence of this element in vertex buffer; Or address to vertex data i...
Definition: VertexDeclaration.hh:92
ACG::MeshCompilerFaceInput::getSingleFaceAttr
virtual int getSingleFaceAttr(const int _faceID, const int _faceCorner, const int _attrID) const
Definition: MeshCompiler.cc:4152
ACG::MeshCompiler::setNumFaces
void setNumFaces(const int _numFaces, const int _numIndices)
Set number of faces and indices if known by user.
Definition: MeshCompiler.cc:1166
ACG::MeshCompilerFaceInput::getVertexAdjCount
virtual int getVertexAdjCount(const int _vertexID) const
Definition: MeshCompiler.hh:188
ACG::MeshCompiler::getIndexAdjBuffer_BruteForce
void getIndexAdjBuffer_BruteForce(void *_dst, const int _borderIndex=-1)
Slow brute-force version of getIndexAdjBuffer.
Definition: MeshCompiler.cc:3554
ACG::MeshCompiler::getNumInputAttributes
int getNumInputAttributes(int _attrIdx) const
Definition: MeshCompiler.cc:1873
ACG::MeshCompilerDefaultFaceInput::getFaceAttr
bool getFaceAttr(const int _faceID, const int _attrID, int *_out) const
Definition: MeshCompiler.cc:4081
ACG::MeshCompiler_EdgeTriMapKey
Definition: MeshCompiler.cc:3190
ACG::MeshCompiler::getIndex
int getIndex(int _i) const
Definition: MeshCompiler.cc:2999
ACG::MeshCompiler::getVertex
void getVertex(int _id, void *_out) const
Definition: MeshCompiler.cc:2970
ACG::MeshCompiler::dbgdump
void dbgdump(const char *_filename) const
dump mesh info to text file
Definition: MeshCompiler.cc:2308