refactored object rendering into a separate class

deque
Marc Zinnschlag 11 years ago
parent 30f8e279ed
commit 0c1ad54e68

@ -70,7 +70,7 @@ opencs_units (view/render
opencs_units_noqt (view/render
navigation navigation1st navigationfree navigationorbit lighting lightingday lightingnight
lightingbright
lightingbright object
)
opencs_units_noqt (view/world

@ -0,0 +1,217 @@
#include "object.hpp"
#include <OgreSceneManager.h>
#include <OgreSceneNode.h>
#include <OgreEntity.h>
#include "../../model/world/data.hpp"
#include "../../model/world/ref.hpp"
#include "../../model/world/refidcollection.hpp"
void CSVRender::Object::clearSceneNode (Ogre::SceneNode *node)
{
for (Ogre::SceneNode::ObjectIterator iter = node->getAttachedObjectIterator();
iter.hasMoreElements(); )
{
Ogre::MovableObject* object = dynamic_cast<Ogre::MovableObject*> (iter.getNext());
node->getCreator()->destroyMovableObject (object);
}
for (Ogre::SceneNode::ChildNodeIterator iter = node->getChildIterator();
iter.hasMoreElements(); )
{
Ogre::SceneNode* childNode = dynamic_cast<Ogre::SceneNode*> (iter.getNext());
clearSceneNode (childNode);
node->getCreator()->destroySceneNode (childNode);
}
}
void CSVRender::Object::clear()
{
mObject.setNull();
clearSceneNode (mBase);
}
void CSVRender::Object::update()
{
clear();
std::string model;
int error = 0; // 1 referemceanöe does not exist, 2 referenceable does not specify a mesh
const CSMWorld::RefIdCollection& referenceables = mData.getReferenceables();
int index = referenceables.searchId (mReferenceableId);
if (index==-1)
error = 1;
else
{
// xxx check for Deleted state (error 1)
model = referenceables.getData (index,
referenceables.findColumnIndex (CSMWorld::Columns::ColumnId_Model)).
toString().toUtf8().constData();
if (model.empty())
error = 2;
}
if (error)
{
Ogre::Entity* entity = mBase->getCreator()->createEntity (Ogre::SceneManager::PT_CUBE);
entity->setMaterialName("BaseWhite"); /// \todo adjust material according to error
mBase->attachObject (entity);
}
else
{
mObject = NifOgre::Loader::createObjects (mBase, "Meshes\\" + model);
}
}
void CSVRender::Object::adjust()
{
if (mReferenceId.empty())
return;
const CSMWorld::CellRef& reference = getReference();
// position
if (!mForceBaseToZero)
{
Ogre::Vector3 (reference.mPos.pos[0], reference.mPos.pos[1], reference.mPos.pos[2]);
mBase->setPosition (Ogre::Vector3 (
reference.mPos.pos[0], reference.mPos.pos[1], reference.mPos.pos[2]));
}
// orientation
Ogre::Quaternion xr (Ogre::Radian (-reference.mPos.pos[0]), Ogre::Vector3::UNIT_X);
Ogre::Quaternion yr (Ogre::Radian (-reference.mPos.pos[1]), Ogre::Vector3::UNIT_Y);
Ogre::Quaternion zr (Ogre::Radian (-reference.mPos.pos[2]), Ogre::Vector3::UNIT_Z);
mBase->setOrientation (xr*yr*zr);
// scale
mBase->setScale (reference.mScale, reference.mScale, reference.mScale);
}
const CSMWorld::CellRef& CSVRender::Object::getReference() const
{
if (mReferenceId.empty())
throw std::logic_error ("object does not represent a reference");
return mData.getReferences().getRecord (mReferenceId).get();
}
CSVRender::Object::Object (const CSMWorld::Data& data, Ogre::SceneNode *cellNode,
const std::string& id, bool referenceable, bool forceBaseToZero)
: mData (data), mBase (0), mForceBaseToZero (forceBaseToZero)
{
mBase = cellNode->createChildSceneNode();
if (referenceable)
{
mReferenceableId = id;
}
else
{
mReferenceId = id;
mReferenceableId = getReference().mRefID;
}
update();
adjust();
}
CSVRender::Object::~Object()
{
clear();
if (mBase)
mBase->getCreator()->destroySceneNode (mBase);
}
bool CSVRender::Object::ReferenceableDataChanged (const QModelIndex& topLeft,
const QModelIndex& bottomRight)
{
const CSMWorld::RefIdCollection& referenceables = mData.getReferenceables();
int index = referenceables.searchId (mReferenceableId);
if (index!=-1 && index>=topLeft.row() && index<=bottomRight.row())
{
update();
adjust();
return true;
}
return false;
}
bool CSVRender::Object::ReferenceableAboutToBeRemoved (const QModelIndex& parent, int start,
int end)
{
const CSMWorld::RefIdCollection& referenceables = mData.getReferenceables();
int index = referenceables.searchId (mReferenceableId);
if (index!=-1 && index>=start && index<=end)
{
// Deletion of referenceable-type objects is handled outside of Object.
if (!mReferenceId.empty())
{
update();
adjust();
return true;
}
}
return false;
}
bool CSVRender::Object::ReferenceDataChanged (const QModelIndex& topLeft,
const QModelIndex& bottomRight)
{
if (mReferenceId.empty())
return false;
const CSMWorld::RefCollection& references = mData.getReferences();
int index = references.searchId (mReferenceId);
if (index!=-1 && index>=topLeft.row() && index<=bottomRight.row())
{
int columnIndex =
references.findColumnIndex (CSMWorld::Columns::ColumnId_ReferenceableId);
if (columnIndex>=topLeft.column() && columnIndex<=bottomRight.row())
{
mReferenceableId =
references.getData (index, columnIndex).toString().toUtf8().constData();
update();
}
adjust();
return true;
}
return false;
}
std::string CSVRender::Object::getReferenceId() const
{
return mReferenceId;
}
std::string CSVRender::Object::getReferenceableId() const
{
return mReferenceableId;
}

@ -0,0 +1,80 @@
#ifndef OPENCS_VIEW_OBJECT_H
#define OPENCS_VIEW_OBJECT_H
#include <components/nifogre/ogrenifloader.hpp>
class QModelIndex;
namespace Ogre
{
class SceneNode;
}
namespace CSMWorld
{
class Data;
class CellRef;
}
namespace CSVRender
{
class Object
{
const CSMWorld::Data& mData;
std::string mReferenceId;
std::string mReferenceableId;
Ogre::SceneNode *mBase;
NifOgre::ObjectScenePtr mObject;
bool mForceBaseToZero;
/// Not implemented
Object (const Object&);
/// Not implemented
Object& operator= (const Object&);
/// Destroy all scene nodes and movable objects attached to node.
static void clearSceneNode (Ogre::SceneNode *node);
/// Remove object from node (includes deleting)
void clear();
/// Update model
void update();
/// Adjust position, orientation and scale
void adjust();
/// Throws an exception if *this was constructed with referenceable
const CSMWorld::CellRef& getReference() const;
public:
Object (const CSMWorld::Data& data, Ogre::SceneNode *cellNode,
const std::string& id, bool referenceable, bool forceBaseToZero = false);
/// \param forceBaseToZero If this is a reference ignore the coordinates and place
/// it at 0, 0, 0 instead.
~Object();
/// \return Did this call result in a modification of the visual representation of
/// this object?
bool ReferenceableDataChanged (const QModelIndex& topLeft,
const QModelIndex& bottomRight);
/// \return Did this call result in a modification of the visual representation of
/// this object?
bool ReferenceableAboutToBeRemoved (const QModelIndex& parent, int start, int end);
/// \return Did this call result in a modification of the visual representation of
/// this object?
bool ReferenceDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight);
/// Returns an empty string if this is a refereceable-type object.
std::string getReferenceId() const;
std::string getReferenceableId() const;
};
}
#endif

@ -7,15 +7,13 @@
#include "../../model/world/data.hpp"
#include "../../model/world/idtable.hpp"
void CSVRender::PreviewWidget::setup()
CSVRender::PreviewWidget::PreviewWidget (CSMWorld::Data& data,
const std::string& id, bool referenceable, QWidget *parent)
: SceneWidget (parent), mData (data),
mObject (data, getSceneManager()->getRootSceneNode(), id, referenceable, true)
{
setNavigation (&mOrbit);
mNode = getSceneManager()->getRootSceneNode()->createChildSceneNode();
mNode->setPosition (Ogre::Vector3 (0, 0, 0));
setModel();
QAbstractItemModel *referenceables =
mData.getTableModel (CSMWorld::UniversalId::Type_Referenceables);
@ -23,142 +21,57 @@ void CSVRender::PreviewWidget::setup()
this, SLOT (ReferenceableDataChanged (const QModelIndex&, const QModelIndex&)));
connect (referenceables, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)),
this, SLOT (ReferenceableAboutToBeRemoved (const QModelIndex&, int, int)));
}
void CSVRender::PreviewWidget::setModel()
{
if (mNode)
if (!referenceable)
{
mObject.setNull();
if (mReferenceableId.empty())
return;
int column =
mData.getReferenceables().findColumnIndex (CSMWorld::Columns::ColumnId_Model);
int row = mData.getReferenceables().searchId (mReferenceableId);
QAbstractItemModel *references =
mData.getTableModel (CSMWorld::UniversalId::Type_References);
if (row==-1)
return;
QVariant value = mData.getReferenceables().getData (row, column);
if (!value.isValid())
return;
std::string model = value.toString().toUtf8().constData();
if (model.empty())
return;
mObject = NifOgre::Loader::createObjects (mNode, "Meshes\\" + model);
connect (references, SIGNAL (dataChanged (const QModelIndex&, const QModelIndex&)),
this, SLOT (ReferenceDataChanged (const QModelIndex&, const QModelIndex&)));
connect (references, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)),
this, SLOT (ReferenceAboutToBeRemoved (const QModelIndex&, int, int)));
}
}
void CSVRender::PreviewWidget::adjust()
{
if (mNode)
{
int row = mData.getReferences().getIndex (mReferenceId);
float scale = mData.getReferences().getData (row, mData.getReferences().
findColumnIndex (CSMWorld::Columns::ColumnId_Scale)).toFloat();
float rotX = mData.getReferences().getData (row, mData.getReferences().
findColumnIndex (CSMWorld::Columns::ColumnId_PositionXRot)).toFloat();
float rotY = mData.getReferences().getData (row, mData.getReferences().
findColumnIndex (CSMWorld::Columns::ColumnId_PositionYRot)).toFloat();
float rotZ = mData.getReferences().getData (row, mData.getReferences().
findColumnIndex (CSMWorld::Columns::ColumnId_PositionZRot)).toFloat();
mNode->setScale (scale, scale, scale);
Ogre::Quaternion xr (Ogre::Radian(-rotX), Ogre::Vector3::UNIT_X);
Ogre::Quaternion yr (Ogre::Radian(-rotY), Ogre::Vector3::UNIT_Y);
Ogre::Quaternion zr (Ogre::Radian(-rotZ), Ogre::Vector3::UNIT_Z);
mNode->setOrientation (xr*yr*zr);
}
}
CSVRender::PreviewWidget::PreviewWidget (CSMWorld::Data& data,
const std::string& referenceableId, QWidget *parent)
: SceneWidget (parent), mData (data), mNode (0), mReferenceableId (referenceableId)
{
setup();
}
CSVRender::PreviewWidget::PreviewWidget (CSMWorld::Data& data,
const std::string& referenceableId, const std::string& referenceId, QWidget *parent)
: SceneWidget (parent), mData (data), mReferenceableId (referenceableId),
mReferenceId (referenceId)
{
setup();
adjust();
QAbstractItemModel *references =
mData.getTableModel (CSMWorld::UniversalId::Type_References);
connect (references, SIGNAL (dataChanged (const QModelIndex&, const QModelIndex&)),
this, SLOT (ReferenceDataChanged (const QModelIndex&, const QModelIndex&)));
connect (references, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)),
this, SLOT (ReferenceAboutToBeRemoved (const QModelIndex&, int, int)));
}
void CSVRender::PreviewWidget::ReferenceableDataChanged (const QModelIndex& topLeft,
const QModelIndex& bottomRight)
{
if (mReferenceableId.empty())
return;
CSMWorld::IdTable& referenceables = dynamic_cast<CSMWorld::IdTable&> (
*mData.getTableModel (CSMWorld::UniversalId::Type_Referenceables));
QModelIndex index = referenceables.getModelIndex (mReferenceableId, 0);
if (index.row()>=topLeft.row() && index.row()<=bottomRight.row())
{
/// \todo possible optimisation; check columns and only update if relevant columns have
/// changed
setModel();
if (mObject.ReferenceableDataChanged (topLeft, bottomRight))
flagAsModified();
}
}
void CSVRender::PreviewWidget::ReferenceableAboutToBeRemoved (const QModelIndex& parent, int start,
int end)
{
if (mReferenceableId.empty())
if (mObject.ReferenceableAboutToBeRemoved (parent, start, end))
flagAsModified();
if (mObject.getReferenceableId().empty())
return;
CSMWorld::IdTable& referenceables = dynamic_cast<CSMWorld::IdTable&> (
*mData.getTableModel (CSMWorld::UniversalId::Type_Referenceables));
QModelIndex index = referenceables.getModelIndex (mReferenceableId, 0);
QModelIndex index = referenceables.getModelIndex (mObject.getReferenceableId(), 0);
if (index.row()>=start && index.row()<=end)
{
if (mReferenceId.empty())
if (mObject.getReferenceId().empty())
{
// this is a preview for a referenceble
emit closeRequest();
}
else
{
// this is a preview for a reference
mObject.setNull();
flagAsModified();
}
}
}
void CSVRender::PreviewWidget::ReferenceDataChanged (const QModelIndex& topLeft,
const QModelIndex& bottomRight)
{
if (mReferenceId.empty())
if (mObject.ReferenceDataChanged (topLeft, bottomRight))
flagAsModified();
if (mObject.getReferenceId().empty())
return;
CSMWorld::IdTable& references = dynamic_cast<CSMWorld::IdTable&> (
@ -166,35 +79,23 @@ void CSVRender::PreviewWidget::ReferenceDataChanged (const QModelIndex& topLeft,
int columnIndex = references.findColumnIndex (CSMWorld::Columns::ColumnId_ReferenceableId);
QModelIndex index = references.getModelIndex (mReferenceId, columnIndex);
QModelIndex index = references.getModelIndex (mObject.getReferenceId(), columnIndex);
if (index.row()>=topLeft.row() && index.row()<=bottomRight.row())
{
/// \todo possible optimisation; check columns and only update if relevant columns have
/// changed
adjust();
if (index.column()>=topLeft.column() && index.column()<=bottomRight.row())
{
mReferenceableId = references.data (index).toString().toUtf8().constData();
emit referenceableIdChanged (mReferenceableId);
setModel();
}
flagAsModified();
}
emit referenceableIdChanged (mObject.getReferenceableId());
}
void CSVRender::PreviewWidget::ReferenceAboutToBeRemoved (const QModelIndex& parent, int start,
int end)
{
if (mReferenceId.empty())
if (mObject.getReferenceId().empty())
return;
CSMWorld::IdTable& references = dynamic_cast<CSMWorld::IdTable&> (
*mData.getTableModel (CSMWorld::UniversalId::Type_References));
QModelIndex index = references.getModelIndex (mReferenceId, 0);
QModelIndex index = references.getModelIndex (mObject.getReferenceId(), 0);
if (index.row()>=start && index.row()<=end)
emit closeRequest();

@ -1,11 +1,10 @@
#ifndef OPENCS_VIEW_PREVIEWWIDGET_H
#define OPENCS_VIEW_PREVIEWWIDGET_H
#include <components/nifogre/ogrenifloader.hpp>
#include "scenewidget.hpp"
#include "navigationorbit.hpp"
#include "object.hpp"
class QModelIndex;
@ -22,26 +21,13 @@ namespace CSVRender
CSMWorld::Data& mData;
CSVRender::NavigationOrbit mOrbit;
NifOgre::ObjectScenePtr mObject;
Ogre::SceneNode *mNode;
std::string mReferenceId;
std::string mReferenceableId;
void setup();
void setModel();
void adjust();
///< Adjust referenceable preview according to the reference
Object mObject;
public:
PreviewWidget (CSMWorld::Data& data, const std::string& referenceableId,
PreviewWidget (CSMWorld::Data& data, const std::string& id, bool referenceable,
QWidget *parent = 0);
PreviewWidget (CSMWorld::Data& data, const std::string& referenceableId,
const std::string& referenceId, QWidget *parent = 0);
signals:
void closeRequest();

@ -23,10 +23,10 @@ CSVWorld::PreviewSubView::PreviewSubView (const CSMWorld::UniversalId& id, CSMDo
referenceableIdChanged (referenceableId);
mScene =
new CSVRender::PreviewWidget (document.getData(), referenceableId, id.getId(), this);
new CSVRender::PreviewWidget (document.getData(), id.getId(), false, this);
}
else
mScene = new CSVRender::PreviewWidget (document.getData(), id.getId(), this);
mScene = new CSVRender::PreviewWidget (document.getData(), id.getId(), true, this);
SceneToolbar *toolbar = new SceneToolbar (48+6, this);

Loading…
Cancel
Save