changeset 6:4d6fec8f0c64

Implement optional support for vertex/fragment shaders. Cleanups.
author Matti Hamalainen <ccr@tnsp.org>
date Sun, 27 Oct 2019 22:09:38 +0200
parents 5dcae4dddcd9
children 95dd5417e7de
files Makefile dragon.frag dragon.vert glxdragon.cpp
diffstat 4 files changed, 206 insertions(+), 116 deletions(-) [+]
line wrap: on
line diff
--- a/Makefile	Sun Oct 27 18:29:23 2019 +0200
+++ b/Makefile	Sun Oct 27 22:09:38 2019 +0200
@@ -1,6 +1,6 @@
 BINEXT = 
 
-CFLAGS  = -O3 -W -Wall $(shell pkg-config --cflags sdl2 gl glu)
+CFLAGS  = -O3 -W -Wall $(shell pkg-config --cflags sdl2 gl glu) -DGL_GLEXT_PROTOTYPES
 LDFLAGS = $(shell pkg-config --libs sdl2 gl glu)
 
 TARGETS = glxdragon$(BINEXT)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dragon.frag	Sun Oct 27 22:09:38 2019 +0200
@@ -0,0 +1,9 @@
+void main()
+{
+gl_FragColor = vec4(
+	gl_FragCoord.x * 0.1,
+	gl_FragCoord.y * 0.001,
+	0.0,
+	1.0);
+};
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dragon.vert	Sun Oct 27 22:09:38 2019 +0200
@@ -0,0 +1,4 @@
+void main()
+{
+gl_Position = ftransform();
+}
--- a/glxdragon.cpp	Sun Oct 27 18:29:23 2019 +0200
+++ b/glxdragon.cpp	Sun Oct 27 22:09:38 2019 +0200
@@ -31,14 +31,12 @@
 #include <SDL.h>
 #include <SDL_opengl.h>
 #include <GL/glu.h>
+#include <GL/glext.h>
 
 #include <iostream>
-#include <sstream>
 #include <fstream>
-#include <stdexcept>
 #include <string>
 #include <vector>
-#include <algorithm>
 #include <cstdio>
 #include <ctime>
 
@@ -46,8 +44,9 @@
 #define SET_FRAMES (180 * 2)
 
 
-SDL_Window *s_window = NULL;
-SDL_GLContext s_context;
+bool opt_shaders = false;
+SDL_Window *sdl_window = NULL;
+SDL_GLContext sdl_glctx = NULL;
 
 
 struct Mesh
@@ -55,18 +54,23 @@
     int nvertices, nfaces;
     std::vector<float>    vertices;
     std::vector<unsigned> faces;
+
+    GLuint id_prog, id_ps, id_vs;
 };
 
 
 
 bool dmInitSDLGL(const int width, const int height, const char *title)
 {
-    SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
-    SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
-    SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
+    // 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",
@@ -74,7 +78,8 @@
         return false;
     }
 
