diff --git a/CMakeLists.txt b/CMakeLists.txt index 4132eda..e90d60c 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -87,12 +87,6 @@ set(sources "src/main.cpp" "src/CanvasComponents/EllipseCanvasComponent.cpp" "src/CanvasComponents/ImageCanvasComponent.cpp" "src/CanvasComponents/CanvasComponent.cpp" - "src/DrawComponents/DrawEllipse.cpp" - "src/DrawComponents/DrawRectangle.cpp" - "src/DrawComponents/DrawImage.cpp" - "src/DrawComponents/DrawBrushStroke.cpp" - "src/DrawComponents/DrawTextBox.cpp" - "src/DrawComponents/DrawComponent.cpp" "src/GUIStuff/GUIManager.cpp" "src/GUIStuff/GUIManagerID.cpp" "src/GUIStuff/ClayImplement.cpp" diff --git a/include/Helpers/NetworkingObjects/DelayUpdateSerializedClassManager.hpp b/include/Helpers/NetworkingObjects/DelayUpdateSerializedClassManager.hpp index dfbf032..753cbca 100644 --- a/include/Helpers/NetworkingObjects/DelayUpdateSerializedClassManager.hpp +++ b/include/Helpers/NetworkingObjects/DelayUpdateSerializedClassManager.hpp @@ -7,46 +7,80 @@ namespace NetworkingObjects { class DelayUpdateSerializedClassManager { public: - template void register_class(NetObjManager& objMan) { + template struct CustomConstructors { + std::function writeConstructor = [](const T& o, cereal::PortableBinaryOutputArchive& a) { + a(o); + }; + std::function readConstructor = [](T& o, cereal::PortableBinaryOutputArchive& a) { + a(o); + }; + std::function writeUpdate = [](const T& o, cereal::PortableBinaryOutputArchive& a) { + a(o); + }; + std::function readUpdate = [](T& o, cereal::PortableBinaryOutputArchive& a) { + a(o); + }; + std::function(const T& o)> allocateCopy = [](const T& o) { + return std::make_shared(); + }; + std::function assignmentFunc = [](T& o, const T& o2) { + constexpr bool hasDefaultAssignment = requires(T& t, const T& t2) { + t = t2; + }; + if constexpr(hasDefaultAssignment) + o = o2; + }; + std::function postUpdateFunc = [](T& o) {}; + }; + template void register_class(NetObjManager& objMan, const CustomConstructors& t = CustomConstructors()) { objMan.register_class({ - .writeConstructorFuncClient = [&](const NetObjTemporaryPtr& o, cereal::PortableBinaryOutputArchive& a){write_constructor_func(o, a);}, - .readConstructorFuncClient = [&](const NetObjTemporaryPtr& o, cereal::PortableBinaryInputArchive& a, const std::shared_ptr&){read_constructor_func(o, a);}, - .readUpdateFuncClient = [&](const NetObjTemporaryPtr& o, cereal::PortableBinaryInputArchive& a, const std::shared_ptr&){client_read_update_func(o, a);}, - .writeConstructorFuncServer = [&](const NetObjTemporaryPtr& o, cereal::PortableBinaryOutputArchive& a){write_constructor_func(o, a);}, - .readConstructorFuncServer = [&](const NetObjTemporaryPtr& o, cereal::PortableBinaryInputArchive& a, const std::shared_ptr&){read_constructor_func(o, a);}, - .readUpdateFuncServer = [&](const NetObjTemporaryPtr& o, cereal::PortableBinaryInputArchive& a, const std::shared_ptr&){server_read_update_func(o, a);} + .writeConstructorFuncClient = t.writeConstructor, + .readConstructorFuncClient = t.readConstructor, + .readUpdateFuncClient = [&, readUpdate = t.readUpdate](const NetObjTemporaryPtr& o, cereal::PortableBinaryInputArchive& a, const std::shared_ptr&){client_read_update_func(o, a, readUpdate);}, + .writeConstructorFuncServer = t.writeConstructor, + .readConstructorFuncServer = t.readConstructor, + .readUpdateFuncServer = [&, readUpdate = t.readUpdate](const NetObjTemporaryPtr& o, cereal::PortableBinaryInputArchive& a, const std::shared_ptr&){server_read_update_func(o, a, readUpdate);} }); + typeIndexFuncs[std::type_index(typeid(T))] = { + .writeUpdateFunc = [writeFunc = t.writeUpdate](const void* o, cereal::PortableBinaryOutputArchive& a) { + writeFunc(*static_cast(o), a); + }, + .assignmentFunc = [assignFunc = t.assignmentFunc](void* o, const void* o2) { + assignFunc(*static_cast(o), *static_cast(o2)); + }, + .postUpdateFunc = [postUpdateFunc = t.postUpdateFunc](void* o) { + postUpdateFunc(*static_cast(o)); + }, + .allocateCopyFunc = [allocateCopyFunc = t.allocateCopy](const void* o) { + return std::static_pointer_cast(allocateCopyFunc(*static_cast(o))); + } + }; } - template void send_update_to_all(const NetworkingObjects::NetObjTemporaryPtr& o, const std::function& postAssignmentFunc, bool finalUpdate) { + template void send_update_to_all(const NetworkingObjects::NetObjTemporaryPtr& o, bool finalUpdate) { o.send_update_to_all(finalUpdate ? RELIABLE_COMMAND_CHANNEL : UNRELIABLE_COMMAND_CHANNEL, [&](const NetObjTemporaryPtr& o, cereal::PortableBinaryOutputArchive& a) { if(o.get_obj_man()->is_server()) - server_write_func(o, a, postAssignmentFunc); + server_write_func(o, a); else - client_write_update_func(o, a, postAssignmentFunc, finalUpdate); + client_write_update_func(o, a, finalUpdate); }); } void update(); private: - template void write_constructor_func(const NetObjTemporaryPtr& o, cereal::PortableBinaryOutputArchive& a) { - a(*o); - } - - template void client_write_update_func(const NetObjTemporaryPtr& o, cereal::PortableBinaryOutputArchive& a, const std::function& postAssignmentFunc, bool finalUpdate) { + template void client_write_update_func(const NetObjTemporaryPtr& o, cereal::PortableBinaryOutputArchive& a, bool finalUpdate) { a(finalUpdate); - a(*o); + typeIndexFuncs[std::type_index(typeid(T))].writeUpdateFunc(static_cast(o.get()), a); auto it = updatingObjs.find(o.get_net_id()); if(it == updatingObjs.end()) { UpdatingObject toAdd; - toAdd.objToUpdateCurrentData = std::static_pointer_cast(std::make_shared(*o)); + toAdd.objToUpdateCurrentData = typeIndexFuncs[std::type_index(typeid(T))].allocateCopyFunc(static_cast(o.get())); toAdd.doLastAssignment = std::make_shared(true); toAdd.lastUpdateTimePoint = std::chrono::steady_clock::now(); - toAdd.setDataAfterTimeout = [postAssignmentFunc, oWeak = NetObjWeakPtr(o), currentData = toAdd.objToUpdateCurrentData, doLastAssignment = toAdd.doLastAssignment]() { + toAdd.setDataAfterTimeout = [&typeIndexFuncs = typeIndexFuncs, oWeak = NetObjWeakPtr(o), currentData = toAdd.objToUpdateCurrentData, doLastAssignment = toAdd.doLastAssignment]() { NetObjTemporaryPtr oLock = oWeak.lock(); if(oLock && *doLastAssignment) { - *oLock = *std::static_pointer_cast(currentData); - if(postAssignmentFunc) - postAssignmentFunc(*oLock); + typeIndexFuncs[std::type_index(typeid(T))].assignmentFunc(static_cast(oLock.get()), static_cast(currentData.get())); + typeIndexFuncs[std::type_index(typeid(T))].postUpdateFunc(static_cast(oLock.get())); } }; updatingObjs.emplace(o.get_net_id(), toAdd); @@ -57,38 +91,35 @@ namespace NetworkingObjects { } } - template void read_constructor_func(const NetObjTemporaryPtr& o, cereal::PortableBinaryInputArchive& a) { - a(*o); - } - - template void client_read_update_func(const NetObjTemporaryPtr& o, cereal::PortableBinaryInputArchive& a) { + template void client_read_update_func(const NetObjTemporaryPtr& o, cereal::PortableBinaryInputArchive& a, const std::function& readUpdate) { auto it = updatingObjs.find(o.get_net_id()); - if(it == updatingObjs.end()) - a(*o); + if(it == updatingObjs.end()) { + readUpdate(*o, a); + typeIndexFuncs[std::type_index(typeid(T))].postUpdateFunc(static_cast(o.get())); + } else { auto& [netID, updatingObjData] = *it; - a(*std::static_pointer_cast(updatingObjData.objToUpdateCurrentData)); + readUpdate(*std::static_pointer_cast(updatingObjData.objToUpdateCurrentData), a); *updatingObjData.doLastAssignment = true; } } template void server_write_func(const NetObjTemporaryPtr& o, cereal::PortableBinaryOutputArchive& a, const std::function& postAssignmentFunc) { - a(*o); + typeIndexFuncs[std::type_index(typeid(T))].writeUpdateFunc(static_cast(o.get()), a); auto it = updatingObjs.find(o.get_net_id()); if(it == updatingObjs.end()) { UpdatingObject toAdd; - toAdd.objToUpdateCurrentData = std::static_pointer_cast(std::make_shared(*o)); + toAdd.objToUpdateCurrentData = typeIndexFuncs[std::type_index(typeid(T))].allocateCopyFunc(static_cast(o.get())); toAdd.lastUpdateTimePoint = std::chrono::steady_clock::now(); toAdd.doLastAssignment = std::make_shared(false); - toAdd.setDataAfterTimeout = [postAssignmentFunc, oWeak = NetObjWeakPtr(o), currentData = toAdd.objToUpdateCurrentData, doLastAssignment = toAdd.doLastAssignment]() { + toAdd.setDataAfterTimeout = [&typeIndexFuncs = typeIndexFuncs, postAssignmentFunc, oWeak = NetObjWeakPtr(o), currentData = toAdd.objToUpdateCurrentData, doLastAssignment = toAdd.doLastAssignment]() { NetObjTemporaryPtr oLock = oWeak.lock(); if(oLock && *doLastAssignment) { - *oLock = *std::static_pointer_cast(currentData); - if(postAssignmentFunc) - postAssignmentFunc(*oLock); - oLock.send_server_update_to_all_clients(RELIABLE_COMMAND_CHANNEL, [](const NetObjTemporaryPtr& o, cereal::PortableBinaryOutputArchive& a) { - a(*o); + typeIndexFuncs[std::type_index(typeid(T))].assignmentFunc(static_cast(oLock.get()), static_cast(currentData.get())); + typeIndexFuncs[std::type_index(typeid(T))].postUpdateFunc(static_cast(oLock.get())); + oLock.send_server_update_to_all_clients(RELIABLE_COMMAND_CHANNEL, [&typeIndexFuncs = typeIndexFuncs](const NetObjTemporaryPtr& o, cereal::PortableBinaryOutputArchive& a) { + typeIndexFuncs[std::type_index(typeid(T))].writeUpdateFunc(static_cast(o.get()), a); }); } }; @@ -97,23 +128,26 @@ namespace NetworkingObjects { else { auto& [netID, updatingObjData] = *it; updatingObjData.lastUpdateTimePoint = std::chrono::steady_clock::now(); - *std::static_pointer_cast(updatingObjs[o.get_net_id()].objToUpdateCurrentData) = *o; + typeIndexFuncs[std::type_index(typeid(T))].assignmentFunc(static_cast(updatingObjs[o.get_net_id()].objToUpdateCurrentData.get()), static_cast(o.get())); *updatingObjData.doLastAssignment = false; } } - template void server_read_update_func(const NetObjTemporaryPtr& o, cereal::PortableBinaryInputArchive& a) { + template void server_read_update_func(const NetObjTemporaryPtr& o, cereal::PortableBinaryInputArchive& a, const std::function& readUpdate) { auto it = updatingObjs.find(o.get_net_id()); bool finalUpdate; if(it == updatingObjs.end()) { - a(finalUpdate, *o); - o.send_server_update_to_all_clients(finalUpdate ? RELIABLE_COMMAND_CHANNEL : UNRELIABLE_COMMAND_CHANNEL, [](const NetObjTemporaryPtr& o, cereal::PortableBinaryOutputArchive& a) { - a(*o); + a(finalUpdate); + readUpdate(*o, a); + typeIndexFuncs[std::type_index(typeid(T))].postUpdateFunc(static_cast(o.get())); + o.send_server_update_to_all_clients(finalUpdate ? RELIABLE_COMMAND_CHANNEL : UNRELIABLE_COMMAND_CHANNEL, [&typeIndexFuncs = typeIndexFuncs](const NetObjTemporaryPtr& o, cereal::PortableBinaryOutputArchive& a) { + typeIndexFuncs[std::type_index(typeid(T))].writeUpdateFunc(static_cast(o.get()), a); }); } else { auto& [netID, updatingObjData] = *it; - a(finalUpdate, *std::static_pointer_cast(updatingObjData.objToUpdateCurrentData)); + a(finalUpdate); + readUpdate(*std::static_pointer_cast(updatingObjData.objToUpdateCurrentData), a); *updatingObjData.doLastAssignment = true; } } @@ -125,5 +159,13 @@ namespace NetworkingObjects { std::function setDataAfterTimeout; }; std::unordered_map updatingObjs; + + struct ExtraFunctions { + std::function writeUpdateFunc; + std::function assignmentFunc; + std::function postUpdateFunc; + std::function(const void*)> allocateCopyFunc; + }; + std::unordered_map typeIndexFuncs; }; } diff --git a/include/Helpers/NetworkingObjects/NetObjOrderedList.hpp b/include/Helpers/NetworkingObjects/NetObjOrderedList.hpp index e879e35..0879e4c 100644 --- a/include/Helpers/NetworkingObjects/NetObjOrderedList.hpp +++ b/include/Helpers/NetworkingObjects/NetObjOrderedList.hpp @@ -97,6 +97,7 @@ namespace NetworkingObjects { } virtual bool contains(const NetObjID& p) const = 0; + virtual const std::vector>& get_data() const = 0; virtual uint32_t size() const = 0; virtual const NetObjOrderedListObjectInfoPtr& at(uint32_t index) const = 0; virtual bool empty() const = 0; @@ -162,6 +163,9 @@ namespace NetworkingObjects { virtual bool contains(const NetObjID& id) const override { return idToDataMap.contains(id); } + virtual const std::vector>& get_data() const override { + return data; + } virtual uint32_t size() const override { return data.size(); } @@ -330,6 +334,9 @@ namespace NetworkingObjects { virtual bool contains(const NetObjID& id) const override { return clientIdToDataMap.contains(id); } + virtual const std::vector>& get_data() const override { + return clientData; + } virtual uint32_t size() const override { return clientData.size(); } diff --git a/include/Helpers/NetworkingObjects/NetObjWeakPtr.hpp b/include/Helpers/NetworkingObjects/NetObjWeakPtr.hpp index b8f068f..8c1868f 100644 --- a/include/Helpers/NetworkingObjects/NetObjWeakPtr.hpp +++ b/include/Helpers/NetworkingObjects/NetObjWeakPtr.hpp @@ -53,6 +53,10 @@ namespace NetworkingObjects { return NetObjTemporaryPtr(); return NetObjTemporaryPtr(objMan, id, static_cast(it->second.p)); } + void reset() { + objMan = nullptr; + id = NetObjID({0, 0}); + } NetObjManager* get_obj_man() const { return objMan; } diff --git a/src/CanvasComponents/CanvasComponent.hpp b/src/CanvasComponents/CanvasComponent.hpp index 7b81f46..619f1dc 100644 --- a/src/CanvasComponents/CanvasComponent.hpp +++ b/src/CanvasComponents/CanvasComponent.hpp @@ -28,6 +28,7 @@ class CanvasComponent { protected: friend class CanvasComponentContainer; + friend class CanvasComponentAllocator; virtual void draw(SkCanvas* canvas, const DrawData& drawData) const = 0; virtual void initialize_draw_data(DrawingProgram& drawP) = 0; diff --git a/src/CanvasComponents/CanvasComponentAllocator.cpp b/src/CanvasComponents/CanvasComponentAllocator.cpp index 8615c8f..6bae126 100644 --- a/src/CanvasComponents/CanvasComponentAllocator.cpp +++ b/src/CanvasComponents/CanvasComponentAllocator.cpp @@ -1,4 +1,6 @@ #include "CanvasComponentAllocator.hpp" +#include "CanvasComponentContainer.hpp" +#include "../DrawingProgram/DrawingProgram.hpp" CanvasComponentAllocator::CanvasComponentAllocator() {} @@ -6,25 +8,35 @@ CanvasComponentAllocator::CanvasComponentAllocator(CanvasComponent::CompType typ comp = std::unique_ptr(CanvasComponent::allocate_comp(typeToAllocate)); } -void CanvasComponentAllocator::register_class(NetworkingObjects::NetObjManager& objMan) { - objMan.register_class({ - .writeConstructorFuncClient = write_constructor_func, - .readConstructorFuncClient = read_constructor_func, - .readUpdateFuncClient = nullptr, - .writeConstructorFuncServer = write_constructor_func, - .readConstructorFuncServer = read_constructor_func, - .readUpdateFuncServer = nullptr, +void CanvasComponentAllocator::register_class(DrawingProgram& drawP, NetworkingObjects::DelayUpdateSerializedClassManager& delayUpdateMan, NetworkingObjects::NetObjManager& objMan) { + delayUpdateMan.register_class(objMan, NetworkingObjects::DelayUpdateSerializedClassManager::CustomConstructors{ + .writeConstructor = [](const CanvasComponentAllocator& o, cereal::PortableBinaryOutputArchive& a) { + a(o.comp->get_type()); + a(*o.comp); + }, + .readConstructor = [](CanvasComponentAllocator& o, cereal::PortableBinaryOutputArchive& a) { + CanvasComponent::CompType typeToAllocate; + a(typeToAllocate); + o.comp = std::unique_ptr(CanvasComponent::allocate_comp(typeToAllocate)); + a(*o.comp); + }, + .writeUpdate = [](const CanvasComponentAllocator& o, cereal::PortableBinaryOutputArchive& a) { + a(*o.comp); + }, + .readUpdate = [](CanvasComponentAllocator& o, cereal::PortableBinaryOutputArchive& a) { + a(*o.comp); + }, + .allocateCopy = [](const CanvasComponentAllocator& o) { + auto theCopy = std::make_shared(); + theCopy->comp = std::unique_ptr(CanvasComponent::allocate_comp(o.comp->get_type())); + // Maybe do an assignment here + return theCopy; + }, + .assignmentFunc = [](CanvasComponentAllocator& o, const CanvasComponentAllocator& o2) { + // Assignment still needs to be implemented + }, + .postUpdateFunc = [&drawP](CanvasComponentAllocator& o) { + o.comp->compContainer->commit_update(drawP); + } }); } - -void CanvasComponentAllocator::write_constructor_func(const NetworkingObjects::NetObjTemporaryPtr& o, cereal::PortableBinaryOutputArchive& a) { - a(o->comp->get_type()); - a(*o->comp); -} - -void CanvasComponentAllocator::read_constructor_func(const NetworkingObjects::NetObjTemporaryPtr& o, cereal::PortableBinaryInputArchive& a, const std::shared_ptr& c) { - CanvasComponent::CompType typeToAllocate; - a(typeToAllocate); - o->comp = std::unique_ptr(CanvasComponent::allocate_comp(typeToAllocate)); - a(*o->comp); -} diff --git a/src/CanvasComponents/CanvasComponentAllocator.hpp b/src/CanvasComponents/CanvasComponentAllocator.hpp index 0a53d46..654ff1b 100644 --- a/src/CanvasComponents/CanvasComponentAllocator.hpp +++ b/src/CanvasComponents/CanvasComponentAllocator.hpp @@ -2,14 +2,14 @@ #include #include "CanvasComponent.hpp" #include +#include + +class DrawingProgram; class CanvasComponentAllocator { public: CanvasComponentAllocator(); CanvasComponentAllocator(CanvasComponent::CompType typeToAllocate); std::unique_ptr comp; - static void register_class(NetworkingObjects::NetObjManager& objMan); - private: - static void write_constructor_func(const NetworkingObjects::NetObjTemporaryPtr& o, cereal::PortableBinaryOutputArchive& a); - static void read_constructor_func(const NetworkingObjects::NetObjTemporaryPtr& o, cereal::PortableBinaryInputArchive& a, const std::shared_ptr& c); + static void register_class(DrawingProgram& drawP, NetworkingObjects::DelayUpdateSerializedClassManager& delayUpdateMan, NetworkingObjects::NetObjManager& objMan); }; diff --git a/src/CanvasComponents/CanvasComponentContainer.cpp b/src/CanvasComponents/CanvasComponentContainer.cpp index aea0752..8ce9b81 100644 --- a/src/CanvasComponents/CanvasComponentContainer.cpp +++ b/src/CanvasComponents/CanvasComponentContainer.cpp @@ -2,6 +2,8 @@ #include "CanvasComponentAllocator.hpp" #include "../DrawData.hpp" #include "../DrawingProgram/DrawingProgram.hpp" +#include "../World.hpp" +#include using namespace NetworkingObjects; @@ -22,6 +24,10 @@ void CanvasComponentContainer::register_class(NetObjManager& objMan) { }); } +void CanvasComponentContainer::send_comp_update(DrawingProgram& drawP, bool finalUpdate) { + drawP.world.delayedUpdateObjectManager.send_update_to_all(compAllocator, finalUpdate); +} + void CanvasComponentContainer::write_constructor_func(const NetworkingObjects::NetObjTemporaryPtr& o, cereal::PortableBinaryOutputArchive& a) { a(o->coords); o->compAllocator.write_create_message(a); @@ -53,19 +59,25 @@ void CanvasComponentContainer::draw(SkCanvas* canvas, const DrawData& drawData) canvas->restore(); } +void CanvasComponentContainer::set_owner_obj_info(const ObjInfoSharedPtr& ownerObjInfo) { + objInfo = ownerObjInfo; +} + void CanvasComponentContainer::commit_update(DrawingProgram& drawP) { - //if(worldAABB.has_value()) // This is the only point where worldAABB could be nullopt - // drawP.preupdate_component(objInfo); + auto lockedObjInfo = objInfo.lock(); + if(worldAABB.has_value()) // This is the only point where worldAABB could be nullopt + drawP.preupdate_component(lockedObjInfo); get_comp().initialize_draw_data(drawP); calculate_world_bounds(); - //drawP.preupdate_component(objInfo); + drawP.preupdate_component(lockedObjInfo); } void CanvasComponentContainer::commit_transform(DrawingProgram& drawP) { - //if(worldAABB.has_value()) // This is the only point where worldAABB could be nullopt - // drawP.preupdate_component(objInfo); + auto lockedObjInfo = objInfo.lock(); + if(worldAABB.has_value()) // This is the only point where worldAABB could be nullopt + drawP.preupdate_component(lockedObjInfo); calculate_world_bounds(); - //drawP.preupdate_component(objInfo); + drawP.preupdate_component(lockedObjInfo); } void CanvasComponentContainer::commit_update_dont_invalidate_cache(DrawingProgram& drawP) { @@ -73,6 +85,10 @@ void CanvasComponentContainer::commit_update_dont_invalidate_cache(DrawingProgra calculate_world_bounds(); } +void CanvasComponentContainer::commit_transform_dont_invalidate_cache(DrawingProgram& drawP) { + calculate_world_bounds(); +} + bool CanvasComponentContainer::collides_with_world_coords(const CoordSpaceHelper& camCoords, const SCollision::ColliderCollection& checkAgainstWorld) const { return collides_with(camCoords, checkAgainstWorld, camCoords.world_collider_to_coords>(checkAgainstWorld)); } @@ -130,14 +146,10 @@ void CanvasComponentContainer::calculate_world_bounds() { worldAABB = coords.collider_to_world, SCollision::AABB>(get_comp().get_obj_coord_bounds()); } -std::optional> CanvasComponentContainer::get_world_bounds() const { - return worldAABB; +SCollision::AABB CanvasComponentContainer::get_world_bounds() const { + return worldAABB.value(); } CanvasComponent& CanvasComponentContainer::get_comp() const { return *compAllocator->comp; } - -const CoordSpaceHelper& CanvasComponentContainer::get_coords() const { - return coords; -} diff --git a/src/CanvasComponents/CanvasComponentContainer.hpp b/src/CanvasComponents/CanvasComponentContainer.hpp index d0729fd..5d58eae 100644 --- a/src/CanvasComponents/CanvasComponentContainer.hpp +++ b/src/CanvasComponents/CanvasComponentContainer.hpp @@ -3,14 +3,17 @@ #include "CanvasComponent.hpp" #include #include "../VersionConstants.hpp" -#include "Helpers/NetworkingObjects/NetObjOrderedList.hpp" +#include #include class DrawingProgram; class CanvasComponentAllocator; +class DrawingProgramCacheBVHNode; class CanvasComponentContainer { public: + typedef NetworkingObjects::NetObjOrderedList NetList; + typedef NetworkingObjects::NetObjOwnerPtr> NetListOwnerPtr; typedef NetworkingObjects::NetObjOrderedListObjectInfo ObjInfo; typedef std::shared_ptr ObjInfoSharedPtr; typedef std::weak_ptr ObjInfoWeakPtr; @@ -29,16 +32,21 @@ class CanvasComponentContainer { void save_file(cereal::PortableBinaryOutputArchive& a) const; void load_file(cereal::PortableBinaryInputArchive& a, VersionNumber version); CanvasComponent& get_comp() const; - const CoordSpaceHelper& get_coords() const; - std::optional> get_world_bounds() const; + SCollision::AABB get_world_bounds() const; void draw(SkCanvas* canvas, const DrawData& drawData) const; void commit_update(DrawingProgram& drawP); + void commit_transform_dont_invalidate_cache(DrawingProgram& drawP); // Must be thread safe void commit_transform(DrawingProgram& drawP); void commit_update_dont_invalidate_cache(DrawingProgram& drawP); // Must be thread safe bool should_draw(const DrawData& drawData) const; bool collides_with_world_coords(const CoordSpaceHelper& camCoords, const SCollision::ColliderCollection& checkAgainstWorld) const; bool collides_with_cam_coords(const CoordSpaceHelper& camCoords, const SCollision::ColliderCollection& checkAgainstCam) const; bool collides_with(const CoordSpaceHelper& camCoords, const SCollision::ColliderCollection& checkAgainstWorld, const SCollision::ColliderCollection& checkAgainstCam) const; + void set_owner_obj_info(const ObjInfoSharedPtr& ownerObjInfo); + void send_comp_update(DrawingProgram& drawP, bool finalUpdate); + + std::weak_ptr parentBvhNode; + CoordSpaceHelper coords; private: friend class BrushStrokeCanvasComponent; friend class ImageCanvasComponent; @@ -58,9 +66,7 @@ class CanvasComponentContainer { TransformDrawData calculate_draw_transform(const DrawData& drawData) const; void calculate_world_bounds(); - ObjInfo* objInfo = nullptr; - + ObjInfoWeakPtr objInfo; std::optional> worldAABB; NetworkingObjects::NetObjOwnerPtr compAllocator; - CoordSpaceHelper coords; }; diff --git a/src/CanvasComponents/TextBoxCanvasComponent.cpp b/src/CanvasComponents/TextBoxCanvasComponent.cpp index 047a349..5519768 100644 --- a/src/CanvasComponents/TextBoxCanvasComponent.cpp +++ b/src/CanvasComponents/TextBoxCanvasComponent.cpp @@ -84,7 +84,7 @@ void TextBoxCanvasComponent::draw(SkCanvas* canvas, const DrawData& drawData) co } Vector2f TextBoxCanvasComponent::get_mouse_pos(DrawingProgram& drawP) const { - return compContainer->get_coords().get_mouse_pos(drawP.world) - d.p1 - Vector2f{TEXTBOX_PADDING, TEXTBOX_PADDING}; + return compContainer->coords.get_mouse_pos(drawP.world) - d.p1 - Vector2f{TEXTBOX_PADDING, TEXTBOX_PADDING}; } void TextBoxCanvasComponent::initialize_draw_data(DrawingProgram& drawP) { diff --git a/src/CollabList.hpp b/src/CollabList.hpp deleted file mode 100644 index 63800fb..0000000 --- a/src/CollabList.hpp +++ /dev/null @@ -1,383 +0,0 @@ -#pragma once -#include "SharedTypes.hpp" -#include - -template class CollabList { - public: - CollabList(const std::function& initGetNewIDFunc): - getNewIDFunc(initGetNewIDFunc) - {} - - struct ObjectInfo { - bool syncIgnore; - T obj; - uint64_t pos; - }; - - 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; - std::function& c)> clientInsertOrderedVectorCallback; - std::function clientServerFirstPosShiftCallback; - - void set_server_from_client_list() { - serverSideList = clientSideList; - for(auto& obj : serverSideList) - obj->syncIgnore = false; - } - - ObjectInfoPtr get_item_by_id(IDType id) { - auto it = idToObjectMap.find(id); - return (idToObjectMap.end() == it) ? nullptr : it->second; - } - - void client_erase_if(const std::function&)>& func) { - bool erasedSomething = false; - for(int64_t i = 0; i < (int64_t)clientSideList.size(); i++) { - if(func((uint64_t)i, clientSideList[i])) { - if(clientEraseCallback) - clientEraseCallback(clientSideList[i]); - clientSideList[i]->obj->collabListInfo.reset(); - idToObjectMap.erase(clientSideList[i]->obj->id); - clientSideList.erase(clientSideList.begin() + i); - i--; - if(updateCallback) - updateCallback(); - erasedSomething = true; - } - } - if(erasedSomething) - complete_client_pos_refresh(false); - } - - ObjectInfoPtr client_insert(uint64_t pos, const T& item, bool createNewIDs = true) { - auto newObj(std::make_shared()); - newObj->syncIgnore = true; - newObj->obj = item; - if(createNewIDs) - newObj->obj->id = getNewIDFunc(); - newObj->pos = std::min(static_cast(clientSideList.size()), pos); - item->collabListInfo = newObj; - - clientSideList.insert(clientSideList.begin() + newObj->pos, newObj); - idToObjectMap.emplace(newObj->obj->id, newObj); - - client_pos_refresh_after_insert(newObj->pos); - - if(clientInsertCallback) - clientInsertCallback(newObj); - if(updateCallback) - updateCallback(); - - return newObj; - } - - std::vector client_insert_ordered_vector_items(uint64_t pos, const std::vector& items, bool createNewIDs = true) { - std::vector itemsToPushIn; - for(auto& item : items) { - auto& newObj = itemsToPushIn.emplace_back(std::make_shared()); - newObj->syncIgnore = true; - newObj->obj = item; - if(createNewIDs) - newObj->obj->id = getNewIDFunc(); - item->collabListInfo = newObj; - idToObjectMap.emplace(newObj->obj->id, newObj); - } - - clientSideList.insert(clientSideList.begin() + pos, itemsToPushIn.begin(), itemsToPushIn.end()); - - complete_client_pos_refresh(false); - - if(clientInsertOrderedVectorCallback) - clientInsertOrderedVectorCallback(itemsToPushIn); - if(updateCallback) - updateCallback(); - - return itemsToPushIn; - } - - IDType client_insert(const ObjectInfoPtr& objInfoToInsert, bool createNewIDs = true) { - objInfoToInsert->syncIgnore = true; - if(createNewIDs) - objInfoToInsert->obj->id = getNewIDFunc(); - objInfoToInsert->pos = std::min(static_cast(clientSideList.size()), objInfoToInsert->pos); - objInfoToInsert->obj->collabListInfo = objInfoToInsert; - - clientSideList.insert(clientSideList.begin() + objInfoToInsert->pos, objInfoToInsert); - idToObjectMap.emplace(objInfoToInsert->obj->id, objInfoToInsert); - - client_pos_refresh_after_insert(objInfoToInsert->pos); - - if(clientInsertCallback) - clientInsertCallback(objInfoToInsert); - if(updateCallback) - updateCallback(); - - return objInfoToInsert->obj->id; - } - - void client_erase(const ObjectInfoPtr& objToErase) { - bool erasedSomething = false; - std::erase_if(clientSideList, [&](const auto& obj) { - if(obj->obj == objToErase->obj) { - if(clientEraseCallback) - clientEraseCallback(obj); - idToObjectMap.erase(objToErase->obj->id); - obj->syncIgnore = true; - obj->obj->collabListInfo.reset(); - erasedSomething = true; - return true; - } - return false; - }); - if(erasedSomething) { - if(updateCallback) - updateCallback(); - complete_client_pos_refresh(false); - } - } - - void client_erase_set(const std::unordered_set& objSet) { - bool erasedSomething = false; - std::erase_if(clientSideList, [&](const auto& obj) { - if(objSet.contains(obj)) { - if(clientEraseCallback) - clientEraseCallback(obj); - idToObjectMap.erase(obj->obj->id); - obj->syncIgnore = true; - obj->obj->collabListInfo.reset(); - erasedSomething = true; - return true; - } - return false; - }); - if(erasedSomething) { - complete_client_pos_refresh(false); - if(updateCallback) - updateCallback(); - for(auto& o : objSet) - o->obj->collabListInfo.reset(); - } - } - - // NOTE: Dont use this function unless you're certain every object in the vector isn't already in the client list - void client_insert_ordered_vector(const std::vector& objOrderedVector, bool createNewIDs = true) { - if(objOrderedVector.empty()) - return; - - uint64_t startPoint = 0; - objOrderedVector.front()->syncIgnore = true; - if(createNewIDs) - objOrderedVector.front()->obj->id = getNewIDFunc(); - objOrderedVector.front()->obj->collabListInfo = objOrderedVector.front(); - idToObjectMap.emplace(objOrderedVector.front()->obj->id, objOrderedVector.front()); - - for(uint64_t i = 1; i < static_cast(objOrderedVector.size()); i++) { - auto& obj = objOrderedVector[i]; - obj->syncIgnore = true; - if(createNewIDs) - obj->obj->id = getNewIDFunc(); - obj->obj->collabListInfo = obj; - idToObjectMap.emplace(obj->obj->id, obj); - if(obj->pos - objOrderedVector[startPoint]->pos != (i - startPoint)) { - uint64_t insertPosition = std::min(clientSideList.size(), objOrderedVector[startPoint]->pos); - clientSideList.insert(clientSideList.begin() + insertPosition, objOrderedVector.begin() + startPoint, objOrderedVector.begin() + i); - startPoint = i; - } - } - clientSideList.insert(clientSideList.begin() + std::min(clientSideList.size(), objOrderedVector[startPoint]->pos), objOrderedVector.begin() + startPoint, objOrderedVector.end()); - - complete_client_pos_refresh(false); - if(updateCallback) - updateCallback(); - if(clientInsertOrderedVectorCallback) - clientInsertOrderedVectorCallback(objOrderedVector); - } - - std::vector server_insert_ordered_vector(std::vector objOrderedVector) { - if(objOrderedVector.empty()) - return std::vector(); - - std::vector didntExistPreviously(objOrderedVector.size(), true); - - uint64_t startPoint = 0; - auto foundInClient1 = idToObjectMap.emplace(objOrderedVector.front()->obj->id, objOrderedVector.front()); - if(!foundInClient1.second) { // object already existed - objOrderedVector.front() = foundInClient1.first->second; - didntExistPreviously[0] = false; - } - objOrderedVector.front()->syncIgnore = false; - objOrderedVector.front()->obj->collabListInfo = objOrderedVector.front(); - - for(uint64_t i = 1; i < static_cast(objOrderedVector.size()); i++) { - auto& obj = objOrderedVector[i]; - - auto foundInClient = idToObjectMap.emplace(obj->obj->id, obj); - if(!foundInClient.second) { // object already existed - obj = foundInClient.first->second; - didntExistPreviously[i] = false; - } - obj->syncIgnore = false; - obj->obj->collabListInfo = obj; - - if(obj->pos - objOrderedVector[startPoint]->pos != (i - startPoint)) { - uint64_t insertPosition = std::min(clientSideList.size(), objOrderedVector[startPoint]->pos); - clientSideList.insert(clientSideList.begin() + insertPosition, objOrderedVector.begin() + startPoint, objOrderedVector.begin() + i); - uint64_t insertPositionServer = std::min(serverSideList.size(), objOrderedVector[startPoint]->pos); - serverSideList.insert(serverSideList.begin() + insertPositionServer, objOrderedVector.begin() + startPoint, objOrderedVector.begin() + i); - startPoint = i; - } - } - clientSideList.insert(clientSideList.begin() + std::min(clientSideList.size(), objOrderedVector[startPoint]->pos), objOrderedVector.begin() + startPoint, objOrderedVector.end()); - serverSideList.insert(serverSideList.begin() + std::min(serverSideList.size(), objOrderedVector[startPoint]->pos), objOrderedVector.begin() + startPoint, objOrderedVector.end()); - - if(clientInsertOrderedVectorCallback) - clientInsertOrderedVectorCallback(objOrderedVector); - - sync(); - - return didntExistPreviously; - } - - bool server_insert(uint64_t pos, const T& item) { - auto foundInClient = idToObjectMap.find(item->id); - if(foundInClient != idToObjectMap.end()) { - ObjectInfoPtr& o = foundInClient->second; - serverSideList.insert(serverSideList.begin() + pos, o); - o->syncIgnore = false; - sync(); - return false; - } - auto newObj(std::make_shared()); - newObj->syncIgnore = false; - newObj->obj = item; - newObj->pos = std::min(pos, clientSideList.size()); - idToObjectMap.emplace(newObj->obj->id, newObj); - item->collabListInfo = newObj; - - serverSideList.insert(serverSideList.begin() + pos, newObj); - clientSideList.insert(clientSideList.begin() + newObj->pos, newObj); - - for(uint64_t i = newObj->pos + 1; i < static_cast(clientSideList.size()); i++) - clientSideList[i]->pos++; - - if(clientInsertCallback) - clientInsertCallback(newObj); - - sync(); - return true; - } - void server_erase(IDType id) { - std::erase_if(serverSideList, [&](const auto& obj) { - if(obj->obj->id == id) { - obj->syncIgnore = false; - return true; - } - return false; - }); - std::erase_if(clientSideList, [&](const auto& obj) { - if(obj->obj->id == id) { - obj->syncIgnore = false; - idToObjectMap.erase(obj->obj->id); - if(clientEraseCallback) - clientEraseCallback(obj); - obj->obj->collabListInfo.reset(); - return true; - } - return false; - }); - sync(); - } - - void server_erase_set(const std::unordered_set& idsToErase) { - std::erase_if(serverSideList, [&](const auto& obj) { - if(idsToErase.contains(obj->obj->id)) { - obj->syncIgnore = false; - return true; - } - return false; - }); - std::erase_if(clientSideList, [&](const auto& obj) { - if(idsToErase.contains(obj->obj->id)) { - obj->syncIgnore = false; - if(clientEraseCallback) - clientEraseCallback(obj); - idToObjectMap.erase(obj->obj->id); - obj->obj->collabListInfo.reset(); - return true; - } - return false; - }); - sync(); - } - - void init_emplace_back(const T& item) { - auto newObj(std::make_shared()); - newObj->syncIgnore = false; - newObj->obj = item; - item->collabListInfo = newObj; - idToObjectMap.emplace(newObj->obj->id, newObj); - - serverSideList.emplace_back(newObj); - clientSideList.emplace_back(newObj); - - newObj->pos = clientSideList.size() - 1; - - if(clientInsertCallback) - clientInsertCallback(newObj); - if(updateCallback) - updateCallback(); - } - private: - void complete_client_pos_refresh(bool syncFromServer) { - uint64_t firstShiftPos = std::numeric_limits::max(); - bool shiftHappened = false; - for(uint64_t i = 0; i < clientSideList.size(); i++) { - auto& c = clientSideList[i]; - if(c->pos != i) { - firstShiftPos = std::min(firstShiftPos, c->pos); - firstShiftPos = std::min(firstShiftPos, i); - shiftHappened = true; - c->pos = i; - } - } - if(syncFromServer && shiftHappened && clientServerFirstPosShiftCallback) - clientServerFirstPosShiftCallback(firstShiftPos); - } - - void client_pos_refresh_after_insert(uint64_t posToRefreshAfter) { - for(uint64_t i = posToRefreshAfter + 1; i < static_cast(clientSideList.size()); i++) - clientSideList[i]->pos = i; - } - - void sync() { - std::vector> ignoredToReinsert; - for(uint64_t i = 0; i < clientSideList.size(); i++) - if(clientSideList[i]->syncIgnore) - ignoredToReinsert.emplace_back(std::pair>{i, clientSideList[i]}); - clientSideList = serverSideList; - std::erase_if(clientSideList, [&](const auto& obj) { - return obj->syncIgnore; - }); - for(auto& p : ignoredToReinsert) { - if(p.first > clientSideList.size()) - clientSideList.emplace_back(p.second); - else - clientSideList.insert(clientSideList.begin() + p.first, p.second); - } - if(updateCallback) - updateCallback(); - complete_client_pos_refresh(true); - } - - std::function getNewIDFunc; - std::vector clientSideList; - std::vector serverSideList; - std::unordered_map idToObjectMap; -}; diff --git a/src/DrawComponents/DrawBrushStroke.cpp b/src/DrawComponents/DrawBrushStroke.cpp deleted file mode 100644 index 031f743..0000000 --- a/src/DrawComponents/DrawBrushStroke.cpp +++ /dev/null @@ -1,460 +0,0 @@ -#include "DrawBrushStroke.hpp" -#include -#include -#include - -#ifndef IS_SERVER -#include -#include "Helpers/MathExtras.hpp" -#include "../TimePoint.hpp" -#include -#include -#include "../DrawCollision.hpp" -#endif - -#define AABB_PRECHECK_BVH_LEVELS 2 -#define DEFAULT_SMOOTHNESS 5 - -void DrawBrushStroke::save(cereal::PortableBinaryOutputArchive& a) const { - a(d->points, d->color, d->hasRoundCaps); -} - -void DrawBrushStroke::load(cereal::PortableBinaryInputArchive& a) { - a(d->points, d->color, d->hasRoundCaps); -} - -void DrawBrushStroke::save_file(cereal::PortableBinaryOutputArchive& a) const { - a(d->points, d->color, d->hasRoundCaps); -} - -void DrawBrushStroke::load_file(cereal::PortableBinaryInputArchive& a, VersionNumber version) { - a(d->points, d->color, d->hasRoundCaps); -} - -DrawComponentType DrawBrushStroke::get_type() const { - return DRAWCOMPONENT_BRUSHSTROKE; -} - -#ifndef IS_SERVER - -std::shared_ptr DrawBrushStroke::copy(DrawingProgram& drawP) const { - auto a = std::make_shared(); - a->d = d; - a->coords = coords; - return a; -} - -std::shared_ptr DrawBrushStroke::deep_copy(DrawingProgram& drawP) const { - auto a = std::make_shared(); - a->d = d; - a->coords = coords; - // Just copy pointers over, brush strokes cant be edited so they can share the same memory - a->brushPath = brushPath; - a->brushPathLOD = brushPathLOD; - a->bounds = bounds; - - return a; -} - -void DrawBrushStroke::update_from_delayed_ptr(const std::shared_ptr& delayedUpdatePtr) { - std::shared_ptr newPtr = std::static_pointer_cast(delayedUpdatePtr); - d = newPtr->d; -} - -Vector2f two_dim_vec_slerp(const Vector2f& v1, const Vector2f& v2) { - Vector2f v1Norm = v1.normalized(); - Vector2f v2Norm = v2.normalized(); - Vector2f avg = (v1Norm + v2Norm) * 0.5f; - if(std::fabs(avg.x()) < 0.00001f && std::fabs(avg.y()) < 0.00001f) - return perpendicular_vec2(v1Norm).normalized(); - else - return avg.normalized(); -} - -void DrawBrushStroke::draw(SkCanvas* canvas, const DrawData& drawData) { - if(drawSetupData.shouldDraw && brushPath) { - //bool deepPrecheck = false; - //for(auto& aabb : precheckAABBLevels) { - // if(SCollision::collide(drawData.cam.viewingAreaGenerousCollider, aabb)) { - // deepPrecheck = true; - // break; - // } - //} - //if(!deepPrecheck && !precheckAABBLevels.empty()) - // return; - - SkPaint paint; - //paint.setStroke(true); - //paint.setStrokeWidth(0.0f); - canvas->save(); - paint.setColor4f(SkColor4f{d->color.x(), d->color.y(), d->color.z(), d->color.w()}); - canvas_do_calculated_transform(canvas); - if(drawSetupData.mipmapLevel == 0 || drawData.dontUseDrawProgCache) // check dontUseDrawProgCache, to make sure that SVG screenshots dont use LOD - canvas->drawPath(*brushPath, paint); - else - canvas->drawPath(*brushPathLOD[drawSetupData.mipmapLevel - 1], paint); - //SkPaint p2(SkColor4f{1, 0, 0, 1}); - //p2.setStroke(true); - //SkPaint p3(SkColor4f{0, 1, 0, 1}); - //SkPaint p4(SkColor4f{0, 0, 1, 1}); - //p3.setStroke(true); - //p4.setStroke(true); - //for(auto& precheckAABBLevel : precheckAABBLevels) - // draw_collider(canvas, drawData, precheckAABBLevel, p4); - //draw_collider(canvas, drawData, collisionTree, p3); - canvas->restore(); - } -} - -void DrawBrushStroke::initialize_draw_data(DrawingProgram& drawP) { - if(!d->points.empty()) { - std::vector points = smooth_points(0, d->points.size() - 1, DEFAULT_SMOOTHNESS); - auto triangleFunc = [&](Vector2f a, Vector2f b, Vector2f c) { - return false; - }; - - auto brushPathBuilder = std::make_shared(); - auto brushPathLOD0Builder = std::make_shared(); - auto brushPathLOD1Builder = std::make_shared(); - - create_triangles(triangleFunc, points, 0, brushPathBuilder); - create_triangles(triangleFunc, points, 4, brushPathLOD0Builder); - create_triangles(triangleFunc, points, 30, brushPathLOD1Builder); - - brushPath = std::make_shared(brushPathBuilder->detach()); - brushPathLOD[0] = std::make_shared(brushPathLOD0Builder->detach()); - brushPathLOD[1] = std::make_shared(brushPathLOD1Builder->detach()); - } - create_collider(); -} - -std::vector DrawBrushStroke::get_wedge_indices(const std::vector& points) { - if(points.size() < 2) - return {}; - std::vector toRet; - toRet.emplace_back(0); - for(size_t i = 1; i < points.size() - 1; i++) { - Vector2f v1Norm = (points[i - 1].pos - points[i].pos).normalized(); - Vector2f v2Norm = (points[i + 1].pos - points[i].pos).normalized(); - if(v1Norm.dot(v2Norm) > -0.6f) - toRet.emplace_back(i); - } - toRet.emplace_back(points.size() - 1); - return toRet; -} - -std::vector DrawBrushStroke::smooth_points(size_t beginIndex, size_t endIndex, unsigned numOfDivisions) { - std::vector& points = d->points; - - size_t pointsSize = endIndex - beginIndex + 1; - if(pointsSize < 2) - return {points[beginIndex], points[endIndex]}; - - std::vector toRet; - - DrawBrushStrokePoint p0 = points[beginIndex]; - p0.pos = p0.pos + p0.width * (p0.pos - points[beginIndex + 1].pos).normalized() * DRAW_MINIMUM_LIMIT; - DrawBrushStrokePoint p1 = points[beginIndex]; - DrawBrushStrokePoint p2 = points[beginIndex + 1]; - DrawBrushStrokePoint p3; - - for(size_t i = beginIndex; i < endIndex; i++) { - - if(i == endIndex - 1) { - p3 = points[i + 1]; - p3.pos = p3.pos + p3.width * (p3.pos - points[i].pos).normalized() * DRAW_MINIMUM_LIMIT; - } - else - p3 = points[i + 2]; - - toRet.emplace_back(p1); - - float tMove = 1.0 / static_cast(numOfDivisions); - for(unsigned d = 1; d < numOfDivisions; d++) { - float t = tMove * static_cast(d); - DrawBrushStrokePoint pToAdd; - pToAdd.pos = catmull_rom(p0.pos, p1.pos, p2.pos, p3.pos, t); - pToAdd.width = std::lerp(p1.width, p2.width, t); - if(!(std::isnan(pToAdd.pos.x()) || std::isnan(pToAdd.pos.y()))) // Don't add NAN values - toRet.emplace_back(pToAdd); - } - p0 = p1; - p1 = p2; - p2 = p3; - } - toRet.emplace_back(points[endIndex]); - - return toRet; -} - -std::vector DrawBrushStroke::smooth_points_avg(size_t beginIndex, size_t endIndex, unsigned numOfDivisions) { - std::vector& points = d->points; - - size_t pointsSize = endIndex - beginIndex + 1; - if(pointsSize < 2) - return {points[beginIndex], points[endIndex]}; - - std::vector toRet; - - for(size_t i = beginIndex; i < endIndex; i++) { - const DrawBrushStrokePoint& p1 = points[i]; - const DrawBrushStrokePoint& p2 = points[i + 1]; - - float tMove = 1.0 / static_cast(numOfDivisions); - for(unsigned d = 0; d < numOfDivisions; d++) { - float t = tMove * static_cast(d); - DrawBrushStrokePoint pToAdd; - pToAdd.pos = lerp_vec(p1.pos, p2.pos, t); - pToAdd.width = std::lerp(p1.width, p2.width, t); - if(!(std::isnan(pToAdd.pos.x()) || std::isnan(pToAdd.pos.y()))) // Don't add NAN values - toRet.emplace_back(pToAdd); - } - } - - toRet.emplace_back(points[endIndex]); - - return toRet; -} - -std::vector DrawBrushStroke::every_nth_point_include_front_and_back(const std::vector& pts, size_t n) { - if(pts.size() <= 3 || n == 0) - return pts; - std::vector toRet; - toRet.emplace_back(pts.front()); - for(size_t i = n; i < pts.size() - 1; i += n) - toRet.emplace_back(pts[i]); - toRet.emplace_back(pts.back()); - return toRet; -} - -void DrawBrushStroke::create_triangles(const std::function& passTriangleFunc, const std::vector& smoothedPoints, size_t skipVertexCount, std::shared_ptr bPathBuilder) { - const int ARC_SMOOTHNESS = 10; - const int CIRCLE_SMOOTHNESS = 20; - const std::vector& pointsN = d->points; - std::vector topPoints; - std::vector bottomPoints; - - if(pointsN.size() == 1 && d->hasRoundCaps) { - std::vector circlePoints = gen_circle_points(pointsN.front().pos, pointsN.front().width / 2.0f, CIRCLE_SMOOTHNESS); - for(size_t i = 0; i < circlePoints.size(); i++) { - if(passTriangleFunc(pointsN.front().pos, circlePoints[i], circlePoints[(i + 1) % circlePoints.size()])) return; - topPoints.emplace_back(convert_vec2(circlePoints[i])); - } - } - - if(pointsN.size() < 2) { - if(bPathBuilder && !topPoints.empty()) - bPathBuilder->addPolygon({topPoints.data(), topPoints.size()}, false); - return; - } - - auto points = every_nth_point_include_front_and_back(smoothedPoints, skipVertexCount); - - std::vector wedgeIndices = get_wedge_indices(points); - for(size_t i = 0; i < wedgeIndices.size() - 1; i++) { - - size_t pointsBegin = wedgeIndices[i]; - size_t pointsEnd = wedgeIndices[i + 1]; - - std::array vertArray; - size_t newIndex = 0; - - Vector2f perpPrev = perpendicular_vec2((points[pointsBegin + 1].pos - points[pointsBegin].pos).eval()); - perpPrev.normalize(); - - vertArray[0] = points[pointsBegin].pos + perpPrev * points[pointsBegin].width * 0.5f; - topPoints.emplace_back(convert_vec2(vertArray[0])); - vertArray[1] = points[pointsBegin].pos - perpPrev * points[pointsBegin].width * 0.5f; - bottomPoints.emplace_back(convert_vec2(vertArray[1])); - newIndex = 2; - - if(d->hasRoundCaps && pointsBegin == 0) { - Vector2f arcDirStart = (convert_vec2(vertArray[0]) - points[0].pos).normalized(); - Vector2f arcDirEnd = (convert_vec2(vertArray[1]) - points[0].pos).normalized(); - Vector2f arcDirCenter = (points[0].pos - points[1].pos).normalized(); - std::vector arcPoints = arc_vec(points[0].pos, arcDirStart, arcDirEnd, arcDirCenter, points[0].width * 0.5f, ARC_SMOOTHNESS); - arcPoints.emplace(arcPoints.begin(), convert_vec2(vertArray[0])); - arcPoints.emplace_back(convert_vec2(vertArray[1])); - for(size_t i = 0; i < arcPoints.size() - 1; i++) { - if(passTriangleFunc(points[0].pos, arcPoints[i], arcPoints[i + 1])) return; - bottomPoints.emplace_back(convert_vec2(arcPoints[i])); - } - bottomPoints.emplace_back(convert_vec2(arcPoints.back())); - } - - for(size_t j = pointsBegin + 1; j < pointsEnd; j++) { - if(j >= pointsEnd) - j = pointsEnd - 1; - - Vector2f v1 = points[j - 1].pos - points[j].pos; - Vector2f v2 = points[j].pos - points[j + 1].pos; - Vector2f perp = perpendicular_vec2((v1 + v2).eval()).normalized(); - if(std::isnan(perp.dot(perpPrev))) { - std::cout << "NAN FOUND" << std::endl; - std::cout << v1 << std::endl; - std::cout << v2 << std::endl; - std::cout << perp << std::endl; - std::cout << perpPrev << std::endl; - throw 1; - } - if(perp.dot(perpPrev) < 0.0) - perp = -perp; - - vertArray[newIndex] = points[j].pos + perp * 0.5f * points[j].width; - topPoints.emplace_back(convert_vec2(vertArray[newIndex])); - newIndex = (newIndex + 1) % 3; - if(passTriangleFunc(vertArray[0], vertArray[1], vertArray[2])) return; - - vertArray[newIndex] = points[j].pos - perp * 0.5f * points[j].width; - bottomPoints.emplace_back(convert_vec2(vertArray[newIndex])); - newIndex = (newIndex + 1) % 3; - if(passTriangleFunc(vertArray[0], vertArray[1], vertArray[2])) return; - - perpPrev = perp; - } - - Vector2f rectDir = points[pointsEnd - 1].pos - points[pointsEnd].pos; - rectDir.normalize(); - Vector2f perp = perpendicular_vec2(rectDir); - if(perp.dot(perpPrev) < 0.0) - perp = -perp; - vertArray[newIndex] = points[pointsEnd].pos + perp * points[pointsEnd].width * 0.5; - topPoints.emplace_back(convert_vec2(vertArray[newIndex])); - newIndex = (newIndex + 1) % 3; - if(passTriangleFunc(vertArray[0], vertArray[1], vertArray[2])) return; - - vertArray[newIndex] = points[pointsEnd].pos - perp * points[pointsEnd].width * 0.5; - bottomPoints.emplace_back(convert_vec2(vertArray[newIndex])); - newIndex = (newIndex + 1) % 3; - if(passTriangleFunc(vertArray[0], vertArray[1], vertArray[2])) return; - - // Render wedge - if(pointsEnd != points.size() - 1) { - // Find 4 points involved in intersection - Vector2f currentP1 = points[pointsEnd].pos - perp * points[pointsEnd].width * 0.5; - Vector2f currentP2 = points[pointsEnd].pos + perp * points[pointsEnd].width * 0.5; - Vector2f nextRectDir = points[pointsEnd + 1].pos - points[pointsEnd].pos; - nextRectDir.normalize(); - Vector2f nextPerp = perpendicular_vec2(nextRectDir); - Vector2f nextP1 = points[pointsEnd].pos - nextPerp * points[pointsEnd].width * 0.5; - Vector2f nextP2 = points[pointsEnd].pos + nextPerp * points[pointsEnd].width * 0.5; - - // Find center of wedge - Vector2f wedgeCenter = line_line_intersection(currentP1, currentP2, nextP1, nextP2); - - Vector2f wedgeP1 = ((currentP1 - currentP2).dot(nextRectDir)) <= 0.0 ? currentP1 : currentP2; - Vector2f wedgeP2 = ((nextP1 - nextP2).dot(rectDir)) <= 0.0 ? nextP1 : nextP2; - bool isTopWedge = wedgeP1 == convert_vec2(topPoints.back()); - - float arcRadius; - - std::vector arcPoints; - - if(wedgeCenter.x() == std::numeric_limits::max()) { - wedgeCenter = (currentP1 + currentP2) * 0.5; - wedgeP1 = currentP1; - wedgeP2 = currentP2; - arcRadius = points[pointsEnd].width * 0.5; - arcPoints = arc_vec(wedgeCenter, (wedgeP1 - wedgeCenter).normalized(), (wedgeP2 - wedgeCenter).normalized(), (-rectDir).eval(), arcRadius, ARC_SMOOTHNESS); - } - else { - arcRadius = (wedgeCenter - wedgeP1).norm(); - arcPoints = arc_vec(wedgeCenter, (wedgeP1 - wedgeCenter).normalized(), (wedgeP2 - wedgeCenter).normalized(), lerp_vec((-rectDir).eval(), (-nextRectDir).eval(), 0.5).normalized(), arcRadius, ARC_SMOOTHNESS); - } - - arcPoints.emplace(arcPoints.begin(), wedgeP1); - arcPoints.emplace_back(wedgeP2); - for(size_t i = 0; i < arcPoints.size() - 1; i++) { - if(passTriangleFunc(wedgeCenter, arcPoints[i], arcPoints[i + 1])) return; - if(isTopWedge) - topPoints.emplace_back(convert_vec2(arcPoints[i])); - else - bottomPoints.emplace_back(convert_vec2(arcPoints[i])); - } - if(isTopWedge) - topPoints.emplace_back(convert_vec2(arcPoints.back())); - else - bottomPoints.emplace_back(convert_vec2(arcPoints.back())); - } - else if(d->hasRoundCaps) { // It's the last point, cap it off - Vector2f arcDirStart = (convert_vec2(vertArray[(newIndex + 1) % 3]) - points.back().pos).normalized(); - Vector2f arcDirEnd = (convert_vec2(vertArray[(newIndex + 2) % 3]) - points.back().pos).normalized(); - Vector2f arcDirCenter = -rectDir; - std::vector arcPoints = arc_vec(points.back().pos, arcDirStart, arcDirEnd, arcDirCenter, points.back().width * 0.5f, ARC_SMOOTHNESS); - arcPoints.emplace(arcPoints.begin(), convert_vec2(vertArray[(newIndex + 1) % 3])); - arcPoints.emplace_back(convert_vec2(vertArray[(newIndex + 2) % 3])); - for(size_t i = 0; i < arcPoints.size() - 1; i++) { - if(passTriangleFunc(points.back().pos, arcPoints[i], arcPoints[i + 1])) return; - topPoints.emplace_back(convert_vec2(arcPoints[i])); - } - topPoints.emplace_back(convert_vec2(arcPoints.back())); - } - } - - if(bPathBuilder && !topPoints.empty()) { - topPoints.insert(topPoints.begin(), bottomPoints.rbegin(), bottomPoints.rend()); - bPathBuilder->addPolygon({topPoints.data(), topPoints.size()}, false); - } -} - -void DrawBrushStroke::create_collider() { - using namespace SCollision; - if(d->points.empty()) - return; - ColliderCollection strokeObjects; - std::vector points = smooth_points(0, d->points.size() - 1, DEFAULT_SMOOTHNESS); - create_triangles([&](Vector2f a, Vector2f b, Vector2f c) { - strokeObjects.triangle.emplace_back(a, b, c); - return false; - }, points, 0, nullptr); - strokeObjects.recalculate_bounds(); - - SCollision::BVHContainer collisionTree; - - collisionTree.calculate_bvh_recursive(strokeObjects, AABB_PRECHECK_BVH_LEVELS + 1); - precheckAABBLevels.clear(); - add_precheck_aabb_level(AABB_PRECHECK_BVH_LEVELS, collisionTree.children); - - bounds = collisionTree.objects.bounds; -} - -void DrawBrushStroke::add_precheck_aabb_level(size_t level, const std::vector>& levelArray) { - for(const auto& a : levelArray) { - if(level == 0 || a.children.empty()) - precheckAABBLevels.emplace_back(a.objects.bounds); - else - add_precheck_aabb_level(level - 1, a.children); - } -} - -void DrawBrushStroke::update(DrawingProgram& drawP) { -} - -bool DrawBrushStroke::collides_within_coords(const SCollision::ColliderCollection& checkAgainst) { - if(!SCollision::collide(checkAgainst, bounds)) - return false; - - bool deepPrecheck = false; - for(auto& aabb : precheckAABBLevels) { - if(SCollision::collide(checkAgainst, aabb)) { - deepPrecheck = true; - break; - } - } - if(!deepPrecheck && !precheckAABBLevels.empty()) - return false; - - bool toRet = false; - std::vector points = smooth_points(0, d->points.size() - 1, DEFAULT_SMOOTHNESS); - create_triangles([&](Vector2f a, Vector2f b, Vector2f c) { - toRet = SCollision::collide(checkAgainst, SCollision::Triangle{a, b, c}); - return toRet; - }, points, 0, nullptr); - return toRet; -} - -SCollision::AABB DrawBrushStroke::get_obj_coord_bounds() const { - return bounds; -} - -#endif diff --git a/src/DrawComponents/DrawBrushStroke.hpp b/src/DrawComponents/DrawBrushStroke.hpp deleted file mode 100644 index 3a1c369..0000000 --- a/src/DrawComponents/DrawBrushStroke.hpp +++ /dev/null @@ -1,67 +0,0 @@ -#pragma once -#include "../SharedTypes.hpp" -#include "DrawComponent.hpp" -#include "Helpers/SCollision.hpp" -#include - -#ifndef IS_SERVER -#include -#include -#endif - -#define DRAW_MINIMUM_LIMIT 0.3 - - -struct DrawBrushStrokePoint { - Vector2f pos; - float width; - - template void serialize(Archive& a) { - a(pos, width); - } -}; - -class DrawBrushStroke : public DrawComponent { - public: - virtual DrawComponentType get_type() const override; - virtual void save(cereal::PortableBinaryOutputArchive& a) const override; - virtual void load(cereal::PortableBinaryInputArchive& a) override; - virtual void save_file(cereal::PortableBinaryOutputArchive& a) const override; - virtual void load_file(cereal::PortableBinaryInputArchive& a, VersionNumber version) override; - - struct Data { - std::vector points; - Vector4f color; - bool hasRoundCaps; - }; - std::shared_ptr d = std::make_shared(); // It's a pointer here since brush strokes cant be edited - -#ifndef IS_SERVER - virtual std::shared_ptr copy(DrawingProgram& drawP) const override; - virtual std::shared_ptr deep_copy(DrawingProgram& drawP) const override; - - virtual void draw(SkCanvas* canvas, const DrawData& drawData) override; - virtual void initialize_draw_data(DrawingProgram& drawP) override; - virtual void update(DrawingProgram& drawP) override; - virtual bool collides_within_coords(const SCollision::ColliderCollection& checkAgainst) override; - void create_collider(); - virtual void update_from_delayed_ptr(const std::shared_ptr& delayedUpdatePtr) override; - - virtual SCollision::AABB get_obj_coord_bounds() const override; - - std::shared_ptr brushPath; - SCollision::AABB bounds; - - std::array, 2> brushPathLOD; - private: - std::vector every_nth_point_include_front_and_back(const std::vector& pts, size_t n); - - void add_precheck_aabb_level(size_t level, const std::vector>& levelArray); - std::vector> precheckAABBLevels; - void create_triangles(const std::function& passTriangleFunc, const std::vector& smoothedPoints, size_t skipVertexCount, std::shared_ptr bPath); - std::vector get_wedge_indices(const std::vector& points); - std::vector smooth_points(size_t beginIndex, size_t endIndex, unsigned numOfDivisions); - std::vector smooth_points_avg(size_t beginIndex, size_t endIndex, unsigned numOfDivisions); -#endif -}; - diff --git a/src/DrawComponents/DrawComponent.cpp b/src/DrawComponents/DrawComponent.cpp deleted file mode 100644 index e0b4e57..0000000 --- a/src/DrawComponents/DrawComponent.cpp +++ /dev/null @@ -1,229 +0,0 @@ -#include "DrawComponent.hpp" -#include "DrawBrushStroke.hpp" -#include "DrawEllipse.hpp" -#include "DrawRectangle.hpp" -#include "DrawTextBox.hpp" -#include "DrawImage.hpp" -#include "Helpers/Networking/NetLibrary.hpp" -#include "../SharedTypes.hpp" -#include "../Server/CommandList.hpp" -#include -#include - -#ifndef IS_SERVER -#include "../MainProgram.hpp" -#endif - -void save(cereal::PortableBinaryOutputArchive& a, const CollabListType::ObjectInfo& o) { - // Client will send ID, but server should ignore ID and generate its own - a(o.pos, o.obj->get_type(), o.obj->id, o.obj->coords, *o.obj); -} - -void load(cereal::PortableBinaryInputArchive& a, CollabListType::ObjectInfo& o) { - DrawComponentType t; - a(o.pos, t); - o.obj = DrawComponent::allocate_comp_type(t); - a(o.obj->id, o.obj->coords, *o.obj); -} - -void SendOrderedComponentVectorOp::save(cereal::PortableBinaryOutputArchive& a) const { - a((uint64_t)v->size()); - for(auto& c : *v) - a(*c); -} - -void SendOrderedComponentVectorOp::load(cereal::PortableBinaryInputArchive& a) { - v->clear(); - uint64_t vSize; - a(vSize); - for(uint64_t i = 0; i < vSize; i++) - a(*v->emplace_back(std::make_shared())); -} - -std::shared_ptr DrawComponent::allocate_comp_type(DrawComponentType type) { - switch(type) { - case DRAWCOMPONENT_BRUSHSTROKE: - return std::make_shared(); - case DRAWCOMPONENT_RECTANGLE: - return std::make_shared(); - case DRAWCOMPONENT_ELLIPSE: - return std::make_shared(); - case DRAWCOMPONENT_TEXTBOX: - return std::make_shared(); - case DRAWCOMPONENT_IMAGE: - return std::make_shared(); - } - return nullptr; -} - -void DrawComponent::server_send_place_many(MainServer& server, std::vector& comps) { - server.netServer->send_items_to_all_clients(RELIABLE_COMMAND_CHANNEL, CLIENT_PLACE_MANY_COMPONENTS, SendOrderedComponentVectorOp{&comps}); -} - -void DrawComponent::server_send_place(MainServer& server, uint64_t placement) { - server.netServer->send_items_to_all_clients(RELIABLE_COMMAND_CHANNEL, CLIENT_PLACE_SINGLE_COMPONENT, placement, get_type(), id, this->coords, *this); -} - -void DrawComponent::server_send_erase(MainServer& server, ServerClientID id) { - server.netServer->send_items_to_all_clients(RELIABLE_COMMAND_CHANNEL, CLIENT_ERASE_SINGLE_COMPONENT, id); -} - -void DrawComponent::server_send_erase_set(MainServer& server, const std::unordered_set& ids) { - server.netServer->send_items_to_all_clients(RELIABLE_COMMAND_CHANNEL, CLIENT_ERASE_MANY_COMPONENTS, ids); -} - -void DrawComponent::server_send_update(MainServer& server, bool final) { - if(final) - server.netServer->send_items_to_all_clients(RELIABLE_COMMAND_CHANNEL, CLIENT_UPDATE_COMPONENT, final, id, *this); - else - server.netServer->send_items_to_all_clients(UNRELIABLE_COMMAND_CHANNEL, CLIENT_UPDATE_COMPONENT, final, id, *this); -} - -void DrawComponent::server_send_transform_many(MainServer& server, const std::vector>& transforms) { - server.netServer->send_items_to_all_clients(RELIABLE_COMMAND_CHANNEL, CLIENT_TRANSFORM_MANY_COMPONENTS, transforms); -} - -void DrawComponent::get_used_resources(std::unordered_set& v) const { -} - -void DrawComponent::remap_resource_ids(std::unordered_map& newIDs) { -} - -#ifndef IS_SERVER - -bool DrawComponent::bounds_draw_check(const DrawData& drawData) const { - bool a = !drawData.clampDrawBetween || (drawData.clampDrawMinimum < coords.inverseScale); - return a; -} - -bool DrawComponent::check_timers(DrawingProgram& drawP, const std::shared_ptr& delayedUpdatePtr) { - if(delayedUpdatePtr) { - if(std::chrono::steady_clock::now() - lastUpdateTime > CLIENT_DRAWCOMP_DELAY_TIMER_DURATION) { - update_from_delayed_ptr(delayedUpdatePtr); - commit_update(drawP); - return true; - } - return false; - } - return true; -} - -void DrawComponent::commit_update(DrawingProgram& drawP, bool invalidateCache) { - auto lockedCollabInfo = collabListInfo.lock(); - if(invalidateCache && lockedCollabInfo && worldAABB) - drawP.preupdate_component(lockedCollabInfo); - initialize_draw_data(drawP); - calculate_world_bounds(); - if(invalidateCache && lockedCollabInfo && worldAABB) - drawP.preupdate_component(lockedCollabInfo); -} - -void DrawComponent::commit_transform(DrawingProgram& drawP, bool invalidateCache) { - auto lockedCollabInfo = collabListInfo.lock(); - if(invalidateCache && lockedCollabInfo && worldAABB) - drawP.preupdate_component(lockedCollabInfo); - calculate_world_bounds(); - if(invalidateCache && lockedCollabInfo && worldAABB) - drawP.preupdate_component(lockedCollabInfo); -} - -void DrawComponent::scale_up(const WorldScalar& scaleUpAmount) { - coords.scale_about(WorldVec{0, 0}, scaleUpAmount, true); - calculate_world_bounds(); -} - -void DrawComponent::client_send_place_many(DrawingProgram& drawP, std::vector& comps) { - drawP.world.con.client_send_items_to_server(RELIABLE_COMMAND_CHANNEL, SERVER_PLACE_MANY_COMPONENTS, SendOrderedComponentVectorOp{&comps}); -} - -void DrawComponent::client_send_place(DrawingProgram& drawP) { - //if(collabListInfo.lock()) If this fails, then there's a real issue - drawP.world.con.client_send_items_to_server(RELIABLE_COMMAND_CHANNEL, SERVER_PLACE_SINGLE_COMPONENT, collabListInfo.lock()->pos, get_type(), id, this->coords, *this); -} - -void DrawComponent::client_send_update(DrawingProgram& drawP, bool final) { - if(collabListInfo.lock()) { - if(final) - drawP.world.con.client_send_items_to_server(RELIABLE_COMMAND_CHANNEL, SERVER_UPDATE_COMPONENT, final, id, *this); - else - drawP.world.con.client_send_items_to_server(UNRELIABLE_COMMAND_CHANNEL, SERVER_UPDATE_COMPONENT, final, id, *this); - } -} - -void DrawComponent::client_send_transform_many(DrawingProgram& drawP, const std::vector>& transforms) { - drawP.world.con.client_send_items_to_server(RELIABLE_COMMAND_CHANNEL, SERVER_TRANSFORM_MANY_COMPONENTS, transforms); -} - -void DrawComponent::client_send_erase(DrawingProgram& drawP) { - if(collabListInfo.lock()) - drawP.world.con.client_send_items_to_server(RELIABLE_COMMAND_CHANNEL, SERVER_ERASE_SINGLE_COMPONENT, id); -} - -void DrawComponent::client_send_erase_set(DrawingProgram& drawP, const std::unordered_set& ids) { - drawP.world.con.client_send_items_to_server(RELIABLE_COMMAND_CHANNEL, SERVER_ERASE_MANY_COMPONENTS, ids); -} - -bool DrawComponent::collides_with_world_coords(const CoordSpaceHelper& camCoords, const SCollision::ColliderCollection& checkAgainstWorld) { - return collides_with(camCoords, checkAgainstWorld, camCoords.world_collider_to_coords>(checkAgainstWorld)); -} - -bool DrawComponent::collides_with_cam_coords(const CoordSpaceHelper& camCoords, const SCollision::ColliderCollection& checkAgainstCam) { - return collides_with(camCoords, camCoords.collider_to_world>(checkAgainstCam), checkAgainstCam); -} - -// We could just send one of the checkAgainst colliders, since they represent the same thing, but sending both saves on redundant transformations, since we can save both of the versions on the executor side -bool DrawComponent::collides_with(const CoordSpaceHelper& camCoords, const SCollision::ColliderCollection& checkAgainstWorld, const SCollision::ColliderCollection& checkAgainstCam) { - if((camCoords.inverseScale << DRAWCOMP_MAX_SHIFT_BEFORE_STOP_COLLISIONS) < coords.inverseScale) // Object is too large, just dismiss the collision - return false; - else if((camCoords.inverseScale >> DRAWCOMP_COLLIDE_MIN_SHIFT_TINY) >= coords.inverseScale) { - if(!worldAABB) - return false; - return SCollision::collide(checkAgainstCam, camCoords.to_space(worldAABB->min)); - } - else { - auto c = checkAgainstWorld.transform( - [&coords = coords](const WorldVec& a) { - return coords.to_space(a); - }, - [&coords = coords](const WorldScalar& a) { - return coords.scalar_to_space(a); - }); - return collides_within_coords(c); - } -} - -void DrawComponent::canvas_do_calculated_transform(SkCanvas* canvas) { - canvas->scale(drawSetupData.transformData.scale, drawSetupData.transformData.scale); - canvas->rotate(drawSetupData.transformData.rotation); - canvas->translate(drawSetupData.transformData.translation.x(), drawSetupData.transformData.translation.y()); -} - -void DrawComponent::calculate_draw_transform(const DrawData& drawData) { - drawSetupData.shouldDraw = !drawData.clampDrawBetween || (drawData.clampDrawMinimum < coords.inverseScale); - if(drawSetupData.shouldDraw) { - drawSetupData.shouldDraw = !worldAABB || SCollision::collide(*worldAABB, drawData.cam.viewingAreaGenerousCollider); - if(drawSetupData.shouldDraw) { - if(drawData.mipMapLevelTwo > coords.inverseScale) - drawSetupData.mipmapLevel = 2; - else if(drawData.mipMapLevelOne > coords.inverseScale) - drawSetupData.mipmapLevel = 1; - else - drawSetupData.mipmapLevel = 0; - drawSetupData.transformData.translation = -coords.to_space(drawData.cam.c.pos); - drawSetupData.transformData.rotation = (coords.rotation - drawData.cam.c.rotation) * 180.0 / std::numbers::pi; - drawSetupData.transformData.scale = std::min(static_cast(coords.inverseScale / drawData.cam.c.inverseScale), static_cast(1 << DRAWCOMP_MAX_SHIFT_BEFORE_STOP_SCALING)); - } - } -} - -void DrawComponent::calculate_world_bounds() { - worldAABB = std::optional>(coords.collider_to_world, SCollision::AABB>(get_obj_coord_bounds())); -} - -std::optional> DrawComponent::get_world_bounds() const { - return worldAABB; -} - -#endif - -DrawComponent::~DrawComponent() { } diff --git a/src/DrawComponents/DrawComponent.hpp b/src/DrawComponents/DrawComponent.hpp deleted file mode 100644 index 34bf034..0000000 --- a/src/DrawComponents/DrawComponent.hpp +++ /dev/null @@ -1,117 +0,0 @@ -#pragma once -#include "Helpers/SCollision.hpp" -#include -#include "cereal/archives/portable_binary.hpp" -#include "../SharedTypes.hpp" -#include "../CoordSpaceHelper.hpp" -#include "../Server/MainServer.hpp" -#include "../CollabList.hpp" -#include - -#ifndef IS_SERVER -#include "../DrawData.hpp" -#include -#include -#include -#endif - -#define CLIENT_DRAWCOMP_DELAY_TIMER_DURATION std::chrono::seconds(6) - -#define DRAWCOMP_MAX_SHIFT_BEFORE_STOP_COLLISIONS 14 -#define DRAWCOMP_MAX_SHIFT_BEFORE_STOP_SCALING 14 -#define DRAWCOMP_MIN_SHIFT_BEFORE_DISAPPEAR 11 -#define DRAWCOMP_COLLIDE_MIN_SHIFT_TINY 9 -#define DRAWCOMP_MIPMAP_LEVEL_ONE 2 -#define DRAWCOMP_MIPMAP_LEVEL_TWO 5 - -class DrawingProgram; -class DrawComponent; -class DrawingProgramCacheBVHNode; - -typedef CollabList, ServerClientID> CollabListType; - -void save(cereal::PortableBinaryOutputArchive& a, const CollabListType::ObjectInfo& o); -void load(cereal::PortableBinaryInputArchive& a, CollabListType::ObjectInfo& o); - -struct SendOrderedComponentVectorOp { - std::vector* v; - void save(cereal::PortableBinaryOutputArchive& a) const; - void load(cereal::PortableBinaryInputArchive& a); -}; - -class DrawComponent { - public: - static std::shared_ptr allocate_comp_type(DrawComponentType type); - virtual void save(cereal::PortableBinaryOutputArchive& a) const = 0; - virtual void load(cereal::PortableBinaryInputArchive& a) = 0; - virtual void save_file(cereal::PortableBinaryOutputArchive& a) const = 0; - virtual void load_file(cereal::PortableBinaryInputArchive& a, VersionNumber version) = 0; - virtual DrawComponentType get_type() const = 0; - virtual void get_used_resources(std::unordered_set& v) const; - virtual void remap_resource_ids(std::unordered_map& newIDs); - virtual ~DrawComponent(); - - // NOTE: Permanantly altering the coordinates during transformation can lead to loss of detail for smaller objects - CoordSpaceHelper coords; - - struct DrawSetupData { - struct TransformDrawData { - Vector2f translation; - float rotation; - float scale; - } transformData; - bool shouldDraw = false; - uint8_t mipmapLevel = 0; - } drawSetupData; - - void canvas_do_calculated_transform(SkCanvas* canvas); - void calculate_draw_transform(const DrawData& drawData); - - void server_send_place(MainServer& server, uint64_t placement); - - void scale_up(const WorldScalar& scaleUpAmount); - - static void server_send_place_many(MainServer& server, std::vector& comps); - static void server_send_erase(MainServer& server, ServerClientID id); - static void server_send_erase_set(MainServer& server, const std::unordered_set& ids); - void server_send_update(MainServer& server, bool final); - static void server_send_transform_many(MainServer& server, const std::vector>& transforms); - - std::weak_ptr collabListInfo; - std::weak_ptr parentBvhNode; - ServerClientID id = {0, 0}; - -#ifndef IS_SERVER - std::chrono::time_point lastUpdateTime; - - bool bounds_draw_check(const DrawData& drawData) const; - - bool check_timers(DrawingProgram& drawP, const std::shared_ptr& delayedUpdatePtr); - static void client_send_place_many(DrawingProgram& drawP, std::vector& comps); - void client_send_place(DrawingProgram& drawP); - void client_send_erase(DrawingProgram& drawP); - static void client_send_erase_set(DrawingProgram& drawP, const std::unordered_set& ids); - void client_send_update(DrawingProgram& drawP, bool final); - static void client_send_transform_many(DrawingProgram& drawP, const std::vector>& transforms); - - std::optional> worldAABB; - - std::optional> get_world_bounds() const; - void calculate_world_bounds(); - virtual SCollision::AABB get_obj_coord_bounds() const = 0; - - virtual std::shared_ptr copy(DrawingProgram& drawP) const = 0; - virtual std::shared_ptr deep_copy(DrawingProgram& drawP) const = 0; - - virtual void draw(SkCanvas* canvas, const DrawData& drawData) = 0; - void commit_update(DrawingProgram& drawP, bool invalidateCache = true); // invalidateCache = false version should be thread safe - void commit_transform(DrawingProgram& drawP, bool invalidateCache = true); // invalidateCache = false version should be thread safe - virtual void initialize_draw_data(DrawingProgram& drawP) = 0; - virtual void update(DrawingProgram& drawP) = 0; - virtual bool collides_within_coords(const SCollision::ColliderCollection& checkAgainst) = 0; - bool collides_with_world_coords(const CoordSpaceHelper& camCoords, const SCollision::ColliderCollection& checkAgainstWorld); - bool collides_with_cam_coords(const CoordSpaceHelper& camCoords, const SCollision::ColliderCollection& checkAgainstCam); - bool collides_with(const CoordSpaceHelper& camCoords, const SCollision::ColliderCollection& checkAgainstWorld, const SCollision::ColliderCollection& checkAgainstCam); - virtual void update_from_delayed_ptr(const std::shared_ptr& delayedUpdatePtr) = 0; -#endif -}; diff --git a/src/DrawComponents/DrawEllipse.cpp b/src/DrawComponents/DrawEllipse.cpp deleted file mode 100644 index 19f793c..0000000 --- a/src/DrawComponents/DrawEllipse.cpp +++ /dev/null @@ -1,154 +0,0 @@ -#include "DrawEllipse.hpp" -#include "Helpers/ConvertVec.hpp" -#include "Helpers/SCollision.hpp" -#include - -#ifndef IS_SERVER -#include "../DrawCollision.hpp" -#endif - -DrawComponentType DrawEllipse::get_type() const { - return DRAWCOMPONENT_ELLIPSE; -} - -void DrawEllipse::save(cereal::PortableBinaryOutputArchive& a) const { - a(d.strokeColor, d.fillColor, d.strokeWidth, d.p1, d.p2, d.fillStrokeMode); -} - -void DrawEllipse::load(cereal::PortableBinaryInputArchive& a) { - a(d.strokeColor, d.fillColor, d.strokeWidth, d.p1, d.p2, d.fillStrokeMode); -} - -void DrawEllipse::save_file(cereal::PortableBinaryOutputArchive& a) const { - a(d.strokeColor, d.fillColor, d.strokeWidth, d.p1, d.p2, d.fillStrokeMode); -} - -void DrawEllipse::load_file(cereal::PortableBinaryInputArchive& a, VersionNumber version) { - a(d.strokeColor, d.fillColor, d.strokeWidth, d.p1, d.p2, d.fillStrokeMode); -} - -#ifndef IS_SERVER -std::shared_ptr DrawEllipse::copy(DrawingProgram& drawP) const { - auto a = std::make_shared(); - a->d = d; - a->coords = coords; - return a; -} - -std::shared_ptr DrawEllipse::deep_copy(DrawingProgram& drawP) const { - auto a = std::make_shared(); - a->d = d; - a->coords = coords; - a->ellipsePath = ellipsePath; - a->collisionTree = collisionTree; - return a; -} - -void DrawEllipse::update_from_delayed_ptr(const std::shared_ptr& delayedUpdatePtr) { - std::shared_ptr newPtr = std::static_pointer_cast(delayedUpdatePtr); - d = newPtr->d; -} - -void DrawEllipse::draw(SkCanvas* canvas, const DrawData& drawData) { - if(drawSetupData.shouldDraw) { - canvas->save(); - canvas_do_calculated_transform(canvas); - if(d.fillStrokeMode == 0 || d.fillStrokeMode == 2) { - SkPaint p; - p.setStyle(SkPaint::kFill_Style); - p.setColor4f(convert_vec4(d.fillColor)); - canvas->drawPath(ellipsePath, p); - } - if(d.fillStrokeMode == 1 || d.fillStrokeMode == 2) { - SkPaint p; - p.setStyle(SkPaint::kStroke_Style); - p.setColor4f(convert_vec4(d.strokeColor)); - p.setStrokeWidth(d.strokeWidth); - canvas->drawPath(ellipsePath, p); - } - canvas->restore(); - } -} - -void DrawEllipse::create_draw_data() { - SkPathBuilder ellipsePathBuilder; - SkRect newRect = SkRect::MakeLTRB(d.p1.x(), d.p1.y(), d.p2.x(), d.p2.y()); - ellipsePathBuilder.addOval(newRect); - ellipsePath = ellipsePathBuilder.detach(); -} - -void DrawEllipse::initialize_draw_data(DrawingProgram& drawP) { - create_draw_data(); - create_collider(); -} - -void DrawEllipse::update(DrawingProgram& drawP) { -} - -bool DrawEllipse::collides_within_coords(const SCollision::ColliderCollection& checkAgainst) { - return collisionTree.is_collide(checkAgainst); -} - -void DrawEllipse::create_collider() { - using namespace SCollision; - ColliderCollection strokeObjects; - - if(d.fillStrokeMode == 0) { - Vector2f ellipseCenter = (d.p1 + d.p2) * 0.5; - float a = ellipseCenter.x() - d.p1.x(); - float b = ellipseCenter.y() - d.p1.y(); - Vector2f prevPoint = ellipseCenter + Vector2f{a * std::cos(0), b * std::sin(0)}; - unsigned numOfSegments = 20; - float segmentStep = 1.0 / numOfSegments; - float t = 0.0; - for(unsigned i = 0; i <= numOfSegments; i++) { - Vector2f nextPoint = ellipseCenter + Vector2f{a * std::cos(t), b * std::sin(t)}; - strokeObjects.triangle.emplace_back(ellipseCenter, prevPoint, nextPoint); - prevPoint = nextPoint; - t += segmentStep * std::numbers::pi * 2.0; - } - } - else if(d.fillStrokeMode == 1) { - std::vector points; - - Vector2f ellipseCenter = (d.p1 + d.p2) * 0.5; - float a = ellipseCenter.x() - d.p1.x(); - float b = ellipseCenter.y() - d.p1.y(); - unsigned numOfSegments = 40; - float segmentStep = 1.0 / numOfSegments; - float t = 0.0; - for(unsigned i = 0; i < numOfSegments; i++) { - points.emplace_back(ellipseCenter + Vector2f{a * std::cos(t), b * std::sin(t)}); - t += segmentStep * std::numbers::pi * 2.0; - } - generate_polyline(strokeObjects, points, d.strokeWidth, true); - - } - else if(d.fillStrokeMode == 2) { - float strokeRadius = d.strokeWidth * 0.5f; - Vector2f wNewP1 = d.p1 - Vector2f{strokeRadius, strokeRadius}; - Vector2f wNewP2 = d.p2 + Vector2f{strokeRadius, strokeRadius}; - Vector2f ellipseCenter = (wNewP1 + wNewP2) * 0.5; - float a = ellipseCenter.x() - wNewP1.x(); - float b = ellipseCenter.y() - wNewP1.y(); - Vector2f prevPoint = ellipseCenter + Vector2f{a * std::cos(0), b * std::sin(0)}; - unsigned numOfSegments = 20; - float segmentStep = 1.0 / numOfSegments; - float t = 0.0; - for(unsigned i = 0; i <= numOfSegments; i++) { - Vector2f nextPoint = ellipseCenter + Vector2f{a * std::cos(t), b * std::sin(t)}; - strokeObjects.triangle.emplace_back(ellipseCenter, prevPoint, nextPoint); - prevPoint = nextPoint; - t += segmentStep * std::numbers::pi * 2.0; - } - } - - collisionTree.clear(); - collisionTree.calculate_bvh_recursive(strokeObjects); -} - -SCollision::AABB DrawEllipse::get_obj_coord_bounds() const { - return collisionTree.objects.bounds; -} - -#endif diff --git a/src/DrawComponents/DrawEllipse.hpp b/src/DrawComponents/DrawEllipse.hpp deleted file mode 100644 index b06dde4..0000000 --- a/src/DrawComponents/DrawEllipse.hpp +++ /dev/null @@ -1,50 +0,0 @@ -#pragma once -#include "../SharedTypes.hpp" -#include "DrawComponent.hpp" -#include "../CoordSpaceHelper.hpp" - -#ifndef IS_SERVER -#include -#endif - -class DrawEllipse : public DrawComponent { - public: - virtual void save(cereal::PortableBinaryOutputArchive& a) const override; - virtual void load(cereal::PortableBinaryInputArchive& a) override; - virtual void save_file(cereal::PortableBinaryOutputArchive& a) const override; - virtual void load_file(cereal::PortableBinaryInputArchive& a, VersionNumber version) override; - virtual DrawComponentType get_type() const override; - - // User input data - struct Data { - Vector4f strokeColor; - Vector4f fillColor; - float strokeWidth; - Vector2f p1; - Vector2f p2; - uint8_t fillStrokeMode; - bool operator==(const Data& o) const = default; - } d; - -#ifndef IS_SERVER - virtual std::shared_ptr copy(DrawingProgram& drawP) const override; - virtual std::shared_ptr deep_copy(DrawingProgram& drawP) const override; - - virtual void draw(SkCanvas* canvas, const DrawData& drawData) override; - virtual void initialize_draw_data(DrawingProgram& drawP) override; - virtual void update(DrawingProgram& drawP) override; - virtual bool collides_within_coords(const SCollision::ColliderCollection& checkAgainst) override; - virtual void update_from_delayed_ptr(const std::shared_ptr& delayedUpdatePtr) override; - void create_draw_data(); - void create_collider(); - - virtual SCollision::AABB get_obj_coord_bounds() const override; - - SkPath ellipsePath; - - // Cache - SCollision::BVHContainer collisionTree; - private: - void create_triangles(const std::function& passTriangleFunc); -#endif -}; diff --git a/src/DrawComponents/DrawImage.cpp b/src/DrawComponents/DrawImage.cpp deleted file mode 100644 index fd38f79..0000000 --- a/src/DrawComponents/DrawImage.cpp +++ /dev/null @@ -1,136 +0,0 @@ -#include "DrawImage.hpp" -#include "Helpers/ConvertVec.hpp" -#include "Helpers/MathExtras.hpp" -#include "Helpers/SCollision.hpp" -#include "../SharedTypes.hpp" -#include "../World.hpp" - -#include "../MainProgram.hpp" - -#ifndef IS_SERVER -#include -#include "../DrawCollision.hpp" -#endif - -DrawComponentType DrawImage::get_type() const { - return DRAWCOMPONENT_IMAGE; -} - -void DrawImage::save(cereal::PortableBinaryOutputArchive& a) const { - a(d.p1, d.p2, d.imageID); -} - -void DrawImage::load(cereal::PortableBinaryInputArchive& a) { - a(d.p1, d.p2, d.imageID); -} - -void DrawImage::save_file(cereal::PortableBinaryOutputArchive& a) const { - a(d.p1, d.p2, d.imageID); -} - -void DrawImage::load_file(cereal::PortableBinaryInputArchive& a, VersionNumber version) { - a(d.p1, d.p2, d.imageID); -} - -void DrawImage::get_used_resources(std::unordered_set& v) const { - v.emplace(d.imageID); -} - -void DrawImage::remap_resource_ids(std::unordered_map& newIDs) { - auto it = newIDs.find(d.imageID); - if(it != newIDs.end()) - d.imageID = it->second; -} - -#ifndef IS_SERVER -std::shared_ptr DrawImage::copy(DrawingProgram& drawP) const { - auto a = std::make_shared(); - a->d = d; - a->coords = coords; - return a; -} - -std::shared_ptr DrawImage::deep_copy(DrawingProgram& drawP) const { - auto a = std::make_shared(); - a->d = d; - a->coords = coords; - a->imRect = imRect; - a->collisionTree = collisionTree; - return a; -} - -void DrawImage::update_from_delayed_ptr(const std::shared_ptr& delayedUpdatePtr) { - std::shared_ptr newPtr = std::static_pointer_cast(delayedUpdatePtr); - d = newPtr->d; -} - -void DrawImage::draw_download_progress_bar(SkCanvas* canvas, const DrawData& drawData, float progress) { - if(progress == 0.0f) - return; - calculate_draw_transform(drawData); - if(drawSetupData.shouldDraw) { - canvas->save(); - canvas_do_calculated_transform(canvas); - SkPaint p; - p.setStroke(true); - p.setStrokeWidth(10.0f); - p.setStrokeCap(SkPaint::kRound_Cap); - p.setColor4f(drawData.main->toolbar.io->theme->fillColor1); - Vector2f center = convert_vec2(imRect.center()); - - const float DOWNLOAD_ARC_RADIUS = 50.0f; - canvas->drawArc(SkRect::MakeLTRB(center.x() - DOWNLOAD_ARC_RADIUS, center.y() - DOWNLOAD_ARC_RADIUS, center.x() + DOWNLOAD_ARC_RADIUS, center.y() + DOWNLOAD_ARC_RADIUS), 0.0f, progress * 360.0f, false, p); - canvas->restore(); - drawSetupData.shouldDraw = false; - } -} - -void DrawImage::draw(SkCanvas* canvas, const DrawData& drawData) { - if(drawSetupData.shouldDraw) { - canvas->save(); - canvas_do_calculated_transform(canvas); - ResourceDisplay* display = drawData.rMan->get_display_data(d.imageID); - if(display) - display->draw(canvas, drawData, imRect); - else - canvas->drawRect(imRect, SkPaint({0.5f, 0.5f, 0.5f, 0.5f})); - canvas->restore(); - } -} - -void DrawImage::update(DrawingProgram& drawP) { - ResourceDisplay* display = drawP.world.drawData.rMan->get_display_data(d.imageID); - if(display) { - if(display->update_draw() && collabListInfo.lock()) - drawP.invalidate_cache_at_component(collabListInfo.lock()); - } -} - -void DrawImage::initialize_draw_data(DrawingProgram& drawP) { - create_draw_data(); - create_collider(); -} - -bool DrawImage::collides_within_coords(const SCollision::ColliderCollection& checkAgainst) { - return collisionTree.is_collide(checkAgainst); -} - -void DrawImage::create_draw_data() { - imRect = SkRect::MakeLTRB(d.p1.x(), d.p1.y(), d.p2.x(), d.p2.y()); -} - -void DrawImage::create_collider() { - using namespace SCollision; - ColliderCollection strokeObjects; - std::array newT = triangle_from_rect_points(d.p1, d.p2); - strokeObjects.triangle.emplace_back(newT[0], newT[1], newT[2]); - strokeObjects.triangle.emplace_back(newT[2], newT[3], newT[0]); - collisionTree.clear(); - collisionTree.calculate_bvh_recursive(strokeObjects); -} - -SCollision::AABB DrawImage::get_obj_coord_bounds() const { - return collisionTree.objects.bounds; -} - -#endif diff --git a/src/DrawComponents/DrawImage.hpp b/src/DrawComponents/DrawImage.hpp deleted file mode 100644 index 8429845..0000000 --- a/src/DrawComponents/DrawImage.hpp +++ /dev/null @@ -1,49 +0,0 @@ -#pragma once -#include "../SharedTypes.hpp" -#include "DrawComponent.hpp" -#include "../CoordSpaceHelper.hpp" - -#ifndef IS_SERVER -#include -#endif - -class DrawImage : public DrawComponent { - public: - virtual void save(cereal::PortableBinaryOutputArchive& a) const override; - virtual void load(cereal::PortableBinaryInputArchive& a) override; - virtual void save_file(cereal::PortableBinaryOutputArchive& a) const override; - virtual void load_file(cereal::PortableBinaryInputArchive& a, VersionNumber version) override; - virtual DrawComponentType get_type() const override; - virtual void get_used_resources(std::unordered_set& v) const override; - virtual void remap_resource_ids(std::unordered_map& newIDs) override; - - void draw_download_progress_bar(SkCanvas* canvas, const DrawData& drawData, float progress); - - // User input data - struct Data { - Vector2f p1; - Vector2f p2; - - ServerClientID imageID; - } d; - -#ifndef IS_SERVER - virtual std::shared_ptr copy(DrawingProgram& drawP) const override; - virtual std::shared_ptr deep_copy(DrawingProgram& drawP) const override; - - virtual void draw(SkCanvas* canvas, const DrawData& drawData) override; - virtual void initialize_draw_data(DrawingProgram& drawP) override; - virtual void update(DrawingProgram& drawP) override; - virtual bool collides_within_coords(const SCollision::ColliderCollection& checkAgainst) override; - void create_draw_data(); - void create_collider(); - virtual void update_from_delayed_ptr(const std::shared_ptr& delayedUpdatePtr) override; - - virtual SCollision::AABB get_obj_coord_bounds() const override; - - SkRect imRect; - - SCollision::BVHContainer collisionTree; -#endif -}; - diff --git a/src/DrawComponents/DrawRectangle.cpp b/src/DrawComponents/DrawRectangle.cpp deleted file mode 100644 index b0ec6e7..0000000 --- a/src/DrawComponents/DrawRectangle.cpp +++ /dev/null @@ -1,138 +0,0 @@ -#include "DrawRectangle.hpp" -#include "Helpers/ConvertVec.hpp" -#include "Helpers/MathExtras.hpp" -#include "Helpers/SCollision.hpp" -#include -#include -#include "../SharedTypes.hpp" - -#ifndef IS_SERVER -#include "../DrawCollision.hpp" -#endif - -DrawComponentType DrawRectangle::get_type() const { - return DRAWCOMPONENT_RECTANGLE; -} - -void DrawRectangle::save(cereal::PortableBinaryOutputArchive& a) const { - a(d.strokeColor, d.fillColor, d.cornerRadius, d.strokeWidth, d.p1, d.p2, d.fillStrokeMode); -} - -void DrawRectangle::load(cereal::PortableBinaryInputArchive& a) { - a(d.strokeColor, d.fillColor, d.cornerRadius, d.strokeWidth, d.p1, d.p2, d.fillStrokeMode); -} - -void DrawRectangle::save_file(cereal::PortableBinaryOutputArchive& a) const { - a(d.strokeColor, d.fillColor, d.cornerRadius, d.strokeWidth, d.p1, d.p2, d.fillStrokeMode); -} - -void DrawRectangle::load_file(cereal::PortableBinaryInputArchive& a, VersionNumber version) { - a(d.strokeColor, d.fillColor, d.cornerRadius, d.strokeWidth, d.p1, d.p2, d.fillStrokeMode); -} - -#ifndef IS_SERVER -std::shared_ptr DrawRectangle::copy(DrawingProgram& drawP) const { - auto a = std::make_shared(); - a->d = d; - a->coords = coords; - return a; -} - -std::shared_ptr DrawRectangle::deep_copy(DrawingProgram& drawP) const { - auto a = std::make_shared(); - a->d = d; - a->coords = coords; - a->rectPath = rectPath; - a->collisionTree = collisionTree; - return a; -} - -void DrawRectangle::update_from_delayed_ptr(const std::shared_ptr& delayedUpdatePtr) { - std::shared_ptr newPtr = std::static_pointer_cast(delayedUpdatePtr); - d = newPtr->d; -} - -void DrawRectangle::draw(SkCanvas* canvas, const DrawData& drawData) { - if(drawSetupData.shouldDraw) { - canvas->save(); - canvas_do_calculated_transform(canvas); - if(d.fillStrokeMode == 0 || d.fillStrokeMode == 2) { - SkPaint p; - p.setStyle(SkPaint::kFill_Style); - p.setStrokeCap(SkPaint::kRound_Cap); - p.setColor4f(convert_vec4(d.fillColor)); - canvas->drawPath(rectPath, p); - } - if(d.fillStrokeMode == 1 || d.fillStrokeMode == 2) { - SkPaint p; - p.setStyle(SkPaint::kStroke_Style); - p.setStrokeCap(SkPaint::kRound_Cap); - p.setColor4f(convert_vec4(d.strokeColor)); - p.setStrokeWidth(d.strokeWidth); - canvas->drawPath(rectPath, p); - } - canvas->restore(); - } -} - -void DrawRectangle::update(DrawingProgram& drawP) { -} - -void DrawRectangle::initialize_draw_data(DrawingProgram& drawP) { - create_draw_data(); - create_collider(); -} - -bool DrawRectangle::collides_within_coords(const SCollision::ColliderCollection& checkAgainst) { - return collisionTree.is_collide(checkAgainst); -} - -void DrawRectangle::create_draw_data() { - SkPathBuilder rectPathBuilder; - if(d.p1.x() == d.p2.x() || d.p1.y() == d.p2.y()) { - rectPathBuilder.moveTo(convert_vec2(d.p1)); - rectPathBuilder.lineTo(convert_vec2(d.p2)); - rectPath = rectPathBuilder.detach(); - } - else { - SkRRect newRect = SkRRect::MakeRectXY(SkRect::MakeLTRB(d.p1.x(), d.p1.y(), d.p2.x(), d.p2.y()), d.cornerRadius, d.cornerRadius); - rectPathBuilder.addRRect(newRect); - rectPath = rectPathBuilder.detach(); - } -} - -void DrawRectangle::create_collider() { - using namespace SCollision; - ColliderCollection strokeObjects; - if(d.fillStrokeMode == 0) { - std::array newT = triangle_from_rect_points(d.p1, d.p2); - strokeObjects.triangle.emplace_back(newT[0], newT[1], newT[2]); - strokeObjects.triangle.emplace_back(newT[2], newT[3], newT[0]); - } - else if(d.fillStrokeMode == 1) { - if(d.p1.x() == d.p2.x() || d.p1.y() == d.p2.y()) { - std::vector points = {d.p1, d.p2}; - generate_polyline(strokeObjects, points, d.strokeWidth, true); - } - else { - std::array pointArr = triangle_from_rect_points(d.p1, d.p2); - std::vector points(pointArr.begin(), pointArr.end()); - generate_polyline(strokeObjects, points, d.strokeWidth, true); - } - } - else if(d.fillStrokeMode == 2) { - float strokeRadius = d.strokeWidth * 0.5f; - std::array newT = triangle_from_rect_points((d.p1 - Vector2f{strokeRadius, strokeRadius}).eval(), (d.p2 + Vector2f{strokeRadius, strokeRadius}).eval()); - strokeObjects.triangle.emplace_back(newT[0], newT[1], newT[2]); - strokeObjects.triangle.emplace_back(newT[2], newT[3], newT[0]); - } - - collisionTree.clear(); - collisionTree.calculate_bvh_recursive(strokeObjects); -} - -SCollision::AABB DrawRectangle::get_obj_coord_bounds() const { - return collisionTree.objects.bounds; -} - -#endif diff --git a/src/DrawComponents/DrawRectangle.hpp b/src/DrawComponents/DrawRectangle.hpp deleted file mode 100644 index 32d5aff..0000000 --- a/src/DrawComponents/DrawRectangle.hpp +++ /dev/null @@ -1,49 +0,0 @@ -#pragma once -#include "../SharedTypes.hpp" -#include "DrawComponent.hpp" -#include "../CoordSpaceHelper.hpp" - -#ifndef IS_SERVER -#include -#endif - -class DrawRectangle : public DrawComponent { - public: - virtual void save(cereal::PortableBinaryOutputArchive& a) const override; - virtual void load(cereal::PortableBinaryInputArchive& a) override; - virtual void save_file(cereal::PortableBinaryOutputArchive& a) const override; - virtual void load_file(cereal::PortableBinaryInputArchive& a, VersionNumber version) override; - virtual DrawComponentType get_type() const override; - - // User input data - struct Data { - Vector4f strokeColor; - Vector4f fillColor; - float cornerRadius; - float strokeWidth; - Vector2f p1; - Vector2f p2; - uint8_t fillStrokeMode; - bool operator==(const Data& o) const = default; - } d; - -#ifndef IS_SERVER - virtual std::shared_ptr copy(DrawingProgram& drawP) const override; - virtual std::shared_ptr deep_copy(DrawingProgram& drawP) const override; - - virtual void draw(SkCanvas* canvas, const DrawData& drawData) override; - virtual void initialize_draw_data(DrawingProgram& drawP) override; - virtual void update(DrawingProgram& drawP) override; - virtual bool collides_within_coords(const SCollision::ColliderCollection& checkAgainst) override; - void create_draw_data(); - void create_collider(); - virtual void update_from_delayed_ptr(const std::shared_ptr& delayedUpdatePtr) override; - - virtual SCollision::AABB get_obj_coord_bounds() const override; - - SkPath rectPath; - - SCollision::BVHContainer collisionTree; -#endif -}; - diff --git a/src/DrawComponents/DrawTextBox.cpp b/src/DrawComponents/DrawTextBox.cpp deleted file mode 100644 index ab567d6..0000000 --- a/src/DrawComponents/DrawTextBox.cpp +++ /dev/null @@ -1,152 +0,0 @@ -#include "DrawTextBox.hpp" -#include "Helpers/ConvertVec.hpp" -#include - -#ifndef IS_SERVER -#include "../MainProgram.hpp" -#include "Helpers/SCollision.hpp" -#include "../DrawingProgram/DrawingProgram.hpp" -#include "../DrawCollision.hpp" -#endif - -using namespace RichText; - -DrawTextBox::DrawTextBox(): - textBox(std::make_shared()), - cursor(std::make_shared()) -{ - skia::textlayout::TextStyle tStyle; - textBox->set_initial_text_style(tStyle); - - textBox->set_initial_text_style_modifier(std::make_shared(Vector4f{1.0f, 1.0f, 1.0f, 1.0f})); - textBox->set_initial_text_style_modifier(std::make_shared(18.0f)); - textBox->set_initial_text_style_modifier(std::make_shared(std::vector{SkString{"Roboto"}})); -} - -DrawComponentType DrawTextBox::get_type() const { - return DRAWCOMPONENT_TEXTBOX; -} - -void DrawTextBox::save(cereal::PortableBinaryOutputArchive& a) const { - a(d.editing, d.p1, d.p2, textBox->get_rich_text_data(), *cursor); -} - -void DrawTextBox::load(cereal::PortableBinaryInputArchive& a) { - TextData richText; - a(d.editing, d.p1, d.p2, richText, *cursor); - textBox->set_rich_text_data(richText); -} - -void DrawTextBox::save_file(cereal::PortableBinaryOutputArchive& a) const { - a(d.p1, d.p2, textBox->get_rich_text_data()); -} - -void DrawTextBox::load_file(cereal::PortableBinaryInputArchive& a, VersionNumber version) { - if(version < VersionNumber(0, 3, 0)) { - bool loadedEditing; // Unused - Vector4f textColor; - float textSize; - RichText::TextBox::Cursor loadedCursor; // Unused, Equivalent to old cursor structure, just paragraph index and text index flipped - std::string currentText; - a(loadedEditing, d.p1, d.p2, textColor, textSize, loadedCursor, currentText); - textBox->insert({0, 0}, currentText); - textBox->set_text_style_modifier_between({0, 0}, textBox->move(RichText::TextBox::Movement::END, {0, 0}), std::make_shared(textColor)); - textBox->set_text_style_modifier_between({0, 0}, textBox->move(RichText::TextBox::Movement::END, {0, 0}), std::make_shared(textSize)); - } - else { - TextData richText; - a(d.p1, d.p2, richText); - textBox->set_rich_text_data(richText); - } -} - -#ifndef IS_SERVER -std::shared_ptr DrawTextBox::copy(DrawingProgram& drawP) const { - auto a = std::make_shared(); - a->d = d; - *a->cursor = *cursor; - a->coords = coords; - a->textBox->set_rich_text_data(textBox->get_rich_text_data()); - a->init_text_box(drawP); - return a; -} - -std::shared_ptr DrawTextBox::deep_copy(DrawingProgram& drawP) const { - auto a = std::make_shared(); - a->d = d; - *a->cursor = *cursor; - a->coords = coords; - a->textBox->set_rich_text_data(textBox->get_rich_text_data()); - a->collisionTree = collisionTree; - a->init_text_box(drawP); - return a; -} - -void DrawTextBox::update_from_delayed_ptr(const std::shared_ptr& delayedUpdatePtr) { - std::shared_ptr newPtr = std::static_pointer_cast(delayedUpdatePtr); - d = newPtr->d; - *cursor = *newPtr->cursor; - textBox->set_rich_text_data(newPtr->textBox->get_rich_text_data()); -} - -void DrawTextBox::init_text_box(DrawingProgram& drawP) { - textBox->set_font_data(drawP.world.main.fonts); // Getting a segfault relating to the paragraph cache means that the font collection hasn't been set yet - textBox->set_width(d.p2.x() - d.p1.x() - TEXTBOX_PADDING * 2.0f); -} - -void DrawTextBox::draw(SkCanvas* canvas, const DrawData& drawData) { - if(drawSetupData.shouldDraw) { - canvas->save(); - canvas_do_calculated_transform(canvas); - SkRect clipR = SkRect::MakeLTRB(d.p1.x(), d.p1.y(), d.p2.x(), d.p2.y()); - if(d.editing) { - SkPaint p; - p.setStyle(SkPaint::kStroke_Style); - p.setStrokeWidth(0.0f); - p.setColor4f({0.5f, 0.5f, 0.5f, 1.0f}); - canvas->drawRect(clipR, p); - } - canvas->clipRect(clipR); - canvas->translate(d.p1.x() + TEXTBOX_PADDING, d.p1.y() + TEXTBOX_PADDING); - - TextBox::PaintOpts paintOpts; - paintOpts.cursorColor = {0.7f, 0.7f, 1.0f}; - if(d.editing && cursor) - paintOpts.cursor = *cursor; - - textBox->paint(canvas, paintOpts); - canvas->restore(); - } -} - -void DrawTextBox::update(DrawingProgram& drawP) { -} - -Vector2f DrawTextBox::get_mouse_pos(DrawingProgram& drawP) { - return coords.get_mouse_pos(drawP.world) - d.p1 - Vector2f{TEXTBOX_PADDING, TEXTBOX_PADDING}; -} - -void DrawTextBox::initialize_draw_data(DrawingProgram& drawP) { - init_text_box(drawP); - create_collider(); -} - -bool DrawTextBox::collides_within_coords(const SCollision::ColliderCollection& checkAgainst) { - return collisionTree.is_collide(checkAgainst); -} - -void DrawTextBox::create_collider() { - using namespace SCollision; - ColliderCollection strokeObjects; - std::array newT = triangle_from_rect_points(d.p1, d.p2); - strokeObjects.triangle.emplace_back(newT[0], newT[1], newT[2]); - strokeObjects.triangle.emplace_back(newT[2], newT[3], newT[0]); - collisionTree.clear(); - collisionTree.calculate_bvh_recursive(strokeObjects); -} - -SCollision::AABB DrawTextBox::get_obj_coord_bounds() const { - return collisionTree.objects.bounds; -} - -#endif diff --git a/src/DrawComponents/DrawTextBox.hpp b/src/DrawComponents/DrawTextBox.hpp deleted file mode 100644 index 7cd7f68..0000000 --- a/src/DrawComponents/DrawTextBox.hpp +++ /dev/null @@ -1,50 +0,0 @@ -#pragma once -#include "../SharedTypes.hpp" -#include "DrawComponent.hpp" -#include "../CoordSpaceHelper.hpp" -#include "../RichText/TextBox.hpp" - -#ifndef IS_SERVER - #include -#endif - -class DrawTextBox : public DrawComponent { - public: - constexpr static float TEXTBOX_PADDING = 5.0f; - - DrawTextBox(); - virtual DrawComponentType get_type() const override; - virtual void save(cereal::PortableBinaryOutputArchive& a) const override; - virtual void load(cereal::PortableBinaryInputArchive& a) override; - virtual void save_file(cereal::PortableBinaryOutputArchive& a) const override; - virtual void load_file(cereal::PortableBinaryInputArchive& a, VersionNumber version) override; - - // User input data - struct Data { - Vector2f p1; - Vector2f p2; - bool editing = false; // Should probably move this out of the Data struct - bool operator==(const Data& o) const = default; - bool operator!=(const Data& o) const = default; - } d; - -#ifndef IS_SERVER - virtual std::shared_ptr copy(DrawingProgram& drawP) const override; - virtual std::shared_ptr deep_copy(DrawingProgram& drawP) const override; - - virtual void draw(SkCanvas* canvas, const DrawData& drawData) override; - virtual void initialize_draw_data(DrawingProgram& drawP) override; - virtual bool collides_within_coords(const SCollision::ColliderCollection& checkAgainst) override; - virtual void update(DrawingProgram& drawP) override; - void create_collider(); - virtual void update_from_delayed_ptr(const std::shared_ptr& delayedUpdatePtr) override; - void init_text_box(DrawingProgram& drawP); - Vector2f get_mouse_pos(DrawingProgram& drawP); - - virtual SCollision::AABB get_obj_coord_bounds() const override; - - std::shared_ptr textBox; - std::shared_ptr cursor; - SCollision::BVHContainer collisionTree; -#endif -}; diff --git a/src/DrawingProgram/BrushTool.cpp b/src/DrawingProgram/BrushTool.cpp index 681dabe..36cb448 100644 --- a/src/DrawingProgram/BrushTool.cpp +++ b/src/DrawingProgram/BrushTool.cpp @@ -1,10 +1,12 @@ #include "BrushTool.hpp" #include -#include "../DrawComponents/DrawBrushStroke.hpp" #include "../GUIStuff/GUIManager.hpp" #include "DrawingProgram.hpp" #include "../MainProgram.hpp" #include "DrawingProgramToolBase.hpp" +#include "../CanvasComponents/BrushStrokeCanvasComponent.hpp" +#include "Helpers/NetworkingObjects/NetObjTemporaryPtr.decl.hpp" +#include "Helpers/NetworkingObjects/NetObjWeakPtr.hpp" #include #define VEL_SMOOTH_MIN 0.6 @@ -23,8 +25,8 @@ void BrushTool::switch_tool(DrawingProgramToolType newTool) { commit_stroke(); } -bool BrushTool::extensive_point_checking(const Vector2f& newPoint) { - auto& points = controls.intermediateItem->d->points; +bool BrushTool::extensive_point_checking(const BrushStrokeCanvasComponent& brushStroke, const Vector2f& newPoint) { + auto& points = brushStroke.d->points; if(points.size() >= 1 && (newPoint - points[points.size() - 1].pos).norm() < MINIMUM_DISTANCE_TO_NEXT_POINT) return false; if(points.size() >= 2 && (newPoint - points[points.size() - 2].pos).norm() < MINIMUM_DISTANCE_TO_NEXT_POINT) @@ -34,8 +36,8 @@ bool BrushTool::extensive_point_checking(const Vector2f& newPoint) { return true; } -bool BrushTool::extensive_point_checking_back(const Vector2f& newPoint) { - auto& points = controls.intermediateItem->d->points; +bool BrushTool::extensive_point_checking_back(const BrushStrokeCanvasComponent& brushStroke, const Vector2f& newPoint) { + auto& points = brushStroke.d->points; if(points.size() >= 2 && (newPoint - points[points.size() - 2].pos).norm() < MINIMUM_DISTANCE_TO_NEXT_POINT) return false; if(points.size() >= 3 && (newPoint - points[points.size() - 3].pos).norm() < MINIMUM_DISTANCE_TO_NEXT_POINT) @@ -49,107 +51,117 @@ void BrushTool::tool_update() { if(drawP.controls.cursorHoveringOverCanvas) drawP.world.main.input.hideCursor = true; - if(!controls.isDrawing) - controls.penSmoothingData.clear(); + if(!isDrawing) + penSmoothingData.clear(); if(drawP.world.main.input.pen.isDown && drawP.controls.leftClickHeld && drawP.world.main.toolbar.tabletOptions.pressureAffectsBrushWidth) { - while(!controls.penSmoothingData.empty() && (std::chrono::steady_clock::now() - controls.penSmoothingData.front().t) > std::chrono::milliseconds(static_cast(drawP.world.main.toolbar.tabletOptions.smoothingSamplingTime * 1000.0f))) - controls.penSmoothingData.pop_front(); - controls.penSmoothingData.emplace_back( + while(!penSmoothingData.empty() && (std::chrono::steady_clock::now() - penSmoothingData.front().t) > std::chrono::milliseconds(static_cast(drawP.world.main.toolbar.tabletOptions.smoothingSamplingTime * 1000.0f))) + penSmoothingData.pop_front(); + penSmoothingData.emplace_back( drawP.world.main.input.pen.pressure, std::chrono::steady_clock::now() ); float averagePressure = 0.0f; - for(auto& [width, t] : controls.penSmoothingData) + for(auto& [width, t] : penSmoothingData) averagePressure += width; - averagePressure /= controls.penSmoothingData.size(); - controls.penWidth = averagePressure; - if(controls.penWidth != 0.0f) { + averagePressure /= penSmoothingData.size(); + penWidth = averagePressure; + if(penWidth != 0.0f) { float brushMinSize = drawP.world.main.toolbar.tabletOptions.brushMinimumSize; - controls.penWidth = brushMinSize + controls.penWidth * (1.0f - brushMinSize); + penWidth = brushMinSize + penWidth * (1.0f - brushMinSize); } } else - controls.penWidth = 1.0f; + penWidth = 1.0f; bool isPenDown = false; if(drawP.world.main.input.pen.isDown && drawP.controls.leftClickHeld) - isPenDown = controls.penWidth != 0.0; + isPenDown = penWidth != 0.0; else if(drawP.controls.leftClickHeld) isPenDown = true; if(isPenDown) { - if(!controls.isDrawing) { - controls.isDrawing = true; - controls.intermediateItem = std::make_shared(); - DrawBrushStrokePoint p; + if(!isDrawing) { + isDrawing = true; + CanvasComponentContainer* newBrushStrokeContainer = new CanvasComponentContainer(drawP.world.netObjMan, CanvasComponent::CompType::BRUSHSTROKE); + BrushStrokeCanvasComponent& newBrushStroke = static_cast(newBrushStrokeContainer->get_comp()); + + BrushStrokeCanvasComponentPoint p; p.pos = drawP.world.main.input.mouse.pos; - p.width = drawP.controls.relativeWidth * controls.penWidth; - controls.prevPointUnaltered = p.pos; - controls.intermediateItem->d->points.emplace_back(p); - controls.intermediateItem->d->color = drawP.controls.foregroundColor; - controls.intermediateItem->d->hasRoundCaps = controls.hasRoundCaps; - controls.intermediateItem->coords = drawP.world.drawData.cam.c; - controls.intermediateItem->lastUpdateTime = std::chrono::steady_clock::now(); - uint64_t placement = drawP.components.client_list().size(); - auto objAdd = drawP.components.client_insert(placement, controls.intermediateItem); - controls.intermediateItem->commit_update(drawP); - controls.intermediateItem->client_send_place(drawP); - // NOTE: The data isnt finallized at this point, so a BVH isn't generated for an object that you undo while youre drawing (this isnt just for brush strokes) - // The fix for now is to generate a BVH for an object when you redo it - drawP.add_undo_place_component(objAdd); - controls.addedTemporaryPoint = false; + p.width = drawP.controls.relativeWidth * penWidth; + prevPointUnaltered = p.pos; + newBrushStroke.d->points.emplace_back(p); + newBrushStroke.d->color = drawP.controls.foregroundColor; + newBrushStroke.d->hasRoundCaps = hasRoundCaps; + newBrushStrokeContainer->coords = drawP.world.drawData.cam.c; + intermediateContainer = drawP.components->push_back_and_send_create(drawP.components, newBrushStrokeContainer)->obj; + addedTemporaryPoint = false; } else { - controls.intermediateItem->lastUpdateTime = std::chrono::steady_clock::now(); + NetworkingObjects::NetObjTemporaryPtr containerPtr = intermediateContainer.lock(); + if(!containerPtr) { + isDrawing = false; + intermediateContainer.reset(); + return; + } + BrushStrokeCanvasComponent& brushStroke = static_cast(containerPtr->get_comp()); - DrawBrushStrokePoint p; - p.pos = controls.intermediateItem->coords.get_mouse_pos(drawP.world); - p.width = drawP.controls.relativeWidth * controls.penWidth; + BrushStrokeCanvasComponentPoint p; + p.pos = containerPtr->coords.get_mouse_pos(drawP.world); + p.width = drawP.controls.relativeWidth * penWidth; - if(!controls.addedTemporaryPoint) { - if(extensive_point_checking(p.pos)) { - controls.intermediateItem->d->points.emplace_back(p); - controls.addedTemporaryPoint = true; + if(!addedTemporaryPoint) { + if(extensive_point_checking(brushStroke, p.pos)) { + brushStroke.d->points.emplace_back(p); + addedTemporaryPoint = true; } else - controls.intermediateItem->d->points.back().width = std::max(controls.intermediateItem->d->points.back().width, p.width); + brushStroke.d->points.back().width = std::max(brushStroke.d->points.back().width, p.width); } - if(controls.addedTemporaryPoint) { - const DrawBrushStrokePoint& prevP = controls.intermediateItem->d->points[controls.intermediateItem->d->points.size() - 2]; + if(addedTemporaryPoint) { + const BrushStrokeCanvasComponentPoint& prevP = brushStroke.d->points[brushStroke.d->points.size() - 2]; float distToPrev = (p.pos - prevP.pos).norm(); - if(extensive_point_checking_back(p.pos)) { - controls.intermediateItem->d->points.back().pos = p.pos; - controls.intermediateItem->d->points.back().width = std::max(controls.intermediateItem->d->points.back().width, p.width); - controls.intermediateItem->d->points[controls.intermediateItem->d->points.size() - 2].width = std::max(controls.intermediateItem->d->points[controls.intermediateItem->d->points.size() - 2].width, p.width); + if(extensive_point_checking_back(brushStroke, p.pos)) { + brushStroke.d->points.back().pos = p.pos; + brushStroke.d->points.back().width = std::max(brushStroke.d->points.back().width, p.width); + brushStroke.d->points[brushStroke.d->points.size() - 2].width = std::max(brushStroke.d->points[brushStroke.d->points.size() - 2].width, p.width); } - if((!controls.drawingMinimumRelativeToSize && distToPrev >= 10.0) || (controls.drawingMinimumRelativeToSize && distToPrev >= drawP.controls.relativeWidth * DRAW_MINIMUM_LIMIT)) { - controls.intermediateItem->d->points.back() = p; - controls.addedTemporaryPoint = false; - controls.intermediateItem->client_send_update(drawP, false); + if((!drawingMinimumRelativeToSize && distToPrev >= 10.0) || (drawingMinimumRelativeToSize && distToPrev >= drawP.controls.relativeWidth * BrushStrokeCanvasComponent::DRAW_MINIMUM_LIMIT)) { + brushStroke.d->points.back() = p; + addedTemporaryPoint = false; + containerPtr->send_comp_update(drawP, true); - if(controls.midwayInterpolation) { - if(controls.intermediateItem->d->points.size() != 2) // Don't interpolate the first point - controls.intermediateItem->d->points[controls.intermediateItem->d->points.size() - 2].pos = (controls.prevPointUnaltered + p.pos) * 0.5; - controls.prevPointUnaltered = p.pos; + if(midwayInterpolation) { + if(brushStroke.d->points.size() != 2) // Don't interpolate the first point + brushStroke.d->points[brushStroke.d->points.size() - 2].pos = (prevPointUnaltered + p.pos) * 0.5; + prevPointUnaltered = p.pos; } } - controls.intermediateItem->commit_update(drawP); + containerPtr->commit_update(drawP); } } } - else if(controls.isDrawing) { - controls.isDrawing = false; + else if(isDrawing) { + isDrawing = false; commit_stroke(); } } +void BrushTool::commit_stroke() { + NetworkingObjects::NetObjTemporaryPtr lockedPtr = intermediateContainer.lock(); + if(lockedPtr) { + lockedPtr->commit_update(drawP); + lockedPtr->send_comp_update(drawP, true); + } + intermediateContainer.reset(); +} + void BrushTool::gui_toolbox() { Toolbar& t = drawP.world.main.toolbar; t.gui.push_id("brush tool"); t.gui.text_label_centered("Brush"); - t.gui.checkbox_field("hasroundcaps", "Round Caps", &controls.hasRoundCaps); + t.gui.checkbox_field("hasroundcaps", "Round Caps", &hasRoundCaps); t.gui.slider_scalar_field("relwidth", "Size", &drawP.controls.relativeWidth, 3.0f, 40.0f); t.gui.pop_id(); } @@ -161,17 +173,7 @@ bool BrushTool::right_click_popup_gui(Vector2f popupPos) { } bool BrushTool::prevent_undo_or_redo() { - return controls.intermediateItem != nullptr; -} - -void BrushTool::commit_stroke() { - if(controls.intermediateItem && controls.intermediateItem->collabListInfo.lock()) { - if(!controls.intermediateItem->d->points.empty()) { - controls.intermediateItem->client_send_update(drawP, true); - controls.intermediateItem->commit_update(drawP); - } - } - controls.intermediateItem = nullptr; + return isDrawing; } void BrushTool::draw(SkCanvas* canvas, const DrawData& drawData) { @@ -181,8 +183,8 @@ void BrushTool::draw(SkCanvas* canvas, const DrawData& drawData) { linePaint.setStroke(true); linePaint.setStrokeWidth(0.0f); float width; - if(controls.isDrawing) - width = drawP.controls.relativeWidth * controls.penWidth * 0.5f; + if(isDrawing) + width = drawP.controls.relativeWidth * penWidth * 0.5f; else width = drawP.controls.relativeWidth * 0.5f; Vector2f pos = drawData.main->input.mouse.pos; diff --git a/src/DrawingProgram/BrushTool.hpp b/src/DrawingProgram/BrushTool.hpp index 86c5848..38502b0 100644 --- a/src/DrawingProgram/BrushTool.hpp +++ b/src/DrawingProgram/BrushTool.hpp @@ -1,17 +1,17 @@ #pragma once -#include "../SharedTypes.hpp" #include "DrawingProgramToolBase.hpp" #include #include #include #include #include -#include #include +#include "../CanvasComponents/CanvasComponentContainer.hpp" +#include class DrawingProgram; -class DrawBrushStroke; struct DrawData; +class BrushStrokeCanvasComponent; class BrushTool : public DrawingProgramToolBase { public: @@ -24,24 +24,22 @@ class BrushTool : public DrawingProgramToolBase { virtual void draw(SkCanvas* canvas, const DrawData& drawData) override; virtual bool prevent_undo_or_redo() override; private: + bool extensive_point_checking_back(const BrushStrokeCanvasComponent& brushStroke, const Vector2f& newPoint); + bool extensive_point_checking(const BrushStrokeCanvasComponent& brushStroke, const Vector2f& newPoint); void commit_stroke(); - bool extensive_point_checking_back(const Vector2f& newPoint); - bool extensive_point_checking(const Vector2f& newPoint); - struct BrushToolControls { - float penWidth = 1.0f; - bool addedTemporaryPoint = false; - struct SmoothingPoint { - float val; - std::chrono::steady_clock::time_point t; - }; - std::deque penSmoothingData; + float penWidth = 1.0f; + bool addedTemporaryPoint = false; + struct SmoothingPoint { + float val; + std::chrono::steady_clock::time_point t; + }; + std::deque penSmoothingData; - std::shared_ptr intermediateItem; - bool isDrawing = false; - bool hasRoundCaps = true; - bool drawingMinimumRelativeToSize = true; - bool midwayInterpolation = true; - Vector2f prevPointUnaltered = {0, 0}; - } controls; + NetworkingObjects::NetObjWeakPtr intermediateContainer; + bool isDrawing = false; + bool hasRoundCaps = true; + bool drawingMinimumRelativeToSize = true; + bool midwayInterpolation = true; + Vector2f prevPointUnaltered = {0, 0}; }; diff --git a/src/DrawingProgram/DrawingProgram.cpp b/src/DrawingProgram/DrawingProgram.cpp index 94aa235..8ecabb9 100644 --- a/src/DrawingProgram/DrawingProgram.cpp +++ b/src/DrawingProgram/DrawingProgram.cpp @@ -3,7 +3,6 @@ #include #include #include "../DrawCamera.hpp" -#include "../DrawComponents/DrawComponent.hpp" #include "EllipseDrawTool.hpp" #include "EyeDropperTool.hpp" #include "GridModifyTool.hpp" @@ -14,13 +13,13 @@ #include #include #include -#include "../DrawComponents/DrawImage.hpp" #include #include #include "../World.hpp" #include "../MainProgram.hpp" -#include "Helpers/FileDownloader.hpp" -#include "Helpers/StringHelpers.hpp" +#include +#include +#include #include "LassoSelectTool.hpp" #include #include @@ -34,153 +33,66 @@ DrawingProgram::DrawingProgram(World& initWorld): world(initWorld), compCache(*this), - components([&](){ return world.get_new_id(); }), selection(*this) { drawTool = DrawingProgramToolBase::allocate_tool_type(*this, DrawingProgramToolType::BRUSH); +} - components.clientInsertCallback = [&](const CollabListType::ObjectInfoPtr& c) { - if(addToCompCacheOnInsert) - compCache.add_component(c); - DrawComponentType t = c->obj->get_type(); - if(t == DRAWCOMPONENT_IMAGE) - updateableComponents.emplace(c->obj); - }; - components.clientEraseCallback = [&](const CollabListType::ObjectInfoPtr& c) { +void DrawingProgram::init() { + if(world.netObjMan.is_server()) { + components = world.netObjMan.make_obj>(); + set_component_list_callbacks(); + } +} + +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(drawTool->get_type() == DrawingProgramToolType::ERASER) { + EraserTool* eraserTool = static_cast(drawTool.get()); + eraserTool->erasedComponents.erase(c); + } + }); + components->set_erase_callback([&](const CanvasComponentContainer::ObjInfoSharedPtr& c) { compCache.erase_component(c); selection.erase_component(c); - delayedUpdateComponents.erase(c->obj); - updateableComponents.erase(c->obj); - }; - components.clientInsertOrderedVectorCallback = [&](const std::vector& comps) { - for(auto& c : comps) - components.clientInsertCallback(c); - }; - components.clientServerFirstPosShiftCallback = [&](uint64_t firstShiftPos) { + }); + components->set_post_sync_callback([&]() { clear_draw_cache(); - }; + }); } void DrawingProgram::init_client_callbacks() { - world.con.client_add_recv_callback(CLIENT_UPDATE_COMPONENT, [&](cereal::PortableBinaryInputArchive& message) { - ServerClientID id; - bool isFinal; // Not actually used, but sent for debugging purposes - message(isFinal, id); - auto objPtr = components.get_item_by_id(id); - if(!objPtr) - return; - std::shared_ptr& comp = objPtr->obj; - if((std::chrono::steady_clock::now() - comp->lastUpdateTime) > CLIENT_DRAWCOMP_DELAY_TIMER_DURATION) { - delayedUpdateComponents.erase(comp); - message(*comp); - comp->commit_update(*this); - } - else { - auto delayedUpdatePtr = DrawComponent::allocate_comp_type(comp->get_type()); - message(*delayedUpdatePtr); - delayedUpdateComponents[comp] = delayedUpdatePtr; - } - }); - world.con.client_add_recv_callback(CLIENT_TRANSFORM_MANY_COMPONENTS, [&](cereal::PortableBinaryInputArchive& message) { - std::vector> transforms; - message(transforms); - if(transforms.size() >= DrawingProgramCache::MINIMUM_COMPONENTS_TO_START_REBUILD) { - std::atomic objsActuallyTransformed = 0; - parallel_loop_container(transforms, [&](auto& p) { - auto& [id, coords] = p; - auto objPtr = components.get_item_by_id(id); - if(!objPtr || selection.is_selected(objPtr)) // Whatever transformation we're doing right now will overwrite this transformation, so we can ignore this message - return; - std::shared_ptr& comp = objPtr->obj; - if(comp->coords == coords) - return; - comp->coords = coords; - objsActuallyTransformed++; - comp->commit_transform(*this, false); - }); - if(objsActuallyTransformed != 0) - force_rebuild_cache(); - } - else { - for(auto& [id, coords] : transforms) { - auto objPtr = components.get_item_by_id(id); - if(!objPtr || selection.is_selected(objPtr)) // Whatever transformation we're doing right now will overwrite this transformation, so we can ignore this message - continue; - std::shared_ptr& comp = objPtr->obj; - if(comp->coords == coords) - return; - comp->coords = coords; - comp->commit_transform(*this); - } - } - }); - world.con.client_add_recv_callback(CLIENT_PLACE_SINGLE_COMPONENT, [&](cereal::PortableBinaryInputArchive& message) { - uint64_t insertPosition; - DrawComponentType type; - message(insertPosition, type); - auto newObj = DrawComponent::allocate_comp_type(type); - message(newObj->id, newObj->coords, *newObj); - bool didntExistPreviously = components.server_insert(insertPosition, newObj); - if(didntExistPreviously) - newObj->commit_update(*this); - }); - world.con.client_add_recv_callback(CLIENT_PLACE_MANY_COMPONENTS, [&](cereal::PortableBinaryInputArchive& message) { - std::vector sortedPlacedComponents; - - SendOrderedComponentVectorOp a{&sortedPlacedComponents}; - message(a); - - std::vector didntExistPreviously = components.server_insert_ordered_vector(sortedPlacedComponents); - bool isSingleThread = sortedPlacedComponents.size() < DrawingProgramCache::MINIMUM_COMPONENTS_TO_START_REBUILD; - parallel_loop_container(sortedPlacedComponents, [&](const auto& c){ - c->obj->commit_update(*this, isSingleThread); - }, isSingleThread); - if(!isSingleThread) - force_rebuild_cache(); - }); - world.con.client_add_recv_callback(CLIENT_ERASE_SINGLE_COMPONENT, [&](cereal::PortableBinaryInputArchive& message) { - ServerClientID idToErase; - message(idToErase); - components.server_erase(idToErase); - }); - world.con.client_add_recv_callback(CLIENT_ERASE_MANY_COMPONENTS, [&](cereal::PortableBinaryInputArchive& message) { - std::unordered_set idsToErase; - message(idsToErase); - components.server_erase_set(idsToErase); - }); } void DrawingProgram::scale_up(const WorldScalar& scaleUpAmount) { - for(auto& c : components.client_list()) - c->obj->scale_up(scaleUpAmount); - selection.deselect_all(); - force_rebuild_cache(); - switch_to_tool(drawTool->get_type() == DrawingProgramToolType::GRIDMODIFY ? DrawingProgramToolType::EDIT : drawTool->get_type(), true); + //for(auto& c : components->get_data()) + // c->obj->scale_up(scaleUpAmount); + //selection.deselect_all(); + //force_rebuild_cache(); + //switch_to_tool(drawTool->get_type() == DrawingProgramToolType::GRIDMODIFY ? DrawingProgramToolType::EDIT : drawTool->get_type(), true); } -void DrawingProgram::check_delayed_update_timers() { - std::erase_if(delayedUpdateComponents, [&](auto& p) { - auto& [comp, delayedUpdatePtr] = p; - return comp->check_timers(*this, delayedUpdatePtr); - }); -} - -void DrawingProgram::check_updateable_components() { - for(auto& comp : updateableComponents) - comp->update(*this); -} - -void DrawingProgram::parallel_loop_all_components(std::function, ServerClientID>::ObjectInfo>&)> func) { - parallel_loop_container(components.client_list(), func); +void DrawingProgram::parallel_loop_all_components(std::function func) { + parallel_loop_container(components->get_data(), func); } std::unordered_set DrawingProgram::get_used_resources() const { std::unordered_set toRet; - for(auto& c : components.client_list()) - c->obj->get_used_resources(toRet); + //for(auto& c : components->get_data()) + // c->obj->get_used_resources(toRet); return toRet; } +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(); @@ -365,13 +277,6 @@ void DrawingProgram::update() { controls.previousMouseWorldPos = controls.currentMouseWorldPos; controls.currentMouseWorldPos = world.get_mouse_world_pos(); - if(addFileInNextFrame) { - add_file_to_canvas_by_path_execute(addFileInfo.first, addFileInfo.second); - addFileInNextFrame = false; - } - - drag_drop_update(); - if(world.main.input.key(InputManager::KEY_DRAW_TOOL_BRUSH).pressed) switch_to_tool(DrawingProgramToolType::BRUSH); else if(world.main.input.key(InputManager::KEY_DRAW_TOOL_ERASER).pressed) @@ -406,18 +311,14 @@ void DrawingProgram::update() { if(controls.leftClickReleased) controls.leftClickReleased = false; - check_delayed_update_timers(); - check_updateable_components(); - update_downloading_dropped_files(); - if(drawTool->get_type() == DrawingProgramToolType::ERASER) { EraserTool* eraserTool = static_cast(drawTool.get()); - compCache.test_rebuild_dont_include_set_dont_include_nodes(components.client_list(), eraserTool->erasedComponents, eraserTool->erasedBVHNodes); + 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.client_list(), selection.get_selected_set()); + compCache.test_rebuild_dont_include_set(components->get_data(), selection.get_selected_set()); else - compCache.test_rebuild(components.client_list()); + compCache.test_rebuild(components->get_data()); } bool DrawingProgram::is_actual_selection_tool(DrawingProgramToolType typeToCheck) { @@ -463,287 +364,28 @@ SkPaint DrawingProgram::select_tool_line_paint() { void DrawingProgram::force_rebuild_cache() { if(drawTool->get_type() == DrawingProgramToolType::ERASER) { EraserTool* eraserTool = static_cast(drawTool.get()); - compCache.test_rebuild_dont_include_set_dont_include_nodes(components.client_list(), eraserTool->erasedComponents, eraserTool->erasedBVHNodes, true); + compCache.test_rebuild_dont_include_set_dont_include_nodes(components->get_data(), eraserTool->erasedComponents, eraserTool->erasedBVHNodes, true); } else if(is_selection_allowing_tool(drawTool->get_type())) - compCache.test_rebuild_dont_include_set(components.client_list(), selection.get_selected_set(), true); + compCache.test_rebuild_dont_include_set(components->get_data(), selection.get_selected_set(), true); else - compCache.test_rebuild(components.client_list(), true); + compCache.test_rebuild(components->get_data(), true); } -void DrawingProgram::drag_drop_update() { - if(controls.cursorHoveringOverCanvas) { - for(auto& droppedItem : world.main.input.droppedItems) { - if(droppedItem.dataPath.has_value() && std::filesystem::is_regular_file(droppedItem.dataPath.value())) { -#ifdef __EMSCRIPTEN_ - add_file_to_canvas_by_path(droppedItem.dataPath.value(), world.main.input.mouse.pos, true); -#else - add_file_to_canvas_by_path(droppedItem.dataPath.value(), droppedItem.pos, true); -#endif - } - else if(droppedItem.dataText.has_value() && is_valid_http_url(droppedItem.dataText.value())) { - auto img(std::make_shared()); - img->coords = world.drawData.cam.c; - Vector2f imDim = Vector2f{100.0f, 100.0f}; - img->d.p1 = droppedItem.pos - imDim; - img->d.p2 = droppedItem.pos + imDim; - img->d.imageID = {0, 0}; - img->commit_update(*this); - uint64_t placement = components.client_list().size(); - auto objAdd = components.client_insert(placement, img); - img->client_send_place(*this); - add_undo_place_component(objAdd); - droppedDownloadingFiles.emplace_back(objAdd, world.main.window.size.cast(), FileDownloader::download_data_from_url(droppedItem.dataText.value())); - } - } - } -} - -void DrawingProgram::update_downloading_dropped_files() { - std::erase_if(droppedDownloadingFiles, [&](auto& downFile) { - switch(downFile.downData->status) { - case FileDownloader::DownloadData::Status::SUCCESS: { - std::shared_ptr img = std::static_pointer_cast(downFile.comp->obj); - Vector2f dropPos = (img->d.p1 + img->d.p2) * 0.5f; - - ResourceData newResource; - newResource.data = std::make_shared(downFile.downData->str); - newResource.name = downFile.downData->fileName; - ServerClientID imageID = world.rMan.add_resource(newResource); - 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"); - client_erase_set({downFile.comp}); - } - else { - Vector2f imTrueDim = display->get_dimensions(); - - float imWidth = imTrueDim.x() / (imTrueDim.x() + imTrueDim.y()); - float imHeight = imTrueDim.y() / (imTrueDim.x() + imTrueDim.y()); - Vector2f imDim = Vector2f{downFile.windowSizeWhenDropped.x() * imWidth, downFile.windowSizeWhenDropped.x() * imHeight} * display->get_dimension_scale(); - img->d.p1 = dropPos - imDim; - img->d.p2 = dropPos + imDim; - img->d.imageID = imageID; - img->commit_update(*this); - img->client_send_update(*this, true); - } - return true; - } - case FileDownloader::DownloadData::Status::FAILURE: - Logger::get().log("WORLDFATAL", "Failed to download data from URL"); - client_erase_set({downFile.comp}); - return true; - case FileDownloader::DownloadData::Status::IN_PROGRESS: - return false; - } - return false; - }); -} - -void DrawingProgram::add_file_to_canvas_by_path(const std::filesystem::path& filePath, Vector2f dropPos, bool addInSameThread) { - if(addInSameThread) - add_file_to_canvas_by_path_execute(filePath, dropPos); - else if(!addFileInNextFrame) { - addFileInfo = {filePath, dropPos}; - addFileInNextFrame = true; - } -} - -void DrawingProgram::add_file_to_canvas_by_path_execute(const std::filesystem::path& filePath, Vector2f dropPos) { - ServerClientID imageID = world.rMan.add_resource_file(filePath); - if(imageID != ServerClientID{0, 0}) { - ResourceDisplay* display = world.rMan.get_display_data(imageID); - Vector2f imTrueDim = display->get_dimensions(); - auto img(std::make_shared()); - img->coords = world.drawData.cam.c; - float imWidth = imTrueDim.x() / (imTrueDim.x() + imTrueDim.y()); - float imHeight = imTrueDim.y() / (imTrueDim.x() + imTrueDim.y()); - Vector2f imDim = Vector2f{world.main.window.size.x() * imWidth, world.main.window.size.x() * imHeight} * display->get_dimension_scale(); - img->d.p1 = dropPos - imDim; - img->d.p2 = dropPos + imDim; - img->d.imageID = imageID; - img->commit_update(*this); - uint64_t placement = components.client_list().size(); - auto objAdd = components.client_insert(placement, img); - img->client_send_place(*this); - add_undo_place_component(objAdd); - } -} - -void DrawingProgram::add_file_to_canvas_by_data(const std::string& fileName, std::string_view fileBuffer, Vector2f dropPos) { - ResourceData newResource; - newResource.data = std::make_shared(fileBuffer); - newResource.name = fileName; - ServerClientID imageID = world.rMan.add_resource(newResource); - - ResourceDisplay* display = world.rMan.get_display_data(imageID); - Vector2f imTrueDim = display->get_dimensions(); - auto img(std::make_shared()); - img->coords = world.drawData.cam.c; - float imWidth = imTrueDim.x() / (imTrueDim.x() + imTrueDim.y()); - float imHeight = imTrueDim.y() / (imTrueDim.x() + imTrueDim.y()); - Vector2f imDim = Vector2f{world.main.window.size.x() * imWidth, world.main.window.size.x() * imHeight} * display->get_dimension_scale(); - img->d.p1 = dropPos - imDim; - img->d.p2 = dropPos + imDim; - img->d.imageID = imageID; - img->commit_update(*this); - uint64_t placement = components.client_list().size(); - auto objAdd = components.client_insert(placement, img); - img->client_send_place(*this); - add_undo_place_component(objAdd); -} - -void DrawingProgram::initialize_draw_data(cereal::PortableBinaryInputArchive& a) { - uint64_t compCount; - a(compCount); - for(uint64_t i = 0; i < compCount; i++) { - DrawComponentType t; - a(t); - auto newComp = DrawComponent::allocate_comp_type(t); - a(newComp->id, newComp->coords, *newComp); - components.init_emplace_back(newComp); - } - parallel_loop_all_components([&](const auto& c){ - c->obj->commit_update(*this, false); - }); - compCache.test_rebuild(components.client_list(), true); -} - -void DrawingProgram::load_file(cereal::PortableBinaryInputArchive& a, VersionNumber version) { - uint64_t compCount; - a(compCount); - for(uint64_t i = 0; i < compCount; i++) { - DrawComponentType t; - a(t); - auto newComp = DrawComponent::allocate_comp_type(t); - a(newComp->id, newComp->coords); - newComp->load_file(a, version); - components.init_emplace_back(newComp); - } - parallel_loop_all_components([&](const auto& c){ - c->obj->commit_update(*this, false); - }); - compCache.test_rebuild(components.client_list(), true); -} - -void DrawingProgram::client_erase_set(std::unordered_set erasedComponents) { - std::unordered_set idsToErase; - for(auto& c : erasedComponents) - idsToErase.emplace(c->obj->id); - DrawComponent::client_send_erase_set(*this, idsToErase); - components.client_erase_set(erasedComponents); - add_undo_erase_components(erasedComponents); -} - -void DrawingProgram::add_undo_place_component(const CollabListType::ObjectInfoPtr& objToUndo) { - world.undo.push(UndoManager::UndoRedoPair{ - [&, objToUndo]() { - objToUndo->obj->client_send_erase(*this); - components.client_erase(objToUndo); - return true; - }, - [&, objToUndo]() { - if(objToUndo->obj->collabListInfo.lock()) - return false; - components.client_insert(objToUndo, false); - objToUndo->obj->client_send_place(*this); - return true; - } - }); -} - -void DrawingProgram::invalidate_cache_at_component(const CollabListType::ObjectInfoPtr& objToCheck) { +void DrawingProgram::invalidate_cache_at_component(const CanvasComponentContainer::ObjInfoSharedPtr& objToCheck) { if(selection.is_selected(objToCheck)) - selection.invalidate_cache_at_optional_aabb_before_pos(objToCheck->obj->worldAABB, objToCheck->pos); + selection.invalidate_cache_at_aabb_before_pos(objToCheck->obj->get_world_bounds(), objToCheck->pos); else - compCache.invalidate_cache_at_optional_aabb_before_pos(objToCheck->obj->worldAABB, objToCheck->pos); + compCache.invalidate_cache_at_aabb_before_pos(objToCheck->obj->get_world_bounds(), objToCheck->pos); } -void DrawingProgram::preupdate_component(const CollabListType::ObjectInfoPtr& objToCheck) { +void DrawingProgram::preupdate_component(const CanvasComponentContainer::ObjInfoSharedPtr& objToCheck) { if(selection.is_selected(objToCheck)) selection.preupdate_component(objToCheck); else compCache.preupdate_component(objToCheck); } -void DrawingProgram::add_undo_place_components(const std::unordered_set& objSetToUndo) { - world.undo.push(UndoManager::UndoRedoPair{ - [&, objSetToUndo = objSetToUndo]() { - for(auto& comp : objSetToUndo) - if(!comp->obj->collabListInfo.lock()) - return false; - - std::unordered_set idsToErase; - for(auto& c : objSetToUndo) - idsToErase.emplace(c->obj->id); - - DrawComponent::client_send_erase_set(*this, idsToErase); - components.client_erase_set(objSetToUndo); - - return true; - }, - [&, objSetToUndo = objSetToUndo]() { - std::vector sortedObjects(objSetToUndo.begin(), objSetToUndo.end()); - std::sort(sortedObjects.begin(), sortedObjects.end(), [](auto& a, auto& b) { - return a->pos < b->pos; - }); - - for(auto& comp : sortedObjects) - if(comp->obj->collabListInfo.lock()) - return false; - - components.client_insert_ordered_vector(sortedObjects, false); - DrawComponent::client_send_place_many(*this, sortedObjects); - - return true; - } - }); -} - -void DrawingProgram::add_undo_erase_components(const std::unordered_set& objSetToUndo) { - world.undo.push(UndoManager::UndoRedoPair{ - [&, objSetToUndo = objSetToUndo]() { - std::vector sortedObjects(objSetToUndo.begin(), objSetToUndo.end()); - std::sort(sortedObjects.begin(), sortedObjects.end(), [](auto& a, auto& b) { - return a->pos < b->pos; - }); - - for(auto& comp : sortedObjects) - if(comp->obj->collabListInfo.lock()) - return false; - - components.client_insert_ordered_vector(sortedObjects, false); - DrawComponent::client_send_place_many(*this, sortedObjects); - - return true; - }, - [&, objSetToUndo = objSetToUndo]() { - for(auto& comp : objSetToUndo) - if(!comp->obj->collabListInfo.lock()) - return false; - - std::unordered_set idsToErase; - for(auto& c : objSetToUndo) - idsToErase.emplace(c->obj->id); - - DrawComponent::client_send_erase_set(*this, idsToErase); - components.client_erase_set(objSetToUndo); - - return true; - } - }); -} - -ClientPortionID DrawingProgram::get_max_id(ServerPortionID serverID) { - ClientPortionID maxClientID = 0; - auto& cList = components.client_list(); - for(auto& comp : cList) { - if(comp->obj->id.first == serverID) - maxClientID = std::max(maxClientID, comp->obj->id.second); - } - return maxClientID; -} - float DrawingProgram::drag_point_radius() { return 8.0f * world.main.toolbar.final_gui_scale(); } @@ -758,24 +400,36 @@ void DrawingProgram::draw_drag_circle(SkCanvas* canvas, const Vector2f& sPos, co canvas->drawCircle(sPos.x(), sPos.y(), constantRadius, paintOutline); } +void DrawingProgram::load_file(cereal::PortableBinaryInputArchive& a, VersionNumber version) { + //uint64_t compCount; + //a(compCount); + //for(uint64_t i = 0; i < compCount; i++) { + // DrawComponentType t; + // a(t); + // auto newComp = DrawComponent::allocate_comp_type(t); + // a(newComp->id, newComp->coords); + // newComp->load_file(a, version); + // components.init_emplace_back(newComp); + //} + //parallel_loop_all_components([&](const auto& c){ + // c->obj->commit_update(*this, false); + //}); + //compCache.test_rebuild(components.client_list(), true); +} + void DrawingProgram::save_file(cereal::PortableBinaryOutputArchive& a) const { - auto& cList = components.client_list(); - a((uint64_t)cList.size()); - for(size_t i = 0; i < cList.size(); i++) { - a(cList[i]->obj->get_type(), cList[i]->obj->id, cList[i]->obj->coords); - cList[i]->obj->save_file(a); - } + //auto& cList = components->get_data(); + //a((uint64_t)cList.size()); + //for(size_t i = 0; i < cList.size(); i++) { + // a(cList[i]->obj->get_type(), cList[i]->obj->id, cList[i]->obj->coords); + // cList[i]->obj->save_file(a); + //} } void DrawingProgram::draw(SkCanvas* canvas, const DrawData& drawData) { if(drawData.dontUseDrawProgCache) { - parallel_loop_all_components([&](auto& c) { - c->obj->calculate_draw_transform(drawData); - }); - for(auto& c : components.client_list()) { + for(auto& c : components->get_data()) c->obj->draw(canvas, drawData); - c->obj->drawSetupData.shouldDraw = false; - } } else { canvas->saveLayer(nullptr, nullptr); @@ -786,22 +440,6 @@ void DrawingProgram::draw(SkCanvas* canvas, const DrawData& drawData) { selection.draw_components(canvas, drawData); canvas->restore(); canvas->restore(); - - if(!drawData.main->takingScreenshot) { - for(auto& droppedDownFile : droppedDownloadingFiles) { - if(droppedDownFile.comp->obj->collabListInfo.lock()) - std::static_pointer_cast(droppedDownFile.comp->obj)->draw_download_progress_bar(canvas, drawData, droppedDownFile.downData->progress); - } - - for(auto& c : updateableComponents) { - if(c->get_type() == DRAWCOMPONENT_IMAGE) { - auto img = std::static_pointer_cast(c); - 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); } diff --git a/src/DrawingProgram/DrawingProgram.hpp b/src/DrawingProgram/DrawingProgram.hpp index a095e29..422eeb5 100644 --- a/src/DrawingProgram/DrawingProgram.hpp +++ b/src/DrawingProgram/DrawingProgram.hpp @@ -11,19 +11,20 @@ #include #include #include -#include #include #include "DrawingProgramSelection.hpp" -#include "../CollabList.hpp" #include "DrawingProgramToolBase.hpp" #include +#include class World; class DrawingProgram { public: DrawingProgram(World& initWorld); + void init(); void init_client_callbacks(); + void set_component_list_callbacks(); void toolbar_gui(); void tool_options_gui(); bool right_click_popup_gui(Vector2f popupPos); @@ -31,39 +32,26 @@ class DrawingProgram { void scale_up(const WorldScalar& scaleUpAmount); void draw(SkCanvas* canvas, const DrawData& drawData); - void initialize_draw_data(cereal::PortableBinaryInputArchive& a); - void load_file(cereal::PortableBinaryInputArchive& a, VersionNumber version); - std::unordered_set get_used_resources() const; - ClientPortionID get_max_id(ServerPortionID serverID); + void load_file(cereal::PortableBinaryInputArchive& a, VersionNumber version); void save_file(cereal::PortableBinaryOutputArchive& a) const; World& world; bool prevent_undo_or_redo(); - - void add_file_to_canvas_by_path(const std::filesystem::path& 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); + 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 CollabListType::ObjectInfoPtr& objToCheck); - void preupdate_component(const CollabListType::ObjectInfoPtr& objToCheck); + void invalidate_cache_at_component(const CanvasComponentContainer::ObjInfoSharedPtr& objToCheck); + void preupdate_component(const CanvasComponentContainer::ObjInfoSharedPtr& objToCheck); DrawingProgramCache compCache; - CollabListType components; - - std::unordered_set> updateableComponents; - std::unordered_map, std::shared_ptr> delayedUpdateComponents; + 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: @@ -71,31 +59,17 @@ class DrawingProgram { std::optional unorderedObjectsExistTimePoint; bool selection_action_menu(Vector2f popupPos); - - void client_erase_set(std::unordered_set erasedComponents); // The set might be modified while this is being called, so dont pass by reference - - void check_delayed_update_timers(); - void check_updateable_components(); - void force_rebuild_cache(); - bool addToCompCacheOnInsert = true; - std::atomic addFileInNextFrame = false; std::pair addFileInfo; - void add_file_to_canvas_by_path_execute(const std::filesystem::path& filePath, Vector2f dropPos); - - void drag_drop_update(); - float drag_point_radius(); void draw_drag_circle(SkCanvas* canvas, const Vector2f& pos, const SkColor4f& c, const DrawData& drawData, float radiusMultiplier = 1.0f); - - void add_undo_place_component(const CollabListType::ObjectInfoPtr& objToUndo); - void add_undo_place_components(const std::unordered_set& objSetToUndo); - void add_undo_erase_components(const std::unordered_set& objSetToUndo); - 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; @@ -105,9 +79,6 @@ class DrawingProgram { bool temporaryPan = false; DrawingProgramToolType toolTypeAfterTempPan; - bool is_actual_selection_tool(DrawingProgramToolType typeToCheck); - bool is_selection_allowing_tool(DrawingProgramToolType typeToCheck); - struct GlobalControls { float relativeWidth = 15.0f; @@ -130,15 +101,6 @@ class DrawingProgram { uint32_t nextID = 0; - struct DroppedDownloadingFile { - CollabListType::ObjectInfoPtr comp; - Vector2f windowSizeWhenDropped; - std::shared_ptr downData; - }; - std::vector droppedDownloadingFiles; - - void update_downloading_dropped_files(); - friend class EyeDropperTool; friend class RectDrawTool; friend class EllipseDrawTool; diff --git a/src/DrawingProgram/DrawingProgramCache.cpp b/src/DrawingProgram/DrawingProgramCache.cpp index df5ec44..4669014 100644 --- a/src/DrawingProgram/DrawingProgramCache.cpp +++ b/src/DrawingProgram/DrawingProgramCache.cpp @@ -23,18 +23,10 @@ DrawingProgramCache::DrawingProgramCache(DrawingProgram& initDrawP): lastBvhBuildTime = std::chrono::steady_clock::now(); } -void DrawingProgramCache::build(std::vector components) { +void DrawingProgramCache::build(std::vector components) { bvhRoot = std::make_shared(); unsortedComponents.clear(); clear_own_cached_surfaces(); - std::erase_if(components, [&](auto& c) { - if(!c->obj->worldAABB) { - unsortedComponents.emplace_back(c); - c->obj->parentBvhNode.reset(); - return true; - } - return false; - }); build_bvh_node(bvhRoot, components); lastBvhBuildTime = std::chrono::steady_clock::now(); } @@ -59,17 +51,17 @@ 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) { +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) { +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) { +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); @@ -77,30 +69,30 @@ void DrawingProgramCache::test_rebuild_dont_include_set_dont_include_nodes(const } } -void DrawingProgramCache::move_components_from_bvh_nodes_to_set(std::unordered_set& s, const std::unordered_set>& bvhNodes) { +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) { +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) { +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) { +void DrawingProgramCache::force_rebuild(const std::vector& componentsToBuild) { build(componentsToBuild); } -const std::vector& DrawingProgramCache::get_unsorted_component_list() const { +const std::vector& DrawingProgramCache::get_unsorted_component_list() const { return unsortedComponents; } @@ -108,12 +100,12 @@ const std::chrono::steady_clock::time_point& DrawingProgramCache::get_last_bvh_b return lastBvhBuildTime; } -void DrawingProgramCache::add_component(const CollabListType::ObjectInfoPtr& c) { +void DrawingProgramCache::add_component(const CanvasComponentContainer::ObjInfoSharedPtr& c) { unsortedComponents.emplace_back(c); - invalidate_cache_at_optional_aabb_before_pos(c->obj->worldAABB, c->pos); + invalidate_cache_at_aabb_before_pos(c->obj->get_world_bounds(), c->pos); } -void DrawingProgramCache::erase_component(const CollabListType::ObjectInfoPtr& c) { +void DrawingProgramCache::erase_component(const CanvasComponentContainer::ObjInfoSharedPtr& c) { auto parentBvhNode = c->obj->parentBvhNode.lock(); if(parentBvhNode) { std::erase(parentBvhNode->components, c); @@ -121,33 +113,16 @@ void DrawingProgramCache::erase_component(const CollabListType::ObjectInfoPtr& c } else std::erase(unsortedComponents, c); - invalidate_cache_at_optional_aabb_before_pos(c->obj->worldAABB, c->pos); + invalidate_cache_at_aabb_before_pos(c->obj->get_world_bounds(), c->pos); } -std::pair, std::vector::iterator> DrawingProgramCache::get_bvh_node_fully_containing_recursive(const std::shared_ptr& 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_erase_function(const SCollision::AABB& aabb, std::function& node, std::vector& components)> 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; } -bool DrawingProgramCache::traverse_bvh_erase_function_recursive(const std::shared_ptr& bvhNode, const SCollision::AABB& aabb, std::function& node, std::vector& components)> 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; @@ -158,22 +133,22 @@ bool DrawingProgramCache::traverse_bvh_erase_function_recursive(const std::share return false; } -void DrawingProgramCache::traverse_bvh_run_function(const SCollision::AABB& aabb, std::function& node, const std::vector& components)> f) { +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) { +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); } } -CollabListType::ObjectInfoPtr DrawingProgramCache::get_front_object_colliding_with(const SCollision::ColliderCollection& cC) { +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); - CollabListType::ObjectInfoPtr p; - traverse_bvh_run_function(cCWorld.bounds, [&](const std::shared_ptr& bvhNode, const std::vector& components) { + 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; @@ -183,23 +158,23 @@ CollabListType::ObjectInfoPtr DrawingProgramCache::get_front_object_colliding_wi return p; } -void DrawingProgramCache::preupdate_component(const CollabListType::ObjectInfoPtr& c) { +void DrawingProgramCache::preupdate_component(const CanvasComponentContainer::ObjInfoSharedPtr& c) { auto parentBvhNode = c->obj->parentBvhNode.lock(); if(parentBvhNode) { unsortedComponents.emplace_back(c); std::erase(parentBvhNode->components, c); c->obj->parentBvhNode.reset(); } - invalidate_cache_at_optional_aabb_before_pos(c->obj->worldAABB, c->pos); + invalidate_cache_at_aabb_before_pos(c->obj->get_world_bounds(), c->pos); } -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; - bvhNode->bounds = components.front()->obj->worldAABB.value(); + bvhNode->bounds = components.front()->obj->get_world_bounds(); for(auto& c : components) - bvhNode->bounds.include_aabb_in_bounds(c->obj->worldAABB.value()); + bvhNode->bounds.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; @@ -215,10 +190,10 @@ void DrawingProgramCache::build_bvh_node(const std::shared_ptrbounds.center(); - std::array, 4> parts; + std::array, 4> parts; for(auto& c : components) { - const auto& cAABB = c->obj->worldAABB.value(); + 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()) @@ -271,7 +246,7 @@ 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(uint64_t placementToInvalidateAt) { +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) @@ -286,14 +261,7 @@ void DrawingProgramCache::invalidate_cache_before_pos(uint64_t placementToInvali }); } -void DrawingProgramCache::invalidate_cache_at_optional_aabb_before_pos(const std::optional>& aabb, uint64_t placementToInvalidateAt) { - if(aabb) - invalidate_cache_at_aabb_before_pos(aabb.value(), placementToInvalidateAt); - else - invalidate_cache_before_pos(placementToInvalidateAt); -} - -void DrawingProgramCache::invalidate_cache_at_aabb_before_pos(const SCollision::AABB& aabb, uint64_t placementToInvalidateAt) { +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(); @@ -312,7 +280,7 @@ void DrawingProgramCache::invalidate_cache_at_aabb_before_pos(const SCollision:: 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) { + 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) nodeFlatList.emplace_front(node); @@ -415,16 +383,16 @@ void DrawingProgramCache::refresh_draw_cache(const std::shared_ptr> cachedNodesToDraw; struct UncachedObjectToDraw { - CollabListType::ObjectInfoPtr comp; + CanvasComponentContainer::ObjInfoSharedPtr comp; bool isAnUnsortedObject; }; std::vector uncachedCompsToDraw; - traverse_bvh_run_function(drawData.cam.viewingAreaGenerousCollider, [&](const std::shared_ptr& node, const std::vector& comps) { + 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); @@ -432,10 +400,8 @@ void DrawingProgramCache::draw_components_to_canvas(SkCanvas* canvas, const Draw } for(auto& c : comps) { - if(!optData.drawBounds.has_value() || !c->obj->worldAABB.has_value() || SCollision::collide(optData.drawBounds.value(), c->obj->worldAABB.value())) { - c->obj->calculate_draw_transform(drawData); + 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); } @@ -463,8 +429,6 @@ void DrawingProgramCache::draw_components_to_canvas(SkCanvas* canvas, const Draw uncachedComp.comp->obj->draw(canvas, drawData); if(uncachedComp.isAnUnsortedObject) unsortedCompDrawTime += std::chrono::duration_cast(std::chrono::steady_clock::now() - drawStartTime); - - uncachedComp.comp->obj->drawSetupData.shouldDraw = false; } for(;nextCacheToRender < cachedNodesToDraw.size(); nextCacheToRender++) draw_cache_image_to_canvas(canvas, drawData, cachedNodesToDraw[nextCacheToRender]); diff --git a/src/DrawingProgram/DrawingProgramCache.hpp b/src/DrawingProgram/DrawingProgramCache.hpp index 8042fe7..325f28b 100644 --- a/src/DrawingProgram/DrawingProgramCache.hpp +++ b/src/DrawingProgram/DrawingProgramCache.hpp @@ -4,7 +4,7 @@ #include #include #include "../DrawData.hpp" -#include "../DrawComponents/DrawComponent.hpp" +#include "../CanvasComponents/CanvasComponentContainer.hpp" class DrawingProgram; class DrawingProgramCache; @@ -12,13 +12,13 @@ class DrawingProgramCache; class DrawingProgramCacheBVHNode { public: SCollision::AABB bounds; - std::vector components; + std::vector components; std::vector> children; CoordSpaceHelper coords; Vector2i resolution; struct DrawCacheData { - uint64_t lastDrawnComponentPlacement; + uint32_t lastDrawnComponentPlacement; sk_sp surface; std::chrono::steady_clock::time_point lastRenderTime; DrawingProgramCache* attachedCache; @@ -38,56 +38,54 @@ class DrawingProgramCache { static constexpr size_t MAXIMUM_COMPONENTS_IN_SINGLE_NODE = 50; 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); + 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); + 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 CollabListType::ObjectInfoPtr& c); - void add_component(const CollabListType::ObjectInfoPtr& c); + 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); + 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 CollabListType::ObjectInfoPtr& c); - void invalidate_cache_before_pos(uint64_t placementToInvalidateAt); - void invalidate_cache_at_aabb_before_pos(const SCollision::AABB& aabb, uint64_t placementToInvalidateAt); - void invalidate_cache_at_optional_aabb_before_pos(const std::optional>& aabb, uint64_t placementToInvalidateAt); + 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 { - uint64_t* lastDrawnComponentPlacement = nullptr; + uint32_t* lastDrawnComponentPlacement = nullptr; std::optional> drawBounds; }; void draw_components_to_canvas(SkCanvas* canvas, const DrawData& drawData, DrawComponentsToCanvasOptionalData optData); - const std::vector& get_unsorted_component_list() const; + const std::vector& get_unsorted_component_list() const; const std::chrono::steady_clock::time_point& get_last_bvh_build_time() const; void clear_own_cached_surfaces(); - CollabListType::ObjectInfoPtr get_front_object_colliding_with(const SCollision::ColliderCollection& cC); + CanvasComponentContainer::ObjInfoSharedPtr get_front_object_colliding_with(const SCollision::ColliderCollection& cC); private: static std::unordered_set> nodesWithCachedSurfaces; void draw_cache_image_to_canvas(SkCanvas* canvas, const DrawData& drawData, const std::shared_ptr& bvhNode); - void force_rebuild_dont_include_objs(std::vector componentsToBuild, const std::unordered_set& objsToNotInclude); - void force_rebuild(const std::vector& componentsToBuild); + 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); + 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); - std::pair, std::vector::iterator> get_bvh_node_fully_containing_recursive(const std::shared_ptr& bvhNode, DrawComponent* c); + 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); + 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::vector unsortedComponents; + std::vector unsortedComponents; DrawingProgram& drawP; }; diff --git a/src/DrawingProgram/DrawingProgramSelection.cpp b/src/DrawingProgram/DrawingProgramSelection.cpp index f141335..9c3c175 100644 --- a/src/DrawingProgram/DrawingProgramSelection.cpp +++ b/src/DrawingProgram/DrawingProgramSelection.cpp @@ -27,18 +27,18 @@ DrawingProgramSelection::DrawingProgramSelection(DrawingProgram& initDrawP): drawP(initDrawP) {} -const std::unordered_set& DrawingProgramSelection::get_selected_set() { +const std::unordered_set& DrawingProgramSelection::get_selected_set() { return selectedSet; } -void DrawingProgramSelection::erase_component(const CollabListType::ObjectInfoPtr& objToCheck) { +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) { +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); @@ -47,7 +47,7 @@ void DrawingProgramSelection::fully_collided_erase_select_objects_func(std::unor } } -std::function&, std::vector&)> DrawingProgramSelection::erase_select_objects_in_bvh_func(std::unordered_set& selectedComponents, const SCollision::ColliderCollection& cC, const SCollision::ColliderCollection& cCWorld) { +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)) && @@ -61,7 +61,7 @@ std::function&, std::vect 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->worldAABB.value(), c->obj->collabListInfo.lock()->pos); + drawP.compCache.invalidate_cache_at_aabb_before_pos(c->obj->get_world_bounds(), c->pos); return true; } return false; @@ -73,9 +73,9 @@ std::function&, std::vect } void DrawingProgramSelection::add_from_cam_coord_collider_to_selection(const SCollision::ColliderCollection& cC, bool frontObjectOnly) { - std::unordered_set selectedComponents; + std::unordered_set selectedComponents; if(frontObjectOnly) { - CollabListType::ObjectInfoPtr a = drawP.compCache.get_front_object_colliding_with(cC); + CanvasComponentContainer::ObjInfoSharedPtr a = drawP.compCache.get_front_object_colliding_with(cC); if(a) { selectedComponents.emplace(a); drawP.compCache.erase_component(a); @@ -90,9 +90,9 @@ void DrawingProgramSelection::add_from_cam_coord_collider_to_selection(const SCo 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; + std::unordered_set selectedComponents; if(frontObjectOnly) { - CollabListType::ObjectInfoPtr a = cache.get_front_object_colliding_with(cC); + CanvasComponentContainer::ObjInfoSharedPtr a = cache.get_front_object_colliding_with(cC); if(a) { selectedComponents.emplace(a); cache.erase_component(a); @@ -117,7 +117,7 @@ void DrawingProgramSelection::remove_from_cam_coord_collider_to_selection(const } } -void DrawingProgramSelection::add_to_selection(const std::unordered_set& newSelection) { +void DrawingProgramSelection::add_to_selection(const std::unordered_set& newSelection) { selectedSet.insert(newSelection.begin(), newSelection.end()); for(auto& obj : newSelection) cache.add_component(obj); @@ -125,7 +125,7 @@ void DrawingProgramSelection::add_to_selection(const std::unordered_set& newSelection) { +void DrawingProgramSelection::set_to_selection(const std::unordered_set& newSelection) { selectedSet = newSelection; for(auto& obj : selectedSet) cache.add_component(obj); @@ -139,9 +139,9 @@ bool DrawingProgramSelection::is_something_selected() { void DrawingProgramSelection::calculate_aabb() { if(is_something_selected()) { - initialSelectionAABB = (*selectedSet.begin())->obj->worldAABB.value(); + initialSelectionAABB = (*selectedSet.begin())->obj->get_world_bounds(); for(auto& c : selectedSet) - initialSelectionAABB.include_aabb_in_bounds(c->obj->worldAABB.value()); + initialSelectionAABB.include_aabb_in_bounds(c->obj->get_world_bounds()); } } @@ -149,7 +149,7 @@ 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.client_list(), true); + drawP.compCache.test_rebuild(drawP.components->get_data(), true); else { for(auto& obj : selectedSet) drawP.compCache.add_component(obj); @@ -162,99 +162,51 @@ void DrawingProgramSelection::deselect_all() { void DrawingProgramSelection::commit_transform_selection() { auto selectedSetTemp = selectedSet; - std::vector a(selectedSet.begin(), selectedSet.end()); - std::vector> transformsFrom; + 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(drawP, false); + obj->obj->commit_transform_dont_invalidate_cache(drawP); }, isSingleThread); - std::vector> transformsTo; - std::vector> transformsToSend; + std::vector> transformsTo; + std::vector> transformsToSend; for(auto& transformedObj : a) { - transformsToSend.emplace_back(transformedObj->obj->id, transformedObj->obj->coords); + 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); - drawP.world.undo.push(UndoManager::UndoRedoPair{ - [isSingleThread, &drawP = drawP, transformsFrom = transformsFrom]() { - std::vector> transformsToSend; - for(auto& [comp, coords] : transformsFrom) { - auto lockObjInfo = comp->obj->collabListInfo.lock(); - if(lockObjInfo) - transformsToSend.emplace_back(lockObjInfo->obj->id, coords); - else - return false; - } - - parallel_loop_container(transformsFrom, [&](auto& p) { - auto& [comp, coords] = p; - comp->obj->coords = coords; - comp->obj->commit_transform(drawP, isSingleThread); - }, isSingleThread); - - DrawComponent::client_send_transform_many(drawP, transformsToSend); - - if(!isSingleThread) - drawP.force_rebuild_cache(); - - return true; - }, - [isSingleThread, &drawP = drawP, transformsTo = transformsTo]() { - std::vector> transformsToSend; - for(auto& [comp, coords] : transformsTo) { - auto lockObjInfo = comp->obj->collabListInfo.lock(); - if(lockObjInfo) - transformsToSend.emplace_back(lockObjInfo->obj->id, coords); - else - return false; - } - - parallel_loop_container(transformsTo, [&](auto& p) { - auto& [comp, coords] = p; - comp->obj->coords = coords; - comp->obj->commit_transform(drawP, isSingleThread); - }, isSingleThread); - - DrawComponent::client_send_transform_many(drawP, transformsToSend); - - if(!isSingleThread) - drawP.force_rebuild_cache(); - - return true; - } - }); + //DrawComponent::client_send_transform_many(drawP, transformsToSend); reset_selection_data(); reset_transform_data(); set_to_selection(selectedSetTemp); } -CollabListType::ObjectInfoPtr DrawingProgramSelection::get_front_object_colliding_with(const SCollision::ColliderCollection& cC) { +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_optional_aabb_before_pos(const std::optional>& aabb, uint64_t placementToInvalidateAt) { - cache.invalidate_cache_at_optional_aabb_before_pos(aabb, placementToInvalidateAt); +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 CollabListType::ObjectInfoPtr& objToCheck) { +void DrawingProgramSelection::preupdate_component(const CanvasComponentContainer::ObjInfoSharedPtr& objToCheck) { cache.preupdate_component(objToCheck); } -bool DrawingProgramSelection::is_selected(const CollabListType::ObjectInfoPtr& 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); + //drawP.client_erase_set(selectedSet); reset_selection_data(); reset_transform_data(); } @@ -262,26 +214,26 @@ void DrawingProgramSelection::delete_all() { // 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); + //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); + 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()); @@ -397,45 +349,42 @@ bool DrawingProgramSelection::is_being_transformed() { } void DrawingProgramSelection::paste_clipboard(Vector2f pasteScreenPos) { - auto& clipboard = drawP.world.main.clipboard; + //auto& clipboard = drawP.world.main.clipboard; - if(!drawP.is_selection_allowing_tool(drawP.drawTool->get_type())) - drawP.switch_to_tool(DrawingProgramToolType::EDIT); + //if(!drawP.is_selection_allowing_tool(drawP.drawTool->get_type())) + // drawP.switch_to_tool(DrawingProgramToolType::EDIT); - uint64_t allPlacement = drawP.components.client_list().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; - } - } + //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->coords.translate(-moveVec); - c->obj->coords.scale_about(mousePos, scaleMultiplier); - //std::cout << c->obj->coords.inverseScale << std::endl; - //if(c->obj->coords.inverseScale == WorldScalar(0)) - // throw std::runtime_error("DONE"); - 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); + //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() { diff --git a/src/DrawingProgram/DrawingProgramSelection.hpp b/src/DrawingProgram/DrawingProgramSelection.hpp index a9d4d20..5ef896f 100644 --- a/src/DrawingProgram/DrawingProgramSelection.hpp +++ b/src/DrawingProgram/DrawingProgramSelection.hpp @@ -10,7 +10,7 @@ class DrawingProgramSelection { 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); - CollabListType::ObjectInfoPtr get_front_object_colliding_with(const SCollision::ColliderCollection& cC); + CanvasComponentContainer::ObjInfoSharedPtr get_front_object_colliding_with(const SCollision::ColliderCollection& cC); void deselect_all(); void update(); @@ -18,31 +18,31 @@ class DrawingProgramSelection { void draw_gui(SkCanvas* canvas, const DrawData& drawData); bool is_something_selected(); bool mouse_collided_with_selection(); - void erase_component(const CollabListType::ObjectInfoPtr& objToCheck); - bool is_selected(const CollabListType::ObjectInfoPtr& objToCheck); - const std::unordered_set& get_selected_set(); + 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_optional_aabb_before_pos(const std::optional>& aabb, uint64_t placementToInvalidateAt); + void invalidate_cache_at_aabb_before_pos(const SCollision::AABB& aabb, uint64_t placementToInvalidateAt); void clear_own_cached_surfaces(); - void preupdate_component(const CollabListType::ObjectInfoPtr& objToCheck); + 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); + 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 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(); @@ -59,7 +59,7 @@ class DrawingProgramSelection { CoordSpaceHelperTransform selectionTransformCoords; - std::unordered_set selectedSet; + std::unordered_set selectedSet; DrawingProgramCache cache; DrawingProgram& drawP; diff --git a/src/DrawingProgram/EllipseDrawTool.cpp b/src/DrawingProgram/EllipseDrawTool.cpp index 73c8282..3d8bdfc 100644 --- a/src/DrawingProgram/EllipseDrawTool.cpp +++ b/src/DrawingProgram/EllipseDrawTool.cpp @@ -1,16 +1,12 @@ #include "EllipseDrawTool.hpp" -#include #include "DrawingProgram.hpp" -#include "../Server/CommandList.hpp" #include "../MainProgram.hpp" #include "../DrawData.hpp" #include "DrawingProgramToolBase.hpp" #include "Helpers/MathExtras.hpp" -#include "Helpers/SCollision.hpp" -#include "Helpers/Serializers.hpp" #include "../InputManager.hpp" -#include "../SharedTypes.hpp" #include +#include "../CanvasComponents/EllipseCanvasComponent.hpp" EllipseDrawTool::EllipseDrawTool(DrawingProgram& initDrawP): DrawingProgramToolBase(initDrawP) @@ -24,10 +20,10 @@ void EllipseDrawTool::gui_toolbox() { Toolbar& t = drawP.world.main.toolbar; t.gui.push_id("ellipse draw tool"); t.gui.text_label_centered("Draw Ellipse"); - if(t.gui.radio_button_field("fillonly", "Fill only", controls.fillStrokeMode == 0)) controls.fillStrokeMode = 0; - if(t.gui.radio_button_field("outlineonly", "Outline only", controls.fillStrokeMode == 1)) controls.fillStrokeMode = 1; - if(t.gui.radio_button_field("filloutline", "Fill and Outline", controls.fillStrokeMode == 2)) controls.fillStrokeMode = 2; - if(controls.fillStrokeMode == 1 || controls.fillStrokeMode == 2) + if(t.gui.radio_button_field("fillonly", "Fill only", fillStrokeMode == 0)) fillStrokeMode = 0; + if(t.gui.radio_button_field("outlineonly", "Outline only", fillStrokeMode == 1)) fillStrokeMode = 1; + if(t.gui.radio_button_field("filloutline", "Fill and Outline", fillStrokeMode == 2)) fillStrokeMode = 2; + if(fillStrokeMode == 1 || fillStrokeMode == 2) t.gui.slider_scalar_field("relstrokewidth", "Outline Size", &drawP.controls.relativeWidth, 3.0f, 40.0f); t.gui.pop_id(); } @@ -43,46 +39,45 @@ void EllipseDrawTool::switch_tool(DrawingProgramToolType newTool) { } void EllipseDrawTool::tool_update() { - switch(controls.drawStage) { + switch(drawStage) { case 0: { if(drawP.controls.leftClick) { - controls.startAt = drawP.world.main.input.mouse.pos; - controls.intermediateItem = std::make_shared(); - controls.intermediateItem->d.strokeColor = drawP.controls.foregroundColor; - controls.intermediateItem->d.fillColor = drawP.controls.backgroundColor; - controls.intermediateItem->d.strokeWidth = drawP.controls.relativeWidth; - controls.intermediateItem->d.p1 = controls.startAt; - controls.intermediateItem->d.p2 = controls.startAt; - controls.intermediateItem->d.p2 = ensure_points_have_distance(controls.intermediateItem->d.p1, controls.intermediateItem->d.p2, MINIMUM_DISTANCE_BETWEEN_BOUNDS); - controls.intermediateItem->d.fillStrokeMode = static_cast(controls.fillStrokeMode); - controls.intermediateItem->coords = drawP.world.drawData.cam.c; - controls.intermediateItem->lastUpdateTime = std::chrono::steady_clock::now(); - uint64_t placement = drawP.components.client_list().size(); - auto objAdd = drawP.components.client_insert(placement, controls.intermediateItem); - controls.intermediateItem->client_send_place(drawP); - drawP.add_undo_place_component(objAdd); - controls.intermediateItem->commit_update(drawP); - controls.drawStage = 1; + CanvasComponentContainer* newContainer = new CanvasComponentContainer(drawP.world.netObjMan, CanvasComponent::CompType::ELLIPSE); + EllipseCanvasComponent& newEllipse = static_cast(newContainer->get_comp()); + + startAt = drawP.world.main.input.mouse.pos; + newEllipse.d.strokeColor = drawP.controls.foregroundColor; + newEllipse.d.fillColor = drawP.controls.backgroundColor; + newEllipse.d.strokeWidth = drawP.controls.relativeWidth; + newEllipse.d.p1 = startAt; + newEllipse.d.p2 = startAt; + newEllipse.d.p2 = ensure_points_have_distance(newEllipse.d.p1, newEllipse.d.p2, MINIMUM_DISTANCE_BETWEEN_BOUNDS); + newEllipse.d.fillStrokeMode = static_cast(fillStrokeMode); + newContainer->coords = drawP.world.drawData.cam.c; + + intermediateContainer = drawP.components->push_back_and_send_create(drawP.components, newContainer)->obj; + drawStage = 1; } break; } case 1: { - if(drawP.controls.leftClickHeld) { - controls.intermediateItem->lastUpdateTime = std::chrono::steady_clock::now(); - Vector2f newPos = controls.intermediateItem->coords.get_mouse_pos(drawP.world); + NetworkingObjects::NetObjTemporaryPtr containerPtr = intermediateContainer.lock(); + if(drawP.controls.leftClickHeld && containerPtr) { + Vector2f newPos = containerPtr->coords.get_mouse_pos(drawP.world); if(drawP.world.main.input.key(InputManager::KEY_GENERIC_LSHIFT).held) { - float height = std::fabs(controls.startAt.y() - newPos.y()); - newPos.x() = controls.startAt.x() + (((newPos.x() - controls.startAt.x()) < 0.0f ? -1.0f : 1.0f) * height); + float height = std::fabs(startAt.y() - newPos.y()); + newPos.x() = startAt.x() + (((newPos.x() - startAt.x()) < 0.0f ? -1.0f : 1.0f) * height); } - controls.intermediateItem->d.p1 = cwise_vec_min(controls.startAt, newPos); - controls.intermediateItem->d.p2 = cwise_vec_max(controls.startAt, newPos); - controls.intermediateItem->d.p2 = ensure_points_have_distance(controls.intermediateItem->d.p1, controls.intermediateItem->d.p2, MINIMUM_DISTANCE_BETWEEN_BOUNDS); - controls.intermediateItem->client_send_update(drawP, false); - controls.intermediateItem->commit_update(drawP); + EllipseCanvasComponent& ellipse = static_cast(containerPtr->get_comp()); + ellipse.d.p1 = cwise_vec_min(startAt, newPos); + ellipse.d.p2 = cwise_vec_max(startAt, newPos); + ellipse.d.p2 = ensure_points_have_distance(ellipse.d.p1, ellipse.d.p2, MINIMUM_DISTANCE_BETWEEN_BOUNDS); + containerPtr->send_comp_update(drawP, true); + containerPtr->commit_update(drawP); } else { commit(); - controls.drawStage = 0; + drawStage = 0; } break; } @@ -90,15 +85,16 @@ void EllipseDrawTool::tool_update() { } bool EllipseDrawTool::prevent_undo_or_redo() { - return controls.intermediateItem != nullptr; + return (drawStage == 1); } void EllipseDrawTool::commit() { - if(controls.intermediateItem && controls.intermediateItem->collabListInfo.lock()) { - controls.intermediateItem->client_send_update(drawP, true); - controls.intermediateItem->commit_update(drawP); + NetworkingObjects::NetObjTemporaryPtr lockedPtr = intermediateContainer.lock(); + if(lockedPtr) { + lockedPtr->commit_update(drawP); + drawP.world.delayedUpdateObjectManager.send_update_to_all(lockedPtr, true); } - controls.intermediateItem = nullptr; + intermediateContainer.reset(); } void EllipseDrawTool::draw(SkCanvas* canvas, const DrawData& drawData) { diff --git a/src/DrawingProgram/EllipseDrawTool.hpp b/src/DrawingProgram/EllipseDrawTool.hpp index 02cca2b..93a0a3d 100644 --- a/src/DrawingProgram/EllipseDrawTool.hpp +++ b/src/DrawingProgram/EllipseDrawTool.hpp @@ -1,8 +1,8 @@ #pragma once #include "DrawingProgramToolBase.hpp" -#include "../DrawComponents/DrawEllipse.hpp" -#include #include +#include +#include "../CanvasComponents/CanvasComponentContainer.hpp" class DrawingProgram; @@ -19,10 +19,8 @@ class EllipseDrawTool : public DrawingProgramToolBase { private: void commit(); - struct EllipseDrawControls { - Vector2f startAt; - int fillStrokeMode = 1; - int drawStage = 0; - std::shared_ptr intermediateItem; - } controls; + Vector2f startAt; + int fillStrokeMode = 1; + int drawStage = 0; + NetworkingObjects::NetObjWeakPtr intermediateContainer; }; diff --git a/src/DrawingProgram/EraserTool.cpp b/src/DrawingProgram/EraserTool.cpp index 1a73521..4b5e8a5 100644 --- a/src/DrawingProgram/EraserTool.cpp +++ b/src/DrawingProgram/EraserTool.cpp @@ -27,9 +27,9 @@ bool EraserTool::right_click_popup_gui(Vector2f popupPos) { } void EraserTool::switch_tool(DrawingProgramToolType newTool) { + DrawingProgramCache::move_components_from_bvh_nodes_to_set(erasedComponents, erasedBVHNodes); if(!erasedComponents.empty()) { - DrawingProgramCache::move_components_from_bvh_nodes_to_set(erasedComponents, erasedBVHNodes); - drawP.client_erase_set(erasedComponents); + 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 @@ -62,7 +62,7 @@ void EraserTool::tool_update() { std::erase_if(comps, [&](auto& c) { if(c->obj->collides_with(drawP.world.drawData.cam.c, cCWorld, cC)) { erasedComponents.emplace(c); - drawP.compCache.invalidate_cache_at_aabb_before_pos(c->obj->worldAABB.value(), c->obj->collabListInfo.lock()->pos); + drawP.compCache.invalidate_cache_at_aabb_before_pos(c->obj->get_world_bounds(), c->pos); return true; } return false; diff --git a/src/DrawingProgram/EraserTool.hpp b/src/DrawingProgram/EraserTool.hpp index e521ab7..770b4a4 100644 --- a/src/DrawingProgram/EraserTool.hpp +++ b/src/DrawingProgram/EraserTool.hpp @@ -1,8 +1,8 @@ #pragma once #include #include "../DrawData.hpp" -#include "../DrawComponents/DrawComponent.hpp" #include "DrawingProgramToolBase.hpp" +#include "DrawingProgramCache.hpp" class DrawingProgram; @@ -17,6 +17,6 @@ class EraserTool : public DrawingProgramToolBase { virtual void draw(SkCanvas* canvas, const DrawData& drawData) override; virtual bool prevent_undo_or_redo() override; - std::unordered_set erasedComponents; + 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/GridModifyTool.cpp b/src/DrawingProgram/GridModifyTool.cpp index 2d61167..8f5705a 100644 --- a/src/DrawingProgram/GridModifyTool.cpp +++ b/src/DrawingProgram/GridModifyTool.cpp @@ -141,7 +141,7 @@ void GridModifyTool::tool_update() { selectionMode = 0; break; } - drawP.world.delayedUpdateObjectManager.send_update_to_all(gLock, nullptr, false); + drawP.world.delayedUpdateObjectManager.send_update_to_all(gLock, false); } else selectionMode = 0; @@ -187,5 +187,5 @@ void GridModifyTool::draw(SkCanvas* canvas, const DrawData& drawData) { void GridModifyTool::switch_tool(DrawingProgramToolType newTool) { NetworkingObjects::NetObjTemporaryPtr gLock = grid.lock(); if(gLock) - drawP.world.delayedUpdateObjectManager.send_update_to_all(gLock, nullptr, true); + drawP.world.delayedUpdateObjectManager.send_update_to_all(gLock, true); } diff --git a/src/DrawingProgram/RectDrawTool.cpp b/src/DrawingProgram/RectDrawTool.cpp index 42b328d..841abae 100644 --- a/src/DrawingProgram/RectDrawTool.cpp +++ b/src/DrawingProgram/RectDrawTool.cpp @@ -3,7 +3,7 @@ #include "../MainProgram.hpp" #include "../DrawData.hpp" #include "DrawingProgramToolBase.hpp" -#include +#include "../CanvasComponents/RectangleCanvasComponent.hpp" RectDrawTool::RectDrawTool(DrawingProgram& initDrawP): DrawingProgramToolBase(initDrawP) @@ -17,11 +17,11 @@ void RectDrawTool::gui_toolbox() { Toolbar& t = drawP.world.main.toolbar; t.gui.push_id("rect draw tool"); t.gui.text_label_centered("Draw Rectangle"); - t.gui.slider_scalar_field("relradiuswidth", "Corner Radius", &controls.relativeRadiusWidth, 0.0f, 40.0f); - if(t.gui.radio_button_field("fillonly", "Fill only", controls.fillStrokeMode == 0)) controls.fillStrokeMode = 0; - if(t.gui.radio_button_field("outlineonly", "Outline only", controls.fillStrokeMode == 1)) controls.fillStrokeMode = 1; - if(t.gui.radio_button_field("filloutline", "Fill and Outline", controls.fillStrokeMode == 2)) controls.fillStrokeMode = 2; - if(controls.fillStrokeMode == 1 || controls.fillStrokeMode == 2) + t.gui.slider_scalar_field("relradiuswidth", "Corner Radius", &relativeRadiusWidth, 0.0f, 40.0f); + if(t.gui.radio_button_field("fillonly", "Fill only", fillStrokeMode == 0)) fillStrokeMode = 0; + if(t.gui.radio_button_field("outlineonly", "Outline only", fillStrokeMode == 1)) fillStrokeMode = 1; + if(t.gui.radio_button_field("filloutline", "Fill and Outline", fillStrokeMode == 2)) fillStrokeMode = 2; + if(fillStrokeMode == 1 || fillStrokeMode == 2) t.gui.slider_scalar_field("relstrokewidth", "Outline Size", &drawP.controls.relativeWidth, 3.0f, 40.0f); t.gui.pop_id(); } @@ -34,51 +34,49 @@ bool RectDrawTool::right_click_popup_gui(Vector2f popupPos) { void RectDrawTool::switch_tool(DrawingProgramToolType newTool) { commit_rectangle(); - controls.drawStage = 0; + drawStage = 0; } void RectDrawTool::tool_update() { - switch(controls.drawStage) { + switch(drawStage) { case 0: { if(drawP.controls.leftClick) { - controls.startAt = drawP.world.main.input.mouse.pos; - controls.intermediateItem = std::make_shared(); - controls.intermediateItem->d.strokeColor = drawP.controls.foregroundColor; - controls.intermediateItem->d.fillColor = drawP.controls.backgroundColor; - controls.intermediateItem->d.cornerRadius = controls.relativeRadiusWidth; - controls.intermediateItem->d.strokeWidth = drawP.controls.relativeWidth; - controls.intermediateItem->d.p1 = controls.startAt; - controls.intermediateItem->d.p2 = controls.startAt; - controls.intermediateItem->d.p2 = ensure_points_have_distance(controls.intermediateItem->d.p1, controls.intermediateItem->d.p2, MINIMUM_DISTANCE_BETWEEN_BOUNDS); - controls.intermediateItem->d.fillStrokeMode = static_cast(controls.fillStrokeMode); - controls.intermediateItem->coords = drawP.world.drawData.cam.c; - controls.intermediateItem->lastUpdateTime = std::chrono::steady_clock::now(); - uint64_t placement = drawP.components.client_list().size(); - auto objAdd = drawP.components.client_insert(placement, controls.intermediateItem); - controls.intermediateItem->commit_update(drawP); - controls.intermediateItem->client_send_place(drawP); - drawP.add_undo_place_component(objAdd); - controls.drawStage = 1; + CanvasComponentContainer* newContainer = new CanvasComponentContainer(drawP.world.netObjMan, CanvasComponent::CompType::RECTANGLE); + RectangleCanvasComponent& newRectangle = static_cast(newContainer->get_comp()); + + startAt = drawP.world.main.input.mouse.pos; + newRectangle.d.strokeColor = drawP.controls.foregroundColor; + newRectangle.d.fillColor = drawP.controls.backgroundColor; + newRectangle.d.cornerRadius = relativeRadiusWidth; + newRectangle.d.strokeWidth = drawP.controls.relativeWidth; + newRectangle.d.p1 = startAt; + newRectangle.d.p2 = startAt; + newRectangle.d.p2 = ensure_points_have_distance(newRectangle.d.p1, newRectangle.d.p2, MINIMUM_DISTANCE_BETWEEN_BOUNDS); + newRectangle.d.fillStrokeMode = static_cast(fillStrokeMode); + newContainer->coords = drawP.world.drawData.cam.c; + intermediateContainer = drawP.components->push_back_and_send_create(drawP.components, newContainer)->obj; + drawStage = 1; } break; } case 1: { - if(drawP.controls.leftClickHeld) { - controls.intermediateItem->lastUpdateTime = std::chrono::steady_clock::now(); - Vector2f newPos = controls.intermediateItem->coords.get_mouse_pos(drawP.world); + NetworkingObjects::NetObjTemporaryPtr containerPtr = intermediateContainer.lock(); + if(drawP.controls.leftClickHeld && containerPtr) { + Vector2f newPos = containerPtr->coords.get_mouse_pos(drawP.world); if(drawP.world.main.input.key(InputManager::KEY_GENERIC_LSHIFT).held) { - float height = std::fabs(controls.startAt.y() - newPos.y()); - newPos.x() = controls.startAt.x() + (((newPos.x() - controls.startAt.x()) < 0.0f ? -1.0f : 1.0f) * height); + float height = std::fabs(startAt.y() - newPos.y()); + newPos.x() = startAt.x() + (((newPos.x() - startAt.x()) < 0.0f ? -1.0f : 1.0f) * height); } - controls.intermediateItem->d.p1 = cwise_vec_min(controls.startAt, newPos); - controls.intermediateItem->d.p2 = cwise_vec_max(controls.startAt, newPos); - controls.intermediateItem->d.p2 = ensure_points_have_distance(controls.intermediateItem->d.p1, controls.intermediateItem->d.p2, MINIMUM_DISTANCE_BETWEEN_BOUNDS); - controls.intermediateItem->client_send_update(drawP, false); - controls.intermediateItem->commit_update(drawP); + RectangleCanvasComponent& rectangle = static_cast(containerPtr->get_comp()); + rectangle.d.p1 = cwise_vec_min(startAt, newPos); + rectangle.d.p2 = cwise_vec_max(startAt, newPos); + rectangle.d.p2 = ensure_points_have_distance(rectangle.d.p1, rectangle.d.p2, MINIMUM_DISTANCE_BETWEEN_BOUNDS); + containerPtr->send_comp_update(drawP, true); + containerPtr->commit_update(drawP); } else { commit_rectangle(); - controls.drawStage = 0; + drawStage = 0; } break; } @@ -86,15 +84,16 @@ void RectDrawTool::tool_update() { } bool RectDrawTool::prevent_undo_or_redo() { - return controls.intermediateItem != nullptr; + return (drawStage == 1); } void RectDrawTool::commit_rectangle() { - if(controls.intermediateItem && controls.intermediateItem->collabListInfo.lock()) { - controls.intermediateItem->client_send_update(drawP, true); - controls.intermediateItem->commit_update(drawP); + NetworkingObjects::NetObjTemporaryPtr lockedPtr = intermediateContainer.lock(); + if(lockedPtr) { + lockedPtr->commit_update(drawP); + drawP.world.delayedUpdateObjectManager.send_update_to_all(lockedPtr, true); } - controls.intermediateItem = nullptr; + intermediateContainer.reset(); } void RectDrawTool::draw(SkCanvas* canvas, const DrawData& drawData) { diff --git a/src/DrawingProgram/RectDrawTool.hpp b/src/DrawingProgram/RectDrawTool.hpp index 73c7ab6..30f4dab 100644 --- a/src/DrawingProgram/RectDrawTool.hpp +++ b/src/DrawingProgram/RectDrawTool.hpp @@ -1,8 +1,7 @@ #pragma once #include "DrawingProgramToolBase.hpp" -#include "../DrawComponents/DrawRectangle.hpp" #include -#include +#include "../CanvasComponents/CanvasComponentContainer.hpp" class DrawingProgram; @@ -19,11 +18,9 @@ class RectDrawTool : public DrawingProgramToolBase { private: void commit_rectangle(); - struct RectDrawControls { - Vector2f startAt; - float relativeRadiusWidth = 10.0f; - int fillStrokeMode = 1; - int drawStage = 0; - std::shared_ptr intermediateItem; - } controls; + Vector2f startAt; + float relativeRadiusWidth = 10.0f; + int fillStrokeMode = 1; + int drawStage = 0; + NetworkingObjects::NetObjWeakPtr intermediateContainer; }; diff --git a/src/Server/CommandList.hpp b/src/Server/CommandList.hpp index bd501fc..bf4f067 100644 --- a/src/Server/CommandList.hpp +++ b/src/Server/CommandList.hpp @@ -12,9 +12,6 @@ enum ServerCommands : MessageCommandType { SERVER_PLACE_SINGLE_COMPONENT, SERVER_PLACE_MANY_COMPONENTS, SERVER_TRANSFORM_MANY_COMPONENTS, - SERVER_ERASE_SINGLE_COMPONENT, - SERVER_ERASE_MANY_COMPONENTS, - SERVER_UPDATE_COMPONENT, SERVER_NEW_RESOURCE_ID, SERVER_NEW_RESOURCE_DATA, SERVER_CHAT_MESSAGE, @@ -29,12 +26,7 @@ enum ClientCommands : MessageCommandType { CLIENT_UPDATE_NETWORK_OBJECT, CLIENT_USER_CONNECT, CLIENT_USER_DISCONNECT, - CLIENT_PLACE_SINGLE_COMPONENT, - CLIENT_PLACE_MANY_COMPONENTS, CLIENT_TRANSFORM_MANY_COMPONENTS, - CLIENT_ERASE_SINGLE_COMPONENT, - CLIENT_ERASE_MANY_COMPONENTS, - CLIENT_UPDATE_COMPONENT, CLIENT_MOVE_CAMERA, CLIENT_MOVE_SCREEN_MOUSE, CLIENT_NEW_RESOURCE_ID, diff --git a/src/Server/MainServer.cpp b/src/Server/MainServer.cpp index 292af93..4ef5601 100644 --- a/src/Server/MainServer.cpp +++ b/src/Server/MainServer.cpp @@ -3,9 +3,6 @@ #include "Helpers/HsvRgb.hpp" #include "Helpers/Networking/NetLibrary.hpp" #include "ServerData.hpp" -#include "../DrawComponents/DrawBrushStroke.hpp" -#include "../DrawComponents/DrawRectangle.hpp" -#include "../DrawComponents/DrawEllipse.hpp" #include "../SharedTypes.hpp" #include "../CoordSpaceHelper.hpp" #include @@ -19,17 +16,11 @@ #include #include #include -#include "../DrawComponents/DrawComponent.hpp" #include "../World.hpp" MainServer::MainServer(World& initWorld, const std::string& serverLocalID): world(initWorld) { - for(auto& c : world.drawProg.components.client_list()) { - data.components.emplace_back(c->obj->copy(world.drawProg)); - data.components.back()->id = c->obj->id; - data.idToComponentMap.emplace(data.components.back()->id, data.components.back()); - } data.canvasScale = world.canvasScale; data.resources = world.rMan.resource_list(); data.canvasBackColor = convert_vec3(world.canvasTheme.backColor); @@ -97,116 +88,6 @@ MainServer::MainServer(World& initWorld, const std::string& serverLocalID): message(c.cursorPos); netServer->send_items_to_all_clients_except(client, UNRELIABLE_COMMAND_CHANNEL, CLIENT_MOVE_SCREEN_MOUSE, c.serverID, c.cursorPos); }); - netServer->add_recv_callback(SERVER_PLACE_SINGLE_COMPONENT, [&](std::shared_ptr client, cereal::PortableBinaryInputArchive& message) { - uint64_t placement; - DrawComponentType type; - message(placement, type); - auto newComp = DrawComponent::allocate_comp_type(type); - message(newComp->id, newComp->coords, *newComp); - placement = std::min(placement, data.components.size()); - data.components.insert(data.components.begin() + placement, newComp); - data.idToComponentMap.emplace(newComp->id, newComp); - - auto& c = clients[client->customID]; - if(c.canvasScale < data.canvasScale) - newComp->scale_up(FixedPoint::pow_int(CANVAS_SCALE_UP_STEP, data.canvasScale - c.canvasScale)); - - newComp->server_send_place(*this, placement); - }); - netServer->add_recv_callback(SERVER_PLACE_MANY_COMPONENTS, [&](std::shared_ptr client, cereal::PortableBinaryInputArchive& message) { - std::vector objOrderedVector; - SendOrderedComponentVectorOp a{&objOrderedVector}; - message(a); - - std::vector> objOrderedComponentPairs; - for(auto& o : objOrderedVector) - objOrderedComponentPairs.emplace_back(o->obj); - - uint64_t startPoint = 0; - - if(objOrderedVector.empty()) - return; - - data.idToComponentMap.emplace(objOrderedVector.front()->obj->id, objOrderedVector.front()->obj); - - for(uint64_t i = 1; i < static_cast(objOrderedVector.size()); i++) { - auto& obj = objOrderedVector[i]; - data.idToComponentMap.emplace(obj->obj->id, obj->obj); - if(obj->pos - objOrderedVector[startPoint]->pos != (i - startPoint)) { - uint64_t insertPosition = std::min(data.components.size(), objOrderedVector[startPoint]->pos); - data.components.insert(data.components.begin() + insertPosition, objOrderedComponentPairs.begin() + startPoint, objOrderedComponentPairs.begin() + i); - startPoint = i; - } - } - - data.components.insert(data.components.begin() + std::min(data.components.size(), objOrderedVector[startPoint]->pos), objOrderedComponentPairs.begin() + startPoint, objOrderedComponentPairs.end()); - - startPoint = 0; - - for(uint64_t i = 0; i < data.components.size(); i++) { - if(startPoint >= objOrderedVector.size()) - break; - auto& c = data.components[i]; - auto& o = objOrderedVector[startPoint]; - if(c == o->obj) { - o->pos = i; - startPoint++; - } - } - - auto& c = clients[client->customID]; - if(c.canvasScale < data.canvasScale) { - for(auto& o : objOrderedVector) - o->obj->scale_up(FixedPoint::pow_int(CANVAS_SCALE_UP_STEP, data.canvasScale - c.canvasScale)); - } - - DrawComponent::server_send_place_many(*this, objOrderedVector); - }); - netServer->add_recv_callback(SERVER_ERASE_SINGLE_COMPONENT, [&](std::shared_ptr client, cereal::PortableBinaryInputArchive& message) { - ServerClientID compToRemove; - message(compToRemove); - DrawComponent::server_send_erase(*this, compToRemove); - data.idToComponentMap.erase(compToRemove); - std::erase_if(data.components, [&](auto& p) { - return p->id == compToRemove; - }); - }); - netServer->add_recv_callback(SERVER_ERASE_MANY_COMPONENTS, [&](std::shared_ptr client, cereal::PortableBinaryInputArchive& message) { - std::unordered_set idsToRemove; - message(idsToRemove); - DrawComponent::server_send_erase_set(*this, idsToRemove); - for(auto& id : idsToRemove) - data.idToComponentMap.erase(id); - std::erase_if(data.components, [&](auto& p) { - return idsToRemove.contains(p->id); - }); - }); - netServer->add_recv_callback(SERVER_TRANSFORM_MANY_COMPONENTS, [&](std::shared_ptr client, cereal::PortableBinaryInputArchive& message) { - std::vector> transformsToSend; - message(transformsToSend); - for(auto& t : transformsToSend) { - auto it = data.idToComponentMap.find(t.first); - if(it != data.idToComponentMap.end()) - it->second->coords = t.second; - } - auto& c = clients[client->customID]; - if(c.canvasScale < data.canvasScale) { - for(auto& [id, coord] : transformsToSend) - coord.scale_about(WorldVec{0, 0}, FixedPoint::pow_int(CANVAS_SCALE_UP_STEP, data.canvasScale - c.canvasScale), true); - } - DrawComponent::server_send_transform_many(*this, transformsToSend); - }); - netServer->add_recv_callback(SERVER_UPDATE_COMPONENT, [&](std::shared_ptr client, cereal::PortableBinaryInputArchive& message) { - bool isFinalUpdate; - ServerClientID idToUpdate; - message(isFinalUpdate, idToUpdate); - auto it = data.idToComponentMap.find(idToUpdate); - if(it != data.idToComponentMap.end()) { - std::shared_ptr& comp = it->second; - message(*comp); - comp->server_send_update(*this, isFinalUpdate); - } - }); netServer->add_recv_callback(SERVER_NEW_RESOURCE_ID, [&](std::shared_ptr client, cereal::PortableBinaryInputArchive& message) { auto& c = clients[client->customID]; message(c.pendingResourceID); diff --git a/src/Server/ServerData.hpp b/src/Server/ServerData.hpp index 2bd12e3..7594023 100644 --- a/src/Server/ServerData.hpp +++ b/src/Server/ServerData.hpp @@ -8,8 +8,6 @@ class DrawComponent; class ServerData { public: - std::vector> components; - std::unordered_map> idToComponentMap; std::unordered_map resources; uint64_t canvasScale = 0; Vector3f canvasBackColor; diff --git a/src/World.cpp b/src/World.cpp index af0a8b0..40f3647 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -1,5 +1,4 @@ #include "World.hpp" -#include "DrawComponents/DrawComponent.hpp" #include #include #include @@ -14,7 +13,7 @@ #include "Toolbar.hpp" #include "VersionConstants.hpp" #include "WorldGrid.hpp" -#include "cereal/archives/portable_binary.hpp" +#include #include #include "FileHelpers.hpp" #include "FontData.hpp" @@ -24,6 +23,8 @@ #include #include #include +#include "CanvasComponents/CanvasComponentContainer.hpp" +#include "CanvasComponents/CanvasComponentAllocator.hpp" #ifdef __EMSCRIPTEN__ #include @@ -40,6 +41,7 @@ World::World(MainProgram& initMain, OpenWorldInfo& worldInfo): init_net_obj_type_list(); gridMan.init(); bMan.init(); + drawProg.init(); set_canvas_background_color(main.defaultCanvasBackgroundColor); displayName = main.displayName; @@ -82,6 +84,8 @@ void World::init_net_obj_type_list() { NetworkingObjects::register_ordered_list_class(netObjMan); delayedUpdateObjectManager.register_class(netObjMan); NetworkingObjects::register_ordered_list_class(netObjMan); + CanvasComponentAllocator::register_class(delayedUpdateObjectManager, netObjMan); + CanvasComponentContainer::register_class(netObjMan); } void World::init_client_callbacks() { @@ -99,7 +103,7 @@ void World::init_client_callbacks() { message(newBackColor); set_canvas_background_color(newBackColor, false); message(canvasScale); - drawProg.initialize_draw_data(message); + //drawProg.initialize_draw_data(message); bMan.bookmarks = netObjMan.read_create_message>(message, nullptr); gridMan.grids = netObjMan.read_create_message>(message, nullptr); } @@ -302,7 +306,6 @@ void World::start_hosting(const std::string& initNetSource, const std::string& s con.client_send_items_to_server(RELIABLE_COMMAND_CHANNEL, SERVER_INITIAL_DATA, displayName, true, drawData.cam.c, main.window.size.cast().eval()); conType = CONNECTIONTYPE_SERVER; netSource = initNetSource; - drawProg.components.set_server_from_client_list(); clientStillConnecting = true; } @@ -387,7 +390,7 @@ void World::load_from_file(const std::filesystem::path& filePathToLoadFrom, std: } ClientPortionID World::get_max_id(ServerPortionID serverID) { - return std::max(rMan.get_max_id(serverID), drawProg.get_max_id(serverID)); + return rMan.get_max_id(serverID); } void World::save_file(cereal::PortableBinaryOutputArchive& a) const {