1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-01-26 18:35:20 +00:00

Merge branch 'master' into tooltips

This commit is contained in:
scrawl 2012-05-04 07:38:27 +02:00
commit 4ddd24fdfc
26 changed files with 2896 additions and 97 deletions

View File

@ -122,6 +122,10 @@ set(OENGINE_BULLET
${LIBDIR}/openengine/bullet/physic.hpp ${LIBDIR}/openengine/bullet/physic.hpp
${LIBDIR}/openengine/bullet/BulletShapeLoader.cpp ${LIBDIR}/openengine/bullet/BulletShapeLoader.cpp
${LIBDIR}/openengine/bullet/BulletShapeLoader.h ${LIBDIR}/openengine/bullet/BulletShapeLoader.h
${LIBDIR}/openengine/bullet/pmove.cpp
${LIBDIR}/openengine/bullet/pmove.h
${LIBDIR}/openengine/bullet/trace.cpp
${LIBDIR}/openengine/bullet/trace.h
) )

View File

@ -148,7 +148,6 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager)
, mNewGame (false) , mNewGame (false)
, mUseSound (true) , mUseSound (true)
, mCompileAll (false) , mCompileAll (false)
, mFocusTDiff (0)
, mScriptContext (0) , mScriptContext (0)
, mFSStrict (false) , mFSStrict (false)
, mCfgMgr(configurationManager) , mCfgMgr(configurationManager)
@ -263,7 +262,6 @@ void OMW::Engine::setNewGame(bool newGame)
void OMW::Engine::go() void OMW::Engine::go()
{ {
mFocusTDiff = 0;
assert (!mCellName.empty()); assert (!mCellName.empty());
assert (!mMaster.empty()); assert (!mMaster.empty());
assert (!mOgre); assert (!mOgre);

View File

@ -74,7 +74,6 @@ namespace OMW
bool mNewGame; bool mNewGame;
bool mUseSound; bool mUseSound;
bool mCompileAll; bool mCompileAll;
float mFocusTDiff;
std::string mFocusName; std::string mFocusName;
std::map<std::string,std::string> mFallbackMap; std::map<std::string,std::string> mFallbackMap;

View File

@ -287,11 +287,12 @@ namespace MWClass
{ {
Ogre::Vector3 vector (0, 0, 0); Ogre::Vector3 vector (0, 0, 0);
vector.x = - getMovementSettings (ptr).mLeftRight * 200; vector.x = - getMovementSettings (ptr).mLeftRight * 127;
vector.y = getMovementSettings (ptr).mForwardBackward * 200; vector.y = getMovementSettings (ptr).mForwardBackward * 127;
vector.z = getMovementSettings(ptr).mUpDown * 127;
if (getStance (ptr, Run, false)) //if (getStance (ptr, Run, false))
vector *= 2; // vector *= 2;
return vector; return vector;
} }

View File

@ -161,6 +161,8 @@ namespace MWDialogue
bool DialogueManager::functionFilter(const MWWorld::Ptr& actor, const ESM::DialInfo& info,bool choice) bool DialogueManager::functionFilter(const MWWorld::Ptr& actor, const ESM::DialInfo& info,bool choice)
{ {
bool isCreature = (actor.getTypeName() != typeid(ESM::NPC).name());
for (std::vector<ESM::DialInfo::SelectStruct>::const_iterator iter (info.selects.begin()); for (std::vector<ESM::DialInfo::SelectStruct>::const_iterator iter (info.selects.begin());
iter != info.selects.end(); ++iter) iter != info.selects.end(); ++iter)
{ {
@ -195,6 +197,9 @@ namespace MWDialogue
case 46://Same faction case 46://Same faction
{ {
if (isCreature)
return false;
MWMechanics::NpcStats PCstats = MWWorld::Class::get(MWBase::Environment::get().getWorld()->getPlayer().getPlayer()).getNpcStats(MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); MWMechanics::NpcStats PCstats = MWWorld::Class::get(MWBase::Environment::get().getWorld()->getPlayer().getPlayer()).getNpcStats(MWBase::Environment::get().getWorld()->getPlayer().getPlayer());
MWMechanics::NpcStats NPCstats = MWWorld::Class::get(actor).getNpcStats(actor); MWMechanics::NpcStats NPCstats = MWWorld::Class::get(actor).getNpcStats(actor);
int sameFaction = 0; int sameFaction = 0;
@ -283,6 +288,8 @@ namespace MWDialogue
bool DialogueManager::isMatching (const MWWorld::Ptr& actor, bool DialogueManager::isMatching (const MWWorld::Ptr& actor,
const ESM::DialInfo::SelectStruct& select) const const ESM::DialInfo::SelectStruct& select) const
{ {
bool isCreature = (actor.getTypeName() != typeid(ESM::NPC).name());
char type = select.selectRule[1]; char type = select.selectRule[1];
if (type!='0') if (type!='0')
@ -380,6 +387,9 @@ namespace MWDialogue
return true; return true;
case '8':// not faction case '8':// not faction
if (isCreature)
return false;
if(select.type==ESM::VT_Int) if(select.type==ESM::VT_Int)
{ {
ESMS::LiveCellRef<ESM::NPC, MWWorld::RefData>* npc = actor.get<ESM::NPC>(); ESMS::LiveCellRef<ESM::NPC, MWWorld::RefData>* npc = actor.get<ESM::NPC>();
@ -394,6 +404,9 @@ namespace MWDialogue
return true; return true;
case '9':// not class case '9':// not class
if (isCreature)
return false;
if(select.type==ESM::VT_Int) if(select.type==ESM::VT_Int)
{ {
ESMS::LiveCellRef<ESM::NPC, MWWorld::RefData>* npc = actor.get<ESM::NPC>(); ESMS::LiveCellRef<ESM::NPC, MWWorld::RefData>* npc = actor.get<ESM::NPC>();
@ -408,6 +421,9 @@ namespace MWDialogue
return true; return true;
case 'A'://not Race case 'A'://not Race
if (isCreature)
return false;
if(select.type==ESM::VT_Int) if(select.type==ESM::VT_Int)
{ {
ESMS::LiveCellRef<ESM::NPC, MWWorld::RefData>* npc = actor.get<ESM::NPC>(); ESMS::LiveCellRef<ESM::NPC, MWWorld::RefData>* npc = actor.get<ESM::NPC>();
@ -464,6 +480,8 @@ namespace MWDialogue
bool DialogueManager::isMatching (const MWWorld::Ptr& actor, const ESM::DialInfo& info) const bool DialogueManager::isMatching (const MWWorld::Ptr& actor, const ESM::DialInfo& info) const
{ {
bool isCreature = (actor.getTypeName() != typeid(ESM::NPC).name());
// actor id // actor id
if (!info.actor.empty()) if (!info.actor.empty())
if (toLower (info.actor)!=MWWorld::Class::get (actor).getId (actor)) if (toLower (info.actor)!=MWWorld::Class::get (actor).getId (actor))
@ -472,6 +490,9 @@ namespace MWDialogue
//NPC race //NPC race
if (!info.race.empty()) if (!info.race.empty())
{ {
if (isCreature)
return false;
ESMS::LiveCellRef<ESM::NPC, MWWorld::RefData> *cellRef = actor.get<ESM::NPC>(); ESMS::LiveCellRef<ESM::NPC, MWWorld::RefData> *cellRef = actor.get<ESM::NPC>();
if (!cellRef) if (!cellRef)
@ -484,6 +505,9 @@ namespace MWDialogue
//NPC class //NPC class
if (!info.clas.empty()) if (!info.clas.empty())
{ {
if (isCreature)
return false;
ESMS::LiveCellRef<ESM::NPC, MWWorld::RefData> *cellRef = actor.get<ESM::NPC>(); ESMS::LiveCellRef<ESM::NPC, MWWorld::RefData> *cellRef = actor.get<ESM::NPC>();
if (!cellRef) if (!cellRef)
@ -496,6 +520,9 @@ namespace MWDialogue
//NPC faction //NPC faction
if (!info.npcFaction.empty()) if (!info.npcFaction.empty())
{ {
if (isCreature)
return false;
//MWWorld::Class npcClass = MWWorld::Class::get(actor); //MWWorld::Class npcClass = MWWorld::Class::get(actor);
MWMechanics::NpcStats stats = MWWorld::Class::get(actor).getNpcStats(actor); MWMechanics::NpcStats stats = MWWorld::Class::get(actor).getNpcStats(actor);
std::map<std::string,int>::iterator it = stats.mFactionRank.find(info.npcFaction); std::map<std::string,int>::iterator it = stats.mFactionRank.find(info.npcFaction);
@ -529,16 +556,18 @@ namespace MWDialogue
} }
//check gender //check gender
ESMS::LiveCellRef<ESM::NPC, MWWorld::RefData>* npc = actor.get<ESM::NPC>(); if (!isCreature)
if(npc->base->flags&npc->base->Female)
{ {
if(static_cast<int> (info.data.gender)==0) return false; ESMS::LiveCellRef<ESM::NPC, MWWorld::RefData>* npc = actor.get<ESM::NPC>();
if(npc->base->flags&npc->base->Female)
{
if(static_cast<int> (info.data.gender)==0) return false;
}
else
{
if(static_cast<int> (info.data.gender)==1) return false;
}
} }
else
{
if(static_cast<int> (info.data.gender)==1) return false;
}
// check cell // check cell
if (!info.cell.empty()) if (!info.cell.empty())
@ -839,6 +868,9 @@ namespace MWDialogue
std::string DialogueManager::getFaction() std::string DialogueManager::getFaction()
{ {
if (mActor.getTypeName() != typeid(ESM::NPC).name())
return "";
std::string factionID(""); std::string factionID("");
MWMechanics::NpcStats stats = MWWorld::Class::get(mActor).getNpcStats(mActor); MWMechanics::NpcStats stats = MWWorld::Class::get(mActor).getNpcStats(mActor);
if(stats.mFactionRank.empty()) if(stats.mFactionRank.empty())

View File

@ -9,6 +9,7 @@
#include "mode.hpp" #include "mode.hpp"
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwsound/soundmanager.hpp"
namespace namespace
{ {
@ -16,6 +17,7 @@ namespace
{ {
const char* mText; const char* mText;
const char* mButtons[3]; const char* mButtons[3];
const char* mSound;
ESM::Class::Specialization mSpecializations[3]; // The specialization for each answer ESM::Class::Specialization mSpecializations[3]; // The specialization for each answer
}; };
@ -25,6 +27,7 @@ namespace
{"Draw your dagger, mercifully endings its life with a single thrust.", {"Draw your dagger, mercifully endings its life with a single thrust.",
"Use herbs from your pack to put it to sleep.", "Use herbs from your pack to put it to sleep.",
"Do not interfere in the natural evolution of events, but rather take the opportunity to learn more about a strange animal that you have never seen before."}, "Do not interfere in the natural evolution of events, but rather take the opportunity to learn more about a strange animal that you have never seen before."},
"vo\\misc\\chargen qa1.wav",
{ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth} {ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth}
}, },
// Question 2 // Question 2
@ -32,6 +35,7 @@ namespace
{"Work in the forge with him casting iron for a new plow.", {"Work in the forge with him casting iron for a new plow.",
"Gather herbs for your mother who is preparing dinner.", "Gather herbs for your mother who is preparing dinner.",
"Go catch fish at the stream using a net and line."}, "Go catch fish at the stream using a net and line."},
"vo\\misc\\chargen qa2.wav",
{ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth} {ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth}
}, },
// Question 3 // Question 3
@ -39,6 +43,7 @@ namespace
{"Beat up your cousin, then tell him that if he ever calls you that nickname again, you will bloody him worse than this time.", {"Beat up your cousin, then tell him that if he ever calls you that nickname again, you will bloody him worse than this time.",
"Make up a story that makes your nickname a badge of honor instead of something humiliating.", "Make up a story that makes your nickname a badge of honor instead of something humiliating.",
"Make up an even more embarrassing nickname for him and use it constantly until he learns his lesson."}, "Make up an even more embarrassing nickname for him and use it constantly until he learns his lesson."},
"vo\\misc\\chargen qa3.wav",
{ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth} {ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth}
}, },
// Question 4 // Question 4
@ -46,6 +51,7 @@ namespace
{"This is a terrible practice. A person's thoughts are his own and no one, not even a king, has the right to make such an invasion into another human's mind.", {"This is a terrible practice. A person's thoughts are his own and no one, not even a king, has the right to make such an invasion into another human's mind.",
"Loyal followers to the king have nothing to fear from a Telepath. It is important to have a method of finding assassins and spies before it is too late.", "Loyal followers to the king have nothing to fear from a Telepath. It is important to have a method of finding assassins and spies before it is too late.",
"In these times, it is a necessary evil. Although you do not necessarily like the idea, a Telepath could have certain advantages during a time of war or in finding someone innocent of a crime."}, "In these times, it is a necessary evil. Although you do not necessarily like the idea, a Telepath could have certain advantages during a time of war or in finding someone innocent of a crime."},
"vo\\misc\\chargen qa4.wav",
{ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth} {ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth}
}, },
// Question 5 // Question 5
@ -53,6 +59,7 @@ namespace
{"Return to the store and give the shopkeeper his hard-earned money, explaining to him the mistake?", {"Return to the store and give the shopkeeper his hard-earned money, explaining to him the mistake?",
"Decide to put the extra money to good use and purchase items that would help your family?", "Decide to put the extra money to good use and purchase items that would help your family?",
"Pocket the extra money, knowing that shopkeepers in general tend to overcharge customers anyway?"}, "Pocket the extra money, knowing that shopkeepers in general tend to overcharge customers anyway?"},
"vo\\misc\\chargen qa5.wav",
{ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth} {ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth}
}, },
// Question 6 // Question 6
@ -60,6 +67,7 @@ namespace
{"Pick up the bag and signal to the guard, knowing that the only honorable thing to do is return the money to its rightful owner.", {"Pick up the bag and signal to the guard, knowing that the only honorable thing to do is return the money to its rightful owner.",
"Leave the bag there, knowing that it is better not to get involved.", "Leave the bag there, knowing that it is better not to get involved.",
"Pick up the bag and pocket it, knowing that the extra windfall will help your family in times of trouble."}, "Pick up the bag and pocket it, knowing that the extra windfall will help your family in times of trouble."},
"vo\\misc\\chargen qa6.wav",
{ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth} {ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth}
}, },
// Question 7 // Question 7
@ -67,6 +75,7 @@ namespace
{"Decline his offer, knowing that your father expects you to do the work, and it is better not to be in debt.", {"Decline his offer, knowing that your father expects you to do the work, and it is better not to be in debt.",
"Ask him to help you, knowing that two people can do the job faster than one, and agree to help him with one task of his choosing in the future.", "Ask him to help you, knowing that two people can do the job faster than one, and agree to help him with one task of his choosing in the future.",
"Accept his offer, reasoning that as long as the stables are cleaned, it matters not who does the cleaning."}, "Accept his offer, reasoning that as long as the stables are cleaned, it matters not who does the cleaning."},
"vo\\misc\\chargen qa7.wav",
{ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth} {ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth}
}, },
// Question 8 // Question 8
@ -74,6 +83,7 @@ namespace
{"Position yourself between the pipe and your mother.", {"Position yourself between the pipe and your mother.",
"Grab the hot pipe and try to push it away.", "Grab the hot pipe and try to push it away.",
"Push your mother out of the way."}, "Push your mother out of the way."},
"vo\\misc\\chargen qa8.wav",
{ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth} {ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth}
}, },
// Question 9 // Question 9
@ -81,6 +91,7 @@ namespace
{"Drop the sweetroll and step on it, then get ready for the fight.", {"Drop the sweetroll and step on it, then get ready for the fight.",
"Give him the sweetroll now without argument, knowing that later this afternoon you will have all your friends with you and can come and take whatever he owes you.", "Give him the sweetroll now without argument, knowing that later this afternoon you will have all your friends with you and can come and take whatever he owes you.",
"Act like you're going to give him the sweetroll, but at the last minute throw it in the air, hoping that they'll pay attention to it long enough for you to get a shot in on the leader."}, "Act like you're going to give him the sweetroll, but at the last minute throw it in the air, hoping that they'll pay attention to it long enough for you to get a shot in on the leader."},
"vo\\misc\\chargen qa9.wav",
{ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth} {ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth}
}, },
// Question 10 // Question 10
@ -88,6 +99,7 @@ namespace
{"Rush to the town's aid immediately, despite your lack of knowledge of the circumstances.", {"Rush to the town's aid immediately, despite your lack of knowledge of the circumstances.",
"Stand aside and allow the man and the mob to pass, realizing it is probably best not to get involved.", "Stand aside and allow the man and the mob to pass, realizing it is probably best not to get involved.",
"Rush to the man's aid immediately, despite your lack of knowledge of the circumstances."}, "Rush to the man's aid immediately, despite your lack of knowledge of the circumstances."},
"vo\\misc\\chargen qa10.wav",
{ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth} {ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth}
} }
} }; } };
@ -479,6 +491,8 @@ void CharacterCreation::onCreateClassDialogBack()
void CharacterCreation::onClassQuestionChosen(int _index) void CharacterCreation::onClassQuestionChosen(int _index)
{ {
MWBase::Environment::get().getSoundManager()->stopSay();
if (mGenerateClassQuestionDialog) if (mGenerateClassQuestionDialog)
mWM->removeDialog(mGenerateClassQuestionDialog); mWM->removeDialog(mGenerateClassQuestionDialog);
if (_index < 0 || _index >= 3) if (_index < 0 || _index >= 3)
@ -584,6 +598,8 @@ void CharacterCreation::showClassQuestionDialog()
mGenerateClassQuestionDialog->setButtons(buttons); mGenerateClassQuestionDialog->setButtons(buttons);
mGenerateClassQuestionDialog->eventButtonSelected += MyGUI::newDelegate(this, &CharacterCreation::onClassQuestionChosen); mGenerateClassQuestionDialog->eventButtonSelected += MyGUI::newDelegate(this, &CharacterCreation::onClassQuestionChosen);
mGenerateClassQuestionDialog->open(); mGenerateClassQuestionDialog->open();
MWBase::Environment::get().getSoundManager()->say(sGenerateClassSteps[mGenerateClassStep].mSound);
} }
void CharacterCreation::onGenerateClassBack() void CharacterCreation::onGenerateClassBack()

View File

@ -60,6 +60,7 @@ namespace MWInput
A_CycleWeaponRight, A_CycleWeaponRight,
A_ToggleSneak, //Toggles Sneak, add Push-Sneak later A_ToggleSneak, //Toggles Sneak, add Push-Sneak later
A_ToggleWalk, //Toggle Walking/Running A_ToggleWalk, //Toggle Walking/Running
A_Crouch,
A_QuickSave, A_QuickSave,
A_QuickLoad, A_QuickLoad,
@ -310,6 +311,9 @@ namespace MWInput
poller.bind(A_MoveRight, KC_D); poller.bind(A_MoveRight, KC_D);
poller.bind(A_MoveForward, KC_W); poller.bind(A_MoveForward, KC_W);
poller.bind(A_MoveBackward, KC_S); poller.bind(A_MoveBackward, KC_S);
poller.bind(A_Jump, KC_E);
poller.bind(A_Crouch, KC_LCONTROL);
} }
//NOTE: Used to check for movement keys //NOTE: Used to check for movement keys
@ -356,6 +360,13 @@ namespace MWInput
} }
else else
player.setForwardBackward (0); player.setForwardBackward (0);
if (poller.isDown(A_Jump))
player.setUpDown (1);
else if (poller.isDown(A_Crouch))
player.setUpDown (-1);
else
player.setUpDown (0);
} }
// Switch between gui modes. Besides controlling the Gui windows // Switch between gui modes. Besides controlling the Gui windows

