1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the libgltf project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  */
9 
10 #include "APITest.h"
11 #include "OpenGLContext.h"
12 #include "PNGHelper.h"
13 
14 #include <libgltf.h>
15 #include "TimeFunction.h"
16 
17 #include <iostream>
18 #include <fstream>
19 #include <sstream>
20 #include <cmath>
21 
22 namespace libgltf { namespace test
23 {
24 
setUp()25 void APITest::setUp()
26 {
27 }
28 
tearDown()29 void APITest::tearDown()
30 {
31 }
32 
33 // I) Testing gltf_renderer_init() method
test_gltf_renderer_init()34 void APITest::test_gltf_renderer_init()
35 {
36     // 1) Test the usual case, valid *.json and empty vInputFiles
37     {
38         std::vector<glTFFile> vInputFiles;
39         glTFHandle* pHandle = gltf_renderer_init(DUCK_FILE_NAME, vInputFiles);
40         CPPUNIT_ASSERT(pHandle);
41         CPPUNIT_ASSERT_EQUAL(size_t(4), vInputFiles.size());
42 
43         CPPUNIT_ASSERT_EQUAL(std::string("duckCM.png"), vInputFiles[0].filename);
44         CPPUNIT_ASSERT_EQUAL(GLTF_IMAGE, vInputFiles[0].type);
45 
46         CPPUNIT_ASSERT_EQUAL(std::string("duck.bin"), vInputFiles[1].filename);
47         CPPUNIT_ASSERT_EQUAL(GLTF_BINARY, vInputFiles[1].type);
48 
49         CPPUNIT_ASSERT_EQUAL(std::string("duck0FS.glsl"), vInputFiles[2].filename);
50         CPPUNIT_ASSERT_EQUAL(GLTF_GLSL, vInputFiles[2].type);
51 
52         CPPUNIT_ASSERT_EQUAL(std::string("duck0VS.glsl"), vInputFiles[3].filename);
53         CPPUNIT_ASSERT_EQUAL(GLTF_GLSL, vInputFiles[3].type);
54 
55         gltf_renderer_release(pHandle);
56     }
57 
58     // 2) When *.json file name is empty
59     {
60         std::vector<glTFFile> vInputFiles;
61         glTFHandle* pHandle = gltf_renderer_init("", vInputFiles);
62         CPPUNIT_ASSERT(!pHandle);
63     }
64 
65     // 3) When *.json file does not exist
66     {
67         std::vector<glTFFile> vInputFiles;
68         glTFHandle* pHandle = gltf_renderer_init("../duck_model/duck.json", vInputFiles);
69         CPPUNIT_ASSERT(!pHandle);
70     }
71 
72     // 4) When *.json file is broken (invalid content)
73     {
74         std::vector<glTFFile> vInputFiles;
75         glTFHandle* pHandle = gltf_renderer_init("../data/duck_model/duck_broken.json", vInputFiles);
76         CPPUNIT_ASSERT(!pHandle);
77     }
78 
79     // 5) When the output vector is not empty, check whether the method overwrites the vector
80     {
81         std::vector<glTFFile> vInputFiles;
82         vInputFiles.resize(10);
83         vInputFiles[0].filename = "dummy";
84         vInputFiles[0].size = 2000;
85         glTFHandle* pHandle = gltf_renderer_init(DUCK_FILE_NAME, vInputFiles);
86         CPPUNIT_ASSERT(pHandle);
87         CPPUNIT_ASSERT_EQUAL(size_t(4), vInputFiles.size());
88 
89         CPPUNIT_ASSERT_EQUAL(std::string("duckCM.png"), vInputFiles[0].filename);
90         CPPUNIT_ASSERT_EQUAL(size_t(0), vInputFiles[0].size);
91 
92         gltf_renderer_release(pHandle);
93     }
94 
95     // 6) When *.json file contains not only file name of image/binary files but also a path
96     {
97         std::vector<glTFFile> vInputFiles;
98         glTFHandle* pHandle = gltf_renderer_init("../data/duck_model/duck_with_relative_path.json", vInputFiles);
99         CPPUNIT_ASSERT(pHandle);
100         CPPUNIT_ASSERT_EQUAL(size_t(4), vInputFiles.size());
101 
102         CPPUNIT_ASSERT_EQUAL(std::string("textures/duckCM.png"), vInputFiles[0].filename);
103         CPPUNIT_ASSERT_EQUAL(GLTF_IMAGE, vInputFiles[0].type);
104 
105         CPPUNIT_ASSERT_EQUAL(std::string("buffers/duck.bin"), vInputFiles[1].filename);
106         CPPUNIT_ASSERT_EQUAL(GLTF_BINARY, vInputFiles[1].type);
107 
108         CPPUNIT_ASSERT_EQUAL(std::string("shaders/duck0FS.glsl"), vInputFiles[2].filename);
109         CPPUNIT_ASSERT_EQUAL(GLTF_GLSL, vInputFiles[2].type);
110 
111         CPPUNIT_ASSERT_EQUAL(std::string("shaders/duck0VS.glsl"), vInputFiles[3].filename);
112         CPPUNIT_ASSERT_EQUAL(GLTF_GLSL, vInputFiles[3].type);
113 
114         gltf_renderer_release(pHandle);
115     }
116 }
117 
118 // II) Testing gltf_renderer_set_content() method
test_gltf_renderer_set_content()119 void APITest::test_gltf_renderer_set_content()
120 {
121     OpenGLContext aContext;
122     aContext.init();
123 
124     // 1) Check when all files are available
125     {
126         std::vector<glTFFile> vInputFiles;
127         glTFHandle* pHandle = parseJsonAndLoadInputFiles(vInputFiles);
128 
129         int nRet = gltf_renderer_set_content(pHandle, vInputFiles);
130         CPPUNIT_ASSERT_EQUAL(LIBGLTF_SUCCESS, nRet);
131         gltf_renderer_release(pHandle);
132         releaseInputFiles(vInputFiles);
133     }
134 
135     // 2) Check when the texture file is missing entirely
136     {
137         std::vector<glTFFile> vInputFiles;
138         glTFHandle* pHandle = parseJsonAndLoadInputFiles(vInputFiles);
139 
140         delete vInputFiles[0].buffer;
141         vInputFiles.erase(vInputFiles.begin());
142 
143         int nRet = gltf_renderer_set_content(pHandle, vInputFiles);
144         CPPUNIT_ASSERT_EQUAL(LIBGLTF_FILE_NOT_LOAD, nRet);
145         gltf_renderer_release(pHandle);
146         releaseInputFiles(vInputFiles);
147     }
148 
149     // 3) Check when the texture was not loaded actually
150     {
151         std::vector<glTFFile> vInputFiles;
152         glTFHandle* pHandle = parseJsonAndLoadInputFiles(vInputFiles);
153 
154         delete vInputFiles[0].buffer;
155         vInputFiles[0].buffer = 0;
156         vInputFiles[0].imagewidth = 0;
157 
158         int nRet = gltf_renderer_set_content(pHandle, vInputFiles);
159         CPPUNIT_ASSERT_EQUAL(LIBGLTF_FILE_NOT_LOAD, nRet);
160         gltf_renderer_release(pHandle);
161         releaseInputFiles(vInputFiles);
162     }
163 
164     // 4) Check when the *.bin file is missing entirely
165     {
166         std::vector<glTFFile> vInputFiles;
167         glTFHandle* pHandle = parseJsonAndLoadInputFiles(vInputFiles);
168 
169         delete vInputFiles[1].buffer;
170         vInputFiles.erase(++vInputFiles.begin());
171 
172         int nRet = gltf_renderer_set_content(pHandle, vInputFiles);
173         CPPUNIT_ASSERT_EQUAL(LIBGLTF_FILE_NOT_LOAD, nRet);
174         gltf_renderer_release(pHandle);
175         releaseInputFiles(vInputFiles);
176     }
177 
178     // 5) Check when the *.bin file was not loaded actually
179     {
180         std::vector<glTFFile> vInputFiles;
181         glTFHandle* pHandle = parseJsonAndLoadInputFiles(vInputFiles);
182 
183         delete vInputFiles[1].buffer;
184         vInputFiles[1].buffer = 0;
185         vInputFiles[1].size = 0;
186 
187         int nRet = gltf_renderer_set_content(pHandle, vInputFiles);
188         CPPUNIT_ASSERT_EQUAL(LIBGLTF_FILE_NOT_LOAD, nRet);
189         gltf_renderer_release(pHandle);
190         releaseInputFiles(vInputFiles);
191     }
192 
193     // 6) Check when the *.bin file size is not equal with the size read from the *.json file
194     {
195         std::vector<glTFFile> vInputFiles;
196         glTFHandle* pHandle = parseJsonAndLoadInputFiles(vInputFiles);
197 
198         vInputFiles[1].size = 10;
199 
200         int nRet = gltf_renderer_set_content(pHandle, vInputFiles);
201         CPPUNIT_ASSERT_EQUAL(LIBGLTF_FILE_NOT_LOAD, nRet);
202         gltf_renderer_release(pHandle);
203         releaseInputFiles(vInputFiles);
204     }
205 
206     // 7) Check when fragment shader is missing entirely
207     {
208         std::vector<glTFFile> vInputFiles;
209         glTFHandle* pHandle = parseJsonAndLoadInputFiles(vInputFiles);
210 
211         delete vInputFiles[2].buffer;
212         vInputFiles.erase(++(++vInputFiles.begin()));
213 
214         int nRet = gltf_renderer_set_content(pHandle, vInputFiles);
215         CPPUNIT_ASSERT_EQUAL(LIBGLTF_FILE_NOT_LOAD, nRet);
216         gltf_renderer_release(pHandle);
217         releaseInputFiles(vInputFiles);
218     }
219 
220     // 8) Check when fragment shader file was not loaded actually
221     {
222         std::vector<glTFFile> vInputFiles;
223         glTFHandle* pHandle = parseJsonAndLoadInputFiles(vInputFiles);
224 
225         delete vInputFiles[2].buffer;
226         vInputFiles[2].buffer = 0;
227         vInputFiles[2].size = 0;
228 
229         int nRet = gltf_renderer_set_content(pHandle, vInputFiles);
230         CPPUNIT_ASSERT_EQUAL(LIBGLTF_FILE_NOT_LOAD, nRet);
231         gltf_renderer_release(pHandle);
232         releaseInputFiles(vInputFiles);
233     }
234 
235     // 9) Check when fragment shader is invalid (GLSL error)
236     {
237         std::vector<glTFFile> vInputFiles;
238         glTFHandle* pHandle = parseJsonAndLoadInputFiles(vInputFiles,"../data/duck_model/duck_with_invalid_FS.json" );
239 
240         int nRet = gltf_renderer_set_content(pHandle, vInputFiles);
241         CPPUNIT_ASSERT_EQUAL(LIBGLTF_SHADER_ERROR, nRet);
242         gltf_renderer_release(pHandle);
243         releaseInputFiles(vInputFiles);
244     }
245 
246     // 10) Check when vertex shader is missing entirely
247     {
248         std::vector<glTFFile> vInputFiles;
249         glTFHandle* pHandle = parseJsonAndLoadInputFiles(vInputFiles);
250 
251         delete vInputFiles[3].buffer;
252         vInputFiles.erase(++(++(++vInputFiles.begin())));
253 
254         int nRet = gltf_renderer_set_content(pHandle, vInputFiles);
255         CPPUNIT_ASSERT_EQUAL(LIBGLTF_FILE_NOT_LOAD, nRet);
256         gltf_renderer_release(pHandle);
257         releaseInputFiles(vInputFiles);
258     }
259 
260     // 11) Check when vertex shader file was not loaded actually
261     {
262         std::vector<glTFFile> vInputFiles;
263         glTFHandle* pHandle = parseJsonAndLoadInputFiles(vInputFiles);
264 
265         delete vInputFiles[3].buffer;
266         vInputFiles[3].buffer = 0;
267         vInputFiles[3].size = 0;
268 
269         int nRet = gltf_renderer_set_content(pHandle, vInputFiles);
270         CPPUNIT_ASSERT_EQUAL(LIBGLTF_FILE_NOT_LOAD, nRet);
271         gltf_renderer_release(pHandle);
272         releaseInputFiles(vInputFiles);
273     }
274 
275     // 12) Check when vertex shader is invalid (GLSL error)
276     {
277         std::vector<glTFFile> vInputFiles;
278         glTFHandle* pHandle = parseJsonAndLoadInputFiles(vInputFiles,"../data/duck_model/duck_with_invalid_VS.json" );
279 
280         int nRet = gltf_renderer_set_content(pHandle, vInputFiles);
281         CPPUNIT_ASSERT_EQUAL(LIBGLTF_SHADER_ERROR, nRet);
282         gltf_renderer_release(pHandle);
283         releaseInputFiles(vInputFiles);
284     }
285 
286     // 13) Check when non of the files are available
287     {
288         std::vector<glTFFile> vInputFiles;
289         glTFHandle* pHandle = parseJsonAndLoadInputFiles(vInputFiles);
290 
291         releaseInputFiles(vInputFiles);
292 
293         int nRet = gltf_renderer_set_content(pHandle, vInputFiles);
294         CPPUNIT_ASSERT_EQUAL(LIBGLTF_FILE_NOT_LOAD, nRet);
295         gltf_renderer_release(pHandle);
296     }
297 
298     // 14) Check when input files are given with relative path
299     {
300         std::vector<glTFFile> vInputFiles;
301         glTFHandle* pHandle = parseJsonAndLoadInputFiles(vInputFiles, "../data/duck_model/duck_with_relative_path.json");
302 
303         int nRet = gltf_renderer_set_content(pHandle, vInputFiles);
304         CPPUNIT_ASSERT_EQUAL(LIBGLTF_SUCCESS, nRet);
305         gltf_renderer_release(pHandle);
306     }
307 }
308 
309 // III) Testing gltf_get_camera_pos() method
test_gltf_get_camera_pos()310 void APITest::test_gltf_get_camera_pos()
311 {
312     // 1) When gltf_renderer_set_content() was not called yet (crash test)
313     {
314         std::vector<glTFFile> vInputFiles;
315         glTFHandle* pHandle = parseJsonAndLoadInputFiles(vInputFiles);
316 
317         glm::vec3 vEye, vView, vUp;
318         gltf_get_camera_pos(pHandle, &vEye, &vView, &vUp);
319 
320         CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, vEye.x, 0.0001);
321         CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, vEye.y, 0.0001);
322         CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, vEye.z, 0.0001);
323 
324         CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, vView.x, 0.0001);
325         CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, vView.y, 0.0001);
326         CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, vView.z, 0.0001);
327 
328         CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, vUp.x, 0.0001);
329         CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, vUp.y, 0.0001);
330         CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, vUp.z, 0.0001);
331 
332         gltf_renderer_release(pHandle);
333         releaseInputFiles(vInputFiles);
334     }
335 
336     // 2) When one of the parameters is null pointer (crash test)
337     {
338         std::vector<glTFFile> vInputFiles;
339         glTFHandle* pHandle = parseJsonAndLoadInputFiles(vInputFiles);
340 
341         glm::vec3 vEye, vView, vUp;
342         gltf_get_camera_pos(pHandle, 0, &vView, &vUp);
343         gltf_get_camera_pos(pHandle, &vEye, 0, &vUp);
344         gltf_get_camera_pos(pHandle, &vEye, &vView, 0);
345 
346         gltf_renderer_release(pHandle);
347         releaseInputFiles(vInputFiles);
348     }
349 
350     // 3) Call with invalid handle
351     {
352         glm::vec3 vEye(1.0f), vView(1.0f), vUp(1.0f);
353         gltf_get_camera_pos(0, &vEye, &vView, &vUp);
354 
355         CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, vEye.x, 0.0001);
356         CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, vEye.y, 0.0001);
357         CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, vEye.z, 0.0001);
358 
359         CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, vView.x, 0.0001);
360         CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, vView.y, 0.0001);
361         CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, vView.z, 0.0001);
362 
363         CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, vUp.x, 0.0001);
364         CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, vUp.y, 0.0001);
365         CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, vUp.z, 0.0001);
366     }
367 
368     OpenGLContext aContext;
369     aContext.init();
370 
371     // 4) When everything is ok
372     {
373         glTFHandle* pHandle = initSceneAndSetContent();
374 
375         glm::vec3 vEye, vView, vUp;
376         gltf_get_camera_pos(pHandle, &vEye, &vView, &vUp);
377 
378         CPPUNIT_ASSERT_DOUBLES_EQUAL(400.1130371, vEye.x, 0.0001);
379         CPPUNIT_ASSERT_DOUBLES_EQUAL(463.2640075, vEye.y, 0.0001);
380         CPPUNIT_ASSERT_DOUBLES_EQUAL(-431.0780029, vEye.z, 0.0001);
381 
382         CPPUNIT_ASSERT_DOUBLES_EQUAL(399.5765686, vView.x, 0.0001);
383         CPPUNIT_ASSERT_DOUBLES_EQUAL(462.6428528, vView.y, 0.0001);
384         CPPUNIT_ASSERT_DOUBLES_EQUAL(-430.5067138, vView.z, 0.0001);
385 
386         CPPUNIT_ASSERT_DOUBLES_EQUAL(-0.4252052, vUp.x, 0.0001);
387         CPPUNIT_ASSERT_DOUBLES_EQUAL(0.7836933, vUp.y, 0.0001);
388         CPPUNIT_ASSERT_DOUBLES_EQUAL(0.4527971, vUp.z, 0.0001);
389         gltf_renderer_release(pHandle);
390     }
391 
392     // 5) Test whether moving camera in walkthrough mode has any effect on camera position
393     {
394         glTFHandle* pHandle = initSceneAndSetContent();
395 
396         // Get initial position
397         glm::vec3 vEye, vView, vUp;
398         gltf_get_camera_pos(pHandle, &vEye, &vView, &vUp);
399 
400         // Move camera
401         gltf_renderer_move_camera(pHandle, 2.0, 3.0, 0.0, 0.0);
402 
403         // Get changed position
404         glm::vec3 vEye2, vView2, vUp2;
405         gltf_get_camera_pos(pHandle, &vEye2, &vView2, &vUp2);
406 
407         // Affect on eye and view vector
408         CPPUNIT_ASSERT(std::abs(vEye.x - vEye2.x) > 0.01 ||
409                          std::abs(vEye.y - vEye2.y) > 0.01 ||
410                          std::abs(vEye.z - vEye2.z) > 0.01);
411 
412         CPPUNIT_ASSERT(std::abs(vView.x - vView2.x) > 0.01 ||
413                          std::abs(vView.y - vView2.y) > 0.01 ||
414                          std::abs(vView.z - vView2.z) > 0.01);
415 
416         // No affect on up vector
417         CPPUNIT_ASSERT_DOUBLES_EQUAL(vUp.x, vUp2.x, 0.0001);
418         CPPUNIT_ASSERT_DOUBLES_EQUAL(vUp.y, vUp2.y, 0.0001);
419         CPPUNIT_ASSERT_DOUBLES_EQUAL(vUp.z, vUp2.z, 0.0001);
420 
421         gltf_renderer_release(pHandle);
422     }
423 
424     // 6) Test whether rotating camera in walkthrough mode has any effect on camera position
425     {
426         glTFHandle* pHandle = initSceneAndSetContent();
427 
428         // a) horizontal rotation should affect view vector
429         // Get initial position
430         glm::vec3 vEye, vView, vUp;
431         gltf_get_camera_pos(pHandle, &vEye, &vView, &vUp);
432 
433         // Rotate camera
434         gltf_renderer_rotate_camera(pHandle, 3.0, 0.0, 0.0);
435 
436         // Get changed position
437         glm::vec3 vEye2, vView2, vUp2;
438         gltf_get_camera_pos(pHandle, &vEye2, &vView2, &vUp2);
439 
440         // Affect on view vector
441         CPPUNIT_ASSERT(std::abs(vView.x - vView2.x) > 0.001 ||
442                        std::abs(vView.y - vView2.y) > 0.001 ||
443                        std::abs(vView.z - vView2.z) > 0.001);
444 
445         // No affect on eye and up vector
446         CPPUNIT_ASSERT_DOUBLES_EQUAL(vEye.x, vEye2.x, 0.0001);
447         CPPUNIT_ASSERT_DOUBLES_EQUAL(vEye.y, vEye2.y, 0.0001);
448         CPPUNIT_ASSERT_DOUBLES_EQUAL(vEye.z, vEye2.z, 0.0001);
449 
450         CPPUNIT_ASSERT_DOUBLES_EQUAL(vUp.x, vUp2.x, 0.0001);
451         CPPUNIT_ASSERT_DOUBLES_EQUAL(vUp.y, vUp2.y, 0.0001);
452         CPPUNIT_ASSERT_DOUBLES_EQUAL(vUp.z, vUp2.z, 0.0001);
453 
454         // b) vertical rotation should affect both view and up vector
455         // Get initial position
456         gltf_get_camera_pos(pHandle, &vEye, &vView, &vUp);
457 
458         // Rotate camera
459         gltf_renderer_rotate_camera(pHandle, 0.0, 3.0, 0.0);
460 
461         // Get changed position
462         gltf_get_camera_pos(pHandle, &vEye2, &vView2, &vUp2);
463 
464         // Affect on view and up vector
465         CPPUNIT_ASSERT(std::abs(vView.x - vView2.x) > 0.001 ||
466                        std::abs(vView.y - vView2.y) > 0.001 ||
467                        std::abs(vView.z - vView2.z) > 0.001);
468 
469         CPPUNIT_ASSERT(std::abs(vUp.x - vUp2.x) < 0.01 ||
470                        std::abs(vUp.y - vUp2.y) < 0.01 ||
471                        std::abs(vUp.z - vUp2.z) < 0.01);
472 
473         // No affect on eye vector
474         // TODO: small changes in eye vector (be more precise)?
475         CPPUNIT_ASSERT_DOUBLES_EQUAL(vEye.x, vEye2.x, 0.0001);
476         CPPUNIT_ASSERT_DOUBLES_EQUAL(vEye.y, vEye2.y, 0.0001);
477         CPPUNIT_ASSERT_DOUBLES_EQUAL(vEye.z, vEye2.z, 0.0001);
478 
479         gltf_renderer_release(pHandle);
480     }
481 
482     // 7) Test whether rotating camera in orbit mode has any effect on camera position
483     {
484         glTFHandle* pHandle = initSceneAndSetContent();
485 
486         // a) horizontal rotation should affect eye vector
487         gltf_orbit_mode_start(pHandle);
488         glm::vec3 vEye, vView, vUp;
489         gltf_get_camera_pos(pHandle, &vEye, &vView, &vUp);
490 
491         gltf_renderer_rotate_model(pHandle, 2.0, 0.0, 0.0);
492 
493         glm::vec3 vEye2, vView2, vUp2;
494         gltf_get_camera_pos(pHandle, &vEye2, &vView2, &vUp2);
495 
496         // Affect on eye vector
497         CPPUNIT_ASSERT(std::abs(vEye.x - vEye2.x) > 0.01 ||
498                        std::abs(vEye.y - vEye2.y) > 0.01 ||
499                        std::abs(vEye.z - vEye2.z) > 0.01);
500 
501         // No affect on view and up vector
502         CPPUNIT_ASSERT_DOUBLES_EQUAL(vView.x, vView2.x, 0.0001);
503         CPPUNIT_ASSERT_DOUBLES_EQUAL(vView.y, vView2.y, 0.0001);
504         CPPUNIT_ASSERT_DOUBLES_EQUAL(vView.z, vView2.z, 0.0001);
505 
506         CPPUNIT_ASSERT_DOUBLES_EQUAL(vUp.x, vUp.x, 0.0001);
507         CPPUNIT_ASSERT_DOUBLES_EQUAL(vUp.y, vUp.y, 0.0001);
508         CPPUNIT_ASSERT_DOUBLES_EQUAL(vUp.z, vUp.z, 0.0001);
509 
510         // b) vertical rotation should affect up and eye vectors
511         gltf_get_camera_pos(pHandle, &vEye, &vView, &vUp);
512         gltf_orbit_mode_start(pHandle);
513 
514         gltf_renderer_rotate_model(pHandle, 0.0, 2.0, 0.0);
515 
516         gltf_get_camera_pos(pHandle, &vEye2, &vView2, &vUp2);
517 
518         // Affect on eye and up vector
519         CPPUNIT_ASSERT(std::abs(vEye.x - vEye2.x) > 0.01 ||
520                        std::abs(vEye.y - vEye2.y) > 0.01 ||
521                        std::abs(vEye.z - vEye2.z) > 0.01);
522 
523         CPPUNIT_ASSERT(std::abs(vUp.x - vUp2.x) > 0.001 ||
524                        std::abs(vUp.y - vUp2.y) > 0.001 ||
525                        std::abs(vUp.z - vUp2.z) > 0.001);
526 
527         // No affect on view vector
528         CPPUNIT_ASSERT_DOUBLES_EQUAL(vView.x, vView2.x, 0.0001);
529         CPPUNIT_ASSERT_DOUBLES_EQUAL(vView.y, vView2.y, 0.0001);
530         CPPUNIT_ASSERT_DOUBLES_EQUAL(vView.z, vView2.z, 0.0001);
531 
532         gltf_renderer_release(pHandle);
533     }
534 
535     // 8) Test whether moving camera in orbit mode has any effect on camera position
536     {
537         glTFHandle* pHandle = initSceneAndSetContent();
538 
539         gltf_orbit_mode_start(pHandle);
540         glm::vec3 vEye, vView, vUp;
541         gltf_get_camera_pos(pHandle, &vEye, &vView, &vUp);
542 
543         gltf_renderer_move_camera(pHandle, 2.0, 3.0, 0.0, 0.0);
544 
545         glm::vec3 vEye2, vView2, vUp2;
546         gltf_get_camera_pos(pHandle, &vEye2, &vView2, &vUp2);
547 
548         // Affect on eye vector
549         CPPUNIT_ASSERT(std::abs(vEye.x - vEye2.x) > 0.01 ||
550                        std::abs(vEye.y - vEye2.y) > 0.01 ||
551                        std::abs(vEye.z - vEye2.z) > 0.01);
552 
553         // No affect on view and up vector
554         CPPUNIT_ASSERT_DOUBLES_EQUAL(vView.x, vView2.x, 0.0001);
555         CPPUNIT_ASSERT_DOUBLES_EQUAL(vView.y, vView2.y, 0.0001);
556         CPPUNIT_ASSERT_DOUBLES_EQUAL(vView.z, vView2.z, 0.0001);
557 
558         CPPUNIT_ASSERT_DOUBLES_EQUAL(vUp.x, vUp.x, 0.0001);
559         CPPUNIT_ASSERT_DOUBLES_EQUAL(vUp.y, vUp.y, 0.0001);
560         CPPUNIT_ASSERT_DOUBLES_EQUAL(vUp.z, vUp.z, 0.0001);
561 
562         gltf_renderer_release(pHandle);
563     }
564 
565     // 9) Test whether camera position loaded from *.json file has any effect on the returned values
566     {
567         glTFHandle* pHandle = initSceneAndSetContent();
568 
569         // Get camera position in walkthrough mode
570         glm::vec3 vEye, vView, vUp;
571         gltf_get_camera_pos(pHandle, &vEye, &vView, &vUp);
572         gltf_orbit_mode_start(pHandle);
573 
574         // Compare it with the camera postion of the orbit mode (orbit mode ignores the default camera position)
575         // All the three vectors should change
576         glm::vec3 vEye2, vView2, vUp2;
577         gltf_get_camera_pos(pHandle, &vEye2, &vView2, &vUp2);
578 
579         CPPUNIT_ASSERT(std::abs(vEye.x - vEye2.x) > 0.01 ||
580                        std::abs(vEye.y - vEye2.y) > 0.01 ||
581                        std::abs(vEye.z - vEye2.z) > 0.01);
582 
583         CPPUNIT_ASSERT(std::abs(vView.x - vView2.x) > 0.01 ||
584                        std::abs(vView.y - vView2.y) > 0.01 ||
585                        std::abs(vView.z - vView2.z) > 0.01);
586 
587         CPPUNIT_ASSERT(std::abs(vUp.x - vUp2.x) > 0.01 ||
588                        std::abs(vUp.y - vUp2.y) > 0.01 ||
589                        std::abs(vUp.z - vUp2.z) > 0.01);
590 
591         gltf_renderer_release(pHandle);
592     }
593 }
594 
595 // IV) Testing gltf_get_model_center_pos() method
test_gltf_get_model_center_pos()596 void APITest::test_gltf_get_model_center_pos()
597 {
598     // 1) When gltf_renderer_set_content() was not called yet (initial value: 0,0,0)
599     {
600         std::vector<glTFFile> vInputFiles;
601         glTFHandle* pHandle = parseJsonAndLoadInputFiles(vInputFiles);
602 
603         glm::vec3* vCenterPos = gltf_get_model_center_pos(pHandle);
604 
605         CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, vCenterPos->x, 0.0001);
606         CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, vCenterPos->y, 0.0001);
607         CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, vCenterPos->z, 0.0001);
608 
609         gltf_renderer_release(pHandle);
610         releaseInputFiles(vInputFiles);
611     }
612 
613     // 2) Call with invalid handle
614     {
615         glm::vec3* vCenterPos = gltf_get_model_center_pos(0);
616 
617         CPPUNIT_ASSERT_EQUAL((glm::vec3*)(0), vCenterPos);
618     }
619 
620     OpenGLContext aContext;
621     aContext.init();
622 
623     // 3) Default view in walkthrough mode
624     {
625         glTFHandle* pHandle = initSceneAndSetContent();
626 
627         glm::vec3* vCenterPos = gltf_get_model_center_pos(pHandle);
628 
629         CPPUNIT_ASSERT_DOUBLES_EQUAL(13.4406967, vCenterPos->x, 0.0001);
630         CPPUNIT_ASSERT_DOUBLES_EQUAL(86.9496841, vCenterPos->y, 0.0001);
631         CPPUNIT_ASSERT_DOUBLES_EQUAL(-3.70149993, vCenterPos->z, 0.0001);
632 
633         gltf_renderer_release(pHandle);
634     }
635 
636     // 4) Test whether switching to orbit mode makes any difference
637     {
638         glTFHandle* pHandle = initSceneAndSetContent();
639 
640         gltf_orbit_mode_start(pHandle);
641 
642         glm::vec3* vCenterPos = gltf_get_model_center_pos(pHandle);
643 
644         CPPUNIT_ASSERT_DOUBLES_EQUAL(13.4406967, vCenterPos->x, 0.0001);
645         CPPUNIT_ASSERT_DOUBLES_EQUAL(86.9496841, vCenterPos->y, 0.0001);
646         CPPUNIT_ASSERT_DOUBLES_EQUAL(-3.70149993, vCenterPos->z, 0.0001);
647 
648         gltf_renderer_release(pHandle);
649     }
650 
651     // 5) Check whether camera look at the center position in orbit mode
652     {
653         glTFHandle* pHandle = initSceneAndSetContent();
654 
655         gltf_orbit_mode_start(pHandle);
656 
657         glm::vec3* vCenterPos = gltf_get_model_center_pos(pHandle);
658 
659         glm::vec3 vEye, vView, vUp;
660         gltf_get_camera_pos(pHandle, &vEye, &vView, &vUp);
661 
662         CPPUNIT_ASSERT_DOUBLES_EQUAL(vView.x, vCenterPos->x, 0.0001);
663         CPPUNIT_ASSERT_DOUBLES_EQUAL(vView.y, vCenterPos->y, 0.0001);
664         CPPUNIT_ASSERT_DOUBLES_EQUAL(vView.z, vCenterPos->z, 0.0001);
665 
666         gltf_renderer_release(pHandle);
667     }
668 
669     // 6) Change the position via the pointer and check whether it has effect
670     //    on the internal variables of the scene
671     {
672         glTFHandle* pHandle = initSceneAndSetContent();
673 
674         gltf_orbit_mode_start(pHandle);
675 
676         glm::vec3* vCenterPos = gltf_get_model_center_pos(pHandle);
677         vCenterPos->x = 6.0f;
678 
679         glm::vec3* vCenterPos2 = gltf_get_model_center_pos(pHandle);
680         CPPUNIT_ASSERT_DOUBLES_EQUAL(vCenterPos->x, vCenterPos2->x, 0.0001);
681         CPPUNIT_ASSERT_DOUBLES_EQUAL(vCenterPos->y, vCenterPos2->y, 0.0001);
682         CPPUNIT_ASSERT_DOUBLES_EQUAL(vCenterPos->z, vCenterPos2->z, 0.0001);
683 
684         glm::vec3 vEye, vView, vUp;
685         gltf_get_camera_pos(pHandle, &vEye, &vView, &vUp);
686 
687         CPPUNIT_ASSERT_DOUBLES_EQUAL(vCenterPos->x, vView.x, 0.0001);
688         CPPUNIT_ASSERT_DOUBLES_EQUAL(vCenterPos->y, vView.y, 0.0001);
689         CPPUNIT_ASSERT_DOUBLES_EQUAL(vCenterPos->z, vView.z, 0.0001);
690 
691         gltf_renderer_release(pHandle);
692     }
693 }
694 
695 // VI) Testing gltf_get_model_size() method
test_gltf_get_model_size()696 void APITest::test_gltf_get_model_size()
697 {
698     // 1) When gltf_renderer_set_content() was not called yet (initial value: 0.0)
699     {
700         std::vector<glTFFile> vInputFiles;
701         glTFHandle* pHandle = parseJsonAndLoadInputFiles(vInputFiles);
702 
703         double dSize = gltf_get_model_size(pHandle);
704 
705         CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, dSize, 0.0001);
706 
707         gltf_renderer_release(pHandle);
708         releaseInputFiles(vInputFiles);
709     }
710 
711     // 2) Call with invalid handle
712     {
713         double dSize = gltf_get_model_size(0);
714         CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, dSize, 0.0001);
715     }
716 
717     OpenGLContext aContext;
718     aContext.init();
719 
720     // 3) When everything is ok
721     {
722         glTFHandle* pHandle = initSceneAndSetContent();
723 
724         double dSize = gltf_get_model_size(0);
725 
726         CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, dSize, 0.0001);
727 
728         gltf_renderer_release(pHandle);
729     }
730 
731     // 4) Test whether view affect the size (view independent size)
732     {
733         glTFHandle* pHandle = initSceneAndSetContent();
734 
735         double dSize = gltf_get_model_size(0);
736 
737         gltf_orbit_mode_start(pHandle);
738 
739         double dSize2 = gltf_get_model_size(0);
740 
741         CPPUNIT_ASSERT_DOUBLES_EQUAL(dSize, dSize2, 0.0001);
742 
743         gltf_renderer_release(pHandle);
744     }
745 }
746 
747 // VI) Testing gltf_{enable\disable}_rotation() method
test_gltf_enable_disable_rotation()748 void APITest::test_gltf_enable_disable_rotation()
749 {
750     // 1) When gltf_renderer_set_content() was not called yet (crash test)
751     {
752         std::vector<glTFFile> vInputFiles;
753         glTFHandle* pHandle = parseJsonAndLoadInputFiles(vInputFiles);
754 
755         gltf_enable_rotation(pHandle);
756         gltf_disable_rotation(pHandle);
757 
758         gltf_renderer_release(pHandle);
759         releaseInputFiles(vInputFiles);
760     }
761 
762     OpenGLContext aContext;
763     aContext.init();
764 
765     // 2) By default camera rotation is enabled -> rotation works
766     {
767         glTFHandle* pHandle = initSceneAndSetContent();
768 
769         // Get initial position
770         glm::vec3 vEye, vView, vUp;
771         gltf_get_camera_pos(pHandle, &vEye, &vView, &vUp);
772 
773         // Rotate camera
774         gltf_renderer_rotate_camera(pHandle, 3.0, 0.0, 0.0);
775 
776         // Get changed position
777         glm::vec3 vEye2, vView2, vUp2;
778         gltf_get_camera_pos(pHandle, &vEye2, &vView2, &vUp2);
779 
780         // Rotation has affect on view vector
781         CPPUNIT_ASSERT(std::abs(vView.x - vView2.x) > 0.001 ||
782                        std::abs(vView.y - vView2.y) > 0.001 ||
783                        std::abs(vView.z - vView2.z) > 0.001);
784 
785         gltf_renderer_release(pHandle);
786     }
787 
788     // 3) disable rotation in walkthrough mode -> no rotation
789     {
790         glTFHandle* pHandle = initSceneAndSetContent();
791 
792         gltf_disable_rotation(pHandle);
793 
794         // Get initial position
795         glm::vec3 vEye, vView, vUp;
796         gltf_get_camera_pos(pHandle, &vEye, &vView, &vUp);
797 
798         // Rotate camera
799         gltf_renderer_rotate_camera(pHandle, 3.0, 0.0, 0.0);
800 
801         // Get changed position
802         glm::vec3 vEye2, vView2, vUp2;
803         gltf_get_camera_pos(pHandle, &vEye2, &vView2, &vUp2);
804 
805         // Rotation was not applied on the camera position
806         CPPUNIT_ASSERT_DOUBLES_EQUAL(vView.x, vView2.x, 0.0001);
807         CPPUNIT_ASSERT_DOUBLES_EQUAL(vView.y, vView2.y, 0.0001);
808         CPPUNIT_ASSERT_DOUBLES_EQUAL(vView.z, vView2.z, 0.0001);
809 
810         CPPUNIT_ASSERT_DOUBLES_EQUAL(vEye.x, vEye2.x, 0.0001);
811         CPPUNIT_ASSERT_DOUBLES_EQUAL(vEye.y, vEye2.y, 0.0001);
812         CPPUNIT_ASSERT_DOUBLES_EQUAL(vEye.z, vEye2.z, 0.0001);
813 
814         CPPUNIT_ASSERT_DOUBLES_EQUAL(vUp.x, vUp2.x, 0.0001);
815         CPPUNIT_ASSERT_DOUBLES_EQUAL(vUp.y, vUp2.y, 0.0001);
816         CPPUNIT_ASSERT_DOUBLES_EQUAL(vUp.z, vUp2.z, 0.0001);
817 
818         gltf_renderer_release(pHandle);
819     }
820 
821     // 4) disable and reenable rotation in walkthrough mode -> rotation applied on the position
822     {
823         glTFHandle* pHandle = initSceneAndSetContent();
824 
825         gltf_disable_rotation(pHandle);
826         gltf_enable_rotation(pHandle);
827 
828         // Get initial position
829         glm::vec3 vEye, vView, vUp;
830         gltf_get_camera_pos(pHandle, &vEye, &vView, &vUp);
831 
832         // Rotate camera
833         gltf_renderer_rotate_camera(pHandle, 3.0, 0.0, 0.0);
834 
835         // Get changed position
836         glm::vec3 vEye2, vView2, vUp2;
837         gltf_get_camera_pos(pHandle, &vEye2, &vView2, &vUp2);
838 
839         // Rotation has affect on view vector
840         CPPUNIT_ASSERT(std::abs(vView.x - vView2.x) > 0.001 ||
841                        std::abs(vView.y - vView2.y) > 0.001 ||
842                        std::abs(vView.z - vView2.z) > 0.001);
843 
844         gltf_renderer_release(pHandle);
845     }
846 
847     // 5) disable rotation in orbit mode -> no rotation
848     {
849         glTFHandle* pHandle = initSceneAndSetContent();
850 
851         gltf_disable_rotation(pHandle);
852 
853         gltf_orbit_mode_start(pHandle);
854         glm::vec3 vEye, vView, vUp;
855         gltf_get_camera_pos(pHandle, &vEye, &vView, &vUp);
856 
857         gltf_renderer_rotate_model(pHandle, 2.0, 0.0, 0.0);
858 
859         glm::vec3 vEye2, vView2, vUp2;
860         gltf_get_camera_pos(pHandle, &vEye2, &vView2, &vUp2);
861 
862         // Rotation was not applied on the camera position
863         CPPUNIT_ASSERT_DOUBLES_EQUAL(vEye.x, vEye2.x, 0.0001);
864         CPPUNIT_ASSERT_DOUBLES_EQUAL(vEye.y, vEye2.y, 0.0001);
865         CPPUNIT_ASSERT_DOUBLES_EQUAL(vEye.z, vEye2.z, 0.0001);
866 
867         CPPUNIT_ASSERT_DOUBLES_EQUAL(vView.x, vView2.x, 0.0001);
868         CPPUNIT_ASSERT_DOUBLES_EQUAL(vView.y, vView2.y, 0.0001);
869         CPPUNIT_ASSERT_DOUBLES_EQUAL(vView.z, vView2.z, 0.0001);
870 
871         CPPUNIT_ASSERT_DOUBLES_EQUAL(vUp.x, vUp.x, 0.0001);
872         CPPUNIT_ASSERT_DOUBLES_EQUAL(vUp.y, vUp.y, 0.0001);
873         CPPUNIT_ASSERT_DOUBLES_EQUAL(vUp.z, vUp.z, 0.0001);
874 
875         gltf_renderer_release(pHandle);
876     }
877 
878     // 6) disable and reenable rotation in orbit mode -> rotation applied on the position
879     {
880         glTFHandle* pHandle = initSceneAndSetContent();
881 
882         gltf_disable_rotation(pHandle);
883         gltf_enable_rotation(pHandle);
884 
885         gltf_orbit_mode_start(pHandle);
886         glm::vec3 vEye, vView, vUp;
887         gltf_get_camera_pos(pHandle, &vEye, &vView, &vUp);
888 
889         gltf_renderer_rotate_model(pHandle, 2.0, 0.0, 0.0);
890 
891         glm::vec3 vEye2, vView2, vUp2;
892         gltf_get_camera_pos(pHandle, &vEye2, &vView2, &vUp2);
893 
894         // Affect on eye vector
895         CPPUNIT_ASSERT(std::abs(vEye.x - vEye2.x) > 0.01 ||
896                        std::abs(vEye.y - vEye2.y) > 0.01 ||
897                        std::abs(vEye.z - vEye2.z) > 0.01);
898 
899         gltf_renderer_release(pHandle);
900     }
901 }
902 
parseJsonAndLoadInputFiles(std::vector<glTFFile> & vInputFiles,const std::string & sFilename)903 glTFHandle* APITest::parseJsonAndLoadInputFiles(std::vector<glTFFile>& vInputFiles, const std::string& sFilename)
904 {
905     glTFHandle* pHandle = gltf_renderer_init(sFilename.c_str(), vInputFiles);
906     CPPUNIT_ASSERT(pHandle);
907     CPPUNIT_ASSERT_EQUAL(size_t(4), vInputFiles.size());
908 
909     readInputFiles(vInputFiles, sFilename);
910 
911     return pHandle;
912 }
913 
initSceneAndSetContent(const std::string & sFilename)914 glTFHandle* APITest::initSceneAndSetContent(const std::string& sFilename)
915 {
916     std::vector<glTFFile> vInputFiles;
917     glTFHandle* pHandle = parseJsonAndLoadInputFiles(vInputFiles, sFilename);
918 
919     int nRet = gltf_renderer_set_content(pHandle, vInputFiles);
920     CPPUNIT_ASSERT_EQUAL(LIBGLTF_SUCCESS, nRet);
921     releaseInputFiles(vInputFiles);
922     return pHandle;
923 }
924 
readInputFiles(std::vector<glTFFile> & vInputFiles,const std::string & sJsonName)925 void APITest::readInputFiles(std::vector<glTFFile>& vInputFiles, const std::string& sJsonName)
926 {
927     for( size_t i = 0; i < vInputFiles.size(); ++i )
928     {
929         glTFFile& rFile = vInputFiles[i];
930         const std::string sFileName(sJsonName.substr(0,sJsonName.find_last_of('/')+1) + rFile.filename);
931         if( rFile.type == GLTF_IMAGE )
932         {
933             bool bRet = pnghelper::ReadPNGFromFile(sFileName, &rFile.buffer, rFile.imagewidth, rFile.imageheight );
934             rFile.size = 4 * rFile.imagewidth * rFile.imageheight;
935             CPPUNIT_ASSERT_EQUAL(true, bRet);
936         }
937         else
938         {
939             std::ifstream ifs(sFileName.c_str());
940             CPPUNIT_ASSERT_EQUAL(true, ifs.is_open());
941 
942             ifs.seekg (0, ifs.end);
943             rFile.size = ifs.tellg();
944             ifs.seekg (0, ifs.beg);
945             rFile.buffer = new char[rFile.size];
946             ifs.read (rFile.buffer,rFile.size);
947             ifs.close();
948         }
949     }
950 }
951 
releaseInputFiles(std::vector<glTFFile> & vInputFiles)952 void APITest::releaseInputFiles(std::vector<glTFFile>& vInputFiles)
953 {
954     for( size_t i = 0; i < vInputFiles.size(); ++i )
955     {
956         glTFFile& rFile = vInputFiles[i];
957         delete rFile.buffer;
958         rFile.buffer = 0;
959         rFile.size = 0;
960         rFile.imagewidth = 0;
961         rFile.imageheight = 0;
962     }
963     vInputFiles.clear();
964 }
965 
966 CPPUNIT_TEST_SUITE_REGISTRATION(APITest);
967 
968 } // test
969 } // libgltf
970 
971 
972 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
973