Mercurial > hg > forks > gldragon
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 } |