rework drag selection, now checks for occlusion and bounds + optimizations

optimize multi selections pivot updates management
experimental rendering update : don't do object frustum/visibiltiy checks if camera/objects did not move
This commit is contained in:
T1ti
2024-09-27 08:42:38 +02:00
parent 7541e31c3a
commit 279a675651
15 changed files with 352 additions and 113 deletions

View File

@@ -100,6 +100,7 @@ public:
std::atomic<bool> changed;
bool _was_rendered_last_frame = false;
bool intersect (math::ray const&, selection_result*);
@@ -218,7 +219,6 @@ private:
bool _load_textures;
World* _world;
Noggit::Rendering::TileRender _renderer;
Noggit::Rendering::FlightBoundsRender _fl_bounds_render;

View File

@@ -3459,7 +3459,8 @@ glm::mat4x4 MapView::model_view(bool use_debug_cam) const
glm::mat4x4 MapView::projection() const
{
float far_z = _settings->value("view_distance", 2000.f).toFloat() + 1.f;
// float far_z = _settings->value("view_distance", 2000.f).toFloat() + 1.f;
float far_z = _world->renderer()->_view_distance + 1.0f;
if (_display_mode == display_mode::in_2D)
{
@@ -4011,7 +4012,7 @@ void MapView::mouseReleaseEvent (QMouseEvent* event)
glm::vec2(std::max(_drag_start_pos.x(), drag_end_pos.x()), std::max(_drag_start_pos.y(), drag_end_pos.y()))
};
// _world->select_objects_in_area(selection_box, !_mod_shift_down, model_view(), projection(), width(), height(), objectEditor->drag_selection_depth(), _camera.position);
_world->select_objects_in_area(selection_box, !_mod_shift_down, model_view(), projection(), width(), height(), 3000.0f, _camera.position);
_world->select_objects_in_area(selection_box, !_mod_shift_down, model_view(), projection(), width(), height(), 50000.0f, _camera.position);
}
else // Do normal selection when we just clicked
{
@@ -4063,7 +4064,10 @@ void MapView::save(save_mode mode)
first_warning.setIcon(QMessageBox::Critical);
first_warning.setWindowIcon(QIcon (":/icon"));
first_warning.setWindowTitle("Some models couldn't be loaded");
first_warning.setText("Error:\nSome models could not be loaded and saving will cause collision and culling issues, would you still like to save ?");
first_warning.setText("Error:\nSome models could not be loaded and saving will cause collision and culling issues,"
" this is most likely caused by missing or corrupted models."
"\nCheck the log file for the list of model errors and fix them."
"\nWould you still like to save ?");
// roles are swapped to force the user to pay attention and both are "accept" roles so that escape does nothing
no = first_warning.addButton("No", QMessageBox::ButtonRole::AcceptRole);
yes = first_warning.addButton("Yes", QMessageBox::ButtonRole::YesRole);
@@ -4222,7 +4226,7 @@ void MapView::onSettingsSave()
_world->renderer()->markTerrainParamsUniformBlockDirty();
_world->renderer()->setViewDistance(_settings->value("view_distance", 2000.f).toFloat());
_world->renderer()->_view_distance = _settings->value("view_distance", 2000.f).toFloat();
_world.get()->mapIndex.setLoadingRadius(_settings->value("loading_radius", 2).toInt());
_world.get()->mapIndex.setUnloadDistance(_settings->value("unload_dist", 5).toInt());

View File

@@ -55,6 +55,12 @@ namespace misc
clipSpacePos.x = (ndcX + 1.0f) * 0.5f * viewport_width;
clipSpacePos.y = (1.0f - (ndcY + 1.0f) * 0.5f) * viewport_height;
// from MapView::normalized_device_coords
// x 2.0f * x / viewport_width - 1.0f
// y 1.0f - 2.0f * y / viewport_height
// z 0.0f
// w 1.0f
valid = true;
return clipSpacePos;
}

View File

@@ -11,13 +11,13 @@
#include <noggit/TextureManager.h>
#include <noggit/tool_enums.hpp>
#include <noggit/ContextObject.hpp>
#include <noggit/rendering/ModelRender.hpp>
#include <opengl/scoped.hpp>
#include <opengl/shader.fwd.hpp>
#include <ClientFile.hpp>
#include <optional>
#include <string>
#include <vector>
#include <noggit/rendering/ModelRender.hpp>
#include <map>
class Bone;
class Model;
@@ -188,6 +188,8 @@ public:
[[nodiscard]]
Noggit::Rendering::ModelRender* renderer() { return &_renderer; }
uint32_t get_anim_lenght(int16_t anim_id) { return _animation_length[anim_id]; }
// ===============================
// Toggles
// ===============================
@@ -276,5 +278,6 @@ private:
Noggit::Rendering::ModelRender _renderer;
bool _hidden = false;
};

View File

@@ -90,6 +90,8 @@ public:
bool isInFrustum(math::frustum const& frustum);
bool isInRenderDist(const float& cull_distance, const glm::vec3& camera, display_mode display);
bool extentsDirty() { return _need_recalc_extents || !model->finishedLoading(); };
[[nodiscard]]
virtual glm::vec3 const& get_pos() const { return pos; }

View File

@@ -86,6 +86,9 @@ public:
unsigned int uid;
int frame;
// Note : First, need to check if the tile that contained it was rendered too
bool _rendered_last_frame = false;
protected:
SceneObjectTypes _type;

View File

@@ -317,8 +317,9 @@ void selection_group::select_group()
if (_world->is_selected(instance))
continue;
_world->add_to_selection(obj.value(), true);
_world->add_to_selection(obj.value(), true, false);
}
_world->update_selection_pivot();
_is_selected = true;
}
@@ -328,9 +329,9 @@ 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, true);
_world->remove_from_selection(obj_uid, true, false);
}
_world->update_selection_pivot();
_is_selected = false;
}

View File

@@ -111,5 +111,5 @@ private:
// bool _need_recalc_extents = false;
};
using selection_entry = std::pair<float, selection_type>;
using selection_entry = std::pair<float, selection_type>; // float = hit distance
using selection_result = std::vector<selection_entry>;

View File

@@ -35,6 +35,7 @@ namespace Noggit
{
display_mode displayMode = display_mode::in_3D;
bool underMap = false;
bool camera_moved_since_last_draw = false;
bool left_mouse = false;
bool right_mouse = false;

View File

@@ -558,7 +558,8 @@ void World::set_current_selection(selection_type entry)
add_to_selection(entry);
}
void World::add_to_selection(selection_type entry, bool skip_group)
// updating pivot is expensive, in mass selection situation, it should only be updated once after operation is done
void World::add_to_selection(selection_type entry, bool skip_group, bool update_pivot)
{
ZoneScoped;
if (entry.index() == eEntry_Object)
@@ -583,10 +584,12 @@ void World::add_to_selection(selection_type entry, bool skip_group)
}
}
_current_selection.push_back(entry);
if (update_pivot)
update_selection_pivot();
}
void World::remove_from_selection(selection_type entry, bool skip_group)
void World::remove_from_selection(selection_type entry, bool skip_group, bool update_pivot)
{
ZoneScoped;
std::vector<selection_type>::iterator position = std::find(_current_selection.begin(), _current_selection.end(), entry);
@@ -613,11 +616,12 @@ void World::remove_from_selection(selection_type entry, bool skip_group)
}
_current_selection.erase(position);
if (update_pivot)
update_selection_pivot();
}
}
void World::remove_from_selection(std::uint32_t uid, bool skip_group)
void World::remove_from_selection(std::uint32_t uid, bool skip_group, bool update_pivot)
{
ZoneScoped;
for (auto it = _current_selection.begin(); it != _current_selection.end(); ++it)
@@ -645,7 +649,7 @@ void World::remove_from_selection(std::uint32_t uid, bool skip_group)
}
}
}
if (update_pivot)
update_selection_pivot();
return;
}
@@ -2041,6 +2045,10 @@ void World::remove_models_if_needed(std::vector<uint32_t> const& uids)
{
reset_selection();
}
else
{
update_selection_pivot();
}
/*
if (uids.size())
{
@@ -3030,14 +3038,15 @@ void World::range_add_to_selection(glm::vec3 const& pos, float radius, bool remo
{
if (remove)
{
remove_from_selection(obj);
remove_from_selection(obj, false, false);
}
else
{
if (!is_selected(obj))
add_to_selection(obj);
add_to_selection(obj, false, false);
}
}
update_selection_pivot();
}
float World::getMaxTileHeight(const TileIndex& tile)
@@ -3576,14 +3585,14 @@ void World::notifyTileRendererOnSelectedTextureChange()
}
void World::select_objects_in_area(
const std::array<glm::vec2, 2> selection_box,
const std::array<glm::vec2, 2>& selection_box,
bool reset_selection,
glm::mat4x4 view,
glm::mat4x4 projection,
const glm::mat4x4& view,
const glm::mat4x4& projection,
int viewport_width,
int viewport_height,
float user_depth,
glm::vec3 camera_position)
const glm::vec3& camera_position)
{
ZoneScoped;
@@ -3594,6 +3603,15 @@ void World::select_objects_in_area(
glm::mat4 VPmatrix = projection * view;
constexpr int max_position_raycast_processing = 10000;
constexpr int max_bounds_raycast_processing = 5000; // when selecting large amount of objects, avoid doing complex ray calculations to not freeze
constexpr float bounds_check_scale = 0.8f; // size of the bounding box to use when interesecting withs election rectangle
constexpr float obj_raycast_min_size = 30.0f; // screen size rectangle lenght in pixels
int processed_obj_count = 0;
// int debug_count_obj_min_size = 0;
// int debug_count_obj_min_size_not = 0;
for (auto& map_object : _loaded_tiles_buffer)
{
MapTile* tile = map_object.second;
@@ -3607,17 +3625,19 @@ void World::select_objects_in_area(
{
// tile not in screen, skip
// frustum.intersects(tile_extents[1], tile_extents[0])
if (tile->renderer()->isFrustumCulled())
if (!tile->_was_rendered_last_frame)
continue;
// check if tile combined extents are within selection rectangle
// note very useful because cases where a tile is fully rendered and not selected are very rare
// skip if no objects
if (tile->getObjectInstances().empty())
continue;
// check if tile combined extents are within selection rectangle
bool valid = false;
auto screenBounds = misc::getAABBScreenBounds(tile->getCombinedExtents(), VPmatrix
, viewport_width, viewport_height, valid);
, viewport_width, viewport_height, valid, 1.0f);
// this only works if all tile points are in screen space
if (valid && !math::boxIntersects(screenBounds[0], screenBounds[1]
@@ -3629,12 +3649,33 @@ void World::select_objects_in_area(
for (auto& pair : tile->getObjectInstances())
{
[[unlikely]]
if (!pair.first->finishedLoading())
continue;
auto objectType = pair.second[0]->which();
if (objectType == eMODEL || objectType == eWMO)
{
[[unlikely]]
if (!(objectType == eMODEL || objectType == eWMO))
continue;
for (auto& instance : pair.second)
{
// problem : M2s have additional sized based culling with >isInRenderDist()
// if (!instance->_rendered_last_frame)
// continue;
// unsigned int uid = instance->uid;
// auto modelInstance = _model_instance_storage.get_instance(uid);
// [[unlikely]]
// if (!modelInstance || !modelInstance.value().index() == eEntry_Object)
// continue;
// auto obj = std::get<selected_object_type>(modelInstance.value());
bool do_selection = false;
// Old code to check position point instead of bound box
{
glm::vec4 screenPos = VPmatrix * glm::vec4(instance->pos, 1.0f);
// if screenPos.w < 0.0f, object is behind camera
@@ -3650,42 +3691,107 @@ void World::select_objects_in_area(
screenPos.y = (1.0f - (screenPos.y + 1.0f) * 0.5f) * viewport_height;
float depth = glm::distance(camera_position, instance->pos);
if (depth <= user_depth)
{
bool do_selection = false;
float distance = glm::distance(camera_position, instance->pos);
if (distance > user_depth)
continue;
// check if position(origin) point is within rectangle first because it is much cheaper
{
const glm::vec2 screenPos2D = glm::vec2(screenPos);
if (misc::pointInside(screenPos2D, selection_box))
{
processed_obj_count++;
// check if point is occluded by terrain
if (processed_obj_count < max_position_raycast_processing
&& !is_point_occluded_by_terrain(instance->pos, view, VPmatrix, viewport_width, viewport_height, camera_position))
{
do_selection = true;
}
// else
// bool debug_breakpoint = true;
}
}
}
// if it's not, check again if bounding box is within selection
if (!do_selection)
if (!do_selection && instance->_rendered_last_frame && (processed_obj_count < max_bounds_raycast_processing) )
{
bool valid = false;
auto screenBounds = misc::getAABBScreenBounds(instance->getExtents(), VPmatrix
, viewport_width, viewport_height, valid, 0.5f);
, viewport_width, viewport_height, valid, 0.75f);
if (valid && math::boxIntersects(screenBounds[0], screenBounds[1]
, selection_box[0], selection_box[1]))
do_selection = true;
{
// do_selection = true;
}
else
continue;
// Optimization : Only do raycast bounds checks for object that take enough screen space
if (!do_selection)
{
if (glm::distance(screenBounds[0], screenBounds[1]) < obj_raycast_min_size)
{
// debug_count_obj_min_size++;
continue;
}
else
{
// debug_count_obj_min_size_not++;
}
}
}
if (do_selection)
// Occlusion test on object's corners (that are in selection box)
// uses ray casting, very expensive
if (!do_selection)
{
unsigned int uid = instance->uid;
auto modelInstance = _model_instance_storage.get_instance(uid);
if (modelInstance && modelInstance.value().index() == eEntry_Object) {
auto obj = std::get<selected_object_type>(modelInstance.value());
auto which = std::get<selected_object_type>(modelInstance.value())->which();
math::aabb obj_aabb(instance->getExtents()[0], instance->getExtents()[1]);
auto obj_aabb_corners = obj_aabb.all_corners();
// int required_num_unoccluded_corers = 6; // require 6 of 8 corners to not be occluded
bool object_occluded = true;
for (const auto& corner : obj_aabb_corners)
{
// TODO : only need to do max top left and max top right in 2d instead of all corners?
// only process points that are within selection rectangle
bool point_valid = false;
auto point_screen_pos = misc::projectPointToScreen(corner, VPmatrix, viewport_width, viewport_height, point_valid);
if (!point_valid)
continue;
if (!misc::pointInside(point_screen_pos, selection_box))
continue;
bool corner_occluded = is_point_occluded_by_terrain(corner, view, VPmatrix, viewport_width, viewport_height, camera_position);
if (!corner_occluded)
{
object_occluded = false;
break;
}
// object_occluded = true;
}
do_selection = !object_occluded;
}
if (!do_selection)
continue;
auto& obj = instance;
auto which = obj->which();
if (which == eWMO)
{
auto model_instance = static_cast<WMOInstance*>(obj);
if (!is_selected(obj) && !model_instance->wmo->is_hidden())
{
this->add_to_selection(obj);
this->add_to_selection(obj, false, false);
}
}
else if (which == eMODEL)
@@ -3694,16 +3800,84 @@ void World::select_objects_in_area(
if (!is_selected(obj) && !model_instance->model->is_hidden())
{
this->add_to_selection(obj);
this->add_to_selection(obj, false, false);
}
}
}
}
}
this->update_selection_pivot();
}
bool World::is_point_occluded_by_terrain(const glm::vec3& point,
const glm::mat4x4& view,
const glm::mat4& VPmatrix,
float viewport_width,
float viewport_height,
const glm::vec3& camera_position)
{
/*
bool point_valid = false;
auto point_screen_pos = misc::projectPointToScreen(point, VPmatrix, viewport_width, viewport_height, point_valid);
if (!point_valid)
{
return true;
}*/
math::ray ray(camera_position, point - camera_position); // 3d display mode only.
// intersect only terrain with a ray to object's position
selection_result terrain_intersect_results
(intersect
(glm::transpose(view)
, ray
, true
, false
, true
, false
, false
, false
, false
)
);
float distance = glm::distance(camera_position, point);
// bool point_occluded = false;
for (const auto& terrain_hit : terrain_intersect_results)
{
// if terrain hit is further, skip
if (terrain_hit.first + 10.0f > distance) // add some leeway, skip hits that are too close, especially for the terrain at object's origin
continue;
return true;
auto const& hitChunkInfo = std::get<selected_chunk_type>(terrain_hit.second);
/*
// check if terrain hit is higher than the object's corner in 2D screen space
bool point_valid = false;
auto terrain_hit_screen_pos = misc::projectPointToScreen(hitChunkInfo.position, VPmatrix, viewport_width, viewport_height, point_valid);
if (!point_valid)
{
continue;
}
// if any terrain intersection point is above point, it means point is occluded
if (point_screen_pos.y > terrain_hit_screen_pos.y)
{
return true;
}
*/
}
// no terrain intersection point above point
return false;
}
void World::add_object_group_from_selection()

View File

@@ -136,9 +136,9 @@ 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, bool skip_group = false);
void remove_from_selection(selection_type entry, bool skip_group = false);
void remove_from_selection(std::uint32_t uid, bool skip_group = false);
void add_to_selection(selection_type entry, bool skip_group = false, bool update_pivot = true);
void remove_from_selection(selection_type entry, bool skip_group = false, bool update_pivot = true);
void remove_from_selection(std::uint32_t uid, bool skip_group = false, bool update_pivot = true);
void reset_selection();
void delete_selected_models();
glm::vec3 get_ground_height(glm::vec3 pos);
@@ -396,21 +396,25 @@ public:
unsigned getNumRenderedObjects() const { return _n_rendered_objects; };
void select_objects_in_area(
const std::array<glm::vec2, 2> selection_box,
const std::array<glm::vec2, 2>& selection_box,
bool reset_selection,
glm::mat4x4 view,
glm::mat4x4 projection,
const glm::mat4x4& view,
const glm::mat4x4& projection,
int viewport_width,
int viewport_height,
float user_depth,
glm::vec3 camera_position
const glm::vec3& camera_position
);
void add_object_group_from_selection();
void remove_selection_group(selection_group* group);
void clear_selection_groups();
private:
bool is_point_occluded_by_terrain(const glm::vec3& point, const glm::mat4x4& view, const glm::mat4& VPmatrix, float viewport_width, float viewport_height, const glm::vec3& camera_position);
protected:
// void update_models_by_filename();

View File

@@ -107,7 +107,7 @@ void WorldRender::draw (glm::mat4x4 const& model_view
unsigned tile_counter = 0;
for (MapTile* tile : _world->mapIndex.loaded_tiles())
{
tile->recalcCombinedExtents();
tile->_was_rendered_last_frame = false;
if (minimap_render)
{
@@ -226,6 +226,7 @@ void WorldRender::draw (glm::mat4x4 const& model_view
, frustum
, _cull_distance
, _world->animtime
, _world->time
, draw_skybox
, _outdoor_light_stats
);
@@ -304,6 +305,7 @@ void WorldRender::draw (glm::mat4x4 const& model_view
);
_world->_n_rendered_tiles++;
tile->_was_rendered_last_frame = true;
}
@@ -383,10 +385,20 @@ void WorldRender::draw (glm::mat4x4 const& model_view
// TODO: subject to potential generalization
for (auto& pair : tile->getObjectInstances())
{
if (!pair.first->finishedLoading())
continue;
if (pair.second[0]->which() == eMODEL)
{
if (!draw_models && !(minimap_render && minimap_render_settings->use_filters))
{
// can optimize this with a tile.rendered_m2s_lastframe or just check if models are enabled
for (auto& instance : pair.second)
{
instance->_rendered_last_frame = false;
}
continue;
}
auto& instances = models_to_draw[reinterpret_cast<Model*>(pair.first)];
@@ -405,9 +417,12 @@ void WorldRender::draw (glm::mat4x4 const& model_view
for (auto& instance : pair.second)
{
instance->_rendered_last_frame = false;
// do not render twice the cross-referenced objects twice
if (instance->frame == frame)
{
instance->_rendered_last_frame = true;
continue;
}
@@ -415,9 +430,20 @@ void WorldRender::draw (glm::mat4x4 const& model_view
auto m2_instance = static_cast<ModelInstance*>(instance);
if ((tile->renderer()->objectsFrustumCullTest() > 1 || m2_instance->isInFrustum(frustum)) && m2_instance->isInRenderDist(_cull_distance, camera_pos, display))
// experimental : if camera and object haven't moved/changed since last frame, we don't need to do frustum culling again
if (!camera_moved && !m2_instance->extentsDirty()/* && not_moved*/)
{
if (m2_instance->_rendered_last_frame)
{
instances.push_back(m2_instance->transformMatrix());
m2_instance->_rendered_last_frame = true;
continue; // skip visibility checks
}
}
if (m2_instance->isInRenderDist(_cull_distance, camera_pos, display) && (tile->renderer()->objectsFrustumCullTest() > 1 || m2_instance->isInFrustum(frustum)))
{
instances.push_back(m2_instance->transformMatrix());
m2_instance->_rendered_last_frame = true;
}
}
@@ -426,7 +452,13 @@ void WorldRender::draw (glm::mat4x4 const& model_view
else if (pair.second[0]->which() == eWMO)
{
if (!draw_wmo)
{
for (auto& instance : pair.second)
{
instance->_rendered_last_frame = false;
}
continue;
}
// memory allocation heuristic. all objects will pass if tile is entirely in frustum.
// otherwise we only allocate for a half
@@ -442,9 +474,12 @@ void WorldRender::draw (glm::mat4x4 const& model_view
for (auto& instance : pair.second)
{
instance->_rendered_last_frame = false;
// do not render twice the cross-referenced objects twice
if (instance->frame == frame)
{
instance->_rendered_last_frame = true;
continue;
}
@@ -452,9 +487,20 @@ void WorldRender::draw (glm::mat4x4 const& model_view
auto wmo_instance = static_cast<WMOInstance*>(instance);
// experimental : if camera and object haven't moved/changed since last frame, we don't need to do frustum culling again
if (!camera_moved && !wmo_instance->extentsDirty()/* && not_moved*/)
{
if (wmo_instance->_rendered_last_frame)
{
wmos_to_draw.push_back(wmo_instance);
wmo_instance->_rendered_last_frame = true;
continue; // skip visibility checks
}
}
if (tile->renderer()->objectsFrustumCullTest() > 1 || frustum.intersects(wmo_instance->getExtents()[1], wmo_instance->getExtents()[0]))
{
wmos_to_draw.push_back(wmo_instance);
wmo_instance->_rendered_last_frame = true;
if (draw_wmo_doodads)
{
@@ -831,7 +877,7 @@ void WorldRender::draw (glm::mat4x4 const& model_view
if (model->isInFrustum(frustum) && model->isInRenderDist(_cull_distance, camera_pos, display))
if (model->isInRenderDist(_cull_distance, camera_pos, display) && model->isInFrustum(frustum))
{
bool is_selected = false;
/*

View File

@@ -86,7 +86,7 @@ namespace Noggit::Rendering
[[nodiscard]] std::unique_ptr<Skies>& skies() { return _skies; };
void setViewDistance(float distance) { _view_distance = distance; };
float _view_distance;
private:
@@ -109,7 +109,6 @@ namespace Noggit::Rendering
World* _world;
float _cull_distance;
float _view_distance;
// shaders
std::unique_ptr<OpenGL::program> _mcnk_program;;
@@ -134,6 +133,7 @@ namespace Noggit::Rendering
Noggit::Rendering::Primitives::Sphere _sphere_render;
Noggit::Rendering::Primitives::Square _square_render;
Noggit::Rendering::Primitives::Line _line_render;
Noggit::Rendering::Primitives::WireBox _wirebox_render;
// buffers
OpenGL::Scoped::deferred_upload_buffers<8> _buffers;

View File

@@ -219,7 +219,7 @@ namespace Noggit
{
if (model_instance.instance_model()->file_key().filepath() == model_name)
{
world->add_to_selection(&model_instance);
world->add_to_selection(&model_instance, false, false);
}
});
}
@@ -229,16 +229,11 @@ namespace Noggit
if (wmo_instance.instance_model()->file_key().filepath() == model_name)
{
// objects_to_select.push_back(wmo_instance.uid);
world->add_to_selection(&wmo_instance);
world->add_to_selection(&wmo_instance, false, false);
}
});
// for (auto uid_it = objects_to_select.begin(); uid_it != objects_to_select.end(); uid_it++)
// {
// auto instance = world->getObjectInstance(*uid_it);
// // if (!world->is_selected(instance))
// world->add_to_selection(instance);
// }
world->update_selection_pivot();
}
});
@@ -790,7 +785,7 @@ namespace Noggit
glm::vec2(std::max(_drag_start_pos.x(), drag_end_pos.x()), std::max(_drag_start_pos.y(), drag_end_pos.y()))
};
// _world->select_objects_in_area(selection_box, !_mod_shift_down, model_view(), projection(), width(), height(), objectEditor->drag_selection_depth(), _camera.position);
mapView()->selectObjects(selection_box, 3000.0f);
mapView()->selectObjects(selection_box, 10000.0f);
}
else // Do normal selection when we just clicked, or selection box is too small
{
@@ -846,7 +841,7 @@ namespace Noggit
}
}
if (params.mod_shift_down || params.mod_ctrl_down)
if (_area_selection->isHidden() && (params.mod_shift_down || params.mod_ctrl_down) )
{
mapView->doSelection(false, true);
}

View File

@@ -197,7 +197,7 @@ namespace Noggit
if (--_instance_count_per_uid.at(uid) == 0)
{
_world->remove_from_selection(uid);
_world->remove_from_selection(uid, false, false);
_instance_count_per_uid.erase(uid);
_m2s.erase(uid);