-    if ((s_window = SDL_CreateWindow(title,
+    // Attempt to create a window
+    if ((sdl_window = SDL_CreateWindow(title,
             SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
             width, height,
             SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE)) == NULL)
@@ -84,13 +89,14 @@
         return false;
     }
 
-    if ((s_context = SDL_GL_CreateContext(s_window)) == NULL)
+    if ((sdl_glctx = SDL_GL_CreateContext(sdl_window)) == NULL)
     {
         printf("ERROR: Unable to create SDL OpenGL context: %s\n",
             SDL_GetError());
         return false;
     }
 
+    // Dump some information
     printf(
         "GL_VENDOR   : %s\n"
         "GL_RENDERER : %s\n"
@@ -137,45 +143,6 @@
 }
 
 
-void dmInitScene(void)
-{
-    glEnable(GL_COLOR_MATERIAL);
-
-    glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
-    glMateriali(GL_FRONT, GL_SHININESS, 96);
-
-    float specReflection[] = { 0.8f, 0.8f, 0.8f, 1.0f };
-    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);
-}
-
-
-void dmFinish()
-{
-    SDL_GL_DeleteContext(s_context);
-    SDL_DestroyWindow(s_window);
-    s_window = NULL;
-    SDL_Quit();
-}
-
-
 void dmDrawModelVA(const Mesh &mesh)
 {
     int maxIndices;
@@ -233,25 +200,55 @@
     glPopMatrix();
 
     glEnable(GL_DEPTH_TEST);
-    glEnable(GL_LIGHTING);
 
-    // Set the color of the model
-    glColor3ub(0x90, 0x80, 0x90);
-
-    // Draw the model using vertex arrays
-    dmDrawModelVA(mesh);
+    // Render the model
+    if (opt_shaders)
+    {
+        // Enable shader program
+        glUseProgram(mesh.id_prog);
+        dmDrawModelVA(mesh);
+        glUseProgram(0);
+    }
+    else
+    {
+        // Set the color of the model
+        glEnable(GL_LIGHTING);
+        glColor3ub(0x90, 0x80, 0x90);
+        dmDrawModelVA(mesh);
+    }
 }
 
 
-void dmLoadMesh(const std::string &filename, Mesh &mesh, int nvertices, int nfaces)
+bool dmReadText(const std::string &filename, std::string &tstr)
+{
+    std::ifstream in(filename.c_str());
+
+    if (!in.is_open())
+    {
+        printf("ERROR: Unable to open file '%s'.\n",
+            filename.c_str());
+        return false;
+    }
+
+    in.seekg(0, std::ios::end);
+    tstr.reserve(in.tellg());
+    in.seekg(0, std::ios::beg);
+
+    tstr.assign((std::istreambuf_iterator<char>(in)), std::istreambuf_iterator<char>());
+
+    return true;
+}
+
+
+bool dmLoadMesh(const std::string &filename, Mesh &mesh, int nvertices, int nfaces)
 {
     std::ifstream in(filename.c_str(), std::ios::binary);
 
     if (!in.is_open())
     {
-        std::stringstream ss;
-        ss << "Unable to open file: " << filename << '\n';
-        throw std::runtime_error(ss.str());
+        printf("ERROR: Unable to open file '%s'.\n",
+            filename.c_str());
+        return false;
     }
 
     mesh.nvertices = nvertices;
@@ -266,79 +263,159 @@
         in.seekg(1, std::ios::cur);
         in.read(reinterpret_cast<char*>(&mesh.faces[i * 3]), 3 * 4);
     }
+
+    return true;
+}
+
+
+GLuint dmSetCompileShader(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 dmLinkMeshShaders(Mesh &mesh)
+{
+    mesh.id_prog = glCreateProgram();
+    glAttachShader(mesh.id_prog, mesh.id_ps);
+    glAttachShader(mesh.id_prog, mesh.id_vs);
+    glLinkProgram(mesh.id_prog);
 }
 
 
-int main()
+int main(int argc, char *argv[])
 {
-    try
+    struct Mesh dragonMesh;
+    std::string dragonVS, dragonFS;
+    std::clock_t startTime;
+    bool exitFlag = false;
+    int steps = 0;
+
+    // Check commandline argument for enabling shaders
+    if (argc > 1 &&
+        (strstr(argv[1], "glsl") != NULL ||
+        strstr(argv[1], "sha") != NULL))
+        opt_shaders = true;
+
+
+    if (!dmLoadMesh("dragon.mesh", dragonMesh, 100139, 200198))
+        goto exit;
+
+    if (opt_shaders)
     {
-        struct Mesh dragonMesh;
-        dmLoadMesh("dragon.mesh", dragonMesh, 100139, 200198);
-
-        //if (!dmInitSDLGL(640, 480, "glxdragon"))
-        if (!dmInitSDLGL(1280, 960, "glxdragon"))
-            throw std::runtime_error("Fatal error.");
-
-        dmInitScene();
+        // Read shader files
+        if (!dmReadText("dragon.frag", dragonFS) ||
+            !dmReadText("dragon.vert", dragonVS))
+            goto exit;
+    }
 
-        bool exitFlag = false;
-        int steps = 0;
-        std::clock_t startTime = std::clock();
+    // Initialize SDL + OpenGL
+    if (!dmInitSDLGL(1280, 960, "GLXDragon2"))
+        goto exit;
 
-        while (!exitFlag)
-        {
-            SDL_Event event;
+    // According to our mode ..
+    if (opt_shaders)
+    {
+        dragonMesh.id_ps = dmSetCompileShader(GL_FRAGMENT_SHADER, dragonFS);
+        dragonMesh.id_vs = dmSetCompileShader(GL_VERTEX_SHADER, dragonVS);
+        dmLinkMeshShaders(dragonMesh);
+    }
+    else
+    {
+        float specReflection[] = { 0.8f, 0.8f, 0.8f, 1.0f };
 
-            // Check for quit events
-            while (SDL_PollEvent(&event))
-            switch (event.type)
-            {
-                case SDL_QUIT:
-                    exitFlag = true;
-                    break;
+        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 };
 
-                case SDL_KEYDOWN:
-                    switch (event.key.keysym.sym)
-                    {
-                        case SDLK_ESCAPE:
-                        case SDLK_q:
-                            exitFlag = true;
-                            break;
-                    }
-            }
+        // 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);
+
 
-            // Render the next frame
-            dmPaintGL(dragonMesh);
+    // Main loop starts
+    startTime = std::clock();
+
+    while (!exitFlag)
+    {
+        SDL_Event event;
 
-            // Draw the current frame
-            SDL_GL_SwapWindow(s_window);
+        // Check for quit events
+        while (SDL_PollEvent(&event))
+        switch (event.type)
+        {
+            case SDL_QUIT:
+                exitFlag = true;
+                break;
 
-            // Rotate for 2 degrees
-            glRotatef(2.0f, 0, 1, 0);
+            case SDL_KEYDOWN:
+                switch (event.key.keysym.sym)
+                {
+                    case SDLK_ESCAPE:
+                    case SDLK_q:
+                        exitFlag = true;
+                        break;
+                }
+        }
 
-            // Return true if a full rotation was done
-            if (steps++ == SET_FRAMES)
-            {
-                // Reset steps
-                steps = 0;
+        // Render the next frame
+        dmPaintGL(dragonMesh);
+
+        // Draw the current frame
+        SDL_GL_SwapWindow(sdl_window);
 
-                // Get the time it took to render a full turn
-                double time = (double(std::clock() - startTime) * 1000.0f) / CLOCKS_PER_SEC;
+        // Rotate for 2 degrees
+        glRotatef(2.0f, 0, 1, 0);
+
+        // Return true if a full rotation was done
+        if (steps++ == SET_FRAMES)
+        {
+            // Reset steps
+            steps = 0;
 
-                // Print the current frames per second
-                printf("%.1lf ms for %d frames = %.1lf FPS\n",
-                    time, SET_FRAMES, (SET_FRAMES * 1000.0f) / time);
+            // Get the time it took to render a full turn
+            double time = (double(std::clock() - startTime) * 1000.0f) / CLOCKS_PER_SEC;
 
-                // Restart the timer
-                startTime = std::clock();
-            }
+            // Print the current frames per second
+            printf("%.1lf ms for %d frames = %.1lf FPS\n",
+                time, SET_FRAMES, (SET_FRAMES * 1000.0f) / time);
+
+            // Restart the timer
+            startTime = std::clock();
         }
     }
-    catch(std::runtime_error & e)
-    {
-        std::cerr << e.what();
-    }
+
+exit:
+    if (sdl_glctx != NULL)
+        SDL_GL_DeleteContext(sdl_glctx);
 
-    dmFinish();
+    if (sdl_window != NULL)
+        SDL_DestroyWindow(sdl_window);
+
+    SDL_Quit();
+
+    return 0;
 }