diff --git a/CMakeLists.txt b/CMakeLists.txt index c395a9c..b6a2c0c 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -58,10 +58,8 @@ set(sources "src/main.cpp" "src/RichText/TextBox.cpp" "src/RichText/TextStyleModifier.cpp" "src/RichText/ParagraphStyleData.cpp" - "src/DrawingProgram/DrawingProgramCacheNew.cpp" "src/DrawingProgram/DrawingProgramCache.cpp" "src/DrawingProgram/DrawingProgram.cpp" - "src/DrawingProgram/DrawingProgramSelection.cpp" "src/DrawingProgram/Tools/BrushTool.cpp" "src/DrawingProgram/Tools/TextBoxTool.cpp" "src/DrawingProgram/Tools/EraserTool.cpp" diff --git a/include/Helpers/NetworkingObjects/NetObjOrderedList.hpp b/include/Helpers/NetworkingObjects/NetObjOrderedList.hpp index dc7e661..ab3b855 100644 --- a/include/Helpers/NetworkingObjects/NetObjOrderedList.hpp +++ b/include/Helpers/NetworkingObjects/NetObjOrderedList.hpp @@ -87,7 +87,6 @@ namespace NetworkingObjects { typedef std::function& objInfo)> InsertCallback; typedef std::function& objInfo)> EraseCallback; typedef std::function& objInfo, uint32_t oldPos)> MoveCallback; - typedef std::function PostSyncCallback; void set_insert_callback(const InsertCallback& func) { insertCallback = func; @@ -98,9 +97,6 @@ namespace NetworkingObjects { void set_move_callback(const MoveCallback& func) { moveCallback = func; } - void set_post_sync_callback(const PostSyncCallback& func) { - postSyncCallback = func; - } virtual bool contains(const NetObjID& p) const = 0; virtual const std::vector>& get_data() const = 0; @@ -142,16 +138,10 @@ namespace NetworkingObjects { moveCallback(objInfo, oldPos); } - void call_post_sync_callback() { - if(postSyncCallback) - postSyncCallback(); - } - private: InsertCallback insertCallback; EraseCallback eraseCallback; MoveCallback moveCallback; - PostSyncCallback postSyncCallback; template friend void register_ordered_list_class(NetObjManager& t); static void write_constructor_func(const NetObjTemporaryPtr>& l, cereal::PortableBinaryOutputArchive& a) { l->write_constructor(l, a); @@ -622,27 +612,17 @@ namespace NetworkingObjects { clientData.insert(clientData.begin() + pos, objInfoPtr); } - // Code that tries to not call post_sync_callback, which refreshes the entire cache. - //uint32_t bumpFromServerInsert = 0; - //for(uint32_t i = 0; i < clientData.size(); i++) { - // if(clientData[i]->pos == std::numeric_limits::max()) { - // clientData[i]->pos = i; - // this->call_insert_callback(clientData[i]); - // bumpFromServerInsert++; - // } - // else if(clientData[i]->pos != (i + bumpFromServerInsert)) { - // uint32_t oldPos = clientData[i]->pos; - // clientData[i]->pos = i; - // this->call_move_callback(clientData[i], oldPos); - // } - // clientData[i]->pos = i; - //} - - // Code that calls post_sync_callback - set_positions_for_object_info_vector(clientData); - for(auto& [id, objInfo] : newServerObjects) - this->call_insert_callback(objInfo); - this->call_post_sync_callback(); + uint32_t bumpFromServerInsert = 0; + for(uint32_t i = 0; i < clientData.size(); i++) { + uint32_t oldPos = clientData[i]->pos; + clientData[i]->pos = i; + if(oldPos == std::numeric_limits::max()) { + this->call_insert_callback(clientData[i]); + bumpFromServerInsert++; + } + else if(oldPos != (i + bumpFromServerInsert)) + this->call_move_callback(clientData[i], oldPos); + } } std::vector serverData; diff --git a/src/CanvasComponents/CanvasComponentContainer.cpp b/src/CanvasComponents/CanvasComponentContainer.cpp index ffbe513..68ac6e2 100644 --- a/src/CanvasComponents/CanvasComponentContainer.cpp +++ b/src/CanvasComponents/CanvasComponentContainer.cpp @@ -65,20 +65,20 @@ void CanvasComponentContainer::set_owner_obj_info(const ObjInfoSharedPtr& ownerO } void CanvasComponentContainer::commit_update(DrawingProgram& drawP) { - //auto lockedObjInfo = objInfo.lock(); - //if(worldAABB.has_value()) // This is the only point where worldAABB could be nullopt - // drawP.preupdate_component(lockedObjInfo); + auto lockedObjInfo = objInfo.lock(); + if(worldAABB.has_value()) // This is the only point where worldAABB could be nullopt + drawP.drawCache.preupdate_component(lockedObjInfo); get_comp().initialize_draw_data(drawP); calculate_world_bounds(); - //drawP.preupdate_component(lockedObjInfo); + drawP.drawCache.preupdate_component(lockedObjInfo); } void CanvasComponentContainer::commit_transform(DrawingProgram& drawP) { - //auto lockedObjInfo = objInfo.lock(); - //if(worldAABB.has_value()) // This is the only point where worldAABB could be nullopt - // drawP.preupdate_component(lockedObjInfo); + auto lockedObjInfo = objInfo.lock(); + if(worldAABB.has_value()) // This is the only point where worldAABB could be nullopt + drawP.drawCache.preupdate_component(lockedObjInfo); calculate_world_bounds(); - //drawP.preupdate_component(lockedObjInfo); + drawP.drawCache.preupdate_component(lockedObjInfo); } void CanvasComponentContainer::commit_update_dont_invalidate_cache(DrawingProgram& drawP) { diff --git a/src/CanvasComponents/CanvasComponentContainer.hpp b/src/CanvasComponents/CanvasComponentContainer.hpp index 9d4ef25..ebaa2a8 100644 --- a/src/CanvasComponents/CanvasComponentContainer.hpp +++ b/src/CanvasComponents/CanvasComponentContainer.hpp @@ -9,6 +9,7 @@ class DrawingProgram; class DrawingProgramCacheBVHNode; +class DrawingProgramLayerListItem; class CanvasComponentContainer { public: @@ -44,7 +45,8 @@ class CanvasComponentContainer { void set_owner_obj_info(const ObjInfoSharedPtr& ownerObjInfo); void send_comp_update(DrawingProgram& drawP, bool finalUpdate); - std::weak_ptr parentBvhNode; + std::weak_ptr parentBvhNode; // Should be removed later, the new cache uses an unordered_map to map objects to their cache node + DrawingProgramLayerListItem* parentLayer = nullptr; CoordSpaceHelper coords; private: friend class BrushStrokeCanvasComponent; diff --git a/src/CanvasComponents/ImageCanvasComponent.cpp b/src/CanvasComponents/ImageCanvasComponent.cpp index 77ca074..d51dd5b 100644 --- a/src/CanvasComponents/ImageCanvasComponent.cpp +++ b/src/CanvasComponents/ImageCanvasComponent.cpp @@ -65,7 +65,7 @@ void ImageCanvasComponent::update(DrawingProgram& drawP) { ResourceDisplay* display = drawP.world.drawData.rMan->get_display_data(d.imageID); if(display) { if(display->update_draw()) - drawP.invalidate_cache_at_component(compContainer->objInfo.lock()); + drawP.drawCache.invalidate_cache_at_aabb(compContainer->get_world_bounds()); } } diff --git a/src/CanvasTheme.cpp b/src/CanvasTheme.cpp index eb304c1..7fe85c5 100644 --- a/src/CanvasTheme.cpp +++ b/src/CanvasTheme.cpp @@ -45,7 +45,7 @@ void CanvasTheme::set_tool_front_color(DrawingProgram& drawP) { else toolFrontColor = SkColor4f{1.0f, 1.0f, 1.0f, 1.0f}; if(oldToolFrontColor != toolFrontColor) - drawP.clear_draw_cache(); + drawP.drawCache.clear_own_cached_surfaces(); } void CanvasTheme::register_class() { diff --git a/src/DrawingProgram/DrawingProgram.cpp b/src/DrawingProgram/DrawingProgram.cpp index 5b5095d..9444d68 100644 --- a/src/DrawingProgram/DrawingProgram.cpp +++ b/src/DrawingProgram/DrawingProgram.cpp @@ -27,48 +27,23 @@ #include #include #include "../CanvasComponents/ImageCanvasComponent.hpp" +#include "Layers/DrawingProgramLayer.hpp" +#include "Layers/DrawingProgramLayerListItem.hpp" #include "Tools/EraserTool.hpp" DrawingProgram::DrawingProgram(World& initWorld): world(initWorld), - compCache(*this), - layerMan(*this), - selection(*this) + drawCache(*this), + layerMan(*this) { drawTool = DrawingProgramToolBase::allocate_tool_type(*this, DrawingProgramToolType::BRUSH); } void DrawingProgram::init() { - if(world.netObjMan.is_server()) { - components = world.netObjMan.make_obj>(); - set_component_list_callbacks(); - } layerMan.init(); } -void DrawingProgram::set_component_list_callbacks() { - components->set_insert_callback([&](const CanvasComponentContainer::ObjInfoSharedPtr& c) { - c->obj->set_owner_obj_info(c); - c->obj->commit_update(*this); // Run commit update on insert so that world bounds are calculated - compCache.add_component(c); - if(c->obj->get_comp().get_type() == CanvasComponentType::IMAGE) - updateableComponents.emplace(c); - }); - components->set_erase_callback([&](const CanvasComponentContainer::ObjInfoSharedPtr& c) { - compCache.erase_component(c); - selection.erase_component(c); - drawTool->erase_component(c); - std::erase_if(droppedDownloadingFiles, [&c](auto& downloadingFile) { - return downloadingFile.comp == c; - }); - updateableComponents.erase(c); - }); - components->set_post_sync_callback([&]() { - clear_draw_cache(); - }); -} - void DrawingProgram::scale_up(const WorldScalar& scaleUpAmount) { //for(auto& c : components->get_data()) // c->obj->scale_up(scaleUpAmount); @@ -77,35 +52,13 @@ void DrawingProgram::scale_up(const WorldScalar& scaleUpAmount) { //switch_to_tool(drawTool->get_type() == DrawingProgramToolType::GRIDMODIFY ? DrawingProgramToolType::EDIT : drawTool->get_type(), true); } -void DrawingProgram::parallel_loop_all_components(std::function func) { - parallel_loop_container(components->get_data(), func); -} - -void DrawingProgram::erase_component_set(const std::unordered_set& compsToErase) { - std::unordered_set idsToErase; - for(auto& c : compsToErase) - idsToErase.emplace(c->obj.get_net_id()); - components->erase_unordered_set(components, idsToErase); -} - -void DrawingProgram::clear_draw_cache() { - compCache.clear_own_cached_surfaces(); - selection.clear_own_cached_surfaces(); -} - void DrawingProgram::write_components_server(cereal::PortableBinaryOutputArchive& a) { - components.write_create_message(a); layerMan.write_components_server(a); } void DrawingProgram::read_components_client(cereal::PortableBinaryInputArchive& a) { - components = world.netObjMan.read_create_message>(a, nullptr); - parallel_loop_all_components([&](const auto& c){ - c->obj->commit_update_dont_invalidate_cache(*this); - }); - compCache.test_rebuild(components->get_data(), true); - set_component_list_callbacks(); layerMan.read_components_client(a); + drawCache.build({}); } void DrawingProgram::toolbar_gui() { @@ -154,26 +107,26 @@ bool DrawingProgram::selection_action_menu(Vector2f popupPos) { bool shouldClose = false; t.gui.list_popup_menu("Selection popup menu", popupPos, [&]() { t.gui.text_label_light("Selection menu"); - if(t.gui.text_button_left_transparent("Paste", "Paste")) { - selection.deselect_all(); - selection.paste_clipboard(popupPos * t.final_gui_scale()); - shouldClose = true; - } - if(selection.is_something_selected()) { - if(t.gui.text_button_left_transparent("Copy", "Copy")) { - selection.selection_to_clipboard(); - shouldClose = true; - } - if(t.gui.text_button_left_transparent("Cut", "Cut")) { - selection.selection_to_clipboard(); - selection.delete_all(); - shouldClose = true; - } - if(t.gui.text_button_left_transparent("Delete", "Delete")) { - selection.delete_all(); - shouldClose = true; - } - } + //if(t.gui.text_button_left_transparent("Paste", "Paste")) { + // selection.deselect_all(); + // selection.paste_clipboard(popupPos * t.final_gui_scale()); + // shouldClose = true; + //} + //if(selection.is_something_selected()) { + // if(t.gui.text_button_left_transparent("Copy", "Copy")) { + // selection.selection_to_clipboard(); + // shouldClose = true; + // } + // if(t.gui.text_button_left_transparent("Cut", "Cut")) { + // selection.selection_to_clipboard(); + // selection.delete_all(); + // shouldClose = true; + // } + // if(t.gui.text_button_left_transparent("Delete", "Delete")) { + // selection.delete_all(); + // shouldClose = true; + // } + //} }); return !shouldClose; } @@ -216,7 +169,7 @@ void DrawingProgram::update() { if(!badFrametimeTimePoint) badFrametimeTimePoint = std::chrono::steady_clock::now(); else if(unorderedObjectsExistTimePoint && std::chrono::steady_clock::now() - badFrametimeTimePoint.value() >= std::chrono::seconds(5) && std::chrono::steady_clock::now() - unorderedObjectsExistTimePoint.value() >= std::chrono::seconds(5)) { - force_rebuild_cache(); + rebuild_cache(); unorderedObjectsExistTimePoint = std::nullopt; badFrametimeTimePoint = std::nullopt; } @@ -224,12 +177,10 @@ void DrawingProgram::update() { else badFrametimeTimePoint = std::nullopt; - if(compCache.get_unsorted_component_list().empty()) { + if(!drawCache.unsorted_components_exist()) unorderedObjectsExistTimePoint = std::nullopt; - } - else if(!unorderedObjectsExistTimePoint) { + else if(!unorderedObjectsExistTimePoint) unorderedObjectsExistTimePoint = std::chrono::steady_clock::now(); - } if(world.main.input.pen.isEraser && !temporaryEraser) { if(drawTool->get_type() == DrawingProgramToolType::BRUSH) @@ -317,7 +268,7 @@ void DrawingProgram::update() { else if(world.main.input.key(InputManager::KEY_DRAW_TOOL_PAN).pressed) switch_to_tool(DrawingProgramToolType::PAN); - selection.update(); + //selection.update(); drawTool->tool_update(); // Switch tools after the tool update, not before, so that we dont have to call erase_component on the toolToSwitchToAfterUpdate as well (components will not be erased in this time period) @@ -332,14 +283,8 @@ void DrawingProgram::update() { update_downloading_dropped_files(); check_updateable_components(); - if(drawTool->get_type() == DrawingProgramToolType::ERASER) { - EraserTool* eraserTool = static_cast(drawTool.get()); - compCache.test_rebuild_dont_include_set_dont_include_nodes(components->get_data(), eraserTool->erasedComponents, eraserTool->erasedBVHNodes); - } - else if(is_selection_allowing_tool(drawTool->get_type())) - compCache.test_rebuild_dont_include_set(components->get_data(), selection.get_selected_set()); - else - compCache.test_rebuild(components->get_data()); + if(drawCache.should_rebuild()) + rebuild_cache(); } void DrawingProgram::check_updateable_components() { @@ -387,19 +332,20 @@ SkPaint DrawingProgram::select_tool_line_paint() { return selectLinePaint; } -void DrawingProgram::force_rebuild_cache() { +void DrawingProgram::rebuild_cache() { if(drawTool->get_type() == DrawingProgramToolType::ERASER) { EraserTool* eraserTool = static_cast(drawTool.get()); - compCache.test_rebuild_dont_include_set_dont_include_nodes(components->get_data(), eraserTool->erasedComponents, eraserTool->erasedBVHNodes, true); + drawCache.build(eraserTool->erasedComponents); + } + else if(is_selection_allowing_tool(drawTool->get_type())) { + //compCache.test_rebuild_dont_include_set(components->get_data(), selection.get_selected_set(), true); } - else if(is_selection_allowing_tool(drawTool->get_type())) - compCache.test_rebuild_dont_include_set(components->get_data(), selection.get_selected_set(), true); else - compCache.test_rebuild(components->get_data(), true); + drawCache.build({}); } void DrawingProgram::drag_drop_update() { - if(controls.cursorHoveringOverCanvas) { + if(controls.cursorHoveringOverCanvas && layerMan.is_a_layer_being_edited()) { for(auto& droppedItem : world.main.input.droppedItems) { if(droppedItem.dataPath.has_value() && std::filesystem::is_regular_file(droppedItem.dataPath.value())) { #ifdef __EMSCRIPTEN_ @@ -416,7 +362,7 @@ void DrawingProgram::drag_drop_update() { img.d.p1 = droppedItem.pos - imDim; img.d.p2 = droppedItem.pos + imDim; img.d.imageID = {0, 0}; - auto newObjInfo = components->push_back_and_send_create(components, newContainer); + auto newObjInfo = layerMan.add_component_to_layer_being_edited(newContainer); droppedDownloadingFiles.emplace_back(newObjInfo, world.main.window.size.cast(), FileDownloader::download_data_from_url(droppedItem.dataText.value())); } } @@ -437,7 +383,8 @@ void DrawingProgram::update_downloading_dropped_files() { ResourceDisplay* display = world.rMan.get_display_data(imageID); if(display->get_type() == ResourceDisplay::Type::FILE) { Logger::get().log("WORLDFATAL", "Failed to parse image from URL"); - components->erase(components, downFile.comp->obj.get_net_id()); + auto& parentLayerComponents = downFile.comp->obj->parentLayer->get_layer().components; + parentLayerComponents->erase(parentLayerComponents, downFile.comp->obj.get_net_id()); } else { Vector2f imTrueDim = display->get_dimensions(); @@ -453,10 +400,12 @@ void DrawingProgram::update_downloading_dropped_files() { } return true; } - case FileDownloader::DownloadData::Status::FAILURE: + case FileDownloader::DownloadData::Status::FAILURE: { Logger::get().log("WORLDFATAL", "Failed to download data from URL"); - components->erase(components, downFile.comp->obj.get_net_id()); + auto& parentLayerComponents = downFile.comp->obj->parentLayer->get_layer().components; + parentLayerComponents->erase(parentLayerComponents, downFile.comp->obj.get_net_id()); return true; + } case FileDownloader::DownloadData::Status::IN_PROGRESS: return false; } @@ -488,7 +437,7 @@ void DrawingProgram::add_file_to_canvas_by_path_execute(const std::filesystem::p img.d.p1 = dropPos - imDim; img.d.p2 = dropPos + imDim; img.d.imageID = imageID; - components->push_back_and_send_create(components, newContainer); + layerMan.add_component_to_layer_being_edited(newContainer); } } @@ -508,21 +457,7 @@ void DrawingProgram::add_file_to_canvas_by_data(const std::string& fileName, std img.d.p1 = dropPos - imDim; img.d.p2 = dropPos + imDim; img.d.imageID = imageID; - components->push_back_and_send_create(components, newContainer); -} - -void DrawingProgram::invalidate_cache_at_component(const CanvasComponentContainer::ObjInfoSharedPtr& objToCheck) { - if(selection.is_selected(objToCheck)) - selection.invalidate_cache_at_aabb_before_pos(objToCheck->obj->get_world_bounds(), objToCheck->pos); - else - compCache.invalidate_cache_at_aabb_before_pos(objToCheck->obj->get_world_bounds(), objToCheck->pos); -} - -void DrawingProgram::preupdate_component(const CanvasComponentContainer::ObjInfoSharedPtr& objToCheck) { - if(selection.is_selected(objToCheck)) - selection.preupdate_component(objToCheck); - else - compCache.preupdate_component(objToCheck); + layerMan.add_component_to_layer_being_edited(newContainer); } float DrawingProgram::drag_point_radius() { @@ -566,36 +501,33 @@ void DrawingProgram::save_file(cereal::PortableBinaryOutputArchive& a) const { } void DrawingProgram::draw(SkCanvas* canvas, const DrawData& drawData) { - layerMan.draw(canvas, drawData); - //if(drawData.dontUseDrawProgCache) { - // for(auto& c : components->get_data()) - // c->obj->draw(canvas, drawData); - //} - //else { - // canvas->saveLayer(nullptr, nullptr); - // canvas->clear(SkColor4f{0.0f, 0.0f, 0.0f, 0.0f}); - // compCache.refresh_all_draw_cache(drawData); - // compCache.draw_components_to_canvas(canvas, drawData, {}); - // canvas->saveLayer(nullptr, nullptr); - // selection.draw_components(canvas, drawData); - // canvas->restore(); - // canvas->restore(); + if(drawData.dontUseDrawProgCache) + layerMan.draw(canvas, drawData); + else { + canvas->saveLayer(nullptr, nullptr); + canvas->clear(SkColor4f{0.0f, 0.0f, 0.0f, 0.0f}); + drawCache.refresh_all_draw_cache(drawData); + drawCache.draw_components_to_canvas(canvas, drawData, {}); + //canvas->saveLayer(nullptr, nullptr); + // selection.draw_components(canvas, drawData); + //canvas->restore(); + canvas->restore(); - // if(!drawData.main->takingScreenshot) { - // for(auto& droppedDownFile : droppedDownloadingFiles) - // static_cast(droppedDownFile.comp->obj->get_comp()).draw_download_progress_bar(canvas, drawData, droppedDownFile.downData->progress); + if(!drawData.main->takingScreenshot) { + for(auto& droppedDownFile : droppedDownloadingFiles) + static_cast(droppedDownFile.comp->obj->get_comp()).draw_download_progress_bar(canvas, drawData, droppedDownFile.downData->progress); - // for(auto& c : updateableComponents) { - // if(c->obj->get_comp().get_type() == CanvasComponentType::IMAGE) { - // auto& img = static_cast(c->obj->get_comp()); - // float progress = drawData.main->world->rMan.get_resource_retrieval_progress(img.d.imageID); - // img.draw_download_progress_bar(canvas, drawData, progress); - // } - // } - // } + for(auto& c : updateableComponents) { + if(c->obj->get_comp().get_type() == CanvasComponentType::IMAGE) { + auto& img = static_cast(c->obj->get_comp()); + float progress = drawData.main->world->rMan.get_resource_retrieval_progress(img.d.imageID); + img.draw_download_progress_bar(canvas, drawData, progress); + } + } + } - // selection.draw_gui(canvas, drawData); - //} + //selection.draw_gui(canvas, drawData); + } drawTool->draw(canvas, drawData); } diff --git a/src/DrawingProgram/DrawingProgram.hpp b/src/DrawingProgram/DrawingProgram.hpp index a16f8dd..242860f 100644 --- a/src/DrawingProgram/DrawingProgram.hpp +++ b/src/DrawingProgram/DrawingProgram.hpp @@ -12,7 +12,6 @@ #include #include #include -#include "DrawingProgramSelection.hpp" #include "Tools/DrawingProgramToolBase.hpp" #include #include @@ -24,7 +23,6 @@ class DrawingProgram { public: DrawingProgram(World& initWorld); void init(); - void set_component_list_callbacks(); void toolbar_gui(); void tool_options_gui(); bool right_click_popup_gui(Vector2f popupPos); @@ -42,21 +40,13 @@ class DrawingProgram { World& world; bool prevent_undo_or_redo(); - void parallel_loop_all_components(std::function func); - - // This function, unlike preupdate_component, does not take the object out of the BVH. Use for a draw update that doesn't change the object's bounding box - void invalidate_cache_at_component(const CanvasComponentContainer::ObjInfoSharedPtr& objToCheck); - void preupdate_component(const CanvasComponentContainer::ObjInfoSharedPtr& objToCheck); - - DrawingProgramCache compCache; + DrawingProgramCache drawCache; DrawingProgramLayerManager layerMan; - CanvasComponentContainer::NetListOwnerPtr components; Vector4f* get_foreground_color_ptr(); void switch_to_tool(DrawingProgramToolType newToolType, bool force = false); void switch_to_tool_ptr(std::unique_ptr newTool); - void clear_draw_cache(); void modify_grid(const NetworkingObjects::NetObjWeakPtr& gridToModify); private: @@ -69,7 +59,7 @@ class DrawingProgram { std::optional unorderedObjectsExistTimePoint; bool selection_action_menu(Vector2f popupPos); - void force_rebuild_cache(); + void rebuild_cache(); std::atomic addFileInNextFrame = false; std::pair addFileInfo; @@ -79,9 +69,8 @@ class DrawingProgram { SkPaint select_tool_line_paint(); bool is_actual_selection_tool(DrawingProgramToolType typeToCheck); bool is_selection_allowing_tool(DrawingProgramToolType typeToCheck); - void erase_component_set(const std::unordered_set& compsToErase); - DrawingProgramSelection selection; + //DrawingProgramSelection selection; std::unique_ptr toolToSwitchToAfterUpdate; std::unordered_set updateableComponents; @@ -105,6 +94,8 @@ class DrawingProgram { bool middleClickReleased = false; bool cursorHoveringOverCanvas = false; + DrawingProgramLayerManager::LayerSelector layerSelector = DrawingProgramLayerManager::LayerSelector::LAYER_BEING_EDITED; + int colorEditing = 0; } controls; @@ -140,4 +131,7 @@ class DrawingProgram { friend class ZoomCanvasTool; friend class PanCanvasTool; friend class DrawCamera; + friend class DrawingProgramLayerManager; + friend class DrawingProgramLayer; + friend class DrawingProgramLayerFolder; }; diff --git a/src/DrawingProgram/DrawingProgramCache.cpp b/src/DrawingProgram/DrawingProgramCache.cpp index 4669014..4a0ecdf 100644 --- a/src/DrawingProgram/DrawingProgramCache.cpp +++ b/src/DrawingProgram/DrawingProgramCache.cpp @@ -2,9 +2,6 @@ #include "DrawingProgram.hpp" #include "../World.hpp" #include "../MainProgram.hpp" -#include "Helpers/Parallel.hpp" -#include -#include #ifdef USE_SKIA_BACKEND_GRAPHITE #include @@ -13,162 +10,80 @@ #include #endif -#define MAXIMUM_DRAW_CACHE_SURFACES 40 - -std::unordered_set> DrawingProgramCache::nodesWithCachedSurfaces; +std::unordered_map, DrawingProgramCache::NodeCache> DrawingProgramCache::nodeCacheMap; DrawingProgramCache::DrawingProgramCache(DrawingProgram& initDrawP): drawP(initDrawP) -{ - lastBvhBuildTime = std::chrono::steady_clock::now(); -} - -void DrawingProgramCache::build(std::vector components) { - bvhRoot = std::make_shared(); - unsortedComponents.clear(); - clear_own_cached_surfaces(); - build_bvh_node(bvhRoot, components); - lastBvhBuildTime = std::chrono::steady_clock::now(); -} - -void DrawingProgramCache::clear() { - bvhRoot = nullptr; - unsortedComponents.clear(); - clear_own_cached_surfaces(); -} - -void DrawingProgramCache::clear_own_cached_surfaces() { - std::erase_if(nodesWithCachedSurfaces, [&](auto& n) { - if(n->drawCache.value().attachedCache == this) { - n->drawCache = std::nullopt; - return true; - } - return false; - }); -} - -bool DrawingProgramCache::check_if_rebuild_should_occur() { - return (unsortedComponents.size() >= MINIMUM_COMPONENTS_TO_START_REBUILD); -} - -void DrawingProgramCache::test_rebuild(const std::vector& comps, bool force) { - if(force || check_if_rebuild_should_occur()) - force_rebuild(comps); -} - -void DrawingProgramCache::test_rebuild_dont_include_set(const std::vector& comps, const std::unordered_set& objsToNotInclude, bool force) { - if(force || check_if_rebuild_should_occur()) - force_rebuild_dont_include_objs(comps, objsToNotInclude); -} - -void DrawingProgramCache::test_rebuild_dont_include_set_dont_include_nodes(const std::vector& comps, const std::unordered_set& objsToNotInclude, const std::unordered_set>& nodesToNotInclude, bool force) { - if(force || check_if_rebuild_should_occur()) { - auto objsToNotIncludeNew = objsToNotInclude; - move_components_from_bvh_nodes_to_set(objsToNotIncludeNew, nodesToNotInclude); - force_rebuild_dont_include_objs(comps, objsToNotIncludeNew); - } -} - -void DrawingProgramCache::move_components_from_bvh_nodes_to_set(std::unordered_set& s, const std::unordered_set>& bvhNodes) { - for(auto& b : bvhNodes) - move_components_from_bvh_node_to_set(s, b); -} - -void DrawingProgramCache::move_components_from_bvh_node_to_set(std::unordered_set& s, const std::shared_ptr& bvhNode) { - for(auto& c : bvhNode->components) - s.emplace(c); - for(auto& p : bvhNode->children) - move_components_from_bvh_node_to_set(s, p); -} - -void DrawingProgramCache::force_rebuild_dont_include_objs(std::vector componentsToBuild, const std::unordered_set& objsToNotInclude) { - std::erase_if(componentsToBuild, [&objsToNotInclude](auto& c) { - return objsToNotInclude.contains(c); - }); - build(componentsToBuild); -} - -void DrawingProgramCache::force_rebuild(const std::vector& componentsToBuild) { - build(componentsToBuild); -} - -const std::vector& DrawingProgramCache::get_unsorted_component_list() const { - return unsortedComponents; -} - -const std::chrono::steady_clock::time_point& DrawingProgramCache::get_last_bvh_build_time() const { - return lastBvhBuildTime; -} +{} void DrawingProgramCache::add_component(const CanvasComponentContainer::ObjInfoSharedPtr& c) { unsortedComponents.emplace_back(c); - invalidate_cache_at_aabb_before_pos(c->obj->get_world_bounds(), c->pos); + invalidate_cache_at_aabb(c->obj->get_world_bounds()); } void DrawingProgramCache::erase_component(const CanvasComponentContainer::ObjInfoSharedPtr& c) { - auto parentBvhNode = c->obj->parentBvhNode.lock(); - if(parentBvhNode) { - std::erase(parentBvhNode->components, c); - c->obj->parentBvhNode.reset(); - } + auto it = objToBVHNode.find(c); + if(it != objToBVHNode.end()) + objToBVHNode.erase(it); else std::erase(unsortedComponents, c); - invalidate_cache_at_aabb_before_pos(c->obj->get_world_bounds(), c->pos); + invalidate_cache_at_aabb(c->obj->get_world_bounds()); } -void DrawingProgramCache::traverse_bvh_erase_function(const SCollision::AABB& aabb, std::function& node, std::vector& components)> f) { - f(nullptr, unsortedComponents); - if(traverse_bvh_erase_function_recursive(bvhRoot, aabb, f)) - bvhRoot = nullptr; -} - -bool DrawingProgramCache::traverse_bvh_erase_function_recursive(const std::shared_ptr& bvhNode, const SCollision::AABB& aabb, std::function& node, std::vector& components)> f) { - if(bvhNode && SCollision::collide(aabb, bvhNode->bounds)) { - if(f(bvhNode, bvhNode->components)) - return true; - std::erase_if(bvhNode->children, [&](auto& p) { - return traverse_bvh_erase_function_recursive(p, aabb, f); - }); - } - return false; -} - -void DrawingProgramCache::traverse_bvh_run_function(const SCollision::AABB& aabb, std::function& node, const std::vector& components)> f) { - f(nullptr, unsortedComponents); - traverse_bvh_run_function_recursive(bvhRoot, aabb, f); -} - -void DrawingProgramCache::traverse_bvh_run_function_recursive(const std::shared_ptr& bvhNode, const SCollision::AABB& aabb, std::function& node, const std::vector& components)> f) { - if(bvhNode && SCollision::collide(aabb, bvhNode->bounds) && f(bvhNode, bvhNode->components)) { - for(auto& p : bvhNode->children) - traverse_bvh_run_function_recursive(p, aabb, f); - } -} - -CanvasComponentContainer::ObjInfoSharedPtr DrawingProgramCache::get_front_object_colliding_with(const SCollision::ColliderCollection& cC) { - auto cCWorld = drawP.world.drawData.cam.c.collider_to_world, SCollision::ColliderCollection>(cC); - CanvasComponentContainer::ObjInfoSharedPtr p; - traverse_bvh_run_function(cCWorld.bounds, [&](const std::shared_ptr& bvhNode, const std::vector& components) { - for(auto& c : components) { - if((!p || c->pos >= p->pos) && c->obj->collides_with_world_coords(drawP.world.drawData.cam.c, cCWorld)) - p = c; +void DrawingProgramCache::invalidate_cache_at_aabb(const SCollision::AABB& aabb) { + for(auto& [node, nodeCache] : nodeCacheMap) { + if(nodeCache.attachedDrawingProgramCache == this && SCollision::collide(aabb, node->bounds)) { + if(nodeCache.invalidBounds.has_value()) { + auto& iBounds = nodeCache.invalidBounds.value(); + iBounds.include_aabb_in_bounds(aabb); + } + else + nodeCache.invalidBounds = aabb; } - return true; + } +} + +bool DrawingProgramCache::should_rebuild() const { + return (unsortedComponents.size() >= MINIMUM_COMPONENTS_TO_START_REBUILD); +} + +bool DrawingProgramCache::unsorted_components_exist() const { + return !unsortedComponents.empty(); +} + +void DrawingProgramCache::build(const std::unordered_set& objsToExclude) { + static int i = 0; + std::cout << "rebuilding... " << i++ << std::endl; + internal_build(drawP.layerMan.get_flattened_component_list(), objsToExclude); +} + +void DrawingProgramCache::internal_build(std::vector componentsToBuild, const std::unordered_set& objsToNotInclude) { + std::erase_if(componentsToBuild, [&objsToNotInclude](auto& c) { + return objsToNotInclude.contains(c); + }); + bvhRoot = std::make_shared(); + unsortedComponents.clear(); + clear_own_cached_surfaces(); + build_bvh_node(bvhRoot, componentsToBuild); +} + +void DrawingProgramCache::clear_own_cached_surfaces() { + std::erase_if(nodeCacheMap, [&](auto& nodeCachePair) { + return nodeCachePair.second.attachedDrawingProgramCache == this; }); - return p; } void DrawingProgramCache::preupdate_component(const CanvasComponentContainer::ObjInfoSharedPtr& c) { - auto parentBvhNode = c->obj->parentBvhNode.lock(); - if(parentBvhNode) { + // Can be called even if object isn't in cache yet. In that case, it'll just invalidate the cache at the object's AABB + auto it = objToBVHNode.find(c); + if(it != objToBVHNode.end()) { unsortedComponents.emplace_back(c); - std::erase(parentBvhNode->components, c); - c->obj->parentBvhNode.reset(); + std::erase(it->second->components, c); } - invalidate_cache_at_aabb_before_pos(c->obj->get_world_bounds(), c->pos); + invalidate_cache_at_aabb(c->obj->get_world_bounds()); } -void DrawingProgramCache::build_bvh_node(const std::shared_ptr& bvhNode, const std::vector& components) { +void DrawingProgramCache::build_bvh_node(const std::shared_ptr& bvhNode, const std::vector& components) { if(components.empty()) return; @@ -176,15 +91,12 @@ void DrawingProgramCache::build_bvh_node(const std::shared_ptrbounds.include_aabb_in_bounds(c->obj->get_world_bounds()); - //std::cout << "component count: " << components.size() << std::endl; - //std::cout << "bvhNode->bounds " << vec_pretty(bvhNode->bounds.min) << " " << vec_pretty(bvhNode->bounds.max) << std::endl; - build_bvh_node_coords_and_resolution(*bvhNode); if(components.size() < MAXIMUM_COMPONENTS_IN_SINGLE_NODE) { bvhNode->components = components; for(auto& c : bvhNode->components) - c->obj->parentBvhNode = bvhNode; + objToBVHNode.emplace(c, bvhNode); return; } @@ -204,31 +116,24 @@ void DrawingProgramCache::build_bvh_node(const std::shared_ptrcomponents.emplace_back(c); - c->obj->parentBvhNode = bvhNode; + objToBVHNode.emplace(c, bvhNode); } } for(auto& p : parts) { if(!p.empty()) - build_bvh_node(bvhNode->children.emplace_back(std::make_shared()), p); + build_bvh_node(bvhNode->children.emplace_back(std::make_shared()), p); } } -void DrawingProgramCache::build_bvh_node_coords_and_resolution(DrawingProgramCacheBVHNode& node) { +void DrawingProgramCache::build_bvh_node_coords_and_resolution(BVHNode& node) { // These are part of the draw cache data, but we're putting it out here, because: // - We dont have to recalculate it every time we refresh the cache // - Some of the data here is needed to determine whether to generate the cache in the first place - // NOTE: We're assuming that devices using OpenGLES are mobile devices have less VRAM, so we decrease the size of the draw cache - // This isn't necessarily true, but it can improve performance on those devices without adding more settings - #if defined(USE_BACKEND_OPENGLES_3_0) - const int MAX_DIMENSION_RESOLUTION = 1024; - #else - const int MAX_DIMENSION_RESOLUTION = 2048; - #endif + constexpr int MAX_DIMENSION_RESOLUTION = 2048; WorldVec cacheBoundDim = node.bounds.dim(); - //std::cout << "cache bound: " << vec_pretty(cacheBoundDim) << std::endl; if(cacheBoundDim.x() > cacheBoundDim.y()) { node.resolution.x() = MAX_DIMENSION_RESOLUTION; node.resolution.y() = MAX_DIMENSION_RESOLUTION * static_cast(cacheBoundDim.y() / cacheBoundDim.x()); @@ -246,43 +151,12 @@ void DrawingProgramCache::build_bvh_node_coords_and_resolution(DrawingProgramCac node.coords.inverseScale = cacheBoundDim.y().divide_double(node.resolution.y()); } -void DrawingProgramCache::invalidate_cache_before_pos(uint32_t placementToInvalidateAt) { - // We could use worldAABB of component to invalidate specific areas. However, that comes with some issues: - // - The AABB couldve been changed from the last frame, so the current worldAABB doesnt actually represent what we should update - // - The worldAABB might not be calculated yet, or mightve been invalidated (worldAABB = nullopt) - // For now, we will ignore worldAABB and just clear cache by placement in list - - std::erase_if(nodesWithCachedSurfaces, [&](auto& n) { - if(n->drawCache.value().attachedCache == this && placementToInvalidateAt <= n->drawCache.value().lastDrawnComponentPlacement) { - n->drawCache = std::nullopt; - return true; - } - return false; - }); -} - -void DrawingProgramCache::invalidate_cache_at_aabb_before_pos(const SCollision::AABB& aabb, uint32_t placementToInvalidateAt) { - std::for_each(nodesWithCachedSurfaces.begin(), nodesWithCachedSurfaces.end(), [&](auto& n) { - if(n->drawCache.value().attachedCache == this && SCollision::collide(aabb, n->bounds)) { - auto& dCache = n->drawCache.value(); - if(dCache.invalidBounds.has_value()) { - auto& iBounds = dCache.invalidBounds.value(); - iBounds.include_aabb_in_bounds(aabb); - } - else - dCache.invalidBounds = aabb; - - if(placementToInvalidateAt <= n->drawCache.value().lastDrawnComponentPlacement) - dCache.isInvalid = true; - } - }); -} - void DrawingProgramCache::refresh_all_draw_cache(const DrawData& drawData) { - std::deque> nodeFlatList; // We want to render children before parents, so that parents can make use of the cached children - traverse_bvh_run_function(drawData.cam.viewingAreaGenerousCollider, [&](std::shared_ptr node, const std::vector& comps) { + std::deque> nodeFlatList; // We want to render children before parents, so that parents can make use of the cached children + traverse_bvh_run_function(drawData.cam.viewingAreaGenerousCollider, [&](std::shared_ptr node, const std::vector& comps) { if(node && node->coords.inverseScale <= drawData.cam.c.inverseScale) { - if(!node->drawCache || node->drawCache.value().isInvalid) + auto it = nodeCacheMap.find(node); + if((it == nodeCacheMap.end()) || it->second.invalidBounds.has_value()) nodeFlatList.emplace_front(node); return false; } @@ -292,14 +166,51 @@ void DrawingProgramCache::refresh_all_draw_cache(const DrawData& drawData) { refresh_draw_cache(nodeFlatList.front(), drawData); } -void DrawingProgramCache::refresh_draw_cache(const std::shared_ptr& bvhNode, const DrawData& drawData) { +void DrawingProgramCache::traverse_bvh_run_function(const SCollision::AABB& aabb, std::function& node, const std::vector& components)> f) { + f(nullptr, unsortedComponents); + traverse_bvh_run_function_recursive(bvhRoot, aabb, f); +} + +void DrawingProgramCache::traverse_bvh_erase_function(const SCollision::AABB& aabb, std::function& node, std::vector& components)> f) { + f(nullptr, unsortedComponents); + if(traverse_bvh_erase_function_recursive(bvhRoot, aabb, f)) + bvhRoot = nullptr; +} + +void DrawingProgramCache::traverse_bvh_run_function_recursive(const std::shared_ptr& bvhNode, const SCollision::AABB& aabb, std::function& node, const std::vector& components)> f) { + if(bvhNode && SCollision::collide(aabb, bvhNode->bounds) && f(bvhNode, bvhNode->components)) { + for(auto& p : bvhNode->children) + traverse_bvh_run_function_recursive(p, aabb, f); + } +} + +bool DrawingProgramCache::traverse_bvh_erase_function_recursive(const std::shared_ptr& bvhNode, const SCollision::AABB& aabb, std::function& node, std::vector& components)> f) { + if(bvhNode && SCollision::collide(aabb, bvhNode->bounds)) { + if(f(bvhNode, bvhNode->components)) + return true; + std::erase_if(bvhNode->children, [&](auto& p) { + return traverse_bvh_erase_function_recursive(p, aabb, f); + }); + } + return false; +} + +void DrawingProgramCache::move_components_from_bvh_node_to_set(std::unordered_set& s, const std::shared_ptr& bvhNode) { + for(auto& c : bvhNode->components) + s.emplace(c); + for(auto& p : bvhNode->children) + move_components_from_bvh_node_to_set(s, p); +} + +void DrawingProgramCache::refresh_draw_cache(const std::shared_ptr& bvhNode, const DrawData& drawData) { if(bvhNode->children.empty() && bvhNode->components.empty()) return; - DrawingProgramCacheBVHNode::DrawCacheData drawCache; - if(bvhNode->drawCache) { - drawCache = bvhNode->drawCache.value(); - bvhNode->drawCache = std::nullopt; // Ensure drawCache is nullopt, so that the draw_components_to_canvas function doesnt use it while drawing + NodeCache nodeCache; + auto bvhNodeCacheIt = nodeCacheMap.find(bvhNode); + if(bvhNodeCacheIt != nodeCacheMap.end()) { + nodeCache = bvhNodeCacheIt->second; + nodeCacheMap.erase(bvhNode); // Ensure nodeCache is erased, so that the draw_components_to_canvas function doesnt use it while drawing } else { #ifdef USE_BACKEND_OPENGLES_3_0 @@ -308,24 +219,24 @@ void DrawingProgramCache::refresh_draw_cache(const std::shared_ptrresolution.x(), bvhNode->resolution.y()); #endif #ifdef USE_SKIA_BACKEND_GRAPHITE - drawCache.surface = SkSurfaces::RenderTarget(drawP.world.main.window.recorder(), imgInfo, skgpu::Mipmapped::kNo, drawP.world.main.window.defaultMSAASurfaceProps); + nodeCache.surface = SkSurfaces::RenderTarget(drawP.world.main.window.recorder(), imgInfo, skgpu::Mipmapped::kNo, drawP.world.main.window.defaultMSAASurfaceProps); #elif USE_SKIA_BACKEND_GANESH - drawCache.surface = SkSurfaces::RenderTarget(drawP.world.main.window.ctx.get(), skgpu::Budgeted::kNo, imgInfo, drawP.world.main.window.defaultMSAASampleCount, &drawP.world.main.window.defaultMSAASurfaceProps); + nodeCache.surface = SkSurfaces::RenderTarget(drawP.world.main.window.ctx.get(), skgpu::Budgeted::kNo, imgInfo, drawP.world.main.window.defaultMSAASampleCount, &drawP.world.main.window.defaultMSAASurfaceProps); #endif - if(!drawCache.surface) + if(!nodeCache.surface) throw std::runtime_error("[DrawingProgramCache::refresh_draw_cache] Could not make cache surface"); } - SkCanvas* cacheCanvas = drawCache.surface->getCanvas(); + SkCanvas* cacheCanvas = nodeCache.surface->getCanvas(); DrawData cacheDrawData = drawData; cacheDrawData.cam.c = bvhNode->coords; cacheDrawData.cam.set_viewing_area(bvhNode->resolution.cast()); cacheDrawData.refresh_draw_optimizing_values(); - if(drawCache.isInvalid) { - auto iBounds = drawCache.invalidBounds.value(); + if(nodeCache.invalidBounds.has_value()) { + auto iBounds = nodeCache.invalidBounds.value(); iBounds = bvhNode->bounds.get_intersection_between_aabbs(iBounds); WorldVec bDim = bvhNode->bounds.dim(); @@ -349,108 +260,103 @@ void DrawingProgramCache::refresh_draw_cache(const std::shared_ptrsave(); cacheCanvas->clipIRect(clipRect); cacheCanvas->clear(SkColor4f{0, 0, 0, 0}); - draw_components_to_canvas(cacheCanvas, cacheDrawData, { - .lastDrawnComponentPlacement = &drawCache.lastDrawnComponentPlacement, - .drawBounds = clipRectBoundAABBWorld, - }); + draw_components_to_canvas(cacheCanvas, cacheDrawData, clipRectBoundAABBWorld); cacheCanvas->restore(); - drawCache.invalidBounds = std::nullopt; - drawCache.isInvalid = false; + nodeCache.invalidBounds = std::nullopt; } else { cacheCanvas->clear(SkColor4f{0, 0, 0, 0}); - draw_components_to_canvas(cacheCanvas, cacheDrawData, { - .lastDrawnComponentPlacement = &drawCache.lastDrawnComponentPlacement, + draw_components_to_canvas(cacheCanvas, cacheDrawData, std::nullopt); + } + + nodeCache.lastRenderTime = std::chrono::steady_clock::now(); + nodeCache.attachedDrawingProgramCache = this; + + while(nodeCacheMap.size() >= MAXIMUM_DRAW_CACHE_SURFACES) { + auto leastUsedNodeIt = nodeCacheMap.begin(); + for(auto it = nodeCacheMap.begin(); it != nodeCacheMap.end(); ++it) { + if(it->second.lastRenderTime < leastUsedNodeIt->second.lastRenderTime) + leastUsedNodeIt = it; + } + nodeCacheMap.erase(leastUsedNodeIt); + } + + nodeCacheMap.emplace(bvhNode, nodeCache); // Set the nodeCache after rendering is done, so that the draw function doesnt assume we have this node cached +} + +void DrawingProgramCache::draw_components_to_canvas(SkCanvas* canvas, const DrawData& drawData, const std::optional>& drawBounds) { + if(drawP.layerMan.layer_tree_root_exists()) { + std::vector> cachedNodesToDraw; + std::vector> uncachedNodes; + + traverse_bvh_run_function(drawData.cam.viewingAreaGenerousCollider, [&](const std::shared_ptr& node, const std::vector& comps) { + if(node) { + auto it = nodeCacheMap.find(node); + if(it != nodeCacheMap.end()) { + auto& nodeCache = it->second; + if(!nodeCache.invalidBounds.has_value() && node->coords.inverseScale <= drawData.cam.c.inverseScale) { + cachedNodesToDraw.emplace_back(node); + return false; + } + } + } + if(node) // Not the "unsorted components" node (which is nullptr) + uncachedNodes.emplace_back(node); + return true; }); + + recursive_draw_layer_item_to_canvas(drawP.layerMan.get_layer_root(), canvas, drawData, drawBounds, uncachedNodes); + + for(auto& nodeCacheToDraw : cachedNodesToDraw) + draw_cache_image_to_canvas(canvas, drawData, nodeCacheToDraw); } +} - drawCache.lastRenderTime = std::chrono::steady_clock::now(); - drawCache.attachedCache = this; - - bvhNode->drawCache = drawCache; // Set the drawCache after rendering is done, so that the draw function doesnt assume we have this node cached - - while(nodesWithCachedSurfaces.size() >= MAXIMUM_DRAW_CACHE_SURFACES) { - std::shared_ptr leastUsedNode = *nodesWithCachedSurfaces.begin(); - for(const std::shared_ptr& n : nodesWithCachedSurfaces) { - if(n->drawCache.value().lastRenderTime < leastUsedNode->drawCache.value().lastRenderTime) - leastUsedNode = n; +void DrawingProgramCache::recursive_draw_layer_item_to_canvas(const DrawingProgramLayerListItem& layerListItem, SkCanvas* canvas, const DrawData& drawData, const std::optional>& drawBounds, const std::vector>& nodesToDraw) { + if(layerListItem.get_visible()) { + SkPaint layerPaint; + layerPaint.setAlphaf(layerListItem.get_alpha()); + layerPaint.setBlendMode(serialized_blend_mode_to_sk_blend_mode(layerListItem.get_blend_mode())); + canvas->saveLayer(nullptr, &layerPaint); + if(layerListItem.is_folder()) { + for(auto& p : layerListItem.get_folder().folderList->get_data() | std::views::reverse) + recursive_draw_layer_item_to_canvas(*p->obj, canvas, drawData, drawBounds, nodesToDraw); } - leastUsedNode->drawCache = std::nullopt; - nodesWithCachedSurfaces.erase(leastUsedNode); + else { + std::vector compsToDraw; + for(auto& c : unsortedComponents) { + if(c->obj->parentLayer == &layerListItem && (!drawBounds.has_value() || SCollision::collide(drawBounds.value(), c->obj->get_world_bounds()))) + compsToDraw.emplace_back(c); + } + for(auto& node : nodesToDraw) { + for(auto& c : node->components) { + if(c->obj->parentLayer == &layerListItem && (!drawBounds.has_value() || SCollision::collide(drawBounds.value(), c->obj->get_world_bounds()))) + compsToDraw.emplace_back(c); + } + } + std::sort(compsToDraw.begin(), compsToDraw.end(), [](auto& a, auto& b) { + return a->pos < b->pos; + }); + for(auto& c : compsToDraw) + c->obj->draw(canvas, drawData); + } + canvas->restore(); } - - nodesWithCachedSurfaces.emplace(bvhNode); } -void DrawingProgramCache::draw_components_to_canvas(SkCanvas* canvas, const DrawData& drawData, DrawComponentsToCanvasOptionalData optData) { - uint32_t lastComponentDrawn = 0; +void DrawingProgramCache::draw_cache_image_to_canvas(SkCanvas* canvas, const DrawData& drawData, const std::shared_ptr& bvhNode) { + auto it = nodeCacheMap.find(bvhNode); + if(it != nodeCacheMap.end()) { + auto& nodeCache = it->second; + canvas->save(); + bvhNode->coords.transform_sk_canvas(canvas, drawData); + nodeCache.lastRenderTime = std::chrono::steady_clock::now(); - std::vector> cachedNodesToDraw; - struct UncachedObjectToDraw { - CanvasComponentContainer::ObjInfoSharedPtr comp; - bool isAnUnsortedObject; - }; - std::vector uncachedCompsToDraw; + SkPaint srcPaint; + srcPaint.setBlendMode(SkBlendMode::kSrc); - traverse_bvh_run_function(drawData.cam.viewingAreaGenerousCollider, [&](const std::shared_ptr& node, const std::vector& comps) { - if(node && node->drawCache && !node->drawCache.value().isInvalid && node->coords.inverseScale <= drawData.cam.c.inverseScale) { - cachedNodesToDraw.emplace_back(node); - lastComponentDrawn = std::max(lastComponentDrawn, node->drawCache->lastDrawnComponentPlacement); - return false; - } + canvas->drawImage(nodeCache.surface->makeTemporaryImage(), 0, 0, {SkFilterMode::kLinear, SkMipmapMode::kLinear}, &srcPaint); - for(auto& c : comps) { - if(!optData.drawBounds.has_value() || SCollision::collide(optData.drawBounds.value(), c->obj->get_world_bounds())) - uncachedCompsToDraw.emplace_back(c, !node); - lastComponentDrawn = std::max(lastComponentDrawn, c->pos); - } - - return true; - }); - - std::sort(uncachedCompsToDraw.begin(), uncachedCompsToDraw.end(), [](auto& a, auto& b) { - return a.comp->pos < b.comp->pos; - }); - std::sort(cachedNodesToDraw.begin(), cachedNodesToDraw.end(), [](auto& a, auto& b) { - return a->drawCache.value().lastDrawnComponentPlacement < b->drawCache.value().lastDrawnComponentPlacement; - }); - size_t nextCacheToRender = 0; - - std::chrono::microseconds unsortedCompDrawTime(0); - - for(auto& uncachedComp : uncachedCompsToDraw) { - for(;;) { - if(nextCacheToRender >= cachedNodesToDraw.size() || uncachedComp.comp->pos <= cachedNodesToDraw[nextCacheToRender]->drawCache.value().lastDrawnComponentPlacement) - break; - draw_cache_image_to_canvas(canvas, drawData, cachedNodesToDraw[nextCacheToRender]); - nextCacheToRender++; - } - std::chrono::time_point drawStartTime = std::chrono::steady_clock::now(); - uncachedComp.comp->obj->draw(canvas, drawData); - if(uncachedComp.isAnUnsortedObject) - unsortedCompDrawTime += std::chrono::duration_cast(std::chrono::steady_clock::now() - drawStartTime); + canvas->restore(); } - for(;nextCacheToRender < cachedNodesToDraw.size(); nextCacheToRender++) - draw_cache_image_to_canvas(canvas, drawData, cachedNodesToDraw[nextCacheToRender]); - - if(optData.lastDrawnComponentPlacement) - *optData.lastDrawnComponentPlacement = lastComponentDrawn; -} - -void DrawingProgramCache::draw_cache_image_to_canvas(SkCanvas* canvas, const DrawData& drawData, const std::shared_ptr& bvhNode) { - auto& drawCache = bvhNode->drawCache.value(); - canvas->save(); - bvhNode->coords.transform_sk_canvas(canvas, drawData); - drawCache.lastRenderTime = std::chrono::steady_clock::now(); - - SkPaint srcPaint; - srcPaint.setBlendMode(SkBlendMode::kSrc); - - canvas->drawImage(drawCache.surface->makeTemporaryImage(), 0, 0, {SkFilterMode::kLinear, SkMipmapMode::kLinear}, &srcPaint); - - canvas->restore(); -} - -DrawingProgramCache::~DrawingProgramCache() { - clear_own_cached_surfaces(); } diff --git a/src/DrawingProgram/DrawingProgramCache.hpp b/src/DrawingProgram/DrawingProgramCache.hpp index 325f28b..b1f59fe 100644 --- a/src/DrawingProgram/DrawingProgramCache.hpp +++ b/src/DrawingProgram/DrawingProgramCache.hpp @@ -1,91 +1,55 @@ #pragma once -#include -#include -#include -#include -#include "../DrawData.hpp" #include "../CanvasComponents/CanvasComponentContainer.hpp" - -class DrawingProgram; -class DrawingProgramCache; - -class DrawingProgramCacheBVHNode { - public: - SCollision::AABB bounds; - std::vector components; - std::vector> children; - - CoordSpaceHelper coords; - Vector2i resolution; - struct DrawCacheData { - uint32_t lastDrawnComponentPlacement; - sk_sp surface; - std::chrono::steady_clock::time_point lastRenderTime; - DrawingProgramCache* attachedCache; - std::optional> invalidBounds; - bool isInvalid = false; - }; - - std::optional drawCache; -}; +#include class DrawingProgramCache { public: - DrawingProgramCache(DrawingProgram& initDrawP); - ~DrawingProgramCache(); - static constexpr size_t MINIMUM_COMPONENTS_TO_START_REBUILD = 1000; static constexpr size_t MAXIMUM_COMPONENTS_IN_SINGLE_NODE = 50; + static constexpr size_t MAXIMUM_DRAW_CACHE_SURFACES = 40; - bool check_if_rebuild_should_occur(); - void test_rebuild(const std::vector& comps, bool force = false); - void test_rebuild_dont_include_set(const std::vector& comps, const std::unordered_set& objsToNotInclude, bool force = false); - void test_rebuild_dont_include_set_dont_include_nodes(const std::vector& comps, const std::unordered_set& objsToNotInclude, const std::unordered_set>& nodesToNotInclude, bool force = false); - - static void move_components_from_bvh_nodes_to_set(std::unordered_set& s, const std::unordered_set>& bvhNodes); - static void move_components_from_bvh_node_to_set(std::unordered_set& s, const std::shared_ptr& bvhNode); - - void erase_component(const CanvasComponentContainer::ObjInfoSharedPtr& c); - void add_component(const CanvasComponentContainer::ObjInfoSharedPtr& c); - void refresh_all_draw_cache(const DrawData& drawData); - void traverse_bvh_run_function(const SCollision::AABB& aabb, std::function& node, const std::vector& components)> f); - void traverse_bvh_erase_function(const SCollision::AABB& aabb, std::function& node, std::vector& components)> f); - // Run before actually updating the component - void preupdate_component(const CanvasComponentContainer::ObjInfoSharedPtr& c); - void invalidate_cache_before_pos(uint32_t placementToInvalidateAt); - void invalidate_cache_at_aabb_before_pos(const SCollision::AABB& aabb, uint32_t placementToInvalidateAt); - void clear(); - - struct DrawComponentsToCanvasOptionalData { - uint32_t* lastDrawnComponentPlacement = nullptr; - std::optional> drawBounds; + struct BVHNode { + SCollision::AABB bounds; + std::vector components; + std::vector> children; + CoordSpaceHelper coords; + Vector2i resolution; }; - void draw_components_to_canvas(SkCanvas* canvas, const DrawData& drawData, DrawComponentsToCanvasOptionalData optData); - const std::vector& get_unsorted_component_list() const; - const std::chrono::steady_clock::time_point& get_last_bvh_build_time() const; + DrawingProgramCache(DrawingProgram& initDrawP); + void add_component(const CanvasComponentContainer::ObjInfoSharedPtr& c); + void erase_component(const CanvasComponentContainer::ObjInfoSharedPtr& c); void clear_own_cached_surfaces(); - - CanvasComponentContainer::ObjInfoSharedPtr get_front_object_colliding_with(const SCollision::ColliderCollection& cC); - + void preupdate_component(const CanvasComponentContainer::ObjInfoSharedPtr& c); + void build(const std::unordered_set& objsToExclude); + void traverse_bvh_run_function(const SCollision::AABB& aabb, std::function& node, const std::vector& components)> f); + void traverse_bvh_erase_function(const SCollision::AABB& aabb, std::function& node, std::vector& components)> f); + bool should_rebuild() const; + void draw_components_to_canvas(SkCanvas* canvas, const DrawData& drawData, const std::optional>& drawBounds); + bool unsorted_components_exist() const; + void invalidate_cache_at_aabb(const SCollision::AABB& aabb); + void move_components_from_bvh_node_to_set(std::unordered_set& s, const std::shared_ptr& bvhNode); + void refresh_all_draw_cache(const DrawData& drawData); private: - static std::unordered_set> nodesWithCachedSurfaces; + struct NodeCache { + sk_sp surface; + std::chrono::steady_clock::time_point lastRenderTime; + DrawingProgramCache* attachedDrawingProgramCache; + std::optional> invalidBounds; + }; + static std::unordered_map, NodeCache> nodeCacheMap; - void draw_cache_image_to_canvas(SkCanvas* canvas, const DrawData& drawData, const std::shared_ptr& bvhNode); + void internal_build(std::vector componentsToBuild, const std::unordered_set& objsToNotInclude); + void build_bvh_node(const std::shared_ptr& bvhNode, const std::vector& components); + void build_bvh_node_coords_and_resolution(BVHNode& node); + void refresh_draw_cache(const std::shared_ptr& bvhNode, const DrawData& drawData); + void traverse_bvh_run_function_recursive(const std::shared_ptr& bvhNode, const SCollision::AABB& aabb, std::function& node, const std::vector& components)> f); + bool traverse_bvh_erase_function_recursive(const std::shared_ptr& bvhNode, const SCollision::AABB& aabb, std::function& node, std::vector& components)> f); + void draw_cache_image_to_canvas(SkCanvas* canvas, const DrawData& drawData, const std::shared_ptr& bvhNode); + void recursive_draw_layer_item_to_canvas(const DrawingProgramLayerListItem& layerListItem, SkCanvas* canvas, const DrawData& drawData, const std::optional>& drawBounds, const std::vector>& nodesToDraw); - void force_rebuild_dont_include_objs(std::vector componentsToBuild, const std::unordered_set& objsToNotInclude); - void force_rebuild(const std::vector& componentsToBuild); - - bool traverse_bvh_erase_function_recursive(const std::shared_ptr& bvhNode, const SCollision::AABB& aabb, std::function& node, std::vector& components)> f); - void build_bvh_node_coords_and_resolution(DrawingProgramCacheBVHNode& node); - void refresh_draw_cache(const std::shared_ptr& bvhNode, const DrawData& drawData); - void build(std::vector components); - void traverse_bvh_run_function_recursive(const std::shared_ptr& bvhNode, const SCollision::AABB& aabb, std::function& node, const std::vector& components)> f); - - void build_bvh_node(const std::shared_ptr& bvhNode, const std::vector& components); - - std::chrono::steady_clock::time_point lastBvhBuildTime; - std::shared_ptr bvhRoot; + std::unordered_map> objToBVHNode; + std::shared_ptr bvhRoot; std::vector unsortedComponents; DrawingProgram& drawP; }; diff --git a/src/DrawingProgram/DrawingProgramCacheNew.cpp b/src/DrawingProgram/DrawingProgramCacheNew.cpp deleted file mode 100644 index 4b45df3..0000000 --- a/src/DrawingProgram/DrawingProgramCacheNew.cpp +++ /dev/null @@ -1,141 +0,0 @@ -#include "DrawingProgramCacheNew.hpp" -#include "DrawingProgram.hpp" - -std::unordered_set> DrawingProgramCacheNew::nodesWithCachedSurfaces; - -DrawingProgramCacheNew::DrawingProgramCacheNew(DrawingProgram& initDrawP): - drawP(initDrawP) -{} - -void DrawingProgramCacheNew::add_component(const CanvasComponentContainer::ObjInfoSharedPtr& c) { - unsortedComponents.emplace_back(c); - invalidate_cache_at_aabb(c->obj->get_world_bounds()); -} - -void DrawingProgramCacheNew::erase_component(const CanvasComponentContainer::ObjInfoSharedPtr& c) { - auto it = objToBVHNode.find(c); - if(it != objToBVHNode.end()) - objToBVHNode.erase(it); - else - std::erase(unsortedComponents, c); - invalidate_cache_at_aabb(c->obj->get_world_bounds()); -} - -void DrawingProgramCacheNew::invalidate_cache_at_aabb(const SCollision::AABB& aabb) { - std::for_each(nodesWithCachedSurfaces.begin(), nodesWithCachedSurfaces.end(), [&](auto& n) { - if(n->drawCache.value().attachedCache == this && SCollision::collide(aabb, n->bounds)) { - auto& dCache = n->drawCache.value(); - if(dCache.invalidBounds.has_value()) { - auto& iBounds = dCache.invalidBounds.value(); - iBounds.include_aabb_in_bounds(aabb); - } - else - dCache.invalidBounds = aabb; - } - }); -} - -bool DrawingProgramCacheNew::should_rebuild() const { - return (unsortedComponents.size() >= MINIMUM_COMPONENTS_TO_START_REBUILD); -} - -void DrawingProgramCacheNew::build(const std::unordered_set& objsToExclude) { - internal_build(drawP.layerMan.get_flattened_component_list(), objsToExclude); -} - -void DrawingProgramCacheNew::internal_build(std::vector componentsToBuild, const std::unordered_set& objsToNotInclude) { - std::erase_if(componentsToBuild, [&objsToNotInclude](auto& c) { - return objsToNotInclude.contains(c); - }); - bvhRoot = std::make_shared(); - unsortedComponents.clear(); - clear_own_cached_surfaces(); - build_bvh_node(bvhRoot, componentsToBuild); -} - -void DrawingProgramCacheNew::clear_own_cached_surfaces() { - std::erase_if(nodesWithCachedSurfaces, [&](auto& n) { - if(n->drawCache.value().attachedCache == this) { - n->drawCache = std::nullopt; - return true; - } - return false; - }); -} - -void DrawingProgramCacheNew::preupdate_component(const CanvasComponentContainer::ObjInfoSharedPtr& c) { - auto it = objToBVHNode.find(c); - if(it != objToBVHNode.end()) { - unsortedComponents.emplace_back(c); - std::erase(it->second->components, c); - } - invalidate_cache_at_aabb(c->obj->get_world_bounds()); -} - -void DrawingProgramCacheNew::build_bvh_node(const std::shared_ptr& bvhNode, const std::vector& components) { - if(components.empty()) - return; - - bvhNode->bounds = components.front()->obj->get_world_bounds(); - for(auto& c : components) - bvhNode->bounds.include_aabb_in_bounds(c->obj->get_world_bounds()); - - build_bvh_node_coords_and_resolution(*bvhNode); - - if(components.size() < MAXIMUM_COMPONENTS_IN_SINGLE_NODE) { - bvhNode->components = components; - for(auto& c : bvhNode->components) - objToBVHNode.emplace(c, bvhNode); - return; - } - - WorldVec boundsCenter = bvhNode->bounds.center(); - - std::array, 4> parts; - - for(auto& c : components) { - const auto& cAABB = c->obj->get_world_bounds(); - 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()) - parts[1].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()) - parts[2].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()) - parts[3].emplace_back(c); - else { - bvhNode->components.emplace_back(c); - objToBVHNode.emplace(c, bvhNode); - } - } - - for(auto& p : parts) { - if(!p.empty()) - build_bvh_node(bvhNode->children.emplace_back(std::make_shared()), p); - } -} - -void DrawingProgramCacheNew::build_bvh_node_coords_and_resolution(BVHNode& node) { - // These are part of the draw cache data, but we're putting it out here, because: - // - We dont have to recalculate it every time we refresh the cache - // - Some of the data here is needed to determine whether to generate the cache in the first place - - constexpr int MAX_DIMENSION_RESOLUTION = 2048; - - WorldVec cacheBoundDim = node.bounds.dim(); - if(cacheBoundDim.x() > cacheBoundDim.y()) { - node.resolution.x() = MAX_DIMENSION_RESOLUTION; - node.resolution.y() = MAX_DIMENSION_RESOLUTION * static_cast(cacheBoundDim.y() / cacheBoundDim.x()); - } - else { - node.resolution.y() = MAX_DIMENSION_RESOLUTION; - node.resolution.x() = MAX_DIMENSION_RESOLUTION * static_cast(cacheBoundDim.x() / cacheBoundDim.y()); - } - node.coords.rotation = 0.0; - node.coords.pos = node.bounds.min; - // Not necessary, but we choose the number that had less operations done on it for more accuracy - if(node.resolution.x() > node.resolution.y()) - node.coords.inverseScale = cacheBoundDim.x().divide_double(node.resolution.x()); - else - node.coords.inverseScale = cacheBoundDim.y().divide_double(node.resolution.y()); -} diff --git a/src/DrawingProgram/DrawingProgramCacheNew.hpp b/src/DrawingProgram/DrawingProgramCacheNew.hpp deleted file mode 100644 index 2d4b7d5..0000000 --- a/src/DrawingProgram/DrawingProgramCacheNew.hpp +++ /dev/null @@ -1,46 +0,0 @@ -#pragma once -#include "../CanvasComponents/CanvasComponentContainer.hpp" -#include - -class DrawingProgramCacheNew { - public: - static constexpr size_t MINIMUM_COMPONENTS_TO_START_REBUILD = 1000; - static constexpr size_t MAXIMUM_COMPONENTS_IN_SINGLE_NODE = 50; - static constexpr size_t MAXIMUM_DRAW_CACHE_SURFACES = 40; - - DrawingProgramCacheNew(DrawingProgram& initDrawP); - void add_component(const CanvasComponentContainer::ObjInfoSharedPtr& c); - void erase_component(const CanvasComponentContainer::ObjInfoSharedPtr& c); - void clear_own_cached_surfaces(); - void preupdate_component(const CanvasComponentContainer::ObjInfoSharedPtr& c); - void build(const std::unordered_set& objsToExclude); - bool should_rebuild() const; - private: - struct BVHNode { - SCollision::AABB bounds; - std::vector components; - std::vector> children; - - CoordSpaceHelper coords; - Vector2i resolution; - struct DrawCacheData { - sk_sp surface; - std::chrono::steady_clock::time_point lastRenderTime; - DrawingProgramCacheNew* attachedCache; - std::optional> invalidBounds; - }; - - std::optional drawCache; - }; - static std::unordered_set> nodesWithCachedSurfaces; - - void internal_build(std::vector componentsToBuild, const std::unordered_set& objsToNotInclude); - void invalidate_cache_at_aabb(const SCollision::AABB& aabb); - void build_bvh_node(const std::shared_ptr& bvhNode, const std::vector& components); - void build_bvh_node_coords_and_resolution(BVHNode& node); - - std::unordered_map> objToBVHNode; - std::shared_ptr bvhRoot; - std::vector unsortedComponents; - DrawingProgram& drawP; -}; diff --git a/src/DrawingProgram/DrawingProgramSelection.cpp b/src/DrawingProgram/DrawingProgramSelection.cpp deleted file mode 100644 index b90965e..0000000 --- a/src/DrawingProgram/DrawingProgramSelection.cpp +++ /dev/null @@ -1,500 +0,0 @@ -#include "DrawingProgramSelection.hpp" -#include "DrawingProgram.hpp" -#include "../World.hpp" -#include "../MainProgram.hpp" -#include "Tools/DrawingProgramToolBase.hpp" -#include "Helpers/FixedPoint.hpp" -#include -#include -#include -#include - -#ifdef USE_SKIA_BACKEND_GRAPHITE - #include -#elif USE_SKIA_BACKEND_GANESH - #include - #include -#endif - -#include -#include - -#define ROTATION_POINT_RADIUS_MULTIPLIER 0.7f -#define ROTATION_POINTS_DISTANCE 20.0f - -DrawingProgramSelection::DrawingProgramSelection(DrawingProgram& initDrawP): - cache(initDrawP), - drawP(initDrawP) -{} - -const std::unordered_set& DrawingProgramSelection::get_selected_set() { - return selectedSet; -} - -void DrawingProgramSelection::erase_component(const CanvasComponentContainer::ObjInfoSharedPtr& objToCheck) { - if(is_selected(objToCheck)) { - cache.erase_component(objToCheck); - selectedSet.erase(objToCheck); - } -} - -void DrawingProgramSelection::fully_collided_erase_select_objects_func(std::unordered_set& selectedComponents, const std::shared_ptr& bvhNode) { - if(bvhNode) { - for(auto& c : bvhNode->components) - selectedComponents.emplace(c); - for(auto& p : bvhNode->children) - fully_collided_erase_select_objects_func(selectedComponents, p); - } -} - -std::function&, std::vector&)> DrawingProgramSelection::erase_select_objects_in_bvh_func(std::unordered_set& selectedComponents, const SCollision::ColliderCollection& cC, const SCollision::ColliderCollection& cCWorld) { - auto toRet = [&](const auto& bvhNode, auto& comps) { - if(bvhNode && (bvhNode->coords.inverseScale << 9) < drawP.world.drawData.cam.c.inverseScale && - SCollision::collide(cC, drawP.world.drawData.cam.c.to_space(bvhNode->bounds.min)) && - SCollision::collide(cC, drawP.world.drawData.cam.c.to_space(bvhNode->bounds.max)) && - SCollision::collide(cC, drawP.world.drawData.cam.c.to_space(bvhNode->bounds.top_right())) && - SCollision::collide(cC, drawP.world.drawData.cam.c.to_space(bvhNode->bounds.bottom_left()))) { - fully_collided_erase_select_objects_func(selectedComponents, bvhNode); - drawP.compCache.invalidate_cache_at_aabb_before_pos(bvhNode->bounds, 0); - return true; - } - std::erase_if(comps, [&](auto& c) { - if(c->obj->collides_with(drawP.world.drawData.cam.c, cCWorld, cC)) { - selectedComponents.emplace(c); - drawP.compCache.invalidate_cache_at_aabb_before_pos(c->obj->get_world_bounds(), c->pos); - return true; - } - return false; - }); - return false; - }; - - return toRet; -} - -void DrawingProgramSelection::add_from_cam_coord_collider_to_selection(const SCollision::ColliderCollection& cC, bool frontObjectOnly) { - std::unordered_set selectedComponents; - if(frontObjectOnly) { - CanvasComponentContainer::ObjInfoSharedPtr a = drawP.compCache.get_front_object_colliding_with(cC); - if(a) { - selectedComponents.emplace(a); - drawP.compCache.erase_component(a); - } - } - else { - auto cCWorld = drawP.world.drawData.cam.c.collider_to_world, SCollision::ColliderCollection>(cC); - drawP.compCache.traverse_bvh_erase_function(cCWorld.bounds, erase_select_objects_in_bvh_func(selectedComponents, cC, cCWorld)); - } - add_to_selection(selectedComponents); -} - -void DrawingProgramSelection::remove_from_cam_coord_collider_to_selection(const SCollision::ColliderCollection& cC, bool frontObjectOnly) { - auto cCWorld = drawP.world.drawData.cam.c.collider_to_world, SCollision::ColliderCollection>(cC); - std::unordered_set selectedComponents; - if(frontObjectOnly) { - CanvasComponentContainer::ObjInfoSharedPtr a = cache.get_front_object_colliding_with(cC); - if(a) { - selectedComponents.emplace(a); - cache.erase_component(a); - } - } - else { - cache.traverse_bvh_erase_function(cCWorld.bounds, erase_select_objects_in_bvh_func(selectedComponents, cC, cCWorld)); - cache.clear_own_cached_surfaces(); - } - std::erase_if(selectedSet, [&](auto& c) { - return selectedComponents.contains(c); - }); - for(auto& obj : selectedComponents) - drawP.compCache.add_component(obj); - if(!is_something_selected()) { - reset_selection_data(); - reset_transform_data(); - } - else { - calculate_aabb(); - calculate_initial_rotate_center_location(); - } -} - -void DrawingProgramSelection::add_to_selection(const std::unordered_set& newSelection) { - selectedSet.insert(newSelection.begin(), newSelection.end()); - for(auto& obj : newSelection) - cache.add_component(obj); - calculate_aabb(); - calculate_initial_rotate_center_location(); -} - -void DrawingProgramSelection::set_to_selection(const std::unordered_set& newSelection) { - selectedSet = newSelection; - for(auto& obj : selectedSet) - cache.add_component(obj); - calculate_aabb(); - calculate_initial_rotate_center_location(); -} - -bool DrawingProgramSelection::is_something_selected() { - return !selectedSet.empty(); -} - -void DrawingProgramSelection::calculate_aabb() { - if(is_something_selected()) { - initialSelectionAABB = (*selectedSet.begin())->obj->get_world_bounds(); - for(auto& c : selectedSet) - initialSelectionAABB.include_aabb_in_bounds(c->obj->get_world_bounds()); - } -} - -void DrawingProgramSelection::deselect_all() { - if(is_something_selected()) { - bool cacheWillRebuildAnyway = selectedSet.size() >= DrawingProgramCache::MINIMUM_COMPONENTS_TO_START_REBUILD; - if(cacheWillRebuildAnyway) - drawP.compCache.test_rebuild(drawP.components->get_data(), true); - else { - for(auto& obj : selectedSet) - drawP.compCache.add_component(obj); - } - reset_selection_data(); - reset_transform_data(); - } -} - -void DrawingProgramSelection::commit_transform_selection() { - auto selectedSetTemp = selectedSet; - - std::vector a(selectedSet.begin(), selectedSet.end()); - std::vector> transformsFrom; - for(auto& transformedObj : a) - transformsFrom.emplace_back(transformedObj, transformedObj->obj->coords); - bool isSingleThread = a.size() < DrawingProgramCache::MINIMUM_COMPONENTS_TO_START_REBUILD; - parallel_loop_container(a, [&](auto& obj) { - obj->obj->coords = selectionTransformCoords.other_coord_space_from_this_space(obj->obj->coords); - obj->obj->commit_transform_dont_invalidate_cache(drawP); - }, isSingleThread); - std::vector> transformsTo; - std::vector> transformsToSend; - for(auto& transformedObj : a) { - transformsToSend.emplace_back(transformedObj->obj.get_net_id(), transformedObj->obj->coords); - transformsTo.emplace_back(transformedObj, transformedObj->obj->coords); - } - //DrawComponent::client_send_transform_many(drawP, transformsToSend); - - reset_selection_data(); - reset_transform_data(); - set_to_selection(selectedSetTemp); -} - -CanvasComponentContainer::ObjInfoSharedPtr DrawingProgramSelection::get_front_object_colliding_with(const SCollision::ColliderCollection& cC) { - return cache.get_front_object_colliding_with(cC); -} - -void DrawingProgramSelection::invalidate_cache_at_aabb_before_pos(const SCollision::AABB& aabb, uint64_t placementToInvalidateAt) { - cache.invalidate_cache_at_aabb_before_pos(aabb, placementToInvalidateAt); -} - -void DrawingProgramSelection::clear_own_cached_surfaces() { - cache.clear_own_cached_surfaces(); -} - -void DrawingProgramSelection::preupdate_component(const CanvasComponentContainer::ObjInfoSharedPtr& objToCheck) { - cache.preupdate_component(objToCheck); -} - -bool DrawingProgramSelection::is_selected(const CanvasComponentContainer::ObjInfoSharedPtr& objToCheck) { - return selectedSet.contains(objToCheck); -} - -void DrawingProgramSelection::delete_all() { - if(is_something_selected()) { - //drawP.client_erase_set(selectedSet); - reset_selection_data(); - reset_transform_data(); - } -} - -// NOTE: Only run this if no transformations happened -void DrawingProgramSelection::selection_to_clipboard() { - //auto& clipboard = drawP.world.main.clipboard; - //std::unordered_set resourceSet; - //for(auto& c : selectedSet) - // c->obj->get_used_resources(resourceSet); - //std::vector compVecSort(selectedSet.begin(), selectedSet.end()); - //std::sort(compVecSort.begin(), compVecSort.end(), [&](auto& a, auto& b) { - // return a->pos < b->pos; - //}); - //clipboard.components.clear(); - //for(auto& c : compVecSort) - // clipboard.components.emplace_back(c->obj->deep_copy(drawP)); - //clipboard.pos = initialSelectionAABB.center(); - //clipboard.inverseScale = drawP.world.drawData.cam.c.inverseScale; - //drawP.world.rMan.copy_resource_set_to_map(resourceSet, clipboard.resources); -} - -void DrawingProgramSelection::update() { - if(is_something_selected()) { - if(cache.check_if_rebuild_should_occur()) - cache.test_rebuild(std::vector(selectedSet.begin(), selectedSet.end()), true); - - selectionRectPoints[0] = selectionTransformCoords.from_space_world(initialSelectionAABB.min); - selectionRectPoints[1] = selectionTransformCoords.from_space_world(initialSelectionAABB.bottom_left()); - selectionRectPoints[2] = selectionTransformCoords.from_space_world(initialSelectionAABB.max); - selectionRectPoints[3] = selectionTransformCoords.from_space_world(initialSelectionAABB.top_right()); - - scaleData.handlePoint = drawP.world.drawData.cam.c.to_space(initialSelectionAABB.max); - rotateData.centerHandlePoint = drawP.world.drawData.cam.c.to_space(rotateData.centerPos); - rotateData.handlePoint = get_rotation_point_pos_from_angle(rotateData.rotationAngle); - - rebuild_cam_space(); - - if(drawP.is_actual_selection_tool(drawP.drawTool->get_type())) { - switch(transformOpHappening) { - case TransformOperation::NONE: - if(drawP.controls.leftClick && !drawP.world.main.input.key(InputManager::KEY_GENERIC_LSHIFT).held && !drawP.world.main.input.key(InputManager::KEY_GENERIC_LALT).held) { - if(mouse_collided_with_scale_point()) { - scaleData.currentPos = scaleData.startPos = selectionTransformCoords.from_space_world(initialSelectionAABB.max); - scaleData.centerPos = selectionTransformCoords.from_space_world(initialSelectionAABB.center()); - transformOpHappening = TransformOperation::SCALE; - } - else if(mouse_collided_with_rotate_center_handle_point()) - transformOpHappening = TransformOperation::ROTATE_RELOCATE_CENTER; - else if(mouse_collided_with_rotate_handle_point()) { - rotateData.rotationAngle = 0.0; - transformOpHappening = TransformOperation::ROTATE; - } - else if(mouse_collided_with_selection_aabb()) { - translateData.startPos = drawP.world.get_mouse_world_pos(); - transformOpHappening = TransformOperation::TRANSLATE; - } - } - break; - case TransformOperation::TRANSLATE: - if(drawP.controls.leftClickHeld) - selectionTransformCoords = CoordSpaceHelperTransform(drawP.world.get_mouse_world_pos() - translateData.startPos); - else { - commit_transform_selection(); - return; - } - break; - case TransformOperation::SCALE: - if(drawP.controls.leftClickHeld) { - WorldVec centerToScaleStart = scaleData.startPos - scaleData.centerPos; - Vector2f centerToScaleStartInCamSpace = drawP.world.drawData.cam.c.normalized_dir_to_space(centerToScaleStart.normalized()); - Vector2f scaleCenterPointInCamSpace = drawP.world.drawData.cam.c.to_space(scaleData.centerPos); - scaleData.currentPos = drawP.world.drawData.cam.c.from_space(project_point_on_line(drawP.world.main.input.mouse.pos, scaleCenterPointInCamSpace, (scaleCenterPointInCamSpace + centerToScaleStartInCamSpace).eval())); - - WorldVec centerToScaleCurrent = scaleData.currentPos - scaleData.centerPos; - - WorldScalar centerToScaleStartNorm = centerToScaleStart.norm(); - WorldScalar centerToScaleCurrentNorm = centerToScaleCurrent.norm(); - bool isAnyNumberZero = centerToScaleCurrentNorm == WorldScalar(0) || centerToScaleStartNorm == WorldScalar(0); - - if(!isAnyNumberZero) { - WorldMultiplier scaleAmount = WorldMultiplier(centerToScaleStartNorm) / WorldMultiplier(centerToScaleCurrentNorm); - - selectionTransformCoords = CoordSpaceHelperTransform(scaleData.centerPos, scaleAmount); - } - } - else { - commit_transform_selection(); - return; - } - break; - case TransformOperation::ROTATE_RELOCATE_CENTER: - if(drawP.controls.leftClickHeld) - rotateData.centerPos = drawP.world.get_mouse_world_pos(); - else - transformOpHappening = TransformOperation::NONE; - break; - case TransformOperation::ROTATE: - if(drawP.controls.leftClickHeld) { - Vector2f rotationPointDiff = drawP.world.main.input.mouse.pos - rotateData.centerHandlePoint; - rotateData.rotationAngle = std::atan2(rotationPointDiff.y(), rotationPointDiff.x()); - selectionTransformCoords = CoordSpaceHelperTransform(rotateData.centerPos, rotateData.rotationAngle); - } - else { - commit_transform_selection(); - return; - } - break; - } - } - else if(transformOpHappening != TransformOperation::NONE) { - commit_transform_selection(); - return; - } - - if(drawP.world.main.input.key(InputManager::KEY_GENERIC_ESCAPE).pressed) - deselect_all(); - else if(drawP.world.main.input.key(InputManager::KEY_DRAW_DELETE).pressed) - delete_all(); - else if(drawP.world.main.input.key(InputManager::KEY_COPY).pressed && !is_being_transformed()) - selection_to_clipboard(); - else if(drawP.world.main.input.key(InputManager::KEY_CUT).pressed && !is_being_transformed()) { - selection_to_clipboard(); - delete_all(); - } - else if(drawP.world.main.input.key(InputManager::KEY_PASTE).pressed) { - deselect_all(); - paste_clipboard(drawP.world.main.input.mouse.pos); - } - } - else if(drawP.world.main.input.key(InputManager::KEY_PASTE).pressed && !drawP.prevent_undo_or_redo()) - paste_clipboard(drawP.world.main.input.mouse.pos); - else if(drawP.world.main.input.key(InputManager::KEY_GENERIC_ESCAPE).pressed) - drawP.switch_to_tool(DrawingProgramToolType::EDIT, true); -} - -bool DrawingProgramSelection::is_being_transformed() { - return transformOpHappening != TransformOperation::NONE; -} - -void DrawingProgramSelection::paste_clipboard(Vector2f pasteScreenPos) { - //auto& clipboard = drawP.world.main.clipboard; - - //if(!drawP.is_selection_allowing_tool(drawP.drawTool->get_type())) - // drawP.switch_to_tool(DrawingProgramToolType::EDIT); - - //uint32_t allPlacement = drawP.components->size(); - //std::vector> placedComponents; - //WorldVec mousePos = drawP.world.drawData.cam.c.from_space(pasteScreenPos); - //WorldVec moveVec = drawP.world.main.clipboard.pos - mousePos; - //WorldMultiplier scaleMultiplier = WorldMultiplier(drawP.world.main.clipboard.inverseScale) / WorldMultiplier(drawP.world.drawData.cam.c.inverseScale); - //WorldScalar scaleLimit(0.001); - //for(auto& c : drawP.world.main.clipboard.components) { - // if((c->coords.inverseScale / scaleMultiplier) < scaleLimit) { - // Logger::get().log("WORLDFATAL", "Some pasted objects will be too small! Scale up the canvas first (zoom in alot)"); - // return; - // } - //} - - //std::unordered_map resourceRemapIDs; - //for(auto& r : clipboard.resources) - // resourceRemapIDs[r.first] = drawP.world.rMan.add_resource(r.second); - //for(auto& c : clipboard.components) - // placedComponents.emplace_back(c->deep_copy(drawP)); - //drawP.addToCompCacheOnInsert = false; - //auto compListInserted = drawP.components.client_insert_ordered_vector_items(allPlacement, placedComponents); - //parallel_loop_container(compListInserted, [&](auto& c) { - // c->obj->remap_resource_ids(resourceRemapIDs); - // c->obj->get_coords().translate(-moveVec); - // c->obj->get_coords().scale_about(mousePos, scaleMultiplier); - // c->obj->commit_transform(drawP, false); - //}); - //DrawComponent::client_send_place_many(drawP, compListInserted); - //drawP.addToCompCacheOnInsert = true; - //std::unordered_set compSetInserted(compListInserted.begin(), compListInserted.end()); - //set_to_selection(compSetInserted); - //drawP.add_undo_place_components(compSetInserted); -} - -void DrawingProgramSelection::rebuild_cam_space() { - SCollision::ColliderCollection collideRectWorld; - collideRectWorld.triangle.emplace_back(selectionRectPoints[0], selectionRectPoints[1], selectionRectPoints[2]); - collideRectWorld.triangle.emplace_back(selectionRectPoints[0], selectionRectPoints[2], selectionRectPoints[3]); - collideRectWorld.recalculate_bounds(); - - camSpaceSelection = drawP.world.drawData.cam.c.world_collider_to_coords>(collideRectWorld); -} - -void DrawingProgramSelection::calculate_initial_rotate_center_location() { - rotateData.centerPos = initialSelectionAABB.center(); -} - -bool DrawingProgramSelection::mouse_collided_with_selection() { - return mouse_collided_with_selection_aabb() || mouse_collided_with_scale_point() || mouse_collided_with_rotate_center_handle_point() || mouse_collided_with_rotate_handle_point(); -} - -bool DrawingProgramSelection::mouse_collided_with_selection_aabb() { - return SCollision::collide(camSpaceSelection, drawP.world.main.input.mouse.pos); -} - -bool DrawingProgramSelection::mouse_collided_with_scale_point() { - return SCollision::collide(SCollision::Circle(scaleData.handlePoint, drawP.drag_point_radius()), drawP.world.main.input.mouse.pos); -} - -bool DrawingProgramSelection::mouse_collided_with_rotate_center_handle_point() { - return SCollision::collide(SCollision::Circle(rotateData.centerHandlePoint, drawP.drag_point_radius()), drawP.world.main.input.mouse.pos); -} - -bool DrawingProgramSelection::mouse_collided_with_rotate_handle_point() { - return SCollision::collide(SCollision::Circle(rotateData.handlePoint, drawP.drag_point_radius() * ROTATION_POINT_RADIUS_MULTIPLIER), drawP.world.main.input.mouse.pos); -} - -Vector2f DrawingProgramSelection::get_rotation_point_pos_from_angle(double angle) { - return Vector2f{rotateData.centerHandlePoint + ROTATION_POINTS_DISTANCE * drawP.world.main.toolbar.final_gui_scale() * Vector2f{std::cos(angle), std::sin(angle)}}; -} - -void DrawingProgramSelection::draw_components(SkCanvas* canvas, const DrawData& drawData) { - if(is_something_selected()) { - selectionRectPoints[0] = selectionTransformCoords.from_space_world(initialSelectionAABB.min); - selectionRectPoints[1] = selectionTransformCoords.from_space_world(initialSelectionAABB.bottom_left()); - selectionRectPoints[2] = selectionTransformCoords.from_space_world(initialSelectionAABB.max); - selectionRectPoints[3] = selectionTransformCoords.from_space_world(initialSelectionAABB.top_right()); - - scaleData.handlePoint = drawP.world.drawData.cam.c.to_space(selectionTransformCoords.from_space_world(initialSelectionAABB.max)); - rotateData.centerHandlePoint = drawP.world.drawData.cam.c.to_space(selectionTransformCoords.from_space_world(rotateData.centerPos)); - rotateData.handlePoint = get_rotation_point_pos_from_angle(rotateData.rotationAngle); - - rebuild_cam_space(); - - DrawData selectionDrawData = drawData; - selectionDrawData.cam.c = selectionTransformCoords.other_coord_space_to_this_space(selectionDrawData.cam.c); - selectionDrawData.cam.set_viewing_area(drawP.world.main.window.size.cast()); - selectionDrawData.refresh_draw_optimizing_values(); - - cache.refresh_all_draw_cache(selectionDrawData); - - SkImageInfo imgInfo = canvas->imageInfo(); - sk_sp surface; - #ifdef USE_SKIA_BACKEND_GRAPHITE - surface = SkSurfaces::RenderTarget(drawP.world.main.window.recorder(), imgInfo, skgpu::Mipmapped::kNo, drawP.world.main.window.defaultMSAASurfaceProps); - #elif USE_SKIA_BACKEND_GANESH - surface = SkSurfaces::RenderTarget(drawP.world.main.window.ctx.get(), skgpu::Budgeted::kNo, imgInfo, drawP.world.main.window.defaultMSAASampleCount, &drawP.world.main.window.defaultMSAASurfaceProps); - #endif - if(!surface) - throw std::runtime_error("[DrawingProgramSelection::draw_components] Could not make temporary surface"); - - cache.draw_components_to_canvas(surface->getCanvas(), selectionDrawData, {}); - - SkPaint glowBlurP; - glowBlurP.setImageFilter(SkImageFilters::Blur(5, 5, nullptr)); - - canvas->drawImage(surface->makeTemporaryImage(), 0, 0, SkSamplingOptions{SkFilterMode::kLinear}, &glowBlurP); - canvas->drawImage(surface->makeTemporaryImage(), 0, 0, SkSamplingOptions{SkFilterMode::kLinear}, nullptr); - } -} - -void DrawingProgramSelection::draw_gui(SkCanvas* canvas, const DrawData& drawData) { - if(is_something_selected() && !camSpaceSelection.triangle.empty()) { - SkPathBuilder selectionRectPath; - selectionRectPath.moveTo(convert_vec2(camSpaceSelection.triangle[0].p[0])); - selectionRectPath.lineTo(convert_vec2(camSpaceSelection.triangle[0].p[1])); - selectionRectPath.lineTo(convert_vec2(camSpaceSelection.triangle[0].p[2])); - selectionRectPath.lineTo(convert_vec2(camSpaceSelection.triangle[1].p[2])); - selectionRectPath.close(); - SkPaint p{SkColor4f{0.3f, 0.6f, 0.9f, 0.4f}}; - canvas->drawPath(selectionRectPath.detach(), p); - - if(drawP.is_actual_selection_tool(drawP.drawTool->get_type())) { - if(transformOpHappening == TransformOperation::NONE || transformOpHappening == TransformOperation::ROTATE || transformOpHappening == TransformOperation::ROTATE_RELOCATE_CENTER) - drawP.draw_drag_circle(canvas, rotateData.centerHandlePoint, {0.9f, 0.5f, 0.1f, 1.0f}, drawData); - if(transformOpHappening == TransformOperation::NONE || transformOpHappening == TransformOperation::ROTATE) - drawP.draw_drag_circle(canvas, rotateData.handlePoint, {0.9f, 0.5f, 0.1f, 1.0f}, drawData, ROTATION_POINT_RADIUS_MULTIPLIER); - if(transformOpHappening == TransformOperation::NONE || transformOpHappening == TransformOperation::SCALE) - drawP.draw_drag_circle(canvas, scaleData.handlePoint, {0.1f, 0.9f, 0.9f, 1.0f}, drawData); - } - } -} - -void DrawingProgramSelection::reset_selection_data() { - selectedSet.clear(); - cache.clear(); -} - -void DrawingProgramSelection::reset_transform_data() { - selectionTransformCoords = CoordSpaceHelperTransform(); - transformOpHappening = TransformOperation::NONE; - translateData = TranslationData(); - scaleData = ScaleData(); - rotateData = RotationData(); -} diff --git a/src/DrawingProgram/DrawingProgramSelection.hpp b/src/DrawingProgram/DrawingProgramSelection.hpp deleted file mode 100644 index 5ef896f..0000000 --- a/src/DrawingProgram/DrawingProgramSelection.hpp +++ /dev/null @@ -1,94 +0,0 @@ -#pragma once -#include "DrawingProgramCache.hpp" -#include "../CoordSpaceHelperTransform.hpp" - -class DrawingProgram; - -class DrawingProgramSelection { - public: - DrawingProgramSelection(DrawingProgram& initDrawP); - void add_from_cam_coord_collider_to_selection(const SCollision::ColliderCollection& cC, bool frontObjectOnly = false); - void remove_from_cam_coord_collider_to_selection(const SCollision::ColliderCollection& cC, bool frontObjectOnly = false); - - CanvasComponentContainer::ObjInfoSharedPtr get_front_object_colliding_with(const SCollision::ColliderCollection& cC); - - void deselect_all(); - void update(); - void draw_components(SkCanvas* canvas, const DrawData& drawData); - void draw_gui(SkCanvas* canvas, const DrawData& drawData); - bool is_something_selected(); - bool mouse_collided_with_selection(); - void erase_component(const CanvasComponentContainer::ObjInfoSharedPtr& objToCheck); - bool is_selected(const CanvasComponentContainer::ObjInfoSharedPtr& objToCheck); - const std::unordered_set& get_selected_set(); - - bool is_being_transformed(); - - void invalidate_cache_at_aabb_before_pos(const SCollision::AABB& aabb, uint64_t placementToInvalidateAt); - void clear_own_cached_surfaces(); - void preupdate_component(const CanvasComponentContainer::ObjInfoSharedPtr& objToCheck); - - void selection_to_clipboard(); - void paste_clipboard(Vector2f pasteScreenPos); - void delete_all(); - private: - std::function&, std::vector&)> erase_select_objects_in_bvh_func(std::unordered_set& selectedComponents, const SCollision::ColliderCollection& cC, const SCollision::ColliderCollection& cCWorld); - void fully_collided_erase_select_objects_func(std::unordered_set& selectedComponents, const std::shared_ptr& bvhNode); - - bool mouse_collided_with_selection_aabb(); - bool mouse_collided_with_scale_point(); - bool mouse_collided_with_rotate_center_handle_point(); - bool mouse_collided_with_rotate_handle_point(); - - void set_to_selection(const std::unordered_set& newSelection); - void add_to_selection(const std::unordered_set& newSelection); - void add_erased_objects_back_to_cache(const std::unordered_set& erasedObjects); - - void commit_transform_selection(); - - void calculate_aabb(); - void calculate_initial_rotate_center_location(); - void rebuild_cam_space(); - - Vector2f get_rotation_point_pos_from_angle(double angle); - - SCollision::AABB initialSelectionAABB; - SCollision::ColliderCollection camSpaceSelection; - - std::array selectionRectPoints; - - CoordSpaceHelperTransform selectionTransformCoords; - - std::unordered_set selectedSet; - DrawingProgramCache cache; - DrawingProgram& drawP; - - enum class TransformOperation { - NONE = 0, - TRANSLATE, - SCALE, - ROTATE_RELOCATE_CENTER, - ROTATE - } transformOpHappening = TransformOperation::NONE; - - struct TranslationData { - WorldVec startPos; - } translateData; - - struct ScaleData { - WorldVec startPos; - WorldVec centerPos; - WorldVec currentPos; - Vector2f handlePoint; - } scaleData; - - struct RotationData { - WorldVec centerPos; - Vector2f centerHandlePoint; - Vector2f handlePoint; - double rotationAngle = 0.0; - } rotateData; - - void reset_selection_data(); - void reset_transform_data(); -}; diff --git a/src/DrawingProgram/Layers/DrawingProgramLayer.cpp b/src/DrawingProgram/Layers/DrawingProgramLayer.cpp index 5e5c912..1ed6daa 100644 --- a/src/DrawingProgram/Layers/DrawingProgramLayer.cpp +++ b/src/DrawingProgram/Layers/DrawingProgramLayer.cpp @@ -8,10 +8,25 @@ void DrawingProgramLayer::draw(SkCanvas* canvas, const DrawData& drawData) const p->obj->draw(canvas, drawData); } -void DrawingProgramLayer::set_component_list_callbacks(DrawingProgramLayerManager& layerMan) const { +void DrawingProgramLayer::set_component_list_callbacks(DrawingProgramLayerListItem& layerListItem, DrawingProgramLayerManager& layerMan) const { components->set_insert_callback([&](const CanvasComponentContainer::ObjInfoSharedPtr& c) { c->obj->set_owner_obj_info(c); + c->obj->parentLayer = &layerListItem; c->obj->commit_update(layerMan.drawP); // Run commit update on insert so that world bounds are calculated + layerMan.drawP.drawCache.add_component(c); + if(c->obj->get_comp().get_type() == CanvasComponentType::IMAGE) + layerMan.drawP.updateableComponents.emplace(c); + }); + components->set_erase_callback([&](const CanvasComponentContainer::ObjInfoSharedPtr& c) { + layerMan.drawP.drawCache.erase_component(c); + layerMan.drawP.drawTool->erase_component(c); + std::erase_if(layerMan.drawP.droppedDownloadingFiles, [&c](auto& downloadingFile) { + return downloadingFile.comp == c; + }); + layerMan.drawP.updateableComponents.erase(c); + }); + components->set_move_callback([&](const CanvasComponentContainer::ObjInfoSharedPtr& c, uint32_t oldPos) { + layerMan.drawP.drawCache.invalidate_cache_at_aabb(c->obj->get_world_bounds()); }); } diff --git a/src/DrawingProgram/Layers/DrawingProgramLayer.hpp b/src/DrawingProgram/Layers/DrawingProgramLayer.hpp index 1886e3f..59f6f4e 100644 --- a/src/DrawingProgram/Layers/DrawingProgramLayer.hpp +++ b/src/DrawingProgram/Layers/DrawingProgramLayer.hpp @@ -8,7 +8,7 @@ class DrawingProgramLayerManager; class DrawingProgramLayer { public: void draw(SkCanvas* canvas, const DrawData& drawData) const; - void set_component_list_callbacks(DrawingProgramLayerManager& layerMan) const; + void set_component_list_callbacks(DrawingProgramLayerListItem& layerListItem, DrawingProgramLayerManager& layerMan) const; void commit_update_dont_invalidate_cache(DrawingProgramLayerManager& layerMan) const; void get_flattened_component_list(std::vector& objList) const; diff --git a/src/DrawingProgram/Layers/DrawingProgramLayerListItem.cpp b/src/DrawingProgram/Layers/DrawingProgramLayerListItem.cpp index 4403648..cc9012d 100644 --- a/src/DrawingProgram/Layers/DrawingProgramLayerListItem.cpp +++ b/src/DrawingProgram/Layers/DrawingProgramLayerListItem.cpp @@ -36,7 +36,7 @@ void DrawingProgramLayerListItem::set_component_list_callbacks(DrawingProgramLay if(folderData) folderData->set_component_list_callbacks(layerMan); else - layerData->set_component_list_callbacks(layerMan); + layerData->set_component_list_callbacks(*this, layerMan); } void DrawingProgramLayerListItem::commit_update_dont_invalidate_cache(DrawingProgramLayerManager& layerMan) { @@ -90,10 +90,11 @@ const std::string& DrawingProgramLayerListItem::get_name() const { return nameData->name; } -void DrawingProgramLayerListItem::set_alpha(NetworkingObjects::DelayUpdateSerializedClassManager& delayedNetObjMan, float newAlpha) const { +void DrawingProgramLayerListItem::set_alpha(DrawingProgramLayerManager& layerMan, float newAlpha) const { if(displayData && displayData->alpha != newAlpha) { displayData->alpha = newAlpha; - delayedNetObjMan.send_update_to_all(displayData, false); + // MUST CLEAR CACHE + layerMan.drawP.world.delayedUpdateObjectManager.send_update_to_all(displayData, false); } } @@ -101,10 +102,11 @@ float DrawingProgramLayerListItem::get_alpha() const { return displayData->alpha; } -void DrawingProgramLayerListItem::set_visible(NetworkingObjects::DelayUpdateSerializedClassManager& delayedNetObjMan, bool newVisible) const { +void DrawingProgramLayerListItem::set_visible(DrawingProgramLayerManager& layerMan, bool newVisible) const { if(displayData && displayData->visible != newVisible) { displayData->visible = newVisible; - delayedNetObjMan.send_update_to_all(displayData, false); + // MUST CLEAR CACHE + layerMan.drawP.world.delayedUpdateObjectManager.send_update_to_all(displayData, false); } } @@ -112,10 +114,11 @@ bool DrawingProgramLayerListItem::get_visible() const { return displayData->visible; } -void DrawingProgramLayerListItem::set_blend_mode(NetworkingObjects::DelayUpdateSerializedClassManager& delayedNetObjMan, SerializedBlendMode newBlendMode) const { +void DrawingProgramLayerListItem::set_blend_mode(DrawingProgramLayerManager& layerMan, SerializedBlendMode newBlendMode) const { if(displayData && displayData->blendMode != newBlendMode) { displayData->blendMode = newBlendMode; - delayedNetObjMan.send_update_to_all(displayData, false); + // MUST CLEAR CACHE + layerMan.drawP.world.delayedUpdateObjectManager.send_update_to_all(displayData, false); } } @@ -133,7 +136,11 @@ void DrawingProgramLayerListItem::register_class(World& w) { .readUpdateFuncServer = nullptr, }); w.delayedUpdateObjectManager.register_class(w.netObjMan); - w.delayedUpdateObjectManager.register_class(w.netObjMan); + w.delayedUpdateObjectManager.register_class(w.netObjMan, NetworkingObjects::DelayUpdateSerializedClassManager::CustomConstructors{ + .postUpdateFunc = [&](DisplayData& o) { + // MUST CLEAR CACHE + } + }); } void DrawingProgramLayerListItem::write_constructor_func(const NetworkingObjects::NetObjTemporaryPtr& o, cereal::PortableBinaryOutputArchive& a) { diff --git a/src/DrawingProgram/Layers/DrawingProgramLayerListItem.hpp b/src/DrawingProgram/Layers/DrawingProgramLayerListItem.hpp index eadd987..01881ad 100644 --- a/src/DrawingProgram/Layers/DrawingProgramLayerListItem.hpp +++ b/src/DrawingProgram/Layers/DrawingProgramLayerListItem.hpp @@ -28,13 +28,13 @@ class DrawingProgramLayerListItem { const std::string& get_name() const; void get_flattened_component_list(std::vector& objList) const; - void set_alpha(NetworkingObjects::DelayUpdateSerializedClassManager& delayedNetObjMan, float newAlpha) const; + void set_alpha(DrawingProgramLayerManager& layerMan, float newAlpha) const; float get_alpha() const; - void set_visible(NetworkingObjects::DelayUpdateSerializedClassManager& delayedNetObjMan, bool newVisible) const; + void set_visible(DrawingProgramLayerManager& layerMan, bool newVisible) const; bool get_visible() const; - void set_blend_mode(NetworkingObjects::DelayUpdateSerializedClassManager& delayedNetObjMan, SerializedBlendMode newBlendMode) const; + void set_blend_mode(DrawingProgramLayerManager& layerMan, SerializedBlendMode newBlendMode) const; SerializedBlendMode get_blend_mode() const; private: static void write_constructor_func(const NetworkingObjects::NetObjTemporaryPtr& o, cereal::PortableBinaryOutputArchive& a); diff --git a/src/DrawingProgram/Layers/DrawingProgramLayerManager.cpp b/src/DrawingProgram/Layers/DrawingProgramLayerManager.cpp index 92e3993..0f14f0b 100644 --- a/src/DrawingProgram/Layers/DrawingProgramLayerManager.cpp +++ b/src/DrawingProgram/Layers/DrawingProgramLayerManager.cpp @@ -38,3 +38,31 @@ std::vector DrawingProgramLayerManag layerTreeRoot->get_flattened_component_list(toRet); return toRet; } + +bool DrawingProgramLayerManager::layer_tree_root_exists() { + return layerTreeRoot; +} + +const DrawingProgramLayerListItem& DrawingProgramLayerManager::get_layer_root() { + return *layerTreeRoot; +} + +void DrawingProgramLayerManager::erase_component_set(const std::unordered_set& compsToErase) { + std::unordered_map> idsToEraseInSpecificLayers; + for(auto& c : compsToErase) + idsToEraseInSpecificLayers[c->obj->parentLayer].emplace(c->obj.get_net_id()); + for(auto& [layerListItem, netObjSetToErase] : idsToEraseInSpecificLayers) { + auto& layerComponentList = layerListItem->get_layer().components; + layerComponentList->erase_unordered_set(layerComponentList, netObjSetToErase); + } +} + +bool DrawingProgramLayerManager::component_passes_layer_selector(const CanvasComponentContainer::ObjInfoSharedPtr& c, LayerSelector layerSelector) { + switch(layerSelector) { + case LayerSelector::ALL_VISIBLE_LAYERS: + return c->obj->parentLayer->get_visible(); + case LayerSelector::LAYER_BEING_EDITED: + return is_a_layer_being_edited() && c->obj->parentLayer == editingLayer.lock().get(); + } + return false; +} diff --git a/src/DrawingProgram/Layers/DrawingProgramLayerManager.hpp b/src/DrawingProgram/Layers/DrawingProgramLayerManager.hpp index a01e16e..e7462bc 100644 --- a/src/DrawingProgram/Layers/DrawingProgramLayerManager.hpp +++ b/src/DrawingProgram/Layers/DrawingProgramLayerManager.hpp @@ -12,6 +12,10 @@ class DrawingProgramLayerManager { NetworkingObjects::NetObjOwnerPtr layerTreeRoot; NetworkingObjects::NetObjWeakPtr editingLayer; public: + enum class LayerSelector { + ALL_VISIBLE_LAYERS, + LAYER_BEING_EDITED + }; DrawingProgramLayerManager(DrawingProgram& drawProg); void init(); @@ -19,6 +23,12 @@ class DrawingProgramLayerManager { void write_components_server(cereal::PortableBinaryOutputArchive& a); void read_components_client(cereal::PortableBinaryInputArchive& a); bool is_a_layer_being_edited(); + void erase_component_set(const std::unordered_set& compsToErase); + bool component_passes_layer_selector(const CanvasComponentContainer::ObjInfoSharedPtr& c, LayerSelector layerSelector); + + bool layer_tree_root_exists(); + const DrawingProgramLayerListItem& get_layer_root(); + template CanvasComponentContainer::ObjInfoSharedPtr add_component_to_layer_being_edited(T* newObj) { auto editLayerPtr = editingLayer.lock(); if(!editLayerPtr) diff --git a/src/DrawingProgram/Layers/DrawingProgramLayerManagerGUI.cpp b/src/DrawingProgram/Layers/DrawingProgramLayerManagerGUI.cpp index d816ae2..473445f 100644 --- a/src/DrawingProgram/Layers/DrawingProgramLayerManagerGUI.cpp +++ b/src/DrawingProgram/Layers/DrawingProgramLayerManagerGUI.cpp @@ -85,7 +85,7 @@ void DrawingProgramLayerManagerGUI::setup_list_gui(const std::string& id, bool& gui.text_label(tempPtr->get_name()); } if(gui.svg_icon_button_transparent("visible button", tempPtr->get_visible() ? "data/icons/eyeopen.svg" : "data/icons/eyeclose.svg", false, GUIStuff::TreeListing::ENTRY_HEIGHT)) { - tempPtr->set_visible(world.delayedUpdateObjectManager, !tempPtr->get_visible()); + tempPtr->set_visible(layerMan, !tempPtr->get_visible()); isButtonClicked = true; } if(gui.svg_icon_button_transparent("delete button", "data/icons/trash.svg", false, GUIStuff::TreeListing::ENTRY_HEIGHT)) { @@ -178,7 +178,7 @@ void DrawingProgramLayerManagerGUI::setup_list_gui(const std::string& id, bool& gui.input_text_field("input edit name", "Name", &nameToEdit); tempPtr->set_name(world.delayedUpdateObjectManager, nameToEdit); gui.slider_scalar_field("input alpha slider", "Alpha", &alphaValToEdit, 0.0f, 1.0f, 2); - tempPtr->set_alpha(world.delayedUpdateObjectManager, alphaValToEdit); + tempPtr->set_alpha(layerMan, alphaValToEdit); gui.left_to_right_line_layout([&]() { gui.text_label("Blend Mode"); gui.dropdown_select("input blend mode", &blendModeValToEdit, get_blend_mode_name_list(), 200.0f, [&hoveringOverDropdown]() { @@ -186,7 +186,7 @@ void DrawingProgramLayerManagerGUI::setup_list_gui(const std::string& id, bool& hoveringOverDropdown = true; }); }); - tempPtr->set_blend_mode(world.delayedUpdateObjectManager, static_cast(blendModeValToEdit)); + tempPtr->set_blend_mode(layerMan, static_cast(blendModeValToEdit)); } } diff --git a/src/DrawingProgram/Tools/EditTool.cpp b/src/DrawingProgram/Tools/EditTool.cpp index d19426d..b148b5f 100644 --- a/src/DrawingProgram/Tools/EditTool.cpp +++ b/src/DrawingProgram/Tools/EditTool.cpp @@ -63,8 +63,8 @@ void EditTool::switch_tool(DrawingProgramToolType newTool) { pointDragging = nullptr; isEditing = false; - if(!drawP.is_selection_allowing_tool(newTool)) - drawP.selection.deselect_all(); + //if(!drawP.is_selection_allowing_tool(newTool)) + // drawP.selection.deselect_all(); } void EditTool::edit_start(const CanvasComponentContainer::ObjInfoSharedPtr& comp) { @@ -114,26 +114,26 @@ void EditTool::tool_update() { camCMouseAABB.recalculate_bounds(); if(drawP.controls.leftClick) { - bool modifySelection = !drawP.selection.is_being_transformed(); - if(drawP.world.main.input.mouse.leftClicks >= 2 && !drawP.world.main.input.key(InputManager::KEY_GENERIC_LSHIFT).held && !drawP.world.main.input.key(InputManager::KEY_GENERIC_LALT).held) { - CanvasComponentContainer::ObjInfoSharedPtr selectedObjectToEdit = drawP.selection.get_front_object_colliding_with(camCMouseAABB); + //bool modifySelection = !drawP.selection.is_being_transformed(); + //if(drawP.world.main.input.mouse.leftClicks >= 2 && !drawP.world.main.input.key(InputManager::KEY_GENERIC_LSHIFT).held && !drawP.world.main.input.key(InputManager::KEY_GENERIC_LALT).held) { + // CanvasComponentContainer::ObjInfoSharedPtr selectedObjectToEdit = drawP.selection.get_front_object_colliding_with(camCMouseAABB); - if(selectedObjectToEdit && is_editable(selectedObjectToEdit)) { - drawP.selection.deselect_all(); - edit_start(selectedObjectToEdit); - modifySelection = false; - } - } - if(modifySelection) { - if(drawP.world.main.input.key(InputManager::KEY_GENERIC_LSHIFT).held) - drawP.selection.add_from_cam_coord_collider_to_selection(camCMouseAABB, true); - else if(drawP.world.main.input.key(InputManager::KEY_GENERIC_LALT).held) - drawP.selection.remove_from_cam_coord_collider_to_selection(camCMouseAABB, true); - else { - drawP.selection.deselect_all(); - drawP.selection.add_from_cam_coord_collider_to_selection(camCMouseAABB, true); - } - } + // if(selectedObjectToEdit && is_editable(selectedObjectToEdit)) { + // drawP.selection.deselect_all(); + // edit_start(selectedObjectToEdit); + // modifySelection = false; + // } + //} + //if(modifySelection) { + // if(drawP.world.main.input.key(InputManager::KEY_GENERIC_LSHIFT).held) + // drawP.selection.add_from_cam_coord_collider_to_selection(camCMouseAABB, true); + // else if(drawP.world.main.input.key(InputManager::KEY_GENERIC_LALT).held) + // drawP.selection.remove_from_cam_coord_collider_to_selection(camCMouseAABB, true); + // else { + // drawP.selection.deselect_all(); + // drawP.selection.add_from_cam_coord_collider_to_selection(camCMouseAABB, true); + // } + //} } } else { diff --git a/src/DrawingProgram/Tools/EraserTool.cpp b/src/DrawingProgram/Tools/EraserTool.cpp index 992bf13..42fc240 100644 --- a/src/DrawingProgram/Tools/EraserTool.cpp +++ b/src/DrawingProgram/Tools/EraserTool.cpp @@ -17,6 +17,11 @@ void EraserTool::gui_toolbox() { t.gui.push_id("eraser tool"); t.gui.text_label_centered("Eraser"); t.gui.slider_scalar_field("relwidth", "Size", &drawP.controls.relativeWidth, 3.0f, 40.0f); + t.gui.text_label("Erase from:"); + if(t.gui.radio_button_field("layer edited", "Layer being edited", drawP.controls.layerSelector == DrawingProgramLayerManager::LayerSelector::LAYER_BEING_EDITED)) + drawP.controls.layerSelector = DrawingProgramLayerManager::LayerSelector::LAYER_BEING_EDITED; + if(t.gui.radio_button_field("all visible", "All visible layers", drawP.controls.layerSelector == DrawingProgramLayerManager::LayerSelector::ALL_VISIBLE_LAYERS)) + drawP.controls.layerSelector = DrawingProgramLayerManager::LayerSelector::ALL_VISIBLE_LAYERS; t.gui.pop_id(); } @@ -31,16 +36,7 @@ void EraserTool::erase_component(const CanvasComponentContainer::ObjInfoSharedPt } void EraserTool::switch_tool(DrawingProgramToolType newTool) { - DrawingProgramCache::move_components_from_bvh_nodes_to_set(erasedComponents, erasedBVHNodes); - if(!erasedComponents.empty()) { - drawP.erase_component_set(erasedComponents); - // NOTE: Ideally, you would just recalculate the lastDrawnPos of every cache instead of invalidating and redrawing the caches - // However, the eraser might have other visual glitches during drawing that i am unaware of, so for now, just refresh the - // cache after a draw - drawP.compCache.clear_own_cached_surfaces(); - } - erasedComponents.clear(); - erasedBVHNodes.clear(); + drawP.layerMan.erase_component_set(erasedComponents); } void EraserTool::tool_update() { @@ -53,20 +49,20 @@ void EraserTool::tool_update() { SCollision::generate_wide_line(cC, prevMousePos, drawP.world.main.input.mouse.pos, drawP.controls.relativeWidth * 2.0f, true); auto cCWorld = drawP.world.drawData.cam.c.collider_to_world, SCollision::ColliderCollection>(cC); - drawP.compCache.traverse_bvh_erase_function(cCWorld.bounds, [&](const auto& bvhNode, auto& comps) { + drawP.drawCache.traverse_bvh_erase_function(cCWorld.bounds, [&](const auto& bvhNode, auto& comps) { if(bvhNode && SCollision::collide(cC, drawP.world.drawData.cam.c.to_space(bvhNode->bounds.min)) && SCollision::collide(cC, drawP.world.drawData.cam.c.to_space(bvhNode->bounds.max)) && SCollision::collide(cC, drawP.world.drawData.cam.c.to_space(bvhNode->bounds.top_right())) && SCollision::collide(cC, drawP.world.drawData.cam.c.to_space(bvhNode->bounds.bottom_left()))) { - erasedBVHNodes.emplace(bvhNode); - drawP.compCache.invalidate_cache_at_aabb_before_pos(bvhNode->bounds, 0); + drawP.drawCache.invalidate_cache_at_aabb(bvhNode->bounds); + drawP.drawCache.move_components_from_bvh_node_to_set(erasedComponents, bvhNode); return true; } std::erase_if(comps, [&](auto& c) { - if(c->obj->collides_with(drawP.world.drawData.cam.c, cCWorld, cC)) { + 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.compCache.invalidate_cache_at_aabb_before_pos(c->obj->get_world_bounds(), c->pos); + drawP.drawCache.invalidate_cache_at_aabb(c->obj->get_world_bounds()); return true; } return false; diff --git a/src/DrawingProgram/Tools/EraserTool.hpp b/src/DrawingProgram/Tools/EraserTool.hpp index ce13d5d..a81edf8 100644 --- a/src/DrawingProgram/Tools/EraserTool.hpp +++ b/src/DrawingProgram/Tools/EraserTool.hpp @@ -19,5 +19,4 @@ class EraserTool : public DrawingProgramToolBase { virtual bool prevent_undo_or_redo() override; std::unordered_set erasedComponents; // Pointers will be erased from this set if theyre erased in the main list (done by callback) - std::unordered_set> erasedBVHNodes; }; diff --git a/src/DrawingProgram/Tools/LassoSelectTool.cpp b/src/DrawingProgram/Tools/LassoSelectTool.cpp index 81a96ff..f537809 100644 --- a/src/DrawingProgram/Tools/LassoSelectTool.cpp +++ b/src/DrawingProgram/Tools/LassoSelectTool.cpp @@ -50,19 +50,19 @@ void LassoSelectTool::erase_component(const CanvasComponentContainer::ObjInfoSha } void LassoSelectTool::switch_tool(DrawingProgramToolType newTool) { - if(!drawP.is_selection_allowing_tool(newTool)) - drawP.selection.deselect_all(); + //if(!drawP.is_selection_allowing_tool(newTool)) + // drawP.selection.deselect_all(); } void LassoSelectTool::tool_update() { switch(controls.selectionMode) { case 0: { - if(drawP.controls.leftClick && !drawP.selection.is_being_transformed()) { - controls = LassoSelectControls(); - controls.coords = drawP.world.drawData.cam.c; - controls.lassoPoints.emplace_back(controls.coords.get_mouse_pos(drawP.world)); - controls.selectionMode = 1; - } + //if(drawP.controls.leftClick && !drawP.selection.is_being_transformed()) { + // controls = LassoSelectControls(); + // controls.coords = drawP.world.drawData.cam.c; + // controls.lassoPoints.emplace_back(controls.coords.get_mouse_pos(drawP.world)); + // controls.selectionMode = 1; + //} break; } case 1: { @@ -92,17 +92,18 @@ void LassoSelectTool::tool_update() { cC.recalculate_bounds(); - if(drawP.world.main.input.key(InputManager::KEY_GENERIC_LSHIFT).held) - drawP.selection.add_from_cam_coord_collider_to_selection(cC); - else if(drawP.world.main.input.key(InputManager::KEY_GENERIC_LALT).held) - drawP.selection.remove_from_cam_coord_collider_to_selection(cC); - else { - drawP.selection.deselect_all(); - drawP.selection.add_from_cam_coord_collider_to_selection(cC); - } + //if(drawP.world.main.input.key(InputManager::KEY_GENERIC_LSHIFT).held) + // drawP.selection.add_from_cam_coord_collider_to_selection(cC); + //else if(drawP.world.main.input.key(InputManager::KEY_GENERIC_LALT).held) + // drawP.selection.remove_from_cam_coord_collider_to_selection(cC); + //else { + // drawP.selection.deselect_all(); + // drawP.selection.add_from_cam_coord_collider_to_selection(cC); + //} + } + else if(!drawP.world.main.input.key(InputManager::KEY_GENERIC_LSHIFT).held && !drawP.world.main.input.key(InputManager::KEY_GENERIC_LALT).held) { + //drawP.selection.deselect_all(); } - else if(!drawP.world.main.input.key(InputManager::KEY_GENERIC_LSHIFT).held && !drawP.world.main.input.key(InputManager::KEY_GENERIC_LALT).held) - drawP.selection.deselect_all(); controls.selectionMode = 0; } break; @@ -111,7 +112,7 @@ void LassoSelectTool::tool_update() { } bool LassoSelectTool::prevent_undo_or_redo() { - return drawP.selection.is_something_selected() || controls.selectionMode == 1; + return true;//drawP.selection.is_something_selected() || controls.selectionMode == 1; } void LassoSelectTool::draw(SkCanvas* canvas, const DrawData& drawData) { diff --git a/src/DrawingProgram/Tools/PanCanvasTool.cpp b/src/DrawingProgram/Tools/PanCanvasTool.cpp index b8d60b1..a795a26 100644 --- a/src/DrawingProgram/Tools/PanCanvasTool.cpp +++ b/src/DrawingProgram/Tools/PanCanvasTool.cpp @@ -39,6 +39,6 @@ void PanCanvasTool::draw(SkCanvas* canvas, const DrawData& drawData) { } void PanCanvasTool::switch_tool(DrawingProgramToolType newTool) { - if(!drawP.is_selection_allowing_tool(newTool)) - drawP.selection.deselect_all(); + //if(!drawP.is_selection_allowing_tool(newTool)) + // drawP.selection.deselect_all(); } diff --git a/src/DrawingProgram/Tools/RectSelectTool.cpp b/src/DrawingProgram/Tools/RectSelectTool.cpp index 980b221..e596b7b 100644 --- a/src/DrawingProgram/Tools/RectSelectTool.cpp +++ b/src/DrawingProgram/Tools/RectSelectTool.cpp @@ -28,19 +28,19 @@ bool RectSelectTool::right_click_popup_gui(Vector2f popupPos) { } void RectSelectTool::switch_tool(DrawingProgramToolType newTool) { - if(!drawP.is_selection_allowing_tool(newTool)) - drawP.selection.deselect_all(); + //if(!drawP.is_selection_allowing_tool(newTool)) + // drawP.selection.deselect_all(); } void RectSelectTool::tool_update() { switch(controls.selectionMode) { case 0: { - if(drawP.controls.leftClick && !drawP.selection.is_being_transformed()) { - controls = RectSelectControls(); - controls.coords = drawP.world.drawData.cam.c; - controls.selectStartAt = controls.coords.get_mouse_pos(drawP.world); - controls.selectionMode = 1; - } + //if(drawP.controls.leftClick && !drawP.selection.is_being_transformed()) { + // controls = RectSelectControls(); + // controls.coords = drawP.world.drawData.cam.c; + // controls.selectStartAt = controls.coords.get_mouse_pos(drawP.world); + // controls.selectionMode = 1; + //} break; } case 1: { @@ -55,14 +55,14 @@ void RectSelectTool::tool_update() { cC.triangle.emplace_back(controls.newT[2], controls.newT[3], controls.newT[0]); cC.recalculate_bounds(); - if(drawP.world.main.input.key(InputManager::KEY_GENERIC_LSHIFT).held) - drawP.selection.add_from_cam_coord_collider_to_selection(cC); - else if(drawP.world.main.input.key(InputManager::KEY_GENERIC_LALT).held) - drawP.selection.remove_from_cam_coord_collider_to_selection(cC); - else { - drawP.selection.deselect_all(); - drawP.selection.add_from_cam_coord_collider_to_selection(cC); - } + //if(drawP.world.main.input.key(InputManager::KEY_GENERIC_LSHIFT).held) + // drawP.selection.add_from_cam_coord_collider_to_selection(cC); + //else if(drawP.world.main.input.key(InputManager::KEY_GENERIC_LALT).held) + // drawP.selection.remove_from_cam_coord_collider_to_selection(cC); + //else { + // drawP.selection.deselect_all(); + // drawP.selection.add_from_cam_coord_collider_to_selection(cC); + //} controls.selectionMode = 0; } @@ -72,7 +72,8 @@ void RectSelectTool::tool_update() { } bool RectSelectTool::prevent_undo_or_redo() { - return drawP.selection.is_something_selected() || controls.selectionMode == 1; + //return drawP.selection.is_something_selected() || controls.selectionMode == 1; + return true; } void RectSelectTool::draw(SkCanvas* canvas, const DrawData& drawData) { diff --git a/src/DrawingProgram/Tools/ZoomCanvasTool.cpp b/src/DrawingProgram/Tools/ZoomCanvasTool.cpp index c896d30..bc073f9 100644 --- a/src/DrawingProgram/Tools/ZoomCanvasTool.cpp +++ b/src/DrawingProgram/Tools/ZoomCanvasTool.cpp @@ -39,6 +39,6 @@ void ZoomCanvasTool::draw(SkCanvas* canvas, const DrawData& drawData) { } void ZoomCanvasTool::switch_tool(DrawingProgramToolType newTool) { - if(!drawP.is_selection_allowing_tool(newTool)) - drawP.selection.deselect_all(); + //if(!drawP.is_selection_allowing_tool(newTool)) + // drawP.selection.deselect_all(); } diff --git a/src/Toolbar.cpp b/src/Toolbar.cpp index a548f92..aa4ae96 100644 --- a/src/Toolbar.cpp +++ b/src/Toolbar.cpp @@ -1228,8 +1228,6 @@ void Toolbar::performance_metrics() { std::stringstream a; a << "FPS: " << std::fixed << std::setprecision(0) << (1.0 / main.deltaTime); gui.text_label(a.str()); - if(main.world->drawProg.components) - gui.text_label("Item Count: " + std::to_string(main.world->drawProg.components->size())); std::stringstream b; b << "Coord: " << main.world->drawData.cam.c.pos.x().display_int_str(5) << ", " << main.world->drawData.cam.c.pos.y().display_int_str(5); gui.text_label(b.str());