diff options
| author | kasull <qsullian@gmail.com> | 2026-03-11 00:24:47 -0400 |
|---|---|---|
| committer | kasull <qsullian@gmail.com> | 2026-03-11 00:24:47 -0400 |
| commit | ae6718ec0fb21077b767e189aca26b0fed488775 (patch) | |
| tree | a4216103d8a9a77edbc470dc4ab094e77ac30261 /src/editor/editor.cpp | |
| parent | bc1ea16c5be92e3bc810b0a30e01fbc9a7f191a9 (diff) | |
editor object placement and context menus
replace the editor menubar dropdown flow with a reusable context menu
component
merge sprite/entity placement into a single object tool
persist entities, and add undo
support for created sprites and entities
Diffstat (limited to 'src/editor/editor.cpp')
| -rw-r--r-- | src/editor/editor.cpp | 138 |
1 files changed, 138 insertions, 0 deletions
diff --git a/src/editor/editor.cpp b/src/editor/editor.cpp index 3873913..dee5080 100644 --- a/src/editor/editor.cpp +++ b/src/editor/editor.cpp @@ -1,6 +1,7 @@ #include "editor.h" #include "../game.h" +#include "../game/object.h" GAME_EDITOR* editor = 0; @@ -20,6 +21,7 @@ void editor_clear_gui_state_refs( GAME_EDITOR* e ) { e->gui.status = 0; e->gui.assets_scroll = 0; + e->gui.contextmenu = 0; e->gui.header_toolbar = 0; e->gui.header_viewtype_label = 0; e->gui.header_back = 0; @@ -82,6 +84,18 @@ static U8 editor_poly_eq( const MAP_POLYGON& a, const MAP_POLYGON& b ) { return 1; } +static U8 editor_sprite_eq( const MAP_SPRITE& a, const MAP_SPRITE& b ) { + return a.pos == b.pos + && a.size == b.size + && editor_clr_eq( a.clr, b.clr ) + && a.tex == b.tex; +} + +static U8 editor_entity_eq( const MAP_ENTITY& a, const MAP_ENTITY& b ) { + return a.pos == b.pos + && a.classid == b.classid; +} + static I32 editor_clamp_valid_idx( I32 idx, I32 size ) { if( size <= 0 ) return -1; @@ -139,6 +153,24 @@ static I32 editor_find_poly_idx( WORLD_MAP* map, const MAP_POLYGON& want, I32 ex } ); } +static I32 editor_find_sprite_idx( WORLD_MAP* map, const MAP_SPRITE& want, I32 expected_idx ) { + if( !map ) + return -1; + + return editor_find_nearest_idx( (I32)map->sprites.size, expected_idx, fn( I32 i ) { + return editor_sprite_eq( map->sprites[i], want ); + } ); +} + +static I32 editor_find_entity_idx( WORLD_MAP* map, const MAP_ENTITY& want, I32 expected_idx ) { + if( !map ) + return -1; + + return editor_find_nearest_idx( (I32)map->entities.size, expected_idx, fn( I32 i ) { + return editor_entity_eq( map->entities[i], want ); + } ); +} + static void editor_mark_clear_wall_refs( GAME_EDITOR* e, MAP_WALL* w, U8* clear_props_select, U8* clear_view_select, U8* clear_view_drag ) { if( e->gui.props ) { if( e->gui.props->seltype == EDITOR_SELECT_WALL && e->gui.props->curselect == w ) @@ -196,6 +228,30 @@ static void editor_mark_clear_poly_refs( GAME_EDITOR* e, MAP_POLYGON* p, U8* cle } } +static void editor_mark_clear_sprite_refs( GAME_EDITOR* e, MAP_SPRITE* s, U8* clear_props_select, U8* clear_view_select, U8* clear_view_drag ) { + if( e->gui.props && e->gui.props->seltype == EDITOR_SELECT_SPRITE && e->gui.props->curselect == s ) + *clear_props_select = 1; + + if( e->gui.v2d ) { + if( e->gui.v2d->seltype == EDITOR_SELECT_SPRITE && e->gui.v2d->curselect == s ) + *clear_view_select = 1; + if( e->gui.v2d->dragtype == EDITOR_SELECT_SPRITE && e->gui.v2d->curdrag == s ) + *clear_view_drag = 1; + } +} + +static void editor_mark_clear_entity_refs( GAME_EDITOR* e, MAP_ENTITY* ent, U8* clear_props_select, U8* clear_view_select, U8* clear_view_drag ) { + if( e->gui.props && e->gui.props->seltype == EDITOR_SELECT_ENT && e->gui.props->curselect == ent ) + *clear_props_select = 1; + + if( e->gui.v2d ) { + if( e->gui.v2d->seltype == EDITOR_SELECT_ENT && e->gui.v2d->curselect == ent ) + *clear_view_select = 1; + if( e->gui.v2d->dragtype == EDITOR_SELECT_ENT && e->gui.v2d->curdrag == ent ) + *clear_view_drag = 1; + } +} + void editor_undo_clear( GAME_EDITOR* e ) { if( !e ) return; @@ -243,6 +299,38 @@ void editor_undo_record_create_poly( GAME_EDITOR* e, I32 start_idx ) { editor_push_undo_action( e, action ); } +void editor_undo_record_create_sprite( GAME_EDITOR* e, I32 start_idx ) { + if( !e || !e->map ) + return; + + WORLD_MAP* map = e->map; + if( start_idx < 0 || start_idx >= (I32)map->sprites.size ) + return; + + GAME_EDITOR::EDITOR_UNDO_ACTION action{}; + action.type = EDITOR_UNDO_CREATE_SPRITES; + action.start_idx = start_idx; + action.sprites.push( map->sprites[start_idx] ); + + editor_push_undo_action( e, action ); +} + +void editor_undo_record_create_entity( GAME_EDITOR* e, I32 start_idx ) { + if( !e || !e->map ) + return; + + WORLD_MAP* map = e->map; + if( start_idx < 0 || start_idx >= (I32)map->entities.size ) + return; + + GAME_EDITOR::EDITOR_UNDO_ACTION action{}; + action.type = EDITOR_UNDO_CREATE_ENTITIES; + action.start_idx = start_idx; + action.entities.push( map->entities[start_idx] ); + + editor_push_undo_action( e, action ); +} + static U8 editor_apply_undo_action_reverse( GAME_EDITOR* e, GAME_EDITOR::EDITOR_UNDO_ACTION& action ) { if( !e || !e->map ) return 0; @@ -289,6 +377,38 @@ static U8 editor_apply_undo_action_reverse( GAME_EDITOR* e, GAME_EDITOR::EDITOR_ map->polygons.erase( idx ); } } break; + case EDITOR_UNDO_CREATE_SPRITES: { + I32 count = (I32)action.sprites.size; + for( I32 i = count - 1; i >= 0; --i ) { + if( !map->sprites.size ) + break; + + I32 expected = action.start_idx + i; + I32 idx = editor_find_sprite_idx( map, action.sprites[i], expected ); + if( idx < 0 ) + idx = editor_clamp_valid_idx( expected, (I32)map->sprites.size ); + + MAP_SPRITE* s = &map->sprites[idx]; + editor_mark_clear_sprite_refs( e, s, &clear_props_select, &clear_view_select, &clear_view_drag ); + map->sprites.erase( idx ); + } + } break; + case EDITOR_UNDO_CREATE_ENTITIES: { + I32 count = (I32)action.entities.size; + for( I32 i = count - 1; i >= 0; --i ) { + if( !map->entities.size ) + break; + + I32 expected = action.start_idx + i; + I32 idx = editor_find_entity_idx( map, action.entities[i], expected ); + if( idx < 0 ) + idx = editor_clamp_valid_idx( expected, (I32)map->entities.size ); + + MAP_ENTITY* ent = &map->entities[idx]; + editor_mark_clear_entity_refs( e, ent, &clear_props_select, &clear_view_select, &clear_view_drag ); + map->entities.erase( idx ); + } + } break; default: return 0; } @@ -333,6 +453,22 @@ static U8 editor_apply_undo_action_forward( GAME_EDITOR* e, GAME_EDITOR::EDITOR_ map->polygons.push( *p ); } ); } break; + case EDITOR_UNDO_CREATE_SPRITES: { + if( !action.sprites.size ) + return 0; + + action.sprites.each( fn( MAP_SPRITE* s ) { + map->sprites.push( *s ); + } ); + } break; + case EDITOR_UNDO_CREATE_ENTITIES: { + if( !action.entities.size ) + return 0; + + action.entities.each( fn( MAP_ENTITY* ent ) { + map->entities.push( *ent ); + } ); + } break; default: return 0; } @@ -415,6 +551,8 @@ GAME_EDITOR* editor_create( GAME_DATA* game ) { e->tool.polysides = EDITOR_DEFAULT_POLY_SIDES; e->tool.wallheight = EDITOR_DEFAULT_WALL_HEIGHT; e->tool.placementheight = EDITOR_DEFAULT_PLACEMENT_HEIGHT; + e->tool.entclass = OBJCLASS_TRIGGER; + e->tool.objecttype = EDITOR_OBJECT_SPRITE; e->game = game; gui_init( game ); |
