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