Mercurial > hg > forks > gldragon
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; +}