diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index 9a352ffad..691b909bb 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -1,10 +1,14 @@ #include "cell.hpp" +#include +#include +#include #include #include #include #include +#include #include "../../model/world/idtable.hpp" #include "../../model/world/columns.hpp" @@ -64,6 +68,18 @@ 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), @@ -77,6 +93,17 @@ 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) @@ -104,6 +131,8 @@ CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::st mCellBorder->buildShape(esmLand); } } + + recreatePathgrid(); } } @@ -254,6 +283,31 @@ bool CSVRender::Cell::referenceAdded (const QModelIndex& parent, int start, int return addObjects (start, end); } +void CSVRender::Cell::pathgridAdded(const CSMWorld::Pathgrid& pathgrid) +{ + recreatePathgrid(); +} + +void CSVRender::Cell::pathgridRemoved() +{ + mPathgridGeode->removeDrawable(mPathgridGeometry); +} + +void CSVRender::Cell::pathgridDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight) +{ + recreatePathgrid(); +} + +void CSVRender::Cell::pathgridRowRemoved(const QModelIndex& parent, int start, int end) +{ + recreatePathgrid(); +} + +void CSVRender::Cell::pathgridRowAdded(const QModelIndex& parent, int start, int end) +{ + recreatePathgrid(); +} + 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..e265fc21c 100644 --- a/apps/opencs/view/render/cell.hpp +++ b/apps/opencs/view/render/cell.hpp @@ -23,12 +23,15 @@ class QModelIndex; namespace osg { class Group; + class Geometry; + class Geode; } namespace CSMWorld { class Data; class CellCoordinates; + class Pathgrid; } namespace CSVRender @@ -40,6 +43,8 @@ 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; @@ -64,6 +69,8 @@ namespace CSVRender /// \return Have any objects been added? bool addObjects (int start, int end); + void recreatePathgrid(); + public: enum Selection @@ -103,6 +110,16 @@ namespace CSVRender /// this cell? bool referenceAdded (const QModelIndex& parent, int start, int end); + void pathgridAdded(const CSMWorld::Pathgrid& pathgrid); + + void pathgridRemoved(); + + void pathgridDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight); + + void pathgridRowRemoved(const QModelIndex& parent, int start, int end); + + void 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..1d9b22216 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -275,6 +275,107 @@ 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::pathgridRemoved (const QModelIndex& parent, int start, int end) +{ + const CSMWorld::SubCellCollection& pathgrids = mDocument.getData().getPathgrids(); + + if (parent.isValid()) + { + // 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->pathgridRowRemoved(parent, start, end); + 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(); + } + } + } +} + +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..3cd628df0 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.hpp +++ b/apps/opencs/view/render/pagedworldspacewidget.hpp @@ -52,6 +52,14 @@ namespace CSVRender virtual void referenceAdded (const QModelIndex& index, int start, int end); + virtual void pathgridDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight); + + virtual void pathgridRemoved (const QModelIndex& parent, int start, int end); + + 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/unpagedworldspacewidget.cpp b/apps/opencs/view/render/unpagedworldspacewidget.cpp index 79ffd4fb0..84b7a0ca8 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,90 @@ 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::pathgridRemoved (const QModelIndex& parent, int start, int end) +{ + const CSMWorld::SubCellCollection& pathgrids = mDocument.getData().getPathgrids(); + + if (parent.isValid()){ + // Pathgrid data was modified + int row = parent.row(); + + const CSMWorld::Pathgrid& pathgrid = pathgrids.getRecord(row).get(); + if (mCellId == pathgrid.mId) + { + mCell->pathgridRowRemoved(parent, start, end); + 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(); + } + } + } +} + +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); + flagAsModified(); + } + } + } + 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..f06302032 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,15 @@ namespace CSVRender virtual void referenceAdded (const QModelIndex& index, int start, int end); + virtual void pathgridDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight); + + virtual void pathgridRemoved (const QModelIndex& parent, int start, int end); + + 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..1bd3df981 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -59,6 +59,17 @@ 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 (rowsRemoved (const QModelIndex&, int, int)), + this, SLOT (pathgridRemoved (const QModelIndex&, int, int))); + 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..d70694d22 100644 --- a/apps/opencs/view/render/worldspacewidget.hpp +++ b/apps/opencs/view/render/worldspacewidget.hpp @@ -228,6 +228,15 @@ 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 pathgridRemoved (const QModelIndex& parent, int start, int end) = 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, diff --git a/apps/openmw/mwrender/pathgrid.cpp b/apps/openmw/mwrender/pathgrid.cpp index d79604a91..aae97fe35 100644 --- a/apps/openmw/mwrender/pathgrid.cpp +++ b/apps/openmw/mwrender/pathgrid.cpp @@ -8,6 +8,7 @@ #include #include +#include #include "../mwbase/world.hpp" // these includes can be removed once the static-hack is gone #include "../mwbase/environment.hpp" @@ -23,107 +24,6 @@ namespace MWRender { -static const int POINT_MESH_BASE = 35; - -osg::ref_ptr Pathgrid::createPathgridLines(const ESM::Pathgrid *pathgrid) -{ - osg::ref_ptr geom = new osg::Geometry; - - osg::ref_ptr vertices = new osg::Vec3Array; - - for(ESM::Pathgrid::EdgeList::const_iterator it = pathgrid->mEdges.begin(); - it != pathgrid->mEdges.end(); - ++it) - { - const ESM::Pathgrid::Edge &edge = *it; - const ESM::Pathgrid::Point &p1 = pathgrid->mPoints[edge.mV0], &p2 = pathgrid->mPoints[edge.mV1]; - - osg::Vec3f direction = MWMechanics::PathFinder::MakeOsgVec3(p2) - MWMechanics::PathFinder::MakeOsgVec3(p1); - osg::Vec3f lineDisplacement = (direction^osg::Vec3f(0,0,1)); - lineDisplacement.normalize(); - - lineDisplacement = lineDisplacement * POINT_MESH_BASE + - osg::Vec3f(0, 0, 10); // move lines up a little, so they will be less covered by meshes/landscape - - vertices->push_back(MWMechanics::PathFinder::MakeOsgVec3(p1) + lineDisplacement); - vertices->push_back(MWMechanics::PathFinder::MakeOsgVec3(p2) + lineDisplacement); - } - - geom->setVertexArray(vertices); - - geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINES, 0, vertices->size())); - - osg::ref_ptr colors = new osg::Vec4Array; - colors->push_back(osg::Vec4(1.f, 1.f, 0.f, 1.f)); - geom->setColorArray(colors, osg::Array::BIND_OVERALL); - - return geom; -} - -osg::ref_ptr Pathgrid::createPathgridPoints(const ESM::Pathgrid *pathgrid) -{ - osg::ref_ptr geom = new osg::Geometry; - - const float height = POINT_MESH_BASE * sqrtf(2); - - osg::ref_ptr vertices = new osg::Vec3Array; - osg::ref_ptr indices = new osg::UShortArray; - - bool first = true; - unsigned short startIndex = 0; - for(ESM::Pathgrid::PointList::const_iterator it = pathgrid->mPoints.begin(); - it != pathgrid->mPoints.end(); - ++it, startIndex += 6) - { - osg::Vec3f pointPos(MWMechanics::PathFinder::MakeOsgVec3(*it)); - - if (!first) - { - // degenerate triangle from previous octahedron - indices->push_back(startIndex - 4); // 2nd point of previous octahedron - indices->push_back(startIndex); // start point of current octahedron - } - - float pointMeshBase = static_cast(POINT_MESH_BASE); - - vertices->push_back(pointPos + osg::Vec3f(0, 0, height)); // 0 - vertices->push_back(pointPos + osg::Vec3f(-pointMeshBase, -pointMeshBase, 0)); // 1 - vertices->push_back(pointPos + osg::Vec3f(pointMeshBase, -pointMeshBase, 0)); // 2 - vertices->push_back(pointPos + osg::Vec3f(pointMeshBase, pointMeshBase, 0)); // 3 - vertices->push_back(pointPos + osg::Vec3f(-pointMeshBase, pointMeshBase, 0)); // 4 - vertices->push_back(pointPos + osg::Vec3f(0, 0, -height)); // 5 - - indices->push_back(startIndex + 0); - indices->push_back(startIndex + 1); - indices->push_back(startIndex + 2); - indices->push_back(startIndex + 5); - indices->push_back(startIndex + 3); - indices->push_back(startIndex + 4); - // degenerates - indices->push_back(startIndex + 4); - indices->push_back(startIndex + 5); - indices->push_back(startIndex + 5); - // end degenerates - indices->push_back(startIndex + 1); - indices->push_back(startIndex + 4); - indices->push_back(startIndex + 0); - indices->push_back(startIndex + 3); - indices->push_back(startIndex + 2); - - first = false; - } - - geom->setVertexArray(vertices); - - geom->addPrimitiveSet(new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLE_STRIP, indices->size(), &(*indices)[0])); - - osg::ref_ptr colors = new osg::Vec4Array; - colors->push_back(osg::Vec4(1.f, 0.f, 0.f, 1.f)); - geom->setColorArray(colors, osg::Array::BIND_OVERALL); - - return geom; -} - Pathgrid::Pathgrid(osg::ref_ptr root) : mPathgridEnabled(false) , mRootNode(root) @@ -212,12 +112,9 @@ void Pathgrid::enableCellPathgrid(const MWWorld::CellStore *store) osg::ref_ptr cellPathGrid = new osg::PositionAttitudeTransform; cellPathGrid->setPosition(cellPathGridPos); - osg::ref_ptr lines = createPathgridLines(pathgrid); + osg::ref_ptr geometry = SceneUtil::createPathgridGeometry(*pathgrid); - osg::ref_ptr points = createPathgridPoints(pathgrid); - - cellPathGrid->addChild(lines); - cellPathGrid->addChild(points); + cellPathGrid->addChild(geometry); mPathGridRoot->addChild(cellPathGrid); diff --git a/apps/openmw/mwrender/pathgrid.hpp b/apps/openmw/mwrender/pathgrid.hpp index 39a6d71ed..22bfa8e73 100644 --- a/apps/openmw/mwrender/pathgrid.hpp +++ b/apps/openmw/mwrender/pathgrid.hpp @@ -48,9 +48,6 @@ namespace MWRender void enableCellPathgrid(const MWWorld::CellStore *store); void disableCellPathgrid(const MWWorld::CellStore *store); - // path grid meshes - osg::ref_ptr createPathgridLines(const ESM::Pathgrid *pathgrid); - osg::ref_ptr createPathgridPoints(const ESM::Pathgrid *pathgrid); public: Pathgrid(osg::ref_ptr root); ~Pathgrid(); diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 2508cdc82..db8904f2b 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -22,7 +22,7 @@ endif (GIT_CHECKOUT) if (OPENGL_ES) find_package(OpenGLES REQUIRED) -else() +else() find_package(OpenGL REQUIRED) endif() @@ -50,7 +50,7 @@ add_component_dir (shader add_component_dir (sceneutil clone attach visitor util statesetupdater controller skeleton riggeometry lightcontroller - lightmanager lightutil positionattitudetransform workqueue unrefqueue + lightmanager lightutil positionattitudetransform workqueue unrefqueue pathgridutil ) add_component_dir (nif @@ -191,7 +191,7 @@ else() set(GL_LIB ${OPENGL_gl_LIBRARY}) endif() -target_link_libraries(components +target_link_libraries(components ${Boost_SYSTEM_LIBRARY} ${Boost_FILESYSTEM_LIBRARY} ${Boost_THREAD_LIBRARY} diff --git a/components/sceneutil/pathgridutil.cpp b/components/sceneutil/pathgridutil.cpp new file mode 100644 index 000000000..5d71efd1e --- /dev/null +++ b/components/sceneutil/pathgridutil.cpp @@ -0,0 +1,158 @@ +#include "pathgridutil.hpp" + +#include + +#include +#include + +namespace SceneUtil +{ + const unsigned short DiamondVertexCount = 6; + const unsigned short DiamondIndexCount = 24; + + const unsigned short DiamondConnectorVertexCount = 4; + + const unsigned short DiamondTotalVertexCount = DiamondVertexCount + DiamondConnectorVertexCount; + + const float DiamondHalfHeight = 40.f; + const float DiamondHalfWidth = 16.f; + + const osg::Vec3f DiamondPoints[DiamondVertexCount] = + { + osg::Vec3f( 0.f, 0.f, DiamondHalfHeight * 2.f), + osg::Vec3f(-DiamondHalfWidth, -DiamondHalfWidth, DiamondHalfHeight), + osg::Vec3f(-DiamondHalfWidth, DiamondHalfWidth, DiamondHalfHeight), + osg::Vec3f( DiamondHalfWidth, -DiamondHalfWidth, DiamondHalfHeight), + osg::Vec3f( DiamondHalfWidth, DiamondHalfWidth, DiamondHalfHeight), + osg::Vec3f( 0.f, 0.f, 0.f) + }; + + const unsigned short DiamondIndices[DiamondIndexCount] = + { + 0, 2, 1, + 0, 1, 3, + 0, 3, 4, + 0, 4, 2, + 5, 1, 2, + 5, 3, 1, + 5, 4, 3, + 5, 2, 4 + }; + + const unsigned short DiamondConnectorVertices[DiamondConnectorVertexCount] = + { + 1, 2, 3, 4 + }; + + const osg::Vec4f DiamondColors[DiamondVertexCount] = + { + osg::Vec4f(0.f, 0.f, 1.f, 1.f), + osg::Vec4f(0.f, .05f, .95f, 1.f), + osg::Vec4f(0.f, .1f, .95f, 1.f), + osg::Vec4f(0.f, .15f, .95f, 1.f), + osg::Vec4f(0.f, .2f, .95f, 1.f), + osg::Vec4f(0.f, .25f, 9.f, 1.f) + }; + + const osg::Vec4f DiamondEdgeColor = osg::Vec4f(0.5f, 1.f, 1.f, 1.f); + + osg::ref_ptr createPathgridGeometry(const ESM::Pathgrid& pathgrid) + { + const unsigned short PointCount = static_cast(pathgrid.mPoints.size()); + const size_t EdgeCount = pathgrid.mEdges.size(); + + const unsigned short VertexCount = PointCount * DiamondTotalVertexCount; + const unsigned short ColorCount = VertexCount; + const size_t PointIndexCount = PointCount * DiamondIndexCount; + const size_t EdgeIndexCount = EdgeCount * 2; + + osg::ref_ptr gridGeometry = new osg::Geometry(); + + osg::ref_ptr vertices = new osg::Vec3Array(VertexCount); + osg::ref_ptr colors = new osg::Vec4Array(ColorCount); + osg::ref_ptr pointIndices = + new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLES, PointIndexCount); + osg::ref_ptr lineIndices = + new osg::DrawElementsUShort(osg::PrimitiveSet::LINES, EdgeIndexCount); + + // Add each point/node + for (unsigned short pointIndex = 0; pointIndex < PointCount; ++pointIndex) + { + const ESM::Pathgrid::Point& point = pathgrid.mPoints[pointIndex]; + osg::Vec3f position = osg::Vec3f(point.mX, point.mY, point.mZ); + + unsigned short vertexOffset = pointIndex * DiamondTotalVertexCount; + unsigned short indexOffset = pointIndex * DiamondIndexCount; + + // Point + for (unsigned short i = 0; i < DiamondVertexCount; ++i) + { + (*vertices)[vertexOffset + i] = position + DiamondPoints[i]; + (*colors)[vertexOffset + i] = DiamondColors[i]; + } + + for (unsigned short i = 0; i < DiamondIndexCount; ++i) + { + pointIndices->setElement(indexOffset + i, vertexOffset + DiamondIndices[i]); + } + + // Connectors + vertexOffset += DiamondVertexCount; + for (unsigned short i = 0; i < DiamondConnectorVertexCount; ++i) + { + (*vertices)[vertexOffset + i] = position + DiamondPoints[DiamondConnectorVertices[i]]; + (*colors)[vertexOffset + i] = DiamondEdgeColor; + } + } + + // Add edges + unsigned short lineIndex = 0; + + for (ESM::Pathgrid::EdgeList::const_iterator edge = pathgrid.mEdges.begin(); + edge != pathgrid.mEdges.end(); ++edge) + { + if (edge->mV0 == edge->mV1 || edge->mV0 < 0 || edge->mV0 >= PointCount || + edge->mV1 < 0 || edge->mV1 >= PointCount) + continue; + + const ESM::Pathgrid::Point& from = pathgrid.mPoints[edge->mV0]; + const ESM::Pathgrid::Point& to = pathgrid.mPoints[edge->mV1]; + + osg::Vec3f fromPos = osg::Vec3f(from.mX, from.mY, from.mZ); + osg::Vec3f toPos = osg::Vec3f(to.mX, to.mY, to.mZ); + osg::Vec3f dir = toPos - fromPos; + dir.normalize(); + + osg::Quat rot = osg::Quat(-osg::PI / 2, osg::Vec3(0, 0, 1)); + dir = rot * dir; + + unsigned short diamondIndex = 0; + if (dir.isNaN()) + diamondIndex = 0; + else if (dir.y() >= 0 && dir.x() > 0) + diamondIndex = 3; + else if (dir.x() <= 0 && dir.y() > 0) + diamondIndex = 1; + else if (dir.y() <= 0 && dir.x() < 0) + diamondIndex = 0; + else if (dir.x() >= 0 && dir.y() < 0) + diamondIndex = 2; + + unsigned short fromIndex = static_cast(edge->mV0); + unsigned short toIndex = static_cast(edge->mV1); + + lineIndices->setElement(lineIndex++, fromIndex * DiamondTotalVertexCount + DiamondVertexCount + diamondIndex); + lineIndices->setElement(lineIndex++, toIndex * DiamondTotalVertexCount + DiamondVertexCount + diamondIndex); + } + + lineIndices->resize(lineIndex); + + gridGeometry->setVertexArray(vertices); + gridGeometry->setColorArray(colors, osg::Array::BIND_PER_VERTEX); + gridGeometry->addPrimitiveSet(pointIndices); + gridGeometry->addPrimitiveSet(lineIndices); + gridGeometry->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF); + + return gridGeometry; + } +} diff --git a/components/sceneutil/pathgridutil.hpp b/components/sceneutil/pathgridutil.hpp new file mode 100644 index 000000000..d547bbf3e --- /dev/null +++ b/components/sceneutil/pathgridutil.hpp @@ -0,0 +1,17 @@ +#ifndef OPENMW_COMPONENTS_PATHGRIDUTIL_H +#define OPENMW_COMPONENTS_PATHGRIDUTIL_H + +#include +#include + +namespace ESM +{ + class Pathgrid; +} + +namespace SceneUtil +{ + osg::ref_ptr createPathgridGeometry(const ESM::Pathgrid& pathgrid); +} + +#endif