Use Animation-derived objects for generic objects

actorid
Chris Robinson 12 years ago
parent a9dca21d05
commit 3555476dfd

@ -34,11 +34,10 @@ namespace MWClass
MWRender::Objects& objects = renderingInterface.getObjects(); MWRender::Objects& objects = renderingInterface.getObjects();
objects.insertBegin(ptr, ptr.getRefData().isEnabled(), false); objects.insertBegin(ptr, ptr.getRefData().isEnabled(), false);
if(!model.empty())
if (!model.empty()) objects.insertMesh(ptr, "meshes\\" + model);
objects.insertMesh(ptr, "meshes\\" + model, true);
else else
objects.insertLight(ptr); objects.insertMesh(ptr, "");
} }
void Light::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const void Light::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const

@ -9,6 +9,7 @@
#include <OgreSubMesh.h> #include <OgreSubMesh.h>
#include <OgreSceneManager.h> #include <OgreSceneManager.h>
#include <OgreControllerManager.h> #include <OgreControllerManager.h>
#include <OgreStaticGeometry.h>
#include <libs/openengine/ogre/lights.hpp> #include <libs/openengine/ogre/lights.hpp>
@ -21,6 +22,8 @@
#include "../mwworld/class.hpp" #include "../mwworld/class.hpp"
#include "../mwworld/fallback.hpp" #include "../mwworld/fallback.hpp"
#include "renderconst.hpp"
namespace MWRender 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!"); 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 mdlname = Misc::StringUtils::lowerCase(model);
std::string::size_type p = mdlname.rfind('\\'); std::string::size_type p = mdlname.rfind('\\');
if(p == std::string::npos) if(p == std::string::npos)
@ -105,9 +114,6 @@ void Animation::setObjectRoot(const std::string &model, bool baseonly)
Misc::StringUtils::toLower(mdlname); Misc::StringUtils::toLower(mdlname);
} }
mSkelBase = NULL;
destroyObjectList(mInsert->getCreator(), mObjectRoot);
mObjectRoot = (!baseonly ? NifOgre::Loader::createObjects(mInsert, mdlname) : mObjectRoot = (!baseonly ? NifOgre::Loader::createObjects(mInsert, mdlname) :
NifOgre::Loader::createObjectBase(mInsert, mdlname)); NifOgre::Loader::createObjectBase(mInsert, mdlname));
if(mObjectRoot.mSkelBase) if(mObjectRoot.mSkelBase)
@ -157,16 +163,18 @@ void Animation::setObjectRoot(const std::string &model, bool baseonly)
class VisQueueSet { class VisQueueSet {
Ogre::uint32 mVisFlags; Ogre::uint32 mVisFlags;
Ogre::uint8 mSolidQueue, mTransQueue; Ogre::uint8 mSolidQueue, mTransQueue;
Ogre::Real mDist;
public: public:
VisQueueSet(Ogre::uint32 visflags, Ogre::uint8 solidqueue, Ogre::uint8 transqueue) VisQueueSet(Ogre::uint32 visflags, Ogre::uint8 solidqueue, Ogre::uint8 transqueue, Ogre::Real dist)
: mVisFlags(visflags), mSolidQueue(solidqueue), mTransQueue(transqueue) : mVisFlags(visflags), mSolidQueue(solidqueue), mTransQueue(transqueue), mDist(dist)
{ } { }
void operator()(Ogre::Entity *entity) const void operator()(Ogre::Entity *entity) const
{ {
if(mVisFlags != 0) if(mVisFlags != 0)
entity->setVisibilityFlags(mVisFlags); entity->setVisibilityFlags(mVisFlags);
entity->setRenderingDistance(mDist);
unsigned int numsubs = entity->getNumSubEntities(); unsigned int numsubs = entity->getNumSubEntities();
for(unsigned int i = 0;i < numsubs;++i) for(unsigned int i = 0;i < numsubs;++i)
@ -180,17 +188,18 @@ public:
{ {
if(mVisFlags != 0) if(mVisFlags != 0)
psys->setVisibilityFlags(mVisFlags); psys->setVisibilityFlags(mVisFlags);
psys->setRenderingDistance(mDist);
// TODO: Check particle material for actual transparency // TODO: Check particle material for actual transparency
psys->setRenderQueueGroup(mTransQueue); 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(), 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(), 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 bool Animation::isPriorityActive(int priority) const
{ {
for (AnimStateMap::const_iterator it = mStates.begin(); it != mStates.end(); ++it) for (AnimStateMap::const_iterator it = mStates.begin(); it != mStates.end(); ++it)
@ -931,4 +977,65 @@ void Animation::detachObjectFromBone(Ogre::MovableObject *obj)
mSkelBase->detachObjectFromBone(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 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(); void clearAnimSources();
@ -229,6 +229,10 @@ public:
virtual void showWeapons(bool showWeapon); virtual void showWeapons(bool showWeapon);
void enableLights(bool enable);
Ogre::AxisAlignedBox getWorldBounds();
void setCamera(Camera *cam) void setCamera(Camera *cam)
{ mCamera = cam; } { mCamera = cam; }
@ -241,5 +245,15 @@ public:
void detachObjectFromBone(Ogre::MovableObject *obj); 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 #endif

@ -18,6 +18,7 @@
#include "../mwworld/class.hpp" #include "../mwworld/class.hpp"
#include "renderconst.hpp" #include "renderconst.hpp"
#include "animation.hpp"
using namespace MWRender; using namespace MWRender;
float Objects::lightLinearValue() float Objects::lightLinearValue()
@ -124,73 +125,41 @@ void Objects::insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_)
mIsStatic = 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(); Ogre::SceneNode* insert = ptr.getRefData().getBaseNode();
assert(insert); assert(insert);
Ogre::AxisAlignedBox bounds = Ogre::AxisAlignedBox::BOX_NULL; std::auto_ptr<ObjectAnimation> anim(new ObjectAnimation(ptr, mesh, mIsStatic));
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));
Ogre::AxisAlignedBox bounds = anim->getWorldBounds();
Ogre::Vector3 extents = bounds.getSize(); Ogre::Vector3 extents = bounds.getSize();
extents *= insert->getScale(); extents *= insert->getScale();
float size = std::max(std::max(extents.x, extents.y), extents.z); 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 // 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; small = false;
if (mBounds.find(ptr.getCell()) == mBounds.end()) if (mBounds.find(ptr.getCell()) == mBounds.end())
mBounds[ptr.getCell()] = Ogre::AxisAlignedBox::BOX_NULL; mBounds[ptr.getCell()] = Ogre::AxisAlignedBox::BOX_NULL;
mBounds[ptr.getCell()].merge(bounds); mBounds[ptr.getCell()].merge(bounds);
bool anyTransparency = false; if(ptr.getTypeName() == typeid(ESM::Light).name())
for(size_t i = 0;!anyTransparency && i < objects.mEntities.size();i++) anim->addLight(ptr.get<ESM::Light>()->mBase);
{
Ogre::Entity *ent = objects.mEntities[i];
for(unsigned int i=0;!anyTransparency && i < ent->getNumSubEntities(); ++i)
{
anyTransparency = ent->getSubEntity(i)->getMaterial()->isTransparent();
}
}
if(!mIsStatic || !Settings::Manager::getBool("use static geometry", "Objects") || if(mIsStatic && Settings::Manager::getBool("use static geometry", "Objects") && anim->canBatch())
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
{ {
Ogre::StaticGeometry* sg = 0; Ogre::StaticGeometry* sg = 0;
if (small) if (small)
{ {
if( mStaticGeometrySmall.find(ptr.getCell()) == mStaticGeometrySmall.end()) if(mStaticGeometrySmall.find(ptr.getCell()) == mStaticGeometrySmall.end())
{ {
uniqueID = uniqueID +1; uniqueID = uniqueID+1;
sg = mRenderer.getScene()->createStaticGeometry( "sg" + Ogre::StringConverter::toString(uniqueID)); sg = mRenderer.getScene()->createStaticGeometry("sg" + Ogre::StringConverter::toString(uniqueID));
mStaticGeometrySmall[ptr.getCell()] = sg; mStaticGeometrySmall[ptr.getCell()] = sg;
sg->setRenderingDistance(Settings::Manager::getInt("small object distance", "Viewing distance")); 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 else
{ {
if( mStaticGeometry.find(ptr.getCell()) == mStaticGeometry.end()) if(mStaticGeometry.find(ptr.getCell()) == mStaticGeometry.end())
{ {
uniqueID = uniqueID+1;
uniqueID = uniqueID +1; sg = mRenderer.getScene()->createStaticGeometry("sg" + Ogre::StringConverter::toString(uniqueID));
sg = mRenderer.getScene()->createStaticGeometry( "sg" + Ogre::StringConverter::toString(uniqueID));
mStaticGeometry[ptr.getCell()] = sg; mStaticGeometry[ptr.getCell()] = sg;
} }
else else
@ -225,155 +193,75 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh, bool
sg->setRenderQueueGroup(RQG_Main); sg->setRenderQueueGroup(RQG_Main);
std::vector<Ogre::Entity*>::reverse_iterator iter = objects.mEntities.rbegin(); anim->fillBatch(sg);
while(iter != objects.mEntities.rend()) /* 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
Ogre::Node *node = (*iter)->getParentNode(); * it. Would require associating the Ptr with the StaticGeometry. */
sg->addEntity(*iter, node->_getDerivedPosition(), node->_getDerivedOrientation(), node->_getDerivedScale()); anim.reset();
(*iter)->detachFromParent();
mRenderer.getScene()->destroyEntity(*iter);
++iter;
}
} }
if (light) if(anim.get() != NULL)
{ mObjects.insert(std::make_pair(ptr, anim.release()));
insertLight(ptr, objects.mSkelBase, bounds.getCenter() - insert->_getDerivedPosition());
}
} }
void Objects::insertLight (const MWWorld::Ptr& ptr, Ogre::Entity* skelBase, Ogre::Vector3 fallbackCenter) bool Objects::deleteObject (const MWWorld::Ptr& ptr)
{ {
Ogre::SceneNode* insert = mRenderer.getScene()->getSceneNode(ptr.getRefData().getHandle()); if(!ptr.getRefData().getBaseNode())
assert(insert); return true;
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 PtrAnimationMap::iterator iter = mObjects.find(ptr);
info.time = Ogre::Math::RangeRandom(-500, +500); if(iter != mObjects.end())
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(); delete iter->second;
float attenuation = lightQuadraticValue() / std::pow(r, 2); mObjects.erase(iter);
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 mRenderer.getScene()->destroySceneNode(ptr.getRefData().getBaseNode());
if (skelBase && skelBase->getSkeleton ()->hasBone ("AttachLight")) ptr.getRefData().setBaseNode(0);
{ return true;
skelBase->attachObjectToBone ("AttachLight", light);
}
else
{
Ogre::SceneNode* childNode = insert->createChildSceneNode (fallbackCenter);
childNode->attachObject(light);
} }
mLights.push_back(info); return false;
} }
bool Objects::deleteObject (const MWWorld::Ptr& ptr)
{
if (Ogre::SceneNode *base = ptr.getRefData().getBaseNode())
{
Ogre::SceneNode *parent = base->getParentSceneNode();
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;
}
return true;
}
void Objects::removeCell(MWWorld::Ptr::CellStore* store) 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]; if(iter->first.getCell() == store)
{
for (int i=0; i<base->numChildren(); ++i) delete iter->second;
clearSceneNode (static_cast<Ogre::SceneNode *> (base->getChild (i))); mObjects.erase(iter++);
}
base->removeAndDestroyAllChildren(); else
mCellSceneNodes.erase(store); ++iter;
mRenderer.getScene()->destroySceneNode(base);
base = 0;
} }
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]; Ogre::StaticGeometry *sg = geom->second;
mStaticGeometry.erase(store); mStaticGeometry.erase(geom);
mRenderer.getScene()->destroyStaticGeometry (sg); mRenderer.getScene()->destroyStaticGeometry(sg);
sg = 0;
} }
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); mStaticGeometrySmall.erase(store);
mRenderer.getScene()->destroyStaticGeometry (sg); mRenderer.getScene()->destroyStaticGeometry(sg);
sg = 0;
} }
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) void Objects::buildStaticGeometry(MWWorld::Ptr::CellStore& cell)
@ -397,146 +285,23 @@ Ogre::AxisAlignedBox Objects::getDimensions(MWWorld::Ptr::CellStore* cell)
void Objects::enableLights() void Objects::enableLights()
{ {
std::vector<LightInfo>::iterator it = mLights.begin(); PtrAnimationMap::const_iterator it = mObjects.begin();
while (it != mLights.end()) for(;it != mObjects.end();it++)
{ it->second->enableLights(true);
if (mRootNode->getCreator()->hasLight(it->name))
{
mRootNode->getCreator()->getLight(it->name)->setVisible(true);
++it;
}
else
it = mLights.erase(it);
}
} }
void Objects::disableLights() void Objects::disableLights()
{ {
std::vector<LightInfo>::iterator it = mLights.begin(); PtrAnimationMap::const_iterator it = mObjects.begin();
while (it != mLights.end()) for(;it != mObjects.end();it++)
{ it->second->enableLights(false);
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;
}
}
} }
void Objects::update(const float dt) void Objects::update(const float dt)
{ {
std::vector<LightInfo>::iterator it = mLights.begin(); PtrAnimationMap::const_iterator it = mObjects.begin();
while (it != mLights.end()) for(;it != mObjects.end();it++)
{ it->second->runAnimation(dt);
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);
}
} }
void Objects::rebuildStaticGeometry() void Objects::rebuildStaticGeometry()

