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