From 0d35938794f161a84ff66ae587e95fae8e0f2c12 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 12 Oct 2015 14:12:01 +0200 Subject: [PATCH 1/9] basic cell arrow rendering (shape is a placeholder) --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/view/render/cell.cpp | 24 +++++ apps/opencs/view/render/cell.hpp | 8 ++ apps/opencs/view/render/cellarrow.cpp | 93 +++++++++++++++++++ apps/opencs/view/render/cellarrow.hpp | 70 ++++++++++++++ .../view/render/pagedworldspacewidget.cpp | 32 +++++++ 6 files changed, 228 insertions(+), 1 deletion(-) create mode 100644 apps/opencs/view/render/cellarrow.cpp create mode 100644 apps/opencs/view/render/cellarrow.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 196e899b2..6af04e8fc 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -90,7 +90,7 @@ opencs_units (view/render opencs_units_noqt (view/render lighting lightingday lightingnight - lightingbright object cell terrainstorage tagbase + lightingbright object cell terrainstorage tagbase cellarrow ) opencs_hdrs_noqt (view/render diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index c4f744510..345bc79a7 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -9,6 +9,7 @@ #include "../../model/world/columns.hpp" #include "../../model/world/data.hpp" #include "../../model/world/refcollection.hpp" +#include "../../model/world/cellcoordinates.hpp" #include "elements.hpp" #include "terrainstorage.hpp" @@ -232,3 +233,26 @@ void CSVRender::Cell::setSelection (int elementMask, Selection mode) } } } + +void CSVRender::Cell::setCellArrows (int mask) +{ + for (int i=0; i<4; ++i) + { + CellArrow::Direction direction = static_cast (1< mTerrain; int mX; int mY; + std::auto_ptr mCellArrows[4]; /// Ignored if cell does not have an object with the given ID. /// @@ -86,6 +89,11 @@ namespace CSVRender bool referenceAdded (const QModelIndex& parent, int start, int end); void setSelection (int elementMask, Selection mode); + + void setCellArrows (int mask); + + /// Returns 0, 0 in case of an unpaged cell. + CSMWorld::CellCoordinates getCoordinates() const; }; } diff --git a/apps/opencs/view/render/cellarrow.cpp b/apps/opencs/view/render/cellarrow.cpp new file mode 100644 index 000000000..ee055a0b1 --- /dev/null +++ b/apps/opencs/view/render/cellarrow.cpp @@ -0,0 +1,93 @@ + +#include "cellarrow.hpp" + +#include +#include + +#include +#include +#include + + +#include "elements.hpp" + +CSVRender::CellArrowTag::CellArrowTag (CellArrow *arrow) +: TagBase (Element_CellArrow), mArrow (arrow) +{} + +CSVRender::CellArrow *CSVRender::CellArrowTag::getCellArrow() const +{ + return mArrow; +} + + +void CSVRender::CellArrow::adjustTransform() +{ + // position + const int cellSize = 8192; + const int offset = cellSize / 2 + 400; + + int x = mXIndex*cellSize + cellSize/2; + int y = mYIndex*cellSize + cellSize/2; + + switch (mDirection) + { + case Direction_North: y += offset; break; + case Direction_West: x -= offset; break; + case Direction_South: y -= offset; break; + case Direction_East: x += offset; break; + }; + + mBaseNode->setPosition (osg::Vec3f (x, y, 0)); + + // orientation + osg::Quat xr (0, osg::Vec3f (1,0,0)); + osg::Quat yr (0, osg::Vec3f (0,1,0)); + osg::Quat zr (0, osg::Vec3f (0,0,1)); + mBaseNode->setAttitude (zr*yr*xr); +} + +void CSVRender::CellArrow::buildShape() +{ + /// \todo placeholder shape -> replace + osg::ref_ptr shape(new osg::Box(osg::Vec3f(0,0,0), 200)); + osg::ref_ptr shapedrawable(new osg::ShapeDrawable); + shapedrawable->setShape(shape); + + osg::ref_ptr geode (new osg::Geode); + geode->addDrawable(shapedrawable); + + mBaseNode->addChild (geode); +} + +CSVRender::CellArrow::CellArrow (osg::Group *cellNode, Direction direction, + int xIndex, int yIndex) +: mDirection (direction), mParentNode (cellNode), mXIndex (xIndex), mYIndex (yIndex) +{ + mBaseNode = new osg::PositionAttitudeTransform; + + mBaseNode->setUserData (new CellArrowTag (this)); + + mParentNode->addChild (mBaseNode); + + // 0x1 reserved for separating cull and update visitors + mBaseNode->setNodeMask (Element_CellArrow<<1); + + adjustTransform(); + buildShape(); +} + +CSVRender::CellArrow::~CellArrow() +{ + mParentNode->removeChild (mBaseNode); +} + +int CSVRender::CellArrow::getXIndex() const +{ + return mXIndex; +} + +int CSVRender::CellArrow::getYIndex() const +{ + return mYIndex; +} diff --git a/apps/opencs/view/render/cellarrow.hpp b/apps/opencs/view/render/cellarrow.hpp new file mode 100644 index 000000000..822e63bdc --- /dev/null +++ b/apps/opencs/view/render/cellarrow.hpp @@ -0,0 +1,70 @@ +#ifndef OPENCS_VIEW_CELLARROW_H +#define OPENCS_VIEW_CELLARROW_H + +#include "tagbase.hpp" + +#include + +namespace osg +{ + class PositionAttitudeTransform; + class Group; +} + +namespace CSVRender +{ + class CellArrow; + + class CellArrowTag : public TagBase + { + CellArrow *mArrow; + + public: + + CellArrowTag (CellArrow *arrow); + + CellArrow *getCellArrow() const; + }; + + + class CellArrow + { + public: + + enum Direction + { + Direction_North = 1, + Direction_West = 2, + Direction_South = 4, + Direction_East = 8 + }; + + private: + + // not implemented + CellArrow (const CellArrow&); + CellArrow& operator= (const CellArrow&); + + Direction mDirection; + osg::Group* mParentNode; + osg::ref_ptr mBaseNode; + int mXIndex; + int mYIndex; + + void adjustTransform(); + + void buildShape(); + + public: + + CellArrow (osg::Group *cellNode, Direction direction, int xIndex, int yIndex); + + ~CellArrow(); + + int getXIndex() const; + + int getYIndex() const; + }; +} + +#endif diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index 7403113b3..070ce7d17 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -21,6 +21,7 @@ bool CSVRender::PagedWorldspaceWidget::adjustCells() { bool modified = false; + bool wasEmpty = mCells.empty(); const CSMWorld::IdCollection& cells = mDocument.getData().getCells(); @@ -32,6 +33,7 @@ bool CSVRender::PagedWorldspaceWidget::adjustCells() { int index = cells.searchId (iter->first.getId (mWorldspace)); + /// \todo handle cells that don't exist if (!mSelection.has (iter->first) || index==-1 || cells.getRecord (index).mState==CSMWorld::RecordBase::State_Deleted) { @@ -60,6 +62,7 @@ bool CSVRender::PagedWorldspaceWidget::adjustCells() { int index = cells.searchId (iter->getId (mWorldspace)); + /// \todo handle cells that don't exist if (index > 0 && cells.getRecord (index).mState!=CSMWorld::RecordBase::State_Deleted && mCells.find (*iter)==mCells.end()) { @@ -72,6 +75,35 @@ bool CSVRender::PagedWorldspaceWidget::adjustCells() } if (modified) + { + for (std::map::const_iterator iter (mCells.begin()); + iter!=mCells.end(); ++iter) + { + int mask = 0; + + for (int i=CellArrow::Direction_North; i<=CellArrow::Direction_East; i *= 2) + { + CSMWorld::CellCoordinates coordinates (iter->second->getCoordinates()); + + switch (i) + { + case CellArrow::Direction_North: coordinates = coordinates.move (0, 1); break; + case CellArrow::Direction_West: coordinates = coordinates.move (-1, 0); break; + case CellArrow::Direction_South: coordinates = coordinates.move (0, -1); break; + case CellArrow::Direction_East: coordinates = coordinates.move (1, 0); break; + } + + if (!mSelection.has (coordinates)) + mask |= i; + } + + iter->second->setCellArrows (mask); + } + } + + /// \todo do not overwrite manipulator object + /// \todo move code to useViewHint function + if (modified && wasEmpty) mView->setCameraManipulator(new osgGA::TrackballManipulator); return modified; From b81ee606c831f3a7b700165716f0df568d0a6ad3 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 12 Oct 2015 14:31:55 +0200 Subject: [PATCH 2/9] use CellCoordinates instead of a pair of ints for cell coordinates --- apps/opencs/view/render/cell.cpp | 9 ++++----- apps/opencs/view/render/cell.hpp | 3 +-- apps/opencs/view/render/cellarrow.cpp | 18 ++++++------------ apps/opencs/view/render/cellarrow.hpp | 12 ++++++------ 4 files changed, 17 insertions(+), 25 deletions(-) diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index 345bc79a7..e0e63c8c9 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -52,7 +52,7 @@ bool CSVRender::Cell::addObjects (int start, int end) } CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::string& id) -: mData (data), mId (Misc::StringUtils::lowerCase (id)), mX(0), mY(0) +: mData (data), mId (Misc::StringUtils::lowerCase (id)) { mCellNode = new osg::Group; rootNode->addChild(mCellNode); @@ -76,8 +76,7 @@ CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::st mTerrain->loadCell(esmLand.mX, esmLand.mY); - mX = esmLand.mX; - mY = esmLand.mY; + mCoordinates = CSMWorld::CellCoordinates (esmLand.mX, esmLand.mY); } } } @@ -245,7 +244,7 @@ void CSVRender::Cell::setCellArrows (int mask) if (enable!=(mCellArrows[i].get()!=0)) { if (enable) - mCellArrows[i].reset (new CellArrow (mCellNode, direction, mX, mY)); + mCellArrows[i].reset (new CellArrow (mCellNode, direction, mCoordinates)); else mCellArrows[i].reset (0); } @@ -254,5 +253,5 @@ void CSVRender::Cell::setCellArrows (int mask) CSMWorld::CellCoordinates CSVRender::Cell::getCoordinates() const { - return CSMWorld::CellCoordinates (mX, mY); + return mCoordinates; } diff --git a/apps/opencs/view/render/cell.hpp b/apps/opencs/view/render/cell.hpp index 5b1badcbe..7cced4fe3 100644 --- a/apps/opencs/view/render/cell.hpp +++ b/apps/opencs/view/render/cell.hpp @@ -38,8 +38,7 @@ namespace CSVRender osg::ref_ptr mCellNode; std::map mObjects; std::auto_ptr mTerrain; - int mX; - int mY; + CSMWorld::CellCoordinates mCoordinates; std::auto_ptr mCellArrows[4]; /// Ignored if cell does not have an object with the given ID. diff --git a/apps/opencs/view/render/cellarrow.cpp b/apps/opencs/view/render/cellarrow.cpp index ee055a0b1..443d398dd 100644 --- a/apps/opencs/view/render/cellarrow.cpp +++ b/apps/opencs/view/render/cellarrow.cpp @@ -8,7 +8,6 @@ #include #include - #include "elements.hpp" CSVRender::CellArrowTag::CellArrowTag (CellArrow *arrow) @@ -27,8 +26,8 @@ void CSVRender::CellArrow::adjustTransform() const int cellSize = 8192; const int offset = cellSize / 2 + 400; - int x = mXIndex*cellSize + cellSize/2; - int y = mYIndex*cellSize + cellSize/2; + int x = mCoordinates.getX()*cellSize + cellSize/2; + int y = mCoordinates.getY()*cellSize + cellSize/2; switch (mDirection) { @@ -61,8 +60,8 @@ void CSVRender::CellArrow::buildShape() } CSVRender::CellArrow::CellArrow (osg::Group *cellNode, Direction direction, - int xIndex, int yIndex) -: mDirection (direction), mParentNode (cellNode), mXIndex (xIndex), mYIndex (yIndex) + const CSMWorld::CellCoordinates& coordinates) +: mDirection (direction), mParentNode (cellNode), mCoordinates (coordinates) { mBaseNode = new osg::PositionAttitudeTransform; @@ -82,12 +81,7 @@ CSVRender::CellArrow::~CellArrow() mParentNode->removeChild (mBaseNode); } -int CSVRender::CellArrow::getXIndex() const +CSMWorld::CellCoordinates CSVRender::CellArrow::getCoordinates() const { - return mXIndex; -} - -int CSVRender::CellArrow::getYIndex() const -{ - return mYIndex; + return mCoordinates; } diff --git a/apps/opencs/view/render/cellarrow.hpp b/apps/opencs/view/render/cellarrow.hpp index 822e63bdc..4422ec890 100644 --- a/apps/opencs/view/render/cellarrow.hpp +++ b/apps/opencs/view/render/cellarrow.hpp @@ -5,6 +5,8 @@ #include +#include "../../model/world/cellcoordinates.hpp" + namespace osg { class PositionAttitudeTransform; @@ -48,8 +50,7 @@ namespace CSVRender Direction mDirection; osg::Group* mParentNode; osg::ref_ptr mBaseNode; - int mXIndex; - int mYIndex; + CSMWorld::CellCoordinates mCoordinates; void adjustTransform(); @@ -57,13 +58,12 @@ namespace CSVRender public: - CellArrow (osg::Group *cellNode, Direction direction, int xIndex, int yIndex); + CellArrow (osg::Group *cellNode, Direction direction, + const CSMWorld::CellCoordinates& coordinates); ~CellArrow(); - int getXIndex() const; - - int getYIndex() const; + CSMWorld::CellCoordinates getCoordinates() const; }; } From 3f9db7ba3cc12739a238207797c92c07b74332ab Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 12 Oct 2015 18:00:44 +0200 Subject: [PATCH 3/9] more reliable method of obtaining the cell coordinates in CSVRender::Cell --- apps/opencs/model/world/cellcoordinates.cpp | 17 +++++++++++++++++ apps/opencs/model/world/cellcoordinates.hpp | 6 ++++++ apps/opencs/view/render/cell.cpp | 7 +++++-- 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/world/cellcoordinates.cpp b/apps/opencs/model/world/cellcoordinates.cpp index 95e206e2d..3ef3e6c69 100644 --- a/apps/opencs/model/world/cellcoordinates.cpp +++ b/apps/opencs/model/world/cellcoordinates.cpp @@ -32,6 +32,23 @@ std::string CSMWorld::CellCoordinates::getId (const std::string& worldspace) con return stream.str(); } +std::pair CSMWorld::CellCoordinates::fromId ( + const std::string& id) +{ + // no worldspace for now, needs to be changed for 1.1 + if (!id.empty() && id[0]=='#') + { + int x, y; + char ignore; + + std::istringstream stream (id); + if (stream >> ignore >> x >> y) + return std::make_pair (CellCoordinates (x, y), true); + } + + return std::make_pair (CellCoordinates(), false); +} + bool CSMWorld::operator== (const CellCoordinates& left, const CellCoordinates& right) { return left.getX()==right.getX() && left.getY()==right.getY(); diff --git a/apps/opencs/model/world/cellcoordinates.hpp b/apps/opencs/model/world/cellcoordinates.hpp index ee395ea7e..63db60c29 100644 --- a/apps/opencs/model/world/cellcoordinates.hpp +++ b/apps/opencs/model/world/cellcoordinates.hpp @@ -28,6 +28,12 @@ namespace CSMWorld std::string getId (const std::string& worldspace) const; ///< Return the ID for the cell at these coordinates. + + /// \return first: CellCoordinates (or 0, 0 if cell does not have coordinates), + /// second: is cell paged? + /// + /// \note The worldspace part of \a id is ignored + static std::pair fromId (const std::string& id); }; bool operator== (const CellCoordinates& left, const CellCoordinates& right); diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index e0e63c8c9..5ec69a5f2 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -54,6 +54,11 @@ bool CSVRender::Cell::addObjects (int start, int end) CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::string& id) : mData (data), mId (Misc::StringUtils::lowerCase (id)) { + std::pair result = CSMWorld::CellCoordinates::fromId (id); + + if (result.second) + mCoordinates = result.first; + mCellNode = new osg::Group; rootNode->addChild(mCellNode); @@ -75,8 +80,6 @@ CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::st mTerrain.reset(new Terrain::TerrainGrid(mCellNode, data.getResourceSystem().get(), NULL, new TerrainStorage(mData), Element_Terrain<<1)); mTerrain->loadCell(esmLand.mX, esmLand.mY); - - mCoordinates = CSMWorld::CellCoordinates (esmLand.mX, esmLand.mY); } } } From 6e140c9cb1c3cb3406295a57488f32e5d6acc288 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 13 Oct 2015 11:43:33 +0200 Subject: [PATCH 4/9] proper shape for cell arrows (kinda) --- apps/opencs/view/render/cellarrow.cpp | 95 ++++++++++++++++++++++----- 1 file changed, 78 insertions(+), 17 deletions(-) diff --git a/apps/opencs/view/render/cellarrow.cpp b/apps/opencs/view/render/cellarrow.cpp index 443d398dd..8f03b489f 100644 --- a/apps/opencs/view/render/cellarrow.cpp +++ b/apps/opencs/view/render/cellarrow.cpp @@ -3,10 +3,9 @@ #include #include - -#include -#include #include +#include +#include #include "elements.hpp" @@ -24,37 +23,99 @@ void CSVRender::CellArrow::adjustTransform() { // position const int cellSize = 8192; - const int offset = cellSize / 2 + 400; + const int offset = cellSize / 2 + 800; int x = mCoordinates.getX()*cellSize + cellSize/2; int y = mCoordinates.getY()*cellSize + cellSize/2; + float xr = 0; + float yr = 0; + float zr = 0; + + float angle = osg::DegreesToRadians (90.0f); + switch (mDirection) { - case Direction_North: y += offset; break; - case Direction_West: x -= offset; break; - case Direction_South: y -= offset; break; - case Direction_East: x += offset; break; + case Direction_North: y += offset; xr = -angle; zr = angle; break; + case Direction_West: x -= offset; yr = -angle; break; + case Direction_South: y -= offset; xr = angle; zr = angle; break; + case Direction_East: x += offset; yr = angle; break; }; mBaseNode->setPosition (osg::Vec3f (x, y, 0)); // orientation - osg::Quat xr (0, osg::Vec3f (1,0,0)); - osg::Quat yr (0, osg::Vec3f (0,1,0)); - osg::Quat zr (0, osg::Vec3f (0,0,1)); - mBaseNode->setAttitude (zr*yr*xr); + osg::Quat xr2 (xr, osg::Vec3f (1,0,0)); + osg::Quat yr2 (yr, osg::Vec3f (0,1,0)); + osg::Quat zr2 (zr, osg::Vec3f (0,0,1)); + mBaseNode->setAttitude (zr2*yr2*xr2); } void CSVRender::CellArrow::buildShape() { - /// \todo placeholder shape -> replace - osg::ref_ptr shape(new osg::Box(osg::Vec3f(0,0,0), 200)); - osg::ref_ptr shapedrawable(new osg::ShapeDrawable); - shapedrawable->setShape(shape); + osg::ref_ptr geometry (new osg::Geometry); + + const int arrowWidth = 4000; + const int arrowLength = 1500; + const int arrowHeight = 500; + + osg::Vec3Array *vertices = new osg::Vec3Array; + for (int i2=0; i2<2; ++i2) + for (int i=0; i<2; ++i) + { + float height = i ? -arrowHeight/2 : arrowHeight/2; + vertices->push_back (osg::Vec3f (height, -arrowWidth/2, 0)); + vertices->push_back (osg::Vec3f (height, arrowWidth/2, 0)); + vertices->push_back (osg::Vec3f (height, 0, arrowLength)); + } + + geometry->setVertexArray (vertices); + + osg::DrawElementsUShort *top = new osg::DrawElementsUShort (osg::PrimitiveSet::TRIANGLES, 0); + top->push_back (0); + top->push_back (1); + top->push_back (2); + geometry->addPrimitiveSet (top); + + osg::DrawElementsUShort *bottom = new osg::DrawElementsUShort (osg::PrimitiveSet::TRIANGLES, 0); + bottom->push_back (5); + bottom->push_back (4); + bottom->push_back (3); + geometry->addPrimitiveSet (bottom); + + osg::DrawElementsUShort *back = new osg::DrawElementsUShort (osg::PrimitiveSet::QUADS, 0); + back->push_back (3+6); + back->push_back (4+6); + back->push_back (1+6); + back->push_back (0+6); + geometry->addPrimitiveSet (back); + + osg::DrawElementsUShort *side1 = new osg::DrawElementsUShort (osg::PrimitiveSet::QUADS, 0); + side1->push_back (0+6); + side1->push_back (2+6); + side1->push_back (5+6); + side1->push_back (3+6); + geometry->addPrimitiveSet (side1); + + osg::DrawElementsUShort *side2 = new osg::DrawElementsUShort (osg::PrimitiveSet::QUADS, 0); + side2->push_back (4+6); + side2->push_back (5+6); + side2->push_back (2+6); + side2->push_back (1+6); + geometry->addPrimitiveSet (side2); + + osg::Vec4Array *colours = new osg::Vec4Array; + + for (int i=0; i<6; ++i) + colours->push_back (osg::Vec4f (1.0f, 0.0f, 0.0f, 1.0f)); + for (int i=0; i<6; ++i) + colours->push_back (osg::Vec4f (1.0f, 0.0f, 0.4f, 1.0f)); + + geometry->setColorArray (colours); + geometry->setColorBinding (osg::Geometry::BIND_PER_VERTEX); osg::ref_ptr geode (new osg::Geode); - geode->addDrawable(shapedrawable); + geode->addDrawable (geometry); mBaseNode->addChild (geode); } From 0b1d6bddc8b1f2f16b61d51be7bc4fd09e618049 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 13 Oct 2015 16:11:47 +0200 Subject: [PATCH 5/9] merged primitives arrays --- apps/opencs/view/render/cellarrow.cpp | 63 +++++++++++++++------------ 1 file changed, 35 insertions(+), 28 deletions(-) diff --git a/apps/opencs/view/render/cellarrow.cpp b/apps/opencs/view/render/cellarrow.cpp index 8f03b489f..526c9a24c 100644 --- a/apps/opencs/view/render/cellarrow.cpp +++ b/apps/opencs/view/render/cellarrow.cpp @@ -71,38 +71,45 @@ void CSVRender::CellArrow::buildShape() geometry->setVertexArray (vertices); - osg::DrawElementsUShort *top = new osg::DrawElementsUShort (osg::PrimitiveSet::TRIANGLES, 0); - top->push_back (0); - top->push_back (1); - top->push_back (2); - geometry->addPrimitiveSet (top); + osg::DrawElementsUShort *primitives = new osg::DrawElementsUShort (osg::PrimitiveSet::TRIANGLES, 0); - osg::DrawElementsUShort *bottom = new osg::DrawElementsUShort (osg::PrimitiveSet::TRIANGLES, 0); - bottom->push_back (5); - bottom->push_back (4); - bottom->push_back (3); - geometry->addPrimitiveSet (bottom); + // top + primitives->push_back (0); + primitives->push_back (1); + primitives->push_back (2); - osg::DrawElementsUShort *back = new osg::DrawElementsUShort (osg::PrimitiveSet::QUADS, 0); - back->push_back (3+6); - back->push_back (4+6); - back->push_back (1+6); - back->push_back (0+6); - geometry->addPrimitiveSet (back); + // bottom + primitives->push_back (5); + primitives->push_back (4); + primitives->push_back (3); - osg::DrawElementsUShort *side1 = new osg::DrawElementsUShort (osg::PrimitiveSet::QUADS, 0); - side1->push_back (0+6); - side1->push_back (2+6); - side1->push_back (5+6); - side1->push_back (3+6); - geometry->addPrimitiveSet (side1); + // back + primitives->push_back (3+6); + primitives->push_back (4+6); + primitives->push_back (1+6); - osg::DrawElementsUShort *side2 = new osg::DrawElementsUShort (osg::PrimitiveSet::QUADS, 0); - side2->push_back (4+6); - side2->push_back (5+6); - side2->push_back (2+6); - side2->push_back (1+6); - geometry->addPrimitiveSet (side2); + primitives->push_back (3+6); + primitives->push_back (1+6); + primitives->push_back (0+6); + + // sides + primitives->push_back (0+6); + primitives->push_back (2+6); + primitives->push_back (5+6); + + primitives->push_back (0+6); + primitives->push_back (5+6); + primitives->push_back (3+6); + + primitives->push_back (4+6); + primitives->push_back (5+6); + primitives->push_back (2+6); + + primitives->push_back (4+6); + primitives->push_back (2+6); + primitives->push_back (1+6); + + geometry->addPrimitiveSet (primitives); osg::Vec4Array *colours = new osg::Vec4Array; From 68115c4e8aa3447e8848528b816c3fd4a8253e64 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 13 Oct 2015 16:15:53 +0200 Subject: [PATCH 6/9] (somewhat) improved the colour scheme --- apps/opencs/view/render/cellarrow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/view/render/cellarrow.cpp b/apps/opencs/view/render/cellarrow.cpp index 526c9a24c..59460b626 100644 --- a/apps/opencs/view/render/cellarrow.cpp +++ b/apps/opencs/view/render/cellarrow.cpp @@ -116,7 +116,7 @@ void CSVRender::CellArrow::buildShape() for (int i=0; i<6; ++i) colours->push_back (osg::Vec4f (1.0f, 0.0f, 0.0f, 1.0f)); for (int i=0; i<6; ++i) - colours->push_back (osg::Vec4f (1.0f, 0.0f, 0.4f, 1.0f)); + colours->push_back (osg::Vec4f (0.8f, (i==2 || i==5) ? 0.6f : 0.4f, 0.0f, 1.0f)); geometry->setColorArray (colours); geometry->setColorBinding (osg::Geometry::BIND_PER_VERTEX); From 773df6fd22e756ec39f0ad516edd47286914eef0 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 13 Oct 2015 16:53:40 +0200 Subject: [PATCH 7/9] some OSG fixes --- apps/opencs/view/render/cellarrow.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/render/cellarrow.cpp b/apps/opencs/view/render/cellarrow.cpp index 59460b626..720db5327 100644 --- a/apps/opencs/view/render/cellarrow.cpp +++ b/apps/opencs/view/render/cellarrow.cpp @@ -118,8 +118,9 @@ void CSVRender::CellArrow::buildShape() for (int i=0; i<6; ++i) colours->push_back (osg::Vec4f (0.8f, (i==2 || i==5) ? 0.6f : 0.4f, 0.0f, 1.0f)); - geometry->setColorArray (colours); - geometry->setColorBinding (osg::Geometry::BIND_PER_VERTEX); + geometry->setColorArray (colours, osg::Array::BIND_PER_VERTEX); + + geometry->getOrCreateStateSet()->setMode (GL_LIGHTING, osg::StateAttribute::OFF); osg::ref_ptr geode (new osg::Geode); geode->addDrawable (geometry); From 361634489ed7a1286919bef02b687fe3682cd619 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 15 Oct 2015 14:46:08 +0200 Subject: [PATCH 8/9] properly handle cells that don't exist --- apps/opencs/view/render/cell.cpp | 52 +++++++++++++------ apps/opencs/view/render/cell.hpp | 8 ++- .../view/render/pagedworldspacewidget.cpp | 47 +++++++++++------ 3 files changed, 73 insertions(+), 34 deletions(-) diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index 5ec69a5f2..da40f7e7c 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -51,8 +51,9 @@ bool CSVRender::Cell::addObjects (int start, int end) return modified; } -CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::string& id) -: mData (data), mId (Misc::StringUtils::lowerCase (id)) +CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::string& id, + bool deleted) +: mData (data), mId (Misc::StringUtils::lowerCase (id)), mDeleted (deleted) { std::pair result = CSMWorld::CellCoordinates::fromId (id); @@ -62,24 +63,27 @@ CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::st mCellNode = new osg::Group; rootNode->addChild(mCellNode); - CSMWorld::IdTable& references = dynamic_cast ( - *mData.getTableModel (CSMWorld::UniversalId::Type_References)); - - int rows = references.rowCount(); - - addObjects (0, rows-1); - - const CSMWorld::IdCollection& land = mData.getLand(); - int landIndex = land.searchId(mId); - if (landIndex != -1) + if (!mDeleted) { - const ESM::Land& esmLand = land.getRecord(mId).get(); + CSMWorld::IdTable& references = dynamic_cast ( + *mData.getTableModel (CSMWorld::UniversalId::Type_References)); - if (esmLand.getLandData (ESM::Land::DATA_VHGT)) + int rows = references.rowCount(); + + addObjects (0, rows-1); + + const CSMWorld::IdCollection& land = mData.getLand(); + int landIndex = land.searchId(mId); + if (landIndex != -1) { - mTerrain.reset(new Terrain::TerrainGrid(mCellNode, data.getResourceSystem().get(), NULL, new TerrainStorage(mData), Element_Terrain<<1)); - mTerrain->loadCell(esmLand.mX, - esmLand.mY); + const ESM::Land& esmLand = land.getRecord(mId).get(); + + if (esmLand.getLandData (ESM::Land::DATA_VHGT)) + { + mTerrain.reset(new Terrain::TerrainGrid(mCellNode, data.getResourceSystem().get(), NULL, new TerrainStorage(mData), Element_Terrain<<1)); + mTerrain->loadCell(esmLand.mX, + esmLand.mY); + } } } } @@ -125,6 +129,9 @@ bool CSVRender::Cell::referenceableAboutToBeRemoved (const QModelIndex& parent, bool CSVRender::Cell::referenceDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) { + if (mDeleted) + return false; + CSMWorld::IdTable& references = dynamic_cast ( *mData.getTableModel (CSMWorld::UniversalId::Type_References)); @@ -192,6 +199,9 @@ bool CSVRender::Cell::referenceAboutToBeRemoved (const QModelIndex& parent, int if (parent.isValid()) return false; + if (mDeleted) + return false; + CSMWorld::IdTable& references = dynamic_cast ( *mData.getTableModel (CSMWorld::UniversalId::Type_References)); @@ -212,6 +222,9 @@ bool CSVRender::Cell::referenceAdded (const QModelIndex& parent, int start, int if (parent.isValid()) return false; + if (mDeleted) + return false; + return addObjects (start, end); } @@ -258,3 +271,8 @@ CSMWorld::CellCoordinates CSVRender::Cell::getCoordinates() const { return mCoordinates; } + +bool CSVRender::Cell::isDeleted() const +{ + return mDeleted; +} diff --git a/apps/opencs/view/render/cell.hpp b/apps/opencs/view/render/cell.hpp index 7cced4fe3..59f4cafee 100644 --- a/apps/opencs/view/render/cell.hpp +++ b/apps/opencs/view/render/cell.hpp @@ -40,6 +40,7 @@ namespace CSVRender std::auto_ptr mTerrain; CSMWorld::CellCoordinates mCoordinates; std::auto_ptr mCellArrows[4]; + bool mDeleted; /// Ignored if cell does not have an object with the given ID. /// @@ -62,7 +63,10 @@ namespace CSVRender public: - Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::string& id); + /// \note Deleted covers both cells that are deleted and cells that don't exist in + /// the first place. + Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::string& id, + bool deleted = false); ~Cell(); @@ -93,6 +97,8 @@ namespace CSVRender /// Returns 0, 0 in case of an unpaged cell. CSMWorld::CellCoordinates getCoordinates() const; + + bool isDeleted() const; }; } diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index 070ce7d17..dd740ab9a 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -1,5 +1,6 @@ #include "pagedworldspacewidget.hpp" +#include #include #include @@ -26,17 +27,14 @@ bool CSVRender::PagedWorldspaceWidget::adjustCells() const CSMWorld::IdCollection& cells = mDocument.getData().getCells(); { - // remove (or name/region modified) + // remove/update std::map::iterator iter (mCells.begin()); while (iter!=mCells.end()) { - int index = cells.searchId (iter->first.getId (mWorldspace)); - - /// \todo handle cells that don't exist - if (!mSelection.has (iter->first) || index==-1 || - cells.getRecord (index).mState==CSMWorld::RecordBase::State_Deleted) + if (!mSelection.has (iter->first)) { + // remove delete iter->second; mCells.erase (iter++); @@ -44,12 +42,33 @@ bool CSVRender::PagedWorldspaceWidget::adjustCells() } else { - // check if name or region field has changed - // FIXME: config setting - //std::string name = cells.getRecord(index).get().mName; - //std::string region = cells.getRecord(index).get().mRegion; + // update + int index = cells.searchId (iter->first.getId (mWorldspace)); - // cell marker update goes here + bool deleted = index==-1 || + cells.getRecord (index).mState==CSMWorld::RecordBase::State_Deleted; + + if (deleted!=iter->second->isDeleted()) + { + modified = true; + + std::auto_ptr cell (new Cell (mDocument.getData(), mRootNode, + iter->first.getId (mWorldspace), deleted)); + + delete iter->second; + iter->second = cell.release(); + } + else if (!deleted) + { + // delete state has not changed -> just update + + // TODO check if name or region field has changed (cell marker) + // FIXME: config setting + //std::string name = cells.getRecord(index).get().mName; + //std::string region = cells.getRecord(index).get().mRegion; + + modified = true; + } ++iter; } @@ -60,11 +79,7 @@ bool CSVRender::PagedWorldspaceWidget::adjustCells() for (CSMWorld::CellSelection::Iterator iter (mSelection.begin()); iter!=mSelection.end(); ++iter) { - int index = cells.searchId (iter->getId (mWorldspace)); - - /// \todo handle cells that don't exist - if (index > 0 && cells.getRecord (index).mState!=CSMWorld::RecordBase::State_Deleted && - mCells.find (*iter)==mCells.end()) + if (mCells.find (*iter)==mCells.end()) { Cell *cell = new Cell (mDocument.getData(), mRootNode, iter->getId (mWorldspace)); From e34af4c4b5fe860c033dd4f55cd7aae0279d4bbc Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 25 Oct 2015 15:16:22 +0100 Subject: [PATCH 9/9] handle primary and secondary edit button clicks on cell arrows --- apps/opencs/view/render/cellarrow.cpp | 5 + apps/opencs/view/render/cellarrow.hpp | 2 + .../view/render/pagedworldspacewidget.cpp | 142 +++++++++++++++++- .../view/render/pagedworldspacewidget.hpp | 16 ++ apps/opencs/view/render/worldspacewidget.cpp | 21 ++- apps/opencs/view/render/worldspacewidget.hpp | 3 + 6 files changed, 177 insertions(+), 12 deletions(-) diff --git a/apps/opencs/view/render/cellarrow.cpp b/apps/opencs/view/render/cellarrow.cpp index 720db5327..fce5ffda5 100644 --- a/apps/opencs/view/render/cellarrow.cpp +++ b/apps/opencs/view/render/cellarrow.cpp @@ -154,3 +154,8 @@ CSMWorld::CellCoordinates CSVRender::CellArrow::getCoordinates() const { return mCoordinates; } + +CSVRender::CellArrow::Direction CSVRender::CellArrow::getDirection() const +{ + return mDirection; +} diff --git a/apps/opencs/view/render/cellarrow.hpp b/apps/opencs/view/render/cellarrow.hpp index 4422ec890..cbbcc9d5e 100644 --- a/apps/opencs/view/render/cellarrow.hpp +++ b/apps/opencs/view/render/cellarrow.hpp @@ -64,6 +64,8 @@ namespace CSVRender ~CellArrow(); CSMWorld::CellCoordinates getCoordinates() const; + + Direction getDirection() const; }; } diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index dd740ab9a..6e5c2587d 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -4,6 +4,7 @@ #include #include +#include #include @@ -81,10 +82,7 @@ bool CSVRender::PagedWorldspaceWidget::adjustCells() { if (mCells.find (*iter)==mCells.end()) { - Cell *cell = new Cell (mDocument.getData(), mRootNode, - iter->getId (mWorldspace)); - mCells.insert (std::make_pair (*iter, cell)); - + addCellToScene (*iter); modified = true; } } @@ -152,6 +150,76 @@ void CSVRender::PagedWorldspaceWidget::addEditModeSelectorButtons ( "terrain-move"); } +void CSVRender::PagedWorldspaceWidget::handleMouseClick (osg::ref_ptr tag, const std::string& button) +{ + if (tag && tag->getElement()==Element_CellArrow) + { + if (button=="p-edit" || button=="s-edit") + { + if (CellArrowTag *cellArrowTag = + dynamic_cast (tag.get())) + { + CellArrow *arrow = cellArrowTag->getCellArrow(); + + CSMWorld::CellCoordinates coordinates = arrow->getCoordinates(); + + CellArrow::Direction direction = arrow->getDirection(); + + int x = 0; + int y = 0; + + switch (direction) + { + case CellArrow::Direction_North: y = 1; break; + case CellArrow::Direction_West: x = -1; break; + case CellArrow::Direction_South: y = -1; break; + case CellArrow::Direction_East: x = 1; break; + } + + bool modified = false; + + if (QApplication::keyboardModifiers() & Qt::ShiftModifier) + { + if (button=="p-edit") + addCellSelection (x, y); + else + moveCellSelection (x, y); + + modified = true; + } + else + { + CSMWorld::CellCoordinates newCoordinates = coordinates.move (x, y); + + if (mCells.find (newCoordinates)==mCells.end()) + { + addCellToScene (newCoordinates); + mSelection.add (newCoordinates); + modified = true; + } + + if (button=="s-edit") + { + if (mCells.find (coordinates)!=mCells.end()) + { + removeCellFromScene (coordinates); + mSelection.remove (coordinates); + modified = true; + } + } + } + + if (modified) + adjustCells(); + + return; + } + } + } + + WorldspaceWidget::handleMouseClick (tag, button); +} + void CSVRender::PagedWorldspaceWidget::referenceableDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) { @@ -231,6 +299,72 @@ std::string CSVRender::PagedWorldspaceWidget::getStartupInstruction() return stream.str(); } +void CSVRender::PagedWorldspaceWidget::addCellToScene ( + const CSMWorld::CellCoordinates& coordinates) +{ + const CSMWorld::IdCollection& cells = mDocument.getData().getCells(); + + int index = cells.searchId (coordinates.getId (mWorldspace)); + + bool deleted = index==-1 || + cells.getRecord (index).mState==CSMWorld::RecordBase::State_Deleted; + + Cell *cell = new Cell (mDocument.getData(), mRootNode, coordinates.getId (mWorldspace), + deleted); + + mCells.insert (std::make_pair (coordinates, cell)); +} + +void CSVRender::PagedWorldspaceWidget::removeCellFromScene ( + const CSMWorld::CellCoordinates& coordinates) +{ + std::map::iterator iter = mCells.find (coordinates); + + if (iter!=mCells.end()) + { + delete iter->second; + mCells.erase (iter); + } +} + +void CSVRender::PagedWorldspaceWidget::addCellSelection (int x, int y) +{ + CSMWorld::CellSelection newSelection = mSelection; + newSelection.move (x, y); + + for (CSMWorld::CellSelection::Iterator iter (newSelection.begin()); iter!=newSelection.end(); + ++iter) + { + if (mCells.find (*iter)==mCells.end()) + { + addCellToScene (*iter); + mSelection.add (*iter); + } + } +} + +void CSVRender::PagedWorldspaceWidget::moveCellSelection (int x, int y) +{ + CSMWorld::CellSelection newSelection = mSelection; + newSelection.move (x, y); + + for (CSMWorld::CellSelection::Iterator iter (mSelection.begin()); iter!=mSelection.end(); + ++iter) + { + if (!newSelection.has (*iter)) + removeCellFromScene (*iter); + } + + for (CSMWorld::CellSelection::Iterator iter (newSelection.begin()); iter!=newSelection.end(); + ++iter) + { + if (!mSelection.has (*iter)) + addCellToScene (*iter); + } + + mSelection = newSelection; +} + CSVRender::PagedWorldspaceWidget::PagedWorldspaceWidget (QWidget* parent, CSMDoc::Document& document) : WorldspaceWidget (document, parent), mDocument (document), mWorldspace ("std::default"), mControlElements(NULL), mDisplayCellCoord(true) diff --git a/apps/opencs/view/render/pagedworldspacewidget.hpp b/apps/opencs/view/render/pagedworldspacewidget.hpp index d52efd90e..e1a43ba7c 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.hpp +++ b/apps/opencs/view/render/pagedworldspacewidget.hpp @@ -53,6 +53,20 @@ namespace CSVRender virtual std::string getStartupInstruction(); + /// \note Does not update the view or any cell marker + void addCellToScene (const CSMWorld::CellCoordinates& coordinates); + + /// \note Does not update the view or any cell marker + /// + /// \note Calling this function for a cell that is not in the selection is a no-op. + void removeCellFromScene (const CSMWorld::CellCoordinates& coordinates); + + /// \note Does not update the view or any cell marker + void addCellSelection (int x, int y); + + /// \note Does not update the view or any cell marker + void moveCellSelection (int x, int y); + public: PagedWorldspaceWidget (QWidget *parent, CSMDoc::Document& document); @@ -88,6 +102,8 @@ namespace CSVRender virtual void addEditModeSelectorButtons (CSVWidget::SceneToolMode *tool); + virtual void handleMouseClick (osg::ref_ptr tag, const std::string& button); + signals: void cellSelectionChanged (const CSMWorld::CellSelection& selection); diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 75dd800eb..a542a3c59 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -574,14 +574,7 @@ void CSVRender::WorldspaceWidget::mousePressEvent (QMouseEvent *event) { osg::ref_ptr tag = mousePick (event); - EditMode& editMode = dynamic_cast (*mEditMode->getCurrent()); - - if (button=="p-edit") - editMode.primaryEditPressed (tag); - else if (button=="s-edit") - editMode.secondaryEditPressed (tag); - else if (button=="select") - editMode.selectPressed (tag); + handleMouseClick (tag, button); } } @@ -650,3 +643,15 @@ void CSVRender::WorldspaceWidget::keyPressEvent (QKeyEvent *event) else RenderWidget::keyPressEvent(event); } + +void CSVRender::WorldspaceWidget::handleMouseClick (osg::ref_ptr tag, const std::string& button) +{ + EditMode& editMode = dynamic_cast (*mEditMode->getCurrent()); + + if (button=="p-edit") + editMode.primaryEditPressed (tag); + else if (button=="s-edit") + editMode.secondaryEditPressed (tag); + else if (button=="select") + editMode.selectPressed (tag); +} diff --git a/apps/opencs/view/render/worldspacewidget.hpp b/apps/opencs/view/render/worldspacewidget.hpp index f5e7970b6..fe766cf87 100644 --- a/apps/opencs/view/render/worldspacewidget.hpp +++ b/apps/opencs/view/render/worldspacewidget.hpp @@ -27,6 +27,7 @@ namespace CSVWidget namespace CSVRender { class TagBase; + class CellArrow; class WorldspaceWidget : public SceneWidget { @@ -132,6 +133,8 @@ namespace CSVRender virtual void wheelEvent (QWheelEvent *event); virtual void keyPressEvent (QKeyEvent *event); + virtual void handleMouseClick (osg::ref_ptr tag, const std::string& button); + private: void dragEnterEvent(QDragEnterEvent *event);