diff --git a/src/CanvasComponents/CanvasComponentContainer.cpp b/src/CanvasComponents/CanvasComponentContainer.cpp index 8f59c0d..83b2f52 100644 --- a/src/CanvasComponents/CanvasComponentContainer.cpp +++ b/src/CanvasComponents/CanvasComponentContainer.cpp @@ -102,16 +102,14 @@ void CanvasComponentContainer::draw_with_predraw_data(SkCanvas* canvas, const Dr } void CanvasComponentContainer::commit_update(DrawingProgram& drawP) { - if(worldAABB.has_value()) // This is the only point where worldAABB could be nullopt - drawP.preupdate_component(&(*objInfo)); + drawP.preupdate_component(&(*objInfo)); get_comp().initialize_draw_data(drawP); calculate_world_bounds(); drawP.preupdate_component(&(*objInfo)); } void CanvasComponentContainer::commit_transform(DrawingProgram& drawP) { - if(worldAABB.has_value()) // This is the only point where worldAABB could be nullopt - drawP.preupdate_component(&(*objInfo)); + drawP.preupdate_component(&(*objInfo)); calculate_world_bounds(); drawP.preupdate_component(&(*objInfo)); } @@ -135,6 +133,8 @@ bool CanvasComponentContainer::collides_with_cam_coords(const CoordSpaceHelper& // We could just send one of the checkAgainst colliders, since they represent the same thing, but sending both saves on redundant transformations, since we can save both of the versions on the executor side bool CanvasComponentContainer::collides_with(const CoordSpaceHelper& camCoords, const SCollision::ColliderCollection& checkAgainstWorld, const SCollision::ColliderCollection& checkAgainstCam) const { + if(!worldAABB.has_value()) + return false; if((camCoords.inverseScale << COMP_MAX_SHIFT_BEFORE_STOP_COLLISIONS) < coords.inverseScale) // Object is too large, just dismiss the collision return false; else if(coords.inverseScale < (camCoords.inverseScale >> COMP_COLLIDE_MIN_SHIFT_TINY)) @@ -158,7 +158,7 @@ void CanvasComponentContainer::canvas_do_transform(SkCanvas* canvas, const Trans } bool CanvasComponentContainer::should_draw(const DrawData& drawData) const { - return (!drawData.clampDrawBetween || (drawData.clampDrawMinimum < coords.inverseScale)) && SCollision::collide(worldAABB.value(), drawData.cam.viewingAreaGenerousCollider) && get_comp().should_draw_extra(drawData, coords); + return (!drawData.clampDrawBetween || (drawData.clampDrawMinimum < coords.inverseScale)) && worldAABB.has_value() && SCollision::collide(worldAABB.value(), drawData.cam.viewingAreaGenerousCollider) && get_comp().should_draw_extra(drawData, coords); } CanvasComponentContainer::PreDrawData CanvasComponentContainer::calculate_predraw_data(const DrawData& drawData) const { @@ -195,10 +195,13 @@ unsigned CanvasComponentContainer::get_mipmap_level(const DrawData& drawData) co void CanvasComponentContainer::calculate_world_bounds() { worldAABB = coords.collider_to_world, SCollision::AABB>(get_comp().get_obj_coord_bounds()); + WorldVec dim = worldAABB.value().dim(); + if(dim.x() == WorldScalar(0) || dim.y() == WorldScalar(0)) + worldAABB = std::nullopt; } -SCollision::AABB CanvasComponentContainer::get_world_bounds() const { - return worldAABB.value(); +const std::optional>& CanvasComponentContainer::get_world_bounds() const { + return worldAABB; } CanvasComponent& CanvasComponentContainer::get_comp() const { diff --git a/src/CanvasComponents/CanvasComponentContainer.hpp b/src/CanvasComponents/CanvasComponentContainer.hpp index c3e528c..c9fef5a 100644 --- a/src/CanvasComponents/CanvasComponentContainer.hpp +++ b/src/CanvasComponents/CanvasComponentContainer.hpp @@ -55,7 +55,7 @@ class CanvasComponentContainer { void save_file(cereal::PortableBinaryOutputArchive& a) const; void load_file(cereal::PortableBinaryInputArchive& a, VersionNumber version, NetworkingObjects::NetObjManager& objMan); CanvasComponent& get_comp() const; - SCollision::AABB get_world_bounds() const; + const std::optional>& get_world_bounds() const; void draw(SkCanvas* canvas, const DrawData& drawData) const; void draw_with_predraw_data(SkCanvas* canvas, const DrawData& drawData, const PreDrawData& preDrawData) const; PreDrawData calculate_predraw_data(const DrawData& drawData) const; diff --git a/src/CanvasComponents/ImageCanvasComponent.cpp b/src/CanvasComponents/ImageCanvasComponent.cpp index cfb5564..e6175b2 100644 --- a/src/CanvasComponents/ImageCanvasComponent.cpp +++ b/src/CanvasComponents/ImageCanvasComponent.cpp @@ -130,7 +130,8 @@ void ImageCanvasComponent::update(DrawingProgram& drawP) { if(display) { if(display->update_draw()) drawP.invalidate_cache_at_component(&(*compContainer->objInfo)); - display->camera_view_update(compContainer->coords, compContainer->get_world_bounds(), drawP.world.drawData, rect_from_points(d.p1, d.p2)); + if(compContainer->get_world_bounds().has_value()) + display->camera_view_update(compContainer->coords, compContainer->get_world_bounds().value(), drawP.world.drawData, rect_from_points(d.p1, d.p2)); } } diff --git a/src/DrawingProgram/DrawingProgram.cpp b/src/DrawingProgram/DrawingProgram.cpp index dd53c5f..fa5c3df 100644 --- a/src/DrawingProgram/DrawingProgram.cpp +++ b/src/DrawingProgram/DrawingProgram.cpp @@ -527,7 +527,7 @@ void DrawingProgram::pen_tool_switch_check() { void DrawingProgram::invalidate_cache_at_component(CanvasComponentContainer::ObjInfo* objToCheck) { if(!selection.is_selected(objToCheck)) - drawCache.invalidate_cache_at_aabb(objToCheck->obj->get_world_bounds()); + drawCache.invalidate_cache_at_optional_aabb(objToCheck->obj->get_world_bounds()); } void DrawingProgram::preupdate_component(CanvasComponentContainer::ObjInfo* objToCheck) { diff --git a/src/DrawingProgram/DrawingProgramCache.cpp b/src/DrawingProgram/DrawingProgramCache.cpp index 85a7d20..6b3dc90 100644 --- a/src/DrawingProgram/DrawingProgramCache.cpp +++ b/src/DrawingProgram/DrawingProgramCache.cpp @@ -32,7 +32,7 @@ DrawingProgramCache::DrawingProgramCache(DrawingProgram& initDrawP): void DrawingProgramCache::add_component(CanvasComponentContainer::ObjInfo* c) { unsortedComponents.emplace_back(c); - invalidate_cache_at_aabb(c->obj->get_world_bounds()); + invalidate_cache_at_optional_aabb(c->obj->get_world_bounds()); } void DrawingProgramCache::erase_component(CanvasComponentContainer::ObjInfo* c) { @@ -43,7 +43,7 @@ void DrawingProgramCache::erase_component(CanvasComponentContainer::ObjInfo* c) } else std::erase(unsortedComponents, c); - invalidate_cache_at_aabb(c->obj->get_world_bounds()); + invalidate_cache_at_optional_aabb(c->obj->get_world_bounds()); } void DrawingProgramCache::invalidate_cache_at_aabb(const SCollision::AABB& aabb) { @@ -67,6 +67,11 @@ void DrawingProgramCache::invalidate_cache_at_aabb(const SCollision::AABB>& aabb) { + if(aabb.has_value()) + invalidate_cache_at_aabb(aabb.value()); +} + bool DrawingProgramCache::should_rebuild() const { return (unsortedComponents.size() >= MINIMUM_COMPONENTS_TO_START_REBUILD); } @@ -97,11 +102,17 @@ void DrawingProgramCache::build(const std::unordered_set componentsToBuild, const std::unordered_set& objsToNotInclude) { - std::erase_if(componentsToBuild, [&objsToNotInclude](auto& c) { - return objsToNotInclude.contains(c); - }); bvhRoot = std::make_shared(); unsortedComponents.clear(); + std::erase_if(componentsToBuild, [&unsortedComponents = unsortedComponents, &objsToNotInclude](auto& c) { + if(objsToNotInclude.contains(c)) + return true; + if(!c->obj->get_world_bounds().has_value()) { + unsortedComponents.emplace_back(c); + return true; + } + return false; + }); clear_own_cached_surfaces(); build_bvh_node(bvhRoot, componentsToBuild); } @@ -156,16 +167,16 @@ void DrawingProgramCache::preupdate_component(CanvasComponentContainer::ObjInfo* std::erase(cacheParentBvhNodeLock->components, c); c->obj->cacheParentBvhNode.reset(); } - invalidate_cache_at_aabb(c->obj->get_world_bounds()); + invalidate_cache_at_optional_aabb(c->obj->get_world_bounds()); } void DrawingProgramCache::build_bvh_node(const std::shared_ptr& bvhNode, const std::vector& components) { if(components.empty()) return; - bvhNode->bounds = components.front()->obj->get_world_bounds(); + bvhNode->bounds = components.front()->obj->get_world_bounds().value(); for(auto& c : components) - bvhNode->bounds.include_aabb_in_bounds(c->obj->get_world_bounds()); + bvhNode->bounds.include_aabb_in_bounds(c->obj->get_world_bounds().value()); build_bvh_node_coords_and_resolution(*bvhNode); @@ -181,7 +192,7 @@ void DrawingProgramCache::build_bvh_node(const std::shared_ptr, 4> parts; for(auto& c : components) { - const auto& cAABB = c->obj->get_world_bounds(); + const auto& cAABB = c->obj->get_world_bounds().value(); if(cAABB.min.x() < boundsCenter.x() && cAABB.max.x() < boundsCenter.x() && cAABB.min.y() < boundsCenter.y() && cAABB.max.y() < boundsCenter.y()) parts[0].emplace_back(c); else if(cAABB.min.x() > boundsCenter.x() && cAABB.max.x() > boundsCenter.x() && cAABB.min.y() < boundsCenter.y() && cAABB.max.y() < boundsCenter.y()) @@ -425,14 +436,14 @@ void DrawingProgramCache::recursive_draw_layer_item_to_canvas(const DrawingProgr std::vector compsToDraw; parallel_loop_container(nodesToDraw, [&](auto& node) { std::for_each(node->components.begin(), node->components.end(), [&](auto& c) { - if(c->obj->parentLayer == &layerListItem && (!drawBounds.has_value() || SCollision::collide(drawBounds.value(), c->obj->get_world_bounds())) && c->obj->should_draw(drawData)) + if(c->obj->parentLayer == &layerListItem && (!drawBounds.has_value() || SCollision::collide(drawBounds.value(), c->obj->get_world_bounds().value())) && c->obj->should_draw(drawData)) c->obj->preDrawDataHolder = c->obj->calculate_predraw_data(drawData); else c->obj->preDrawDataHolder = std::nullopt; }); }); parallel_loop_container(unsortedComponents, [&](auto& c) { - if(c->obj->parentLayer == &layerListItem && (!drawBounds.has_value() || SCollision::collide(drawBounds.value(), c->obj->get_world_bounds())) && c->obj->should_draw(drawData)) + if(c->obj->parentLayer == &layerListItem && c->obj->get_world_bounds().has_value() && (!drawBounds.has_value() || SCollision::collide(drawBounds.value(), c->obj->get_world_bounds().value())) && c->obj->should_draw(drawData)) c->obj->preDrawDataHolder = c->obj->calculate_predraw_data(drawData); else c->obj->preDrawDataHolder = std::nullopt; diff --git a/src/DrawingProgram/DrawingProgramCache.hpp b/src/DrawingProgram/DrawingProgramCache.hpp index 993e7fa..0fd434f 100644 --- a/src/DrawingProgram/DrawingProgramCache.hpp +++ b/src/DrawingProgram/DrawingProgramCache.hpp @@ -38,6 +38,7 @@ class DrawingProgramCache { void update_and_draw_cached_canvas(SkCanvas* canvas, const DrawData& drawData); void draw_components_to_canvas(SkCanvas* canvas, const DrawData& drawData, const std::optional>& drawBounds); void invalidate_cache_at_aabb(const SCollision::AABB& aabb); + void invalidate_cache_at_optional_aabb(const std::optional>& aabb); static void delete_all_draw_cache(); CanvasComponentContainer::ObjInfo* get_front_object_colliding_with_in_editing_layer(const SCollision::ColliderCollection& cC); diff --git a/src/DrawingProgram/DrawingProgramSelection.cpp b/src/DrawingProgram/DrawingProgramSelection.cpp index 2e96cbb..758d12d 100644 --- a/src/DrawingProgram/DrawingProgramSelection.cpp +++ b/src/DrawingProgram/DrawingProgramSelection.cpp @@ -197,7 +197,7 @@ std::function&)> DrawingP drawP.drawCache.node_loop_erase_if_components(bvhNode, [&](auto c) { if(drawP.layerMan.component_passes_layer_selector(c, drawP.controls.layerSelector) && c->obj->collides_with(drawP.world.drawData.cam.c, cCWorld, cC)) { selectedComponents.emplace_back(c); - drawP.drawCache.invalidate_cache_at_aabb(c->obj->get_world_bounds()); + drawP.drawCache.invalidate_cache_at_optional_aabb(c->obj->get_world_bounds()); return true; } return false; @@ -232,9 +232,9 @@ void DrawingProgramSelection::sort_selection() { void DrawingProgramSelection::calculate_aabb() { if(is_something_selected()) { - initialSelectionAABB = (*selectedSet.begin())->obj->get_world_bounds(); + initialSelectionAABB = (*selectedSet.begin())->obj->get_world_bounds().value(); for(auto& c : selectedSet) - initialSelectionAABB.include_aabb_in_bounds(c->obj->get_world_bounds()); + initialSelectionAABB.include_aabb_in_bounds(c->obj->get_world_bounds().value()); rotateData.centerPos = initialSelectionAABB.center(); } } diff --git a/src/DrawingProgram/Layers/DrawingProgramLayer.cpp b/src/DrawingProgram/Layers/DrawingProgramLayer.cpp index 41d6cc3..f0c011d 100644 --- a/src/DrawingProgram/Layers/DrawingProgramLayer.cpp +++ b/src/DrawingProgram/Layers/DrawingProgramLayer.cpp @@ -2,7 +2,9 @@ #include "DrawingProgramLayerManager.hpp" #include "../DrawingProgram.hpp" #include "../../World.hpp" +#include #include +#include void DrawingProgramLayer::draw(SkCanvas* canvas, const DrawData& drawData) const { for(auto& p : *components) @@ -32,7 +34,7 @@ void DrawingProgramLayer::set_component_list_callbacks(DrawingProgramLayerListIt components->set_insert_callback(insertCallback); components->set_erase_callback(eraseCallback); components->set_move_callback([&](const CanvasComponentContainer::ObjInfoIterator& c, uint32_t oldPos) { - layerMan.drawP.drawCache.invalidate_cache_at_aabb(c->obj->get_world_bounds()); + layerMan.drawP.drawCache.invalidate_cache_at_optional_aabb(c->obj->get_world_bounds()); if(layerMan.drawP.selection.is_selected(&(*c))) layerMan.drawP.selection.sort_selection(); // If item is selected, selected items will be unordered, so sort everything again }); @@ -67,6 +69,18 @@ void DrawingProgramLayer::load_file(cereal::PortableBinaryInputArchive& a, Versi } } +void DrawingProgramLayer::erase_invalid_components() { + std::vector> compsToErase; + for(auto it = components->begin(); it != components->end(); ++it) { + if(!it->obj->get_world_bounds().has_value()) + compsToErase.emplace_back(it); + } + if(!compsToErase.empty()) { + Logger::get().log("INFO", "[DrawingProgramLayer::erase_invalid_components] Erased " + std::to_string(compsToErase.size()) + " invalid component(s) from layer"); + components->erase_list(components, compsToErase); + } +} + void DrawingProgramLayer::save_file(cereal::PortableBinaryOutputArchive& a) const { a(components->size()); for(auto& comp : *components) diff --git a/src/DrawingProgram/Layers/DrawingProgramLayer.hpp b/src/DrawingProgram/Layers/DrawingProgramLayer.hpp index ea60377..5194544 100644 --- a/src/DrawingProgram/Layers/DrawingProgramLayer.hpp +++ b/src/DrawingProgram/Layers/DrawingProgramLayer.hpp @@ -25,6 +25,7 @@ class DrawingProgramLayer { void save_file(cereal::PortableBinaryOutputArchive& a) const; void get_used_resources(std::unordered_set& resourceSet) const; + void erase_invalid_components(); private: std::function eraseCallback; }; diff --git a/src/DrawingProgram/Layers/DrawingProgramLayerFolder.cpp b/src/DrawingProgram/Layers/DrawingProgramLayerFolder.cpp index 93e1959..43b6203 100644 --- a/src/DrawingProgram/Layers/DrawingProgramLayerFolder.cpp +++ b/src/DrawingProgram/Layers/DrawingProgramLayerFolder.cpp @@ -75,6 +75,11 @@ void DrawingProgramLayerFolder::save_file(cereal::PortableBinaryOutputArchive& a listItem.obj->save_file(a); } +void DrawingProgramLayerFolder::erase_invalid_components() { + for(auto& listItem : *folderList) + listItem.obj->erase_invalid_components(); +} + void DrawingProgramLayerFolder::get_used_resources(std::unordered_set& resourceSet) const { for(auto& listItem : *folderList) listItem.obj->get_used_resources(resourceSet); diff --git a/src/DrawingProgram/Layers/DrawingProgramLayerFolder.hpp b/src/DrawingProgram/Layers/DrawingProgramLayerFolder.hpp index 06ecfbd..5ca12f7 100644 --- a/src/DrawingProgram/Layers/DrawingProgramLayerFolder.hpp +++ b/src/DrawingProgram/Layers/DrawingProgramLayerFolder.hpp @@ -23,4 +23,5 @@ class DrawingProgramLayerFolder { void save_file(cereal::PortableBinaryOutputArchive& a) const; void get_used_resources(std::unordered_set& resourceSet) const; + void erase_invalid_components(); }; diff --git a/src/DrawingProgram/Layers/DrawingProgramLayerListItem.cpp b/src/DrawingProgram/Layers/DrawingProgramLayerListItem.cpp index dd530ae..e5adf17 100644 --- a/src/DrawingProgram/Layers/DrawingProgramLayerListItem.cpp +++ b/src/DrawingProgram/Layers/DrawingProgramLayerListItem.cpp @@ -271,6 +271,13 @@ DrawingProgramLayerListItemMetaInfo DrawingProgramLayerListItem::get_metainfo() }; } +void DrawingProgramLayerListItem::erase_invalid_components() { + if(folderData) + folderData->erase_invalid_components(); + else + layerData->erase_invalid_components(); +} + void DrawingProgramLayerListItem::register_class(World& w) { w.netObjMan.register_class({ .writeConstructorFuncClient = write_constructor_func, diff --git a/src/DrawingProgram/Layers/DrawingProgramLayerListItem.hpp b/src/DrawingProgram/Layers/DrawingProgramLayerListItem.hpp index 07afc51..9663628 100644 --- a/src/DrawingProgram/Layers/DrawingProgramLayerListItem.hpp +++ b/src/DrawingProgram/Layers/DrawingProgramLayerListItem.hpp @@ -66,6 +66,8 @@ class DrawingProgramLayerListItem { DrawingProgramLayerListItemMetaInfo get_metainfo() const; uint32_t get_component_count() const; + + void erase_invalid_components(); private: static void write_constructor_func(const NetworkingObjects::NetObjTemporaryPtr& o, cereal::PortableBinaryOutputArchive& a); static void read_constructor_func(const NetworkingObjects::NetObjTemporaryPtr& o, cereal::PortableBinaryInputArchive& a, const std::shared_ptr& c); diff --git a/src/DrawingProgram/Layers/DrawingProgramLayerManager.cpp b/src/DrawingProgram/Layers/DrawingProgramLayerManager.cpp index 7c88d2c..c3cd72a 100644 --- a/src/DrawingProgram/Layers/DrawingProgramLayerManager.cpp +++ b/src/DrawingProgram/Layers/DrawingProgramLayerManager.cpp @@ -284,6 +284,7 @@ void DrawingProgramLayerManager::load_file(cereal::PortableBinaryInputArchive& a parallel_loop_container(flattenedCompList, [&drawP = drawP](CanvasComponentContainer::ObjInfo* comp) { comp->obj->commit_update_dont_invalidate_cache(drawP); }); + layerTreeRoot->erase_invalid_components(); drawP.rebuild_cache(); editingLayer = layerTreeRoot->get_folder().get_initial_editing_layer(); } diff --git a/src/DrawingProgram/Tools/BrushTool.cpp b/src/DrawingProgram/Tools/BrushTool.cpp index df42b27..0076f85 100644 --- a/src/DrawingProgram/Tools/BrushTool.cpp +++ b/src/DrawingProgram/Tools/BrushTool.cpp @@ -162,7 +162,12 @@ void BrushTool::commit_stroke() { NetworkingObjects::NetObjOwnerPtr& containerPtr = objInfoBeingEdited->obj; containerPtr->commit_update(drawP); containerPtr->send_comp_update(drawP, true); - drawP.layerMan.add_undo_place_component(objInfoBeingEdited); + if(containerPtr->get_world_bounds().has_value()) + drawP.layerMan.add_undo_place_component(objInfoBeingEdited); + else { + auto& components = containerPtr->parentLayer->get_layer().components; + components->erase(components, containerPtr->objInfo); + } objInfoBeingEdited = nullptr; } } diff --git a/src/DrawingProgram/Tools/EllipseDrawTool.cpp b/src/DrawingProgram/Tools/EllipseDrawTool.cpp index 5b42954..b65105f 100644 --- a/src/DrawingProgram/Tools/EllipseDrawTool.cpp +++ b/src/DrawingProgram/Tools/EllipseDrawTool.cpp @@ -115,7 +115,12 @@ void EllipseDrawTool::commit() { NetworkingObjects::NetObjOwnerPtr& containerPtr = objInfoBeingEdited->obj; containerPtr->commit_update(drawP); containerPtr->send_comp_update(drawP, true); - drawP.layerMan.add_undo_place_component(objInfoBeingEdited); + if(containerPtr->get_world_bounds().has_value()) + drawP.layerMan.add_undo_place_component(objInfoBeingEdited); + else { + auto& components = containerPtr->parentLayer->get_layer().components; + components->erase(components, containerPtr->objInfo); + } objInfoBeingEdited = nullptr; } } diff --git a/src/DrawingProgram/Tools/EraserTool.cpp b/src/DrawingProgram/Tools/EraserTool.cpp index 4ec049a..b1e7a29 100644 --- a/src/DrawingProgram/Tools/EraserTool.cpp +++ b/src/DrawingProgram/Tools/EraserTool.cpp @@ -89,7 +89,7 @@ void EraserTool::erase_between_points(const Vector2f& start, const Vector2f& end drawP.drawCache.node_loop_erase_if_components(bvhNode, [&](auto c) { if(drawP.layerMan.component_passes_layer_selector(c, drawP.controls.layerSelector) && c->obj->collides_with(drawP.world.drawData.cam.c, cCWorld, cC)) { erasedComponents.emplace(c); - drawP.drawCache.invalidate_cache_at_aabb(c->obj->get_world_bounds()); + drawP.drawCache.invalidate_cache_at_optional_aabb(c->obj->get_world_bounds()); return true; } return false; diff --git a/src/DrawingProgram/Tools/LineDrawTool.cpp b/src/DrawingProgram/Tools/LineDrawTool.cpp index ee5d307..fe91c28 100644 --- a/src/DrawingProgram/Tools/LineDrawTool.cpp +++ b/src/DrawingProgram/Tools/LineDrawTool.cpp @@ -110,7 +110,12 @@ void LineDrawTool::commit() { NetworkingObjects::NetObjOwnerPtr& containerPtr = objInfoBeingEdited->obj; containerPtr->commit_update(drawP); containerPtr->send_comp_update(drawP, true); - drawP.layerMan.add_undo_place_component(objInfoBeingEdited); + if(containerPtr->get_world_bounds().has_value()) + drawP.layerMan.add_undo_place_component(objInfoBeingEdited); + else { + auto& components = containerPtr->parentLayer->get_layer().components; + components->erase(components, containerPtr->objInfo); + } objInfoBeingEdited = nullptr; } } diff --git a/src/DrawingProgram/Tools/RectDrawTool.cpp b/src/DrawingProgram/Tools/RectDrawTool.cpp index e02064f..f2b959a 100644 --- a/src/DrawingProgram/Tools/RectDrawTool.cpp +++ b/src/DrawingProgram/Tools/RectDrawTool.cpp @@ -119,7 +119,12 @@ void RectDrawTool::commit() { NetworkingObjects::NetObjOwnerPtr& containerPtr = objInfoBeingEdited->obj; containerPtr->commit_update(drawP); containerPtr->send_comp_update(drawP, true); - drawP.layerMan.add_undo_place_component(objInfoBeingEdited); + if(containerPtr->get_world_bounds().has_value()) + drawP.layerMan.add_undo_place_component(objInfoBeingEdited); + else { + auto& components = containerPtr->parentLayer->get_layer().components; + components->erase(components, containerPtr->objInfo); + } objInfoBeingEdited = nullptr; } }