remaining = vg_linear_remaining( vg_async.buffer ),
capacity = vg_linear_get_capacity( vg_async.buffer );
- if( total_allocation > capacity ){
+ if( total_allocation > capacity )
+ {
SDL_AtomicUnlock( &vg_async.sl_index );
- vg_error( "Requested: %umb. Buffer size: %umb\n",
+ vg_fatal_condition();
+ vg_info( "async alloc invalid size\n" );
+ vg_info( "Requested: %umb. Buffer size: %umb\n",
(total_allocation/1024)/1024,
(capacity/1024)/1024 );
-
- vg_fatal_error( "async alloc invalid size\n" );
+ vg_fatal_exit();
}
- if( total_allocation > remaining ){
+ if( total_allocation > remaining )
+ {
SDL_AtomicUnlock( &vg_async.sl_index );
SDL_SemWait( vg_async.sem_wait_for_flush );
SDL_AtomicLock( &vg_async.sl_index );
*/
void vg_async_stall(void)
{
- vg_assert_thread(k_thread_purpose_loader);
+ VG_ASSERT( vg_thread_purpose() == k_thread_purpose_loader );
SDL_SemWait( vg_async.sem_wait_for_flush );
}
void vg_async_dispatch( vg_async_item *item,
void (*runner)( void *payload, u32 size ) )
{
- vg_assert_thread(k_thread_purpose_loader);
+ VG_ASSERT( vg_thread_purpose() == k_thread_purpose_loader );
if( SDL_SemValue(vg_async.sem_wait_for_flush) )
SDL_SemWait(vg_async.sem_wait_for_flush);
void vg_async_call( void (*runner)( void *payload, u32 size ),
void *payload, u32 size )
{
- vg_assert_thread(k_thread_purpose_loader);
+ VG_ASSERT( vg_thread_purpose() == k_thread_purpose_loader );
vg_async_item *call = vg_async_alloc(0);
call->payload = payload;
call->size = size;
if( !vg_validf( framevol_l ) ||
!vg_validf( framevol_r ) ||
- !vg_validf( frame_samplerate ) ){
- vg_fatal_error( "Invalid sampling conditions.\n"
- "This crash is to protect your ears.\n"
- " channel: %p (%s)\n"
- " sample_rate: %f\n"
- " volume: L%f R%f\n"
- " listener: %.2f %.2f %.2f [%.2f %.2f %.2f]\n",
- ch, ch->name, frame_samplerate,
- framevol_l, framevol_r,
- vg_audio.internal_listener_pos[0],
- vg_audio.internal_listener_pos[1],
- vg_audio.internal_listener_pos[2],
- vg_audio.internal_listener_ears[0],
- vg_audio.internal_listener_ears[1],
- vg_audio.internal_listener_ears[2]
- );
+ !vg_validf( frame_samplerate ) )
+ {
+ vg_fatal_condition();
+ vg_info( "Invalid sampling conditions.\n"
+ "This crash is to protect your ears.\n" );
+ vg_info( " channel: %p (%s)\n", ch, ch->name );
+ vg_info( " sample_rate: %f\n", frame_samplerate );
+ vg_info( " volume: L%f R%f\n", framevol_l, framevol_r );
+ vg_info( " listener: %.2f %.2f %.2f [%.2f %.2f %.2f]\n",
+ vg_audio.internal_listener_pos[0],
+ vg_audio.internal_listener_pos[1],
+ vg_audio.internal_listener_pos[2],
+ vg_audio.internal_listener_ears[0],
+ vg_audio.internal_listener_ears[1],
+ vg_audio.internal_listener_ears[2] );
+ vg_fatal_exit();
}
}
* NULL when we get the clip
*/
- if( format == k_audio_format_vorbis ){
- if( !clip->path ){
- vg_fatal_error( "No path specified, embeded vorbis unsupported" );
+ if( format == k_audio_format_vorbis )
+ {
+ if( !clip->path )
+ {
+ vg_error( "No path specified, embeded vorbis unsupported\n" );
}
audio_lock();
audio_unlock();
if( !clip->data )
- vg_fatal_error( "Audio failed to load" );
+ {
+ vg_error( "Audio failed to load\n" );
+ }
float mb = (float)(clip->size) / (1024.0f*1024.0f);
vg_info( "Loaded audio clip '%s' (%.1fmb)\n", clip->path, mb );
}
- else if( format == k_audio_format_stereo ){
- vg_fatal_error( "Unsupported format (Stereo uncompressed)" );
+ else if( format == k_audio_format_stereo )
+ {
+ vg_error( "Unsupported format (Stereo uncompressed)\n" );
}
- else if( format == k_audio_format_bird ){
- if( !clip->data ){
- vg_fatal_error( "No data, external birdsynth unsupported" );
+ else if( format == k_audio_format_bird )
+ {
+ if( !clip->data )
+ {
+ vg_error( "No data, external birdsynth unsupported\n" );
}
u32 total_size = clip->size + sizeof(struct synth_bird);
total_size = vg_align8( total_size );
if( total_size > AUDIO_DECODE_SIZE )
- vg_fatal_error( "Bird coding too long\n" );
+ {
+ vg_error( "Bird coding too long, and exceeds maximum decode size\n" );
+ }
struct synth_bird *bird = vg_linear_alloc( lin_alloc, total_size );
memcpy( &bird->settings, clip->data, clip->size );
vg_info( "Loaded bird synthesis pattern (%u bytes)\n", total_size );
}
- else{
- if( !clip->path ){
- vg_fatal_error( "No path specified, embeded mono unsupported" );
+ else
+ {
+ if( !clip->path )
+ {
+ vg_error( "No path specified, embeded mono unsupported\n" );
}
vg_linear_clear( vg_mem.scratch );
stb_vorbis *decoder = stb_vorbis_open_memory(
filedata, fsize, &err, &alloc );
- if( !decoder ){
- vg_error( "stb_vorbis_open_memory failed on '%s' (%d)\n",
+ if( !decoder )
+ {
+ vg_fatal_condition();
+ vg_info( "Vorbis decode error\n" );
+ vg_info( "stb_vorbis_open_memory failed on '%s' (%d)\n",
clip->path, err );
- vg_fatal_error( "Vorbis decode error" );
+ vg_fatal_exit();
}
/* only mono is supported in uncompressed */
decoder, clip->data, length_samples );
if( read_samples != length_samples )
- vg_fatal_error( "Decode error" );
-
-#if 0
- float mb = (float)(data_size) / (1024.0f*1024.0f);
- vg_info( "Loaded audio clip '%s' (%.1fmb) %u samples\n", clip->path, mb,
- length_samples );
-#endif
+ {
+ vg_error( "Decode error, read_samples did not match length_samples\n" );
+ }
}
}
return;
audio_unlock();
+
vg_fatal_error( "Must load audio clip before playing! \n" );
}
samples = vg_align4( samples );
if( vg_dsp.allocations + samples > (1024*1024)/4 )
- vg_fatal_error( "too much dsp" );
+ {
+ vg_fatal_error( "Ran out of memory in the DSP buffer\n"
+ " Request was %u samples\n", samples );
+ }
float *buf = &vg_dsp.buffer[ vg_dsp.allocations ];
vg_dsp.allocations += samples;
{
/* check for problems in configuration */
if( env->libc != k_libc_version_native )
+ {
if( env->compiler != k_compiler_zigcc )
- vg_fatal_error(
+ {
+ vg_fatal_condition();
+ vg_info(
"Cannot specify libc version using the '%s' compiler.\n",
compiler_names[ env->compiler ] );
+ vg_fatal_exit();
+ }
+ }
if( env->compiler == k_compiler_clang )
+ {
if( env->platform != k_platform_linux )
- vg_fatal_error( "Cannot compile for '%s' using the '%s' compiler;" );
+ {
+ vg_fatal_condition();
+ vg_info( "Cannot compile for '%s' using the '%s' compiler;" );
+ vg_fatal_exit();
+ }
+ }
vg_str cmd = {0};
vg_strcat( &cmd, "ccache " );
appname, k_obj_type_exe );
}
else
- vg_fatal_error( "Programming error" );
+ {
+ vg_fatal_condition();
+ vg_info( "No compile procedure set for platform '%s'\n",
+ platform_names[env->platform] );
+ vg_fatal_exit();
+ }
return (struct compile_result){};
}
FILE *header = fopen( path_header, "w" );
if( !header )
- {
- fprintf(stderr, "Could not open '%s'\n", path_header );
- vg_fatal_error( "IO error" );
- return 0;
- }
+ vg_fatal_error( "Could not open '%s'\n", path_header );
fprintf( header, "#pragma once\n" );
fprintf( header, "#include \"vg/vg_engine.h\"\n" );
{
fclose( header );
vg_fatal_error( "Failed to assemble vertex source code" );
- return 0;
}
vg_strcatf( c_body, "\n .fs = \n" );
{
fclose( header );
vg_fatal_error( "Failed to assemble fragment source code" );
- return 0;
}
vg_strcatf( c_body, "\n};\n\n" );
if( uf->array )
continue;
- for( int j=0; j<vg_list_size(types); j ++ )
+ for( int j=0; j<VG_ARRAY_LEN(types); j ++ )
{
struct type_info *inf = &types[j];
}
}
else{
- if( it->depth+1 >= vg_list_size(it->stack) ){
+ if( it->depth+1 >= VG_ARRAY_LEN(it->stack) ){
vg_error( "Maximum stack reached!\n" );
return 0;
}
void vg_console_reg_var( const char *alias, void *ptr, enum vg_var_dtype type,
u32 flags )
{
- if( vg_thread_purpose() == k_thread_purpose_main )
- vg_fatal_error( "FIXME: Cannot register VAR from main thread" );
-
- if( vg_console.var_count > vg_list_size(vg_console.vars) )
- vg_fatal_error( "Too many vars registered" );
+ VG_ASSERT( vg_thread_purpose() != k_thread_purpose_main );
+ VG_ASSERT( vg_console.var_count < VG_ARRAY_LEN(vg_console.vars) );
vg_var *var = &vg_console.vars[ vg_console.var_count ++ ];
var->name = alias;
int (*function)(int argc, const char *argv[]),
void (*poll_suggest)(int argc, const char *argv[]) )
{
- if( vg_thread_purpose() == k_thread_purpose_main )
- vg_fatal_error( "FIXME: Cannot register CMD from main thread" );
-
- if( vg_console.function_count > vg_list_size(vg_console.functions) )
- vg_fatal_error( "Too many functions registered" );
+ VG_ASSERT( vg_thread_purpose() != k_thread_purpose_main );
+ VG_ASSERT( vg_console.function_count < VG_ARRAY_LEN(vg_console.functions) );
vg_cmd *cmd = &vg_console.functions[ vg_console.function_count ++ ];
best_pos = j;
/* insert if good score */
- if( best_pos < vg_list_size( vg_console.suggestions ) )
+ if( best_pos < VG_ARRAY_LEN( vg_console.suggestions ) )
{
int start = VG_MIN( vg_console.suggestion_count,
- vg_list_size( vg_console.suggestions )-1 );
+ VG_ARRAY_LEN( vg_console.suggestions )-1 );
for( int j=start; j>best_pos; j -- )
vg_console.suggestions[j] = vg_console.suggestions[j-1];
vg_console.suggestions[ best_pos ].lev_score = score;
if( vg_console.suggestion_count <
- vg_list_size( vg_console.suggestions ) )
+ VG_ARRAY_LEN( vg_console.suggestions ) )
vg_console.suggestion_count ++;
}
}
{
strncpy( target,
vg_console.suggestions[ vg_console.suggestion_select ].str,
- vg_list_size( vg_console.input )-1 );
+ VG_ARRAY_LEN( vg_console.input )-1 );
_ui_textbox_move_cursor( ctx,
&ctx->textbox.cursor_user,
int offset = VG_MIN( entry_num, vg_console.history_count -1 ),
pick = (vg_console.history_last - offset) %
- vg_list_size( vg_console.history );
+ VG_ARRAY_LEN( vg_console.history );
strcpy( buf, vg_console.history[ pick ] );
}
vg_console.history_pos+1,
VG_MIN
(
- vg_list_size( vg_console.history ),
+ VG_ARRAY_LEN( vg_console.history ),
vg_console.history_count - 1
)
)
_ui_textbox_move_cursor( ctx,
&ctx->textbox.cursor_user,
&ctx->textbox.cursor_pos,
- vg_list_size(vg_console.input)-1, 1 );
+ VG_ARRAY_LEN(vg_console.input)-1, 1 );
}
}
_ui_textbox_move_cursor( ctx,
&ctx->textbox.cursor_user,
&ctx->textbox.cursor_pos,
- vg_list_size(vg_console.input)-1, 1 );
+ VG_ARRAY_LEN(vg_console.input)-1, 1 );
}
}
vg_console.history[ vg_console.history_last ]) )
{
vg_console.history_last = ( vg_console.history_last + 1) %
- vg_list_size(vg_console.history );
+ VG_ARRAY_LEN(vg_console.history );
vg_console.history_count =
- VG_MIN( vg_list_size( vg_console.history ),
+ VG_MIN( VG_ARRAY_LEN( vg_console.history ),
vg_console.history_count + 1 );
strcpy( vg_console.history[ vg_console.history_last ],
vg_console.input );
{
ptr --;
- if( ptr < 0 ) ptr = vg_list_size( vg_log.log )-1;
+ if( ptr < 0 ) ptr = VG_ARRAY_LEN( vg_log.log )-1;
ui_text( ctx, rect_line, vg_log.log[ptr], 1, k_ui_align_left, 0 );
rect_line[1] -= fh;
.enter = _vg_console_on_enter,
};
ui_textbox( ctx, rect_input, NULL,
- vg_console.input, vg_list_size(vg_console.input), 1,
+ vg_console.input, VG_ARRAY_LEN(vg_console.input), 1,
UI_TEXTBOX_AUTOFOCUS, &callbacks );
/*
#include "vg/vg_ui/imgui_impl_opengl.c"
#include "vg/vg_default_font.gc"
-#define TEMP_STATUS_LOCK SDL_AtomicLock
-#define TEMP_STATUS_UNLOCK SDL_AtomicUnlock
-#define TEMP_SEM_POST(X) SDL_SemPost( X )
-#define TEMP_SEM_WAIT(X) SDL_SemWait( X )
-#define TEMP_SEM_GET(X) SDL_SemValue( X )
-
enum engine_status _vg_engine_status(void)
{
- TEMP_STATUS_LOCK( &vg.sl_status );
+ SDL_AtomicLock( &vg.sl_status );
enum engine_status status = vg.engine_status;
- TEMP_STATUS_UNLOCK( &vg.sl_status );
+ SDL_AtomicUnlock( &vg.sl_status );
return status;
}
enum vg_thread_purpose vg_thread_purpose(void)
{
- TEMP_STATUS_LOCK( &vg.sl_status );
- if( vg.thread_id_main == SDL_GetThreadID(NULL) )
+ SDL_AtomicLock( &vg.sl_status );
+
+ SDL_threadID id = SDL_GetThreadID(NULL);
+ if( vg.thread_id_main == id )
{
- TEMP_STATUS_UNLOCK( &vg.sl_status );
+ SDL_AtomicUnlock( &vg.sl_status );
return k_thread_purpose_main;
}
- else
+ else if( vg.thread_id_loader == id )
{
- TEMP_STATUS_UNLOCK( &vg.sl_status );
+ SDL_AtomicUnlock( &vg.sl_status );
return k_thread_purpose_loader;
}
-}
-
-static void vg_assert_thread( enum vg_thread_purpose required )
-{
- enum vg_thread_purpose purpose = vg_thread_purpose();
-
- if( purpose != required ){
- vg_fatal_error( "thread_purpose must be %u not %u\n", required, purpose );
+ else
+ {
+ SDL_AtomicUnlock( &vg.sl_status );
+ return k_thread_purpose_nothing;
}
}
vg_prof_render = {.name="render()"},
vg_prof_swap = {.name="swap"};
-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_error( "OpenGL Error" );
-}
-
static void async_vg_bake_shaders( void *payload, u32 size )
{
vg_shaders_compile();
{
vg_success( "Internal async setup complete\n" );
- TEMP_STATUS_LOCK( &vg.sl_status );
+ SDL_AtomicLock( &vg.sl_status );
if( vg.engine_status == k_engine_status_crashed )
{
- TEMP_STATUS_UNLOCK( &vg.sl_status );
+ SDL_AtomicUnlock( &vg.sl_status );
return;
}
else
vg.engine_status = k_engine_status_running;
}
- TEMP_STATUS_UNLOCK( &vg.sl_status );
-
- vg.client_has_control = 1;
+ SDL_AtomicUnlock( &vg.sl_status );
}
#ifdef VG_CUSTOM_SHADERS
return 0;
}
-static int _vg_crashscreen(void)
+static void _vg_crashscreen(void)
{
-#if 0
- if( vg_getkey( SDLK_ESCAPE ) )
- return 1;
-#endif
-
glBindFramebuffer( GL_FRAMEBUFFER, 0 );
glEnable(GL_BLEND);
glDisable(GL_DEPTH_TEST);
glClear( GL_COLOR_BUFFER_BIT );
glViewport( 0,0, vg.window_x, vg.window_y );
-#if 0
- _vg_render_log();
-#endif
+ ui_prerender( &vg_ui.ctx );
+ vg_ui_set_screen( vg.window_x, vg.window_y );
+ ui_update_mouse( &vg_ui.ctx,
+ (ui_px[2]){ vg.mouse_pos[0], vg.mouse_pos[1] }, vg.mouse_state );
- return 0;
+ vg_framebuffer_ui( &vg_ui.ctx );
+
+ vg_console.enabled = 1;
+ ui_ignore_input_frames( &vg_ui.ctx, 10 );
+ vg_gui( &vg_ui.ctx );
+ ui_ignore_input_frames( &vg_ui.ctx, 0 );
+ ui_capture_mouse( &vg_ui.ctx, 1 );
+ vg_console_draw( &vg_ui.ctx );
+
+ ui_postrender( &vg_ui.ctx, vg.time_frame_delta );
+ vg_ui_post_update();
}
static void _vg_gameloop(void)
if( status == k_engine_status_crashed )
{
- if( _vg_crashscreen() )
- break;
+ _vg_crashscreen();
}
else
{
/* Shutdown */
vg_console_write_persistent();
- TEMP_STATUS_LOCK( &vg.sl_status );
+ SDL_AtomicLock( &vg.sl_status );
vg.engine_status = k_engine_status_none;
- TEMP_STATUS_UNLOCK( &vg.sl_status );
+ SDL_AtomicUnlock( &vg.sl_status );
- vg_loader_free();
-
- vg_success( "If you see this it means everything went.. \"well\".....\n" );
+ vg_loader_atexit();
SDL_GL_DeleteContext( vg.gl_context );
SDL_Quit();
+
+ vg_success( "The program has terminated 'correctly'\n" );
exit(0);
}
/* Opengl-required systems */
vg_ui_init();
- vg_loader_init();
vg.engine_status = k_engine_status_load_internal;
+ vg_loader_step( vg_loader_init, vg_loader_free );
_vg_opengl_sync_init();
- vg_loader_start( _vg_load_full, NULL );
+ vg_loader_start( _vg_load_full, NULL );
_vg_gameloop();
_vg_terminate();
}
-void vg_fatal_error( const char *fmt, ... )
+#ifndef _WIN32
+ #include <execinfo.h>
+#endif
+
+void vg_fatal_exit(void)
{
- va_list args;
- va_start( args, fmt );
- _vg_logx_va( stderr, NULL, "fatal", KRED, fmt, args );
- va_end( args );
+ /* append backtrace */
+#if !defined(_WIN32)
+ void *array[20];
+ char **strings;
+ int size, i;
+
+ size = backtrace( array, 20 );
+ strings = backtrace_symbols( array, size );
+
+ if( strings != NULL )
+ {
+ vg_info( "\n\n---------------- gnu backtrace -------------\n" );
- vg_print_backtrace();
+ for( int i=0; i<size; i++ )
+ vg_info( "%s\n", strings[i] );
+ }
+
+ free( strings );
+#endif
- TEMP_STATUS_LOCK( &vg.sl_status );
+ SDL_AtomicLock( &vg.sl_status );
vg.engine_status = k_engine_status_crashed;
- TEMP_STATUS_UNLOCK( &vg.sl_status );
+ SDL_AtomicUnlock( &vg.sl_status );
if( vg_thread_purpose() == k_thread_purpose_loader )
{
}
else
{
- vg_error( "There is no jump to the error runner thing yet! bai bai\n" );
+ /* TODO: This should also be able to go to the crash screen? */
_vg_terminate();
}
}
+void vg_fatal_error( const char *fmt, ... )
+{
+ vg_fatal_condition();
+
+ va_list args;
+ va_start( args, fmt );
+ _vg_logx_va( stderr, NULL, "fatal", KRED, fmt, args );
+ va_end( args );
+
+ vg_fatal_exit();
+}
+
/*
* settings menu
* ---------------------------------------------------------------------------
if( vg_settings.audio_devices.new_value == -1 ){ }
else if( vg_settings.audio_devices.new_value == -2 )
{
- vg_fatal_error( "Programming error\n" );
+ vg_fatal_exit();
}
else
{
};
static i32 page = 0;
- ui_tabs( ctx, panel, panel, opts, vg_list_size(opts), &page );
+ ui_tabs( ctx, panel, panel, opts, VG_ARRAY_LEN(opts), &page );
if( page == 0 )
{
/*
* Graphic cards will check these to force it to use the GPU.
- * TODO: explicit declexport. since -flto strips these symbols in release.
*/
-u32 NvOptimusEnablement = 0x00000001;
-int AmdPowerXpressRequestHighPerformance = 1;
+__attribute__((used)) u32 NvOptimusEnablement = 0x00000001;
+__attribute__((used)) int AmdPowerXpressRequestHighPerformance = 1;
#include "vg_async.c"
#include "vg_audio.c"
#include "vg_shader.c"
#include "vg_framebuffer.c"
#include "vg_render.c"
+#include "vg_opengl.c"
#ifdef VG_CUSTOM_SHADERS
#include "shaders/impl.c"
#include "vg_mem.h"
#include "vg_m.h"
#include "vg_font.h"
+#include "vg_string.h"
#include "vg_ui/imgui.h"
#include <setjmp.h>
SDL_GLContext gl_context;
SDL_sem *sem_loader; /* allows only one loader at a time */
- bool client_has_control; /* [T0] If 0: VG will display a loader screen
- If 1: The game is responsible for
- drawing everything.
- This can be set back to 0 after vg_load is
- complete to blinder the client
- Not recommended! */
-
SDL_threadID thread_id_main,
thread_id_loader;
if( (at->purpose != k_framebuffer_attachment_type_texture) &&
(at->purpose != k_framebuffer_attachment_type_texture_depth) )
{
- vg_fatal_error( "illegal operation: bind non-texture framebuffer"
- " attachment to texture slot" );
+ vg_fatal_condition();
+ vg_info( "illegal operation: bind non-texture framebuffer"
+ " attachment to texture slot" );
+ vg_fatal_exit();
}
glActiveTexture( GL_TEXTURE0 + slot );
FB_FORMAT_STR(GL_DEPTH_STENCIL_ATTACHMENT)
};
- for( int i=0; i<vg_list_size(formats); i++ )
+ for( int i=0; i<VG_ARRAY_LEN(formats); i++ )
if( formats[i].e == e )
return formats[i].str;
FB_FORMAT_STR(GL_RGBA32UI)
};
- for( int i=0; i<vg_list_size(formats); i++ )
+ for( int i=0; i<VG_ARRAY_LEN(formats); i++ )
if( formats[i].e == format )
return formats[i].str;
if( track )
{
- if( _vg_framebuffer.count != vg_list_size(_vg_framebuffer.list) )
+ if( _vg_framebuffer.count != VG_ARRAY_LEN(_vg_framebuffer.list) )
_vg_framebuffer.list[ _vg_framebuffer.count ++ ] = fb;
else
- vg_fatal_error( "Framebuffer list is full" );
+ {
+ vg_fatal_condition();
+ vg_info( "Framebuffer list is full, and tried to allocate another.\n");
+ vg_fatal_exit();
+ }
}
fb->attachments = vg_linear_alloc( alloc,
}
else
{
+ vg_fatal_condition();
if( result == GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT )
- vg_error( " status: Incomplete attachment" );
+ vg_info( " status: Incomplete attachment" );
else if( result == GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT )
- vg_error( " status: Missing attachment" );
+ vg_info( " status: Missing attachment" );
else if( result == GL_FRAMEBUFFER_UNSUPPORTED )
- vg_error( " status: Unsupported framebuffer format" );
+ vg_info( " status: Unsupported framebuffer format" );
else
- vg_error( " status: Generic Error" );
-
+ vg_info( " status: Generic Error" );
vg_info( "}\n" );
- vg_fatal_error( "Incomplete framebuffer (see logs)" );
+ vg_fatal_exit();
}
}
else if( op == vg_gui_visible )
pc ++;
else
- vg_fatal_error( "unknown op\n" );
+ vg_fatal_error( "unknown op (%u)\n", op );
goto next_code;
}
{
static const char *controller_glyphs[ SDL_CONTROLLER_BUTTON_MAX ][2] = {
/* xbox/generic playstation */
- [ SDL_CONTROLLER_BUTTON_A ] = { KGRN "\x06\x02\x85",KBLU "\x06\x02\x82" },
- [ SDL_CONTROLLER_BUTTON_B ] = { KRED "\x06\x02\x86",KRED "\x06\x02\x81" },
- [ SDL_CONTROLLER_BUTTON_X ] = { KBLU "\x06\x02\x83",KMAG "\x06\x02\x7f" },
- [ SDL_CONTROLLER_BUTTON_Y ] = { KYEL "\x06\x02\x84",KGRN "\x06\x02\x80" },
+ [ SDL_CONTROLLER_BUTTON_A ] = { KGRN "\x06\x02\x85",KBLU "\x06\x02\x82" },
+ [ SDL_CONTROLLER_BUTTON_B ] = { KRED "\x06\x02\x86",KRED "\x06\x02\x81" },
+ [ SDL_CONTROLLER_BUTTON_X ] = { KBLU "\x06\x02\x83",KMAG "\x06\x02\x7f" },
+ [ SDL_CONTROLLER_BUTTON_Y ] = { KYEL "\x06\x02\x84",KGRN "\x06\x02\x80" },
[ SDL_CONTROLLER_BUTTON_LEFTSTICK ] = { "\x87","\x87" },
[ SDL_CONTROLLER_BUTTON_RIGHTSTICK ] = { "\x8b","\x8b" },
[ SDL_CONTROLLER_BUTTON_LEFTSHOULDER ] = { "\x91","\x91" },
dir->index = 0;
}
-void vg_file_print_invalid( FILE *fp )
+void vg_file_error_info( FILE *fp )
{
- if( feof( fp )) {
+ if( feof( fp ))
+ {
vg_error( "mdl_open: header too short\n" );
}
- else{
- if( ferror( fp ))
- vg_error( "mdl_open: %s\n", strerror(errno) );
- else
- vg_error( "mdl_open: unkown failure\n" );
-
+ else
+ {
+ if( ferror( fp )) vg_info( "fopen: %s\n", strerror(errno) );
+ else vg_info( "fopen: unkown failure\n" );
}
}
void *vg_file_read( void *lin_alloc, const char *path, u32 *size )
{
FILE *f = fopen( path, "rb" );
- if( f ){
+ if( f )
+ {
void *buffer = lin_alloc? vg_linear_alloc( lin_alloc, 0 ):
NULL;
u64 current = 0;
/* read in chunks */
- for( u32 i=0; 1; i++ ){
+ for( u32 i=0; 1; i++ )
+ {
if( lin_alloc )
buffer = vg_linear_extend( lin_alloc,buffer,VG_FILE_IO_CHUNK_SIZE );
else
u64 l = fread( buffer + current, 1, VG_FILE_IO_CHUNK_SIZE, f );
current += l;
- if( l != VG_FILE_IO_CHUNK_SIZE ){
- if( feof( f ) ){
+ if( l != VG_FILE_IO_CHUNK_SIZE )
+ {
+ if( feof( f ) )
+ {
break;
}
- else{
- if( ferror( f ) ){
+ else
+ {
+ if( ferror( f ) )
+ {
fclose(f);
- vg_fatal_error( "read error" );
+ vg_fatal_condition();
+ vg_info( "Read error\n" );
+ vg_fatal_exit();
}
- else{
+ else
+ {
fclose(f);
- vg_fatal_error( "unknown error codition" );
+ vg_fatal_condition();
+ vg_info( "Unknown error condition\n" );
+ vg_fatal_exit();
}
}
}
int vg_dir_next_entry( vg_dir *dir );
enum vg_entry_type vg_dir_entry_type( vg_dir *dir );
void vg_dir_close( vg_dir *dir );
-void vg_file_print_invalid( FILE *fp );
/*
* File I/O
int vg_asset_write( const char *path, void *data, i64 size );
int vg_file_copy( const char *src, const char *dst, void *lin_alloc );
const char *vg_path_filename( const char *path );
+void vg_file_error_info( FILE *fp );
glBufferData( GL_ARRAY_BUFFER, VG_LINES_BUFFER_SIZE, NULL, GL_DYNAMIC_DRAW );
glBindVertexArray( vg_lines.vao );
- VG_CHECK_GL_ERR();
/* Pointers */
glVertexAttribPointer(
(void*)(offsetof( struct vg_lines_vert, colour ))
);
glEnableVertexAttribArray( 1 );
-
- VG_CHECK_GL_ERR();
}
void vg_lines_init(void)
{4,5},{5,7},{7,6},{6,4},
{4,0},{5,1},{6,2},{7,3}};
- vg_line_mesh( verts, indices, vg_list_size(indices), colour );
+ vg_line_mesh( verts, indices, VG_ARRAY_LEN(indices), colour );
}
void vg_line_boxf_transformed( m4x3f m, boxf box, u32 colour )
{4,5},{5,7},{7,6},{6,4},
{4,0},{5,1},{6,2},{7,3}};
- vg_line_mesh( verts, indices, vg_list_size(indices), colour );
+ vg_line_mesh( verts, indices, VG_ARRAY_LEN(indices), colour );
}
void vg_line_cross(v3f pos,u32 colour, float scale)
glVertexAttribPointer( 0, 2, GL_FLOAT, GL_FALSE, sizeof(float)*2, (void*)0 );
glEnableVertexAttribArray( 0 );
- VG_CHECK_GL_ERR();
-
- if( !vg_shader_compile( &_shader_loader ) )
- vg_fatal_error( "failed to compile shader" );
+ vg_compile_shader( &_shader_loader );
}
-static void vg_loader_free(void)
+void vg_loader_free(void)
{
- vg_info( "vg_loader_free\n" );
glDeleteVertexArrays( 1, &vg_loader.vao );
glDeleteBuffers( 1, &vg_loader.vbo );
+}
+void vg_loader_atexit(void)
+{
+ vg_info( "Shutdown steps\n" );
for( int i=0; i<vg_loader.step_count; i++ )
{
struct loader_free_step *step =
}
/* Run client loader */
- //vg_info( "Starting client loader thread @%p\n", pfn );
void (*call_func)(void *data) = pfn;
call_func( vg.thread_data );
- TEMP_SEM_POST( vg.sem_loader );
+ SDL_SemPost( vg.sem_loader );
vg.thread_id_loader = 0;
return 0;
int vg_loader_availible(void)
{
- if( TEMP_SEM_GET( vg.sem_loader ) )
+ if( SDL_SemValue( vg.sem_loader ) )
{
if( !(vg_async.start) )
return 1;
void vg_loader_start( void(*pfn)(void *data), void *data )
{
- TEMP_SEM_WAIT( vg.sem_loader );
+ SDL_SemWait( vg.sem_loader );
vg.thread_data = data;
SDL_CreateThread( _vg_loader_thread, "vg: loader", pfn );
* Schedule something to be ran now, freed later. Checks in with engine status
*/
void _vg_loader_step( void( *fn_load )(void), void( *fn_free )(void),
- const char *alias ){
-
+ const char *alias )
+{
u64 t0 = SDL_GetPerformanceCounter();
vg.time_hp_last = vg.time_hp;
double dt = (double)udt / (double)SDL_GetPerformanceFrequency();
vg_info( "ltime [%p] %s: %fs\n", fn_load, alias, dt );
- if( fn_free ){
+ if( fn_free )
+ {
struct loader_free_step step;
step.fn_free = fn_free;
- if( vg_loader.step_count == vg_list_size(vg_loader.step_buffer) )
- vg_fatal_error( "Too many free steps" );
-
+ VG_ASSERT( vg_loader.step_count < VG_ARRAY_LEN(vg_loader.step_buffer) );
vg_loader.step_buffer[ vg_loader.step_count ++ ] = step;
}
- /* TODO: There was a quit checker here, re-add this? */
+ SDL_AtomicLock( &vg.sl_status );
+ enum engine_status status = vg.engine_status;
+ SDL_AtomicUnlock( &vg.sl_status );
+
+ if( status != k_engine_status_load_internal )
+ {
+ vg_info( "Joining loader thread.\n" );
+ longjmp( vg.env_loader_exit, 1 );
+ }
}
int vg_loader_availible(void);
void vg_loader_render(void);
void vg_loader_render_ring( f32 opacity );
-static void vg_loader_free(void);
+void vg_loader_free(void);
+void vg_loader_atexit(void);
void vg_loader_init(void);
#define vg_loader_step( FN, FN_FREE )\
#include "vg_log.h"
#include "vg_string.h"
-#ifndef _WIN32
- #include <execinfo.h>
-#endif
-
struct vg_log vg_log;
static void _vg_log_append_line( const char *str )
{
- if( vg_log.log_line_count < vg_list_size( vg_log.log ) )
+ if( vg_log.log_line_count < VG_ARRAY_LEN( vg_log.log ) )
vg_log.log_line_count ++;
char *dest = vg_log.log[ vg_log.log_line_current ++ ];
- vg_strncpy( str, dest, vg_list_size(vg_log.log[0]), k_strncpy_allow_cutoff );
+ vg_strncpy( str, dest, VG_ARRAY_LEN(vg_log.log[0]), k_strncpy_allow_cutoff );
- if( vg_log.log_line_current >= vg_list_size( vg_log.log ) )
+ if( vg_log.log_line_current >= VG_ARRAY_LEN( vg_log.log ) )
vg_log.log_line_current = 0;
}
char buffer[4096];
- vsnprintf( buffer, vg_list_size(buffer), fmt, args );
+ vsnprintf( buffer, VG_ARRAY_LEN(buffer), fmt, args );
const char *line = buffer;
char logline[96];
- for( u32 i=0; i<vg_list_size(buffer); i++ ){
+ for( u32 i=0; i<VG_ARRAY_LEN(buffer); i++ ){
char c = buffer[i];
if( c == '\0' || c == '\n' ){
};
const char *colour = thread_colours[
- (vg_thread_purpose() % vg_list_size( thread_colours ))];
+ (vg_thread_purpose() % VG_ARRAY_LEN( thread_colours ))];
fprintf( file, "%s[%u]"KNRM"%.32s",
colour, vg_thread_purpose(), line_location );
va_end( args );
}
-void vg_print_backtrace(void)
+void vg_fatal_condition(void)
{
-#if !defined(_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<size; i++ )
- vg_info( "%s\n", strings[i] );
-
- vg_error( "---------------- gnu backtrace -------------\n" );
- }
-
- free( strings );
-
-#endif
+ vg_error( "--------- Fatal condition entered --------- \n" );
}
const char *location, const char *prefix,
const char *colour,
const char *fmt, va_list args );
-
-void vg_print_backtrace(void);
-
size = vg_align8( size );
if( ((u64)buffer) % 8 )
- vg_fatal_error( "unaligned buffer (%p)", buffer );
+ vg_fatal_error( "Tried allocating to an unaligned buffer (%p)", buffer );
vg_linear_allocator *alloc = vg_linear_header( buffer );
if( (alloc->cur + size) > alloc->size )
- {
vg_fatal_error( "linear allocator overflow (%u + %u > %u)\n",
- alloc->cur, size, alloc->size );
- }
+ alloc->cur, size, alloc->size );
if( alloc->flags & VG_MEMORY_SYSTEM )
{
if( (alloc->allocation_count + 1) > VG_MAX_ALLOCATIONS )
{
- vg_error( "Alloc (%p) allocation count is at the limit of"
- " %u allocations.\n", alloc, VG_MAX_ALLOCATIONS );
- vg_fatal_error( "Max linear allocations reached" );
+ vg_fatal_condition();
+ vg_info( "Linear allocators marked as 'SYSTEMS', have a hard limit of "
+ "%u allocations.\n\n"
+ "The limit was exceeded by the following request:\n",
+ VG_MAX_ALLOCATIONS );
+ vg_info( " Name: %s\n", constr_name );
+ vg_info( " Size: %u bytes\n", size );
+ vg_fatal_exit();
}
}
void *data;
- if( vg_mem.use_libc_malloc && (alloc->flags & VG_MEMORY_SYSTEM) ){
+ if( vg_mem.use_libc_malloc && (alloc->flags & VG_MEMORY_SYSTEM) )
+ {
data = malloc( size );
vg_allocation_meta *meta = &alloc->alloc_table[ alloc->allocation_count ];
meta->size = size;
meta->name = constr_name;
}
- else{
+ else
data = buffer + alloc->cur;
- }
u8 *bytes = data;
- for( u32 i=0; i<size; i++ ){
+ for( u32 i=0; i<size; i++ )
bytes[i] = 0xfe;
- }
alloc->allocation_count ++;
alloc->last_alloc = data;
alloc->last_alloc_size = size;
alloc->cur += size;
- if( ((u64)data) % 8 ){
- vg_fatal_error( "unaligned" );
- }
-
+ if( ((u64)data) % 8 )
+ vg_fatal_error( "Resultant allocation was unaligned, most likely memory "
+ "corruption or programmer error\n" );
return data;
}
newsize = vg_align8( newsize );
if( alloc->last_alloc != data )
- vg_fatal_error( "This block has been fixed!" );
+ vg_fatal_error( "Tried to resize allocation in linear allocator which "
+ "has allocated other things after this block.\n" );
if( (alloc->cur - alloc->last_alloc_size + newsize) > alloc->size )
- vg_fatal_error( "Cannot resize, overflow" );
+ vg_fatal_error( "Tried to resize allocation to new size which would "
+ "overflow the allocator\n" );
alloc->cur -= alloc->last_alloc_size;
alloc->cur += newsize;
alloc->last_alloc_size = newsize;
- if( vg_mem.use_libc_malloc && (alloc->flags & VG_MEMORY_SYSTEM) ){
+ if( vg_mem.use_libc_malloc && (alloc->flags & VG_MEMORY_SYSTEM) )
+ {
data = realloc( data, newsize );
if( !data )
- vg_fatal_error( "realloc failed" );
+ vg_fatal_error( "We are libc mode, and realloc failed" );
alloc->alloc_table[ alloc->allocation_count-1 ].data = data;
alloc->alloc_table[ alloc->allocation_count-1 ].size = newsize;
alloc->last_alloc = data;
return data;
}
- else{
- return data;
- }
+ else return data;
}
/* its possible to delete just the last item */
{
vg_linear_allocator *alloc = vg_linear_header( buffer );
- if( alloc->last_alloc != data ){
- vg_fatal_error( "This block has been fixed! Last alloc: %p, this: %p\n",
- alloc->last_alloc, data );
- }
+ if( alloc->last_alloc != data )
+ vg_fatal_error( "This block has been fixed and cannot be deleted.\n"
+ "Last alloc: %p, this: %p\n", alloc->last_alloc, data );
- if( vg_mem.use_libc_malloc && (alloc->flags & VG_MEMORY_SYSTEM) ){
+ if( vg_mem.use_libc_malloc && (alloc->flags & VG_MEMORY_SYSTEM) )
+ {
vg_allocation_meta *meta = &alloc->alloc_table[alloc->allocation_count-1];
if( meta->type == k_allocation_type_linear )
vg_fatal_error( "Cannot free a linear allocator in this conext" );
void *_vg_create_linear_allocator( void *lin_alloc, u32 size,
u16 flags, const char *constr_name)
{
- if( sizeof( vg_linear_allocator ) != 32 )
- vg_fatal_error( "Programming error" );
+ VG_ASSERT( sizeof( vg_linear_allocator ) == 32 );
vg_linear_allocator *header;
u32 block_size = size + sizeof(vg_linear_allocator);
/* Creating it inside an existing one */
- if( lin_alloc ){
+ if( lin_alloc )
+ {
vg_linear_allocator *alloc = vg_linear_header( lin_alloc );
if( alloc->cur + block_size > alloc->size )
- vg_fatal_error( "Out of memory" );
+ vg_fatal_error( "Out of memory (%u + %u > %u)\n",
+ alloc->cur, block_size, alloc->size );
if( alloc->allocation_count + 1 > VG_MAX_ALLOCATIONS )
- vg_fatal_error( "Max allocations in linear allocator" );
+ vg_fatal_error( "Exceeded max allocations in linear allocator (%u)\n",
+ VG_MAX_ALLOCATIONS );
if( (flags && VG_MEMORY_SYSTEM) && (alloc->flags & VG_MEMORY_REALTIME) )
- vg_fatal_error( "Cannot declare realtime allocator inside systems"
- " allocator" );
+ vg_fatal_error( "Cannot declare realtime allocator inside systems "
+ "allocator");
if( vg_mem.use_libc_malloc ){
vg_allocation_meta *meta =
meta->size = size;
meta->name = constr_name;
}
- else{
- header = lin_alloc + alloc->cur;
- }
+ else header = lin_alloc + alloc->cur;
alloc->cur += block_size;
alloc->last_alloc = header;
header->size = size;
header->flags = flags;
- if( vg_mem.use_libc_malloc && (flags & VG_MEMORY_SYSTEM) ){
+ if( vg_mem.use_libc_malloc && (flags & VG_MEMORY_SYSTEM) )
+ {
u32 table_size = sizeof(vg_allocation_meta)*VG_MAX_ALLOCATIONS;
header->alloc_table = malloc( table_size );
}
- else
- header->alloc_table = NULL;
+ else header->alloc_table = NULL;
return header+1;
}
#pragma once
-#define VG_MAX_ALLOCATIONS 256
+#define VG_MAX_ALLOCATIONS 128
typedef struct vg_linear_allocator vg_linear_allocator;
typedef struct vg_allocation_meta vg_allocation_meta;
{
vg_pool_node *node = vg_pool_nodeptr( pool, id );
- if( !node->ref_count ){
+ if( !node->ref_count )
vg_pool_unlink( pool, id );
- }
if( node->ref_count == 0xffff )
- vg_fatal_error( "pool watch missmatch (limit is 128)\n" );
+ vg_fatal_error( "Pool watch missmatch (limit is 128)\n" );
node->ref_count ++;
}
vg_fatal_error( "pool unwatch missmatch (no watchers)\n" );
node->ref_count --;
- if( !node->ref_count ){
+ if( !node->ref_count )
+ {
vg_pool_node *head = vg_pool_nodeptr( pool, pool->head ),
*tail = vg_pool_nodeptr( pool, pool->tail );
u8 vg_msg_count_bits( u32 count )
{
- if( count > 16 ) vg_fatal_error( "Too large\n" );
+ VG_ASSERT( count <= 16 );
return ((count-1)<<2);
}
--- /dev/null
+#include "vg/vg_opengl.h"
+
+static const char *gl_error_names[] =
+{
+ "GL_INVALID_ENUM",
+ "GL_INVALID_VALUE",
+ "GL_INVALID_OPERATION",
+ "GL_STACK_OVERFLOW",
+ "GL_STACK_UNDERFLOW",
+ "GL_OUT_OF_MEMORY",
+ "GL_INVALID_FRAMEBUFFER_OPERATION"
+};
+
+void vg_opengl_log_errors(void)
+{
+ u32 err_count = 0;
+ GLenum err;
+ while( (err = glGetError()) != GL_NO_ERROR )
+ {
+ if( !err_count )
+ vg_info( "OpenGL error buffer:\n" );
+
+ u32 err_i = err - 0x0500;
+ if( err_i < VG_ARRAY_LEN(gl_error_names) )
+ {
+ vg_info( " %u %s\n", err, gl_error_names[ err_i ] );
+ }
+ else
+ {
+ vg_info( "%u (unknown code)\n", err );
+ }
+
+ err_count ++;
+ }
+
+ if( !err_count )
+ vg_info( "OpenGL error buffer is empty.\n" );
+}
#include "dep/glad/glad.h"
+
+void vg_opengl_log_errors(void);
typedef v4f m4x4f[4];
typedef v3f boxf[2];
-/* anything compiled against VG shall implement this function somewhere. */
+/* anything compiled against VG shall implement vg_fatal_exit() somewhere. */
+void vg_fatal_condition(void);
+void vg_fatal_exit(void);
void vg_fatal_error( const char *fmt, ... );
#define VG_ASSERT( ITEM, ... ) \
- if( !( ITEM ) ) { \
- vg_fatal_error( "Assertion failed: " VG_LOG_MCSTR(ITEM) "\n" \
- VG_LOG_WHERE ); \
- }
+ if( !( ITEM ) ) { \
+ vg_fatal_error( "Assertion failed: " VG_LOG_MCSTR(ITEM) "\n" VG_LOG_WHERE );\
+ }
#define VG_MIN( A, B ) ((A)<(B)?(A):(B))
#define VG_MAX( A, B ) ((A)>(B)?(A):(B))
-#define vg_list_size( A ) (sizeof(A)/sizeof(A[0]))
+#define VG_ARRAY_LEN( A ) (sizeof(A)/sizeof(A[0]))
ui_fill( ctx, panel, 0xa0000000 );
- if( count > 8 ) vg_fatal_error( "Too many profiles\n" );
+ VG_ASSERT( count <= 8 );
f64 avgs[8];
u32 colours[8];
void rb_iter( rigidbody *rb )
{
- if( !vg_validf( rb->v[0] ) ||
- !vg_validf( rb->v[1] ) ||
- !vg_validf( rb->v[2] ) )
+ if( !vg_validf(rb->v[0]) || !vg_validf(rb->v[1]) || !vg_validf(rb->v[2]) )
{
- vg_fatal_error( "NaN velocity" );
+ vg_fatal_error(
+ "Aborting the program because velocity has invalid value in one "
+ "or more components: %f %f %f\n", rb->v[0],rb->v[1],rb->v[2] );
}
v3f gravity = { 0.0f, -9.8f, 0.0f };
int rb_global_has_space( void )
{
- if( rb_contact_count + 16 > vg_list_size(rb_contact_buffer) )
+ if( rb_contact_count + 16 > VG_ARRAY_LEN(rb_contact_buffer) )
return 0;
return 1;
glVertexAttribPointer( 1, 3, GL_FLOAT, GL_FALSE,
stride, (void *)offsetof(rb_view_vert, n) );
glEnableVertexAttribArray( 1 );
-
- VG_CHECK_GL_ERR();
}
void vg_rb_view_init(void)
}
static vg_shaders;
-static GLuint vg_shader_subshader( const char *src, GLint gliShaderType )
+/*
+ * Compile OpenGL subshader from GLSL source. Type is subshader type.
+ * If critical is set to 1, the program will fatal exit on compile failure.
+ */
+static GLuint vg_compile_opengl_subshader( GLint type,
+ const char *src, bool critical )
{
- GLint shader = glCreateShader( gliShaderType );
+ GLuint shader = glCreateShader( type );
- if( shader == GL_NONE )
+ if( shader == 0 )
{
- vg_error( "Could not 'glCreateShader()'\n" );
+ vg_fatal_condition();
+ vg_info( "glCreateShader returned 0.\n" );
+ vg_opengl_log_errors();
+ vg_fatal_exit();
return 0;
}
GLint status;
glGetShaderiv( shader, GL_COMPILE_STATUS, &status );
- if( status != GL_TRUE )
- {
+ if( status == GL_TRUE )
+ {
+ return shader;
+ }
+ else
+ {
+ if( critical ) vg_fatal_condition();
+
GLchar info[1024];
GLsizei len;
+ glGetShaderInfoLog( shader, sizeof(info), &len, info );
- glGetShaderInfoLog( shader, sizeof(info), &len, info );
- vg_error( "Error info:\n%s\n", info );
- return 0;
- }
+ const char *type_str = "?";
+
+ if( type == GL_VERTEX_SHADER ) type_str = "GL_VERTEX_SHADER";
+ else if( type == GL_FRAGMENT_SHADER ) type_str = "GL_FRAGMENT_SHADER";
+
+ vg_info( "%s subshader compile error:\n\n%s\n", type_str, info );
- return shader;
+ if( critical ) vg_fatal_exit();
+ return 0;
+ }
}
-int vg_shader_compile( struct vg_shader *shader )
+/*
+ * Final compilation by linking, if critical is 1, a fatal exit will occur on
+ * link failure
+ */
+static int vg_link_opengl_program( GLuint program, bool critical )
{
- GLuint program, vert, frag;
-
- /* If we are compiling this again, we obviously need to try to take the src
- * from the disk instead.
- *
- * Only do this if we have filenames set on the shader, so engine shaders
- * dont have to do it (text.. etc).
- */
-
- int use_source_files = 0;
- if( shader->compiled ){
- if( shader->vs.orig_file && shader->fs.orig_file ){
- use_source_files = 1;
- }
- else {
- vg_warn( "No source files for shader '%s'\n", shader->name );
- return 1;
- }
- }
+ glLinkProgram( program );
+
+ GLint success;
+ glGetProgramiv( program, GL_LINK_STATUS, &success );
- vg_info( "Compile shader '%s'\n", shader->name );
-
- if( use_source_files ){
- char error[260];
- char path[260];
-
- strcpy( path, "../../" );
- strcat( path, shader->vs.orig_file );
- char *vertex_src = stb_include_file( path, "", "../../shaders", error );
-
- strcpy( path, "../../" );
- strcat( path, shader->fs.orig_file );
- char *fragment_src = stb_include_file( path, "", "../../shaders", error );
-
- if( !vertex_src || !fragment_src ){
- const char *errstr = "Could not find shader source files (%s)\n";
- if( shader->compiled ){
- vg_warn( errstr, shader->vs.orig_file );
- free( vertex_src );
- free( fragment_src );
- return 1;
- }
- else{
- vg_error( errstr, shader->vs.orig_file );
- free( vertex_src );
- free( fragment_src );
- return 0;
- }
- }
-
- vert = vg_shader_subshader( vertex_src, GL_VERTEX_SHADER );
- frag = vg_shader_subshader( fragment_src, GL_FRAGMENT_SHADER );
-
- free( vertex_src );
- free( fragment_src );
- }
- else{
- vert = vg_shader_subshader( shader->vs.static_src, GL_VERTEX_SHADER );
- frag = vg_shader_subshader( shader->fs.static_src, GL_FRAGMENT_SHADER );
- }
-
- if( !vert || !frag )
+ if( success ) return 1;
+ else
+ {
+ if( critical ) vg_fatal_condition();
+
+ char info[ 512 ];
+ glGetProgramInfoLog( program, sizeof(info), NULL, info );
+ vg_info( "Shader program link error:\n\n%s\n", info );
+
+ if( critical ) vg_fatal_exit();
return 0;
-
- program = glCreateProgram();
+ }
+}
+
+/*
+ * Compile vg_shader from static source code. Will fatal exit if there is a
+ * compile error
+ */
+void vg_compile_shader( struct vg_shader *shader )
+{
+ VG_ASSERT( shader->compiled == 0 );
+
+ const char *vs = shader->vs.static_src,
+ *fs = shader->fs.static_src;
+
+ GLuint vert = vg_compile_opengl_subshader( GL_VERTEX_SHADER, vs, 1 ),
+ frag = vg_compile_opengl_subshader( GL_FRAGMENT_SHADER, fs, 1 ),
+ program = glCreateProgram();
glAttachShader( program, vert );
glAttachShader( program, frag );
- glLinkProgram( program );
+
+ vg_link_opengl_program( program, 1 );
glDeleteShader( vert );
glDeleteShader( frag );
-
- /* Check for link errors */
- char infoLog[ 512 ];
- int success_link = 1;
-
- glGetProgramiv( program, GL_LINK_STATUS, &success_link );
- if( !success_link )
- {
- glGetProgramInfoLog( program, 512, NULL, infoLog );
- vg_error( "Link failed: %s\n", infoLog );
- glDeleteProgram( program );
- return 0;
- }
-
- if( shader->compiled )
- glDeleteProgram( shader->id );
-
+
shader->id = program;
- shader->compiled = 1;
- return 1;
+ shader->compiled = 1;
+}
+
+/*
+ * Recompile vg_shader from its original source files. This won't work in the
+ * shipped version of the engine.
+ */
+void vg_recompile_shader( struct vg_shader *shader )
+{
+ VG_ASSERT( shader->compiled == 1 );
+
+ char error[260];
+ char path[260];
+
+ strcpy( path, "../../" );
+ strcat( path, shader->vs.orig_file );
+ char *vs = stb_include_file( path, "", "../../shaders", error );
+
+ strcpy( path, "../../" );
+ strcat( path, shader->fs.orig_file );
+ char *fs = stb_include_file( path, "", "../../shaders", error );
+
+ if( !vs || !fs )
+ {
+ vg_warn( "Could not recompile shader due to missing source files:\n" );
+
+ if( !vs ) vg_info( " Vertex: %s\n", shader->vs.orig_file );
+ if( !fs ) vg_info( " Fragment: %s\n", shader->fs.orig_file );
+ free( vs );
+ free( fs );
+ return;
+ }
+
+ GLuint vert = vg_compile_opengl_subshader( GL_VERTEX_SHADER, vs, 0 ),
+ frag = vg_compile_opengl_subshader( GL_FRAGMENT_SHADER, fs, 0 );
+
+ free( vs );
+ free( fs );
+
+ if( !vert || !frag ) return;
+
+ GLuint program = glCreateProgram();
+
+ glAttachShader( program, vert );
+ glAttachShader( program, frag );
+
+ if( vg_link_opengl_program( program, 0 ) )
+ {
+ /* replace existing */
+ glDeleteProgram( shader->id );
+ shader->id = program;
+ }
+ else
+ {
+ /* womp womp */
+ glDeleteProgram( program );
+ }
+
+ glDeleteShader( vert );
+ glDeleteShader( frag );
}
void vg_free_shader( struct vg_shader *shader )
if( shader->compiled )
{
glDeleteProgram( shader->id );
+ shader->id = 0;
shader->compiled = 0;
}
}
{
vg_info( "Compiling shaders\n" );
- for( int i=0; i<vg_shaders.count; i ++ ){
- vg_shader *shader = vg_shaders.shaders[i];
-
- if( !vg_shader_compile( shader ) )
- vg_fatal_error( "Failed to compile shader" );
- }
+ for( int i=0; i<vg_shaders.count; i ++ )
+ vg_compile_shader( vg_shaders.shaders[i] );
#ifdef VG_CUSTOM_SHADERS
vg_auto_shader_link();
#endif
}
-int vg_shaders_live_recompile(int argc, const char *argv[])
+int vg_shaders_live_recompile( int argc, const char *argv[] )
{
vg_info( "Recompiling shaders\n" );
for( int i=0; i<vg_shaders.count; i ++ )
{
struct vg_shader *shader = vg_shaders.shaders[i];
- vg_shader_compile( shader );
+ vg_compile_shader( shader );
}
return 0;
void vg_shader_register( struct vg_shader *shader )
{
- if( vg_shaders.count == vg_list_size(vg_shaders.shaders) )
- vg_fatal_error( "Too many shaders" );
+ VG_ASSERT( vg_shaders.count < VG_ARRAY_LEN(vg_shaders.shaders) );
shader->compiled = 0;
- shader->id = 0; /* TODO: make this an error shader */
+ shader->id = 0; /* TODO: make this an error shader */
vg_shaders.shaders[ vg_shaders.count ++ ] = shader;
}
void vg_shaders_compile(void);
int vg_shaders_live_recompile(int argc, const char *argv[]);
void vg_shader_register( struct vg_shader *shader );
-int vg_shader_compile( struct vg_shader *shader );
+void vg_compile_shader( struct vg_shader *shader );
+void vg_recompile_shader( struct vg_shader *shader );
void vg_free_shader( struct vg_shader *shader );
vg_steam_async_call *vg_alloc_async_steam_api_call(void)
{
- if( vg_steam.call_count == vg_list_size(vg_steam.calls) ){
+ if( vg_steam.call_count == VG_ARRAY_LEN(vg_steam.calls) )
+ {
vg_fatal_error( "Maximum concurrent API calls exceeded (%u)\n",
vg_steam.call_count );
}
void steam_register_callback( u32 id, void (*p_handler)( CallbackMsg_t *msg ) )
{
if( vg_steam.callback_handler_count ==
- vg_list_size(vg_steam.callback_handlers) )
+ VG_ARRAY_LEN(vg_steam.callback_handlers) )
{
vg_fatal_error( "Too many steam callback handlers registered (%u)\n",
vg_steam.callback_handler_count );
*/
void vg_strnull( vg_str *str, char *buffer, i32 len )
{
- if( len == -1 ) vg_fatal_error( "waaaa" );
+ VG_ASSERT( len >= 0 );
str->buffer = buffer;
if( buffer )
}
else if( behaviour == k_strncpy_overflow_fatal )
{
- vg_fatal_error( "Strncpy dest exceeded buffer length\n" );
+ vg_fatal_condition();
+ vg_info( "vg_strncpy to buffer with maximum length '%u' exceeded"
+ " the end of the buffer.\n", len );
+ vg_fatal_exit();
}
}
}
static void _vg_strcatf_va( vg_str *str, const char *fmt, va_list args )
{
char buffer[4096];
- vsnprintf( buffer, vg_list_size(buffer), fmt, args );
+ vsnprintf( buffer, VG_ARRAY_LEN(buffer), fmt, args );
vg_strcat( str, buffer );
}
static void async_vg_tex2d_upload( void *payload, u32 size )
{
- if( vg_thread_purpose() != k_thread_purpose_main ){
- vg_fatal_error( "Catastrophic programming error.\n" );
- }
+ VG_ASSERT( vg_thread_purpose() == k_thread_purpose_main );
struct texture_load_info *info = payload;
void vg_tex2d_load_qoi_async_file( const char *path, u32 flags, GLuint *dest )
{
if( vg_thread_purpose() != k_thread_purpose_loader )
- vg_fatal_error( "wrong thread\n" );
+ vg_fatal_error( "Called aync texture load from wrong thread (main)\n" );
vg_linear_clear( vg_mem.scratch );
#include "vg_mem_queue.c"
#include "vg_io.c"
+void vg_fatal_exit(void)
+{
+ exit(1);
+}
+
void vg_fatal_error( const char *fmt, ... )
{
+ vg_fatal_condition();
+
va_list args;
va_start( args, fmt );
_vg_logx_va( stderr, NULL, "fatal", KRED, fmt, args );
va_end( args );
- exit(1);
+
+ vg_fatal_exit();
}
#pragma once
#include "vg_log.h"
-void vg_fatal_error( const char *fmt, ... );
u16 start = ctx->cur_vert;
u32 mesh[] = { 0,2,1, 0,3,2 };
- for( u32 i=0; i<vg_list_size(mesh); i++ )
+ for( u32 i=0; i<VG_ARRAY_LEN(mesh); i++ )
indices[i] = start+mesh[i];
ctx->cur_indice += 6;
mask = UI_TOP|UI_LEFT|UI_BOTTOM|UI_RIGHT;
u32 c = 0;
- for( u32 i=0; i<vg_list_size(mesh)/6; i++ )
+ for( u32 i=0; i<VG_ARRAY_LEN(mesh)/6; i++ )
{
if( (0x1<<i) & mask )
{
{
ui_rect window = {ctx->area[0]-256,0,256,ctx->area[1]}, swatch;
- const char *names[vg_list_size(ctx->scheme)] = {
+ const char *names[VG_ARRAY_LEN(ctx->scheme)] = {
[k_ui_bg] = "k_ui_bg", "k_ui_bg+1", "k_ui_bg+2", "k_ui_bg+3",
"k_ui_bg+4", "k_ui_bg+5", "k_ui_bg+6", "k_ui_bg+7",
ui_rect col[2];
ui_split_ratio( window, k_ui_axis_v, 0.5f, 0, col[0], col[1] );
- for( int i=0; i<vg_list_size(ctx->scheme); i++ )
+ for( int i=0; i<VG_ARRAY_LEN(ctx->scheme); i++ )
{
int which = (i/8)%2;
glUniform1f( glGetUniformLocation(_shader_ui_hsv.id,"uHue"), inf->hue );
}
else
- vg_fatal_error( "Invalid UI shader (%d)\n", shader );
+ {
+ vg_fatal_condition();
+ vg_info( "Invalid UI shader (%d)\n", shader );
+ vg_fatal_exit();
+ }
glDrawElements( GL_TRIANGLES, batch->indice_count, GL_UNSIGNED_SHORT,
(void *)((size_t)batch->indice_offset) );
if( ev.mod & KMOD_ALT )
mod |= KMOD_ALT;
- for( int i=0; i<vg_list_size( mappings ); i++ )
+ for( int i=0; i<VG_ARRAY_LEN( mappings ); i++ )
{
struct textbox_mapping *mapping = &mappings[i];
void vg_ui_init(void)
{
- if( !vg_shader_compile( &_shader_ui ) ||
- !vg_shader_compile( &_shader_ui_hsv ) ||
- !vg_shader_compile( &_shader_ui_image ) )
- {
- vg_fatal_error( "" );
- }
+ vg_compile_shader( &_shader_ui );
+ vg_compile_shader( &_shader_ui_hsv );
+ vg_compile_shader( &_shader_ui_image );
u32 verts = 30000, indices = 20000;
ui_init( &vg_ui.ctx,
glTexImage2D( GL_TEXTURE_2D, 0, GL_R8, sheet->w, sheet->h, 0,
GL_RED, GL_UNSIGNED_BYTE, image );
- VG_CHECK_GL_ERR();
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );