{
if terminal
- add source/terminal/main.c
+ add source/terminal_main.c
}
{
/* Voyager common application interface */
-#define API
-#define IMPL
-
#define VG_PRE_MAIN \
_exit_init(); \
_log_init(); \
typedef unsigned char bool;
#define NULL 0
+
#define BYTES_KB( X ) X*1024
#define BYTES_MB( X ) X*1024*1024
#define BYTES_GB( X ) X*1024*1024*1024
c8 *keyvalues_key( struct keyvalues *kvs, u32 kv_offset, u32 *out_length );
c8 *keyvalues_value( struct keyvalues *kvs, u32 kv_offset, u32 *out_length );
-u32 keyvalues_get( struct keyvalues *kvs, u32 root_offset, const c8 *key );
+u32 keyvalues_get( struct keyvalues *kvs, u32 root_offset, const c8 *key, bool relative );
u32 keyvalues_get_next( struct keyvalues *kvs, u32 kv_offset );
u32 keyvalues_get_child( struct keyvalues *kvs, u32 root_offset, u32 index );
bool keyvalues_read_i32s( struct keyvalues *kvs, u32 root_offset, const c8 *key, i32 *default_values, i32 *out_values, u32 len );
bool keyvalues_read_u32s( struct keyvalues *kvs, u32 root_offset, const c8 *key, u32 *default_values, u32 *out_values, u32 len );
bool keyvalues_read_f32s( struct keyvalues *kvs, u32 root_offset, const c8 *key, f32 *default_values, f32 *out_values, u32 len );
+u32 keyvalues_append_frame( struct keyvalues *kvs, u32 parent_offset, const c8 *key );
u32 keyvalues_append_string( struct keyvalues *kvs, u32 parent_offset, const c8 *key, const c8 *value );
u32 keyvalues_append_i32s( struct keyvalues *kvs, u32 parent_offset, const c8 *key, i32 *values, u32 len );
u32 keyvalues_append_u32s( struct keyvalues *kvs, u32 parent_offset, const c8 *key, u32 *values, u32 len );
-IMPL void _engine_console_ui(void);
-IMPL void _engine_console_init(void);
+void _engine_console_ui(void);
+void _engine_console_init(void);
-IMPL void _engine_ui_init(void);
-IMPL void _engine_ui_pre_render(void);
-IMPL void _engine_ui_post_render(void);
-IMPL void _engine_ui_input_character( u32 codepoint );
+void _engine_ui_init(void);
+void _engine_ui_pre_render(void);
+void _engine_ui_post_render(void);
+void _engine_ui_input_character( u32 codepoint );
};
#pragma pack(pop)
+union colour graphics_lerp_colour( union colour c0, union colour c1, i32 d, i32 t );
+
enum blending_mode
{
k_blending_mode_mix_alpha,
void _graphics_fill_rect( i16 rect[4], union colour colour );
void _graphics_line_rect( i16 rect[4], union colour colour );
void _graphics_line( i16 p0[2], i16 p1[2], union colour colour );
+void _graphics_line2( i16 p0[2], i16 p1[2], union colour c0, union colour c1 );
void _graphics_line_triangle( i16 p0[2], i16 p1[2], i16 p2[2], union colour colour );
void _graphics_fill_triangle( i16 in_p0[2], i16 in_p1[2], i16 in_p2[2], union colour colour );
void _graphics_glyph( i16 co[2], u32 glyph, i16 scale, union colour colour );
void _ui_set_mouse( i16 x, i16 y );
void _ui_get_mouse_co( i16 out_co[2] );
void _ui_input_text( const c8 *text );
+bool _ui_want_mouse( i16 area[4] );
#define UI_PADDING_PX 8
#define UI_ROW_PADDING_PX 18
void _input_layer_whitelist( u32 whitelist );
bool _input_layer_filter( u32 mask );
+void _input_string( struct stream *stream, enum input_id id );
#include "generated/input.h"
#include "vg/dep/glad.4.3/glad/glad.h"
#include "generated/shaders.h"
-API GLuint compile_opengl_subshader( GLint type, const c8 *sources[], u32 source_count, bool critical, const c8 *debug_path );
-API bool link_opengl_program( GLuint program, bool critical );
+GLuint compile_opengl_subshader( GLint type, const c8 *sources[], u32 source_count, bool critical, const c8 *debug_path );
+bool link_opengl_program( GLuint program, bool critical );
void _shader_bind( enum shader_id id );
{
_whitelist = whitelist;
}
+
+void _input_string( struct stream *stream, enum input_id id )
+{
+ u32 matched = 0;
+
+ for( u32 i=0; i<stretchy_count( &_bind_allocator ); i ++ )
+ {
+ struct bind *bind = stretchy_get( &_bind_allocator, i );
+ if( bind->input_index == id )
+ {
+ if( matched )
+ $v_string( stream, {" or "} );
+
+ matched ++;
+
+ for( u32 j=0; j<ARRAY_COUNT( _input_aliases ); j ++ )
+ {
+ struct input_alias *alias_j = &_input_aliases[j];
+ if( (alias_j->device_type == k_input_device_modifier) && (bind->modifiers & alias_j->key) )
+ {
+ $v_string( stream, {alias_j->alias}, {"+"} );
+ }
+ }
+ for( u32 j=0; j<ARRAY_COUNT( _input_aliases ); j ++ )
+ {
+ struct input_alias *alias_j = &_input_aliases[j];
+ if( (alias_j->device_type == bind->device) && (alias_j->key == bind->id) )
+ {
+ $v_string( stream, {alias_j->alias} );
+ }
+ }
+ }
+ }
+}
_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[]){ 0, 0, _engine.w, _engine.h }, (union colour){{0,0,0,255}} );
}
void _engine_ui_input_character( u32 codepoint )
void _engine_ui_post_render(void)
{
+ glEnable( GL_BLEND );
+ glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
+ glBlendEquation( GL_FUNC_ADD );
+
glActiveTexture( GL_TEXTURE0 );
glBindTexture( GL_TEXTURE_2D, _ui_surface_texture );
glTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, 1920, 1080, GL_BGRA, GL_UNSIGNED_BYTE, _ui_surface.buffer );
_shader_blit_uInverseRatio( (f32[2]){ (f64)_engine.w/1920.0, (f64)_engine.h/1080.0 } );
glBindVertexArray( quad_vao );
glDrawArrays( GL_TRIANGLES, 0, 6 );
+
+ glDisable( GL_BLEND );
}
c += 1 << (SMALL_SEGMENTS + i);
stretchy->segments[i] = NULL;
}
+ stretchy->count = 0;
}
void stretchy_shrink( struct stretchy_allocator *stretchy )
return kv_offset;
}
+u32 keyvalues_append_frame( struct keyvalues *kvs, u32 parent_offset, const c8 *key )
+{
+ return keyvalues_append_string( kvs, parent_offset, key, NULL );
+}
+
u32 keyvalues_type( struct keyvalues *kvs, u32 kv_offset )
{
struct keyvalue *kv = stack_pointer( kvs->stack, kv_offset );
else return 0;
}
-u32 keyvalues_get( struct keyvalues *kvs, u32 root_offset, const c8 *key )
+u32 keyvalues_get( struct keyvalues *kvs, u32 root_offset, const c8 *key, bool relative )
{
if( root_offset == 0 )
root_offset = kvs->root_offset;
u32 hash = buffer_djb2( key, 0 );
- u32 child_offset = keyvalues_get_child( kvs, root_offset, 0 );
+ u32 child_offset;
+
+ if( relative )
+ child_offset = keyvalues_get_next( kvs, root_offset );
+ else
+ child_offset = keyvalues_get_child( kvs, root_offset, 0 );
+
while( child_offset )
{
struct keyvalue *kv = stack_pointer( kvs->stack, child_offset );
bool good = 1;
u32 value_length;
- char *value = keyvalues_value( kvs, keyvalues_get( kvs, root_offset, key ), &value_length );
+ char *value = keyvalues_value( kvs, keyvalues_get( kvs, root_offset, key, 0 ), &value_length );
struct stream s;
stream_open_buffer_read( &s, value, value_length, 0 );
bool good = 1;
u32 value_length;
- char *value = keyvalues_value( kvs, keyvalues_get( kvs, root_offset, key ), &value_length );
+ char *value = keyvalues_value( kvs, keyvalues_get( kvs, root_offset, key, 0 ), &value_length );
struct stream s;
stream_open_buffer_read( &s, value, value_length, 0 );
bool good = 1;
u32 value_length;
- char *value = keyvalues_value( kvs, keyvalues_get( kvs, root_offset, key ), &value_length );
+ char *value = keyvalues_value( kvs, keyvalues_get( kvs, root_offset, key, 0 ), &value_length );
struct stream s;
stream_open_buffer_read( &s, value, value_length, 0 );
const c8 *keyvalues_read_string( struct keyvalues *kvs, u32 root_offset, const c8 *key, const c8 *default_value )
{
- const c8 *value = keyvalues_value( kvs, keyvalues_get( kvs, root_offset, key ), NULL );
+ const c8 *value = keyvalues_value( kvs, keyvalues_get( kvs, root_offset, key, 0 ), NULL );
return value? value: default_value;
}
-#define KV_APPEND_TEMPLATE( FUNCTION, ... ) \
- u32 temp_frame = _start_temporary_frame(); \
- struct stream value_str; \
- stream_open_stack( &value_str, _temporary_stack_allocator(), k_stream_null_terminate ); \
- for( u32 i=0; i<len; i++ ) \
- { \
- FUNCTION ( &value_str, values[i], __VA_ARGS__ ); \
- if( i+1!=len ) \
- string_append_c8( &value_str, ' ' ); \
- } \
+#define KV_APPEND_TEMPLATE( FUNCTION, ... ) \
+ struct stream value_str; \
+ stream_open_stack( &value_str, kvs->stack, k_stream_null_terminate ); \
+ for( u32 i=0; i<len; i++ ) \
+ { \
+ FUNCTION ( &value_str, values[i], __VA_ARGS__ ); \
+ if( i+1!=len ) \
+ string_append_c8( &value_str, ' ' ); \
+ } \
u32 r = keyvalues_append_string( kvs, parent_offset, key, string_get(&value_str) ); \
- _end_temporary_frame( temp_frame ); \
return r;
-u32 keyvalues_append_vu32( struct keyvalues *kvs, u32 parent_offset, const c8 *key, u32 *values, u32 len )
+u32 keyvalues_append_u32s( struct keyvalues *kvs, u32 parent_offset, const c8 *key, u32 *values, u32 len )
{
KV_APPEND_TEMPLATE( string_append_u64, 10 )
}
-u32 keyvalues_append_vi32( struct keyvalues *kvs, u32 parent_offset, const c8 *key, i32 *values, u32 len )
+u32 keyvalues_append_i32s( struct keyvalues *kvs, u32 parent_offset, const c8 *key, i32 *values, u32 len )
{
KV_APPEND_TEMPLATE( string_append_i64, 10 );
}
-u32 keyvalues_append_vf32( struct keyvalues *kvs, u32 parent_offset, const c8 *key, f32 *values, u32 len )
+u32 keyvalues_append_f32s( struct keyvalues *kvs, u32 parent_offset, const c8 *key, f32 *values, u32 len )
{
KV_APPEND_TEMPLATE( string_append_f64, 10, 5 )
}
}
}
+static void kv_write_string( struct stream *out_stream, const c8 *string )
+{
+ c8 delim=0;
+ bool passed = 0;
+
+ for( u32 i=0; i<4096; i ++ )
+ {
+ c8 c = string[i];
+ if( c == '\0' )
+ {
+ if( i == 0 )
+ delim = '"';
+
+ passed = 1;
+ break;
+ }
+
+ c8 new_delim = 0;
+ if( c == '"' )
+ new_delim = '\'';
+ else if( c == '\'' || ((delim == 0) && (c == ' ' || c == '\t' || c == '\n')) )
+ new_delim = '"';
+
+ if( new_delim )
+ {
+ if( delim && (new_delim != delim) )
+ {
+ break;
+ }
+ else delim = new_delim;
+ }
+ }
+
+ if( passed )
+ {
+ if( delim ) string_append_c8( out_stream, delim );
+ string_append( out_stream, string, 0 );
+ if( delim ) string_append_c8( out_stream, delim );
+ }
+ else
+ {
+ string_append( out_stream, "ERROR_KV_UNWRITABLE_STRING", 0 );
+ }
+}
void keyvalues_write_stream( struct keyvalues *kvs, struct stream *out_stream, u32 node, u32 depth )
{
+ if( node == 0 )
+ node = kvs->root_offset;
+
+ ASSERT_CRITICAL( keyvalues_type( kvs, node ) == k_keyvalue_type_frame );
u32 kv = keyvalues_get_child( kvs, node, 0 );
while( kv )
{
{
for( u32 i=0; i<depth; i ++ )
$v_string( out_stream, {" "} );
- $v_string( out_stream, {keyvalues_key( kvs, kv, NULL )}, {" "}, {keyvalues_value( kvs, kv, NULL )}, {"\n"} );
+
+ kv_write_string( out_stream, keyvalues_key( kvs, kv, NULL ) );
+ $v_string( out_stream, {" "} );
+ kv_write_string( out_stream, keyvalues_value( kvs, kv, NULL ) );
+ $v_string( out_stream, {"\n"} );
}
else
+ {
+ const c8 *key = keyvalues_key( kvs, kv, NULL);
+ if( key )
+ {
+ for( u32 i=0; i<depth; i ++ ) $v_string( out_stream, {" "} );
+ kv_write_string( out_stream, keyvalues_key( kvs, kv, NULL ) );
+ $v_string( out_stream, {"\n"} );
+ }
+
+ for( u32 i=0; i<depth; i ++ ) $v_string( out_stream, {" "} );
+ $v_string( out_stream, {"{\n"} );
+
keyvalues_write_stream( kvs, out_stream, kv, depth+1 );
+
+ for( u32 i=0; i<depth; i ++ ) $v_string( out_stream, {" "} );
+ $v_string( out_stream, {"}\n"} );
+ }
kv = keyvalues_get_next( kvs, kv );
}
}
vg_stream_write( w->stream, (c8[]){ ' ' }, 1 );
}
-static void vg_kv_write_string( vg_kv_write *w, const c8 *string, u32 length )
-{
- if( length == 0 )
- length = 0xffffffff;
-
- u32 i=0;
- char delim=0;
- for( ;i<length; i ++ )
- {
- char c = string[i];
- if( c == '\0' )
- break;
-
- char new_delim = 0;
- if( c == '"' )
- new_delim = '\'';
- else if( c == '\'' || c == ' ' || c == '\t' || c == '\n' )
- new_delim = '"';
-
- if( new_delim )
- {
- if( delim && (new_delim != delim) )
- {
- vg_kv_write_string( w, "VG_KV_UNWRITABLE_STRING", 0 );
- return;
- }
- else delim = new_delim;
- }
- }
-
- if( delim ) vg_stream_write( w->stream, (c8[]){ delim }, 1 );
- vg_stream_write( w->stream, string, i );
- if( delim ) vg_stream_write( w->stream, (c8[]){ delim }, 1 );
-}
-
void vg_kv_write_block( vg_kv_write *w, const c8 *name, u32 name_length )
{
vg_kv_write_indent( w );
_graphics_pixel( wl, colour );
}
+union colour graphics_lerp_colour( union colour c0, union colour c1, i32 d, i32 t )
+{
+ if( t == 0 ) return c0;
+ if( t == d ) return c1;
+ if( d == 0 ) return c0;
+
+ return (union colour){{ (i32)c0.r + (((i32)c1.r - (i32)c0.r)*d*t) / (d*d),
+ (i32)c0.g + (((i32)c1.g - (i32)c0.g)*d*t) / (d*d),
+ (i32)c0.b + (((i32)c1.b - (i32)c0.b)*d*t) / (d*d),
+ (i32)c0.a + (((i32)c1.a - (i32)c0.a)*d*t) / (d*d) }};
+}
+
+void _graphics_line2( i16 p0[2], i16 p1[2], union colour c0, union colour c1 )
+{
+ struct bresenham b;
+ bresenham_init( &b, p0, p1 );
+ i16 wl[2];
+ while( bresenham_iter( &b, wl ) )
+ {
+ i32 d = b.delta[0],
+ t = b.x;
+ _graphics_pixel( wl, graphics_lerp_colour( c0, c1, d, t ) );
+ }
+}
+
void _graphics_line_triangle( i16 p0[2], i16 p1[2], i16 p2[2], union colour colour )
{
_graphics_line( p0, p1, colour );
//i16 clipping_area[4];
i16 mouse_co[2], mouse_co_clicked[2];
+ bool mouse_went_in_click_hole;
/* internal state */
enum ui_control_type
}
for( i32 i=0; i<input_length; i ++ )
- if( i < _ui.controls.textbox.text_buffer_length )
+ if( i0+i < _ui.controls.textbox.text_buffer_length )
buffer[i0+i] = input[i];
buffer[ i32_min( _ui.controls.textbox.text_buffer_length-1, i0+input_length+remainder_length ) ] = 0;
- _ui.controls.textbox.cursor_pos = i0+1;
- _ui.controls.textbox.cursor_user = i0+1;
+ _ui.controls.textbox.cursor_pos = i32_min( i0+input_length, _ui.controls.textbox.text_buffer_length-1 );
+ _ui.controls.textbox.cursor_user = _ui.controls.textbox.cursor_pos;
}
static void _ui_textbox_set_cursor_user( i32 position, bool super )
_ui.controls.textbox.action = k_textbox_no_action;
}
+ enum textbox_action return_action = k_textbox_no_action;
+
union colour text_colour = (union colour){{255,255,255,255}};
if( _ui.active_control_type == k_ui_control_textbox )
{
_ui.controls.textbox.cursor_user = _ui_textbox_visual_to_buffer_index( rect, co );
}
else
+ {
_ui.active_control_type = k_ui_control_none;
+ _ui.active_control_touched = 1;
+ }
+ }
+
+ return_action = _ui.controls.textbox.action;
+ _ui.controls.textbox.action = k_textbox_no_action;
+ if( (return_action == k_textbox_enter) && !(flags & UI_MULTILINE ) )
+ {
+ _ui.active_control_type = k_ui_control_none;
+ _ui.active_control_touched = 1;
}
}
}
_ui_text( rect, text_buffer, k_ui_align_x_left, text_colour );
- enum textbox_action return_action = _ui.controls.textbox.action;
- _ui.controls.textbox.action = k_textbox_no_action;
- if( (return_action == k_textbox_enter) && !(flags & UI_MULTILINE ) )
- _ui.active_control_type = k_ui_control_none;
return return_action;
}
}
_ui.active_control_touched = 0;
+ _ui.mouse_went_in_click_hole = 0;
+
return _ui.redraw;
}
_graphics_fill_rect( (i16[]){ _ui.mouse_co[0],_ui.mouse_co[1], 3,3 }, (union colour){{255,255,255,255}} );
}
+bool _ui_want_mouse( i16 area[4] )
+{
+ if( _ui.active_control_touched )
+ return 1;
+
+ if( ui_inside_rect( area, _ui.mouse_co ) )
+ {
+ if( _ui.active_control_type != k_ui_control_none )
+ return 1;
+
+ if( _input_button_down( k_input_action_ui_click, 0 ) )
+ return 1;
+ }
+
+ return 0;
+}
--- /dev/null
+#include "generated/hooks.h"
+
+i32 main( i32 argc, const c8 *argv[] )
+{
+ VG_PRE_MAIN;
+ EVENT_CALL( START );
+}