run_after=false
do_build=true
+compile_tools=false
+compile_models=false
while (( "$#" )); do
case $1 in
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
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
}
}
-void vg_ui(void){}
+void vg_ui(void)
+{
+ ui_test();
+}
#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;
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
// ===========================================================================================================
vg_update();
vg_render();
- vg_lines_drawall();
+ vg_lines_drawall((float*)vg_pv);
vg_ui();
--- /dev/null
+// 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 ];
+ }
+ }
+}
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 );
--- /dev/null
+// 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 );
+}