From 711dc59f09775120e1e5373145c1cb1435d56727 Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Fri, 28 Feb 2020 13:20:57 +0200 Subject: [PATCH] Implement four different functions for dropping --- apps/opencs/model/prefs/state.cpp | 6 +- apps/opencs/view/render/instancemode.cpp | 139 ++++++++++++++++++----- apps/opencs/view/render/instancemode.hpp | 16 ++- 3 files changed, 124 insertions(+), 37 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,7 +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) +{ + 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 == 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::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; @@ -736,28 +799,42 @@ void CSVRender::InstanceMode::dropSelectedInstances(bool active) 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); - } + 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); }; }