comparison gldragon.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 7b138613e2fc
children d6ffc59bb84d
comparison
equal deleted inserted replaced
61:7b138613e2fc 62:baccf2044289
6 // See file "COPYING" for license information. 6 // See file "COPYING" for license information.
7 // 7 //
8 // Originally based on 'glxdragon' Copyright (c) 2009, Thomas Trummer 8 // Originally based on 'glxdragon' Copyright (c) 2009, Thomas Trummer
9 // 9 //
10 #include <SDL.h> 10 #include <SDL.h>
11 #include <SDL_opengl.h>
12 #include <GL/glu.h>
13
14 #include "dmutil.h" 11 #include "dmutil.h"
15 #include "dmscene.h" 12 #include "dmglrender.h"
16 13
17 14
18 /* Default settings etc. constants 15 /* Default settings etc. constants
19 */ 16 */
20 #define SET_DEF_WIDTH 1280 17 #define SET_DEF_WIDTH 1280
32 29
33 30
34 /* Globals 31 /* Globals
35 */ 32 */
36 SDL_Window *dmWindow = NULL; 33 SDL_Window *dmWindow = NULL;
37 SDL_GLContext dmGLContext = NULL;
38 34
39 35
40 /* Helpers 36 /* Helpers
41 */ 37 */
42 bool dmGLCheckErrors(void) 38 bool dmInitSDL(DMSimpleRenderer &renderer, const int width, const int height, const char *title)
43 {
44 bool ok = true;
45 GLenum err;
46 while ((err = glGetError()) != GL_NO_ERROR)
47 {
48 dmError("OpenGL error code: 0x%x (%d)\n", err);
49 ok = false;
50 }
51 return ok;
52 }
53
54
55 #ifdef GL_GLEXT_PROTOTYPES
56 #define DM_GLEXT_INIT(extproctype, extprocname) /* stub */
57 #else
58 #define DM_GLEXT_INIT(extproctype, extprocname) extproctype extprocname = NULL;
59 #include "dmglexts.h"
60 #undef DM_GLEXT_INIT
61
62
63 void dmGLCheckExtension(const std::string &name, bool &status)
64 {
65 if (!SDL_GL_ExtensionSupported(name.c_str()))
66 {
67 status = false;
68 dmMsg(" - '%s' NOT supported.\n",
69 name.c_str());
70 }
71 }
72
73
74 void * dmGLGetProcAddr(const std::string &name)
75 {
76 void *ptr = SDL_GL_GetProcAddress(name.c_str());
77
78 if (ptr == NULL)
79 dmMsg(" - '%s' NOT supported.\n");
80
81 return ptr;
82 }
83
84
85 void * dmGLExtInit(const std::string &name, bool &status)
86 {
87 void *ptr;
88 bool ok =
89 (ptr = dmGLGetProcAddr(name)) != NULL ||
90 (ptr = dmGLGetProcAddr(name + "EXT")) != NULL ||
91 (ptr = dmGLGetProcAddr(name + "ARB")) != NULL;
92
93 if (!ok)
94 status = false;
95
96 return ptr;
97 }
98 #endif
99
100
101 bool dmInitGLExtensions(void)
102 {
103 bool status = true;
104 dmMsg("Checking for required OpenGL extensions ..\n");
105
106 #ifndef GL_GLEXT_PROTOTYPES
107 dmGLCheckExtension("GL_ARB_shader_objects", status);
108 dmGLCheckExtension("GL_ARB_shading_language_100", status);
109 dmGLCheckExtension("GL_ARB_vertex_shader", status);
110 dmGLCheckExtension("GL_ARB_fragment_shader", status);
111 if (!status)
112 {
113 dmError("One or more of the required OpenGL extensions not supported.\n");
114 return false;
115 }
116
117 #define DM_GLEXT_INIT(extproctype, extprocname) \
118 extprocname = (extproctype) dmGLExtInit(#extprocname, status);
119 #include "dmglexts.h"
120 #endif
121
122 return status;
123 }
124
125
126 bool dmInitSDLGL(const int width, const int height, const char *title)
127 { 39 {
128 int ret; 40 int ret;
129 std::string msg; 41 std::string msg;
130 42
131 // Attempt to initialize libSDL 43 // Attempt to initialize libSDL
134 dmError("Unable to initialize SDL: %s\n", 46 dmError("Unable to initialize SDL: %s\n",
135 SDL_GetError()); 47 SDL_GetError());
136 return false; 48 return false;
137 } 49 }
138 50
139 // Set GL attributes 51 // Part 1 of initialization
140 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); 52 if (!renderer.initRender1())
141 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1); 53 return false;
142 SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
143
144 SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
145 SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
146 SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
147 SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
148
149 SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
150 //SDL_GL_SetAttribute(SDL_GL_BUFFER_SIZE, 32);
151 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
152 54
153 // Attempt to create a window 55 // Attempt to create a window
154 if ((dmWindow = SDL_CreateWindow(title, 56 if ((dmWindow = SDL_CreateWindow(title,
155 SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 57 SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
156 width, height, 58 width, height,
159 dmError("Could not create SDL window: %s", 61 dmError("Could not create SDL window: %s",
160 SDL_GetError()); 62 SDL_GetError());
161 return false; 63 return false;
162 } 64 }
163 65
164 if ((dmGLContext = SDL_GL_CreateContext(dmWindow)) == NULL) 66 // Part 2 of initialization
165 { 67 if (!renderer.initRender2(dmWindow))
166 dmError("Unable to create SDL OpenGL context: %s\n", 68 return false;
167 SDL_GetError()); 69
168 return false;
169 }
170 70
171 // Check if we want to attempt to use vsync 71 // Check if we want to attempt to use vsync
172 switch (optVSyncMode) 72 switch (optVSyncMode)
173 { 73 {
174 case 3: 74 case 3:
202 dmError("Could not set vsync mode to %s.\n", 102 dmError("Could not set vsync mode to %s.\n",
203 msg.c_str()); 103 msg.c_str());
204 return false; 104 return false;
205 } 105 }
206 106
207 // Get/initialize OpenGL extension function pointers 107 // Part 3 of initialization
208 if (optUseShaders && !dmInitGLExtensions()) 108 if (!renderer.initRender3(width, height))
209 return false; 109 return false;
210 110
211 // Dump some information
212 dmMsg("GL_VENDOR : %s\n", glGetString(GL_VENDOR));
213 dmMsg("GL_RENDERER : %s\n", glGetString(GL_RENDERER));
214 dmMsg("GL_VERSION : %s\n", glGetString(GL_VERSION));
215 dmMsg("VSync mode : %s\n", msg.c_str()); 111 dmMsg("VSync mode : %s\n", msg.c_str());
216 112
217 if (!dmGLCheckErrors()) 113 return true;
218 return false;
219
220 // Setup the window and view port
221 glViewport(0, 0, width, height);
222
223 glMatrixMode(GL_PROJECTION);
224 glLoadIdentity();
225
226 gluPerspective(45.0f, GLfloat(width) / GLfloat(height), 0.1f, 1000.0f);
227
228 glMatrixMode(GL_MODELVIEW);
229 glLoadIdentity();
230
231 // Enable back face culling
232 glEnable(GL_CULL_FACE);
233
234 // Enable smooth shading
235 glShadeModel(GL_SMOOTH);
236
237 // Enable the depth buffer
238 glEnable(GL_DEPTH_TEST);
239
240 // Enable normal rescaling
241 glEnable(GL_RESCALE_NORMAL);
242
243 glEnable(GL_COLOR_MATERIAL);
244
245 // Setup depth buffer
246 glClearDepth(1.0f);
247
248 // Set the depth buffer function
249 glDepthFunc(GL_LEQUAL);
250
251 // Enable vertex and and normal arrays
252 glEnableClientState(GL_VERTEX_ARRAY);
253 glEnableClientState(GL_NORMAL_ARRAY);
254
255 // Set correct perspective correction
256 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
257
258 return dmGLCheckErrors();
259 }
260
261
262 void dmDrawModel(const DMSimpleScene &scene, const DMModel &model)
263 {
264 int maxIndices;
265
266 if (optUseShaders)
267 {
268 // Enable shader program
269 glUseProgram(model.id_prog);
270 glUniform1i(glGetUniformLocation(model.id_prog, "nlights"), scene.lights.size());
271 }
272
273 // Set the material of the model
274 glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
275 glMateriali(GL_FRONT, GL_SHININESS, model.material.shininess);
276 glMaterialfv(GL_FRONT, GL_SPECULAR, model.material.specular.values);
277 glColor4fv(model.material.diffuse.values);
278
279 // Render the model
280 glGetIntegerv(GL_MAX_ELEMENTS_INDICES, &maxIndices);
281
282 // Add transforms
283 if (model.scaleSet)
284 glScalef(model.scale.x, model.scale.y, model.scale.z);
285
286 if (model.translateSet)
287 glTranslatef(model.translate.x, model.translate.y, model.translate.z);
288
289 if (model.rotateSet)
290 {
291 glRotatef(model.rotate.x, 1.0f, 0.0f, 0.0f);
292 glRotatef(model.rotate.y, 0.0f, 1.0f, 0.0f);
293 glRotatef(model.rotate.z, 0.0f, 0.0f, 1.0f);
294 }
295
296 glVertexPointer(3, GL_FLOAT, 0, &model.vertices[0]);
297 glNormalPointer( GL_FLOAT, 0, &model.normals[0]);
298
299 for (int n = 0; n < model.nfaces; n += maxIndices)
300 {
301 const int count = std::min(maxIndices, model.nfaces - n);
302 glDrawElements(GL_TRIANGLES, count * 3, GL_UNSIGNED_INT, &model.faces[n * 3]);
303 }
304
305 // Restore
306 if (optUseShaders)
307 {
308 glUseProgram(0);
309 }
310 }
311
312
313 void dmDrawScene(const DMSimpleScene &scene)
314 {
315 glClear(GL_DEPTH_BUFFER_BIT);
316
317 glMatrixMode(GL_PROJECTION);
318 glPushMatrix();
319 glLoadIdentity();
320
321 glOrtho(0.0, 1.0, 0.0, 1.0, -1, 1);
322
323 glMatrixMode(GL_MODELVIEW);
324 glPushMatrix();
325 glLoadIdentity();
326
327 // Draw the background gradient
328 glDisable(GL_DEPTH_TEST);
329 glDisable(GL_LIGHTING);
330 glBegin(GL_QUADS);
331 {
332 glColor3ub(0x3B, 0x3B, 0x75);
333 glVertex2f(0.0f, 0.0f);
334 glVertex2f(1.0f, 0.0f);
335
336 glColor3ub(0x00, 0x00, 0x00);
337 glVertex2f(1.0f, 1.0f);
338 glVertex2f(0.0f, 1.0f);
339 }
340 glEnd();
341
342 // Restore the 3D projection
343 glMatrixMode(GL_PROJECTION);
344 glPopMatrix();
345
346 glMatrixMode(GL_MODELVIEW);
347 glPopMatrix();
348
349 glEnable(GL_DEPTH_TEST);
350 glEnable(GL_LIGHTING);
351
352 // Draw models
353 for (const DMModel &model : scene.models)
354 {
355 glPushMatrix();
356 dmDrawModel(scene, model);
357 glPopMatrix();
358 }
359 }
360
361
362 bool dmCompileShader(const GLenum stype, const std::string &src, GLuint &shader)
363 {
364 GLint status;
365 const char *tmp = src.c_str();
366
367 shader = glCreateShader(stype);
368 glShaderSource(shader, 1, &tmp, 0);
369 glCompileShader(shader);
370
371 glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
372 if (status == GL_TRUE)
373 return true;
374 else
375 {
376 GLint bufLen = 0;
377 glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &bufLen);
378
379 if (bufLen > 0)
380 {
381 char *buf = new char[bufLen];
382 glGetShaderInfoLog(shader, bufLen, NULL, buf);
383 dmError("Shader compilation error:\n%s\n",
384 buf);
385 delete[] buf;
386 }
387 else
388 {
389 dmError("Shader compilation error occured, but no error information got.\n");
390 }
391 return false;
392 }
393 }
394
395
396 void dmLinkModelShaders(DMModel &model)
397 {
398 model.id_prog = glCreateProgram();
399 glAttachShader(model.id_prog, model.id_fs);
400 glAttachShader(model.id_prog, model.id_vs);
401 glLinkProgram(model.id_prog);
402 }
403
404
405 void dmSetupLight(const int n, const DMLight &light)
406 {
407 glEnable(GL_LIGHT0 + n);
408 glLightfv(GL_LIGHT0 + n, GL_AMBIENT, light.color.ambient.values);
409 glLightfv(GL_LIGHT0 + n, GL_DIFFUSE, light.color.diffuse.values);
410 glLightfv(GL_LIGHT0 + n, GL_SPECULAR, light.color.specular.values);
411 glLightfv(GL_LIGHT0 + n, GL_POSITION, light.position.values);
412 } 114 }
413 115
414 116
415 int main(int argc, char *argv[]) 117 int main(int argc, char *argv[])
416 { 118 {
419 bool 121 bool
420 exitFlag = false, 122 exitFlag = false,
421 optShowHelp = false, 123 optShowHelp = false,
422 optSetInputFilename = false; 124 optSetInputFilename = false;
423 std::string optInputFilename = "dragon.scene", basePath; 125 std::string optInputFilename = "dragon.scene", basePath;
126 DMGLSimpleRenderer renderer;
424 DMSimpleScene scene; 127 DMSimpleScene scene;
425 128
426 // Check commandline argument for enabling shaders 129 // Check commandline argument for enabling shaders
427 for (int narg = 1; narg < argc; narg++) 130 for (int narg = 1; narg < argc; narg++)
428 { 131 {
557 !dmReadText(vertFile, model.vertShaderStr, SET_MAX_SHADER_SIZE)) 260 !dmReadText(vertFile, model.vertShaderStr, SET_MAX_SHADER_SIZE))
558 goto exit; 261 goto exit;
559 } 262 }
560 } 263 }
561 264
265 // Set shader usage
266 renderer.useShaders = optUseShaders;
267
562 // Initialize SDL + OpenGL 268 // Initialize SDL + OpenGL
563 if (!dmInitSDLGL(optWidth, optHeight, "GLDragon")) 269 if (!dmInitSDL(renderer, optWidth, optHeight, "GLDragon"))
564 goto exit; 270 goto exit;
565 271
566 // According to our mode .. 272 // Compile shaders for scene
567 if (optUseShaders) 273 if (!renderer.compileSceneShaders(scene))
568 { 274 goto exit;
569 for (DMModel &model : scene.models) 275
570 { 276 // Setup lights and camera
571 if (!dmCompileShader(GL_FRAGMENT_SHADER, model.fragShaderStr, model.id_fs) || 277 renderer.setupLights(scene);
572 !dmCompileShader(GL_VERTEX_SHADER, model.vertShaderStr, model.id_vs)) 278 renderer.setupCamera(scene.camera);
573 goto exit;
574
575 dmLinkModelShaders(model);
576 }
577 }
578
579 // Setup lights
580 for (size_t n = 0; n < scene.lights.size(); n++)
581 dmSetupLight(n, scene.lights[n]);
582
583 // Define the camera
584 gluLookAt(0, 0.12, 0.24, 0, 0.12, 0, 0, 1, 0);
585
586 279
587 // Main loop starts 280 // Main loop starts
588 startTime = cycleStart = SDL_GetTicks(); 281 startTime = cycleStart = SDL_GetTicks();
589 282
590 while (!exitFlag) 283 while (!exitFlag)
608 break; 301 break;
609 } 302 }
610 } 303 }
611 304
612 // Render the next frame 305 // Render the next frame
613 dmDrawScene(scene); 306 totalTime = SDL_GetTicks() - startTime;
307 renderer.drawScene(scene, totalTime);
614 308
615 // Draw the current frame 309 // Draw the current frame
616 SDL_GL_SwapWindow(dmWindow); 310 SDL_GL_SwapWindow(dmWindow);
617 311
618 // Rotate for 2 degrees 312 // Rotate for 2 degrees
619 glRotatef(2.0f, 0, 1, 0); 313 renderer.animate(scene, totalTime);
620 314
621 // Check for errors 315 // Check for errors
622 dmGLCheckErrors(); 316 renderer.checkErrors();
623 317
624 // Return true if a full rotation was done 318 // Return true if a full rotation was done
625 totalFrames++; 319 totalFrames++;
626 if (cycleFrames++ == SET_FRAMES) 320 if (cycleFrames++ == SET_FRAMES)
627 { 321 {
645 totalTime = SDL_GetTicks() - startTime; 339 totalTime = SDL_GetTicks() - startTime;
646 printf("%.1lf ms total for %d total frames = %.2lf FPS average\n", 340 printf("%.1lf ms total for %d total frames = %.2lf FPS average\n",
647 totalTime, totalFrames, (totalFrames * 1000.0f) / totalTime); 341 totalTime, totalFrames, (totalFrames * 1000.0f) / totalTime);
648 342
649 exit: 343 exit:
650 if (dmGLContext != NULL) 344 renderer.shutdownRenderer();
651 SDL_GL_DeleteContext(dmGLContext);
652 345
653 if (dmWindow != NULL) 346 if (dmWindow != NULL)
654 SDL_DestroyWindow(dmWindow); 347 SDL_DestroyWindow(dmWindow);
655 348
656 SDL_Quit(); 349 SDL_Quit();