instance moving via drag in 3D scenes

move
Marc Zinnschlag 9 years ago
parent b5dc3953a4
commit dececf6c38

@ -85,7 +85,7 @@ opencs_units (view/widget
opencs_units (view/render
scenewidget worldspacewidget pagedworldspacewidget unpagedworldspacewidget
previewwidget editmode instancemode instanceselectionmode
previewwidget editmode instancemode instanceselectionmode instancemovemode
)
opencs_units_noqt (view/render

@ -338,3 +338,16 @@ std::vector<osg::ref_ptr<CSVRender::TagBase> > CSVRender::Cell::getSelection (un
return result;
}
std::vector<osg::ref_ptr<CSVRender::TagBase> > CSVRender::Cell::getEdited (unsigned int elementMask) const
{
std::vector<osg::ref_ptr<TagBase> > result;
if (elementMask & Mask_Reference)
for (std::map<std::string, Object *>::const_iterator iter (mObjects.begin());
iter!=mObjects.end(); ++iter)
if (iter->second->isEdited())
result.push_back (iter->second->getTag());
return result;
}

@ -116,6 +116,8 @@ namespace CSVRender
bool isDeleted() const;
std::vector<osg::ref_ptr<TagBase> > getSelection (unsigned int elementMask) const;
std::vector<osg::ref_ptr<TagBase> > getEdited (unsigned int elementMask) const;
};
}

