#ifdef STB_INCLUDE_IMPLEMENTATION
#include <stdio.h>
-#include <stdlib.h>
#include <string.h>
+#ifndef STB_MALLOC
+ #define STB_STDLIB
+ #define STB_MALLOC malloc
+#endif
+
+#ifndef STB_FREE
+ #define STB_STDLIB
+ #define STB_FREE free
+#endif
+
+#ifndef STB_REALLOC
+ #define STB_STDLIB
+ #define STB_REALLOC realloc
+#endif
+
+#ifdef STB_STDLIB
+ #include <stdlib.h>
+#endif
+
static char *stb_include_load_file(char *filename, size_t *plen)
{
char *text;
fseek(f, 0, SEEK_END);
len = (size_t) ftell(f);
if (plen) *plen = len;
- text = (char *) malloc(len+1);
+ text = (char *) STB_MALLOC(len+1);
if (text == 0) return 0;
fseek(f, 0, SEEK_SET);
fread(text, 1, len, f);
static include_info *stb_include_append_include(include_info *array, int len, int offset, int end, char *filename, int next_line)
{
- include_info *z = (include_info *) realloc(array, sizeof(*z) * (len+1));
+ include_info *z = (include_info *)STB_REALLOC(array, sizeof(*z) * (len+1));
z[len].offset = offset;
z[len].end = end;
z[len].filename = filename;
{
int i;
for (i=0; i < len; ++i)
- free(array[i].filename);
- free(array);
+ STB_FREE(array[i].filename);
+ STB_FREE(array);
}
static int stb_include_isspace(int ch)
while (*t != '"' && *t != '\n' && *t != '\r' && *t != 0)
++t;
if (*t == '"') {
- char *filename = (char *) malloc(t-s+1);
+ char *filename = (char *) STB_MALLOC(t-s+1);
memcpy(filename, s, t-s);
filename[t-s] = 0;
s=t;
static char *stb_include_append(char *str, size_t *curlen, char *addstr, size_t addlen)
{
- str = (char *) realloc(str, *curlen + addlen);
+ str = (char *)STB_REALLOC(str, *curlen + addlen);
memcpy(str + *curlen, addstr, addlen);
*curlen += addlen;
return str;
return NULL;
}
text = stb_include_append(text, &textlen, inc, strlen(inc));
- free(inc);
+ STB_FREE(inc);
}
// write out line directive
#ifndef STB_INCLUDE_LINE_NONE
size_t length=0;
for (i=0; i < count; ++i)
length += strlen(strs[i]);
- text = (char *) malloc(length+1);
+ text = (char *) STB_MALLOC(length+1);
length = 0;
for (i=0; i < count; ++i) {
strcpy(text + length, strs[i]);
length += strlen(strs[i]);
}
result = stb_include_string(text, inject, path_to_includes, filename, error);
- free(text);
+ STB_FREE(text);
return result;
}
return 0;
}
result = stb_include_string(text, inject, path_to_includes, filename, error);
- free(text);
+ STB_FREE(text);
return result;
}
#ifndef VG_HEADER_H
#define VG_HEADER_H
-#include <stdio.h>
-#include <stdlib.h>
-#include <dirent.h>
-#include <string.h>
-#include <stdarg.h>
-#include <ctype.h>
-#include <math.h>
+#include "vg_platform.h"
+
#if defined(VG_SERVER) || defined(VG_TOOLS)
#define VG_NON_CLIENT
#include "../../dep/glfw/glfw3.h"
#endif
-#define STB_DS_IMPLEMENTATION
-#include "stb/stb_ds.h"
-
-#define QOI_IMPLEMENTATION
-#include "phoboslab/qoi.h"
-
#include "vg_stdint.h"
-#include "vg_platform.h"
void vg_register_exit( void( *funcptr )(void), const char *name );
vg_time_last,
vg_time_delta;
-
struct vg
{
/* Engine sync */
vg_mutex mux_context;
vg_semaphore sem_allow_exec,
- sem_exec_finished;
+ sem_exec_finished,
+ sem_loader,
+ sem_fatal;
int exec_context;
vg_mutex mux_engine_status;
- int engine_running;
+ 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;
}
static vg;
+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(...) vg_info(__VA_ARGS__)
+ #define VG_SYNC_LOG(STR,...) vg_info(STR,vg_thread_info.purpose,##__VA_ARGS__)
#else
#define VG_SYNC_LOG(...)
#endif
-/*
- * Sync execution so that the OpenGL context is switched onto this thread.
- * Anything after this call will be in a valid context.
- */
-static int vg_acquire_thread_sync( int id )
+static void vg_fatal_exit_loop( const char *error );
+
+static void vg_ensure_engine_running(void)
{
- if( id == 0 )
- {
- /* no action */
- return 1;
- }
- else
+ /* Check if the engine is no longer running */
+ vg_mutex_lock( &vg.mux_engine_status );
+ if( vg.engine_status != k_engine_status_running )
{
- /* Check if the engine is no longer running */
- vg_mutex_lock( &vg.mux_engine_status );
- if( !vg.engine_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_SYNC_LOG( "[%d] Engine is no longer running\n", id );
- vg_mutex_unlock( &vg.mux_engine_status );
- return 0;
+ vg_semaphore_post( &vg.sem_loader );
}
- vg_mutex_unlock( &vg.mux_engine_status );
+ VG_SYNC_LOG( "[%d] about to kill\n");
+ vg_thread_exit();
+ }
+ vg_mutex_unlock( &vg.mux_engine_status );
+}
- vg_mutex_lock( &vg.mux_context );
- VG_SYNC_LOG( "[%d] Signal to sync.\n", id );
- vg.exec_context = id;
- vg_mutex_unlock( &vg.mux_context );
-
- /* wait until told we can go */
- VG_SYNC_LOG( "[%d] Waiting to acuire sync.\n", id );
- vg_semaphore_wait( &vg.sem_allow_exec );
- glfwMakeContextCurrent( vg.window );
+/*
+ * 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;
- /* context now valid to work in while we hold up main thread */
- VG_SYNC_LOG( "[%d] Context acquired.\n", id );
+ assert( vg_thread_info.purpose == k_thread_purpose_loader );
- return 1;
+ 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.
*/
-static void vg_release_thread_sync( int id )
+static void vg_release_thread_sync(void)
{
- if( id == 0 )
- {
- vg_mutex_lock( &vg.mux_context );
+ if( vg_thread_info.purpose == k_thread_purpose_main )
+ return;
- if( vg.exec_context != 0 )
- {
- VG_SYNC_LOG( "[%d] Allowing content (%d).\n", id, vg.exec_context );
+ assert( vg_thread_info.purpose == k_thread_purpose_loader );
- /* allow operations to go */
- glfwMakeContextCurrent( NULL );
- vg_semaphore_post( &vg.sem_allow_exec );
+ /* signal that we are done */
+ vg_thread_info.gl_context_level --;
- /* wait for operations to complete */
- VG_SYNC_LOG( "[%d] Waiting for content (%d).\n", id, vg.exec_context );
- vg_semaphore_wait( &vg.sem_exec_finished );
-
- /* re-engage main thread */
- VG_SYNC_LOG( "[%d] Re-engaging.\n", id );
- vg.exec_context = 0;
- glfwMakeContextCurrent( vg.window );
- }
-
- vg_mutex_unlock( &vg.mux_context );
- }
- else
+ if( !vg_thread_info.gl_context_level )
{
- /* signal that we are done */
- VG_SYNC_LOG( "[%d] Releasing context.\n", id );
+ VG_SYNC_LOG( "[%d] Releasing context.\n" );
glfwMakeContextCurrent( NULL );
vg_semaphore_post( &vg.sem_exec_finished );
}
}
+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 );
+}
+
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 );
-}
-static void vg_opengl_sync_free(void)
-{
- vg_semaphore_free( &vg.sem_allow_exec );
- vg_semaphore_free( &vg.sem_exec_finished );
- vg_mutex_free( &vg.mux_context );
+ vg_set_thread_name( "[vg] Main" );
+ vg_thread_info.purpose = k_thread_purpose_main;
+ vg_thread_info.gl_context_level = 1;
}
-
-int vg_checkgl( const char *src_info );
+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__) )
static void vg_render(void) VG_GAMELOOP;
static void vg_ui(void) VG_GAMELOOP;
-int vg_checkgl( const char *src_info )
+static void vg_checkgl( const char *src_info )
{
int fail = 0;
fail = 1;
}
- return fail;
+ if( fail )
+ vg_fatal_exit_loop( "OpenGL Error" );
}
-
-
void vg_mouse_callback( GLFWwindow* ptrW, double xpos, double ypos )
{
vg_mouse[0] = xpos;
static int vg_bake_shaders(void)
{
- if( vg_acquire_thread_sync(1) )
- {
- if( !vg_shaders_recompile() )
- {
- vg_shaders_free(NULL);
- vg_release_thread_sync(1);
- return 0;
- }
- else
- {
- vg_release_thread_sync(1);
+ vg_acquire_thread_sync();
- if( !vg_loader_highwater( vg_shaders_free, NULL ) ) return 0;
- else return 1;
- }
+ 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;
}
-
- return 0;
}
-int vg_preload(void);
-int vg_load(void);
-static int vg_load_full(void)
+void vg_preload(void);
+void vg_load(void);
+static void vg_load_full(void)
{
- if( !vg_preload() ) return 0;
+ vg_preload();
/* internal */
- if( !vg_gamepad_init() ) return 0;
- if( !vg_loader_highwater( NULL, NULL ) ) return 0;
-
- if( !vg_lines_init() ) return 0;
- if( !vg_loader_highwater( vg_lines_free, NULL ) ) return 0;
-
- if( !vg_audio_init() ) return 0;
- if( !vg_loader_highwater( vg_audio_free, NULL ) ) return 0;
+ 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 */
- if( !vg_load() ) return 0;
+ vg_load();
- return 1;
+ vg_acquire_thread_sync();
+ vg.is_loaded = 1;
+ vg_release_thread_sync();
}
static void vg_enter( int argc, char *argv[], const char *window_name )
goto il_exit_loader;
vg_mutex_init( &vg.mux_engine_status );
- vg.engine_running = 1;
+ vg.engine_status = k_engine_status_running;
vg_opengl_sync_init();
vg_loader_start();
int loaded = 0;
-
+ int counter =0;
while(1)
{
- vg_acquire_thread_sync( 0 );
-
if( glfwWindowShouldClose( vg.window ) )
- {
break;
- }
v2_copy( (v2f){ 0.0f, 0.0f }, vg_mouse_wheel );
glfwPollEvents();
vg_time = glfwGetTime();
vg_time_delta = vg_minf( vg_time - vg_time_last, 0.1f );
- enum loader_status load_status = vg_loader_status();
-
- if( load_status == k_loader_status_complete )
+ 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 );
}
else
{
- if( load_status == k_loader_status_fail )
- {
- break;
- }
- else
- {
- vg_loader_render();
- }
+ 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
+
if( loaded )
{
vg_render();
}
}
-
-
-
glfwSwapBuffers( vg.window );
-
- if( VG_CHECK_GL_ERR() )
- break;
-
- vg_release_thread_sync( 0 );
+ vg_run_synced_content();
}
vg_console_write_persistent();
vg_mutex_lock( &vg.mux_engine_status );
- vg.engine_running = 0;
+ vg.engine_status = k_engine_status_none;
vg_mutex_unlock( &vg.mux_engine_status );
-
vg_loader_free();
- vg_opengl_sync_free();
-
- vg_mutex_free( &vg.mux_engine_status );
il_exit_loader:
ui_default_free();
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.
+ */
+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();
+
+ vg_time = glfwGetTime();
+ vg_time_delta = vg_minf( vg_time - vg_time_last, 0.1f );
+
+ glClearColor( sinf(vg_time*20.0)*0.5f+0.5f, 0.0f, 0.0f,1.0f );
+ glClear( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT );
+
+ glfwSwapBuffers( vg.window );
+ }
+
+ /* Can now shutdown and EXIT */
+ vg_loader_free();
+ ui_default_free();
+
+ glfwTerminate();
+ exit(0);
+ }
+}
+
#endif
/*
#pragma GCC optimize ("O3")
#endif
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+
#define STB_VORBIS_MAX_CHANNELS 2
#include "stb/stb_vorbis.h"
+#pragma GCC diagnostic pop
+
#ifdef __GNUC__
#pragma GCC pop_options
#endif
{
u32 new_current = vg_audio.mem_current + size;
if( new_current > vg_audio.mem_total )
- {
- vg_error( "audio pool over budget!\n" );
- free( vg_audio.mem );
- return NULL;
- }
+ vg_fatal_exit_loop( "Audio pool ran out of memory" );
void *ptr = vg_audio.mem + vg_audio.mem_current;
vg_audio.mem_current = new_current;
static void audio_mixer_callback( ma_device *pDevice, void *pOutBuf,
const void *pInput, ma_uint32 frameCount );
-static int vg_audio_init(void)
+static void vg_audio_init(void)
{
vg_mutex_init( &vg_audio.mux_checker );
vg_mutex_init( &vg_audio.mux_sync );
u32 decode_region = AUDIO_DECODE_SIZE * SFX_MAX_SYSTEMS;
vg_audio.mem_total = 1024*1024*32;
vg_audio.mem_current = 0;
- vg_audio.mem = malloc( vg_audio.mem_total + decode_region );
+ vg_audio.mem = vg_alloc( vg_audio.mem_total + decode_region );
vg_audio.decode_mem = &((u8 *)vg_audio.mem)[vg_audio.mem_total];
/* setup pool */
if( ma_device_init( NULL, dconf, device) != MA_SUCCESS )
{
- vg_error( "ma_device failed to initialize" );
- return 0;
+ vg_fatal_exit_loop( "(audio) ma_device failed to initialize" );
}
else
{
if( ma_device_start( device ) != MA_SUCCESS )
{
ma_device_uninit( device );
- vg_error( "ma_device failed to start" );
- return 0;
+ vg_fatal_exit_loop( "(audio) ma_device failed to start" );
}
}
vg_success( "Ready\n" );
- return 1;
}
static void vg_audio_free(void * nothing)
ma_device *device = &vg_audio.miniaudio_device;
ma_device_uninit( device );
- free( vg_audio.mem );
-
- vg_mutex_free( &vg_audio.mux_checker );
- vg_mutex_free( &vg_audio.mux_sync );
+ vg_free( vg_audio.mem );
+ vg_audio.mem = NULL;
}
/*
if( player->init )
return;
- vg_error( "Must init before playing! (%s)\n", player->name );
- abort();
+ vg_fatal_exit_loop( "Must init audio player before playing! \n" );
+}
+
+static void audio_require_clip_loaded( audio_clip *clip )
+{
+ if( clip->data )
+ return;
+
+ vg_fatal_exit_loop( "Must load audio clip before playing! \n" );
}
/* Play a clip using player. If its already playing something, it will
{
audio_require_lock();
audio_require_init( player );
+ audio_require_clip_loaded( clip );
player->info.source = clip;
audio_player_commit( player );
static void audio_play_oneshot( audio_clip *clip, float volume )
{
audio_require_lock();
+ audio_require_clip_loaded( clip );
if( vg_audio.queue_len >= vg_list_size( vg_audio.entity_queue ) )
{
#include "vg/vg_ui.h"
#include "vg/vg_log.h"
-
struct vg_console
{
struct vg_convar
const char *name;
}
*functions;
+
+ u32 convar_count, convar_cap,
+ function_count, function_cap;
char input[96];
int cursor_user, cursor_pos, string_length;
static void vg_convar_push( struct vg_convar cv )
{
- arrpush( vg_console.convars, cv );
+ vg_info( "Console variable '%s' registered\n", cv.name );
+ vg_console.convars = buffer_reserve( vg_console.convars,
+ vg_console.convar_count,
+ &vg_console.convar_cap, 1,
+ sizeof( struct vg_convar ) );
+
+ vg_console.convars[ vg_console.convar_count ++ ] = cv;
}
static void vg_function_push( struct vg_cmd cmd )
{
- arrpush( vg_console.functions, cmd );
+ vg_info( "Console command '%s' registered\n", cmd.name );
+ vg_console.functions = buffer_reserve( vg_console.functions,
+ vg_console.function_count,
+ &vg_console.function_cap, 1,
+ sizeof( struct vg_cmd ) );
+
+ vg_console.functions[ vg_console.function_count ++ ] = cmd;
}
static void vg_console_draw( void )
static int vg_console_list( int argc, char const *argv[] )
{
- for( int i = 0; i < arrlen( vg_console.functions ); i ++ )
+ for( int i=0; i<vg_console.function_count; i ++ )
{
struct vg_cmd *cmd = &vg_console.functions[ i ];
vg_info( "* %s\n", cmd->name );
vg_info( "* snowsound\n" );
- for( int i = 0; i < arrlen( vg_console.convars ); i ++ )
+ for( int i=0; i<vg_console.convar_count; i ++ )
{
struct vg_convar *cv = &vg_console.convars[ i ];
vg_info( "%s\n", cv->name );
return 0;
}
+static int _test_break( int argc, const char *argv[] )
+{
+ vg_fatal_exit_loop( "Test crash from main, after loading (console)" );
+ return 0;
+}
+
static void vg_console_init(void)
{
vg_convar_push( (struct vg_convar)
.name = "chartest",
.function = vg_console_chartest
});
+
+ vg_function_push( (struct vg_cmd)
+ {
+ .name = "crash",
+ .function = _test_break
+ });
}
static void vg_console_load_autos(void)
{
FILE *fp = fopen( "cfg/auto.conf", "w" );
- for( int i = 0; i < arrlen( vg_console.convars ); i ++ )
+ for( int i=0; i<vg_console.convar_count; i ++ )
{
struct vg_convar *cv = &vg_console.convars[i];
{
vg_console_write_persistent();
- arrfree( vg_console.convars );
- arrfree( vg_console.functions );
+ vg_free( vg_console.convars );
+ vg_free( vg_console.functions );
}
static void execute_console_input( const char *cmd )
int data_int;
float data_float;
- for( int i = 0; i < arrlen( vg_console.convars ); i ++ )
+ for( int i=0; i<vg_console.convar_count; i ++ )
{
struct vg_convar *cv = &vg_console.convars[ i ];
if( !strcmp( cv->name, args[0] ) )
/*
* Find and excecute command
*/
- for( int i = 0; i < arrlen( vg_console.functions ); i ++ )
+ for( int i=0; i<vg_console.function_count; i ++ )
{
struct vg_cmd *cmd = &vg_console.functions[ i ];
if( !strcmp( cmd->name, args[0] ) )
strcpy( buf, vg_console.history[ pick ] );
}
+/* Receed secondary cursor */
+static void _console_left_select(void)
+{
+ console_move_cursor( &vg_console.cursor_user, NULL, -1, 0 );
+}
+
+/* Match and receed both cursors */
+static void _console_left(void)
+{
+ int cursor_diff = vg_console.cursor_pos - vg_console.cursor_user? 0: 1;
+
+ console_move_cursor( &vg_console.cursor_user,
+ &vg_console.cursor_pos, -cursor_diff, 1 );
+}
+
+static void _console_right_select(void)
+{
+ console_move_cursor( &vg_console.cursor_user, NULL, 1, 0 );
+}
+
+static void _console_right(void)
+{
+ int cursor_diff = vg_console.cursor_pos - vg_console.cursor_user? 0: 1;
+
+ console_move_cursor( &vg_console.cursor_user,
+ &vg_console.cursor_pos, +cursor_diff, 1 );
+}
+
+static void _console_down(void)
+{
+ vg_console.history_pos = VG_MAX( 0, vg_console.history_pos-1 );
+ console_history_get( vg_console.input, vg_console.history_pos );
+
+ console_move_cursor( &vg_console.cursor_user,
+ &vg_console.cursor_pos,
+ vg_list_size( vg_console.input ), 1 );
+}
+
+static void _console_up(void)
+{
+ vg_console.history_pos = VG_MAX
+ (
+ 0,
+ VG_MIN
+ (
+ vg_console.history_pos+1,
+ VG_MIN
+ (
+ vg_list_size( vg_console.history ),
+ vg_console.history_count - 1
+ )
+ )
+ );
+
+ console_history_get( vg_console.input, vg_console.history_pos );
+ console_move_cursor( &vg_console.cursor_user,
+ &vg_console.cursor_pos,
+ vg_list_size( vg_console.input ), 1);
+}
+
+static void _console_backspace(void)
+{
+ vg_console.cursor_user = console_delete_char( -1 );
+ vg_console.cursor_pos = vg_console.cursor_user;
+}
+
+static void _console_delete(void)
+{
+ vg_console.cursor_user = console_delete_char( 1 );
+ vg_console.cursor_pos = vg_console.cursor_user;
+}
+
+static void _console_home_select(void)
+{
+ console_move_cursor( &vg_console.cursor_user, NULL, -10000, 0 );
+}
+
+static void _console_home(void)
+{
+ console_move_cursor( &vg_console.cursor_user,
+ &vg_console.cursor_pos, -10000, 1 );
+}
+
+static void _console_end_select(void)
+{
+ console_move_cursor( &vg_console.cursor_user, NULL, 10000, 0 );
+}
+
+static void _console_end(void)
+{
+ console_move_cursor( &vg_console.cursor_user,
+ &vg_console.cursor_pos,
+ vg_list_size( vg_console.input ), 1 );
+}
+
+static void _console_select_all(void)
+{
+ console_move_cursor( &vg_console.cursor_user, NULL, 10000, 0);
+ console_move_cursor( &vg_console.cursor_pos, NULL, -10000, 0);
+}
+
+static void _console_cut(void)
+{
+ console_to_clipboard();
+ vg_console.cursor_user = console_delete_char(0);
+ vg_console.cursor_pos = vg_console.cursor_user;
+}
+
+static void _console_enter(void)
+{
+ if( !strlen( vg_console.input ) )
+ return;
+
+ vg_info( "%s\n", vg_console.input );
+
+ if( strcmp( vg_console.input,
+ vg_console.history[ vg_console.history_last ]) )
+ {
+ vg_console.history_last = ( vg_console.history_last + 1) %
+ vg_list_size(vg_console.history );
+ vg_console.history_count =
+ VG_MIN( vg_list_size( vg_console.history ),
+ vg_console.history_count + 1 );
+ strcpy( vg_console.history[ vg_console.history_last ],
+ vg_console.input );
+ }
+
+ vg_console.history_pos = -1;
+ execute_console_input( vg_console.input );
+ console_move_cursor( &vg_console.cursor_user,
+ &vg_console.cursor_pos, -10000, 1 );
+ vg_console.input[0] = '\0';
+}
+
static void console_proc_key( GLFWwindow* ptrW, int key, int scancode,
- int action, int mods )
+ int action, int mods )
{
- if( action )
- {
- int cursor_diff = vg_console.cursor_pos - vg_console.cursor_user? 0: 1;
+ if( !action )
+ return;
- if( key == GLFW_KEY_GRAVE_ACCENT )
- {
- vg_console.enabled = !vg_console.enabled;
- return;
- }
-
- if( !vg_console.enabled )
- return;
-
- if( key == GLFW_KEY_LEFT )
- {
- if( mods & GLFW_MOD_SHIFT ) /* Receed secondary cursor */
- {
- console_move_cursor( &vg_console.cursor_user, NULL, -1, 0 );
- }
- else /* Match and receed both cursors */
- {
- console_move_cursor( &vg_console.cursor_user,
- &vg_console.cursor_pos, -cursor_diff, 1 );
- }
- }
- else if( key == GLFW_KEY_RIGHT ) /* Advance secondary cursor */
- {
- if( mods & GLFW_MOD_SHIFT )
- {
- console_move_cursor( &vg_console.cursor_user, NULL, 1, 0 );
- }
- else /* Match and advance both cursors */
- {
- console_move_cursor( &vg_console.cursor_user,
- &vg_console.cursor_pos, +cursor_diff, 1 );
- }
- }
- else if( key == GLFW_KEY_DOWN )
- {
- if( mods & GLFW_MOD_SHIFT ){}
- else
- {
- vg_console.history_pos = VG_MAX( 0, vg_console.history_pos-1 );
- console_history_get( vg_console.input, vg_console.history_pos );
- console_move_cursor( &vg_console.cursor_user,
- &vg_console.cursor_pos, vg_list_size( vg_console.input ), 1 );
- }
- }
- else if( key == GLFW_KEY_UP )
- {
- if( mods & GLFW_MOD_SHIFT ){}
- else
- {
- vg_console.history_pos = VG_MAX
- (
- 0,
- VG_MIN
- (
- vg_console.history_pos+1,
- VG_MIN
- (
- vg_list_size( vg_console.history ),
- vg_console.history_count - 1
- )
- )
- );
-
- console_history_get( vg_console.input, vg_console.history_pos );
- console_move_cursor( &vg_console.cursor_user,
- &vg_console.cursor_pos,
- vg_list_size( vg_console.input ), 1);
- }
- }
- else if( key == GLFW_KEY_BACKSPACE ) /* Lookback delete */
- {
- vg_console.cursor_user = console_delete_char( -1 );
- vg_console.cursor_pos = vg_console.cursor_user;
- }
- else if( key == GLFW_KEY_DELETE ) /* Lookforward delete */
- {
- vg_console.cursor_user = console_delete_char( 1 );
- vg_console.cursor_pos = vg_console.cursor_user;
- }
- else if( key == GLFW_KEY_HOME ) /* Home key */
- {
- if( mods & GLFW_MOD_SHIFT )
- console_move_cursor( &vg_console.cursor_user, NULL, -10000, 0 );
- else
- console_move_cursor( &vg_console.cursor_user,
- &vg_console.cursor_pos, -10000, 1 );
- }
- else if( key == GLFW_KEY_END ) /* End key */
- {
- if( mods & GLFW_MOD_SHIFT )
- console_move_cursor( &vg_console.cursor_user, NULL, 10000, 0 );
- else
- console_move_cursor( &vg_console.cursor_user,
- &vg_console.cursor_pos,
- vg_list_size( vg_console.input ), 1 );
- }
- else if( key == GLFW_KEY_A )
- {
- if( mods & GLFW_MOD_CONTROL ) /* Select all */
- {
- console_move_cursor( &vg_console.cursor_user, NULL, 10000, 0);
- console_move_cursor( &vg_console.cursor_pos, NULL, -10000, 0);
- }
- }
- else if( key == GLFW_KEY_C ) /* Copy */
- {
- if( mods & GLFW_MOD_CONTROL )
- {
- console_to_clipboard();
- }
- }
- else if( key == GLFW_KEY_X ) /* Cut */
- {
- if( mods & GLFW_MOD_CONTROL )
- {
- console_to_clipboard();
- vg_console.cursor_user = console_delete_char(0);
- vg_console.cursor_pos = vg_console.cursor_user;
- }
- }
- else if( key == GLFW_KEY_V ) /* Paste */
- {
- if( mods & GLFW_MOD_CONTROL )
- {
- console_clipboard_paste();
- }
- }
- else if( key == GLFW_KEY_ENTER )
- {
- if( !strlen( vg_console.input ) )
- return;
-
- vg_info( "%s\n", vg_console.input );
-
- if( strcmp( vg_console.input,
- vg_console.history[ vg_console.history_last ]) )
- {
- vg_console.history_last = ( vg_console.history_last + 1) %
- vg_list_size(vg_console.history );
- vg_console.history_count =
- VG_MIN( vg_list_size( vg_console.history ),
- vg_console.history_count + 1 );
- strcpy( vg_console.history[ vg_console.history_last ],
- vg_console.input );
- }
-
- vg_console.history_pos = -1;
- execute_console_input( vg_console.input );
- console_move_cursor( &vg_console.cursor_user,
- &vg_console.cursor_pos, -10000, 1 );
- vg_console.input[0] = '\0';
- }
- }
+ /* Open / close console */
+ if( key == GLFW_KEY_GRAVE_ACCENT )
+ vg_console.enabled = !vg_console.enabled;
+
+ if( !vg_console.enabled ) return;
+
+ struct console_mapping
+ {
+ u32 mod, key;
+ void (*handler)(void);
+ }
+ mapping[] =
+ {
+ { 0, GLFW_KEY_LEFT, _console_left },
+ { GLFW_MOD_SHIFT, GLFW_KEY_LEFT, _console_left_select },
+ { 0, GLFW_KEY_RIGHT, _console_right },
+ { GLFW_MOD_SHIFT, GLFW_KEY_RIGHT, _console_right_select },
+ { 0, GLFW_KEY_DOWN, _console_down },
+ { 0, GLFW_KEY_UP, _console_up },
+ { 0, GLFW_KEY_BACKSPACE, _console_backspace },
+ { 0, GLFW_KEY_DELETE, _console_delete },
+ { 0, GLFW_KEY_HOME, _console_home },
+ { GLFW_MOD_SHIFT, GLFW_KEY_HOME, _console_home_select },
+ { 0, GLFW_KEY_END, _console_end },
+ { GLFW_MOD_SHIFT, GLFW_KEY_END, _console_end_select },
+ { GLFW_MOD_CONTROL, GLFW_KEY_A, _console_select_all },
+ { GLFW_MOD_CONTROL, GLFW_KEY_C, console_to_clipboard },
+ { GLFW_MOD_CONTROL, GLFW_KEY_X, _console_cut },
+ { GLFW_MOD_CONTROL, GLFW_KEY_V, console_clipboard_paste },
+ { 0, GLFW_KEY_ENTER, _console_enter }
+ };
+
+ for( int i=0; i<vg_list_size( mapping ); i++ )
+ {
+ struct console_mapping *mk = &mapping[i];
+
+ if( mk->key == key )
+ {
+ if( mk->mod == 0 )
+ {
+ if( mods == 0 )
+ {
+ mk->handler();
+ return;
+ }
+ }
+ else if( (mods & mk->mod) == mk->mod )
+ {
+ mk->handler();
+ return;
+ }
+ }
+ }
}
/* Handle an OS based input of UTF32 character from the keyboard or such */
}
}
-static int vg_gamepad_init(void)
+static void vg_gamepad_init(void)
{
- if( vg_acquire_thread_sync(1) )
+ vg_acquire_thread_sync();
+
+ for( int id=0; id<=GLFW_JOYSTICK_LAST; id ++ )
{
- for( int id=0; id<=GLFW_JOYSTICK_LAST; id ++ )
+ if( glfwJoystickPresent( id ) )
{
- if( glfwJoystickPresent( id ) )
- {
- vg_info( "Joystick found: '%s'\n", glfwGetJoystickName(id) );
- }
-
- if( glfwJoystickIsGamepad( id ) )
- {
- vg.gamepad_name = glfwGetGamepadName( id );
- vg_success( "Gamepad mapping registered: %s\n", vg.gamepad_name );
-
- vg.gamepad_ready = 1;
- vg.gamepad_id = id;
- break;
- }
+ vg_info( "Joystick found: '%s'\n", glfwGetJoystickName(id) );
}
- vg_release_thread_sync(1);
- return 1;
+ if( glfwJoystickIsGamepad( id ) )
+ {
+ vg.gamepad_name = glfwGetGamepadName( id );
+ vg_success( "Gamepad mapping registered: %s\n", vg.gamepad_name );
+
+ vg.gamepad_ready = 1;
+ vg.gamepad_id = id;
+ break;
+ }
}
- return 0;
+ vg_release_thread_sync();
}
#endif
if( f )
{
i64 fsize = vg_file_size( f );
- void *buf = malloc( fsize + reserve_end );
+ void *buf = vg_alloc( fsize + reserve_end );
- if( buf )
- {
- /* Invalid / corrupt read */
- if( fread( buf, 1, fsize, f ) != fsize )
- {
- free( buf );
- buf = NULL;
- }
- }
+ /* Invalid / corrupt read */
+ if( fread( buf, 1, fsize, f ) != fsize )
+ {
+ vg_free( buf );
+ buf = NULL;
+ }
*size = fsize;
}
vg_lines;
-static int vg_lines_init(void)
+static void vg_lines_init(void)
{
vg_info( "vg_lines_init\n" );
});
vg_shader_register( &_shader_lines );
-
- if( vg_acquire_thread_sync(1) )
+ vg_acquire_thread_sync();
{
glGenVertexArrays( 1, &vg_lines.vao );
glGenBuffers( 1, &vg_lines.vbo );
glBufferData( GL_ARRAY_BUFFER, vg_lines.buffer_size,
NULL, GL_DYNAMIC_DRAW );
glBindVertexArray( vg_lines.vao );
-
- if( VG_CHECK_GL_ERR() )
- {
- vg_release_thread_sync(1);
- vg_error( "Failed\n" );
- }
+ VG_CHECK_GL_ERR();
/* Pointers */
glVertexAttribPointer(
);
glEnableVertexAttribArray( 1 );
- if( VG_CHECK_GL_ERR() )
- goto il_delete_buffers_and_fail;
+ VG_CHECK_GL_ERR();
/* Alloc RAM */
- vg_lines.buffer = malloc( vg_lines.buffer_size );
- if( vg_lines.buffer )
- {
- vg_success( "done\n" );
- vg_release_thread_sync(1);
- return 1;
- }
-
-il_delete_buffers_and_fail:
- glDeleteBuffers( 1, &vg_lines.vbo );
- glDeleteVertexArrays( 1, &vg_lines.vao );
- vg_release_thread_sync(1);
- return 0;
+ vg_lines.buffer = vg_alloc( vg_lines.buffer_size );
+ vg_success( "done\n" );
}
- return 0;
+ vg_release_thread_sync();
}
static void vg_lines_free(void *nothing)
{
glDeleteVertexArrays( 1, &vg_lines.vao );
glDeleteBuffers( 1, &vg_lines.vbo );
- free( vg_lines.buffer );
+ vg_free( vg_lines.buffer );
}
static void vg_lines_drawall( float* projection )
static struct vg_loader
{
- /* Synchronization */
- vg_semaphore sem_loading;
- vg_mutex mux_status;
-
- enum loader_status
- {
- k_loader_status_loading,
- k_loader_status_complete,
- k_loader_status_fail
- }
- status;
-
/* Shutdown steps */
struct loader_free_step
{
static int vg_loader_init(void)
{
- vg_semaphore_init( &vg_loader.sem_loading, 0 );
- vg_mutex_init( &vg_loader.mux_status );
return 1;
}
static void vg_loader_free(void)
{
- vg_semaphore_wait( &vg_loader.sem_loading );
- vg_semaphore_free( &vg_loader.sem_loading );
- vg_mutex_free( &vg_loader.mux_status );
+ vg_info( "vg_loader_free\n" );
for( int i=0; i<vg_loader.step_count; i++ )
{
struct loader_free_step *step =
&vg_loader.step_buffer[vg_loader.step_count -1 -i];
+ vg_info( " -> %p\n", step->fn_free );
step->fn_free( step->data );
}
- free( vg_loader.step_buffer );
-}
-
-static enum loader_status vg_loader_status(void)
-{
- enum loader_status answer;
-
- vg_mutex_lock( &vg_loader.mux_status );
- answer = vg_loader.status;
- vg_mutex_unlock( &vg_loader.mux_status );
-
- return answer;
+ vg_free( vg_loader.step_buffer );
+ vg_info( "done\n" );
}
static float hue_to_rgb( float p, float q, float t )
static void vg_loader_render(void)
{
- float h = vg_fractf(vg_time*0.1),
- s = 0.2f,
+ float h = vg_randf(),
+ s = 0.7f,
l = 0.1f, //* (0.5f+vg_fractf(vg_time*40.0)*0.5f),
q = l < 0.5f ? l * (1.0f + s) : l + s - l * s,
p = 2.0f * l - q,
}
-static int vg_load_full(void);
+static void vg_load_full(void);
static void vg_loader_thread(void * nothing)
{
- /* Run client loader */
- int res = vg_load_full();
-
- /* Propogate status */
- vg_mutex_lock( &vg_loader.mux_status );
- if( res )
- {
- vg_loader.status = k_loader_status_complete;
- }
- else
- {
- vg_loader.status = k_loader_status_fail;
- }
- vg_mutex_unlock( &vg_loader.mux_status );
+ vg_thread_info.gl_context_level = 0;
+ vg_thread_info.purpose = k_thread_purpose_loader;
+ vg_set_thread_name( "[vg] Loader" );
- vg_semaphore_post( &vg_loader.sem_loading );
+ /* Run client loader */
+ vg_load_full();
+ vg_semaphore_post( &vg.sem_loader );
}
static void vg_loader_start(void)
{
+ vg_semaphore_wait( &vg.sem_loader );
vg_thread_run( vg_loader_thread, NULL );
}
static void vg_free_libc_malloced( void *data )
{
- free( data );
+ vg_free( data );
}
-static int vg_loader_push_free_step( struct loader_free_step step )
+static void vg_loader_push_free_step( struct loader_free_step step )
{
- void *buf = buffer_reserve( vg_loader.step_buffer, vg_loader.step_count,
+ vg_loader.step_buffer =
+ buffer_reserve( vg_loader.step_buffer, vg_loader.step_count,
&vg_loader.step_cap, 1,
sizeof( struct loader_free_step ) );
- if( !buf )
- return 0;
-
- vg_loader.step_buffer = buf;
vg_loader.step_buffer[ vg_loader.step_count ++ ] = step;
- return 1;
}
+
/*
- * Schedule something to be freed
+ * Schedule something to be ran now, freed later
*/
-__attribute__((warn_unused_result))
-static int vg_loader_highwater( void( *fn_free )(void *), void *data )
+static void vg_loader_highwater( void( *fn_load )(void),
+ void( *fn_free )(void *), void *data )
{
+ if( fn_load )
+ fn_load();
+
if( fn_free )
{
struct loader_free_step step;
step.data = data;
step.fn_free = fn_free;
- if( !vg_loader_push_free_step( step ) )
- return 0;
+ vg_loader_push_free_step( step );
}
else
{
step.data = data;
step.fn_free = vg_free_libc_malloced;
- if( !vg_loader_push_free_step( step ) )
- return 0;
+ vg_loader_push_free_step( step );
}
}
- vg_mutex_lock( &vg.mux_engine_status );
-
- if( !vg.engine_running )
- {
- vg_mutex_unlock( &vg.mux_engine_status );
- return 0;
- }
-
- vg_mutex_unlock( &vg.mux_engine_status );
- return 1;
+ vg_ensure_engine_running();
}
#endif /* VG_LOADER_H */
-
-#if 0
-#ifndef LOADER_H
-#define LOADER_H
-
-#include "common.h"
-
-static struct loader
-{
- MUTEX_TYPE mux;
-
- struct loader_step
- {
- int (*fn_load)(void);
- void (*fn_free)(void);
-
- int require_opengl;
- const char *name;
- }
- *step_buffer;
- u32 step_count, step_cap, step_action,
- low_water_mark; /* What is the minumum number of systems we can have? */
-
- enum loader_status
- {
- k_loader_status_loading,
- k_loader_status_complete,
- k_loader_status_fail
- }
- status;
-
- int cancel;
-}
-loader;
-
-static void loader_add_stage( struct loader_step step )
-{
- loader.step_buffer = buffer_reserve( loader.step_buffer, loader.step_count,
- &loader.step_cap,
- 1, sizeof( struct loader_step ) );
-
- loader.step_buffer[ loader.step_count ++ ] = step;
-}
-
-static void loader_insert_stage( struct loader_step step )
-{
-
-}
-
-static void loader_cancel(void)
-{
- MUTEX_LOCK( loader.mux );
- loader.cancel = 1;
- MUTEX_UNLOCK( loader.mux );
-}
-
-static void loader_worker_thread( void *nothing )
-{
- while(1)
- {
- vg_sleep_ms( 1000.0 );
- vg_info( "... loader ....\n" );
-
- if( loader.cancel )
- {
- return;
- }
- }
-}
-
-static void loader_begin(void)
-{
- if( loader.step_count == 0 )
- {
- loader.status = k_loader_status_complete;
- return;
- }
-
- loader.status = k_loader_status_loading;
- vg_thread_run( loader_worker_thread, NULL );
-}
-
-static void loader_free(void)
-{
- /* TODO */
- for( int i=0; i<loader.step_count; i++ )
- {
- struct loader_step *step = &loader.step_buffer[ loader.step_count -i -1 ];
- if( step->fn_free )
- step->fn_free();
- }
-}
-
-/*
- * Returns 0 if loading is not happening
- * Returns 1 if we are loading something
- */
-static int loader_update(void)
-{
- MUTEX_LOCK( loader.mux );
-
- if( loader.status == k_loader_status_complete )
- {
- MUTEX_UNLOCK( loader.mux );
- return 0;
- }
- else
- {
- struct loader_step *cstep = &loader.step_buffer[ loader.step_action ];
-
- if( cstep->require_opengl )
- {
- if( !cstep->fn_load() )
- {
- loader.cancel = 1;
- MUTEX_UNLOCK( loader.mux );
-
- loader_free();
- vg_exit();
- }
-
- loader.step_action ++;
- }
-
- MUTEX_UNLOCK( loader.mux );
- return 1;
- }
-}
-
-#endif /* LOADER_H */
-#endif
return rand()%max;
}
+static void eval_bezier_time( v3f p0, v3f p1, v3f h0, v3f h1, float t, v3f p )
+{
+ float tt = t*t,
+ ttt = tt*t;
+
+ v3_muls( p1, ttt, p );
+ v3_muladds( p, h1, 3.0f*tt -3.0f*ttt, p );
+ v3_muladds( p, h0, 3.0f*ttt -6.0f*tt +3.0f*t, p );
+ v3_muladds( p, p0, 3.0f*tt -ttt -3.0f*t +1.0f, p );
+}
+
#endif /* VG_M_H */
--- /dev/null
+#ifndef VG_MODULE_H
+#define VG_MODULE_H
+
+#include "vg_shader.h"
+
+struct vg_module
+{
+ const char *name;
+
+ struct
+ {
+ struct vg_shader *shaders;
+ u32 shader_count;
+
+ vg_tex2d *textures;
+ u32 texture_count;
+ }
+ resources;
+
+ int (*fn_load)(void);
+ void (*fn_free)(void);
+};
+
+static int vg_module_load( struct vg_module *m )
+{
+
+}
+
+#endif /* VG_MODULE_H */
#define VG_PLATFORM_H
#include "vg.h"
+#include "vg_stdint.h"
/* Copyright (C) 2021-2022 Harry Godden (hgn) - All Rights Reserved */
#define vg_static_assert _Static_assert
#define vg_list_size( A ) (sizeof(A)/sizeof(A[0]))
+#define VG_MUST_USE_RESULT __attribute__((warn_unused_result))
#ifdef _WIN32
#include <windows.h>
/* TODO */
+#define VG_DEPRECATED __declspec(deprecated)
#else
#include <pthread.h>
#include <semaphore.h>
+#define VG_DEPRECATED __attribute__((deprecated))
+
+ #define VG_THREAD_LOCAL __thread
+
typedef sem_t vg_semaphore;
typedef pthread_mutex_t vg_mutex;
+#endif
+
+#include <stdlib.h>
+
+/* TODO: If there is no graphics, we dont need to do an exit loop */
+
+static void vg_fatal_exit_loop( const char *error );
+static void *vg_alloc( size_t size )
+{
+ void *ptr = malloc( size );
+
+ if( !ptr )
+ vg_fatal_exit_loop( "Out of memory" );
+
+ return ptr;
+}
+
+static void *vg_realloc( void *orig, size_t size )
+{
+ void *ptr = realloc( orig, size );
+
+ if( !ptr )
+ vg_fatal_exit_loop( "Out of memory" );
+
+ return ptr;
+}
+
+/* seems to be a GCC bug when inlining this, its low priority anyway */
+__attribute__ ((noinline))
+static void vg_free( void *ptr )
+{
+ free( ptr );
+}
+
+static void vg_required( void *ptr, const char *path )
+{
+ if( !ptr )
+ {
+ vg_fatal_exit_loop( path );
+ }
+}
+
+#define VG_REQUIRED_ASSET( TYPE, DECL, FN, PATH, ... ) \
+ TYPE DECL = FN( PATH,##__VA_ARGS__ ); \
+ vg_required( DECL, "Resource is required but failed to load: '" PATH "'" );
+
+VG_DEPRECATED
+void *malloc( size_t size );
+
+VG_DEPRECATED
+void *realloc( void *orig, size_t size );
+
+VG_DEPRECATED
+void free( void *ptr );
+
+#include <stdio.h>
+#include <dirent.h>
+#include <string.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <math.h>
+#include <assert.h>
+
+#ifdef _WIN32
+#else
+
+static void vg_thread_exit(void)
+{
+ pthread_exit(NULL);
+}
+
+static void vg_set_thread_name( const char *name )
+{
+ /* not defined but links?? */
+#if 0
+ pthread_setname_np(pthread_self());
+#endif
+}
+
static int vg_semaphore_init( vg_semaphore *sem, u32 value )
{
- if( !sem_init( sem, 0, value ) )
- return 1;
- else
- return 0;
+ return !sem_init( sem, 0, value );
+}
+
+static int vg_semaphore_trywait( vg_semaphore *sem )
+{
+ return !sem_trywait( sem );
}
static int vg_semaphore_wait( vg_semaphore *sem )
{
- if( !sem_wait( sem ) )
- return 1;
- else
- return 0;
+ return !sem_wait( sem );
}
static int vg_semaphore_post( vg_semaphore *sem )
{
- if( !sem_post( sem ) )
- return 1;
- else
- return 0;
+ return !sem_post( sem );
}
static void vg_semaphore_free( vg_semaphore *sem )
static void vg_mutex_free( vg_mutex *mutex )
{
-
+
}
#endif
if( count+amount > *cap )
{
*cap = VG_MAX( (*cap)*2, (*cap)+amount );
-
- return realloc( buffer, (*cap) * emsize );
+ return vg_realloc( buffer, (*cap) * emsize );
}
return buffer;
static void *buffer_fix( void *buffer, u32 count, u32 *cap, size_t emsize )
{
*cap = count;
- return realloc( buffer, (*cap) * emsize );
+ return vg_realloc( buffer, (*cap) * emsize );
}
#endif
#define STB_INCLUDE_IMPLEMENTATION
#define STB_INCLUDE_LINE_GLSL
+#define STB_MALLOC vg_alloc
+#define STB_FREE vg_free
+#define STB_REALLOC vg_realloc
#include "stb/stb_include.h"
const char *vg_shader_gl_ver = "#version 330 core\n";
+static
struct vg_shader
{
GLuint id;
int compiled;
}
** vg_shaders_active = NULL;
+static u32 vg_shader_count,
+ vg_shader_cap;
static GLuint vg_shader_subshader( const char *src, GLint gliShaderType )
{
vg_error( "Could not find shader source files (%s)\n",
shader->vs.orig_file );
- free( avs );
- free( afs );
+ vg_free( avs );
+ vg_free( afs );
return 0;
}
if( !static_src )
{
- free( avs );
- free( afs );
+ vg_free( avs );
+ vg_free( afs );
}
if( !vert || !frag )
static void vg_shaders_free(void *nothing)
{
- for( int i = 0; i < arrlen( vg_shaders_active ); i ++ )
+ for( int i=0; i<vg_shader_count; i ++ )
{
struct vg_shader *shader = vg_shaders_active[i];
glDeleteProgram( shader->id );
}
- arrfree( vg_shaders_active );
+ vg_free( vg_shaders_active );
}
static int vg_shaders_recompile(void)
{
vg_info( "Compiling shaders\n" );
- for( int i=0; i<arrlen( vg_shaders_active ); i ++ )
+ for( int i=0; i<vg_shader_count; i ++ )
{
struct vg_shader *shader = vg_shaders_active[i];
{
shader->compiled = 0;
shader->id = 0; /* TODO: make this an error shader */
- arrpush( vg_shaders_active, shader );
+ vg_shaders_active = buffer_reserve( vg_shaders_active, vg_shader_count,
+ &vg_shader_cap, 1,
+ sizeof( struct vg_shader * ) );
+
+ vg_shaders_active[ vg_shader_count ++ ] = shader;
}
#endif /* VG_SHADER_H */
SteamAPICallCompleted_t *pCallCompleted =
(SteamAPICallCompleted_t *)callback.m_pubParam;
- void *pTmpCallResult = malloc( pCallCompleted->m_cubParam );
+ void *pTmpCallResult = vg_alloc( pCallCompleted->m_cubParam );
int bFailed;
if( SteamAPI_ManualDispatch_GetAPICallResult(
#endif
}
- free( pTmpCallResult );
+ vg_free( pTmpCallResult );
}
else
{
#ifndef VG_STEAM_AUTH_H
#define VG_STEAM_AUTH_H
+#include "vg/vg_platform.h"
+
typedef u32 HAuthTicket;
enum{ k_HAuthTicketInvalid = 0 };
if( len < k_nSteamEncryptedAppTicketSymmetricKeyLen )
{
vg_error( "Application key was invalid size\n" );
- free( text_src );
+ vg_free( text_src );
return 0;
}
vg_char_base16( text_src[i*2+1] );
}
- free( text_src );
+ vg_free( text_src );
return 1;
}
else
#define VG_TEXTURE_NEAREST 0x8
#define VG_TEXTURE_ALLOCATED_INTERNAL 0x10
+#define QOI_IMPLEMENTATION
+#define QOI_MALLOC vg_alloc
+#define QOI_FREE vg_free
+
+#include "phoboslab/qoi.h"
+
struct vg_tex2d
{
const char *path;
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, info.width, info.height,
0, GL_RGBA, GL_UNSIGNED_BYTE, tex_buffer );
- free( tex_buffer );
- free( src_data );
+ vg_free( tex_buffer );
+ vg_free( src_data );
}
else
{
static ui_ctx ui_global_ctx;
-static void ui_context_free( ui_ctx *ctx )
+static void ui_context_vg_free( ui_ctx *ctx )
{
glDeleteVertexArrays( 1, &ctx->vao );
glDeleteBuffers( 1, &ctx->vbo );
glDeleteBuffers( 1, &ctx->ebo );
- free( ctx->verts );
- free( ctx->indices );
+ vg_free( ctx->verts );
+ vg_free( ctx->indices );
}
static int ui_init_context( ui_ctx *ctx, int index_buffer_size )
glBufferData( GL_ELEMENT_ARRAY_BUFFER,
index_buffer_size * sizeof( u16 ), NULL, GL_DYNAMIC_DRAW );
- if( VG_CHECK_GL_ERR() )
- goto il_fail_alloc_gpu;
+ VG_CHECK_GL_ERR();
/* Set pointers */
u32 const stride = sizeof( struct ui_vert );
(void *)offsetof( struct ui_vert, clip ) );
glEnableVertexAttribArray( 3 );
- if( VG_CHECK_GL_ERR() )
- goto il_fail_attributes;
-
+ VG_CHECK_GL_ERR();
/* Alloc RAM default context */
- ctx->verts = (struct ui_vert *)malloc(
+ ctx->verts = (struct ui_vert *)vg_alloc(
vertex_buffer_size * sizeof(struct ui_vert) );
if( !ctx->verts )
goto il_fail_alloc_verts;
- ctx->indices = (u16*)malloc( index_buffer_size * sizeof(u16) );
+ ctx->indices = (u16*)vg_alloc( index_buffer_size * sizeof(u16) );
if( !ctx->indices )
goto il_fail_alloc_indices;
return 1;
- free( ctx->indices );
+ vg_free( ctx->indices );
ctx->indices = NULL;
il_fail_alloc_indices:
- free( ctx->verts );
+ vg_free( ctx->verts );
ctx->verts = NULL;
il_fail_alloc_verts:
-il_fail_attributes:
-il_fail_alloc_gpu:
glDeleteBuffers( 1, &ctx->ebo );
glDeleteBuffers( 1, &ctx->vbo );
glDeleteVertexArrays( 1, &ctx->vao );
};
u32 pixels = 0, total = 256*256, data = 0;
- u8 *image = malloc( total );
- if( !image ) goto il_fail_alloc_image;
+ u8 *image = vg_alloc( total );
while( pixels < total )
{
}
glGenTextures( 1, &ui_glyph_texture );
- if( !ui_glyph_texture ) goto il_fail_gen_texture;
-
glBindTexture( GL_TEXTURE_2D, ui_glyph_texture );
glTexImage2D( GL_TEXTURE_2D, 0, GL_R8, 256, 256, 0,
GL_RED, GL_UNSIGNED_BYTE, image );
+
+ vg_free( image );
- if( VG_CHECK_GL_ERR() ) goto il_fail_alloc_gpu;
+ VG_CHECK_GL_ERR();
vg_tex2d_clamp();
vg_tex2d_nearest();
-
- free( image );
if( !ui_init_context( &ui_global_ctx, 20000 ) ) goto il_generic_fail;
if( !vg_shader_compile( &_shader_ui ) ) goto il_shader_fail;
return 1;
il_shader_fail:
-il_fail_alloc_gpu:
il_generic_fail:
glDeleteTextures( 1, &ui_glyph_texture );
-
-il_fail_gen_texture:
- free( image );
-
-il_fail_alloc_image:
+ vg_free( image );
return 0;
}
{
vg_free_shader( &_shader_ui );
glDeleteTextures( 1, &ui_glyph_texture );
- ui_context_free( &ui_global_ctx );
+ ui_context_vg_free( &ui_global_ctx );
}
static struct ui_vert *ui_fill_rect_uv( ui_ctx *ctx, ui_rect rect,