diff dmglrender.cpp @ 62:baccf2044289

Move the OpenGL rendering, setup etc. into a separate module/class, perhaps facilitating other types of renderers in future .. maybe.
author Matti Hamalainen <ccr@tnsp.org>
date Sat, 14 Dec 2019 16:39:20 +0200
parents
children d6ffc59bb84d
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmglrender.cpp	Sat Dec 14 16:39:20 2019 +0200
@@ -0,0 +1,366 @@
+//
+// GLDragon - OpenGL PLY model viewer / simple benchmark
+// -- OpenGL rendering of DMSimpleScene
+// 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.
+//
+#include "dmglrender.h"
+#include <GL/glu.h>
+
+
+#ifdef GL_GLEXT_PROTOTYPES
+#define DM_GLEXT_INIT(extproctype, extprocname) /* stub */
+#else
+#define DM_GLEXT_INIT(extproctype, extprocname) extproctype extprocname = NULL;
+#include "dmglexts.h"
+#undef DM_GLEXT_INIT
+
+
+static void dmGLCheckExtension(const std::string &name, bool &status)
+{
+    if (!SDL_GL_ExtensionSupported(name.c_str()))
+    {
+        status = false;
+        dmMsg(" - '%s' NOT supported.\n",
+            name.c_str());
+    }
+}
+
+
+static void * dmGLGetProcAddr(const std::string &name)
+{
+    void *ptr = SDL_GL_GetProcAddress(name.c_str());
+
+    if (ptr == NULL)
+        dmMsg(" - '%s' NOT supported.\n");
+
+    return ptr;
+}
+
+
+static void * dmGLExtInit(const std::string &name, bool &status)
+{
+    void *ptr;
+    bool ok =
+        (ptr = dmGLGetProcAddr(name)) != NULL ||
+        (ptr = dmGLGetProcAddr(name + "EXT")) != NULL ||
+        (ptr = dmGLGetProcAddr(name + "ARB")) != NULL;
+
+    if (!ok)
+        status = false;
+
+    return ptr;
+}
+#endif
+
+
+static bool dmCompileShader(const GLenum stype, const std::string &src, GLuint &shader)
+{
+    GLint status;
+    const char *tmp = src.c_str();
+
+    shader = glCreateShader(stype);
+    glShaderSource(shader, 1, &tmp, 0);
+    glCompileShader(shader);
+
+    glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
+    if (status == GL_TRUE)
+        return true;
+    else
+    {
+        GLint bufLen = 0;
+        glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &bufLen);
+
+        if (bufLen > 0)
+        {
+            char *buf = new char[bufLen];
+            glGetShaderInfoLog(shader, bufLen, NULL, buf);
+            dmError("Shader compilation error:\n%s\n",
+                buf);
+            delete[] buf;
+        }
+        else
+        {
+            dmError("Shader compilation error occured, but no error information got.\n");
+        }
+        return false;
+    }
+}
+
+
+bool DMGLSimpleRenderer::checkErrors(void)
+{
+    bool ok = true;
+    GLenum err;
+    while ((err = glGetError()) != GL_NO_ERROR)
+    {
+        dmError("OpenGL error code: 0x%x (%d)\n", err);
+        ok = false;
+    }
+    return ok;
+}
+
+
+bool DMGLSimpleRenderer::initRender1(void)
+{
+    // 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_RED_SIZE, 8);
+    SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
+    SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
+    SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
+
+    SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
+    //SDL_GL_SetAttribute(SDL_GL_BUFFER_SIZE, 32);
+    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
+
+    return true;
+}
+
+
+bool DMGLSimpleRenderer::initRender2(SDL_Window *window)
+{
+    // Create OpenGL context
+    if ((glContext = SDL_GL_CreateContext(window)) == NULL)
+    {
+        dmError("Unable to create SDL OpenGL context: %s\n",
+            SDL_GetError());
+        return false;
+    }
+
+    // If shaders are disabled, do not initialize OpenGL extensions
+    if (!useShaders)
+        return true;
+
+    bool status = true;
+    dmMsg("Checking for required OpenGL extensions ..\n");
+
+#ifndef GL_GLEXT_PROTOTYPES
+    dmGLCheckExtension("GL_ARB_shader_objects", status);
+    dmGLCheckExtension("GL_ARB_shading_language_100", status);
+    dmGLCheckExtension("GL_ARB_vertex_shader", status);
+    dmGLCheckExtension("GL_ARB_fragment_shader", status);
+    if (!status)
+    {
+        dmError("One or more of the required OpenGL extensions not supported.\n");
+        return false;
+    }
+
+#define DM_GLEXT_INIT(extproctype, extprocname) \
+    extprocname = (extproctype) dmGLExtInit(#extprocname, status);
+#include "dmglexts.h"
+#endif
+
+    return status;
+}
+
+
+bool DMGLSimpleRenderer::initRender3(const int width, const int height)
+{
+    // Dump some information
+    dmMsg("GL_VENDOR   : %s\n", glGetString(GL_VENDOR));
+    dmMsg("GL_RENDERER : %s\n", glGetString(GL_RENDERER));
+    dmMsg("GL_VERSION  : %s\n", glGetString(GL_VERSION));
+
+    if (!checkErrors())
+        return false;
+
+    // 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);
+
+    glEnable(GL_COLOR_MATERIAL);
+
+    // 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 checkErrors();
+}
+
+
+bool DMGLSimpleRenderer::compileModelShaders(DMModel &model)
+{
+    if (useShaders)
+    {
+        if (!dmCompileShader(GL_FRAGMENT_SHADER, model.fragShaderStr, model.id_fs) ||
+            !dmCompileShader(GL_VERTEX_SHADER, model.vertShaderStr, model.id_vs))
+            return false;
+
+        model.id_prog = glCreateProgram();
+        glAttachShader(model.id_prog, model.id_fs);
+        glAttachShader(model.id_prog, model.id_vs);
+        glLinkProgram(model.id_prog);
+    }
+    return true;
+}
+
+
+void DMGLSimpleRenderer::shutdownRenderer(void)
+{
+    if (glContext != NULL)
+        SDL_GL_DeleteContext(glContext);
+}
+
+
+void DMGLSimpleRenderer::drawModel(const DMSimpleScene &scene, const DMModel &model, const float time)
+{
+    int maxIndices;
+
+    if (useShaders)
+    {
+        // Enable shader program
+        glUseProgram(model.id_prog);
+        glUniform1i(glGetUniformLocation(model.id_prog, "nlights"), scene.lights.size());
+    }
+
+    // Set the material of the model
+    glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
+    glMateriali(GL_FRONT, GL_SHININESS, model.material.shininess);
+    glMaterialfv(GL_FRONT, GL_SPECULAR, model.material.specular.values);
+    glColor4fv(model.material.diffuse.values);
+
+    // Render the model
+    glGetIntegerv(GL_MAX_ELEMENTS_INDICES, &maxIndices);
+
+    // Add transforms
+    if (model.scaleSet)
+        glScalef(model.scale.x, model.scale.y, model.scale.z);
+
+    if (model.translateSet)
+        glTranslatef(model.translate.x, model.translate.y, model.translate.z);
+
+    if (model.rotateSet)
+    {
+        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]);
+    }
+
+    // Restore
+    if (useShaders)
+    {
+        glUseProgram(0);
+    }
+}
+
+
+void DMGLSimpleRenderer::drawScene(const DMSimpleScene &scene, const float time)
+{
+    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);
+    glEnable(GL_LIGHTING);
+
+    // Draw models
+    for (const DMModel &model : scene.models)
+    {
+        glPushMatrix();
+        drawModel(scene, model, time);
+        glPopMatrix();
+    }
+}
+
+
+bool DMGLSimpleRenderer::setupLight(const int n, DMLight &light)
+{
+    glEnable(GL_LIGHT0 + n);
+    glLightfv(GL_LIGHT0 + n, GL_AMBIENT, light.color.ambient.values);
+    glLightfv(GL_LIGHT0 + n, GL_DIFFUSE, light.color.diffuse.values);
+    glLightfv(GL_LIGHT0 + n, GL_SPECULAR, light.color.specular.values);
+    glLightfv(GL_LIGHT0 + n, GL_POSITION, light.position.values);
+    return true;
+}
+
+
+bool DMGLSimpleRenderer::setupCamera(DMCamera &camera)
+{
+    (void) camera;
+
+    gluLookAt(0, 0.12, 0.24, 0, 0.12, 0, 0, 1, 0);
+    return true;
+}
+
+
+bool DMGLSimpleRenderer::animate(DMSimpleScene &scene, const float time)
+{
+    (void) scene;
+    (void) time;
+
+    glRotatef(2.0f, 0, 1, 0);
+    return true;
+}