@ -18,10 +18,11 @@
#include "worldspacewidget.hpp"
#include "pagedworldspacewidget.hpp"
#include "instanceselectionmode.hpp"
#include "instancemovemode.hpp"
CSVRender::InstanceMode::InstanceMode (WorldspaceWidget *worldspaceWidget, QWidget *parent)
: EditMode (worldspaceWidget, QIcon (":placeholder"), Mask_Reference, "Instance editing",
parent), mSubMode (0), mSelectionMode (0)
parent), mSubMode (0), mSelectionMode (0), mDragMode (DragMode_None)
{
}
@ -30,12 +31,7 @@ void CSVRender::InstanceMode::activate (CSVWidget::SceneToolbar *toolbar)
if (!mSubMode)
{
mSubMode = new CSVWidget::SceneToolMode (toolbar, "Edit Sub-Mode");
mSubMode->addButton (":placeholder", "move",
"Move selected instances"
"<ul><li>Use primary edit to move instances around freely</li>"
"<li>Use secondary edit to move instances around within the grid</li>"
"</ul>"
"<font color=Red>Not implemented yet</font color>");
mSubMode->addButton (new InstanceMoveMode (this), "move");
mSubMode->addButton (":placeholder", "rotate",
"Rotate selected instances"
"<ul><li>Use primary edit to rotate instances freely</li>"
@ -53,6 +49,8 @@ void CSVRender::InstanceMode::activate (CSVWidget::SceneToolbar *toolbar)
if (!mSelectionMode)
mSelectionMode = new InstanceSelectionMode (toolbar, getWorldspaceWidget());
mDragMode = DragMode_None;
EditMode::activate (toolbar);
toolbar->addTool (mSubMode);
@ -120,6 +118,154 @@ void CSVRender::InstanceMode::secondarySelectPressed (osg::ref_ptr<TagBase> tag)
}
}
bool CSVRender::InstanceMode::primaryEditStartDrag (osg::ref_ptr<TagBase> tag)
{
if (mDragMode!=DragMode_None)
return false;
if (tag && CSMPrefs::get()["3D Scene Input"]["context-select"].isTrue())
{
getWorldspaceWidget().clearSelection (Mask_Reference);
if (CSVRender::ObjectTag *objectTag = dynamic_cast<CSVRender::ObjectTag *> (tag.get()))
{
CSVRender::Object* object = objectTag->mObject;
object->setSelected (true);
}
}
std::vector<osg::ref_ptr<TagBase> > selection =
getWorldspaceWidget().getSelection (Mask_Reference);
if (selection.empty())
return false;
// \todo check for sub-mode
for (std::vector<osg::ref_ptr<TagBase> >::iterator iter (selection.begin());
iter!=selection.end(); ++iter)
{
if (CSVRender::ObjectTag *objectTag = dynamic_cast<CSVRender::ObjectTag *> (iter->get()))
{
objectTag->mObject->setEdited (Object::Override_Position);
}
}
mDragMode = DragMode_Move;
return true;
}
bool CSVRender::InstanceMode::secondaryEditStartDrag (osg::ref_ptr<TagBase> tag)
{
return false;
}
void CSVRender::InstanceMode::drag (int diffX, int diffY, double speedFactor)
{
switch (mDragMode)
{
case DragMode_Move:
{
osg::Vec3f eye;
osg::Vec3f centre;
osg::Vec3f up;
getWorldspaceWidget().getCamera()->getViewMatrix().getLookAt (eye, centre, up);
osg::Vec3f offset;
if (diffY)
offset += up * diffY * speedFactor;
if (diffX)
offset += ((centre-eye) ^ up) * diffX * speedFactor;
std::vector<osg::ref_ptr<TagBase> > selection =
getWorldspaceWidget().getEdited (Mask_Reference);
for (std::vector<osg::ref_ptr<TagBase> >::iterator iter (selection.begin());
iter!=selection.end(); ++iter)
{
if (CSVRender::ObjectTag *objectTag = dynamic_cast<CSVRender::ObjectTag *> (iter->get()))
{
ESM::Position position = objectTag->mObject->getPosition();
for (int i=0; i<3; ++i)
position.pos[i] += offset[i];
objectTag->mObject->setPosition (position.pos);
}
}
break;
}
case DragMode_None: break;
}
}
void CSVRender::InstanceMode::dragCompleted()
{
std::vector<osg::ref_ptr<TagBase> > selection =
getWorldspaceWidget().getEdited (Mask_Reference);
QUndoStack& undoStack = getWorldspaceWidget().getDocument().getUndoStack();
QString description;
switch (mDragMode)
{
case DragMode_Move: description = "Move Instances"; break;
case DragMode_None: break;
}
undoStack.beginMacro (description);
for (std::vector<osg::ref_ptr<TagBase> >::iterator iter (selection.begin());
iter!=selection.end(); ++iter)
{
if (CSVRender::ObjectTag *objectTag = dynamic_cast<CSVRender::ObjectTag *> (iter->get()))
{
objectTag->mObject->apply (undoStack);
}
}
undoStack.endMacro();
mDragMode = DragMode_None;
}
void CSVRender::InstanceMode::dragWheel (int diff, double speedFactor)
{
if (mDragMode==DragMode_Move)
{
osg::Vec3f eye;
osg::Vec3f centre;
osg::Vec3f up;
getWorldspaceWidget().getCamera()->getViewMatrix().getLookAt (eye, centre, up);
osg::Vec3f offset = centre - eye;
offset.normalize();
offset *= diff * speedFactor;
std::vector<osg::ref_ptr<TagBase> > selection =
getWorldspaceWidget().getEdited (Mask_Reference);
for (std::vector<osg::ref_ptr<TagBase> >::iterator iter (selection.begin());
iter!=selection.end(); ++iter)
{
if (CSVRender::ObjectTag *objectTag = dynamic_cast<CSVRender::ObjectTag *> (iter->get()))
{
ESM::Position position = objectTag->mObject->getPosition();
for (int i=0; i<3; ++i)
position.pos[i] += offset[i];
objectTag->mObject->setPosition (position.pos);
}
}
}
}
void CSVRender::InstanceMode::dragEnterEvent (QDragEnterEvent *event)
{
if (const CSMWorld::TableMimeData* mime = dynamic_cast<const CSMWorld::TableMimeData*> (event->mimeData()))

@ -15,8 +15,17 @@ namespace CSVRender
class InstanceMode : public EditMode
{
Q_OBJECT
enum DragMode
{
DragMode_None,
DragMode_Move
};
CSVWidget::SceneToolMode *mSubMode;
InstanceSelectionMode *mSelectionMode;
DragMode mDragMode;
public:
@ -34,6 +43,16 @@ namespace CSVRender
virtual void secondarySelectPressed (osg::ref_ptr<TagBase> tag);
virtual bool primaryEditStartDrag (osg::ref_ptr<TagBase> tag);
virtual bool secondaryEditStartDrag (osg::ref_ptr<TagBase> tag);
virtual void drag (int diffX, int diffY, double speedFactor);
virtual void dragCompleted();
virtual void dragWheel (int diff, double speedFactor);
virtual void dragEnterEvent (QDragEnterEvent *event);
virtual void dropEvent (QDropEvent* event);

@ -0,0 +1,12 @@
#include "instancemovemode.hpp"
CSVRender::InstanceMoveMode::InstanceMoveMode (QWidget *parent)
: ModeButton (QIcon (QPixmap (":placeholder")),
"Move selected instances"
"<ul><li>Use primary edit to move instances around freely</li>"
"<li>Use secondary edit to move instances around within the grid</li>"
"</ul>"
"<font color=Red>Not implemented yet</font color>",
parent)
{}

@ -0,0 +1,18 @@
#ifndef CSV_RENDER_INSTANCEMOVEMODE_H
#define CSV_RENDER_INSTANCEMOVEMODE_H
#include "../widget/modebutton.hpp"
namespace CSVRender
{
class InstanceMoveMode : public CSVWidget::ModeButton
{
Q_OBJECT
public:
InstanceMoveMode (QWidget *parent = 0);
};
}
#endif

@ -15,6 +15,8 @@
#include "../../model/world/data.hpp"
#include "../../model/world/ref.hpp"
#include "../../model/world/refidcollection.hpp"
#include "../../model/world/commands.hpp"
#include "../../model/world/universalid.hpp"
#include <components/resource/scenemanager.hpp>
#include <components/sceneutil/lightutil.hpp>
@ -130,18 +132,20 @@ void CSVRender::Object::adjustTransform()
if (mReferenceId.empty())
return;
const CSMWorld::CellRef& reference = getReference();
ESM::Position position = getPosition();
// position
mBaseNode->setPosition(mForceBaseToZero ? osg::Vec3() : osg::Vec3f(reference.mPos.pos[0], reference.mPos.pos[1], reference.mPos.pos[2]));
mBaseNode->setPosition(mForceBaseToZero ? osg::Vec3() : osg::Vec3f(position.pos[0], position.pos[1], position.pos[2]));
// orientation
osg::Quat xr (-reference.mPos.rot[0], osg::Vec3f(1,0,0));
osg::Quat yr (-reference.mPos.rot[1], osg::Vec3f(0,1,0));
osg::Quat zr (-reference.mPos.rot[2], osg::Vec3f(0,0,1));
osg::Quat xr (-position.rot[0], osg::Vec3f(1,0,0));
osg::Quat yr (-position.rot[1], osg::Vec3f(0,1,0));
osg::Quat zr (-position.rot[2], osg::Vec3f(0,0,1));
mBaseNode->setAttitude(zr*yr*xr);
mBaseNode->setScale(osg::Vec3(reference.mScale, reference.mScale, reference.mScale));
float scale = getScale();
mBaseNode->setScale(osg::Vec3(scale, scale, scale));
}
const CSMWorld::CellRef& CSVRender::Object::getReference() const
@ -154,7 +158,8 @@ const CSMWorld::CellRef& CSVRender::Object::getReference() const
CSVRender::Object::Object (CSMWorld::Data& data, osg::Group* parentNode,
const std::string& id, bool referenceable, bool forceBaseToZero)
: mData (data), mBaseNode(0), mSelected(false), mParentNode(parentNode), mResourceSystem(data.getResourceSystem().get()), mForceBaseToZero (forceBaseToZero)
: mData (data), mBaseNode(0), mSelected(false), mParentNode(parentNode), mResourceSystem(data.getResourceSystem().get()), mForceBaseToZero (forceBaseToZero),
mScaleOverride (1), mOverrideFlags (0)
{
mBaseNode = new osg::PositionAttitudeTransform;
mBaseNode->addCullCallback(new SceneUtil::LightListCallback);
@ -290,3 +295,121 @@ osg::ref_ptr<CSVRender::TagBase> CSVRender::Object::getTag() const
{
return static_cast<CSVRender::TagBase *> (mBaseNode->getUserData());
}
bool CSVRender::Object::isEdited() const
{
return mOverrideFlags;
}
void CSVRender::Object::setEdited (int flags)
{
bool discard = mOverrideFlags & ~flags;
int added = flags & ~mOverrideFlags;
mOverrideFlags = flags;
if (added & Override_Position)
for (int i=0; i<3; ++i)
mPositionOverride.pos[i] = getReference().mPos.pos[i];
if (added & Override_Rotation)
for (int i=0; i<3; ++i)
mPositionOverride.rot[i] = getReference().mPos.rot[i];
if (added & Override_Scale)
mScaleOverride = getReference().mScale;
if (discard)
adjustTransform();
}
ESM::Position CSVRender::Object::getPosition() const
{
ESM::Position position = getReference().mPos;
if (mOverrideFlags & Override_Position)
for (int i=0; i<3; ++i)
position.pos[i] = mPositionOverride.pos[i];
if (mOverrideFlags & Override_Rotation)
for (int i=0; i<3; ++i)
position.rot[i] = mPositionOverride.rot[i];
return position;
}
float CSVRender::Object::getScale() const
{
return mOverrideFlags & Override_Scale ? mScaleOverride : getReference().mScale;
}
void CSVRender::Object::setPosition (const float position[3])
{
mOverrideFlags |= Override_Position;
for (int i=0; i<3; ++i)
mPositionOverride.pos[i] = position[i];
adjustTransform();
}
void CSVRender::Object::setRotation (const float rotation[3])
{
mOverrideFlags |= Override_Rotation;
for (int i=0; i<3; ++i)
mPositionOverride.rot[i] = rotation[i];
adjustTransform();
}
void CSVRender::Object::setScale (float scale)
{
mOverrideFlags |= Override_Scale;
mScaleOverride = scale;
adjustTransform();
}
void CSVRender::Object::apply (QUndoStack& undoStack)
{
const CSMWorld::RefCollection& collection = mData.getReferences();
QAbstractItemModel *model = mData.getTableModel (CSMWorld::UniversalId::Type_References);
int recordIndex = collection.getIndex (mReferenceId);
if (mOverrideFlags & Override_Position)
{
for (int i=0; i<3; ++i)
{
int column = collection.findColumnIndex (static_cast<CSMWorld::Columns::ColumnId> (
CSMWorld::Columns::ColumnId_PositionXPos+i));
undoStack.push (new CSMWorld::ModifyCommand (*model,
model->index (recordIndex, column), mPositionOverride.pos[i]));
}
}
if (mOverrideFlags & Override_Rotation)
{
for (int i=0; i<3; ++i)
{
int column = collection.findColumnIndex (static_cast<CSMWorld::Columns::ColumnId> (
CSMWorld::Columns::ColumnId_PositionXRot+i));
undoStack.push (new CSMWorld::ModifyCommand (*model,
model->index (recordIndex, column), mPositionOverride.rot[i]));
}
}
if (mOverrideFlags & Override_Scale)
{
int column = collection.findColumnIndex (CSMWorld::Columns::ColumnId_Scale);
undoStack.push (new CSMWorld::ModifyCommand (*model,
model->index (recordIndex, column), mScaleOverride));
}
mOverrideFlags = 0;
}

@ -8,9 +8,12 @@
#include <osg/ref_ptr>
#include <osg/Referenced>
#include <components/esm/defs.hpp>
#include "tagbase.hpp"
class QModelIndex;
class QUndoStack;
namespace osg
{
@ -53,7 +56,18 @@ namespace CSVRender
class Object
{
const CSMWorld::Data& mData;
public:
enum OverrideFlags
{
Override_Position = 1,
Override_Rotation = 2,
Override_Scale = 4
};
private:
CSMWorld::Data& mData;
std::string mReferenceId;
std::string mReferenceableId;
osg::ref_ptr<osg::PositionAttitudeTransform> mBaseNode;
@ -62,6 +76,9 @@ namespace CSVRender
osg::Group* mParentNode;
Resource::ResourceSystem* mResourceSystem;
bool mForceBaseToZero;
ESM::Position mPositionOverride;
int mScaleOverride;
int mOverrideFlags;
/// Not implemented
Object (const Object&);
@ -116,6 +133,27 @@ namespace CSVRender
std::string getReferenceableId() const;
osg::ref_ptr<TagBase> getTag() const;
/// Is there currently an editing operation running on this object?
bool isEdited() const;
void setEdited (int flags);
ESM::Position getPosition() const;
float getScale() const;
/// Set override position.
void setPosition (const float position[3]);
/// Set override rotation
void setRotation (const float rotation[3]);
/// Set override scale
void setScale (float scale);
/// Apply override changes via command and end edit mode
void apply (QUndoStack& undoStack);
};
}

@ -555,6 +555,23 @@ std::vector<osg::ref_ptr<CSVRender::TagBase> > CSVRender::PagedWorldspaceWidget:
return result;
}
std::vector<osg::ref_ptr<CSVRender::TagBase> > CSVRender::PagedWorldspaceWidget::getEdited (
unsigned int elementMask) const
{
std::vector<osg::ref_ptr<CSVRender::TagBase> > result;
for (std::map<CSMWorld::CellCoordinates, Cell *>::const_iterator iter = mCells.begin();
iter!=mCells.end(); ++iter)
{
std::vector<osg::ref_ptr<CSVRender::TagBase> > cellResult =
iter->second->getEdited (elementMask);
result.insert (result.end(), cellResult.begin(), cellResult.end());
}
return result;
}
CSVWidget::SceneToolToggle *CSVRender::PagedWorldspaceWidget::makeControlVisibilitySelector (
CSVWidget::SceneToolbar *parent)
{

@ -112,6 +112,9 @@ namespace CSVRender
virtual std::vector<osg::ref_ptr<TagBase> > getSelection (unsigned int elementMask)
const;
virtual std::vector<osg::ref_ptr<TagBase> > getEdited (unsigned int elementMask)
const;
protected:
virtual void addVisibilitySelectorButtons (CSVWidget::SceneToolToggle2 *tool);

@ -120,6 +120,12 @@ bool RenderWidget::eventFilter(QObject* obj, QEvent* event)
return QObject::eventFilter(obj, event);
}
osg::Camera *RenderWidget::getCamera()
{
return mView->getCamera();
}
// --------------------------------------------------
CompositeViewer::CompositeViewer()

@ -21,6 +21,7 @@ namespace Resource
namespace osg
{
class Group;
class Camera;
}
namespace CSVWidget
@ -47,6 +48,8 @@ namespace CSVRender
bool eventFilter(QObject *, QEvent *);
osg::Camera *getCamera();
protected:
osg::ref_ptr<osgViewer::View> mView;

@ -131,6 +131,12 @@ std::vector<osg::ref_ptr<CSVRender::TagBase> > CSVRender::UnpagedWorldspaceWidge
return mCell->getSelection (elementMask);
}
std::vector<osg::ref_ptr<CSVRender::TagBase> > CSVRender::UnpagedWorldspaceWidget::getEdited (
unsigned int elementMask) const
{
return mCell->getEdited (elementMask);
}
void CSVRender::UnpagedWorldspaceWidget::referenceableDataChanged (const QModelIndex& topLeft,
const QModelIndex& bottomRight)
{

@ -60,6 +60,9 @@ namespace CSVRender
virtual std::vector<osg::ref_ptr<TagBase> > getSelection (unsigned int elementMask)
const;
virtual std::vector<osg::ref_ptr<TagBase> > getEdited (unsigned int elementMask)
const;
private:
virtual void referenceableDataChanged (const QModelIndex& topLeft,

@ -152,6 +152,9 @@ namespace CSVRender
virtual std::vector<osg::ref_ptr<TagBase> > getSelection (unsigned int elementMask)
const = 0;
virtual std::vector<osg::ref_ptr<TagBase> > getEdited (unsigned int elementMask)
const = 0;
protected:
/// Visual elements in a scene

Loading…
Cancel
Save