mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-01-25 06:35:30 +00:00
Merge branch 'master' of https://github.com/zinnschlag/openmw into compiler-reorg
This commit is contained in:
commit
a0931b01fe
@ -78,6 +78,7 @@ set(LIBDIR ${CMAKE_SOURCE_DIR}/libs)
|
||||
set(OENGINE_OGRE
|
||||
${LIBDIR}/openengine/ogre/renderer.cpp
|
||||
${LIBDIR}/openengine/ogre/fader.cpp
|
||||
${LIBDIR}/openengine/ogre/lights.cpp
|
||||
${LIBDIR}/openengine/ogre/particles.cpp
|
||||
${LIBDIR}/openengine/ogre/selectionbuffer.cpp
|
||||
${LIBDIR}/openengine/ogre/imagerotate.cpp
|
||||
|
@ -138,6 +138,10 @@ namespace MWBase
|
||||
virtual void setValue (const std::string& id, const std::string& value) = 0;
|
||||
virtual void setValue (const std::string& id, int value) = 0;
|
||||
|
||||
/// Set time left for the player to start drowning (update the drowning bar)
|
||||
/// @param time value from [0,20]
|
||||
virtual void setDrowningTimeLeft (float time) =0;
|
||||
|
||||
virtual void setPlayerClass (const ESM::Class &class_) = 0;
|
||||
///< set current class of player
|
||||
|
||||
@ -181,6 +185,9 @@ namespace MWBase
|
||||
virtual void setInteriorMapTexture(const int x, const int y) = 0;
|
||||
///< set the index of the map texture that should be used (for interiors)
|
||||
|
||||
/// sets the visibility of the drowning bar
|
||||
virtual void setDrowningBarVisibility(bool visible) = 0;
|
||||
|
||||
/// sets the visibility of the hud health/magicka/stamina bars
|
||||
virtual void setHMSVisibility(bool visible) = 0;
|
||||
|
||||
|
@ -323,6 +323,8 @@ namespace MWBase
|
||||
|
||||
virtual bool isFlying(const MWWorld::Ptr &ptr) const = 0;
|
||||
virtual bool isSwimming(const MWWorld::Ptr &object) const = 0;
|
||||
///Is the head of the creature underwater?
|
||||
virtual bool isSubmerged(const MWWorld::Ptr &object) const = 0;
|
||||
virtual bool isUnderwater(const MWWorld::Ptr::CellStore* cell, const Ogre::Vector3 &pos) const = 0;
|
||||
virtual bool isOnGround(const MWWorld::Ptr &ptr) const = 0;
|
||||
|
||||
|
@ -25,9 +25,7 @@ namespace MWClass
|
||||
{
|
||||
const std::string model = getModel(ptr);
|
||||
if (!model.empty()) {
|
||||
MWRender::Objects& objects = renderingInterface.getObjects();
|
||||
objects.insertBegin(ptr, ptr.getRefData().isEnabled(), false);
|
||||
objects.insertMesh(ptr, model);
|
||||
renderingInterface.getObjects().insertModel(ptr, model);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -30,9 +30,7 @@ namespace MWClass
|
||||
{
|
||||
const std::string model = getModel(ptr);
|
||||
if (!model.empty()) {
|
||||
MWRender::Objects& objects = renderingInterface.getObjects();
|
||||
objects.insertBegin(ptr, ptr.getRefData().isEnabled(), false);
|
||||
objects.insertMesh(ptr, model);
|
||||
renderingInterface.getObjects().insertModel(ptr, model);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -23,9 +23,7 @@ namespace MWClass
|
||||
{
|
||||
const std::string model = getModel(ptr);
|
||||
if (!model.empty()) {
|
||||
MWRender::Objects& objects = renderingInterface.getObjects();
|
||||
objects.insertBegin(ptr, ptr.getRefData().isEnabled(), false);
|
||||
objects.insertMesh(ptr, model);
|
||||
renderingInterface.getObjects().insertModel(ptr, model);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -27,9 +27,7 @@ namespace MWClass
|
||||
{
|
||||
const std::string model = getModel(ptr);
|
||||
if (!model.empty()) {
|
||||
MWRender::Objects& objects = renderingInterface.getObjects();
|
||||
objects.insertBegin(ptr, ptr.getRefData().isEnabled(), false);
|
||||
objects.insertMesh(ptr, model);
|
||||
renderingInterface.getObjects().insertModel(ptr, model);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -61,9 +61,7 @@ namespace MWClass
|
||||
{
|
||||
const std::string model = getModel(ptr);
|
||||
if (!model.empty()) {
|
||||
MWRender::Objects& objects = renderingInterface.getObjects();
|
||||
objects.insertBegin(ptr, ptr.getRefData().isEnabled(), false);
|
||||
objects.insertMesh(ptr, model);
|
||||
renderingInterface.getObjects().insertModel(ptr, model);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -29,9 +29,7 @@ namespace MWClass
|
||||
{
|
||||
const std::string model = getModel(ptr);
|
||||
if (!model.empty()) {
|
||||
MWRender::Objects& objects = renderingInterface.getObjects();
|
||||
objects.insertBegin(ptr, ptr.getRefData().isEnabled(), false);
|
||||
objects.insertMesh(ptr, model);
|
||||
renderingInterface.getObjects().insertModel(ptr, model);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -36,9 +36,7 @@ namespace MWClass
|
||||
{
|
||||
const std::string model = getModel(ptr);
|
||||
if (!model.empty()) {
|
||||
MWRender::Objects& objects = renderingInterface.getObjects();
|
||||
objects.insertBegin(ptr, ptr.getRefData().isEnabled(), false);
|
||||
objects.insertMesh(ptr, model);
|
||||
renderingInterface.getObjects().insertModel(ptr, model);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -26,19 +26,10 @@ namespace MWClass
|
||||
{
|
||||
void Light::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const
|
||||
{
|
||||
MWWorld::LiveCellRef<ESM::Light> *ref =
|
||||
ptr.get<ESM::Light>();
|
||||
assert (ref->mBase != NULL);
|
||||
|
||||
const std::string &model = ref->mBase->mModel;
|
||||
|
||||
MWRender::Objects& objects = renderingInterface.getObjects();
|
||||
objects.insertBegin(ptr, ptr.getRefData().isEnabled(), false);
|
||||
|
||||
if (!model.empty())
|
||||
objects.insertMesh(ptr, "meshes\\" + model, true);
|
||||
else
|
||||
objects.insertLight(ptr);
|
||||
const std::string model = getModel(ptr);
|
||||
if(!model.empty()) {
|
||||
renderingInterface.getObjects().insertModel(ptr, model);
|
||||
}
|
||||
}
|
||||
|
||||
void Light::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const
|
||||
|
@ -26,9 +26,7 @@ namespace MWClass
|
||||
{
|
||||
const std::string model = getModel(ptr);
|
||||
if (!model.empty()) {
|
||||
MWRender::Objects& objects = renderingInterface.getObjects();
|
||||
objects.insertBegin(ptr, ptr.getRefData().isEnabled(), false);
|
||||
objects.insertMesh(ptr, model);
|
||||
renderingInterface.getObjects().insertModel(ptr, model);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -42,9 +42,7 @@ namespace MWClass
|
||||
{
|
||||
const std::string model = getModel(ptr);
|
||||
if (!model.empty()) {
|
||||
MWRender::Objects& objects = renderingInterface.getObjects();
|
||||
objects.insertBegin(ptr, ptr.getRefData().isEnabled(), false);
|
||||
objects.insertMesh(ptr, model);
|
||||
renderingInterface.getObjects().insertModel(ptr, model);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -725,15 +725,15 @@ namespace MWClass
|
||||
|
||||
float x = fJumpAcrobaticsBase->getFloat() +
|
||||
std::pow(a / 15.0f, fJumpAcroMultiplier->getFloat());
|
||||
x += 3 * b * fJumpAcroMultiplier->getFloat();
|
||||
x += mageffects.get(MWMechanics::EffectKey(9/*jump*/)).mMagnitude * 64;
|
||||
x += 3.0f * b * fJumpAcroMultiplier->getFloat();
|
||||
x += mageffects.get(MWMechanics::EffectKey(ESM::MagicEffect::Jump)).mMagnitude * 64;
|
||||
x *= encumbranceTerm;
|
||||
|
||||
if(Npc::getStance(ptr, Run, false))
|
||||
x *= fJumpRunMultiplier->getFloat();
|
||||
x *= 1.25f;//fatigueTerm;
|
||||
x -= -627.2/*gravity constant*/;
|
||||
x /= 3;
|
||||
x *= npcdata->mCreatureStats.getFatigueTerm();
|
||||
x -= -627.2f;/*gravity constant*/
|
||||
x /= 3.0f;
|
||||
|
||||
return x;
|
||||
}
|
||||
|
@ -28,9 +28,7 @@ namespace MWClass
|
||||
{
|
||||
const std::string model = getModel(ptr);
|
||||
if (!model.empty()) {
|
||||
MWRender::Objects& objects = renderingInterface.getObjects();
|
||||
objects.insertBegin(ptr, ptr.getRefData().isEnabled(), false);
|
||||
objects.insertMesh(ptr, model);
|
||||
renderingInterface.getObjects().insertModel(ptr, model);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -26,9 +26,7 @@ namespace MWClass
|
||||
{
|
||||
const std::string model = getModel(ptr);
|
||||
if (!model.empty()) {
|
||||
MWRender::Objects& objects = renderingInterface.getObjects();
|
||||
objects.insertBegin(ptr, ptr.getRefData().isEnabled(), false);
|
||||
objects.insertMesh(ptr, model);
|
||||
renderingInterface.getObjects().insertModel(ptr, model);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -25,9 +25,7 @@ namespace MWClass
|
||||
{
|
||||
const std::string model = getModel(ptr);
|
||||
if (!model.empty()) {
|
||||
MWRender::Objects& objects = renderingInterface.getObjects();
|
||||
objects.insertBegin(ptr, ptr.getRefData().isEnabled(), false);
|
||||
objects.insertMesh(ptr, model);
|
||||
renderingInterface.getObjects().insertModel(ptr, model);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -15,9 +15,7 @@ namespace MWClass
|
||||
{
|
||||
const std::string model = getModel(ptr);
|
||||
if (!model.empty()) {
|
||||
MWRender::Objects& objects = renderingInterface.getObjects();
|
||||
objects.insertBegin(ptr, ptr.getRefData().isEnabled(), true);
|
||||
objects.insertMesh(ptr, model);
|
||||
renderingInterface.getObjects().insertModel(ptr, model);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -33,9 +33,7 @@ namespace MWClass
|
||||
{
|
||||
const std::string model = getModel(ptr);
|
||||
if (!model.empty()) {
|
||||
MWRender::Objects& objects = renderingInterface.getObjects();
|
||||
objects.insertBegin(ptr, ptr.getRefData().isEnabled(), false);
|
||||
objects.insertMesh(ptr, model);
|
||||
renderingInterface.getObjects().insertModel(ptr, model);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -25,6 +25,8 @@ namespace MWGui
|
||||
, mHealth(NULL)
|
||||
, mMagicka(NULL)
|
||||
, mStamina(NULL)
|
||||
, mDrowning(NULL)
|
||||
, mDrowningFrame(NULL)
|
||||
, mWeapImage(NULL)
|
||||
, mSpellImage(NULL)
|
||||
, mWeapStatus(NULL)
|
||||
@ -69,6 +71,11 @@ namespace MWGui
|
||||
magickaFrame->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onHMSClicked);
|
||||
fatigueFrame->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onHMSClicked);
|
||||
|
||||
//Drowning bar
|
||||
getWidget(mDrowningFrame, "DrowningFrame");
|
||||
getWidget(mDrowning, "Drowning");
|
||||
mDrowning->setProgressRange(200);
|
||||
|
||||
const MyGUI::IntSize& viewSize = MyGUI::RenderManager::getInstance().getViewSize();
|
||||
|
||||
// Item and spell images and status bars
|
||||
@ -197,6 +204,16 @@ namespace MWGui
|
||||
}
|
||||
}
|
||||
|
||||
void HUD::setDrowningTimeLeft(float time)
|
||||
{
|
||||
mDrowning->setProgressPosition(time/20.0*200.0);
|
||||
}
|
||||
|
||||
void HUD::setDrowningBarVisible(bool visible)
|
||||
{
|
||||
mDrowningFrame->setVisible(visible);
|
||||
}
|
||||
|
||||
void HUD::onWorldClicked(MyGUI::Widget* _sender)
|
||||
{
|
||||
if (!MWBase::Environment::get().getWindowManager ()->isGuiMode ())
|
||||
|
@ -18,6 +18,11 @@ namespace MWGui
|
||||
void setTriangleCount(unsigned int count);
|
||||
void setBatchCount(unsigned int count);
|
||||
|
||||
/// Set time left for the player to start drowning
|
||||
/// @param time value from [0,20]
|
||||
void setDrowningTimeLeft(float time);
|
||||
void setDrowningBarVisible(bool visible);
|
||||
|
||||
void setHmsVisible(bool visible);
|
||||
void setWeapVisible(bool visible);
|
||||
void setSpellVisible(bool visible);
|
||||
@ -50,7 +55,7 @@ namespace MWGui
|
||||
void setEnemy(const MWWorld::Ptr& enemy);
|
||||
|
||||
private:
|
||||
MyGUI::ProgressBar *mHealth, *mMagicka, *mStamina, *mEnemyHealth;
|
||||
MyGUI::ProgressBar *mHealth, *mMagicka, *mStamina, *mEnemyHealth, *mDrowning;
|
||||
MyGUI::Widget* mHealthFrame;
|
||||
MyGUI::Widget *mWeapBox, *mSpellBox, *mSneakBox;
|
||||
MyGUI::ImageBox *mWeapImage, *mSpellImage;
|
||||
@ -62,6 +67,7 @@ namespace MWGui
|
||||
MyGUI::ImageBox* mCrosshair;
|
||||
MyGUI::TextBox* mCellNameBox;
|
||||
MyGUI::TextBox* mWeaponSpellBox;
|
||||
MyGUI::Widget* mDrowningFrame;
|
||||
|
||||
MyGUI::Widget* mDummy;
|
||||
|
||||
|
@ -599,6 +599,11 @@ namespace MWGui
|
||||
mStatsWindow->setValue (id, value);
|
||||
}
|
||||
|
||||
void WindowManager::setDrowningTimeLeft (float time)
|
||||
{
|
||||
mHud->setDrowningTimeLeft(time);
|
||||
}
|
||||
|
||||
void WindowManager::setPlayerClass (const ESM::Class &class_)
|
||||
{
|
||||
mStatsWindow->setValue("class", class_.mName);
|
||||
@ -787,6 +792,11 @@ namespace MWGui
|
||||
mHud->setPlayerDir(x,y);
|
||||
}
|
||||
|
||||
void WindowManager::setDrowningBarVisibility(bool visible)
|
||||
{
|
||||
mHud->setDrowningBarVisible(visible);
|
||||
}
|
||||
|
||||
void WindowManager::setHMSVisibility(bool visible)
|
||||
{
|
||||
mHud->setHmsVisible (visible);
|
||||
|
@ -148,6 +148,10 @@ namespace MWGui
|
||||
virtual void setValue (const std::string& id, const std::string& value);
|
||||
virtual void setValue (const std::string& id, int value);
|
||||
|
||||
/// Set time left for the player to start drowning (update the drowning bar)
|
||||
/// @param time value from [0,20]
|
||||
virtual void setDrowningTimeLeft (float time);
|
||||
|
||||
virtual void setPlayerClass (const ESM::Class &class_); ///< set current class of player
|
||||
virtual void configureSkills (const SkillList& major, const SkillList& minor); ///< configure skill groups, each set contains the skill ID for that group.
|
||||
virtual void setReputation (int reputation); ///< set the current reputation value
|
||||
@ -173,6 +177,9 @@ namespace MWGui
|
||||
virtual void setInteriorMapTexture(const int x, const int y);
|
||||
///< set the index of the map texture that should be used (for interiors)
|
||||
|
||||
/// sets the visibility of the drowning bar
|
||||
virtual void setDrowningBarVisibility(bool visible);
|
||||
|
||||
// sets the visibility of the hud health/magicka/stamina bars
|
||||
virtual void setHMSVisibility(bool visible);
|
||||
// sets the visibility of the hud minimap
|
||||
|
@ -268,10 +268,6 @@ namespace MWInput
|
||||
case A_ToggleHUD:
|
||||
mWindows.toggleHud();
|
||||
break;
|
||||
case A_Use:
|
||||
if (!MWBase::Environment::get().getWindowManager()->isGuiMode())
|
||||
mPlayer.use();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
|
||||
#include "npcstats.hpp"
|
||||
#include "creaturestats.hpp"
|
||||
#include "movement.hpp"
|
||||
|
||||
@ -40,6 +41,8 @@ namespace MWMechanics
|
||||
{
|
||||
if (!paused && ptr.getRefData().getHandle()!="player")
|
||||
MWWorld::Class::get (ptr).getInventoryStore (ptr).autoEquip (ptr);
|
||||
if(!paused)
|
||||
updateDrowning(ptr,duration);
|
||||
}
|
||||
|
||||
void Actors::adjustMagicEffects (const MWWorld::Ptr& creature)
|
||||
@ -159,6 +162,37 @@ namespace MWMechanics
|
||||
}
|
||||
}
|
||||
|
||||
void Actors::updateDrowning(const MWWorld::Ptr& ptr, float duration)
|
||||
{
|
||||
Ogre::Vector3 pos(ptr.getRefData().getPosition().pos);
|
||||
CreatureStats& creatureStats=MWWorld::Class::get(ptr).getCreatureStats(ptr);
|
||||
NpcStats& stats=MWWorld::Class::get(ptr).getNpcStats(ptr);
|
||||
bool waterBreathing=creatureStats.getMagicEffects().get(ESM::MagicEffect::WaterBreathing).mMagnitude>0;
|
||||
if(MWBase::Environment::get().getWorld()->isSubmerged(ptr) && !waterBreathing)
|
||||
{
|
||||
if(creatureStats.getFatigue().getCurrent()==0)
|
||||
stats.setTimeToStartDrowning(0);
|
||||
float timeLeft=stats.getTimeToStartDrowning()-duration;
|
||||
if(timeLeft<0)
|
||||
timeLeft=0;
|
||||
stats.setTimeToStartDrowning(timeLeft);
|
||||
if(timeLeft==0)
|
||||
stats.setLastDrowningHitTime(stats.getLastDrowningHitTime()+duration);
|
||||
}
|
||||
else
|
||||
{
|
||||
stats.setTimeToStartDrowning(20);
|
||||
stats.setLastDrowningHitTime(0);
|
||||
}
|
||||
//if npc is drowning and it's time to hit, then hit
|
||||
while(stats.getTimeToStartDrowning()==0.0 && stats.getLastDrowningHitTime()>0.33)
|
||||
{
|
||||
stats.setLastDrowningHitTime(stats.getLastDrowningHitTime()-0.33);
|
||||
//fixme: replace it with something different once screen hit effects are implemented (blood on screen)
|
||||
MWWorld::Class::get(ptr).setActorHealth(ptr, creatureStats.getHealth().getCurrent()-1.0);
|
||||
}
|
||||
}
|
||||
|
||||
Actors::Actors() : mDuration (0) {}
|
||||
|
||||
void Actors::addActor (const MWWorld::Ptr& ptr)
|
||||
|
@ -44,6 +44,7 @@ namespace MWMechanics
|
||||
|
||||
void calculateRestoration (const MWWorld::Ptr& ptr, float duration);
|
||||
|
||||
void updateDrowning (const MWWorld::Ptr& ptr, float duration);
|
||||
|
||||
public:
|
||||
|
||||
|
@ -24,12 +24,14 @@
|
||||
#include "movement.hpp"
|
||||
#include "npcstats.hpp"
|
||||
#include "creaturestats.hpp"
|
||||
#include "security.hpp"
|
||||
|
||||
#include "../mwrender/animation.hpp"
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/soundmanager.hpp"
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
|
||||
#include "../mwworld/player.hpp"
|
||||
#include "../mwworld/class.hpp"
|
||||
@ -465,7 +467,36 @@ bool CharacterController::updateNpcState()
|
||||
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 ||
|
||||
mWeaponType == WeapType_ThowWeapon)
|
||||
|
@ -110,7 +110,7 @@ namespace MWMechanics
|
||||
return mMagicEffects;
|
||||
}
|
||||
|
||||
const bool &CreatureStats::getAttackingOrSpell() const
|
||||
bool CreatureStats::getAttackingOrSpell() const
|
||||
{
|
||||
return mAttackingOrSpell;
|
||||
}
|
||||
@ -216,7 +216,7 @@ namespace MWMechanics
|
||||
mMagicEffects = effects;
|
||||
}
|
||||
|
||||
void CreatureStats::setAttackingOrSpell(const bool &attackingOrSpell)
|
||||
void CreatureStats::setAttackingOrSpell(bool attackingOrSpell)
|
||||
{
|
||||
mAttackingOrSpell = attackingOrSpell;
|
||||
}
|
||||
|
@ -59,7 +59,7 @@ namespace MWMechanics
|
||||
|
||||
const MagicEffects & getMagicEffects() const;
|
||||
|
||||
const bool & getAttackingOrSpell() const;
|
||||
bool getAttackingOrSpell() const;
|
||||
|
||||
int getLevel() const;
|
||||
|
||||
@ -90,7 +90,7 @@ namespace MWMechanics
|
||||
|
||||
void setMagicEffects(const MagicEffects &effects);
|
||||
|
||||
void setAttackingOrSpell(const bool &attackingOrSpell);
|
||||
void setAttackingOrSpell(bool attackingOrSpell);
|
||||
|
||||
enum AttackType
|
||||
{
|
||||
|
@ -254,6 +254,20 @@ namespace MWMechanics
|
||||
MWBase::Environment::get().getWindowManager()->setValue(dynamicNames[2], stats.getFatigue());
|
||||
}
|
||||
|
||||
if(npcStats.getTimeToStartDrowning() != mWatchedNpc.getTimeToStartDrowning())
|
||||
{
|
||||
mWatchedNpc.setTimeToStartDrowning(npcStats.getTimeToStartDrowning());
|
||||
if(npcStats.getTimeToStartDrowning()>=20.0)
|
||||
{
|
||||
MWBase::Environment::get().getWindowManager()->setDrowningBarVisibility(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
MWBase::Environment::get().getWindowManager()->setDrowningBarVisibility(true);
|
||||
MWBase::Environment::get().getWindowManager()->setDrowningTimeLeft(npcStats.getTimeToStartDrowning());
|
||||
}
|
||||
}
|
||||
|
||||
bool update = false;
|
||||
|
||||
//Loop over ESM::Skill::SkillEnum
|
||||
|
@ -32,6 +32,8 @@ MWMechanics::NpcStats::NpcStats()
|
||||
, mWerewolfKills (0)
|
||||
, mProfit(0)
|
||||
, mAttackStrength(0.0f)
|
||||
, mTimeToStartDrowning(20.0)
|
||||
, mLastDrowningHit(0)
|
||||
{
|
||||
mSkillIncreases.resize (ESM::Attribute::Length);
|
||||
for (int i=0; i<ESM::Attribute::Length; ++i)
|
||||
@ -382,3 +384,23 @@ void MWMechanics::NpcStats::modifyProfit(int diff)
|
||||
{
|
||||
mProfit += diff;
|
||||
}
|
||||
|
||||
float MWMechanics::NpcStats::getTimeToStartDrowning()
|
||||
{
|
||||
return mTimeToStartDrowning;
|
||||
}
|
||||
void MWMechanics::NpcStats::setTimeToStartDrowning(float time)
|
||||
{
|
||||
assert(time>=0 && time<=20);
|
||||
mTimeToStartDrowning=time;
|
||||
}
|
||||
|
||||
float MWMechanics::NpcStats::getLastDrowningHitTime()
|
||||
{
|
||||
return mLastDrowningHit;
|
||||
}
|
||||
|
||||
void MWMechanics::NpcStats::setLastDrowningHitTime(float time)
|
||||
{
|
||||
mLastDrowningHit=time;
|
||||
}
|
||||
|
@ -62,6 +62,11 @@ namespace MWMechanics
|
||||
|
||||
std::set<std::string> mUsedIds;
|
||||
|
||||
/// Countdown to getting damage while underwater
|
||||
float mTimeToStartDrowning;
|
||||
/// time since last hit from drowning
|
||||
float mLastDrowningHit;
|
||||
|
||||
public:
|
||||
|
||||
NpcStats();
|
||||
@ -142,6 +147,16 @@ namespace MWMechanics
|
||||
void setWerewolf (bool set);
|
||||
|
||||
int getWerewolfKills() const;
|
||||
|
||||
float getTimeToStartDrowning();
|
||||
/// Sets time left for the creature to drown if it stays underwater.
|
||||
/// @param time value from [0,20]
|
||||
void setTimeToStartDrowning(float time);
|
||||
|
||||
float getLastDrowningHitTime();
|
||||
/// Sets time since last hit caused by drowning.
|
||||
/// @param time value from [0,0.33]
|
||||
void setLastDrowningHitTime(float time);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -12,16 +12,16 @@ ActivatorAnimation::~ActivatorAnimation()
|
||||
}
|
||||
|
||||
ActivatorAnimation::ActivatorAnimation(const MWWorld::Ptr &ptr)
|
||||
: Animation(ptr)
|
||||
: Animation(ptr, ptr.getRefData().getBaseNode())
|
||||
{
|
||||
MWWorld::LiveCellRef<ESM::Activator> *ref = mPtr.get<ESM::Activator>();
|
||||
|
||||
assert (ref->mBase != NULL);
|
||||
assert(ref->mBase != NULL);
|
||||
if(!ref->mBase->mModel.empty())
|
||||
{
|
||||
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);
|
||||
|
||||
addAnimSource(name);
|
||||
|
@ -27,6 +27,8 @@ namespace MWRender
|
||||
CellSceneNodeMap mCellSceneNodes;
|
||||
PtrAnimationMap mAllActors;
|
||||
|
||||
void insertBegin(const MWWorld::Ptr &ptr);
|
||||
|
||||
public:
|
||||
Actors(OEngine::Render::OgreRenderer& _rend, MWRender::RenderingManager* rendering)
|
||||
: mRend(_rend)
|
||||
@ -36,7 +38,7 @@ namespace MWRender
|
||||
~Actors();
|
||||
|
||||
void setRootNode(Ogre::SceneNode* root);
|
||||
void insertBegin (const MWWorld::Ptr& ptr);
|
||||
|
||||
void insertNPC(const MWWorld::Ptr& ptr, MWWorld::InventoryStore& inv);
|
||||
void insertCreature (const MWWorld::Ptr& ptr);
|
||||
void insertActivator (const MWWorld::Ptr& ptr);
|
||||
|
@ -8,6 +8,10 @@
|
||||
#include <OgreBone.h>
|
||||
#include <OgreSubMesh.h>
|
||||
#include <OgreSceneManager.h>
|
||||
#include <OgreControllerManager.h>
|
||||
#include <OgreStaticGeometry.h>
|
||||
|
||||
#include <libs/openengine/ogre/lights.hpp>
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/soundmanager.hpp"
|
||||
@ -16,6 +20,9 @@
|
||||
#include "../mwmechanics/character.hpp"
|
||||
#include "../mwmechanics/creaturestats.hpp"
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwworld/fallback.hpp"
|
||||
|
||||
#include "renderconst.hpp"
|
||||
|
||||
namespace MWRender
|
||||
{
|
||||
@ -35,17 +42,26 @@ void Animation::AnimationValue::setValue(Ogre::Real)
|
||||
|
||||
void Animation::destroyObjectList(Ogre::SceneManager *sceneMgr, NifOgre::ObjectList &objects)
|
||||
{
|
||||
for(size_t i = 0;i < objects.mLights.size();i++)
|
||||
{
|
||||
Ogre::Light *light = objects.mLights[i];
|
||||
// If parent is a scene node, it was created specifically for this light. Destroy it now.
|
||||
if(light->isAttached() && !light->isParentTagPoint())
|
||||
sceneMgr->destroySceneNode(light->getParentSceneNode());
|
||||
sceneMgr->destroyLight(light);
|
||||
}
|
||||
for(size_t i = 0;i < objects.mParticles.size();i++)
|
||||
sceneMgr->destroyParticleSystem(objects.mParticles[i]);
|
||||
for(size_t i = 0;i < objects.mEntities.size();i++)
|
||||
sceneMgr->destroyEntity(objects.mEntities[i]);
|
||||
objects.mControllers.clear();
|
||||
objects.mLights.clear();
|
||||
objects.mParticles.clear();
|
||||
objects.mEntities.clear();
|
||||
objects.mSkelBase = NULL;
|
||||
}
|
||||
|
||||
Animation::Animation(const MWWorld::Ptr &ptr)
|
||||
Animation::Animation(const MWWorld::Ptr &ptr, Ogre::SceneNode *node)
|
||||
: mPtr(ptr)
|
||||
, mCamera(NULL)
|
||||
, mInsert(NULL)
|
||||
@ -58,6 +74,7 @@ Animation::Animation(const MWWorld::Ptr &ptr)
|
||||
{
|
||||
for(size_t i = 0;i < sNumGroups;i++)
|
||||
mAnimationValuePtr[i].bind(OGRE_NEW AnimationValue(this));
|
||||
mInsert = node->createChildSceneNode();
|
||||
}
|
||||
|
||||
Animation::~Animation()
|
||||
@ -68,15 +85,21 @@ Animation::~Animation()
|
||||
|
||||
Ogre::SceneManager *sceneMgr = mInsert->getCreator();
|
||||
destroyObjectList(sceneMgr, mObjectRoot);
|
||||
|
||||
sceneMgr->destroySceneNode(mInsert);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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!");
|
||||
if(!mInsert)
|
||||
mInsert = node->createChildSceneNode();
|
||||
|
||||
mSkelBase = NULL;
|
||||
destroyObjectList(mInsert->getCreator(), mObjectRoot);
|
||||
|
||||
if(model.empty())
|
||||
return;
|
||||
|
||||
std::string mdlname = Misc::StringUtils::lowerCase(model);
|
||||
std::string::size_type p = mdlname.rfind('\\');
|
||||
@ -92,9 +115,6 @@ void Animation::setObjectRoot(Ogre::SceneNode *node, const std::string &model, b
|
||||
Misc::StringUtils::toLower(mdlname);
|
||||
}
|
||||
|
||||
mSkelBase = NULL;
|
||||
destroyObjectList(mInsert->getCreator(), mObjectRoot);
|
||||
|
||||
mObjectRoot = (!baseonly ? NifOgre::Loader::createObjects(mInsert, mdlname) :
|
||||
NifOgre::Loader::createObjectBase(mInsert, mdlname));
|
||||
if(mObjectRoot.mSkelBase)
|
||||
@ -140,28 +160,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
|
||||
{
|
||||
if(mVisFlags != 0)
|
||||
entity->setVisibilityFlags(mVisFlags);
|
||||
entity->setRenderingDistance(mDist);
|
||||
|
||||
unsigned int numsubs = entity->getNumSubEntities();
|
||||
for(unsigned int i = 0;i < numsubs;++i)
|
||||
{
|
||||
Ogre::SubEntity* subEnt = ent->getSubEntity(j);
|
||||
subEnt->setRenderQueueGroup(subEnt->getMaterial()->isTransparent() ? transqueue : solidqueue);
|
||||
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(visflags != 0)
|
||||
part->setVisibilityFlags(visflags);
|
||||
if(mVisFlags != 0)
|
||||
psys->setVisibilityFlags(mVisFlags);
|
||||
psys->setRenderingDistance(mDist);
|
||||
// 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 +293,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)
|
||||
{
|
||||
if(mSkelBase)
|
||||
@ -805,6 +914,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
|
||||
{
|
||||
for (AnimStateMap::const_iterator it = mStates.begin(); it != mStates.end(); ++it)
|
||||
@ -833,4 +979,66 @@ void Animation::detachObjectFromBone(Ogre::MovableObject *obj)
|
||||
mSkelBase->detachObjectFromBone(obj);
|
||||
}
|
||||
|
||||
|
||||
ObjectAnimation::ObjectAnimation(const MWWorld::Ptr& ptr, const std::string &model)
|
||||
: 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, (mPtr.getTypeName() == typeid(ESM::Static).name()) ?
|
||||
(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);
|
||||
};
|
||||
|
||||
|
||||
class NullAnimationValue : public Ogre::ControllerValue<Ogre::Real>
|
||||
{
|
||||
public:
|
||||
@ -61,6 +62,7 @@ protected:
|
||||
{ }
|
||||
};
|
||||
|
||||
|
||||
struct AnimSource : public Ogre::AnimationAlloc {
|
||||
NifOgre::TextKeyMap mTextKeys;
|
||||
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
|
||||
* 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
|
||||
* the filename portion of the provided model name will be prepended with 'x', and the .nif
|
||||
* extension will be replaced with .kf. */
|
||||
void addAnimSource(const std::string &model);
|
||||
|
||||
/** Adds an additional light to the given object list using the specified ESM record. */
|
||||
void addExtraLight(Ogre::SceneManager *sceneMgr, NifOgre::ObjectList &objlist, const ESM::Light *light);
|
||||
|
||||
static void destroyObjectList(Ogre::SceneManager *sceneMgr, NifOgre::ObjectList &objects);
|
||||
|
||||
static void setRenderProperties(const NifOgre::ObjectList &objlist, Ogre::uint32 visflags, Ogre::uint8 solidqueue, Ogre::uint8 transqueue);
|
||||
static void setRenderProperties(const NifOgre::ObjectList &objlist, Ogre::uint32 visflags, Ogre::uint8 solidqueue, Ogre::uint8 transqueue, Ogre::Real dist=0.0f);
|
||||
|
||||
void clearAnimSources();
|
||||
|
||||
public:
|
||||
Animation(const MWWorld::Ptr &ptr);
|
||||
Animation(const MWWorld::Ptr &ptr, Ogre::SceneNode *node);
|
||||
virtual ~Animation();
|
||||
|
||||
void updatePtr(const MWWorld::Ptr &ptr);
|
||||
@ -224,6 +229,10 @@ public:
|
||||
|
||||
virtual void showWeapons(bool showWeapon);
|
||||
|
||||
void enableLights(bool enable);
|
||||
|
||||
Ogre::AxisAlignedBox getWorldBounds();
|
||||
|
||||
void setCamera(Camera *cam)
|
||||
{ mCamera = cam; }
|
||||
|
||||
@ -236,5 +245,15 @@ public:
|
||||
void detachObjectFromBone(Ogre::MovableObject *obj);
|
||||
};
|
||||
|
||||
class ObjectAnimation : public Animation {
|
||||
public:
|
||||
ObjectAnimation(const MWWorld::Ptr& ptr, const std::string &model);
|
||||
|
||||
void addLight(const ESM::Light *light);
|
||||
|
||||
bool canBatch() const;
|
||||
void fillBatch(Ogre::StaticGeometry *sg);
|
||||
};
|
||||
|
||||
}
|
||||
#endif
|
||||
|
@ -12,7 +12,7 @@ CreatureAnimation::~CreatureAnimation()
|
||||
}
|
||||
|
||||
CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr)
|
||||
: Animation(ptr)
|
||||
: Animation(ptr, ptr.getRefData().getBaseNode())
|
||||
{
|
||||
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;
|
||||
|
||||
setObjectRoot(mPtr.getRefData().getBaseNode(), model, false);
|
||||
setObjectRoot(model, false);
|
||||
setRenderProperties(mObjectRoot, RV_Actors, RQG_Main, RQG_Alpha);
|
||||
|
||||
if((ref->mBase->mFlags&ESM::Creature::Biped))
|
||||
|
@ -20,46 +20,50 @@
|
||||
namespace MWRender
|
||||
{
|
||||
|
||||
const NpcAnimation::PartInfo NpcAnimation::sPartList[NpcAnimation::sPartListSize] = {
|
||||
{ ESM::PRT_Head, "Head" },
|
||||
{ ESM::PRT_Hair, "Head" },
|
||||
{ ESM::PRT_Neck, "Neck" },
|
||||
{ ESM::PRT_Cuirass, "Chest" },
|
||||
{ ESM::PRT_Groin, "Groin" },
|
||||
{ ESM::PRT_Skirt, "Groin" },
|
||||
{ ESM::PRT_RHand, "Right Hand" },
|
||||
{ ESM::PRT_LHand, "Left Hand" },
|
||||
{ ESM::PRT_RWrist, "Right Wrist" },
|
||||
{ ESM::PRT_LWrist, "Left Wrist" },
|
||||
{ ESM::PRT_Shield, "Shield Bone" },
|
||||
{ ESM::PRT_RForearm, "Right Forearm" },
|
||||
{ ESM::PRT_LForearm, "Left Forearm" },
|
||||
{ ESM::PRT_RUpperarm, "Right Upper Arm" },
|
||||
{ ESM::PRT_LUpperarm, "Left Upper Arm" },
|
||||
{ ESM::PRT_RFoot, "Right Foot" },
|
||||
{ ESM::PRT_LFoot, "Left Foot" },
|
||||
{ ESM::PRT_RAnkle, "Right Ankle" },
|
||||
{ ESM::PRT_LAnkle, "Left Ankle" },
|
||||
{ ESM::PRT_RKnee, "Right Knee" },
|
||||
{ ESM::PRT_LKnee, "Left Knee" },
|
||||
{ ESM::PRT_RLeg, "Right Upper Leg" },
|
||||
{ ESM::PRT_LLeg, "Left Upper Leg" },
|
||||
{ ESM::PRT_RPauldron, "Right Clavicle" },
|
||||
{ ESM::PRT_LPauldron, "Left Clavicle" },
|
||||
{ ESM::PRT_Weapon, "Weapon Bone" },
|
||||
{ ESM::PRT_Tail, "Tail" }
|
||||
};
|
||||
static NpcAnimation::PartBoneMap createPartListMap()
|
||||
{
|
||||
NpcAnimation::PartBoneMap result;
|
||||
result.insert(std::make_pair(ESM::PRT_Head, "Head"));
|
||||
result.insert(std::make_pair(ESM::PRT_Hair, "Head"));
|
||||
result.insert(std::make_pair(ESM::PRT_Neck, "Neck"));
|
||||
result.insert(std::make_pair(ESM::PRT_Cuirass, "Chest"));
|
||||
result.insert(std::make_pair(ESM::PRT_Groin, "Groin"));
|
||||
result.insert(std::make_pair(ESM::PRT_Skirt, "Groin"));
|
||||
result.insert(std::make_pair(ESM::PRT_RHand, "Right Hand"));
|
||||
result.insert(std::make_pair(ESM::PRT_LHand, "Left Hand"));
|
||||
result.insert(std::make_pair(ESM::PRT_RWrist, "Right Wrist"));
|
||||
result.insert(std::make_pair(ESM::PRT_LWrist, "Left Wrist"));
|
||||
result.insert(std::make_pair(ESM::PRT_Shield, "Shield Bone"));
|
||||
result.insert(std::make_pair(ESM::PRT_RForearm, "Right Forearm"));
|
||||
result.insert(std::make_pair(ESM::PRT_LForearm, "Left Forearm"));
|
||||
result.insert(std::make_pair(ESM::PRT_RUpperarm, "Right Upper Arm"));
|
||||
result.insert(std::make_pair(ESM::PRT_LUpperarm, "Left Upper Arm"));
|
||||
result.insert(std::make_pair(ESM::PRT_RFoot, "Right Foot"));
|
||||
result.insert(std::make_pair(ESM::PRT_LFoot, "Left Foot"));
|
||||
result.insert(std::make_pair(ESM::PRT_RAnkle, "Right Ankle"));
|
||||
result.insert(std::make_pair(ESM::PRT_LAnkle, "Left Ankle"));
|
||||
result.insert(std::make_pair(ESM::PRT_RKnee, "Right Knee"));
|
||||
result.insert(std::make_pair(ESM::PRT_LKnee, "Left Knee"));
|
||||
result.insert(std::make_pair(ESM::PRT_RLeg, "Right Upper Leg"));
|
||||
result.insert(std::make_pair(ESM::PRT_LLeg, "Left Upper Leg"));
|
||||
result.insert(std::make_pair(ESM::PRT_RPauldron, "Right Clavicle"));
|
||||
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()
|
||||
{
|
||||
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]);
|
||||
}
|
||||
|
||||
|
||||
NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWorld::InventoryStore& inv, int visibilityFlags, ViewMode viewMode)
|
||||
: Animation(ptr),
|
||||
: Animation(ptr, node),
|
||||
mStateID(-1),
|
||||
mTimeToChange(0),
|
||||
mVisibilityFlags(visibilityFlags),
|
||||
@ -82,7 +86,7 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor
|
||||
{
|
||||
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
|
||||
mPartPriorities[i] = 0;
|
||||
@ -102,7 +106,7 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor
|
||||
std::string smodel = (viewMode != VM_FirstPerson) ?
|
||||
(!isBeast ? "meshes\\base_anim.nif" : "meshes\\base_animkna.nif") :
|
||||
(!isBeast ? "meshes\\base_anim.1st.nif" : "meshes\\base_animkna.1st.nif") ;
|
||||
setObjectRoot(node, smodel, true);
|
||||
setObjectRoot(smodel, true);
|
||||
|
||||
if(mViewMode != VM_FirstPerson)
|
||||
{
|
||||
@ -143,7 +147,7 @@ void NpcAnimation::setViewMode(NpcAnimation::ViewMode viewMode)
|
||||
std::string smodel = (viewMode != VM_FirstPerson) ?
|
||||
(!isBeast ? "meshes\\base_anim.nif" : "meshes\\base_animkna.nif") :
|
||||
(!isBeast ? "meshes\\base_anim.1st.nif" : "meshes\\base_animkna.1st.nif") ;
|
||||
setObjectRoot(mInsert->getParentSceneNode(), smodel, true);
|
||||
setObjectRoot(smodel, true);
|
||||
|
||||
if(mViewMode != VM_FirstPerson)
|
||||
{
|
||||
@ -168,8 +172,8 @@ void NpcAnimation::setViewMode(NpcAnimation::ViewMode viewMode)
|
||||
}
|
||||
MWBase::Environment::get().getMechanicsManager()->forceStateUpdate(mPtr);
|
||||
|
||||
for(size_t i = 0;i < sPartListSize;i++)
|
||||
removeIndividualPart(i);
|
||||
for(size_t i = 0;i < ESM::PRT_Count;i++)
|
||||
removeIndividualPart((ESM::PartReferenceType)i);
|
||||
forceUpdate();
|
||||
}
|
||||
|
||||
@ -267,6 +271,19 @@ void NpcAnimation::updateParts(bool forceupdate)
|
||||
if(mViewMode == VM_HeadOnly)
|
||||
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);
|
||||
|
||||
const int Flag_Female = 0x01;
|
||||
@ -366,23 +383,31 @@ void NpcAnimation::updateParts(bool forceupdate)
|
||||
{
|
||||
const ESM::BodyPart* bodypart = parts[part];
|
||||
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 objects = NifOgre::Loader::createObjects(mSkelBase, bonename, mInsert, model);
|
||||
setRenderProperties(objects, (mViewMode == VM_FirstPerson) ? RV_FirstPerson : mVisibilityFlags, RQG_Main, RQG_Alpha);
|
||||
|
||||
for(size_t i = 0;i < objects.mEntities.size();i++)
|
||||
{
|
||||
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));
|
||||
std::for_each(objects.mEntities.begin(), objects.mEntities.end(), SetObjectGroup(group));
|
||||
std::for_each(objects.mParticles.begin(), objects.mParticles.end(), SetObjectGroup(group));
|
||||
|
||||
if(objects.mSkelBase)
|
||||
{
|
||||
@ -422,7 +447,7 @@ Ogre::Vector3 NpcAnimation::runAnimation(float timepassed)
|
||||
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());
|
||||
for(;ctrl != mObjectParts[i].mControllers.end();ctrl++)
|
||||
@ -437,22 +462,15 @@ Ogre::Vector3 NpcAnimation::runAnimation(float timepassed)
|
||||
return ret;
|
||||
}
|
||||
|
||||
void NpcAnimation::removeIndividualPart(int type)
|
||||
void NpcAnimation::removeIndividualPart(ESM::PartReferenceType type)
|
||||
{
|
||||
mPartPriorities[type] = 0;
|
||||
mPartslots[type] = -1;
|
||||
|
||||
for(size_t i = 0;i < sPartListSize;i++)
|
||||
{
|
||||
if(type == sPartList[i].type)
|
||||
{
|
||||
destroyObjectList(mInsert->getCreator(), mObjectParts[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
destroyObjectList(mInsert->getCreator(), mObjectParts[type]);
|
||||
}
|
||||
|
||||
void NpcAnimation::reserveIndividualPart(int type, int group, int priority)
|
||||
void NpcAnimation::reserveIndividualPart(ESM::PartReferenceType type, int group, int priority)
|
||||
{
|
||||
if(priority > mPartPriorities[type])
|
||||
{
|
||||
@ -464,14 +482,14 @@ void NpcAnimation::reserveIndividualPart(int type, int group, int priority)
|
||||
|
||||
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)
|
||||
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])
|
||||
return false;
|
||||
@ -480,28 +498,36 @@ bool NpcAnimation::addOrReplaceIndividualPart(int type, int group, int priority,
|
||||
mPartslots[type] = group;
|
||||
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);
|
||||
|
||||
// TODO:
|
||||
// type == ESM::PRT_Head should get an animation source based on the current output of
|
||||
// the actor's 'say' sound (0 = silent, 1 = loud?).
|
||||
// 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?)
|
||||
std::vector<Ogre::Controller<Ogre::Real> >::iterator ctrl(mObjectParts[i].mControllers.begin());
|
||||
for(;ctrl != mObjectParts[i].mControllers.end();ctrl++)
|
||||
{
|
||||
if(ctrl->getSource().isNull())
|
||||
ctrl->setSource(mNullAnimationValuePtr);
|
||||
}
|
||||
|
||||
break;
|
||||
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();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
// TODO:
|
||||
// type == ESM::PRT_Head should get an animation source based on the current output of
|
||||
// the actor's 'say' sound (0 = silent, 1 = loud?).
|
||||
// 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?)
|
||||
std::vector<Ogre::Controller<Ogre::Real> >::iterator ctrl(mObjectParts[type].mControllers.begin());
|
||||
for(;ctrl != mObjectParts[type].mControllers.end();ctrl++)
|
||||
{
|
||||
if(ctrl->getSource().isNull())
|
||||
ctrl->setSource(mNullAnimationValuePtr);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void NpcAnimation::addPartGroup(int group, int priority, const std::vector<ESM::PartReference> &parts)
|
||||
@ -542,9 +568,9 @@ void NpcAnimation::addPartGroup(int group, int priority, const std::vector<ESM::
|
||||
}
|
||||
|
||||
if(bodypart)
|
||||
addOrReplaceIndividualPart(part->mPart, group, priority, "meshes\\"+bodypart->mModel);
|
||||
addOrReplaceIndividualPart((ESM::PartReferenceType)part->mPart, group, priority, "meshes\\"+bodypart->mModel);
|
||||
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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -21,25 +21,21 @@ namespace MWRender
|
||||
class NpcAnimation : public Animation
|
||||
{
|
||||
public:
|
||||
struct PartInfo {
|
||||
ESM::PartReferenceType type;
|
||||
const char name[32];
|
||||
};
|
||||
typedef std::map<ESM::PartReferenceType,std::string> PartBoneMap;
|
||||
|
||||
enum ViewMode {
|
||||
VM_Normal,
|
||||
VM_FirstPerson,
|
||||
VM_HeadOnly
|
||||
};
|
||||
enum ViewMode {
|
||||
VM_Normal,
|
||||
VM_FirstPerson,
|
||||
VM_HeadOnly
|
||||
};
|
||||
|
||||
private:
|
||||
static const size_t sPartListSize = 27;
|
||||
static const PartInfo sPartList[sPartListSize];
|
||||
static const PartBoneMap sPartList;
|
||||
|
||||
int mStateID;
|
||||
|
||||
// Bounded Parts
|
||||
NifOgre::ObjectList mObjectParts[sPartListSize];
|
||||
NifOgre::ObjectList mObjectParts[ESM::PRT_Count];
|
||||
|
||||
const ESM::NPC *mNpc;
|
||||
std::string mHeadModel;
|
||||
@ -66,17 +62,17 @@ private:
|
||||
|
||||
int mVisibilityFlags;
|
||||
|
||||
int mPartslots[sPartListSize]; //Each part slot is taken by clothing, armor, or is empty
|
||||
int mPartPriorities[sPartListSize];
|
||||
int mPartslots[ESM::PRT_Count]; //Each part slot is taken by clothing, armor, or is empty
|
||||
int mPartPriorities[ESM::PRT_Count];
|
||||
|
||||
NifOgre::ObjectList insertBoundedPart(const std::string &model, int group, const std::string &bonename);
|
||||
|
||||
void updateParts(bool forceupdate = false);
|
||||
|
||||
void removeIndividualPart(int type);
|
||||
void reserveIndividualPart(int type, int group, int priority);
|
||||
void removeIndividualPart(ESM::PartReferenceType type);
|
||||
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 addPartGroup(int group, int priority, const std::vector<ESM::PartReference> &parts);
|
||||
|
||||
|
@ -18,70 +18,18 @@
|
||||
#include "../mwworld/class.hpp"
|
||||
|
||||
#include "renderconst.hpp"
|
||||
#include "animation.hpp"
|
||||
|
||||
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;
|
||||
|
||||
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)
|
||||
{
|
||||
mRootNode = root;
|
||||
}
|
||||
|
||||
void Objects::insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_)
|
||||
void Objects::insertBegin(const MWWorld::Ptr& ptr)
|
||||
{
|
||||
Ogre::SceneNode* root = mRootNode;
|
||||
Ogre::SceneNode* cellnode;
|
||||
@ -118,79 +66,45 @@ void Objects::insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_)
|
||||
// Rotates first around z, then y, then x
|
||||
insert->setOrientation(xr*yr*zr);
|
||||
|
||||
if (!enabled)
|
||||
insert->setVisible (false);
|
||||
ptr.getRefData().setBaseNode(insert);
|
||||
mIsStatic = static_;
|
||||
}
|
||||
|
||||
void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh, bool light)
|
||||
void Objects::insertModel(const MWWorld::Ptr &ptr, const std::string &mesh)
|
||||
{
|
||||
Ogre::SceneNode* insert = ptr.getRefData().getBaseNode();
|
||||
assert(insert);
|
||||
insertBegin(ptr);
|
||||
|
||||
Ogre::AxisAlignedBox bounds = Ogre::AxisAlignedBox::BOX_NULL;
|
||||
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));
|
||||
std::auto_ptr<ObjectAnimation> anim(new ObjectAnimation(ptr, mesh));
|
||||
|
||||
Ogre::AxisAlignedBox bounds = anim->getWorldBounds();
|
||||
Ogre::Vector3 extents = bounds.getSize();
|
||||
extents *= insert->getScale();
|
||||
extents *= ptr.getRefData().getBaseNode()->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");
|
||||
|
||||
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)
|
||||
if(ptr.getTypeName().find("Door") != std::string::npos)
|
||||
small = false;
|
||||
|
||||
if (mBounds.find(ptr.getCell()) == mBounds.end())
|
||||
mBounds[ptr.getCell()] = Ogre::AxisAlignedBox::BOX_NULL;
|
||||
mBounds[ptr.getCell()].merge(bounds);
|
||||
|
||||
bool anyTransparency = false;
|
||||
for(size_t i = 0;!anyTransparency && i < objects.mEntities.size();i++)
|
||||
{
|
||||
Ogre::Entity *ent = objects.mEntities[i];
|
||||
for(unsigned int i=0;!anyTransparency && i < ent->getNumSubEntities(); ++i)
|
||||
{
|
||||
anyTransparency = ent->getSubEntity(i)->getMaterial()->isTransparent();
|
||||
}
|
||||
}
|
||||
if(ptr.getTypeName() == typeid(ESM::Light).name())
|
||||
anim->addLight(ptr.get<ESM::Light>()->mBase);
|
||||
|
||||
if(!mIsStatic || !Settings::Manager::getBool("use static geometry", "Objects") ||
|
||||
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
|
||||
if(ptr.getTypeName() == typeid(ESM::Static).name() &&
|
||||
Settings::Manager::getBool("use static geometry", "Objects") &&
|
||||
anim->canBatch())
|
||||
{
|
||||
Ogre::StaticGeometry* sg = 0;
|
||||
|
||||
if (small)
|
||||
{
|
||||
if( mStaticGeometrySmall.find(ptr.getCell()) == mStaticGeometrySmall.end())
|
||||
if(mStaticGeometrySmall.find(ptr.getCell()) == mStaticGeometrySmall.end())
|
||||
{
|
||||
uniqueID = uniqueID +1;
|
||||
sg = mRenderer.getScene()->createStaticGeometry( "sg" + Ogre::StringConverter::toString(uniqueID));
|
||||
uniqueID = uniqueID+1;
|
||||
sg = mRenderer.getScene()->createStaticGeometry("sg" + Ogre::StringConverter::toString(uniqueID));
|
||||
mStaticGeometrySmall[ptr.getCell()] = sg;
|
||||
|
||||
sg->setRenderingDistance(Settings::Manager::getInt("small object distance", "Viewing distance"));
|
||||
@ -200,11 +114,10 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh, bool
|
||||
}
|
||||
else
|
||||
{
|
||||
if( mStaticGeometry.find(ptr.getCell()) == mStaticGeometry.end())
|
||||
if(mStaticGeometry.find(ptr.getCell()) == mStaticGeometry.end())
|
||||
{
|
||||
|
||||
uniqueID = uniqueID +1;
|
||||
sg = mRenderer.getScene()->createStaticGeometry( "sg" + Ogre::StringConverter::toString(uniqueID));
|
||||
uniqueID = uniqueID+1;
|
||||
sg = mRenderer.getScene()->createStaticGeometry("sg" + Ogre::StringConverter::toString(uniqueID));
|
||||
mStaticGeometry[ptr.getCell()] = sg;
|
||||
}
|
||||
else
|
||||
@ -225,155 +138,75 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh, bool
|
||||
|
||||
sg->setRenderQueueGroup(RQG_Main);
|
||||
|
||||
std::vector<Ogre::Entity*>::reverse_iterator iter = objects.mEntities.rbegin();
|
||||
while(iter != objects.mEntities.rend())
|
||||
{
|
||||
Ogre::Node *node = (*iter)->getParentNode();
|
||||
sg->addEntity(*iter, node->_getDerivedPosition(), node->_getDerivedOrientation(), node->_getDerivedScale());
|
||||
|
||||
(*iter)->detachFromParent();
|
||||
mRenderer.getScene()->destroyEntity(*iter);
|
||||
++iter;
|
||||
}
|
||||
anim->fillBatch(sg);
|
||||
/* 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
|
||||
* it. Would require associating the Ptr with the StaticGeometry. */
|
||||
anim.reset();
|
||||
}
|
||||
|
||||
if (light)
|
||||
{
|
||||
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);
|
||||
if(anim.get() != NULL)
|
||||
mObjects.insert(std::make_pair(ptr, anim.release()));
|
||||
}
|
||||
|
||||
bool Objects::deleteObject (const MWWorld::Ptr& ptr)
|
||||
{
|
||||
if (Ogre::SceneNode *base = ptr.getRefData().getBaseNode())
|
||||
if(!ptr.getRefData().getBaseNode())
|
||||
return true;
|
||||
|
||||
PtrAnimationMap::iterator iter = mObjects.find(ptr);
|
||||
if(iter != mObjects.end())
|
||||
{
|
||||
Ogre::SceneNode *parent = base->getParentSceneNode();
|
||||
delete iter->second;
|
||||
mObjects.erase(iter);
|
||||
|
||||
for (std::map<MWWorld::Ptr::CellStore *, Ogre::SceneNode *>::const_iterator iter (
|
||||
mCellSceneNodes.begin()); iter!=mCellSceneNodes.end(); ++iter)
|
||||
if (iter->second==parent)
|
||||
{
|
||||
clearSceneNode (base);
|
||||
base->removeAndDestroyAllChildren();
|
||||
mRenderer.getScene()->destroySceneNode (base);
|
||||
ptr.getRefData().setBaseNode (0);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
mRenderer.getScene()->destroySceneNode(ptr.getRefData().getBaseNode());
|
||||
ptr.getRefData().setBaseNode(0);
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
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];
|
||||
|
||||
for (int i=0; i<base->numChildren(); ++i)
|
||||
clearSceneNode (static_cast<Ogre::SceneNode *> (base->getChild (i)));
|
||||
|
||||
base->removeAndDestroyAllChildren();
|
||||
mCellSceneNodes.erase(store);
|
||||
mRenderer.getScene()->destroySceneNode(base);
|
||||
base = 0;
|
||||
if(iter->first.getCell() == store)
|
||||
{
|
||||
delete iter->second;
|
||||
mObjects.erase(iter++);
|
||||
}
|
||||
else
|
||||
++iter;
|
||||
}
|
||||
|
||||
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];
|
||||
mStaticGeometry.erase(store);
|
||||
mRenderer.getScene()->destroyStaticGeometry (sg);
|
||||
sg = 0;
|
||||
Ogre::StaticGeometry *sg = geom->second;
|
||||
mStaticGeometry.erase(geom);
|
||||
mRenderer.getScene()->destroyStaticGeometry(sg);
|
||||
}
|
||||
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);
|
||||
mRenderer.getScene()->destroyStaticGeometry (sg);
|
||||
sg = 0;
|
||||
mRenderer.getScene()->destroyStaticGeometry(sg);
|
||||
}
|
||||
|
||||
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)
|
||||
@ -397,146 +230,23 @@ Ogre::AxisAlignedBox Objects::getDimensions(MWWorld::Ptr::CellStore* cell)
|
||||
|
||||
void Objects::enableLights()
|
||||
{
|
||||
std::vector<LightInfo>::iterator it = mLights.begin();
|
||||
while (it != mLights.end())
|
||||
{
|
||||
if (mRootNode->getCreator()->hasLight(it->name))
|
||||
{
|
||||
mRootNode->getCreator()->getLight(it->name)->setVisible(true);
|
||||
++it;
|
||||
}
|
||||
else
|
||||
it = mLights.erase(it);
|
||||
}
|
||||
PtrAnimationMap::const_iterator it = mObjects.begin();
|
||||
for(;it != mObjects.end();it++)
|
||||
it->second->enableLights(true);
|
||||
}
|
||||
|
||||
void Objects::disableLights()
|
||||
{
|
||||
std::vector<LightInfo>::iterator it = mLights.begin();
|
||||
while (it != mLights.end())
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
PtrAnimationMap::const_iterator it = mObjects.begin();
|
||||
for(;it != mObjects.end();it++)
|
||||
it->second->enableLights(false);
|
||||
}
|
||||
|
||||
void Objects::update(const float dt)
|
||||
{
|
||||
std::vector<LightInfo>::iterator it = mLights.begin();
|
||||
while (it != mLights.end())
|
||||
{
|
||||
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);
|
||||
}
|
||||
PtrAnimationMap::const_iterator it = mObjects.begin();
|
||||
for(;it != mObjects.end();it++)
|
||||
it->second->runAnimation(dt);
|
||||
}
|
||||
|
||||
void Objects::rebuildStaticGeometry()
|
||||
|
@ -5,7 +5,6 @@
|
||||
#include <OgreAxisAlignedBox.h>
|
||||
|
||||
#include <openengine/ogre/renderer.hpp>
|
||||
#include "../mwworld/fallback.hpp"
|
||||
|
||||
namespace MWWorld
|
||||
{
|
||||
@ -15,72 +14,32 @@ namespace MWWorld
|
||||
|
||||
namespace MWRender{
|
||||
|
||||
/// information about light needed for rendering
|
||||
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 ObjectAnimation;
|
||||
|
||||
class Objects{
|
||||
typedef std::map<MWWorld::Ptr,ObjectAnimation*> PtrAnimationMap;
|
||||
|
||||
OEngine::Render::OgreRenderer &mRenderer;
|
||||
std::map<MWWorld::CellStore *, Ogre::SceneNode *> mCellSceneNodes;
|
||||
std::map<MWWorld::CellStore *, Ogre::StaticGeometry*> mStaticGeometry;
|
||||
std::map<MWWorld::CellStore *, Ogre::StaticGeometry*> mStaticGeometrySmall;
|
||||
std::map<MWWorld::CellStore *, Ogre::AxisAlignedBox> mBounds;
|
||||
std::vector<LightInfo> mLights;
|
||||
|
||||
std::map<MWWorld::CellStore*,Ogre::SceneNode*> mCellSceneNodes;
|
||||
std::map<MWWorld::CellStore*,Ogre::StaticGeometry*> mStaticGeometry;
|
||||
std::map<MWWorld::CellStore*,Ogre::StaticGeometry*> mStaticGeometrySmall;
|
||||
std::map<MWWorld::CellStore*,Ogre::AxisAlignedBox> mBounds;
|
||||
PtrAnimationMap mObjects;
|
||||
|
||||
Ogre::SceneNode* mRootNode;
|
||||
bool mIsStatic;
|
||||
|
||||
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.
|
||||
void insertBegin(const MWWorld::Ptr& ptr);
|
||||
|
||||
public:
|
||||
Objects(OEngine::Render::OgreRenderer& renderer, MWWorld::Fallback* fallback)
|
||||
: mRenderer (renderer)
|
||||
, mIsStatic(false)
|
||||
, mFallback(fallback)
|
||||
Objects(OEngine::Render::OgreRenderer &renderer)
|
||||
: mRenderer(renderer)
|
||||
, mRootNode(NULL)
|
||||
{}
|
||||
~Objects(){}
|
||||
void insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_);
|
||||
void insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh, bool light=false);
|
||||
void insertLight (const MWWorld::Ptr& ptr, Ogre::Entity *skelBase=0, Ogre::Vector3 fallbackCenter=Ogre::Vector3(0.0f));
|
||||
void insertModel(const MWWorld::Ptr& ptr, const std::string &model);
|
||||
|
||||
void enableLights();
|
||||
void disableLights();
|
||||
|
@ -57,7 +57,7 @@ RenderingManager::RenderingManager(OEngine::Render::OgreRenderer& _rend, const b
|
||||
MWWorld::Fallback* fallback)
|
||||
: mRendering(_rend)
|
||||
, mFallback(fallback)
|
||||
, mObjects(mRendering, mFallback)
|
||||
, mObjects(mRendering)
|
||||
, mActors(mRendering, this)
|
||||
, mPlayerAnimation(NULL)
|
||||
, mAmbientMode(0)
|
||||
|
@ -45,7 +45,7 @@ namespace MWRender
|
||||
// Setting this to 0 seems to cause glitches though. :/
|
||||
mTerrainGlobals->setMaxPixelError(1);
|
||||
|
||||
mTerrainGlobals->setLayerBlendMapSize(32);
|
||||
mTerrainGlobals->setLayerBlendMapSize(ESM::Land::LAND_TEXTURE_SIZE/2 + 1);
|
||||
|
||||
//10 (default) didn't seem to be quite enough
|
||||
mTerrainGlobals->setSkirtSize(128);
|
||||
@ -246,9 +246,9 @@ namespace MWRender
|
||||
//cells which may lead to inconsistent results when shading between cells
|
||||
int num = MWBase::Environment::get().getWorld()->getStore().get<ESM::LandTexture>().getSize(plugin);
|
||||
std::set<uint16_t> ltexIndexes;
|
||||
for ( int y = fromY - 1; y < fromY + size + 1; y++ )
|
||||
for ( int y = fromY; y < fromY + size + 1; y++ )
|
||||
{
|
||||
for ( int x = fromX - 1; x < fromX + size + 1; x++ )
|
||||
for ( int x = fromX - 1; x < fromX + size; x++ ) // NB we wrap X from the other side because Y is reversed
|
||||
{
|
||||
int idx = getLtexIndexAt(cellX, cellY, x, y);
|
||||
// This is a quick hack to prevent the program from trying to fetch textures
|
||||
@ -340,7 +340,6 @@ namespace MWRender
|
||||
assert( (size & (size - 1)) == 0 && "Size must be a power of 2");
|
||||
|
||||
const int blendMapSize = terrain->getLayerBlendMapSize();
|
||||
const int splatSize = blendMapSize / size;
|
||||
|
||||
//zero out every map
|
||||
std::map<uint16_t, int>::const_iterator iter;
|
||||
@ -352,9 +351,9 @@ namespace MWRender
|
||||
}
|
||||
|
||||
//covert the ltex data into a set of blend maps
|
||||
for ( int texY = fromY - 1; texY < fromY + size + 1; texY++ )
|
||||
for ( int texY = fromY; texY < fromY + size + 1; texY++ )
|
||||
{
|
||||
for ( int texX = fromX - 1; texX < fromX + size + 1; texX++ )
|
||||
for ( int texX = fromX - 1; texX < fromX + size; texX++ ) // NB we wrap X from the other side because Y is reversed
|
||||
{
|
||||
const uint16_t ltexIndex = getLtexIndexAt(cellX, cellY, texX, texY);
|
||||
|
||||
@ -367,7 +366,7 @@ namespace MWRender
|
||||
|
||||
//while texX is the splat index relative to the entire cell,
|
||||
//relX is relative to the current segment we are splatting
|
||||
const int relX = texX - fromX;
|
||||
const int relX = texX - fromX + 1;
|
||||
const int relY = texY - fromY;
|
||||
|
||||
const int layerIndex = indexes.find(ltexIndex)->second;
|
||||
@ -375,35 +374,15 @@ namespace MWRender
|
||||
float* const pBlend = terrain->getLayerBlendMap(layerIndex)
|
||||
->getBlendPointer();
|
||||
|
||||
for ( int y = -1; y < splatSize + 1; y++ )
|
||||
{
|
||||
for ( int x = -1; x < splatSize + 1; x++ )
|
||||
{
|
||||
|
||||
//Note: Y is reversed
|
||||
const int splatY = blendMapSize - 1 - relY * splatSize - y;
|
||||
const int splatX = relX * splatSize + x;
|
||||
const int splatY = blendMapSize - relY - 1;
|
||||
const int splatX = relX;
|
||||
|
||||
if ( splatX >= 0 && splatX < blendMapSize &&
|
||||
splatY >= 0 && splatY < blendMapSize )
|
||||
{
|
||||
const int index = (splatY)*blendMapSize + splatX;
|
||||
assert(splatX >= 0 && splatX < blendMapSize);
|
||||
assert(splatY >= 0 && splatY < blendMapSize);
|
||||
|
||||
if ( y >= 0 && y < splatSize &&
|
||||
x >= 0 && x < splatSize )
|
||||
{
|
||||
pBlend[index] = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
//this provides a transition shading but also
|
||||
//rounds off the corners slightly
|
||||
pBlend[index] = std::min(1.0f, pBlend[index] + 0.5f);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
const int index = (splatY)*blendMapSize + splatX;
|
||||
pBlend[index] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11,10 +11,6 @@
|
||||
|
||||
#include "../mwmechanics/movement.hpp"
|
||||
#include "../mwmechanics/npcstats.hpp"
|
||||
#include "../mwmechanics/character.hpp"
|
||||
#include "../mwmechanics/security.hpp"
|
||||
|
||||
#include "../mwrender/animation.hpp"
|
||||
|
||||
#include "class.hpp"
|
||||
|
||||
@ -144,51 +140,6 @@ namespace MWWorld
|
||||
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()
|
||||
{
|
||||
MWWorld::Ptr ptr = getPlayer();
|
||||
|
@ -58,9 +58,6 @@ namespace MWWorld
|
||||
void setForwardBackward (int value);
|
||||
void setUpDown(int value);
|
||||
|
||||
void use ();
|
||||
///< Use item equipped on right hand, or fists
|
||||
|
||||
void setRunState(bool run);
|
||||
void setSneak(bool sneak);
|
||||
|
||||
|
@ -74,7 +74,7 @@ namespace MWWorld
|
||||
|
||||
bool isInCell() const
|
||||
{
|
||||
return (mContainerStore == 0);
|
||||
return (mContainerStore == 0) && (mCell != 0);
|
||||
}
|
||||
|
||||
void setContainerStore (ContainerStore *store);
|
||||
|
@ -1566,6 +1566,17 @@ namespace MWWorld
|
||||
return false;
|
||||
}
|
||||
|
||||
bool World::isSubmerged(const MWWorld::Ptr &object) const
|
||||
{
|
||||
float *fpos = object.getRefData().getPosition().pos;
|
||||
Ogre::Vector3 pos(fpos[0], fpos[1], fpos[2]);
|
||||
|
||||
const OEngine::Physic::PhysicActor *actor = mPhysEngine->getCharacter(object.getRefData().getHandle());
|
||||
if(actor) pos.z += 1.85*actor->getHalfExtents().z;
|
||||
|
||||
return isUnderwater(object.getCell(), pos);
|
||||
}
|
||||
|
||||
bool
|
||||
World::isSwimming(const MWWorld::Ptr &object) const
|
||||
{
|
||||
|
@ -348,6 +348,8 @@ namespace MWWorld
|
||||
virtual void processChangedSettings(const Settings::CategorySettingVector& settings);
|
||||
|
||||
virtual bool isFlying(const MWWorld::Ptr &ptr) const;
|
||||
///Is the head of the creature underwater?
|
||||
virtual bool isSubmerged(const MWWorld::Ptr &object) const;
|
||||
virtual bool isSwimming(const MWWorld::Ptr &object) const;
|
||||
virtual bool isUnderwater(const MWWorld::Ptr::CellStore* cell, const Ogre::Vector3 &pos) const;
|
||||
virtual bool isOnGround(const MWWorld::Ptr &ptr) const;
|
||||
|
@ -43,6 +43,7 @@ struct ObjectList {
|
||||
Ogre::Entity *mSkelBase;
|
||||
std::vector<Ogre::Entity*> mEntities;
|
||||
std::vector<Ogre::ParticleSystem*> mParticles;
|
||||
std::vector<Ogre::Light*> mLights;
|
||||
|
||||
std::map<int,TextKeyMap> mTextKeys;
|
||||
|
||||
|
@ -205,7 +205,6 @@
|
||||
shUniform(float, waterLevel) @shSharedParameter(waterLevel)
|
||||
#endif
|
||||
|
||||
|
||||
SH_START_PROGRAM
|
||||
{
|
||||
|
||||
@ -232,35 +231,46 @@ float previousAlpha = 1.f;
|
||||
#endif
|
||||
|
||||
// Layer calculations
|
||||
// rescale UV to directly map vertices to texel centers
|
||||
// TODO: parameterize texel size
|
||||
float2 blendUV = (UV - 0.5) * (8.0 / (8.0+1.0)) + 0.5;
|
||||
@shForeach(@shPropertyString(num_blendmaps))
|
||||
float4 blendValues@shIterator = shSample(blendMap@shIterator, UV);
|
||||
float4 blendValues@shIterator = shSample(blendMap@shIterator, blendUV);
|
||||
@shEndForeach
|
||||
|
||||
float3 albedo = float3(0,0,0);
|
||||
|
||||
float2 layerUV = UV * 8;
|
||||
|
||||
@shForeach(@shPropertyString(num_layers))
|
||||
|
||||
|
||||
#if IS_FIRST_PASS
|
||||
#if @shIterator == 0
|
||||
// first layer of first pass is the base layer and doesn't need a blend map
|
||||
albedo = shSample(diffuseMap0, UV * 10).rgb;
|
||||
albedo = shSample(diffuseMap0, layerUV).rgb;
|
||||
#else
|
||||
albedo = shLerp(albedo, shSample(diffuseMap@shIterator, UV * 10).rgb, blendValues@shPropertyString(blendmap_component_@shIterator));
|
||||
albedo = shLerp(albedo, shSample(diffuseMap@shIterator, layerUV).rgb, blendValues@shPropertyString(blendmap_component_@shIterator));
|
||||
#endif
|
||||
#else
|
||||
#if @shIterator == 0
|
||||
albedo = shSample(diffuseMap@shIterator, UV * 10).rgb, blendValues@shPropertyString(blendmap_component_@shIterator);
|
||||
albedo = shSample(diffuseMap@shIterator, layerUV).rgb, blendValues@shPropertyString(blendmap_component_@shIterator);
|
||||
#else
|
||||
albedo = shLerp(albedo, shSample(diffuseMap@shIterator, UV * 10).rgb, blendValues@shPropertyString(blendmap_component_@shIterator));
|
||||
albedo = shLerp(albedo, shSample(diffuseMap@shIterator, layerUV).rgb, blendValues@shPropertyString(blendmap_component_@shIterator));
|
||||
#endif
|
||||
previousAlpha *= 1.f-blendValues@shPropertyString(blendmap_component_@shIterator);
|
||||
#endif
|
||||
@shEndForeach
|
||||
|
||||
shOutputColour(0) = float4(1,1,1,1);
|
||||
|
||||
|
||||
#if COLOUR_MAP
|
||||
shOutputColour(0).rgb *= shSample(colourMap, UV).rgb;
|
||||
// Since we're emulating vertex colors here,
|
||||
// rescale UV to directly map vertices to texel centers. TODO: parameterize texel size
|
||||
const float colourmapSize = 33.f;
|
||||
float2 colourUV = (UV - 0.5) * (colourmapSize / (colourmapSize+1.f)) + 0.5;
|
||||
shOutputColour(0).rgb *= shSample(colourMap, colourUV).rgb;
|
||||
#endif
|
||||
|
||||
shOutputColour(0).rgb *= albedo;
|
||||
@ -347,6 +357,7 @@ float previousAlpha = 1.f;
|
||||
#else
|
||||
shOutputColour(0).a = 1.f-previousAlpha;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -32,7 +32,21 @@
|
||||
<Property key="NeedMouse" value="false"/>
|
||||
</Widget>
|
||||
</Widget>
|
||||
|
||||
|
||||
<!-- Drowning bar -->
|
||||
<Widget type="Widget" skin="HUD_Box" position="0 36 220 56" align="Center Top" name="DrowningFrame">
|
||||
<Property key="Visible" value="false"/>
|
||||
<Widget type="TextBox" skin="SandText" position="0 8 220 24" name="DrowningTitle" align="Center Top HStretch">
|
||||
<Property key="Caption" value="#{sBreath}"/>
|
||||
<Property key="TextAlign" value="Center"/>
|
||||
<Property key="TextShadow" value="true"/>
|
||||
<Property key="TextShadowColour" value="0 0 0"/>
|
||||
</Widget>
|
||||
<Widget type="ProgressBar" skin="MW_Progress_Loading" position="12 36 196 8" align="Center Top" name="Drowning">
|
||||
<Property key="NeedMouse" value="false"/>
|
||||
</Widget>
|
||||
</Widget>
|
||||
|
||||
<!-- Equipped weapon/selected spell name display for a few seconds after it changes -->
|
||||
<Widget type="TextBox" skin="SandText" position="13 118 270 24" name="WeaponSpellName" align="Left Bottom HStretch">
|
||||
<Property key="Visible" value="false"/>
|
||||
|
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 <OgreSubEntity.h>
|
||||
#include <OgreEntity.h>
|
||||
#include <OgreTechnique.h>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <extern/shiny/Main/Factory.hpp>
|
||||
@ -100,7 +101,16 @@ namespace Render
|
||||
return m->getTechnique(1);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user