From de95926e9ff4e8e42e4d6ef030d21d184249882d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 6 Aug 2013 00:04:39 -0700 Subject: [PATCH] Use controllers to animate lights in ObjectLists --- CMakeLists.txt | 1 + apps/openmw/mwrender/animation.cpp | 33 ++++---- apps/openmw/mwrender/animation.hpp | 2 + libs/openengine/ogre/lights.cpp | 118 +++++++++++++++++++++++++++++ libs/openengine/ogre/lights.hpp | 51 +++++++++++++ 5 files changed, 186 insertions(+), 19 deletions(-) create mode 100644 libs/openengine/ogre/lights.cpp create mode 100644 libs/openengine/ogre/lights.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 9fc37b413..575fecd0c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -78,6 +78,7 @@ set(LIBDIR ${CMAKE_SOURCE_DIR}/libs) set(OENGINE_OGRE ${LIBDIR}/openengine/ogre/renderer.cpp ${LIBDIR}/openengine/ogre/fader.cpp + ${LIBDIR}/openengine/ogre/lights.cpp ${LIBDIR}/openengine/ogre/particles.cpp ${LIBDIR}/openengine/ogre/selectionbuffer.cpp ${LIBDIR}/openengine/ogre/imagerotate.cpp diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index adee771f6..533a7eab3 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -8,6 +8,9 @@ #include #include #include +#include + +#include #include "../mwbase/environment.hpp" #include "../mwbase/soundmanager.hpp" @@ -281,26 +284,18 @@ void Animation::addExtraLight(Ogre::SceneManager *sceneMgr, NifOgre::ObjectList Ogre::Light *olight = objlist.mLights.back(); olight->setDiffuseColour(color); - bool interior = !(mPtr.isInCell() && mPtr.getCell()->mCell->isExterior()); - - // TODO: Create Controllers for these -#if 0 - // randomize lights animations - info.time = Ogre::Math::RangeRandom(-500, +500); - info.phase = Ogre::Math::RangeRandom(-500, +500); - - if((light->mData.mFlags&ESM::Light::Flicker)) - info.type = LT_Flicker; - else if((light->mData.mFlags&ESM::Light::FlickerSlow)) - info.type = LT_FlickerSlow; - else if((light->mData.mFlags&ESM::Light::Pulse)) - info.type = LT_Pulse; - else if((light->mData.mFlags&ESM::Light::PulseSlow)) - info.type = LT_PulseSlow; - else - info.type = LT_Normal; -#endif + Ogre::ControllerValueRealPtr src(Ogre::ControllerManager::getSingleton().getFrameTimeSource()); + Ogre::ControllerValueRealPtr dest(OGRE_NEW OEngine::Render::LightValue(olight, color)); + Ogre::ControllerFunctionRealPtr func(OGRE_NEW OEngine::Render::LightFunction( + (light->mData.mFlags&ESM::Light::Flicker) ? OEngine::Render::LT_Flicker : + (light->mData.mFlags&ESM::Light::FlickerSlow) ? OEngine::Render::LT_FlickerSlow : + (light->mData.mFlags&ESM::Light::Pulse) ? OEngine::Render::LT_Pulse : + (light->mData.mFlags&ESM::Light::PulseSlow) ? OEngine::Render::LT_PulseSlow : + OEngine::Render::LT_Normal + )); + objlist.mControllers.push_back(Ogre::Controller(src, dest, func)); + bool interior = !(mPtr.isInCell() && mPtr.getCell()->mCell->isExterior()); bool quadratic = fallback->getFallbackBool("LightAttenuation_OutQuadInLin") ? !interior : fallback->getFallbackBool("LightAttenuation_UseQuadratic"); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 541509fb6..ceda463ff 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -52,6 +52,7 @@ protected: virtual void setValue(Ogre::Real value); }; + class NullAnimationValue : public Ogre::ControllerValue { public: @@ -61,6 +62,7 @@ protected: { } }; + struct AnimSource : public Ogre::AnimationAlloc { NifOgre::TextKeyMap mTextKeys; std::vector > mControllers[sNumGroups]; diff --git a/libs/openengine/ogre/lights.cpp b/libs/openengine/ogre/lights.cpp new file mode 100644 index 000000000..52aca6a70 --- /dev/null +++ b/libs/openengine/ogre/lights.cpp @@ -0,0 +1,118 @@ +#include "lights.hpp" + +#include +#include + +namespace OEngine { +namespace Render { + + +LightFunction::LightFunction(LightType type) + : ControllerFunction(true) + , mType(type) + , mPhase(Ogre::Math::RangeRandom(-500.0f, +500.0f)) + , mDirection(1.0f) +{ +} + +Ogre::Real LightFunction::pulseAmplitude(Ogre::Real time) +{ + return std::sin(time); +} + +Ogre::Real LightFunction::flickerAmplitude(Ogre::Real time) +{ + static const float fb = 1.17024f; + 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; + + float v = 0.0f; + for(int i = 0;i < 3;++i) + v += std::sin(fb*time*f[i] + o[1])*m[i]; + return v * s; +} + +Ogre::Real LightFunction::flickerFrequency(Ogre::Real phase) +{ + static const float fa = 0.785398f; + static const float tdo = 0.94f; + static const float tdm = 2.48f; + + return tdo + tdm*std::sin(fa * phase); +} + +Ogre::Real LightFunction::calculate(Ogre::Real value) +{ + Ogre::Real brightness = 1.0f; + float cycle_time; + float time_distortion; + + if(mType == LT_Pulse || mType == LT_PulseSlow) + { + cycle_time = 2.0f * Ogre::Math::PI; + time_distortion = 20.0f; + } + else + { + static const float fa = 0.785398f; + static const float phase_wavelength = 120.0f * 3.14159265359f / fa; + + cycle_time = 500.0f; + mPhase = std::fmod(mPhase + value, phase_wavelength); + time_distortion = flickerFrequency(mPhase); + } + + mDeltaCount += mDirection*value*time_distortion; + if(mDirection > 0 && mDeltaCount > +cycle_time) + { + mDirection = -1.0f; + mDeltaCount = 2.0f*cycle_time - mDeltaCount; + } + if(mDirection < 0 && mDeltaCount < -cycle_time) + { + mDirection = +1.0f; + mDeltaCount = -2.0f*cycle_time - mDeltaCount; + } + + 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(mType == LT_Normal) + { + // Less than 1/255 light modifier for a constant light: + brightness = 1.0 + flickerAmplitude(mDeltaCount*slow)/255.0f; + } + else if(mType == LT_Flicker) + brightness = 0.75 + flickerAmplitude(mDeltaCount*fast)*0.25; + else if(mType == LT_FlickerSlow) + brightness = 0.75 + flickerAmplitude(mDeltaCount*slow)*0.25; + else if(mType == LT_Pulse) + brightness = 1.0 + pulseAmplitude(mDeltaCount*fast)*0.25; + else if(mType == LT_PulseSlow) + brightness = 1.0 + pulseAmplitude(mDeltaCount*slow)*0.25; + + return brightness; +} + + +LightValue::LightValue(Ogre::Light *light, const Ogre::ColourValue &color) + : mTarget(light) + , mColor(color) +{ +} + +Ogre::Real LightValue::getValue() const +{ + return 0.0f; +} + +void LightValue::setValue(Ogre::Real value) +{ + mTarget->setDiffuseColour(mColor * value); +} + +} +} diff --git a/libs/openengine/ogre/lights.hpp b/libs/openengine/ogre/lights.hpp new file mode 100644 index 000000000..c63f16425 --- /dev/null +++ b/libs/openengine/ogre/lights.hpp @@ -0,0 +1,51 @@ +#ifndef OENGINE_OGRE_LIGHTS_H +#define OENGINE_OGRE_LIGHTS_H + +#include +#include + +/* + * Controller classes to handle pulsing and flicker lights + */ + +namespace OEngine { +namespace Render { + enum LightType { + LT_Normal, + LT_Flicker, + LT_FlickerSlow, + LT_Pulse, + LT_PulseSlow + }; + + class LightFunction : public Ogre::ControllerFunction + { + LightType mType; + Ogre::Real mPhase; + Ogre::Real mDirection; + + static Ogre::Real pulseAmplitude(Ogre::Real time); + + static Ogre::Real flickerAmplitude(Ogre::Real time); + static Ogre::Real flickerFrequency(Ogre::Real phase); + + public: + LightFunction(LightType type); + virtual Ogre::Real calculate(Ogre::Real value); + }; + + class LightValue : public Ogre::ControllerValue + { + Ogre::Light *mTarget; + Ogre::ColourValue mColor; + + public: + LightValue(Ogre::Light *light, const Ogre::ColourValue &color); + + virtual Ogre::Real getValue() const; + virtual void setValue(Ogre::Real value); + }; +} +} + +#endif