Fixed selected object ordering

This commit is contained in:
Yousef Khadadeh 2025-12-31 10:06:26 +03:00
parent 9d752af00c
commit b688c39e68
6 changed files with 52 additions and 68 deletions

View file

@ -348,9 +348,8 @@ void DrawingProgram::rebuild_cache() {
EraserTool* eraserTool = static_cast<EraserTool*>(drawTool.get());
drawCache.build(eraserTool->erasedComponents);
}
else if(is_selection_allowing_tool(drawTool->get_type())) {
drawCache.build(selection.get_selected_set());
}
else if(is_selection_allowing_tool(drawTool->get_type()))
drawCache.build(selection.get_selection_as_set());
else
drawCache.build({});
}

View file

@ -23,11 +23,11 @@ DrawingProgramSelection::DrawingProgramSelection(DrawingProgram& initDrawP):
{}
void DrawingProgramSelection::add_from_cam_coord_collider_to_selection(const SCollision::ColliderCollection<float>& cC, DrawingProgramLayerManager::LayerSelector layerSelector, bool frontObjectOnly) {
std::unordered_set<CanvasComponentContainer::ObjInfo*> selectedComponents;
std::vector<CanvasComponentContainer::ObjInfo*> selectedComponents;
if(frontObjectOnly) {
CanvasComponentContainer::ObjInfo* a = drawP.drawCache.get_front_object_colliding_with_in_editing_layer(cC);
if(a) {
selectedComponents.emplace(a);
selectedComponents.emplace_back(a);
drawP.drawCache.erase_component(a);
}
}
@ -43,7 +43,7 @@ void DrawingProgramSelection::remove_from_cam_coord_collider_to_selection(const
CanvasComponentContainer::ObjInfo* p = get_front_object_colliding_with_in_editing_layer(cC);
if(p) {
drawP.drawCache.add_component(p);
selectedSet.erase(p);
std::erase(selectedSet, p);
}
}
else {
@ -60,7 +60,7 @@ void DrawingProgramSelection::remove_from_cam_coord_collider_to_selection(const
calculate_aabb();
}
std::function<bool(const std::shared_ptr<DrawingProgramCacheBVHNode>&)> DrawingProgramSelection::erase_select_objects_in_bvh_func(std::unordered_set<CanvasComponentContainer::ObjInfo*>& selectedComponents, const SCollision::ColliderCollection<float>& cC, const SCollision::ColliderCollection<WorldScalar>& cCWorld, DrawingProgramLayerManager::LayerSelector layerSelector) {
std::function<bool(const std::shared_ptr<DrawingProgramCacheBVHNode>&)> DrawingProgramSelection::erase_select_objects_in_bvh_func(std::vector<CanvasComponentContainer::ObjInfo*>& 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)) &&
@ -71,7 +71,7 @@ std::function<bool(const std::shared_ptr<DrawingProgramCacheBVHNode>&)> DrawingP
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);
selectedComponents.emplace_back(c);
return true;
}
return false;
@ -82,7 +82,7 @@ std::function<bool(const std::shared_ptr<DrawingProgramCacheBVHNode>&)> DrawingP
}
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);
selectedComponents.emplace_back(c);
drawP.drawCache.invalidate_cache_at_aabb(c->obj->get_world_bounds());
return true;
}
@ -94,16 +94,28 @@ std::function<bool(const std::shared_ptr<DrawingProgramCacheBVHNode>&)> DrawingP
return toRet;
}
void DrawingProgramSelection::add_to_selection(const std::unordered_set<CanvasComponentContainer::ObjInfo*>& newSelection) {
selectedSet.insert(newSelection.begin(), newSelection.end());
void DrawingProgramSelection::add_to_selection(const std::vector<CanvasComponentContainer::ObjInfo*>& newSelection) {
selectedSet.insert(selectedSet.end(), newSelection.begin(), newSelection.end());
sort_selection();
calculate_aabb();
}
void DrawingProgramSelection::set_to_selection(const std::unordered_set<CanvasComponentContainer::ObjInfo*>& newSelection) {
void DrawingProgramSelection::set_to_selection(const std::vector<CanvasComponentContainer::ObjInfo*>& newSelection) {
selectedSet = newSelection;
sort_selection();
calculate_aabb();
}
void DrawingProgramSelection::sort_selection() {
std::vector<DrawingProgramLayerListItem*> flattenedLayerList = drawP.layerMan.get_flattened_layer_list();
std::unordered_map<DrawingProgramLayerListItem*, size_t> flattenedLayerListOrder;
for(size_t i = 0; i < flattenedLayerList.size(); i++)
flattenedLayerListOrder[flattenedLayerList[i]] = i;
std::sort(selectedSet.begin(), selectedSet.end(), [&](auto& a, auto& b) {
return (flattenedLayerListOrder[a->obj->parentLayer] < flattenedLayerListOrder[b->obj->parentLayer]) || (a->obj->parentLayer == b->obj->parentLayer && a->pos < b->pos);
});
}
void DrawingProgramSelection::calculate_aabb() {
if(is_something_selected()) {
initialSelectionAABB = (*selectedSet.begin())->obj->get_world_bounds();
@ -118,7 +130,7 @@ bool DrawingProgramSelection::is_something_selected() {
}
bool DrawingProgramSelection::is_selected(CanvasComponentContainer::ObjInfo* objToCheck) {
return selectedSet.contains(objToCheck);
return std::find(selectedSet.begin(), selectedSet.end(), objToCheck) != selectedSet.end();
}
void DrawingProgramSelection::reset_all() {
@ -292,13 +304,13 @@ 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);
drawP.layerMan.erase_component_container(selectedSetTemp);
}
}
void DrawingProgramSelection::erase_component(CanvasComponentContainer::ObjInfo* objToCheck) {
if(is_selected(objToCheck)) {
selectedSet.erase(objToCheck);
std::erase(selectedSet, objToCheck);
if(selectedSet.empty())
reset_all();
}
@ -319,16 +331,8 @@ void DrawingProgramSelection::selection_to_clipboard() {
std::unordered_set<NetworkingObjects::NetObjID> resourceSet;
for(auto& c : selectedSet)
c->obj->get_comp().get_used_resources(resourceSet);
std::vector<CanvasComponentContainer::ObjInfo*> compVecSort(selectedSet.begin(), selectedSet.end());
std::vector<DrawingProgramLayerListItem*> flattenedLayerList = drawP.layerMan.get_flattened_layer_list();
std::unordered_map<DrawingProgramLayerListItem*, size_t> flattenedLayerListOrder;
for(size_t i = 0; i < flattenedLayerList.size(); i++)
flattenedLayerListOrder[flattenedLayerList[i]] = i;
std::sort(compVecSort.begin(), compVecSort.end(), [&](auto& a, auto& b) {
return (flattenedLayerListOrder[a->obj->parentLayer] < flattenedLayerListOrder[b->obj->parentLayer]) || (a->obj->parentLayer == b->obj->parentLayer && a->pos < b->pos);
});
clipboard.components.clear();
for(auto& c : compVecSort)
for(auto& c : selectedSet)
clipboard.components.emplace_back(c->obj->get_data_copy());
clipboard.pos = initialSelectionAABB.center();
clipboard.inverseScale = drawP.world.drawData.cam.c.inverseScale;
@ -365,9 +369,11 @@ void DrawingProgramSelection::paste_clipboard(Vector2f pasteScreenPos) {
placedComponents.emplace_back(drawP.layerMan.get_edited_layer_end_iterator(), newComponentContainer);
}
auto newlyInsertedObjectIts = drawP.layerMan.add_many_components_to_layer_being_edited(placedComponents);
std::unordered_set<CanvasComponentContainer::ObjInfo*> compSetInserted;
for(auto& it : newlyInsertedObjectIts)
compSetInserted.emplace(&(*it));
std::vector<CanvasComponentContainer::ObjInfo*> compSetInserted;
for(auto& it : newlyInsertedObjectIts) {
drawP.drawCache.erase_component(&(*it));
compSetInserted.emplace_back(&(*it));
}
set_to_selection(compSetInserted);
//drawP.add_undo_place_components(compSetInserted);
}
@ -377,8 +383,8 @@ bool DrawingProgramSelection::is_being_transformed() {
return transformOpHappening != TransformOperation::NONE;
}
const std::unordered_set<CanvasComponentContainer::ObjInfo*>& DrawingProgramSelection::get_selected_set() {
return selectedSet;
std::unordered_set<CanvasComponentContainer::ObjInfo*> DrawingProgramSelection::get_selection_as_set() {
return std::unordered_set<CanvasComponentContainer::ObjInfo*>(selectedSet.begin(), selectedSet.end());
}
void DrawingProgramSelection::rebuild_cam_space() {
@ -422,7 +428,8 @@ void DrawingProgramSelection::draw_components(SkCanvas* canvas, const DrawData&
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);
for(auto& c : selectedSet)
c->obj->draw(canvas, selectionDrawData);
SkPaint glowBlurP;
glowBlurP.setImageFilter(SkImageFilters::Blur(5, 5, nullptr));
@ -453,23 +460,3 @@ void DrawingProgramSelection::draw_gui(SkCanvas* canvas, const DrawData& drawDat
}
}
}
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 | 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();
}
}

View file

@ -19,12 +19,11 @@ class DrawingProgramSelection {
void update();
void deselect_all();
void paste_clipboard(Vector2f pasteScreenPos);
const std::unordered_set<CanvasComponentContainer::ObjInfo*>& get_selected_set();
std::unordered_set<CanvasComponentContainer::ObjInfo*> get_selection_as_set();
void delete_all();
void selection_to_clipboard();
CanvasComponentContainer::ObjInfo* 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();
@ -34,16 +33,17 @@ class DrawingProgramSelection {
void rebuild_cam_space();
Vector2f get_rotation_point_pos_from_angle(double angle);
void set_to_selection(const std::unordered_set<CanvasComponentContainer::ObjInfo*>& newSelection);
void add_to_selection(const std::unordered_set<CanvasComponentContainer::ObjInfo*>& newSelection);
void set_to_selection(const std::vector<CanvasComponentContainer::ObjInfo*>& newSelection);
void add_to_selection(const std::vector<CanvasComponentContainer::ObjInfo*>& newSelection);
void sort_selection();
void calculate_aabb();
void reset_all();
std::function<bool(const std::shared_ptr<DrawingProgramCacheBVHNode>&)> erase_select_objects_in_bvh_func(std::unordered_set<CanvasComponentContainer::ObjInfo*>& selectedComponents, const SCollision::ColliderCollection<float>& cC, const SCollision::ColliderCollection<WorldScalar>& cCWorld, DrawingProgramLayerManager::LayerSelector layerSelector);
std::function<bool(const std::shared_ptr<DrawingProgramCacheBVHNode>&)> erase_select_objects_in_bvh_func(std::vector<CanvasComponentContainer::ObjInfo*>& 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::ObjInfo*> selectedSet;
std::vector<CanvasComponentContainer::ObjInfo*> selectedSet;
SCollision::AABB<WorldScalar> initialSelectionAABB;
DrawingProgram& drawP;

View file

@ -62,16 +62,6 @@ const DrawingProgramLayerListItem& DrawingProgramLayerManager::get_layer_root()
return *layerTreeRoot;
}
void DrawingProgramLayerManager::erase_component_set(const std::unordered_set<CanvasComponentContainer::ObjInfo*>& compsToErase) {
std::unordered_map<DrawingProgramLayerListItem*, std::vector<CanvasComponentContainer::ObjInfoIterator>> idsToEraseInSpecificLayers;
for(auto& c : compsToErase)
idsToEraseInSpecificLayers[c->obj->parentLayer].emplace_back(c->obj->objInfo);
for(auto& [layerListItem, netObjSetToErase] : idsToEraseInSpecificLayers) {
auto& layerComponentList = layerListItem->get_layer().components;
layerComponentList->erase_list(layerComponentList, netObjSetToErase);
}
}
bool DrawingProgramLayerManager::component_passes_layer_selector(CanvasComponentContainer::ObjInfo* c, LayerSelector layerSelector) {
switch(layerSelector) {
case LayerSelector::ALL_VISIBLE_LAYERS:

View file

@ -24,7 +24,15 @@ class DrawingProgramLayerManager {
void write_components_server(cereal::PortableBinaryOutputArchive& a);
void read_components_client(cereal::PortableBinaryInputArchive& a);
bool is_a_layer_being_edited();
void erase_component_set(const std::unordered_set<CanvasComponentContainer::ObjInfo*>& compsToErase);
template <typename List> void erase_component_container(const List& compsToErase) {
std::unordered_map<DrawingProgramLayerListItem*, std::vector<CanvasComponentContainer::ObjInfoIterator>> idsToEraseInSpecificLayers;
for(auto& c : compsToErase)
idsToEraseInSpecificLayers[c->obj->parentLayer].emplace_back(c->obj->objInfo);
for(auto& [layerListItem, netObjSetToErase] : idsToEraseInSpecificLayers) {
auto& layerComponentList = layerListItem->get_layer().components;
layerComponentList->erase_list(layerComponentList, netObjSetToErase);
}
}
uint32_t edited_layer_component_count();
CanvasComponentContainer::ObjInfoIterator get_edited_layer_end_iterator();
bool component_passes_layer_selector(CanvasComponentContainer::ObjInfo* c, LayerSelector layerSelector);

View file

@ -36,7 +36,7 @@ void EraserTool::erase_component(CanvasComponentContainer::ObjInfo* erasedComp)
}
void EraserTool::switch_tool(DrawingProgramToolType newTool) {
drawP.layerMan.erase_component_set(erasedComponents);
drawP.layerMan.erase_component_container(erasedComponents);
}
void EraserTool::tool_update() {