Merge remote-tracking branch 'scrawl/master'

deque
Marc Zinnschlag 11 years ago
commit 85965bfd47

@ -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::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);
Ogre::MaterialPtr mat = params.mObjects->mMaterialControllerMgr.getWritableMaterial(partSys);
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)
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())
{
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;
delete mStaticMesh;
if (mCompoundShape)
{
int n = mCompoundShape->getNumChildShapes();
for(int i=0; i <n;i++)
delete (mCompoundShape->getChildShape(i));
delete mCompoundShape;
}
}
else if (mHasShape && mShape->mCollide)
else
{
mShape->mCollisionShape = new TriangleMeshShape(mesh1,true);
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);
}
else
delete mesh1;
//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;
btTriangleMesh* mesh2 = new btTriangleMesh();
mStaticMesh = NULL;
mCompoundShape = NULL;
handleNode(mesh2, node,0,true,true,false);
handleNode(node,0,true,true,false);
if(mBoundingBox != NULL)
{
mShape->mRaycastingShape = mBoundingBox;
delete mesh2;
}
else if (mHasShape)
if (mCompoundShape)
{
mShape->mRaycastingShape = new TriangleMeshShape(mesh2,true);
mShape->mRaycastingShape = mCompoundShape;
if (mStaticMesh)
{
btTransform trans;
trans.setIdentity();
mCompoundShape->addChildShape(trans, new TriangleMeshShape(mStaticMesh,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
{
assert(mBody);
if(pos != getPosition())
{
mEngine->adjustRigidBody(mBody, pos, getRotation(), mBoxScaledTranslation, mBoxRotation);
mEngine->adjustRigidBody(mRaycastingBody, pos, getRotation(), mBoxScaledTranslation, mBoxRotation);
}
return mPosition;
}
void PhysicActor::setRotation(const Ogre::Quaternion &quat)
void PhysicActor::setPosition(const Ogre::Vector3 &position)
{
assert(mBody);
if(!quat.equals(getRotation(), Ogre::Radian(0))){
mEngine->adjustRigidBody(mBody, getPosition(), quat, mBoxScaledTranslation, mBoxRotation);
mEngine->adjustRigidBody(mRaycastingBody, getPosition(), quat, mBoxScaledTranslation, mBoxRotation);
}
}
mPosition = position;
btTransform tr = mBody->getWorldTransform();
Ogre::Quaternion meshrot = mMeshOrientation;
Ogre::Vector3 transrot = meshrot * (mMeshTranslation * mScale);
Ogre::Vector3 newPosition = transrot + position;
Ogre::Vector3 PhysicActor::getPosition()
{
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;
tr.setOrigin(BtOgre::Convert::toBullet(newPosition));
mBody->setWorldTransform(tr);
}
Ogre::Quaternion PhysicActor::getRotation()
void PhysicActor::setRotation (const Ogre::Quaternion& rotation)
{
assert(mBody);
btQuaternion quat = mBody->getWorldTransform().getRotation();
return Ogre::Quaternion(quat.getW(), quat.getX(), quat.getY(), quat.getZ()) * mBoxRotationInverse;
btTransform tr = mBody->getWorldTransform();
tr.setRotation(BtOgre::Convert::toBullet(mMeshOrientation * rotation));
mBody->setWorldTransform(tr);
}
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
void PhysicActor::setScale(float scale)
{
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);
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 (!raycasting)
{
assert (mCollisionObjectMap.find(name) == mCollisionObjectMap.end());
mCollisionObjectMap[name] = body;
mDynamicsWorld->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;
else
{
assert (mRaycastingObjectMap.find(name) == mRaycastingObjectMap.end());
mRaycastingObjectMap[name] = body;
mDynamicsWorld->addRigidBody(body,CollisionType_Raycasting,CollisionType_Raycasting);
}
return body;
}
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();
boost::shared_ptr<btCollisionShape> mShape;
OEngine::Physic::RigidBody* mBody;
OEngine::Physic::RigidBody* mRaycastingBody;
Ogre::Vector3 mBoxScaledTranslation;
Ogre::Quaternion mBoxRotation;
Ogre::Quaternion mBoxRotationInverse;
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…
Cancel
Save