mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-16 18:19:55 +00:00
[OpenMW-CS] Cube and sphere instance selection
This commit is contained in:
parent
cdf0bc1d8d
commit
313e895912
16 changed files with 627 additions and 25 deletions
|
@ -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.
|
||||
|
|
18
apps/opencs/view/render/instancedragmodes.hpp
Normal file
18
apps/opencs/view/render/instancedragmodes.hpp
Normal file
|
@ -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…
Reference in a new issue