View File

@ -8,8 +8,9 @@ namespace MWMechanics
{ {
signed char mLeftRight; // 1: wants to move left, -1: wants to move right signed char mLeftRight; // 1: wants to move left, -1: wants to move right
signed char mForwardBackward; // 1:wants to move forward, -1: wants to move backward signed char mForwardBackward; // 1:wants to move forward, -1: wants to move backward
signed char mUpDown;
Movement() : mLeftRight (0), mForwardBackward (0) {} Movement() : mLeftRight (0), mForwardBackward (0), mUpDown(0) {}
}; };
} }

View File

@ -53,8 +53,10 @@ void Objects::insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_)
Ogre::SceneNode* insert = cellnode->createChildSceneNode(); Ogre::SceneNode* insert = cellnode->createChildSceneNode();
const float *f = ptr.getRefData().getPosition().pos; const float *f = ptr.getRefData().getPosition().pos;
insert->setPosition(f[0], f[1], f[2]); insert->setPosition(f[0], f[1], f[2]);
insert->setScale(ptr.getCellRef().scale, ptr.getCellRef().scale, ptr.getCellRef().scale); insert->setScale(ptr.getCellRef().scale, ptr.getCellRef().scale, ptr.getCellRef().scale);
// Convert MW rotation to a quaternion: // Convert MW rotation to a quaternion:
f = ptr.getCellRef().pos.rot; f = ptr.getCellRef().pos.rot;

