Developer Documentation
MeshCompiler.hh
1 /*===========================================================================*\
2  * *
3  * OpenFlipper *
4  * Copyright (c) 2001-2015, RWTH-Aachen University *
5  * Department of Computer Graphics and Multimedia *
6  * All rights reserved. *
7  * www.openflipper.org *
8  * *
9  *---------------------------------------------------------------------------*
10  * This file is part of OpenFlipper. *
11  *---------------------------------------------------------------------------*
12  * *
13  * Redistribution and use in source and binary forms, with or without *
14  * modification, are permitted provided that the following conditions *
15  * are met: *
16  * *
17  * 1. Redistributions of source code must retain the above copyright notice, *
18  * this list of conditions and the following disclaimer. *
19  * *
20  * 2. Redistributions in binary form must reproduce the above copyright *
21  * notice, this list of conditions and the following disclaimer in the *
22  * documentation and/or other materials provided with the distribution. *
23  * *
24  * 3. Neither the name of the copyright holder nor the names of its *
25  * contributors may be used to endorse or promote products derived from *
26  * this software without specific prior written permission. *
27  * *
28  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
29  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
30  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
31  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
32  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
33  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
34  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
35  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
36  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
37  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
38  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
39  * *
40 \*===========================================================================*/
41 
42 
43 
44 
45 #pragma once
46 
47 #include "VertexDeclaration.hh"
48 
49 #include <map>
50 #include <vector>
51 #include <cstdio>
52 #include <string>
53 #include <fstream>
54 
55 #include <ACG/GL/gl.hh>
56 
57 /*
58 
59 Mesh buffer assembler:
60 
61 Builds a pair of vertex and index buffer based on a poly mesh.
62 
63 
64 - flexible processing pipeline
65 - uses index mapping only -> lower memory consumption
66 - independent of OpenMesh, OpenGL
67 -
68 
69 
70 
71 usage
72 
73 1. Create a vertex declaration to specify your wanted
74  vertex format, such as float3 pos, float3 normal..
75 
76 2. Set your vertex data.
77  Example in (float3 pos, float3 normal, float2 texc) format:
78 
79  float VertexPositions[100*3] = {..};
80  float VertexNormals[120*3] = {..};
81  float VertexUV[80*2] = {..};
82 
83  drawMesh->setVertices(100, VertexPositions, 12);
84  drawMesh->setNormals(120, VertexNormals, 12);
85  drawMesh->setTexCoords(80, VertexUV, 8);
86 
87  Note that different indices for vertices, normals and texcoords are allowed,
88  hence the various element numbers 100, 120 and 80.
89 
90 
91  Example 2 (interleaved input)
92 
93  float Vertices[100] = {
94  x0, y0, z0, u0, v0, nx0, ny0, nz0,
95  x1, y1, z1, u1, v1, nx1, ny1, nz1,
96  ...
97  };
98 
99  The stride is 8*4 = 32 bytes.
100  We use parameters as follows.
101 
102  drawMesh->setVertices(100, Vertices, 32);
103  drawMesh->setNormals(100, (char*)Vertices + 20, 32);
104  drawMesh->setTexCoords(100, (char*)Vertices + 12, 32);
105 
106 3. Set index data.
107 
108  Two methods are supported for this.
109 
110  You can either specify one index set for all vertex attributes
111  or use another index buffer for each vertex attribute.
112  The latter means having different indices for vertex and texcoords for example.
113 
114 
115  drawMesh->setNumFaces(32, 96);
116 
117 
118  for each face i
119  int* faceVertexIndices = {v0, v1, v2, ...};
120  setFaceVerts(i, 3, faceVertexIndices);
121 
122 4. finish the initialization by calling the build() function
123 
124 */
125 
126 namespace ACG{
127 
128 class ACGDLLEXPORT MeshCompilerFaceInput
129 {
130  // face data input interface
131  // allows flexible and memory efficient face data input
132 
133 public:
135  virtual ~MeshCompilerFaceInput(){}
136 
137  virtual int getNumFaces() const = 0;
138 
143  virtual int getNumIndices() const = 0;
144 
148  virtual int getFaceSize(const int _faceID) const = 0;
149 
157  virtual int getSingleFaceAttr(const int _faceID, const int _faceCorner, const int _attrID) const;
158 
165  virtual bool getFaceAttr(const int _faceID, const int _attrID, int* _out) const {return false;}
166 
172  virtual int* getFaceAttr(const int _faceID, const int _attrID) const {return 0;}
173 
174 
175  // Adjacency information can be provided if it has been generated already.
176  // Otherwise it will be generated on the fly when needed, which might be time consuming.
177 
182  virtual int getVertexAdjCount(const int _vertexID) const {return -1;}
183 
189  virtual int getVertexAdjFace(const int _vertexID, const int _k) const {return -1;}
190 
191 };
192 
194 {
195 public:
196  MeshCompilerDefaultFaceInput(int _numFaces, int _numIndices);
197  virtual ~MeshCompilerDefaultFaceInput(){}
198 
199  int getNumFaces() const {return numFaces_;}
200  int getNumIndices() const {return numIndices_;}
201 
202  int getFaceSize(const int _faceID) const {return faceSize_[_faceID];}
203 
204  int getSingleFaceAttr(const int _faceID, const int _faceCorner, const int _attrID) const;
205 
206  bool getFaceAttr(const int _faceID, const int _attrID, int* _out) const;
207 
208  void dbgWriteToObjFile(FILE* _file, int _posAttrID = 0, int _normalAttrID = -1, int _texcAttrID = -1);
209 
210 
211  void setFaceData(int _faceID, int _size, int* _data, int _attrID = 0);
212 
213 protected:
214 
215  int numFaces_,
216  numIndices_;
217 
218  // input data is stored in a sequence stream
219  // face offsets may not be in sequence
220  std::vector<int> faceOffset_;
221  std::vector<int> faceSize_;
222 
223  // face index buffer for each vertex attribute
224  std::vector<int> faceData_[16];
225 
226 };
227 
228 
229 class ACGDLLEXPORT MeshCompilerVertexCompare
230 {
231 public:
232  MeshCompilerVertexCompare(double _d_eps = 1e-4, float _f_eps = 1e-4f) : d_eps_(_d_eps), f_eps_(_f_eps) {}
233 
234  virtual bool equalVertex(const void* v0, const void* v1, const VertexDeclaration* _decl);
235 
236  const double d_eps_;
237  const float f_eps_;
238 };
239 
240 class ACGDLLEXPORT MeshCompiler
241 {
242 public:
243 
244  explicit MeshCompiler(const VertexDeclaration& _decl);
245 
246  virtual ~MeshCompiler();
247 
248 //===========================================================================
251 //===========================================================================
252 
262  void setVertices(size_t _num, const void* _data, size_t _stride = 0, bool _internalCopy = false, GLuint _fmt = 0, int _elementSize = -1);
263 
273  void setNormals(size_t _num, const void* _data, size_t _stride = 0, bool _internalCopy = false, GLuint _fmt = 0, int _elementSize = -1);
274 
284  void setTexCoords(size_t _num, const void* _data, size_t _stride = 0, bool _internalCopy = false, GLuint _fmt = 0, int _elementSize = -1);
285 
297  void setAttribVec(int _attrIdx, size_t _num, const void* _data, size_t _stride = 0, bool _internalCopy = false, GLuint _fmt = 0, int _elementSize = -1);
298 
306  void setAttrib(int _attrIdx, int _v, const void* _data);
307 
308 
313  int getNumInputAttributes(int _attrIdx) const;
314 
318 //===========================================================================
321 //===========================================================================
322 
330  void setFaceInput(MeshCompilerFaceInput* _faceInput);
331 
334 //===========================================================================
337 //===========================================================================
338 
346  void setNumFaces(const int _numFaces, const int _numIndices);
347 
348 
356  void setIndexBufferInterleaved(int _numTris, int _indexSize, const void* _indices);
357 
365  void setFaceVerts(int _i, int _v0, int _v1, int _v2);
366 
373  void setFaceVerts(int _i, int _faceSize, int* _v);
374 
382  void setFaceNormals(int _i, int _v0, int _v1, int _v2);
383 
390  void setFaceNormals(int _i, int _faceSize, int* _v);
391 
399  void setFaceTexCoords(int _i, int _v0, int _v1, int _v2);
400 
407  void setFaceTexCoords(int _i, int _faceSize, int* _v);
408 
409 
418  void setFaceAttrib(int _i, int _v0, int _v1, int _v2, int _attrID);
419 
427  void setFaceAttrib(int _i, int _faceSize, int* _v, int _attrID);
428 
429 
432 //===========================================================================
435 //===========================================================================
436 
437 
445  void setFaceGroup(int _i, short _groupID);
446 
447  // subset/group management
448  struct Subset
449  {
450  int id; // subset id
451  unsigned int startIndex; // 1st occurrence of group in index buffer
452  unsigned int numTris; // number of tris belonging to subset in index buffer
453 
454  unsigned int numFaces; // number of faces belonging to subset
455  unsigned int startFace; // index into sorted list of faces
456  };
457 
463  int findGroupSubset(int _groupID);
464 
470  int getFaceGroup(int _faceID) const;
471 
477  int getTriGroup(int _triID) const;
478 
483  int getNumSubsets() const {return (int)subsets_.size();}
484 
490  const Subset* getSubset(int _i) const;
491 
492 
495 //===========================================================================
498 //===========================================================================
499 
500 
508  void build(bool _weldVertices = false, bool _optimizeVCache = true, bool _needPerFaceAttribute = false, bool _keepIsolatedVertices = false);
509 
512  int getNumVertices() const {return numDrawVerts_;}
513 
524  void setProvokingVertex(int _v);
525 
530  int getProvokingVertex() const {return provokingVertex_;}
531 
532 
541  void getVertexBuffer(void* _dst, const int _offset = 0, const int _range = -1);
542 
545  const int* getIndexBuffer() const {return indices_.data();}
546 
571  void getIndexAdjBuffer(void* _dst, const int _borderIndex = -1);
572 
582  void getIndexAdjBuffer_BruteForce(void* _dst, const int _borderIndex = -1);
583 
584 
587  int getNumTriangles() const {return numTris_;}
588 
591  int getNumFaces() const;
592 
598  inline int getFaceSize(const int _i) const
599  {
600  return int(faceSize_.empty() ? maxFaceSize_ : faceSize_[_i]);
601  }
602 
605  const VertexDeclaration* getVertexDeclaration() const {return &decl_;}
606 
609  void getVertex(int _id, void* _out) const;
610 
613  int getIndex(int _i) const;
614 
615 
620 //===========================================================================
623 //===========================================================================
624 
625 
633  int mapToOriginalVertexID(const size_t _i, int& _faceID, int& _cornerID) const;
634 
640  int mapToOriginalFaceID(const int _triID) const;
641 
646  const int* mapToOriginalFaceIDPtr() const;
647 
654  int mapToDrawVertexID(const int _faceID, const int _cornerID) const;
655 
663  int mapToDrawTriID(const int _faceID, const int _k = 0, int* _numTrisOut = 0) const;
664 
665 
669 //===========================================================================
672 //===========================================================================
673 
676  bool isTriangleMesh() const;
677 
686  bool isFaceEdge(const int _triID, const int _edge) const;
687 
688 
693 private:
694 
695  // compute adjacency information: vertex -> neighboring faces (, face -> neighboring faces [removed] )
696  void computeAdjacency(bool _forceRecompute = false);
697 
698  // convert per-face vertices to unique ids
699  void splitVertices();
700 
701 private:
702 
703  // small helper functions
704 
709  void getInputFaceVertex(const int _face, const int _corner, int* _out) const;
710 
715  void getInputFaceVertex_Welded(const int _face, const int _corner, int* _out) const;
716 
721  void getInputFaceVertexData(const int _face, const int _corner, void* _out) const;
722 
723 
724  inline int getInputIndex( const int& _face, const int& _corner, const int& _attrId ) const
725  {
726  return faceInput_->getSingleFaceAttr(_face, _corner, _attrId);
727 
728  // alternatively avoid virtual function call at cost of higher memory overhead ( could not confirm any run-time difference )
729  // to use this, uncomment code in prepareData() that initializes faceData_ array as well
730 // return faceData_[(getInputFaceOffset(_face) + _corner) * numAttributes_ + _attrId];
731  }
732 
733 
734 private:
735 
736  // ====================================================
737  // input data
738 
739 
740  // vertex buffer input
741 
742  struct ACGDLLEXPORT VertexElementInput
743  {
745  ~VertexElementInput();
746 
748  char* internalBuf;
749 
753  const char* data;
754 
756  int count;
757 
759  int stride;
760 
762  int attrSize;
763 
764 
765  // vertex data access
766 
768  GLuint fmt;
769 
772 
774  void getElementData(int _idx, void* _dst, const VertexElement* _desc) const;
775  };
776 
777  // input vertex data
778  VertexElementInput input_[16];
779 
780  // convenient attribute indices
781  int inputIDPos_; // index of positions into input_ array
782  int inputIDNorm_; // index of normals into input_ array
783  int inputIDTexC_; // index of texcoords into input_ array
784 
785  int numAttributes_;
786  VertexDeclaration decl_;
787 
788 
789  // input face data
790 
791  int numFaces_,
792  numIndices_;
793 
794  std::vector<int> faceStart_; // start position in buf for each face
795  std::vector<int> faceSize_; // face size, copy of faceInput_->getFaceSize() for better performance
796  std::vector<int> faceData_;
797  size_t maxFaceSize_; // max(faceSize_)
798  bool constantFaceSize_;
799  std::vector<short> faceGroupIDs_; // group id for each face (optional input)
800  int curFaceInputPos_; // current # indices set by user
801 
802  MeshCompilerFaceInput* faceInput_; // face data input interface
803  bool deleteFaceInputeData_; // delete if face input data internally created
804 
805  std::vector<int> faceBufSplit_; // mapping from (faceID, cornerID) to interleaved vertex id after splitting
806  std::vector<int> faceSortMap_; // face IDs sorted by group; maps sortFaceID -> FaceID
807  int provokingVertex_; // provoking vertex of each triangle
808  bool provokingVertexSetByUser_; // was the provoking vertex selected by user or set to default?
809 
810  int numTris_;
811  std::vector<int> triIndexBuffer_; // triangulated index buffer with interleaved vertices
812 
813  // IDs of isolated vertices: index into input position buffer
814  std::vector<int> isolatedVertices_;
815 
816  // face grouping with subsets for per-face materials
817  int numSubsets_;
818  std::vector<Subset> subsets_;
819  std::map<int, int> subsetIDMap_; // maps groupId -> subsetID
820 
821  // =====================================================
822 
823  struct ACGDLLEXPORT AdjacencyList
824  {
825  AdjacencyList()
826  : start(0), count(0), buf(0), bufSize(0), num(0) {}
827  ~AdjacencyList()
828  {
829  delete [] start;
830  delete [] buf;
831  delete [] count;
832  }
833 
834  void init(int n);
835  int getAdj(int i, int k) const;
836  int getCount(int i) const;
837 
838  void clear();
839 
840  int* start; // index to adjacency buffer
841  unsigned char* count; // # of adjacent faces
842  int* buf; // adjacency data
843  int bufSize; // size of buf
844  int num; // # adjacency entries
845 
846 // void dbgdump(FILE* file) const;
847  void dbgdump(std::ofstream& file) const;
848  };
849 
850  // adjacency list: vertex -> faces
851  AdjacencyList adjacencyVert_;
852 
853  // adjacency access interface (choosing between user input / self generated data)
854  int getAdjVertexFaceCount(int _vertexID) const;
855  int getAdjVertexFace(int _vertexID, int _k) const;
856 
857 
859  {
860  int faceId;
861  int cornerId;
862 
863  int refFaceId;
864  int refCornerId;
865  };
866 
867  struct ACGDLLEXPORT WeldList
868  {
869  void add(const int _face, const int _corner);
870 
871  std::vector< WeldListEntry > list;
872 
873  MeshCompiler* meshComp;
874  MeshCompilerVertexCompare* cmpFunc;
875 
876  char* workBuf;
877  };
878 
879 
880  static MeshCompilerVertexCompare defaultVertexCompare;
881  MeshCompilerVertexCompare* vertexCompare_;
882 
883  // mapping from <faceId, faceCornerId> -> <weldFaceId, weldFaceCorner>
884 // std::vector< std::pair<int, unsigned char> > vertexWeldMap_; // std::pair<int, unsigned char> gets padded to 8 bytes
885  std::vector<int> vertexWeldMapFace_;
886  std::vector<int> vertexWeldMapCorner_;
887 
888 
889  struct ACGDLLEXPORT VertexSplitter
890  {
891  // worst case split: num entries in vertex adj list
892  // estBufferIncrease: if numWorstCase == 0, then we estimate an increase in vertex buffer by this percentage
893  VertexSplitter(int numAttribs,
894  int numVerts,
895  int numWorstCase = 0,
896  float estBufferIncrease = 0.5f);
897 
898  ~VertexSplitter();
899 
901  int split(int* vertex);
902 
904  bool isIsolated(const int vertexPosID);
905 
906  int numAttribs;
907 
909  int numVerts;
910 
912  const int numBaseVerts;
913 
925 // int* splits;
926  std::vector<int> splits;
927 
928  // split list access
929  int getNext(const int id);
930  int* getAttribs(const int id);
931  void setNext(const int id, const int next);
932  void setAttribs(const int id, int* attr);
933 
934  // debugging metrics
935  int dbg_numResizes;
936  int dbg_numSplits;
937  };
938 
939  VertexSplitter* splitter_;
940 
941  // =====================================================
942 
943  // mappings
944 
946  std::vector<int> triToSortFaceMap_;
947 
949  std::vector<int> triOptMap_;
950 
952 // std::vector<std::pair<int, unsigned char> > vertexMap_; // sizeof( std::pair<int, unsigned char> ) = 8!!
953  std::vector<int> vertexMapFace_;
954  std::vector<int> vertexMapCorner_;
955 
957  std::vector<int> faceToTriMap_;
958  std::vector<int> faceToTriMapOffset_;
959 
961  std::vector<int> triToFaceMap_;
962 
963  // =====================================================
964 
965  // final buffers used for drawing
966 
969 
972 
974  std::vector<int> indices_;
975 
976 private:
977 
978  // return interleaved vertex id for input buffers
979  int getInputIndexSplit(const int _face, const int _corner) const;
980 
981  void setInputIndexSplit(const int _face, const int _corner, const int _val);
982 
983  int mapTriToInputFace(const int _tri) const;
984 
985  int getInputIndexOffset(const int _face, const int _corner) const;
986 
987  inline int getInputFaceOffset(const int _face) const
988  {
989  return int(faceStart_.empty() ? maxFaceSize_ * _face : faceStart_[_face]);
990  }
991 
993  void prepareData();
994 
995  // find isolated vertices
996  void findIsolatedVertices();
997 
998  // make sure each face has one vertex id without any references by neighboring faces
999  // split vertices when necessary
1000  void forceUnsharedFaceVertex();
1001 
1002  // eliminate duplicate attribute entries
1003  void weldVertices();
1004 
1005  // fix incomplete welding map if mesh contains isolated vertices
1006  void fixWeldMap();
1007 
1008  // convert n-poly -> tris (triangle fans)
1009  void triangulate();
1010 
1011  // resolve triangulation
1012  void resolveTriangulation();
1013 
1014  // sort input faces by group ids
1015  void sortFacesByGroup();
1016 
1017  // v-cache optimization + vertex reorder
1018  void optimize();
1019 
1020  // create vertex mapping: input id <-> final buffer id
1021  void createVertexMap(bool _keepIsolatedVerts);
1022 
1023  // create face mapping: input id <-> final tri id
1024  void createFaceMap();
1025 
1026 public:
1027 
1035  void getIndexAdjBuffer_MT(void* _dst, const int _borderIndex = -1);
1036 
1037  // debugging tools
1038 
1040  void dbgdump(const char* _filename) const;
1041 
1043  void dbgdumpObj(const char* _filename) const;
1044 
1046  void dbgdumpInputBin(const char* _filename, bool _seperateFiles = false) const;
1047 
1049  void dbgdumpInputObj(const char* _filename) const;
1050 
1052  void dbgdumpAdjList(const char* _filename) const;
1053 
1055  bool dbgVerify(const char* _filename) const;
1056 
1058  std::string vertexToString(const void* v) const;
1059 
1062  size_t getMemoryUsage(bool _printConsole = true) const;
1063 
1065  std::string checkInputData() const;
1066 };
1067 
1069 {
1070  RingTriangle() {}
1071  RingTriangle(int i, RingTriangle* p, RingTriangle* n) : id(i), prev(p), next(n) {}
1072 
1073  int id; // local index of the triangle within a polygon [0, ... faceSize-3]
1074  RingTriangle* prev; // prev triangle in the ring
1075  RingTriangle* next; // next triangle in the ring
1076 };
1077 
1078 
1079 }
Namespace providing different geometric functions concerning angles.
Class to define the vertex input layout.
virtual int * getFaceAttr(const int _faceID, const int _attrID) const
std::vector< int > vertexMapFace_
vertex index in vbo -> input (face id, corner id) pair , also inverse of faceBufSplit_ ...
int getFaceSize(const int _faceID) const
virtual int getVertexAdjFace(const int _vertexID, const int _k) const
GLuint fmt
element data format
int attrSize
size in bytes of one attribute
int getNumVertices() const
const VertexDeclaration * getVertexDeclaration() const
const int * getIndexBuffer() const
std::vector< int > triOptMap_
maps from optimized tri ID to unoptimized tri ID
int getNumTriangles() const
virtual int getVertexAdjCount(const int _vertexID) const
std::vector< int > triToFaceMap_
output tri index -> input face index
const int numBaseVerts
number of input vertex positions
Description of one vertex element.
int numVerts
number of vertex combinations currently in use
virtual bool getFaceAttr(const int _faceID, const int _attrID, int *_out) const
std::vector< int > indices_
index buffer
int stride
offset in bytes from one element to the next
int getProvokingVertex() const
std::vector< int > triToSortFaceMap_
maps from triangle ID to sorted face ID
int getFaceSize(const int _i) const
Get size of input face.
int elementSize
number of ints/floats/bytes per element
int getNumSubsets() const
Get the number of subsets.
size_t numIsolatedVerts_
isolated vertices
char * internalBuf
mem alloc if attribute buffer managed by this class
std::vector< int > faceToTriMap_
input face index -> output tri index
size_t numDrawVerts_
vertices in vbo