admin stuff
authorhgn <hgodden00@gmail.com>
Sat, 19 Apr 2025 08:34:58 +0000 (09:34 +0100)
committerhgn <hgodden00@gmail.com>
Sat, 19 Apr 2025 08:34:58 +0000 (09:34 +0100)
12 files changed:
vg_async2.c
vg_async2.h
vg_console.c
vg_engine.c
vg_engine.h
vg_loader.c
vg_loader.h
vg_opt.c
vg_opt.h
vg_tex.c
vg_tower.c [new file with mode: 0644]
vg_tower.h [new file with mode: 0644]

index 926cce6ea6b155b88e919f4cc88a3a4da23543d2..57e76ae55e87ceb577e92356ac76d93c208882b0 100644 (file)
@@ -129,6 +129,9 @@ void vg_async_queue_end( vg_async_queue *queue, enum async_quit quit )
    VG_SEMAPHORE_POST( queue->work_semaphore );
 }
 
+/* 
+ * simple functions
+ * ------------------------------------------------------------------------------------------------------------------ */
 struct simple_function_info
 {
    void (*fn)(void *userdata);
@@ -149,3 +152,97 @@ void vg_async_call( vg_async_queue *queue, void(*fn)(void *userdata), void *user
    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 );
+}
index 22c0e6c527b2cbe41a8a3bb62cf3e3ecbd1fa24c..80c2c532b63f61b2a78a714794c4bd70b3594862 100644 (file)
@@ -5,6 +5,7 @@
 
 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
 {
@@ -35,6 +36,35 @@ struct vg_async_task
    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 );
 
index 19937beb2b31add16b4c2497892bd5e6336e2509..e4e41dd8c8c8b01e36618be02b92fa7849f15014 100644 (file)
@@ -9,7 +9,7 @@ struct vg_console vg_console;
 
 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 ++ ];
@@ -25,7 +25,7 @@ void vg_console_reg_cmd( const char *alias,
                          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 ++ ];
index af6f137c36f862893d71a75fb193e768c5a5222c..fe16c7b869b978980c60d8ce4b420225479e176c 100644 (file)
@@ -16,9 +16,8 @@ struct vg_engine vg =
    }
 };
 
-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)
 {
@@ -81,75 +80,62 @@ void vg_bake_shaders(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)
@@ -511,39 +497,6 @@ static void _vg_gameloop(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" );
@@ -715,7 +668,7 @@ static int cmd_log_memory( int argc, const char *argv[] )
 
 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;
@@ -725,21 +678,52 @@ static int _vg_loader_thread( void *pfn )
 }
 
 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();
@@ -756,19 +740,17 @@ void vg_enter( int argc, char *argv[], const char *window_name )
 
    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();
@@ -802,7 +784,7 @@ void vg_fatal_exit(void)
 
    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 );
    }
@@ -1336,6 +1318,7 @@ __attribute__((used)) int AmdPowerXpressRequestHighPerformance = 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"
index 1b977cac358afa3a55285197b734fd6c92db7956..2cc8b6d18808b7bb1eda3f0138d07d27a9908e0e 100644 (file)
@@ -1,58 +1,6 @@
 #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);
@@ -125,20 +71,21 @@ struct vg_engine
    /* 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,
@@ -242,24 +189,17 @@ struct vg_setting_ranged_i32
 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
index f22a826b238e17cbf1669fd82e38fadee311f805..bbd134df0db39bf6ff68a3c39690daa7da0a3fcf 100644 (file)
@@ -1,6 +1,7 @@
 #include "vg_engine.h"
 #include "vg_loader.h"
 #include "vg_shader.h"
+#include "vg_async2.h"
 
 struct vg_loader vg_loader;
 
@@ -108,7 +109,7 @@ void async_loader_set_user_information( vg_async_task *task )
 
 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;
@@ -193,9 +194,9 @@ void _vg_loader_step( void( *fn_load )(void), void( *fn_free )(void), const char
 
    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 );
    }
 }
+
index 8f43b3afe2f7f514ec07912b86e901088a1b1a80..9dfb600e40ee4ab087240dfdf7375233475003ab 100644 (file)
 #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 */
@@ -24,8 +30,9 @@ struct vg_loader
    u32 step_count, step_action;
 
    GLuint vao, vbo;
-
    const char *information_for_user;
+
+   u32 readyness;
 }
 extern vg_loader;
 
index 80b314678666e660500fa03b771f5ef338c35d85..ce224e32c5287c1c952fd4febe8ee56f6847d45c 100644 (file)
--- a/vg_opt.c
+++ b/vg_opt.c
@@ -1,5 +1,5 @@
 /*
- * 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;
 }
index 0dac45ce26a771433c67eeb041e5456a47ce7a85..12e6187a26a2aa4d74cb2c55bb4119b223fdf24c 100644 (file)
--- a/vg_opt.h
+++ b/vg_opt.h
@@ -1,26 +1,24 @@
 /*
- * 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 );
index 7db6171c8cab41034147974fe3fa82fe40dc833a..e82fa31db0aca0db4fa28c23332ee20d201ce8ff 100644 (file)
--- a/vg_tex.c
+++ b/vg_tex.c
@@ -298,9 +298,7 @@ void vg_tex2d_load_qoi_async( const u8 *bytes, u32 size, u32 flags, GLuint *dest
 
 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;
diff --git a/vg_tower.c b/vg_tower.c
new file mode 100644 (file)
index 0000000..96d0a63
--- /dev/null
@@ -0,0 +1,87 @@
+#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;
+}
diff --git a/vg_tower.h b/vg_tower.h
new file mode 100644 (file)
index 0000000..b3b9cae
--- /dev/null
@@ -0,0 +1,30 @@
+#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 );