comparison glxdragon.cpp @ 6:4d6fec8f0c64

Implement optional support for vertex/fragment shaders. Cleanups.
author Matti Hamalainen <ccr@tnsp.org>
date Sun, 27 Oct 2019 22:09:38 +0200
parents 5dcae4dddcd9
children 95dd5417e7de
comparison
equal deleted inserted replaced
5:5dcae4dddcd9 6:4d6fec8f0c64
29 // 29 //
30 30
31 #include <SDL.h> 31 #include <SDL.h>
32 #include <SDL_opengl.h> 32 #include <SDL_opengl.h>
33 #include <GL/glu.h> 33 #include <GL/glu.h>
34 #include <GL/glext.h>
34 35
35 #include <iostream> 36 #include <iostream>
36 #include <sstream>
37 #include <fstream> 37 #include <fstream>
38 #include <stdexcept>
39 #include <string> 38 #include <string>
40 #include <vector> 39 #include <vector>
41 #include <algorithm>
42 #include <cstdio> 40 #include <cstdio>
43 #include <ctime> 41 #include <ctime>
44 42
45 43
46 #define SET_FRAMES (180 * 2) 44 #define SET_FRAMES (180 * 2)
47 45
48 46
49 SDL_Window *s_window = NULL; 47 bool opt_shaders = false;
50 SDL_GLContext s_context; 48 SDL_Window *sdl_window = NULL;
49 SDL_GLContext sdl_glctx = NULL;
51 50
52 51
53 struct Mesh 52 struct Mesh
54 { 53 {
55 int nvertices, nfaces; 54 int nvertices, nfaces;
56 std::vector<float> vertices; 55 std::vector<float> vertices;
57 std::vector<unsigned> faces; 56 std::vector<unsigned> faces;
57
58 GLuint id_prog, id_ps, id_vs;
58 }; 59 };
59 60
60 61
61 62
62 bool dmInitSDLGL(const int width, const int height, const char *title) 63 bool dmInitSDLGL(const int width, const int height, const char *title)
63 { 64 {
64 SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); 65 // Set GL attributes
65 SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); 66 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
66 SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); 67 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
68 SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
69
67 SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); 70 SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
68 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); 71 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
69 72
73 // Attempt to initialize libSDL
70 if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_EVENTS) != 0) 74 if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_EVENTS) != 0)
71 { 75 {
72 printf("ERROR: Unable to initialize SDL: %s\n", 76 printf("ERROR: Unable to initialize SDL: %s\n",
73 SDL_GetError()); 77 SDL_GetError());
74 return false; 78 return false;
75 } 79 }
76 80
77 if ((s_window = SDL_CreateWindow(title, 81 // Attempt to create a window
82 if ((sdl_window = SDL_CreateWindow(title,
78 SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 83 SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
79 width, height, 84 width, height,
80 SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE)) == NULL) 85 SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE)) == NULL)
81 { 86 {
82 printf("ERROR: Could not create SDL window: %s", 87 printf("ERROR: Could not create SDL window: %s",
83 SDL_GetError()); 88 SDL_GetError());
84 return false; 89 return false;
85 } 90 }
86 91
87 if ((s_context = SDL_GL_CreateContext(s_window)) == NULL) 92 if ((sdl_glctx = SDL_GL_CreateContext(sdl_window)) == NULL)
88 { 93 {
89 printf("ERROR: Unable to create SDL OpenGL context: %s\n", 94 printf("ERROR: Unable to create SDL OpenGL context: %s\n",
90 SDL_GetError()); 95 SDL_GetError());
91 return false; 96 return false;
92 } 97 }
93 98
99 // Dump some information
94 printf( 100 printf(
95 "GL_VENDOR : %s\n" 101 "GL_VENDOR : %s\n"
96 "GL_RENDERER : %s\n" 102 "GL_RENDERER : %s\n"
97 "GL_VERSION : %s\n", 103 "GL_VERSION : %s\n",
98 glGetString(GL_VENDOR), 104 glGetString(GL_VENDOR),
135 141
136 return true; 142 return true;
137 } 143 }
138 144
139 145
140 void dmInitScene(void)
141 {
142 glEnable(GL_COLOR_MATERIAL);
143
144 glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
145 glMateriali(GL_FRONT, GL_SHININESS, 96);
146
147 float specReflection[] = { 0.8f, 0.8f, 0.8f, 1.0f };
148 glMaterialfv(GL_FRONT, GL_SPECULAR, specReflection);
149
150
151 glEnable(GL_LIGHT0);
152
153 // Define the light components and position
154 GLfloat ambient[] = { 0.2f, 0.2f, 0.2f, 1.0f };
155 GLfloat diffuse[] = { 0.8f, 0.8f, 0.8f, 1.0f };
156 GLfloat specular[] = { 0.5f, 0.5f, 0.5f, 1.0f };
157 GLfloat position[] = { 10.0f, 10.0f, 0.0f, 0.0f };
158
159 // Define the light components and position
160 glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
161 glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
162 glLightfv(GL_LIGHT0, GL_SPECULAR, specular);
163 glLightfv(GL_LIGHT0, GL_POSITION, position);
164
165 // Define the camera
166 gluLookAt(0, 0.12, 0.24, 0, 0.12, 0, 0, 1, 0);
167 }
168
169
170 void dmFinish()
171 {
172 SDL_GL_DeleteContext(s_context);
173 SDL_DestroyWindow(s_window);
174 s_window = NULL;
175 SDL_Quit();
176 }
177
178
179 void dmDrawModelVA(const Mesh &mesh) 146 void dmDrawModelVA(const Mesh &mesh)
180 { 147 {
181 int maxIndices; 148 int maxIndices;
182 149
183 glGetIntegerv(GL_MAX_ELEMENTS_INDICES, &maxIndices); 150 glGetIntegerv(GL_MAX_ELEMENTS_INDICES, &maxIndices);
231 198
232 glMatrixMode(GL_MODELVIEW); 199 glMatrixMode(GL_MODELVIEW);
233 glPopMatrix(); 200 glPopMatrix();
234 201
235 glEnable(GL_DEPTH_TEST); 202 glEnable(GL_DEPTH_TEST);
236 glEnable(GL_LIGHTING); 203
237 204 // Render the model
238 // Set the color of the model 205 if (opt_shaders)
239 glColor3ub(0x90, 0x80, 0x90); 206 {
240 207 // Enable shader program
241 // Draw the model using vertex arrays 208 glUseProgram(mesh.id_prog);
242 dmDrawModelVA(mesh); 209 dmDrawModelVA(mesh);
243 } 210 glUseProgram(0);
244 211 }
245 212 else
246 void dmLoadMesh(const std::string &filename, Mesh &mesh, int nvertices, int nfaces) 213 {
214 // Set the color of the model
215 glEnable(GL_LIGHTING);
216 glColor3ub(0x90, 0x80, 0x90);
217 dmDrawModelVA(mesh);
218 }
219 }
220
221
222 bool dmReadText(const std::string &filename, std::string &tstr)
223 {
224 std::ifstream in(filename.c_str());
225
226 if (!in.is_open())
227 {
228 printf("ERROR: Unable to open file '%s'.\n",
229 filename.c_str());
230 return false;
231 }
232
233 in.seekg(0, std::ios::end);
234 tstr.reserve(in.tellg());
235 in.seekg(0, std::ios::beg);
236
237 tstr.assign((std::istreambuf_iterator<char>(in)), std::istreambuf_iterator<char>());
238
239 return true;
240 }
241
242
243 bool dmLoadMesh(const std::string &filename, Mesh &mesh, int nvertices, int nfaces)
247 { 244 {
248 std::ifstream in(filename.c_str(), std::ios::binary); 245 std::ifstream in(filename.c_str(), std::ios::binary);
249 246
250 if (!in.is_open()) 247 if (!in.is_open())
251 { 248 {
252 std::stringstream ss; 249 printf("ERROR: Unable to open file '%s'.\n",
253 ss << "Unable to open file: " << filename << '\n'; 250 filename.c_str());
254 throw std::runtime_error(ss.str()); 251 return false;
255 } 252 }
256 253
257 mesh.nvertices = nvertices; 254 mesh.nvertices = nvertices;
258 mesh.vertices.resize(mesh.nvertices * 6); 255 mesh.vertices.resize(mesh.nvertices * 6);
259 in.read(reinterpret_cast<char*>(&mesh.vertices[0]), mesh.nvertices * 6 * 4); 256 in.read(reinterpret_cast<char*>(&mesh.vertices[0]), mesh.nvertices * 6 * 4);
264 for (int i = 0; i < nfaces; i++) 261 for (int i = 0; i < nfaces; i++)
265 { 262 {
266 in.seekg(1, std::ios::cur); 263 in.seekg(1, std::ios::cur);
267 in.read(reinterpret_cast<char*>(&mesh.faces[i * 3]), 3 * 4); 264 in.read(reinterpret_cast<char*>(&mesh.faces[i * 3]), 3 * 4);
268 } 265 }
269 } 266
270 267 return true;
271 268 }
272 int main() 269
273 { 270
274 try 271 GLuint dmSetCompileShader(const GLenum stype, const std::string &src)
275 { 272 {
276 struct Mesh dragonMesh; 273 GLuint shader = glCreateShader(stype);
277 dmLoadMesh("dragon.mesh", dragonMesh, 100139, 200198); 274 const char *tmp = src.c_str();
278 275
279 //if (!dmInitSDLGL(640, 480, "glxdragon")) 276 glShaderSource(shader, 1, &tmp, 0);
280 if (!dmInitSDLGL(1280, 960, "glxdragon")) 277 glCompileShader(shader);
281 throw std::runtime_error("Fatal error."); 278
282 279 return shader;
283 dmInitScene(); 280 }
284 281
285 bool exitFlag = false; 282
286 int steps = 0; 283 void dmLinkMeshShaders(Mesh &mesh)
287 std::clock_t startTime = std::clock(); 284 {
288 285 mesh.id_prog = glCreateProgram();
289 while (!exitFlag) 286 glAttachShader(mesh.id_prog, mesh.id_ps);
287 glAttachShader(mesh.id_prog, mesh.id_vs);
288 glLinkProgram(mesh.id_prog);
289 }
290
291
292 int main(int argc, char *argv[])
293 {
294 struct Mesh dragonMesh;
295 std::string dragonVS, dragonFS;
296 std::clock_t startTime;
297 bool exitFlag = false;
298 int steps = 0;
299
300 // Check commandline argument for enabling shaders
301 if (argc > 1 &&
302 (strstr(argv[1], "glsl") != NULL ||
303 strstr(argv[1], "sha") != NULL))
304 opt_shaders = true;
305
306
307 if (!dmLoadMesh("dragon.mesh", dragonMesh, 100139, 200198))
308 goto exit;
309
310 if (opt_shaders)
311 {
312 // Read shader files
313 if (!dmReadText("dragon.frag", dragonFS) ||
314 !dmReadText("dragon.vert", dragonVS))
315 goto exit;
316 }
317
318 // Initialize SDL + OpenGL
319 if (!dmInitSDLGL(1280, 960, "GLXDragon2"))
320 goto exit;
321
322 // According to our mode ..
323 if (opt_shaders)
324 {
325 dragonMesh.id_ps = dmSetCompileShader(GL_FRAGMENT_SHADER, dragonFS);
326 dragonMesh.id_vs = dmSetCompileShader(GL_VERTEX_SHADER, dragonVS);
327 dmLinkMeshShaders(dragonMesh);
328 }
329 else
330 {
331 float specReflection[] = { 0.8f, 0.8f, 0.8f, 1.0f };
332
333 glEnable(GL_COLOR_MATERIAL);
334
335 glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
336 glMateriali(GL_FRONT, GL_SHININESS, 96);
337
338 glMaterialfv(GL_FRONT, GL_SPECULAR, specReflection);
339
340 glEnable(GL_LIGHT0);
341
342 // Define the light components and position
343 GLfloat ambient[] = { 0.2f, 0.2f, 0.2f, 1.0f };
344 GLfloat diffuse[] = { 0.8f, 0.8f, 0.8f, 1.0f };
345 GLfloat specular[] = { 0.5f, 0.5f, 0.5f, 1.0f };
346 GLfloat position[] = { 10.0f, 10.0f, 0.0f, 0.0f };
347
348 // Define the light components and position
349 glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
350 glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
351 glLightfv(GL_LIGHT0, GL_SPECULAR, specular);
352 glLightfv(GL_LIGHT0, GL_POSITION, position);
353 }
354
355 // Define the camera
356 gluLookAt(0, 0.12, 0.24, 0, 0.12, 0, 0, 1, 0);
357
358
359 // Main loop starts
360 startTime = std::clock();
361
362 while (!exitFlag)
363 {
364 SDL_Event event;
365
366 // Check for quit events
367 while (SDL_PollEvent(&event))
368 switch (event.type)
290 { 369 {
291 SDL_Event event; 370 case SDL_QUIT:
292 371 exitFlag = true;
293 // Check for quit events 372 break;
294 while (SDL_PollEvent(&event)) 373
295 switch (event.type) 374 case SDL_KEYDOWN:
296 { 375 switch (event.key.keysym.sym)
297 case SDL_QUIT: 376 {
298 exitFlag = true; 377 case SDLK_ESCAPE:
299 break; 378 case SDLK_q:
300 379 exitFlag = true;
301 case SDL_KEYDOWN: 380 break;
302 switch (event.key.keysym.sym) 381 }
303 {
304 case SDLK_ESCAPE:
305 case SDLK_q:
306 exitFlag = true;
307 break;
308 }
309 }
310
311 // Render the next frame
312 dmPaintGL(dragonMesh);
313
314 // Draw the current frame
315 SDL_GL_SwapWindow(s_window);
316
317 // Rotate for 2 degrees
318 glRotatef(2.0f, 0, 1, 0);
319
320 // Return true if a full rotation was done
321 if (steps++ == SET_FRAMES)
322 {
323 // Reset steps
324 steps = 0;
325
326 // Get the time it took to render a full turn
327 double time = (double(std::clock() - startTime) * 1000.0f) / CLOCKS_PER_SEC;
328
329 // Print the current frames per second
330 printf("%.1lf ms for %d frames = %.1lf FPS\n",
331 time, SET_FRAMES, (SET_FRAMES * 1000.0f) / time);
332
333 // Restart the timer
334 startTime = std::clock();
335 }
336 } 382 }
337 } 383
338 catch(std::runtime_error & e) 384 // Render the next frame
339 { 385 dmPaintGL(dragonMesh);
340 std::cerr << e.what(); 386
341 } 387 // Draw the current frame
342 388 SDL_GL_SwapWindow(sdl_window);
343 dmFinish(); 389
344 } 390 // Rotate for 2 degrees
391 glRotatef(2.0f, 0, 1, 0);
392
393 // Return true if a full rotation was done
394 if (steps++ == SET_FRAMES)
395 {
396 // Reset steps
397 steps = 0;
398
399 // Get the time it took to render a full turn
400 double time = (double(std::clock() - startTime) * 1000.0f) / CLOCKS_PER_SEC;
401
402 // Print the current frames per second
403 printf("%.1lf ms for %d frames = %.1lf FPS\n",
404 time, SET_FRAMES, (SET_FRAMES * 1000.0f) / time);
405
406 // Restart the timer
407 startTime = std::clock();
408 }
409 }
410
411 exit:
412 if (sdl_glctx != NULL)
413 SDL_GL_DeleteContext(sdl_glctx);
414
415 if (sdl_window != NULL)
416 SDL_DestroyWindow(sdl_window);
417
418 SDL_Quit();
419
420 return 0;
421 }