From 32ba5bf8b87bb25eb09b02ff8eca4c996a22e134 Mon Sep 17 00:00:00 2001 From: Aesylwinn Date: Thu, 12 May 2016 19:35:49 -0400 Subject: [PATCH] Initial pathgrid editting, support for selection and movement. --- apps/opencs/CMakeLists.txt | 4 +- apps/opencs/view/render/cell.cpp | 50 ++-- apps/opencs/view/render/cell.hpp | 6 +- apps/opencs/view/render/pathgrid.cpp | 287 +++++++++++++++++++ apps/opencs/view/render/pathgrid.hpp | 105 +++++++ apps/opencs/view/render/pathgridmode.cpp | 152 ++++++++++ apps/opencs/view/render/pathgridmode.hpp | 53 ++++ apps/opencs/view/render/worldspacewidget.cpp | 8 +- components/sceneutil/pathgridutil.cpp | 77 +++++ components/sceneutil/pathgridutil.hpp | 5 + 10 files changed, 707 insertions(+), 40 deletions(-) create mode 100644 apps/opencs/view/render/pathgrid.cpp create mode 100644 apps/opencs/view/render/pathgrid.hpp create mode 100644 apps/opencs/view/render/pathgridmode.cpp create mode 100644 apps/opencs/view/render/pathgridmode.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index e7312d0ba..b33dc1508 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -86,12 +86,12 @@ opencs_units (view/widget opencs_units (view/render scenewidget worldspacewidget pagedworldspacewidget unpagedworldspacewidget previewwidget editmode instancemode instanceselectionmode instancemovemode - orbitcameramode + orbitcameramode pathgridmode ) opencs_units_noqt (view/render lighting lightingday lightingnight lightingbright object cell terrainstorage tagbase - cellarrow cellmarker cellborder cameracontroller + cellarrow cellmarker cellborder cameracontroller pathgrid ) opencs_hdrs_noqt (view/render diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index 691b909bb..a8e36728c 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -17,6 +17,7 @@ #include "../../model/world/cellcoordinates.hpp" #include "mask.hpp" +#include "pathgrid.hpp" #include "terrainstorage.hpp" bool CSVRender::Cell::removeObject (const std::string& id) @@ -68,18 +69,6 @@ bool CSVRender::Cell::addObjects (int start, int end) return modified; } -void CSVRender::Cell::recreatePathgrid() -{ - const CSMWorld::SubCellCollection& pathgrids = mData.getPathgrids(); - int pathgridIndex = pathgrids.searchId(mId); - if (pathgridIndex != -1) - { - mPathgridGeode->removeDrawable(mPathgridGeometry); - mPathgridGeometry = SceneUtil::createPathgridGeometry(pathgrids.getRecord(pathgridIndex).get()); - mPathgridGeode->addDrawable(mPathgridGeometry); - } -} - CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::string& id, bool deleted) : mData (data), mId (Misc::StringUtils::lowerCase (id)), mDeleted (deleted), mSubMode (0), @@ -93,17 +82,6 @@ CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::st mCellNode = new osg::Group; rootNode->addChild(mCellNode); - osg::ref_ptr pathgridTransform = new osg::PositionAttitudeTransform(); - pathgridTransform->setPosition(osg::Vec3f(mCoordinates.getX() * ESM::Land::REAL_SIZE, - mCoordinates.getY() * ESM::Land::REAL_SIZE, 0)); - pathgridTransform->setNodeMask(Mask_Pathgrid); - mCellNode->addChild(pathgridTransform); - - mPathgridGeode = new osg::Geode(); - pathgridTransform->addChild(mPathgridGeode); - - mPathgridGeometry = 0; - setCellMarker(); if (!mDeleted) @@ -132,7 +110,7 @@ CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::st } } - recreatePathgrid(); + mPathgrid.reset(new Pathgrid(mData, mCellNode, mId, mCoordinates)); } } @@ -285,27 +263,27 @@ bool CSVRender::Cell::referenceAdded (const QModelIndex& parent, int start, int void CSVRender::Cell::pathgridAdded(const CSMWorld::Pathgrid& pathgrid) { - recreatePathgrid(); + mPathgrid->recreateGeometry(); } void CSVRender::Cell::pathgridRemoved() { - mPathgridGeode->removeDrawable(mPathgridGeometry); + mPathgrid->recreateGeometry(); } void CSVRender::Cell::pathgridDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight) { - recreatePathgrid(); + mPathgrid->recreateGeometry(); } void CSVRender::Cell::pathgridRowRemoved(const QModelIndex& parent, int start, int end) { - recreatePathgrid(); + mPathgrid->recreateGeometry(); } void CSVRender::Cell::pathgridRowAdded(const QModelIndex& parent, int start, int end) { - recreatePathgrid(); + mPathgrid->recreateGeometry(); } void CSVRender::Cell::setSelection (int elementMask, Selection mode) @@ -327,6 +305,15 @@ void CSVRender::Cell::setSelection (int elementMask, Selection mode) iter->second->setSelected (selected); } } + if (elementMask & Mask_Pathgrid) + { + switch (mode) + { + case Selection_Clear: mPathgrid->clearSelected(); break; + case Selection_All: mPathgrid->selectAll(); break; + case Selection_Invert: mPathgrid->invertSelected(); break; + } + } } void CSVRender::Cell::selectAllWithSameParentId (int elementMask) @@ -406,6 +393,9 @@ std::vector > CSVRender::Cell::getSelection (un iter!=mObjects.end(); ++iter) if (iter->second->getSelected()) result.push_back (iter->second->getTag()); + if (elementMask & Mask_Pathgrid) + if (mPathgrid->isSelected()) + result.push_back(mPathgrid->getTag()); return result; } @@ -440,4 +430,6 @@ void CSVRender::Cell::reset (unsigned int elementMask) for (std::map::const_iterator iter (mObjects.begin()); iter!=mObjects.end(); ++iter) iter->second->reset(); + if (elementMask & Mask_Pathgrid) + mPathgrid->resetMove(); } diff --git a/apps/opencs/view/render/cell.hpp b/apps/opencs/view/render/cell.hpp index e265fc21c..caf6c59a9 100644 --- a/apps/opencs/view/render/cell.hpp +++ b/apps/opencs/view/render/cell.hpp @@ -36,6 +36,7 @@ namespace CSMWorld namespace CSVRender { + class Pathgrid; class TagBase; class Cell @@ -43,14 +44,13 @@ namespace CSVRender CSMWorld::Data& mData; std::string mId; osg::ref_ptr mCellNode; - osg::ref_ptr mPathgridGeode; - osg::ref_ptr mPathgridGeometry; std::map mObjects; std::auto_ptr mTerrain; CSMWorld::CellCoordinates mCoordinates; std::auto_ptr mCellArrows[4]; std::auto_ptr mCellMarker; std::auto_ptr mCellBorder; + std::auto_ptr mPathgrid; bool mDeleted; int mSubMode; unsigned int mSubModeElementMask; @@ -69,8 +69,6 @@ namespace CSVRender /// \return Have any objects been added? bool addObjects (int start, int end); - void recreatePathgrid(); - public: enum Selection diff --git a/apps/opencs/view/render/pathgrid.cpp b/apps/opencs/view/render/pathgrid.cpp new file mode 100644 index 000000000..4aa254a44 --- /dev/null +++ b/apps/opencs/view/render/pathgrid.cpp @@ -0,0 +1,287 @@ +#include "pathgrid.hpp" + +#include + +#include +#include +#include +#include +#include + +#include + +#include "../../model/world/commands.hpp" +#include "../../model/world/commandmacro.hpp" +#include "../../model/world/data.hpp" + +namespace CSVRender +{ + PathgridTag::PathgridTag(Pathgrid* pathgrid) + : TagBase(Mask_Pathgrid), mPathgrid(pathgrid) + { + } + + Pathgrid* PathgridTag::getPathgrid() const + { + return mPathgrid; + } + + QString PathgridTag::getToolTip(bool hideBasics) const + { + QString text("Pathgrid: "); + text += mPathgrid->getId().c_str(); + + if (!hideBasics) + { + text += "

Only one pathgrid may be edited at a time."; + } + + return text; + } + + Pathgrid::Pathgrid(CSMWorld::Data& data, osg::Group* parent, const std::string& pathgridId, + const CSMWorld::CellCoordinates& coordinates) + : mData(data) + , mId(pathgridId) + , mCoords(coordinates) + , mParent(parent) + , mPathgridGeometry(0) + , mSelectedGeometry(0) + , mTag(new PathgridTag(this)) + { + const float CoordScalar = ESM::Land::REAL_SIZE; + + mBaseNode = new osg::PositionAttitudeTransform (); + mBaseNode->setPosition(osg::Vec3f(mCoords.getX() * CoordScalar, mCoords.getY() * CoordScalar, 0.f)); + mBaseNode->setUserData(mTag); + mBaseNode->setNodeMask(Mask_Pathgrid); + mParent->addChild(mBaseNode); + + mSelectedNode = new osg::PositionAttitudeTransform(); + mBaseNode->addChild(mSelectedNode); + + mPathgridGeode = new osg::Geode(); + mBaseNode->addChild(mPathgridGeode); + + mSelectedGeode = new osg::Geode(); + mSelectedNode->addChild(mSelectedGeode); + + recreateGeometry(); + } + + Pathgrid::~Pathgrid() + { + mParent->removeChild(mBaseNode); + } + + const CSMWorld::CellCoordinates& Pathgrid::getCoordinates() const + { + return mCoords; + } + + const std::string& Pathgrid::getId() const + { + return mId; + } + + bool Pathgrid::isSelected() const + { + return !mSelected.empty(); + } + + const Pathgrid::NodeList& Pathgrid::getSelected() const + { + return mSelected; + } + + void Pathgrid::selectAll() + { + mSelected.clear(); + + const CSMWorld::SubCellCollection& pathgrids = mData.getPathgrids(); + int pathgridIndex = pathgrids.searchId(mId); + if (pathgridIndex != -1) + { + const CSMWorld::Pathgrid& source = pathgrids.getRecord(pathgridIndex).get(); + for (unsigned short i = 0; i < static_cast(source.mPoints.size()); ++i) + mSelected.push_back(i); + + recreateSelectedGeometry(source); + } + else + { + removeSelectedGeometry(); + } + } + + void Pathgrid::toggleSelected(unsigned short node) + { + NodeList::iterator searchResult = std::find(mSelected.begin(), mSelected.end(), node); + if (searchResult != mSelected.end()) + { + mSelected.erase(searchResult); + } + else + { + mSelected.push_back(node); + } + + recreateSelectedGeometry(); + } + + void Pathgrid::invertSelected() + { + NodeList temp = NodeList(mSelected.begin(), mSelected.end()); + mSelected.clear(); + + const CSMWorld::SubCellCollection& pathgrids = mData.getPathgrids(); + int pathgridIndex = pathgrids.searchId(mId); + if (pathgridIndex != -1) + { + const CSMWorld::Pathgrid& source = pathgrids.getRecord(pathgridIndex).get(); + for (unsigned short i = 0; i < static_cast(source.mPoints.size()); ++i) + { + if (std::find(temp.begin(), temp.end(), i) == temp.end()) + mSelected.push_back(i); + } + + recreateSelectedGeometry(source); + } + else + { + removeSelectedGeometry(); + } + } + + void Pathgrid::clearSelected() + { + mSelected.clear(); + removeSelectedGeometry(); + } + + void Pathgrid::moveSelected(const osg::Vec3d& offset) + { + mSelectedNode->setPosition(mSelectedNode->getPosition() + offset); + } + + void Pathgrid::resetMove() + { + mSelectedNode->setPosition(osg::Vec3f(0,0,0)); + } + + void Pathgrid::applyPosition(CSMWorld::CommandMacro& commands) + { + const CSMWorld::SubCellCollection& pathgrids = mData.getPathgrids(); + int pathgridIndex = pathgrids.searchId(mId); + if (pathgridIndex != -1) + { + const CSMWorld::Pathgrid& source = pathgrids.getRecord(pathgridIndex).get(); + osg::Vec3d localCoords = mSelectedNode->getPosition(); + + int oX = static_cast(localCoords.x()); + int oY = static_cast(localCoords.y()); + int oZ = static_cast(localCoords.z()); + + CSMWorld::SubCellCollection& collection = mData.getPathgrids(); + QAbstractItemModel* model = mData.getTableModel (CSMWorld::UniversalId::Type_Pathgrids); + + int recordIndex = collection.getIndex (mId); + int parentColumn = collection.findColumnIndex(CSMWorld::Columns::ColumnId_PathgridPoints); + + QModelIndex parent = model->index(recordIndex, parentColumn); + + for (size_t i = 0; i < mSelected.size(); ++i) + { + const CSMWorld::Pathgrid::Point& point = source.mPoints[mSelected[i]]; + int row = mSelected[i]; + + // X + int column = collection.searchNestedColumnIndex(parentColumn, CSMWorld::Columns::ColumnId_PathgridPosX); + commands.push (new CSMWorld::ModifyCommand(*model, model->index(row, column, parent), point.mX + oX)); + + // Y + column = collection.searchNestedColumnIndex(parentColumn, CSMWorld::Columns::ColumnId_PathgridPosY); + commands.push (new CSMWorld::ModifyCommand(*model, model->index(row, column, parent), point.mY + oY)); + + // Z + column = collection.searchNestedColumnIndex(parentColumn, CSMWorld::Columns::ColumnId_PathgridPosZ); + commands.push (new CSMWorld::ModifyCommand(*model, model->index(row, column, parent), point.mZ + oZ)); + } + } + + resetMove(); + } + + void Pathgrid::applyEdge(CSMWorld::CommandMacro& commands, unsigned short node1, unsigned short node2) + { + // TODO + } + + void Pathgrid::applyEdges(CSMWorld::CommandMacro& commands, unsigned short node) + { + // TODO + } + + osg::ref_ptr Pathgrid::getTag() const + { + return mTag; + } + + void Pathgrid::recreateGeometry() + { + removePathgridGeometry(); + removeSelectedGeometry(); + + // Make new + const CSMWorld::SubCellCollection& pathgrids = mData.getPathgrids(); + int pathgridIndex = pathgrids.searchId(mId); + if (pathgridIndex != -1) + { + const CSMWorld::Pathgrid& source = pathgrids.getRecord(pathgridIndex).get(); + mPathgridGeometry = SceneUtil::createPathgridGeometry(source); + mPathgridGeode->addDrawable(mPathgridGeometry); + + recreateSelectedGeometry(source); + } + } + + void Pathgrid::recreateSelectedGeometry() + { + const CSMWorld::SubCellCollection& pathgrids = mData.getPathgrids(); + int pathgridIndex = pathgrids.searchId(mId); + if (pathgridIndex != -1) + { + const CSMWorld::Pathgrid& source = pathgrids.getRecord(pathgridIndex).get(); + recreateSelectedGeometry(source); + } + else + { + removeSelectedGeometry(); + } + } + + void Pathgrid::recreateSelectedGeometry(const CSMWorld::Pathgrid& source) + { + removeSelectedGeometry(); + mSelectedGeometry = SceneUtil::createPathgridSelectedWireframe(source, mSelected); + mSelectedGeode->addDrawable(mSelectedGeometry); + } + + void Pathgrid::removePathgridGeometry() + { + if (mPathgridGeometry) + { + mPathgridGeode->removeDrawable(mPathgridGeometry); + mPathgridGeometry.release(); + } + } + + void Pathgrid::removeSelectedGeometry() + { + if (mSelectedGeometry) + { + mSelectedGeode->removeDrawable(mSelectedGeometry); + mSelectedGeometry.release(); + } + } +} diff --git a/apps/opencs/view/render/pathgrid.hpp b/apps/opencs/view/render/pathgrid.hpp new file mode 100644 index 000000000..c1a8f9308 --- /dev/null +++ b/apps/opencs/view/render/pathgrid.hpp @@ -0,0 +1,105 @@ +#ifndef CSV_RENDER_PATHGRID_H +#define CSV_RENDER_PATHGRID_H + +#include + +#include +#include + +#include "../../model/world/cellcoordinates.hpp" + +#include "tagbase.hpp" + +namespace osg +{ + class Geode; + class Geometry; + class Group; + class PositionAttitudeTransform; + class Vec3d; +} + +namespace CSMWorld +{ + class CommandMacro; + class Data; + class Pathgrid; +} + +namespace CSVRender +{ + class Pathgrid; + + class PathgridTag : public TagBase + { + public: + + PathgridTag (Pathgrid* pathgrid); + + Pathgrid* getPathgrid () const; + + virtual QString getToolTip (bool hideBasics) const; + + private: + + Pathgrid* mPathgrid; + }; + + class Pathgrid + { + public: + + typedef std::vector NodeList; + + Pathgrid(CSMWorld::Data& data, osg::Group* parent, const std::string& pathgridId, + const CSMWorld::CellCoordinates& coordinates); + + ~Pathgrid(); + + const CSMWorld::CellCoordinates& getCoordinates() const; + const std::string& getId() const; + + bool isSelected() const; + const NodeList& getSelected() const; + void selectAll(); + void toggleSelected(unsigned short node); // Adds to end of vector + void invertSelected(); + void clearSelected(); + + void moveSelected(const osg::Vec3d& offset); + void resetMove(); + + void applyPosition(CSMWorld::CommandMacro& commands); + void applyEdge(CSMWorld::CommandMacro& commands, unsigned short node1, unsigned short node2); + void applyEdges(CSMWorld::CommandMacro& commands, unsigned short node); + + osg::ref_ptr getTag() const; + + void recreateGeometry(); + + private: + + CSMWorld::Data& mData; + std::string mId; + CSMWorld::CellCoordinates mCoords; + + NodeList mSelected; + + osg::Group* mParent; + osg::ref_ptr mBaseNode; + osg::ref_ptr mSelectedNode; + osg::ref_ptr mPathgridGeode; + osg::ref_ptr mSelectedGeode; + osg::ref_ptr mPathgridGeometry; + osg::ref_ptr mSelectedGeometry; + + osg::ref_ptr mTag; + + void recreateSelectedGeometry(); + void recreateSelectedGeometry(const CSMWorld::Pathgrid& source); + void removePathgridGeometry(); + void removeSelectedGeometry(); + }; +} + +#endif diff --git a/apps/opencs/view/render/pathgridmode.cpp b/apps/opencs/view/render/pathgridmode.cpp new file mode 100644 index 000000000..93b6a747d --- /dev/null +++ b/apps/opencs/view/render/pathgridmode.cpp @@ -0,0 +1,152 @@ +#include "pathgridmode.hpp" + +#include + +#include "../../model/world/commands.hpp" +#include "../../model/world/commandmacro.hpp" +#include "../../model/world/idtable.hpp" +#include "../../model/world/idtree.hpp" + +#include "mask.hpp" +#include "pathgrid.hpp" +#include "worldspacewidget.hpp" + +namespace CSVRender +{ + PathgridMode::PathgridMode(WorldspaceWidget* worldspaceWidget, QWidget* parent) + : EditMode(worldspaceWidget, QIcon(":placeholder"), Mask_Pathgrid, "Pathgrid editing", parent) + , mDragMode(DragMode_None) + , mFromNode(0) + { + } + + void PathgridMode::primaryEditPressed(const WorldspaceHitResult& hit) + { + } + + void PathgridMode::secondaryEditPressed(const WorldspaceHitResult& hit) + { + } + + void PathgridMode::primarySelectPressed(const WorldspaceHitResult& hit) + { + getWorldspaceWidget().clearSelection(Mask_Pathgrid); + + if (hit.tag) + { + if (PathgridTag* tag = dynamic_cast(hit.tag.get())) + { + unsigned short node = SceneUtil::getPathgridNode(static_cast(hit.i0)); + tag->getPathgrid()->toggleSelected(node); + } + } + } + + void PathgridMode::secondarySelectPressed(const WorldspaceHitResult& hit) + { + if (hit.tag) + { + if (PathgridTag* tag = dynamic_cast(hit.tag.get())) + { + if (tag->getPathgrid()->getId() != mLastId) + { + getWorldspaceWidget().clearSelection(Mask_Pathgrid); + mLastId = tag->getPathgrid()->getId(); + } + + unsigned short node = SceneUtil::getPathgridNode(static_cast(hit.i0)); + tag->getPathgrid()->toggleSelected(node); + + return; + } + } + + getWorldspaceWidget().clearSelection(Mask_Pathgrid); + } + + bool PathgridMode::primaryEditStartDrag(const WorldspaceHitResult& hit) + { + std::vector > selection = getWorldspaceWidget().getSelection (Mask_Pathgrid); + + if (!selection.empty()) + { + mDragMode = DragMode_Move; + return true; + } + else + { + return false; + } + } + + bool PathgridMode::secondaryEditStartDrag(const WorldspaceHitResult& hit) + { + if (hit.tag) + { + if (PathgridTag* tag = dynamic_cast(hit.tag.get())) + { + mDragMode = DragMode_Edge; + mFromNode = SceneUtil::getPathgridNode(static_cast(hit.i0)); + return true; + } + } + + return false; + } + + void PathgridMode::drag(int diffX, int diffY, double speedFactor) + { + std::vector > selection = getWorldspaceWidget().getSelection (Mask_Pathgrid); + + for (std::vector >::iterator it = selection.begin(); it != selection.end(); ++it) + { + if (PathgridTag* tag = dynamic_cast(it->get())) + { + if (mDragMode == DragMode_Move) + { + osg::Vec3d eye, center, up, offset; + getWorldspaceWidget().getCamera()->getViewMatrix().getLookAt (eye, center, up); + + offset = (up * diffY * speedFactor) + (((center - eye) ^ up) * diffX * speedFactor); + + tag->getPathgrid()->moveSelected(offset); + } + else if (mDragMode == DragMode_Edge) + { + // TODO make indicators + } + } + } + } + + void PathgridMode::dragCompleted() + { + std::vector > selection = getWorldspaceWidget().getSelection (Mask_Pathgrid); + + for (std::vector >::iterator it = selection.begin(); it != selection.end(); ++it) + { + if (PathgridTag* tag = dynamic_cast(it->get())) + { + if (mDragMode == DragMode_Move) + { + QUndoStack& undoStack = getWorldspaceWidget().getDocument().getUndoStack(); + QString description = "Move pathgrid node(s)"; + + CSMWorld::CommandMacro macro(undoStack, description); + tag->getPathgrid()->applyPosition(macro); + } + else if (mDragMode == DragMode_Edge) + { + // TODO raycast for other node and apply if needed with mFromNode + } + } + } + + mDragMode = DragMode_None; + } + + void PathgridMode::dragAborted() + { + getWorldspaceWidget().reset(Mask_Pathgrid); + } +} diff --git a/apps/opencs/view/render/pathgridmode.hpp b/apps/opencs/view/render/pathgridmode.hpp new file mode 100644 index 000000000..0a84b6b10 --- /dev/null +++ b/apps/opencs/view/render/pathgridmode.hpp @@ -0,0 +1,53 @@ +#ifndef CSV_RENDER_PATHGRIDMODE_H +#define CSV_RENDER_PATHGRIDMODE_H + +#include + +#include "editmode.hpp" + +namespace CSVRender +{ + class PathgridMode : public EditMode + { + Q_OBJECT + + public: + + PathgridMode(WorldspaceWidget* worldspace, QWidget* parent=0); + + virtual void primaryEditPressed(const WorldspaceHitResult& hit); + + virtual void secondaryEditPressed(const WorldspaceHitResult& hit); + + virtual void primarySelectPressed(const WorldspaceHitResult& hit); + + virtual void secondarySelectPressed(const WorldspaceHitResult& hit); + + virtual bool primaryEditStartDrag (const WorldspaceHitResult& hit); + + virtual bool secondaryEditStartDrag (const WorldspaceHitResult& hit); + + virtual void drag (int diffX, int diffY, double speedFactor); + + virtual void dragCompleted(); + + /// \note dragAborted will not be called, if the drag is aborted via changing + /// editing mode + virtual void dragAborted(); + + private: + + enum DragMode + { + DragMode_None, + DragMode_Move, + DragMode_Edge + }; + + std::string mLastId; + DragMode mDragMode; + unsigned short mFromNode; + }; +} + +#endif diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index e90a4fd5a..5963107e9 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -27,8 +27,8 @@ #include "object.hpp" #include "mask.hpp" -#include "editmode.hpp" #include "instancemode.hpp" +#include "pathgridmode.hpp" #include "cameracontroller.hpp" CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidget* parent) @@ -295,7 +295,7 @@ unsigned int CSVRender::WorldspaceWidget::getVisibilityMask() const void CSVRender::WorldspaceWidget::setInteractionMask (unsigned int mask) { - mInteractionMask = mask | Mask_CellMarker | Mask_CellArrow; + mInteractionMask = mask | Mask_CellMarker | Mask_CellArrow | Mask_Pathgrid | Mask_Terrain; } unsigned int CSVRender::WorldspaceWidget::getInteractionMask() const @@ -320,9 +320,7 @@ void CSVRender::WorldspaceWidget::addEditModeSelectorButtons (CSVWidget::SceneTo { /// \todo replace EditMode with suitable subclasses tool->addButton (new InstanceMode (this, tool), "object"); - tool->addButton ( - new EditMode (this, QIcon (":placeholder"), Mask_Pathgrid, "Pathgrid editing"), - "pathgrid"); + tool->addButton (new PathgridMode (this, tool), "pathgrid"); } CSMDoc::Document& CSVRender::WorldspaceWidget::getDocument() diff --git a/components/sceneutil/pathgridutil.cpp b/components/sceneutil/pathgridutil.cpp index 5d71efd1e..5078b1edb 100644 --- a/components/sceneutil/pathgridutil.cpp +++ b/components/sceneutil/pathgridutil.cpp @@ -9,6 +9,7 @@ namespace SceneUtil { const unsigned short DiamondVertexCount = 6; const unsigned short DiamondIndexCount = 24; + const unsigned short DiamondWireframeIndexCount = 24; const unsigned short DiamondConnectorVertexCount = 4; @@ -16,6 +17,7 @@ namespace SceneUtil const float DiamondHalfHeight = 40.f; const float DiamondHalfWidth = 16.f; + const float DiamondWireframeScalar = 1.1f; const osg::Vec3f DiamondPoints[DiamondVertexCount] = { @@ -39,6 +41,22 @@ namespace SceneUtil 5, 2, 4 }; + const unsigned short DiamondWireframeIndices[DiamondWireframeIndexCount] = + { + 0, 1, + 0, 2, + 0, 3, + 0, 4, + 1, 2, + 2, 4, + 4, 3, + 3, 1, + 5, 1, + 5, 2, + 5, 3, + 5, 4 + }; + const unsigned short DiamondConnectorVertices[DiamondConnectorVertexCount] = { 1, 2, 3, 4 @@ -55,6 +73,8 @@ namespace SceneUtil }; const osg::Vec4f DiamondEdgeColor = osg::Vec4f(0.5f, 1.f, 1.f, 1.f); + const osg::Vec4f DiamondWireColor = osg::Vec4f(0.8f, 1.f, 0.9f, 1.f); + const osg::Vec4f DiamondFocusWireColor = osg::Vec4f(0.4f, 1.f, 0.4f, 1.f); osg::ref_ptr createPathgridGeometry(const ESM::Pathgrid& pathgrid) { @@ -155,4 +175,61 @@ namespace SceneUtil return gridGeometry; } + + osg::ref_ptr createPathgridSelectedWireframe(const ESM::Pathgrid& pathgrid, + const std::vector& selected) + { + const unsigned short PointCount = selected.size(); + + const unsigned short VertexCount = PointCount * DiamondVertexCount; + const unsigned short ColorCount = VertexCount; + const size_t IndexCount = PointCount * DiamondWireframeIndexCount; + + osg::ref_ptr wireframeGeometry = new osg::Geometry(); + + osg::ref_ptr vertices = new osg::Vec3Array(VertexCount); + osg::ref_ptr colors = new osg::Vec4Array(ColorCount); + osg::ref_ptr indices = + new osg::DrawElementsUShort(osg::PrimitiveSet::LINES, IndexCount); + + osg::Vec3f wireOffset = osg::Vec3f(0, 0, (1 - DiamondWireframeScalar) * DiamondHalfHeight); + + // Add each point/node + for (unsigned short it = 0; it < PointCount; ++it) + { + const ESM::Pathgrid::Point& point = pathgrid.mPoints[selected[it]]; + osg::Vec3f position = osg::Vec3f(point.mX, point.mY, point.mZ) + wireOffset; + + unsigned short vertexOffset = it * DiamondVertexCount; + unsigned short indexOffset = it * DiamondWireframeIndexCount; + + // Point + for (unsigned short i = 0; i < DiamondVertexCount; ++i) + { + (*vertices)[vertexOffset + i] = position + DiamondPoints[i] * DiamondWireframeScalar; + + if (it == PointCount - 1) + (*colors)[vertexOffset + i] = DiamondFocusWireColor; + else + (*colors)[vertexOffset + i] = DiamondWireColor; + } + + for (unsigned short i = 0; i < DiamondWireframeIndexCount; ++i) + { + indices->setElement(indexOffset + i, vertexOffset + DiamondWireframeIndices[i]); + } + } + + wireframeGeometry->setVertexArray(vertices); + wireframeGeometry->setColorArray(colors, osg::Array::BIND_PER_VERTEX); + wireframeGeometry->addPrimitiveSet(indices); + wireframeGeometry->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF); + + return wireframeGeometry; + } + + unsigned short getPathgridNode(unsigned short vertexIndex) + { + return vertexIndex / (DiamondVertexCount + DiamondConnectorVertexCount); + } } diff --git a/components/sceneutil/pathgridutil.hpp b/components/sceneutil/pathgridutil.hpp index eb1ab1e3e..9a93ddf91 100644 --- a/components/sceneutil/pathgridutil.hpp +++ b/components/sceneutil/pathgridutil.hpp @@ -12,6 +12,11 @@ namespace ESM namespace SceneUtil { osg::ref_ptr createPathgridGeometry(const ESM::Pathgrid& pathgrid); + + osg::ref_ptr createPathgridSelectedWireframe(const ESM::Pathgrid& pathgrid, + const std::vector& selected); + + unsigned short getPathgridNode(unsigned short vertexIndex); } #endif