changeset 23:f080349584b8

Rename from glxdragon to gldragon.
author Matti Hamalainen <ccr@tnsp.org>
date Fri, 22 Nov 2019 05:29:34 +0200
parents 03b86b9c2f29
children c1897cfc8463
files Makefile gldragon.cpp glxdragon.cpp
diffstat 3 files changed, 528 insertions(+), 528 deletions(-) [+]
line wrap: on
line diff
--- a/Makefile	Fri Nov 22 05:29:02 2019 +0200
+++ b/Makefile	Fri Nov 22 05:29:34 2019 +0200
@@ -9,7 +9,7 @@
 CFLAGS += $(SDLGL_CFLAGS)
 LDFLAGS += $(SDLGL_LIBS)
 
-TARGETS = glxdragon$(BINEXT)
+TARGETS = gldragon$(BINEXT)
 
 
 %.o: %.cpp %.h
@@ -19,7 +19,7 @@
 	$(CXX) $(CFLAGS) -c -o $@ $<
 
 
-glxdragon$(BINEXT): glxdragon.o dmmodel.o dmutil.o
+gldragon$(BINEXT): gldragon.o dmmodel.o dmutil.o
 	$(CXX) -o $@ $+ $(LDFLAGS)
 
 clean:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gldragon.cpp	Fri Nov 22 05:29:34 2019 +0200
