mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-19 23:53:52 +00:00
Merge remote-tracking branch 'kcat/light-objects'
This commit is contained in:
commit
932fffd1a7
23 changed files with 686 additions and 612 deletions
|
@ -78,6 +78,7 @@ set(LIBDIR ${CMAKE_SOURCE_DIR}/libs)
|
||||||
set(OENGINE_OGRE
|
set(OENGINE_OGRE
|
||||||
${LIBDIR}/openengine/ogre/renderer.cpp
|
${LIBDIR}/openengine/ogre/renderer.cpp
|
||||||
${LIBDIR}/openengine/ogre/fader.cpp
|
${LIBDIR}/openengine/ogre/fader.cpp
|
||||||
|
${LIBDIR}/openengine/ogre/lights.cpp
|
||||||
${LIBDIR}/openengine/ogre/particles.cpp
|
${LIBDIR}/openengine/ogre/particles.cpp
|
||||||
${LIBDIR}/openengine/ogre/selectionbuffer.cpp
|
${LIBDIR}/openengine/ogre/selectionbuffer.cpp
|
||||||
${LIBDIR}/openengine/ogre/imagerotate.cpp
|
${LIBDIR}/openengine/ogre/imagerotate.cpp
|
||||||
|
|
|
@ -34,11 +34,10 @@ namespace MWClass
|
||||||
|
|
||||||
MWRender::Objects& objects = renderingInterface.getObjects();
|
MWRender::Objects& objects = renderingInterface.getObjects();
|
||||||
objects.insertBegin(ptr, ptr.getRefData().isEnabled(), false);
|
objects.insertBegin(ptr, ptr.getRefData().isEnabled(), false);
|
||||||
|
if(!model.empty())
|
||||||
if (!model.empty())
|
objects.insertMesh(ptr, "meshes\\" + model);
|
||||||
objects.insertMesh(ptr, "meshes\\" + model, true);
|
|
||||||
else
|
else
|
||||||
objects.insertLight(ptr);
|
objects.insertMesh(ptr, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
void Light::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const
|
void Light::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const
|
||||||
|
|
|
@ -725,15 +725,15 @@ namespace MWClass
|
||||||
|
|
||||||
float x = fJumpAcrobaticsBase->getFloat() +
|
float x = fJumpAcrobaticsBase->getFloat() +
|
||||||
std::pow(a / 15.0f, fJumpAcroMultiplier->getFloat());
|
std::pow(a / 15.0f, fJumpAcroMultiplier->getFloat());
|
||||||
x += 3 * b * fJumpAcroMultiplier->getFloat();
|
x += 3.0f * b * fJumpAcroMultiplier->getFloat();
|
||||||
x += mageffects.get(MWMechanics::EffectKey(9/*jump*/)).mMagnitude * 64;
|
x += mageffects.get(MWMechanics::EffectKey(ESM::MagicEffect::Jump)).mMagnitude * 64;
|
||||||
x *= encumbranceTerm;
|
x *= encumbranceTerm;
|
||||||
|
|
||||||
if(Npc::getStance(ptr, Run, false))
|
if(Npc::getStance(ptr, Run, false))
|
||||||
x *= fJumpRunMultiplier->getFloat();
|
x *= fJumpRunMultiplier->getFloat();
|
||||||
x *= 1.25f;//fatigueTerm;
|
x *= npcdata->mCreatureStats.getFatigueTerm();
|
||||||
x -= -627.2/*gravity constant*/;
|
x -= -627.2f;/*gravity constant*/
|
||||||
x /= 3;
|
x /= 3.0f;
|
||||||
|
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
|
@ -268,10 +268,6 @@ namespace MWInput
|
||||||
case A_ToggleHUD:
|
case A_ToggleHUD:
|
||||||
mWindows.toggleHud();
|
mWindows.toggleHud();
|
||||||
break;
|
break;
|
||||||
case A_Use:
|
|
||||||
if (!MWBase::Environment::get().getWindowManager()->isGuiMode())
|
|
||||||
mPlayer.use();
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,12 +24,14 @@
|
||||||
#include "movement.hpp"
|
#include "movement.hpp"
|
||||||
#include "npcstats.hpp"
|
#include "npcstats.hpp"
|
||||||
#include "creaturestats.hpp"
|
#include "creaturestats.hpp"
|
||||||
|
#include "security.hpp"
|
||||||
|
|
||||||
#include "../mwrender/animation.hpp"
|
#include "../mwrender/animation.hpp"
|
||||||
|
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
#include "../mwbase/world.hpp"
|
#include "../mwbase/world.hpp"
|
||||||
#include "../mwbase/soundmanager.hpp"
|
#include "../mwbase/soundmanager.hpp"
|
||||||
|
#include "../mwbase/windowmanager.hpp"
|
||||||
|
|
||||||
#include "../mwworld/player.hpp"
|
#include "../mwworld/player.hpp"
|
||||||
#include "../mwworld/class.hpp"
|
#include "../mwworld/class.hpp"
|
||||||
|
@ -465,7 +467,36 @@ bool CharacterController::updateNpcState()
|
||||||
sndMgr->playSound3D(mPtr, schools[effect->mData.mSchool]+" cast", 1.0f, 1.0f);
|
sndMgr->playSound3D(mPtr, schools[effect->mData.mSchool]+" cast", 1.0f, 1.0f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(mWeaponType != WeapType_PickProbe)
|
else if(mWeaponType == WeapType_PickProbe)
|
||||||
|
{
|
||||||
|
MWWorld::Ptr item = *weapon;
|
||||||
|
MWWorld::Ptr target = MWBase::Environment::get().getWorld()->getFacedObject();
|
||||||
|
std::string resultMessage, resultSound;
|
||||||
|
|
||||||
|
if(!target.isEmpty())
|
||||||
|
{
|
||||||
|
if(item.getTypeName() == typeid(ESM::Lockpick).name())
|
||||||
|
Security(mPtr).pickLock(target, item, resultMessage, resultSound);
|
||||||
|
else if(item.getTypeName() == typeid(ESM::Probe).name())
|
||||||
|
Security(mPtr).probeTrap(target, item, resultMessage, resultSound);
|
||||||
|
}
|
||||||
|
mAnimation->play(mCurrentWeapon, Priority_Weapon,
|
||||||
|
MWRender::Animation::Group_UpperBody, true,
|
||||||
|
1.0f, "start", "stop", 0.0, 0);
|
||||||
|
mUpperBodyState = UpperCharState_FollowStartToFollowStop;
|
||||||
|
|
||||||
|
if(!resultMessage.empty())
|
||||||
|
MWBase::Environment::get().getWindowManager()->messageBox(resultMessage);
|
||||||
|
if(!resultSound.empty())
|
||||||
|
MWBase::Environment::get().getSoundManager()->playSound(resultSound, 1.0f, 1.0f);
|
||||||
|
|
||||||
|
// tool used up?
|
||||||
|
if(!item.getRefData().getCount())
|
||||||
|
MWBase::Environment::get().getWindowManager()->unsetSelectedWeapon();
|
||||||
|
else
|
||||||
|
MWBase::Environment::get().getWindowManager()->setSelectedWeapon(item);
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
if(mWeaponType == WeapType_Crossbow || mWeaponType == WeapType_BowAndArrow ||
|
if(mWeaponType == WeapType_Crossbow || mWeaponType == WeapType_BowAndArrow ||
|
||||||
mWeaponType == WeapType_ThowWeapon)
|
mWeaponType == WeapType_ThowWeapon)
|
||||||
|
|
|
@ -110,7 +110,7 @@ namespace MWMechanics
|
||||||
return mMagicEffects;
|
return mMagicEffects;
|
||||||
}
|
}
|
||||||
|
|
||||||
const bool &CreatureStats::getAttackingOrSpell() const
|
bool CreatureStats::getAttackingOrSpell() const
|
||||||
{
|
{
|
||||||
return mAttackingOrSpell;
|
return mAttackingOrSpell;
|
||||||
}
|
}
|
||||||
|
@ -216,7 +216,7 @@ namespace MWMechanics
|
||||||
mMagicEffects = effects;
|
mMagicEffects = effects;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CreatureStats::setAttackingOrSpell(const bool &attackingOrSpell)
|
void CreatureStats::setAttackingOrSpell(bool attackingOrSpell)
|
||||||
{
|
{
|
||||||
mAttackingOrSpell = attackingOrSpell;
|
mAttackingOrSpell = attackingOrSpell;
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,7 +59,7 @@ namespace MWMechanics
|
||||||
|
|
||||||
const MagicEffects & getMagicEffects() const;
|
const MagicEffects & getMagicEffects() const;
|
||||||
|
|
||||||
const bool & getAttackingOrSpell() const;
|
bool getAttackingOrSpell() const;
|
||||||
|
|
||||||
int getLevel() const;
|
int getLevel() const;
|
||||||
|
|
||||||
|
@ -90,7 +90,7 @@ namespace MWMechanics
|
||||||
|
|
||||||
void setMagicEffects(const MagicEffects &effects);
|
void setMagicEffects(const MagicEffects &effects);
|
||||||
|
|
||||||
void setAttackingOrSpell(const bool &attackingOrSpell);
|
void setAttackingOrSpell(bool attackingOrSpell);
|
||||||
|
|
||||||
enum AttackType
|
enum AttackType
|
||||||
{
|
{
|
||||||
|
|
|
@ -12,16 +12,16 @@ ActivatorAnimation::~ActivatorAnimation()
|
||||||
}
|
}
|
||||||
|
|
||||||
ActivatorAnimation::ActivatorAnimation(const MWWorld::Ptr &ptr)
|
ActivatorAnimation::ActivatorAnimation(const MWWorld::Ptr &ptr)
|
||||||
: Animation(ptr)
|
: Animation(ptr, ptr.getRefData().getBaseNode())
|
||||||
{
|
{
|
||||||
MWWorld::LiveCellRef<ESM::Activator> *ref = mPtr.get<ESM::Activator>();
|
MWWorld::LiveCellRef<ESM::Activator> *ref = mPtr.get<ESM::Activator>();
|
||||||
|
|
||||||
assert (ref->mBase != NULL);
|
assert(ref->mBase != NULL);
|
||||||
if(!ref->mBase->mModel.empty())
|
if(!ref->mBase->mModel.empty())
|
||||||
{
|
{
|
||||||
const std::string name = "meshes\\"+ref->mBase->mModel;
|
const std::string name = "meshes\\"+ref->mBase->mModel;
|
||||||
|
|
||||||
setObjectRoot(mPtr.getRefData().getBaseNode(), name, false);
|
setObjectRoot(name, false);
|
||||||
setRenderProperties(mObjectRoot, RV_Misc, RQG_Main, RQG_Alpha);
|
setRenderProperties(mObjectRoot, RV_Misc, RQG_Main, RQG_Alpha);
|
||||||
|
|
||||||
addAnimSource(name);
|
addAnimSource(name);
|
||||||
|
|
|
@ -8,6 +8,10 @@
|
||||||
#include <OgreBone.h>
|
#include <OgreBone.h>
|
||||||
#include <OgreSubMesh.h>
|
#include <OgreSubMesh.h>
|
||||||
#include <OgreSceneManager.h>
|
#include <OgreSceneManager.h>
|
||||||
|
#include <OgreControllerManager.h>
|
||||||
|
#include <OgreStaticGeometry.h>
|
||||||
|
|
||||||
|
#include <libs/openengine/ogre/lights.hpp>
|
||||||
|
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
#include "../mwbase/soundmanager.hpp"
|
#include "../mwbase/soundmanager.hpp"
|
||||||
|
@ -16,6 +20,9 @@
|
||||||
#include "../mwmechanics/character.hpp"
|
#include "../mwmechanics/character.hpp"
|
||||||
#include "../mwmechanics/creaturestats.hpp"
|
#include "../mwmechanics/creaturestats.hpp"
|
||||||
#include "../mwworld/class.hpp"
|
#include "../mwworld/class.hpp"
|
||||||
|
#include "../mwworld/fallback.hpp"
|
||||||
|
|
||||||
|
#include "renderconst.hpp"
|
||||||
|
|
||||||
namespace MWRender
|
namespace MWRender
|
||||||
{
|
{
|
||||||
|
@ -35,17 +42,26 @@ void Animation::AnimationValue::setValue(Ogre::Real)
|
||||||
|
|
||||||
void Animation::destroyObjectList(Ogre::SceneManager *sceneMgr, NifOgre::ObjectList &objects)
|
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++)
|
for(size_t i = 0;i < objects.mParticles.size();i++)
|
||||||
sceneMgr->destroyParticleSystem(objects.mParticles[i]);
|
sceneMgr->destroyParticleSystem(objects.mParticles[i]);
|
||||||
for(size_t i = 0;i < objects.mEntities.size();i++)
|
for(size_t i = 0;i < objects.mEntities.size();i++)
|
||||||
sceneMgr->destroyEntity(objects.mEntities[i]);
|
sceneMgr->destroyEntity(objects.mEntities[i]);
|
||||||
objects.mControllers.clear();
|
objects.mControllers.clear();
|
||||||
|
objects.mLights.clear();
|
||||||
objects.mParticles.clear();
|
objects.mParticles.clear();
|
||||||
objects.mEntities.clear();
|
objects.mEntities.clear();
|
||||||
objects.mSkelBase = NULL;
|
objects.mSkelBase = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
Animation::Animation(const MWWorld::Ptr &ptr)
|
Animation::Animation(const MWWorld::Ptr &ptr, Ogre::SceneNode *node)
|
||||||
: mPtr(ptr)
|
: mPtr(ptr)
|
||||||
, mCamera(NULL)
|
, mCamera(NULL)
|
||||||
, mInsert(NULL)
|
, mInsert(NULL)
|
||||||
|
@ -58,6 +74,8 @@ Animation::Animation(const MWWorld::Ptr &ptr)
|
||||||
{
|
{
|
||||||
for(size_t i = 0;i < sNumGroups;i++)
|
for(size_t i = 0;i < sNumGroups;i++)
|
||||||
mAnimationValuePtr[i].bind(OGRE_NEW AnimationValue(this));
|
mAnimationValuePtr[i].bind(OGRE_NEW AnimationValue(this));
|
||||||
|
mInsert = node ? node->createChildSceneNode() :
|
||||||
|
mPtr.getRefData().getBaseNode()->createChildSceneNode();
|
||||||
}
|
}
|
||||||
|
|
||||||
Animation::~Animation()
|
Animation::~Animation()
|
||||||
|
@ -72,11 +90,15 @@ Animation::~Animation()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Animation::setObjectRoot(Ogre::SceneNode *node, const std::string &model, bool baseonly)
|
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!");
|
||||||
if(!mInsert)
|
|
||||||
mInsert = node->createChildSceneNode();
|
mSkelBase = NULL;
|
||||||
|
destroyObjectList(mInsert->getCreator(), mObjectRoot);
|
||||||
|
|
||||||
|
if(model.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
std::string mdlname = Misc::StringUtils::lowerCase(model);
|
std::string mdlname = Misc::StringUtils::lowerCase(model);
|
||||||
std::string::size_type p = mdlname.rfind('\\');
|
std::string::size_type p = mdlname.rfind('\\');
|
||||||
|
@ -92,9 +114,6 @@ void Animation::setObjectRoot(Ogre::SceneNode *node, const std::string &model, b
|
||||||
Misc::StringUtils::toLower(mdlname);
|
Misc::StringUtils::toLower(mdlname);
|
||||||
}
|
}
|
||||||
|
|
||||||
mSkelBase = NULL;
|
|
||||||
destroyObjectList(mInsert->getCreator(), mObjectRoot);
|
|
||||||
|
|
||||||
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)
|
||||||
|
@ -140,28 +159,47 @@ void Animation::setObjectRoot(Ogre::SceneNode *node, const std::string &model, b
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Animation::setRenderProperties(const NifOgre::ObjectList &objlist, Ogre::uint32 visflags, Ogre::uint8 solidqueue, Ogre::uint8 transqueue)
|
|
||||||
{
|
|
||||||
for(size_t i = 0;i < objlist.mEntities.size();i++)
|
|
||||||
{
|
|
||||||
Ogre::Entity *ent = objlist.mEntities[i];
|
|
||||||
if(visflags != 0)
|
|
||||||
ent->setVisibilityFlags(visflags);
|
|
||||||
|
|
||||||
for(unsigned int j = 0;j < ent->getNumSubEntities();++j)
|
class VisQueueSet {
|
||||||
|
Ogre::uint32 mVisFlags;
|
||||||
|
Ogre::uint8 mSolidQueue, mTransQueue;
|
||||||
|
Ogre::Real mDist;
|
||||||
|
|
||||||
|
public:
|
||||||
|
VisQueueSet(Ogre::uint32 visflags, Ogre::uint8 solidqueue, Ogre::uint8 transqueue, Ogre::Real dist)
|
||||||
|
: mVisFlags(visflags), mSolidQueue(solidqueue), mTransQueue(transqueue), mDist(dist)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
void operator()(Ogre::Entity *entity) const
|
||||||
{
|
{
|
||||||
Ogre::SubEntity* subEnt = ent->getSubEntity(j);
|
if(mVisFlags != 0)
|
||||||
subEnt->setRenderQueueGroup(subEnt->getMaterial()->isTransparent() ? transqueue : solidqueue);
|
entity->setVisibilityFlags(mVisFlags);
|
||||||
|
entity->setRenderingDistance(mDist);
|
||||||
|
|
||||||
|
unsigned int numsubs = entity->getNumSubEntities();
|
||||||
|
for(unsigned int i = 0;i < numsubs;++i)
|
||||||
|
{
|
||||||
|
Ogre::SubEntity* subEnt = entity->getSubEntity(i);
|
||||||
|
subEnt->setRenderQueueGroup(subEnt->getMaterial()->isTransparent() ? mTransQueue : mSolidQueue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for(size_t i = 0;i < objlist.mParticles.size();i++)
|
|
||||||
|
void operator()(Ogre::ParticleSystem *psys) const
|
||||||
{
|
{
|
||||||
Ogre::ParticleSystem *part = objlist.mParticles[i];
|
if(mVisFlags != 0)
|
||||||
if(visflags != 0)
|
psys->setVisibilityFlags(mVisFlags);
|
||||||
part->setVisibilityFlags(visflags);
|
psys->setRenderingDistance(mDist);
|
||||||
// TODO: Check particle material for actual transparency
|
// TODO: Check particle material for actual transparency
|
||||||
part->setRenderQueueGroup(transqueue);
|
psys->setRenderQueueGroup(mTransQueue);
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void Animation::setRenderProperties(const NifOgre::ObjectList &objlist, Ogre::uint32 visflags, Ogre::uint8 solidqueue, Ogre::uint8 transqueue, Ogre::Real dist)
|
||||||
|
{
|
||||||
|
std::for_each(objlist.mEntities.begin(), objlist.mEntities.end(),
|
||||||
|
VisQueueSet(visflags, solidqueue, transqueue, dist));
|
||||||
|
std::for_each(objlist.mParticles.begin(), objlist.mParticles.end(),
|
||||||
|
VisQueueSet(visflags, solidqueue, transqueue, dist));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -254,6 +292,76 @@ void Animation::clearAnimSources()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Animation::addExtraLight(Ogre::SceneManager *sceneMgr, NifOgre::ObjectList &objlist, const ESM::Light *light)
|
||||||
|
{
|
||||||
|
const MWWorld::Fallback *fallback = MWBase::Environment::get().getWorld()->getFallback();
|
||||||
|
|
||||||
|
const int clr = light->mData.mColor;
|
||||||
|
Ogre::ColourValue color(((clr >> 0) & 0xFF) / 255.0f,
|
||||||
|
((clr >> 8) & 0xFF) / 255.0f,
|
||||||
|
((clr >> 16) & 0xFF) / 255.0f);
|
||||||
|
const float radius = float(light->mData.mRadius);
|
||||||
|
|
||||||
|
if((light->mData.mFlags&ESM::Light::Negative))
|
||||||
|
color *= -1;
|
||||||
|
|
||||||
|
objlist.mLights.push_back(sceneMgr->createLight());
|
||||||
|
Ogre::Light *olight = objlist.mLights.back();
|
||||||
|
olight->setDiffuseColour(color);
|
||||||
|
|
||||||
|
Ogre::ControllerValueRealPtr src(Ogre::ControllerManager::getSingleton().getFrameTimeSource());
|
||||||
|
Ogre::ControllerValueRealPtr dest(OGRE_NEW OEngine::Render::LightValue(olight, color));
|
||||||
|
Ogre::ControllerFunctionRealPtr func(OGRE_NEW OEngine::Render::LightFunction(
|
||||||
|
(light->mData.mFlags&ESM::Light::Flicker) ? OEngine::Render::LT_Flicker :
|
||||||
|
(light->mData.mFlags&ESM::Light::FlickerSlow) ? OEngine::Render::LT_FlickerSlow :
|
||||||
|
(light->mData.mFlags&ESM::Light::Pulse) ? OEngine::Render::LT_Pulse :
|
||||||
|
(light->mData.mFlags&ESM::Light::PulseSlow) ? OEngine::Render::LT_PulseSlow :
|
||||||
|
OEngine::Render::LT_Normal
|
||||||
|
));
|
||||||
|
objlist.mControllers.push_back(Ogre::Controller<Ogre::Real>(src, dest, func));
|
||||||
|
|
||||||
|
bool interior = !(mPtr.isInCell() && mPtr.getCell()->mCell->isExterior());
|
||||||
|
bool quadratic = fallback->getFallbackBool("LightAttenuation_OutQuadInLin") ?
|
||||||
|
!interior : fallback->getFallbackBool("LightAttenuation_UseQuadratic");
|
||||||
|
|
||||||
|
// with the standard 1 / (c + d*l + d*d*q) equation the attenuation factor never becomes zero,
|
||||||
|
// so we ignore lights if their attenuation falls below this factor.
|
||||||
|
const float threshold = 0.03;
|
||||||
|
|
||||||
|
if (!quadratic)
|
||||||
|
{
|
||||||
|
float r = radius * fallback->getFallbackFloat("LightAttenuation_LinearRadiusMult");
|
||||||
|
float attenuation = fallback->getFallbackFloat("LightAttenuation_LinearValue") / r;
|
||||||
|
float activationRange = 1.0f / (threshold * attenuation);
|
||||||
|
olight->setAttenuation(activationRange, 0, attenuation, 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
float r = radius * fallback->getFallbackFloat("LightAttenuation_QuadraticRadiusMult");
|
||||||
|
float attenuation = fallback->getFallbackFloat("LightAttenuation_QuadraticValue") / std::pow(r, 2);
|
||||||
|
float activationRange = std::sqrt(1.0f / (threshold * attenuation));
|
||||||
|
olight->setAttenuation(activationRange, 0, 0, attenuation);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there's an AttachLight bone, attach the light to that, otherwise put it in the center,
|
||||||
|
if(objlist.mSkelBase && objlist.mSkelBase->getSkeleton()->hasBone("AttachLight"))
|
||||||
|
objlist.mSkelBase->attachObjectToBone("AttachLight", olight);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Ogre::AxisAlignedBox bounds = Ogre::AxisAlignedBox::BOX_NULL;
|
||||||
|
for(size_t i = 0;i < objlist.mEntities.size();i++)
|
||||||
|
{
|
||||||
|
Ogre::Entity *ent = objlist.mEntities[i];
|
||||||
|
bounds.merge(ent->getBoundingBox());
|
||||||
|
}
|
||||||
|
|
||||||
|
Ogre::SceneNode *node = bounds.isFinite() ? mInsert->createChildSceneNode(bounds.getCenter())
|
||||||
|
: mInsert->createChildSceneNode();
|
||||||
|
node->attachObject(olight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Ogre::Node *Animation::getNode(const std::string &name)
|
Ogre::Node *Animation::getNode(const std::string &name)
|
||||||
{
|
{
|
||||||
if(mSkelBase)
|
if(mSkelBase)
|
||||||
|
@ -805,6 +913,43 @@ void Animation::showWeapons(bool showWeapon)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class ToggleLight {
|
||||||
|
bool mEnable;
|
||||||
|
|
||||||
|
public:
|
||||||
|
ToggleLight(bool enable) : mEnable(enable) { }
|
||||||
|
|
||||||
|
void operator()(Ogre::Light *light) const
|
||||||
|
{ light->setVisible(mEnable); }
|
||||||
|
};
|
||||||
|
|
||||||
|
void Animation::enableLights(bool enable)
|
||||||
|
{
|
||||||
|
std::for_each(mObjectRoot.mLights.begin(), mObjectRoot.mLights.end(), ToggleLight(enable));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class MergeBounds {
|
||||||
|
Ogre::AxisAlignedBox *mBounds;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MergeBounds(Ogre::AxisAlignedBox *bounds) : mBounds(bounds) { }
|
||||||
|
|
||||||
|
void operator()(Ogre::MovableObject *obj)
|
||||||
|
{
|
||||||
|
mBounds->merge(obj->getWorldBoundingBox(true));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Ogre::AxisAlignedBox Animation::getWorldBounds()
|
||||||
|
{
|
||||||
|
Ogre::AxisAlignedBox bounds = Ogre::AxisAlignedBox::BOX_NULL;
|
||||||
|
std::for_each(mObjectRoot.mEntities.begin(), mObjectRoot.mEntities.end(), MergeBounds(&bounds));
|
||||||
|
return bounds;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Animation::isPriorityActive(int priority) const
|
bool Animation::isPriorityActive(int priority) const
|
||||||
{
|
{
|
||||||
for (AnimStateMap::const_iterator it = mStates.begin(); it != mStates.end(); ++it)
|
for (AnimStateMap::const_iterator it = mStates.begin(); it != mStates.end(); ++it)
|
||||||
|
@ -833,4 +978,65 @@ void Animation::detachObjectFromBone(Ogre::MovableObject *obj)
|
||||||
mSkelBase->detachObjectFromBone(obj);
|
mSkelBase->detachObjectFromBone(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ObjectAnimation::ObjectAnimation(const MWWorld::Ptr& ptr, const std::string &model, bool isStatic)
|
||||||
|
: Animation(ptr, ptr.getRefData().getBaseNode())
|
||||||
|
{
|
||||||
|
setObjectRoot(model, false);
|
||||||
|
|
||||||
|
Ogre::AxisAlignedBox bounds = getWorldBounds();
|
||||||
|
|
||||||
|
Ogre::Vector3 extents = bounds.getSize();
|
||||||
|
extents *= mInsert->getParentSceneNode()->getScale();
|
||||||
|
float size = std::max(std::max(extents.x, extents.y), extents.z);
|
||||||
|
|
||||||
|
bool small = (size < Settings::Manager::getInt("small object size", "Viewing distance")) &&
|
||||||
|
Settings::Manager::getBool("limit small object distance", "Viewing distance");
|
||||||
|
// do not fade out doors. that will cause holes and look stupid
|
||||||
|
if(ptr.getTypeName().find("Door") != std::string::npos)
|
||||||
|
small = false;
|
||||||
|
|
||||||
|
float dist = small ? Settings::Manager::getInt("small object distance", "Viewing distance") : 0.0f;
|
||||||
|
setRenderProperties(mObjectRoot, isStatic ? (small ? RV_StaticsSmall : RV_Statics) : RV_Misc,
|
||||||
|
RQG_Main, RQG_Alpha, dist);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ObjectAnimation::addLight(const ESM::Light *light)
|
||||||
|
{
|
||||||
|
addExtraLight(mInsert->getCreator(), mObjectRoot, light);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class FindEntityTransparency {
|
||||||
|
public:
|
||||||
|
bool operator()(Ogre::Entity *ent) const
|
||||||
|
{
|
||||||
|
unsigned int numsubs = ent->getNumSubEntities();
|
||||||
|
for(unsigned int i = 0;i < numsubs;++i)
|
||||||
|
{
|
||||||
|
if(ent->getSubEntity(i)->getMaterial()->isTransparent())
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
bool ObjectAnimation::canBatch() const
|
||||||
|
{
|
||||||
|
if(!mObjectRoot.mParticles.empty() || !mObjectRoot.mLights.empty() || !mObjectRoot.mControllers.empty())
|
||||||
|
return false;
|
||||||
|
return std::find_if(mObjectRoot.mEntities.begin(), mObjectRoot.mEntities.end(),
|
||||||
|
FindEntityTransparency()) == mObjectRoot.mEntities.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ObjectAnimation::fillBatch(Ogre::StaticGeometry *sg)
|
||||||
|
{
|
||||||
|
std::vector<Ogre::Entity*>::reverse_iterator iter = mObjectRoot.mEntities.rbegin();
|
||||||
|
for(;iter != mObjectRoot.mEntities.rend();++iter)
|
||||||
|
{
|
||||||
|
Ogre::Node *node = (*iter)->getParentNode();
|
||||||
|
sg->addEntity(*iter, node->_getDerivedPosition(), node->_getDerivedOrientation(), node->_getDerivedScale());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,6 +52,7 @@ protected:
|
||||||
virtual void setValue(Ogre::Real value);
|
virtual void setValue(Ogre::Real value);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class NullAnimationValue : public Ogre::ControllerValue<Ogre::Real>
|
class NullAnimationValue : public Ogre::ControllerValue<Ogre::Real>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -61,6 +62,7 @@ protected:
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
struct AnimSource : public Ogre::AnimationAlloc {
|
struct AnimSource : public Ogre::AnimationAlloc {
|
||||||
NifOgre::TextKeyMap mTextKeys;
|
NifOgre::TextKeyMap mTextKeys;
|
||||||
std::vector<Ogre::Controller<Ogre::Real> > mControllers[sNumGroups];
|
std::vector<Ogre::Controller<Ogre::Real> > mControllers[sNumGroups];
|
||||||
|
@ -151,21 +153,24 @@ protected:
|
||||||
* Note that you must make sure all animation sources are cleared before reseting the object
|
* Note that you must make sure all animation sources are cleared before reseting the object
|
||||||
* root. All nodes previously retrieved with getNode will also become invalidated.
|
* root. All nodes previously retrieved with getNode will also become invalidated.
|
||||||
*/
|
*/
|
||||||
void setObjectRoot(Ogre::SceneNode *node, const std::string &model, bool baseonly);
|
void setObjectRoot(const std::string &model, bool baseonly);
|
||||||
|
|
||||||
/* Adds the keyframe controllers in the specified model as a new animation source. Note that
|
/* Adds the keyframe controllers in the specified model as a new animation source. Note that
|
||||||
* the filename portion of the provided model name will be prepended with 'x', and the .nif
|
* the filename portion of the provided model name will be prepended with 'x', and the .nif
|
||||||
* extension will be replaced with .kf. */
|
* extension will be replaced with .kf. */
|
||||||
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. */
|
||||||
|
void addExtraLight(Ogre::SceneManager *sceneMgr, NifOgre::ObjectList &objlist, const ESM::Light *light);
|
||||||
|
|
||||||
static void destroyObjectList(Ogre::SceneManager *sceneMgr, NifOgre::ObjectList &objects);
|
static void destroyObjectList(Ogre::SceneManager *sceneMgr, NifOgre::ObjectList &objects);
|
||||||
|
|
||||||
static void setRenderProperties(const NifOgre::ObjectList &objlist, Ogre::uint32 visflags, Ogre::uint8 solidqueue, Ogre::uint8 transqueue);
|
static void setRenderProperties(const NifOgre::ObjectList &objlist, Ogre::uint32 visflags, Ogre::uint8 solidqueue, Ogre::uint8 transqueue, Ogre::Real dist=0.0f);
|
||||||
|
|
||||||
void clearAnimSources();
|
void clearAnimSources();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Animation(const MWWorld::Ptr &ptr);
|
Animation(const MWWorld::Ptr &ptr, Ogre::SceneNode *node);
|
||||||
virtual ~Animation();
|
virtual ~Animation();
|
||||||
|
|
||||||
void updatePtr(const MWWorld::Ptr &ptr);
|
void updatePtr(const MWWorld::Ptr &ptr);
|
||||||
|
@ -224,6 +229,10 @@ public:
|
||||||
|
|
||||||
virtual void showWeapons(bool showWeapon);
|
virtual void showWeapons(bool showWeapon);
|
||||||
|
|
||||||
|
void enableLights(bool enable);
|
||||||
|
|
||||||
|
Ogre::AxisAlignedBox getWorldBounds();
|
||||||
|
|
||||||
void setCamera(Camera *cam)
|
void setCamera(Camera *cam)
|
||||||
{ mCamera = cam; }
|
{ mCamera = cam; }
|
||||||
|
|
||||||
|
@ -236,5 +245,15 @@ public:
|
||||||
void detachObjectFromBone(Ogre::MovableObject *obj);
|
void detachObjectFromBone(Ogre::MovableObject *obj);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ObjectAnimation : public Animation {
|
||||||
|
public:
|
||||||
|
ObjectAnimation(const MWWorld::Ptr& ptr, const std::string &model, bool isStatic);
|
||||||
|
|
||||||
|
void addLight(const ESM::Light *light);
|
||||||
|
|
||||||
|
bool canBatch() const;
|
||||||
|
void fillBatch(Ogre::StaticGeometry *sg);
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -12,7 +12,7 @@ CreatureAnimation::~CreatureAnimation()
|
||||||
}
|
}
|
||||||
|
|
||||||
CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr)
|
CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr)
|
||||||
: Animation(ptr)
|
: Animation(ptr, ptr.getRefData().getBaseNode())
|
||||||
{
|
{
|
||||||
MWWorld::LiveCellRef<ESM::Creature> *ref = mPtr.get<ESM::Creature>();
|
MWWorld::LiveCellRef<ESM::Creature> *ref = mPtr.get<ESM::Creature>();
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr)
|
||||||
{
|
{
|
||||||
std::string model = "meshes\\"+ref->mBase->mModel;
|
std::string model = "meshes\\"+ref->mBase->mModel;
|
||||||
|
|
||||||
setObjectRoot(mPtr.getRefData().getBaseNode(), model, false);
|
setObjectRoot(model, false);
|
||||||
setRenderProperties(mObjectRoot, RV_Actors, RQG_Main, RQG_Alpha);
|
setRenderProperties(mObjectRoot, RV_Actors, RQG_Main, RQG_Alpha);
|
||||||
|
|
||||||
if((ref->mBase->mFlags&ESM::Creature::Biped))
|
if((ref->mBase->mFlags&ESM::Creature::Biped))
|
||||||
|
|
|
@ -20,46 +20,50 @@
|
||||||
namespace MWRender
|
namespace MWRender
|
||||||
{
|
{
|
||||||
|
|
||||||
const NpcAnimation::PartInfo NpcAnimation::sPartList[NpcAnimation::sPartListSize] = {
|
static NpcAnimation::PartBoneMap createPartListMap()
|
||||||
{ ESM::PRT_Head, "Head" },
|
{
|
||||||
{ ESM::PRT_Hair, "Head" },
|
NpcAnimation::PartBoneMap result;
|
||||||
{ ESM::PRT_Neck, "Neck" },
|
result.insert(std::make_pair(ESM::PRT_Head, "Head"));
|
||||||
{ ESM::PRT_Cuirass, "Chest" },
|
result.insert(std::make_pair(ESM::PRT_Hair, "Head"));
|
||||||
{ ESM::PRT_Groin, "Groin" },
|
result.insert(std::make_pair(ESM::PRT_Neck, "Neck"));
|
||||||
{ ESM::PRT_Skirt, "Groin" },
|
result.insert(std::make_pair(ESM::PRT_Cuirass, "Chest"));
|
||||||
{ ESM::PRT_RHand, "Right Hand" },
|
result.insert(std::make_pair(ESM::PRT_Groin, "Groin"));
|
||||||
{ ESM::PRT_LHand, "Left Hand" },
|
result.insert(std::make_pair(ESM::PRT_Skirt, "Groin"));
|
||||||
{ ESM::PRT_RWrist, "Right Wrist" },
|
result.insert(std::make_pair(ESM::PRT_RHand, "Right Hand"));
|
||||||
{ ESM::PRT_LWrist, "Left Wrist" },
|
result.insert(std::make_pair(ESM::PRT_LHand, "Left Hand"));
|
||||||
{ ESM::PRT_Shield, "Shield Bone" },
|
result.insert(std::make_pair(ESM::PRT_RWrist, "Right Wrist"));
|
||||||
{ ESM::PRT_RForearm, "Right Forearm" },
|
result.insert(std::make_pair(ESM::PRT_LWrist, "Left Wrist"));
|
||||||
{ ESM::PRT_LForearm, "Left Forearm" },
|
result.insert(std::make_pair(ESM::PRT_Shield, "Shield Bone"));
|
||||||
{ ESM::PRT_RUpperarm, "Right Upper Arm" },
|
result.insert(std::make_pair(ESM::PRT_RForearm, "Right Forearm"));
|
||||||
{ ESM::PRT_LUpperarm, "Left Upper Arm" },
|
result.insert(std::make_pair(ESM::PRT_LForearm, "Left Forearm"));
|
||||||
{ ESM::PRT_RFoot, "Right Foot" },
|
result.insert(std::make_pair(ESM::PRT_RUpperarm, "Right Upper Arm"));
|
||||||
{ ESM::PRT_LFoot, "Left Foot" },
|
result.insert(std::make_pair(ESM::PRT_LUpperarm, "Left Upper Arm"));
|
||||||
{ ESM::PRT_RAnkle, "Right Ankle" },
|
result.insert(std::make_pair(ESM::PRT_RFoot, "Right Foot"));
|
||||||
{ ESM::PRT_LAnkle, "Left Ankle" },
|
result.insert(std::make_pair(ESM::PRT_LFoot, "Left Foot"));
|
||||||
{ ESM::PRT_RKnee, "Right Knee" },
|
result.insert(std::make_pair(ESM::PRT_RAnkle, "Right Ankle"));
|
||||||
{ ESM::PRT_LKnee, "Left Knee" },
|
result.insert(std::make_pair(ESM::PRT_LAnkle, "Left Ankle"));
|
||||||
{ ESM::PRT_RLeg, "Right Upper Leg" },
|
result.insert(std::make_pair(ESM::PRT_RKnee, "Right Knee"));
|
||||||
{ ESM::PRT_LLeg, "Left Upper Leg" },
|
result.insert(std::make_pair(ESM::PRT_LKnee, "Left Knee"));
|
||||||
{ ESM::PRT_RPauldron, "Right Clavicle" },
|
result.insert(std::make_pair(ESM::PRT_RLeg, "Right Upper Leg"));
|
||||||
{ ESM::PRT_LPauldron, "Left Clavicle" },
|
result.insert(std::make_pair(ESM::PRT_LLeg, "Left Upper Leg"));
|
||||||
{ ESM::PRT_Weapon, "Weapon Bone" },
|
result.insert(std::make_pair(ESM::PRT_RPauldron, "Right Clavicle"));
|
||||||
{ ESM::PRT_Tail, "Tail" }
|
result.insert(std::make_pair(ESM::PRT_LPauldron, "Left Clavicle"));
|
||||||
};
|
result.insert(std::make_pair(ESM::PRT_Weapon, "Weapon Bone"));
|
||||||
|
result.insert(std::make_pair(ESM::PRT_Tail, "Tail"));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
const NpcAnimation::PartBoneMap NpcAnimation::sPartList = createPartListMap();
|
||||||
|
|
||||||
NpcAnimation::~NpcAnimation()
|
NpcAnimation::~NpcAnimation()
|
||||||
{
|
{
|
||||||
Ogre::SceneManager *sceneMgr = mInsert->getCreator();
|
Ogre::SceneManager *sceneMgr = mInsert->getCreator();
|
||||||
for(size_t i = 0;i < sPartListSize;i++)
|
for(size_t i = 0;i < ESM::PRT_Count;i++)
|
||||||
destroyObjectList(sceneMgr, mObjectParts[i]);
|
destroyObjectList(sceneMgr, mObjectParts[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWorld::InventoryStore& inv, int visibilityFlags, ViewMode viewMode)
|
NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWorld::InventoryStore& inv, int visibilityFlags, ViewMode viewMode)
|
||||||
: Animation(ptr),
|
: Animation(ptr, node),
|
||||||
mStateID(-1),
|
mStateID(-1),
|
||||||
mTimeToChange(0),
|
mTimeToChange(0),
|
||||||
mVisibilityFlags(visibilityFlags),
|
mVisibilityFlags(visibilityFlags),
|
||||||
|
@ -82,7 +86,7 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor
|
||||||
{
|
{
|
||||||
mNpc = mPtr.get<ESM::NPC>()->mBase;
|
mNpc = mPtr.get<ESM::NPC>()->mBase;
|
||||||
|
|
||||||
for(size_t i = 0;i < sPartListSize;i++)
|
for(size_t i = 0;i < ESM::PRT_Count;i++)
|
||||||
{
|
{
|
||||||
mPartslots[i] = -1; //each slot is empty
|
mPartslots[i] = -1; //each slot is empty
|
||||||
mPartPriorities[i] = 0;
|
mPartPriorities[i] = 0;
|
||||||
|
@ -102,7 +106,7 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor
|
||||||
std::string smodel = (viewMode != VM_FirstPerson) ?
|
std::string smodel = (viewMode != VM_FirstPerson) ?
|
||||||
(!isBeast ? "meshes\\base_anim.nif" : "meshes\\base_animkna.nif") :
|
(!isBeast ? "meshes\\base_anim.nif" : "meshes\\base_animkna.nif") :
|
||||||
(!isBeast ? "meshes\\base_anim.1st.nif" : "meshes\\base_animkna.1st.nif") ;
|
(!isBeast ? "meshes\\base_anim.1st.nif" : "meshes\\base_animkna.1st.nif") ;
|
||||||
setObjectRoot(node, smodel, true);
|
setObjectRoot(smodel, true);
|
||||||
|
|
||||||
if(mViewMode != VM_FirstPerson)
|
if(mViewMode != VM_FirstPerson)
|
||||||
{
|
{
|
||||||
|
@ -143,7 +147,7 @@ void NpcAnimation::setViewMode(NpcAnimation::ViewMode viewMode)
|
||||||
std::string smodel = (viewMode != VM_FirstPerson) ?
|
std::string smodel = (viewMode != VM_FirstPerson) ?
|
||||||
(!isBeast ? "meshes\\base_anim.nif" : "meshes\\base_animkna.nif") :
|
(!isBeast ? "meshes\\base_anim.nif" : "meshes\\base_animkna.nif") :
|
||||||
(!isBeast ? "meshes\\base_anim.1st.nif" : "meshes\\base_animkna.1st.nif") ;
|
(!isBeast ? "meshes\\base_anim.1st.nif" : "meshes\\base_animkna.1st.nif") ;
|
||||||
setObjectRoot(mInsert->getParentSceneNode(), smodel, true);
|
setObjectRoot(smodel, true);
|
||||||
|
|
||||||
if(mViewMode != VM_FirstPerson)
|
if(mViewMode != VM_FirstPerson)
|
||||||
{
|
{
|
||||||
|
@ -168,8 +172,8 @@ void NpcAnimation::setViewMode(NpcAnimation::ViewMode viewMode)
|
||||||
}
|
}
|
||||||
MWBase::Environment::get().getMechanicsManager()->forceStateUpdate(mPtr);
|
MWBase::Environment::get().getMechanicsManager()->forceStateUpdate(mPtr);
|
||||||
|
|
||||||
for(size_t i = 0;i < sPartListSize;i++)
|
for(size_t i = 0;i < ESM::PRT_Count;i++)
|
||||||
removeIndividualPart(i);
|
removeIndividualPart((ESM::PartReferenceType)i);
|
||||||
forceUpdate();
|
forceUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -267,6 +271,19 @@ void NpcAnimation::updateParts(bool forceupdate)
|
||||||
if(mViewMode == VM_HeadOnly)
|
if(mViewMode == VM_HeadOnly)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if(mPartPriorities[ESM::PRT_Shield] < 1)
|
||||||
|
{
|
||||||
|
MWWorld::ContainerStoreIterator store = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedLeft);
|
||||||
|
MWWorld::Ptr part;
|
||||||
|
if(store != inv.end() && (part=*store).getTypeName() == typeid(ESM::Light).name())
|
||||||
|
{
|
||||||
|
const ESM::Light *light = part.get<ESM::Light>()->mBase;
|
||||||
|
addOrReplaceIndividualPart(ESM::PRT_Shield, MWWorld::InventoryStore::Slot_CarriedLeft,
|
||||||
|
1, "meshes\\"+light->mModel);
|
||||||
|
addExtraLight(mInsert->getCreator(), mObjectParts[ESM::PRT_Shield], light);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
showWeapons(mShowWeapons);
|
showWeapons(mShowWeapons);
|
||||||
|
|
||||||
const int Flag_Female = 0x01;
|
const int Flag_Female = 0x01;
|
||||||
|
@ -366,23 +383,31 @@ void NpcAnimation::updateParts(bool forceupdate)
|
||||||
{
|
{
|
||||||
const ESM::BodyPart* bodypart = parts[part];
|
const ESM::BodyPart* bodypart = parts[part];
|
||||||
if(bodypart)
|
if(bodypart)
|
||||||
addOrReplaceIndividualPart(part, -1,1, "meshes\\"+bodypart->mModel);
|
addOrReplaceIndividualPart((ESM::PartReferenceType)part, -1, 1,
|
||||||
|
"meshes\\"+bodypart->mModel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class SetObjectGroup {
|
||||||
|
int mGroup;
|
||||||
|
|
||||||
|
public:
|
||||||
|
SetObjectGroup(int group) : mGroup(group) { }
|
||||||
|
|
||||||
|
void operator()(Ogre::MovableObject *obj) const
|
||||||
|
{
|
||||||
|
obj->getUserObjectBindings().setUserAny(Ogre::Any(mGroup));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
NifOgre::ObjectList NpcAnimation::insertBoundedPart(const std::string &model, int group, const std::string &bonename)
|
NifOgre::ObjectList NpcAnimation::insertBoundedPart(const std::string &model, int group, const std::string &bonename)
|
||||||
{
|
{
|
||||||
NifOgre::ObjectList objects = NifOgre::Loader::createObjects(mSkelBase, bonename, mInsert, model);
|
NifOgre::ObjectList objects = NifOgre::Loader::createObjects(mSkelBase, bonename, mInsert, model);
|
||||||
setRenderProperties(objects, (mViewMode == VM_FirstPerson) ? RV_FirstPerson : mVisibilityFlags, RQG_Main, RQG_Alpha);
|
setRenderProperties(objects, (mViewMode == VM_FirstPerson) ? RV_FirstPerson : mVisibilityFlags, RQG_Main, RQG_Alpha);
|
||||||
|
|
||||||
for(size_t i = 0;i < objects.mEntities.size();i++)
|
std::for_each(objects.mEntities.begin(), objects.mEntities.end(), SetObjectGroup(group));
|
||||||
{
|
std::for_each(objects.mParticles.begin(), objects.mParticles.end(), SetObjectGroup(group));
|
||||||
Ogre::Entity *ent = objects.mEntities[i];
|
|
||||||
ent->getUserObjectBindings().setUserAny(Ogre::Any(group));
|
|
||||||
}
|
|
||||||
for(size_t i = 0;i < objects.mParticles.size();i++)
|
|
||||||
objects.mParticles[i]->getUserObjectBindings().setUserAny(Ogre::Any(group));
|
|
||||||
|
|
||||||
if(objects.mSkelBase)
|
if(objects.mSkelBase)
|
||||||
{
|
{
|
||||||
|
@ -422,7 +447,7 @@ Ogre::Vector3 NpcAnimation::runAnimation(float timepassed)
|
||||||
node->pitch(Ogre::Radian(pitch*0.75f), Ogre::Node::TS_WORLD);
|
node->pitch(Ogre::Radian(pitch*0.75f), Ogre::Node::TS_WORLD);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(size_t i = 0;i < sPartListSize;i++)
|
for(size_t i = 0;i < ESM::PRT_Count;i++)
|
||||||
{
|
{
|
||||||
std::vector<Ogre::Controller<Ogre::Real> >::iterator ctrl(mObjectParts[i].mControllers.begin());
|
std::vector<Ogre::Controller<Ogre::Real> >::iterator ctrl(mObjectParts[i].mControllers.begin());
|
||||||
for(;ctrl != mObjectParts[i].mControllers.end();ctrl++)
|
for(;ctrl != mObjectParts[i].mControllers.end();ctrl++)
|
||||||
|
@ -437,22 +462,15 @@ Ogre::Vector3 NpcAnimation::runAnimation(float timepassed)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NpcAnimation::removeIndividualPart(int type)
|
void NpcAnimation::removeIndividualPart(ESM::PartReferenceType type)
|
||||||
{
|
{
|
||||||
mPartPriorities[type] = 0;
|
mPartPriorities[type] = 0;
|
||||||
mPartslots[type] = -1;
|
mPartslots[type] = -1;
|
||||||
|
|
||||||
for(size_t i = 0;i < sPartListSize;i++)
|
destroyObjectList(mInsert->getCreator(), mObjectParts[type]);
|
||||||
{
|
|
||||||
if(type == sPartList[i].type)
|
|
||||||
{
|
|
||||||
destroyObjectList(mInsert->getCreator(), mObjectParts[i]);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NpcAnimation::reserveIndividualPart(int type, int group, int priority)
|
void NpcAnimation::reserveIndividualPart(ESM::PartReferenceType type, int group, int priority)
|
||||||
{
|
{
|
||||||
if(priority > mPartPriorities[type])
|
if(priority > mPartPriorities[type])
|
||||||
{
|
{
|
||||||
|
@ -464,14 +482,14 @@ void NpcAnimation::reserveIndividualPart(int type, int group, int priority)
|
||||||
|
|
||||||
void NpcAnimation::removePartGroup(int group)
|
void NpcAnimation::removePartGroup(int group)
|
||||||
{
|
{
|
||||||
for(int i = 0; i < 27; i++)
|
for(int i = 0; i < ESM::PRT_Count; i++)
|
||||||
{
|
{
|
||||||
if(mPartslots[i] == group)
|
if(mPartslots[i] == group)
|
||||||
removeIndividualPart(i);
|
removeIndividualPart((ESM::PartReferenceType)i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NpcAnimation::addOrReplaceIndividualPart(int type, int group, int priority, const std::string &mesh)
|
bool NpcAnimation::addOrReplaceIndividualPart(ESM::PartReferenceType type, int group, int priority, const std::string &mesh)
|
||||||
{
|
{
|
||||||
if(priority <= mPartPriorities[type])
|
if(priority <= mPartPriorities[type])
|
||||||
return false;
|
return false;
|
||||||
|
@ -480,27 +498,35 @@ bool NpcAnimation::addOrReplaceIndividualPart(int type, int group, int priority,
|
||||||
mPartslots[type] = group;
|
mPartslots[type] = group;
|
||||||
mPartPriorities[type] = priority;
|
mPartPriorities[type] = priority;
|
||||||
|
|
||||||
for(size_t i = 0;i < sPartListSize;i++)
|
mObjectParts[type] = insertBoundedPart(mesh, group, sPartList.at(type));
|
||||||
|
if(mObjectParts[type].mSkelBase && mObjectParts[type].mSkelBase->isParentTagPoint())
|
||||||
{
|
{
|
||||||
if(type == sPartList[i].type)
|
Ogre::Node *root = mObjectParts[type].mSkelBase->getParentNode();
|
||||||
|
Ogre::SkeletonInstance *skel = mObjectParts[type].mSkelBase->getSkeleton();
|
||||||
|
if(skel->hasBone("BoneOffset"))
|
||||||
{
|
{
|
||||||
mObjectParts[i] = insertBoundedPart(mesh, group, sPartList[i].name);
|
Ogre::Bone *offset = skel->getBone("BoneOffset");
|
||||||
|
root->translate(offset->getPosition());
|
||||||
|
root->rotate(offset->getOrientation());
|
||||||
|
// HACK: Why an extra -90 degree rotation?
|
||||||
|
root->pitch(Ogre::Degree(-90.0f));
|
||||||
|
root->scale(offset->getScale());
|
||||||
|
root->setInitialState();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TODO:
|
// TODO:
|
||||||
// type == ESM::PRT_Head should get an animation source based on the current output of
|
// type == ESM::PRT_Head should get an animation source based on the current output of
|
||||||
// the actor's 'say' sound (0 = silent, 1 = loud?).
|
// the actor's 'say' sound (0 = silent, 1 = loud?).
|
||||||
// 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[i].mControllers.begin());
|
std::vector<Ogre::Controller<Ogre::Real> >::iterator ctrl(mObjectParts[type].mControllers.begin());
|
||||||
for(;ctrl != mObjectParts[i].mControllers.end();ctrl++)
|
for(;ctrl != mObjectParts[type].mControllers.end();ctrl++)
|
||||||
{
|
{
|
||||||
if(ctrl->getSource().isNull())
|
if(ctrl->getSource().isNull())
|
||||||
ctrl->setSource(mNullAnimationValuePtr);
|
ctrl->setSource(mNullAnimationValuePtr);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -542,9 +568,9 @@ void NpcAnimation::addPartGroup(int group, int priority, const std::vector<ESM::
|
||||||
}
|
}
|
||||||
|
|
||||||
if(bodypart)
|
if(bodypart)
|
||||||
addOrReplaceIndividualPart(part->mPart, group, priority, "meshes\\"+bodypart->mModel);
|
addOrReplaceIndividualPart((ESM::PartReferenceType)part->mPart, group, priority, "meshes\\"+bodypart->mModel);
|
||||||
else
|
else
|
||||||
reserveIndividualPart(part->mPart, group, priority);
|
reserveIndividualPart((ESM::PartReferenceType)part->mPart, group, priority);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -557,7 +583,8 @@ void NpcAnimation::showWeapons(bool showWeapon)
|
||||||
mWeapon = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
mWeapon = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
||||||
if(mWeapon != inv.end()) // special case for weapons
|
if(mWeapon != inv.end()) // special case for weapons
|
||||||
{
|
{
|
||||||
std::string mesh = MWWorld::Class::get(*mWeapon).getModel(*mWeapon);
|
MWWorld::Ptr weapon = *mWeapon;
|
||||||
|
std::string mesh = MWWorld::Class::get(weapon).getModel(weapon);
|
||||||
addOrReplaceIndividualPart(ESM::PRT_Weapon, MWWorld::InventoryStore::Slot_CarriedRight, 1, mesh);
|
addOrReplaceIndividualPart(ESM::PRT_Weapon, MWWorld::InventoryStore::Slot_CarriedRight, 1, mesh);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,25 +21,21 @@ namespace MWRender
|
||||||
class NpcAnimation : public Animation
|
class NpcAnimation : public Animation
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
struct PartInfo {
|
typedef std::map<ESM::PartReferenceType,std::string> PartBoneMap;
|
||||||
ESM::PartReferenceType type;
|
|
||||||
const char name[32];
|
|
||||||
};
|
|
||||||
|
|
||||||
enum ViewMode {
|
enum ViewMode {
|
||||||
VM_Normal,
|
VM_Normal,
|
||||||
VM_FirstPerson,
|
VM_FirstPerson,
|
||||||
VM_HeadOnly
|
VM_HeadOnly
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static const size_t sPartListSize = 27;
|
static const PartBoneMap sPartList;
|
||||||
static const PartInfo sPartList[sPartListSize];
|
|
||||||
|
|
||||||
int mStateID;
|
int mStateID;
|
||||||
|
|
||||||
// Bounded Parts
|
// Bounded Parts
|
||||||
NifOgre::ObjectList mObjectParts[sPartListSize];
|
NifOgre::ObjectList mObjectParts[ESM::PRT_Count];
|
||||||
|
|
||||||
const ESM::NPC *mNpc;
|
const ESM::NPC *mNpc;
|
||||||
std::string mHeadModel;
|
std::string mHeadModel;
|
||||||
|
@ -66,17 +62,17 @@ private:
|
||||||
|
|
||||||
int mVisibilityFlags;
|
int mVisibilityFlags;
|
||||||
|
|
||||||
int mPartslots[sPartListSize]; //Each part slot is taken by clothing, armor, or is empty
|
int mPartslots[ESM::PRT_Count]; //Each part slot is taken by clothing, armor, or is empty
|
||||||
int mPartPriorities[sPartListSize];
|
int mPartPriorities[ESM::PRT_Count];
|
||||||
|
|
||||||
NifOgre::ObjectList insertBoundedPart(const std::string &model, int group, const std::string &bonename);
|
NifOgre::ObjectList insertBoundedPart(const std::string &model, int group, const std::string &bonename);
|
||||||
|
|
||||||
void updateParts(bool forceupdate = false);
|
void updateParts(bool forceupdate = false);
|
||||||
|
|
||||||
void removeIndividualPart(int type);
|
void removeIndividualPart(ESM::PartReferenceType type);
|
||||||
void reserveIndividualPart(int type, int group, int priority);
|
void reserveIndividualPart(ESM::PartReferenceType type, int group, int priority);
|
||||||
|
|
||||||
bool addOrReplaceIndividualPart(int type, int group, int priority, const std::string &mesh);
|
bool addOrReplaceIndividualPart(ESM::PartReferenceType type, int group, int priority, const std::string &mesh);
|
||||||
void removePartGroup(int group);
|
void removePartGroup(int group);
|
||||||
void addPartGroup(int group, int priority, const std::vector<ESM::PartReference> &parts);
|
void addPartGroup(int group, int priority, const std::vector<ESM::PartReference> &parts);
|
||||||
|
|
||||||
|
|
|
@ -18,64 +18,12 @@
|
||||||
#include "../mwworld/class.hpp"
|
#include "../mwworld/class.hpp"
|
||||||
|
|
||||||
#include "renderconst.hpp"
|
#include "renderconst.hpp"
|
||||||
|
#include "animation.hpp"
|
||||||
|
|
||||||
using namespace MWRender;
|
using namespace MWRender;
|
||||||
float Objects::lightLinearValue()
|
|
||||||
{
|
|
||||||
return mFallback->getFallbackFloat("LightAttenuation_LinearValue");
|
|
||||||
}
|
|
||||||
float Objects::lightLinearRadiusMult()
|
|
||||||
{
|
|
||||||
return mFallback->getFallbackFloat("LightAttenuation_LinearRadiusMult");
|
|
||||||
}
|
|
||||||
float Objects::lightQuadraticValue()
|
|
||||||
{
|
|
||||||
return mFallback->getFallbackFloat("LightAttenuation_QuadraticValue");
|
|
||||||
}
|
|
||||||
float Objects::lightQuadraticRadiusMult()
|
|
||||||
{
|
|
||||||
return mFallback->getFallbackFloat("LightAttenuation_QuadraticRadiusMult");
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Objects::lightOutQuadInLin()
|
|
||||||
{
|
|
||||||
return mFallback->getFallbackBool("LightAttenuation_OutQuadInLin");
|
|
||||||
}
|
|
||||||
bool Objects::lightQuadratic()
|
|
||||||
{
|
|
||||||
return mFallback->getFallbackBool("LightAttenuation_UseQuadratic");
|
|
||||||
}
|
|
||||||
|
|
||||||
int Objects::uniqueID = 0;
|
int Objects::uniqueID = 0;
|
||||||
|
|
||||||
void Objects::clearSceneNode (Ogre::SceneNode *node)
|
|
||||||
{
|
|
||||||
for (int i=node->numAttachedObjects()-1; i>=0; --i)
|
|
||||||
{
|
|
||||||
Ogre::MovableObject *object = node->getAttachedObject (i);
|
|
||||||
|
|
||||||
// for entities, destroy any objects attached to bones
|
|
||||||
if (object->getTypeFlags () == Ogre::SceneManager::ENTITY_TYPE_MASK)
|
|
||||||
{
|
|
||||||
Ogre::Entity* ent = static_cast<Ogre::Entity*>(object);
|
|
||||||
Ogre::Entity::ChildObjectListIterator children = ent->getAttachedObjectIterator ();
|
|
||||||
while (children.hasMoreElements())
|
|
||||||
{
|
|
||||||
mRenderer.getScene ()->destroyMovableObject (children.getNext ());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
node->detachObject (object);
|
|
||||||
mRenderer.getScene()->destroyMovableObject (object);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ogre::Node::ChildNodeIterator it = node->getChildIterator ();
|
|
||||||
while (it.hasMoreElements ())
|
|
||||||
{
|
|
||||||
clearSceneNode(static_cast<Ogre::SceneNode*>(it.getNext ()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Objects::setRootNode(Ogre::SceneNode* root)
|
void Objects::setRootNode(Ogre::SceneNode* root)
|
||||||
{
|
{
|
||||||
mRootNode = root;
|
mRootNode = root;
|
||||||
|
@ -124,73 +72,41 @@ void Objects::insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_)
|
||||||
mIsStatic = static_;
|
mIsStatic = static_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh, bool light)
|
void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh)
|
||||||
{
|
{
|
||||||
Ogre::SceneNode* insert = ptr.getRefData().getBaseNode();
|
Ogre::SceneNode* insert = ptr.getRefData().getBaseNode();
|
||||||
assert(insert);
|
assert(insert);
|
||||||
|
|
||||||
Ogre::AxisAlignedBox bounds = Ogre::AxisAlignedBox::BOX_NULL;
|
std::auto_ptr<ObjectAnimation> anim(new ObjectAnimation(ptr, mesh, mIsStatic));
|
||||||
NifOgre::ObjectList objects = NifOgre::Loader::createObjects(insert, mesh);
|
|
||||||
for(size_t i = 0;i < objects.mEntities.size();i++)
|
|
||||||
bounds.merge(objects.mEntities[i]->getWorldBoundingBox(true));
|
|
||||||
|
|
||||||
|
Ogre::AxisAlignedBox bounds = anim->getWorldBounds();
|
||||||
Ogre::Vector3 extents = bounds.getSize();
|
Ogre::Vector3 extents = bounds.getSize();
|
||||||
extents *= insert->getScale();
|
extents *= insert->getScale();
|
||||||
float size = std::max(std::max(extents.x, extents.y), extents.z);
|
float size = std::max(std::max(extents.x, extents.y), extents.z);
|
||||||
|
|
||||||
bool small = (size < Settings::Manager::getInt("small object size", "Viewing distance")) && Settings::Manager::getBool("limit small object distance", "Viewing distance");
|
bool small = (size < Settings::Manager::getInt("small object size", "Viewing distance")) &&
|
||||||
|
Settings::Manager::getBool("limit small object distance", "Viewing distance");
|
||||||
// do not fade out doors. that will cause holes and look stupid
|
// do not fade out doors. that will cause holes and look stupid
|
||||||
if (ptr.getTypeName().find("Door") != std::string::npos)
|
if(ptr.getTypeName().find("Door") != std::string::npos)
|
||||||
small = false;
|
small = false;
|
||||||
|
|
||||||
if (mBounds.find(ptr.getCell()) == mBounds.end())
|
if (mBounds.find(ptr.getCell()) == mBounds.end())
|
||||||
mBounds[ptr.getCell()] = Ogre::AxisAlignedBox::BOX_NULL;
|
mBounds[ptr.getCell()] = Ogre::AxisAlignedBox::BOX_NULL;
|
||||||
mBounds[ptr.getCell()].merge(bounds);
|
mBounds[ptr.getCell()].merge(bounds);
|
||||||
|
|
||||||
bool anyTransparency = false;
|
if(ptr.getTypeName() == typeid(ESM::Light).name())
|
||||||
for(size_t i = 0;!anyTransparency && i < objects.mEntities.size();i++)
|
anim->addLight(ptr.get<ESM::Light>()->mBase);
|
||||||
{
|
|
||||||
Ogre::Entity *ent = objects.mEntities[i];
|
|
||||||
for(unsigned int i=0;!anyTransparency && i < ent->getNumSubEntities(); ++i)
|
|
||||||
{
|
|
||||||
anyTransparency = ent->getSubEntity(i)->getMaterial()->isTransparent();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!mIsStatic || !Settings::Manager::getBool("use static geometry", "Objects") ||
|
if(mIsStatic && Settings::Manager::getBool("use static geometry", "Objects") && anim->canBatch())
|
||||||
anyTransparency || !objects.mParticles.empty())
|
|
||||||
{
|
|
||||||
for(size_t i = 0;i < objects.mEntities.size();i++)
|
|
||||||
{
|
|
||||||
Ogre::Entity *ent = objects.mEntities[i];
|
|
||||||
for(unsigned int i=0; i < ent->getNumSubEntities(); ++i)
|
|
||||||
{
|
|
||||||
Ogre::SubEntity* subEnt = ent->getSubEntity(i);
|
|
||||||
subEnt->setRenderQueueGroup(subEnt->getMaterial()->isTransparent() ? RQG_Alpha : RQG_Main);
|
|
||||||
}
|
|
||||||
ent->setRenderingDistance(small ? Settings::Manager::getInt("small object distance", "Viewing distance") : 0);
|
|
||||||
ent->setVisibilityFlags(mIsStatic ? (small ? RV_StaticsSmall : RV_Statics) : RV_Misc);
|
|
||||||
}
|
|
||||||
for(size_t i = 0;i < objects.mParticles.size();i++)
|
|
||||||
{
|
|
||||||
Ogre::ParticleSystem *part = objects.mParticles[i];
|
|
||||||
// TODO: Check the particle system's material for actual transparency
|
|
||||||
part->setRenderQueueGroup(RQG_Alpha);
|
|
||||||
part->setRenderingDistance(small ? Settings::Manager::getInt("small object distance", "Viewing distance") : 0);
|
|
||||||
part->setVisibilityFlags(mIsStatic ? (small ? RV_StaticsSmall : RV_Statics) : RV_Misc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
Ogre::StaticGeometry* sg = 0;
|
Ogre::StaticGeometry* sg = 0;
|
||||||
|
|
||||||
if (small)
|
if (small)
|
||||||
{
|
{
|
||||||
if( mStaticGeometrySmall.find(ptr.getCell()) == mStaticGeometrySmall.end())
|
if(mStaticGeometrySmall.find(ptr.getCell()) == mStaticGeometrySmall.end())
|
||||||
{
|
{
|
||||||
uniqueID = uniqueID +1;
|
uniqueID = uniqueID+1;
|
||||||
sg = mRenderer.getScene()->createStaticGeometry( "sg" + Ogre::StringConverter::toString(uniqueID));
|
sg = mRenderer.getScene()->createStaticGeometry("sg" + Ogre::StringConverter::toString(uniqueID));
|
||||||
mStaticGeometrySmall[ptr.getCell()] = sg;
|
mStaticGeometrySmall[ptr.getCell()] = sg;
|
||||||
|
|
||||||
sg->setRenderingDistance(Settings::Manager::getInt("small object distance", "Viewing distance"));
|
sg->setRenderingDistance(Settings::Manager::getInt("small object distance", "Viewing distance"));
|
||||||
|
@ -200,11 +116,10 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh, bool
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if( mStaticGeometry.find(ptr.getCell()) == mStaticGeometry.end())
|
if(mStaticGeometry.find(ptr.getCell()) == mStaticGeometry.end())
|
||||||
{
|
{
|
||||||
|
uniqueID = uniqueID+1;
|
||||||
uniqueID = uniqueID +1;
|
sg = mRenderer.getScene()->createStaticGeometry("sg" + Ogre::StringConverter::toString(uniqueID));
|
||||||
sg = mRenderer.getScene()->createStaticGeometry( "sg" + Ogre::StringConverter::toString(uniqueID));
|
|
||||||
mStaticGeometry[ptr.getCell()] = sg;
|
mStaticGeometry[ptr.getCell()] = sg;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -225,155 +140,75 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh, bool
|
||||||
|
|
||||||
sg->setRenderQueueGroup(RQG_Main);
|
sg->setRenderQueueGroup(RQG_Main);
|
||||||
|
|
||||||
std::vector<Ogre::Entity*>::reverse_iterator iter = objects.mEntities.rbegin();
|
anim->fillBatch(sg);
|
||||||
while(iter != objects.mEntities.rend())
|
/* TODO: We could hold on to this and just detach it from the scene graph, so if the Ptr
|
||||||
{
|
* ever needs to modify we can reattach it and rebuild the StaticGeometry object without
|
||||||
Ogre::Node *node = (*iter)->getParentNode();
|
* it. Would require associating the Ptr with the StaticGeometry. */
|
||||||
sg->addEntity(*iter, node->_getDerivedPosition(), node->_getDerivedOrientation(), node->_getDerivedScale());
|
anim.reset();
|
||||||
|
|
||||||
(*iter)->detachFromParent();
|
|
||||||
mRenderer.getScene()->destroyEntity(*iter);
|
|
||||||
++iter;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (light)
|
if(anim.get() != NULL)
|
||||||
{
|
mObjects.insert(std::make_pair(ptr, anim.release()));
|
||||||
insertLight(ptr, objects.mSkelBase, bounds.getCenter() - insert->_getDerivedPosition());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Objects::insertLight (const MWWorld::Ptr& ptr, Ogre::Entity* skelBase, Ogre::Vector3 fallbackCenter)
|
|
||||||
{
|
|
||||||
Ogre::SceneNode* insert = mRenderer.getScene()->getSceneNode(ptr.getRefData().getHandle());
|
|
||||||
assert(insert);
|
|
||||||
|
|
||||||
MWWorld::LiveCellRef<ESM::Light> *ref = ptr.get<ESM::Light>();
|
|
||||||
|
|
||||||
const int color = ref->mBase->mData.mColor;
|
|
||||||
const float r = ((color >> 0) & 0xFF) / 255.0f;
|
|
||||||
const float g = ((color >> 8) & 0xFF) / 255.0f;
|
|
||||||
const float b = ((color >> 16) & 0xFF) / 255.0f;
|
|
||||||
const float radius = float (ref->mBase->mData.mRadius);
|
|
||||||
|
|
||||||
Ogre::Light *light = mRenderer.getScene()->createLight();
|
|
||||||
light->setDiffuseColour (r, g, b);
|
|
||||||
|
|
||||||
LightInfo info;
|
|
||||||
info.name = light->getName();
|
|
||||||
info.radius = radius;
|
|
||||||
info.colour = Ogre::ColourValue(r, g, b);
|
|
||||||
|
|
||||||
if (ref->mBase->mData.mFlags & ESM::Light::Negative)
|
|
||||||
info.colour *= -1;
|
|
||||||
|
|
||||||
info.interior = !ptr.getCell()->mCell->isExterior();
|
|
||||||
|
|
||||||
if (ref->mBase->mData.mFlags & ESM::Light::Flicker)
|
|
||||||
info.type = LT_Flicker;
|
|
||||||
else if (ref->mBase->mData.mFlags & ESM::Light::FlickerSlow)
|
|
||||||
info.type = LT_FlickerSlow;
|
|
||||||
else if (ref->mBase->mData.mFlags & ESM::Light::Pulse)
|
|
||||||
info.type = LT_Pulse;
|
|
||||||
else if (ref->mBase->mData.mFlags & ESM::Light::PulseSlow)
|
|
||||||
info.type = LT_PulseSlow;
|
|
||||||
else
|
|
||||||
info.type = LT_Normal;
|
|
||||||
|
|
||||||
// randomize lights animations
|
|
||||||
info.time = Ogre::Math::RangeRandom(-500, +500);
|
|
||||||
info.phase = Ogre::Math::RangeRandom(-500, +500);
|
|
||||||
|
|
||||||
bool quadratic = lightOutQuadInLin() ? !info.interior : lightQuadratic();
|
|
||||||
|
|
||||||
// with the standard 1 / (c + d*l + d*d*q) equation the attenuation factor never becomes zero,
|
|
||||||
// so we ignore lights if their attenuation falls below this factor.
|
|
||||||
const float threshold = 0.03;
|
|
||||||
|
|
||||||
if (!quadratic)
|
|
||||||
{
|
|
||||||
float r = radius * lightLinearRadiusMult();
|
|
||||||
float attenuation = lightLinearValue() / r;
|
|
||||||
float activationRange = 1 / (threshold * attenuation);
|
|
||||||
light->setAttenuation(activationRange, 0, attenuation, 0);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
float r = radius * lightQuadraticRadiusMult();
|
|
||||||
float attenuation = lightQuadraticValue() / std::pow(r, 2);
|
|
||||||
float activationRange = std::sqrt(1 / (threshold * attenuation));
|
|
||||||
light->setAttenuation(activationRange, 0, 0, attenuation);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If there's an AttachLight bone, attach the light to that, otherwise attach it to the base scene node
|
|
||||||
if (skelBase && skelBase->getSkeleton ()->hasBone ("AttachLight"))
|
|
||||||
{
|
|
||||||
skelBase->attachObjectToBone ("AttachLight", light);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Ogre::SceneNode* childNode = insert->createChildSceneNode (fallbackCenter);
|
|
||||||
childNode->attachObject(light);
|
|
||||||
}
|
|
||||||
|
|
||||||
mLights.push_back(info);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Objects::deleteObject (const MWWorld::Ptr& ptr)
|
bool Objects::deleteObject (const MWWorld::Ptr& ptr)
|
||||||
{
|
{
|
||||||
if (Ogre::SceneNode *base = ptr.getRefData().getBaseNode())
|
if(!ptr.getRefData().getBaseNode())
|
||||||
{
|
return true;
|
||||||
Ogre::SceneNode *parent = base->getParentSceneNode();
|
|
||||||
|
|
||||||
for (std::map<MWWorld::Ptr::CellStore *, Ogre::SceneNode *>::const_iterator iter (
|
PtrAnimationMap::iterator iter = mObjects.find(ptr);
|
||||||
mCellSceneNodes.begin()); iter!=mCellSceneNodes.end(); ++iter)
|
if(iter != mObjects.end())
|
||||||
if (iter->second==parent)
|
|
||||||
{
|
{
|
||||||
clearSceneNode (base);
|
delete iter->second;
|
||||||
base->removeAndDestroyAllChildren();
|
mObjects.erase(iter);
|
||||||
mRenderer.getScene()->destroySceneNode (base);
|
|
||||||
ptr.getRefData().setBaseNode (0);
|
mRenderer.getScene()->destroySceneNode(ptr.getRefData().getBaseNode());
|
||||||
|
ptr.getRefData().setBaseNode(0);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Objects::removeCell(MWWorld::Ptr::CellStore* store)
|
void Objects::removeCell(MWWorld::Ptr::CellStore* store)
|
||||||
{
|
{
|
||||||
if(mCellSceneNodes.find(store) != mCellSceneNodes.end())
|
for(PtrAnimationMap::iterator iter = mObjects.begin();iter != mObjects.end();)
|
||||||
{
|
{
|
||||||
Ogre::SceneNode* base = mCellSceneNodes[store];
|
if(iter->first.getCell() == store)
|
||||||
|
{
|
||||||
for (int i=0; i<base->numChildren(); ++i)
|
delete iter->second;
|
||||||
clearSceneNode (static_cast<Ogre::SceneNode *> (base->getChild (i)));
|
mObjects.erase(iter++);
|
||||||
|
}
|
||||||
base->removeAndDestroyAllChildren();
|
else
|
||||||
mCellSceneNodes.erase(store);
|
++iter;
|
||||||
mRenderer.getScene()->destroySceneNode(base);
|
|
||||||
base = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(mStaticGeometry.find(store) != mStaticGeometry.end())
|
std::map<MWWorld::CellStore*,Ogre::StaticGeometry*>::iterator geom = mStaticGeometry.find(store);
|
||||||
|
if(geom != mStaticGeometry.end())
|
||||||
{
|
{
|
||||||
Ogre::StaticGeometry* sg = mStaticGeometry[store];
|
Ogre::StaticGeometry *sg = geom->second;
|
||||||
mStaticGeometry.erase(store);
|
mStaticGeometry.erase(geom);
|
||||||
mRenderer.getScene()->destroyStaticGeometry (sg);
|
mRenderer.getScene()->destroyStaticGeometry(sg);
|
||||||
sg = 0;
|
|
||||||
}
|
}
|
||||||
if(mStaticGeometrySmall.find(store) != mStaticGeometrySmall.end())
|
|
||||||
|
geom = mStaticGeometrySmall.find(store);
|
||||||
|
if(geom != mStaticGeometrySmall.end())
|
||||||
{
|
{
|
||||||
Ogre::StaticGeometry* sg = mStaticGeometrySmall[store];
|
Ogre::StaticGeometry *sg = geom->second;
|
||||||
mStaticGeometrySmall.erase(store);
|
mStaticGeometrySmall.erase(store);
|
||||||
mRenderer.getScene()->destroyStaticGeometry (sg);
|
mRenderer.getScene()->destroyStaticGeometry(sg);
|
||||||
sg = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(mBounds.find(store) != mBounds.end())
|
|
||||||
mBounds.erase(store);
|
mBounds.erase(store);
|
||||||
|
|
||||||
|
std::map<MWWorld::CellStore*,Ogre::SceneNode*>::iterator cell = mCellSceneNodes.find(store);
|
||||||
|
if(cell != mCellSceneNodes.end())
|
||||||
|
{
|
||||||
|
cell->second->removeAndDestroyAllChildren();
|
||||||
|
mRenderer.getScene()->destroySceneNode(cell->second);
|
||||||
|
mCellSceneNodes.erase(cell);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Objects::buildStaticGeometry(MWWorld::Ptr::CellStore& cell)
|
void Objects::buildStaticGeometry(MWWorld::Ptr::CellStore& cell)
|
||||||
|
@ -397,146 +232,23 @@ Ogre::AxisAlignedBox Objects::getDimensions(MWWorld::Ptr::CellStore* cell)
|
||||||
|
|
||||||
void Objects::enableLights()
|
void Objects::enableLights()
|
||||||
{
|
{
|
||||||
std::vector<LightInfo>::iterator it = mLights.begin();
|
PtrAnimationMap::const_iterator it = mObjects.begin();
|
||||||
while (it != mLights.end())
|
for(;it != mObjects.end();it++)
|
||||||
{
|
it->second->enableLights(true);
|
||||||
if (mRootNode->getCreator()->hasLight(it->name))
|
|
||||||
{
|
|
||||||
mRootNode->getCreator()->getLight(it->name)->setVisible(true);
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
it = mLights.erase(it);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Objects::disableLights()
|
void Objects::disableLights()
|
||||||
{
|
{
|
||||||
std::vector<LightInfo>::iterator it = mLights.begin();
|
PtrAnimationMap::const_iterator it = mObjects.begin();
|
||||||
while (it != mLights.end())
|
for(;it != mObjects.end();it++)
|
||||||
{
|
it->second->enableLights(false);
|
||||||
if (mRootNode->getCreator()->hasLight(it->name))
|
|
||||||
{
|
|
||||||
mRootNode->getCreator()->getLight(it->name)->setVisible(false);
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
it = mLights.erase(it);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace MWRender
|
|
||||||
{
|
|
||||||
namespace Pulse
|
|
||||||
{
|
|
||||||
static float amplitude (float phase)
|
|
||||||
{
|
|
||||||
return sin (phase);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace Flicker
|
|
||||||
{
|
|
||||||
static const float fa = 0.785398f;
|
|
||||||
static const float fb = 1.17024f;
|
|
||||||
|
|
||||||
static const float tdo = 0.94f;
|
|
||||||
static const float tdm = 2.48f;
|
|
||||||
|
|
||||||
static const float f [3] = { 1.5708f, 4.18774f, 5.19934f };
|
|
||||||
static const float o [3] = { 0.804248f, 2.11115f, 3.46832f };
|
|
||||||
static const float m [3] = { 1.0f, 0.785f, 0.876f };
|
|
||||||
static const float s = 0.394f;
|
|
||||||
|
|
||||||
static const float phase_wavelength = 120.0f * 3.14159265359f / fa;
|
|
||||||
|
|
||||||
static float frequency (float x)
|
|
||||||
{
|
|
||||||
return tdo + tdm * sin (fa * x);
|
|
||||||
}
|
|
||||||
|
|
||||||
static float amplitude (float x)
|
|
||||||
{
|
|
||||||
float v = 0.0f;
|
|
||||||
for (int i = 0; i < 3; ++i)
|
|
||||||
v += sin (fb*x*f[i] + o[1])*m[i];
|
|
||||||
return v * s;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Objects::update(const float dt)
|
void Objects::update(const float dt)
|
||||||
{
|
{
|
||||||
std::vector<LightInfo>::iterator it = mLights.begin();
|
PtrAnimationMap::const_iterator it = mObjects.begin();
|
||||||
while (it != mLights.end())
|
for(;it != mObjects.end();it++)
|
||||||
{
|
it->second->runAnimation(dt);
|
||||||
if (mRootNode->getCreator()->hasLight(it->name))
|
|
||||||
{
|
|
||||||
Ogre::Light* light = mRootNode->getCreator()->getLight(it->name);
|
|
||||||
|
|
||||||
float brightness;
|
|
||||||
float cycle_time;
|
|
||||||
float time_distortion;
|
|
||||||
|
|
||||||
if ((it->type == LT_Pulse) && (it->type == LT_PulseSlow))
|
|
||||||
{
|
|
||||||
cycle_time = 2 * Ogre::Math::PI;
|
|
||||||
time_distortion = 20.0f;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
cycle_time = 500.0f;
|
|
||||||
it->phase = fmod (it->phase + dt, Flicker::phase_wavelength);
|
|
||||||
time_distortion = Flicker::frequency (it->phase);
|
|
||||||
}
|
|
||||||
|
|
||||||
it->time += it->dir*dt*time_distortion;
|
|
||||||
if (it->dir > 0 && it->time > +cycle_time)
|
|
||||||
{
|
|
||||||
it->dir = -1.0f;
|
|
||||||
it->time = +2*cycle_time - it->time;
|
|
||||||
}
|
|
||||||
if (it->dir < 0 && it->time < -cycle_time)
|
|
||||||
{
|
|
||||||
it->dir = +1.0f;
|
|
||||||
it->time = -2*cycle_time - it->time;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const float fast = 4.0f/1.0f;
|
|
||||||
static const float slow = 1.0f/1.0f;
|
|
||||||
|
|
||||||
// These formulas are just guesswork, but they work pretty well
|
|
||||||
if (it->type == LT_Normal)
|
|
||||||
{
|
|
||||||
// Less than 1/255 light modifier for a constant light:
|
|
||||||
brightness = (const float)(1.0 + Flicker::amplitude(it->time*slow) / 255.0 );
|
|
||||||
}
|
|
||||||
else if (it->type == LT_Flicker)
|
|
||||||
{
|
|
||||||
brightness = (const float)(0.75 + Flicker::amplitude(it->time*fast) * 0.25);
|
|
||||||
}
|
|
||||||
else if (it->type == LT_FlickerSlow)
|
|
||||||
{
|
|
||||||
brightness = (const float)(0.75 + Flicker::amplitude(it->time*slow) * 0.25);
|
|
||||||
}
|
|
||||||
else if (it->type == LT_Pulse)
|
|
||||||
{
|
|
||||||
brightness = (const float)(1.0 + Pulse::amplitude (it->time*fast) * 0.25);
|
|
||||||
}
|
|
||||||
else if (it->type == LT_PulseSlow)
|
|
||||||
{
|
|
||||||
brightness = (const float)(1.0 + Pulse::amplitude (it->time*slow) * 0.25);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
assert(0 && "Invalid light type");
|
|
||||||
|
|
||||||
light->setDiffuseColour(it->colour * brightness);
|
|
||||||
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
it = mLights.erase(it);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Objects::rebuildStaticGeometry()
|
void Objects::rebuildStaticGeometry()
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
#include <OgreAxisAlignedBox.h>
|
#include <OgreAxisAlignedBox.h>
|
||||||
|
|
||||||
#include <openengine/ogre/renderer.hpp>
|
#include <openengine/ogre/renderer.hpp>
|
||||||
#include "../mwworld/fallback.hpp"
|
|
||||||
|
|
||||||
namespace MWWorld
|
namespace MWWorld
|
||||||
{
|
{
|
||||||
|
@ -15,72 +14,32 @@ namespace MWWorld
|
||||||
|
|
||||||
namespace MWRender{
|
namespace MWRender{
|
||||||
|
|
||||||
/// information about light needed for rendering
|
class ObjectAnimation;
|
||||||
enum LightType
|
|
||||||
{
|
|
||||||
// These are all mutually exclusive
|
|
||||||
LT_Normal=0,
|
|
||||||
LT_Flicker=1,
|
|
||||||
LT_FlickerSlow=2,
|
|
||||||
LT_Pulse=3,
|
|
||||||
LT_PulseSlow=4
|
|
||||||
};
|
|
||||||
|
|
||||||
struct LightInfo
|
|
||||||
{
|
|
||||||
// Constants
|
|
||||||
std::string name; // ogre handle
|
|
||||||
Ogre::ColourValue colour;
|
|
||||||
float radius;
|
|
||||||
bool interior; // Does this light belong to an interior or exterior cell
|
|
||||||
LightType type;
|
|
||||||
|
|
||||||
// Runtime variables
|
|
||||||
float dir; // direction time is running...
|
|
||||||
float time; // current time
|
|
||||||
float phase; // current phase
|
|
||||||
|
|
||||||
LightInfo() :
|
|
||||||
dir(1.0f), time(0.0f), phase (0.0f),
|
|
||||||
interior(true), type(LT_Normal), radius(1.0)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class Objects{
|
class Objects{
|
||||||
|
typedef std::map<MWWorld::Ptr,ObjectAnimation*> PtrAnimationMap;
|
||||||
|
|
||||||
OEngine::Render::OgreRenderer &mRenderer;
|
OEngine::Render::OgreRenderer &mRenderer;
|
||||||
std::map<MWWorld::CellStore *, Ogre::SceneNode *> mCellSceneNodes;
|
|
||||||
std::map<MWWorld::CellStore *, Ogre::StaticGeometry*> mStaticGeometry;
|
std::map<MWWorld::CellStore*,Ogre::SceneNode*> mCellSceneNodes;
|
||||||
std::map<MWWorld::CellStore *, Ogre::StaticGeometry*> mStaticGeometrySmall;
|
std::map<MWWorld::CellStore*,Ogre::StaticGeometry*> mStaticGeometry;
|
||||||
std::map<MWWorld::CellStore *, Ogre::AxisAlignedBox> mBounds;
|
std::map<MWWorld::CellStore*,Ogre::StaticGeometry*> mStaticGeometrySmall;
|
||||||
std::vector<LightInfo> mLights;
|
std::map<MWWorld::CellStore*,Ogre::AxisAlignedBox> mBounds;
|
||||||
|
PtrAnimationMap mObjects;
|
||||||
|
|
||||||
Ogre::SceneNode* mRootNode;
|
Ogre::SceneNode* mRootNode;
|
||||||
bool mIsStatic;
|
bool mIsStatic;
|
||||||
static int uniqueID;
|
static int uniqueID;
|
||||||
MWWorld::Fallback* mFallback;
|
|
||||||
float lightLinearValue();
|
|
||||||
float lightLinearRadiusMult();
|
|
||||||
|
|
||||||
bool lightQuadratic();
|
|
||||||
float lightQuadraticValue();
|
|
||||||
float lightQuadraticRadiusMult();
|
|
||||||
|
|
||||||
bool lightOutQuadInLin();
|
|
||||||
|
|
||||||
void clearSceneNode (Ogre::SceneNode *node);
|
|
||||||
///< Remove all movable objects from \a node.
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Objects(OEngine::Render::OgreRenderer& renderer, MWWorld::Fallback* fallback)
|
Objects(OEngine::Render::OgreRenderer &renderer)
|
||||||
: mRenderer (renderer)
|
: mRenderer(renderer)
|
||||||
, mIsStatic(false)
|
, mIsStatic(false)
|
||||||
, mFallback(fallback)
|
|
||||||
, mRootNode(NULL)
|
, mRootNode(NULL)
|
||||||
{}
|
{}
|
||||||
~Objects(){}
|
~Objects(){}
|
||||||
void insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_);
|
void insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_);
|
||||||
void insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh, bool light=false);
|
void insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh);
|
||||||
void insertLight (const MWWorld::Ptr& ptr, Ogre::Entity *skelBase=0, Ogre::Vector3 fallbackCenter=Ogre::Vector3(0.0f));
|
|
||||||
|
|
||||||
void enableLights();
|
void enableLights();
|
||||||
void disableLights();
|
void disableLights();
|
||||||
|
|
|
@ -57,7 +57,7 @@ RenderingManager::RenderingManager(OEngine::Render::OgreRenderer& _rend, const b
|
||||||
MWWorld::Fallback* fallback)
|
MWWorld::Fallback* fallback)
|
||||||
: mRendering(_rend)
|
: mRendering(_rend)
|
||||||
, mFallback(fallback)
|
, mFallback(fallback)
|
||||||
, mObjects(mRendering, mFallback)
|
, mObjects(mRendering)
|
||||||
, mActors(mRendering, this)
|
, mActors(mRendering, this)
|
||||||
, mPlayerAnimation(NULL)
|
, mPlayerAnimation(NULL)
|
||||||
, mAmbientMode(0)
|
, mAmbientMode(0)
|
||||||
|
|
|
@ -11,10 +11,6 @@
|
||||||
|
|
||||||
#include "../mwmechanics/movement.hpp"
|
#include "../mwmechanics/movement.hpp"
|
||||||
#include "../mwmechanics/npcstats.hpp"
|
#include "../mwmechanics/npcstats.hpp"
|
||||||
#include "../mwmechanics/character.hpp"
|
|
||||||
#include "../mwmechanics/security.hpp"
|
|
||||||
|
|
||||||
#include "../mwrender/animation.hpp"
|
|
||||||
|
|
||||||
#include "class.hpp"
|
#include "class.hpp"
|
||||||
|
|
||||||
|
@ -144,51 +140,6 @@ namespace MWWorld
|
||||||
MWWorld::Class::get(ptr).getMovementSettings(ptr).mRotation[1] += roll;
|
MWWorld::Class::get(ptr).getMovementSettings(ptr).mRotation[1] += roll;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Player::use()
|
|
||||||
{
|
|
||||||
MWWorld::InventoryStore& store = MWWorld::Class::get(getPlayer()).getInventoryStore(getPlayer());
|
|
||||||
MWWorld::ContainerStoreIterator equipped = store.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
|
||||||
|
|
||||||
if (getDrawState() == MWMechanics::DrawState_Weapon)
|
|
||||||
{
|
|
||||||
if (equipped != store.end())
|
|
||||||
{
|
|
||||||
MWWorld::Ptr item = *equipped;
|
|
||||||
MWRender::Animation* anim = MWBase::Environment::get().getWorld()->getAnimation(getPlayer());
|
|
||||||
MWWorld::Ptr target = MWBase::Environment::get().getWorld()->getFacedObject();
|
|
||||||
|
|
||||||
if (anim->isPriorityActive(MWMechanics::Priority_Weapon))
|
|
||||||
return;
|
|
||||||
|
|
||||||
std::string resultMessage, resultSound;
|
|
||||||
|
|
||||||
if (item.getTypeName() == typeid(ESM::Lockpick).name())
|
|
||||||
{
|
|
||||||
if (!target.isEmpty())
|
|
||||||
MWMechanics::Security(getPlayer()).pickLock(target, item, resultMessage, resultSound);
|
|
||||||
anim->play("pickprobe", MWMechanics::Priority_Weapon, MWRender::Animation::Group_UpperBody, true, 1.0f, "start", "stop", 0.0, 0);
|
|
||||||
}
|
|
||||||
else if (item.getTypeName() == typeid(ESM::Probe).name())
|
|
||||||
{
|
|
||||||
if (!target.isEmpty())
|
|
||||||
MWMechanics::Security(getPlayer()).probeTrap(target, item, resultMessage, resultSound);
|
|
||||||
anim->play("pickprobe", MWMechanics::Priority_Weapon, MWRender::Animation::Group_UpperBody, true, 1.0f, "start", "stop", 0.0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!resultMessage.empty())
|
|
||||||
MWBase::Environment::get().getWindowManager()->messageBox(resultMessage);
|
|
||||||
if (!resultSound.empty())
|
|
||||||
MWBase::Environment::get().getSoundManager()->playSound(resultSound,1,1);
|
|
||||||
|
|
||||||
// tool used up?
|
|
||||||
if (!item.getRefData().getCount())
|
|
||||||
MWBase::Environment::get().getWindowManager()->unsetSelectedWeapon();
|
|
||||||
else
|
|
||||||
MWBase::Environment::get().getWindowManager()->setSelectedWeapon(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MWMechanics::DrawState_ Player::getDrawState()
|
MWMechanics::DrawState_ Player::getDrawState()
|
||||||
{
|
{
|
||||||
MWWorld::Ptr ptr = getPlayer();
|
MWWorld::Ptr ptr = getPlayer();
|
||||||
|
|
|
@ -58,9 +58,6 @@ namespace MWWorld
|
||||||
void setForwardBackward (int value);
|
void setForwardBackward (int value);
|
||||||
void setUpDown(int value);
|
void setUpDown(int value);
|
||||||
|
|
||||||
void use ();
|
|
||||||
///< Use item equipped on right hand, or fists
|
|
||||||
|
|
||||||
void setRunState(bool run);
|
void setRunState(bool run);
|
||||||
void setSneak(bool sneak);
|
void setSneak(bool sneak);
|
||||||
|
|
||||||
|
|
|
@ -74,7 +74,7 @@ namespace MWWorld
|
||||||
|
|
||||||
bool isInCell() const
|
bool isInCell() const
|
||||||
{
|
{
|
||||||
return (mContainerStore == 0);
|
return (mContainerStore == 0) && (mCell != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setContainerStore (ContainerStore *store);
|
void setContainerStore (ContainerStore *store);
|
||||||
|
|
|
@ -43,6 +43,7 @@ struct ObjectList {
|
||||||
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::map<int,TextKeyMap> mTextKeys;
|
std::map<int,TextKeyMap> mTextKeys;
|
||||||
|
|
||||||
|
|
118
libs/openengine/ogre/lights.cpp
Normal file
118
libs/openengine/ogre/lights.cpp
Normal file
|
@ -0,0 +1,118 @@
|
||||||
|
#include "lights.hpp"
|
||||||
|
|
||||||
|
#include <OgreLight.h>
|
||||||
|
#include <OgreMath.h>
|
||||||
|
|
||||||
|
namespace OEngine {
|
||||||
|
namespace Render {
|
||||||
|
|
||||||
|
|
||||||
|
LightFunction::LightFunction(LightType type)
|
||||||
|
: ControllerFunction<Ogre::Real>(true)
|
||||||
|
, mType(type)
|
||||||
|
, mPhase(Ogre::Math::RangeRandom(-500.0f, +500.0f))
|
||||||
|
, mDirection(1.0f)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Ogre::Real LightFunction::pulseAmplitude(Ogre::Real time)
|
||||||
|
{
|
||||||
|
return std::sin(time);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ogre::Real LightFunction::flickerAmplitude(Ogre::Real time)
|
||||||
|
{
|
||||||
|
static const float fb = 1.17024f;
|
||||||
|
static const float f[3] = { 1.5708f, 4.18774f, 5.19934f };
|
||||||
|
static const float o[3] = { 0.804248f, 2.11115f, 3.46832f };
|
||||||
|
static const float m[3] = { 1.0f, 0.785f, 0.876f };
|
||||||
|
static const float s = 0.394f;
|
||||||
|
|
||||||
|
float v = 0.0f;
|
||||||
|
for(int i = 0;i < 3;++i)
|
||||||
|
v += std::sin(fb*time*f[i] + o[1])*m[i];
|
||||||
|
return v * s;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ogre::Real LightFunction::flickerFrequency(Ogre::Real phase)
|
||||||
|
{
|
||||||
|
static const float fa = 0.785398f;
|
||||||
|
static const float tdo = 0.94f;
|
||||||
|
static const float tdm = 2.48f;
|
||||||
|
|
||||||
|
return tdo + tdm*std::sin(fa * phase);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ogre::Real LightFunction::calculate(Ogre::Real value)
|
||||||
|
{
|
||||||
|
Ogre::Real brightness = 1.0f;
|
||||||
|
float cycle_time;
|
||||||
|
float time_distortion;
|
||||||
|
|
||||||
|
if(mType == LT_Pulse || mType == LT_PulseSlow)
|
||||||
|
{
|
||||||
|
cycle_time = 2.0f * Ogre::Math::PI;
|
||||||
|
time_distortion = 20.0f;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
static const float fa = 0.785398f;
|
||||||
|
static const float phase_wavelength = 120.0f * 3.14159265359f / fa;
|
||||||
|
|
||||||
|
cycle_time = 500.0f;
|
||||||
|
mPhase = std::fmod(mPhase + value, phase_wavelength);
|
||||||
|
time_distortion = flickerFrequency(mPhase);
|
||||||
|
}
|
||||||
|
|
||||||
|
mDeltaCount += mDirection*value*time_distortion;
|
||||||
|
if(mDirection > 0 && mDeltaCount > +cycle_time)
|
||||||
|
{
|
||||||
|
mDirection = -1.0f;
|
||||||
|
mDeltaCount = 2.0f*cycle_time - mDeltaCount;
|
||||||
|
}
|
||||||
|
if(mDirection < 0 && mDeltaCount < -cycle_time)
|
||||||
|
{
|
||||||
|
mDirection = +1.0f;
|
||||||
|
mDeltaCount = -2.0f*cycle_time - mDeltaCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const float fast = 4.0f/1.0f;
|
||||||
|
static const float slow = 1.0f/1.0f;
|
||||||
|
|
||||||
|
// These formulas are just guesswork, but they work pretty well
|
||||||
|
if(mType == LT_Normal)
|
||||||
|
{
|
||||||
|
// Less than 1/255 light modifier for a constant light:
|
||||||
|
brightness = 1.0 + flickerAmplitude(mDeltaCount*slow)/255.0f;
|
||||||
|
}
|
||||||
|
else if(mType == LT_Flicker)
|
||||||
|
brightness = 0.75 + flickerAmplitude(mDeltaCount*fast)*0.25;
|
||||||
|
else if(mType == LT_FlickerSlow)
|
||||||
|
brightness = 0.75 + flickerAmplitude(mDeltaCount*slow)*0.25;
|
||||||
|
else if(mType == LT_Pulse)
|
||||||
|
brightness = 1.0 + pulseAmplitude(mDeltaCount*fast)*0.25;
|
||||||
|
else if(mType == LT_PulseSlow)
|
||||||
|
brightness = 1.0 + pulseAmplitude(mDeltaCount*slow)*0.25;
|
||||||
|
|
||||||
|
return brightness;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LightValue::LightValue(Ogre::Light *light, const Ogre::ColourValue &color)
|
||||||
|
: mTarget(light)
|
||||||
|
, mColor(color)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Ogre::Real LightValue::getValue() const
|
||||||
|
{
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LightValue::setValue(Ogre::Real value)
|
||||||
|
{
|
||||||
|
mTarget->setDiffuseColour(mColor * value);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
51
libs/openengine/ogre/lights.hpp
Normal file
51
libs/openengine/ogre/lights.hpp
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
#ifndef OENGINE_OGRE_LIGHTS_H
|
||||||
|
#define OENGINE_OGRE_LIGHTS_H
|
||||||
|
|
||||||
|
#include <OgreController.h>
|
||||||
|
#include <OgreColourValue.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Controller classes to handle pulsing and flicker lights
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace OEngine {
|
||||||
|
namespace Render {
|
||||||
|
enum LightType {
|
||||||
|
LT_Normal,
|
||||||
|
LT_Flicker,
|
||||||
|
LT_FlickerSlow,
|
||||||
|
LT_Pulse,
|
||||||
|
LT_PulseSlow
|
||||||
|
};
|
||||||
|
|
||||||
|
class LightFunction : public Ogre::ControllerFunction<Ogre::Real>
|
||||||
|
{
|
||||||
|
LightType mType;
|
||||||
|
Ogre::Real mPhase;
|
||||||
|
Ogre::Real mDirection;
|
||||||
|
|
||||||
|
static Ogre::Real pulseAmplitude(Ogre::Real time);
|
||||||
|
|
||||||
|
static Ogre::Real flickerAmplitude(Ogre::Real time);
|
||||||
|
static Ogre::Real flickerFrequency(Ogre::Real phase);
|
||||||
|
|
||||||
|
public:
|
||||||
|
LightFunction(LightType type);
|
||||||
|
virtual Ogre::Real calculate(Ogre::Real value);
|
||||||
|
};
|
||||||
|
|
||||||
|
class LightValue : public Ogre::ControllerValue<Ogre::Real>
|
||||||
|
{
|
||||||
|
Ogre::Light *mTarget;
|
||||||
|
Ogre::ColourValue mColor;
|
||||||
|
|
||||||
|
public:
|
||||||
|
LightValue(Ogre::Light *light, const Ogre::ColourValue &color);
|
||||||
|
|
||||||
|
virtual Ogre::Real getValue() const;
|
||||||
|
virtual void setValue(Ogre::Real value);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -4,6 +4,7 @@
|
||||||
#include <OgreRenderTexture.h>
|
#include <OgreRenderTexture.h>
|
||||||
#include <OgreSubEntity.h>
|
#include <OgreSubEntity.h>
|
||||||
#include <OgreEntity.h>
|
#include <OgreEntity.h>
|
||||||
|
#include <OgreTechnique.h>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
#include <extern/shiny/Main/Factory.hpp>
|
#include <extern/shiny/Main/Factory.hpp>
|
||||||
|
@ -100,7 +101,16 @@ namespace Render
|
||||||
return m->getTechnique(1);
|
return m->getTechnique(1);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
throw std::runtime_error("selectionbuffer only works with entities");
|
{
|
||||||
|
m = Ogre::MaterialManager::getSingleton().getByName("NullMaterial");
|
||||||
|
if(m.isNull())
|
||||||
|
{
|
||||||
|
m = Ogre::MaterialManager::getSingleton().create("NullMaterial", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
|
||||||
|
m->getTechnique(0)->getPass(0)->setDepthCheckEnabled(true);
|
||||||
|
m->getTechnique(0)->getPass(0)->setDepthFunction(Ogre::CMPF_ALWAYS_FAIL);
|
||||||
|
}
|
||||||
|
return m->getTechnique(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue