mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-02-06 02:15:32 +00:00
Initial pathgrid editting, support for selection and movement.
This commit is contained in:
parent
9645d0cc8a
commit
32ba5bf8b8
10 changed files with 707 additions and 40 deletions
|
@ -86,12 +86,12 @@ opencs_units (view/widget
|
|||
opencs_units (view/render
|
||||
scenewidget worldspacewidget pagedworldspacewidget unpagedworldspacewidget
|
||||
previewwidget editmode instancemode instanceselectionmode instancemovemode
|
||||
orbitcameramode
|
||||
orbitcameramode pathgridmode
|
||||
)
|
||||
|
||||
opencs_units_noqt (view/render
|
||||
lighting lightingday lightingnight lightingbright object cell terrainstorage tagbase
|
||||
cellarrow cellmarker cellborder cameracontroller
|
||||
cellarrow cellmarker cellborder cameracontroller pathgrid
|
||||
)
|
||||
|
||||
opencs_hdrs_noqt (view/render
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "../../model/world/cellcoordinates.hpp"
|
||||
|
||||
#include "mask.hpp"
|
||||
#include "pathgrid.hpp"
|
||||
#include "terrainstorage.hpp"
|
||||
|
||||
bool CSVRender::Cell::removeObject (const std::string& id)
|
||||
|
@ -68,18 +69,6 @@ bool CSVRender::Cell::addObjects (int start, int end)
|
|||
return modified;
|
||||
}
|
||||
|
||||
void CSVRender::Cell::recreatePathgrid()
|
||||
{
|
||||
const CSMWorld::SubCellCollection<CSMWorld::Pathgrid>& pathgrids = mData.getPathgrids();
|
||||
int pathgridIndex = pathgrids.searchId(mId);
|
||||
if (pathgridIndex != -1)
|
||||
{
|
||||
mPathgridGeode->removeDrawable(mPathgridGeometry);
|
||||
mPathgridGeometry = SceneUtil::createPathgridGeometry(pathgrids.getRecord(pathgridIndex).get());
|
||||
mPathgridGeode->addDrawable(mPathgridGeometry);
|
||||
}
|
||||
}
|
||||
|
||||
CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::string& id,
|
||||
bool deleted)
|
||||
: mData (data), mId (Misc::StringUtils::lowerCase (id)), mDeleted (deleted), mSubMode (0),
|
||||
|
@ -93,17 +82,6 @@ CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::st
|
|||
mCellNode = new osg::Group;
|
||||
rootNode->addChild(mCellNode);
|
||||
|
||||
osg::ref_ptr<osg::PositionAttitudeTransform> pathgridTransform = new osg::PositionAttitudeTransform();
|
||||
pathgridTransform->setPosition(osg::Vec3f(mCoordinates.getX() * ESM::Land::REAL_SIZE,
|
||||
mCoordinates.getY() * ESM::Land::REAL_SIZE, 0));
|
||||
pathgridTransform->setNodeMask(Mask_Pathgrid);
|
||||
mCellNode->addChild(pathgridTransform);
|
||||
|
||||
mPathgridGeode = new osg::Geode();
|
||||
pathgridTransform->addChild(mPathgridGeode);
|
||||
|
||||
mPathgridGeometry = 0;
|
||||
|
||||
setCellMarker();
|
||||
|
||||
if (!mDeleted)
|
||||
|
@ -132,7 +110,7 @@ CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::st
|
|||
}
|
||||
}
|
||||
|
||||
recreatePathgrid();
|
||||
mPathgrid.reset(new Pathgrid(mData, mCellNode, mId, mCoordinates));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -285,27 +263,27 @@ bool CSVRender::Cell::referenceAdded (const QModelIndex& parent, int start, int
|
|||
|
||||
void CSVRender::Cell::pathgridAdded(const CSMWorld::Pathgrid& pathgrid)
|
||||
{
|
||||
recreatePathgrid();
|
||||
mPathgrid->recreateGeometry();
|
||||
}
|
||||
|
||||
void CSVRender::Cell::pathgridRemoved()
|
||||
{
|
||||
mPathgridGeode->removeDrawable(mPathgridGeometry);
|
||||
mPathgrid->recreateGeometry();
|
||||
}
|
||||
|
||||
void CSVRender::Cell::pathgridDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight)
|
||||
{
|
||||
recreatePathgrid();
|
||||
mPathgrid->recreateGeometry();
|
||||
}
|
||||
|
||||
void CSVRender::Cell::pathgridRowRemoved(const QModelIndex& parent, int start, int end)
|
||||
{
|
||||
recreatePathgrid();
|
||||
mPathgrid->recreateGeometry();
|
||||
}
|
||||
|
||||
void CSVRender::Cell::pathgridRowAdded(const QModelIndex& parent, int start, int end)
|
||||
{
|
||||
recreatePathgrid();
|
||||
mPathgrid->recreateGeometry();
|
||||
}
|
||||
|
||||
void CSVRender::Cell::setSelection (int elementMask, Selection mode)
|
||||
|
@ -327,6 +305,15 @@ void CSVRender::Cell::setSelection (int elementMask, Selection mode)
|
|||
iter->second->setSelected (selected);
|
||||
}
|
||||
}
|
||||
if (elementMask & Mask_Pathgrid)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case Selection_Clear: mPathgrid->clearSelected(); break;
|
||||
case Selection_All: mPathgrid->selectAll(); break;
|
||||
case Selection_Invert: mPathgrid->invertSelected(); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CSVRender::Cell::selectAllWithSameParentId (int elementMask)
|
||||
|
@ -406,6 +393,9 @@ std::vector<osg::ref_ptr<CSVRender::TagBase> > CSVRender::Cell::getSelection (un
|
|||
iter!=mObjects.end(); ++iter)
|
||||
if (iter->second->getSelected())
|
||||
result.push_back (iter->second->getTag());
|
||||
if (elementMask & Mask_Pathgrid)
|
||||
if (mPathgrid->isSelected())
|
||||
result.push_back(mPathgrid->getTag());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -440,4 +430,6 @@ void CSVRender::Cell::reset (unsigned int elementMask)
|
|||
for (std::map<std::string, Object *>::const_iterator iter (mObjects.begin());
|
||||
iter!=mObjects.end(); ++iter)
|
||||
iter->second->reset();
|
||||
if (elementMask & Mask_Pathgrid)
|
||||
mPathgrid->resetMove();
|
||||
}
|
||||
|
|
|
@ -36,6 +36,7 @@ namespace CSMWorld
|
|||
|
||||
namespace CSVRender
|
||||
{
|
||||
class Pathgrid;
|
||||
class TagBase;
|
||||
|
||||
class Cell
|
||||
|
@ -43,14 +44,13 @@ namespace CSVRender
|
|||
CSMWorld::Data& mData;
|
||||
std::string mId;
|
||||
osg::ref_ptr<osg::Group> mCellNode;
|
||||
osg::ref_ptr<osg::Geode> mPathgridGeode;
|
||||
osg::ref_ptr<osg::Geometry> mPathgridGeometry;
|
||||
std::map<std::string, Object *> mObjects;
|
||||
std::auto_ptr<Terrain::TerrainGrid> mTerrain;
|
||||
CSMWorld::CellCoordinates mCoordinates;
|
||||
std::auto_ptr<CellArrow> mCellArrows[4];
|
||||
std::auto_ptr<CellMarker> mCellMarker;
|
||||
std::auto_ptr<CellBorder> mCellBorder;
|
||||
std::auto_ptr<Pathgrid> mPathgrid;
|
||||
bool mDeleted;
|
||||
int mSubMode;
|
||||
unsigned int mSubModeElementMask;
|
||||
|
@ -69,8 +69,6 @@ namespace CSVRender
|
|||
/// \return Have any objects been added?
|
||||
bool addObjects (int start, int end);
|
||||
|
||||
void recreatePathgrid();
|
||||
|
||||
public:
|
||||
|
||||
enum Selection
|
||||
|
|
287
apps/opencs/view/render/pathgrid.cpp
Normal file
287
apps/opencs/view/render/pathgrid.cpp
Normal file
|
@ -0,0 +1,287 @@
|
|||
#include "pathgrid.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <osg/Geode>
|
||||
#include <osg/Geometry>
|
||||
#include <osg/Group>
|
||||
#include <osg/PositionAttitudeTransform>
|
||||
#include <osg/Vec3>
|
||||
|
||||
#include <components/sceneutil/pathgridutil.hpp>
|
||||
|
||||
#include "../../model/world/commands.hpp"
|
||||
#include "../../model/world/commandmacro.hpp"
|
||||
#include "../../model/world/data.hpp"
|
||||
|
||||
namespace CSVRender
|
||||
{
|
||||
PathgridTag::PathgridTag(Pathgrid* pathgrid)
|
||||
: TagBase(Mask_Pathgrid), mPathgrid(pathgrid)
|
||||
{
|
||||
}
|
||||
|
||||
Pathgrid* PathgridTag::getPathgrid() const
|
||||
{
|
||||
return mPathgrid;
|
||||
}
|
||||
|
||||
QString PathgridTag::getToolTip(bool hideBasics) const
|
||||
{
|
||||
QString text("Pathgrid: ");
|
||||
text += mPathgrid->getId().c_str();
|
||||
|
||||
if (!hideBasics)
|
||||
{
|
||||
text += "<p>Only one pathgrid may be edited at a time.";
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
Pathgrid::Pathgrid(CSMWorld::Data& data, osg::Group* parent, const std::string& pathgridId,
|
||||
const CSMWorld::CellCoordinates& coordinates)
|
||||
: mData(data)
|
||||
, mId(pathgridId)
|
||||
, mCoords(coordinates)
|
||||
, mParent(parent)
|
||||
, mPathgridGeometry(0)
|
||||
, mSelectedGeometry(0)
|
||||
, mTag(new PathgridTag(this))
|
||||
{
|
||||
const float CoordScalar = ESM::Land::REAL_SIZE;
|
||||
|
||||
mBaseNode = new osg::PositionAttitudeTransform ();
|
||||
mBaseNode->setPosition(osg::Vec3f(mCoords.getX() * CoordScalar, mCoords.getY() * CoordScalar, 0.f));
|
||||
mBaseNode->setUserData(mTag);
|
||||
mBaseNode->setNodeMask(Mask_Pathgrid);
|
||||
mParent->addChild(mBaseNode);
|
||||
|
||||
mSelectedNode = new osg::PositionAttitudeTransform();
|
||||
mBaseNode->addChild(mSelectedNode);
|
||||
|
||||
mPathgridGeode = new osg::Geode();
|
||||
mBaseNode->addChild(mPathgridGeode);
|
||||
|
||||
mSelectedGeode = new osg::Geode();
|
||||
mSelectedNode->addChild(mSelectedGeode);
|
||||
|
||||
recreateGeometry();
|
||||
}
|
||||
|
||||
Pathgrid::~Pathgrid()
|
||||
{
|
||||
mParent->removeChild(mBaseNode);
|
||||
}
|
||||
|
||||
const CSMWorld::CellCoordinates& Pathgrid::getCoordinates() const
|
||||
{
|
||||
return mCoords;
|
||||
}
|
||||
|
||||
const std::string& Pathgrid::getId() const
|
||||
{
|
||||
return mId;
|
||||
}
|
||||
|
||||
bool Pathgrid::isSelected() const
|
||||
{
|
||||
return !mSelected.empty();
|
||||
}
|
||||
|
||||
const Pathgrid::NodeList& Pathgrid::getSelected() const
|
||||
{
|
||||
return mSelected;
|
||||
}
|
||||
|
||||
void Pathgrid::selectAll()
|
||||
{
|
||||
mSelected.clear();
|
||||
|
||||
const CSMWorld::SubCellCollection<CSMWorld::Pathgrid>& pathgrids = mData.getPathgrids();
|
||||
int pathgridIndex = pathgrids.searchId(mId);
|
||||
if (pathgridIndex != -1)
|
||||
{
|
||||
const CSMWorld::Pathgrid& source = pathgrids.getRecord(pathgridIndex).get();
|
||||
for (unsigned short i = 0; i < static_cast<unsigned short>(source.mPoints.size()); ++i)
|
||||
mSelected.push_back(i);
|
||||
|
||||
recreateSelectedGeometry(source);
|
||||
}
|
||||
else
|
||||
{
|
||||
removeSelectedGeometry();
|
||||
}
|
||||
}
|
||||
|
||||
void Pathgrid::toggleSelected(unsigned short node)
|
||||
{
|
||||
NodeList::iterator searchResult = std::find(mSelected.begin(), mSelected.end(), node);
|
||||
if (searchResult != mSelected.end())
|
||||
{
|
||||
mSelected.erase(searchResult);
|
||||
}
|
||||
else
|
||||
{
|
||||
mSelected.push_back(node);
|
||||
}
|
||||
|
||||
recreateSelectedGeometry();
|
||||
}
|
||||
|
||||
void Pathgrid::invertSelected()
|
||||
{
|
||||
NodeList temp = NodeList(mSelected.begin(), mSelected.end());
|
||||
mSelected.clear();
|
||||
|
||||
const CSMWorld::SubCellCollection<CSMWorld::Pathgrid>& pathgrids = mData.getPathgrids();
|
||||
int pathgridIndex = pathgrids.searchId(mId);
|
||||
if (pathgridIndex != -1)
|
||||
{
|
||||
const CSMWorld::Pathgrid& source = pathgrids.getRecord(pathgridIndex).get();
|
||||
for (unsigned short i = 0; i < static_cast<unsigned short>(source.mPoints.size()); ++i)
|
||||
{
|
||||
if (std::find(temp.begin(), temp.end(), i) == temp.end())
|
||||
mSelected.push_back(i);
|
||||
}
|
||||
|
||||
recreateSelectedGeometry(source);
|
||||
}
|
||||
else
|
||||
{
|
||||
removeSelectedGeometry();
|
||||
}
|
||||
}
|
||||
|
||||
void Pathgrid::clearSelected()
|
||||
{
|
||||
mSelected.clear();
|
||||
removeSelectedGeometry();
|
||||
}
|
||||
|
||||
void Pathgrid::moveSelected(const osg::Vec3d& offset)
|
||||
{
|
||||
mSelectedNode->setPosition(mSelectedNode->getPosition() + offset);
|
||||
}
|
||||
|
||||
void Pathgrid::resetMove()
|
||||
{
|
||||
mSelectedNode->setPosition(osg::Vec3f(0,0,0));
|
||||
}
|
||||
|
||||
void Pathgrid::applyPosition(CSMWorld::CommandMacro& commands)
|
||||
{
|
||||
const CSMWorld::SubCellCollection<CSMWorld::Pathgrid>& pathgrids = mData.getPathgrids();
|
||||
int pathgridIndex = pathgrids.searchId(mId);
|
||||
if (pathgridIndex != -1)
|
||||
{
|
||||
const CSMWorld::Pathgrid& source = pathgrids.getRecord(pathgridIndex).get();
|
||||
osg::Vec3d localCoords = mSelectedNode->getPosition();
|
||||
|
||||
int oX = static_cast<int>(localCoords.x());
|
||||
int oY = static_cast<int>(localCoords.y());
|
||||
int oZ = static_cast<int>(localCoords.z());
|
||||
|
||||
CSMWorld::SubCellCollection<CSMWorld::Pathgrid>& collection = mData.getPathgrids();
|
||||
QAbstractItemModel* model = mData.getTableModel (CSMWorld::UniversalId::Type_Pathgrids);
|
||||
|
||||
int recordIndex = collection.getIndex (mId);
|
||||
int parentColumn = collection.findColumnIndex(CSMWorld::Columns::ColumnId_PathgridPoints);
|
||||
|
||||
QModelIndex parent = model->index(recordIndex, parentColumn);
|
||||
|
||||
for (size_t i = 0; i < mSelected.size(); ++i)
|
||||
{
|
||||
const CSMWorld::Pathgrid::Point& point = source.mPoints[mSelected[i]];
|
||||
int row = mSelected[i];
|
||||
|
||||
// X
|
||||
int column = collection.searchNestedColumnIndex(parentColumn, CSMWorld::Columns::ColumnId_PathgridPosX);
|
||||
commands.push (new CSMWorld::ModifyCommand(*model, model->index(row, column, parent), point.mX + oX));
|
||||
|
||||
// Y
|
||||
column = collection.searchNestedColumnIndex(parentColumn, CSMWorld::Columns::ColumnId_PathgridPosY);
|
||||
commands.push (new CSMWorld::ModifyCommand(*model, model->index(row, column, parent), point.mY + oY));
|
||||
|
||||
// Z
|
||||
column = collection.searchNestedColumnIndex(parentColumn, CSMWorld::Columns::ColumnId_PathgridPosZ);
|
||||
commands.push (new CSMWorld::ModifyCommand(*model, model->index(row, column, parent), point.mZ + oZ));
|
||||
}
|
||||
}
|
||||
|
||||
resetMove();
|
||||
}
|
||||
|
||||
void Pathgrid::applyEdge(CSMWorld::CommandMacro& commands, unsigned short node1, unsigned short node2)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
void Pathgrid::applyEdges(CSMWorld::CommandMacro& commands, unsigned short node)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
osg::ref_ptr<PathgridTag> Pathgrid::getTag() const
|
||||
{
|
||||
return mTag;
|
||||
}
|
||||
|
||||
void Pathgrid::recreateGeometry()
|
||||
{
|
||||
removePathgridGeometry();
|
||||
removeSelectedGeometry();
|
||||
|
||||
// Make new
|
||||
const CSMWorld::SubCellCollection<CSMWorld::Pathgrid>& pathgrids = mData.getPathgrids();
|
||||
int pathgridIndex = pathgrids.searchId(mId);
|
||||
if (pathgridIndex != -1)
|
||||
{
|
||||
const CSMWorld::Pathgrid& source = pathgrids.getRecord(pathgridIndex).get();
|
||||
mPathgridGeometry = SceneUtil::createPathgridGeometry(source);
|
||||
mPathgridGeode->addDrawable(mPathgridGeometry);
|
||||
|
||||
recreateSelectedGeometry(source);
|
||||
}
|
||||
}
|
||||
|
||||
void Pathgrid::recreateSelectedGeometry()
|
||||
{
|
||||
const CSMWorld::SubCellCollection<CSMWorld::Pathgrid>& pathgrids = mData.getPathgrids();
|
||||
int pathgridIndex = pathgrids.searchId(mId);
|
||||
if (pathgridIndex != -1)
|
||||
{
|
||||
const CSMWorld::Pathgrid& source = pathgrids.getRecord(pathgridIndex).get();
|
||||
recreateSelectedGeometry(source);
|
||||
}
|
||||
else
|
||||
{
|
||||
removeSelectedGeometry();
|
||||
}
|
||||
}
|
||||
|
||||
void Pathgrid::recreateSelectedGeometry(const CSMWorld::Pathgrid& source)
|
||||
{
|
||||
removeSelectedGeometry();
|
||||
mSelectedGeometry = SceneUtil::createPathgridSelectedWireframe(source, mSelected);
|
||||
mSelectedGeode->addDrawable(mSelectedGeometry);
|
||||
}
|
||||
|
||||
void Pathgrid::removePathgridGeometry()
|
||||
{
|
||||
if (mPathgridGeometry)
|
||||
{
|
||||
mPathgridGeode->removeDrawable(mPathgridGeometry);
|
||||
mPathgridGeometry.release();
|
||||
}
|
||||
}
|
||||
|
||||
void Pathgrid::removeSelectedGeometry()
|
||||
{
|
||||
if (mSelectedGeometry)
|
||||
{
|
||||
mSelectedGeode->removeDrawable(mSelectedGeometry);
|
||||
mSelectedGeometry.release();
|
||||
}
|
||||
}
|
||||
}
|
105
apps/opencs/view/render/pathgrid.hpp
Normal file
105
apps/opencs/view/render/pathgrid.hpp
Normal file
|
@ -0,0 +1,105 @@
|
|||
#ifndef CSV_RENDER_PATHGRID_H
|
||||
#define CSV_RENDER_PATHGRID_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <QString>
|
||||
#include <osg/ref_ptr>
|
||||
|
||||
#include "../../model/world/cellcoordinates.hpp"
|
||||
|
||||
#include "tagbase.hpp"
|
||||
|
||||
namespace osg
|
||||
{
|
||||
class Geode;
|
||||
class Geometry;
|
||||
class Group;
|
||||
class PositionAttitudeTransform;
|
||||
class Vec3d;
|
||||
}
|
||||
|
||||
namespace CSMWorld
|
||||
{
|
||||
class CommandMacro;
|
||||
class Data;
|
||||
class Pathgrid;
|
||||
}
|
||||
|
||||
namespace CSVRender
|
||||
{
|
||||
class Pathgrid;
|
||||
|
||||
class PathgridTag : public TagBase
|
||||
{
|
||||
public:
|
||||
|
||||
PathgridTag (Pathgrid* pathgrid);
|
||||
|
||||
Pathgrid* getPathgrid () const;
|
||||
|
||||
virtual QString getToolTip (bool hideBasics) const;
|
||||
|
||||
private:
|
||||
|
||||
Pathgrid* mPathgrid;
|
||||
};
|
||||
|
||||
class Pathgrid
|
||||
{
|
||||
public:
|
||||
|
||||
typedef std::vector<unsigned short> NodeList;
|
||||
|
||||
Pathgrid(CSMWorld::Data& data, osg::Group* parent, const std::string& pathgridId,
|
||||
const CSMWorld::CellCoordinates& coordinates);
|
||||
|
||||
~Pathgrid();
|
||||
|
||||
const CSMWorld::CellCoordinates& getCoordinates() const;
|
||||
const std::string& getId() const;
|
||||
|
||||
bool isSelected() const;
|
||||
const NodeList& getSelected() const;
|
||||
void selectAll();
|
||||
void toggleSelected(unsigned short node); // Adds to end of vector
|
||||
void invertSelected();
|
||||
void clearSelected();
|
||||
|
||||
void moveSelected(const osg::Vec3d& offset);
|
||||
void resetMove();
|
||||
|
||||
void applyPosition(CSMWorld::CommandMacro& commands);
|
||||
void applyEdge(CSMWorld::CommandMacro& commands, unsigned short node1, unsigned short node2);
|
||||
void applyEdges(CSMWorld::CommandMacro& commands, unsigned short node);
|
||||
|
||||
osg::ref_ptr<PathgridTag> getTag() const;
|
||||
|
||||
void recreateGeometry();
|
||||
|
||||
private:
|
||||
|
||||
CSMWorld::Data& mData;
|
||||
std::string mId;
|
||||
CSMWorld::CellCoordinates mCoords;
|
||||
|
||||
NodeList mSelected;
|
||||
|
||||
osg::Group* mParent;
|
||||
osg::ref_ptr<osg::PositionAttitudeTransform> mBaseNode;
|
||||
osg::ref_ptr<osg::PositionAttitudeTransform> mSelectedNode;
|
||||
osg::ref_ptr<osg::Geode> mPathgridGeode;
|
||||
osg::ref_ptr<osg::Geode> mSelectedGeode;
|
||||
osg::ref_ptr<osg::Geometry> mPathgridGeometry;
|
||||
osg::ref_ptr<osg::Geometry> mSelectedGeometry;
|
||||
|
||||
osg::ref_ptr<PathgridTag> mTag;
|
||||
|
||||
void recreateSelectedGeometry();
|
||||
void recreateSelectedGeometry(const CSMWorld::Pathgrid& source);
|
||||
void removePathgridGeometry();
|
||||
void removeSelectedGeometry();
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
152
apps/opencs/view/render/pathgridmode.cpp
Normal file
152
apps/opencs/view/render/pathgridmode.cpp
Normal file
|
@ -0,0 +1,152 @@
|
|||
#include "pathgridmode.hpp"
|
||||
|
||||
#include <components/sceneutil/pathgridutil.hpp>
|
||||
|
||||
#include "../../model/world/commands.hpp"
|
||||
#include "../../model/world/commandmacro.hpp"
|
||||
#include "../../model/world/idtable.hpp"
|
||||
#include "../../model/world/idtree.hpp"
|
||||
|
||||
#include "mask.hpp"
|
||||
#include "pathgrid.hpp"
|
||||
#include "worldspacewidget.hpp"
|
||||
|
||||
namespace CSVRender
|
||||
{
|
||||
PathgridMode::PathgridMode(WorldspaceWidget* worldspaceWidget, QWidget* parent)
|
||||
: EditMode(worldspaceWidget, QIcon(":placeholder"), Mask_Pathgrid, "Pathgrid editing", parent)
|
||||
, mDragMode(DragMode_None)
|
||||
, mFromNode(0)
|
||||
{
|
||||
}
|
||||
|
||||
void PathgridMode::primaryEditPressed(const WorldspaceHitResult& hit)
|
||||
{
|
||||
}
|
||||
|
||||
void PathgridMode::secondaryEditPressed(const WorldspaceHitResult& hit)
|
||||
{
|
||||
}
|
||||
|
||||
void PathgridMode::primarySelectPressed(const WorldspaceHitResult& hit)
|
||||
{
|
||||
getWorldspaceWidget().clearSelection(Mask_Pathgrid);
|
||||
|
||||
if (hit.tag)
|
||||
{
|
||||
if (PathgridTag* tag = dynamic_cast<PathgridTag*>(hit.tag.get()))
|
||||
{
|
||||
unsigned short node = SceneUtil::getPathgridNode(static_cast<unsigned short>(hit.i0));
|
||||
tag->getPathgrid()->toggleSelected(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PathgridMode::secondarySelectPressed(const WorldspaceHitResult& hit)
|
||||
{
|
||||
if (hit.tag)
|
||||
{
|
||||
if (PathgridTag* tag = dynamic_cast<PathgridTag*>(hit.tag.get()))
|
||||
{
|
||||
if (tag->getPathgrid()->getId() != mLastId)
|
||||
{
|
||||
getWorldspaceWidget().clearSelection(Mask_Pathgrid);
|
||||
mLastId = tag->getPathgrid()->getId();
|
||||
}
|
||||
|
||||
unsigned short node = SceneUtil::getPathgridNode(static_cast<unsigned short>(hit.i0));
|
||||
tag->getPathgrid()->toggleSelected(node);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
getWorldspaceWidget().clearSelection(Mask_Pathgrid);
|
||||
}
|
||||
|
||||
bool PathgridMode::primaryEditStartDrag(const WorldspaceHitResult& hit)
|
||||
{
|
||||
std::vector<osg::ref_ptr<TagBase> > selection = getWorldspaceWidget().getSelection (Mask_Pathgrid);
|
||||
|
||||
if (!selection.empty())
|
||||
{
|
||||
mDragMode = DragMode_Move;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool PathgridMode::secondaryEditStartDrag(const WorldspaceHitResult& hit)
|
||||
{
|
||||
if (hit.tag)
|
||||
{
|
||||
if (PathgridTag* tag = dynamic_cast<PathgridTag*>(hit.tag.get()))
|
||||
{
|
||||
mDragMode = DragMode_Edge;
|
||||
mFromNode = SceneUtil::getPathgridNode(static_cast<unsigned short>(hit.i0));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void PathgridMode::drag(int diffX, int diffY, double speedFactor)
|
||||
{
|
||||
std::vector<osg::ref_ptr<TagBase> > selection = getWorldspaceWidget().getSelection (Mask_Pathgrid);
|
||||
|
||||
for (std::vector<osg::ref_ptr<TagBase> >::iterator it = selection.begin(); it != selection.end(); ++it)
|
||||
{
|
||||
if (PathgridTag* tag = dynamic_cast<PathgridTag*>(it->get()))
|
||||
{
|
||||
if (mDragMode == DragMode_Move)
|
||||
{
|
||||
osg::Vec3d eye, center, up, offset;
|
||||
getWorldspaceWidget().getCamera()->getViewMatrix().getLookAt (eye, center, up);
|
||||
|
||||
offset = (up * diffY * speedFactor) + (((center - eye) ^ up) * diffX * speedFactor);
|
||||
|
||||
tag->getPathgrid()->moveSelected(offset);
|
||||
}
|
||||
else if (mDragMode == DragMode_Edge)
|
||||
{
|
||||
// TODO make indicators
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PathgridMode::dragCompleted()
|
||||
{
|
||||
std::vector<osg::ref_ptr<TagBase> > selection = getWorldspaceWidget().getSelection (Mask_Pathgrid);
|
||||
|
||||
for (std::vector<osg::ref_ptr<TagBase> >::iterator it = selection.begin(); it != selection.end(); ++it)
|
||||
{
|
||||
if (PathgridTag* tag = dynamic_cast<PathgridTag*>(it->get()))
|
||||
{
|
||||
if (mDragMode == DragMode_Move)
|
||||
{
|
||||
QUndoStack& undoStack = getWorldspaceWidget().getDocument().getUndoStack();
|
||||
QString description = "Move pathgrid node(s)";
|
||||
|
||||
CSMWorld::CommandMacro macro(undoStack, description);
|
||||
tag->getPathgrid()->applyPosition(macro);
|
||||
}
|
||||
else if (mDragMode == DragMode_Edge)
|
||||
{
|
||||
// TODO raycast for other node and apply if needed with mFromNode
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mDragMode = DragMode_None;
|
||||
}
|
||||
|
||||
void PathgridMode::dragAborted()
|
||||
{
|
||||
getWorldspaceWidget().reset(Mask_Pathgrid);
|
||||
}
|
||||
}
|
53
apps/opencs/view/render/pathgridmode.hpp
Normal file
53
apps/opencs/view/render/pathgridmode.hpp
Normal file
|
@ -0,0 +1,53 @@
|
|||
#ifndef CSV_RENDER_PATHGRIDMODE_H
|
||||
#define CSV_RENDER_PATHGRIDMODE_H
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "editmode.hpp"
|
||||
|
||||
namespace CSVRender
|
||||
{
|
||||
class PathgridMode : public EditMode
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
PathgridMode(WorldspaceWidget* worldspace, QWidget* parent=0);
|
||||
|
||||
virtual void primaryEditPressed(const WorldspaceHitResult& hit);
|
||||
|
||||
virtual void secondaryEditPressed(const WorldspaceHitResult& hit);
|
||||
|
||||
virtual void primarySelectPressed(const WorldspaceHitResult& hit);
|
||||
|
||||
virtual void secondarySelectPressed(const WorldspaceHitResult& hit);
|
||||
|
||||
virtual bool primaryEditStartDrag (const WorldspaceHitResult& hit);
|
||||
|
||||
virtual bool secondaryEditStartDrag (const WorldspaceHitResult& hit);
|
||||
|
||||
virtual void drag (int diffX, int diffY, double speedFactor);
|
||||
|
||||
virtual void dragCompleted();
|
||||
|
||||
/// \note dragAborted will not be called, if the drag is aborted via changing
|
||||
/// editing mode
|
||||
virtual void dragAborted();
|
||||
|
||||
private:
|
||||
|
||||
enum DragMode
|
||||
{
|
||||
DragMode_None,
|
||||
DragMode_Move,
|
||||
DragMode_Edge
|
||||
};
|
||||
|
||||
std::string mLastId;
|
||||
DragMode mDragMode;
|
||||
unsigned short mFromNode;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -27,8 +27,8 @@
|
|||
|
||||
#include "object.hpp"
|
||||
#include "mask.hpp"
|
||||
#include "editmode.hpp"
|
||||
#include "instancemode.hpp"
|
||||
#include "pathgridmode.hpp"
|
||||
#include "cameracontroller.hpp"
|
||||
|
||||
CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidget* parent)
|
||||
|
@ -295,7 +295,7 @@ unsigned int CSVRender::WorldspaceWidget::getVisibilityMask() const
|
|||
|
||||
void CSVRender::WorldspaceWidget::setInteractionMask (unsigned int mask)
|
||||
{
|
||||
mInteractionMask = mask | Mask_CellMarker | Mask_CellArrow;
|
||||
mInteractionMask = mask | Mask_CellMarker | Mask_CellArrow | Mask_Pathgrid | Mask_Terrain;
|
||||
}
|
||||
|
||||
unsigned int CSVRender::WorldspaceWidget::getInteractionMask() const
|
||||
|
@ -320,9 +320,7 @@ void CSVRender::WorldspaceWidget::addEditModeSelectorButtons (CSVWidget::SceneTo
|
|||
{
|
||||
/// \todo replace EditMode with suitable subclasses
|
||||
tool->addButton (new InstanceMode (this, tool), "object");
|
||||
tool->addButton (
|
||||
new EditMode (this, QIcon (":placeholder"), Mask_Pathgrid, "Pathgrid editing"),
|
||||
"pathgrid");
|
||||
tool->addButton (new PathgridMode (this, tool), "pathgrid");
|
||||
}
|
||||
|
||||
CSMDoc::Document& CSVRender::WorldspaceWidget::getDocument()
|
||||
|
|
|
@ -9,6 +9,7 @@ namespace SceneUtil
|
|||
{
|
||||
const unsigned short DiamondVertexCount = 6;
|
||||
const unsigned short DiamondIndexCount = 24;
|
||||
const unsigned short DiamondWireframeIndexCount = 24;
|
||||
|
||||
const unsigned short DiamondConnectorVertexCount = 4;
|
||||
|
||||
|
@ -16,6 +17,7 @@ namespace SceneUtil
|
|||
|
||||
const float DiamondHalfHeight = 40.f;
|
||||
const float DiamondHalfWidth = 16.f;
|
||||
const float DiamondWireframeScalar = 1.1f;
|
||||
|
||||
const osg::Vec3f DiamondPoints[DiamondVertexCount] =
|
||||
{
|
||||
|
@ -39,6 +41,22 @@ namespace SceneUtil
|
|||
5, 2, 4
|
||||
};
|
||||
|
||||
const unsigned short DiamondWireframeIndices[DiamondWireframeIndexCount] =
|
||||
{
|
||||
0, 1,
|
||||
0, 2,
|
||||
0, 3,
|
||||
0, 4,
|
||||
1, 2,
|
||||
2, 4,
|
||||
4, 3,
|
||||
3, 1,
|
||||
5, 1,
|
||||
5, 2,
|
||||
5, 3,
|
||||
5, 4
|
||||
};
|
||||
|
||||
const unsigned short DiamondConnectorVertices[DiamondConnectorVertexCount] =
|
||||
{
|
||||
1, 2, 3, 4
|
||||
|
@ -55,6 +73,8 @@ namespace SceneUtil
|
|||
};
|
||||
|
||||
const osg::Vec4f DiamondEdgeColor = osg::Vec4f(0.5f, 1.f, 1.f, 1.f);
|
||||
const osg::Vec4f DiamondWireColor = osg::Vec4f(0.8f, 1.f, 0.9f, 1.f);
|
||||
const osg::Vec4f DiamondFocusWireColor = osg::Vec4f(0.4f, 1.f, 0.4f, 1.f);
|
||||
|
||||
osg::ref_ptr<osg::Geometry> createPathgridGeometry(const ESM::Pathgrid& pathgrid)
|
||||
{
|
||||
|
@ -155,4 +175,61 @@ namespace SceneUtil
|
|||
|
||||
return gridGeometry;
|
||||
}
|
||||
|
||||
osg::ref_ptr<osg::Geometry> createPathgridSelectedWireframe(const ESM::Pathgrid& pathgrid,
|
||||
const std::vector<unsigned short>& selected)
|
||||
{
|
||||
const unsigned short PointCount = selected.size();
|
||||
|
||||
const unsigned short VertexCount = PointCount * DiamondVertexCount;
|
||||
const unsigned short ColorCount = VertexCount;
|
||||
const size_t IndexCount = PointCount * DiamondWireframeIndexCount;
|
||||
|
||||
osg::ref_ptr<osg::Geometry> wireframeGeometry = new osg::Geometry();
|
||||
|
||||
osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array(VertexCount);
|
||||
osg::ref_ptr<osg::Vec4Array> colors = new osg::Vec4Array(ColorCount);
|
||||
osg::ref_ptr<osg::DrawElementsUShort> indices =
|
||||
new osg::DrawElementsUShort(osg::PrimitiveSet::LINES, IndexCount);
|
||||
|
||||
osg::Vec3f wireOffset = osg::Vec3f(0, 0, (1 - DiamondWireframeScalar) * DiamondHalfHeight);
|
||||
|
||||
// Add each point/node
|
||||
for (unsigned short it = 0; it < PointCount; ++it)
|
||||
{
|
||||
const ESM::Pathgrid::Point& point = pathgrid.mPoints[selected[it]];
|
||||
osg::Vec3f position = osg::Vec3f(point.mX, point.mY, point.mZ) + wireOffset;
|
||||
|
||||
unsigned short vertexOffset = it * DiamondVertexCount;
|
||||
unsigned short indexOffset = it * DiamondWireframeIndexCount;
|
||||
|
||||
// Point
|
||||
for (unsigned short i = 0; i < DiamondVertexCount; ++i)
|
||||
{
|
||||
(*vertices)[vertexOffset + i] = position + DiamondPoints[i] * DiamondWireframeScalar;
|
||||
|
||||
if (it == PointCount - 1)
|
||||
(*colors)[vertexOffset + i] = DiamondFocusWireColor;
|
||||
else
|
||||
(*colors)[vertexOffset + i] = DiamondWireColor;
|
||||
}
|
||||
|
||||
for (unsigned short i = 0; i < DiamondWireframeIndexCount; ++i)
|
||||
{
|
||||
indices->setElement(indexOffset + i, vertexOffset + DiamondWireframeIndices[i]);
|
||||
}
|
||||
}
|
||||
|
||||
wireframeGeometry->setVertexArray(vertices);
|
||||
wireframeGeometry->setColorArray(colors, osg::Array::BIND_PER_VERTEX);
|
||||
wireframeGeometry->addPrimitiveSet(indices);
|
||||
wireframeGeometry->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
|
||||
|
||||
return wireframeGeometry;
|
||||
}
|
||||
|
||||
unsigned short getPathgridNode(unsigned short vertexIndex)
|
||||
{
|
||||
return vertexIndex / (DiamondVertexCount + DiamondConnectorVertexCount);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,11 @@ namespace ESM
|
|||
namespace SceneUtil
|
||||
{
|
||||
osg::ref_ptr<osg::Geometry> createPathgridGeometry(const ESM::Pathgrid& pathgrid);
|
||||
|
||||
osg::ref_ptr<osg::Geometry> createPathgridSelectedWireframe(const ESM::Pathgrid& pathgrid,
|
||||
const std::vector<unsigned short>& selected);
|
||||
|
||||
unsigned short getPathgridNode(unsigned short vertexIndex);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue