Merge remote-tracking branch 'upstream/master' into opencs-settings

This commit is contained in:
U-NSFW-50TH\cc9c 2014-09-17 21:00:22 +10:00
commit ca80a2b856
25 changed files with 616 additions and 141 deletions

View file

@ -12,7 +12,7 @@ before_install:
- sudo apt-get update -qq
- sudo apt-get install -qq libgtest-dev google-mock
- sudo apt-get install -qq libboost-filesystem-dev libboost-program-options-dev libboost-system-dev libboost-thread-dev libboost-wave-dev
- sudo apt-get install -qq libavcodec-dev libavformat-dev libavutil-dev libswscale-dev
- sudo apt-get install -qq libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libavresample-dev
- sudo apt-get install -qq libbullet-dev libogre-1.9-dev libmygui-dev libsdl2-dev libunshield-dev libtinyxml-dev libopenal-dev libqt4-dev
- sudo mkdir /usr/src/gtest/build
- cd /usr/src/gtest/build

View file

@ -140,10 +140,24 @@ set(OPENMW_LIBS ${OENGINE_ALL})
set(OPENMW_LIBS_HEADER)
# Sound setup
set(FFmpeg_FIND_COMPONENTS AVCODEC AVFORMAT AVUTIL SWSCALE)
find_package(FFmpeg REQUIRED)
set(FFmpeg_FIND_COMPONENTS AVCODEC AVFORMAT AVUTIL SWSCALE SWRESAMPLE AVRESAMPLE)
unset(FFMPEG_LIBRARIES CACHE)
find_package(FFmpeg)
if ( NOT AVCODEC_FOUND OR NOT AVFORMAT_FOUND OR NOT AVUTIL_FOUND OR NOT SWSCALE_FOUND )
message(FATAL_ERROR "FFmpeg component required, but not found!")
endif()
set(SOUND_INPUT_INCLUDES ${FFMPEG_INCLUDE_DIRS})
set(SOUND_INPUT_LIBRARY ${FFMPEG_LIBRARIES} ${SWSCALE_LIBRARIES})
if( SWRESAMPLE_FOUND )
add_definitions(-DHAVE_LIBSWRESAMPLE)
set(SOUND_INPUT_LIBRARY ${FFMPEG_LIBRARIES} ${SWRESAMPLE_LIBRARIES})
else()
if( AVRESAMPLE_FOUND )
set(SOUND_INPUT_LIBRARY ${FFMPEG_LIBRARIES} ${AVRESAMPLE_LIBRARIES})
else()
message(FATAL_ERROR "Install either libswresample (FFmpeg) or libavresample (Libav).")
endif()
endif()
# TinyXML
option(USE_SYSTEM_TINYXML "Use system TinyXML library instead of internal." OFF)

View file

@ -46,7 +46,7 @@ namespace
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Filters, "Filters", 0 },
{ CSMWorld::UniversalId::Class_ResourceList, CSMWorld::UniversalId::Type_Meshes, "Meshes", 0 },
{ CSMWorld::UniversalId::Class_ResourceList, CSMWorld::UniversalId::Type_Icons, "Icons", 0 },
{ CSMWorld::UniversalId::Class_ResourceList, CSMWorld::UniversalId::Type_Musics, "Musics", 0 },
{ CSMWorld::UniversalId::Class_ResourceList, CSMWorld::UniversalId::Type_Musics, "Music Files", 0 },
{ CSMWorld::UniversalId::Class_ResourceList, CSMWorld::UniversalId::Type_SoundsRes, "Sound Files", 0 },
{ CSMWorld::UniversalId::Class_ResourceList, CSMWorld::UniversalId::Type_Textures, "Textures", 0 },
{ CSMWorld::UniversalId::Class_ResourceList, CSMWorld::UniversalId::Type_Videos, "Videos", 0 },

View file

