Developer Documentation

MeshCompiler_test.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 #include <gtest/gtest.h>
43
44 #include <ACG/GL/VertexDeclaration.hh>
45 #include <ACG/GL/MeshCompiler.hh>
46
47 #include "MeshCompiler_testData.hh"
48
49
50 // Importer for custom binary file format developed to debug/profe MeshCompiler
51
52 class SBFReader : public ACG::MeshCompilerDefaultFaceInput
53 {
54 public:
55 explicit SBFReader(const char* szObjFile);
56 virtual ~SBFReader(void) {}
57
58 int getNumVertices() {return m_Vertices.size() / 3;}
59 int getNumTexcoords() {return m_TexCoords.size() / 2;}
60 int getNumNormals() {return m_Normals.size() / 3;}
61
62 float* getVertices() {return m_Vertices.empty() ? 0 : &m_Vertices[0];}
63 float* getNormals() {return m_Normals.empty() ? 0 : &m_Normals[0];}
64 float* getTexCoords() {return m_TexCoords.empty() ? 0 : &m_TexCoords[0];}
65
66 virtual int getVertexAdjCount(const int _vertexID) const
67 {
68 if (m_AdjVertexCount.size()) return m_AdjVertexCount[_vertexID];
69 else return -1;
70 }
71 virtual int getVertexAdjFace(const int _vertexID, const int _k) const
72 {
73 if (m_AdjVertexOffset.size()) return m_AdjVertexBuf[m_AdjVertexOffset[_vertexID] + _k];
74 else return -1;
75 }
76 virtual int getFaceAdjCount(int _faceID)
77 {
78 if (m_AdjFaceCount.size()) return m_AdjFaceCount[_faceID];
79 else return -1;
80 }
81 virtual int getFaceAdjFace(int _faceID, int _k)
82 {
83 if (m_AdjFaceOffset.size()) return m_AdjFaceBuf[m_AdjFaceOffset[_faceID] + _k];
84 else return -1;
85 }
86
87 void writeFile(const char* szFile);
88
89 private:
90
91 int m_NumVerts,
92 m_NumNormals,
93 m_NumTexCoords;
94
95
96 std::vector<float> m_Vertices;
97 std::vector<float> m_Normals;
98 std::vector<float> m_TexCoords;
99
100 int m_PosAttrID,
101 m_NormAttrID,
102 m_TexCAttrID;
103
104
105
106 // adjacency
107 std::vector<unsigned char> m_AdjVertexCount;
108 std::vector<int> m_AdjVertexOffset;
109 std::vector<int> m_AdjVertexBuf;
110
111 std::vector<int> m_AdjFaceOffset;
112 std::vector<unsigned char> m_AdjFaceCount;
113 std::vector<int> m_AdjFaceBuf;
114 };
115
116 SBFReader::SBFReader(const char* szObjFile)
117 : MeshCompilerDefaultFaceInput(0, 0),
118 m_NumVerts(0), m_NumNormals(0), m_NumTexCoords(0),
119 m_PosAttrID(0), m_NormAttrID(-1), m_TexCAttrID(-1)
120 {
121 if (szObjFile)
122 {
123 FILE* pFile = fopen(szObjFile, "rb");
124
125 // count # tris, verts
126
127 numFaces_ = 0;
128 m_NumVerts = 0; m_NumNormals = 0; m_NumTexCoords = 0;
129
130 if (pFile)
131 {
132 fread(&numFaces_, 4, 1, pFile);
133 fread(&m_NumVerts, 4, 1, pFile);
134 fread(&m_NumNormals, 4, 1, pFile);
135 fread(&m_NumTexCoords, 4, 1, pFile);
136
137 int faceBufSize = 0;
138 fread(&faceBufSize, 4, 1, pFile);
139
140
141 m_Vertices.resize(m_NumVerts * 3);
142 m_Normals.resize(m_NumNormals * 3);
143 m_TexCoords.resize(m_NumTexCoords * 3);
144 faceOffset_.resize(numFaces_);
145 faceSize_.resize(numFaces_);
146
147 fread(&faceSize_[0], 4, numFaces_, pFile);
148
149 faceOffset_[0] = 0;
150 for (int i = 1; i < numFaces_; ++i)
151 faceOffset_[i] = faceOffset_[i-1] + faceSize_[i-1];
152
153 if (m_NumVerts)
154 {
155 faceData_[m_PosAttrID].resize(faceBufSize);
156 fread(&faceData_[m_PosAttrID][0], 4, faceBufSize, pFile);
157 }
158
159 if (m_NumTexCoords)
160 {
161 m_TexCAttrID = 1;
162 faceData_[m_TexCAttrID].resize(faceBufSize);
163 fread(&faceData_[m_TexCAttrID][0], 4, faceBufSize, pFile);
164 }
165
166 if (m_NumNormals)
167 {
168 m_NormAttrID = m_TexCAttrID >= 0 ? m_TexCAttrID + 1 : m_PosAttrID + 1;
169 faceData_[m_NormAttrID].resize(faceBufSize);
170 fread(&faceData_[m_NormAttrID][0], 4, faceBufSize, pFile);
171 }
172
173
174 if (m_NumVerts)
175 fread(&m_Vertices[0], 12, m_NumVerts, pFile);
176
177 if (m_NumTexCoords)
178 fread(&m_TexCoords[0], 8, m_NumTexCoords, pFile);
179
180 if (m_NumNormals)
181 fread(&m_Normals[0], 12, m_NumNormals, pFile);
182
183
184 int numVertAdj, numFaceAdj, vertAdjSize, faceAdjSize;
185
186 if (fread(&numVertAdj, 4, 1, pFile) == 1)
187 {
188 fread(&vertAdjSize, 4, 1, pFile);
189
190 m_AdjVertexOffset.resize(numVertAdj);
191 m_AdjVertexCount.resize(numVertAdj);
192 m_AdjVertexBuf.resize(vertAdjSize);
193
194 fread(&m_AdjVertexOffset[0], 4, numVertAdj, pFile);
195 fread(&m_AdjVertexCount[0], 1, numVertAdj, pFile);
196 fread(&m_AdjVertexBuf[0], 4, vertAdjSize, pFile);
197
198 if (fread(&numFaceAdj, 4, 1, pFile) == 1)
199 {
200 fread(&faceAdjSize, 4, 1, pFile);
201
202 m_AdjFaceOffset.resize(numFaceAdj);
203 m_AdjFaceCount.resize(numFaceAdj);
204 m_AdjFaceBuf.resize(faceAdjSize);
205
206 fread(&m_AdjFaceOffset[0], 4, numFaceAdj, pFile);
207 fread(&m_AdjFaceCount[0], 1, numFaceAdj, pFile);
208 fread(&m_AdjFaceBuf[0], 4, faceAdjSize, pFile);
209 }
210 }
211
212 fclose(pFile);
213 }
214
215 }
216
217 }
218
219
220
221 class MeshCompilerTest : public testing::Test {
222
223 public:
224 MeshCompilerTest()
225 {
226 // create mesh 0
227 MeshTestData input0;
228 MeshCompilerTest_GetInput0(&input0);
229 mesh0_ = CreateMesh(input0);
230
231 // create mesh 1
232 MeshTestData input1;
233 MeshCompilerTest_GetInput1(&input1);
234 mesh1_ = CreateMesh(input1);
235 }
236
237 protected:
238
239 // This function is called before each test is run
240 virtual void SetUp() {
241
242 }
243
244 // This function is called after all tests are through
245 virtual void TearDown() {
246
247 delete mesh0_; mesh0_ = 0;
248 delete mesh1_; mesh1_ = 0;
249 }
250
251
252 ACG::MeshCompiler* CreateMesh(const MeshTestData& input) {
253
254 ACG::VertexDeclaration decl;
255 decl.addElement(GL_FLOAT, 3, ACG::VERTEX_USAGE_POSITION);
256 if (input.numTexcoords_)
257 decl.addElement(GL_FLOAT, 2, ACG::VERTEX_USAGE_TEXCOORD);
258 if (input.numNormals_)
259 decl.addElement(GL_FLOAT, 3, ACG::VERTEX_USAGE_NORMAL);
260
261
262 ACG::MeshCompiler* mesh = new ACG::MeshCompiler(decl);
263
264 // vertex data input
265 mesh->setVertices(input.numVerts_, input.vdata_pos);
266 mesh->setTexCoords(input.numTexcoords_, input.vdata_t);
267 mesh->setNormals(input.numNormals_, input.vdata_n);
268
269 // face input
270 mesh->setNumFaces(input.numFaces_, input.numIndices_);
271
272 int offset = 0;
273 for (int i = 0; i < input.numFaces_; ++i)
274 {
275 int fsize = input.fsize_[i];
276 mesh->setFaceVerts(i, fsize, ((int*)input.fdata_pos) + offset);
277
278 if (input.numTexcoords_ && input.fdata_t)
279 mesh->setFaceTexCoords(i, fsize, ((int*)input.fdata_t) + offset);
280
281 if (input.numNormals_ && input.fdata_n)
282 mesh->setFaceNormals(i, fsize, ((int*)input.fdata_n) + offset);
283
284 offset += fsize;
285 }
286
287 // test group id sorting
288
289 const int numGroups = 5;
290
291 //srand(GetTickCount());
292
293 for (int i = 0; i < input.numFaces_; ++i)
294 mesh->setFaceGroup(i, rand()% numGroups);
295
296 return mesh;
297 }
298
299
300 ACG::MeshCompiler* mesh0_;
301 ACG::MeshCompiler* mesh1_;
302
303 };
304
305
306 TEST_F(MeshCompilerTest, npoly_vpos__fff ) {
307
308 mesh0_->build(false, false, false);
309 EXPECT_EQ(mesh0_->dbgVerify(0), true) << "compiled mesh contains errors";
310 }
311
312 TEST_F(MeshCompilerTest, npoly_vpos__tff ) {
313
314 mesh0_->build(true, false, false);
315
316 EXPECT_EQ(mesh0_->dbgVerify(0), true) << "compiled mesh contains errors";
317 }
318
319 TEST_F(MeshCompilerTest, npoly_vpos__ftf ) {
320
321 mesh0_->build(false, true, false);
322
323 EXPECT_EQ(mesh0_->dbgVerify(0), true) << "compiled mesh contains errors";
324 }
325
326 TEST_F(MeshCompilerTest, npoly_vpos__ttf ) {
327
328 mesh0_->build(true, true, false);
329
330 EXPECT_EQ(mesh0_->dbgVerify(0), true) << "compiled mesh contains errors";
331 }
332
333
334
335
336
337 TEST_F(MeshCompilerTest, npoly_vpos__fft ) {
338
339 mesh0_->build(false, false, true);
340
341 EXPECT_EQ(mesh0_->dbgVerify(0), true) << "compiled mesh contains errors";
342 }
343
344 TEST_F(MeshCompilerTest, npoly_vpos__tft ) {
345
346 mesh0_->build(true, false, true);
347
348 EXPECT_EQ(mesh0_->dbgVerify(0), true) << "compiled mesh contains errors";
349 }
350
351 TEST_F(MeshCompilerTest, npoly_vpos__ftt ) {
352
353 mesh0_->build(false, true, true);
354
355 EXPECT_EQ(mesh0_->dbgVerify(0), true) << "compiled mesh contains errors";
356 }
357
358 TEST_F(MeshCompilerTest, npoly_vpos__ttt ) {
359
360 mesh0_->build(true, true, true);
361
362 EXPECT_EQ(mesh0_->dbgVerify(0), true) << "compiled mesh contains errors";
363 }
364
365
366
367
368
369 TEST_F(MeshCompilerTest, tri_vpos_texc__fff ) {
370
371 mesh1_->build(false, false, false);
372
373 EXPECT_EQ(mesh1_->dbgVerify(0), true) << "compiled mesh contains errors";
374 }
375
376 TEST_F(MeshCompilerTest, tri_vpos_texc__tff ) {
377
378 mesh1_->build(true, false, false);
379
380 EXPECT_EQ(mesh1_->dbgVerify(0), true) << "compiled mesh contains errors";
381 }
382
383 TEST_F(MeshCompilerTest, tri_vpos_texc__ftf ) {
384
385 mesh1_->build(false, true, false);
386
387 EXPECT_EQ(mesh1_->dbgVerify(0), true) << "compiled mesh contains errors";
388 }
389
390 TEST_F(MeshCompilerTest, tri_vpos_texc__ttf ) {
391
392 mesh1_->build(true, true, false);
393
394 EXPECT_EQ(mesh1_->dbgVerify(0), true) << "compiled mesh contains errors";
395 }
396
397
398
399
400
401 TEST_F(MeshCompilerTest, tri_vpos_texc__fft ) {
402
403 mesh1_->build(false, false, true);
404
405 EXPECT_EQ(mesh1_->dbgVerify(0), true) << "compiled mesh contains errors";
406 }
407
408 TEST_F(MeshCompilerTest, tri_vpos_texc__tft ) {
409
410 mesh1_->build(true, false, true);
411
412 EXPECT_EQ(mesh1_->dbgVerify(0), true) << "compiled mesh contains errors";
413 }
414
415 TEST_F(MeshCompilerTest, tri_vpos_texc__ftt ) {
416
417 mesh1_->build(false, true, true);
418
419 EXPECT_EQ(mesh1_->dbgVerify(0), true) << "compiled mesh contains errors";
420 }
421
422 TEST_F(MeshCompilerTest, tri_vpos_texc__ttt ) {
423
424 mesh1_->build(true, true, true);
425
426 EXPECT_EQ(mesh1_->dbgVerify(0), true) << "compiled mesh contains errors";
427 }
ACG::VertexDeclaration
Class to define the vertex input layout.
Definition: VertexDeclaration.hh:268
ACG::MeshCompiler::setFaceGroup
void setFaceGroup(int _i, short _groupID)
Specify face groups.
Definition: MeshCompiler.cc:3199
ACG::MeshCompiler
Definition: MeshCompiler.hh:240
SBFReader::getVertexAdjCount
virtual int getVertexAdjCount(const int _vertexID) const
Definition: MeshCompiler_test.cc:66
SBFReader
Definition: MeshCompiler_test.cc:52
ACG::MeshCompiler::setTexCoords
void setTexCoords(size_t _num, const void *_data, size_t _stride=0, bool _internalCopy=false, GLuint _fmt=0, int _elementSize=-1)
Definition: MeshCompiler.cc:263
ACG::MeshCompiler::setNormals
void setNormals(size_t _num, const void *_data, size_t _stride=0, bool _internalCopy=false, GLuint _fmt=0, int _elementSize=-1)
Definition: MeshCompiler.cc:258
ACG::MeshCompiler::setVertices
void setVertices(size_t _num, const void *_data, size_t _stride=0, bool _internalCopy=false, GLuint _fmt=0, int _elementSize=-1)
Definition: MeshCompiler.cc:253
ACG::MeshCompiler::setNumFaces
void setNumFaces(const int _numFaces, const int _numIndices)
Set number of faces and indices if known by user.
Definition: MeshCompiler.cc:1202
ACG::VertexDeclaration::addElement
void addElement(const VertexElement *_pElement)
Definition: VertexDeclaration.cc:115
ACG::MeshCompiler::setFaceNormals
void setFaceNormals(int _i, int _v0, int _v1, int _v2)
Set normal ids per triangle.
Definition: MeshCompiler.cc:2988
MeshTestData
Definition: MeshCompiler_testData.hh:45
ACG::MeshCompilerDefaultFaceInput
Definition: MeshCompiler.hh:193
MeshCompilerTest
Definition: MeshCompiler_test.cc:221
ACG::MeshCompiler::setFaceTexCoords
void setFaceTexCoords(int _i, int _v0, int _v1, int _v2)
Set texcoord ids per triangle.
Definition: MeshCompiler.cc:3000
ACG::VERTEX_USAGE_NORMAL
"inNormal"
Definition: VertexDeclaration.hh:66
SBFReader::getVertexAdjFace
virtual int getVertexAdjFace(const int _vertexID, const int _k) const
Definition: MeshCompiler_test.cc:71
ACG::VERTEX_USAGE_POSITION
"inPosition"
Definition: VertexDeclaration.hh:65
ACG::MeshCompiler::setFaceVerts
void setFaceVerts(int _i, int _v0, int _v1, int _v2)
Set vertex ids per triangle.
Definition: MeshCompiler.cc:2977
ACG::VERTEX_USAGE_TEXCOORD
"inTexCoord"
Definition: VertexDeclaration.hh:67