commit 3d123b64f2cf5a6726b832c28ee5d651550f4d66
parent f035b25a197253d032d136f5ba94d786128de55a
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Fri, 25 Nov 2016 09:02:07 +0100
Implement the s3dut_create_sphere function
Diffstat:
| A | src/s3dut_sphere.c | | | 184 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
1 file changed, 184 insertions(+), 0 deletions(-)
diff --git a/src/s3dut_sphere.c b/src/s3dut_sphere.c
@@ -0,0 +1,184 @@
+/* Copyright (C) |Meso|Star> 2016 (contact@meso-star.com)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "s3dut.h"
+#include "s3dut_mesh.h"
+
+/*******************************************************************************
+ * Helper functions
+ ******************************************************************************/
+static res_T
+setup_sphere_coords
+ (struct mem_allocator* allocator,
+ struct darray_double* coords,
+ const double radius,
+ const unsigned nslices, /* # subdivisions around the Z axis */
+ const unsigned nstacks) /* # subdivisions along the Z axis */
+{
+ enum { SIN, COS };
+ struct darray_double sincos_theta;
+ struct darray_double sincos_phi;
+ double step_theta;
+ double step_phi;
+ size_t itheta;
+ size_t iphi;
+ size_t i;
+ res_T res = RES_OK;
+ ASSERT(coords && radius > 0 && nslices >= 2 && nstacks >= 2);
+
+ darray_double_init(allocator, &sincos_theta);
+ darray_double_init(allocator, &sincos_phi);
+
+ res = darray_double_resize(&sincos_theta, nslices*2/*sin & cos*/);
+ if(res != RES_OK) goto error;
+ res = darray_double_resize(&sincos_phi, nstacks*2/*sin & cos*/);
+ if(res != RES_OK) goto error;
+
+ /* Precompute the sinus/cosine of the theta/phi angles */
+ step_theta = 2*PI / (double)nslices;
+ FOR_EACH(itheta, 0, nslices) {
+ const double theta = -PI + (double)itheta * step_theta;
+ darray_double_data_get(&sincos_theta)[itheta*2 + SIN] = sin(theta);
+ darray_double_data_get(&sincos_theta)[itheta*2 + COS] = cos(theta);
+ }
+ step_phi = PI/(double)nstacks;
+ FOR_EACH(iphi, 0, nstacks) {
+ const double phi = -PI/2 + (double)(iphi+1) * step_phi;
+ darray_double_data_get(&sincos_phi)[iphi*2 + SIN] = sin(phi);
+ darray_double_data_get(&sincos_phi)[iphi*2 + COS] = cos(phi);
+ }
+
+ /* Setup the contour vertices */
+ i = 0;
+ FOR_EACH(itheta, 0, nslices) {
+ const double* theta = darray_double_cdata_get(&sincos_theta) + itheta*2;
+ FOR_EACH(iphi, 0, nstacks-1) {
+ const double* phi = darray_double_cdata_get(&sincos_phi) + iphi*2;
+ darray_double_data_get(coords)[i++] = radius * COS[theta] * COS[phi];
+ darray_double_data_get(coords)[i++] = radius * SIN[theta] * COS[phi];
+ darray_double_data_get(coords)[i++] = radius * SIN[phi];
+ }
+ }
+
+ /* Setup the bottom polar vertex */
+ darray_double_data_get(coords)[i++] = 0;
+ darray_double_data_get(coords)[i++] = 0;
+ darray_double_data_get(coords)[i++] = -radius;
+
+ /* Setup the top polar vertex */
+ darray_double_data_get(coords)[i++] = 0;
+ darray_double_data_get(coords)[i++] = 0;
+ darray_double_data_get(coords)[i++] = radius;
+
+exit:
+ darray_double_release(&sincos_theta);
+ darray_double_release(&sincos_phi);
+ return res;
+error:
+ goto exit;
+}
+
+static void
+setup_sphere_indices
+ (struct darray_size_t* ids,
+ const unsigned nslices, /* # subdivisions around the Z axis */
+ const unsigned nstacks) /* # subdivisions along the Z axis */
+{
+ size_t i, itheta, iphi;
+ ASSERT(ids && nslices && nstacks);
+
+ /* Define the indices of the contour primitives */
+ i = 0;
+ FOR_EACH(itheta, 0, nslices) {
+ const size_t itheta0 = itheta * (nstacks - 1);
+ const size_t itheta1 = ((itheta + 1) % nslices) * (nstacks - 1);
+ FOR_EACH(iphi, 0, nstacks-2) {
+ const size_t iphi0 = iphi + 0;
+ const size_t iphi1 = iphi + 1;
+
+ darray_size_t_data_get(ids)[i++] = itheta0 + iphi0;
+ darray_size_t_data_get(ids)[i++] = itheta0 + iphi1;
+ darray_size_t_data_get(ids)[i++] = itheta1 + iphi0;
+
+ darray_size_t_data_get(ids)[i++] = itheta1 + iphi0;
+ darray_size_t_data_get(ids)[i++] = itheta0 + iphi1;
+ darray_size_t_data_get(ids)[i++] = itheta1 + iphi1;
+ }
+ }
+
+ /* Define the indices of the polar primitives */
+ FOR_EACH(itheta, 0, nstacks) {
+ const size_t itheta0 = itheta * (nstacks - 1);
+ const size_t itheta1 = ((itheta + 1) % nslices) * (nstacks - 1);
+
+ darray_size_t_data_get(ids)[i++] = nslices * (nstacks - 1);
+ darray_size_t_data_get(ids)[i++] = itheta0;
+ darray_size_t_data_get(ids)[i++] = itheta1;
+
+ darray_size_t_data_get(ids)[i++] = nslices * (nstacks - 1) + 1;
+ darray_size_t_data_get(ids)[i++] = itheta1 + (nstacks - 2);
+ darray_size_t_data_get(ids)[i++] = itheta0 + (nstacks - 2);
+ }
+}
+
+/*******************************************************************************
+ * Exported function
+ ******************************************************************************/
+res_T
+s3dut_create_sphere
+ (struct mem_allocator* allocator,
+ const double radius,
+ const unsigned nslices, /* # subdivisions around the Z axis */
+ const unsigned nstacks, /* # subdivisions along the Z axis */
+ struct s3dut_mesh** mesh)
+{
+ struct s3dut_mesh* sphere = NULL;
+ size_t nverts;
+ size_t ntris;
+ res_T res = RES_OK;
+
+ if(radius <= 0 || nslices < 2 || nstacks < 2 || !mesh) {
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ res = mesh_create(allocator, &sphere);
+ if(res != RES_OK) goto error;
+ sphere->type = S3DUT_MESH_SPHERE;
+
+ nverts = nslices*(nstacks-1)/* #contour verts*/ + 2/*polar verts*/;
+ ntris = 2*nslices*(nstacks-2)/* #contour tris*/ + 2*nslices/* #polar tris*/;
+
+ res = darray_double_resize(&sphere->coords, nverts*3/*#coords*/);
+ if(res != RES_OK) goto error;
+ res = darray_size_t_resize(&sphere->ids, ntris*3/*#ids per triangle*/);
+ if(res != RES_OK) goto error;
+
+ res = setup_sphere_coords
+ (allocator, &sphere->coords, radius, nslices, nstacks);
+ if(res != RES_OK) goto error;
+
+ setup_sphere_indices(&sphere->ids, nslices, nstacks);
+
+exit:
+ if(mesh) *mesh = sphere;
+ return res;
+error:
+ if(sphere) {
+ S3DUT(mesh_ref_put(sphere));
+ sphere = NULL;
+ }
+ goto exit;
+}
+