@@ -0,0 +1,526 @@
+//
+// GLDragon - OpenGL PLY model viewer / simple benchmark
+// Programmed and designed by Matti 'ccr' Hämäläinen <ccr@tnsp.org>
+// (C) Copyright 2019 Tecnic Software productions (TNSP)
+//
+// See file "COPYING" for license information.
+//
+// Originally based on 'glxdragon' Copyright (c) 2009, Thomas Trummer
+//
+#include <SDL.h>
+#include <SDL_opengl.h>
+#include <GL/glu.h>
+#include <GL/glext.h>
+
+#include "dmutil.h"
+#include "dmmodel.h"
+
+
+/* Default settings etc. constants
+ */
+#define SET_DEF_WIDTH        1280
+#define SET_DEF_HEIGHT       960
+#define SET_FRAMES           (180)
+#define SET_MAX_SHADER_SIZE  (128 * 1024)
+
+
+/* Options
+ */
+bool   optUseShaders = false;
+int    optWidth = SET_DEF_WIDTH,
+       optHeight = SET_DEF_HEIGHT,
+       optVSyncMode = 1;
+
+
+
+/* Globals
+ */
+SDL_Window *dmWindow = NULL;
+SDL_GLContext dmGLContext = NULL;
+
+
+/* Helpers
+ */
+bool dmInitSDLGL(const int width, const int height, const char *title)
+{
+    int ret;
+    std::string msg;
+
+    // Set GL attributes
+    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
+    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
+    SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
+
+    SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
+    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
+
+    // Attempt to initialize libSDL
+    if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_EVENTS) != 0)
+    {
+        printf("ERROR: Unable to initialize SDL: %s\n",
+            SDL_GetError());
+        return false;
+    }
+
+    // Attempt to create a window
+    if ((dmWindow = SDL_CreateWindow(title,
+            SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
+            width, height,
+            SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE)) == NULL)
+    {
+        printf("ERROR: Could not create SDL window: %s",
+            SDL_GetError());
+        return false;
+    }
+
+    if ((dmGLContext = SDL_GL_CreateContext(dmWindow)) == NULL)
+    {
+        printf("ERROR: Unable to create SDL OpenGL context: %s\n",
+            SDL_GetError());
+        return false;
+    }
+
+    // Check if we want to attempt to use vsync
+    switch (optVSyncMode)
+    {
+        case 3:
+            ret = SDL_GL_SetSwapInterval(-1);
+            msg = "adaptive vsync";
+            break;
+
+        case 2:
+            ret = SDL_GL_SetSwapInterval(1);
+            msg = "synchronized (vsync)";
+            break;
+
+        case 1:
+            ret = SDL_GL_SetSwapInterval(0);
+            msg = "immediate (no vsync)";
+            break;
+
+        default:
+            ret = -1;
+            msg = "INVALID VSYNC MODE";
+            break;
+    }
+
+    if (ret != 0)
+    {
+        printf("ERROR: Could not set vsync mode to %s.\n",
+            msg.c_str());
+        return false;
+    }
+
+    // Dump some information
+    printf(
+        "GL_VENDOR   : %s\n"
+        "GL_RENDERER : %s\n"
+        "GL_VERSION  : %s\n"
+        "VSync mode  : %s\n",
+        glGetString(GL_VENDOR),
+        glGetString(GL_RENDERER),
+        glGetString(GL_VERSION),
+        msg.c_str());
+
+    // Setup the window and view port
+    glViewport(0, 0, width, height);
+
+    glMatrixMode(GL_PROJECTION);
+    glLoadIdentity();
+
+    gluPerspective(45.0f, GLfloat(width) / GLfloat(height), 0.1f, 1000.0f);
+
+    glMatrixMode(GL_MODELVIEW);
+    glLoadIdentity();
+
+    // Enable back face culling
+    glEnable(GL_CULL_FACE);
+
+    // Enable smooth shading
+    glShadeModel(GL_SMOOTH);
+
+    // Enable the depth buffer
+    glEnable(GL_DEPTH_TEST);
+
+    // Enable normal rescaling
+    glEnable(GL_RESCALE_NORMAL);
+
+    // Setup depth buffer
+    glClearDepth(1.0f);
+
+    // Set the depth buffer function
+    glDepthFunc(GL_LEQUAL);
+
+    // Enable vertex and and normal arrays
+    glEnableClientState(GL_VERTEX_ARRAY);
+    glEnableClientState(GL_NORMAL_ARRAY);
+
+    // Set correct perspective correction
+    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
+
+    return true;
+}
+
+
+void dmDrawModel(const DMModel &model)
+{
+    int maxIndices;
+
+    if (optUseShaders)
+    {
+        // Enable shader program
+        glUseProgram(model.id_prog);
+    }
+    else
+    {
+        // Set the color of the model
+        glEnable(GL_LIGHTING);
+        glColor3ub(0x90, 0x80, 0x90);
+    }
+
+    // Render the model
+    glGetIntegerv(GL_MAX_ELEMENTS_INDICES, &maxIndices);
+
+    glPushMatrix();
+
+    // Add transforms
+    glScalef(model.scale.x, model.scale.y, model.scale.z);
+    glTranslatef(model.translate.x, model.translate.y, model.translate. z);
+    glRotatef(model.rotate.x, 1.0f, 0.0f, 0.0f);
+    glRotatef(model.rotate.y, 0.0f, 1.0f, 0.0f);
+    glRotatef(model.rotate.z, 0.0f, 0.0f, 1.0f);
+
+    glVertexPointer(3, GL_FLOAT, 0, &model.vertices[0]);
+    glNormalPointer(   GL_FLOAT, 0, &model.normals[0]);
+
+    for (int n = 0; n < model.nfaces; n += maxIndices)
+    {
+        const int count = std::min(maxIndices, model.nfaces - n);
+        glDrawElements(GL_TRIANGLES, count * 3, GL_UNSIGNED_INT, &model.faces[n * 3]);
+    }
+
+    glPopMatrix();
+
+    // Restore
+    if (optUseShaders)
+    {
+        glUseProgram(0);
+    }
+}
+
+
+void dmDrawScene(const DMSimpleScene &scene)
+{
+    glClear(GL_DEPTH_BUFFER_BIT);
+
+    glMatrixMode(GL_PROJECTION);
+    glPushMatrix();
+    glLoadIdentity();
+
+    glOrtho(0.0, 1.0, 0.0, 1.0, -1, 1);
+
+    glMatrixMode(GL_MODELVIEW);
+    glPushMatrix();
+    glLoadIdentity();
+
+    // Draw the background gradient
+    glDisable(GL_DEPTH_TEST);
+    glDisable(GL_LIGHTING);
+    glBegin(GL_QUADS);
+    {
+        glColor3ub(0x3B, 0x3B, 0x75);
+        glVertex2f(0.0f, 0.0f);
+        glVertex2f(1.0f, 0.0f);
+
+        glColor3ub(0x00, 0x00, 0x00);
+        glVertex2f(1.0f, 1.0f);
+        glVertex2f(0.0f, 1.0f);
+    }
+    glEnd();
+
+
+    // Restore the 3D projection
+    glMatrixMode(GL_PROJECTION);
+    glPopMatrix();
+
+    glMatrixMode(GL_MODELVIEW);
+    glPopMatrix();
+
+    glEnable(GL_DEPTH_TEST);
+
+    // Draw models
+    for (const DMModel &model : scene.models)
+        dmDrawModel(model);
+}
+
+
+GLuint dmCompileShader(const GLenum stype, const std::string &src)
+{
+    GLuint shader = glCreateShader(stype);
+    const char *tmp = src.c_str();
+
+    glShaderSource(shader, 1, &tmp, 0);
+    glCompileShader(shader);
+
+    return shader;
+}
+
+
+void dmLinkModelShaders(DMModel &model)
+{
+    model.id_prog = glCreateProgram();
+    glAttachShader(model.id_prog, model.id_fs);
+    glAttachShader(model.id_prog, model.id_vs);
+    glLinkProgram(model.id_prog);
+}
+
+
+int main(int argc, char *argv[])
+{
+    int startTime, cycleStart, cycleFrames = 0, totalFrames = 0;
+    double totalTime;
+    bool
+        exitFlag = false,
+        optShowHelp = false,
+        optSetInputFilename = false;
+    std::string optInputFilename = "dragon.scene", basePath;
+    DMSimpleScene scene;
+
+    // Check commandline argument for enabling shaders
+    for (int narg = 1; narg < argc; narg++)
+    {
+        char *arg = argv[narg];
+        if (arg[0] == '-')
+        {
+            char *opt = arg + 1;
+
+            if ((opt[0] == '-' && opt[1] == 'h' && opt[2] == 'e') ||
+                opt[0] == '?' || (opt[0] == '-' && opt[1] == '?'))
+            {
+                optShowHelp = true;
+                break;
+            }
+            else
+            if (opt[0] == '-')
+                opt++;
+
+            if (opt[0] == 'g')
+                optUseShaders = true;
+            else
+            switch (opt[0])
+            {
+                case 'w':
+                case 'h':
+                case 'm':
+                case 'v':
+                    if (opt[1] == 0)
+                    {
+                        printf("Option '%s' requires an argument.\n", opt);
+                        goto exit;
+                    }
+
+                    switch (opt[0])
+                    {
+                        case 'w': optWidth = atoi(opt + 1); break;
+                        case 'h': optHeight = atoi(opt + 1); break;
+                        case 'v': optVSyncMode = atoi(opt + 1); break;
+                    }
+                    break;
+
+                default:
+                    printf("Unknown option '%s'.\n", opt);
+                    goto exit;
+            }
+        }
+        else
+        {
+            if (optSetInputFilename)
+            {
+                printf("ERROR: Please specify only one scene file.\n");
+                goto exit;
+            }
+
+            optSetInputFilename = true;
+            optInputFilename = std::string(arg);
+            if (optInputFilename.empty())
+            {
+                printf("ERROR: Invalid input filename.\n");
+                goto exit;
+            }
+
+        }
+    }
+
+    if (optShowHelp)
+    {
+        printf(
+            "Usage: %s [options] [<scenefile.scene>]\n"
+            "-?            Show this help\n"
+            "-g            Use GLSL shader instead of basic OpenGL lighting\n"
+            "-w<width>     Window width (default %d)\n"
+            "-h<height>    Window height (default %d)\n"
+            "-v<1-3>       Set vsync mode: 1 = no vsync, 2 = vsync, 3 = adaptive\n"
+            "              Default is no vsync. Using vsync will result in FPS being\n"
+            "              approx whatever your monitor refresh rate is.\n"
+            "\n",
+            argv[0],
+            SET_DEF_WIDTH, SET_DEF_HEIGHT
+            );
+
+        goto exit;
+    }
+
+    if (optWidth < 100 || optWidth > 8192 || optHeight < 100 || optHeight > 8192)
+    {
+        printf("ERROR: Invalid window width or height (%d x %d).\n",
+            optWidth, optHeight);
+        goto exit;
+    }
+
+    // Load the scene
+    if (!scene.loadInfo(optInputFilename))
+        goto exit;
+
+    if (scene.models.size() == 0)
+    {
+        printf("ERROR: Scenefile '%s' contains no models.\n",
+            optInputFilename.c_str());
+        goto exit;
+    }
+
+    printf("INFO: Loading %ld model(s) ..\n",
+        scene.models.size());
+
+    basePath = dmGetPath(optInputFilename);
+    printf("INFO: Model base path '%s'\n", basePath.c_str());
+
+    for (DMModel &model : scene.models)
+    {
+        if (!model.loadFromPLY(basePath + model.modelFile))
+            goto exit;
+
+        if (optUseShaders)
+        {
+            std::string
+                fragFile = model.fragShaderFile.empty() ? "shader.frag" : basePath + model.fragShaderFile,
+                vertFile = model.vertShaderFile.empty() ? "shader.vert" : basePath + model.vertShaderFile;
+
+            if (!dmReadText(fragFile, model.fragShaderStr, SET_MAX_SHADER_SIZE) ||
+                !dmReadText(vertFile, model.vertShaderStr, SET_MAX_SHADER_SIZE))
+                goto exit;
+        }
+    }
+
+    // Initialize SDL + OpenGL
+    if (!dmInitSDLGL(optWidth, optHeight, "GLDragon"))
+        goto exit;
+
+    // According to our mode ..
+    if (optUseShaders)
+    {
+        for (DMModel &model : scene.models)
+        {
+            model.id_fs = dmCompileShader(GL_FRAGMENT_SHADER, model.fragShaderStr);
+            model.id_vs = dmCompileShader(GL_VERTEX_SHADER, model.vertShaderStr);
+            dmLinkModelShaders(model);
+        }
+    }
+    else
+    {
+        float specReflection[] = { 0.8f, 0.8f, 0.8f, 1.0f };
+
+        glEnable(GL_COLOR_MATERIAL);
+
+        glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
+        glMateriali(GL_FRONT, GL_SHININESS, 96);
+        glMaterialfv(GL_FRONT, GL_SPECULAR, specReflection);
+
+        glEnable(GL_LIGHT0);
+
+        // Define the light components and position
+        GLfloat ambient[]  = {   0.2f,  0.2f,  0.2f,  1.0f };
+        GLfloat diffuse[]  = {   0.8f,  0.8f,  0.8f,  1.0f };
+        GLfloat specular[] = {   0.5f,  0.5f,  0.5f,  1.0f };
+        GLfloat position[] = {  10.0f, 10.0f,  0.0f,  0.0f };
+
+        // Define the light components and position
+        glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
+        glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
+        glLightfv(GL_LIGHT0, GL_SPECULAR, specular);
+        glLightfv(GL_LIGHT0, GL_POSITION, position);
+    }
+
+    // Define the camera
+    gluLookAt(0, 0.12, 0.24, 0, 0.12, 0, 0, 1, 0);
+
+
+    // Main loop starts
+    startTime = cycleStart = SDL_GetTicks();
+
+    while (!exitFlag)
+    {
+        SDL_Event event;
+
+        // Check for quit events
+        while (SDL_PollEvent(&event))
+        switch (event.type)
+        {
+            case SDL_QUIT:
+                exitFlag = true;
+                break;
+
+            case SDL_KEYDOWN:
+                switch (event.key.keysym.sym)
+                {
+                    case SDLK_ESCAPE:
+                    case SDLK_q:
+                        exitFlag = true;
+                        break;
+                }
+        }
+
+        // Render the next frame
+        dmDrawScene(scene);
+
+        // Draw the current frame
+        SDL_GL_SwapWindow(dmWindow);
+
+        // Rotate for 2 degrees
+        glRotatef(2.0f, 0, 1, 0);
+
+        // Return true if a full rotation was done
+        totalFrames++;
+        if (cycleFrames++ == SET_FRAMES)
+        {
+            // Reset cycleFrames
+            cycleFrames = 0;
+
+            // Get the time it took to render a full turn
+            int cycleEnd = SDL_GetTicks();
+            double cycleTime = cycleEnd - cycleStart;
+
+            // Restart the timer
+            cycleStart = SDL_GetTicks();
+
+            // Print the current frames per second
+            printf("%.1lf ms for %d frames = %.1lf FPS\n",
+                cycleTime, SET_FRAMES, (SET_FRAMES * 1000.0f) / cycleTime);
+        }
+    }
+
+    // Show totals
+    totalTime = SDL_GetTicks() - startTime;
+    printf("%.1lf ms total for %d total frames = %.2lf FPS average\n",
+        totalTime, totalFrames, (totalFrames * 1000.0f) / totalTime);
+
+exit:
+    if (dmGLContext != NULL)
+        SDL_GL_DeleteContext(dmGLContext);
+
+    if (dmWindow != NULL)
+        SDL_DestroyWindow(dmWindow);
+
+    SDL_Quit();
+
+    return 0;
+}
--- a/glxdragon.cpp	Fri Nov 22 05:29:02 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,526 +0,0 @@
-//
-// GLDragon - OpenGL PLY model viewer / simple benchmark
-// Programmed and designed by Matti 'ccr' Hämäläinen <ccr@tnsp.org>
-// (C) Copyright 2019 Tecnic Software productions (TNSP)
-//
-// See file "COPYING" for license information.
-//
-// Originally based on 'glxdragon' Copyright (c) 2009, Thomas Trummer
-//
-#include <SDL.h>
-#include <SDL_opengl.h>
-#include <GL/glu.h>
-#include <GL/glext.h>
-
-#include "dmutil.h"
-#include "dmmodel.h"
-
-
-/* Default settings etc. constants
- */
-#define SET_DEF_WIDTH        1280
-#define SET_DEF_HEIGHT       960
-#define SET_FRAMES           (180)
-#define SET_MAX_SHADER_SIZE  (128 * 1024)
-
-
-/* Options
- */
-bool   optUseShaders = false;
-int    optWidth = SET_DEF_WIDTH,
-       optHeight = SET_DEF_HEIGHT,
-       optVSyncMode = 1;
-
-
-
-/* Globals
- */
-SDL_Window *dmWindow = NULL;
-SDL_GLContext dmGLContext = NULL;
-
-
-/* Helpers
- */
-bool dmInitSDLGL(const int width, const int height, const char *title)
-{
-    int ret;
-    std::string msg;
-
-    // Set GL attributes
-    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
-    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
-    SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
-
-    SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
-    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
-
-    // Attempt to initialize libSDL
-    if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_EVENTS) != 0)
-    {
-        printf("ERROR: Unable to initialize SDL: %s\n",
-            SDL_GetError());
-        return false;
-    }
-
-    // Attempt to create a window
-    if ((dmWindow = SDL_CreateWindow(title,
-            SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
-            width, height,
-            SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE)) == NULL)
-    {
-        printf("ERROR: Could not create SDL window: %s",
-            SDL_GetError());
-        return false;
-    }
-
-    if ((dmGLContext = SDL_GL_CreateContext(dmWindow)) == NULL)
-    {
-        printf("ERROR: Unable to create SDL OpenGL context: %s\n",
-            SDL_GetError());
-        return false;
-    }
-
-    // Check if we want to attempt to use vsync
-    switch (optVSyncMode)
-    {
-        case 3:
-            ret = SDL_GL_SetSwapInterval(-1);
-            msg = "adaptive vsync";
-            break;
-
-        case 2:
-            ret = SDL_GL_SetSwapInterval(1);
-            msg = "synchronized (vsync)";
-            break;
-
-        case 1:
-            ret = SDL_GL_SetSwapInterval(0);
-            msg = "immediate (no vsync)";
-            break;
-
-        default:
-            ret = -1;
-            msg = "INVALID VSYNC MODE";
-            break;
-    }
-
-    if (ret != 0)
-    {
-        printf("ERROR: Could not set vsync mode to %s.\n",
-            msg.c_str());
-        return false;
-    }
-
-    // Dump some information
-    printf(
-        "GL_VENDOR   : %s\n"
-        "GL_RENDERER : %s\n"
-        "GL_VERSION  : %s\n"
-        "VSync mode  : %s\n",
-        glGetString(GL_VENDOR),
-        glGetString(GL_RENDERER),
-        glGetString(GL_VERSION),
-        msg.c_str());
-
-    // Setup the window and view port
-    glViewport(0, 0, width, height);
-
-    glMatrixMode(GL_PROJECTION);
-    glLoadIdentity();
-
-    gluPerspective(45.0f, GLfloat(width) / GLfloat(height), 0.1f, 1000.0f);
-
-    glMatrixMode(GL_MODELVIEW);
-    glLoadIdentity();
-
-    // Enable back face culling
-    glEnable(GL_CULL_FACE);
-
-    // Enable smooth shading
-    glShadeModel(GL_SMOOTH);
-
-    // Enable the depth buffer
-    glEnable(GL_DEPTH_TEST);
-
-    // Enable normal rescaling
-    glEnable(GL_RESCALE_NORMAL);
-
-    // Setup depth buffer
-    glClearDepth(1.0f);
-
-    // Set the depth buffer function
-    glDepthFunc(GL_LEQUAL);
-
-    // Enable vertex and and normal arrays
-    glEnableClientState(GL_VERTEX_ARRAY);
-    glEnableClientState(GL_NORMAL_ARRAY);
-
-    // Set correct perspective correction
-    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
-
-    return true;
-}
-
-
-void dmDrawModel(const DMModel &model)
-{
-    int maxIndices;
-
-    if (optUseShaders)
-    {
-        // Enable shader program
-        glUseProgram(model.id_prog);
-    }
-    else
-    {
-        // Set the color of the model
-        glEnable(GL_LIGHTING);
-        glColor3ub(0x90, 0x80, 0x90);
-    }
-
-    // Render the model
-    glGetIntegerv(GL_MAX_ELEMENTS_INDICES, &maxIndices);
-
-    glPushMatrix();
-
-    // Add transforms
-    glScalef(model.scale.x, model.scale.y, model.scale.z);
-    glTranslatef(model.translate.x, model.translate.y, model.translate. z);
-    glRotatef(model.rotate.x, 1.0f, 0.0f, 0.0f);
-    glRotatef(model.rotate.y, 0.0f, 1.0f, 0.0f);
-    glRotatef(model.rotate.z, 0.0f, 0.0f, 1.0f);
-
-    glVertexPointer(3, GL_FLOAT, 0, &model.vertices[0]);
-    glNormalPointer(   GL_FLOAT, 0, &model.normals[0]);
-
-    for (int n = 0; n < model.nfaces; n += maxIndices)
-    {
-        const int count = std::min(maxIndices, model.nfaces - n);
-        glDrawElements(GL_TRIANGLES, count * 3, GL_UNSIGNED_INT, &model.faces[n * 3]);
-    }
-
-    glPopMatrix();
-
-    // Restore
-    if (optUseShaders)
-    {
-        glUseProgram(0);
-    }
-}
-
-
-void dmDrawScene(const DMSimpleScene &scene)
-{
-    glClear(GL_DEPTH_BUFFER_BIT);
-
-    glMatrixMode(GL_PROJECTION);
-    glPushMatrix();
-    glLoadIdentity();
-
-    glOrtho(0.0, 1.0, 0.0, 1.0, -1, 1);
-
-    glMatrixMode(GL_MODELVIEW);
-    glPushMatrix();
-    glLoadIdentity();
-
-    // Draw the background gradient
-    glDisable(GL_DEPTH_TEST);
-    glDisable(GL_LIGHTING);
-    glBegin(GL_QUADS);
-    {
-        glColor3ub(0x3B, 0x3B, 0x75);
-        glVertex2f(0.0f, 0.0f);
-        glVertex2f(1.0f, 0.0f);
-
-        glColor3ub(0x00, 0x00, 0x00);
-        glVertex2f(1.0f, 1.0f);
-        glVertex2f(0.0f, 1.0f);
-    }
-    glEnd();
-
-
-    // Restore the 3D projection
-    glMatrixMode(GL_PROJECTION);
-    glPopMatrix();
-
-    glMatrixMode(GL_MODELVIEW);
-    glPopMatrix();
-
-    glEnable(GL_DEPTH_TEST);
-
-    // Draw models
-    for (const DMModel &model : scene.models)
-        dmDrawModel(model);
-}
-
-
-GLuint dmCompileShader(const GLenum stype, const std::string &src)
-{
-    GLuint shader = glCreateShader(stype);
-    const char *tmp = src.c_str();
-
-    glShaderSource(shader, 1, &tmp, 0);
-    glCompileShader(shader);
-
-    return shader;
-}
-
-
-void dmLinkModelShaders(DMModel &model)
-{
-    model.id_prog = glCreateProgram();
-    glAttachShader(model.id_prog, model.id_fs);
-    glAttachShader(model.id_prog, model.id_vs);
-    glLinkProgram(model.id_prog);
-}
-
-
-int main(int argc, char *argv[])
-{
-    int startTime, cycleStart, cycleFrames = 0, totalFrames = 0;
-    double totalTime;
-    bool
-        exitFlag = false,
-        optShowHelp = false,
-        optSetInputFilename = false;
-    std::string optInputFilename = "dragon.scene", basePath;
-    DMSimpleScene scene;
-
-    // Check commandline argument for enabling shaders
-    for (int narg = 1; narg < argc; narg++)
-    {
-        char *arg = argv[narg];
-        if (arg[0] == '-')
-        {
-            char *opt = arg + 1;
-
-            if ((opt[0] == '-' && opt[1] == 'h' && opt[2] == 'e') ||
-                opt[0] == '?' || (opt[0] == '-' && opt[1] == '?'))
-            {
-                optShowHelp = true;
-                break;
-            }
-            else
-            if (opt[0] == '-')
-                opt++;
-
-            if (opt[0] == 'g')
-                optUseShaders = true;
-            else
-            switch (opt[0])
-            {
-                case 'w':
-                case 'h':
-                case 'm':
-                case 'v':
-                    if (opt[1] == 0)
-                    {
-                        printf("Option '%s' requires an argument.\n", opt);
-                        goto exit;
-                    }
-
-                    switch (opt[0])
-                    {
-                        case 'w': optWidth = atoi(opt + 1); break;
-                        case 'h': optHeight = atoi(opt + 1); break;
-                        case 'v': optVSyncMode = atoi(opt + 1); break;
-                    }
-                    break;
-
-                default:
-                    printf("Unknown option '%s'.\n", opt);
-                    goto exit;
-            }
-        }
-        else
-        {
-            if (optSetInputFilename)
-            {
-                printf("ERROR: Please specify only one scene file.\n");
-                goto exit;
-            }
-
-            optSetInputFilename = true;
-            optInputFilename = std::string(arg);
-            if (optInputFilename.empty())
-            {
-                printf("ERROR: Invalid input filename.\n");
-                goto exit;
-            }
-
-        }
-    }
-
-    if (optShowHelp)
-    {
-        printf(
-            "Usage: %s [options] [<scenefile.scene>]\n"
-            "-?            Show this help\n"
-            "-g            Use GLSL shader instead of basic OpenGL lighting\n"
-            "-w<width>     Window width (default %d)\n"
-            "-h<height>    Window height (default %d)\n"
-            "-v<1-3>       Set vsync mode: 1 = no vsync, 2 = vsync, 3 = adaptive\n"
-            "              Default is no vsync. Using vsync will result in FPS being\n"
-            "              approx whatever your monitor refresh rate is.\n"
-            "\n",
-            argv[0],
-            SET_DEF_WIDTH, SET_DEF_HEIGHT
-            );
-
-        goto exit;
-    }
-
-    if (optWidth < 100 || optWidth > 8192 || optHeight < 100 || optHeight > 8192)
-    {
-        printf("ERROR: Invalid window width or height (%d x %d).\n",
-            optWidth, optHeight);
-        goto exit;
-    }
-
-    // Load the scene
-    if (!scene.loadInfo(optInputFilename))
-        goto exit;
-
-    if (scene.models.size() == 0)
-    {
-        printf("ERROR: Scenefile '%s' contains no models.\n",
-            optInputFilename.c_str());
-        goto exit;
-    }
-
-    printf("INFO: Loading %ld model(s) ..\n",
-        scene.models.size());
-
-    basePath = dmGetPath(optInputFilename);
-    printf("INFO: Model base path '%s'\n", basePath.c_str());
-
-    for (DMModel &model : scene.models)
-    {
-        if (!model.loadFromPLY(basePath + model.modelFile))
-            goto exit;
-
-        if (optUseShaders)
-        {
-            std::string
-                fragFile = model.fragShaderFile.empty() ? "shader.frag" : basePath + model.fragShaderFile,
-                vertFile = model.vertShaderFile.empty() ? "shader.vert" : basePath + model.vertShaderFile;
-
-            if (!dmReadText(fragFile, model.fragShaderStr, SET_MAX_SHADER_SIZE) ||
-                !dmReadText(vertFile, model.vertShaderStr, SET_MAX_SHADER_SIZE))
-                goto exit;
-        }
-    }
-
-    // Initialize SDL + OpenGL
-    if (!dmInitSDLGL(optWidth, optHeight, "GLDragon"))
-        goto exit;
-
-    // According to our mode ..
-    if (optUseShaders)
-    {
-        for (DMModel &model : scene.models)
-        {
-            model.id_fs = dmCompileShader(GL_FRAGMENT_SHADER, model.fragShaderStr);
-            model.id_vs = dmCompileShader(GL_VERTEX_SHADER, model.vertShaderStr);
-            dmLinkModelShaders(model);
-        }
-    }
-    else
-    {
-        float specReflection[] = { 0.8f, 0.8f, 0.8f, 1.0f };
-
-        glEnable(GL_COLOR_MATERIAL);
-
-        glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
-        glMateriali(GL_FRONT, GL_SHININESS, 96);
-        glMaterialfv(GL_FRONT, GL_SPECULAR, specReflection);
-
-        glEnable(GL_LIGHT0);
-
-        // Define the light components and position
-        GLfloat ambient[]  = {   0.2f,  0.2f,  0.2f,  1.0f };
-        GLfloat diffuse[]  = {   0.8f,  0.8f,  0.8f,  1.0f };
-        GLfloat specular[] = {   0.5f,  0.5f,  0.5f,  1.0f };
-        GLfloat position[] = {  10.0f, 10.0f,  0.0f,  0.0f };
-
-        // Define the light components and position
-        glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
-        glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
-        glLightfv(GL_LIGHT0, GL_SPECULAR, specular);
-        glLightfv(GL_LIGHT0, GL_POSITION, position);
-    }
-
-    // Define the camera
-    gluLookAt(0, 0.12, 0.24, 0, 0.12, 0, 0, 1, 0);
-
-
-    // Main loop starts
-    startTime = cycleStart = SDL_GetTicks();
-
-    while (!exitFlag)
-    {
-        SDL_Event event;
-
-        // Check for quit events
-        while (SDL_PollEvent(&event))
-        switch (event.type)
-        {
-            case SDL_QUIT:
-                exitFlag = true;
-                break;
-
-            case SDL_KEYDOWN:
-                switch (event.key.keysym.sym)
-                {
-                    case SDLK_ESCAPE:
-                    case SDLK_q:
-                        exitFlag = true;
-                        break;
-                }
-        }
-
-        // Render the next frame
-        dmDrawScene(scene);
-
-        // Draw the current frame
-        SDL_GL_SwapWindow(dmWindow);
-
-        // Rotate for 2 degrees
-        glRotatef(2.0f, 0, 1, 0);
-
-        // Return true if a full rotation was done
-        totalFrames++;
-        if (cycleFrames++ == SET_FRAMES)
-        {
-            // Reset cycleFrames
-            cycleFrames = 0;
-
-            // Get the time it took to render a full turn
-            int cycleEnd = SDL_GetTicks();
-            double cycleTime = cycleEnd - cycleStart;
-
-            // Restart the timer
-            cycleStart = SDL_GetTicks();
-
-            // Print the current frames per second
-            printf("%.1lf ms for %d frames = %.1lf FPS\n",
-                cycleTime, SET_FRAMES, (SET_FRAMES * 1000.0f) / cycleTime);
-        }
-    }
-
-    // Show totals
-    totalTime = SDL_GetTicks() - startTime;
-    printf("%.1lf ms total for %d total frames = %.2lf FPS average\n",
-        totalTime, totalFrames, (totalFrames * 1000.0f) / totalTime);
-
-exit:
-    if (dmGLContext != NULL)
-        SDL_GL_DeleteContext(dmGLContext);
-
-    if (dmWindow != NULL)
-        SDL_DestroyWindow(dmWindow);
-
-    SDL_Quit();
-
-    return 0;
-}