diff options
| -rw-r--r-- | src/editor/editor.cpp | 12 | ||||
| -rw-r--r-- | src/editor/editor.h | 16 | ||||
| -rw-r--r-- | src/editor/editor_contextmenu.cpp | 35 | ||||
| -rw-r--r-- | src/editor/editor_infobox.cpp | 2 | ||||
| -rw-r--r-- | src/editor/editor_menubar.cpp | 46 | ||||
| -rw-r--r-- | src/editor/properties.cpp | 252 | ||||
| -rw-r--r-- | src/editor/properties.h | 160 | ||||
| -rw-r--r-- | src/editor/toolview.cpp | 20 | ||||
| -rw-r--r-- | src/game/world/map.cpp | 52 | ||||
| -rw-r--r-- | src/game/world/map.h | 87 | ||||
| -rw-r--r-- | src/gui/base.h | 5 | ||||
| -rw-r--r-- | src/util/allocator.h | 11 | ||||
| -rw-r--r-- | src/util/callback.h | 84 | ||||
| -rw-r--r-- | src/util/color.h | 4 | ||||
| -rw-r--r-- | src/util/config.h | 25 | ||||
| -rw-r--r-- | src/util/config/config.cpp | 13 | ||||
| -rw-r--r-- | src/util/config/serializers.cpp | 115 | ||||
| -rw-r--r-- | src/util/file.h | 4 | ||||
| -rw-r--r-- | src/util/input.h | 3 | ||||
| -rw-r--r-- | src/util/str_tokenizer.h | 140 | ||||
| -rw-r--r-- | src/util/string.h | 27 | ||||
| -rw-r--r-- | src/util/vector.h | 8 |
22 files changed, 744 insertions, 377 deletions
diff --git a/src/editor/editor.cpp b/src/editor/editor.cpp index dee5080..ba61961 100644 --- a/src/editor/editor.cpp +++ b/src/editor/editor.cpp @@ -56,7 +56,6 @@ static U8 editor_clr_eq( const CLR& a, const CLR& b ) { static U8 editor_vertex_eq( const MAP_VERTEX& a, const MAP_VERTEX& b ) { return a.pos == b.pos - && a.normal == b.normal && a.uv == b.uv && editor_clr_eq( a.clr, b.clr ); } @@ -604,15 +603,15 @@ STAT editor_new_map( GAME_EDITOR* e, const char* mapname ) { WORLD_MAP* m = new WORLD_MAP; defer( map_free( e->game, m ) ); - strcpy( m->name, mapname ); - strcat( m->name, ".hmap" ); + m->name = mapname; + m->name += ".hmap"; m->startpos = { 10.f, 10.f, 0.f }; m->props.push( { .clr = { 1.f, 1.f, 1.f, 1.f } } ); m->walls.push( { + .propid = 0, .start = { 0 , 0, -40.f }, .end = { 10.f, 0, 80.f }, - .propid = 0 } ); CFG_SECTION* map_cfg = map_serialize( m ); @@ -641,11 +640,10 @@ STAT editor_save_map( GAME_EDITOR* e ) { if( !serialized ) return STAT_ERR; defer( cfg_free( serialized ) ); - char full_path[256]; - sprintf( full_path, "../assets/maps/%s", e->map->name ); + STR full_path = { "../assets/maps/%s", e->map->name.data }; if( !OK( cfg_save( serialized, full_path ) ) ) { - dlog( "failed to save map %s", full_path ); + dlog( "failed to save map %s", full_path.data ); return STAT_ERR; } diff --git a/src/editor/editor.h b/src/editor/editor.h index 828f2e4..33396df 100644 --- a/src/editor/editor.h +++ b/src/editor/editor.h @@ -66,7 +66,7 @@ enum EditorObjectType_t { typedef void( *EDITOR_CONTEXTMENU_CALLBACK )( void* data ); struct EDITOR_CONTEXTMENU_ITEM; -typedef U8( *EDITOR_CONTEXTMENU_ENABLED_CALLBACK )( const EDITOR_CONTEXTMENU_ITEM* item ); +typedef U8( *EDITOR_CONTEXTMENU_ENABLED_CALLBACK )( EDITOR_CONTEXTMENU_ITEM* item ); struct EDITOR_CONTEXTMENU_ITEM { char text[64]{}; @@ -209,9 +209,6 @@ extern void editor_create_map_view( GAME_EDITOR* e ); extern void editor_update_properties_column( GAME_EDITOR* e ); extern const char* editor_tool_name(); extern void editor_set_view_mode( I32 mode ); -extern void editor_show_contextmenu( I32 x, I32 y, LIST<EDITOR_CONTEXTMENU_ITEM>* items, const char* title = 0 ); -extern void editor_hide_contextmenu(); -extern U8 editor_contextmenu_open(); extern void editor_undo_clear( GAME_EDITOR* e ); extern void editor_undo_record_create_walls( GAME_EDITOR* e, I32 start_idx, I32 count ); extern void editor_undo_record_create_poly( GAME_EDITOR* e, I32 start_idx ); @@ -220,6 +217,17 @@ extern void editor_undo_record_create_entity( GAME_EDITOR* e, I32 start_idx ); extern U8 editor_undo( GAME_EDITOR* e ); extern U8 editor_redo( GAME_EDITOR* e ); +extern void editor_show_contextmenu( I32 x, I32 y, LIST<EDITOR_CONTEXTMENU_ITEM>* items, const char* title = 0 ); +extern void editor_hide_contextmenu(); +extern U8 editor_contextmenu_open(); +extern void editor_contextmenu_set_item( + EDITOR_CONTEXTMENU_ITEM* item, + const char* text, + EDITOR_CONTEXTMENU_CALLBACK cb = 0, + void* data = 0, + EDITOR_CONTEXTMENU_ENABLED_CALLBACK enabled_cb = 0 +); + struct GUI_EDITORWINDOW : GUI_WINDOW {}; struct GUI_EDITOR_3DVIEW : GUI_VIEW { U8 heldoutbounds; diff --git a/src/editor/editor_contextmenu.cpp b/src/editor/editor_contextmenu.cpp index 2b0bb1f..4f9dbe6 100644 --- a/src/editor/editor_contextmenu.cpp +++ b/src/editor/editor_contextmenu.cpp @@ -1,6 +1,6 @@ #include "editor_gui_internal.h" -static U8 editor_contextmenu_item_enabled( const EDITOR_CONTEXTMENU_ITEM* item ) { +U8 editor_contextmenu_item_enabled( EDITOR_CONTEXTMENU_ITEM* item ) { if( !item ) return 0; @@ -10,15 +10,15 @@ static U8 editor_contextmenu_item_enabled( const EDITOR_CONTEXTMENU_ITEM* item ) return item->enabled; } -static I32 editor_contextmenu_title_h( const GUI_EDITOR_CONTEXTMENU* menu ) { +I32 editor_contextmenu_title_h( GUI_EDITOR_CONTEXTMENU* menu ) { return ( menu && menu->title[0] ) ? 18 : 0; } -static I32 editor_contextmenu_row_h() { +I32 editor_contextmenu_row_h() { return 20; } -static I32 editor_contextmenu_width( LIST<EDITOR_CONTEXTMENU_ITEM>* items, const char* title ) { +I32 editor_contextmenu_width( LIST<EDITOR_CONTEXTMENU_ITEM>* items, const char* title ) { I32 width = EDITOR_TOOLBAR_DROPDOWN_W; if( title && title[0] ) { I32 text_w = 0; @@ -38,7 +38,7 @@ static I32 editor_contextmenu_width( LIST<EDITOR_CONTEXTMENU_ITEM>* items, const return width; } -static I32 editor_contextmenu_height( LIST<EDITOR_CONTEXTMENU_ITEM>* items, const char* title ) { +I32 editor_contextmenu_height( LIST<EDITOR_CONTEXTMENU_ITEM>* items, const char* title ) { I32 height = 4 + editor_contextmenu_row_h() * ( items ? (I32)items->size : 0 ); if( title && title[0] ) height += 18 + 1; @@ -52,7 +52,7 @@ static I32 editor_contextmenu_items_y( GUI_EDITOR_CONTEXTMENU* menu ) { return y; } -static I32 editor_contextmenu_hit_test( GUI_EDITOR_CONTEXTMENU* menu, I32 mx, I32 my ) { +I32 editor_contextmenu_hit_test( GUI_EDITOR_CONTEXTMENU* menu, I32 mx, I32 my ) { if( !menu || !menu->items ) return -1; @@ -72,7 +72,7 @@ static I32 editor_contextmenu_hit_test( GUI_EDITOR_CONTEXTMENU* menu, I32 mx, I3 return idx; } -static void gui_editor_contextmenu_draw_fn( void* ptr ) { +void gui_editor_contextmenu_draw_fn( void* ptr ) { GUI_EDITOR_CONTEXTMENU* menu = (GUI_EDITOR_CONTEXTMENU*)ptr; if( !menu || !menu->items || !menu->items->size ) return; @@ -128,7 +128,7 @@ static void gui_editor_contextmenu_draw_fn( void* ptr ) { } } -static void gui_editor_contextmenu_input_fn( void* ptr ) { +void gui_editor_contextmenu_input_fn( void* ptr ) { GUI_EDITOR_CONTEXTMENU* menu = (GUI_EDITOR_CONTEXTMENU*)ptr; if( !menu || !menu->items || !menu->items->size ) return; @@ -199,6 +199,25 @@ U8 editor_contextmenu_open() { return editor && editor->gui.contextmenu && editor->gui.contextmenu->enabled; } + +void editor_contextmenu_set_item( + EDITOR_CONTEXTMENU_ITEM* item, + const char* text, + EDITOR_CONTEXTMENU_CALLBACK cb, + void* data, + EDITOR_CONTEXTMENU_ENABLED_CALLBACK enabled_cb +) { + if( !item ) + return; + + item->items.clear(); + snprintf( item->text, sizeof( item->text ), "%s", text ? text : "" ); + item->cb = cb; + item->data = data; + item->enabled = 1; + item->enabled_cb = enabled_cb; +} + void editor_show_contextmenu( I32 x, I32 y, LIST<EDITOR_CONTEXTMENU_ITEM>* items, const char* title ) { editor_hide_contextmenu(); if( !editor || !editor->wnd || !items || !items->size ) diff --git a/src/editor/editor_infobox.cpp b/src/editor/editor_infobox.cpp index 9f9060d..479b59d 100644 --- a/src/editor/editor_infobox.cpp +++ b/src/editor/editor_infobox.cpp @@ -100,7 +100,7 @@ static void gui_editor_infobox_draw_assets( GUI_EDITOR_INFOBOX* box, I32 panel_x I32 text_x = tx + EDITOR_ASSETS_THUMB + 8; CLR txt = ui_clr.txt; if( map_entry ) { - gui_draw_str( text_x, row_y + 7, ALIGN_L, FNT_JPN12, txt, "[map] -> %s", map->name ); + gui_draw_str( text_x, row_y + 7, ALIGN_L, FNT_JPN12, txt, "[map] -> %s", map->name.data ); } else if( p->tex ) { gui_draw_str( text_x, row_y + 7, ALIGN_L, FNT_JPN12, txt, "[%d] -> %s", idx - 1, p->tex->name ); } else { diff --git a/src/editor/editor_menubar.cpp b/src/editor/editor_menubar.cpp index b89d1c6..cef2650 100644 --- a/src/editor/editor_menubar.cpp +++ b/src/editor/editor_menubar.cpp @@ -66,56 +66,38 @@ void editor_raise_header_toolbar( GAME_EDITOR* e ) { parent->children.push( bar ); } -static void editor_contextmenu_set_item( - EDITOR_CONTEXTMENU_ITEM* item, - const char* text, - EDITOR_CONTEXTMENU_CALLBACK cb = 0, - void* data = 0, - EDITOR_CONTEXTMENU_ENABLED_CALLBACK enabled_cb = 0 -) { - if( !item ) - return; - - item->items.clear(); - snprintf( item->text, sizeof( item->text ), "%s", text ? text : "" ); - item->cb = cb; - item->data = data; - item->enabled = 1; - item->enabled_cb = enabled_cb; -} - -static void editor_contextmenu_save_cb( void* ) { +void editor_contextmenu_save_cb( void* ) { if( editor ) editor_save_map( editor ); } -static void editor_contextmenu_undo_cb( void* ) { +void editor_contextmenu_undo_cb( void* ) { if( editor ) editor_undo( editor ); } -static void editor_contextmenu_redo_cb( void* ) { +void editor_contextmenu_redo_cb( void* ) { if( editor ) editor_redo( editor ); } -static void editor_contextmenu_set_view_mode_cb( void* data ) { +void editor_contextmenu_set_view_mode_cb( void* data ) { editor_set_view_mode( (I32)(I64)data ); } -static void editor_contextmenu_set_tool_cb( void* data ) { +void editor_contextmenu_set_tool_cb( void* data ) { editor_settool( (U8)(I64)data ); } -static U8 editor_contextmenu_undo_enabled( const EDITOR_CONTEXTMENU_ITEM* ) { +U8 editor_contextmenu_undo_enabled( EDITOR_CONTEXTMENU_ITEM* ) { return editor && editor->undo_actions.size > 0; } -static U8 editor_contextmenu_redo_enabled( const EDITOR_CONTEXTMENU_ITEM* ) { +U8 editor_contextmenu_redo_enabled( EDITOR_CONTEXTMENU_ITEM* ) { return editor && editor->redo_actions.size > 0; } -static void editor_toolbar_init_entries( GUI_EDITOR_TOOLBAR* bar ) { +void editor_toolbar_init_entries( GUI_EDITOR_TOOLBAR* bar ) { if( !bar ) return; @@ -146,7 +128,7 @@ static void editor_toolbar_init_entries( GUI_EDITOR_TOOLBAR* bar ) { editor_contextmenu_set_item( &bar->entries[3].items[4], "object", editor_contextmenu_set_tool_cb, (void*)(I64)EDITOR_TOOL_OBJECT ); } -static I32 editor_toolbar_root_width( const EDITOR_CONTEXTMENU_ITEM* entry ) { +I32 editor_toolbar_root_width( const EDITOR_CONTEXTMENU_ITEM* entry ) { if( !entry ) return 44; @@ -155,7 +137,7 @@ static I32 editor_toolbar_root_width( const EDITOR_CONTEXTMENU_ITEM* entry ) { return max( 44, text_w + 16 ); } -static void editor_toolbar_root_rect( GUI_EDITOR_TOOLBAR* bar, I32 idx, I32* rx, I32* ry, I32* rw, I32* rh ) { +void editor_toolbar_root_rect( GUI_EDITOR_TOOLBAR* bar, I32 idx, I32* rx, I32* ry, I32* rw, I32* rh ) { I32 x = gui_relx( bar ); I32 y = gui_rely( bar ); I32 cx = x + 8; @@ -172,11 +154,11 @@ struct EDITOR_TOOLBAR_HIT { I32 root{-1}; }; -static U8 editor_toolbar_pt_in_rect( I32 mx, I32 my, I32 x, I32 y, I32 w, I32 h ) { +U8 editor_toolbar_pt_in_rect( I32 mx, I32 my, I32 x, I32 y, I32 w, I32 h ) { return mx >= x && mx < x + w && my >= y && my < y + h; } -static EDITOR_TOOLBAR_HIT editor_toolbar_hit_test( GUI_EDITOR_TOOLBAR* bar, I32 mx, I32 my ) { +EDITOR_TOOLBAR_HIT editor_toolbar_hit_test( GUI_EDITOR_TOOLBAR* bar, I32 mx, I32 my ) { EDITOR_TOOLBAR_HIT hit{}; for( I32 i = 0; i < (I32)bar->entries.size; ++i ) { I32 x = 0, y = 0, w = 0, h = 0; @@ -190,7 +172,7 @@ static EDITOR_TOOLBAR_HIT editor_toolbar_hit_test( GUI_EDITOR_TOOLBAR* bar, I32 return hit; } -static void gui_editor_toolbar_draw_fn( void* ptr ) { +void gui_editor_toolbar_draw_fn( void* ptr ) { GUI_EDITOR_TOOLBAR* bar = (GUI_EDITOR_TOOLBAR*)ptr; I32 x = gui_relx( bar ); I32 y = gui_rely( bar ); @@ -229,7 +211,7 @@ static void gui_editor_toolbar_draw_fn( void* ptr ) { } } -static void gui_editor_toolbar_input_fn( void* ptr ) { +void gui_editor_toolbar_input_fn( void* ptr ) { GUI_EDITOR_TOOLBAR* bar = (GUI_EDITOR_TOOLBAR*)ptr; I32 mx = 0, my = 0; gui_cursor_pos( &mx, &my ); diff --git a/src/editor/properties.cpp b/src/editor/properties.cpp index ac21bb0..c9eb991 100644 --- a/src/editor/properties.cpp +++ b/src/editor/properties.cpp @@ -1,3 +1,4 @@ +#include "properties.h" #include "editor.h" #include "../render/gl.h" #include "../game/assets.h" @@ -8,36 +9,36 @@ const I32 PROPVIEW_PAD = 10; const I32 PROPVIEW_ACTION_BTN_W = 20; const I32 PROPVIEW_ACTION_BTN_GAP = 5; -static I32 propview_col_left() { +I32 propview_col_left() { return PROPVIEW_PAD; } -static I32 propview_col_right( GUI_EDITOR_PROPVIEW* view ) { +I32 propview_col_right( GUI_EDITOR_PROPVIEW* view ) { if( !view ) return PROPVIEW_PAD; return max( PROPVIEW_PAD, view->w - PROPVIEW_PAD ); } -static I32 propview_input_width( GUI_EDITOR_PROPVIEW* view ) { +I32 propview_input_width( GUI_EDITOR_PROPVIEW* view ) { return max( 120, propview_col_right( view ) - propview_col_left() ); } -static I32 propview_sub_input_x( I32 x ) { +I32 propview_sub_input_x( I32 x ) { return x + 10; } -static I32 propview_sub_input_width( GUI_EDITOR_PROPVIEW* view, I32 x ) { - I32 right = propview_col_right( view ); - return max( 100, right - propview_sub_input_x( x ) ); -} +// I32 propview_sub_input_width( GUI_EDITOR_PROPVIEW* view, I32 x ) { +// I32 right = propview_col_right( view ); +// return max( 100, right - propview_sub_input_x( x ) ); +// } -static I32 propview_action_x( GUI_EDITOR_PROPVIEW* view ) { +I32 propview_action_x( GUI_EDITOR_PROPVIEW* view ) { I32 right = propview_col_right( view ); return max( propview_col_left(), right - PROPVIEW_ACTION_BTN_W ); } -static I32 propview_action2_x( GUI_EDITOR_PROPVIEW* view ) { +I32 propview_action2_x( GUI_EDITOR_PROPVIEW* view ) { return max( propview_col_left(), propview_action_x( view ) - PROPVIEW_ACTION_BTN_W - PROPVIEW_ACTION_BTN_GAP @@ -66,122 +67,137 @@ void gui_editor_propview_select( GUI_EDITOR_PROPVIEW* view, void* what, U8 selty gui_editor_propview_update( view ); } -// returns the subentry height -I32 gui_editor_propview_surfprops_subentry( - GUI_EDITOR_PROPVIEW* view, - I32 x, - I32 y, - I32* propid, - SURF_PROPS* props -) { - I32 oldy = y; - I32 space = 20; - I32 action_x = propview_action_x( view ); + + +void gui_editor_propview_create_eobj_props( GUI_EDITOR_PROPVIEW* view, EOBJECT* e, I32* x, I32* y, I32 w ); +void gui_editor_propview_create_eobj_prop( GUI_EDITOR_PROPVIEW* view, EDITOR_PROP* prop, I32* x, I32* y, I32 w, I32 space ) { + F32 action_x = propview_action_x( view ); I32 action2_x = propview_action2_x( view ); - gui_label( x, y, "prop id: %d", *propid ); - GUI_BUTTON* newprop = gui_button( action2_x, y, 20, 20, "+", pfn( void* ptr ) { - GUI_BUTTON* btn = (GUI_BUTTON*)ptr; - SURF_PROPS props; - props.tex = 0; - props.clr = { 1.f, 1.f, 1.f, 1.f }; - - editor->map->props.push( props ); - *(U32*)(btn->extra) = editor->map->props.size - 1; - // Keep the newest prop visible in the assets panel (pixel scroll). - editor->gui.assets_scroll = ( editor->map->props.size + 1 ) * 28; - gui_editor_propview_update( editor->gui.props ); - } ); - newprop->extra = propid; - GUI_BUTTON* goprop = gui_button( action_x, y, 20, 20, "\x1A", pfn( void* ptr ) { - GUI_BUTTON* btn = (GUI_BUTTON*)ptr; - gui_editor_propview_select( editor->gui.props, btn->extra, EDITOR_SELECT_SURFPROPS ); - } ); - goprop->extra = props; + const char* n = prop->displayname; + F32 min = prop->min; + F32 max = prop->max; + F32 step; + + if( prop->step ) step = prop->step; + else step = editor->propgrid ? editor->grid : 0.25f; + + switch( prop->type ) { + case EPROP_F32: gui_floatinput( *x, *y, w, n, (F32*)eprop_ptr( prop ), min, max, step ); *y += (space+18); break; + case EPROP_VEC2: gui_vectorinput( *x, *y, w, n, (F32*)eprop_ptr( prop ), 2, min, max, step, "xy", "%.03f" ); *y += (space+18); break; + case EPROP_VEC3: gui_vectorinput( *x, *y, w, n, (F32*)eprop_ptr( prop ), 3, min, max, step, "xyz", "%.02f" ); *y += (space+18); break; + case EPROP_VEC4: gui_vectorinput( *x, *y, w, n, (F32*)eprop_ptr( prop ), 3, min, max, step, "xyzw", "%0.02f" ); *y += (space+18); break; + case EPROP_CLR: gui_colorinput( *x, *y, w, n, (CLR*)eprop_ptr( prop ) ); *y += (space+18); break; + case EPROP_MAPPROP: { + MAP_PROPREF* ref = (MAP_PROPREF*)eprop_ptr( prop ); + SURF_PROPS* props = map_get_props( editor->map, *ref ); + gui_label( *x, *y, "prop id: %d", *ref ); + + GUI_BUTTON* newprop = gui_button( action2_x, *y, 20, 20, "+", pfn( void* ptr ) { + GUI_BUTTON* btn = (GUI_BUTTON*)ptr; + SURF_PROPS props{ .tex = 0, .clr = CLR::WHITE() }; + editor->map->props.push( props ); + + ((MAP_PROPREF*)btn->extra)->id = editor->map->props.size - 1; + editor->gui.assets_scroll = ( editor->map->props.size + 1 ) * 28; + gui_editor_propview_update( editor->gui.props ); + } ); newprop->extra = ref; + + GUI_BUTTON* goprop = gui_button( action_x, *y, 20, 20, "\x1A", pfn( void* ptr ) { + GUI_BUTTON* btn = (GUI_BUTTON*)ptr; + gui_editor_propview_select( editor->gui.props, btn->extra, EDITOR_SELECT_SURFPROPS ); + } ); goprop->extra = props; *y += space; + + *x += 10; gui_editor_propview_create_eobj_props( view, props, x, y, w - 10 ); *x -= 10; + } break; + case EPROP_TEXTURE: { + GL_TEX2D** tex = (GL_TEX2D**)eprop_ptr( prop ); + if( *tex ) gui_label( *x, *y, "%s: %s", n, (*tex)->name ); + else gui_label( *x, *y, "%s: none", n ); + GUI_BUTTON* btn = gui_button( action_x, *y, 20, 20, "\x1A", pfn( void* ptr ) { + GUI_BUTTON* btn = (GUI_BUTTON*)ptr; + GL_TEX2D** ptex = (GL_TEX2D**)btn->extra; + GUI_EDITOR_TEXTUREPICKER* picker = gui_editor_texturepicker( 200, 100, 400, 400, ptex ); + picker->cb = pfn( void* ) { gui_editor_propview_update( editor->gui.props ); }; + } ); btn->extra = tex; *y += space; + } break; + case EPROP_VERTEX_LIST: { + LIST<MAP_VERTEX>* list = ( LIST<MAP_VERTEX>* )eprop_ptr( prop ); + gui_label( *x, *y, "%s : %d", n, list->size ); *y += space; + for( U32 i = 0; i < list->size; ++i ) { + MAP_VERTEX* v = &list->data[i]; + gui_label( (*x) + 10, *y, "[%d] -> [%s]", i, to_str( v->pos ).data ); + GUI_BUTTON* btn = gui_button( action_x, *y, 20, 20, "\x1A", pfn( void* ptr ) { + GUI_BUTTON* btn = (GUI_BUTTON*)ptr; + gui_editor_propview_select( editor->gui.props, btn->extra, EDITOR_SELECT_PVERTEX ); + } ); btn->extra = v; *y += space; + } + } break; + default: break; + } +} - y += space; +void gui_editor_propview_create_eobj_prop_ro( GUI_EDITOR_PROPVIEW* view, EDITOR_PROP* prop, I32* x, I32* y, I32 w, I32 space ) { + STR str = prop->displayname; + str += " : ["; + void* ptr = eprop_ptr( prop ); + + switch( prop->type ) { + case EPROP_F32: str += to_str( *(F32*)ptr ); break; + case EPROP_VEC2: str += to_str( *(VEC2*)ptr ); break; + case EPROP_VEC3: str += to_str( *(VEC3*)ptr ); break; + case EPROP_VEC4: str += to_str( *(VEC4*)ptr ); break; + case EPROP_CLR: str += to_str( *(CLR*)ptr ); break; + case EPROP_U32: str += to_str( *(U32*)ptr ); break; + case EPROP_U64: str += to_str( *(U64*)ptr ); break; + case EPROP_I32: str += to_str( *(I32*)ptr ); break; + case EPROP_I64: str += to_str( *(I64*)ptr ); break; + case EPROP_STRING: str += to_str( *(CLR*)ptr ); break; + } - if( props->tex ) - gui_label( x + 10, y, "texture: %s", props->tex->name ); - else - gui_label( x + 10, y, "texture: none" ); + str += "]"; + gui_label( *x, *y, str.data ); + *y += space; +} - GUI_BUTTON* btn = gui_button( action_x, y, 20, 20, "\x1A", pfn( void* ptr ) { - GUI_BUTTON* btn = (GUI_BUTTON*)ptr; - GL_TEX2D** ptex = (GL_TEX2D**)btn->extra; - GUI_EDITOR_TEXTUREPICKER* picker = gui_editor_texturepicker( 200, 100, 400, 400, ptex ); - picker->cb = pfn( void* ) { gui_editor_propview_update( editor->gui.props ); }; - } ); +void gui_editor_propview_create_eobj_props( GUI_EDITOR_PROPVIEW* view, EOBJECT* e, I32* x, I32* y, I32 w ) { + I32 space = 20; - btn->extra = &props->tex; - y += space; - gui_colorinput( - propview_sub_input_x( x ), - y, - propview_sub_input_width( view, x ), - "color", - &props->clr - ); y += (space+18); - - return y - oldy; + for( auto& it : e->eprops ) { + EDITOR_PROP* eprop = eprop_from_ref( e, it ); + if( eprop->readonly ) + gui_editor_propview_create_eobj_prop_ro( view, eprop, x, y, w, space ); + else + gui_editor_propview_create_eobj_prop( view, eprop, x, y, w, space ); + } } void gui_editor_propview_create_wallprops( GUI_EDITOR_PROPVIEW* view ) { MAP_WALL* s = (MAP_WALL*)view->curselect; WORLD_MAP* m = editor->map; - SURF_PROPS* props = wall_get_props( m, s ); I32 x = 10, y = 10; I32 space = 20; - F32 step = editor->propgrid? editor->grid : 0.25f; I32 wall_idx = m->walls.idx_where( fn( MAP_WALL* ms ) { return s == ms; } ); gui_label( x, y, "idx: %d", wall_idx ); y += space; - y += gui_editor_propview_surfprops_subentry( view, x, y, &s->propid, props ); - - GUI_VECTORINPUT* posinput; - posinput = gui_vectorinput( x, y, propview_input_width( view ), "start", (F32*)&s->start, 3, -INFINITY, INFINITY, step ); y += (space+18); - posinput->cb = pfn( void* ) { map_check_bounds( editor->map ); }; - posinput = gui_vectorinput( x, y, propview_input_width( view ), "end", (F32*)&s->end, 3, -INFINITY, INFINITY, step ); y += (space+18); - posinput->cb = pfn( void* ) { map_check_bounds( editor->map ); }; + return gui_editor_propview_create_eobj_props( view, s, &x, &y, propview_input_width( view ) ); } void gui_editor_propview_create_polyprops( GUI_EDITOR_PROPVIEW* view ) { MAP_POLYGON* p = (MAP_POLYGON*)view->curselect; WORLD_MAP* m = editor->map; - SURF_PROPS* props = polygon_get_props( m, p ); - I32 x = 10, y = 10; I32 space = 20; I32 poly_idx = m->polygons.idx_where( fn( MAP_POLYGON* mp ) { return p == mp; } ); - I32 action_x = propview_action_x( view ); gui_label( x, y, "idx: %d", poly_idx ); y += space; - y += gui_editor_propview_surfprops_subentry( view, x, y, &p->propid, props ); - - gui_label( x, y, "vertices: %d", p->vertices.size ); y += space; - I32 idx = 0; - p->vertices.each( fn( MAP_VERTEX* v ) { - gui_label( x + 10, y, "[%d] -> { %.02f, %.02f, %.02f }", idx, v->pos.x, v->pos.y, v->pos.z ); - GUI_BUTTON* btn = gui_button( action_x, y - 2, 20, 20, "\x1A", pfn( void* ptr ) { - GUI_EDITOR_PROPVIEW* view = editor->gui.props; - GUI_BUTTON* btn = (GUI_BUTTON*)ptr; - MAP_POLYGON* p = (MAP_POLYGON*)view->curselect; - I64 idx = (I64)btn->extra; - if( p ) // p100 - gui_editor_propview_select( view, &p->vertices[idx], EDITOR_SELECT_PVERTEX ); - } ); - - y += space; - btn->extra = (void*)( (I64)idx++ ); - } ); - gui_label( x, y, "mins: { %1.02f, %1.02f, %1.02f }", p->mins.x, p->mins.y, p->mins.z ); y += space; - gui_label( x, y, "maxs: { %1.02f, %1.02f, %1.02f }", p->maxs.x, p->maxs.y, p->maxs.z ); y += space; + return gui_editor_propview_create_eobj_props( view, p, &x, &y, propview_input_width( view ) ); } void gui_editor_propview_create_mapprops( GUI_EDITOR_PROPVIEW* view ) { @@ -192,7 +208,7 @@ void gui_editor_propview_create_mapprops( GUI_EDITOR_PROPVIEW* view ) { F32 step = editor->propgrid? editor->grid : 0.25f; - gui_label( x, y, "name: %s", m->name ); y += space; + gui_label( x, y, "name: %s", m->name.data ); y += space; gui_label( x, y, "walls: %d", m->walls.size ); y += space; gui_label( x, y, "polygons: %d", m->polygons.size ); y += space; gui_label( x, y, "props: %d", m->props.size ); y += space; @@ -232,12 +248,10 @@ void gui_editor_propview_create_pvertexprops( GUI_EDITOR_PROPVIEW* view ) { return vert_idx != -1; } ); - F32 step = editor->propgrid? editor->grid : 0.25f; I32 action_x = propview_action_x( view ); gui_label( x, y, "idx: %d", vert_idx ); y += space; gui_label( x, y, "polygon idx: %d", poly_idx ); - gui_button( action_x, y - 2, 20, 20, "\x1A", pfn( void* ) { GUI_EDITOR_PROPVIEW* view = editor->gui.props; MAP_VERTEX* v = (MAP_VERTEX*)view->curselect; @@ -249,15 +263,12 @@ void gui_editor_propview_create_pvertexprops( GUI_EDITOR_PROPVIEW* view ) { if( polygon ) gui_editor_propview_select( view, polygon, EDITOR_SELECT_POLY ); - } ); - y += space; + } ); y += space; - GUI_VECTORINPUT* posinput = gui_vectorinput( x, y, propview_input_width( view ), "position", (F32*)&v->pos, 3, -INFINITY, INFINITY, step ); y += (space+18); - posinput->cb = pfn( void* ptr ) { map_check_bounds( editor->map ); }; - gui_vectorinput( x, y, propview_input_width( view ), "texture coordinates", (F32*)&v->uv, 2, 0.f, 1.f, 0.005f, "xy", "%.03f" ); y += (space+18); - gui_colorinput( x, y, propview_input_width( view ), "color", &v->clr ); y += (space+18); + return gui_editor_propview_create_eobj_props( view, v, &x, &y, propview_input_width( view ) ); } + void gui_editor_propview_create_spriteprops( GUI_EDITOR_PROPVIEW* view ) { MAP_SPRITE* s = (MAP_SPRITE*)view->curselect; WORLD_MAP* m = editor->map; @@ -268,27 +279,9 @@ void gui_editor_propview_create_spriteprops( GUI_EDITOR_PROPVIEW* view ) { I32 sprite_idx = m->sprites.idx_where( fn( MAP_SPRITE* ms ) { return ms == s; } ); - I32 action_x = propview_action_x( view ); - - F32 step = editor->propgrid? editor->grid : 0.25f; gui_label( x, y, "idx: %d", sprite_idx ); y += space; - gui_vectorinput( x, y, propview_input_width( view ), "position", (F32*)&s->pos, 3, -INFINITY, INFINITY, step ); y += (space+18); - gui_vectorinput( x, y, propview_input_width( view ), "size", (F32*)&s->size, 2, 1.f, INFINITY, 1.f, "wh" ); y += (space+18); - gui_colorinput( x, y, propview_input_width( view ), "color", &s->clr ); y += (space+18); - if( s->tex ) - gui_label( x, y, "texture: %s", s->tex->name ); - else - gui_label( x, y, "texture: none" ); - - GUI_BUTTON* btn = gui_button( action_x, y, 20, 20, "\x1A", pfn( void* ptr ) { - GUI_BUTTON* btn = (GUI_BUTTON*)ptr; - GL_TEX2D** ptex = (GL_TEX2D**)btn->extra; - GUI_EDITOR_TEXTUREPICKER* picker = gui_editor_texturepicker( 200, 100, 400, 400, ptex ); - picker->cb = pfn( void* ) { gui_editor_propview_update( editor->gui.props ); }; - } ); - btn->extra = &s->tex; - y += space; + return gui_editor_propview_create_eobj_props( view, s, &x, &y, propview_input_width( view ) ); } void gui_editor_propview_create_surfprops( GUI_EDITOR_PROPVIEW* view ) { @@ -301,22 +294,9 @@ void gui_editor_propview_create_surfprops( GUI_EDITOR_PROPVIEW* view ) { I32 i = m->props.idx_where( fn( SURF_PROPS* mp ) { return mp == p; } ); if( i == -1 ) return; - I32 action_x = propview_action_x( view ); gui_label( x, y, "prop id: %d", i ); y += space; - if( p->tex ) - gui_label( x, y, "texture: %s", assets_abspath( p->tex->name ) ); - else - gui_label( x, y, "texture: none" ); - GUI_BUTTON* btn = gui_button( action_x, y, 20, 20, "\x1A", pfn( void* ptr ) { - GUI_BUTTON* btn = (GUI_BUTTON*)ptr; - GL_TEX2D** ptex = (GL_TEX2D**)btn->extra; - GUI_EDITOR_TEXTUREPICKER* picker = gui_editor_texturepicker( 200, 100, 400, 400, ptex ); - picker->cb = pfn( void* ) { gui_editor_propview_update( editor->gui.props ); }; - } ); - btn->extra = &p->tex; - y += space; - gui_colorinput( x, y, propview_input_width( view ), "color", &p->clr ); y += (space+18); + return gui_editor_propview_create_eobj_props( view, p, &x, &y, propview_input_width( view ) ); } void gui_editor_propview_create_entprops( GUI_EDITOR_PROPVIEW* view ) { diff --git a/src/editor/properties.h b/src/editor/properties.h index 34ac765..d663a6b 100644 --- a/src/editor/properties.h +++ b/src/editor/properties.h @@ -1,7 +1,6 @@ #pragma once #include "../gamedef.h" -#include <concepts> #if IS_EDITOR #include <math.h> @@ -9,17 +8,46 @@ #define EPROP( _type, name, value, display ) \ _type name = value; \ - EDITOR_PROP name##_prop{ .pdata = &name, .type = eprop_type<_type>(), .displayname = display, .parent = this }; + EDITOR_PROP name##_prop{ &name, eprop_type<_type>(), display, this, 0 } + +#define EPROP_RO( _type, name, value, display ) \ + _type name = value; \ + EDITOR_PROP name##_prop{ &name, eprop_type<_type>(), display, this, 1 } #define EPROP_RANGED( _type, name, value, display, _min, _max ) \ - _type name{ value }; \ - EDITOR_PROP{ \ - .pdata = &name, \ - .type = eprop_type<_type>(), \ - .displayname = display, \ - .parent = this, \ - .min = _min, \ - .max = _max \ + _type name = value; \ + EDITOR_PROP name##_prop{ \ + &name, \ + eprop_type<_type>(), \ + display, \ + this, \ + _min, \ + _max, \ + 0 \ + } + +#define EPROP_STEP( _type, name, value, display, step ) \ + _type name = value; \ + EDITOR_PROP name##_prop{ \ + &name, \ + eprop_type<_type>(), \ + display, \ + step, \ + this, \ + 0 \ + } + +#define EPROP_RANGED_STEP( _type, name, value, display, min, max, step ) \ + _type name = value; \ + EDITOR_PROP name##_prop{ \ + &name, \ + eprop_type<_type>(), \ + display, \ + step, \ + this, \ + min, \ + max, \ + 0 \ } enum EditorPropType_t { @@ -34,15 +62,27 @@ enum EditorPropType_t { EPROP_I64, EPROP_F32, EPROP_F64, + EPROP_VEC2, + EPROP_VEC3, + EPROP_VEC4, + EPROP_CLR, + EPROP_MAPPROP, EPROP_STRING, EPROP_OBJ, EPROP_LIST, + EPROP_TEXTURE, EPROP_TEXTURE_LIST, + EPROP_VERTEX, + EPROP_VERTEX_LIST +}; + +struct EPROP_ENTRY { + U64 offset; }; // editor map object struct EOBJECT { - LIST<struct EDITOR_PROP*> eprops{}; + LIST<EPROP_ENTRY> eprops{}; }; template <typename T> @@ -50,13 +90,89 @@ concept __eobject_base = __is_base_of(EOBJECT, T); // editor object property struct EDITOR_PROP { - void* pdata; + EDITOR_PROP( void* _pdata, U8 _type, STR _displayname, struct EOBJECT* _parent, U8 _readonly = 0 ) { + type = _type; + displayname = _displayname; + min = -INFINITY; + max = INFINITY; + step = 0; + readonly = _readonly; + + U64 _this = (U64)this; + U64 pdata = (U64)_pdata; + U64 parent = (U64)_parent; + U64 offset = _this - parent; + + _parent->eprops.push( { offset } ); + + offset = _this - pdata; + dataoff = offset; + } + + EDITOR_PROP( void* _pdata, U8 _type, STR _displayname, F32 _step, struct EOBJECT* _parent, U8 _readonly = 0 ) { + type = _type; + displayname = _displayname; + min = -INFINITY; + max = INFINITY; + step = _step; + readonly = _readonly; + + U64 _this = (U64)this; + U64 pdata = (U64)_pdata; + U64 parent = (U64)_parent; + U64 offset = _this - parent; + + _parent->eprops.push( { offset } ); + + offset = _this - pdata; + dataoff = offset; + } + + EDITOR_PROP( void* _pdata, U8 _type, STR _displayname, struct EOBJECT* _parent, F32 _min, F32 _max, U8 _readonly = 0 ) { + type = _type; + displayname = _displayname; + min = _min; + max = _max; + step = 0; + readonly = _readonly; + + U64 _this = (U64)this; + U64 pdata = (U64)_pdata; + U64 parent = (U64)_parent; + U64 offset = _this - parent; + + _parent->eprops.push( { offset } ); + + offset = _this - pdata; + dataoff = offset; + } + + EDITOR_PROP( void* _pdata, U8 _type, STR _displayname, F32 _step, struct EOBJECT* _parent, F32 _min, F32 _max, U8 _readonly = 0 ) { + type = _type; + displayname = _displayname; + min = _min; + max = _max; + step = _step; + readonly = _readonly; + + U64 _this = (U64)this; + U64 pdata = (U64)_pdata; + U64 parent = (U64)_parent; + U64 offset = _this - parent; + + _parent->eprops.push( { offset } ); + + offset = _this - pdata; + dataoff = offset; + } + + U64 dataoff; U8 type; STR displayname; F64 min{ -INFINITY }; F64 max{ INFINITY }; - struct EOBJECT* parent; - + F32 step; + U8 readonly; template <typename T> struct __eprop_type { static const U8 type = EPROP_INVALID; @@ -72,11 +188,27 @@ struct EDITOR_PROP { template <> struct __eprop_type<F32> { static const U8 type = EPROP_F32; }; template <> struct __eprop_type<F64> { static const U8 type = EPROP_F64; }; template <> struct __eprop_type<STR> { static const U8 type = EPROP_STRING; }; + template <> struct __eprop_type<struct CLR> { static const U8 type = EPROP_CLR; }; + template <> struct __eprop_type<struct VEC2> { static const U8 type = EPROP_VEC2; }; + template <> struct __eprop_type<struct VEC3> { static const U8 type = EPROP_VEC3; }; + template <> struct __eprop_type<struct VEC4> { static const U8 type = EPROP_VEC4; }; + template <> struct __eprop_type<struct MAP_PROPREF> { static const U8 type = EPROP_MAPPROP; }; + template <> struct __eprop_type<struct GL_TEX2D*> { static const U8 type = EPROP_TEXTURE; }; template <__eobject_base T> struct __eprop_type<T> { static const U8 type = EPROP_OBJ; }; template <typename LT> struct __eprop_type<LIST<LT>> { static const U8 type = EPROP_LIST; }; template <> struct __eprop_type<LIST<struct MAP_TEXTURE_ENTRY*>> { static const U8 type = EPROP_TEXTURE_LIST; }; + template <> struct __eprop_type<struct MAP_VERTEX> { static const U8 type = EPROP_VERTEX; }; + template <> struct __eprop_type<LIST<struct MAP_VERTEX>> { static const U8 type = EPROP_VERTEX_LIST; }; }; +inline EDITOR_PROP* eprop_from_ref( EOBJECT* obj, EPROP_ENTRY e ) { + return (EDITOR_PROP*)( (U64)obj + e.offset ); +} + +inline void* eprop_ptr( EDITOR_PROP* prop ) { + return (void*)( (U64)prop - prop->dataoff); +} + template <typename T> const U8 eprop_type() { return EDITOR_PROP::__eprop_type<T>::type; diff --git a/src/editor/toolview.cpp b/src/editor/toolview.cpp index 25c308d..6bbaa3a 100644 --- a/src/editor/toolview.cpp +++ b/src/editor/toolview.cpp @@ -22,11 +22,11 @@ GUI_EDITOR_TOOLVIEW* gui_editor_toolview_from_item_child( GUI_BASE* child ) { } I32 gui_editor_toolview_visible_h( GUI_EDITOR_TOOLVIEW* view ) { - return std::max( 1, view->h - 4 ); + return max( 1, view->h - 4 ); } I32 gui_editor_toolview_max_scroll( GUI_EDITOR_TOOLVIEW* view ) { - return std::max( 0, view->content_h - gui_editor_toolview_visible_h( view ) ); + return max( 0, view->content_h - gui_editor_toolview_visible_h( view ) ); } void gui_editor_toolview_clamp_scroll( GUI_EDITOR_TOOLVIEW* view ) { @@ -34,7 +34,7 @@ void gui_editor_toolview_clamp_scroll( GUI_EDITOR_TOOLVIEW* view ) { return; I32 max_scroll = gui_editor_toolview_max_scroll( view ); - view->scroll = std::min( std::max( 0, view->scroll ), max_scroll ); + view->scroll = min( max( 0, view->scroll ), max_scroll ); if( view->itemview ) { view->itemview->y = TOOLVIEW_TITLE_OFFSET - view->scroll; } @@ -417,17 +417,17 @@ void gui_editor_toolview_draw_scrollbar( GUI_EDITOR_TOOLVIEW* view, I32 x, I32 y I32 track_x = x + view->w - TOOLVIEW_SCROLLBAR_W - 3; I32 track_y = y + 2; - I32 track_h = std::max( 8, h - 4 ); + I32 track_h = max( 8, h - 4 ); gui_draw_frect( track_x, track_y, TOOLVIEW_SCROLLBAR_W, track_h, ui_clr.bg_alt ); gui_draw_rect( track_x, track_y, TOOLVIEW_SCROLLBAR_W, track_h, ui_clr.border ); I32 visible_h = gui_editor_toolview_visible_h( view ); - I32 thumb_h = std::max( TOOLVIEW_SCROLLBAR_MIN_H, ( track_h * visible_h ) / std::max( 1, view->content_h ) ); - thumb_h = std::min( thumb_h, track_h ); - I32 travel = std::max( 1, track_h - thumb_h ); - I32 thumb_y = track_y + ( travel * view->scroll ) / std::max( 1, max_scroll ); + I32 thumb_h = max( TOOLVIEW_SCROLLBAR_MIN_H, ( track_h * visible_h ) / max( 1, view->content_h ) ); + thumb_h = min( thumb_h, track_h ); + I32 travel = max( 1, track_h - thumb_h ); + I32 thumb_y = track_y + ( travel * view->scroll ) / max( 1, max_scroll ); - gui_draw_frect( track_x + 1, thumb_y + 1, TOOLVIEW_SCROLLBAR_W - 2, std::max( 1, thumb_h - 2 ), ui_clr.txt ); + gui_draw_frect( track_x + 1, thumb_y + 1, TOOLVIEW_SCROLLBAR_W - 2, max( 1, thumb_h - 2 ), ui_clr.txt ); } void gui_editor_toolview_draw_fn( void* ptr ) { @@ -453,7 +453,7 @@ void gui_editor_toolview_draw_fn( void* ptr ) { if( max_scroll > 0 ) clip_w -= TOOLVIEW_SCROLLBAR_W + 2; - gui_draw_push_clip( x + 2, y + 2, std::max( 1, clip_w ), std::max( 1, h - 4 ) ); + gui_draw_push_clip( x + 2, y + 2, max( 1, clip_w ), max( 1, h - 4 ) ); view->itemview->draw_fn( view->itemview ); gui_draw_pop_clip(); gui_editor_toolview_draw_scrollbar( view, x, y, h ); diff --git a/src/game/world/map.cpp b/src/game/world/map.cpp index a44f191..7b8060b 100644 --- a/src/game/world/map.cpp +++ b/src/game/world/map.cpp @@ -1,4 +1,4 @@ -#include <cfloat> +#include <float.h> #include "map.h" #include "../../game.h" @@ -83,7 +83,7 @@ STAT map_polygon_verts_from_section( WORLD_MAP* m, MAP_POLYGON* p, CFG_SECTION* sprintf( vertsec, "%d", i ); CFG_SECTION* v = cfg_section( vertices, vertsec ); if( !v ) { - dlog( "map_polygon_verts_from_section() : missing vertex %d in polygon with propid %d in map %s\n", i, p->propid, m->name ); + dlog( "map_polygon_verts_from_section() : missing vertex %d in polygon with propid %d in map %s\n", i, p->propid.id, m->name.data ); continue; } @@ -92,7 +92,7 @@ STAT map_polygon_verts_from_section( WORLD_MAP* m, MAP_POLYGON* p, CFG_SECTION* CFG_CLR* clr = cfg_clr( v, "clr" ); if( !pos ) { - dlog( "map_polygon_verts_from_section() : missing pos for vertex %d in polygon with propid %d in map %s\n", i, p->propid, m->name ); + dlog( "map_polygon_verts_from_section() : missing pos for vertex %d in polygon with propid %d in map %s\n", i, p->propid.id, m->name.data ); return STAT_ERR; } @@ -104,7 +104,7 @@ STAT map_polygon_verts_from_section( WORLD_MAP* m, MAP_POLYGON* p, CFG_SECTION* } if( !p->vertices.size ) { - dlog( "map_polygon_verts_from_section() : invalid vertex count for polygon with propid %d in map %s\n", p->propid, m->name ); + dlog( "map_polygon_verts_from_section() : invalid vertex count for polygon with propid %d in map %s\n", p->propid.id, m->name.data ); return STAT_ERR; } @@ -126,7 +126,7 @@ void map_polygon_calc_bounds( MAP_POLYGON* p ) { STAT map_polygons_from_section( WORLD_MAP* m, GAME_DATA* g, CFG_SECTION* polygons, U32 polyc ) { if( !polyc ) { - dlog( "map_polygons_from_section() : no polygons in %s\n", m->name ); + dlog( "map_polygons_from_section() : no polygons in %s\n", m->name.data ); return STAT_OK; } @@ -138,20 +138,20 @@ STAT map_polygons_from_section( WORLD_MAP* m, GAME_DATA* g, CFG_SECTION* polygon sprintf( polysec, "%d", i ); CFG_SECTION* p = cfg_section( polygons, polysec ); if( !p ) { - dlog( "map_polygons_from_section() : missing polygon %d in %s\n", i, m->name ); + dlog( "map_polygons_from_section() : missing polygon %d in %s\n", i, m->name.data ); continue; } CFG_INT* propid = cfg_int( p, "propid" ); if( !propid ) { - dlog( "map_polygons_from_section() : missing propid for polygon %d in map %s\n", i, m->name ); + dlog( "map_polygons_from_section() : missing propid for polygon %d in map %s\n", i, m->name.data ); continue; } poly.propid = propid->value; CFG_INT* polytype = cfg_int( p, "type" ); if( !polytype ) { - dlog( "map_polygons_from_section() : missing polygon type for polygon %d in %s\n", i, m->name ); + dlog( "map_polygons_from_section() : missing polygon type for polygon %d in %s\n", i, m->name.data ); continue; } @@ -159,13 +159,13 @@ STAT map_polygons_from_section( WORLD_MAP* m, GAME_DATA* g, CFG_SECTION* polygon CFG_INT* vertc = cfg_int( p, "vertcount" ); if( !vertc || !vertc->value ) { - dlog( "map_polygons_from_section() : missing vertex count for polygon %d in %s\n", i, m->name ); + dlog( "map_polygons_from_section() : missing vertex count for polygon %d in %s\n", i, m->name.data ); continue; } CFG_SECTION* vertices = cfg_section( p, "vertices" ); if( !vertices ) { - dlog( "map_polygons_from_section() : missing vertices for polygon %d in %s", i, m->name ); + dlog( "map_polygons_from_section() : missing vertices for polygon %d in %s", i, m->name.data ); continue; } @@ -182,7 +182,7 @@ STAT map_polygons_from_section( WORLD_MAP* m, GAME_DATA* g, CFG_SECTION* polygon STAT map_walls_from_section( WORLD_MAP* m, GAME_DATA* g, CFG_SECTION* walls, U32 wallc ) { if( !wallc ) { - dlog( "map_walls_from_section() : no walls in %s\n", m->name ); + dlog( "map_walls_from_section() : no walls in %s\n", m->name.data ); return STAT_OK; } @@ -194,7 +194,7 @@ STAT map_walls_from_section( WORLD_MAP* m, GAME_DATA* g, CFG_SECTION* walls, U32 sprintf( wallsec, "%d", i ); CFG_SECTION* w = cfg_section( walls, wallsec ); if( !w ) { - dlog( "map_walls_from_section() : missing wall %d in %s\n", i, m->name ); + dlog( "map_walls_from_section() : missing wall %d in %s\n", i, m->name.data ); continue; } @@ -203,7 +203,7 @@ STAT map_walls_from_section( WORLD_MAP* m, GAME_DATA* g, CFG_SECTION* walls, U32 CFG_INT* prop = cfg_int( w, "propid" ); if( !start || !end || !prop ) { - dlog( "map_walls_from_section() : bad wall definition in %s idx %d [%p %p %p]\n", m->name, i, start, end, prop ); + dlog( "map_walls_from_section() : bad wall definition in %s idx %d [%p %p %p]\n", m->name.data, i, start, end, prop ); continue; } @@ -221,7 +221,7 @@ STAT map_walls_from_section( WORLD_MAP* m, GAME_DATA* g, CFG_SECTION* walls, U32 STAT map_props_from_section( WORLD_MAP* m, GAME_DATA* g, CFG_SECTION* props, U32 propc ) { if( !propc ) { - dlog( "map_props_from_section() : no props in %s\n", m->name ); + dlog( "map_props_from_section() : no props in %s\n", m->name.data ); return STAT_ERR; } @@ -233,7 +233,7 @@ STAT map_props_from_section( WORLD_MAP* m, GAME_DATA* g, CFG_SECTION* props, U32 sprintf( propsec, "%d", i ); CFG_SECTION* p = cfg_section( props, propsec ); if( !p ) { - dlog( "map_props_from_section() : missing prop %d in %s\n", i, m->name ); + dlog( "map_props_from_section() : missing prop %d in %s\n", i, m->name.data ); continue; } @@ -261,7 +261,7 @@ STAT map_props_from_section( WORLD_MAP* m, GAME_DATA* g, CFG_SECTION* props, U32 STAT map_sprites_from_section( WORLD_MAP* m, GAME_DATA* g, CFG_SECTION* sprites, U32 spritec ) { if( !spritec ) { - dlog( "map_sprites_from_section() : no sprites in %s\n", m->name ); + dlog( "map_sprites_from_section() : no sprites in %s\n", m->name.data ); return STAT_OK; } @@ -273,7 +273,7 @@ STAT map_sprites_from_section( WORLD_MAP* m, GAME_DATA* g, CFG_SECTION* sprites, sprintf( spritesec, "%d", i ); CFG_SECTION* s = cfg_section( sprites, spritesec ); if( !s ) { - dlog( "map_sprites_from_section() : missing sprite %d in %s\n", i, m->name ); + dlog( "map_sprites_from_section() : missing sprite %d in %s\n", i, m->name.data ); continue; } @@ -283,7 +283,7 @@ STAT map_sprites_from_section( WORLD_MAP* m, GAME_DATA* g, CFG_SECTION* sprites, CFG_VEC2* size = cfg_vec2( s, "size" ); if( !tex || !pos || !size ) { - dlog( "map_sprites_from_section() : invalid sprite %d in %s\n", i, m->name ); + dlog( "map_sprites_from_section() : invalid sprite %d in %s\n", i, m->name.data ); continue; } @@ -305,7 +305,7 @@ STAT map_sprites_from_section( WORLD_MAP* m, GAME_DATA* g, CFG_SECTION* sprites, STAT map_entities_from_section( WORLD_MAP* m, GAME_DATA*, CFG_SECTION* entities, U32 entityc ) { if( !entityc ) { - dlog( "map_entities_from_section() : no entities in %s\n", m->name ); + dlog( "map_entities_from_section() : no entities in %s\n", m->name.data ); return STAT_OK; } @@ -317,14 +317,14 @@ STAT map_entities_from_section( WORLD_MAP* m, GAME_DATA*, CFG_SECTION* entities, sprintf( entitysec, "%d", i ); CFG_SECTION* s = cfg_section( entities, entitysec ); if( !s ) { - dlog( "map_entities_from_section() : missing entity %d in %s\n", i, m->name ); + dlog( "map_entities_from_section() : missing entity %d in %s\n", i, m->name.data ); continue; } CFG_INT* classid = cfg_int( s, "classid" ); CFG_VEC3* pos = cfg_vec3( s, "pos" ); if( !classid || !pos ) { - dlog( "map_entities_from_section() : invalid entity %d in %s\n", i, m->name ); + dlog( "map_entities_from_section() : invalid entity %d in %s\n", i, m->name.data ); continue; } @@ -380,24 +380,24 @@ void map_gen_skybox( WORLD_MAP* m ) { VEC3 maxs = m->maxs + VEC3( SKYBOX_OFFSET, SKYBOX_OFFSET, SKYBOX_OFFSET ); m->skybox.walls[0] = { + .propid = MAPPROP_SKYBOX, .start = { mins.x, mins.y, mins.z }, .end = { maxs.x, mins.y, maxs.z - mins.z }, - .propid = MAPPROP_SKYBOX }; m->skybox.walls[1] = { + .propid = MAPPROP_SKYBOX, .start = { maxs.x, mins.y, mins.z }, .end = { maxs.x, maxs.y, maxs.z - mins.z }, - .propid = MAPPROP_SKYBOX }; m->skybox.walls[2] = { + .propid = MAPPROP_SKYBOX, .start = { maxs.x, maxs.y, mins.z }, .end = { mins.x, maxs.y, maxs.z - mins.z }, - .propid = MAPPROP_SKYBOX }; m->skybox.walls[3] = { + .propid = MAPPROP_SKYBOX, .start = { mins.x, maxs.y, mins.z }, .end = { mins.x, mins.y, maxs.z - mins.z }, - .propid = MAPPROP_SKYBOX }; VEC2 floor[] = { @@ -496,7 +496,7 @@ WORLD_MAP* map_from_file( GAME_DATA* game, const char* path ) { WORLD_MAP* m = new WORLD_MAP; const char* name = file_path_last_of( path ); - strcpy( m->name, name ); + m->name = name; CFG_SECTION* s = cfg_section( root, "map" ); if( !s ) { dlog( errstr, "map", path ); delete m; return 0; } diff --git a/src/game/world/map.h b/src/game/world/map.h index 2b8a7a5..21bfa1f 100644 --- a/src/game/world/map.h +++ b/src/game/world/map.h @@ -6,23 +6,22 @@ #include "../../util/fnv.h" #include "../../editor/properties.h" -#include <string.h> - enum MapPropId_t { MAPPROP_SKYBOX = -1, MAPPROP_CLIPBRUSH = -2, }; struct SURF_PROPS : public EOBJECT { - struct GL_TEX2D* tex; - CLR clr; + EPROP( GL_TEX2D*, tex, {}, "texture" ); + EPROP( CLR, clr, {}, "color" ); }; struct MAP_VERTEX : public EOBJECT { - VEC3 pos; - VEC3 normal; - VEC2 uv; - CLR clr; + EPROP( VEC3, pos, {}, "position" ); + EPROP_RANGED_STEP( VEC2, uv, {}, "uv", 0.f, 1.f, 0.025f ); + EPROP( CLR, clr, {}, "color" ); + + EPROP_RO( VEC3, normal, {}, "normal" ); }; enum MapPolygonType_t { @@ -30,23 +29,33 @@ enum MapPolygonType_t { MPT_CEILING }; +struct MAP_PROPREF { + operator I32&() { return id; } + operator I32() const { return id; } + + MAP_PROPREF() {} + MAP_PROPREF( U32 id ) : id( id ) {} + + I32 id; +}; + struct MAP_POLYGON : public EOBJECT { - LIST<MAP_VERTEX> vertices; + EPROP( MAP_PROPREF, propid, {}, "prop id" ); + EPROP( LIST<MAP_VERTEX>, vertices, {}, "vertices" ); - VEC3 mins; - VEC3 maxs; + EPROP_RO( VEC3, mins, {}, "mins" ); + EPROP_RO( VEC3, maxs, {}, "maxs" ); U8 type; - I32 propid; }; struct MAP_WALL : public EOBJECT { - VEC3 start; - VEC3 end; + EPROP( MAP_PROPREF, propid, {}, "prop id" ); - VEC2 uvstart; - VEC2 uvend; + EPROP( VEC3, start, {}, "start pos" ); + EPROP( VEC3, end, {}, "end pos" ); - I32 propid; + EPROP_RANGED_STEP( VEC2, uvstart, {}, "uv start offset", 0.f, 1.f, 0.025f ); + EPROP_RANGED_STEP( VEC2, uvend, {}, "uv end offset", 0.f, 1.f, 0.025f ); }; struct MAP_TEXTURE_ENTRY { @@ -56,40 +65,42 @@ struct MAP_TEXTURE_ENTRY { }; struct MAP_SPRITE : public EOBJECT { - VEC3 pos; - VEC2 size; - CLR clr; - GL_TEX2D* tex; + EPROP( GL_TEX2D*, tex, {}, "texture" ); + EPROP( VEC3, pos, {}, "position" ); + EPROP_RANGED( VEC2, size, {}, "size", 0.25f, INFINITY ); + EPROP( CLR, clr, {}, "color" ); }; -struct MAP_ENTITY { - VEC3 pos; - U32 classid; - LIST<struct OBJECT_PROP*> props; +struct MAP_ENTITY : public EOBJECT { + EPROP( VEC3, pos, {}, "position" ); + EPROP( U32, classid, {}, "entity class" ); + + EPROP( LIST<struct OBJECT_PROP*>, props, {}, "entity properties" ); }; struct MAP_SKYBOX : public EOBJECT { - SURF_PROPS props; + EPROP( SURF_PROPS, props, {}, "skybox surface properties" ); MAP_WALL walls[4]; MAP_POLYGON polygons[2]; }; struct WORLD_MAP : public EOBJECT { - LIST<MAP_WALL> walls; - LIST<MAP_POLYGON> polygons; - LIST<MAP_SPRITE> sprites; - LIST<MAP_ENTITY> entities; - LIST<SURF_PROPS> props; - MAP_SKYBOX skybox; + EPROP_RO( STR, name, {}, "name" ); + EPROP( VEC3, startpos, {}, "spawn position" ); + EPROP( F32, startang, {}, "spawn angle" ); + + EPROP( LIST<MAP_WALL> , walls, {}, "walls" ); + EPROP( LIST<MAP_POLYGON>, polygons, {}, "polygons" ); + EPROP( LIST<MAP_SPRITE> , sprites, {}, "sprites" ); + EPROP( LIST<MAP_ENTITY> , entities, {}, "entities" ); + EPROP( LIST<SURF_PROPS> , props, {}, "surface properties" ); + + EPROP( MAP_SKYBOX, skybox, {}, "skybox" ); F32 w; F32 h; - VEC3 mins; - VEC3 maxs; - char name[256]; - - VEC3 startpos; - F32 startang; + EPROP_RO( VEC3, mins, {}, "mins" ); + EPROP_RO( VEC3, maxs, {}, "maxs" ); struct BSP* bsp{}; diff --git a/src/gui/base.h b/src/gui/base.h index e62c66a..293de74 100644 --- a/src/gui/base.h +++ b/src/gui/base.h @@ -1,6 +1,5 @@ #pragma once #include "../render/gl_2d.h" -#include <functional> // ======================================= [ colorscheme ] ======================================== @@ -46,7 +45,7 @@ extern U8 gui_is_fg_window( struct GUI_BASE* node ); // 1 if pa // ======================================= [ components ] ========================================= -using GUI_CALLBACK = std::function<void( void* )>; +using GUI_CALLBACK = FN<void( void* )>; struct GUI_LIST_ENTRY { I32 val; char title[256]; @@ -129,6 +128,8 @@ extern void gui_base_input_fn( void* ); extern void gui_view_draw_fn( void* ); struct GUI_BASE { + virtual ~GUI_BASE() = default; + I32 x{}, y{}; I32 w{}, h{}; U8 enabled{1}; diff --git a/src/util/allocator.h b/src/util/allocator.h index 327dfc1..623d227 100644 --- a/src/util/allocator.h +++ b/src/util/allocator.h @@ -2,8 +2,7 @@ #include <stdlib.h> #include <string.h> -#include <functional> -#include "typedef.h" +#include "callback.h" template <typename T> struct LIST_ITERATOR { @@ -19,7 +18,7 @@ struct LIST_ITERATOR { }; template <typename T> -using QSORT_FN = std::function< U8( T*, T* ) >; +using QSORT_FN = FN< U8( T*, T* ) >; template <typename T> static U8 qsort_basic_sort( T* t1, T* t2 ) { @@ -58,8 +57,8 @@ struct LIST { U32 capacity; U32 size; - using ON_EACH_FN = std::function< void(T*) >; - using ON_SEARCH_FN = std::function< bool(T*) >; + using ON_EACH_FN = FN< void(T*) >; + using ON_SEARCH_FN = FN< U8(T*) >; LIST() { data = (T*)malloc( sizeof( T ) ); @@ -265,6 +264,8 @@ struct LIST { } T ret = data[--size]; + if constexpr( !__is_trivially_destructible(T) ) + data[size].~T(); if( size < capacity / 4 ) shrink(); diff --git a/src/util/callback.h b/src/util/callback.h new file mode 100644 index 0000000..a2c9477 --- /dev/null +++ b/src/util/callback.h @@ -0,0 +1,84 @@ +#pragma once +#include "typedef.h" + +template <typename T> +struct FN; +// voodoo +template <typename RET, typename... ARGS> +struct FN<RET(ARGS...)> { + template <typename T> struct __strip_ref { using type = T; }; + template <typename T> struct __strip_ref<T&> { using type = T; }; + template <typename T> struct __strip_ref<T&&> { using type = T; }; + template <typename R, typename... A> struct __strip_ref<R(A...)> { using type = R(*)(A...); }; + template <typename R, typename... A> struct __strip_ref<R(&)(A...)> { using type = R(*)(A...); }; + + static const unsigned int BUF_SIZE = 32; + + alignas(8) char buf[BUF_SIZE]; + void* data; + RET( *invoke )( void*, ARGS... ); + void( *destroy )( void* ); + void*( *clone )( void*, char* ); + + template <typename F> + FN(F&& f) { + using __stripped = typename __strip_ref<F>::type; + + if constexpr( sizeof(__stripped) <= BUF_SIZE ) { + new (buf) __stripped( f ); + data = buf; + destroy = pfn( void* d ) { + ( (__stripped*)d )->~__stripped(); + }; + clone = pfn( void* d, char* dst ) -> void* { + new (dst) __stripped( *(__stripped*)d ); + return dst; + }; + } else { + data = new __stripped( f ); + destroy = pfn( void* d ) { + delete (__stripped*)d; + }; + clone = pfn( void* d, char* dst ) -> void* { + return new __stripped( *(__stripped*)d ); + }; + } + + invoke = pfn( void* d, ARGS... args ) -> RET { + return ( *(__stripped*)d )( args... ); + }; + } + + FN( I32&& ) : data( 0 ), invoke( 0 ), destroy( 0 ), clone( 0 ) {} + FN( U32&& ) : data( 0 ), invoke( 0 ), destroy( 0 ), clone( 0 ) {} + FN() : data( 0 ), invoke( 0 ), destroy( 0 ), clone( 0 ) {} + + FN( const FN& other ) : invoke( other.invoke ), destroy( other.destroy ), clone( other.clone ) { + if( !other.data ) { + data = 0; + return; + } + + data = other.clone( other.data, buf ); + } + + FN& operator=( const FN& other ) { + if( this == &other ) return *this; + if( destroy && data ) destroy( data ); + invoke = other.invoke; + destroy = other.destroy; + clone = other.clone; + data = other.data ? other.clone( other.data, buf ) : 0; + return *this; + } + + ~FN() { + if( destroy && data ) destroy( data ); + } + + RET operator()( ARGS... args ) const { + return invoke( data, args... ); + } + + operator bool() const { return !!invoke; } +}; diff --git a/src/util/color.h b/src/util/color.h index 526cddc..8b1a259 100644 --- a/src/util/color.h +++ b/src/util/color.h @@ -1,5 +1,5 @@ #pragma once -#include "typedef.h" +#include "string.h" #include <math.h> struct CLR { @@ -166,3 +166,5 @@ struct CLR { return *this; } }; + +inline STR to_str( CLR c ) { return STR( "%.02f %.02f %.02f %.02f", c.r, c.g, c.b, c.a ); } diff --git a/src/util/config.h b/src/util/config.h index 7973db0..d8c1c2e 100644 --- a/src/util/config.h +++ b/src/util/config.h @@ -1,7 +1,7 @@ #pragma once #include <stdio.h> -#include "allocator.h" +#include "string.h" #include "vector.h" #include "color.h" @@ -26,8 +26,8 @@ enum CfgNodeType_t { // ===================================== [ definitions ] =========================================== -using CFG_PARSEFN = std::function<void( CFG_PARSER*, CFG_SECTION*, char* )>; -using CFG_SERIALIZEFN = std::function<void( CFG_SERIALIZER*, CFG_NODE*, char* )>; +using CFG_PARSEFN = FN<STAT( CFG_PARSER*, CFG_SECTION*, char* )>; +using CFG_SERIALIZEFN = FN<STR( CFG_SERIALIZER*, CFG_NODE*)>; struct CFG_TYPE { U8 type; @@ -37,7 +37,7 @@ struct CFG_TYPE { }; struct CFG_NODE { - char name[64]; + STR name; CFG_NODE* parent; U8 type; }; @@ -66,14 +66,14 @@ extern STAT cfg_parser_clr( CFG_PARSER* parser, CFG_SECTION* section, char* name // ====================================== [ serializers ] ========================================== -extern void cfg_serialize_section( CFG_SERIALIZER* serializer, CFG_NODE* section, char* buf ); -extern void cfg_serialize_bytes( CFG_SERIALIZER* serializer, CFG_NODE* node, char* buf ); -extern void cfg_serialize_str( CFG_SERIALIZER* serializer, CFG_NODE* node, char* buf ); -extern void cfg_serialize_float( CFG_SERIALIZER* serializer, CFG_NODE* node, char* buf ); -extern void cfg_serialize_int( CFG_SERIALIZER* serializer, CFG_NODE* node, char* buf ); -extern void cfg_serialize_vec2( CFG_SERIALIZER* serializer, CFG_NODE* node, char* buf ); -extern void cfg_serialize_vec3( CFG_SERIALIZER* serializer, CFG_NODE* node, char* buf ); -extern void cfg_serialize_clr( CFG_SERIALIZER* serializer, CFG_NODE* node, char* buf ); +extern STR cfg_serialize_section( CFG_SERIALIZER* serializer, CFG_NODE* section ); +extern STR cfg_serialize_bytes( CFG_SERIALIZER* serializer, CFG_NODE* node ); +extern STR cfg_serialize_str( CFG_SERIALIZER* serializer, CFG_NODE* node ); +extern STR cfg_serialize_float( CFG_SERIALIZER* serializer, CFG_NODE* node ); +extern STR cfg_serialize_int( CFG_SERIALIZER* serializer, CFG_NODE* node ); +extern STR cfg_serialize_vec2( CFG_SERIALIZER* serializer, CFG_NODE* node ); +extern STR cfg_serialize_vec3( CFG_SERIALIZER* serializer, CFG_NODE* node ); +extern STR cfg_serialize_clr( CFG_SERIALIZER* serializer, CFG_NODE* node ); // ========================================= [ config ] ============================================ @@ -158,6 +158,7 @@ static void cfg_free( CFG_NODE* n ) { else if( n->type == CFGT_SECTION ) { CFG_SECTION* s = (CFG_SECTION*)n; s->children.each( fn( CFG_NODE** child ) { cfg_free( *child ); } ); + return delete s; } delete n; diff --git a/src/util/config/config.cpp b/src/util/config/config.cpp index a41e455..00a2512 100644 --- a/src/util/config/config.cpp +++ b/src/util/config/config.cpp @@ -30,9 +30,7 @@ inline void trim_whitespace( char* buf ) { } inline void init_cfg_node( CFG_NODE* node, const char* name, CFG_NODE* parent, U8 type ) { - memset( node->name, 0, sizeof(node->name) ); - strcpy( node->name, name ); - node->name[sizeof(node->name) - 1] = '\0'; + node->name = name; node->parent = parent; if( parent ) ( (CFG_SECTION*)parent )->children.push( node ); @@ -290,17 +288,12 @@ STAT cfg_save( CFG_SECTION* root, const char* path ) { if( !f ) return STAT_ERR; - char* buf = (char*)malloc( 999999 ); - buf[0] = 0; CFG_SERIALIZER s; s.tabc = 0; s.f = f; - cfg_serialize_section( &s, (CFG_NODE*)root, buf ); - U32 len = strlen( buf ); - - fwrite( buf, 1, len, f ); - free( buf ); + STR buf = cfg_serialize_section( &s, (CFG_NODE*)root ); + fwrite( buf, 1, buf.size, f ); fclose( f ); return STAT_OK; diff --git a/src/util/config/serializers.cpp b/src/util/config/serializers.cpp index 01f416c..15ddae0 100644 --- a/src/util/config/serializers.cpp +++ b/src/util/config/serializers.cpp @@ -1,109 +1,122 @@ -#include <cstdarg> -#include <cstdio> - #include "../config.h" -void serialize_node( CFG_SERIALIZER* s, CFG_NODE* n, char* buf ) { - U32 len = strlen( buf ); - for( U32 i = 0; i < s->tabc * 2; ++i ) buf[i + len] = ' '; - buf[len + s->tabc * 2] = 0; - sprintf( buf, "%s%s %s", buf, cfg_types[n->type].def, n->name ); +STR serialize_node( CFG_SERIALIZER* s, CFG_NODE* n ) { + STR ret{}; + for( U32 i = 0; i < s->tabc * 2; ++i ) ret.append( " " ); + ret.fmt( "%s %s", cfg_types[n->type].def, n->name.data ); + + return ret; } -void cfg_serialize_section( CFG_SERIALIZER* s, CFG_NODE *n, char *buf ) { +STR cfg_serialize_section( CFG_SERIALIZER* s, CFG_NODE *n ) { CFG_SECTION* sec = (CFG_SECTION*)n; + STR buf; if( sec->parent ) { - serialize_node( s, n, buf ); - strcat( buf, " {\n" ); + buf += serialize_node( s, n ); + buf += " {\n"; s->tabc++; } - char line[8192]; for( U32 i = 0; i < sec->children.size; ++i ) { - line[0] = 0; CFG_NODE* c = sec->children[i]; if( c->type == CFGT_SECTION ) { - cfg_serialize_section( s, c, buf ); + buf += cfg_serialize_section( s, c ); continue; } - cfg_types[c->type].serializer( s, c, line ); - strcat( buf, line ); - strcat( buf, "\n" ); + buf += cfg_types[c->type].serializer( s, c ); + buf += "\n"; } if( sec->parent ) { s->tabc--; - char tabbuf[512] = { 0 }; - for( U32 i = 0 ; i < s->tabc * 2; ++i ) - tabbuf[i] = ' '; - tabbuf[s->tabc * 2] = 0; - strcat( buf, tabbuf ); - strcat( buf, "}" ); + for( U32 i = 0 ; i < s->tabc * 2; ++i ) buf += ' '; + buf += "}"; if( sec->parent ) - strcat( buf, "\n" ); + buf += "\n"; } + + return buf; } -void cfg_serialize_bytes( CFG_SERIALIZER* s, CFG_NODE* n, char* buf ) { +STR cfg_serialize_bytes( CFG_SERIALIZER* s, CFG_NODE* n ) { CFG_BYTES* b = (CFG_BYTES*)n; U32 size = b->size; U8* bytes = b->bytes; - serialize_node( s, n, buf ); - sprintf( buf, "%s[%d] = \"", buf, size ); - U32 len = strlen( buf ); + STR buf{}; + + buf += serialize_node( s, n ); + buf.fmt( "[%d] = \"", size ); for( U32 i = 0; i < size; ++i ) { - sprintf( buf + len + i * 2, "%02X", bytes[i] ); + buf.fmt( "%02X", bytes[i] ); } - - sprintf( buf, "%s%s", buf, "\";" ); + buf += "\";"; + return buf; } -void cfg_serialize_str( CFG_SERIALIZER* s, CFG_NODE* n, char *buf ) { +STR cfg_serialize_str( CFG_SERIALIZER* s, CFG_NODE* n ) { CFG_STR* sn = (CFG_STR*)n; char* str = sn->str; - serialize_node( s, n, buf ); - sprintf( buf, "%s[%d] = \"%s\";", buf, sn->len, str ); + STR buf{}; + + buf += serialize_node( s, n ); + buf.fmt( "[%d] = \"%s\";", sn->len, str ); + return buf; } -void cfg_serialize_int( CFG_SERIALIZER* s, CFG_NODE* n, char *buf ) { - CFG_INT* i = (CFG_INT*)n; - I32 ival = i->value; +STR cfg_serialize_int( CFG_SERIALIZER* s, CFG_NODE* n ) { + CFG_INT* i = (CFG_INT*)n; + I32 ival = i->value; - serialize_node( s, n, buf ); - sprintf( buf, "%s = %d;", buf, ival ); + STR buf{}; + + buf += serialize_node( s, n ); + buf.fmt( " = %d;", ival ); + return buf; } -void cfg_serialize_float( CFG_SERIALIZER* s, CFG_NODE* n, char *buf ) { +STR cfg_serialize_float( CFG_SERIALIZER* s, CFG_NODE* n ) { CFG_FLOAT* f = (CFG_FLOAT*)n; F32 fval = f->value; - serialize_node( s, n, buf ); - sprintf( buf, "%s = %g;", buf, fval ); + STR buf{}; + + buf += serialize_node( s, n ); + buf.fmt( " = %g;", fval ); + return buf; } -void cfg_serialize_vec2( CFG_SERIALIZER* s, CFG_NODE* n, char *buf ) { +STR cfg_serialize_vec2( CFG_SERIALIZER* s, CFG_NODE* n ) { CFG_VEC2* v = (CFG_VEC2*)n; VEC2 val = v->value; - serialize_node( s, n, buf ); - sprintf( buf, "%s = { %g, %g };", buf, val.x, val.y ); + STR buf{}; + + buf += serialize_node( s, n ); + buf.fmt( " = { %g, %g };", val.x, val.y ); + return buf; } -void cfg_serialize_vec3( CFG_SERIALIZER* s, CFG_NODE* n, char *buf ) { +STR cfg_serialize_vec3( CFG_SERIALIZER* s, CFG_NODE* n ) { CFG_VEC3* v = (CFG_VEC3*)n; VEC3 val = v->value; - serialize_node( s, n, buf ); - sprintf( buf, "%s = { %g, %g, %g };", buf, val.x, val.y, val.z ); + STR buf{}; + + buf += serialize_node( s, n ); + buf.fmt( " = { %g, %g, %g };", val.x, val.y, val.z ); + return buf; } -void cfg_serialize_clr( CFG_SERIALIZER* s, CFG_NODE* n, char *buf ) { +STR cfg_serialize_clr( CFG_SERIALIZER* s, CFG_NODE* n ) { CFG_CLR* v = (CFG_CLR*)n; CLR val = v->value; - serialize_node( s, n, buf ); - sprintf( buf, "%s = { %g, %g, %g, %g };", buf, val.r, val.g, val.b, val.a ); + STR buf{}; + + buf += serialize_node( s, n ); + buf.fmt( " = { %g, %g, %g, %g };", val.r, val.g, val.b, val.a ); + return buf; } diff --git a/src/util/file.h b/src/util/file.h index 7e4d413..4309e62 100644 --- a/src/util/file.h +++ b/src/util/file.h @@ -1,7 +1,7 @@ #pragma once -#include <cstdlib> -#include <cstring> +#include <stdlib.h> +#include <string.h> #include <stdio.h> #include <dirent.h> #include <sys/stat.h> diff --git a/src/util/input.h b/src/util/input.h index 1317f94..af5e258 100644 --- a/src/util/input.h +++ b/src/util/input.h @@ -1,7 +1,6 @@ #pragma once #include <SDL_events.h> -#include <functional> #include "vector.h" #include "allocator.h" @@ -33,7 +32,7 @@ struct INPUT_KEYBINDS { U8 crouch = SDL_SCANCODE_LCTRL; }; -using ON_INPUT_FN = std::function<void( SDL_Event* )>; +using ON_INPUT_FN = FN<void( SDL_Event* )>; struct INPUT_DATA { MOUSE_DATA mouse; diff --git a/src/util/str_tokenizer.h b/src/util/str_tokenizer.h new file mode 100644 index 0000000..8a3aebf --- /dev/null +++ b/src/util/str_tokenizer.h @@ -0,0 +1,140 @@ +#pragma once + +#include "string.h" + +using TOKENIZER_COMPARE_FN = FN<U8( char )>; + +struct STR_TOKENIZER { + STR str; + STR ignored; + + I32 cur; + I32 last; +}; + +inline STR_TOKENIZER tok_init( STR str, STR whitespace_chars = " \t\n\r" ) { + return { + .str = str, + .ignored = { whitespace_chars }, + .cur = 0, + .last = 0, + }; +} + +inline STR tok_next( STR_TOKENIZER* t ) { + if( t->cur >= t->str.size ) + return ""; + + U8 start = 0; + for( I32 i = t->cur; i < t->str.size; i++ ) { + U8 c = t->str.data[i]; + if( i == t->str.size - 1 ) { + if( !start ) + return ""; + + STR ret = { (U32)i - t->cur + 1, t->str.data + t->cur }; + t->last = t->cur; + t->cur = i + 1; + return ret; + } + + for( auto& it : t->ignored ) { + if( c == it ) { + if( !start ) { + t->cur = i + 1; + continue; + } else { + STR ret = { (U32)i - t->cur, t->str.data + t->cur }; + t->last = t->cur; + t->cur = i + 1; + return ret; + } + } + } + + start = 1; + } + + return ""; +} + +inline STR tok_peek( STR_TOKENIZER* t ) { + if( t->cur >= t->str.size ) + return ""; + + U8 start = 0; + I32 cur = t->cur; + for( I32 i = cur; i < t->str.size; i++ ) { + U8 c = t->str.data[i]; + if( i == t->str.size - 1 ) { + if( !start ) + return ""; + + STR ret = { (U32)i - cur + 1, t->str.data + cur }; + return ret; + } + + for( auto& it : t->ignored ) { + if( c == it ) { + if( !start ) { + cur = i + 1; + continue; + } else { + STR ret = { (U32)i - cur, t->str.data + cur }; + return ret; + } + } + } + + start = 1; + } + + return ""; +} + + +inline STR tok_next( STR_TOKENIZER* t, STR what ) { + if( t->cur >= t->str.size ) + return ""; + + if( !what.size ) + return ""; + + for( I32 i = t->cur; i <= t->str.size - what.size; i++ ) { + STR slice = { what.size, t->str.data + i }; + if( slice == what ) { + STR ret = { (U32)i - t->cur, t->str.data + i + what.size }; + t->last = t->cur; + t->cur = i + what.size; + return ret; + } + } + + return ""; +} + +inline char tok_nextchar( STR_TOKENIZER* t ) { + if( t->cur >= t->str.size ) + return 0; + + U32 last = t->cur; + for( ; t->cur < t->str.size; t->cur++ ) { + U8 cont = 0; + for( auto& it : t->ignored ) { + if( t->str.data[t->cur] == it ) { + cont = 1; + break; + } + } + + if( cont ) + continue; + else { + t->last = last; + t->cur++; + return t->str.data[t->cur]; + } + } + + return 0; +} diff --git a/src/util/string.h b/src/util/string.h index 2268a36..672fb5d 100644 --- a/src/util/string.h +++ b/src/util/string.h @@ -55,8 +55,6 @@ template <typename CT> struct __str : public LIST<CT> { __str() : LIST<CT>() {} __str( U32 count, const CT* str ) : LIST<CT>() { - this->data = 0; - this->capacity = 0; this->reserve( count * 2 ); memcpy( this->data, str, count ); this->size = count; @@ -69,8 +67,6 @@ struct __str : public LIST<CT> { va_copy( args2, args ); U32 c = vsnprintf( 0, 0, fmt, args ); va_end( args ); - this->data = 0; - this->capacity = 0; this->reserve( c * 2 ); vsnprintf( this->data, c + 1, fmt, args2 ); this->data[c] = 0; @@ -89,8 +85,6 @@ struct __str : public LIST<CT> { if( this->data && this->data != other.data ) free( this->data ); - this->data = 0; - if( !other.capacity || !other.size ) { this->capacity = 1; this->size = 0; @@ -116,8 +110,9 @@ struct __str : public LIST<CT> { __str<CT> operator+( const CT rhs ) { __str<CT> ret = *this; ret.push( rhs ); return ret; } __str<CT>& operator+=( const __str<CT>& rhs ) { return this->append( rhs ); } __str<CT>& operator+=( const CT* rhs ) { return this->append( rhs ); } - __str<CT>& operator+=( const CT rhs ) { this->push( rhs ); return this; } + __str<CT>& operator+=( const CT rhs ) { this->push( rhs ); return *this; } + operator const CT*() { return this->data; } operator CT*() { return this->data; } CT operator[]( U32 i ) { @@ -128,10 +123,8 @@ struct __str : public LIST<CT> { if( rhs.size != this->size ) return 0; - for( U32 i = 0; i < this->size; ++i ) { - if( this->data[i] != rhs.data[i] ) - return 0; - } + if( !!memcmp( this->data, rhs.data, this->size ) ) + return 0; return 1; } @@ -165,7 +158,7 @@ struct __str : public LIST<CT> { __str<CT>& append( const CT* str ) { U32 len; for( len = 0; !!str[len]; ++len ); - if( this->size + len > this->capacity ) + if( this->size + len + 1 >= this->capacity ) this->reserve( this->size + len + 1 ); memcpy( this->data + this->size, str, len * sizeof(CT) ); @@ -179,7 +172,7 @@ struct __str : public LIST<CT> { if( this->size + len + 1 >= this->capacity ) this->reserve( this->size + len + 1 ); - memcpy( this->data + this->size, str, len * sizeof(CT) ); + memcpy( this->data + this->size, str.data, len * sizeof(CT) ); this->size += len; this->data[this->size] = 0; return *this; @@ -281,3 +274,11 @@ struct __str : public LIST<CT> { using STR = __str<char>; using WSTR = __str<wchar_t>; + +inline STR to_str( F32 f ) { return STR( "%.02f", f ); } +inline STR to_str( F64 f ) { return STR( "%.02g", f ); } +inline STR to_str( I32 i ) { return STR( "%d", i ); } +inline STR to_str( I64 i ) { return STR( "%lld", i ); } +inline STR to_str( U32 u ) { return STR( "%u", u ); } +inline STR to_str( U64 u ) { return STR( "%llu", u ); } +inline STR to_str( void* p ) { return STR( "%llx", (U64)p ); } diff --git a/src/util/vector.h b/src/util/vector.h index 854b454..eb386ab 100644 --- a/src/util/vector.h +++ b/src/util/vector.h @@ -1,7 +1,7 @@ #pragma once #include <math.h> -#include "typedef.h" +#include "string.h" static const F32 PI = 3.14159265359f; static const F32 PIRAD = 0.01745329251f; @@ -13,7 +13,6 @@ struct VEC2 { VEC2() { x = y = 0.0f; } VEC2( F32 X, F32 Y ) { x = X; y = Y; } - VEC2( const F32* v ) { x = v[0]; y = v[1]; } VEC2( const VEC2& v ) { x = v.x; y = v.y; } bool operator==( const VEC2& v ) const { return ( x == v.x && y == v.y ); } @@ -49,7 +48,6 @@ struct VEC3 { VEC3() { x = y = z = 0.0f; } VEC3( F32 X, F32 Y, F32 Z ) { x = X; y = Y; z = Z; } - VEC3( const F32* v ) { x = v[0]; y = v[1]; z = v[2]; } VEC3( const VEC3& v ) { x = v.x; y = v.y; z = v.z; } VEC3( const VEC2& v ) { x = v.x; y = v.y; z = 0.f; } @@ -250,3 +248,7 @@ inline void angle_vectors( const VEC3& angles, VEC3* forward, VEC3* right, VEC3* up->z = cr * cp; } } + +inline STR to_str( VEC2 v ) { return STR( "%.02f, %.02f", v.x, v.y ); } +inline STR to_str( VEC3 v ) { return STR( "%.02f, %.02f, %.02f", v.x, v.y, v.z ); } +inline STR to_str( VEC4 v ) { return STR( "%.02f, %.02f, %.02f, %.02f", v.x, v.y, v.z, v.w ); } |
