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