diff options
author | Ian Romanick <idr@freedesktop.org> | 2011-02-02 15:07:26 -0800 |
---|---|---|
committer | Ian Romanick <idr@freedesktop.org> | 2011-02-02 15:07:26 -0800 |
commit | 40f167c46786575cf877a921e8477d6ba1ebd4a8 (patch) | |
tree | e824523767afb1a5f074f3ddb0459311a0b11004 | |
parent | 273d22b87594e698dbf892af900fb0b7981a7706 (diff) |
GLUshape: Add a torus shape generator
-rw-r--r-- | include/glu3.h | 29 | ||||
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/revolve.c | 49 | ||||
-rw-r--r-- | src/revolve.h | 5 | ||||
-rw-r--r-- | src/torus.cpp | 116 |
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); +} |