1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-02-10 21:40:15 +00:00

Undo rendering works, but not using signals yet.

This commit is contained in:
cc9cii 2015-04-23 22:20:45 +10:00
parent 27a73a25e3
commit 1a31aecc2f
5 changed files with 127 additions and 166 deletions

View File

@ -6,6 +6,7 @@
#include "idtree.hpp" #include "idtree.hpp"
#include <components/misc/stringops.hpp> #include <components/misc/stringops.hpp>
#include "nestedtablewrapper.hpp" #include "nestedtablewrapper.hpp"
#include "../../view/render/cell.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)
@ -248,8 +249,9 @@ const CSMWorld::NestedTableWrapperBase& CSMWorld::NestedTableStoring::getOld() c
// Current interface does not allow adding a non-blank row, so we're forced to modify // Current interface does not allow adding a non-blank row, so we're forced to modify
// the whole record. // the whole record.
CSMWorld::ModifyPathgridCommand::ModifyPathgridCommand(IdTree& model, CSMWorld::ModifyPathgridCommand::ModifyPathgridCommand(IdTree& model,
const std::string& id, int parentColumn, NestedTableWrapperBase* newRecord, QUndoCommand* parent) const std::string& id, int parentColumn, CSVRender::Cell *cell,
: mModel(model), mId(id), mParentColumn(parentColumn), mRecord(newRecord) NestedTableWrapperBase* newRecord, QUndoCommand* parent)
: mModel(model), mId(id), mParentColumn(parentColumn), mRecord(newRecord), mCell(cell)
, QUndoCommand(parent), NestedTableStoring(model, id, parentColumn) , QUndoCommand(parent), NestedTableStoring(model, id, parentColumn)
{ {
setText (("Modify Pathgrid record " + mId).c_str()); // FIXME: better description setText (("Modify Pathgrid record " + mId).c_str()); // FIXME: better description
@ -268,5 +270,6 @@ void CSMWorld::ModifyPathgridCommand::undo()
mModel.setNestedTable(parentIndex, getOld()); mModel.setNestedTable(parentIndex, getOld());
// FIXME: needs to tell the cell to redraw, possibly using signals mCell->clearPathgrid();
mCell->buildPathgrid();
} }

View File

