From a19ac722151b18bef3199a30180a2bba33e226e3 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 1 Mar 2016 15:48:34 +0100 Subject: [PATCH] render marker --- apps/opencs/view/render/cell.cpp | 21 ++- apps/opencs/view/render/cell.hpp | 4 + apps/opencs/view/render/editmode.cpp | 5 + apps/opencs/view/render/editmode.hpp | 3 + apps/opencs/view/render/instancemode.cpp | 22 +++ apps/opencs/view/render/instancemode.hpp | 8 + apps/opencs/view/render/object.cpp | 157 +++++++++++++++++- apps/opencs/view/render/object.hpp | 21 +++ .../view/render/pagedworldspacewidget.cpp | 16 +- .../view/render/pagedworldspacewidget.hpp | 2 + .../view/render/unpagedworldspacewidget.cpp | 5 + .../view/render/unpagedworldspacewidget.hpp | 2 + apps/opencs/view/render/worldspacewidget.cpp | 5 + apps/opencs/view/render/worldspacewidget.hpp | 5 + apps/opencs/view/widget/scenetoolmode.cpp | 5 + apps/opencs/view/widget/scenetoolmode.hpp | 3 + 16 files changed, 278 insertions(+), 6 deletions(-) diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index f82ef31502..6e47d35945 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -51,7 +51,12 @@ bool CSVRender::Cell::addObjects (int start, int end) { std::string id = Misc::StringUtils::lowerCase (collection.getRecord (i).get().mId); - mObjects.insert (std::make_pair (id, new Object (mData, mCellNode, id, false))); + std::auto_ptr object (new Object (mData, mCellNode, id, false)); + + if (mSubModeElementMask & Mask_Reference) + object->setSubMode (mSubMode); + + mObjects.insert (std::make_pair (id, object.release())); modified = true; } } @@ -61,7 +66,8 @@ bool CSVRender::Cell::addObjects (int start, int end) CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::string& id, bool deleted) -: mData (data), mId (Misc::StringUtils::lowerCase (id)), mDeleted (deleted) +: mData (data), mId (Misc::StringUtils::lowerCase (id)), mDeleted (deleted), mSubMode (0), + mSubModeElementMask (0) { std::pair result = CSMWorld::CellCoordinates::fromId (id); @@ -359,3 +365,14 @@ std::vector > CSVRender::Cell::getEdited (unsig return result; } + +void CSVRender::Cell::setSubMode (int subMode, unsigned int elementMask) +{ + mSubMode = subMode; + mSubModeElementMask = elementMask; + + if (elementMask & Mask_Reference) + for (std::map::const_iterator iter (mObjects.begin()); + iter!=mObjects.end(); ++iter) + iter->second->setSubMode (subMode); +} diff --git a/apps/opencs/view/render/cell.hpp b/apps/opencs/view/render/cell.hpp index 6cdafbf36d..21949992d1 100644 --- a/apps/opencs/view/render/cell.hpp +++ b/apps/opencs/view/render/cell.hpp @@ -45,6 +45,8 @@ namespace CSVRender std::auto_ptr mCellArrows[4]; std::auto_ptr mCellMarker; bool mDeleted; + int mSubMode; + unsigned int mSubModeElementMask; /// Ignored if cell does not have an object with the given ID. /// @@ -118,6 +120,8 @@ namespace CSVRender std::vector > getSelection (unsigned int elementMask) const; std::vector > getEdited (unsigned int elementMask) const; + + void setSubMode (int subMode, unsigned int elementMask); }; } diff --git a/apps/opencs/view/render/editmode.cpp b/apps/opencs/view/render/editmode.cpp index b325e31fb0..be264afc7c 100644 --- a/apps/opencs/view/render/editmode.cpp +++ b/apps/opencs/view/render/editmode.cpp @@ -70,3 +70,8 @@ void CSVRender::EditMode::dragEnterEvent (QDragEnterEvent *event) {} void CSVRender::EditMode::dropEvent (QDropEvent* event) {} void CSVRender::EditMode::dragMoveEvent (QDragMoveEvent *event) {} + +int CSVRender::EditMode::getSubMode() const +{ + return -1; +} diff --git a/apps/opencs/view/render/editmode.hpp b/apps/opencs/view/render/editmode.hpp index 3ba97cf007..f5cef1be29 100644 --- a/apps/opencs/view/render/editmode.hpp +++ b/apps/opencs/view/render/editmode.hpp @@ -92,6 +92,9 @@ namespace CSVRender /// Default-implementation: ignored virtual void dragMoveEvent (QDragMoveEvent *event); + + /// Default: return -1 + virtual int getSubMode() const; }; } diff --git a/apps/opencs/view/render/instancemode.cpp b/apps/opencs/view/render/instancemode.cpp index f2fb552b00..24e307dc5a 100644 --- a/apps/opencs/view/render/instancemode.cpp +++ b/apps/opencs/view/render/instancemode.cpp @@ -20,6 +20,11 @@ #include "instanceselectionmode.hpp" #include "instancemovemode.hpp" +int CSVRender::InstanceMode::getSubModeFromId (const std::string& id) const +{ + return id=="move" ? 0 : (id=="rotate" ? 1 : 2); +} + CSVRender::InstanceMode::InstanceMode (WorldspaceWidget *worldspaceWidget, QWidget *parent) : EditMode (worldspaceWidget, QIcon (":placeholder"), Mask_Reference, "Instance editing", parent), mSubMode (0), mSelectionMode (0), mDragMode (DragMode_None) @@ -44,6 +49,9 @@ void CSVRender::InstanceMode::activate (CSVWidget::SceneToolbar *toolbar) "
  • Use secondary edit to scale instances along the grid
  • " "" "Not implemented yet"); + + connect (mSubMode, SIGNAL (modeChanged (const std::string&)), + this, SLOT (subModeChanged (const std::string&))); } if (!mSelectionMode) @@ -55,6 +63,10 @@ void CSVRender::InstanceMode::activate (CSVWidget::SceneToolbar *toolbar) toolbar->addTool (mSubMode); toolbar->addTool (mSelectionMode); + + std::string subMode = mSubMode->getCurrentId(); + + getWorldspaceWidget().setSubMode (getSubModeFromId (subMode), Mask_Reference); } void CSVRender::InstanceMode::deactivate (CSVWidget::SceneToolbar *toolbar) @@ -402,3 +414,13 @@ void CSVRender::InstanceMode::dropEvent (QDropEvent* event) event->accept(); } } + +int CSVRender::InstanceMode::getSubMode() const +{ + return mSubMode ? getSubModeFromId (mSubMode->getCurrentId()) : 0; +} + +void CSVRender::InstanceMode::subModeChanged (const std::string& id) +{ + getWorldspaceWidget().setSubMode (getSubModeFromId (id), Mask_Reference); +} diff --git a/apps/opencs/view/render/instancemode.hpp b/apps/opencs/view/render/instancemode.hpp index 7662a0cdc3..5beec56434 100644 --- a/apps/opencs/view/render/instancemode.hpp +++ b/apps/opencs/view/render/instancemode.hpp @@ -27,6 +27,8 @@ namespace CSVRender InstanceSelectionMode *mSelectionMode; DragMode mDragMode; + int getSubModeFromId (const std::string& id) const; + public: InstanceMode (WorldspaceWidget *worldspaceWidget, QWidget *parent = 0); @@ -56,6 +58,12 @@ namespace CSVRender virtual void dragEnterEvent (QDragEnterEvent *event); virtual void dropEvent (QDropEvent* event); + + virtual int getSubMode() const; + + private slots: + + void subModeChanged (const std::string& id); }; } diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index 0f135459b9..b7efa50586 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -9,6 +9,8 @@ #include #include #include +#include +#include #include @@ -52,6 +54,11 @@ QString CSVRender::ObjectTag::getToolTip (bool hideBasics) const } +CSVRender::ObjectMarkerTag::ObjectMarkerTag (Object* object, int axis) +: TagBase (Mask_Reference), mObject (object), mAxis (axis) +{} + + void CSVRender::Object::clear() { } @@ -156,10 +163,144 @@ const CSMWorld::CellRef& CSVRender::Object::getReference() const return mData.getReferences().getRecord (mReferenceId).get(); } +void CSVRender::Object::updateMarker() +{ + for (int i=0; i<3; ++i) + { + if (mMarker[i]) + { + mRootNode->removeChild (mMarker[i]); + mMarker[i] = osg::ref_ptr(); + } + + if (mSelected) + { + if (mSubMode==0) + { + mMarker[i] = makeMarker (i); + mMarker[i]->setUserData(new ObjectMarkerTag (this, i)); + + mRootNode->addChild (mMarker[i]); + } + } + } +} + +osg::ref_ptr CSVRender::Object::makeMarker (int axis) +{ + osg::ref_ptr geometry (new osg::Geometry); + + const float shaftWidth = 10; + const float shaftBaseLength = 50; + const float headWidth = 30; + const float headLength = 30; + + float shaftLength = shaftBaseLength + mBaseNode->getBound().radius(); + + // shaft + osg::Vec3Array *vertices = new osg::Vec3Array; + + for (int i=0; i<2; ++i) + { + float length = i ? shaftLength : 0; + + vertices->push_back (getMarkerPosition (-shaftWidth/2, -shaftWidth/2, length, axis)); + vertices->push_back (getMarkerPosition (-shaftWidth/2, shaftWidth/2, length, axis)); + vertices->push_back (getMarkerPosition (shaftWidth/2, shaftWidth/2, length, axis)); + vertices->push_back (getMarkerPosition (shaftWidth/2, -shaftWidth/2, length, axis)); + } + + // head backside + vertices->push_back (getMarkerPosition (-headWidth/2, -headWidth/2, shaftLength, axis)); + vertices->push_back (getMarkerPosition (-headWidth/2, headWidth/2, shaftLength, axis)); + vertices->push_back (getMarkerPosition (headWidth/2, headWidth/2, shaftLength, axis)); + vertices->push_back (getMarkerPosition (headWidth/2, -headWidth/2, shaftLength, axis)); + + // head + vertices->push_back (getMarkerPosition (0, 0, shaftLength+headLength, axis)); + + geometry->setVertexArray (vertices); + + osg::DrawElementsUShort *primitives = new osg::DrawElementsUShort (osg::PrimitiveSet::TRIANGLES, 0); + + // shaft + for (int i=0; i<4; ++i) + { + int i2 = i==3 ? 0 : i+1; + primitives->push_back (i); + primitives->push_back (4+i); + primitives->push_back (i2); + + primitives->push_back (4+i); + primitives->push_back (4+i2); + primitives->push_back (i2); + } + + // cap + primitives->push_back (0); + primitives->push_back (1); + primitives->push_back (2); + + primitives->push_back (2); + primitives->push_back (3); + primitives->push_back (0); + + // head, backside + primitives->push_back (0+8); + primitives->push_back (1+8); + primitives->push_back (2+8); + + primitives->push_back (2+8); + primitives->push_back (3+8); + primitives->push_back (0+8); + + for (int i=0; i<4; ++i) + { + primitives->push_back (12); + primitives->push_back (8+(i==3 ? 0 : i+1)); + primitives->push_back (8+i); + } + + geometry->addPrimitiveSet (primitives); + + osg::Vec4Array *colours = new osg::Vec4Array; + + for (int i=0; i<8; ++i) + colours->push_back (osg::Vec4f (axis==0 ? 1.0f : 0.2f, axis==1 ? 1.0f : 0.2f, + axis==2 ? 1.0f : 0.2f, 1.0f)); + + for (int i=8; i<8+4+1; ++i) + colours->push_back (osg::Vec4f (axis==0 ? 1.0f : 0.0f, axis==1 ? 1.0f : 0.0f, + axis==2 ? 1.0f : 0.0f, 1.0f)); + + geometry->setColorArray (colours, osg::Array::BIND_PER_VERTEX); + + geometry->getOrCreateStateSet()->setMode (GL_LIGHTING, osg::StateAttribute::OFF); + + osg::ref_ptr geode (new osg::Geode); + geode->addDrawable (geometry); + + return geode; +} + +osg::Vec3f CSVRender::Object::getMarkerPosition (float x, float y, float z, int axis) +{ + switch (axis) + { + case 0: return osg::Vec3f (x, y, z); + case 1: return osg::Vec3f (z, x, y); + case 2: return osg::Vec3f (y, z, x); + + default: + + throw std::logic_error ("invalid axis for marker geometry"); + } +} + 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), - mScaleOverride (1), mOverrideFlags (0) + mScaleOverride (1), mOverrideFlags (0), mSubMode (-1) { mRootNode = new osg::PositionAttitudeTransform; @@ -188,6 +329,7 @@ CSVRender::Object::Object (CSMWorld::Data& data, osg::Group* parentNode, adjustTransform(); update(); + updateMarker(); } CSVRender::Object::~Object() @@ -211,6 +353,8 @@ void CSVRender::Object::setSelected(bool selected) } else mRootNode->addChild(mBaseNode); + + updateMarker(); } bool CSVRender::Object::getSelected() const @@ -229,6 +373,7 @@ bool CSVRender::Object::referenceableDataChanged (const QModelIndex& topLeft, { adjustTransform(); update(); + updateMarker(); return true; } @@ -279,6 +424,7 @@ bool CSVRender::Object::referenceDataChanged (const QModelIndex& topLeft, references.getData (index, columnIndex).toString().toUtf8().constData(); update(); + updateMarker(); } return true; @@ -419,3 +565,12 @@ void CSVRender::Object::apply (QUndoStack& undoStack) mOverrideFlags = 0; } + +void CSVRender::Object::setSubMode (int subMode) +{ + if (subMode!=mSubMode) + { + mSubMode = subMode; + updateMarker(); + } +} diff --git a/apps/opencs/view/render/object.hpp b/apps/opencs/view/render/object.hpp index 4b528b59f1..9cd0a8d670 100644 --- a/apps/opencs/view/render/object.hpp +++ b/apps/opencs/view/render/object.hpp @@ -19,6 +19,8 @@ namespace osg { class PositionAttitudeTransform; class Group; + class Node; + class Geode; } namespace osgFX @@ -53,6 +55,15 @@ namespace CSVRender virtual QString getToolTip (bool hideBasics) const; }; + class ObjectMarkerTag : public TagBase + { + public: + + ObjectMarkerTag (Object* object, int axis); + + Object* mObject; + int mAxis; + }; class Object { @@ -80,6 +91,8 @@ namespace CSVRender ESM::Position mPositionOverride; int mScaleOverride; int mOverrideFlags; + osg::ref_ptr mMarker[3]; + int mSubMode; /// Not implemented Object (const Object&); @@ -100,6 +113,12 @@ namespace CSVRender /// Throws an exception if *this was constructed with referenceable const CSMWorld::CellRef& getReference() const; + void updateMarker(); + + osg::ref_ptr makeMarker (int axis); + + osg::Vec3f getMarkerPosition (float x, float y, float z, int axis); + public: Object (CSMWorld::Data& data, osg::Group *cellNode, @@ -155,6 +174,8 @@ namespace CSVRender /// Apply override changes via command and end edit mode void apply (QUndoStack& undoStack); + + void setSubMode (int subMode); }; } diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index cbba9ef5d9..68c8949f32 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -309,10 +309,13 @@ void CSVRender::PagedWorldspaceWidget::addCellToScene ( bool deleted = index==-1 || cells.getRecord (index).mState==CSMWorld::RecordBase::State_Deleted; - Cell *cell = new Cell (mDocument.getData(), mRootNode, coordinates.getId (mWorldspace), - deleted); + std::auto_ptr cell ( + new Cell (mDocument.getData(), mRootNode, coordinates.getId (mWorldspace), + deleted)); + EditMode *editMode = getEditMode(); + cell->setSubMode (editMode->getSubMode(), editMode->getInteractionMask()); - mCells.insert (std::make_pair (coordinates, cell)); + mCells.insert (std::make_pair (coordinates, cell.release())); } void CSVRender::PagedWorldspaceWidget::removeCellFromScene ( @@ -572,6 +575,13 @@ std::vector > CSVRender::PagedWorldspaceWidget: return result; } +void CSVRender::PagedWorldspaceWidget::setSubMode (int subMode, unsigned int elementMask) +{ + for (std::map::const_iterator iter = mCells.begin(); + iter!=mCells.end(); ++iter) + iter->second->setSubMode (subMode, elementMask); +} + CSVWidget::SceneToolToggle *CSVRender::PagedWorldspaceWidget::makeControlVisibilitySelector ( CSVWidget::SceneToolbar *parent) { diff --git a/apps/opencs/view/render/pagedworldspacewidget.hpp b/apps/opencs/view/render/pagedworldspacewidget.hpp index baec96b039..c77c3ebd23 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.hpp +++ b/apps/opencs/view/render/pagedworldspacewidget.hpp @@ -115,6 +115,8 @@ namespace CSVRender virtual std::vector > getEdited (unsigned int elementMask) const; + virtual void setSubMode (int subMode, unsigned int elementMask); + protected: virtual void addVisibilitySelectorButtons (CSVWidget::SceneToolToggle2 *tool); diff --git a/apps/opencs/view/render/unpagedworldspacewidget.cpp b/apps/opencs/view/render/unpagedworldspacewidget.cpp index 4a7723d2f2..60aeeb4d81 100644 --- a/apps/opencs/view/render/unpagedworldspacewidget.cpp +++ b/apps/opencs/view/render/unpagedworldspacewidget.cpp @@ -137,6 +137,11 @@ std::vector > CSVRender::UnpagedWorldspaceWidge return mCell->getEdited (elementMask); } +void CSVRender::UnpagedWorldspaceWidget::setSubMode (int subMode, unsigned int elementMask) +{ + mCell->setSubMode (subMode, elementMask); +} + void CSVRender::UnpagedWorldspaceWidget::referenceableDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) { diff --git a/apps/opencs/view/render/unpagedworldspacewidget.hpp b/apps/opencs/view/render/unpagedworldspacewidget.hpp index f7b583f3da..a3718d9f3b 100644 --- a/apps/opencs/view/render/unpagedworldspacewidget.hpp +++ b/apps/opencs/view/render/unpagedworldspacewidget.hpp @@ -63,6 +63,8 @@ namespace CSVRender virtual std::vector > getEdited (unsigned int elementMask) const; + virtual void setSubMode (int subMode, unsigned int elementMask); + private: virtual void referenceableDataChanged (const QModelIndex& topLeft, diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 6ba6e95432..83feb0be3e 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -761,3 +761,8 @@ void CSVRender::WorldspaceWidget::handleMouseClick (osg::ref_ptr tag, c else if (button=="s-select") editMode.secondarySelectPressed (tag); } + +CSVRender::EditMode *CSVRender::WorldspaceWidget::getEditMode() +{ + return dynamic_cast (mEditMode->getCurrent()); +} diff --git a/apps/opencs/view/render/worldspacewidget.hpp b/apps/opencs/view/render/worldspacewidget.hpp index 67f585e03c..eee618ed1a 100644 --- a/apps/opencs/view/render/worldspacewidget.hpp +++ b/apps/opencs/view/render/worldspacewidget.hpp @@ -35,6 +35,7 @@ namespace CSVRender { class TagBase; class CellArrow; + class EditMode; class WorldspaceWidget : public SceneWidget { @@ -155,6 +156,8 @@ namespace CSVRender virtual std::vector > getEdited (unsigned int elementMask) const = 0; + virtual void setSubMode (int subMode, unsigned int elementMask) = 0; + protected: /// Visual elements in a scene @@ -184,6 +187,8 @@ namespace CSVRender virtual void handleMouseClick (osg::ref_ptr tag, const std::string& button, bool shift); + EditMode *getEditMode(); + private: void dragEnterEvent(QDragEnterEvent *event); diff --git a/apps/opencs/view/widget/scenetoolmode.cpp b/apps/opencs/view/widget/scenetoolmode.cpp index 125f4ac79a..08e8ad5a4f 100644 --- a/apps/opencs/view/widget/scenetoolmode.cpp +++ b/apps/opencs/view/widget/scenetoolmode.cpp @@ -96,6 +96,11 @@ CSVWidget::ModeButton *CSVWidget::SceneToolMode::getCurrent() return mCurrent; } +std::string CSVWidget::SceneToolMode::getCurrentId() const +{ + return mButtons.find (mCurrent)->second; +} + void CSVWidget::SceneToolMode::selected() { std::map::const_iterator iter = diff --git a/apps/opencs/view/widget/scenetoolmode.hpp b/apps/opencs/view/widget/scenetoolmode.hpp index 3aa8e6799a..c274d84ab2 100644 --- a/apps/opencs/view/widget/scenetoolmode.hpp +++ b/apps/opencs/view/widget/scenetoolmode.hpp @@ -56,6 +56,9 @@ namespace CSVWidget /// Will return a 0-pointer only if the mode does not have any buttons yet. ModeButton *getCurrent(); + /// Must not be called if there aren't any buttons yet. + std::string getCurrentId() const; + signals: void modeChanged (const std::string& id);