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/view2d.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/view2d.cpp')
| -rw-r--r-- | src/editor/view2d.cpp | 149 |
1 files changed, 128 insertions, 21 deletions
diff --git a/src/editor/view2d.cpp b/src/editor/view2d.cpp index 8dbe42c..f1b5b17 100644 --- a/src/editor/view2d.cpp +++ b/src/editor/view2d.cpp @@ -1,6 +1,7 @@ #include <math.h> #include "editor.h" #include "../render/gl_2d.h" +#include "../game/object.h" #include "../game/objlist.h" #include "../game/world/bsp.h" @@ -13,6 +14,7 @@ const I32 EDITOR_POLY_SIDES_RUNTIME_MAX = 256; VEC2 gui_editor_2dview_screen_to_world( GUI_EDITOR_2DVIEW* view, I32 x, I32 y ); VEC2 gui_editor_2dview_world_to_screen( GUI_EDITOR_2DVIEW* view, VEC2 world ); F32 gui_editor_2dview_placement_z(); +void gui_editor_2dview_draw_object_preview( GUI_EDITOR_2DVIEW* view ); VEC3 gui_editor_2dview_plane_to_world3( VEC2 plane, F32 depth ) { return { plane.x, plane.y, depth }; @@ -650,6 +652,25 @@ void gui_editor_2dview_draw_sprites( GUI_EDITOR_2DVIEW* view, I32 x, I32 y ) { } ); } +void gui_editor_2dview_draw_entities( GUI_EDITOR_2DVIEW* view, I32 x, I32 y ) { + WORLD_MAP* m = editor->map; + + m->entities.each( fn( MAP_ENTITY* e ) { + VEC2 pos = gui_editor_2dview_world3_to_screen( view, e->pos ); + I32 px = (I32)pos.x; + I32 py = (I32)pos.y; + U8 sel = gui_editor_2dview_is_gizmo_active( view, e, EDITOR_SELECT_ENT ); + + if( sel ) { + gui_draw_line( px - 8, py, px + 8, py, CLR::WHITE( 0.7f ) ); + gui_draw_line( px, py - 8, px, py + 8, CLR::WHITE( 0.7f ) ); + } + gui_draw_line( px - 6, py, px + 6, py, CLR::YELLOW() ); + gui_draw_line( px, py - 6, px, py + 6, CLR::YELLOW() ); + gui_draw_str( px + 8, py - 8, ALIGN_L, FNT_JPN12, ui_clr.txt, "%s", obj_classid_to_name( e->classid ) ); + } ); +} + void gui_editor_2dview_draw_player( GUI_EDITOR_2DVIEW* view, I32 x, I32 y ) { if( !objl->pl ) @@ -712,10 +733,12 @@ void gui_editor_2dview_draw_fn( void* ptr ) { gui_draw_push_clip( x + offx, y + offy, w - offx, h - offy - EDITORVIEW_TOOLBAR_OFFSET ); gui_editor_2dview_draw_polygons( view, x + offx, y + offy ); gui_editor_2dview_draw_walls( view, x + offx, y + offy ); + gui_editor_2dview_draw_entities( view, x + offx, y + offy ); gui_editor_2dview_draw_sprites( view, x + offx, y + offy ); gui_editor_2dview_draw_player( view, x + offx, y + offy ); gui_editor_2dview_draw_origin( view, x + offx, y + offy ); gui_editor_2dview_draw_poly_preview( view ); + gui_editor_2dview_draw_object_preview( view ); gui_draw_pop_clip(); gui_draw_push_clip( x, y + 16, view->w, view->h ); @@ -882,6 +905,42 @@ void gui_editor_2dview_input_select_drag_sprite( GUI_EDITOR_2DVIEW* view ) { } } +void gui_editor_2dview_draw_object_preview( GUI_EDITOR_2DVIEW* view ) { + if( editor->tool.type != EDITOR_TOOL_OBJECT || !view->held ) + return; + + VEC2 pos = gui_editor_2dview_world3_to_screen( view, view->pending_object_pos ); + I32 px = (I32)pos.x; + I32 py = (I32)pos.y; + + if( view->pending_object_undo_type == EDITOR_SELECT_ENT ) { + gui_draw_line( px - 6, py, px + 6, py, CLR::WHITE( 0.8f ) ); + gui_draw_line( px, py - 6, px, py + 6, CLR::WHITE( 0.8f ) ); + return; + } + + F32 wantedsize = editor->spritesize; + gui_draw_rect( + (I32)( pos.x - wantedsize * 0.5f ), + (I32)( pos.y - wantedsize * 0.5f ), + (I32)wantedsize, + (I32)wantedsize, + CLR::WHITE( 0.8f ) + ); +} + +void gui_editor_2dview_input_select_drag_entity( GUI_EDITOR_2DVIEW* view ) { + MAP_ENTITY* e = (MAP_ENTITY*)view->curdrag; + + gui_editor_2dview_snap_plane( &e->pos ); + + VEC2 mv = gui_editor_2dview_input_get_drag_vec( view ); + if( !is_zero( mv ) ) { + gui_editor_2dview_add_plane_delta( &e->pos, mv ); + gui_editor_2dview_input_select_onmove( view ); + } +} + void gui_editor_2dview_input_select_drag_origin( GUI_EDITOR_2DVIEW* view ) { WORLD_MAP* m = editor->map; @@ -928,6 +987,7 @@ void gui_editor_2dview_input_select_drag( GUI_EDITOR_2DVIEW* view ) { switch( view->dragtype ) { case EDITOR_SELECT_WALL: gui_editor_2dview_input_select_drag_wall( view ); break; case EDITOR_SELECT_POLY: gui_editor_2dview_input_select_drag_polygon( view ); break; + case EDITOR_SELECT_ENT: gui_editor_2dview_input_select_drag_entity( view ); break; case EDITOR_SELECT_SPRITE: gui_editor_2dview_input_select_drag_sprite( view ); break; case EDITOR_SELECT_ORIGIN: gui_editor_2dview_input_select_drag_origin( view ); break; case EDITOR_SELECT_WVERTEX: @@ -1055,6 +1115,30 @@ void gui_editor_2dview_input_select_sprites( GUI_EDITOR_2DVIEW* view ) { gui_editor_2dview_input_select_drag( view ); } +void gui_editor_2dview_input_select_entities( GUI_EDITOR_2DVIEW* view ) { + WORLD_MAP* m = editor->map; + + I32 mx, my; + gui_cursor_pos( &mx, &my ); + + VEC2 mpos = { (F32)mx, (F32)my }; + F32 mindist = editor->spritesize; + for( U32 i = 0; i < m->entities.size; ++i ) { + MAP_ENTITY* e = &m->entities[i]; + VEC2 screen = gui_editor_2dview_world3_to_screen( view, e->pos ); + F32 dist = vec_dist( mpos, screen ); + if( dist < mindist ) { + mindist = dist; + gui_editor_2dview_select( view, e, EDITOR_SELECT_ENT ); + } + } + + if( !view->curselect && !view->held ) + return; + + gui_editor_2dview_input_select_drag( view ); +} + void gui_editor_2dview_input_select_origin( GUI_EDITOR_2DVIEW* view ) { WORLD_MAP* m = editor->map; @@ -1090,6 +1174,8 @@ void gui_editor_2dview_input_tool_select( GUI_EDITOR_2DVIEW* view ) { view->seltype = EDITOR_SELECT_NONE; gui_editor_2dview_input_select_origin( view ); if( view->curselect ) return; + gui_editor_2dview_input_select_entities( view ); + if( view->curselect ) return; gui_editor_2dview_input_select_sprites( view ); if( view->curselect ) return; gui_editor_2dview_input_select_walls( view ); @@ -1230,13 +1316,35 @@ void gui_editor_2dview_input_tool_poly( GUI_EDITOR_2DVIEW* view ) { view->poly_end = world; } -void gui_editor_2dview_input_tool_ent( GUI_EDITOR_2DVIEW* view ) { - -} - -void gui_editor_2dview_input_tool_sprite( GUI_EDITOR_2DVIEW* view ) { +void gui_editor_2dview_input_tool_object( GUI_EDITOR_2DVIEW* view ) { U8 m1 = gui_mbutton_down( 0 ); if( !m1 ) { + if( view->held ) { + if( view->pending_object_undo_type == EDITOR_SELECT_ENT ) { + MAP_ENTITY ent{}; + ent.pos = view->pending_object_pos; + ent.classid = editor->tool.entclass; + + I32 idx = editor->map->entities.size; + editor->map->entities.push( ent ); + editor_undo_record_create_entity( editor, idx ); + } + else if( view->pending_object_undo_type == EDITOR_SELECT_SPRITE ) { + MAP_SPRITE news{}; + news.pos = view->pending_object_pos; + news.size = { 20.f, 20.f }; + news.clr = { 1.f, 1.f, 1.f, 1.f }; + news.tex = 0; + + I32 idx = editor->map->sprites.size; + editor->map->sprites.push( news ); + editor_undo_record_create_sprite( editor, idx ); + } + } + view->pending_object_undo_idx = -1; + view->pending_object_undo_type = EDITOR_SELECT_NONE; + view->curdrag = 0; + view->dragtype = EDITOR_SELECT_NONE; view->held = 0; return; } @@ -1246,17 +1354,10 @@ void gui_editor_2dview_input_tool_sprite( GUI_EDITOR_2DVIEW* view ) { VEC2 world = gui_editor_2dview_screen_to_world( view, mx, my ); if( !view->held ) { - VEC3 wpos = gui_editor_2dview_plane_to_world3( world, gui_editor_2dview_placement_z() ); - MAP_SPRITE news; - news.pos = wpos; - gui_editor_2dview_snap_plane( &news.pos ); - news.size = { 20.f, 20.f }; - news.clr = { 1.f, 1.f, 1.f, 1.f }; - news.tex = 0; - - I32 idx = editor->map->sprites.size; - editor->map->sprites.push( news ); - view->curdrag = &editor->map->sprites[idx]; + view->pending_object_pos = gui_editor_2dview_plane_to_world3( world, gui_editor_2dview_placement_z() ); + gui_editor_2dview_snap_plane( &view->pending_object_pos ); + view->pending_object_undo_idx = -1; + view->pending_object_undo_type = editor->tool.objecttype == EDITOR_OBJECT_ENTITY ? EDITOR_SELECT_ENT : EDITOR_SELECT_SPRITE; view->held = 1; view->oldmx = mx; @@ -1266,7 +1367,8 @@ void gui_editor_2dview_input_tool_sprite( GUI_EDITOR_2DVIEW* view ) { return; } - gui_editor_2dview_input_select_drag_sprite( view ); + view->pending_object_pos = gui_editor_2dview_plane_to_world3( world, gui_editor_2dview_placement_z() ); + gui_editor_2dview_snap_plane( &view->pending_object_pos ); } @@ -1281,8 +1383,7 @@ void gui_editor_2dview_input_tool_draw( GUI_EDITOR_2DVIEW* view ) { switch( editor->tool.type ) { case EDITOR_TOOL_WALL: return gui_editor_2dview_input_tool_wall( view ); case EDITOR_TOOL_POLY: return gui_editor_2dview_input_tool_poly( view ); - case EDITOR_TOOL_ENT: return gui_editor_2dview_input_tool_ent( view ); - case EDITOR_TOOL_SPRITE: return gui_editor_2dview_input_tool_sprite( view ); + case EDITOR_TOOL_OBJECT: return gui_editor_2dview_input_tool_object( view ); default: return; } } @@ -1321,6 +1422,11 @@ void gui_editor_view2d_delete_obj( GUI_EDITOR_2DVIEW* view ) { if( idx != -1 ) editor->map->sprites.erase( idx ); }; break; + case EDITOR_SELECT_ENT: { + I32 idx = editor->map->entities.idx_of( (MAP_ENTITY*)it ); + if( idx != -1 ) + editor->map->entities.erase( idx ); + }; break; case EDITOR_SELECT_PVERTEX: { I32 vidx = -1, idx = editor->map->polygons.idx_where( fn( MAP_POLYGON* p ) { vidx = p->vertices.idx_where( fn( MAP_VERTEX* v ) { @@ -1424,8 +1530,7 @@ void gui_editor_2dview_input_fn( void* ptr ) { case EDITOR_TOOL_SELECT: return gui_editor_2dview_input_tool_select( view ); case EDITOR_TOOL_WALL: case EDITOR_TOOL_POLY: - case EDITOR_TOOL_SPRITE: - case EDITOR_TOOL_ENT: + case EDITOR_TOOL_OBJECT: return gui_editor_2dview_input_tool_draw( view ); default: return gui_editor_2dview_input_tool_none( view ); } @@ -1508,6 +1613,8 @@ GUI_EDITOR_2DVIEW* gui_editor_2dview( I32 x, I32 y, I32 w, I32 h ) { view->poly_start = { 0.f, 0.f }; view->poly_end = { 0.f, 0.f }; view->pending_wall_undo_idx = -1; + view->pending_object_undo_idx = -1; + view->pending_object_undo_type = EDITOR_SELECT_NONE; GUI_BASE* parent = gui_get_view(); if( !parent ) |
