Selection and transformation works with layers
This commit is contained in:
parent
7549ad23a1
commit
3df74095a3
16 changed files with 789 additions and 176 deletions
|
|
@ -67,18 +67,18 @@ void CanvasComponentContainer::set_owner_obj_info(const ObjInfoSharedPtr& ownerO
|
|||
void CanvasComponentContainer::commit_update(DrawingProgram& drawP) {
|
||||
auto lockedObjInfo = objInfo.lock();
|
||||
if(worldAABB.has_value()) // This is the only point where worldAABB could be nullopt
|
||||
drawP.drawCache.preupdate_component(lockedObjInfo);
|
||||
drawP.preupdate_component(lockedObjInfo);
|
||||
get_comp().initialize_draw_data(drawP);
|
||||
calculate_world_bounds();
|
||||
drawP.drawCache.preupdate_component(lockedObjInfo);
|
||||
drawP.preupdate_component(lockedObjInfo);
|
||||
}
|
||||
|
||||
void CanvasComponentContainer::commit_transform(DrawingProgram& drawP) {
|
||||
auto lockedObjInfo = objInfo.lock();
|
||||
if(worldAABB.has_value()) // This is the only point where worldAABB could be nullopt
|
||||
drawP.drawCache.preupdate_component(lockedObjInfo);
|
||||
drawP.preupdate_component(lockedObjInfo);
|
||||
calculate_world_bounds();
|
||||
drawP.drawCache.preupdate_component(lockedObjInfo);
|
||||
drawP.preupdate_component(lockedObjInfo);
|
||||
}
|
||||
|
||||
void CanvasComponentContainer::commit_update_dont_invalidate_cache(DrawingProgram& drawP) {
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@
|
|||
#include "CanvasComponentAllocator.hpp"
|
||||
|
||||
class DrawingProgram;
|
||||
class DrawingProgramCacheBVHNode;
|
||||
class DrawingProgramLayerListItem;
|
||||
struct DrawingProgramCacheBVHNode;
|
||||
|
||||
class CanvasComponentContainer {
|
||||
public:
|
||||
|
|
@ -45,7 +45,7 @@ class CanvasComponentContainer {
|
|||
void set_owner_obj_info(const ObjInfoSharedPtr& ownerObjInfo);
|
||||
void send_comp_update(DrawingProgram& drawP, bool finalUpdate);
|
||||
|
||||
std::weak_ptr<DrawingProgramCacheBVHNode> parentBvhNode; // Should be removed later, the new cache uses an unordered_map to map objects to their cache node
|
||||
std::weak_ptr<DrawingProgramCacheBVHNode> cacheParentBvhNode;
|
||||
DrawingProgramLayerListItem* parentLayer = nullptr;
|
||||
CoordSpaceHelper coords;
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ void ImageCanvasComponent::update(DrawingProgram& drawP) {
|
|||
ResourceDisplay* display = drawP.world.drawData.rMan->get_display_data(d.imageID);
|
||||
if(display) {
|
||||
if(display->update_draw())
|
||||
drawP.drawCache.invalidate_cache_at_aabb(compContainer->get_world_bounds());
|
||||
drawP.invalidate_cache_at_component(compContainer->objInfo.lock());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -35,7 +35,8 @@
|
|||
DrawingProgram::DrawingProgram(World& initWorld):
|
||||
world(initWorld),
|
||||
drawCache(*this),
|
||||
layerMan(*this)
|
||||
layerMan(*this),
|
||||
selection(*this)
|
||||
{
|
||||
drawTool = DrawingProgramToolBase::allocate_tool_type(*this, DrawingProgramToolType::BRUSH);
|
||||
}
|
||||
|
|
@ -107,26 +108,26 @@ bool DrawingProgram::selection_action_menu(Vector2f popupPos) {
|
|||
bool shouldClose = false;
|
||||
t.gui.list_popup_menu("Selection popup menu", popupPos, [&]() {
|
||||
t.gui.text_label_light("Selection menu");
|
||||
//if(t.gui.text_button_left_transparent("Paste", "Paste")) {
|
||||
// selection.deselect_all();
|
||||
// selection.paste_clipboard(popupPos * t.final_gui_scale());
|
||||
// shouldClose = true;
|
||||
//}
|
||||
//if(selection.is_something_selected()) {
|
||||
// if(t.gui.text_button_left_transparent("Copy", "Copy")) {
|
||||
// selection.selection_to_clipboard();
|
||||
// shouldClose = true;
|
||||
// }
|
||||
// if(t.gui.text_button_left_transparent("Cut", "Cut")) {
|
||||
// selection.selection_to_clipboard();
|
||||
// selection.delete_all();
|
||||
// shouldClose = true;
|
||||
// }
|
||||
// if(t.gui.text_button_left_transparent("Delete", "Delete")) {
|
||||
// selection.delete_all();
|
||||
// shouldClose = true;
|
||||
// }
|
||||
//}
|
||||
if(t.gui.text_button_left_transparent("Paste", "Paste")) {
|
||||
selection.deselect_all();
|
||||
selection.paste_clipboard(popupPos * t.final_gui_scale());
|
||||
shouldClose = true;
|
||||
}
|
||||
if(selection.is_something_selected()) {
|
||||
if(t.gui.text_button_left_transparent("Copy", "Copy")) {
|
||||
selection.selection_to_clipboard();
|
||||
shouldClose = true;
|
||||
}
|
||||
if(t.gui.text_button_left_transparent("Cut", "Cut")) {
|
||||
selection.selection_to_clipboard();
|
||||
selection.delete_all();
|
||||
shouldClose = true;
|
||||
}
|
||||
if(t.gui.text_button_left_transparent("Delete", "Delete")) {
|
||||
selection.delete_all();
|
||||
shouldClose = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
return !shouldClose;
|
||||
}
|
||||
|
|
@ -268,7 +269,7 @@ void DrawingProgram::update() {
|
|||
else if(world.main.input.key(InputManager::KEY_DRAW_TOOL_PAN).pressed)
|
||||
switch_to_tool(DrawingProgramToolType::PAN);
|
||||
|
||||
//selection.update();
|
||||
selection.update();
|
||||
drawTool->tool_update();
|
||||
|
||||
// Switch tools after the tool update, not before, so that we dont have to call erase_component on the toolToSwitchToAfterUpdate as well (components will not be erased in this time period)
|
||||
|
|
@ -287,6 +288,16 @@ void DrawingProgram::update() {
|
|||
rebuild_cache();
|
||||
}
|
||||
|
||||
void DrawingProgram::invalidate_cache_at_component(const CanvasComponentContainer::ObjInfoSharedPtr& objToCheck) {
|
||||
if(!selection.is_selected(objToCheck))
|
||||
drawCache.invalidate_cache_at_aabb(objToCheck->obj->get_world_bounds());
|
||||
}
|
||||
|
||||
void DrawingProgram::preupdate_component(const CanvasComponentContainer::ObjInfoSharedPtr& objToCheck) {
|
||||
if(!selection.is_selected(objToCheck))
|
||||
drawCache.preupdate_component(objToCheck);
|
||||
}
|
||||
|
||||
void DrawingProgram::check_updateable_components() {
|
||||
for(auto& comp : updateableComponents)
|
||||
comp->obj->get_comp().update(*this);
|
||||
|
|
@ -338,7 +349,7 @@ void DrawingProgram::rebuild_cache() {
|
|||
drawCache.build(eraserTool->erasedComponents);
|
||||
}
|
||||
else if(is_selection_allowing_tool(drawTool->get_type())) {
|
||||
//compCache.test_rebuild_dont_include_set(components->get_data(), selection.get_selected_set(), true);
|
||||
drawCache.build(selection.get_selected_set());
|
||||
}
|
||||
else
|
||||
drawCache.build({});
|
||||
|
|
@ -508,9 +519,9 @@ void DrawingProgram::draw(SkCanvas* canvas, const DrawData& drawData) {
|
|||
canvas->clear(SkColor4f{0.0f, 0.0f, 0.0f, 0.0f});
|
||||
drawCache.refresh_all_draw_cache(drawData);
|
||||
drawCache.draw_components_to_canvas(canvas, drawData, {});
|
||||
//canvas->saveLayer(nullptr, nullptr);
|
||||
// selection.draw_components(canvas, drawData);
|
||||
//canvas->restore();
|
||||
canvas->saveLayer(nullptr, nullptr);
|
||||
selection.draw_components(canvas, drawData);
|
||||
canvas->restore();
|
||||
canvas->restore();
|
||||
|
||||
if(!drawData.main->takingScreenshot) {
|
||||
|
|
@ -526,7 +537,7 @@ void DrawingProgram::draw(SkCanvas* canvas, const DrawData& drawData) {
|
|||
}
|
||||
}
|
||||
|
||||
//selection.draw_gui(canvas, drawData);
|
||||
selection.draw_gui(canvas, drawData);
|
||||
}
|
||||
|
||||
drawTool->draw(canvas, drawData);
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
#include <Helpers/FileDownloader.hpp>
|
||||
#include <Helpers/NetworkingObjects/NetObjOrderedList.hpp>
|
||||
#include "Layers/DrawingProgramLayerManager.hpp"
|
||||
#include "DrawingProgramSelection.hpp"
|
||||
|
||||
class World;
|
||||
|
||||
|
|
@ -49,6 +50,8 @@ class DrawingProgram {
|
|||
void switch_to_tool_ptr(std::unique_ptr<DrawingProgramToolBase> newTool);
|
||||
void modify_grid(const NetworkingObjects::NetObjWeakPtr<WorldGrid>& gridToModify);
|
||||
|
||||
void invalidate_cache_at_component(const CanvasComponentContainer::ObjInfoSharedPtr& objToCheck);
|
||||
void preupdate_component(const CanvasComponentContainer::ObjInfoSharedPtr& objToCheck);
|
||||
private:
|
||||
void drag_drop_update();
|
||||
void add_file_to_canvas_by_path_execute(const std::filesystem::path& filePath, Vector2f dropPos);
|
||||
|
|
@ -70,7 +73,7 @@ class DrawingProgram {
|
|||
bool is_actual_selection_tool(DrawingProgramToolType typeToCheck);
|
||||
bool is_selection_allowing_tool(DrawingProgramToolType typeToCheck);
|
||||
|
||||
//DrawingProgramSelection selection;
|
||||
DrawingProgramSelection selection;
|
||||
|
||||
std::unique_ptr<DrawingProgramToolBase> toolToSwitchToAfterUpdate;
|
||||
std::unordered_set<CanvasComponentContainer::ObjInfoSharedPtr> updateableComponents;
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
#include "DrawingProgram.hpp"
|
||||
#include "../World.hpp"
|
||||
#include "../MainProgram.hpp"
|
||||
#include "Layers/DrawingProgramLayerManager.hpp"
|
||||
|
||||
#ifdef USE_SKIA_BACKEND_GRAPHITE
|
||||
#include <include/gpu/graphite/Surface.h>
|
||||
|
|
@ -10,7 +11,7 @@
|
|||
#include <include/gpu/ganesh/SkSurfaceGanesh.h>
|
||||
#endif
|
||||
|
||||
std::unordered_map<std::shared_ptr<DrawingProgramCache::BVHNode>, DrawingProgramCache::NodeCache> DrawingProgramCache::nodeCacheMap;
|
||||
std::unordered_map<std::shared_ptr<DrawingProgramCacheBVHNode>, DrawingProgramCache::NodeCache> DrawingProgramCache::nodeCacheMap;
|
||||
|
||||
DrawingProgramCache::DrawingProgramCache(DrawingProgram& initDrawP):
|
||||
drawP(initDrawP)
|
||||
|
|
@ -22,9 +23,11 @@ void DrawingProgramCache::add_component(const CanvasComponentContainer::ObjInfoS
|
|||
}
|
||||
|
||||
void DrawingProgramCache::erase_component(const CanvasComponentContainer::ObjInfoSharedPtr& c) {
|
||||
auto it = objToBVHNode.find(c);
|
||||
if(it != objToBVHNode.end())
|
||||
objToBVHNode.erase(it);
|
||||
auto cacheParentBvhNodeLock = c->obj->cacheParentBvhNode.lock();
|
||||
if(cacheParentBvhNodeLock) {
|
||||
std::erase(cacheParentBvhNodeLock->components, c);
|
||||
c->obj->cacheParentBvhNode.reset();
|
||||
}
|
||||
else
|
||||
std::erase(unsortedComponents, c);
|
||||
invalidate_cache_at_aabb(c->obj->get_world_bounds());
|
||||
|
|
@ -52,8 +55,6 @@ bool DrawingProgramCache::unsorted_components_exist() const {
|
|||
}
|
||||
|
||||
void DrawingProgramCache::build(const std::unordered_set<CanvasComponentContainer::ObjInfoSharedPtr>& objsToExclude) {
|
||||
static int i = 0;
|
||||
std::cout << "rebuilding... " << i++ << std::endl;
|
||||
internal_build(drawP.layerMan.get_flattened_component_list(), objsToExclude);
|
||||
}
|
||||
|
||||
|
|
@ -61,7 +62,7 @@ void DrawingProgramCache::internal_build(std::vector<CanvasComponentContainer::O
|
|||
std::erase_if(componentsToBuild, [&objsToNotInclude](auto& c) {
|
||||
return objsToNotInclude.contains(c);
|
||||
});
|
||||
bvhRoot = std::make_shared<BVHNode>();
|
||||
bvhRoot = std::make_shared<DrawingProgramCacheBVHNode>();
|
||||
unsortedComponents.clear();
|
||||
clear_own_cached_surfaces();
|
||||
build_bvh_node(bvhRoot, componentsToBuild);
|
||||
|
|
@ -73,17 +74,52 @@ void DrawingProgramCache::clear_own_cached_surfaces() {
|
|||
});
|
||||
}
|
||||
|
||||
CanvasComponentContainer::ObjInfoSharedPtr DrawingProgramCache::get_front_object_colliding_with_in_editing_layer(const SCollision::ColliderCollection<float>& cC) {
|
||||
auto cCWorld = drawP.world.drawData.cam.c.collider_to_world<SCollision::ColliderCollection<WorldScalar>, SCollision::ColliderCollection<float>>(cC);
|
||||
CanvasComponentContainer::ObjInfoSharedPtr p;
|
||||
traverse_bvh_run_function(cCWorld.bounds, [&](const std::shared_ptr<DrawingProgramCacheBVHNode>& bvhNode) {
|
||||
node_loop_components(bvhNode, [&](const auto& c) {
|
||||
if(drawP.layerMan.component_passes_layer_selector(c, DrawingProgramLayerManager::LayerSelector::LAYER_BEING_EDITED) && (!p || c->pos >= p->pos) && c->obj->collides_with_world_coords(drawP.world.drawData.cam.c, cCWorld))
|
||||
p = c;
|
||||
});
|
||||
return true;
|
||||
});
|
||||
return p;
|
||||
}
|
||||
|
||||
void DrawingProgramCache::node_loop_erase_if_components(const std::shared_ptr<DrawingProgramCacheBVHNode>& bvhNode, std::function<bool(const CanvasComponentContainer::ObjInfoSharedPtr& comp)> f) {
|
||||
if(bvhNode) {
|
||||
std::erase_if(bvhNode->components, [&f](const auto& comp) {
|
||||
if(f(comp)) {
|
||||
comp->obj->cacheParentBvhNode.reset();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
else
|
||||
std::erase_if(unsortedComponents, f);
|
||||
}
|
||||
|
||||
void DrawingProgramCache::node_loop_components(const std::shared_ptr<DrawingProgramCacheBVHNode>& bvhNode, std::function<void(const CanvasComponentContainer::ObjInfoSharedPtr& comp)> f) {
|
||||
if(bvhNode)
|
||||
std::for_each(bvhNode->components.begin(), bvhNode->components.end(), f);
|
||||
else
|
||||
std::for_each(unsortedComponents.begin(), unsortedComponents.end(), f);
|
||||
}
|
||||
|
||||
void DrawingProgramCache::preupdate_component(const CanvasComponentContainer::ObjInfoSharedPtr& c) {
|
||||
// Can be called even if object isn't in cache yet. In that case, it'll just invalidate the cache at the object's AABB
|
||||
auto it = objToBVHNode.find(c);
|
||||
if(it != objToBVHNode.end()) {
|
||||
auto cacheParentBvhNodeLock = c->obj->cacheParentBvhNode.lock();
|
||||
if(cacheParentBvhNodeLock) {
|
||||
unsortedComponents.emplace_back(c);
|
||||
std::erase(it->second->components, c);
|
||||
std::erase(cacheParentBvhNodeLock->components, c);
|
||||
c->obj->cacheParentBvhNode.reset();
|
||||
}
|
||||
invalidate_cache_at_aabb(c->obj->get_world_bounds());
|
||||
}
|
||||
|
||||
void DrawingProgramCache::build_bvh_node(const std::shared_ptr<BVHNode>& bvhNode, const std::vector<CanvasComponentContainer::ObjInfoSharedPtr>& components) {
|
||||
void DrawingProgramCache::build_bvh_node(const std::shared_ptr<DrawingProgramCacheBVHNode>& bvhNode, const std::vector<CanvasComponentContainer::ObjInfoSharedPtr>& components) {
|
||||
if(components.empty())
|
||||
return;
|
||||
|
||||
|
|
@ -96,7 +132,7 @@ void DrawingProgramCache::build_bvh_node(const std::shared_ptr<BVHNode>& bvhNode
|
|||
if(components.size() < MAXIMUM_COMPONENTS_IN_SINGLE_NODE) {
|
||||
bvhNode->components = components;
|
||||
for(auto& c : bvhNode->components)
|
||||
objToBVHNode.emplace(c, bvhNode);
|
||||
c->obj->cacheParentBvhNode = bvhNode;
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -116,17 +152,17 @@ void DrawingProgramCache::build_bvh_node(const std::shared_ptr<BVHNode>& bvhNode
|
|||
parts[3].emplace_back(c);
|
||||
else {
|
||||
bvhNode->components.emplace_back(c);
|
||||
objToBVHNode.emplace(c, bvhNode);
|
||||
c->obj->cacheParentBvhNode = bvhNode;
|
||||
}
|
||||
}
|
||||
|
||||
for(auto& p : parts) {
|
||||
if(!p.empty())
|
||||
build_bvh_node(bvhNode->children.emplace_back(std::make_shared<BVHNode>()), p);
|
||||
build_bvh_node(bvhNode->children.emplace_back(std::make_shared<DrawingProgramCacheBVHNode>()), p);
|
||||
}
|
||||
}
|
||||
|
||||
void DrawingProgramCache::build_bvh_node_coords_and_resolution(BVHNode& node) {
|
||||
void DrawingProgramCache::build_bvh_node_coords_and_resolution(DrawingProgramCacheBVHNode& node) {
|
||||
// These are part of the draw cache data, but we're putting it out here, because:
|
||||
// - We dont have to recalculate it every time we refresh the cache
|
||||
// - Some of the data here is needed to determine whether to generate the cache in the first place
|
||||
|
|
@ -152,8 +188,8 @@ void DrawingProgramCache::build_bvh_node_coords_and_resolution(BVHNode& node) {
|
|||
}
|
||||
|
||||
void DrawingProgramCache::refresh_all_draw_cache(const DrawData& drawData) {
|
||||
std::deque<std::shared_ptr<BVHNode>> 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<BVHNode> node, const std::vector<CanvasComponentContainer::ObjInfoSharedPtr>& comps) {
|
||||
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) {
|
||||
if(node && node->coords.inverseScale <= drawData.cam.c.inverseScale) {
|
||||
auto it = nodeCacheMap.find(node);
|
||||
if((it == nodeCacheMap.end()) || it->second.invalidBounds.has_value())
|
||||
|
|
@ -166,43 +202,26 @@ void DrawingProgramCache::refresh_all_draw_cache(const DrawData& drawData) {
|
|||
refresh_draw_cache(nodeFlatList.front(), drawData);
|
||||
}
|
||||
|
||||
void DrawingProgramCache::traverse_bvh_run_function(const SCollision::AABB<WorldScalar>& aabb, std::function<bool(const std::shared_ptr<BVHNode>& 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(const SCollision::AABB<WorldScalar>& aabb, std::function<bool(const std::shared_ptr<DrawingProgramCacheBVHNode>& node)> f) {
|
||||
f(nullptr);
|
||||
traverse_bvh_run_function_starting_at_node(bvhRoot, aabb, f);
|
||||
}
|
||||
|
||||
void DrawingProgramCache::traverse_bvh_erase_function(const SCollision::AABB<WorldScalar>& aabb, std::function<bool(const std::shared_ptr<BVHNode>& node, std::vector<CanvasComponentContainer::ObjInfoSharedPtr>& components)> f) {
|
||||
f(nullptr, unsortedComponents);
|
||||
if(traverse_bvh_erase_function_recursive(bvhRoot, aabb, f))
|
||||
bvhRoot = nullptr;
|
||||
}
|
||||
|
||||
void DrawingProgramCache::traverse_bvh_run_function_recursive(const std::shared_ptr<BVHNode>& bvhNode, const SCollision::AABB<WorldScalar>& aabb, std::function<bool(const std::shared_ptr<BVHNode>& node, const std::vector<CanvasComponentContainer::ObjInfoSharedPtr>& components)> f) {
|
||||
if(bvhNode && SCollision::collide(aabb, bvhNode->bounds) && f(bvhNode, bvhNode->components)) {
|
||||
void DrawingProgramCache::traverse_bvh_run_function_starting_at_node(const std::shared_ptr<DrawingProgramCacheBVHNode>& bvhNode, const SCollision::AABB<WorldScalar>& aabb, std::function<bool(const std::shared_ptr<DrawingProgramCacheBVHNode>& node)> f) {
|
||||
if(bvhNode && SCollision::collide(aabb, bvhNode->bounds) && f(bvhNode)) {
|
||||
for(auto& p : bvhNode->children)
|
||||
traverse_bvh_run_function_recursive(p, aabb, f);
|
||||
traverse_bvh_run_function_starting_at_node(p, aabb, f);
|
||||
}
|
||||
}
|
||||
|
||||
bool DrawingProgramCache::traverse_bvh_erase_function_recursive(const std::shared_ptr<BVHNode>& bvhNode, const SCollision::AABB<WorldScalar>& aabb, std::function<bool(const std::shared_ptr<BVHNode>& node, std::vector<CanvasComponentContainer::ObjInfoSharedPtr>& components)> f) {
|
||||
if(bvhNode && SCollision::collide(aabb, bvhNode->bounds)) {
|
||||
if(f(bvhNode, bvhNode->components))
|
||||
return true;
|
||||
std::erase_if(bvhNode->children, [&](auto& p) {
|
||||
return traverse_bvh_erase_function_recursive(p, aabb, f);
|
||||
});
|
||||
void DrawingProgramCache::traverse_bvh_run_function_starting_at_node_no_collision_check(const std::shared_ptr<DrawingProgramCacheBVHNode>& bvhNode, std::function<bool(const std::shared_ptr<DrawingProgramCacheBVHNode>& node)> f) {
|
||||
if(bvhNode && f(bvhNode)) {
|
||||
for(auto& p : bvhNode->children)
|
||||
traverse_bvh_run_function_starting_at_node_no_collision_check(p, f);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void DrawingProgramCache::move_components_from_bvh_node_to_set(std::unordered_set<CanvasComponentContainer::ObjInfoSharedPtr>& s, const std::shared_ptr<BVHNode>& 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::refresh_draw_cache(const std::shared_ptr<BVHNode>& bvhNode, const DrawData& drawData) {
|
||||
void DrawingProgramCache::refresh_draw_cache(const std::shared_ptr<DrawingProgramCacheBVHNode>& bvhNode, const DrawData& drawData) {
|
||||
if(bvhNode->children.empty() && bvhNode->components.empty())
|
||||
return;
|
||||
|
||||
|
|
@ -286,10 +305,10 @@ void DrawingProgramCache::refresh_draw_cache(const std::shared_ptr<BVHNode>& bvh
|
|||
|
||||
void DrawingProgramCache::draw_components_to_canvas(SkCanvas* canvas, const DrawData& drawData, const std::optional<SCollision::AABB<WorldScalar>>& drawBounds) {
|
||||
if(drawP.layerMan.layer_tree_root_exists()) {
|
||||
std::vector<std::shared_ptr<BVHNode>> cachedNodesToDraw;
|
||||
std::vector<std::shared_ptr<BVHNode>> uncachedNodes;
|
||||
std::vector<std::shared_ptr<DrawingProgramCacheBVHNode>> cachedNodesToDraw;
|
||||
std::vector<std::shared_ptr<DrawingProgramCacheBVHNode>> uncachedNodes;
|
||||
|
||||
traverse_bvh_run_function(drawData.cam.viewingAreaGenerousCollider, [&](const std::shared_ptr<BVHNode>& node, const std::vector<CanvasComponentContainer::ObjInfoSharedPtr>& comps) {
|
||||
traverse_bvh_run_function(drawData.cam.viewingAreaGenerousCollider, [&](const std::shared_ptr<DrawingProgramCacheBVHNode>& node) {
|
||||
if(node) {
|
||||
auto it = nodeCacheMap.find(node);
|
||||
if(it != nodeCacheMap.end()) {
|
||||
|
|
@ -312,7 +331,7 @@ void DrawingProgramCache::draw_components_to_canvas(SkCanvas* canvas, const Draw
|
|||
}
|
||||
}
|
||||
|
||||
void DrawingProgramCache::recursive_draw_layer_item_to_canvas(const DrawingProgramLayerListItem& layerListItem, SkCanvas* canvas, const DrawData& drawData, const std::optional<SCollision::AABB<WorldScalar>>& drawBounds, const std::vector<std::shared_ptr<BVHNode>>& nodesToDraw) {
|
||||
void DrawingProgramCache::recursive_draw_layer_item_to_canvas(const DrawingProgramLayerListItem& layerListItem, SkCanvas* canvas, const DrawData& drawData, const std::optional<SCollision::AABB<WorldScalar>>& drawBounds, const std::vector<std::shared_ptr<DrawingProgramCacheBVHNode>>& nodesToDraw) {
|
||||
if(layerListItem.get_visible()) {
|
||||
SkPaint layerPaint;
|
||||
layerPaint.setAlphaf(layerListItem.get_alpha());
|
||||
|
|
@ -344,7 +363,7 @@ void DrawingProgramCache::recursive_draw_layer_item_to_canvas(const DrawingProgr
|
|||
}
|
||||
}
|
||||
|
||||
void DrawingProgramCache::draw_cache_image_to_canvas(SkCanvas* canvas, const DrawData& drawData, const std::shared_ptr<BVHNode>& bvhNode) {
|
||||
void DrawingProgramCache::draw_cache_image_to_canvas(SkCanvas* canvas, const DrawData& drawData, const std::shared_ptr<DrawingProgramCacheBVHNode>& bvhNode) {
|
||||
auto it = nodeCacheMap.find(bvhNode);
|
||||
if(it != nodeCacheMap.end()) {
|
||||
auto& nodeCache = it->second;
|
||||
|
|
@ -360,3 +379,7 @@ void DrawingProgramCache::draw_cache_image_to_canvas(SkCanvas* canvas, const Dra
|
|||
canvas->restore();
|
||||
}
|
||||
}
|
||||
|
||||
DrawingProgramCache::~DrawingProgramCache() {
|
||||
clear_own_cached_surfaces();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,34 +2,41 @@
|
|||
#include "../CanvasComponents/CanvasComponentContainer.hpp"
|
||||
#include <unordered_map>
|
||||
|
||||
struct DrawingProgramCacheBVHNode {
|
||||
public:
|
||||
SCollision::AABB<WorldScalar> bounds;
|
||||
CoordSpaceHelper coords;
|
||||
Vector2i resolution;
|
||||
private:
|
||||
std::vector<CanvasComponentContainer::ObjInfoSharedPtr> components;
|
||||
std::vector<std::shared_ptr<DrawingProgramCacheBVHNode>> children;
|
||||
friend class DrawingProgramCache;
|
||||
};
|
||||
|
||||
class DrawingProgramCache {
|
||||
public:
|
||||
static constexpr size_t MINIMUM_COMPONENTS_TO_START_REBUILD = 1000;
|
||||
static constexpr size_t MAXIMUM_COMPONENTS_IN_SINGLE_NODE = 50;
|
||||
static constexpr size_t MINIMUM_COMPONENTS_TO_START_REBUILD = 10;
|
||||
static constexpr size_t MAXIMUM_COMPONENTS_IN_SINGLE_NODE = 3;
|
||||
static constexpr size_t MAXIMUM_DRAW_CACHE_SURFACES = 40;
|
||||
|
||||
struct BVHNode {
|
||||
SCollision::AABB<WorldScalar> bounds;
|
||||
std::vector<CanvasComponentContainer::ObjInfoSharedPtr> components;
|
||||
std::vector<std::shared_ptr<BVHNode>> children;
|
||||
CoordSpaceHelper coords;
|
||||
Vector2i resolution;
|
||||
};
|
||||
|
||||
DrawingProgramCache(DrawingProgram& initDrawP);
|
||||
void add_component(const CanvasComponentContainer::ObjInfoSharedPtr& c);
|
||||
void erase_component(const CanvasComponentContainer::ObjInfoSharedPtr& c);
|
||||
void clear_own_cached_surfaces();
|
||||
void preupdate_component(const CanvasComponentContainer::ObjInfoSharedPtr& c);
|
||||
void build(const std::unordered_set<CanvasComponentContainer::ObjInfoSharedPtr>& objsToExclude);
|
||||
void traverse_bvh_run_function(const SCollision::AABB<WorldScalar>& aabb, std::function<bool(const std::shared_ptr<BVHNode>& 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<BVHNode>& node, std::vector<CanvasComponentContainer::ObjInfoSharedPtr>& components)> f);
|
||||
void traverse_bvh_run_function(const SCollision::AABB<WorldScalar>& aabb, std::function<bool(const std::shared_ptr<DrawingProgramCacheBVHNode>& node)> f);
|
||||
void traverse_bvh_run_function_starting_at_node(const std::shared_ptr<DrawingProgramCacheBVHNode>& bvhNode, const SCollision::AABB<WorldScalar>& aabb, std::function<bool(const std::shared_ptr<DrawingProgramCacheBVHNode>& node)> f);
|
||||
void traverse_bvh_run_function_starting_at_node_no_collision_check(const std::shared_ptr<DrawingProgramCacheBVHNode>& bvhNode, std::function<bool(const std::shared_ptr<DrawingProgramCacheBVHNode>& node)> f);
|
||||
void node_loop_erase_if_components(const std::shared_ptr<DrawingProgramCacheBVHNode>& bvhNode, std::function<bool(const CanvasComponentContainer::ObjInfoSharedPtr& comp)> f);
|
||||
void node_loop_components(const std::shared_ptr<DrawingProgramCacheBVHNode>& bvhNode, std::function<void(const CanvasComponentContainer::ObjInfoSharedPtr& comp)> f);
|
||||
bool should_rebuild() const;
|
||||
void draw_components_to_canvas(SkCanvas* canvas, const DrawData& drawData, const std::optional<SCollision::AABB<WorldScalar>>& drawBounds);
|
||||
bool unsorted_components_exist() const;
|
||||
void invalidate_cache_at_aabb(const SCollision::AABB<WorldScalar>& aabb);
|
||||
void move_components_from_bvh_node_to_set(std::unordered_set<CanvasComponentContainer::ObjInfoSharedPtr>& s, const std::shared_ptr<BVHNode>& bvhNode);
|
||||
void refresh_all_draw_cache(const DrawData& drawData);
|
||||
CanvasComponentContainer::ObjInfoSharedPtr get_front_object_colliding_with_in_editing_layer(const SCollision::ColliderCollection<float>& cC);
|
||||
~DrawingProgramCache();
|
||||
private:
|
||||
struct NodeCache {
|
||||
sk_sp<SkSurface> surface;
|
||||
|
|
@ -37,19 +44,16 @@ class DrawingProgramCache {
|
|||
DrawingProgramCache* attachedDrawingProgramCache;
|
||||
std::optional<SCollision::AABB<WorldScalar>> invalidBounds;
|
||||
};
|
||||
static std::unordered_map<std::shared_ptr<BVHNode>, NodeCache> nodeCacheMap;
|
||||
static std::unordered_map<std::shared_ptr<DrawingProgramCacheBVHNode>, NodeCache> nodeCacheMap;
|
||||
|
||||
void internal_build(std::vector<CanvasComponentContainer::ObjInfoSharedPtr> componentsToBuild, const std::unordered_set<CanvasComponentContainer::ObjInfoSharedPtr>& objsToNotInclude);
|
||||
void build_bvh_node(const std::shared_ptr<BVHNode>& bvhNode, const std::vector<CanvasComponentContainer::ObjInfoSharedPtr>& components);
|
||||
void build_bvh_node_coords_and_resolution(BVHNode& node);
|
||||
void refresh_draw_cache(const std::shared_ptr<BVHNode>& bvhNode, const DrawData& drawData);
|
||||
void traverse_bvh_run_function_recursive(const std::shared_ptr<BVHNode>& bvhNode, const SCollision::AABB<WorldScalar>& aabb, std::function<bool(const std::shared_ptr<BVHNode>& node, const std::vector<CanvasComponentContainer::ObjInfoSharedPtr>& components)> f);
|
||||
bool traverse_bvh_erase_function_recursive(const std::shared_ptr<BVHNode>& bvhNode, const SCollision::AABB<WorldScalar>& aabb, std::function<bool(const std::shared_ptr<BVHNode>& node, std::vector<CanvasComponentContainer::ObjInfoSharedPtr>& components)> f);
|
||||
void draw_cache_image_to_canvas(SkCanvas* canvas, const DrawData& drawData, const std::shared_ptr<BVHNode>& bvhNode);
|
||||
void recursive_draw_layer_item_to_canvas(const DrawingProgramLayerListItem& layerListItem, SkCanvas* canvas, const DrawData& drawData, const std::optional<SCollision::AABB<WorldScalar>>& drawBounds, const std::vector<std::shared_ptr<BVHNode>>& nodesToDraw);
|
||||
void build_bvh_node(const std::shared_ptr<DrawingProgramCacheBVHNode>& bvhNode, const std::vector<CanvasComponentContainer::ObjInfoSharedPtr>& components);
|
||||
void build_bvh_node_coords_and_resolution(DrawingProgramCacheBVHNode& node);
|
||||
void refresh_draw_cache(const std::shared_ptr<DrawingProgramCacheBVHNode>& bvhNode, const DrawData& drawData);
|
||||
void draw_cache_image_to_canvas(SkCanvas* canvas, const DrawData& drawData, const std::shared_ptr<DrawingProgramCacheBVHNode>& bvhNode);
|
||||
void recursive_draw_layer_item_to_canvas(const DrawingProgramLayerListItem& layerListItem, SkCanvas* canvas, const DrawData& drawData, const std::optional<SCollision::AABB<WorldScalar>>& drawBounds, const std::vector<std::shared_ptr<DrawingProgramCacheBVHNode>>& nodesToDraw);
|
||||
|
||||
std::unordered_map<CanvasComponentContainer::ObjInfoSharedPtr, std::shared_ptr<BVHNode>> objToBVHNode;
|
||||
std::shared_ptr<BVHNode> bvhRoot;
|
||||
std::shared_ptr<DrawingProgramCacheBVHNode> bvhRoot;
|
||||
std::vector<CanvasComponentContainer::ObjInfoSharedPtr> unsortedComponents;
|
||||
DrawingProgram& drawP;
|
||||
};
|
||||
|
|
|
|||
471
src/DrawingProgram/DrawingProgramSelection.cpp
Normal file
471
src/DrawingProgram/DrawingProgramSelection.cpp
Normal file
|
|
@ -0,0 +1,471 @@
|
|||
#include "DrawingProgramSelection.hpp"
|
||||
#include "DrawingProgram.hpp"
|
||||
#include "../World.hpp"
|
||||
#include "../MainProgram.hpp"
|
||||
#include "../InputManager.hpp"
|
||||
#include <Helpers/Parallel.hpp>
|
||||
|
||||
#ifdef USE_SKIA_BACKEND_GRAPHITE
|
||||
#include <include/gpu/graphite/Surface.h>
|
||||
#elif USE_SKIA_BACKEND_GANESH
|
||||
#include <include/gpu/ganesh/GrDirectContext.h>
|
||||
#include <include/gpu/ganesh/SkSurfaceGanesh.h>
|
||||
#endif
|
||||
#include <include/effects/SkImageFilters.h>
|
||||
#include <include/core/SkPathBuilder.h>
|
||||
|
||||
#define ROTATION_POINT_RADIUS_MULTIPLIER 0.7f
|
||||
#define ROTATION_POINTS_DISTANCE 20.0f
|
||||
|
||||
DrawingProgramSelection::DrawingProgramSelection(DrawingProgram& initDrawP):
|
||||
drawP(initDrawP)
|
||||
{}
|
||||
|
||||
void DrawingProgramSelection::add_from_cam_coord_collider_to_selection(const SCollision::ColliderCollection<float>& cC, DrawingProgramLayerManager::LayerSelector layerSelector, bool frontObjectOnly) {
|
||||
std::unordered_set<CanvasComponentContainer::ObjInfoSharedPtr> selectedComponents;
|
||||
if(frontObjectOnly) {
|
||||
CanvasComponentContainer::ObjInfoSharedPtr a = drawP.drawCache.get_front_object_colliding_with_in_editing_layer(cC);
|
||||
if(a) {
|
||||
selectedComponents.emplace(a);
|
||||
drawP.drawCache.erase_component(a);
|
||||
}
|
||||
}
|
||||
else {
|
||||
auto cCWorld = drawP.world.drawData.cam.c.collider_to_world<SCollision::ColliderCollection<WorldScalar>, SCollision::ColliderCollection<float>>(cC);
|
||||
drawP.drawCache.traverse_bvh_run_function(cCWorld.bounds, erase_select_objects_in_bvh_func(selectedComponents, cC, cCWorld, layerSelector));
|
||||
}
|
||||
add_to_selection(selectedComponents);
|
||||
}
|
||||
|
||||
void DrawingProgramSelection::remove_from_cam_coord_collider_to_selection(const SCollision::ColliderCollection<float>& cC, DrawingProgramLayerManager::LayerSelector layerSelector, bool frontObjectOnly) {
|
||||
if(frontObjectOnly) {
|
||||
CanvasComponentContainer::ObjInfoSharedPtr p = get_front_object_colliding_with_in_editing_layer(cC);
|
||||
if(p) {
|
||||
drawP.drawCache.add_component(p);
|
||||
selectedSet.erase(p);
|
||||
}
|
||||
}
|
||||
else {
|
||||
auto cCWorld = drawP.world.drawData.cam.c.collider_to_world<SCollision::ColliderCollection<WorldScalar>, SCollision::ColliderCollection<float>>(cC);
|
||||
std::erase_if(selectedSet, [&](auto& c) {
|
||||
if(drawP.layerMan.component_passes_layer_selector(c, layerSelector) && c->obj->collides_with(drawP.world.drawData.cam.c, cCWorld, cC)) {
|
||||
drawP.drawCache.add_component(c);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
calculate_aabb();
|
||||
}
|
||||
|
||||
std::function<bool(const std::shared_ptr<DrawingProgramCacheBVHNode>&)> DrawingProgramSelection::erase_select_objects_in_bvh_func(std::unordered_set<CanvasComponentContainer::ObjInfoSharedPtr>& selectedComponents, const SCollision::ColliderCollection<float>& cC, const SCollision::ColliderCollection<WorldScalar>& cCWorld, DrawingProgramLayerManager::LayerSelector layerSelector) {
|
||||
auto toRet = [&](const auto& bvhNode) {
|
||||
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)) &&
|
||||
SCollision::collide(cC, drawP.world.drawData.cam.c.to_space(bvhNode->bounds.max)) &&
|
||||
SCollision::collide(cC, drawP.world.drawData.cam.c.to_space(bvhNode->bounds.top_right())) &&
|
||||
SCollision::collide(cC, drawP.world.drawData.cam.c.to_space(bvhNode->bounds.bottom_left()))) {
|
||||
drawP.drawCache.invalidate_cache_at_aabb(bvhNode->bounds);
|
||||
drawP.drawCache.traverse_bvh_run_function_starting_at_node_no_collision_check(bvhNode, [&](const auto& bvhNodeChild) {
|
||||
drawP.drawCache.node_loop_erase_if_components(bvhNodeChild, [&](auto& c) {
|
||||
if(drawP.layerMan.component_passes_layer_selector(c, drawP.controls.layerSelector)) {
|
||||
selectedComponents.emplace(c);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
return true;
|
||||
});
|
||||
return false;
|
||||
}
|
||||
drawP.drawCache.node_loop_erase_if_components(bvhNode, [&](auto& c) {
|
||||
if(drawP.layerMan.component_passes_layer_selector(c, drawP.controls.layerSelector) && c->obj->collides_with(drawP.world.drawData.cam.c, cCWorld, cC)) {
|
||||
selectedComponents.emplace(c);
|
||||
drawP.drawCache.invalidate_cache_at_aabb(c->obj->get_world_bounds());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
return true;
|
||||
};
|
||||
|
||||
return toRet;
|
||||
}
|
||||
|
||||
void DrawingProgramSelection::add_to_selection(const std::unordered_set<CanvasComponentContainer::ObjInfoSharedPtr>& newSelection) {
|
||||
selectedSet.insert(newSelection.begin(), newSelection.end());
|
||||
calculate_aabb();
|
||||
}
|
||||
|
||||
void DrawingProgramSelection::set_to_selection(const std::unordered_set<CanvasComponentContainer::ObjInfoSharedPtr>& newSelection) {
|
||||
selectedSet = newSelection;
|
||||
calculate_aabb();
|
||||
}
|
||||
|
||||
void DrawingProgramSelection::calculate_aabb() {
|
||||
if(is_something_selected()) {
|
||||
initialSelectionAABB = (*selectedSet.begin())->obj->get_world_bounds();
|
||||
for(auto& c : selectedSet)
|
||||
initialSelectionAABB.include_aabb_in_bounds(c->obj->get_world_bounds());
|
||||
rotateData.centerPos = initialSelectionAABB.center();
|
||||
}
|
||||
}
|
||||
|
||||
bool DrawingProgramSelection::is_something_selected() {
|
||||
return !selectedSet.empty();
|
||||
}
|
||||
|
||||
bool DrawingProgramSelection::is_selected(const CanvasComponentContainer::ObjInfoSharedPtr& objToCheck) {
|
||||
return selectedSet.contains(objToCheck);
|
||||
}
|
||||
|
||||
void DrawingProgramSelection::reset_all() {
|
||||
selectedSet.clear();
|
||||
selectionTransformCoords = CoordSpaceHelperTransform();
|
||||
transformOpHappening = TransformOperation::NONE;
|
||||
translateData = TranslationData();
|
||||
scaleData = ScaleData();
|
||||
rotateData = RotationData();
|
||||
}
|
||||
|
||||
bool DrawingProgramSelection::mouse_collided_with_selection_aabb() {
|
||||
return SCollision::collide(camSpaceSelection, drawP.world.main.input.mouse.pos);
|
||||
}
|
||||
|
||||
bool DrawingProgramSelection::mouse_collided_with_scale_point() {
|
||||
return SCollision::collide(SCollision::Circle(scaleData.handlePoint, drawP.drag_point_radius()), drawP.world.main.input.mouse.pos);
|
||||
}
|
||||
|
||||
bool DrawingProgramSelection::mouse_collided_with_rotate_center_handle_point() {
|
||||
return SCollision::collide(SCollision::Circle(rotateData.centerHandlePoint, drawP.drag_point_radius()), drawP.world.main.input.mouse.pos);
|
||||
}
|
||||
|
||||
bool DrawingProgramSelection::mouse_collided_with_rotate_handle_point() {
|
||||
return SCollision::collide(SCollision::Circle(rotateData.handlePoint, drawP.drag_point_radius() * ROTATION_POINT_RADIUS_MULTIPLIER), drawP.world.main.input.mouse.pos);
|
||||
}
|
||||
|
||||
void DrawingProgramSelection::commit_transform_selection() {
|
||||
auto selectedSetTemp = selectedSet;
|
||||
|
||||
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);
|
||||
for(auto& comp : a) {
|
||||
comp->obj->coords = selectionTransformCoords.other_coord_space_from_this_space(comp->obj->coords);
|
||||
comp->obj->commit_transform(drawP);
|
||||
}
|
||||
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.get_net_id(), transformedObj->obj->coords);
|
||||
transformsTo.emplace_back(transformedObj, transformedObj->obj->coords);
|
||||
}
|
||||
//DrawComponent::client_send_transform_many(drawP, transformsToSend);
|
||||
|
||||
reset_all();
|
||||
set_to_selection(selectedSetTemp);
|
||||
}
|
||||
|
||||
void DrawingProgramSelection::update() {
|
||||
if(is_something_selected()) {
|
||||
selectionRectPoints[0] = selectionTransformCoords.from_space_world(initialSelectionAABB.min);
|
||||
selectionRectPoints[1] = selectionTransformCoords.from_space_world(initialSelectionAABB.bottom_left());
|
||||
selectionRectPoints[2] = selectionTransformCoords.from_space_world(initialSelectionAABB.max);
|
||||
selectionRectPoints[3] = selectionTransformCoords.from_space_world(initialSelectionAABB.top_right());
|
||||
|
||||
scaleData.handlePoint = drawP.world.drawData.cam.c.to_space(initialSelectionAABB.max);
|
||||
rotateData.centerHandlePoint = drawP.world.drawData.cam.c.to_space(rotateData.centerPos);
|
||||
rotateData.handlePoint = get_rotation_point_pos_from_angle(rotateData.rotationAngle);
|
||||
|
||||
rebuild_cam_space();
|
||||
|
||||
if(drawP.is_actual_selection_tool(drawP.drawTool->get_type())) {
|
||||
switch(transformOpHappening) {
|
||||
case TransformOperation::NONE:
|
||||
if(drawP.controls.leftClick && !drawP.world.main.input.key(InputManager::KEY_GENERIC_LSHIFT).held && !drawP.world.main.input.key(InputManager::KEY_GENERIC_LALT).held) {
|
||||
if(mouse_collided_with_scale_point()) {
|
||||
scaleData.currentPos = scaleData.startPos = selectionTransformCoords.from_space_world(initialSelectionAABB.max);
|
||||
scaleData.centerPos = selectionTransformCoords.from_space_world(initialSelectionAABB.center());
|
||||
transformOpHappening = TransformOperation::SCALE;
|
||||
}
|
||||
else if(mouse_collided_with_rotate_center_handle_point())
|
||||
transformOpHappening = TransformOperation::ROTATE_RELOCATE_CENTER;
|
||||
else if(mouse_collided_with_rotate_handle_point()) {
|
||||
rotateData.rotationAngle = 0.0;
|
||||
transformOpHappening = TransformOperation::ROTATE;
|
||||
}
|
||||
else if(mouse_collided_with_selection_aabb()) {
|
||||
translateData.startPos = drawP.world.get_mouse_world_pos();
|
||||
transformOpHappening = TransformOperation::TRANSLATE;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TransformOperation::TRANSLATE:
|
||||
if(drawP.controls.leftClickHeld)
|
||||
selectionTransformCoords = CoordSpaceHelperTransform(drawP.world.get_mouse_world_pos() - translateData.startPos);
|
||||
else {
|
||||
commit_transform_selection();
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case TransformOperation::SCALE:
|
||||
if(drawP.controls.leftClickHeld) {
|
||||
WorldVec centerToScaleStart = scaleData.startPos - scaleData.centerPos;
|
||||
Vector2f centerToScaleStartInCamSpace = drawP.world.drawData.cam.c.normalized_dir_to_space(centerToScaleStart.normalized());
|
||||
Vector2f scaleCenterPointInCamSpace = drawP.world.drawData.cam.c.to_space(scaleData.centerPos);
|
||||
scaleData.currentPos = drawP.world.drawData.cam.c.from_space(project_point_on_line(drawP.world.main.input.mouse.pos, scaleCenterPointInCamSpace, (scaleCenterPointInCamSpace + centerToScaleStartInCamSpace).eval()));
|
||||
|
||||
WorldVec centerToScaleCurrent = scaleData.currentPos - scaleData.centerPos;
|
||||
|
||||
WorldScalar centerToScaleStartNorm = centerToScaleStart.norm();
|
||||
WorldScalar centerToScaleCurrentNorm = centerToScaleCurrent.norm();
|
||||
bool isAnyNumberZero = centerToScaleCurrentNorm == WorldScalar(0) || centerToScaleStartNorm == WorldScalar(0);
|
||||
|
||||
if(!isAnyNumberZero) {
|
||||
WorldMultiplier scaleAmount = WorldMultiplier(centerToScaleStartNorm) / WorldMultiplier(centerToScaleCurrentNorm);
|
||||
|
||||
selectionTransformCoords = CoordSpaceHelperTransform(scaleData.centerPos, scaleAmount);
|
||||
}
|
||||
}
|
||||
else {
|
||||
commit_transform_selection();
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case TransformOperation::ROTATE_RELOCATE_CENTER:
|
||||
if(drawP.controls.leftClickHeld)
|
||||
rotateData.centerPos = drawP.world.get_mouse_world_pos();
|
||||
else
|
||||
transformOpHappening = TransformOperation::NONE;
|
||||
break;
|
||||
case TransformOperation::ROTATE:
|
||||
if(drawP.controls.leftClickHeld) {
|
||||
Vector2f rotationPointDiff = drawP.world.main.input.mouse.pos - rotateData.centerHandlePoint;
|
||||
rotateData.rotationAngle = std::atan2(rotationPointDiff.y(), rotationPointDiff.x());
|
||||
selectionTransformCoords = CoordSpaceHelperTransform(rotateData.centerPos, rotateData.rotationAngle);
|
||||
}
|
||||
else {
|
||||
commit_transform_selection();
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if(transformOpHappening != TransformOperation::NONE) {
|
||||
commit_transform_selection();
|
||||
return;
|
||||
}
|
||||
|
||||
if(drawP.world.main.input.key(InputManager::KEY_GENERIC_ESCAPE).pressed)
|
||||
deselect_all();
|
||||
else if(drawP.world.main.input.key(InputManager::KEY_DRAW_DELETE).pressed)
|
||||
delete_all();
|
||||
else if(drawP.world.main.input.key(InputManager::KEY_COPY).pressed && !is_being_transformed())
|
||||
selection_to_clipboard();
|
||||
else if(drawP.world.main.input.key(InputManager::KEY_CUT).pressed && !is_being_transformed()) {
|
||||
selection_to_clipboard();
|
||||
delete_all();
|
||||
}
|
||||
else if(drawP.world.main.input.key(InputManager::KEY_PASTE).pressed) {
|
||||
deselect_all();
|
||||
paste_clipboard(drawP.world.main.input.mouse.pos);
|
||||
}
|
||||
}
|
||||
else if(drawP.world.main.input.key(InputManager::KEY_PASTE).pressed && !drawP.prevent_undo_or_redo())
|
||||
paste_clipboard(drawP.world.main.input.mouse.pos);
|
||||
else if(drawP.world.main.input.key(InputManager::KEY_GENERIC_ESCAPE).pressed)
|
||||
drawP.switch_to_tool(DrawingProgramToolType::EDIT, true);
|
||||
}
|
||||
|
||||
void DrawingProgramSelection::deselect_all() {
|
||||
if(is_something_selected()) {
|
||||
for(auto& obj : selectedSet)
|
||||
drawP.drawCache.add_component(obj);
|
||||
reset_all();
|
||||
}
|
||||
}
|
||||
|
||||
void DrawingProgramSelection::delete_all() {
|
||||
if(is_something_selected()) {
|
||||
auto selectedSetTemp = selectedSet;
|
||||
reset_all(); // Clear set before erasing, since calling erase_component_set will run a check to see if each object is selected and erase them one by one, which is slower
|
||||
drawP.layerMan.erase_component_set(selectedSetTemp);
|
||||
}
|
||||
}
|
||||
|
||||
void DrawingProgramSelection::erase_component(const CanvasComponentContainer::ObjInfoSharedPtr& objToCheck) {
|
||||
if(is_selected(objToCheck)) {
|
||||
selectedSet.erase(objToCheck);
|
||||
if(selectedSet.empty())
|
||||
reset_all();
|
||||
}
|
||||
}
|
||||
|
||||
CanvasComponentContainer::ObjInfoSharedPtr DrawingProgramSelection::get_front_object_colliding_with_in_editing_layer(const SCollision::ColliderCollection<float>& cC) {
|
||||
auto cCWorld = drawP.world.drawData.cam.c.collider_to_world<SCollision::ColliderCollection<WorldScalar>, SCollision::ColliderCollection<float>>(cC);
|
||||
CanvasComponentContainer::ObjInfoSharedPtr p;
|
||||
for(auto& c : selectedSet) {
|
||||
if(drawP.layerMan.component_passes_layer_selector(c, DrawingProgramLayerManager::LayerSelector::LAYER_BEING_EDITED) && (!p || c->pos >= p->pos) && c->obj->collides_with(drawP.world.drawData.cam.c, cCWorld, cC))
|
||||
p = c;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
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<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::paste_clipboard(Vector2f pasteScreenPos) {
|
||||
//auto& clipboard = drawP.world.main.clipboard;
|
||||
|
||||
//if(!drawP.is_selection_allowing_tool(drawP.drawTool->get_type()))
|
||||
// drawP.switch_to_tool(DrawingProgramToolType::EDIT);
|
||||
|
||||
//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->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);
|
||||
}
|
||||
|
||||
bool DrawingProgramSelection::is_being_transformed() {
|
||||
return transformOpHappening != TransformOperation::NONE;
|
||||
}
|
||||
|
||||
const std::unordered_set<CanvasComponentContainer::ObjInfoSharedPtr>& DrawingProgramSelection::get_selected_set() {
|
||||
return selectedSet;
|
||||
}
|
||||
|
||||
void DrawingProgramSelection::rebuild_cam_space() {
|
||||
SCollision::ColliderCollection<WorldScalar> collideRectWorld;
|
||||
collideRectWorld.triangle.emplace_back(selectionRectPoints[0], selectionRectPoints[1], selectionRectPoints[2]);
|
||||
collideRectWorld.triangle.emplace_back(selectionRectPoints[0], selectionRectPoints[2], selectionRectPoints[3]);
|
||||
collideRectWorld.recalculate_bounds();
|
||||
|
||||
camSpaceSelection = drawP.world.drawData.cam.c.world_collider_to_coords<SCollision::ColliderCollection<float>>(collideRectWorld);
|
||||
}
|
||||
|
||||
Vector2f DrawingProgramSelection::get_rotation_point_pos_from_angle(double angle) {
|
||||
return Vector2f{rotateData.centerHandlePoint + ROTATION_POINTS_DISTANCE * drawP.world.main.toolbar.final_gui_scale() * Vector2f{std::cos(angle), std::sin(angle)}};
|
||||
}
|
||||
|
||||
void DrawingProgramSelection::draw_components(SkCanvas* canvas, const DrawData& drawData) {
|
||||
if(is_something_selected()) {
|
||||
selectionRectPoints[0] = selectionTransformCoords.from_space_world(initialSelectionAABB.min);
|
||||
selectionRectPoints[1] = selectionTransformCoords.from_space_world(initialSelectionAABB.bottom_left());
|
||||
selectionRectPoints[2] = selectionTransformCoords.from_space_world(initialSelectionAABB.max);
|
||||
selectionRectPoints[3] = selectionTransformCoords.from_space_world(initialSelectionAABB.top_right());
|
||||
|
||||
scaleData.handlePoint = drawP.world.drawData.cam.c.to_space(selectionTransformCoords.from_space_world(initialSelectionAABB.max));
|
||||
rotateData.centerHandlePoint = drawP.world.drawData.cam.c.to_space(selectionTransformCoords.from_space_world(rotateData.centerPos));
|
||||
rotateData.handlePoint = get_rotation_point_pos_from_angle(rotateData.rotationAngle);
|
||||
|
||||
rebuild_cam_space();
|
||||
|
||||
DrawData selectionDrawData = drawData;
|
||||
selectionDrawData.cam.c = selectionTransformCoords.other_coord_space_to_this_space(selectionDrawData.cam.c);
|
||||
selectionDrawData.cam.set_viewing_area(drawP.world.main.window.size.cast<float>());
|
||||
selectionDrawData.refresh_draw_optimizing_values();
|
||||
|
||||
SkImageInfo imgInfo = canvas->imageInfo();
|
||||
sk_sp<SkSurface> surface;
|
||||
#ifdef USE_SKIA_BACKEND_GRAPHITE
|
||||
surface = SkSurfaces::RenderTarget(drawP.world.main.window.recorder(), imgInfo, skgpu::Mipmapped::kNo, drawP.world.main.window.defaultMSAASurfaceProps);
|
||||
#elif USE_SKIA_BACKEND_GANESH
|
||||
surface = SkSurfaces::RenderTarget(drawP.world.main.window.ctx.get(), skgpu::Budgeted::kNo, imgInfo, drawP.world.main.window.defaultMSAASampleCount, &drawP.world.main.window.defaultMSAASurfaceProps);
|
||||
#endif
|
||||
if(!surface)
|
||||
throw std::runtime_error("[DrawingProgramSelection::draw_components] Could not make temporary surface");
|
||||
|
||||
draw_components_recursive(drawP.layerMan.get_layer_root(), surface->getCanvas(), selectionDrawData);
|
||||
|
||||
SkPaint glowBlurP;
|
||||
glowBlurP.setImageFilter(SkImageFilters::Blur(5, 5, nullptr));
|
||||
|
||||
canvas->drawImage(surface->makeTemporaryImage(), 0, 0, SkSamplingOptions{SkFilterMode::kLinear}, &glowBlurP);
|
||||
canvas->drawImage(surface->makeTemporaryImage(), 0, 0, SkSamplingOptions{SkFilterMode::kLinear}, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void DrawingProgramSelection::draw_gui(SkCanvas* canvas, const DrawData& drawData) {
|
||||
if(is_something_selected() && !camSpaceSelection.triangle.empty()) {
|
||||
SkPathBuilder selectionRectPath;
|
||||
selectionRectPath.moveTo(convert_vec2<SkPoint>(camSpaceSelection.triangle[0].p[0]));
|
||||
selectionRectPath.lineTo(convert_vec2<SkPoint>(camSpaceSelection.triangle[0].p[1]));
|
||||
selectionRectPath.lineTo(convert_vec2<SkPoint>(camSpaceSelection.triangle[0].p[2]));
|
||||
selectionRectPath.lineTo(convert_vec2<SkPoint>(camSpaceSelection.triangle[1].p[2]));
|
||||
selectionRectPath.close();
|
||||
SkPaint p{SkColor4f{0.3f, 0.6f, 0.9f, 0.4f}};
|
||||
canvas->drawPath(selectionRectPath.detach(), p);
|
||||
|
||||
if(drawP.is_actual_selection_tool(drawP.drawTool->get_type())) {
|
||||
if(transformOpHappening == TransformOperation::NONE || transformOpHappening == TransformOperation::ROTATE || transformOpHappening == TransformOperation::ROTATE_RELOCATE_CENTER)
|
||||
drawP.draw_drag_circle(canvas, rotateData.centerHandlePoint, {0.9f, 0.5f, 0.1f, 1.0f}, drawData);
|
||||
if(transformOpHappening == TransformOperation::NONE || transformOpHappening == TransformOperation::ROTATE)
|
||||
drawP.draw_drag_circle(canvas, rotateData.handlePoint, {0.9f, 0.5f, 0.1f, 1.0f}, drawData, ROTATION_POINT_RADIUS_MULTIPLIER);
|
||||
if(transformOpHappening == TransformOperation::NONE || transformOpHappening == TransformOperation::SCALE)
|
||||
drawP.draw_drag_circle(canvas, scaleData.handlePoint, {0.1f, 0.9f, 0.9f, 1.0f}, drawData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DrawingProgramSelection::draw_components_recursive(const DrawingProgramLayerListItem& layerItem, SkCanvas* canvas, const DrawData& drawData) {
|
||||
if(layerItem.get_visible()) {
|
||||
SkPaint layerPaint;
|
||||
layerPaint.setAlphaf(layerItem.get_alpha());
|
||||
//layerPaint.setBlendMode(serialized_blend_mode_to_sk_blend_mode(displayData->blendMode)); // For selection, everything should just be in default blend mode (SrcOver)
|
||||
canvas->saveLayer(nullptr, &layerPaint);
|
||||
if(layerItem.is_folder()) {
|
||||
for(auto& p : layerItem.get_folder().folderList->get_data() | std::views::reverse)
|
||||
draw_components_recursive(*p->obj, canvas, drawData);
|
||||
}
|
||||
else {
|
||||
for(auto& c : selectedSet) { // Loop on selected set and not layer component list, since i'm assuming selected set will be small
|
||||
if(c->obj->parentLayer == &layerItem)
|
||||
c->obj->draw(canvas, drawData);
|
||||
}
|
||||
}
|
||||
canvas->restore();
|
||||
}
|
||||
}
|
||||
75
src/DrawingProgram/DrawingProgramSelection.hpp
Normal file
75
src/DrawingProgram/DrawingProgramSelection.hpp
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
#pragma once
|
||||
#include "../CoordSpaceHelperTransform.hpp"
|
||||
#include "Layers/DrawingProgramLayerManager.hpp"
|
||||
#include "DrawingProgramCache.hpp"
|
||||
|
||||
class DrawingProgram;
|
||||
|
||||
class DrawingProgramSelection {
|
||||
public:
|
||||
DrawingProgramSelection(DrawingProgram& initDrawP);
|
||||
void add_from_cam_coord_collider_to_selection(const SCollision::ColliderCollection<float>& cC, DrawingProgramLayerManager::LayerSelector layerSelector, bool frontObjectOnly);
|
||||
void remove_from_cam_coord_collider_to_selection(const SCollision::ColliderCollection<float>& cC, DrawingProgramLayerManager::LayerSelector layerSelector, bool frontObjectOnly);
|
||||
void erase_component(const CanvasComponentContainer::ObjInfoSharedPtr& objToCheck);
|
||||
bool is_something_selected();
|
||||
bool is_selected(const CanvasComponentContainer::ObjInfoSharedPtr& objToCheck);
|
||||
void draw_components(SkCanvas* canvas, const DrawData& drawData);
|
||||
void draw_gui(SkCanvas* canvas, const DrawData& drawData);
|
||||
bool is_being_transformed();
|
||||
void update();
|
||||
void deselect_all();
|
||||
void paste_clipboard(Vector2f pasteScreenPos);
|
||||
const std::unordered_set<CanvasComponentContainer::ObjInfoSharedPtr>& get_selected_set();
|
||||
void delete_all();
|
||||
void selection_to_clipboard();
|
||||
CanvasComponentContainer::ObjInfoSharedPtr get_front_object_colliding_with_in_editing_layer(const SCollision::ColliderCollection<float>& cC);
|
||||
private:
|
||||
void draw_components_recursive(const DrawingProgramLayerListItem& layerItem, SkCanvas* canvas, const DrawData& drawData);
|
||||
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 commit_transform_selection();
|
||||
void rebuild_cam_space();
|
||||
Vector2f get_rotation_point_pos_from_angle(double angle);
|
||||
|
||||
void set_to_selection(const std::unordered_set<CanvasComponentContainer::ObjInfoSharedPtr>& newSelection);
|
||||
void add_to_selection(const std::unordered_set<CanvasComponentContainer::ObjInfoSharedPtr>& newSelection);
|
||||
void calculate_aabb();
|
||||
void reset_all();
|
||||
std::function<bool(const std::shared_ptr<DrawingProgramCacheBVHNode>&)> erase_select_objects_in_bvh_func(std::unordered_set<CanvasComponentContainer::ObjInfoSharedPtr>& selectedComponents, const SCollision::ColliderCollection<float>& cC, const SCollision::ColliderCollection<WorldScalar>& cCWorld, DrawingProgramLayerManager::LayerSelector layerSelector);
|
||||
|
||||
SCollision::ColliderCollection<float> camSpaceSelection;
|
||||
std::array<WorldVec, 4> selectionRectPoints;
|
||||
CoordSpaceHelperTransform selectionTransformCoords;
|
||||
std::unordered_set<CanvasComponentContainer::ObjInfoSharedPtr> selectedSet;
|
||||
SCollision::AABB<WorldScalar> initialSelectionAABB;
|
||||
DrawingProgram& drawP;
|
||||
|
||||
enum class TransformOperation {
|
||||
NONE = 0,
|
||||
TRANSLATE,
|
||||
SCALE,
|
||||
ROTATE_RELOCATE_CENTER,
|
||||
ROTATE
|
||||
} transformOpHappening = TransformOperation::NONE;
|
||||
|
||||
struct TranslationData {
|
||||
WorldVec startPos;
|
||||
} translateData;
|
||||
|
||||
struct ScaleData {
|
||||
WorldVec startPos;
|
||||
WorldVec centerPos;
|
||||
WorldVec currentPos;
|
||||
Vector2f handlePoint;
|
||||
} scaleData;
|
||||
|
||||
struct RotationData {
|
||||
WorldVec centerPos;
|
||||
Vector2f centerHandlePoint;
|
||||
Vector2f handlePoint;
|
||||
double rotationAngle = 0.0;
|
||||
} rotateData;
|
||||
};
|
||||
|
|
@ -18,6 +18,7 @@ void DrawingProgramLayer::set_component_list_callbacks(DrawingProgramLayerListIt
|
|||
layerMan.drawP.updateableComponents.emplace(c);
|
||||
});
|
||||
components->set_erase_callback([&](const CanvasComponentContainer::ObjInfoSharedPtr& c) {
|
||||
layerMan.drawP.selection.erase_component(c);
|
||||
layerMan.drawP.drawCache.erase_component(c);
|
||||
layerMan.drawP.drawTool->erase_component(c);
|
||||
std::erase_if(layerMan.drawP.droppedDownloadingFiles, [&c](auto& downloadingFile) {
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ const std::string& DrawingProgramLayerListItem::get_name() const {
|
|||
void DrawingProgramLayerListItem::set_alpha(DrawingProgramLayerManager& layerMan, float newAlpha) const {
|
||||
if(displayData && displayData->alpha != newAlpha) {
|
||||
displayData->alpha = newAlpha;
|
||||
// MUST CLEAR CACHE
|
||||
layerMan.drawP.drawCache.clear_own_cached_surfaces();
|
||||
layerMan.drawP.world.delayedUpdateObjectManager.send_update_to_all<DisplayData>(displayData, false);
|
||||
}
|
||||
}
|
||||
|
|
@ -105,7 +105,7 @@ float DrawingProgramLayerListItem::get_alpha() const {
|
|||
void DrawingProgramLayerListItem::set_visible(DrawingProgramLayerManager& layerMan, bool newVisible) const {
|
||||
if(displayData && displayData->visible != newVisible) {
|
||||
displayData->visible = newVisible;
|
||||
// MUST CLEAR CACHE
|
||||
layerMan.drawP.drawCache.clear_own_cached_surfaces();
|
||||
layerMan.drawP.world.delayedUpdateObjectManager.send_update_to_all<DisplayData>(displayData, false);
|
||||
}
|
||||
}
|
||||
|
|
@ -117,7 +117,7 @@ bool DrawingProgramLayerListItem::get_visible() const {
|
|||
void DrawingProgramLayerListItem::set_blend_mode(DrawingProgramLayerManager& layerMan, SerializedBlendMode newBlendMode) const {
|
||||
if(displayData && displayData->blendMode != newBlendMode) {
|
||||
displayData->blendMode = newBlendMode;
|
||||
// MUST CLEAR CACHE
|
||||
layerMan.drawP.drawCache.clear_own_cached_surfaces();
|
||||
layerMan.drawP.world.delayedUpdateObjectManager.send_update_to_all<DisplayData>(displayData, false);
|
||||
}
|
||||
}
|
||||
|
|
@ -138,7 +138,7 @@ void DrawingProgramLayerListItem::register_class(World& w) {
|
|||
w.delayedUpdateObjectManager.register_class<NameData>(w.netObjMan);
|
||||
w.delayedUpdateObjectManager.register_class<DisplayData>(w.netObjMan, NetworkingObjects::DelayUpdateSerializedClassManager::CustomConstructors<DisplayData>{
|
||||
.postUpdateFunc = [&](DisplayData& o) {
|
||||
// MUST CLEAR CACHE
|
||||
w.drawProg.drawCache.clear_own_cached_surfaces();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -63,8 +63,8 @@ void EditTool::switch_tool(DrawingProgramToolType newTool) {
|
|||
pointDragging = nullptr;
|
||||
isEditing = false;
|
||||
|
||||
//if(!drawP.is_selection_allowing_tool(newTool))
|
||||
// drawP.selection.deselect_all();
|
||||
if(!drawP.is_selection_allowing_tool(newTool))
|
||||
drawP.selection.deselect_all();
|
||||
}
|
||||
|
||||
void EditTool::edit_start(const CanvasComponentContainer::ObjInfoSharedPtr& comp) {
|
||||
|
|
@ -114,26 +114,26 @@ void EditTool::tool_update() {
|
|||
camCMouseAABB.recalculate_bounds();
|
||||
|
||||
if(drawP.controls.leftClick) {
|
||||
//bool modifySelection = !drawP.selection.is_being_transformed();
|
||||
//if(drawP.world.main.input.mouse.leftClicks >= 2 && !drawP.world.main.input.key(InputManager::KEY_GENERIC_LSHIFT).held && !drawP.world.main.input.key(InputManager::KEY_GENERIC_LALT).held) {
|
||||
// CanvasComponentContainer::ObjInfoSharedPtr selectedObjectToEdit = drawP.selection.get_front_object_colliding_with(camCMouseAABB);
|
||||
bool modifySelection = !drawP.selection.is_being_transformed();
|
||||
if(drawP.world.main.input.mouse.leftClicks >= 2 && !drawP.world.main.input.key(InputManager::KEY_GENERIC_LSHIFT).held && !drawP.world.main.input.key(InputManager::KEY_GENERIC_LALT).held) {
|
||||
CanvasComponentContainer::ObjInfoSharedPtr selectedObjectToEdit = drawP.selection.get_front_object_colliding_with_in_editing_layer(camCMouseAABB);
|
||||
|
||||
// if(selectedObjectToEdit && is_editable(selectedObjectToEdit)) {
|
||||
// drawP.selection.deselect_all();
|
||||
// edit_start(selectedObjectToEdit);
|
||||
// modifySelection = false;
|
||||
// }
|
||||
//}
|
||||
//if(modifySelection) {
|
||||
// if(drawP.world.main.input.key(InputManager::KEY_GENERIC_LSHIFT).held)
|
||||
// drawP.selection.add_from_cam_coord_collider_to_selection(camCMouseAABB, true);
|
||||
// else if(drawP.world.main.input.key(InputManager::KEY_GENERIC_LALT).held)
|
||||
// drawP.selection.remove_from_cam_coord_collider_to_selection(camCMouseAABB, true);
|
||||
// else {
|
||||
// drawP.selection.deselect_all();
|
||||
// drawP.selection.add_from_cam_coord_collider_to_selection(camCMouseAABB, true);
|
||||
// }
|
||||
//}
|
||||
if(selectedObjectToEdit && is_editable(selectedObjectToEdit)) {
|
||||
drawP.selection.deselect_all();
|
||||
edit_start(selectedObjectToEdit);
|
||||
modifySelection = false;
|
||||
}
|
||||
}
|
||||
if(modifySelection) {
|
||||
if(drawP.world.main.input.key(InputManager::KEY_GENERIC_LSHIFT).held)
|
||||
drawP.selection.add_from_cam_coord_collider_to_selection(camCMouseAABB, DrawingProgramLayerManager::LayerSelector::LAYER_BEING_EDITED, true);
|
||||
else if(drawP.world.main.input.key(InputManager::KEY_GENERIC_LALT).held)
|
||||
drawP.selection.remove_from_cam_coord_collider_to_selection(camCMouseAABB, DrawingProgramLayerManager::LayerSelector::LAYER_BEING_EDITED, true);
|
||||
else {
|
||||
drawP.selection.deselect_all();
|
||||
drawP.selection.add_from_cam_coord_collider_to_selection(camCMouseAABB, DrawingProgramLayerManager::LayerSelector::LAYER_BEING_EDITED, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
|
|
|||
|
|
@ -49,17 +49,26 @@ void EraserTool::tool_update() {
|
|||
SCollision::generate_wide_line(cC, prevMousePos, drawP.world.main.input.mouse.pos, drawP.controls.relativeWidth * 2.0f, true);
|
||||
auto cCWorld = drawP.world.drawData.cam.c.collider_to_world<SCollision::ColliderCollection<WorldScalar>, SCollision::ColliderCollection<float>>(cC);
|
||||
|
||||
drawP.drawCache.traverse_bvh_erase_function(cCWorld.bounds, [&](const auto& bvhNode, auto& comps) {
|
||||
drawP.drawCache.traverse_bvh_run_function(cCWorld.bounds, [&](const auto& bvhNode) {
|
||||
if(bvhNode &&
|
||||
SCollision::collide(cC, drawP.world.drawData.cam.c.to_space(bvhNode->bounds.min)) &&
|
||||
SCollision::collide(cC, drawP.world.drawData.cam.c.to_space(bvhNode->bounds.max)) &&
|
||||
SCollision::collide(cC, drawP.world.drawData.cam.c.to_space(bvhNode->bounds.top_right())) &&
|
||||
SCollision::collide(cC, drawP.world.drawData.cam.c.to_space(bvhNode->bounds.bottom_left()))) {
|
||||
drawP.drawCache.invalidate_cache_at_aabb(bvhNode->bounds);
|
||||
drawP.drawCache.move_components_from_bvh_node_to_set(erasedComponents, bvhNode);
|
||||
return true;
|
||||
drawP.drawCache.traverse_bvh_run_function_starting_at_node_no_collision_check(bvhNode, [&](const auto& bvhNodeChild) {
|
||||
drawP.drawCache.node_loop_erase_if_components(bvhNodeChild, [&](auto& c) {
|
||||
if(drawP.layerMan.component_passes_layer_selector(c, drawP.controls.layerSelector)) {
|
||||
erasedComponents.emplace(c);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
return true;
|
||||
});
|
||||
return false;
|
||||
}
|
||||
std::erase_if(comps, [&](auto& c) {
|
||||
drawP.drawCache.node_loop_erase_if_components(bvhNode, [&](auto& c) {
|
||||
if(drawP.layerMan.component_passes_layer_selector(c, drawP.controls.layerSelector) && c->obj->collides_with(drawP.world.drawData.cam.c, cCWorld, cC)) {
|
||||
erasedComponents.emplace(c);
|
||||
drawP.drawCache.invalidate_cache_at_aabb(c->obj->get_world_bounds());
|
||||
|
|
@ -67,7 +76,7 @@ void EraserTool::tool_update() {
|
|||
}
|
||||
return false;
|
||||
});
|
||||
return false;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
else
|
||||
|
|
|
|||
|
|
@ -39,7 +39,15 @@ DrawingProgramToolType LassoSelectTool::get_type() {
|
|||
}
|
||||
|
||||
void LassoSelectTool::gui_toolbox() {
|
||||
drawP.world.main.toolbar.gui.text_label_centered("Lasso Select");
|
||||
auto& t = drawP.world.main.toolbar;
|
||||
t.gui.push_id("lasso select tool");
|
||||
t.gui.text_label_centered("Lasso Select");
|
||||
t.gui.text_label("Select from:");
|
||||
if(t.gui.radio_button_field("layer edited", "Layer being edited", drawP.controls.layerSelector == DrawingProgramLayerManager::LayerSelector::LAYER_BEING_EDITED))
|
||||
drawP.controls.layerSelector = DrawingProgramLayerManager::LayerSelector::LAYER_BEING_EDITED;
|
||||
if(t.gui.radio_button_field("all visible", "All visible layers", drawP.controls.layerSelector == DrawingProgramLayerManager::LayerSelector::ALL_VISIBLE_LAYERS))
|
||||
drawP.controls.layerSelector = DrawingProgramLayerManager::LayerSelector::ALL_VISIBLE_LAYERS;
|
||||
t.gui.pop_id();
|
||||
}
|
||||
|
||||
bool LassoSelectTool::right_click_popup_gui(Vector2f popupPos) {
|
||||
|
|
@ -50,19 +58,19 @@ void LassoSelectTool::erase_component(const CanvasComponentContainer::ObjInfoSha
|
|||
}
|
||||
|
||||
void LassoSelectTool::switch_tool(DrawingProgramToolType newTool) {
|
||||
//if(!drawP.is_selection_allowing_tool(newTool))
|
||||
// drawP.selection.deselect_all();
|
||||
if(!drawP.is_selection_allowing_tool(newTool))
|
||||
drawP.selection.deselect_all();
|
||||
}
|
||||
|
||||
void LassoSelectTool::tool_update() {
|
||||
switch(controls.selectionMode) {
|
||||
case 0: {
|
||||
//if(drawP.controls.leftClick && !drawP.selection.is_being_transformed()) {
|
||||
// controls = LassoSelectControls();
|
||||
// controls.coords = drawP.world.drawData.cam.c;
|
||||
// controls.lassoPoints.emplace_back(controls.coords.get_mouse_pos(drawP.world));
|
||||
// controls.selectionMode = 1;
|
||||
//}
|
||||
if(drawP.controls.leftClick && !drawP.selection.is_being_transformed()) {
|
||||
controls = LassoSelectControls();
|
||||
controls.coords = drawP.world.drawData.cam.c;
|
||||
controls.lassoPoints.emplace_back(controls.coords.get_mouse_pos(drawP.world));
|
||||
controls.selectionMode = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
|
|
@ -92,17 +100,17 @@ void LassoSelectTool::tool_update() {
|
|||
|
||||
cC.recalculate_bounds();
|
||||
|
||||
//if(drawP.world.main.input.key(InputManager::KEY_GENERIC_LSHIFT).held)
|
||||
// drawP.selection.add_from_cam_coord_collider_to_selection(cC);
|
||||
//else if(drawP.world.main.input.key(InputManager::KEY_GENERIC_LALT).held)
|
||||
// drawP.selection.remove_from_cam_coord_collider_to_selection(cC);
|
||||
//else {
|
||||
// drawP.selection.deselect_all();
|
||||
// drawP.selection.add_from_cam_coord_collider_to_selection(cC);
|
||||
//}
|
||||
if(drawP.world.main.input.key(InputManager::KEY_GENERIC_LSHIFT).held)
|
||||
drawP.selection.add_from_cam_coord_collider_to_selection(cC, drawP.controls.layerSelector, false);
|
||||
else if(drawP.world.main.input.key(InputManager::KEY_GENERIC_LALT).held)
|
||||
drawP.selection.remove_from_cam_coord_collider_to_selection(cC, drawP.controls.layerSelector, false);
|
||||
else {
|
||||
drawP.selection.deselect_all();
|
||||
drawP.selection.add_from_cam_coord_collider_to_selection(cC, drawP.controls.layerSelector, false);
|
||||
}
|
||||
}
|
||||
else if(!drawP.world.main.input.key(InputManager::KEY_GENERIC_LSHIFT).held && !drawP.world.main.input.key(InputManager::KEY_GENERIC_LALT).held) {
|
||||
//drawP.selection.deselect_all();
|
||||
drawP.selection.deselect_all();
|
||||
}
|
||||
controls.selectionMode = 0;
|
||||
}
|
||||
|
|
@ -112,7 +120,7 @@ void LassoSelectTool::tool_update() {
|
|||
}
|
||||
|
||||
bool LassoSelectTool::prevent_undo_or_redo() {
|
||||
return true;//drawP.selection.is_something_selected() || controls.selectionMode == 1;
|
||||
return drawP.selection.is_something_selected() || controls.selectionMode == 1;
|
||||
}
|
||||
|
||||
void LassoSelectTool::draw(SkCanvas* canvas, const DrawData& drawData) {
|
||||
|
|
|
|||
|
|
@ -17,7 +17,15 @@ DrawingProgramToolType RectSelectTool::get_type() {
|
|||
}
|
||||
|
||||
void RectSelectTool::gui_toolbox() {
|
||||
drawP.world.main.toolbar.gui.text_label_centered("Rectangle Select");
|
||||
auto& t = drawP.world.main.toolbar;
|
||||
t.gui.push_id("rectangle select tool");
|
||||
t.gui.text_label_centered("Rectangle Select");
|
||||
t.gui.text_label("Select from:");
|
||||
if(t.gui.radio_button_field("layer edited", "Layer being edited", drawP.controls.layerSelector == DrawingProgramLayerManager::LayerSelector::LAYER_BEING_EDITED))
|
||||
drawP.controls.layerSelector = DrawingProgramLayerManager::LayerSelector::LAYER_BEING_EDITED;
|
||||
if(t.gui.radio_button_field("all visible", "All visible layers", drawP.controls.layerSelector == DrawingProgramLayerManager::LayerSelector::ALL_VISIBLE_LAYERS))
|
||||
drawP.controls.layerSelector = DrawingProgramLayerManager::LayerSelector::ALL_VISIBLE_LAYERS;
|
||||
t.gui.pop_id();
|
||||
}
|
||||
|
||||
void RectSelectTool::erase_component(const CanvasComponentContainer::ObjInfoSharedPtr& erasedComp) {
|
||||
|
|
@ -28,19 +36,19 @@ bool RectSelectTool::right_click_popup_gui(Vector2f popupPos) {
|
|||
}
|
||||
|
||||
void RectSelectTool::switch_tool(DrawingProgramToolType newTool) {
|
||||
//if(!drawP.is_selection_allowing_tool(newTool))
|
||||
// drawP.selection.deselect_all();
|
||||
if(!drawP.is_selection_allowing_tool(newTool))
|
||||
drawP.selection.deselect_all();
|
||||
}
|
||||
|
||||
void RectSelectTool::tool_update() {
|
||||
switch(controls.selectionMode) {
|
||||
case 0: {
|
||||
//if(drawP.controls.leftClick && !drawP.selection.is_being_transformed()) {
|
||||
// controls = RectSelectControls();
|
||||
// controls.coords = drawP.world.drawData.cam.c;
|
||||
// controls.selectStartAt = controls.coords.get_mouse_pos(drawP.world);
|
||||
// controls.selectionMode = 1;
|
||||
//}
|
||||
if(drawP.controls.leftClick && !drawP.selection.is_being_transformed()) {
|
||||
controls = RectSelectControls();
|
||||
controls.coords = drawP.world.drawData.cam.c;
|
||||
controls.selectStartAt = controls.coords.get_mouse_pos(drawP.world);
|
||||
controls.selectionMode = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
|
|
@ -55,14 +63,14 @@ void RectSelectTool::tool_update() {
|
|||
cC.triangle.emplace_back(controls.newT[2], controls.newT[3], controls.newT[0]);
|
||||
cC.recalculate_bounds();
|
||||
|
||||
//if(drawP.world.main.input.key(InputManager::KEY_GENERIC_LSHIFT).held)
|
||||
// drawP.selection.add_from_cam_coord_collider_to_selection(cC);
|
||||
//else if(drawP.world.main.input.key(InputManager::KEY_GENERIC_LALT).held)
|
||||
// drawP.selection.remove_from_cam_coord_collider_to_selection(cC);
|
||||
//else {
|
||||
// drawP.selection.deselect_all();
|
||||
// drawP.selection.add_from_cam_coord_collider_to_selection(cC);
|
||||
//}
|
||||
if(drawP.world.main.input.key(InputManager::KEY_GENERIC_LSHIFT).held)
|
||||
drawP.selection.add_from_cam_coord_collider_to_selection(cC, drawP.controls.layerSelector, false);
|
||||
else if(drawP.world.main.input.key(InputManager::KEY_GENERIC_LALT).held)
|
||||
drawP.selection.remove_from_cam_coord_collider_to_selection(cC, drawP.controls.layerSelector, false);
|
||||
else {
|
||||
drawP.selection.deselect_all();
|
||||
drawP.selection.add_from_cam_coord_collider_to_selection(cC, drawP.controls.layerSelector, false);
|
||||
}
|
||||
|
||||
controls.selectionMode = 0;
|
||||
}
|
||||
|
|
@ -72,8 +80,7 @@ void RectSelectTool::tool_update() {
|
|||
}
|
||||
|
||||
bool RectSelectTool::prevent_undo_or_redo() {
|
||||
//return drawP.selection.is_something_selected() || controls.selectionMode == 1;
|
||||
return true;
|
||||
return drawP.selection.is_something_selected() || controls.selectionMode == 1;
|
||||
}
|
||||
|
||||
void RectSelectTool::draw(SkCanvas* canvas, const DrawData& drawData) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue