summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoraura <nw@moneybot.cc>2026-07-28 19:11:34 +0200
committeraura <nw@moneybot.cc>2026-07-28 19:11:34 +0200
commit86d248ed2b033fe36ce53b0387b2cbdcb69c0b72 (patch)
treea70f32a0f44b927a6d137998efa405e330689c0f
parent468813b133a6a3ff0b85d3b34f1009cfeae815e4 (diff)
finish undo/redo
-rw-r--r--src/editor/editor.cpp54
-rw-r--r--src/editor/editor.h25
-rw-r--r--src/editor/properties.cpp127
-rw-r--r--src/editor/texturepicker.cpp3
-rw-r--r--src/editor/view2d.cpp6
-rw-r--r--src/game.cpp6
-rw-r--r--src/gui/base.h9
-rw-r--r--src/gui/button.cpp6
-rw-r--r--src/gui/checkbox.cpp4
-rw-r--r--src/gui/floatinput.cpp53
-rw-r--r--src/gui/list.cpp6
-rw-r--r--src/gui/textbox.cpp10
-rw-r--r--src/gui/vectorinput.cpp17
-rw-r--r--src/render/gl.cpp9
-rw-r--r--src/util/allocator.h1
-rw-r--r--src/util/typedef.h2
16 files changed, 225 insertions, 113 deletions
diff --git a/src/editor/editor.cpp b/src/editor/editor.cpp
index 72ca4d2..2e76039 100644
--- a/src/editor/editor.cpp
+++ b/src/editor/editor.cpp
@@ -32,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 EDITOR_UNDO_ACTION& action ) {
+void editor_push_undo_action( GAME_EDITOR* e, EDITOR_UNDO_ACTION action ) {
if( !e )
return;
@@ -267,7 +267,7 @@ void editor_undo_record_create_walls( GAME_EDITOR* e, I32 start_idx, I32 count )
return;
EDITOR_UNDO_ACTION action{};
- action.type = EDITOR_UNDO_CREATE_WALLS;
+ action.typemask = EDITOR_UNDO_CREATE_WALLS;
action.create.start_idx = start_idx;
for( I32 i = 0; i < count; ++i )
action.create.walls.push( map->walls[start_idx + i] );
@@ -284,7 +284,7 @@ void editor_undo_record_create_poly( GAME_EDITOR* e, I32 start_idx ) {
return;
EDITOR_UNDO_ACTION action{
- .type = EDITOR_UNDO_CREATE_POLY,
+ .typemask = EDITOR_UNDO_CREATE_POLY,
.create = { .start_idx = start_idx }
};
action.create.polys.push( map->polygons[start_idx] );
@@ -301,7 +301,7 @@ void editor_undo_record_create_sprite( GAME_EDITOR* e, I32 start_idx ) {
return;
EDITOR_UNDO_ACTION action = {
- .type = EDITOR_UNDO_CREATE_SPRITES,
+ .typemask = EDITOR_UNDO_CREATE_SPRITES,
.create = { .start_idx = start_idx }
};
@@ -319,7 +319,7 @@ void editor_undo_record_create_entity( GAME_EDITOR* e, I32 start_idx ) {
return;
EDITOR_UNDO_ACTION action{
- .type = EDITOR_UNDO_CREATE_ENTITIES,
+ .typemask = EDITOR_UNDO_CREATE_ENTITIES,
.create = { .start_idx = start_idx }
};
action.create.entities.push( map->entities[start_idx] );
@@ -334,7 +334,7 @@ void editor_undo_record_change_prop( GAME_EDITOR* e, FNV1A hash, void* oldv, voi
if( !e || !e->map )
return;
- EDITOR_UNDO_ACTION rec{ .type = EDITOR_UNDO_EDITPROPS };
+ EDITOR_UNDO_ACTION rec{ .typemask = EDITOR_UNDO_EDITPROPS };
for( auto e : e->gui.props->curselect ) {
EDITOR_UNDO_PROPS::CHANGES changes{};
@@ -344,16 +344,16 @@ void editor_undo_record_change_prop( GAME_EDITOR* e, FNV1A hash, void* oldv, voi
rec.props.changes.push( changes );
}
- e->undo_actions.push( rec );
+ editor_push_undo_action( e, rec );
}
-U8 editor_apply_undo_action_reverse_create( GAME_EDITOR* e, EDITOR_UNDO_ACTION& action ) {
+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;
U8 clear_view_drag = 0;
- switch( action.type ) {
+ switch( action.typemask ) {
case EDITOR_UNDO_CREATE_WALLS: {
I32 count = (I32)action.create.walls.size;
for( I32 i = count - 1; i >= 0; --i ) {
@@ -444,7 +444,7 @@ U8 editor_apply_undo_action_reverse_create( GAME_EDITOR* e, EDITOR_UNDO_ACTION&
return 1;
}
-U8 editor_apply_undo_action_reverse_props( GAME_EDITOR* e, 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 ) {
@@ -464,17 +464,37 @@ U8 editor_apply_undo_action_reverse_props( GAME_EDITOR* e, EDITOR_UNDO_ACTION& a
return 1;
}
+U8 editor_apply_undo_action_reverse_mapprop( GAME_EDITOR* e, EDITOR_UNDO_ACTION action ) {
+ if( !e->map )
+ return 0;
+
+ if( action.mapprop.ref.id > e->map->props.size ) {
+ dlog( "editor_apply_undo_action_reverse_mapprop() : warn: attempted to remove non-existent prop %x\n", action.mapprop.ref.id );
+ return 0;
+ }
+
+ // todo : replace with proper slots
+ e->map->props.erase( action.mapprop.ref.id );
+ editor_update_properties_column( e );
+ 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 );
+ U8 ret = 0;
+ if( action.typemask & EDITOR_UNDO_EDITPROPS )
+ ret |= editor_apply_undo_action_reverse_props( e, action );
+ if( action.typemask & EDITOR_UNDO_CREATE_MAPPROP )
+ ret |= editor_apply_undo_action_reverse_mapprop( e, action );
+ if( action.typemask & EDITOR_UNDO_CREATE_EOBJ )
+ ret |= editor_apply_undo_action_reverse_create( e, action );
- return editor_apply_undo_action_reverse_create( e, action );
+ return ret;
}
-U8 editor_apply_undo_action_forward_props( GAME_EDITOR* e, EDITOR_UNDO_ACTION& 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 ) {
@@ -494,9 +514,9 @@ U8 editor_apply_undo_action_forward_props( GAME_EDITOR* e, EDITOR_UNDO_ACTION& a
return 1;
}
-U8 editor_apply_undo_action_forward_create( GAME_EDITOR* e, EDITOR_UNDO_ACTION& action ) {
+U8 editor_apply_undo_action_forward_create( GAME_EDITOR* e, EDITOR_UNDO_ACTION action ) {
WORLD_MAP* map = e->map;
- switch( action.type ) {
+ switch( action.typemask ) {
case EDITOR_UNDO_CREATE_WALLS: {
if( !action.create.walls.size )
return 0;
@@ -542,7 +562,7 @@ 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 )
+ if( action.typemask == EDITOR_UNDO_EDITPROPS )
return editor_apply_undo_action_forward_props( e, action );
return editor_apply_undo_action_forward_create( e, action );
diff --git a/src/editor/editor.h b/src/editor/editor.h
index b506d9c..3d27951 100644
--- a/src/editor/editor.h
+++ b/src/editor/editor.h
@@ -36,11 +36,16 @@ enum EditorSelectType_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_EDITPROPS = 5
+ EDITOR_UNDO_CREATE_WALLS = 1 << 1,
+ EDITOR_UNDO_CREATE_POLY = 1 << 2,
+ EDITOR_UNDO_CREATE_SPRITES = 1 << 3,
+ EDITOR_UNDO_CREATE_ENTITIES = 1 << 4,
+ EDITOR_UNDO_EDITPROPS = 1 << 5,
+ EDITOR_UNDO_CREATE_MAPPROP = 1 << 6,
+
+
+
+ EDITOR_UNDO_CREATE_EOBJ = EDITOR_UNDO_CREATE_WALLS | EDITOR_UNDO_CREATE_POLY | EDITOR_UNDO_CREATE_SPRITES | EDITOR_UNDO_CREATE_ENTITIES,
};
enum EditorInfoBoxType_t {
@@ -140,10 +145,15 @@ struct EDITOR_UNDO_CREATE {
LIST<MAP_ENTITY> entities{};
};
+struct EDITOR_UNDO_MAPPROP {
+ MAP_PROPREF ref;
+};
+
struct EDITOR_UNDO_ACTION {
- U8 type;
+ U64 typemask;
EDITOR_UNDO_PROPS props;
EDITOR_UNDO_CREATE create;
+ EDITOR_UNDO_MAPPROP mapprop;
};
struct GAME_EDITOR {
@@ -247,6 +257,7 @@ extern LIST<GUI_LIST_ENTRY>* editor_get_map_list( GAME_EDITOR* e );
extern void editor_load_map_cb( void* );
extern void editor_new_map_cb( void* );
+extern void editor_push_undo_action( GAME_EDITOR* e, EDITOR_UNDO_ACTION action );
extern void editor_create_map_view( GAME_EDITOR* e );
extern void editor_update_properties_column( GAME_EDITOR* e );
extern const char* editor_tool_name();
@@ -317,6 +328,7 @@ struct GUI_EDITOR_PROPVIEW : GUI_VIEW {
LIST<PROPVIEW_SELECT> curselect;
LIST<EDITOR_PROP*> curprops;
GUI_VIEW* itemview;
+ EDITOR_UNDO_ACTION pending_undo;
};
struct GUI_EDITOR_TOOLVIEW : GUI_VIEW {
@@ -348,6 +360,7 @@ struct GUI_EDITOR_TEXTUREPICKER : GUI_WINDOW {
GUI_LABEL* densitylabel;
GUI_CALLBACK cb;
+ GUI_CALLBACK pre_cb;
void* cbextra;
};
diff --git a/src/editor/properties.cpp b/src/editor/properties.cpp
index 109e622..dc2233d 100644
--- a/src/editor/properties.cpp
+++ b/src/editor/properties.cpp
@@ -112,7 +112,6 @@ 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 );
@@ -121,26 +120,19 @@ 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 ) {
- 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 ) {
if( view->curselect.size < 2 ) return;
- EDITOR_PROP** pptr = view->curprops.where( fn( EDITOR_PROP** pptr ) { return (*pptr)->displayname == propname; } );
+ FNV1A hash = fnv1a( propname );
+ EDITOR_PROP** pptr = view->curprops.where( fn( EDITOR_PROP** pptr ) { return (*pptr)->hash == hash; } );
if( !pptr )
return;
@@ -151,7 +143,6 @@ void gui_editor_propview_sync_props_fdiff( GUI_EDITOR_PROPVIEW* view, EDITOR_PRO
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 );
@@ -162,21 +153,10 @@ 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 ) {
@@ -188,6 +168,54 @@ void gui_editor_propview_sync_props_fdiff( GUI_EDITOR_PROPVIEW* view, const char
gui_editor_propview_sync_props_fdiff( view, *pptr, fdiff, valc );
}
+void gui_editor_propview_undo_eprop_start( GUI_EDITOR_PROPVIEW* view, EDITOR_PROP* prop ) {
+ view->pending_undo.typemask |= EDITOR_UNDO_EDITPROPS;
+ for( auto& it : view->curselect ) {
+ EDITOR_PROP* tprop = eprop_from_hash( (EOBJECT*)it.obj, prop->hash );
+ if( !tprop ) continue;
+
+ EDITOR_UNDO_PROPS* undo_props = &view->pending_undo.props;
+ EDITOR_UNDO_PROPS::CHANGES* change = undo_props->changes.where( fn( EDITOR_UNDO_PROPS::CHANGES* v ) {
+ return v->obj == (EOBJECT*)it.obj;
+ } );
+
+ if( !change ) {
+ change = undo_props->changes.push( { .obj = (EOBJECT*)it.obj } );
+ }
+
+ EDITOR_UNDO_PROPS::PROP_VALUE* propv = change->props.where( fn( EDITOR_UNDO_PROPS::PROP_VALUE* v ) {
+ return v->hash == prop->hash;
+ } );
+
+ if( propv ) {
+ continue;
+ }
+
+ propv = change->props.push( { tprop->hash, tprop->size } );
+ memcpy( propv->oldval.data, eprop_ptr( tprop ), tprop->size );
+ }
+}
+
+void gui_editor_propview_undo_mapprop( GUI_EDITOR_PROPVIEW* view, EDITOR_PROP* prop ) {
+ view->pending_undo.typemask |= EDITOR_UNDO_CREATE_MAPPROP;
+ view->pending_undo.mapprop.ref = *(MAP_PROPREF*)eprop_ptr( prop );
+}
+
+void gui_editor_propview_undo_commit( GUI_EDITOR_PROPVIEW* view ) {
+ for( auto& it : view->pending_undo.props.changes ) {
+ EOBJECT* obj = it.obj;
+ for( auto& it2 : it.props ) {
+ EDITOR_PROP* tprop = eprop_from_hash( obj, it2.hash );
+ if( !tprop ) continue;
+
+ memcpy( it2.newval.data, eprop_ptr( tprop ), tprop->size );
+ }
+ }
+
+ editor_push_undo_action( editor, view->pending_undo );
+ view->pending_undo = {};
+}
+
// todo : int diff
struct TEXBTN_CB {
@@ -211,26 +239,22 @@ void gui_editor_propview_create_eobj_prop( GUI_EDITOR_PROPVIEW* view, EDITOR_PRO
switch( prop->type ) {
case EPROP_F32: { GUI_FLOATINPUT* in = gui_floatinput( *x, *y, w, n, (F32*)eprop_ptr( prop ), min, max, step );
in->drawval = val;
- in->cb = pfn( void* ptr ) {
- GUI_FLOATINPUT* fin = (GUI_FLOATINPUT*)ptr;
- gui_editor_propview_sync_props_fdiff( editor->gui.props, (EDITOR_PROP*)fin->cbextra, &fin->lastchange, 1 );
- }; in->cbextra = prop;
+ in->pre_cb = cfn( void* ) { gui_editor_propview_undo_eprop_start( view, prop ); };
+ in->cb = cfn( void* ) { gui_editor_propview_sync_props_fdiff( editor->gui.props, prop, &in->lastchange, 1 ); };
+ in->release_cb = cfn( void* ) { gui_editor_propview_undo_commit( editor->gui.props ); };
*y += (s+18);
} break;
case EPROP_VEC2: case EPROP_VEC3: case EPROP_VEC4: { U32 c = prop->type - EPROP_VEC2 + 2;
GUI_VECTORINPUT* in = gui_vectorinput( *x, *y, w, n, (F32*)eprop_ptr( prop ), c, min, max, step, "xyzw", c == 2 ? "%.03f" : "%0.02f", val );
- in->cb = pfn( void* ptr ) {
- GUI_VECTORINPUT* vin = (GUI_VECTORINPUT*)ptr;
- gui_editor_propview_sync_props_fdiff( editor->gui.props, (EDITOR_PROP*)vin->cbextra, vin->lastchange.data, vin->inputs.size );
- }; in->cbextra = prop;
-
+ in->pre_cb = cfn( void* ) { gui_editor_propview_undo_eprop_start( view, prop ); };
+ in->cb = cfn( void* ) { gui_editor_propview_sync_props_fdiff( editor->gui.props, prop, in->lastchange.data, in->inputs.size ); };
+ in->release_cb = cfn( void* ) { gui_editor_propview_undo_commit( editor->gui.props ); };
*y += (s+18);
} break;
- case EPROP_CLR: { GUI_COLORINPUT* cin = gui_colorinput( *x, *y, w, n, (CLR*)eprop_ptr( prop ) );
- cin->cb = pfn( void* ptr ) {
- GUI_COLORINPUT* cin = (GUI_COLORINPUT*)ptr;
- gui_editor_propview_sync_props_fdiff( editor->gui.props, (EDITOR_PROP*)cin->cbextra, cin->lastchange.data, cin->inputs.size );
- }; cin->cbextra = prop;
+ case EPROP_CLR: { GUI_COLORINPUT* in = gui_colorinput( *x, *y, w, n, (CLR*)eprop_ptr( prop ) );
+ in->pre_cb = cfn( void* ) { gui_editor_propview_undo_eprop_start( view, prop ); };
+ in->cb = cfn( void* ) { gui_editor_propview_sync_props_fdiff( editor->gui.props, prop, in->lastchange.data, in->inputs.size ); };
+ in->release_cb = cfn( void* ) { gui_editor_propview_undo_commit( editor->gui.props ); };
*y += (s+18);
}break;
case EPROP_MAPPROP: {
@@ -239,18 +263,19 @@ void gui_editor_propview_create_eobj_prop( GUI_EDITOR_PROPVIEW* view, EDITOR_PRO
if( val ) gui_label( *x, *y, "prop id: %d", *ref );
else gui_label( *x, *y, "prop id: *" );
- GUI_BUTTON* newprop = gui_button( action2_x, *y, 20, 20, "+", pfn( void* ptr ) {
- GUI_BUTTON* btn = (GUI_BUTTON*)ptr;
+ gui_button( action2_x, *y, 20, 20, "+", cfn( void* ) {
SURF_PROPS props{ .tex = 0, .clr = CLR::WHITE() };
editor->map->props.push( props );
- EDITOR_PROP* eprop = (EDITOR_PROP*)btn->extra;
- MAP_PROPREF* ref = (MAP_PROPREF*)eprop_ptr( eprop );
+ MAP_PROPREF* ref = (MAP_PROPREF*)eprop_ptr( prop );
+ gui_editor_propview_undo_eprop_start( view, prop );
(ref)->id = editor->map->props.size - 1;
editor->gui.assets_scroll = ( editor->map->props.size + 1 ) * 28;
- gui_editor_propview_sync_props_value( editor->gui.props, eprop );
+ gui_editor_propview_undo_mapprop( view, prop );
+ gui_editor_propview_sync_props_value( editor->gui.props, prop );
+ gui_editor_propview_undo_commit( view );
gui_editor_propview_update( editor->gui.props );
- } ); newprop->extra = prop;
+ } );
if( val ) {
GUI_BUTTON* goprop = gui_button( action_x, *y, 20, 20, "\x1A", pfn( void* ptr ) {
@@ -265,16 +290,15 @@ void gui_editor_propview_create_eobj_prop( GUI_EDITOR_PROPVIEW* view, EDITOR_PRO
if( val && *tex ) gui_label( *x, *y, "%s: %s", n, (*tex)->name );
else if( !val ) gui_label( *x, *y, "%s: *", n );
else gui_label( *x, *y, "%s: none", n );
- GUI_BUTTON* btn = gui_button( action_x, *y, 20, 20, "\x1A", cfn( 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* p ) {
- GUI_EDITOR_TEXTUREPICKER* picker = (GUI_EDITOR_TEXTUREPICKER*)p;
- gui_editor_propview_sync_props_value( editor->gui.props, (EDITOR_PROP*)picker->cbextra );
+ gui_button( action_x, *y, 20, 20, "\x1A", cfn( void* ptr ) {
+ GUI_EDITOR_TEXTUREPICKER* picker = gui_editor_texturepicker( 200, 100, 400, 400, tex );
+ picker->pre_cb = cfn( void* ) { gui_editor_propview_undo_eprop_start( view, prop ); };
+ picker->cb = cfn( void* p ) {
+ gui_editor_propview_sync_props_value( editor->gui.props, prop );
+ gui_editor_propview_undo_commit( view );
gui_editor_propview_update( editor->gui.props );
- }; picker->cbextra = prop;
- } ); btn->extra = tex; *y += s;
+ };
+ } ); *y += s;
} break;
case EPROP_VERTEX_LIST: {
LIST<MAP_VERTEX>* list = ( LIST<MAP_VERTEX>* )eprop_ptr( prop );
@@ -612,6 +636,7 @@ GUI_EDITOR_PROPVIEW* gui_editor_propview( I32 x, I32 y, I32 w, I32 h ) {
view->input_fn = gui_base_input_fn;
view->curselect = {};
+ view->pending_undo = {};
GUI_VIEW* parent = gui_get_view();
parent->children.push( view );
diff --git a/src/editor/texturepicker.cpp b/src/editor/texturepicker.cpp
index 621f0c2..1152ef7 100644
--- a/src/editor/texturepicker.cpp
+++ b/src/editor/texturepicker.cpp
@@ -192,6 +192,9 @@ void gui_editor_textureview_accept( GUI_EDITOR_TEXTUREPICKER* wnd ) {
gl_texture_destroy( _gui.batch->gl, tex );
} );
+ if( wnd->pre_cb )
+ wnd->pre_cb( wnd );
+
if( !isnone ) {
if( map_add_texture_ref( editor->map, wnd->curselect ) == STAT_ALREADYEXISTS ) {
const char* name = assets_abspath( wnd->curselect->name );
diff --git a/src/editor/view2d.cpp b/src/editor/view2d.cpp
index cca83d1..fe82c08 100644
--- a/src/editor/view2d.cpp
+++ b/src/editor/view2d.cpp
@@ -1047,8 +1047,8 @@ void gui_editor_2dview_input_select_ondrop( GUI_EDITOR_2DVIEW* view ) {
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 );
+ EDITOR_UNDO_ACTION rec{ .typemask = EDITOR_UNDO_EDITPROPS, .props = view->pending_undo_props };
+ editor_push_undo_action( editor, rec );
view->pending_undo_props = {};
}
@@ -1109,7 +1109,7 @@ void gui_editor_2dview_input_select_drag( GUI_EDITOR_2DVIEW* view ) {
return;
}
- EDITOR_UNDO_ACTION rec{ .type = EDITOR_UNDO_EDITPROPS };
+ EDITOR_UNDO_ACTION rec{ .typemask = 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;
diff --git a/src/game.cpp b/src/game.cpp
index 523e884..7b526ae 100644
--- a/src/game.cpp
+++ b/src/game.cpp
@@ -224,6 +224,12 @@ void game_on_tick( GAME_DATA* game ) { _profiled
}
void game_destroy( GAME_DATA *game ) {
+#if IS_EDITOR
+ editor_destroy( game->editor );
+#endif
+ if( game->state.map )
+ map_free( game, game->state.map );
+
gl_batch_destroy( game->render.batch_2d );
gl_batch_destroy( game->render.batch_3d );
gl_destroy( game->gl );
diff --git a/src/gui/base.h b/src/gui/base.h
index 1a1c4cb..108988d 100644
--- a/src/gui/base.h
+++ b/src/gui/base.h
@@ -169,10 +169,12 @@ struct GUI_LIST : GUI_BASE {
U8 held;
GUI_CALLBACK cb;
+ GUI_CALLBACK pre_cb;
};
struct GUI_BUTTON : GUI_BASE {
GUI_CALLBACK cb;
+ GUI_CALLBACK pre_cb;
U8 held;
void* extra;
};
@@ -182,6 +184,7 @@ struct GUI_CHECKBOX : GUI_BASE {
U8* pval;
GUI_CALLBACK cb;
+ GUI_CALLBACK pre_cb;
};
struct GUI_DROPDOWN : GUI_BASE {
@@ -190,6 +193,7 @@ struct GUI_DROPDOWN : GUI_BASE {
U8 held;
GUI_CALLBACK cb;
+ GUI_CALLBACK pre_cb;
GUI_WINDOW* listwnd;
GUI_VIEW* listview;
};
@@ -216,6 +220,7 @@ struct GUI_TEXTBOX : GUI_BASE {
U8 m1held;
GUI_CALLBACK cb;
+ GUI_CALLBACK pre_cb;
};
struct GUI_CONTEXTBOX : GUI_BASE {
@@ -243,6 +248,8 @@ struct GUI_FLOATINPUT : GUI_BASE {
U8 wraparound;
GUI_CALLBACK cb;
+ GUI_CALLBACK pre_cb;
+ GUI_CALLBACK release_cb;
void* cbextra;
};
@@ -261,6 +268,8 @@ struct GUI_VECTORINPUT : GUI_VIEW {
LIST<F32> lastchange;
GUI_CALLBACK cb;
+ GUI_CALLBACK pre_cb;
+ GUI_CALLBACK release_cb;
void* cbextra;
};
diff --git a/src/gui/button.cpp b/src/gui/button.cpp
index e66130b..7cf0524 100644
--- a/src/gui/button.cpp
+++ b/src/gui/button.cpp
@@ -48,8 +48,10 @@ void gui_button_input_fn( void* ptr ) {
// button could be destroyed by callback
U8 was_held = btn->held;
btn->held = 0;
- if( inbounds && was_held )
- btn->cb( btn );
+ if( inbounds && was_held ) {
+ if( btn->pre_cb ) btn->pre_cb( btn );
+ if( btn->cb ) btn->cb( btn );
+ }
return;
}
diff --git a/src/gui/checkbox.cpp b/src/gui/checkbox.cpp
index 02cadc6..97ce804 100644
--- a/src/gui/checkbox.cpp
+++ b/src/gui/checkbox.cpp
@@ -40,9 +40,9 @@ void gui_checkbox_input_fn( void* ptr ) {
U8 was_held = check->held;
check->held = 0;
if( inbounds && was_held ) {
+ if( check->pre_cb ) check->pre_cb( check );
*check->pval = !*check->pval;
- if( check->cb )
- check->cb( check );
+ if( check->cb ) check->cb( check );
}
return;
diff --git a/src/gui/floatinput.cpp b/src/gui/floatinput.cpp
index 095c562..8e3fc2c 100644
--- a/src/gui/floatinput.cpp
+++ b/src/gui/floatinput.cpp
@@ -169,6 +169,7 @@ void gui_floatinput_input_bound( GUI_FLOATINPUT* input ) {
return;
F32 oldval = *input->pval;
+ F32 val = oldval;
I32 x = gui_relx( input );
I32 w = gui_floatinput_content_w( input );
@@ -184,9 +185,13 @@ void gui_floatinput_input_bound( GUI_FLOATINPUT* input ) {
F32 nval = min + (max - min) * progress;
F32 rmn = remainderf( nval, input->step );
- *input->pval = nval - rmn;
- if( oldval != *input->pval )
- input->lastchange = *input->pval - oldval;
+ val = nval - rmn;
+ if( oldval != val ) {
+ if( input->pre_cb ) input->pre_cb( input );
+ input->lastchange = val - oldval;
+ *input->pval = val;
+ if( input->cb ) input->cb( input );
+ }
}
void gui_floatinput_input_unbound( GUI_FLOATINPUT* input ) {
@@ -197,22 +202,28 @@ void gui_floatinput_input_unbound( GUI_FLOATINPUT* input ) {
gui_cursor_pos( &mx, &my );
F32 oldval = *input->pval;
+ F32 val = oldval;
I32 dx = mx - input->lastmx;
if( dx )
- *input->pval += dx * input->step;
+ val += dx * input->step;
F32 min = input->min;
F32 max = input->max;
- if( isfinite( min ) && *input->pval < min )
- *input->pval = input->wraparound? max : min;
- if( isfinite( max ) && *input->pval > max )
- *input->pval = input->wraparound? min : max;
+ if( isfinite( min ) && val < min )
+ val = input->wraparound? max : min;
+ if( isfinite( max ) && val > max )
+ val = input->wraparound? min : max;
- F32 rmn = remainderf( *input->pval, input->step );
- *input->pval -= rmn;
- if( oldval != *input->pval )
- input->lastchange = *input->pval - oldval;
+ F32 rmn = remainderf( val, input->step );
+ val -= rmn;
+
+ if( val != oldval ) {
+ if( input->pre_cb ) input->pre_cb( input );
+ input->lastchange = val - oldval;
+ *input->pval = val;
+ if( input->cb ) input->cb( input );
+ }
}
void gui_floatinput_input_scroll( GUI_FLOATINPUT* input ) {
@@ -234,12 +245,12 @@ void gui_floatinput_input_scroll( GUI_FLOATINPUT* input ) {
if( isfinite( input->max ) && nval > input->max )
nval = input->wraparound? input->min : input->max;
+ if( input->pre_cb ) input->pre_cb( input );
F32 rmn = remainderf( nval, input->step );
*input->pval = nval - rmn;
input->lastchange = *input->pval - oldval;
- if( input->cb )
- input->cb( input );
+ if( input->cb ) input->cb( input );
}
void gui_floatinput_input_fn( void* ptr ) {
@@ -276,11 +287,13 @@ void gui_floatinput_input_fn( void* ptr ) {
U8 inc = my < split_y;
F32 step = fine ? 0.1f : 1.f;
F32 val = *input->pval;
+
+ if( input->pre_cb ) input->pre_cb( input );
*input->pval += inc ? step : -step;
gui_floatinput_clamp_and_snap( input );
input->lastchange = *input->pval - val;
- if( input->cb )
- input->cb( input );
+ if( input->cb ) input->cb( input );
+
input->held = 1;
}
return;
@@ -298,6 +311,8 @@ void gui_floatinput_input_fn( void* ptr ) {
if( !m1 ) {
input->heldoutbounds = 0;
+ if( input->release_cb && input->held )
+ input->release_cb( input );
input->held = 0;
return;
}
@@ -305,17 +320,12 @@ void gui_floatinput_input_fn( void* ptr ) {
if( input->heldoutbounds )
return;
- F32 oldv = *input->pval;
if( !gui_floatinput_is_bound_val( input ) )
gui_floatinput_input_unbound( input );
else
gui_floatinput_input_bound( input );
gui_floatinput_clamp_and_snap( input );
- if( input->cb && oldv != *input->pval ) {
- input->cb( input );
- }
-
input->lastmx = mx;
}
@@ -333,6 +343,7 @@ struct GUI_FLOATINPUT* gui_floatinput( I32 x, I32 y, I32 w, const char* title, F
input->lastchange = 0;
input->cb = 0;
+ input->release_cb = 0;
input->pval = pval;
input->min = min;
input->max = max;
diff --git a/src/gui/list.cpp b/src/gui/list.cpp
index 0a2a3d3..aa0992e 100644
--- a/src/gui/list.cpp
+++ b/src/gui/list.cpp
@@ -66,10 +66,10 @@ void gui_list_input_fn( void* ptr ) {
if( m1 ) {
if( !list->held ) {
GUI_LIST_ENTRY* e = &list->plist->data[idx];
- *list->pval = e->val;
- if( list->cb )
- list->cb( list );
+ if( list->pre_cb ) list->pre_cb( list );
+ *list->pval = e->val;
+ if( list->cb ) list->cb( list );
}
list->held = 1;
} else {
diff --git a/src/gui/textbox.cpp b/src/gui/textbox.cpp
index 688450b..c367193 100644
--- a/src/gui/textbox.cpp
+++ b/src/gui/textbox.cpp
@@ -178,18 +178,20 @@ void gui_textbox_handle_repeat( GUI_TEXTBOX* tb ) {
if( gui_time() - tb->repeattime > 0.05f ) {
U32 len = strlen( tb->value );
if( is_printable_char( tb->heldkey ) && len < (tb->maxlen - 1) ) {
+ if( tb->pre_cb ) tb->pre_cb( tb );
+
if( tb->keys[SDLK_LSHIFT & 0xff] || tb->keys[SDLK_RSHIFT & 0xff] )
tb->value[len] = tb->heldkey + ('a' - 'A');
else
tb->value[len] = tb->heldkey;
tb->value[++len] = 0;
- if( tb->cb )
- tb->cb( tb );
+
+ if( tb->cb ) tb->cb( tb );
}
else if( tb->heldkey == '\b' && len > 0 ) {
+ if( tb->pre_cb ) tb->pre_cb( tb );
tb->value[--len] = 0;
- if( tb->cb )
- tb->cb( tb );
+ if( tb->cb ) tb->cb( tb );
}
tb->repeattime = gui_time();
diff --git a/src/gui/vectorinput.cpp b/src/gui/vectorinput.cpp
index ad28c0d..3e36e31 100644
--- a/src/gui/vectorinput.cpp
+++ b/src/gui/vectorinput.cpp
@@ -39,6 +39,20 @@ void gui_vectorinput_child_cb( void* ptr ) {
parent->cb( parent );
}
+void gui_vectorinput_child_pre_cb( void* ptr ) {
+ GUI_FLOATINPUT* child = (GUI_FLOATINPUT*)ptr;
+ GUI_VECTORINPUT* parent = (GUI_VECTORINPUT*)child->parent->parent;
+ if( parent->pre_cb )
+ parent->pre_cb( parent );
+}
+
+void gui_vectorinput_child_release_cb( void* ptr ) {
+ GUI_FLOATINPUT* child = (GUI_FLOATINPUT*)ptr;
+ GUI_VECTORINPUT* parent = (GUI_VECTORINPUT*)child->parent->parent;
+ if( parent->release_cb )
+ parent->release_cb( parent );
+}
+
void __gui_internal_vectorinput_init(
GUI_VECTORINPUT *input,
I32 x, I32 y, I32 w,
@@ -69,6 +83,7 @@ void __gui_internal_vectorinput_init(
gui_set_view( input );
input->cb = 0;
+ input->release_cb = 0;
input->pval = pval;
input->letters = letters;
input->inputview = gui_view( 0, VECTORINPUT_TITLE_OFFSET, w, input->h );
@@ -90,6 +105,8 @@ void __gui_internal_vectorinput_init(
input->inputs.push( slider );
slider->cb = gui_vectorinput_child_cb;
+ slider->pre_cb = gui_vectorinput_child_pre_cb;
+ slider->release_cb = gui_vectorinput_child_release_cb;
}
gui_set_view( parent );
diff --git a/src/render/gl.cpp b/src/render/gl.cpp
index 6ab2117..7425ff4 100644
--- a/src/render/gl.cpp
+++ b/src/render/gl.cpp
@@ -241,9 +241,9 @@ void gl_gen_buffers( GL_DATA* gl ) {
void gl_destroy( GL_DATA *gl ) {
SDL_SetEventFilter( 0, 0 );
- gl->programs.each( fn( GL_SHADER_PROGRAM** it ) { gl_program_destroy( gl, *it ); } );
- gl->fonts.each( fn( GL_FONT** it ) { gl_font_destroy( gl, *it ); } );
- gl->textures.each( fn( GL_TEX2D** it ) { gl_texture_destroy( gl, *it ); } );
+ while( gl->programs.size ) { gl_program_destroy( gl, gl->programs.pop() ); }
+ while( gl->fonts.size ) { gl_font_destroy( gl, gl->fonts.pop() ); }
+ while( gl->textures.size ) { gl_texture_destroy( gl, gl->textures.pop() ); }
if( gl->ctx )
SDL_GL_DeleteContext( gl->ctx );
@@ -407,6 +407,9 @@ void gl_program_destroy( GL_DATA* gl, GL_SHADER_PROGRAM* program ) {
if( program->vsh.compiled )
gl_shader_destroy( gl, &program->vsh );
+ I32 idx = gl->programs.idx_of( program );
+ gl->programs.erase( idx );
+
free( program );
}
diff --git a/src/util/allocator.h b/src/util/allocator.h
index 3cee282..63fc94a 100644
--- a/src/util/allocator.h
+++ b/src/util/allocator.h
@@ -206,6 +206,7 @@ struct LIST {
return &data[size - 1];
}
+ // does not call copy funcs or constructors
template < typename ... IT >
void emplace( const T& item, IT&& ... items ) {
constexpr U32 nsize = sizeof...( IT ) + 1;
diff --git a/src/util/typedef.h b/src/util/typedef.h
index 4a28624..fb26b0e 100644
--- a/src/util/typedef.h
+++ b/src/util/typedef.h
@@ -57,6 +57,6 @@ __defer_t<T> __defer_func( T f ) {
#define dlog( ... ) (void)printf( __VA_ARGS__ )
#define ddef( x ) x
#else
-#define dlog( ... ) {}
+#define dlog( ... ) (void)0
#define ddef( x )
#endif