1 /* Copyright (C) 2021-2022 Harry Godden (hgn) - All Rights Reserved */
14 #if defined(VG_SERVER) || defined(VG_TOOLS)
19 #include "../../dep/glad/glad.h"
20 #include "../../dep/glfw/glfw3.h"
23 #define STB_DS_IMPLEMENTATION
24 #include "stb/stb_ds.h"
26 #define QOI_IMPLEMENTATION
27 #include "phoboslab/qoi.h"
29 #include "vg_stdint.h"
30 #include "vg_platform.h"
32 void vg_register_exit( void( *funcptr
)(void), const char *name
);
39 //#include "vg_steamworks.h"
44 #include "vg_gldiag.h"
51 #ifdef VG_CAPTURE_MODE
52 int vg_window_x
= 1920;
53 int vg_window_y
= 1080;
55 int vg_window_x
= 1366;
56 int vg_window_y
= 768;
74 vg_semaphore sem_allow_exec
,
78 vg_mutex mux_engine_status
;
83 GLFWgamepadstate gamepad
;
85 const char *gamepad_name
;
91 //#define VG_SYNC_DEBUG
94 #define VG_SYNC_LOG(...) vg_info(__VA_ARGS__)
96 #define VG_SYNC_LOG(...)
100 * Sync execution so that the OpenGL context is switched onto this thread.
101 * Anything after this call will be in a valid context.
103 static int vg_acquire_thread_sync( int id
)
112 /* Check if the engine is no longer running */
113 vg_mutex_lock( &vg
.mux_engine_status
);
114 if( !vg
.engine_running
)
116 VG_SYNC_LOG( "[%d] Engine is no longer running\n", id
);
117 vg_mutex_unlock( &vg
.mux_engine_status
);
120 vg_mutex_unlock( &vg
.mux_engine_status
);
123 vg_mutex_lock( &vg
.mux_context
);
124 VG_SYNC_LOG( "[%d] Signal to sync.\n", id
);
125 vg
.exec_context
= id
;
126 vg_mutex_unlock( &vg
.mux_context
);
128 /* wait until told we can go */
129 VG_SYNC_LOG( "[%d] Waiting to acuire sync.\n", id
);
130 vg_semaphore_wait( &vg
.sem_allow_exec
);
131 glfwMakeContextCurrent( vg
.window
);
133 /* context now valid to work in while we hold up main thread */
134 VG_SYNC_LOG( "[%d] Context acquired.\n", id
);
141 * Signify that we are done with the OpenGL context in this thread.
142 * Anything after this call will be in an undefined context.
144 static void vg_release_thread_sync( int id
)
148 vg_mutex_lock( &vg
.mux_context
);
150 if( vg
.exec_context
!= 0 )
152 VG_SYNC_LOG( "[%d] Allowing content (%d).\n", id
, vg
.exec_context
);
154 /* allow operations to go */
155 glfwMakeContextCurrent( NULL
);
156 vg_semaphore_post( &vg
.sem_allow_exec
);
158 /* wait for operations to complete */
159 VG_SYNC_LOG( "[%d] Waiting for content (%d).\n", id
, vg
.exec_context
);
160 vg_semaphore_wait( &vg
.sem_exec_finished
);
162 /* re-engage main thread */
163 VG_SYNC_LOG( "[%d] Re-engaging.\n", id
);
165 glfwMakeContextCurrent( vg
.window
);
168 vg_mutex_unlock( &vg
.mux_context
);
172 /* signal that we are done */
173 VG_SYNC_LOG( "[%d] Releasing context.\n", id
);
174 glfwMakeContextCurrent( NULL
);
175 vg_semaphore_post( &vg
.sem_exec_finished
);
179 static void vg_opengl_sync_init(void)
181 vg_semaphore_init( &vg
.sem_allow_exec
, 0 );
182 vg_semaphore_init( &vg
.sem_exec_finished
, 0 );
183 vg_mutex_init( &vg
.mux_context
);
186 static void vg_opengl_sync_free(void)
188 vg_semaphore_free( &vg
.sem_allow_exec
);
189 vg_semaphore_free( &vg
.sem_exec_finished
);
190 vg_mutex_free( &vg
.mux_context
);
194 int vg_checkgl( const char *src_info
);
195 #define VG_STRINGIT( X ) #X
196 #define VG_CHECK_GL_ERR() vg_checkgl( __FILE__ ":L" VG_STRINGIT(__LINE__) )
198 #include "vg_audio.h"
199 #include "vg_shader.h"
201 #include "vg_input.h"
203 #include "vg_console.h"
204 #include "vg_lines.h"
205 #include "vg_debug.h"
206 #include "vg_loader.h"
209 static void vg_register(void) VG_GAMELOOP
;
210 static void vg_start(void) VG_GAMELOOP
;
211 static void vg_update(int loaded
) VG_GAMELOOP
;
212 static void vg_framebuffer_resize(int w
, int h
) VG_GAMELOOP
;
213 static void vg_render(void) VG_GAMELOOP
;
214 static void vg_ui(void) VG_GAMELOOP
;
216 int vg_checkgl( const char *src_info
)
221 while( (err
= glGetError()) != GL_NO_ERROR
)
223 vg_error( "(%s) OpenGL Error: #%d\n", src_info
, err
);
232 void vg_mouse_callback( GLFWwindow
* ptrW
, double xpos
, double ypos
)
238 void vg_scroll_callback( GLFWwindow
* ptrW
, double xoffset
, double yoffset
)
240 vg_mouse_wheel
[0] += xoffset
;
241 vg_mouse_wheel
[1] += yoffset
;
244 void vg_framebuffer_resize_callback( GLFWwindow
*ptrW
, int w
, int h
)
249 vg_framebuffer_resize(w
,h
);
252 static int vg_bake_shaders(void)
254 if( vg_acquire_thread_sync(1) )
256 if( !vg_shaders_recompile() )
258 vg_shaders_free(NULL
);
259 vg_release_thread_sync(1);
264 vg_release_thread_sync(1);
266 if( !vg_loader_highwater( vg_shaders_free
, NULL
) ) return 0;
274 int vg_preload(void);
276 static int vg_load_full(void)
278 if( !vg_preload() ) return 0;
281 if( !vg_gamepad_init() ) return 0;
282 if( !vg_loader_highwater( NULL
, NULL
) ) return 0;
284 if( !vg_lines_init() ) return 0;
285 if( !vg_loader_highwater( vg_lines_free
, NULL
) ) return 0;
287 if( !vg_audio_init() ) return 0;
288 if( !vg_loader_highwater( vg_audio_free
, NULL
) ) return 0;
291 if( !vg_load() ) return 0;
296 static void vg_enter( int argc
, char *argv
[], const char *window_name
)
302 glfwWindowHint( GLFW_CONTEXT_VERSION_MAJOR
, 3 );
303 glfwWindowHint( GLFW_CONTEXT_VERSION_MINOR
, 3 );
304 glfwWindowHint( GLFW_OPENGL_PROFILE
, GLFW_OPENGL_CORE_PROFILE
);
305 glfwWindowHint( GLFW_OPENGL_DEBUG_CONTEXT
, GL_TRUE
);
307 glfwWindowHint( GLFW_RESIZABLE
, GLFW_TRUE
);
308 glfwWindowHint( GLFW_DOUBLEBUFFER
, GLFW_TRUE
);
311 glfwWindowHint(GLFW_SAMPLES
,4);
314 GLFWmonitor
*monitor_primary
= glfwGetPrimaryMonitor();
316 const GLFWvidmode
*mode
= glfwGetVideoMode( monitor_primary
);
317 glfwWindowHint( GLFW_RED_BITS
, mode
->redBits
);
318 glfwWindowHint( GLFW_GREEN_BITS
, mode
->greenBits
);
319 glfwWindowHint( GLFW_BLUE_BITS
, mode
->blueBits
);
321 /* This is set like this because of an OS issue */
322 int refresh_rate
= mode
->refreshRate
;
323 if( refresh_rate
< 28 || refresh_rate
>= 144 )
325 glfwWindowHint( GLFW_REFRESH_RATE
, refresh_rate
);
327 if( !(vg
.window
= glfwCreateWindow( vg_window_x
, vg_window_y
,
328 window_name
, NULL
, NULL
)) )
330 vg_error( "GLFW Failed to initialize\n" );
334 glfwMakeContextCurrent( vg
.window
);
335 glfwSwapInterval( 1 );
337 glfwSetWindowSizeLimits( vg
.window
, 800, 600, GLFW_DONT_CARE
,GLFW_DONT_CARE
);
338 glfwSetFramebufferSizeCallback( vg
.window
, vg_framebuffer_resize_callback
);
340 glfwSetCursorPosCallback( vg
.window
, vg_mouse_callback
);
341 glfwSetScrollCallback( vg
.window
, vg_scroll_callback
);
343 glfwSetCharCallback( vg
.window
, console_proc_wchar
);
344 glfwSetKeyCallback( vg
.window
, console_proc_key
);
346 glfwSetInputMode(vg_window
, GLFW_CURSOR
, GLFW_CURSOR_HIDDEN
);
349 if( !gladLoadGLLoader((GLADloadproc
)glfwGetProcAddress
) )
351 vg_error( "Glad Failed to initialize\n" );
356 const unsigned char* glver
= glGetString( GL_VERSION
);
357 vg_success( "Load setup complete, OpenGL version: %s\n", glver
);
358 vg_run_gfx_diagnostics();
360 if( !ui_default_init() )
363 if( !vg_loader_init() )
366 vg_mutex_init( &vg
.mux_engine_status
);
367 vg
.engine_running
= 1;
369 vg_opengl_sync_init();
376 vg_acquire_thread_sync( 0 );
378 if( glfwWindowShouldClose( vg
.window
) )
383 v2_copy( (v2f
){ 0.0f
, 0.0f
}, vg_mouse_wheel
);
386 vg_time_last
= vg_time
;
387 vg_time
= glfwGetTime();
388 vg_time_delta
= vg_minf( vg_time
- vg_time_last
, 0.1f
);
390 enum loader_status load_status
= vg_loader_status();
392 if( load_status
== k_loader_status_complete
)
394 glClearColor( 0.0f
,sinf(vg_time
*20.0)*0.5f
+0.5f
,0.0f
,1.0f
);
395 glClear( GL_COLOR_BUFFER_BIT
|GL_DEPTH_BUFFER_BIT
);
405 if( load_status
== k_loader_status_fail
)
424 ui_begin( &ui_global_ctx
, vg_window_x
, vg_window_y
);
425 ui_set_mouse( &ui_global_ctx
, vg_mouse
[0], vg_mouse
[1],
426 vg_get_button_state( "primary" ) );
428 audio_debug_ui( vg_pv
);
432 ui_resolve( &ui_global_ctx
);
433 ui_draw( &ui_global_ctx
, NULL
);
440 glfwSwapBuffers( vg
.window
);
442 if( VG_CHECK_GL_ERR() )
445 vg_release_thread_sync( 0 );
448 vg_console_write_persistent();
450 vg_mutex_lock( &vg
.mux_engine_status
);
451 vg
.engine_running
= 0;
452 vg_mutex_unlock( &vg
.mux_engine_status
);
456 vg_opengl_sync_free();
458 vg_mutex_free( &vg
.mux_engine_status
);
470 * Graphic cards will check these to force it to use the GPU
472 u32 NvOptimusEnablement
= 0x00000001;
473 int AmdPowerXpressRequestHighPerformance
= 1;