summaryrefslogtreecommitdiff
path: root/src/editor
diff options
context:
space:
mode:
Diffstat (limited to 'src/editor')
-rw-r--r--src/editor/editor.cpp161
-rw-r--r--src/editor/editor.h65
-rw-r--r--src/editor/properties.cpp31
-rw-r--r--src/editor/properties.h35
-rw-r--r--src/editor/view2d.cpp180
5 files changed, 372 insertions, 100 deletions
diff --git a/src/editor/editor.cpp b/src/editor/editor.cpp
index c96f908..72ca4d2 100644
--- a/src/editor/editor.cpp
+++ b/src/editor/editor.cpp
@@ -2,6 +2,7 @@
#include "../game.h"
#include "../game/object.h"
+#include "properties.h"
GAME_EDITOR* editor = 0;
@@ -31,7 +32,7 @@ void editor_clear_gui_state_refs( GAME_EDITOR* e ) {
e->gui.header_viewtype = 0;
}
-void editor_push_undo_action( GAME_EDITOR* e, const GAME_EDITOR::EDITOR_UNDO_ACTION& action ) {
+void editor_push_undo_action( GAME_EDITOR* e, const EDITOR_UNDO_ACTION& action ) {
if( !e )
return;
@@ -265,11 +266,11 @@ void editor_undo_record_create_walls( GAME_EDITOR* e, I32 start_idx, I32 count )
if( count <= 0 )
return;
- GAME_EDITOR::EDITOR_UNDO_ACTION action{};
+ EDITOR_UNDO_ACTION action{};
action.type = EDITOR_UNDO_CREATE_WALLS;
- action.start_idx = start_idx;
+ action.create.start_idx = start_idx;
for( I32 i = 0; i < count; ++i )
- action.walls.push( map->walls[start_idx + i] );
+ action.create.walls.push( map->walls[start_idx + i] );
editor_push_undo_action( e, action );
}
@@ -282,10 +283,11 @@ void editor_undo_record_create_poly( GAME_EDITOR* e, I32 start_idx ) {
if( start_idx < 0 || start_idx >= (I32)map->polygons.size )
return;
- GAME_EDITOR::EDITOR_UNDO_ACTION action{};
- action.type = EDITOR_UNDO_CREATE_POLY;
- action.start_idx = start_idx;
- action.polys.push( map->polygons[start_idx] );
+ EDITOR_UNDO_ACTION action{
+ .type = EDITOR_UNDO_CREATE_POLY,
+ .create = { .start_idx = start_idx }
+ };
+ action.create.polys.push( map->polygons[start_idx] );
editor_push_undo_action( e, action );
}
@@ -298,10 +300,12 @@ void editor_undo_record_create_sprite( GAME_EDITOR* e, I32 start_idx ) {
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_UNDO_ACTION action = {
+ .type = EDITOR_UNDO_CREATE_SPRITES,
+ .create = { .start_idx = start_idx }
+ };
+
+ action.create.sprites.push( map->sprites[start_idx] );
editor_push_undo_action( e, action );
}
@@ -314,18 +318,36 @@ void editor_undo_record_create_entity( GAME_EDITOR* e, I32 start_idx ) {
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_UNDO_ACTION action{
+ .type = EDITOR_UNDO_CREATE_ENTITIES,
+ .create = { .start_idx = start_idx }
+ };
+ action.create.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 ) {
+// NOTE:
+// this is a util func.
+// individual components create records manually
+void editor_undo_record_change_prop( GAME_EDITOR* e, FNV1A hash, void* oldv, void* newv, U32 size ) {
if( !e || !e->map )
- return 0;
+ return;
+
+ EDITOR_UNDO_ACTION rec{ .type = EDITOR_UNDO_EDITPROPS };
+ for( auto e : e->gui.props->curselect ) {
+ EDITOR_UNDO_PROPS::CHANGES changes{};
+
+ changes.props.push( { hash, size, oldv, newv } );
+ changes.obj = (EOBJECT*)e.obj;
+ rec.props.changes.push( changes );
+ }
+
+ e->undo_actions.push( rec );
+}
+
+U8 editor_apply_undo_action_reverse_create( GAME_EDITOR* e, EDITOR_UNDO_ACTION& action ) {
WORLD_MAP* map = e->map;
U8 clear_props_select = 0;
U8 clear_view_select = 0;
@@ -333,13 +355,13 @@ static U8 editor_apply_undo_action_reverse( GAME_EDITOR* e, GAME_EDITOR::EDITOR_
switch( action.type ) {
case EDITOR_UNDO_CREATE_WALLS: {
- I32 count = (I32)action.walls.size;
+ I32 count = (I32)action.create.walls.size;
for( I32 i = count - 1; i >= 0; --i ) {
if( !map->walls.size )
break;
- I32 expected = action.start_idx + i;
- I32 idx = editor_find_wall_idx( map, action.walls[i], expected );
+ I32 expected = action.create.start_idx + i;
+ I32 idx = editor_find_wall_idx( map, action.create.walls[i], expected );
if( idx < 0 )
idx = editor_clamp_valid_idx( expected, (I32)map->walls.size );
@@ -350,15 +372,15 @@ static U8 editor_apply_undo_action_reverse( GAME_EDITOR* e, GAME_EDITOR::EDITOR_
}
} break;
case EDITOR_UNDO_CREATE_POLY: {
- I32 count = (I32)action.polys.size;
+ I32 count = (I32)action.create.polys.size;
if( count <= 0 )
return 0;
for( I32 i = count - 1; i >= 0; --i ) {
if( !map->polygons.size )
break;
- I32 expected = action.start_idx + i;
- I32 idx = i < (I32)action.polys.size ? editor_find_poly_idx( map, action.polys[i], expected ) : -1;
+ I32 expected = action.create.start_idx + i;
+ I32 idx = i < (I32)action.create.polys.size ? editor_find_poly_idx( map, action.create.polys[i], expected ) : -1;
if( idx < 0 )
idx = editor_clamp_valid_idx( expected, (I32)map->polygons.size );
@@ -369,13 +391,13 @@ static U8 editor_apply_undo_action_reverse( GAME_EDITOR* e, GAME_EDITOR::EDITOR_
}
} break;
case EDITOR_UNDO_CREATE_SPRITES: {
- I32 count = (I32)action.sprites.size;
+ I32 count = (I32)action.create.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 );
+ I32 expected = action.create.start_idx + i;
+ I32 idx = editor_find_sprite_idx( map, action.create.sprites[i], expected );
if( idx < 0 )
idx = editor_clamp_valid_idx( expected, (I32)map->sprites.size );
@@ -385,13 +407,13 @@ static U8 editor_apply_undo_action_reverse( GAME_EDITOR* e, GAME_EDITOR::EDITOR_
}
} break;
case EDITOR_UNDO_CREATE_ENTITIES: {
- I32 count = (I32)action.entities.size;
+ I32 count = (I32)action.create.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 );
+ I32 expected = action.create.start_idx + i;
+ I32 idx = editor_find_entity_idx( map, action.create.entities[i], expected );
if( idx < 0 )
idx = editor_clamp_valid_idx( expected, (I32)map->entities.size );
@@ -422,41 +444,88 @@ static U8 editor_apply_undo_action_reverse( GAME_EDITOR* e, GAME_EDITOR::EDITOR_
return 1;
}
-static U8 editor_apply_undo_action_forward( GAME_EDITOR* e, GAME_EDITOR::EDITOR_UNDO_ACTION& action ) {
+U8 editor_apply_undo_action_reverse_props( GAME_EDITOR* e, EDITOR_UNDO_ACTION& action ) {
+ EDITOR_UNDO_PROPS* c = &action.props;
+
+ for( auto it : c->changes ) {
+ EOBJECT* obj = it.obj;
+ for( auto it2 : it.props ) {
+ EDITOR_PROP* p = eprop_from_hash( obj, it2.hash );
+ if( !p ) {
+ dlog( "editor_apply_undo_action_reverse_props() : warn: prop not found %x\n", it2.hash );
+ return 0;
+ }
+
+ void* data = eprop_ptr( p );
+ memcpy( data, it2.oldval.data, p->size );
+ }
+ }
+
+ return 1;
+}
+
+U8 editor_apply_undo_action_reverse( GAME_EDITOR* e, EDITOR_UNDO_ACTION& action ) {
if( !e || !e->map )
return 0;
+ if( action.type == EDITOR_UNDO_EDITPROPS )
+ return editor_apply_undo_action_reverse_props( e, action );
+
+ return editor_apply_undo_action_reverse_create( e, action );
+}
+
+U8 editor_apply_undo_action_forward_props( GAME_EDITOR* e, EDITOR_UNDO_ACTION& action ) {
+ EDITOR_UNDO_PROPS* c = &action.props;
+
+ for( auto it : c->changes ) {
+ EOBJECT* obj = it.obj;
+ for( auto it2 : it.props ) {
+ EDITOR_PROP* p = eprop_from_hash( obj, it2.hash );
+ if( !p ) {
+ dlog( "editor_apply_undo_action_forward_props() : warn: prop not found %x\n", it2.hash );
+ return 0;
+ }
+
+ void* data = eprop_ptr( p );
+ memcpy( data, it2.newval.data, p->size );
+ }
+ }
+
+ return 1;
+}
+
+U8 editor_apply_undo_action_forward_create( GAME_EDITOR* e, EDITOR_UNDO_ACTION& action ) {
WORLD_MAP* map = e->map;
switch( action.type ) {
case EDITOR_UNDO_CREATE_WALLS: {
- if( !action.walls.size )
+ if( !action.create.walls.size )
return 0;
- action.walls.each( fn( MAP_WALL* w ) {
+ action.create.walls.each( fn( MAP_WALL* w ) {
map->walls.push( *w );
} );
} break;
case EDITOR_UNDO_CREATE_POLY: {
- if( !action.polys.size )
+ if( !action.create.polys.size )
return 0;
- action.polys.each( fn( MAP_POLYGON* p ) {
+ action.create.polys.each( fn( MAP_POLYGON* p ) {
map->polygons.push( *p );
} );
} break;
case EDITOR_UNDO_CREATE_SPRITES: {
- if( !action.sprites.size )
+ if( !action.create.sprites.size )
return 0;
- action.sprites.each( fn( MAP_SPRITE* s ) {
+ action.create.sprites.each( fn( MAP_SPRITE* s ) {
map->sprites.push( *s );
} );
} break;
case EDITOR_UNDO_CREATE_ENTITIES: {
- if( !action.entities.size )
+ if( !action.create.entities.size )
return 0;
- action.entities.each( fn( MAP_ENTITY* ent ) {
+ action.create.entities.each( fn( MAP_ENTITY* ent ) {
map->entities.push( *ent );
} );
} break;
@@ -469,11 +538,21 @@ static U8 editor_apply_undo_action_forward( GAME_EDITOR* e, GAME_EDITOR::EDITOR_
return 1;
}
+U8 editor_apply_undo_action_forward( GAME_EDITOR* e, EDITOR_UNDO_ACTION& action ) {
+ if( !e || !e->map )
+ return 0;
+
+ if( action.type == EDITOR_UNDO_EDITPROPS )
+ return editor_apply_undo_action_forward_props( e, action );
+
+ return editor_apply_undo_action_forward_create( e, action );
+}
+
U8 editor_undo( GAME_EDITOR* e ) {
if( !e || !e->map || !e->undo_actions.size )
return 0;
- GAME_EDITOR::EDITOR_UNDO_ACTION action = e->undo_actions.pop();
+ EDITOR_UNDO_ACTION action = e->undo_actions.pop();
if( !editor_apply_undo_action_reverse( e, action ) ) {
e->undo_actions.push( action );
return 0;
@@ -487,7 +566,7 @@ U8 editor_redo( GAME_EDITOR* e ) {
if( !e || !e->map || !e->redo_actions.size )
return 0;
- GAME_EDITOR::EDITOR_UNDO_ACTION action = e->redo_actions.pop();
+ EDITOR_UNDO_ACTION action = e->redo_actions.pop();
if( !editor_apply_undo_action_forward( e, action ) ) {
e->redo_actions.push( action );
return 0;
diff --git a/src/editor/editor.h b/src/editor/editor.h
index 4050029..b506d9c 100644
--- a/src/editor/editor.h
+++ b/src/editor/editor.h
@@ -34,12 +34,13 @@ enum EditorSelectType_t {
EDITOR_SELECT_SURFPROPS
};
-enum EditorUndoType_t {
+enum EditorActionType_t {
EDITOR_UNDO_NONE = 0,
EDITOR_UNDO_CREATE_WALLS = 1,
EDITOR_UNDO_CREATE_POLY = 2,
EDITOR_UNDO_CREATE_SPRITES = 3,
- EDITOR_UNDO_CREATE_ENTITIES = 4
+ EDITOR_UNDO_CREATE_ENTITIES = 4,
+ EDITOR_UNDO_EDITPROPS = 5
};
enum EditorInfoBoxType_t {
@@ -96,6 +97,55 @@ struct GAME_EDITOR_TOOL {
I32 objecttype;
};
+struct EDITOR_UNDO_PROPS {
+ struct PROP_VALUE {
+ LIST<U8> oldval{};
+ LIST<U8> newval{};
+ FNV1A hash;
+ U32 size;
+
+ PROP_VALUE() = default;
+ PROP_VALUE( FNV1A _hash, U32 _size ) {
+ this->hash = _hash;
+ this->size = _size;
+
+ this->oldval.resize( _size );
+ this->newval.resize( _size );
+ }
+ PROP_VALUE( FNV1A _hash, U32 _size, void* oldv, void* newv ) {
+ this->hash = _hash;
+ this->size = _size;
+
+ this->oldval.resize( _size );
+ this->newval.resize( _size );
+ memcpy( this->oldval.data, oldv, _size );
+ memcpy( this->newval.data, newv, _size );
+ }
+ };
+
+ struct CHANGES {
+ EOBJECT* obj;
+ LIST<PROP_VALUE> props;
+ };
+ LIST<CHANGES> changes;
+};
+
+struct EDITOR_UNDO_CREATE {
+ U8 objtype{};
+ I32 start_idx{};
+
+ LIST<MAP_WALL> walls{};
+ LIST<MAP_POLYGON> polys{};
+ LIST<MAP_SPRITE> sprites{};
+ LIST<MAP_ENTITY> entities{};
+};
+
+struct EDITOR_UNDO_ACTION {
+ U8 type;
+ EDITOR_UNDO_PROPS props;
+ EDITOR_UNDO_CREATE create;
+};
+
struct GAME_EDITOR {
GAME_DATA* game;
@@ -150,14 +200,6 @@ struct GAME_EDITOR {
LIST<GUI_LIST_ENTRY> map_list{};
- struct EDITOR_UNDO_ACTION {
- U8 type{};
- I32 start_idx{};
- LIST<MAP_WALL> walls{};
- LIST<MAP_POLYGON> polys{};
- LIST<MAP_SPRITE> sprites{};
- LIST<MAP_ENTITY> entities{};
- };
LIST<EDITOR_UNDO_ACTION> undo_actions{};
LIST<EDITOR_UNDO_ACTION> redo_actions{};
};
@@ -214,6 +256,7 @@ extern void editor_undo_record_create_walls( GAME_EDITOR* e, I32 start_idx, I32
extern void editor_undo_record_create_poly( GAME_EDITOR* e, I32 start_idx );
extern void editor_undo_record_create_sprite( GAME_EDITOR* e, I32 start_idx );
extern void editor_undo_record_create_entity( GAME_EDITOR* e, I32 start_idx );
+extern void editor_undo_record_change_prop( GAME_EDITOR* e, FNV1A hash, void* oldv, void* newv, U32 size );
extern U8 editor_undo( GAME_EDITOR* e );
extern U8 editor_redo( GAME_EDITOR* e );
@@ -261,6 +304,8 @@ struct GUI_EDITOR_2DVIEW : GUI_VIEW {
I32 pending_wall_undo_idx;
I32 pending_object_undo_idx;
U8 pending_object_undo_type;
+
+ EDITOR_UNDO_PROPS pending_undo_props{};
};
struct GUI_EDITOR_PROPVIEW : GUI_VIEW {
diff --git a/src/editor/properties.cpp b/src/editor/properties.cpp
index a9835e4..109e622 100644
--- a/src/editor/properties.cpp
+++ b/src/editor/properties.cpp
@@ -111,6 +111,8 @@ U8 gui_editor_propview_is_selected( GUI_EDITOR_PROPVIEW *e, void *what, U8 selty
void gui_editor_propview_sync_props_value( GUI_EDITOR_PROPVIEW* view, EDITOR_PROP* prop ) {
void* valuep = eprop_ptr( prop );
+
+ EDITOR_UNDO_ACTION rec{ .type = EDITOR_UNDO_EDITPROPS };
for( auto& it : view->curselect ) {
EOBJECT* eobj = (EOBJECT*)it.obj;
EDITOR_PROP* otherp = eprop_from_name( eobj, prop->displayname );
@@ -118,10 +120,22 @@ void gui_editor_propview_sync_props_value( GUI_EDITOR_PROPVIEW* view, EDITOR_PRO
if( otherp && otherp->type == prop->type ) {
void* targetp = eprop_ptr( otherp );
- if( targetp != valuep )
+ if( targetp != valuep ) {
+ EDITOR_UNDO_PROPS::CHANGES changes;
+
+ void* oldval = alloca( prop->size );
+ memcpy( oldval, targetp, prop->size );
memcpy( targetp, valuep, prop->size );
+
+ changes.props.push( { prop->hash, prop->size, oldval, targetp } );
+ changes.obj = eobj;
+ rec.props.changes.push( changes );
+ }
}
}
+
+ if( rec.props.changes.size )
+ editor->undo_actions.push( rec );
}
void gui_editor_propview_sync_props_value( GUI_EDITOR_PROPVIEW* view, const char* propname ) {
@@ -134,6 +148,10 @@ void gui_editor_propview_sync_props_value( GUI_EDITOR_PROPVIEW* view, const char
}
void gui_editor_propview_sync_props_fdiff( GUI_EDITOR_PROPVIEW* view, EDITOR_PROP* prop, F32* fdiff, U32 valc ) {
+ if( !fdiff )
+ return;
+
+ EDITOR_UNDO_ACTION rec{ .type = EDITOR_UNDO_EDITPROPS };
for( auto& it : view->curselect ) {
EOBJECT* eobj = (EOBJECT*)it.obj;
EDITOR_PROP* otherp = eprop_from_name( eobj, prop->displayname );
@@ -144,10 +162,21 @@ void gui_editor_propview_sync_props_fdiff( GUI_EDITOR_PROPVIEW* view, EDITOR_PRO
if( targetp == eprop_ptr( prop ) )
continue;
+ EDITOR_UNDO_PROPS::CHANGES changes;
+ F32* oldval = (F32*)alloca( prop->size );
+ memcpy( oldval, targetp, prop->size );
+
for( U32 i = 0; i < valc; ++i )
targetp[i] += fdiff[i];
+
+ changes.props.push( { prop->hash, prop->size, oldval, targetp } );
+ changes.obj = eobj;
+ rec.props.changes.push( changes );
}
}
+
+ if( rec.props.changes.size )
+ editor->undo_actions.push( rec );
}
void gui_editor_propview_sync_props_fdiff( GUI_EDITOR_PROPVIEW* view, const char* propname, F32* fdiff, U32 valc ) {
diff --git a/src/editor/properties.h b/src/editor/properties.h
index 810c075..d4fc3bb 100644
--- a/src/editor/properties.h
+++ b/src/editor/properties.h
@@ -6,6 +6,7 @@
#include <math.h>
#include "../util/string.h"
#include "../util/fnv.h"
+#include "../util/profiler.h"
#define EPROP( _type, name, value, display ) \
_type name = value; \
@@ -90,6 +91,7 @@ struct EOBJECT {
LIST<EPROP_ENTRY> eprops{};
};
+
template <typename T>
concept __eobject_base = __is_base_of(EOBJECT, T);
@@ -112,6 +114,7 @@ struct EDITOR_PROP {
_parent->eprops.push( { offset } );
+ parentoff = pdata - parent;
offset = _this - pdata;
dataoff = offset;
}
@@ -133,6 +136,7 @@ struct EDITOR_PROP {
_parent->eprops.push( { offset } );
+ parentoff = pdata - parent;
offset = _this - pdata;
dataoff = offset;
}
@@ -154,6 +158,7 @@ struct EDITOR_PROP {
_parent->eprops.push( { offset } );
+ parentoff = pdata - parent;
offset = _this - pdata;
dataoff = offset;
}
@@ -175,11 +180,13 @@ struct EDITOR_PROP {
_parent->eprops.push( { offset } );
+ parentoff = pdata - parent;
offset = _this - pdata;
dataoff = offset;
}
U64 dataoff;
+ U64 parentoff;
U8 type;
STR displayname;
F64 min{ -INFINITY };
@@ -220,22 +227,40 @@ inline EDITOR_PROP* eprop_from_ref( EOBJECT* obj, EPROP_ENTRY e ) {
return (EDITOR_PROP*)( (U64)obj + e.offset );
}
+inline EDITOR_PROP* eprop_from_ptr( EOBJECT* obj, void* ptr ) {
+ if( (U64)ptr < (U64)obj ) {
+ trace( "eprop_from_ptr() : error : invalid pointer access, obj = %llx, ptr = %llx\n", (U64)obj, (U64)ptr );
+ return 0;
+ }
+
+ U64 off = ( (U64)ptr - (U64)obj );
+ for( auto& it : obj->eprops ) {
+ EDITOR_PROP* p = eprop_from_ref( obj, it );
+ if( off == p->parentoff )
+ return p;
+ }
+
+ return 0;
+}
+
inline void* eprop_ptr( EDITOR_PROP* prop ) {
return (void*)( (U64)prop - prop->dataoff);
}
-inline EDITOR_PROP* eprop_from_name( EOBJECT* obj, STR name ) {
- FNV1A fnv = fnv1a( name );
-
+inline EDITOR_PROP* eprop_from_hash( EOBJECT* obj, FNV1A hash ) {
for( auto& it : obj->eprops ) {
EDITOR_PROP* prop = eprop_from_ref( obj, it );
- if( fnv == prop->hash )
+ if( hash == prop->hash )
return prop;
}
-
return 0;
}
+inline EDITOR_PROP* eprop_from_name( EOBJECT* obj, STR name ) {
+ FNV1A fnv = fnv1a( name );
+ return eprop_from_hash( obj, fnv );
+}
+
template <typename T>
const U8 eprop_type() {
return EDITOR_PROP::__eprop_type<T>::type;
diff --git a/src/editor/view2d.cpp b/src/editor/view2d.cpp
index c4738dd..cca83d1 100644
--- a/src/editor/view2d.cpp
+++ b/src/editor/view2d.cpp
@@ -4,7 +4,6 @@
#include "../render/gl_2d.h"
#include "../game/object.h"
#include "../game/objlist.h"
-#include "../game/world/bsp.h"
const I32 EDITORVIEW_TITLE_OFFSET = 15;
const I32 EDITORVIEW_GUTTERS_OFFSETX = 22;
@@ -839,36 +838,9 @@ VEC2 gui_editor_2dview_input_get_drag_vec( GUI_EDITOR_2DVIEW* view ) {
}
U8 gui_editor_2dview_input_select_drag_obj( GUI_EDITOR_2DVIEW* view, void* obj, U8 seltype );
-U8 gui_editor_2dview_move_group( GUI_EDITOR_2DVIEW* view ) {
- U8 update = 0;
- if( view->dragtype == EDITOR_SELECT_WVERTEX || view->dragtype == EDITOR_SELECT_PVERTEX )
- return update;
-
- GUI_EDITOR_PROPVIEW* props = editor->gui.props;
- // update all selected objects
- for( auto& it : props->curselect ) {
- if( it.obj == view->curdrag ) {
- update = 1;
- continue;
- }
+U8 gui_editor_2dview_drag_group( GUI_EDITOR_2DVIEW* view );
- // special case where a wall is selected but we are dragging one of its vertices
- if( props->curselect.size == 1 && it.seltype == EDITOR_SELECT_WALL ) {
- MAP_WALL* w = (MAP_WALL*)it.obj;
- if( &w->start == view->curdrag || &w->end == view->curdrag ) {
- update = 1;
- continue;
- }
- }
-
- if( gui_editor_2dview_input_select_drag_obj( view, it.obj, it.seltype ) )
- update = 1;
- }
-
- return update;
-}
-
-void gui_editor_2dview_input_select_onmove( GUI_EDITOR_2DVIEW* view ) {
+void gui_editor_2dview_input_select_onmove( GUI_EDITOR_2DVIEW* view, EDITOR_UNDO_PROPS* undo ) {
I32 mx, my;
gui_cursor_pos( &mx, &my );
@@ -883,7 +855,7 @@ void gui_editor_2dview_input_select_onmove( GUI_EDITOR_2DVIEW* view ) {
GUI_EDITOR_PROPVIEW* props = editor->gui.props;
U8 update = !is_zero( gui_editor_2dview_input_get_drag_vec( view ) );
if( update && gui_editor_propview_is_selected( props, view->curdrag, view->dragtype ) ) {
- if( gui_editor_2dview_move_group( view ) )
+ if( gui_editor_2dview_drag_group( view ) )
gui_editor_propview_update( props );
}
@@ -894,45 +866,109 @@ void gui_editor_2dview_input_select_onmove( GUI_EDITOR_2DVIEW* view ) {
view->dragmoved = 1;
}
-void gui_editor_2dview_input_select_drag_wall( GUI_EDITOR_2DVIEW* view, MAP_WALL* s ) {
+void gui_editor_2dview_set_undo_prop( GUI_EDITOR_2DVIEW* view, EOBJECT* target, FNV1A hash, U32 size, void* oldv, void* newv = 0 ) {
+ if( !target )
+ return;
+
+ EDITOR_UNDO_PROPS::CHANGES* target_change = view->pending_undo_props.changes.where(
+ [&]( EDITOR_UNDO_PROPS::CHANGES* c ) { return c->obj == target; }
+ );
+
+ if( !target_change ) {
+ target_change = view->pending_undo_props.changes.push( { .obj = target } );
+ }
+
+ EDITOR_UNDO_PROPS::PROP_VALUE* target_prop = target_change->props.where(
+ [&]( EDITOR_UNDO_PROPS::PROP_VALUE* p ) { return p->hash == hash; }
+ );
+
+ if( !target_prop ) {
+ target_prop = target_change->props.push( { hash, size } );
+ memcpy( target_prop->oldval.data, oldv, size );
+ }
+
+ if( target_prop->size != size ) {
+ return dlog( "gui_editor_2dview_set_undo_prop() : prop size mismatch" );
+ }
+
+ if( newv )
+ memcpy( target_prop->newval.data, newv, size );
+}
+
+void gui_editor_2dview_input_select_drag_wall(
+ GUI_EDITOR_2DVIEW* view,
+ MAP_WALL* s
+) {
gui_editor_2dview_snap_plane( &s->start );
gui_editor_2dview_snap_plane( &s->end );
VEC2 mv = gui_editor_2dview_input_get_drag_vec( view );
if( !is_zero( mv ) ) {
+ VEC3 olds = s->start;
+ VEC3 olde = s->end;
gui_editor_2dview_add_plane_delta( &s->start, mv );
gui_editor_2dview_add_plane_delta( &s->end, mv );
+
+ EDITOR_PROP* sprop = eprop_from_ptr( s, &s->start );
+ EDITOR_PROP* eprop = eprop_from_ptr( s, &s->end );
+
+ gui_editor_2dview_set_undo_prop( view, s, sprop->hash, sprop->size, &olds, &s->start );
+ gui_editor_2dview_set_undo_prop( view, s, eprop->hash, eprop->size, &olde, &s->end );
+
map_check_bounds( editor->map );
}
}
-void gui_editor_2dview_input_select_drag_pos( GUI_EDITOR_2DVIEW* view, VEC3* v ) {
+void gui_editor_2dview_input_select_drag_wallpos(
+ GUI_EDITOR_2DVIEW* view,
+ VEC3* v
+) {
gui_editor_2dview_snap_plane( v );
VEC2 mv = gui_editor_2dview_input_get_drag_vec( view );
if( !is_zero( mv ) ) {
+ VEC3 oldv = *v;
gui_editor_2dview_add_plane_delta( v, mv );
map_check_bounds( editor->map );
+
+ // giga hack
+ EDITOR_PROP* p = (EDITOR_PROP*)( (U64)v + sizeof(VEC3) );
+ MAP_WALL* s = (MAP_WALL*)( (U64)v - p->parentoff );
+ gui_editor_2dview_set_undo_prop( view, s, p->hash, p->size, &oldv, v );
}
}
-void gui_editor_2dview_input_select_drag_vertex( GUI_EDITOR_2DVIEW* view, MAP_VERTEX* v ) {
+void gui_editor_2dview_input_select_drag_vertex(
+ GUI_EDITOR_2DVIEW* view,
+ MAP_VERTEX* v
+) {
gui_editor_2dview_snap_plane( &v->pos );
VEC2 mv = gui_editor_2dview_input_get_drag_vec( view );
if( !is_zero( mv ) ) {
+ VEC3 oldv = v->pos;
gui_editor_2dview_add_plane_delta( &v->pos, mv );
map_check_bounds( editor->map );
+
+ EDITOR_PROP* p = eprop_from_ptr( v, &v->pos );
+ gui_editor_2dview_set_undo_prop( view, v, p->hash, p->size, &oldv, &v->pos );
}
}
-void gui_editor_2dview_input_select_drag_polygon( GUI_EDITOR_2DVIEW* view, MAP_POLYGON* p ) {
+void gui_editor_2dview_input_select_drag_polygon(
+ GUI_EDITOR_2DVIEW* view,
+ MAP_POLYGON* p
+) {
VEC2 mv = gui_editor_2dview_input_get_drag_vec( view );
if( !is_zero( mv ) ) {
p->vertices.each( fn( MAP_VERTEX* v ) {
+ VEC3 oldv = v->pos;
gui_editor_2dview_snap_plane( &v->pos );
gui_editor_2dview_add_plane_delta( &v->pos, mv );
+
+ EDITOR_PROP* p = eprop_from_ptr( v, &v->pos );
+ gui_editor_2dview_set_undo_prop( view, v, p->hash, p->size, &oldv, &v->pos );
} );
map_polygon_calc_bounds( p );
@@ -940,31 +976,51 @@ void gui_editor_2dview_input_select_drag_polygon( GUI_EDITOR_2DVIEW* view, MAP_P
}
}
-void gui_editor_2dview_input_select_drag_sprite( GUI_EDITOR_2DVIEW* view, MAP_SPRITE* s ) {
+void gui_editor_2dview_input_select_drag_sprite(
+ GUI_EDITOR_2DVIEW* view,
+ MAP_SPRITE* s
+) {
gui_editor_2dview_snap_plane( &s->pos );
VEC2 mv = gui_editor_2dview_input_get_drag_vec( view );
if( !is_zero( mv ) ) {
+ VEC3 oldv = s->pos;
gui_editor_2dview_add_plane_delta( &s->pos, mv );
+
+ EDITOR_PROP* p = eprop_from_ptr( s, &s->pos );
+ gui_editor_2dview_set_undo_prop( view, s, p->hash, p->size, &oldv, &s->pos );
}
}
-
-void gui_editor_2dview_input_select_drag_entity( GUI_EDITOR_2DVIEW* view, MAP_ENTITY* e ) {
+void gui_editor_2dview_input_select_drag_entity(
+ GUI_EDITOR_2DVIEW* view,
+ MAP_ENTITY* e
+) {
gui_editor_2dview_snap_plane( &e->pos );
VEC2 mv = gui_editor_2dview_input_get_drag_vec( view );
if( !is_zero( mv ) ) {
+ VEC3 oldv = e->pos;
gui_editor_2dview_add_plane_delta( &e->pos, mv );
+
+ EDITOR_PROP* p = eprop_from_ptr( e, &e->pos );
+ gui_editor_2dview_set_undo_prop( view, e, p->hash, p->size, &oldv, &e->pos );
}
}
-void gui_editor_2dview_input_select_drag_origin( GUI_EDITOR_2DVIEW* view, WORLD_MAP* m ) {
+void gui_editor_2dview_input_select_drag_origin(
+ GUI_EDITOR_2DVIEW* view,
+ WORLD_MAP* m
+) {
gui_editor_2dview_snap_plane( &m->startpos );
VEC2 mv = gui_editor_2dview_input_get_drag_vec( view );
if( !is_zero( mv ) ) {
+ VEC3 oldv = m->startpos;
gui_editor_2dview_add_plane_delta( &m->startpos, mv );
+
+ EDITOR_PROP* p = eprop_from_ptr( m, &m->startpos );
+ gui_editor_2dview_set_undo_prop( view, m, p->hash, p->size, &oldv, &m->startpos );
}
}
@@ -980,7 +1036,7 @@ U8 gui_editor_2dview_input_select_drag_obj( GUI_EDITOR_2DVIEW* view, void* obj,
case EDITOR_SELECT_SPRITE: gui_editor_2dview_input_select_drag_sprite( view, (MAP_SPRITE*)p ); return 1;
case EDITOR_SELECT_ORIGIN: gui_editor_2dview_input_select_drag_origin( view, (WORLD_MAP*)p ); return 1;
case EDITOR_SELECT_PVERTEX: gui_editor_2dview_input_select_drag_vertex( view, (MAP_VERTEX*)p ); return 1;
- case EDITOR_SELECT_WVERTEX: gui_editor_2dview_input_select_drag_pos( view, (VEC3*)p ); return 1;
+ case EDITOR_SELECT_WVERTEX: gui_editor_2dview_input_select_drag_wallpos( view, (VEC3*)p ); return 1;
}
return 0;
@@ -990,9 +1046,45 @@ void gui_editor_2dview_input_select_ondrop( GUI_EDITOR_2DVIEW* view ) {
if( !view->dragmoved )
gui_editor_propview_select( editor->gui.props, view->curdrag, view->dragtype, !input.keys[SDL_SCANCODE_LCTRL] );
+ if( view->pending_undo_props.changes.size ) {
+ EDITOR_UNDO_ACTION rec{ .type = EDITOR_UNDO_EDITPROPS, .props = view->pending_undo_props };
+ editor->undo_actions.push( rec );
+ view->pending_undo_props = {};
+ }
+
view->curdrag = 0;
}
+U8 gui_editor_2dview_drag_group( GUI_EDITOR_2DVIEW* view ) {
+ U8 update = 0;
+ if( view->dragtype == EDITOR_SELECT_WVERTEX || view->dragtype == EDITOR_SELECT_PVERTEX )
+ return update;
+
+ GUI_EDITOR_PROPVIEW* props = editor->gui.props;
+ // update all selected objects
+ for( auto& it : props->curselect ) {
+ if( it.obj == view->curdrag ) {
+ update = 1;
+ continue;
+ }
+
+ // special case where a wall is selected but we are dragging one of its vertices
+ if( props->curselect.size == 1 && it.seltype == EDITOR_SELECT_WALL ) {
+ MAP_WALL* w = (MAP_WALL*)it.obj;
+ if( &w->start == view->curdrag || &w->end == view->curdrag ) {
+ update = 1;
+ continue;
+ }
+ }
+
+ if( gui_editor_2dview_input_select_drag_obj( view, it.obj, it.seltype ) ) {
+ update = 1;
+ }
+ }
+
+ return update;
+}
+
void gui_editor_2dview_input_select_drag( GUI_EDITOR_2DVIEW* view ) {
U8 m1 = gui_mbutton_down( 0 );
I32 mx, my;
@@ -1017,15 +1109,17 @@ void gui_editor_2dview_input_select_drag( GUI_EDITOR_2DVIEW* view ) {
return;
}
+ EDITOR_UNDO_ACTION rec{ .type = EDITOR_UNDO_EDITPROPS };
+ EDITOR_UNDO_PROPS::CHANGES changes{ .obj = (EOBJECT*)view->curdrag };
if( !gui_editor_2dview_input_select_drag_obj( view, view->curdrag, view->dragtype ) ) {
view->oldmx = mx;
view->oldmy = my;
return;
}
- VEC2 mv = gui_editor_2dview_input_get_drag_vec( view );
- if( !is_zero( mv ) ) {
- gui_editor_2dview_input_select_onmove( view );
+ if( !is_zero( gui_editor_2dview_input_get_drag_vec( view ) ) ) {
+ gui_editor_2dview_input_select_onmove( view, &rec.props );
+ rec.props.changes.push( changes );
}
}