summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKenneth Graunke <kenneth@whitecape.org>2010-10-06 20:55:32 -0700
committerKenneth Graunke <kenneth@whitecape.org>2010-10-06 20:55:32 -0700
commitdf43818ff58074cfdcb2e196a2db9fa22a4f40b4 (patch)
treea7c4086c1d901d816ebbf8444c11fc04408fee1d
Initial commit. lol
-rwxr-xr-xMakefile.am24
-rwxr-xr-xautogen.sh12
-rwxr-xr-xconfigure.ac96
-rwxr-xr-xsrc/Makefile.am27
-rwxr-xr-xsrc/bezier.cpp34
-rwxr-xr-xsrc/bezier.h60
-rwxr-xr-xsrc/main.cpp474
-rwxr-xr-xsrc/model_consumer.cpp143
-rwxr-xr-xsrc/patch_set.h49
-rwxr-xr-xsrc/phong.frag20
-rwxr-xr-xsrc/phong.vert24
11 files changed, 963 insertions, 0 deletions
diff --git a/Makefile.am b/Makefile.am
new file mode 100755
index 0000000..51d21bb
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,24 @@
+# Copyright © 2009 Ian D. Romanick
+# All Rights Reserved.
+#
+# 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
+# on the rights to use, copy, modify, merge, publish, distribute, sub
+# license, 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 NON-INFRINGEMENT. IN NO EVENT SHALL
+# AUTHORS, COPYRIGHT HOLDERS, AND/OR THEIR SUPPLIERS 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.
+
+AUTOMAKE_OPTIONS = foreign
+SUBDIRS = src
diff --git a/autogen.sh b/autogen.sh
new file mode 100755
index 0000000..904cd67
--- /dev/null
+++ b/autogen.sh
@@ -0,0 +1,12 @@
+#! /bin/sh
+
+srcdir=`dirname $0`
+test -z "$srcdir" && srcdir=.
+
+ORIGDIR=`pwd`
+cd $srcdir
+
+autoreconf -v --install || exit 1
+cd $ORIGDIR || exit $?
+
+$srcdir/configure --enable-maintainer-mode "$@"
diff --git a/configure.ac b/configure.ac
new file mode 100755
index 0000000..4e7de98
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,96 @@
+# -*- Autoconf -*-
+# Process this file with autoconf to produce a configure script.
+
+AC_PREREQ(2.61)
+AC_INIT(bezier_demo, 2010Q1.1, idr@freedesktop.org, bezier_demo)
+AC_CONFIG_SRCDIR([Makefile.am])
+AM_CONFIG_HEADER([config.h])
+
+AM_INIT_AUTOMAKE
+
+AM_MAINTAINER_MODE
+
+# Checks for programs.
+AC_PROG_CXX
+AC_PROG_CC
+AC_PROG_MAKE_SET
+AC_PROG_RANLIB
+PKG_PROG_PKG_CONFIG
+
+# Checks for libraries.
+
+# Checks for header files.
+
+# Checks for typedefs, structures, and compiler characteristics.
+
+# Checks for library functions.
+AC_HEADER_STDC
+
+
+# SDL is required for this application. Find its header files and
+# libraries. Make sure they exist.
+
+CPPFLAGS="$CPPFLAGS `sdl-config --cflags`"
+LIBS="$LIBS `sdl-config --libs`"
+
+AC_CHECK_HEADER(SDL.h, [], [exit 1])
+
+
+# OpenGL is required for this application. Find its header files and
+# libraries. Make sure they exist.
+
+AC_CHECK_HEADER(GL/gl.h, [], [exit 1])
+AC_CHECK_LIB([GL], [glVertexPointer], [], [exit 1])
+
+
+# GLEW is required for this application. Find its header files and
+# libraries. Make sure they exist.
+
+AC_CHECK_HEADER(GL/glew.h, [], [exit 1])
+AC_CHECK_LIB([GLEW], [glewInit], [], [exit 1], [-lGL])
+
+AC_LANG_CPLUSPLUS
+
+PKG_CHECK_MODULES([GLU3], [glu3])
+AC_SUBST(GLU3_CFLAGS)
+AC_SUBST(GLU3_LIBS)
+
+AC_ARG_ENABLE([debug],
+ [AS_HELP_STRING([--enable-debug],
+ [use debug compiler flags and macros @<:@default=disabled@:>@])],
+ [enable_debug="$enableval"],
+ [enable_debug=no]
+)
+if test "x$enable_debug" = xyes; then
+ DEFINES="$DEFINES -DDEBUG"
+ if test "x$GCC" = xyes; then
+ # Remove any -g flags from the command line
+ CFLAGS=[`echo $CFLAGS | sed 's/-g[^ \t]*[ \t]*//g'`]
+ CFLAGS="$CFLAGS -ggdb3 -fstack-protector -D_FORTIFY_SOURCE=2"
+ fi
+ if test "x$GXX" = xyes; then
+ # Remove any -g flags from the command line
+ CXXFLAGS=[`echo $CXXFLAGS | sed 's/-g[^ \t]*[ \t]*//g'`]
+ CXXFLAGS="$CXXFLAGS -ggdb3 -fstack-protector -D_FORTIFY_SOURCE=2"
+ fi
+fi
+
+
+if test "x$GCC" = xyes ; then
+ WARN="-Wall -Wextra -Wunsafe-loop-optimizations -Wstack-protector"
+else
+ WARN=""
+fi
+
+if test "x$GXX" = xyes ; then
+ WARN="-Wall -Wextra -Wunsafe-loop-optimizations -Wstack-protector"
+else
+ WARN=""
+fi
+
+CFLAGS="$CFLAGS $WARN"
+CXXFLAGS="$CXXFLAGS $WARN"
+
+AC_OUTPUT([Makefile
+ src/Makefile])
+
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100755
index 0000000..c363b8d
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,27 @@
+# Copyright © 2009 Ian D. Romanick
+# All Rights Reserved.
+#
+# 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
+# on the rights to use, copy, modify, merge, publish, distribute, sub
+# license, 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 NON-INFRINGEMENT. IN NO EVENT SHALL
+# AUTHORS, COPYRIGHT HOLDERS, AND/OR THEIR SUPPLIERS 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.
+
+bin_PROGRAMS = camera_demo
+camera_demo_SOURCES = main.cpp bezier.cpp model_consumer.cpp
+
+AM_CXXFLAGS= $(GLU3_CFLAGS)
+camera_demo_LDADD = $(GLU3_LIBS)
diff --git a/src/bezier.cpp b/src/bezier.cpp
new file mode 100755
index 0000000..e3fa37d
--- /dev/null
+++ b/src/bezier.cpp
@@ -0,0 +1,34 @@
+/*
+ * Copyright © 2009, 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 "bezier.h"
+
+GLUvec4
+bezier_curve::position(float t) const
+{
+ /* FINISHME: Implement this function.
+ */
+ GLUvec4 result(0.0, 0.0, 0.0, 0.0);
+
+ return result;
+}
diff --git a/src/bezier.h b/src/bezier.h
new file mode 100755
index 0000000..9bff5e9
--- /dev/null
+++ b/src/bezier.h
@@ -0,0 +1,60 @@
+/* -*- c++ -*- */
+/*
+ * Copyright © 2009, 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>
+
+class bezier_curve {
+public:
+ bezier_curve(void) { }
+
+ inline bezier_curve(const GLUvec4 *control_points)
+ {
+ this->p[0] = control_points[0];
+ this->p[1] = control_points[1];
+ this->p[2] = control_points[2];
+ this->p[3] = control_points[3];
+ }
+
+ inline bezier_curve(const GLUvec4 &p0, const GLUvec4 &p1,
+ const GLUvec4 &p2, const GLUvec4 &p3)
+ {
+ this->p[0] = p0;
+ this->p[1] = p1;
+ this->p[2] = p2;
+ this->p[3] = p3;
+ }
+
+ /**
+ * Evaluate the position on a curve at a particular parameter value.
+ */
+ GLUvec4 position(float t) const;
+
+ const GLUvec4 &operator[](unsigned i) const
+ {
+ return this->p[i];
+ }
+
+private:
+ GLUvec4 p[4];
+};
diff --git a/src/main.cpp b/src/main.cpp
new file mode 100755
index 0000000..b272f67
--- /dev/null
+++ b/src/main.cpp
@@ -0,0 +1,474 @@
+/*
+ * Copyright © 2009, 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 <GL/glew.h>
+#include <SDL.h>
+
+#include <glu3.h>
+
+#include "bezier.h"
+#include "patch_set.h"
+
+#define BUFFER_OFFSET(i) ((char *)NULL + (i))
+#define ELEMENTS_OF(x) (sizeof(x) / sizeof(x[0]))
+
+static SDL_Surface *my_surf = NULL;
+
+static bool anim = true;
+static bool done = false;
+
+static GLUvec4 eye(0.0, 1.5f, 10.0f, 0.0f);
+
+/**
+ * Points in 3-space that the camera must hit.
+ */
+static const GLUvec4 linear_control_points[] = {
+ GLUvec4(0.0, 1.5f, 10.0f, 0.0f),
+ GLUvec4(10.0, 1.5f, 0.0f, 0.0f),
+ GLUvec4(-30.0, 1.5f, -30.0f, 0.0f),
+
+};
+
+/**
+ * Basic C0 cameara control curves that hit the points in linear_control_points
+ *
+ * FINISHME: Fill these in.
+ */
+#if 0
+static const bezier_curve camera_curves[] = {
+ bezier_curve(GLUvec4(...), // start point
+ GLUvec4(...), // control
+ GLUvec4(...), // control
+ GLUvec4(...)), // end point
+ ...
+};
+#endif
+
+/**
+ * Control curves from camera_curves "fixed" to be G1.
+ *
+ * \sa make_curves_g1
+ */
+#if 0
+static bezier_curve camera_curves_G1[ELEMENTS_OF(camera_curves)];
+#endif
+
+/**
+ * Control curves from camera_curves "fixed" to be C1.
+ *
+ * \sa make_curves_c1
+ */
+#if 0
+static bezier_curve camera_curves_C1[ELEMENTS_OF(camera_curves)];
+#endif
+
+/**
+ * Positions in 3-space of the spheres.
+ */
+static const GLUvec4 sphere_locations[] = {
+ GLUvec4(3.0, 0.0, 0.0, 0.0),
+ GLUvec4(-3.0, 0.0, 0.0, 0.0),
+ GLUvec4(0.0, 0.0, 3.0, 0.0),
+ GLUvec4(0.0, 4.0, 0.0, 0.0),
+};
+
+static float specular_exponent[ELEMENTS_OF(sphere_locations)] = {
+ 198.0,
+ 64.0,
+ 32.0,
+ 4.0,
+};
+
+/**
+ * Selects the camera control mode.
+ */
+enum {
+ camera_linear,
+ camera_G0,
+ camera_C1,
+} camera_mode = camera_linear;
+
+static Uint32 t0;
+
+static GLUmat4 projection_matrix;
+
+static GLuint prog;
+static GLint mvp_location;
+static GLint mv_location;
+static GLint s_location;
+
+static patch_set_info *object = NULL;
+
+static void
+Redisplay(const patch_set_info *info)
+{
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ const GLUvec4 ref(0.0f, 0.0f, 0.0f, 1.0f);
+ const GLUvec4 up(0.0f, 1.0f, 0.0f, 0.0f);
+ const GLUmat4 view(gluLookAt(eye, ref, up));
+
+ GLUmat4 model(gluRotate(GLUvec4(1.0, 0.0, 0.0, 0.0), 3.0 * M_PI_2));
+
+ glUseProgram(prog);
+ glBindBuffer(GL_ARRAY_BUFFER, info->buffer_object);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, info->buffer_object);
+
+ for (unsigned attr = 0; attr < info->num_attribs; attr++)
+ glVertexAttribPointer(attr,
+ info->attribs[attr].size,
+ info->attribs[attr].type,
+ GL_FALSE,
+ info->attribs[attr].stride,
+ BUFFER_OFFSET(info->attribs[attr].base));
+
+
+ for (unsigned i = 0; i < ELEMENTS_OF(sphere_locations); i++) {
+ const GLUmat4 m(gluTranslate(sphere_locations[i])
+ * model);
+ const GLUmat4 mv(view * m);
+ const GLUmat4 mvp(projection_matrix * mv);
+
+ glUniform1f(s_location, specular_exponent[i]);
+ glUniformMatrix4fv(mvp_location, 1, false, (float *) &mvp);
+ glUniformMatrix4fv(mv_location, 1, false, (float *) &mv);
+
+ glMultiDrawElements(info->mode, info->count, info->type,
+ (const GLvoid**) info->indices,
+ info->num_patches);
+ }
+
+ SDL_GL_SwapBuffers();
+}
+
+
+static void
+Idle(void)
+{
+ static Uint32 last_t = ~0;
+ Uint32 t = SDL_GetTicks();
+
+
+ if (last_t != (Uint32)~0) {
+ float dt = (float) (t - last_t) / 1000.0f;
+
+ if (anim) {
+ static float total_t = 0.0;
+
+ /* FINISHME: Perform some calculations so that the
+ * FINISHME: timer wraps around to zero when the last
+ * FINISHME: segment of the camera track is completed.
+ */
+ total_t = fmod(total_t + dt, 10.0);
+
+ /* FINISHME: Based on the timer, determine which
+ * FINISHME: segment of the camera track is active.
+ */
+
+ /* FINISHME: Calculate t_segment as the time within the
+ * FINISHME: active segment.
+ */
+
+
+ /* FINISHME: Calculate the camera position from the
+ * FINISHME: active segement and t_segment.
+ */
+ }
+ }
+
+ last_t = t;
+}
+
+
+/* Load, compile, link, etc. the vertex and fragment programs.
+ */
+static void
+load_and_compile_program_code(const char *shader)
+{
+ char buf[512];
+
+ if (!gluInitializeCompiler()) {
+ printf("GLSL not supported.\n");
+ exit(1);
+ }
+
+ snprintf(buf, sizeof(buf), "../src/%s.vert", shader);
+
+ const char *const vs_code = gluLoadTextFile(buf);
+
+ snprintf(buf, sizeof(buf), "../src/%s.frag", shader);
+
+ const char *const fs_code = gluLoadTextFile(buf);
+
+ char *vs_log = NULL;
+ char *fs_log = NULL;
+ GLuint vs = gluCompileShader(GL_VERTEX_SHADER, vs_code,
+ &vs_log);
+ GLuint fs = gluCompileShader(GL_FRAGMENT_SHADER, fs_code,
+ &fs_log);
+
+ if ((vs != 0) && (fs != 0)) {
+ prog = glCreateProgram();
+
+ gluAttachShaders(prog, vs, fs, 0);
+ gluBindAttributes(prog,
+ "normal", 1,
+ "tangent", 2,
+ "uv", 3,
+ NULL);
+ if (gluLinkProgram(prog, NULL)) {
+ glUseProgram(prog);
+ mvp_location = glGetUniformLocation(prog, "mvp");
+ mv_location = glGetUniformLocation(prog, "mv");
+ s_location = glGetUniformLocation(prog, "s");
+ } else {
+ glDeleteProgram(prog);
+ prog = 0;
+ }
+ } else {
+ printf("Vertex shader log:\n");
+ if (vs_log != NULL) {
+ printf("%s\n", vs_log);
+ gluReleaseInfoLog(vs_log);
+ }
+
+ printf("Fragment shader log:\n");
+ if (fs_log != NULL) {
+ printf("%s\n", fs_log);
+ gluReleaseInfoLog(fs_log);
+ }
+ }
+
+ gluUnloadTextFile(vs_code);
+ gluUnloadTextFile(fs_code);
+}
+
+
+/**
+ * Modify the control points of two C0 curves to make the G1
+ *
+ * The curves generated by this function will only modify the neighboring
+ * control points. This means that the first control point of \c s0 and the
+ * second control point \c s1 are unmodified.
+ *
+ * \param s0 First input curve
+ * \param s1 Second input curve
+ * \param d0 First output curve
+ * \param d1 Second output curve
+ */
+void
+make_curves_G1(const bezier_curve &s0, const bezier_curve &s1,
+ bezier_curve &d0, bezier_curve &d1)
+{
+ /* FINISHME: Implement this function.
+ */
+}
+
+
+/**
+ * Modify the control points of two C0 curves to make the C1
+ *
+ * The curves generated by this function will only modify the neighboring
+ * control points. This means that the first control point of \c s0 and the
+ * second control point \c s1 are unmodified.
+ *
+ * \param s0 First input curve
+ * \param s1 Second input curve
+ * \param d0 First output curve
+ * \param d1 Second output curve
+ */
+void
+make_curves_C1(const bezier_curve &s0, const bezier_curve &s1,
+ bezier_curve &d0, bezier_curve &d1)
+{
+ /* FINISHME: Implement this function.
+ */
+}
+
+
+static void
+Init(void)
+{
+ if (!GLEW_VERSION_2_0) {
+ printf ("Sorry, this demo requires OpenGL 2.0 or later.\n");
+ exit(1);
+ }
+
+ load_and_compile_program_code("phong");
+ if (prog == 0) {
+ exit(1);
+ }
+
+
+ glEnable(GL_DEPTH_TEST);
+ glEnable(GL_CULL_FACE);
+ glClearColor(0.3, 0.3, 0.3, 1.0);
+
+ object = generate_sphere();
+
+ glEnableVertexAttribArray(0);
+ glEnableVertexAttribArray(1);
+ glEnableVertexAttribArray(2);
+ glEnableVertexAttribArray(3);
+
+ printf("GL_RENDERER = %s\n", (const char *) glGetString(GL_RENDERER));
+ printf("Keyboard input:\n"
+ " f: Toggle fullscreen.\n"
+ " a: Toggle animation of object.\n"
+ " c: Re-load and compile shader program code.\n"
+ " ESC: Exit program.\n");
+
+ /* FINISHME: Invoke make_curves_G1 here to fix the basic curves.
+ */
+
+ /* FINISHME: Invoke make_curves_C1 here to fix the basic curves.
+ */
+}
+
+
+static void
+Reshape(int width, int height)
+{
+ my_surf = SDL_SetVideoMode(width, height, 0,
+ SDL_OPENGL | SDL_RESIZABLE);
+ if (my_surf == NULL) {
+ exit(1);
+ }
+
+ glewInit();
+
+ const float aspect = float(width) / float(height);
+ gluPerspective4f(& projection_matrix, 55.0f * M_PI / 180.0f,
+ aspect, 5.0f, 56.0f);
+
+ glViewport(0, 0, width, height);
+}
+
+
+static void
+Key(SDLKey sym, bool state)
+{
+ if (!state)
+ return;
+
+ /* FINISHME: Add controls to cycle through the 3 camera control modes.
+ */
+
+ switch (sym) {
+ case SDLK_ESCAPE:
+ done = true;
+ break;
+
+ case 'f':
+ SDL_WM_ToggleFullScreen(my_surf);
+ break;
+
+ case ' ':
+ case 'a':
+ anim = !anim;
+ break;
+
+ case 'c':
+ printf("Reloading and compiling program code...\n");
+ load_and_compile_program_code("phong");
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+/**
+ * Push an event each time the timer callback fires.
+ */
+Uint32
+timer_callback(Uint32 interval, void *not_used)
+{
+ SDL_Event e;
+
+ (void) not_used;
+
+ e.type = SDL_USEREVENT;
+ e.user.code = 0;
+ e.user.data1 = NULL;
+ e.user.data2 = NULL;
+ SDL_PushEvent(& e);
+
+ return interval;
+}
+
+
+int
+main(int argc, char **argv)
+{
+ (void) argc;
+ (void) argv;
+
+ if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) < 0) {
+ exit(1);
+ }
+
+ atexit(SDL_Quit);
+
+ Reshape(800, 600);
+ Init();
+
+ SDL_TimerID timer_id = SDL_AddTimer(10, timer_callback, NULL);
+ t0 = SDL_GetTicks();
+
+ while (!done) {
+ SDL_Event event;
+
+ SDL_WaitEvent(&event);
+ do {
+ switch (event.type) {
+ case SDL_VIDEORESIZE:
+ Reshape(event.resize.w, event.resize.h);
+ break;
+
+ case SDL_QUIT:
+ done = true;
+ break;
+
+ case SDL_KEYDOWN:
+ Key(event.key.keysym.sym, true);
+ break;
+
+ case SDL_KEYUP:
+ Key(event.key.keysym.sym, false);
+ break;
+
+ default:
+ break;
+ }
+ } while (SDL_PollEvent(&event));
+
+ Idle();
+ Redisplay(object);
+ }
+
+ SDL_RemoveTimer(timer_id);
+
+ SDL_Quit();
+ return 0;
+}
diff --git a/src/model_consumer.cpp b/src/model_consumer.cpp
new file mode 100755
index 0000000..39d044f
--- /dev/null
+++ b/src/model_consumer.cpp
@@ -0,0 +1,143 @@
+/*
+ * 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 <GL/glew.h>
+#include <glu3.h>
+#include "patch_set.h"
+
+#define ROUND_UP(s, u) (((s + (u - 1)) / u) * u)
+
+class model_consumer : public GLUshapeConsumer {
+public:
+ model_consumer(void *data, void *first_elt, patch_set_info *info)
+ : base(data), first_elt(first_elt), info(info),
+ current_primitive(-1)
+ {
+ this->elt = (GLushort *) this->first_elt;
+ }
+
+ virtual void begin_primitive(GLenum mode, unsigned count)
+ {
+ this->info->mode = mode;
+
+ this->current_primitive++;
+
+ const int idx = this->current_primitive;
+ this->info->count[idx] = count;
+ this->info->indices[idx] =
+ (void *)((char *) this->elt - (char *) this->base);
+ this->info->basevertex[idx] = 0;
+ }
+
+ virtual void index_batch(const unsigned *idx, unsigned count)
+ {
+ for (unsigned i = 0; i < count; i++)
+ this->elt[i] = GLushort(idx[i]);
+
+ this->elt += count;
+ }
+
+private:
+ void *base;
+ void *first_elt;
+ GLushort *elt;
+ patch_set_info *info;
+ int current_primitive;
+};
+
+static patch_set_info *
+generate_common(GLUshapeProducer &prod)
+{
+ patch_set_info *info = new patch_set_info;
+
+ const unsigned num_verts = prod.vertex_count();
+
+ info->num_attribs = 4;
+ info->attribs[0].base = (4 * sizeof(GLfloat)) * (0 * num_verts);
+ info->attribs[0].size = 4;
+ info->attribs[0].type = GL_FLOAT;
+ info->attribs[0].stride = 4 * sizeof(GLfloat);
+
+ info->attribs[1].base = (4 * sizeof(GLfloat)) * (1 * num_verts);
+ info->attribs[1].size = 4;
+ info->attribs[1].type = GL_FLOAT;
+ info->attribs[1].stride = 4 * sizeof(GLfloat);
+
+ info->attribs[2].base = (4 * sizeof(GLfloat)) * (2 * num_verts);
+ info->attribs[2].size = 4;
+ info->attribs[2].type = GL_FLOAT;
+ info->attribs[2].stride = 4 * sizeof(GLfloat);
+
+ info->attribs[3].base = (4 * sizeof(GLfloat)) * (3 * num_verts);
+ info->attribs[3].size = 2;
+ info->attribs[3].type = GL_FLOAT;
+ info->attribs[3].stride = 4 * sizeof(GLfloat);
+
+ info->num_patches = prod.primitive_count();
+ info->count = new GLsizei[info->num_patches];
+ info->type = GL_UNSIGNED_SHORT;
+ info->indices = new GLvoid*[info->num_patches];
+ info->basevertex = new GLint[info->num_patches];
+
+
+ /* The vertex stride needs to be an even multiple of GLUvec4 because
+ * each GLUvec4 element needs to be sizeof(GLUvec4) aligned.
+ */
+ info->vertex_stride = ROUND_UP((4 * sizeof(GLfloat)) // position
+ + (4 * sizeof(GLfloat))// normal
+ + (4 * sizeof(GLfloat))// tangent
+ + (2 * sizeof(GLfloat)),// tex coord
+ sizeof(GLUvec4));
+
+ const size_t size = (info->vertex_stride * num_verts)
+ + (sizeof(GLushort) * prod.element_count());
+
+ glGenBuffers(1, & info->buffer_object);
+ glBindBuffer(GL_ARRAY_BUFFER, info->buffer_object);
+ glBufferData(GL_ARRAY_BUFFER, size, NULL, GL_STATIC_DRAW);
+
+ GLUvec4 *const p =
+ (GLUvec4 *) glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
+ model_consumer cons(p, (char *) p + (info->vertex_stride * num_verts),
+ info);
+
+ cons.position = &p[0 * num_verts];
+ cons.normal = &p[1 * num_verts];
+ cons.tangent = &p[2 * num_verts];
+ cons.uv = &p[3 * num_verts];
+ cons.vertex_count = num_verts;
+
+ prod.generate(&cons);
+
+ glUnmapBuffer(GL_ARRAY_BUFFER);
+
+ return info;
+}
+
+
+patch_set_info *
+generate_sphere(void)
+{
+ GLUsphereProducer prod(2.0, 16, 10);
+
+ return generate_common(prod);
+}
diff --git a/src/patch_set.h b/src/patch_set.h
new file mode 100755
index 0000000..571d212
--- /dev/null
+++ b/src/patch_set.h
@@ -0,0 +1,49 @@
+/* -*- c++ -*- */
+/*
+ * 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.
+ */
+
+struct patch_set_info {
+ unsigned num_patches;
+
+ GLuint buffer_object;
+
+ unsigned vertex_stride;
+
+ unsigned num_attribs;
+
+ struct {
+ unsigned base;
+ unsigned size;
+ GLenum type;
+ unsigned stride;
+ } attribs[8];
+
+
+ GLenum mode;
+ GLsizei *count;
+ GLenum type;
+ GLvoid **indices;
+ GLint *basevertex;
+};
+
+patch_set_info *generate_sphere(void);
diff --git a/src/phong.frag b/src/phong.frag
new file mode 100755
index 0000000..3385f68
--- /dev/null
+++ b/src/phong.frag
@@ -0,0 +1,20 @@
+varying vec4 normal_es;
+varying vec4 position_es;
+varying vec2 texcoord;
+
+/* Specular exponent.
+ */
+uniform float s;
+
+/* Position of the light in eye-space.
+ */
+const vec4 light_es = vec4(0.0, 3.0, 0.0, 1.0);
+
+void main(void)
+{
+ /* FINISHME: Calculate lighting.
+ */
+ vec4 color = vec4(1.0, 0.0, 0.0, 1.0);
+
+ gl_FragColor = color;
+}
diff --git a/src/phong.vert b/src/phong.vert
new file mode 100755
index 0000000..4e7ca2e
--- /dev/null
+++ b/src/phong.vert
@@ -0,0 +1,24 @@
+uniform mat4 mvp;
+uniform mat4 mv;
+
+attribute vec4 normal;
+attribute vec2 uv;
+
+/* Normal transformed to eye space.
+ */
+varying vec4 normal_es;
+
+/* Vertex position transformed to eye space.
+ */
+varying vec4 position_es;
+
+void main(void)
+{
+ gl_Position = mvp * gl_Vertex;
+
+ /* FINISHME: Calculate normal_es.
+ */
+
+ /* FINISHME: Calculate position_es.
+ */
+}