Mercurial > hg > forks > gldragon
diff gldragon.cpp @ 23:f080349584b8
Rename from glxdragon to gldragon.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Fri, 22 Nov 2019 05:29:34 +0200 |
parents | glxdragon.cpp@03b86b9c2f29 |
children | c1897cfc8463 |
line wrap: on
line diff
--- /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; +}