@ -15,6 +15,8 @@ namespace MWWorld
namespace MWRender{ namespace MWRender{
class ObjectAnimation;
/// information about light needed for rendering /// information about light needed for rendering
enum LightType enum LightType
{ {
@ -48,15 +50,20 @@ struct LightInfo
}; };
class Objects{ class Objects{
typedef std::map<MWWorld::Ptr,ObjectAnimation*> PtrAnimationMap;
OEngine::Render::OgreRenderer &mRenderer; OEngine::Render::OgreRenderer &mRenderer;
std::map<MWWorld::CellStore *, Ogre::SceneNode *> mCellSceneNodes;
std::map<MWWorld::CellStore *, Ogre::StaticGeometry*> mStaticGeometry; std::map<MWWorld::CellStore*,Ogre::SceneNode*> mCellSceneNodes;
std::map<MWWorld::CellStore *, Ogre::StaticGeometry*> mStaticGeometrySmall; std::map<MWWorld::CellStore*,Ogre::StaticGeometry*> mStaticGeometry;
std::map<MWWorld::CellStore *, Ogre::AxisAlignedBox> mBounds; std::map<MWWorld::CellStore*,Ogre::StaticGeometry*> mStaticGeometrySmall;
std::vector<LightInfo> mLights; std::map<MWWorld::CellStore*,Ogre::AxisAlignedBox> mBounds;
PtrAnimationMap mObjects;
Ogre::SceneNode* mRootNode; Ogre::SceneNode* mRootNode;
bool mIsStatic; bool mIsStatic;
static int uniqueID; static int uniqueID;
MWWorld::Fallback* mFallback; MWWorld::Fallback* mFallback;
float lightLinearValue(); float lightLinearValue();
float lightLinearRadiusMult(); float lightLinearRadiusMult();
@ -79,8 +86,7 @@ public:
{} {}
~Objects(){} ~Objects(){}
void insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_); void insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_);
void insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh, bool light=false); void insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh);
void insertLight (const MWWorld::Ptr& ptr, Ogre::Entity *skelBase=0, Ogre::Vector3 fallbackCenter=Ogre::Vector3(0.0f));
void enableLights(); void enableLights();
void disableLights(); void disableLights();

Loading…
Cancel
Save