View File

@ -189,7 +189,7 @@ void MpgSnd_Decoder::readAll(std::vector<char> &output)
{ {
size_t pos = output.size(); size_t pos = output.size();
output.resize(pos + mSndInfo.frames*mSndInfo.channels*2); output.resize(pos + mSndInfo.frames*mSndInfo.channels*2);
sf_readf_short(mSndFile, (short*)(output.data()+pos), mSndInfo.frames); sf_readf_short(mSndFile, (short*)(&output[0]+pos), mSndInfo.frames);
return; return;
} }
// Fallback in case we don't know the total already // Fallback in case we don't know the total already

View File

@ -222,8 +222,8 @@ void OpenAL_SoundStream::play()
for(ALuint i = 0;i < sNumBuffers;i++) for(ALuint i = 0;i < sNumBuffers;i++)
{ {
size_t got; size_t got;
got = mDecoder->read(data.data(), data.size()); got = mDecoder->read(&data[0], data.size());
alBufferData(mBuffers[i], mFormat, data.data(), got, mSampleRate); alBufferData(mBuffers[i], mFormat, &data[0], got, mSampleRate);
} }
throwALerror(); throwALerror();
@ -299,11 +299,11 @@ bool OpenAL_SoundStream::process()
if(finished) if(finished)
continue; continue;
got = mDecoder->read(data.data(), data.size()); got = mDecoder->read(&data[0], data.size());
finished = (got < data.size()); finished = (got < data.size());
if(got > 0) if(got > 0)
{ {
alBufferData(bufid, mFormat, data.data(), got, mSampleRate); alBufferData(bufid, mFormat, &data[0], got, mSampleRate);
alSourceQueueBuffers(mSource, 1, &bufid); alSourceQueueBuffers(mSource, 1, &bufid);
} }
} while(processed > 0); } while(processed > 0);
@ -595,7 +595,7 @@ ALuint OpenAL_Output::getBuffer(const std::string &fname)
alGenBuffers(1, &buf); alGenBuffers(1, &buf);
throwALerror(); throwALerror();
alBufferData(buf, format, data.data(), data.size(), srate); alBufferData(buf, format, &data[0], data.size(), srate);
mBufferCache[fname] = buf; mBufferCache[fname] = buf;
mBufferRefs[buf] = 1; mBufferRefs[buf] = 1;

View File

