MAKE METACOMPILER GOOD
authorhgn <hgodden00@gmail.com>
Wed, 22 Oct 2025 02:10:34 +0000 (03:10 +0100)
committerhgn <hgodden00@gmail.com>
Wed, 22 Oct 2025 02:10:34 +0000 (03:10 +0100)
13 files changed:
bootstrap.sh
source/async/async.kv
source/console/console_system.h
source/engine/array_file.h
source/engine/engine.kv
source/engine/model_entity.h
source/engine/vg_engine.c
source/engine/vg_engine.h
source/foundation/foundation.h
source/foundation/foundation.kv
source/foundation/keyvalues.c
source/maths/common_maths.h
source/tools/metacompiler.c

index 38805e54afbcd8127e7a1d7ac8eb46a55cd627c3..e1ac54a4451dcbcc62699e7cdbb6e32a74537032 100755 (executable)
@@ -1,5 +1,5 @@
 mkdir -p bin/vg.metacompiler-linux-x86_64-zig-cc/ &&
-taskset -c 0-1 zig cc -I. -I./include/ -fsanitize=address -lasan -Wall -Wno-unused-function -O0 -ggdb \
+taskset -c 0-1 zig cc -I. -I./include/ -fsanitize=address -lasan -Wall -Wno-unused-function -O1 -ggdb \
    -std=c11 -D_DEFAULT_SOURCE \
    -include "source/types.h" \
    -I./source/foundation/ \
index dfab494cd80ae12fe871fe5d18c148e5597dcafb..bb3a9a834de60fae9155eb80a8ac743b7ba72eb8 100644 (file)
@@ -1,8 +1,16 @@
 include ""
 
+test_feature
 {
-   if SDL
-   add sdl_async.c
+   feature SDL
+   yes
+   {
+      add sdl_async.c
+   }
+   no
+   {
+
+   }
 }
 
 hook
index f2b2329c9e9d728d691c5fbbee697297127ac6d2..a996f801bdde08c25662bad4a4a97e1762e99ada 100644 (file)
@@ -1,5 +1,3 @@
-#include "generated/console.h"
-
 void _console_init(void);
 void _console_execute( const c8 *command, b8 silent, b8 cheat_allowed );
 
@@ -9,3 +7,5 @@ struct console_arguments
    u32 count;
 };
 const c8 *console_get_argument( struct console_arguments *args, u32 index );
+
+#include "generated/console.h"
index 68f9739e80c092d52120d2295124ff6fcb43b3b2..5abd1645798bdd07ee2f978867ebffd090cc9783 100644 (file)
@@ -47,8 +47,8 @@ const c8 *af_str( const void *packed_strings, u32 pstr );
 u32 af_str_hash( const void *packed_strings, u32 pstr );
 b8 af_str_eq( const void *packed_strings, u32 pstr, const char *str, u32 str_hash );
 
-#define AF_STR_EQ( CTX, PSTR, CONSTR ) \
-   af_str_eq( CTX, PSTR, CONSTR, vg_strdjb2( CONSTR ) )
+#define AF_STR_EQ( PACKED, PSTR, CONSTR ) \
+   af_str_eq( PACKED, PSTR, CONSTR, buffer_djb2( CONSTR, 0 ) )
 
 /* COmpiler 
  * ------------------------------------ */
index 0c66c16ff037e144c6b57a5049af3be45563875e..e81bb621f56052b307ca53347a07237003d2dd0b 100644 (file)
@@ -8,127 +8,115 @@ add ../../dep/glad.4.3/glad.c
 enable SDL
 append ../foundation/foundation.kv
 
+add vg_engine.c
+hook
 {
-   add vg_engine.c
-   hook
-   {
-      event OPTIONS
-      function _engine_options
-   }
-   event
-   {
-      name ENGINE_NEW_FRAME
-      prototype "void"
-   }
-   event
-   {
-      name ENGINE_FIXED_UPDATE
-      prototype "void"
-   }
-   event
-   {
-      name ENGINE_RENDER
-      prototype "void"
-   }
-   event
-   {
-      name ENGINE_UI
-      prototype "void"
-   }
-   event
-   {
-      name ENGINE_WINDOW_RESIZE
-      prototype "void"
-   }
+   event OPTIONS
+   function _engine_options
+}
+event
+{
+   name ENGINE_NEW_FRAME
+   prototype "void"
+}
+event
+{
+   name ENGINE_FIXED_UPDATE
+   prototype "void"
+}
+event
+{
+   name ENGINE_RENDER
+   prototype "void"
+}
+event
+{
+   name ENGINE_UI
+   prototype "void"
+}
+event
+{
+   name ENGINE_WINDOW_RESIZE
+   prototype "void"
 }
 
+add vg_ui.c
+hook
 {
-   add vg_ui.c
-   hook
-   {
-      event START
-      function _engine_ui_init
-   }
+   event START
+   function _engine_ui_init
 }
 
+add vg_input.c
+hook
 {
-   add vg_input.c
-   hook
+   event START
+   function _input_init
+}
+hook
+{
+   event ENGINE_NEW_FRAME
+   function _input_update
+}
+ccmd
+{
+   name bind
+   function _input_bind_ccmd
+   description "Bind device input to a button, action or axis"
+
+   parameter
    {
-      event START
-      function _input_init
+      description "Device input alias"
    }
-   hook
+
+   parameter
    {
-      event ENGINE_NEW_FRAME
-      function _input_update
+      description "button,action,axis name"
    }
-   ccmd
-   {
-      name bind
-      function _input_bind_ccmd
-      description "Bind device input to a button, action or axis"
-
-      parameter
-      {
-         description "Device input alias"
-      }
+}
+ccmd
+{
+   name unbind
+   description "Unbind all bindings that match"
+   function _input_unbind_ccmd
 
-      parameter
-      {
-         description "button,action,axis name"
-      }
-   }
-   ccmd
+   parameter
    {
-      name unbind
-      description "Unbind all bindings that match"
-      function _input_unbind_ccmd
-
-      parameter
-      {
-         description "binding"
-      }
+      description "binding"
    }
 }
 
 append ../console/console_system.kv
+add console.c
+hook
 {
-   add console.c
-   hook
-   {
-      event START
-      function _engine_console_init
-   }
-   hook
-   {
-      event ENGINE_NEW_FRAME
-      function _engine_console_update
-   }
-   hook
-   {
-      event ENGINE_UI
-      function _engine_console_ui
-      affinity 9999
-   }
+   event START
+   function _engine_console_init
+}
+hook
+{
+   event ENGINE_NEW_FRAME
+   function _engine_console_update
+}
+hook
+{
+   event ENGINE_UI
+   function _engine_console_ui
+   affinity 9999
 }
 
+add vg_framebuffer.c
+hook 
 {
-   add vg_framebuffer.c
-   hook 
-   {
-      event ENGINE_WINDOW_RESIZE
-      function _framebuffer_resize
-   }
+   event ENGINE_WINDOW_RESIZE
+   function _framebuffer_resize
 }
 
+add vg_render.c
+hook
 {
-   add vg_render.c
-   hook
-   {
-      event START
-      function _vg_render_init
-   }
+   event START
+   function _vg_render_init
 }
 
 add vg_shader.c
index 65e26af817131bce6ec8bc99e8507ada50d387dd..513d02a10f105837f5288057238aff68f8f800e0 100644 (file)
@@ -39,10 +39,14 @@ enum entity_alias
    k_mdl_mesh        = 33,
    k_editer_property = 34,
    k_editer_item     = 35,
+
+   k_ent_flame       = 200,
+   k_ent_waterfall   = 201,
    k_ent_max
 };
 
