mirror of
https://github.com/OpenMW/openmw.git
synced 2025-02-01 07:45:36 +00:00
commit
c7c0023ed2
27 changed files with 1147 additions and 174 deletions
|
@ -19,6 +19,7 @@ opencs_hdrs_noqt (model/doc
|
||||||
|
|
||||||
opencs_units (model/world
|
opencs_units (model/world
|
||||||
idtable idtableproxymodel regionmap data commanddispatcher idtablebase resourcetable nestedtableproxymodel idtree infotableproxymodel
|
idtable idtableproxymodel regionmap data commanddispatcher idtablebase resourcetable nestedtableproxymodel idtree infotableproxymodel
|
||||||
|
pathgridcommands
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -91,6 +92,7 @@ opencs_units (view/render
|
||||||
opencs_units_noqt (view/render
|
opencs_units_noqt (view/render
|
||||||
navigation navigation1st navigationfree navigationorbit lighting lightingday lightingnight
|
navigation navigation1st navigationfree navigationorbit lighting lightingday lightingnight
|
||||||
lightingbright object cell terrainstorage textoverlay overlaymask overlaysystem mousestate
|
lightingbright object cell terrainstorage textoverlay overlaymask overlaysystem mousestate
|
||||||
|
pathgridpoint
|
||||||
)
|
)
|
||||||
|
|
||||||
opencs_hdrs_noqt (view/render
|
opencs_hdrs_noqt (view/render
|
||||||
|
|
|
@ -425,6 +425,9 @@ std::auto_ptr<sh::Factory> CS::Editor::setupGraphics()
|
||||||
// for font used in overlays
|
// for font used in overlays
|
||||||
Ogre::Root::getSingleton().addResourceLocation ((mResources / "mygui").string(),
|
Ogre::Root::getSingleton().addResourceLocation ((mResources / "mygui").string(),
|
||||||
"FileSystem", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, true);
|
"FileSystem", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, true);
|
||||||
|
// for pathgrid point nif
|
||||||
|
Ogre::Root::getSingleton().addResourceLocation ((mResources / "materials").string(),
|
||||||
|
"FileSystem", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, true);
|
||||||
|
|
||||||
if (!boost::filesystem::exists (mCfgMgr.getCachePath()))
|
if (!boost::filesystem::exists (mCfgMgr.getCachePath()))
|
||||||
boost::filesystem::create_directories (mCfgMgr.getCachePath());
|
boost::filesystem::create_directories (mCfgMgr.getCachePath());
|
||||||
|
|
|
@ -12,7 +12,6 @@
|
||||||
#include <QModelIndex>
|
#include <QModelIndex>
|
||||||
|
|
||||||
#include "universalid.hpp"
|
#include "universalid.hpp"
|
||||||
#include "nestedtablewrapper.hpp"
|
|
||||||
|
|
||||||
class QModelIndex;
|
class QModelIndex;
|
||||||
class QAbstractItemModel;
|
class QAbstractItemModel;
|
||||||
|
@ -205,7 +204,8 @@ namespace CSMWorld
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
DeleteNestedCommand (IdTree& model, const std::string& id, int nestedRow, int parentColumn, QUndoCommand* parent = 0);
|
DeleteNestedCommand (IdTree& model,
|
||||||
|
const std::string& id, int nestedRow, int parentColumn, QUndoCommand* parent = 0);
|
||||||
|
|
||||||
virtual void redo();
|
virtual void redo();
|
||||||
|
|
||||||
|
@ -227,7 +227,8 @@ namespace CSMWorld
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
AddNestedCommand(IdTree& model, const std::string& id, int nestedRow, int parentColumn, QUndoCommand* parent = 0);
|
AddNestedCommand(IdTree& model,
|
||||||
|
const std::string& id, int nestedRow, int parentColumn, QUndoCommand* parent = 0);
|
||||||
|
|
||||||
virtual void redo();
|
virtual void redo();
|
||||||
|
|
||||||
|
|
|
@ -259,6 +259,10 @@ void CSMWorld::IdTree::setNestedTable(const QModelIndex& index, const CSMWorld::
|
||||||
{
|
{
|
||||||
emit resetEnd(this->index(index.row(), 0).data().toString());
|
emit resetEnd(this->index(index.row(), 0).data().toString());
|
||||||
}
|
}
|
||||||
|
// FIXME: Removing pathgrid points will also remove pathgrid edges, but we have
|
||||||
|
// no way of emitting signals to indicate those changes. In addition, the
|
||||||
|
// removed edges can be any index (and there can be several edges removed
|
||||||
|
// but always by a factor of two)
|
||||||
}
|
}
|
||||||
|
|
||||||
CSMWorld::NestedTableWrapperBase* CSMWorld::IdTree::nestedTable(const QModelIndex& index) const
|
CSMWorld::NestedTableWrapperBase* CSMWorld::IdTree::nestedTable(const QModelIndex& index) const
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include "pathgrid.hpp"
|
#include "pathgrid.hpp"
|
||||||
#include "info.hpp"
|
#include "info.hpp"
|
||||||
#include "usertype.hpp"
|
#include "usertype.hpp"
|
||||||
|
#include "pathgridpointswrap.hpp"
|
||||||
|
|
||||||
namespace CSMWorld
|
namespace CSMWorld
|
||||||
{
|
{
|
||||||
|
@ -148,6 +149,8 @@ namespace CSMWorld
|
||||||
PathgridEdgeListAdapter::PathgridEdgeListAdapter () {}
|
PathgridEdgeListAdapter::PathgridEdgeListAdapter () {}
|
||||||
|
|
||||||
// ToDo: seems to be auto-sorted in the dialog table display after insertion
|
// ToDo: seems to be auto-sorted in the dialog table display after insertion
|
||||||
|
//
|
||||||
|
// FIXME: edges should be added in pairs
|
||||||
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();
|
||||||
|
@ -169,6 +172,7 @@ namespace CSMWorld
|
||||||
record.setModified (pathgrid);
|
record.setModified (pathgrid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: edges should be removed in pairs and Point.mConnectionNum updated
|
||||||
void PathgridEdgeListAdapter::removeRow(Record<Pathgrid>& record, int rowToRemove) const
|
void PathgridEdgeListAdapter::removeRow(Record<Pathgrid>& record, int rowToRemove) const
|
||||||
{
|
{
|
||||||
Pathgrid pathgrid = record.get();
|
Pathgrid pathgrid = record.get();
|
||||||
|
@ -219,6 +223,8 @@ namespace CSMWorld
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToDo: detect duplicates in mEdges
|
// ToDo: detect duplicates in mEdges
|
||||||
|
//
|
||||||
|
// FIXME: Point.mConnectionNum needs to be updated
|
||||||
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
|
||||||
{
|
{
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
|
|
||||||
#include <QVariant>
|
#include <QVariant>
|
||||||
|
|
||||||
#include <components/esm/loadpgrd.hpp>
|
|
||||||
#include <components/esm/effectlist.hpp>
|
#include <components/esm/effectlist.hpp>
|
||||||
#include <components/esm/loadmgef.hpp> // for converting magic effect id to string & back
|
#include <components/esm/loadmgef.hpp> // for converting magic effect id to string & back
|
||||||
#include <components/esm/loadskil.hpp> // for converting skill names
|
#include <components/esm/loadskil.hpp> // for converting skill names
|
||||||
|
@ -25,21 +24,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:
|
||||||
|
|
48
apps/opencs/model/world/pathgridcommands.cpp
Normal file
48
apps/opencs/model/world/pathgridcommands.cpp
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
#include "pathgridcommands.hpp"
|
||||||
|
|
||||||
|
#include "../../view/render/cell.hpp"
|
||||||
|
|
||||||
|
#include "idtree.hpp"
|
||||||
|
#include "nestedtablewrapper.hpp"
|
||||||
|
|
||||||
|
// Current interface does not allow adding a non-blank row, so we're forced to modify
|
||||||
|
// the whole record.
|
||||||
|
CSMWorld::ModifyPathgridCommand::ModifyPathgridCommand(IdTree& model,
|
||||||
|
const std::string& id, int parentColumn, NestedTableWrapperBase* newRecord, QUndoCommand* parent)
|
||||||
|
: mModel(model), mId(id), mParentColumn(parentColumn), mRecord(newRecord)
|
||||||
|
, QUndoCommand(parent), NestedTableStoring(model, id, parentColumn)
|
||||||
|
{
|
||||||
|
setText (("Modify Pathgrid record " + mId).c_str()); // FIXME: better description
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSMWorld::ModifyPathgridCommand::redo()
|
||||||
|
{
|
||||||
|
const QModelIndex& parentIndex = mModel.getModelIndex(mId, mParentColumn);
|
||||||
|
|
||||||
|
mModel.setNestedTable(parentIndex, *mRecord);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSMWorld::ModifyPathgridCommand::undo()
|
||||||
|
{
|
||||||
|
const QModelIndex& parentIndex = mModel.getModelIndex(mId, mParentColumn);
|
||||||
|
|
||||||
|
mModel.setNestedTable(parentIndex, getOld());
|
||||||
|
|
||||||
|
emit undoActioned();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSMWorld::SignalHandler::rebuildPathgrid()
|
||||||
|
{
|
||||||
|
mParent->clearPathgrid();
|
||||||
|
mParent->buildPathgrid();
|
||||||
|
|
||||||
|
emit flagAsModified();
|
||||||
|
}
|
||||||
|
|
||||||
|
CSMWorld::SignalHandler::SignalHandler (CSVRender::Cell *parent) : mParent(parent)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void CSMWorld::SignalHandler::connectToCommand(const CSMWorld::ModifyPathgridCommand *command)
|
||||||
|
{
|
||||||
|
connect (command, SIGNAL(undoActioned()), this, SLOT(rebuildPathgrid()));
|
||||||
|
}
|
65
apps/opencs/model/world/pathgridcommands.hpp
Normal file
65
apps/opencs/model/world/pathgridcommands.hpp
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
#ifndef CSM_WOLRD_PATHGRIDCOMMANDS_H
|
||||||
|
#define CSM_WOLRD_PATHGRIDCOMMANDS_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
#include "commands.hpp"
|
||||||
|
|
||||||
|
namespace CSVRender
|
||||||
|
{
|
||||||
|
class Cell;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace CSMWorld
|
||||||
|
{
|
||||||
|
class IdTree;
|
||||||
|
class NestedTableWrapperBase;
|
||||||
|
|
||||||
|
class ModifyPathgridCommand : public QObject, public QUndoCommand, private NestedTableStoring
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
IdTree& mModel;
|
||||||
|
std::string mId;
|
||||||
|
|
||||||
|
int mParentColumn;
|
||||||
|
|
||||||
|
NestedTableWrapperBase* mRecord;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
ModifyPathgridCommand(IdTree& model,
|
||||||
|
const std::string& id, int parentColumn, NestedTableWrapperBase* newRecord,
|
||||||
|
QUndoCommand* parent = 0);
|
||||||
|
|
||||||
|
virtual void redo();
|
||||||
|
|
||||||
|
virtual void undo();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
|
||||||
|
void undoActioned();
|
||||||
|
};
|
||||||
|
|
||||||
|
class SignalHandler : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
CSVRender::Cell *mParent;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
SignalHandler (CSVRender::Cell *parent);
|
||||||
|
|
||||||
|
void connectToCommand(const ModifyPathgridCommand *command);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
|
||||||
|
void rebuildPathgrid();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
|
||||||
|
void flagAsModified();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif // CSM_WOLRD_PATHGRIDCOMMANDS_H
|
26
apps/opencs/model/world/pathgridpointswrap.hpp
Normal file
26
apps/opencs/model/world/pathgridpointswrap.hpp
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
#ifndef CSM_WOLRD_PATHGRIDPOINTSWRAP_H
|
||||||
|
#define CSM_WOLRD_PATHGRIDPOINTSWRAP_H
|
||||||
|
|
||||||
|
#include <components/esm/loadpgrd.hpp>
|
||||||
|
|
||||||
|
#include "nestedtablewrapper.hpp"
|
||||||
|
|
||||||
|
namespace CSMWorld
|
||||||
|
{
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // CSM_WOLRD_PATHGRIDPOINTSWRAP_H
|
|
@ -2,18 +2,83 @@
|
||||||
|
|
||||||
#include <OgreSceneManager.h>
|
#include <OgreSceneManager.h>
|
||||||
#include <OgreSceneNode.h>
|
#include <OgreSceneNode.h>
|
||||||
|
#include <OgreManualObject.h>
|
||||||
|
|
||||||
#include <components/misc/stringops.hpp>
|
#include <components/misc/stringops.hpp>
|
||||||
#include <components/esm/loadland.hpp>
|
#include <components/esm/loadland.hpp>
|
||||||
|
|
||||||
|
#include "../../model/doc/document.hpp"
|
||||||
#include "../../model/world/idtable.hpp"
|
#include "../../model/world/idtable.hpp"
|
||||||
|
#include "../../model/world/idtree.hpp"
|
||||||
#include "../../model/world/columns.hpp"
|
#include "../../model/world/columns.hpp"
|
||||||
#include "../../model/world/data.hpp"
|
#include "../../model/world/data.hpp"
|
||||||
#include "../../model/world/refcollection.hpp"
|
#include "../../model/world/refcollection.hpp"
|
||||||
|
#include "../../model/world/pathgrid.hpp"
|
||||||
|
#include "../../model/world/commands.hpp"
|
||||||
|
#include "../../model/world/pathgridcommands.hpp"
|
||||||
|
#include "../../model/world/pathgridpointswrap.hpp"
|
||||||
|
#include "../../model/world/nestedtableproxymodel.hpp"
|
||||||
#include "../world/physicssystem.hpp"
|
#include "../world/physicssystem.hpp"
|
||||||
|
|
||||||
#include "elements.hpp"
|
#include "elements.hpp"
|
||||||
#include "terrainstorage.hpp"
|
#include "terrainstorage.hpp"
|
||||||
|
#include "pathgridpoint.hpp"
|
||||||
|
|
||||||
|
namespace CSVRender
|
||||||
|
{
|
||||||
|
// PLEASE NOTE: pathgrid edge code copied and adapted from mwrender/debugging
|
||||||
|
static const std::string PG_LINE_MATERIAL = "pathgridLineMaterial";
|
||||||
|
static const int POINT_MESH_BASE = 35;
|
||||||
|
static const std::string DEBUGGING_GROUP = "debugging";
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVRender::Cell::createGridMaterials()
|
||||||
|
{
|
||||||
|
if(!Ogre::ResourceGroupManager::getSingleton().resourceGroupExists(DEBUGGING_GROUP))
|
||||||
|
Ogre::ResourceGroupManager::getSingleton().createResourceGroup(DEBUGGING_GROUP);
|
||||||
|
|
||||||
|
if(Ogre::MaterialManager::getSingleton().getByName(PG_LINE_MATERIAL, DEBUGGING_GROUP).isNull())
|
||||||
|
{
|
||||||
|
Ogre::MaterialPtr lineMatPtr =
|
||||||
|
Ogre::MaterialManager::getSingleton().create(PG_LINE_MATERIAL, DEBUGGING_GROUP);
|
||||||
|
lineMatPtr->setReceiveShadows(false);
|
||||||
|
lineMatPtr->getTechnique(0)->setLightingEnabled(true);
|
||||||
|
lineMatPtr->getTechnique(0)->getPass(0)->setDiffuse(1,1,0,0);
|
||||||
|
lineMatPtr->getTechnique(0)->getPass(0)->setAmbient(1,1,0);
|
||||||
|
lineMatPtr->getTechnique(0)->getPass(0)->setSelfIllumination(1,1,0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVRender::Cell::destroyGridMaterials()
|
||||||
|
{
|
||||||
|
if(Ogre::ResourceGroupManager::getSingleton().resourceGroupExists(DEBUGGING_GROUP))
|
||||||
|
{
|
||||||
|
if(!Ogre::MaterialManager::getSingleton().getByName(PG_LINE_MATERIAL, DEBUGGING_GROUP).isNull())
|
||||||
|
Ogre::MaterialManager::getSingleton().remove(PG_LINE_MATERIAL);
|
||||||
|
|
||||||
|
Ogre::ResourceGroupManager::getSingleton().destroyResourceGroup(DEBUGGING_GROUP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ogre::ManualObject *CSVRender::Cell::createPathgridEdge(const std::string &name,
|
||||||
|
const Ogre::Vector3 &start, const Ogre::Vector3 &end)
|
||||||
|
{
|
||||||
|
Ogre::ManualObject *result = mSceneMgr->createManualObject(name);
|
||||||
|
|
||||||
|
createGridMaterials();
|
||||||
|
result->begin(PG_LINE_MATERIAL, Ogre::RenderOperation::OT_LINE_LIST);
|
||||||
|
|
||||||
|
Ogre::Vector3 direction = (end - start);
|
||||||
|
Ogre::Vector3 lineDisplacement = direction.crossProduct(Ogre::Vector3::UNIT_Z).normalisedCopy();
|
||||||
|
// move lines up a little, so they will be less covered by meshes/landscape
|
||||||
|
lineDisplacement = lineDisplacement * POINT_MESH_BASE + Ogre::Vector3(0, 0, 10);
|
||||||
|
result->position(start + lineDisplacement);
|
||||||
|
result->position(end + lineDisplacement);
|
||||||
|
|
||||||
|
result->end();
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
bool CSVRender::Cell::removeObject (const std::string& id)
|
bool CSVRender::Cell::removeObject (const std::string& id)
|
||||||
{
|
{
|
||||||
|
@ -32,7 +97,7 @@ bool CSVRender::Cell::addObjects (int start, int end)
|
||||||
{
|
{
|
||||||
bool modified = false;
|
bool modified = false;
|
||||||
|
|
||||||
const CSMWorld::RefCollection& collection = mData.getReferences();
|
const CSMWorld::RefCollection& collection = mDocument.getData().getReferences();
|
||||||
|
|
||||||
for (int i=start; i<=end; ++i)
|
for (int i=start; i<=end; ++i)
|
||||||
{
|
{
|
||||||
|
@ -44,7 +109,7 @@ bool CSVRender::Cell::addObjects (int start, int end)
|
||||||
{
|
{
|
||||||
std::string id = Misc::StringUtils::lowerCase (collection.getRecord (i).get().mId);
|
std::string id = Misc::StringUtils::lowerCase (collection.getRecord (i).get().mId);
|
||||||
|
|
||||||
mObjects.insert (std::make_pair (id, new Object (mData, mCellNode, id, false, mPhysics)));
|
mObjects.insert (std::make_pair (id, new Object (mDocument.getData(), mCellNode, id, false, mPhysics)));
|
||||||
modified = true;
|
modified = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -52,21 +117,23 @@ bool CSVRender::Cell::addObjects (int start, int end)
|
||||||
return modified;
|
return modified;
|
||||||
}
|
}
|
||||||
|
|
||||||
CSVRender::Cell::Cell (CSMWorld::Data& data, 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)
|
||||||
: mData (data), mId (Misc::StringUtils::lowerCase (id)), mPhysics(physics), mSceneMgr(sceneManager), mX(0), mY(0)
|
: mDocument (document), mId (Misc::StringUtils::lowerCase (id))
|
||||||
|
, mProxyModel(0), mModel(0), mPgIndex(-1), mHandler(new CSMWorld::SignalHandler(this))
|
||||||
|
, mPhysics(physics), mSceneMgr(sceneManager), mX(0), mY(0)
|
||||||
{
|
{
|
||||||
mCellNode = sceneManager->getRootSceneNode()->createChildSceneNode();
|
mCellNode = sceneManager->getRootSceneNode()->createChildSceneNode();
|
||||||
mCellNode->setPosition (origin);
|
mCellNode->setPosition (origin);
|
||||||
|
|
||||||
CSMWorld::IdTable& references = dynamic_cast<CSMWorld::IdTable&> (
|
CSMWorld::IdTable& references = dynamic_cast<CSMWorld::IdTable&> (
|
||||||
*mData.getTableModel (CSMWorld::UniversalId::Type_References));
|
*mDocument.getData().getTableModel (CSMWorld::UniversalId::Type_References));
|
||||||
|
|
||||||
int rows = references.rowCount();
|
int rows = references.rowCount();
|
||||||
|
|
||||||
addObjects (0, rows-1);
|
addObjects (0, rows-1);
|
||||||
|
|
||||||
const CSMWorld::IdCollection<CSMWorld::Land>& land = mData.getLand();
|
const CSMWorld::IdCollection<CSMWorld::Land>& land = mDocument.getData().getLand();
|
||||||
int landIndex = land.searchId(mId);
|
int landIndex = land.searchId(mId);
|
||||||
if (landIndex != -1)
|
if (landIndex != -1)
|
||||||
{
|
{
|
||||||
|
@ -74,7 +141,7 @@ CSVRender::Cell::Cell (CSMWorld::Data& data, Ogre::SceneManager *sceneManager,
|
||||||
|
|
||||||
if (esmLand.getLandData (ESM::Land::DATA_VHGT))
|
if (esmLand.getLandData (ESM::Land::DATA_VHGT))
|
||||||
{
|
{
|
||||||
mTerrain.reset(new Terrain::TerrainGrid(sceneManager, new TerrainStorage(mData), Element_Terrain, true,
|
mTerrain.reset(new Terrain::TerrainGrid(sceneManager, new TerrainStorage(mDocument.getData()), Element_Terrain, true,
|
||||||
Terrain::Align_XY));
|
Terrain::Align_XY));
|
||||||
mTerrain->loadCell(esmLand.mX,
|
mTerrain->loadCell(esmLand.mX,
|
||||||
esmLand.mY);
|
esmLand.mY);
|
||||||
|
@ -88,10 +155,19 @@ CSVRender::Cell::Cell (CSMWorld::Data& data, Ogre::SceneManager *sceneManager,
|
||||||
esmLand.getLandData(ESM::Land::DATA_VHGT)->mHeights, mX, mY, 0, worldsize / (verts-1), verts);
|
esmLand.getLandData(ESM::Land::DATA_VHGT)->mHeights, mX, mY, 0, worldsize / (verts-1), verts);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setupPathgrid();
|
||||||
|
buildPathgrid();
|
||||||
}
|
}
|
||||||
|
|
||||||
CSVRender::Cell::~Cell()
|
CSVRender::Cell::~Cell()
|
||||||
{
|
{
|
||||||
|
clearPathgrid();
|
||||||
|
destroyGridMaterials();
|
||||||
|
|
||||||
|
delete mProxyModel;
|
||||||
|
delete mHandler;
|
||||||
|
|
||||||
if (mTerrain.get())
|
if (mTerrain.get())
|
||||||
mPhysics->removeHeightField(mSceneMgr, mX, mY);
|
mPhysics->removeHeightField(mSceneMgr, mX, mY);
|
||||||
|
|
||||||
|
@ -135,7 +211,7 @@ bool CSVRender::Cell::referenceDataChanged (const QModelIndex& topLeft,
|
||||||
const QModelIndex& bottomRight)
|
const QModelIndex& bottomRight)
|
||||||
{
|
{
|
||||||
CSMWorld::IdTable& references = dynamic_cast<CSMWorld::IdTable&> (
|
CSMWorld::IdTable& references = dynamic_cast<CSMWorld::IdTable&> (
|
||||||
*mData.getTableModel (CSMWorld::UniversalId::Type_References));
|
*mDocument.getData().getTableModel (CSMWorld::UniversalId::Type_References));
|
||||||
|
|
||||||
int idColumn = references.findColumnIndex (CSMWorld::Columns::ColumnId_Id);
|
int idColumn = references.findColumnIndex (CSMWorld::Columns::ColumnId_Id);
|
||||||
int cellColumn = references.findColumnIndex (CSMWorld::Columns::ColumnId_Cell);
|
int cellColumn = references.findColumnIndex (CSMWorld::Columns::ColumnId_Cell);
|
||||||
|
@ -187,7 +263,7 @@ bool CSVRender::Cell::referenceDataChanged (const QModelIndex& topLeft,
|
||||||
for (std::map<std::string, bool>::iterator iter (ids.begin()); iter!=ids.end(); ++iter)
|
for (std::map<std::string, bool>::iterator iter (ids.begin()); iter!=ids.end(); ++iter)
|
||||||
{
|
{
|
||||||
mObjects.insert (std::make_pair (
|
mObjects.insert (std::make_pair (
|
||||||
iter->first, new Object (mData, mCellNode, iter->first, false, mPhysics)));
|
iter->first, new Object (mDocument.getData(), mCellNode, iter->first, false, mPhysics)));
|
||||||
|
|
||||||
modified = true;
|
modified = true;
|
||||||
}
|
}
|
||||||
|
@ -202,7 +278,7 @@ bool CSVRender::Cell::referenceAboutToBeRemoved (const QModelIndex& parent, int
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
CSMWorld::IdTable& references = dynamic_cast<CSMWorld::IdTable&> (
|
CSMWorld::IdTable& references = dynamic_cast<CSMWorld::IdTable&> (
|
||||||
*mData.getTableModel (CSMWorld::UniversalId::Type_References));
|
*mDocument.getData().getTableModel (CSMWorld::UniversalId::Type_References));
|
||||||
|
|
||||||
int idColumn = references.findColumnIndex (CSMWorld::Columns::ColumnId_Id);
|
int idColumn = references.findColumnIndex (CSMWorld::Columns::ColumnId_Id);
|
||||||
|
|
||||||
|
@ -231,3 +307,287 @@ float CSVRender::Cell::getTerrainHeightAt(const Ogre::Vector3 &pos) const
|
||||||
else
|
else
|
||||||
return -std::numeric_limits<float>::max();
|
return -std::numeric_limits<float>::max();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSVRender::Cell::pathgridDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight)
|
||||||
|
{
|
||||||
|
CSMWorld::IdTree *pathgrids = dynamic_cast<CSMWorld::IdTree *>(
|
||||||
|
mDocument.getData().getTableModel(CSMWorld::UniversalId::Type_Pathgrid));
|
||||||
|
|
||||||
|
int idColumn = pathgrids->findColumnIndex(CSMWorld::Columns::ColumnId_Id);
|
||||||
|
int colPaths = pathgrids->findColumnIndex(CSMWorld::Columns::ColumnId_PathgridPoints);
|
||||||
|
//int colEdges = pathgrids->findColumnIndex(CSMWorld::Columns::ColumnId_PathgridEdges);
|
||||||
|
|
||||||
|
// FIXME: how to detect adds/deletes/modifies?
|
||||||
|
|
||||||
|
for (int i=topLeft.row(); i<=bottomRight.row(); ++i)
|
||||||
|
{
|
||||||
|
std::string cell = Misc::StringUtils::lowerCase (pathgrids->data (
|
||||||
|
pathgrids->index (i, idColumn)).toString().toUtf8().constData());
|
||||||
|
|
||||||
|
if (cell==mId && colPaths >= topLeft.column() && colPaths <= bottomRight.column())
|
||||||
|
{
|
||||||
|
if (!mModel)
|
||||||
|
setupPathgrid();
|
||||||
|
|
||||||
|
mHandler->rebuildPathgrid();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME:
|
||||||
|
// - adding edges (need the ability to select a pathgrid and highlight)
|
||||||
|
// - repainting edges while moving
|
||||||
|
void CSVRender::Cell::setupPathgrid()
|
||||||
|
{
|
||||||
|
const CSMWorld::SubCellCollection<CSMWorld::Pathgrid>& pathgrids = mDocument.getData().getPathgrids();
|
||||||
|
int index = pathgrids.searchId(mId);
|
||||||
|
if(index != -1)
|
||||||
|
{
|
||||||
|
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 *>(
|
||||||
|
mDocument.getData().getTableModel(CSMWorld::UniversalId::Type_Pathgrid));
|
||||||
|
|
||||||
|
mProxyModel = new CSMWorld::NestedTableProxyModel (mModel->index(mPgIndex, col),
|
||||||
|
CSMWorld::ColumnBase::Display_NestedHeader, mModel);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVRender::Cell::clearPathgrid()
|
||||||
|
{
|
||||||
|
// 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))
|
||||||
|
{
|
||||||
|
Ogre::ManualObject *manual = mSceneMgr->getManualObject((*iter).second);
|
||||||
|
Ogre::SceneNode *node = manual->getParentSceneNode();
|
||||||
|
mSceneMgr->destroyManualObject((*iter).second);
|
||||||
|
if(mSceneMgr->hasSceneNode(node->getName()))
|
||||||
|
mSceneMgr->destroySceneNode(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mPgEdges.clear();
|
||||||
|
|
||||||
|
// destroy points
|
||||||
|
for(std::map<std::string, PathgridPoint *>::iterator iter (mPgPoints.begin());
|
||||||
|
iter!=mPgPoints.end(); ++iter)
|
||||||
|
{
|
||||||
|
delete iter->second;
|
||||||
|
}
|
||||||
|
mPgPoints.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: getName() generates a string representation of mId+index to uniquely identify a
|
||||||
|
// pathgrid point. The trouble is that the index can change when a pathgrid point is deleted.
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
const CSMWorld::SubCellCollection<CSMWorld::Pathgrid>& pathgrids = mDocument.getData().getPathgrids();
|
||||||
|
const CSMWorld::Pathgrid &pathgrid = pathgrids.getRecord(mPgIndex).get();
|
||||||
|
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: pos is in world coordinates
|
||||||
|
void CSVRender::Cell::pathgridPointAdded(const Ogre::Vector3 &pos, bool interior)
|
||||||
|
{
|
||||||
|
const CSMWorld::SubCellCollection<CSMWorld::Pathgrid>& pathgrids = mDocument.getData().getPathgrids();
|
||||||
|
CSMWorld::Pathgrid pathgrid = pathgrids.getRecord(mPgIndex).get();
|
||||||
|
|
||||||
|
std::string name = PathgridPoint::getName(mId, pathgrid.mPoints.size()); // generate a new name
|
||||||
|
|
||||||
|
mPgPoints.insert(std::make_pair(name, new PathgridPoint(name, mCellNode, pos, mPhysics)));
|
||||||
|
|
||||||
|
// store to document
|
||||||
|
int worldsize = ESM::Land::REAL_SIZE;
|
||||||
|
|
||||||
|
int x = pos.x;
|
||||||
|
int y = pos.y;
|
||||||
|
if(!interior)
|
||||||
|
{
|
||||||
|
x = x - (worldsize * mX);
|
||||||
|
y = y - (worldsize * mY);
|
||||||
|
}
|
||||||
|
|
||||||
|
ESM::Pathgrid::Point point(x, y, (int)pos.z);
|
||||||
|
point.mConnectionNum = 0;
|
||||||
|
pathgrid.mPoints.push_back(point);
|
||||||
|
// FIXME: update other scene managers
|
||||||
|
|
||||||
|
pathgrid.mData.mS2 += 1; // increment the number of points
|
||||||
|
|
||||||
|
// TODO: check for possible issue if this cell is deleted and undo() is actioned afterwards
|
||||||
|
CSMWorld::ModifyPathgridCommand *cmd = new CSMWorld::ModifyPathgridCommand(*mModel,
|
||||||
|
mProxyModel->getParentId(), mProxyModel->getParentColumn(),
|
||||||
|
new CSMWorld::PathgridPointsWrap(pathgrid));
|
||||||
|
mHandler->connectToCommand(cmd);
|
||||||
|
mDocument.getUndoStack().push(cmd);
|
||||||
|
// emit signal here?
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVRender::Cell::pathgridPointRemoved(const std::string &name)
|
||||||
|
{
|
||||||
|
std::pair<std::string, int> result = PathgridPoint::getIdAndIndex(name);
|
||||||
|
if(result.first == "")
|
||||||
|
return;
|
||||||
|
|
||||||
|
std::string pathgridId = result.first;
|
||||||
|
int index = result.second;
|
||||||
|
|
||||||
|
const CSMWorld::SubCellCollection<CSMWorld::Pathgrid>& pathgrids = mDocument.getData().getPathgrids();
|
||||||
|
CSMWorld::Pathgrid pathgrid = pathgrids.getRecord(mPgIndex).get();
|
||||||
|
|
||||||
|
// check if the point exists
|
||||||
|
if(index < 0 || (unsigned int)index >= pathgrid.mPoints.size())
|
||||||
|
return;
|
||||||
|
|
||||||
|
int numToDelete = pathgrid.mPoints[index].mConnectionNum * 2; // for sanity check later
|
||||||
|
int deletedEdgeCount = 0;
|
||||||
|
|
||||||
|
// update edge indicies to account for the deleted pathgrid point
|
||||||
|
std::vector<ESM::Pathgrid::Edge>::iterator iter = pathgrid.mEdges.begin();
|
||||||
|
for (; iter != pathgrid.mEdges.end();)
|
||||||
|
{
|
||||||
|
if (((*iter).mV0 == index) || ((*iter).mV1 == index))
|
||||||
|
{
|
||||||
|
iter = pathgrid.mEdges.erase(iter);
|
||||||
|
pathgrid.mPoints[index].mConnectionNum -= 1;
|
||||||
|
deletedEdgeCount++; // for sanity check later
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
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
|
||||||
|
|
||||||
|
if(deletedEdgeCount != numToDelete)
|
||||||
|
{
|
||||||
|
// WARNING: continue anyway? Or should this be an exception?
|
||||||
|
std::cerr << "The no of edges del does not match the no of conn for: "
|
||||||
|
<< pathgridId + "_" + QString::number(index).toStdString() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: check for possible issue if this cell is deleted and undo() is actioned afterwards
|
||||||
|
CSMWorld::ModifyPathgridCommand *cmd = new CSMWorld::ModifyPathgridCommand(*mModel,
|
||||||
|
mProxyModel->getParentId(), mProxyModel->getParentColumn(),
|
||||||
|
new CSMWorld::PathgridPointsWrap(pathgrid));
|
||||||
|
mHandler->connectToCommand(cmd);
|
||||||
|
mDocument.getUndoStack().push(cmd);
|
||||||
|
|
||||||
|
clearPathgrid();
|
||||||
|
buildPathgrid();
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: newPos is in world coordinates
|
||||||
|
void CSVRender::Cell::pathgridPointMoved(const std::string &name,
|
||||||
|
const Ogre::Vector3 &newPos, bool interior)
|
||||||
|
{
|
||||||
|
std::pair<std::string, int> result = PathgridPoint::getIdAndIndex(name);
|
||||||
|
if(result.first == "")
|
||||||
|
return;
|
||||||
|
|
||||||
|
std::string pathgridId = result.first;
|
||||||
|
int index = result.second;
|
||||||
|
|
||||||
|
const CSMWorld::SubCellCollection<CSMWorld::Pathgrid>& pathgrids = mDocument.getData().getPathgrids();
|
||||||
|
CSMWorld::Pathgrid pathgrid = pathgrids.getRecord(mPgIndex).get();
|
||||||
|
|
||||||
|
// check if the point exists
|
||||||
|
if(index < 0 || (unsigned int)index >= pathgrid.mPoints.size())
|
||||||
|
return;
|
||||||
|
|
||||||
|
int worldsize = ESM::Land::REAL_SIZE;
|
||||||
|
|
||||||
|
int x = newPos.x;
|
||||||
|
int y = newPos.y;
|
||||||
|
if(!interior)
|
||||||
|
{
|
||||||
|
x = x - (worldsize * mX);
|
||||||
|
y = y - (worldsize * mY);
|
||||||
|
}
|
||||||
|
|
||||||
|
pathgrid.mPoints[index].mX = x;
|
||||||
|
pathgrid.mPoints[index].mY = y;
|
||||||
|
pathgrid.mPoints[index].mZ = newPos.z;
|
||||||
|
|
||||||
|
// TODO: check for possible issue if this cell is deleted and undo() is actioned afterwards
|
||||||
|
CSMWorld::ModifyPathgridCommand *cmd = new CSMWorld::ModifyPathgridCommand(*mModel,
|
||||||
|
mProxyModel->getParentId(), mProxyModel->getParentColumn(),
|
||||||
|
new CSMWorld::PathgridPointsWrap(pathgrid));
|
||||||
|
mHandler->connectToCommand(cmd);
|
||||||
|
mDocument.getUndoStack().push(cmd);
|
||||||
|
|
||||||
|
clearPathgrid();
|
||||||
|
buildPathgrid();
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: save to the document
|
||||||
|
void CSVRender::Cell::addPathgridEdge()
|
||||||
|
{
|
||||||
|
// check if the points exist
|
||||||
|
// update the edges
|
||||||
|
// store to document
|
||||||
|
// FIXME: update other scene managers
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: save to the document
|
||||||
|
void CSVRender::Cell::removePathgridEdge()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
CSMWorld::SignalHandler *CSVRender::Cell::getSignalHandler()
|
||||||
|
{
|
||||||
|
return mHandler;
|
||||||
|
}
|
||||||
|
|
|
@ -21,11 +21,20 @@ namespace Ogre
|
||||||
{
|
{
|
||||||
class SceneManager;
|
class SceneManager;
|
||||||
class SceneNode;
|
class SceneNode;
|
||||||
|
class ManualObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace CSMDoc
|
||||||
|
{
|
||||||
|
class Document;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace CSMWorld
|
namespace CSMWorld
|
||||||
{
|
{
|
||||||
class Data;
|
class Pathgrid;
|
||||||
|
class NestedTableProxyModel;
|
||||||
|
class IdTree;
|
||||||
|
class SignalHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace CSVWorld
|
namespace CSVWorld
|
||||||
|
@ -35,12 +44,22 @@ namespace CSVWorld
|
||||||
|
|
||||||
namespace CSVRender
|
namespace CSVRender
|
||||||
{
|
{
|
||||||
|
class PathgridPoint;
|
||||||
|
|
||||||
class Cell
|
class Cell
|
||||||
{
|
{
|
||||||
CSMWorld::Data& mData;
|
CSMDoc::Document& mDocument;
|
||||||
std::string mId;
|
std::string mId;
|
||||||
Ogre::SceneNode *mCellNode;
|
Ogre::SceneNode *mCellNode;
|
||||||
std::map<std::string, Object *> mObjects;
|
std::map<std::string, Object *> mObjects;
|
||||||
|
std::map<std::string, PathgridPoint *> mPgPoints;
|
||||||
|
std::map<std::pair<int, int>, std::string> mPgEdges;
|
||||||
|
|
||||||
|
CSMWorld::NestedTableProxyModel *mProxyModel;
|
||||||
|
CSMWorld::IdTree *mModel;
|
||||||
|
int mPgIndex;
|
||||||
|
CSMWorld::SignalHandler *mHandler;
|
||||||
|
|
||||||
std::auto_ptr<Terrain::TerrainGrid> mTerrain;
|
std::auto_ptr<Terrain::TerrainGrid> mTerrain;
|
||||||
boost::shared_ptr<CSVWorld::PhysicsSystem> mPhysics;
|
boost::shared_ptr<CSVWorld::PhysicsSystem> mPhysics;
|
||||||
Ogre::SceneManager *mSceneMgr;
|
Ogre::SceneManager *mSceneMgr;
|
||||||
|
@ -59,7 +78,7 @@ namespace CSVRender
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Cell (CSMWorld::Data& data, Ogre::SceneManager *sceneManager, const std::string& id,
|
Cell (CSMDoc::Document& document, Ogre::SceneManager *sceneManager, const std::string& id,
|
||||||
boost::shared_ptr<CSVWorld::PhysicsSystem> physics, const Ogre::Vector3& origin = Ogre::Vector3 (0, 0, 0));
|
boost::shared_ptr<CSVWorld::PhysicsSystem> physics, const Ogre::Vector3& origin = Ogre::Vector3 (0, 0, 0));
|
||||||
|
|
||||||
~Cell();
|
~Cell();
|
||||||
|
@ -86,6 +105,31 @@ namespace CSVRender
|
||||||
bool referenceAdded (const QModelIndex& parent, int start, int end);
|
bool referenceAdded (const QModelIndex& parent, int start, int end);
|
||||||
|
|
||||||
float getTerrainHeightAt(const Ogre::Vector3 &pos) const;
|
float getTerrainHeightAt(const Ogre::Vector3 &pos) const;
|
||||||
|
|
||||||
|
void pathgridPointAdded(const Ogre::Vector3 &pos, bool interior = false);
|
||||||
|
void pathgridPointMoved(const std::string &name,
|
||||||
|
const Ogre::Vector3 &newPos, bool interior = false);
|
||||||
|
void pathgridPointRemoved(const std::string &name);
|
||||||
|
|
||||||
|
void pathgridDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
// for drawing pathgrid points & lines
|
||||||
|
void createGridMaterials();
|
||||||
|
void destroyGridMaterials();
|
||||||
|
void setupPathgrid();
|
||||||
|
Ogre::ManualObject *createPathgridEdge(const std::string &name,
|
||||||
|
const Ogre::Vector3 &start, const Ogre::Vector3 &end);
|
||||||
|
|
||||||
|
void addPathgridEdge();
|
||||||
|
void removePathgridEdge();
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
void clearPathgrid();
|
||||||
|
void buildPathgrid();
|
||||||
|
CSMWorld::SignalHandler *getSignalHandler();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -59,9 +59,9 @@ namespace CSVRender
|
||||||
|
|
||||||
MouseState::MouseState(WorldspaceWidget *parent)
|
MouseState::MouseState(WorldspaceWidget *parent)
|
||||||
: mMouseState(Mouse_Default), mParent(parent), mPhysics(parent->mDocument.getPhysics())
|
: mMouseState(Mouse_Default), mParent(parent), mPhysics(parent->mDocument.getPhysics())
|
||||||
, mSceneManager(parent->getSceneManager()), mOldPos(0,0), mCurrentObj(""), mGrabbedSceneNode("")
|
, mSceneManager(parent->getSceneManager()), mOldCursorPos(0,0), mCurrentObj(""), mGrabbedSceneNode(""), mGrabbedRefId("")
|
||||||
, mMouseEventTimer(0), mPlane(0), mOrigObjPos(Ogre::Vector3()), mOrigMousePos(Ogre::Vector3())
|
, mMouseEventTimer(0), mPlane(0), mOrigObjPos(Ogre::Vector3()), mOrigMousePos(Ogre::Vector3())
|
||||||
, mCurrentMousePos(Ogre::Vector3()), mOffset(0.0f), mIdTableModel(0), mColIndexPosX(0)
|
, mOldMousePos(Ogre::Vector3()), mIdTableModel(0), mColIndexPosX(0)
|
||||||
, mColIndexPosY(0), mColIndexPosZ(0)
|
, mColIndexPosY(0), mColIndexPosZ(0)
|
||||||
{
|
{
|
||||||
const CSMWorld::RefCollection& references = mParent->mDocument.getData().getReferences();
|
const CSMWorld::RefCollection& references = mParent->mDocument.getData().getReferences();
|
||||||
|
@ -113,24 +113,22 @@ namespace CSVRender
|
||||||
}
|
}
|
||||||
case Mouse_Drag:
|
case Mouse_Drag:
|
||||||
{
|
{
|
||||||
if(event->pos() != mOldPos) // TODO: maybe don't update less than a quantum?
|
if(event->pos() != mOldCursorPos) // TODO: maybe don't update less than a quantum?
|
||||||
{
|
{
|
||||||
mOldPos = event->pos();
|
mOldCursorPos = event->pos();
|
||||||
|
|
||||||
// ray test against the plane to provide feedback to the user the
|
// ray test against the plane to provide feedback to the user the
|
||||||
// relative movement of the object on the x-y plane
|
// relative movement of the object on the movement plane
|
||||||
std::pair<bool, Ogre::Vector3> planeResult = mousePositionOnPlane(event->pos(), *mPlane);
|
std::pair<bool, Ogre::Vector3> planeResult = mousePosOnPlane(event->pos(), *mPlane);
|
||||||
if(planeResult.first)
|
if(planeResult.first)
|
||||||
{
|
{
|
||||||
if(mGrabbedSceneNode != "")
|
Ogre::Vector3 pos = mOrigObjPos + (planeResult.second-mOrigMousePos);
|
||||||
{
|
|
||||||
std::pair<Ogre::Vector3, Ogre::Vector3> planeRes = planeAxis();
|
mSceneManager->getSceneNode(mGrabbedSceneNode)->setPosition(pos);
|
||||||
Ogre::Vector3 pos = mOrigObjPos + planeRes.first*mOffset;
|
mPhysics->moveSceneNodes(mGrabbedSceneNode, pos);
|
||||||
mSceneManager->getSceneNode(mGrabbedSceneNode)->setPosition(pos+planeResult.second-mOrigMousePos);
|
|
||||||
mCurrentMousePos = planeResult.second;
|
|
||||||
mPhysics->moveSceneNodes(mGrabbedSceneNode, pos+planeResult.second-mOrigMousePos);
|
|
||||||
updateSceneWidgets();
|
updateSceneWidgets();
|
||||||
}
|
|
||||||
|
mOldMousePos = planeResult.second;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -158,21 +156,27 @@ namespace CSVRender
|
||||||
{
|
{
|
||||||
if(event->buttons() & Qt::RightButton)
|
if(event->buttons() & Qt::RightButton)
|
||||||
{
|
{
|
||||||
std::pair<std::string, Ogre::Vector3> result = objectUnderCursor(event->x(), event->y());
|
// get object or pathgrid
|
||||||
|
std::pair<std::string, Ogre::Vector3> result = underCursor(event->x(), event->y(),
|
||||||
|
CSVRender::Element_Reference|CSVRender::Element_Pathgrid);
|
||||||
|
|
||||||
if(result.first == "")
|
if(result.first == "")
|
||||||
break;
|
break;
|
||||||
|
|
||||||
mGrabbedSceneNode = result.first;
|
mGrabbedSceneNode = mPhysics->refIdToSceneNode(result.first, mSceneManager);
|
||||||
|
if(!mSceneManager->hasSceneNode(mGrabbedSceneNode))
|
||||||
|
break;
|
||||||
|
|
||||||
|
mGrabbedRefId = result.first;
|
||||||
// ray test agaist the plane to get a starting position of the
|
// ray test agaist the plane to get a starting position of the
|
||||||
// mouse in relation to the object position
|
// mouse in relation to the object position
|
||||||
std::pair<Ogre::Vector3, Ogre::Vector3> planeRes = planeAxis();
|
std::pair<Ogre::Vector3, Ogre::Vector3> planeRes = planeAxis();
|
||||||
mPlane->redefine(planeRes.first, result.second);
|
mPlane->redefine(planeRes.first, result.second);
|
||||||
std::pair<bool, Ogre::Vector3> planeResult = mousePositionOnPlane(event->pos(), *mPlane);
|
std::pair<bool, Ogre::Vector3> planeResult = mousePosOnPlane(event->pos(), *mPlane);
|
||||||
if(planeResult.first)
|
if(planeResult.first)
|
||||||
{
|
{
|
||||||
mOrigMousePos = planeResult.second;
|
mOrigMousePos = planeResult.second;
|
||||||
mCurrentMousePos = planeResult.second;
|
mOldMousePos = planeResult.second;
|
||||||
mOffset = 0.0f;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mOrigObjPos = mSceneManager->getSceneNode(mGrabbedSceneNode)->getPosition();
|
mOrigObjPos = mSceneManager->getSceneNode(mGrabbedSceneNode)->getPosition();
|
||||||
|
@ -192,7 +196,9 @@ namespace CSVRender
|
||||||
{
|
{
|
||||||
case Mouse_Grab:
|
case Mouse_Grab:
|
||||||
{
|
{
|
||||||
std::pair<std::string, Ogre::Vector3> result = objectUnderCursor(event->x(), event->y());
|
std::pair<std::string, Ogre::Vector3> result = underCursor(event->x(), event->y(),
|
||||||
|
CSVRender::Element_Reference|CSVRender::Element_Pathgrid);
|
||||||
|
|
||||||
if(result.first != "")
|
if(result.first != "")
|
||||||
{
|
{
|
||||||
if(result.first == mCurrentObj)
|
if(result.first == mCurrentObj)
|
||||||
|
@ -208,45 +214,75 @@ namespace CSVRender
|
||||||
mCurrentObj = result.first;
|
mCurrentObj = result.first;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
//#if 0
|
||||||
|
// print some debug info
|
||||||
|
std::cout << "result grab release: " << result.first << std::endl;
|
||||||
|
std::cout << " hit pos "+ QString::number(result.second.x).toStdString()
|
||||||
|
+ ", " + QString::number(result.second.y).toStdString()
|
||||||
|
+ ", " + QString::number(result.second.z).toStdString() << std::endl;
|
||||||
|
//#endif
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Mouse_Drag:
|
case Mouse_Drag:
|
||||||
{
|
{
|
||||||
// final placement
|
// final placement
|
||||||
std::pair<bool, Ogre::Vector3> planeResult = mousePositionOnPlane(event->pos(), *mPlane);
|
std::pair<bool, Ogre::Vector3> planeResult = mousePosOnPlane(event->pos(), *mPlane);
|
||||||
if(planeResult.first)
|
if(planeResult.first)
|
||||||
{
|
{
|
||||||
if(mGrabbedSceneNode != "")
|
Ogre::Vector3 pos = mOrigObjPos + (planeResult.second-mOrigMousePos);
|
||||||
{
|
|
||||||
std::pair<Ogre::Vector3, Ogre::Vector3> planeRes = planeAxis();
|
|
||||||
Ogre::Vector3 pos = mOrigObjPos+planeRes.first*mOffset+planeResult.second-mOrigMousePos;
|
|
||||||
// use the saved scene node name since the physics model has not moved yet
|
|
||||||
std::string referenceId = mPhysics->sceneNodeToRefId(mGrabbedSceneNode);
|
|
||||||
|
|
||||||
|
// use the saved reference Id since the physics model has not moved yet
|
||||||
|
if(QString(mGrabbedRefId.c_str()).contains(QRegExp("^Pathgrid")))
|
||||||
|
{
|
||||||
|
// FIXME: move pathgrid point, but don't save yet (need pathgrid
|
||||||
|
// table feature & its data structure to be completed)
|
||||||
|
// Also need to signal PathgridPoint object of change
|
||||||
|
std::pair<std::string, float> result =
|
||||||
|
mPhysics->distToClosest(pos,
|
||||||
|
getCamera()->getViewport()->getVisibilityMask(), 600); // snap
|
||||||
|
|
||||||
|
if(result.first != "" && // don't allow pathgrid points under the cursor
|
||||||
|
!QString(result.first.c_str()).contains(QRegExp("^Pathgrid")))
|
||||||
|
{
|
||||||
|
pos.z -= result.second;
|
||||||
|
pos.z += 1; // arbitrary number, lift up slightly (maybe change the nif?)
|
||||||
|
// FIXME: rather than just updating at the end, should
|
||||||
|
// consider providing visual feedback of terrain height
|
||||||
|
// while dragging the pathgrid point (maybe check whether
|
||||||
|
// the object is a pathgrid point at the begging and set
|
||||||
|
// a flag?)
|
||||||
|
placeObject(mGrabbedSceneNode, pos); // result.second
|
||||||
|
mParent->pathgridMoved(mGrabbedRefId, pos); // result.second
|
||||||
|
}
|
||||||
|
else
|
||||||
|
cancelDrag(); // FIXME: does not allow editing if terrain not visible
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
mParent->mDocument.getUndoStack().beginMacro (QObject::tr("Move Object"));
|
mParent->mDocument.getUndoStack().beginMacro (QObject::tr("Move Object"));
|
||||||
mParent->mDocument.getUndoStack().push(new CSMWorld::ModifyCommand(*mIdTableModel,
|
mParent->mDocument.getUndoStack().push(new CSMWorld::ModifyCommand(*mIdTableModel,
|
||||||
mIdTableModel->getModelIndex(referenceId, mColIndexPosX), pos.x));
|
mIdTableModel->getModelIndex(mGrabbedRefId, mColIndexPosX), pos.x));
|
||||||
mParent->mDocument.getUndoStack().push(new CSMWorld::ModifyCommand(*mIdTableModel,
|
mParent->mDocument.getUndoStack().push(new CSMWorld::ModifyCommand(*mIdTableModel,
|
||||||
mIdTableModel->getModelIndex(referenceId, mColIndexPosY), pos.y));
|
mIdTableModel->getModelIndex(mGrabbedRefId, mColIndexPosY), pos.y));
|
||||||
mParent->mDocument.getUndoStack().push(new CSMWorld::ModifyCommand(*mIdTableModel,
|
mParent->mDocument.getUndoStack().push(new CSMWorld::ModifyCommand(*mIdTableModel,
|
||||||
mIdTableModel->getModelIndex(referenceId, mColIndexPosZ), pos.z));
|
mIdTableModel->getModelIndex(mGrabbedRefId, mColIndexPosZ), pos.z));
|
||||||
mParent->mDocument.getUndoStack().endMacro();
|
mParent->mDocument.getUndoStack().endMacro();
|
||||||
|
}
|
||||||
|
|
||||||
// FIXME: highlight current object?
|
// FIXME: highlight current object?
|
||||||
//mCurrentObj = mGrabbedSceneNode; // FIXME: doesn't work?
|
//mCurrentObj = mGrabbedRefId; // FIXME: doesn't work?
|
||||||
mCurrentObj = ""; // whether the object is selected
|
mCurrentObj = ""; // whether the object is selected
|
||||||
|
|
||||||
mMouseState = Mouse_Edit;
|
mMouseState = Mouse_Edit;
|
||||||
|
|
||||||
// reset states
|
// reset states
|
||||||
mCurrentMousePos = Ogre::Vector3(); // mouse pos to use in wheel event
|
mGrabbedRefId = ""; // id of the object
|
||||||
|
mGrabbedSceneNode = "";
|
||||||
mOrigMousePos = Ogre::Vector3(); // starting pos of mouse in world space
|
mOrigMousePos = Ogre::Vector3(); // starting pos of mouse in world space
|
||||||
mOrigObjPos = Ogre::Vector3(); // starting pos of object in world space
|
mOrigObjPos = Ogre::Vector3(); // starting pos of object in world space
|
||||||
mGrabbedSceneNode = ""; // id of the object
|
mOldMousePos = Ogre::Vector3(); // mouse pos to use in wheel event
|
||||||
mOffset = 0.0f; // used for z-axis movement
|
mOldCursorPos = QPoint(0, 0); // to calculate relative movement of mouse
|
||||||
mOldPos = QPoint(0, 0); // to calculate relative movement of mouse
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -254,10 +290,18 @@ namespace CSVRender
|
||||||
case Mouse_Default:
|
case Mouse_Default:
|
||||||
{
|
{
|
||||||
// probably terrain, check
|
// probably terrain, check
|
||||||
std::pair<std::string, Ogre::Vector3> result = terrainUnderCursor(event->x(), event->y());
|
std::pair<std::string, Ogre::Vector3> result = underCursor(event->x(), event->y(),
|
||||||
|
CSVRender::Element_Terrain);
|
||||||
|
|
||||||
if(result.first != "")
|
if(result.first != "")
|
||||||
{
|
{
|
||||||
// FIXME: terrain editing goes here
|
// FIXME: terrain editing goes here
|
||||||
|
//#if 0
|
||||||
|
std::cout << "result default/edit release: " << result.first << std::endl;
|
||||||
|
std::cout << " hit pos "+ QString::number(result.second.x).toStdString()
|
||||||
|
+ ", " + QString::number(result.second.y).toStdString()
|
||||||
|
+ ", " + QString::number(result.second.z).toStdString() << std::endl;
|
||||||
|
//#endif
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -283,17 +327,49 @@ namespace CSVRender
|
||||||
/* FALL_THROUGH */
|
/* FALL_THROUGH */
|
||||||
case Mouse_Drag:
|
case Mouse_Drag:
|
||||||
{
|
{
|
||||||
// move the object along the z axis during Mouse_Drag or Mouse_Grab
|
// move the object along the axis normal to the plane during Mouse_Drag or Mouse_Grab
|
||||||
if (event->delta())
|
if (event->delta())
|
||||||
{
|
{
|
||||||
// seems positive is up and negative is down
|
// The mouse point is where the mouse points the object when dragging starts.
|
||||||
mOffset += (event->delta()/1); // FIXME: arbitrary number, make config option?
|
// The object position is usually a little away from the mount point.
|
||||||
|
|
||||||
|
// Get the new world position of mouse on the plane offset from the wheel
|
||||||
|
// FIXME: make the sensitivity a user setting and/or allow modifiers
|
||||||
std::pair<Ogre::Vector3, Ogre::Vector3> planeRes = planeAxis();
|
std::pair<Ogre::Vector3, Ogre::Vector3> planeRes = planeAxis();
|
||||||
Ogre::Vector3 pos = mOrigObjPos + planeRes.first*mOffset;
|
Ogre::Vector3 mousePos = mOldMousePos + planeRes.first*(event->delta()/1.5);
|
||||||
mSceneManager->getSceneNode(mGrabbedSceneNode)->setPosition(pos+mCurrentMousePos-mOrigMousePos);
|
|
||||||
mPhysics->moveSceneNodes(mGrabbedSceneNode, pos+mCurrentMousePos-mOrigMousePos);
|
// Move the movement plane to the new mouse position. The plane is created on
|
||||||
|
// the mouse point (i.e. not the object position)
|
||||||
|
mPlane->redefine(planeRes.first, mousePos);
|
||||||
|
|
||||||
|
// Calculate the new screen position of the cursor
|
||||||
|
Ogre::Vector3 screenPos =
|
||||||
|
getCamera()->getProjectionMatrix() * getCamera()->getViewMatrix() * mousePos;
|
||||||
|
int screenX = (screenPos.x/2+0.5) * getViewport()->getActualWidth();
|
||||||
|
int screenY = (1-(screenPos.y/2+0.5)) * getViewport()->getActualHeight();
|
||||||
|
|
||||||
|
// Move the cursor to the new screen position
|
||||||
|
QCursor::setPos(mParent->mapToGlobal(QPoint(screenX, screenY)));
|
||||||
|
|
||||||
|
// Use the new position to check the world position of the mouse
|
||||||
|
std::pair<bool, Ogre::Vector3> planeResult =
|
||||||
|
mousePosOnPlane(QPoint(screenX, screenY), *mPlane);
|
||||||
|
{
|
||||||
|
if(planeResult.first)
|
||||||
|
mousePos = planeResult.second;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the final world position of the object
|
||||||
|
Ogre::Vector3 finalPos = mOrigObjPos + (mousePos-mOrigMousePos);
|
||||||
|
|
||||||
|
// update Ogre and Bullet
|
||||||
|
mSceneManager->getSceneNode(mGrabbedSceneNode)->setPosition(finalPos);
|
||||||
|
mPhysics->moveSceneNodes(mGrabbedSceneNode, finalPos);
|
||||||
updateSceneWidgets();
|
updateSceneWidgets();
|
||||||
|
|
||||||
|
// remember positions for next time
|
||||||
|
mOldMousePos = mousePos;
|
||||||
|
mOldCursorPos = QPoint(screenX, screenY);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -323,14 +399,14 @@ namespace CSVRender
|
||||||
|
|
||||||
// reset states
|
// reset states
|
||||||
mMouseState = Mouse_Default;
|
mMouseState = Mouse_Default;
|
||||||
mCurrentMousePos = Ogre::Vector3();
|
mOldMousePos = Ogre::Vector3();
|
||||||
mOrigMousePos = Ogre::Vector3();
|
mOrigMousePos = Ogre::Vector3();
|
||||||
mOrigObjPos = Ogre::Vector3();
|
mOrigObjPos = Ogre::Vector3();
|
||||||
|
mGrabbedRefId = "";
|
||||||
mGrabbedSceneNode = "";
|
mGrabbedSceneNode = "";
|
||||||
mCurrentObj = "";
|
mCurrentObj = "";
|
||||||
mOldPos = QPoint(0, 0);
|
mOldCursorPos = QPoint(0, 0);
|
||||||
mMouseEventTimer->invalidate();
|
mMouseEventTimer->invalidate();
|
||||||
mOffset = 0.0f;
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -375,7 +451,7 @@ namespace CSVRender
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<bool, Ogre::Vector3> MouseState::mousePositionOnPlane(const QPoint &pos, const Ogre::Plane &plane)
|
std::pair<bool, Ogre::Vector3> MouseState::mousePosOnPlane(const QPoint &pos, const Ogre::Plane &plane)
|
||||||
{
|
{
|
||||||
// using a really small value seems to mess up with the projections
|
// using a really small value seems to mess up with the projections
|
||||||
float nearClipDistance = getCamera()->getNearClipDistance(); // save existing
|
float nearClipDistance = getCamera()->getNearClipDistance(); // save existing
|
||||||
|
@ -392,7 +468,8 @@ namespace CSVRender
|
||||||
return std::make_pair(false, Ogre::Vector3()); // should only happen if the plane is too small
|
return std::make_pair(false, Ogre::Vector3()); // should only happen if the plane is too small
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<std::string, Ogre::Vector3> MouseState::terrainUnderCursor(const int mouseX, const int mouseY)
|
std::pair<std::string, Ogre::Vector3> MouseState::underCursor(const int mouseX,
|
||||||
|
const int mouseY, Ogre::uint32 elements)
|
||||||
{
|
{
|
||||||
if(!getViewport())
|
if(!getViewport())
|
||||||
return std::make_pair("", Ogre::Vector3());
|
return std::make_pair("", Ogre::Vector3());
|
||||||
|
@ -401,44 +478,18 @@ namespace CSVRender
|
||||||
float y = (float) mouseY / getViewport()->getActualHeight();
|
float y = (float) mouseY / getViewport()->getActualHeight();
|
||||||
|
|
||||||
std::pair<std::string, Ogre::Vector3> result = mPhysics->castRay(x, y, mSceneManager, getCamera());
|
std::pair<std::string, Ogre::Vector3> result = mPhysics->castRay(x, y, mSceneManager, getCamera());
|
||||||
if(result.first != "")
|
|
||||||
{
|
if(result.first != "" &&
|
||||||
// FIXME: is there a better way to distinguish terrain from objects?
|
((elements & (Ogre::uint32)CSVRender::Element_Terrain &&
|
||||||
QString name = QString(result.first.c_str());
|
QString(result.first.c_str()).contains(QRegExp("^Height"))) ||
|
||||||
if(name.contains(QRegExp("^HeightField")))
|
(elements & (Ogre::uint32)CSVRender::Element_Reference &&
|
||||||
|
QString(result.first.c_str()).contains(QRegExp("^ref#"))) ||
|
||||||
|
(elements & (Ogre::uint32)CSVRender::Element_Pathgrid &&
|
||||||
|
QString(result.first.c_str()).contains(QRegExp("^Pathgrid")))))
|
||||||
{
|
{
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
|
|
||||||
return std::make_pair("", Ogre::Vector3());
|
|
||||||
}
|
|
||||||
|
|
||||||
std::pair<std::string, Ogre::Vector3> MouseState::objectUnderCursor(const int mouseX, const int mouseY)
|
|
||||||
{
|
|
||||||
if(!getViewport())
|
|
||||||
return std::make_pair("", Ogre::Vector3());
|
|
||||||
|
|
||||||
float x = (float) mouseX / getViewport()->getActualWidth();
|
|
||||||
float y = (float) mouseY / getViewport()->getActualHeight();
|
|
||||||
|
|
||||||
std::pair<std::string, Ogre::Vector3> result = mPhysics->castRay(x, y, mSceneManager, getCamera());
|
|
||||||
if(result.first != "")
|
|
||||||
{
|
|
||||||
// NOTE: anything not terrain is assumed to be an object
|
|
||||||
QString name = QString(result.first.c_str());
|
|
||||||
if(!name.contains(QRegExp("^HeightField")))
|
|
||||||
{
|
|
||||||
uint32_t visibilityMask = getViewport()->getVisibilityMask();
|
|
||||||
bool ignoreObjects = !(visibilityMask & (uint32_t)CSVRender::Element_Reference);
|
|
||||||
|
|
||||||
if(!ignoreObjects && mSceneManager->hasSceneNode(result.first))
|
|
||||||
{
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return std::make_pair("", Ogre::Vector3());
|
return std::make_pair("", Ogre::Vector3());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -462,4 +513,15 @@ namespace CSVRender
|
||||||
{
|
{
|
||||||
return mParent->getCamera()->getViewport();
|
return mParent->getCamera()->getViewport();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MouseState::placeObject(const std::string sceneNodeName, const Ogre::Vector3 &pos)
|
||||||
|
{
|
||||||
|
mSceneManager->getSceneNode(sceneNodeName)->setPosition(pos);
|
||||||
|
|
||||||
|
// update physics
|
||||||
|
mPhysics->replaceObject(sceneNodeName, 1, pos, Ogre::Quaternion::IDENTITY);
|
||||||
|
|
||||||
|
// update all SceneWidgets and their SceneManagers
|
||||||
|
updateSceneWidgets();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,15 +47,15 @@ namespace CSVRender
|
||||||
boost::shared_ptr<CSVWorld::PhysicsSystem> mPhysics;
|
boost::shared_ptr<CSVWorld::PhysicsSystem> mPhysics;
|
||||||
Ogre::SceneManager *mSceneManager; // local copy
|
Ogre::SceneManager *mSceneManager; // local copy
|
||||||
|
|
||||||
QPoint mOldPos;
|
QPoint mOldCursorPos;
|
||||||
std::string mCurrentObj;
|
std::string mCurrentObj;
|
||||||
std::string mGrabbedSceneNode;
|
std::string mGrabbedSceneNode;
|
||||||
|
std::string mGrabbedRefId;
|
||||||
QElapsedTimer *mMouseEventTimer;
|
QElapsedTimer *mMouseEventTimer;
|
||||||
Ogre::Plane *mPlane;
|
Ogre::Plane *mPlane;
|
||||||
Ogre::Vector3 mOrigObjPos;
|
Ogre::Vector3 mOrigObjPos;
|
||||||
Ogre::Vector3 mOrigMousePos;
|
Ogre::Vector3 mOrigMousePos;
|
||||||
Ogre::Vector3 mCurrentMousePos;
|
Ogre::Vector3 mOldMousePos;
|
||||||
float mOffset;
|
|
||||||
|
|
||||||
CSMWorld::IdTable *mIdTableModel;
|
CSMWorld::IdTable *mIdTableModel;
|
||||||
int mColIndexPosX;
|
int mColIndexPosX;
|
||||||
|
@ -73,16 +73,19 @@ namespace CSVRender
|
||||||
void mouseDoubleClickEvent (QMouseEvent *event);
|
void mouseDoubleClickEvent (QMouseEvent *event);
|
||||||
bool wheelEvent (QWheelEvent *event);
|
bool wheelEvent (QWheelEvent *event);
|
||||||
|
|
||||||
|
std::pair<std::string, Ogre::Vector3> underCursor(const int mouseX,
|
||||||
|
const int mouseY, Ogre::uint32 elements = 0xFFFFFFFF);
|
||||||
|
|
||||||
void cancelDrag();
|
void cancelDrag();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
std::pair<bool, Ogre::Vector3> mousePositionOnPlane(const QPoint &pos, const Ogre::Plane &plane);
|
std::pair<bool, Ogre::Vector3> mousePosOnPlane(const QPoint &pos, const Ogre::Plane &plane);
|
||||||
std::pair<std::string, Ogre::Vector3> terrainUnderCursor(const int mouseX, const int mouseY);
|
|
||||||
std::pair<std::string, Ogre::Vector3> objectUnderCursor(const int mouseX, const int mouseY);
|
|
||||||
std::pair<Ogre::Vector3, Ogre::Vector3> planeAxis();
|
std::pair<Ogre::Vector3, Ogre::Vector3> planeAxis();
|
||||||
void updateSceneWidgets();
|
void updateSceneWidgets();
|
||||||
|
|
||||||
|
void placeObject(const std::string sceneNodeName, const Ogre::Vector3 &pos); // FIXME
|
||||||
|
|
||||||
Ogre::Camera *getCamera(); // friend access
|
Ogre::Camera *getCamera(); // friend access
|
||||||
Ogre::Viewport *getViewport(); // friend access
|
Ogre::Viewport *getViewport(); // friend access
|
||||||
};
|
};
|
||||||
|
|
|
@ -223,12 +223,10 @@ bool CSVRender::Object::referenceDataChanged (const QModelIndex& topLeft,
|
||||||
{
|
{
|
||||||
mReferenceableId =
|
mReferenceableId =
|
||||||
references.getData (index, columnIndex).toString().toUtf8().constData();
|
references.getData (index, columnIndex).toString().toUtf8().constData();
|
||||||
|
|
||||||
update();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
update();
|
||||||
adjust();
|
adjust();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,7 @@ namespace CSVRender
|
||||||
NifOgre::ObjectScenePtr mObject;
|
NifOgre::ObjectScenePtr mObject;
|
||||||
bool mForceBaseToZero;
|
bool mForceBaseToZero;
|
||||||
boost::shared_ptr<CSVWorld::PhysicsSystem> mPhysics;
|
boost::shared_ptr<CSVWorld::PhysicsSystem> mPhysics;
|
||||||
|
std::string mPhysicsObject;
|
||||||
|
|
||||||
/// Not implemented
|
/// Not implemented
|
||||||
Object (const Object&);
|
Object (const Object&);
|
||||||
|
|
|
@ -20,11 +20,14 @@
|
||||||
|
|
||||||
#include "../../model/world/tablemimedata.hpp"
|
#include "../../model/world/tablemimedata.hpp"
|
||||||
#include "../../model/world/idtable.hpp"
|
#include "../../model/world/idtable.hpp"
|
||||||
|
#include "../../model/world/pathgridcommands.hpp"
|
||||||
|
|
||||||
#include "../widget/scenetooltoggle.hpp"
|
#include "../widget/scenetooltoggle.hpp"
|
||||||
#include "../widget/scenetoolmode.hpp"
|
#include "../widget/scenetoolmode.hpp"
|
||||||
#include "../widget/scenetooltoggle2.hpp"
|
#include "../widget/scenetooltoggle2.hpp"
|
||||||
|
#include "../world/physicssystem.hpp"
|
||||||
|
|
||||||
|
#include "pathgridpoint.hpp"
|
||||||
#include "editmode.hpp"
|
#include "editmode.hpp"
|
||||||
#include "elements.hpp"
|
#include "elements.hpp"
|
||||||
|
|
||||||
|
@ -112,8 +115,9 @@ bool CSVRender::PagedWorldspaceWidget::adjustCells()
|
||||||
if (index > 0 && cells.getRecord (index).mState!=CSMWorld::RecordBase::State_Deleted &&
|
if (index > 0 && cells.getRecord (index).mState!=CSMWorld::RecordBase::State_Deleted &&
|
||||||
mCells.find (*iter)==mCells.end())
|
mCells.find (*iter)==mCells.end())
|
||||||
{
|
{
|
||||||
Cell *cell = new Cell (mDocument.getData(), getSceneManager(),
|
Cell *cell = new Cell (mDocument, getSceneManager(),
|
||||||
iter->getId (mWorldspace), mDocument.getPhysics());
|
iter->getId (mWorldspace), mDocument.getPhysics());
|
||||||
|
connect (cell->getSignalHandler(), SIGNAL(flagAsModified()), this, SLOT(flagAsModSlot()));
|
||||||
mCells.insert (std::make_pair (*iter, cell));
|
mCells.insert (std::make_pair (*iter, cell));
|
||||||
|
|
||||||
float height = cell->getTerrainHeightAt(Ogre::Vector3(
|
float height = cell->getTerrainHeightAt(Ogre::Vector3(
|
||||||
|
@ -327,6 +331,106 @@ void CSVRender::PagedWorldspaceWidget::referenceAdded (const QModelIndex& parent
|
||||||
flagAsModified();
|
flagAsModified();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSVRender::PagedWorldspaceWidget::pathgridDataChanged (const QModelIndex& topLeft,
|
||||||
|
const QModelIndex& bottomRight)
|
||||||
|
{
|
||||||
|
for (std::map<CSMWorld::CellCoordinates, Cell *>::iterator iter (mCells.begin());
|
||||||
|
iter!=mCells.end(); ++iter)
|
||||||
|
iter->second->pathgridDataChanged (topLeft, bottomRight);
|
||||||
|
}
|
||||||
|
|
||||||
|
CSVRender::Cell *CSVRender::PagedWorldspaceWidget::findCell(const std::string &cellId)
|
||||||
|
{
|
||||||
|
const CSMWorld::IdCollection<CSMWorld::Cell>& cells = mDocument.getData().getCells();
|
||||||
|
|
||||||
|
std::map<CSMWorld::CellCoordinates, Cell *>::iterator iter (mCells.begin());
|
||||||
|
for(; iter!= mCells.end(); ++iter)
|
||||||
|
{
|
||||||
|
int index = cells.searchId(cellId);
|
||||||
|
|
||||||
|
if (index != -1 && cellId == iter->first.getId (mWorldspace))
|
||||||
|
{
|
||||||
|
return iter->second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: allow placing pathgrid points above objects and terrain
|
||||||
|
void CSVRender::PagedWorldspaceWidget::pathgridInserted (const std::string &referenceId, const Ogre::Vector3 &pos)
|
||||||
|
{
|
||||||
|
QString id = QString(referenceId.c_str());
|
||||||
|
|
||||||
|
bool terrain = id.startsWith("HeightField_");
|
||||||
|
bool object = QString(referenceId.c_str()).startsWith("ref#");
|
||||||
|
// don't allow placing another one on top of a pathgrid point
|
||||||
|
if (id.isEmpty() || (!terrain && !object))
|
||||||
|
return;
|
||||||
|
|
||||||
|
std::string cellId;
|
||||||
|
if(terrain)
|
||||||
|
{
|
||||||
|
QRegExp nameRe("^HeightField_([\\d-]+)_([\\d-]+)$");
|
||||||
|
if (nameRe.indexIn(id) == -1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int cellX = nameRe.cap(1).toInt();
|
||||||
|
int cellY = nameRe.cap(2).toInt();
|
||||||
|
|
||||||
|
std::ostringstream stream;
|
||||||
|
stream << "#" << cellX << " " << cellY;
|
||||||
|
cellId = stream.str();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const CSMWorld::RefCollection& references = mDocument.getData().getReferences();
|
||||||
|
int index = references.searchId(referenceId);
|
||||||
|
if(index == -1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
cellId = references.getData(index, references.findColumnIndex(CSMWorld::Columns::ColumnId_Cell))
|
||||||
|
.toString().toUtf8().constData();
|
||||||
|
}
|
||||||
|
|
||||||
|
Cell *cell = findCell(cellId);
|
||||||
|
if(cell)
|
||||||
|
{
|
||||||
|
cell->pathgridPointAdded(pos);
|
||||||
|
flagAsModified();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVRender::PagedWorldspaceWidget::pathgridMoved (const std::string &pgName, const Ogre::Vector3 &pos)
|
||||||
|
{
|
||||||
|
std::pair<std::string, int> result = PathgridPoint::getIdAndIndex(pgName);
|
||||||
|
|
||||||
|
Cell *cell = findCell(result.first);
|
||||||
|
if(cell)
|
||||||
|
{
|
||||||
|
cell->pathgridPointMoved(pgName, pos);
|
||||||
|
flagAsModified();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVRender::PagedWorldspaceWidget::pathgridAboutToBeRemoved (const std::string &pgName)
|
||||||
|
{
|
||||||
|
std::pair<std::string, int> result = PathgridPoint::getIdAndIndex(pgName);
|
||||||
|
|
||||||
|
Cell *cell = findCell(result.first);
|
||||||
|
if(cell)
|
||||||
|
{
|
||||||
|
cell->pathgridPointRemoved(pgName);
|
||||||
|
flagAsModified();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::string CSVRender::PagedWorldspaceWidget::getStartupInstruction()
|
std::string CSVRender::PagedWorldspaceWidget::getStartupInstruction()
|
||||||
{
|
{
|
||||||
Ogre::Vector3 position = getCamera()->getPosition();
|
Ogre::Vector3 position = getCamera()->getPosition();
|
||||||
|
@ -526,3 +630,8 @@ void CSVRender::PagedWorldspaceWidget::cellAdded (const QModelIndex& index, int
|
||||||
if (adjustCells())
|
if (adjustCells())
|
||||||
flagAsModified();
|
flagAsModified();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSVRender::PagedWorldspaceWidget::flagAsModSlot ()
|
||||||
|
{
|
||||||
|
flagAsModified();
|
||||||
|
}
|
||||||
|
|
|
@ -55,6 +55,8 @@ namespace CSVRender
|
||||||
|
|
||||||
virtual std::string getStartupInstruction();
|
virtual std::string getStartupInstruction();
|
||||||
|
|
||||||
|
Cell *findCell(const std::string &cellId);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
PagedWorldspaceWidget (QWidget *parent, CSMDoc::Document& document);
|
PagedWorldspaceWidget (QWidget *parent, CSMDoc::Document& document);
|
||||||
|
@ -95,6 +97,10 @@ namespace CSVRender
|
||||||
|
|
||||||
virtual void mouseDoubleClickEvent (QMouseEvent *event);
|
virtual void mouseDoubleClickEvent (QMouseEvent *event);
|
||||||
|
|
||||||
|
virtual void pathgridInserted (const std::string &referenceId, const Ogre::Vector3 &pos);
|
||||||
|
virtual void pathgridMoved (const std::string &pgName, const Ogre::Vector3 &pos);
|
||||||
|
virtual void pathgridAboutToBeRemoved (const std::string &pgName);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|
||||||
void cellSelectionChanged (const CSMWorld::CellSelection& selection);
|
void cellSelectionChanged (const CSMWorld::CellSelection& selection);
|
||||||
|
@ -107,6 +113,9 @@ namespace CSVRender
|
||||||
|
|
||||||
virtual void cellAdded (const QModelIndex& index, int start, int end);
|
virtual void cellAdded (const QModelIndex& index, int start, int end);
|
||||||
|
|
||||||
|
virtual void flagAsModSlot();
|
||||||
|
|
||||||
|
virtual void pathgridDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
70
apps/opencs/view/render/pathgridpoint.cpp
Normal file
70
apps/opencs/view/render/pathgridpoint.cpp
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
#include "pathgridpoint.hpp"
|
||||||
|
|
||||||
|
#include <QRegExp>
|
||||||
|
|
||||||
|
#include <OgreSceneManager.h>
|
||||||
|
#include <OgreSceneNode.h>
|
||||||
|
|
||||||
|
#include "../world/physicssystem.hpp"
|
||||||
|
|
||||||
|
#include "elements.hpp"
|
||||||
|
|
||||||
|
namespace CSVRender
|
||||||
|
{
|
||||||
|
PathgridPoint::PathgridPoint(const std::string &name,
|
||||||
|
Ogre::SceneNode *cellNode, const Ogre::Vector3 &pos, boost::shared_ptr<CSVWorld::PhysicsSystem> physics)
|
||||||
|
: mBase(cellNode), mPhysics(physics)
|
||||||
|
{
|
||||||
|
mBase = cellNode->createChildSceneNode();
|
||||||
|
|
||||||
|
mPgPoint = NifOgre::Loader::createObjects(mBase, "pathgrid_pt.nif");
|
||||||
|
mPgPoint->setVisibilityFlags(Element_Pathgrid);
|
||||||
|
mBase->setPosition(pos);
|
||||||
|
|
||||||
|
physics->addObject("pathgrid_pt.nif",
|
||||||
|
mBase->getName(), name, 1, pos, Ogre::Quaternion::IDENTITY);
|
||||||
|
}
|
||||||
|
|
||||||
|
PathgridPoint::~PathgridPoint()
|
||||||
|
{
|
||||||
|
mPgPoint.setNull();
|
||||||
|
|
||||||
|
mPhysics->removeObject(mBase->getName());
|
||||||
|
|
||||||
|
if (mBase)
|
||||||
|
mBase->getCreator()->destroySceneNode(mBase);
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: Is there a way to identify the pathgrid point other than via the index?
|
||||||
|
// ESM::Pathgrid::Edge itself uses the indicies so any change (add/delete) must be
|
||||||
|
// propagated everywhere.
|
||||||
|
std::pair<std::string, int> PathgridPoint::getIdAndIndex(const std::string &name)
|
||||||
|
{
|
||||||
|
// decode name
|
||||||
|
QString id = QString(name.c_str());
|
||||||
|
QRegExp pathgridRe("^Pathgrid_(.+)_(\\d+)$");
|
||||||
|
|
||||||
|
if (id.isEmpty() || !id.startsWith("Pathgrid_"))
|
||||||
|
return std::make_pair("", -1);
|
||||||
|
|
||||||
|
std::string pathgridId = "";
|
||||||
|
int index = -1;
|
||||||
|
if (pathgridRe.indexIn(id) != -1)
|
||||||
|
{
|
||||||
|
pathgridId = pathgridRe.cap(1).toStdString();
|
||||||
|
index = pathgridRe.cap(2).toInt();
|
||||||
|
|
||||||
|
return std::make_pair(pathgridId, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::make_pair("", -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string PathgridPoint::getName(const std::string &pathgridId, const int index)
|
||||||
|
{
|
||||||
|
std::ostringstream stream;
|
||||||
|
stream << "Pathgrid_" << pathgridId << "_" << index;
|
||||||
|
|
||||||
|
return stream.str();
|
||||||
|
}
|
||||||
|
}
|
42
apps/opencs/view/render/pathgridpoint.hpp
Normal file
42
apps/opencs/view/render/pathgridpoint.hpp
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
#ifndef OPENCS_VIEW_PATHGRIDPOINT_H
|
||||||
|
#define OPENCS_VIEW_PATHGRIDPOINT_H
|
||||||
|
|
||||||
|
#include <boost/shared_ptr.hpp>
|
||||||
|
|
||||||
|
#include <components/nifogre/ogrenifloader.hpp>
|
||||||
|
|
||||||
|
namespace Ogre
|
||||||
|
{
|
||||||
|
class Vector3;
|
||||||
|
class SceneNode;
|
||||||
|
class SceneManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace CSVWorld
|
||||||
|
{
|
||||||
|
class PhysicsSystem;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace CSVRender
|
||||||
|
{
|
||||||
|
class PathgridPoint
|
||||||
|
{
|
||||||
|
boost::shared_ptr<CSVWorld::PhysicsSystem> mPhysics; // local copy
|
||||||
|
NifOgre::ObjectScenePtr mPgPoint;
|
||||||
|
Ogre::SceneNode *mBase;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
PathgridPoint(const std::string &name,
|
||||||
|
Ogre::SceneNode *cellNode, const Ogre::Vector3 &pos,
|
||||||
|
boost::shared_ptr<CSVWorld::PhysicsSystem> physics);
|
||||||
|
|
||||||
|
~PathgridPoint();
|
||||||
|
|
||||||
|
static std::pair<std::string, int> getIdAndIndex(const std::string &name);
|
||||||
|
|
||||||
|
static std::string getName(const std::string &pathgridId, int index);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // OPENCS_VIEW_PATHGRIDPOINT_H
|
|
@ -12,6 +12,7 @@
|
||||||
#include "../../model/world/data.hpp"
|
#include "../../model/world/data.hpp"
|
||||||
#include "../../model/world/idtable.hpp"
|
#include "../../model/world/idtable.hpp"
|
||||||
#include "../../model/world/tablemimedata.hpp"
|
#include "../../model/world/tablemimedata.hpp"
|
||||||
|
#include "../../model/world/pathgridcommands.hpp"
|
||||||
|
|
||||||
#include "../widget/scenetooltoggle.hpp"
|
#include "../widget/scenetooltoggle.hpp"
|
||||||
#include "../widget/scenetooltoggle2.hpp"
|
#include "../widget/scenetooltoggle2.hpp"
|
||||||
|
@ -48,7 +49,9 @@ CSVRender::UnpagedWorldspaceWidget::UnpagedWorldspaceWidget (const std::string&
|
||||||
|
|
||||||
update();
|
update();
|
||||||
|
|
||||||
mCell.reset (new Cell (document.getData(), getSceneManager(), mCellId, document.getPhysics()));
|
Cell *cell = new Cell (document, getSceneManager(), mCellId, document.getPhysics());
|
||||||
|
connect (cell->getSignalHandler(), SIGNAL(flagAsModified()), this, SLOT(flagAsModSlot()));
|
||||||
|
mCell.reset (cell);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSVRender::UnpagedWorldspaceWidget::cellDataChanged (const QModelIndex& topLeft,
|
void CSVRender::UnpagedWorldspaceWidget::cellDataChanged (const QModelIndex& topLeft,
|
||||||
|
@ -90,7 +93,9 @@ bool CSVRender::UnpagedWorldspaceWidget::handleDrop (const std::vector<CSMWorld:
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
mCellId = data.begin()->getId();
|
mCellId = data.begin()->getId();
|
||||||
mCell.reset (new Cell (getDocument().getData(), getSceneManager(), mCellId, getDocument().getPhysics()));
|
Cell *cell = new Cell (getDocument(), getSceneManager(), mCellId, getDocument().getPhysics());
|
||||||
|
connect (cell->getSignalHandler(), SIGNAL(flagAsModified()), this, SLOT(flagAsModSlot()));
|
||||||
|
mCell.reset (cell);
|
||||||
|
|
||||||
update();
|
update();
|
||||||
emit cellChanged(*data.begin());
|
emit cellChanged(*data.begin());
|
||||||
|
@ -160,6 +165,12 @@ void CSVRender::UnpagedWorldspaceWidget::addVisibilitySelectorButtons (
|
||||||
tool->addButton (Element_Fog, "Fog");
|
tool->addButton (Element_Fog, "Fog");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSVRender::UnpagedWorldspaceWidget::pathgridDataChanged (const QModelIndex& topLeft,
|
||||||
|
const QModelIndex& bottomRight)
|
||||||
|
{
|
||||||
|
// FIXME:
|
||||||
|
}
|
||||||
|
|
||||||
std::string CSVRender::UnpagedWorldspaceWidget::getStartupInstruction()
|
std::string CSVRender::UnpagedWorldspaceWidget::getStartupInstruction()
|
||||||
{
|
{
|
||||||
Ogre::Vector3 position = getCamera()->getPosition();
|
Ogre::Vector3 position = getCamera()->getPosition();
|
||||||
|
@ -193,3 +204,8 @@ CSVRender::WorldspaceWidget::dropRequirments CSVRender::UnpagedWorldspaceWidget:
|
||||||
return ignored;
|
return ignored;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSVRender::UnpagedWorldspaceWidget::flagAsModSlot ()
|
||||||
|
{
|
||||||
|
flagAsModified();
|
||||||
|
}
|
||||||
|
|
|
@ -70,6 +70,10 @@ namespace CSVRender
|
||||||
|
|
||||||
void cellRowsAboutToBeRemoved (const QModelIndex& parent, int start, int end);
|
void cellRowsAboutToBeRemoved (const QModelIndex& parent, int start, int end);
|
||||||
|
|
||||||
|
virtual void flagAsModSlot();
|
||||||
|
|
||||||
|
virtual void pathgridDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|
||||||
void cellChanged(const CSMWorld::UniversalId& id);
|
void cellChanged(const CSMWorld::UniversalId& id);
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include <QDropEvent>
|
#include <QDropEvent>
|
||||||
#include <QMouseEvent>
|
#include <QMouseEvent>
|
||||||
#include <QKeyEvent>
|
#include <QKeyEvent>
|
||||||
|
#include <QPoint>
|
||||||
|
|
||||||
#include "../../model/world/universalid.hpp"
|
#include "../../model/world/universalid.hpp"
|
||||||
#include "../../model/world/idtable.hpp"
|
#include "../../model/world/idtable.hpp"
|
||||||
|
@ -59,6 +60,12 @@ CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidg
|
||||||
connect (debugProfiles, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)),
|
connect (debugProfiles, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)),
|
||||||
this, SLOT (debugProfileAboutToBeRemoved (const QModelIndex&, int, int)));
|
this, SLOT (debugProfileAboutToBeRemoved (const QModelIndex&, int, int)));
|
||||||
|
|
||||||
|
QAbstractItemModel *pathgrids =
|
||||||
|
document.getData().getTableModel (CSMWorld::UniversalId::Type_Pathgrid);
|
||||||
|
|
||||||
|
connect (pathgrids, SIGNAL (dataChanged (const QModelIndex&, const QModelIndex&)),
|
||||||
|
this, SLOT (pathgridDataChanged (const QModelIndex&, const QModelIndex&)));
|
||||||
|
|
||||||
mPhysics = document.getPhysics(); // create physics if one doesn't exist
|
mPhysics = document.getPhysics(); // create physics if one doesn't exist
|
||||||
mPhysics->addSceneManager(getSceneManager(), this);
|
mPhysics->addSceneManager(getSceneManager(), this);
|
||||||
mMouse = new MouseState(this);
|
mMouse = new MouseState(this);
|
||||||
|
@ -415,12 +422,52 @@ void CSVRender::WorldspaceWidget::wheelEvent (QWheelEvent *event)
|
||||||
SceneWidget::wheelEvent(event);
|
SceneWidget::wheelEvent(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: mouse button events are processed in MouseState but key events are
|
||||||
|
// processed here - seems inconsistent
|
||||||
void CSVRender::WorldspaceWidget::keyPressEvent (QKeyEvent *event)
|
void CSVRender::WorldspaceWidget::keyPressEvent (QKeyEvent *event)
|
||||||
{
|
{
|
||||||
if(event->key() == Qt::Key_Escape)
|
if(event->key() == Qt::Key_Escape)
|
||||||
{
|
{
|
||||||
mMouse->cancelDrag();
|
mMouse->cancelDrag();
|
||||||
}
|
}
|
||||||
|
else if(event->key() == Qt::Key_Delete)
|
||||||
|
{
|
||||||
|
QPoint p = this->mapFromGlobal(QCursor::pos());
|
||||||
|
std::pair<std::string, Ogre::Vector3> result =
|
||||||
|
mMouse->underCursor(p.x(), p.y(), CSVRender::Element_Pathgrid);
|
||||||
|
|
||||||
|
if(result.first != "")
|
||||||
|
{
|
||||||
|
pathgridAboutToBeRemoved(result.first);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
SceneWidget::keyPressEvent(event);
|
SceneWidget::keyPressEvent(event);
|
||||||
}
|
}
|
||||||
|
else if(event->key() == Qt::Key_Insert)
|
||||||
|
{
|
||||||
|
QPoint p = this->mapFromGlobal(QCursor::pos());
|
||||||
|
std::pair<std::string, Ogre::Vector3> result =
|
||||||
|
mMouse->underCursor(p.x(), p.y(), CSVRender::Element_Reference|CSVRender::Element_Terrain);
|
||||||
|
|
||||||
|
if(result.first != "")
|
||||||
|
{
|
||||||
|
pathgridInserted(result.first, result.second);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
SceneWidget::keyPressEvent(event);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
SceneWidget::keyPressEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVRender::WorldspaceWidget::pathgridAboutToBeRemoved (const std::string &pgName)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVRender::WorldspaceWidget::pathgridMoved (const std::string &pgName, const Ogre::Vector3 &newPos)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVRender::WorldspaceWidget::pathgridInserted (const std::string &name, const Ogre::Vector3 &pos)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
|
@ -124,6 +124,11 @@ namespace CSVRender
|
||||||
virtual void wheelEvent (QWheelEvent *event);
|
virtual void wheelEvent (QWheelEvent *event);
|
||||||
virtual void keyPressEvent (QKeyEvent *event);
|
virtual void keyPressEvent (QKeyEvent *event);
|
||||||
|
|
||||||
|
// FIXME: temporary only until the signals from the document are implemented
|
||||||
|
virtual void pathgridInserted (const std::string &terrain, const Ogre::Vector3 &pos);
|
||||||
|
virtual void pathgridMoved (const std::string &pgName, const Ogre::Vector3 &pos);
|
||||||
|
virtual void pathgridAboutToBeRemoved (const std::string &pgName);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void dragEnterEvent(QDragEnterEvent *event);
|
void dragEnterEvent(QDragEnterEvent *event);
|
||||||
|
@ -158,6 +163,7 @@ namespace CSVRender
|
||||||
|
|
||||||
void debugProfileAboutToBeRemoved (const QModelIndex& parent, int start, int end);
|
void debugProfileAboutToBeRemoved (const QModelIndex& parent, int start, int end);
|
||||||
|
|
||||||
|
virtual void pathgridDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) = 0;
|
||||||
|
|
||||||
protected slots:
|
protected slots:
|
||||||
|
|
||||||
|
|
|
@ -72,9 +72,6 @@ namespace CSVWorld
|
||||||
|
|
||||||
if(referenceId != "")
|
if(referenceId != "")
|
||||||
{
|
{
|
||||||
mSceneNodeToRefId.erase(sceneNodeName);
|
|
||||||
mSceneNodeToMesh.erase(sceneNodeName);
|
|
||||||
|
|
||||||
// find which SceneManager has this object
|
// find which SceneManager has this object
|
||||||
Ogre::SceneManager *sceneManager = findSceneManager(sceneNodeName);
|
Ogre::SceneManager *sceneManager = findSceneManager(sceneNodeName);
|
||||||
if(!sceneManager)
|
if(!sceneManager)
|
||||||
|
@ -99,7 +96,8 @@ namespace CSVWorld
|
||||||
mRefIdToSceneNode.begin();
|
mRefIdToSceneNode.begin();
|
||||||
for(; itRef != mRefIdToSceneNode.end(); ++itRef)
|
for(; itRef != mRefIdToSceneNode.end(); ++itRef)
|
||||||
{
|
{
|
||||||
if((*itRef).second.find(sceneManager) != (*itRef).second.end())
|
if((*itRef).first == referenceId &&
|
||||||
|
(*itRef).second.find(sceneManager) != (*itRef).second.end())
|
||||||
{
|
{
|
||||||
(*itRef).second.erase(sceneManager);
|
(*itRef).second.erase(sceneManager);
|
||||||
break;
|
break;
|
||||||
|
@ -107,11 +105,15 @@ namespace CSVWorld
|
||||||
}
|
}
|
||||||
|
|
||||||
// check whether the physics model should be deleted
|
// check whether the physics model should be deleted
|
||||||
if(mRefIdToSceneNode.find(referenceId) == mRefIdToSceneNode.end())
|
itRef = mRefIdToSceneNode.find(referenceId);
|
||||||
|
if(itRef == mRefIdToSceneNode.end() || (*itRef).second.empty())
|
||||||
{
|
{
|
||||||
mEngine->removeRigidBody(referenceId);
|
mEngine->removeRigidBody(referenceId);
|
||||||
mEngine->deleteRigidBody(referenceId);
|
mEngine->deleteRigidBody(referenceId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mSceneNodeToRefId.erase(sceneNodeName);
|
||||||
|
mSceneNodeToMesh.erase(sceneNodeName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -211,11 +213,6 @@ namespace CSVWorld
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// sceneMgr: to lookup the scene node name from the object's referenceId
|
|
||||||
// camera: primarily used to get the visibility mask for the viewport
|
|
||||||
//
|
|
||||||
// returns the found object's scene node name and its position in the world space
|
|
||||||
//
|
|
||||||
// WARNING: far clip distance is a global setting, if it changes in future
|
// WARNING: far clip distance is a global setting, if it changes in future
|
||||||
// this method will need to be updated
|
// this method will need to be updated
|
||||||
std::pair<std::string, Ogre::Vector3> PhysicsSystem::castRay(float mouseX,
|
std::pair<std::string, Ogre::Vector3> PhysicsSystem::castRay(float mouseX,
|
||||||
|
@ -241,27 +238,86 @@ namespace CSVWorld
|
||||||
_from = btVector3(from.x, from.y, from.z);
|
_from = btVector3(from.x, from.y, from.z);
|
||||||
_to = btVector3(to.x, to.y, to.z);
|
_to = btVector3(to.x, to.y, to.z);
|
||||||
|
|
||||||
uint32_t visibilityMask = camera->getViewport()->getVisibilityMask();
|
Ogre::uint32 visibilityMask = camera->getViewport()->getVisibilityMask();
|
||||||
bool ignoreHeightMap = !(visibilityMask & (uint32_t)CSVRender::Element_Terrain);
|
bool ignoreHeightMap = !(visibilityMask & (Ogre::uint32)CSVRender::Element_Terrain);
|
||||||
bool ignoreObjects = !(visibilityMask & (uint32_t)CSVRender::Element_Reference);
|
bool ignoreObjects = !(visibilityMask & (Ogre::uint32)CSVRender::Element_Reference);
|
||||||
|
bool ignorePathgrid = !(visibilityMask & (Ogre::uint32)CSVRender::Element_Pathgrid);
|
||||||
|
|
||||||
Ogre::Vector3 norm; // not used
|
std::pair<std::string, float> result = std::make_pair("", -1);
|
||||||
std::pair<std::string, float> result =
|
short mask = OEngine::Physic::CollisionType_Raycasting;
|
||||||
mEngine->rayTest(_from, _to, !ignoreObjects, ignoreHeightMap, &norm);
|
std::vector<std::pair<float, std::string> > objects = mEngine->rayTest2(_from, _to, mask);
|
||||||
|
|
||||||
|
for (std::vector<std::pair<float, std::string> >::iterator it = objects.begin();
|
||||||
|
it != objects.end(); ++it)
|
||||||
|
{
|
||||||
|
if(ignorePathgrid && QString((*it).second.c_str()).contains(QRegExp("^Pathgrid")))
|
||||||
|
continue;
|
||||||
|
else if(ignoreObjects && QString((*it).second.c_str()).contains(QRegExp("^ref#")))
|
||||||
|
continue;
|
||||||
|
else if(ignoreHeightMap && QString((*it).second.c_str()).contains(QRegExp("^Height")))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
result = std::make_pair((*it).second, (*it).first);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// result.first is the object's referenceId
|
// result.first is the object's referenceId
|
||||||
if(result.first == "")
|
if(result.first == "")
|
||||||
return std::make_pair("", Ogre::Vector3(0,0,0));
|
return std::make_pair("", Ogre::Vector3());
|
||||||
else
|
else
|
||||||
{
|
return std::make_pair(result.first, ray.getPoint(farClipDist*result.second));
|
||||||
std::string name = refIdToSceneNode(result.first, sceneMgr);
|
|
||||||
if(name == "")
|
|
||||||
name = result.first;
|
|
||||||
else
|
|
||||||
name = refIdToSceneNode(result.first, sceneMgr);
|
|
||||||
|
|
||||||
return std::make_pair(name, ray.getPoint(farClipDist*result.second));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::pair<std::string, float> PhysicsSystem::distToGround(const Ogre::Vector3 &position,
|
||||||
|
Ogre::uint32 visibilityMask, const float limit)
|
||||||
|
{
|
||||||
|
btVector3 _from, _to;
|
||||||
|
_from = btVector3(position.x, position.y, position.z);
|
||||||
|
_to = btVector3(position.x, position.y, position.z-limit);
|
||||||
|
|
||||||
|
bool ignoreHeightMap = !(visibilityMask & (Ogre::uint32)CSVRender::Element_Terrain);
|
||||||
|
bool ignoreObjects = !(visibilityMask & (Ogre::uint32)CSVRender::Element_Reference);
|
||||||
|
bool ignorePathgrid = !(visibilityMask & (Ogre::uint32)CSVRender::Element_Pathgrid);
|
||||||
|
|
||||||
|
std::pair<std::string, float> result = std::make_pair("", -1);
|
||||||
|
short mask = OEngine::Physic::CollisionType_Raycasting;
|
||||||
|
std::vector<std::pair<float, std::string> > objects = mEngine->rayTest2(_from, _to, mask);
|
||||||
|
|
||||||
|
for (std::vector<std::pair<float, std::string> >::iterator it = objects.begin();
|
||||||
|
it != objects.end(); ++it)
|
||||||
|
{
|
||||||
|
if(ignorePathgrid && QString((*it).second.c_str()).contains(QRegExp("^Pathgrid")))
|
||||||
|
continue;
|
||||||
|
else if(ignoreObjects && QString((*it).second.c_str()).contains(QRegExp("^ref#")))
|
||||||
|
continue;
|
||||||
|
else if(ignoreHeightMap && QString((*it).second.c_str()).contains(QRegExp("^Height")))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
result = std::make_pair((*it).second, (*it).first);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// result.first is the object's referenceId
|
||||||
|
if(result.first == "")
|
||||||
|
return std::make_pair("", -1);
|
||||||
|
else
|
||||||
|
return std::make_pair(result.first, limit*result.second);
|
||||||
|
}
|
||||||
|
|
||||||
|
// tries to find the distance to the "top" of the closest object (ignores pathgrid points)
|
||||||
|
std::pair<std::string, float> PhysicsSystem::distToClosest(const Ogre::Vector3 &position,
|
||||||
|
Ogre::uint32 visibilityMask, const float limit)
|
||||||
|
{
|
||||||
|
const float thickness = 50; // arbitrary number
|
||||||
|
|
||||||
|
std::pair<std::string, float> resDown =
|
||||||
|
distToGround(Ogre::Vector3(position.x, position.y, position.z+thickness),
|
||||||
|
visibilityMask&(~CSVRender::Element_Pathgrid), limit+thickness);
|
||||||
|
|
||||||
|
if(resDown.first != "")
|
||||||
|
return std::make_pair(resDown.first, resDown.second-thickness);
|
||||||
|
else
|
||||||
|
return std::make_pair("", -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string PhysicsSystem::refIdToSceneNode(std::string referenceId, Ogre::SceneManager *sceneMgr)
|
std::string PhysicsSystem::refIdToSceneNode(std::string referenceId, Ogre::SceneManager *sceneMgr)
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
|
#include <OgrePlatform.h>
|
||||||
|
|
||||||
namespace Ogre
|
namespace Ogre
|
||||||
{
|
{
|
||||||
class Vector3;
|
class Vector3;
|
||||||
|
@ -73,7 +75,13 @@ namespace CSVWorld
|
||||||
std::pair<std::string, Ogre::Vector3> castRay(float mouseX,
|
std::pair<std::string, Ogre::Vector3> castRay(float mouseX,
|
||||||
float mouseY, Ogre::SceneManager *sceneMgr, Ogre::Camera *camera);
|
float mouseY, Ogre::SceneManager *sceneMgr, Ogre::Camera *camera);
|
||||||
|
|
||||||
std::string sceneNodeToRefId(std::string sceneNodeName);
|
std::pair<std::string, float> distToGround(const Ogre::Vector3 &position,
|
||||||
|
Ogre::uint32 visibilityMask, const float limit = 300000);
|
||||||
|
|
||||||
|
std::pair<std::string, float> distToClosest(const Ogre::Vector3 &position,
|
||||||
|
Ogre::uint32 visibilityMask, const float limit = 100.0f);
|
||||||
|
|
||||||
|
std::string refIdToSceneNode(std::string referenceId, Ogre::SceneManager *sceneMgr);
|
||||||
|
|
||||||
// for multi-scene manager per physics engine
|
// for multi-scene manager per physics engine
|
||||||
std::map<Ogre::SceneManager*, CSVRender::SceneWidget *> sceneWidgets();
|
std::map<Ogre::SceneManager*, CSVRender::SceneWidget *> sceneWidgets();
|
||||||
|
@ -83,9 +91,7 @@ namespace CSVWorld
|
||||||
void moveSceneNodeImpl(const std::string sceneNodeName,
|
void moveSceneNodeImpl(const std::string sceneNodeName,
|
||||||
const std::string referenceId, const Ogre::Vector3 &position);
|
const std::string referenceId, const Ogre::Vector3 &position);
|
||||||
|
|
||||||
void updateSelectionHighlight(std::string sceneNode, const Ogre::Vector3 &position);
|
std::string sceneNodeToRefId(std::string sceneNodeName);
|
||||||
|
|
||||||
std::string refIdToSceneNode(std::string referenceId, Ogre::SceneManager *sceneMgr);
|
|
||||||
|
|
||||||
Ogre::SceneManager *findSceneManager(std::string sceneNodeName);
|
Ogre::SceneManager *findSceneManager(std::string sceneNodeName);
|
||||||
};
|
};
|
||||||
|
|
|
@ -17,6 +17,7 @@ set(MATERIAL_FILES
|
||||||
objects.shader
|
objects.shader
|
||||||
objects.shaderset
|
objects.shaderset
|
||||||
openmw.configuration
|
openmw.configuration
|
||||||
|
pathgrid_pt.nif
|
||||||
quad.mat
|
quad.mat
|
||||||
quad.shader
|
quad.shader
|
||||||
quad.shaderset
|
quad.shaderset
|
||||||
|
|
BIN
files/materials/pathgrid_pt.nif
Normal file
BIN
files/materials/pathgrid_pt.nif
Normal file
Binary file not shown.
Loading…
Reference in a new issue