Developer Documentation
Loading...
Searching...
No Matches
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
59Mesh buffer assembler:
60
61Builds 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
71usage
72
731. Create a vertex declaration to specify your wanted
74 vertex format, such as float3 pos, float3 normal..
75
762. 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
1063. 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
1224. finish the initialization by calling the build() function
123
124*/
125
126namespace ACG{
127
128class ACGDLLEXPORT MeshCompilerFaceInput
129{
130 // face data input interface
131 // allows flexible and memory efficient face data input
132
133public:
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{
195public:
196 MeshCompilerDefaultFaceInput(int _numFaces, int _numIndices);
198
199 int getNumFaces() const override {return numFaces_;}
200 int getNumIndices() const override {return numIndices_;}
201
202 int getFaceSize(const int _faceID) const override {return faceSize_[_faceID];}
203
204 int getSingleFaceAttr(const int _faceID, const int _faceCorner, const int _attrID) const override;
205
206 bool getFaceAttr(const int _faceID, const int _attrID, int* _out) const override;
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
213protected:
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
230{
231public:
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
240class ACGDLLEXPORT MeshCompiler
241{
242public:
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
693private:
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
701private:
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
734private:
735
736 // ====================================================
737 // input data
738
739
740 // vertex buffer input
741
742 struct ACGDLLEXPORT VertexElementInput
743 {
746
749
753 const char* data;
754
756 int count;
757
760
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 {
826 : start(0), count(0), buf(0), bufSize(0), num(0) {}
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;
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
899
901 int split(int* vertex);
902
904 bool isIsolated(const int vertexPosID);
905
906 int numAttribs;
907
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
976private:
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
1026public:
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}
int getFaceSize(const int _faceID) const override
int getNumIndices() const override
virtual bool getFaceAttr(const int _faceID, const int _attrID, int *_out) const
virtual int * getFaceAttr(const int _faceID, const int _attrID) const
virtual int getVertexAdjCount(const int _vertexID) const
virtual int getNumIndices() const =0
virtual int getFaceSize(const int _faceID) const =0
virtual int getVertexAdjFace(const int _vertexID, const int _k) const
int getFaceSize(const int _i) const
Get size of input face.
int getNumTriangles() const
std::vector< int > triToSortFaceMap_
maps from triangle ID to sorted face ID
int getProvokingVertex() const
std::vector< int > triToFaceMap_
output tri index -> input face index
std::vector< int > triOptMap_
maps from optimized tri ID to unoptimized tri ID
std::vector< int > faceToTriMap_
input face index -> output tri index
int getNumSubsets() const
Get the number of subsets.
const int * getIndexBuffer() const
std::vector< int > vertexMapFace_
vertex index in vbo -> input (face id, corner id) pair , also inverse of faceBufSplit_
std::vector< int > indices_
index buffer
int getNumVertices() const
int getTriGroup(int _triID) const
Get Group Id of the triangle.
const VertexDeclaration * getVertexDeclaration() const
Class to define the vertex input layout.
Namespace providing different geometric functions concerning angles.
int stride
offset in bytes from one element to the next
char * internalBuf
mem alloc if attribute buffer managed by this class
int attrSize
size in bytes of one attribute
int elementSize
number of ints/floats/bytes per element
const int numBaseVerts
number of input vertex positions
int numVerts
number of vertex combinations currently in use
Description of one vertex element.