test_shapes.c 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. #include "describe.h"
  2. #define PAR_SHAPES_IMPLEMENTATION
  3. #include "par_shapes.h"
  4. #include <fcntl.h>
  5. #include <unistd.h>
  6. #define STRINGIFY(A) #A
  7. int main()
  8. {
  9. describe("cylinders and spheres") {
  10. it("should fail when the number of stacks or slices is invalid") {
  11. par_shapes_mesh* bad1 = par_shapes_create_cylinder(1, 1);
  12. par_shapes_mesh* bad2 = par_shapes_create_cylinder(1, 3);
  13. par_shapes_mesh* good = par_shapes_create_cylinder(3, 1);
  14. assert_null(bad1);
  15. assert_null(bad2);
  16. assert_ok(good);
  17. par_shapes_free_mesh(good);
  18. }
  19. it("should generate correct number of vertices") {
  20. par_shapes_mesh* m = par_shapes_create_cylinder(5, 6);
  21. assert_equal(m->npoints, 42);
  22. par_shapes_free_mesh(m);
  23. }
  24. it("should have expected number of triangles") {
  25. par_shapes_mesh* m;
  26. int slices, stacks ;
  27. slices = 5; stacks = 6;
  28. m = par_shapes_create_cylinder(slices, stacks);
  29. assert_equal(m->ntriangles, slices * stacks * 2);
  30. par_shapes_free_mesh(m);
  31. slices = 5; stacks = 6;
  32. m = par_shapes_create_parametric_sphere(slices, stacks);
  33. assert_equal(m->ntriangles, slices * 2 + (stacks - 2) * slices * 2);
  34. par_shapes_free_mesh(m);
  35. slices = 12; stacks = 13;
  36. m = par_shapes_create_parametric_sphere(slices, stacks);
  37. assert_equal(m->ntriangles, slices * 2 + (stacks - 2) * slices * 2);
  38. par_shapes_free_mesh(m);
  39. slices = 16; stacks = 16;
  40. m = par_shapes_create_parametric_sphere(slices, stacks);
  41. assert_equal(m->ntriangles, slices * 2 + (stacks - 2) * slices * 2);
  42. par_shapes_free_mesh(m);
  43. }
  44. }
  45. describe("par_shapes_create_plane") {
  46. it("should not have NaN's") {
  47. par_shapes_mesh* m = par_shapes_create_plane(5, 6);
  48. for (int i = 0; i < m->npoints * 3; i++) {
  49. assert_ok(m->points[i] == m->points[i]);
  50. assert_ok(m->normals[i] == m->normals[i]);
  51. }
  52. par_shapes_free_mesh(m);
  53. }
  54. }
  55. describe("par_shapes_export") {
  56. it("should generate an OBJ file") {
  57. par_shapes_mesh* m;
  58. m = par_shapes_create_torus(7, 10, 0.5);
  59. par_shapes_export(m, "build/test_shapes_torus.obj");
  60. par_shapes_free_mesh(m);
  61. m = par_shapes_create_subdivided_sphere(2);
  62. par_shapes_export(m, "build/test_shapes_ssphere.obj");
  63. par_shapes_free_mesh(m);
  64. m = par_shapes_create_klein_bottle(10, 20);
  65. par_shapes_export(m, "build/test_shapes_klein.obj");
  66. par_shapes_free_mesh(m);
  67. m = par_shapes_create_trefoil_knot(20, 100, 0.5);
  68. par_shapes_export(m, "build/test_shapes_trefoil.obj");
  69. par_shapes_free_mesh(m);
  70. m = par_shapes_create_hemisphere(5, 6);
  71. par_shapes_export(m, "build/test_shapes_hemisphere.obj");
  72. par_shapes_free_mesh(m);
  73. m = par_shapes_create_icosahedron();
  74. par_shapes_export(m, "build/test_shapes_icosahedron.obj");
  75. par_shapes_free_mesh(m);
  76. m = par_shapes_create_dodecahedron();
  77. par_shapes_export(m, "build/test_shapes_dodecahedron.obj");
  78. par_shapes_free_mesh(m);
  79. m = par_shapes_create_octahedron();
  80. par_shapes_export(m, "build/test_shapes_octahedron.obj");
  81. par_shapes_free_mesh(m);
  82. m = par_shapes_create_tetrahedron();
  83. par_shapes_export(m, "build/test_shapes_tetrahedron.obj");
  84. par_shapes_free_mesh(m);
  85. m = par_shapes_create_cube();
  86. par_shapes_export(m, "build/test_shapes_cube.obj");
  87. par_shapes_free_mesh(m);
  88. m = par_shapes_create_rock(1, 3);
  89. par_shapes_export(m, "build/test_shapes_rock.obj");
  90. par_shapes_free_mesh(m);
  91. float center[3] = {0, 0, 0};
  92. float normal[3] = {0, 0, 1};
  93. m = par_shapes_create_disk(1, 5, center, normal);
  94. par_shapes_export(m, "build/test_shapes_disk.obj");
  95. par_shapes_free_mesh(m);
  96. }
  97. }
  98. describe("par_shapes_merge") {
  99. it("should concatenate two meshes") {
  100. par_shapes_mesh* a, *b;
  101. a = par_shapes_create_klein_bottle(10, 20);
  102. int npts = a->npoints;
  103. int ntris = a->ntriangles;
  104. b = par_shapes_create_plane(3, 3);
  105. par_shapes_merge(a, b);
  106. assert_equal(a->npoints, npts + b->npoints);
  107. assert_equal(a->ntriangles, ntris + b->ntriangles);
  108. par_shapes_free_mesh(a);
  109. par_shapes_free_mesh(b);
  110. }
  111. }
  112. describe("transforms") {
  113. it("should support translation") {
  114. par_shapes_mesh* a, *b;
  115. a = par_shapes_create_cylinder(20, 3);
  116. b = par_shapes_create_cylinder(4, 3);
  117. par_shapes_translate(a, 0.5, 0.5, 0.25);
  118. par_shapes_merge(a, b);
  119. par_shapes_free_mesh(a);
  120. par_shapes_free_mesh(b);
  121. }
  122. it("should support rotation") {
  123. par_shapes_mesh* a, *b;
  124. a = par_shapes_create_cylinder(20, 3);
  125. b = par_shapes_create_cylinder(4, 3);
  126. float axis1[3] = {0, 1, 0};
  127. float axis2[3] = {0, 0, 1};
  128. par_shapes_rotate(a, PAR_PI * 0.5, axis1);
  129. par_shapes_rotate(a, PAR_PI * 0.25, axis2);
  130. par_shapes_merge(a, b);
  131. par_shapes_free_mesh(a);
  132. par_shapes_free_mesh(b);
  133. }
  134. it("should support non-uniform scale") {
  135. par_shapes_mesh* a;
  136. a = par_shapes_create_cylinder(15, 3);
  137. par_shapes_scale(a, 1, 1, 5);
  138. par_shapes_free_mesh(a);
  139. }
  140. }
  141. describe("misc shapes") {
  142. it("create an orientable disk in 3-space") {
  143. int slices = 32;
  144. float aradius = 1;
  145. float anormal[3] = {0, 0, 1};
  146. float acenter[3] = {0, 0, 0};
  147. par_shapes_mesh* a, *b;
  148. a = par_shapes_create_disk(aradius, slices, acenter, anormal);
  149. float bradius = 0.2;
  150. float bcenter[3] = {0, 0, 0.2};
  151. float bnormal[3] = {0, 1, 0};
  152. b = par_shapes_create_disk(bradius, slices, bcenter, bnormal);
  153. par_shapes_merge(a, b);
  154. par_shapes_free_mesh(a);
  155. par_shapes_free_mesh(b);
  156. }
  157. it("create a rock on the Y plane") {
  158. int slices = 32;
  159. float radius = 2;
  160. float normal[3] = {0, 1, 0};
  161. float center[3] = {0, 0, 0};
  162. par_shapes_mesh* a, *b;
  163. a = par_shapes_create_disk(radius, slices, center, normal);
  164. b = par_shapes_create_rock(1, 2);
  165. float aabb[6];
  166. par_shapes_compute_aabb(b, aabb);
  167. par_shapes_translate(b, 0, -aabb[1] / 2, 0);
  168. par_shapes_merge(a, b);
  169. par_shapes_free_mesh(a);
  170. par_shapes_free_mesh(b);
  171. }
  172. it("create a polyhedron on the Y plane") {
  173. int slices = 32;
  174. float radius = 2;
  175. float normal[3] = {0, 1, 0};
  176. float center[3] = {0, 0, 0};
  177. par_shapes_mesh* a, *b;
  178. a = par_shapes_create_disk(radius, slices, center, normal);
  179. b = par_shapes_create_dodecahedron();
  180. par_shapes_translate(b, 0, 0.934, 0);
  181. par_shapes_merge(a, b);
  182. par_shapes_free_mesh(a);
  183. par_shapes_free_mesh(b);
  184. }
  185. it("create a rounded cylinder via composition") {
  186. const float O[3] = {0, 0, 0};
  187. const float I[3] = {1, 0, 0};
  188. const float J[3] = {0, 1, 0};
  189. const float K[3] = {0, 0, 1};
  190. const float top_center[3] = {0, 1.2, 0};
  191. const int tess = 30;
  192. par_shapes_mesh *a, *b, *c, *d;
  193. a = par_shapes_create_disk(2.5, tess, O, J);
  194. b = par_shapes_create_cylinder(tess, 3);
  195. c = par_shapes_create_torus(15, tess, 0.1);
  196. d = par_shapes_create_disk(1, tess, top_center, J);
  197. par_shapes_rotate(c, PAR_PI / tess, K);
  198. par_shapes_translate(c, 0, 0, 1);
  199. par_shapes_scale(b, 1.2, 1.2, 1);
  200. par_shapes_merge(b, c);
  201. par_shapes_rotate(b, -PAR_PI * 0.5, I);
  202. par_shapes_merge(b, d);
  203. par_shapes_merge(b, a);
  204. par_shapes_scale(b, 1, 2, 1);
  205. par_shapes_free_mesh(a);
  206. par_shapes_free_mesh(b);
  207. par_shapes_free_mesh(c);
  208. par_shapes_free_mesh(d);
  209. }
  210. }
  211. describe("lsystems") {
  212. it("export a tree-like shape") {
  213. char const* program = STRINGIFY(
  214. sx 2 sy 2
  215. ry 90 rx 90
  216. shape tube rx 15 call rlimb rx -15
  217. shape tube rx -15 call llimb rx 15
  218. shape tube ry 15 call rlimb ry -15
  219. shape tube ry 15 call llimb ry -15
  220. rule rlimb
  221. sx 0.925 sy 0.925 tz 1 rx 1.2
  222. call rlimb2
  223. rule rlimb2.1
  224. shape connect
  225. call rlimb
  226. rule rlimb2.1
  227. rx 15 shape tube call rlimb rx -15
  228. rx -15 shape tube call llimb rx 15
  229. rule rlimb.1
  230. call llimb
  231. rule llimb.1
  232. call rlimb
  233. rule llimb.10
  234. sx 0.925 sy 0.925
  235. tz 1
  236. rx -1.2
  237. shape connect
  238. call llimb
  239. );
  240. const float O[3] = {0, 0, 0};
  241. const float J[3] = {0, 1, 0};
  242. par_shapes_mesh* mesh = par_shapes_create_lsystem(program, 5, 60);
  243. par_shapes_mesh* disk = par_shapes_create_disk(10, 30, O, J);
  244. par_shapes_merge(mesh, disk);
  245. par_shapes_export(mesh, "build/lsystem.obj");
  246. par_shapes_free_mesh(mesh);
  247. }
  248. }
  249. return assert_failures();
  250. }