summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Romanick <idr@freedesktop.org>2011-02-02 15:07:26 -0800
committerIan Romanick <idr@freedesktop.org>2011-02-02 15:07:26 -0800
commit40f167c46786575cf877a921e8477d6ba1ebd4a8 (patch)
treee824523767afb1a5f074f3ddb0459311a0b11004
parent273d22b87594e698dbf892af900fb0b7981a7706 (diff)
GLUshape: Add a torus shape generator
-rw-r--r--include/glu3.h29
-rw-r--r--src/Makefile.am2
-rw-r--r--src/revolve.c49
-rw-r--r--src/revolve.h5
-rw-r--r--src/torus.cpp116
5 files changed, 200 insertions, 1 deletions
diff --git a/include/glu3.h b/include/glu3.h
index 2edeb5b..210f713 100644
--- a/include/glu3.h
+++ b/include/glu3.h
@@ -504,6 +504,35 @@ private:
/**
+ * Shape generator that generates a torus.
+ */
+class GLUtorusProducer : public GLUmeshProducer {
+public:
+ /**
+ * Construct a new torus shape generator
+ *
+ * \param tube_radius Specifies the radius of the "solid" part of the
+ * torus.
+ * \param path_radius Specifies the distance from the center of the
+ * "hole" to the center of the solid part.
+ * \param sides Specifies the number of subdivisions around each
+ * ring.
+ * \param rings Specifies the number of subdivisions along the
+ * path. These are roughly analogous the longitude
+ * lines on a globe.
+ */
+ GLUtorusProducer(double tube_radius, double path_radius,
+ unsigned sides, unsigned rings);
+ virtual unsigned vertex_count(void) const;
+ virtual void generate(GLUshapeConsumer *consumer) const;
+
+private:
+ double tube_radius;
+ double path_radius;
+};
+
+
+/**
* Shape generator that generates a cube.
*/
class GLUcubeProducer : public GLUshapeProducer {
diff --git a/src/Makefile.am b/src/Makefile.am
index 739c95e..c3e0335 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -25,7 +25,7 @@ AM_CFLAGS=-I../include
lib_LIBRARIES = libGLU3.a
libGLU3_a_SOURCES = matrix.c load_text.c arcball.c revolve.c mesh.cpp \
- sphere.cpp cube.cpp shader.c mesh.h revolve.h system.h \
+ sphere.cpp torus.cpp cube.cpp shader.c mesh.h revolve.h system.h \
buffer.c buffer.h shape.cpp
libGLU3includedir = ${includedir}
diff --git a/src/revolve.c b/src/revolve.c
index 71285ac..03606c9 100644
--- a/src/revolve.c
+++ b/src/revolve.c
@@ -126,3 +126,52 @@ generate_sphere(double radius, unsigned slices, unsigned stacks,
revolve(positions, normals, u, stacks + 1, & y_axis,
slices + 1, 2.0 * M_PI, 0.0, cb, data, buf);
}
+
+
+void
+generate_torus(double tube_radius, double path_radius,
+ unsigned sides, unsigned rings, _Bool normals_point_out,
+ revolve_cb *cb, void *data, struct cb_buffer *buf)
+{
+ const GLUvec4 y_axis = {{ 0.0, 1.0, 0.0, 0.0 }};
+ GLUvec4 *positions;
+ GLUvec4 *normals;
+ float *u;
+ double angle_step;
+ unsigned i;
+
+ positions = (GLUvec4 *) malloc((2 * sizeof(GLUvec4) + sizeof(float))
+ * (sides + 1));
+ normals = positions + (sides + 1);
+ u = (float *)(normals + (sides + 1));
+
+ angle_step = 2.0 * M_PI / (double)(sides);
+ for (i = 0; i < (sides + 1); i++) {
+ const double angle = angle_step * i;
+
+ normals[i].values[0] = sin(angle);
+ normals[i].values[1] = cos(angle);
+ normals[i].values[2] = 0.0;
+ normals[i].values[3] = 0.0;
+
+ gluMult4v_f(& positions[i],
+ & normals[i],
+ tube_radius);
+ positions[i].values[3] = 1.0;
+ positions[i].values[0] += path_radius;
+
+ u[i] = (float) i / (float) sides;
+
+ if (!normals_point_out) {
+ normals[i].values[0] = -normals[i].values[0];
+ normals[i].values[1] = -normals[i].values[1];
+ }
+ }
+
+ /* Note the rotation is *from* 2pi *to* 0. The counter-clockwise
+ * rotation ensures that the vertices are generated in the correct
+ * order to be drawn using triangle strips with back-face culling.
+ */
+ revolve(positions, normals, u, sides + 1, & y_axis,
+ rings + 1, 2.0 * M_PI, 0.0, cb, data, buf);
+}
diff --git a/src/revolve.h b/src/revolve.h
index 7d02cff..887654c 100644
--- a/src/revolve.h
+++ b/src/revolve.h
@@ -69,6 +69,11 @@ generate_sphere(double radius, unsigned slices, unsigned stacks,
bool normals_point_out, revolve_cb *cb, void *data,
struct cb_buffer *buf);
+extern void
+generate_torus(double tube_radius, double path_radius,
+ unsigned sides, unsigned rings, bool normals_point_out,
+ revolve_cb *cb, void *data, struct cb_buffer *buf);
+
#ifdef __cplusplus
};
#endif
diff --git a/src/torus.cpp b/src/torus.cpp
new file mode 100644
index 0000000..32ae4e7
--- /dev/null
+++ b/src/torus.cpp
@@ -0,0 +1,116 @@
+/*
+ * Copyright © 2011 Ian D. Romanick
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+#include "glu3.h"
+#include "revolve.h"
+#include "mesh.h"
+
+/**
+ * Call-back function for sphere generation routine
+ */
+static void torus_revolve_cb(void *data,
+ const GLUvec4 *position,
+ const GLUvec4 *normal,
+ const GLUvec4 *tangent,
+ const GLUvec4 *uv,
+ unsigned count);
+
+/**
+ * GLUtorusProducer decorator to implement call-backs
+ *
+ * To generate the torus data, the \c GLUtorusProducer class interfaces with
+ * a C functions that uses a call-back mechanism. This call-backs is
+ * analogous to \c vertex_batch method that \c GLUshapeConsumer subclasses
+ * will provide.
+ *
+ * However, this method is \c protected. As a result the non-class call-back
+ * functions cannot call this method unless it is a \c friend function. It is
+ * undesireable to expose this implementation detail in the application-facing
+ * header file. This can be worked around by creating a dummy subclass of \c
+ * GLUshapeConsumer that only contains the \c friend function declaration.
+ * Pointers to \c GLUshapeConsumer objects can be cast to pointers to
+ * \c GLUconsumerFriend objects without side-effect.
+ *
+ * This is arguably a mis-use of the "decorator" pattern, but it is the most
+ * efficient way to do this.
+ */
+class GLUconsumerFriend : public GLUshapeConsumer {
+ friend void torus_revolve_cb(void *data,
+ const GLUvec4 *position,
+ const GLUvec4 *normal,
+ const GLUvec4 *tangent,
+ const GLUvec4 *uv,
+ unsigned count);
+};
+
+
+GLUtorusProducer::GLUtorusProducer(double tube_radius, double path_radius,
+ unsigned sides, unsigned rings)
+ : GLUmeshProducer(rings, sides + 1, sides + 1)
+{
+ this->tube_radius = fabs(tube_radius);
+ this->path_radius = fabs(path_radius);
+ this->rows = (rings < 3) ? 3 : rings;
+ this->columns = (sides < 3) ? 4 : (sides + 1);
+ this->width = this->columns;
+}
+
+
+unsigned
+GLUtorusProducer::vertex_count(void) const
+{
+ return (this->rows + 1) * this->columns;
+}
+
+
+static void
+torus_revolve_cb(void *data, const GLUvec4 *position, const GLUvec4 *normal,
+ const GLUvec4 *tangent, const GLUvec4 *uv, unsigned count)
+{
+ GLUconsumerFriend *c = (GLUconsumerFriend *) data;
+
+ c->vertex_batch(position, normal, tangent, uv, count);
+}
+
+
+void
+GLUtorusProducer::generate(GLUshapeConsumer *consumer) const
+{
+ GLUvec4 data[4 * 16];
+ cb_buffer buf;
+
+ if (consumer->vertex_count == 0) {
+ cb_buffer_init(&buf, &data[0], &data[16], &data[32],
+ &data[48], 16);
+ } else {
+ cb_buffer_init(&buf, consumer->position, consumer->normal,
+ consumer->tangent, consumer->uv,
+ consumer->vertex_count);
+ }
+
+ generate_torus(this->tube_radius, this->path_radius,
+ this->columns - 1, this->rows,
+ this->normals_point_out,
+ torus_revolve_cb, (void *) consumer, &buf);
+
+ GLUmeshProducer::generate(consumer);
+}