summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am32
-rw-r--r--complex-points.sln20
-rw-r--r--complex-points.vcxproj92
-rw-r--r--config.h.in79
-rw-r--r--configure.ac100
-rw-r--r--data/angle_addition.vert13
-rw-r--r--data/ellipse.frag8
-rw-r--r--data/explicit_rotation.vert13
-rw-r--r--data/matrix_rotation.vert10
-rw-r--r--src/Makefile.am27
-rw-r--r--src/main.cpp499
-rw-r--r--src/shader.cpp69
-rw-r--r--src/shader.h41
13 files changed, 1003 insertions, 0 deletions
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..4efa30e
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,32 @@
+# Copyright © 2012 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
+
+EXTRA_DIST = \
+ data/angle_addition.vert \
+ data/ellipse.frag \
+ data/explicit_rotation.vert \
+ data/matrix_rotation.vert \
+ complex-points.vcxproj \
+ complex-points.sln
diff --git a/complex-points.sln b/complex-points.sln
new file mode 100644
index 0000000..90206a5
--- /dev/null
+++ b/complex-points.sln
@@ -0,0 +1,20 @@
+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "complex-points", "complex-points.vcxproj", "{72889E2D-CE6A-8AA3-4376-187DDC442361}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {72889E2D-CE6A-8AA3-4376-187DDC442361}.Debug|Win32.ActiveCfg = Debug|Win32
+ {72889E2D-CE6A-8AA3-4376-187DDC442361}.Debug|Win32.Build.0 = Debug|Win32
+ {72889E2D-CE6A-8AA3-4376-187DDC442361}.Release|Win32.ActiveCfg = Release|Win32
+ {72889E2D-CE6A-8AA3-4376-187DDC442361}.Release|Win32.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/complex-points.vcxproj b/complex-points.vcxproj
new file mode 100644
index 0000000..078eb86
--- /dev/null
+++ b/complex-points.vcxproj
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <Keyword>Win32Proj</Keyword>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <LinkIncremental>true</LinkIncremental>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <LinkIncremental>true</LinkIncremental>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <PreprocessorDefinitions>WIN32;_USE_MATH_DEFINES;_DEBUG;_CONSOLE;%(PreprocessorDefinitions);USE_MATH_DEFINES</PreprocessorDefinitions>
+ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>$(ProjectDir)\src;$(ProjectDir)\..\include\SDL;$(ProjectDir)\..\include\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Link>
+ <TargetMachine>MachineX86</TargetMachine>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <SubSystem>Console</SubSystem>
+ <AdditionalLibraryDirectories>$(ProjectDir)\..\lib;$(ProjectDir)\..\lib\Debug;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <AdditionalDependencies>opengl32.lib;glew32.lib;SDL.lib;SDLmain.lib;glu3.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <PreprocessorDefinitions>WIN32;_USE_MATH_DEFINES;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ </ClCompile>
+ <Link>
+ <TargetMachine>MachineX86</TargetMachine>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <SubSystem>Console</SubSystem>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ <AdditionalDependencies>opengl32.lib;glew32s.lib;SDL.lib;SDLmain.lib;glu3.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <AdditionalLibraryDirectories>$(ProjectDir)\..\..\lib\;$(ProjectDir)\..\lib\Release;$(ProjectDir)\..\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="src\main.cpp" />
+ <ClCompile Include="src\shader.cpp" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="config.h" />
+ <ClInclude Include="src\shader.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="data\angle_addition.vert" />
+ <None Include="data\ellipse.frag" />
+ <None Include="data\explicit_rotation.vert" />
+ <None Include="data\matrix_rotation.vert" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/config.h.in b/config.h.in
new file mode 100644
index 0000000..d424c01
--- /dev/null
+++ b/config.h.in
@@ -0,0 +1,79 @@
+/* config.h.in. Generated from configure.ac by autoheader. */
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#undef HAVE_FCNTL_H
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the `GL' library (-lGL). */
+#undef HAVE_LIBGL
+
+/* Define to 1 if you have the `GLEW' library (-lGLEW). */
+#undef HAVE_LIBGLEW
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Name of package */
+#undef PACKAGE
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the home page for this package. */
+#undef PACKAGE_URL
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Version number of package */
+#undef VERSION
+
+/* Define for Solaris 2.5.1 so the uint8_t typedef from <sys/synch.h>,
+ <pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the
+ #define below would cause a syntax error. */
+#undef _UINT8_T
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+#undef size_t
+
+/* Define to `int' if <sys/types.h> does not define. */
+#undef ssize_t
+
+/* Define to the type of an unsigned integer type of width exactly 8 bits if
+ such a type exists and the standard includes do not define it. */
+#undef uint8_t
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..adc4ee2
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,100 @@
+# -*- Autoconf -*-
+# Process this file with autoconf to produce a configure script.
+
+AC_PREREQ(2.61)
+AC_INIT(ellipse, 2012Q4.1, idr@freedesktop.org, complex-plane-points)
+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
+
+# Checks for libraries.
+
+# Checks for header files.
+AC_CHECK_HEADERS([fcntl.h unistd.h])
+
+# Checks for typedefs, structures, and compiler characteristics.
+AC_TYPE_SIZE_T
+AC_TYPE_SSIZE_T
+AC_TYPE_UINT8_T
+
+# 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/data/angle_addition.vert b/data/angle_addition.vert
new file mode 100644
index 0000000..f410305
--- /dev/null
+++ b/data/angle_addition.vert
@@ -0,0 +1,13 @@
+#version 120
+
+attribute vec2 z;
+uniform float rotation_angle;
+
+void main()
+{
+ gl_Position.x = z.x;
+ gl_Position.y = z.y;
+ gl_Position.z = 0.;
+ gl_Position.w = 1.;
+ gl_PointSize = 32.;
+}
diff --git a/data/ellipse.frag b/data/ellipse.frag
new file mode 100644
index 0000000..bf35027
--- /dev/null
+++ b/data/ellipse.frag
@@ -0,0 +1,8 @@
+#version 120
+
+uniform mat2 m = mat2(1.);
+
+void main()
+{
+ gl_FragColor = vec4(1.0);
+}
diff --git a/data/explicit_rotation.vert b/data/explicit_rotation.vert
new file mode 100644
index 0000000..f410305
--- /dev/null
+++ b/data/explicit_rotation.vert
@@ -0,0 +1,13 @@
+#version 120
+
+attribute vec2 z;
+uniform float rotation_angle;
+
+void main()
+{
+ gl_Position.x = z.x;
+ gl_Position.y = z.y;
+ gl_Position.z = 0.;
+ gl_Position.w = 1.;
+ gl_PointSize = 32.;
+}
diff --git a/data/matrix_rotation.vert b/data/matrix_rotation.vert
new file mode 100644
index 0000000..af9165d
--- /dev/null
+++ b/data/matrix_rotation.vert
@@ -0,0 +1,10 @@
+#version 120
+
+attribute vec2 z;
+uniform mat2 m = mat2(1.);
+
+void main()
+{
+ gl_Position = vec4(m * z, 0.0, 1.0);
+ gl_PointSize = 32.;
+}
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..19b90d5
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,27 @@
+# Copyright © 2012 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 = complex-plane
+complex_plane_SOURCES = main.cpp shader.cpp
+
+AM_CXXFLAGS= $(GLU3_CFLAGS)
+complex_plane_LDADD = $(GLU3_LIBS)
diff --git a/src/main.cpp b/src/main.cpp
new file mode 100644
index 0000000..083427c
--- /dev/null
+++ b/src/main.cpp
@@ -0,0 +1,499 @@
+/*
+ * Copyright © 2012 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 <math.h>
+#include <GL/glew.h>
+#include <glu3.h>
+#include <SDL.h>
+#include <assert.h>
+#include "shader.h"
+
+#define NUM_POINTS 57
+
+static SDL_Surface *my_surf = NULL;
+
+static bool anim = true;
+static bool done = false;
+static int shift_status = 0;
+
+static float angle_offset = 0.0f;
+
+static GLuint buf = 0;
+
+class complex_points_program : public shader_program {
+public:
+ complex_points_program(GLuint vs, GLuint fs)
+ : shader_program(vs, fs, 0)
+ {
+ /* empty */
+ }
+
+ void get_uniform_locations()
+ {
+ this->angle_uniform =
+ glGetUniformLocation(this->program, "rotation_angle");
+ this->matrix_uniform =
+ glGetUniformLocation(this->program, "m");
+ }
+
+ GLint angle_uniform;
+ GLint matrix_uniform;
+};
+
+static complex_points_program *explicit_rotation = 0;
+static complex_points_program *angle_addition = 0;
+static complex_points_program *matrix_rotation = 0;
+
+static GLuint timer_queries[3] = { 0, 0, 0 };
+
+#define BUFFER_OFFSET(i) ((char *)0 + (i))
+
+#define CHECK_GL_ERROR(e) \
+ do { \
+ e = glGetError(); \
+ if (e != 0) { \
+ printf("%s:%u: GL error = 0x%04x\n", __func__, \
+ __LINE__, e); \
+ } \
+ } while (0)
+
+
+static void
+Redisplay(void)
+{
+ const float m[4] = {
+ 1.0, 0.0,
+ 0.0, 1.0
+ };
+
+
+ /* Set the viewport to the whole window and clear the screen.
+ */
+ glViewport(0, 0, my_surf->w, my_surf->h);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+
+ /* Reset the viewport ot the lower left quadrant and draw using the
+ * "explicit rotation" shader. This shader uses the vertex data
+ * stored as (real, imaginary) pairs.
+ */
+ glViewport(0, 0, my_surf->w / 2, my_surf->h / 2);
+
+ glUseProgram(explicit_rotation->program);
+ glUniform1f(explicit_rotation->angle_uniform, angle_offset);
+ glUniformMatrix2fv(explicit_rotation->matrix_uniform, 1, false, m);
+
+ if (timer_queries[0])
+ glBeginQuery(GL_TIME_ELAPSED, timer_queries[0]);
+
+ glDrawArrays(GL_POINTS, 0, NUM_POINTS);
+
+ if (timer_queries[0])
+ glEndQuery(GL_TIME_ELAPSED);
+
+
+ /* Reset the viewport to the upper left quadrant and draw using the
+ * "angle addition" shader. This shader uses the vertex data stored
+ * as (modulus, angle) pairs.
+ */
+ glViewport(0, my_surf->h / 2, my_surf->w / 2, my_surf->h / 2);
+
+ glUseProgram(angle_addition->program);
+ glUniform1f(angle_addition->angle_uniform, angle_offset);
+ glUniformMatrix2fv(angle_addition->matrix_uniform, 1, false, m);
+
+ if (timer_queries[1])
+ glBeginQuery(GL_TIME_ELAPSED, timer_queries[1]);
+
+ glDrawArrays(GL_POINTS, NUM_POINTS, NUM_POINTS);
+
+ if (timer_queries[1])
+ glEndQuery(GL_TIME_ELAPSED);
+
+ /* Reset the viewport to the upper right quadrant and draw using the
+ * "matrix rotation" shader. This shader uses the vertex data stored
+ * as (real, imaginary) pairs.
+ */
+ glViewport(my_surf->w / 2, my_surf->h / 2,
+ my_surf->w / 2, my_surf->h / 2);
+
+ glUseProgram(matrix_rotation->program);
+ glUniform1f(matrix_rotation->angle_uniform, angle_offset);
+ glUniformMatrix2fv(matrix_rotation->matrix_uniform, 1, false, m);
+
+ if (timer_queries[2])
+ glBeginQuery(GL_TIME_ELAPSED, timer_queries[2]);
+
+ glDrawArrays(GL_POINTS, 0, NUM_POINTS);
+
+ if (timer_queries[2])
+ glEndQuery(GL_TIME_ELAPSED);
+
+ SDL_GL_SwapBuffers();
+
+ assert((timer_queries[0] == 0) == (timer_queries[1] == 0));
+ if (timer_queries[0]) {
+ static GLuint64 totals[3] = { 0, 0, 0 };
+ static unsigned count = 0;
+ GLuint64 result[3] = { 0, 0, 0 };
+
+ for (unsigned i = 0; i < 3; i++) {
+ glGetQueryObjectui64vEXT(timer_queries[i],
+ GL_QUERY_RESULT,
+ &result[i]);
+ totals[i] += result[i];
+ }
+
+ count++;
+ if (count > 100) {
+ printf("Timings: %lu, %lu, %lu\n",
+ totals[0] / 100,
+ totals[1] / 100,
+ totals[2] / 100);
+
+ memset(totals, 0, sizeof(totals));
+ count = 0;
+ }
+ }
+}
+
+
+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) {
+ angle_offset += M_PI * dt;
+ }
+ }
+
+ last_t = t;
+}
+
+
+
+
+static GLuint
+compile_shader_from_file(GLenum target, const char *filename)
+{
+ static const char *const paths_to_try[] = {
+ "",
+ "data/",
+ "../data/",
+ 0
+ };
+
+ GLuint shader;
+ char *log = NULL;
+ const char *code;
+
+ const size_t name_len = strlen(filename);
+ for (unsigned i = 0; paths_to_try[i] != 0; i++) {
+ const size_t path_len = strlen(paths_to_try[i]);
+ char *name_with_path = new char [path_len + name_len + 1];
+
+ memcpy(name_with_path, paths_to_try[i], path_len);
+ memcpy(&name_with_path[path_len], filename, name_len);
+ name_with_path[path_len + name_len] = '\0';
+
+ code = gluLoadTextFile(name_with_path);
+ delete [] name_with_path;
+
+ if (code != NULL)
+ break;
+ }
+
+ if (code == NULL) {
+ fprintf(stderr, "Unable to load shader code for %s.\n",
+ filename);
+ exit(1);
+ }
+
+ shader = gluCompileShader(target, code, &log);
+ if (log != NULL) {
+ printf("Shader compile log for %s:\n%s\n", filename, log);
+ gluReleaseInfoLog(log);
+ log = NULL;
+ }
+
+ if (shader == 0) {
+ fprintf(stderr, "Failed to compile %s.\n", filename);
+ exit(1);
+ }
+
+ gluUnloadTextFile(code);
+
+ return shader;
+}
+
+
+static complex_points_program *
+create_program(GLuint vs, GLuint fs, const char *name)
+{
+ complex_points_program *p = new complex_points_program(vs, fs);
+
+ const bool linked = p->link();
+ if (p->log != NULL)
+ printf("%s link log:\n%s\n", name, p->log);
+
+ if (!linked) {
+ fprintf(stderr, "Failed to link %s.\n", name);
+ exit(1);
+ }
+
+ p->get_uniform_locations();
+ return p;
+}
+
+/* Load, compile, link, etc. the vertex and fragment programs.
+ */
+static void
+build_all_shaders(void)
+{
+ GLuint vs[3];
+ GLuint fs;
+
+ /* If there are dangling instances of these program hanging around,
+ * clean them up.
+ */
+ if (explicit_rotation)
+ delete explicit_rotation;
+
+ if (angle_addition)
+ delete angle_addition;
+
+ if (matrix_rotation)
+ delete matrix_rotation;
+
+
+ /* Compile all of the shaders
+ */
+ vs[0] = compile_shader_from_file(GL_VERTEX_SHADER,
+ "explicit_rotation.vert");
+ vs[1] = compile_shader_from_file(GL_VERTEX_SHADER,
+ "angle_addition.vert");
+ vs[2] = compile_shader_from_file(GL_VERTEX_SHADER,
+ "matrix_rotation.vert");
+
+ fs = compile_shader_from_file(GL_FRAGMENT_SHADER,
+ "ellipse.frag");
+
+ /* Create all of the programs that use the previously created shaders.
+ */
+ explicit_rotation = create_program(vs[0], fs, "explicit rotation");
+ angle_addition = create_program(vs[1], fs, "angle addition");
+ matrix_rotation = create_program(vs[2], fs, "matrix rotation");
+
+ /* The individual shaders have been attached to the programs, so they
+ * can safely be deleted.
+ */
+ glDeleteShader(vs[0]);
+ glDeleteShader(vs[1]);
+ glDeleteShader(vs[2]);
+ glDeleteShader(fs);
+}
+
+
+static void
+Init(void)
+{
+ glewInit();
+
+ if (!GLEW_VERSION_2_0) {
+ printf ("Sorry, this demo requires OpenGL 2.0 or later.\n");
+ exit(1);
+ }
+
+ if (GLEW_EXT_timer_query || GLEW_ARB_timer_query)
+ glGenQueries(3, timer_queries);
+
+ gluInitializeCompiler();
+
+ explicit_rotation = 0;
+ angle_addition = 0;
+ matrix_rotation = 0;
+
+ build_all_shaders();
+
+ float data[2 * (2 * NUM_POINTS)];
+
+ for (unsigned i = 0; i < NUM_POINTS; i++) {
+ const float angle = float(i) * M_PI * 2.0f / float(NUM_POINTS);
+ const float r = cos(5.0f * angle) * 0.4f + 0.5f;
+
+ data[(i + 0) * 2 + 0] = r * cos(angle);
+ data[(i + 0) * 2 + 1] = r * sin(angle);
+ data[(i + NUM_POINTS) * 2 + 0] = r;
+ data[(i + NUM_POINTS) * 2 + 1] = angle;
+ }
+
+ glGenBuffers(1, &buf);
+ glBindBuffer(GL_ARRAY_BUFFER, buf);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW);
+
+ glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat),
+ BUFFER_OFFSET(0));
+ glEnableVertexAttribArray(0);
+
+ glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
+
+
+ printf("GL_RENDERER = %s\n", (const char *) glGetString(GL_RENDERER));
+ printf("Keyboard input:\n"
+ " a: Toggle animation of object.\n"
+ " c: Re-load and compile shader program code.\n"
+ " ESC: Exit program.\n");
+}
+
+
+static void
+Reshape(int w, int h)
+{
+ my_surf = SDL_SetVideoMode(w, h, 0, SDL_OPENGL | SDL_RESIZABLE);
+ if (my_surf == NULL) {
+ exit(1);
+ }
+
+ glViewport(0, 0, my_surf->w, my_surf->h);
+ Init();
+}
+
+
+static void
+Key(SDLKey sym)
+{
+ switch (sym) {
+ case SDLK_ESCAPE:
+ done = true;
+ break;
+
+ case ' ':
+ case 'a':
+ anim = !anim;
+ break;
+
+ case 'c':
+ printf("Reloading and compiling program code...\n");
+ build_all_shaders();
+ 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);
+
+ SDL_TimerID timer_id = SDL_AddTimer(10, timer_callback, NULL);
+
+ 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:
+ if ((event.key.keysym.sym == SDLK_RSHIFT)
+ || (event.key.keysym.sym == SDLK_LSHIFT)) {
+ shift_status++;
+ } else {
+ Key(event.key.keysym.sym);
+ }
+ break;
+
+ case SDL_KEYUP:
+ if ((event.key.keysym.sym == SDLK_RSHIFT)
+ || (event.key.keysym.sym == SDLK_LSHIFT)) {
+ shift_status--;
+ }
+
+ /* By clamping the shift status value to 0 we
+ * prevent some bugs when the program is
+ * started with one or both of the shift keys
+ * held down.
+ */
+ if (shift_status < 0) {
+ shift_status = 0;
+ }
+ break;
+
+ default:
+ break;
+ }
+ } while (SDL_PollEvent(&event));
+
+
+ Idle();
+ Redisplay();
+ }
+
+ SDL_RemoveTimer(timer_id);
+
+ SDL_Quit();
+ return 0;
+}
diff --git a/src/shader.cpp b/src/shader.cpp
new file mode 100644
index 0000000..8456362
--- /dev/null
+++ b/src/shader.cpp
@@ -0,0 +1,69 @@
+/*
+ * Copyright © 2012 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 <stdarg.h>
+#include <GL/glew.h>
+#include <glu3.h>
+#include "shader.h"
+
+void shader_program::init()
+{
+ this->program = glCreateProgram();
+ this->log = 0;
+}
+
+shader_program::shader_program()
+{
+ init();
+}
+
+shader_program::shader_program(GLint shader, ...)
+{
+ va_list ap;
+ GLint sh;
+
+ init();
+
+ glAttachShader(this->program, shader);
+
+ va_start(ap, shader);
+ while ((sh = va_arg(ap, GLint)) != 0) {
+ glAttachShader(this->program, sh);
+ }
+ va_end(ap);
+}
+
+shader_program::~shader_program()
+{
+ glDeleteProgram(this->program);
+ this->program = 0;
+
+ if (this->log) {
+ gluReleaseInfoLog(this->log);
+ this->log = 0;
+ }
+}
+
+bool shader_program::link()
+{
+ return gluLinkProgram(this->program, &this->log);
+}
diff --git a/src/shader.h b/src/shader.h
new file mode 100644
index 0000000..5e49dc3
--- /dev/null
+++ b/src/shader.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright © 2012 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.
+ */
+#ifndef SHADER_PROGRAM_H
+#define SHADER_PROGRAM_H
+
+class shader_program {
+public:
+ shader_program();
+ shader_program(GLint shader, ...);
+ ~shader_program();
+
+ bool link();
+
+ GLint program;
+ char *log;
+
+private:
+ void init();
+};
+
+#endif /* SHADER_PROGRAM_H */