unit-MeshPrimitive2.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509
  1. #include <catch2/catch.hpp>
  2. #include <iostream>
  3. #include <gul/MeshPrimitive2.h>
  4. #include <glm/glm.hpp>
  5. #include <glm/gtc/vec1.hpp>
  6. SCENARIO("types")
  7. {
  8. REQUIRE( gul::type_to_component<glm::vec1>() == gul::eComponentType::FLOAT);
  9. REQUIRE( gul::type_to_component<float >() == gul::eComponentType::FLOAT);
  10. REQUIRE( gul::type_to_component<glm::mat2>() == gul::eComponentType::FLOAT);
  11. REQUIRE( gul::type_to_component<glm::vec4>() == gul::eComponentType::FLOAT);
  12. REQUIRE( gul::type_to_component<glm::mat4>() == gul::eComponentType::FLOAT);
  13. REQUIRE( gul::type_to_type<uint32_t>() == gul::eType::SCALAR);
  14. REQUIRE( gul::type_to_type<glm::vec1>() == gul::eType::SCALAR);
  15. REQUIRE( gul::type_to_type<glm::vec2>() == gul::eType::VEC2);
  16. REQUIRE( gul::type_to_type<glm::vec3>() == gul::eType::VEC3);
  17. REQUIRE( gul::type_to_type<glm::vec4>() == gul::eType::VEC4);
  18. REQUIRE( gul::type_to_type<glm::mat2>() == gul::eType::MAT2);
  19. REQUIRE( gul::type_to_type<glm::mat3>() == gul::eType::MAT3);
  20. REQUIRE( gul::type_to_type<glm::mat4>() == gul::eType::MAT4);
  21. }
  22. SCENARIO("Initialize attribute with vector")
  23. {
  24. GIVEN("A vertex attribute with items")
  25. {
  26. gul::VertexAttribute V = std::vector<glm::uvec2>( {{1,2}, {3,4}});
  27. REQUIRE( V.getComponentType() == gul::eComponentType::UNSIGNED_INT);
  28. REQUIRE( V.getType() == gul::eType::VEC2);
  29. REQUIRE( V.attributeCount() == 2);
  30. REQUIRE( V.size() == 4); // 4 total components
  31. auto readBack = V.toVector<glm::uvec2>();
  32. REQUIRE( readBack[0][0] == 1);
  33. REQUIRE( readBack[0][1] == 2);
  34. REQUIRE( readBack[1][0] == 3);
  35. REQUIRE( readBack[1][1] == 4);
  36. }
  37. }
  38. SCENARIO("changing types")
  39. {
  40. GIVEN("A vertex attribute with 3 items")
  41. {
  42. gul::VertexAttribute V = std::vector<glm::uvec2>( {{1,2}, {3,4}, {5,6}});
  43. REQUIRE( V.getComponentType() == gul::eComponentType::UNSIGNED_INT);
  44. REQUIRE( V.getType() == gul::eType::VEC2);
  45. REQUIRE( V.attributeCount() == 3);
  46. REQUIRE( V.size() == 6); // 4 total components
  47. WHEN("We change the type to a scalar")
  48. {
  49. V.setType( gul::eType::SCALAR);
  50. REQUIRE(V.attributeCount() == 6);
  51. REQUIRE(V.size() == 6);
  52. auto readBack = V.toVector<uint32_t>();
  53. REQUIRE(readBack.size() == V.attributeCount() );
  54. REQUIRE( readBack[0] == 1);
  55. REQUIRE( readBack[1] == 2);
  56. REQUIRE( readBack[2] == 3);
  57. REQUIRE( readBack[3] == 4);
  58. REQUIRE( readBack[4] == 5);
  59. REQUIRE( readBack[5] == 6);
  60. }
  61. WHEN("We change the type to a VEC3")
  62. {
  63. V.setType( gul::eType::VEC3);
  64. REQUIRE(V.attributeCount() == 2);
  65. REQUIRE(V.size() == 6);
  66. auto readBack = V.toVector<glm::uvec3>();
  67. REQUIRE(readBack.size() == V.attributeCount() );
  68. REQUIRE( readBack[0][0] == 1);
  69. REQUIRE( readBack[0][1] == 2);
  70. REQUIRE( readBack[0][2] == 3);
  71. REQUIRE( readBack[1][0] == 4);
  72. REQUIRE( readBack[1][1] == 5);
  73. REQUIRE( readBack[1][2] == 6);
  74. }
  75. WHEN("We change the type to a VEC4")
  76. {
  77. V.setType( gul::eType::VEC4);
  78. THEN("We have only 1 attribute, since 4 does not evenly divide 6")
  79. {
  80. // only 1 item is available
  81. REQUIRE(V.attributeCount() == 1);
  82. REQUIRE(V.size() == 4);
  83. auto readBack = V.toVector<glm::uvec4>();
  84. REQUIRE(readBack.size() == V.attributeCount() );
  85. REQUIRE( readBack[0][0] == 1);
  86. REQUIRE( readBack[0][1] == 2);
  87. REQUIRE( readBack[0][2] == 3);
  88. REQUIRE( readBack[0][3] == 4);
  89. }
  90. }
  91. WHEN("We change the type to a MAT2")
  92. {
  93. V.setType( gul::eType::MAT2);
  94. THEN("We have only 1 attribute, since 4 does not evenly divide 6")
  95. {
  96. // only 1 item is available
  97. REQUIRE(V.attributeCount() == 1);
  98. REQUIRE(V.size() == 4);
  99. auto readBack = V.toVector<glm::umat2x2>();
  100. REQUIRE(readBack.size() == V.attributeCount() );
  101. REQUIRE( readBack[0][0][0] == 1);
  102. REQUIRE( readBack[0][0][1] == 2);
  103. REQUIRE( readBack[0][1][0] == 3);
  104. REQUIRE( readBack[0][1][1] == 4);
  105. }
  106. }
  107. }
  108. }
  109. SCENARIO("strideCopyOffset")
  110. {
  111. GIVEN("A vertex attribute with 3 items")
  112. {
  113. gul::VertexAttribute V = std::vector<glm::uvec2>( {{1,2}, {3,4}, {5,6}});
  114. REQUIRE( V.getComponentType() == gul::eComponentType::UNSIGNED_INT);
  115. REQUIRE( V.getType() == gul::eType::VEC2);
  116. REQUIRE( V.attributeCount() == 3);
  117. REQUIRE( V.size() == 6); // 4 total components
  118. auto readBack = V.toVector<glm::uvec2>();
  119. WHEN("We do a strideCopy with a stride size of 2*sizeof( glm::vec2)")
  120. {
  121. std::vector<uint32_t> D = {0,0,0,0,0,0,0,0,0,0,0,0,0,0};
  122. V.strideCopyOffset(D.data(),
  123. 2*sizeof(glm::uvec2),
  124. 0, // copy data to
  125. 1, // start at the second index
  126. 10); // copy 10 attributes
  127. THEN("Every other value is copied")
  128. {
  129. REQUIRE( D[0] == 3);
  130. REQUIRE( D[1] == 4);
  131. REQUIRE( D[2] == 0); // skipped
  132. REQUIRE( D[3] == 0); // skipped
  133. REQUIRE( D[4] == 5);
  134. REQUIRE( D[5] == 6);
  135. REQUIRE( D[6] == 0); // not copied, overflow
  136. REQUIRE( D[7] == 0); // not copied, overflow
  137. REQUIRE( D[8] == 0); // not copied, overflow
  138. REQUIRE( D[9] == 0); // not copied, overflow
  139. }
  140. }
  141. }
  142. }
  143. SCENARIO("Accessing data")
  144. {
  145. GIVEN("A vertex attribute with items")
  146. {
  147. gul::VertexAttribute V = std::vector<glm::uvec2>( {{1,2}, {3,4}, {5,6}});
  148. WHEN("When we use get()")
  149. {
  150. REQUIRE(V.get<uint32_t>(0) == 1);
  151. REQUIRE(V.get<uint32_t>(1) == 2);
  152. REQUIRE(V.get<uint32_t>(2) == 3);
  153. REQUIRE(V.get<uint32_t>(3) == 4);
  154. REQUIRE(V.get<uint32_t>(4) == 5);
  155. REQUIRE(V.get<uint32_t>(5) == 6);
  156. }
  157. WHEN("When we use getAttributeAs()")
  158. {
  159. REQUIRE(V.getAttributeAs<uint32_t>(0) == 1); // reads V[0][0]
  160. REQUIRE(V.getAttributeAs<uint32_t>(1) == 3); // reads V[1][0]
  161. REQUIRE(V.getAttributeAs<uint32_t>(2) == 5); // reads V[2][0]
  162. }
  163. }
  164. }
  165. SCENARIO("Merging")
  166. {
  167. GIVEN("A vertex attribute with items")
  168. {
  169. gul::VertexAttribute V = std::vector<glm::uvec2>( {{1,2}, {3,4}, {5,6}});
  170. gul::VertexAttribute V2 = std::vector<glm::uvec2>( {{7,8}, {9,10}});
  171. auto byteOffset = V.merge(V2);
  172. REQUIRE( byteOffset == sizeof(glm::uvec2) * 3);
  173. REQUIRE( V.attributeCount() == 5);
  174. }
  175. }
  176. SCENARIO("Mesh::calculateInterleavedStride")
  177. {
  178. GIVEN("A 2 vertex attribute with items")
  179. {
  180. gul::VertexAttribute V1 = std::vector<glm::uvec2>( {{1,2}, {3,4}, {5,6}});
  181. gul::VertexAttribute V2 = std::vector<glm::ivec2>( {{-1,-2}, {-3,-4}, {-5,-6}});
  182. REQUIRE(16 == gul::calculateInterleavedStride({&V1, &V2}));
  183. }
  184. }
  185. SCENARIO("Mesh::calculateInterleavedBytes")
  186. {
  187. GIVEN("A 2 vertex attribute with items")
  188. {
  189. gul::VertexAttribute V1 = std::vector<glm::uvec2>( {{1,2}, {3,4}, {5,6}});
  190. gul::VertexAttribute V2 = std::vector<glm::ivec2>( {{-1,-2}, {-3,-4}, {-5,-6}});
  191. REQUIRE(48 == gul::calculateInterleavedBytes({&V1, &V2}));
  192. }
  193. }
  194. SCENARIO("Mesh::copyVertexAttributesInterleaved")
  195. {
  196. GIVEN("A 2 vertex attribute with items")
  197. {
  198. gul::VertexAttribute V1 = std::vector<glm::uvec2>( {{1,2}, {3,4}, {5,6}});
  199. gul::VertexAttribute V2 = std::vector<glm::ivec2>( {{-1,-2}, {-3,-4}, {-5,-6}});
  200. struct Vertex
  201. {
  202. glm::uvec2 a;
  203. glm::ivec2 b;
  204. };
  205. REQUIRE( offsetof(Vertex, a) == 0);
  206. REQUIRE( offsetof(Vertex, b) == sizeof(glm::uvec2));
  207. THEN("We can copy each attribute sequentually to a vertex vector")
  208. {
  209. std::vector<Vertex> raw;
  210. gul::MeshPrimitive::copyVertexAttributesInterleaved(raw, {&V1,&V2});
  211. REQUIRE( raw.size() == 3);
  212. WHEN("When we use get()")
  213. {
  214. REQUIRE(raw[0].a[0] == 1);
  215. REQUIRE(raw[0].a[1] == 2);
  216. REQUIRE(raw[1].a[0] == 3);
  217. REQUIRE(raw[1].a[1] == 4);
  218. REQUIRE(raw[2].a[0] == 5);
  219. REQUIRE(raw[2].a[1] == 6);
  220. REQUIRE(raw[0].b[0] == -1);
  221. REQUIRE(raw[0].b[1] == -2);
  222. REQUIRE(raw[1].b[0] == -3);
  223. REQUIRE(raw[1].b[1] == -4);
  224. REQUIRE(raw[2].b[0] == -5);
  225. REQUIRE(raw[2].b[1] == -6);
  226. }
  227. }
  228. }
  229. }
  230. SCENARIO("get minmax")
  231. {
  232. GIVEN("A vertex attribute with 3 items")
  233. {
  234. gul::VertexAttribute V = std::vector<glm::uvec2>( {{1,2}, {3,4}, {5,6}, {7,8} });
  235. WHEN("We change the type to a scalar")
  236. {
  237. V.setType( gul::eType::SCALAR);
  238. auto [_m, _M] = V.getMinMax<uint32_t>();
  239. REQUIRE( _m.size() == 1);
  240. REQUIRE( _M.size() == 1);
  241. REQUIRE( _m[0] == 1);
  242. REQUIRE( _M[0] == 8);
  243. }
  244. WHEN("We change the type to a vec2")
  245. {
  246. V.setType( gul::eType::VEC2);
  247. auto [_m, _M] = V.getMinMax<uint32_t>();
  248. REQUIRE( _m.size() == 2);
  249. REQUIRE( _M.size() == 2);
  250. REQUIRE( _m[0] == 1);
  251. REQUIRE( _m[1] == 2);
  252. REQUIRE( _M[0] == 7);
  253. REQUIRE( _M[1] == 8);
  254. }
  255. WHEN("We change the type to a vec4")
  256. {
  257. V.setType( gul::eType::VEC4);
  258. auto [_m, _M] = V.getMinMax<uint32_t>();
  259. REQUIRE( _m.size() == 4);
  260. REQUIRE( _M.size() == 4);
  261. REQUIRE( _m[0] == 1);
  262. REQUIRE( _m[1] == 2);
  263. REQUIRE( _m[2] == 3);
  264. REQUIRE( _m[3] == 4);
  265. REQUIRE( _M[0] == 5);
  266. REQUIRE( _M[1] == 6);
  267. REQUIRE( _M[2] == 7);
  268. REQUIRE( _M[3] == 8);
  269. }
  270. WHEN("We change the type to a mat4")
  271. {
  272. V.setType( gul::eType::MAT2);
  273. auto [_m, _M] = V.getMinMax<uint32_t>();
  274. REQUIRE( _m.size() == 4);
  275. REQUIRE( _M.size() == 4);
  276. REQUIRE( _m[0] == 1);
  277. REQUIRE( _m[1] == 2);
  278. REQUIRE( _m[2] == 3);
  279. REQUIRE( _m[3] == 4);
  280. REQUIRE( _M[0] == 5);
  281. REQUIRE( _M[1] == 6);
  282. REQUIRE( _M[2] == 7);
  283. REQUIRE( _M[3] == 8);
  284. }
  285. }
  286. GIVEN("A vertex attribute with 3 items")
  287. {
  288. gul::VertexAttribute V = std::vector<glm::vec2>( {{1,2}, {7,8}, {3,4}, {5,6} });
  289. WHEN("We change the type to a scalar")
  290. {
  291. auto [_m, _M] = V.getMinMax<float>();
  292. REQUIRE( _m[0] == Approx(1));
  293. REQUIRE( _m[1] == Approx(2));
  294. REQUIRE( _M[0] == Approx(7));
  295. REQUIRE( _M[1] == Approx(8));
  296. }
  297. }
  298. }
  299. SCENARIO("Mesh")
  300. {
  301. // box mesh has position, normals, texcoords0, index
  302. auto S = gul::Box(1,1,1);
  303. constexpr uint64_t vertexCount = 36;
  304. constexpr uint64_t indexCount = 36;
  305. constexpr uint64_t vertexSize = sizeof(glm::vec3) + sizeof(glm::vec3) + sizeof(glm::vec2);
  306. constexpr uint64_t vertexDeviceSize = vertexCount * vertexSize;
  307. constexpr uint64_t indexDeviceSize = indexCount * sizeof(uint32_t);
  308. constexpr uint64_t deviceSize = indexDeviceSize + vertexDeviceSize;
  309. REQUIRE(S.INDEX.attributeCount() == indexCount);
  310. REQUIRE(S.indexCount() == indexCount);
  311. REQUIRE( S.POSITION.attributeCount() == vertexCount);
  312. REQUIRE( S.NORMAL.attributeCount() == vertexCount);
  313. REQUIRE( S.TEXCOORD_0.attributeCount() == vertexCount);
  314. REQUIRE( S.calculateDeviceSize() == deviceSize);
  315. REQUIRE(S.getVertexByteSize() == vertexSize);
  316. REQUIRE( vertexDeviceSize == S.calculateInterleavedBufferSize() );
  317. THEN("We can copy the mesh vertices in interleaved format")
  318. {
  319. std::vector<uint8_t> raw;
  320. raw.resize(vertexDeviceSize);
  321. auto totalCopied = S.copyVertexAttributesInterleaved(raw.data(), 0);
  322. REQUIRE( totalCopied == vertexCount);
  323. }
  324. THEN("We can copy the mesh vertices in sequential format")
  325. {
  326. std::vector<uint8_t> raw;
  327. raw.resize( S.calculateDeviceSize() ); // need device size
  328. auto offsets = S.copyVertexAttributesSquential(raw.data());
  329. REQUIRE( offsets.size() == 9);
  330. REQUIRE( offsets[0] == 0); // positions at 0
  331. REQUIRE( offsets[1] == 36*12); // normal after position
  332. REQUIRE( offsets[2] == 0);
  333. REQUIRE( offsets[3] == 36*(12+12)); // texcoord after position/normal
  334. REQUIRE( offsets[4] == 0);
  335. REQUIRE( offsets[5] == 0);
  336. REQUIRE( offsets[6] == 0);
  337. REQUIRE( offsets[7] == 0);
  338. REQUIRE( offsets[8] == 36*(12+12+8)); // indices after position/normal/texcoord
  339. }
  340. }
  341. SCENARIO("Mesh Merge")
  342. {
  343. // box mesh has position, normals, texcoords0, index
  344. auto FirstMesh = gul::Box(1,1,1);
  345. auto S = gul::Sphere(1.0);
  346. // only a single primitive in the box mesh
  347. REQUIRE( FirstMesh.primitives.size() == 1 );
  348. REQUIRE(FirstMesh.primitives[0].indexCount == 36);
  349. REQUIRE(FirstMesh.primitives[0].vertexCount == 36);
  350. REQUIRE(FirstMesh.primitives[0].indexOffset == 0);
  351. REQUIRE(FirstMesh.primitives[0].vertexOffset == 0);
  352. WHEN("We merge the sphere into the box with renumbering the indices")
  353. {
  354. FirstMesh.merge(S, true);
  355. THEN("There are two primitives")
  356. {
  357. REQUIRE(FirstMesh.primitives.size() == 2);
  358. THEN("The index offset will be the number of indices in the first mesh. and the vertex offset is zero")
  359. {
  360. REQUIRE( static_cast<uint32_t>(FirstMesh.primitives[1].indexOffset) == FirstMesh.primitives[0].indexCount );
  361. REQUIRE( FirstMesh.primitives[1].vertexOffset == 0 );
  362. }
  363. THEN("Each index in the merged mesh is offset")
  364. {
  365. uint32_t indexOffset = FirstMesh.primitives[0].indexCount;
  366. for(uint32_t i=0; i < FirstMesh.primitives[1].indexCount; i++)
  367. {
  368. uint32_t j = i + static_cast<uint32_t>(FirstMesh.primitives[1].indexOffset);
  369. REQUIRE(FirstMesh.INDEX.get<uint32_t>(j) - indexOffset == S.INDEX.get<uint32_t>(i) );
  370. }
  371. }
  372. }
  373. }
  374. WHEN("We merge the sphere into the box without renumbering the indices")
  375. {
  376. FirstMesh.merge(S, false);
  377. THEN("There are two primitives")
  378. {
  379. REQUIRE(FirstMesh.primitives.size() == 2);
  380. }
  381. THEN("The index offset will be the number of indices in the first mesh. and the vertex offset is the number of vertices in the first mesh")
  382. {
  383. REQUIRE( static_cast<uint32_t>(FirstMesh.primitives[1].indexOffset) == FirstMesh.primitives[0].indexCount );
  384. REQUIRE( static_cast<uint32_t>(FirstMesh.primitives[1].vertexOffset) == FirstMesh.primitives[0].vertexCount );
  385. }
  386. THEN("Each index in the merged mesh is NOT offset")
  387. {
  388. for(uint32_t i=0; i < FirstMesh.primitives[1].indexCount; i++)
  389. {
  390. uint32_t j = i + static_cast<uint32_t>(FirstMesh.primitives[1].indexOffset);
  391. REQUIRE(S.INDEX.get<uint32_t>(i) == FirstMesh.INDEX.get<uint32_t>(j) );
  392. }
  393. }
  394. }
  395. }
  396. SCENARIO("Bounding Sphere")
  397. {
  398. // box mesh has position, normals, texcoords0, index
  399. auto B = gul::Box(1,1,1);
  400. auto S = gul::Sphere(1.0);
  401. auto br = B.calculateBoundingSphereRadius();
  402. auto sr = S.calculateBoundingSphereRadius();
  403. REQUIRE( sr > 0.99f );
  404. REQUIRE( sr < 1.09f );
  405. REQUIRE( br > 0.865f );
  406. REQUIRE( br < 0.867f ); // sqrt(1+1+1)
  407. {
  408. auto sr1 = S.calculateBoundingSphereRadius(S.primitives[0]);
  409. REQUIRE( sr1 > 0.99f );
  410. REQUIRE( sr1 < 1.09f );
  411. }
  412. {
  413. B.merge(S);
  414. auto sr1 = B.calculateBoundingSphereRadius(B.primitives[1]);
  415. REQUIRE( sr1 > 0.99f );
  416. REQUIRE( sr1 < 1.09f );
  417. }
  418. }