@ -17,6 +17,11 @@
class QModelIndex; class QModelIndex;
class QAbstractItemModel; class QAbstractItemModel;
namespace CSVRender
{
class Cell;
}
namespace CSMWorld namespace CSMWorld
{ {
class IdTable; class IdTable;
@ -204,11 +209,13 @@ namespace CSMWorld
int mParentColumn; int mParentColumn;
NestedTableWrapperBase* mRecord; NestedTableWrapperBase* mRecord;
CSVRender::Cell *mCell;
public: public:
// if newEdges is NULL, only the paths are updated // if newEdges is NULL, only the paths are updated
ModifyPathgridCommand(IdTree& model, const std::string& id, int parentColumn, ModifyPathgridCommand(IdTree& model,
const std::string& id, int parentColumn, CSVRender::Cell *cell,
NestedTableWrapperBase* newRecord, QUndoCommand* parent = 0); NestedTableWrapperBase* newRecord, QUndoCommand* parent = 0);
virtual void redo(); virtual void redo();

View File

@ -120,7 +120,7 @@ bool CSVRender::Cell::addObjects (int start, int end)
CSVRender::Cell::Cell (CSMDoc::Document& document, Ogre::SceneManager *sceneManager, CSVRender::Cell::Cell (CSMDoc::Document& document, Ogre::SceneManager *sceneManager,
const std::string& id, boost::shared_ptr<CSVWorld::PhysicsSystem> physics, const Ogre::Vector3& origin) const std::string& id, boost::shared_ptr<CSVWorld::PhysicsSystem> physics, const Ogre::Vector3& origin)
: mDocument (document), mId (Misc::StringUtils::lowerCase (id)), mSceneMgr(sceneManager) : mDocument (document), mId (Misc::StringUtils::lowerCase (id)), mSceneMgr(sceneManager)
, mPhysics(physics), mX(0), mY(0), mPgIndex(-1), mModel(0), mProxyModel(0)// ,mPathgridId("") , mPhysics(physics), mX(0), mY(0), mPgIndex(-1), mModel(0), mProxyModel(0)
{ {
mCellNode = sceneManager->getRootSceneNode()->createChildSceneNode(); mCellNode = sceneManager->getRootSceneNode()->createChildSceneNode();
mCellNode->setPosition (origin); mCellNode->setPosition (origin);
@ -153,32 +153,15 @@ CSVRender::Cell::Cell (CSMDoc::Document& document, Ogre::SceneManager *sceneMana
} }
} }
loadPathgrid(); setupPathgrid();
buildPathgrid();
} }
CSVRender::Cell::~Cell() CSVRender::Cell::~Cell()
{ {
// destroy manual objects clearPathgrid();
for(std::map<std::pair<int, int>, std::string>::iterator iter = mPgEdges.begin();
iter != mPgEdges.end(); ++iter)
{
if(mSceneMgr->hasManualObject((*iter).second))
{
Ogre::ManualObject *manual = mSceneMgr->getManualObject((*iter).second);
Ogre::SceneNode *node = manual->getParentSceneNode();
mSceneMgr->destroyManualObject((*iter).second);
if(mSceneMgr->hasSceneNode(node->getName()))
mSceneMgr->destroySceneNode(node);
}
}
destroyGridMaterials(); destroyGridMaterials();
for(std::map<std::string, PathgridPoint *>::iterator iter (mPgPoints.begin());
iter!=mPgPoints.end(); ++iter)
{
delete iter->second;
}
delete mProxyModel; delete mProxyModel;
if (mTerrain.get()) if (mTerrain.get())
@ -322,62 +305,101 @@ float CSVRender::Cell::getTerrainHeightAt(const Ogre::Vector3 &pos) const
} }
// FIXME: // FIXME:
// - updating indicies, including mData
// - adding edges (need the ability to select a pathgrid and highlight) // - adding edges (need the ability to select a pathgrid and highlight)
// - save to document & signals // - save to document & signals
// - repainting edges while moving // - repainting edges while moving
void CSVRender::Cell::loadPathgrid() void CSVRender::Cell::setupPathgrid()
{ {
int worldsize = ESM::Land::REAL_SIZE;
const CSMWorld::SubCellCollection<CSMWorld::Pathgrid>& pathgrids = mDocument.getData().getPathgrids(); const CSMWorld::SubCellCollection<CSMWorld::Pathgrid>& pathgrids = mDocument.getData().getPathgrids();
int index = pathgrids.searchId(mId); int index = pathgrids.searchId(mId);
if(index != -1) if(index != -1)
{ {
mPgIndex = index; // keep a copy to save from searching mId all the time
int col = pathgrids.findColumnIndex(CSMWorld::Columns::ColumnId_PathgridPoints); int col = pathgrids.findColumnIndex(CSMWorld::Columns::ColumnId_PathgridPoints);
mPgIndex = index; // keep a copy to save from searching mId all the time
mModel = dynamic_cast<CSMWorld::IdTree *>( mModel = dynamic_cast<CSMWorld::IdTree *>(
mDocument.getData().getTableModel(CSMWorld::UniversalId::Type_Pathgrid)); mDocument.getData().getTableModel(CSMWorld::UniversalId::Type_Pathgrid));
mProxyModel = new CSMWorld::NestedTableProxyModel (mModel->index(mPgIndex, col), mProxyModel = new CSMWorld::NestedTableProxyModel (mModel->index(mPgIndex, col),
CSMWorld::ColumnBase::Display_NestedHeader, mModel); CSMWorld::ColumnBase::Display_NestedHeader, mModel);
const CSMWorld::Pathgrid &pathgrid = pathgrids.getRecord(index).get(); }
}
std::vector<ESM::Pathgrid::Point>::const_iterator iter = pathgrid.mPoints.begin(); void CSVRender::Cell::clearPathgrid()
for(index = 0; iter != pathgrid.mPoints.end(); ++iter, ++index) {
// destroy manual objects (edges)
for(std::map<std::pair<int, int>, std::string>::iterator iter = mPgEdges.begin();
iter != mPgEdges.end(); ++iter)
{
if(mSceneMgr->hasManualObject((*iter).second))
{ {
std::string name = PathgridPoint::getName(pathgrid.mId, index); Ogre::ManualObject *manual = mSceneMgr->getManualObject((*iter).second);
Ogre::SceneNode *node = manual->getParentSceneNode();
Ogre::Vector3 pos = mSceneMgr->destroyManualObject((*iter).second);
Ogre::Vector3(worldsize*mX+(*iter).mX, worldsize*mY+(*iter).mY, (*iter).mZ); if(mSceneMgr->hasSceneNode(node->getName()))
mSceneMgr->destroySceneNode(node);
mPgPoints.insert(std::make_pair(name, new PathgridPoint(name, mCellNode, pos, mPhysics)));
} }
}
mPgEdges.clear();
for(ESM::Pathgrid::EdgeList::const_iterator it = pathgrid.mEdges.begin(); // destroy points
it != pathgrid.mEdges.end(); for(std::map<std::string, PathgridPoint *>::iterator iter (mPgPoints.begin());
++it) iter!=mPgPoints.end(); ++iter)
{ {
Ogre::SceneNode *node = mCellNode->createChildSceneNode(); delete iter->second;
const ESM::Pathgrid::Edge &edge = *it; }
const ESM::Pathgrid::Point &p0 = pathgrid.mPoints[edge.mV0]; mPgPoints.clear();
const ESM::Pathgrid::Point &p1 = pathgrid.mPoints[edge.mV1]; }
std::ostringstream stream; // NOTE: getName() generates a string representation of mId+index to uniquely identify a
stream << pathgrid.mId << "_" << edge.mV0 << " " << edge.mV1; // pathgrid point. The trouble is that the index can change when a pathgrid point is deleted.
std::string name = stream.str(); // Need a new way of uniquely identifying a pathgrid point.
//
// A workaround is to re-generate the pathgrids and edges each time a point is deleted or
// undo() is called (probably via a signal)
void CSVRender::Cell::buildPathgrid()
{
if (!mModel)
return;
Ogre::ManualObject *line = createPathgridEdge(name, const CSMWorld::SubCellCollection<CSMWorld::Pathgrid>& pathgrids = mDocument.getData().getPathgrids();
Ogre::Vector3(worldsize*mX+p0.mX, worldsize*mY+p0.mY, p0.mZ), const CSMWorld::Pathgrid &pathgrid = pathgrids.getRecord(mPgIndex).get();
Ogre::Vector3(worldsize*mX+p1.mX, worldsize*mY+p1.mY, p1.mZ));
line->setVisibilityFlags(Element_Pathgrid);
node->attachObject(line);
mPgEdges.insert(std::make_pair(std::make_pair(edge.mV0, edge.mV1), name)); int worldsize = ESM::Land::REAL_SIZE;
}
std::vector<ESM::Pathgrid::Point>::const_iterator iter = pathgrid.mPoints.begin();
for(int index = 0; iter != pathgrid.mPoints.end(); ++iter, ++index)
{
std::string name = PathgridPoint::getName(pathgrid.mId, index);
Ogre::Vector3 pos =
Ogre::Vector3(worldsize*mX+(*iter).mX, worldsize*mY+(*iter).mY, (*iter).mZ);
mPgPoints.insert(std::make_pair(name, new PathgridPoint(name, mCellNode, pos, mPhysics)));
}
for(ESM::Pathgrid::EdgeList::const_iterator it = pathgrid.mEdges.begin();
it != pathgrid.mEdges.end();
++it)
{
Ogre::SceneNode *node = mCellNode->createChildSceneNode();
const ESM::Pathgrid::Edge &edge = *it;
const ESM::Pathgrid::Point &p0 = pathgrid.mPoints[edge.mV0];
const ESM::Pathgrid::Point &p1 = pathgrid.mPoints[edge.mV1];
std::ostringstream stream;
stream << pathgrid.mId << "_" << edge.mV0 << " " << edge.mV1;
std::string name = stream.str();
Ogre::ManualObject *line = createPathgridEdge(name,
Ogre::Vector3(worldsize*mX+p0.mX, worldsize*mY+p0.mY, p0.mZ),
Ogre::Vector3(worldsize*mX+p1.mX, worldsize*mY+p1.mY, p1.mZ));
line->setVisibilityFlags(Element_Pathgrid);
node->attachObject(line);
mPgEdges.insert(std::make_pair(std::make_pair(edge.mV0, edge.mV1), name));
} }
} }
@ -411,7 +433,7 @@ void CSVRender::Cell::pathgridPointAdded(const Ogre::Vector3 &pos, bool interior
// FIXME: probably will crash if this cell is deleted and undo() is actioned afterwards // FIXME: probably will crash if this cell is deleted and undo() is actioned afterwards
mDocument.getUndoStack().push(new CSMWorld::ModifyPathgridCommand(*mModel, mDocument.getUndoStack().push(new CSMWorld::ModifyPathgridCommand(*mModel,
mProxyModel->getParentId(), mProxyModel->getParentColumn(), mProxyModel->getParentId(), mProxyModel->getParentColumn(), this,
new CSMWorld::PathgridPointsWrap(pathgrid))); new CSMWorld::PathgridPointsWrap(pathgrid)));
// emit signal here? // emit signal here?
} }
@ -433,81 +455,46 @@ void CSVRender::Cell::pathgridPointRemoved(const std::string &name)
return; return;
int numToDelete = pathgrid.mPoints[index].mConnectionNum * 2; // for sanity check later int numToDelete = pathgrid.mPoints[index].mConnectionNum * 2; // for sanity check later
int edgeCount = 0; int deletedEdgeCount = 0;
// find edges to delete // update edge indicies to account for the deleted pathgrid point
std::vector<std::pair<int, int> > edges; std::vector<ESM::Pathgrid::Edge>::iterator iter = pathgrid.mEdges.begin();
for(unsigned i = 0; i < pathgrid.mEdges.size(); ++i) for (; iter != pathgrid.mEdges.end();)
{ {
if(pathgrid.mEdges[i].mV0 == index || pathgrid.mEdges[i].mV1 == index) if (((*iter).mV0 == index) || ((*iter).mV1 == index))
{ {
for(std::map<std::pair<int, int>, std::string>::iterator iter = mPgEdges.begin(); iter = pathgrid.mEdges.erase(iter);
iter != mPgEdges.end(); ++iter) pathgrid.mPoints[index].mConnectionNum -= 1;
{ deletedEdgeCount++; // for sanity check later
if((*iter).first.first == index || (*iter).first.second == index) }
{ else
edges.push_back(std::make_pair((*iter).first.first, (*iter).first.second)); {
} if ((*iter).mV0 > index)
} (*iter).mV0--;
if ((*iter).mV1 > index)
(*iter).mV1--;
++iter;
} }
} }
pathgrid.mPoints.erase(pathgrid.mPoints.begin()+index);
pathgrid.mData.mS2 -= 1; // decrement the number of points
// delete the edges if(deletedEdgeCount != numToDelete)
for(std::vector<std::pair<int, int> >::iterator iter = edges.begin();
iter != edges.end(); ++iter)
{
std::string name = mPgEdges[*iter];
if(mSceneMgr->hasManualObject(name))
{
// remove manual objects
Ogre::ManualObject *manual = mSceneMgr->getManualObject(name);
Ogre::SceneNode *node = manual->getParentSceneNode();
mSceneMgr->destroyManualObject(name);
if(mSceneMgr->hasSceneNode(node->getName()))
mSceneMgr->destroySceneNode(node);
edgeCount++; // for sanity check later
// update map
mPgEdges.erase(*iter);
// update document
assert(pathgrid.mPoints[(*iter).first].mConnectionNum > 0);
pathgrid.mPoints[(*iter).first].mConnectionNum -= 1;
for(unsigned i = pathgrid.mEdges.size() - 1; i > 0; --i)
{
if(pathgrid.mEdges[i].mV0 == index || pathgrid.mEdges[i].mV1 == index)
pathgrid.mEdges.erase(pathgrid.mEdges.begin() + i);
}
}
}
if(edgeCount != numToDelete)
{ {
// WARNING: continue anyway? Or should this be an exception? // WARNING: continue anyway? Or should this be an exception?
std::cerr << "The no of edges del does not match the no of conn for: " std::cerr << "The no of edges del does not match the no of conn for: "
<< pathgridId + "_" + QString::number(index).toStdString() << std::endl; << pathgridId + "_" + QString::number(index).toStdString() << std::endl;
} }
if(edgeCount || pathgrid.mPoints[index].mConnectionNum == 0)
{
// remove the point
delete mPgPoints[name];
mPgPoints.erase(name);
// FIXME: update other scene managers
}
// store to document
//mPoints.erase(mPoints.begin() + index); // WARNING: Can't erase because the index will change
// FIXME: it should be possible to refresh indicies but that means index values
// can't be stored in maps, names, etc
// FIXME: probably will crash if this cell is deleted and undo() is actioned afterwards // FIXME: probably will crash if this cell is deleted and undo() is actioned afterwards
mDocument.getUndoStack().push(new CSMWorld::ModifyPathgridCommand(*mModel, mDocument.getUndoStack().push(new CSMWorld::ModifyPathgridCommand(*mModel,
mProxyModel->getParentId(), mProxyModel->getParentColumn(), new CSMWorld::PathgridPointsWrap(pathgrid))); mProxyModel->getParentId(), mProxyModel->getParentColumn(), this,
new CSMWorld::PathgridPointsWrap(pathgrid)));
clearPathgrid();
buildPathgrid();
} }
// NOTE: newPos is in world coordinates // NOTE: newPos is in world coordinates
@ -542,50 +529,13 @@ void CSVRender::Cell::pathgridPointMoved(const std::string &name,
pathgrid.mPoints[index].mY = y; pathgrid.mPoints[index].mY = y;
pathgrid.mPoints[index].mZ = newPos.z; pathgrid.mPoints[index].mZ = newPos.z;
// delete then recreate the edges
for(unsigned i = 0; i < pathgrid.mEdges.size(); ++i)
{
if(pathgrid.mEdges[i].mV0 == index || pathgrid.mEdges[i].mV1 == index)
{
std::ostringstream stream;
stream << pathgridId << "_" << pathgrid.mEdges[i].mV0 << " " << pathgrid.mEdges[i].mV1;
std::string name = stream.str();
if(mSceneMgr->hasManualObject(name))
{
// remove manual objects
Ogre::ManualObject *manual = mSceneMgr->getManualObject(name);
Ogre::SceneNode *node = manual->getParentSceneNode();
mSceneMgr->destroyManualObject(name);
if(pathgrid.mEdges[i].mV0 == index)
{
const ESM::Pathgrid::Point &p1 = pathgrid.mPoints[pathgrid.mEdges[i].mV1];
Ogre::ManualObject *line = createPathgridEdge(name,
newPos,
Ogre::Vector3(worldsize*mX+p1.mX, worldsize*mY+p1.mY, p1.mZ));
line->setVisibilityFlags(Element_Pathgrid);
node->attachObject(line);
}
else if(pathgrid.mEdges[i].mV1 == index)
{
const ESM::Pathgrid::Point &p0 = pathgrid.mPoints[pathgrid.mEdges[i].mV0];
Ogre::ManualObject *line = createPathgridEdge(name,
Ogre::Vector3(worldsize*mX+p0.mX, worldsize*mY+p0.mY, p0.mZ),
newPos);
line->setVisibilityFlags(Element_Pathgrid);
node->attachObject(line);
}
}
}
}
// FIXME: probably will crash if this cell is deleted and undo() is actioned afterwards // FIXME: probably will crash if this cell is deleted and undo() is actioned afterwards
mDocument.getUndoStack().push(new CSMWorld::ModifyPathgridCommand(*mModel, mDocument.getUndoStack().push(new CSMWorld::ModifyPathgridCommand(*mModel,
mProxyModel->getParentId(), mProxyModel->getParentColumn(), mProxyModel->getParentId(), mProxyModel->getParentColumn(), this,
new CSMWorld::PathgridPointsWrap(pathgrid))); new CSMWorld::PathgridPointsWrap(pathgrid)));
clearPathgrid();
buildPathgrid();
} }
// FIXME: save to the document // FIXME: save to the document

