diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 816b8d732..1c04a1263 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -91,7 +91,7 @@ opencs_units (view/render 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 9a352ffad..35f08f836 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -14,6 +14,7 @@ #include "mask.hpp" #include "terrainstorage.hpp" +#include "pathgrid.hpp" bool CSVRender::Cell::removeObject (const std::string& id) { @@ -104,6 +105,11 @@ CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::st mCellBorder->buildShape(esmLand); } } + + const CSMWorld::SubCellCollection& pathgrids = mData.getPathgrids(); + int pathgridIndex = pathgrids.searchId(mId); + if (pathgridIndex != -1) + mPathgrid.reset(new Pathgrid(mCellNode, pathgrids.getRecord(pathgridIndex).get(), mCoordinates)); } } @@ -254,6 +260,46 @@ bool CSVRender::Cell::referenceAdded (const QModelIndex& parent, int start, int return addObjects (start, end); } +void CSVRender::Cell::pathgridAdded(const CSMWorld::Pathgrid& pathgrid) +{ + mPathgrid.reset(new Pathgrid(mCellNode, pathgrid, mCoordinates)); +} + +void CSVRender::Cell::pathgridRemoved() +{ + mPathgrid.reset(); +} + +bool CSVRender::Cell::pathgridDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight) +{ + if (mPathgrid.get() != 0) + { + return mPathgrid->dataChanged(topLeft, bottomRight); + } + + return false; +} + +bool CSVRender::Cell::pathgridRowAboutToBeRemoved(const QModelIndex& parent, int start, int end) +{ + if (mPathgrid.get() != 0) + { + return mPathgrid->rowAboutToBeRemoved(parent, start, end); + } + + return false; +} + +bool CSVRender::Cell::pathgridRowAdded(const QModelIndex& parent, int start, int end) +{ + if (mPathgrid.get() != 0) + { + return mPathgrid->rowAdded(parent, start, end); + } + + return false; +} + void CSVRender::Cell::setSelection (int elementMask, Selection mode) { if (elementMask & Mask_Reference) diff --git a/apps/opencs/view/render/cell.hpp b/apps/opencs/view/render/cell.hpp index 631df24aa..5f6d33e4a 100644 --- a/apps/opencs/view/render/cell.hpp +++ b/apps/opencs/view/render/cell.hpp @@ -29,12 +29,15 @@ namespace CSMWorld { class Data; class CellCoordinates; + class Pathgrid; } namespace CSVRender { class TagBase; + class Pathgrid; + class Cell { CSMWorld::Data& mData; @@ -46,6 +49,7 @@ namespace CSVRender std::auto_ptr mCellArrows[4]; std::auto_ptr mCellMarker; std::auto_ptr mCellBorder; + std::auto_ptr mPathgrid; bool mDeleted; int mSubMode; unsigned int mSubModeElementMask; @@ -103,6 +107,16 @@ namespace CSVRender /// this cell? bool referenceAdded (const QModelIndex& parent, int start, int end); + void pathgridAdded(const CSMWorld::Pathgrid& pathgrid); + + void pathgridRemoved(); + + bool pathgridDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight); + + bool pathgridRowAboutToBeRemoved(const QModelIndex& parent, int start, int end); + + bool pathgridRowAdded(const QModelIndex& parent, int start, int end); + void setSelection (int elementMask, Selection mode); // Select everything that references the same ID as at least one of the elements diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index 22b0e3805..08c6e4f68 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -275,6 +275,97 @@ void CSVRender::PagedWorldspaceWidget::referenceAdded (const QModelIndex& parent flagAsModified(); } +void CSVRender::PagedWorldspaceWidget::pathgridDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) +{ + const CSMWorld::SubCellCollection& pathgrids = mDocument.getData().getPathgrids(); + + if (topLeft.parent().isValid()) + { + int row = topLeft.parent().row(); + + const CSMWorld::Pathgrid& pathgrid = pathgrids.getRecord(row).get(); + CSMWorld::CellCoordinates coords = CSMWorld::CellCoordinates(pathgrid.mData.mX, pathgrid.mData.mY); + + std::map::iterator searchResult = mCells.find(coords); + if (searchResult != mCells.end() && searchResult->second->pathgridDataChanged(topLeft, bottomRight)) + flagAsModified(); + } +} + +void CSVRender::PagedWorldspaceWidget::pathgridAboutToBeRemoved (const QModelIndex& parent, int start, int end) +{ + const CSMWorld::SubCellCollection& pathgrids = mDocument.getData().getPathgrids(); + + if (!parent.isValid()) + { + // Pathgrid going to be deleted + for (int row = start; row <= end; ++row) + { + const CSMWorld::Pathgrid& pathgrid = pathgrids.getRecord(row).get(); + CSMWorld::CellCoordinates coords = CSMWorld::CellCoordinates(pathgrid.mData.mX, pathgrid.mData.mY); + + std::map::iterator searchResult = mCells.find(coords); + if (searchResult != mCells.end()) + { + searchResult->second->pathgridRemoved(); + flagAsModified(); + } + } + } + else + { + // Pathgrid data was modified + int row = parent.row(); + + const CSMWorld::Pathgrid& pathgrid = pathgrids.getRecord(row).get(); + CSMWorld::CellCoordinates coords = CSMWorld::CellCoordinates(pathgrid.mData.mX, pathgrid.mData.mY); + + std::map::iterator searchResult = mCells.find(coords); + if (searchResult != mCells.end()) + { + searchResult->second->pathgridRowAboutToBeRemoved(parent, start, end); + flagAsModified(); + } + } +} + +void CSVRender::PagedWorldspaceWidget::pathgridAdded(const QModelIndex& parent, int start, int end) +{ + const CSMWorld::SubCellCollection& pathgrids = mDocument.getData().getPathgrids(); + + if (!parent.isValid()) + { + // Pathgrid added theoretically, unable to test until it is possible to add pathgrids + for (int row = start; row <= end; ++row) + { + const CSMWorld::Pathgrid& pathgrid = pathgrids.getRecord(row).get(); + CSMWorld::CellCoordinates coords = CSMWorld::CellCoordinates(pathgrid.mData.mX, pathgrid.mData.mY); + + std::map::iterator searchResult = mCells.find(coords); + if (searchResult != mCells.end()) + { + searchResult->second->pathgridAdded(pathgrid); + flagAsModified(); + } + } + } + else + { + // Pathgrid data was modified + int row = parent.row(); + + const CSMWorld::Pathgrid& pathgrid = pathgrids.getRecord(row).get(); + CSMWorld::CellCoordinates coords = CSMWorld::CellCoordinates(pathgrid.mData.mX, pathgrid.mData.mY); + + std::map::iterator searchResult = mCells.find(coords); + if (searchResult != mCells.end()) + { + searchResult->second->pathgridRowAdded(parent, start, end); + flagAsModified(); + } + } +} + std::string CSVRender::PagedWorldspaceWidget::getStartupInstruction() { osg::Vec3d eye, center, up; diff --git a/apps/opencs/view/render/pagedworldspacewidget.hpp b/apps/opencs/view/render/pagedworldspacewidget.hpp index 4bdaa3820..1a6db7cbd 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.hpp +++ b/apps/opencs/view/render/pagedworldspacewidget.hpp @@ -52,6 +52,12 @@ namespace CSVRender virtual void referenceAdded (const QModelIndex& index, int start, int end); + virtual void pathgridDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight); + + virtual void pathgridAboutToBeRemoved (const QModelIndex& parent, int start, int end); + + virtual void pathgridAdded (const QModelIndex& parent, int start, int end); + virtual std::string getStartupInstruction(); /// \note Does not update the view or any cell marker diff --git a/apps/opencs/view/render/pathgrid.cpp b/apps/opencs/view/render/pathgrid.cpp new file mode 100644 index 000000000..80f02c4e1 --- /dev/null +++ b/apps/opencs/view/render/pathgrid.cpp @@ -0,0 +1,474 @@ +#include "pathgrid.hpp" + +#include + +#include +#include +#include +#include +#include + +#include + +#include "../../model/world/cellcoordinates.hpp" +#include "../../model/world/idcollection.hpp" +#include "../../model/world/pathgrid.hpp" + +#include "mask.hpp" + +namespace CSVRender +{ + const float Pathgrid::PointShapeSize = 50.f; + + Pathgrid::Pathgrid(osg::Group* parent, const CSMWorld::Pathgrid& pathgrid, const CSMWorld::CellCoordinates& coords) + : mPathgridData(pathgrid) + , mParentNode(parent) + , mBaseNode(new osg::PositionAttitudeTransform()) + , mPointGeometry(new osg::Geometry()) + , mEdgeNode(new osg::Geode()) + { + const int CoordScalar = ESM::Land::REAL_SIZE; + + mParentNode->addChild(mBaseNode); + mBaseNode->setPosition(osg::Vec3(coords.getX() * CoordScalar, coords.getY() * CoordScalar, 0)); + mBaseNode->setNodeMask(Mask_Pathgrid); + mBaseNode->addChild(mEdgeNode); + + constructPointShape(); + buildGrid(); + } + + Pathgrid::~Pathgrid() + { + destroyGrid(); + mBaseNode->removeChild(mEdgeNode); + mParentNode->removeChild(mBaseNode); + } + + bool Pathgrid::dataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight) + { + const int PointColumn = 3; + const int EdgeColumn = 4; + + if (topLeft.parent().isValid()) + { + int start = topLeft.row(); + int end = bottomRight.row(); + + if (topLeft.parent().column() == PointColumn) + { + std::set changedEdges; + + for (int row = start; row <= end; ++row) + { + // Recreate point + destroyEdges(row); + destroyPoint(row); + + buildPoint(row); + changedEdges.insert(row); + + // Correct affected edges + for (unsigned short i = 0; i < mPointData.size(); ++i) + { + PointData& data = mPointData[i]; + for (std::vector::iterator edge = data.edgeList.begin(); + edge != data.edgeList.end(); ++edge) + { + if (*edge == row) + changedEdges.insert(i); + } + } + } + + // Reconstruct edges + for (std::set::iterator index = changedEdges.begin(); + index != changedEdges.end(); ++index) + { + destroyEdges(*index); + buildEdges(*index); + } + + return true; + } + else if (topLeft.parent().column() == EdgeColumn) + { + const unsigned short NumPoints = static_cast(mPathgridData.mPoints.size()); + const size_t NumEdges = mPathgridData.mEdges.size(); + + std::set changedEdges; + + // Clear edge lists + for (int row = start; row <= end; ++row) + { + mPointData[row].edgeList.clear(); + } + + // Recreate edge lists + for (size_t i = 0; i < NumEdges; ++i) + { + const CSMWorld::Pathgrid::Edge& edge = mPathgridData.mEdges[i]; + unsigned short v0 = static_cast(edge.mV0); + unsigned short v1 = static_cast(edge.mV1); + + if ((v0 >= start && v0 <= end) && (v0 != v1 && v0 < NumPoints && v1 < NumPoints)) + mPointData[v0].edgeList.push_back(v1); + } + + // Reconstruct edges + for (int row = start; row <= end; ++row) + { + destroyEdges(row); + buildEdges(row); + } + + return true; + } + } + + return false; + } + + bool Pathgrid::rowAboutToBeRemoved(const QModelIndex& parent, int start, int end) + { + const int PointColumn = 3; + const int EdgeColumn = 4; + + if (!parent.parent().isValid()) + { + if (parent.column() == PointColumn) + { + // Dangling edges will be removed and edges past start decremented + for (size_t i = 0; i < mPointData.size(); ++i) + { + PointData& data = mPointData[i]; + + // They are getting removed anyway + if (i >= (size_t) start && i <= (size_t) end) + continue; + + bool modified = false; + + for (std::vector::iterator edge = data.edgeList.begin(); + edge != data.edgeList.end();) + { + if (*edge >= start && *edge <= end) + { + edge = data.edgeList.erase(edge); + modified = true; + } + else + { + ++edge; + } + } + + // Need to do this before modifying the rest + if (modified) + { + destroyEdges(i); + buildEdges(i); + } + + for (std::vector::iterator edge = data.edgeList.begin(); + edge != data.edgeList.end(); ++edge) + { + if (*edge > end) + --(*edge); + } + } + + // Remove points + for (int i = start; i <= end; ++i) + { + destroyEdges(static_cast(start)); + destroyPoint(static_cast(start)); + mPointData.erase(mPointData.begin() + start); + } + + return true; + } + else if (parent.column() == EdgeColumn) + { + std::set changedEdges; + + // Remove affected edges + for (int i = start; i <= end; ++i) + { + const CSMWorld::Pathgrid::Edge& edge = mPathgridData.mEdges[i]; + unsigned short v0 = static_cast(edge.mV0); + unsigned short v1 = static_cast(edge.mV1); + + // Only remove one + for (std::vector::iterator it = mPointData[v0].edgeList.begin(); + it != mPointData[v1].edgeList.end(); ++it) + { + if (*it == v1) + { + mPointData[v0].edgeList.erase(it); + changedEdges.insert(v0); + break; + } + } + } + + // Reconstruct edges + for (std::set::iterator index = changedEdges.begin(); + index != changedEdges.end(); ++index) + { + destroyEdges(*index); + buildEdges(*index); + } + } + } + + return false; + } + + bool Pathgrid::rowAdded(const QModelIndex& parent, int start, int end) + { + const int PointColumn = 3; + const int EdgeColumn = 4; + + if (!parent.parent().isValid()) + { + if (parent.column() == PointColumn) + { + // Edges at and beyond start point have been incremented + for (std::vector::iterator point = mPointData.begin(); point != mPointData.end(); ++point) + { + for (std::vector::iterator edge = point->edgeList.begin(); + edge != point->edgeList.end(); ++edge) + { + if (*edge >= start) + *edge += end - start + 1; + } + } + + // Add points + mPointData.insert(mPointData.begin() + start, end - start + 1, PointData()); + for (int row = start; row <= end; ++row) + buildPoint(static_cast(row)); + + return true; + } + else if (parent.column() == EdgeColumn) + { + const unsigned short NumPoints = static_cast(mPathgridData.mPoints.size()); + + std::set changedEdges; + + // Add edges + for (int row = start; row <= end; ++row) + { + const CSMWorld::Pathgrid::Edge& edge = mPathgridData.mEdges[row]; + unsigned short v0 = static_cast(edge.mV0); + unsigned short v1 = static_cast(edge.mV1); + + if (v0 != v1 && v0 < NumPoints && v1 < NumPoints) + { + mPointData[v0].edgeList.push_back(v1); + changedEdges.insert(v0); + } + } + + // Reconstruct edges + for (std::set::iterator index = changedEdges.begin(); + index != changedEdges.end(); ++index) + { + destroyEdges(*index); + buildEdges(*index); + } + } + } + + return false; + } + + void Pathgrid::constructPointShape() + { + // Construct a diamond + const unsigned short VertexCount = 24; + + const osg::Vec3f ShapePoints[6] = + { + osg::Vec3f( 0.f, 0.f, PointShapeSize), + osg::Vec3f(-PointShapeSize/2, -PointShapeSize/2, 0.f), + osg::Vec3f(-PointShapeSize/2, PointShapeSize/2, 0.f), + osg::Vec3f( PointShapeSize/2, -PointShapeSize/2, 0.f), + osg::Vec3f( PointShapeSize/2, PointShapeSize/2, 0.f), + osg::Vec3f( 0.f, 0.f, -PointShapeSize) + }; + + const unsigned short ShapeIndices[VertexCount] = + { + 0, 2, 1, + 0, 1, 3, + 0, 3, 4, + 0, 4, 2, + 5, 1, 2, + 5, 3, 1, + 5, 4, 3, + 5, 2, 4 + }; + + osg::ref_ptr vertexArray = new osg::Vec3Array(); + osg::ref_ptr normalArray = new osg::Vec3Array(); + osg::ref_ptr colorArray = new osg::Vec4Array(); + osg::ref_ptr indexArray = new osg::DrawElementsUShort( + osg::PrimitiveSet::TRIANGLES, 24); + + for (unsigned short i = 0; i < VertexCount; ++i) + { + vertexArray->push_back(ShapePoints[ShapeIndices[i]]); + indexArray->setElement(i, i); + } + + for (unsigned short i = 0; i < VertexCount; i += 3) + { + osg::Vec3f v1 = vertexArray->at(i+1) - vertexArray->at(i); + osg::Vec3f v2 = vertexArray->at(i+2) - vertexArray->at(i); + osg::Vec3f normal = v1 ^ v2; + + normalArray->push_back(normal); + normalArray->push_back(normal); + normalArray->push_back(normal); + } + + colorArray->push_back(osg::Vec4f(1.f, 0.f, 0.f, 1.f)); + + mPointGeometry->setVertexArray(vertexArray); + mPointGeometry->setNormalArray(normalArray, osg::Array::BIND_PER_VERTEX); + mPointGeometry->setColorArray(colorArray, osg::Array::BIND_OVERALL); + mPointGeometry->addPrimitiveSet(indexArray); + } + + void Pathgrid::buildGrid() + { + // Note: the number of pathgrid points is limited to the capacity of a signed short + const unsigned short NumPoints = static_cast(mPathgridData.mPoints.size()); + const size_t NumEdges = mPathgridData.mEdges.size(); + + // Make points + mPointData.resize(NumPoints); + for (unsigned short i = 0; i < NumPoints; ++i) + buildPoint(i); + + // Add edges to list + for (size_t i = 0; i < NumEdges; ++i) + { + const CSMWorld::Pathgrid::Edge& edge = mPathgridData.mEdges[i]; + unsigned short v0 = static_cast(edge.mV0); + unsigned short v1 = static_cast(edge.mV1); + + if (v0 != v1 && v0 < NumPoints && v1 < NumPoints) + mPointData[v0].edgeList.push_back(v1); + } + + // Make edges + for (unsigned short i = 0; i < NumPoints; ++i) + buildEdges(i); + } + + void Pathgrid::destroyGrid() + { + const unsigned short NumPoints = static_cast(mPathgridData.mPoints.size()); + + for (unsigned short i = 0; i < NumPoints; ++i) + { + destroyEdges(i); + destroyPoint(i); + } + + mPointData.clear(); + } + + void Pathgrid::buildPoint(unsigned short index) + { + const CSMWorld::Pathgrid::Point& source = mPathgridData.mPoints[index]; + PointData& data = mPointData[index]; + + data.posNode = new osg::PositionAttitudeTransform(); + data.posNode->setPosition(osg::Vec3f(source.mX, source.mY, source.mZ)); + mBaseNode->addChild(data.posNode); + + osg::ref_ptr pointNode = new osg::Geode(); + pointNode->addDrawable(mPointGeometry); + data.posNode->addChild(pointNode); + + data.edgeGeometry = new osg::Geometry(); + mEdgeNode->addDrawable(data.edgeGeometry); + } + + void Pathgrid::destroyPoint(unsigned short index) + { + PointData& data = mPointData[index]; + + mBaseNode->removeChild(data.posNode); + data.posNode = 0; + + mEdgeNode->removeDrawable(data.edgeGeometry); + data.edgeGeometry = 0; + } + + void Pathgrid::buildEdges(unsigned short index) + { + // Note: the number of edges per point is limited to the capacity of an unsigned char + const unsigned short VertexCount = static_cast(mPointData[index].edgeList.size() * 2); + const osg::Quat DefaultRotation = osg::Quat(osg::PI / 2.f, osg::Vec3f(0.f, 0.f, 1.f)); + const osg::Vec3f DefaultDirection = osg::Vec3f(0.f, 1.f, 0.f); + const osg::Vec3f Offset = osg::Vec3f(0.f, 0.f, 10.f); + const osg::Vec4f StartColor = osg::Vec4f(1.f, 0.f, 0.f, 1.f); + const osg::Vec4f EndColor = osg::Vec4f(1.f, 0.5f, 0.f, 1.f); + + if (VertexCount == 0) + return; + + // Construct geometry + osg::ref_ptr vertexArray = new osg::Vec3Array(); + osg::ref_ptr colorArray = new osg::Vec4Array(); + osg::ref_ptr indexArray = new osg::DrawElementsUShort( + osg::PrimitiveSet::LINES, VertexCount); + + for (unsigned short i = 0; i < VertexCount; i += 2) + { + const std::vector& edges = mPointData[index].edgeList; + + const CSMWorld::Pathgrid::Point& originPoint = mPathgridData.mPoints[index]; + const CSMWorld::Pathgrid::Point& destPoint = mPathgridData.mPoints[edges[i / 2]]; + + osg::Vec3f origin = osg::Vec3f(originPoint.mX, originPoint.mY, originPoint.mZ); + osg::Vec3f destination = osg::Vec3f(destPoint.mX, destPoint.mY, destPoint.mZ); + osg::Vec3f direction = destination - origin; + + direction.z() = 0; + direction.normalize(); + + // In case the x,y coordinates are too similar + if (direction.isNaN()) + direction = DefaultDirection; + + vertexArray->push_back(origin + Offset + DefaultRotation.inverse() * direction * 0.33f * PointShapeSize); + vertexArray->push_back(destination+ Offset - DefaultRotation * direction * 0.33f * PointShapeSize); + colorArray->push_back(StartColor); + colorArray->push_back(EndColor); + indexArray->setElement(i, i); + indexArray->setElement(i + 1, i + 1); + } + + osg::ref_ptr edgeGeometry = mPointData[index].edgeGeometry; + edgeGeometry->setVertexArray(vertexArray); + edgeGeometry->setColorArray(colorArray, osg::Array::BIND_PER_VERTEX); + edgeGeometry->addPrimitiveSet(indexArray); + edgeGeometry->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF); + } + + void Pathgrid::destroyEdges(unsigned short index) + { + PointData& data = mPointData[index]; + + data.edgeGeometry->setVertexArray(0); + data.edgeGeometry->setColorArray(0); + data.edgeGeometry->getPrimitiveSetList().clear(); + } +} diff --git a/apps/opencs/view/render/pathgrid.hpp b/apps/opencs/view/render/pathgrid.hpp new file mode 100644 index 000000000..589614a8f --- /dev/null +++ b/apps/opencs/view/render/pathgrid.hpp @@ -0,0 +1,74 @@ +#ifndef OPENCS_VIEW_PATHGRID_H +#define OPENCS_VIEW_PATHGRID_H + +#include + +#include +#include + +namespace osg +{ + class Geode; + class Geometry; + class Group; + class PositionAttitudeTransform; +} + +namespace CSMWorld +{ + struct Pathgrid; + class CellCoordinates; +} + +namespace CSVRender +{ + class Pathgrid + { + public: + + Pathgrid(osg::Group* parent, const CSMWorld::Pathgrid& pathgrid, const CSMWorld::CellCoordinates& coords); + ~Pathgrid(); + + bool dataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight); + + bool rowAboutToBeRemoved(const QModelIndex& parent, int start, int end); + + bool rowAdded(const QModelIndex& parent, int start, int end); + + private: + + struct PointData + { + osg::ref_ptr posNode; + std::vector edgeList; + osg::ref_ptr edgeGeometry; + }; + + static const float PointShapeSize; + + const CSMWorld::Pathgrid& mPathgridData; + std::vector mPointData; + + osg::ref_ptr mParentNode; + osg::ref_ptr mBaseNode; + osg::ref_ptr mPointGeometry; + osg::ref_ptr mEdgeNode; + + void constructPointShape(); + + void buildGrid(); + void destroyGrid(); + + void buildPoint(unsigned short index); + void destroyPoint(unsigned short index); + + void buildEdges(unsigned short index); + void destroyEdges(unsigned short index); + + // Not implemented + Pathgrid(const Pathgrid&); + Pathgrid& operator=(const Pathgrid&); + }; +} + +#endif diff --git a/apps/opencs/view/render/unpagedworldspacewidget.cpp b/apps/opencs/view/render/unpagedworldspacewidget.cpp index 79ffd4fb0..c7e875c18 100644 --- a/apps/opencs/view/render/unpagedworldspacewidget.cpp +++ b/apps/opencs/view/render/unpagedworldspacewidget.cpp @@ -32,7 +32,7 @@ void CSVRender::UnpagedWorldspaceWidget::update() } CSVRender::UnpagedWorldspaceWidget::UnpagedWorldspaceWidget (const std::string& cellId, CSMDoc::Document& document, QWidget* parent) -: WorldspaceWidget (document, parent), mCellId (cellId) +: WorldspaceWidget (document, parent), mDocument(document), mCellId (cellId) { mCellsModel = &dynamic_cast ( *document.getData().getTableModel (CSMWorld::UniversalId::Type_Cells)); @@ -197,6 +197,81 @@ void CSVRender::UnpagedWorldspaceWidget::referenceAdded (const QModelIndex& pare flagAsModified(); } +void CSVRender::UnpagedWorldspaceWidget::pathgridDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) +{ + const CSMWorld::SubCellCollection& pathgrids = mDocument.getData().getPathgrids(); + + if (topLeft.parent().isValid()) + { + int row = topLeft.parent().row(); + + const CSMWorld::Pathgrid& pathgrid = pathgrids.getRecord(row).get(); + if (mCellId == pathgrid.mId && mCell->pathgridDataChanged(topLeft, bottomRight)) + flagAsModified(); + } +} + +void CSVRender::UnpagedWorldspaceWidget::pathgridAboutToBeRemoved (const QModelIndex& parent, int start, int end) +{ + const CSMWorld::SubCellCollection& pathgrids = mDocument.getData().getPathgrids(); + + if (!parent.isValid()) + { + // Pathgrid going to be deleted + for (int row = start; row <= end; ++row) + { + const CSMWorld::Pathgrid& pathgrid = pathgrids.getRecord(row).get(); + if (mCellId == pathgrid.mId) + { + mCell->pathgridRemoved(); + flagAsModified(); + } + } + } + else + { + // Pathgrid data was modified + int row = parent.row(); + + const CSMWorld::Pathgrid& pathgrid = pathgrids.getRecord(row).get(); + if (mCellId == pathgrid.mId) + { + mCell->pathgridRowAboutToBeRemoved(parent, start, end); + flagAsModified(); + } + } +} + +void CSVRender::UnpagedWorldspaceWidget::pathgridAdded (const QModelIndex& parent, int start, int end) +{ + const CSMWorld::SubCellCollection& pathgrids = mDocument.getData().getPathgrids(); + + if (!parent.isValid()) + { + // Pathgrid added theoretically, unable to test until it is possible to add pathgrids + for (int row = start; row <= end; ++row) + { + const CSMWorld::Pathgrid& pathgrid = pathgrids.getRecord(row).get(); + if (mCellId == pathgrid.mId) + { + mCell->pathgridAdded(pathgrid); + } + } + } + else + { + // Pathgrid data was modified + int row = parent.row(); + + const CSMWorld::Pathgrid& pathgrid = pathgrids.getRecord(row).get(); + if (mCellId == pathgrid.mId) + { + mCell->pathgridRowAdded(parent, start, end); + flagAsModified(); + } + } +} + void CSVRender::UnpagedWorldspaceWidget::addVisibilitySelectorButtons ( CSVWidget::SceneToolToggle2 *tool) { diff --git a/apps/opencs/view/render/unpagedworldspacewidget.hpp b/apps/opencs/view/render/unpagedworldspacewidget.hpp index c5bfd22e6..24b511c4c 100644 --- a/apps/opencs/view/render/unpagedworldspacewidget.hpp +++ b/apps/opencs/view/render/unpagedworldspacewidget.hpp @@ -25,6 +25,7 @@ namespace CSVRender { Q_OBJECT + CSMDoc::Document& mDocument; std::string mCellId; CSMWorld::IdTable *mCellsModel; CSMWorld::IdTable *mReferenceablesModel; @@ -83,6 +84,12 @@ namespace CSVRender virtual void referenceAdded (const QModelIndex& index, int start, int end); + virtual void pathgridDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight); + + virtual void pathgridAboutToBeRemoved (const QModelIndex& parent, int start, int end); + + virtual void pathgridAdded (const QModelIndex& parent, int start, int end); + virtual std::string getStartupInstruction(); protected: diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 927ce545f..fa5fd0bee 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -59,6 +59,15 @@ CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidg connect (references, SIGNAL (rowsInserted (const QModelIndex&, int, int)), this, SLOT (referenceAdded (const QModelIndex&, int, int))); + QAbstractItemModel *pathgrids = document.getData().getTableModel (CSMWorld::UniversalId::Type_Pathgrids); + + connect (pathgrids, SIGNAL (dataChanged (const QModelIndex&, const QModelIndex&)), + this, SLOT (pathgridDataChanged (const QModelIndex&, const QModelIndex&))); + connect (pathgrids, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)), + this, SLOT (pathgridAboutToBeRemoved (const QModelIndex&, int, int))); + connect (pathgrids, SIGNAL (rowsInserted (const QModelIndex&, int, int)), + this, SLOT (pathgridAdded (const QModelIndex&, int, int))); + QAbstractItemModel *debugProfiles = document.getData().getTableModel (CSMWorld::UniversalId::Type_DebugProfiles); diff --git a/apps/opencs/view/render/worldspacewidget.hpp b/apps/opencs/view/render/worldspacewidget.hpp index b18123944..bc528f52d 100644 --- a/apps/opencs/view/render/worldspacewidget.hpp +++ b/apps/opencs/view/render/worldspacewidget.hpp @@ -228,6 +228,12 @@ namespace CSVRender virtual void referenceAdded (const QModelIndex& index, int start, int end) = 0; + virtual void pathgridDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) = 0; + + virtual void pathgridAboutToBeRemoved (const QModelIndex& parent, int start, int end) = 0; + + virtual void pathgridAdded (const QModelIndex& parent, int start, int end) = 0; + virtual void runRequest (const std::string& profile); void debugProfileDataChanged (const QModelIndex& topLeft,