1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-01-20 12:53:52 +00:00

Merge branch 'objects'

This commit is contained in:
Marc Zinnschlag 2014-06-27 11:55:28 +02:00
commit 099c406226
7 changed files with 382 additions and 160 deletions

View file

@ -70,7 +70,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 lightingbright object
) )
opencs_units_noqt (view/world opencs_units_noqt (view/world

View file

@ -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;
}

View file

@ -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

View file

@ -7,194 +7,119 @@
#include "../../model/world/data.hpp" #include "../../model/world/data.hpp"
#include "../../model/world/idtable.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); setNavigation (&mOrbit);
mNode = getSceneManager()->getRootSceneNode()->createChildSceneNode();
mNode->setPosition (Ogre::Vector3 (0, 0, 0));
setModel();
QAbstractItemModel *referenceables = QAbstractItemModel *referenceables =
mData.getTableModel (CSMWorld::UniversalId::Type_Referenceables); mData.getTableModel (CSMWorld::UniversalId::Type_Referenceables);
connect (referenceables, SIGNAL (dataChanged (const QModelIndex&, const QModelIndex&)), connect (referenceables, SIGNAL (dataChanged (const QModelIndex&, const QModelIndex&)),
this, SLOT (ReferenceableDataChanged (const QModelIndex&, const QModelIndex&))); this, SLOT (referenceableDataChanged (const QModelIndex&, const QModelIndex&)));
connect (referenceables, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)), connect (referenceables, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)),
this, SLOT (ReferenceableAboutToBeRemoved (const QModelIndex&, int, int))); this, SLOT (referenceableAboutToBeRemoved (const QModelIndex&, int, int)));
}
void CSVRender::PreviewWidget::setModel() if (!referenceable)
{
if (mNode)
{ {
mObject.setNull(); QAbstractItemModel *references =
mData.getTableModel (CSMWorld::UniversalId::Type_References);
if (mReferenceableId.empty()) connect (references, SIGNAL (dataChanged (const QModelIndex&, const QModelIndex&)),
return; this, SLOT (referenceDataChanged (const QModelIndex&, const QModelIndex&)));
connect (references, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)),
int column = this, SLOT (referenceAboutToBeRemoved (const QModelIndex&, int, int)));
mData.getReferenceables().findColumnIndex (CSMWorld::Columns::ColumnId_Model);
int row = mData.getReferenceables().searchId (mReferenceableId);
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);
} }
} }
void CSVRender::PreviewWidget::adjust() void CSVRender::PreviewWidget::referenceableDataChanged (const QModelIndex& topLeft,
{
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) const QModelIndex& bottomRight)
{ {
if (mReferenceableId.empty()) if (mObject.referenceableDataChanged (topLeft, bottomRight))
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();
flagAsModified(); flagAsModified();
if (mObject.getReferenceId().empty())
{
CSMWorld::IdTable& referenceables = dynamic_cast<CSMWorld::IdTable&> (
*mData.getTableModel (CSMWorld::UniversalId::Type_Referenceables));
QModelIndex index = referenceables.getModelIndex (mObject.getReferenceableId(),
referenceables.findColumnIndex (CSMWorld::Columns::ColumnId_Modification));
if (referenceables.data (index).toInt()==CSMWorld::RecordBase::State_Deleted)
emit closeRequest();
} }
} }
void CSVRender::PreviewWidget::ReferenceableAboutToBeRemoved (const QModelIndex& parent, int start, void CSVRender::PreviewWidget::referenceableAboutToBeRemoved (const QModelIndex& parent, int start,
int end) int end)
{ {
if (mReferenceableId.empty()) if (mObject.referenceableAboutToBeRemoved (parent, start, end))
flagAsModified();
if (mObject.getReferenceableId().empty())
return; return;
CSMWorld::IdTable& referenceables = dynamic_cast<CSMWorld::IdTable&> ( CSMWorld::IdTable& referenceables = dynamic_cast<CSMWorld::IdTable&> (
*mData.getTableModel (CSMWorld::UniversalId::Type_Referenceables)); *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 (index.row()>=start && index.row()<=end)
{ {
if (mReferenceId.empty()) if (mObject.getReferenceId().empty())
{ {
// this is a preview for a referenceble // this is a preview for a referenceble
emit closeRequest(); emit closeRequest();
} }
else
{
// this is a preview for a reference
mObject.setNull();
flagAsModified();
}
} }
} }
void CSVRender::PreviewWidget::ReferenceDataChanged (const QModelIndex& topLeft, void CSVRender::PreviewWidget::referenceDataChanged (const QModelIndex& topLeft,
const QModelIndex& bottomRight) const QModelIndex& bottomRight)
{ {
if (mReferenceId.empty()) if (mObject.referenceDataChanged (topLeft, bottomRight))
flagAsModified();
if (mObject.getReferenceId().empty())
return; return;
CSMWorld::IdTable& references = dynamic_cast<CSMWorld::IdTable&> ( CSMWorld::IdTable& references = dynamic_cast<CSMWorld::IdTable&> (
*mData.getTableModel (CSMWorld::UniversalId::Type_References)); *mData.getTableModel (CSMWorld::UniversalId::Type_References));
// check for deleted state
{
QModelIndex index = references.getModelIndex (mObject.getReferenceId(),
references.findColumnIndex (CSMWorld::Columns::ColumnId_Modification));
if (references.data (index).toInt()==CSMWorld::RecordBase::State_Deleted)
{
emit closeRequest();
return;
}
}
int columnIndex = references.findColumnIndex (CSMWorld::Columns::ColumnId_ReferenceableId); 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()) 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()) if (index.column()>=topLeft.column() && index.column()<=bottomRight.row())
{ emit referenceableIdChanged (mObject.getReferenceableId());
mReferenceableId = references.data (index).toString().toUtf8().constData();
emit referenceableIdChanged (mReferenceableId);
setModel();
}
flagAsModified();
}
} }
void CSVRender::PreviewWidget::ReferenceAboutToBeRemoved (const QModelIndex& parent, int start, void CSVRender::PreviewWidget::referenceAboutToBeRemoved (const QModelIndex& parent, int start,
int end) int end)
{ {
if (mReferenceId.empty()) if (mObject.getReferenceId().empty())
return; return;
CSMWorld::IdTable& references = dynamic_cast<CSMWorld::IdTable&> ( CSMWorld::IdTable& references = dynamic_cast<CSMWorld::IdTable&> (
*mData.getTableModel (CSMWorld::UniversalId::Type_References)); *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) if (index.row()>=start && index.row()<=end)
emit closeRequest(); emit closeRequest();

View file

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

View file

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

View file

@ -115,12 +115,12 @@ void CSVWorld::Table::contextMenuEvent (QContextMenuEvent *event)
if (selectedRows.size()==1) if (selectedRows.size()==1)
{ {
int row = selectedRows.begin()->row();
row = mProxyModel->mapToSource (mProxyModel->index (row, 0)).row();
if (mModel->getFeatures() & CSMWorld::IdTable::Feature_View) if (mModel->getFeatures() & CSMWorld::IdTable::Feature_View)
{ {
int row = selectedRows.begin()->row();
row = mProxyModel->mapToSource (mProxyModel->index (row, 0)).row();
CSMWorld::UniversalId id = mModel->view (row).first; CSMWorld::UniversalId id = mModel->view (row).first;
int index = mDocument.getData().getCells().searchId (id.getId()); int index = mDocument.getData().getCells().searchId (id.getId());
@ -132,7 +132,16 @@ void CSVWorld::Table::contextMenuEvent (QContextMenuEvent *event)
} }
if (mModel->getFeatures() & CSMWorld::IdTable::Feature_Preview) if (mModel->getFeatures() & CSMWorld::IdTable::Feature_Preview)
menu.addAction (mPreviewAction); {
QModelIndex index = mModel->index (row,
mModel->findColumnIndex (CSMWorld::Columns::ColumnId_Modification));
CSMWorld::RecordBase::State state = static_cast<CSMWorld::RecordBase::State> (
mModel->data (index).toInt());
if (state!=CSMWorld::RecordBase::State_Deleted)
menu.addAction (mPreviewAction);
}
} }
menu.exec (event->globalPos()); menu.exec (event->globalPos());
@ -377,7 +386,12 @@ void CSVWorld::Table::previewRecord()
{ {
std::string id = getUniversalId (selectedRows.begin()->row()).getId(); std::string id = getUniversalId (selectedRows.begin()->row()).getId();
emit editRequest (CSMWorld::UniversalId (CSMWorld::UniversalId::Type_Preview, id) , ""); QModelIndex index = mModel->getModelIndex (id,
mModel->findColumnIndex (CSMWorld::Columns::ColumnId_Modification));
if (mModel->data (index)!=CSMWorld::RecordBase::State_Deleted)
emit editRequest (CSMWorld::UniversalId (CSMWorld::UniversalId::Type_Preview, id),
"");
} }
} }