Merge remote-tracking branch 'scrawl/master'

This commit is contained in:
Marc Zinnschlag 2013-12-09 18:39:34 +01:00
commit 77a2179d1e
25 changed files with 723 additions and 334 deletions

View file

@ -517,6 +517,8 @@ void OMW::Engine::activate()
std::string script = MWWorld::Class::get (ptr).getScript (ptr); std::string script = MWWorld::Class::get (ptr).getScript (ptr);
MWBase::Environment::get().getWorld()->breakInvisibility(MWBase::Environment::get().getWorld()->getPlayer().getPlayer());
if (!script.empty()) if (!script.empty())
{ {
MWBase::Environment::get().getWorld()->getLocalScripts().setIgnore (ptr); MWBase::Environment::get().getWorld()->getLocalScripts().setIgnore (ptr);

View file

@ -419,6 +419,8 @@ namespace MWBase
virtual void launchProjectile (const std::string& id, bool stack, const ESM::EffectList& effects, virtual void launchProjectile (const std::string& id, bool stack, const ESM::EffectList& effects,
const MWWorld::Ptr& actor, const std::string& sourceName) = 0; const MWWorld::Ptr& actor, const std::string& sourceName) = 0;
virtual void breakInvisibility (const MWWorld::Ptr& actor) = 0;
}; };
} }

View file

