Initial pathgrid editting, support for selection and movement.
parent
9645d0cc8a
commit
32ba5bf8b8
@ -0,0 +1,287 @@
|
||||
#include "pathgrid.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <osg/Geode>
|
||||
#include <osg/Geometry>
|
||||
#include <osg/Group>
|
||||
#include <osg/PositionAttitudeTransform>
|
||||
#include <osg/Vec3>
|
||||
|
||||
#include <components/sceneutil/pathgridutil.hpp>
|
||||
|
||||
#include "../../model/world/commands.hpp"
|
||||
#include "../../model/world/commandmacro.hpp"
|
||||
#include "../../model/world/data.hpp"
|
||||
|
||||
namespace CSVRender
|
||||
{
|
||||
PathgridTag::PathgridTag(Pathgrid* pathgrid)
|
||||
: TagBase(Mask_Pathgrid), mPathgrid(pathgrid)
|
||||
{
|
||||
}
|
||||
|
||||
Pathgrid* PathgridTag::getPathgrid() const
|
||||
{
|
||||
return mPathgrid;
|
||||
}
|
||||
|
||||
QString PathgridTag::getToolTip(bool hideBasics) const
|
||||
{
|
||||
QString text("Pathgrid: ");
|
||||
text += mPathgrid->getId().c_str();
|
||||
|
||||
if (!hideBasics)
|
||||
{
|
||||
text += "<p>Only one pathgrid may be edited at a time.";
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
Pathgrid::Pathgrid(CSMWorld::Data& data, osg::Group* parent, const std::string& pathgridId,
|
||||
const CSMWorld::CellCoordinates& coordinates)
|
||||
: mData(data)
|
||||
, mId(pathgridId)
|
||||
, mCoords(coordinates)
|
||||
, mParent(parent)
|
||||
, mPathgridGeometry(0)
|
||||
, mSelectedGeometry(0)
|
||||
, mTag(new PathgridTag(this))
|
||||
{
|
||||
const float CoordScalar = ESM::Land::REAL_SIZE;
|
||||
|
||||
mBaseNode = new osg::PositionAttitudeTransform ();
|
||||
mBaseNode->setPosition(osg::Vec3f(mCoords.getX() * CoordScalar, mCoords.getY() * CoordScalar, 0.f));
|
||||
mBaseNode->setUserData(mTag);
|
||||
mBaseNode->setNodeMask(Mask_Pathgrid);
|
||||
mParent->addChild(mBaseNode);
|
||||
|
||||
mSelectedNode = new osg::PositionAttitudeTransform();
|
||||
mBaseNode->addChild(mSelectedNode);
|
||||
|
||||
mPathgridGeode = new osg::Geode();
|
||||
mBaseNode->addChild(mPathgridGeode);
|
||||
|
||||
mSelectedGeode = new osg::Geode();
|
||||
mSelectedNode->addChild(mSelectedGeode);
|
||||
|
||||
recreateGeometry();
|
||||
}
|
||||
|
||||
Pathgrid::~Pathgrid()
|
||||
{
|
||||
mParent->removeChild(mBaseNode);
|
||||
}
|
||||
|
||||
const CSMWorld::CellCoordinates& Pathgrid::getCoordinates() const
|
||||
{
|
||||
return mCoords;
|
||||
}
|
||||
|
||||
const std::string& Pathgrid::getId() const
|
||||
{
|
||||
return mId;
|
||||
}
|
||||
|
||||
bool Pathgrid::isSelected() const
|
||||
{
|
||||
return !mSelected.empty();
|
||||
}
|
||||
|
||||
const Pathgrid::NodeList& Pathgrid::getSelected() const
|
||||
{
|
||||
return mSelected;
|
||||
}
|
||||
|
||||
void Pathgrid::selectAll()
|
||||
{
|
||||
mSelected.clear();
|
||||
|
||||
const CSMWorld::SubCellCollection<CSMWorld::Pathgrid>& pathgrids = mData.getPathgrids();
|
||||
int pathgridIndex = pathgrids.searchId(mId);
|
||||
if (pathgridIndex != -1)
|
||||
{
|
||||
const CSMWorld::Pathgrid& source = pathgrids.getRecord(pathgridIndex).get();
|
||||
for (unsigned short i = 0; i < static_cast<unsigned short>(source.mPoints.size()); ++i)
|
||||
mSelected.push_back(i);
|
||||
|
||||
recreateSelectedGeometry(source);
|
||||
}
|
||||
else
|
||||
{
|
||||
removeSelectedGeometry();
|
||||
}
|
||||
}
|
||||
|
||||
void Pathgrid::toggleSelected(unsigned short node)
|
||||
{
|
||||
NodeList::iterator searchResult = std::find(mSelected.begin(), mSelected.end(), node);
|
||||
if (searchResult != mSelected.end())
|
||||
{
|
||||
mSelected.erase(searchResult);
|
||||
}
|
||||
else
|
||||
{
|
||||
mSelected.push_back(node);
|
||||
}
|
||||
|
||||
recreateSelectedGeometry();
|
||||
}
|
||||
|
||||
void Pathgrid::invertSelected()
|
||||
{
|
||||
NodeList temp = NodeList(mSelected.begin(), mSelected.end());
|
||||
mSelected.clear();
|
||||
|
||||
const CSMWorld::SubCellCollection<CSMWorld::Pathgrid>& pathgrids = mData.getPathgrids();
|
||||
int pathgridIndex = pathgrids.searchId(mId);
|
||||
if (pathgridIndex != -1)
|
||||
{
|
||||
const CSMWorld::Pathgrid& source = pathgrids.getRecord(pathgridIndex).get();
|
||||
for (unsigned short i = 0; i < static_cast<unsigned short>(source.mPoints.size()); ++i)
|
||||
{
|
||||
if (std::find(temp.begin(), temp.end(), i) == temp.end())
|
||||
mSelected.push_back(i);
|
||||
}
|
||||
|
||||
recreateSelectedGeometry(source);
|
||||
}
|
||||
else
|
||||
{
|
||||
removeSelectedGeometry();
|
||||
}
|
||||
}
|
||||
|
||||
void Pathgrid::clearSelected()
|
||||
{
|
||||
mSelected.clear();
|
||||
removeSelectedGeometry();
|
||||
}
|
||||
|
||||
void Pathgrid::moveSelected(const osg::Vec3d& offset)
|
||||
{
|
||||
mSelectedNode->setPosition(mSelectedNode->getPosition() + offset);
|
||||
}
|
||||
|
||||
void Pathgrid::resetMove()
|
||||
{
|
||||
mSelectedNode->setPosition(osg::Vec3f(0,0,0));
|
||||
}
|
||||
|
||||
void Pathgrid::applyPosition(CSMWorld::CommandMacro& commands)
|
||||
{
|
||||
const CSMWorld::SubCellCollection<CSMWorld::Pathgrid>& pathgrids = mData.getPathgrids();
|
||||
int pathgridIndex = pathgrids.searchId(mId);
|
||||
if (pathgridIndex != -1)
|
||||
{
|
||||
const CSMWorld::Pathgrid& source = pathgrids.getRecord(pathgridIndex).get();
|
||||
osg::Vec3d localCoords = mSelectedNode->getPosition();
|
||||
|
||||
int oX = static_cast<int>(localCoords.x());
|
||||
int oY = static_cast<int>(localCoords.y());
|
||||
int oZ = static_cast<int>(localCoords.z());
|
||||
|
||||
CSMWorld::SubCellCollection<CSMWorld::Pathgrid>& collection = mData.getPathgrids();
|
||||
QAbstractItemModel* model = mData.getTableModel (CSMWorld::UniversalId::Type_Pathgrids);
|
||||
|
||||
int recordIndex = collection.getIndex (mId);
|
||||
int parentColumn = collection.findColumnIndex(CSMWorld::Columns::ColumnId_PathgridPoints);
|
||||
|
||||
QModelIndex parent = model->index(recordIndex, parentColumn);
|
||||
|
||||
for (size_t i = 0; i < mSelected.size(); ++i)
|
||||
{
|
||||
const CSMWorld::Pathgrid::Point& point = source.mPoints[mSelected[i]];
|
||||
int row = mSelected[i];
|
||||
|
||||
// X
|
||||
int column = collection.searchNestedColumnIndex(parentColumn, CSMWorld::Columns::ColumnId_PathgridPosX);
|
||||
commands.push (new CSMWorld::ModifyCommand(*model, model->index(row, column, parent), point.mX + oX));
|
||||
|
||||
// Y
|
||||
column = collection.searchNestedColumnIndex(parentColumn, CSMWorld::Columns::ColumnId_PathgridPosY);
|
||||
commands.push (new CSMWorld::ModifyCommand(*model, model->index(row, column, parent), point.mY + oY));
|
||||
|
||||
// Z
|
||||
column = collection.searchNestedColumnIndex(parentColumn, CSMWorld::Columns::ColumnId_PathgridPosZ);
|
||||
commands.push (new CSMWorld::ModifyCommand(*model, model->index(row, column, parent), point.mZ + oZ));
|
||||
}
|
||||
}
|
||||
|
||||
resetMove();
|
||||
}
|
||||
|
||||
void Pathgrid::applyEdge(CSMWorld::CommandMacro& commands, unsigned short node1, unsigned short node2)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
void Pathgrid::applyEdges(CSMWorld::CommandMacro& commands, unsigned short node)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
osg::ref_ptr<PathgridTag> Pathgrid::getTag() const
|
||||
{
|
||||
return mTag;
|
||||
}
|
||||
|
||||
void Pathgrid::recreateGeometry()
|
||||
{
|
||||
removePathgridGeometry();
|
||||
removeSelectedGeometry();
|
||||
|
||||
// Make new
|
||||
const CSMWorld::SubCellCollection<CSMWorld::Pathgrid>& pathgrids = mData.getPathgrids();
|
||||
int pathgridIndex = pathgrids.searchId(mId);
|
||||
if (pathgridIndex != -1)
|
||||
{
|
||||
const CSMWorld::Pathgrid& source = pathgrids.getRecord(pathgridIndex).get();
|
||||
mPathgridGeometry = SceneUtil::createPathgridGeometry(source);
|
||||
mPathgridGeode->addDrawable(mPathgridGeometry);
|
||||
|
||||
recreateSelectedGeometry(source);
|
||||
}
|
||||
}
|
||||
|
||||
void Pathgrid::recreateSelectedGeometry()
|
||||
{
|
||||
const CSMWorld::SubCellCollection<CSMWorld::Pathgrid>& pathgrids = mData.getPathgrids();
|
||||
int pathgridIndex = pathgrids.searchId(mId);
|
||||
if (pathgridIndex != -1)
|
||||
{
|
||||
const CSMWorld::Pathgrid& source = pathgrids.getRecord(pathgridIndex).get();
|
||||
recreateSelectedGeometry(source);
|
||||
}
|
||||
else
|
||||
{
|
||||
removeSelectedGeometry();
|
||||
}
|
||||
}
|
||||
|
||||
void Pathgrid::recreateSelectedGeometry(const CSMWorld::Pathgrid& source)
|
||||
{
|
||||
removeSelectedGeometry();
|
||||
mSelectedGeometry = SceneUtil::createPathgridSelectedWireframe(source, mSelected);
|
||||
mSelectedGeode->addDrawable(mSelectedGeometry);
|
||||
}
|
||||
|
||||
void Pathgrid::removePathgridGeometry()
|
||||
{
|
||||
if (mPathgridGeometry)
|
||||
{
|
||||
mPathgridGeode->removeDrawable(mPathgridGeometry);
|
||||
mPathgridGeometry.release();
|
||||
}
|
||||
}
|
||||
|
||||
void Pathgrid::removeSelectedGeometry()
|
||||
{
|
||||
if (mSelectedGeometry)
|
||||
{
|
||||
mSelectedGeode->removeDrawable(mSelectedGeometry);
|
||||
mSelectedGeometry.release();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,105 @@
|
||||
#ifndef CSV_RENDER_PATHGRID_H
|
||||
#define CSV_RENDER_PATHGRID_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <QString>
|
||||
#include <osg/ref_ptr>
|
||||
|
||||
#include "../../model/world/cellcoordinates.hpp"
|
||||
|
||||
#include "tagbase.hpp"
|
||||
|
||||
namespace osg
|
||||
{
|
||||
class Geode;
|
||||
class Geometry;
|
||||
class Group;
|
||||
class PositionAttitudeTransform;
|
||||
class Vec3d;
|
||||
}
|
||||
|
||||
namespace CSMWorld
|
||||
{
|
||||
class CommandMacro;
|
||||
class Data;
|
||||
class Pathgrid;
|
||||
}
|
||||
|
||||
namespace CSVRender
|
||||
{
|
||||
class Pathgrid;
|
||||
|
||||
class PathgridTag : public TagBase
|
||||
{
|
||||
public:
|
||||
|
||||
PathgridTag (Pathgrid* pathgrid);
|
||||
|
||||
Pathgrid* getPathgrid () const;
|
||||
|
||||
virtual QString getToolTip (bool hideBasics) const;
|
||||
|
||||
private:
|
||||
|
||||
Pathgrid* mPathgrid;
|
||||
};
|
||||
|
||||
class Pathgrid
|
||||
{
|
||||
public:
|
||||
|
||||
typedef std::vector<unsigned short> NodeList;
|
||||
|
||||
Pathgrid(CSMWorld::Data& data, osg::Group* parent, const std::string& pathgridId,
|
||||
const CSMWorld::CellCoordinates& coordinates);
|
||||
|
||||
~Pathgrid();
|
||||
|
||||
const CSMWorld::CellCoordinates& getCoordinates() const;
|
||||
const std::string& getId() const;
|
||||
|
||||
bool isSelected() const;
|
||||
const NodeList& getSelected() const;
|
||||
void selectAll();
|
||||
void toggleSelected(unsigned short node); // Adds to end of vector
|
||||
void invertSelected();
|
||||
void clearSelected();
|
||||
|
||||
void moveSelected(const osg::Vec3d& offset);
|
||||
void resetMove();
|
||||
|
||||
void applyPosition(CSMWorld::CommandMacro& commands);
|
||||
void applyEdge(CSMWorld::CommandMacro& commands, unsigned short node1, unsigned short node2);
|
||||
void applyEdges(CSMWorld::CommandMacro& commands, unsigned short node);
|
||||
|
||||
osg::ref_ptr<PathgridTag> getTag() const;
|
||||
|
||||
void recreateGeometry();
|
||||
|
||||
private:
|
||||
|
||||
CSMWorld::Data& mData;
|
||||
std::string mId;
|
||||
CSMWorld::CellCoordinates mCoords;
|
||||
|
||||
NodeList mSelected;
|
||||
|
||||
osg::Group* mParent;
|
||||
osg::ref_ptr<osg::PositionAttitudeTransform> mBaseNode;
|
||||
osg::ref_ptr<osg::PositionAttitudeTransform> mSelectedNode;
|
||||
osg::ref_ptr<osg::Geode> mPathgridGeode;
|
||||
osg::ref_ptr<osg::Geode> mSelectedGeode;
|
||||
osg::ref_ptr<osg::Geometry> mPathgridGeometry;
|
||||
osg::ref_ptr<osg::Geometry> mSelectedGeometry;
|
||||
|
||||
osg::ref_ptr<PathgridTag> mTag;
|
||||
|
||||
void recreateSelectedGeometry();
|
||||
void recreateSelectedGeometry(const CSMWorld::Pathgrid& source);
|
||||
void removePathgridGeometry();
|
||||
void removeSelectedGeometry();
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,152 @@
|
||||
#include "pathgridmode.hpp"
|
||||
|
||||
#include <components/sceneutil/pathgridutil.hpp>
|
||||
|
||||
#include "../../model/world/commands.hpp"
|
||||
#include "../../model/world/commandmacro.hpp"
|
||||
#include "../../model/world/idtable.hpp"
|
||||
#include "../../model/world/idtree.hpp"
|
||||
|
||||
#include "mask.hpp"
|
||||
#include "pathgrid.hpp"
|
||||
#include "worldspacewidget.hpp"
|
||||
|
||||
namespace CSVRender
|
||||
{
|
||||
PathgridMode::PathgridMode(WorldspaceWidget* worldspaceWidget, QWidget* parent)
|
||||
: EditMode(worldspaceWidget, QIcon(":placeholder"), Mask_Pathgrid, "Pathgrid editing", parent)
|
||||
, mDragMode(DragMode_None)
|
||||
, mFromNode(0)
|
||||
{
|
||||
}
|
||||
|
||||
void PathgridMode::primaryEditPressed(const WorldspaceHitResult& hit)
|
||||
{
|
||||
}
|
||||
|
||||
void PathgridMode::secondaryEditPressed(const WorldspaceHitResult& hit)
|
||||
{
|
||||
}
|
||||
|
||||
void PathgridMode::primarySelectPressed(const WorldspaceHitResult& hit)
|
||||
{
|
||||
getWorldspaceWidget().clearSelection(Mask_Pathgrid);
|
||||
|
||||
if (hit.tag)
|
||||
{
|
||||
if (PathgridTag* tag = dynamic_cast<PathgridTag*>(hit.tag.get()))
|
||||
{
|
||||
unsigned short node = SceneUtil::getPathgridNode(static_cast<unsigned short>(hit.i0));
|
||||
tag->getPathgrid()->toggleSelected(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PathgridMode::secondarySelectPressed(const WorldspaceHitResult& hit)
|
||||
{
|
||||
if (hit.tag)
|
||||
{
|
||||
if (PathgridTag* tag = dynamic_cast<PathgridTag*>(hit.tag.get()))
|
||||
{
|
||||
if (tag->getPathgrid()->getId() != mLastId)
|
||||
{
|
||||
getWorldspaceWidget().clearSelection(Mask_Pathgrid);
|
||||
mLastId = tag->getPathgrid()->getId();
|
||||
}
|
||||
|
||||
unsigned short node = SceneUtil::getPathgridNode(static_cast<unsigned short>(hit.i0));
|
||||
tag->getPathgrid()->toggleSelected(node);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
getWorldspaceWidget().clearSelection(Mask_Pathgrid);
|
||||
}
|
||||
|
||||
bool PathgridMode::primaryEditStartDrag(const WorldspaceHitResult& hit)
|
||||
{
|
||||
std::vector<osg::ref_ptr<TagBase> > selection = getWorldspaceWidget().getSelection (Mask_Pathgrid);
|
||||
|
||||
if (!selection.empty())
|
||||
{
|
||||
mDragMode = DragMode_Move;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool PathgridMode::secondaryEditStartDrag(const WorldspaceHitResult& hit)
|
||||
{
|
||||
if (hit.tag)
|
||||
{
|
||||
if (PathgridTag* tag = dynamic_cast<PathgridTag*>(hit.tag.get()))
|
||||
{
|
||||
mDragMode = DragMode_Edge;
|
||||
mFromNode = SceneUtil::getPathgridNode(static_cast<unsigned short>(hit.i0));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void PathgridMode::drag(int diffX, int diffY, double speedFactor)
|
||||
{
|
||||
std::vector<osg::ref_ptr<TagBase> > selection = getWorldspaceWidget().getSelection (Mask_Pathgrid);
|
||||
|
||||
for (std::vector<osg::ref_ptr<TagBase> >::iterator it = selection.begin(); it != selection.end(); ++it)
|
||||
{
|
||||
if (PathgridTag* tag = dynamic_cast<PathgridTag*>(it->get()))
|
||||
{
|
||||
if (mDragMode == DragMode_Move)
|
||||
{
|
||||
osg::Vec3d eye, center, up, offset;
|
||||
getWorldspaceWidget().getCamera()->getViewMatrix().getLookAt (eye, center, up);
|
||||
|
||||
offset = (up * diffY * speedFactor) + (((center - eye) ^ up) * diffX * speedFactor);
|
||||
|
||||
tag->getPathgrid()->moveSelected(offset);
|
||||
}
|
||||
else if (mDragMode == DragMode_Edge)
|
||||
{
|
||||
// TODO make indicators
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PathgridMode::dragCompleted()
|
||||
{
|
||||
std::vector<osg::ref_ptr<TagBase> > selection = getWorldspaceWidget().getSelection (Mask_Pathgrid);
|
||||
|
||||
for (std::vector<osg::ref_ptr<TagBase> >::iterator it = selection.begin(); it != selection.end(); ++it)
|
||||
{
|
||||
if (PathgridTag* tag = dynamic_cast<PathgridTag*>(it->get()))
|
||||
{
|
||||
if (mDragMode == DragMode_Move)
|
||||
{
|
||||
QUndoStack& undoStack = getWorldspaceWidget().getDocument().getUndoStack();
|
||||
QString description = "Move pathgrid node(s)";
|
||||
|
||||
CSMWorld::CommandMacro macro(undoStack, description);
|
||||
tag->getPathgrid()->applyPosition(macro);
|
||||
}
|
||||
else if (mDragMode == DragMode_Edge)
|
||||
{
|
||||
// TODO raycast for other node and apply if needed with mFromNode
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mDragMode = DragMode_None;
|
||||
}
|
||||
|
||||
void PathgridMode::dragAborted()
|
||||
{
|
||||
getWorldspaceWidget().reset(Mask_Pathgrid);
|
||||
}
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
#ifndef CSV_RENDER_PATHGRIDMODE_H
|
||||
#define CSV_RENDER_PATHGRIDMODE_H
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "editmode.hpp"
|
||||
|
||||
namespace CSVRender
|
||||
{
|
||||
class PathgridMode : public EditMode
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
PathgridMode(WorldspaceWidget* worldspace, QWidget* parent=0);
|
||||
|
||||
virtual void primaryEditPressed(const WorldspaceHitResult& hit);
|
||||
|
||||
virtual void secondaryEditPressed(const WorldspaceHitResult& hit);
|
||||
|
||||
virtual void primarySelectPressed(const WorldspaceHitResult& hit);
|
||||
|
||||
virtual void secondarySelectPressed(const WorldspaceHitResult& hit);
|
||||
|
||||
virtual bool primaryEditStartDrag (const WorldspaceHitResult& hit);
|
||||
|
||||
virtual bool secondaryEditStartDrag (const WorldspaceHitResult& hit);
|
||||
|
||||
virtual void drag (int diffX, int diffY, double speedFactor);
|
||||
|
||||
virtual void dragCompleted();
|
||||
|
||||
/// \note dragAborted will not be called, if the drag is aborted via changing
|
||||
/// editing mode
|
||||
virtual void dragAborted();
|
||||
|
||||
private:
|
||||
|
||||
enum DragMode
|
||||
{
|
||||
DragMode_None,
|
||||
DragMode_Move,
|
||||
DragMode_Edge
|
||||
};
|
||||
|
||||
std::string mLastId;
|
||||
DragMode mDragMode;
|
||||
unsigned short mFromNode;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue