From e976bb16c5b195d44ce0dfe1b7d390cbecae6fbc Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 5 Aug 2013 17:46:38 -0700 Subject: [PATCH] Add a light for torches --- apps/openmw/mwrender/animation.cpp | 86 ++++++++++++++++++++++++++- apps/openmw/mwrender/animation.hpp | 3 + apps/openmw/mwrender/npcanimation.cpp | 8 +++ 3 files changed, 96 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index b3f601270..adee771f6 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -16,6 +16,7 @@ #include "../mwmechanics/character.hpp" #include "../mwmechanics/creaturestats.hpp" #include "../mwworld/class.hpp" +#include "../mwworld/fallback.hpp" namespace MWRender { @@ -36,7 +37,13 @@ void Animation::AnimationValue::setValue(Ogre::Real) void Animation::destroyObjectList(Ogre::SceneManager *sceneMgr, NifOgre::ObjectList &objects) { for(size_t i = 0;i < objects.mLights.size();i++) - sceneMgr->destroyLight(objects.mLights[i]); + { + Ogre::Light *light = objects.mLights[i]; + // If parent is a scene node, it was created specifically for this light. Destroy it now. + if(light->isAttached() && !light->isParentTagPoint()) + sceneMgr->destroySceneNode(light->getParentSceneNode()); + sceneMgr->destroyLight(light); + } for(size_t i = 0;i < objects.mParticles.size();i++) sceneMgr->destroyParticleSystem(objects.mParticles[i]); for(size_t i = 0;i < objects.mEntities.size();i++) @@ -257,6 +264,83 @@ void Animation::clearAnimSources() } +void Animation::addExtraLight(Ogre::SceneManager *sceneMgr, NifOgre::ObjectList &objlist, const ESM::Light *light) +{ + const MWWorld::Fallback *fallback = MWBase::Environment::get().getWorld()->getFallback(); + + const int clr = light->mData.mColor; + Ogre::ColourValue color(((clr >> 0) & 0xFF) / 255.0f, + ((clr >> 8) & 0xFF) / 255.0f, + ((clr >> 16) & 0xFF) / 255.0f); + const float radius = float(light->mData.mRadius); + + if((light->mData.mFlags&ESM::Light::Negative)) + color *= -1; + + objlist.mLights.push_back(sceneMgr->createLight()); + 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 + + bool quadratic = fallback->getFallbackBool("LightAttenuation_OutQuadInLin") ? + !interior : fallback->getFallbackBool("LightAttenuation_UseQuadratic"); + + // 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 * fallback->getFallbackFloat("LightAttenuation_LinearRadiusMult"); + float attenuation = fallback->getFallbackFloat("LightAttenuation_LinearValue") / r; + float activationRange = 1.0f / (threshold * attenuation); + olight->setAttenuation(activationRange, 0, attenuation, 0); + } + else + { + float r = radius * fallback->getFallbackFloat("LightAttenuation_QuadraticRadiusMult"); + float attenuation = fallback->getFallbackFloat("LightAttenuation_QuadraticValue") / std::pow(r, 2); + float activationRange = std::sqrt(1.0f / (threshold * attenuation)); + olight->setAttenuation(activationRange, 0, 0, attenuation); + } + + // If there's an AttachLight bone, attach the light to that, otherwise put it in the center, + if(objlist.mSkelBase && objlist.mSkelBase->getSkeleton()->hasBone("AttachLight")) + objlist.mSkelBase->attachObjectToBone("AttachLight", olight); + else + { + Ogre::AxisAlignedBox bounds = Ogre::AxisAlignedBox::BOX_NULL; + for(size_t i = 0;i < objlist.mEntities.size();i++) + { + Ogre::Entity *ent = objlist.mEntities[i]; + bounds.merge(ent->getBoundingBox()); + } + + Ogre::SceneNode *node = mInsert->createChildSceneNode(bounds.getCenter()); + node->attachObject(olight); + } +} + + Ogre::Node *Animation::getNode(const std::string &name) { if(mSkelBase) diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 0b8f3a02f..541509fb6 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -158,6 +158,9 @@ protected: * extension will be replaced with .kf. */ void addAnimSource(const std::string &model); + /** Adds an additional light to the given object list using the specified ESM record. */ + void addExtraLight(Ogre::SceneManager *sceneMgr, NifOgre::ObjectList &objlist, const ESM::Light *light); + 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); diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 0232c71c5..6611b3694 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -276,6 +276,14 @@ void NpcAnimation::updateParts(bool forceupdate) const ESM::Light *light = part.get()->mBase; addOrReplaceIndividualPart(ESM::PRT_Shield, MWWorld::InventoryStore::Slot_CarriedLeft, 1, "meshes\\"+light->mModel); + for(size_t i = 0;i < sPartListSize;i++) + { + if(ESM::PRT_Shield == sPartList[i].type) + { + addExtraLight(mInsert->getCreator(), mObjectParts[i], light); + break; + } + } } }