add none compiler
[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
310 static void _vg_process_events(void)
311 {
312 v2_zero( vg.mouse_wheel );
313 v2_zero( vg.mouse_delta );
314
315 /* Update input */
316 vg_process_inputs();
317
318 /* SDL event loop */
319 SDL_Event event;
320 while( SDL_PollEvent( &event ) ){
321 if( event.type == SDL_KEYDOWN ){
322 if( vg_console.enabled &&
323 (vg_ui.focused_control_type != k_ui_control_modal) ){
324 if( event.key.keysym.sym == SDLK_ESCAPE ||
325 event.key.keysym.scancode == SDL_SCANCODE_GRAVE ){
326 vg_console.enabled = 0;
327 ui_defocus_all();
328 }
329 else if( (event.key.keysym.mod & KMOD_CTRL) &&
330 event.key.keysym.sym == SDLK_n ){
331 _console_suggest_next();
332 }
333 else if( (event.key.keysym.mod & KMOD_CTRL ) &&
334 event.key.keysym.sym == SDLK_p ){
335 _console_suggest_prev();
336 }
337 else{
338 _ui_proc_key( event.key.keysym );
339 }
340 }
341 else{
342 if( event.key.keysym.scancode == SDL_SCANCODE_GRAVE ){
343 vg_console.enabled = 1;
344 }
345 else {
346 _ui_proc_key( event.key.keysym );
347 }
348 }
349 }
350 else if( event.type == SDL_MOUSEWHEEL ){
351 vg.mouse_wheel[0] += event.wheel.preciseX;
352 vg.mouse_wheel[1] += event.wheel.preciseY;
353 }
354 else if( event.type == SDL_CONTROLLERDEVICEADDED ||
355 event.type == SDL_CONTROLLERDEVICEREMOVED )
356 {
357 vg_input_device_event( &event );
358 }
359 else if( event.type == SDL_CONTROLLERAXISMOTION ||
360 event.type == SDL_CONTROLLERBUTTONDOWN ||
361 event.type == SDL_CONTROLLERBUTTONUP )
362 {
363 vg_input_controller_event( &event );
364 }
365 else if( event.type == SDL_MOUSEMOTION ){
366 vg.mouse_delta[0] += event.motion.xrel;
367 vg.mouse_delta[1] += event.motion.yrel;
368 }
369 else if( event.type == SDL_WINDOWEVENT ){
370 if( event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED ){
371 int w, h;
372 SDL_GL_GetDrawableSize( vg.window, &w, &h );
373
374 if( !w || !h ){
375 vg_warn( "Got a invalid framebuffer size: "
376 "%dx%d... ignoring\n", w, h );
377 }
378 else{
379 vg.window_x = w;
380 vg.window_y = h;
381
382 vg_framebuffer_resize(w,h);
383 }
384 }
385 else if( event.window.event == SDL_WINDOWEVENT_CLOSE ){
386 vg.window_should_close = 1;
387 }
388 }
389 else if( event.type == SDL_TEXTINPUT ){
390 ui_proc_utf8( event.text.text );
391 }
392 }
393
394 vg.mouse_pos[0] += vg.mouse_delta[0];
395 vg.mouse_pos[1] += vg.mouse_delta[1];
396 }
397
398 static void _vg_gameloop_update(void)
399 {
400 vg_profile_begin( &vg_prof_update );
401
402 vg.engine_stage = k_engine_stage_update;
403 vg_pre_update();
404
405 /* Fixed update loop */
406 vg.engine_stage = k_engine_stage_update_fixed;
407
408 vg.fixed_iterations = 0;
409 vg_lines.allow_input = 1;
410 vg.time_fixed_accumulator += vg.time_delta;
411
412 while( vg.time_fixed_accumulator >= VG_TIMESTEP_FIXED ){
413 vg_fixed_update();
414 vg_lines.allow_input = 0;
415 vg.time_fixed_accumulator -= VG_TIMESTEP_FIXED;
416
417 vg.fixed_iterations ++;
418 if( vg.fixed_iterations == 8 ){
419 break;
420 }
421 }
422 vg_lines.allow_input = 1;
423 vg.time_fixed_extrapolate = vg.time_fixed_accumulator / VG_TIMESTEP_FIXED;
424
425 vg.engine_stage = k_engine_stage_update;
426 vg_post_update();
427 vg_profile_end( &vg_prof_update );
428 }
429
430 static void _vg_gameloop_render(void)
431 {
432 vg_profile_begin( &vg_prof_render );
433
434 /* render */
435 vg.engine_stage = k_engine_stage_rendering;
436 vg_render();
437
438 /* ui */
439 vg.engine_stage = k_engine_stage_ui;
440 {
441 ui_prerender();
442 if( vg_console.enabled ){
443 vg_ui.ignore_input_frames = 10;
444 vg_gui();
445 vg_ui.ignore_input_frames = 0;
446 vg_ui.wants_mouse = 1;
447 _vg_console_draw();
448 }
449 else vg_gui();
450
451 /* vg tools */
452 #ifndef VG_NO_AUDIO
453 audio_debug_ui( vg.pv );
454 #endif
455
456 /* profiling */
457 int frame_target = vg.display_refresh_rate;
458 if( vg.fps_limit > 0 ) frame_target = vg.fps_limit;
459 vg_profile_drawn(
460 (struct vg_profile *[]){
461 &vg_prof_update,&vg_prof_render,&vg_prof_swap}, 3,
462 (1.0f/(float)frame_target)*1000.0f,
463 (ui_rect){ 4, 4, 250, 0 }, 0
464 );
465 if( vg_profiler ){
466 char perf[256];
467
468 snprintf( perf, 255,
469 "x: %d y: %d\n"
470 "refresh: %d (%.1fms)\n"
471 "samples: %d\n"
472 "iterations: %d (acc: %.3fms%%)\n"
473 "time: real(%.2f) delta(%.2f) rate(%.2f)\n"
474 " extrap(%.2f) frame(%.2f) spin( "PRINTF_U64" )\n",
475 vg.window_x, vg.window_y,
476 frame_target, (1.0f/(float)frame_target)*1000.0f,
477 vg.samples,
478 vg.fixed_iterations,
479 (vg.time_fixed_accumulator/VG_TIMESTEP_FIXED)*100.0f,
480 vg.time_real, vg.time_delta, vg.time_rate,
481 vg.time_fixed_extrapolate, vg.time_frame_delta,
482 vg.time_spinning );
483
484 ui_text( (ui_rect){258, 4+24+12+12,900,900},perf,1,0,k_ui_align_left);
485 }
486 ui_postrender();
487 }
488
489 vg_profile_end( &vg_prof_render );
490 }
491
492 static int vg_framefilter( double dt )
493 {
494 if( (vg.fps_limit <= 0) && (vg.vsync_feature != k_vsync_feature_error) ){
495 /* turn on vsync if not enabled */
496
497 enum vsync_feature requested = k_vsync_feature_enabled;
498 if( vg.fps_limit < 0 ) requested = k_vsync_feature_enabled_adaptive;
499
500 if( vg.vsync_feature != requested ){
501 vg_info( "Setting swap interval\n" );
502
503 int swap_interval = 1;
504 if( requested == k_vsync_feature_enabled_adaptive ) swap_interval = -1;
505
506 if( SDL_GL_SetSwapInterval( swap_interval ) == -1 ){
507 if( requested == k_vsync_feature_enabled ){
508 vg_error( "Vsync is not supported by your system\n" );
509 vg_warn( "You may be overriding it in your"
510 " graphics control panel.\n" );
511 }
512 else{
513 vg_error( "Adaptive Vsync is not supported by your system\n" );
514 }
515
516 vg.vsync_feature = k_vsync_feature_error;
517 vg.fps_limit = vg.display_refresh_rate;
518
519 /* TODO: Make popup to notify user that this happened */
520 return 1;
521 }
522 else{
523 vg_success( "Vsync enabled (%d)\n", requested );
524 vg.vsync_feature = requested;
525 }
526 }
527
528 return 0;
529 }
530
531 if( vg.vsync_feature != k_vsync_feature_disabled ){
532 SDL_GL_SetSwapInterval( 0 );
533 vg.vsync_feature = k_vsync_feature_disabled;
534 }
535
536 if( vg.fps_limit < 25 ) vg.fps_limit = 25;
537 if( vg.fps_limit > 300 ) vg.fps_limit = 300;
538
539 double min_frametime = 1.0/(double)vg.fps_limit;
540 if( vg.time_frame_delta < min_frametime ){
541 /* TODO: we can use high res nanosleep on Linux here */
542 double sleep_ms = (min_frametime-vg.time_frame_delta) * 1000.0;
543 u32 ms = (u32)floor( sleep_ms );
544
545 if( ms ){
546 SDL_Delay( ms );
547 }
548 else{
549 vg.time_spinning ++;
550 }
551
552 return 1;
553 }
554
555 return 0;
556 }
557
558 static int _vg_crashscreen(void)
559 {
560 #if 0
561 if( vg_getkey( SDLK_ESCAPE ) )
562 return 1;
563 #endif
564
565 glBindFramebuffer( GL_FRAMEBUFFER, 0 );
566 glEnable(GL_BLEND);
567 glDisable(GL_DEPTH_TEST);
568 glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_DST_ALPHA);
569 glBlendEquation(GL_FUNC_ADD);
570
571 glClearColor( 0.15f + sinf(vg.time_real)*0.1f, 0.0f, 0.0f,1.0f );
572 glClear( GL_COLOR_BUFFER_BIT );
573 glViewport( 0,0, vg.window_x, vg.window_y );
574
575 _vg_render_log();
576
577 return 0;
578 }
579
580 static void _vg_gameloop(void){
581 //vg.time_fixed_accumulator = 0.75f * (1.0f/60.0f);
582
583 vg.time_hp = SDL_GetPerformanceCounter();
584 vg.time_hp_last = vg.time_hp;
585
586 int post_start = 0;
587 while(1){
588
589 vg.time_hp = SDL_GetPerformanceCounter();
590 u64 udt = vg.time_hp - vg.time_hp_last;
591 vg.time_hp_last = vg.time_hp;
592
593 double dt = (double)udt / (double)SDL_GetPerformanceFrequency();
594
595 vg.time_frame_delta += dt;
596
597 if( vg_framefilter( dt ) )
598 continue;
599
600 vg_profile_begin( &vg_prof_swap );
601 SDL_GL_SwapWindow( vg.window );
602 vg_profile_end( &vg_prof_swap );
603
604 enum engine_status status = _vg_engine_status();
605
606 vg.time_real += vg.time_frame_delta;
607 vg.time_delta = vg.time_frame_delta * vg.time_rate;
608 vg.time += vg.time_delta;
609
610 vg_run_async_checked();
611 _vg_process_events();
612
613 if( vg.window_should_close )
614 break;
615
616 if( status == k_engine_status_crashed ){
617 if( _vg_crashscreen() )
618 break;
619 }
620 else{
621 if( status == k_engine_status_running ){
622 _vg_gameloop_update();
623 _vg_gameloop_render();
624 }
625 else{
626 _vg_loader_render();
627 }
628 }
629
630 if( vg.loader_ring > 0.01f ){
631 _vg_loader_render_ring( vg.loader_ring );
632 vg.loader_ring -= vg.time_frame_delta * 0.5f;
633 }
634
635 vg.time_frame_delta = 0.0;
636 vg.time_spinning = 0;
637 }
638 }
639
640 static void _vg_process_launch_opts_internal( int argc, char *argv[] )
641 {
642 char *arg;
643 while( vg_argp( argc, argv ) ){
644 if( (arg = vg_opt_arg( 'w' )) ){
645 vg.window_x = atoi( arg );
646 }
647
648 if( (arg = vg_opt_arg( 'h' )) ){
649 vg.window_y = atoi( arg );
650 }
651
652 if( (arg = vg_long_opt_arg( "samples" )) ){
653 vg.samples = VG_MAX( 0, VG_MIN( 8, atoi( arg ) ) );
654 }
655
656 if( vg_long_opt( "use-libc-malloc" ) ){
657 vg_mem.use_libc_malloc = 1;
658 }
659
660 if( vg_long_opt( "high-performance" ) ){
661 vg.quality_profile = k_quality_profile_low;
662 }
663
664 vg_launch_opt();
665 }
666 }
667
668 static void _vg_init_window( const char *window_name )
669 {
670 vg_info( "SDL_INIT\n" );
671
672 if( SDL_Init( SDL_INIT_VIDEO ) != 0 ){
673 vg_error( "SDL_Init failed: %s\n", SDL_GetError() );
674 exit(0);
675 }
676
677 #ifndef VG_NO_AUDIO
678 SDL_InitSubSystem( SDL_INIT_AUDIO );
679 #endif
680 SDL_InitSubSystem( SDL_INIT_GAMECONTROLLER );
681
682 char *exe_basepath = SDL_GetBasePath();
683 u32 len = vg_align8( strlen(exe_basepath)+1 );
684 char *dest = vg_linear_alloc( vg_mem.rtmemory, len );
685 strcpy( dest, exe_basepath );
686 SDL_free( exe_basepath );
687 vg.base_path = dest;
688
689 vg_info( "Basepath: %s\n", vg.base_path );
690
691 SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
692 SDL_GL_SetAttribute( SDL_GL_CONTEXT_MAJOR_VERSION, 3 );
693 SDL_GL_SetAttribute( SDL_GL_CONTEXT_MINOR_VERSION, 3 );
694 SDL_GL_SetAttribute( SDL_GL_CONTEXT_PROFILE_MASK,
695 SDL_GL_CONTEXT_PROFILE_CORE );
696
697 SDL_GL_SetAttribute( SDL_GL_CONTEXT_RELEASE_BEHAVIOR,
698 SDL_GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH );
699
700 SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 8 );
701 SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 8 );
702 SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 8 );
703 SDL_GL_SetAttribute( SDL_GL_ALPHA_SIZE, 8 );
704 SDL_GL_SetAttribute( SDL_GL_STENCIL_SIZE, 0 );
705
706 /*
707 * Get monitor information
708 */
709 vg_info( "Getting display count\n" );
710 int display_count = 0,
711 display_index = 0,
712 mode_index = 0;
713
714 SDL_DisplayMode video_mode;
715 if( SDL_GetDesktopDisplayMode( display_index, &video_mode ) ){
716 vg_error( "SDL_GetDesktopDisplayMode failed: %s\n", SDL_GetError() );
717 SDL_Quit();
718 exit(0);
719 }
720
721 vg.display_refresh_rate = video_mode.refresh_rate;
722 vg.window_x = video_mode.w;
723 vg.window_y = video_mode.h;
724
725 #ifdef VG_DEVWINDOW
726 vg.window_x = 1200;
727 vg.window_y = 880;
728 #endif
729
730 #ifndef _WIN32
731 SDL_SetHint( "SDL_VIDEO_X11_XINERAMA", "1" );
732 SDL_SetHint( "SDL_VIDEO_X11_XRANDR", "0" );
733 SDL_SetHint( "SDL_VIDEO_X11_XVIDMODE", "0" );
734 #endif
735
736 vg_info( "CreateWindow( %d %d @%dhz )\n", vg.window_x, vg.window_y,
737 vg.display_refresh_rate );
738
739 /* TODO: Allow selecting closest video mode from launch opts */
740 if((vg.window = SDL_CreateWindow( window_name,
741
742 #ifdef VG_DEVWINDOW
743 0, 0, vg.window_x, vg.window_y,
744 SDL_WINDOW_BORDERLESS|SDL_WINDOW_OPENGL|SDL_WINDOW_INPUT_GRABBED
745 ))){
746 SDL_SetWindowPosition( vg.window, video_mode.w-vg.window_x, 0 );
747 }
748 #else
749 0, 0,
750 vg.window_x, vg.window_y,
751
752 SDL_WINDOW_FULLSCREEN_DESKTOP |
753 SDL_WINDOW_OPENGL |
754 SDL_WINDOW_INPUT_GRABBED
755 )))
756 {
757 if( SDL_SetWindowDisplayMode( vg.window, &video_mode ) ){
758 vg_error( "SDL_SetWindowDisplayMode failed: %s", SDL_GetError() );
759 SDL_Quit();
760 exit(0);
761 }
762 }
763 #endif
764 else{
765 vg_error( "SDL_CreateWindow failed: %s", SDL_GetError() );
766 exit(0);
767 }
768
769 SDL_RaiseWindow( vg.window );
770
771 vg_info( "CreateContext\n" );
772
773 /* ????? */
774 if( SDL_IsTextInputActive() ) SDL_StopTextInput();
775
776 /*
777 * OpenGL loading
778 */
779 if( (vg.gl_context = SDL_GL_CreateContext(vg.window) )){
780 SDL_GL_GetDrawableSize( vg.window, &vg.window_x, &vg.window_y );
781 vg_success( "Window created (%dx%d)\n", vg.window_x, vg.window_y );
782 }
783 else{
784 vg_error( "SDL_GL_CreateContext failed: %s\n", SDL_GetError() );
785 SDL_Quit();
786 exit(0);
787 }
788
789 if( !gladLoadGLLoader((GLADloadproc)SDL_GL_GetProcAddress) ) {
790 vg_error( "Glad Failed to initialize\n" );
791 SDL_GL_DeleteContext( vg.gl_context );
792 SDL_Quit();
793 exit(0);
794 }
795
796 const unsigned char* glver = glGetString( GL_VERSION );
797 vg_success( "Load setup complete, OpenGL version: %s\n", glver );
798
799 SDL_GL_SetSwapInterval(0); /* disable vsync while loading */
800
801 SDL_DisplayMode dispmode;
802 if( !SDL_GetWindowDisplayMode( vg.window, &dispmode ) ){
803 if( dispmode.refresh_rate ){
804 vg.display_refresh_rate = dispmode.refresh_rate;
805 }
806 }
807
808 if( vg.display_refresh_rate < 25 || vg.display_refresh_rate > 300 ){
809 vg.display_refresh_rate = 60;
810 }
811
812 vg_info( "Display refresh rate: %d\n", dispmode.refresh_rate );
813
814 #if defined(_WIN32) || defined(VG_DEVWINDOW)
815 vg.fps_limit = vg.display_refresh_rate;
816 #else
817 vg.fps_limit = 0;
818 #endif
819 }
820
821 static void _vg_terminate(void)
822 {
823 /* Shutdown */
824 _vg_console_write_persistent();
825
826 SDL_AtomicLock( &vg.sl_status );
827 vg.engine_status = k_engine_status_none;
828 SDL_AtomicUnlock( &vg.sl_status );
829
830 _vg_loader_free();
831
832 vg_success( "If you see this it means everything went.. \"well\".....\n" );
833
834 SDL_GL_DeleteContext( vg.gl_context );
835 SDL_Quit();
836 exit(0);
837 }
838
839 static void vg_enter( int argc, char *argv[], const char *window_name )
840 {
841 vg_rand_seed( 461 );
842 _vg_process_launch_opts_internal( argc, argv );
843
844 /* Systems init */
845 vg_alloc_quota();
846 _vg_console_init();
847
848 vg_console_reg_var( "fps_limit", &vg.fps_limit, k_var_dtype_i32, 0 );
849 _vg_init_window( window_name );
850
851 vg_async_init();
852 SDL_SetRelativeMouseMode(1);
853
854 vg.thread_id_main = SDL_GetThreadID(NULL);
855
856 /* Opengl-required systems */
857 _vg_ui_init();
858 _vg_loader_init();
859
860 vg.engine_status = k_engine_status_load_internal;
861
862 _vg_opengl_sync_init();
863 vg_loader_start( _vg_load_full, NULL );
864 _vg_gameloop();
865 _vg_terminate();
866 }
867
868 static void vg_fatal_error( const char *fmt, ... )
869 {
870 va_list args;
871 va_start( args, fmt );
872 _vg_logx_va( stderr, NULL, "fatal", KRED, fmt, args );
873 va_end( args );
874
875 vg_print_backtrace();
876
877 SDL_AtomicLock( &vg.sl_status );
878 vg.engine_status = k_engine_status_crashed;
879 SDL_AtomicUnlock( &vg.sl_status );
880
881 if( vg_thread_purpose() == k_thread_purpose_loader ){
882 longjmp( vg.env_loader_exit, 1 );
883 }
884 else{
885 vg_error( "There is no jump to the error runner thing yet! bai bai\n" );
886 _vg_terminate();
887 }
888 }
889
890 #else /* VG_GAME */
891
892 #include "vg_log.h"
893 static void vg_fatal_error( const char *fmt, ... )
894 {
895 va_list args;
896 va_start( args, fmt );
897 _vg_logx_va( stderr, NULL, "fatal", KRED, fmt, args );
898 va_end( args );
899 exit(0);
900 }
901
902 #endif /* VG_GAME */
903
904 /*
905 * Graphic cards will check these to force it to use the GPU
906 */
907 u32 NvOptimusEnablement = 0x00000001;
908 int AmdPowerXpressRequestHighPerformance = 1;
909
910 #include "vg_log.c"
911
912 #endif /* VG_HEADER_H */