@ -228,11 +228,47 @@ namespace MWSound
} }
} }
void SoundManager::say(const std::string& filename)
{
if(!mOutput->isInitialized())
return;
try
{
float basevol = mMasterVolume * mSFXVolume;
std::string filePath = "Sound/"+filename;
SoundPtr sound = mOutput->playSound(filePath, basevol, 1.0f, Play_Normal);
sound->mBaseVolume = basevol;
mActiveSounds[sound] = std::make_pair(MWWorld::Ptr(), std::string("_say_sound"));
}
catch(std::exception &e)
{
std::cout <<"Sound Error: "<<e.what()<< std::endl;
}
}
bool SoundManager::sayDone(MWWorld::Ptr ptr) const bool SoundManager::sayDone(MWWorld::Ptr ptr) const
{ {
return !isPlaying(ptr, "_say_sound"); return !isPlaying(ptr, "_say_sound");
} }
void SoundManager::stopSay(MWWorld::Ptr ptr)
{
SoundMap::iterator snditer = mActiveSounds.begin();
while(snditer != mActiveSounds.end())
{
if(snditer->second.first == ptr && snditer->second.second == "_say_sound")
{
snditer->first->stop();
mActiveSounds.erase(snditer++);
}
else
snditer++;
}
}
SoundPtr SoundManager::playSound(const std::string& soundId, float volume, float pitch, int mode) SoundPtr SoundManager::playSound(const std::string& soundId, float volume, float pitch, int mode)
{ {

View File

@ -97,11 +97,18 @@ namespace MWSound
void say(MWWorld::Ptr reference, const std::string& filename); void say(MWWorld::Ptr reference, const std::string& filename);
///< Make an actor say some text. ///< Make an actor say some text.
/// \param filename name of a sound file in "Sound/Vo/" in the data directory. /// \param filename name of a sound file in "Sound/" in the data directory.
bool sayDone(MWWorld::Ptr reference) const; void say(const std::string& filename);
///< Say some text, without an actor ref
/// \param filename name of a sound file in "Sound/" in the data directory.
bool sayDone(MWWorld::Ptr reference=MWWorld::Ptr()) const;
///< Is actor not speaking? ///< Is actor not speaking?
void stopSay(MWWorld::Ptr reference=MWWorld::Ptr());
///< Stop an actor speaking
SoundPtr playSound(const std::string& soundId, float volume, float pitch, int mode=Play_Normal); SoundPtr playSound(const std::string& soundId, float volume, float pitch, int mode=Play_Normal);
///< Play a sound, independently of 3D-position ///< Play a sound, independently of 3D-position

View File

@ -21,23 +21,24 @@ namespace MWWorld
PhysicsSystem::PhysicsSystem(OEngine::Render::OgreRenderer &_rend) : PhysicsSystem::PhysicsSystem(OEngine::Render::OgreRenderer &_rend) :
mRender(_rend), mEngine(0), mFreeFly (true) mRender(_rend), mEngine(0), mFreeFly (true)
{ {
playerphysics = new playerMove;
// Create physics. shapeLoader is deleted by the physic engine // Create physics. shapeLoader is deleted by the physic engine
NifBullet::ManualBulletShapeLoader* shapeLoader = new NifBullet::ManualBulletShapeLoader(); NifBullet::ManualBulletShapeLoader* shapeLoader = new NifBullet::ManualBulletShapeLoader();
mEngine = new OEngine::Physic::PhysicEngine(shapeLoader); mEngine = new OEngine::Physic::PhysicEngine(shapeLoader);
playerphysics->mEngine = mEngine;
} }
PhysicsSystem::~PhysicsSystem() PhysicsSystem::~PhysicsSystem()
{ {
delete mEngine; delete mEngine;
} }
OEngine::Physic::PhysicEngine* PhysicsSystem::getEngine() OEngine::Physic::PhysicEngine* PhysicsSystem::getEngine()
{ {
return mEngine; return mEngine;
} }
std::pair<std::string, float> PhysicsSystem::getFacedHandle (MWWorld::World& world) std::pair<std::string, float> PhysicsSystem::getFacedHandle (MWWorld::World& world)
{ {
std::string handle = ""; std::string handle = "";
@ -65,6 +66,13 @@ namespace MWWorld
return mEngine->rayTest2(from,to); return mEngine->rayTest2(from,to);
} }
void PhysicsSystem::setCurrentWater(bool hasWater, int waterHeight){
playerphysics->hasWater = hasWater;
if(hasWater){
playerphysics->waterHeight = waterHeight;
}
}
btVector3 PhysicsSystem::getRayPoint(float extent) btVector3 PhysicsSystem::getRayPoint(float extent)
{ {
@ -75,35 +83,35 @@ namespace MWWorld
btVector3 result(centerRay.getPoint(500*extent).x,-centerRay.getPoint(500*extent).z,centerRay.getPoint(500*extent).y); btVector3 result(centerRay.getPoint(500*extent).x,-centerRay.getPoint(500*extent).z,centerRay.getPoint(500*extent).y);
return result; return result;
} }
bool PhysicsSystem::castRay(const Vector3& from, const Vector3& to) bool PhysicsSystem::castRay(const Vector3& from, const Vector3& to)
{ {
btVector3 _from, _to; btVector3 _from, _to;
_from = btVector3(from.x, from.y, from.z); _from = btVector3(from.x, from.y, from.z);
_to = btVector3(to.x, to.y, to.z); _to = btVector3(to.x, to.y, to.z);
std::pair<std::string, float> result = mEngine->rayTest(_from, _to); std::pair<std::string, float> result = mEngine->rayTest(_from, _to);
return !(result.first == ""); return !(result.first == "");
} }
void PhysicsSystem::doPhysics(float dt, const std::vector<std::pair<std::string, Ogre::Vector3> >& actors)
std::vector< std::pair<std::string, Ogre::Vector3> > PhysicsSystem::doPhysics (float duration,
const std::vector<std::pair<std::string, Ogre::Vector3> >& actors)
{ {
//set the DebugRenderingMode. To disable it,set it to 0 //set the DebugRenderingMode. To disable it,set it to 0
//eng->setDebugRenderingMode(1); //eng->setDebugRenderingMode(1);
//set the walkdirection to 0 (no movement) for every actor) //set the walkdirection to 0 (no movement) for every actor)
for(std::map<std::string,OEngine::Physic::PhysicActor*>::iterator it = mEngine->PhysicActorMap.begin(); it != mEngine->PhysicActorMap.end();it++) for(std::map<std::string,OEngine::Physic::PhysicActor*>::iterator it = mEngine->PhysicActorMap.begin(); it != mEngine->PhysicActorMap.end();it++)
{ {
OEngine::Physic::PhysicActor* act = it->second; OEngine::Physic::PhysicActor* act = it->second;
act->setWalkDirection(btVector3(0,0,0)); act->setWalkDirection(btVector3(0,0,0));
} }
playerMove::playercmd& pm_ref = playerphysics->cmd;
pm_ref.rightmove = 0;
pm_ref.forwardmove = 0;
pm_ref.upmove = 0;
//playerphysics->ps.move_type = PM_NOCLIP; //playerphysics->ps.move_type = PM_NOCLIP;
for (std::vector<std::pair<std::string, Ogre::Vector3> >::const_iterator iter (actors.begin()); for (std::vector<std::pair<std::string, Ogre::Vector3> >::const_iterator iter (actors.begin());
iter!=actors.end(); ++iter) iter!=actors.end(); ++iter)
@ -118,21 +126,24 @@ namespace MWWorld
Ogre::Node* yawNode = sceneNode->getChildIterator().getNext(); Ogre::Node* yawNode = sceneNode->getChildIterator().getNext();
Ogre::Node* pitchNode = yawNode->getChildIterator().getNext(); Ogre::Node* pitchNode = yawNode->getChildIterator().getNext();
Ogre::Quaternion yawQuat = yawNode->getOrientation(); Ogre::Quaternion yawQuat = yawNode->getOrientation();
Ogre::Quaternion pitchQuat = pitchNode->getOrientation(); Ogre::Quaternion pitchQuat = pitchNode->getOrientation();
Ogre::Quaternion both = yawQuat * pitchQuat;
// unused
//Ogre::Quaternion both = yawQuat * pitchQuat;
//playerphysics->ps.viewangles.z = both.getPitch().valueDegrees();
playerphysics->ps.viewangles.x = pitchQuat.getPitch().valueDegrees();
playerphysics->ps.viewangles.z = 0;
playerphysics->ps.viewangles.y = yawQuat.getYaw().valueDegrees() *-1 + 90;
if(mFreeFly) if(mFreeFly)
{ {
Ogre::Vector3 dir1(iter->second.x,iter->second.z,-iter->second.y); Ogre::Vector3 dir1(iter->second.x,iter->second.z,-iter->second.y);
pm_ref.rightmove = -dir1.x;
pm_ref.forwardmove = dir1.z;
pm_ref.upmove = dir1.y;
//std::cout << "Current angle" << yawQuat.getYaw().valueDegrees() - 90<< "\n"; //std::cout << "Current angle" << yawQuat.getYaw().valueDegrees() - 90<< "\n";
//playerphysics->ps.viewangles.x = pitchQuat.getPitch().valueDegrees(); //playerphysics->ps.viewangles.x = pitchQuat.getPitch().valueDegrees();
//std::cout << "Pitch: " << yawQuat.getPitch() << "Yaw:" << yawQuat.getYaw() << "Roll: " << yawQuat.getRoll() << "\n"; //std::cout << "Pitch: " << yawQuat.getPitch() << "Yaw:" << yawQuat.getYaw() << "Roll: " << yawQuat.getRoll() << "\n";
@ -140,31 +151,65 @@ namespace MWWorld
} }
else else
{ {
Ogre::Quaternion quat = yawNode->getOrientation(); Ogre::Quaternion quat = yawNode->getOrientation();
Ogre::Vector3 dir1(iter->second.x,iter->second.z,-iter->second.y); Ogre::Vector3 dir1(iter->second.x,iter->second.z,-iter->second.y);
pm_ref.rightmove = -dir1.x;
pm_ref.forwardmove = dir1.z;
pm_ref.upmove = dir1.y;
dir = 0.025*(quat*dir1); dir = 0.025*(quat*dir1);
} }
//set the walk direction //set the walk direction
act->setWalkDirection(btVector3(dir.x,-dir.z,dir.y)); act->setWalkDirection(btVector3(dir.x,-dir.z,dir.y));
} }
mEngine->stepSimulation(duration); mEngine->stepSimulation(dt);
}
std::vector< std::pair<std::string, Ogre::Vector3> > PhysicsSystem::doPhysicsFixed (
const std::vector<std::pair<std::string, Ogre::Vector3> >& actors)
{
Pmove(playerphysics);
std::vector< std::pair<std::string, Ogre::Vector3> > response; std::vector< std::pair<std::string, Ogre::Vector3> > response;
for(std::map<std::string,OEngine::Physic::PhysicActor*>::iterator it = mEngine->PhysicActorMap.begin(); it != mEngine->PhysicActorMap.end();it++) for(std::map<std::string,OEngine::Physic::PhysicActor*>::iterator it = mEngine->PhysicActorMap.begin(); it != mEngine->PhysicActorMap.end();it++)
{ {
btVector3 newPos = it->second->getPosition(); btVector3 newPos = it->second->getPosition();
Ogre::Vector3 coord(newPos.x(), newPos.y(), newPos.z()); Ogre::Vector3 coord(newPos.x(), newPos.y(), newPos.z());
if(it->first == "player"){
coord = playerphysics->ps.origin;
//std::cout << "ZCoord: " << coord.z << "\n";
//std::cout << "Coord" << coord << "\n";
//coord = Ogre::Vector3(coord.x, coord.z, coord.y); //x, z, -y
}
response.push_back(std::pair<std::string, Ogre::Vector3>(it->first, coord)); response.push_back(std::pair<std::string, Ogre::Vector3>(it->first, coord));
} }
return response; return response;
} }
void PhysicsSystem::addHeightField (float* heights,
int x, int y, float yoffset,
float triSize, float sqrtVerts)
{
mEngine->addHeightField(heights, x, y, yoffset, triSize, sqrtVerts);
}
void PhysicsSystem::removeHeightField (int x, int y)
{
mEngine->removeHeightField(x, y);
}
void PhysicsSystem::addObject (const std::string& handle, const std::string& mesh, void PhysicsSystem::addObject (const std::string& handle, const std::string& mesh,
const Ogre::Quaternion& rotation, float scale, const Ogre::Vector3& position) const Ogre::Quaternion& rotation, float scale, const Ogre::Vector3& position)
{ {
@ -207,7 +252,14 @@ namespace MWWorld
{ {
// TODO very dirty hack to avoid crash during setup -> needs cleaning up to allow // TODO very dirty hack to avoid crash during setup -> needs cleaning up to allow
// start positions others than 0, 0, 0 // start positions others than 0, 0, 0
act->setPosition(btVector3(position.x,position.y,position.z)); if (handle == "player")
{
playerphysics->ps.origin = position;
}
else
{
act->setPosition(btVector3(position.x,position.y,position.z));
}
} }
} }
@ -228,6 +280,11 @@ namespace MWWorld
bool PhysicsSystem::toggleCollisionMode() bool PhysicsSystem::toggleCollisionMode()
{ {
if(playerphysics->ps.move_type==PM_NOCLIP)
playerphysics->ps.move_type=PM_NORMAL;
else
playerphysics->ps.move_type=PM_NOCLIP;
for(std::map<std::string,OEngine::Physic::PhysicActor*>::iterator it = mEngine->PhysicActorMap.begin(); it != mEngine->PhysicActorMap.end();it++) for(std::map<std::string,OEngine::Physic::PhysicActor*>::iterator it = mEngine->PhysicActorMap.begin(); it != mEngine->PhysicActorMap.end();it++)
{ {
if (it->first=="player") if (it->first=="player")
@ -258,7 +315,12 @@ namespace MWWorld
} }
void PhysicsSystem::insertObjectPhysics(const MWWorld::Ptr& ptr, const std::string model){ void PhysicsSystem::insertObjectPhysics(const MWWorld::Ptr& ptr, const std::string model){
Ogre::SceneNode* node = ptr.getRefData().getBaseNode(); Ogre::SceneNode* node = ptr.getRefData().getBaseNode();
// unused
//Ogre::Vector3 objPos = node->getPosition();
addObject (node->getName(), model, node->getOrientation(), addObject (node->getName(), model, node->getOrientation(),
node->getScale().x, node->getPosition()); node->getScale().x, node->getPosition());
} }

View File

@ -5,6 +5,7 @@
#include <openengine/ogre/renderer.hpp> #include <openengine/ogre/renderer.hpp>
#include <openengine/bullet/physic.hpp> #include <openengine/bullet/physic.hpp>
#include "ptr.hpp" #include "ptr.hpp"
#include <openengine/bullet/pmove.h>
namespace MWWorld namespace MWWorld
{ {
@ -15,8 +16,11 @@ namespace MWWorld
PhysicsSystem (OEngine::Render::OgreRenderer &_rend); PhysicsSystem (OEngine::Render::OgreRenderer &_rend);
~PhysicsSystem (); ~PhysicsSystem ();
std::vector< std::pair<std::string, Ogre::Vector3> > doPhysics (float duration, void doPhysics(float duration, const std::vector<std::pair<std::string, Ogre::Vector3> >& actors);
const std::vector<std::pair<std::string, Ogre::Vector3> >& actors); ///< do physics with dt - Usage: first call doPhysics with frame dt, then call doPhysicsFixed as often as time steps have passed
std::vector< std::pair<std::string, Ogre::Vector3> > doPhysicsFixed (const std::vector<std::pair<std::string, Ogre::Vector3> >& actors);
///< do physics with fixed timestep - Usage: first call doPhysics with frame dt, then call doPhysicsFixed as often as time steps have passed
void addObject (const std::string& handle, const std::string& mesh, void addObject (const std::string& handle, const std::string& mesh,
const Ogre::Quaternion& rotation, float scale, const Ogre::Vector3& position); const Ogre::Quaternion& rotation, float scale, const Ogre::Vector3& position);
@ -24,6 +28,12 @@ namespace MWWorld
void addActor (const std::string& handle, const std::string& mesh, void addActor (const std::string& handle, const std::string& mesh,
const Ogre::Vector3& position); const Ogre::Vector3& position);
void addHeightField (float* heights,
int x, int y, float yoffset,
float triSize, float sqrtVerts);
void removeHeightField (int x, int y);
void removeObject (const std::string& handle); void removeObject (const std::string& handle);
void moveObject (const std::string& handle, const Ogre::Vector3& position); void moveObject (const std::string& handle, const Ogre::Vector3& position);
@ -49,11 +59,13 @@ namespace MWWorld
OEngine::Physic::PhysicEngine* getEngine(); OEngine::Physic::PhysicEngine* getEngine();
void setCurrentWater(bool hasWater, int waterHeight);
private: private:
OEngine::Render::OgreRenderer &mRender; OEngine::Render::OgreRenderer &mRender;
OEngine::Physic::PhysicEngine* mEngine; OEngine::Physic::PhysicEngine* mEngine;
bool mFreeFly; bool mFreeFly;
playerMove* playerphysics;
PhysicsSystem (const PhysicsSystem&); PhysicsSystem (const PhysicsSystem&);
PhysicsSystem& operator= (const PhysicsSystem&); PhysicsSystem& operator= (const PhysicsSystem&);

View File

@ -85,6 +85,14 @@ namespace MWWorld
MWWorld::Class::get (ptr).getMovementSettings (ptr).mForwardBackward = value; MWWorld::Class::get (ptr).getMovementSettings (ptr).mForwardBackward = value;
} }
void Player::setUpDown(int value)
{
MWWorld::Ptr ptr = getPlayer();
MWWorld::Class::get (ptr).getMovementSettings (ptr).mUpDown = value;
}
void Player::toggleRunning() void Player::toggleRunning()
{ {
@ -100,4 +108,5 @@ namespace MWWorld
MWWorld::Ptr ptr = getPlayer(); MWWorld::Ptr ptr = getPlayer();
return MWWorld::Class::get(ptr).getNpcStats(ptr).mDrawState; return MWWorld::Class::get(ptr).getNpcStats(ptr).mDrawState;
} }
} }

View File

@ -116,6 +116,7 @@ namespace MWWorld
void setLeftRight (int value); void setLeftRight (int value);
void setForwardBackward (int value); void setForwardBackward (int value);
void setUpDown(int value);
void toggleRunning(); void toggleRunning();
}; };

View File

@ -75,11 +75,14 @@ namespace MWWorld
// silence annoying g++ warning // silence annoying g++ warning
for (std::vector<Ogre::SceneNode*>::const_iterator iter (functor.mHandles.begin()); for (std::vector<Ogre::SceneNode*>::const_iterator iter2 (functor.mHandles.begin());
iter!=functor.mHandles.end(); ++iter){ iter2!=functor.mHandles.end(); ++iter2){
Ogre::SceneNode* node = *iter; Ogre::SceneNode* node = *iter2;
mPhysics->removeObject (node->getName()); mPhysics->removeObject (node->getName());
} }
if (!((*iter)->cell->data.flags & ESM::Cell::Interior))
mPhysics->removeHeightField( (*iter)->cell->data.gridX, (*iter)->cell->data.gridY );
} }
mRendering.removeCell(*iter); mRendering.removeCell(*iter);
@ -103,20 +106,36 @@ namespace MWWorld
std::pair<CellStoreCollection::iterator, bool> result = std::pair<CellStoreCollection::iterator, bool> result =
mActiveCells.insert(cell); mActiveCells.insert(cell);
if(result.second){
insertCell(*cell);
mRendering.cellAdded(cell);
mRendering.configureAmbient(*cell);
mRendering.requestMap(cell);
mRendering.configureAmbient(*cell);
}
if(result.second)
{
insertCell(*cell);
mRendering.cellAdded (cell);
float verts = ESM::Land::LAND_SIZE;
float worldsize = ESM::Land::REAL_SIZE;
if (!(cell->cell->data.flags & ESM::Cell::Interior))
{
ESM::Land* land = mWorld->getStore().lands.search(cell->cell->data.gridX,cell->cell->data.gridY);
mPhysics->addHeightField (land->landData->heights,
cell->cell->data.gridX, cell->cell->data.gridY,
0, ( worldsize/(verts-1) ), verts);
}
mRendering.configureAmbient(*cell);
mRendering.requestMap(cell);
mRendering.configureAmbient(*cell);
}
} }
void Scene::playerCellChange (Ptr::CellStore *cell, const ESM::Position& position, void Scene::playerCellChange (Ptr::CellStore *cell, const ESM::Position& position,
bool adjustPlayerPos) bool adjustPlayerPos)
{ {
bool hasWater = cell->cell->data.flags & cell->cell->HasWater;
mPhysics->setCurrentWater(hasWater, cell->cell->water);
if (adjustPlayerPos) if (adjustPlayerPos)
mWorld->getPlayer().setPos (position.pos[0], position.pos[1], position.pos[2]); mWorld->getPlayer().setPos (position.pos[0], position.pos[1], position.pos[2]);

View File

@ -215,6 +215,7 @@ namespace MWWorld
setFallbackValues(fallbackMap); setFallbackValues(fallbackMap);
lastTick = mTimer.getMilliseconds();
} }
@ -559,8 +560,9 @@ namespace MWWorld
} }
} }
void World::moveObjectImp (Ptr ptr, float x, float y, float z) bool World::moveObjectImp (Ptr ptr, float x, float y, float z)
{ {
bool ret = false;
ptr.getRefData().getPosition().pos[0] = x; ptr.getRefData().getPosition().pos[0] = x;
ptr.getRefData().getPosition().pos[1] = y; ptr.getRefData().getPosition().pos[1] = y;
ptr.getRefData().getPosition().pos[2] = z; ptr.getRefData().getPosition().pos[2] = z;
@ -582,6 +584,7 @@ namespace MWWorld
if (currentCell->cell->data.gridX!=cellX || currentCell->cell->data.gridY!=cellY) if (currentCell->cell->data.gridX!=cellX || currentCell->cell->data.gridY!=cellY)
{ {
mWorldScene->changeCell (cellX, cellY, mPlayer->getPlayer().getRefData().getPosition(), false); mWorldScene->changeCell (cellX, cellY, mPlayer->getPlayer().getRefData().getPosition(), false);
ret = true;
} }
} }
@ -591,6 +594,8 @@ namespace MWWorld
/// \todo cell change for non-player ref /// \todo cell change for non-player ref
mRendering->moveObject (ptr, Ogre::Vector3 (x, y, z)); mRendering->moveObject (ptr, Ogre::Vector3 (x, y, z));
return ret;
} }
void World::moveObject (Ptr ptr, float x, float y, float z) void World::moveObject (Ptr ptr, float x, float y, float z)
@ -632,29 +637,50 @@ namespace MWWorld
void World::doPhysics (const std::vector<std::pair<std::string, Ogre::Vector3> >& actors, void World::doPhysics (const std::vector<std::pair<std::string, Ogre::Vector3> >& actors,
float duration) float duration)
{ {
std::vector< std::pair<std::string, Ogre::Vector3> > vectors = mPhysics->doPhysics (duration, actors); mPhysics->doPhysics(duration, actors);
std::vector< std::pair<std::string, Ogre::Vector3> >::iterator player = vectors.end(); const int tick = 16; // 16 ms ^= 60 Hz
for (std::vector< std::pair<std::string, Ogre::Vector3> >::iterator it = vectors.begin(); // Game clock part of the loop, contains everything that has to be executed in a fixed timestep
it!= vectors.end(); ++it) long long dt = mTimer.getMilliseconds() - lastTick;
if (dt >= 100)
{ {
if (it->first=="player") // throw away wall clock time if necessary to keep the framerate above the minimum of 10 fps
lastTick += (dt - 100);
dt = 100;
}
while (dt >= tick)
{
dt -= tick;
lastTick += tick;
std::vector< std::pair<std::string, Ogre::Vector3> > vectors = mPhysics->doPhysicsFixed (actors);
std::vector< std::pair<std::string, Ogre::Vector3> >::iterator player = vectors.end();
for (std::vector< std::pair<std::string, Ogre::Vector3> >::iterator it = vectors.begin();
it!= vectors.end(); ++it)
{ {
player = it; if (it->first=="player")
{
player = it;
}
else
{
MWWorld::Ptr ptr = getPtrViaHandle (it->first);
moveObjectImp (ptr, it->second.x, it->second.y, it->second.z);
}
} }
else
// Make sure player is moved last (otherwise the cell might change in the middle of an update
// loop)
if (player!=vectors.end())
{ {
MWWorld::Ptr ptr = getPtrViaHandle (it->first); if (moveObjectImp (getPtrViaHandle (player->first),
moveObjectImp (ptr, it->second.x, it->second.y, it->second.z); player->second.x, player->second.y, player->second.z) == true)
return; // abort the current loop if the cell has changed
} }
} }
// Make sure player is moved last (otherwise the cell might change in the middle of an update
// loop)
if (player!=vectors.end())
moveObjectImp (getPtrViaHandle (player->first),
player->second.x, player->second.y, player->second.z);
} }
bool World::toggleCollisionMode() bool World::toggleCollisionMode()
@ -789,7 +815,8 @@ namespace MWWorld
std::vector < std::pair < float, std::string > >::iterator it = results.begin(); std::vector < std::pair < float, std::string > >::iterator it = results.begin();
while (it != results.end()) while (it != results.end())
{ {
if ( getPtrViaHandle((*it).second) == mPlayer->getPlayer() ) 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)
{ {
it = results.erase(it); it = results.erase(it);
} }

View File

@ -22,6 +22,8 @@
#include <openengine/bullet/physic.hpp> #include <openengine/bullet/physic.hpp>
#include <openengine/ogre/fader.hpp> #include <openengine/ogre/fader.hpp>
#include <OgreTimer.h>
namespace Ogre namespace Ogre
{ {
class Vector3; class Vector3;
@ -100,9 +102,13 @@ namespace MWWorld
int mNumFacing; int mNumFacing;
std::map<std::string,std::string> mFallback; std::map<std::string,std::string> mFallback;
unsigned long lastTick;
Ogre::Timer mTimer;
int getDaysPerMonth (int month) const; int getDaysPerMonth (int month) const;
void moveObjectImp (Ptr ptr, float x, float y, float z); bool moveObjectImp (Ptr ptr, float x, float y, float z);
///< @return true if the active cell (cell player is in) changed
public: public:

View File

@ -1,6 +1,7 @@
#include "physic.hpp" #include "physic.hpp"
#include <btBulletDynamicsCommon.h> #include <btBulletDynamicsCommon.h>
#include <btBulletCollisionCommon.h> #include <btBulletCollisionCommon.h>
#include <BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h>
#include <components/nifbullet/bullet_nif_loader.hpp> #include <components/nifbullet/bullet_nif_loader.hpp>
//#include <apps\openmw\mwworld\world.hpp> //#include <apps\openmw\mwworld\world.hpp>
#include "CMotionState.h" #include "CMotionState.h"
@ -10,6 +11,8 @@
#include "BtOgreGP.h" #include "BtOgreGP.h"
#include "BtOgreExtras.h" #include "BtOgreExtras.h"
#include <boost/lexical_cast.hpp>
#define BIT(x) (1<<(x)) #define BIT(x) (1<<(x))
namespace OEngine { namespace OEngine {
@ -161,10 +164,12 @@ namespace Physic
// The actual physics solver // The actual physics solver
solver = new btSequentialImpulseConstraintSolver; solver = new btSequentialImpulseConstraintSolver;
//btOverlappingPairCache* pairCache = new btSortedOverlappingPairCache();
pairCache = new btSortedOverlappingPairCache(); pairCache = new btSortedOverlappingPairCache();
//pairCache->setInternalGhostPairCallback( new btGhostPairCallback() ); //pairCache->setInternalGhostPairCallback( new btGhostPairCallback() );
broadphase = new btDbvtBroadphase(pairCache); broadphase = new btDbvtBroadphase();
// The world. // The world.
dynamicsWorld = new btDiscreteDynamicsWorld(dispatcher,broadphase,solver,collisionConfiguration); dynamicsWorld = new btDiscreteDynamicsWorld(dispatcher,broadphase,solver,collisionConfiguration);
@ -253,6 +258,60 @@ namespace Physic
delete mShapeLoader; delete mShapeLoader;
} }
void PhysicEngine::addHeightField(float* heights,
int x, int y, float yoffset,
float triSize, float sqrtVerts)
{
const std::string name = "HeightField_"
+ boost::lexical_cast<std::string>(x) + "_"
+ boost::lexical_cast<std::string>(y);
// find the minimum and maximum heights (needed for bullet)
float minh;
float maxh;
for (int i=0; i<sqrtVerts*sqrtVerts; ++i)
{
float h = heights[i];
if (i==0)
{
minh = h;
maxh = h;
}
if (h>maxh) maxh = h;
if (h<minh) minh = h;
}
btHeightfieldTerrainShape* hfShape = new btHeightfieldTerrainShape(
sqrtVerts, sqrtVerts, heights, 1,
minh, maxh, 2,
PHY_FLOAT,true);
hfShape->setUseDiamondSubdivision(true);
btVector3 scl(triSize, triSize, 1);
hfShape->setLocalScaling(scl);
CMotionState* newMotionState = new CMotionState(this,name);
btRigidBody::btRigidBodyConstructionInfo CI = btRigidBody::btRigidBodyConstructionInfo(0,newMotionState,hfShape);
RigidBody* body = new RigidBody(CI,name);
body->collide = true;
body->getWorldTransform().setOrigin(btVector3( (x+0.5)*triSize*(sqrtVerts-1), (y+0.5)*triSize*(sqrtVerts-1), (maxh+minh)/2.f));
addRigidBody(body);
}
void PhysicEngine::removeHeightField(int x, int y)
{
const std::string name = "HeightField_"
+ boost::lexical_cast<std::string>(x) + "_"
+ boost::lexical_cast<std::string>(y);
removeRigidBody(name);
deleteRigidBody(name);
}
RigidBody* PhysicEngine::createRigidBody(std::string mesh,std::string name,float scale) RigidBody* PhysicEngine::createRigidBody(std::string mesh,std::string name,float scale)
{ {
//get the shape from the .nif //get the shape from the .nif
@ -334,7 +393,7 @@ namespace Physic
void PhysicEngine::stepSimulation(double deltaT) void PhysicEngine::stepSimulation(double deltaT)
{ {
dynamicsWorld->stepSimulation(deltaT,1,1/50.); dynamicsWorld->stepSimulation(deltaT,10, 1/60.0);
if(isDebugCreated) if(isDebugCreated)
{ {
mDebugDrawer->step(); mDebugDrawer->step();

View File

@ -140,6 +140,18 @@ namespace Physic
*/ */
RigidBody* createRigidBody(std::string mesh,std::string name,float scale); RigidBody* createRigidBody(std::string mesh,std::string name,float scale);
/**
* Add a HeightField to the simulation
*/
void addHeightField(float* heights,
int x, int y, float yoffset,
float triSize, float sqrtVerts);
/**
* Remove a HeightField from the simulation
*/
void removeHeightField(int x, int y);
/** /**
* Add a RigidBody to the simulation * Add a RigidBody to the simulation
*/ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,200 @@
#ifndef OENGINE_BULLET_PMOVE_H
#define OENGINE_BULLET_PMOVE_H
/*
This source file is a *modified* version of various header files from the Quake 3 Arena source code,
which was released under the GNU GPL (v2) in 2005.
Quake 3 Arena is copyright (C) 1999-2005 Id Software, Inc.
*/
#include <Ogre.h>
#include <OgreMath.h>
#include <float.h>
#include "trace.h"
#include "physic.hpp"
//#include "GameMath.h"
//#include "GameTime.h"
// Forwards-declare it!
/*#ifndef COMPILING_PMOVE
#include "Scene.h"
extern SceneInstance* global_lastscene;
#endif*/
static const Ogre::Vector3 halfExtents(14.64f * 2, 14.24f * 2, 33.25f * 2);
#define MAX_CLIP_PLANES 5
#define OVERCLIP 1.001f
//#define STEPSIZE 18 // 18 is way too much
#define STEPSIZE (18 / 2)
#ifndef M_PI
#define M_PI 3.14159265358979323846f
#endif
#define YAW 0
#define PITCH /*1*/2
#define ROLL /*2*/1
#define SHORT2ANGLE(x) ( (x) * (360.0f / 65536.0f) )
#define ANGLE2SHORT(x) ( (const short)( (x) / (360.0f / 65536.0f) ) )
#define GENTITYNUM_BITS 10 // don't need to send any more
#define MAX_GENTITIES (1 << GENTITYNUM_BITS)
#define ENTITYNUM_NONE (MAX_GENTITIES - 1)
#define ENTITYNUM_WORLD (MAX_GENTITIES - 2)
#define MIN_WALK_NORMAL 0.7f // can't walk on very steep slopes
#define JUMP_VELOCITY (270)
#define PS_PMOVEFRAMECOUNTBITS 6
#define MINS_Z -24
#define DEFAULT_VIEWHEIGHT 26
#define CROUCH_VIEWHEIGHT 12
#define DEAD_VIEWHEIGHT (-16)
#define CONTENTS_SOLID 1 // an eye is never valid in a solid
#define CONTENTS_LAVA 8
#define CONTENTS_SLIME 16
#define CONTENTS_WATER 32
#define CONTENTS_FOG 64
static const float pm_accelerate = 10.0f;
static const float pm_stopspeed = 100.0f;
static const float pm_friction = 12.0f;
static const float pm_flightfriction = 3.0f;
static const float pm_waterfriction = 1.0f;
static const float pm_airaccelerate = 1.0f;
static const float pm_swimScale = 0.50f;
static const float pm_duckScale = 0.25f;
static const float pm_flyaccelerate = 8.0f;
static const float pm_wateraccelerate = 4.0f;
enum pmtype_t
{
PM_NORMAL, // can accelerate and turn
PM_NOCLIP, // noclip movement
PM_SPECTATOR, // still run into walls
PM_DEAD, // no acceleration or turning, but free falling
PM_FREEZE, // stuck in place with no control
PM_INTERMISSION, // no movement or status bar
PM_SPINTERMISSION // no movement or status bar
};
enum waterlevel_t
{
WL_DRYLAND = 0,
WL_ANKLE,
WL_WAIST,
WL_UNDERWATER
};
//#include "bprintf.h"
struct playerMove
{
struct playerStruct
{
playerStruct() : gravity(800.0f), speed(480.0f), pmove_framecount(20), groundEntityNum(ENTITYNUM_NONE), commandTime(40), move_type(PM_NOCLIP), pm_time(0), snappingImplemented(true), bSnap(false), counter(-1)
{
origin = Ogre::Vector3(733.164f,900.0f, 839.432f);
velocity = Ogre::Vector3(0.0f, 0.0f, 0.0f);
viewangles = Ogre::Vector3(0.0f, 0.0f, 0.0f);
delta_angles[0] = delta_angles[1] = delta_angles[2] = 0;
lastframe_origin.x = lastframe_origin.y = lastframe_origin.z = 0;
lerp_multiplier.x = lerp_multiplier.y = lerp_multiplier.z = 0;
}
inline void SpeedUp(void)
{
//printf("speed up to: %f\n", speed);
speed *= 1.25f;
}
inline void SpeedDown(void)
{
//printf("speed down to %f\n", speed);
speed /= 1.25f;
}
Ogre::Vector3 velocity;
Ogre::Vector3 origin;
bool bSnap;
bool snappingImplemented;
int counter;
float gravity; // default = 800
float speed; // default = 320
int commandTime; // the time at which this command was issued (in milliseconds)
int pm_time;
Ogre::Vector3 viewangles;
int groundEntityNum;
int pmove_framecount;
int watertype;
waterlevel_t waterlevel;
signed short delta_angles[3];
pmtype_t move_type;
float last_compute_time;
Ogre::Vector3 lastframe_origin;
Ogre::Vector3 lerp_multiplier;
} ps;
struct playercmd
{
enum CMDstateChange
{
NO_CHANGE,
KEYDOWN,
KEYUP
};
playercmd() : forwardmove(0), rightmove(0), upmove(0), serverTime(50), ducking(false),
activating(false), lastActivatingState(false), procActivating(NO_CHANGE),
dropping(false), lastDroppingState(false), procDropping(NO_CHANGE)
{
angles[0] = angles[1] = angles[2] = 0;
}
int serverTime;
short angles[3];
signed char forwardmove;
signed char rightmove;
signed char upmove;
bool ducking;
bool activating; // if the user is holding down the activate button
bool dropping; // if the user is dropping an item
bool lastActivatingState;
bool lastDroppingState;
CMDstateChange procActivating;
CMDstateChange procDropping;
} cmd;
playerMove() : msec(50), pmove_fixed(false), pmove_msec(50), waterHeight(0), isInterior(true), hasWater(false)
{
}
int msec;
int pmove_msec;
bool pmove_fixed;
int waterHeight;
bool hasWater;
bool isInterior;
//Object* traceObj;
OEngine::Physic::PhysicEngine* mEngine;
};
void Pmove (playerMove* const pmove);
void Ext_UpdateViewAngles(playerMove* const pm);
void AngleVectors( const Ogre::Vector3& angles, Ogre::Vector3* const forward, Ogre::Vector3* const right, Ogre::Vector3* const up) ;
#endif

View File

@ -0,0 +1,190 @@
#include "trace.h"
#include <map>
void newtrace(traceResults* const results, const Ogre::Vector3& start, const Ogre::Vector3& end, const Ogre::Vector3& BBHalfExtents, const float rotation, bool isInterior, OEngine::Physic::PhysicEngine* enginePass) //Traceobj was a Aedra Object
{
//if (!traceobj)
// return;
//if (!traceobj->incellptr)
// return;
const Ogre::Vector3 rayDir = end - start;
// Nudge starting point backwards
//const Position3D nudgestart = start + (rayDir * -0.1f); // by 10% (isn't that too much?)
//const Position3D nudgestart = start;
NewPhysTraceResults out;
//std::cout << "Starting trace\n";
//Ogre::Vector3 startReplace = Ogre::Vector3(650,950, 45);
//Ogre::Vector3 endReplace = startReplace;
//endReplace.z -= .25;
const bool hasHit = NewPhysicsTrace<collisionWorldTrace>(&out, start, end, BBHalfExtents, Ogre::Vector3(0.0f, 0.0, rotation), isInterior, enginePass);
if (out.fraction < 0.001f)
results->startsolid = true;
else
results->startsolid = false;
//results->allsolid = out.startSolid;
// If outside and underground, we're solid
/*if (isInterior)
{
const Ogre::Vector3 height = GetGroundPosition(start, CellCoords(traceCell->data->gridX, traceCell->data->gridY) );
if (start.yPos - height.yPos < (-2.0f * BBHalfExtents.yPos) )
{
results->allsolid = true;
}
else
results->allsolid = false;
}*/
// If inside and out of the tree, we're solid
//else
//{
results->allsolid = out.startSolid;
//std::cout << "allsolid" << results->allsolid << "\n";
//}
if (!hasHit)
{
results->endpos = end;
results->planenormal = Ogre::Vector3(0.0f, 0.0f, 1.0f);
results->entityNum = ENTITYNUM_NONE;
results->fraction = 1.0f;
}
else
{
results->fraction = out.fraction;
results->planenormal = out.hitNormal;
results->endpos = rayDir * results->fraction + start;
results->entityNum = ENTITYNUM_WORLD;
/*bprintf("Start: (%f, %f, %f) End: (%f, %f, %f) TraceDir: (%f, %f, %f) HitNormal: (%f, %f, %f) Fraction: %f Hitpos: (%f, %f, %f) CompensatedHitpos: (%f, %f, %f)\n",
start.xPos, start.yPos, start.zPos,
end.xPos, end.yPos, end.zPos,
rayDir.xPos, rayDir.yPos, rayDir.zPos,
results->planenormal.xPos, results->planenormal.yPos, results->planenormal.zPos, results->fraction,
out.endPos.xPos, out.endPos.yPos, out.endPos.zPos,
results->endpos.xPos, results->endpos.yPos, results->endpos.zPos);*/
}
}
template <const traceWorldType traceType>
const bool NewPhysicsTrace(NewPhysTraceResults* const out, const Ogre::Vector3& start, const Ogre::Vector3& end,
const Ogre::Vector3& BBHalfExtents, const Ogre::Vector3& rotation, bool isInterior, OEngine::Physic::PhysicEngine* enginePass)
{
//if (!traceobj->incellptr)
// return false;
//if(enginePass->dynamicsWorld->getCollisionObjectArray().at(60)->getCollisionShape()->isConvex())
// std::cout << "It's convex\n";
const btVector3 btstart(start.x, start.y, start.z);
const btVector3 btend(end.x, end.y, end.z);
const btQuaternion btrot(rotation.y, rotation.x, rotation.z); //y, x, z
const btBoxShape newshape(btVector3(BBHalfExtents.x, BBHalfExtents.y, BBHalfExtents.z));
const btTransform from(btrot, btstart);
const btTransform to(btrot, btend);
// warning: unused variable ...
/*
float x = from.getOrigin().getX();
float y = from.getOrigin().getY();
float z = from.getOrigin().getZ();
float x2 = to.getOrigin().getX();
float y2 = to.getOrigin().getY();
float z2 = to.getOrigin().getZ();
*/
//std::cout << "BtFrom: " << x << "," << y << "," << z << "\n";
//std::cout << "BtTo: " << x2 << "," << y2 << "," << z2 << "\n";
//std::cout << "BtTo: " << to.getOrigin().getX() << "," << to.getOrigin().getY() << "," << to.getOrigin().getZ() << "\n";
btCollisionWorld::ClosestConvexResultCallback
newTraceCallback(btstart, btend);
newTraceCallback.m_collisionFilterMask = (traceType == collisionWorldTrace) ? Only_Collision : Only_Pickup;
enginePass->dynamicsWorld->convexSweepTest(&newshape, from, to, newTraceCallback);
//newTraceCallback.
//std::cout << "NUM: " << enginePass->dynamicsWorld->getNumCollisionObjects() << "\n";
// Copy the hit data over to our trace results struct:
out->fraction = newTraceCallback.m_closestHitFraction;
Ogre::Vector3& outhitnormal = out->hitNormal;
const btVector3& tracehitnormal = newTraceCallback.m_hitNormalWorld;
outhitnormal.x = tracehitnormal.x();
outhitnormal.y = tracehitnormal.y();
outhitnormal.z = tracehitnormal.z();
Ogre::Vector3& outhitpos = out->endPos;
const btVector3& tracehitpos = newTraceCallback.m_hitPointWorld;
outhitpos.x = tracehitpos.x();
outhitpos.y = tracehitpos.y();
outhitpos.z= tracehitpos.z();
// StartSolid test:
{
out->startSolid = false;
//btCollisionObject collision;
//collision.setCollisionShape(const_cast<btBoxShape* const>(&newshape) );
//CustomContactCallback crb;
//world.world->contactTest(&collision, crb);
//out->startSolid = crb.hit;
// If outside and underground, we're solid
if (!isInterior) //Check if we are interior
{
}
// If inside and out of the tree, we're solid
else
{
btVector3 aabbMin, aabbMax;
enginePass->broadphase->getBroadphaseAabb(aabbMin, aabbMax);
//std::cout << "AABBMIN" << aabbMin.getX() <<"," <<aabbMin.getY() << "," << aabbMin.getZ() << "\n";
//std::cout << "AABBMAX" << aabbMax.getX() <<"," <<aabbMax.getY() << "," << aabbMax.getZ() << "\n";
//std::cout << "AABBMAX" << aabbMax << "\n";
if (!TestPointAgainstAabb2(aabbMin, aabbMax, *(const btVector3* const)&(start) ) )
{
//We're solid
out->startSolid = true;
}
}
}
const bool hasHit = newTraceCallback.hasHit();
return hasHit;
}

View File

@ -18,7 +18,7 @@ enum traceWorldType
bothWorldTrace = collisionWorldTrace | pickWorldTrace bothWorldTrace = collisionWorldTrace | pickWorldTrace
}; };
enum collaborativePhysicsType : unsigned enum collaborativePhysicsType
{ {
No_Physics = 0, // Both are empty (example: statics you can walk through, like tall grass) No_Physics = 0, // Both are empty (example: statics you can walk through, like tall grass)
Only_Collision = 1, // This object only has collision physics but no pickup physics (example: statics) Only_Collision = 1, // This object only has collision physics but no pickup physics (example: statics)
@ -53,10 +53,10 @@ struct traceResults
template <const traceWorldType traceType> template <const traceWorldType traceType>
const bool NewPhysicsTrace(NewPhysTraceResults* const out, const Ogre::Vector3& start, const Ogre::Vector3& end, const Ogre::Vector3& BBExtents, const Ogre::Vector3& rotation, bool isInterior, OEngine::Physic::PhysicEngine* enginePass); const bool NewPhysicsTrace(NewPhysTraceResults* const out, const Ogre::Vector3& start, const Ogre::Vector3& end, const Ogre::Vector3& BBExtents, const Ogre::Vector3& rotation, bool isInterior, OEngine::Physic::PhysicEngine* enginePass);
template const bool NewPhysicsTrace<collisionWorldTrace>(NewPhysTraceResults* const out, const Ogre::Vector3& start, const Ogre::Vector3& end, const Ogre::Vector3& BBExtents, const Ogre::Vector3& rotation, bool isInterior, OEngine::Physic::PhysicEngine* enginePass); //template const bool NewPhysicsTrace<collisionWorldTrace>(NewPhysTraceResults* const out, const Ogre::Vector3& start, const Ogre::Vector3& end, const Ogre::Vector3& BBExtents, const Ogre::Vector3& rotation, bool isInterior, OEngine::Physic::PhysicEngine* enginePass);
template const bool NewPhysicsTrace<pickWorldTrace>(NewPhysTraceResults* const out, const Ogre::Vector3& start, const Ogre::Vector3& end, const Ogre::Vector3& BBExtents, const Ogre::Vector3& rotation, bool isInterior, OEngine::Physic::PhysicEngine* enginePass); //template const bool NewPhysicsTrace<pickWorldTrace>(NewPhysTraceResults* const out, const Ogre::Vector3& start, const Ogre::Vector3& end, const Ogre::Vector3& BBExtents, const Ogre::Vector3& rotation, bool isInterior, OEngine::Physic::PhysicEngine* enginePass);
void newtrace(traceResults* const results, const Ogre::Vector3& start, const Ogre::Vector3& end, const Ogre::Vector3& BBExtents, const float rotation, bool isInterior, OEngine::Physic::PhysicEngine* enginePass); void newtrace(traceResults* const results, const Ogre::Vector3& start, const Ogre::Vector3& end, const Ogre::Vector3& BBExtents, const float rotation, bool isInterior, OEngine::Physic::PhysicEngine* enginePass);
#endif #endif