-const char *_entity_alias_str[] =
+// FIXME
+static const char *_entity_alias_str[] =
 {
    [k_ent_none] = "none/null",
    [k_ent_gate] = "ent_gate",
index 925c293474ed0162f44c9466c0fb02bfa1044942..6d14fac98e2c396f2ad077c5a9e154f42aa99c4c 100644 (file)
@@ -213,6 +213,8 @@ i32 main( i32 argc, const c8 *argv[] )
 
    /* ------------- */
 
+   mt_random_seed( &_engine.random, 887765 );
+
    EVENT_CALL( START );
    SDL_CreateThread( async_thread, "ASync thread", NULL );
    ASSERT_CRITICAL( async_thread );
index 091cc2ff74605ab90316d9cff2fe4a71722e4843..8f6e563f9cb70bad384b199eafc0913e05081394 100644 (file)
@@ -1,3 +1,5 @@
+#include "random.h"
+
 struct _engine
 {
    b8 vsync;
@@ -17,5 +19,7 @@ struct _engine
    i32 w, h;
 
    i32 native_fbo;
+
+   struct mt_random random;
 }
 extern _engine;
index b682a41827a4083fbd9dce3dcdab210c27d15d59..33d2fc26d115989c49db0df52d1463cecb76aaf1 100644 (file)
@@ -308,6 +308,7 @@ struct keyvalues
 void keyvalues_init( struct keyvalues *kvs, struct stack_allocator *stack );
 void keyvalues_parse_stream( struct keyvalues *kvs, u32 root_offset, struct stream *in_stream );
 void keyvalues_write_stream( struct keyvalues *kvs, struct stream *out_stream, u32 node, u32 depth );
+u32 keyvalues_current_offset( struct keyvalues *kvs );
 
 b8 keyvalues_read_file( struct keyvalues *kvs, const char *path, struct stack_allocator *stack );
 b8 keyvalues_write_file( struct keyvalues *kvs, const char *path );
@@ -327,6 +328,8 @@ u32 keyvalues_get( struct keyvalues *kvs, u32 root_offset, const c8 *key, b8 rel
 u32 keyvalues_get_next( struct keyvalues *kvs, u32 kv_offset );
 u32 keyvalues_get_child( struct keyvalues *kvs, u32 root_offset, u32 index );
 
+b8 keyvalues_foreach( struct keyvalues *kvs, u32 *kv, u32 block, const c8 *alias );
+
 const c8 *keyvalues_read_string( struct keyvalues *kvs, u32 root_offset, const c8 *key, const c8 *default_value );
 b8 keyvalues_read_i32s( struct keyvalues *kvs, u32 root_offset, const c8 *key, i32 *default_values, i32 *out_values, u32 len );
 b8 keyvalues_read_u32s( struct keyvalues *kvs, u32 root_offset, const c8 *key, u32 *default_values, u32 *out_values, u32 len );
index 83ff4eab9816bdc4aaf0a2733bf88203982b8aa8..a4fb6e67555a43e85af7f4080857636f9988ebf8 100644 (file)
@@ -29,24 +29,30 @@ add keyvalues.c
 add buffer_operations.c
 add temporary.c
 
+test_feature
 {
-   if linux
-   add io.c
-   add exit.c
+   feature linux
+   yes
+   {
+      add io.c
+      add exit.c
+   }
+   no
+   {
+      add io_windows.c
+      add exit_windows.c
+   }
 }
 
+test_feature
 {
-   if windows
-   add io_windows.c
-   add exit_windows.c
-}
-
-{
-   if SDL
-   add threads_sdl.c
-}
-
-{
-   if !SDL
-   add threads_c11.c
+   feature SDL
+   yes
+   {
+      add threads_sdl.c
+   }
+   no
+   {
+      add threads_c11.c
+   }
 }
index 5710f8102c1cc3a5c89d11c643332034f1b6aefc..179adea67aab580cd345636cecb280739d546845 100644 (file)
@@ -38,6 +38,11 @@ static struct keyvalue *keyvalues_new( struct keyvalues *kvs )
    return kv;
 }
 
+u32 keyvalues_current_offset( struct keyvalues *kvs )
+{
+   return kvs->kv_page_offset + kvs->kv_page_count*sizeof(struct keyvalue);
+}
+
 void keyvalues_init( struct keyvalues *kvs, struct stack_allocator *stack )
 {
    zero_buffer( kvs, sizeof(struct keyvalues) );
@@ -204,6 +209,25 @@ u32 keyvalues_get( struct keyvalues *kvs, u32 root_offset, const c8 *key, b8 rel
    return 0;
 }
 
+b8 keyvalues_foreach( struct keyvalues *kvs, u32 *kv, u32 block, const c8 *alias )
+{
+   if( *kv == 0 ) 
+   {
+      if( alias )
+         *kv = keyvalues_get( kvs, block, alias, 0 );
+      else
+         *kv = keyvalues_get_child( kvs, block, 0 );
+   }
+   else  
+   {
+      if( alias )
+         *kv = keyvalues_get( kvs, *kv, alias, 1 );
+      else
+         *kv = keyvalues_get_next( kvs, *kv );
+   }
+   return (*kv) != 0;
+}
+
 b8 keyvalues_read_i32s( struct keyvalues *kvs, u32 root_offset, const c8 *key, i32 *default_values, i32 *out_values, u32 len )
 {
    b8 good = 1;
index 99450162a391dd2dc992e68ba35e3d91c574a415..7fc07f18b944ea7791ef761f7a4de3c4789bd922 100644 (file)
@@ -18,7 +18,7 @@ static inline f32 f32_friction( f32 velocity, f32 F )
 }
 static inline f32 f32_lerp( f32 a, f32 b, f32 t ) { return a + t*(b-a); }
 static inline f64 f64_lerp( f64 a, f64 b, f64 t ) { return a + t*(b-a); }
-static inline void vg_slewf( f32 *a, f32 b, f32 speed )
+static inline void f32_slew( f32 *a, f32 b, f32 speed )
 {
    f32 d = f32_sign( b-*a ),
        c = *a + d*speed;
@@ -1403,3 +1403,12 @@ static inline b8 segment_segment_intersect_2d( f32 a0[2], f32 a1[2], f32 b0[2],
        return 1;
 }
 
+static inline f32 closest_point_on_segment_2d( f32 co[2], f32 a[2], f32 b[2], f32 d[2] )
+{
+   f32 v0[2], v1[2];
+   v2_sub( b, a, v0 );
+   v2_sub( co, a, v1 );
+   f32 t = f32_clamp( v2_dot( v0, v1 ) / v2_dot( v0, v0 ), 0.0f, 1.0f );
+   v2_muladds( a, v0, t, d );
+   return t;
+}
index 16baa93b73578fb3e8340a21143710011ea05047..e925b44c1d6bc6ba19915949bf3ece0b2d127405 100644 (file)
@@ -1,18 +1,16 @@
 #include <stdlib.h>
 #include "foundation.h"
 
-struct stream folder_string;
-struct stream tripple_string;
-b8 _setup_done = 0;
-
-const c8 *target_file_path = NULL;
-
-b8 use_tsan = 0;
-b8 use_asan = 0;
-b8 shared = 0;
-b8 no_pdb = 0;
-
-u32 optimise = 0;
+const c8 *_option_file_path = NULL;
+u64 _option_processors = 4;
+b8 _option_use_tsan = 0;
+b8 _option_use_asan = 0;
+b8 _option_no_pdb = 0;
+b8 _option_shared = 0;
+b8 _option_assemble_only = 0;
+u32 _option_optimise = 0;
+struct stream _assemble_file;
+struct keyvalues _assembly;
 
 enum libc_version 
 {
@@ -20,7 +18,7 @@ enum libc_version
    k_libc_version_2_23,
    k_libc_version_count,
 }
-libc = k_libc_version_native;
+_option_libc = k_libc_version_native;
 const c8 *libc_names[] = 
 {
    [k_libc_version_native]  = "",
@@ -34,7 +32,7 @@ enum architecture
    k_architecture_x86_64,
    k_architecture_count,
 }
-arch = k_architecture_x86_64;
+_option_arch = k_architecture_x86_64;
 const c8 *architecture_names[] = 
 {
    [k_architecture_native] = "native",
@@ -49,583 +47,133 @@ enum platform
    k_platform_linux,
    k_platform_count,
 }
-platform = k_platform_linux;
+_option_platform = k_platform_linux;
 const c8 *platform_names[] = 
 {
    [k_platform_native]      = "native",
    [k_platform_windows]     = "windows",
    [k_platform_linux]       = "linux",
 };
-u64 processors = 4;
-
-void system_call( const c8 *call )
-{
-   $log( $shell, {call} );
-   ASSERT_CRITICAL( system(call) == 0 );
-}
-
 
 struct
 {
-   c8 project_name[ 128 ];
-   struct stream source_list, include_path_list, define_list, configuration;
+   struct stream name, tripple, folder;
    const c8 *enabled_features[ 64 ];
 }
 static _metacompiler;
 
-struct
-{
-   b8 using;
-   struct stream layer_enums;
-   struct stream input_enums, input_structures;
-}
-static _input;
-
-struct
-{
-   b8 using;
-   struct stream enums, structures;
-}
-static _threads;
-
-struct hook_event
-{
-   struct stream alias, returns, proto;
-   struct stretchy_allocator users;
-};
-struct hook_user
+struct shell_command
 {
-   struct stream function_name;
-   i32 affinity;
+   u32 temp_frame;
+   struct stream line;
 };
-struct
-{
-   b8 using;
-   struct stretchy_allocator events;
-}
-static _hooks;
 
-struct
+struct shell_command *_shell_command(void)
 {
-   b8 using;
-   struct stream cvar_header, cvar_definitions, command_prototypes, command_definitions;
-   u32 command_count;
+   u32 temp_frame = _start_temporary_frame();
+   struct shell_command *command = _temporary_allocate( sizeof(struct shell_command), 8 );
+   command->temp_frame = temp_frame;
+   stream_open_stack( &command->line, _temporary_stack_allocator(), k_stream_null_terminate );
+   return command;
 }
-static _console;
-
-enum subshader_type
-{
-   k_subshader_vertex,
-   k_subshader_fragment,
-   k_subshader_geometry
-};
-struct shader
-{
-   struct stream name;
-   struct subshader
-   {
-      enum subshader_type type;
-      struct stream debug_source_list, static_source, uniform_source;
-      u32 debug_source_count;
-   }
-   subshaders[3];
-   u32 subshader_count;
 
-   u32 uniform_start, uniform_count;
-};
-struct
+void _shell_run( struct shell_command *command )
 {
-   b8 using;
-   struct stream shader_enum, uniform_enum, uniform_aliases, uniform_func_protos, uniform_funcs;
-   u32 uniform_count;
-   struct stretchy_allocator shaders;
+   $log( $shell, {string_get( &command->line )} );
+   ASSERT_CRITICAL( system( string_get( &command->line ) ) == 0 );
+   _end_temporary_frame( command->temp_frame );
 }
-static _shaders;
 
-struct shell_command
-{
-   struct stream command;
-};
-struct
+u32 _assembly_kv_file_context( u32 kv )
 {
-   struct stretchy_allocator shell;
-}
-static _commands;
+   u32 vgc_block = keyvalues_get( &_assembly, 0, "vgc", 0 );
+   ASSERT_CRITICAL( vgc_block );
 
-struct block_context
-{
-   enum target_type 
+   u32 narrowest = 0;
+   u32 it = 0;
+   while( keyvalues_foreach( &_assembly, &it, vgc_block, "file_context" ) )
    {
-      k_target_main,
-      k_target_input_layer,
-      k_target_input,
-      k_target_shader,
-      k_target_cvar,
-      k_target_ccmd,
-      k_target_thread,
-      k_target_hook,
-      k_target_subshader
+      u32 min = 0, max = 0;
+      keyvalues_read_u32s( &_assembly, it, "kv_start", NULL, &min, 1 );
+      keyvalues_read_u32s( &_assembly, it, "kv_end", NULL, &max, 1 );
+
+      if( (kv >= min) && (kv <= max) )
+         narrowest = it;
    }
-   target;
-   u32 feature_count;
-   const c8 *folder;
-};
+   return narrowest;
+}
 
-void _append_kv_list( const c8 *path, struct block_context context );
-void _parse_kv_block( struct keyvalues *kvs, u32 block, struct block_context context )
+void _assemble_kv_file( const c8 *path, u32 assembly_block, u32 feature_count );
+void _parse_kv_block( struct keyvalues *kvs, u32 block, u32 file_context, u32 assembly_block, u32 feature_count )
 {
-   const c8 *block_key = keyvalues_key( kvs, block, NULL );
-   if( block_key != NULL )
+   u32 it = 0;
+   while( keyvalues_foreach( kvs, &it, block, NULL ) )
    {
-      if( context.target == k_target_shader )
+      const c8 *it_k = keyvalues_key( kvs, it, NULL );
+      if( keyvalues_type( kvs, it ) == k_keyvalue_type_frame )
       {
-         if( compare_buffers( block_key, 0, "subshader", 0 )) 
+         if( compare_buffers( it_k, 0, "test_feature", 0 ) )
          {
-            context.target = k_target_subshader;
+            const c8 *test_feature = keyvalues_read_string( kvs, it, "feature", NULL );
+            ASSERT_CRITICAL( test_feature );
 
-            struct shader *shader = stretchy_get( &_shaders.shaders, stretchy_count( &_shaders.shaders ) -1 );
-            struct subshader *subshader = &shader->subshaders[ shader->subshader_count ++ ];
+            b8 result = 0;
+            for( u32 i=0; i<feature_count; i ++ )
+               if( compare_buffers( _metacompiler.enabled_features[i], 0, test_feature, 0 ) )
+                  result = 1;
 
-            const c8 *type = keyvalues_read_string( kvs, block, "type", NULL );
-            ASSERT_CRITICAL( type );
-
-            if( compare_buffers( type, 0, "vertex", 0 ) )
-               subshader->type = k_subshader_vertex;
-            else if( compare_buffers( type, 0, "fragment", 0 ) )
-               subshader->type = k_subshader_fragment;
-            else if( compare_buffers( type, 0, "geometry", 0 ) )
-               subshader->type = k_subshader_geometry;
-            else
-            {
-               $log( $warning, {"Invalid subshader type '"}, {type}, {"'"} );
-               return;
-            }
-
-            subshader->debug_source_count = 0;
-            stream_open_auto( &subshader->debug_source_list, k_stream_null_terminate );
-            stream_open_auto( &subshader->static_source, k_stream_null_terminate );
-            stream_open_auto( &subshader->uniform_source, k_stream_null_terminate );
-         }
-         else
-         {
-            $log( $warning, {"We don't have a compiler:shader definition for block '"}, {block_key}, {"'"} );
-            return;
-         }
-      }
-      else if( context.target == k_target_subshader )
-      {
-         struct shader *shader = stretchy_get( &_shaders.shaders, stretchy_count( &_shaders.shaders ) -1 );
-         struct subshader *subshader = &shader->subshaders[ shader->subshader_count -1 ];
-
-         if( compare_buffers( block_key, 0, "uniform", 0 )) 
-         {
-            const c8 *alias = keyvalues_read_string( kvs, block, "alias", NULL );
-            const c8 *type = keyvalues_read_string( kvs, block, "type", NULL );
-            ASSERT_CRITICAL( type && alias );
-            
-            struct glsl_trans
-            {
-               const c8 *type, *args, *call, *end;
-            }
-            type_list[] =
-            {
-               { "int",          "i32 b",        "glUniform1i",            "b" },
-               { "vec2",         "f32 v[2]",     "glUniform2fv",           "1,v" },
-               { "vec3",         "f32 v[3]",     "glUniform3fv",           "1,v" },
-               { "vec4",         "f32 v[4]",     "glUniform4fv",           "1,v" },
-               { "bool",         "i32 b",        "glUniform1i",            "b" },
-               { "mat2",         "f32 m[2][2]",  "glUniformMatrix2fv",     "1,GL_FALSE,(f32*)m" },
-               { "mat3",         "f32 m[3][3]",  "glUniformMatrix3fv",     "1,GL_FALSE,(f32*)m" },
-               { "mat4",         "f32 m[4][4]",  "glUniformMatrix4fv",     "1,GL_FALSE,(f32*)m" },
-               { "float",        "f32 f",        "glUniform1f",            "f" },
-               { "mat4x3",       "f32 m[4][3]",  "glUniformMatrix4x3fv",   "1,GL_FALSE,(f32*)m" },
-               { "sampler2D",    "i32 i",        "glUniform1i",            "i" },
-               { "usampler3D",   "i32 i",        "glUniform1i",            "i" },
-               { "samplerCube",  "i32 i",        "glUniform1i",            "i" },
-               { "samplerBuffer","i32 i",        "glUniform1i",            "i" },
-            },
-            *trans = NULL;
-
-            for( u32 i=0; i<ARRAY_COUNT( type_list ); i ++ )
-            {
-               if( compare_buffers( type_list[i].type, 0, type, 0 ) )
-               {
-                  trans = &type_list[i];
-                  break;
-               }
-            }
-            ASSERT_CRITICAL( trans );
-
-            $v_string( &_shaders.uniform_enum, {"   k_shader_"}, {string_get(&shader->name)}, {"_"}, {alias}, {",\n"} );
-            $v_string( &_shaders.uniform_aliases, {"   [k_shader_"}, {string_get(&shader->name)}, {"_"}, {alias}, {"] = \""},
-                  {alias},{"\",\n"} );
-            $v_string( &subshader->uniform_source, {"uniform "}, {type}, {" "}, {alias}, {";\\n"} );
-
-            $v_string( &_shaders.uniform_func_protos, {"void _shader_"}, {string_get(&shader->name)}, {"_"}, {alias}, {"( "},{trans->args},{" );\n"} );
-            $v_string( &_shaders.uniform_funcs, {"void _shader_"}, {string_get(&shader->name)}, {"_"}, {alias}, {"( "},{trans->args},{" )"},
-                     {"{ "},{trans->call},{"( _uniform_locations["}, 
-                        {"k_shader_"}, {string_get(&shader->name)}, {"_"}, {alias},
-                     {"], "},{trans->end},{" ); }\n"});
-
-            shader->uniform_count ++;
-            _shaders.uniform_count ++;
+            u32 pass_block = keyvalues_get( kvs, it, result? "yes": "no", 0 );
+            if( pass_block )
+               _parse_kv_block( kvs, pass_block, file_context, assembly_block, feature_count );
          }
          else
          {
-            $log( $warning, {"We don't have a compiler:subshader definition for block '"}, {block_key}, {"'"} );
-            return;
+            /* Add the block title to the assembly if it's not a pre-processor thing */
+            _parse_kv_block( kvs, it, file_context, keyvalues_append_frame( &_assembly, assembly_block, it_k ), feature_count );
          }
       }
       else
       {
-         ASSERT_CRITICAL( context.target == k_target_main );
-         if( compare_buffers( block_key, 0, "input_layer", 0 )) 
-         {
-            _input.using = 1;
-            context.target = k_target_input_layer;
-            const c8 *layer_name = keyvalues_read_string( kvs, block, "name", NULL );
-            ASSERT_CRITICAL( layer_name );
-
-            $v_string( &_input.layer_enums, {"   k_input_layer_"}, {layer_name}, {",\n"} );
-         }
-         else if( compare_buffers( block_key, 0, "input", 0 )) 
-         {
-            _input.using = 1;
-            context.target = k_target_input;
-
-            const c8 *name = keyvalues_read_string( kvs, block, "name", NULL );
-            ASSERT_CRITICAL( name );
-
-            const c8 *type = keyvalues_read_string( kvs, block, "type", NULL );
-            ASSERT_CRITICAL( type );
-
-            const c8 *layer_mask = keyvalues_read_string( kvs, block, "layer_mask", NULL );
-            
-            $v_string( &_input.input_enums, {"   k_input_"},{type},{"_"}, {name}, {",\n"} );
-            $v_string( &_input.input_structures, {"   [k_input_"},{type},{"_"},{name},{"]=\n   {\n"} );
-            $v_string( &_input.input_structures, {"      .name = \""},{name},{"\",\n"} );
-            $v_string( &_input.input_structures, {"      .type = k_input_type_"},{type},{",\n"} );
-
-            if( layer_mask )
-               $v_string( &_input.input_structures, {"      .layer_mask = 1<<k_input_layer_"}, {layer_mask}, {",\n"} );
-#if 0
-            const c8 *keyboard_key = keyvalues_read_string( kvs, block, "keyboard", NULL );
-            if( keyboard_key )
-               $v_string( &_input.button_structures, {"      .key_id = GLFW_KEY_"}, {keyboard_key}, {",\n"} );
-#endif
-            $v_string( &_input.input_structures, {"   },\n"} );
-         }
-         else if( compare_buffers( block_key, 0, "cvar", 0 )) 
-         {
-            _console.using = 1;
-            context.target = k_target_cvar;
-            const c8 *name = keyvalues_read_string( kvs, block, "name", NULL );
-            const c8 *type = keyvalues_read_string( kvs, block, "type", NULL );
-            const c8 *default_value = keyvalues_read_string( kvs, block, "default", NULL );
-            ASSERT_CRITICAL( name && type && default_value );
-
-            $v_string( &_console.cvar_header, {"extern "}, {type}, {" cvar_"}, {name}, {";\n"} );
-            $v_string( &_console.cvar_definitions, {type}, {" cvar_"}, {name}, {" = "}, {default_value}, {";\n"} );
-         }
-         else if( compare_buffers( block_key, 0, "ccmd", 0 )) 
-         {
-            _console.using = 1;
-            _console.command_count ++;
-            context.target = k_target_ccmd;
-            const c8 *name = keyvalues_read_string( kvs, block, "name", NULL );
-            const c8 *function = keyvalues_read_string( kvs, block, "function", NULL );
-            ASSERT_CRITICAL( name && function );
-            $v_string( &_console.command_definitions, {"   {\n      .alias = \""}, {name}, {"\",\n      .fn = "}, 
-                                                      {function}, {"\n   },\n"} );
-            $v_string( &_console.command_prototypes, {"i32 "}, {function}, {"( struct console_arguments *args );\n"} );
-            // TODO: process parameter descriptions
-            return;
-         }
-         else if( compare_buffers( block_key, 0, "shader", 0 )) 
-         {
-            _shaders.using = 1;
-            context.target = k_target_shader;
-            struct shader *shader = stretchy_append( &_shaders.shaders );
-            shader->subshader_count = 0;
-            shader->uniform_start = _shaders.uniform_count;
-            shader->uniform_count = 0;
-
-            stream_open_auto( &shader->name, k_stream_null_terminate );
-            $v_string( &shader->name, {keyvalues_read_string( kvs, block, "name", NULL )} );
-            $v_string( &_shaders.shader_enum, {"   k_shader_"}, {string_get(&shader->name)}, {",\n"} );
-         }
-         else if( compare_buffers( block_key, 0, "thread", 0 )) 
-         {
-            _threads.using = 1;
-            context.target = k_target_thread;
-            const c8 *name = keyvalues_read_string( kvs, block, "name", NULL );
-            ASSERT_CRITICAL( name );
-
-            $v_string( &_threads.enums, {"   k_thread_"},{name}, {",\n"} );
-            $v_string( &_threads.structures, {"   [k_thread_"},{name},{"]=\n   {\n"} );
-            $v_string( &_threads.structures, {"      .name = \""}, {name}, {"\",\n"} );
-
-            u32 queue_size_m = 0;
-            if( keyvalues_read_u32s( kvs, block, "queue_size_m", NULL, &queue_size_m, 1 ) )
-               $v_string( &_threads.structures, {"      .queue_size_m = "}, $unsigned(queue_size_m), {",\n"} );
-
-            
-            u32 flag_kv = keyvalues_get( kvs, block, "flag", 0 );
-            if( flag_kv )
-               $v_string( &_threads.structures, {"      .flags = "} );
-
-            u32 flag_count = 0;
-            while( flag_kv )
-            {
-               const c8 *flag_name = keyvalues_value( kvs, flag_kv, NULL );
-               $v_string( &_threads.structures, {flag_count? "|": ""}, {"THREAD_FLAG_"}, {flag_name} );
-
-               flag_kv = keyvalues_get( kvs, flag_kv, "flag", 1 );
-               flag_count ++;
-            }
-            if( flag_count )
-               $v_string( &_threads.structures, {",\n"} );
-
-            $v_string( &_threads.structures, {"   },\n"} );
-         }
-         else if( compare_buffers( block_key, 0, "event", 0 )) 
-         {
-            _hooks.using = 1;
-            context.target = k_target_hook;
-            const c8 *name = keyvalues_read_string( kvs, block, "name", NULL );
-            const c8 *prototype = keyvalues_read_string( kvs, block, "prototype", NULL );
-            const c8 *returns = keyvalues_read_string( kvs, block, "returns", "void" );
-            ASSERT_CRITICAL( name && prototype && returns );
-
-            struct hook_event *event = stretchy_append( &_hooks.events );
-
-            stream_open_auto( &event->alias, k_stream_null_terminate );
-            $v_string( &event->alias, {name} );
-            stream_open_auto( &event->returns, k_stream_null_terminate );
-            $v_string( &event->returns, {returns} );
-            stream_open_auto( &event->proto, k_stream_null_terminate );
-            $v_string( &event->proto, {prototype} );
-
-            stretchy_init( &event->users, sizeof( struct hook_user ) );
-         }
-         else if( compare_buffers( block_key, 0, "hook", 0 ))
-         {
-            _hooks.using = 1;
-            const c8 *event_alias = keyvalues_read_string( kvs, block, "event", NULL );
-            const c8 *function = keyvalues_read_string( kvs, block, "function", NULL );
-
-            ASSERT_CRITICAL( event_alias && function );
-
-            i32 affinity = 0;
-            keyvalues_read_i32s( kvs, block, "affinity", NULL, &affinity, 1 );
-
-            b8 found = 0;
-
-            for( u32 i=0; i<stretchy_count( &_hooks.events ); i ++ )
-            {
-               struct hook_event *event = stretchy_get( &_hooks.events, i );
-               if( compare_buffers( string_get( &event->alias ), 0, event_alias, 0 ) )
-               {
-                  struct hook_user *user = stretchy_append( &event->users );
-                  stream_open_auto( &user->function_name, k_stream_null_terminate );
-                  $v_string( &user->function_name, {function} );
-                  user->affinity = affinity;
-                  found = 1;
-                  break;
-               }
-            }
-
-            if( !found )
-            {
-               $log( $fatal, {"We don't have an event registered called '"}, {event_alias}, {"'"} );
-               _fatal_exit();
-            }
-         }
-         else if( compare_buffers( block_key, 0, "symlink", 0 ) )
-         {
-            const c8 *source = keyvalues_read_string( kvs, block, "source", NULL );
-            const c8 *name = keyvalues_read_string( kvs, block, "name", NULL );
-            ASSERT_CRITICAL( source );
-
-            struct shell_command *command = stretchy_append( &_commands.shell );
-            stream_open_auto( &command->command, k_stream_null_terminate );
-            $v_string( &command->command, {"ln -snf "}, {context.folder}, {"/"}, {source}, {" "}, {string_get( &folder_string )}, {"/"}, { name? name: source } );
-         }
-         else
-         {
-            $log( $warning, {"We don't have a compiler definition for block '"}, {block_key}, {"'"} );
-            return;
-         }
-      }
-   }
-
-   u32 kv = keyvalues_get_child( kvs, block, 0 );
-   while( kv )
-   {
-      if( keyvalues_type( kvs, kv ) == k_keyvalue_type_frame )
-      {
-         _parse_kv_block( kvs, kv, context );
-         kv = keyvalues_get_next( kvs, kv );
-         continue;
-      }
-
-      const c8 *key = keyvalues_key( kvs, kv, NULL );
-      const c8 *value = keyvalues_value( kvs, kv, NULL );
-
-      /* MUST COME FIRST */
-      if( _setup_done == 0 )
-      {
-         if( compare_buffers( key, 0, "name", 0 ) )
-         {
-            buffer_copy( value, 0, _metacompiler.project_name, sizeof(_metacompiler.project_name) );
-
-            c8 *output_folder = realpath( target_file_path, NULL );
-            if( !output_folder )
-            {
-               $log( $fatal, {"'"}, {target_file_path}, {"' "}, $errno() );
-               _fatal_exit();
-            }
-
-            i32 s = buffer_last_index( output_folder, '/', 0 );
-            if( s != -1 )
-               output_folder[s] = '\0';
-
-
-            stream_open_auto( &tripple_string, k_stream_null_terminate );
-            $v_string( &tripple_string, {architecture_names[arch]}, {"-"}, {platform_names[platform]} );
-            if( platform == k_platform_linux )
-            {
-               $v_string( &tripple_string, {"-gnu"} );
-               if( libc != k_libc_version_native )
-                  $v_string( &tripple_string, {"."}, {libc_names[libc]} );
-            }
-
-            stream_open_auto( &folder_string, k_stream_null_terminate );
-            $v_string( &folder_string, {output_folder}, {"/bin/"}, {_metacompiler.project_name}, {"-"}, {string_get(&tripple_string)} );
-            
-            free(output_folder);
-
-            u32 temp_frame = _start_temporary_frame();
-            {
-               struct stream command_string;
-               stream_open_stack( &command_string, _temporary_stack_allocator(), k_stream_null_terminate );
-               $v_string( &command_string, {"mkdir -p "}, {string_get( &folder_string )} );
-               system_call( string_get( &command_string ) );
-            }
-            _end_temporary_frame( temp_frame );
-
-            _setup_done = 1;
-         }
-      }
-      
-      ASSERT_CRITICAL( _setup_done );
-
-      /* availible in all targets */
-      if( compare_buffers( key, 0, "enable", 0 ) )
-         _metacompiler.enabled_features[ context.feature_count ++ ] = keyvalues_value( kvs, kv, NULL );
-
-      if( compare_buffers( key, 0, "if", 0 ) )
-      {
-         b8 invert = 0;
-         if( value[0] == '!' )
-         {
-            value ++;
-            invert = 1;
-         }
-
-         b8 result = 0 ^ invert;
-         for( u32 i=0; i<context.feature_count; i ++ )
-            if( compare_buffers( _metacompiler.enabled_features[i], 0, value, 0 ) )
-               result = 1 ^ invert;
-
-         if( !result )
-            return;
-      }
-
-      if( compare_buffers( key, 0, "append", 0 ) )
-      {
-         u32 temp_frame = _start_temporary_frame();
-         {
-            struct stream path_string;
-            stream_open_stack( &path_string, _temporary_stack_allocator(), k_stream_null_terminate );
-            $v_string( &path_string, {context.folder}, {"/"}, {value} );
-            _append_kv_list( string_get( &path_string ), context );
-         }
-         _end_temporary_frame( temp_frame );
-      }
-
-      if( compare_buffers( key, 0, "config", 0 ) )
-         $v_string( &_metacompiler.configuration, {value}, {"\n"} );
-
-      if( context.target == k_target_main )
-      {
-         if( compare_buffers( key, 0, "object_type", 0 ) )
-         {
-                 if( compare_buffers( value, 0, "executable", 0 ) ) shared = 0;
-            else if( compare_buffers( value, 0, "shared", 0 ) ) shared = 1;
-            else
-            {
-               $log( $fatal, {"Unknown output type '"}, {value}, {"'"} );
-               _fatal_exit();
-            }
-         }
-
-         if( compare_buffers( key, 0, "add", 0 ) )
-            $v_string( &_metacompiler.source_list, {"      "}, {context.folder}, {"/"}, {value}, {" \\\n"} );
-
-         if( compare_buffers( key, 0, "include", 0 ) )
-            $v_string( &_metacompiler.include_path_list, {"      -I"}, {context.folder}, {"/"}, {value}, {" \\\n"} );
-
-         if( compare_buffers( key, 0, "define", 0 ) )
-            $v_string( &_metacompiler.include_path_list, {"      -D"}, {value}, {" \\\n"} );
+         const c8 *it_v = keyvalues_value( kvs, it, NULL );
 
-         if( compare_buffers( key, 0, "link", 0 ) )
-            $v_string( &_metacompiler.include_path_list, {"      -l"}, {value}, {" \\\n"} );
-         if( compare_buffers( key, 0, "link_folder", 0 ) )
-            $v_string( &_metacompiler.include_path_list, {"      -L"}, {value}, {" \\\n"} );
-      }
-      else if( context.target == k_target_subshader )
-      {
-         struct shader *shader = stretchy_get( &_shaders.shaders, stretchy_count( &_shaders.shaders ) -1 );
-         struct subshader *subshader = &shader->subshaders[ shader->subshader_count -1 ];
+         /* ENABLE FEATURE */
+         if( compare_buffers( it_k, 0, "enable", 0 ) )
+            _metacompiler.enabled_features[ feature_count ++ ] = it_v;
 
-         if( compare_buffers( key, 0, "add", 0 ) )
+         /* APPEND */
+         else if( compare_buffers( it_k, 0, "append", 0 ) )
          {
             u32 temp_frame = _start_temporary_frame();
             {
                struct stream path_string;
                stream_open_stack( &path_string, _temporary_stack_allocator(), k_stream_null_terminate );
-               $v_string( &path_string, {context.folder}, {"/"}, {value} );
-
-               struct stream source;
-               ASSERT_CRITICAL( stream_open_file( &source, string_get( &path_string ), k_stream_read ) );
-               
-               u32 block_size = BYTES_KB(128);
-               c8 *temp = _temporary_allocate( block_size, 4 );
-               while(1)
-               {
-                  u32 l = stream_read( &source, temp, block_size );
-                  $v_string( &subshader->static_source, {temp, .length = l} );
-                  if( l != block_size )
-                     break;
-               }
+   
+               const c8 *folder = keyvalues_read_string( &_assembly, file_context, "folder", NULL );
+               ASSERT_CRITICAL( folder );
 
-               stream_close( &source );
-               $v_string( &subshader->debug_source_list, {"               \""}, {string_get(&path_string)}, {"\",\n"} );
-               subshader->debug_source_count ++;
+               $v_string( &path_string, {folder}, {"/"}, {it_v} );
+               _assemble_kv_file( string_get( &path_string ), assembly_block, feature_count );
             }
             _end_temporary_frame( temp_frame );
          }
-      }
 
-      kv = keyvalues_get_next( kvs, kv );
+         /* NORMAL KV */
+         else 
+            keyvalues_append_string( &_assembly, assembly_block, it_k, it_v );
+      }
    }
 }
 
-void _append_kv_list( const c8 *path, struct block_context context )
+void _assemble_kv_file( const c8 *path, u32 assembly_block, u32 feature_count )
 {
-   u32 temp_frame = _start_temporary_frame();
+   /* Append context block */
+   u32 vgc_block = keyvalues_get( &_assembly, 0, "vgc", 0 );
+   ASSERT_CRITICAL( vgc_block );
+   u32 context_block = keyvalues_append_frame( &_assembly, vgc_block, "file_context" );
 
+   u32 start_offset = keyvalues_current_offset( &_assembly );
+
+   u32 temp_frame = _start_temporary_frame();
    c8 *folder = realpath( path, NULL );
    if( !folder )
    {
@@ -635,17 +183,19 @@ void _append_kv_list( const c8 *path, struct block_context context )
 
    i32 s = buffer_last_index( folder, '/', 0 );
    if( s != -1 )
-   {
       folder[s] = '\0';
-   }
 
-   context.folder = folder;
+   keyvalues_append_string( &_assembly, context_block, "folder", folder );
+   free( folder );
 
-   struct keyvalues list;
-   ASSERT_CRITICAL( keyvalues_read_file( &list, path, _temporary_stack_allocator() ) );
-   _parse_kv_block( &list, 0, context );
+   /* read file and pre-process it into the assembly */
+   struct keyvalues kvs;
+   ASSERT_CRITICAL( keyvalues_read_file( &kvs, path, _temporary_stack_allocator() ) );
+   _parse_kv_block( &kvs, 0, context_block, assembly_block, feature_count );
 
-   free( folder );
+   u32 end_offset = keyvalues_current_offset( &_assembly );
+   keyvalues_append_u32s( &_assembly, context_block, "kv_start", &start_offset, 1 );
+   keyvalues_append_u32s( &_assembly, context_block, "kv_end", &end_offset, 1 );
    _end_temporary_frame( temp_frame );
 }
 
@@ -667,42 +217,48 @@ void _metacompiler_options(void)
 {
    const c8 *arg;
    if( _option_long( "tsan", "Build using thread sanitizer" ) )
-      use_tsan = 1;
+      _option_use_tsan = 1;
 
    if( _option_long( "asan", "Build using address sanitizer" ) )
-      use_asan = 1;
+      _option_use_asan = 1;
 
-   if( use_tsan || use_asan )
-      ASSERT_CRITICAL( use_tsan != use_asan );
+   if( _option_use_tsan || _option_use_asan )
+      ASSERT_CRITICAL( _option_use_tsan != _option_use_asan );
 
    if( _option_long( "shared", "Create a shared object, instead of executable" ) )
-      shared = 1;
+      _option_shared = 1;
 
    if( _option_long( "no-pdb", "Prevent compiler from outputing pdb files" ) )
-      no_pdb = 1;
+      _option_no_pdb = 1;
 
    if( (arg = _option_long_argument( "libc", "native, 2.23 (recommended)" )) )
-      libc = enum_read( libc_names, k_libc_version_count, arg );
+      _option_libc = enum_read( libc_names, k_libc_version_count, arg );
 
    if( (arg = _option_long_argument( "arch", "native, i386, x86_64" )) )
-      arch = enum_read( architecture_names, k_architecture_count, arg );
-   ASSERT_CRITICAL( arch == k_architecture_x86_64 );
+      _option_arch = enum_read( architecture_names, k_architecture_count, arg );
+   ASSERT_CRITICAL( _option_arch == k_architecture_x86_64 );
 
    if( (arg = _option_long_argument( "platform", "native, linux, windows" )) )
-      platform = enum_read( platform_names, k_platform_count, arg );
+      _option_platform = enum_read( platform_names, k_platform_count, arg );
 
    if( (arg = _option_argument( 'j', "CPU count <0-8>" )) )
    {
       struct stream arg_stream;
       stream_open_buffer_read( &arg_stream, (void*)arg, buffer_last_index(arg,0,0)+1, 0 );
-      ASSERT_CRITICAL( string_parse_u64( &arg_stream, &processors ) == k_string_parse_ok );
+      ASSERT_CRITICAL( string_parse_u64( &arg_stream, &_option_processors ) == k_string_parse_ok );
    }
 
    if( _option_flag( 'O', "Run optimisers" ) )
-      optimise = 3;
+      _option_optimise = 3;
+
+   if( (arg = _option_argument( 'E', "Assemble target KV's only, and output it to file" )) )
+   {
+      _option_assemble_only = 1;
+      ASSERT_CRITICAL( stream_open_file( &_assemble_file, arg, k_stream_write ) );
+   }
    
-   target_file_path = _option();
-   ASSERT_CRITICAL( target_file_path );
+   _option_file_path = _option();
+   ASSERT_CRITICAL( _option_file_path );
 }
 
 void (*_event_OPTIONS_subscribers[])( void ) = 
@@ -711,281 +267,567 @@ void (*_event_OPTIONS_subscribers[])( void ) =
    NULL
 };
 
-i32 main( i32 argc, const c8 *argv[] )
+i32 compar( const void *a, const void *b )
 {
-   VG_PRE_MAIN;
+   return ((struct sort_index *)a)->value - ((struct sort_index *)b)->value;
+}
 
-   u32 options = k_stream_null_terminate;
-   stream_open_auto( &_metacompiler.source_list, options );
-   stream_open_auto( &_metacompiler.include_path_list, options );
-   stream_open_auto( &_metacompiler.define_list, options );
-   stream_open_auto( &_metacompiler.configuration, options );
-   stream_open_auto( &_input.layer_enums, options );
-   stream_open_auto( &_input.input_enums, options );
-   stream_open_auto( &_input.input_structures, options );
-   stream_open_auto( &_console.cvar_header, options );
-   stream_open_auto( &_console.cvar_definitions, options );
-   stream_open_auto( &_console.command_definitions, options );
-   stream_open_auto( &_console.command_prototypes, options );
-   stream_open_auto( &_threads.enums, options );
-   stream_open_auto( &_threads.structures, options );
-   stream_open_auto( &_shaders.shader_enum, options );
-   stream_open_auto( &_shaders.uniform_enum, options );
-   stream_open_auto( &_shaders.uniform_aliases, options );
-   stream_open_auto( &_shaders.uniform_funcs, options );
-   stream_open_auto( &_shaders.uniform_func_protos, options );
-   stretchy_init( &_hooks.events, sizeof( struct hook_event ) );
-   stretchy_init( &_shaders.shaders, sizeof( struct shader ) );
-   stretchy_init( &_commands.shell, sizeof( struct shell_command ) );
-
-   if( platform == k_platform_linux )   _metacompiler.enabled_features[0] = "linux";
-   if( platform == k_platform_windows ) _metacompiler.enabled_features[0] = "windows";
-
-   struct block_context context = {0};
-   context.feature_count = 1;
-   _append_kv_list( target_file_path, context );
-
-   ASSERT_CRITICAL( _setup_done );
-
-   system_call( "mkdir -p generated" );
-   
-   $log( $info, {"Generating input header"} );
-   if( _input.using )
-   {
-      struct stream input_header, input_source;
-      ASSERT_CRITICAL( stream_open_file( &input_header, "generated/input.h", k_stream_write ) );
-      $v_string( &input_header, {"enum input_layer_id\n{\n"}, {string_get( &_input.layer_enums )}, {"   k_input_layer_count\n};\n"} );
-      $v_string( &input_header, {"enum input_id\n{\n"}, {string_get( &_input.input_enums )}, {"   k_input_count\n};\n"} );
-      stream_close( &input_header );
-
-      ASSERT_CRITICAL( stream_open_file( &input_source, "generated/input.c", k_stream_write ) );
-      $v_string( &input_source, {"struct input_info _input_infos[k_input_count] = \n{\n"}, 
-            {string_get( &_input.input_structures )}, {"};\n"} );
-      stream_close( &input_source );
-   }
+void index_sort( struct sort_index *indices, u32 indice_count )
+{
+   qsort( indices, indice_count, sizeof(struct sort_index), compar );
+}
 
-   $log( $info, {"Generating threads header"} );
-   if( _threads.using )
+void _codegen_hooks(void)
+{
+   $log( $info, {"[CODEGEN] hooks.h/hooks.c"} );
+   struct stream hooks_c, hooks_h;
+   stream_open_file( &hooks_h, "generated/hooks.h", k_stream_write );
+   stream_open_file( &hooks_c, "generated/hooks.c", k_stream_write );
+
+   u32 it = 0;
+   while( keyvalues_foreach( &_assembly, &it, 0, "event" ) )
    {
-      struct stream thread_header, thread_source;
-      ASSERT_CRITICAL( stream_open_file( &thread_header, "generated/threads.h", k_stream_write ) );
-      $v_string( &thread_header, {"enum thread_id\n{\n"}, 
-                                 {string_get( &_threads.enums )}, 
-                                 {"   k_thread_count\n};\n"} );
-      stream_close( &thread_header );
-
-      ASSERT_CRITICAL( stream_open_file( &thread_source, "generated/threads.c", k_stream_write ) );
-      $v_string( &thread_source, {"struct thread_info _thread_infos[k_thread_count] = \n{\n"}, 
-            {string_get( &_threads.structures )}, {"};\n"} );
-      stream_close( &thread_source );
+      const c8 *name = keyvalues_read_string( &_assembly, it, "name", NULL );
+      const c8 *prototype = keyvalues_read_string( &_assembly, it, "prototype", NULL );
+      const c8 *returns = keyvalues_read_string( &_assembly, it, "returns", "void" );
+      ASSERT_CRITICAL( name && prototype && returns );
+
+      $v_string( &hooks_h, {"extern "}, {returns}, {" (*_event_"}, {name}, {"_subscribers[])( "}, {prototype}, {" );\n"} );
+      
+      struct sort_index indices[ 128 ];
+      u32 indice_count = 0;
+      
+      u32 user_it = 0;
+      while( keyvalues_foreach( &_assembly, &user_it, 0, "hook" ) )
+      {
+         if( compare_buffers( keyvalues_read_string( &_assembly, user_it, "event", NULL ), 0, name, 0 ) )
+         {
+            i32 affinity = 0;
+            keyvalues_read_i32s( &_assembly, user_it, "affinity", NULL, &affinity, 1 );
+
+            ASSERT_CRITICAL( indice_count < ARRAY_COUNT( indices ) );
+            indices[ indice_count ].index = user_it;
+            indices[ indice_count ++ ].value = affinity;
+
+            const c8 *function = keyvalues_read_string( &_assembly, user_it, "function", NULL );
+            ASSERT_CRITICAL( function );
+            $v_string( &hooks_c, {returns}, {" "}, {function}, {"( "}, {prototype}, {" );\n"} );
+         }
+      }
+
+      index_sort( indices, indice_count );
+
+      $v_string( &hooks_c, {returns}, {" (*_event_"}, {name}, {"_subscribers[])( "}, {prototype}, {" ) = \n{\n"} );
+      for( u32 i=0; i<indice_count; i ++ )
+      {
+         const c8 *function = keyvalues_read_string( &_assembly, indices[i].index, "function", NULL );
+         ASSERT_CRITICAL( function );
+         $v_string( &hooks_c, {"   "}, {function}, {",\n"} );
+      }
+      $v_string( &hooks_c, {"   NULL\n};\n\n"} );
    }
 
-   $log( $info, {"Generating console header"} );
-   if( _console.using )
+   stream_close( &hooks_h );
+   stream_close( &hooks_c );
+}
+
+void _codegen_shaders(void)
+{
+   $log( $info, {"[CODEGEN] shaders.h/shaders.c"} );
+   struct stream C, H;
+   stream_open_file( &H, "generated/shaders.h", k_stream_write );
+   stream_open_file( &C, "generated/shaders.c", k_stream_write );
+
+   struct uniform_info
    {
-      struct stream console_header, console_source;
-      ASSERT_CRITICAL( stream_open_file( &console_header, "generated/console.h", k_stream_write ) );
-      $v_string( &console_header, {string_get( &_console.cvar_header )} );
-      stream_close( &console_header );
-
-      ASSERT_CRITICAL( stream_open_file( &console_source, "generated/console.c", k_stream_write ) );
-      $v_string( &console_source, {string_get( &_console.cvar_definitions )} );
-      $v_string( &console_source, {string_get( &_console.command_prototypes )} );
-      $v_string( &console_source, {"static struct console_command _console_commands[] = \n{\n"}, 
-            {string_get( &_console.command_definitions )}, {"};\n\n"} );
-      stream_close( &console_source );
+      u32 kv;
+      i32 glsl_index;
+      const c8 *type;
+      const c8 *alias;
+      const c8 *shader_name;
+   };
+   struct stretchy_allocator uniforms;
+   stretchy_init( &uniforms, sizeof(struct uniform_info) );
+
+   struct glsl_trans
+   {
+      const c8 *type, *args, *call, *end;
    }
-
-   $log( $info, {"Generating hooks header"} );
-   if( _hooks.using )
+   glsl_list[] =
    {
-      struct stream header, source;
-      ASSERT_CRITICAL( stream_open_file( &header, "generated/hooks.h", k_stream_write ) );
-      ASSERT_CRITICAL( stream_open_file( &source, "generated/hooks.c", k_stream_write ) );
-
-      for( u32 i=0; i<stretchy_count( &_hooks.events ); i ++ )
-      {
-         struct hook_event *event = stretchy_get( &_hooks.events, i );
+      { "int",          "i32 b",        "glUniform1i",            "b" },
+      { "vec2",         "f32 v[2]",     "glUniform2fv",           "1,v" },
+      { "vec3",         "f32 v[3]",     "glUniform3fv",           "1,v" },
+      { "vec4",         "f32 v[4]",     "glUniform4fv",           "1,v" },
+      { "bool",         "i32 b",        "glUniform1i",            "b" },
+      { "mat2",         "f32 m[2][2]",  "glUniformMatrix2fv",     "1,GL_FALSE,(f32*)m" },
+      { "mat3",         "f32 m[3][3]",  "glUniformMatrix3fv",     "1,GL_FALSE,(f32*)m" },
+      { "mat4",         "f32 m[4][4]",  "glUniformMatrix4fv",     "1,GL_FALSE,(f32*)m" },
+      { "float",        "f32 f",        "glUniform1f",            "f" },
+      { "mat4x3",       "f32 m[4][3]",  "glUniformMatrix4x3fv",   "1,GL_FALSE,(f32*)m" },
+      { "sampler2D",    "i32 i",        "glUniform1i",            "i" },
+      { "usampler3D",   "i32 i",        "glUniform1i",            "i" },
+      { "samplerCube",  "i32 i",        "glUniform1i",            "i" },
+      { "samplerBuffer","i32 i",        "glUniform1i",            "i" },
+   };
+
+   $v_string( &C, {"struct shader _shader_definitions[] = {\n"} );
+   $v_string( &H, {"enum shader_id\n{\n"} );
+   u32 it = 0;
+   while( keyvalues_foreach( &_assembly, &it, 0, "shader" ) )
+   {
+      u32 uniform_start = stretchy_count( &uniforms ),
+          uniform_count = 0;
 
-         const c8 *returns = string_get( &event->returns ),
-                  *alias = string_get( &event->alias ),
-                  *prototype = string_get( &event->proto );
+      const c8 *shader_name = keyvalues_read_string( &_assembly, it, "name", NULL );
+      ASSERT_CRITICAL( shader_name );
+      $v_string( &H, {"   k_shader_"},{shader_name},{",\n"} );
+      $v_string( &C, {"   [k_shader_"},{shader_name},{"] = \n   {\n"} );
+      $v_string( &C, {"      .name = \""}, {shader_name}, {"\",\n"} );
+      $v_string( &C, {"      .uniform_start = "}, $unsigned( uniform_start ), {",\n"} );
 
-         $v_string( &header, {"extern "}, {returns}, {" (*_event_"}, {alias}, {"_subscribers[])( "}, {prototype}, {" );\n"} );
+      $v_string( &C, {"      .subshaders = (struct subshader[])\n      {\n"} );
 
-         for( u32 j=0; j<stretchy_count( &event->users ); j ++ )
+      u32 subshader_count = 0;
+      u32 subshader_it = 0;
+      while( keyvalues_foreach( &_assembly, &subshader_it, it, "subshader" ) )
+      {
+         const c8 *subshader_type = keyvalues_read_string( &_assembly, subshader_it, "type", NULL );
+         ASSERT_CRITICAL( subshader_type );
+
+         $v_string( &C, {"         {\n"} );
+         $v_string( &C, {"            .type = k_subshader_"}, {subshader_type}, {",\n"} );
+         $v_string( &C, {"            .source_list = (const c8 *[])\n"} );
+         $v_string( &C, {"            {\n"} );
+
+         u32 sources[ 32 ];
+         u32 source_count = 0;
+         u32 source_it = 0;
+         while( keyvalues_foreach( &_assembly, &source_it, subshader_it, "add" ) )
          {
-            struct hook_user *user = stretchy_get( &event->users, j );
-            $v_string( &source, {returns}, {" "}, {string_get(&user->function_name)}, {"( "}, {prototype}, {" );\n"} );
+            ASSERT_CRITICAL( source_count < ARRAY_COUNT( sources ) );
+
+            /* FIXME: EXPAND PATH TO FULL PATH LIKE SOURCE ADDS */
+            const c8 *path = keyvalues_value( &_assembly, source_it, NULL );
+            $v_string( &C, {"               \""}, {path}, {"\",\n"} );
+            sources[ source_count ++ ] = source_it;
          }
-         $v_string( &source, {"\n"} );
 
-         b8 sorted = 0;
-         while( !sorted )
+         $v_string( &C, {"            },\n"} );
+         $v_string( &C, {"            .source_count = "}, $unsigned( source_count ), {",\n"} );
+         $v_string( &C, {"            .source_static = \""} );
+
+         for( u32 i=0; i<source_count; i ++ )
          {
-            sorted = 1;
-            
-            for( u32 j=1; j<stretchy_count( &event->users ); j ++ )
+            u32 context_block = _assembly_kv_file_context( sources[i] );
+            u32 temp_frame = _start_temporary_frame();
             {
-               struct hook_user *j1 = stretchy_get( &event->users, j ),
-                                *j0 = stretchy_get( &event->users, j-1 );
-               if( j1->affinity < j0->affinity )
+               struct stream path_string;
+               stream_open_stack( &path_string, _temporary_stack_allocator(), k_stream_null_terminate );
+               $v_string( &path_string, {keyvalues_read_string( &_assembly, context_block, "folder", NULL )}, {"/"}, 
+                                        {keyvalues_value( &_assembly, sources[i], NULL )} );
+
+               struct stream source_file;
+               ASSERT_CRITICAL( stream_open_file( &source_file, string_get( &path_string ), k_stream_read ) );
+               u32 l;
+               const c8 *source = stream_read_all( &source_file, _temporary_stack_allocator(), 4, &l );
+               for( u32 k=0; k<l; k ++ )
                {
-                  struct hook_user temp = *j0;
-                  *j0 = *j1;
-                  *j1 = temp;
-                  sorted = 0;
+                  c8 c = source[k];
+                  if( c == '\n' ) $v_string( &C, {"\\n"} );
+                  else            string_append_c8( &C, c );
                }
             }
+            _end_temporary_frame( temp_frame );
          }
 
-         $v_string( &source, {returns}, {" (*_event_"}, {alias}, {"_subscribers[])( "}, {prototype}, {" ) = \n{\n"} );
-         for( u32 j=0; j<stretchy_count( &event->users ); j ++ )
+         $v_string( &C, {"\",\n"} );
+         $v_string( &C, {"            .source_uniforms = \""} );
+
+         u32 uniform_it = 0;
+         while( keyvalues_foreach( &_assembly, &uniform_it, subshader_it, "uniform" ) )
          {
-            struct hook_user *user = stretchy_get( &event->users, j );
-            $v_string( &source, {"   "}, {string_get(&user->function_name)}, {",\n"} );
+            struct uniform_info *uniform = stretchy_append( &uniforms );
+            uniform->kv = uniform_it;
+            uniform->glsl_index = -1;
+            uniform->type = keyvalues_read_string( &_assembly, uniform_it, "type", NULL );
+            uniform->alias = keyvalues_read_string( &_assembly, uniform_it, "alias", NULL );
+            uniform->shader_name = shader_name;
+            ASSERT_CRITICAL( uniform->type && uniform->alias );
+
+            for( i32 i=0; i<ARRAY_COUNT( glsl_list ); i ++ )
+            {
+               if( compare_buffers( glsl_list[i].type, 0, uniform->type, 0 ) )
+               {
+                  uniform->glsl_index = i;
+                  break;
+               }
+            }
+            ASSERT_CRITICAL( uniform->glsl_index != -1 );
+            uniform_count ++;
+
+            $v_string( &C, {"uniform "}, {uniform->type}, {" "}, {uniform->alias}, {";\\n"} );
          }
-         $v_string( &source, {"   NULL\n};\n\n"} );
+         $v_string( &C, {"\",\n"}, {"         },\n"} );
+         subshader_count ++;
       }
 
-      stream_close( &source );
-      stream_close( &header );
+      $v_string( &C, {"      },\n"} );
+      $v_string( &C, {"      .uniform_count = "}, $unsigned( uniform_count ), {",\n"} );
+      $v_string( &C, {"      .subshader_count = "}, $unsigned( subshader_count ), {",\n"} );
+      $v_string( &C, {"   },\n"} );
+   }
+   $v_string( &C, {"};\n"} );
+   $v_string( &H, {"   k_shader_count\n};\n\n"} );
+
 
-      $v_string( &_metacompiler.source_list, {"      generated/hooks.c \\\n"} );
+   for( u32 i=0; i<stretchy_count(&uniforms); i ++ )
+   {
+      struct uniform_info *uniform = stretchy_get( &uniforms, i );
+      struct glsl_trans *trans = &glsl_list[ uniform->glsl_index ];
+      $v_string( &H, {"void _shader_"}, {uniform->shader_name}, {"_"}, {uniform->alias}, {"( "},{trans->args},{" );\n"} );
+      $v_string( &C, {"void _shader_"}, {uniform->shader_name}, {"_"}, {uniform->alias}, {"( "},{trans->args},{" )"},
+               {"{ "},{trans->call},{"( _uniform_locations["}, {"k_shader_"}, {uniform->shader_name}, {"_"}, {uniform->alias},
+               {"], "},{trans->end},{" ); }\n"});
    }
 
-   $log( $info, {"Generating shader header"} );
-   if( _shaders.using )
+   $v_string( &C, {"const c8 *_uniform_aliases[] = \n{\n"} );
+   $v_string( &H, {"enum shader_uniform_id\n{\n"} );
+   for( u32 i=0; i<stretchy_count(&uniforms); i ++ )
    {
-      struct stream header, source;
-      ASSERT_CRITICAL( stream_open_file( &header, "generated/shaders.h", k_stream_write ) );
-      ASSERT_CRITICAL( stream_open_file( &source, "generated/shaders.c", k_stream_write ) );
+      struct uniform_info *uniform = stretchy_get( &uniforms, i );
 
-      $v_string( &header, {"enum shader_id\n{\n"}, {string_get( &_shaders.shader_enum )}, {"   k_shader_count\n};\n"} );
-      $v_string( &header, {"enum shader_uniform_id\n{\n"}, {string_get( &_shaders.uniform_enum )}, {"   k_shader_uniform_count\n};\n"} );
-      $v_string( &header, {string_get( &_shaders.uniform_func_protos )} );
+      $v_string( &H, {"   k_shader_"}, {uniform->shader_name}, {"_"}, {uniform->alias}, {",\n"} );
+      $v_string( &C, {"   [k_shader_"}, {uniform->shader_name}, {"_"}, {uniform->alias}, {"] = \""}, {uniform->alias},{"\",\n"} );
+   }
+   $v_string( &H, {"   k_shader_uniform_count\n};\n\n"} );
+   $v_string( &C, {"};\n"} );
 
-      $v_string( &source, {"const c8 *_uniform_aliases[] = \n{\n"}, {string_get( &_shaders.uniform_aliases )}, {"};\n"} );
+   stream_close( &H );
+   stream_close( &C );
 
-      $v_string( &source, {"struct shader _shader_definitions[] = {\n"} );
-      for( u32 i=0; i<stretchy_count( &_shaders.shaders ); i ++ )
-      {
-         struct shader *shader = stretchy_get( &_shaders.shaders, i );
-         $v_string( &source, {"   [k_shader_"}, {string_get( &shader->name )}, {"] = \n   {\n"} );
-         $v_string( &source, {"      .name = \""}, {string_get( &shader->name )}, {"\",\n"} );
-         $v_string( &source, {"      .subshader_count = "}, $unsigned( shader->subshader_count ), {",\n"} );
-         $v_string( &source, {"      .uniform_start = "}, $unsigned( shader->uniform_start ), {",\n"} );
-         $v_string( &source, {"      .uniform_count = "}, $unsigned( shader->uniform_count ), {",\n"} );
-         $v_string( &source, {"      .subshaders = (struct subshader[])\n      {\n"} );
-
-         for( u32 j=0; j<shader->subshader_count; j ++ )
-         {
-            struct subshader *subshader = &shader->subshaders[ j ];
-            $v_string( &source, {"         {\n"} );
-            $v_string( &source, {"            .type = "}, 
-                  { (const c8 *[]){ [k_subshader_vertex] = "k_subshader_vertex",
-                                    [k_subshader_fragment] = "k_subshader_fragment",
-                                    [k_subshader_geometry] = "k_subshader_geometry" }[ subshader->type ] }, {",\n"} );
-            $v_string( &source, {"            .source_count = "}, $unsigned( subshader->debug_source_count ), {",\n"} );
-            $v_string( &source, {"            .source_list = (const c8 *[])\n"} );
-            $v_string( &source, {"            {\n"} );
-            $v_string( &source, {string_get( &subshader->debug_source_list )} );
-            $v_string( &source, {"            },\n"} );
-            $v_string( &source, {"            .source_static = \""} );
-
-            for( u32 k=0; k<subshader->static_source.offset; k ++ )
-            {
-               c8 c = subshader->static_source.buffer_read[ k ];
-               if( c == '\n' ) $v_string( &source, {"\\n"} );
-               else            string_append_c8( &source, c );
-            }
-            $v_string( &source, {"\",\n"} );
-            $v_string( &source, {"            .source_uniforms = \""}, {string_get( &subshader->uniform_source )}, {"\",\n"} );
-            $v_string( &source, {"         },\n"} );
-         }
+   stretchy_free( &uniforms );
+}
 
-         $v_string( &source, {"      },\n"} );
-         $v_string( &source, {"   },\n"} );
-      }
-      $v_string( &source, {"};\n"} );
-      $v_string( &source, {string_get( &_shaders.uniform_funcs )} );
+void _codegen_inputs(void)
+{
+   $log( $info, {"[CODEGEN] input.h/input.c"} );
+   struct stream C, H;
+   stream_open_file( &H, "generated/input.h", k_stream_write );
+   stream_open_file( &C, "generated/input.c", k_stream_write );
+
+   $v_string( &H, {"enum input_layer_id\n{\n"} );
+   u32 layer_it = 0;
+   while( keyvalues_foreach( &_assembly, &layer_it, 0, "input_layer" ) )
+   {
+      const c8 *layer_name = keyvalues_read_string( &_assembly, layer_it, "name", NULL );
+      ASSERT_CRITICAL( layer_name );
+      $v_string( &H, {"   k_input_layer_"}, {layer_name}, {",\n"} );
+   }
+   $v_string( &H, {"   k_input_layer_count\n};\n"} );
+   
+   $v_string( &H, {"enum input_id\n{\n"} );
+   $v_string( &C, {"struct input_info _input_infos[k_input_count] = \n{\n"} );
+   u32 input_it = 0;
+   while( keyvalues_foreach( &_assembly, &input_it, 0, "input" ) )
+   {
+      const c8 *name = keyvalues_read_string( &_assembly, input_it, "name", NULL );
+      const c8 *type = keyvalues_read_string( &_assembly, input_it, "type", NULL );
+      const c8 *layer_mask = keyvalues_read_string( &_assembly, input_it, "layer_mask", NULL );
+      ASSERT_CRITICAL( name && type );
+
+      $v_string( &H, {"   k_input_"},{type},{"_"}, {name}, {",\n"} );
+      $v_string( &C, {"   [k_input_"},{type},{"_"},{name},{"]=\n   {\n"} );
+      $v_string( &C, {"      .name = \""},{name},{"\",\n"} );
+      $v_string( &C, {"      .type = k_input_type_"},{type},{",\n"} );
+      if( layer_mask )
+         $v_string( &C, {"      .layer_mask = 1<<k_input_layer_"}, {layer_mask}, {",\n"} );
+      $v_string( &C, {"   },\n"} );
+   }
+   $v_string( &H, {"   k_input_count\n};\n"} );
+   $v_string( &C, {"};\n"} );
+
+   stream_close( &H );
+   stream_close( &C );
+}
+
+void _codegen_console(void)
+{
+   $log( $info, {"[CODEGEN] console.h/console.c"} );
+   struct stream C, H;
+   stream_open_file( &H, "generated/console.h", k_stream_write );
+   stream_open_file( &C, "generated/console.c", k_stream_write );
+
+   $v_string( &C, {"static struct console_command _console_commands[] = \n{\n"} );
+                  
+   u32 ccmd_it = 0;
+   while( keyvalues_foreach( &_assembly, &ccmd_it, 0, "ccmd" ) )
+   {
+      const c8 *name = keyvalues_read_string( &_assembly, ccmd_it, "name", NULL );
+      const c8 *function = keyvalues_read_string( &_assembly, ccmd_it, "function", NULL );
+      ASSERT_CRITICAL( name && function );
+
+      $v_string( &H, {"i32 "}, {function}, {"( struct console_arguments *args );\n"} );
+      $v_string( &C, {"   {\n      .alias = \""}, {name}, {"\",\n      .fn = "}, {function}, {"\n   },\n"} );
+   }
+   $v_string( &C, {"};\n\n"} );
+
+   stream_close( &H );
+   stream_close( &C );
+}
 
-      stream_close( &source );
-      stream_close( &header );
+void _codegen_threads(void)
+{
+   $log( $info, {"[CODEGEN] threads.h/threads.c"} );
+   struct stream C, H;
+   stream_open_file( &H, "generated/threads.h", k_stream_write );
+   stream_open_file( &C, "generated/threads.c", k_stream_write );
+
+   $v_string( &H, {"enum thread_id\n{\n"} );
+   $v_string( &C, {"struct thread_info _thread_infos[k_thread_count] = \n{\n"} );
+
+   u32 thread_it = 0;
+   while( keyvalues_foreach( &_assembly, &thread_it, 0, "thread" ) )
+   {
+      const c8 *name = keyvalues_read_string( &_assembly, thread_it, "name", NULL );
+      ASSERT_CRITICAL( name );
+
+      $v_string( &H, {"   k_thread_"},{name}, {",\n"} );
+
+      $v_string( &C, {"   [k_thread_"},{name},{"]=\n   {\n"} );
+      $v_string( &C, {"      .name = \""}, {name}, {"\",\n"} );
+
+      u32 queue_size_m = 0;
+      if( keyvalues_read_u32s( &_assembly, thread_it, "queue_size_m", NULL, &queue_size_m, 1 ) )
+         $v_string( &C, {"      .queue_size_m = "}, $unsigned(queue_size_m), {",\n"} );
+
+      u32 flag_kv = keyvalues_get( &_assembly, thread_it, "flag", 0 );
+      if( flag_kv )
+         $v_string( &C, {"      .flags = "} );
+
+      u32 flag_count = 0;
+      while( flag_kv )
+      {
+         const c8 *flag_name = keyvalues_value( &_assembly, flag_kv, NULL );
+         $v_string( &C, {flag_count? "|": ""}, {"THREAD_FLAG_"}, {flag_name} );
+         flag_kv = keyvalues_get( &_assembly, flag_kv, "flag", 1 );
+         flag_count ++;
+      }
+      if( flag_count )
+         $v_string( &C, {",\n"} );
+      $v_string( &C, {"   },\n"} );
    }
 
-   /* main */
+   $v_string( &H, {"   k_thread_count\n};\n"} );
+   $v_string( &C, {"};\n"} );
+
+   stream_close( &H );
+   stream_close( &C );
+}
+
+void _default_config_gen(void)
+{
+   $log( $info, {"[CODEGEN] default.cfg"} );
+
+   struct shell_command *cmd = _shell_command();
+   $v_string( &cmd->line, {"mkdir -p "}, {string_get( &_metacompiler.folder )}, {"/cfg"} );
+   _shell_run( cmd );
+
    u32 temp_frame = _start_temporary_frame();
    {
-      struct stream command_string;
-      stream_open_stack( &command_string, _temporary_stack_allocator(), k_stream_null_terminate );
-      $v_string( &command_string, {"taskset -c 0-"}, $unsigned(processors), 
-                                  {" zig cc -Wall -Wno-unused-function -std=gnu99 -D_REENTRANT -lm \\\n"}, 
-                                  {"   -include \"source/types.h\" \\\n"} );
+      struct stream config_path;
+      stream_open_stack( &config_path, _temporary_stack_allocator(), k_stream_null_terminate );
+      $v_string( &config_path, {string_get( &_metacompiler.folder )}, {"/cfg/default.cfg"} );
+
+      struct stream config_file;
+      ASSERT_CRITICAL( stream_open_file( &config_file, string_get( &config_path ), k_stream_write ) );
+
+      u32 config_it = 0;
+      while( keyvalues_foreach( &_assembly, &config_it, 0, "config" ) )
+         $v_string( &config_file, {keyvalues_value( &_assembly, config_it, NULL ) }, {"\n"} );
+
+      stream_close( &config_file );
+   }
+   _end_temporary_frame( temp_frame );
+}
+
+i32 main( i32 argc, const c8 *argv[] )
+{
+   VG_PRE_MAIN;
+
+   /* Get name of target and do a few checks */
+   i32 name_start = buffer_last_index( _option_file_path, '/', 0 );
+   if( name_start == -1 ) name_start = 0;
+   i32 name_end = buffer_last_index( _option_file_path+name_start, '.', 0 );
+
+   b8 valid_kv = 1;
+   if( name_end == -1 )
+      valid_kv = 0;
+   else if( !compare_buffers( ".kv", 0, _option_file_path+name_start+name_end, 0 ) )
+      valid_kv = 0;
+
+   if( !valid_kv )
+   {
+      $log( $fatal, {"Target file must be a text KV file"} );
+      _fatal_exit();
+   }
+
+   struct stream open_test;
+   if( stream_open_file( &open_test, _option_file_path, k_stream_read ) )
+      stream_close( &open_test );
+   else
+   {
+      $log( $fatal, {"Can't open for reading: '"}, {_option_file_path}, {"'"} );
+      _fatal_exit();
+   }
+
+   stream_open_auto( &_metacompiler.name, k_stream_null_terminate );
+   string_append( &_metacompiler.name, _option_file_path+name_start, name_end );
+
+   /* Create tripple string from configuration */
+   stream_open_auto( &_metacompiler.tripple, k_stream_null_terminate );
+   $v_string( &_metacompiler.tripple, {architecture_names[_option_arch]}, {"-"}, {platform_names[_option_platform]} );
+   if( _option_platform == k_platform_linux )
+   {
+      $v_string( &_metacompiler.tripple, {"-gnu"} );
+      if( _option_libc != k_libc_version_native )
+         $v_string( &_metacompiler.tripple, {"."}, {libc_names[_option_libc]} );
+   }
+
+   /* Create output folder (relative to target file) from tripple + name */
+   c8 *output_folder = realpath( _option_file_path, NULL );
+   if( !output_folder )
+   {
+      $log( $fatal, {"While making output folder, realpath of '"}, {_option_file_path}, {"' failed. "}, $errno() );
+      _fatal_exit();
+   }
+
+   i32 s = buffer_last_index( output_folder, '/', 0 );
+   if( s != -1 )
+      output_folder[s] = '\0';
+
+   stream_open_auto( &_metacompiler.folder, k_stream_null_terminate );
+   $v_string( &_metacompiler.folder, {output_folder}, {"/bin/"}, 
+               {string_get( &_metacompiler.name )}, {"-"}, {string_get( &_metacompiler.tripple )} );
+   
+   free(output_folder);
+   $log( $info, {"Target: "}, {string_get( &_metacompiler.name )}, {"\n"},
+                {"  configuration: "}, {string_get( &_metacompiler.tripple )}, {_option_shared?" SO":" EXE"}, {"\n"},
+                {"  output: "}, {string_get( &_metacompiler.folder )}, {"\n"},
+                {"  options: "}, 
+                  {_option_use_tsan? "TSAN ": ""}, 
+                  {_option_use_asan? "ASAN ": ""}, 
+                  {"O"}, $unsigned( _option_optimise ), {" "},
+                  {_option_no_pdb? "NO-PDB ": ""} );
+
+   /* Assemble target into main assembly */
+   struct stack_allocator stack;
+   stack_init( &stack, NULL, BYTES_MB(16), "Assembly KV" );
+   keyvalues_init( &_assembly, &stack );
+
+   u32 info_block = keyvalues_append_frame( &_assembly, 0, "vgc" );
+   keyvalues_append_string( &_assembly, info_block, "version", "0.2" );
+   keyvalues_append_string( &_assembly, info_block, "name", string_get( &_metacompiler.name ) );
+   keyvalues_append_string( &_assembly, info_block, "tripple", string_get( &_metacompiler.tripple ) );
+   keyvalues_append_string( &_assembly, info_block, "folder", string_get( &_metacompiler.folder ) );
+
+   if( _option_platform == k_platform_linux )   _metacompiler.enabled_features[0] = "linux";
+   if( _option_platform == k_platform_windows ) _metacompiler.enabled_features[0] = "windows";
+   _assemble_kv_file( _option_file_path, 0, 1 );
+   
+   if( _option_assemble_only )
+   {
+      keyvalues_write_stream( &_assembly, &_assemble_file, 0, 0 );
+      stream_close( &_assemble_file );
+      _normal_exit();
+   }
+
+   {
+      struct shell_command *cmd = _shell_command();
+      $v_string( &cmd->line, {"mkdir -p "}, {string_get( &_metacompiler.folder )} );
+      _shell_run( cmd );
+   }
+
+   {
+      struct shell_command *cmd = _shell_command();
+      $v_string( &cmd->line, {"mkdir -p generated"} );
+      _shell_run( cmd );
+   }
+
+   _codegen_hooks();
+   _codegen_shaders();
+   _codegen_inputs();
+   _codegen_console();
+   _codegen_threads();
+   
+   {
+      struct shell_command *cmd = _shell_command();
+      $v_string( &cmd->line, {"taskset -c 0-"}, $unsigned(_option_processors), 
+                             {" zig cc -Wall -Wno-unused-function -std=gnu99 -D_REENTRANT -lm \\\n"}, 
+                             {"   -include \"vg/source/types.h\" \\\n"} );
 
 #if 0
-      if( use_tsan ) $v_string( &command_string, {"   -fsanitize=thread -lasan -L/lib/x86_64-linux-gnu \\\n"} );
-      if( use_asan ) $v_string( &command_string, {"   -fsanitize=address -lasan -L/lib/x86_64-linux-gnu \\\n"} );
+      if( _option_use_tsan ) $v_string( &cmd->line, {"   -fsanitize=thread -lasan -L/lib/x86_64-linux-gnu \\\n"} );
+      if( _option_use_asan ) $v_string( &cmd->line, {"   -fsanitize=address -lasan -L/lib/x86_64-linux-gnu \\\n"} );
 #else
-      if( use_tsan ) $v_string( &command_string, {"   -fsanitize=thread -lasan -L/usr/lib \\\n"} );
-      if( use_asan ) $v_string( &command_string, {"   -fsanitize=address -lasan -L/usr/lib \\\n"} );
+      if( _option_use_tsan ) $v_string( &cmd->line, {"   -fsanitize=thread -lasan -L/usr/lib \\\n"} );
+      if( _option_use_asan ) $v_string( &cmd->line, {"   -fsanitize=address -lasan -L/usr/lib \\\n"} );
 #endif
-      $v_string( &command_string, { "   -O" }, $unsigned( optimise ) );
-      if( optimise == 0 ) $v_string( &command_string, { " -ggdb" } );
-      $v_string( &command_string, {" \\\n"} );
+      $v_string( &cmd->line, { "   -O" }, $unsigned( _option_optimise ) );
+      if( _option_optimise == 0 ) $v_string( &cmd->line, { " -ggdb" } );
+      $v_string( &cmd->line, {" \\\n"} );
 
-      $v_string( &command_string, {shared? " -shared -fPIC ": " "} );
-      if( platform == k_platform_windows )
+      $v_string( &cmd->line, {_option_shared? " -shared -fPIC ": " "} );
+      if( _option_platform == k_platform_windows )
       {
-         $v_string( &command_string, {"   -target "}, {string_get(&tripple_string)}, {" \\\n"} );
-         if( !shared )
-            $v_string( &command_string, {"-Wl,--subsystem=windows "} );
+         $v_string( &cmd->line, {"   -target "}, {string_get(&_metacompiler.tripple)}, {" \\\n"} );
+         if( !_option_shared )
+            $v_string( &cmd->line, {"-Wl,--subsystem=windows "} );
 
-         if( no_pdb )
-            $v_string( &command_string, {"-Wl,/pdb:/dev/null "} );
+         if( _option_no_pdb )
+            $v_string( &cmd->line, {"-Wl,/pdb:/dev/null "} );
       }
-      $v_string( &command_string, {"\\\n"} );
-
-      $v_string( &command_string, {"   -fno-sanitize=undefined \\\n"} );
-      $v_string( &command_string, {"   -fkeep-static-consts -fkeep-persistent-storage-variables \\\n"} );
-
-      $v_string( &command_string, {"      -I. \\\n"} );
-      $v_string( &command_string, {string_get( &_metacompiler.include_path_list )} );
-      $v_string( &command_string, {string_get( &_metacompiler.define_list )} );
-      $v_string( &command_string, {string_get( &_metacompiler.source_list )} );
+      $v_string( &cmd->line, {"\\\n"} );
 
-      $v_string( &command_string, {"-o "}, {string_get( &folder_string )}, {"/"}, {_metacompiler.project_name} );
-      if( platform == k_platform_windows ) $v_string( &command_string, {shared? ".dll ": ".exe "} );
-      else                                 $v_string( &command_string, {shared? ".so ": " "} );
+      $v_string( &cmd->line, {"   -fno-sanitize=undefined \\\n"} );
+      $v_string( &cmd->line, {"   -fkeep-static-consts -fkeep-persistent-storage-variables \\\n"} );
 
-      system_call( string_get( &command_string ) );
+      $v_string( &cmd->line, {"      -I. \\\n"} );
 
-      if( _console.using )
+      u32 compile_it = 0;
+      while( keyvalues_foreach( &_assembly, &compile_it, 0, NULL ) )
       {
-         u32 temp_frame2 = _start_temporary_frame();
-         struct stream command_string;
-         stream_open_stack( &command_string, _temporary_stack_allocator(), k_stream_null_terminate );
-         $v_string( &command_string, {"mkdir -p "}, {string_get( &folder_string )}, {"/cfg"} );
-         system_call( string_get( &command_string ) );
-
-         struct stream config_path;
-         stream_open_stack( &config_path, _temporary_stack_allocator(), k_stream_null_terminate );
-         $v_string( &config_path, {string_get( &folder_string )}, {"/cfg/default.cfg"} );
-
-         struct stream config_file;
-         ASSERT_CRITICAL( stream_open_file( &config_file, string_get( &config_path ), k_stream_write ) );
-         $v_string( &config_file, {string_get( &_metacompiler.configuration )} );
-         stream_close( &config_file );
-
-         _end_temporary_frame( temp_frame2 ); 
+         const c8 *key = keyvalues_key( &_assembly, compile_it, NULL );
+         b8 include   = compare_buffers( key, 0, "include", 0 ),
+            link      = compare_buffers( key, 0, "link", 0 ),
+            link_path = compare_buffers( key, 0, "link_folder", 0 ),
+            define    = compare_buffers( key, 0, "define", 0 ),
+            add       = compare_buffers( key, 0, "add", 0 );
+
+         if( include || link_path || add )
+         {
+            u32 context_block = _assembly_kv_file_context( compile_it );
+            if( include )   $v_string( &cmd->line, {"     -I"} );
+            if( link_path ) $v_string( &cmd->line, {"     -L"} );
+            if( add )       $v_string( &cmd->line, {"      "} );
+            $v_string( &cmd->line, {keyvalues_read_string( &_assembly, context_block, "folder", NULL )}, 
+                                   {"/"}, {keyvalues_value( &_assembly, compile_it, NULL )}, {" \\\n"} );
+         }
+         else if( define || link )
+         {
+            if( define ) $v_string( &cmd->line, {"     -D"} );
+            if( link )   $v_string( &cmd->line, {"     -l"} );
+            $v_string( &cmd->line, {keyvalues_value( &_assembly, compile_it, NULL )}, {" \\\n"} );
+         }
       }
+      $v_string( &cmd->line, {"    generated/hooks.c \\\n"} );
 
-      for( u32 i=0; i< stretchy_count( &_commands.shell ); i ++ )
-      {
-         struct shell_command *command = stretchy_get( &_commands.shell, i );
-         system_call( string_get( &command->command ) );
-      }
+      $v_string( &cmd->line, {"-o "}, {string_get( &_metacompiler.folder )}, {"/"}, {string_get(&_metacompiler.name)} );
+      if( _option_platform == k_platform_windows ) $v_string( &cmd->line, {_option_shared? ".dll ": ".exe "} );
+      else                                         $v_string( &cmd->line, {_option_shared? ".so ": " "} );
+      _shell_run( cmd );
    }
-   _end_temporary_frame( temp_frame ); 
+
+   _default_config_gen();
    return 0;
 }