@ -17,7 +17,7 @@ CSVDoc::FileWidget::FileWidget (QWidget *parent) : QWidget (parent), mAddon (fal
QHBoxLayout *layout = new QHBoxLayout (this);
mInput = new QLineEdit (this);
mInput->setValidator (new QRegExpValidator(QRegExp("^[a-zA-Z0-9\\s]*$")));
mInput->setValidator (new QRegExpValidator(QRegExp("^[a-zA-Z0-9_-\\s]*$")));
layout->addWidget (mInput, 1);

View file

@ -30,6 +30,11 @@ void CSVDoc::View::closeEvent (QCloseEvent *event)
{
if (!mViewManager.closeRequest (this))
event->ignore();
else
{
// closeRequest() returns true if last document
mViewManager.removeDocAndView(mDocument);
}
}
void CSVDoc::View::setupFileMenu()

View file

@ -172,7 +172,7 @@ bool CSVDoc::ViewManager::closeRequest (View *view)
{
std::vector<View *>::iterator iter = std::find (mViews.begin(), mViews.end(), view);
bool continueWithClose = true;
bool continueWithClose = false;
if (iter!=mViews.end())
{
@ -192,6 +192,24 @@ bool CSVDoc::ViewManager::closeRequest (View *view)
return continueWithClose;
}
// NOTE: This method assumes that it is called only if the last document
void CSVDoc::ViewManager::removeDocAndView (CSMDoc::Document *document)
{
for (std::vector<View *>::iterator iter (mViews.begin()); iter!=mViews.end(); ++iter)
{
// the first match should also be the only match
if((*iter)->getDocument() == document)
{
mDocumentManager.removeDocument(document);
(*iter)->deleteLater();
mViews.erase (iter);
updateIndices();
return;
}
}
}
bool CSVDoc::ViewManager::notifySaveOnClose (CSVDoc::View *view)
{
bool result = true;
@ -210,13 +228,19 @@ bool CSVDoc::ViewManager::notifySaveOnClose (CSVDoc::View *view)
bool CSVDoc::ViewManager::showModifiedDocumentMessageBox (CSVDoc::View *view)
{
QMessageBox messageBox;
emit closeMessageBox();
QMessageBox messageBox(view);
CSMDoc::Document *document = view->getDocument();
messageBox.setWindowTitle (document->getSavePath().filename().string().c_str());
messageBox.setText ("The document has been modified.");
messageBox.setInformativeText ("Do you want to save your changes?");
messageBox.setStandardButtons (QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
messageBox.setDefaultButton (QMessageBox::Save);
messageBox.setWindowModality (Qt::NonModal);
messageBox.hide();
messageBox.show();
bool retVal = true;
@ -341,8 +365,40 @@ void CSVDoc::ViewManager::onExitWarningHandler (int state, CSMDoc::Document *doc
}
}
bool CSVDoc::ViewManager::removeDocument (CSVDoc::View *view)
{
if(!notifySaveOnClose(view))
return false;
else
{
// don't bother closing views or updating indicies, but remove from mViews
CSMDoc::Document * document = view->getDocument();
std::vector<View *> remainingViews;
std::vector<View *>::const_iterator iter = mViews.begin();
for (; iter!=mViews.end(); ++iter)
{
if(document == (*iter)->getDocument())
(*iter)->setVisible(false);
else
remainingViews.push_back(*iter);
}
mDocumentManager.removeDocument(document);
mViews = remainingViews;
}
return true;
}
void CSVDoc::ViewManager::exitApplication (CSVDoc::View *view)
{
if (notifySaveOnClose (view))
QApplication::instance()->exit();
if(!removeDocument(view)) // close the current document first
return;
while(!mViews.empty()) // attempt to close all other documents
{
mViews.back()->activateWindow();
mViews.back()->raise(); // raise the window to alert the user
if(!removeDocument(mViews.back()))
return;
}
// Editor exits (via a signal) when the last document is deleted
}

View file

@ -41,6 +41,7 @@ namespace CSVDoc
bool notifySaveOnClose (View *view = 0);
bool showModifiedDocumentMessageBox (View *view);
bool showSaveInProgressMessageBox (View *view);
bool removeDocument(View *view);
public:
@ -55,6 +56,7 @@ namespace CSVDoc
///< Return number of views for \a document.
bool closeRequest (View *view);
void removeDocAndView (CSMDoc::Document *document);
signals:

View file

@ -13,7 +13,9 @@ CSVFilter::RecordFilterBox::RecordFilterBox (CSMWorld::Data& data, QWidget *pare
layout->setContentsMargins (0, 0, 0, 0);
layout->addWidget (new QLabel ("Record Filter", this));
QLabel *label = new QLabel("Record Filter", this);
label->setIndent(2);
layout->addWidget (label);
mEdit = new EditWidget (data, this);

View file

@ -114,8 +114,20 @@ void CSVSettings::Dialog::show()
setViewValues();
}
QPoint screenCenter = QApplication::desktop()->screenGeometry().center();
move (screenCenter - geometry().center());
QWidget *currView = QApplication::activeWindow();
if(currView)
{
// place at the center of the window with focus
QSize size = currView->size();
move(currView->geometry().x()+(size.width() - frameGeometry().width())/2,
currView->geometry().y()+(size.height() - frameGeometry().height())/2);
}
else
{
// something's gone wrong, place at the center of the screen
QPoint screenCenter = QApplication::desktop()->screenGeometry().center();
move(screenCenter - QPoint(frameGeometry().width()/2,
frameGeometry().height()/2));
}
QWidget::show();
}

View file

@ -448,12 +448,12 @@ void CSVWorld::Table::tableSizeUpdate()
size = rows;
}
tableSizeChanged (size, deleted, modified);
emit tableSizeChanged (size, deleted, modified);
}
void CSVWorld::Table::selectionSizeUpdate()
{
selectionSizeChanged (selectionModel()->selectedRows().size());
emit selectionSizeChanged (selectionModel()->selectedRows().size());
}
void CSVWorld::Table::requestFocus (const std::string& id)
@ -467,6 +467,8 @@ void CSVWorld::Table::requestFocus (const std::string& id)
void CSVWorld::Table::recordFilterChanged (boost::shared_ptr<CSMFilter::Node> filter)
{
mProxyModel->setFilter (filter);
tableSizeUpdate();
selectionSizeUpdate();
}
void CSVWorld::Table::mouseMoveEvent (QMouseEvent* event)

View file

@ -55,7 +55,7 @@ add_openmw_dir (mwscript
)
add_openmw_dir (mwsound
soundmanagerimp openal_output ffmpeg_decoder sound sound_decoder sound_output loudness
soundmanagerimp openal_output ffmpeg_decoder sound sound_decoder sound_output loudness libavwrapper
)
add_openmw_dir (mwworld

View file

@ -209,6 +209,9 @@ namespace MWClass
const MWWorld::Store<ESM::GameSetting> &gmst = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
MWMechanics::CreatureStats &stats = getCreatureStats(ptr);
if (stats.getDrawState() != MWMechanics::DrawState_Weapon)
return;
// Get the weapon used (if hand-to-hand, weapon = inv.end())
MWWorld::Ptr weapon;
if (ptr.getClass().hasInventoryStore(ptr))

View file

@ -8,7 +8,7 @@
#include "../mwworld/inventorystore.hpp"
#include "../mwworld/actionequip.hpp"
#include "../mwmechanics/creaturestats.hpp"
#include "../mwmechanics/npcstats.hpp"
#include <components/esm/loadench.hpp>
#include <components/esm/loadmgef.hpp>
@ -292,6 +292,38 @@ namespace MWMechanics
case ESM::MagicEffect::CurePoison:
return 1001.f * numEffectsToCure(actor, ESM::MagicEffect::Poison);
case ESM::MagicEffect::DisintegrateArmor: // TODO: check if actor is wearing armor
case ESM::MagicEffect::DisintegrateWeapon: // TODO: check if actor is wearing weapon
break;
case ESM::MagicEffect::DamageAttribute:
case ESM::MagicEffect::DrainAttribute:
if (!target.isEmpty() && target.getClass().getCreatureStats(target).getAttribute(effect.mAttribute).getModified() <= 0)
return 0.f;
{
const float attributePriorities[ESM::Attribute::Length] = {
1.f, // Strength
0.5, // Intelligence
0.6, // Willpower
0.7, // Agility
0.5, // Speed
0.8, // Endurance
0.7, // Personality
0.3 // Luck
};
if (effect.mAttribute >= 0 && effect.mAttribute < ESM::Attribute::Length)
rating *= attributePriorities[effect.mAttribute];
}
break;
case ESM::MagicEffect::DamageSkill:
case ESM::MagicEffect::DrainSkill:
if (target.isEmpty() || !target.getClass().isNpc())
return 0.f;
if (target.getClass().getNpcStats(target).getSkill(effect.mSkill).getModified() <= 0)
return 0.f;
break;
default:
break;
}

View file

@ -258,6 +258,8 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat
}
const WeaponInfo *weap = std::find_if(sWeaponTypeList, sWeaponTypeListEnd, FindWeaponType(mWeaponType));
if (!mPtr.getClass().hasInventoryStore(mPtr))
weap = sWeaponTypeListEnd;
if(force || idle != mIdleState)
{
@ -308,7 +310,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat
}
}
if(mJumpState == JumpState_Falling)
if(mJumpState == JumpState_InAir)
{
int mode = ((jump == mCurrentJump) ? 2 : 1);
@ -414,7 +416,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat
speedmult = mMovementSpeed / vel;
}
else if (mMovementState == CharState_TurnLeft || mMovementState == CharState_TurnRight)
speedmult = 1.f; // TODO: should get a speed mult depending on the current turning speed
speedmult = 1.f; // adjusted each frame
else if (mMovementSpeed > 0.0f)
{
// The first person anims don't have any velocity to calculate a speed multiplier from.
@ -590,6 +592,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim
, mSkipAnim(false)
, mSecondsOfRunning(0)
, mSecondsOfSwimming(0)
, mTurnAnimationThreshold(0)
{
if(!mAnimation)
return;
@ -666,10 +669,10 @@ void CharacterController::updateIdleStormState()
mAnimation->getInfo("idlestorm", &complete);
if (complete == 0)
mAnimation->play("idlestorm", Priority_Torch, MWRender::Animation::Group_RightArm, false,
mAnimation->play("idlestorm", Priority_Storm, 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,
mAnimation->play("idlestorm", Priority_Storm, MWRender::Animation::Group_RightArm, false,
1.0f, "loop start", "loop stop", 0.0f, ~0ul);
}
else
@ -680,7 +683,7 @@ void CharacterController::updateIdleStormState()
{
if (mAnimation->getCurrentTime("idlestorm") < mAnimation->getTextKeyTime("idlestorm: loop stop"))
{
mAnimation->play("idlestorm", Priority_Torch, MWRender::Animation::Group_RightArm, true,
mAnimation->play("idlestorm", Priority_Storm, MWRender::Animation::Group_RightArm, true,
1.0f, "loop stop", "stop", 0.0f, 0);
}
}
@ -690,11 +693,52 @@ void CharacterController::updateIdleStormState()
}
}
void CharacterController::castSpell(const std::string &spellid)
{
static const std::string schools[] = {
"alteration", "conjuration", "destruction", "illusion", "mysticism", "restoration"
};
const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore();
const ESM::Spell *spell = store.get<ESM::Spell>().find(spellid);
const ESM::ENAMstruct &effectentry = spell->mEffects.mList.at(0);
const ESM::MagicEffect *effect;
effect = store.get<ESM::MagicEffect>().find(effectentry.mEffectID);
const ESM::Static* castStatic;
if (!effect->mCasting.empty())
castStatic = store.get<ESM::Static>().find (effect->mCasting);
else
castStatic = store.get<ESM::Static>().find ("VFX_DefaultCast");
mAnimation->addEffect("meshes\\" + castStatic->mModel, effect->mIndex);
MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
if(!effect->mCastSound.empty())
sndMgr->playSound3D(mPtr, effect->mCastSound, 1.0f, 1.0f);
else
sndMgr->playSound3D(mPtr, schools[effect->mData.mSchool]+" cast", 1.0f, 1.0f);
}
bool CharacterController::updateCreatureState()
{
const MWWorld::Class &cls = mPtr.getClass();
CreatureStats &stats = cls.getCreatureStats(mPtr);
WeaponType weapType = WeapType_None;
if(stats.getDrawState() == DrawState_Weapon)
weapType = WeapType_HandToHand;
else if (stats.getDrawState() == DrawState_Spell)
weapType = WeapType_Spell;
if (weapType != mWeaponType)
{
mWeaponType = weapType;
if (mAnimation->isPlaying(mCurrentWeapon))
mAnimation->disable(mCurrentWeapon);
}
if(stats.getAttackingOrSpell())
{
if(mUpperBodyState == UpperCharState_Nothing && mHitState == CharState_None)
@ -715,7 +759,18 @@ bool CharacterController::updateCreatureState()
1, "start", "stop",
0.0f, 0);
mUpperBodyState = UpperCharState_StartToMinAttack;
if (weapType == WeapType_Spell)
{
const std::string spellid = stats.getSpells().getSelectedSpell();
if (!spellid.empty() && MWBase::Environment::get().getWorld()->startSpellCast(mPtr))
{
castSpell(spellid);
MWBase::Environment::get().getWorld()->castSpell(mPtr);
}
}
}
stats.setAttackingOrSpell(false);
}
@ -854,9 +909,7 @@ bool CharacterController::updateWeaponState()
if(!spellid.empty() && MWBase::Environment::get().getWorld()->startSpellCast(mPtr))
{
static const std::string schools[] = {
"alteration", "conjuration", "destruction", "illusion", "mysticism", "restoration"
};
castSpell(spellid);
const ESM::Spell *spell = store.get<ESM::Spell>().find(spellid);
const ESM::ENAMstruct &effectentry = spell->mEffects.mList.at(0);
@ -864,15 +917,7 @@ bool CharacterController::updateWeaponState()
const ESM::MagicEffect *effect;
effect = store.get<ESM::MagicEffect>().find(effectentry.mEffectID);
const ESM::Static* castStatic;
if (!effect->mCasting.empty())
castStatic = store.get<ESM::Static>().find (effect->mCasting);
else
castStatic = store.get<ESM::Static>().find ("VFX_DefaultCast");
mAnimation->addEffect("meshes\\" + castStatic->mModel, effect->mIndex);
castStatic = MWBase::Environment::get().getWorld()->getStore().get<ESM::Static>().find ("VFX_Hands");
const ESM::Static* castStatic = MWBase::Environment::get().getWorld()->getStore().get<ESM::Static>().find ("VFX_Hands");
if (mAnimation->getNode("Left Hand"))
{
mAnimation->addEffect("meshes\\" + castStatic->mModel, -1, false, "Left Hand", effect->mParticle);
@ -896,12 +941,6 @@ bool CharacterController::updateWeaponState()
weapSpeed, mAttackType+" start", mAttackType+" stop",
0.0f, 0);
mUpperBodyState = UpperCharState_CastingSpell;
MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
if(!effect->mCastSound.empty())
sndMgr->playSound3D(mPtr, effect->mCastSound, 1.0f, 1.0f);
else
sndMgr->playSound3D(mPtr, schools[effect->mData.mSchool]+" cast", 1.0f, 1.0f);
}
if (inv.getSelectedEnchantItem() != inv.end())
{
@ -1237,17 +1276,8 @@ void CharacterController::update(float duration)
}
}
//Ogre::Vector3 vec = cls.getMovementVector(mPtr);
Ogre::Vector3 vec(cls.getMovementSettings(mPtr).mPosition);
if(vec.z > 0.0f) // to avoid slow-down when jumping
{
Ogre::Vector2 vecXY = Ogre::Vector2(vec.x, vec.y);
vecXY.normalise();
vec.x = vecXY.x;
vec.y = vecXY.y;
}
else
vec.normalise();
vec.normalise();
if(mHitState != CharState_None && mJumpState == JumpState_None)
vec = Ogre::Vector3(0.0f);
@ -1341,32 +1371,28 @@ void CharacterController::update(float duration)
cls.getCreatureStats(mPtr).land();
}
forcestateupdate = (mJumpState != JumpState_Falling);
mJumpState = JumpState_Falling;
forcestateupdate = (mJumpState != JumpState_InAir);
mJumpState = JumpState_InAir;
// This is a guess. All that seems to be known is that "While the player is in the
// air, fJumpMoveBase and fJumpMoveMult governs air control." Assuming Acrobatics
// plays a role, this makes the most sense.
float mult = 0.0f;
if(cls.isNpc())
{
const NpcStats &stats = cls.getNpcStats(mPtr);
static const float fJumpMoveBase = gmst.find("fJumpMoveBase")->getFloat();
static const float fJumpMoveMult = gmst.find("fJumpMoveMult")->getFloat();
// air, fJumpMoveBase and fJumpMoveMult governs air control". What does fJumpMoveMult do?
static const float fJumpMoveBase = gmst.find("fJumpMoveBase")->getFloat();
mult = fJumpMoveBase +
(stats.getSkill(ESM::Skill::Acrobatics).getModified()/100.0f *
fJumpMoveMult);
}
vec.x *= mult;
vec.y *= mult;
vec.x *= fJumpMoveBase;
vec.y *= fJumpMoveBase;
vec.z = 0.0f;
}
else if(vec.z > 0.0f && mJumpState == JumpState_None)
{
// Started a jump.
vec.z = cls.getJump(mPtr);
float z = cls.getJump(mPtr);
if(vec.x == 0 && vec.y == 0)
vec = Ogre::Vector3(0.0f, 0.0f, z);
else
{
Ogre::Vector3 lat = Ogre::Vector3(vec.x, vec.y, 0.0f).normalisedCopy();
vec = Ogre::Vector3(lat.x, lat.y, 1.0f) * z * 0.707f;
}
// advance acrobatics
if (mPtr.getRefData().getHandle() == "player")
@ -1382,7 +1408,7 @@ void CharacterController::update(float duration)
fatigue.setCurrent(fatigue.getCurrent() - fatigueDecrease);
cls.getCreatureStats(mPtr).setFatigue(fatigue);
}
else if(mJumpState == JumpState_Falling)
else if(mJumpState == JumpState_InAir)
{
forcestateupdate = true;
mJumpState = JumpState_Landing;
@ -1455,6 +1481,15 @@ void CharacterController::update(float duration)
}
}
mTurnAnimationThreshold -= duration;
if (movestate == CharState_TurnRight || movestate == CharState_TurnLeft)
mTurnAnimationThreshold = 0.05;
else if (movestate == CharState_None && (mMovementState == CharState_TurnRight || mMovementState == CharState_TurnLeft)
&& mTurnAnimationThreshold > 0)
{
movestate = mMovementState;
}
if (onground)
cls.getCreatureStats(mPtr).land();
@ -1485,6 +1520,12 @@ void CharacterController::update(float duration)
if (inJump)
mMovementAnimationControlled = false;
if (mMovementState == CharState_TurnLeft || mMovementState == CharState_TurnRight)
{
if (duration > 0)
mAnimation->adjustSpeedMult(mCurrentMovement, std::min(1.5f, std::abs(rot.z) / duration / Ogre::Math::PI));
}
if (!mSkipAnim)
{
rot *= Ogre::Math::RadiansToDegrees(1.0f);
@ -1503,7 +1544,9 @@ void CharacterController::update(float duration)
world->queueMovement(mPtr, Ogre::Vector3(0.0f));
movement = vec;
cls.getMovementSettings(mPtr).mPosition[0] = cls.getMovementSettings(mPtr).mPosition[1] = cls.getMovementSettings(mPtr).mPosition[2] = 0;
cls.getMovementSettings(mPtr).mPosition[0] = cls.getMovementSettings(mPtr).mPosition[1] = 0;
// Can't reset jump state (mPosition[2]) here; we don't know for sure whether the PhysicSystem will actually handle it in this frame
// due to the fixed minimum timestep used for the physics update. It will be reset in PhysicSystem::move once the jump is handled.
}
else if(cls.getCreatureStats(mPtr).isDead())
{

View file

@ -32,6 +32,7 @@ enum Priority {
Priority_Weapon,
Priority_Knockdown,
Priority_Torch,
Priority_Storm,
Priority_Death,
@ -129,7 +130,7 @@ enum UpperBodyCharacterState {
enum JumpingState {
JumpState_None,
JumpState_Falling,
JumpState_InAir,
JumpState_Landing
};
@ -170,6 +171,8 @@ class CharacterController
float mSecondsOfSwimming;
float mSecondsOfRunning;
float mTurnAnimationThreshold; // how long to continue playing turning animation after actor stopped turning
std::string mAttackType; // slash, chop or thrust
void determineAttackType();
@ -181,6 +184,8 @@ class CharacterController
bool updateCreatureState();
void updateIdleStormState();
void castSpell(const std::string& spellid);
void updateVisibility();
void playDeath(float startpoint, CharacterState death);

View file

@ -914,6 +914,13 @@ void Animation::play(const std::string &groupname, int priority, int groups, boo
}
}
void Animation::adjustSpeedMult(const std::string &groupname, float speedmult)
{
AnimStateMap::iterator state(mStates.find(groupname));
if(state != mStates.end())
state->second.mSpeedMult = speedmult;
}
bool Animation::isPlaying(const std::string &groupname) const
{
AnimStateMap::const_iterator state(mStates.find(groupname));

View file

@ -260,6 +260,10 @@ public:
float speedmult, const std::string &start, const std::string &stop,
float startpoint, size_t loops);
/** Adjust the speed multiplier of an already playing animation.
*/
void adjustSpeedMult (const std::string& groupname, float speedmult);
/** Returns true if the named animation group is playing. */
bool isPlaying(const std::string &groupname) const;

View file

@ -32,10 +32,15 @@ extern "C"
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
// From libavformat version 55.0.100 and onward the declaration of av_gettime() is removed from libavformat/avformat.h and moved
// to libavutil/time.h
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(55,28,1)
#define av_frame_alloc avcodec_alloc_frame
#endif
// From libavformat version 55.0.100 and onward the declaration of av_gettime() is
// removed from libavformat/avformat.h and moved to libavutil/time.h
// https://github.com/FFmpeg/FFmpeg/commit/06a83505992d5f49846c18507a6c3eb8a47c650e
#if AV_VERSION_INT(55, 0, 100) <= AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, LIBAVFORMAT_VERSION_MINOR, LIBAVFORMAT_VERSION_MICRO)
#if AV_VERSION_INT(55, 0, 100) <= AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \
LIBAVFORMAT_VERSION_MINOR, LIBAVFORMAT_VERSION_MICRO)
#include <libavutil/time.h>
#endif
@ -46,30 +51,25 @@ extern "C"
LIBAVUTIL_VERSION_MINOR, LIBAVUTIL_VERSION_MICRO)
#include <libavutil/channel_layout.h>
#endif
}
#ifdef _WIN32
// Decide whether to play binkaudio.
#include <libavcodec/version.h>
// libavcodec versions 54.10.100 (or maybe earlier) to 54.54.100 potentially crashes Windows 64bit.
// From version 54.56 or higher, there's no sound due to the encoding format changing from S16 to FLTP
// (see https://gitorious.org/ffmpeg/ffmpeg/commit/7bfd1766d1c18f07b0a2dd042418a874d49ea60d and
// http://git.videolan.org/?p=ffmpeg.git;a=commitdiff;h=3049d5b9b32845c86aa5588bb3352bdeb2edfdb2;hp=43c6b45a53a186a187f7266e4d6bd3c2620519f1),
// but does not crash (or at least no known crash).
#if (LIBAVCODEC_VERSION_MAJOR > 54)
#define FFMPEG_PLAY_BINKAUDIO
// WARNING: avcodec versions up to 54.54.100 potentially crashes on Windows 64bit.
// From version 54.56 binkaudio encoding format changed from S16 to FLTP. See:
// https://gitorious.org/ffmpeg/ffmpeg/commit/7bfd1766d1c18f07b0a2dd042418a874d49ea60d
// http://ffmpeg.zeranoe.com/forum/viewtopic.php?f=15&t=872
#ifdef HAVE_LIBSWRESAMPLE
#include <libswresample/swresample.h>
#else
#ifdef _WIN64
#if ((LIBAVCODEC_VERSION_MAJOR == 54) && (LIBAVCODEC_VERSION_MINOR >= 55))
#define FFMPEG_PLAY_BINKAUDIO
#endif
#else
#if ((LIBAVCODEC_VERSION_MAJOR == 54) && (LIBAVCODEC_VERSION_MINOR >= 10))
#define FFMPEG_PLAY_BINKAUDIO
#endif
#endif
/* FIXME: remove this section once libswresample is available on all platforms */
#include <libavresample/avresample.h>
#include <libavutil/opt.h>
#define SwrContext AVAudioResampleContext
int swr_init(AVAudioResampleContext *avr);
void swr_free(AVAudioResampleContext **avr);
int swr_convert( AVAudioResampleContext *avr, uint8_t** output, int out_samples, const uint8_t** input, int in_samples);
AVAudioResampleContext * swr_alloc_set_opts( AVAudioResampleContext *avr, int64_t out_ch_layout, AVSampleFormat out_fmt, int out_rate, int64_t in_ch_layout, AVSampleFormat in_fmt, int in_rate, int o, void* l);
#endif
#endif
}
#define MAX_AUDIOQ_SIZE (5 * 16 * 1024)
#define MAX_VIDEOQ_SIZE (5 * 256 * 1024)
@ -317,6 +317,12 @@ class MovieAudioDecoder : public MWSound::Sound_Decoder
VideoState *mVideoState;
AVStream *mAVStream;
SwrContext *mSwr;
enum AVSampleFormat mOutputSampleFormat;
uint8_t *mDataBuf;
uint8_t **mFrameData;
int mDataBufLen;
AutoAVPacket mPacket;
AVFrame *mFrame;
ssize_t mFramePos;
@ -383,6 +389,28 @@ class MovieAudioDecoder : public MWSound::Sound_Decoder
if(!got_frame || frame->nb_samples <= 0)
continue;
if(mSwr)
{
if(!mDataBuf || mDataBufLen < frame->nb_samples)
{
av_freep(&mDataBuf);
if(av_samples_alloc(&mDataBuf, NULL, mAVStream->codec->channels,
frame->nb_samples, mOutputSampleFormat, 0) < 0)
break;
else
mDataBufLen = frame->nb_samples;
}
if(swr_convert(mSwr, (uint8_t**)&mDataBuf, frame->nb_samples,
(const uint8_t**)frame->extended_data, frame->nb_samples) < 0)
{
break;
}
mFrameData = &mDataBuf;
}
else
mFrameData = &frame->data[0];
mAudioClock += (double)frame->nb_samples /
(double)mAVStream->codec->sample_rate;
@ -420,7 +448,7 @@ public:
MovieAudioDecoder(VideoState *is)
: mVideoState(is)
, mAVStream(*is->audio_st)
, mFrame(avcodec_alloc_frame())
, mFrame(av_frame_alloc())
, mFramePos(0)
, mFrameSize(0)
, mAudioClock(0.0)
@ -429,10 +457,17 @@ public:
/* Correct audio only if larger error than this */
, mAudioDiffThreshold(2.0 * 0.050/* 50 ms */)
, mAudioDiffAvgCount(0)
, mSwr(0)
, mOutputSampleFormat(AV_SAMPLE_FMT_NONE)
, mDataBuf(NULL)
, mFrameData(NULL)
, mDataBufLen(0)
{ }
virtual ~MovieAudioDecoder()
{
av_freep(&mFrame);
swr_free(&mSwr);
av_freep(&mDataBuf);
}
void getInfo(int *samplerate, MWSound::ChannelConfig *chans, MWSound::SampleType * type)
@ -443,10 +478,18 @@ public:
*type = MWSound::SampleType_Int16;
else if(mAVStream->codec->sample_fmt == AV_SAMPLE_FMT_FLT)
*type = MWSound::SampleType_Float32;
else if(mAVStream->codec->sample_fmt == AV_SAMPLE_FMT_U8P)
*type = MWSound::SampleType_UInt8;
else if(mAVStream->codec->sample_fmt == AV_SAMPLE_FMT_S16P)
*type = MWSound::SampleType_Int16;
else if(mAVStream->codec->sample_fmt == AV_SAMPLE_FMT_FLTP)
*type = MWSound::SampleType_Float32;
else
fail(std::string("Unsupported sample format: ")+
av_get_sample_fmt_name(mAVStream->codec->sample_fmt));
int64_t ch_layout = mAVStream->codec->channel_layout;
if(mAVStream->codec->channel_layout == AV_CH_LAYOUT_MONO)
*chans = MWSound::ChannelConfig_Mono;
else if(mAVStream->codec->channel_layout == AV_CH_LAYOUT_STEREO)
@ -461,9 +504,15 @@ public:
{
/* Unknown channel layout. Try to guess. */
if(mAVStream->codec->channels == 1)
{
*chans = MWSound::ChannelConfig_Mono;
ch_layout = AV_CH_LAYOUT_MONO;
}
else if(mAVStream->codec->channels == 2)
{
*chans = MWSound::ChannelConfig_Stereo;
ch_layout = AV_CH_LAYOUT_STEREO;
}
else
{
std::stringstream sstr("Unsupported raw channel count: ");
@ -480,6 +529,30 @@ public:
}
*samplerate = mAVStream->codec->sample_rate;
if(mAVStream->codec->sample_fmt == AV_SAMPLE_FMT_U8P)
mOutputSampleFormat = AV_SAMPLE_FMT_U8;
else if(mAVStream->codec->sample_fmt == AV_SAMPLE_FMT_S16P)
mOutputSampleFormat = AV_SAMPLE_FMT_S16;
else if(mAVStream->codec->sample_fmt == AV_SAMPLE_FMT_FLTP)
mOutputSampleFormat = AV_SAMPLE_FMT_FLT;
if(mOutputSampleFormat != AV_SAMPLE_FMT_NONE)
{
mSwr = swr_alloc_set_opts(mSwr, // SwrContext
ch_layout, // output ch layout
mOutputSampleFormat, // output sample format
mAVStream->codec->sample_rate, // output sample rate
ch_layout, // input ch layout
mAVStream->codec->sample_fmt, // input sample format
mAVStream->codec->sample_rate, // input sample rate
0, // logging level offset
NULL); // log context
if(!mSwr)
fail(std::string("Couldn't allocate SwrContext"));
if(swr_init(mSwr) < 0)
fail(std::string("Couldn't initialize SwrContext"));
}
}
size_t read(char *stream, size_t len)
@ -500,7 +573,8 @@ public:
}
mFramePos = std::min<ssize_t>(mFrameSize, sample_skip);
sample_skip -= mFramePos;
if(sample_skip > 0 || mFrameSize > -sample_skip)
sample_skip -= mFramePos;
continue;
}
@ -508,7 +582,7 @@ public:
if(mFramePos >= 0)
{
len1 = std::min<size_t>(len1, mFrameSize-mFramePos);
memcpy(stream, mFrame->data[0]+mFramePos, len1);
memcpy(stream, mFrameData[0]+mFramePos, len1);
}
else
{
@ -519,29 +593,29 @@ public:
/* add samples by copying the first sample*/
if(n == 1)
memset(stream, *mFrame->data[0], len1);
memset(stream, *mFrameData[0], len1);
else if(n == 2)
{
const int16_t val = *((int16_t*)mFrame->data[0]);
const int16_t val = *((int16_t*)mFrameData[0]);
for(size_t nb = 0;nb < len1;nb += n)
*((int16_t*)(stream+nb)) = val;
}
else if(n == 4)
{
const int32_t val = *((int32_t*)mFrame->data[0]);
const int32_t val = *((int32_t*)mFrameData[0]);
for(size_t nb = 0;nb < len1;nb += n)
*((int32_t*)(stream+nb)) = val;
}
else if(n == 8)
{
const int64_t val = *((int64_t*)mFrame->data[0]);
const int64_t val = *((int64_t*)mFrameData[0]);
for(size_t nb = 0;nb < len1;nb += n)
*((int64_t*)(stream+nb)) = val;
}
else
{
for(size_t nb = 0;nb < len1;nb += n)
memcpy(stream+nb, mFrame->data[0], n);
memcpy(stream+nb, mFrameData[0], n);
}
}
@ -768,9 +842,9 @@ void VideoState::video_thread_loop(VideoState *self)
AVFrame *pFrame;
double pts;
pFrame = avcodec_alloc_frame();
pFrame = av_frame_alloc();
self->rgbaFrame = avcodec_alloc_frame();
self->rgbaFrame = av_frame_alloc();
avpicture_alloc((AVPicture*)self->rgbaFrame, PIX_FMT_RGBA, (*self->video_st)->codec->width, (*self->video_st)->codec->height);
while(self->videoq.get(packet, self) >= 0)
@ -992,12 +1066,8 @@ void VideoState::init(const std::string& resourceName)
this->external_clock_base = av_gettime();
#if !defined(_WIN32) || defined(FFMPEG_PLAY_BINKAUDIO)
if(audio_index >= 0)
this->stream_open(audio_index, this->format_ctx);
#else
std::cout<<"FFmpeg sound disabled for \""+resourceName+"\""<<std::endl;
#endif
if(video_index >= 0)
{

View file

@ -5,6 +5,16 @@
#include <stdexcept>
extern "C" {
#ifndef HAVE_LIBSWRESAMPLE
/* FIXME: remove this section once libswresample is available on all platforms */
int swr_init(AVAudioResampleContext *avr);
void swr_free(AVAudioResampleContext **avr);
int swr_convert( AVAudioResampleContext *avr, uint8_t** output, int out_samples, const uint8_t** input, int in_samples);
AVAudioResampleContext * swr_alloc_set_opts( AVAudioResampleContext *avr, int64_t out_ch_layout, AVSampleFormat out_fmt, int out_rate, int64_t in_ch_layout, AVSampleFormat in_fmt, int in_rate, int o, void* l);
#endif
}
namespace MWSound
{
@ -95,6 +105,29 @@ bool FFmpeg_Decoder::getAVAudioData()
memmove(mPacket.data, &mPacket.data[len], remaining);
av_shrink_packet(&mPacket, remaining);
}
if(mSwr)
{
if(!mDataBuf || mDataBufLen < mFrame->nb_samples)
{
av_freep(&mDataBuf);
if(av_samples_alloc(&mDataBuf, NULL, (*mStream)->codec->channels,
mFrame->nb_samples, mOutputSampleFormat, 0) < 0)
break;
else
mDataBufLen = mFrame->nb_samples;
}
if(swr_convert(mSwr, (uint8_t**)&mDataBuf, mFrame->nb_samples,
(const uint8_t**)mFrame->extended_data, mFrame->nb_samples) < 0)
{
break;
}
mFrameData = &mDataBuf;
}
else
mFrameData = &mFrame->data[0];
} while(got_frame == 0 || mFrame->nb_samples == 0);
mNextPts += (double)mFrame->nb_samples / (double)(*mStream)->codec->sample_rate;
@ -122,7 +155,7 @@ size_t FFmpeg_Decoder::readAVAudioData(void *data, size_t length)
size_t rem = std::min<size_t>(length-dec, mFrameSize-mFramePos);
/* Copy the data to the app's buffer and increment */
memcpy(data, mFrame->data[0]+mFramePos, rem);
memcpy(data, mFrameData[0]+mFramePos, rem);
data = (char*)data + rem;
dec += rem;
mFramePos += rem;
@ -132,19 +165,6 @@ size_t FFmpeg_Decoder::readAVAudioData(void *data, size_t length)
return dec;
}
static AVSampleFormat ffmpegNonPlanarSampleFormat (AVSampleFormat format)
{
switch (format)
{
case AV_SAMPLE_FMT_U8P: return AV_SAMPLE_FMT_U8;
case AV_SAMPLE_FMT_S16P: return AV_SAMPLE_FMT_S16;
case AV_SAMPLE_FMT_S32P: return AV_SAMPLE_FMT_S32;
case AV_SAMPLE_FMT_FLTP: return AV_SAMPLE_FMT_FLT;
case AV_SAMPLE_FMT_DBLP: return AV_SAMPLE_FMT_DBL;
default:return format;
}
}
void FFmpeg_Decoder::open(const std::string &fname)
{
close();
@ -191,7 +211,7 @@ void FFmpeg_Decoder::open(const std::string &fname)
if(!mStream)
fail("No audio streams in "+fname);
(*mStream)->codec->request_sample_fmt = ffmpegNonPlanarSampleFormat ((*mStream)->codec->sample_fmt);
(*mStream)->codec->request_sample_fmt = (*mStream)->codec->sample_fmt;
AVCodec *codec = avcodec_find_decoder((*mStream)->codec->codec_id);
if(!codec)
@ -203,7 +223,7 @@ void FFmpeg_Decoder::open(const std::string &fname)
if(avcodec_open2((*mStream)->codec, codec, NULL) < 0)
fail("Failed to open audio codec " + std::string(codec->long_name));
mFrame = avcodec_alloc_frame();
mFrame = av_frame_alloc();
}
catch(std::exception&)
{
@ -228,6 +248,8 @@ void FFmpeg_Decoder::close()
av_free_packet(&mPacket);
av_freep(&mFrame);
swr_free(&mSwr);
av_freep(&mDataBuf);
if(mFormatCtx)
{
@ -268,10 +290,18 @@ void FFmpeg_Decoder::getInfo(int *samplerate, ChannelConfig *chans, SampleType *
*type = SampleType_Int16;
else if((*mStream)->codec->sample_fmt == AV_SAMPLE_FMT_FLT)
*type = SampleType_Float32;
else if((*mStream)->codec->sample_fmt == AV_SAMPLE_FMT_U8P)
*type = SampleType_UInt8;
else if((*mStream)->codec->sample_fmt == AV_SAMPLE_FMT_S16P)
*type = SampleType_Int16;
else if((*mStream)->codec->sample_fmt == AV_SAMPLE_FMT_FLTP)
*type = SampleType_Float32;
else
fail(std::string("Unsupported sample format: ")+
av_get_sample_fmt_name((*mStream)->codec->sample_fmt));
int64_t ch_layout = (*mStream)->codec->channel_layout;
if((*mStream)->codec->channel_layout == AV_CH_LAYOUT_MONO)
*chans = ChannelConfig_Mono;
else if((*mStream)->codec->channel_layout == AV_CH_LAYOUT_STEREO)
@ -286,9 +316,15 @@ void FFmpeg_Decoder::getInfo(int *samplerate, ChannelConfig *chans, SampleType *
{
/* Unknown channel layout. Try to guess. */
if((*mStream)->codec->channels == 1)
{
*chans = ChannelConfig_Mono;
ch_layout = AV_CH_LAYOUT_MONO;
}
else if((*mStream)->codec->channels == 2)
{
*chans = ChannelConfig_Stereo;
ch_layout = AV_CH_LAYOUT_STEREO;
}
else
{
std::stringstream sstr("Unsupported raw channel count: ");
@ -305,6 +341,31 @@ void FFmpeg_Decoder::getInfo(int *samplerate, ChannelConfig *chans, SampleType *
}
*samplerate = (*mStream)->codec->sample_rate;
if((*mStream)->codec->sample_fmt == AV_SAMPLE_FMT_U8P)
mOutputSampleFormat = AV_SAMPLE_FMT_U8;
else if((*mStream)->codec->sample_fmt == AV_SAMPLE_FMT_S16P)
mOutputSampleFormat = AV_SAMPLE_FMT_S16;
else if((*mStream)->codec->sample_fmt == AV_SAMPLE_FMT_FLTP)
mOutputSampleFormat = AV_SAMPLE_FMT_FLT;
if(mOutputSampleFormat != AV_SAMPLE_FMT_NONE)
{
mSwr = swr_alloc_set_opts(mSwr, // SwrContext
ch_layout, // output ch layout
mOutputSampleFormat, // output sample format
(*mStream)->codec->sample_rate, // output sample rate
ch_layout, // input ch layout
(*mStream)->codec->sample_fmt, // input sample format
(*mStream)->codec->sample_rate, // input sample rate
0, // logging level offset
NULL); // log context
if(!mSwr)
fail(std::string("Couldn't allocate SwrContext"));
if(swr_init(mSwr) < 0)
fail(std::string("Couldn't initialize SwrContext"));
}
}
size_t FFmpeg_Decoder::read(char *buffer, size_t bytes)
@ -323,7 +384,7 @@ void FFmpeg_Decoder::readAll(std::vector<char> &output)
{
size_t got = mFrame->nb_samples * (*mStream)->codec->channels *
av_get_bytes_per_sample((*mStream)->codec->sample_fmt);
const char *inbuf = reinterpret_cast<char*>(mFrame->data[0]);
const char *inbuf = reinterpret_cast<char*>(mFrameData[0]);
output.insert(output.end(), inbuf, inbuf+got);
}
}
@ -352,6 +413,11 @@ FFmpeg_Decoder::FFmpeg_Decoder()
, mFrameSize(0)
, mFramePos(0)
, mNextPts(0.0)
, mSwr(0)
, mOutputSampleFormat(AV_SAMPLE_FMT_NONE)
, mDataBuf(NULL)
, mFrameData(NULL)
, mDataBufLen(0)
{
memset(&mPacket, 0, sizeof(mPacket));

View file

@ -18,6 +18,21 @@ extern "C"
LIBAVUTIL_VERSION_MINOR, LIBAVUTIL_VERSION_MICRO)
#include <libavutil/channel_layout.h>
#endif
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(55,28,1)
#define av_frame_alloc avcodec_alloc_frame
#endif
// From version 54.56 binkaudio encoding format changed from S16 to FLTP. See:
// https://gitorious.org/ffmpeg/ffmpeg/commit/7bfd1766d1c18f07b0a2dd042418a874d49ea60d
// http://ffmpeg.zeranoe.com/forum/viewtopic.php?f=15&t=872
#ifdef HAVE_LIBSWRESAMPLE
#include <libswresample/swresample.h>
#else
#include <libavresample/avresample.h>
#include <libavutil/opt.h>
#define SwrContext AVAudioResampleContext
#endif
}
#include <string>
@ -40,6 +55,12 @@ namespace MWSound
double mNextPts;
SwrContext *mSwr;
enum AVSampleFormat mOutputSampleFormat;
uint8_t *mDataBuf;
uint8_t **mFrameData;
int mDataBufLen;
bool getNextPacket();
Ogre::DataStreamPtr mDataStream;

View file

@ -0,0 +1,109 @@
#ifndef HAVE_LIBSWRESAMPLE
extern "C"
{
#define __STDC_CONSTANT_MACROS
#include <stdint.h>
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
// From libavutil version 52.2.0 and onward the declaration of
// AV_CH_LAYOUT_* is removed from libavcodec/avcodec.h and moved to
// libavutil/channel_layout.h
#if AV_VERSION_INT(52, 2, 0) <= AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \
LIBAVUTIL_VERSION_MINOR, LIBAVUTIL_VERSION_MICRO)
#include <libavutil/channel_layout.h>
#endif
#include <libavresample/avresample.h>
#include <libavutil/opt.h>
/* FIXME: delete this file once libswresample is available on all platforms */
int swr_init(AVAudioResampleContext *avr) { return 1; }
void swr_free(AVAudioResampleContext **avr) { avresample_free(avr); }
int swr_convert(
AVAudioResampleContext *avr,
uint8_t** output,
int out_samples,
const uint8_t** input,
int in_samples)
{
// FIXME: potential performance hit
int out_plane_size = 0;
int in_plane_size = 0;
return avresample_convert(avr, output, out_plane_size, out_samples,
(uint8_t **)input, in_plane_size, in_samples);
}
AVAudioResampleContext * swr_alloc_set_opts(
AVAudioResampleContext *avr,
int64_t out_ch_layout,
AVSampleFormat out_fmt,
int out_rate,
int64_t in_ch_layout,
AVSampleFormat in_fmt,
int in_rate,
int o,
void* l)
{
avr = avresample_alloc_context();
if(!avr)
return 0;
int res;
res = av_opt_set_int(avr, "out_channel_layout", out_ch_layout, 0);
if(res < 0)
{
av_log(avr, AV_LOG_ERROR, "av_opt_set_int: out_ch_layout = %d\n", res);
return 0;
}
res = av_opt_set_int(avr, "out_sample_fmt", out_fmt, 0);
if(res < 0)
{
av_log(avr, AV_LOG_ERROR, "av_opt_set_int: out_fmt = %d\n", res);
return 0;
}
res = av_opt_set_int(avr, "out_sample_rate", out_rate, 0);
if(res < 0)
{
av_log(avr, AV_LOG_ERROR, "av_opt_set_int: out_rate = %d\n", res);
return 0;
}
res = av_opt_set_int(avr, "in_channel_layout", in_ch_layout, 0);
if(res < 0)
{
av_log(avr, AV_LOG_ERROR, "av_opt_set_int: in_ch_layout = %d\n", res);
return 0;
}
res = av_opt_set_int(avr, "in_sample_fmt", in_fmt, 0);
if(res < 0)
{
av_log(avr, AV_LOG_ERROR, "av_opt_set_int: in_fmt = %d\n", res);
return 0;
}
res = av_opt_set_int(avr, "in_sample_rate", in_rate, 0);
if(res < 0)
{
av_log(avr, AV_LOG_ERROR, "av_opt_set_int: in_rate = %d\n", res);
return 0;
}
res = av_opt_set_int(avr, "internal_sample_fmt", AV_SAMPLE_FMT_FLTP, 0);
if(res < 0)
{
av_log(avr, AV_LOG_ERROR, "av_opt_set_int: internal_sample_fmt\n");
return 0;
}
if(avresample_open(avr) < 0)
{
av_log(avr, AV_LOG_ERROR, "Error opening context\n");
return 0;
}
else
return avr;
}
}
#endif

View file

@ -23,6 +23,7 @@
#include "../mwbase/environment.hpp"
#include "../mwmechanics/creaturestats.hpp"
#include "../mwmechanics/movement.hpp"
#include "../mwworld/esmstore.hpp"
#include "../mwworld/cellstore.hpp"
@ -296,21 +297,24 @@ namespace MWWorld
else
{
velocity = Ogre::Quaternion(Ogre::Radian(refpos.rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z) * movement;
// not in water nor can fly, so need to deal with gravity
if(!physicActor->getOnGround()) // if current OnGround status is false, must be falling or jumping
{
// If falling, add part of the incoming velocity with the current inertia
// TODO: but we could be jumping up?
velocity = velocity * time + physicActor->getInertialForce();
// avoid getting infinite inertia in air
// If falling or jumping up, add part of the incoming velocity with the current inertia,
// but don't allow increasing inertia beyond actor's speed (except on the initial jump impulse)
float actorSpeed = ptr.getClass().getSpeed(ptr);
float speedXY = Ogre::Vector2(velocity.x, velocity.y).length();
if (speedXY > actorSpeed)
float cap = std::max(actorSpeed, Ogre::Vector2(physicActor->getInertialForce().x, physicActor->getInertialForce().y).length());
Ogre::Vector3 newVelocity = velocity + physicActor->getInertialForce();
if (Ogre::Vector2(newVelocity.x, newVelocity.y).squaredLength() > cap*cap)
{
velocity.x *= actorSpeed / speedXY;
velocity.y *= actorSpeed / speedXY;
velocity = newVelocity;
float speedXY = Ogre::Vector2(velocity.x, velocity.y).length();
velocity.x *= cap / speedXY;
velocity.y *= cap / speedXY;
}
else
velocity = newVelocity;
}
inertia = velocity; // NOTE: velocity is for z axis only in this code block
@ -331,6 +335,7 @@ namespace MWWorld
}
}
}
ptr.getClass().getMovementSettings(ptr).mPosition[2] = 0;
// Now that we have the effective movement vector, apply wind forces to it
if (MWBase::Environment::get().getWorld()->isInStorm())

View file

@ -162,7 +162,6 @@ namespace MWWorld
mWeatherManager = new MWWorld::WeatherManager(mRendering,&mFallback);
// NOTE: We might need to reserve one more for the running game / save.
mEsm.resize(contentFiles.size());
Loading::Listener* listener = MWBase::Environment::get().getWindowManager()->getLoadingScreen();
listener->loadingOn();
@ -2502,9 +2501,9 @@ namespace MWWorld
{
const ESM::Spell* spell = getStore().get<ESM::Spell>().search(selectedSpell);
// A power can be used once per 24h
if (spell->mData.mType == ESM::Spell::ST_Power)
stats.getSpells().usePower(spell->mId);
// A power can be used once per 24h
if (spell->mData.mType == ESM::Spell::ST_Power)
stats.getSpells().usePower(spell->mId);
cast.cast(spell);
}

View file

@ -14,6 +14,7 @@
# - AVUTIL
# - POSTPROCESS
# - SWSCALE
# - SWRESAMPLE
# the following variables will be defined
# <component>_FOUND - System has <component>
# <component>_INCLUDE_DIRS - Include directory necessary for using the <component> headers
@ -112,6 +113,8 @@ if (NOT FFMPEG_LIBRARIES)
find_component(AVUTIL libavutil avutil libavutil/avutil.h)
find_component(SWSCALE libswscale swscale libswscale/swscale.h)
find_component(POSTPROC libpostproc postproc libpostproc/postprocess.h)
find_component(SWRESAMPLE libswresample swresample libswresample/swresample.h)
find_component(AVRESAMPLE libavresample avresample libavresample/avresample.h)
# Check if the required components were found and add their stuff to the FFMPEG_* vars.
foreach (_component ${FFmpeg_FIND_COMPONENTS})
@ -142,7 +145,7 @@ if (NOT FFMPEG_LIBRARIES)
endif ()
# Now set the noncached _FOUND vars for the components.
foreach (_component AVCODEC AVDEVICE AVFORMAT AVUTIL POSTPROCESS SWSCALE)
foreach (_component AVCODEC AVDEVICE AVFORMAT AVUTIL POSTPROCESS SWSCALE SWRESAMPLE AVRESAMPLE)
set_component_found(${_component})
endforeach ()

View file

@ -30,22 +30,28 @@ darkf
Dmitry Shkurskiy (endorph)
Douglas Diniz (Dgdiniz)
Douglas Mencken (dougmencken)
dreamer-dead
Edmondo Tommasina (edmondo)
Eduard Cot (trombonecot)
Eli2
Emanuel Guével (potatoesmaster)
eroen
Fil Krynicki (filkry)
Gašper Sedej
gugus/gus
Hallfaer Tuilinn
Jacob Essex (Yacoby)
Jannik Heller (scrawl)
Jason Hooks (jhooks)
jeaye
Jeffrey Haines (Jyby)
Joel Graff (graffy)
John Blomberg (fstp)
Jordan Ayers
Jordan Milne
Julien Voisin (jvoisin/ap0)
Karl-Felix Glatzer (k1ll)
Kevin Poitra (PuppyKevin)
Lars Söderberg (Lazaroth)
lazydev
Leon Saunders (emoose)
@ -61,16 +67,23 @@ Michael Hogan (Xethik)
Michael Mc Donnell
Michael Papageorgiou (werdanith)
Michał Bień (Glorf)
Miroslav Puda (pakanek)
MiroslavR
Nathan Jeffords (blunted2night)
Nikolay Kasyanov (corristo)
nobrakal
Nolan Poe (nopoe)
Paul McElroy (Greendogo)
Pieter van der Kloet (pvdk)
Radu-Marius Popovici (rpopovici)
riothamus
Robert MacGregor (Ragora)
Rohit Nirmal
Roman Melnik (Kromgart)
Roman Proskuryakov (humbug)
sandstranger
Sandy Carter (bwrsandman)
Scott Howard
Sebastian Wick (swick)
Sergey Shambir
sir_herrbatka
@ -80,6 +93,7 @@ Sylvain Thesnieres (Garvek)
Thomas Luppi (Digmaster)
Tom Mason (wheybags)
Torben Leif Carrington (TorbenC)
Vincent Heuken
Packagers:
Alexander Olofsson (Ace) - Windows
@ -124,11 +138,12 @@ Sadler
Artwork:
Necrod - OpenMW Logo
Mickey Lyle (raevol) - Wordpress Theme
Okulo - OpenMW Editor Icons
Okulo, SirHerrbatka, crysthala - OpenMW Editor Icons
Inactive Contributors:
Ardekantur
Armin Preiml
Berulacks
Carl Maxwell
Diggory Hardy
Dmitry Marakasov (AMDmi3)