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