X-Git-Url: https://harrygodden.com/git/?a=blobdiff_plain;f=src%2Fvg%2Fvg.h;h=f3ed6991690edd23e57b12697a910e2b5ebe557d;hb=367883958336d1c04c8a304af6119b21f0f2f15a;hp=e2102774e004c70260216327106fa74c4a368570;hpb=6cfa3e0895e42f702276e97c85ad371f3512c67d;p=vg.git diff --git a/src/vg/vg.h b/src/vg/vg.h index e210277..f3ed699 100644 --- a/src/vg/vg.h +++ b/src/vg/vg.h @@ -1,312 +1,642 @@ -// Copyright (C) 2021 Harry Godden (hgn) - All Rights Reserved +/* Copyright (C) 2021-2022 Harry Godden (hgn) - All Rights Reserved */ -#include -#include -#include -#include -#include -#include -#include -#include +#ifndef VG_HEADER_H +#define VG_HEADER_H -#include "glad/glad.h" -#include "glfw/glfw3.h" +#include "vg_platform.h" -#define STB_DS_IMPLEMENTATION -#include "stb/stb_ds.h" -//#define STB_IMAGE_IMPLEMENTATION -//#include "stb/stb_image.h" -#define QOI_IMPLEMENTATION -#include "phoboslab/qoi.h" +#if defined(VG_SERVER) || defined(VG_TOOLS) + #define VG_NON_CLIENT +#endif -#include "vg/vg_platform.h" +#ifndef VG_SERVER +#include "../../dep/glad/glad.h" -void vg_register_exit( void( *funcptr )(void), const char *name ); -void vg_exiterr( const char *strErr ); +#define GLFW_INCLUDE_GLCOREARB -m3x3f vg_pv; +#ifdef _WIN32 + #define GLFW_DLL +#endif -#include "vg/vg_m.h" -#include "vg/vg_io.h" -#include "vg/vg_gldiag.h" +#include "../../dep/glfw/glfw3.h" +#endif -#ifndef VG_TOOLS +#include "vg_stdint.h" -// Engine globals -GLFWwindow* vg_window; +void vg_register_exit( void( *funcptr )(void), const char *name ); -// 1366, 768 -// 1920, 1080 +#include "vg_m.h" +#include "vg_io.h" +#include "vg_log.h" -#ifdef VG_CAPTURE_MODE -int vg_window_x = 1920; -int vg_window_y = 1080; -#else -int vg_window_x = 1366; -int vg_window_y = 768; +#ifdef VG_STEAM +//#include "vg_steamworks.h" +#include "vg_steam.h" +#endif + +#ifndef VG_NON_CLIENT +#include "vg_gldiag.h" #endif +#ifndef VG_NON_CLIENT + +m4x4f vg_pv; + +int vg_window_x = 0; +int vg_window_y = 0; +int vg_samples = 0; + v2f vg_mouse; v2f vg_mouse_wheel; v3f vg_mouse_ws; -float vg_time; -float vg_time_last; -float vg_time_delta; +double vg_time, + vg_time_last, + vg_time_delta; -// Engine components -#include "vg/vg_audio.h" -#include "vg/vg_shader.h" -#include "vg/vg_lines.h" -#include "vg/vg_tex.h" -#include "vg/vg_input.h" -#include "vg/vg_ui.h" -#include "vg/vg_console.h" -#include "vg/vg_debug.h" +struct vg +{ + /* Engine sync */ + GLFWwindow* window; + + vg_mutex mux_context; + vg_semaphore sem_allow_exec, + sem_exec_finished, + sem_loader, + sem_fatal; + int exec_context; + + vg_mutex mux_engine_status; + enum engine_status + { + k_engine_status_none, + k_engine_status_running, + k_engine_status_crashed + } + engine_status; + const char *str_const_engine_err; + + int is_loaded; + + /* Gamepad */ + GLFWgamepadstate gamepad; + int gamepad_ready; + const char *gamepad_name; + int gamepad_id; +} +static vg; -#ifdef VG_STEAM -#include "vg/vg_steamworks.h" -#endif +struct vg_thread_info +{ + enum vg_thread_purpose + { + k_thread_purpose_nothing, + k_thread_purpose_main, + k_thread_purpose_loader + } + purpose; -// Engine main -// =========================================================================================================== + int gl_context_level; +}; + +static VG_THREAD_LOCAL struct vg_thread_info vg_thread_info; -#ifndef VG_RELEASE -void vg_checkgl( const char *src_info ) -{ - GLenum err; - while( (err = glGetError()) != GL_NO_ERROR ) - { - vg_error( "(%s) OpenGL Error: #%d\n", src_info, err ); - } -} - #define VG_STRINGIT( X ) #X - #define VG_CHECK_GL() vg_checkgl( __FILE__ ":L" VG_STRINGIT(__LINE__) ) +//#define VG_SYNC_DEBUG + +#ifdef VG_SYNC_DEBUG + #define VG_SYNC_LOG(STR,...) vg_info(STR,vg_thread_info.purpose,##__VA_ARGS__) #else - #define VG_CHECK_GL() + #define VG_SYNC_LOG(...) #endif +static void vg_fatal_exit_loop( const char *error ); -#define VG_GAMELOOP +static void vg_ensure_engine_running(void) +{ + /* Check if the engine is no longer running */ + vg_mutex_lock( &vg.mux_engine_status ); + if( vg.engine_status != k_engine_status_running ) + { + VG_SYNC_LOG( "[%d] Engine is no longer running\n"); + vg_mutex_unlock( &vg.mux_engine_status ); + + /* Safe to disregard loader thread from this point on, elswhere */ + if( vg_thread_info.purpose == k_thread_purpose_loader ) + { + vg_semaphore_post( &vg.sem_loader ); + } + + VG_SYNC_LOG( "[%d] about to kill\n"); + vg_thread_exit(); + } + vg_mutex_unlock( &vg.mux_engine_status ); +} -void( *vg_on_exit[16] )(void); -u32 vg_exit_count = 0; +/* + * Sync execution so that the OpenGL context is switched onto this thread. + * Anything after this call will be in a valid context. + */ +static void vg_acquire_thread_sync(void) +{ + /* We dont want to do anything if this is the main thread */ + if( vg_thread_info.purpose == k_thread_purpose_main ) + return; + + assert( vg_thread_info.purpose == k_thread_purpose_loader ); + + vg_ensure_engine_running(); + + /* Check if thread already has the context */ + if( vg_thread_info.gl_context_level ) + { + vg_thread_info.gl_context_level ++; + VG_SYNC_LOG( "[%d] We already have sync here\n" ); + return; + } + + vg_mutex_lock( &vg.mux_context ); + VG_SYNC_LOG( "[%d] Signal to sync.\n" ); + vg.exec_context = 1; + vg_mutex_unlock( &vg.mux_context ); + + /* wait until told we can go */ + VG_SYNC_LOG( "[%d] Waiting to acuire sync.\n" ); + vg_semaphore_wait( &vg.sem_allow_exec ); + glfwMakeContextCurrent( vg.window ); + + /* context now valid to work in while we hold up main thread */ + VG_SYNC_LOG( "[%d] Context acquired.\n" ); + vg_thread_info.gl_context_level ++; +} -// Add a shutdown step -void vg_register_exit( void( *funcptr )(void), const char *name ) +/* + * Signify that we are done with the OpenGL context in this thread. + * Anything after this call will be in an undefined context. + */ +static void vg_release_thread_sync(void) { - vg_info( "exit registered: (%u)'%s'\n", vg_exit_count, name ); - vg_on_exit[ vg_exit_count ++ ] = funcptr; + if( vg_thread_info.purpose == k_thread_purpose_main ) + return; + + assert( vg_thread_info.purpose == k_thread_purpose_loader ); + + /* signal that we are done */ + vg_thread_info.gl_context_level --; + + if( !vg_thread_info.gl_context_level ) + { + VG_SYNC_LOG( "[%d] Releasing context.\n" ); + glfwMakeContextCurrent( NULL ); + vg_semaphore_post( &vg.sem_exec_finished ); + } } -void vg_exit(void) +static void vg_run_synced_content(void) { - for( int i = vg_exit_count-1; i >= 0; i -- ) - { - vg_info( "engine_exit[%d]()\n", i ); - vg_on_exit[i](); - } - - vg_info( "done\n" ); + assert( vg_thread_info.purpose == k_thread_purpose_main ); + + vg_mutex_lock( &vg.mux_context ); + + if( vg.exec_context != 0 ) + { + VG_SYNC_LOG( "[%d] Allowing content (%d).\n", vg.exec_context ); + + /* allow operations to go */ + vg_thread_info.gl_context_level = 0; + glfwMakeContextCurrent( NULL ); + vg_semaphore_post( &vg.sem_allow_exec ); + + /* wait for operations to complete */ + VG_SYNC_LOG( "[%d] Waiting for content (%d).\n", vg.exec_context ); + vg_semaphore_wait( &vg.sem_exec_finished ); + + /* check if we killed the engine */ + vg_ensure_engine_running(); + + /* re-engage main thread */ + VG_SYNC_LOG( "[%d] Re-engaging.\n" ); + vg.exec_context = 0; + glfwMakeContextCurrent( vg.window ); + vg_thread_info.gl_context_level = 1; + } + + vg_mutex_unlock( &vg.mux_context ); } -// Forcefully exit program after error -void vg_exiterr( const char *strErr ) +static void vg_opengl_sync_init(void) { - vg_error( "Engine Fatal: %s\n", strErr ); - vg_exit(); - exit(0); + vg_semaphore_init( &vg.sem_allow_exec, 0 ); + vg_semaphore_init( &vg.sem_exec_finished, 0 ); + vg_semaphore_init( &vg.sem_loader, 1 ); + vg_semaphore_init( &vg.sem_fatal, 1 ); + vg_mutex_init( &vg.mux_context ); + + vg_set_thread_name( "[vg] Main" ); + vg_thread_info.purpose = k_thread_purpose_main; + vg_thread_info.gl_context_level = 1; } -// Callbacks -// --------- +static void vg_checkgl( const char *src_info ); +#define VG_STRINGIT( X ) #X +#define VG_CHECK_GL_ERR() vg_checkgl( __FILE__ ":L" VG_STRINGIT(__LINE__) ) + +#include "vg_audio.h" +#include "vg_shader.h" +#include "vg_tex.h" +#include "vg_input.h" +#include "vg_ui.h" +#include "vg_console.h" +#include "vg_lines.h" +#include "vg_debug.h" +#include "vg_loader.h" +#include "vg_opt.h" + +#define VG_GAMELOOP +static void vg_register(void) VG_GAMELOOP; +static void vg_start(void) VG_GAMELOOP; +static void vg_update(int loaded) VG_GAMELOOP; +static void vg_framebuffer_resize(int w, int h) VG_GAMELOOP; +static void vg_render(void) VG_GAMELOOP; +static void vg_ui(void) VG_GAMELOOP; + +static void vg_checkgl( const char *src_info ) +{ + int fail = 0; + + GLenum err; + while( (err = glGetError()) != GL_NO_ERROR ) + { + vg_error( "(%s) OpenGL Error: #%d\n", src_info, err ); + fail = 1; + } + + if( fail ) + vg_fatal_exit_loop( "OpenGL Error" ); +} void vg_mouse_callback( GLFWwindow* ptrW, double xpos, double ypos ) { - vg_mouse[0] = xpos; - vg_mouse[1] = ypos; + vg_mouse[0] = xpos; + vg_mouse[1] = ypos; } void vg_scroll_callback( GLFWwindow* ptrW, double xoffset, double yoffset ) { - vg_mouse_wheel[0] += xoffset; - vg_mouse_wheel[1] += yoffset; + vg_mouse_wheel[0] += xoffset; + vg_mouse_wheel[1] += yoffset; } void vg_framebuffer_resize_callback( GLFWwindow *ptrW, int w, int h ) { - vg_window_x = w; - vg_window_y = h; + if( !w || !h ) + { + vg_warn( "Got a invalid framebuffer size: %dx%d... ignoring\n", w, h ); + return; + } + + vg_window_x = w; + vg_window_y = h; + + vg_framebuffer_resize(w,h); } -static void vg_register(void) VG_GAMELOOP; -static void vg_start(void) VG_GAMELOOP; -static void vg_update(void) VG_GAMELOOP; -static void vg_render(void) VG_GAMELOOP; -static void vg_ui(void) VG_GAMELOOP; -static void vg_free(void) VG_GAMELOOP; +static int vg_bake_shaders(void) +{ + vg_acquire_thread_sync(); + + if( !vg_shaders_recompile() ) + { + vg_shaders_free(NULL); + vg_release_thread_sync(); + return 0; + } + else + { + vg_release_thread_sync(); + vg_loader_highwater( NULL, vg_shaders_free, NULL ); + return 1; + } +} -static void vg_init( int argc, char *argv[], const char *window_name ) +void vg_preload(void); +void vg_load(void); +static void vg_load_full(void) { -#ifdef VG_STEAM - // Initialize steamworks - if( !sw_init() ) - return; + vg_preload(); + + /* internal */ + vg_loader_highwater( vg_gamepad_init, NULL, NULL ); + vg_loader_highwater( vg_lines_init, vg_lines_free, NULL ); + vg_loader_highwater( vg_audio_init, vg_audio_free, NULL ); + + /* client */ + vg_load(); + + vg_acquire_thread_sync(); + vg.is_loaded = 1; + vg_release_thread_sync(); +} + +static void vg_enter( int argc, char *argv[], const char *window_name ) +{ + char *arg; + while( vg_argp( argc, argv ) ) + { + if( (arg = vg_opt_arg( 'w' )) ) + { + vg_window_x = atoi( arg ); + } + + if( (arg = vg_opt_arg( 'h' )) ) + { + vg_window_y = atoi( arg ); + } + + if( (arg = vg_long_opt_arg( "samples" )) ) + { + vg_samples = VG_MAX( 0, VG_MIN( 8, atoi( arg ) ) ); + } + } + + vg_log_init(); + vg_console_init(); + + glfwInit(); + glfwWindowHint( GLFW_CONTEXT_VERSION_MAJOR, 3 ); + glfwWindowHint( GLFW_CONTEXT_VERSION_MINOR, 3 ); + glfwWindowHint( GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE ); + glfwWindowHint( GLFW_OPENGL_DEBUG_CONTEXT, GL_TRUE ); + glfwWindowHint( GLFW_CONTEXT_RELEASE_BEHAVIOR, GLFW_RELEASE_BEHAVIOR_FLUSH ); + + glfwWindowHint( GLFW_RESIZABLE, GLFW_FALSE ); + glfwWindowHint( GLFW_DOUBLEBUFFER, GLFW_TRUE ); + + glfwWindowHint( GLFW_SAMPLES, vg_samples ); + + GLFWmonitor *monitor_primary = glfwGetPrimaryMonitor(); + + const GLFWvidmode *mode = glfwGetVideoMode( monitor_primary ); + glfwWindowHint( GLFW_RED_BITS, mode->redBits ); + glfwWindowHint( GLFW_GREEN_BITS, mode->greenBits ); + glfwWindowHint( GLFW_BLUE_BITS, mode->blueBits ); + + /* TODO? */ + glfwWindowHint( GLFW_REFRESH_RATE, 60 ); + + if( !vg_window_x ) + vg_window_x = mode->width; + + if( !vg_window_y ) + vg_window_y = mode->height; + + + if( (vg.window = glfwCreateWindow( vg_window_x, vg_window_y, + window_name, monitor_primary, NULL)) ) + { + glfwGetFramebufferSize( vg.window, &vg_window_x, &vg_window_y ); + vg_success( "Window created (%dx%d)\n", vg_window_x, vg_window_y ); + } + else + { + vg_error( "GLFW Failed to initialize\n" ); + return; + } + + /* We need 3.1.2 for correct VSync on windows */ + { + int vmaj, vmin, vrev; + glfwGetVersion( &vmaj, &vmin, &vrev ); + + if( vmaj < 3 || + (vmaj == 3 && vmin < 1) || + (vmaj == 3 && vmin == 1 && vrev < 2 ) ) + { + vg_error( "GLFW out of date (%d.%d.%d); (3.1.2 is required)\n", + vmaj, vmin, vrev ); + + glfwTerminate(); + return; + } + + vg_success( "GLFW Version %d.%d.%d\n", vmaj, vmin, vrev ); + } + + glfwMakeContextCurrent( vg.window ); + glfwSwapInterval( 1 ); + + glfwSetWindowSizeLimits( vg.window, 800, 600, GLFW_DONT_CARE,GLFW_DONT_CARE); + glfwSetFramebufferSizeCallback( vg.window, vg_framebuffer_resize_callback ); + + glfwSetCursorPosCallback( vg.window, vg_mouse_callback ); + glfwSetScrollCallback( vg.window, vg_scroll_callback ); + + glfwSetCharCallback( vg.window, console_proc_wchar ); + glfwSetKeyCallback( vg.window, console_proc_key ); +#if 0 + glfwSetInputMode(vg_window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN); #endif - - // Context creation - // ========================================================================================================================== - glfwInit(); - glfwWindowHint( GLFW_CONTEXT_VERSION_MAJOR, 3 ); - glfwWindowHint( GLFW_CONTEXT_VERSION_MINOR, 3 ); - glfwWindowHint( GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE ); - glfwWindowHint( GLFW_OPENGL_DEBUG_CONTEXT, GL_TRUE ); - -#ifdef VG_CAPTURE_MODE - glfwWindowHint( GLFW_RESIZABLE, GLFW_FALSE ); -#else - glfwWindowHint( GLFW_RESIZABLE, GLFW_TRUE ); + + if( !gladLoadGLLoader((GLADloadproc)glfwGetProcAddress) ) + { + vg_error( "Glad Failed to initialize\n" ); + glfwTerminate(); + return; + } + + const unsigned char* glver = glGetString( GL_VERSION ); + vg_success( "Load setup complete, OpenGL version: %s\n", glver ); + vg_run_gfx_diagnostics(); + + if( !ui_default_init() ) + goto il_exit_ui; + + if( !vg_loader_init() ) + goto il_exit_loader; + + vg_mutex_init( &vg.mux_engine_status ); + vg.engine_status = k_engine_status_running; + + vg_opengl_sync_init(); + vg_loader_start(); + + int loaded = 0; + int counter =0; + while(1) + { + if( glfwWindowShouldClose( vg.window ) ) + break; + + v2_copy( (v2f){ 0.0f, 0.0f }, vg_mouse_wheel ); + glfwPollEvents(); + + vg_time_last = vg_time; + vg_time = glfwGetTime(); + vg_time_delta = vg_minf( vg_time - vg_time_last, 0.1f ); + + if( vg.is_loaded ) + { + glClearColor( 0.0f,sinf(vg_time*20.0)*0.5f+0.5f,0.0f,1.0f ); + glClear( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT ); + + if( !loaded ) + { + vg_start(); + loaded = 1; + } + } + else + { + vg_loader_render(); + } + + vg_update_inputs(); + vg_update( loaded ); + + counter ++; + +#if 0 + if( counter == 30 ) + vg_fatal_exit_loop( "Test crash from main, while loading (-O0)" ); #endif - glfwWindowHint( GLFW_SAMPLES, 4 ); - - GLFWmonitor *monitor_primary = glfwGetPrimaryMonitor(); - - const GLFWvidmode *mode = glfwGetVideoMode( monitor_primary ); - glfwWindowHint( GLFW_RED_BITS, mode->redBits ); - glfwWindowHint( GLFW_GREEN_BITS, mode->greenBits ); - glfwWindowHint( GLFW_BLUE_BITS, mode->blueBits ); - glfwWindowHint( GLFW_REFRESH_RATE, mode->refreshRate ); - - if( !(vg_window = glfwCreateWindow( vg_window_x, vg_window_y, window_name, NULL, NULL)) ) - { - vg_exiterr( "GLFW Failed to initialize" ); - } - else - { - vg_register_exit( &glfwTerminate, "glfwTerminate" ); - } - - glfwMakeContextCurrent( vg_window ); - glfwSwapInterval( 1 ); - - // Set callbacks - glfwSetFramebufferSizeCallback( vg_window, vg_framebuffer_resize_callback ); - - glfwSetCursorPosCallback( vg_window, vg_mouse_callback ); - glfwSetScrollCallback( vg_window, vg_scroll_callback ); - - glfwSetCharCallback( vg_window, console_proc_wchar ); - glfwSetKeyCallback( vg_window, console_proc_key ); - //glfwSetInputMode(vg_window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN); - - if( !gladLoadGLLoader((GLADloadproc)glfwGetProcAddress) ) - { - vg_exiterr( "Glad failed to initialize" ); - } - - const unsigned char* glver = glGetString( GL_VERSION ); - vg_success( "Load setup complete, OpenGL version: %s\n", glver ); - - vg_run_gfx_diagnostics(); - - for( int id = 0; id <= GLFW_JOYSTICK_LAST; id ++ ) - { - if( glfwJoystickIsGamepad( id ) ) - { - vg_gamepad_name = glfwGetGamepadName( id ); - vg_success( "Gamepad with mapping registered: %s\n", vg_gamepad_name ); - - vg_gamepad_ready = 1; - vg_gamepad_id = id; - - break; - } - } - - vg_lines_init(); - vg_register_exit( &vg_lines_free, "vg_lines_free" ); - ui_default_init(); - vg_register_exit( &ui_default_free, "UI" ); - - vg_register(); - vg_register_exit( &vg_free, "vg_free" ); - - if( vg_shaders_compile() ) - { - vg_start(); - - vg_console_init(); - vg_register_exit( &vg_console_free, "Console" ); - - vg_audio_init(); - vg_register_exit( &vg_audio_free, "vg_audio_free" ); - - vg_debugtools_setup(); - - // Main gameloop - while( !glfwWindowShouldClose( vg_window ) ) - { - v2_copy( (v2f){ 0.0f, 0.0f }, vg_mouse_wheel ); - - glfwPollEvents(); - - #ifdef VG_STEAM - sw_event_loop(); - #endif - - vg_time_last = vg_time; - vg_time = glfwGetTime(); - vg_time_delta = vg_minf( vg_time - vg_time_last, 0.1f ); - - vg_update_inputs(); - vg_update(); - vg_render(); - - vg_lines_drawall((float*)vg_pv); - - { - ui_begin( &ui_global_ctx, vg_window_x, vg_window_y ); - ui_set_mouse( &ui_global_ctx, vg_mouse[0], vg_mouse[1], vg_get_button_state( "primary" ) ); - - vg_ui(); - vg_console_draw(); - vg_debugtools_draw(); - - ui_resolve( &ui_global_ctx ); - ui_draw( &ui_global_ctx, NULL ); - } - - glfwSwapBuffers( vg_window ); - - VG_CHECK_GL(); - } - } - - vg_exit(); + if( loaded ) + { + vg_render(); + + /* ui */ + { + ui_begin( &ui_global_ctx, vg_window_x, vg_window_y ); + ui_set_mouse( &ui_global_ctx, vg_mouse[0], vg_mouse[1], + vg_get_button_state( "primary" ) ); + + audio_debug_ui( vg_pv ); + vg_ui(); + vg_console_draw(); + + ui_resolve( &ui_global_ctx ); + ui_draw( &ui_global_ctx, NULL ); + } + } + + glfwSwapBuffers( vg.window ); + vg_run_synced_content(); + } + + vg_console_write_persistent(); + + vg_mutex_lock( &vg.mux_engine_status ); + vg.engine_status = k_engine_status_none; + vg_mutex_unlock( &vg.mux_engine_status ); + + vg_loader_free(); + +il_exit_loader: + ui_default_free(); + +il_exit_ui: + glfwTerminate(); } -// Screen projections -// ============================================================================================ +/* + * Immediately transfer away from calling thread into a safe loop, signal for + * others to shutdown, then free everything once the user closes the window. + */ +static void vg_fatal_exit_loop( const char *error ) +{ + vg_error( "Fatal error: %s\n", error ); + assert( vg_semaphore_trywait( &vg.sem_fatal ) ); + + vg_mutex_lock( &vg.mux_engine_status ); + + if( vg.engine_status == k_engine_status_none ) + { + vg_mutex_unlock( &vg.mux_engine_status ); + + /* TODO: Correct shutdown before other systems */ + exit(0); + } + else + { + vg_mutex_unlock( &vg.mux_engine_status ); + + /* + * if main + * if loader running + * wait until loader checks in, it will die + * else + * pass immediately + * else + * if have context + * pass immediately + * else + * wait for main to get to us, it will never be used again + * + * undefined behaviour: + * fatal_exit_loop is called in both threads, preventing an appropriate + * reaction to the crash. This *should* be made + * obvious by the assertion + */ + vg_acquire_thread_sync(); + + vg_mutex_lock( &vg.mux_engine_status ); + vg.engine_status = k_engine_status_crashed; + vg.str_const_engine_err = error; + vg_mutex_unlock( &vg.mux_engine_status ); + + /* + * Wait for loader to finish what it was doing, if it was running. + * Then we can continue in our nice error screen + */ + if( vg_thread_info.purpose == k_thread_purpose_main ) + { + vg_semaphore_wait( &vg.sem_loader ); + } + vg_audio_free(NULL); + + /* + * todo: draw error loop + */ + while(1) + { + if( glfwWindowShouldClose( vg.window ) ) + break; + + glfwPollEvents(); + + glClearColor( 0.15f + sinf(glfwGetTime())*0.1f, 0.0f, 0.0f,1.0f ); + glClear( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT ); + glViewport( 0,0, vg_window_x, vg_window_y ); + + vg_render_log(); + + glfwSwapBuffers( vg.window ); + } + + /* Can now shutdown and EXIT */ + vg_loader_free(); + ui_default_free(); + + glfwTerminate(); + exit(0); + } +} -void vg_projection_update(void) +#else + +static void vg_fatal_exit_loop( const char *error ) { - // Do transform local->world - vg_mouse_ws[0] = vg_mouse[0]; - vg_mouse_ws[1] = vg_mouse[1]; - vg_mouse_ws[2] = 1.0f; - - vg_mouse_ws[0] = (2.0f * vg_mouse_ws[0]) / ((float)vg_window_x) - 1.0f; - vg_mouse_ws[1] = -((2.0f * vg_mouse_ws[1]) / ((float)vg_window_y) - 1.0f); - - m3x3f inverse; - m3x3_inv( vg_pv, inverse ); - m3x3_mulv( inverse, vg_mouse_ws, vg_mouse_ws ); + vg_error( "Fatal error: %s\n", error ); + exit(0); } #endif +/* + * Graphic cards will check these to force it to use the GPU + */ u32 NvOptimusEnablement = 0x00000001; int AmdPowerXpressRequestHighPerformance = 1; + +#endif