async runner order adjustment
[vg.git] / vg.h
1 /* Copyright (C) 2021-2023 Harry Godden (hgn) - All Rights Reserved */
2
3 /*
4
5 .-. VG Event loop
6 | 0 |
7 | | .---------------------------------------------------------.
8 |API| | vg_enter( int argc, char *argv[], const char *window_name |
9 | | '---------------------------------------------------------'
10 | | |
11 | | v
12 |IMP| vg_launch_opt(void) <--.
13 | | | |
14 | | |'---------------'
15 | | | .-.
16 | | |'-----------------------------------| 1 |------.
17 | | | | | |
18 | | | | | v
19 | | | |IMP| vg_preload(void)
20 | | | | | |
21 | | .-----+. | | v
22 | | | | |IMP| vg_load(void)
23 | | | v '___' |
24 |IMP| | vg_framebuffer_resize(void) |
25 | | | | |
26 |IMP| | |.------------- vg_start(void) ---------------'
27 | | | |
28 | | | v
29 |IMP| | vg_pre_update(void)
30 | | | |
31 | | | .-----+.
32 | | | | | called 0x to 8x
33 | | | | v
34 |IMP| | '- vg_fixed_update(void)
35 | | | |
36 | | | .-'
37 | | | |
38 | | | v
39 |IMP| | vg_post_update(void)
40 | | | |
41 | | | v
42 |IMP| | vg_render(void)
43 | | | |
44 | | | v
45 |IMP| | vg_ui(void)
46 | | | |
47 | | '----'
48 '___'
49
50 */
51
52 #ifndef VG_HEADER_H
53 #define VG_HEADER_H
54
55 const char *vg_get_basepath(void);
56
57 #include "vg_platform.h"
58 #include "vg_mem.h"
59
60 #ifdef VG_GAME
61 #include "dep/glad/glad.h"
62 #include "dep/sdl/include/SDL.h"
63 #include "vg_stdint.h"
64
65 void vg_register_exit( void( *funcptr )(void), const char *name );
66
67 #include "vg_m.h"
68 #include "vg_io.h"
69 #include "vg_log.h"
70 #ifndef VG_NO_STEAM
71 #include "vg_steam.h"
72 #endif
73
74 //#define VG_SYNC_DEBUG
75 #ifdef VG_SYNC_DEBUG
76 #define VG_SYNC_LOG(STR,...) \
77 vg_info(STR,SDL_GetThreadID(NULL),##__VA_ARGS__)
78 #else
79 #define VG_SYNC_LOG(...)
80 #endif
81
82 /* API */
83 static void vg_enter( int argc, char *argv[], const char *window_name );
84
85 /* Thread 1 */
86 static void vg_preload(void);
87 static void vg_load(void);
88
89 /* Main thread */
90 static void vg_launch_opt(void);
91 static void vg_start(void);
92
93 static void vg_framebuffer_resize(int w, int h);
94 static void vg_pre_update(void);
95 static void vg_fixed_update(void);
96 static void vg_post_update(void);
97
98 static void vg_render(void);
99 static void vg_gui(void);
100
101 struct vg{
102 /* Engine sync */
103 SDL_Window *window;
104 SDL_GLContext gl_context;
105 const char *base_path;
106
107 SDL_sem *sem_loader; /* allows only one loader at a time */
108 jmp_buf env_loader_exit;
109
110 SDL_threadID thread_id_main,
111 thread_id_loader;
112 void *thread_data;
113
114 SDL_SpinLock sl_status;
115 enum engine_status{
116 k_engine_status_none,
117 k_engine_status_load_internal,
118 k_engine_status_running,
119 k_engine_status_crashed
120 }
121 engine_status;
122
123 /* Window information */
124 int window_x,
125 window_y,
126 samples,
127 window_should_close;
128
129 int display_refresh_rate,
130 fps_limit; /* 0: use vsync, >0: cap fps to this, no vsync */
131
132 enum vsync_feature{
133 k_vsync_feature_disabled=0,
134 k_vsync_feature_enabled=1,
135 k_vsync_feature_enabled_adaptive=2,
136 k_vsync_feature_error=3
137 }
138 vsync_feature;
139
140 double mouse_pos[2];
141 v2f mouse_delta,
142 mouse_wheel;
143
144 /* Runtime */
145 double time,
146 time_real,
147 time_delta,
148 time_rate,
149
150 time_fixed_accumulator,
151 time_fixed_extrapolate,
152 time_frame_delta;
153
154 u64 time_hp, time_hp_last, time_spinning;
155
156 int fixed_iterations;
157
158 enum engine_stage{
159 k_engine_stage_none,
160 k_engine_stage_update,
161 k_engine_stage_update_fixed,
162 k_engine_stage_rendering,
163 k_engine_stage_ui
164 }
165 engine_stage;
166
167 /* graphics */
168 m4x4f pv;
169 enum quality_profile{
170 k_quality_profile_high = 0,
171 k_quality_profile_low = 1,
172 }
173 quality_profile;
174
175 float loader_ring;
176 GLuint tex_missing;
177 }
178 static vg = { .time_rate = 1.0 };
179 const char *vg_get_basepath(void){
180 return vg.base_path;
181 }
182
183 enum vg_thread_purpose
184 {
185 k_thread_purpose_nothing,
186 k_thread_purpose_main,
187 k_thread_purpose_loader
188 };
189
190 #include "vg_async.h"
191
192 static enum engine_status _vg_engine_status(void)
193 {
194 SDL_AtomicLock( &vg.sl_status );
195 enum engine_status status = vg.engine_status;
196 SDL_AtomicUnlock( &vg.sl_status );
197
198 return status;
199 }
200
201 static enum vg_thread_purpose vg_thread_purpose(void)
202 {
203 SDL_AtomicLock( &vg.sl_status );
204
205 if( vg.thread_id_main == SDL_GetThreadID(NULL) ){
206 SDL_AtomicUnlock( &vg.sl_status );
207 return k_thread_purpose_main;
208 }
209 else{
210 SDL_AtomicUnlock( &vg.sl_status );
211 return k_thread_purpose_loader;
212 }
213 }
214
215 static void vg_assert_thread( enum vg_thread_purpose required ){
216 enum vg_thread_purpose purpose = vg_thread_purpose();
217
218 if( purpose != required ){
219 vg_fatal_error( "thread_purpose must be %u not %u\n", required, purpose );
220 }
221 }
222
223 static void _vg_opengl_sync_init(void)
224 {
225 vg.sem_loader = SDL_CreateSemaphore(1);
226 }
227
228 static void vg_checkgl( const char *src_info );
229 #define VG_STRINGIT( X ) #X
230 #define VG_CHECK_GL_ERR() vg_checkgl( __FILE__ ":L" VG_STRINGIT(__LINE__) )
231
232 #include "vg_console.h"
233 #include "vg_profiler.h"
234 #ifndef VG_NO_AUDIO
235 #include "vg_audio.h"
236 #endif
237 #include "vg_shader.h"
238 #include "vg_tex.h"
239 #include "vg_input.h"
240 #include "vg_imgui.h"
241 #include "vg_lines.h"
242 #include "vg_loader.h"
243 #include "vg_opt.h"
244
245 /* Diagnostic */
246 static struct vg_profile vg_prof_update = {.name="update()"},
247 vg_prof_render = {.name="render()"},
248 vg_prof_swap = {.name="swap"};
249
250 static void vg_checkgl( const char *src_info )
251 {
252 int fail = 0;
253
254 GLenum err;
255 while( (err = glGetError()) != GL_NO_ERROR ){
256 vg_error( "(%s) OpenGL Error: #%d\n", src_info, err );
257 fail = 1;
258 }
259
260 if( fail )
261 vg_fatal_error( "OpenGL Error" );
262 }
263
264 static void async_vg_bake_shaders( void *payload, u32 size )
265 {
266 vg_shaders_compile();
267 }
268
269 static void vg_bake_shaders(void)
270 {
271 vg_console_reg_cmd( "reload_shaders", vg_shaders_live_recompile, NULL );
272 vg_async_call( async_vg_bake_shaders, NULL, 0 );
273 }
274
275 void async_internal_complete( void *payload, u32 size )
276 {
277 vg_success( "Internal async setup complete\n" );
278 SDL_AtomicLock( &vg.sl_status );
279
280 if( vg.engine_status == k_engine_status_crashed ){
281 SDL_AtomicUnlock( &vg.sl_status );
282 return;
283 }
284 else{
285 vg.engine_status = k_engine_status_running;
286 }
287
288 SDL_AtomicUnlock( &vg.sl_status );
289 }
290
291 static void _vg_load_full( void *data )
292 {
293 vg_preload();
294
295 /* internal */
296 vg_tex2d_replace_with_error( &vg.tex_missing );
297 vg_loader_step( vg_input_init, vg_input_free );
298 vg_loader_step( vg_lines_init, NULL );
299 #ifndef VG_NO_AUDIO
300 vg_loader_step( vg_audio_init, vg_audio_free );
301 #endif
302 vg_loader_step( vg_profiler_init, NULL );
303
304 vg_async_call( async_internal_complete, NULL, 0 );
305
306 /* client */
307 vg_load();
308
309 vg_success( "Client loaded in %fs\n", vg.time_real );
310 }
311
312 static void _vg_process_events(void)
313 {
314 v2_zero( vg.mouse_wheel );
315 v2_zero( vg.mouse_delta );
316
317 /* Update input */
318 vg_process_inputs();
319
320 /* SDL event loop */
321 SDL_Event event;
322 while( SDL_PollEvent( &event ) ){
323 if( event.type == SDL_KEYDOWN ){
324 if( vg_console.enabled &&
325 (vg_ui.focused_control_type != k_ui_control_modal) ){
326 if( event.key.keysym.sym == SDLK_ESCAPE ||
327 event.key.keysym.scancode == SDL_SCANCODE_GRAVE ){
328 vg_console.enabled = 0;
329 ui_defocus_all();
330 }
331 else if( (event.key.keysym.mod & KMOD_CTRL) &&
332 event.key.keysym.sym == SDLK_n ){
333 _console_suggest_next();
334 }
335 else if( (event.key.keysym.mod & KMOD_CTRL ) &&
336 event.key.keysym.sym == SDLK_p ){
337 _console_suggest_prev();
338 }
339 else{
340 _ui_proc_key( event.key.keysym );
341 }
342 }
343 else{
344 if( event.key.keysym.scancode == SDL_SCANCODE_GRAVE ){
345 vg_console.enabled = 1;
346 }
347 else {
348 _ui_proc_key( event.key.keysym );
349 }
350 }
351 }
352 else if( event.type == SDL_MOUSEWHEEL ){
353 vg.mouse_wheel[0] += event.wheel.preciseX;
354 vg.mouse_wheel[1] += event.wheel.preciseY;
355 }
356 else if( event.type == SDL_CONTROLLERDEVICEADDED ||
357 event.type == SDL_CONTROLLERDEVICEREMOVED )
358 {
359 vg_input_device_event( &event );
360 }
361 else if( event.type == SDL_CONTROLLERAXISMOTION ||
362 event.type == SDL_CONTROLLERBUTTONDOWN ||
363 event.type == SDL_CONTROLLERBUTTONUP )
364 {
365 vg_input_controller_event( &event );
366 }
367 else if( event.type == SDL_MOUSEMOTION ){
368 vg.mouse_delta[0] += event.motion.xrel;
369 vg.mouse_delta[1] += event.motion.yrel;
370 }
371 else if( event.type == SDL_WINDOWEVENT ){
372 if( event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED ){
373 int w, h;
374 SDL_GL_GetDrawableSize( vg.window, &w, &h );
375
376 if( !w || !h ){
377 vg_warn( "Got a invalid framebuffer size: "
378 "%dx%d... ignoring\n", w, h );
379 }
380 else{
381 vg.window_x = w;
382 vg.window_y = h;
383
384 vg_framebuffer_resize(w,h);
385 }
386 }
387 else if( event.window.event == SDL_WINDOWEVENT_CLOSE ){
388 vg.window_should_close = 1;
389 }
390 }
391 else if( event.type == SDL_TEXTINPUT ){
392 ui_proc_utf8( event.text.text );
393 }
394 }
395
396 vg.mouse_pos[0] += vg.mouse_delta[0];
397 vg.mouse_pos[1] += vg.mouse_delta[1];
398 }
399
400 static void _vg_gameloop_update(void)
401 {
402 vg_profile_begin( &vg_prof_update );
403
404 vg.engine_stage = k_engine_stage_update;
405 vg_pre_update();
406
407 /* Fixed update loop */
408 vg.engine_stage = k_engine_stage_update_fixed;
409
410 vg.fixed_iterations = 0;
411 vg_lines.allow_input = 1;
412 vg.time_fixed_accumulator += vg.time_delta;
413
414 while( vg.time_fixed_accumulator >= VG_TIMESTEP_FIXED ){
415 vg_fixed_update();
416 vg_lines.allow_input = 0;
417 vg.time_fixed_accumulator -= VG_TIMESTEP_FIXED;
418
419 vg.fixed_iterations ++;
420 if( vg.fixed_iterations == 8 ){
421 break;
422 }
423 }
424 vg_lines.allow_input = 1;
425 vg.time_fixed_extrapolate = vg.time_fixed_accumulator / VG_TIMESTEP_FIXED;
426
427 vg.engine_stage = k_engine_stage_update;
428 vg_post_update();
429 vg_profile_end( &vg_prof_update );
430 }
431
432 static void _vg_gameloop_render(void)
433 {
434 vg_profile_begin( &vg_prof_render );
435
436 /* render */
437 vg.engine_stage = k_engine_stage_rendering;
438 vg_render();
439
440 /* ui */
441 vg.engine_stage = k_engine_stage_ui;
442 {
443 ui_prerender();
444 if( vg_console.enabled ){
445 vg_ui.ignore_input_frames = 10;
446 vg_gui();
447 vg_ui.ignore_input_frames = 0;
448 vg_ui.wants_mouse = 1;
449 _vg_console_draw();
450 }
451 else vg_gui();
452
453 /* vg tools */
454 #ifndef VG_NO_AUDIO
455 audio_debug_ui( vg.pv );
456 #endif
457
458 /* profiling */
459 int frame_target = vg.display_refresh_rate;
460 if( vg.fps_limit > 0 ) frame_target = vg.fps_limit;
461 vg_profile_drawn(
462 (struct vg_profile *[]){
463 &vg_prof_update,&vg_prof_render,&vg_prof_swap}, 3,
464 (1.0f/(float)frame_target)*1000.0f,
465 (ui_rect){ 4, 4, 250, 0 }, 0
466 );
467 if( vg_profiler ){
468 char perf[256];
469
470 snprintf( perf, 255,
471 "x: %d y: %d\n"
472 "refresh: %d (%.1fms)\n"
473 "samples: %d\n"
474 "iterations: %d (acc: %.3fms%%)\n"
475 "time: real(%.2f) delta(%.2f) rate(%.2f)\n"
476 " extrap(%.2f) frame(%.2f) spin( "PRINTF_U64" )\n",
477 vg.window_x, vg.window_y,
478 frame_target, (1.0f/(float)frame_target)*1000.0f,
479 vg.samples,
480 vg.fixed_iterations,
481 (vg.time_fixed_accumulator/VG_TIMESTEP_FIXED)*100.0f,
482 vg.time_real, vg.time_delta, vg.time_rate,
483 vg.time_fixed_extrapolate, vg.time_frame_delta,
484 vg.time_spinning );
485
486 ui_text( (ui_rect){258, 4+24+12+12,900,900},perf,1,0,k_ui_align_left);
487 }
488 ui_postrender();
489 }
490
491 vg_profile_end( &vg_prof_render );
492 }
493
494 static int vg_framefilter( double dt )
495 {
496 if( (vg.fps_limit <= 0) && (vg.vsync_feature != k_vsync_feature_error) ){
497 /* turn on vsync if not enabled */
498
499 enum vsync_feature requested = k_vsync_feature_enabled;
500 if( vg.fps_limit < 0 ) requested = k_vsync_feature_enabled_adaptive;
501
502 if( vg.vsync_feature != requested ){
503 vg_info( "Setting swap interval\n" );
504
505 int swap_interval = 1;
506 if( requested == k_vsync_feature_enabled_adaptive ) swap_interval = -1;
507
508 if( SDL_GL_SetSwapInterval( swap_interval ) == -1 ){
509 if( requested == k_vsync_feature_enabled ){
510 vg_error( "Vsync is not supported by your system\n" );
511 vg_warn( "You may be overriding it in your"
512 " graphics control panel.\n" );
513 }
514 else{
515 vg_error( "Adaptive Vsync is not supported by your system\n" );
516 }
517
518 vg.vsync_feature = k_vsync_feature_error;
519 vg.fps_limit = vg.display_refresh_rate;
520
521 /* TODO: Make popup to notify user that this happened */
522 return 1;
523 }
524 else{
525 vg_success( "Vsync enabled (%d)\n", requested );
526 vg.vsync_feature = requested;
527 }
528 }
529
530 return 0;
531 }
532
533 if( vg.vsync_feature != k_vsync_feature_disabled ){
534 SDL_GL_SetSwapInterval( 0 );
535 vg.vsync_feature = k_vsync_feature_disabled;
536 }
537
538 if( vg.fps_limit < 25 ) vg.fps_limit = 25;
539 if( vg.fps_limit > 300 ) vg.fps_limit = 300;
540
541 double min_frametime = 1.0/(double)vg.fps_limit;
542 if( vg.time_frame_delta < min_frametime ){
543 /* TODO: we can use high res nanosleep on Linux here */
544 double sleep_ms = (min_frametime-vg.time_frame_delta) * 1000.0;
545 u32 ms = (u32)floor( sleep_ms );
546
547 if( ms ){
548 SDL_Delay( ms );
549 }
550 else{
551 vg.time_spinning ++;
552 }
553
554 return 1;
555 }
556
557 return 0;
558 }
559
560 static int _vg_crashscreen(void)
561 {
562 #if 0
563 if( vg_getkey( SDLK_ESCAPE ) )
564 return 1;
565 #endif
566
567 glBindFramebuffer( GL_FRAMEBUFFER, 0 );
568 glEnable(GL_BLEND);
569 glDisable(GL_DEPTH_TEST);
570 glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_DST_ALPHA);
571 glBlendEquation(GL_FUNC_ADD);
572
573 glClearColor( 0.15f + sinf(vg.time_real)*0.1f, 0.0f, 0.0f,1.0f );
574 glClear( GL_COLOR_BUFFER_BIT );
575 glViewport( 0,0, vg.window_x, vg.window_y );
576
577 _vg_render_log();
578
579 return 0;
580 }
581
582 static void _vg_gameloop(void){
583 //vg.time_fixed_accumulator = 0.75f * (1.0f/60.0f);
584
585 vg.time_hp = SDL_GetPerformanceCounter();
586 vg.time_hp_last = vg.time_hp;
587
588 int post_start = 0;
589 while(1){
590
591 vg.time_hp = SDL_GetPerformanceCounter();
592 u64 udt = vg.time_hp - vg.time_hp_last;
593 vg.time_hp_last = vg.time_hp;
594
595 double dt = (double)udt / (double)SDL_GetPerformanceFrequency();
596
597 vg.time_frame_delta += dt;
598 vg_run_async_checked();
599
600 if( vg_framefilter( dt ) )
601 continue;
602
603 vg_profile_begin( &vg_prof_swap );
604 SDL_GL_SwapWindow( vg.window );
605 vg_profile_end( &vg_prof_swap );
606
607 enum engine_status status = _vg_engine_status();
608
609 vg.time_real += vg.time_frame_delta;
610 vg.time_delta = vg.time_frame_delta * vg.time_rate;
611 vg.time += vg.time_delta;
612
613 _vg_process_events();
614
615 if( vg.window_should_close )
616 break;
617
618 if( status == k_engine_status_crashed ){
619 if( _vg_crashscreen() )
620 break;
621 }
622 else{
623 if( status == k_engine_status_running ){
624 _vg_gameloop_update();
625 _vg_gameloop_render();
626 }
627 else{
628 _vg_loader_render();
629 }
630 }
631
632 if( vg.loader_ring > 0.01f ){
633 _vg_loader_render_ring( vg.loader_ring );
634 vg.loader_ring -= vg.time_frame_delta * 0.5f;
635 }
636
637 vg.time_frame_delta = 0.0;
638 vg.time_spinning = 0;
639 }
640 }
641
642 static void _vg_process_launch_opts_internal( int argc, char *argv[] )
643 {
644 char *arg;
645 while( vg_argp( argc, argv ) ){
646 if( (arg = vg_opt_arg( 'w' )) ){
647 vg.window_x = atoi( arg );
648 }
649
650 if( (arg = vg_opt_arg( 'h' )) ){
651 vg.window_y = atoi( arg );
652 }
653
654 if( (arg = vg_long_opt_arg( "samples" )) ){
655 vg.samples = VG_MAX( 0, VG_MIN( 8, atoi( arg ) ) );
656 }
657
658 if( vg_long_opt( "use-libc-malloc" ) ){
659 vg_mem.use_libc_malloc = 1;
660 }
661
662 if( vg_long_opt( "high-performance" ) ){
663 vg.quality_profile = k_quality_profile_low;
664 }
665
666 vg_launch_opt();
667 }
668 }
669
670 static void _vg_init_window( const char *window_name )
671 {
672 vg_info( "SDL_INIT\n" );
673
674 if( SDL_Init( SDL_INIT_VIDEO ) != 0 ){
675 vg_error( "SDL_Init failed: %s\n", SDL_GetError() );
676 exit(0);
677 }
678
679 #ifndef VG_NO_AUDIO
680 SDL_InitSubSystem( SDL_INIT_AUDIO );
681 #endif
682 SDL_InitSubSystem( SDL_INIT_GAMECONTROLLER );
683
684 char *exe_basepath = SDL_GetBasePath();
685 u32 len = vg_align8( strlen(exe_basepath)+1 );
686 char *dest = vg_linear_alloc( vg_mem.rtmemory, len );
687 strcpy( dest, exe_basepath );
688 SDL_free( exe_basepath );
689 vg.base_path = dest;
690
691 vg_info( "Basepath: %s\n", vg.base_path );
692
693 SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
694 SDL_GL_SetAttribute( SDL_GL_CONTEXT_MAJOR_VERSION, 3 );
695 SDL_GL_SetAttribute( SDL_GL_CONTEXT_MINOR_VERSION, 3 );
696 SDL_GL_SetAttribute( SDL_GL_CONTEXT_PROFILE_MASK,
697 SDL_GL_CONTEXT_PROFILE_CORE );
698
699 SDL_GL_SetAttribute( SDL_GL_CONTEXT_RELEASE_BEHAVIOR,
700 SDL_GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH );
701
702 SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 8 );
703 SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 8 );
704 SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 8 );
705 SDL_GL_SetAttribute( SDL_GL_ALPHA_SIZE, 8 );
706 SDL_GL_SetAttribute( SDL_GL_STENCIL_SIZE, 0 );
707
708 /*
709 * Get monitor information
710 */
711 vg_info( "Getting display count\n" );
712 int display_count = 0,
713 display_index = 0,
714 mode_index = 0;
715
716 SDL_DisplayMode video_mode;
717 if( SDL_GetDesktopDisplayMode( display_index, &video_mode ) ){
718 vg_error( "SDL_GetDesktopDisplayMode failed: %s\n", SDL_GetError() );
719 SDL_Quit();
720 exit(0);
721 }
722
723 vg.display_refresh_rate = video_mode.refresh_rate;
724 vg.window_x = video_mode.w;
725 vg.window_y = video_mode.h;
726
727 #ifdef VG_DEVWINDOW
728 vg.window_x = 1200;
729 vg.window_y = 880;
730 #endif
731
732 #ifndef _WIN32
733 SDL_SetHint( "SDL_VIDEO_X11_XINERAMA", "1" );
734 SDL_SetHint( "SDL_VIDEO_X11_XRANDR", "0" );
735 SDL_SetHint( "SDL_VIDEO_X11_XVIDMODE", "0" );
736 #endif
737
738 vg_info( "CreateWindow( %d %d @%dhz )\n", vg.window_x, vg.window_y,
739 vg.display_refresh_rate );
740
741 /* TODO: Allow selecting closest video mode from launch opts */
742 if((vg.window = SDL_CreateWindow( window_name,
743
744 #ifdef VG_DEVWINDOW
745 0, 0, vg.window_x, vg.window_y,
746 SDL_WINDOW_BORDERLESS|SDL_WINDOW_OPENGL|SDL_WINDOW_INPUT_GRABBED
747 ))){
748 SDL_SetWindowPosition( vg.window, video_mode.w-vg.window_x, 0 );
749 }
750 #else
751 0, 0,
752 vg.window_x, vg.window_y,
753
754 SDL_WINDOW_FULLSCREEN_DESKTOP |
755 SDL_WINDOW_OPENGL |
756 SDL_WINDOW_INPUT_GRABBED
757 )))
758 {
759 if( SDL_SetWindowDisplayMode( vg.window, &video_mode ) ){
760 vg_error( "SDL_SetWindowDisplayMode failed: %s", SDL_GetError() );
761 SDL_Quit();
762 exit(0);
763 }
764 }
765 #endif
766 else{
767 vg_error( "SDL_CreateWindow failed: %s", SDL_GetError() );
768 exit(0);
769 }
770
771 SDL_RaiseWindow( vg.window );
772
773 vg_info( "CreateContext\n" );
774
775 /* ????? */
776 if( SDL_IsTextInputActive() ) SDL_StopTextInput();
777
778 /*
779 * OpenGL loading
780 */
781 if( (vg.gl_context = SDL_GL_CreateContext(vg.window) )){
782 SDL_GL_GetDrawableSize( vg.window, &vg.window_x, &vg.window_y );
783 vg_success( "Window created (%dx%d)\n", vg.window_x, vg.window_y );
784 }
785 else{
786 vg_error( "SDL_GL_CreateContext failed: %s\n", SDL_GetError() );
787 SDL_Quit();
788 exit(0);
789 }
790
791 if( !gladLoadGLLoader((GLADloadproc)SDL_GL_GetProcAddress) ) {
792 vg_error( "Glad Failed to initialize\n" );
793 SDL_GL_DeleteContext( vg.gl_context );
794 SDL_Quit();
795 exit(0);
796 }
797
798 const unsigned char* glver = glGetString( GL_VERSION );
799 vg_success( "Load setup complete, OpenGL version: %s\n", glver );
800
801 SDL_GL_SetSwapInterval(0); /* disable vsync while loading */
802
803 SDL_DisplayMode dispmode;
804 if( !SDL_GetWindowDisplayMode( vg.window, &dispmode ) ){
805 if( dispmode.refresh_rate ){
806 vg.display_refresh_rate = dispmode.refresh_rate;
807 }
808 }
809
810 if( vg.display_refresh_rate < 25 || vg.display_refresh_rate > 300 ){
811 vg.display_refresh_rate = 60;
812 }
813
814 vg_info( "Display refresh rate: %d\n", dispmode.refresh_rate );
815
816 #if defined(_WIN32) || defined(VG_DEVWINDOW)
817 vg.fps_limit = vg.display_refresh_rate;
818 #else
819 vg.fps_limit = 0;
820 #endif
821 }
822
823 static void _vg_terminate(void)
824 {
825 /* Shutdown */
826 _vg_console_write_persistent();
827
828 SDL_AtomicLock( &vg.sl_status );
829 vg.engine_status = k_engine_status_none;
830 SDL_AtomicUnlock( &vg.sl_status );
831
832 _vg_loader_free();
833
834 vg_success( "If you see this it means everything went.. \"well\".....\n" );
835
836 SDL_GL_DeleteContext( vg.gl_context );
837 SDL_Quit();
838 exit(0);
839 }
840
841 static void vg_enter( int argc, char *argv[], const char *window_name )
842 {
843 vg_rand_seed( 461 );
844 _vg_process_launch_opts_internal( argc, argv );
845
846 /* Systems init */
847 vg_alloc_quota();
848 _vg_console_init();
849
850 vg_console_reg_var( "fps_limit", &vg.fps_limit, k_var_dtype_i32, 0 );
851 _vg_init_window( window_name );
852
853 vg_async_init();
854 SDL_SetRelativeMouseMode(1);
855
856 vg.thread_id_main = SDL_GetThreadID(NULL);
857
858 /* Opengl-required systems */
859 _vg_ui_init();
860 _vg_loader_init();
861
862 vg.engine_status = k_engine_status_load_internal;
863
864 _vg_opengl_sync_init();
865 vg_loader_start( _vg_load_full, NULL );
866 _vg_gameloop();
867 _vg_terminate();
868 }
869
870 static void vg_fatal_error( const char *fmt, ... )
871 {
872 va_list args;
873 va_start( args, fmt );
874 _vg_logx_va( stderr, NULL, "fatal", KRED, fmt, args );
875 va_end( args );
876
877 vg_print_backtrace();
878
879 SDL_AtomicLock( &vg.sl_status );
880 vg.engine_status = k_engine_status_crashed;
881 SDL_AtomicUnlock( &vg.sl_status );
882
883 if( vg_thread_purpose() == k_thread_purpose_loader ){
884 longjmp( vg.env_loader_exit, 1 );
885 }
886 else{
887 vg_error( "There is no jump to the error runner thing yet! bai bai\n" );
888 _vg_terminate();
889 }
890 }
891
892 #else /* VG_GAME */
893
894 #include "vg_log.h"
895 static void vg_fatal_error( const char *fmt, ... )
896 {
897 va_list args;
898 va_start( args, fmt );
899 _vg_logx_va( stderr, NULL, "fatal", KRED, fmt, args );
900 va_end( args );
901 exit(0);
902 }
903
904 #endif /* VG_GAME */
905
906 /*
907 * Graphic cards will check these to force it to use the GPU
908 */
909 u32 NvOptimusEnablement = 0x00000001;
910 int AmdPowerXpressRequestHighPerformance = 1;
911
912 #include "vg_log.c"
913
914 #endif /* VG_HEADER_H */