comparison glxdragon.cpp @ 3:be31ff9e5f58

Port to libSDL2, clean up the code and some de-C++-ifications.
author Matti Hamalainen <ccr@tnsp.org>
date Sun, 27 Oct 2019 17:57:37 +0200
parents b45d8958e5a6
children 5dcae4dddcd9
comparison
equal deleted inserted replaced
2:b45d8958e5a6 3:be31ff9e5f58
1 1 //
2 // Copyright (c) 2009, Thomas Trummer 2 // Copyright (c) 2009, Thomas Trummer
3 // All rights reserved. 3 // All rights reserved.
4 //
5 // Port to libSDL2 and cleanups by Matti Hämäläinen <ccr@tnsp.org>
6 // (C) Copyright 2019 Tecnic Software productions (TNSP)
4 // 7 //
5 // Redistribution and use in source and binary forms, with or without 8 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are met: 9 // modification, are permitted provided that the following conditions are met:
7 // * Redistributions of source code must retain the above copyright 10 // * Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer. 11 // notice, this list of conditions and the following disclaimer.
21 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 25 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 29 //
27 30
28 #include <SDL.h> 31 #include <SDL.h>
29 #include <SDL_opengl.h> 32 #include <SDL_opengl.h>
33 #include <GL/glu.h>
30 34
31 #include <iostream> 35 #include <iostream>
32 #include <sstream> 36 #include <sstream>
33 #include <fstream> 37 #include <fstream>
34 #include <stdexcept> 38 #include <stdexcept>
37 #include <algorithm> 41 #include <algorithm>
38 #include <cstdio> 42 #include <cstdio>
39 #include <ctime> 43 #include <ctime>
40 44
41 45
46 #define SET_FRAMES (180 * 2)
47
48
49 SDL_Window *s_window = NULL;
50 SDL_GLContext s_context;
51
52
42 struct Mesh 53 struct Mesh
43 { 54 {
44 std::vector <float> vertices; 55 std::vector<float> vertices;
45 std::vector <unsigned> faces; 56 std::vector<unsigned> faces;
46 } 57 };
47 dragonMesh; 58
48 59
49 60 bool init(const int width, const int height, const char *title)
50 void init(const int windowWidth, const int windowHeight, const std::string& windowTitle) 61 {
51 {
52 std::stringstream ss;
53
54
55 if (SDL_Init(SDL_INIT_VIDEO) != 0)
56 {
57 ss << "Unable to initialize SDL: " << SDL_GetError() << '\n';
58
59 throw std::runtime_error(ss.str());
60 }
61
62
63 SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); 62 SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
64 SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); 63 SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
65 SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); 64 SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
66 SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); 65 SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
67 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); 66 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
68 67
69 68 if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_EVENTS) != 0)
70 SDL_WM_SetCaption(windowTitle.c_str(), 0); 69 {
71 70 printf("ERROR: Unable to initialize SDL: %s\n",
72 71 SDL_GetError());
73 if ((SDL_SetVideoMode(windowWidth, windowHeight, 0, SDL_OPENGL)) == NULL) 72 return false;
74 { 73 }
75 ss << "Couldn't set GL mode: " << SDL_GetError() << '\n'; 74
76 75 if ((s_window = SDL_CreateWindow(title,
77 throw std::runtime_error(ss.str()); 76 SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
78 } 77 width, height,
79 78 SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE)) == NULL)
80 79 {
81 std::cout << "GL_VENDOR : " << glGetString(GL_VENDOR) << std::endl; 80 printf("ERROR: Could not create SDL window: %s",
82 std::cout << "GL_RENDERER : " << glGetString(GL_RENDERER) << std::endl; 81 SDL_GetError());
83 std::cout << "GL_VERSION : " << glGetString(GL_VERSION) << std::endl; 82 return false;
84 83 }
85 std::cout << std::endl; 84
86 85 if ((s_context = SDL_GL_CreateContext(s_window)) == NULL)
86 {
87 printf("ERROR: Unable to create SDL OpenGL context: %s\n",
88 SDL_GetError());
89 return false;
90 }
91
92 printf(
93 "GL_VENDOR : %s\n"
94 "GL_RENDERER : %s\n"
95 "GL_VERSION : %s\n",
96 glGetString(GL_VENDOR),
97 glGetString(GL_RENDERER),
98 glGetString(GL_VERSION));
87 99
88 // Setup the window and view port 100 // Setup the window and view port
89 glViewport(0, 0, windowWidth, windowHeight); 101 glViewport(0, 0, width, height);
90 102
91 glMatrixMode(GL_PROJECTION); 103 glMatrixMode(GL_PROJECTION);
92 glLoadIdentity(); 104 glLoadIdentity();
93 105
94 gluPerspective(45.0f, GLfloat(windowWidth) / GLfloat(windowHeight), 0.1f, 1000.0f); 106 gluPerspective(45.0f, GLfloat(width) / GLfloat(height), 0.1f, 1000.0f);
95 107
96 glMatrixMode(GL_MODELVIEW); 108 glMatrixMode(GL_MODELVIEW);
97 glLoadIdentity(); 109 glLoadIdentity();
98 110
99 111
116 glEnableClientState(GL_VERTEX_ARRAY); 128 glEnableClientState(GL_VERTEX_ARRAY);
117 glEnableClientState(GL_NORMAL_ARRAY); 129 glEnableClientState(GL_NORMAL_ARRAY);
118 130
119 // Set correct perspective correction 131 // Set correct perspective correction
120 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); 132 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
133
134 return true;
121 } 135 }
122 136
123 137
124 void initScene() 138 void initScene()
125 { 139 {
151 } 165 }
152 166
153 167
154 void done() 168 void done()
155 { 169 {
170 SDL_GL_DeleteContext(s_context);
171 SDL_DestroyWindow(s_window);
172 s_window = NULL;
156 SDL_Quit(); 173 SDL_Quit();
157 } 174 }
158 175
159 176
160 void drawModelVA(const Mesh& mesh) 177 void drawModelVA(const Mesh& mesh)
161 { 178 {
162 int maxIndices; 179 int maxIndices;
163 180
164 glGetIntegerv(GL_MAX_ELEMENTS_INDICES, &maxIndices); 181 glGetIntegerv(GL_MAX_ELEMENTS_INDICES, &maxIndices);
165
166 182
167 glVertexPointer(3, GL_FLOAT, 24, &mesh.vertices[0]); 183 glVertexPointer(3, GL_FLOAT, 24, &mesh.vertices[0]);
168 glNormalPointer(GL_FLOAT, 24, &mesh.vertices[3]); 184 glNormalPointer(GL_FLOAT, 24, &mesh.vertices[3]);
169 185
170
171 for (size_t n = 0; n < mesh.faces.size() / 3; n += maxIndices) 186 for (size_t n = 0; n < mesh.faces.size() / 3; n += maxIndices)
172 { 187 {
173 const int count = std::min(maxIndices, int(mesh.faces.size() / 3 - n)); 188 const int count = std::min(maxIndices, int(mesh.faces.size() / 3 - n));
174 189 glDrawElements(GL_TRIANGLES, count * 3, GL_UNSIGNED_INT, &mesh.faces[n * 3]);
175 glDrawElements(GL_TRIANGLES, count * 3, GL_UNSIGNED_INT, &dragonMesh.faces[n * 3]); 190 }
176 } 191 }
177 } 192
178 193
179 194 void paintGL(Mesh &mesh)
180 bool paintGL()
181 { 195 {
182 glClear(GL_DEPTH_BUFFER_BIT); 196 glClear(GL_DEPTH_BUFFER_BIT);
183
184 197
185 glMatrixMode(GL_PROJECTION); 198 glMatrixMode(GL_PROJECTION);
186 glPushMatrix(); 199 glPushMatrix();
187 glLoadIdentity(); 200 glLoadIdentity();
188 201
215 glPopMatrix(); 228 glPopMatrix();
216 229
217 glMatrixMode(GL_MODELVIEW); 230 glMatrixMode(GL_MODELVIEW);
218 glPopMatrix(); 231 glPopMatrix();
219 232
220
221 glEnable(GL_DEPTH_TEST); 233 glEnable(GL_DEPTH_TEST);
234
222 glEnable(GL_LIGHTING); 235 glEnable(GL_LIGHTING);
223
224
225 // Set the color of the model 236 // Set the color of the model
226 glColor3ub(0x90, 0x80, 0x90); 237 glColor3ub(0x90, 0x80, 0x90);
227 238
239
240
241
228 // Draw the model using vertex arrays 242 // Draw the model using vertex arrays
229 drawModelVA(dragonMesh); 243 drawModelVA(mesh);
230 244 }
231 // Draw the current frame 245
232 SDL_GL_SwapBuffers(); 246
233 247 void loadMesh(const std::string& filename, Mesh& mesh, size_t nvertices, size_t nfaces)
234 248 {
235 249 std::ifstream in(filename.c_str(), std::ios::binary);
236 static int steps = 0; 250
237 251 if (!in.is_open())
238 // Rotate for 2 degrees 252 {
239 glRotatef(2.0f, 0, 1, 0); 253 std::stringstream ss;
240 254 ss << "Unable to open file: " << filename << '\n';
241 // Return true if a full rotation was done 255 throw std::runtime_error(ss.str());
242 return (steps++ == 180) ? (steps = 0, true) : false; 256 }
243 } 257
244 258 mesh.vertices.resize(nvertices * 6);
245 259 in.read(reinterpret_cast<char*>(&mesh.vertices[0]), nvertices * 6 * 4);
246 void runEventLoop() 260
247 { 261 mesh.faces.resize(nfaces * 3);
248 static std::clock_t startTime = std::clock(); 262
249 263 for (size_t i = 0; i < nfaces; i++)
250 while (true) 264 {
251 { 265 in.seekg(1, std::ios::cur);
252 SDL_Event event; 266 in.read(reinterpret_cast<char*>(&mesh.faces[i * 3]), 3 * 4);
253 267 }
254 if (SDL_PollEvent(&event)) 268 }
269
270
271 int main()
272 {
273 try
274 {
275 struct Mesh dragonMesh;
276 loadMesh("dragon.mesh", dragonMesh, 100139, 200198);
277
278 //if (!init(640, 480, "glxdragon"))
279 if (!init(1280, 960, "glxdragon"))
280 throw std::runtime_error("Fatal error.");
281
282 initScene();
283
284 bool exitFlag = false;
285 int steps = 0;
286 std::clock_t startTime = std::clock();
287
288 while (!exitFlag)
255 { 289 {
256 if (event.type == SDL_QUIT) 290 SDL_Event event;
257 break; 291
258 } 292 // Check for quit events
259 else 293 while (SDL_PollEvent(&event))
260 { 294 switch (event.type)
261 // Render the next frame and test if a full turn was completed
262 if (paintGL())
263 { 295 {
296 case SDL_QUIT:
297 exitFlag = true;
298 break;
299
300 case SDL_KEYDOWN:
301 switch (event.key.keysym.sym)
302 {
303 case SDLK_ESCAPE:
304 case SDLK_q:
305 exitFlag = true;
306 break;
307 }
308 }
309
310
311 // Render the next frame
312 paintGL(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
264 // Get the time it took to render a full turn 326 // Get the time it took to render a full turn
265 double time = double(std::clock() - startTime) / CLOCKS_PER_SEC; 327 double time = (double(std::clock() - startTime) * 1000.0f) / CLOCKS_PER_SEC;
266 328
267 // Print the current frames per second 329 // Print the current frames per second
268 std::printf("%.1lf seconds for 180 frames = %.1lf FPS\n", time, 180 / time); 330 std::printf("%.1lf ms for %d frames = %.1lf FPS\n",
331 time, SET_FRAMES, (SET_FRAMES * 1000.0f) / time);
269 332
270 // Restart the timer 333 // Restart the timer
271 startTime = std::clock(); 334 startTime = std::clock();
272 } 335 }
273 } 336 }
274 } 337 }
275 }
276
277
278 void loadMesh(const std::string& fileName, Mesh& mesh)
279 {
280 std::ifstream in(fileName.c_str(), std::ios::binary);
281
282
283 if (!in.is_open())
284 {
285 std::stringstream ss;
286
287 ss << "Unable to open file: " << fileName << '\n';
288
289 throw std::runtime_error(ss.str());
290
291 }
292
293
294 mesh.vertices.resize(100139 * 6);
295 in.read(reinterpret_cast<char*>(&mesh.vertices[0]), 100139 * 6 * 4);
296
297
298 mesh.faces.resize(200198 * 3);
299 for (unsigned i = 0; i < 200198; i++)
300 {
301 in.seekg(1, std::ios::cur);
302
303 in.read(reinterpret_cast<char*>(&mesh.faces[i * 3]), 3 * 4);
304 }
305 }
306
307
308 int main()
309 {
310 try
311 {
312 loadMesh("dragon.mesh", dragonMesh);
313
314 init(640, 480, "glxdragon");
315
316 initScene();
317
318 runEventLoop();
319 }
320 catch(std::runtime_error & e) 338 catch(std::runtime_error & e)
321 { 339 {
322 std::cerr << e.what(); 340 std::cerr << e.what();
323 } 341 }
324
325 done(); 342 done();
326 } 343 }