diff options
author | Ian Romanick <idr@freedesktop.org> | 2010-02-15 15:14:02 -0800 |
---|---|---|
committer | Ian Romanick <idr@freedesktop.org> | 2010-02-15 15:14:02 -0800 |
commit | be4ad7ab08a541f119871d932cef369e0c42bc13 (patch) | |
tree | 76018b16d7d631314ee4c901e04f58d6c88fb2cb | |
parent | 241f99cd6bcc8e0d0899c7fc2088ced7734966ab (diff) |
GLUshape: Add GLUsphere class for generating sphere shapes
-rw-r--r-- | include/glu3.h | 29 | ||||
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/sphere.cpp | 167 |
3 files changed, 197 insertions, 1 deletions
diff --git a/include/glu3.h b/include/glu3.h index cf3d9ac..95be831 100644 --- a/include/glu3.h +++ b/include/glu3.h @@ -383,6 +383,35 @@ protected: bool normals_point_out; bool normals_per_vertex; }; + + +/** + * Shape generator that generates a sphere. + */ +class GLUsphere : public GLUshape { +public: + /** + * Construct a new sphere shape generator + * + * \param radius Specifies the radius of the sphere. + * \param slices Specifies the number of subdivisions around the + * z-axis. These subdivisions are analogous to the + * slices of an orange. These also match longitude + * lines on the globe. + * \param stacks Specifies the number of subdivisions along the + * z-axis. These match the latitude lines on the globe. + */ + GLUsphere(GLdouble radius, GLint slices, GLint stacks); + virtual unsigned vertex_count(void) const; + virtual unsigned element_count(void) const; + virtual unsigned primitive_count(void) const; + virtual void generate(void); + +private: + double radius; + unsigned slices; + unsigned stacks; +}; #endif #ifndef __cplusplus diff --git a/src/Makefile.am b/src/Makefile.am index 736ee5c..697a60e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -24,7 +24,7 @@ AM_CXXFLAGS=-I../include AM_CFLAGS=-I../include lib_LIBRARIES = libGLU3.a -libGLU3_a_SOURCES = matrix.c load_text.c arcball.c revolve.c mesh.c +libGLU3_a_SOURCES = matrix.c load_text.c arcball.c revolve.c mesh.c sphere.cpp libGLU3includedir = ${includedir} libGLU3include_HEADERS = ../include/glu3.h ../include/glu3_scalar.h diff --git a/src/sphere.cpp b/src/sphere.cpp new file mode 100644 index 0000000..f51160e --- /dev/null +++ b/src/sphere.cpp @@ -0,0 +1,167 @@ +/* + + * Copyright © 2010 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" + +/** + * \name Call-back functions for sphere generation routine + */ +/*@{*/ +static void sphere_revolve_cb(void *data, + const GLUvec4 *position, + const GLUvec4 *normal, + const GLUvec4 *tangent, + const GLUvec4 *uv); + +static void sphere_begin_cb(void *data, GLenum mode); + +static void sphere_index_cb(void *data, unsigned index); + +static void sphere_end_cb(void *data); +/*@}*/ + +/** + * GLUsphere decorator to implement call-backs + * + * To generate the sphere data, the \c GLUsphere class interfaces with various + * C functions that use a call-back mechanism. These call-backs are analogous + * the \c emit_vertex, \c emit_begin, \c emit_index, and \c emit_end methods + * that \c GLUsphere subclasses will provide. + * + * However, these methods are all \c protected. As a result the non-class + * call-back functions cannot call these methods unless they are \c friend + * functions. It is undesireable to expose the implementation detail in the + * application-facing header file. This can be worked around by creating a + * dummy subclass of \c GLUsphere that only contains the \c friend function + * declarations. Pointers to \c GLUsphere objects can be cast to pointers to + * \c GLUsphereFriend 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 GLUsphereFriend : public GLUsphere { + friend void sphere_revolve_cb(void *data, + const GLUvec4 *position, + const GLUvec4 *normal, + const GLUvec4 *tangent, + const GLUvec4 *uv); + + friend void sphere_begin_cb(void *data, GLenum mode); + + friend void sphere_index_cb(void *data, unsigned index); + + friend void sphere_end_cb(void *data); +}; + + +GLUsphere::GLUsphere(GLdouble radius, GLint slices, GLint stacks) +{ + this->radius = radius; + this->slices = (slices < 4) ? 4 : (unsigned) slices; + this->stacks = (stacks < 4) ? 4 : (unsigned) stacks; +} + + +unsigned +GLUsphere::vertex_count(void) const +{ + /* Each line of vertices from the north pole to the south pole consists + * of (stacks+1) vertices. There are a total of (slices+1) of these + * lines of vertices. + */ + return (slices + 1) * (stacks + 1); +} + + +unsigned +GLUsphere::primitive_count(void) const +{ + /* For each slice there is a triangle strip from the north pole to the + * south pole. + */ + return slices; +} + + +unsigned +GLUsphere::element_count(void) const +{ + /* Each slice is a triangle strip represented by 2 elements plus + * 2 elements for each stack; + */ + return slices * (2 * (stacks + 1)); +} + + +static void +sphere_revolve_cb(void *data, const GLUvec4 *position, const GLUvec4 *normal, + const GLUvec4 *tangent, const GLUvec4 *uv) +{ + GLUsphereFriend *s = (GLUsphereFriend *) data; + + s->emit_vertex(*position, *normal, *tangent, *uv); +} + + +static void +sphere_begin_cb(void *data, GLenum mode) +{ + GLUsphereFriend *s = (GLUsphereFriend *) data; + + s->emit_begin(mode); +} + + +static void +sphere_index_cb(void *data, unsigned index) +{ + GLUsphereFriend *s = (GLUsphereFriend *) data; + + s->emit_index(index); +} + + +static void +sphere_end_cb(void *data) +{ + GLUsphereFriend *s = (GLUsphereFriend *) data; + + s->emit_end(); +} + + +void +GLUsphere::generate(void) +{ + generate_sphere(radius, slices, stacks, + normals_point_out, + sphere_revolve_cb, (void *) this); + + generate_triangle_mesh(slices, stacks + 1, stacks + 1, + sphere_begin_cb, + sphere_index_cb, + sphere_end_cb, + (void *) this); +} |