diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 7505d3405..b70fcd0cc 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -727,6 +727,8 @@ void CharacterController::update(float duration) const MWWorld::Class &cls = MWWorld::Class::get(mPtr); Ogre::Vector3 movement(0.0f); + updateVisibility(); + if(!cls.isActor()) { if(mAnimQueue.size() > 1) @@ -1130,4 +1132,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); +} + } diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 0b55534a6..9e07fca7d 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -173,6 +173,8 @@ class CharacterController bool updateNpcState(bool onground, bool inwater, bool isrunning, bool sneak); + void updateVisibility(); + public: CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim); virtual ~CharacterController(); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index b11b2b0a5..aa04e39e2 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -215,6 +215,8 @@ public: void addEffect (const std::string& model, int effectId, bool loop = false, const std::string& bonename = "", std::string texture = ""); void removeEffect (int effectId); void getLoopingEffects (std::vector& out); + + virtual void setAlpha(float alpha) {} private: void updateEffects(float duration); diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index a57816f34..eb0c5dfbc 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -5,6 +5,8 @@ #include #include +#include + #include "../mwworld/esmstore.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwworld/class.hpp" @@ -116,7 +118,8 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, int v mViewMode(viewMode), mShowWeapons(false), mShowShield(true), - mFirstPersonOffset(0.f, 0.f, 0.f) + mFirstPersonOffset(0.f, 0.f, 0.f), + mAlpha(1.f) { mNpc = mPtr.get()->mBase; @@ -219,6 +222,7 @@ void NpcAnimation::updateNpcBase() void NpcAnimation::updateParts() { + mAlpha = 1.f; const MWWorld::Class &cls = MWWorld::Class::get(mPtr); MWWorld::InventoryStore &inv = cls.getInventoryStore(mPtr); @@ -647,6 +651,7 @@ void NpcAnimation::showWeapons(bool showWeapon) { removeIndividualPart(ESM::PRT_Weapon); } + mAlpha = 1.f; } void NpcAnimation::showShield(bool show) @@ -705,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; imEntities.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); + } + } +} + } diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 962663268..04dde87c7 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -64,6 +64,8 @@ private: Ogre::SharedPtr mSayAnimationValue; + float mAlpha; + void updateNpcBase(); NifOgre::ObjectScenePtr insertBoundedPart(const std::string &model, int group, const std::string &bonename, @@ -78,6 +80,8 @@ private: void addPartGroup(int group, int priority, const std::vector &parts, bool enchantedGlow=false, Ogre::Vector3* glowColor=NULL); + void applyAlpha(float alpha, Ogre::Entity* ent, NifOgre::ObjectScenePtr scene); + public: /** * @param ptr @@ -109,6 +113,9 @@ public: /// Rebuilds the NPC, updating their root model, animation sources, and equipment. void rebuild(); + + /// Make the NPC only partially visible + virtual void setAlpha(float alpha); }; } diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 26e88fb0d..b216c789f 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -60,14 +60,14 @@ RenderingManager::RenderingManager(OEngine::Render::OgreRenderer& _rend, const b MWWorld::Fallback* fallback) : mRendering(_rend) , mFallback(fallback) - , mObjects(mRendering) - , mActors(mRendering, this) , mPlayerAnimation(NULL) , mAmbientMode(0) , mSunEnabled(0) , mPhysicsEngine(engine) , mTerrain(NULL) { + mActors = new MWRender::Actors(mRendering, this); + mObjects = new MWRender::Objects(mRendering); // select best shader mode 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); @@ -162,8 +162,8 @@ RenderingManager::RenderingManager(OEngine::Render::OgreRenderer& _rend, const b mRootNode = mRendering.getScene()->getRootSceneNode(); mRootNode->createChildSceneNode("player"); - mObjects.setRootNode(mRootNode); - mActors.setRootNode(mRootNode); + mObjects->setRootNode(mRootNode); + mActors->setRootNode(mRootNode); mCamera = new MWRender::Camera(mRendering.getCamera()); @@ -201,6 +201,8 @@ RenderingManager::~RenderingManager () delete mCompositors; delete mWater; delete mVideoPlayer; + delete mActors; + delete mObjects; delete mFactory; } @@ -210,10 +212,10 @@ MWRender::SkyManager* RenderingManager::getSkyManager() } MWRender::Objects& RenderingManager::getObjects(){ - return mObjects; + return *mObjects; } MWRender::Actors& RenderingManager::getActors(){ - return mActors; + return *mActors; } OEngine::Render::Fader* RenderingManager::getFader() @@ -223,8 +225,8 @@ OEngine::Render::Fader* RenderingManager::getFader() void RenderingManager::removeCell (MWWorld::Ptr::CellStore *store) { - mObjects.removeCell(store); - mActors.removeCell(store); + mObjects->removeCell(store); + mActors->removeCell(store); mDebugging->cellRemoved(store); } @@ -240,7 +242,7 @@ void RenderingManager::toggleWater() void RenderingManager::cellAdded (MWWorld::Ptr::CellStore *store) { - mObjects.buildStaticGeometry (*store); + mObjects->buildStaticGeometry (*store); sh::Factory::getInstance().unloadUnreferencedMaterials(); mDebugging->cellAdded(store); waterAdded(store); @@ -254,8 +256,8 @@ void RenderingManager::addObject (const MWWorld::Ptr& ptr){ void RenderingManager::removeObject (const MWWorld::Ptr& ptr) { - if (!mObjects.deleteObject (ptr)) - mActors.deleteObject (ptr); + if (!mObjects->deleteObject (ptr)) + mActors->deleteObject (ptr); } 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); if (MWWorld::Class::get(old).isActor()) { - mActors.updateObjectCell(old, cur); + mActors->updateObjectCell(old, cur); } 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") anim = mPlayerAnimation; else if(MWWorld::Class::get(ptr).isActor()) - anim = dynamic_cast(mActors.getAnimation(ptr)); + anim = dynamic_cast(mActors->getAnimation(ptr)); if(anim) { anim->rebuild(); @@ -380,8 +382,8 @@ void RenderingManager::update (float duration, bool paused) if(paused) return; - mActors.update (duration); - mObjects.update (duration); + mActors->update (duration); + mObjects->update (duration); mSkyManager->update(duration); @@ -657,7 +659,7 @@ void RenderingManager::requestMap(MWWorld::Ptr::CellStore* cell) { 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); 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); } else - mLocalMap->requestMap(cell, mObjects.getDimensions(cell)); + mLocalMap->requestMap(cell, mObjects->getDimensions(cell)); } void RenderingManager::preCellChange(MWWorld::Ptr::CellStore* cell) @@ -677,13 +679,13 @@ void RenderingManager::preCellChange(MWWorld::Ptr::CellStore* cell) void RenderingManager::disableLights(bool sun) { - mObjects.disableLights(); + mObjects->disableLights(); sunDisable(sun); } void RenderingManager::enableLights(bool sun) { - mObjects.enableLights(); + mObjects->enableLights(); sunEnable(sun); } @@ -859,7 +861,7 @@ void RenderingManager::processChangedSettings(const Settings::CategorySettingVec if (rebuild) { - mObjects.rebuildStaticGeometry(); + mObjects->rebuildStaticGeometry(); if (mTerrain) mTerrain->applyMaterials(Settings::Manager::getBool("enabled", "Shadows"), Settings::Manager::getBool("split", "Shadows")); @@ -976,13 +978,13 @@ void RenderingManager::setupExternalRendering (MWRender::ExternalRendering& rend Animation* RenderingManager::getAnimation(const MWWorld::Ptr &ptr) { - Animation *anim = mActors.getAnimation(ptr); + Animation *anim = mActors->getAnimation(ptr); if(!anim && ptr.getRefData().getHandle() == "player") anim = mPlayerAnimation; if (!anim) - anim = mObjects.getAnimation(ptr); + anim = mObjects->getAnimation(ptr); return anim; } diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 2d0813912..e5dcf0aeb 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -242,8 +242,8 @@ private: OEngine::Render::OgreRenderer &mRendering; - MWRender::Objects mObjects; - MWRender::Actors mActors; + MWRender::Objects* mObjects; + MWRender::Actors* mActors; MWRender::NpcAnimation *mPlayerAnimation; diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 4819be4ca..e6c535b9b 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -63,11 +63,12 @@ Ogre::MaterialPtr MaterialControllerManager::getWritableMaterial(Ogre::MovableOb else if (Ogre::ParticleSystem* partSys = dynamic_cast(movable)) mat = Ogre::MaterialManager::getSingleton().getByName(partSys->getMaterialName()); - // Make sure techniques are created - sh::Factory::getInstance()._ensureMaterial(mat->getName(), "Default"); - static int count=0; - mat = mat->clone(mat->getName() + Ogre::StringConverter::toString(count++)); + 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; @@ -84,7 +85,7 @@ MaterialControllerManager::~MaterialControllerManager() { for (std::map::iterator it = mClonedMaterials.begin(); it != mClonedMaterials.end(); ++it) { - Ogre::MaterialManager::getSingleton().remove(it->second->getName()); + sh::Factory::getInstance().destroyMaterialInstance(it->second->getName()); } } diff --git a/files/materials/objects.shader b/files/materials/objects.shader index 5a3d872a5..3d873f463 100644 --- a/files/materials/objects.shader +++ b/files/materials/objects.shader @@ -98,9 +98,7 @@ #if VERTEXCOLOR_MODE != 2 shUniform(float4, materialAmbient) @shAutoConstant(materialAmbient, surface_ambient_colour) #endif -#if VERTEXCOLOR_MODE != 2 shUniform(float4, materialDiffuse) @shAutoConstant(materialDiffuse, surface_diffuse_colour) -#endif #if VERTEXCOLOR_MODE != 1 shUniform(float4, materialEmissive) @shAutoConstant(materialEmissive, surface_emissive_colour) #endif @@ -234,9 +232,7 @@ lightResult.xyz += lightAmbient.xyz * materialAmbient.xyz + materialEmissive.xyz; #endif -#if VERTEXCOLOR_MODE != 2 lightResult.a *= materialDiffuse.a; -#endif #endif } @@ -339,9 +335,7 @@ #if VERTEXCOLOR_MODE != 2 shUniform(float4, materialAmbient) @shAutoConstant(materialAmbient, surface_ambient_colour) #endif - #if VERTEXCOLOR_MODE != 2 shUniform(float4, materialDiffuse) @shAutoConstant(materialDiffuse, surface_diffuse_colour) - #endif #if VERTEXCOLOR_MODE != 1 shUniform(float4, materialEmissive) @shAutoConstant(materialEmissive, surface_emissive_colour) #endif @@ -434,9 +428,7 @@ lightResult.xyz += lightAmbient.xyz * materialAmbient.xyz + materialEmissive.xyz; #endif -#if VERTEXCOLOR_MODE != 2 lightResult.a *= materialDiffuse.a; -#endif #endif // shadows only for the first (directional) light