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 
62 namespace ACG{
63 
64 /*
65 use case
66 
67 
68 mesh with float3 pos, float2 uv, float3 n:
69 
70 VertexElement elements[] = {{..}, ..};
71 VertexDeclaration decl;
72 
73 decl.addElement(..float3 position..)
74 decl.addElement(..float2 uv..)
75 decl.addElement(..float3 normal..)
76 
77 MeshCompiler mesh(decl);
78 
79 mesh.setVertices(..)
80 mesh.setNormals(..)
81 mesh.setTexCoords(..)
82 
83 
84 mesh.setNumFaces(333);
85 mesh.setTriangles(indexBuffer);
86 for each face i
87  mesh.setFaceMaterial(i, matID)
88 
89 mesh.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 
106 MeshCompilerVertexCompare MeshCompiler::defaultVertexCompare;
107 
108 void 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 
127 int 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 
138 int MeshCompiler::AdjacencyList::getCount( const int i ) const
139 {
140  return count[i];
141 }
142 
143 void 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 
154 void 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 
253 void 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 
258 void 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 
263 void 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 
269 void 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 
327 void 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 
376 void 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 
558 void 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 
578 void MeshCompiler::findIsolatedVertices()
579 {
580  const int nVerts = input_[inputIDPos_].count;
581 
582  numIsolatedVerts_ = 0;
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 
601 void 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 
783 bool MeshCompiler_forceUnsharedFaceVertex_InnerValenceSorter( const std::pair<int, int>& a, const std::pair<int, int>& b )
784 {
785  return a.second > b.second;
786 }
787 
788 void 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 
1068 void 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 
1074 void 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 
1092 void 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 
1107 MeshCompiler::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;
1122  numIsolatedVerts_ = 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 
1152 MeshCompiler::~MeshCompiler()
1153 {
1154  if (deleteFaceInputeData_)
1155  delete faceInput_;
1156 
1157  delete splitter_;
1158 }
1159 
1160 
1161 int 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 
1172 void 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 
1183 int 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 
1193 MeshCompilerDefaultFaceInput::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 
1202 void 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 
1217 void 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 
1231 void 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 
1239 MeshCompiler::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 
1259 MeshCompiler::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 
1322 int 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 
1338 void 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 
1354 int* 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 
1370 void MeshCompiler::VertexSplitter::setAttribs( const int id, int* attr )
1371 {
1372  memcpy(getAttribs(id), attr, numAttribs * sizeof(int));
1373 }
1374 
1375 bool MeshCompiler::VertexSplitter::isIsolated( const int vertexPosID )
1376 {
1377  return (vertexPosID < numBaseVerts) && (getNext(vertexPosID) < 0);
1378 }
1379 
1380 
1381 
1382 MeshCompiler::VertexElementInput::VertexElementInput()
1383 : internalBuf(0), data(0),
1384  count(0), stride(0), attrSize(0),
1385  fmt(0), elementSize(-1)
1386 {
1387 }
1388 
1389 MeshCompiler::VertexElementInput::~VertexElementInput()
1390 {
1391  delete [] internalBuf;
1392 }
1393 
1394 
1395 
1396 
1397 
1398 
1399 
1400 
1401 void 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 
1531 void 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 
1571 void 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 
1642 void 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 
1699 void 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 
1894 void 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 
1909 int MeshCompiler::getNumInputAttributes( int _attrIdx ) const
1910 {
1911  assert (_attrIdx >= 0);
1912  assert(_attrIdx < int(decl_.getNumElements()));
1913 
1914  return input_[_attrIdx].count;
1915 }
1916 
1917 
1918 int 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 
1934 int 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 
1952 std::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 
2021 bool 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 
2344 void 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 
2450 void 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 
2462 void 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 
2566 void 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 
2619 void 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 
2706 void 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 
2972 void MeshCompiler::setFaceVerts( int _i, int _numEdges, int* _v )
2973 {
2974  setFaceAttrib(_i, _numEdges, _v, inputIDPos_);
2975 }
2976 
2977 void 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 
2983 void MeshCompiler::setFaceNormals( int _i, int _numEdges, int* _v )
2984 {
2985  setFaceAttrib(_i, _numEdges, _v, inputIDNorm_);
2986 }
2987 
2988 void 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 
2995 void MeshCompiler::setFaceTexCoords( int _i, int _numEdges, int* _v )
2996 {
2997  setFaceAttrib(_i, _numEdges, _v, inputIDTexC_);
2998 }
2999 
3000 void 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 
3006 void 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 
3035 int MeshCompiler::getIndex( int _i ) const
3036 {
3037  assert(_i >= 0);
3038  assert(_i < numTris_ * 3);
3039  return indices_[_i];
3040 }
3041 
3042 void 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)
3050  numDrawVerts_ += numIsolatedVerts_; // keep
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 
3097 void 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 
3168 void 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 
3199 void 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 
3207 void 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
3254 struct 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
3262 uint 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 
3269 void 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 
3454 void 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 
3590 void 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 
3660 int 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 
3687 int MeshCompiler::mapToOriginalVertexID( const size_t _i, int& _faceID, int& _cornerID ) const
3688 {
3689  int positionID = -1;
3690 
3691  if (_i < numDrawVerts_ - numIsolatedVerts_)
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 
3711 int MeshCompiler::mapToDrawVertexID( const int _faceID, const int _cornerID ) const
3712 {
3713  return getInputIndexSplit(_faceID, _cornerID);
3714 }
3715 
3716 int 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 
3729 size_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 
3830 std::string MeshCompiler::checkInputData() const
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();
3962  numIsolatedVerts_ = 0;
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 
3987 void 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 
4027 int MeshCompiler::getAdjVertexFaceCount( int _vertexID ) const
4028 {
4029  return adjacencyVert_.num ? adjacencyVert_.getCount(_vertexID) : faceInput_->getVertexAdjCount(_vertexID);
4030 }
4031 
4032 int 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 
4042 bool 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 
4087 void 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 
4117 bool 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 
4128 int 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 
4141 void 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 
4188 int 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 
4215 bool 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 }
int split(int *vertex)
returns a unique index for a vertex-attribute combination
const unsigned int * GetTriangleMap() const
Retrieves the map from dst triangle to src triangle. how to remap: for each triangle t in DstTriBuffe...
Namespace providing different geometric functions concerning angles.
void setAttribVec(int _attrIdx, size_t _num, const void *_data, size_t _stride=0, bool _internalCopy=false, GLuint _fmt=0, int _elementSize=-1)
Class to define the vertex input layout.
const Subset * getSubset(int _i) const
get a specific subset
void dbgdumpAdjList(const char *_filename) const
dump adjacency list to text file
void dbgdumpInputObj(const char *_filename) const
dump input mesh to wavefront obj format
int getFaceGroup(int _faceID) const
Get Face Group of the given face.
void setFaceGroup(int _i, short _groupID)
Specify face groups.
void prepareData()
build() preparation
bool dbgVerify(const char *_filename) const
test correctness of input <-> output id mappings, unshared per face vertex.. logs errors in file ...
int getSingleFaceAttr(const int _faceID, const int _faceCorner, const int _attrID) const
void setFaceAttrib(int _i, int _v0, int _v1, int _v2, int _attrID)
Set attribute ids per triangle.
void dbgdumpObj(const char *_filename) const
dump mesh in wavefront obj format
void setFaceInput(MeshCompilerFaceInput *_faceInput)
void dbgdump(const char *_filename) const
dump mesh info to text file
std::vector< int > vertexMapFace_
vertex index in vbo -> input (face id, corner id) pair , also inverse of faceBufSplit_ ...
int attrSize
size in bytes of one attribute
bool getFaceAttr(const int _faceID, const int _attrID, int *_out) const
int getNumVertices() const
std::string vertexToString(const void *v) const
interpret vertex data according declaration and write to string
unsigned int getNumElements() const
unsigned int divisor_
For instanced rendering: Step rate describing how many instances are drawn before advancing to the ne...
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.
int mapToOriginalVertexID(const size_t _i, int &_faceID, int &_cornerID) const
void WriteIndexBuffer(unsigned int DstIndexSize, void *pDst)
Applies the remapping on the initial pIndices constructor&#39;s param and stores the result in the given ...
int mapToOriginalFaceID(const int _triID) const
void setTexCoords(size_t _num, const void *_data, size_t _stride=0, bool _internalCopy=false, GLuint _fmt=0, int _elementSize=-1)
int index(int _i) const
Get local vertex index.
Definition: Triangulator.hh:81
std::vector< int > triOptMap_
maps from optimized tri ID to unoptimized tri ID
int mapToDrawVertexID(const int _faceID, const int _cornerID) const
virtual int getSingleFaceAttr(const int _faceID, const int _faceCorner, const int _attrID) const
void setNormals(size_t _num, const void *_data, size_t _stride=0, bool _internalCopy=false, GLuint _fmt=0, int _elementSize=-1)
void setVertices(size_t _num, const void *_data, size_t _stride=0, bool _internalCopy=false, GLuint _fmt=0, int _elementSize=-1)
void setAttrib(int _attrIdx, int _v, const void *_data)
void getVertexBuffer(void *_dst, const int _offset=0, const int _range=-1)
Get vertex buffer ready for rendering.
void setNumFaces(const int _numFaces, const int _numIndices)
Set number of faces and indices if known by user.
std::string checkInputData() const
check for errors in input data
bool convex() const
Is the polygon convex?
Definition: Triangulator.hh:93
std::vector< int > triToFaceMap_
output tri index -> input face index
VERTEX_USAGE usage_
position, normal, shader input ..
void getVertex(int _id, void *_out) const
void build(bool _weldVertices=false, bool _optimizeVCache=true, bool _needPerFaceAttribute=false, bool _keepIsolatedVertices=false)
Build vertex + index buffer.
void setFaceNormals(int _i, int _v0, int _v1, int _v2)
Set normal ids per triangle.
const char * shaderInputName_
set shader input name, if usage_ = VERTEX_USAGE_USER_DEFINED otherwise this is set automatically...
void setIndexBufferInterleaved(int _numTris, int _indexSize, const void *_indices)
Set index buffer for a triangle mesh.
size_t getMemoryUsage(bool _printConsole=true) const
Description of one vertex element.
int getIndex(int _i) const
int findGroupSubset(int _groupID)
get subset ID of a group
void dbgdumpInputBin(const char *_filename, bool _seperateFiles=false) const
dump input mesh to binary file format
std::vector< int > indices_
index buffer
bool isFaceEdge(const int _triID, const int _edge) const
int stride
offset in bytes from one element to the next
std::vector< int > triToSortFaceMap_
maps from triangle ID to sorted face ID
void setProvokingVertex(int _v)
void getInputFaceVertex_Welded(const int _face, const int _corner, int *_out) const
static size_t getElementSize(const VertexElement *_pElement)
void getIndexAdjBuffer_BruteForce(void *_dst, const int _borderIndex=-1)
Slow brute-force version of getIndexAdjBuffer.
int mapToDrawTriID(const int _faceID, const int _k=0, int *_numTrisOut=0) const
bool isIsolated(const int vertexPosID)
check if vertex is isolated with a complete splitting list
int getFaceSize(const int _i) const
Get size of input face.
const int * mapToOriginalFaceIDPtr() const
void setFaceTexCoords(int _i, int _v0, int _v1, int _v2)
Set texcoord ids per triangle.
int getNumInputAttributes(int _attrIdx) const
int getNumSubsets() const
Get the number of subsets.
void getIndexAdjBuffer_MT(void *_dst, const int _borderIndex=-1)
Multi-threaded version of getIndexAdjBuffer.
size_t numIsolatedVerts_
isolated vertices
const void * pointer_
Offset in bytes to the first occurrence of this element in vertex buffer; Or address to vertex data i...
unsigned int vbo_
Explicit vbo source of this element, set to 0 if the buffer bound at the time of activating the decla...
unsigned int numElements_
how many elements of type_
char * internalBuf
mem alloc if attribute buffer managed by this class
void getInputFaceVertexData(const int _face, const int _corner, void *_out) const
void getIndexAdjBuffer(void *_dst, const int _borderIndex=-1)
Get index buffer with adjacency information ready for rendering.
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 getElementData(int _idx, void *_dst, const VertexElement *_desc) const
read a vertex element
size_t numTriangles() const
Get number of triangles.
Definition: Triangulator.hh:74
const VertexElement * getElement(unsigned int i) const
size_t numDrawVerts_
vertices in vbo
bool isTriangleMesh() const
void getInputFaceVertex(const int _face, const int _corner, int *_out) const
int getNumFaces() const
unsigned int type_
GL_FLOAT, GL_UNSIGNED_BYTE, GL_INT, ...