diff --git a/CMakeLists.txt b/CMakeLists.txt index 2d133ec..01623f4 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -134,6 +134,8 @@ if((NOT EMSCRIPTEN) AND (NOT APPLE)) find_package(TBB REQUIRED) endif() +find_package(zstd REQUIRED) + message("Skia root: " ${SKIA_INCLUDE}) message("Build type: " ${CMAKE_BUILD_TYPE}) @@ -236,7 +238,7 @@ if((NOT EMSCRIPTEN) AND (NOT APPLE)) endif() endif() -target_link_libraries(infinipaint SDL3::SDL3) +target_link_libraries(infinipaint SDL3::SDL3 zstd::libzstd_static) if(EMSCRIPTEN) add_subdirectory(deps/datachannel-wasm EXCLUDE_FROM_ALL) diff --git a/conanfile.py b/conanfile.py index ccf5ffa..3f2b531 100644 --- a/conanfile.py +++ b/conanfile.py @@ -52,7 +52,9 @@ class CompressorRecipe(ConanFile): if self.settings.os != "Emscripten": self.requires("libdatachannel/0.23.1") - + + self.requires("zstd/1.5.7") + def build_requirements(self): self.tool_requires("cmake/3.27.0") diff --git a/include/Helpers/Networking/ByteStream.cpp b/include/Helpers/Networking/ByteStream.cpp index 2971f7c..ee8a464 100644 --- a/include/Helpers/Networking/ByteStream.cpp +++ b/include/Helpers/Networking/ByteStream.cpp @@ -2,6 +2,7 @@ #include #include #include "NetLibrary.hpp" +#include ByteMemBuf::ByteMemBuf(char* p, size_t l) { setg(p, p, p + l); @@ -15,16 +16,30 @@ ByteMemStream::ByteMemStream(char* p, size_t l): rdbuf(&buffer); } -std::vector> fragment_message(std::string_view v, uint64_t stride) { - if(v.length() <= stride) +std::vector> fragment_message(std::string_view uncompressedView, uint64_t stride) { + if(uncompressedView.length() <= stride) return {}; + + std::vector compressedData(ZSTD_compressBound(uncompressedView.size())); + size_t trueCompressedSize = ZSTD_compress(compressedData.data(), compressedData.size(), uncompressedView.data(), uncompressedView.size(), ZSTD_CLEVEL_DEFAULT); + + std::string_view v(compressedData.data(), trueCompressedSize); + uint64_t nextByte = 0; std::vector> toRet; + toRet.emplace_back(std::make_shared()); + + size_t messFirstStride = std::min(stride, v.size()); + { cereal::PortableBinaryOutputArchive m(*toRet.back()); - m((MessageCommandType)0, (uint64_t)v.length(), cereal::binary_data(v.data() + nextByte, stride)); + m((MessageCommandType)0, (uint64_t)v.length(), cereal::binary_data(v.data() + nextByte, messFirstStride)); } + + if(messFirstStride == v.size()) + return toRet; + nextByte += stride; for(;;) { if((v.length() - nextByte) <= stride) { @@ -44,3 +59,39 @@ std::vector> fragment_message(std::string_vie } return toRet; } + +void uncompress_and_run_func(PartialFragmentMessage& spfm, std::function runAfterDecoded) { + std::vector uncompressedData(ZSTD_getFrameContentSize(spfm.partialFragmentMessage.data(), spfm.partialFragmentMessage.size())); + size_t trueUncompressedSize = ZSTD_decompress(uncompressedData.data(), uncompressedData.size(), spfm.partialFragmentMessage.data(), spfm.partialFragmentMessage.size()); + + ByteMemStream completeStrm(uncompressedData.data(), trueUncompressedSize); + cereal::PortableBinaryInputArchive completeArchive(completeStrm); + runAfterDecoded(completeArchive); + spfm.partialFragmentMessage.clear(); + spfm.partialFragmentMessageLoc = 0; +} + +void decode_fragmented_message(cereal::PortableBinaryInputArchive& inArchive, PartialFragmentMessage& spfm, size_t fragmentMessageStride, std::function runAfterDecoded) { + if(spfm.partialFragmentMessage.size() == 0) { + spfm.partialFragmentMessageLoc = 0; + uint64_t messageSize; + inArchive(messageSize); + spfm.partialFragmentMessage.resize(messageSize); + + size_t messStride = std::min(fragmentMessageStride, spfm.partialFragmentMessage.size()); + + inArchive(cereal::binary_data(spfm.partialFragmentMessage.data() + spfm.partialFragmentMessageLoc, messStride)); + spfm.partialFragmentMessageLoc += messStride; + + if(messStride == spfm.partialFragmentMessage.size()) + uncompress_and_run_func(spfm, runAfterDecoded); + } + else if(spfm.partialFragmentMessage.size() - spfm.partialFragmentMessageLoc <= fragmentMessageStride) { + inArchive(cereal::binary_data(spfm.partialFragmentMessage.data() + spfm.partialFragmentMessageLoc, spfm.partialFragmentMessage.size() - spfm.partialFragmentMessageLoc)); + uncompress_and_run_func(spfm, runAfterDecoded); + } + else { + inArchive(cereal::binary_data(spfm.partialFragmentMessage.data() + spfm.partialFragmentMessageLoc, fragmentMessageStride)); + spfm.partialFragmentMessageLoc += fragmentMessageStride; + } +} diff --git a/include/Helpers/Networking/ByteStream.hpp b/include/Helpers/Networking/ByteStream.hpp index 84528ed..814d772 100644 --- a/include/Helpers/Networking/ByteStream.hpp +++ b/include/Helpers/Networking/ByteStream.hpp @@ -3,6 +3,7 @@ #include #include #include +#include // https://tuttlem.github.io/2014/08/18/getting-istream-to-work-off-a-byte-array.html class ByteMemBuf : public std::basic_streambuf { @@ -16,4 +17,10 @@ class ByteMemStream : public std::istream { ByteMemBuf buffer; }; -std::vector> fragment_message(std::string_view v, uint64_t stride); +struct PartialFragmentMessage { + std::string partialFragmentMessage; + uint64_t partialFragmentMessageLoc = 0; +}; + +std::vector> fragment_message(std::string_view uncompressedView, uint64_t stride); +void decode_fragmented_message(cereal::PortableBinaryInputArchive& inArchive, PartialFragmentMessage& spfm, size_t fragmentMessageStride, std::function runAfterDecoded); diff --git a/include/Helpers/Networking/NetClient.cpp b/include/Helpers/Networking/NetClient.cpp index 611e303..3ca51b6 100644 --- a/include/Helpers/Networking/NetClient.cpp +++ b/include/Helpers/Networking/NetClient.cpp @@ -80,28 +80,11 @@ void NetClient::parse_received_messages() { inArchive(commandID); if(commandID == 0) { - if(spfm.partialFragmentMessage.size() == 0) { - spfm.partialFragmentMessageLoc = 0; - uint64_t messageSize; - inArchive(messageSize); - spfm.partialFragmentMessage.resize(messageSize); - inArchive(cereal::binary_data(spfm.partialFragmentMessage.data() + spfm.partialFragmentMessageLoc, NetLibrary::FRAGMENT_MESSAGE_STRIDE)); - spfm.partialFragmentMessageLoc += NetLibrary::FRAGMENT_MESSAGE_STRIDE; - } - else if(spfm.partialFragmentMessage.size() - spfm.partialFragmentMessageLoc <= NetLibrary::FRAGMENT_MESSAGE_STRIDE) { - inArchive(cereal::binary_data(spfm.partialFragmentMessage.data() + spfm.partialFragmentMessageLoc, spfm.partialFragmentMessage.size() - spfm.partialFragmentMessageLoc)); - ByteMemStream completeStrm(spfm.partialFragmentMessage.data(), spfm.partialFragmentMessage.size()); - cereal::PortableBinaryInputArchive completeArchive(completeStrm); + decode_fragmented_message(inArchive, spfm, NetLibrary::FRAGMENT_MESSAGE_STRIDE, [&](cereal::PortableBinaryInputArchive& completeArchive) { MessageCommandType completeCommandID; completeArchive(completeCommandID); recvCallbacks[completeCommandID](completeArchive); - spfm.partialFragmentMessage.clear(); - spfm.partialFragmentMessageLoc = 0; - } - else { - inArchive(cereal::binary_data(spfm.partialFragmentMessage.data() + spfm.partialFragmentMessageLoc, NetLibrary::FRAGMENT_MESSAGE_STRIDE)); - spfm.partialFragmentMessageLoc += NetLibrary::FRAGMENT_MESSAGE_STRIDE; - } + }); } else recvCallbacks[commandID](inArchive); diff --git a/include/Helpers/Networking/NetClient.hpp b/include/Helpers/Networking/NetClient.hpp index 7f9ace8..374d131 100644 --- a/include/Helpers/Networking/NetClient.hpp +++ b/include/Helpers/Networking/NetClient.hpp @@ -59,10 +59,6 @@ class NetClient : public std::enable_shared_from_this { std::unordered_map> channels; - struct PartialFragmentMessage { - std::string partialFragmentMessage; - uint64_t partialFragmentMessageLoc = 0; - }; std::unordered_map pfm; std::unordered_map recvCallbacks; diff --git a/include/Helpers/Networking/NetServer.cpp b/include/Helpers/Networking/NetServer.cpp index 2c7987f..ffddb0a 100644 --- a/include/Helpers/Networking/NetServer.cpp +++ b/include/Helpers/Networking/NetServer.cpp @@ -1,10 +1,12 @@ #include "NetServer.hpp" +#include "Helpers/Networking/ByteStream.hpp" #include "NetLibrary.hpp" #include #include #include #include #include "NetClient.hpp" +#include "cereal/archives/portable_binary.hpp" NetServer::NetServer(const std::string& serverLocalID) { localID = serverLocalID; @@ -163,28 +165,11 @@ void NetServer::ClientData::parse_received_messages(NetServer& server) { inArchive(commandID); if(commandID == 0) { - if(spfm.partialFragmentMessage.size() == 0) { - spfm.partialFragmentMessageLoc = 0; - uint64_t messageSize; - inArchive(messageSize); - spfm.partialFragmentMessage.resize(messageSize); - inArchive(cereal::binary_data(spfm.partialFragmentMessage.data() + spfm.partialFragmentMessageLoc, NetLibrary::FRAGMENT_MESSAGE_STRIDE)); - spfm.partialFragmentMessageLoc += NetLibrary::FRAGMENT_MESSAGE_STRIDE; - } - else if(spfm.partialFragmentMessage.size() - spfm.partialFragmentMessageLoc <= NetLibrary::FRAGMENT_MESSAGE_STRIDE) { - inArchive(cereal::binary_data(spfm.partialFragmentMessage.data() + spfm.partialFragmentMessageLoc, spfm.partialFragmentMessage.size() - spfm.partialFragmentMessageLoc)); - ByteMemStream completeStrm(spfm.partialFragmentMessage.data(), spfm.partialFragmentMessage.size()); - cereal::PortableBinaryInputArchive completeArchive(completeStrm); + decode_fragmented_message(inArchive, spfm, NetLibrary::FRAGMENT_MESSAGE_STRIDE, [&](cereal::PortableBinaryInputArchive& completeArchive) { MessageCommandType completeCommandID; completeArchive(completeCommandID); server.recvCallbacks[completeCommandID](shared_from_this(), completeArchive); - spfm.partialFragmentMessage.clear(); - spfm.partialFragmentMessageLoc = 0; - } - else { - inArchive(cereal::binary_data(spfm.partialFragmentMessage.data() + spfm.partialFragmentMessageLoc, NetLibrary::FRAGMENT_MESSAGE_STRIDE)); - spfm.partialFragmentMessageLoc += NetLibrary::FRAGMENT_MESSAGE_STRIDE; - } + }); } else server.recvCallbacks[commandID](shared_from_this(), inArchive); diff --git a/include/Helpers/Networking/NetServer.hpp b/include/Helpers/Networking/NetServer.hpp index ca268e5..cf61488 100644 --- a/include/Helpers/Networking/NetServer.hpp +++ b/include/Helpers/Networking/NetServer.hpp @@ -17,10 +17,6 @@ class NetServer : public std::enable_shared_from_this { typedef std::function)> NetServerDisconnectCallback; struct ClientData : public std::enable_shared_from_this { std::unordered_map>> messages; - struct PartialFragmentMessage { - std::string partialFragmentMessage; - uint64_t partialFragmentMessageLoc = 0; - }; std::unordered_map pfm; MessageOrder nextMessageOrderToSend = 0; diff --git a/src/DrawComponents/DrawBrushStroke.cpp b/src/DrawComponents/DrawBrushStroke.cpp index 596fe7d..a346f05 100644 --- a/src/DrawComponents/DrawBrushStroke.cpp +++ b/src/DrawComponents/DrawBrushStroke.cpp @@ -344,15 +344,14 @@ void DrawBrushStroke::create_collider() { return false; }, points, 0); strokeObjects.recalculate_bounds(); - collisionTree.clear(); + + SCollision::BVHContainer collisionTree; + collisionTree.calculate_bvh_recursive(strokeObjects); precheckAABBLevels.clear(); add_precheck_aabb_level(0, collisionTree.children); - collisionTree.objects.aabb.clear(); - collisionTree.objects.circle.clear(); - collisionTree.objects.triangle.clear(); - collisionTree.children.clear(); + bounds = collisionTree.objects.bounds; calculate_world_bounds(); } @@ -377,7 +376,7 @@ void DrawBrushStroke::update(DrawingProgram& drawP) { } bool DrawBrushStroke::collides_within_coords(const SCollision::ColliderCollection& checkAgainst) { - if(!SCollision::collide(checkAgainst, collisionTree.objects.bounds)) + if(!SCollision::collide(checkAgainst, bounds)) return false; bool deepPrecheck = false; @@ -400,7 +399,7 @@ bool DrawBrushStroke::collides_within_coords(const SCollision::ColliderCollectio } SCollision::AABB DrawBrushStroke::get_obj_coord_bounds() const { - return collisionTree.objects.bounds; + return bounds; } #endif diff --git a/src/DrawComponents/DrawBrushStroke.hpp b/src/DrawComponents/DrawBrushStroke.hpp index 55f4589..015f492 100644 --- a/src/DrawComponents/DrawBrushStroke.hpp +++ b/src/DrawComponents/DrawBrushStroke.hpp @@ -45,7 +45,7 @@ class DrawBrushStroke : public DrawComponent { sk_sp vertices; std::array, 3> verticesMipMap; - SCollision::BVHContainer collisionTree; + SCollision::AABB bounds; private: void add_precheck_aabb_level(size_t level, const std::vector>& levelArray);