diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index b5ad0fe66..904931ab8 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -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 diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index a91679dc6..7e1a0aebe 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include @@ -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::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()); + } +} + } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 42f57d5f1..74e3c503f 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -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 diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index bede95a26..16d0bedae 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -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 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()->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::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()); - } + if(anim.get() != NULL) + mObjects.insert(std::make_pair(ptr, anim.release())); } -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()); - assert(insert); - - MWWorld::LiveCellRef *ref = ptr.get(); - - 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; + if(!ptr.getRefData().getBaseNode()) + return true; - // 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 + PtrAnimationMap::iterator iter = mObjects.find(ptr); + if(iter != mObjects.end()) { - float r = radius * lightQuadraticRadiusMult(); - float attenuation = lightQuadraticValue() / std::pow(r, 2); - float activationRange = std::sqrt(1 / (threshold * attenuation)); - light->setAttenuation(activationRange, 0, 0, attenuation); - } + delete iter->second; + mObjects.erase(iter); - // 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); + mRenderer.getScene()->destroySceneNode(ptr.getRefData().getBaseNode()); + ptr.getRefData().setBaseNode(0); + return true; } - 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::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) { - if(mCellSceneNodes.find(store) != mCellSceneNodes.end()) + for(PtrAnimationMap::iterator iter = mObjects.begin();iter != mObjects.end();) { - Ogre::SceneNode* base = mCellSceneNodes[store]; - - for (int i=0; inumChildren(); ++i) - clearSceneNode (static_cast (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::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::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::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::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::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() diff --git a/apps/openmw/mwrender/objects.hpp b/apps/openmw/mwrender/objects.hpp index d428aae96..1e3ce3ddf 100644 --- a/apps/openmw/mwrender/objects.hpp +++ b/apps/openmw/mwrender/objects.hpp @@ -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 PtrAnimationMap; + OEngine::Render::OgreRenderer &mRenderer; - std::map mCellSceneNodes; - std::map mStaticGeometry; - std::map mStaticGeometrySmall; - std::map mBounds; - std::vector mLights; + + std::map mCellSceneNodes; + std::map mStaticGeometry; + std::map mStaticGeometrySmall; + std::map 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();