VG_SEMAPHORE_POST( queue->work_semaphore );
}
+/*
+ * simple functions
+ * ------------------------------------------------------------------------------------------------------------------ */
struct simple_function_info
{
void (*fn)(void *userdata);
info->userdata = userdata;
vg_async_task_dispatch( task, simple_function_call );
}
+
+/*
+ * Coroutines
+ * ------------------------------------------------------------------------------------------------------------------ */
+
+bool co_begin( vg_coroutine *co )
+{
+ co->i = 0;
+ if( co->state == k_coroutine_state_none )
+ {
+ co->state = k_coroutine_state_init;
+ return 1;
+ }
+ else
+ {
+ co->state = k_coroutine_state_run;
+ return 0;
+ }
+}
+
+void co_thread( vg_coroutine *co, i32 thread_id, vg_async_queue *queue )
+{
+ co->worker_queues[thread_id] = queue;
+}
+
+void *co_storage( vg_coroutine *co, u16 size )
+{
+ co->data_size = size;
+ co->task = vg_allocate_async_task( co->worker_queues[0], sizeof(vg_coroutine) + size, 1 );
+ vg_coroutine *next_co = (void *)co->task->data;
+ memcpy( next_co, co, sizeof(vg_coroutine) );
+ memset( next_co->data, 0, size );
+ return next_co->data;
+}
+
+static void co_internal_call( vg_async_task *task )
+{
+ vg_coroutine *co = (void *)task->data;
+ co->userdata = NULL;
+ co->task = NULL;
+ co->fn( co );
+}
+
+bool co_step( vg_coroutine *co, i32 thread_id )
+{
+ if( co->state == k_coroutine_state_run )
+ {
+ if( co->i == co->step )
+ {
+ if( thread_id == co->thread )
+ {
+ co->step ++;
+ co->i ++;
+ return 1;
+ }
+ else
+ {
+ co->thread = thread_id;
+ u32 size = sizeof(vg_coroutine) + co->data_size;
+ co->task = vg_allocate_async_task( co->worker_queues[ thread_id ], size, 1 );
+ vg_coroutine *co_copy = (void *)co->task->data;
+ memcpy( co_copy, co, size );
+ co->state = k_coroutine_state_orphan;
+ return 0;
+ }
+ }
+ else
+ co->i ++;
+ }
+
+ return 0;
+}
+
+void co_end( vg_coroutine *co )
+{
+ if( co->state == k_coroutine_state_init )
+ {
+ if( !co->task )
+ co_storage( co, 0 );
+ }
+
+ if( co->task )
+ vg_async_task_dispatch( co->task, co_internal_call );
+}
+
+void co_run( void(*fn)(vg_coroutine *co), void *userdata )
+{
+ vg_coroutine bootstrap = {0};
+ bootstrap.userdata = userdata;
+ bootstrap.state = k_coroutine_state_none;
+ bootstrap.thread = 0xffff;
+ bootstrap.fn = fn;
+ fn( &bootstrap );
+}
typedef struct vg_async_queue vg_async_queue;
typedef struct vg_async_task vg_async_task;
+typedef struct vg_coroutine vg_coroutine;
struct vg_async_queue
{
u8 data[];
};
+struct vg_coroutine
+{
+ void *userdata;
+ vg_async_task *task;
+ vg_async_queue *worker_queues[2];
+ void (*fn)(vg_coroutine *co);
+
+ u16 step, i, thread;
+
+ enum
+ {
+ k_coroutine_state_none,
+ k_coroutine_state_init,
+ k_coroutine_state_run,
+ k_coroutine_state_orphan
+ }
+ state;
+
+ u16 data_size;
+ u8 data[];
+};
+
+void *co_storage( vg_coroutine *co, u16 size );
+bool co_begin( vg_coroutine *co );
+void co_thread( vg_coroutine *co, i32 thread_id, vg_async_queue *queue );
+bool co_step( vg_coroutine *co, i32 thread_id );
+void co_run( void(*fn)(vg_coroutine *co), void *userdata );
+void co_end( vg_coroutine *co );
+
bool vg_init_async_queue( vg_async_queue *queue );
void vg_free_async_queue( vg_async_queue *queue );
void vg_console_reg_var( const char *alias, void *ptr, enum vg_var_dtype type, u32 flags )
{
- VG_ASSERT( vg_thread_purpose() != k_thread_purpose_main );
+ THREAD_1;
VG_ASSERT( vg_console.var_count < VG_ARRAY_LEN(vg_console.vars) );
vg_var *var = &vg_console.vars[ vg_console.var_count ++ ];
int (*function)(int argc, const char *argv[]),
void (*poll_suggest)(int argc, const char *argv[]) )
{
- VG_ASSERT( vg_thread_purpose() != k_thread_purpose_main );
+ THREAD_1;
VG_ASSERT( vg_console.function_count < VG_ARRAY_LEN(vg_console.functions) );
vg_cmd *cmd = &vg_console.functions[ vg_console.function_count ++ ];
}
};
-const u32 k_thread_purpose_nothing = 0x00;
-const u32 k_thread_purpose_main = 0x01;
-const u32 k_thread_purpose_loader = 0x02;
+u32 _thread_purpose_main = 0x01;
+u32 _thread_purpose_loader = 0x01;
u32 vg_thread_purpose(void)
{
void vg_auto_shader_register(void); /* created from codegen */
#endif
-static void _vg_load_step0(void *_);
-static void _vg_load_step1(void *_);
-static void _vg_load_step2(void *_);
-static void _vg_load_step_complete(void *_);
-
-static void _vg_load_step0(void *_)
+static void vg_load_co( vg_coroutine *co )
{
- THREAD_1;
-vg_info(" Copyright . . . -----, ,----- ,---. .---. \n" );
-vg_info(" 2021-2025 |\\ /| | / | | | | /| \n" );
-vg_info(" | \\ / | +-- / +----- +---' | / | \n" );
-vg_info(" | \\ / | | / | | \\ | / | \n" );
-vg_info(" | \\/ | | / | | \\ | / | \n" );
-vg_info(" ' ' '--' [] '----- '----- ' ' '---' "
- "SOFTWARE\n" );
-
- vg_preload();
- vg_tex2d_replace_with_error_async( 0, &vg.tex_missing );
- vg_async_call( &vg.main_tasks, _vg_load_step1, NULL );
-}
+ if( co_begin( co ) )
+ {
+ co_thread( co, 0, &vg.main_tasks );
+ co_thread( co, 1, &vg.loader_tasks );
+ }
-static void _vg_load_step1(void *_)
-{
- THREAD_0;
- vg_async_call( &vg.loader_tasks, _vg_load_step2, NULL );
-}
+ if( co_step( co, 1 ) )
+ {
+ vg_info(" Copyright . . . -----, ,----- ,---. .---. \n" );
+ vg_info(" 2021-2025 |\\ /| | / | | | | /| \n" );
+ vg_info(" | \\ / | +-- / +----- +---' | / | \n" );
+ vg_info(" | \\ / | | / | | \\ | / | \n" );
+ vg_info(" | \\/ | | / | | \\ | / | \n" );
+ vg_info(" ' ' '--' [] '----- '----- ' ' '---' "
+ "SOFTWARE\n" );
+
+ vg_tex2d_replace_with_error_async( 0, &vg.tex_missing );
+ }
-static void _vg_load_step2(void *_)
-{
- THREAD_1;
- vg_ui.tex_bg = vg.tex_missing;
+ if( co_step( co, 0 ) )
+ {
+ vg_ui.tex_bg = vg.tex_missing;
+ }
- /* internal */
- vg_loader_step( vg_framebuffer_init, NULL );
- vg_loader_step( vg_render_init, NULL );
- vg_loader_step( vg_input_init, vg_input_free );
- vg_loader_step( vg_lines_init, NULL );
- vg_loader_step( vg_rb_view_init, NULL );
- _vg_profile_reg_set( &_vg_prof_gameloop );
+ if( co_step( co, 1 ) )
+ {
+ /* internal */
+ vg_loader_step( vg_framebuffer_init, NULL );
+ vg_loader_step( vg_render_init, NULL );
+ vg_loader_step( vg_input_init, vg_input_free );
+ vg_loader_step( vg_lines_init, NULL );
+ vg_loader_step( vg_rb_view_init, NULL );
+ _vg_profile_reg_set( &_vg_prof_gameloop );
#ifndef VG_NO_AUDIO
- vg_loader_step( vg_audio_init, vg_audio_free );
+ vg_loader_step( vg_audio_init, vg_audio_free );
#endif
- vg_loader_step( vg_profiler_init, NULL );
- vg_loader_step( vg_mem_view_init, NULL );
+ vg_loader_step( vg_profiler_init, NULL );
+ vg_loader_step( vg_mem_view_init, NULL );
- /* client */
+ /* client */
#ifdef VG_CUSTOM_SHADERS
- vg_auto_shader_register();
+ vg_auto_shader_register();
#endif
- vg_load();
-}
-
-void _vg_load_temp_end(void)
-{
- vg_async_call( &vg.main_tasks, _vg_load_step_complete, NULL );
- vg_success( "Client loaded in %fs\n", vg.time_real );
-}
-
-static void _vg_load_step_complete(void *_)
-{
- vg_success( "Internal async setup complete\n" );
+ //vg_success( "Client loaded in %fs\n", vg.time_real );
+ }
- if( SDL_AtomicGet( &vg.engine_status ) == k_engine_status_crashed )
- return;
- else
+ if( co_step( co, 0 ) )
+ {
SDL_AtomicSet( &vg.engine_status, k_engine_status_running );
+ _vg_tower_set_flag( vg.sig_engine, 1 );
+ }
- vg_magi_restore();
+ co_end( co );
}
static void _vg_process_events(void)
}
}
-static void _vg_process_launch_opts_internal( int argc, char *argv[] )
-{
- char *arg;
- while( vg_argp( argc, argv ) )
- {
- if( (arg = vg_opt_arg( 'w', "Render output width" )) )
- vg.window_x = atoi( arg );
-
- if( (arg = vg_opt_arg( 'h', "Render output height" )) )
- vg.window_y = atoi( arg );
-
- if( (arg = vg_long_opt_arg( "samples", "Rendering samples per pixel" )) )
- vg.samples = VG_MAX( 0, VG_MIN( 8, atoi( arg ) ) );
-
- if( vg_long_opt( "use-libc-malloc", "Use standard libc allocator" ) )
- vg_mem.use_libc_malloc = 1;
-
- if( vg_long_opt( "high-performance", "Turn graphics to lowest quality" ) )
- vg.quality_profile = k_quality_profile_low;
-
- if( (arg = vg_long_opt_arg( "load-step-delay", "Loader step delay (ms)" )) )
- vg.load_step_delay = atoi(arg);
-
- vg_launch_opt();
-
- if( vg_long_opt( "help", "Helps you" ) )
- {
- _vg_print_options();
- exit(0);
- }
- }
-}
-
static void _vg_init_window( const char *window_name )
{
vg_info( "SDL_INIT\n" );
static int _vg_loader_thread( void *pfn )
{
- SDL_TLSSet( vg.thread_purpose, &k_thread_purpose_loader, NULL );
+ SDL_TLSSet( vg.thread_purpose, &_thread_purpose_loader, NULL );
if( setjmp( vg.env_loader_exit ) )
return 0;
}
static int cmd_vg_settings_toggle( int argc, const char *argv[] );
-void vg_enter( int argc, char *argv[], const char *window_name )
+void vg_init( int argc, const char *argv[], const char *window_name )
{
+ vg.thread_purpose = SDL_TLSCreate();
+ VG_ASSERT( vg.thread_purpose );
+ SDL_TLSSet( vg.thread_purpose, &_thread_purpose_main, NULL );
+
+ vg_log_init();
+
+ vg.sig_engine = _vg_tower_create_signal( "Engine" );
+ vg.sig_client = _vg_tower_create_signal( "Client" );
+
if( !vg_init_async_queue( &vg.main_tasks ) )
return;
if( !vg_init_async_queue( &vg.loader_tasks ) )
return;
- vg.thread_purpose = SDL_TLSCreate();
- VG_ASSERT( vg.thread_purpose );
+ vg_rand_seed( &vg.rand, 461 );
- /* we pretend to be loader thread while it doesn't exist */
- SDL_TLSSet( vg.thread_purpose, &k_thread_purpose_loader, NULL );
+ /* launch options */
+ _vg_opt_init( argc, argv );
+ const char *arg;
+ if( (arg = vg_opt_arg( 'w', "Render output width" )) )
+ vg.window_x = atoi( arg );
- vg_rand_seed( &vg.rand, 461 );
- _vg_process_launch_opts_internal( argc, argv );
+ if( (arg = vg_opt_arg( 'h', "Render output height" )) )
+ vg.window_y = atoi( arg );
+
+ if( (arg = vg_long_opt_arg( "samples", "Rendering samples per pixel" )) )
+ vg.samples = VG_MAX( 0, VG_MIN( 8, atoi( arg ) ) );
+
+ if( vg_long_opt( "use-libc-malloc", "Use standard libc allocator" ) )
+ vg_mem.use_libc_malloc = 1;
+
+ if( vg_long_opt( "high-performance", "Turn graphics to lowest quality" ) )
+ vg.quality_profile = k_quality_profile_low;
+
+ if( (arg = vg_long_opt_arg( "load-step-delay", "Loader step delay (ms)" )) )
+ vg.load_step_delay = atoi(arg);
+
+ vg.window_name = window_name;
+}
+
+void vg_run(void)
+{
+ if( !_vg_opt_check() )
+ exit(0);
/* Systems init */
vg_alloc_quota();
vg_console_reg_cmd( "vg_settings", cmd_vg_settings_toggle, NULL );
vg_console_reg_cmd( "vg_rtmemory", cmd_log_memory, NULL );
- _vg_init_window( window_name );
-
+ _vg_init_window( vg.window_name );
SDL_SetRelativeMouseMode(1);
-
- /* multi-threaded loading phase */
- SDL_AtomicSet( &vg.engine_status, k_engine_status_load_internal );
/* Opengl-required systems */
vg_ui_init();
vg_loader_step( vg_loader_init, vg_loader_free );
- vg_async_call( &vg.loader_tasks, _vg_load_step0, NULL );
- SDL_TLSSet( vg.thread_purpose, &k_thread_purpose_main, NULL );
+ SDL_AtomicSet( &vg.engine_status, k_engine_status_load_internal );
+ co_run( vg_load_co, NULL );
+
+ _thread_purpose_loader = 0x2;
SDL_CreateThread( _vg_loader_thread, "vg: loader", NULL );
_vg_gameloop();
_vg_terminate();
SDL_AtomicSet( &vg.engine_status, k_engine_status_crashed );
- if( vg_thread_purpose() == k_thread_purpose_loader )
+ if( vg_thread_purpose() == _thread_purpose_loader )
{
longjmp( vg.env_loader_exit, 1 );
}
#include "vg_render.c"
#include "vg_opengl.c"
#include "vg_mem_view.c"
+#include "vg_tower.c"
#ifdef VG_CUSTOM_SHADERS
#include "shaders/impl.c"
#pragma once
-/* Copyright (C) 2021-2024 Mt.Zero Software - All Rights Reserved */
-/*
- .-. VG Event loop
-| 0 |
-| | .---------------------------------------------------------.
-|API| | vg_enter( int argc, char *argv[], const char *window_name |
-| | '---------------------------------------------------------'
-| | |
-| | v
-|IMP| vg_launch_opt(void) <--.
-| | | |
-| | |'---------------'
-| | | .-.
-| | |'-----------------------------------| 1 |------.
-| | | | | |
-| | | | | v
-| | | |IMP| vg_preload(void)
-| | | | | |
-| | .-----+. | | v
-| | | | |IMP| vg_load(void)
-| | | v '___' |
-|IMP| | vg_framebuffer_resize(void) |
-| | | | |
-|IMP| | |.--------------------------------------------'
-| | | |
-| | | v
-|IMP| | vg_pre_update(void)
-| | | |
-| | | .-----+.
-| | | | | called 0x to 8x
-| | | | v
-|IMP| | '- vg_fixed_update(void)
-| | | |
-| | | .-'
-| | | |
-| | | v
-|IMP| | vg_post_update(void)
-| | | |
-| | | v
-|IMP| | vg_render(void)
-| | | |
-| | | v
-|IMP| | vg_gui(void)
-| | | |
-| | | v
-|IMP| | vg_game_settings_init(void)
-|IMP| | vg_game_settings_gui( ui_rect panel )
-| | | | (optional: #define VG_GAME_SETTINGS)
-| | | |
-| | '----'
-'___'
-
-*/
+/* Copyright (C) 2021-2025 Mt.Zero Software - All Rights Reserved */
/* configuration warnings */
#include "vg_string.h"
#include "vg_ui/imgui.h"
#include "vg_async2.h"
+#include "vg_tower.h"
#include <setjmp.h>
/* API */
-void vg_enter( int argc, char *argv[], const char *window_name );
+void vg_init( int argc, const char *argv[], const char *window_name );
+void vg_run(void);
/* Thread 1 */
void vg_bake_shaders(void);
-extern void vg_preload(void);
-extern void vg_load(void);
-
/* Main thread */
-extern void vg_launch_opt(void);
extern void vg_framebuffer_resize(int w, int h);
extern void vg_pre_update(void);
extern void vg_fixed_update(void);
/* Engine sync */
SDL_Window *window;
SDL_GLContext gl_context;
-
SDL_TLSID thread_purpose;
vg_async_queue main_tasks, loader_tasks;
jmp_buf env_loader_exit; /* for deep fatal error handling */
-
SDL_atomic_t engine_status;
+ vg_signal_id sig_engine, sig_client;
+
/* Window information */
int window_x,
window_y,
samples,
window_should_close;
- const char *base_path;
+ const char *base_path;
+ const char *window_name;
int display_refresh_rate,
fps_limit,
void ui_settings_ranged_i32_init( struct vg_setting_ranged_i32 *prop );
void ui_settings_enum_init( struct vg_setting_enum *prop );
bool vg_settings_enum_diff( struct vg_setting_enum *prop );
-bool vg_settings_enum( ui_context *ctx,
- struct vg_setting_enum *prop, ui_rect rect );
-void vg_settings_ui_header( ui_context *ctx,
- ui_rect inout_panel, const char *name );
-bool vg_settings_apply_button( ui_context *ctx,
- ui_rect inout_panel, bool validated );
-
+bool vg_settings_enum( ui_context *ctx, struct vg_setting_enum *prop, ui_rect rect );
+void vg_settings_ui_header( ui_context *ctx, ui_rect inout_panel, const char *name );
+bool vg_settings_apply_button( ui_context *ctx, ui_rect inout_panel, bool validated );
enum engine_status _vg_engine_status(void);
-
-extern const u32 k_thread_purpose_nothing;
-extern const u32 k_thread_purpose_main;
-extern const u32 k_thread_purpose_loader;
+extern u32 _thread_purpose_main;
+extern u32 _thread_purpose_loader;
u32 vg_thread_purpose(void);
-void _vg_load_temp_end(void);
-#define THREAD_0 VG_ASSERT( vg_thread_purpose() == k_thread_purpose_main )
-#define THREAD_1 VG_ASSERT( vg_thread_purpose() == k_thread_purpose_loader )
+#define THREAD_0 VG_ASSERT( vg_thread_purpose() == _thread_purpose_main )
+#define THREAD_1 VG_ASSERT( vg_thread_purpose() == _thread_purpose_loader )
void vg_checkgl( const char *src_info );
#define VG_STRINGIT( X ) #X
#include "vg_engine.h"
#include "vg_loader.h"
#include "vg_shader.h"
+#include "vg_async2.h"
struct vg_loader vg_loader;
void vg_loader_set_user_information( const char *information )
{
- if( vg_thread_purpose() == k_thread_purpose_loader )
+ if( vg_thread_purpose() == _thread_purpose_loader )
{
vg_async_task *task = vg_allocate_async_task( &vg.main_tasks, sizeof(struct async_set_information_args), 1 );
struct async_set_information_args *args = (void *)task->data;
enum engine_status status = SDL_AtomicGet( &vg.engine_status );
- if( status != k_engine_status_load_internal )
+ if( status == k_engine_status_crashed )
{
- vg_info( "Joining loader thread.\n" );
longjmp( vg.env_loader_exit, 1 );
}
}
+
#include "vg_platform.h"
#include "vg_engine.h"
+#define VG_ENGINE_READY 0x1
+#define VG_CLIENT_READY 0x2
+#define VG_ALL_READY (VG_ENGINE_READY|VG_CLIENT_READY)
+#define VG_READYNESS_MAX 0x8000
+#define VG_CLIENT_READYNESS_MAX 0x80000000
+
struct vg_loader
{
/* Shutdown steps */
u32 step_count, step_action;
GLuint vao, vbo;
-
const char *information_for_user;
+
+ u32 readyness;
}
extern vg_loader;
/*
- * Copyright (C) 2021-2024 Mt.ZERO Software, Harry Godden - All Rights Reserved
+ * Copyright (C) 2021-2025 Mt.ZERO Software, Harry Godden - All Rights Reserved
*/
#include "vg_opt.h"
* standard agument | regular_thing
*/
-static int vg_argi = 1;
-static int vg_argj = 1;
-static int vg_argc = 0;
-static int vg_consume_next = 0;
-static char **vg_argv;
-
-enum vg_opt_type
-{
- k_vg_opt_type_standard,
- k_vg_opt_type_flag,
- k_vg_opt_type_arg,
- k_vg_opt_type_long_flag,
- k_vg_opt_type_long_arg
-};
-
-struct _vg_opt_reg
-{
- const char *alias, *desc;
- char alias_c;
- u8 type;
-}
-static _vg_all_opts[32];
-static u32 _vg_opt_count = 0;
-
-static void _vg_opt_observe( const char *alias, char alias_c, const char *desc,
- enum vg_opt_type type )
+struct
{
- for( u32 i=0; i<_vg_opt_count; i ++ )
+ struct vg_opt_reg
{
- struct _vg_opt_reg *reg = &_vg_all_opts[i];
- if( (type == k_vg_opt_type_flag || type == k_vg_opt_type_arg)
- && reg->alias_c == alias_c )
- {
- return;
- }
-
- if( (type == k_vg_opt_type_long_flag || type == k_vg_opt_type_long_arg)
- && reg->alias == alias )
- {
- return;
- }
+ const char *alias, *desc;
+ char alias_c;
- if( (type == k_vg_opt_type_standard)
- && (reg->alias == NULL && reg->alias_c == 0) )
+ enum opt_type
{
- return;
+ k_opt_flag,
+ k_opt_opt,
+ k_opt_long_flag,
+ k_opt_long_opt
}
+ type;
}
+ infos[32];
+ u32 info_count;
- if( _vg_opt_count < VG_ARRAY_LEN( _vg_all_opts ) )
+ struct vg_arg
{
- struct _vg_opt_reg *reg = &_vg_all_opts[ _vg_opt_count ++ ];
- reg->alias = alias;
- reg->alias_c = alias_c;
- reg->desc = desc;
- reg->type = type;
+ enum arg_type
+ {
+ k_arg_singles,
+ k_arg_long,
+ k_arg_assign,
+ k_arg_regular
+ }
+ type;
+
+ u32 arg_len;
+ const char *arg, *value;
+ u32 used;
}
+ args[32];
+ u32 arg_count;
}
+_vg_opt;
-void _vg_print_options(void)
+static void _vg_opt_reg( struct vg_opt_reg reg )
{
- for( u32 i=0; i<_vg_opt_count; i ++ )
- {
- struct _vg_opt_reg *reg = &_vg_all_opts[i];
-
- if( reg->type == k_vg_opt_type_flag )
- printf( "-%c %s\n", reg->alias_c, reg->desc );
-
- if( reg->type == k_vg_opt_type_arg )
- printf( "-%c <value> %s\n", reg->alias_c, reg->desc );
+ if( _vg_opt.info_count < VG_ARRAY_LEN( _vg_opt.infos ) )
+ _vg_opt.infos[ _vg_opt.info_count ++ ] = reg;
+}
- if( reg->type == k_vg_opt_type_long_flag )
- printf( "--%-21s %s\n", reg->alias, reg->desc );
+void _vg_opt_init( int argc, const char *argv[] )
+{
+ if( argc+1 >= VG_ARRAY_LEN( _vg_opt.args ) )
+ {
+ vg_error( "Too many arguments!\n" );
+ exit(-1);
+ }
- if( reg->type == k_vg_opt_type_long_arg )
+ _vg_opt.arg_count = 0;
+ for( u32 i=1; i<argc; i ++ )
+ {
+ const char *v = argv[i];
+ struct vg_arg *arg = &_vg_opt.args[ _vg_opt.arg_count ++ ];
+ arg->arg = NULL;
+ arg->value = NULL;
+ arg->arg_len = 0;
+ arg->used = 0;
+ if( v[0] == '-' )
{
- char temp[32];
- snprintf( temp, 32, "--%s=<value>", reg->alias );
- printf( "%-23s %s\n", temp, reg->desc );
+ if( v[1] == '-' )
+ {
+ arg->arg = v+2;
+ arg->type = k_arg_long;
+ u32 k=2;
+ while( v[ k ] )
+ {
+ if( v[ k ] == '=' )
+ {
+ arg->arg_len = k-2;
+ arg->value = v + k + 1;
+ arg->type = k_arg_assign;
+ goto next;
+ }
+ k ++;
+ }
+ }
+ else
+ {
+ arg->arg = v+1;
+ arg->type = k_arg_singles;
+ u32 k=1;
+ while( v[k] )
+ k ++;
+ arg->arg_len = k-1;
+ arg->used = ~((0x1<<arg->arg_len)-1);
+ }
}
-
- if( reg->type == k_vg_opt_type_standard )
+ else
{
- printf( "<standard> %s\n", reg->desc );
+ arg->type = k_arg_regular;
+ arg->value = v;
+ arg->arg = v;
}
+next:;
}
}
-/* Will return 0 if exhausted */
-int vg_argp( int argc, char *argv[] )
+bool _vg_opt_check(void)
{
- vg_argv = argv;
- vg_argc = argc;
-
- static int delta_i = 0;
- static int delta_j = 0;
-
- if( vg_argj != 1 && !vg_argv[ vg_argi ][ vg_argj ] )
+ if( vg_long_opt( "help", "Helps you" ) )
{
- vg_argj = 1;
- vg_argi ++;
- }
+ for( u32 i=0; i<_vg_opt.info_count; i ++ )
+ {
+ struct vg_opt_reg *reg = &_vg_opt.infos[i];
+ const char *desc = reg->desc? reg->desc: "";
- if( vg_consume_next )
- {
- vg_consume_next = 0;
- vg_argi ++;
- }
+ if( reg->type == k_opt_flag )
+ printf( "-%c %s\n", reg->alias_c, desc );
- if( vg_argi >= argc )
- return 0;
+ if( reg->type == k_opt_opt )
+ printf( "-%c <value> %s\n", reg->alias_c, desc );
- if( (delta_i == vg_argi) && (delta_j == vg_argj) )
- {
- char *cur = &vg_argv[ vg_argi ][ vg_argj ];
-
- if( *cur != '-' )
- {
- vg_error( "Unknown opt '-%c'\n", *cur );
+ if( reg->type == k_opt_long_flag )
+ printf( "--%-21s %s\n", reg->alias, desc );
+
+ if( reg->type == k_opt_long_opt )
+ {
+ char temp[32];
+ snprintf( temp, 32, "--%s=<value>", reg->alias );
+ printf( "%-23s %s\n", temp, desc );
+ }
}
- else
+ exit(0);
+ }
+
+ bool errors = 0;
+ for( u32 i=0; i<_vg_opt.arg_count; i ++ )
+ {
+ struct vg_arg *arg = &_vg_opt.args[ i ];
+ if( arg->used != 0xffffffff )
{
- vg_error( "Unknown opt '--%s'\n", cur + 1 );
+ if( arg->type == k_arg_singles )
+ {
+ for( u32 j=0; j<32; j ++ )
+ {
+ if( !(arg->used & (0x1<<j)) )
+ vg_error( "Unknown option '%c'\n", arg->arg[j] );
+ }
+ }
+ else
+ vg_error( "Unknown option '%s'\n", arg->arg );
+ errors = 1;
}
-
- exit(0);
}
-
- delta_i = vg_argi;
- delta_j = vg_argj;
- return 1;
+ return errors == 0;
}
-/* Example: see if -c is set */
-int vg_opt( char c, const char *desc )
+bool vg_opt( char c, const char *desc )
{
- _vg_opt_observe( NULL, c, desc, k_vg_opt_type_flag );
-
- char *carg = vg_argv[ vg_argi ];
-
- if( carg[0] == '-' )
+ _vg_opt_reg( (struct vg_opt_reg){ .alias=NULL, .alias_c=c, .desc=desc, .type=k_opt_flag } );
+ for( u32 i=0; i<_vg_opt.arg_count; i ++ )
{
- if( carg[1] == '-' )
- return 0;
-
- if( carg[ vg_argj ] == c )
+ struct vg_arg *arg = &_vg_opt.args[ i ];
+ if( arg->type == k_arg_singles )
{
- vg_argj ++;
-
- return 1;
+ for( u32 j=0; j<arg->arg_len; j ++ )
+ {
+ if( arg->arg[j] == c )
+ {
+ arg->used |= 0x1 << j;
+ return 1;
+ }
+ }
}
}
-
return 0;
}
-/* Example: get -c *value* */
-char *vg_opt_arg( char c, const char *desc )
-{
- _vg_opt_observe( NULL, c, desc, k_vg_opt_type_arg );
-
- if( vg_opt( c, NULL ) )
+const char *vg_opt_arg( char c, const char *desc )
+{
+ _vg_opt_reg( (struct vg_opt_reg){ .alias=NULL, .alias_c=c, .desc=desc, .type=k_opt_opt } );
+ for( u32 i=0; i+1<_vg_opt.arg_count; i ++ )
{
- if( vg_argi < vg_argc-1 )
+ struct vg_arg *arg = &_vg_opt.args[ i ];
+ if( arg->type == k_arg_singles )
{
- if( vg_argv[ vg_argi + 1 ][0] != '-' )
+ for( u32 j=0; j<arg->arg_len; j ++ )
{
- vg_consume_next = 1;
- return vg_argv[ vg_argi + 1 ];
+ if( arg->arg[j] == c )
+ {
+ arg->used |= 0x1 << j;
+ return _vg_opt.args[ i + 1 ].value;
+ }
}
}
-
- vg_error( "Option '%c' requires argument!\n", c );
- exit(0);
}
-
return NULL;
}
-/* Example see if --big is set */
-int vg_long_opt( char *name, const char *desc )
-{
- _vg_opt_observe( name, 0, desc, k_vg_opt_type_long_flag );
-
- char *carg = vg_argv[ vg_argi ];
-
- if( carg[0] == '-' )
+bool vg_long_opt( char *name, const char *desc )
+{
+ _vg_opt_reg( (struct vg_opt_reg){ .alias=name, .alias_c=0, .desc=desc, .type=k_opt_long_flag } );
+ for( u32 i=0; i<_vg_opt.arg_count; i ++ )
{
- if( carg[1] == '-' )
+ struct vg_arg *arg = &_vg_opt.args[ i ];
+ if( arg->type == k_arg_long )
{
- if( !strcmp( name, carg+2 ) )
+ if( !strcmp( arg->arg, name ) )
{
- vg_consume_next = 1;
+ arg->used = 0xffffffff;
return 1;
}
}
}
-
return 0;
}
-/* Example: get --big=value */
-char *vg_long_opt_arg( char *name, const char *desc )
-{
- _vg_opt_observe( name, 0, desc, k_vg_opt_type_long_arg );
-
- char *carg = vg_argv[ vg_argi ];
-
- if( carg[0] == '-' )
+const char *vg_long_opt_arg( char *name, const char *desc )
+{
+ _vg_opt_reg( (struct vg_opt_reg){ .alias=name, .alias_c=0, .desc=desc, .type=k_opt_long_opt } );
+ for( u32 i=0; i<_vg_opt.arg_count; i ++ )
{
- if( carg[1] == '-' )
+ struct vg_arg *arg = &_vg_opt.args[ i ];
+ if( arg->type == k_arg_assign )
{
- int k = 2; int set = 0;
- while( carg[ k ] )
+ if( !strncmp( arg->arg, name, arg->arg_len ) )
{
- if( carg[ k ] == '=' )
- {
- set = 1;
- break;
- }
-
- k ++;
+ arg->used = 0xffffffff;
+ return arg->value;
}
-
- if( !strncmp( name, carg+2, k-2 ) )
- {
- vg_consume_next = 1;
-
- // the rest
- if( set )
- {
- return carg + k + 1;
- }
- else
- {
- vg_error( "Long option '%s' requires argument\n", name );
- }
- }
}
}
-
return NULL;
}
-/* Example: get regular_thing */
-char *vg_arg( const char *desc )
-{
- _vg_opt_observe( NULL, 0, desc, k_vg_opt_type_standard );
-
- char *carg = vg_argv[ vg_argi ];
-
- if( carg[0] != '-' )
+const char *vg_arg( u32 index )
+{
+ u32 count = 0;
+ for( u32 i=0; i<_vg_opt.arg_count; i ++ )
{
- vg_consume_next = 1;
- return carg;
+ struct vg_arg *arg = &_vg_opt.args[ i ];
+ if( arg->type == k_arg_regular )
+ {
+ count ++;
+ if( index+1 == count )
+ {
+ arg->used = 0xffffffff;
+ return arg->value;
+ }
+ }
}
-
return NULL;
}
/*
- * Copyright (C) 2021-2024 Mt.ZERO Software - All Rights Reserved
+ * Copyright (C) 2021-2025 Mt.ZERO Software - All Rights Reserved
*/
#pragma once
+#include "vg_platform.h"
-/* Will return 0 if exhausted */
-int vg_argp( int argc, char *argv[] );
+void _vg_opt_init( int argc, const char *argv[] );
+bool _vg_opt_check(void);
/* Example: see if -c is set */
-int vg_opt( char c, const char *desc );
+bool vg_opt( char c, const char *desc );
/* Example: get -c *value* */
-char *vg_opt_arg( char c, const char *desc );
+const char *vg_opt_arg( char c, const char *desc );
/* Example see if --big is set */
-int vg_long_opt( char *name, const char *desc );
+bool vg_long_opt( char *name, const char *desc );
/* Example: get --big=value */
-char *vg_long_opt_arg( char *name, const char *desc );
+const char *vg_long_opt_arg( char *name, const char *desc );
/* Example: get regular_thing */
-char *vg_arg( const char *desc );
-
-/* You should probably bind this to --help (and call it last!) */
-void _vg_print_options(void);
+const char *vg_arg( u32 index );
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( "Called aync texture load from wrong thread (main)\n" );
-
+ THREAD_1;
vg_linear_clear( vg_mem.scratch );
u32 size;
--- /dev/null
+#pragma once
+#include "vg_tower.h"
+
+struct _vg_tower _vg_tower;
+
+vg_signal_id _vg_tower_create_signal( const char *name )
+{
+ THREAD_0;
+ VG_ASSERT( _vg_tower.signal_count < VG_ARRAY_LEN( _vg_tower.signals ) );
+ vg_signal_id id = _vg_tower.signal_count;
+ struct signal_info *inf = &_vg_tower.signals[ id ];
+ inf->name = name;
+ _vg_tower.signal_count ++;
+ return id;
+}
+
+void _vg_tower_register_trigger( u64 mask, void(*fn)( vg_signal_id id, bool state ) )
+{
+ THREAD_0;
+ VG_ASSERT( _vg_tower.trigger_count < VG_ARRAY_LEN( _vg_tower.triggers ) );
+ struct tower_trigger *trigger = &_vg_tower.triggers[ _vg_tower.trigger_count ++ ];
+ trigger->mask = mask;
+ trigger->fn = fn;
+}
+
+struct async_tower_info
+{
+ vg_signal_id id;
+ bool state;
+};
+static void _vg_tower_set_flag_recall( vg_async_task *task )
+{
+ struct async_tower_info *info = (void *)task->data;
+ _vg_tower_set_flag( info->id, info->state );
+}
+void _vg_tower_set_flag( vg_signal_id id, bool state )
+{
+ if( vg_thread_purpose() == _thread_purpose_loader )
+ {
+ vg_async_task *task = vg_allocate_async_task( &vg.main_tasks, sizeof(struct async_tower_info), 1 );
+ struct async_tower_info *info = (void *)task->data;
+ info->id = id;
+ info->state = state;
+ vg_async_task_dispatch( task, _vg_tower_set_flag_recall );
+ return;
+ }
+
+ THREAD_0;
+
+ u64 bit = 0x1lu << (u64)id;
+ if( state ) _vg_tower.state |= bit;
+ else _vg_tower.state &= ~bit;
+ vg_info( "[tower] %s:%s [%lx]\n", _vg_tower.signals[id].name, state? "true": "false", _vg_tower.state );
+
+ for( u32 i=0; i<_vg_tower.trigger_count; i ++ )
+ {
+ struct tower_trigger *trig = &_vg_tower.triggers[i];
+ if( trig->mask & bit )
+ {
+ trig->fn( id, state );
+ }
+ }
+
+#if 0
+ // TODO: Make subscription
+ if( (flag == VG_ENGINE_READY) && state )
+ {
+ vg_load();
+ }
+
+ if( (flag == VG_CLIENT_READY) && state )
+ {
+ vg_magi_restore();
+ }
+#endif
+}
+bool _vg_tower_clearence( u64 mask )
+{
+ THREAD_0;
+ return (_vg_tower.state & mask) == mask;
+}
+
+u64 _vg_tower_mask( vg_signal_id id )
+{
+ u64 bit = 0x1lu << (u64)id;
+ return bit;
+}
--- /dev/null
+#pragma once
+#include "vg_async2.h"
+
+typedef u8 vg_signal_id;
+
+struct _vg_tower
+{
+ struct tower_trigger
+ {
+ u64 mask;
+ void( *fn )( vg_signal_id id, bool state );
+ }
+ triggers[ 64 ];
+
+ struct signal_info
+ {
+ const char *name;
+ }
+ signals[ 64 ];
+
+ u32 trigger_count, signal_count;
+ u64 state;
+}
+extern _vg_tower;
+
+vg_signal_id _vg_tower_create_signal( const char *name );
+void _vg_tower_register_trigger( u64 mask, void(*fn)( vg_signal_id id, bool state ) );
+void _vg_tower_set_flag( vg_signal_id id, bool state );
+bool _vg_tower_clearence( u64 mask );
+u64 _vg_tower_mask( vg_signal_id id );