# HG changeset patch # User Matti Hamalainen # Date 1572206978 -7200 # Node ID 4d6fec8f0c64f1cc4c8f340a45605f2c4dd73869 # Parent 5dcae4dddcd97ecccf92e7d36a7914fb924976a1 Implement optional support for vertex/fragment shaders. Cleanups. diff -r 5dcae4dddcd9 -r 4d6fec8f0c64 Makefile --- 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) diff -r 5dcae4dddcd9 -r 4d6fec8f0c64 dragon.frag --- /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); +}; + diff -r 5dcae4dddcd9 -r 4d6fec8f0c64 dragon.vert --- /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(); +} diff -r 5dcae4dddcd9 -r 4d6fec8f0c64 glxdragon.cpp --- 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 #include #include +#include #include -#include #include -#include #include #include -#include #include #include @@ -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 vertices; std::vector 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(in)), std::istreambuf_iterator()); + + 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(&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; }