comparison 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
comparison
equal deleted inserted replaced
22:03b86b9c2f29 23:f080349584b8
1 //
2 // GLDragon - OpenGL PLY model viewer / simple benchmark
3 // Programmed and designed by Matti 'ccr' Hämäläinen <ccr@tnsp.org>
4 // (C) Copyright 2019 Tecnic Software productions (TNSP)
5 //
6 // See file "COPYING" for license information.
7 //
8 // Originally based on 'glxdragon' Copyright (c) 2009, Thomas Trummer
9 //
10 #include <SDL.h>
11 #include <SDL_opengl.h>
12 #include <GL/glu.h>
13 #include <GL/glext.h>
14
15 #include "dmutil.h"
16 #include "dmmodel.h"
17
18
19 /* Default settings etc. constants
20 */
21 #define SET_DEF_WIDTH 1280
22 #define SET_DEF_HEIGHT 960
23 #define SET_FRAMES (180)
24 #define SET_MAX_SHADER_SIZE (128 * 1024)
25
26
27 /* Options
28 */
29 bool optUseShaders = false;
30 int optWidth = SET_DEF_WIDTH,
31 optHeight = SET_DEF_HEIGHT,
32 optVSyncMode = 1;
33
34
35
36 /* Globals
37 */
38 SDL_Window *dmWindow = NULL;
39 SDL_GLContext dmGLContext = NULL;
40
41
42 /* Helpers
43 */
44 bool dmInitSDLGL(const int width, const int height, const char *title)
45 {
46 int ret;
47 std::string msg;
48
49 // Set GL attributes
50 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
51 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
52 SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
53
54 SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
55 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
56
57 // Attempt to initialize libSDL
58 if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_EVENTS) != 0)
59 {
60 printf("ERROR: Unable to initialize SDL: %s\n",
61 SDL_GetError());
62 return false;
63 }
64
65 // Attempt to create a window
66 if ((dmWindow = SDL_CreateWindow(title,
67 SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
68 width, height,
69 SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE)) == NULL)
70 {
71 printf("ERROR: Could not create SDL window: %s",
72 SDL_GetError());
73 return false;
74 }
75
76 if ((dmGLContext = SDL_GL_CreateContext(dmWindow)) == NULL)
77 {
78 printf("ERROR: Unable to create SDL OpenGL context: %s\n",
79 SDL_GetError());
80 return false;
81 }
82
83 // Check if we want to attempt to use vsync
84 switch (optVSyncMode)
85 {
86 case 3:
87 ret = SDL_GL_SetSwapInterval(-1);
88 msg = "adaptive vsync";
89 break;
90
91 case 2:
92 ret = SDL_GL_SetSwapInterval(1);
93 msg = "synchronized (vsync)";
94 break;
95
96 case 1:
97 ret = SDL_GL_SetSwapInterval(0);
98 msg = "immediate (no vsync)";
99 break;
100
101 default:
102 ret = -1;
103 msg = "INVALID VSYNC MODE";
104 break;
105 }
106
107 if (ret != 0)
108 {
109 printf("ERROR: Could not set vsync mode to %s.\n",
110 msg.c_str());
111 return false;
112 }
113
114 // Dump some information
115 printf(
116 "GL_VENDOR : %s\n"
117 "GL_RENDERER : %s\n"
118 "GL_VERSION : %s\n"
119 "VSync mode : %s\n",
120 glGetString(GL_VENDOR),
121 glGetString(GL_RENDERER),
122 glGetString(GL_VERSION),
123 msg.c_str());
124
125 // Setup the window and view port
126 glViewport(0, 0, width, height);
127
128 glMatrixMode(GL_PROJECTION);
129 glLoadIdentity();
130
131 gluPerspective(45.0f, GLfloat(width) / GLfloat(height), 0.1f, 1000.0f);
132
133 glMatrixMode(GL_MODELVIEW);
134 glLoadIdentity();
135
136 // Enable back face culling
137 glEnable(GL_CULL_FACE);
138
139 // Enable smooth shading
140 glShadeModel(GL_SMOOTH);
141
142 // Enable the depth buffer
143 glEnable(GL_DEPTH_TEST);
144
145 // Enable normal rescaling
146 glEnable(GL_RESCALE_NORMAL);
147
148 // Setup depth buffer
149 glClearDepth(1.0f);
150
151 // Set the depth buffer function
152 glDepthFunc(GL_LEQUAL);
153
154 // Enable vertex and and normal arrays
155 glEnableClientState(GL_VERTEX_ARRAY);
156 glEnableClientState(GL_NORMAL_ARRAY);
157
158 // Set correct perspective correction
159 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
160
161 return true;
162 }
163
164
165 void dmDrawModel(const DMModel &model)
166 {
167 int maxIndices;
168
169 if (optUseShaders)
170 {
171 // Enable shader program
172 glUseProgram(model.id_prog);
173 }
174 else
175 {
176 // Set the color of the model
177 glEnable(GL_LIGHTING);
178 glColor3ub(0x90, 0x80, 0x90);
179 }
180
181 // Render the model
182 glGetIntegerv(GL_MAX_ELEMENTS_INDICES, &maxIndices);
183
184 glPushMatrix();
185
186 // Add transforms
187 glScalef(model.scale.x, model.scale.y, model.scale.z);
188 glTranslatef(model.translate.x, model.translate.y, model.translate. z);
189 glRotatef(model.rotate.x, 1.0f, 0.0f, 0.0f);
190 glRotatef(model.rotate.y, 0.0f, 1.0f, 0.0f);
191 glRotatef(model.rotate.z, 0.0f, 0.0f, 1.0f);
192
193 glVertexPointer(3, GL_FLOAT, 0, &model.vertices[0]);
194 glNormalPointer( GL_FLOAT, 0, &model.normals[0]);
195
196 for (int n = 0; n < model.nfaces; n += maxIndices)
197 {
198 const int count = std::min(maxIndices, model.nfaces - n);
199 glDrawElements(GL_TRIANGLES, count * 3, GL_UNSIGNED_INT, &model.faces[n * 3]);
200 }
201
202 glPopMatrix();
203
204 // Restore
205 if (optUseShaders)
206 {
207 glUseProgram(0);
208 }
209 }
210
211
212 void dmDrawScene(const DMSimpleScene &scene)
213 {
214 glClear(GL_DEPTH_BUFFER_BIT);
215
216 glMatrixMode(GL_PROJECTION);
217 glPushMatrix();
218 glLoadIdentity();
219
220 glOrtho(0.0, 1.0, 0.0, 1.0, -1, 1);
221
222 glMatrixMode(GL_MODELVIEW);
223 glPushMatrix();
224 glLoadIdentity();
225
226 // Draw the background gradient
227 glDisable(GL_DEPTH_TEST);
228 glDisable(GL_LIGHTING);
229 glBegin(GL_QUADS);
230 {
231 glColor3ub(0x3B, 0x3B, 0x75);
232 glVertex2f(0.0f, 0.0f);
233 glVertex2f(1.0f, 0.0f);
234
235 glColor3ub(0x00, 0x00, 0x00);
236 glVertex2f(1.0f, 1.0f);
237 glVertex2f(0.0f, 1.0f);
238 }
239 glEnd();
240
241
242 // Restore the 3D projection
243 glMatrixMode(GL_PROJECTION);
244 glPopMatrix();
245
246 glMatrixMode(GL_MODELVIEW);
247 glPopMatrix();
248
249 glEnable(GL_DEPTH_TEST);
250
251 // Draw models
252 for (const DMModel &model : scene.models)
253 dmDrawModel(model);
254 }
255
256
257 GLuint dmCompileShader(const GLenum stype, const std::string &src)
258 {
259 GLuint shader = glCreateShader(stype);
260 const char *tmp = src.c_str();
261
262 glShaderSource(shader, 1, &tmp, 0);
263 glCompileShader(shader);
264
265 return shader;
266 }
267
268
269 void dmLinkModelShaders(DMModel &model)
270 {
271 model.id_prog = glCreateProgram();
272 glAttachShader(model.id_prog, model.id_fs);
273 glAttachShader(model.id_prog, model.id_vs);
274 glLinkProgram(model.id_prog);
275 }
276
277
278 int main(int argc, char *argv[])
279 {
280 int startTime, cycleStart, cycleFrames = 0, totalFrames = 0;
281 double totalTime;
282 bool
283 exitFlag = false,
284 optShowHelp = false,
285 optSetInputFilename = false;
286 std::string optInputFilename = "dragon.scene", basePath;
287 DMSimpleScene scene;
288
289 // Check commandline argument for enabling shaders
290 for (int narg = 1; narg < argc; narg++)
291 {
292 char *arg = argv[narg];
293 if (arg[0] == '-')
294 {
295 char *opt = arg + 1;
296
297 if ((opt[0] == '-' && opt[1] == 'h' && opt[2] == 'e') ||
298 opt[0] == '?' || (opt[0] == '-' && opt[1] == '?'))
299 {
300 optShowHelp = true;
301 break;
302 }
303 else
304 if (opt[0] == '-')
305 opt++;
306
307 if (opt[0] == 'g')
308 optUseShaders = true;
309 else
310 switch (opt[0])
311 {
312 case 'w':
313 case 'h':
314 case 'm':
315 case 'v':
316 if (opt[1] == 0)
317 {
318 printf("Option '%s' requires an argument.\n", opt);
319 goto exit;
320 }
321
322 switch (opt[0])
323 {
324 case 'w': optWidth = atoi(opt + 1); break;
325 case 'h': optHeight = atoi(opt + 1); break;
326 case 'v': optVSyncMode = atoi(opt + 1); break;
327 }
328 break;
329
330 default:
331 printf("Unknown option '%s'.\n", opt);
332 goto exit;
333 }
334 }
335 else
336 {
337 if (optSetInputFilename)
338 {
339 printf("ERROR: Please specify only one scene file.\n");
340 goto exit;
341 }
342
343 optSetInputFilename = true;
344 optInputFilename = std::string(arg);
345 if (optInputFilename.empty())
346 {
347 printf("ERROR: Invalid input filename.\n");
348 goto exit;
349 }
350
351 }
352 }
353
354 if (optShowHelp)
355 {
356 printf(
357 "Usage: %s [options] [<scenefile.scene>]\n"
358 "-? Show this help\n"
359 "-g Use GLSL shader instead of basic OpenGL lighting\n"
360 "-w<width> Window width (default %d)\n"
361 "-h<height> Window height (default %d)\n"
362 "-v<1-3> Set vsync mode: 1 = no vsync, 2 = vsync, 3 = adaptive\n"
363 " Default is no vsync. Using vsync will result in FPS being\n"
364 " approx whatever your monitor refresh rate is.\n"
365 "\n",
366 argv[0],
367 SET_DEF_WIDTH, SET_DEF_HEIGHT
368 );
369
370 goto exit;
371 }
372
373 if (optWidth < 100 || optWidth > 8192 || optHeight < 100 || optHeight > 8192)
374 {
375 printf("ERROR: Invalid window width or height (%d x %d).\n",
376 optWidth, optHeight);
377 goto exit;
378 }
379
380 // Load the scene
381 if (!scene.loadInfo(optInputFilename))
382 goto exit;
383
384 if (scene.models.size() == 0)
385 {
386 printf("ERROR: Scenefile '%s' contains no models.\n",
387 optInputFilename.c_str());
388 goto exit;
389 }
390
391 printf("INFO: Loading %ld model(s) ..\n",
392 scene.models.size());
393
394 basePath = dmGetPath(optInputFilename);
395 printf("INFO: Model base path '%s'\n", basePath.c_str());
396
397 for (DMModel &model : scene.models)
398 {
399 if (!model.loadFromPLY(basePath + model.modelFile))
400 goto exit;
401
402 if (optUseShaders)
403 {
404 std::string
405 fragFile = model.fragShaderFile.empty() ? "shader.frag" : basePath + model.fragShaderFile,
406 vertFile = model.vertShaderFile.empty() ? "shader.vert" : basePath + model.vertShaderFile;
407
408 if (!dmReadText(fragFile, model.fragShaderStr, SET_MAX_SHADER_SIZE) ||
409 !dmReadText(vertFile, model.vertShaderStr, SET_MAX_SHADER_SIZE))
410 goto exit;
411 }
412 }
413
414 // Initialize SDL + OpenGL
415 if (!dmInitSDLGL(optWidth, optHeight, "GLDragon"))
416 goto exit;
417
418 // According to our mode ..
419 if (optUseShaders)
420 {
421 for (DMModel &model : scene.models)
422 {
423 model.id_fs = dmCompileShader(GL_FRAGMENT_SHADER, model.fragShaderStr);
424 model.id_vs = dmCompileShader(GL_VERTEX_SHADER, model.vertShaderStr);
425 dmLinkModelShaders(model);
426 }
427 }
428 else
429 {
430 float specReflection[] = { 0.8f, 0.8f, 0.8f, 1.0f };
431
432 glEnable(GL_COLOR_MATERIAL);
433
434 glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
435 glMateriali(GL_FRONT, GL_SHININESS, 96);
436 glMaterialfv(GL_FRONT, GL_SPECULAR, specReflection);
437
438 glEnable(GL_LIGHT0);
439
440 // Define the light components and position
441 GLfloat ambient[] = { 0.2f, 0.2f, 0.2f, 1.0f };
442 GLfloat diffuse[] = { 0.8f, 0.8f, 0.8f, 1.0f };
443 GLfloat specular[] = { 0.5f, 0.5f, 0.5f, 1.0f };
444 GLfloat position[] = { 10.0f, 10.0f, 0.0f, 0.0f };
445
446 // Define the light components and position
447 glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
448 glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
449 glLightfv(GL_LIGHT0, GL_SPECULAR, specular);
450 glLightfv(GL_LIGHT0, GL_POSITION, position);
451 }
452
453 // Define the camera
454 gluLookAt(0, 0.12, 0.24, 0, 0.12, 0, 0, 1, 0);
455
456
457 // Main loop starts
458 startTime = cycleStart = SDL_GetTicks();
459
460 while (!exitFlag)
461 {
462 SDL_Event event;
463
464 // Check for quit events
465 while (SDL_PollEvent(&event))
466 switch (event.type)
467 {
468 case SDL_QUIT:
469 exitFlag = true;
470 break;
471
472 case SDL_KEYDOWN:
473 switch (event.key.keysym.sym)
474 {
475 case SDLK_ESCAPE:
476 case SDLK_q:
477 exitFlag = true;
478 break;
479 }
480 }
481
482 // Render the next frame
483 dmDrawScene(scene);
484
485 // Draw the current frame
486 SDL_GL_SwapWindow(dmWindow);
487
488 // Rotate for 2 degrees
489 glRotatef(2.0f, 0, 1, 0);
490
491 // Return true if a full rotation was done
492 totalFrames++;
493 if (cycleFrames++ == SET_FRAMES)
494 {
495 // Reset cycleFrames
496 cycleFrames = 0;
497
498 // Get the time it took to render a full turn
499 int cycleEnd = SDL_GetTicks();
500 double cycleTime = cycleEnd - cycleStart;
501
502 // Restart the timer
503 cycleStart = SDL_GetTicks();
504
505 // Print the current frames per second
506 printf("%.1lf ms for %d frames = %.1lf FPS\n",
507 cycleTime, SET_FRAMES, (SET_FRAMES * 1000.0f) / cycleTime);
508 }
509 }
510
511 // Show totals
512 totalTime = SDL_GetTicks() - startTime;
513 printf("%.1lf ms total for %d total frames = %.2lf FPS average\n",
514 totalTime, totalFrames, (totalFrames * 1000.0f) / totalTime);
515
516 exit:
517 if (dmGLContext != NULL)
518 SDL_GL_DeleteContext(dmGLContext);
519
520 if (dmWindow != NULL)
521 SDL_DestroyWindow(dmWindow);
522
523 SDL_Quit();
524
525 return 0;
526 }