mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-03-03 03:49:41 +00:00
Use Animation-derived objects for generic objects
This commit is contained in:
parent
a9dca21d05
commit
3555476dfd
5 changed files with 217 additions and 326 deletions
|
@ -34,11 +34,10 @@ namespace MWClass
|
|||
|
||||
MWRender::Objects& objects = renderingInterface.getObjects();
|
||||
objects.insertBegin(ptr, ptr.getRefData().isEnabled(), false);
|
||||
|
||||
if (!model.empty())
|
||||
objects.insertMesh(ptr, "meshes\\" + model, true);
|
||||
if(!model.empty())
|
||||
objects.insertMesh(ptr, "meshes\\" + model);
|
||||
else
|
||||
objects.insertLight(ptr);
|
||||
objects.insertMesh(ptr, "");
|
||||
}
|
||||
|
||||
void Light::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <OgreSubMesh.h>
|
||||
#include <OgreSceneManager.h>
|
||||
#include <OgreControllerManager.h>
|
||||
#include <OgreStaticGeometry.h>
|
||||
|
||||
#include <libs/openengine/ogre/lights.hpp>
|
||||
|
||||
|
@ -21,6 +22,8 @@
|
|||
#include "../mwworld/class.hpp"
|
||||
#include "../mwworld/fallback.hpp"
|
||||
|
||||
#include "renderconst.hpp"
|
||||
|
||||
namespace MWRender
|
||||
{
|
||||
|
||||
|
@ -91,6 +94,12 @@ void Animation::setObjectRoot(const std::string &model, bool baseonly)
|
|||
{
|
||||
OgreAssert(mAnimSources.empty(), "Setting object root while animation sources are set!");
|
||||
|
||||
mSkelBase = NULL;
|
||||
destroyObjectList(mInsert->getCreator(), mObjectRoot);
|
||||
|
||||
if(model.empty())
|
||||
return;
|
||||
|
||||
std::string mdlname = Misc::StringUtils::lowerCase(model);
|
||||
std::string::size_type p = mdlname.rfind('\\');
|
||||
if(p == std::string::npos)
|
||||
|
@ -105,9 +114,6 @@ void Animation::setObjectRoot(const std::string &model, bool baseonly)
|
|||
Misc::StringUtils::toLower(mdlname);
|
||||
}
|
||||
|
||||
mSkelBase = NULL;
|
||||
destroyObjectList(mInsert->getCreator(), mObjectRoot);
|
||||
|
||||
mObjectRoot = (!baseonly ? NifOgre::Loader::createObjects(mInsert, mdlname) :
|
||||
NifOgre::Loader::createObjectBase(mInsert, mdlname));
|
||||
if(mObjectRoot.mSkelBase)
|
||||
|
@ -157,16 +163,18 @@ void Animation::setObjectRoot(const std::string &model, bool baseonly)
|
|||
class VisQueueSet {
|
||||
Ogre::uint32 mVisFlags;
|
||||
Ogre::uint8 mSolidQueue, mTransQueue;
|
||||
Ogre::Real mDist;
|
||||
|
||||
public:
|
||||
VisQueueSet(Ogre::uint32 visflags, Ogre::uint8 solidqueue, Ogre::uint8 transqueue)
|
||||
: mVisFlags(visflags), mSolidQueue(solidqueue), mTransQueue(transqueue)
|
||||
VisQueueSet(Ogre::uint32 visflags, Ogre::uint8 solidqueue, Ogre::uint8 transqueue, Ogre::Real dist)
|
||||
: mVisFlags(visflags), mSolidQueue(solidqueue), mTransQueue(transqueue), mDist(dist)
|
||||
{ }
|
||||
|
||||
void operator()(Ogre::Entity *entity) const
|
||||
{
|
||||
if(mVisFlags != 0)
|
||||
entity->setVisibilityFlags(mVisFlags);
|
||||
entity->setRenderingDistance(mDist);
|
||||
|
||||
unsigned int numsubs = entity->getNumSubEntities();
|
||||
for(unsigned int i = 0;i < numsubs;++i)
|
||||
|
@ -180,17 +188,18 @@ public:
|
|||
{
|
||||
if(mVisFlags != 0)
|
||||
psys->setVisibilityFlags(mVisFlags);
|
||||
psys->setRenderingDistance(mDist);
|
||||
// TODO: Check particle material for actual transparency
|
||||
psys->setRenderQueueGroup(mTransQueue);
|
||||
}
|
||||
};
|
||||
|
||||
void Animation::setRenderProperties(const NifOgre::ObjectList &objlist, Ogre::uint32 visflags, Ogre::uint8 solidqueue, Ogre::uint8 transqueue)
|
||||
void Animation::setRenderProperties(const NifOgre::ObjectList &objlist, Ogre::uint32 visflags, Ogre::uint8 solidqueue, Ogre::uint8 transqueue, Ogre::Real dist)
|
||||
{
|
||||
std::for_each(objlist.mEntities.begin(), objlist.mEntities.end(),
|
||||
VisQueueSet(visflags, solidqueue, transqueue));
|
||||
VisQueueSet(visflags, solidqueue, transqueue, dist));
|
||||
std::for_each(objlist.mParticles.begin(), objlist.mParticles.end(),
|
||||
VisQueueSet(visflags, solidqueue, transqueue));
|
||||
VisQueueSet(visflags, solidqueue, transqueue, dist));
|
||||
}
|
||||
|
||||
|
||||
|
@ -903,6 +912,43 @@ void Animation::showWeapons(bool showWeapon)
|
|||
{
|
||||
}
|
||||
|
||||
|
||||
class ToggleLight {
|
||||
bool mEnable;
|
||||
|
||||
public:
|
||||
ToggleLight(bool enable) : mEnable(enable) { }
|
||||
|
||||
void operator()(Ogre::Light *light) const
|
||||
{ light->setVisible(mEnable); }
|
||||
};
|
||||
|
||||
void Animation::enableLights(bool enable)
|
||||
{
|
||||
std::for_each(mObjectRoot.mLights.begin(), mObjectRoot.mLights.end(), ToggleLight(enable));
|
||||
}
|
||||
|
||||
|
||||
class MergeBounds {
|
||||
Ogre::AxisAlignedBox *mBounds;
|
||||
|
||||
public:
|
||||
MergeBounds(Ogre::AxisAlignedBox *bounds) : mBounds(bounds) { }
|
||||
|
||||
void operator()(Ogre::MovableObject *obj)
|
||||
{
|
||||
mBounds->merge(obj->getWorldBoundingBox(true));
|
||||
}
|
||||
};
|
||||
|
||||
Ogre::AxisAlignedBox Animation::getWorldBounds()
|
||||
{
|
||||
Ogre::AxisAlignedBox bounds = Ogre::AxisAlignedBox::BOX_NULL;
|
||||
std::for_each(mObjectRoot.mEntities.begin(), mObjectRoot.mEntities.end(), MergeBounds(&bounds));
|
||||
return bounds;
|
||||
}
|
||||
|
||||
|
||||
bool Animation::isPriorityActive(int priority) const
|
||||
{
|
||||
for (AnimStateMap::const_iterator it = mStates.begin(); it != mStates.end(); ++it)
|
||||
|
@ -931,4 +977,65 @@ void Animation::detachObjectFromBone(Ogre::MovableObject *obj)
|
|||
mSkelBase->detachObjectFromBone(obj);
|
||||
}
|
||||
|
||||
|
||||
ObjectAnimation::ObjectAnimation(const MWWorld::Ptr& ptr, const std::string &model, bool isStatic)
|
||||
: Animation(ptr, ptr.getRefData().getBaseNode())
|
||||
{
|
||||
setObjectRoot(model, false);
|
||||
|
||||
Ogre::AxisAlignedBox bounds = getWorldBounds();
|
||||
|
||||
Ogre::Vector3 extents = bounds.getSize();
|
||||
extents *= mInsert->getParentSceneNode()->getScale();
|
||||
float size = std::max(std::max(extents.x, extents.y), extents.z);
|
||||
|
||||
bool small = (size < Settings::Manager::getInt("small object size", "Viewing distance")) &&
|
||||
Settings::Manager::getBool("limit small object distance", "Viewing distance");
|
||||
// do not fade out doors. that will cause holes and look stupid
|
||||
if(ptr.getTypeName().find("Door") != std::string::npos)
|
||||
small = false;
|
||||
|
||||
float dist = small ? Settings::Manager::getInt("small object distance", "Viewing distance") : 0.0f;
|
||||
setRenderProperties(mObjectRoot, isStatic ? (small ? RV_StaticsSmall : RV_Statics) : RV_Misc,
|
||||
RQG_Main, RQG_Alpha, dist);
|
||||
}
|
||||
|
||||
void ObjectAnimation::addLight(const ESM::Light *light)
|
||||
{
|
||||
addExtraLight(mInsert->getCreator(), mObjectRoot, light);
|
||||
}
|
||||
|
||||
|
||||
class FindEntityTransparency {
|
||||
public:
|
||||
bool operator()(Ogre::Entity *ent) const
|
||||
{
|
||||
unsigned int numsubs = ent->getNumSubEntities();
|
||||
for(unsigned int i = 0;i < numsubs;++i)
|
||||
{
|
||||
if(ent->getSubEntity(i)->getMaterial()->isTransparent())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
bool ObjectAnimation::canBatch() const
|
||||
{
|
||||
if(!mObjectRoot.mParticles.empty() || !mObjectRoot.mLights.empty() || !mObjectRoot.mControllers.empty())
|
||||
return false;
|
||||
return std::find_if(mObjectRoot.mEntities.begin(), mObjectRoot.mEntities.end(),
|
||||
FindEntityTransparency()) == mObjectRoot.mEntities.end();
|
||||
}
|
||||
|
||||
void ObjectAnimation::fillBatch(Ogre::StaticGeometry *sg)
|
||||
{
|
||||
std::vector<Ogre::Entity*>::reverse_iterator iter = mObjectRoot.mEntities.rbegin();
|
||||
for(;iter != mObjectRoot.mEntities.rend();++iter)
|
||||
{
|
||||
Ogre::Node *node = (*iter)->getParentNode();
|
||||
sg->addEntity(*iter, node->_getDerivedPosition(), node->_getDerivedOrientation(), node->_getDerivedScale());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -165,7 +165,7 @@ protected:
|
|||
|
||||
static void destroyObjectList(Ogre::SceneManager *sceneMgr, NifOgre::ObjectList &objects);
|
||||
|
||||
static void setRenderProperties(const NifOgre::ObjectList &objlist, Ogre::uint32 visflags, Ogre::uint8 solidqueue, Ogre::uint8 transqueue);
|
||||
static void setRenderProperties(const NifOgre::ObjectList &objlist, Ogre::uint32 visflags, Ogre::uint8 solidqueue, Ogre::uint8 transqueue, Ogre::Real dist=0.0f);
|
||||
|
||||
void clearAnimSources();
|
||||
|
||||
|
@ -229,6 +229,10 @@ public:
|
|||
|
||||
virtual void showWeapons(bool showWeapon);
|
||||
|
||||
void enableLights(bool enable);
|
||||
|
||||
Ogre::AxisAlignedBox getWorldBounds();
|
||||
|
||||
void setCamera(Camera *cam)
|
||||
{ mCamera = cam; }
|
||||
|
||||
|
@ -241,5 +245,15 @@ public:
|
|||
void detachObjectFromBone(Ogre::MovableObject *obj);
|
||||
};
|
||||
|
||||
class ObjectAnimation : public Animation {
|
||||
public:
|
||||
ObjectAnimation(const MWWorld::Ptr& ptr, const std::string &model, bool isStatic);
|
||||
|
||||
void addLight(const ESM::Light *light);
|
||||
|
||||
bool canBatch() const;
|
||||
void fillBatch(Ogre::StaticGeometry *sg);
|
||||
};
|
||||
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "../mwworld/class.hpp"
|
||||
|
||||
#include "renderconst.hpp"
|
||||
#include "animation.hpp"
|
||||
|
||||
using namespace MWRender;
|
||||
float Objects::lightLinearValue()
|
||||
|
@ -124,73 +125,41 @@ void Objects::insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_)
|
|||
mIsStatic = static_;
|
||||
}
|
||||
|
||||
void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh, bool light)
|
||||
void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh)
|
||||
{
|
||||
Ogre::SceneNode* insert = ptr.getRefData().getBaseNode();
|
||||
assert(insert);
|
||||
|
||||
Ogre::AxisAlignedBox bounds = Ogre::AxisAlignedBox::BOX_NULL;
|
||||
NifOgre::ObjectList objects = NifOgre::Loader::createObjects(insert, mesh);
|
||||
for(size_t i = 0;i < objects.mEntities.size();i++)
|
||||
bounds.merge(objects.mEntities[i]->getWorldBoundingBox(true));
|
||||
std::auto_ptr<ObjectAnimation> anim(new ObjectAnimation(ptr, mesh, mIsStatic));
|
||||
|
||||
Ogre::AxisAlignedBox bounds = anim->getWorldBounds();
|
||||
Ogre::Vector3 extents = bounds.getSize();
|
||||
extents *= insert->getScale();
|
||||
float size = std::max(std::max(extents.x, extents.y), extents.z);
|
||||
|
||||
bool small = (size < Settings::Manager::getInt("small object size", "Viewing distance")) && Settings::Manager::getBool("limit small object distance", "Viewing distance");
|
||||
|
||||
bool small = (size < Settings::Manager::getInt("small object size", "Viewing distance")) &&
|
||||
Settings::Manager::getBool("limit small object distance", "Viewing distance");
|
||||
// do not fade out doors. that will cause holes and look stupid
|
||||
if (ptr.getTypeName().find("Door") != std::string::npos)
|
||||
if(ptr.getTypeName().find("Door") != std::string::npos)
|
||||
small = false;
|
||||
|
||||
if (mBounds.find(ptr.getCell()) == mBounds.end())
|
||||
mBounds[ptr.getCell()] = Ogre::AxisAlignedBox::BOX_NULL;
|
||||
mBounds[ptr.getCell()].merge(bounds);
|
||||
|
||||
bool anyTransparency = false;
|
||||
for(size_t i = 0;!anyTransparency && i < objects.mEntities.size();i++)
|
||||
{
|
||||
Ogre::Entity *ent = objects.mEntities[i];
|
||||
for(unsigned int i=0;!anyTransparency && i < ent->getNumSubEntities(); ++i)
|
||||
{
|
||||
anyTransparency = ent->getSubEntity(i)->getMaterial()->isTransparent();
|
||||
}
|
||||
}
|
||||
if(ptr.getTypeName() == typeid(ESM::Light).name())
|
||||
anim->addLight(ptr.get<ESM::Light>()->mBase);
|
||||
|
||||
if(!mIsStatic || !Settings::Manager::getBool("use static geometry", "Objects") ||
|
||||
anyTransparency || !objects.mParticles.empty() || !objects.mLights.empty())
|
||||
{
|
||||
for(size_t i = 0;i < objects.mEntities.size();i++)
|
||||
{
|
||||
Ogre::Entity *ent = objects.mEntities[i];
|
||||
for(unsigned int i=0; i < ent->getNumSubEntities(); ++i)
|
||||
{
|
||||
Ogre::SubEntity* subEnt = ent->getSubEntity(i);
|
||||
subEnt->setRenderQueueGroup(subEnt->getMaterial()->isTransparent() ? RQG_Alpha : RQG_Main);
|
||||
}
|
||||
ent->setRenderingDistance(small ? Settings::Manager::getInt("small object distance", "Viewing distance") : 0);
|
||||
ent->setVisibilityFlags(mIsStatic ? (small ? RV_StaticsSmall : RV_Statics) : RV_Misc);
|
||||
}
|
||||
for(size_t i = 0;i < objects.mParticles.size();i++)
|
||||
{
|
||||
Ogre::ParticleSystem *part = objects.mParticles[i];
|
||||
// TODO: Check the particle system's material for actual transparency
|
||||
part->setRenderQueueGroup(RQG_Alpha);
|
||||
part->setRenderingDistance(small ? Settings::Manager::getInt("small object distance", "Viewing distance") : 0);
|
||||
part->setVisibilityFlags(mIsStatic ? (small ? RV_StaticsSmall : RV_Statics) : RV_Misc);
|
||||
}
|
||||
}
|
||||
else
|
||||
if(mIsStatic && Settings::Manager::getBool("use static geometry", "Objects") && anim->canBatch())
|
||||
{
|
||||
Ogre::StaticGeometry* sg = 0;
|
||||
|
||||
if (small)
|
||||
{
|
||||
if( mStaticGeometrySmall.find(ptr.getCell()) == mStaticGeometrySmall.end())
|
||||
if(mStaticGeometrySmall.find(ptr.getCell()) == mStaticGeometrySmall.end())
|
||||
{
|
||||
uniqueID = uniqueID +1;
|
||||
sg = mRenderer.getScene()->createStaticGeometry( "sg" + Ogre::StringConverter::toString(uniqueID));
|
||||
uniqueID = uniqueID+1;
|
||||
sg = mRenderer.getScene()->createStaticGeometry("sg" + Ogre::StringConverter::toString(uniqueID));
|
||||
mStaticGeometrySmall[ptr.getCell()] = sg;
|
||||
|
||||
sg->setRenderingDistance(Settings::Manager::getInt("small object distance", "Viewing distance"));
|
||||
|
@ -200,11 +169,10 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh, bool
|
|||
}
|
||||
else
|
||||
{
|
||||
if( mStaticGeometry.find(ptr.getCell()) == mStaticGeometry.end())
|
||||
if(mStaticGeometry.find(ptr.getCell()) == mStaticGeometry.end())
|
||||
{
|
||||
|
||||
uniqueID = uniqueID +1;
|
||||
sg = mRenderer.getScene()->createStaticGeometry( "sg" + Ogre::StringConverter::toString(uniqueID));
|
||||
uniqueID = uniqueID+1;
|
||||
sg = mRenderer.getScene()->createStaticGeometry("sg" + Ogre::StringConverter::toString(uniqueID));
|
||||
mStaticGeometry[ptr.getCell()] = sg;
|
||||
}
|
||||
else
|
||||
|
@ -225,155 +193,75 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh, bool
|
|||
|
||||
sg->setRenderQueueGroup(RQG_Main);
|
||||
|
||||
std::vector<Ogre::Entity*>::reverse_iterator iter = objects.mEntities.rbegin();
|
||||
while(iter != objects.mEntities.rend())
|
||||
{
|
||||
Ogre::Node *node = (*iter)->getParentNode();
|
||||
sg->addEntity(*iter, node->_getDerivedPosition(), node->_getDerivedOrientation(), node->_getDerivedScale());
|
||||
|
||||
(*iter)->detachFromParent();
|
||||
mRenderer.getScene()->destroyEntity(*iter);
|
||||
++iter;
|
||||
}
|
||||
anim->fillBatch(sg);
|
||||
/* TODO: We could hold on to this and just detach it from the scene graph, so if the Ptr
|
||||
* ever needs to modify we can reattach it and rebuild the StaticGeometry object without
|
||||
* it. Would require associating the Ptr with the StaticGeometry. */
|
||||
anim.reset();
|
||||
}
|
||||
|
||||
if (light)
|
||||
{
|
||||
insertLight(ptr, objects.mSkelBase, bounds.getCenter() - insert->_getDerivedPosition());
|
||||
}
|
||||
}
|
||||
|
||||
void Objects::insertLight (const MWWorld::Ptr& ptr, Ogre::Entity* skelBase, Ogre::Vector3 fallbackCenter)
|
||||
{
|
||||
Ogre::SceneNode* insert = mRenderer.getScene()->getSceneNode(ptr.getRefData().getHandle());
|
||||
assert(insert);
|
||||
|
||||
MWWorld::LiveCellRef<ESM::Light> *ref = ptr.get<ESM::Light>();
|
||||
|
||||
const int color = ref->mBase->mData.mColor;
|
||||
const float r = ((color >> 0) & 0xFF) / 255.0f;
|
||||
const float g = ((color >> 8) & 0xFF) / 255.0f;
|
||||
const float b = ((color >> 16) & 0xFF) / 255.0f;
|
||||
const float radius = float (ref->mBase->mData.mRadius);
|
||||
|
||||
Ogre::Light *light = mRenderer.getScene()->createLight();
|
||||
light->setDiffuseColour (r, g, b);
|
||||
|
||||
LightInfo info;
|
||||
info.name = light->getName();
|
||||
info.radius = radius;
|
||||
info.colour = Ogre::ColourValue(r, g, b);
|
||||
|
||||
if (ref->mBase->mData.mFlags & ESM::Light::Negative)
|
||||
info.colour *= -1;
|
||||
|
||||
info.interior = !ptr.getCell()->mCell->isExterior();
|
||||
|
||||
if (ref->mBase->mData.mFlags & ESM::Light::Flicker)
|
||||
info.type = LT_Flicker;
|
||||
else if (ref->mBase->mData.mFlags & ESM::Light::FlickerSlow)
|
||||
info.type = LT_FlickerSlow;
|
||||
else if (ref->mBase->mData.mFlags & ESM::Light::Pulse)
|
||||
info.type = LT_Pulse;
|
||||
else if (ref->mBase->mData.mFlags & ESM::Light::PulseSlow)
|
||||
info.type = LT_PulseSlow;
|
||||
else
|
||||
info.type = LT_Normal;
|
||||
|
||||
// randomize lights animations
|
||||
info.time = Ogre::Math::RangeRandom(-500, +500);
|
||||
info.phase = Ogre::Math::RangeRandom(-500, +500);
|
||||
|
||||
bool quadratic = lightOutQuadInLin() ? !info.interior : lightQuadratic();
|
||||
|
||||
// with the standard 1 / (c + d*l + d*d*q) equation the attenuation factor never becomes zero,
|
||||
// so we ignore lights if their attenuation falls below this factor.
|
||||
const float threshold = 0.03;
|
||||
|
||||
if (!quadratic)
|
||||
{
|
||||
float r = radius * lightLinearRadiusMult();
|
||||
float attenuation = lightLinearValue() / r;
|
||||
float activationRange = 1 / (threshold * attenuation);
|
||||
light->setAttenuation(activationRange, 0, attenuation, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
float r = radius * lightQuadraticRadiusMult();
|
||||
float attenuation = lightQuadraticValue() / std::pow(r, 2);
|
||||
float activationRange = std::sqrt(1 / (threshold * attenuation));
|
||||
light->setAttenuation(activationRange, 0, 0, attenuation);
|
||||
}
|
||||
|
||||
// If there's an AttachLight bone, attach the light to that, otherwise attach it to the base scene node
|
||||
if (skelBase && skelBase->getSkeleton ()->hasBone ("AttachLight"))
|
||||
{
|
||||
skelBase->attachObjectToBone ("AttachLight", light);
|
||||
}
|
||||
else
|
||||
{
|
||||
Ogre::SceneNode* childNode = insert->createChildSceneNode (fallbackCenter);
|
||||
childNode->attachObject(light);
|
||||
}
|
||||
|
||||
mLights.push_back(info);
|
||||
if(anim.get() != NULL)
|
||||
mObjects.insert(std::make_pair(ptr, anim.release()));
|
||||
}
|
||||
|
||||
bool Objects::deleteObject (const MWWorld::Ptr& ptr)
|
||||
{
|
||||
if (Ogre::SceneNode *base = ptr.getRefData().getBaseNode())
|
||||
if(!ptr.getRefData().getBaseNode())
|
||||
return true;
|
||||
|
||||
PtrAnimationMap::iterator iter = mObjects.find(ptr);
|
||||
if(iter != mObjects.end())
|
||||
{
|
||||
Ogre::SceneNode *parent = base->getParentSceneNode();
|
||||
delete iter->second;
|
||||
mObjects.erase(iter);
|
||||
|
||||
for (std::map<MWWorld::Ptr::CellStore *, Ogre::SceneNode *>::const_iterator iter (
|
||||
mCellSceneNodes.begin()); iter!=mCellSceneNodes.end(); ++iter)
|
||||
if (iter->second==parent)
|
||||
{
|
||||
clearSceneNode (base);
|
||||
base->removeAndDestroyAllChildren();
|
||||
mRenderer.getScene()->destroySceneNode (base);
|
||||
ptr.getRefData().setBaseNode (0);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
mRenderer.getScene()->destroySceneNode(ptr.getRefData().getBaseNode());
|
||||
ptr.getRefData().setBaseNode(0);
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void Objects::removeCell(MWWorld::Ptr::CellStore* store)
|
||||
{
|
||||
if(mCellSceneNodes.find(store) != mCellSceneNodes.end())
|
||||
for(PtrAnimationMap::iterator iter = mObjects.begin();iter != mObjects.end();)
|
||||
{
|
||||
Ogre::SceneNode* base = mCellSceneNodes[store];
|
||||
|
||||
for (int i=0; i<base->numChildren(); ++i)
|
||||
clearSceneNode (static_cast<Ogre::SceneNode *> (base->getChild (i)));
|
||||
|
||||
base->removeAndDestroyAllChildren();
|
||||
mCellSceneNodes.erase(store);
|
||||
mRenderer.getScene()->destroySceneNode(base);
|
||||
base = 0;
|
||||
if(iter->first.getCell() == store)
|
||||
{
|
||||
delete iter->second;
|
||||
mObjects.erase(iter++);
|
||||
}
|
||||
else
|
||||
++iter;
|
||||
}
|
||||
|
||||
if(mStaticGeometry.find(store) != mStaticGeometry.end())
|
||||
std::map<MWWorld::CellStore*,Ogre::StaticGeometry*>::iterator geom = mStaticGeometry.find(store);
|
||||
if(geom != mStaticGeometry.end())
|
||||
{
|
||||
Ogre::StaticGeometry* sg = mStaticGeometry[store];
|
||||
mStaticGeometry.erase(store);
|
||||
mRenderer.getScene()->destroyStaticGeometry (sg);
|
||||
sg = 0;
|
||||
Ogre::StaticGeometry *sg = geom->second;
|
||||
mStaticGeometry.erase(geom);
|
||||
mRenderer.getScene()->destroyStaticGeometry(sg);
|
||||
}
|
||||
if(mStaticGeometrySmall.find(store) != mStaticGeometrySmall.end())
|
||||
|
||||
geom = mStaticGeometrySmall.find(store);
|
||||
if(geom != mStaticGeometrySmall.end())
|
||||
{
|
||||
Ogre::StaticGeometry* sg = mStaticGeometrySmall[store];
|
||||
Ogre::StaticGeometry *sg = geom->second;
|
||||
mStaticGeometrySmall.erase(store);
|
||||
mRenderer.getScene()->destroyStaticGeometry (sg);
|
||||
sg = 0;
|
||||
mRenderer.getScene()->destroyStaticGeometry(sg);
|
||||
}
|
||||
|
||||
if(mBounds.find(store) != mBounds.end())
|
||||
mBounds.erase(store);
|
||||
mBounds.erase(store);
|
||||
|
||||
std::map<MWWorld::CellStore*,Ogre::SceneNode*>::iterator cell = mCellSceneNodes.find(store);
|
||||
if(cell != mCellSceneNodes.end())
|
||||
{
|
||||
cell->second->removeAndDestroyAllChildren();
|
||||
mRenderer.getScene()->destroySceneNode(cell->second);
|
||||
mCellSceneNodes.erase(cell);
|
||||
}
|
||||
}
|
||||
|
||||
void Objects::buildStaticGeometry(MWWorld::Ptr::CellStore& cell)
|
||||
|
@ -397,146 +285,23 @@ Ogre::AxisAlignedBox Objects::getDimensions(MWWorld::Ptr::CellStore* cell)
|
|||
|
||||
void Objects::enableLights()
|
||||
{
|
||||
std::vector<LightInfo>::iterator it = mLights.begin();
|
||||
while (it != mLights.end())
|
||||
{
|
||||
if (mRootNode->getCreator()->hasLight(it->name))
|
||||
{
|
||||
mRootNode->getCreator()->getLight(it->name)->setVisible(true);
|
||||
++it;
|
||||
}
|
||||
else
|
||||
it = mLights.erase(it);
|
||||
}
|
||||
PtrAnimationMap::const_iterator it = mObjects.begin();
|
||||
for(;it != mObjects.end();it++)
|
||||
it->second->enableLights(true);
|
||||
}
|
||||
|
||||
void Objects::disableLights()
|
||||
{
|
||||
std::vector<LightInfo>::iterator it = mLights.begin();
|
||||
while (it != mLights.end())
|
||||
{
|
||||
if (mRootNode->getCreator()->hasLight(it->name))
|
||||
{
|
||||
mRootNode->getCreator()->getLight(it->name)->setVisible(false);
|
||||
++it;
|
||||
}
|
||||
else
|
||||
it = mLights.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
namespace MWRender
|
||||
{
|
||||
namespace Pulse
|
||||
{
|
||||
static float amplitude (float phase)
|
||||
{
|
||||
return sin (phase);
|
||||
}
|
||||
}
|
||||
|
||||
namespace Flicker
|
||||
{
|
||||
static const float fa = 0.785398f;
|
||||
static const float fb = 1.17024f;
|
||||
|
||||
static const float tdo = 0.94f;
|
||||
static const float tdm = 2.48f;
|
||||
|
||||
static const float f [3] = { 1.5708f, 4.18774f, 5.19934f };
|
||||
static const float o [3] = { 0.804248f, 2.11115f, 3.46832f };
|
||||
static const float m [3] = { 1.0f, 0.785f, 0.876f };
|
||||
static const float s = 0.394f;
|
||||
|
||||
static const float phase_wavelength = 120.0f * 3.14159265359f / fa;
|
||||
|
||||
static float frequency (float x)
|
||||
{
|
||||
return tdo + tdm * sin (fa * x);
|
||||
}
|
||||
|
||||
static float amplitude (float x)
|
||||
{
|
||||
float v = 0.0f;
|
||||
for (int i = 0; i < 3; ++i)
|
||||
v += sin (fb*x*f[i] + o[1])*m[i];
|
||||
return v * s;
|
||||
}
|
||||
}
|
||||
PtrAnimationMap::const_iterator it = mObjects.begin();
|
||||
for(;it != mObjects.end();it++)
|
||||
it->second->enableLights(false);
|
||||
}
|
||||
|
||||
void Objects::update(const float dt)
|
||||
{
|
||||
std::vector<LightInfo>::iterator it = mLights.begin();
|
||||
while (it != mLights.end())
|
||||
{
|
||||
if (mRootNode->getCreator()->hasLight(it->name))
|
||||
{
|
||||
Ogre::Light* light = mRootNode->getCreator()->getLight(it->name);
|
||||
|
||||
float brightness;
|
||||
float cycle_time;
|
||||
float time_distortion;
|
||||
|
||||
if ((it->type == LT_Pulse) && (it->type == LT_PulseSlow))
|
||||
{
|
||||
cycle_time = 2 * Ogre::Math::PI;
|
||||
time_distortion = 20.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
cycle_time = 500.0f;
|
||||
it->phase = fmod (it->phase + dt, Flicker::phase_wavelength);
|
||||
time_distortion = Flicker::frequency (it->phase);
|
||||
}
|
||||
|
||||
it->time += it->dir*dt*time_distortion;
|
||||
if (it->dir > 0 && it->time > +cycle_time)
|
||||
{
|
||||
it->dir = -1.0f;
|
||||
it->time = +2*cycle_time - it->time;
|
||||
}
|
||||
if (it->dir < 0 && it->time < -cycle_time)
|
||||
{
|
||||
it->dir = +1.0f;
|
||||
it->time = -2*cycle_time - it->time;
|
||||
}
|
||||
|
||||
static const float fast = 4.0f/1.0f;
|
||||
static const float slow = 1.0f/1.0f;
|
||||
|
||||
// These formulas are just guesswork, but they work pretty well
|
||||
if (it->type == LT_Normal)
|
||||
{
|
||||
// Less than 1/255 light modifier for a constant light:
|
||||
brightness = (const float)(1.0 + Flicker::amplitude(it->time*slow) / 255.0 );
|
||||
}
|
||||
else if (it->type == LT_Flicker)
|
||||
{
|
||||
brightness = (const float)(0.75 + Flicker::amplitude(it->time*fast) * 0.25);
|
||||
}
|
||||
else if (it->type == LT_FlickerSlow)
|
||||
{
|
||||
brightness = (const float)(0.75 + Flicker::amplitude(it->time*slow) * 0.25);
|
||||
}
|
||||
else if (it->type == LT_Pulse)
|
||||
{
|
||||
brightness = (const float)(1.0 + Pulse::amplitude (it->time*fast) * 0.25);
|
||||
}
|
||||
else if (it->type == LT_PulseSlow)
|
||||
{
|
||||
brightness = (const float)(1.0 + Pulse::amplitude (it->time*slow) * 0.25);
|
||||
}
|
||||
else
|
||||
assert(0 && "Invalid light type");
|
||||
|
||||
light->setDiffuseColour(it->colour * brightness);
|
||||
|
||||
++it;
|
||||
}
|
||||
else
|
||||
it = mLights.erase(it);
|
||||
}
|
||||
PtrAnimationMap::const_iterator it = mObjects.begin();
|
||||
for(;it != mObjects.end();it++)
|
||||
it->second->runAnimation(dt);
|
||||
}
|
||||
|
||||
void Objects::rebuildStaticGeometry()
|
||||
|
|
|
@ -15,6 +15,8 @@ namespace MWWorld
|
|||
|
||||
namespace MWRender{
|
||||
|
||||
class ObjectAnimation;
|
||||
|
||||
/// information about light needed for rendering
|
||||
enum LightType
|
||||
{
|
||||
|
@ -48,15 +50,20 @@ struct LightInfo
|
|||
};
|
||||
|
||||
class Objects{
|
||||
typedef std::map<MWWorld::Ptr,ObjectAnimation*> PtrAnimationMap;
|
||||
|
||||
OEngine::Render::OgreRenderer &mRenderer;
|
||||
std::map<MWWorld::CellStore *, Ogre::SceneNode *> mCellSceneNodes;
|
||||
std::map<MWWorld::CellStore *, Ogre::StaticGeometry*> mStaticGeometry;
|
||||
std::map<MWWorld::CellStore *, Ogre::StaticGeometry*> mStaticGeometrySmall;
|
||||
std::map<MWWorld::CellStore *, Ogre::AxisAlignedBox> mBounds;
|
||||
std::vector<LightInfo> mLights;
|
||||
|
||||
std::map<MWWorld::CellStore*,Ogre::SceneNode*> mCellSceneNodes;
|
||||
std::map<MWWorld::CellStore*,Ogre::StaticGeometry*> mStaticGeometry;
|
||||
std::map<MWWorld::CellStore*,Ogre::StaticGeometry*> mStaticGeometrySmall;
|
||||
std::map<MWWorld::CellStore*,Ogre::AxisAlignedBox> mBounds;
|
||||
PtrAnimationMap mObjects;
|
||||
|
||||
Ogre::SceneNode* mRootNode;
|
||||
bool mIsStatic;
|
||||
static int uniqueID;
|
||||
|
||||
MWWorld::Fallback* mFallback;
|
||||
float lightLinearValue();
|
||||
float lightLinearRadiusMult();
|
||||
|
@ -79,8 +86,7 @@ public:
|
|||
{}
|
||||
~Objects(){}
|
||||
void insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_);
|
||||
void insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh, bool light=false);
|
||||
void insertLight (const MWWorld::Ptr& ptr, Ogre::Entity *skelBase=0, Ogre::Vector3 fallbackCenter=Ogre::Vector3(0.0f));
|
||||
void insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh);
|
||||
|
||||
void enableLights();
|
||||
void disableLights();
|
||||
|
|
Loading…
Reference in a new issue