update
This commit is contained in:
@@ -5705,14 +5705,9 @@ void MapView::ShowContextMenu(QPoint pos)
|
||||
if (!last_entry.value().index() == eEntry_Object)
|
||||
return;
|
||||
|
||||
// Only works with m2 doodads
|
||||
auto obj = std::get<selected_object_type>(last_entry.value());
|
||||
auto model_name = obj->instance_model()->file_key().filepath();
|
||||
// auto models = _world->get_models_by_filename()[model_name];
|
||||
// std::vector< uint32_t> objects_to_select;
|
||||
|
||||
//makeCurrent();
|
||||
//OpenGL::context::scoped_setter const _(::gl, context());
|
||||
|
||||
_world->reset_selection();
|
||||
|
||||
@@ -5754,21 +5749,12 @@ void MapView::ShowContextMenu(QPoint pos)
|
||||
{
|
||||
if (_world->has_selection())
|
||||
{
|
||||
for (auto& selection : _world->current_selection())
|
||||
for (auto& obj : _world->get_selected_objects())
|
||||
{
|
||||
if (selection.index() != eEntry_Object)
|
||||
continue;
|
||||
|
||||
auto obj = std::get<selected_object_type>(selection);
|
||||
|
||||
if (obj->which() == eMODEL)
|
||||
{
|
||||
static_cast<ModelInstance*>(obj)->model->hide();
|
||||
}
|
||||
else if (obj->which() == eWMO)
|
||||
{
|
||||
static_cast<WMOInstance*>(obj)->wmo->hide();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -5783,8 +5769,6 @@ void MapView::ShowContextMenu(QPoint pos)
|
||||
action_palette_add.setEnabled(_world->get_selected_model_count() == 1);
|
||||
QObject::connect(&action_palette_add, &QAction::triggered, [=]()
|
||||
{
|
||||
|
||||
|
||||
auto last_entry = _world->get_last_selected_model();
|
||||
if (last_entry)
|
||||
{
|
||||
@@ -5823,13 +5807,8 @@ void MapView::ShowContextMenu(QPoint pos)
|
||||
auto replace_path = replace_obj->instance_model()->file_key();
|
||||
|
||||
// iterate selection (objects to replace)
|
||||
for (auto& entry : _world->current_selection())
|
||||
for (auto& source_obj : _world->get_selected_objects())
|
||||
{
|
||||
if (entry.index() == eEntry_Object)
|
||||
{
|
||||
auto source_obj = std::get<selected_object_type>(entry);
|
||||
|
||||
//SceneObject* source_scene_obj = source_obj;
|
||||
|
||||
math::degrees::vec3 source_rot(math::degrees(0)._, math::degrees(0)._, math::degrees(0)._);
|
||||
source_rot = source_obj->dir;
|
||||
@@ -5882,8 +5861,6 @@ void MapView::ShowContextMenu(QPoint pos)
|
||||
new_obj->model->waitForChildrenLoaded();
|
||||
new_obj->recalcExtents();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
// can cause the usual crash of deleting models overlapping unloaded tiles.
|
||||
DeleteSelectedObjects();
|
||||
@@ -5908,13 +5885,26 @@ void MapView::ShowContextMenu(QPoint pos)
|
||||
|
||||
menu->addSeparator();
|
||||
// TODO
|
||||
QAction action_6("Group Selected Objects TODO", this);
|
||||
menu->addAction(&action_6);
|
||||
action_6.setEnabled(_world->has_multiple_model_selected() && false); // TODO, some "notgrouped" condition
|
||||
QAction action_group("Group Selected Objects TODO", this);
|
||||
menu->addAction(&action_group);
|
||||
action_group.setEnabled(_world->has_multiple_model_selected() && true); // TODO, some "notgrouped" condition
|
||||
QObject::connect(&action_snap, &QAction::triggered, [=]()
|
||||
{
|
||||
_world->add_object_group();
|
||||
|
||||
//auto selected_objects = _world->get_selected_objects();
|
||||
//for (auto selected_obj : selected_objects)
|
||||
//{
|
||||
//
|
||||
//}
|
||||
|
||||
});
|
||||
|
||||
|
||||
QAction action_ungroup("Ungroup Selected Objects TODO", this);
|
||||
|
||||
|
||||
QAction action_7("Ungroup Selected Objects TODO", this);
|
||||
|
||||
menu->addSeparator();
|
||||
|
||||
menu->exec(mapToGlobal(pos)); // synch
|
||||
// menu->popup(mapToGlobal(pos)); // asynch
|
||||
|
||||
@@ -75,3 +75,117 @@ void selected_chunk_type::updateDetails(Noggit::Ui::detail_infos* detail_widget)
|
||||
|
||||
detail_widget->setText(select_info.str());
|
||||
}
|
||||
|
||||
selection_group::selection_group(std::vector<selected_object_type> selected_objects, World* world)
|
||||
: _world(world)
|
||||
{
|
||||
_object_count = selected_objects.size();
|
||||
|
||||
if (!_object_count)
|
||||
return;
|
||||
|
||||
// default group extents to first obj
|
||||
_group_extents = selected_objects.front()->getExtents();
|
||||
|
||||
_members_uid.reserve(selected_objects.size());
|
||||
for (auto& selected_obj : selected_objects)
|
||||
{
|
||||
_members_uid.push_back(selected_obj->uid);
|
||||
|
||||
if (selected_obj->getExtents()[0].x < _group_extents[0].x)
|
||||
_group_extents[0].x = selected_obj->extents[0].x;
|
||||
if (selected_obj->getExtents()[0].y < _group_extents[0].y)
|
||||
_group_extents[0].y = selected_obj->extents[0].y;
|
||||
if (selected_obj->getExtents()[0].z < _group_extents[0].z)
|
||||
_group_extents[0].z = selected_obj->extents[0].z;
|
||||
|
||||
if (selected_obj->getExtents()[1].x > _group_extents[1].x)
|
||||
_group_extents[1].x = selected_obj->extents[1].x;
|
||||
if (selected_obj->getExtents()[1].y > _group_extents[1].y)
|
||||
_group_extents[1].y = selected_obj->extents[1].y;
|
||||
if (selected_obj->getExtents()[1].z > _group_extents[1].z)
|
||||
_group_extents[1].z = selected_obj->extents[1].z;
|
||||
}
|
||||
}
|
||||
|
||||
bool selection_group::group_contains_object(selected_object_type object)
|
||||
{
|
||||
for (unsigned int member_uid : _members_uid)
|
||||
{
|
||||
if (object->uid == member_uid)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void selection_group::select_group()
|
||||
{
|
||||
for (unsigned int obj_uid : _members_uid)
|
||||
{
|
||||
std::optional<selection_type> obj = _world->get_model(obj_uid);
|
||||
if (!obj)
|
||||
continue;
|
||||
|
||||
SceneObject* instance = std::get<SceneObject*>(obj.value());
|
||||
|
||||
if (_world->is_selected(instance))
|
||||
continue;
|
||||
|
||||
_world->add_to_selection(obj.value(), true);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void selection_group::unselect_group()
|
||||
{
|
||||
for (unsigned int obj_uid : _members_uid)
|
||||
{
|
||||
// don't need to check if it's not selected
|
||||
_world->remove_from_selection(obj_uid);
|
||||
|
||||
/*
|
||||
std::optional<selection_type> obj = _world->get_model(obj_uid);
|
||||
if (!obj)
|
||||
continue;
|
||||
|
||||
SceneObject* instance = std::get<SceneObject*>(obj.value());
|
||||
|
||||
if (_world->is_selected(instance))
|
||||
_world->remove_from_selection(obj.value());
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
void selection_group::move_group()
|
||||
{
|
||||
|
||||
// _world->select_objects_in_area
|
||||
}
|
||||
|
||||
void selection_group::recalcExtents()
|
||||
{
|
||||
for (unsigned int obj_uid : _members_uid)
|
||||
{
|
||||
std::optional<selection_type> obj = _world->get_model(obj_uid);
|
||||
if (!obj)
|
||||
continue;
|
||||
|
||||
SceneObject* instance = std::get<SceneObject*>(obj.value());
|
||||
|
||||
// min = glm::min(min, point);
|
||||
if (instance->getExtents()[0].x < _group_extents[0].x)
|
||||
_group_extents[0].x = instance->extents[0].x;
|
||||
if (instance->getExtents()[0].y < _group_extents[0].y)
|
||||
_group_extents[0].y = instance->extents[0].y;
|
||||
if (instance->getExtents()[0].z < _group_extents[0].z)
|
||||
_group_extents[0].z = instance->extents[0].z;
|
||||
|
||||
if (instance->getExtents()[1].x > _group_extents[1].x)
|
||||
_group_extents[1].x = instance->extents[1].x;
|
||||
if (instance->getExtents()[1].y > _group_extents[1].y)
|
||||
_group_extents[1].y = instance->extents[1].y;
|
||||
if (instance->getExtents()[1].z > _group_extents[1].z)
|
||||
_group_extents[1].z = instance->extents[1].z;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,10 @@
|
||||
#include <vector>
|
||||
#include <QString>
|
||||
|
||||
// #include <noggit/World.h>
|
||||
|
||||
|
||||
class World;
|
||||
class SceneObject;
|
||||
class MapChunk;
|
||||
|
||||
@@ -48,22 +51,47 @@ enum eSelectionEntryTypes
|
||||
eEntry_MapChunk
|
||||
};
|
||||
|
||||
using selection_entry = std::pair<float, selection_type>;
|
||||
using selection_result = std::vector<selection_entry>;
|
||||
|
||||
struct selection_group
|
||||
|
||||
|
||||
class selection_group
|
||||
{
|
||||
selection_group()
|
||||
{
|
||||
};
|
||||
public:
|
||||
selection_group(std::vector<selected_object_type> selected_objects, World* world);
|
||||
|
||||
void add_member(selected_object_type);
|
||||
void add_member(selected_object_type object);
|
||||
|
||||
void set_selected_as_group(std::vector<selection_type> selection);
|
||||
bool group_contains_object(selected_object_type object);
|
||||
|
||||
void select_group();
|
||||
void unselect_group();
|
||||
|
||||
// void set_selected_as_group(std::vector<selected_object_type> selection);
|
||||
|
||||
void copy_group(); // create and save a new selection group from copied objects
|
||||
|
||||
std::vector<unsigned int> object_members; // uids
|
||||
void move_group();
|
||||
void scale_group();
|
||||
void rotate_group();
|
||||
|
||||
std::array<glm::vec3, 2> extents;
|
||||
std::vector<unsigned int> const& getObjects() const { return _members_uid; }
|
||||
|
||||
[[nodiscard]]
|
||||
std::array<glm::vec3, 2> const& getExtents() { return _group_extents; } // ensureExtents();
|
||||
|
||||
private:
|
||||
void recalcExtents();
|
||||
|
||||
std::vector<unsigned int> _members_uid; // uids
|
||||
|
||||
// std::vector<SceneObject*> _object_members;
|
||||
|
||||
std::array<glm::vec3, 2> _group_extents;
|
||||
|
||||
unsigned int _object_count = 0;
|
||||
|
||||
World* _world;
|
||||
};
|
||||
|
||||
using selection_entry = std::pair<float, selection_type>;
|
||||
using selection_result = std::vector<selection_entry>;
|
||||
@@ -232,6 +232,25 @@ std::optional<selection_type> World::get_last_selected_model() const
|
||||
? std::optional<selection_type>() : std::optional<selection_type> (*it);
|
||||
}
|
||||
|
||||
std::vector<selected_object_type> const& World::get_selected_objects() const
|
||||
{
|
||||
// std::vector<selected_object_type> objects(_selected_model_count);
|
||||
std::vector<selected_object_type> objects;
|
||||
objects.reserve(_selected_model_count);
|
||||
|
||||
ZoneScoped;
|
||||
for (auto& entry : _current_selection)
|
||||
{
|
||||
if (entry.index() == eEntry_Object)
|
||||
{
|
||||
auto obj = std::get<selected_object_type>(entry);
|
||||
objects.push_back(obj);
|
||||
}
|
||||
}
|
||||
|
||||
return objects;
|
||||
}
|
||||
|
||||
glm::vec3 getBarycentricCoordinatesAt(
|
||||
const glm::vec3& a,
|
||||
const glm::vec3& b,
|
||||
@@ -490,17 +509,31 @@ void World::set_current_selection(selection_type entry)
|
||||
_current_selection.push_back(entry);
|
||||
_multi_select_pivot = std::nullopt;
|
||||
|
||||
_selected_model_count = entry.index() == eEntry_MapChunk ? 0 : 1;
|
||||
_selected_model_count = entry.index() != eEntry_Object ? 0 : 1;
|
||||
}
|
||||
|
||||
void World::add_to_selection(selection_type entry)
|
||||
void World::add_to_selection(selection_type entry, bool skip_group)
|
||||
{
|
||||
ZoneScoped;
|
||||
if (entry.index() != eEntry_MapChunk)
|
||||
if (entry.index() == eEntry_Object)
|
||||
{
|
||||
_selected_model_count++;
|
||||
}
|
||||
|
||||
// check if it is in a group
|
||||
if (!skip_group)
|
||||
{
|
||||
auto obj = std::get<selected_object_type>(entry);
|
||||
for (auto& group : _selection_groups)
|
||||
{
|
||||
if (group.group_contains_object(obj))
|
||||
{
|
||||
// this then calls add_to_selection() with skip_group = true to avoid repetition
|
||||
group.select_group();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_current_selection.push_back(entry);
|
||||
update_selection_pivot();
|
||||
}
|
||||
@@ -511,7 +544,7 @@ void World::remove_from_selection(selection_type entry)
|
||||
std::vector<selection_type>::iterator position = std::find(_current_selection.begin(), _current_selection.end(), entry);
|
||||
if (position != _current_selection.end())
|
||||
{
|
||||
if (entry.index() != eEntry_MapChunk)
|
||||
if (entry.index() == eEntry_Object)
|
||||
{
|
||||
_selected_model_count--;
|
||||
}
|
||||
@@ -3356,3 +3389,13 @@ void World::select_objects_in_area(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void World::add_object_group()
|
||||
{
|
||||
// auto selected_objects = get_selected_objects();
|
||||
selection_group selection_group(get_selected_objects(), this);
|
||||
|
||||
_selection_groups.push_back(selection_group);
|
||||
|
||||
// write group to project
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ protected:
|
||||
// std::unordered_map<std::string, std::vector<ModelInstance*>> _models_by_filename;
|
||||
Noggit::world_model_instances_storage _model_instance_storage;
|
||||
Noggit::world_tile_update_queue _tile_update_queue;
|
||||
std::vector< selection_group> _selection_groups;
|
||||
std::vector<selection_group> _selection_groups;
|
||||
|
||||
public:
|
||||
MapIndex mapIndex;
|
||||
@@ -123,6 +123,7 @@ public:
|
||||
bool is_selected(selection_type selection) const;
|
||||
bool is_selected(std::uint32_t uid) const;
|
||||
std::vector<selection_type> const& current_selection() const { return _current_selection; }
|
||||
std::vector<selected_object_type> const& get_selected_objects() const;
|
||||
std::optional<selection_type> get_last_selected_model() const;
|
||||
bool has_selection() const { return !_current_selection.empty(); }
|
||||
bool has_multiple_model_selected() const { return _selected_model_count > 1; }
|
||||
@@ -130,7 +131,7 @@ public:
|
||||
// Unused in Red, models are now iterated by adt because of the occlusion check
|
||||
// std::unordered_map<std::string, std::vector<ModelInstance*>> get_models_by_filename() const& { return _models_by_filename; }
|
||||
void set_current_selection(selection_type entry);
|
||||
void add_to_selection(selection_type entry);
|
||||
void add_to_selection(selection_type entry, bool skip_group = false);
|
||||
void remove_from_selection(selection_type entry);
|
||||
void remove_from_selection(std::uint32_t uid);
|
||||
void reset_selection();
|
||||
@@ -389,6 +390,9 @@ public:
|
||||
glm::vec3 camera_position
|
||||
);
|
||||
|
||||
void add_object_group();
|
||||
void delete_object_group();
|
||||
|
||||
protected:
|
||||
// void update_models_by_filename();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user