diff options
-rw-r--r-- | Makefile.am | 32 | ||||
-rw-r--r-- | complex-points.sln | 20 | ||||
-rw-r--r-- | complex-points.vcxproj | 92 | ||||
-rw-r--r-- | config.h.in | 79 | ||||
-rw-r--r-- | configure.ac | 100 | ||||
-rw-r--r-- | data/angle_addition.vert | 13 | ||||
-rw-r--r-- | data/ellipse.frag | 8 | ||||
-rw-r--r-- | data/explicit_rotation.vert | 13 | ||||
-rw-r--r-- | data/matrix_rotation.vert | 10 | ||||
-rw-r--r-- | src/Makefile.am | 27 | ||||
-rw-r--r-- | src/main.cpp | 499 | ||||
-rw-r--r-- | src/shader.cpp | 69 | ||||
-rw-r--r-- | src/shader.h | 41 |
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 */ |