| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305 |
- #include "describe.h"
- #define PAR_SHAPES_IMPLEMENTATION
- #include "par_shapes.h"
- #include <fcntl.h>
- #include <unistd.h>
- #define STRINGIFY(A) #A
- int main()
- {
- describe("cylinders and spheres") {
- it("should fail when the number of stacks or slices is invalid") {
- par_shapes_mesh* bad1 = par_shapes_create_cylinder(1, 1);
- par_shapes_mesh* bad2 = par_shapes_create_cylinder(1, 3);
- par_shapes_mesh* good = par_shapes_create_cylinder(3, 1);
- assert_null(bad1);
- assert_null(bad2);
- assert_ok(good);
- par_shapes_free_mesh(good);
- }
- it("should generate correct number of vertices") {
- par_shapes_mesh* m = par_shapes_create_cylinder(5, 6);
- assert_equal(m->npoints, 42);
- par_shapes_free_mesh(m);
- }
- it("should have expected number of triangles") {
- par_shapes_mesh* m;
- int slices, stacks ;
- slices = 5; stacks = 6;
- m = par_shapes_create_cylinder(slices, stacks);
- assert_equal(m->ntriangles, slices * stacks * 2);
- par_shapes_free_mesh(m);
- slices = 5; stacks = 6;
- m = par_shapes_create_parametric_sphere(slices, stacks);
- assert_equal(m->ntriangles, slices * 2 + (stacks - 2) * slices * 2);
- par_shapes_free_mesh(m);
- slices = 12; stacks = 13;
- m = par_shapes_create_parametric_sphere(slices, stacks);
- assert_equal(m->ntriangles, slices * 2 + (stacks - 2) * slices * 2);
- par_shapes_free_mesh(m);
- slices = 16; stacks = 16;
- m = par_shapes_create_parametric_sphere(slices, stacks);
- assert_equal(m->ntriangles, slices * 2 + (stacks - 2) * slices * 2);
- par_shapes_free_mesh(m);
- }
- }
- describe("par_shapes_create_plane") {
- it("should not have NaN's") {
- par_shapes_mesh* m = par_shapes_create_plane(5, 6);
- for (int i = 0; i < m->npoints * 3; i++) {
- assert_ok(m->points[i] == m->points[i]);
- assert_ok(m->normals[i] == m->normals[i]);
- }
- par_shapes_free_mesh(m);
- }
- }
- describe("par_shapes_export") {
- it("should generate an OBJ file") {
- par_shapes_mesh* m;
- m = par_shapes_create_torus(7, 10, 0.5);
- par_shapes_export(m, "build/test_shapes_torus.obj");
- par_shapes_free_mesh(m);
- m = par_shapes_create_subdivided_sphere(2);
- par_shapes_export(m, "build/test_shapes_ssphere.obj");
- par_shapes_free_mesh(m);
- m = par_shapes_create_klein_bottle(10, 20);
- par_shapes_export(m, "build/test_shapes_klein.obj");
- par_shapes_free_mesh(m);
- m = par_shapes_create_trefoil_knot(20, 100, 0.5);
- par_shapes_export(m, "build/test_shapes_trefoil.obj");
- par_shapes_free_mesh(m);
- m = par_shapes_create_hemisphere(5, 6);
- par_shapes_export(m, "build/test_shapes_hemisphere.obj");
- par_shapes_free_mesh(m);
- m = par_shapes_create_icosahedron();
- par_shapes_export(m, "build/test_shapes_icosahedron.obj");
- par_shapes_free_mesh(m);
- m = par_shapes_create_dodecahedron();
- par_shapes_export(m, "build/test_shapes_dodecahedron.obj");
- par_shapes_free_mesh(m);
- m = par_shapes_create_octahedron();
- par_shapes_export(m, "build/test_shapes_octahedron.obj");
- par_shapes_free_mesh(m);
- m = par_shapes_create_tetrahedron();
- par_shapes_export(m, "build/test_shapes_tetrahedron.obj");
- par_shapes_free_mesh(m);
- m = par_shapes_create_cube();
- par_shapes_export(m, "build/test_shapes_cube.obj");
- par_shapes_free_mesh(m);
- m = par_shapes_create_rock(1, 3);
- par_shapes_export(m, "build/test_shapes_rock.obj");
- par_shapes_free_mesh(m);
- m = par_shapes_create_cone(15, 3);
- par_shapes_export(m, "build/test_shapes_cone.obj");
- par_shapes_free_mesh(m);
- m = par_shapes_create_parametric_disk(15, 3);
- par_shapes_export(m, "build/test_shapes_parametric_disk.obj");
- par_shapes_free_mesh(m);
- float center[3] = {0, 0, 0};
- float normal[3] = {0, 0, 1};
- m = par_shapes_create_disk(1, 5, center, normal);
- par_shapes_export(m, "build/test_shapes_disk.obj");
- par_shapes_free_mesh(m);
- }
- }
- describe("par_shapes_merge") {
- it("should concatenate two meshes") {
- par_shapes_mesh* a, *b;
- a = par_shapes_create_klein_bottle(10, 20);
- int npts = a->npoints;
- int ntris = a->ntriangles;
- b = par_shapes_create_plane(3, 3);
- par_shapes_merge(a, b);
- assert_equal(a->npoints, npts + b->npoints);
- assert_equal(a->ntriangles, ntris + b->ntriangles);
- par_shapes_free_mesh(a);
- par_shapes_free_mesh(b);
- }
- }
- describe("transforms") {
- it("should support translation") {
- par_shapes_mesh* a, *b;
- a = par_shapes_create_cylinder(20, 3);
- b = par_shapes_create_cylinder(4, 3);
- par_shapes_translate(a, 0.5, 0.5, 0.25);
- par_shapes_merge(a, b);
- par_shapes_free_mesh(a);
- par_shapes_free_mesh(b);
- }
- it("should support rotation") {
- par_shapes_mesh* a, *b;
- a = par_shapes_create_cylinder(20, 3);
- b = par_shapes_create_cylinder(4, 3);
- float axis1[3] = {0, 1, 0};
- float axis2[3] = {0, 0, 1};
- par_shapes_rotate(a, PAR_PI * 0.5, axis1);
- par_shapes_rotate(a, PAR_PI * 0.25, axis2);
- par_shapes_merge(a, b);
- par_shapes_free_mesh(a);
- par_shapes_free_mesh(b);
- }
- it("should support non-uniform scale") {
- par_shapes_mesh* a;
- a = par_shapes_create_cylinder(15, 3);
- par_shapes_scale(a, 1, 1, 5);
- par_shapes_free_mesh(a);
- }
- it("should support degenerate scale") {
- par_shapes_mesh* a;
- a = par_shapes_create_cone(15, 3);
- assert_ok(a);
- par_shapes_scale(a, 1, 1, 0);
- for (int i = 0; i < a->npoints * 3; i++) {
- // should not have nans
- assert_ok(a->points[i] == a->points[i]);
- assert_ok(a->normals[i] == a->normals[i]);
- // check components
- if (i % 3 != 2) {
- assert_ok(a->normals[i] == 0.0f);
- } else {
- assert_ok(a->normals[i] == 1.0f);
- assert_ok(a->points[i] == 0.0f);
- }
- }
- par_shapes_free_mesh(a);
- }
- }
- describe("misc shapes") {
- it("create an orientable disk in 3-space") {
- int slices = 32;
- float aradius = 1;
- float anormal[3] = {0, 0, 1};
- float acenter[3] = {0, 0, 0};
- par_shapes_mesh* a, *b;
- a = par_shapes_create_disk(aradius, slices, acenter, anormal);
- float bradius = 0.2;
- float bcenter[3] = {0, 0, 0.2};
- float bnormal[3] = {0, 1, 0};
- b = par_shapes_create_disk(bradius, slices, bcenter, bnormal);
- par_shapes_merge(a, b);
- par_shapes_free_mesh(a);
- par_shapes_free_mesh(b);
- }
- it("create a rock on the Y plane") {
- int slices = 32;
- float radius = 2;
- float normal[3] = {0, 1, 0};
- float center[3] = {0, 0, 0};
- par_shapes_mesh* a, *b;
- a = par_shapes_create_disk(radius, slices, center, normal);
- b = par_shapes_create_rock(1, 2);
- float aabb[6];
- par_shapes_compute_aabb(b, aabb);
- par_shapes_translate(b, 0, -aabb[1] / 2, 0);
- par_shapes_merge(a, b);
- par_shapes_free_mesh(a);
- par_shapes_free_mesh(b);
- }
- it("create a polyhedron on the Y plane") {
- int slices = 32;
- float radius = 2;
- float normal[3] = {0, 1, 0};
- float center[3] = {0, 0, 0};
- par_shapes_mesh* a, *b;
- a = par_shapes_create_disk(radius, slices, center, normal);
- b = par_shapes_create_dodecahedron();
- par_shapes_translate(b, 0, 0.934, 0);
- par_shapes_merge(a, b);
- par_shapes_free_mesh(a);
- par_shapes_free_mesh(b);
- }
- it("create a rounded cylinder via composition") {
- const float O[3] = {0, 0, 0};
- const float I[3] = {1, 0, 0};
- const float J[3] = {0, 1, 0};
- const float K[3] = {0, 0, 1};
- const float top_center[3] = {0, 1.2, 0};
- const int tess = 30;
- par_shapes_mesh *a, *b, *c, *d;
- a = par_shapes_create_disk(2.5, tess, O, J);
- b = par_shapes_create_cylinder(tess, 3);
- c = par_shapes_create_torus(15, tess, 0.1);
- d = par_shapes_create_disk(1, tess, top_center, J);
- par_shapes_rotate(c, PAR_PI / tess, K);
- par_shapes_translate(c, 0, 0, 1);
- par_shapes_scale(b, 1.2, 1.2, 1);
- par_shapes_merge(b, c);
- par_shapes_rotate(b, -PAR_PI * 0.5, I);
- par_shapes_merge(b, d);
- par_shapes_merge(b, a);
- par_shapes_scale(b, 1, 2, 1);
- par_shapes_free_mesh(a);
- par_shapes_free_mesh(b);
- par_shapes_free_mesh(c);
- par_shapes_free_mesh(d);
- }
- }
- describe("lsystems") {
- it("export a tree-like shape") {
- char const* program = STRINGIFY(
- sx 2 sy 2
- ry 90 rx 90
- shape tube rx 15 call rlimb rx -15
- shape tube rx -15 call llimb rx 15
- shape tube ry 15 call rlimb ry -15
- shape tube ry 15 call llimb ry -15
- rule rlimb
- sx 0.925 sy 0.925 tz 1 rx 1.2
- call rlimb2
- rule rlimb2.1
- shape connect
- call rlimb
- rule rlimb2.1
- rx 15 shape tube call rlimb rx -15
- rx -15 shape tube call llimb rx 15
- rule rlimb.1
- call llimb
- rule llimb.1
- call rlimb
- rule llimb.10
- sx 0.925 sy 0.925
- tz 1
- rx -1.2
- shape connect
- call llimb
- );
- const float O[3] = {0, 0, 0};
- const float J[3] = {0, 1, 0};
- par_shapes_mesh* mesh = par_shapes_create_lsystem(program, 5, 60);
- par_shapes_mesh* disk = par_shapes_create_disk(10, 30, O, J);
- par_shapes_merge(mesh, disk);
- par_shapes_export(mesh, "build/lsystem.obj");
- par_shapes_free_mesh(mesh);
- }
- }
- return assert_failures();
- }
|