View File

@ -11,7 +11,6 @@
#ifndef Q_MOC_RUN #ifndef Q_MOC_RUN
#include <components/terrain/terraingrid.hpp> #include <components/terrain/terraingrid.hpp>
#include <components/esm/loadpgrd.hpp> // FIXME: temporaty storage until saving to document
#endif #endif
#include "object.hpp" #include "object.hpp"
@ -116,12 +115,17 @@ namespace CSVRender
// for drawing pathgrid points & lines // for drawing pathgrid points & lines
void createGridMaterials(); void createGridMaterials();
void destroyGridMaterials(); void destroyGridMaterials();
void loadPathgrid(); void setupPathgrid();
Ogre::ManualObject *createPathgridEdge(const std::string &name, Ogre::ManualObject *createPathgridEdge(const std::string &name,
const Ogre::Vector3 &start, const Ogre::Vector3 &end); const Ogre::Vector3 &start, const Ogre::Vector3 &end);
void addPathgridEdge(); void addPathgridEdge();
void removePathgridEdge(); void removePathgridEdge();
public:
void clearPathgrid();
void buildPathgrid();
}; };
} }

View File

@ -1,13 +1,10 @@
#include "pathgridpoint.hpp" #include "pathgridpoint.hpp"
#include <iostream> // FIXME
#include <QRegExp> #include <QRegExp>
#include <OgreSceneManager.h> #include <OgreSceneManager.h>
#include <OgreSceneNode.h> #include <OgreSceneNode.h>
//#include "../../model/world/pathgrid.hpp"
#include "../world/physicssystem.hpp" #include "../world/physicssystem.hpp"
#include "elements.hpp" #include "elements.hpp"