X-Git-Url: https://harrygodden.com/git/?a=blobdiff_plain;f=src%2Fvg%2Fvg.h;fp=src%2Fvg%2Fvg.h;h=0000000000000000000000000000000000000000;hb=4c48fe01a5d1983be89b7dce6f08e6b708cfbb05;hp=77d27e2fb9f80553cacad4469608b79f82a4678d;hpb=3dd767bb10e6fee9cbffeb185d1a9685810c17b5;p=vg.git diff --git a/src/vg/vg.h b/src/vg/vg.h deleted file mode 100644 index 77d27e2..0000000 --- a/src/vg/vg.h +++ /dev/null @@ -1,812 +0,0 @@ -/* Copyright (C) 2021-2022 Harry Godden (hgn) - All Rights Reserved */ - -/* - * Memory model: - * [global (.data)] [temp-stack] [system-stack] [game-heap] - * - * 1. Program starts: .data memory is loaded - * 2. System initialization: - * 2a. the large heap buffer is allocated - * 2b. each engine system is initialized in order, using some of the - * system stack - * 2c. game systems are also put into here - */ - - -#ifndef VG_HEADER_H -#define VG_HEADER_H - -#include "vg_platform.h" -#include "vg_mem.h" - -#ifndef _WIN32 -#include -#endif - - -#if defined(VG_SERVER) || defined(VG_TOOLS) - #define VG_NON_CLIENT -#endif - -#ifndef VG_SERVER -#include "../../dep/glad/glad.h" - -#define GLFW_INCLUDE_GLCOREARB - -#ifdef _WIN32 - #define GLFW_DLL -#endif - -#include "../../dep/glfw/glfw3.h" -#endif - -#include "vg_stdint.h" - -void vg_register_exit( void( *funcptr )(void), const char *name ); - -#include "vg_m.h" -#include "vg_io.h" -#include "vg_log.h" - -#ifdef VG_STEAM -//#include "vg_steamworks.h" -#include "vg_steam.h" -#endif - -#ifndef VG_NON_CLIENT - -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; - - /* Window information */ - int window_x, - window_y, - samples; - float refresh_rate; - - double mouse_pos[2]; - v2f - mouse_delta, - mouse_wheel; - - /* Runtime */ - double time, - time_delta, - frame_delta, - time_real, - time_real_last, - time_rate, - accumulator; - - int fixed_iterations; - - enum engine_stage - { - k_engine_stage_none, - k_engine_stage_update, - k_engine_stage_update_fixed, - k_engine_stage_rendering, - k_engine_stage_ui - } - engine_stage; - - /* graphics */ - m4x4f pv; - enum quality_profile - { - k_quality_profile_high = 0, - k_quality_profile_low = 1, - } - quality_profile; - - /* Gamepad */ - GLFWgamepadstate gamepad; - int gamepad_ready; - const char *gamepad_name; - int gamepad_id; - int gamepad_use_trackpad_look; -} -VG_STATIC vg = { .time_rate = 1.0 }; - -struct vg_thread_info -{ - enum vg_thread_purpose - { - k_thread_purpose_nothing, - k_thread_purpose_main, - k_thread_purpose_loader - } - purpose; - - int gl_context_level; -}; - -static VG_THREAD_LOCAL struct vg_thread_info vg_thread_info; - - -//#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_SYNC_LOG(...) -#endif - -VG_STATIC void vg_fatal_exit_loop( const char *error ); -VG_STATIC void vg_required( void *ptr, const char *path ) -{ - if( !ptr ) - { - vg_fatal_exit_loop( path ); - } -} - - -VG_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 ); -} - -/* - * Sync execution so that the OpenGL context is switched onto this thread. - * Anything after this call will be in a valid context. - */ -VG_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 ++; -} - -/* - * Signify that we are done with the OpenGL context in this thread. - * Anything after this call will be in an undefined context. - */ -VG_STATIC void vg_release_thread_sync(void) -{ - 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 ); - } -} - -VG_STATIC void vg_run_synced_content(void) -{ - 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 ); -} - -VG_STATIC void vg_opengl_sync_init(void) -{ - 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; -} - -VG_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_console.h" -#include "vg_profiler.h" -#include "vg_audio.h" -#include "vg_shader.h" -#include "vg_tex.h" -#include "vg_input.h" -#include "vg_ui.h" -#include "vg_lines.h" -#include "vg_loader.h" -#include "vg_opt.h" - -/* Diagnostic */ -VG_STATIC struct vg_profile vg_prof_update = {.name="update()"}, - vg_prof_render = {.name="render()"}; - -#define VG_GAMELOOP -VG_STATIC void vg_register(void) VG_GAMELOOP; -VG_STATIC void vg_start(void) VG_GAMELOOP; - -VG_STATIC void vg_update(int loaded) VG_GAMELOOP; -VG_STATIC void vg_update_fixed(int loaded) VG_GAMELOOP; -VG_STATIC void vg_update_post(int loaded) VG_GAMELOOP; - -VG_STATIC void vg_framebuffer_resize(int w, int h) VG_GAMELOOP; -VG_STATIC void vg_render(void) VG_GAMELOOP; -VG_STATIC void vg_ui(void) VG_GAMELOOP; - -VG_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_delta[0] += xpos - vg.mouse_pos[0]; - vg.mouse_delta[1] += ypos - vg.mouse_pos[1]; - - vg.mouse_pos[0] = xpos; - vg.mouse_pos[1] = ypos; -} - -void vg_scroll_callback( GLFWwindow* ptrW, double xoffset, double yoffset ) -{ - vg.mouse_wheel[0] += xoffset; - vg.mouse_wheel[1] += yoffset; -} - -void vg_framebuffer_resize_callback( GLFWwindow *ptrW, int w, int 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); -} - -VG_STATIC void vg_bake_shaders(void) -{ - vg_acquire_thread_sync(); - -#if 0 - vg_function_push( (struct vg_cmd) - { - .name = "shaders", - .function = vg_shaders_live_recompile - }); -#endif - - vg_shaders_compile(); - vg_release_thread_sync(); -} - -VG_STATIC void vg_preload(void); -VG_STATIC void vg_load(void); -VG_STATIC void vg_load_full(void) -{ - vg_preload(); - - /* internal */ - vg_loader_highwater( vg_gamepad_init, NULL, NULL ); - vg_loader_highwater( vg_lines_init, NULL, NULL ); - vg_loader_highwater( vg_audio_init, vg_audio_free, NULL ); - vg_loader_highwater( vg_profiler_init, NULL, NULL ); - - /* client */ - vg_load(); - - vg_acquire_thread_sync(); - vg.is_loaded = 1; - vg_release_thread_sync(); -} - -VG_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 ) ) ); - } - - if( vg_long_opt( "use-libc-malloc" ) ) - { - vg_mem.use_libc_malloc = atoi( arg ); - } - - if( vg_long_opt( "high-performance" ) ) - { - vg.quality_profile = k_quality_profile_low; - } - } - - vg_alloc_quota(); - 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_FALSE ); - 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 ); - - glfwWindowHint( GLFW_REFRESH_RATE, mode->refreshRate ); - - if( !vg.window_x ) - vg.window_x = mode->width; - - if( !vg.window_y ) - vg.window_y = mode->height; - - vg.refresh_rate = mode->refreshRate; - - 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 ); - glfwSetInputMode( vg.window, GLFW_CURSOR, GLFW_CURSOR_DISABLED ); - - if( glfwRawMouseMotionSupported() ) - glfwSetInputMode( vg.window, GLFW_RAW_MOUSE_MOTION, 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 ); - - /* init systems - * -----------------------------------------------------------------------*/ - ui_init_context(); - vg_loader_init(); - - vg_mutex_init( &vg.mux_engine_status ); - vg.engine_status = k_engine_status_running; - - vg_opengl_sync_init(); - vg_loader_start(); - - vg.accumulator = 0.75f * (1.0f/60.0f); - - int loaded = 0; - while(1) - { - if( glfwWindowShouldClose( vg.window ) ) - break; - - v2_zero( vg.mouse_wheel ); - v2_zero( vg.mouse_delta ); - - glfwPollEvents(); - - vg.time_real_last = vg.time_real; - vg.time_real = glfwGetTime(); - vg.frame_delta = vg.time_real-vg.time_real_last; - - /* scaled time */ - vg.time_delta = vg.frame_delta * vg.time_rate; - vg.time += vg.time_delta; - - if( vg.is_loaded ) - { - if( !loaded ) - { - vg_start(); - loaded = 1; - } - } - else - { - vg_loader_render(); - } - - /* - * Game logic - * ------------------------------------------------------- - */ - vg_profile_begin( &vg_prof_update ); - vg_update_inputs(); - - vg.engine_stage = k_engine_stage_update; - vg_update( loaded ); - - /* Fixed update loop */ - vg.engine_stage = k_engine_stage_update_fixed; - vg.accumulator += vg.time_delta; - - vg.fixed_iterations = 0; - vg_lines.allow_input = 1; - while( vg.accumulator >= (VG_TIMESTEP_FIXED-0.00125) ) - { - vg_update_fixed( loaded ); - vg_lines.allow_input = 0; - - vg.accumulator -= VG_TIMESTEP_FIXED; - vg.accumulator = VG_MAX( 0.0, vg.accumulator ); - - vg.fixed_iterations ++; - if( vg.fixed_iterations == 8 ) - { - break; - } - } - vg_lines.allow_input = 1; - - /* - * Rendering - * --------------------------------------------- - */ - vg.engine_stage = k_engine_stage_update; - vg_update_post( loaded ); - vg_profile_end( &vg_prof_update ); - - vg_profile_begin( &vg_prof_render ); - - if( loaded ) - { - /* render */ - vg.engine_stage = k_engine_stage_rendering; - vg_render(); - - /* ui */ - vg.engine_stage = k_engine_stage_ui; - { - ui_begin( vg.window_x, vg.window_y ); - - /* TODO */ - ui_set_mouse( vg.mouse_pos[0], vg.mouse_pos[1], 0 ); - - vg_profile_drawn( - (struct vg_profile *[]){&vg_prof_update,&vg_prof_render}, 2, - (1.0f/(float)vg.refresh_rate)*1000.0f, - (ui_rect){ 4, 4, 250, 0 }, 0 - ); - - if( vg_profiler ) - { - - char perf[128]; - - snprintf( perf, 127, - "x: %d y: %d\n" - "refresh: %.1f (%.1fms)\n" - "samples: %d\n" - "iterations: %d (acc: %.3fms%%)\n", - vg.window_x, vg.window_y, - vg.refresh_rate, (1.0f/vg.refresh_rate)*1000.0f, - vg.samples, - vg.fixed_iterations, - (vg.accumulator/VG_TIMESTEP_FIXED)*100.0f ); - - ui_text( (ui_rect){258, 4+24+12,0,0},perf, 1,0); - } - - audio_debug_ui( vg.pv ); - vg_ui(); - vg_console_draw(); - - ui_resolve(); - ui_draw( NULL ); - } - } - - vg_profile_end( &vg_prof_render ); - - 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(); - - vg_success( "If you see this it means everything went.. \"well\".....\n" ); - glfwTerminate(); -} - -/* - * Immediately transfer away from calling thread into a safe loop, signal for - * others to shutdown, then free everything once the user closes the window. - * - * FIXME(bug): glfwWindowShouldClose() never returns 1 in windows via wine, ONLY - * when calling the program from outside its normal directory. - */ -VG_STATIC void vg_fatal_exit_loop( const char *error ) -{ - /* - * https://www.gnu.org/software/libc/manual/html_node/Backtraces.html - * thanks gnu <3 - * - * TODO: this on windows? - */ - -#ifndef _WIN32 - - void *array[20]; - char **strings; - int size, i; - - size = backtrace( array, 20 ); - strings = backtrace_symbols( array, size ); - - if( strings != NULL ) - { - vg_error( "---------------- gnu backtrace -------------\n" ); - - for( int i=0; i