1 | /*! |
2 | * \file sdl_demo.cpp |
3 | * \brief file sdl_demo.cpp |
4 | * |
5 | * Adapted from: sdl_demo.cpp of WRATH: |
6 | * |
7 | * Copyright 2013 by Nomovok Ltd. |
8 | * Contact: info@nomovok.com |
9 | * This Source Code Form is subject to the |
10 | * terms of the Mozilla Public License, v. 2.0. |
11 | * If a copy of the MPL was not distributed with |
12 | * this file, You can obtain one at |
13 | * http://mozilla.org/MPL/2.0/. |
14 | * |
15 | * \author Kevin Rogovin <kevin.rogovin@nomovok.com> |
16 | * \author Kevin Rogovin <kevin.rogovin@gmail.com> |
17 | * |
18 | */ |
19 | |
20 | |
21 | #include <typeinfo> |
22 | #include <fstream> |
23 | #include <SDL_syswm.h> |
24 | #include <SDL_video.h> |
25 | #include <SDL_render.h> |
26 | #include <SDL_surface.h> |
27 | |
28 | #include <fastuidraw/util/vecN.hpp> |
29 | #include <fastuidraw/util/fastuidraw_memory.hpp> |
30 | #include <fastuidraw/gl_backend/gl_binding.hpp> |
31 | #include <fastuidraw/gl_backend/gl_get.hpp> |
32 | |
33 | #include "generic_command_line.hpp" |
34 | #include "simple_time.hpp" |
35 | #include "stream_holder.hpp" |
36 | #include "sdl_demo.hpp" |
37 | |
38 | namespace |
39 | { |
40 | int |
41 | GetSDLGLValue(SDL_GLattr arg) |
42 | { |
43 | int R(0); |
44 | SDL_GL_GetAttribute(arg, &R); |
45 | return R; |
46 | } |
47 | |
48 | void |
49 | print_gl_extensions(std::ostream &dst) |
50 | { |
51 | int cnt; |
52 | |
53 | cnt = fastuidraw::gl::context_get<GLint>(GL_NUM_EXTENSIONS); |
54 | dst << "\nGL_EXTENSIONS(" << cnt << "):" ; |
55 | for(int i = 0; i < cnt; ++i) |
56 | { |
57 | dst << "\n\t" << fastuidraw_glGetStringi(GL_EXTENSIONS, i); |
58 | } |
59 | } |
60 | |
61 | bool |
62 | is_help_request(const std::string &v) |
63 | { |
64 | return v==std::string("-help" ) |
65 | or v==std::string("--help" ) |
66 | or v==std::string("-h" ); |
67 | } |
68 | |
69 | void |
70 | reverse_y_of_sdl_event(int h, SDL_Event &ev) |
71 | { |
72 | switch(ev.type) |
73 | { |
74 | case SDL_MOUSEBUTTONUP: |
75 | case SDL_MOUSEBUTTONDOWN: |
76 | ev.button.y = h - ev.button.y; |
77 | break; |
78 | |
79 | case SDL_MOUSEMOTION: |
80 | ev.motion.y = h - ev.motion.y; |
81 | ev.motion.yrel = -ev.motion.yrel; |
82 | break; |
83 | } |
84 | } |
85 | |
86 | void* |
87 | get_proc(fastuidraw::c_string proc_name) |
88 | { |
89 | return SDL_GL_GetProcAddress(proc_name); |
90 | } |
91 | |
92 | class OstreamLogger:public fastuidraw::gl_binding::CallbackGL |
93 | { |
94 | public: |
95 | explicit |
96 | OstreamLogger(const fastuidraw::reference_counted_ptr<StreamHolder> &str): |
97 | m_str(str) |
98 | {} |
99 | |
100 | virtual |
101 | void |
102 | pre_call(fastuidraw::c_string call_string_values, |
103 | fastuidraw::c_string call_string_src, |
104 | fastuidraw::c_string function_name, |
105 | void *function_ptr, |
106 | fastuidraw::c_string src_file, int src_line); |
107 | |
108 | virtual |
109 | void |
110 | post_call(fastuidraw::c_string call_string_values, |
111 | fastuidraw::c_string call_string_src, |
112 | fastuidraw::c_string function_name, |
113 | fastuidraw::c_string error_string, |
114 | void *function_ptr, |
115 | fastuidraw::c_string src_file, int src_line); |
116 | |
117 | virtual |
118 | void |
119 | message(fastuidraw::c_string message, |
120 | fastuidraw::c_string src_file, int src_line); |
121 | |
122 | private: |
123 | fastuidraw::reference_counted_ptr<StreamHolder> m_str; |
124 | }; |
125 | } |
126 | |
127 | ////////////////////////// |
128 | // OstreamLogger methods |
129 | void |
130 | OstreamLogger:: |
131 | pre_call(fastuidraw::c_string call_string_values, |
132 | fastuidraw::c_string call_string_src, |
133 | fastuidraw::c_string function_name, |
134 | void *function_ptr, |
135 | fastuidraw::c_string src_file, int src_line) |
136 | { |
137 | FASTUIDRAWunused(call_string_src); |
138 | FASTUIDRAWunused(function_name); |
139 | FASTUIDRAWunused(function_ptr); |
140 | m_str->stream() << "Pre: [" << src_file << "," << src_line << "] " |
141 | << call_string_values << "\n" ; |
142 | } |
143 | |
144 | void |
145 | OstreamLogger:: |
146 | post_call(fastuidraw::c_string call_string_values, |
147 | fastuidraw::c_string call_string_src, |
148 | fastuidraw::c_string function_name, |
149 | fastuidraw::c_string error_string, |
150 | void *function_ptr, |
151 | fastuidraw::c_string src_file, int src_line) |
152 | { |
153 | FASTUIDRAWunused(call_string_src); |
154 | FASTUIDRAWunused(function_name); |
155 | FASTUIDRAWunused(function_ptr); |
156 | FASTUIDRAWunused(error_string); |
157 | m_str->stream() << "Post: [" << src_file << "," << src_line << "] " |
158 | << call_string_values; |
159 | |
160 | if (error_string && *error_string) |
161 | { |
162 | m_str->stream() << "{" << error_string << "}" ; |
163 | } |
164 | m_str->stream() << "\n" ; |
165 | } |
166 | |
167 | void |
168 | OstreamLogger:: |
169 | message(fastuidraw::c_string message, |
170 | fastuidraw::c_string src_file, |
171 | int src_line) |
172 | { |
173 | m_str->stream() << "Message: [" << src_file << "," << src_line << "] " |
174 | << message << "\n" ; |
175 | } |
176 | |
177 | //////////////////////////// |
178 | // sdl_demo methods |
179 | sdl_demo:: |
180 | sdl_demo(const std::string &about_text, bool dimensions_must_match_default_value): |
181 | m_handle_events(true), |
182 | m_about(command_line_argument::tabs_to_spaces(command_line_argument::format_description_string("" , about_text))), |
183 | m_common_label("Screen and Context Option" , *this), |
184 | m_red_bits(8, "red_bits" , |
185 | "Bpp of red channel, non-positive values mean use SDL defaults" , |
186 | *this), |
187 | m_green_bits(8, "green_bits" , |
188 | "Bpp of green channel, non-positive values mean use SDL defaults" , |
189 | *this), |
190 | m_blue_bits(8, "blue_bits" , |
191 | "Bpp of blue channel, non-positive values mean use SDL defaults" , |
192 | *this), |
193 | m_alpha_bits(8, "alpha_bits" , |
194 | "Bpp of alpha channel, non-positive values mean use SDL defaults" , |
195 | *this), |
196 | m_depth_bits(24, "depth_bits" , |
197 | "Bpp of depth buffer, non-positive values mean use SDL defaults" , |
198 | *this), |
199 | m_stencil_bits(8, "stencil_bits" , |
200 | "Bpp of stencil buffer, non-positive values mean use SDL defaults" , |
201 | *this), |
202 | m_fullscreen(false, "fullscreen" , "fullscreen mode" , *this), |
203 | m_hide_cursor(false, "hide_cursor" , "If true, hide the mouse cursor with a SDL call" , *this), |
204 | m_use_msaa(false, "enable_msaa" , "If true enables MSAA" , *this), |
205 | m_msaa(4, "msaa_samples" , |
206 | "If greater than 0, specifies the number of samples " |
207 | "to request for MSAA. If not, SDL will choose the " |
208 | "sample count as the highest available value" , |
209 | *this), |
210 | m_width(800, "width" , "window width" , *this), |
211 | m_height(480, "height" , "window height" , *this), |
212 | m_dimensions_must_match(dimensions_must_match_default_value, "dimensions_must_match" , |
213 | "If true, then will abort if the created window dimensions do not " |
214 | "match precisely the width and height parameters" , *this), |
215 | m_bpp(32, "bpp" , "bits per pixel" , *this), |
216 | m_log_gl_commands("" , "log_gl" , "if non-empty, GL commands are logged to the named file. " |
217 | "If value is stderr then logged to stderr, if value is stdout logged to stdout" , *this), |
218 | m_print_gl_info(false, "print_gl_info" , "If true print to stdout GL information" , *this), |
219 | m_swap_interval(-1, "swap_interval" , |
220 | "If set, pass the specified value to SDL_GL_SetSwapInterval, " |
221 | "a value of 0 means no vsync, a value of 1 means vsync and " |
222 | "a value of -1, if the platform supports, late swap tearing " |
223 | "as found in extensions GLX_EXT_swap_control_tear and " |
224 | "WGL_EXT_swap_control_tear. STRONG REMINDER: the value is " |
225 | "only passed to SDL_GL_SetSwapInterval if the value is set " |
226 | "at command line" , *this), |
227 | #ifdef FASTUIDRAW_GL_USE_GLES |
228 | m_gl_major(3, "gles_major" , "GLES major version" , *this), |
229 | m_gl_minor(0, "gles_minor" , "GLES minor version" , *this), |
230 | #else |
231 | m_gl_major(3, "gl_major" , "GL major version" , *this), |
232 | m_gl_minor(3, "gl_minor" , "GL minor version" , *this), |
233 | m_gl_forward_compatible_context(false, "foward_context" , "if true request forward compatible context" , *this), |
234 | m_gl_debug_context(false, "debug_context" , "if true request a context with debug" , *this), |
235 | m_gl_core_profile(true, "core_context" , "if true request a context which is core profile" , *this), |
236 | m_try_to_get_latest_gl_version(true, "try_to_get_latest_gl_version" , |
237 | "If true, first create a GL context the old fashioned way " |
238 | "and query its context version and then max that value with " |
239 | "the requested version before making the context used by the application" , |
240 | *this), |
241 | #endif |
242 | |
243 | m_show_framerate(false, "show_framerate" , "if true show the cumulative framerate at end" , *this), |
244 | m_num_warm_up_frames(10, "num_warm_up_frames" , |
245 | "Number of warm-up frames to ignore in timing the average framerate" , *this), |
246 | m_reverse_event_y(false), |
247 | m_window(nullptr), |
248 | m_ctx(nullptr) |
249 | { |
250 | |
251 | } |
252 | |
253 | sdl_demo:: |
254 | ~sdl_demo() |
255 | { |
256 | if (m_window) |
257 | { |
258 | if (m_ctx) |
259 | { |
260 | SDL_GL_MakeCurrent(m_window, nullptr); |
261 | SDL_GL_DeleteContext(m_ctx); |
262 | } |
263 | |
264 | SDL_ShowCursor(SDL_ENABLE); |
265 | SDL_SetWindowGrab(m_window, SDL_FALSE); |
266 | |
267 | SDL_DestroyWindow(m_window); |
268 | SDL_Quit(); |
269 | } |
270 | } |
271 | |
272 | void |
273 | sdl_demo:: |
274 | set_sdl_gl_context_attributes(void) |
275 | { |
276 | #ifdef FASTUIDRAW_GL_USE_GLES |
277 | { |
278 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, m_gl_major.value()); |
279 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, m_gl_minor.value()); |
280 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); |
281 | } |
282 | #else |
283 | { |
284 | if (m_gl_major.value() >= 3) |
285 | { |
286 | int context_flags(0); |
287 | int profile_mask(0); |
288 | |
289 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, m_gl_major.value()); |
290 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, m_gl_minor.value()); |
291 | |
292 | if (m_gl_forward_compatible_context.value()) |
293 | { |
294 | context_flags |= SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG; |
295 | } |
296 | |
297 | if (m_gl_debug_context.value()) |
298 | { |
299 | context_flags |= SDL_GL_CONTEXT_DEBUG_FLAG; |
300 | } |
301 | |
302 | if (m_gl_core_profile.value()) |
303 | { |
304 | profile_mask = SDL_GL_CONTEXT_PROFILE_CORE; |
305 | } |
306 | else |
307 | { |
308 | profile_mask = SDL_GL_CONTEXT_PROFILE_COMPATIBILITY; |
309 | } |
310 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, context_flags); |
311 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, profile_mask); |
312 | } |
313 | } |
314 | #endif |
315 | } |
316 | |
317 | void |
318 | sdl_demo:: |
319 | create_sdl_gl_context(void) |
320 | { |
321 | #ifdef FASTUIDRAW_GL_USE_GLES |
322 | { |
323 | set_sdl_gl_context_attributes(); |
324 | m_ctx = SDL_GL_CreateContext(m_window); |
325 | } |
326 | #else |
327 | { |
328 | if (!m_try_to_get_latest_gl_version.value()) |
329 | { |
330 | set_sdl_gl_context_attributes(); |
331 | m_ctx = SDL_GL_CreateContext(m_window); |
332 | return; |
333 | } |
334 | |
335 | /* Some WGL/GLX implementations will only give the exact GL |
336 | * version requested, but for our purposes we really want the |
337 | * latest version we can get. Very often, by having SDL create |
338 | * a context the old-fashioned way, we can get a context of |
339 | * the greatest version for compatibility profiles. We get SDL to |
340 | * make a GL context the old-fashioned way by NOT setting any |
341 | * of the SDL-GL attributes related to context versions/profiles |
342 | */ |
343 | m_ctx = SDL_GL_CreateContext(m_window); |
344 | if (m_ctx == nullptr) |
345 | { |
346 | std::cerr << "Unable to create vanilla GL context: " << SDL_GetError() << "\n" ; |
347 | return; |
348 | } |
349 | SDL_GL_MakeCurrent(m_window, m_ctx); |
350 | |
351 | /* Query the version of a context made the old-way and max |
352 | * that value with the requested version; note that we |
353 | * CANNOT use ngl_ system because (1) the get_proc function |
354 | * is not yet assigned and (2) some GL implementation on |
355 | * MS-Windows have that the functions returned by |
356 | * wglGetProcAddress are only good for the context that made |
357 | * them (shudders). |
358 | */ |
359 | PFNGLGETINTEGERVPROC get_integer; |
360 | get_integer = (PFNGLGETINTEGERVPROC)get_proc("glGetIntegerv" ); |
361 | if (get_integer) |
362 | { |
363 | fastuidraw::ivec2 ver(0, 0); |
364 | fastuidraw::ivec2 req(m_gl_major.value(), m_gl_minor.value()); |
365 | |
366 | get_integer(GL_MAJOR_VERSION, &ver.x()); |
367 | get_integer(GL_MINOR_VERSION, &ver.y()); |
368 | req = fastuidraw::t_max(ver, req); |
369 | m_gl_major.value() = req.x(); |
370 | m_gl_minor.value() = req.y(); |
371 | } |
372 | |
373 | SDL_GL_MakeCurrent(m_window, nullptr); |
374 | SDL_GL_DeleteContext(m_ctx); |
375 | set_sdl_gl_context_attributes(); |
376 | m_ctx = SDL_GL_CreateContext(m_window); |
377 | } |
378 | #endif |
379 | } |
380 | |
381 | enum fastuidraw::return_code |
382 | sdl_demo:: |
383 | init_sdl(void) |
384 | { |
385 | #ifdef _WIN32 |
386 | { |
387 | SetProcessDPIAware(); |
388 | } |
389 | #endif |
390 | |
391 | if (SDL_Init(SDL_INIT_EVERYTHING) < 0) |
392 | { |
393 | std::cerr << "\nFailed on SDL_Init\n" ; |
394 | return fastuidraw::routine_fail; |
395 | } |
396 | |
397 | int video_flags; |
398 | video_flags = SDL_WINDOW_RESIZABLE; |
399 | |
400 | if (m_fullscreen.value()) |
401 | { |
402 | video_flags = video_flags | SDL_WINDOW_FULLSCREEN; |
403 | } |
404 | |
405 | SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); |
406 | SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, m_stencil_bits.value()); |
407 | SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, m_depth_bits.value()); |
408 | SDL_GL_SetAttribute(SDL_GL_RED_SIZE, m_red_bits.value()); |
409 | SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, m_green_bits.value()); |
410 | SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, m_blue_bits.value()); |
411 | SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, m_alpha_bits.value()); |
412 | if (m_use_msaa.value()) |
413 | { |
414 | SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1); |
415 | SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, m_msaa.value()); |
416 | } |
417 | |
418 | video_flags |= SDL_WINDOW_OPENGL; |
419 | m_window = SDL_CreateWindow("" , |
420 | SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, |
421 | m_width.value(), |
422 | m_height.value(), |
423 | video_flags); |
424 | |
425 | if (m_window == nullptr) |
426 | { |
427 | std::cerr << "\nFailed on SDL_SetVideoMode\n" ; |
428 | return fastuidraw::routine_fail; |
429 | } |
430 | |
431 | if (m_dimensions_must_match.value()) |
432 | { |
433 | int w, h; |
434 | bool is_fullscreen; |
435 | is_fullscreen = (SDL_GetWindowFlags(m_window) & SDL_WINDOW_FULLSCREEN) != 0; |
436 | SDL_GetWindowSize(m_window, &w, &h); |
437 | if (w != m_width.value() || h != m_height.value() || is_fullscreen != m_fullscreen.value()) |
438 | { |
439 | std::cerr << "\nDimensions did not match and required to match\n" ; |
440 | return fastuidraw::routine_fail; |
441 | } |
442 | } |
443 | |
444 | fastuidraw::reference_counted_ptr<StreamHolder> str; |
445 | if (!m_log_gl_commands.value().empty()) |
446 | { |
447 | str = FASTUIDRAWnew StreamHolder(m_log_gl_commands.value()); |
448 | } |
449 | |
450 | create_sdl_gl_context(); |
451 | if (m_ctx == nullptr) |
452 | { |
453 | std::cerr << "Unable to create GL context: " << SDL_GetError() << "\n" ; |
454 | return fastuidraw::routine_fail; |
455 | } |
456 | SDL_GL_MakeCurrent(m_window, m_ctx); |
457 | |
458 | if (m_swap_interval.set_by_command_line()) |
459 | { |
460 | if (SDL_GL_SetSwapInterval(m_swap_interval.value()) != 0) |
461 | { |
462 | std::cerr << "Warning unable to set swap interval: " |
463 | << SDL_GetError() << "\n" ; |
464 | } |
465 | } |
466 | fastuidraw::gl_binding::get_proc_function(get_proc); |
467 | |
468 | if (m_hide_cursor.value()) |
469 | { |
470 | SDL_ShowCursor(SDL_DISABLE); |
471 | } |
472 | |
473 | if (str) |
474 | { |
475 | m_gl_logger = FASTUIDRAWnew OstreamLogger(str); |
476 | } |
477 | |
478 | if (m_print_gl_info.value()) |
479 | { |
480 | std::cout << "\nSwapInterval: " << SDL_GL_GetSwapInterval() |
481 | << "\ndepth bits: " << GetSDLGLValue(SDL_GL_DEPTH_SIZE) |
482 | << "\nstencil bits: " << GetSDLGLValue(SDL_GL_STENCIL_SIZE) |
483 | << "\nred bits: " << GetSDLGLValue(SDL_GL_RED_SIZE) |
484 | << "\ngreen bits: " << GetSDLGLValue(SDL_GL_GREEN_SIZE) |
485 | << "\nblue bits: " << GetSDLGLValue(SDL_GL_BLUE_SIZE) |
486 | << "\nalpha bits: " << GetSDLGLValue(SDL_GL_ALPHA_SIZE) |
487 | << "\ndouble buffered: " << GetSDLGLValue(SDL_GL_DOUBLEBUFFER) |
488 | << "\nGL_MAJOR_VERSION: " << fastuidraw::gl::context_get<GLint>(GL_MAJOR_VERSION) |
489 | << "\nGL_MINOR_VERSION: " << fastuidraw::gl::context_get<GLint>(GL_MINOR_VERSION) |
490 | << "\nGL_VERSION string:" << fastuidraw_glGetString(GL_VERSION) |
491 | << "\nGL_VENDOR:" << fastuidraw_glGetString(GL_VENDOR) |
492 | << "\nGL_RENDERER:" << fastuidraw_glGetString(GL_RENDERER) |
493 | << "\nGL_SHADING_LANGUAGE_VERSION:" << fastuidraw_glGetString(GL_SHADING_LANGUAGE_VERSION) |
494 | << "\nGL_MAX_VARYING_COMPONENTS:" << fastuidraw::gl::context_get<GLint>(GL_MAX_VARYING_COMPONENTS) |
495 | << "\nGL_MAX_VERTEX_ATTRIBS:" << fastuidraw::gl::context_get<GLint>(GL_MAX_VERTEX_ATTRIBS) |
496 | << "\nGL_MAX_VERTEX_TEXTURE_IMAGE_UNITS:" << fastuidraw::gl::context_get<GLint>(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS) |
497 | << "\nGL_MAX_VERTEX_UNIFORM_BLOCKS:" << fastuidraw::gl::context_get<GLint>(GL_MAX_VERTEX_UNIFORM_BLOCKS) |
498 | << "\nGL_MAX_FRAGMENT_UNIFORM_BLOCKS:" << fastuidraw::gl::context_get<GLint>(GL_MAX_FRAGMENT_UNIFORM_BLOCKS) |
499 | << "\nGL_MAX_COMBINED_UNIFORM_BLOCKS:" << fastuidraw::gl::context_get<GLint>(GL_MAX_COMBINED_UNIFORM_BLOCKS) |
500 | << "\nGL_MAX_UNIFORM_BLOCK_SIZE:" << fastuidraw::gl::context_get<GLint>(GL_MAX_UNIFORM_BLOCK_SIZE) |
501 | << "\nGL_MAX_TEXTURE_SIZE: " << fastuidraw::gl::context_get<GLint>(GL_MAX_TEXTURE_SIZE) |
502 | << "\nGL_MAX_ARRAY_TEXTURE_LAYERS: " << fastuidraw::gl::context_get<GLint>(GL_MAX_ARRAY_TEXTURE_LAYERS) |
503 | << "\nGL_MAX_TEXTURE_BUFFER_SIZE: " << fastuidraw::gl::context_get<GLint>(GL_MAX_TEXTURE_BUFFER_SIZE); |
504 | |
505 | |
506 | #ifndef FASTUIDRAW_GL_USE_GLES |
507 | { |
508 | std::cout << "\nGL_MAX_GEOMETRY_UNIFORM_BLOCKS:" << fastuidraw::gl::context_get<GLint>(GL_MAX_GEOMETRY_UNIFORM_BLOCKS) |
509 | << "\nGL_MAX_CLIP_DISTANCES:" << fastuidraw::gl::context_get<GLint>(GL_MAX_CLIP_DISTANCES); |
510 | } |
511 | #endif |
512 | |
513 | print_gl_extensions(std::cout); |
514 | std::cout << "\n" ; |
515 | } |
516 | |
517 | return fastuidraw::routine_success; |
518 | } |
519 | |
520 | void |
521 | sdl_demo:: |
522 | reverse_event_y(bool v) |
523 | { |
524 | m_reverse_event_y = v; |
525 | } |
526 | |
527 | void |
528 | sdl_demo:: |
529 | swap_buffers(unsigned int count) |
530 | { |
531 | for(unsigned int i = 0; i < count; ++i) |
532 | { |
533 | SDL_GL_SwapWindow(m_window); |
534 | } |
535 | } |
536 | |
537 | |
538 | int |
539 | sdl_demo:: |
540 | main(int argc, char **argv) |
541 | { |
542 | simple_time render_time; |
543 | unsigned int num_frames; |
544 | |
545 | if (argc == 2 && is_help_request(argv[1])) |
546 | { |
547 | std::cout << m_about << "\n\nUsage: " << argv[0]; |
548 | print_help(std::cout); |
549 | print_detailed_help(std::cout); |
550 | return 0; |
551 | } |
552 | |
553 | std::cout << "\n\nRunning: \"" ; |
554 | for(int i = 0; i < argc; ++i) |
555 | { |
556 | std::cout << argv[i] << " " ; |
557 | } |
558 | |
559 | parse_command_line(argc, argv); |
560 | std::cout << "\n\n" << std::flush; |
561 | |
562 | enum fastuidraw::return_code R; |
563 | R = init_sdl(); |
564 | int w, h; |
565 | |
566 | if (R == fastuidraw::routine_fail) |
567 | { |
568 | return -1; |
569 | } |
570 | |
571 | m_run_demo = true; |
572 | SDL_GetWindowSize(m_window, &w, &h); |
573 | init_gl(w, h); |
574 | |
575 | num_frames = 0; |
576 | while(m_run_demo) |
577 | { |
578 | if (num_frames == m_num_warm_up_frames.value()) |
579 | { |
580 | render_time.restart(); |
581 | } |
582 | |
583 | pre_draw_frame(); |
584 | draw_frame(); |
585 | post_draw_frame(); |
586 | swap_buffers(); |
587 | ++num_frames; |
588 | |
589 | if (m_run_demo && m_handle_events) |
590 | { |
591 | SDL_Event ev; |
592 | while(m_run_demo && m_handle_events && SDL_PollEvent(&ev)) |
593 | { |
594 | if (m_reverse_event_y) |
595 | { |
596 | int w, h; |
597 | FASTUIDRAWassert(m_window); |
598 | SDL_GetWindowSize(m_window, &w, &h); |
599 | reverse_y_of_sdl_event(h, ev); |
600 | } |
601 | handle_event(ev); |
602 | } |
603 | } |
604 | } |
605 | |
606 | if (m_show_framerate.value() && num_frames > m_num_warm_up_frames.value()) |
607 | { |
608 | int32_t ms; |
609 | float msf, numf; |
610 | |
611 | num_frames -= m_num_warm_up_frames.value(); |
612 | |
613 | ms = render_time.elapsed(); |
614 | numf = static_cast<float>(std::max(1u, num_frames)); |
615 | msf = static_cast<float>(std::max(1, ms)); |
616 | std::cout << "Rendered " << num_frames << " in " << ms << " ms.\n" |
617 | << "ms/frame = " << msf / numf << "\n" |
618 | << "FPS = " << 1000.0f * numf / msf << "\n" ; |
619 | } |
620 | |
621 | return m_return_value; |
622 | } |
623 | |
624 | fastuidraw::ivec2 |
625 | sdl_demo:: |
626 | dimensions(void) |
627 | { |
628 | fastuidraw::ivec2 return_value; |
629 | |
630 | FASTUIDRAWassert(m_window); |
631 | SDL_GetWindowSize(m_window, &return_value.x(), &return_value.y()); |
632 | return return_value; |
633 | } |
634 | |