diff --git a/CMakeLists.txt b/CMakeLists.txt index 6a987b4..68d6ca6 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -51,6 +51,7 @@ set(sources "src/main.cpp" "src/ResourceDisplay/ImageResourceDisplay.cpp" "src/ResourceDisplay/FileResourceDisplay.cpp" "src/Server/MainServer.cpp" + "src/Server/ServerData.cpp" "src/CollabTextBox/CollabTextBox.cpp" "src/CollabTextBox/CollabTextBoxShaper.cpp" "src/DrawingProgram/DrawingProgramCache.cpp" diff --git a/include/Helpers/FixedPoint.hpp b/include/Helpers/FixedPoint.hpp index 27ca0ea..e11bd61 100644 --- a/include/Helpers/FixedPoint.hpp +++ b/include/Helpers/FixedPoint.hpp @@ -105,6 +105,15 @@ namespace FixedPoint { return toRet; } + template T pow_int(const T& x, uint64_t exp) { + if(exp == 0) + return T(1); + T toRet = x; + for(uint64_t i = 1; i < exp; i++) + toRet *= toRet; + return toRet; + } + // https://github.com/Koishi-Satori/EirinFixed/blob/main/include/eirin/math.hpp template T log2(const T& a) { typename T::UnderlyingType b(typename T::UnderlyingType(1u) << (a.bit_fraction_count() - 1)); diff --git a/src/BookmarkManager.cpp b/src/BookmarkManager.cpp index e2a725f..d9f9d56 100644 --- a/src/BookmarkManager.cpp +++ b/src/BookmarkManager.cpp @@ -5,6 +5,10 @@ #include "MainProgram.hpp" #include +void Bookmark::scale_up(const WorldScalar& scaleUpAmount) { + coords.scale_about(WorldVec{0, 0}, scaleUpAmount, true); +} + BookmarkManager::BookmarkManager(World& w): world(w) {} @@ -63,5 +67,5 @@ const std::unordered_map& BookmarkManager::bookmark_list( void BookmarkManager::scale_up(const WorldScalar& scaleUpAmount) { for(auto& [n, b] : bookmarks) - b.coords.scale_about(WorldVec{0, 0}, scaleUpAmount, true); + b.scale_up(scaleUpAmount); } diff --git a/src/BookmarkManager.hpp b/src/BookmarkManager.hpp index 78c7e02..8747c01 100644 --- a/src/BookmarkManager.hpp +++ b/src/BookmarkManager.hpp @@ -10,6 +10,7 @@ struct Bookmark { template void serialize(Archive& a) { a(coords, windowSize); } + void scale_up(const WorldScalar& scaleUpAmount); }; class World; diff --git a/src/DrawCamera.cpp b/src/DrawCamera.cpp index 55eea64..8747c3d 100755 --- a/src/DrawCamera.cpp +++ b/src/DrawCamera.cpp @@ -3,6 +3,7 @@ #include "Helpers/FixedPoint.hpp" #include "Helpers/MathExtras.hpp" #include "MainProgram.hpp" +#include "Server/CommandList.hpp" #include "World.hpp" #include "InputManager.hpp" #include @@ -154,8 +155,6 @@ void DrawCamera::update_main(World& w) { set_viewing_area(w.main.window.size.cast()); - if(c.inverseScale < WorldScalar(1)) { - std::cout << "yes!" << std::endl; - w.scale_up(WorldScalar(1000000)); - } + if(c.inverseScale < WorldScalar(1)) + w.scale_up_step(); } diff --git a/src/DrawingProgram/DrawingProgram.cpp b/src/DrawingProgram/DrawingProgram.cpp index 519cfe1..1b7e744 100644 --- a/src/DrawingProgram/DrawingProgram.cpp +++ b/src/DrawingProgram/DrawingProgram.cpp @@ -152,6 +152,7 @@ void DrawingProgram::scale_up(const WorldScalar& scaleUpAmount) { 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() { diff --git a/src/Server/ClientData.hpp b/src/Server/ClientData.hpp index 1562656..7285d34 100644 --- a/src/Server/ClientData.hpp +++ b/src/Server/ClientData.hpp @@ -18,6 +18,8 @@ class ClientData { std::string displayName; ServerPortionID serverID = 0; + uint64_t canvasScale = 0; + std::queue pendingResourceData; std::queue pendingResourceID; diff --git a/src/Server/CommandList.hpp b/src/Server/CommandList.hpp index 315e065..c348223 100644 --- a/src/Server/CommandList.hpp +++ b/src/Server/CommandList.hpp @@ -20,7 +20,8 @@ enum ServerCommands : MessageCommandType { SERVER_REMOVE_BOOKMARK, SERVER_CANVAS_COLOR, SERVER_SET_GRID, - SERVER_REMOVE_GRID + SERVER_REMOVE_GRID, + SERVER_CANVAS_SCALE }; enum ClientCommands : MessageCommandType { @@ -42,7 +43,8 @@ enum ClientCommands : MessageCommandType { CLIENT_REMOVE_BOOKMARK, CLIENT_CANVAS_COLOR, CLIENT_SET_GRID, - CLIENT_REMOVE_GRID + CLIENT_REMOVE_GRID, + CLIENT_CANVAS_SCALE }; // NOTE: Do not change savefile header length @@ -53,3 +55,6 @@ enum ClientCommands : MessageCommandType { #define SAVEFILE_HEADER_V1 "INFPNT000001" // Version header #define VERSION_STRING "0.2.0" + +// Arbitrary value. Higher scale up values lead to less scale up events (which can cause stuttering), but leads to larger numbers overall, which can cause a tiny bit of lag and increased memory usage +#define CANVAS_SCALE_UP_STEP WorldScalar("100000000000000000000000000000000000000000000000000") diff --git a/src/Server/MainServer.cpp b/src/Server/MainServer.cpp index e126991..6d5129f 100644 --- a/src/Server/MainServer.cpp +++ b/src/Server/MainServer.cpp @@ -22,31 +22,6 @@ #include "../DrawComponents/DrawComponent.hpp" #include "../World.hpp" -WorldVec cursorPos; - -void ServerData::save(cereal::PortableBinaryOutputArchive& a) const { - a(canvasBackColor); - a((uint64_t)components.size()); - for(uint64_t i = 0; i < components.size(); i++) - a(components[i]->get_type(), components[i]->id, components[i]->coords, *components[i]); - a(bookmarks, grids); -} - -void ServerData::load(cereal::PortableBinaryInputArchive& a) { - a(canvasBackColor); - 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.emplace_back(newComp); - idToComponentMap.emplace(newComp->id, newComp); - } - a(bookmarks, grids); -} - MainServer::MainServer(World& initWorld, const std::string& serverLocalID): world(initWorld) { @@ -55,6 +30,7 @@ MainServer::MainServer(World& initWorld, const std::string& serverLocalID): data.components.back()->id = c->obj->id; data.idToComponentMap.emplace(data.components.back()->id, data.components.back()); } + data.canvasScale = world.canvasScale; data.bookmarks = world.bMan.bookmark_list(); data.grids = world.gridMan.grids; data.resources = world.rMan.resource_list(); @@ -105,6 +81,11 @@ MainServer::MainServer(World& initWorld, const std::string& serverLocalID): 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, c.canvasScale - data.canvasScale)); + newComp->server_send_place(*this, placement); }); netServer->add_recv_callback(SERVER_PLACE_MANY_COMPONENTS, [&](std::shared_ptr client, cereal::PortableBinaryInputArchive& message) { @@ -148,6 +129,12 @@ MainServer::MainServer(World& initWorld, const std::string& serverLocalID): } } + 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, c.canvasScale - data.canvasScale)); + } + DrawComponent::server_send_place_many(*this, objOrderedVector); }); netServer->add_recv_callback(SERVER_ERASE_SINGLE_COMPONENT, [&](std::shared_ptr client, cereal::PortableBinaryInputArchive& message) { @@ -177,6 +164,11 @@ MainServer::MainServer(World& initWorld, const std::string& serverLocalID): 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, c.canvasScale - data.canvasScale), true); + } DrawComponent::server_send_transform_many(*this, transformsToSend); }); netServer->add_recv_callback(SERVER_UPDATE_COMPONENT, [&](std::shared_ptr client, cereal::PortableBinaryInputArchive& message) { @@ -226,6 +218,11 @@ MainServer::MainServer(World& initWorld, const std::string& serverLocalID): message(name); Bookmark& b = data.bookmarks[name]; message(b); + + auto& c = clients[client->customID]; + if(c.canvasScale < data.canvasScale) + b.scale_up(FixedPoint::pow_int(CANVAS_SCALE_UP_STEP, c.canvasScale - data.canvasScale)); + netServer->send_items_to_all_clients(RELIABLE_COMMAND_CHANNEL, CLIENT_NEW_BOOKMARK, name, b); }); netServer->add_recv_callback(SERVER_REMOVE_BOOKMARK, [&](std::shared_ptr client, cereal::PortableBinaryInputArchive& message) { @@ -239,6 +236,11 @@ MainServer::MainServer(World& initWorld, const std::string& serverLocalID): message(gID); WorldGrid& g = data.grids[gID]; message(g); + + auto& c = clients[client->customID]; + if(c.canvasScale < data.canvasScale) + g.scale_up(FixedPoint::pow_int(CANVAS_SCALE_UP_STEP, c.canvasScale - data.canvasScale)); + netServer->send_items_to_all_clients(RELIABLE_COMMAND_CHANNEL, CLIENT_SET_GRID, gID, g); }); netServer->add_recv_callback(SERVER_REMOVE_GRID, [&](std::shared_ptr client, cereal::PortableBinaryInputArchive& message) { @@ -251,6 +253,15 @@ MainServer::MainServer(World& initWorld, const std::string& serverLocalID): message(data.canvasBackColor); netServer->send_items_to_all_clients(RELIABLE_COMMAND_CHANNEL, CLIENT_CANVAS_COLOR, data.canvasBackColor); }); + netServer->add_recv_callback(SERVER_CANVAS_SCALE, [&](std::shared_ptr client, cereal::PortableBinaryInputArchive& message) { + auto& c = clients[client->customID]; + message(c.canvasScale); + if(c.canvasScale > data.canvasScale) { + data.scale_up(FixedPoint::pow_int(CANVAS_SCALE_UP_STEP, c.canvasScale - data.canvasScale)); + data.canvasScale = c.canvasScale; + netServer->send_items_to_all_clients(RELIABLE_COMMAND_CHANNEL, CLIENT_CANVAS_SCALE, data.canvasScale); + } + }); netServer->add_recv_callback(SERVER_KEEP_ALIVE, [&](std::shared_ptr client, cereal::PortableBinaryInputArchive& message) { }); netServer->add_disconnect_callback([&](std::shared_ptr client) { diff --git a/src/Server/ServerData.cpp b/src/Server/ServerData.cpp new file mode 100644 index 0000000..98415b6 --- /dev/null +++ b/src/Server/ServerData.cpp @@ -0,0 +1,34 @@ +#include "ServerData.hpp" +#include "../DrawComponents/DrawComponent.hpp" + +void ServerData::save(cereal::PortableBinaryOutputArchive& a) const { + a(canvasBackColor, canvasScale); + a((uint64_t)components.size()); + for(uint64_t i = 0; i < components.size(); i++) + a(components[i]->get_type(), components[i]->id, components[i]->coords, *components[i]); + a(bookmarks, grids); +} + +void ServerData::load(cereal::PortableBinaryInputArchive& a) { + a(canvasBackColor, canvasScale); + 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.emplace_back(newComp); + idToComponentMap.emplace(newComp->id, newComp); + } + a(bookmarks, grids); +} + +void ServerData::scale_up(const WorldScalar& scaleUpAmount) { + for(auto& [n, b] : bookmarks) + b.scale_up(scaleUpAmount); + for(auto& [n, g] : grids) + g.scale_up(scaleUpAmount); + for(auto& c : components) + c->scale_up(scaleUpAmount); +} diff --git a/src/Server/ServerData.hpp b/src/Server/ServerData.hpp index aee936c..0ce3062 100644 --- a/src/Server/ServerData.hpp +++ b/src/Server/ServerData.hpp @@ -14,9 +14,10 @@ class ServerData { std::unordered_map resources; std::unordered_map bookmarks; std::unordered_map grids; - + uint64_t canvasScale = 0; Vector3f canvasBackColor; + void save(cereal::PortableBinaryOutputArchive& a) const; - void write_to_file(cereal::PortableBinaryOutputArchive& a) const; void load(cereal::PortableBinaryInputArchive& a); + void scale_up(const WorldScalar& scaleUpAmount); }; diff --git a/src/World.cpp b/src/World.cpp index 9554537..047e95e 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -78,6 +78,7 @@ void World::init_client_callbacks() { Vector3f newBackColor; message(newBackColor); set_canvas_background_color(newBackColor, false); + message(canvasScale); drawProg.initialize_draw_data(message); message(bMan, gridMan); } @@ -118,6 +119,13 @@ void World::init_client_callbacks() { message(newBackColor); set_canvas_background_color(newBackColor, false); }); + con.client_add_recv_callback(CLIENT_CANVAS_SCALE, [&](cereal::PortableBinaryInputArchive& message) { + uint64_t newCanvasScale; + message(newCanvasScale); + con.client_send_items_to_server(RELIABLE_COMMAND_CHANNEL, SERVER_CANVAS_SCALE, newCanvasScale); + scale_up(FixedPoint::pow_int(CANVAS_SCALE_UP_STEP, newCanvasScale - canvasScale)); + canvasScale = newCanvasScale; + }); con.client_add_recv_callback(CLIENT_KEEP_ALIVE, [&](cereal::PortableBinaryInputArchive& message) { }); } @@ -407,13 +415,23 @@ void World::draw_other_player_cursors(SkCanvas* canvas, const DrawData& drawData } } +void World::scale_up_step() { + canvasScale++; + con.client_send_items_to_server(RELIABLE_COMMAND_CHANNEL, SERVER_CANVAS_SCALE, canvasScale); + scale_up(WorldScalar(CANVAS_SCALE_UP_STEP)); +} + void World::scale_up(const WorldScalar& scaleUpAmount) { Logger::get().log("USERINFO", "Canvas scaled up"); - drawProg.scale_up(scaleUpAmount); bMan.scale_up(scaleUpAmount); gridMan.scale_up(scaleUpAmount); drawData.cam.scale_up(*this, scaleUpAmount); - undo.clear(); + // drawProg will be sending info on committed objects/modified grids. These objects will be scaled up already. + // This means that the scale up message must be send BEFORE the World::scale_up function is called on our end + // if this client is the one responsible for the scale up + drawProg.scale_up(scaleUpAmount); + + undo.clear(); // Do last to make sure that any undo generated while scaling up is removed, as it contains outdated scale info } void World::draw(SkCanvas* canvas) { diff --git a/src/World.hpp b/src/World.hpp index 5f23107..371ac15 100644 --- a/src/World.hpp +++ b/src/World.hpp @@ -100,6 +100,9 @@ class World { } canvasTheme; void scale_up(const WorldScalar& scaleUpAmount); + void scale_up_step(); + + uint64_t canvasScale = 0; private: ClientPortionID get_max_id(ServerPortionID serverID);