[OpenMW-CS] Cube and sphere instance selection

cherry-pick-c431f31c
Nelsson Huotari 3 years ago committed by psi29a
parent cdf0bc1d8d
commit 313e895912

@ -94,6 +94,7 @@
Feature #2386: Distant Statics in the form of Object Paging
Feature #2404: Levelled List can not be placed into a container
Feature #2686: Timestamps in openmw.log
Feature #3171: OpenMW-CS: Instance drag selection
Feature #4894: Consider actors as obstacles for pathfinding
Feature #5043: Head Bobbing
Feature #5199: Improve Scene Colors

@ -21,7 +21,7 @@ New Features:
- Basics of Collada animations are now supported via osgAnimation plugin (#5456)
New Editor Features:
- ?
- Instance selection modes are now implemented (centred cube, corner-dragged cube, sphere) with four user-configurable actions (select only, add to selection, remove from selection, invert selection) (#3171)
Bug Fixes:
- NiParticleColorModifier in NIF files is now properly handled which solves issues regarding particle effects, e.g., smoke and fire (#1952, #3676)

@ -247,6 +247,15 @@ void CSMPrefs::State::declare()
EnumValues landeditOutsideVisibleCell;
landeditOutsideVisibleCell.add (showAndLandEdit).add (dontLandEdit);
EnumValue SelectOnly ("Select only");
EnumValue SelectAdd ("Add to selection");
EnumValue SelectRemove ("Remove from selection");
EnumValue selectInvert ("Invert selection");
EnumValues primarySelectAction;
primarySelectAction.add (SelectOnly).add (SelectAdd).add (SelectRemove).add (selectInvert);
EnumValues secondarySelectAction;
secondarySelectAction.add (SelectOnly).add (SelectAdd).add (SelectRemove).add (selectInvert);
declareCategory ("3D Scene Editing");
declareInt ("distance", "Drop Distance", 50).
setTooltip ("If an instance drop can not be placed against another object at the "
@ -276,6 +285,12 @@ void CSMPrefs::State::declare()
declareBool ("open-list-view", "Open displays list view", false).
setTooltip ("When opening a reference from the scene view, it will open the"
" instance list view instead of the individual instance record view.");
declareEnum ("primary-select-action", "Action for primary select", SelectOnly).
setTooltip("Selection can be chosen between select only, add to selection, remove from selection and invert selection.").
addValues (primarySelectAction);
declareEnum ("secondary-select-action", "Action for secondary select", SelectAdd).
setTooltip("Selection can be chosen between select only, add to selection, remove from selection and invert selection.").
addValues (secondarySelectAction);
declareCategory ("Key Bindings");

@ -1,5 +1,7 @@
#include "cell.hpp"
#include <math.h>
#include <osg/PositionAttitudeTransform>
#include <osg/Geode>
#include <osg/Geometry>
@ -25,6 +27,7 @@
#include "pathgrid.hpp"
#include "terrainstorage.hpp"
#include "object.hpp"
#include "instancedragmodes.hpp"
namespace CSVRender
{
@ -496,6 +499,50 @@ void CSVRender::Cell::selectAllWithSameParentId (int elementMask)
}
}
void CSVRender::Cell::handleSelectDrag(Object* object, DragMode dragMode)
{
if (dragMode == DragMode_Select_Only || dragMode == DragMode_Select_Add)
object->setSelected(true);
else if (dragMode == DragMode_Select_Remove)
object->setSelected(false);
else if (dragMode == DragMode_Select_Invert)
object->setSelected (!object->getSelected());
}
void CSVRender::Cell::selectInsideCube(const osg::Vec3d& pointA, const osg::Vec3d& pointB, DragMode dragMode)
{
for (auto& object : mObjects)
{
if (dragMode == DragMode_Select_Only) object.second->setSelected (false);
if ( ( object.second->getPosition().pos[0] > pointA[0] && object.second->getPosition().pos[0] < pointB[0] ) ||
( object.second->getPosition().pos[0] > pointB[0] && object.second->getPosition().pos[0] < pointA[0] ))
{
if ( ( object.second->getPosition().pos[1] > pointA[1] && object.second->getPosition().pos[1] < pointB[1] ) ||
( object.second->getPosition().pos[1] > pointB[1] && object.second->getPosition().pos[1] < pointA[1] ))
{
if ( ( object.second->getPosition().pos[2] > pointA[2] && object.second->getPosition().pos[2] < pointB[2] ) ||
( object.second->getPosition().pos[2] > pointB[2] && object.second->getPosition().pos[2] < pointA[2] ))
handleSelectDrag(object.second, dragMode);
}
}
}
}
void CSVRender::Cell::selectWithinDistance(const osg::Vec3d& point, float distance, DragMode dragMode)
{
for (auto& object : mObjects)
{
if (dragMode == DragMode_Select_Only) object.second->setSelected (false);
float distanceFromObject = (point - object.second->getPosition().asVec3()).length();
if (distanceFromObject < distance) handleSelectDrag(object.second, dragMode);
}
}
void CSVRender::Cell::setCellArrows (int mask)
{
for (int i=0; i<4; ++i)

@ -10,6 +10,7 @@
#include "../../model/world/cellcoordinates.hpp"
#include "terrainstorage.hpp"
#include "instancedragmodes.hpp"
class QModelIndex;
@ -152,6 +153,12 @@ namespace CSVRender
// already selected
void selectAllWithSameParentId (int elementMask);
void handleSelectDrag(Object* object, DragMode dragMode);
void selectInsideCube(const osg::Vec3d& pointA, const osg::Vec3d& pointB, DragMode dragMode);
void selectWithinDistance(const osg::Vec3d& pointA, float distance, DragMode dragMode);
void setCellArrows (int mask);
/// \brief Set marker for this cell.

@ -0,0 +1,18 @@
#ifndef CSV_WIDGET_INSTANCEDRAGMODES_H
#define CSV_WIDGET_INSTANCEDRAGMODES_H
namespace CSVRender
{
enum DragMode
{
DragMode_None,
DragMode_Move,
DragMode_Rotate,
DragMode_Scale,
DragMode_Select_Only,
DragMode_Select_Add,
DragMode_Select_Remove,
DragMode_Select_Invert
};
}
#endif

@ -96,6 +96,33 @@ osg::Vec3f CSVRender::InstanceMode::getScreenCoords(const osg::Vec3f& pos)
return pos * combined;
}
osg::Vec3f CSVRender::InstanceMode::getProjectionSpaceCoords(const osg::Vec3f& pos)
{
osg::Matrix viewMatrix = getWorldspaceWidget().getCamera()->getViewMatrix();
osg::Matrix projMatrix = getWorldspaceWidget().getCamera()->getProjectionMatrix();
osg::Matrix combined = viewMatrix * projMatrix;
return pos * combined;
}
osg::Vec3f CSVRender::InstanceMode::getMousePlaneCoords(const QPoint& point, const osg::Vec3d& dragStart)
{
osg::Matrix viewMatrix;
viewMatrix.invert(getWorldspaceWidget().getCamera()->getViewMatrix());
osg::Matrix projMatrix;
projMatrix.invert(getWorldspaceWidget().getCamera()->getProjectionMatrix());
osg::Matrix combined = projMatrix * viewMatrix;
/* calculate viewport normalized coordinates
note: is there a reason to use getCamera()->getViewport()->computeWindowMatrix() instead? */
float x = (point.x() * 2) / getWorldspaceWidget().getCamera()->getViewport()->width() - 1.0f;
float y = 1.0f - (point.y() * 2) / getWorldspaceWidget().getCamera()->getViewport()->height();
osg::Vec3f mousePlanePoint = osg::Vec3f(x, y, dragStart.z()) * combined;
return mousePlanePoint;
}
CSVRender::InstanceMode::InstanceMode (WorldspaceWidget *worldspaceWidget, osg::ref_ptr<osg::Group> parentNode, QWidget *parent)
: EditMode (worldspaceWidget, QIcon (":scenetoolbar/editing-instance"), Mask_Reference | Mask_Terrain, "Instance editing",
parent), mSubMode (nullptr), mSubModeId ("move"), mSelectionMode (nullptr), mDragMode (DragMode_None),
@ -146,7 +173,7 @@ void CSVRender::InstanceMode::activate (CSVWidget::SceneToolbar *toolbar)
}
if (!mSelectionMode)
mSelectionMode = new InstanceSelectionMode (toolbar, getWorldspaceWidget());
mSelectionMode = new InstanceSelectionMode (toolbar, getWorldspaceWidget(), mParentNode);
mDragMode = DragMode_None;
@ -322,6 +349,42 @@ bool CSVRender::InstanceMode::secondaryEditStartDrag (const QPoint& pos)
return false;
}
bool CSVRender::InstanceMode::primarySelectStartDrag (const QPoint& pos)
{
if (mDragMode!=DragMode_None || mLocked)
return false;
std::string primarySelectAction = CSMPrefs::get()["3D Scene Editing"]["primary-select-action"].toString();
if ( primarySelectAction == "Select only" ) mDragMode = DragMode_Select_Only;
else if ( primarySelectAction == "Add to selection" ) mDragMode = DragMode_Select_Add;
else if ( primarySelectAction == "Remove from selection" ) mDragMode = DragMode_Select_Remove;
else if ( primarySelectAction == "Invert selection" ) mDragMode = DragMode_Select_Invert;
WorldspaceHitResult hit = getWorldspaceWidget().mousePick (pos, getWorldspaceWidget().getInteractionMask());
mSelectionMode->setDragStart(hit.worldPos);
return true;
}
bool CSVRender::InstanceMode::secondarySelectStartDrag (const QPoint& pos)
{
if (mDragMode!=DragMode_None || mLocked)
return false;
std::string secondarySelectAction = CSMPrefs::get()["3D Scene Editing"]["secondary-select-action"].toString();
if ( secondarySelectAction == "Select only" ) mDragMode = DragMode_Select_Only;
else if ( secondarySelectAction == "Add to selection" ) mDragMode = DragMode_Select_Add;
else if ( secondarySelectAction == "Remove from selection" ) mDragMode = DragMode_Select_Remove;
else if ( secondarySelectAction == "Invert selection" ) mDragMode = DragMode_Select_Invert;
WorldspaceHitResult hit = getWorldspaceWidget().mousePick (pos, getWorldspaceWidget().getInteractionMask());
mSelectionMode->setDragStart(hit.worldPos);
return true;
}
void CSVRender::InstanceMode::drag (const QPoint& pos, int diffX, int diffY, double speedFactor)
{
osg::Vec3f offset;
@ -432,6 +495,24 @@ void CSVRender::InstanceMode::drag (const QPoint& pos, int diffX, int diffY, dou
// Only uniform scaling is currently supported
offset = osg::Vec3f(scale, scale, scale);
}
else if (mSelectionMode->getCurrentId() == "cube-centre")
{
osg::Vec3f mousePlanePoint = getMousePlaneCoords(pos, getProjectionSpaceCoords(mSelectionMode->getDragStart()));
mSelectionMode->drawSelectionCubeCentre (mousePlanePoint);
return;
}
else if (mSelectionMode->getCurrentId() == "cube-corner")
{
osg::Vec3f mousePlanePoint = getMousePlaneCoords(pos, getProjectionSpaceCoords(mSelectionMode->getDragStart()));
mSelectionMode->drawSelectionCubeCorner (mousePlanePoint);
return;
}
else if (mSelectionMode->getCurrentId() == "sphere")
{
osg::Vec3f mousePlanePoint = getMousePlaneCoords(pos, getProjectionSpaceCoords(mSelectionMode->getDragStart()));
mSelectionMode->drawSelectionSphere (mousePlanePoint);
return;
}
// Apply
for (std::vector<osg::ref_ptr<TagBase> >::iterator iter (selection.begin()); iter!=selection.end(); ++iter)
@ -495,6 +576,22 @@ void CSVRender::InstanceMode::dragCompleted(const QPoint& pos)
case DragMode_Move: description = "Move Instances"; break;
case DragMode_Rotate: description = "Rotate Instances"; break;
case DragMode_Scale: description = "Scale Instances"; break;
case DragMode_Select_Only :
handleSelectDrag(pos);
return;
break;
case DragMode_Select_Add :
handleSelectDrag(pos);
return;
break;
case DragMode_Select_Remove :
handleSelectDrag(pos);
return;
break;
case DragMode_Select_Invert :
handleSelectDrag(pos);
return;
break;
case DragMode_None: break;
}
@ -680,6 +777,13 @@ void CSVRender::InstanceMode::subModeChanged (const std::string& id)
getWorldspaceWidget().setSubMode (getSubModeFromId (id), Mask_Reference);
}
void CSVRender::InstanceMode::handleSelectDrag(const QPoint& pos)
{
osg::Vec3f mousePlanePoint = getMousePlaneCoords(pos, getProjectionSpaceCoords(mSelectionMode->getDragStart()));
mSelectionMode->dragEnded (mousePlanePoint, mDragMode);
mDragMode = DragMode_None;
}
void CSVRender::InstanceMode::deleteSelectedInstances(bool active)
{
std::vector<osg::ref_ptr<TagBase> > selection = getWorldspaceWidget().getSelection (Mask_Reference);

@ -9,6 +9,7 @@
#include <osg/Vec3f>
#include "editmode.hpp"
#include "instancedragmodes.hpp"
namespace CSVWidget
{
@ -25,14 +26,6 @@ namespace CSVRender
{
Q_OBJECT
enum DragMode
{
DragMode_None,
DragMode_Move,
DragMode_Rotate,
DragMode_Scale
};
enum DropMode
{
Collision,
@ -57,6 +50,9 @@ namespace CSVRender
osg::Vec3f getSelectionCenter(const std::vector<osg::ref_ptr<TagBase> >& selection) const;
osg::Vec3f getScreenCoords(const osg::Vec3f& pos);
osg::Vec3f getProjectionSpaceCoords(const osg::Vec3f& pos);
osg::Vec3f getMousePlaneCoords(const QPoint& point, const osg::Vec3d& dragStart);
void handleSelectDrag(const QPoint& pos);
void dropInstance(DropMode dropMode, CSVRender::Object* object, float objectHeight);
float getDropHeight(DropMode dropMode, CSVRender::Object* object, float objectHeight);
@ -84,6 +80,10 @@ namespace CSVRender
bool secondaryEditStartDrag (const QPoint& pos) override;
bool primarySelectStartDrag(const QPoint& pos) override;
bool secondarySelectStartDrag(const QPoint& pos) override;
void drag (const QPoint& pos, int diffX, int diffY, double speedFactor) override;
void dragCompleted(const QPoint& pos) override;

@ -2,17 +2,24 @@
#include <QMenu>
#include <QAction>
#include <QPoint>
#include <osg/Group>
#include <osg/PositionAttitudeTransform>
#include <osg/ref_ptr>
#include <osg/Vec3d>
#include "../../model/world/idtable.hpp"
#include "../../model/world/commands.hpp"
#include "instancedragmodes.hpp"
#include "worldspacewidget.hpp"
#include "object.hpp"
namespace CSVRender
{
InstanceSelectionMode::InstanceSelectionMode(CSVWidget::SceneToolbar* parent, WorldspaceWidget& worldspaceWidget)
: SelectionMode(parent, worldspaceWidget, Mask_Reference)
InstanceSelectionMode::InstanceSelectionMode(CSVWidget::SceneToolbar* parent, WorldspaceWidget& worldspaceWidget, osg::Group *cellNode)
: SelectionMode(parent, worldspaceWidget, Mask_Reference), mParentNode(cellNode)
{
mSelectSame = new QAction("Extend selection to instances with same object ID", this);
mDeleteSelection = new QAction("Delete selected instances", this);
@ -21,6 +28,342 @@ namespace CSVRender
connect(mDeleteSelection, SIGNAL(triggered()), this, SLOT(deleteSelection()));
}
InstanceSelectionMode::~InstanceSelectionMode()
{
mParentNode->removeChild(mBaseNode);
}
void InstanceSelectionMode::setDragStart(const osg::Vec3d& dragStart)
{
mDragStart = dragStart;
}
const osg::Vec3d& InstanceSelectionMode::getDragStart()
{
return mDragStart;
}
void InstanceSelectionMode::dragEnded(const osg::Vec3d& dragEndPoint, DragMode dragMode)
{
float dragDistance = (mDragStart - dragEndPoint).length();
if (mBaseNode) mParentNode->removeChild (mBaseNode);
if (getCurrentId() == "cube-centre")
{
osg::Vec3d pointA(mDragStart[0] - dragDistance, mDragStart[1] - dragDistance, mDragStart[2] - dragDistance);
osg::Vec3d pointB(mDragStart[0] + dragDistance, mDragStart[1] + dragDistance, mDragStart[2] + dragDistance);
getWorldspaceWidget().selectInsideCube(pointA, pointB, dragMode);
}
else if (getCurrentId() == "cube-corner")
{
getWorldspaceWidget().selectInsideCube(mDragStart, dragEndPoint, dragMode);
}
else if (getCurrentId() == "sphere")
{
getWorldspaceWidget().selectWithinDistance(mDragStart, dragDistance, dragMode);
}
}
void InstanceSelectionMode::drawSelectionCubeCentre(const osg::Vec3f& mousePlanePoint)
{
float dragDistance = (mDragStart - mousePlanePoint).length();
drawSelectionCube(mDragStart, dragDistance);
}
void InstanceSelectionMode::drawSelectionCubeCorner(const osg::Vec3f& mousePlanePoint)
{
drawSelectionBox(mDragStart, mousePlanePoint);
}
void InstanceSelectionMode::drawSelectionBox(const osg::Vec3d& pointA, const osg::Vec3d& pointB)
{
if (mBaseNode) mParentNode->removeChild (mBaseNode);
mBaseNode = new osg::PositionAttitudeTransform;
mBaseNode->setPosition(pointA);
osg::ref_ptr<osg::Geometry> geometry (new osg::Geometry);
osg::Vec3Array *vertices = new osg::Vec3Array;
vertices->push_back (osg::Vec3f (0.0f, 0.0f, 0.0f));
vertices->push_back (osg::Vec3f (0.0f, 0.0f, pointB[2] - pointA[2]));
vertices->push_back (osg::Vec3f (0.0f, pointB[1] - pointA[1], 0.0f));
vertices->push_back (osg::Vec3f (0.0f, pointB[1] - pointA[1], pointB[2] - pointA[2]));
vertices->push_back (osg::Vec3f (pointB[0] - pointA[0], 0.0f, 0.0f));
vertices->push_back (osg::Vec3f (pointB[0] - pointA[0], 0.0f, pointB[2] - pointA[2]));
vertices->push_back (osg::Vec3f (pointB[0] - pointA[0], pointB[1] - pointA[1], 0.0f));
vertices->push_back (osg::Vec3f (pointB[0] - pointA[0], pointB[1] - pointA[1], pointB[2] - pointA[2]));
geometry->setVertexArray (vertices);
osg::DrawElementsUShort *primitives = new osg::DrawElementsUShort (osg::PrimitiveSet::TRIANGLES, 0);
// top
primitives->push_back (2);
primitives->push_back (1);
primitives->push_back (0);
primitives->push_back (3);
primitives->push_back (1);
primitives->push_back (2);
// bottom
primitives->push_back (4);
primitives->push_back (5);
primitives->push_back (6);
primitives->push_back (6);
primitives->push_back (5);
primitives->push_back (7);
// sides
primitives->push_back (1);
primitives->push_back (4);
primitives->push_back (0);
primitives->push_back (4);
primitives->push_back (1);
primitives->push_back (5);
primitives->push_back (4);
primitives->push_back (2);
primitives->push_back (0);
primitives->push_back (6);
primitives->push_back (2);
primitives->push_back (4);
primitives->push_back (6);
primitives->push_back (3);
primitives->push_back (2);
primitives->push_back (7);
primitives->push_back (3);
primitives->push_back (6);
primitives->push_back (1);
primitives->push_back (3);
primitives->push_back (5);
primitives->push_back (5);
primitives->push_back (3);
primitives->push_back (7);
geometry->addPrimitiveSet (primitives);
osg::Vec4Array *colours = new osg::Vec4Array;
colours->push_back (osg::Vec4f (0.3f, 0.3f, 0.5f, 0.2f));
colours->push_back (osg::Vec4f (0.9f, 0.9f, 1.0f, 0.2f));
colours->push_back (osg::Vec4f (0.3f, 0.3f, 0.4f, 0.2f));
colours->push_back (osg::Vec4f (0.9f, 0.9f, 1.0f, 0.2f));
colours->push_back (osg::Vec4f (0.3f, 0.3f, 0.4f, 0.2f));
colours->push_back (osg::Vec4f (0.9f, 0.9f, 1.0f, 0.2f));
colours->push_back (osg::Vec4f (0.3f, 0.3f, 0.4f, 0.2f));
colours->push_back (osg::Vec4f (0.9f, 0.9f, 1.0f, 0.2f));
geometry->setColorArray (colours, osg::Array::BIND_PER_VERTEX);
geometry->getOrCreateStateSet()->setMode (GL_LIGHTING, osg::StateAttribute::OFF);
geometry->getOrCreateStateSet()->setMode (GL_BLEND, osg::StateAttribute::ON);
geometry->getOrCreateStateSet()->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);
geometry->getOrCreateStateSet()->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
mBaseNode->addChild (geometry);
mParentNode->addChild(mBaseNode);
}
void InstanceSelectionMode::drawSelectionCube(const osg::Vec3d& point, float radius)
{
if (mBaseNode) mParentNode->removeChild (mBaseNode);
mBaseNode = new osg::PositionAttitudeTransform;
mBaseNode->setPosition(point);
osg::ref_ptr<osg::Geometry> geometry (new osg::Geometry);
osg::Vec3Array *vertices = new osg::Vec3Array;
for (int i = 0; i < 2; ++i)
{
float height = i ? -radius : radius;
vertices->push_back (osg::Vec3f (height, -radius, -radius));
vertices->push_back (osg::Vec3f (height, -radius, radius));
vertices->push_back (osg::Vec3f (height, radius, -radius));
vertices->push_back (osg::Vec3f (height, radius, radius));
}
geometry->setVertexArray (vertices);
osg::DrawElementsUShort *primitives = new osg::DrawElementsUShort (osg::PrimitiveSet::TRIANGLES, 0);
// top
primitives->push_back (2);
primitives->push_back (1);
primitives->push_back (0);
primitives->push_back (3);
primitives->push_back (1);
primitives->push_back (2);
// bottom
primitives->push_back (4);
primitives->push_back (5);
primitives->push_back (6);
primitives->push_back (6);
primitives->push_back (5);
primitives->push_back (7);
// sides
primitives->push_back (1);
primitives->push_back (4);
primitives->push_back (0);
primitives->push_back (4);
primitives->push_back (1);
primitives->push_back (5);
primitives->push_back (4);
primitives->push_back (2);
primitives->push_back (0);
primitives->push_back (6);
primitives->push_back (2);
primitives->push_back (4);
primitives->push_back (6);
primitives->push_back (3);
primitives->push_back (2);
primitives->push_back (7);
primitives->push_back (3);
primitives->push_back (6);
primitives->push_back (1);
primitives->push_back (3);
primitives->push_back (5);
primitives->push_back (5);
primitives->push_back (3);
primitives->push_back (7);
geometry->addPrimitiveSet (primitives);
osg::Vec4Array *colours = new osg::Vec4Array;
colours->push_back (osg::Vec4f (0.3f, 0.3f, 0.5f, 0.2f));
colours->push_back (osg::Vec4f (0.9f, 0.9f, 1.0f, 0.2f));
colours->push_back (osg::Vec4f (0.3f, 0.3f, 0.4f, 0.2f));
colours->push_back (osg::Vec4f (0.9f, 0.9f, 1.0f, 0.2f));
colours->push_back (osg::Vec4f (0.3f, 0.3f, 0.4f, 0.2f));
colours->push_back (osg::Vec4f (0.9f, 0.9f, 1.0f, 0.2f));
colours->push_back (osg::Vec4f (0.3f, 0.3f, 0.4f, 0.2f));
colours->push_back (osg::Vec4f (0.9f, 0.9f, 1.0f, 0.2f));
geometry->setColorArray (colours, osg::Array::BIND_PER_VERTEX);
geometry->getOrCreateStateSet()->setMode (GL_LIGHTING, osg::StateAttribute::OFF);
geometry->getOrCreateStateSet()->setMode (GL_BLEND, osg::StateAttribute::ON);
geometry->getOrCreateStateSet()->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);
geometry->getOrCreateStateSet()->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
mBaseNode->addChild (geometry);
mParentNode->addChild(mBaseNode);
}
void InstanceSelectionMode::drawSelectionSphere(const osg::Vec3f& mousePlanePoint)
{
float dragDistance = (mDragStart - mousePlanePoint).length();
drawSelectionSphere(mDragStart, dragDistance);
}
void InstanceSelectionMode::drawSelectionSphere(const osg::Vec3d& point, float radius)
{
if (mBaseNode) mParentNode->removeChild (mBaseNode);
mBaseNode = new osg::PositionAttitudeTransform;
mBaseNode->setPosition(point);
osg::ref_ptr<osg::Geometry> geometry (new osg::Geometry);
osg::Vec3Array *vertices = new osg::Vec3Array;
int resolution = 32;
float radiusPerResolution = radius / resolution;
float reciprocalResolution = 1.0f / resolution;
float doubleReciprocalRes = reciprocalResolution * 2;
osg::Vec4Array *colours = new osg::Vec4Array;
for (float i = 0.0; i <= resolution; i += 2)
{
float iShifted = (static_cast<float>(i) - resolution / 2.0f); // i - 16 = -16 ... 16
float xPercentile = iShifted * doubleReciprocalRes;
float x = xPercentile * radius;
float thisRadius = sqrt (radius * radius - x * x);
//the next row
float iShifted2 = (static_cast<float>(i + 1) - resolution / 2.0f);
float xPercentile2 = iShifted2 * doubleReciprocalRes;
float x2 = xPercentile2 * radius;
float thisRadius2 = sqrt (radius * radius - x2 * x2);
for (int j = 0; j < resolution; ++j)
{
float vertexX = thisRadius * sin(j * reciprocalResolution * osg::PI * 2);
float vertexY = i * radiusPerResolution * 2 - radius;
float vertexZ = thisRadius * cos(j * reciprocalResolution * osg::PI * 2);
float heightPercentage = (vertexZ + radius) / (radius * 2);
vertices->push_back (osg::Vec3f (vertexX, vertexY, vertexZ));
colours->push_back (osg::Vec4f (heightPercentage, heightPercentage, heightPercentage, 0.3f));
float vertexNextRowX = thisRadius2 * sin(j * reciprocalResolution * osg::PI * 2);
float vertexNextRowY = (i + 1) * radiusPerResolution * 2 - radius;
float vertexNextRowZ = thisRadius2 * cos(j * reciprocalResolution * osg::PI * 2);
float heightPercentageNextRow = (vertexZ + radius) / (radius * 2);
vertices->push_back (osg::Vec3f (vertexNextRowX, vertexNextRowY, vertexNextRowZ));
colours->push_back (osg::Vec4f (heightPercentageNextRow, heightPercentageNextRow, heightPercentageNextRow, 0.3f));
}
}
geometry->setVertexArray (vertices);
osg::DrawElementsUShort *primitives = new osg::DrawElementsUShort (osg::PrimitiveSet::TRIANGLE_STRIP, 0);
for (int i = 0; i < resolution; ++i)
{
//Even
for (int j = 0; j < resolution * 2; ++j)
{
if (i * resolution * 2 + j > static_cast<int>(vertices->size()) - 1) continue;
primitives->push_back (i * resolution * 2 + j);
}
if (i * resolution * 2 > static_cast<int>(vertices->size()) - 1) continue;
primitives->push_back (i * resolution * 2);
primitives->push_back (i * resolution * 2 + 1);
//Odd
for (int j = 1; j < resolution * 2 - 2; j += 2)
{
if ((i + 1) * resolution * 2 + j - 1 > static_cast<int>(vertices->size()) - 1) continue;
primitives->push_back ((i + 1) * resolution * 2 + j - 1);
primitives->push_back (i * resolution * 2 + j + 2);
}
if ((i + 2) * resolution * 2 - 2 > static_cast<int>(vertices->size()) - 1) continue;
primitives->push_back ((i + 2) * resolution * 2 - 2);
primitives->push_back (i * resolution * 2 + 1);
primitives->push_back ((i + 1) * resolution * 2);
}
geometry->addPrimitiveSet (primitives);
geometry->setColorArray (colours, osg::Array::BIND_PER_VERTEX);
geometry->getOrCreateStateSet()->setMode (GL_LIGHTING, osg::StateAttribute::OFF);
geometry->getOrCreateStateSet()->setMode (GL_BLEND, osg::StateAttribute::ON);
geometry->getOrCreateStateSet()->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);
geometry->getOrCreateStateSet()->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
mBaseNode->addChild (geometry);
mParentNode->addChild(mBaseNode);
}
bool InstanceSelectionMode::createContextMenu(QMenu* menu)
{
if (menu)

@ -1,7 +1,13 @@
#ifndef CSV_RENDER_INSTANCE_SELECTION_MODE_H
#define CSV_RENDER_INSTANCE_SELECTION_MODE_H
#include <QPoint>
#include <osg/PositionAttitudeTransform>
#include <osg/Vec3d>
#include "selectionmode.hpp"
#include "instancedragmodes.hpp"
namespace CSVRender
{
@ -11,8 +17,25 @@ namespace CSVRender
public:
InstanceSelectionMode(CSVWidget::SceneToolbar* parent, WorldspaceWidget& worldspaceWidget);
InstanceSelectionMode(CSVWidget::SceneToolbar* parent, WorldspaceWidget& worldspaceWidget, osg::Group *cellNode);
~InstanceSelectionMode();
/// Store the worldspace-coordinate when drag begins
void setDragStart(const osg::Vec3d& dragStart);
/// Store the worldspace-coordinate when drag begins
const osg::Vec3d& getDragStart();
/// Store the screen-coordinate when drag begins
void setScreenDragStart(const QPoint& dragStartPoint);
/// Apply instance selection changes
void dragEnded(const osg::Vec3d& dragEndPoint, DragMode dragMode);
void drawSelectionCubeCentre(const osg::Vec3f& mousePlanePoint );
void drawSelectionCubeCorner(const osg::Vec3f& mousePlanePoint );
void drawSelectionSphere(const osg::Vec3f& mousePlanePoint );
protected:
/// Add context menu items to \a menu.
@ -25,8 +48,15 @@ namespace CSVRender
private:
void drawSelectionBox(const osg::Vec3d& pointA, const osg::Vec3d& pointB);
void drawSelectionCube(const osg::Vec3d& point, float radius);
void drawSelectionSphere(const osg::Vec3d& point, float radius);
QAction* mDeleteSelection;
QAction* mSelectSame;
osg::Vec3d mDragStart;
osg::Group* mParentNode;
osg::ref_ptr<osg::PositionAttitudeTransform> mBaseNode;
private slots:

@ -768,6 +768,22 @@ void CSVRender::PagedWorldspaceWidget::selectAllWithSameParentId (int elementMas
flagAsModified();
}
void CSVRender::PagedWorldspaceWidget::selectInsideCube(const osg::Vec3d& pointA, const osg::Vec3d& pointB, DragMode dragMode)
{
for (auto& cell : mCells)
{
cell.second->selectInsideCube (pointA, pointB, dragMode);
}
}
void CSVRender::PagedWorldspaceWidget::selectWithinDistance(const osg::Vec3d& point, float distance, DragMode dragMode)
{
for (auto& cell : mCells)
{
cell.second->selectWithinDistance (point, distance, dragMode);
}
}
std::string CSVRender::PagedWorldspaceWidget::getCellId (const osg::Vec3f& point) const
{
CSMWorld::CellCoordinates cellCoordinates (

@ -7,6 +7,7 @@
#include "worldspacewidget.hpp"
#include "cell.hpp"
#include "instancedragmodes.hpp"
namespace CSVWidget
{
@ -120,6 +121,10 @@ namespace CSVRender
/// \param elementMask Elements to be affected by the select operation
void selectAllWithSameParentId (int elementMask) override;
void selectInsideCube(const osg::Vec3d& pointA, const osg::Vec3d& pointB, DragMode dragMode) override;
void selectWithinDistance(const osg::Vec3d& point, float distance, DragMode dragMode) override;
std::string getCellId (const osg::Vec3f& point) const override;
Cell* getCell(const osg::Vec3d& point) const override;

@ -15,30 +15,27 @@ namespace CSVRender
{
addButton(":scenetoolbar/selection-mode-cube", "cube-centre",
"Centred cube"
"<ul><li>Drag with {scene-select-primary} (make instances the selection) or {scene-select-secondary} "
"(invert selection state) from the centre of the selection cube outwards</li>"
"<ul><li>Drag with {scene-select-primary} for primary select or {scene-select-secondary} for secondary select "
"from the centre of the selection cube outwards.</li>"
"<li>The selection cube is aligned to the word space axis</li>"
"<li>If context selection mode is enabled, a drag with {scene-edit-primary} or {scene-edit-secondary} not "
"starting on an instance will have the same effect</li>"
"</ul>"
"<font color=Red>Not implemented yet</font color>");
"</ul>");
addButton(":scenetoolbar/selection-mode-cube-corner", "cube-corner",
"Cube corner to corner"
"<ul><li>Drag with {scene-select-primary} (make instances the selection) or {scene-select-secondary} "
"(invert selection state) from one corner of the selection cube to the opposite corner</li>"
"<ul><li>Drag with {scene-select-primary} for primary select or {scene-select-secondary} for secondary select "
"from one corner of the selection cube to the opposite corner</li>"
"<li>The selection cube is aligned to the word space axis</li>"
"<li>If context selection mode is enabled, a drag with {scene-edit-primary} or {scene-edit-secondary} not "
"starting on an instance will have the same effect</li>"
"</ul>"
"<font color=Red>Not implemented yet</font color>");
"</ul>");
addButton(":scenetoolbar/selection-mode-cube-sphere", "sphere",
"Centred sphere"
"<ul><li>Drag with {scene-select-primary} (make instances the selection) or {scene-select-secondary} "
"(invert selection state) from the centre of the selection sphere outwards</li>"
"<ul><li>Drag with {scene-select-primary} for primary select or {scene-select-secondary} for secondary select "
"from the centre of the selection sphere outwards</li>"
"<li>If context selection mode is enabled, a drag with {scene-edit-primary} or {scene-edit-secondary} not "
"starting on an instance will have the same effect</li>"
"</ul>"
"<font color=Red>Not implemented yet</font color>");
"</ul>");
mSelectAll = new QAction("Select all", this);
mDeselectAll = new QAction("Clear selection", this);

@ -140,6 +140,16 @@ void CSVRender::UnpagedWorldspaceWidget::selectAllWithSameParentId (int elementM
flagAsModified();
}
void CSVRender::UnpagedWorldspaceWidget::selectInsideCube(const osg::Vec3d& pointA, const osg::Vec3d& pointB, DragMode dragMode)
{
mCell->selectInsideCube (pointA, pointB, dragMode);
}
void CSVRender::UnpagedWorldspaceWidget::selectWithinDistance(const osg::Vec3d& point, float distance, DragMode dragMode)
{
mCell->selectWithinDistance (point, distance, dragMode);
}
std::string CSVRender::UnpagedWorldspaceWidget::getCellId (const osg::Vec3f& point) const
{
return mCellId;

@ -60,6 +60,10 @@ namespace CSVRender
/// \param elementMask Elements to be affected by the select operation
void selectAllWithSameParentId (int elementMask) override;
void selectInsideCube(const osg::Vec3d& pointA, const osg::Vec3d& pointB, DragMode dragMode) override;
void selectWithinDistance(const osg::Vec3d& point, float distance, DragMode dragMode) override;
std::string getCellId (const osg::Vec3f& point) const override;
Cell* getCell(const osg::Vec3d& point) const override;

@ -7,6 +7,7 @@
#include "../../model/doc/document.hpp"
#include "../../model/world/tablemimedata.hpp"
#include "instancedragmodes.hpp"
#include "scenewidget.hpp"
#include "mask.hpp"
@ -160,6 +161,10 @@ namespace CSVRender
/// \param elementMask Elements to be affected by the select operation
virtual void selectAllWithSameParentId (int elementMask) = 0;
virtual void selectInsideCube(const osg::Vec3d& pointA, const osg::Vec3d& pointB, DragMode dragMode) = 0;
virtual void selectWithinDistance(const osg::Vec3d& point, float distance, DragMode dragMode) = 0;
/// Return the next intersection with scene elements matched by
/// \a interactionMask based on \a localPos and the camera vector.
/// If there is no such intersection, instead a point "in front" of \a localPos will be

Loading…
Cancel
Save