@ -149,7 +149,7 @@ namespace MWGui
// health, magicka, fatigue tooltip // health, magicka, fatigue tooltip
MyGUI::Widget* w; MyGUI::Widget* w;
std::string valStr = boost::lexical_cast<std::string>(value.getCurrent()) + "/" + boost::lexical_cast<std::string>(value.getModified()); std::string valStr = boost::lexical_cast<std::string>(int(value.getCurrent())) + "/" + boost::lexical_cast<std::string>(int(value.getModified()));
if (i==0) if (i==0)
{ {
getWidget(w, "Health"); getWidget(w, "Health");

View file

@ -501,6 +501,7 @@ bool CharacterController::updateNpcState(bool onground, bool inwater, bool isrun
{ {
if(mUpperBodyState == UpperCharState_WeapEquiped) if(mUpperBodyState == UpperCharState_WeapEquiped)
{ {
MWBase::Environment::get().getWorld()->breakInvisibility(mPtr);
mAttackType.clear(); mAttackType.clear();
if(mWeaponType == WeapType_Spell) if(mWeaponType == WeapType_Spell)
{ {
@ -727,6 +728,8 @@ void CharacterController::update(float duration)
const MWWorld::Class &cls = MWWorld::Class::get(mPtr); const MWWorld::Class &cls = MWWorld::Class::get(mPtr);
Ogre::Vector3 movement(0.0f); Ogre::Vector3 movement(0.0f);
updateVisibility();
if(!cls.isActor()) if(!cls.isActor())
{ {
if(mAnimQueue.size() > 1) if(mAnimQueue.size() > 1)
@ -1130,4 +1133,25 @@ void CharacterController::updateContinuousVfx()
} }
} }
void CharacterController::updateVisibility()
{
if (!mPtr.getClass().isActor())
return;
float alpha = 1.f;
if (mPtr.getClass().getCreatureStats(mPtr).getMagicEffects().get(ESM::MagicEffect::Invisibility).mMagnitude)
{
if (mPtr.getRefData().getHandle() == "player")
alpha = 0.4f;
else
alpha = 0.f;
}
float chameleon = mPtr.getClass().getCreatureStats(mPtr).getMagicEffects().get(ESM::MagicEffect::Chameleon).mMagnitude;
if (chameleon)
{
alpha *= std::max(0.2f, (100.f - chameleon)/100.f);
}
mAnimation->setAlpha(alpha);
}
} }

View file

@ -173,6 +173,8 @@ class CharacterController
bool updateNpcState(bool onground, bool inwater, bool isrunning, bool sneak); bool updateNpcState(bool onground, bool inwater, bool isrunning, bool sneak);
void updateVisibility();
public: public:
CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim); CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim);
virtual ~CharacterController(); virtual ~CharacterController();

View file

@ -51,28 +51,6 @@ void Animation::EffectAnimationValue::setValue(Ogre::Real)
{ {
} }
void Animation::destroyObjectList(Ogre::SceneManager *sceneMgr, NifOgre::ObjectList &objects)
{
for(size_t i = 0;i < objects.mLights.size();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++)
sceneMgr->destroyEntity(objects.mEntities[i]);
objects.mControllers.clear();
objects.mLights.clear();
objects.mParticles.clear();
objects.mEntities.clear();
objects.mSkelBase = NULL;
}
Animation::Animation(const MWWorld::Ptr &ptr, Ogre::SceneNode *node) Animation::Animation(const MWWorld::Ptr &ptr, Ogre::SceneNode *node)
: mPtr(ptr) : mPtr(ptr)
, mCamera(NULL) , mCamera(NULL)
@ -90,13 +68,9 @@ Animation::Animation(const MWWorld::Ptr &ptr, Ogre::SceneNode *node)
Animation::~Animation() Animation::~Animation()
{ {
for (std::vector<EffectParams>::iterator it = mEffects.begin(); it != mEffects.end(); ++it) mEffects.clear();
destroyObjectList(mInsert->getCreator(), it->mObjects);
mAnimSources.clear(); mAnimSources.clear();
Ogre::SceneManager *sceneMgr = mInsert->getCreator();
destroyObjectList(sceneMgr, mObjectRoot);
} }
@ -105,7 +79,7 @@ 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; mSkelBase = NULL;
destroyObjectList(mInsert->getCreator(), mObjectRoot); mObjectRoot.setNull();
if(model.empty()) if(model.empty())
return; return;
@ -126,11 +100,11 @@ void Animation::setObjectRoot(const std::string &model, bool baseonly)
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)
{ {
mSkelBase = mObjectRoot.mSkelBase; mSkelBase = mObjectRoot->mSkelBase;
Ogre::AnimationStateSet *aset = mObjectRoot.mSkelBase->getAllAnimationStates(); Ogre::AnimationStateSet *aset = mObjectRoot->mSkelBase->getAllAnimationStates();
Ogre::AnimationStateIterator asiter = aset->getAnimationStateIterator(); Ogre::AnimationStateIterator asiter = aset->getAnimationStateIterator();
while(asiter.hasMoreElements()) while(asiter.hasMoreElements())
{ {
@ -141,7 +115,7 @@ void Animation::setObjectRoot(const std::string &model, bool baseonly)
// Set the bones as manually controlled since we're applying the // Set the bones as manually controlled since we're applying the
// transformations manually // transformations manually
Ogre::SkeletonInstance *skelinst = mObjectRoot.mSkelBase->getSkeleton(); Ogre::SkeletonInstance *skelinst = mObjectRoot->mSkelBase->getSkeleton();
Ogre::Skeleton::BoneIterator boneiter = skelinst->getBoneIterator(); Ogre::Skeleton::BoneIterator boneiter = skelinst->getBoneIterator();
while(boneiter.hasMoreElements()) while(boneiter.hasMoreElements())
boneiter.getNext()->setManuallyControlled(true); boneiter.getNext()->setManuallyControlled(true);
@ -162,10 +136,10 @@ void Animation::setObjectRoot(const std::string &model, bool baseonly)
else else
mAttachedObjects.clear(); mAttachedObjects.clear();
for(size_t i = 0;i < mObjectRoot.mControllers.size();i++) for(size_t i = 0;i < mObjectRoot->mControllers.size();i++)
{ {
if(mObjectRoot.mControllers[i].getSource().isNull()) if(mObjectRoot->mControllers[i].getSource().isNull())
mObjectRoot.mControllers[i].setSource(mAnimationValuePtr[0]); mObjectRoot->mControllers[i].setSource(mAnimationValuePtr[0]);
} }
} }
@ -233,15 +207,15 @@ public:
} }
}; };
void Animation::setRenderProperties(const NifOgre::ObjectList &objlist, Ogre::uint32 visflags, Ogre::uint8 solidqueue, Ogre::uint8 transqueue, Ogre::Real dist, bool enchantedGlow, Ogre::Vector3* glowColor) void Animation::setRenderProperties(NifOgre::ObjectScenePtr objlist, Ogre::uint32 visflags, Ogre::uint8 solidqueue, Ogre::uint8 transqueue, Ogre::Real dist, bool enchantedGlow, Ogre::Vector3* glowColor)
{ {
std::for_each(objlist.mEntities.begin(), objlist.mEntities.end(), std::for_each(objlist->mEntities.begin(), objlist->mEntities.end(),
VisQueueSet(visflags, solidqueue, transqueue, dist)); 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, dist)); VisQueueSet(visflags, solidqueue, transqueue, dist));
if (enchantedGlow) if (enchantedGlow)
std::for_each(objlist.mEntities.begin(), objlist.mEntities.end(), std::for_each(objlist->mEntities.begin(), objlist->mEntities.end(),
AddGlow(glowColor)); AddGlow(glowColor));
} }
@ -340,7 +314,7 @@ void Animation::clearAnimSources()
} }
void Animation::addExtraLight(Ogre::SceneManager *sceneMgr, NifOgre::ObjectList &objlist, const ESM::Light *light) void Animation::addExtraLight(Ogre::SceneManager *sceneMgr, NifOgre::ObjectScenePtr objlist, const ESM::Light *light)
{ {
const MWWorld::Fallback *fallback = MWBase::Environment::get().getWorld()->getFallback(); const MWWorld::Fallback *fallback = MWBase::Environment::get().getWorld()->getFallback();
@ -353,8 +327,8 @@ void Animation::addExtraLight(Ogre::SceneManager *sceneMgr, NifOgre::ObjectList
if((light->mData.mFlags&ESM::Light::Negative)) if((light->mData.mFlags&ESM::Light::Negative))
color *= -1; color *= -1;
objlist.mLights.push_back(sceneMgr->createLight()); objlist->mLights.push_back(sceneMgr->createLight());
Ogre::Light *olight = objlist.mLights.back(); Ogre::Light *olight = objlist->mLights.back();
olight->setDiffuseColour(color); olight->setDiffuseColour(color);
Ogre::ControllerValueRealPtr src(Ogre::ControllerManager::getSingleton().getFrameTimeSource()); Ogre::ControllerValueRealPtr src(Ogre::ControllerManager::getSingleton().getFrameTimeSource());
@ -366,7 +340,7 @@ void Animation::addExtraLight(Ogre::SceneManager *sceneMgr, NifOgre::ObjectList
(light->mData.mFlags&ESM::Light::PulseSlow) ? OEngine::Render::LT_PulseSlow : (light->mData.mFlags&ESM::Light::PulseSlow) ? OEngine::Render::LT_PulseSlow :
OEngine::Render::LT_Normal OEngine::Render::LT_Normal
)); ));
objlist.mControllers.push_back(Ogre::Controller<Ogre::Real>(src, dest, func)); objlist->mControllers.push_back(Ogre::Controller<Ogre::Real>(src, dest, func));
bool interior = !(mPtr.isInCell() && mPtr.getCell()->mCell->isExterior()); bool interior = !(mPtr.isInCell() && mPtr.getCell()->mCell->isExterior());
bool quadratic = fallback->getFallbackBool("LightAttenuation_OutQuadInLin") ? bool quadratic = fallback->getFallbackBool("LightAttenuation_OutQuadInLin") ?
@ -392,14 +366,14 @@ void Animation::addExtraLight(Ogre::SceneManager *sceneMgr, NifOgre::ObjectList
} }
// If there's an AttachLight bone, attach the light to that, otherwise put it in the center, // 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")) if(objlist->mSkelBase && objlist->mSkelBase->getSkeleton()->hasBone("AttachLight"))
objlist.mSkelBase->attachObjectToBone("AttachLight", olight); objlist->mSkelBase->attachObjectToBone("AttachLight", olight);
else else
{ {
Ogre::AxisAlignedBox bounds = Ogre::AxisAlignedBox::BOX_NULL; Ogre::AxisAlignedBox bounds = Ogre::AxisAlignedBox::BOX_NULL;
for(size_t i = 0;i < objlist.mEntities.size();i++) for(size_t i = 0;i < objlist->mEntities.size();i++)
{ {
Ogre::Entity *ent = objlist.mEntities[i]; Ogre::Entity *ent = objlist->mEntities[i];
bounds.merge(ent->getBoundingBox()); bounds.merge(ent->getBoundingBox());
} }
@ -942,8 +916,8 @@ Ogre::Vector3 Animation::runAnimation(float duration)
++stateiter; ++stateiter;
} }
for(size_t i = 0;i < mObjectRoot.mControllers.size();i++) for(size_t i = 0;i < mObjectRoot->mControllers.size();i++)
mObjectRoot.mControllers[i].update(); mObjectRoot->mControllers[i].update();
// Apply group controllers // Apply group controllers
for(size_t grp = 0;grp < sNumGroups;grp++) for(size_t grp = 0;grp < sNumGroups;grp++)
@ -986,7 +960,7 @@ public:
void Animation::enableLights(bool enable) void Animation::enableLights(bool enable)
{ {
std::for_each(mObjectRoot.mLights.begin(), mObjectRoot.mLights.end(), ToggleLight(enable)); std::for_each(mObjectRoot->mLights.begin(), mObjectRoot->mLights.end(), ToggleLight(enable));
} }
@ -1005,7 +979,7 @@ public:
Ogre::AxisAlignedBox Animation::getWorldBounds() Ogre::AxisAlignedBox Animation::getWorldBounds()
{ {
Ogre::AxisAlignedBox bounds = Ogre::AxisAlignedBox::BOX_NULL; Ogre::AxisAlignedBox bounds = Ogre::AxisAlignedBox::BOX_NULL;
std::for_each(mObjectRoot.mEntities.begin(), mObjectRoot.mEntities.end(), MergeBounds(&bounds)); std::for_each(mObjectRoot->mEntities.begin(), mObjectRoot->mEntities.end(), MergeBounds(&bounds));
return bounds; return bounds;
} }
@ -1055,17 +1029,17 @@ void Animation::addEffect(const std::string &model, int effectId, bool loop, con
params.mEffectId = effectId; params.mEffectId = effectId;
params.mBoneName = bonename; params.mBoneName = bonename;
for(size_t i = 0;i < params.mObjects.mControllers.size();i++) for(size_t i = 0;i < params.mObjects->mControllers.size();i++)
{ {
if(params.mObjects.mControllers[i].getSource().isNull()) if(params.mObjects->mControllers[i].getSource().isNull())
params.mObjects.mControllers[i].setSource(Ogre::SharedPtr<EffectAnimationValue> (new EffectAnimationValue())); params.mObjects->mControllers[i].setSource(Ogre::SharedPtr<EffectAnimationValue> (new EffectAnimationValue()));
} }
if (!texture.empty()) if (!texture.empty())
{ {
for(size_t i = 0;i < params.mObjects.mParticles.size(); ++i) for(size_t i = 0;i < params.mObjects->mParticles.size(); ++i)
{ {
Ogre::ParticleSystem* partSys = params.mObjects.mParticles[i]; Ogre::ParticleSystem* partSys = params.mObjects->mParticles[i];
sh::Factory::getInstance()._ensureMaterial(partSys->getMaterialName(), "Default"); sh::Factory::getInstance()._ensureMaterial(partSys->getMaterialName(), "Default");
Ogre::MaterialPtr mat = Ogre::MaterialManager::getSingleton().getByName(partSys->getMaterialName()); Ogre::MaterialPtr mat = Ogre::MaterialManager::getSingleton().getByName(partSys->getMaterialName());
static int count = 0; static int count = 0;
@ -1099,7 +1073,6 @@ void Animation::removeEffect(int effectId)
{ {
if (it->mEffectId == effectId) if (it->mEffectId == effectId)
{ {
destroyObjectList(mInsert->getCreator(), it->mObjects);
mEffects.erase(it); mEffects.erase(it);
return; return;
} }
@ -1119,32 +1092,31 @@ void Animation::updateEffects(float duration)
{ {
for (std::vector<EffectParams>::iterator it = mEffects.begin(); it != mEffects.end(); ) for (std::vector<EffectParams>::iterator it = mEffects.begin(); it != mEffects.end(); )
{ {
NifOgre::ObjectList& objects = it->mObjects; NifOgre::ObjectScenePtr objects = it->mObjects;
for(size_t i = 0; i < objects.mControllers.size() ;i++) for(size_t i = 0; i < objects->mControllers.size() ;i++)
{ {
EffectAnimationValue* value = dynamic_cast<EffectAnimationValue*>(objects.mControllers[i].getSource().get()); EffectAnimationValue* value = dynamic_cast<EffectAnimationValue*>(objects->mControllers[i].getSource().get());
if (value) if (value)
value->addTime(duration); value->addTime(duration);
objects.mControllers[i].update(); objects->mControllers[i].update();
} }
if (objects.mControllers[0].getSource()->getValue() >= objects.mMaxControllerLength) if (objects->mControllers[0].getSource()->getValue() >= objects->mMaxControllerLength)
{ {
if (it->mLoop) if (it->mLoop)
{ {
// Start from the beginning again; carry over the remainder // Start from the beginning again; carry over the remainder
float remainder = objects.mControllers[0].getSource()->getValue() - objects.mMaxControllerLength; float remainder = objects->mControllers[0].getSource()->getValue() - objects->mMaxControllerLength;
for(size_t i = 0; i < objects.mControllers.size() ;i++) for(size_t i = 0; i < objects->mControllers.size() ;i++)
{ {
EffectAnimationValue* value = dynamic_cast<EffectAnimationValue*>(objects.mControllers[i].getSource().get()); EffectAnimationValue* value = dynamic_cast<EffectAnimationValue*>(objects->mControllers[i].getSource().get());
if (value) if (value)
value->resetTime(remainder); value->resetTime(remainder);
} }
} }
else else
{ {
destroyObjectList(mInsert->getCreator(), it->mObjects);
it = mEffects.erase(it); it = mEffects.erase(it);
continue; continue;
} }
@ -1214,16 +1186,16 @@ public:
bool ObjectAnimation::canBatch() const bool ObjectAnimation::canBatch() const
{ {
if(!mObjectRoot.mParticles.empty() || !mObjectRoot.mLights.empty() || !mObjectRoot.mControllers.empty()) if(!mObjectRoot->mParticles.empty() || !mObjectRoot->mLights.empty() || !mObjectRoot->mControllers.empty())
return false; return false;
return std::find_if(mObjectRoot.mEntities.begin(), mObjectRoot.mEntities.end(), return std::find_if(mObjectRoot->mEntities.begin(), mObjectRoot->mEntities.end(),
FindEntityTransparency()) == mObjectRoot.mEntities.end(); FindEntityTransparency()) == mObjectRoot->mEntities.end();
} }
void ObjectAnimation::fillBatch(Ogre::StaticGeometry *sg) void ObjectAnimation::fillBatch(Ogre::StaticGeometry *sg)
{ {
std::vector<Ogre::Entity*>::reverse_iterator iter = mObjectRoot.mEntities.rbegin(); std::vector<Ogre::Entity*>::reverse_iterator iter = mObjectRoot->mEntities.rbegin();
for(;iter != mObjectRoot.mEntities.rend();++iter) for(;iter != mObjectRoot->mEntities.rend();++iter)
{ {
Ogre::Node *node = (*iter)->getParentNode(); Ogre::Node *node = (*iter)->getParentNode();
sg->addEntity(*iter, node->_getDerivedPosition(), node->_getDerivedOrientation(), node->_getDerivedScale()); sg->addEntity(*iter, node->_getDerivedPosition(), node->_getDerivedOrientation(), node->_getDerivedScale());

View file

@ -112,7 +112,7 @@ protected:
struct EffectParams struct EffectParams
{ {
std::string mModelName; // Just here so we don't add the same effect twice std::string mModelName; // Just here so we don't add the same effect twice
NifOgre::ObjectList mObjects; NifOgre::ObjectScenePtr mObjects;
int mEffectId; int mEffectId;
bool mLoop; bool mLoop;
std::string mBoneName; std::string mBoneName;
@ -125,7 +125,7 @@ protected:
Ogre::SceneNode *mInsert; Ogre::SceneNode *mInsert;
Ogre::Entity *mSkelBase; Ogre::Entity *mSkelBase;
NifOgre::ObjectList mObjectRoot; NifOgre::ObjectScenePtr mObjectRoot;
AnimSourceList mAnimSources; AnimSourceList mAnimSources;
Ogre::Node *mAccumRoot; Ogre::Node *mAccumRoot;
Ogre::Node *mNonAccumRoot; Ogre::Node *mNonAccumRoot;
@ -187,11 +187,9 @@ protected:
void addAnimSource(const std::string &model); void addAnimSource(const std::string &model);
/** Adds an additional light to the given object list using the specified ESM record. */ /** 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); void addExtraLight(Ogre::SceneManager *sceneMgr, NifOgre::ObjectScenePtr objlist, const ESM::Light *light);
static void destroyObjectList(Ogre::SceneManager *sceneMgr, NifOgre::ObjectList &objects); static void setRenderProperties(NifOgre::ObjectScenePtr objlist, Ogre::uint32 visflags, Ogre::uint8 solidqueue,
static void setRenderProperties(const NifOgre::ObjectList &objlist, Ogre::uint32 visflags, Ogre::uint8 solidqueue,
Ogre::uint8 transqueue, Ogre::Real dist=0.0f, Ogre::uint8 transqueue, Ogre::Real dist=0.0f,
bool enchantedGlow=false, Ogre::Vector3* glowColor=NULL); bool enchantedGlow=false, Ogre::Vector3* glowColor=NULL);
@ -217,6 +215,8 @@ public:
void addEffect (const std::string& model, int effectId, bool loop = false, const std::string& bonename = "", std::string texture = ""); void addEffect (const std::string& model, int effectId, bool loop = false, const std::string& bonename = "", std::string texture = "");
void removeEffect (int effectId); void removeEffect (int effectId);
void getLoopingEffects (std::vector<int>& out); void getLoopingEffects (std::vector<int>& out);
virtual void setAlpha(float alpha) {}
private: private:
void updateEffects(float duration); void updateEffects(float duration);

View file

@ -5,6 +5,8 @@
#include <OgreParticleSystem.h> #include <OgreParticleSystem.h>
#include <OgreSubEntity.h> #include <OgreSubEntity.h>
#include <extern/shiny/Main/Factory.hpp>
#include "../mwworld/esmstore.hpp" #include "../mwworld/esmstore.hpp"
#include "../mwworld/inventorystore.hpp" #include "../mwworld/inventorystore.hpp"
#include "../mwworld/class.hpp" #include "../mwworld/class.hpp"
@ -106,10 +108,6 @@ NpcAnimation::~NpcAnimation()
{ {
if (!mListenerDisabled) if (!mListenerDisabled)
mPtr.getClass().getInventoryStore(mPtr).setListener(NULL, mPtr); mPtr.getClass().getInventoryStore(mPtr).setListener(NULL, mPtr);
Ogre::SceneManager *sceneMgr = mInsert->getCreator();
for(size_t i = 0;i < ESM::PRT_Count;i++)
destroyObjectList(sceneMgr, mObjectParts[i]);
} }
@ -120,7 +118,8 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, int v
mViewMode(viewMode), mViewMode(viewMode),
mShowWeapons(false), mShowWeapons(false),
mShowShield(true), mShowShield(true),
mFirstPersonOffset(0.f, 0.f, 0.f) mFirstPersonOffset(0.f, 0.f, 0.f),
mAlpha(1.f)
{ {
mNpc = mPtr.get<ESM::NPC>()->mBase; mNpc = mPtr.get<ESM::NPC>()->mBase;
@ -223,6 +222,7 @@ void NpcAnimation::updateNpcBase()
void NpcAnimation::updateParts() void NpcAnimation::updateParts()
{ {
mAlpha = 1.f;
const MWWorld::Class &cls = MWWorld::Class::get(mPtr); const MWWorld::Class &cls = MWWorld::Class::get(mPtr);
MWWorld::InventoryStore &inv = cls.getInventoryStore(mPtr); MWWorld::InventoryStore &inv = cls.getInventoryStore(mPtr);
@ -447,18 +447,18 @@ public:
} }
}; };
NifOgre::ObjectList NpcAnimation::insertBoundedPart(const std::string &model, int group, const std::string &bonename, bool enchantedGlow, Ogre::Vector3* glowColor) NifOgre::ObjectScenePtr NpcAnimation::insertBoundedPart(const std::string &model, int group, const std::string &bonename, bool enchantedGlow, Ogre::Vector3* glowColor)
{ {
NifOgre::ObjectList objects = NifOgre::Loader::createObjects(mSkelBase, bonename, mInsert, model); NifOgre::ObjectScenePtr objects = NifOgre::Loader::createObjects(mSkelBase, bonename, mInsert, model);
setRenderProperties(objects, (mViewMode == VM_FirstPerson) ? RV_FirstPerson : mVisibilityFlags, RQG_Main, RQG_Alpha, 0, setRenderProperties(objects, (mViewMode == VM_FirstPerson) ? RV_FirstPerson : mVisibilityFlags, RQG_Main, RQG_Alpha, 0,
enchantedGlow, glowColor); enchantedGlow, glowColor);
std::for_each(objects.mEntities.begin(), objects.mEntities.end(), SetObjectGroup(group)); std::for_each(objects->mEntities.begin(), objects->mEntities.end(), SetObjectGroup(group));
std::for_each(objects.mParticles.begin(), objects.mParticles.end(), SetObjectGroup(group)); std::for_each(objects->mParticles.begin(), objects->mParticles.end(), SetObjectGroup(group));
if(objects.mSkelBase) if(objects->mSkelBase)
{ {
Ogre::AnimationStateSet *aset = objects.mSkelBase->getAllAnimationStates(); Ogre::AnimationStateSet *aset = objects->mSkelBase->getAllAnimationStates();
Ogre::AnimationStateIterator asiter = aset->getAnimationStateIterator(); Ogre::AnimationStateIterator asiter = aset->getAnimationStateIterator();
while(asiter.hasMoreElements()) while(asiter.hasMoreElements())
{ {
@ -466,7 +466,7 @@ NifOgre::ObjectList NpcAnimation::insertBoundedPart(const std::string &model, in
state->setEnabled(false); state->setEnabled(false);
state->setLoop(false); state->setLoop(false);
} }
Ogre::SkeletonInstance *skelinst = objects.mSkelBase->getSkeleton(); Ogre::SkeletonInstance *skelinst = objects->mSkelBase->getSkeleton();
Ogre::Skeleton::BoneIterator boneiter = skelinst->getBoneIterator(); Ogre::Skeleton::BoneIterator boneiter = skelinst->getBoneIterator();
while(boneiter.hasMoreElements()) while(boneiter.hasMoreElements())
boneiter.getNext()->setManuallyControlled(true); boneiter.getNext()->setManuallyControlled(true);
@ -494,11 +494,13 @@ Ogre::Vector3 NpcAnimation::runAnimation(float timepassed)
for(size_t i = 0;i < ESM::PRT_Count;i++) for(size_t i = 0;i < ESM::PRT_Count;i++)
{ {
std::vector<Ogre::Controller<Ogre::Real> >::iterator ctrl(mObjectParts[i].mControllers.begin()); if (mObjectParts[i].isNull())
for(;ctrl != mObjectParts[i].mControllers.end();ctrl++) continue;
std::vector<Ogre::Controller<Ogre::Real> >::iterator ctrl(mObjectParts[i]->mControllers.begin());
for(;ctrl != mObjectParts[i]->mControllers.end();ctrl++)
ctrl->update(); ctrl->update();
Ogre::Entity *ent = mObjectParts[i].mSkelBase; Ogre::Entity *ent = mObjectParts[i]->mSkelBase;
if(!ent) continue; if(!ent) continue;
updateSkeletonInstance(baseinst, ent->getSkeleton()); updateSkeletonInstance(baseinst, ent->getSkeleton());
ent->getAllAnimationStates()->_notifyDirty(); ent->getAllAnimationStates()->_notifyDirty();
@ -512,7 +514,7 @@ void NpcAnimation::removeIndividualPart(ESM::PartReferenceType type)
mPartPriorities[type] = 0; mPartPriorities[type] = 0;
mPartslots[type] = -1; mPartslots[type] = -1;
destroyObjectList(mInsert->getCreator(), mObjectParts[type]); mObjectParts[type].setNull();
} }
void NpcAnimation::reserveIndividualPart(ESM::PartReferenceType type, int group, int priority) void NpcAnimation::reserveIndividualPart(ESM::PartReferenceType type, int group, int priority)
@ -544,12 +546,12 @@ bool NpcAnimation::addOrReplaceIndividualPart(ESM::PartReferenceType type, int g
mPartPriorities[type] = priority; mPartPriorities[type] = priority;
mObjectParts[type] = insertBoundedPart(mesh, group, sPartList.at(type), enchantedGlow, glowColor); mObjectParts[type] = insertBoundedPart(mesh, group, sPartList.at(type), enchantedGlow, glowColor);
if(mObjectParts[type].mSkelBase) if(mObjectParts[type]->mSkelBase)
{ {
Ogre::SkeletonInstance *skel = mObjectParts[type].mSkelBase->getSkeleton(); Ogre::SkeletonInstance *skel = mObjectParts[type]->mSkelBase->getSkeleton();
if(mObjectParts[type].mSkelBase->isParentTagPoint()) if(mObjectParts[type]->mSkelBase->isParentTagPoint())
{ {
Ogre::Node *root = mObjectParts[type].mSkelBase->getParentNode(); Ogre::Node *root = mObjectParts[type]->mSkelBase->getParentNode();
if(skel->hasBone("BoneOffset")) if(skel->hasBone("BoneOffset"))
{ {
Ogre::Bone *offset = skel->getBone("BoneOffset"); Ogre::Bone *offset = skel->getBone("BoneOffset");
@ -571,8 +573,8 @@ bool NpcAnimation::addOrReplaceIndividualPart(ESM::PartReferenceType type, int g
// TODO: // TODO:
// type == ESM::PRT_Weapon should get an animation source based on the current offset // type == ESM::PRT_Weapon should get an animation source based on the current offset
// of the weapon attack animation (from its beginning, or start marker?) // of the weapon attack animation (from its beginning, or start marker?)
std::vector<Ogre::Controller<Ogre::Real> >::iterator ctrl(mObjectParts[type].mControllers.begin()); std::vector<Ogre::Controller<Ogre::Real> >::iterator ctrl(mObjectParts[type]->mControllers.begin());
for(;ctrl != mObjectParts[type].mControllers.end();ctrl++) for(;ctrl != mObjectParts[type]->mControllers.end();ctrl++)
{ {
if(ctrl->getSource().isNull()) if(ctrl->getSource().isNull())
{ {
@ -649,6 +651,7 @@ void NpcAnimation::showWeapons(bool showWeapon)
{ {
removeIndividualPart(ESM::PRT_Weapon); removeIndividualPart(ESM::PRT_Weapon);
} }
mAlpha = 1.f;
} }
void NpcAnimation::showShield(bool show) void NpcAnimation::showShield(bool show)
@ -707,4 +710,56 @@ void NpcAnimation::permanentEffectAdded(const ESM::MagicEffect *magicEffect, boo
} }
} }
void NpcAnimation::setAlpha(float alpha)
{
if (alpha == mAlpha)
return;
mAlpha = alpha;
for (int i=0; i<ESM::PRT_Count; ++i)
{
if (mObjectParts[i].isNull())
continue;
for (unsigned int j=0; j<mObjectParts[i]->mEntities.size(); ++j)
{
Ogre::Entity* ent = mObjectParts[i]->mEntities[j];
if (ent != mObjectParts[i]->mSkelBase)
applyAlpha(alpha, ent, mObjectParts[i]);
}
}
}
void NpcAnimation::applyAlpha(float alpha, Ogre::Entity *ent, NifOgre::ObjectScenePtr scene)
{
ent->getSubEntity(0)->setRenderQueueGroup(alpha != 1.f || ent->getSubEntity(0)->getMaterial()->isTransparent()
? RQG_Alpha : RQG_Main);
Ogre::MaterialPtr mat = scene->mMaterialControllerMgr.getWritableMaterial(ent);
if (mAlpha == 1.f)
{
// Don't bother remembering what the original values were. Just remove the techniques and let the factory restore them.
mat->removeAllTechniques();
sh::Factory::getInstance()._ensureMaterial(mat->getName(), "Default");
return;
}
Ogre::Material::TechniqueIterator techs = mat->getTechniqueIterator();
while(techs.hasMoreElements())
{
Ogre::Technique *tech = techs.getNext();
Ogre::Technique::PassIterator passes = tech->getPassIterator();
while(passes.hasMoreElements())
{
Ogre::Pass *pass = passes.getNext();
pass->setSceneBlending(Ogre::SBT_TRANSPARENT_ALPHA);
Ogre::ColourValue diffuse = pass->getDiffuse();
diffuse.a = alpha;
pass->setDiffuse(diffuse);
pass->setVertexColourTracking(pass->getVertexColourTracking() &~Ogre::TVC_DIFFUSE);
}
}
}
} }

View file

@ -46,7 +46,7 @@ private:
bool mListenerDisabled; bool mListenerDisabled;
// Bounded Parts // Bounded Parts
NifOgre::ObjectList mObjectParts[ESM::PRT_Count]; NifOgre::ObjectScenePtr mObjectParts[ESM::PRT_Count];
const ESM::NPC *mNpc; const ESM::NPC *mNpc;
std::string mHeadModel; std::string mHeadModel;
@ -64,9 +64,11 @@ private:
Ogre::SharedPtr<SayAnimationValue> mSayAnimationValue; Ogre::SharedPtr<SayAnimationValue> mSayAnimationValue;
float mAlpha;
void updateNpcBase(); void updateNpcBase();
NifOgre::ObjectList insertBoundedPart(const std::string &model, int group, const std::string &bonename, NifOgre::ObjectScenePtr insertBoundedPart(const std::string &model, int group, const std::string &bonename,
bool enchantedGlow, Ogre::Vector3* glowColor=NULL); bool enchantedGlow, Ogre::Vector3* glowColor=NULL);
void removeIndividualPart(ESM::PartReferenceType type); void removeIndividualPart(ESM::PartReferenceType type);
@ -78,6 +80,8 @@ private:
void addPartGroup(int group, int priority, const std::vector<ESM::PartReference> &parts, void addPartGroup(int group, int priority, const std::vector<ESM::PartReference> &parts,
bool enchantedGlow=false, Ogre::Vector3* glowColor=NULL); bool enchantedGlow=false, Ogre::Vector3* glowColor=NULL);
void applyAlpha(float alpha, Ogre::Entity* ent, NifOgre::ObjectScenePtr scene);
public: public:
/** /**
* @param ptr * @param ptr
@ -109,6 +113,9 @@ public:
/// Rebuilds the NPC, updating their root model, animation sources, and equipment. /// Rebuilds the NPC, updating their root model, animation sources, and equipment.
void rebuild(); void rebuild();
/// Make the NPC only partially visible
virtual void setAlpha(float alpha);
}; };
} }

View file

@ -60,14 +60,14 @@ RenderingManager::RenderingManager(OEngine::Render::OgreRenderer& _rend, const b
MWWorld::Fallback* fallback) MWWorld::Fallback* fallback)
: mRendering(_rend) : mRendering(_rend)
, mFallback(fallback) , mFallback(fallback)
, mObjects(mRendering)
, mActors(mRendering, this)
, mPlayerAnimation(NULL) , mPlayerAnimation(NULL)
, mAmbientMode(0) , mAmbientMode(0)
, mSunEnabled(0) , mSunEnabled(0)
, mPhysicsEngine(engine) , mPhysicsEngine(engine)
, mTerrain(NULL) , mTerrain(NULL)
{ {
mActors = new MWRender::Actors(mRendering, this);
mObjects = new MWRender::Objects(mRendering);
// select best shader mode // select best shader mode
bool openGL = (Ogre::Root::getSingleton ().getRenderSystem ()->getName().find("OpenGL") != std::string::npos); bool openGL = (Ogre::Root::getSingleton ().getRenderSystem ()->getName().find("OpenGL") != std::string::npos);
bool glES = (Ogre::Root::getSingleton ().getRenderSystem ()->getName().find("OpenGL ES") != std::string::npos); bool glES = (Ogre::Root::getSingleton ().getRenderSystem ()->getName().find("OpenGL ES") != std::string::npos);
@ -162,8 +162,8 @@ RenderingManager::RenderingManager(OEngine::Render::OgreRenderer& _rend, const b
mRootNode = mRendering.getScene()->getRootSceneNode(); mRootNode = mRendering.getScene()->getRootSceneNode();
mRootNode->createChildSceneNode("player"); mRootNode->createChildSceneNode("player");
mObjects.setRootNode(mRootNode); mObjects->setRootNode(mRootNode);
mActors.setRootNode(mRootNode); mActors->setRootNode(mRootNode);
mCamera = new MWRender::Camera(mRendering.getCamera()); mCamera = new MWRender::Camera(mRendering.getCamera());
@ -201,6 +201,8 @@ RenderingManager::~RenderingManager ()
delete mCompositors; delete mCompositors;
delete mWater; delete mWater;
delete mVideoPlayer; delete mVideoPlayer;
delete mActors;
delete mObjects;
delete mFactory; delete mFactory;
} }
@ -210,10 +212,10 @@ MWRender::SkyManager* RenderingManager::getSkyManager()
} }
MWRender::Objects& RenderingManager::getObjects(){ MWRender::Objects& RenderingManager::getObjects(){
return mObjects; return *mObjects;
} }
MWRender::Actors& RenderingManager::getActors(){ MWRender::Actors& RenderingManager::getActors(){
return mActors; return *mActors;
} }
OEngine::Render::Fader* RenderingManager::getFader() OEngine::Render::Fader* RenderingManager::getFader()
@ -223,8 +225,8 @@ OEngine::Render::Fader* RenderingManager::getFader()
void RenderingManager::removeCell (MWWorld::Ptr::CellStore *store) void RenderingManager::removeCell (MWWorld::Ptr::CellStore *store)
{ {
mObjects.removeCell(store); mObjects->removeCell(store);
mActors.removeCell(store); mActors->removeCell(store);
mDebugging->cellRemoved(store); mDebugging->cellRemoved(store);
} }
@ -240,7 +242,7 @@ void RenderingManager::toggleWater()
void RenderingManager::cellAdded (MWWorld::Ptr::CellStore *store) void RenderingManager::cellAdded (MWWorld::Ptr::CellStore *store)
{ {
mObjects.buildStaticGeometry (*store); mObjects->buildStaticGeometry (*store);
sh::Factory::getInstance().unloadUnreferencedMaterials(); sh::Factory::getInstance().unloadUnreferencedMaterials();
mDebugging->cellAdded(store); mDebugging->cellAdded(store);
waterAdded(store); waterAdded(store);
@ -254,8 +256,8 @@ void RenderingManager::addObject (const MWWorld::Ptr& ptr){
void RenderingManager::removeObject (const MWWorld::Ptr& ptr) void RenderingManager::removeObject (const MWWorld::Ptr& ptr)
{ {
if (!mObjects.deleteObject (ptr)) if (!mObjects->deleteObject (ptr))
mActors.deleteObject (ptr); mActors->deleteObject (ptr);
} }
void RenderingManager::moveObject (const MWWorld::Ptr& ptr, const Ogre::Vector3& position) void RenderingManager::moveObject (const MWWorld::Ptr& ptr, const Ogre::Vector3& position)
@ -295,9 +297,9 @@ RenderingManager::updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr &
parent->removeChild(child); parent->removeChild(child);
if (MWWorld::Class::get(old).isActor()) { if (MWWorld::Class::get(old).isActor()) {
mActors.updateObjectCell(old, cur); mActors->updateObjectCell(old, cur);
} else { } else {
mObjects.updateObjectCell(old, cur); mObjects->updateObjectCell(old, cur);
} }
} }
@ -315,7 +317,7 @@ void RenderingManager::rebuildPtr(const MWWorld::Ptr &ptr)
if(ptr.getRefData().getHandle() == "player") if(ptr.getRefData().getHandle() == "player")
anim = mPlayerAnimation; anim = mPlayerAnimation;
else if(MWWorld::Class::get(ptr).isActor()) else if(MWWorld::Class::get(ptr).isActor())
anim = dynamic_cast<NpcAnimation*>(mActors.getAnimation(ptr)); anim = dynamic_cast<NpcAnimation*>(mActors->getAnimation(ptr));
if(anim) if(anim)
{ {
anim->rebuild(); anim->rebuild();
@ -380,8 +382,8 @@ void RenderingManager::update (float duration, bool paused)
if(paused) if(paused)
return; return;
mActors.update (duration); mActors->update (duration);
mObjects.update (duration); mObjects->update (duration);
mSkyManager->update(duration); mSkyManager->update(duration);
@ -657,7 +659,7 @@ void RenderingManager::requestMap(MWWorld::Ptr::CellStore* cell)
{ {
assert(mTerrain); assert(mTerrain);
Ogre::AxisAlignedBox dims = mObjects.getDimensions(cell); Ogre::AxisAlignedBox dims = mObjects->getDimensions(cell);
Ogre::Vector2 center(cell->mCell->getGridX() + 0.5, cell->mCell->getGridY() + 0.5); Ogre::Vector2 center(cell->mCell->getGridX() + 0.5, cell->mCell->getGridY() + 0.5);
dims.merge(mTerrain->getWorldBoundingBox(center)); dims.merge(mTerrain->getWorldBoundingBox(center));
@ -667,7 +669,7 @@ void RenderingManager::requestMap(MWWorld::Ptr::CellStore* cell)
mLocalMap->requestMap(cell, dims.getMinimum().z, dims.getMaximum().z); mLocalMap->requestMap(cell, dims.getMinimum().z, dims.getMaximum().z);
} }
else else
mLocalMap->requestMap(cell, mObjects.getDimensions(cell)); mLocalMap->requestMap(cell, mObjects->getDimensions(cell));
} }
void RenderingManager::preCellChange(MWWorld::Ptr::CellStore* cell) void RenderingManager::preCellChange(MWWorld::Ptr::CellStore* cell)
@ -677,13 +679,13 @@ void RenderingManager::preCellChange(MWWorld::Ptr::CellStore* cell)
void RenderingManager::disableLights(bool sun) void RenderingManager::disableLights(bool sun)
{ {
mObjects.disableLights(); mObjects->disableLights();
sunDisable(sun); sunDisable(sun);
} }
void RenderingManager::enableLights(bool sun) void RenderingManager::enableLights(bool sun)
{ {
mObjects.enableLights(); mObjects->enableLights();
sunEnable(sun); sunEnable(sun);
} }
@ -859,7 +861,7 @@ void RenderingManager::processChangedSettings(const Settings::CategorySettingVec
if (rebuild) if (rebuild)
{ {
mObjects.rebuildStaticGeometry(); mObjects->rebuildStaticGeometry();
if (mTerrain) if (mTerrain)
mTerrain->applyMaterials(Settings::Manager::getBool("enabled", "Shadows"), mTerrain->applyMaterials(Settings::Manager::getBool("enabled", "Shadows"),
Settings::Manager::getBool("split", "Shadows")); Settings::Manager::getBool("split", "Shadows"));
@ -976,13 +978,13 @@ void RenderingManager::setupExternalRendering (MWRender::ExternalRendering& rend
Animation* RenderingManager::getAnimation(const MWWorld::Ptr &ptr) Animation* RenderingManager::getAnimation(const MWWorld::Ptr &ptr)
{ {
Animation *anim = mActors.getAnimation(ptr); Animation *anim = mActors->getAnimation(ptr);
if(!anim && ptr.getRefData().getHandle() == "player") if(!anim && ptr.getRefData().getHandle() == "player")
anim = mPlayerAnimation; anim = mPlayerAnimation;
if (!anim) if (!anim)
anim = mObjects.getAnimation(ptr); anim = mObjects->getAnimation(ptr);
return anim; return anim;
} }

View file

@ -242,8 +242,8 @@ private:
OEngine::Render::OgreRenderer &mRendering; OEngine::Render::OgreRenderer &mRendering;
MWRender::Objects mObjects; MWRender::Objects* mObjects;
MWRender::Actors mActors; MWRender::Actors* mActors;
MWRender::NpcAnimation *mPlayerAnimation; MWRender::NpcAnimation *mPlayerAnimation;

View file

@ -285,10 +285,10 @@ void SkyManager::create()
// Stars // Stars
mAtmosphereNight = mRootNode->createChildSceneNode(); mAtmosphereNight = mRootNode->createChildSceneNode();
NifOgre::ObjectList objects = NifOgre::Loader::createObjects(mAtmosphereNight, "meshes\\sky_night_01.nif"); NifOgre::ObjectScenePtr objects = NifOgre::Loader::createObjects(mAtmosphereNight, "meshes\\sky_night_01.nif");
for(size_t i = 0, matidx = 0;i < objects.mEntities.size();i++) for(size_t i = 0, matidx = 0;i < objects->mEntities.size();i++)
{ {
Entity* night1_ent = objects.mEntities[i]; Entity* night1_ent = objects->mEntities[i];
night1_ent->setRenderQueueGroup(RQG_SkiesEarly+1); night1_ent->setRenderQueueGroup(RQG_SkiesEarly+1);
night1_ent->setVisibilityFlags(RV_Sky); night1_ent->setVisibilityFlags(RV_Sky);
night1_ent->setCastShadows(false); night1_ent->setCastShadows(false);
@ -307,14 +307,14 @@ void SkyManager::create()
night1_ent->getSubEntity(j)->setMaterialName(matName); night1_ent->getSubEntity(j)->setMaterialName(matName);
} }
} }
mObjects.push_back(objects);
// Atmosphere (day) // Atmosphere (day)
mAtmosphereDay = mRootNode->createChildSceneNode(); mAtmosphereDay = mRootNode->createChildSceneNode();
objects = NifOgre::Loader::createObjects(mAtmosphereDay, "meshes\\sky_atmosphere.nif"); objects = NifOgre::Loader::createObjects(mAtmosphereDay, "meshes\\sky_atmosphere.nif");
for(size_t i = 0;i < objects.mEntities.size();i++) for(size_t i = 0;i < objects->mEntities.size();i++)
{ {
Entity* atmosphere_ent = objects.mEntities[i]; Entity* atmosphere_ent = objects->mEntities[i];
atmosphere_ent->setCastShadows(false); atmosphere_ent->setCastShadows(false);
atmosphere_ent->setRenderQueueGroup(RQG_SkiesEarly); atmosphere_ent->setRenderQueueGroup(RQG_SkiesEarly);
atmosphere_ent->setVisibilityFlags(RV_Sky); atmosphere_ent->setVisibilityFlags(RV_Sky);
@ -325,14 +325,14 @@ void SkyManager::create()
// Using infinite AAB here to prevent being clipped by the custom near clip plane used for reflections/refractions // Using infinite AAB here to prevent being clipped by the custom near clip plane used for reflections/refractions
atmosphere_ent->getMesh()->_setBounds (aabInf); atmosphere_ent->getMesh()->_setBounds (aabInf);
} }
mObjects.push_back(objects);
// Clouds // Clouds
SceneNode* clouds_node = mRootNode->createChildSceneNode(); SceneNode* clouds_node = mRootNode->createChildSceneNode();
objects = NifOgre::Loader::createObjects(clouds_node, "meshes\\sky_clouds_01.nif"); objects = NifOgre::Loader::createObjects(clouds_node, "meshes\\sky_clouds_01.nif");
for(size_t i = 0;i < objects.mEntities.size();i++) for(size_t i = 0;i < objects->mEntities.size();i++)
{ {
Entity* clouds_ent = objects.mEntities[i]; Entity* clouds_ent = objects->mEntities[i];
clouds_ent->setVisibilityFlags(RV_Sky); clouds_ent->setVisibilityFlags(RV_Sky);
clouds_ent->setRenderQueueGroup(RQG_SkiesEarly+5); clouds_ent->setRenderQueueGroup(RQG_SkiesEarly+5);
for(unsigned int j = 0;j < clouds_ent->getNumSubEntities();j++) for(unsigned int j = 0;j < clouds_ent->getNumSubEntities();j++)
@ -341,6 +341,7 @@ void SkyManager::create()
// Using infinite AAB here to prevent being clipped by the custom near clip plane used for reflections/refractions // Using infinite AAB here to prevent being clipped by the custom near clip plane used for reflections/refractions
clouds_ent->getMesh()->_setBounds (aabInf); clouds_ent->getMesh()->_setBounds (aabInf);
} }
mObjects.push_back(objects);
mCreated = true; mCreated = true;
} }

View file

@ -11,6 +11,8 @@
#include <extern/shiny/Main/Factory.hpp> #include <extern/shiny/Main/Factory.hpp>
#include <components/nifogre/ogrenifloader.hpp>
#include "../mwworld/weather.hpp" #include "../mwworld/weather.hpp"
@ -196,6 +198,8 @@ namespace MWRender
Ogre::SceneNode* mAtmosphereDay; Ogre::SceneNode* mAtmosphereDay;
Ogre::SceneNode* mAtmosphereNight; Ogre::SceneNode* mAtmosphereNight;
std::vector<NifOgre::ObjectScenePtr> mObjects;
// remember some settings so we don't have to apply them again if they didnt change // remember some settings so we don't have to apply them again if they didnt change
Ogre::String mClouds; Ogre::String mClouds;
Ogre::String mNextClouds; Ogre::String mNextClouds;

View file

@ -615,3 +615,8 @@ void MWWorld::InventoryStore::rechargeItems(float duration)
it->second); it->second);
} }
} }
void MWWorld::InventoryStore::purgeEffect(short effectId)
{
mMagicEffects.add(MWMechanics::EffectKey(effectId), -mMagicEffects.get(MWMechanics::EffectKey(effectId)).mMagnitude);
}

View file

@ -179,7 +179,10 @@ namespace MWWorld
void visitEffectSources (MWMechanics::EffectSourceVisitor& visitor); void visitEffectSources (MWMechanics::EffectSourceVisitor& visitor);
void rechargeItems (float duration); void rechargeItems (float duration);
/// Restore charge on enchanted items. Note this should only be done for the player. ///< Restore charge on enchanted items. Note this should only be done for the player.
void purgeEffect (short effectId);
///< Remove a magic effect
}; };
} }

View file

@ -1845,6 +1845,13 @@ namespace MWWorld
bool World::getLOS(const MWWorld::Ptr& npc,const MWWorld::Ptr& targetNpc) bool World::getLOS(const MWWorld::Ptr& npc,const MWWorld::Ptr& targetNpc)
{ {
// This is a placeholder! Needs to go into an NPC awareness check function (see
// https://wiki.openmw.org/index.php?title=Research:NPC_AI_Behaviour#NPC_Awareness_Check )
if (targetNpc.getClass().getCreatureStats(targetNpc).getMagicEffects().get(ESM::MagicEffect::Invisibility).mMagnitude)
return false;
if (targetNpc.getClass().getCreatureStats(targetNpc).getMagicEffects().get(ESM::MagicEffect::Chameleon).mMagnitude > 100)
return false;
Ogre::Vector3 halfExt1 = mPhysEngine->getCharacter(npc.getRefData().getHandle())->getHalfExtents(); Ogre::Vector3 halfExt1 = mPhysEngine->getCharacter(npc.getRefData().getHandle())->getHalfExtents();
float* pos1 = npc.getRefData().getPosition().pos; float* pos1 = npc.getRefData().getPosition().pos;
Ogre::Vector3 halfExt2 = mPhysEngine->getCharacter(targetNpc.getRefData().getHandle())->getHalfExtents(); Ogre::Vector3 halfExt2 = mPhysEngine->getCharacter(targetNpc.getRefData().getHandle())->getHalfExtents();
@ -2231,4 +2238,10 @@ namespace MWWorld
deleteObject(movedPtr); deleteObject(movedPtr);
} }
} }
void World::breakInvisibility(const Ptr &actor)
{
actor.getClass().getCreatureStats(actor).getActiveSpells().purgeEffect(ESM::MagicEffect::Invisibility);
actor.getClass().getInventoryStore(actor).purgeEffect(ESM::MagicEffect::Invisibility);
}
} }

View file

@ -504,6 +504,8 @@ namespace MWWorld
virtual void launchProjectile (const std::string& id, bool stack, const ESM::EffectList& effects, virtual void launchProjectile (const std::string& id, bool stack, const ESM::EffectList& effects,
const MWWorld::Ptr& actor, const std::string& sourceName); const MWWorld::Ptr& actor, const std::string& sourceName);
virtual void breakInvisibility (const MWWorld::Ptr& actor);
}; };
} }

View file

@ -19,7 +19,7 @@ add_component_dir (nif
) )
add_component_dir (nifogre add_component_dir (nifogre
ogrenifloader skeleton material mesh particles ogrenifloader skeleton material mesh particles controller
) )
add_component_dir (nifbullet add_component_dir (nifbullet

View file

@ -306,7 +306,7 @@ public:
class NiFlipController : public Controller class NiFlipController : public Controller
{ {
public: public:
int mTexSlot; int mTexSlot; // NiTexturingProperty::TextureType
float mDelta; // Time between two flips. delta = (start_time - stop_time) / num_sources float mDelta; // Time between two flips. delta = (start_time - stop_time) / num_sources
NiSourceTextureList mSources; NiSourceTextureList mSources;

View file

@ -0,0 +1,95 @@
#ifndef COMPONENTS_NIFOGRE_CONTROLLER_H
#define COMPONENTS_NIFOGRE_CONTROLLER_H
#include <components/nif/niffile.hpp>
#include <OgreController.h>
namespace NifOgre
{
class ValueInterpolator
{
protected:
float interpKey(const Nif::FloatKeyList::VecType &keys, float time, float def=0.f) const
{
if (keys.size() == 0)
return def;
if(time <= keys.front().mTime)
return keys.front().mValue;
Nif::FloatKeyList::VecType::const_iterator iter(keys.begin()+1);
for(;iter != keys.end();iter++)
{
if(iter->mTime < time)
continue;
Nif::FloatKeyList::VecType::const_iterator last(iter-1);
float a = (time-last->mTime) / (iter->mTime-last->mTime);
return last->mValue + ((iter->mValue - last->mValue)*a);
}
return keys.back().mValue;
}
Ogre::Vector3 interpKey(const Nif::Vector3KeyList::VecType &keys, float time) const
{
if(time <= keys.front().mTime)
return keys.front().mValue;
Nif::Vector3KeyList::VecType::const_iterator iter(keys.begin()+1);
for(;iter != keys.end();iter++)
{
if(iter->mTime < time)
continue;
Nif::Vector3KeyList::VecType::const_iterator last(iter-1);
float a = (time-last->mTime) / (iter->mTime-last->mTime);
return last->mValue + ((iter->mValue - last->mValue)*a);
}
return keys.back().mValue;
}
};
// FIXME: Should not be here.
class DefaultFunction : public Ogre::ControllerFunction<Ogre::Real>
{
private:
float mFrequency;
float mPhase;
float mStartTime;
public:
float mStopTime;
public:
DefaultFunction(const Nif::Controller *ctrl, bool deltaInput)
: Ogre::ControllerFunction<Ogre::Real>(deltaInput)
, mFrequency(ctrl->frequency)
, mPhase(ctrl->phase)
, mStartTime(ctrl->timeStart)
, mStopTime(ctrl->timeStop)
{
if(mDeltaInput)
mDeltaCount = mPhase;
}
virtual Ogre::Real calculate(Ogre::Real value)
{
if(mDeltaInput)
{
mDeltaCount += value*mFrequency;
if(mDeltaCount < mStartTime)
mDeltaCount = mStopTime - std::fmod(mStartTime - mDeltaCount,
mStopTime - mStartTime);
mDeltaCount = std::fmod(mDeltaCount - mStartTime,
mStopTime - mStartTime) + mStartTime;
return mDeltaCount;
}
value = std::min(mStopTime, std::max(mStartTime, value+mPhase));
return value;
}
};
}
#endif

View file

@ -237,7 +237,8 @@ Ogre::String NIFMaterialLoader::getMaterial(const Nif::ShapeData *shapedata,
Nif::ControllerPtr ctrls = matprop->controller; Nif::ControllerPtr ctrls = matprop->controller;
while(!ctrls.empty()) while(!ctrls.empty())
{ {
warn("Unhandled material controller "+ctrls->recName+" in "+name); if (ctrls->recType != Nif::RC_NiAlphaController && ctrls->recType != Nif::RC_NiMaterialColorController)
warn("Unhandled material controller "+ctrls->recName+" in "+name);
ctrls = ctrls->next; ctrls = ctrls->next;
} }
} }

View file

@ -37,9 +37,9 @@ class NIFMaterialLoader {
static std::map<size_t,std::string> sMaterialMap; static std::map<size_t,std::string> sMaterialMap;
public:
static std::string findTextureName(const std::string &filename); static std::string findTextureName(const std::string &filename);
public:
static Ogre::String getMaterial(const Nif::ShapeData *shapedata, static Ogre::String getMaterial(const Nif::ShapeData *shapedata,
const Ogre::String &name, const Ogre::String &group, const Ogre::String &name, const Ogre::String &group,
const Nif::NiTexturingProperty *texprop, const Nif::NiTexturingProperty *texprop,

View file

@ -37,54 +37,241 @@
#include <OgreSkeletonManager.h> #include <OgreSkeletonManager.h>
#include <OgreControllerManager.h> #include <OgreControllerManager.h>
#include <extern/shiny/Main/Factory.hpp>
#include <components/nif/node.hpp> #include <components/nif/node.hpp>
#include <components/misc/stringops.hpp> #include <components/misc/stringops.hpp>
#include "skeleton.hpp" #include "skeleton.hpp"
#include "material.hpp" #include "material.hpp"
#include "mesh.hpp" #include "mesh.hpp"
#include "controller.hpp"
namespace NifOgre namespace NifOgre
{ {
// FIXME: Should not be here. Ogre::MaterialPtr MaterialControllerManager::getWritableMaterial(Ogre::MovableObject *movable)
class DefaultFunction : public Ogre::ControllerFunction<Ogre::Real>
{ {
private: if (mClonedMaterials.find(movable) != mClonedMaterials.end())
float mFrequency; return mClonedMaterials[movable];
float mPhase;
float mStartTime;
public:
float mStopTime;
public: else
DefaultFunction(const Nif::Controller *ctrl, bool deltaInput)
: Ogre::ControllerFunction<Ogre::Real>(deltaInput)
, mFrequency(ctrl->frequency)
, mPhase(ctrl->phase)
, mStartTime(ctrl->timeStart)
, mStopTime(ctrl->timeStop)
{ {
if(mDeltaInput) Ogre::MaterialPtr mat;
mDeltaCount = mPhase; if (Ogre::Entity* ent = dynamic_cast<Ogre::Entity*>(movable))
mat = ent->getSubEntity(0)->getMaterial();
else if (Ogre::ParticleSystem* partSys = dynamic_cast<Ogre::ParticleSystem*>(movable))
mat = Ogre::MaterialManager::getSingleton().getByName(partSys->getMaterialName());
static int count=0;
Ogre::String newName = mat->getName() + Ogre::StringConverter::toString(count++);
sh::Factory::getInstance().createMaterialInstance(newName, mat->getName());
// Make sure techniques are created
sh::Factory::getInstance()._ensureMaterial(newName, "Default");
mat = Ogre::MaterialManager::getSingleton().getByName(newName);
mClonedMaterials[movable] = mat;
if (Ogre::Entity* ent = dynamic_cast<Ogre::Entity*>(movable))
ent->getSubEntity(0)->setMaterial(mat);
else if (Ogre::ParticleSystem* partSys = dynamic_cast<Ogre::ParticleSystem*>(movable))
partSys->setMaterialName(mat->getName());
return mat;
} }
}
virtual Ogre::Real calculate(Ogre::Real value) MaterialControllerManager::~MaterialControllerManager()
{
for (std::map<Ogre::MovableObject*, Ogre::MaterialPtr>::iterator it = mClonedMaterials.begin(); it != mClonedMaterials.end(); ++it)
{ {
if(mDeltaInput) sh::Factory::getInstance().destroyMaterialInstance(it->second->getName());
}
}
ObjectScene::~ObjectScene()
{
for(size_t i = 0;i < mLights.size();i++)
{
Ogre::Light *light = mLights[i];
// If parent is a scene node, it was created specifically for this light. Destroy it now.
if(light->isAttached() && !light->isParentTagPoint())
mSceneMgr->destroySceneNode(light->getParentSceneNode());
mSceneMgr->destroyLight(light);
}
for(size_t i = 0;i < mParticles.size();i++)
mSceneMgr->destroyParticleSystem(mParticles[i]);
for(size_t i = 0;i < mEntities.size();i++)
mSceneMgr->destroyEntity(mEntities[i]);
mControllers.clear();
mLights.clear();
mParticles.clear();
mEntities.clear();
mSkelBase = NULL;
}
// Animates a texture
class FlipController
{
public:
class Value : public Ogre::ControllerValue<Ogre::Real>
{
private:
Ogre::MovableObject* mMovable;
int mTexSlot;
float mDelta;
std::vector<std::string> mTextures;
MaterialControllerManager* mMaterialControllerMgr;
public:
Value(Ogre::MovableObject *movable, const Nif::NiFlipController *ctrl, MaterialControllerManager* materialControllerMgr)
: mMovable(movable)
, mMaterialControllerMgr(materialControllerMgr)
{ {
mDeltaCount += value*mFrequency; mTexSlot = ctrl->mTexSlot;
if(mDeltaCount < mStartTime) mDelta = ctrl->mDelta;
mDeltaCount = mStopTime - std::fmod(mStartTime - mDeltaCount, for (unsigned int i=0; i<ctrl->mSources.length(); ++i)
mStopTime - mStartTime); {
mDeltaCount = std::fmod(mDeltaCount - mStartTime, const Nif::NiSourceTexture* tex = ctrl->mSources[i].getPtr();
mStopTime - mStartTime) + mStartTime; if (!tex->external)
return mDeltaCount; std::cerr << "Warning: Found internal texture, ignoring." << std::endl;
mTextures.push_back(NIFMaterialLoader::findTextureName(tex->filename));
}
} }
value = std::min(mStopTime, std::max(mStartTime, value+mPhase)); virtual Ogre::Real getValue() const
return value; {
} // Should not be called
return 0.0f;
}
virtual void setValue(Ogre::Real time)
{
if (mDelta == 0)
return;
int curTexture = int(time / mDelta) % mTextures.size();
Ogre::MaterialPtr mat = mMaterialControllerMgr->getWritableMaterial(mMovable);
Ogre::Material::TechniqueIterator techs = mat->getTechniqueIterator();
while(techs.hasMoreElements())
{
Ogre::Technique *tech = techs.getNext();
Ogre::Technique::PassIterator passes = tech->getPassIterator();
while(passes.hasMoreElements())
{
Ogre::Pass *pass = passes.getNext();
Ogre::Pass::TextureUnitStateIterator textures = pass->getTextureUnitStateIterator();
while (textures.hasMoreElements())
{
Ogre::TextureUnitState *texture = textures.getNext();
if ((texture->getName() == "diffuseMap" && mTexSlot == Nif::NiTexturingProperty::BaseTexture)
|| (texture->getName() == "normalMap" && mTexSlot == Nif::NiTexturingProperty::BumpTexture)
|| (texture->getName() == "detailMap" && mTexSlot == Nif::NiTexturingProperty::DetailTexture)
|| (texture->getName() == "emissiveMap" && mTexSlot == Nif::NiTexturingProperty::GlowTexture))
texture->setTextureName(mTextures[curTexture]);
}
}
}
}
};
typedef DefaultFunction Function;
};
class AlphaController
{
public:
class Value : public Ogre::ControllerValue<Ogre::Real>, public ValueInterpolator
{
private:
Ogre::MovableObject* mMovable;
Nif::FloatKeyList mData;
MaterialControllerManager* mMaterialControllerMgr;
public:
Value(Ogre::MovableObject *movable, const Nif::NiFloatData *data, MaterialControllerManager* materialControllerMgr)
: mMovable(movable)
, mData(data->mKeyList)
, mMaterialControllerMgr(materialControllerMgr)
{
}
virtual Ogre::Real getValue() const
{
// Should not be called
return 0.0f;
}
virtual void setValue(Ogre::Real time)
{
float value = interpKey(mData.mKeys, time);
Ogre::MaterialPtr mat = mMaterialControllerMgr->getWritableMaterial(mMovable);
Ogre::Material::TechniqueIterator techs = mat->getTechniqueIterator();
while(techs.hasMoreElements())
{
Ogre::Technique *tech = techs.getNext();
Ogre::Technique::PassIterator passes = tech->getPassIterator();
while(passes.hasMoreElements())
{
Ogre::Pass *pass = passes.getNext();
Ogre::ColourValue diffuse = pass->getDiffuse();
diffuse.a = value;
pass->setDiffuse(diffuse);
}
}
}
};
typedef DefaultFunction Function;
};
class MaterialColorController
{
public:
class Value : public Ogre::ControllerValue<Ogre::Real>, public ValueInterpolator
{
private:
Ogre::MovableObject* mMovable;
Nif::Vector3KeyList mData;
MaterialControllerManager* mMaterialControllerMgr;
public:
Value(Ogre::MovableObject *movable, const Nif::NiPosData *data, MaterialControllerManager* materialControllerMgr)
: mMovable(movable)
, mData(data->mKeyList)
, mMaterialControllerMgr(materialControllerMgr)
{
}
virtual Ogre::Real getValue() const
{
// Should not be called
return 0.0f;
}
virtual void setValue(Ogre::Real time)
{
Ogre::Vector3 value = interpKey(mData.mKeys, time);
Ogre::MaterialPtr mat = mMaterialControllerMgr->getWritableMaterial(mMovable);
Ogre::Material::TechniqueIterator techs = mat->getTechniqueIterator();
while(techs.hasMoreElements())
{
Ogre::Technique *tech = techs.getNext();
Ogre::Technique::PassIterator passes = tech->getPassIterator();
while(passes.hasMoreElements())
{
Ogre::Pass *pass = passes.getNext();
Ogre::ColourValue diffuse = pass->getDiffuse();
diffuse.r = value.x;
diffuse.g = value.y;
diffuse.b = value.z;
pass->setDiffuse(diffuse);
}
}
}
};
typedef DefaultFunction Function;
}; };
class VisController class VisController
@ -163,48 +350,14 @@ public:
class KeyframeController class KeyframeController
{ {
public: public:
class Value : public NodeTargetValue<Ogre::Real> class Value : public NodeTargetValue<Ogre::Real>, public ValueInterpolator
{ {
private: private:
Nif::QuaternionKeyList mRotations; Nif::QuaternionKeyList mRotations;
Nif::Vector3KeyList mTranslations; Nif::Vector3KeyList mTranslations;
Nif::FloatKeyList mScales; Nif::FloatKeyList mScales;
static float interpKey(const Nif::FloatKeyList::VecType &keys, float time) using ValueInterpolator::interpKey;
{
if(time <= keys.front().mTime)
return keys.front().mValue;
Nif::FloatKeyList::VecType::const_iterator iter(keys.begin()+1);
for(;iter != keys.end();iter++)
{
if(iter->mTime < time)
continue;
Nif::FloatKeyList::VecType::const_iterator last(iter-1);
float a = (time-last->mTime) / (iter->mTime-last->mTime);
return last->mValue + ((iter->mValue - last->mValue)*a);
}
return keys.back().mValue;
}
static Ogre::Vector3 interpKey(const Nif::Vector3KeyList::VecType &keys, float time)
{
if(time <= keys.front().mTime)
return keys.front().mValue;
Nif::Vector3KeyList::VecType::const_iterator iter(keys.begin()+1);
for(;iter != keys.end();iter++)
{
if(iter->mTime < time)
continue;
Nif::Vector3KeyList::VecType::const_iterator last(iter-1);
float a = (time-last->mTime) / (iter->mTime-last->mTime);
return last->mValue + ((iter->mValue - last->mValue)*a);
}
return keys.back().mValue;
}
static Ogre::Quaternion interpKey(const Nif::QuaternionKeyList::VecType &keys, float time) static Ogre::Quaternion interpKey(const Nif::QuaternionKeyList::VecType &keys, float time)
{ {
@ -276,43 +429,24 @@ public:
class UVController class UVController
{ {
public: public:
class Value : public Ogre::ControllerValue<Ogre::Real> class Value : public Ogre::ControllerValue<Ogre::Real>, public ValueInterpolator
{ {
private: private:
Ogre::MaterialPtr mMaterial; Ogre::MovableObject* mMovable;
Nif::FloatKeyList mUTrans; Nif::FloatKeyList mUTrans;
Nif::FloatKeyList mVTrans; Nif::FloatKeyList mVTrans;
Nif::FloatKeyList mUScale; Nif::FloatKeyList mUScale;
Nif::FloatKeyList mVScale; Nif::FloatKeyList mVScale;
MaterialControllerManager* mMaterialControllerMgr;
static float lookupValue(const Nif::FloatKeyList &keys, float time, float def)
{
if(keys.mKeys.size() == 0)
return def;
if(time <= keys.mKeys.front().mTime)
return keys.mKeys.front().mValue;
Nif::FloatKeyList::VecType::const_iterator iter(keys.mKeys.begin()+1);
for(;iter != keys.mKeys.end();iter++)
{
if(iter->mTime < time)
continue;
Nif::FloatKeyList::VecType::const_iterator last(iter-1);
float a = (time-last->mTime) / (iter->mTime-last->mTime);
return last->mValue + ((iter->mValue - last->mValue)*a);
}
return keys.mKeys.back().mValue;
}
public: public:
Value(const Ogre::MaterialPtr &material, const Nif::NiUVData *data) Value(Ogre::MovableObject* movable, const Nif::NiUVData *data, MaterialControllerManager* materialControllerMgr)
: mMaterial(material) : mMovable(movable)
, mUTrans(data->mKeyList[0]) , mUTrans(data->mKeyList[0])
, mVTrans(data->mKeyList[1]) , mVTrans(data->mKeyList[1])
, mUScale(data->mKeyList[2]) , mUScale(data->mKeyList[2])
, mVScale(data->mKeyList[3]) , mVScale(data->mKeyList[3])
, mMaterialControllerMgr(materialControllerMgr)
{ } { }
virtual Ogre::Real getValue() const virtual Ogre::Real getValue() const
@ -323,12 +457,14 @@ public:
virtual void setValue(Ogre::Real value) virtual void setValue(Ogre::Real value)
{ {
float uTrans = lookupValue(mUTrans, value, 0.0f); float uTrans = interpKey(mUTrans.mKeys, value, 0.0f);
float vTrans = lookupValue(mVTrans, value, 0.0f); float vTrans = interpKey(mVTrans.mKeys, value, 0.0f);
float uScale = lookupValue(mUScale, value, 1.0f); float uScale = interpKey(mUScale.mKeys, value, 1.0f);
float vScale = lookupValue(mVScale, value, 1.0f); float vScale = interpKey(mVScale.mKeys, value, 1.0f);
Ogre::Material::TechniqueIterator techs = mMaterial->getTechniqueIterator(); Ogre::MaterialPtr material = mMaterialControllerMgr->getWritableMaterial(mMovable);
Ogre::Material::TechniqueIterator techs = material->getTechniqueIterator();
while(techs.hasMoreElements()) while(techs.hasMoreElements())
{ {
Ogre::Technique *tech = techs.getNext(); Ogre::Technique *tech = techs.getNext();
@ -380,7 +516,7 @@ public:
class GeomMorpherController class GeomMorpherController
{ {
public: public:
class Value : public Ogre::ControllerValue<Ogre::Real> class Value : public Ogre::ControllerValue<Ogre::Real>, public ValueInterpolator
{ {
private: private:
Ogre::SubEntity *mSubEntity; Ogre::SubEntity *mSubEntity;
@ -389,24 +525,6 @@ public:
std::vector<Ogre::Vector3> mVertices; std::vector<Ogre::Vector3> mVertices;
static float interpKey(const Nif::FloatKeyList::VecType &keys, float time)
{
if(time <= keys.front().mTime)
return keys.front().mValue;
Nif::FloatKeyList::VecType::const_iterator iter(keys.begin()+1);
for(;iter != keys.end();iter++)
{
if(iter->mTime < time)
continue;
Nif::FloatKeyList::VecType::const_iterator last(iter-1);
float a = (time-last->mTime) / (iter->mTime-last->mTime);
return last->mValue + ((iter->mValue - last->mValue)*a);
}
return keys.back().mValue;
}
public: public:
Value(Ogre::SubEntity *subent, const Nif::NiMorphData *data) Value(Ogre::SubEntity *subent, const Nif::NiMorphData *data)
: mSubEntity(subent) : mSubEntity(subent)
@ -504,7 +622,7 @@ class NIFObjectLoader
static void createEntity(const std::string &name, const std::string &group, static void createEntity(const std::string &name, const std::string &group,
Ogre::SceneManager *sceneMgr, ObjectList &objectlist, Ogre::SceneManager *sceneMgr, ObjectScenePtr scene,
const Nif::Node *node, int flags, int animflags) const Nif::Node *node, int flags, int animflags)
{ {
const Nif::NiTriShape *shape = static_cast<const Nif::NiTriShape*>(node); const Nif::NiTriShape *shape = static_cast<const Nif::NiTriShape*>(node);
@ -521,16 +639,16 @@ class NIFObjectLoader
Ogre::Entity *entity = sceneMgr->createEntity(fullname); Ogre::Entity *entity = sceneMgr->createEntity(fullname);
entity->setVisible(!(flags&Nif::NiNode::Flag_Hidden)); entity->setVisible(!(flags&Nif::NiNode::Flag_Hidden));
objectlist.mEntities.push_back(entity); scene->mEntities.push_back(entity);
if(objectlist.mSkelBase) if(scene->mSkelBase)
{ {
if(entity->hasSkeleton()) if(entity->hasSkeleton())
entity->shareSkeletonInstanceWith(objectlist.mSkelBase); entity->shareSkeletonInstanceWith(scene->mSkelBase);
else else
{ {
int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, shape->recIndex); int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, shape->recIndex);
Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); Ogre::Bone *trgtbone = scene->mSkelBase->getSkeleton()->getBone(trgtid);
objectlist.mSkelBase->attachObjectToBone(trgtbone->getName(), entity); scene->mSkelBase->attachObjectToBone(trgtbone->getName(), entity);
} }
} }
@ -541,17 +659,16 @@ class NIFObjectLoader
{ {
const Nif::NiUVController *uv = static_cast<const Nif::NiUVController*>(ctrl.getPtr()); const Nif::NiUVController *uv = static_cast<const Nif::NiUVController*>(ctrl.getPtr());
const Ogre::MaterialPtr &material = entity->getSubEntity(0)->getMaterial();
Ogre::ControllerValueRealPtr srcval((animflags&Nif::NiNode::AnimFlag_AutoPlay) ? Ogre::ControllerValueRealPtr srcval((animflags&Nif::NiNode::AnimFlag_AutoPlay) ?
Ogre::ControllerManager::getSingleton().getFrameTimeSource() : Ogre::ControllerManager::getSingleton().getFrameTimeSource() :
Ogre::ControllerValueRealPtr()); Ogre::ControllerValueRealPtr());
Ogre::ControllerValueRealPtr dstval(OGRE_NEW UVController::Value(material, uv->data.getPtr())); Ogre::ControllerValueRealPtr dstval(OGRE_NEW UVController::Value(entity, uv->data.getPtr(), &scene->mMaterialControllerMgr));
UVController::Function* function = OGRE_NEW UVController::Function(uv, (animflags&Nif::NiNode::AnimFlag_AutoPlay)); UVController::Function* function = OGRE_NEW UVController::Function(uv, (animflags&Nif::NiNode::AnimFlag_AutoPlay));
objectlist.mMaxControllerLength = std::max(function->mStopTime, objectlist.mMaxControllerLength); scene->mMaxControllerLength = std::max(function->mStopTime, scene->mMaxControllerLength);
Ogre::ControllerFunctionRealPtr func(function); Ogre::ControllerFunctionRealPtr func(function);
objectlist.mControllers.push_back(Ogre::Controller<Ogre::Real>(srcval, dstval, func)); scene->mControllers.push_back(Ogre::Controller<Ogre::Real>(srcval, dstval, func));
} }
else if(ctrl->recType == Nif::RC_NiGeomMorpherController) else if(ctrl->recType == Nif::RC_NiGeomMorpherController)
{ {
@ -563,15 +680,81 @@ class NIFObjectLoader
Ogre::ControllerValueRealPtr dstval(OGRE_NEW GeomMorpherController::Value(entity->getSubEntity(0), geom->data.getPtr())); Ogre::ControllerValueRealPtr dstval(OGRE_NEW GeomMorpherController::Value(entity->getSubEntity(0), geom->data.getPtr()));
GeomMorpherController::Function* function = OGRE_NEW GeomMorpherController::Function(geom, (animflags&Nif::NiNode::AnimFlag_AutoPlay)); GeomMorpherController::Function* function = OGRE_NEW GeomMorpherController::Function(geom, (animflags&Nif::NiNode::AnimFlag_AutoPlay));
objectlist.mMaxControllerLength = std::max(function->mStopTime, objectlist.mMaxControllerLength); scene->mMaxControllerLength = std::max(function->mStopTime, scene->mMaxControllerLength);
Ogre::ControllerFunctionRealPtr func(function); Ogre::ControllerFunctionRealPtr func(function);
objectlist.mControllers.push_back(Ogre::Controller<Ogre::Real>(srcval, dstval, func)); scene->mControllers.push_back(Ogre::Controller<Ogre::Real>(srcval, dstval, func));
} }
ctrl = ctrl->next; ctrl = ctrl->next;
} }
createMaterialControllers(shape, entity, animflags, scene);
} }
static void createMaterialControllers (const Nif::Node* node, Ogre::MovableObject* movable, int animflags, ObjectScenePtr scene)
{
const Nif::NiTexturingProperty *texprop = NULL;
const Nif::NiMaterialProperty *matprop = NULL;
const Nif::NiAlphaProperty *alphaprop = NULL;
const Nif::NiVertexColorProperty *vertprop = NULL;
const Nif::NiZBufferProperty *zprop = NULL;
const Nif::NiSpecularProperty *specprop = NULL;
const Nif::NiWireframeProperty *wireprop = NULL;
node->getProperties(texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop);
Ogre::ControllerValueRealPtr srcval((animflags&Nif::NiNode::AnimFlag_AutoPlay) ?
Ogre::ControllerManager::getSingleton().getFrameTimeSource() :
Ogre::ControllerValueRealPtr());
if(matprop)
{
Nif::ControllerPtr ctrls = matprop->controller;
while(!ctrls.empty())
{
if (ctrls->recType == Nif::RC_NiAlphaController)
{
const Nif::NiAlphaController *alphaCtrl = dynamic_cast<const Nif::NiAlphaController*>(ctrls.getPtr());
Ogre::ControllerValueRealPtr dstval(OGRE_NEW AlphaController::Value(movable, alphaCtrl->data.getPtr(), &scene->mMaterialControllerMgr));
AlphaController::Function* function = OGRE_NEW AlphaController::Function(alphaCtrl, (animflags&Nif::NiNode::AnimFlag_AutoPlay));
scene->mMaxControllerLength = std::max(function->mStopTime, scene->mMaxControllerLength);
Ogre::ControllerFunctionRealPtr func(function);
scene->mControllers.push_back(Ogre::Controller<Ogre::Real>(srcval, dstval, func));
}
else if (ctrls->recType == Nif::RC_NiMaterialColorController)
{
const Nif::NiMaterialColorController *matCtrl = dynamic_cast<const Nif::NiMaterialColorController*>(ctrls.getPtr());
Ogre::ControllerValueRealPtr dstval(OGRE_NEW MaterialColorController::Value(movable, matCtrl->data.getPtr(), &scene->mMaterialControllerMgr));
AlphaController::Function* function = OGRE_NEW AlphaController::Function(matCtrl, (animflags&Nif::NiNode::AnimFlag_AutoPlay));
scene->mMaxControllerLength = std::max(function->mStopTime, scene->mMaxControllerLength);
Ogre::ControllerFunctionRealPtr func(function);
scene->mControllers.push_back(Ogre::Controller<Ogre::Real>(srcval, dstval, func));
}
ctrls = ctrls->next;
}
}
if (texprop)
{
Nif::ControllerPtr ctrls = texprop->controller;
while(!ctrls.empty())
{
if (ctrls->recType == Nif::RC_NiFlipController)
{
const Nif::NiFlipController *flipCtrl = dynamic_cast<const Nif::NiFlipController*>(ctrls.getPtr());
Ogre::ControllerValueRealPtr dstval(OGRE_NEW FlipController::Value(
movable, flipCtrl, &scene->mMaterialControllerMgr));
FlipController::Function* function = OGRE_NEW FlipController::Function(flipCtrl, (animflags&Nif::NiNode::AnimFlag_AutoPlay));
scene->mMaxControllerLength = std::max(function->mStopTime, scene->mMaxControllerLength);
Ogre::ControllerFunctionRealPtr func(function);
scene->mControllers.push_back(Ogre::Controller<Ogre::Real>(srcval, dstval, func));
}
ctrls = ctrls->next;
}
}
}
static void createParticleEmitterAffectors(Ogre::ParticleSystem *partsys, static void createParticleEmitterAffectors(Ogre::ParticleSystem *partsys,
const Nif::NiParticleSystemController *partctrl, Ogre::Bone* bone, const Nif::NiParticleSystemController *partctrl, Ogre::Bone* bone,
@ -647,8 +830,8 @@ class NIFObjectLoader
} }
static void createParticleSystem(const std::string &name, const std::string &group, static void createParticleSystem(const std::string &name, const std::string &group,
Ogre::SceneNode *sceneNode, ObjectList &objectlist, Ogre::SceneNode *sceneNode, ObjectScenePtr scene,
const Nif::Node *partnode, int flags, int partflags) const Nif::Node *partnode, int flags, int partflags, int animflags)
{ {
const Nif::NiAutoNormalParticlesData *particledata = NULL; const Nif::NiAutoNormalParticlesData *particledata = NULL;
if(partnode->recType == Nif::RC_NiAutoNormalParticles) if(partnode->recType == Nif::RC_NiAutoNormalParticles)
@ -696,8 +879,8 @@ class NIFObjectLoader
if(!partctrl->emitter.empty()) if(!partctrl->emitter.empty())
{ {
int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, partctrl->emitter->recIndex); int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, partctrl->emitter->recIndex);
Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); Ogre::Bone *trgtbone = scene->mSkelBase->getSkeleton()->getBone(trgtid);
createParticleEmitterAffectors(partsys, partctrl, trgtbone, objectlist.mSkelBase->getName()); createParticleEmitterAffectors(partsys, partctrl, trgtbone, scene->mSkelBase->getName());
} }
Ogre::ControllerValueRealPtr srcval((partflags&Nif::NiNode::ParticleFlag_AutoPlay) ? Ogre::ControllerValueRealPtr srcval((partflags&Nif::NiNode::ParticleFlag_AutoPlay) ?
@ -707,20 +890,22 @@ class NIFObjectLoader
ParticleSystemController::Function* function = ParticleSystemController::Function* function =
OGRE_NEW ParticleSystemController::Function(partctrl, (partflags&Nif::NiNode::ParticleFlag_AutoPlay)); OGRE_NEW ParticleSystemController::Function(partctrl, (partflags&Nif::NiNode::ParticleFlag_AutoPlay));
objectlist.mMaxControllerLength = std::max(function->mStopTime, objectlist.mMaxControllerLength); scene->mMaxControllerLength = std::max(function->mStopTime, scene->mMaxControllerLength);
Ogre::ControllerFunctionRealPtr func(function); Ogre::ControllerFunctionRealPtr func(function);
objectlist.mControllers.push_back(Ogre::Controller<Ogre::Real>(srcval, dstval, func)); scene->mControllers.push_back(Ogre::Controller<Ogre::Real>(srcval, dstval, func));
} }
ctrl = ctrl->next; ctrl = ctrl->next;
} }
partsys->setVisible(!(flags&Nif::NiNode::Flag_Hidden)); partsys->setVisible(!(flags&Nif::NiNode::Flag_Hidden));
objectlist.mParticles.push_back(partsys); scene->mParticles.push_back(partsys);
createMaterialControllers(partnode, partsys, animflags, scene);
} }
static void createNodeControllers(const std::string &name, Nif::ControllerPtr ctrl, ObjectList &objectlist, int animflags) static void createNodeControllers(const std::string &name, Nif::ControllerPtr ctrl, ObjectScenePtr scene, int animflags)
{ {
do { do {
if(ctrl->recType == Nif::RC_NiVisController) if(ctrl->recType == Nif::RC_NiVisController)
@ -728,17 +913,17 @@ class NIFObjectLoader
const Nif::NiVisController *vis = static_cast<const Nif::NiVisController*>(ctrl.getPtr()); const Nif::NiVisController *vis = static_cast<const Nif::NiVisController*>(ctrl.getPtr());
int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, ctrl->target->recIndex); int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, ctrl->target->recIndex);
Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); Ogre::Bone *trgtbone = scene->mSkelBase->getSkeleton()->getBone(trgtid);
Ogre::ControllerValueRealPtr srcval((animflags&Nif::NiNode::AnimFlag_AutoPlay) ? Ogre::ControllerValueRealPtr srcval((animflags&Nif::NiNode::AnimFlag_AutoPlay) ?
Ogre::ControllerManager::getSingleton().getFrameTimeSource() : Ogre::ControllerManager::getSingleton().getFrameTimeSource() :
Ogre::ControllerValueRealPtr()); Ogre::ControllerValueRealPtr());
Ogre::ControllerValueRealPtr dstval(OGRE_NEW VisController::Value(trgtbone, vis->data.getPtr())); Ogre::ControllerValueRealPtr dstval(OGRE_NEW VisController::Value(trgtbone, vis->data.getPtr()));
VisController::Function* function = OGRE_NEW VisController::Function(vis, (animflags&Nif::NiNode::AnimFlag_AutoPlay)); VisController::Function* function = OGRE_NEW VisController::Function(vis, (animflags&Nif::NiNode::AnimFlag_AutoPlay));
objectlist.mMaxControllerLength = std::max(function->mStopTime, objectlist.mMaxControllerLength); scene->mMaxControllerLength = std::max(function->mStopTime, scene->mMaxControllerLength);
Ogre::ControllerFunctionRealPtr func(function); Ogre::ControllerFunctionRealPtr func(function);
objectlist.mControllers.push_back(Ogre::Controller<Ogre::Real>(srcval, dstval, func)); scene->mControllers.push_back(Ogre::Controller<Ogre::Real>(srcval, dstval, func));
} }
else if(ctrl->recType == Nif::RC_NiKeyframeController) else if(ctrl->recType == Nif::RC_NiKeyframeController)
{ {
@ -746,16 +931,16 @@ class NIFObjectLoader
if(!key->data.empty()) if(!key->data.empty())
{ {
int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, ctrl->target->recIndex); int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, ctrl->target->recIndex);
Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); Ogre::Bone *trgtbone = scene->mSkelBase->getSkeleton()->getBone(trgtid);
Ogre::ControllerValueRealPtr srcval((animflags&Nif::NiNode::AnimFlag_AutoPlay) ? Ogre::ControllerValueRealPtr srcval((animflags&Nif::NiNode::AnimFlag_AutoPlay) ?
Ogre::ControllerManager::getSingleton().getFrameTimeSource() : Ogre::ControllerManager::getSingleton().getFrameTimeSource() :
Ogre::ControllerValueRealPtr()); Ogre::ControllerValueRealPtr());
Ogre::ControllerValueRealPtr dstval(OGRE_NEW KeyframeController::Value(trgtbone, key->data.getPtr())); Ogre::ControllerValueRealPtr dstval(OGRE_NEW KeyframeController::Value(trgtbone, key->data.getPtr()));
KeyframeController::Function* function = OGRE_NEW KeyframeController::Function(key, (animflags&Nif::NiNode::AnimFlag_AutoPlay)); KeyframeController::Function* function = OGRE_NEW KeyframeController::Function(key, (animflags&Nif::NiNode::AnimFlag_AutoPlay));
objectlist.mMaxControllerLength = std::max(function->mStopTime, objectlist.mMaxControllerLength); scene->mMaxControllerLength = std::max(function->mStopTime, scene->mMaxControllerLength);
Ogre::ControllerFunctionRealPtr func(function); Ogre::ControllerFunctionRealPtr func(function);
objectlist.mControllers.push_back(Ogre::Controller<Ogre::Real>(srcval, dstval, func)); scene->mControllers.push_back(Ogre::Controller<Ogre::Real>(srcval, dstval, func));
} }
} }
ctrl = ctrl->next; ctrl = ctrl->next;
@ -804,7 +989,7 @@ class NIFObjectLoader
static void createObjects(const std::string &name, const std::string &group, static void createObjects(const std::string &name, const std::string &group,
Ogre::SceneNode *sceneNode, const Nif::Node *node, Ogre::SceneNode *sceneNode, const Nif::Node *node,
ObjectList &objectlist, int flags, int animflags, int partflags) ObjectScenePtr scene, int flags, int animflags, int partflags)
{ {
// Do not create objects for the collision shape (includes all children) // Do not create objects for the collision shape (includes all children)
if(node->recType == Nif::RC_RootCollisionNode) if(node->recType == Nif::RC_RootCollisionNode)
@ -830,7 +1015,7 @@ class NIFObjectLoader
const Nif::NiTextKeyExtraData *tk = static_cast<const Nif::NiTextKeyExtraData*>(e.getPtr()); const Nif::NiTextKeyExtraData *tk = static_cast<const Nif::NiTextKeyExtraData*>(e.getPtr());
int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, node->recIndex); int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, node->recIndex);
extractTextKeys(tk, objectlist.mTextKeys[trgtid]); extractTextKeys(tk, scene->mTextKeys[trgtid]);
} }
else if(e->recType == Nif::RC_NiStringExtraData) else if(e->recType == Nif::RC_NiStringExtraData)
{ {
@ -849,7 +1034,7 @@ class NIFObjectLoader
} }
if(!node->controller.empty() && (node->parent || node->recType != Nif::RC_NiNode)) if(!node->controller.empty() && (node->parent || node->recType != Nif::RC_NiNode))
createNodeControllers(name, node->controller, objectlist, animflags); createNodeControllers(name, node->controller, scene, animflags);
if(node->recType == Nif::RC_NiCamera) if(node->recType == Nif::RC_NiCamera)
{ {
@ -858,13 +1043,13 @@ class NIFObjectLoader
if(node->recType == Nif::RC_NiTriShape && !(flags&0x80000000)) if(node->recType == Nif::RC_NiTriShape && !(flags&0x80000000))
{ {
createEntity(name, group, sceneNode->getCreator(), objectlist, node, flags, animflags); createEntity(name, group, sceneNode->getCreator(), scene, node, flags, animflags);
} }
if((node->recType == Nif::RC_NiAutoNormalParticles || if((node->recType == Nif::RC_NiAutoNormalParticles ||
node->recType == Nif::RC_NiRotatingParticles) && !(flags&0x40000000)) node->recType == Nif::RC_NiRotatingParticles) && !(flags&0x40000000))
{ {
createParticleSystem(name, group, sceneNode, objectlist, node, flags, partflags); createParticleSystem(name, group, sceneNode, scene, node, flags, partflags, animflags);
} }
const Nif::NiNode *ninode = dynamic_cast<const Nif::NiNode*>(node); const Nif::NiNode *ninode = dynamic_cast<const Nif::NiNode*>(node);
@ -874,14 +1059,14 @@ class NIFObjectLoader
for(size_t i = 0;i < children.length();i++) for(size_t i = 0;i < children.length();i++)
{ {
if(!children[i].empty()) if(!children[i].empty())
createObjects(name, group, sceneNode, children[i].getPtr(), objectlist, flags, animflags, partflags); createObjects(name, group, sceneNode, children[i].getPtr(), scene, flags, animflags, partflags);
} }
} }
} }
static void createSkelBase(const std::string &name, const std::string &group, static void createSkelBase(const std::string &name, const std::string &group,
Ogre::SceneManager *sceneMgr, const Nif::Node *node, Ogre::SceneManager *sceneMgr, const Nif::Node *node,
ObjectList &objectlist) ObjectScenePtr scene)
{ {
/* This creates an empty mesh to which a skeleton gets attached. This /* This creates an empty mesh to which a skeleton gets attached. This
* is to ensure we have an entity with a skeleton instance, even if all * is to ensure we have an entity with a skeleton instance, even if all
@ -890,12 +1075,12 @@ class NIFObjectLoader
if(meshMgr.getByName(name).isNull()) if(meshMgr.getByName(name).isNull())
NIFMeshLoader::createMesh(name, name, group, ~(size_t)0); NIFMeshLoader::createMesh(name, name, group, ~(size_t)0);
objectlist.mSkelBase = sceneMgr->createEntity(name); scene->mSkelBase = sceneMgr->createEntity(name);
objectlist.mEntities.push_back(objectlist.mSkelBase); scene->mEntities.push_back(scene->mSkelBase);
} }
public: public:
static void load(Ogre::SceneNode *sceneNode, ObjectList &objectlist, const std::string &name, const std::string &group, int flags=0) static void load(Ogre::SceneNode *sceneNode, ObjectScenePtr scene, const std::string &name, const std::string &group, int flags=0)
{ {
Nif::NIFFile::ptr nif = Nif::NIFFile::create(name); Nif::NIFFile::ptr nif = Nif::NIFFile::create(name);
if(nif->numRoots() < 1) if(nif->numRoots() < 1)
@ -919,9 +1104,9 @@ public:
!NIFSkeletonLoader::createSkeleton(name, group, node).isNull()) !NIFSkeletonLoader::createSkeleton(name, group, node).isNull())
{ {
// Create a base skeleton entity if this NIF needs one // Create a base skeleton entity if this NIF needs one
createSkelBase(name, group, sceneNode->getCreator(), node, objectlist); createSkelBase(name, group, sceneNode->getCreator(), node, scene);
} }
createObjects(name, group, sceneNode, node, objectlist, flags, 0, 0); createObjects(name, group, sceneNode, node, scene, flags, 0, 0);
} }
static void loadKf(Ogre::Skeleton *skel, const std::string &name, static void loadKf(Ogre::Skeleton *skel, const std::string &name,
@ -984,37 +1169,37 @@ public:
}; };
ObjectList Loader::createObjects(Ogre::SceneNode *parentNode, std::string name, const std::string &group) ObjectScenePtr Loader::createObjects(Ogre::SceneNode *parentNode, std::string name, const std::string &group)
{ {
ObjectList objectlist; ObjectScenePtr scene = ObjectScenePtr (new ObjectScene(parentNode->getCreator()));;
Misc::StringUtils::toLower(name); Misc::StringUtils::toLower(name);
NIFObjectLoader::load(parentNode, objectlist, name, group); NIFObjectLoader::load(parentNode, scene, name, group);
for(size_t i = 0;i < objectlist.mEntities.size();i++) for(size_t i = 0;i < scene->mEntities.size();i++)
{ {
Ogre::Entity *entity = objectlist.mEntities[i]; Ogre::Entity *entity = scene->mEntities[i];
if(!entity->isAttached()) if(!entity->isAttached())
parentNode->attachObject(entity); parentNode->attachObject(entity);
} }
return objectlist; return scene;
} }
ObjectList Loader::createObjects(Ogre::Entity *parent, const std::string &bonename, ObjectScenePtr Loader::createObjects(Ogre::Entity *parent, const std::string &bonename,
Ogre::SceneNode *parentNode, Ogre::SceneNode *parentNode,
std::string name, const std::string &group) std::string name, const std::string &group)
{ {
ObjectList objectlist; ObjectScenePtr scene = ObjectScenePtr (new ObjectScene(parentNode->getCreator()));
Misc::StringUtils::toLower(name); Misc::StringUtils::toLower(name);
NIFObjectLoader::load(parentNode, objectlist, name, group); NIFObjectLoader::load(parentNode, scene, name, group);
bool isskinned = false; bool isskinned = false;
for(size_t i = 0;i < objectlist.mEntities.size();i++) for(size_t i = 0;i < scene->mEntities.size();i++)
{ {
Ogre::Entity *ent = objectlist.mEntities[i]; Ogre::Entity *ent = scene->mEntities[i];
if(objectlist.mSkelBase != ent && ent->hasSkeleton()) if(scene->mSkelBase != ent && ent->hasSkeleton())
{ {
isskinned = true; isskinned = true;
break; break;
@ -1029,12 +1214,12 @@ ObjectList Loader::createObjects(Ogre::Entity *parent, const std::string &bonena
{ {
std::string filter = "@shape=tri "+bonename; std::string filter = "@shape=tri "+bonename;
Misc::StringUtils::toLower(filter); Misc::StringUtils::toLower(filter);
for(size_t i = 0;i < objectlist.mEntities.size();i++) for(size_t i = 0;i < scene->mEntities.size();i++)
{ {
Ogre::Entity *entity = objectlist.mEntities[i]; Ogre::Entity *entity = scene->mEntities[i];
if(entity->hasSkeleton()) if(entity->hasSkeleton())
{ {
if(entity == objectlist.mSkelBase || if(entity == scene->mSkelBase ||
entity->getMesh()->getName().find(filter) != std::string::npos) entity->getMesh()->getName().find(filter) != std::string::npos)
parentNode->attachObject(entity); parentNode->attachObject(entity);
} }
@ -1047,9 +1232,9 @@ ObjectList Loader::createObjects(Ogre::Entity *parent, const std::string &bonena
} }
else else
{ {
for(size_t i = 0;i < objectlist.mEntities.size();i++) for(size_t i = 0;i < scene->mEntities.size();i++)
{ {
Ogre::Entity *entity = objectlist.mEntities[i]; Ogre::Entity *entity = scene->mEntities[i];
if(!entity->isAttached()) if(!entity->isAttached())
{ {
Ogre::TagPoint *tag = parent->attachObjectToBone(bonename, entity); Ogre::TagPoint *tag = parent->attachObjectToBone(bonename, entity);
@ -1058,32 +1243,32 @@ ObjectList Loader::createObjects(Ogre::Entity *parent, const std::string &bonena
} }
} }
for(size_t i = 0;i < objectlist.mParticles.size();i++) for(size_t i = 0;i < scene->mParticles.size();i++)
{ {
Ogre::ParticleSystem *partsys = objectlist.mParticles[i]; Ogre::ParticleSystem *partsys = scene->mParticles[i];
if(partsys->isAttached()) if(partsys->isAttached())
partsys->detachFromParent(); partsys->detachFromParent();
Ogre::TagPoint *tag = objectlist.mSkelBase->attachObjectToBone( Ogre::TagPoint *tag = scene->mSkelBase->attachObjectToBone(
objectlist.mSkelBase->getSkeleton()->getRootBone()->getName(), partsys); scene->mSkelBase->getSkeleton()->getRootBone()->getName(), partsys);
tag->setScale(scale); tag->setScale(scale);
} }
return objectlist; return scene;
} }
ObjectList Loader::createObjectBase(Ogre::SceneNode *parentNode, std::string name, const std::string &group) ObjectScenePtr Loader::createObjectBase(Ogre::SceneNode *parentNode, std::string name, const std::string &group)
{ {
ObjectList objectlist; ObjectScenePtr scene = ObjectScenePtr (new ObjectScene(parentNode->getCreator()));
Misc::StringUtils::toLower(name); Misc::StringUtils::toLower(name);
NIFObjectLoader::load(parentNode, objectlist, name, group, 0xC0000000); NIFObjectLoader::load(parentNode, scene, name, group, 0xC0000000);
if(objectlist.mSkelBase) if(scene->mSkelBase)
parentNode->attachObject(objectlist.mSkelBase); parentNode->attachObject(scene->mSkelBase);
return objectlist; return scene;
} }

View file

@ -25,6 +25,7 @@
#define OPENMW_COMPONENTS_NIFOGRE_OGRENIFLOADER_HPP #define OPENMW_COMPONENTS_NIFOGRE_OGRENIFLOADER_HPP
#include <OgreResource.h> #include <OgreResource.h>
#include <OgreMaterial.h>
#include <OgreController.h> #include <OgreController.h>
#include <vector> #include <vector>
@ -37,39 +38,60 @@
namespace NifOgre namespace NifOgre
{ {
/**
* @brief Clones materials as necessary to not make controllers affect other objects (that share the original material).
*/
class MaterialControllerManager
{
public:
~MaterialControllerManager();
Ogre::MaterialPtr getWritableMaterial (Ogre::MovableObject* movable);
private:
std::map<Ogre::MovableObject*, Ogre::MaterialPtr> mClonedMaterials;
};
typedef std::multimap<float,std::string> TextKeyMap; typedef std::multimap<float,std::string> TextKeyMap;
static const char sTextKeyExtraDataID[] = "TextKeyExtraData"; static const char sTextKeyExtraDataID[] = "TextKeyExtraData";
struct ObjectList { struct ObjectScene {
Ogre::Entity *mSkelBase; Ogre::Entity *mSkelBase;
std::vector<Ogre::Entity*> mEntities; std::vector<Ogre::Entity*> mEntities;
std::vector<Ogre::ParticleSystem*> mParticles; std::vector<Ogre::ParticleSystem*> mParticles;
std::vector<Ogre::Light*> mLights; std::vector<Ogre::Light*> mLights;
Ogre::SceneManager* mSceneMgr;
// The maximum length on any of the controllers. For animations with controllers, but no text keys, consider this the animation length. // The maximum length on any of the controllers. For animations with controllers, but no text keys, consider this the animation length.
float mMaxControllerLength; float mMaxControllerLength;
std::map<int,TextKeyMap> mTextKeys; std::map<int,TextKeyMap> mTextKeys;
MaterialControllerManager mMaterialControllerMgr;
std::vector<Ogre::Controller<Ogre::Real> > mControllers; std::vector<Ogre::Controller<Ogre::Real> > mControllers;
ObjectList() : mSkelBase(0), mMaxControllerLength(0) ObjectScene(Ogre::SceneManager* sceneMgr) : mSkelBase(0), mMaxControllerLength(0), mSceneMgr(sceneMgr)
{ } { }
~ObjectScene();
}; };
typedef Ogre::SharedPtr<ObjectScene> ObjectScenePtr;
class Loader class Loader
{ {
public: public:
static ObjectList createObjects(Ogre::Entity *parent, const std::string &bonename, static ObjectScenePtr createObjects(Ogre::Entity *parent, const std::string &bonename,
Ogre::SceneNode *parentNode, Ogre::SceneNode *parentNode,
std::string name, std::string name,
const std::string &group="General"); const std::string &group="General");
static ObjectList createObjects(Ogre::SceneNode *parentNode, static ObjectScenePtr createObjects(Ogre::SceneNode *parentNode,
std::string name, std::string name,
const std::string &group="General"); const std::string &group="General");
static ObjectList createObjectBase(Ogre::SceneNode *parentNode, static ObjectScenePtr createObjectBase(Ogre::SceneNode *parentNode,
std::string name, std::string name,
const std::string &group="General"); const std::string &group="General");

View file

@ -98,9 +98,7 @@
#if VERTEXCOLOR_MODE != 2 #if VERTEXCOLOR_MODE != 2
shUniform(float4, materialAmbient) @shAutoConstant(materialAmbient, surface_ambient_colour) shUniform(float4, materialAmbient) @shAutoConstant(materialAmbient, surface_ambient_colour)
#endif #endif
#if VERTEXCOLOR_MODE != 2
shUniform(float4, materialDiffuse) @shAutoConstant(materialDiffuse, surface_diffuse_colour) shUniform(float4, materialDiffuse) @shAutoConstant(materialDiffuse, surface_diffuse_colour)
#endif
#if VERTEXCOLOR_MODE != 1 #if VERTEXCOLOR_MODE != 1
shUniform(float4, materialEmissive) @shAutoConstant(materialEmissive, surface_emissive_colour) shUniform(float4, materialEmissive) @shAutoConstant(materialEmissive, surface_emissive_colour)
#endif #endif
@ -234,9 +232,7 @@
lightResult.xyz += lightAmbient.xyz * materialAmbient.xyz + materialEmissive.xyz; lightResult.xyz += lightAmbient.xyz * materialAmbient.xyz + materialEmissive.xyz;
#endif #endif
#if VERTEXCOLOR_MODE != 2
lightResult.a *= materialDiffuse.a; lightResult.a *= materialDiffuse.a;
#endif
#endif #endif
} }
@ -339,9 +335,7 @@
#if VERTEXCOLOR_MODE != 2 #if VERTEXCOLOR_MODE != 2
shUniform(float4, materialAmbient) @shAutoConstant(materialAmbient, surface_ambient_colour) shUniform(float4, materialAmbient) @shAutoConstant(materialAmbient, surface_ambient_colour)
#endif #endif
#if VERTEXCOLOR_MODE != 2
shUniform(float4, materialDiffuse) @shAutoConstant(materialDiffuse, surface_diffuse_colour) shUniform(float4, materialDiffuse) @shAutoConstant(materialDiffuse, surface_diffuse_colour)
#endif
#if VERTEXCOLOR_MODE != 1 #if VERTEXCOLOR_MODE != 1
shUniform(float4, materialEmissive) @shAutoConstant(materialEmissive, surface_emissive_colour) shUniform(float4, materialEmissive) @shAutoConstant(materialEmissive, surface_emissive_colour)
#endif #endif
@ -434,9 +428,7 @@
lightResult.xyz += lightAmbient.xyz * materialAmbient.xyz + materialEmissive.xyz; lightResult.xyz += lightAmbient.xyz * materialAmbient.xyz + materialEmissive.xyz;
#endif #endif
#if VERTEXCOLOR_MODE != 2
lightResult.a *= materialDiffuse.a; lightResult.a *= materialDiffuse.a;
#endif
#endif #endif
// shadows only for the first (directional) light // shadows only for the first (directional) light