mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-16 18:19:55 +00:00
Merge remote-tracking branch 'aesylwinn/EditPathgrid'
This commit is contained in:
commit
b079db7913
32 changed files with 1867 additions and 472 deletions
|
@ -86,12 +86,12 @@ opencs_units (view/widget
|
||||||
opencs_units (view/render
|
opencs_units (view/render
|
||||||
scenewidget worldspacewidget pagedworldspacewidget unpagedworldspacewidget
|
scenewidget worldspacewidget pagedworldspacewidget unpagedworldspacewidget
|
||||||
previewwidget editmode instancemode instanceselectionmode instancemovemode
|
previewwidget editmode instancemode instanceselectionmode instancemovemode
|
||||||
orbitcameramode
|
orbitcameramode pathgridmode selectionmode pathgridselectionmode
|
||||||
)
|
)
|
||||||
|
|
||||||
opencs_units_noqt (view/render
|
opencs_units_noqt (view/render
|
||||||
lighting lightingday lightingnight lightingbright object cell terrainstorage tagbase
|
lighting lightingday lightingnight lightingbright object cell terrainstorage tagbase
|
||||||
cellarrow cellmarker cellborder cameracontroller
|
cellarrow cellmarker cellborder cameracontroller pathgrid
|
||||||
)
|
)
|
||||||
|
|
||||||
opencs_hdrs_noqt (view/render
|
opencs_hdrs_noqt (view/render
|
||||||
|
|
|
@ -70,20 +70,6 @@ void CSMTools::PathgridCheckStage::perform (int stage, CSMDoc::Messages& message
|
||||||
|
|
||||||
for (unsigned int i = 0; i < pathgrid.mPoints.size(); ++i)
|
for (unsigned int i = 0; i < pathgrid.mPoints.size(); ++i)
|
||||||
{
|
{
|
||||||
// check the connection number for each point matches the edge connections
|
|
||||||
if (pathgrid.mPoints[i].mConnectionNum > pointList[i].mConnectionNum)
|
|
||||||
{
|
|
||||||
std::ostringstream ss;
|
|
||||||
ss << " has has less edges than expected for point " << i;
|
|
||||||
messages.add (id, pathgrid.mId + ss.str(), "", CSMDoc::Message::Severity_Error);
|
|
||||||
}
|
|
||||||
else if (pathgrid.mPoints[i].mConnectionNum < pointList[i].mConnectionNum)
|
|
||||||
{
|
|
||||||
std::ostringstream ss;
|
|
||||||
ss << " has has more edges than expected for point " << i;
|
|
||||||
messages.add (id, pathgrid.mId + ss.str(), "", CSMDoc::Message::Severity_Error);
|
|
||||||
}
|
|
||||||
|
|
||||||
// check that edges are bidirectional
|
// check that edges are bidirectional
|
||||||
bool foundReverse = false;
|
bool foundReverse = false;
|
||||||
for (unsigned int j = 0; j < pointList[i].mOtherIndex.size(); ++j)
|
for (unsigned int j = 0; j < pointList[i].mOtherIndex.size(); ++j)
|
||||||
|
|
|
@ -8,9 +8,12 @@
|
||||||
#include <QAbstractItemModel>
|
#include <QAbstractItemModel>
|
||||||
#include <QAbstractProxyModel>
|
#include <QAbstractProxyModel>
|
||||||
|
|
||||||
|
#include "cellcoordinates.hpp"
|
||||||
|
#include "idcollection.hpp"
|
||||||
#include "idtable.hpp"
|
#include "idtable.hpp"
|
||||||
#include "idtree.hpp"
|
#include "idtree.hpp"
|
||||||
#include "nestedtablewrapper.hpp"
|
#include "nestedtablewrapper.hpp"
|
||||||
|
#include "pathgrid.hpp"
|
||||||
|
|
||||||
CSMWorld::ModifyCommand::ModifyCommand (QAbstractItemModel& model, const QModelIndex& index,
|
CSMWorld::ModifyCommand::ModifyCommand (QAbstractItemModel& model, const QModelIndex& index,
|
||||||
const QVariant& new_, QUndoCommand* parent)
|
const QVariant& new_, QUndoCommand* parent)
|
||||||
|
@ -235,6 +238,29 @@ void CSMWorld::CloneCommand::undo()
|
||||||
mModel.removeRow (mModel.getModelIndex (mId, 0).row());
|
mModel.removeRow (mModel.getModelIndex (mId, 0).row());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CSMWorld::CreatePathgridCommand::CreatePathgridCommand(IdTable& model, const std::string& id, QUndoCommand *parent)
|
||||||
|
: CreateCommand(model, id, parent)
|
||||||
|
{
|
||||||
|
setType(UniversalId::Type_Pathgrid);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSMWorld::CreatePathgridCommand::redo()
|
||||||
|
{
|
||||||
|
CreateCommand::redo();
|
||||||
|
|
||||||
|
Record<Pathgrid> record = static_cast<const Record<Pathgrid>& >(mModel.getRecord(mId));
|
||||||
|
record.get().blank();
|
||||||
|
record.get().mCell = mId;
|
||||||
|
|
||||||
|
std::pair<CellCoordinates, bool> coords = CellCoordinates::fromId(mId);
|
||||||
|
if (coords.second)
|
||||||
|
{
|
||||||
|
record.get().mData.mX = coords.first.getX();
|
||||||
|
record.get().mData.mY = coords.first.getY();
|
||||||
|
}
|
||||||
|
|
||||||
|
mModel.setRecord(mId, record, mType);
|
||||||
|
}
|
||||||
|
|
||||||
CSMWorld::UpdateCellCommand::UpdateCellCommand (IdTable& model, int row, QUndoCommand *parent)
|
CSMWorld::UpdateCellCommand::UpdateCellCommand (IdTable& model, int row, QUndoCommand *parent)
|
||||||
: QUndoCommand (parent), mModel (model), mRow (row)
|
: QUndoCommand (parent), mModel (model), mRow (row)
|
||||||
|
|
|
@ -153,6 +153,15 @@ namespace CSMWorld
|
||||||
virtual void undo();
|
virtual void undo();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class CreatePathgridCommand : public CreateCommand
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
CreatePathgridCommand(IdTable& model, const std::string& id, QUndoCommand *parent = 0);
|
||||||
|
|
||||||
|
virtual void redo();
|
||||||
|
};
|
||||||
|
|
||||||
/// \brief Update cell ID according to x/y-coordinates
|
/// \brief Update cell ID according to x/y-coordinates
|
||||||
///
|
///
|
||||||
/// \note The new value will be calculated in the first call to redo instead of the
|
/// \note The new value will be calculated in the first call to redo instead of the
|
||||||
|
|
|
@ -27,20 +27,8 @@ namespace CSMWorld
|
||||||
point.mConnectionNum = 0;
|
point.mConnectionNum = 0;
|
||||||
point.mUnknown = 0;
|
point.mUnknown = 0;
|
||||||
|
|
||||||
// inserting a point should trigger re-indexing of the edges
|
|
||||||
//
|
|
||||||
// FIXME: does not auto refresh edges table view
|
|
||||||
std::vector<ESM::Pathgrid::Edge>::iterator iter = pathgrid.mEdges.begin();
|
|
||||||
for (;iter != pathgrid.mEdges.end(); ++iter)
|
|
||||||
{
|
|
||||||
if ((*iter).mV0 >= position)
|
|
||||||
(*iter).mV0++;
|
|
||||||
if ((*iter).mV1 >= position)
|
|
||||||
(*iter).mV1++;
|
|
||||||
}
|
|
||||||
|
|
||||||
points.insert(points.begin()+position, point);
|
points.insert(points.begin()+position, point);
|
||||||
pathgrid.mData.mS2 += 1; // increment the number of points
|
pathgrid.mData.mS2 = pathgrid.mPoints.size();
|
||||||
|
|
||||||
record.setModified (pathgrid);
|
record.setModified (pathgrid);
|
||||||
}
|
}
|
||||||
|
@ -54,28 +42,10 @@ namespace CSMWorld
|
||||||
if (rowToRemove < 0 || rowToRemove >= static_cast<int> (points.size()))
|
if (rowToRemove < 0 || rowToRemove >= static_cast<int> (points.size()))
|
||||||
throw std::runtime_error ("index out of range");
|
throw std::runtime_error ("index out of range");
|
||||||
|
|
||||||
// deleting a point should trigger re-indexing of the edges
|
// Do not remove dangling edges, does not work with current undo mechanism
|
||||||
// dangling edges are not allowed and hence removed
|
// Do not automatically adjust indices, what would be done with dangling edges?
|
||||||
//
|
|
||||||
// FIXME: does not auto refresh edges table view
|
|
||||||
std::vector<ESM::Pathgrid::Edge>::iterator iter = pathgrid.mEdges.begin();
|
|
||||||
for (; iter != pathgrid.mEdges.end();)
|
|
||||||
{
|
|
||||||
if (((*iter).mV0 == rowToRemove) || ((*iter).mV1 == rowToRemove))
|
|
||||||
iter = pathgrid.mEdges.erase(iter);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if ((*iter).mV0 > rowToRemove)
|
|
||||||
(*iter).mV0--;
|
|
||||||
|
|
||||||
if ((*iter).mV1 > rowToRemove)
|
|
||||||
(*iter).mV1--;
|
|
||||||
|
|
||||||
++iter;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
points.erase(points.begin()+rowToRemove);
|
points.erase(points.begin()+rowToRemove);
|
||||||
pathgrid.mData.mS2 -= 1; // decrement the number of points
|
pathgrid.mData.mS2 = pathgrid.mPoints.size();
|
||||||
|
|
||||||
record.setModified (pathgrid);
|
record.setModified (pathgrid);
|
||||||
}
|
}
|
||||||
|
@ -84,14 +54,8 @@ namespace CSMWorld
|
||||||
const NestedTableWrapperBase& nestedTable) const
|
const NestedTableWrapperBase& nestedTable) const
|
||||||
{
|
{
|
||||||
Pathgrid pathgrid = record.get();
|
Pathgrid pathgrid = record.get();
|
||||||
|
pathgrid.mPoints = static_cast<const NestedTableWrapper<ESM::Pathgrid::PointList> &>(nestedTable).mNestedTable;
|
||||||
pathgrid.mPoints =
|
pathgrid.mData.mS2 = pathgrid.mPoints.size();
|
||||||
static_cast<const PathgridPointsWrap &>(nestedTable).mRecord.mPoints;
|
|
||||||
pathgrid.mData.mS2 =
|
|
||||||
static_cast<const PathgridPointsWrap &>(nestedTable).mRecord.mData.mS2;
|
|
||||||
// also update edges in case points were added/removed
|
|
||||||
pathgrid.mEdges =
|
|
||||||
static_cast<const PathgridPointsWrap &>(nestedTable).mRecord.mEdges;
|
|
||||||
|
|
||||||
record.setModified (pathgrid);
|
record.setModified (pathgrid);
|
||||||
}
|
}
|
||||||
|
@ -99,7 +63,7 @@ namespace CSMWorld
|
||||||
NestedTableWrapperBase* PathgridPointListAdapter::table(const Record<Pathgrid>& record) const
|
NestedTableWrapperBase* PathgridPointListAdapter::table(const Record<Pathgrid>& record) const
|
||||||
{
|
{
|
||||||
// deleted by dtor of NestedTableStoring
|
// deleted by dtor of NestedTableStoring
|
||||||
return new PathgridPointsWrap(record.get());
|
return new NestedTableWrapper<ESM::Pathgrid::PointList>(record.get().mPoints);
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant PathgridPointListAdapter::getData(const Record<Pathgrid>& record,
|
QVariant PathgridPointListAdapter::getData(const Record<Pathgrid>& record,
|
||||||
|
@ -147,7 +111,6 @@ namespace CSMWorld
|
||||||
|
|
||||||
PathgridEdgeListAdapter::PathgridEdgeListAdapter () {}
|
PathgridEdgeListAdapter::PathgridEdgeListAdapter () {}
|
||||||
|
|
||||||
// ToDo: seems to be auto-sorted in the dialog table display after insertion
|
|
||||||
void PathgridEdgeListAdapter::addRow(Record<Pathgrid>& record, int position) const
|
void PathgridEdgeListAdapter::addRow(Record<Pathgrid>& record, int position) const
|
||||||
{
|
{
|
||||||
Pathgrid pathgrid = record.get();
|
Pathgrid pathgrid = record.get();
|
||||||
|
@ -218,7 +181,6 @@ namespace CSMWorld
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToDo: detect duplicates in mEdges
|
|
||||||
void PathgridEdgeListAdapter::setData(Record<Pathgrid>& record,
|
void PathgridEdgeListAdapter::setData(Record<Pathgrid>& record,
|
||||||
const QVariant& value, int subRowIndex, int subColIndex) const
|
const QVariant& value, int subRowIndex, int subColIndex) const
|
||||||
{
|
{
|
||||||
|
|
|
@ -25,21 +25,6 @@ namespace CSMWorld
|
||||||
struct Pathgrid;
|
struct Pathgrid;
|
||||||
struct Info;
|
struct Info;
|
||||||
|
|
||||||
struct PathgridPointsWrap : public NestedTableWrapperBase
|
|
||||||
{
|
|
||||||
ESM::Pathgrid mRecord;
|
|
||||||
|
|
||||||
PathgridPointsWrap(ESM::Pathgrid pathgrid)
|
|
||||||
: mRecord(pathgrid) {}
|
|
||||||
|
|
||||||
virtual ~PathgridPointsWrap() {}
|
|
||||||
|
|
||||||
virtual int size() const
|
|
||||||
{
|
|
||||||
return mRecord.mPoints.size(); // used in IdTree::setNestedTable()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class PathgridPointListAdapter : public NestedColumnAdapter<Pathgrid>
|
class PathgridPointListAdapter : public NestedColumnAdapter<Pathgrid>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include "../../model/world/cellcoordinates.hpp"
|
#include "../../model/world/cellcoordinates.hpp"
|
||||||
|
|
||||||
#include "mask.hpp"
|
#include "mask.hpp"
|
||||||
|
#include "pathgrid.hpp"
|
||||||
#include "terrainstorage.hpp"
|
#include "terrainstorage.hpp"
|
||||||
|
|
||||||
bool CSVRender::Cell::removeObject (const std::string& id)
|
bool CSVRender::Cell::removeObject (const std::string& id)
|
||||||
|
@ -68,18 +69,6 @@ bool CSVRender::Cell::addObjects (int start, int end)
|
||||||
return modified;
|
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,
|
CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::string& id,
|
||||||
bool deleted)
|
bool deleted)
|
||||||
: mData (data), mId (Misc::StringUtils::lowerCase (id)), mDeleted (deleted), mSubMode (0),
|
: 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;
|
mCellNode = new osg::Group;
|
||||||
rootNode->addChild(mCellNode);
|
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();
|
setCellMarker();
|
||||||
|
|
||||||
if (!mDeleted)
|
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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,6 +123,11 @@ CSVRender::Cell::~Cell()
|
||||||
mCellNode->getParent(0)->removeChild(mCellNode);
|
mCellNode->getParent(0)->removeChild(mCellNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CSVRender::Pathgrid* CSVRender::Cell::getPathgrid() const
|
||||||
|
{
|
||||||
|
return mPathgrid.get();
|
||||||
|
}
|
||||||
|
|
||||||
bool CSVRender::Cell::referenceableDataChanged (const QModelIndex& topLeft,
|
bool CSVRender::Cell::referenceableDataChanged (const QModelIndex& topLeft,
|
||||||
const QModelIndex& bottomRight)
|
const QModelIndex& bottomRight)
|
||||||
{
|
{
|
||||||
|
@ -283,29 +266,14 @@ bool CSVRender::Cell::referenceAdded (const QModelIndex& parent, int start, int
|
||||||
return addObjects (start, end);
|
return addObjects (start, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSVRender::Cell::pathgridAdded(const CSMWorld::Pathgrid& pathgrid)
|
void CSVRender::Cell::pathgridModified()
|
||||||
{
|
{
|
||||||
recreatePathgrid();
|
mPathgrid->recreateGeometry();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSVRender::Cell::pathgridRemoved()
|
void CSVRender::Cell::pathgridRemoved()
|
||||||
{
|
{
|
||||||
mPathgridGeode->removeDrawable(mPathgridGeometry);
|
mPathgrid->removeGeometry();
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
void CSVRender::Cell::setSelection (int elementMask, Selection mode)
|
||||||
|
@ -327,6 +295,27 @@ void CSVRender::Cell::setSelection (int elementMask, Selection mode)
|
||||||
iter->second->setSelected (selected);
|
iter->second->setSelected (selected);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (elementMask & Mask_Pathgrid)
|
||||||
|
{
|
||||||
|
// Only one pathgrid may be selected, so some operations will only have an effect
|
||||||
|
// if the pathgrid is already focused
|
||||||
|
switch (mode)
|
||||||
|
{
|
||||||
|
case Selection_Clear:
|
||||||
|
mPathgrid->clearSelected();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Selection_All:
|
||||||
|
if (mPathgrid->isSelected())
|
||||||
|
mPathgrid->selectAll();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Selection_Invert:
|
||||||
|
if (mPathgrid->isSelected())
|
||||||
|
mPathgrid->invertSelected();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSVRender::Cell::selectAllWithSameParentId (int elementMask)
|
void CSVRender::Cell::selectAllWithSameParentId (int elementMask)
|
||||||
|
@ -406,6 +395,9 @@ std::vector<osg::ref_ptr<CSVRender::TagBase> > CSVRender::Cell::getSelection (un
|
||||||
iter!=mObjects.end(); ++iter)
|
iter!=mObjects.end(); ++iter)
|
||||||
if (iter->second->getSelected())
|
if (iter->second->getSelected())
|
||||||
result.push_back (iter->second->getTag());
|
result.push_back (iter->second->getTag());
|
||||||
|
if (elementMask & Mask_Pathgrid)
|
||||||
|
if (mPathgrid->isSelected())
|
||||||
|
result.push_back(mPathgrid->getTag());
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -440,4 +432,6 @@ void CSVRender::Cell::reset (unsigned int elementMask)
|
||||||
for (std::map<std::string, Object *>::const_iterator iter (mObjects.begin());
|
for (std::map<std::string, Object *>::const_iterator iter (mObjects.begin());
|
||||||
iter!=mObjects.end(); ++iter)
|
iter!=mObjects.end(); ++iter)
|
||||||
iter->second->reset();
|
iter->second->reset();
|
||||||
|
if (elementMask & Mask_Pathgrid)
|
||||||
|
mPathgrid->resetIndicators();
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,11 +31,11 @@ namespace CSMWorld
|
||||||
{
|
{
|
||||||
class Data;
|
class Data;
|
||||||
class CellCoordinates;
|
class CellCoordinates;
|
||||||
class Pathgrid;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace CSVRender
|
namespace CSVRender
|
||||||
{
|
{
|
||||||
|
class Pathgrid;
|
||||||
class TagBase;
|
class TagBase;
|
||||||
|
|
||||||
class Cell
|
class Cell
|
||||||
|
@ -43,14 +43,13 @@ namespace CSVRender
|
||||||
CSMWorld::Data& mData;
|
CSMWorld::Data& mData;
|
||||||
std::string mId;
|
std::string mId;
|
||||||
osg::ref_ptr<osg::Group> mCellNode;
|
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::map<std::string, Object *> mObjects;
|
||||||
std::auto_ptr<Terrain::TerrainGrid> mTerrain;
|
std::auto_ptr<Terrain::TerrainGrid> mTerrain;
|
||||||
CSMWorld::CellCoordinates mCoordinates;
|
CSMWorld::CellCoordinates mCoordinates;
|
||||||
std::auto_ptr<CellArrow> mCellArrows[4];
|
std::auto_ptr<CellArrow> mCellArrows[4];
|
||||||
std::auto_ptr<CellMarker> mCellMarker;
|
std::auto_ptr<CellMarker> mCellMarker;
|
||||||
std::auto_ptr<CellBorder> mCellBorder;
|
std::auto_ptr<CellBorder> mCellBorder;
|
||||||
|
std::auto_ptr<Pathgrid> mPathgrid;
|
||||||
bool mDeleted;
|
bool mDeleted;
|
||||||
int mSubMode;
|
int mSubMode;
|
||||||
unsigned int mSubModeElementMask;
|
unsigned int mSubModeElementMask;
|
||||||
|
@ -69,8 +68,6 @@ namespace CSVRender
|
||||||
/// \return Have any objects been added?
|
/// \return Have any objects been added?
|
||||||
bool addObjects (int start, int end);
|
bool addObjects (int start, int end);
|
||||||
|
|
||||||
void recreatePathgrid();
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
enum Selection
|
enum Selection
|
||||||
|
@ -89,6 +86,9 @@ namespace CSVRender
|
||||||
|
|
||||||
~Cell();
|
~Cell();
|
||||||
|
|
||||||
|
/// \note Returns the pathgrid representation which will exist as long as the cell exists
|
||||||
|
Pathgrid* getPathgrid() const;
|
||||||
|
|
||||||
/// \return Did this call result in a modification of the visual representation of
|
/// \return Did this call result in a modification of the visual representation of
|
||||||
/// this cell?
|
/// this cell?
|
||||||
bool referenceableDataChanged (const QModelIndex& topLeft,
|
bool referenceableDataChanged (const QModelIndex& topLeft,
|
||||||
|
@ -110,16 +110,10 @@ namespace CSVRender
|
||||||
/// this cell?
|
/// this cell?
|
||||||
bool referenceAdded (const QModelIndex& parent, int start, int end);
|
bool referenceAdded (const QModelIndex& parent, int start, int end);
|
||||||
|
|
||||||
void pathgridAdded(const CSMWorld::Pathgrid& pathgrid);
|
void pathgridModified();
|
||||||
|
|
||||||
void pathgridRemoved();
|
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);
|
void setSelection (int elementMask, Selection mode);
|
||||||
|
|
||||||
// Select everything that references the same ID as at least one of the elements
|
// Select everything that references the same ID as at least one of the elements
|
||||||
|
|
|
@ -29,37 +29,37 @@ void CSVRender::EditMode::setEditLock (bool locked)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSVRender::EditMode::primaryEditPressed (osg::ref_ptr<TagBase> tag) {}
|
void CSVRender::EditMode::primaryEditPressed (const WorldspaceHitResult& hit) {}
|
||||||
|
|
||||||
void CSVRender::EditMode::secondaryEditPressed (osg::ref_ptr<TagBase> tag) {}
|
void CSVRender::EditMode::secondaryEditPressed (const WorldspaceHitResult& hit) {}
|
||||||
|
|
||||||
void CSVRender::EditMode::primarySelectPressed (osg::ref_ptr<TagBase> tag) {}
|
void CSVRender::EditMode::primarySelectPressed (const WorldspaceHitResult& hit) {}
|
||||||
|
|
||||||
void CSVRender::EditMode::secondarySelectPressed (osg::ref_ptr<TagBase> tag) {}
|
void CSVRender::EditMode::secondarySelectPressed (const WorldspaceHitResult& hit) {}
|
||||||
|
|
||||||
bool CSVRender::EditMode::primaryEditStartDrag (osg::ref_ptr<TagBase> tag)
|
bool CSVRender::EditMode::primaryEditStartDrag (const QPoint& pos)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CSVRender::EditMode::secondaryEditStartDrag (osg::ref_ptr<TagBase> tag)
|
bool CSVRender::EditMode::secondaryEditStartDrag (const QPoint& pos)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CSVRender::EditMode::primarySelectStartDrag (osg::ref_ptr<TagBase> tag)
|
bool CSVRender::EditMode::primarySelectStartDrag (const QPoint& pos)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CSVRender::EditMode::secondarySelectStartDrag (osg::ref_ptr<TagBase> tag)
|
bool CSVRender::EditMode::secondarySelectStartDrag (const QPoint& pos)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSVRender::EditMode::drag (int diffX, int diffY, double speedFactor) {}
|
void CSVRender::EditMode::drag (const QPoint& pos, int diffX, int diffY, double speedFactor) {}
|
||||||
|
|
||||||
void CSVRender::EditMode::dragCompleted() {}
|
void CSVRender::EditMode::dragCompleted(const QPoint& pos) {}
|
||||||
|
|
||||||
void CSVRender::EditMode::dragAborted() {}
|
void CSVRender::EditMode::dragAborted() {}
|
||||||
|
|
||||||
|
@ -67,7 +67,7 @@ void CSVRender::EditMode::dragWheel (int diff, double speedFactor) {}
|
||||||
|
|
||||||
void CSVRender::EditMode::dragEnterEvent (QDragEnterEvent *event) {}
|
void CSVRender::EditMode::dragEnterEvent (QDragEnterEvent *event) {}
|
||||||
|
|
||||||
void CSVRender::EditMode::dropEvent (QDropEvent* event) {}
|
void CSVRender::EditMode::dropEvent (QDropEvent *event) {}
|
||||||
|
|
||||||
void CSVRender::EditMode::dragMoveEvent (QDragMoveEvent *event) {}
|
void CSVRender::EditMode::dragMoveEvent (QDragMoveEvent *event) {}
|
||||||
|
|
||||||
|
|
|
@ -8,10 +8,12 @@
|
||||||
class QDragEnterEvent;
|
class QDragEnterEvent;
|
||||||
class QDropEvent;
|
class QDropEvent;
|
||||||
class QDragMoveEvent;
|
class QDragMoveEvent;
|
||||||
|
class QPoint;
|
||||||
|
|
||||||
namespace CSVRender
|
namespace CSVRender
|
||||||
{
|
{
|
||||||
class WorldspaceWidget;
|
class WorldspaceWidget;
|
||||||
|
struct WorldspaceHitResult;
|
||||||
class TagBase;
|
class TagBase;
|
||||||
|
|
||||||
class EditMode : public CSVWidget::ModeButton
|
class EditMode : public CSVWidget::ModeButton
|
||||||
|
@ -38,42 +40,42 @@ namespace CSVRender
|
||||||
virtual void setEditLock (bool locked);
|
virtual void setEditLock (bool locked);
|
||||||
|
|
||||||
/// Default-implementation: Ignored.
|
/// Default-implementation: Ignored.
|
||||||
virtual void primaryEditPressed (osg::ref_ptr<TagBase> tag);
|
virtual void primaryEditPressed (const WorldspaceHitResult& hit);
|
||||||
|
|
||||||
/// Default-implementation: Ignored.
|
/// Default-implementation: Ignored.
|
||||||
virtual void secondaryEditPressed (osg::ref_ptr<TagBase> tag);
|
virtual void secondaryEditPressed (const WorldspaceHitResult& hit);
|
||||||
|
|
||||||
/// Default-implementation: Ignored.
|
/// Default-implementation: Ignored.
|
||||||
virtual void primarySelectPressed (osg::ref_ptr<TagBase> tag);
|
virtual void primarySelectPressed (const WorldspaceHitResult& hit);
|
||||||
|
|
||||||
/// Default-implementation: Ignored.
|
/// Default-implementation: Ignored.
|
||||||
virtual void secondarySelectPressed (osg::ref_ptr<TagBase> tag);
|
virtual void secondarySelectPressed (const WorldspaceHitResult& hit);
|
||||||
|
|
||||||
/// Default-implementation: ignore and return false
|
/// Default-implementation: ignore and return false
|
||||||
///
|
///
|
||||||
/// \return Drag accepted?
|
/// \return Drag accepted?
|
||||||
virtual bool primaryEditStartDrag (osg::ref_ptr<TagBase> tag);
|
virtual bool primaryEditStartDrag (const QPoint& pos);
|
||||||
|
|
||||||
/// Default-implementation: ignore and return false
|
/// Default-implementation: ignore and return false
|
||||||
///
|
///
|
||||||
/// \return Drag accepted?
|
/// \return Drag accepted?
|
||||||
virtual bool secondaryEditStartDrag (osg::ref_ptr<TagBase> tag);
|
virtual bool secondaryEditStartDrag (const QPoint& pos);
|
||||||
|
|
||||||
/// Default-implementation: ignore and return false
|
/// Default-implementation: ignore and return false
|
||||||
///
|
///
|
||||||
/// \return Drag accepted?
|
/// \return Drag accepted?
|
||||||
virtual bool primarySelectStartDrag (osg::ref_ptr<TagBase> tag);
|
virtual bool primarySelectStartDrag (const QPoint& pos);
|
||||||
|
|
||||||
/// Default-implementation: ignore and return false
|
/// Default-implementation: ignore and return false
|
||||||
///
|
///
|
||||||
/// \return Drag accepted?
|
/// \return Drag accepted?
|
||||||
virtual bool secondarySelectStartDrag (osg::ref_ptr<TagBase> tag);
|
virtual bool secondarySelectStartDrag (const QPoint& pos);
|
||||||
|
|
||||||
/// Default-implementation: ignored
|
/// Default-implementation: ignored
|
||||||
virtual void drag (int diffX, int diffY, double speedFactor);
|
virtual void drag (const QPoint& pos, int diffX, int diffY, double speedFactor);
|
||||||
|
|
||||||
/// Default-implementation: ignored
|
/// Default-implementation: ignored
|
||||||
virtual void dragCompleted();
|
virtual void dragCompleted(const QPoint& pos);
|
||||||
|
|
||||||
/// Default-implementation: ignored
|
/// Default-implementation: ignored
|
||||||
///
|
///
|
||||||
|
@ -88,7 +90,7 @@ namespace CSVRender
|
||||||
virtual void dragEnterEvent (QDragEnterEvent *event);
|
virtual void dragEnterEvent (QDragEnterEvent *event);
|
||||||
|
|
||||||
/// Default-implementation: ignored
|
/// Default-implementation: ignored
|
||||||
virtual void dropEvent (QDropEvent* event);
|
virtual void dropEvent (QDropEvent *event);
|
||||||
|
|
||||||
/// Default-implementation: ignored
|
/// Default-implementation: ignored
|
||||||
virtual void dragMoveEvent (QDragMoveEvent *event);
|
virtual void dragMoveEvent (QDragMoveEvent *event);
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#include "instancemode.hpp"
|
#include "instancemode.hpp"
|
||||||
|
|
||||||
#include <QDragEnterEvent>
|
#include <QDragEnterEvent>
|
||||||
|
#include <QPoint>
|
||||||
|
|
||||||
#include "../../model/prefs/state.hpp"
|
#include "../../model/prefs/state.hpp"
|
||||||
|
|
||||||
|
@ -103,25 +104,25 @@ void CSVRender::InstanceMode::setEditLock (bool locked)
|
||||||
getWorldspaceWidget().abortDrag();
|
getWorldspaceWidget().abortDrag();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSVRender::InstanceMode::primaryEditPressed (osg::ref_ptr<TagBase> tag)
|
void CSVRender::InstanceMode::primaryEditPressed (const WorldspaceHitResult& hit)
|
||||||
{
|
{
|
||||||
if (CSMPrefs::get()["3D Scene Input"]["context-select"].isTrue())
|
if (CSMPrefs::get()["3D Scene Input"]["context-select"].isTrue())
|
||||||
primarySelectPressed (tag);
|
primarySelectPressed (hit);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSVRender::InstanceMode::secondaryEditPressed (osg::ref_ptr<TagBase> tag)
|
void CSVRender::InstanceMode::secondaryEditPressed (const WorldspaceHitResult& hit)
|
||||||
{
|
{
|
||||||
if (CSMPrefs::get()["3D Scene Input"]["context-select"].isTrue())
|
if (CSMPrefs::get()["3D Scene Input"]["context-select"].isTrue())
|
||||||
secondarySelectPressed (tag);
|
secondarySelectPressed (hit);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSVRender::InstanceMode::primarySelectPressed (osg::ref_ptr<TagBase> tag)
|
void CSVRender::InstanceMode::primarySelectPressed (const WorldspaceHitResult& hit)
|
||||||
{
|
{
|
||||||
getWorldspaceWidget().clearSelection (Mask_Reference);
|
getWorldspaceWidget().clearSelection (Mask_Reference);
|
||||||
|
|
||||||
if (tag)
|
if (hit.tag)
|
||||||
{
|
{
|
||||||
if (CSVRender::ObjectTag *objectTag = dynamic_cast<CSVRender::ObjectTag *> (tag.get()))
|
if (CSVRender::ObjectTag *objectTag = dynamic_cast<CSVRender::ObjectTag *> (hit.tag.get()))
|
||||||
{
|
{
|
||||||
// hit an Object, select it
|
// hit an Object, select it
|
||||||
CSVRender::Object* object = objectTag->mObject;
|
CSVRender::Object* object = objectTag->mObject;
|
||||||
|
@ -131,11 +132,11 @@ void CSVRender::InstanceMode::primarySelectPressed (osg::ref_ptr<TagBase> tag)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSVRender::InstanceMode::secondarySelectPressed (osg::ref_ptr<TagBase> tag)
|
void CSVRender::InstanceMode::secondarySelectPressed (const WorldspaceHitResult& hit)
|
||||||
{
|
{
|
||||||
if (tag)
|
if (hit.tag)
|
||||||
{
|
{
|
||||||
if (CSVRender::ObjectTag *objectTag = dynamic_cast<CSVRender::ObjectTag *> (tag.get()))
|
if (CSVRender::ObjectTag *objectTag = dynamic_cast<CSVRender::ObjectTag *> (hit.tag.get()))
|
||||||
{
|
{
|
||||||
// hit an Object, toggle its selection state
|
// hit an Object, toggle its selection state
|
||||||
CSVRender::Object* object = objectTag->mObject;
|
CSVRender::Object* object = objectTag->mObject;
|
||||||
|
@ -145,15 +146,16 @@ void CSVRender::InstanceMode::secondarySelectPressed (osg::ref_ptr<TagBase> tag)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CSVRender::InstanceMode::primaryEditStartDrag (osg::ref_ptr<TagBase> tag)
|
bool CSVRender::InstanceMode::primaryEditStartDrag (const QPoint& pos)
|
||||||
{
|
{
|
||||||
if (mDragMode!=DragMode_None || mLocked)
|
if (mDragMode!=DragMode_None || mLocked)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (tag && CSMPrefs::get()["3D Scene Input"]["context-select"].isTrue())
|
WorldspaceHitResult hit = getWorldspaceWidget().mousePick (pos, getWorldspaceWidget().getInteractionMask());
|
||||||
|
if (hit.tag && CSMPrefs::get()["3D Scene Input"]["context-select"].isTrue())
|
||||||
{
|
{
|
||||||
getWorldspaceWidget().clearSelection (Mask_Reference);
|
getWorldspaceWidget().clearSelection (Mask_Reference);
|
||||||
if (CSVRender::ObjectTag *objectTag = dynamic_cast<CSVRender::ObjectTag *> (tag.get()))
|
if (CSVRender::ObjectTag *objectTag = dynamic_cast<CSVRender::ObjectTag *> (hit.tag.get()))
|
||||||
{
|
{
|
||||||
CSVRender::Object* object = objectTag->mObject;
|
CSVRender::Object* object = objectTag->mObject;
|
||||||
object->setSelected (true);
|
object->setSelected (true);
|
||||||
|
@ -177,7 +179,7 @@ bool CSVRender::InstanceMode::primaryEditStartDrag (osg::ref_ptr<TagBase> tag)
|
||||||
|
|
||||||
// \todo check for sub-mode
|
// \todo check for sub-mode
|
||||||
|
|
||||||
if (CSVRender::ObjectMarkerTag *objectTag = dynamic_cast<CSVRender::ObjectMarkerTag *> (tag.get()))
|
if (CSVRender::ObjectMarkerTag *objectTag = dynamic_cast<CSVRender::ObjectMarkerTag *> (hit.tag.get()))
|
||||||
{
|
{
|
||||||
mDragAxis = objectTag->mAxis;
|
mDragAxis = objectTag->mAxis;
|
||||||
}
|
}
|
||||||
|
@ -189,7 +191,7 @@ bool CSVRender::InstanceMode::primaryEditStartDrag (osg::ref_ptr<TagBase> tag)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CSVRender::InstanceMode::secondaryEditStartDrag (osg::ref_ptr<TagBase> tag)
|
bool CSVRender::InstanceMode::secondaryEditStartDrag (const QPoint& pos)
|
||||||
{
|
{
|
||||||
if (mLocked)
|
if (mLocked)
|
||||||
return false;
|
return false;
|
||||||
|
@ -197,7 +199,7 @@ bool CSVRender::InstanceMode::secondaryEditStartDrag (osg::ref_ptr<TagBase> tag)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSVRender::InstanceMode::drag (int diffX, int diffY, double speedFactor)
|
void CSVRender::InstanceMode::drag (const QPoint& pos, int diffX, int diffY, double speedFactor)
|
||||||
{
|
{
|
||||||
osg::Vec3f eye;
|
osg::Vec3f eye;
|
||||||
osg::Vec3f centre;
|
osg::Vec3f centre;
|
||||||
|
@ -244,7 +246,7 @@ void CSVRender::InstanceMode::drag (int diffX, int diffY, double speedFactor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSVRender::InstanceMode::dragCompleted()
|
void CSVRender::InstanceMode::dragCompleted(const QPoint& pos)
|
||||||
{
|
{
|
||||||
std::vector<osg::ref_ptr<TagBase> > selection =
|
std::vector<osg::ref_ptr<TagBase> > selection =
|
||||||
getWorldspaceWidget().getEdited (Mask_Reference);
|
getWorldspaceWidget().getEdited (Mask_Reference);
|
||||||
|
@ -333,9 +335,9 @@ void CSVRender::InstanceMode::dropEvent (QDropEvent* event)
|
||||||
if (!mime->fromDocument (document))
|
if (!mime->fromDocument (document))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
osg::Vec3f insertPoint = getWorldspaceWidget().getIntersectionPoint (event->pos());
|
WorldspaceHitResult hit = getWorldspaceWidget().mousePick (event->pos(), getWorldspaceWidget().getInteractionMask());
|
||||||
|
|
||||||
std::string cellId = getWorldspaceWidget().getCellId (insertPoint);
|
std::string cellId = getWorldspaceWidget().getCellId (hit.worldPos);
|
||||||
|
|
||||||
CSMWorld::IdTree& cellTable = dynamic_cast<CSMWorld::IdTree&> (
|
CSMWorld::IdTree& cellTable = dynamic_cast<CSMWorld::IdTree&> (
|
||||||
*document.getData().getTableModel (CSMWorld::UniversalId::Type_Cells));
|
*document.getData().getTableModel (CSMWorld::UniversalId::Type_Cells));
|
||||||
|
@ -412,11 +414,11 @@ void CSVRender::InstanceMode::dropEvent (QDropEvent* event)
|
||||||
createCommand->addValue (referencesTable.findColumnIndex (
|
createCommand->addValue (referencesTable.findColumnIndex (
|
||||||
CSMWorld::Columns::ColumnId_Cell), QString::fromUtf8 (cellId.c_str()));
|
CSMWorld::Columns::ColumnId_Cell), QString::fromUtf8 (cellId.c_str()));
|
||||||
createCommand->addValue (referencesTable.findColumnIndex (
|
createCommand->addValue (referencesTable.findColumnIndex (
|
||||||
CSMWorld::Columns::ColumnId_PositionXPos), insertPoint.x());
|
CSMWorld::Columns::ColumnId_PositionXPos), hit.worldPos.x());
|
||||||
createCommand->addValue (referencesTable.findColumnIndex (
|
createCommand->addValue (referencesTable.findColumnIndex (
|
||||||
CSMWorld::Columns::ColumnId_PositionYPos), insertPoint.y());
|
CSMWorld::Columns::ColumnId_PositionYPos), hit.worldPos.y());
|
||||||
createCommand->addValue (referencesTable.findColumnIndex (
|
createCommand->addValue (referencesTable.findColumnIndex (
|
||||||
CSMWorld::Columns::ColumnId_PositionZPos), insertPoint.z());
|
CSMWorld::Columns::ColumnId_PositionZPos), hit.worldPos.z());
|
||||||
createCommand->addValue (referencesTable.findColumnIndex (
|
createCommand->addValue (referencesTable.findColumnIndex (
|
||||||
CSMWorld::Columns::ColumnId_ReferenceableId),
|
CSMWorld::Columns::ColumnId_ReferenceableId),
|
||||||
QString::fromUtf8 (iter->getId().c_str()));
|
QString::fromUtf8 (iter->getId().c_str()));
|
||||||
|
|
|
@ -41,21 +41,21 @@ namespace CSVRender
|
||||||
|
|
||||||
virtual void setEditLock (bool locked);
|
virtual void setEditLock (bool locked);
|
||||||
|
|
||||||
virtual void primaryEditPressed (osg::ref_ptr<TagBase> tag);
|
virtual void primaryEditPressed (const WorldspaceHitResult& hit);
|
||||||
|
|
||||||
virtual void secondaryEditPressed (osg::ref_ptr<TagBase> tag);
|
virtual void secondaryEditPressed (const WorldspaceHitResult& hit);
|
||||||
|
|
||||||
virtual void primarySelectPressed (osg::ref_ptr<TagBase> tag);
|
virtual void primarySelectPressed (const WorldspaceHitResult& hit);
|
||||||
|
|
||||||
virtual void secondarySelectPressed (osg::ref_ptr<TagBase> tag);
|
virtual void secondarySelectPressed (const WorldspaceHitResult& hit);
|
||||||
|
|
||||||
virtual bool primaryEditStartDrag (osg::ref_ptr<TagBase> tag);
|
virtual bool primaryEditStartDrag (const QPoint& pos);
|
||||||
|
|
||||||
virtual bool secondaryEditStartDrag (osg::ref_ptr<TagBase> tag);
|
virtual bool secondaryEditStartDrag (const QPoint& pos);
|
||||||
|
|
||||||
virtual void drag (int diffX, int diffY, double speedFactor);
|
virtual void drag (const QPoint& pos, int diffX, int diffY, double speedFactor);
|
||||||
|
|
||||||
virtual void dragCompleted();
|
virtual void dragCompleted(const QPoint& pos);
|
||||||
|
|
||||||
/// \note dragAborted will not be called, if the drag is aborted via changing
|
/// \note dragAborted will not be called, if the drag is aborted via changing
|
||||||
/// editing mode
|
/// editing mode
|
||||||
|
@ -65,7 +65,7 @@ namespace CSVRender
|
||||||
|
|
||||||
virtual void dragEnterEvent (QDragEnterEvent *event);
|
virtual void dragEnterEvent (QDragEnterEvent *event);
|
||||||
|
|
||||||
virtual void dropEvent (QDropEvent* event);
|
virtual void dropEvent (QDropEvent *event);
|
||||||
|
|
||||||
virtual int getSubMode() const;
|
virtual int getSubMode() const;
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
#include "instanceselectionmode.hpp"
|
#include "instanceselectionmode.hpp"
|
||||||
|
|
||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
|
@ -10,84 +9,49 @@
|
||||||
#include "worldspacewidget.hpp"
|
#include "worldspacewidget.hpp"
|
||||||
#include "object.hpp"
|
#include "object.hpp"
|
||||||
|
|
||||||
bool CSVRender::InstanceSelectionMode::createContextMenu (QMenu *menu)
|
namespace CSVRender
|
||||||
{
|
{
|
||||||
if (menu)
|
InstanceSelectionMode::InstanceSelectionMode(CSVWidget::SceneToolbar* parent, WorldspaceWidget& worldspaceWidget)
|
||||||
|
: SelectionMode(parent, worldspaceWidget, Mask_Reference)
|
||||||
{
|
{
|
||||||
menu->addAction (mSelectAll);
|
mSelectSame = new QAction("Extend selection to instances with same object ID", this);
|
||||||
menu->addAction (mDeselectAll);
|
mDeleteSelection = new QAction("Delete selected instances", this);
|
||||||
menu->addAction (mSelectSame);
|
|
||||||
menu->addAction (mDeleteSelection);
|
connect(mSelectSame, SIGNAL(triggered()), this, SLOT(selectSame()));
|
||||||
|
connect(mDeleteSelection, SIGNAL(triggered()), this, SLOT(deleteSelection()));
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
bool InstanceSelectionMode::createContextMenu(QMenu* menu)
|
||||||
}
|
|
||||||
|
|
||||||
CSVRender::InstanceSelectionMode::InstanceSelectionMode (CSVWidget::SceneToolbar *parent,
|
|
||||||
WorldspaceWidget& worldspaceWidget)
|
|
||||||
: CSVWidget::SceneToolMode (parent, "Selection Mode"), mWorldspaceWidget (worldspaceWidget)
|
|
||||||
{
|
|
||||||
addButton (":placeholder", "cube-centre",
|
|
||||||
"Centred cube"
|
|
||||||
"<ul><li>Drag with primary (make instances the selection) or secondary (invert selection state) select button from the centre of the selection cube outwards</li>"
|
|
||||||
"<li>The selection cube is aligned to the word space axis</li>"
|
|
||||||
"<li>If context selection mode is enabled, a drag with primary/secondary edit not starting on an instance will have the same effect</li>"
|
|
||||||
"</ul>"
|
|
||||||
"<font color=Red>Not implemented yet</font color>");
|
|
||||||
addButton (":placeholder", "cube-corner",
|
|
||||||
"Cube corner to corner"
|
|
||||||
"<ul><li>Drag with primary (make instances the selection) or secondary (invert selection state) select button from one corner of the selection cube to the opposite corner</li>"
|
|
||||||
"<li>The selection cube is aligned to the word space axis</li>"
|
|
||||||
"<li>If context selection mode is enabled, a drag with primary/secondary edit not starting on an instance will have the same effect</li>"
|
|
||||||
"</ul>"
|
|
||||||
"<font color=Red>Not implemented yet</font color>");
|
|
||||||
addButton (":placeholder", "sphere",
|
|
||||||
"Centred sphere"
|
|
||||||
"<ul><li>Drag with primary (make instances the selection) or secondary (invert selection state) select button from the centre of the selection sphere outwards</li>"
|
|
||||||
"<li>If context selection mode is enabled, a drag with primary/secondary edit not starting on an instance will have the same effect</li>"
|
|
||||||
"</ul>"
|
|
||||||
"<font color=Red>Not implemented yet</font color>");
|
|
||||||
|
|
||||||
mSelectAll = new QAction ("Select all instances", this);
|
|
||||||
mDeselectAll = new QAction ("Clear selection", this);
|
|
||||||
mDeleteSelection = new QAction ("Delete selected instances", this);
|
|
||||||
mSelectSame = new QAction ("Extend selection to instances with same object ID", this);
|
|
||||||
connect (mSelectAll, SIGNAL (triggered ()), this, SLOT (selectAll()));
|
|
||||||
connect (mDeselectAll, SIGNAL (triggered ()), this, SLOT (clearSelection()));
|
|
||||||
connect (mDeleteSelection, SIGNAL (triggered ()), this, SLOT (deleteSelection()));
|
|
||||||
connect (mSelectSame, SIGNAL (triggered ()), this, SLOT (selectSame()));
|
|
||||||
}
|
|
||||||
|
|
||||||
void CSVRender::InstanceSelectionMode::selectAll()
|
|
||||||
{
|
|
||||||
mWorldspaceWidget.selectAll (Mask_Reference);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CSVRender::InstanceSelectionMode::clearSelection()
|
|
||||||
{
|
|
||||||
mWorldspaceWidget.clearSelection (Mask_Reference);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CSVRender::InstanceSelectionMode::deleteSelection()
|
|
||||||
{
|
|
||||||
std::vector<osg::ref_ptr<TagBase> > selection =
|
|
||||||
mWorldspaceWidget.getSelection (Mask_Reference);
|
|
||||||
|
|
||||||
CSMWorld::IdTable& referencesTable =
|
|
||||||
dynamic_cast<CSMWorld::IdTable&> (*mWorldspaceWidget.getDocument().getData().
|
|
||||||
getTableModel (CSMWorld::UniversalId::Type_References));
|
|
||||||
|
|
||||||
for (std::vector<osg::ref_ptr<TagBase> >::iterator iter (selection.begin());
|
|
||||||
iter!=selection.end(); ++iter)
|
|
||||||
{
|
{
|
||||||
CSMWorld::DeleteCommand *command = new CSMWorld::DeleteCommand (referencesTable,
|
if (menu)
|
||||||
static_cast<ObjectTag *> (iter->get())->mObject->getReferenceId());
|
{
|
||||||
|
SelectionMode::createContextMenu(menu);
|
||||||
|
|
||||||
mWorldspaceWidget.getDocument().getUndoStack().push (command);
|
menu->addAction(mSelectSame);
|
||||||
|
menu->addAction(mDeleteSelection);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void InstanceSelectionMode::selectSame()
|
||||||
|
{
|
||||||
|
getWorldspaceWidget().selectAllWithSameParentId(Mask_Reference);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InstanceSelectionMode::deleteSelection()
|
||||||
|
{
|
||||||
|
std::vector<osg::ref_ptr<TagBase> > selection = getWorldspaceWidget().getSelection(Mask_Reference);
|
||||||
|
|
||||||
|
CSMWorld::IdTable& referencesTable = dynamic_cast<CSMWorld::IdTable&>(
|
||||||
|
*getWorldspaceWidget().getDocument().getData().getTableModel(CSMWorld::UniversalId::Type_References));
|
||||||
|
|
||||||
|
for (std::vector<osg::ref_ptr<TagBase> >::iterator iter = selection.begin(); iter != selection.end(); ++iter)
|
||||||
|
{
|
||||||
|
CSMWorld::DeleteCommand* command = new CSMWorld::DeleteCommand(referencesTable,
|
||||||
|
static_cast<ObjectTag*>(iter->get())->mObject->getReferenceId());
|
||||||
|
|
||||||
|
getWorldspaceWidget().getDocument().getUndoStack().push(command);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSVRender::InstanceSelectionMode::selectSame()
|
|
||||||
{
|
|
||||||
mWorldspaceWidget.selectAllWithSameParentId (Mask_Reference);
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,23 +1,19 @@
|
||||||
#ifndef CSV_RENDER_INSTANCE_SELECTION_MODE_H
|
#ifndef CSV_RENDER_INSTANCE_SELECTION_MODE_H
|
||||||
#define CSV_RENDER_INSTANCE_SELECTION_MODE_H
|
#define CSV_RENDER_INSTANCE_SELECTION_MODE_H
|
||||||
|
|
||||||
#include "../widget/scenetoolmode.hpp"
|
#include "selectionmode.hpp"
|
||||||
|
|
||||||
class QAction;
|
|
||||||
|
|
||||||
namespace CSVRender
|
namespace CSVRender
|
||||||
{
|
{
|
||||||
class WorldspaceWidget;
|
class InstanceSelectionMode : public SelectionMode
|
||||||
|
|
||||||
class InstanceSelectionMode : public CSVWidget::SceneToolMode
|
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
WorldspaceWidget& mWorldspaceWidget;
|
public:
|
||||||
QAction *mSelectAll;
|
|
||||||
QAction *mDeselectAll;
|
InstanceSelectionMode(CSVWidget::SceneToolbar* parent, WorldspaceWidget& worldspaceWidget);
|
||||||
QAction *mDeleteSelection;
|
|
||||||
QAction *mSelectSame;
|
protected:
|
||||||
|
|
||||||
/// Add context menu items to \a menu.
|
/// Add context menu items to \a menu.
|
||||||
///
|
///
|
||||||
|
@ -25,20 +21,16 @@ namespace CSVRender
|
||||||
///
|
///
|
||||||
/// \return Have there been any menu items to be added (if menu is 0 and there
|
/// \return Have there been any menu items to be added (if menu is 0 and there
|
||||||
/// items to be added, the function must return true anyway.
|
/// items to be added, the function must return true anyway.
|
||||||
virtual bool createContextMenu (QMenu *menu);
|
bool createContextMenu(QMenu* menu);
|
||||||
|
|
||||||
public:
|
private:
|
||||||
|
|
||||||
InstanceSelectionMode (CSVWidget::SceneToolbar *parent, WorldspaceWidget& worldspaceWidget);
|
QAction* mDeleteSelection;
|
||||||
|
QAction* mSelectSame;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
|
||||||
void selectAll();
|
|
||||||
|
|
||||||
void clearSelection();
|
|
||||||
|
|
||||||
void deleteSelection();
|
void deleteSelection();
|
||||||
|
|
||||||
void selectSame();
|
void selectSame();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -142,14 +142,15 @@ void CSVRender::PagedWorldspaceWidget::addEditModeSelectorButtons (
|
||||||
"terrain-move");
|
"terrain-move");
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSVRender::PagedWorldspaceWidget::handleMouseClick (osg::ref_ptr<TagBase> tag, const std::string& button, bool shift)
|
void CSVRender::PagedWorldspaceWidget::handleMouseClick (const WorldspaceHitResult& hit, const std::string& button,
|
||||||
|
bool shift)
|
||||||
{
|
{
|
||||||
if (tag && tag->getMask()==Mask_CellArrow)
|
if (hit.tag && hit.tag->getMask()==Mask_CellArrow)
|
||||||
{
|
{
|
||||||
if (button=="p-edit" || button=="s-edit")
|
if (button=="p-edit" || button=="s-edit")
|
||||||
{
|
{
|
||||||
if (CellArrowTag *cellArrowTag =
|
if (CellArrowTag *cellArrowTag =
|
||||||
dynamic_cast<CSVRender::CellArrowTag *> (tag.get()))
|
dynamic_cast<CSVRender::CellArrowTag *> (hit.tag.get()))
|
||||||
{
|
{
|
||||||
CellArrow *arrow = cellArrowTag->getCellArrow();
|
CellArrow *arrow = cellArrowTag->getCellArrow();
|
||||||
|
|
||||||
|
@ -209,7 +210,7 @@ void CSVRender::PagedWorldspaceWidget::handleMouseClick (osg::ref_ptr<TagBase> t
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
WorldspaceWidget::handleMouseClick (tag, button, shift);
|
WorldspaceWidget::handleMouseClick (hit, button, shift);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSVRender::PagedWorldspaceWidget::referenceableDataChanged (const QModelIndex& topLeft,
|
void CSVRender::PagedWorldspaceWidget::referenceableDataChanged (const QModelIndex& topLeft,
|
||||||
|
@ -279,38 +280,29 @@ void CSVRender::PagedWorldspaceWidget::pathgridDataChanged (const QModelIndex& t
|
||||||
{
|
{
|
||||||
const CSMWorld::SubCellCollection<CSMWorld::Pathgrid>& pathgrids = mDocument.getData().getPathgrids();
|
const CSMWorld::SubCellCollection<CSMWorld::Pathgrid>& pathgrids = mDocument.getData().getPathgrids();
|
||||||
|
|
||||||
|
int rowStart = -1;
|
||||||
|
int rowEnd = -1;
|
||||||
|
|
||||||
if (topLeft.parent().isValid())
|
if (topLeft.parent().isValid())
|
||||||
{
|
{
|
||||||
int row = topLeft.parent().row();
|
rowStart = topLeft.parent().row();
|
||||||
|
rowEnd = bottomRight.parent().row();
|
||||||
const CSMWorld::Pathgrid& pathgrid = pathgrids.getRecord(row).get();
|
|
||||||
CSMWorld::CellCoordinates coords = CSMWorld::CellCoordinates(pathgrid.mData.mX, pathgrid.mData.mY);
|
|
||||||
|
|
||||||
std::map<CSMWorld::CellCoordinates, Cell*>::iterator searchResult = mCells.find(coords);
|
|
||||||
if (searchResult != mCells.end())
|
|
||||||
{
|
|
||||||
searchResult->second->pathgridDataChanged(topLeft, bottomRight);
|
|
||||||
flagAsModified();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
|
|
||||||
void CSVRender::PagedWorldspaceWidget::pathgridRemoved (const QModelIndex& parent, int start, int end)
|
|
||||||
{
|
|
||||||
const CSMWorld::SubCellCollection<CSMWorld::Pathgrid>& pathgrids = mDocument.getData().getPathgrids();
|
|
||||||
|
|
||||||
if (parent.isValid())
|
|
||||||
{
|
{
|
||||||
// Pathgrid data was modified
|
rowStart = topLeft.row();
|
||||||
int row = parent.row();
|
rowEnd = bottomRight.row();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int row = rowStart; row <= rowEnd; ++row)
|
||||||
|
{
|
||||||
const CSMWorld::Pathgrid& pathgrid = pathgrids.getRecord(row).get();
|
const CSMWorld::Pathgrid& pathgrid = pathgrids.getRecord(row).get();
|
||||||
CSMWorld::CellCoordinates coords = CSMWorld::CellCoordinates(pathgrid.mData.mX, pathgrid.mData.mY);
|
CSMWorld::CellCoordinates coords = CSMWorld::CellCoordinates(pathgrid.mData.mX, pathgrid.mData.mY);
|
||||||
|
|
||||||
std::map<CSMWorld::CellCoordinates, Cell*>::iterator searchResult = mCells.find(coords);
|
std::map<CSMWorld::CellCoordinates, Cell*>::iterator searchResult = mCells.find(coords);
|
||||||
if (searchResult != mCells.end())
|
if (searchResult != mCells.end())
|
||||||
{
|
{
|
||||||
searchResult->second->pathgridRowRemoved(parent, start, end);
|
searchResult->second->pathgridModified();
|
||||||
flagAsModified();
|
flagAsModified();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -340,11 +332,10 @@ void CSVRender::PagedWorldspaceWidget::pathgridAboutToBeRemoved (const QModelInd
|
||||||
|
|
||||||
void CSVRender::PagedWorldspaceWidget::pathgridAdded(const QModelIndex& parent, int start, int end)
|
void CSVRender::PagedWorldspaceWidget::pathgridAdded(const QModelIndex& parent, int start, int end)
|
||||||
{
|
{
|
||||||
const CSMWorld::SubCellCollection<CSMWorld::Pathgrid>& pathgrids = mDocument.getData().getPathgrids();
|
const CSMWorld::SubCellCollection<CSMWorld::Pathgrid>& pathgrids = mDocument.getData().getPathgrids();
|
||||||
|
|
||||||
if (!parent.isValid())
|
if (!parent.isValid())
|
||||||
{
|
{
|
||||||
// Pathgrid added theoretically, unable to test until it is possible to add pathgrids
|
|
||||||
for (int row = start; row <= end; ++row)
|
for (int row = start; row <= end; ++row)
|
||||||
{
|
{
|
||||||
const CSMWorld::Pathgrid& pathgrid = pathgrids.getRecord(row).get();
|
const CSMWorld::Pathgrid& pathgrid = pathgrids.getRecord(row).get();
|
||||||
|
@ -353,26 +344,11 @@ void CSVRender::PagedWorldspaceWidget::pathgridAdded(const QModelIndex& parent,
|
||||||
std::map<CSMWorld::CellCoordinates, Cell*>::iterator searchResult = mCells.find(coords);
|
std::map<CSMWorld::CellCoordinates, Cell*>::iterator searchResult = mCells.find(coords);
|
||||||
if (searchResult != mCells.end())
|
if (searchResult != mCells.end())
|
||||||
{
|
{
|
||||||
searchResult->second->pathgridAdded(pathgrid);
|
searchResult->second->pathgridModified();
|
||||||
flagAsModified();
|
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<CSMWorld::CellCoordinates, Cell*>::iterator searchResult = mCells.find(coords);
|
|
||||||
if (searchResult != mCells.end())
|
|
||||||
{
|
|
||||||
searchResult->second->pathgridRowAdded(parent, start, end);
|
|
||||||
flagAsModified();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -605,6 +581,15 @@ void CSVRender::PagedWorldspaceWidget::clearSelection (int elementMask)
|
||||||
flagAsModified();
|
flagAsModified();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSVRender::PagedWorldspaceWidget::invertSelection (int elementMask)
|
||||||
|
{
|
||||||
|
for (std::map<CSMWorld::CellCoordinates, Cell *>::iterator iter = mCells.begin();
|
||||||
|
iter!=mCells.end(); ++iter)
|
||||||
|
iter->second->setSelection (elementMask, Cell::Selection_Invert);
|
||||||
|
|
||||||
|
flagAsModified();
|
||||||
|
}
|
||||||
|
|
||||||
void CSVRender::PagedWorldspaceWidget::selectAll (int elementMask)
|
void CSVRender::PagedWorldspaceWidget::selectAll (int elementMask)
|
||||||
{
|
{
|
||||||
for (std::map<CSMWorld::CellCoordinates, Cell *>::iterator iter = mCells.begin();
|
for (std::map<CSMWorld::CellCoordinates, Cell *>::iterator iter = mCells.begin();
|
||||||
|
@ -634,6 +619,21 @@ std::string CSVRender::PagedWorldspaceWidget::getCellId (const osg::Vec3f& point
|
||||||
return cellCoordinates.getId (mWorldspace);
|
return cellCoordinates.getId (mWorldspace);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CSVRender::Cell* CSVRender::PagedWorldspaceWidget::getCell(const osg::Vec3d& point) const
|
||||||
|
{
|
||||||
|
const int cellSize = 8192;
|
||||||
|
|
||||||
|
CSMWorld::CellCoordinates coords(
|
||||||
|
static_cast<int> (std::floor (point.x()/cellSize)),
|
||||||
|
static_cast<int> (std::floor (point.y()/cellSize)));
|
||||||
|
|
||||||
|
std::map<CSMWorld::CellCoordinates, Cell*>::const_iterator searchResult = mCells.find(coords);
|
||||||
|
if (searchResult != mCells.end())
|
||||||
|
return searchResult->second;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<osg::ref_ptr<CSVRender::TagBase> > CSVRender::PagedWorldspaceWidget::getSelection (
|
std::vector<osg::ref_ptr<CSVRender::TagBase> > CSVRender::PagedWorldspaceWidget::getSelection (
|
||||||
unsigned int elementMask) const
|
unsigned int elementMask) const
|
||||||
{
|
{
|
||||||
|
|
|
@ -54,8 +54,6 @@ namespace CSVRender
|
||||||
|
|
||||||
virtual void pathgridDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight);
|
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 pathgridAboutToBeRemoved (const QModelIndex& parent, int start, int end);
|
||||||
|
|
||||||
virtual void pathgridAdded (const QModelIndex& parent, int start, int end);
|
virtual void pathgridAdded (const QModelIndex& parent, int start, int end);
|
||||||
|
@ -107,6 +105,9 @@ namespace CSVRender
|
||||||
/// \param elementMask Elements to be affected by the clear operation
|
/// \param elementMask Elements to be affected by the clear operation
|
||||||
virtual void clearSelection (int elementMask);
|
virtual void clearSelection (int elementMask);
|
||||||
|
|
||||||
|
/// \param elementMask Elements to be affected by the select operation
|
||||||
|
virtual void invertSelection (int elementMask);
|
||||||
|
|
||||||
/// \param elementMask Elements to be affected by the select operation
|
/// \param elementMask Elements to be affected by the select operation
|
||||||
virtual void selectAll (int elementMask);
|
virtual void selectAll (int elementMask);
|
||||||
|
|
||||||
|
@ -118,6 +119,8 @@ namespace CSVRender
|
||||||
|
|
||||||
virtual std::string getCellId (const osg::Vec3f& point) const;
|
virtual std::string getCellId (const osg::Vec3f& point) const;
|
||||||
|
|
||||||
|
virtual Cell* getCell(const osg::Vec3d& point) const;
|
||||||
|
|
||||||
virtual std::vector<osg::ref_ptr<TagBase> > getSelection (unsigned int elementMask)
|
virtual std::vector<osg::ref_ptr<TagBase> > getSelection (unsigned int elementMask)
|
||||||
const;
|
const;
|
||||||
|
|
||||||
|
@ -135,7 +138,7 @@ namespace CSVRender
|
||||||
|
|
||||||
virtual void addEditModeSelectorButtons (CSVWidget::SceneToolMode *tool);
|
virtual void addEditModeSelectorButtons (CSVWidget::SceneToolMode *tool);
|
||||||
|
|
||||||
virtual void handleMouseClick (osg::ref_ptr<TagBase> tag, const std::string& button, bool shift);
|
virtual void handleMouseClick (const WorldspaceHitResult& hit, const std::string& button, bool shift);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|
||||||
|
|
680
apps/opencs/view/render/pathgrid.cpp
Normal file
680
apps/opencs/view/render/pathgrid.cpp
Normal file
|
@ -0,0 +1,680 @@
|
||||||
|
#include "pathgrid.hpp"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include <osg/Array>
|
||||||
|
#include <osg/Geode>
|
||||||
|
#include <osg/Geometry>
|
||||||
|
#include <osg/Group>
|
||||||
|
#include <osg/PositionAttitudeTransform>
|
||||||
|
#include <osg/Vec3>
|
||||||
|
|
||||||
|
#include <components/sceneutil/pathgridutil.hpp>
|
||||||
|
|
||||||
|
#include "../../model/world/cell.hpp"
|
||||||
|
#include "../../model/world/commands.hpp"
|
||||||
|
#include "../../model/world/commandmacro.hpp"
|
||||||
|
#include "../../model/world/data.hpp"
|
||||||
|
#include "../../model/world/idtree.hpp"
|
||||||
|
|
||||||
|
namespace CSVRender
|
||||||
|
{
|
||||||
|
class PathgridNodeCallback : public osg::NodeCallback
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
|
||||||
|
{
|
||||||
|
PathgridTag* tag = static_cast<PathgridTag*>(node->getUserData());
|
||||||
|
tag->getPathgrid()->update();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
Pathgrid::Pathgrid(CSMWorld::Data& data, osg::Group* parent, const std::string& pathgridId,
|
||||||
|
const CSMWorld::CellCoordinates& coordinates)
|
||||||
|
: mData(data)
|
||||||
|
, mPathgridCollection(mData.getPathgrids())
|
||||||
|
, mId(pathgridId)
|
||||||
|
, mCoords(coordinates)
|
||||||
|
, mInterior(false)
|
||||||
|
, mDragOrigin(0)
|
||||||
|
, mChangeGeometry(true)
|
||||||
|
, mRemoveGeometry(false)
|
||||||
|
, mUseOffset(true)
|
||||||
|
, mParent(parent)
|
||||||
|
, mPathgridGeometry(0)
|
||||||
|
, mDragGeometry(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->setUpdateCallback(new PathgridNodeCallback());
|
||||||
|
mBaseNode->setNodeMask(Mask_Pathgrid);
|
||||||
|
mParent->addChild(mBaseNode);
|
||||||
|
|
||||||
|
mPathgridGeode = new osg::Geode();
|
||||||
|
mBaseNode->addChild(mPathgridGeode);
|
||||||
|
|
||||||
|
recreateGeometry();
|
||||||
|
|
||||||
|
int index = mData.getCells().searchId(mId);
|
||||||
|
if (index != -1)
|
||||||
|
{
|
||||||
|
const CSMWorld::Cell& cell = mData.getCells().getRecord(index).get();
|
||||||
|
mInterior = cell.mData.mFlags & ESM::Cell::Interior;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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::Pathgrid* source = getPathgridSource();
|
||||||
|
if (source)
|
||||||
|
{
|
||||||
|
for (unsigned short i = 0; i < static_cast<unsigned short>(source->mPoints.size()); ++i)
|
||||||
|
mSelected.push_back(i);
|
||||||
|
|
||||||
|
createSelectedGeometry(*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);
|
||||||
|
}
|
||||||
|
|
||||||
|
createSelectedGeometry();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Pathgrid::invertSelected()
|
||||||
|
{
|
||||||
|
NodeList temp = NodeList(mSelected);
|
||||||
|
mSelected.clear();
|
||||||
|
|
||||||
|
const CSMWorld::Pathgrid* source = getPathgridSource();
|
||||||
|
if (source)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
createSelectedGeometry(*source);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
removeSelectedGeometry();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Pathgrid::clearSelected()
|
||||||
|
{
|
||||||
|
mSelected.clear();
|
||||||
|
removeSelectedGeometry();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Pathgrid::moveSelected(const osg::Vec3d& offset)
|
||||||
|
{
|
||||||
|
mUseOffset = true;
|
||||||
|
mMoveOffset += offset;
|
||||||
|
|
||||||
|
recreateGeometry();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Pathgrid::setDragOrigin(unsigned short node)
|
||||||
|
{
|
||||||
|
mDragOrigin = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Pathgrid::setDragEndpoint(unsigned short node)
|
||||||
|
{
|
||||||
|
const CSMWorld::Pathgrid* source = getPathgridSource();
|
||||||
|
if (source)
|
||||||
|
{
|
||||||
|
const CSMWorld::Pathgrid::Point& pointA = source->mPoints[mDragOrigin];
|
||||||
|
const CSMWorld::Pathgrid::Point& pointB = source->mPoints[node];
|
||||||
|
|
||||||
|
osg::Vec3f start = osg::Vec3f(pointA.mX, pointA.mY, pointA.mZ + SceneUtil::DiamondHalfHeight);
|
||||||
|
osg::Vec3f end = osg::Vec3f(pointB.mX, pointB.mY, pointB.mZ + SceneUtil::DiamondHalfHeight);
|
||||||
|
|
||||||
|
createDragGeometry(start, end, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Pathgrid::setDragEndpoint(const osg::Vec3d& pos)
|
||||||
|
{
|
||||||
|
const CSMWorld::Pathgrid* source = getPathgridSource();
|
||||||
|
if (source)
|
||||||
|
{
|
||||||
|
const CSMWorld::Pathgrid::Point& point = source->mPoints[mDragOrigin];
|
||||||
|
|
||||||
|
osg::Vec3f start = osg::Vec3f(point.mX, point.mY, point.mZ + SceneUtil::DiamondHalfHeight);
|
||||||
|
osg::Vec3f end = pos - mBaseNode->getPosition();
|
||||||
|
createDragGeometry(start, end, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Pathgrid::resetIndicators()
|
||||||
|
{
|
||||||
|
mUseOffset = false;
|
||||||
|
mMoveOffset.set(0, 0, 0);
|
||||||
|
|
||||||
|
mPathgridGeode->removeDrawable(mDragGeometry);
|
||||||
|
mDragGeometry = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Pathgrid::applyPoint(CSMWorld::CommandMacro& commands, const osg::Vec3d& worldPos)
|
||||||
|
{
|
||||||
|
CSMWorld::IdTree* model = dynamic_cast<CSMWorld::IdTree*>(mData.getTableModel(
|
||||||
|
CSMWorld::UniversalId::Type_Pathgrids));
|
||||||
|
|
||||||
|
const CSMWorld::Pathgrid* source = getPathgridSource();
|
||||||
|
if (source)
|
||||||
|
{
|
||||||
|
osg::Vec3d localCoords = worldPos - mBaseNode->getPosition();
|
||||||
|
|
||||||
|
int posX = clampToCell(static_cast<int>(localCoords.x()));
|
||||||
|
int posY = clampToCell(static_cast<int>(localCoords.y()));
|
||||||
|
int posZ = clampToCell(static_cast<int>(localCoords.z()));
|
||||||
|
|
||||||
|
int recordIndex = mPathgridCollection.getIndex (mId);
|
||||||
|
int parentColumn = mPathgridCollection.findColumnIndex(CSMWorld::Columns::ColumnId_PathgridPoints);
|
||||||
|
|
||||||
|
int posXColumn = mPathgridCollection.searchNestedColumnIndex(parentColumn,
|
||||||
|
CSMWorld::Columns::ColumnId_PathgridPosX);
|
||||||
|
|
||||||
|
int posYColumn = mPathgridCollection.searchNestedColumnIndex(parentColumn,
|
||||||
|
CSMWorld::Columns::ColumnId_PathgridPosY);
|
||||||
|
|
||||||
|
int posZColumn = mPathgridCollection.searchNestedColumnIndex(parentColumn,
|
||||||
|
CSMWorld::Columns::ColumnId_PathgridPosZ);
|
||||||
|
|
||||||
|
QModelIndex parent = model->index(recordIndex, parentColumn);
|
||||||
|
int row = static_cast<int>(source->mPoints.size());
|
||||||
|
|
||||||
|
// Add node to end of list
|
||||||
|
commands.push(new CSMWorld::AddNestedCommand(*model, mId, row, parentColumn));
|
||||||
|
commands.push(new CSMWorld::ModifyCommand(*model, model->index(row, posXColumn, parent), posX));
|
||||||
|
commands.push(new CSMWorld::ModifyCommand(*model, model->index(row, posYColumn, parent), posY));
|
||||||
|
commands.push(new CSMWorld::ModifyCommand(*model, model->index(row, posZColumn, parent), posZ));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int index = mPathgridCollection.searchId(mId);
|
||||||
|
if (index == -1)
|
||||||
|
{
|
||||||
|
// Does not exist
|
||||||
|
commands.push(new CSMWorld::CreatePathgridCommand(*model, mId));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
source = &mPathgridCollection.getRecord(index).get();
|
||||||
|
|
||||||
|
// Deleted, so revert and remove all data
|
||||||
|
commands.push(new CSMWorld::RevertCommand(*model, mId));
|
||||||
|
|
||||||
|
int parentColumn = mPathgridCollection.findColumnIndex(CSMWorld::Columns::ColumnId_PathgridPoints);
|
||||||
|
for (int row = source->mPoints.size() - 1; row >= 0; --row)
|
||||||
|
{
|
||||||
|
commands.push(new CSMWorld::DeleteNestedCommand(*model, mId, row, parentColumn));
|
||||||
|
}
|
||||||
|
|
||||||
|
parentColumn = mPathgridCollection.findColumnIndex(CSMWorld::Columns::ColumnId_PathgridEdges);
|
||||||
|
for (int row = source->mEdges.size() - 1; row >= 0; --row)
|
||||||
|
{
|
||||||
|
commands.push(new CSMWorld::DeleteNestedCommand(*model, mId, row, parentColumn));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Pathgrid::applyPosition(CSMWorld::CommandMacro& commands)
|
||||||
|
{
|
||||||
|
const CSMWorld::Pathgrid* source = getPathgridSource();
|
||||||
|
if (source)
|
||||||
|
{
|
||||||
|
osg::Vec3d localCoords = mMoveOffset;
|
||||||
|
|
||||||
|
int offsetX = static_cast<int>(localCoords.x());
|
||||||
|
int offsetY = static_cast<int>(localCoords.y());
|
||||||
|
int offsetZ = static_cast<int>(localCoords.z());
|
||||||
|
|
||||||
|
QAbstractItemModel* model = mData.getTableModel(CSMWorld::UniversalId::Type_Pathgrids);
|
||||||
|
|
||||||
|
int recordIndex = mPathgridCollection.getIndex(mId);
|
||||||
|
int parentColumn = mPathgridCollection.findColumnIndex(CSMWorld::Columns::ColumnId_PathgridPoints);
|
||||||
|
|
||||||
|
int posXColumn = mPathgridCollection.searchNestedColumnIndex(parentColumn,
|
||||||
|
CSMWorld::Columns::ColumnId_PathgridPosX);
|
||||||
|
|
||||||
|
int posYColumn = mPathgridCollection.searchNestedColumnIndex(parentColumn,
|
||||||
|
CSMWorld::Columns::ColumnId_PathgridPosY);
|
||||||
|
|
||||||
|
int posZColumn = mPathgridCollection.searchNestedColumnIndex(parentColumn,
|
||||||
|
CSMWorld::Columns::ColumnId_PathgridPosZ);
|
||||||
|
|
||||||
|
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 = static_cast<int>(mSelected[i]);
|
||||||
|
|
||||||
|
commands.push(new CSMWorld::ModifyCommand(*model, model->index(row, posXColumn, parent),
|
||||||
|
clampToCell(point.mX + offsetX)));
|
||||||
|
|
||||||
|
commands.push(new CSMWorld::ModifyCommand(*model, model->index(row, posYColumn, parent),
|
||||||
|
clampToCell(point.mY + offsetY)));
|
||||||
|
|
||||||
|
commands.push(new CSMWorld::ModifyCommand(*model, model->index(row, posZColumn, parent),
|
||||||
|
clampToCell(point.mZ + offsetZ)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Pathgrid::applyEdge(CSMWorld::CommandMacro& commands, unsigned short node1, unsigned short node2)
|
||||||
|
{
|
||||||
|
const CSMWorld::Pathgrid* source = getPathgridSource();
|
||||||
|
if (source)
|
||||||
|
{
|
||||||
|
addEdge(commands, *source, node1, node2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Pathgrid::applyEdges(CSMWorld::CommandMacro& commands, unsigned short node)
|
||||||
|
{
|
||||||
|
const CSMWorld::Pathgrid* source = getPathgridSource();
|
||||||
|
if (source)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < mSelected.size(); ++i)
|
||||||
|
{
|
||||||
|
addEdge(commands, *source, node, mSelected[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Pathgrid::applyRemoveNodes(CSMWorld::CommandMacro& commands)
|
||||||
|
{
|
||||||
|
const CSMWorld::Pathgrid* source = getPathgridSource();
|
||||||
|
if (source)
|
||||||
|
{
|
||||||
|
CSMWorld::IdTree* model = dynamic_cast<CSMWorld::IdTree*>(mData.getTableModel(
|
||||||
|
CSMWorld::UniversalId::Type_Pathgrids));
|
||||||
|
|
||||||
|
// Want to remove nodes from end of list first
|
||||||
|
std::sort(mSelected.begin(), mSelected.end(), std::greater<int>());
|
||||||
|
|
||||||
|
int recordIndex = mPathgridCollection.getIndex(mId);
|
||||||
|
int parentColumn = mPathgridCollection.findColumnIndex(CSMWorld::Columns::ColumnId_PathgridPoints);
|
||||||
|
|
||||||
|
for (std::vector<unsigned short>::iterator row = mSelected.begin(); row != mSelected.end(); ++row)
|
||||||
|
{
|
||||||
|
commands.push(new CSMWorld::DeleteNestedCommand(*model, mId, static_cast<int>(*row), parentColumn));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fix/remove edges
|
||||||
|
std::set<int, std::greater<int> > edgeRowsToRemove;
|
||||||
|
|
||||||
|
parentColumn = mPathgridCollection.findColumnIndex(CSMWorld::Columns::ColumnId_PathgridEdges);
|
||||||
|
|
||||||
|
int edge0Column = mPathgridCollection.searchNestedColumnIndex(parentColumn,
|
||||||
|
CSMWorld::Columns::ColumnId_PathgridEdge0);
|
||||||
|
|
||||||
|
int edge1Column = mPathgridCollection.searchNestedColumnIndex(parentColumn,
|
||||||
|
CSMWorld::Columns::ColumnId_PathgridEdge1);
|
||||||
|
|
||||||
|
QModelIndex parent = model->index(recordIndex, parentColumn);
|
||||||
|
|
||||||
|
for (size_t edge = 0; edge < source->mEdges.size(); ++edge)
|
||||||
|
{
|
||||||
|
int adjustment0 = 0;
|
||||||
|
int adjustment1 = 0;
|
||||||
|
|
||||||
|
// Determine necessary adjustment
|
||||||
|
for (std::vector<unsigned short>::iterator point = mSelected.begin(); point != mSelected.end(); ++point)
|
||||||
|
{
|
||||||
|
if (source->mEdges[edge].mV0 == *point || source->mEdges[edge].mV1 == *point)
|
||||||
|
{
|
||||||
|
edgeRowsToRemove.insert(static_cast<int>(edge));
|
||||||
|
|
||||||
|
adjustment0 = 0; // No need to adjust, its getting removed
|
||||||
|
adjustment1 = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (source->mEdges[edge].mV0 > *point)
|
||||||
|
--adjustment0;
|
||||||
|
|
||||||
|
if (source->mEdges[edge].mV1 > *point)
|
||||||
|
--adjustment1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (adjustment0 != 0)
|
||||||
|
{
|
||||||
|
int adjustedEdge = source->mEdges[edge].mV0 + adjustment0;
|
||||||
|
commands.push(new CSMWorld::ModifyCommand(*model, model->index(edge, edge0Column, parent),
|
||||||
|
adjustedEdge));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (adjustment1 != 0)
|
||||||
|
{
|
||||||
|
int adjustedEdge = source->mEdges[edge].mV1 + adjustment1;
|
||||||
|
commands.push(new CSMWorld::ModifyCommand(*model, model->index(edge, edge1Column, parent),
|
||||||
|
adjustedEdge));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::set<int, std::greater<int> >::iterator row;
|
||||||
|
for (row = edgeRowsToRemove.begin(); row != edgeRowsToRemove.end(); ++row)
|
||||||
|
{
|
||||||
|
commands.push(new CSMWorld::DeleteNestedCommand(*model, mId, *row, parentColumn));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
clearSelected();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Pathgrid::applyRemoveEdges(CSMWorld::CommandMacro& commands)
|
||||||
|
{
|
||||||
|
const CSMWorld::Pathgrid* source = getPathgridSource();
|
||||||
|
if (source)
|
||||||
|
{
|
||||||
|
// Want to remove from end of row first
|
||||||
|
std::set<int, std::greater<int> > rowsToRemove;
|
||||||
|
for (size_t i = 0; i <= mSelected.size(); ++i)
|
||||||
|
{
|
||||||
|
for (size_t j = i + 1; j < mSelected.size(); ++j)
|
||||||
|
{
|
||||||
|
int row = edgeExists(*source, mSelected[i], mSelected[j]);
|
||||||
|
if (row != -1)
|
||||||
|
{
|
||||||
|
rowsToRemove.insert(row);
|
||||||
|
}
|
||||||
|
|
||||||
|
row = edgeExists(*source, mSelected[j], mSelected[i]);
|
||||||
|
if (row != -1)
|
||||||
|
{
|
||||||
|
rowsToRemove.insert(row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CSMWorld::IdTree* model = dynamic_cast<CSMWorld::IdTree*>(mData.getTableModel(
|
||||||
|
CSMWorld::UniversalId::Type_Pathgrids));
|
||||||
|
|
||||||
|
int parentColumn = mPathgridCollection.findColumnIndex(CSMWorld::Columns::ColumnId_PathgridEdges);
|
||||||
|
|
||||||
|
std::set<int, std::greater<int> >::iterator row;
|
||||||
|
for (row = rowsToRemove.begin(); row != rowsToRemove.end(); ++row)
|
||||||
|
{
|
||||||
|
commands.push(new CSMWorld::DeleteNestedCommand(*model, mId, *row, parentColumn));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
osg::ref_ptr<PathgridTag> Pathgrid::getTag() const
|
||||||
|
{
|
||||||
|
return mTag;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Pathgrid::recreateGeometry()
|
||||||
|
{
|
||||||
|
mChangeGeometry = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Pathgrid::removeGeometry()
|
||||||
|
{
|
||||||
|
mRemoveGeometry = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Pathgrid::update()
|
||||||
|
{
|
||||||
|
if (mRemoveGeometry)
|
||||||
|
{
|
||||||
|
removePathgridGeometry();
|
||||||
|
removeSelectedGeometry();
|
||||||
|
}
|
||||||
|
else if (mChangeGeometry)
|
||||||
|
{
|
||||||
|
createGeometry();
|
||||||
|
}
|
||||||
|
|
||||||
|
mChangeGeometry = false;
|
||||||
|
mRemoveGeometry = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Pathgrid::createGeometry()
|
||||||
|
{
|
||||||
|
const CSMWorld::Pathgrid* source = getPathgridSource();
|
||||||
|
if (source)
|
||||||
|
{
|
||||||
|
CSMWorld::Pathgrid temp;
|
||||||
|
if (mUseOffset)
|
||||||
|
{
|
||||||
|
temp = *source;
|
||||||
|
|
||||||
|
for (NodeList::iterator it = mSelected.begin(); it != mSelected.end(); ++it)
|
||||||
|
{
|
||||||
|
temp.mPoints[*it].mX += mMoveOffset.x();
|
||||||
|
temp.mPoints[*it].mY += mMoveOffset.y();
|
||||||
|
temp.mPoints[*it].mZ += mMoveOffset.z();
|
||||||
|
}
|
||||||
|
|
||||||
|
source = &temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
removePathgridGeometry();
|
||||||
|
mPathgridGeometry = SceneUtil::createPathgridGeometry(*source);
|
||||||
|
mPathgridGeode->addDrawable(mPathgridGeometry);
|
||||||
|
|
||||||
|
createSelectedGeometry(*source);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
removePathgridGeometry();
|
||||||
|
removeSelectedGeometry();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Pathgrid::createSelectedGeometry()
|
||||||
|
{
|
||||||
|
const CSMWorld::Pathgrid* source = getPathgridSource();
|
||||||
|
if (source)
|
||||||
|
{
|
||||||
|
createSelectedGeometry(*source);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
removeSelectedGeometry();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Pathgrid::createSelectedGeometry(const CSMWorld::Pathgrid& source)
|
||||||
|
{
|
||||||
|
removeSelectedGeometry();
|
||||||
|
|
||||||
|
mSelectedGeometry = SceneUtil::createPathgridSelectedWireframe(source, mSelected);
|
||||||
|
mPathgridGeode->addDrawable(mSelectedGeometry);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Pathgrid::removePathgridGeometry()
|
||||||
|
{
|
||||||
|
if (mPathgridGeometry)
|
||||||
|
{
|
||||||
|
mPathgridGeode->removeDrawable(mPathgridGeometry);
|
||||||
|
mPathgridGeometry = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Pathgrid::removeSelectedGeometry()
|
||||||
|
{
|
||||||
|
if (mSelectedGeometry)
|
||||||
|
{
|
||||||
|
mPathgridGeode->removeDrawable(mSelectedGeometry);
|
||||||
|
mSelectedGeometry = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Pathgrid::createDragGeometry(const osg::Vec3f& start, const osg::Vec3f& end, bool valid)
|
||||||
|
{
|
||||||
|
if (mDragGeometry)
|
||||||
|
mPathgridGeode->removeDrawable(mDragGeometry);
|
||||||
|
|
||||||
|
mDragGeometry = new osg::Geometry();
|
||||||
|
|
||||||
|
osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array(2);
|
||||||
|
osg::ref_ptr<osg::Vec4Array> colors = new osg::Vec4Array(1);
|
||||||
|
osg::ref_ptr<osg::DrawElementsUShort> indices = new osg::DrawElementsUShort(osg::PrimitiveSet::LINES, 2);
|
||||||
|
|
||||||
|
(*vertices)[0] = start;
|
||||||
|
(*vertices)[1] = end;
|
||||||
|
|
||||||
|
if (valid)
|
||||||
|
{
|
||||||
|
(*colors)[0] = osg::Vec4f(0.91f, 0.66f, 1.f, 1.f);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
(*colors)[0] = osg::Vec4f(1.f, 0.f, 0.f, 1.f);
|
||||||
|
}
|
||||||
|
|
||||||
|
indices->setElement(0, 0);
|
||||||
|
indices->setElement(1, 1);
|
||||||
|
|
||||||
|
mDragGeometry->setVertexArray(vertices);
|
||||||
|
mDragGeometry->setColorArray(colors, osg::Array::BIND_OVERALL);
|
||||||
|
mDragGeometry->addPrimitiveSet(indices);
|
||||||
|
mDragGeometry->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
|
||||||
|
|
||||||
|
mPathgridGeode->addDrawable(mDragGeometry);
|
||||||
|
}
|
||||||
|
|
||||||
|
const CSMWorld::Pathgrid* Pathgrid::getPathgridSource()
|
||||||
|
{
|
||||||
|
int index = mPathgridCollection.searchId(mId);
|
||||||
|
if (index != -1 && !mPathgridCollection.getRecord(index).isDeleted())
|
||||||
|
{
|
||||||
|
return &mPathgridCollection.getRecord(index).get();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Pathgrid::edgeExists(const CSMWorld::Pathgrid& source, unsigned short node1, unsigned short node2)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < source.mEdges.size(); ++i)
|
||||||
|
{
|
||||||
|
if (source.mEdges[i].mV0 == node1 && source.mEdges[i].mV1 == node2)
|
||||||
|
return static_cast<int>(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Pathgrid::addEdge(CSMWorld::CommandMacro& commands, const CSMWorld::Pathgrid& source, unsigned short node1,
|
||||||
|
unsigned short node2)
|
||||||
|
{
|
||||||
|
CSMWorld::IdTree* model = dynamic_cast<CSMWorld::IdTree*>(mData.getTableModel(
|
||||||
|
CSMWorld::UniversalId::Type_Pathgrids));
|
||||||
|
|
||||||
|
int recordIndex = mPathgridCollection.getIndex(mId);
|
||||||
|
int parentColumn = mPathgridCollection.findColumnIndex(CSMWorld::Columns::ColumnId_PathgridEdges);
|
||||||
|
|
||||||
|
int edge0Column = mPathgridCollection.searchNestedColumnIndex(parentColumn,
|
||||||
|
CSMWorld::Columns::ColumnId_PathgridEdge0);
|
||||||
|
|
||||||
|
int edge1Column = mPathgridCollection.searchNestedColumnIndex(parentColumn,
|
||||||
|
CSMWorld::Columns::ColumnId_PathgridEdge1);
|
||||||
|
|
||||||
|
QModelIndex parent = model->index(recordIndex, parentColumn);
|
||||||
|
int row = static_cast<int>(source.mEdges.size());
|
||||||
|
|
||||||
|
if (edgeExists(source, node1, node2) == -1)
|
||||||
|
{
|
||||||
|
commands.push(new CSMWorld::AddNestedCommand(*model, mId, row, parentColumn));
|
||||||
|
commands.push(new CSMWorld::ModifyCommand(*model, model->index(row, edge0Column, parent), node1));
|
||||||
|
commands.push(new CSMWorld::ModifyCommand(*model, model->index(row, edge1Column, parent), node2));
|
||||||
|
++row;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (edgeExists(source, node2, node1) == -1)
|
||||||
|
{
|
||||||
|
commands.push(new CSMWorld::AddNestedCommand(*model, mId, row, parentColumn));
|
||||||
|
commands.push(new CSMWorld::ModifyCommand(*model, model->index(row, edge0Column, parent), node2));
|
||||||
|
commands.push(new CSMWorld::ModifyCommand(*model, model->index(row, edge1Column, parent), node1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int Pathgrid::clampToCell(int v)
|
||||||
|
{
|
||||||
|
const int CellExtent = ESM::Land::REAL_SIZE;
|
||||||
|
|
||||||
|
if (mInterior)
|
||||||
|
return v;
|
||||||
|
else if (v > CellExtent)
|
||||||
|
return CellExtent;
|
||||||
|
else if (v < 0)
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
}
|
137
apps/opencs/view/render/pathgrid.hpp
Normal file
137
apps/opencs/view/render/pathgrid.hpp
Normal file
|
@ -0,0 +1,137 @@
|
||||||
|
#ifndef CSV_RENDER_PATHGRID_H
|
||||||
|
#define CSV_RENDER_PATHGRID_H
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
|
#include <osg/ref_ptr>
|
||||||
|
#include <osg/Vec3d>
|
||||||
|
|
||||||
|
#include "../../model/world/cellcoordinates.hpp"
|
||||||
|
#include "../../model/world/idcollection.hpp"
|
||||||
|
#include "../../model/world/subcellcollection.hpp"
|
||||||
|
|
||||||
|
#include "tagbase.hpp"
|
||||||
|
|
||||||
|
namespace osg
|
||||||
|
{
|
||||||
|
class Geode;
|
||||||
|
class Geometry;
|
||||||
|
class Group;
|
||||||
|
class PositionAttitudeTransform;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace CSMWorld
|
||||||
|
{
|
||||||
|
class CommandMacro;
|
||||||
|
class Data;
|
||||||
|
struct 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 setDragOrigin(unsigned short node);
|
||||||
|
void setDragEndpoint(unsigned short node);
|
||||||
|
void setDragEndpoint(const osg::Vec3d& pos);
|
||||||
|
|
||||||
|
void resetIndicators();
|
||||||
|
|
||||||
|
void applyPoint(CSMWorld::CommandMacro& commands, const osg::Vec3d& worldPos);
|
||||||
|
void applyPosition(CSMWorld::CommandMacro& commands);
|
||||||
|
void applyEdge(CSMWorld::CommandMacro& commands, unsigned short node1, unsigned short node2);
|
||||||
|
void applyEdges(CSMWorld::CommandMacro& commands, unsigned short node);
|
||||||
|
void applyRemoveNodes(CSMWorld::CommandMacro& commands);
|
||||||
|
void applyRemoveEdges(CSMWorld::CommandMacro& commands);
|
||||||
|
|
||||||
|
osg::ref_ptr<PathgridTag> getTag() const;
|
||||||
|
|
||||||
|
void recreateGeometry();
|
||||||
|
void removeGeometry();
|
||||||
|
|
||||||
|
void update();
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
CSMWorld::Data& mData;
|
||||||
|
CSMWorld::SubCellCollection<CSMWorld::Pathgrid>& mPathgridCollection;
|
||||||
|
std::string mId;
|
||||||
|
CSMWorld::CellCoordinates mCoords;
|
||||||
|
bool mInterior;
|
||||||
|
|
||||||
|
NodeList mSelected;
|
||||||
|
osg::Vec3d mMoveOffset;
|
||||||
|
unsigned short mDragOrigin;
|
||||||
|
|
||||||
|
bool mChangeGeometry;
|
||||||
|
bool mRemoveGeometry;
|
||||||
|
bool mUseOffset;
|
||||||
|
|
||||||
|
osg::Group* mParent;
|
||||||
|
osg::ref_ptr<osg::PositionAttitudeTransform> mBaseNode;
|
||||||
|
osg::ref_ptr<osg::Geode> mPathgridGeode;
|
||||||
|
osg::ref_ptr<osg::Geometry> mPathgridGeometry;
|
||||||
|
osg::ref_ptr<osg::Geometry> mSelectedGeometry;
|
||||||
|
osg::ref_ptr<osg::Geometry> mDragGeometry;
|
||||||
|
|
||||||
|
osg::ref_ptr<PathgridTag> mTag;
|
||||||
|
|
||||||
|
void createGeometry();
|
||||||
|
void createSelectedGeometry();
|
||||||
|
void createSelectedGeometry(const CSMWorld::Pathgrid& source);
|
||||||
|
void removePathgridGeometry();
|
||||||
|
void removeSelectedGeometry();
|
||||||
|
|
||||||
|
void createDragGeometry(const osg::Vec3f& start, const osg::Vec3f& end, bool valid);
|
||||||
|
|
||||||
|
const CSMWorld::Pathgrid* getPathgridSource();
|
||||||
|
|
||||||
|
int edgeExists(const CSMWorld::Pathgrid& source, unsigned short node1, unsigned short node2);
|
||||||
|
void addEdge(CSMWorld::CommandMacro& commands, const CSMWorld::Pathgrid& source, unsigned short node1,
|
||||||
|
unsigned short node2);
|
||||||
|
void removeEdge(CSMWorld::CommandMacro& commands, const CSMWorld::Pathgrid& source, unsigned short node1,
|
||||||
|
unsigned short node2);
|
||||||
|
|
||||||
|
int clampToCell(int v);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
265
apps/opencs/view/render/pathgridmode.cpp
Normal file
265
apps/opencs/view/render/pathgridmode.cpp
Normal file
|
@ -0,0 +1,265 @@
|
||||||
|
#include "pathgridmode.hpp"
|
||||||
|
|
||||||
|
#include <QMenu>
|
||||||
|
#include <QPoint>
|
||||||
|
|
||||||
|
#include <components/sceneutil/pathgridutil.hpp>
|
||||||
|
|
||||||
|
#include "../../model/prefs/state.hpp"
|
||||||
|
|
||||||
|
#include "../../model/world/commands.hpp"
|
||||||
|
#include "../../model/world/commandmacro.hpp"
|
||||||
|
#include "../../model/world/idtable.hpp"
|
||||||
|
#include "../../model/world/idtree.hpp"
|
||||||
|
|
||||||
|
#include "../widget/scenetoolbar.hpp"
|
||||||
|
|
||||||
|
#include "cell.hpp"
|
||||||
|
#include "mask.hpp"
|
||||||
|
#include "pathgrid.hpp"
|
||||||
|
#include "pathgridselectionmode.hpp"
|
||||||
|
#include "worldspacewidget.hpp"
|
||||||
|
|
||||||
|
namespace CSVRender
|
||||||
|
{
|
||||||
|
PathgridMode::PathgridMode(WorldspaceWidget* worldspaceWidget, QWidget* parent)
|
||||||
|
: EditMode(worldspaceWidget, QIcon(":placeholder"), Mask_Pathgrid | Mask_Terrain | Mask_Reference,
|
||||||
|
getTooltip(), parent)
|
||||||
|
, mDragMode(DragMode_None)
|
||||||
|
, mFromNode(0)
|
||||||
|
, mSelectionMode(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QString PathgridMode::getTooltip()
|
||||||
|
{
|
||||||
|
return QString(
|
||||||
|
"Pathgrid editing"
|
||||||
|
"<ul><li>Primary edit: Add node to scene</li>"
|
||||||
|
"<li>Secondary edit: Connect selected nodes to node</li>"
|
||||||
|
"<li>Primary drag: Move selected nodes</li>"
|
||||||
|
"<li>Secondary drag: Connect one node to another</li>"
|
||||||
|
"</ul><p>Note: Only a single cell's pathgrid may be edited at a time");
|
||||||
|
}
|
||||||
|
|
||||||
|
void PathgridMode::activate(CSVWidget::SceneToolbar* toolbar)
|
||||||
|
{
|
||||||
|
if (!mSelectionMode)
|
||||||
|
{
|
||||||
|
mSelectionMode = new PathgridSelectionMode(toolbar, getWorldspaceWidget());
|
||||||
|
}
|
||||||
|
|
||||||
|
EditMode::activate(toolbar);
|
||||||
|
toolbar->addTool(mSelectionMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PathgridMode::primaryEditPressed(const WorldspaceHitResult& hitResult)
|
||||||
|
{
|
||||||
|
if (CSMPrefs::get()["3D Scene Input"]["context-select"].isTrue() &&
|
||||||
|
dynamic_cast<PathgridTag*>(hitResult.tag.get()))
|
||||||
|
{
|
||||||
|
primarySelectPressed(hitResult);
|
||||||
|
}
|
||||||
|
else if (Cell* cell = getWorldspaceWidget().getCell (hitResult.worldPos))
|
||||||
|
{
|
||||||
|
// Add node
|
||||||
|
QUndoStack& undoStack = getWorldspaceWidget().getDocument().getUndoStack();
|
||||||
|
QString description = "Add node";
|
||||||
|
|
||||||
|
CSMWorld::CommandMacro macro(undoStack, description);
|
||||||
|
cell->getPathgrid()->applyPoint(macro, hitResult.worldPos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PathgridMode::secondaryEditPressed(const WorldspaceHitResult& hit)
|
||||||
|
{
|
||||||
|
if (hit.tag)
|
||||||
|
{
|
||||||
|
if (PathgridTag* tag = dynamic_cast<PathgridTag*>(hit.tag.get()))
|
||||||
|
{
|
||||||
|
if (tag->getPathgrid()->isSelected())
|
||||||
|
{
|
||||||
|
unsigned short node = SceneUtil::getPathgridNode(static_cast<unsigned short>(hit.index0));
|
||||||
|
|
||||||
|
QUndoStack& undoStack = getWorldspaceWidget().getDocument().getUndoStack();
|
||||||
|
QString description = "Connect node to selected nodes";
|
||||||
|
|
||||||
|
CSMWorld::CommandMacro macro(undoStack, description);
|
||||||
|
tag->getPathgrid()->applyEdges(macro, node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PathgridMode::primarySelectPressed(const WorldspaceHitResult& hit)
|
||||||
|
{
|
||||||
|
getWorldspaceWidget().clearSelection(Mask_Pathgrid);
|
||||||
|
|
||||||
|
if (hit.tag)
|
||||||
|
{
|
||||||
|
if (PathgridTag* tag = dynamic_cast<PathgridTag*>(hit.tag.get()))
|
||||||
|
{
|
||||||
|
mLastId = tag->getPathgrid()->getId();
|
||||||
|
unsigned short node = SceneUtil::getPathgridNode(static_cast<unsigned short>(hit.index0));
|
||||||
|
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.index0));
|
||||||
|
tag->getPathgrid()->toggleSelected(node);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getWorldspaceWidget().clearSelection(Mask_Pathgrid);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PathgridMode::primaryEditStartDrag(const QPoint& pos)
|
||||||
|
{
|
||||||
|
std::vector<osg::ref_ptr<TagBase> > selection = getWorldspaceWidget().getSelection (Mask_Pathgrid);
|
||||||
|
|
||||||
|
if (CSMPrefs::get()["3D Scene Input"]["context-select"].isTrue())
|
||||||
|
{
|
||||||
|
WorldspaceHitResult hit = getWorldspaceWidget().mousePick (pos, getWorldspaceWidget().getInteractionMask());
|
||||||
|
|
||||||
|
if (dynamic_cast<PathgridTag*>(hit.tag.get()))
|
||||||
|
{
|
||||||
|
primarySelectPressed(hit);
|
||||||
|
selection = getWorldspaceWidget().getSelection (Mask_Pathgrid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!selection.empty())
|
||||||
|
{
|
||||||
|
mDragMode = DragMode_Move;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PathgridMode::secondaryEditStartDrag(const QPoint& pos)
|
||||||
|
{
|
||||||
|
WorldspaceHitResult hit = getWorldspaceWidget().mousePick (pos, getWorldspaceWidget().getInteractionMask());
|
||||||
|
if (hit.tag)
|
||||||
|
{
|
||||||
|
if (PathgridTag* tag = dynamic_cast<PathgridTag*>(hit.tag.get()))
|
||||||
|
{
|
||||||
|
mDragMode = DragMode_Edge;
|
||||||
|
mEdgeId = tag->getPathgrid()->getId();
|
||||||
|
mFromNode = SceneUtil::getPathgridNode(static_cast<unsigned short>(hit.index0));
|
||||||
|
|
||||||
|
tag->getPathgrid()->setDragOrigin(mFromNode);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PathgridMode::drag(const QPoint& pos, int diffX, int diffY, double speedFactor)
|
||||||
|
{
|
||||||
|
if (mDragMode == DragMode_Move)
|
||||||
|
{
|
||||||
|
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()))
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
WorldspaceHitResult hit = getWorldspaceWidget().mousePick (pos, getWorldspaceWidget().getInteractionMask());
|
||||||
|
|
||||||
|
Cell* cell = getWorldspaceWidget().getCell(hit.worldPos);
|
||||||
|
if (cell)
|
||||||
|
{
|
||||||
|
PathgridTag* tag = 0;
|
||||||
|
if (hit.tag && (tag = dynamic_cast<PathgridTag*>(hit.tag.get())) && tag->getPathgrid()->getId() == mEdgeId)
|
||||||
|
{
|
||||||
|
unsigned short node = SceneUtil::getPathgridNode(static_cast<unsigned short>(hit.index0));
|
||||||
|
cell->getPathgrid()->setDragEndpoint(node);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cell->getPathgrid()->setDragEndpoint(hit.worldPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PathgridMode::dragCompleted(const QPoint& pos)
|
||||||
|
{
|
||||||
|
if (mDragMode == DragMode_Move)
|
||||||
|
{
|
||||||
|
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()))
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
WorldspaceHitResult hit = getWorldspaceWidget().mousePick(pos, getWorldspaceWidget().getInteractionMask());
|
||||||
|
|
||||||
|
if (hit.tag)
|
||||||
|
{
|
||||||
|
if (PathgridTag* tag = dynamic_cast<PathgridTag*>(hit.tag.get()))
|
||||||
|
{
|
||||||
|
if (tag->getPathgrid()->getId() == mEdgeId)
|
||||||
|
{
|
||||||
|
unsigned short toNode = SceneUtil::getPathgridNode(static_cast<unsigned short>(hit.index0));
|
||||||
|
|
||||||
|
QUndoStack& undoStack = getWorldspaceWidget().getDocument().getUndoStack();
|
||||||
|
QString description = "Add edge between nodes";
|
||||||
|
|
||||||
|
CSMWorld::CommandMacro macro(undoStack, description);
|
||||||
|
tag->getPathgrid()->applyEdge(macro, mFromNode, toNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mEdgeId.clear();
|
||||||
|
mFromNode = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
mDragMode = DragMode_None;
|
||||||
|
getWorldspaceWidget().reset(Mask_Pathgrid);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PathgridMode::dragAborted()
|
||||||
|
{
|
||||||
|
getWorldspaceWidget().reset(Mask_Pathgrid);
|
||||||
|
}
|
||||||
|
}
|
61
apps/opencs/view/render/pathgridmode.hpp
Normal file
61
apps/opencs/view/render/pathgridmode.hpp
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
#ifndef CSV_RENDER_PATHGRIDMODE_H
|
||||||
|
#define CSV_RENDER_PATHGRIDMODE_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "editmode.hpp"
|
||||||
|
|
||||||
|
namespace CSVRender
|
||||||
|
{
|
||||||
|
class PathgridSelectionMode;
|
||||||
|
|
||||||
|
class PathgridMode : public EditMode
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
PathgridMode(WorldspaceWidget* worldspace, QWidget* parent=0);
|
||||||
|
|
||||||
|
virtual void activate(CSVWidget::SceneToolbar* toolbar);
|
||||||
|
|
||||||
|
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 QPoint& pos);
|
||||||
|
|
||||||
|
virtual bool secondaryEditStartDrag (const QPoint& pos);
|
||||||
|
|
||||||
|
virtual void drag (const QPoint& pos, int diffX, int diffY, double speedFactor);
|
||||||
|
|
||||||
|
virtual void dragCompleted(const QPoint& pos);
|
||||||
|
|
||||||
|
/// \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
|
||||||
|
};
|
||||||
|
|
||||||
|
DragMode mDragMode;
|
||||||
|
std::string mLastId, mEdgeId;
|
||||||
|
unsigned short mFromNode;
|
||||||
|
|
||||||
|
PathgridSelectionMode* mSelectionMode;
|
||||||
|
|
||||||
|
QString getTooltip();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
71
apps/opencs/view/render/pathgridselectionmode.cpp
Normal file
71
apps/opencs/view/render/pathgridselectionmode.cpp
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
#include "pathgridselectionmode.hpp"
|
||||||
|
|
||||||
|
#include <QMenu>
|
||||||
|
#include <QAction>
|
||||||
|
|
||||||
|
#include "../../model/world/idtable.hpp"
|
||||||
|
#include "../../model/world/commands.hpp"
|
||||||
|
#include "../../model/world/commandmacro.hpp"
|
||||||
|
|
||||||
|
#include "worldspacewidget.hpp"
|
||||||
|
#include "pathgrid.hpp"
|
||||||
|
|
||||||
|
namespace CSVRender
|
||||||
|
{
|
||||||
|
PathgridSelectionMode::PathgridSelectionMode(CSVWidget::SceneToolbar* parent, WorldspaceWidget& worldspaceWidget)
|
||||||
|
: SelectionMode(parent, worldspaceWidget, Mask_Pathgrid)
|
||||||
|
{
|
||||||
|
mRemoveSelectedNodes = new QAction("Remove selected nodes", this);
|
||||||
|
mRemoveSelectedEdges = new QAction("Remove edges between selected nodes", this);
|
||||||
|
|
||||||
|
connect(mRemoveSelectedNodes, SIGNAL(triggered()), this, SLOT(removeSelectedNodes()));
|
||||||
|
connect(mRemoveSelectedEdges, SIGNAL(triggered()), this, SLOT(removeSelectedEdges()));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PathgridSelectionMode::createContextMenu(QMenu* menu)
|
||||||
|
{
|
||||||
|
if (menu)
|
||||||
|
{
|
||||||
|
SelectionMode::createContextMenu(menu);
|
||||||
|
|
||||||
|
menu->addAction(mRemoveSelectedNodes);
|
||||||
|
menu->addAction(mRemoveSelectedEdges);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PathgridSelectionMode::removeSelectedNodes()
|
||||||
|
{
|
||||||
|
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()))
|
||||||
|
{
|
||||||
|
QUndoStack& undoStack = getWorldspaceWidget().getDocument().getUndoStack();
|
||||||
|
QString description = "Remove selected nodes";
|
||||||
|
|
||||||
|
CSMWorld::CommandMacro macro(undoStack, description);
|
||||||
|
tag->getPathgrid()->applyRemoveNodes(macro);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PathgridSelectionMode::removeSelectedEdges()
|
||||||
|
{
|
||||||
|
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()))
|
||||||
|
{
|
||||||
|
QUndoStack& undoStack = getWorldspaceWidget().getDocument().getUndoStack();
|
||||||
|
QString description = "Remove edges between selected nodes";
|
||||||
|
|
||||||
|
CSMWorld::CommandMacro macro(undoStack, description);
|
||||||
|
tag->getPathgrid()->applyRemoveEdges(macro);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
38
apps/opencs/view/render/pathgridselectionmode.hpp
Normal file
38
apps/opencs/view/render/pathgridselectionmode.hpp
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
#ifndef CSV_RENDER_PATHGRID_SELECTION_MODE_H
|
||||||
|
#define CSV_RENDER_PATHGRID_SELECTION_MODE_H
|
||||||
|
|
||||||
|
#include "selectionmode.hpp"
|
||||||
|
|
||||||
|
namespace CSVRender
|
||||||
|
{
|
||||||
|
class PathgridSelectionMode : public SelectionMode
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
PathgridSelectionMode(CSVWidget::SceneToolbar* parent, WorldspaceWidget& worldspaceWidget);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
/// Add context menu items to \a menu.
|
||||||
|
///
|
||||||
|
/// \attention menu can be a 0-pointer
|
||||||
|
///
|
||||||
|
/// \return Have there been any menu items to be added (if menu is 0 and there
|
||||||
|
/// items to be added, the function must return true anyway.
|
||||||
|
bool createContextMenu(QMenu* menu);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
QAction* mRemoveSelectedNodes;
|
||||||
|
QAction* mRemoveSelectedEdges;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
|
||||||
|
void removeSelectedNodes();
|
||||||
|
void removeSelectedEdges();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
77
apps/opencs/view/render/selectionmode.cpp
Normal file
77
apps/opencs/view/render/selectionmode.cpp
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
#include "selectionmode.hpp"
|
||||||
|
|
||||||
|
#include <QMenu>
|
||||||
|
#include <QAction>
|
||||||
|
|
||||||
|
#include "worldspacewidget.hpp"
|
||||||
|
|
||||||
|
namespace CSVRender
|
||||||
|
{
|
||||||
|
SelectionMode::SelectionMode(CSVWidget::SceneToolbar* parent, WorldspaceWidget& worldspaceWidget,
|
||||||
|
unsigned int interactionMask)
|
||||||
|
: SceneToolMode(parent, "Selection mode")
|
||||||
|
, mWorldspaceWidget(worldspaceWidget)
|
||||||
|
, mInteractionMask(interactionMask)
|
||||||
|
{
|
||||||
|
addButton(":placeholder", "cube-centre",
|
||||||
|
"Centred cube"
|
||||||
|
"<ul><li>Drag with primary (make instances the selection) or secondary (invert selection state) select button from the centre of the selection cube outwards</li>"
|
||||||
|
"<li>The selection cube is aligned to the word space axis</li>"
|
||||||
|
"<li>If context selection mode is enabled, a drag with primary/secondary edit not starting on an instance will have the same effect</li>"
|
||||||
|
"</ul>"
|
||||||
|
"<font color=Red>Not implemented yet</font color>");
|
||||||
|
addButton(":placeholder", "cube-corner",
|
||||||
|
"Cube corner to corner"
|
||||||
|
"<ul><li>Drag with primary (make instances the selection) or secondary (invert selection state) select button from one corner of the selection cube to the opposite corner</li>"
|
||||||
|
"<li>The selection cube is aligned to the word space axis</li>"
|
||||||
|
"<li>If context selection mode is enabled, a drag with primary/secondary edit not starting on an instance will have the same effect</li>"
|
||||||
|
"</ul>"
|
||||||
|
"<font color=Red>Not implemented yet</font color>");
|
||||||
|
addButton(":placeholder", "sphere",
|
||||||
|
"Centred sphere"
|
||||||
|
"<ul><li>Drag with primary (make instances the selection) or secondary (invert selection state) select button from the centre of the selection sphere outwards</li>"
|
||||||
|
"<li>If context selection mode is enabled, a drag with primary/secondary edit not starting on an instance will have the same effect</li>"
|
||||||
|
"</ul>"
|
||||||
|
"<font color=Red>Not implemented yet</font color>");
|
||||||
|
|
||||||
|
mSelectAll = new QAction("Select all", this);
|
||||||
|
mDeselectAll = new QAction("Clear selection", this);
|
||||||
|
mInvertSelection = new QAction("Invert selection", this);
|
||||||
|
|
||||||
|
connect(mSelectAll, SIGNAL(triggered()), this, SLOT(selectAll()));
|
||||||
|
connect(mDeselectAll, SIGNAL(triggered()), this, SLOT(clearSelection()));
|
||||||
|
connect(mInvertSelection, SIGNAL(triggered()), this, SLOT(invertSelection()));
|
||||||
|
}
|
||||||
|
|
||||||
|
WorldspaceWidget& SelectionMode::getWorldspaceWidget()
|
||||||
|
{
|
||||||
|
return mWorldspaceWidget;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SelectionMode::createContextMenu (QMenu* menu)
|
||||||
|
{
|
||||||
|
if (menu)
|
||||||
|
{
|
||||||
|
menu->addAction(mSelectAll);
|
||||||
|
menu->addAction(mDeselectAll);
|
||||||
|
menu->addAction(mInvertSelection);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SelectionMode::selectAll()
|
||||||
|
{
|
||||||
|
getWorldspaceWidget().selectAll(mInteractionMask);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SelectionMode::clearSelection()
|
||||||
|
{
|
||||||
|
getWorldspaceWidget().clearSelection(mInteractionMask);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SelectionMode::invertSelection()
|
||||||
|
{
|
||||||
|
getWorldspaceWidget().invertSelection(mInteractionMask);
|
||||||
|
}
|
||||||
|
}
|
51
apps/opencs/view/render/selectionmode.hpp
Normal file
51
apps/opencs/view/render/selectionmode.hpp
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
#ifndef CSV_RENDER_SELECTION_MODE_H
|
||||||
|
#define CSV_RENDER_SELECTION_MODE_H
|
||||||
|
|
||||||
|
#include "../widget/scenetoolmode.hpp"
|
||||||
|
|
||||||
|
#include "mask.hpp"
|
||||||
|
|
||||||
|
class QAction;
|
||||||
|
|
||||||
|
namespace CSVRender
|
||||||
|
{
|
||||||
|
class WorldspaceWidget;
|
||||||
|
|
||||||
|
class SelectionMode : public CSVWidget::SceneToolMode
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
SelectionMode(CSVWidget::SceneToolbar* parent, WorldspaceWidget& worldspaceWidget,
|
||||||
|
unsigned int interactionMask);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
WorldspaceWidget& getWorldspaceWidget();
|
||||||
|
|
||||||
|
/// Add context menu items to \a menu.
|
||||||
|
///
|
||||||
|
/// \attention menu can be a 0-pointer
|
||||||
|
///
|
||||||
|
/// \return Have there been any menu items to be added (if menu is 0 and there
|
||||||
|
/// items to be added, the function must return true anyway.
|
||||||
|
virtual bool createContextMenu (QMenu* menu);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
WorldspaceWidget& mWorldspaceWidget;
|
||||||
|
unsigned int mInteractionMask;
|
||||||
|
QAction* mSelectAll;
|
||||||
|
QAction* mDeselectAll;
|
||||||
|
QAction* mInvertSelection;
|
||||||
|
|
||||||
|
protected slots:
|
||||||
|
|
||||||
|
virtual void selectAll();
|
||||||
|
virtual void clearSelection();
|
||||||
|
virtual void invertSelection();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -104,6 +104,12 @@ void CSVRender::UnpagedWorldspaceWidget::clearSelection (int elementMask)
|
||||||
flagAsModified();
|
flagAsModified();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSVRender::UnpagedWorldspaceWidget::invertSelection (int elementMask)
|
||||||
|
{
|
||||||
|
mCell->setSelection (elementMask, Cell::Selection_Invert);
|
||||||
|
flagAsModified();
|
||||||
|
}
|
||||||
|
|
||||||
void CSVRender::UnpagedWorldspaceWidget::selectAll (int elementMask)
|
void CSVRender::UnpagedWorldspaceWidget::selectAll (int elementMask)
|
||||||
{
|
{
|
||||||
mCell->setSelection (elementMask, Cell::Selection_All);
|
mCell->setSelection (elementMask, Cell::Selection_All);
|
||||||
|
@ -121,6 +127,11 @@ std::string CSVRender::UnpagedWorldspaceWidget::getCellId (const osg::Vec3f& poi
|
||||||
return mCellId;
|
return mCellId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CSVRender::Cell* CSVRender::UnpagedWorldspaceWidget::getCell(const osg::Vec3d& point) const
|
||||||
|
{
|
||||||
|
return mCell.get();
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<osg::ref_ptr<CSVRender::TagBase> > CSVRender::UnpagedWorldspaceWidget::getSelection (
|
std::vector<osg::ref_ptr<CSVRender::TagBase> > CSVRender::UnpagedWorldspaceWidget::getSelection (
|
||||||
unsigned int elementMask) const
|
unsigned int elementMask) const
|
||||||
{
|
{
|
||||||
|
@ -201,32 +212,28 @@ void CSVRender::UnpagedWorldspaceWidget::pathgridDataChanged (const QModelIndex&
|
||||||
{
|
{
|
||||||
const CSMWorld::SubCellCollection<CSMWorld::Pathgrid>& pathgrids = mDocument.getData().getPathgrids();
|
const CSMWorld::SubCellCollection<CSMWorld::Pathgrid>& pathgrids = mDocument.getData().getPathgrids();
|
||||||
|
|
||||||
|
int rowStart = -1;
|
||||||
|
int rowEnd = -1;
|
||||||
|
|
||||||
if (topLeft.parent().isValid())
|
if (topLeft.parent().isValid())
|
||||||
{
|
{
|
||||||
int row = topLeft.parent().row();
|
rowStart = topLeft.parent().row();
|
||||||
|
rowEnd = bottomRight.parent().row();
|
||||||
const CSMWorld::Pathgrid& pathgrid = pathgrids.getRecord(row).get();
|
}
|
||||||
if (mCellId == pathgrid.mId)
|
else
|
||||||
{
|
{
|
||||||
mCell->pathgridDataChanged(topLeft, bottomRight);
|
rowStart = topLeft.row();
|
||||||
flagAsModified();
|
rowEnd = bottomRight.row();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void CSVRender::UnpagedWorldspaceWidget::pathgridRemoved (const QModelIndex& parent, int start, int end)
|
|
||||||
{
|
|
||||||
const CSMWorld::SubCellCollection<CSMWorld::Pathgrid>& pathgrids = mDocument.getData().getPathgrids();
|
|
||||||
|
|
||||||
if (parent.isValid()){
|
|
||||||
// Pathgrid data was modified
|
|
||||||
int row = parent.row();
|
|
||||||
|
|
||||||
|
for (int row = rowStart; row <= rowEnd; ++row)
|
||||||
|
{
|
||||||
const CSMWorld::Pathgrid& pathgrid = pathgrids.getRecord(row).get();
|
const CSMWorld::Pathgrid& pathgrid = pathgrids.getRecord(row).get();
|
||||||
if (mCellId == pathgrid.mId)
|
if (mCellId == pathgrid.mId)
|
||||||
{
|
{
|
||||||
mCell->pathgridRowRemoved(parent, start, end);
|
mCell->pathgridModified();
|
||||||
flagAsModified();
|
flagAsModified();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -245,6 +252,7 @@ void CSVRender::UnpagedWorldspaceWidget::pathgridAboutToBeRemoved (const QModelI
|
||||||
{
|
{
|
||||||
mCell->pathgridRemoved();
|
mCell->pathgridRemoved();
|
||||||
flagAsModified();
|
flagAsModified();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -256,29 +264,17 @@ void CSVRender::UnpagedWorldspaceWidget::pathgridAdded (const QModelIndex& paren
|
||||||
|
|
||||||
if (!parent.isValid())
|
if (!parent.isValid())
|
||||||
{
|
{
|
||||||
// Pathgrid added theoretically, unable to test until it is possible to add pathgrids
|
|
||||||
for (int row = start; row <= end; ++row)
|
for (int row = start; row <= end; ++row)
|
||||||
{
|
{
|
||||||
const CSMWorld::Pathgrid& pathgrid = pathgrids.getRecord(row).get();
|
const CSMWorld::Pathgrid& pathgrid = pathgrids.getRecord(row).get();
|
||||||
if (mCellId == pathgrid.mId)
|
if (mCellId == pathgrid.mId)
|
||||||
{
|
{
|
||||||
mCell->pathgridAdded(pathgrid);
|
mCell->pathgridModified();
|
||||||
flagAsModified();
|
flagAsModified();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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 (
|
void CSVRender::UnpagedWorldspaceWidget::addVisibilitySelectorButtons (
|
||||||
|
|
|
@ -47,6 +47,9 @@ namespace CSVRender
|
||||||
/// \param elementMask Elements to be affected by the clear operation
|
/// \param elementMask Elements to be affected by the clear operation
|
||||||
virtual void clearSelection (int elementMask);
|
virtual void clearSelection (int elementMask);
|
||||||
|
|
||||||
|
/// \param elementMask Elements to be affected by the select operation
|
||||||
|
virtual void invertSelection (int elementMask);
|
||||||
|
|
||||||
/// \param elementMask Elements to be affected by the select operation
|
/// \param elementMask Elements to be affected by the select operation
|
||||||
virtual void selectAll (int elementMask);
|
virtual void selectAll (int elementMask);
|
||||||
|
|
||||||
|
@ -58,6 +61,8 @@ namespace CSVRender
|
||||||
|
|
||||||
virtual std::string getCellId (const osg::Vec3f& point) const;
|
virtual std::string getCellId (const osg::Vec3f& point) const;
|
||||||
|
|
||||||
|
virtual Cell* getCell(const osg::Vec3d& point) const;
|
||||||
|
|
||||||
virtual std::vector<osg::ref_ptr<TagBase> > getSelection (unsigned int elementMask)
|
virtual std::vector<osg::ref_ptr<TagBase> > getSelection (unsigned int elementMask)
|
||||||
const;
|
const;
|
||||||
|
|
||||||
|
@ -86,8 +91,6 @@ namespace CSVRender
|
||||||
|
|
||||||
virtual void pathgridDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight);
|
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 pathgridAboutToBeRemoved (const QModelIndex& parent, int start, int end);
|
||||||
|
|
||||||
virtual void pathgridAdded (const QModelIndex& parent, int start, int end);
|
virtual void pathgridAdded (const QModelIndex& parent, int start, int end);
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
#include "worldspacewidget.hpp"
|
#include "worldspacewidget.hpp"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
#include <QEvent>
|
#include <QEvent>
|
||||||
#include <QDragEnterEvent>
|
#include <QDragEnterEvent>
|
||||||
|
@ -27,8 +26,8 @@
|
||||||
|
|
||||||
#include "object.hpp"
|
#include "object.hpp"
|
||||||
#include "mask.hpp"
|
#include "mask.hpp"
|
||||||
#include "editmode.hpp"
|
|
||||||
#include "instancemode.hpp"
|
#include "instancemode.hpp"
|
||||||
|
#include "pathgridmode.hpp"
|
||||||
#include "cameracontroller.hpp"
|
#include "cameracontroller.hpp"
|
||||||
|
|
||||||
CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidget* parent)
|
CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidget* parent)
|
||||||
|
@ -63,8 +62,6 @@ CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidg
|
||||||
|
|
||||||
connect (pathgrids, SIGNAL (dataChanged (const QModelIndex&, const QModelIndex&)),
|
connect (pathgrids, SIGNAL (dataChanged (const QModelIndex&, const QModelIndex&)),
|
||||||
this, SLOT (pathgridDataChanged (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)),
|
connect (pathgrids, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)),
|
||||||
this, SLOT (pathgridAboutToBeRemoved (const QModelIndex&, int, int)));
|
this, SLOT (pathgridAboutToBeRemoved (const QModelIndex&, int, int)));
|
||||||
connect (pathgrids, SIGNAL (rowsInserted (const QModelIndex&, int, int)),
|
connect (pathgrids, SIGNAL (rowsInserted (const QModelIndex&, int, int)),
|
||||||
|
@ -320,9 +317,7 @@ void CSVRender::WorldspaceWidget::addEditModeSelectorButtons (CSVWidget::SceneTo
|
||||||
{
|
{
|
||||||
/// \todo replace EditMode with suitable subclasses
|
/// \todo replace EditMode with suitable subclasses
|
||||||
tool->addButton (new InstanceMode (this, tool), "object");
|
tool->addButton (new InstanceMode (this, tool), "object");
|
||||||
tool->addButton (
|
tool->addButton (new PathgridMode (this, tool), "pathgrid");
|
||||||
new EditMode (this, QIcon (":placeholder"), Mask_Pathgrid, "Pathgrid editing"),
|
|
||||||
"pathgrid");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CSMDoc::Document& CSVRender::WorldspaceWidget::getDocument()
|
CSMDoc::Document& CSVRender::WorldspaceWidget::getDocument()
|
||||||
|
@ -330,52 +325,80 @@ CSMDoc::Document& CSVRender::WorldspaceWidget::getDocument()
|
||||||
return mDocument;
|
return mDocument;
|
||||||
}
|
}
|
||||||
|
|
||||||
osg::Vec3f CSVRender::WorldspaceWidget::getIntersectionPoint (const QPoint& localPos,
|
CSVRender::WorldspaceHitResult CSVRender::WorldspaceWidget::mousePick (const QPoint& localPos,
|
||||||
unsigned int interactionMask, bool ignoreHidden) const
|
unsigned int interactionMask) const
|
||||||
{
|
{
|
||||||
// (0,0) is considered the lower left corner of an OpenGL window
|
// (0,0) is considered the lower left corner of an OpenGL window
|
||||||
int x = localPos.x();
|
int x = localPos.x();
|
||||||
int y = height() - localPos.y();
|
int y = height() - localPos.y();
|
||||||
|
|
||||||
osg::ref_ptr<osgUtil::LineSegmentIntersector> intersector (
|
// Convert from screen space to world space
|
||||||
new osgUtil::LineSegmentIntersector (osgUtil::Intersector::WINDOW, x, y));
|
osg::Matrixd wpvMat;
|
||||||
|
wpvMat.preMult (mView->getCamera()->getViewport()->computeWindowMatrix());
|
||||||
|
wpvMat.preMult (mView->getCamera()->getProjectionMatrix());
|
||||||
|
wpvMat.preMult (mView->getCamera()->getViewMatrix());
|
||||||
|
wpvMat = osg::Matrixd::inverse (wpvMat);
|
||||||
|
|
||||||
intersector->setIntersectionLimit (osgUtil::LineSegmentIntersector::NO_LIMIT);
|
osg::Vec3d start = wpvMat.preMult (osg::Vec3d(x, y, 0));
|
||||||
osgUtil::IntersectionVisitor visitor (intersector);
|
osg::Vec3d end = wpvMat.preMult (osg::Vec3d(x, y, 1));
|
||||||
|
osg::Vec3d direction = end - start;
|
||||||
|
|
||||||
unsigned int mask = interactionMask;
|
// Get intersection
|
||||||
|
osg::ref_ptr<osgUtil::LineSegmentIntersector> intersector (new osgUtil::LineSegmentIntersector(
|
||||||
|
osgUtil::Intersector::MODEL, start, end));
|
||||||
|
|
||||||
if (ignoreHidden)
|
intersector->setIntersectionLimit(osgUtil::LineSegmentIntersector::NO_LIMIT);
|
||||||
mask &= getVisibilityMask();
|
osgUtil::IntersectionVisitor visitor(intersector);
|
||||||
|
|
||||||
visitor.setTraversalMask (mask);
|
visitor.setTraversalMask(interactionMask);
|
||||||
|
|
||||||
mView->getCamera()->accept (visitor);
|
mView->getCamera()->accept(visitor);
|
||||||
|
|
||||||
for (osgUtil::LineSegmentIntersector::Intersections::iterator iter = intersector->getIntersections().begin();
|
// Get relevant data
|
||||||
iter!=intersector->getIntersections().end(); ++iter)
|
for (osgUtil::LineSegmentIntersector::Intersections::iterator it = intersector->getIntersections().begin();
|
||||||
|
it != intersector->getIntersections().end(); ++it)
|
||||||
{
|
{
|
||||||
// reject back-facing polygons
|
osgUtil::LineSegmentIntersector::Intersection intersection = *it;
|
||||||
osg::Vec3f normal = osg::Matrix::transform3x3 (
|
|
||||||
iter->getWorldIntersectNormal(), mView->getCamera()->getViewMatrix());
|
|
||||||
|
|
||||||
if (normal.z()>=0)
|
// reject back-facing polygons
|
||||||
return iter->getWorldIntersectPoint();
|
if (direction * intersection.getWorldIntersectNormal() > 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (std::vector<osg::Node*>::iterator it = intersection.nodePath.begin(); it != intersection.nodePath.end(); ++it)
|
||||||
|
{
|
||||||
|
osg::Node* node = *it;
|
||||||
|
if (osg::ref_ptr<CSVRender::TagBase> tag = dynamic_cast<CSVRender::TagBase *>(node->getUserData()))
|
||||||
|
{
|
||||||
|
WorldspaceHitResult hit = { true, tag, 0, 0, 0, intersection.getWorldIntersectPoint() };
|
||||||
|
if (intersection.indexList.size() >= 3)
|
||||||
|
{
|
||||||
|
hit.index0 = intersection.indexList[0];
|
||||||
|
hit.index1 = intersection.indexList[1];
|
||||||
|
hit.index2 = intersection.indexList[2];
|
||||||
|
}
|
||||||
|
return hit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Something untagged, probably terrain
|
||||||
|
WorldspaceHitResult hit = { true, 0, 0, 0, 0, intersection.getWorldIntersectPoint() };
|
||||||
|
if (intersection.indexList.size() >= 3)
|
||||||
|
{
|
||||||
|
hit.index0 = intersection.indexList[0];
|
||||||
|
hit.index1 = intersection.indexList[1];
|
||||||
|
hit.index2 = intersection.indexList[2];
|
||||||
|
}
|
||||||
|
return hit;
|
||||||
}
|
}
|
||||||
|
|
||||||
osg::Matrixd matrix;
|
// Default placement
|
||||||
matrix.preMult (mView->getCamera()->getViewport()->computeWindowMatrix());
|
|
||||||
matrix.preMult (mView->getCamera()->getProjectionMatrix());
|
|
||||||
matrix.preMult (mView->getCamera()->getViewMatrix());
|
|
||||||
matrix = osg::Matrixd::inverse (matrix);
|
|
||||||
|
|
||||||
osg::Vec3d start = matrix.preMult (intersector->getStart());
|
|
||||||
osg::Vec3d end = matrix.preMult (intersector->getEnd());
|
|
||||||
|
|
||||||
osg::Vec3d direction = end-start;
|
|
||||||
direction.normalize();
|
direction.normalize();
|
||||||
|
direction *= CSMPrefs::get()["Scene Drops"]["distance"].toInt();
|
||||||
|
|
||||||
return start + direction * CSMPrefs::get()["Scene Drops"]["distance"].toInt();
|
WorldspaceHitResult hit = { false, 0, 0, 0, 0, start + direction };
|
||||||
|
return hit;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSVRender::WorldspaceWidget::abortDrag()
|
void CSVRender::WorldspaceWidget::abortDrag()
|
||||||
|
@ -469,48 +492,6 @@ bool CSVRender::WorldspaceWidget::storeMappingSetting (const CSMPrefs::Setting *
|
||||||
return SceneWidget::storeMappingSetting(setting);
|
return SceneWidget::storeMappingSetting(setting);
|
||||||
}
|
}
|
||||||
|
|
||||||
osg::ref_ptr<CSVRender::TagBase> CSVRender::WorldspaceWidget::mousePick (const QPoint& localPos)
|
|
||||||
{
|
|
||||||
// (0,0) is considered the lower left corner of an OpenGL window
|
|
||||||
int x = localPos.x();
|
|
||||||
int y = height() - localPos.y();
|
|
||||||
|
|
||||||
osg::ref_ptr<osgUtil::LineSegmentIntersector> intersector (new osgUtil::LineSegmentIntersector(osgUtil::Intersector::WINDOW, x, y));
|
|
||||||
|
|
||||||
intersector->setIntersectionLimit(osgUtil::LineSegmentIntersector::NO_LIMIT);
|
|
||||||
osgUtil::IntersectionVisitor visitor(intersector);
|
|
||||||
|
|
||||||
visitor.setTraversalMask(getInteractionMask());
|
|
||||||
|
|
||||||
mView->getCamera()->accept(visitor);
|
|
||||||
|
|
||||||
for (osgUtil::LineSegmentIntersector::Intersections::iterator it = intersector->getIntersections().begin();
|
|
||||||
it != intersector->getIntersections().end(); ++it)
|
|
||||||
{
|
|
||||||
osgUtil::LineSegmentIntersector::Intersection intersection = *it;
|
|
||||||
|
|
||||||
// reject back-facing polygons
|
|
||||||
osg::Vec3f normal = intersection.getWorldIntersectNormal();
|
|
||||||
normal = osg::Matrix::transform3x3(normal, mView->getCamera()->getViewMatrix());
|
|
||||||
if (normal.z() < 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
for (std::vector<osg::Node*>::iterator it = intersection.nodePath.begin(); it != intersection.nodePath.end(); ++it)
|
|
||||||
{
|
|
||||||
osg::Node* node = *it;
|
|
||||||
if (osg::ref_ptr<CSVRender::TagBase> tag = dynamic_cast<CSVRender::TagBase *>(node->getUserData()))
|
|
||||||
return tag;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ignoring terrain for now
|
|
||||||
// must be terrain, report coordinates
|
|
||||||
// std::cout << "Terrain hit at " << intersection.getWorldIntersectPoint().x() << " " << intersection.getWorldIntersectPoint().y() << std::endl;
|
|
||||||
// return;
|
|
||||||
}
|
|
||||||
|
|
||||||
return osg::ref_ptr<CSVRender::TagBase>();
|
|
||||||
}
|
|
||||||
|
|
||||||
void CSVRender::WorldspaceWidget::dropEvent (QDropEvent* event)
|
void CSVRender::WorldspaceWidget::dropEvent (QDropEvent* event)
|
||||||
{
|
{
|
||||||
const CSMWorld::TableMimeData* mime = dynamic_cast<const CSMWorld::TableMimeData*> (event->mimeData());
|
const CSMWorld::TableMimeData* mime = dynamic_cast<const CSMWorld::TableMimeData*> (event->mimeData());
|
||||||
|
@ -595,10 +576,11 @@ void CSVRender::WorldspaceWidget::showToolTip()
|
||||||
{
|
{
|
||||||
QPoint pos = QCursor::pos();
|
QPoint pos = QCursor::pos();
|
||||||
|
|
||||||
if (osg::ref_ptr<TagBase> tag = mousePick (mapFromGlobal (pos)))
|
WorldspaceHitResult hit = mousePick (mapFromGlobal (pos), getInteractionMask());
|
||||||
|
if (hit.tag)
|
||||||
{
|
{
|
||||||
bool hideBasics = CSMPrefs::get()["Tooltips"]["scene-hide-basic"].isTrue();
|
bool hideBasics = CSMPrefs::get()["Tooltips"]["scene-hide-basic"].isTrue();
|
||||||
QToolTip::showText (pos, tag->getToolTip (hideBasics), this);
|
QToolTip::showText (pos, hit.tag->getToolTip (hideBasics), this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -631,22 +613,20 @@ void CSVRender::WorldspaceWidget::mouseMoveEvent (QMouseEvent *event)
|
||||||
|
|
||||||
EditMode& editMode = dynamic_cast<CSVRender::EditMode&> (*mEditMode->getCurrent());
|
EditMode& editMode = dynamic_cast<CSVRender::EditMode&> (*mEditMode->getCurrent());
|
||||||
|
|
||||||
editMode.drag (diffX, diffY, factor);
|
editMode.drag (event->pos(), diffX, diffY, factor);
|
||||||
}
|
}
|
||||||
else if (mDragMode=="p-edit" || mDragMode=="s-edit" || mDragMode=="p-select" || mDragMode=="s-select")
|
else if (mDragMode=="p-edit" || mDragMode=="s-edit" || mDragMode=="p-select" || mDragMode=="s-select")
|
||||||
{
|
{
|
||||||
osg::ref_ptr<TagBase> tag = mousePick (event->pos());
|
|
||||||
|
|
||||||
EditMode& editMode = dynamic_cast<CSVRender::EditMode&> (*mEditMode->getCurrent());
|
EditMode& editMode = dynamic_cast<CSVRender::EditMode&> (*mEditMode->getCurrent());
|
||||||
|
|
||||||
if (mDragMode=="p-edit")
|
if (mDragMode=="p-edit")
|
||||||
mDragging = editMode.primaryEditStartDrag (tag);
|
mDragging = editMode.primaryEditStartDrag (event->pos());
|
||||||
else if (mDragMode=="s-edit")
|
else if (mDragMode=="s-edit")
|
||||||
mDragging = editMode.secondaryEditStartDrag (tag);
|
mDragging = editMode.secondaryEditStartDrag (event->pos());
|
||||||
else if (mDragMode=="p-select")
|
else if (mDragMode=="p-select")
|
||||||
mDragging = editMode.primarySelectStartDrag (tag);
|
mDragging = editMode.primarySelectStartDrag (event->pos());
|
||||||
else if (mDragMode=="s-select")
|
else if (mDragMode=="s-select")
|
||||||
mDragging = editMode.secondarySelectStartDrag (tag);
|
mDragging = editMode.secondarySelectStartDrag (event->pos());
|
||||||
|
|
||||||
if (mDragging)
|
if (mDragging)
|
||||||
{
|
{
|
||||||
|
@ -699,14 +679,14 @@ void CSVRender::WorldspaceWidget::mouseReleaseEvent (QMouseEvent *event)
|
||||||
{
|
{
|
||||||
EditMode& editMode = dynamic_cast<CSVRender::EditMode&> (*mEditMode->getCurrent());
|
EditMode& editMode = dynamic_cast<CSVRender::EditMode&> (*mEditMode->getCurrent());
|
||||||
|
|
||||||
editMode.dragCompleted();
|
editMode.dragCompleted(event->pos());
|
||||||
mDragging = false;
|
mDragging = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
osg::ref_ptr<TagBase> tag = mousePick (event->pos());
|
WorldspaceHitResult hit = mousePick(event->pos(), getInteractionMask());
|
||||||
|
|
||||||
handleMouseClick (tag, button, event->modifiers() & Qt::ShiftModifier);
|
handleMouseClick (hit, button, event->modifiers() & Qt::ShiftModifier);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -740,18 +720,18 @@ void CSVRender::WorldspaceWidget::keyPressEvent (QKeyEvent *event)
|
||||||
SceneWidget::keyPressEvent(event);
|
SceneWidget::keyPressEvent(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSVRender::WorldspaceWidget::handleMouseClick (osg::ref_ptr<TagBase> tag, const std::string& button, bool shift)
|
void CSVRender::WorldspaceWidget::handleMouseClick (const WorldspaceHitResult& hit, const std::string& button, bool shift)
|
||||||
{
|
{
|
||||||
EditMode& editMode = dynamic_cast<CSVRender::EditMode&> (*mEditMode->getCurrent());
|
EditMode& editMode = dynamic_cast<CSVRender::EditMode&> (*mEditMode->getCurrent());
|
||||||
|
|
||||||
if (button=="p-edit")
|
if (button=="p-edit")
|
||||||
editMode.primaryEditPressed (tag);
|
editMode.primaryEditPressed (hit);
|
||||||
else if (button=="s-edit")
|
else if (button=="s-edit")
|
||||||
editMode.secondaryEditPressed (tag);
|
editMode.secondaryEditPressed (hit);
|
||||||
else if (button=="p-select")
|
else if (button=="p-select")
|
||||||
editMode.primarySelectPressed (tag);
|
editMode.primarySelectPressed (hit);
|
||||||
else if (button=="s-select")
|
else if (button=="s-select")
|
||||||
editMode.secondarySelectPressed (tag);
|
editMode.secondarySelectPressed (hit);
|
||||||
}
|
}
|
||||||
|
|
||||||
CSVRender::EditMode *CSVRender::WorldspaceWidget::getEditMode()
|
CSVRender::EditMode *CSVRender::WorldspaceWidget::getEditMode()
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include <boost/shared_ptr.hpp>
|
#include <boost/shared_ptr.hpp>
|
||||||
|
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
#include <osg/Vec3>
|
||||||
|
|
||||||
#include "../../model/doc/document.hpp"
|
#include "../../model/doc/document.hpp"
|
||||||
#include "../../model/world/tablemimedata.hpp"
|
#include "../../model/world/tablemimedata.hpp"
|
||||||
|
@ -32,9 +33,18 @@ namespace CSVWidget
|
||||||
namespace CSVRender
|
namespace CSVRender
|
||||||
{
|
{
|
||||||
class TagBase;
|
class TagBase;
|
||||||
|
class Cell;
|
||||||
class CellArrow;
|
class CellArrow;
|
||||||
class EditMode;
|
class EditMode;
|
||||||
|
|
||||||
|
struct WorldspaceHitResult
|
||||||
|
{
|
||||||
|
bool hit;
|
||||||
|
osg::ref_ptr<TagBase> tag;
|
||||||
|
unsigned int index0, index1, index2; // indices of mesh vertices
|
||||||
|
osg::Vec3d worldPos;
|
||||||
|
};
|
||||||
|
|
||||||
class WorldspaceWidget : public SceneWidget
|
class WorldspaceWidget : public SceneWidget
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -127,6 +137,9 @@ namespace CSVRender
|
||||||
/// \param elementMask Elements to be affected by the clear operation
|
/// \param elementMask Elements to be affected by the clear operation
|
||||||
virtual void clearSelection (int elementMask) = 0;
|
virtual void clearSelection (int elementMask) = 0;
|
||||||
|
|
||||||
|
/// \param elementMask Elements to be affected by the select operation
|
||||||
|
virtual void invertSelection (int elementMask) = 0;
|
||||||
|
|
||||||
/// \param elementMask Elements to be affected by the select operation
|
/// \param elementMask Elements to be affected by the select operation
|
||||||
virtual void selectAll (int elementMask) = 0;
|
virtual void selectAll (int elementMask) = 0;
|
||||||
|
|
||||||
|
@ -136,19 +149,17 @@ namespace CSVRender
|
||||||
/// \param elementMask Elements to be affected by the select operation
|
/// \param elementMask Elements to be affected by the select operation
|
||||||
virtual void selectAllWithSameParentId (int elementMask) = 0;
|
virtual void selectAllWithSameParentId (int elementMask) = 0;
|
||||||
|
|
||||||
/// Return the next intersection point with scene elements matched by
|
/// Return the next intersection with scene elements matched by
|
||||||
/// \a interactionMask based on \a localPos and the camera vector.
|
/// \a interactionMask based on \a localPos and the camera vector.
|
||||||
/// If there is no such point, instead a point "in front" of \a localPos will be
|
/// If there is no such intersection, instead a point "in front" of \a localPos will be
|
||||||
/// returned.
|
/// returned.
|
||||||
///
|
WorldspaceHitResult mousePick (const QPoint& localPos, unsigned int interactionMask) const;
|
||||||
/// \param ignoreHidden ignore elements specified in interactionMask that are
|
|
||||||
/// flagged as not visible.
|
|
||||||
osg::Vec3f getIntersectionPoint (const QPoint& localPos,
|
|
||||||
unsigned int interactionMask = Mask_Reference | Mask_Terrain,
|
|
||||||
bool ignoreHidden = false) const;
|
|
||||||
|
|
||||||
virtual std::string getCellId (const osg::Vec3f& point) const = 0;
|
virtual std::string getCellId (const osg::Vec3f& point) const = 0;
|
||||||
|
|
||||||
|
/// \note Returns the cell if it exists, otherwise a null pointer
|
||||||
|
virtual Cell* getCell(const osg::Vec3d& point) const = 0;
|
||||||
|
|
||||||
virtual std::vector<osg::ref_ptr<TagBase> > getSelection (unsigned int elementMask)
|
virtual std::vector<osg::ref_ptr<TagBase> > getSelection (unsigned int elementMask)
|
||||||
const = 0;
|
const = 0;
|
||||||
|
|
||||||
|
@ -191,7 +202,7 @@ namespace CSVRender
|
||||||
virtual void wheelEvent (QWheelEvent *event);
|
virtual void wheelEvent (QWheelEvent *event);
|
||||||
virtual void keyPressEvent (QKeyEvent *event);
|
virtual void keyPressEvent (QKeyEvent *event);
|
||||||
|
|
||||||
virtual void handleMouseClick (osg::ref_ptr<TagBase> tag, const std::string& button,
|
virtual void handleMouseClick (const WorldspaceHitResult& hit, const std::string& button,
|
||||||
bool shift);
|
bool shift);
|
||||||
|
|
||||||
/// \return Is \a key a button mapping setting? (ignored otherwise)
|
/// \return Is \a key a button mapping setting? (ignored otherwise)
|
||||||
|
@ -209,8 +220,6 @@ namespace CSVRender
|
||||||
|
|
||||||
void dragMoveEvent(QDragMoveEvent *event);
|
void dragMoveEvent(QDragMoveEvent *event);
|
||||||
|
|
||||||
osg::ref_ptr<TagBase> mousePick (const QPoint& localPos);
|
|
||||||
|
|
||||||
virtual std::string getStartupInstruction() = 0;
|
virtual std::string getStartupInstruction() = 0;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
@ -230,8 +239,6 @@ namespace CSVRender
|
||||||
|
|
||||||
virtual void pathgridDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) = 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 pathgridAboutToBeRemoved (const QModelIndex& parent, int start, int end) = 0;
|
||||||
|
|
||||||
virtual void pathgridAdded (const QModelIndex& parent, int start, int end) = 0;
|
virtual void pathgridAdded (const QModelIndex& parent, int start, int end) = 0;
|
||||||
|
|
|
@ -119,9 +119,14 @@ void CSVWorld::NestedTable::removeRowActionTriggered()
|
||||||
|
|
||||||
void CSVWorld::NestedTable::addNewRowActionTriggered()
|
void CSVWorld::NestedTable::addNewRowActionTriggered()
|
||||||
{
|
{
|
||||||
|
int row = 0;
|
||||||
|
|
||||||
|
if (!selectionModel()->selectedRows().empty())
|
||||||
|
row = selectionModel()->selectedRows().back().row() + 1;
|
||||||
|
|
||||||
mDocument.getUndoStack().push(new CSMWorld::AddNestedCommand(*(mModel->model()),
|
mDocument.getUndoStack().push(new CSMWorld::AddNestedCommand(*(mModel->model()),
|
||||||
mModel->getParentId(),
|
mModel->getParentId(),
|
||||||
selectionModel()->selectedRows().size(),
|
row,
|
||||||
mModel->getParentColumn()));
|
mModel->getParentColumn()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -127,6 +127,28 @@ namespace ESM
|
||||||
|
|
||||||
void Pathgrid::save(ESMWriter &esm, bool isDeleted) const
|
void Pathgrid::save(ESMWriter &esm, bool isDeleted) const
|
||||||
{
|
{
|
||||||
|
// Correct connection count and sort edges by point
|
||||||
|
// Can probably be optimized
|
||||||
|
PointList correctedPoints = mPoints;
|
||||||
|
std::vector<int> sortedEdges;
|
||||||
|
|
||||||
|
sortedEdges.reserve(mEdges.size());
|
||||||
|
|
||||||
|
for (size_t point = 0; point < correctedPoints.size(); ++point)
|
||||||
|
{
|
||||||
|
correctedPoints[point].mConnectionNum = 0;
|
||||||
|
|
||||||
|
for (EdgeList::const_iterator it = mEdges.begin(); it != mEdges.end(); ++it)
|
||||||
|
{
|
||||||
|
if (static_cast<size_t>(it->mV0) == point)
|
||||||
|
{
|
||||||
|
sortedEdges.push_back(it->mV1);
|
||||||
|
++correctedPoints[point].mConnectionNum;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save
|
||||||
esm.writeHNCString("NAME", mCell);
|
esm.writeHNCString("NAME", mCell);
|
||||||
esm.writeHNT("DATA", mData, 12);
|
esm.writeHNT("DATA", mData, 12);
|
||||||
|
|
||||||
|
@ -136,22 +158,22 @@ namespace ESM
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mPoints.empty())
|
if (!correctedPoints.empty())
|
||||||
{
|
{
|
||||||
esm.startSubRecord("PGRP");
|
esm.startSubRecord("PGRP");
|
||||||
for (PointList::const_iterator it = mPoints.begin(); it != mPoints.end(); ++it)
|
for (PointList::const_iterator it = correctedPoints.begin(); it != correctedPoints.end(); ++it)
|
||||||
{
|
{
|
||||||
esm.writeT(*it);
|
esm.writeT(*it);
|
||||||
}
|
}
|
||||||
esm.endRecord("PGRP");
|
esm.endRecord("PGRP");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mEdges.empty())
|
if (!sortedEdges.empty())
|
||||||
{
|
{
|
||||||
esm.startSubRecord("PGRC");
|
esm.startSubRecord("PGRC");
|
||||||
for (std::vector<Edge>::const_iterator it = mEdges.begin(); it != mEdges.end(); ++it)
|
for (std::vector<int>::const_iterator it = sortedEdges.begin(); it != sortedEdges.end(); ++it)
|
||||||
{
|
{
|
||||||
esm.writeT(it->mV1);
|
esm.writeT(*it);
|
||||||
}
|
}
|
||||||
esm.endRecord("PGRC");
|
esm.endRecord("PGRC");
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,13 +9,13 @@ namespace SceneUtil
|
||||||
{
|
{
|
||||||
const unsigned short DiamondVertexCount = 6;
|
const unsigned short DiamondVertexCount = 6;
|
||||||
const unsigned short DiamondIndexCount = 24;
|
const unsigned short DiamondIndexCount = 24;
|
||||||
|
const unsigned short DiamondWireframeIndexCount = 24;
|
||||||
|
|
||||||
const unsigned short DiamondConnectorVertexCount = 4;
|
const unsigned short DiamondConnectorVertexCount = 4;
|
||||||
|
|
||||||
const unsigned short DiamondTotalVertexCount = DiamondVertexCount + DiamondConnectorVertexCount;
|
const unsigned short DiamondTotalVertexCount = DiamondVertexCount + DiamondConnectorVertexCount;
|
||||||
|
|
||||||
const float DiamondHalfHeight = 40.f;
|
const float DiamondWireframeScalar = 1.1f;
|
||||||
const float DiamondHalfWidth = 16.f;
|
|
||||||
|
|
||||||
const osg::Vec3f DiamondPoints[DiamondVertexCount] =
|
const osg::Vec3f DiamondPoints[DiamondVertexCount] =
|
||||||
{
|
{
|
||||||
|
@ -39,6 +39,22 @@ namespace SceneUtil
|
||||||
5, 2, 4
|
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] =
|
const unsigned short DiamondConnectorVertices[DiamondConnectorVertexCount] =
|
||||||
{
|
{
|
||||||
1, 2, 3, 4
|
1, 2, 3, 4
|
||||||
|
@ -55,6 +71,8 @@ namespace SceneUtil
|
||||||
};
|
};
|
||||||
|
|
||||||
const osg::Vec4f DiamondEdgeColor = osg::Vec4f(0.5f, 1.f, 1.f, 1.f);
|
const osg::Vec4f DiamondEdgeColor = osg::Vec4f(0.5f, 1.f, 1.f, 1.f);
|
||||||
|
const osg::Vec4f DiamondWireColor = osg::Vec4f(0.72f, 0.f, 0.96f, 1.f);
|
||||||
|
const osg::Vec4f DiamondFocusWireColor = osg::Vec4f(0.91f, 0.66f, 1.f, 1.f);
|
||||||
|
|
||||||
osg::ref_ptr<osg::Geometry> createPathgridGeometry(const ESM::Pathgrid& pathgrid)
|
osg::ref_ptr<osg::Geometry> createPathgridGeometry(const ESM::Pathgrid& pathgrid)
|
||||||
{
|
{
|
||||||
|
@ -155,4 +173,61 @@ namespace SceneUtil
|
||||||
|
|
||||||
return gridGeometry;
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,15 @@ namespace ESM
|
||||||
|
|
||||||
namespace SceneUtil
|
namespace SceneUtil
|
||||||
{
|
{
|
||||||
|
const float DiamondHalfHeight = 40.f;
|
||||||
|
const float DiamondHalfWidth = 16.f;
|
||||||
|
|
||||||
osg::ref_ptr<osg::Geometry> createPathgridGeometry(const ESM::Pathgrid& pathgrid);
|
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
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue