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