summaryrefslogtreecommitdiffstats
path: root/libdimension/teapot.c
diff options
context:
space:
mode:
Diffstat (limited to 'libdimension/teapot.c')
-rw-r--r--libdimension/teapot.c455
1 files changed, 455 insertions, 0 deletions
diff --git a/libdimension/teapot.c b/libdimension/teapot.c
new file mode 100644
index 0000000..32c8a16
--- /dev/null
+++ b/libdimension/teapot.c
@@ -0,0 +1,455 @@
+/*************************************************************************
+ * Copyright (C) 2011 Tavian Barnes <tavianator@tavianator.com> *
+ * *
+ * This file is part of The Dimension Library. *
+ * *
+ * The Dimension Library is free software; you can redistribute it and/ *
+ * or modify it under the terms of the GNU Lesser General Public License *
+ * as published by the Free Software Foundation; either version 3 of the *
+ * License, or (at your option) any later version. *
+ * *
+ * The Dimension Library is distributed in the hope that it will be *
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty *
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
+ * Lesser General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Lesser General Public *
+ * License along with this program. If not, see *
+ * <http://www.gnu.org/licenses/>. *
+ *************************************************************************/
+
+/**
+ * @file
+ * Teapots.
+ */
+
+#include "dimension-internal.h"
+
+static const dmnsn_vector dmnsn_teapot_verticies[127] = {
+ { .x = +0.20000, .y = +1.12500, .z = +0.00000 },
+ { .x = +0.20000, .y = +1.12500, .z = -0.11200 },
+ { .x = +0.11200, .y = +1.12500, .z = -0.20000 },
+ { .x = +0.00000, .y = +1.12500, .z = -0.20000 },
+ { .x = +1.33750, .y = +0.95625, .z = +0.00000 },
+ { .x = +1.33750, .y = +0.95625, .z = -0.74900 },
+ { .x = +0.74900, .y = +0.95625, .z = -1.33750 },
+ { .x = +0.00000, .y = +0.95625, .z = -1.33750 },
+ { .x = +1.43750, .y = +0.95625, .z = +0.00000 },
+ { .x = +1.43750, .y = +0.95625, .z = -0.80500 },
+ { .x = +0.80500, .y = +0.95625, .z = -1.43750 },
+ { .x = +0.00000, .y = +0.95625, .z = -1.43750 },
+ { .x = +1.50000, .y = +0.82500, .z = +0.00000 },
+ { .x = +1.50000, .y = +0.82500, .z = -0.84000 },
+ { .x = +0.84000, .y = +0.82500, .z = -1.50000 },
+ { .x = +0.00000, .y = +0.82500, .z = -1.50000 },
+ { .x = +1.75000, .y = +0.30000, .z = +0.00000 },
+ { .x = +1.75000, .y = +0.30000, .z = -0.98000 },
+ { .x = +0.98000, .y = +0.30000, .z = -1.75000 },
+ { .x = +0.00000, .y = +0.30000, .z = -1.75000 },
+ { .x = +2.00000, .y = -0.22500, .z = +0.00000 },
+ { .x = +2.00000, .y = -0.22500, .z = -1.12000 },
+ { .x = +1.12000, .y = -0.22500, .z = -2.00000 },
+ { .x = +0.00000, .y = -0.22500, .z = -2.00000 },
+ { .x = +2.00000, .y = -0.67500, .z = +0.00000 },
+ { .x = +2.00000, .y = -0.67500, .z = -1.12000 },
+ { .x = +1.12000, .y = -0.67500, .z = -2.00000 },
+ { .x = +0.00000, .y = -0.67500, .z = -2.00000 },
+ { .x = -2.00000, .y = -0.67500, .z = +0.00000 },
+ { .x = +2.00000, .y = -1.12500, .z = +0.00000 },
+ { .x = +2.00000, .y = -1.12500, .z = -1.12000 },
+ { .x = +1.12000, .y = -1.12500, .z = -2.00000 },
+ { .x = +0.00000, .y = -1.12500, .z = -2.00000 },
+ { .x = +1.50000, .y = -1.35000, .z = +0.00000 },
+ { .x = +1.50000, .y = -1.35000, .z = -0.84000 },
+ { .x = +0.84000, .y = -1.35000, .z = -1.50000 },
+ { .x = +0.00000, .y = -1.35000, .z = -1.50000 },
+ { .x = +1.50000, .y = -1.42500, .z = +0.00000 },
+ { .x = +1.50000, .y = -1.42500, .z = -0.84000 },
+ { .x = +0.84000, .y = -1.42500, .z = -1.50000 },
+ { .x = +0.00000, .y = -1.42500, .z = -1.50000 },
+ { .x = -1.60000, .y = +0.45000, .z = +0.00000 },
+ { .x = -1.60000, .y = +0.45000, .z = -0.30000 },
+ { .x = -1.50000, .y = +0.67500, .z = -0.30000 },
+ { .x = -1.50000, .y = +0.67500, .z = +0.00000 },
+ { .x = -2.30000, .y = +0.45000, .z = +0.00000 },
+ { .x = -2.30000, .y = +0.45000, .z = -0.30000 },
+ { .x = -2.50000, .y = +0.67500, .z = -0.30000 },
+ { .x = -2.50000, .y = +0.67500, .z = +0.00000 },
+ { .x = -2.70000, .y = +0.45000, .z = +0.00000 },
+ { .x = -2.70000, .y = +0.45000, .z = -0.30000 },
+ { .x = -3.00000, .y = +0.67500, .z = -0.30000 },
+ { .x = -3.00000, .y = +0.67500, .z = +0.00000 },
+ { .x = -2.70000, .y = +0.22500, .z = +0.00000 },
+ { .x = -2.70000, .y = +0.22500, .z = -0.30000 },
+ { .x = -3.00000, .y = +0.22500, .z = -0.30000 },
+ { .x = -3.00000, .y = +0.22500, .z = +0.00000 },
+ { .x = -2.70000, .y = +0.00000, .z = +0.00000 },
+ { .x = -2.70000, .y = +0.00000, .z = -0.30000 },
+ { .x = -3.00000, .y = -0.22500, .z = -0.30000 },
+ { .x = -3.00000, .y = -0.22500, .z = +0.00000 },
+ { .x = -2.50000, .y = -0.45000, .z = +0.00000 },
+ { .x = -2.50000, .y = -0.45000, .z = -0.30000 },
+ { .x = -2.65000, .y = -0.63750, .z = -0.30000 },
+ { .x = -2.65000, .y = -0.63750, .z = +0.00000 },
+ { .x = -2.00000, .y = -0.67500, .z = -0.30000 },
+ { .x = -1.90000, .y = -0.97500, .z = -0.30000 },
+ { .x = -1.90000, .y = -0.97500, .z = +0.00000 },
+ { .x = +1.70000, .y = -0.15000, .z = +0.00000 },
+ { .x = +1.70000, .y = -0.15000, .z = -0.66000 },
+ { .x = +1.70000, .y = -0.97500, .z = -0.66000 },
+ { .x = +1.70000, .y = -0.97500, .z = +0.00000 },
+ { .x = +2.60000, .y = -0.15000, .z = +0.00000 },
+ { .x = +2.60000, .y = -0.15000, .z = -0.66000 },
+ { .x = +3.10000, .y = -0.75000, .z = -0.66000 },
+ { .x = +3.10000, .y = -0.75000, .z = +0.00000 },
+ { .x = +2.30000, .y = +0.52500, .z = +0.00000 },
+ { .x = +2.30000, .y = +0.52500, .z = -0.25000 },
+ { .x = +2.40000, .y = +0.45000, .z = -0.25000 },
+ { .x = +2.40000, .y = +0.45000, .z = +0.00000 },
+ { .x = +2.70000, .y = +0.82500, .z = +0.00000 },
+ { .x = +2.70000, .y = +0.82500, .z = -0.25000 },
+ { .x = +3.30000, .y = +0.82500, .z = -0.25000 },
+ { .x = +3.30000, .y = +0.82500, .z = +0.00000 },
+ { .x = +2.80000, .y = +0.90000, .z = +0.00000 },
+ { .x = +2.80000, .y = +0.90000, .z = -0.25000 },
+ { .x = +3.52500, .y = +0.91875, .z = -0.25000 },
+ { .x = +3.52500, .y = +0.91875, .z = +0.00000 },
+ { .x = +2.90000, .y = +0.90000, .z = +0.00000 },
+ { .x = +2.90000, .y = +0.90000, .z = -0.15000 },
+ { .x = +3.45000, .y = +0.93750, .z = -0.15000 },
+ { .x = +3.45000, .y = +0.93750, .z = +0.00000 },
+ { .x = +2.80000, .y = +0.82500, .z = +0.00000 },
+ { .x = +2.80000, .y = +0.82500, .z = -0.15000 },
+ { .x = +3.20000, .y = +0.82500, .z = -0.15000 },
+ { .x = +3.20000, .y = +0.82500, .z = +0.00000 },
+ { .x = +0.00000, .y = +1.57500, .z = +0.00000 },
+ { .x = +0.80000, .y = +1.57500, .z = +0.00000 },
+ { .x = +0.80000, .y = +1.57500, .z = -0.45000 },
+ { .x = +0.45000, .y = +1.57500, .z = -0.80000 },
+ { .x = +0.00000, .y = +1.57500, .z = -0.80000 },
+ { .x = +0.00000, .y = +1.27500, .z = +0.00000 },
+ { .x = +1.40000, .y = +0.82500, .z = +0.00000 },
+ { .x = +1.40000, .y = +0.82500, .z = -0.78400 },
+ { .x = +0.78400, .y = +0.82500, .z = -1.40000 },
+ { .x = +0.00000, .y = +0.82500, .z = -1.40000 },
+ { .x = +0.40000, .y = +0.97500, .z = +0.00000 },
+ { .x = +0.40000, .y = +0.97500, .z = -0.22400 },
+ { .x = +0.22400, .y = +0.97500, .z = -0.40000 },
+ { .x = +0.00000, .y = +0.97500, .z = -0.40000 },
+ { .x = +1.30000, .y = +0.97500, .z = +0.00000 },
+ { .x = +1.30000, .y = +0.97500, .z = -0.72800 },
+ { .x = +0.72800, .y = +0.97500, .z = -1.30000 },
+ { .x = +0.00000, .y = +0.97500, .z = -1.30000 },
+ { .x = +1.30000, .y = +0.82500, .z = +0.00000 },
+ { .x = +1.30000, .y = +0.82500, .z = -0.72800 },
+ { .x = +0.72800, .y = +0.82500, .z = -1.30000 },
+ { .x = +0.00000, .y = +0.82500, .z = -1.30000 },
+ { .x = +0.00000, .y = -1.57500, .z = +0.00000 },
+ { .x = +1.42500, .y = -1.57500, .z = -0.79800 },
+ { .x = +1.50000, .y = -1.50000, .z = +0.00000 },
+ { .x = +1.42500, .y = -1.57500, .z = +0.00000 },
+ { .x = +0.79800, .y = -1.57500, .z = -1.42500 },
+ { .x = +0.00000, .y = -1.50000, .z = -1.50000 },
+ { .x = +0.00000, .y = -1.57500, .z = -1.42500 },
+ { .x = +1.50000, .y = -1.50000, .z = -0.84000 },
+ { .x = +0.84000, .y = -1.50000, .z = -1.50000 },
+};
+
+#define DMNSN_BEZIER_RESOLUTION 8
+
+#define DMNSN_TEAPOT_NTRIANGLES \
+ (32*2*DMNSN_BEZIER_RESOLUTION*DMNSN_BEZIER_RESOLUTION)
+
+dmnsn_vector dmnsn_teapot_triangles[DMNSN_TEAPOT_NTRIANGLES][6];
+
+static inline double
+dmnsn_Bernstein_value(size_t i, double x)
+{
+ switch (i) {
+ case 0:
+ return (1 - x)*(1 - x)*(1 - x);
+ case 1:
+ return 3.0*x*(1 - x)*(1 - x);
+ case 2:
+ return 3.0*x*x*(1 - x);
+ case 3:
+ return x*x*x;
+ default:
+ dmnsn_unreachable("Wrong Bernstein index.");
+ }
+}
+
+static inline double
+dmnsn_Bernstein_prime(size_t i, double x)
+{
+ switch (i) {
+ case 0:
+ return -3.0*(1 - x)*(1 - x);
+ case 1:
+ return 3.0*(1 - x)*(1 - x) - 6.0*x*(1 - x);
+ case 2:
+ return 6.0*x*(1 - x) - 3.0*x*x;
+ case 3:
+ return 3.0*x*x;
+ default:
+ dmnsn_unreachable("Wrong Bernstein index.");
+ }
+}
+
+static inline dmnsn_vector
+dmnsn_bezier_patch_point(const dmnsn_vector control_points[16],
+ double u, double v)
+{
+ dmnsn_vector r = dmnsn_zero;
+ for (size_t i = 0; i < 4; ++i) {
+ for (size_t j = 0; j < 4; ++j) {
+ r = dmnsn_vector_add(
+ r,
+ dmnsn_vector_mul(
+ dmnsn_Bernstein_value(i, u)*dmnsn_Bernstein_value(j, v),
+ control_points[4*j + i]
+ )
+ );
+ }
+ }
+ return r;
+}
+
+static inline dmnsn_vector
+dmnsn_bezier_patch_normal(const dmnsn_vector control_points[16],
+ double u, double v)
+{
+ dmnsn_vector nu = dmnsn_zero, nv = dmnsn_zero;
+ for (size_t i = 0; i < 4; ++i) {
+ for (size_t j = 0; j < 4; ++j) {
+ nu = dmnsn_vector_add(
+ nu,
+ dmnsn_vector_mul(
+ dmnsn_Bernstein_prime(i, u)*dmnsn_Bernstein_value(j, v),
+ control_points[4*j + i]
+ )
+ );
+
+ nv = dmnsn_vector_add(
+ nv,
+ dmnsn_vector_mul(
+ dmnsn_Bernstein_value(i, u)*dmnsn_Bernstein_prime(j, v),
+ control_points[4*j + i]
+ )
+ );
+ }
+ }
+
+ dmnsn_vector n = dmnsn_vector_cross(nu, nv);
+ if (dmnsn_vector_norm(n) < dmnsn_epsilon) {
+ printf("%g\t%g\t" DMNSN_VECTOR_FORMAT "\t" DMNSN_VECTOR_FORMAT "\n",
+ u, v, DMNSN_VECTOR_PRINTF(nu), DMNSN_VECTOR_PRINTF(nv));
+ for (size_t i = 0; i < 16; ++i) {
+ printf("\t" DMNSN_VECTOR_FORMAT "\n", DMNSN_VECTOR_PRINTF(control_points[i]));
+ }
+ nu = dmnsn_zero;
+ for (size_t i = 0; i < 4; ++i) {
+ for (size_t j = 0; j < 4; ++j) {
+ nu = dmnsn_vector_add(
+ nu,
+ dmnsn_vector_mul(
+ dmnsn_Bernstein_prime(i, u)*dmnsn_Bernstein_value(j, v),
+ control_points[4*j + i]
+ )
+ );
+ if (dmnsn_vector_norm(dmnsn_vector_mul(
+ dmnsn_Bernstein_prime(i, u)*dmnsn_Bernstein_value(j, v),
+ control_points[4*j + i]
+ )) > dmnsn_epsilon)
+ printf(DMNSN_VECTOR_FORMAT "\n", DMNSN_VECTOR_PRINTF(dmnsn_vector_mul(
+ dmnsn_Bernstein_prime(i, u)*dmnsn_Bernstein_value(j, v),
+ control_points[4*j + i]
+ )));
+ }
+ }
+ dmnsn_assert(false, "asdf.");
+ }
+ return n;
+}
+
+static size_t
+dmnsn_mirror_last_triangle(size_t i, bool mirror_x)
+{
+ return i;
+ for (size_t j = 0; j < 6; ++j) {
+ dmnsn_vector v = dmnsn_teapot_triangles[i - 1][j];
+ if (mirror_x) {
+ v.x = -v.x;
+ } else {
+ v.z = -v.z;
+ }
+
+ dmnsn_teapot_triangles[i][j] = v;
+ }
+
+ return i + 1;
+}
+
+static size_t
+dmnsn_subdivide_patch(const size_t indicies[16], size_t i,
+ bool mirror_x)
+{
+ dmnsn_vector control_points[16];
+ for (size_t j = 0; j < 16; ++j) {
+ control_points[j] = dmnsn_teapot_verticies[indicies[j]];
+ }
+
+ dmnsn_vector lastrowr[DMNSN_BEZIER_RESOLUTION + 1];
+ dmnsn_vector lastrown[DMNSN_BEZIER_RESOLUTION + 1];
+ for (size_t k = 0; k <= DMNSN_BEZIER_RESOLUTION; ++k) {
+ lastrowr[k] = dmnsn_bezier_patch_point(
+ control_points, 0.0, (double)k/DMNSN_BEZIER_RESOLUTION
+ );
+ lastrown[k] = dmnsn_bezier_patch_normal(
+ control_points, 0.0, (double)k/DMNSN_BEZIER_RESOLUTION
+ );
+ }
+
+ dmnsn_vector ar, an, dr, dn;
+ for (size_t j = 1; j <= DMNSN_BEZIER_RESOLUTION; ++j) {
+ ar = lastrowr[0];
+ an = lastrown[0];
+ dr = dmnsn_bezier_patch_point(
+ control_points, (double)j/DMNSN_BEZIER_RESOLUTION, 0.0
+ );
+ dn = dmnsn_bezier_patch_normal(
+ control_points, (double)j/DMNSN_BEZIER_RESOLUTION, 0.0
+ );
+ lastrowr[0] = dr;
+ lastrown[0] = dn;
+
+ for (size_t k = 1; k <= DMNSN_BEZIER_RESOLUTION; ++k) {
+ dmnsn_vector br = lastrowr[k];
+ dmnsn_vector bn = lastrown[k];
+ dmnsn_vector cr = dmnsn_bezier_patch_point(
+ control_points,
+ (double)j/DMNSN_BEZIER_RESOLUTION, (double)k/DMNSN_BEZIER_RESOLUTION
+ );
+ dmnsn_vector cn = dmnsn_bezier_patch_normal(
+ control_points,
+ (double)j/DMNSN_BEZIER_RESOLUTION, (double)k/DMNSN_BEZIER_RESOLUTION
+ );
+
+ dmnsn_teapot_triangles[i][0] = ar;
+ dmnsn_teapot_triangles[i][1] = br;
+ dmnsn_teapot_triangles[i][2] = cr;
+ dmnsn_teapot_triangles[i][3] = an;
+ dmnsn_teapot_triangles[i][4] = bn;
+ dmnsn_teapot_triangles[i][5] = cn;
+ ++i;
+ i = dmnsn_mirror_last_triangle(i, false);
+ if (mirror_x) {
+ i = dmnsn_mirror_last_triangle(i, true);
+ i = dmnsn_mirror_last_triangle(i, false);
+ }
+
+ dmnsn_teapot_triangles[i][0] = cr;
+ dmnsn_teapot_triangles[i][1] = dr;
+ dmnsn_teapot_triangles[i][2] = ar;
+ dmnsn_teapot_triangles[i][3] = cn;
+ dmnsn_teapot_triangles[i][4] = dn;
+ dmnsn_teapot_triangles[i][5] = an;
+ ++i;
+ i = dmnsn_mirror_last_triangle(i, false);
+ if (mirror_x) {
+ i = dmnsn_mirror_last_triangle(i, true);
+ i = dmnsn_mirror_last_triangle(i, false);
+ }
+
+ ar = br;
+ an = bn;
+ dr = cr;
+ dn = cn;
+ lastrowr[k] = dr;
+ lastrown[k] = dn;
+ }
+ }
+
+ return i;
+}
+
+static const size_t dmnsn_teapot_rim[16] = {
+ 102, 103, 104, 105, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
+};
+static const size_t dmnsn_teapot_body1[16] = {
+ 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27
+};
+static const size_t dmnsn_teapot_body2[16] = {
+ 24, 25, 26, 27, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40
+};
+static const size_t dmnsn_teapot_lid1[16] = {
+ 96, 96, 96, 96, 97, 98, 99, 100, 101, 101, 101, 101, 0, 1, 2, 3
+};
+static const size_t dmnsn_teapot_lid2[16] = {
+ 0, 1, 2, 3, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117
+};
+static const size_t dmnsn_teapot_bottom[16] = {
+ 118, 118, 118, 118, 124, 122, 119, 121, 123, 126, 125, 120, 40, 39, 38, 37
+};
+static const size_t dmnsn_teapot_handle1[16] = {
+ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56
+};
+static const size_t dmnsn_teapot_handle2[16] = {
+ 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 28, 65, 66, 67
+};
+static const size_t dmnsn_teapot_spout1[16] = {
+ 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83
+};
+static const size_t dmnsn_teapot_spout2[16] = {
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95
+};
+
+static void
+dmnsn_teapot_calculate(void)
+{
+ size_t i = 0;
+ i = dmnsn_subdivide_patch(dmnsn_teapot_rim, i, true);
+ i = dmnsn_subdivide_patch(dmnsn_teapot_body1, i, true);
+ i = dmnsn_subdivide_patch(dmnsn_teapot_body2, i, true);
+ i = dmnsn_subdivide_patch(dmnsn_teapot_lid1, i, true);
+ i = dmnsn_subdivide_patch(dmnsn_teapot_lid2, i, true);
+ i = dmnsn_subdivide_patch(dmnsn_teapot_bottom, i, true);
+ i = dmnsn_subdivide_patch(dmnsn_teapot_handle1, i, false);
+ i = dmnsn_subdivide_patch(dmnsn_teapot_handle2, i, false);
+ i = dmnsn_subdivide_patch(dmnsn_teapot_spout1, i, false);
+ i = dmnsn_subdivide_patch(dmnsn_teapot_spout2, i, false);
+ //dmnsn_assert(i == DMNSN_TEAPOT_NTRIANGLES, "Wrong number of triangles.");
+}
+
+pthread_mutex_t dmnsn_teapot_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+dmnsn_object *
+dmnsn_new_teapot(void)
+{
+ dmnsn_lock_mutex(&dmnsn_teapot_mutex);
+ static bool verticies_calculated = false;
+ if (!verticies_calculated) {
+ dmnsn_teapot_calculate();
+ verticies_calculated = true;
+ }
+ dmnsn_unlock_mutex(&dmnsn_teapot_mutex);
+
+ dmnsn_array *triangles = dmnsn_new_array(sizeof(dmnsn_object *));
+ for (size_t i = 0; i < DMNSN_TEAPOT_NTRIANGLES; ++i) {
+ dmnsn_vector *vertnorms = dmnsn_teapot_triangles[i];
+ dmnsn_object *triangle = dmnsn_new_triangle(
+ vertnorms[0], vertnorms[1], vertnorms[2],
+ vertnorms[3], vertnorms[4], vertnorms[5]
+ );
+ triangle->texture = dmnsn_new_texture();
+ dmnsn_color randcolor;
+ randcolor.R = drand48();
+ randcolor.G = drand48();
+ randcolor.B = drand48();
+ triangle->texture->pigment = dmnsn_new_solid_pigment(DMNSN_TCOLOR(randcolor));
+ dmnsn_array_push(triangles, &triangle);
+ }
+ dmnsn_object *teapot = dmnsn_new_csg_union(triangles);
+ dmnsn_delete_array(triangles);
+ return teapot;
+}