Working on moving canvas code to net objects (broken build)
This commit is contained in:
parent
d2a0bfcda9
commit
45ba26446a
42 changed files with 605 additions and 3186 deletions
|
|
@ -1,10 +1,12 @@
|
|||
#include "BrushTool.hpp"
|
||||
#include <Helpers/ConvertVec.hpp>
|
||||
#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 <chrono>
|
||||
|
||||
#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<int>(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<int>(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<DrawBrushStroke>();
|
||||
DrawBrushStrokePoint p;
|
||||
if(!isDrawing) {
|
||||
isDrawing = true;
|
||||
CanvasComponentContainer* newBrushStrokeContainer = new CanvasComponentContainer(drawP.world.netObjMan, CanvasComponent::CompType::BRUSHSTROKE);
|
||||
BrushStrokeCanvasComponent& newBrushStroke = static_cast<BrushStrokeCanvasComponent&>(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<CanvasComponentContainer> containerPtr = intermediateContainer.lock();
|
||||
if(!containerPtr) {
|
||||
isDrawing = false;
|
||||
intermediateContainer.reset();
|
||||
return;
|
||||
}
|
||||
BrushStrokeCanvasComponent& brushStroke = static_cast<BrushStrokeCanvasComponent&>(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<CanvasComponentContainer> 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;
|
||||
|
|
|
|||
|
|
@ -1,17 +1,17 @@
|
|||
#pragma once
|
||||
#include "../SharedTypes.hpp"
|
||||
#include "DrawingProgramToolBase.hpp"
|
||||
#include <Helpers/Hashes.hpp>
|
||||
#include <include/core/SkPath.h>
|
||||
#include <include/core/SkVertices.h>
|
||||
#include <Helpers/SCollision.hpp>
|
||||
#include <deque>
|
||||
#include <any>
|
||||
#include <include/core/SkCanvas.h>
|
||||
#include "../CanvasComponents/CanvasComponentContainer.hpp"
|
||||
#include <Helpers/NetworkingObjects/NetObjWeakPtr.hpp>
|
||||
|
||||
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<SmoothingPoint> penSmoothingData;
|
||||
float penWidth = 1.0f;
|
||||
bool addedTemporaryPoint = false;
|
||||
struct SmoothingPoint {
|
||||
float val;
|
||||
std::chrono::steady_clock::time_point t;
|
||||
};
|
||||
std::deque<SmoothingPoint> penSmoothingData;
|
||||
|
||||
std::shared_ptr<DrawBrushStroke> intermediateItem;
|
||||
bool isDrawing = false;
|
||||
bool hasRoundCaps = true;
|
||||
bool drawingMinimumRelativeToSize = true;
|
||||
bool midwayInterpolation = true;
|
||||
Vector2f prevPointUnaltered = {0, 0};
|
||||
} controls;
|
||||
NetworkingObjects::NetObjWeakPtr<CanvasComponentContainer> intermediateContainer;
|
||||
bool isDrawing = false;
|
||||
bool hasRoundCaps = true;
|
||||
bool drawingMinimumRelativeToSize = true;
|
||||
bool midwayInterpolation = true;
|
||||
Vector2f prevPointUnaltered = {0, 0};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
#include <include/core/SkPaint.h>
|
||||
#include <include/core/SkVertices.h>
|
||||
#include "../DrawCamera.hpp"
|
||||
#include "../DrawComponents/DrawComponent.hpp"
|
||||
#include "EllipseDrawTool.hpp"
|
||||
#include "EyeDropperTool.hpp"
|
||||
#include "GridModifyTool.hpp"
|
||||
|
|
@ -14,13 +13,13 @@
|
|||
#include <optional>
|
||||
#include <Helpers/ConvertVec.hpp>
|
||||
#include <cereal/types/vector.hpp>
|
||||
#include "../DrawComponents/DrawImage.hpp"
|
||||
#include <include/core/SkImage.h>
|
||||
#include <include/core/SkSurface.h>
|
||||
#include "../World.hpp"
|
||||
#include "../MainProgram.hpp"
|
||||
#include "Helpers/FileDownloader.hpp"
|
||||
#include "Helpers/StringHelpers.hpp"
|
||||
#include <Helpers/FileDownloader.hpp>
|
||||
#include <Helpers/NetworkingObjects/NetObjID.hpp>
|
||||
#include <Helpers/StringHelpers.hpp>
|
||||
#include "LassoSelectTool.hpp"
|
||||
#include <Helpers/Logger.hpp>
|
||||
#include <Helpers/Parallel.hpp>
|
||||
|
|
@ -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<NetworkingObjects::NetObjOrderedList<CanvasComponentContainer>>();
|
||||
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<EraserTool*>(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<CollabListType::ObjectInfoPtr>& 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<DrawComponent>& 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<std::pair<ServerClientID, CoordSpaceHelper>> transforms;
|
||||
message(transforms);
|
||||
if(transforms.size() >= DrawingProgramCache::MINIMUM_COMPONENTS_TO_START_REBUILD) {
|
||||
std::atomic<size_t> 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<DrawComponent>& 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<DrawComponent>& 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<CollabListType::ObjectInfoPtr> sortedPlacedComponents;
|
||||
|
||||
SendOrderedComponentVectorOp a{&sortedPlacedComponents};
|
||||
message(a);
|
||||
|
||||
std::vector<bool> 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<ServerClientID> 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<void(const std::shared_ptr<CollabList<std::shared_ptr<DrawComponent>, ServerClientID>::ObjectInfo>&)> func) {
|
||||
parallel_loop_container(components.client_list(), func);
|
||||
void DrawingProgram::parallel_loop_all_components(std::function<void(const CanvasComponentContainer::ObjInfoSharedPtr&)> func) {
|
||||
parallel_loop_container(components->get_data(), func);
|
||||
}
|
||||
|
||||
std::unordered_set<ServerClientID> DrawingProgram::get_used_resources() const {
|
||||
std::unordered_set<ServerClientID> 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<CanvasComponentContainer::ObjInfoSharedPtr>& compsToErase) {
|
||||
std::unordered_set<NetworkingObjects::NetObjID> 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<EraserTool*>(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<EraserTool*>(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<DrawImage>());
|
||||
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<float>(), 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<DrawImage> img = std::static_pointer_cast<DrawImage>(downFile.comp->obj);
|
||||
Vector2f dropPos = (img->d.p1 + img->d.p2) * 0.5f;
|
||||
|
||||
ResourceData newResource;
|
||||
newResource.data = std::make_shared<std::string>(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<DrawImage>());
|
||||
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<std::string>(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<DrawImage>());
|
||||
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<CollabListType::ObjectInfoPtr> erasedComponents) {
|
||||
std::unordered_set<ServerClientID> 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<CollabListType::ObjectInfoPtr>& objSetToUndo) {
|
||||
world.undo.push(UndoManager::UndoRedoPair{
|
||||
[&, objSetToUndo = objSetToUndo]() {
|
||||
for(auto& comp : objSetToUndo)
|
||||
if(!comp->obj->collabListInfo.lock())
|
||||
return false;
|
||||
|
||||
std::unordered_set<ServerClientID> 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<CollabListType::ObjectInfoPtr> 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<CollabListType::ObjectInfoPtr>& objSetToUndo) {
|
||||
world.undo.push(UndoManager::UndoRedoPair{
|
||||
[&, objSetToUndo = objSetToUndo]() {
|
||||
std::vector<CollabListType::ObjectInfoPtr> 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<ServerClientID> 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<DrawImage>(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<DrawImage>(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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,19 +11,20 @@
|
|||
#include <include/core/SkVertices.h>
|
||||
#include <Helpers/SCollision.hpp>
|
||||
#include <Helpers/Hashes.hpp>
|
||||
#include <list>
|
||||
#include <Helpers/Random.hpp>
|
||||
#include "DrawingProgramSelection.hpp"
|
||||
#include "../CollabList.hpp"
|
||||
#include "DrawingProgramToolBase.hpp"
|
||||
#include <Helpers/FileDownloader.hpp>
|
||||
#include <Helpers/NetworkingObjects/NetObjOrderedList.hpp>
|
||||
|
||||
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<ServerClientID> 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<void(const std::shared_ptr<CollabList<std::shared_ptr<DrawComponent>, ServerClientID>::ObjectInfo>&)> func);
|
||||
void parallel_loop_all_components(std::function<void(const CanvasComponentContainer::ObjInfoSharedPtr&)> 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<std::shared_ptr<DrawComponent>> updateableComponents;
|
||||
std::unordered_map<std::shared_ptr<DrawComponent>, std::shared_ptr<DrawComponent>> 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<DrawingProgramToolBase> newTool);
|
||||
|
||||
void clear_draw_cache();
|
||||
|
||||
void modify_grid(const NetworkingObjects::NetObjWeakPtr<WorldGrid>& gridToModify);
|
||||
|
||||
private:
|
||||
|
|
@ -71,31 +59,17 @@ class DrawingProgram {
|
|||
std::optional<std::chrono::steady_clock::time_point> unorderedObjectsExistTimePoint;
|
||||
|
||||
bool selection_action_menu(Vector2f popupPos);
|
||||
|
||||
void client_erase_set(std::unordered_set<CollabListType::ObjectInfoPtr> 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<bool> addFileInNextFrame = false;
|
||||
std::pair<std::filesystem::path, Vector2f> 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<CollabListType::ObjectInfoPtr>& objSetToUndo);
|
||||
void add_undo_erase_components(const std::unordered_set<CollabListType::ObjectInfoPtr>& 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<CanvasComponentContainer::ObjInfoSharedPtr>& 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<FileDownloader::DownloadData> downData;
|
||||
};
|
||||
std::vector<DroppedDownloadingFile> droppedDownloadingFiles;
|
||||
|
||||
void update_downloading_dropped_files();
|
||||
|
||||
friend class EyeDropperTool;
|
||||
friend class RectDrawTool;
|
||||
friend class EllipseDrawTool;
|
||||
|
|
|
|||
|
|
@ -23,18 +23,10 @@ DrawingProgramCache::DrawingProgramCache(DrawingProgram& initDrawP):
|
|||
lastBvhBuildTime = std::chrono::steady_clock::now();
|
||||
}
|
||||
|
||||
void DrawingProgramCache::build(std::vector<CollabListType::ObjectInfoPtr> components) {
|
||||
void DrawingProgramCache::build(std::vector<CanvasComponentContainer::ObjInfoSharedPtr> components) {
|
||||
bvhRoot = std::make_shared<DrawingProgramCacheBVHNode>();
|
||||
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<CollabListType::ObjectInfoPtr>& comps, bool force) {
|
||||
void DrawingProgramCache::test_rebuild(const std::vector<CanvasComponentContainer::ObjInfoSharedPtr>& comps, bool force) {
|
||||
if(force || check_if_rebuild_should_occur())
|
||||
force_rebuild(comps);
|
||||
}
|
||||
|
||||
void DrawingProgramCache::test_rebuild_dont_include_set(const std::vector<CollabListType::ObjectInfoPtr>& comps, const std::unordered_set<CollabListType::ObjectInfoPtr>& objsToNotInclude, bool force) {
|
||||
void DrawingProgramCache::test_rebuild_dont_include_set(const std::vector<CanvasComponentContainer::ObjInfoSharedPtr>& comps, const std::unordered_set<CanvasComponentContainer::ObjInfoSharedPtr>& 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<CollabListType::ObjectInfoPtr>& comps, const std::unordered_set<CollabListType::ObjectInfoPtr>& objsToNotInclude, const std::unordered_set<std::shared_ptr<DrawingProgramCacheBVHNode>>& nodesToNotInclude, bool force) {
|
||||
void DrawingProgramCache::test_rebuild_dont_include_set_dont_include_nodes(const std::vector<CanvasComponentContainer::ObjInfoSharedPtr>& comps, const std::unordered_set<CanvasComponentContainer::ObjInfoSharedPtr>& objsToNotInclude, const std::unordered_set<std::shared_ptr<DrawingProgramCacheBVHNode>>& 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<CollabListType::ObjectInfoPtr>& s, const std::unordered_set<std::shared_ptr<DrawingProgramCacheBVHNode>>& bvhNodes) {
|
||||
void DrawingProgramCache::move_components_from_bvh_nodes_to_set(std::unordered_set<CanvasComponentContainer::ObjInfoSharedPtr>& s, const std::unordered_set<std::shared_ptr<DrawingProgramCacheBVHNode>>& 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<CollabListType::ObjectInfoPtr>& s, const std::shared_ptr<DrawingProgramCacheBVHNode>& bvhNode) {
|
||||
void DrawingProgramCache::move_components_from_bvh_node_to_set(std::unordered_set<CanvasComponentContainer::ObjInfoSharedPtr>& s, const std::shared_ptr<DrawingProgramCacheBVHNode>& 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<CollabListType::ObjectInfoPtr> componentsToBuild, const std::unordered_set<CollabListType::ObjectInfoPtr>& objsToNotInclude) {
|
||||
void DrawingProgramCache::force_rebuild_dont_include_objs(std::vector<CanvasComponentContainer::ObjInfoSharedPtr> componentsToBuild, const std::unordered_set<CanvasComponentContainer::ObjInfoSharedPtr>& objsToNotInclude) {
|
||||
std::erase_if(componentsToBuild, [&objsToNotInclude](auto& c) {
|
||||
return objsToNotInclude.contains(c);
|
||||
});
|
||||
build(componentsToBuild);
|
||||
}
|
||||
|
||||
void DrawingProgramCache::force_rebuild(const std::vector<CollabListType::ObjectInfoPtr>& componentsToBuild) {
|
||||
void DrawingProgramCache::force_rebuild(const std::vector<CanvasComponentContainer::ObjInfoSharedPtr>& componentsToBuild) {
|
||||
build(componentsToBuild);
|
||||
}
|
||||
|
||||
const std::vector<CollabListType::ObjectInfoPtr>& DrawingProgramCache::get_unsorted_component_list() const {
|
||||
const std::vector<CanvasComponentContainer::ObjInfoSharedPtr>& 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::shared_ptr<DrawingProgramCacheBVHNode>, std::vector<CollabListType::ObjectInfoPtr>::iterator> DrawingProgramCache::get_bvh_node_fully_containing_recursive(const std::shared_ptr<DrawingProgramCacheBVHNode>& bvhNode, DrawComponent* c) {
|
||||
SCollision::AABB<WorldScalar>& 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<WorldScalar>& aabb, std::function<bool(const std::shared_ptr<DrawingProgramCacheBVHNode>& node, std::vector<CollabListType::ObjectInfoPtr>& components)> f) {
|
||||
void DrawingProgramCache::traverse_bvh_erase_function(const SCollision::AABB<WorldScalar>& aabb, std::function<bool(const std::shared_ptr<DrawingProgramCacheBVHNode>& node, std::vector<CanvasComponentContainer::ObjInfoSharedPtr>& 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<DrawingProgramCacheBVHNode>& bvhNode, const SCollision::AABB<WorldScalar>& aabb, std::function<bool(const std::shared_ptr<DrawingProgramCacheBVHNode>& node, std::vector<CollabListType::ObjectInfoPtr>& components)> f) {
|
||||
bool DrawingProgramCache::traverse_bvh_erase_function_recursive(const std::shared_ptr<DrawingProgramCacheBVHNode>& bvhNode, const SCollision::AABB<WorldScalar>& aabb, std::function<bool(const std::shared_ptr<DrawingProgramCacheBVHNode>& node, std::vector<CanvasComponentContainer::ObjInfoSharedPtr>& 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<WorldScalar>& aabb, std::function<bool(const std::shared_ptr<DrawingProgramCacheBVHNode>& node, const std::vector<CollabListType::ObjectInfoPtr>& components)> f) {
|
||||
void DrawingProgramCache::traverse_bvh_run_function(const SCollision::AABB<WorldScalar>& aabb, std::function<bool(const std::shared_ptr<DrawingProgramCacheBVHNode>& node, const std::vector<CanvasComponentContainer::ObjInfoSharedPtr>& components)> f) {
|
||||
f(nullptr, unsortedComponents);
|
||||
traverse_bvh_run_function_recursive(bvhRoot, aabb, f);
|
||||
}
|
||||
|
||||
void DrawingProgramCache::traverse_bvh_run_function_recursive(const std::shared_ptr<DrawingProgramCacheBVHNode>& bvhNode, const SCollision::AABB<WorldScalar>& aabb, std::function<bool(const std::shared_ptr<DrawingProgramCacheBVHNode>& node, const std::vector<CollabListType::ObjectInfoPtr>& components)> f) {
|
||||
void DrawingProgramCache::traverse_bvh_run_function_recursive(const std::shared_ptr<DrawingProgramCacheBVHNode>& bvhNode, const SCollision::AABB<WorldScalar>& aabb, std::function<bool(const std::shared_ptr<DrawingProgramCacheBVHNode>& node, const std::vector<CanvasComponentContainer::ObjInfoSharedPtr>& 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<float>& cC) {
|
||||
CanvasComponentContainer::ObjInfoSharedPtr DrawingProgramCache::get_front_object_colliding_with(const SCollision::ColliderCollection<float>& cC) {
|
||||
auto cCWorld = drawP.world.drawData.cam.c.collider_to_world<SCollision::ColliderCollection<WorldScalar>, SCollision::ColliderCollection<float>>(cC);
|
||||
CollabListType::ObjectInfoPtr p;
|
||||
traverse_bvh_run_function(cCWorld.bounds, [&](const std::shared_ptr<DrawingProgramCacheBVHNode>& bvhNode, const std::vector<CollabListType::ObjectInfoPtr>& components) {
|
||||
CanvasComponentContainer::ObjInfoSharedPtr p;
|
||||
traverse_bvh_run_function(cCWorld.bounds, [&](const std::shared_ptr<DrawingProgramCacheBVHNode>& bvhNode, const std::vector<CanvasComponentContainer::ObjInfoSharedPtr>& 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<DrawingProgramCacheBVHNode>& bvhNode, const std::vector<CollabListType::ObjectInfoPtr>& components) {
|
||||
void DrawingProgramCache::build_bvh_node(const std::shared_ptr<DrawingProgramCacheBVHNode>& bvhNode, const std::vector<CanvasComponentContainer::ObjInfoSharedPtr>& 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_ptr<DrawingProgramCac
|
|||
|
||||
WorldVec boundsCenter = bvhNode->bounds.center();
|
||||
|
||||
std::array<std::vector<CollabListType::ObjectInfoPtr>, 4> parts;
|
||||
std::array<std::vector<CanvasComponentContainer::ObjInfoSharedPtr>, 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<SCollision::AABB<WorldScalar>>& 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<WorldScalar>& aabb, uint64_t placementToInvalidateAt) {
|
||||
void DrawingProgramCache::invalidate_cache_at_aabb_before_pos(const SCollision::AABB<WorldScalar>& 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<std::shared_ptr<DrawingProgramCacheBVHNode>> 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<DrawingProgramCacheBVHNode> node, const std::vector<CollabListType::ObjectInfoPtr>& comps) {
|
||||
traverse_bvh_run_function(drawData.cam.viewingAreaGenerousCollider, [&](std::shared_ptr<DrawingProgramCacheBVHNode> node, const std::vector<CanvasComponentContainer::ObjInfoSharedPtr>& 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<DrawingProgra
|
|||
}
|
||||
|
||||
void DrawingProgramCache::draw_components_to_canvas(SkCanvas* canvas, const DrawData& drawData, DrawComponentsToCanvasOptionalData optData) {
|
||||
uint64_t lastComponentDrawn = 0;
|
||||
uint32_t lastComponentDrawn = 0;
|
||||
|
||||
std::vector<std::shared_ptr<DrawingProgramCacheBVHNode>> cachedNodesToDraw;
|
||||
struct UncachedObjectToDraw {
|
||||
CollabListType::ObjectInfoPtr comp;
|
||||
CanvasComponentContainer::ObjInfoSharedPtr comp;
|
||||
bool isAnUnsortedObject;
|
||||
};
|
||||
std::vector<UncachedObjectToDraw> uncachedCompsToDraw;
|
||||
|
||||
traverse_bvh_run_function(drawData.cam.viewingAreaGenerousCollider, [&](const std::shared_ptr<DrawingProgramCacheBVHNode>& node, const std::vector<CollabListType::ObjectInfoPtr>& comps) {
|
||||
traverse_bvh_run_function(drawData.cam.viewingAreaGenerousCollider, [&](const std::shared_ptr<DrawingProgramCacheBVHNode>& node, const std::vector<CanvasComponentContainer::ObjInfoSharedPtr>& 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::microseconds>(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]);
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
#include <include/core/SkSurface.h>
|
||||
#include <unordered_set>
|
||||
#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<WorldScalar> bounds;
|
||||
std::vector<CollabListType::ObjectInfoPtr> components;
|
||||
std::vector<CanvasComponentContainer::ObjInfoSharedPtr> components;
|
||||
std::vector<std::shared_ptr<DrawingProgramCacheBVHNode>> children;
|
||||
|
||||
CoordSpaceHelper coords;
|
||||
Vector2i resolution;
|
||||
struct DrawCacheData {
|
||||
uint64_t lastDrawnComponentPlacement;
|
||||
uint32_t lastDrawnComponentPlacement;
|
||||
sk_sp<SkSurface> 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<CollabListType::ObjectInfoPtr>& comps, bool force = false);
|
||||
void test_rebuild_dont_include_set(const std::vector<CollabListType::ObjectInfoPtr>& comps, const std::unordered_set<CollabListType::ObjectInfoPtr>& objsToNotInclude, bool force = false);
|
||||
void test_rebuild_dont_include_set_dont_include_nodes(const std::vector<CollabListType::ObjectInfoPtr>& comps, const std::unordered_set<CollabListType::ObjectInfoPtr>& objsToNotInclude, const std::unordered_set<std::shared_ptr<DrawingProgramCacheBVHNode>>& nodesToNotInclude, bool force = false);
|
||||
void test_rebuild(const std::vector<CanvasComponentContainer::ObjInfoSharedPtr>& comps, bool force = false);
|
||||
void test_rebuild_dont_include_set(const std::vector<CanvasComponentContainer::ObjInfoSharedPtr>& comps, const std::unordered_set<CanvasComponentContainer::ObjInfoSharedPtr>& objsToNotInclude, bool force = false);
|
||||
void test_rebuild_dont_include_set_dont_include_nodes(const std::vector<CanvasComponentContainer::ObjInfoSharedPtr>& comps, const std::unordered_set<CanvasComponentContainer::ObjInfoSharedPtr>& objsToNotInclude, const std::unordered_set<std::shared_ptr<DrawingProgramCacheBVHNode>>& nodesToNotInclude, bool force = false);
|
||||
|
||||
static void move_components_from_bvh_nodes_to_set(std::unordered_set<CollabListType::ObjectInfoPtr>& s, const std::unordered_set<std::shared_ptr<DrawingProgramCacheBVHNode>>& bvhNodes);
|
||||
static void move_components_from_bvh_node_to_set(std::unordered_set<CollabListType::ObjectInfoPtr>& s, const std::shared_ptr<DrawingProgramCacheBVHNode>& bvhNode);
|
||||
static void move_components_from_bvh_nodes_to_set(std::unordered_set<CanvasComponentContainer::ObjInfoSharedPtr>& s, const std::unordered_set<std::shared_ptr<DrawingProgramCacheBVHNode>>& bvhNodes);
|
||||
static void move_components_from_bvh_node_to_set(std::unordered_set<CanvasComponentContainer::ObjInfoSharedPtr>& s, const std::shared_ptr<DrawingProgramCacheBVHNode>& 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<WorldScalar>& aabb, std::function<bool(const std::shared_ptr<DrawingProgramCacheBVHNode>& node, const std::vector<CollabListType::ObjectInfoPtr>& components)> f);
|
||||
void traverse_bvh_erase_function(const SCollision::AABB<WorldScalar>& aabb, std::function<bool(const std::shared_ptr<DrawingProgramCacheBVHNode>& node, std::vector<CollabListType::ObjectInfoPtr>& components)> f);
|
||||
void traverse_bvh_run_function(const SCollision::AABB<WorldScalar>& aabb, std::function<bool(const std::shared_ptr<DrawingProgramCacheBVHNode>& node, const std::vector<CanvasComponentContainer::ObjInfoSharedPtr>& components)> f);
|
||||
void traverse_bvh_erase_function(const SCollision::AABB<WorldScalar>& aabb, std::function<bool(const std::shared_ptr<DrawingProgramCacheBVHNode>& node, std::vector<CanvasComponentContainer::ObjInfoSharedPtr>& 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<WorldScalar>& aabb, uint64_t placementToInvalidateAt);
|
||||
void invalidate_cache_at_optional_aabb_before_pos(const std::optional<SCollision::AABB<WorldScalar>>& 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<WorldScalar>& aabb, uint32_t placementToInvalidateAt);
|
||||
void clear();
|
||||
|
||||
struct DrawComponentsToCanvasOptionalData {
|
||||
uint64_t* lastDrawnComponentPlacement = nullptr;
|
||||
uint32_t* lastDrawnComponentPlacement = nullptr;
|
||||
std::optional<SCollision::AABB<WorldScalar>> drawBounds;
|
||||
};
|
||||
|
||||
void draw_components_to_canvas(SkCanvas* canvas, const DrawData& drawData, DrawComponentsToCanvasOptionalData optData);
|
||||
const std::vector<CollabListType::ObjectInfoPtr>& get_unsorted_component_list() const;
|
||||
const std::vector<CanvasComponentContainer::ObjInfoSharedPtr>& 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<float>& cC);
|
||||
CanvasComponentContainer::ObjInfoSharedPtr get_front_object_colliding_with(const SCollision::ColliderCollection<float>& cC);
|
||||
|
||||
private:
|
||||
static std::unordered_set<std::shared_ptr<DrawingProgramCacheBVHNode>> nodesWithCachedSurfaces;
|
||||
|
||||
void draw_cache_image_to_canvas(SkCanvas* canvas, const DrawData& drawData, const std::shared_ptr<DrawingProgramCacheBVHNode>& bvhNode);
|
||||
|
||||
void force_rebuild_dont_include_objs(std::vector<CollabListType::ObjectInfoPtr> componentsToBuild, const std::unordered_set<CollabListType::ObjectInfoPtr>& objsToNotInclude);
|
||||
void force_rebuild(const std::vector<CollabListType::ObjectInfoPtr>& componentsToBuild);
|
||||
void force_rebuild_dont_include_objs(std::vector<CanvasComponentContainer::ObjInfoSharedPtr> componentsToBuild, const std::unordered_set<CanvasComponentContainer::ObjInfoSharedPtr>& objsToNotInclude);
|
||||
void force_rebuild(const std::vector<CanvasComponentContainer::ObjInfoSharedPtr>& componentsToBuild);
|
||||
|
||||
bool traverse_bvh_erase_function_recursive(const std::shared_ptr<DrawingProgramCacheBVHNode>& bvhNode, const SCollision::AABB<WorldScalar>& aabb, std::function<bool(const std::shared_ptr<DrawingProgramCacheBVHNode>& node, std::vector<CollabListType::ObjectInfoPtr>& components)> f);
|
||||
bool traverse_bvh_erase_function_recursive(const std::shared_ptr<DrawingProgramCacheBVHNode>& bvhNode, const SCollision::AABB<WorldScalar>& aabb, std::function<bool(const std::shared_ptr<DrawingProgramCacheBVHNode>& node, std::vector<CanvasComponentContainer::ObjInfoSharedPtr>& components)> f);
|
||||
void build_bvh_node_coords_and_resolution(DrawingProgramCacheBVHNode& node);
|
||||
void refresh_draw_cache(const std::shared_ptr<DrawingProgramCacheBVHNode>& bvhNode, const DrawData& drawData);
|
||||
void build(std::vector<CollabListType::ObjectInfoPtr> components);
|
||||
void traverse_bvh_run_function_recursive(const std::shared_ptr<DrawingProgramCacheBVHNode>& bvhNode, const SCollision::AABB<WorldScalar>& aabb, std::function<bool(const std::shared_ptr<DrawingProgramCacheBVHNode>& node, const std::vector<CollabListType::ObjectInfoPtr>& components)> f);
|
||||
std::pair<std::shared_ptr<DrawingProgramCacheBVHNode>, std::vector<CollabListType::ObjectInfoPtr>::iterator> get_bvh_node_fully_containing_recursive(const std::shared_ptr<DrawingProgramCacheBVHNode>& bvhNode, DrawComponent* c);
|
||||
void build(std::vector<CanvasComponentContainer::ObjInfoSharedPtr> components);
|
||||
void traverse_bvh_run_function_recursive(const std::shared_ptr<DrawingProgramCacheBVHNode>& bvhNode, const SCollision::AABB<WorldScalar>& aabb, std::function<bool(const std::shared_ptr<DrawingProgramCacheBVHNode>& node, const std::vector<CanvasComponentContainer::ObjInfoSharedPtr>& components)> f);
|
||||
|
||||
void build_bvh_node(const std::shared_ptr<DrawingProgramCacheBVHNode>& bvhNode, const std::vector<CollabListType::ObjectInfoPtr>& components);
|
||||
void build_bvh_node(const std::shared_ptr<DrawingProgramCacheBVHNode>& bvhNode, const std::vector<CanvasComponentContainer::ObjInfoSharedPtr>& components);
|
||||
|
||||
std::chrono::steady_clock::time_point lastBvhBuildTime;
|
||||
std::shared_ptr<DrawingProgramCacheBVHNode> bvhRoot;
|
||||
std::vector<CollabListType::ObjectInfoPtr> unsortedComponents;
|
||||
std::vector<CanvasComponentContainer::ObjInfoSharedPtr> unsortedComponents;
|
||||
DrawingProgram& drawP;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -27,18 +27,18 @@ DrawingProgramSelection::DrawingProgramSelection(DrawingProgram& initDrawP):
|
|||
drawP(initDrawP)
|
||||
{}
|
||||
|
||||
const std::unordered_set<CollabListType::ObjectInfoPtr>& DrawingProgramSelection::get_selected_set() {
|
||||
const std::unordered_set<CanvasComponentContainer::ObjInfoSharedPtr>& 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<CollabListType::ObjectInfoPtr>& selectedComponents, const std::shared_ptr<DrawingProgramCacheBVHNode>& bvhNode) {
|
||||
void DrawingProgramSelection::fully_collided_erase_select_objects_func(std::unordered_set<CanvasComponentContainer::ObjInfoSharedPtr>& selectedComponents, const std::shared_ptr<DrawingProgramCacheBVHNode>& 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<bool(const std::shared_ptr<DrawingProgramCacheBVHNode>&, std::vector<CollabListType::ObjectInfoPtr>&)> DrawingProgramSelection::erase_select_objects_in_bvh_func(std::unordered_set<CollabListType::ObjectInfoPtr>& selectedComponents, const SCollision::ColliderCollection<float>& cC, const SCollision::ColliderCollection<WorldScalar>& cCWorld) {
|
||||
std::function<bool(const std::shared_ptr<DrawingProgramCacheBVHNode>&, std::vector<CanvasComponentContainer::ObjInfoSharedPtr>&)> DrawingProgramSelection::erase_select_objects_in_bvh_func(std::unordered_set<CanvasComponentContainer::ObjInfoSharedPtr>& selectedComponents, const SCollision::ColliderCollection<float>& cC, const SCollision::ColliderCollection<WorldScalar>& 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<bool(const std::shared_ptr<DrawingProgramCacheBVHNode>&, 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<bool(const std::shared_ptr<DrawingProgramCacheBVHNode>&, std::vect
|
|||
}
|
||||
|
||||
void DrawingProgramSelection::add_from_cam_coord_collider_to_selection(const SCollision::ColliderCollection<float>& cC, bool frontObjectOnly) {
|
||||
std::unordered_set<CollabListType::ObjectInfoPtr> selectedComponents;
|
||||
std::unordered_set<CanvasComponentContainer::ObjInfoSharedPtr> 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<float>& cC, bool frontObjectOnly) {
|
||||
auto cCWorld = drawP.world.drawData.cam.c.collider_to_world<SCollision::ColliderCollection<WorldScalar>, SCollision::ColliderCollection<float>>(cC);
|
||||
std::unordered_set<CollabListType::ObjectInfoPtr> selectedComponents;
|
||||
std::unordered_set<CanvasComponentContainer::ObjInfoSharedPtr> 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<CollabListType::ObjectInfoPtr>& newSelection) {
|
||||
void DrawingProgramSelection::add_to_selection(const std::unordered_set<CanvasComponentContainer::ObjInfoSharedPtr>& 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<CollabLi
|
|||
calculate_initial_rotate_center_location();
|
||||
}
|
||||
|
||||
void DrawingProgramSelection::set_to_selection(const std::unordered_set<CollabListType::ObjectInfoPtr>& newSelection) {
|
||||
void DrawingProgramSelection::set_to_selection(const std::unordered_set<CanvasComponentContainer::ObjInfoSharedPtr>& 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<CollabListType::ObjectInfoPtr> a(selectedSet.begin(), selectedSet.end());
|
||||
std::vector<std::pair<CollabListType::ObjectInfoPtr, CoordSpaceHelper>> transformsFrom;
|
||||
std::vector<CanvasComponentContainer::ObjInfoSharedPtr> a(selectedSet.begin(), selectedSet.end());
|
||||
std::vector<std::pair<CanvasComponentContainer::ObjInfoSharedPtr, CoordSpaceHelper>> 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<std::pair<CollabListType::ObjectInfoPtr, CoordSpaceHelper>> transformsTo;
|
||||
std::vector<std::pair<ServerClientID, CoordSpaceHelper>> transformsToSend;
|
||||
std::vector<std::pair<CanvasComponentContainer::ObjInfoSharedPtr, CoordSpaceHelper>> transformsTo;
|
||||
std::vector<std::pair<NetworkingObjects::NetObjID, CoordSpaceHelper>> 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<std::pair<ServerClientID, CoordSpaceHelper>> 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<std::pair<ServerClientID, CoordSpaceHelper>> 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<float>& cC) {
|
||||
CanvasComponentContainer::ObjInfoSharedPtr DrawingProgramSelection::get_front_object_colliding_with(const SCollision::ColliderCollection<float>& cC) {
|
||||
return cache.get_front_object_colliding_with(cC);
|
||||
}
|
||||
|
||||
void DrawingProgramSelection::invalidate_cache_at_optional_aabb_before_pos(const std::optional<SCollision::AABB<WorldScalar>>& 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<WorldScalar>& 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<ServerClientID> resourceSet;
|
||||
for(auto& c : selectedSet)
|
||||
c->obj->get_used_resources(resourceSet);
|
||||
std::vector<CollabListType::ObjectInfoPtr> 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<ServerClientID> resourceSet;
|
||||
//for(auto& c : selectedSet)
|
||||
// c->obj->get_used_resources(resourceSet);
|
||||
//std::vector<CanvasComponentContainer::ObjInfoSharedPtr> 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<CollabListType::ObjectInfoPtr>(selectedSet.begin(), selectedSet.end()), true);
|
||||
cache.test_rebuild(std::vector<CanvasComponentContainer::ObjInfoSharedPtr>(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<std::shared_ptr<DrawComponent>> 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<std::shared_ptr<DrawComponent>> 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<ServerClientID, ServerClientID> 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<CollabListType::ObjectInfoPtr> compSetInserted(compListInserted.begin(), compListInserted.end());
|
||||
set_to_selection(compSetInserted);
|
||||
drawP.add_undo_place_components(compSetInserted);
|
||||
//std::unordered_map<ServerClientID, ServerClientID> 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<CanvasComponentContainer::ObjInfoSharedPtr> compSetInserted(compListInserted.begin(), compListInserted.end());
|
||||
//set_to_selection(compSetInserted);
|
||||
//drawP.add_undo_place_components(compSetInserted);
|
||||
}
|
||||
|
||||
void DrawingProgramSelection::rebuild_cam_space() {
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ class DrawingProgramSelection {
|
|||
void add_from_cam_coord_collider_to_selection(const SCollision::ColliderCollection<float>& cC, bool frontObjectOnly = false);
|
||||
void remove_from_cam_coord_collider_to_selection(const SCollision::ColliderCollection<float>& cC, bool frontObjectOnly = false);
|
||||
|
||||
CollabListType::ObjectInfoPtr get_front_object_colliding_with(const SCollision::ColliderCollection<float>& cC);
|
||||
CanvasComponentContainer::ObjInfoSharedPtr get_front_object_colliding_with(const SCollision::ColliderCollection<float>& 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<CollabListType::ObjectInfoPtr>& get_selected_set();
|
||||
void erase_component(const CanvasComponentContainer::ObjInfoSharedPtr& objToCheck);
|
||||
bool is_selected(const CanvasComponentContainer::ObjInfoSharedPtr& objToCheck);
|
||||
const std::unordered_set<CanvasComponentContainer::ObjInfoSharedPtr>& get_selected_set();
|
||||
|
||||
bool is_being_transformed();
|
||||
|
||||
void invalidate_cache_at_optional_aabb_before_pos(const std::optional<SCollision::AABB<WorldScalar>>& aabb, uint64_t placementToInvalidateAt);
|
||||
void invalidate_cache_at_aabb_before_pos(const SCollision::AABB<WorldScalar>& 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<bool(const std::shared_ptr<DrawingProgramCacheBVHNode>&, std::vector<CollabListType::ObjectInfoPtr>&)> erase_select_objects_in_bvh_func(std::unordered_set<CollabListType::ObjectInfoPtr>& selectedComponents, const SCollision::ColliderCollection<float>& cC, const SCollision::ColliderCollection<WorldScalar>& cCWorld);
|
||||
void fully_collided_erase_select_objects_func(std::unordered_set<CollabListType::ObjectInfoPtr>& selectedComponents, const std::shared_ptr<DrawingProgramCacheBVHNode>& bvhNode);
|
||||
std::function<bool(const std::shared_ptr<DrawingProgramCacheBVHNode>&, std::vector<CanvasComponentContainer::ObjInfoSharedPtr>&)> erase_select_objects_in_bvh_func(std::unordered_set<CanvasComponentContainer::ObjInfoSharedPtr>& selectedComponents, const SCollision::ColliderCollection<float>& cC, const SCollision::ColliderCollection<WorldScalar>& cCWorld);
|
||||
void fully_collided_erase_select_objects_func(std::unordered_set<CanvasComponentContainer::ObjInfoSharedPtr>& selectedComponents, const std::shared_ptr<DrawingProgramCacheBVHNode>& 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<CollabListType::ObjectInfoPtr>& newSelection);
|
||||
void add_to_selection(const std::unordered_set<CollabListType::ObjectInfoPtr>& newSelection);
|
||||
void add_erased_objects_back_to_cache(const std::unordered_set<CollabListType::ObjectInfoPtr>& erasedObjects);
|
||||
void set_to_selection(const std::unordered_set<CanvasComponentContainer::ObjInfoSharedPtr>& newSelection);
|
||||
void add_to_selection(const std::unordered_set<CanvasComponentContainer::ObjInfoSharedPtr>& newSelection);
|
||||
void add_erased_objects_back_to_cache(const std::unordered_set<CanvasComponentContainer::ObjInfoSharedPtr>& erasedObjects);
|
||||
|
||||
void commit_transform_selection();
|
||||
|
||||
|
|
@ -59,7 +59,7 @@ class DrawingProgramSelection {
|
|||
|
||||
CoordSpaceHelperTransform selectionTransformCoords;
|
||||
|
||||
std::unordered_set<CollabListType::ObjectInfoPtr> selectedSet;
|
||||
std::unordered_set<CanvasComponentContainer::ObjInfoSharedPtr> selectedSet;
|
||||
DrawingProgramCache cache;
|
||||
DrawingProgram& drawP;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,16 +1,12 @@
|
|||
#include "EllipseDrawTool.hpp"
|
||||
#include <chrono>
|
||||
#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 <cereal/types/vector.hpp>
|
||||
#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<DrawEllipse>();
|
||||
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<uint8_t>(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<EllipseCanvasComponent&>(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<uint8_t>(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<CanvasComponentContainer> 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<EllipseCanvasComponent&>(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<CanvasComponentContainer> lockedPtr = intermediateContainer.lock();
|
||||
if(lockedPtr) {
|
||||
lockedPtr->commit_update(drawP);
|
||||
drawP.world.delayedUpdateObjectManager.send_update_to_all<CanvasComponentContainer>(lockedPtr, true);
|
||||
}
|
||||
controls.intermediateItem = nullptr;
|
||||
intermediateContainer.reset();
|
||||
}
|
||||
|
||||
void EllipseDrawTool::draw(SkCanvas* canvas, const DrawData& drawData) {
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
#pragma once
|
||||
#include "DrawingProgramToolBase.hpp"
|
||||
#include "../DrawComponents/DrawEllipse.hpp"
|
||||
#include <any>
|
||||
#include <Helpers/SCollision.hpp>
|
||||
#include <Helpers/NetworkingObjects/NetObjWeakPtr.hpp>
|
||||
#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<DrawEllipse> intermediateItem;
|
||||
} controls;
|
||||
Vector2f startAt;
|
||||
int fillStrokeMode = 1;
|
||||
int drawStage = 0;
|
||||
NetworkingObjects::NetObjWeakPtr<CanvasComponentContainer> intermediateContainer;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
#pragma once
|
||||
#include <include/core/SkCanvas.h>
|
||||
#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<CollabListType::ObjectInfoPtr> erasedComponents;
|
||||
std::unordered_set<CanvasComponentContainer::ObjInfoSharedPtr> erasedComponents; // Pointers will be erased from this set if theyre erased in the main list (done by callback)
|
||||
std::unordered_set<std::shared_ptr<DrawingProgramCacheBVHNode>> erasedBVHNodes;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -141,7 +141,7 @@ void GridModifyTool::tool_update() {
|
|||
selectionMode = 0;
|
||||
break;
|
||||
}
|
||||
drawP.world.delayedUpdateObjectManager.send_update_to_all<WorldGrid>(gLock, nullptr, false);
|
||||
drawP.world.delayedUpdateObjectManager.send_update_to_all<WorldGrid>(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<WorldGrid> gLock = grid.lock();
|
||||
if(gLock)
|
||||
drawP.world.delayedUpdateObjectManager.send_update_to_all<WorldGrid>(gLock, nullptr, true);
|
||||
drawP.world.delayedUpdateObjectManager.send_update_to_all<WorldGrid>(gLock, true);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
#include "../MainProgram.hpp"
|
||||
#include "../DrawData.hpp"
|
||||
#include "DrawingProgramToolBase.hpp"
|
||||
#include <cereal/types/vector.hpp>
|
||||
#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<DrawRectangle>();
|
||||
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<uint8_t>(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<RectangleCanvasComponent&>(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<uint8_t>(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<CanvasComponentContainer> 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<RectangleCanvasComponent&>(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<CanvasComponentContainer> lockedPtr = intermediateContainer.lock();
|
||||
if(lockedPtr) {
|
||||
lockedPtr->commit_update(drawP);
|
||||
drawP.world.delayedUpdateObjectManager.send_update_to_all<CanvasComponentContainer>(lockedPtr, true);
|
||||
}
|
||||
controls.intermediateItem = nullptr;
|
||||
intermediateContainer.reset();
|
||||
}
|
||||
|
||||
void RectDrawTool::draw(SkCanvas* canvas, const DrawData& drawData) {
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
#pragma once
|
||||
#include "DrawingProgramToolBase.hpp"
|
||||
#include "../DrawComponents/DrawRectangle.hpp"
|
||||
#include <Helpers/SCollision.hpp>
|
||||
#include <any>
|
||||
#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<DrawRectangle> intermediateItem;
|
||||
} controls;
|
||||
Vector2f startAt;
|
||||
float relativeRadiusWidth = 10.0f;
|
||||
int fillStrokeMode = 1;
|
||||
int drawStage = 0;
|
||||
NetworkingObjects::NetObjWeakPtr<CanvasComponentContainer> intermediateContainer;
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue