From f063eeb36ee34c7230de7e670aaab923f08dcdd6 Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Thu, 27 Feb 2020 11:54:11 +0200 Subject: [PATCH 01/10] Drop objects with a keyboard shortcut --- apps/opencs/model/prefs/state.cpp | 2 + apps/opencs/view/render/instancemode.cpp | 84 +++++++++++++++++++- apps/opencs/view/render/instancemode.hpp | 14 +++- apps/opencs/view/render/object.cpp | 5 ++ apps/opencs/view/render/object.hpp | 3 + apps/opencs/view/render/worldspacewidget.cpp | 2 +- 6 files changed, 106 insertions(+), 4 deletions(-) diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index 442e707bf..422e2c1f4 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -356,6 +356,8 @@ void CSMPrefs::State::declare() QKeySequence(Qt::ControlModifier | (int)Qt::MiddleButton)); declareModifier ("scene-speed-modifier", "Speed Modifier", Qt::Key_Shift); declareShortcut ("scene-delete", "Delete Instance", QKeySequence(Qt::Key_Delete)); + declareShortcut ("scene-instance-groundlevel", "Instance to Ground Level", QKeySequence(Qt::Key_G)); + declareShortcut ("scene-instance-drop", "Drop Instance", QKeySequence(Qt::Key_H)); declareShortcut ("scene-load-cam-cell", "Load Camera Cell", QKeySequence(Qt::KeypadModifier | Qt::Key_5)); declareShortcut ("scene-load-cam-eastcell", "Load East Cell", QKeySequence(Qt::KeypadModifier | Qt::Key_6)); declareShortcut ("scene-load-cam-northcell", "Load North Cell", QKeySequence(Qt::KeypadModifier | Qt::Key_8)); diff --git a/apps/opencs/view/render/instancemode.cpp b/apps/opencs/view/render/instancemode.cpp index 92f5cbb2d..c0d478113 100644 --- a/apps/opencs/view/render/instancemode.cpp +++ b/apps/opencs/view/render/instancemode.cpp @@ -6,6 +6,10 @@ #include "../../model/prefs/state.hpp" +#include +#include +#include + #include "../../model/world/idtable.hpp" #include "../../model/world/idtree.hpp" #include "../../model/world/commands.hpp" @@ -90,16 +94,20 @@ osg::Vec3f CSVRender::InstanceMode::getScreenCoords(const osg::Vec3f& pos) return pos * combined; } -CSVRender::InstanceMode::InstanceMode (WorldspaceWidget *worldspaceWidget, QWidget *parent) +CSVRender::InstanceMode::InstanceMode (WorldspaceWidget *worldspaceWidget, osg::ref_ptr parentNode, QWidget *parent) : EditMode (worldspaceWidget, QIcon (":scenetoolbar/editing-instance"), SceneUtil::Mask_EditorReference | SceneUtil::Mask_Terrain, "Instance editing", parent), mSubMode (0), mSubModeId ("move"), mSelectionMode (0), mDragMode (DragMode_None), - mDragAxis (-1), mLocked (false), mUnitScaleDist(1) + mDragAxis (-1), mLocked (false), mUnitScaleDist(1), mParentNode (parentNode) { connect(this, SIGNAL(requestFocus(const std::string&)), worldspaceWidget, SIGNAL(requestFocus(const std::string&))); CSMPrefs::Shortcut* deleteShortcut = new CSMPrefs::Shortcut("scene-delete", worldspaceWidget); connect(deleteShortcut, SIGNAL(activated(bool)), this, SLOT(deleteSelectedInstances(bool))); + CSMPrefs::Shortcut* dropShortcut = new CSMPrefs::Shortcut("scene-instance-drop", worldspaceWidget); + connect(dropShortcut, SIGNAL(activated(bool)), this, SLOT(dropSelectedInstances(bool))); + CSMPrefs::Shortcut* groundlevelShortcut = new CSMPrefs::Shortcut("scene-instance-groundlevel", worldspaceWidget); + connect(groundlevelShortcut, SIGNAL(activated(bool)), this, SLOT(groundlevelSelectedInstances(bool))); } void CSVRender::InstanceMode::activate (CSVWidget::SceneToolbar *toolbar) @@ -681,3 +689,75 @@ void CSVRender::InstanceMode::deleteSelectedInstances(bool active) getWorldspaceWidget().clearSelection (SceneUtil::Mask_EditorReference); } + +void CSVRender::InstanceMode::dropInstance(DropMode dropMode, CSVRender::Object* object) +{ + const osg::Vec3d& point = object->getPosition().asVec3(); + osg::ref_ptr objectNode = object->getRootNode(); + osg::Node::NodeMask oldMask = objectNode->getNodeMask(); + objectNode->setNodeMask(SceneUtil::Mask_Disabled); + + osg::Vec3d start = point; + osg::Vec3d end = point; + start.z() += 1.0f; + end.z() = std::numeric_limits::min(); + + osg::ref_ptr intersector (new osgUtil::LineSegmentIntersector( + osgUtil::Intersector::MODEL, start, end) ); + intersector->setIntersectionLimit(osgUtil::LineSegmentIntersector::NO_LIMIT); + osgUtil::IntersectionVisitor visitor(intersector); + + if (dropMode == Ground_level) visitor.setTraversalMask(SceneUtil::Mask_Terrain); + if (dropMode == Coillision_Below) visitor.setTraversalMask(SceneUtil::Mask_Terrain | SceneUtil::Mask_EditorReference); + + mParentNode->accept(visitor); + + for (osgUtil::LineSegmentIntersector::Intersections::iterator it = intersector->getIntersections().begin(); + it != intersector->getIntersections().end(); ++it) + { + osgUtil::LineSegmentIntersector::Intersection intersection = *it; + ESM::Position position = object->getPosition(); + object->setEdited (Object::Override_Position); + position.pos[2] = intersection.getWorldIntersectPoint().z(); + object->setPosition(position.pos); + objectNode->setNodeMask(oldMask); + + return; + } + + objectNode->setNodeMask(oldMask); +} + +void CSVRender::InstanceMode::dropSelectedInstances(bool active) +{ + std::vector > selection = getWorldspaceWidget().getSelection (SceneUtil::Mask_EditorReference); + if (selection.empty()) return; + + CSMDoc::Document& document = getWorldspaceWidget().getDocument(); + QUndoStack& undoStack = document.getUndoStack(); + + CSMWorld::CommandMacro macro (undoStack, "Drop Instances to next coillision"); + for(osg::ref_ptr tag: selection) + if (CSVRender::ObjectTag *objectTag = dynamic_cast (tag.get())) + { + dropInstance(Coillision_Below, objectTag->mObject); + objectTag->mObject->apply (macro); + } +} + +void CSVRender::InstanceMode::groundlevelSelectedInstances(bool active) +{ + std::vector > selection = getWorldspaceWidget().getSelection (SceneUtil::Mask_EditorReference); + if (selection.empty()) return; + + CSMDoc::Document& document = getWorldspaceWidget().getDocument(); + QUndoStack& undoStack = document.getUndoStack(); + + CSMWorld::CommandMacro macro (undoStack, "Drop Instances to Ground Level"); + for(osg::ref_ptr tag: selection) + if (CSVRender::ObjectTag *objectTag = dynamic_cast (tag.get())) + { + dropInstance(Ground_level, objectTag->mObject); + objectTag->mObject->apply (macro); + } +} diff --git a/apps/opencs/view/render/instancemode.hpp b/apps/opencs/view/render/instancemode.hpp index 23df3f37d..4d7ac9cac 100644 --- a/apps/opencs/view/render/instancemode.hpp +++ b/apps/opencs/view/render/instancemode.hpp @@ -2,6 +2,7 @@ #define CSV_RENDER_INSTANCEMODE_H #include +#include #include #include @@ -16,6 +17,7 @@ namespace CSVRender { class TagBase; class InstanceSelectionMode; + class Object; class InstanceMode : public EditMode { @@ -29,6 +31,12 @@ namespace CSVRender DragMode_Scale }; + enum DropMode + { + Coillision_Below, + Ground_level + }; + CSVWidget::SceneToolMode *mSubMode; std::string mSubModeId; InstanceSelectionMode *mSelectionMode; @@ -36,6 +44,7 @@ namespace CSVRender int mDragAxis; bool mLocked; float mUnitScaleDist; + osg::ref_ptr mParentNode; int getSubModeFromId (const std::string& id) const; @@ -44,10 +53,11 @@ namespace CSVRender osg::Vec3f getSelectionCenter(const std::vector >& selection) const; osg::Vec3f getScreenCoords(const osg::Vec3f& pos); + void dropInstance(DropMode dropMode, CSVRender::Object* object); public: - InstanceMode (WorldspaceWidget *worldspaceWidget, QWidget *parent = 0); + InstanceMode (WorldspaceWidget *worldspaceWidget, osg::ref_ptr parentNode, QWidget *parent = 0); virtual void activate (CSVWidget::SceneToolbar *toolbar); @@ -93,6 +103,8 @@ namespace CSVRender void subModeChanged (const std::string& id); void deleteSelectedInstances(bool active); + void dropSelectedInstances(bool active); + void groundlevelSelectedInstances(bool active); }; } diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index 02f89b0ab..47754b448 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -477,6 +477,11 @@ bool CSVRender::Object::getSelected() const return mSelected; } +osg::ref_ptr CSVRender::Object::getRootNode() +{ + return mRootNode; +} + bool CSVRender::Object::referenceableDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) { diff --git a/apps/opencs/view/render/object.hpp b/apps/opencs/view/render/object.hpp index 10a46fc10..b2561d585 100644 --- a/apps/opencs/view/render/object.hpp +++ b/apps/opencs/view/render/object.hpp @@ -146,6 +146,9 @@ namespace CSVRender bool getSelected() const; + /// For direct altering of object rendering + osg::ref_ptr getRootNode(); + /// \return Did this call result in a modification of the visual representation of /// this object? bool referenceableDataChanged (const QModelIndex& topLeft, diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 77ecba918..6ab4b041b 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -370,7 +370,7 @@ void CSVRender::WorldspaceWidget::addVisibilitySelectorButtons ( void CSVRender::WorldspaceWidget::addEditModeSelectorButtons (CSVWidget::SceneToolMode *tool) { /// \todo replace EditMode with suitable subclasses - tool->addButton (new InstanceMode (this, tool), "object"); + tool->addButton (new InstanceMode (this, mRootNode, tool), "object"); tool->addButton (new PathgridMode (this, tool), "pathgrid"); } From 711dc59f09775120e1e5373145c1cb1435d56727 Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Fri, 28 Feb 2020 13:20:57 +0200 Subject: [PATCH 02/10] Implement four different functions for dropping --- apps/opencs/model/prefs/state.cpp | 6 +- apps/opencs/view/render/instancemode.cpp | 129 ++++++++++++++++++----- apps/opencs/view/render/instancemode.hpp | 16 ++- 3 files changed, 119 insertions(+), 32 deletions(-) diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index 422e2c1f4..89b5283a4 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -356,8 +356,10 @@ void CSMPrefs::State::declare() QKeySequence(Qt::ControlModifier | (int)Qt::MiddleButton)); declareModifier ("scene-speed-modifier", "Speed Modifier", Qt::Key_Shift); declareShortcut ("scene-delete", "Delete Instance", QKeySequence(Qt::Key_Delete)); - declareShortcut ("scene-instance-groundlevel", "Instance to Ground Level", QKeySequence(Qt::Key_G)); - declareShortcut ("scene-instance-drop", "Drop Instance", QKeySequence(Qt::Key_H)); + declareShortcut ("scene-instance-drop-terrain", "Drop to terrain level", QKeySequence(Qt::Key_G)); + declareShortcut ("scene-instance-drop-collision", "Drop to collision", QKeySequence(Qt::Key_H)); + declareShortcut ("scene-instance-drop-terrain-separately", "Drop to terrain level separately", QKeySequence()); + declareShortcut ("scene-instance-drop-collision-separately", "Drop to collision separately", QKeySequence()); declareShortcut ("scene-load-cam-cell", "Load Camera Cell", QKeySequence(Qt::KeypadModifier | Qt::Key_5)); declareShortcut ("scene-load-cam-eastcell", "Load East Cell", QKeySequence(Qt::KeypadModifier | Qt::Key_6)); declareShortcut ("scene-load-cam-northcell", "Load North Cell", QKeySequence(Qt::KeypadModifier | Qt::Key_8)); diff --git a/apps/opencs/view/render/instancemode.cpp b/apps/opencs/view/render/instancemode.cpp index c0d478113..09294c122 100644 --- a/apps/opencs/view/render/instancemode.cpp +++ b/apps/opencs/view/render/instancemode.cpp @@ -3,6 +3,7 @@ #include #include +#include #include "../../model/prefs/state.hpp" @@ -104,10 +105,16 @@ CSVRender::InstanceMode::InstanceMode (WorldspaceWidget *worldspaceWidget, osg: CSMPrefs::Shortcut* deleteShortcut = new CSMPrefs::Shortcut("scene-delete", worldspaceWidget); connect(deleteShortcut, SIGNAL(activated(bool)), this, SLOT(deleteSelectedInstances(bool))); - CSMPrefs::Shortcut* dropShortcut = new CSMPrefs::Shortcut("scene-instance-drop", worldspaceWidget); - connect(dropShortcut, SIGNAL(activated(bool)), this, SLOT(dropSelectedInstances(bool))); - CSMPrefs::Shortcut* groundlevelShortcut = new CSMPrefs::Shortcut("scene-instance-groundlevel", worldspaceWidget); - connect(groundlevelShortcut, SIGNAL(activated(bool)), this, SLOT(groundlevelSelectedInstances(bool))); + + // Following classes could be simplified by using QSignalMapper, which is obsolete in Qt5.10, but not in Qt4.8 and Qt5.14 + CSMPrefs::Shortcut* dropToCollisionShortcut = new CSMPrefs::Shortcut("scene-instance-drop-collision", worldspaceWidget); + connect(dropToCollisionShortcut, SIGNAL(activated(bool)), this, SLOT(dropSelectedInstancesToCollision(bool))); + CSMPrefs::Shortcut* dropToTerrainLevelShortcut = new CSMPrefs::Shortcut("scene-instance-drop-terrain", worldspaceWidget); + connect(dropToTerrainLevelShortcut, SIGNAL(activated(bool)), this, SLOT(dropSelectedInstancesToTerrain(bool))); + CSMPrefs::Shortcut* dropToCollisionShortcut2 = new CSMPrefs::Shortcut("scene-instance-drop-collision-separately", worldspaceWidget); + connect(dropToCollisionShortcut2, SIGNAL(activated(bool)), this, SLOT(dropSelectedInstancesToCollisionSeparately(bool))); + CSMPrefs::Shortcut* dropToTerrainLevelShortcut2 = new CSMPrefs::Shortcut("scene-instance-drop-terrain-separately", worldspaceWidget); + connect(dropToTerrainLevelShortcut2, SIGNAL(activated(bool)), this, SLOT(dropSelectedInstancesToTerrainSeparately(bool))); } void CSVRender::InstanceMode::activate (CSVWidget::SceneToolbar *toolbar) @@ -707,8 +714,8 @@ void CSVRender::InstanceMode::dropInstance(DropMode dropMode, CSVRender::Object* intersector->setIntersectionLimit(osgUtil::LineSegmentIntersector::NO_LIMIT); osgUtil::IntersectionVisitor visitor(intersector); - if (dropMode == Ground_level) visitor.setTraversalMask(SceneUtil::Mask_Terrain); - if (dropMode == Coillision_Below) visitor.setTraversalMask(SceneUtil::Mask_Terrain | SceneUtil::Mask_EditorReference); + if (dropMode == Terrain_sep) visitor.setTraversalMask(SceneUtil::Mask_Terrain); + if (dropMode == Collision_sep) visitor.setTraversalMask(SceneUtil::Mask_Terrain | SceneUtil::Mask_EditorReference); mParentNode->accept(visitor); @@ -728,24 +735,63 @@ void CSVRender::InstanceMode::dropInstance(DropMode dropMode, CSVRender::Object* objectNode->setNodeMask(oldMask); } -void CSVRender::InstanceMode::dropSelectedInstances(bool active) +float CSVRender::InstanceMode::getDropHeight(DropMode dropMode, CSVRender::Object* object) { - std::vector > selection = getWorldspaceWidget().getSelection (SceneUtil::Mask_EditorReference); - if (selection.empty()) return; + const osg::Vec3d& point = object->getPosition().asVec3(); + osg::ref_ptr objectNode = object->getRootNode(); + osg::Node::NodeMask oldMask = objectNode->getNodeMask(); + objectNode->setNodeMask(SceneUtil::Mask_Disabled); - CSMDoc::Document& document = getWorldspaceWidget().getDocument(); - QUndoStack& undoStack = document.getUndoStack(); + osg::Vec3d start = point; + osg::Vec3d end = point; + start.z() += 1.0f; + end.z() = std::numeric_limits::min(); - CSMWorld::CommandMacro macro (undoStack, "Drop Instances to next coillision"); - for(osg::ref_ptr tag: selection) - if (CSVRender::ObjectTag *objectTag = dynamic_cast (tag.get())) - { - dropInstance(Coillision_Below, objectTag->mObject); - objectTag->mObject->apply (macro); - } + osg::ref_ptr intersector (new osgUtil::LineSegmentIntersector( + osgUtil::Intersector::MODEL, start, end) ); + intersector->setIntersectionLimit(osgUtil::LineSegmentIntersector::NO_LIMIT); + osgUtil::IntersectionVisitor visitor(intersector); + + if (dropMode == Terrain) visitor.setTraversalMask(SceneUtil::Mask_Terrain); + if (dropMode == Collision) visitor.setTraversalMask(SceneUtil::Mask_Terrain | SceneUtil::Mask_EditorReference); + + mParentNode->accept(visitor); + + for (osgUtil::LineSegmentIntersector::Intersections::iterator it = intersector->getIntersections().begin(); + it != intersector->getIntersections().end(); ++it) + { + osgUtil::LineSegmentIntersector::Intersection intersection = *it; + ESM::Position position = object->getPosition(); + float dropHeight = intersection.getWorldIntersectPoint().z(); + objectNode->setNodeMask(oldMask); + return position.pos[2] - dropHeight; + } + + objectNode->setNodeMask(oldMask); + return 0.0f; +} + +void CSVRender::InstanceMode::dropSelectedInstancesToCollision(bool active) +{ + handleDropMethod(Collision, "Drop instances to next collision"); +} + +void CSVRender::InstanceMode::dropSelectedInstancesToTerrain(bool active) +{ + handleDropMethod(Terrain, "Drop instances to terrain level"); +} + +void CSVRender::InstanceMode::dropSelectedInstancesToCollisionSeparately(bool active) +{ + handleDropMethod(Terrain_sep, "Drop instances to next collision level separately"); } -void CSVRender::InstanceMode::groundlevelSelectedInstances(bool active) +void CSVRender::InstanceMode::dropSelectedInstancesToTerrainSeparately(bool active) +{ + handleDropMethod(Collision_sep, "Drop instances to terrain level separately"); +} + +void CSVRender::InstanceMode::handleDropMethod(DropMode dropMode, QString commandMsg) { std::vector > selection = getWorldspaceWidget().getSelection (SceneUtil::Mask_EditorReference); if (selection.empty()) return; @@ -753,11 +799,42 @@ void CSVRender::InstanceMode::groundlevelSelectedInstances(bool active) CSMDoc::Document& document = getWorldspaceWidget().getDocument(); QUndoStack& undoStack = document.getUndoStack(); - CSMWorld::CommandMacro macro (undoStack, "Drop Instances to Ground Level"); - for(osg::ref_ptr tag: selection) - if (CSVRender::ObjectTag *objectTag = dynamic_cast (tag.get())) - { - dropInstance(Ground_level, objectTag->mObject); - objectTag->mObject->apply (macro); - } + CSMWorld::CommandMacro macro (undoStack, commandMsg); + + switch (dropMode) + { + case Terrain: + case Collision: + { + float smallestDropHeight = std::numeric_limits::max(); + for(osg::ref_ptr tag: selection) + if (CSVRender::ObjectTag *objectTag = dynamic_cast (tag.get())) + { + float thisDrop = getDropHeight(dropMode, objectTag->mObject); + if (thisDrop < smallestDropHeight) smallestDropHeight = thisDrop; + } + for(osg::ref_ptr tag: selection) + if (CSVRender::ObjectTag *objectTag = dynamic_cast (tag.get())) + { + objectTag->mObject->setEdited (Object::Override_Position); + ESM::Position position = objectTag->mObject->getPosition(); + position.pos[2] -= smallestDropHeight; + objectTag->mObject->setPosition(position.pos); + objectTag->mObject->apply (macro); + } + } + break; + + case Terrain_sep: + case Collision_sep: + for(osg::ref_ptr tag: selection) + if (CSVRender::ObjectTag *objectTag = dynamic_cast (tag.get())) + { + dropInstance(dropMode, objectTag->mObject); + objectTag->mObject->apply (macro); + } + break; + default: + break; + } } diff --git a/apps/opencs/view/render/instancemode.hpp b/apps/opencs/view/render/instancemode.hpp index 4d7ac9cac..883dab405 100644 --- a/apps/opencs/view/render/instancemode.hpp +++ b/apps/opencs/view/render/instancemode.hpp @@ -1,6 +1,8 @@ #ifndef CSV_RENDER_INSTANCEMODE_H #define CSV_RENDER_INSTANCEMODE_H +#include + #include #include #include @@ -33,8 +35,10 @@ namespace CSVRender enum DropMode { - Coillision_Below, - Ground_level + Collision, + Terrain, + Collision_sep, + Terrain_sep }; CSVWidget::SceneToolMode *mSubMode; @@ -54,6 +58,7 @@ namespace CSVRender osg::Vec3f getSelectionCenter(const std::vector >& selection) const; osg::Vec3f getScreenCoords(const osg::Vec3f& pos); void dropInstance(DropMode dropMode, CSVRender::Object* object); + float getDropHeight(DropMode dropMode, CSVRender::Object* object); public: @@ -103,8 +108,11 @@ namespace CSVRender void subModeChanged (const std::string& id); void deleteSelectedInstances(bool active); - void dropSelectedInstances(bool active); - void groundlevelSelectedInstances(bool active); + void dropSelectedInstancesToCollision(bool active); + void dropSelectedInstancesToTerrain(bool active); + void dropSelectedInstancesToCollisionSeparately(bool active); + void dropSelectedInstancesToTerrainSeparately(bool active); + void handleDropMethod(DropMode dropMode, QString commandMsg); }; } From 54738e1e326308b9cd69c8cd26d4467fac59ca24 Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Sat, 29 Feb 2020 14:56:11 +0200 Subject: [PATCH 03/10] Handle mask disabling better --- apps/opencs/view/render/instancemode.cpp | 102 ++++++++++++++--------- 1 file changed, 61 insertions(+), 41 deletions(-) diff --git a/apps/opencs/view/render/instancemode.cpp b/apps/opencs/view/render/instancemode.cpp index 09294c122..12f14b48d 100644 --- a/apps/opencs/view/render/instancemode.cpp +++ b/apps/opencs/view/render/instancemode.cpp @@ -20,6 +20,7 @@ #include "../widget/scenetoolbar.hpp" #include "../widget/scenetoolmode.hpp" +#include #include #include "object.hpp" @@ -700,9 +701,6 @@ void CSVRender::InstanceMode::deleteSelectedInstances(bool active) void CSVRender::InstanceMode::dropInstance(DropMode dropMode, CSVRender::Object* object) { const osg::Vec3d& point = object->getPosition().asVec3(); - osg::ref_ptr objectNode = object->getRootNode(); - osg::Node::NodeMask oldMask = objectNode->getNodeMask(); - objectNode->setNodeMask(SceneUtil::Mask_Disabled); osg::Vec3d start = point; osg::Vec3d end = point; @@ -727,20 +725,15 @@ void CSVRender::InstanceMode::dropInstance(DropMode dropMode, CSVRender::Object* object->setEdited (Object::Override_Position); position.pos[2] = intersection.getWorldIntersectPoint().z(); object->setPosition(position.pos); - objectNode->setNodeMask(oldMask); return; } - - objectNode->setNodeMask(oldMask); } float CSVRender::InstanceMode::getDropHeight(DropMode dropMode, CSVRender::Object* object) { const osg::Vec3d& point = object->getPosition().asVec3(); osg::ref_ptr objectNode = object->getRootNode(); - osg::Node::NodeMask oldMask = objectNode->getNodeMask(); - objectNode->setNodeMask(SceneUtil::Mask_Disabled); osg::Vec3d start = point; osg::Vec3d end = point; @@ -763,11 +756,9 @@ float CSVRender::InstanceMode::getDropHeight(DropMode dropMode, CSVRender::Objec osgUtil::LineSegmentIntersector::Intersection intersection = *it; ESM::Position position = object->getPosition(); float dropHeight = intersection.getWorldIntersectPoint().z(); - objectNode->setNodeMask(oldMask); return position.pos[2] - dropHeight; } - objectNode->setNodeMask(oldMask); return 0.0f; } @@ -801,40 +792,69 @@ void CSVRender::InstanceMode::handleDropMethod(DropMode dropMode, QString comman CSMWorld::CommandMacro macro (undoStack, commandMsg); - switch (dropMode) + std::vector oldMasks; + for(osg::ref_ptr tag: selection) { - case Terrain: - case Collision: + if (CSVRender::ObjectTag *objectTag = dynamic_cast (tag.get())) + { + osg::ref_ptr objectNode = objectTag->mObject->getRootNode(); + oldMasks.emplace_back(objectNode->getNodeMask()); + objectNode->setNodeMask(SceneUtil::Mask_Disabled); + } + } + + try + { + switch (dropMode) + { + case Terrain: + case Collision: { - float smallestDropHeight = std::numeric_limits::max(); - for(osg::ref_ptr tag: selection) - if (CSVRender::ObjectTag *objectTag = dynamic_cast (tag.get())) - { - float thisDrop = getDropHeight(dropMode, objectTag->mObject); - if (thisDrop < smallestDropHeight) smallestDropHeight = thisDrop; - } - for(osg::ref_ptr tag: selection) - if (CSVRender::ObjectTag *objectTag = dynamic_cast (tag.get())) - { - objectTag->mObject->setEdited (Object::Override_Position); - ESM::Position position = objectTag->mObject->getPosition(); - position.pos[2] -= smallestDropHeight; - objectTag->mObject->setPosition(position.pos); - objectTag->mObject->apply (macro); - } + float smallestDropHeight = std::numeric_limits::max(); + for(osg::ref_ptr tag: selection) + if (CSVRender::ObjectTag *objectTag = dynamic_cast (tag.get())) + { + float thisDrop = getDropHeight(dropMode, objectTag->mObject); + if (thisDrop < smallestDropHeight) smallestDropHeight = thisDrop; + } + for(osg::ref_ptr tag: selection) + if (CSVRender::ObjectTag *objectTag = dynamic_cast (tag.get())) + { + objectTag->mObject->setEdited (Object::Override_Position); + ESM::Position position = objectTag->mObject->getPosition(); + position.pos[2] -= smallestDropHeight; + objectTag->mObject->setPosition(position.pos); + objectTag->mObject->apply (macro); + } } - break; + break; + + case Terrain_sep: + case Collision_sep: + for(osg::ref_ptr tag: selection) + if (CSVRender::ObjectTag *objectTag = dynamic_cast (tag.get())) + { + dropInstance(dropMode, objectTag->mObject); + objectTag->mObject->apply (macro); + } + break; + default: + break; + } + } + catch (const std::exception& e) + { + Log(Debug::Error) << "Error in dropping instance: " << e.what(); + } - case Terrain_sep: - case Collision_sep: - for(osg::ref_ptr tag: selection) - if (CSVRender::ObjectTag *objectTag = dynamic_cast (tag.get())) - { - dropInstance(dropMode, objectTag->mObject); - objectTag->mObject->apply (macro); - } - break; - default: - break; + int counter = 0; + for(osg::ref_ptr tag: selection) + { + if (CSVRender::ObjectTag *objectTag = dynamic_cast (tag.get())) + { + osg::ref_ptr objectNode = objectTag->mObject->getRootNode(); + objectNode->setNodeMask(oldMasks[counter]); + counter++; + } } } From b8e6257bebed1baffb177ce6fca35f859e604798 Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Sat, 29 Feb 2020 14:59:03 +0200 Subject: [PATCH 04/10] Add changelog --- CHANGELOG.md | 1 + CHANGELOG_PR.md | 1 + 2 files changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 32255262e..73d6320d2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -263,6 +263,7 @@ Feature #5193: Weapon sheathing Feature #5219: Impelement TestCells console command Feature #5224: Handle NiKeyframeController for NiTriShape + Feature #5274: Editor: Keyboard shortcut to drop objects to ground/obstacle in scene view Feature #5304: Morrowind-style bump-mapping Task #4686: Upgrade media decoder to a more current FFmpeg API Task #4695: Optimize Distant Terrain memory consumption diff --git a/CHANGELOG_PR.md b/CHANGELOG_PR.md index f462da32c..94b0d45ec 100644 --- a/CHANGELOG_PR.md +++ b/CHANGELOG_PR.md @@ -43,6 +43,7 @@ New Editor Features: - Changes to height editing can be cancelled without changes to data (press esc to cancel) (#4840) - Land heightmap/shape editing and vertex selection (#5170) - Deleting instances with a keypress (#5172) +- Dropping objects with keyboard shortcuts (#5274) Bug Fixes: - The Mouse Wheel can now be used for key bindings (#2679) From 035d5205d97faa8cc75341f77b14b67d057a20d2 Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Tue, 3 Mar 2020 21:18:09 +0200 Subject: [PATCH 05/10] Use collision boxes to calculate dropping height, variable naming --- apps/opencs/view/render/instancemode.cpp | 37 +++++++++++++++--------- apps/opencs/view/render/instancemode.hpp | 2 +- apps/opencs/view/render/object.cpp | 5 ++++ apps/opencs/view/render/object.hpp | 5 +++- 4 files changed, 34 insertions(+), 15 deletions(-) diff --git a/apps/opencs/view/render/instancemode.cpp b/apps/opencs/view/render/instancemode.cpp index 12f14b48d..6f0ed01a0 100644 --- a/apps/opencs/view/render/instancemode.cpp +++ b/apps/opencs/view/render/instancemode.cpp @@ -7,6 +7,7 @@ #include "../../model/prefs/state.hpp" +#include #include #include #include @@ -704,7 +705,6 @@ void CSVRender::InstanceMode::dropInstance(DropMode dropMode, CSVRender::Object* osg::Vec3d start = point; osg::Vec3d end = point; - start.z() += 1.0f; end.z() = std::numeric_limits::min(); osg::ref_ptr intersector (new osgUtil::LineSegmentIntersector( @@ -730,14 +730,12 @@ void CSVRender::InstanceMode::dropInstance(DropMode dropMode, CSVRender::Object* } } -float CSVRender::InstanceMode::getDropHeight(DropMode dropMode, CSVRender::Object* object) +float CSVRender::InstanceMode::getDropHeight(DropMode dropMode, CSVRender::Object* object, float objectHeight) { const osg::Vec3d& point = object->getPosition().asVec3(); - osg::ref_ptr objectNode = object->getRootNode(); osg::Vec3d start = point; osg::Vec3d end = point; - start.z() += 1.0f; end.z() = std::numeric_limits::min(); osg::ref_ptr intersector (new osgUtil::LineSegmentIntersector( @@ -754,9 +752,8 @@ float CSVRender::InstanceMode::getDropHeight(DropMode dropMode, CSVRender::Objec it != intersector->getIntersections().end(); ++it) { osgUtil::LineSegmentIntersector::Intersection intersection = *it; - ESM::Position position = object->getPosition(); - float dropHeight = intersection.getWorldIntersectPoint().z(); - return position.pos[2] - dropHeight; + float collisionLevel = intersection.getWorldIntersectPoint().z(); + return point.z() - collisionLevel + objectHeight; } return 0.0f; @@ -793,13 +790,25 @@ void CSVRender::InstanceMode::handleDropMethod(DropMode dropMode, QString comman CSMWorld::CommandMacro macro (undoStack, commandMsg); std::vector oldMasks; + std::vector objectHeights; for(osg::ref_ptr tag: selection) { if (CSVRender::ObjectTag *objectTag = dynamic_cast (tag.get())) { - osg::ref_ptr objectNode = objectTag->mObject->getRootNode(); - oldMasks.emplace_back(objectNode->getNodeMask()); - objectNode->setNodeMask(SceneUtil::Mask_Disabled); + osg::ref_ptr objectNodeWithGUI = objectTag->mObject->getRootNode(); + osg::ref_ptr objectNodeWithoutGUI = objectTag->mObject->getBaseNode(); + + osg::ComputeBoundsVisitor computeBounds; + computeBounds.setTraversalMask(SceneUtil::Mask_EditorReference); + objectNodeWithoutGUI->accept(computeBounds); + osg::BoundingBox bounds = computeBounds.getBoundingBox(); + float boundingBoxOffset = 0.0f; + if (bounds.valid()) boundingBoxOffset = bounds.zMin(); + + objectHeights.emplace_back(boundingBoxOffset); + oldMasks.emplace_back(objectNodeWithGUI->getNodeMask()); + + objectNodeWithGUI->setNodeMask(SceneUtil::Mask_Disabled); } } @@ -811,11 +820,13 @@ void CSVRender::InstanceMode::handleDropMethod(DropMode dropMode, QString comman case Collision: { float smallestDropHeight = std::numeric_limits::max(); + int counter = 0; for(osg::ref_ptr tag: selection) if (CSVRender::ObjectTag *objectTag = dynamic_cast (tag.get())) { - float thisDrop = getDropHeight(dropMode, objectTag->mObject); + float thisDrop = getDropHeight(dropMode, objectTag->mObject, objectHeights[counter]); if (thisDrop < smallestDropHeight) smallestDropHeight = thisDrop; + counter++; } for(osg::ref_ptr tag: selection) if (CSVRender::ObjectTag *objectTag = dynamic_cast (tag.get())) @@ -852,8 +863,8 @@ void CSVRender::InstanceMode::handleDropMethod(DropMode dropMode, QString comman { if (CSVRender::ObjectTag *objectTag = dynamic_cast (tag.get())) { - osg::ref_ptr objectNode = objectTag->mObject->getRootNode(); - objectNode->setNodeMask(oldMasks[counter]); + osg::ref_ptr objectNodeWithGUI = objectTag->mObject->getRootNode(); + objectNodeWithGUI->setNodeMask(oldMasks[counter]); counter++; } } diff --git a/apps/opencs/view/render/instancemode.hpp b/apps/opencs/view/render/instancemode.hpp index 883dab405..38280dd6f 100644 --- a/apps/opencs/view/render/instancemode.hpp +++ b/apps/opencs/view/render/instancemode.hpp @@ -58,7 +58,7 @@ namespace CSVRender osg::Vec3f getSelectionCenter(const std::vector >& selection) const; osg::Vec3f getScreenCoords(const osg::Vec3f& pos); void dropInstance(DropMode dropMode, CSVRender::Object* object); - float getDropHeight(DropMode dropMode, CSVRender::Object* object); + float getDropHeight(DropMode dropMode, CSVRender::Object* object, float objectHeight); public: diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index 47754b448..6b33cdeb2 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -482,6 +482,11 @@ osg::ref_ptr CSVRender::Object::getRootNode() return mRootNode; } +osg::ref_ptr CSVRender::Object::getBaseNode() +{ + return mBaseNode; +} + bool CSVRender::Object::referenceableDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) { diff --git a/apps/opencs/view/render/object.hpp b/apps/opencs/view/render/object.hpp index b2561d585..4d1763f80 100644 --- a/apps/opencs/view/render/object.hpp +++ b/apps/opencs/view/render/object.hpp @@ -146,9 +146,12 @@ namespace CSVRender bool getSelected() const; - /// For direct altering of object rendering + /// Get object node with GUI graphics osg::ref_ptr getRootNode(); + /// Get object node without GUI graphics + osg::ref_ptr getBaseNode(); + /// \return Did this call result in a modification of the visual representation of /// this object? bool referenceableDataChanged (const QModelIndex& topLeft, From af434cffba97965cfb28d1f90a4dc739d10ff2d9 Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Wed, 4 Mar 2020 16:49:37 +0200 Subject: [PATCH 06/10] fix numeric limits min() to lowest(), fix correct drop height --- apps/opencs/view/render/instancemode.cpp | 32 ++++++++++++++---------- apps/opencs/view/render/instancemode.hpp | 10 ++++---- 2 files changed, 24 insertions(+), 18 deletions(-) diff --git a/apps/opencs/view/render/instancemode.cpp b/apps/opencs/view/render/instancemode.cpp index 6f0ed01a0..d7ab59b53 100644 --- a/apps/opencs/view/render/instancemode.cpp +++ b/apps/opencs/view/render/instancemode.cpp @@ -110,13 +110,13 @@ CSVRender::InstanceMode::InstanceMode (WorldspaceWidget *worldspaceWidget, osg: // Following classes could be simplified by using QSignalMapper, which is obsolete in Qt5.10, but not in Qt4.8 and Qt5.14 CSMPrefs::Shortcut* dropToCollisionShortcut = new CSMPrefs::Shortcut("scene-instance-drop-collision", worldspaceWidget); - connect(dropToCollisionShortcut, SIGNAL(activated(bool)), this, SLOT(dropSelectedInstancesToCollision(bool))); + connect(dropToCollisionShortcut, SIGNAL(activated()), this, SLOT(dropSelectedInstancesToCollision())); CSMPrefs::Shortcut* dropToTerrainLevelShortcut = new CSMPrefs::Shortcut("scene-instance-drop-terrain", worldspaceWidget); - connect(dropToTerrainLevelShortcut, SIGNAL(activated(bool)), this, SLOT(dropSelectedInstancesToTerrain(bool))); + connect(dropToTerrainLevelShortcut, SIGNAL(activated()), this, SLOT(dropSelectedInstancesToTerrain())); CSMPrefs::Shortcut* dropToCollisionShortcut2 = new CSMPrefs::Shortcut("scene-instance-drop-collision-separately", worldspaceWidget); - connect(dropToCollisionShortcut2, SIGNAL(activated(bool)), this, SLOT(dropSelectedInstancesToCollisionSeparately(bool))); + connect(dropToCollisionShortcut2, SIGNAL(activated()), this, SLOT(dropSelectedInstancesToCollisionSeparately())); CSMPrefs::Shortcut* dropToTerrainLevelShortcut2 = new CSMPrefs::Shortcut("scene-instance-drop-terrain-separately", worldspaceWidget); - connect(dropToTerrainLevelShortcut2, SIGNAL(activated(bool)), this, SLOT(dropSelectedInstancesToTerrainSeparately(bool))); + connect(dropToTerrainLevelShortcut2, SIGNAL(activated()), this, SLOT(dropSelectedInstancesToTerrainSeparately())); } void CSVRender::InstanceMode::activate (CSVWidget::SceneToolbar *toolbar) @@ -699,13 +699,14 @@ void CSVRender::InstanceMode::deleteSelectedInstances(bool active) getWorldspaceWidget().clearSelection (SceneUtil::Mask_EditorReference); } -void CSVRender::InstanceMode::dropInstance(DropMode dropMode, CSVRender::Object* object) +void CSVRender::InstanceMode::dropInstance(DropMode dropMode, CSVRender::Object* object, float objectHeight) { const osg::Vec3d& point = object->getPosition().asVec3(); osg::Vec3d start = point; + start.z() += objectHeight; osg::Vec3d end = point; - end.z() = std::numeric_limits::min(); + end.z() = std::numeric_limits::lowest(); osg::ref_ptr intersector (new osgUtil::LineSegmentIntersector( osgUtil::Intersector::MODEL, start, end) ); @@ -723,7 +724,7 @@ void CSVRender::InstanceMode::dropInstance(DropMode dropMode, CSVRender::Object* osgUtil::LineSegmentIntersector::Intersection intersection = *it; ESM::Position position = object->getPosition(); object->setEdited (Object::Override_Position); - position.pos[2] = intersection.getWorldIntersectPoint().z(); + position.pos[2] = intersection.getWorldIntersectPoint().z() + objectHeight; object->setPosition(position.pos); return; @@ -735,8 +736,9 @@ float CSVRender::InstanceMode::getDropHeight(DropMode dropMode, CSVRender::Objec const osg::Vec3d& point = object->getPosition().asVec3(); osg::Vec3d start = point; + start.z() += objectHeight; osg::Vec3d end = point; - end.z() = std::numeric_limits::min(); + end.z() = std::numeric_limits::lowest(); osg::ref_ptr intersector (new osgUtil::LineSegmentIntersector( osgUtil::Intersector::MODEL, start, end) ); @@ -759,22 +761,22 @@ float CSVRender::InstanceMode::getDropHeight(DropMode dropMode, CSVRender::Objec return 0.0f; } -void CSVRender::InstanceMode::dropSelectedInstancesToCollision(bool active) +void CSVRender::InstanceMode::dropSelectedInstancesToCollision() { handleDropMethod(Collision, "Drop instances to next collision"); } -void CSVRender::InstanceMode::dropSelectedInstancesToTerrain(bool active) +void CSVRender::InstanceMode::dropSelectedInstancesToTerrain() { handleDropMethod(Terrain, "Drop instances to terrain level"); } -void CSVRender::InstanceMode::dropSelectedInstancesToCollisionSeparately(bool active) +void CSVRender::InstanceMode::dropSelectedInstancesToCollisionSeparately() { handleDropMethod(Terrain_sep, "Drop instances to next collision level separately"); } -void CSVRender::InstanceMode::dropSelectedInstancesToTerrainSeparately(bool active) +void CSVRender::InstanceMode::dropSelectedInstancesToTerrainSeparately() { handleDropMethod(Collision_sep, "Drop instances to terrain level separately"); } @@ -842,12 +844,16 @@ void CSVRender::InstanceMode::handleDropMethod(DropMode dropMode, QString comman case Terrain_sep: case Collision_sep: + { + int counter = 0; for(osg::ref_ptr tag: selection) if (CSVRender::ObjectTag *objectTag = dynamic_cast (tag.get())) { - dropInstance(dropMode, objectTag->mObject); + dropInstance(dropMode, objectTag->mObject, objectHeights[counter]); objectTag->mObject->apply (macro); + counter++; } + } break; default: break; diff --git a/apps/opencs/view/render/instancemode.hpp b/apps/opencs/view/render/instancemode.hpp index 38280dd6f..de7004f4f 100644 --- a/apps/opencs/view/render/instancemode.hpp +++ b/apps/opencs/view/render/instancemode.hpp @@ -57,7 +57,7 @@ namespace CSVRender osg::Vec3f getSelectionCenter(const std::vector >& selection) const; osg::Vec3f getScreenCoords(const osg::Vec3f& pos); - void dropInstance(DropMode dropMode, CSVRender::Object* object); + void dropInstance(DropMode dropMode, CSVRender::Object* object, float objectHeight); float getDropHeight(DropMode dropMode, CSVRender::Object* object, float objectHeight); public: @@ -108,10 +108,10 @@ namespace CSVRender void subModeChanged (const std::string& id); void deleteSelectedInstances(bool active); - void dropSelectedInstancesToCollision(bool active); - void dropSelectedInstancesToTerrain(bool active); - void dropSelectedInstancesToCollisionSeparately(bool active); - void dropSelectedInstancesToTerrainSeparately(bool active); + void dropSelectedInstancesToCollision(); + void dropSelectedInstancesToTerrain(); + void dropSelectedInstancesToCollisionSeparately(); + void dropSelectedInstancesToTerrainSeparately(); void handleDropMethod(DropMode dropMode, QString commandMsg); }; } From 41aa90bfa7c97a5a26ba05498bb3d51bfbd84b39 Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Wed, 18 Mar 2020 11:16:21 +0200 Subject: [PATCH 07/10] Add helper class for safer mask handling --- apps/opencs/view/render/instancemode.cpp | 113 ++++++++++++----------- apps/opencs/view/render/instancemode.hpp | 13 +++ 2 files changed, 71 insertions(+), 55 deletions(-) diff --git a/apps/opencs/view/render/instancemode.cpp b/apps/opencs/view/render/instancemode.cpp index d7ab59b53..42ab8e62e 100644 --- a/apps/opencs/view/render/instancemode.cpp +++ b/apps/opencs/view/render/instancemode.cpp @@ -791,8 +791,57 @@ void CSVRender::InstanceMode::handleDropMethod(DropMode dropMode, QString comman CSMWorld::CommandMacro macro (undoStack, commandMsg); - std::vector oldMasks; - std::vector objectHeights; + DropObjectDataHandler dropObjectDataHandler(&getWorldspaceWidget()); + + switch (dropMode) + { + case Terrain: + case Collision: + { + float smallestDropHeight = std::numeric_limits::max(); + int counter = 0; + for(osg::ref_ptr tag: selection) + if (CSVRender::ObjectTag *objectTag = dynamic_cast (tag.get())) + { + float thisDrop = getDropHeight(dropMode, objectTag->mObject, dropObjectDataHandler.mObjectHeights[counter]); + if (thisDrop < smallestDropHeight) smallestDropHeight = thisDrop; + counter++; + } + for(osg::ref_ptr tag: selection) + if (CSVRender::ObjectTag *objectTag = dynamic_cast (tag.get())) + { + objectTag->mObject->setEdited (Object::Override_Position); + ESM::Position position = objectTag->mObject->getPosition(); + position.pos[2] -= smallestDropHeight; + objectTag->mObject->setPosition(position.pos); + objectTag->mObject->apply (macro); + } + } + break; + + case Terrain_sep: + case Collision_sep: + { + int counter = 0; + for(osg::ref_ptr tag: selection) + if (CSVRender::ObjectTag *objectTag = dynamic_cast (tag.get())) + { + dropInstance(dropMode, objectTag->mObject, dropObjectDataHandler.mObjectHeights[counter]); + objectTag->mObject->apply (macro); + counter++; + } + } + break; + + default: + break; + } +} + +CSVRender::DropObjectDataHandler::DropObjectDataHandler(WorldspaceWidget* worldspacewidget) + : mWorldspaceWidget(worldspacewidget) +{ + std::vector > selection = mWorldspaceWidget->getSelection (SceneUtil::Mask_EditorReference); for(osg::ref_ptr tag: selection) { if (CSVRender::ObjectTag *objectTag = dynamic_cast (tag.get())) @@ -807,70 +856,24 @@ void CSVRender::InstanceMode::handleDropMethod(DropMode dropMode, QString comman float boundingBoxOffset = 0.0f; if (bounds.valid()) boundingBoxOffset = bounds.zMin(); - objectHeights.emplace_back(boundingBoxOffset); - oldMasks.emplace_back(objectNodeWithGUI->getNodeMask()); + mObjectHeights.emplace_back(boundingBoxOffset); + mOldMasks.emplace_back(objectNodeWithGUI->getNodeMask()); objectNodeWithGUI->setNodeMask(SceneUtil::Mask_Disabled); } } +} - try - { - switch (dropMode) - { - case Terrain: - case Collision: - { - float smallestDropHeight = std::numeric_limits::max(); - int counter = 0; - for(osg::ref_ptr tag: selection) - if (CSVRender::ObjectTag *objectTag = dynamic_cast (tag.get())) - { - float thisDrop = getDropHeight(dropMode, objectTag->mObject, objectHeights[counter]); - if (thisDrop < smallestDropHeight) smallestDropHeight = thisDrop; - counter++; - } - for(osg::ref_ptr tag: selection) - if (CSVRender::ObjectTag *objectTag = dynamic_cast (tag.get())) - { - objectTag->mObject->setEdited (Object::Override_Position); - ESM::Position position = objectTag->mObject->getPosition(); - position.pos[2] -= smallestDropHeight; - objectTag->mObject->setPosition(position.pos); - objectTag->mObject->apply (macro); - } - } - break; - - case Terrain_sep: - case Collision_sep: - { - int counter = 0; - for(osg::ref_ptr tag: selection) - if (CSVRender::ObjectTag *objectTag = dynamic_cast (tag.get())) - { - dropInstance(dropMode, objectTag->mObject, objectHeights[counter]); - objectTag->mObject->apply (macro); - counter++; - } - } - break; - default: - break; - } - } - catch (const std::exception& e) - { - Log(Debug::Error) << "Error in dropping instance: " << e.what(); - } - +CSVRender::DropObjectDataHandler::~DropObjectDataHandler() +{ + std::vector > selection = mWorldspaceWidget->getSelection (SceneUtil::Mask_EditorReference); int counter = 0; for(osg::ref_ptr tag: selection) { if (CSVRender::ObjectTag *objectTag = dynamic_cast (tag.get())) { osg::ref_ptr objectNodeWithGUI = objectTag->mObject->getRootNode(); - objectNodeWithGUI->setNodeMask(oldMasks[counter]); + objectNodeWithGUI->setNodeMask(mOldMasks[counter]); counter++; } } diff --git a/apps/opencs/view/render/instancemode.hpp b/apps/opencs/view/render/instancemode.hpp index de7004f4f..b1d5de7fe 100644 --- a/apps/opencs/view/render/instancemode.hpp +++ b/apps/opencs/view/render/instancemode.hpp @@ -114,6 +114,19 @@ namespace CSVRender void dropSelectedInstancesToTerrainSeparately(); void handleDropMethod(DropMode dropMode, QString commandMsg); }; + + /// \brief Helper class to handle object mask data in safe way + class DropObjectDataHandler + { + public: + DropObjectDataHandler(WorldspaceWidget* worldspacewidget); + ~DropObjectDataHandler(); + std::vector mObjectHeights; + + private: + WorldspaceWidget* mWorldspaceWidget; + std::vector mOldMasks; + }; } #endif From 75f6577f6113413ed5512d564064d047a41fa697 Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Wed, 18 Mar 2020 11:26:11 +0200 Subject: [PATCH 08/10] Remove unneeded include --- apps/opencs/view/render/instancemode.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/opencs/view/render/instancemode.cpp b/apps/opencs/view/render/instancemode.cpp index 42ab8e62e..ef7449f56 100644 --- a/apps/opencs/view/render/instancemode.cpp +++ b/apps/opencs/view/render/instancemode.cpp @@ -21,7 +21,6 @@ #include "../widget/scenetoolbar.hpp" #include "../widget/scenetoolmode.hpp" -#include #include #include "object.hpp" From 17cb3414d832c7128e44e5715e15933d196db952 Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Thu, 19 Mar 2020 11:18:54 +0200 Subject: [PATCH 09/10] clean-up, improve formatting --- apps/opencs/view/render/instancemode.cpp | 36 +++++++++++++----------- apps/opencs/view/render/instancemode.hpp | 4 +-- 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/apps/opencs/view/render/instancemode.cpp b/apps/opencs/view/render/instancemode.cpp index ef7449f56..7c0020f1e 100644 --- a/apps/opencs/view/render/instancemode.cpp +++ b/apps/opencs/view/render/instancemode.cpp @@ -700,7 +700,7 @@ void CSVRender::InstanceMode::deleteSelectedInstances(bool active) void CSVRender::InstanceMode::dropInstance(DropMode dropMode, CSVRender::Object* object, float objectHeight) { - const osg::Vec3d& point = object->getPosition().asVec3(); + osg::Vec3d point = object->getPosition().asVec3(); osg::Vec3d start = point; start.z() += objectHeight; @@ -712,8 +712,10 @@ void CSVRender::InstanceMode::dropInstance(DropMode dropMode, CSVRender::Object* intersector->setIntersectionLimit(osgUtil::LineSegmentIntersector::NO_LIMIT); osgUtil::IntersectionVisitor visitor(intersector); - if (dropMode == Terrain_sep) visitor.setTraversalMask(SceneUtil::Mask_Terrain); - if (dropMode == Collision_sep) visitor.setTraversalMask(SceneUtil::Mask_Terrain | SceneUtil::Mask_EditorReference); + if (dropMode == TerrainSep) + visitor.setTraversalMask(SceneUtil::Mask_Terrain); + if (dropMode == CollisionSep) + visitor.setTraversalMask(SceneUtil::Mask_Terrain | SceneUtil::Mask_EditorReference); mParentNode->accept(visitor); @@ -732,7 +734,7 @@ void CSVRender::InstanceMode::dropInstance(DropMode dropMode, CSVRender::Object* float CSVRender::InstanceMode::getDropHeight(DropMode dropMode, CSVRender::Object* object, float objectHeight) { - const osg::Vec3d& point = object->getPosition().asVec3(); + osg::Vec3d point = object->getPosition().asVec3(); osg::Vec3d start = point; start.z() += objectHeight; @@ -744,8 +746,10 @@ float CSVRender::InstanceMode::getDropHeight(DropMode dropMode, CSVRender::Objec intersector->setIntersectionLimit(osgUtil::LineSegmentIntersector::NO_LIMIT); osgUtil::IntersectionVisitor visitor(intersector); - if (dropMode == Terrain) visitor.setTraversalMask(SceneUtil::Mask_Terrain); - if (dropMode == Collision) visitor.setTraversalMask(SceneUtil::Mask_Terrain | SceneUtil::Mask_EditorReference); + if (dropMode == Terrain) + visitor.setTraversalMask(SceneUtil::Mask_Terrain); + if (dropMode == Collision) + visitor.setTraversalMask(SceneUtil::Mask_Terrain | SceneUtil::Mask_EditorReference); mParentNode->accept(visitor); @@ -772,18 +776,19 @@ void CSVRender::InstanceMode::dropSelectedInstancesToTerrain() void CSVRender::InstanceMode::dropSelectedInstancesToCollisionSeparately() { - handleDropMethod(Terrain_sep, "Drop instances to next collision level separately"); + handleDropMethod(TerrainSep, "Drop instances to next collision level separately"); } void CSVRender::InstanceMode::dropSelectedInstancesToTerrainSeparately() { - handleDropMethod(Collision_sep, "Drop instances to terrain level separately"); + handleDropMethod(CollisionSep, "Drop instances to terrain level separately"); } void CSVRender::InstanceMode::handleDropMethod(DropMode dropMode, QString commandMsg) { std::vector > selection = getWorldspaceWidget().getSelection (SceneUtil::Mask_EditorReference); - if (selection.empty()) return; + if (selection.empty()) + return; CSMDoc::Document& document = getWorldspaceWidget().getDocument(); QUndoStack& undoStack = document.getUndoStack(); @@ -803,7 +808,8 @@ void CSVRender::InstanceMode::handleDropMethod(DropMode dropMode, QString comman if (CSVRender::ObjectTag *objectTag = dynamic_cast (tag.get())) { float thisDrop = getDropHeight(dropMode, objectTag->mObject, dropObjectDataHandler.mObjectHeights[counter]); - if (thisDrop < smallestDropHeight) smallestDropHeight = thisDrop; + if (thisDrop < smallestDropHeight) + smallestDropHeight = thisDrop; counter++; } for(osg::ref_ptr tag: selection) @@ -818,8 +824,8 @@ void CSVRender::InstanceMode::handleDropMethod(DropMode dropMode, QString comman } break; - case Terrain_sep: - case Collision_sep: + case TerrainSep: + case CollisionSep: { int counter = 0; for(osg::ref_ptr tag: selection) @@ -831,9 +837,6 @@ void CSVRender::InstanceMode::handleDropMethod(DropMode dropMode, QString comman } } break; - - default: - break; } } @@ -853,7 +856,8 @@ CSVRender::DropObjectDataHandler::DropObjectDataHandler(WorldspaceWidget* worlds objectNodeWithoutGUI->accept(computeBounds); osg::BoundingBox bounds = computeBounds.getBoundingBox(); float boundingBoxOffset = 0.0f; - if (bounds.valid()) boundingBoxOffset = bounds.zMin(); + if (bounds.valid()) + boundingBoxOffset = bounds.zMin(); mObjectHeights.emplace_back(boundingBoxOffset); mOldMasks.emplace_back(objectNodeWithGUI->getNodeMask()); diff --git a/apps/opencs/view/render/instancemode.hpp b/apps/opencs/view/render/instancemode.hpp index b1d5de7fe..84b9e9ee2 100644 --- a/apps/opencs/view/render/instancemode.hpp +++ b/apps/opencs/view/render/instancemode.hpp @@ -37,8 +37,8 @@ namespace CSVRender { Collision, Terrain, - Collision_sep, - Terrain_sep + CollisionSep, + Terrainsep }; CSVWidget::SceneToolMode *mSubMode; From 793ea8566fc62bcd3a9f635a11b77972588c67f9 Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Thu, 19 Mar 2020 12:14:10 +0200 Subject: [PATCH 10/10] Fix typo --- apps/opencs/view/render/instancemode.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/view/render/instancemode.hpp b/apps/opencs/view/render/instancemode.hpp index 84b9e9ee2..beb60aff3 100644 --- a/apps/opencs/view/render/instancemode.hpp +++ b/apps/opencs/view/render/instancemode.hpp @@ -38,7 +38,7 @@ namespace CSVRender Collision, Terrain, CollisionSep, - Terrainsep + TerrainSep }; CSVWidget::SceneToolMode *mSubMode;