uh yeah
authorhgn <hgodden00@gmail.com>
Mon, 6 Oct 2025 22:47:35 +0000 (22:47 +0000)
committerhgn <hgodden00@gmail.com>
Mon, 6 Oct 2025 22:47:35 +0000 (22:47 +0000)
12 files changed:
foundation.kv
include/common_api.h
include/engine_interface.h
include/graphics_api.h
include/input_api.h [new file with mode: 0644]
source/engine/console.c
source/engine/input.c
source/engine/main.c
source/engine/ui.c
source/foundation/keyvalues.c
source/graphics/ui.c
source/tools/metacompiler.c

index 20a0e3c951e7794029280bae362df81a286c9757..259175b8af4d7692c95782dfd0efc855f36b1eca 100644 (file)
@@ -48,7 +48,9 @@ add source/foundation/temporary.c
 }
 
 {
+
    if game_engine
+
    {
       add source/engine/main.c
       hook
@@ -56,6 +58,27 @@ add source/foundation/temporary.c
          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"
+      }
    }
 
    {
@@ -74,6 +97,11 @@ add source/foundation/temporary.c
          event START
          function _input_init
       }
+      hook
+      {
+         event ENGINE_NEW_FRAME
+         function _input_update
+      }
       ccmd
       {
          name bind
@@ -119,6 +147,17 @@ add source/foundation/temporary.c
          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 source/engine/shader.c
@@ -126,6 +165,10 @@ add source/foundation/temporary.c
    {
       name console
    }
+   input_layer
+   {
+      name ui
+   }
    input
    {
       name console
@@ -177,101 +220,90 @@ add source/foundation/temporary.c
    config "bind ENTER ui_enter"
    config "bind TAB ui_indent"
    config "bind HOME ui_home"
-   config "bind SHIFT+HOME ui_home_select"
    config "bind END ui_end"
-   config "bind SHIFT+END ui_end_select"
    config "bind LEFT ui_left"
-   config "bind SHIFT+LEFT ui_left_select"
    config "bind RIGHT ui_right"
-   config "bind SHIFT+RIGHT ui_right_select"
    config "bind UP ui_up"
-   config "bind SHIFT+UP ui_up_select"
    config "bind DOWN ui_down"
-   config "bind SHIFT+DOWN ui_down_select"
+   config "bind MOUSE_LEFT ui_click"
+
+   config "bind LEFT_SHIFT ui_select"
+   config "bind RIGHT_SHIFT ui_select"
 
    input
    {
       name ui_delete
       type action
+      layer_mask ui
    }
    input
    {
       name ui_backspace
       type action
+      layer_mask ui
    }
    input
    {
       name ui_enter
       type action
+      layer_mask ui
    }
    input
    {
       name ui_indent
       type action
+      layer_mask ui
    }
 
    input
    {
-      name ui_home
-      type action
+      name ui_select
+      type button
+      layer_mask ui
    }
    input
    {
-      name ui_home_select
-      type action
+      name ui_home
+      type button
+      layer_mask ui
    }
    input
    {
       name ui_end
-      type action
-   }
-   input
-   {
-      name ui_end_select
-      type action
+      type button
+      layer_mask ui
    }
    input
    {
       name ui_left
-      type action
-   }
-   input
-   {
-      name ui_left_select
-      type action
+      type button
+      layer_mask ui
    }
    input
    {
       name ui_right
-      type action
-   }
-   input
-   {
-      name ui_right_select
-      type action
+      type button
+      layer_mask ui
    }
    input
    {
       name ui_up
-      type action
-   }
-   input
-   {
-      name ui_up_select
-      type action
+      type button
+      layer_mask ui
    }
    input
    {
       name ui_down
-      type action
+      type button
+      layer_mask ui
    }
-   input
+   input 
    {
-      name ui_down_select
+      name ui_click
       type action
+      layer_mask ui
    }
 
-
    shader
    {
       name blit
@@ -314,26 +346,6 @@ add source/foundation/temporary.c
       cheat 1
       description "This is just a test variable!"
    }
-   event
-   {
-      name ENGINE_FIXED_UPDATE
-      prototype "void"
-   }
-   event
-   {
-      name ENGINE_UPDATE
-      prototype "void"
-   }
-   event
-   {
-      name ENGINE_RENDER
-      prototype "void"
-   }
-   event
-   {
-      name ENGINE_UI
-      prototype "void"
-   }
 
    hook
    {
index 985bba41e1a7901c97ab572cf05a2e12453b66eb..da6de5e4842b11598d7a022bd44adcd567515038 100644 (file)
@@ -299,7 +299,7 @@ enum string_parse_result string_parse_string( struct stream *string, u32 *out_st
 #define $TO_STRING( S ) $TO_STRING_1( S )
 #define $TO_STRING_1( S ) #S
 #define $line __FILE__ ":" $TO_STRING(__LINE__)
-#define $log( C, ... ) $v_string( _log_event( C, $line ), __VA_ARGS__ ); _log_end_event();
+#define $log( C, ... ) { $v_string( _log_event( C, $line ), __VA_ARGS__ ); _log_end_event(); }
 
 struct stream *_log_event( u32 type, const c8 *code_location );
 void _log_init(void);
@@ -375,3 +375,9 @@ void directory_close( struct directory *directory );
    for( u32 ev_iter=0; _event_##NAME##_subscribers[ ev_iter ]; ev_iter ++ ) \
       _event_##NAME##_subscribers[ ev_iter ]( __VA_ARGS__ );
 
+struct sort_index
+{
+   u32 index;
+   i32 value;
+};
+void index_sort( struct sort_index *indices, u32 indice_count );
index be2c03e40b3718882ba0f5c5a6deb09426f409a1..58c7a1d15bc5b890a2399c664c2ddf2ecede85b0 100644 (file)
@@ -16,38 +16,4 @@ struct _engine
    i32 w, h;
 }
 extern _engine;
-
-enum input_type
-{
-   k_input_type_action,
-   k_input_type_button,
-   k_input_type_axis
-};
-
-enum input_device
-{
-   k_input_device_none = 0,
-   k_input_device_keyboard,
-   k_input_device_controller
-};
-
-struct input_info
-{
-   const c8 *name;
-   enum input_type type;
-   u32 layer_mask;
-};
-
-enum input_id;
-
-// TODO: These are backend?
-void _input_init(void);
-void _input_update(void);
-
-bool _input_button_down( enum input_id id );
-bool _input_button_up( enum input_id id );
-bool _input_button( enum input_id id );
-u8 _input_action( enum input_id id );
-
-#include "generated/input.h"
 #include "generated/console.h"
index 10c2bdef1e66c7e700812637d6be2b520c8b41c1..701e4924626f611d56abcf1b8a1497323dddc2d0 100644 (file)
@@ -88,24 +88,7 @@ bool _font_decode_bitmap( i16 uv[2] );
 
 /* Immediate mode UI
  * ------------------------------------------------------------------------------------------------------------------ */
-
-enum ui_action
-{
-   k_ui_action_backspace,
-   k_ui_action_delete,
-   k_ui_action_enter,
-   k_ui_action_indent,
-
-   /* + super -> editing selection */
-   k_ui_action_home,
-   k_ui_action_end,
-   k_ui_action_left,
-   k_ui_action_right,
-   k_ui_action_up,
-   k_ui_action_down
-};
-
-void _ui_input_action( enum ui_action action, bool super );
+void _ui_set_mouse( i16 x, i16 y );
 void _ui_input_text( const c8 *text );
 
 #define UI_PADDING_PX     8
diff --git a/include/input_api.h b/include/input_api.h
new file mode 100644 (file)
index 0000000..fa5dc52
--- /dev/null
@@ -0,0 +1,32 @@
+enum input_type
+{
+   k_input_type_action,
+   k_input_type_button,
+   k_input_type_axis
+};
+
+enum input_device
+{
+   k_input_device_none = 0,
+   k_input_device_keyboard,
+   k_input_device_controller,
+   k_input_device_mouse
+};
+
+struct input_info
+{
+   const c8 *name;
+   enum input_type type;
+   u32 layer_mask;
+};
+
+enum input_id;
+
+u8 _input_button_down( enum input_id id, bool allow_repeats );
+u8 _input_button_up( enum input_id id );
+u8 _input_button( enum input_id id );
+
+void _input_layer_whitelist( u32 whitelist );
+bool _input_layer_filter( u32 mask );
+
+#include "generated/input.h"
index 005ff54b5d3c136932f674b3a40e03a5f57e8db5..28a79f49173feb88771dec7c371cdb674bb16be1 100644 (file)
@@ -1,10 +1,12 @@
 #include "console_core.h"
 #include "graphics_api.h"
 #include "engine_interface.h"
+#include "input_api.h"
 
 struct
 {
    struct queue_allocator input_history, log_history;
+   bool open;
 }
 _console;
 
@@ -16,8 +18,42 @@ struct log_history_item
 
 static c8 _input_buffer[ 1024 ];
 
+static void _log_listener( const c8 *line, u32 length, u32 type )
+{
+again:;
+   struct log_history_item *item = queue_alloc( &_console.log_history, sizeof( struct log_history_item ) + length+1 );
+   if( !item )
+   {
+      queue_pop( &_console.log_history );
+      goto again;
+   }
+
+   item->type = type;
+   buffer_copy( line, 0, item->buffer, length+1 );
+}
+
+void _engine_console_init(void)
+{
+   _log_add_listener( _log_listener, ($info | $ok | $warning | $error | $fatal | $shell), 0 );
+   queue_init( &_console.input_history, _heap_allocate( BYTES_KB(2) ), BYTES_KB(2) );
+   queue_init( &_console.log_history, _heap_allocate( BYTES_KB(4) ), BYTES_KB(4) );
+}
+
+void _engine_console_update(void)
+{
+   for( u8 j=0; j<_input_button_down( k_input_action_console, 0 ); j ++ )
+   {
+      _console.open ^= 0x1;
+      u32 console_mask = (1 << k_input_layer_console) | (1 << k_input_layer_ui);
+      _input_layer_whitelist( _console.open? console_mask: 0 );
+   }
+}
+
 void _engine_console_ui(void)
 {
+   if( !_console.open )
+      return;
+   
    i16 kerning[3];
    _font_get_kerning( kerning );
    i16 history_box[4] = { 0, 0, _engine.w, kerning[1] * 32 };
@@ -47,24 +83,3 @@ void _engine_console_ui(void)
       _input_buffer[0] = '\0';
    }
 }
-
-static void _log_listener( const c8 *line, u32 length, u32 type )
-{
-again:;
-   struct log_history_item *item = queue_alloc( &_console.log_history, sizeof( struct log_history_item ) + length+1 );
-   if( !item )
-   {
-      queue_pop( &_console.log_history );
-      goto again;
-   }
-
-   item->type = type;
-   buffer_copy( line, 0, item->buffer, length+1 );
-}
-
-void _engine_console_init(void)
-{
-   _log_add_listener( _log_listener, ($info | $ok | $warning | $error | $fatal | $shell), 0 );
-   queue_init( &_console.input_history, _heap_allocate( BYTES_KB(2) ), BYTES_KB(2) );
-   queue_init( &_console.log_history, _heap_allocate( BYTES_KB(4) ), BYTES_KB(4) );
-}
index 6c98055fbcf85fc28eac133a4df4c68927098ef2..d5e5c2382147bb1a5589c277b09f09b35db859d8 100644 (file)
@@ -1,5 +1,6 @@
 #include "glfw.h"
 #include "engine_interface.h"
+#include "input_api.h"
 #include "console_core.h"
 #include "generated/input.c"
 
@@ -12,6 +13,9 @@ struct input_alias
 }
 _input_aliases[] = 
 {
+   { "MOUSE_LEFT", k_input_device_mouse, .key = GLFW_MOUSE_BUTTON_1 },
+   { "MOUSE_RIGHT", k_input_device_mouse, .key = GLFW_MOUSE_BUTTON_2 },
+   { "MOUSE_MIDDLE", k_input_device_mouse, .key = GLFW_MOUSE_BUTTON_3 },
    { "SPACE", k_input_device_keyboard, .key = GLFW_KEY_SPACE },
    { "APOSTROPHE", k_input_device_keyboard, .key = GLFW_KEY_APOSTROPHE },
    { "COMMA", k_input_device_keyboard, .key = GLFW_KEY_COMMA },
@@ -157,14 +161,7 @@ union input_state
 {
    struct
    {
-      u8 activation_count;
-   }
-   action;
-
-   struct
-   {
-      u8 press_count;
-      bool up, down;
+      u8 hold_count, activation_count, release_count, repeat_count;
    }
    button;
 
@@ -237,7 +234,7 @@ i32 _input_bind_ccmd( struct console_arguments *args )
          else
             new_bind.device = alias->device_type;
 
-         if( alias->device_type == k_input_device_keyboard )
+         if( (alias->device_type == k_input_device_keyboard) || (alias->device_type == k_input_device_mouse) )
          {
             if( alias->key )
             {
@@ -297,56 +294,52 @@ i32 _input_unbind_ccmd( struct console_arguments *args )
    return -1;
 }
 
-// bind LEFT ui_left  <---- action
-// bind RIGHT ui_right <---- action
-// bind SHIFT ui_select
-// bind CTRL+N console_suggest_next
-// bind CTRL+P console_suggest_prev
-//
-// bind W forward <---- button
-// bind S back
-//
-// bind X delete
-// bind SHIFT+X move
-
-static void _input_key_callback( GLFWwindow *window, i32 key, i32 scancode, i32 action, i32 mods )
+static void _input_callback_buttonlike( enum input_device device, i32 id, i32 action, i32 mods )
 {
    for( u32 i=0; i<stretchy_count( &_bind_allocator ); i ++ )
    {
       struct bind *bind = stretchy_get( &_bind_allocator, i );
-      if( bind->device == k_input_device_keyboard )
+      if( bind->device == device )
       {
-         if( bind->id == key )
+         if( bind->id == id )
          {
             struct input_info *input = &_input_infos[ bind->input_index ];
             union input_state *state = &_input_states[ _input_page^0x1 ][ bind->input_index ];
 
-            if( input->type == k_input_type_action )
+            if( (input->type == k_input_type_action) || (input->type == k_input_type_button) )
             {
-               if( (action == GLFW_PRESS) || (action == GLFW_REPEAT) )
+               if( input->type == k_input_type_action )
                {
-                  if( bind->modifiers == mods )
-                  {
-                     ASSERT_CRITICAL( state->action.activation_count < 255 );
-                     state->action.activation_count ++;
-                  }
+                  if( bind->modifiers != mods )
+                     continue;
                }
-            }
-            else if( input->type == k_input_type_button )
-            {
+
+               if( action == GLFW_REPEAT || action == GLFW_PRESS )
+               {
+                  ASSERT_CRITICAL( state->button.repeat_count < 255 );
+                  state->button.repeat_count ++;
+               }
+
                if( action == GLFW_PRESS )
                {
-                  ASSERT_CRITICAL( state->button.press_count < 255 );
-                  if( state->button.press_count == 0 )
-                     state->button.down = 1;
-                  state->button.press_count ++;
+                  ASSERT_CRITICAL( state->button.activation_count < 255 );
+                  state->button.activation_count ++;
+
+                  if( input->type == k_input_type_button )
+                  {
+                     ASSERT_CRITICAL( state->button.hold_count < 255 );
+                     state->button.hold_count ++;
+                  }
                }
-               else if( action == GLFW_RELEASE )
+               
+               if( action == GLFW_RELEASE )
                {
-                  ASSERT_CRITICAL( state->button.press_count > 0 );
-                  state->button.press_count --;
-                  if( state->button.press_count == 0 )
-                     state->button.up = 1;
+                  if( input->type == k_input_type_button )
+                  {
+                     ASSERT_CRITICAL( state->button.hold_count > 0 );
+                     state->button.hold_count --;
+                     state->button.release_count ++;
+                  }
                }
             }
             else if( input->type == k_input_type_axis )
@@ -358,6 +351,16 @@ static void _input_key_callback( GLFWwindow *window, i32 key, i32 scancode, i32
    }
 }
 
+static void _input_mouse_callback( GLFWwindow *window, i32 button, i32 action, i32 mods )
+{
+   _input_callback_buttonlike( k_input_device_mouse, button, action, mods );
+}
+
+static void _input_key_callback( GLFWwindow *window, i32 key, i32 scancode, i32 action, i32 mods )
+{
+   _input_callback_buttonlike( k_input_device_keyboard, key, action, mods );
+}
+
 void _input_init(void)
 {
    glfwSetKeyCallback( _engine.window_handle, _input_key_callback );
@@ -375,42 +378,55 @@ void _input_update(void)
       union input_state *back_state = &_input_states[ _input_page^0x1 ][ i ],
                         *state = &_input_states[ _input_page ][ i ];
 
-      if( input->type == k_input_type_action )
+      if( (input->type == k_input_type_action) || (input->type == k_input_type_button) )
       {
-         back_state->action.activation_count = 0;
-      }
-      else if( input->type == k_input_type_button )
-      {
-         back_state->button.down = 0;
-         back_state->button.up = 0;
-         back_state->button.press_count = state->button.press_count;
+         back_state->button.activation_count = 0;
+         back_state->button.repeat_count = 0;
+         back_state->button.release_count = 0;
+         back_state->button.hold_count = state->button.hold_count;
       }
    }
 }
 
-static union input_state *_get_input_of_type( enum input_type type, enum input_id id )
+static union input_state *_get_input_state( enum input_id id )
 {
-   struct input_info *input = &_input_infos[ id ];
-   ASSERT_CRITICAL( input->type == type );
    return &_input_states[ _input_page ][ id ];
 }
 
-bool _input_button_down( enum input_id id )
+static u32 _whitelist = 0x00;
+
+
+bool _input_layer_filter( u32 mask )
 {
-   return _get_input_of_type( k_input_type_button, id )->button.down;
+   return (_whitelist & mask) || !_whitelist;
+}
+
+bool _filter_input( enum input_id id )
+{
+   return _input_layer_filter( _input_infos[ id ].layer_mask );
+}
+
+u8 _input_button_down( enum input_id id, bool allow_repeats )
+{
+   if( _filter_input(id) )
+   {
+      union input_state *state = _get_input_state( id );
+      return allow_repeats? state->button.repeat_count: state->button.activation_count;
+   }
+   else return 0;
 }
 
-bool _input_button_up( enum input_id id )
+u8 _input_button_up( enum input_id id )
 {
-   return _get_input_of_type( k_input_type_button, id )->button.up;
+   return _filter_input(id) && _get_input_state( id )->button.release_count;
 }
 
-bool _input_button( enum input_id id )
+u8 _input_button( enum input_id id )
 {
-   return _get_input_of_type( k_input_type_button, id )->button.press_count > 0;
+   return _filter_input(id) && _get_input_state( id )->button.hold_count;
 }
 
-u8 _input_action( enum input_id id )
+void _input_layer_whitelist( u32 whitelist )
 {
-   return _get_input_of_type( k_input_type_action, id )->action.activation_count;
+   _whitelist = whitelist; 
 }
index 20fc9feba6b28daf451259a3e2f6dd82486f14f1..c4615f5c4af8ff25076e5d97571ba5f14b7798aa 100644 (file)
@@ -2,6 +2,7 @@
 #include <math.h>
 #include "engine_interface.h"
 #include "engine_backend.h"
+#include "input_api.h"
 #include "opengl.h"
 #include "glfw.h"
 
@@ -35,7 +36,8 @@ static void _engine_set_framerate( f64 hz, bool vsync )
 
 void _character_callback( GLFWwindow *window, u32 codepoint )
 {
-   _engine_ui_input_character( codepoint );
+   if( _input_layer_filter( 1<<k_input_layer_ui ) )
+      _engine_ui_input_character( codepoint );
 }
 
 void _engine_options(void)
@@ -100,14 +102,8 @@ L_new_frame:;
    _engine.time = now;
    next_frame_time = now + 1.0/_engine.framerate_limit;
 
-   _input_update();
-
-   /* pre-update */
-   for( u8 j=0; j<_input_action( k_input_action_console ); j ++ )
-   {
-      _engine_backend.console_open ^= 0x1;
-      //_input.layer_whitelist = _engine_backend.console_open? (1 << k_input_layer_console): 0;
-   }
+   /* normal update */
+   EVENT_CALL( ENGINE_NEW_FRAME );
 
    /* fixed update */
    fixed_accumulator += _engine.time_delta;
@@ -129,15 +125,10 @@ L_new_frame:;
    _engine.time_delta = actual_delta;
    _engine.time_fixed_extrapolate = fixed_accumulator / (1.0/60.0);
 
-   /* normal update */
-   EVENT_CALL( ENGINE_UPDATE );
-
    glfwGetFramebufferSize( _engine.window_handle, &_engine.w, &_engine.h );
    EVENT_CALL( ENGINE_RENDER );
    _engine_ui_pre_render();
    EVENT_CALL( ENGINE_UI );
-   if( _engine_backend.console_open )
-      _engine_console_ui();
    _engine_ui_post_render();
 
    glfwSwapBuffers(_engine.window_handle);
index 931cb280ca406a09e16b9c282b9c92c8e63f12bb..9ed7b11d6a8570c750ab05d8f676662278a3745f 100644 (file)
@@ -2,6 +2,7 @@
 #include "graphics_api.h"
 #include "engine_interface.h"
 #include "engine_backend.h"
+#include "glfw.h"
 
 struct graphics_target _ui_surface = 
 {
@@ -45,50 +46,21 @@ void _engine_ui_pre_render(void)
 {
    ASSERT_CRITICAL( _engine.w <= 1920 );
    ASSERT_CRITICAL( _engine.h <= 1080 );
+   
+   f64 x, y;
+   glfwGetCursorPos( _engine.window_handle, &x, &y );
+   _ui_set_mouse( x, y );
+   _ui_update();
 
    _graphics_set_target( &_ui_surface );
    _graphics_viewport( 0, 0, _engine.w, _engine.h );
    _graphics_fill_rect( (i16[]){ 0, 0, _engine.w, _engine.h }, (union colour){{0,0,0,255}} );
-   _graphics_fill_rect( (i16[]){ 4, 8, 20, 23 }, (union colour){{0,230,20,255}} );
-   _graphics_line_rect( (i16[]){ 0, 0, _engine.w-1, _engine.h-1 }, (union colour){{255,230,20,255}} );
-   _graphics_glyph( (i16[]){0,0}, 'w', 1, (union colour){{30,30,200,255}} );
-
-   c8 buf[128];
-   struct stream str;
-   stream_open_buffer_write( &str, buf, sizeof(buf), k_stream_null_terminate );
-   $v_string( &str, {"Hello! "}, $float( _engine.time, .decimals = 3 ) );
-
-   _ui_text( (i16[]){32,32,400,20}, string_get(&str), k_ui_align_x_left, (union colour){{0,255,0,255}} );
-
-   struct
-   {
-      enum input_id input_id;
-      enum ui_action action_id;
-      bool super;
-   }
-   ui_binds[] =
-   {
-      { k_input_action_ui_backspace, k_ui_action_backspace },
-      { k_input_action_ui_delete, k_ui_action_delete },
-      { k_input_action_ui_enter, k_ui_action_enter },
-      { k_input_action_ui_indent, k_ui_action_indent },
-      { k_input_action_ui_home, k_ui_action_home },
-      { k_input_action_ui_home_select, k_ui_action_home, 1 },
-      { k_input_action_ui_end, k_ui_action_end },
-      { k_input_action_ui_end_select, k_ui_action_end, 1 },
-      { k_input_action_ui_left, k_ui_action_left },
-      { k_input_action_ui_left_select, k_ui_action_left, 1 },
-      { k_input_action_ui_right, k_ui_action_right },
-      { k_input_action_ui_right_select, k_ui_action_right, 1 },
-      { k_input_action_ui_up, k_ui_action_up },
-      { k_input_action_ui_up_select, k_ui_action_up, 1 },
-      { k_input_action_ui_down, k_ui_action_down },
-      { k_input_action_ui_down_select, k_ui_action_down, 1 }
-   };
+}
 
-   for( u32 i=0; i<ARRAY_COUNT( ui_binds ); i ++ )
-      for( u8 j=0; j<_input_action( ui_binds[i].input_id ); j ++ )
-         _ui_input_action( ui_binds[i].action_id, ui_binds[i].super );
+void _engine_ui_input_character( u32 codepoint )
+{
+   if( (codepoint >= (u32)' ') && (codepoint <= (u32)'~') )
+      _ui_input_text( (const c8[]){ codepoint, 0 } );
 }
 
 void _engine_ui_post_render(void)
@@ -104,9 +76,3 @@ void _engine_ui_post_render(void)
    glBindVertexArray( quad_vao );
    glDrawArrays( GL_TRIANGLES, 0, 6 );
 }
-
-void _engine_ui_input_character( u32 codepoint )
-{
-   if( (codepoint >= (u32)' ') && (codepoint <= (u32)'~') )
-      _ui_input_text( (const c8[]){ codepoint, 0 } );
-}
index 1bb4b63bddc0c1743b7be3edaac3a61c8b3f0069..039982c7d4176d6ce5fa0a8c109813e47ed5ce47 100644 (file)
@@ -192,6 +192,30 @@ u32 keyvalues_get( struct keyvalues *kvs, u32 root_offset, const c8 *key )
    return 0;
 }
 
+bool keyvalues_read_i32s( struct keyvalues *kvs, u32 root_offset, const c8 *key, i32 *default_values, i32 *out_values, u32 len )
+{
+   bool good = 1;
+
+   u32 value_length;
+   char *value = keyvalues_value( kvs, keyvalues_get( kvs, root_offset, key ), &value_length );
+   struct stream s;
+   stream_open_buffer_read( &s, value, value_length, 0 );
+
+   for( u32 i=0; i<len; i ++ )
+   {
+      i64 value = 0;
+      if( string_parse_i64( &s, &value ) == k_string_parse_ok ) 
+         out_values[ i ] = (i32)value;
+      else
+      {
+         good = 0;
+         if( default_values ) out_values[ i ] = default_values[ i ];
+         else                 out_values[ i ] = 0;
+      }
+   }
+   return good;
+}
+
 bool keyvalues_read_u32s( struct keyvalues *kvs, u32 root_offset, const c8 *key, u32 *default_values, u32 *out_values, u32 len )
 {
    bool good = 1;
index 1d3296976e8d50b55f43979c1ac1bd7081749315..51de2f64e8c70c88a284d038b37932d5065fc1be 100644 (file)
@@ -1,4 +1,5 @@
 #include "graphics_api.h"
+#include "input_api.h"
 #include "maths/common_maths.h"
 
 #define KEYBOARD_ALT      0x1
@@ -11,9 +12,6 @@ struct
    //i16 clipping_area[4];
 
    i16 mouse_co[2], mouse_co_clicked[2];
-   u32  mouse_clicking, 
-        mouse_click_down,
-        mouse_click_up;
 
    /* internal state */
    enum ui_control_type
@@ -62,60 +60,6 @@ void _ui_set_encoding( enum ui_text_encoding encoding )
    _ui.text_encoding = encoding;
 }
 
-bool _ui_update(void)
-{
-   _ui.mouse_click_down = 0x00;
-   _ui.mouse_click_up = 0x00;
-
-   if( _ui.active_control_type == k_ui_control_button )
-      if( !(_ui.mouse_clicking & MOUSE_LEFT) )
-         _ui.active_control_type = k_ui_control_none;
-
-   return _ui.redraw;
-}
-
-void _ui_draw(void)
-{
-   if( _ui.active_control_type == k_ui_control_dropdown )
-   {
-      _ui.active_control_type = k_ui_control_none;
-      i16 button_rect[4];
-      rect_copy( _ui.controls.dropdown.source_rect, button_rect );
-      i32 current_value = *_ui.controls.dropdown.value;
-
-      for( u32 i=0; i<_ui.controls.dropdown.option_count; i ++ )
-      {
-         button_rect[1] += button_rect[3];
-
-         struct ui_dropdown_option *option = &_ui.controls.dropdown.options[i];
-         if( _ui_button( button_rect ) == k_button_click )
-         {
-            _ui.controls.dropdown.action = k_dropdown_changed;
-            *_ui.controls.dropdown.value = option->value;
-         }
-         
-         c8 temp[32];
-         struct stream string;
-         stream_open_buffer_write( &string, temp, sizeof(temp), k_stream_null_terminate );
-         string_append_i64( &string, option->value, 10 );
-         _ui_text( button_rect, temp, k_ui_align_y_center, (union colour){{128,128,128,255}} );
-         _ui_text( button_rect, option->display_name, k_ui_align_center, (union colour){{255,255,255,255}} );
-
-         if( current_value == option->value )
-         {
-            i16 tick_rect[4] = { button_rect[0]+button_rect[2]-UI_PADDING_PX*2, button_rect[1],
-                                 UI_PADDING_PX*2, button_rect[3] };
-            _ui_text( tick_rect, "\xB3", k_ui_align_center, (union colour){{0,255,0,255}} );
-         }
-      }
-      _ui.active_control_type = k_ui_control_dropdown;
-   }
-
-   _ui.redraw = 0;
-   _graphics_fill_rect( (i16[]){ _ui.mouse_co[0],_ui.mouse_co[1], 4,4 }, (union colour){{0,0,0,255}} );
-   _graphics_fill_rect( (i16[]){ _ui.mouse_co[0],_ui.mouse_co[1], 3,3 }, (union colour){{255,255,255,255}} );
-}
-
 static bool ui_inside_rect( i16 rect[4], i16 co[2] )
 {
    return (co[0] >= rect[0]) && (co[1] >= rect[1]) && (co[0] < rect[0]+rect[2]) && (co[1] < rect[1]+rect[3]);
@@ -272,7 +216,7 @@ enum button_action _ui_button( i16 rect[4] )
    {
       if( ui_inside_rect( rect, _ui.mouse_co ) )
       {
-         if( _ui.mouse_click_down & MOUSE_LEFT )
+         if( _input_button_down( k_input_action_ui_click, 0 ) )
          {
             action = k_button_click;
             debug_colour = (union colour){{ 255, 255, 255, 255 }};
@@ -280,19 +224,23 @@ enum button_action _ui_button( i16 rect[4] )
          }
          else
          {
-            action = (_ui.mouse_clicking & MOUSE_LEFT)? k_button_repeat: k_button_hover;
+            action = _input_button( k_input_action_ui_click )? k_button_repeat: k_button_hover;
             debug_colour = (union colour){{ 0, 0, 255, 170 }};
          }
       }
       else
-         if( _ui.mouse_clicking & MOUSE_LEFT )
+         if( _input_button( k_input_action_ui_click ) )
             if( ui_inside_rect( rect, _ui.mouse_co_clicked ) )
             {
                action = k_button_repeat;
                debug_colour = (union colour){{ 255, 0, 255, 140 }};
             }
    }
+
    _graphics_line_rect( rect, debug_colour );
+
+   if( action == k_button_click || action == k_button_repeat )
+      _ui.active_control_touched = 1;
    return action;
 }
 
@@ -389,111 +337,10 @@ static void _ui_textbox_set_cursor_user( i32 position, bool super )
       _ui.controls.textbox.cursor_pos = position;
 }
 
-void _ui_input_action( enum ui_action action, bool super )
+void _ui_set_mouse( i16 x, i16 y )
 {
-   if( _ui.active_control_type == k_ui_control_textbox )
-   {
-      if( action == k_ui_action_backspace )
-      {
-         i32 i0 = i32_min( _ui.controls.textbox.cursor_pos, _ui.controls.textbox.cursor_user ),
-             i1 = i32_max( _ui.controls.textbox.cursor_pos, _ui.controls.textbox.cursor_user );
-         if( i0 || (i0!=i1) )
-         {
-            if( i0 == i1 )
-               _ui.controls.textbox.cursor_pos --;
-            _ui_textbox_input_string( (const c8[]){ 0 } );
-            i32 i2 = i0;
-            if( i0 == i1 )
-               i2 = i0-1;
-            _ui.controls.textbox.cursor_pos = i2;
-            _ui.controls.textbox.cursor_user = i2;
-         }
-      }
-      else if( action == k_ui_action_enter )
-      {
-         if( _ui.controls.textbox.flags & UI_MULTILINE )
-            _ui_textbox_input_string( (const c8[]){ '\n', 0 } );
-         else
-            _ui.controls.textbox.action = k_textbox_enter;
-      }
-      else if( action == k_ui_action_home )
-         _ui_textbox_set_cursor_user( 0, super );
-      else if( action == k_ui_action_end )
-         _ui_textbox_set_cursor_user( buffer_last_index( _ui.controls.textbox.text_buffer, 0, 0 ), super );
-      else if( action == k_ui_action_right )
-      {
-         i32 p1 = i32_min( buffer_last_index( _ui.controls.textbox.text_buffer, 0, 0 ), _ui.controls.textbox.cursor_user+1 );
-         _ui_textbox_set_cursor_user( p1, super );
-      }
-      else if( action == k_ui_action_left )
-      {
-         i32 p1 = i32_max( 0, _ui.controls.textbox.cursor_user-1 );
-         _ui_textbox_set_cursor_user( p1, super );
-      }
-      else if( action == k_ui_action_up )
-      {
-         if( _ui.controls.textbox.flags & UI_MULTILINE )
-         {
-            i16 user_co[2] = {-1, -1};
-            i32 result_index = -1;
-            struct ui_string_decoder decoder, decoder1;
-            ui_string_decode_init( &decoder, _ui.controls.textbox.text_buffer, _ui.controls.textbox.text_buffer_encoding );
-            decoder1 = decoder;
-            bool loop; do
-            {  
-               loop = ui_string_decode( &decoder );
-               if( decoder.character_index == _ui.controls.textbox.cursor_user )
-               {
-                  user_co[0] = decoder.grid_co[0];
-                  user_co[1] = decoder.grid_co[1];
-                  loop = 0;
-               }
-            } while( loop ); 
-            bool loop1; do
-            {  
-               loop1 = ui_string_decode( &decoder1 );
-               if( decoder1.grid_co[1] == user_co[1]-1 )
-                  if( decoder1.grid_co[0] <= user_co[0] )
-                     result_index = decoder1.character_index;
-            } while( loop1 );
-
-            if( result_index != -1 )
-               _ui_textbox_set_cursor_user( result_index, super );
-         }
-         else
-            _ui.controls.textbox.action = k_textbox_input_up;
-      }
-      else if( action == k_ui_action_down )
-      {
-         if( _ui.controls.textbox.flags & UI_MULTILINE )
-         {
-            i16 user_co[2] = { -1, -1 };
-            i32 result_index = -1;
-            struct ui_string_decoder decoder;
-            ui_string_decode_init( &decoder, _ui.controls.textbox.text_buffer, _ui.controls.textbox.text_buffer_encoding );
-            bool loop; do
-            {  
-               loop = ui_string_decode( &decoder );
-               if( decoder.character_index == _ui.controls.textbox.cursor_user )
-               {
-                  user_co[0] = decoder.grid_co[0];
-                  user_co[1] = decoder.grid_co[1];
-               }
-               if( decoder.grid_co[1] == user_co[1]+1 )
-                  if( decoder.grid_co[0] <= user_co[0] )
-                     result_index = decoder.character_index;
-            } while( loop ); 
-
-            if( result_index != -1 )
-               _ui_textbox_set_cursor_user( result_index, super );
-         }
-         else
-            _ui.controls.textbox.action = k_textbox_input_up;
-      }
-      else if( action == k_ui_action_indent )
-      {
-      }
-   }
+   _ui.mouse_co[0] = x;
+   _ui.mouse_co[1] = y;
 }
 
 void _ui_input_text( const c8 *text )
@@ -522,8 +369,9 @@ enum textbox_action _ui_textbox( i16 rect[4], c8 *text_buffer, u32 text_buffer_l
 
       if( init )
       {
-         _ui.controls.textbox.cursor_pos = 0; 
-         _ui.controls.textbox.cursor_user = 0;
+         i32 p = buffer_last_index( text_buffer, 0, 0 );
+         _ui.controls.textbox.cursor_pos = p;
+         _ui.controls.textbox.cursor_user = p;
       }
    }
 
@@ -585,7 +433,7 @@ enum textbox_action _ui_textbox( i16 rect[4], c8 *text_buffer, u32 text_buffer_l
                                        rect[1] + user_co[1]*kerning[1], kerning[0],kerning[1] },
                                        (union colour){{255,255,0,255}} );
 
-         if( _ui.mouse_clicking & MOUSE_LEFT )
+         if( _input_button( k_input_action_ui_click ) )
          {
             if( ui_inside_rect( rect, _ui.mouse_co_clicked ) )
             {
@@ -644,3 +492,167 @@ enum dropdown_action _ui_dropdown( i16 rect[4], struct ui_dropdown_option *optio
          }
    return k_dropdown_none;
 }
+
+bool _ui_update(void)
+{
+   if( _input_button_down( k_input_action_ui_click, 0 ) )
+   {
+      _ui.mouse_co_clicked[0] = _ui.mouse_co[0];
+      _ui.mouse_co_clicked[1] = _ui.mouse_co[1];
+   }
+
+   if( !_ui.active_control_touched )
+      _ui.active_control_type = k_ui_control_none;
+
+   if( _ui.active_control_type == k_ui_control_textbox )
+   {
+      for( u8 i=0; i<_input_button_down( k_input_action_ui_backspace, 1 ); i ++ )
+      {
+         i32 i0 = i32_min( _ui.controls.textbox.cursor_pos, _ui.controls.textbox.cursor_user ),
+             i1 = i32_max( _ui.controls.textbox.cursor_pos, _ui.controls.textbox.cursor_user );
+         if( i0 || (i0!=i1) )
+         {
+            if( i0 == i1 )
+               _ui.controls.textbox.cursor_pos --;
+            _ui_textbox_input_string( (const c8[]){ 0 } );
+            i32 i2 = i0;
+            if( i0 == i1 )
+               i2 = i0-1;
+            _ui.controls.textbox.cursor_pos = i2;
+            _ui.controls.textbox.cursor_user = i2;
+         }
+      }
+
+      for( u8 i=0; i<_input_button_down( k_input_action_ui_enter, 1 ); i ++ )
+      {
+         if( _ui.controls.textbox.flags & UI_MULTILINE )
+            _ui_textbox_input_string( (const c8[]){ '\n', 0 } );
+         else
+            _ui.controls.textbox.action = k_textbox_enter;
+      }
+
+      bool select_mode = _input_button( k_input_button_ui_select );
+
+      for( u8 i=0; i<_input_button_down( k_input_button_ui_home, 1 ); i ++ ) 
+         _ui_textbox_set_cursor_user( 0, select_mode );
+      for( u8 i=0; i<_input_button_down( k_input_button_ui_end, 1 ); i ++ ) 
+         _ui_textbox_set_cursor_user( buffer_last_index( _ui.controls.textbox.text_buffer, 0, 0 ), select_mode );
+      for( u8 i=0; i<_input_button_down( k_input_button_ui_right, 1 ); i ++ ) 
+      {
+         i32 p1 = i32_min( buffer_last_index( _ui.controls.textbox.text_buffer, 0, 0 ), _ui.controls.textbox.cursor_user+1 );
+         _ui_textbox_set_cursor_user( p1, select_mode );
+      }
+      for( u8 i=0; i<_input_button_down( k_input_button_ui_left, 1 ); i ++ ) 
+      {
+         i32 p1 = i32_max( 0, _ui.controls.textbox.cursor_user-1 );
+         _ui_textbox_set_cursor_user( p1, select_mode );
+      }
+      for( u8 i=0; i<_input_button_down( k_input_button_ui_up, 1 ); i ++ )
+      {
+         if( _ui.controls.textbox.flags & UI_MULTILINE )
+         {
+            i16 user_co[2] = {-1, -1};
+            i32 result_index = -1;
+            struct ui_string_decoder decoder, decoder1;
+            ui_string_decode_init( &decoder, _ui.controls.textbox.text_buffer, _ui.controls.textbox.text_buffer_encoding );
+            decoder1 = decoder;
+            bool loop; do
+            {  
+               loop = ui_string_decode( &decoder );
+               if( decoder.character_index == _ui.controls.textbox.cursor_user )
+               {
+                  user_co[0] = decoder.grid_co[0];
+                  user_co[1] = decoder.grid_co[1];
+                  loop = 0;
+               }
+            } while( loop ); 
+            bool loop1; do
+            {  
+               loop1 = ui_string_decode( &decoder1 );
+               if( decoder1.grid_co[1] == user_co[1]-1 )
+                  if( decoder1.grid_co[0] <= user_co[0] )
+                     result_index = decoder1.character_index;
+            } while( loop1 );
+
+            if( result_index != -1 )
+               _ui_textbox_set_cursor_user( result_index, select_mode );
+         }
+         else
+            _ui.controls.textbox.action = k_textbox_input_up;
+      }
+
+      for( u8 i=0; i<_input_button_down( k_input_button_ui_down, 1 ); i ++ )
+      {
+         if( _ui.controls.textbox.flags & UI_MULTILINE )
+         {
+            i16 user_co[2] = { -1, -1 };
+            i32 result_index = -1;
+            struct ui_string_decoder decoder;
+            ui_string_decode_init( &decoder, _ui.controls.textbox.text_buffer, _ui.controls.textbox.text_buffer_encoding );
+            bool loop; do
+            {  
+               loop = ui_string_decode( &decoder );
+               if( decoder.character_index == _ui.controls.textbox.cursor_user )
+               {
+                  user_co[0] = decoder.grid_co[0];
+                  user_co[1] = decoder.grid_co[1];
+               }
+               if( decoder.grid_co[1] == user_co[1]+1 )
+                  if( decoder.grid_co[0] <= user_co[0] )
+                     result_index = decoder.character_index;
+            } while( loop ); 
+
+            if( result_index != -1 )
+               _ui_textbox_set_cursor_user( result_index, select_mode );
+         }
+         else
+            _ui.controls.textbox.action = k_textbox_input_up;
+      }
+   }
+
+   _ui.active_control_touched = 0;
+   return _ui.redraw;
+}
+
+void _ui_draw(void)
+{
+   if( _ui.active_control_type == k_ui_control_dropdown )
+   {
+      _ui.active_control_type = k_ui_control_none;
+      i16 button_rect[4];
+      rect_copy( _ui.controls.dropdown.source_rect, button_rect );
+      i32 current_value = *_ui.controls.dropdown.value;
+
+      for( u32 i=0; i<_ui.controls.dropdown.option_count; i ++ )
+      {
+         button_rect[1] += button_rect[3];
+
+         struct ui_dropdown_option *option = &_ui.controls.dropdown.options[i];
+         if( _ui_button( button_rect ) == k_button_click )
+         {
+            _ui.controls.dropdown.action = k_dropdown_changed;
+            *_ui.controls.dropdown.value = option->value;
+         }
+         
+         c8 temp[32];
+         struct stream string;
+         stream_open_buffer_write( &string, temp, sizeof(temp), k_stream_null_terminate );
+         string_append_i64( &string, option->value, 10 );
+         _ui_text( button_rect, temp, k_ui_align_y_center, (union colour){{128,128,128,255}} );
+         _ui_text( button_rect, option->display_name, k_ui_align_center, (union colour){{255,255,255,255}} );
+
+         if( current_value == option->value )
+         {
+            i16 tick_rect[4] = { button_rect[0]+button_rect[2]-UI_PADDING_PX*2, button_rect[1],
+                                 UI_PADDING_PX*2, button_rect[3] };
+            _ui_text( tick_rect, "\xB3", k_ui_align_center, (union colour){{0,255,0,255}} );
+         }
+      }
+      _ui.active_control_type = k_ui_control_dropdown;
+   }
+
+   _ui.redraw = 0;
+   _graphics_fill_rect( (i16[]){ _ui.mouse_co[0],_ui.mouse_co[1], 4,4 }, (union colour){{0,0,0,255}} );
+   _graphics_fill_rect( (i16[]){ _ui.mouse_co[0],_ui.mouse_co[1], 3,3 }, (union colour){{255,255,255,255}} );
+}
+
index d8a1c3b7bc63108a6e5ec2847bae65898cce29e0..c8c46e98eb912bf6058d253d62e3e7c820a8dd73 100644 (file)
@@ -31,6 +31,7 @@ struct hook_event
 struct hook_user
 {
    struct stream function_name;
+   i32 affinity;
 };
 struct
 {
@@ -323,6 +324,9 @@ void _parse_kv_block( struct keyvalues *kvs, u32 block, struct block_context con
 
             ASSERT_CRITICAL( event_alias && function );
 
+            i32 affinity = 0;
+            keyvalues_read_i32s( kvs, block, "affinity", NULL, &affinity, 1 );
+
             bool found = 0;
 
             for( u32 i=0; i<stretchy_count( &_hooks.events ); i ++ )
@@ -333,6 +337,7 @@ void _parse_kv_block( struct keyvalues *kvs, u32 block, struct block_context con
                   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;
                }
@@ -705,6 +710,25 @@ i32 main( i32 argc, const c8 *argv[] )
          }
          $v_string( &source, {"\n"} );
 
+         bool sorted = 0;
+         while( !sorted )
+         {
+            sorted = 1;
+            
+            for( u32 j=1; j<stretchy_count( &event->users ); j ++ )
+            {
+               struct hook_user *j1 = stretchy_get( &event->users, j ),
+                                *j0 = stretchy_get( &event->users, j-1 );
+               if( j1->affinity < j0->affinity )
+               {
+                  struct hook_user temp = *j0;
+                  *j0 = *j1;
+                  *j1 = temp;
+                  sorted = 0;
+               }
+            }
+         }
+
          $v_string( &source, {returns}, {" (*_event_"}, {alias}, {"_subscribers[])( "}, {prototype}, {" ) = \n{\n"} );
          for( u32 j=0; j<stretchy_count( &event->users ); j ++ )
          {