super basic UI layouting
authorhgn <hgodden00@gmail.com>
Mon, 11 Oct 2021 22:03:09 +0000 (23:03 +0100)
committerhgn <hgodden00@gmail.com>
Mon, 11 Oct 2021 22:03:09 +0000 (23:03 +0100)
build.sh
fishladder.c
vg/vg.h
vg/vg_input.h [new file with mode: 0644]
vg/vg_lines.h
vg/vg_ui.h [new file with mode: 0644]

index 2395e173115e6cabd491febc5ca2113f9c954ff7..cea0e94e1facfe6f20b8523a9b4fa59af47a5f05 100755 (executable)
--- a/build.sh
+++ b/build.sh
@@ -15,6 +15,8 @@ fi
 
 run_after=false
 do_build=true
+compile_tools=false
+compile_models=false
 
 while (( "$#" )); do
        case $1 in
@@ -30,6 +32,14 @@ while (( "$#" )); do
                        do_build=false
                        echo "no-build"
                ;;
+               -t|--tools)
+                       compile_tools=true
+                       echo "build-tools"
+               ;;
+               -m|--models)
+                       compile_models=true
+                       echo "build-models"
+               ;;
                *) 
                        echo "Unkown param: $1" 
                        exit 1
@@ -38,15 +48,21 @@ while (( "$#" )); do
        shift
 done
 
-echo "Building tools"
-mkdir tools -p
-gcc -Wall -Wstrict-aliasing=3 $lib $flags mdlcomp.c gl/glad.c -o tools/mdlcomp $libs -Wl,-rpath=./ $defines
+# Tools
+if [ "$compile_tools" = true ]; then
+       echo "Building tools"
+       mkdir tools -p
+       gcc -Wall -Wstrict-aliasing=3 $lib $flags mdlcomp.c gl/glad.c -o tools/mdlcomp $libs -Wl,-rpath=./ $defines
+fi
 
