Mercurial > hg > forks > gldragon
view dmglrender.cpp @ 103:f88859a8fa4b
Add note about code origins to COPYING.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Thu, 06 Oct 2022 05:02:07 +0300 |
parents | 50a69d327b4f |
children |
line wrap: on
line source
// // 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> #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; } 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::initRenderer1(const char *title, const int width, const int height, const int sdlWindowHPos, const int sdlWindowVPos, const int sdlFlags) { // 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); // Attempt to create a window if (!DMSimpleRenderer::initRenderer1( title, width, height, sdlWindowHPos, sdlWindowVPos, sdlFlags | SDL_WINDOW_OPENGL)) return false; // Create OpenGL context if ((sdlGLContext = SDL_GL_CreateContext(sdlWindow)) == 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"); 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" #undef DM_GLEXT_INIT return status; } #define TWIDTH 8 #define THEIGHT 8 static char texSrc8[TWIDTH * THEIGHT + 1] = "..%##%.." ".%####%." "%#*..*#%" "##....##" "########" "##....##" "##....##" "##....##"; static Uint32 texSrc32[TWIDTH * THEIGHT]; bool DMGLSimpleRenderer::initRenderer2(void) { // 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, windowWidth, windowHeight); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(45.0f, GLfloat(windowWidth) / GLfloat(windowHeight), 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); // Create texture bitmap for (int yc = 0; yc < THEIGHT; yc++) { Uint8 *dp8 = ((Uint8 *) texSrc8) + yc * TWIDTH; Uint32 *dp32 = ((Uint32 *) texSrc32) + yc * TWIDTH; for (int xc = 0; xc < TWIDTH; xc++) { Uint8 col = dp8[xc]; switch (col) { case '.': col = 0; break; case '#': col = 255; break; case '*': col = 128; break; default: col = 192; break; } dp8[xc] = col; dp32[xc] = col | (col << 8) | (col << 16); } } // Upload to GPU texture glGenTextures(1, &tex8); glBindTexture(GL_TEXTURE_2D, tex8); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, TWIDTH, THEIGHT, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, texSrc8); glBindTexture(GL_TEXTURE_2D, 0); glGenTextures(2, &tex32); glBindTexture(GL_TEXTURE_2D, tex32); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, TWIDTH, THEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, texSrc32); glBindTexture(GL_TEXTURE_2D, 0); return checkErrors(); } bool DMGLSimpleRenderer::compileModelShaders(DMModel &model) { if (useShaders) { GLuint id_fs, id_vs; if (!dmCompileShader(GL_FRAGMENT_SHADER, model.fragShaderStr, id_fs) || !dmCompileShader(GL_VERTEX_SHADER, model.vertShaderStr, id_vs)) return false; model.id_prog = glCreateProgram(); glAttachShader(model.id_prog, id_fs); glAttachShader(model.id_prog, id_vs); glLinkProgram(model.id_prog); glDeleteShader(id_fs); glDeleteShader(id_vs); } return true; } void DMGLSimpleRenderer::shutdownRenderer(void) { if (sdlGLContext != NULL) SDL_GL_DeleteContext(sdlGLContext); DMSimpleRenderer::shutdownRenderer(); } 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()); glUniform1f(glGetUniformLocation(model.id_prog, "ftime"), time); } // 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) { float qx, qy, qw, qh; 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(); // Draw texture #1 glColor3ub(0xff, 0xff, 0xff); qh = 0.35f; qw = qh * 0.6f; qx = 0; qy = 0; glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, tex8); glBegin(GL_QUADS); glTexCoord2i(-1, 0); glVertex2f(qx , qy); glTexCoord2i( 0, 0); glVertex2f(qx + qw, qy); glTexCoord2i( 0, -1); glVertex2f(qx + qw, qy + qh); glTexCoord2i(-1, -1); glVertex2f(qx , qy + qh); glEnd(); // Draw texture #2 qh = 0.25f; qw = qh * 0.6f; qx = 1.0f - qw; qy = 1.0f - qh; glBindTexture(GL_TEXTURE_2D, tex32); glBegin(GL_QUADS); glTexCoord2i(-1, 0); glVertex2f(qx , qy); glTexCoord2i( 0, 0); glVertex2f(qx + qw, qy); glTexCoord2i( 0, -1); glVertex2f(qx + qw, qy + qh); glTexCoord2i(-1, -1); glVertex2f(qx , qy + qh); glEnd(); glBindTexture(GL_TEXTURE_2D, 0); glDisable(GL_TEXTURE_2D); // Restore the 3D projection glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); glEnable(GL_DEPTH_TEST); glEnable(GL_LIGHTING); // Draw models glPushMatrix(); glRotatef(time * 360.0, 0, 1, 0); for (const DMModel &model : scene.models) { glPushMatrix(); drawModel(scene, model, time); glPopMatrix(); } 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; }