summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Romanick <idr@freedesktop.org>2010-02-15 15:14:02 -0800
committerIan Romanick <idr@freedesktop.org>2010-02-15 15:14:02 -0800
commitbe4ad7ab08a541f119871d932cef369e0c42bc13 (patch)
tree76018b16d7d631314ee4c901e04f58d6c88fb2cb
parent241f99cd6bcc8e0d0899c7fc2088ced7734966ab (diff)
GLUshape: Add GLUsphere class for generating sphere shapes
-rw-r--r--include/glu3.h29
-rw-r--r--src/Makefile.am2
-rw-r--r--src/sphere.cpp167
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);
+}