-echo "Recompiling models"
-for f in models/*.obj; 
-       do echo "Compiling $f..";
-       ./tools/mdlcomp $f $f.h
-done
+# Resources
+if [ "$compile_models" = true ]; then
+       echo "Recompiling models"
+       for f in models/*.obj; 
+               do echo "Compiling $f..";
+               ./tools/mdlcomp $f $f.h
+       done
+fi
 
 # Main build
 if [ "$do_build" = true ]; then
index 1f377903d557d3680eeebef03ae96eb06dff4ecb..d66cd2e18780b27eb48890130eeade53a7b0b04c 100644 (file)
@@ -934,4 +934,7 @@ void vg_render(void)
        }
 }
 
-void vg_ui(void){}
+void vg_ui(void)
+{
+       ui_test();
+}
diff --git a/vg/vg.h b/vg/vg.h
index b7abeb634dfeb9f158d4270024d162899ae6d426..658130bfe497992289dfe23977e9a0c98cf7a47c 100644 (file)
--- a/vg/vg.h
+++ b/vg/vg.h
@@ -28,19 +28,7 @@ m3x3f vg_pv;
 
 #ifndef VG_TOOLS
 
-#include "vg/vg_audio.h"
-#include "vg/vg_shader.h"
-#include "vg/vg_lines.h"
-#include "vg/vg_tex.h"
-
-#include "steam/steamworks_thin.h"
-
-static inline float vg_get_axis( const char *axis ) __attribute__((unused));
-static inline int vg_get_button( const char *button ) __attribute__((unused));
-static inline int vg_get_button_down( const char *button ) __attribute__((unused));
-static inline int vg_get_button_up( const char *button ) __attribute__((unused));
-
-// Globals
+// Engine globals
 GLFWwindow* vg_window;
 int vg_window_x = 1280;
 int vg_window_y = 720;
@@ -52,141 +40,15 @@ float      vg_time;
 float  vg_time_last;
 float  vg_time_delta;
 
-// Input
-// ===========================================================================================================
-GLFWgamepadstate vg_gamepad;
-int                    vg_gamepad_ready = 0;
-const char *vg_gamepad_name = NULL;
-int                    vg_gamepad_id;
-
-enum EInputMode
-{
-       k_EInputMode_pc,
-       k_EInputMode_gamepad
-}
-vg_input_mode;
-
-static struct axis_binding
-{
-       const char *name;
-       union
-       {
-               int positive;
-               int bind;
-       };
-       int negative;
-       
-       float value;
-}
-vg_axis_binds[];
-
-static struct button_binding
-{
-       const char *name;
-       int bind;
-       
-       int value; int prev;
-}
-vg_button_binds[];
-
-#include "vg/config.h"
-
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wreturn-type"
-
-static inline float vg_get_axis( const char *axis )
-{
-       for( int i = 0; i < vg_list_size( vg_axis_binds ); i ++ )
-       {
-               if( !strcmp( axis, vg_axis_binds[i].name ) )
-               {
-                       return vg_axis_binds[i].value;
-               }
-       }
-}
-
-static inline struct button_binding *vg_get_button_ptr( const char *button )
-{
-       for( int i = 0; i < vg_list_size( vg_button_binds ); i ++ )
-       {
-               if( !strcmp( button, vg_button_binds[i].name ) )
-               {
-                       return vg_button_binds + i;
-               }
-       }
-}
-#pragma GCC diagnostic pop
-
-static inline int vg_get_button( const char *button )
-{
-       return vg_get_button_ptr( button )->value;
-}
-
-static inline int vg_get_button_down( const char *button )
-{
-       struct button_binding *bind = vg_get_button_ptr( button );
-       return bind->value & (bind->value ^ bind->prev);
-}
-
-static inline int vg_get_button_up( const char *button )
-{
-       struct button_binding *bind = vg_get_button_ptr( button );
-       return bind->prev & (bind->value ^ bind->prev);
-}
-
-static inline int key_is_keyboard( int const id )
-{
-       vg_static_assert( GLFW_MOUSE_BUTTON_LAST < GLFW_KEY_SPACE, "GLFW: Mouse has too many buttons" );
-       return id > GLFW_MOUSE_BUTTON_LAST;
-}
-
-// Mouse AND Keyboard get button press
-int get_button_cross_device( int const id )
-{
-       if( key_is_keyboard( id ) )
-       {
-               return glfwGetKey( vg_window, id );
-       }
-       else
-       {
-               return glfwGetMouseButton( vg_window, id ) == GLFW_PRESS;
-       }
-}
+// Engine components
+#include "vg/vg_audio.h"
+#include "vg/vg_shader.h"
+#include "vg/vg_lines.h"
+#include "vg/vg_tex.h"
+#include "vg/vg_input.h"
+#include "vg/vg_ui.h"
 
-void vg_update_inputs(void)
-{
-       // Update button inputs
-       for( int i = 0; i < vg_list_size( vg_button_binds ); i ++ )
-       {
-               struct button_binding *binding = vg_button_binds + i;
-               binding->prev = binding->value;
-       
-               if( vg_input_mode == k_EInputMode_pc )
-               {
-                       binding->value = get_button_cross_device( binding->bind );
-               }
-               else
-               {
-                       binding->value = vg_gamepad.buttons[ binding->bind ];
-               }
-       }
-       
-       // Update axis inputs
-       for( int i = 0; i < vg_list_size( vg_axis_binds ); i ++ )
-       {
-               struct axis_binding *binding = vg_axis_binds + i;
-               
-               if( vg_input_mode == k_EInputMode_pc )
-               {
-                       binding->value  = get_button_cross_device( binding->positive );
-                       binding->value -= get_button_cross_device( binding->negative );
-               }
-               else
-               {
-                       binding->value = vg_gamepad.axes[ binding->bind ];
-               }
-       }
-}
+#include "steam/steamworks_thin.h"
 
 // Engine main
 // ===========================================================================================================
@@ -373,7 +235,7 @@ static void vg_init( int argc, char *argv[], const char *window_name )
                        vg_update();
                        vg_render();
                        
-                       vg_lines_drawall();
+                       vg_lines_drawall((float*)vg_pv);
                        
                        vg_ui();
                        
diff --git a/vg/vg_input.h b/vg/vg_input.h
new file mode 100644 (file)
index 0000000..4d1ac0e
--- /dev/null
@@ -0,0 +1,142 @@
+// Copyright (C) 2021 Harry Godden (hgn) - All Rights Reserved
+
+static inline float vg_get_axis( const char *axis ) __attribute__((unused));
+static inline int vg_get_button( const char *button ) __attribute__((unused));
+static inline int vg_get_button_down( const char *button ) __attribute__((unused));
+static inline int vg_get_button_up( const char *button ) __attribute__((unused));
+
+// Input
+// ===========================================================================================================
+GLFWgamepadstate vg_gamepad;
+int                    vg_gamepad_ready = 0;
+const char *vg_gamepad_name = NULL;
+int                    vg_gamepad_id;
+
+enum EInputMode
+{
+       k_EInputMode_pc,
+       k_EInputMode_gamepad
+}
+vg_input_mode;
+
+static struct axis_binding
+{
+       const char *name;
+       union
+       {
+               int positive;
+               int bind;
+       };
+       int negative;
+       
+       float value;
+}
+vg_axis_binds[];
+
+static struct button_binding
+{
+       const char *name;
+       int bind;
+       
+       int value; int prev;
+}
+vg_button_binds[];
+
+#include "vg/config.h"
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wreturn-type"
+
+static inline float vg_get_axis( const char *axis )
+{
+       for( int i = 0; i < vg_list_size( vg_axis_binds ); i ++ )
+       {
+               if( !strcmp( axis, vg_axis_binds[i].name ) )
+               {
+                       return vg_axis_binds[i].value;
+               }
+       }
+}
+
+static inline struct button_binding *vg_get_button_ptr( const char *button )
+{
+       for( int i = 0; i < vg_list_size( vg_button_binds ); i ++ )
+       {
+               if( !strcmp( button, vg_button_binds[i].name ) )
+               {
+                       return vg_button_binds + i;
+               }
+       }
+}
+#pragma GCC diagnostic pop
+
+static inline int vg_get_button( const char *button )
+{
+       return vg_get_button_ptr( button )->value;
+}
+
+static inline int vg_get_button_down( const char *button )
+{
+       struct button_binding *bind = vg_get_button_ptr( button );
+       return bind->value & (bind->value ^ bind->prev);
+}
+
+static inline int vg_get_button_up( const char *button )
+{
+       struct button_binding *bind = vg_get_button_ptr( button );
+       return bind->prev & (bind->value ^ bind->prev);
+}
+
+static inline int key_is_keyboard( int const id )
+{
+       vg_static_assert( GLFW_MOUSE_BUTTON_LAST < GLFW_KEY_SPACE, "GLFW: Mouse has too many buttons" );
+       return id > GLFW_MOUSE_BUTTON_LAST;
+}
+
+// Mouse AND Keyboard get button press
+int get_button_cross_device( int const id )
+{
+       if( key_is_keyboard( id ) )
+       {
+               return glfwGetKey( vg_window, id );
+       }
+       else
+       {
+               return glfwGetMouseButton( vg_window, id ) == GLFW_PRESS;
+       }
+}
+
+void vg_update_inputs(void)
+{
+       // Update button inputs
+       for( int i = 0; i < vg_list_size( vg_button_binds ); i ++ )
+       {
+               struct button_binding *binding = vg_button_binds + i;
+               binding->prev = binding->value;
+       
+               if( vg_input_mode == k_EInputMode_pc )
+               {
+                       binding->value = get_button_cross_device( binding->bind );
+               }
+               else
+               {
+                       binding->value = vg_gamepad.buttons[ binding->bind ];
+               }
+       }
+       
+       // Update axis inputs
+       for( int i = 0; i < vg_list_size( vg_axis_binds ); i ++ )
+       {
+               struct axis_binding *binding = vg_axis_binds + i;
+               
+               if( vg_input_mode == k_EInputMode_pc )
+               {
+                       binding->value  = get_button_cross_device( binding->positive );
+                       binding->value -= get_button_cross_device( binding->negative );
+               }
+               else
+               {
+                       binding->value = vg_gamepad.axes[ binding->bind ];
+               }
+       }
+}
index 18a0a7c320950e80d0b13f51372b1a408958627a..469664a9553790225660e7c8ec4960b84c3d8390 100644 (file)
@@ -89,10 +89,10 @@ static void vg_lines_free(void)
        free( vg_lines.buffer );
 }
 
-static void vg_lines_drawall(void)
+static void vg_lines_drawall(float* projection)
 {
        SHADER_USE( vg_line_shader );
-       glUniformMatrix3fv( SHADER_UNIFORM( vg_line_shader, "uPv" ), 1, GL_FALSE, (float *)vg_pv );
+       glUniformMatrix3fv( SHADER_UNIFORM( vg_line_shader, "uPv" ), 1, GL_FALSE, projection );
        
        glBindVertexArray( vg_lines.vao );
        glBindBuffer( GL_ARRAY_BUFFER, vg_lines.vbo );
diff --git a/vg/vg_ui.h b/vg/vg_ui.h
new file mode 100644 (file)
index 0000000..27c0645
--- /dev/null
@@ -0,0 +1,258 @@
+// Copyright (C) 2021 Harry Godden (hgn) - All Rights Reserved
+/*
+
+       Concurrent UI buffer system
+       Coordinate space:
+
+   0,0 --- +(res:x)
+        |
+        |
+        |
++(res:y)
+       
+*/
+
+#define UI_AUTO_FILL 0
+
+// Types
+// ================================================================
+typedef i16                            ui_px;
+typedef u32                            ui_colour;
+typedef ui_px                          ui_rect[4];
+typedef struct ui_ctx  ui_ctx;
+
+struct ui_ctx
+{
+       ui_px padding;
+
+       struct ui_qnode
+       {
+               ui_rect                 rect;
+               ui_colour       colour;
+               int                     mouse_over;
+               int                     capture_id;
+       }
+       stack[ 32 ];
+       
+       ui_rect cursor;
+       u32 stack_count;
+       u32 capture_mouse_id;
+       
+       // User input
+       ui_px mouse[2];
+       int click_state;        // 0: released, 1: on down, 2: pressed, 3: on release
+};
+
+// Rect controls
+// ==========================================================
+
+static void ui_rect_copy( ui_rect src, ui_rect dst )
+{
+       dst[0] = src[0];
+       dst[1] = src[1];
+       dst[2] = src[2];
+       dst[3] = src[3];
+}
+
+static void ui_rect_pad( ui_ctx *ctx, ui_rect rect )
+{
+       rect[0] += ctx->padding;
+       rect[1] += ctx->padding;
+       rect[2] -= ctx->padding*2;
+       rect[3] -= ctx->padding*2;
+}
+
+static void ui_vis_rect( ui_rect rect, u32 colour )
+{
+       v2f p0;
+       v2f p1;
+       
+       p0[0] = rect[0];
+       p0[1] = rect[1];
+       p1[0] = rect[0]+rect[2];
+       p1[1] = rect[1]+rect[3];
+
+       vg_line( p0, (v2f){p1[0],p0[1]}, colour );
+       vg_line( (v2f){p1[0],p0[1]}, p1, colour );
+       vg_line( p1, (v2f){p0[0],p1[1]}, colour );
+       vg_line( (v2f){p0[0],p1[1]}, p0, colour );
+}
+
+static void ui_new_node( ui_ctx *ctx )
+{
+       if( ctx->stack_count == vg_list_size( ctx->stack ) )
+               vg_exiterr( "[UI] Stack overflow while creating box!" );
+       
+       struct ui_qnode *parent = &ctx->stack[ ctx->stack_count-1 ];
+       struct ui_qnode *node = &ctx->stack[ ctx->stack_count++ ];
+       ui_rect_copy( ctx->cursor, node->rect );
+       
+       if( parent->mouse_over )
+       {
+               if( ctx->mouse[0] >= node->rect[0] && ctx->mouse[0] <= node->rect[0]+node->rect[2] &&
+                        ctx->mouse[1] >= node->rect[1] && ctx->mouse[1] <= node->rect[1]+node->rect[3] )
+                       node->mouse_over = 1;
+               else
+                       node->mouse_over = 0;
+       }
+}
+
+static int ui_hasmouse( ui_ctx *ctx )
+{
+       struct ui_qnode *node = &ctx->stack[ ctx->stack_count-1 ];
+       return (node->mouse_over && (node->capture_id == ctx->capture_mouse_id));
+}
+
+static void ui_end( ui_ctx *ctx )
+{
+       struct ui_qnode *node = &ctx->stack[ --ctx->stack_count ];
+
+       ui_rect_copy( node->rect, ctx->cursor );
+       ui_vis_rect( ctx->cursor, (node->mouse_over && (node->capture_id == ctx->capture_mouse_id))? 0xffff0000: 0xff0000ff );
+}
+
+static void ui_end_down( ui_ctx *ctx )
+{
+       ui_px height = ctx->stack[ ctx->stack_count ].rect[3];
+       ui_end( ctx );
+       ctx->cursor[1] += height;
+}
+
+static void ui_end_right( ui_ctx *ctx )
+{
+       ui_px width = ctx->stack[ ctx->stack_count ].rect[2];
+       ui_end( ctx );
+       ctx->cursor[0] += width;
+}
+
+static void ui_capture_mouse( ui_ctx *ctx, int id )
+{
+       struct ui_qnode *node = &ctx->stack[ ctx->stack_count-1 ];
+       node->capture_id = id;
+       
+       if( node->mouse_over )
+       {
+               ctx->capture_mouse_id = id;
+       }
+}
+
+// API control
+// ====================================================================
+
+static void ui_begin( ui_ctx *ctx, ui_px res_x, ui_px res_y )
+{
+       ctx->cursor[0] = 0;
+       ctx->cursor[1] = 0;
+       ctx->cursor[2] = res_x;
+       ctx->cursor[3] = res_y;
+       
+       ui_rect_copy( ctx->cursor, ctx->stack[0].rect );
+       ctx->stack[0].mouse_over = 1;
+       
+       ctx->stack_count = 1;
+}
+
+static void ui_resolve( ui_ctx *ctx )
+{
+       if( ctx->stack_count-1 )
+               vg_exiterr( "[UI] Mismatched node create/drestroy!" );
+}
+
+// User Input piping
+// ====================================================================
+
+static void ui_set_mouse( ui_ctx *ctx, int x, int y, int click_state )
+{
+       ctx->mouse[0] = x;
+       ctx->mouse[1] = y;
+       
+       ctx->click_state = click_state;
+}
+
+static void ui_test(void)
+{
+       /*
+               +------------------------------------------------------+
+               | Central Market                                    [x]|
+               +------+--------------+-+------------------------------+
+               | Buy  | Balance      |#| [filters] [favorites]        |
+               | <>_  | () 2,356     |#|----------------------------+-+
+               |------|--------------|#| [] potion of madness     4 |#| 
+               | Sell | \ Main sword |#|----------------------------|#|
+               | _*^  |--------------|#| [] Balance of time      23 | |
+               |------| * Side arm   |#|----------------------------| |
+               | 235  |--------------| | [] Strength          5,300 | |
+               |      | () Sheild    | |----------------------------| |
+               |      |--------------| | [] Bewilder          2,126 | |
+               |      [ & Spells     ] |----------------------------| |
+               |      |--------------| | [] Eternal flames        6 | |
+               +------+--------------+-+----------------------------+-+
+       */
+       
+       ui_ctx ctx = { .padding = 8 };
+       
+       ui_begin( &ctx, vg_window_x, vg_window_y );
+       
+       // TODO: Find a more elegent form for this
+       int mouse_state = 0;
+       if( vg_get_button( "primary" ) ) mouse_state = 2;
+       if( vg_get_button_down( "primary" ) ) mouse_state = 1;
+       if( vg_get_button_up( "primary" ) ) mouse_state = 3;
+               
+       ui_set_mouse( &ctx, vg_mouse[0], vg_mouse[1], mouse_state );
+       
+       static ui_px window_x = 20;
+       static ui_px window_y = 20;
+       static int window_drag = 0;
+       static ui_px drag_offset[2];
+
+       if( window_drag )
+       {
+               window_x = ctx.mouse[0]+drag_offset[0];
+               window_y = ctx.mouse[1]+drag_offset[1];
+               
+               if( ctx.click_state == 0 )
+               {
+                       window_drag = 0;
+               }
+       }
+       
+       ctx.cursor[0] = window_x;
+       ctx.cursor[1] = window_y;
+       ctx.cursor[2] = 500;
+       ctx.cursor[3] = 350;
+       
+       ui_new_node( &ctx );
+       {
+               ctx.cursor[0] += 20;
+               ctx.cursor[1] += 20;
+               ctx.cursor[2] = 150;
+               ctx.cursor[3] = 25;
+               
+               ui_capture_mouse( &ctx, 1 );
+               
+               ui_new_node( &ctx );
+               {
+                       ui_capture_mouse( &ctx, 2 );
+                       
+                       if( ui_hasmouse( &ctx ) )
+                       {
+                               if( ctx.click_state == 1 ) // start drag
+                               {
+                                       window_drag = 1;
+                                       drag_offset[0] = window_x-ctx.mouse[0];
+                                       drag_offset[1] = window_y-ctx.mouse[1];
+                               }
+                       }
+               }
+               ui_end( &ctx );
+       }
+       ui_end( &ctx );
+       
+       ui_resolve( &ctx );
+       
+       m3x3f view = M3X3_IDENTITY;
+       m3x3_translate( view, (v3f){ -1.0f, 1.0f, 0.0f } );
+       m3x3_scale( view, (v3f){ 1.0f/((float)vg_window_x*0.5f), -1.0f/((float)vg_window_y*0.5f), 1.0f } );
+       vg_lines_drawall( (float*)view );
+}