diff --git a/CMakeLists.txt b/CMakeLists.txt index 3b915ea..4acd46f 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -44,6 +44,7 @@ set(sources "src/main.cpp" "src/Server/ClientData.cpp" "src/CollabTextBox/CollabTextBox.cpp" "src/CollabTextBox/CollabTextBoxShaper.cpp" + "src/DrawingProgram/DrawingProgramCache.cpp" "src/DrawingProgram/DrawingProgram.cpp" "src/DrawingProgram/BrushTool.cpp" "src/DrawingProgram/TextBoxTool.cpp" diff --git a/include/Helpers/SCollision.hpp b/include/Helpers/SCollision.hpp index d4cc7c7..1b5db69 100644 --- a/include/Helpers/SCollision.hpp +++ b/include/Helpers/SCollision.hpp @@ -38,6 +38,9 @@ namespace SCollision { bool operator==(const AABB& other) const { return min == other.min && max == other.max; } + bool fully_contains_aabb(const AABB& other) const { + return other.min.x() >= min.x() && other.min.y() >= min.y() && other.max.x() <= max.x() && other.max.y() <= max.y(); + } template AABB transform(const std::function(const Vector&)>& transformFunc, const std::function& transformLinearFunc) const { Vector aabb1 = transformFunc(min); Vector aabb2 = transformFunc(max); diff --git a/src/CollabList.hpp b/src/CollabList.hpp index 3a332a2..c4dc50d 100644 --- a/src/CollabList.hpp +++ b/src/CollabList.hpp @@ -13,11 +13,15 @@ template class CollabList { T obj; }; + typedef std::shared_ptr ObjectInfoPtr; + const std::vector>& client_list() const { return clientSideList; } std::vector>& client_list() { return clientSideList; } const std::vector>& server_list() const { return serverSideList; } std::function updateCallback; + std::function clientInsertCallback; + std::function clientEraseCallback; void set_server_from_client_list() { serverSideList = clientSideList; @@ -51,6 +55,8 @@ template class CollabList { void client_erase_if(const std::function&)>& func) { for(int64_t i = 0; i < (int64_t)clientSideList.size(); i++) { if(func((uint64_t)i, clientSideList[i])) { + if(clientEraseCallback) + clientEraseCallback(clientSideList[i]); clientSideList.erase(clientSideList.begin() + i); i--; if(updateCallback) @@ -66,6 +72,8 @@ template class CollabList { newObj->obj = item; uint64_t minPos = std::min(static_cast(clientSideList.size()), pos); clientSideList.insert(clientSideList.begin() + minPos, newObj); + if(clientInsertCallback) + clientInsertCallback(newObj); if(updateCallback) updateCallback(); return newObj->id; @@ -73,6 +81,8 @@ template class CollabList { void client_erase(const T& item, IDType& erasedID) { std::erase_if(clientSideList, [&](const auto& obj) { if(obj->obj == item) { + if(clientEraseCallback) + clientEraseCallback(obj); erasedID = obj->id; obj->syncIgnore = true; if(updateCallback) @@ -88,7 +98,7 @@ template class CollabList { return clientObj->id == id; }); if(foundInClient != clientSideList.end()) { - std::shared_ptr& o = *foundInClient; + ObjectInfoPtr& o = *foundInClient; serverSideList.insert(serverSideList.begin() + pos, o); o->syncIgnore = false; sync(); @@ -101,6 +111,8 @@ template class CollabList { serverSideList.insert(serverSideList.begin() + pos, newObj); uint64_t minPos = std::min(pos, clientSideList.size()); clientSideList.insert(clientSideList.begin() + minPos, newObj); + if(clientInsertCallback) + clientInsertCallback(newObj); sync(); return true; } @@ -115,6 +127,8 @@ template class CollabList { std::erase_if(clientSideList, [&](const auto& obj) { if(obj->id == id) { obj->syncIgnore = false; + if(clientEraseCallback) + clientEraseCallback(obj); return true; } return false; @@ -128,12 +142,14 @@ template class CollabList { newObj->obj = item; serverSideList.emplace_back(newObj); clientSideList.emplace_back(newObj); + if(clientInsertCallback) + clientInsertCallback(newObj); if(updateCallback) updateCallback(); } private: void sync() { - std::vector>> ignoredToReinsert; + std::vector> ignoredToReinsert; for(uint64_t i = 0; i < clientSideList.size(); i++) if(clientSideList[i]->syncIgnore) ignoredToReinsert.emplace_back(std::pair>{i, clientSideList[i]}); @@ -151,6 +167,6 @@ template class CollabList { updateCallback(); } std::function getNewIDFunc; - std::vector> clientSideList; - std::vector> serverSideList; + std::vector clientSideList; + std::vector serverSideList; }; diff --git a/src/DrawComponents/DrawComponent.cpp b/src/DrawComponents/DrawComponent.cpp index a358bc2..b935b18 100644 --- a/src/DrawComponents/DrawComponent.cpp +++ b/src/DrawComponents/DrawComponent.cpp @@ -95,7 +95,7 @@ void DrawComponent::check_timers(DrawingProgram& drawP) { if(transformDur > CLIENT_DRAWCOMP_DELAY_TIMER_DURATION) { coords = *delayedCoordinateSpace; delayedCoordinateSpace = nullptr; - finalize_update(drawP.colliderAllocated); + finalize_update(drawP); } } if(delayedUpdatePtr) { @@ -109,13 +109,21 @@ void DrawComponent::check_timers(DrawingProgram& drawP) { } void DrawComponent::temp_update(DrawingProgram& drawP) { + drawP.compCache.preupdate_component(this); + worldAABB = std::nullopt; initialize_draw_data(drawP); updateDraw = true; } +void DrawComponent::transform_temp_update(DrawingProgram& drawP) { + drawP.compCache.preupdate_component(this); + worldAABB = std::nullopt; + updateDraw = true; +} + void DrawComponent::final_update(DrawingProgram& drawP) { initialize_draw_data(drawP); - finalize_update(drawP.colliderAllocated); + finalize_update(drawP); updateDraw = true; } @@ -143,8 +151,9 @@ void DrawComponent::client_send_transform_final(DrawingProgram& drawP, ServerCli drawP.world.con.client_send_items_to_server(RELIABLE_COMMAND_CHANNEL, SERVER_TRANSFORM_COMPONENT, false, id, this->coords); } -void DrawComponent::finalize_update(bool colliderAllocated) { - create_collider(colliderAllocated); +void DrawComponent::finalize_update(DrawingProgram& drawP) { + drawP.compCache.preupdate_component(this); + create_collider(drawP.colliderAllocated); updateDraw = true; } diff --git a/src/DrawComponents/DrawComponent.hpp b/src/DrawComponents/DrawComponent.hpp index 668ee55..4bc6529 100644 --- a/src/DrawComponents/DrawComponent.hpp +++ b/src/DrawComponents/DrawComponent.hpp @@ -68,6 +68,7 @@ class DrawComponent { #ifndef IS_SERVER bool selected = false; + bool updateDraw = true; bool globalCollisionCheck = false; @@ -99,8 +100,9 @@ class DrawComponent { virtual void draw(SkCanvas* canvas, const DrawData& drawData) = 0; void temp_update(DrawingProgram& drawP); void final_update(DrawingProgram& drawP); + void transform_temp_update(DrawingProgram& drawP); virtual void initialize_draw_data(DrawingProgram& drawP) = 0; - virtual void finalize_update(bool colliderAllocated); + virtual void finalize_update(DrawingProgram& drawP); virtual void update(DrawingProgram& drawP) = 0; virtual bool collides_within_coords(const SCollision::ColliderCollection& checkAgainst, bool colliderAllocated) = 0; bool collides_with_world_coords(const CoordSpaceHelper& camCoords, const SCollision::ColliderCollection& checkAgainstWorld, bool colliderAllocated); diff --git a/src/DrawComponents/DrawImage.cpp b/src/DrawComponents/DrawImage.cpp index f6f596a..b8e3b28 100644 --- a/src/DrawComponents/DrawImage.cpp +++ b/src/DrawComponents/DrawImage.cpp @@ -62,7 +62,7 @@ void DrawImage::update(DrawingProgram& drawP) { std::shared_ptr display = drawP.world.drawData.rMan->get_display_data(d.imageID); if(display) { if(display->update_draw())// && bounds_draw_check(drawP.world.drawData, collisionTree)) - updateDraw = true; + temp_update(drawP); } } diff --git a/src/DrawComponents/DrawTextBox.cpp b/src/DrawComponents/DrawTextBox.cpp index 2c5e46d..83cd927 100644 --- a/src/DrawComponents/DrawTextBox.cpp +++ b/src/DrawComponents/DrawTextBox.cpp @@ -93,9 +93,9 @@ void DrawTextBox::set_textbox_string(const std::string& str) { textboxUpdate = false; } -void DrawTextBox::update_contained_string() { +void DrawTextBox::update_contained_string(DrawingProgram& drawP) { d.currentText = textBox.get_string(); - updateDraw = true; + temp_update(drawP); } Vector2f DrawTextBox::get_mouse_pos(DrawingProgram& drawP) { diff --git a/src/DrawComponents/DrawTextBox.hpp b/src/DrawComponents/DrawTextBox.hpp index 931c4fa..af49911 100644 --- a/src/DrawComponents/DrawTextBox.hpp +++ b/src/DrawComponents/DrawTextBox.hpp @@ -36,7 +36,7 @@ class DrawTextBox : public DrawComponent { virtual void create_collider(bool colliderAllocated) override; virtual void update_from_delayed_ptr() override; void init_text_box(DrawingProgram& drawP); - void update_contained_string(); + void update_contained_string(DrawingProgram& drawP); void set_textbox_string(const std::string& str); Vector2f get_mouse_pos(DrawingProgram& drawP); diff --git a/src/DrawingProgram/DrawingProgram.cpp b/src/DrawingProgram/DrawingProgram.cpp index 8cc6842..da532ca 100644 --- a/src/DrawingProgram/DrawingProgram.cpp +++ b/src/DrawingProgram/DrawingProgram.cpp @@ -46,6 +46,12 @@ DrawingProgram::DrawingProgram(World& initWorld): if(&world == world.main.world.get()) world.main.drawProgCache.refresh = true; }; + components.clientInsertCallback = [&](const CollabListType::ObjectInfoPtr& c) { + compCache.add_component(c); + }; + components.clientEraseCallback = [&](const CollabListType::ObjectInfoPtr& c) { + compCache.erase_component(c); + }; } void DrawingProgram::init_client_callbacks() { @@ -82,10 +88,9 @@ void DrawingProgram::init_client_callbacks() { float dur = std::chrono::duration_cast>(std::chrono::steady_clock::now() - comp->lastTransformTime).count(); if(dur > CLIENT_DRAWCOMP_DELAY_TIMER_DURATION){ comp->delayedCoordinateSpace = nullptr; - comp->updateDraw = true; message(comp->coords); if(!isTemp) - comp->finalize_update(colliderAllocated); // No need to update draw data during transformation + comp->finalize_update(*this); // No need to update draw data during transformation } else { comp->delayedCoordinateSpace = std::make_shared(); @@ -122,18 +127,25 @@ void DrawingProgram::allocate_collider_memory() { colliderAllocated = true; } -void DrawingProgram::check_all_collisions_base(const SCollision::ColliderCollection& checkAgainstWorld, const SCollision::ColliderCollection& checkAgainstCam) { +void DrawingProgram::parallel_loop_all_components(std::function, ServerClientID>::ObjectInfo>&)> func) { #ifdef __EMSCRIPTEN__ - std::for_each(components.client_list().begin(), components.client_list().end(), [&](auto& c) { - c->obj->globalCollisionCheck = c->obj->collides_with(world.drawData.cam.c, checkAgainstWorld, checkAgainstCam, colliderAllocated); - }); + std::for_each(components.client_list().begin(), components.client_list().end(), func); #else - std::for_each(std::execution::par_unseq, components.client_list().begin(), components.client_list().end(), [&](auto& c) { - c->obj->globalCollisionCheck = c->obj->collides_with(world.drawData.cam.c, checkAgainstWorld, checkAgainstCam, colliderAllocated); - }); + std::for_each(std::execution::par_unseq, components.client_list().begin(), components.client_list().end(), func); #endif } +void DrawingProgram::check_all_collisions_base(const SCollision::ColliderCollection& checkAgainstWorld, const SCollision::ColliderCollection& checkAgainstCam) { + for(auto& c : components.client_list()) + c->obj->globalCollisionCheck = false; + compCache.traverse_bvh_run_function(checkAgainstWorld.bounds, [&](SCollision::AABB* nodeAABB, const std::vector& comps) { + for(auto& c : comps) { + c->obj->globalCollisionCheck = c->obj->collides_with(world.drawData.cam.c, checkAgainstWorld, checkAgainstCam, colliderAllocated); + } + return true; + }); +} + void DrawingProgram::check_all_collisions(const SCollision::ColliderCollection& checkAgainst) { check_all_collisions_base(checkAgainst, world.drawData.cam.c.world_collider_to_coords>(checkAgainst)); } @@ -232,9 +244,8 @@ void DrawingProgram::tool_options_gui() { default: break; } + t.gui.checkbox_field("Disable Draw Cache", "Disable Cache", &disableCache); } - - } void DrawingProgram::update() { @@ -341,6 +352,8 @@ void DrawingProgram::update() { c->obj->check_timers(*this); c->obj->update(*this); } + + compCache.update(components.client_list()); } void DrawingProgram::drag_drop_update() { @@ -378,8 +391,7 @@ void DrawingProgram::add_file_to_canvas_by_path_execute(const std::string& fileP img->d.p1 = dropPos - imDim; img->d.p2 = dropPos + imDim; img->d.imageID = imageID; - img->initialize_draw_data(*this); - img->finalize_update(colliderAllocated); + img->final_update(*this); uint64_t placement = components.client_list().size(); components.client_insert(placement, img); img->client_send_place(*this, placement); @@ -402,8 +414,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; - img->initialize_draw_data(*this); - img->finalize_update(colliderAllocated); + img->final_update(*this); uint64_t placement = components.client_list().size(); components.client_insert(placement, img); img->client_send_place(*this, placement); @@ -430,8 +441,7 @@ void DrawingProgram::initialize_draw_data(cereal::PortableBinaryInputArchive& a) auto newComp = DrawComponent::allocate_comp_type(t); a(newComp->coords, *newComp); components.init_emplace_back(id, newComp); - newComp->initialize_draw_data(*this); - newComp->finalize_update(colliderAllocated); + newComp->final_update(*this); } } @@ -455,8 +465,7 @@ void DrawingProgram::add_undo_place_component(uint64_t placement, const std::sha if(components.get_id(comp) != ServerClientID{0, 0}) return false; components.client_insert(placement, comp); - comp->initialize_draw_data(*this); // Method to recover after an undo that happened while drawing a component - comp->finalize_update(colliderAllocated); + comp->final_update(*this); // Method to recover after an undo that happened while drawing a component comp->client_send_place(*this, placement); reset_tools(); return true; @@ -489,8 +498,7 @@ void DrawingProgram::add_undo_place_components(uint64_t placement, const std::ve return false; for(auto& c : comps | std::views::reverse) { components.client_insert(placement, c); - c->initialize_draw_data(*this); // Method to recover after an undo that happened while drawing a component - c->finalize_update(colliderAllocated); + c->final_update(*this); // Method to recover after an undo that happened while drawing a component c->client_send_place(*this, placement); } reset_tools(); @@ -530,36 +538,31 @@ void DrawingProgram::write_to_file(cereal::PortableBinaryOutputArchive& a) { void DrawingProgram::draw(SkCanvas* canvas, const DrawData& drawData) { if(drawData.dontUseDrawProgCache) { - for(auto& c : components.client_list()) { + parallel_loop_all_components([&](auto& c) { c->obj->calculate_draw_transform(drawData); + }); + for(auto& c : components.client_list()) c->obj->draw(canvas, drawData); - } } - else if(world.main.drawProgCache.refresh) - draw_cache(canvas, drawData, nullptr); else { - bool caughtFirstUpdated = false; + if(disableCache) { + parallel_loop_all_components([&](auto& c) { + c->obj->calculate_draw_transform(drawData); + }); + } + else { + for(auto& c : components.client_list()) + c->obj->drawSetupData.shouldDraw = false; + compCache.traverse_bvh_run_function(drawData.cam.viewingAreaGenerousCollider, [&](SCollision::AABB* nodeAABB, const std::vector& comps) { + for(auto& c : comps) + c->obj->calculate_draw_transform(drawData); + return true; + }); + } for(auto& c : components.client_list()) { - if(caughtFirstUpdated) { - c->obj->calculate_draw_transform(drawData); - c->obj->draw(canvas, drawData); - } - else if(c->obj == world.main.drawProgCache.firstCompUpdate) { - canvas->drawImage(world.main.drawProgCache.surface->makeTemporaryImage(), 0, 0); - c->obj->calculate_draw_transform(drawData); - c->obj->draw(canvas, drawData); - caughtFirstUpdated = true; - } - else if(c->obj->updateDraw) { - draw_cache(canvas, drawData, c->obj); - c->obj->calculate_draw_transform(drawData); - c->obj->draw(canvas, drawData); - caughtFirstUpdated = true; - } + c->obj->draw(canvas, drawData); c->obj->updateDraw = false; } - if(!caughtFirstUpdated) - canvas->drawImage(world.main.drawProgCache.surface->makeTemporaryImage(), 0, 0); } switch(controls.selectedTool) { @@ -602,15 +605,9 @@ Vector4f* DrawingProgram::get_foreground_color_ptr() { void DrawingProgram::draw_cache(SkCanvas* canvas, const DrawData& drawData, const std::shared_ptr& lastComp) { SkCanvas* cacheCanvas = world.main.drawProgCache.canvas; cacheCanvas->clear(SkColor4f{0, 0, 0, 0}); -#ifdef __EMSCRIPTEN__ - std::for_each(components.client_list().begin(), components.client_list().end(), [&](auto& c) { + parallel_loop_all_components([&](auto& c) { c->obj->calculate_draw_transform(drawData); }); -#else - std::for_each(std::execution::par_unseq, components.client_list().begin(), components.client_list().end(), [&](auto& c) { - c->obj->calculate_draw_transform(drawData); - }); -#endif for(auto& c : components.client_list()) { if(c->obj == lastComp) break; diff --git a/src/DrawingProgram/DrawingProgram.hpp b/src/DrawingProgram/DrawingProgram.hpp index 6c44374..07908fa 100644 --- a/src/DrawingProgram/DrawingProgram.hpp +++ b/src/DrawingProgram/DrawingProgram.hpp @@ -1,5 +1,6 @@ #pragma once #include "../DrawData.hpp" +#include "DrawingProgramCache.hpp" #include "cereal/archives/portable_binary.hpp" #include #include @@ -44,9 +45,15 @@ class DrawingProgram { void add_file_to_canvas_by_path(const std::string& filePath, Vector2f dropPos, bool addInSameThread); void add_file_to_canvas_by_data(const std::string& fileName, std::string_view fileBuffer, Vector2f dropPos); + void parallel_loop_all_components(std::function, ServerClientID>::ObjectInfo>&)> func); + bool colliderAllocated = false; - CollabList, ServerClientID> components; + DrawingProgramCache compCache; + + typedef CollabList, ServerClientID> CollabListType; + + CollabListType components; Vector4f* get_foreground_color_ptr(); private: @@ -72,6 +79,8 @@ class DrawingProgram { void add_undo_place_component(uint64_t placement, const std::shared_ptr& comp); void add_undo_place_components(uint64_t placement, const std::vector>& comps); + bool disableCache = true; + BrushTool brushTool; EraserTool eraserTool; RectSelectTool rectSelectTool; diff --git a/src/DrawingProgram/DrawingProgramCache.cpp b/src/DrawingProgram/DrawingProgramCache.cpp new file mode 100644 index 0000000..0c2a61f --- /dev/null +++ b/src/DrawingProgram/DrawingProgramCache.cpp @@ -0,0 +1,119 @@ +#include "DrawingProgramCache.hpp" + +void DrawingProgramCache::build(std::vector components) { + bvhRoot = BVHNode(); + unsortedComponents.clear(); + std::erase_if(components, [&](auto& c) { + if(!c->obj->worldAABB || c->obj->updateDraw) { + unsortedComponents.emplace_back(c); + return true; + } + return false; + }); + build_bvh_node(bvhRoot, components); +} + +void DrawingProgramCache::update(const std::vector& components) { + if(unsortedComponents.size() >= 1) + build(components); +} + +void DrawingProgramCache::add_component(const CollabListType::ObjectInfoPtr& c) { + unsortedComponents.emplace_back(c); +} + +void DrawingProgramCache::erase_component(const CollabListType::ObjectInfoPtr& c) { + auto it = std::find(unsortedComponents.begin(), unsortedComponents.end(), c); + if(it != unsortedComponents.end()) + unsortedComponents.erase(it); + else { + if(!c->obj->worldAABB.has_value()) + return; + auto bvhNodePair = get_bvh_node_fully_containing_recursive(bvhRoot, c->obj.get()); + if(bvhNodePair.first) + bvhNodePair.first->components.erase(bvhNodePair.second); + } +} + +std::pair::iterator> DrawingProgramCache::get_bvh_node_fully_containing_recursive(BVHNode& bvhNode, DrawComponent* c) { + SCollision::AABB& cAABB = c->worldAABB.value(); + if(!bvhNode.bounds.fully_contains_aabb(cAABB)) + return {nullptr, bvhNode.components.end()}; + auto it = std::find_if(bvhNode.components.begin(), bvhNode.components.end(), [&](const auto& comp) { + return comp->obj.get() == c; + }); + if(it != bvhNode.components.end()) + return {&bvhNode, it}; + for(auto& p : bvhNode.children) { + auto toRet = get_bvh_node_fully_containing_recursive(p, c); + if(toRet.first) + return toRet; + } + return {nullptr, bvhNode.components.end()}; +} + +void DrawingProgramCache::traverse_bvh_run_function(const SCollision::AABB& aabb, std::function* bounds, const std::vector& components)> f) { + f(nullptr, unsortedComponents); + traverse_bvh_run_function_recursive(bvhRoot, aabb, f); +} + +void DrawingProgramCache::traverse_bvh_run_function_recursive(BVHNode& bvhNode, const SCollision::AABB& aabb, std::function* bounds, const std::vector& components)> f) { + if(SCollision::collide(aabb, bvhNode.bounds) && f(&bvhNode.bounds, bvhNode.components)) { + for(auto& p : bvhNode.children) + traverse_bvh_run_function_recursive(p, aabb, f); + } +} + +void DrawingProgramCache::preupdate_component(DrawComponent* c) { + auto it = std::find_if(unsortedComponents.begin(), unsortedComponents.end(), [&](const auto& comp) { + return comp->obj.get() == c; + }); + if(it != unsortedComponents.end()) + return; + else { + if(!c->worldAABB.has_value()) + return; + auto bvhNodePair = get_bvh_node_fully_containing_recursive(bvhRoot, c); + if(bvhNodePair.first) { + unsortedComponents.emplace_back(*bvhNodePair.second); + bvhNodePair.first->components.erase(bvhNodePair.second); + } + } +} + +void DrawingProgramCache::build_bvh_node(BVHNode& node, std::vector components) { + if(components.empty()) + return; + + node.bounds = components.front()->obj->worldAABB.value(); + for(auto& c : components) + node.bounds.include_aabb_in_bounds(c->obj->worldAABB.value()); + + if(components.size() < 50) { + node.components = components; + return; + } + + WorldVec boundsCenter = node.bounds.center(); + + std::array, 4> parts; + + for(auto& c : components) { + const auto& cAABB = c->obj->worldAABB.value(); + if(cAABB.min.x() < boundsCenter.x() && cAABB.max.x() < boundsCenter.x() && cAABB.min.y() < boundsCenter.y() && cAABB.max.y() < boundsCenter.y()) + parts[0].emplace_back(c); + else if(cAABB.min.x() > boundsCenter.x() && cAABB.max.x() > boundsCenter.x() && cAABB.min.y() < boundsCenter.y() && cAABB.max.y() < boundsCenter.y()) + 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 + node.components.emplace_back(c); + } + + for(auto& p : parts) { + if(!p.empty()) + build_bvh_node(node.children.emplace_back(), p); + } +} diff --git a/src/DrawingProgram/DrawingProgramCache.hpp b/src/DrawingProgram/DrawingProgramCache.hpp new file mode 100644 index 0000000..8cfdca7 --- /dev/null +++ b/src/DrawingProgram/DrawingProgramCache.hpp @@ -0,0 +1,32 @@ +#pragma once +#include +#include "../CollabList.hpp" +#include "../DrawComponents/DrawComponent.hpp" + +class DrawingProgramCache { + public: + typedef CollabList, ServerClientID> CollabListType; + void update(const std::vector& components); + void erase_component(const CollabListType::ObjectInfoPtr& c); + void add_component(const CollabListType::ObjectInfoPtr& c); + + struct BVHNode { + SCollision::AABB bounds; + std::vector components; + std::vector children; + }; + + void traverse_bvh_run_function(const SCollision::AABB& aabb, std::function* bounds, const std::vector& components)> f); + + // Run before actually updating the component + void preupdate_component(DrawComponent* c); + private: + void build(std::vector components); + + void traverse_bvh_run_function_recursive(BVHNode& bvhNode, const SCollision::AABB& aabb, std::function* bounds, const std::vector& components)> f); + std::pair::iterator> get_bvh_node_fully_containing_recursive(BVHNode& bvhNode, DrawComponent* c); + + void build_bvh_node(BVHNode& node, std::vector components); + BVHNode bvhRoot; + std::vector unsortedComponents; +}; diff --git a/src/DrawingProgram/EditTool.cpp b/src/DrawingProgram/EditTool.cpp index 7de5c15..72d4da2 100644 --- a/src/DrawingProgram/EditTool.cpp +++ b/src/DrawingProgram/EditTool.cpp @@ -141,7 +141,6 @@ void EditTool::tool_update() { } else { std::shared_ptr a = controls.compToEdit.lock(); - a->updateDraw = true; if(a) { bool isMovingPoint = false; bool clickedAway = false; diff --git a/src/DrawingProgram/RectSelectTool.cpp b/src/DrawingProgram/RectSelectTool.cpp index 6782cdf..49ad781 100644 --- a/src/DrawingProgram/RectSelectTool.cpp +++ b/src/DrawingProgram/RectSelectTool.cpp @@ -148,7 +148,7 @@ void RectSelectTool::tool_update() { auto newCoords = item.oldCoords; newCoords.translate(translationVec); item.comp->coords = newCoords; - item.comp->updateDraw = true; + item.comp->transform_temp_update(drawP); item.comp->client_send_transform_temp(drawP, item.id); item.comp->lastTransformTime = std::chrono::steady_clock::now(); } @@ -185,7 +185,7 @@ void RectSelectTool::tool_update() { newCoords.scale_about(controls.scaleCenterPoint, scaleAmount, flipScale); item.comp->coords = newCoords; item.comp->client_send_transform_temp(drawP, item.id); - item.comp->updateDraw = true; + item.comp->transform_temp_update(drawP); item.comp->lastTransformTime = std::chrono::steady_clock::now(); } } @@ -212,7 +212,7 @@ void RectSelectTool::tool_update() { auto newCoords = item.oldCoords; newCoords.rotate_about(controls.rotationCenter, controls.rotationPointAngle); item.comp->coords = newCoords; - item.comp->updateDraw = true; + item.comp->transform_temp_update(drawP); item.comp->client_send_transform_temp(drawP, item.id); item.comp->lastTransformTime = std::chrono::steady_clock::now(); } @@ -322,7 +322,7 @@ void RectSelectTool::commit_transformation() { std::vector finalCoords; for(auto& item : controls.selectedItems) { item.comp->client_send_transform_final(drawP, item.id); - item.comp->finalize_update(drawP.colliderAllocated); + item.comp->finalize_update(drawP); finalCoords.emplace_back(item.comp->coords); } @@ -333,7 +333,7 @@ void RectSelectTool::commit_transformation() { for(auto& item : sItems) { item.comp->coords = item.oldCoords; item.comp->client_send_transform_final(drawP, drawP.components.get_id(item.comp)); - item.comp->finalize_update(drawP.colliderAllocated); + item.comp->finalize_update(drawP); } drawP.reset_tools(); return true; @@ -342,7 +342,7 @@ void RectSelectTool::commit_transformation() { for(auto [item, finalCoord] : std::views::zip(sItems, finalCoords)) { item.comp->coords = finalCoord; item.comp->client_send_transform_final(drawP, drawP.components.get_id(item.comp)); - item.comp->finalize_update(drawP.colliderAllocated); + item.comp->finalize_update(drawP); } drawP.reset_tools(); return true; diff --git a/src/DrawingProgram/TextBoxTool.cpp b/src/DrawingProgram/TextBoxTool.cpp index fd5f3b7..66d4d96 100644 --- a/src/DrawingProgram/TextBoxTool.cpp +++ b/src/DrawingProgram/TextBoxTool.cpp @@ -268,13 +268,13 @@ void TextBoxTool::tool_update() { // Passing a function in, just in case we have to do something before editing the text void TextBoxTool::edit_text(std::function toRun, const std::shared_ptr& textBox) { toRun(); - textBox->update_contained_string(); + textBox->update_contained_string(drawP); update_textbox_network(textBox); } void TextBoxTool::update_textbox_network(const std::shared_ptr& textBox) { textBox->client_send_update_temp(drawP, drawP.components.get_id(textBox)); - textBox->updateDraw = true; + textBox->temp_update(drawP); } void TextBoxTool::commit() {