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 
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:
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 
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 }
Class to define the vertex input layout.
void setFaceGroup(int _i, short _groupID)
Specify face groups.
virtual int getVertexAdjCount(const int _vertexID) const
void setTexCoords(size_t _num, const void *_data, size_t _stride=0, bool _internalCopy=false, GLuint _fmt=0, int _elementSize=-1)
void setNormals(size_t _num, const void *_data, size_t _stride=0, bool _internalCopy=false, GLuint _fmt=0, int _elementSize=-1)
void setVertices(size_t _num, const void *_data, size_t _stride=0, bool _internalCopy=false, GLuint _fmt=0, int _elementSize=-1)
void setNumFaces(const int _numFaces, const int _numIndices)
Set number of faces and indices if known by user.
void addElement(const VertexElement *_pElement)
void setFaceNormals(int _i, int _v0, int _v1, int _v2)
Set normal ids per triangle.
void setFaceTexCoords(int _i, int _v0, int _v1, int _v2)
Set texcoord ids per triangle.
virtual int getVertexAdjFace(const int _vertexID, const int _k) const
void setFaceVerts(int _i, int _v0, int _v1, int _v2)
Set vertex ids per triangle.