From aea2380c2ba507a1c0fa1b28ca58d71431e9b9be Mon Sep 17 00:00:00 2001 From: Aesylwinn Date: Mon, 16 May 2016 17:25:02 -0400 Subject: [PATCH] Add raytrace to dragCompleted. Implement node drag connection, node and edge removal, and some fixes. --- apps/opencs/view/render/editmode.cpp | 2 +- apps/opencs/view/render/editmode.hpp | 2 +- apps/opencs/view/render/instancemode.cpp | 2 +- apps/opencs/view/render/instancemode.hpp | 2 +- apps/opencs/view/render/pathgrid.cpp | 158 ++++++++++++++++++- apps/opencs/view/render/pathgrid.hpp | 11 ++ apps/opencs/view/render/pathgridmode.cpp | 92 +++++++++-- apps/opencs/view/render/pathgridmode.hpp | 4 +- apps/opencs/view/render/worldspacewidget.cpp | 3 +- 9 files changed, 247 insertions(+), 29 deletions(-) diff --git a/apps/opencs/view/render/editmode.cpp b/apps/opencs/view/render/editmode.cpp index 8da000dc93..22de542182 100644 --- a/apps/opencs/view/render/editmode.cpp +++ b/apps/opencs/view/render/editmode.cpp @@ -59,7 +59,7 @@ bool CSVRender::EditMode::secondarySelectStartDrag (const WorldspaceHitResult& h void CSVRender::EditMode::drag (int diffX, int diffY, double speedFactor) {} -void CSVRender::EditMode::dragCompleted() {} +void CSVRender::EditMode::dragCompleted(const WorldspaceHitResult& hit) {} void CSVRender::EditMode::dragAborted() {} diff --git a/apps/opencs/view/render/editmode.hpp b/apps/opencs/view/render/editmode.hpp index 3381a7105e..37bbafdb1e 100644 --- a/apps/opencs/view/render/editmode.hpp +++ b/apps/opencs/view/render/editmode.hpp @@ -74,7 +74,7 @@ namespace CSVRender virtual void drag (int diffX, int diffY, double speedFactor); /// Default-implementation: ignored - virtual void dragCompleted(); + virtual void dragCompleted(const WorldspaceHitResult& hit); /// Default-implementation: ignored /// diff --git a/apps/opencs/view/render/instancemode.cpp b/apps/opencs/view/render/instancemode.cpp index 52335f2440..958d29337e 100644 --- a/apps/opencs/view/render/instancemode.cpp +++ b/apps/opencs/view/render/instancemode.cpp @@ -244,7 +244,7 @@ void CSVRender::InstanceMode::drag (int diffX, int diffY, double speedFactor) } } -void CSVRender::InstanceMode::dragCompleted() +void CSVRender::InstanceMode::dragCompleted(const WorldspaceHitResult& hit) { std::vector > selection = getWorldspaceWidget().getEdited (Mask_Reference); diff --git a/apps/opencs/view/render/instancemode.hpp b/apps/opencs/view/render/instancemode.hpp index 5b12529123..39e3773ad9 100644 --- a/apps/opencs/view/render/instancemode.hpp +++ b/apps/opencs/view/render/instancemode.hpp @@ -55,7 +55,7 @@ namespace CSVRender virtual void drag (int diffX, int diffY, double speedFactor); - virtual void dragCompleted(); + virtual void dragCompleted(const WorldspaceHitResult& hit); /// \note dragAborted will not be called, if the drag is aborted via changing /// editing mode diff --git a/apps/opencs/view/render/pathgrid.cpp b/apps/opencs/view/render/pathgrid.cpp index 4df9852cb4..7807525ef0 100644 --- a/apps/opencs/view/render/pathgrid.cpp +++ b/apps/opencs/view/render/pathgrid.cpp @@ -45,6 +45,8 @@ namespace CSVRender , mPathgridCollection(mData.getPathgrids()) , mId(pathgridId) , mCoords(coordinates) + , mConnectionIndicator(false) + , mConnectionNode(0) , mParent(parent) , mPathgridGeometry(0) , mSelectedGeometry(0) @@ -161,9 +163,21 @@ namespace CSVRender mSelectedNode->setPosition(mSelectedNode->getPosition() + offset); } + void Pathgrid::setupConnectionIndicator(unsigned short node) + { + mConnectionIndicator = true; + mConnectionNode = node; + recreateSelectedGeometry(); + } + void Pathgrid::resetMove() { mSelectedNode->setPosition(osg::Vec3f(0,0,0)); + if (mConnectionIndicator) + { + mConnectionIndicator = false; + recreateSelectedGeometry(); + } } void Pathgrid::applyPoint(CSMWorld::CommandMacro& commands, const osg::Vec3d& worldPos) @@ -249,18 +263,88 @@ namespace CSVRender point.mZ + offsetZ)); } } - - resetMove(); } void Pathgrid::applyEdge(CSMWorld::CommandMacro& commands, unsigned short node1, unsigned short node2) { - // TODO + const CSMWorld::Pathgrid* source = getPathgridSource(); + if (source) + { + addEdge(commands, *source, node1, node2); + } } void Pathgrid::applyEdges(CSMWorld::CommandMacro& commands, unsigned short node) { - // TODO + const CSMWorld::Pathgrid* source = getPathgridSource(); + if (source) + { + for (size_t i = 0; i < mSelected.size(); ++i) + { + addEdge(commands, *source, node, mSelected[i]); + } + } + } + + void Pathgrid::applyRemoveNodes(CSMWorld::CommandMacro& commands) + { + // Source is aquired here to ensure a pathgrid exists + const CSMWorld::Pathgrid* source = getPathgridSource(); + if (source) + { + // Want to remove from end of row first + std::sort(mSelected.begin(), mSelected.end(), std::greater()); + + CSMWorld::IdTree* model = dynamic_cast(mData.getTableModel( + CSMWorld::UniversalId::Type_Pathgrids)); + + int parentColumn = mPathgridCollection.findColumnIndex(CSMWorld::Columns::ColumnId_PathgridPoints); + + for (std::vector::iterator row = mSelected.begin(); row != mSelected.end(); ++row) + { + commands.push(new CSMWorld::DeleteNestedCommand(*model, mId, static_cast(*row), parentColumn)); + } + } + + clearSelected(); + } + + void Pathgrid::applyRemoveEdges(CSMWorld::CommandMacro& commands) + { + const CSMWorld::Pathgrid* source = getPathgridSource(); + if (source) + { + // Want to remove from end of row first + std::set > rowsToRemove; + for (size_t i = 0; i <= mSelected.size(); ++i) + { + for (size_t j = i + 1; j < mSelected.size(); ++j) + { + int row = edgeExists(*source, mSelected[i], mSelected[j]); + if (row != -1) + { + rowsToRemove.insert(row); + } + + row = edgeExists(*source, mSelected[j], mSelected[i]); + if (row != -1) + { + rowsToRemove.insert(row); + } + } + } + + CSMWorld::IdTree* model = dynamic_cast(mData.getTableModel( + CSMWorld::UniversalId::Type_Pathgrids)); + + int parentColumn = mPathgridCollection.findColumnIndex(CSMWorld::Columns::ColumnId_PathgridEdges); + + std::set >::iterator row; + for (row = rowsToRemove.begin(); row != rowsToRemove.end(); ++row) + { + commands.push(new CSMWorld::DeleteNestedCommand(*model, mId, *row, parentColumn)); + } + } } osg::ref_ptr Pathgrid::getTag() const @@ -303,8 +387,25 @@ namespace CSVRender void Pathgrid::recreateSelectedGeometry(const CSMWorld::Pathgrid& source) { removeSelectedGeometry(); - mSelectedGeometry = SceneUtil::createPathgridSelectedWireframe(source, mSelected); - mSelectedGeode->addDrawable(mSelectedGeometry); + + if (mConnectionIndicator) + { + NodeList tempList = NodeList(mSelected); + + NodeList::iterator searchResult = std::find(tempList.begin(), tempList.end(), mConnectionNode); + if (searchResult != tempList.end()) + tempList.erase(searchResult); + + tempList.push_back(mConnectionNode); + + mSelectedGeometry = SceneUtil::createPathgridSelectedWireframe(source, tempList); + mSelectedGeode->addDrawable(mSelectedGeometry); + } + else + { + mSelectedGeometry = SceneUtil::createPathgridSelectedWireframe(source, mSelected); + mSelectedGeode->addDrawable(mSelectedGeometry); + } } void Pathgrid::removePathgridGeometry() @@ -335,4 +436,49 @@ namespace CSVRender return 0; } + + int Pathgrid::edgeExists(const CSMWorld::Pathgrid& source, unsigned short node1, unsigned short node2) + { + for (size_t i = 0; i < source.mEdges.size(); ++i) + { + if (source.mEdges[i].mV0 == node1 && source.mEdges[i].mV1 == node2) + return static_cast(i); + } + + return -1; + } + + void Pathgrid::addEdge(CSMWorld::CommandMacro& commands, const CSMWorld::Pathgrid& source, unsigned short node1, + unsigned short node2) + { + CSMWorld::IdTree* model = dynamic_cast(mData.getTableModel( + CSMWorld::UniversalId::Type_Pathgrids)); + + int recordIndex = mPathgridCollection.getIndex(mId); + int parentColumn = mPathgridCollection.findColumnIndex(CSMWorld::Columns::ColumnId_PathgridEdges); + + int edge0Column = mPathgridCollection.searchNestedColumnIndex(parentColumn, + CSMWorld::Columns::ColumnId_PathgridEdge0); + + int edge1Column = mPathgridCollection.searchNestedColumnIndex(parentColumn, + CSMWorld::Columns::ColumnId_PathgridEdge1); + + QModelIndex parent = model->index(recordIndex, parentColumn); + int row = static_cast(source.mEdges.size()); + + if (edgeExists(source, node1, node2) == -1) + { + commands.push(new CSMWorld::AddNestedCommand(*model, mId, row, parentColumn)); + commands.push(new CSMWorld::ModifyCommand(*model, model->index(row, edge0Column, parent), node1)); + commands.push(new CSMWorld::ModifyCommand(*model, model->index(row, edge1Column, parent), node2)); + ++row; + } + + if (edgeExists(source, node2, node1) == -1) + { + commands.push(new CSMWorld::AddNestedCommand(*model, mId, row, parentColumn)); + commands.push(new CSMWorld::ModifyCommand(*model, model->index(row, edge0Column, parent), node2)); + commands.push(new CSMWorld::ModifyCommand(*model, model->index(row, edge1Column, parent), node1)); + } + } } diff --git a/apps/opencs/view/render/pathgrid.hpp b/apps/opencs/view/render/pathgrid.hpp index a820417408..62ecef4d66 100644 --- a/apps/opencs/view/render/pathgrid.hpp +++ b/apps/opencs/view/render/pathgrid.hpp @@ -71,10 +71,14 @@ namespace CSVRender void moveSelected(const osg::Vec3d& offset); void resetMove(); + void setupConnectionIndicator(unsigned short node); + void applyPoint(CSMWorld::CommandMacro& commands, const osg::Vec3d& worldPos); void applyPosition(CSMWorld::CommandMacro& commands); void applyEdge(CSMWorld::CommandMacro& commands, unsigned short node1, unsigned short node2); void applyEdges(CSMWorld::CommandMacro& commands, unsigned short node); + void applyRemoveNodes(CSMWorld::CommandMacro& commands); + void applyRemoveEdges(CSMWorld::CommandMacro& commands); osg::ref_ptr getTag() const; @@ -88,6 +92,8 @@ namespace CSVRender CSMWorld::CellCoordinates mCoords; NodeList mSelected; + bool mConnectionIndicator; + unsigned short mConnectionNode; osg::Group* mParent; osg::ref_ptr mBaseNode; @@ -106,6 +112,11 @@ namespace CSVRender const CSMWorld::Pathgrid* getPathgridSource(); + int edgeExists(const CSMWorld::Pathgrid& source, unsigned short node1, unsigned short node2); + void addEdge(CSMWorld::CommandMacro& commands, const CSMWorld::Pathgrid& source, unsigned short node1, + unsigned short node2); + void removeEdge(CSMWorld::CommandMacro& commands, const CSMWorld::Pathgrid& source, unsigned short node1, + unsigned short node2); }; } diff --git a/apps/opencs/view/render/pathgridmode.cpp b/apps/opencs/view/render/pathgridmode.cpp index c06618e74a..e4b0e0994b 100644 --- a/apps/opencs/view/render/pathgridmode.cpp +++ b/apps/opencs/view/render/pathgridmode.cpp @@ -102,6 +102,22 @@ namespace CSVRender void PathgridMode::secondaryEditPressed(const WorldspaceHitResult& hit) { + if (hit.tag) + { + if (PathgridTag* tag = dynamic_cast(hit.tag.get())) + { + if (tag->getPathgrid()->isSelected()) + { + unsigned short node = SceneUtil::getPathgridNode(static_cast(hit.index0)); + + QUndoStack& undoStack = getWorldspaceWidget().getDocument().getUndoStack(); + QString description = "Connect node to selected nodes"; + + CSMWorld::CommandMacro macro(undoStack, description); + tag->getPathgrid()->applyEdges(macro, node); + } + } + } } void PathgridMode::primarySelectPressed(const WorldspaceHitResult& hit) @@ -112,6 +128,7 @@ namespace CSVRender { if (PathgridTag* tag = dynamic_cast(hit.tag.get())) { + mLastId = tag->getPathgrid()->getId(); unsigned short node = SceneUtil::getPathgridNode(static_cast(hit.index0)); tag->getPathgrid()->toggleSelected(node); } @@ -147,12 +164,9 @@ namespace CSVRender if (!selection.empty()) { mDragMode = DragMode_Move; - return true; - } - else - { - return false; } + + return true; } bool PathgridMode::secondaryEditStartDrag(const WorldspaceHitResult& hit) @@ -162,12 +176,14 @@ namespace CSVRender if (PathgridTag* tag = dynamic_cast(hit.tag.get())) { mDragMode = DragMode_Edge; + mEdgeId = tag->getPathgrid()->getId(); mFromNode = SceneUtil::getPathgridNode(static_cast(hit.index0)); - return true; + + tag->getPathgrid()->setupConnectionIndicator(mFromNode); } } - return false; + return true; } void PathgridMode::drag(int diffX, int diffY, double speedFactor) @@ -189,21 +205,20 @@ namespace CSVRender } else if (mDragMode == DragMode_Edge) { - // TODO make indicators + // TODO Add indicator, need raytrace } } } } - void PathgridMode::dragCompleted() + void PathgridMode::dragCompleted(const WorldspaceHitResult& hit) { - std::vector > selection = getWorldspaceWidget().getSelection (Mask_Pathgrid); - - for (std::vector >::iterator it = selection.begin(); it != selection.end(); ++it) + if (mDragMode == DragMode_Move) { - if (PathgridTag* tag = dynamic_cast(it->get())) + std::vector > selection = getWorldspaceWidget().getSelection (Mask_Pathgrid); + for (std::vector >::iterator it = selection.begin(); it != selection.end(); ++it) { - if (mDragMode == DragMode_Move) + if (PathgridTag* tag = dynamic_cast(it->get())) { QUndoStack& undoStack = getWorldspaceWidget().getDocument().getUndoStack(); QString description = "Move pathgrid node(s)"; @@ -211,14 +226,33 @@ namespace CSVRender CSMWorld::CommandMacro macro(undoStack, description); tag->getPathgrid()->applyPosition(macro); } - else if (mDragMode == DragMode_Edge) + } + } + else if (mDragMode == DragMode_Edge) + { + if (hit.tag) + { + if (PathgridTag* tag = dynamic_cast(hit.tag.get())) { - // TODO raycast for other node and apply if needed with mFromNode + if (tag->getPathgrid()->getId() == mEdgeId) + { + unsigned short toNode = SceneUtil::getPathgridNode(static_cast(hit.index0)); + + QUndoStack& undoStack = getWorldspaceWidget().getDocument().getUndoStack(); + QString description = "Add edge between nodes"; + + CSMWorld::CommandMacro macro(undoStack, description); + tag->getPathgrid()->applyEdge(macro, mFromNode, toNode); + } } } + + mEdgeId.clear(); + mFromNode = 0; } mDragMode = DragMode_None; + getWorldspaceWidget().reset(Mask_Pathgrid); } void PathgridMode::dragAborted() @@ -244,9 +278,35 @@ namespace CSVRender void PathgridMode::removeSelected() { + 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())) + { + QUndoStack& undoStack = getWorldspaceWidget().getDocument().getUndoStack(); + QString description = "Remove selected nodes"; + + CSMWorld::CommandMacro macro(undoStack, description); + tag->getPathgrid()->applyRemoveNodes(macro); + } + } } void PathgridMode::removeSelectedEdges() { + 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())) + { + QUndoStack& undoStack = getWorldspaceWidget().getDocument().getUndoStack(); + QString description = "Remove edges between selected nodes"; + + CSMWorld::CommandMacro macro(undoStack, description); + tag->getPathgrid()->applyRemoveEdges(macro); + } + } } } diff --git a/apps/opencs/view/render/pathgridmode.hpp b/apps/opencs/view/render/pathgridmode.hpp index b6a650eb4b..6a070333d0 100644 --- a/apps/opencs/view/render/pathgridmode.hpp +++ b/apps/opencs/view/render/pathgridmode.hpp @@ -33,7 +33,7 @@ namespace CSVRender virtual void drag (int diffX, int diffY, double speedFactor); - virtual void dragCompleted(); + virtual void dragCompleted(const WorldspaceHitResult& hit); /// \note dragAborted will not be called, if the drag is aborted via changing /// editing mode @@ -48,8 +48,8 @@ namespace CSVRender DragMode_Edge }; - std::string mLastId; DragMode mDragMode; + std::string mLastId, mEdgeId; unsigned short mFromNode; QAction* mSelectAll; diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index cd65bd8e87..9146de6199 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -712,8 +712,9 @@ void CSVRender::WorldspaceWidget::mouseReleaseEvent (QMouseEvent *event) if (mDragging) { EditMode& editMode = dynamic_cast (*mEditMode->getCurrent()); + WorldspaceHitResult hit = mousePick (event->pos()); - editMode.dragCompleted(); + editMode.dragCompleted(hit); mDragging = false; } else