1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-01-27 12:35:46 +00:00
OpenMW/apps/openmw/mwrender/objects.cpp

299 lines
8.1 KiB
C++
Raw Normal View History

2011-10-31 23:59:16 -04:00
#include "objects.hpp"
2012-02-06 10:41:13 +01:00
2013-03-29 09:04:02 +01:00
#include <cmath>
#include <osg/io_utils>
#include <osg/Group>
#include <osg/Geode>
#include <osg/PositionAttitudeTransform>
#include <osg/ComputeBoundsVisitor>
2012-02-06 10:41:13 +01:00
#include <osgParticle/ParticleSystem>
#include <osgParticle/ParticleProcessor>
2014-02-23 20:11:05 +01:00
// light
#include <components/sceneutil/lightmanager.hpp>
#include <components/resource/scenemanager.hpp>
#include <components/sceneutil/visitor.hpp>
#include <components/sceneutil/util.hpp>
#include "../mwworld/ptr.hpp"
2012-07-30 23:28:14 +04:00
#include "../mwworld/class.hpp"
2014-02-23 20:11:05 +01:00
#include "../mwworld/cellstore.hpp"
2012-04-03 15:13:47 +02:00
#include "renderconst.hpp"
#include "animation.hpp"
2015-04-15 22:11:38 +02:00
#include "npcanimation.hpp"
2015-04-19 03:05:47 +02:00
#include "creatureanimation.hpp"
namespace
{
/// Removes all particle systems and related nodes in a subgraph.
class RemoveParticlesVisitor : public osg::NodeVisitor
{
public:
RemoveParticlesVisitor()
: osg::NodeVisitor(TRAVERSE_ALL_CHILDREN)
{ }
virtual void apply(osg::Node &node)
{
if (dynamic_cast<osgParticle::ParticleSystem*>(&node) || dynamic_cast<osgParticle::ParticleProcessor*>(&node))
mToRemove.push_back(&node);
traverse(node);
}
2011-10-31 23:59:16 -04:00
void remove()
{
for (std::vector<osg::ref_ptr<osg::Node> >::iterator it = mToRemove.begin(); it != mToRemove.end(); ++it)
{
osg::Node* node = *it;
if (node->getNumParents())
node->getParent(0)->removeChild(node);
}
mToRemove.clear();
}
private:
std::vector<osg::ref_ptr<osg::Node> > mToRemove;
};
}
2011-10-31 23:59:16 -04:00
namespace MWRender
{
Objects::Objects(Resource::ResourceSystem* resourceSystem, osg::ref_ptr<osg::Group> rootNode)
: mResourceSystem(resourceSystem)
, mRootNode(rootNode)
2012-02-06 10:41:13 +01:00
{
}
Objects::~Objects()
{
for(PtrAnimationMap::iterator iter = mObjects.begin();iter != mObjects.end();++iter)
delete iter->second;
mObjects.clear();
for (CellMap::iterator iter = mCellSceneNodes.begin(); iter != mCellSceneNodes.end(); ++iter)
iter->second->getParent(0)->removeChild(iter->second);
mCellSceneNodes.clear();
2011-11-17 17:10:27 -05:00
}
2012-02-06 10:41:13 +01:00
2013-08-07 03:51:57 -07:00
void Objects::insertBegin(const MWWorld::Ptr& ptr)
2012-02-06 10:41:13 +01:00
{
osg::ref_ptr<osg::Group> cellnode;
CellMap::iterator found = mCellSceneNodes.find(ptr.getCell());
if (found == mCellSceneNodes.end())
2011-11-04 21:57:39 -04:00
{
cellnode = new osg::Group;
mRootNode->addChild(cellnode);
2011-11-04 21:57:39 -04:00
mCellSceneNodes[ptr.getCell()] = cellnode;
}
else
cellnode = found->second;
2011-11-04 21:48:52 -04:00
osg::ref_ptr<osg::PositionAttitudeTransform> insert (new osg::PositionAttitudeTransform);
cellnode->addChild(insert);
2012-03-24 22:03:08 -04:00
const float *f = ptr.getRefData().getPosition().pos;
insert->setPosition(osg::Vec3(f[0], f[1], f[2]));
insert->setScale(osg::Vec3(ptr.getCellRef().getScale(), ptr.getCellRef().getScale(), ptr.getCellRef().getScale()));
2011-11-04 21:57:39 -04:00
// Convert MW rotation to a quaternion:
f = ptr.getCellRef().getPosition().rot;
2011-11-04 21:57:39 -04:00
// Rotate around X axis
osg::Quat xr(-f[0], osg::Vec3(1,0,0));
2011-11-04 21:57:39 -04:00
// Rotate around Y axis
osg::Quat yr(-f[1], osg::Vec3(0,1,0));
2011-11-04 21:57:39 -04:00
// Rotate around Z axis
osg::Quat zr(-f[2], osg::Vec3(0,0,1));
2012-02-06 10:41:13 +01:00
// Rotates first around z, then y, then x
insert->setAttitude(zr*yr*xr);
// TODO: actors rotate around z only
2011-11-02 22:41:48 -04:00
ptr.getRefData().setBaseNode(insert);
2011-10-31 23:59:16 -04:00
}
2012-02-06 10:41:13 +01:00
void Objects::insertModel(const MWWorld::Ptr &ptr, const std::string &mesh, bool animated, bool allowLight)
2012-02-06 10:41:13 +01:00
{
2013-08-07 03:51:57 -07:00
insertBegin(ptr);
std::auto_ptr<ObjectAnimation> anim (new ObjectAnimation(ptr, mesh, mResourceSystem));
if (anim->getObjectRoot())
anim->getObjectRoot()->addCullCallback(new SceneUtil::LightListCallback);
if (ptr.getTypeName() == typeid(ESM::Light).name() && allowLight)
2011-11-04 21:57:39 -04:00
{
SceneUtil::FindByNameVisitor visitor("AttachLight");
ptr.getRefData().getBaseNode()->accept(visitor);
osg::Group* attachTo = NULL;
if (visitor.mFoundNode)
{
attachTo = visitor.mFoundNode;
}
else
{
osg::ComputeBoundsVisitor computeBound;
osg::Group* objectRoot = anim->getOrCreateObjectRoot();
objectRoot->accept(computeBound);
2015-04-13 17:30:32 +02:00
// PositionAttitudeTransform seems to be slightly faster than MatrixTransform
osg::ref_ptr<osg::PositionAttitudeTransform> trans(new osg::PositionAttitudeTransform);
trans->setPosition(computeBound.getBoundingBox().center());
objectRoot->addChild(trans);
2015-04-13 17:30:32 +02:00
attachTo = trans;
}
const ESM::Light* esmLight = ptr.get<ESM::Light>()->mBase;
osg::ref_ptr<SceneUtil::LightSource> lightSource = new SceneUtil::LightSource;
osg::Light* light = new osg::Light;
lightSource->setLight(light);
2015-04-17 01:23:37 +02:00
float realRadius = esmLight->mData.mRadius;
lightSource->setRadius(realRadius);
2015-04-17 01:23:37 +02:00
light->setLinearAttenuation(10.f/(esmLight->mData.mRadius*2.f));
//light->setLinearAttenuation(0.05);
light->setConstantAttenuation(0.f);
light->setDiffuse(SceneUtil::colourFromRGB(esmLight->mData.mColor));
light->setAmbient(osg::Vec4f(0,0,0,1));
light->setSpecular(osg::Vec4f(0,0,0,0));
attachTo->addChild(lightSource);
}
if (!allowLight)
{
RemoveParticlesVisitor visitor;
anim->getObjectRoot()->accept(visitor);
visitor.remove();
2011-11-04 21:57:39 -04:00
}
2013-02-23 04:06:05 +01:00
mObjects.insert(std::make_pair(ptr, anim.release()));
}
void Objects::insertCreature(const MWWorld::Ptr &ptr, const std::string &mesh, bool weaponsShields)
{
insertBegin(ptr);
// CreatureAnimation
2015-04-19 03:05:47 +02:00
std::auto_ptr<Animation> anim;
if (weaponsShields)
anim.reset(new CreatureWeaponAnimation(ptr, mesh, mResourceSystem));
else
anim.reset(new CreatureAnimation(ptr, mesh, mResourceSystem));
mObjects.insert(std::make_pair(ptr, anim.release()));
}
void Objects::insertNPC(const MWWorld::Ptr &ptr)
{
2015-04-15 22:11:38 +02:00
insertBegin(ptr);
2015-04-15 22:11:38 +02:00
std::auto_ptr<NpcAnimation> anim (new NpcAnimation(ptr, osg::ref_ptr<osg::Group>(ptr.getRefData().getBaseNode()), mResourceSystem, 0));
mObjects.insert(std::make_pair(ptr, anim.release()));
2011-10-31 23:59:16 -04:00
}
2012-02-06 10:41:13 +01:00
bool Objects::deleteObject (const MWWorld::Ptr& ptr)
2012-02-06 10:41:13 +01:00
{
if(!ptr.getRefData().getBaseNode())
return true;
2012-04-28 20:42:53 +02:00
PtrAnimationMap::iterator iter = mObjects.find(ptr);
if(iter != mObjects.end())
2012-02-06 10:41:13 +01:00
{
delete iter->second;
mObjects.erase(iter);
2012-02-06 10:41:13 +01:00
ptr.getRefData().getBaseNode()->getParent(0)->removeChild(ptr.getRefData().getBaseNode());
ptr.getRefData().setBaseNode(NULL);
return true;
}
return false;
2011-10-31 23:59:16 -04:00
}
2011-11-02 00:13:33 -04:00
2011-11-04 21:48:52 -04:00
void Objects::removeCell(const MWWorld::CellStore* store)
2012-02-06 10:41:13 +01:00
{
for(PtrAnimationMap::iterator iter = mObjects.begin();iter != mObjects.end();)
2011-11-04 21:48:52 -04:00
{
if(iter->first.getCell() == store)
{
delete iter->second;
mObjects.erase(iter++);
}
else
++iter;
2011-11-04 21:48:52 -04:00
}
CellMap::iterator cell = mCellSceneNodes.find(store);
if(cell != mCellSceneNodes.end())
{
cell->second->getParent(0)->removeChild(cell->second);
mCellSceneNodes.erase(cell);
}
}
2012-04-02 19:37:24 +02:00
2015-04-19 01:57:52 +02:00
void Objects::update(float dt)
2012-04-19 20:59:57 +02:00
{
PtrAnimationMap::const_iterator it = mObjects.begin();
for(;it != mObjects.end();++it)
it->second->runAnimation(dt);
2012-07-11 02:31:03 +02:00
}
2012-07-30 23:28:14 +04:00
void Objects::updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr &cur)
2012-07-30 23:28:14 +04:00
{
/*
2012-07-30 23:28:14 +04:00
Ogre::SceneNode *node;
MWWorld::CellStore *newCell = cur.getCell();
2012-07-30 23:28:14 +04:00
if(mCellSceneNodes.find(newCell) == mCellSceneNodes.end()) {
2013-02-26 14:01:10 +01:00
node = mRootNode->createChildSceneNode();
2012-07-30 23:28:14 +04:00
mCellSceneNodes[newCell] = node;
} else {
node = mCellSceneNodes[newCell];
}
node->addChild(cur.getRefData().getBaseNode());
PtrAnimationMap::iterator iter = mObjects.find(old);
if(iter != mObjects.end())
{
ObjectAnimation *anim = iter->second;
mObjects.erase(iter);
anim->updatePtr(cur);
mObjects[cur] = anim;
}
*/
2012-07-30 23:28:14 +04:00
}
Animation* Objects::getAnimation(const MWWorld::Ptr &ptr)
{
PtrAnimationMap::const_iterator iter = mObjects.find(ptr);
if(iter != mObjects.end())
return iter->second;
return NULL;
2012-07-30 23:28:14 +04:00
}
}