mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-03-03 01:49:41 +00:00
Merge remote-tracking branch 'scrawl/master'
This commit is contained in:
commit
85965bfd47
56 changed files with 987 additions and 367 deletions
|
@ -228,6 +228,7 @@ namespace MWBase
|
|||
virtual void showCrosshair(bool show) = 0;
|
||||
virtual bool getSubtitlesEnabled() = 0;
|
||||
virtual void toggleHud() = 0;
|
||||
virtual bool toggleGui() = 0;
|
||||
|
||||
virtual void disallowMouse() = 0;
|
||||
virtual void allowMouse() = 0;
|
||||
|
|
|
@ -521,6 +521,12 @@ namespace MWBase
|
|||
const MWWorld::Ptr& caster, const std::string& id, const std::string& sourceName) = 0;
|
||||
|
||||
virtual void activate (const MWWorld::Ptr& object, const MWWorld::Ptr& actor) = 0;
|
||||
|
||||
/// @see MWWorld::WeatherManager::isInStorm
|
||||
virtual bool isInStorm() const = 0;
|
||||
|
||||
/// @see MWWorld::WeatherManager::getStormDirection
|
||||
virtual Ogre::Vector3 getStormDirection() const = 0;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -537,8 +537,8 @@ namespace MWClass
|
|||
|
||||
bool running = ptr.getClass().getCreatureStats(ptr).getStance(MWMechanics::CreatureStats::Stance_Run);
|
||||
|
||||
float runSpeed = walkSpeed*6;
|
||||
runSpeed = std::min(gmst.fMaxWalkSpeedCreature->getFloat(), runSpeed); // flame atronach runs way too fast without this
|
||||
// The Run speed difference for creatures comes from the animation speed difference (see runStateToWalkState in character.cpp)
|
||||
float runSpeed = walkSpeed;
|
||||
|
||||
float moveSpeed;
|
||||
if(normalizedEncumbrance >= 1.0f)
|
||||
|
|
|
@ -431,6 +431,9 @@ namespace MWGui
|
|||
{
|
||||
mGlobalMapRender = new MWRender::GlobalMap("");
|
||||
mGlobalMapRender->render(loadingListener);
|
||||
mGlobalMap->setCanvasSize (mGlobalMapRender->getWidth(), mGlobalMapRender->getHeight());
|
||||
mGlobalMapImage->setSize(mGlobalMapRender->getWidth(), mGlobalMapRender->getHeight());
|
||||
|
||||
mGlobalMapImage->setImageTexture("GlobalMap.png");
|
||||
mGlobalMapOverlay->setImageTexture("GlobalMapOverlay");
|
||||
}
|
||||
|
@ -512,7 +515,6 @@ namespace MWGui
|
|||
else
|
||||
mGlobalMap->setViewOffset( mGlobalMap->getViewOffset() + diff );
|
||||
|
||||
|
||||
mLastDragPos = MyGUI::IntPoint(_left, _top);
|
||||
}
|
||||
|
||||
|
@ -536,9 +538,6 @@ namespace MWGui
|
|||
|
||||
void MapWindow::open()
|
||||
{
|
||||
mGlobalMap->setCanvasSize (mGlobalMapRender->getWidth(), mGlobalMapRender->getHeight());
|
||||
mGlobalMapImage->setSize(mGlobalMapRender->getWidth(), mGlobalMapRender->getHeight());
|
||||
|
||||
// force markers to foreground
|
||||
for (unsigned int i=0; i<mGlobalMapOverlay->getChildCount (); ++i)
|
||||
{
|
||||
|
|
|
@ -118,6 +118,7 @@ namespace MWGui
|
|||
, mCrosshairEnabled(Settings::Manager::getBool ("crosshair", "HUD"))
|
||||
, mSubtitlesEnabled(Settings::Manager::getBool ("subtitles", "GUI"))
|
||||
, mHudEnabled(true)
|
||||
, mGuiEnabled(true)
|
||||
, mCursorVisible(true)
|
||||
, mPlayerName()
|
||||
, mPlayerRaceId()
|
||||
|
@ -420,7 +421,7 @@ namespace MWGui
|
|||
mRecharge->setVisible(false);
|
||||
mVideoBackground->setVisible(false);
|
||||
|
||||
mHud->setVisible(mHudEnabled);
|
||||
mHud->setVisible(mHudEnabled && mGuiEnabled);
|
||||
|
||||
bool gameMode = !isGuiMode();
|
||||
|
||||
|
@ -430,6 +431,13 @@ namespace MWGui
|
|||
if (gameMode)
|
||||
setKeyFocusWidget (NULL);
|
||||
|
||||
if (!mGuiEnabled)
|
||||
{
|
||||
if (containsMode(GM_Console))
|
||||
mConsole->setVisible(true);
|
||||
return;
|
||||
}
|
||||
|
||||
// Icons of forced hidden windows are displayed
|
||||
setMinimapVisibility((mAllowed & GW_Map) && (!mMap->pinned() || (mForceHidden & GW_Map)));
|
||||
setWeaponVisibility((mAllowed & GW_Inventory) && (!mInventoryWindow->pinned() || (mForceHidden & GW_Inventory)));
|
||||
|
@ -1345,6 +1353,13 @@ namespace MWGui
|
|||
mHud->setVisible (mHudEnabled);
|
||||
}
|
||||
|
||||
bool WindowManager::toggleGui()
|
||||
{
|
||||
mGuiEnabled = !mGuiEnabled;
|
||||
updateVisible();
|
||||
return mGuiEnabled;
|
||||
}
|
||||
|
||||
bool WindowManager::getRestEnabled()
|
||||
{
|
||||
//Enable rest dialogue if character creation finished
|
||||
|
|
|
@ -223,6 +223,9 @@ namespace MWGui
|
|||
virtual bool getSubtitlesEnabled();
|
||||
virtual void toggleHud();
|
||||
|
||||
/// Turn visibility of *all* GUI elements on or off (HUD and all windows, except the console)
|
||||
virtual bool toggleGui();
|
||||
|
||||
virtual void disallowMouse();
|
||||
virtual void allowMouse();
|
||||
virtual void notifyInputActionBound();
|
||||
|
@ -381,6 +384,7 @@ namespace MWGui
|
|||
bool mCrosshairEnabled;
|
||||
bool mSubtitlesEnabled;
|
||||
bool mHudEnabled;
|
||||
bool mGuiEnabled;
|
||||
bool mCursorVisible;
|
||||
|
||||
void setCursorVisible(bool visible);
|
||||
|
|
|
@ -277,7 +277,7 @@ namespace MWInput
|
|||
showQuickKeysMenu();
|
||||
break;
|
||||
case A_ToggleHUD:
|
||||
MWBase::Environment::get().getWindowManager()->toggleHud();
|
||||
MWBase::Environment::get().getWindowManager()->toggleGui();
|
||||
break;
|
||||
case A_QuickSave:
|
||||
quickSave();
|
||||
|
|
|
@ -530,8 +530,12 @@ namespace MWMechanics
|
|||
itemGmst)->getString();
|
||||
if (it->first == ESM::MagicEffect::BoundGloves)
|
||||
{
|
||||
adjustBoundItem("sMagicBoundLeftGauntletID", magnitude > 0, ptr);
|
||||
adjustBoundItem("sMagicBoundRightGauntletID", magnitude > 0, ptr);
|
||||
item = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find(
|
||||
"sMagicBoundLeftGauntletID")->getString();
|
||||
adjustBoundItem(item, magnitude > 0, ptr);
|
||||
item = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find(
|
||||
"sMagicBoundRightGauntletID")->getString();
|
||||
adjustBoundItem(item, magnitude > 0, ptr);
|
||||
}
|
||||
else
|
||||
adjustBoundItem(item, magnitude > 0, ptr);
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "character.hpp"
|
||||
|
||||
#include <OgreStringConverter.h>
|
||||
#include <OgreSceneNode.h>
|
||||
|
||||
#include "movement.hpp"
|
||||
#include "npcstats.hpp"
|
||||
|
@ -54,6 +55,43 @@ std::string getBestAttack (const ESM::Weapon* weapon)
|
|||
return "thrust";
|
||||
}
|
||||
|
||||
// Converts a movement Run state to its equivalent Walk state.
|
||||
MWMechanics::CharacterState runStateToWalkState (MWMechanics::CharacterState state)
|
||||
{
|
||||
using namespace MWMechanics;
|
||||
CharacterState ret = state;
|
||||
switch (state)
|
||||
{
|
||||
case CharState_RunForward:
|
||||
ret = CharState_WalkForward;
|
||||
break;
|
||||
case CharState_RunBack:
|
||||
ret = CharState_WalkBack;
|
||||
break;
|
||||
case CharState_RunLeft:
|
||||
ret = CharState_WalkLeft;
|
||||
break;
|
||||
case CharState_RunRight:
|
||||
ret = CharState_WalkRight;
|
||||
break;
|
||||
case CharState_SwimRunForward:
|
||||
ret = CharState_SwimWalkForward;
|
||||
break;
|
||||
case CharState_SwimRunBack:
|
||||
ret = CharState_SwimWalkBack;
|
||||
break;
|
||||
case CharState_SwimRunLeft:
|
||||
ret = CharState_SwimWalkLeft;
|
||||
break;
|
||||
case CharState_SwimRunRight:
|
||||
ret = CharState_SwimWalkRight;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace MWMechanics
|
||||
|
@ -234,6 +272,8 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat
|
|||
1.0f, "start", "stop", 0.0f, ~0ul);
|
||||
}
|
||||
|
||||
updateIdleStormState();
|
||||
|
||||
if(force && mJumpState != JumpState_None)
|
||||
{
|
||||
std::string jump;
|
||||
|
@ -320,7 +360,18 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat
|
|||
|
||||
bool isrunning = mPtr.getClass().getCreatureStats(mPtr).getStance(MWMechanics::CreatureStats::Stance_Run);
|
||||
|
||||
if(mMovementSpeed > 0.0f && (vel=mAnimation->getVelocity(mCurrentMovement)) > 1.0f)
|
||||
// For non-flying creatures, MW uses the Walk animation to calculate the animation velocity
|
||||
// even if we are running. This must be replicated, otherwise the observed speed would differ drastically.
|
||||
std::string anim = mCurrentMovement;
|
||||
if (mPtr.getClass().getTypeName() == typeid(ESM::Creature).name()
|
||||
&& !(mPtr.get<ESM::Creature>()->mBase->mFlags & ESM::Creature::Flies))
|
||||
{
|
||||
CharacterState walkState = runStateToWalkState(mMovementState);
|
||||
const StateInfo *stateinfo = std::find_if(sMovementList, sMovementListEnd, FindCharState(walkState));
|
||||
anim = stateinfo->groupname;
|
||||
}
|
||||
|
||||
if(mMovementSpeed > 0.0f && (vel=mAnimation->getVelocity(anim)) > 1.0f)
|
||||
{
|
||||
mMovementAnimVelocity = vel;
|
||||
speedmult = mMovementSpeed / vel;
|
||||
|
@ -550,6 +601,45 @@ void CharacterController::updatePtr(const MWWorld::Ptr &ptr)
|
|||
mPtr = ptr;
|
||||
}
|
||||
|
||||
void CharacterController::updateIdleStormState()
|
||||
{
|
||||
bool inStormDirection = false;
|
||||
if (MWBase::Environment::get().getWorld()->isInStorm())
|
||||
{
|
||||
Ogre::Vector3 stormDirection = MWBase::Environment::get().getWorld()->getStormDirection();
|
||||
Ogre::Vector3 characterDirection = mPtr.getRefData().getBaseNode()->getOrientation().yAxis();
|
||||
inStormDirection = stormDirection.angleBetween(characterDirection) < Ogre::Degree(40);
|
||||
}
|
||||
if (inStormDirection && mUpperBodyState == UpperCharState_Nothing && mAnimation->hasAnimation("idlestorm"))
|
||||
{
|
||||
float complete = 0;
|
||||
mAnimation->getInfo("idlestorm", &complete);
|
||||
|
||||
if (complete == 0)
|
||||
mAnimation->play("idlestorm", Priority_Torch, MWRender::Animation::Group_RightArm, false,
|
||||
1.0f, "start", "loop start", 0.0f, 0);
|
||||
else if (complete == 1)
|
||||
mAnimation->play("idlestorm", Priority_Torch, MWRender::Animation::Group_RightArm, false,
|
||||
1.0f, "loop start", "loop stop", 0.0f, ~0ul);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mUpperBodyState == UpperCharState_Nothing)
|
||||
{
|
||||
if (mAnimation->isPlaying("idlestorm"))
|
||||
{
|
||||
if (mAnimation->getCurrentTime("idlestorm") < mAnimation->getTextKeyTime("idlestorm: loop stop"))
|
||||
{
|
||||
mAnimation->play("idlestorm", Priority_Torch, MWRender::Animation::Group_RightArm, true,
|
||||
1.0f, "loop stop", "stop", 0.0f, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
mAnimation->disable("idlestorm");
|
||||
}
|
||||
}
|
||||
|
||||
bool CharacterController::updateCreatureState()
|
||||
{
|
||||
const MWWorld::Class &cls = mPtr.getClass();
|
||||
|
|
|
@ -178,6 +178,7 @@ class CharacterController
|
|||
|
||||
bool updateWeaponState();
|
||||
bool updateCreatureState();
|
||||
void updateIdleStormState();
|
||||
|
||||
void updateVisibility();
|
||||
|
||||
|
|
|
@ -501,7 +501,8 @@ namespace MWMechanics
|
|||
{
|
||||
if (!playerStats.getExpelled(npcFaction))
|
||||
{
|
||||
reaction = playerStats.getFactionReputation(npcFaction);
|
||||
// faction reaction towards itself. yes, that exists
|
||||
reaction = MWBase::Environment::get().getDialogueManager()->getFactionReaction(npcFaction, npcFaction);
|
||||
|
||||
rank = playerStats.getFactionRanks().find(npcFaction)->second;
|
||||
}
|
||||
|
@ -1101,7 +1102,7 @@ namespace MWMechanics
|
|||
if (iter->first.getClass().isClass(iter->first, "Guard"))
|
||||
{
|
||||
MWMechanics::AiSequence& aiSeq = iter->first.getClass().getCreatureStats(iter->first).getAiSequence();
|
||||
if (aiSeq.getActivePackage()->getTypeId() == MWMechanics::AiPackage::TypeIdPursue)
|
||||
if (aiSeq.getTypeId() == MWMechanics::AiPackage::TypeIdPursue)
|
||||
{
|
||||
aiSeq.stopPursuit();
|
||||
aiSeq.stack(MWMechanics::AiCombat(target), ptr);
|
||||
|
@ -1112,7 +1113,7 @@ namespace MWMechanics
|
|||
}
|
||||
|
||||
// Must be done after the target is set up, so that CreatureTargetted dialogue filter works properly
|
||||
if (ptr.getClass().isNpc())
|
||||
if (ptr.getClass().isNpc() && !ptr.getClass().getCreatureStats(ptr).isDead())
|
||||
MWBase::Environment::get().getDialogueManager()->say(ptr, "attack");
|
||||
}
|
||||
|
||||
|
|
|
@ -1027,7 +1027,11 @@ Ogre::Vector3 Animation::runAnimation(float duration)
|
|||
|
||||
if(!state.mPlaying && state.mAutoDisable)
|
||||
{
|
||||
if(mNonAccumCtrl && stateiter->first == mAnimationTimePtr[0]->getAnimName())
|
||||
mAccumRoot->setPosition(0.f,0.f,0.f);
|
||||
|
||||
mStates.erase(stateiter++);
|
||||
|
||||
resetActiveGroups();
|
||||
}
|
||||
else
|
||||
|
@ -1169,20 +1173,68 @@ void Animation::addEffect(const std::string &model, int effectId, bool loop, con
|
|||
params.mObjects->mControllers[i].setSource(Ogre::SharedPtr<EffectAnimationTime> (new EffectAnimationTime()));
|
||||
}
|
||||
|
||||
if (!texture.empty())
|
||||
|
||||
// Do some manual adjustments on the created entities/particle systems
|
||||
|
||||
// It looks like vanilla MW totally ignores lighting settings for effects attached to characters.
|
||||
// If we don't do this, some effects will look way too dark depending on the environment
|
||||
// (e.g. magic_cast_dst.nif). They were clearly meant to use emissive lighting.
|
||||
// We used to have this hack in the NIF material loader, but for effects not attached to characters
|
||||
// (e.g. ash storms) the lighting settings do seem to be in use. Is there maybe a flag we have missed?
|
||||
Ogre::ColourValue ambient = Ogre::ColourValue(0.f, 0.f, 0.f);
|
||||
Ogre::ColourValue diffuse = Ogre::ColourValue(0.f, 0.f, 0.f);
|
||||
Ogre::ColourValue specular = Ogre::ColourValue(0.f, 0.f, 0.f);
|
||||
Ogre::ColourValue emissive = Ogre::ColourValue(1.f, 1.f, 1.f);
|
||||
for(size_t i = 0;i < params.mObjects->mParticles.size(); ++i)
|
||||
{
|
||||
for(size_t i = 0;i < params.mObjects->mParticles.size(); ++i)
|
||||
Ogre::ParticleSystem* partSys = params.mObjects->mParticles[i];
|
||||
|
||||
Ogre::MaterialPtr mat = params.mObjects->mMaterialControllerMgr.getWritableMaterial(partSys);
|
||||
|
||||
for (int t=0; t<mat->getNumTechniques(); ++t)
|
||||
{
|
||||
Ogre::ParticleSystem* partSys = params.mObjects->mParticles[i];
|
||||
|
||||
Ogre::MaterialPtr mat = params.mObjects->mMaterialControllerMgr.getWritableMaterial(partSys);
|
||||
|
||||
for (int t=0; t<mat->getNumTechniques(); ++t)
|
||||
Ogre::Technique* tech = mat->getTechnique(t);
|
||||
for (int p=0; p<tech->getNumPasses(); ++p)
|
||||
{
|
||||
Ogre::Technique* tech = mat->getTechnique(t);
|
||||
for (int p=0; p<tech->getNumPasses(); ++p)
|
||||
Ogre::Pass* pass = tech->getPass(p);
|
||||
|
||||
pass->setAmbient(ambient);
|
||||
pass->setDiffuse(diffuse);
|
||||
pass->setSpecular(specular);
|
||||
pass->setEmissive(emissive);
|
||||
|
||||
if (!texture.empty())
|
||||
{
|
||||
for (int tex=0; tex<pass->getNumTextureUnitStates(); ++tex)
|
||||
{
|
||||
Ogre::TextureUnitState* tus = pass->getTextureUnitState(tex);
|
||||
tus->setTextureName("textures\\" + texture);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for(size_t i = 0;i < params.mObjects->mEntities.size(); ++i)
|
||||
{
|
||||
Ogre::Entity* ent = params.mObjects->mEntities[i];
|
||||
if (ent == params.mObjects->mSkelBase)
|
||||
continue;
|
||||
Ogre::MaterialPtr mat = params.mObjects->mMaterialControllerMgr.getWritableMaterial(ent);
|
||||
|
||||
for (int t=0; t<mat->getNumTechniques(); ++t)
|
||||
{
|
||||
Ogre::Technique* tech = mat->getTechnique(t);
|
||||
for (int p=0; p<tech->getNumPasses(); ++p)
|
||||
{
|
||||
Ogre::Pass* pass = tech->getPass(p);
|
||||
|
||||
pass->setAmbient(ambient);
|
||||
pass->setDiffuse(diffuse);
|
||||
pass->setSpecular(specular);
|
||||
pass->setEmissive(emissive);
|
||||
|
||||
if (!texture.empty())
|
||||
{
|
||||
Ogre::Pass* pass = tech->getPass(p);
|
||||
for (int tex=0; tex<pass->getNumTextureUnitStates(); ++tex)
|
||||
{
|
||||
Ogre::TextureUnitState* tus = pass->getTextureUnitState(tex);
|
||||
|
|
|
@ -62,6 +62,12 @@ namespace MWRender
|
|||
loadingListener->setProgressRange((mMaxX-mMinX+1) * (mMaxY-mMinY+1));
|
||||
loadingListener->setProgress(0);
|
||||
|
||||
const Ogre::ColourValue waterShallowColour(0.15, 0.2, 0.19);
|
||||
const Ogre::ColourValue waterDeepColour(0.1, 0.14, 0.13);
|
||||
const Ogre::ColourValue groundColour(0.254, 0.19, 0.13);
|
||||
const Ogre::ColourValue mountainColour(0.05, 0.05, 0.05);
|
||||
const Ogre::ColourValue hillColour(0.16, 0.12, 0.08);
|
||||
|
||||
//if (!boost::filesystem::exists(mCacheDir + "/GlobalMap.png"))
|
||||
if (1)
|
||||
{
|
||||
|
@ -91,12 +97,6 @@ namespace MWRender
|
|||
int texelX = (x-mMinX) * cellSize + cellX;
|
||||
int texelY = (mHeight-1) - ((y-mMinY) * cellSize + cellY);
|
||||
|
||||
Ogre::ColourValue waterShallowColour(0.15, 0.2, 0.19);
|
||||
Ogre::ColourValue waterDeepColour(0.1, 0.14, 0.13);
|
||||
Ogre::ColourValue groundColour(0.254, 0.19, 0.13);
|
||||
Ogre::ColourValue mountainColour(0.05, 0.05, 0.05);
|
||||
Ogre::ColourValue hillColour(0.16, 0.12, 0.08);
|
||||
|
||||
unsigned char r,g,b;
|
||||
|
||||
if (land)
|
||||
|
|
|
@ -506,10 +506,19 @@ void RenderingManager::configureFog(const float density, const Ogre::ColourValue
|
|||
mFogColour = colour;
|
||||
float max = Settings::Manager::getFloat("max viewing distance", "Viewing distance");
|
||||
|
||||
mFogStart = max / (density) * Settings::Manager::getFloat("fog start factor", "Viewing distance");
|
||||
mFogEnd = max / (density) * Settings::Manager::getFloat("fog end factor", "Viewing distance");
|
||||
if (density == 0)
|
||||
{
|
||||
mFogStart = 0;
|
||||
mFogEnd = std::numeric_limits<float>().max();
|
||||
mRendering.getCamera()->setFarClipDistance (max);
|
||||
}
|
||||
else
|
||||
{
|
||||
mFogStart = max / (density) * Settings::Manager::getFloat("fog start factor", "Viewing distance");
|
||||
mFogEnd = max / (density) * Settings::Manager::getFloat("fog end factor", "Viewing distance");
|
||||
mRendering.getCamera()->setFarClipDistance (max / density);
|
||||
}
|
||||
|
||||
mRendering.getCamera()->setFarClipDistance ( Settings::Manager::getFloat("max viewing distance", "Viewing distance") / density );
|
||||
}
|
||||
|
||||
void RenderingManager::applyFog (bool underwater)
|
||||
|
|
|
@ -8,10 +8,11 @@
|
|||
#include <OgreSceneManager.h>
|
||||
#include <OgreHardwareVertexBuffer.h>
|
||||
#include <OgreHighLevelGpuProgramManager.h>
|
||||
#include <OgreBillboardSet.h>
|
||||
#include <OgreParticleSystem.h>
|
||||
#include <OgreEntity.h>
|
||||
#include <OgreSubEntity.h>
|
||||
#include <OgreTechnique.h>
|
||||
#include <OgreControllerManager.h>
|
||||
|
||||
#include <OgreMeshManager.h>
|
||||
|
||||
|
@ -234,6 +235,7 @@ SkyManager::SkyManager(Ogre::SceneNode *root, Ogre::Camera *pCamera)
|
|||
, mCreated(false)
|
||||
, mCloudAnimationTimer(0.f)
|
||||
, mMoonRed(false)
|
||||
, mParticleNode(NULL)
|
||||
{
|
||||
mSceneMgr = root->getCreator();
|
||||
mRootNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();
|
||||
|
@ -372,6 +374,12 @@ void SkyManager::update(float duration)
|
|||
if (!mEnabled) return;
|
||||
const MWWorld::Fallback* fallback=MWBase::Environment::get().getWorld()->getFallback();
|
||||
|
||||
if (!mParticle.isNull())
|
||||
{
|
||||
for (unsigned int i=0; i<mParticle->mControllers.size(); ++i)
|
||||
mParticle->mControllers[i].update();
|
||||
}
|
||||
|
||||
// UV Scroll the clouds
|
||||
mCloudAnimationTimer += duration * mCloudSpeed;
|
||||
sh::Factory::getInstance().setSharedParameter ("cloudAnimationTimer",
|
||||
|
@ -441,6 +449,37 @@ void SkyManager::setWeather(const MWWorld::WeatherResult& weather)
|
|||
{
|
||||
if (!mCreated) return;
|
||||
|
||||
if (mCurrentParticleEffect != weather.mParticleEffect)
|
||||
{
|
||||
mCurrentParticleEffect = weather.mParticleEffect;
|
||||
|
||||
if (mCurrentParticleEffect.empty())
|
||||
{
|
||||
mParticle.setNull();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!mParticleNode)
|
||||
{
|
||||
mParticleNode = mCamera->getParentSceneNode()->createChildSceneNode(Ogre::Vector3(0,0,100));
|
||||
mParticleNode->setInheritOrientation(false);
|
||||
}
|
||||
|
||||
mParticle = NifOgre::Loader::createObjects(mParticleNode, mCurrentParticleEffect);
|
||||
for(size_t i = 0; i < mParticle->mParticles.size(); ++i)
|
||||
{
|
||||
ParticleSystem* particle = mParticle->mParticles[i];
|
||||
particle->setRenderQueueGroup(RQG_Alpha);
|
||||
particle->setVisibilityFlags(RV_Sky);
|
||||
}
|
||||
for (size_t i = 0; i < mParticle->mControllers.size(); ++i)
|
||||
{
|
||||
if (mParticle->mControllers[i].getSource().isNull())
|
||||
mParticle->mControllers[i].setSource(Ogre::ControllerManager::getSingleton().getFrameTimeSource());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mClouds != weather.mCloudTexture)
|
||||
{
|
||||
sh::Factory::getInstance().setTextureAlias ("cloud_texture_1", "textures\\"+weather.mCloudTexture);
|
||||
|
|
|
@ -200,6 +200,9 @@ namespace MWRender
|
|||
|
||||
std::vector<NifOgre::ObjectScenePtr> mObjects;
|
||||
|
||||
Ogre::SceneNode* mParticleNode;
|
||||
NifOgre::ObjectScenePtr mParticle;
|
||||
|
||||
// remember some settings so we don't have to apply them again if they didnt change
|
||||
Ogre::String mClouds;
|
||||
Ogre::String mNextClouds;
|
||||
|
@ -211,6 +214,8 @@ namespace MWRender
|
|||
Ogre::ColourValue mSkyColour;
|
||||
Ogre::ColourValue mFogColour;
|
||||
|
||||
std::string mCurrentParticleEffect;
|
||||
|
||||
Ogre::Light* mLightning;
|
||||
|
||||
float mRemainingTransitionTime;
|
||||
|
|
|
@ -150,9 +150,19 @@ void WeaponAnimation::pitchSkeleton(float xrot, Ogre::SkeletonInstance* skel)
|
|||
return;
|
||||
|
||||
float pitch = xrot * mPitchFactor;
|
||||
Ogre::Node *node = skel->getBone("Bip01 Spine2");
|
||||
Ogre::Node *node;
|
||||
|
||||
// In spherearcher.nif, we have spine, not Spine. Not sure if all bone names should be case insensitive?
|
||||
if (skel->hasBone("Bip01 spine2"))
|
||||
node = skel->getBone("Bip01 spine2");
|
||||
else
|
||||
node = skel->getBone("Bip01 Spine2");
|
||||
node->pitch(Ogre::Radian(-pitch/2), Ogre::Node::TS_WORLD);
|
||||
node = skel->getBone("Bip01 Spine1");
|
||||
|
||||
if (skel->hasBone("Bip01 spine1")) // in spherearcher.nif
|
||||
node = skel->getBone("Bip01 spine1");
|
||||
else
|
||||
node = skel->getBone("Bip01 Spine1");
|
||||
node->pitch(Ogre::Radian(-pitch/2), Ogre::Node::TS_WORLD);
|
||||
}
|
||||
|
||||
|
|
|
@ -477,6 +477,16 @@ namespace MWScript
|
|||
}
|
||||
};
|
||||
|
||||
template <class R>
|
||||
class OpFace : public Interpreter::Opcode0
|
||||
{
|
||||
public:
|
||||
virtual void execute(Interpreter::Runtime& runtime)
|
||||
{
|
||||
/// \todo implement
|
||||
}
|
||||
};
|
||||
|
||||
void installOpcodes (Interpreter::Interpreter& interpreter)
|
||||
{
|
||||
interpreter.installSegment3 (Compiler::Ai::opcodeAIActivate, new OpAiActivate<ImplicitRef>);
|
||||
|
@ -538,6 +548,9 @@ namespace MWScript
|
|||
interpreter.installSegment5 (Compiler::Ai::opcodeGetFleeExplicit, new OpGetAiSetting<ExplicitRef>(2));
|
||||
interpreter.installSegment5 (Compiler::Ai::opcodeGetAlarm, new OpGetAiSetting<ImplicitRef>(3));
|
||||
interpreter.installSegment5 (Compiler::Ai::opcodeGetAlarmExplicit, new OpGetAiSetting<ExplicitRef>(3));
|
||||
|
||||
interpreter.installSegment5 (Compiler::Ai::opcodeFace, new OpFace<ImplicitRef>);
|
||||
interpreter.installSegment5 (Compiler::Ai::opcodeFaceExplicit, new OpFace<ExplicitRef>);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -227,9 +227,6 @@ namespace MWScript
|
|||
std::string faction2 = runtime.getStringLiteral (runtime[0].mInteger);
|
||||
runtime.pop();
|
||||
|
||||
// ignore extra garbage argument
|
||||
runtime.pop();
|
||||
|
||||
runtime.push(MWBase::Environment::get().getDialogueManager()
|
||||
->getFactionReaction(faction1, faction2));
|
||||
}
|
||||
|
|
|
@ -400,5 +400,8 @@ op 0x2000247: BetaComment
|
|||
op 0x2000248: BetaComment, explicit
|
||||
op 0x2000249: OnMurder
|
||||
op 0x200024a: OnMurder, explicit
|
||||
op 0x200024b: ToggleMenus
|
||||
op 0x200024c: Face
|
||||
op 0x200024d: Face, explicit
|
||||
|
||||
opcodes 0x200024b-0x3ffffff unused
|
||||
opcodes 0x200024e-0x3ffffff unused
|
||||
|
|
|
@ -203,6 +203,15 @@ namespace MWScript
|
|||
}
|
||||
};
|
||||
|
||||
class OpToggleMenus : public Interpreter::Opcode0
|
||||
{
|
||||
public:
|
||||
virtual void execute(Interpreter::Runtime &runtime)
|
||||
{
|
||||
bool state = MWBase::Environment::get().getWindowManager()->toggleGui();
|
||||
runtime.getContext().report(state ? "GUI -> On" : "GUI -> Off");
|
||||
}
|
||||
};
|
||||
|
||||
void installOpcodes (Interpreter::Interpreter& interpreter)
|
||||
{
|
||||
|
@ -242,6 +251,7 @@ namespace MWScript
|
|||
interpreter.installSegment5 (Compiler::Gui::opcodeShowMap, new OpShowMap);
|
||||
interpreter.installSegment5 (Compiler::Gui::opcodeFillMap, new OpFillMap);
|
||||
interpreter.installSegment3 (Compiler::Gui::opcodeMenuTest, new OpMenuTest);
|
||||
interpreter.installSegment5 (Compiler::Gui::opcodeToggleMenus, new OpToggleMenus);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -64,12 +64,12 @@ namespace MWScript
|
|||
Success = false;
|
||||
}
|
||||
|
||||
if (!Success && mVerbose)
|
||||
if (!Success)
|
||||
{
|
||||
std::cerr
|
||||
<< "compiling failed: " << name << std::endl
|
||||
<< script->mScriptText
|
||||
<< std::endl << std::endl;
|
||||
<< "compiling failed: " << name << std::endl;
|
||||
if (mVerbose)
|
||||
std::cerr << script->mScriptText << std::endl << std::endl;
|
||||
}
|
||||
|
||||
if (Success)
|
||||
|
|
|
@ -690,8 +690,11 @@ namespace MWScript
|
|||
Interpreter::Type_Integer value = runtime[0].mInteger;
|
||||
runtime.pop();
|
||||
|
||||
ptr.getClass().getNpcStats (ptr).setBaseDisposition
|
||||
(ptr.getClass().getNpcStats (ptr).getBaseDisposition() + value);
|
||||
if (ptr.getClass().isNpc())
|
||||
ptr.getClass().getNpcStats (ptr).setBaseDisposition
|
||||
(ptr.getClass().getNpcStats (ptr).getBaseDisposition() + value);
|
||||
|
||||
// else: must not throw exception (used by an Almalexia dialogue script)
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -707,7 +710,8 @@ namespace MWScript
|
|||
Interpreter::Type_Integer value = runtime[0].mInteger;
|
||||
runtime.pop();
|
||||
|
||||
ptr.getClass().getNpcStats (ptr).setBaseDisposition (value);
|
||||
if (ptr.getClass().isNpc())
|
||||
ptr.getClass().getNpcStats (ptr).setBaseDisposition (value);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -720,7 +724,10 @@ namespace MWScript
|
|||
{
|
||||
MWWorld::Ptr ptr = R()(runtime);
|
||||
|
||||
runtime.push (MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(ptr));
|
||||
if (!ptr.getClass().isNpc())
|
||||
runtime.push(0);
|
||||
else
|
||||
runtime.push (MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(ptr));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -323,7 +323,7 @@ namespace MWScript
|
|||
}
|
||||
else
|
||||
{
|
||||
throw std::runtime_error ("unknown cell");
|
||||
throw std::runtime_error (std::string("unknown cell (") + cellID + ")");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -420,7 +420,7 @@ namespace MWScript
|
|||
}
|
||||
else
|
||||
{
|
||||
throw std::runtime_error ("unknown cell");
|
||||
throw std::runtime_error ( std::string("unknown cell (") + cellID + ")");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -201,6 +201,13 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot
|
|||
writer.addMaster (*iter, 0); // not using the size information anyway -> use value of 0
|
||||
|
||||
writer.setFormat (ESM::Header::CurrentFormat);
|
||||
|
||||
// all unused
|
||||
writer.setVersion(0);
|
||||
writer.setType(0);
|
||||
writer.setAuthor("");
|
||||
writer.setDescription("");
|
||||
|
||||
int recordCount = 1 // saved game header
|
||||
+MWBase::Environment::get().getJournal()->countSavedGameRecords()
|
||||
+MWBase::Environment::get().getWorld()->countSavedGameRecords()
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
#include <openengine/bullet/trace.h>
|
||||
#include <openengine/bullet/physic.hpp>
|
||||
#include <openengine/bullet/BtOgreExtras.h>
|
||||
#include <openengine/ogre/renderer.hpp>
|
||||
|
||||
#include <components/nifbullet/bulletnifloader.hpp>
|
||||
|
@ -26,10 +27,49 @@
|
|||
#include "../mwworld/esmstore.hpp"
|
||||
#include "../mwworld/cellstore.hpp"
|
||||
|
||||
#include "../apps/openmw/mwrender/animation.hpp"
|
||||
#include "../apps/openmw/mwbase/world.hpp"
|
||||
#include "../apps/openmw/mwbase/environment.hpp"
|
||||
|
||||
#include "ptr.hpp"
|
||||
#include "class.hpp"
|
||||
|
||||
using namespace Ogre;
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
void animateCollisionShapes (std::map<OEngine::Physic::RigidBody*, OEngine::Physic::AnimatedShapeInstance>& map)
|
||||
{
|
||||
for (std::map<OEngine::Physic::RigidBody*, OEngine::Physic::AnimatedShapeInstance>::iterator it = map.begin();
|
||||
it != map.end(); ++it)
|
||||
{
|
||||
MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->searchPtrViaHandle(it->first->mName);
|
||||
MWRender::Animation* animation = MWBase::Environment::get().getWorld()->getAnimation(ptr);
|
||||
|
||||
OEngine::Physic::AnimatedShapeInstance& instance = it->second;
|
||||
|
||||
std::map<std::string, int>& shapes = instance.mAnimatedShapes;
|
||||
for (std::map<std::string, int>::iterator shapeIt = shapes.begin();
|
||||
shapeIt != shapes.end(); ++shapeIt)
|
||||
{
|
||||
Ogre::Node* bone = animation->getNode(shapeIt->first);
|
||||
|
||||
btCompoundShape* compound = dynamic_cast<btCompoundShape*>(instance.mCompound);
|
||||
|
||||
btTransform trans;
|
||||
trans.setOrigin(BtOgre::Convert::toBullet(bone->_getDerivedPosition()));
|
||||
trans.setRotation(BtOgre::Convert::toBullet(bone->_getDerivedOrientation()));
|
||||
|
||||
compound->getChildShape(shapeIt->second)->setLocalScaling(BtOgre::Convert::toBullet(bone->_getDerivedScale()));
|
||||
compound->updateChildTransform(shapeIt->second, trans);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
namespace MWWorld
|
||||
{
|
||||
|
||||
|
@ -175,7 +215,7 @@ namespace MWWorld
|
|||
|
||||
const int maxHeight = 200.f;
|
||||
OEngine::Physic::ActorTracer tracer;
|
||||
tracer.findGround(physicActor->getCollisionBody(), position, position-Ogre::Vector3(0,0,maxHeight), engine);
|
||||
tracer.findGround(physicActor, position, position-Ogre::Vector3(0,0,maxHeight), engine);
|
||||
if(tracer.mFraction >= 1.0f)
|
||||
{
|
||||
physicActor->setOnGround(false);
|
||||
|
@ -564,11 +604,10 @@ namespace MWWorld
|
|||
std::string mesh = ptr.getClass().getModel(ptr);
|
||||
Ogre::SceneNode* node = ptr.getRefData().getBaseNode();
|
||||
handleToMesh[node->getName()] = mesh;
|
||||
OEngine::Physic::RigidBody* body = mEngine->createAndAdjustRigidBody(
|
||||
mEngine->createAndAdjustRigidBody(
|
||||
mesh, node->getName(), node->getScale().x, node->getPosition(), node->getOrientation(), 0, 0, false, placeable);
|
||||
OEngine::Physic::RigidBody* raycastingBody = mEngine->createAndAdjustRigidBody(
|
||||
mEngine->createAndAdjustRigidBody(
|
||||
mesh, node->getName(), node->getScale().x, node->getPosition(), node->getOrientation(), 0, 0, true, placeable);
|
||||
mEngine->addRigidBody(body, true, raycastingBody);
|
||||
}
|
||||
|
||||
void PhysicsSystem::addActor (const Ptr& ptr)
|
||||
|
@ -607,9 +646,10 @@ namespace MWWorld
|
|||
Ogre::SceneNode* node = ptr.getRefData().getBaseNode();
|
||||
const std::string &handle = node->getName();
|
||||
const Ogre::Quaternion &rotation = node->getOrientation();
|
||||
|
||||
// TODO: map to MWWorld::Ptr for faster access
|
||||
if (OEngine::Physic::PhysicActor* act = mEngine->getCharacter(handle))
|
||||
{
|
||||
//Needs to be changed
|
||||
act->setRotation(rotation);
|
||||
}
|
||||
if (OEngine::Physic::RigidBody* body = mEngine->getRigidBody(handle))
|
||||
|
@ -740,8 +780,10 @@ namespace MWWorld
|
|||
btCollisionObject object;
|
||||
object.setCollisionShape(&planeShape);
|
||||
|
||||
// TODO: this seems to have a slight performance impact
|
||||
if (waterCollision)
|
||||
mEngine->dynamicsWorld->addCollisionObject(&object);
|
||||
mEngine->mDynamicsWorld->addCollisionObject(&object,
|
||||
0xff, OEngine::Physic::CollisionType_Actor);
|
||||
|
||||
// 100 points of slowfall reduce gravity by 90% (this is just a guess)
|
||||
float slowFall = 1-std::min(std::max(0.f, (effects.get(ESM::MagicEffect::SlowFall).mMagnitude / 100.f) * 0.9f), 0.9f);
|
||||
|
@ -751,7 +793,7 @@ namespace MWWorld
|
|||
waterlevel, slowFall, mEngine);
|
||||
|
||||
if (waterCollision)
|
||||
mEngine->dynamicsWorld->removeCollisionObject(&object);
|
||||
mEngine->mDynamicsWorld->removeCollisionObject(&object);
|
||||
|
||||
float heightDiff = newpos.z - oldHeight;
|
||||
|
||||
|
@ -767,4 +809,12 @@ namespace MWWorld
|
|||
|
||||
return mMovementResults;
|
||||
}
|
||||
|
||||
void PhysicsSystem::stepSimulation(float dt)
|
||||
{
|
||||
animateCollisionShapes(mEngine->mAnimatedShapes);
|
||||
animateCollisionShapes(mEngine->mAnimatedRaycastingShapes);
|
||||
|
||||
mEngine->stepSimulation(dt);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,6 +53,8 @@ namespace MWWorld
|
|||
|
||||
bool toggleCollisionMode();
|
||||
|
||||
void stepSimulation(float dt);
|
||||
|
||||
std::vector<std::string> getCollisions(const MWWorld::Ptr &ptr); ///< get handles this object collides with
|
||||
Ogre::Vector3 traceDown(const MWWorld::Ptr &ptr);
|
||||
|
||||
|
|
|
@ -78,7 +78,7 @@ namespace MWWorld
|
|||
state.mSourceName = sourceName;
|
||||
state.mId = model;
|
||||
state.mSpellId = spellId;
|
||||
state.mCaster = caster;
|
||||
state.mCasterHandle = caster.getRefData().getHandle();
|
||||
if (caster.getClass().isActor())
|
||||
state.mActorId = caster.getClass().getCreatureStats(caster).getActorId();
|
||||
else
|
||||
|
@ -162,7 +162,7 @@ namespace MWWorld
|
|||
{
|
||||
MWWorld::Ptr obstacle = MWBase::Environment::get().getWorld()->searchPtrViaHandle(cIt->second);
|
||||
|
||||
MWWorld::Ptr caster = it->mCaster;
|
||||
MWWorld::Ptr caster = MWBase::Environment::get().getWorld()->searchPtrViaHandle(it->mCasterHandle);
|
||||
if (caster.isEmpty())
|
||||
caster = MWBase::Environment::get().getWorld()->searchPtrViaActorId(it->mActorId);
|
||||
|
||||
|
|
|
@ -67,12 +67,12 @@ namespace MWWorld
|
|||
|
||||
int mActorId;
|
||||
|
||||
// actorId doesn't work for non-actors, so we also keep track of the Ptr.
|
||||
// actorId doesn't work for non-actors, so we also keep track of the Ogre-handle.
|
||||
// For non-actors, the caster ptr is mainly needed to prevent the projectile
|
||||
// from colliding with its caster.
|
||||
// TODO: this will break when the game is saved and reloaded, since there is currently
|
||||
// no way to write identifiers for non-actors to a savegame.
|
||||
MWWorld::Ptr mCaster;
|
||||
std::string mCasterHandle;
|
||||
|
||||
// MW-id of this projectile
|
||||
std::string mId;
|
||||
|
|
|
@ -54,7 +54,7 @@ namespace MWWorld
|
|||
RefData();
|
||||
|
||||
/// @param cellRef Used to copy constant data such as position into this class where it can
|
||||
/// be altered without effecting the original data. This makes it possible
|
||||
/// be altered without affecting the original data. This makes it possible
|
||||
/// to reset the position as the orignal data is still held in the CellRef
|
||||
RefData (const ESM::CellRef& cellRef);
|
||||
|
||||
|
|
|
@ -58,6 +58,13 @@ void WeatherManager::setFallbackWeather(Weather& weather,const std::string& name
|
|||
weather.mWindSpeed = mFallback->getFallbackFloat("Weather_"+upper+"_Wind_Speed");
|
||||
weather.mCloudSpeed = mFallback->getFallbackFloat("Weather_"+upper+"_Cloud_Speed");
|
||||
weather.mGlareView = mFallback->getFallbackFloat("Weather_"+upper+"_Glare_View");
|
||||
weather.mCloudTexture = mFallback->getFallbackString("Weather_"+upper+"_Cloud_Texture");
|
||||
size_t offset = weather.mCloudTexture.find(".tga");
|
||||
if (offset != std::string::npos)
|
||||
weather.mCloudTexture.replace(offset, weather.mCloudTexture.length() - offset, ".dds");
|
||||
|
||||
weather.mIsStorm = (name == "ashstorm" || name == "blight");
|
||||
|
||||
mWeatherSettings[name] = weather;
|
||||
}
|
||||
|
||||
|
@ -123,48 +130,42 @@ WeatherManager::WeatherManager(MWRender::RenderingManager* rendering,MWWorld::Fa
|
|||
|
||||
//Weather
|
||||
Weather clear;
|
||||
clear.mCloudTexture = "tx_sky_clear.dds";
|
||||
setFallbackWeather(clear,"clear");
|
||||
|
||||
Weather cloudy;
|
||||
cloudy.mCloudTexture = "tx_sky_cloudy.dds";
|
||||
setFallbackWeather(cloudy,"cloudy");
|
||||
|
||||
Weather foggy;
|
||||
foggy.mCloudTexture = "tx_sky_foggy.dds";
|
||||
setFallbackWeather(foggy,"foggy");
|
||||
|
||||
Weather thunderstorm;
|
||||
thunderstorm.mCloudTexture = "tx_sky_thunder.dds";
|
||||
thunderstorm.mRainLoopSoundID = "rain heavy";
|
||||
setFallbackWeather(thunderstorm,"thunderstorm");
|
||||
|
||||
Weather rain;
|
||||
rain.mCloudTexture = "tx_sky_rainy.dds";
|
||||
rain.mRainLoopSoundID = "rain";
|
||||
setFallbackWeather(rain,"rain");
|
||||
|
||||
Weather overcast;
|
||||
overcast.mCloudTexture = "tx_sky_overcast.dds";
|
||||
setFallbackWeather(overcast,"overcast");
|
||||
|
||||
Weather ashstorm;
|
||||
ashstorm.mCloudTexture = "tx_sky_ashstorm.dds";
|
||||
ashstorm.mAmbientLoopSoundID = "ashstorm";
|
||||
ashstorm.mParticleEffect = "meshes\\ashcloud.nif";
|
||||
setFallbackWeather(ashstorm,"ashstorm");
|
||||
|
||||
Weather blight;
|
||||
blight.mCloudTexture = "tx_sky_blight.dds";
|
||||
blight.mAmbientLoopSoundID = "blight";
|
||||
blight.mParticleEffect = "meshes\\blightcloud.nif";
|
||||
setFallbackWeather(blight,"blight");
|
||||
|
||||
Weather snow;
|
||||
snow.mCloudTexture = "tx_bm_sky_snow.dds";
|
||||
snow.mParticleEffect = "meshes\\snow.nif";
|
||||
setFallbackWeather(snow, "snow");
|
||||
|
||||
Weather blizzard;
|
||||
blizzard.mCloudTexture = "tx_bm_sky_blizzard.dds";
|
||||
blizzard.mAmbientLoopSoundID = "BM Blizzard";
|
||||
blizzard.mParticleEffect = "meshes\\blizzard.nif";
|
||||
setFallbackWeather(blizzard,"blizzard");
|
||||
}
|
||||
|
||||
|
@ -214,6 +215,10 @@ void WeatherManager::setResult(const String& weatherType)
|
|||
mResult.mAmbientLoopSoundID = current.mAmbientLoopSoundID;
|
||||
mResult.mSunColor = current.mSunDiscSunsetColor;
|
||||
|
||||
mResult.mIsStorm = current.mIsStorm;
|
||||
|
||||
mResult.mParticleEffect = current.mParticleEffect;
|
||||
|
||||
mResult.mNight = (mHour < mSunriseTime || mHour > mNightStart - 1);
|
||||
|
||||
mResult.mFogDepth = mResult.mNight ? current.mLandFogNightDepth : current.mLandFogDayDepth;
|
||||
|
@ -316,6 +321,9 @@ void WeatherManager::transition(float factor)
|
|||
mResult.mNightFade = lerp(current.mNightFade, other.mNightFade, factor);
|
||||
|
||||
mResult.mNight = current.mNight;
|
||||
|
||||
mResult.mIsStorm = current.mIsStorm;
|
||||
mResult.mParticleEffect = current.mParticleEffect;
|
||||
}
|
||||
|
||||
void WeatherManager::update(float duration)
|
||||
|
@ -770,3 +778,13 @@ void WeatherManager::switchToNextWeather(bool instantly)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool WeatherManager::isInStorm() const
|
||||
{
|
||||
return mResult.mIsStorm;
|
||||
}
|
||||
|
||||
Ogre::Vector3 WeatherManager::getStormDirection() const
|
||||
{
|
||||
return Ogre::Vector3(0,-1,0);
|
||||
}
|
||||
|
|
|
@ -57,7 +57,11 @@ namespace MWWorld
|
|||
bool mNight; // use night skybox
|
||||
float mNightFade; // fading factor for night skybox
|
||||
|
||||
bool mIsStorm;
|
||||
|
||||
std::string mAmbientLoopSoundID;
|
||||
|
||||
std::string mParticleEffect;
|
||||
};
|
||||
|
||||
|
||||
|
@ -100,7 +104,7 @@ namespace MWWorld
|
|||
// Duration of weather transition (in days)
|
||||
float mTransitionDelta;
|
||||
|
||||
// No idea what this one is used for?
|
||||
// Used by scripts to animate signs, etc based on the wind (GetWindSpeed)
|
||||
float mWindSpeed;
|
||||
|
||||
// Cloud animation speed multiplier
|
||||
|
@ -119,7 +123,16 @@ namespace MWWorld
|
|||
// Rain sound effect
|
||||
std::string mRainLoopSoundID;
|
||||
|
||||
/// \todo disease chance
|
||||
// Is this an ash storm / blight storm? This controls two things:
|
||||
// - The particle node will be oriented so that the particles appear to come from the Red Mountain. (not implemented yet)
|
||||
// - Characters will animate their hand to protect eyes from the storm when looking in its direction (idlestorm animation)
|
||||
// Possible effect on movement speed?
|
||||
bool mIsStorm;
|
||||
|
||||
std::string mParticleEffect;
|
||||
|
||||
// Note: For Weather Blight, there is a "Disease Chance" (=0.1) setting. But according to MWSFD this feature
|
||||
// is broken in the vanilla game and was disabled.
|
||||
};
|
||||
|
||||
///
|
||||
|
@ -151,6 +164,11 @@ namespace MWWorld
|
|||
|
||||
float getWindSpeed() const;
|
||||
|
||||
/// Are we in an ash or blight storm?
|
||||
bool isInStorm() const;
|
||||
|
||||
Ogre::Vector3 getStormDirection() const;
|
||||
|
||||
void advanceTime(double hours)
|
||||
{
|
||||
mTimePassed += hours*3600;
|
||||
|
|
|
@ -967,7 +967,7 @@ namespace MWWorld
|
|||
|
||||
Ogre::Vector3 vec(x, y, z);
|
||||
|
||||
CellStore *currCell = ptr.isInCell() ? ptr.getCell() : NULL;
|
||||
CellStore *currCell = ptr.isInCell() ? ptr.getCell() : NULL; // currCell == NULL should only happen for player, during initial startup
|
||||
bool isPlayer = ptr == mPlayer->getPlayer();
|
||||
bool haveToMove = isPlayer || mWorldScene->isCellActive(*currCell);
|
||||
|
||||
|
@ -989,7 +989,9 @@ namespace MWWorld
|
|||
}
|
||||
else
|
||||
{
|
||||
if (!mWorldScene->isCellActive(*currCell) && mWorldScene->isCellActive(*newCell))
|
||||
bool currCellActive = mWorldScene->isCellActive(*currCell);
|
||||
bool newCellActive = mWorldScene->isCellActive(*newCell);
|
||||
if (!currCellActive && newCellActive)
|
||||
{
|
||||
MWWorld::Ptr newPtr = ptr.getClass().copyToCell(ptr, *newCell, pos);
|
||||
mWorldScene->addObjectToScene(newPtr);
|
||||
|
@ -1000,7 +1002,7 @@ namespace MWWorld
|
|||
}
|
||||
addContainerScripts(newPtr, newCell);
|
||||
}
|
||||
else if (!mWorldScene->isCellActive(*newCell) && mWorldScene->isCellActive(*currCell))
|
||||
else if (!newCellActive && currCellActive)
|
||||
{
|
||||
mWorldScene->removeObjectFromScene(ptr);
|
||||
mLocalScripts.remove(ptr);
|
||||
|
@ -1011,7 +1013,9 @@ namespace MWWorld
|
|||
.copyToCell(ptr, *newCell);
|
||||
newPtr.getRefData().setBaseNode(0);
|
||||
}
|
||||
else
|
||||
else if (!currCellActive && !newCellActive)
|
||||
ptr.getClass().copyToCell(ptr, *newCell);
|
||||
else // both cells active
|
||||
{
|
||||
MWWorld::Ptr copy =
|
||||
ptr.getClass().copyToCell(ptr, *newCell, pos);
|
||||
|
@ -1231,7 +1235,7 @@ namespace MWWorld
|
|||
if(player != results.end())
|
||||
moveObjectImp(player->first, player->second.x, player->second.y, player->second.z);
|
||||
|
||||
mPhysEngine->stepSimulation(duration);
|
||||
mPhysics->stepSimulation(duration);
|
||||
}
|
||||
|
||||
bool World::castRay (float x1, float y1, float z1, float x2, float y2, float z2)
|
||||
|
@ -1471,8 +1475,13 @@ namespace MWWorld
|
|||
std::vector < std::pair < float, std::string > >::iterator it = results.begin();
|
||||
while (it != results.end())
|
||||
{
|
||||
if ( (*it).second.find("HeightField") != std::string::npos // not interested in terrain
|
||||
|| getPtrViaHandle((*it).second) == mPlayer->getPlayer() ) // not interested in player (unless you want to talk to yourself)
|
||||
if ((*it).second.find("HeightField") != std::string::npos) // Don't attempt to getPtrViaHandle on terrain
|
||||
{
|
||||
++it;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (getPtrViaHandle((*it).second) == mPlayer->getPlayer() ) // not interested in player (unless you want to talk to yourself)
|
||||
{
|
||||
it = results.erase(it);
|
||||
}
|
||||
|
@ -1480,7 +1489,8 @@ namespace MWWorld
|
|||
++it;
|
||||
}
|
||||
|
||||
if (results.empty())
|
||||
if (results.empty()
|
||||
|| results.front().second.find("HeightField") != std::string::npos) // Blocked by terrain
|
||||
{
|
||||
mFacedHandle = "";
|
||||
mFacedDistance = FLT_MAX;
|
||||
|
@ -1847,7 +1857,7 @@ namespace MWWorld
|
|||
Ogre::Vector3 pos(ptr.getRefData().getPosition().pos);
|
||||
OEngine::Physic::ActorTracer tracer;
|
||||
// a small distance above collision object is considered "on ground"
|
||||
tracer.findGround(physactor->getCollisionBody(),
|
||||
tracer.findGround(physactor,
|
||||
pos,
|
||||
pos - Ogre::Vector3(0, 0, 1.5f), // trace a small amount down
|
||||
mPhysEngine);
|
||||
|
@ -1988,6 +1998,22 @@ namespace MWWorld
|
|||
return 0.f;
|
||||
}
|
||||
|
||||
bool World::isInStorm() const
|
||||
{
|
||||
if (isCellExterior() || isCellQuasiExterior())
|
||||
return mWeatherManager->isInStorm();
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
Ogre::Vector3 World::getStormDirection() const
|
||||
{
|
||||
if (isCellExterior() || isCellQuasiExterior())
|
||||
return mWeatherManager->getStormDirection();
|
||||
else
|
||||
return Ogre::Vector3(0,1,0);
|
||||
}
|
||||
|
||||
void World::getContainersOwnedBy (const MWWorld::Ptr& npc, std::vector<MWWorld::Ptr>& out)
|
||||
{
|
||||
const Scene::CellStoreCollection& collection = mWorldScene->getActiveCells();
|
||||
|
@ -2303,6 +2329,7 @@ namespace MWWorld
|
|||
{
|
||||
MWMechanics::CreatureStats& stats = actor.getClass().getCreatureStats(actor);
|
||||
|
||||
// TODO: this only works for the player
|
||||
MWWorld::Ptr target = getFacedObject();
|
||||
|
||||
std::string selectedSpell = stats.getSpells().getSelectedSpell();
|
||||
|
|
|
@ -591,6 +591,12 @@ namespace MWWorld
|
|||
const MWWorld::Ptr& caster, const std::string& id, const std::string& sourceName);
|
||||
|
||||
virtual void activate (const MWWorld::Ptr& object, const MWWorld::Ptr& actor);
|
||||
|
||||
/// @see MWWorld::WeatherManager::isInStorm
|
||||
virtual bool isInStorm() const;
|
||||
|
||||
/// @see MWWorld::WeatherManager::getStormDirection
|
||||
virtual Ogre::Vector3 getStormDirection() const;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -775,7 +775,7 @@ namespace Compiler
|
|||
{
|
||||
parser.reset();
|
||||
|
||||
if (optional)
|
||||
if (optional || *iter == 'X')
|
||||
parser.setOptional (true);
|
||||
|
||||
scanner.scan (parser);
|
||||
|
@ -783,17 +783,20 @@ namespace Compiler
|
|||
if (optional && parser.isEmpty())
|
||||
break;
|
||||
|
||||
std::vector<Interpreter::Type_Code> tmp;
|
||||
if (*iter != 'X')
|
||||
{
|
||||
std::vector<Interpreter::Type_Code> tmp;
|
||||
|
||||
char type = parser.append (tmp);
|
||||
char type = parser.append (tmp);
|
||||
|
||||
if (type!=*iter)
|
||||
Generator::convert (tmp, type, *iter);
|
||||
if (type!=*iter)
|
||||
Generator::convert (tmp, type, *iter);
|
||||
|
||||
stack.push (tmp);
|
||||
stack.push (tmp);
|
||||
|
||||
if (optional)
|
||||
++optionalCount;
|
||||
if (optional)
|
||||
++optionalCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -20,7 +20,8 @@ namespace Compiler
|
|||
l - Integer <BR>
|
||||
s - Short <BR>
|
||||
S - String, case preserved <BR>
|
||||
x - Optional, ignored argument
|
||||
x - Optional, ignored string argument
|
||||
X - Optional, ignored integer argument
|
||||
**/
|
||||
typedef std::string ScriptArgs;
|
||||
|
||||
|
|
|
@ -70,6 +70,7 @@ namespace Compiler
|
|||
extensions.registerFunction ("getlineofsight", 'l', "c", opcodeGetLineOfSight, opcodeGetLineOfSightExplicit);
|
||||
extensions.registerFunction ("getlos", 'l', "c", opcodeGetLineOfSight, opcodeGetLineOfSightExplicit);
|
||||
extensions.registerFunction("gettarget", 'l', "c", opcodeGetTarget, opcodeGetTargetExplicit);
|
||||
extensions.registerInstruction("face", "llX", opcodeFace, opcodeFaceExplicit);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -179,7 +180,7 @@ namespace Compiler
|
|||
extensions.registerFunction("samefaction", 'l', "", opcodeSameFaction,
|
||||
opcodeSameFactionExplicit);
|
||||
extensions.registerInstruction("modfactionreaction", "ccl", opcodeModFactionReaction);
|
||||
extensions.registerFunction("getfactionreaction", 'l', "ccl", opcodeGetFactionReaction);
|
||||
extensions.registerFunction("getfactionreaction", 'l', "ccX", opcodeGetFactionReaction);
|
||||
extensions.registerInstruction("clearinfoactor", "", opcodeClearInfoActor, opcodeClearInfoActorExplicit);
|
||||
}
|
||||
}
|
||||
|
@ -216,6 +217,8 @@ namespace Compiler
|
|||
extensions.registerInstruction ("showmap", "S", opcodeShowMap);
|
||||
extensions.registerInstruction ("fillmap", "", opcodeFillMap);
|
||||
extensions.registerInstruction ("menutest", "/l", opcodeMenuTest);
|
||||
extensions.registerInstruction ("togglemenus", "", opcodeToggleMenus);
|
||||
extensions.registerInstruction ("tm", "", opcodeToggleMenus);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -403,7 +406,7 @@ namespace Compiler
|
|||
extensions.registerInstruction ("setpccrimelevel", "f", opcodeSetPCCrimeLevel);
|
||||
extensions.registerInstruction ("modpccrimelevel", "f", opcodeModPCCrimeLevel);
|
||||
|
||||
extensions.registerInstruction ("addspell", "cx", opcodeAddSpell, opcodeAddSpellExplicit);
|
||||
extensions.registerInstruction ("addspell", "cxX", opcodeAddSpell, opcodeAddSpellExplicit);
|
||||
extensions.registerInstruction ("removespell", "c", opcodeRemoveSpell,
|
||||
opcodeRemoveSpellExplicit);
|
||||
extensions.registerInstruction ("removespelleffects", "c", opcodeRemoveSpellEffects,
|
||||
|
|
|
@ -59,6 +59,8 @@ namespace Compiler
|
|||
const int opcodeStartCombatExplicit = 0x200023b;
|
||||
const int opcodeStopCombat = 0x200023c;
|
||||
const int opcodeStopCombatExplicit = 0x200023d;
|
||||
const int opcodeFace = 0x200024c;
|
||||
const int opcodeFaceExplicit = 0x200024d;
|
||||
}
|
||||
|
||||
namespace Animation
|
||||
|
@ -178,6 +180,7 @@ namespace Compiler
|
|||
const int opcodeShowMap = 0x20001a0;
|
||||
const int opcodeFillMap = 0x20001a1;
|
||||
const int opcodeMenuTest = 0x2002c;
|
||||
const int opcodeToggleMenus = 0x200024b;
|
||||
}
|
||||
|
||||
namespace Misc
|
||||
|
|
|
@ -108,13 +108,13 @@ void ESM::CellRef::save (ESMWriter &esm, bool wideRefNum, bool inInventory) cons
|
|||
esm.writeHNT("NAM9", mGoldValue);
|
||||
}
|
||||
|
||||
if (mTeleport && !inInventory)
|
||||
if (!inInventory && mTeleport)
|
||||
{
|
||||
esm.writeHNT("DODT", mDoorDest);
|
||||
esm.writeHNOCString("DNAM", mDestCell);
|
||||
}
|
||||
|
||||
if (mLockLevel != 0 && !inInventory) {
|
||||
if (!inInventory && mLockLevel != 0) {
|
||||
esm.writeHNT("FLTV", mLockLevel);
|
||||
}
|
||||
|
||||
|
@ -127,13 +127,13 @@ void ESM::CellRef::save (ESMWriter &esm, bool wideRefNum, bool inInventory) cons
|
|||
if (mReferenceBlocked != -1)
|
||||
esm.writeHNT("UNAM", mReferenceBlocked);
|
||||
|
||||
if (mFltv != 0 && !inInventory)
|
||||
if (!inInventory && mFltv != 0)
|
||||
esm.writeHNT("FLTV", mFltv);
|
||||
|
||||
if (!inInventory)
|
||||
esm.writeHNT("DATA", mPos, 24);
|
||||
|
||||
if (mNam0 != 0 && !inInventory)
|
||||
if (!inInventory && mNam0 != 0)
|
||||
esm.writeHNT("NAM0", mNam0);
|
||||
}
|
||||
|
||||
|
@ -158,6 +158,7 @@ void ESM::CellRef::blank()
|
|||
mReferenceBlocked = 0;
|
||||
mFltv = 0;
|
||||
mNam0 = 0;
|
||||
mTeleport = false;
|
||||
|
||||
for (int i=0; i<3; ++i)
|
||||
{
|
||||
|
|
|
@ -18,6 +18,11 @@ namespace ESM
|
|||
mHeader.mData.version = ver;
|
||||
}
|
||||
|
||||
void ESMWriter::setType(int type)
|
||||
{
|
||||
mHeader.mData.type = type;
|
||||
}
|
||||
|
||||
void ESMWriter::setAuthor(const std::string& auth)
|
||||
{
|
||||
mHeader.mData.author.assign (auth);
|
||||
|
|
|
@ -25,10 +25,15 @@ class ESMWriter
|
|||
ESMWriter();
|
||||
|
||||
unsigned int getVersion() const;
|
||||
|
||||
// Set various header data (ESM::Header::Data). All of the below functions must be called before writing,
|
||||
// otherwise this data will be left uninitialized.
|
||||
void setVersion(unsigned int ver = 0x3fa66666);
|
||||
void setType(int type);
|
||||
void setEncoder(ToUTF8::Utf8Encoder *encoding);
|
||||
void setAuthor(const std::string& author);
|
||||
void setDescription(const std::string& desc);
|
||||
|
||||
// Set the record count for writing it in the file header
|
||||
void setRecordCount (int count);
|
||||
// Counts how many records we have actually written.
|
||||
|
|
|
@ -12,7 +12,8 @@ namespace ESM
|
|||
struct StatState
|
||||
{
|
||||
T mBase;
|
||||
T mMod;
|
||||
T mMod; // Note: can either be the modifier, or the modified value.
|
||||
// A bit inconsistent, but we can't fix this without breaking compatibility.
|
||||
T mCurrent;
|
||||
T mDamage;
|
||||
float mProgress;
|
||||
|
@ -30,7 +31,9 @@ namespace ESM
|
|||
void StatState<T>::load (ESMReader &esm)
|
||||
{
|
||||
esm.getHNT (mBase, "STBA");
|
||||
esm.getHNT (mMod, "STMO");
|
||||
|
||||
mMod = 0;
|
||||
esm.getHNOT (mMod, "STMO");
|
||||
mCurrent = 0;
|
||||
esm.getHNOT (mCurrent, "STCU");
|
||||
mDamage = 0;
|
||||
|
@ -43,7 +46,9 @@ namespace ESM
|
|||
void StatState<T>::save (ESMWriter &esm) const
|
||||
{
|
||||
esm.writeHNT ("STBA", mBase);
|
||||
esm.writeHNT ("STMO", mMod);
|
||||
|
||||
if (mMod != 0)
|
||||
esm.writeHNT ("STMO", mMod);
|
||||
|
||||
if (mCurrent)
|
||||
esm.writeHNT ("STCU", mCurrent);
|
||||
|
@ -56,4 +61,4 @@ namespace ESM
|
|||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -89,7 +89,14 @@ public:
|
|||
float lifetime;
|
||||
float lifetimeRandom;
|
||||
|
||||
int emitFlags; // Bit 0: Emit Rate toggle bit (0 = auto adjust, 1 = use Emit Rate value)
|
||||
enum EmitFlags
|
||||
{
|
||||
NoAutoAdjust = 0x1 // If this flag is set, we use the emitRate value. Otherwise,
|
||||
// we calculate an emit rate so that the maximum number of particles
|
||||
// in the system (numParticles) is never exceeded.
|
||||
};
|
||||
int emitFlags;
|
||||
|
||||
Ogre::Vector3 offsetRandom;
|
||||
|
||||
NodePtr emitter;
|
||||
|
|
|
@ -49,20 +49,6 @@ typedef unsigned char ubyte;
|
|||
namespace NifBullet
|
||||
{
|
||||
|
||||
struct TriangleMeshShape : public btBvhTriangleMeshShape
|
||||
{
|
||||
TriangleMeshShape(btStridingMeshInterface* meshInterface, bool useQuantizedAabbCompression)
|
||||
: btBvhTriangleMeshShape(meshInterface, useQuantizedAabbCompression)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~TriangleMeshShape()
|
||||
{
|
||||
delete getTriangleInfoMap();
|
||||
delete m_meshInterface;
|
||||
}
|
||||
};
|
||||
|
||||
ManualBulletShapeLoader::~ManualBulletShapeLoader()
|
||||
{
|
||||
}
|
||||
|
@ -81,9 +67,8 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource)
|
|||
mBoundingBox = NULL;
|
||||
mShape->mBoxTranslation = Ogre::Vector3(0,0,0);
|
||||
mShape->mBoxRotation = Ogre::Quaternion::IDENTITY;
|
||||
mHasShape = false;
|
||||
|
||||
btTriangleMesh* mesh1 = new btTriangleMesh();
|
||||
mCompoundShape = NULL;
|
||||
mStaticMesh = NULL;
|
||||
|
||||
// Load the NIF. TODO: Wrap this in a try-catch block once we're out
|
||||
// of the early stages of development. Right now we WANT to catch
|
||||
|
@ -111,19 +96,35 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource)
|
|||
mShape->mHasCollisionNode = hasRootCollisionNode(node);
|
||||
|
||||
//do a first pass
|
||||
handleNode(mesh1, node,0,false,false,false);
|
||||
handleNode(node,0,false,false,false);
|
||||
|
||||
if(mBoundingBox != NULL)
|
||||
{
|
||||
mShape->mCollisionShape = mBoundingBox;
|
||||
delete mesh1;
|
||||
}
|
||||
else if (mHasShape && mShape->mCollide)
|
||||
{
|
||||
mShape->mCollisionShape = new TriangleMeshShape(mesh1,true);
|
||||
delete mStaticMesh;
|
||||
if (mCompoundShape)
|
||||
{
|
||||
int n = mCompoundShape->getNumChildShapes();
|
||||
for(int i=0; i <n;i++)
|
||||
delete (mCompoundShape->getChildShape(i));
|
||||
delete mCompoundShape;
|
||||
}
|
||||
}
|
||||
else
|
||||
delete mesh1;
|
||||
{
|
||||
if (mCompoundShape)
|
||||
{
|
||||
mShape->mCollisionShape = mCompoundShape;
|
||||
if (mStaticMesh)
|
||||
{
|
||||
btTransform trans;
|
||||
trans.setIdentity();
|
||||
mCompoundShape->addChildShape(trans, new TriangleMeshShape(mStaticMesh,true));
|
||||
}
|
||||
}
|
||||
else if (mStaticMesh)
|
||||
mShape->mCollisionShape = new TriangleMeshShape(mStaticMesh,true);
|
||||
}
|
||||
|
||||
//second pass which create a shape for raycasting.
|
||||
mResourceName = mShape->getName();
|
||||
|
@ -131,23 +132,23 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource)
|
|||
mBoundingBox = NULL;
|
||||
mShape->mBoxTranslation = Ogre::Vector3(0,0,0);
|
||||
mShape->mBoxRotation = Ogre::Quaternion::IDENTITY;
|
||||
mHasShape = false;
|
||||
mStaticMesh = NULL;
|
||||
mCompoundShape = NULL;
|
||||
|
||||
btTriangleMesh* mesh2 = new btTriangleMesh();
|
||||
handleNode(node,0,true,true,false);
|
||||
|
||||
handleNode(mesh2, node,0,true,true,false);
|
||||
|
||||
if(mBoundingBox != NULL)
|
||||
if (mCompoundShape)
|
||||
{
|
||||
mShape->mRaycastingShape = mBoundingBox;
|
||||
delete mesh2;
|
||||
mShape->mRaycastingShape = mCompoundShape;
|
||||
if (mStaticMesh)
|
||||
{
|
||||
btTransform trans;
|
||||
trans.setIdentity();
|
||||
mCompoundShape->addChildShape(trans, new TriangleMeshShape(mStaticMesh,true));
|
||||
}
|
||||
}
|
||||
else if (mHasShape)
|
||||
{
|
||||
mShape->mRaycastingShape = new TriangleMeshShape(mesh2,true);
|
||||
}
|
||||
else
|
||||
delete mesh2;
|
||||
else if (mStaticMesh)
|
||||
mShape->mRaycastingShape = new TriangleMeshShape(mStaticMesh,true);
|
||||
}
|
||||
|
||||
bool ManualBulletShapeLoader::hasRootCollisionNode(Nif::Node const * node)
|
||||
|
@ -172,14 +173,17 @@ bool ManualBulletShapeLoader::hasRootCollisionNode(Nif::Node const * node)
|
|||
return false;
|
||||
}
|
||||
|
||||
void ManualBulletShapeLoader::handleNode(btTriangleMesh* mesh, const Nif::Node *node, int flags,
|
||||
void ManualBulletShapeLoader::handleNode(const Nif::Node *node, int flags,
|
||||
bool isCollisionNode,
|
||||
bool raycasting, bool isMarker)
|
||||
bool raycasting, bool isMarker, bool isAnimated)
|
||||
{
|
||||
// Accumulate the flags from all the child nodes. This works for all
|
||||
// the flags we currently use, at least.
|
||||
flags |= node->flags;
|
||||
|
||||
if (!node->controller.empty() && node->controller->recType == Nif::RC_NiKeyframeController)
|
||||
isAnimated = true;
|
||||
|
||||
if (!raycasting)
|
||||
isCollisionNode = isCollisionNode || (node->recType == Nif::RC_RootCollisionNode);
|
||||
else
|
||||
|
@ -227,10 +231,12 @@ void ManualBulletShapeLoader::handleNode(btTriangleMesh* mesh, const Nif::Node *
|
|||
if ( (isCollisionNode || (!mShape->mHasCollisionNode && !raycasting))
|
||||
&& (!isMarker || (mShape->mHasCollisionNode && !raycasting)))
|
||||
{
|
||||
// NOTE: a trishape with hasBounds=true, but no BBoxCollision flag should NOT go through handleNiTriShape!
|
||||
// It must be ignored completely.
|
||||
// (occurs in tr_ex_imp_wall_arch_04.nif)
|
||||
if(node->hasBounds)
|
||||
{
|
||||
// Checking for BBoxCollision flag causes issues with some actors :/
|
||||
if (!(node->flags & Nif::NiNode::Flag_Hidden))
|
||||
if (flags & Nif::NiNode::Flag_BBoxCollision && !raycasting)
|
||||
{
|
||||
mShape->mBoxTranslation = node->boundPos;
|
||||
mShape->mBoxRotation = node->boundRot;
|
||||
|
@ -240,7 +246,7 @@ void ManualBulletShapeLoader::handleNode(btTriangleMesh* mesh, const Nif::Node *
|
|||
else if(node->recType == Nif::RC_NiTriShape)
|
||||
{
|
||||
mShape->mCollide = !(flags&0x800);
|
||||
handleNiTriShape(mesh, static_cast<const Nif::NiTriShape*>(node), flags, node->getWorldTransform(), raycasting);
|
||||
handleNiTriShape(static_cast<const Nif::NiTriShape*>(node), flags, node->getWorldTransform(), raycasting, isAnimated);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -252,13 +258,13 @@ void ManualBulletShapeLoader::handleNode(btTriangleMesh* mesh, const Nif::Node *
|
|||
for(size_t i = 0;i < list.length();i++)
|
||||
{
|
||||
if(!list[i].empty())
|
||||
handleNode(mesh, list[i].getPtr(), flags, isCollisionNode, raycasting, isMarker);
|
||||
handleNode(list[i].getPtr(), flags, isCollisionNode, raycasting, isMarker, isAnimated);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ManualBulletShapeLoader::handleNiTriShape(btTriangleMesh* mesh, const Nif::NiTriShape *shape, int flags, const Ogre::Matrix4 &transform,
|
||||
bool raycasting)
|
||||
void ManualBulletShapeLoader::handleNiTriShape(const Nif::NiTriShape *shape, int flags, const Ogre::Matrix4 &transform,
|
||||
bool raycasting, bool isAnimated)
|
||||
{
|
||||
assert(shape != NULL);
|
||||
|
||||
|
@ -281,17 +287,64 @@ void ManualBulletShapeLoader::handleNiTriShape(btTriangleMesh* mesh, const Nif::
|
|||
// bother setting it up.
|
||||
return;
|
||||
|
||||
mHasShape = true;
|
||||
if (!shape->skin.empty())
|
||||
isAnimated = false;
|
||||
|
||||
const Nif::NiTriShapeData *data = shape->data.getPtr();
|
||||
const std::vector<Ogre::Vector3> &vertices = data->vertices;
|
||||
const short *triangles = &data->triangles[0];
|
||||
for(size_t i = 0;i < data->triangles.size();i+=3)
|
||||
if (isAnimated)
|
||||
{
|
||||
Ogre::Vector3 b1 = transform*vertices[triangles[i+0]];
|
||||
Ogre::Vector3 b2 = transform*vertices[triangles[i+1]];
|
||||
Ogre::Vector3 b3 = transform*vertices[triangles[i+2]];
|
||||
mesh->addTriangle(btVector3(b1.x,b1.y,b1.z),btVector3(b2.x,b2.y,b2.z),btVector3(b3.x,b3.y,b3.z));
|
||||
if (!mCompoundShape)
|
||||
mCompoundShape = new btCompoundShape();
|
||||
|
||||
btTriangleMesh* childMesh = new btTriangleMesh();
|
||||
|
||||
const Nif::NiTriShapeData *data = shape->data.getPtr();
|
||||
|
||||
childMesh->preallocateVertices(data->vertices.size());
|
||||
childMesh->preallocateIndices(data->triangles.size());
|
||||
|
||||
const std::vector<Ogre::Vector3> &vertices = data->vertices;
|
||||
const std::vector<short> &triangles = data->triangles;
|
||||
|
||||
for(size_t i = 0;i < data->triangles.size();i+=3)
|
||||
{
|
||||
Ogre::Vector3 b1 = vertices[triangles[i+0]];
|
||||
Ogre::Vector3 b2 = vertices[triangles[i+1]];
|
||||
Ogre::Vector3 b3 = vertices[triangles[i+2]];
|
||||
childMesh->addTriangle(btVector3(b1.x,b1.y,b1.z),btVector3(b2.x,b2.y,b2.z),btVector3(b3.x,b3.y,b3.z));
|
||||
}
|
||||
|
||||
TriangleMeshShape* childShape = new TriangleMeshShape(childMesh,true);
|
||||
|
||||
childShape->setLocalScaling(btVector3(transform[0][0], transform[1][1], transform[2][2]));
|
||||
|
||||
Ogre::Quaternion q = transform.extractQuaternion();
|
||||
Ogre::Vector3 v = transform.getTrans();
|
||||
btTransform trans(btQuaternion(q.x, q.y, q.z, q.w), btVector3(v.x, v.y, v.z));
|
||||
|
||||
if (raycasting)
|
||||
mShape->mAnimatedRaycastingShapes.insert(std::make_pair(shape->name, mCompoundShape->getNumChildShapes()));
|
||||
else
|
||||
mShape->mAnimatedShapes.insert(std::make_pair(shape->name, mCompoundShape->getNumChildShapes()));
|
||||
|
||||
mCompoundShape->addChildShape(trans, childShape);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!mStaticMesh)
|
||||
mStaticMesh = new btTriangleMesh();
|
||||
|
||||
// Static shape, just transform all vertices into position
|
||||
const Nif::NiTriShapeData *data = shape->data.getPtr();
|
||||
const std::vector<Ogre::Vector3> &vertices = data->vertices;
|
||||
const std::vector<short> &triangles = data->triangles;
|
||||
|
||||
for(size_t i = 0;i < data->triangles.size();i+=3)
|
||||
{
|
||||
Ogre::Vector3 b1 = transform*vertices[triangles[i+0]];
|
||||
Ogre::Vector3 b2 = transform*vertices[triangles[i+1]];
|
||||
Ogre::Vector3 b3 = transform*vertices[triangles[i+2]];
|
||||
mStaticMesh->addTriangle(btVector3(b1.x,b1.y,b1.z),btVector3(b2.x,b2.y,b2.z),btVector3(b3.x,b3.y,b3.z));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -304,4 +357,53 @@ void ManualBulletShapeLoader::load(const std::string &name,const std::string &gr
|
|||
OEngine::Physic::BulletShapeManager::getSingleton().create(name,group,true,this);
|
||||
}
|
||||
|
||||
bool findBoundingBox (const Nif::Node* node, Ogre::Vector3& halfExtents, Ogre::Vector3& translation, Ogre::Quaternion& orientation)
|
||||
{
|
||||
if(node->hasBounds)
|
||||
{
|
||||
if (!(node->flags & Nif::NiNode::Flag_Hidden))
|
||||
{
|
||||
translation = node->boundPos;
|
||||
orientation = node->boundRot;
|
||||
halfExtents = node->boundXYZ;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
const Nif::NiNode *ninode = dynamic_cast<const Nif::NiNode*>(node);
|
||||
if(ninode)
|
||||
{
|
||||
const Nif::NodeList &list = ninode->children;
|
||||
for(size_t i = 0;i < list.length();i++)
|
||||
{
|
||||
if(!list[i].empty())
|
||||
if (findBoundingBox(list[i].getPtr(), halfExtents, translation, orientation))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool getBoundingBox(const std::string& nifFile, Ogre::Vector3& halfExtents, Ogre::Vector3& translation, Ogre::Quaternion& orientation)
|
||||
{
|
||||
Nif::NIFFile::ptr pnif (Nif::NIFFile::create (nifFile));
|
||||
Nif::NIFFile & nif = *pnif.get ();
|
||||
|
||||
if (nif.numRoots() < 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Nif::Record *r = nif.getRoot(0);
|
||||
assert(r != NULL);
|
||||
|
||||
Nif::Node *node = dynamic_cast<Nif::Node*>(r);
|
||||
if (node == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return findBoundingBox(node, halfExtents, translation, orientation);
|
||||
}
|
||||
|
||||
} // namespace NifBullet
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include <string>
|
||||
#include <BulletCollision/CollisionShapes/btBvhTriangleMeshShape.h>
|
||||
#include <BulletCollision/CollisionShapes/btConvexTriangleMeshShape.h>
|
||||
#include <BulletCollision/CollisionShapes/btCompoundShape.h>
|
||||
#include <btBulletDynamicsCommon.h>
|
||||
#include <openengine/bullet/BulletShapeLoader.h>
|
||||
|
||||
|
@ -44,6 +45,22 @@ namespace Nif
|
|||
namespace NifBullet
|
||||
{
|
||||
|
||||
// Subclass btBhvTriangleMeshShape to auto-delete the meshInterface
|
||||
struct TriangleMeshShape : public btBvhTriangleMeshShape
|
||||
{
|
||||
TriangleMeshShape(btStridingMeshInterface* meshInterface, bool useQuantizedAabbCompression)
|
||||
: btBvhTriangleMeshShape(meshInterface, useQuantizedAabbCompression)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~TriangleMeshShape()
|
||||
{
|
||||
delete getTriangleInfoMap();
|
||||
delete m_meshInterface;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
*Load bulletShape from NIF files.
|
||||
*/
|
||||
|
@ -52,8 +69,9 @@ class ManualBulletShapeLoader : public OEngine::Physic::BulletShapeLoader
|
|||
public:
|
||||
ManualBulletShapeLoader()
|
||||
: mShape(NULL)
|
||||
, mStaticMesh(NULL)
|
||||
, mCompoundShape(NULL)
|
||||
, mBoundingBox(NULL)
|
||||
, mHasShape(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -88,7 +106,8 @@ private:
|
|||
/**
|
||||
*Parse a node.
|
||||
*/
|
||||
void handleNode(btTriangleMesh* mesh, Nif::Node const *node, int flags, bool isCollisionNode, bool raycasting, bool isMarker);
|
||||
void handleNode(Nif::Node const *node, int flags, bool isCollisionNode,
|
||||
bool raycasting, bool isMarker, bool isAnimated=false);
|
||||
|
||||
/**
|
||||
*Helper function
|
||||
|
@ -98,16 +117,24 @@ private:
|
|||
/**
|
||||
*convert a NiTriShape to a bullet trishape.
|
||||
*/
|
||||
void handleNiTriShape(btTriangleMesh* mesh, const Nif::NiTriShape *shape, int flags, const Ogre::Matrix4 &transform, bool raycasting);
|
||||
void handleNiTriShape(const Nif::NiTriShape *shape, int flags, const Ogre::Matrix4 &transform, bool raycasting, bool isAnimated);
|
||||
|
||||
std::string mResourceName;
|
||||
|
||||
OEngine::Physic::BulletShape* mShape;//current shape
|
||||
btBoxShape *mBoundingBox;
|
||||
|
||||
bool mHasShape;
|
||||
btCompoundShape* mCompoundShape;
|
||||
|
||||
btTriangleMesh* mStaticMesh;
|
||||
|
||||
btBoxShape *mBoundingBox;
|
||||
};
|
||||
|
||||
|
||||
bool getBoundingBox(const std::string& nifFile, Ogre::Vector3& halfExtents, Ogre::Vector3& translation, Ogre::Quaternion& orientation);
|
||||
|
||||
bool findBoundingBox(const Nif::Node* node, Ogre::Vector3& halfExtents, Ogre::Vector3& translation, Ogre::Quaternion& orientation);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -106,7 +106,7 @@ Ogre::String NIFMaterialLoader::getMaterial(const Nif::ShapeData *shapedata,
|
|||
const Nif::NiZBufferProperty *zprop,
|
||||
const Nif::NiSpecularProperty *specprop,
|
||||
const Nif::NiWireframeProperty *wireprop,
|
||||
bool &needTangents, bool disableLighting)
|
||||
bool &needTangents, bool particleMaterial)
|
||||
{
|
||||
Ogre::MaterialManager &matMgr = Ogre::MaterialManager::getSingleton();
|
||||
Ogre::MaterialPtr material = matMgr.getByName(name);
|
||||
|
@ -245,12 +245,9 @@ Ogre::String NIFMaterialLoader::getMaterial(const Nif::ShapeData *shapedata,
|
|||
}
|
||||
}
|
||||
|
||||
if (disableLighting)
|
||||
if (particleMaterial)
|
||||
{
|
||||
ambient = Ogre::Vector3(0.f);
|
||||
diffuse = Ogre::Vector3(0.f);
|
||||
specular = Ogre::Vector3(0.f);
|
||||
emissive = Ogre::Vector3(1.f);
|
||||
alpha = 1.f; // Apparently ignored, might be overridden by particle vertex colors?
|
||||
}
|
||||
|
||||
{
|
||||
|
|
|
@ -49,7 +49,7 @@ public:
|
|||
const Nif::NiZBufferProperty *zprop,
|
||||
const Nif::NiSpecularProperty *specprop,
|
||||
const Nif::NiWireframeProperty *wireprop,
|
||||
bool &needTangents, bool disableLighting=false);
|
||||
bool &needTangents, bool particleMaterial=false);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -756,7 +756,12 @@ class NIFObjectLoader
|
|||
Ogre::ParticleEmitter *emitter = partsys->addEmitter("Nif");
|
||||
emitter->setParticleVelocity(partctrl->velocity - partctrl->velocityRandom*0.5f,
|
||||
partctrl->velocity + partctrl->velocityRandom*0.5f);
|
||||
emitter->setEmissionRate(partctrl->emitRate);
|
||||
|
||||
if (partctrl->emitFlags & Nif::NiParticleSystemController::NoAutoAdjust)
|
||||
emitter->setEmissionRate(partctrl->emitRate);
|
||||
else
|
||||
emitter->setEmissionRate(partctrl->numParticles / (partctrl->lifetime + partctrl->lifetimeRandom/2));
|
||||
|
||||
emitter->setTimeToLive(partctrl->lifetime,
|
||||
partctrl->lifetime + partctrl->lifetimeRandom);
|
||||
emitter->setParameter("width", Ogre::StringConverter::toString(partctrl->offsetRandom.x));
|
||||
|
|
|
@ -32,9 +32,6 @@ namespace Translation
|
|||
boost::filesystem::ifstream stream (
|
||||
dataFileCollections.getCollection (extension).getPath (fileName));
|
||||
|
||||
// Configure the stream to throw exception upon error
|
||||
stream.exceptions ( boost::filesystem::ifstream::failbit | boost::filesystem::ifstream::badbit );
|
||||
|
||||
if (!stream.is_open())
|
||||
throw std::runtime_error ("failed to open translation file: " + fileName);
|
||||
|
||||
|
@ -44,9 +41,8 @@ namespace Translation
|
|||
|
||||
void Storage::loadDataFromStream(ContainerType& container, std::istream& stream)
|
||||
{
|
||||
// NOTE: does not handle failbit/badbit. stream must be set up beforehand to throw in these cases.
|
||||
std::string line;
|
||||
while (!stream.eof())
|
||||
while (!stream.eof() && !stream.fail())
|
||||
{
|
||||
std::getline( stream, line );
|
||||
if (!line.empty() && *line.rbegin() == '\r')
|
||||
|
|
|
@ -17,8 +17,6 @@
|
|||
|
||||
<!-- Global map -->
|
||||
<Widget type="ScrollView" skin="MW_MapView" position="0 0 284 264" align="Stretch" name="GlobalMap">
|
||||
<Property key="CanvasSize" value="1536 1536"/>
|
||||
|
||||
<Widget type="ImageBox" skin="ImageBox" position_real="0 0 1 1" align="Stretch" name="GlobalMapImage">
|
||||
<Widget type="ImageBox" skin="ImageBox" position_real="0 0 1 1" align="Stretch" name="GlobalMapOverlay"/>
|
||||
</Widget>
|
||||
|
|
|
@ -42,7 +42,7 @@ void BulletShape::deleteShape(btCollisionShape* shape)
|
|||
{
|
||||
if(shape->isCompound())
|
||||
{
|
||||
btCompoundShape* ms = static_cast<btCompoundShape*>(mCollisionShape);
|
||||
btCompoundShape* ms = static_cast<btCompoundShape*>(shape);
|
||||
int a = ms->getNumChildShapes();
|
||||
for(int i=0; i <a;i++)
|
||||
{
|
||||
|
@ -51,13 +51,14 @@ void BulletShape::deleteShape(btCollisionShape* shape)
|
|||
}
|
||||
delete shape;
|
||||
}
|
||||
shape = NULL;
|
||||
}
|
||||
|
||||
void BulletShape::unloadImpl()
|
||||
{
|
||||
deleteShape(mCollisionShape);
|
||||
deleteShape(mRaycastingShape);
|
||||
mCollisionShape = NULL;
|
||||
mRaycastingShape = NULL;
|
||||
}
|
||||
|
||||
//TODO:change this?
|
||||
|
|
|
@ -15,8 +15,6 @@ namespace Physic
|
|||
*/
|
||||
class BulletShape : public Ogre::Resource
|
||||
{
|
||||
Ogre::String mString;
|
||||
|
||||
protected:
|
||||
void loadImpl();
|
||||
void unloadImpl();
|
||||
|
@ -32,6 +30,14 @@ public:
|
|||
|
||||
virtual ~BulletShape();
|
||||
|
||||
// Stores animated collision shapes. If any collision nodes in the NIF are animated, then mCollisionShape
|
||||
// will be a btCompoundShape (which consists of one or more child shapes).
|
||||
// In this map, for each animated collision shape,
|
||||
// we store the bone name mapped to the child index of the shape in the btCompoundShape.
|
||||
std::map<std::string, int> mAnimatedShapes;
|
||||
|
||||
std::map<std::string, int> mAnimatedRaycastingShapes;
|
||||
|
||||
btCollisionShape* mCollisionShape;
|
||||
btCollisionShape* mRaycastingShape;
|
||||
|
||||
|
|
|
@ -11,120 +11,159 @@
|
|||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/format.hpp>
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
// Create a copy of the given collision shape (responsibility of user to delete the returned shape).
|
||||
btCollisionShape *duplicateCollisionShape(btCollisionShape *shape)
|
||||
{
|
||||
if(shape->isCompound())
|
||||
{
|
||||
btCompoundShape *comp = static_cast<btCompoundShape*>(shape);
|
||||
btCompoundShape *newShape = new btCompoundShape;
|
||||
|
||||
int numShapes = comp->getNumChildShapes();
|
||||
for(int i = 0;i < numShapes;i++)
|
||||
{
|
||||
btCollisionShape *child = duplicateCollisionShape(comp->getChildShape(i));
|
||||
btTransform trans = comp->getChildTransform(i);
|
||||
newShape->addChildShape(trans, child);
|
||||
}
|
||||
|
||||
return newShape;
|
||||
}
|
||||
|
||||
if(btBvhTriangleMeshShape *trishape = dynamic_cast<btBvhTriangleMeshShape*>(shape))
|
||||
{
|
||||
btTriangleMesh* oldMesh = dynamic_cast<btTriangleMesh*>(trishape->getMeshInterface());
|
||||
btTriangleMesh* newMesh = new btTriangleMesh(*oldMesh);
|
||||
NifBullet::TriangleMeshShape *newShape = new NifBullet::TriangleMeshShape(newMesh, true);
|
||||
|
||||
return newShape;
|
||||
}
|
||||
|
||||
throw std::logic_error(std::string("Unhandled Bullet shape duplication: ")+shape->getName());
|
||||
}
|
||||
|
||||
void deleteShape(btCollisionShape* shape)
|
||||
{
|
||||
if(shape!=NULL)
|
||||
{
|
||||
if(shape->isCompound())
|
||||
{
|
||||
btCompoundShape* ms = static_cast<btCompoundShape*>(shape);
|
||||
int a = ms->getNumChildShapes();
|
||||
for(int i=0; i <a;i++)
|
||||
{
|
||||
deleteShape(ms->getChildShape(i));
|
||||
}
|
||||
}
|
||||
delete shape;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace OEngine {
|
||||
namespace Physic
|
||||
{
|
||||
|
||||
PhysicActor::PhysicActor(const std::string &name, const std::string &mesh, PhysicEngine *engine, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, float scale)
|
||||
: mName(name), mEngine(engine), mMesh(mesh), mBoxScaledTranslation(0,0,0), mBoxRotationInverse(0,0,0,0)
|
||||
, mBody(0), mRaycastingBody(0), mOnGround(false), mCollisionMode(true), mBoxRotation(0,0,0,0)
|
||||
, mCollisionBody(true)
|
||||
: mName(name), mEngine(engine), mMesh(mesh)
|
||||
, mBody(0), mOnGround(false), mInternalCollisionMode(true)
|
||||
, mExternalCollisionMode(true)
|
||||
, mForce(0.0f)
|
||||
, mScale(scale)
|
||||
{
|
||||
mBody = mEngine->createAndAdjustRigidBody(mMesh, mName, scale, position, rotation, &mBoxScaledTranslation, &mBoxRotation);
|
||||
mRaycastingBody = mEngine->createAndAdjustRigidBody(mMesh, mName, scale, position, rotation, &mBoxScaledTranslation, &mBoxRotation, true);
|
||||
Ogre::Quaternion inverse = mBoxRotation.Inverse();
|
||||
mBoxRotationInverse = Ogre::Quaternion(inverse.w, inverse.x, inverse.y,inverse.z);
|
||||
mEngine->addRigidBody(mBody, false, mRaycastingBody,true); //Add rigid body to dynamics world, but do not add to object map
|
||||
if (!NifBullet::getBoundingBox(mMesh, mHalfExtents, mMeshTranslation, mMeshOrientation))
|
||||
{
|
||||
mHalfExtents = Ogre::Vector3(0.f);
|
||||
mMeshTranslation = Ogre::Vector3(0.f);
|
||||
mMeshOrientation = Ogre::Quaternion::IDENTITY;
|
||||
}
|
||||
|
||||
// Use capsule shape only if base is square (nonuniform scaling apparently doesn't work on it)
|
||||
if (std::abs(mHalfExtents.x-mHalfExtents.y)<mHalfExtents.x*0.05 && mHalfExtents.z >= mHalfExtents.x)
|
||||
{
|
||||
// Could also be btCapsuleShapeZ, but the movement solver seems to have issues with it (jumping on slopes doesn't work)
|
||||
mShape.reset(new btCylinderShapeZ(BtOgre::Convert::toBullet(mHalfExtents)));
|
||||
}
|
||||
else
|
||||
mShape.reset(new btBoxShape(BtOgre::Convert::toBullet(mHalfExtents)));
|
||||
|
||||
mShape->setLocalScaling(btVector3(scale,scale,scale));
|
||||
|
||||
btRigidBody::btRigidBodyConstructionInfo CI = btRigidBody::btRigidBodyConstructionInfo
|
||||
(0,0, mShape.get());
|
||||
mBody = new RigidBody(CI, name);
|
||||
mBody->mPlaceable = false;
|
||||
|
||||
setPosition(position);
|
||||
setRotation(rotation);
|
||||
|
||||
mEngine->mDynamicsWorld->addRigidBody(mBody, CollisionType_Actor,
|
||||
CollisionType_Actor|CollisionType_World|CollisionType_HeightMap);
|
||||
}
|
||||
|
||||
PhysicActor::~PhysicActor()
|
||||
{
|
||||
if(mBody)
|
||||
{
|
||||
mEngine->dynamicsWorld->removeRigidBody(mBody);
|
||||
mEngine->mDynamicsWorld->removeRigidBody(mBody);
|
||||
delete mBody;
|
||||
}
|
||||
if(mRaycastingBody)
|
||||
{
|
||||
mEngine->dynamicsWorld->removeRigidBody(mRaycastingBody);
|
||||
delete mRaycastingBody;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PhysicActor::enableCollisionMode(bool collision)
|
||||
{
|
||||
mCollisionMode = collision;
|
||||
mInternalCollisionMode = collision;
|
||||
}
|
||||
|
||||
void PhysicActor::enableCollisionBody(bool collision)
|
||||
{
|
||||
assert(mBody);
|
||||
if(collision && !mCollisionBody) enableCollisionBody();
|
||||
if(!collision && mCollisionBody) disableCollisionBody();
|
||||
mCollisionBody = collision;
|
||||
if(collision && !mExternalCollisionMode) enableCollisionBody();
|
||||
if(!collision && mExternalCollisionMode) disableCollisionBody();
|
||||
mExternalCollisionMode = collision;
|
||||
}
|
||||
|
||||
void PhysicActor::setPosition(const Ogre::Vector3 &pos)
|
||||
const Ogre::Vector3& PhysicActor::getPosition() const
|
||||
{
|
||||
return mPosition;
|
||||
}
|
||||
|
||||
void PhysicActor::setPosition(const Ogre::Vector3 &position)
|
||||
{
|
||||
assert(mBody);
|
||||
if(pos != getPosition())
|
||||
{
|
||||
mEngine->adjustRigidBody(mBody, pos, getRotation(), mBoxScaledTranslation, mBoxRotation);
|
||||
mEngine->adjustRigidBody(mRaycastingBody, pos, getRotation(), mBoxScaledTranslation, mBoxRotation);
|
||||
}
|
||||
|
||||
mPosition = position;
|
||||
|
||||
btTransform tr = mBody->getWorldTransform();
|
||||
Ogre::Quaternion meshrot = mMeshOrientation;
|
||||
Ogre::Vector3 transrot = meshrot * (mMeshTranslation * mScale);
|
||||
Ogre::Vector3 newPosition = transrot + position;
|
||||
|
||||
tr.setOrigin(BtOgre::Convert::toBullet(newPosition));
|
||||
mBody->setWorldTransform(tr);
|
||||
}
|
||||
|
||||
void PhysicActor::setRotation(const Ogre::Quaternion &quat)
|
||||
void PhysicActor::setRotation (const Ogre::Quaternion& rotation)
|
||||
{
|
||||
assert(mBody);
|
||||
if(!quat.equals(getRotation(), Ogre::Radian(0))){
|
||||
mEngine->adjustRigidBody(mBody, getPosition(), quat, mBoxScaledTranslation, mBoxRotation);
|
||||
mEngine->adjustRigidBody(mRaycastingBody, getPosition(), quat, mBoxScaledTranslation, mBoxRotation);
|
||||
|
||||
}
|
||||
btTransform tr = mBody->getWorldTransform();
|
||||
tr.setRotation(BtOgre::Convert::toBullet(mMeshOrientation * rotation));
|
||||
mBody->setWorldTransform(tr);
|
||||
}
|
||||
|
||||
|
||||
Ogre::Vector3 PhysicActor::getPosition()
|
||||
void PhysicActor::setScale(float scale)
|
||||
{
|
||||
assert(mBody);
|
||||
btVector3 vec = mBody->getWorldTransform().getOrigin();
|
||||
Ogre::Quaternion rotation = Ogre::Quaternion(mBody->getWorldTransform().getRotation().getW(), mBody->getWorldTransform().getRotation().getX(),
|
||||
mBody->getWorldTransform().getRotation().getY(), mBody->getWorldTransform().getRotation().getZ());
|
||||
Ogre::Vector3 transrot = rotation * mBoxScaledTranslation;
|
||||
Ogre::Vector3 visualPosition = Ogre::Vector3(vec.getX(), vec.getY(), vec.getZ()) - transrot;
|
||||
return visualPosition;
|
||||
}
|
||||
|
||||
Ogre::Quaternion PhysicActor::getRotation()
|
||||
{
|
||||
assert(mBody);
|
||||
btQuaternion quat = mBody->getWorldTransform().getRotation();
|
||||
return Ogre::Quaternion(quat.getW(), quat.getX(), quat.getY(), quat.getZ()) * mBoxRotationInverse;
|
||||
}
|
||||
|
||||
void PhysicActor::setScale(float scale){
|
||||
//We only need to change the scaled box translation, box rotations remain the same.
|
||||
assert(mBody);
|
||||
mBoxScaledTranslation = mBoxScaledTranslation / mBody->getCollisionShape()->getLocalScaling().getX();
|
||||
mBoxScaledTranslation *= scale;
|
||||
Ogre::Vector3 pos = getPosition();
|
||||
Ogre::Quaternion rot = getRotation();
|
||||
if(mBody){
|
||||
mEngine->dynamicsWorld->removeRigidBody(mBody);
|
||||
mEngine->dynamicsWorld->removeRigidBody(mRaycastingBody);
|
||||
delete mBody;
|
||||
delete mRaycastingBody;
|
||||
}
|
||||
//Create the newly scaled rigid body
|
||||
mBody = mEngine->createAndAdjustRigidBody(mMesh, mName, scale, pos, rot);
|
||||
mRaycastingBody = mEngine->createAndAdjustRigidBody(mMesh, mName, scale, pos, rot, 0, 0, true);
|
||||
mEngine->addRigidBody(mCollisionBody ? mBody : 0, false, mRaycastingBody,true); //Add rigid body to dynamics world, but do not add to object map
|
||||
mScale = scale;
|
||||
mShape->setLocalScaling(btVector3(scale,scale,scale));
|
||||
setPosition(mPosition);
|
||||
}
|
||||
|
||||
Ogre::Vector3 PhysicActor::getHalfExtents() const
|
||||
{
|
||||
if(mBody)
|
||||
{
|
||||
btBoxShape *box = static_cast<btBoxShape*>(mBody->getCollisionShape());
|
||||
if(box != NULL)
|
||||
{
|
||||
btVector3 size = box->getHalfExtentsWithMargin();
|
||||
return Ogre::Vector3(size.getX(), size.getY(), size.getZ());
|
||||
}
|
||||
}
|
||||
return Ogre::Vector3(0.0f);
|
||||
return mHalfExtents * mScale;
|
||||
}
|
||||
|
||||
void PhysicActor::setInertialForce(const Ogre::Vector3 &force)
|
||||
|
@ -139,12 +178,16 @@ namespace Physic
|
|||
|
||||
void PhysicActor::disableCollisionBody()
|
||||
{
|
||||
mEngine->dynamicsWorld->removeRigidBody(mBody);
|
||||
mEngine->mDynamicsWorld->removeRigidBody(mBody);
|
||||
mEngine->mDynamicsWorld->addRigidBody(mBody, CollisionType_Actor,
|
||||
CollisionType_Raycasting);
|
||||
}
|
||||
|
||||
void PhysicActor::enableCollisionBody()
|
||||
{
|
||||
mEngine->dynamicsWorld->addRigidBody(mBody,CollisionType_Actor,CollisionType_World|CollisionType_HeightMap);
|
||||
mEngine->mDynamicsWorld->removeRigidBody(mBody);
|
||||
mEngine->mDynamicsWorld->addRigidBody(mBody, CollisionType_Actor,
|
||||
CollisionType_Actor|CollisionType_World|CollisionType_HeightMap);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -189,8 +232,8 @@ namespace Physic
|
|||
broadphase = new btDbvtBroadphase();
|
||||
|
||||
// The world.
|
||||
dynamicsWorld = new btDiscreteDynamicsWorld(dispatcher,broadphase,solver,collisionConfiguration);
|
||||
dynamicsWorld->setGravity(btVector3(0,0,-10));
|
||||
mDynamicsWorld = new btDiscreteDynamicsWorld(dispatcher,broadphase,solver,collisionConfiguration);
|
||||
mDynamicsWorld->setGravity(btVector3(0,0,-10));
|
||||
|
||||
if(BulletShapeManager::getSingletonPtr() == NULL)
|
||||
{
|
||||
|
@ -208,10 +251,10 @@ namespace Physic
|
|||
if(!isDebugCreated)
|
||||
{
|
||||
Ogre::SceneNode* node = mSceneMgr->getRootSceneNode()->createChildSceneNode();
|
||||
mDebugDrawer = new BtOgre::DebugDrawer(node, dynamicsWorld);
|
||||
dynamicsWorld->setDebugDrawer(mDebugDrawer);
|
||||
mDebugDrawer = new BtOgre::DebugDrawer(node, mDynamicsWorld);
|
||||
mDynamicsWorld->setDebugDrawer(mDebugDrawer);
|
||||
isDebugCreated = true;
|
||||
dynamicsWorld->debugDrawWorld();
|
||||
mDynamicsWorld->debugDrawWorld();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -238,10 +281,15 @@ namespace Physic
|
|||
|
||||
PhysicEngine::~PhysicEngine()
|
||||
{
|
||||
for (std::map<RigidBody*, AnimatedShapeInstance>::iterator it = mAnimatedShapes.begin(); it != mAnimatedShapes.end(); ++it)
|
||||
deleteShape(it->second.mCompound);
|
||||
for (std::map<RigidBody*, AnimatedShapeInstance>::iterator it = mAnimatedRaycastingShapes.begin(); it != mAnimatedRaycastingShapes.end(); ++it)
|
||||
deleteShape(it->second.mCompound);
|
||||
|
||||
HeightFieldContainer::iterator hf_it = mHeightFieldMap.begin();
|
||||
for (; hf_it != mHeightFieldMap.end(); ++hf_it)
|
||||
{
|
||||
dynamicsWorld->removeRigidBody(hf_it->second.mBody);
|
||||
mDynamicsWorld->removeRigidBody(hf_it->second.mBody);
|
||||
delete hf_it->second.mShape;
|
||||
delete hf_it->second.mBody;
|
||||
}
|
||||
|
@ -251,7 +299,7 @@ namespace Physic
|
|||
{
|
||||
if (rb_it->second != NULL)
|
||||
{
|
||||
dynamicsWorld->removeRigidBody(rb_it->second);
|
||||
mDynamicsWorld->removeRigidBody(rb_it->second);
|
||||
|
||||
delete rb_it->second;
|
||||
rb_it->second = NULL;
|
||||
|
@ -262,7 +310,7 @@ namespace Physic
|
|||
{
|
||||
if (rb_it->second != NULL)
|
||||
{
|
||||
dynamicsWorld->removeRigidBody(rb_it->second);
|
||||
mDynamicsWorld->removeRigidBody(rb_it->second);
|
||||
|
||||
delete rb_it->second;
|
||||
rb_it->second = NULL;
|
||||
|
@ -281,7 +329,7 @@ namespace Physic
|
|||
|
||||
delete mDebugDrawer;
|
||||
|
||||
delete dynamicsWorld;
|
||||
delete mDynamicsWorld;
|
||||
delete solver;
|
||||
delete collisionConfiguration;
|
||||
delete dispatcher;
|
||||
|
@ -331,7 +379,7 @@ namespace Physic
|
|||
|
||||
mHeightFieldMap [name] = hf;
|
||||
|
||||
dynamicsWorld->addRigidBody(body,CollisionType_HeightMap|CollisionType_Raycasting,
|
||||
mDynamicsWorld->addRigidBody(body,CollisionType_HeightMap,
|
||||
CollisionType_World|CollisionType_Actor|CollisionType_Raycasting);
|
||||
}
|
||||
|
||||
|
@ -343,7 +391,7 @@ namespace Physic
|
|||
|
||||
HeightField hf = mHeightFieldMap [name];
|
||||
|
||||
dynamicsWorld->removeRigidBody(hf.mBody);
|
||||
mDynamicsWorld->removeRigidBody(hf.mBody);
|
||||
delete hf.mShape;
|
||||
delete hf.mBody;
|
||||
|
||||
|
@ -367,7 +415,6 @@ namespace Physic
|
|||
{
|
||||
std::string sid = (boost::format("%07.3f") % scale).str();
|
||||
std::string outputstring = mesh + sid;
|
||||
//std::cout << "The string" << outputstring << "\n";
|
||||
|
||||
//get the shape from the .nif
|
||||
mShapeLoader->load(outputstring,"General");
|
||||
|
@ -397,17 +444,38 @@ namespace Physic
|
|||
if (!shape->mRaycastingShape && raycasting)
|
||||
return NULL;
|
||||
|
||||
if (!raycasting)
|
||||
shape->mCollisionShape->setLocalScaling( btVector3(scale,scale,scale));
|
||||
else
|
||||
shape->mRaycastingShape->setLocalScaling( btVector3(scale,scale,scale));
|
||||
btCollisionShape* collisionShape = raycasting ? shape->mRaycastingShape : shape->mCollisionShape;
|
||||
|
||||
// If this is an animated compound shape, we must duplicate it so we can animate
|
||||
// multiple instances independently.
|
||||
if (!raycasting && !shape->mAnimatedShapes.empty())
|
||||
collisionShape = duplicateCollisionShape(collisionShape);
|
||||
if (raycasting && !shape->mAnimatedRaycastingShapes.empty())
|
||||
collisionShape = duplicateCollisionShape(collisionShape);
|
||||
|
||||
collisionShape->setLocalScaling( btVector3(scale,scale,scale));
|
||||
|
||||
//create the real body
|
||||
btRigidBody::btRigidBodyConstructionInfo CI = btRigidBody::btRigidBodyConstructionInfo
|
||||
(0,0, raycasting ? shape->mRaycastingShape : shape->mCollisionShape);
|
||||
(0,0, collisionShape);
|
||||
RigidBody* body = new RigidBody(CI,name);
|
||||
body->mPlaceable = placeable;
|
||||
|
||||
if (!raycasting && !shape->mAnimatedShapes.empty())
|
||||
{
|
||||
AnimatedShapeInstance instance;
|
||||
instance.mAnimatedShapes = shape->mAnimatedShapes;
|
||||
instance.mCompound = collisionShape;
|
||||
mAnimatedShapes[body] = instance;
|
||||
}
|
||||
if (raycasting && !shape->mAnimatedRaycastingShapes.empty())
|
||||
{
|
||||
AnimatedShapeInstance instance;
|
||||
instance.mAnimatedShapes = shape->mAnimatedRaycastingShapes;
|
||||
instance.mCompound = collisionShape;
|
||||
mAnimatedRaycastingShapes[body] = instance;
|
||||
}
|
||||
|
||||
if(scaledBoxTranslation != 0)
|
||||
*scaledBoxTranslation = shape->mBoxTranslation * scale;
|
||||
if(boxRotation != 0)
|
||||
|
@ -415,34 +483,20 @@ namespace Physic
|
|||
|
||||
adjustRigidBody(body, position, rotation, shape->mBoxTranslation * scale, shape->mBoxRotation);
|
||||
|
||||
if (!raycasting)
|
||||
{
|
||||
assert (mCollisionObjectMap.find(name) == mCollisionObjectMap.end());
|
||||
mCollisionObjectMap[name] = body;
|
||||
mDynamicsWorld->addRigidBody(body,CollisionType_World,CollisionType_World|CollisionType_Actor|CollisionType_HeightMap);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert (mRaycastingObjectMap.find(name) == mRaycastingObjectMap.end());
|
||||
mRaycastingObjectMap[name] = body;
|
||||
mDynamicsWorld->addRigidBody(body,CollisionType_Raycasting,CollisionType_Raycasting);
|
||||
}
|
||||
|
||||
return body;
|
||||
|
||||
}
|
||||
|
||||
void PhysicEngine::addRigidBody(RigidBody* body, bool addToMap, RigidBody* raycastingBody,bool actor)
|
||||
{
|
||||
if(!body && !raycastingBody)
|
||||
return; // nothing to do
|
||||
|
||||
const std::string& name = (body ? body->mName : raycastingBody->mName);
|
||||
|
||||
if (body){
|
||||
if(actor) dynamicsWorld->addRigidBody(body,CollisionType_Actor,CollisionType_World|CollisionType_HeightMap);
|
||||
else dynamicsWorld->addRigidBody(body,CollisionType_World,CollisionType_World|CollisionType_Actor|CollisionType_HeightMap);
|
||||
}
|
||||
|
||||
if (raycastingBody)
|
||||
dynamicsWorld->addRigidBody(raycastingBody,CollisionType_Raycasting,CollisionType_Raycasting|CollisionType_World);
|
||||
|
||||
if(addToMap){
|
||||
removeRigidBody(name);
|
||||
deleteRigidBody(name);
|
||||
|
||||
if (body)
|
||||
mCollisionObjectMap[name] = body;
|
||||
if (raycastingBody)
|
||||
mRaycastingObjectMap[name] = raycastingBody;
|
||||
}
|
||||
}
|
||||
|
||||
void PhysicEngine::removeRigidBody(const std::string &name)
|
||||
|
@ -453,7 +507,7 @@ namespace Physic
|
|||
RigidBody* body = it->second;
|
||||
if(body != NULL)
|
||||
{
|
||||
dynamicsWorld->removeRigidBody(body);
|
||||
mDynamicsWorld->removeRigidBody(body);
|
||||
}
|
||||
}
|
||||
it = mRaycastingObjectMap.find(name);
|
||||
|
@ -462,7 +516,7 @@ namespace Physic
|
|||
RigidBody* body = it->second;
|
||||
if(body != NULL)
|
||||
{
|
||||
dynamicsWorld->removeRigidBody(body);
|
||||
mDynamicsWorld->removeRigidBody(body);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -476,6 +530,10 @@ namespace Physic
|
|||
|
||||
if(body != NULL)
|
||||
{
|
||||
if (mAnimatedShapes.find(body) != mAnimatedShapes.end())
|
||||
deleteShape(mAnimatedShapes[body].mCompound);
|
||||
mAnimatedShapes.erase(body);
|
||||
|
||||
delete body;
|
||||
}
|
||||
mCollisionObjectMap.erase(it);
|
||||
|
@ -487,6 +545,10 @@ namespace Physic
|
|||
|
||||
if(body != NULL)
|
||||
{
|
||||
if (mAnimatedRaycastingShapes.find(body) != mAnimatedRaycastingShapes.end())
|
||||
deleteShape(mAnimatedRaycastingShapes[body].mCompound);
|
||||
mAnimatedRaycastingShapes.erase(body);
|
||||
|
||||
delete body;
|
||||
}
|
||||
mRaycastingObjectMap.erase(it);
|
||||
|
@ -605,7 +667,7 @@ namespace Physic
|
|||
if (!body) // fall back to raycasting body if there is no collision body
|
||||
body = getRigidBody(name, true);
|
||||
ContactTestResultCallback callback;
|
||||
dynamicsWorld->contactTest(body, callback);
|
||||
mDynamicsWorld->contactTest(body, callback);
|
||||
return callback.mResult;
|
||||
}
|
||||
|
||||
|
@ -615,16 +677,16 @@ namespace Physic
|
|||
btCollisionObject *object)
|
||||
{
|
||||
DeepestNotMeContactTestResultCallback callback(filter, origin);
|
||||
callback.m_collisionFilterGroup = CollisionType_Actor;
|
||||
callback.m_collisionFilterMask = CollisionType_World | CollisionType_HeightMap | CollisionType_Actor;
|
||||
dynamicsWorld->contactTest(object, callback);
|
||||
mDynamicsWorld->contactTest(object, callback);
|
||||
return std::make_pair(callback.mObject, callback.mContactPoint);
|
||||
}
|
||||
|
||||
|
||||
void PhysicEngine::stepSimulation(double deltaT)
|
||||
{
|
||||
// This seems to be needed for character controller objects
|
||||
dynamicsWorld->stepSimulation(deltaT,10, 1/60.0);
|
||||
mDynamicsWorld->stepSimulation(deltaT,10, 1/60.0);
|
||||
if(isDebugCreated)
|
||||
{
|
||||
mDebugDrawer->step();
|
||||
|
@ -640,8 +702,6 @@ namespace Physic
|
|||
|
||||
PhysicActor* newActor = new PhysicActor(name, mesh, this, position, rotation, scale);
|
||||
|
||||
|
||||
//dynamicsWorld->addAction( newActor->mCharacter );
|
||||
mActorMap[name] = newActor;
|
||||
}
|
||||
|
||||
|
@ -653,7 +713,6 @@ namespace Physic
|
|||
PhysicActor* act = it->second;
|
||||
if(act != NULL)
|
||||
{
|
||||
|
||||
delete act;
|
||||
}
|
||||
mActorMap.erase(it);
|
||||
|
@ -684,14 +743,15 @@ namespace Physic
|
|||
float d = -1;
|
||||
|
||||
btCollisionWorld::ClosestRayResultCallback resultCallback1(from, to);
|
||||
resultCallback1.m_collisionFilterGroup = 0xff;
|
||||
if(raycastingObjectOnly)
|
||||
resultCallback1.m_collisionFilterMask = CollisionType_Raycasting;
|
||||
resultCallback1.m_collisionFilterMask = CollisionType_Raycasting|CollisionType_Actor;
|
||||
else
|
||||
resultCallback1.m_collisionFilterMask = CollisionType_World;
|
||||
|
||||
if(!ignoreHeightMap)
|
||||
resultCallback1.m_collisionFilterMask = resultCallback1.m_collisionFilterMask | CollisionType_HeightMap;
|
||||
dynamicsWorld->rayTest(from, to, resultCallback1);
|
||||
mDynamicsWorld->rayTest(from, to, resultCallback1);
|
||||
if (resultCallback1.hasHit())
|
||||
{
|
||||
name = static_cast<const RigidBody&>(*resultCallback1.m_collisionObject).mName;
|
||||
|
@ -724,6 +784,7 @@ namespace Physic
|
|||
std::pair<bool, float> PhysicEngine::sphereCast (float radius, btVector3& from, btVector3& to)
|
||||
{
|
||||
OurClosestConvexResultCallback callback(from, to);
|
||||
callback.m_collisionFilterGroup = 0xff;
|
||||
callback.m_collisionFilterMask = OEngine::Physic::CollisionType_World|OEngine::Physic::CollisionType_HeightMap;
|
||||
|
||||
btSphereShape shape(radius);
|
||||
|
@ -732,7 +793,7 @@ namespace Physic
|
|||
btTransform from_ (btrot, from);
|
||||
btTransform to_ (btrot, to);
|
||||
|
||||
dynamicsWorld->convexSweepTest(&shape, from_, to_, callback);
|
||||
mDynamicsWorld->convexSweepTest(&shape, from_, to_, callback);
|
||||
|
||||
if (callback.hasHit())
|
||||
return std::make_pair(true, callback.m_closestHitFraction);
|
||||
|
@ -743,8 +804,9 @@ namespace Physic
|
|||
std::vector< std::pair<float, std::string> > PhysicEngine::rayTest2(btVector3& from, btVector3& to)
|
||||
{
|
||||
MyRayResultCallback resultCallback1;
|
||||
resultCallback1.m_collisionFilterMask = CollisionType_Raycasting;
|
||||
dynamicsWorld->rayTest(from, to, resultCallback1);
|
||||
resultCallback1.m_collisionFilterGroup = 0xff;
|
||||
resultCallback1.m_collisionFilterMask = CollisionType_Raycasting|CollisionType_Actor|CollisionType_HeightMap;
|
||||
mDynamicsWorld->rayTest(from, to, resultCallback1);
|
||||
std::vector< std::pair<float, const btCollisionObject*> > results = resultCallback1.results;
|
||||
|
||||
std::vector< std::pair<float, std::string> > results2;
|
||||
|
|
|
@ -76,13 +76,13 @@ namespace Physic
|
|||
RigidBody(btRigidBody::btRigidBodyConstructionInfo& CI,std::string name);
|
||||
virtual ~RigidBody();
|
||||
std::string mName;
|
||||
|
||||
// Hack: placeable objects (that can be picked up by the player) have different collision behaviour.
|
||||
// This variable needs to be passed to BulletNifLoader.
|
||||
bool mPlaceable;
|
||||
};
|
||||
|
||||
/**
|
||||
* A physic actor uses a rigid body based on box shapes.
|
||||
* Pmove is used to move the physic actor around the dynamic world.
|
||||
*/
|
||||
|
||||
class PhysicActor
|
||||
{
|
||||
public:
|
||||
|
@ -92,13 +92,6 @@ namespace Physic
|
|||
|
||||
void setPosition(const Ogre::Vector3 &pos);
|
||||
|
||||
/**
|
||||
* This adjusts the rotation of a PhysicActor
|
||||
* If we have any problems with this (getting stuck in pmove) we should change it
|
||||
* from setting the visual orientation to setting the orientation of the rigid body directly.
|
||||
*/
|
||||
void setRotation(const Ogre::Quaternion &quat);
|
||||
|
||||
/**
|
||||
* Sets the collisionMode for this actor. If disabled, the actor can fly and clip geometry.
|
||||
*/
|
||||
|
@ -111,28 +104,20 @@ namespace Physic
|
|||
|
||||
bool getCollisionMode() const
|
||||
{
|
||||
return mCollisionMode;
|
||||
return mInternalCollisionMode;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This returns the visual position of the PhysicActor (used to position a scenenode).
|
||||
* Note - this is different from the position of the contained mBody.
|
||||
*/
|
||||
Ogre::Vector3 getPosition();
|
||||
|
||||
/**
|
||||
* Returns the visual orientation of the PhysicActor
|
||||
*/
|
||||
Ogre::Quaternion getRotation();
|
||||
|
||||
/**
|
||||
* Sets the scale of the PhysicActor
|
||||
*/
|
||||
void setScale(float scale);
|
||||
|
||||
void setRotation (const Ogre::Quaternion& rotation);
|
||||
|
||||
const Ogre::Vector3& getPosition() const;
|
||||
|
||||
/**
|
||||
* Returns the half extents for this PhysiActor
|
||||
* Returns the (scaled) half extents
|
||||
*/
|
||||
Ogre::Vector3 getHalfExtents() const;
|
||||
|
||||
|
@ -153,7 +138,7 @@ namespace Physic
|
|||
|
||||
bool getOnGround() const
|
||||
{
|
||||
return mCollisionMode && mOnGround;
|
||||
return mInternalCollisionMode && mOnGround;
|
||||
}
|
||||
|
||||
btCollisionObject *getCollisionBody() const
|
||||
|
@ -165,17 +150,21 @@ namespace Physic
|
|||
void disableCollisionBody();
|
||||
void enableCollisionBody();
|
||||
|
||||
OEngine::Physic::RigidBody* mBody;
|
||||
OEngine::Physic::RigidBody* mRaycastingBody;
|
||||
boost::shared_ptr<btCollisionShape> mShape;
|
||||
|
||||
Ogre::Vector3 mBoxScaledTranslation;
|
||||
Ogre::Quaternion mBoxRotation;
|
||||
Ogre::Quaternion mBoxRotationInverse;
|
||||
OEngine::Physic::RigidBody* mBody;
|
||||
|
||||
Ogre::Quaternion mMeshOrientation;
|
||||
Ogre::Vector3 mMeshTranslation;
|
||||
Ogre::Vector3 mHalfExtents;
|
||||
|
||||
float mScale;
|
||||
Ogre::Vector3 mPosition;
|
||||
|
||||
Ogre::Vector3 mForce;
|
||||
bool mOnGround;
|
||||
bool mCollisionMode;
|
||||
bool mCollisionBody;
|
||||
bool mInternalCollisionMode;
|
||||
bool mExternalCollisionMode;
|
||||
|
||||
std::string mMesh;
|
||||
std::string mName;
|
||||
|
@ -189,6 +178,14 @@ namespace Physic
|
|||
RigidBody* mBody;
|
||||
};
|
||||
|
||||
struct AnimatedShapeInstance
|
||||
{
|
||||
btCollisionShape* mCompound;
|
||||
|
||||
// Maps bone name to child index in the compound shape
|
||||
std::map<std::string, int> mAnimatedShapes;
|
||||
};
|
||||
|
||||
/**
|
||||
* The PhysicEngine class contain everything which is needed for Physic.
|
||||
* It's needed that Ogre Resources are set up before the PhysicEngine is created.
|
||||
|
@ -239,11 +236,6 @@ namespace Physic
|
|||
*/
|
||||
void removeHeightField(int x, int y);
|
||||
|
||||
/**
|
||||
* Add a RigidBody to the simulation
|
||||
*/
|
||||
void addRigidBody(RigidBody* body, bool addToMap = true, RigidBody* raycastingBody = NULL,bool actor = false);
|
||||
|
||||
/**
|
||||
* Remove a RigidBody from the simulation. It does not delete it, and does not remove it from the RigidBodyMap.
|
||||
*/
|
||||
|
@ -335,7 +327,7 @@ namespace Physic
|
|||
btDefaultCollisionConfiguration* collisionConfiguration;
|
||||
btSequentialImpulseConstraintSolver* solver;
|
||||
btCollisionDispatcher* dispatcher;
|
||||
btDiscreteDynamicsWorld* dynamicsWorld;
|
||||
btDiscreteDynamicsWorld* mDynamicsWorld;
|
||||
|
||||
//the NIF file loader.
|
||||
BulletShapeLoader* mShapeLoader;
|
||||
|
@ -346,8 +338,14 @@ namespace Physic
|
|||
typedef std::map<std::string,RigidBody*> RigidBodyContainer;
|
||||
RigidBodyContainer mCollisionObjectMap;
|
||||
|
||||
// Compound shapes that must be animated each frame based on bone positions
|
||||
// the index refers to an element in mCollisionObjectMap
|
||||
std::map<RigidBody*, AnimatedShapeInstance > mAnimatedShapes;
|
||||
|
||||
RigidBodyContainer mRaycastingObjectMap;
|
||||
|
||||
std::map<RigidBody*, AnimatedShapeInstance > mAnimatedRaycastingShapes;
|
||||
|
||||
typedef std::map<std::string, PhysicActor*> PhysicActorContainer;
|
||||
PhysicActorContainer mActorMap;
|
||||
|
||||
|
|
|
@ -65,12 +65,13 @@ void ActorTracer::doTrace(btCollisionObject *actor, const Ogre::Vector3 &start,
|
|||
to.setOrigin(btend);
|
||||
|
||||
ClosestNotMeConvexResultCallback newTraceCallback(actor, btstart-btend, btScalar(0.0));
|
||||
newTraceCallback.m_collisionFilterGroup = CollisionType_Actor;
|
||||
newTraceCallback.m_collisionFilterMask = CollisionType_World | CollisionType_HeightMap |
|
||||
CollisionType_Actor;
|
||||
|
||||
btCollisionShape *shape = actor->getCollisionShape();
|
||||
assert(shape->isConvex());
|
||||
enginePass->dynamicsWorld->convexSweepTest(static_cast<btConvexShape*>(shape),
|
||||
enginePass->mDynamicsWorld->convexSweepTest(static_cast<btConvexShape*>(shape),
|
||||
from, to, newTraceCallback);
|
||||
|
||||
// Copy the hit data over to our trace results struct:
|
||||
|
@ -89,27 +90,26 @@ void ActorTracer::doTrace(btCollisionObject *actor, const Ogre::Vector3 &start,
|
|||
}
|
||||
}
|
||||
|
||||
void ActorTracer::findGround(btCollisionObject *actor, const Ogre::Vector3 &start, const Ogre::Vector3 &end, const PhysicEngine *enginePass)
|
||||
void ActorTracer::findGround(const OEngine::Physic::PhysicActor* actor, const Ogre::Vector3 &start, const Ogre::Vector3 &end, const PhysicEngine *enginePass)
|
||||
{
|
||||
const btVector3 btstart(start.x, start.y, start.z+1.0f);
|
||||
const btVector3 btend(end.x, end.y, end.z+1.0f);
|
||||
|
||||
const btTransform &trans = actor->getWorldTransform();
|
||||
const btTransform &trans = actor->getCollisionBody()->getWorldTransform();
|
||||
btTransform from(trans.getBasis(), btstart);
|
||||
btTransform to(trans.getBasis(), btend);
|
||||
|
||||
ClosestNotMeConvexResultCallback newTraceCallback(actor, btstart-btend, btScalar(0.0));
|
||||
ClosestNotMeConvexResultCallback newTraceCallback(actor->getCollisionBody(), btstart-btend, btScalar(0.0));
|
||||
newTraceCallback.m_collisionFilterGroup = CollisionType_Actor;
|
||||
newTraceCallback.m_collisionFilterMask = CollisionType_World | CollisionType_HeightMap |
|
||||
CollisionType_Actor;
|
||||
|
||||
const btBoxShape *shape = dynamic_cast<btBoxShape*>(actor->getCollisionShape());
|
||||
assert(shape);
|
||||
btVector3 halfExtents(actor->getHalfExtents().x, actor->getHalfExtents().y, actor->getHalfExtents().z);
|
||||
|
||||
btVector3 halfExtents = shape->getHalfExtentsWithMargin();
|
||||
halfExtents[2] = 1.0f;
|
||||
btBoxShape box(halfExtents);
|
||||
btCylinderShapeZ base(halfExtents);
|
||||
|
||||
enginePass->dynamicsWorld->convexSweepTest(&box, from, to, newTraceCallback);
|
||||
enginePass->mDynamicsWorld->convexSweepTest(&base, from, to, newTraceCallback);
|
||||
if(newTraceCallback.hasHit())
|
||||
{
|
||||
const btVector3& tracehitnormal = newTraceCallback.m_hitNormalWorld;
|
||||
|
|
|
@ -12,6 +12,7 @@ namespace OEngine
|
|||
namespace Physic
|
||||
{
|
||||
class PhysicEngine;
|
||||
class PhysicActor;
|
||||
|
||||
struct ActorTracer
|
||||
{
|
||||
|
@ -22,7 +23,7 @@ namespace Physic
|
|||
|
||||
void doTrace(btCollisionObject *actor, const Ogre::Vector3 &start, const Ogre::Vector3 &end,
|
||||
const PhysicEngine *enginePass);
|
||||
void findGround(btCollisionObject *actor, const Ogre::Vector3 &start, const Ogre::Vector3 &end,
|
||||
void findGround(const OEngine::Physic::PhysicActor* actor, const Ogre::Vector3 &start, const Ogre::Vector3 &end,
|
||||
const PhysicEngine *enginePass);
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue