Mercurial > hg > forks > gldragon
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(); |