diff --git a/CMakeLists.txt b/CMakeLists.txt index 7eeddf4d1..78bc58903 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -217,27 +217,28 @@ if(NOT HAVE_STDINT_H) endif() -set(BOOST_COMPONENTS system filesystem program_options thread) -if(WIN32) - set(BOOST_COMPONENTS ${BOOST_COMPONENTS} locale) -endif(WIN32) - -IF(BOOST_STATIC) - set(Boost_USE_STATIC_LIBS ON) -endif() - IF(BUILD_OPENMW OR BUILD_OPENCS) find_package(OpenSceneGraph 3.3.4 REQUIRED osgDB osgViewer osgText osgGA osgAnimation osgParticle osgUtil osgFX) include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS}) + set(USED_OSG_PLUGINS + osgdb_bmp + osgdb_dds + osgdb_jpeg + osgdb_osg + osgdb_png + osgdb_serializers_osg + osgdb_tga + ) + get_filename_component(OSG_LIB_DIR ${OSGDB_LIBRARY} DIRECTORY) set(OSGPlugins_LIB_DIR "${OSG_LIB_DIR}/osgPlugins-${OPENSCENEGRAPH_VERSION}") if(OSG_STATIC) add_definitions(-DOSG_LIBRARY_STATIC) - find_package(OSGPlugins REQUIRED COMPONENTS osgdb_png osgdb_tga osgdb_dds osgdb_jpeg) + find_package(OSGPlugins REQUIRED COMPONENTS ${USED_OSG_PLUGINS}) list(APPEND OPENSCENEGRAPH_LIBRARIES ${OSGPlugins_LIBRARIES}) endif() @@ -258,6 +259,16 @@ IF(BUILD_OPENMW OR BUILD_OPENCS) ENDIF(BUILD_OPENMW OR BUILD_OPENCS) + +set(BOOST_COMPONENTS system filesystem program_options) +if(WIN32) + set(BOOST_COMPONENTS ${BOOST_COMPONENTS} locale) +endif(WIN32) + +IF(BOOST_STATIC) + set(Boost_USE_STATIC_LIBS ON) +endif() + find_package(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS}) include_directories("." @@ -769,12 +780,6 @@ if (APPLE) " COMPONENT Runtime) set(ABSOLUTE_PLUGINS "") - set(USED_OSG_PLUGINS - osgdb_dds - osgdb_jpeg - osgdb_png - osgdb_tga - ) foreach (PLUGIN_NAME ${USED_OSG_PLUGINS}) set(PLUGIN_ABS "${OSGPlugins_LIB_DIR}/${PLUGIN_NAME}.so") diff --git a/apps/opencs/model/tools/topicinfocheck.cpp b/apps/opencs/model/tools/topicinfocheck.cpp index f6af2a945..05f02c763 100644 --- a/apps/opencs/model/tools/topicinfocheck.cpp +++ b/apps/opencs/model/tools/topicinfocheck.cpp @@ -108,7 +108,7 @@ void CSMTools::TopicInfoCheckStage::perform(int stage, CSMDoc::Messages& message verifyCell(topicInfo.mCell, id, messages); } - if (!topicInfo.mFaction.empty()) + if (!topicInfo.mFaction.empty() && !topicInfo.mFactionLess) { if (verifyId(topicInfo.mFaction, mFactions, id, messages)) { diff --git a/apps/opencs/model/world/infoselectwrapper.cpp b/apps/opencs/model/world/infoselectwrapper.cpp index d036b1965..3bc9bf4d2 100644 --- a/apps/opencs/model/world/infoselectwrapper.cpp +++ b/apps/opencs/model/world/infoselectwrapper.cpp @@ -371,7 +371,6 @@ void CSMWorld::ConstInfoSelectWrapper::updateComparisonType() case Function_NotClass: case Function_NotRace: case Function_NotCell: - case Function_NotLocal: case Function_PcExpelled: case Function_PcCommonDisease: case Function_PcBlightDisease: @@ -454,6 +453,7 @@ void CSMWorld::ConstInfoSelectWrapper::updateComparisonType() // Numeric case Function_Global: case Function_Local: + case Function_NotLocal: case Function_Health_Percent: case Function_PcHealthPercent: @@ -560,7 +560,6 @@ std::pair CSMWorld::ConstInfoSelectWrapper::getValidIntRange() const case Function_NotClass: case Function_NotRace: case Function_NotCell: - case Function_NotLocal: case Function_PcExpelled: case Function_PcCommonDisease: case Function_PcBlightDisease: @@ -657,6 +656,7 @@ std::pair CSMWorld::ConstInfoSelectWrapper::getValidIntRange() const // Numeric case Function_Global: case Function_Local: + case Function_NotLocal: return std::pair(IntMin, IntMax); case Function_PcMagicka: diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index db0637a24..4655ee957 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -130,6 +131,10 @@ CompositeViewer::CompositeViewer() setThreadingModel(threadingModel); +#if OSG_VERSION_GREATER_OR_EQUAL(3,5,5) + setUseConfigureAffinity(false); +#endif + // disable the default setting of viewer.done() by pressing Escape. setKeyEventSetsDone(0); diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 15950e00e..d6c9c0637 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -23,7 +23,7 @@ add_openmw_dir (mwrender actors objects renderingmanager animation rotatecontroller sky npcanimation vismask creatureanimation effectmanager util renderinginterface pathgrid rendermode weaponanimation bulletdebugdraw globalmap characterpreview camera localmap water terrainstorage ripplesimulation - renderbin + renderbin actoranimation ) add_openmw_dir (mwinput @@ -145,14 +145,15 @@ target_link_libraries(tes3mp if (ANDROID) set (OSG_PLUGINS -Wl,--whole-archive - ${OSG_PLUGINS_DIR}/libosgdb_dds.a - ${OSG_PLUGINS_DIR}/libosgdb_bmp.a - ${OSG_PLUGINS_DIR}/libosgdb_tga.a - ${OSG_PLUGINS_DIR}/libosgdb_gif.a - ${OSG_PLUGINS_DIR}/libosgdb_jpeg.a - ${OSG_PLUGINS_DIR}/libosgdb_png.a - -Wl,--no-whole-archive ) + foreach(PLUGIN_NAME ${USED_OSG_PLUGINS}) + set(OSG_PLUGINS ${OSG_PLUGINS} ${OSG_PLUGINS_DIR}/lib${PLUGIN_NAME}.a) + endforeach() + + set (OSG_PLUGINS + ${OSG_PLUGINS} -Wl,--no-whole-archive + ) + target_link_libraries(tes3mp EGL android diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 578b5b9a4..ee6e24938 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -448,6 +448,11 @@ namespace MWDialogue { MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Dialogue); + // Clamp permanent disposition change so that final disposition doesn't go below 0 (could happen with intimidate) + float curDisp = static_cast(MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mActor, false)); + if (curDisp + mPermanentDispositionChange < 0) + mPermanentDispositionChange = -curDisp; + // Apply disposition change to NPC's base disposition if (mActor.getClass().isNpc()) { diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index 9f31fdda6..37a84b287 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -159,6 +159,39 @@ bool MWDialogue::Filter::testDisposition (const ESM::DialInfo& info, bool invert : (actorDisposition >= info.mData.mDisposition); } +bool MWDialogue::Filter::testFunctionLocal(const MWDialogue::SelectWrapper& select) const +{ + std::string scriptName = mActor.getClass().getScript (mActor); + + if (scriptName.empty()) + return false; // no script + + std::string name = Misc::StringUtils::lowerCase (select.getName()); + + const Compiler::Locals& localDefs = + MWBase::Environment::get().getScriptManager()->getLocals (scriptName); + + char type = localDefs.getType (name); + + if (type==' ') + return false; // script does not have a variable of this name. + + int index = localDefs.getIndex (name); + if (index < 0) + return false; // shouldn't happen, we checked that variable has a type above, so must exist + + const MWScript::Locals& locals = mActor.getRefData().getLocals(); + + switch (type) + { + case 's': return select.selectCompare (static_cast (locals.mShorts[index])); + case 'l': return select.selectCompare (locals.mLongs[index]); + case 'f': return select.selectCompare (locals.mFloats[index]); + } + + throw std::logic_error ("unknown local variable type in dialogue filter"); +} + bool MWDialogue::Filter::testSelectStruct (const SelectWrapper& select) const { if (select.isNpcOnly() && (mActor.getTypeName() != typeid (ESM::NPC).name())) @@ -200,35 +233,12 @@ bool MWDialogue::Filter::testSelectStructNumeric (const SelectWrapper& select) c case SelectWrapper::Function_Local: { - std::string scriptName = mActor.getClass().getScript (mActor); - - if (scriptName.empty()) - return false; // no script - - std::string name = Misc::StringUtils::lowerCase (select.getName()); - - const Compiler::Locals& localDefs = - MWBase::Environment::get().getScriptManager()->getLocals (scriptName); - - char type = localDefs.getType (name); - - if (type==' ') - return false; // script does not have a variable of this name. - - int index = localDefs.getIndex (name); - if (index < 0) - return false; // shouldn't happen, we checked that variable has a type above, so must exist - - const MWScript::Locals& locals = mActor.getRefData().getLocals(); - - switch (type) - { - case 's': return select.selectCompare (static_cast (locals.mShorts[index])); - case 'l': return select.selectCompare (locals.mLongs[index]); - case 'f': return select.selectCompare (locals.mFloats[index]); - } + return testFunctionLocal(select); + } - throw std::logic_error ("unknown local variable type in dialogue filter"); + case SelectWrapper::Function_NotLocal: + { + return !testFunctionLocal(select); } case SelectWrapper::Function_PcHealthPercent: @@ -472,20 +482,6 @@ bool MWDialogue::Filter::getSelectStructBoolean (const SelectWrapper& select) co return !Misc::StringUtils::ciEqual(MWBase::Environment::get().getWorld()->getCellName(mActor.getCell()) , select.getName()); - case SelectWrapper::Function_NotLocal: - { - std::string scriptName = mActor.getClass().getScript (mActor); - - if (scriptName.empty()) - // This actor has no attached script, so there is no local variable - return true; - - const Compiler::Locals& localDefs = - MWBase::Environment::get().getScriptManager()->getLocals (scriptName); - - return localDefs.getIndex (Misc::StringUtils::lowerCase (select.getName()))==-1; - } - case SelectWrapper::Function_SameGender: return (player.get()->mBase->mFlags & ESM::NPC::Female)== diff --git a/apps/openmw/mwdialogue/filter.hpp b/apps/openmw/mwdialogue/filter.hpp index d41b7aa1e..4e2ebe6e5 100644 --- a/apps/openmw/mwdialogue/filter.hpp +++ b/apps/openmw/mwdialogue/filter.hpp @@ -33,6 +33,8 @@ namespace MWDialogue bool testDisposition (const ESM::DialInfo& info, bool invert=false) const; ///< Is the actor disposition toward the player high enough (or low enough, if \a invert is true)? + bool testFunctionLocal(const SelectWrapper& select) const; + bool testSelectStruct (const SelectWrapper& select) const; bool testSelectStructNumeric (const SelectWrapper& select) const; diff --git a/apps/openmw/mwdialogue/scripttest.cpp b/apps/openmw/mwdialogue/scripttest.cpp index 3f4654610..54b4d8cd9 100644 --- a/apps/openmw/mwdialogue/scripttest.cpp +++ b/apps/openmw/mwdialogue/scripttest.cpp @@ -39,9 +39,9 @@ void test(const MWWorld::Ptr& actor, int &compiled, int &total, const Compiler:: { std::vector infos = filter.listAll(*it); - for (std::vector::iterator it = infos.begin(); it != infos.end(); ++it) + for (std::vector::iterator iter = infos.begin(); iter != infos.end(); ++iter) { - const ESM::DialInfo* info = *it; + const ESM::DialInfo* info = *iter; if (!info->mResultScript.empty()) { bool success = true; diff --git a/apps/openmw/mwdialogue/selectwrapper.cpp b/apps/openmw/mwdialogue/selectwrapper.cpp index 68c88e943..793963e48 100644 --- a/apps/openmw/mwdialogue/selectwrapper.cpp +++ b/apps/openmw/mwdialogue/selectwrapper.cpp @@ -210,7 +210,7 @@ MWDialogue::SelectWrapper::Type MWDialogue::SelectWrapper::getType() const static const Function numericFunctions[] = { - Function_Global, Function_Local, + Function_Global, Function_Local, Function_NotLocal, Function_PcDynamicStat, Function_PcHealthPercent, Function_HealthPercent, Function_None // end marker @@ -232,7 +232,7 @@ MWDialogue::SelectWrapper::Type MWDialogue::SelectWrapper::getType() const static const Function invertedBooleanFunctions[] = { Function_NotId, Function_NotFaction, Function_NotClass, - Function_NotRace, Function_NotCell, Function_NotLocal, + Function_NotRace, Function_NotCell, Function_None // end marker }; diff --git a/apps/openmw/mwgui/birth.cpp b/apps/openmw/mwgui/birth.cpp index de8614004..327d5e5cf 100644 --- a/apps/openmw/mwgui/birth.cpp +++ b/apps/openmw/mwgui/birth.cpp @@ -225,7 +225,7 @@ namespace MWGui mSpellItems.push_back(label); coord.top += lineHeight; - std::vector::const_iterator end = categories[category].spells.end(); + end = categories[category].spells.end(); for (std::vector::const_iterator it = categories[category].spells.begin(); it != end; ++it) { const std::string &spellId = *it; diff --git a/apps/openmw/mwgui/itemwidget.cpp b/apps/openmw/mwgui/itemwidget.cpp index 75436e797..87fca941e 100644 --- a/apps/openmw/mwgui/itemwidget.cpp +++ b/apps/openmw/mwgui/itemwidget.cpp @@ -28,6 +28,7 @@ namespace MWGui ItemWidget::ItemWidget() : mItem(NULL) + , mItemShadow(NULL) , mFrame(NULL) , mText(NULL) { @@ -44,6 +45,9 @@ namespace MWGui assignWidget(mItem, "Item"); if (mItem) mItem->setNeedMouseFocus(false); + assignWidget(mItemShadow, "ItemShadow"); + if (mItemShadow) + mItemShadow->setNeedMouseFocus(false); assignWidget(mFrame, "Frame"); if (mFrame) mFrame->setNeedMouseFocus(false); @@ -63,6 +67,8 @@ namespace MWGui void ItemWidget::setIcon(const std::string &icon) { + if (mItemShadow) + mItemShadow->setImageTexture(icon); if (mItem) mItem->setImageTexture(icon); } @@ -79,7 +85,10 @@ namespace MWGui void ItemWidget::setIcon(const MWWorld::Ptr &ptr) { - setIcon(MWBase::Environment::get().getWindowManager()->correctIconPath(ptr.getClass().getInventoryIcon(ptr))); + std::string invIcon = ptr.getClass().getInventoryIcon(ptr); + if (invIcon.empty()) + invIcon = "default icon.tga"; + setIcon(MWBase::Environment::get().getWindowManager()->correctIconPath(invIcon)); } diff --git a/apps/openmw/mwgui/itemwidget.hpp b/apps/openmw/mwgui/itemwidget.hpp index e7a902239..ce9f58f50 100644 --- a/apps/openmw/mwgui/itemwidget.hpp +++ b/apps/openmw/mwgui/itemwidget.hpp @@ -44,6 +44,7 @@ namespace MWGui virtual void initialiseOverride(); MyGUI::ImageBox* mItem; + MyGUI::ImageBox* mItemShadow; MyGUI::ImageBox* mFrame; MyGUI::TextBox* mText; }; diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index d51af87d9..4708d6753 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -559,8 +559,8 @@ namespace MWGui std::vector destNotes; CustomMarkerCollection::RangeType markers = mCustomMarkers.getMarkers(marker.dest); - for (CustomMarkerCollection::ContainerType::const_iterator it = markers.first; it != markers.second; ++it) - destNotes.push_back(it->second.mNote); + for (CustomMarkerCollection::ContainerType::const_iterator iter = markers.first; iter != markers.second; ++iter) + destNotes.push_back(iter->second.mNote); MarkerUserData data (mLocalMapRender); data.notes = destNotes; diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index f2ae8dd83..938574f83 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -476,16 +476,16 @@ namespace MWGui MWWorld::Ptr player = MWMechanics::getPlayer(); MWWorld::InventoryStore& store = player.getClass().getInventoryStore(player); MWWorld::Ptr item; - for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it) + for (MWWorld::ContainerStoreIterator iter = store.begin(); iter != store.end(); ++iter) { - if (Misc::StringUtils::ciEqual(it->getCellRef().getRefId(), id)) + if (Misc::StringUtils::ciEqual(iter->getCellRef().getRefId(), id)) { if (item.isEmpty() || // Prefer the stack with the lowest remaining uses - !item.getClass().hasItemHealth(*it) || - it->getClass().getItemHealth(*it) < item.getClass().getItemHealth(item)) + !item.getClass().hasItemHealth(*iter) || + iter->getClass().getItemHealth(*iter) < item.getClass().getItemHealth(item)) { - item = *it; + item = *iter; } } } diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index daa07d5c4..184ce0775 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -362,10 +362,10 @@ namespace MWGui std::sort(items.begin(), items.end(), sortRaces); int index = 0; - for (std::vector >::const_iterator it = items.begin(); it != items.end(); ++it) + for (std::vector >::const_iterator iter = items.begin(); iter != items.end(); ++iter) { - mRaceList->addItem(it->second, it->first); - if (Misc::StringUtils::ciEqual(it->first, mCurrentRaceId)) + mRaceList->addItem(iter->second, iter->first); + if (Misc::StringUtils::ciEqual(iter->first, mCurrentRaceId)) mRaceList->setIndexSelected(index); ++index; } diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 45f793a9b..5b6e762a0 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1046,8 +1046,9 @@ namespace MWMechanics if (!iter->first.getClass().getCreatureStats(iter->first).isDead()) { MWWorld::Ptr actor = iter->first; // make a copy of the map key to avoid it being invalidated when the player teleports + bool cellChanged = MWBase::Environment::get().getWorld()->hasCellChanged(); updateActor(actor, duration); - if (MWBase::Environment::get().getWorld()->hasCellChanged()) + if (!cellChanged && MWBase::Environment::get().getWorld()->hasCellChanged()) { return; // for now abort update of the old cell when cell changes by teleportation magic effect // a better solution might be to apply cell changes at the end of the frame diff --git a/apps/openmw/mwmechanics/aisequence.cpp b/apps/openmw/mwmechanics/aisequence.cpp index b03586c3b..a134fd44a 100644 --- a/apps/openmw/mwmechanics/aisequence.cpp +++ b/apps/openmw/mwmechanics/aisequence.cpp @@ -91,8 +91,8 @@ std::list::const_iterator AiSequence::erase(std::list::c { if (package == it) { - AiPackage* package = *it; - delete package; + AiPackage* packagePtr = *it; + delete packagePtr; return mPackages.erase(it); } } diff --git a/apps/openmw/mwmechanics/alchemy.cpp b/apps/openmw/mwmechanics/alchemy.cpp index 322d59280..783bbf573 100644 --- a/apps/openmw/mwmechanics/alchemy.cpp +++ b/apps/openmw/mwmechanics/alchemy.cpp @@ -73,7 +73,7 @@ void MWMechanics::Alchemy::applyTools (int flags, float& value) const bool duration = !(flags & ESM::MagicEffect::NoDuration); bool negative = (flags & ESM::MagicEffect::Harmful) != 0; - int tool = negative ? ESM::Apparatus::Retort : ESM::Apparatus::Albemic; + int tool = negative ? ESM::Apparatus::Alembic : ESM::Apparatus::Retort; int setup = 0; diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index a905ee3e0..88681384c 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -478,28 +478,28 @@ void CharacterController::refreshIdleAnims(const WeaponInfo* weap, CharacterStat mIdleState = idle; size_t numLoops = ~0ul; - std::string idle; + std::string idleGroup; MWRender::Animation::AnimPriority idlePriority (Priority_Default); // Only play "idleswim" or "idlesneak" if they exist. Otherwise, fallback to // "idle"+weapon or "idle". if(mIdleState == CharState_IdleSwim && mAnimation->hasAnimation("idleswim")) { - idle = "idleswim"; + idleGroup = "idleswim"; idlePriority = Priority_SwimIdle; } else if(mIdleState == CharState_IdleSneak && mAnimation->hasAnimation("idlesneak")) { - idle = "idlesneak"; + idleGroup = "idlesneak"; idlePriority[MWRender::Animation::BoneGroup_LowerBody] = Priority_SneakIdleLowerBody; } else if(mIdleState != CharState_None) { - idle = "idle"; + idleGroup = "idle"; if(weap != sWeaponTypeListEnd) { - idle += weap->shortgroup; - if(!mAnimation->hasAnimation(idle)) - idle = "idle"; + idleGroup += weap->shortgroup; + if(!mAnimation->hasAnimation(idleGroup)) + idleGroup = "idle"; // play until the Loop Stop key 2 to 5 times, then play until the Stop key // this replicates original engine behavior for the "Idle1h" 1st-person animation @@ -508,7 +508,7 @@ void CharacterController::refreshIdleAnims(const WeaponInfo* weap, CharacterStat } mAnimation->disable(mCurrentIdle); - mCurrentIdle = idle; + mCurrentIdle = idleGroup; if(!mCurrentIdle.empty()) mAnimation->play(mCurrentIdle, idlePriority, MWRender::Animation::BlendMask_All, false, 1.0f, "start", "stop", 0.0f, numLoops, true); @@ -571,8 +571,8 @@ MWWorld::ContainerStoreIterator getActiveWeapon(CreatureStats &stats, MWWorld::I else if(type == typeid(ESM::Weapon).name()) { MWWorld::LiveCellRef *ref = weapon->get(); - ESM::Weapon::Type type = (ESM::Weapon::Type)ref->mBase->mData.mType; - switch(type) + ESM::Weapon::Type weaponType = (ESM::Weapon::Type)ref->mBase->mData.mType; + switch(weaponType) { case ESM::Weapon::ShortBladeOneHand: case ESM::Weapon::LongBladeOneHand: @@ -1745,14 +1745,12 @@ void CharacterController::update(float duration) cls.skillUsageSucceeded(mPtr, ESM::Skill::Acrobatics, 0); // decrease fatigue - const MWWorld::Store &gmst = world->getStore().get(); const float fatigueJumpBase = gmst.find("fFatigueJumpBase")->getFloat(); const float fatigueJumpMult = gmst.find("fFatigueJumpMult")->getFloat(); float normalizedEncumbrance = mPtr.getClass().getNormalizedEncumbrance(mPtr); if (normalizedEncumbrance > 1) normalizedEncumbrance = 1; const float fatigueDecrease = fatigueJumpBase + (1 - normalizedEncumbrance) * fatigueJumpMult; - DynamicStat fatigue = cls.getCreatureStats(mPtr).getFatigue(); fatigue.setCurrent(fatigue.getCurrent() - fatigueDecrease); cls.getCreatureStats(mPtr).setFatigue(fatigue); } diff --git a/apps/openmw/mwmechanics/npcstats.cpp b/apps/openmw/mwmechanics/npcstats.cpp index 724e08798..f0994f509 100644 --- a/apps/openmw/mwmechanics/npcstats.cpp +++ b/apps/openmw/mwmechanics/npcstats.cpp @@ -83,8 +83,8 @@ void MWMechanics::NpcStats::raiseRank(const std::string &faction) if (it != mFactionRank.end()) { // Does the next rank exist? - const ESM::Faction* faction = MWBase::Environment::get().getWorld()->getStore().get().find(lower); - if (it->second+1 < 10 && !faction->mRanks[it->second+1].empty()) + const ESM::Faction* factionPtr = MWBase::Environment::get().getWorld()->getStore().get().find(lower); + if (it->second+1 < 10 && !factionPtr->mRanks[it->second+1].empty()) it->second += 1; } } diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 7c99f3376..9aee1d00f 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -482,7 +482,10 @@ namespace MWMechanics ActiveSpells::ActiveEffect effect; effect.mEffectId = effectIt->mEffectID; effect.mArg = MWMechanics::EffectKey(*effectIt).mArg; - effect.mDuration = static_cast(effectIt->mDuration); + if (!hasDuration) + effect.mDuration = 1.0f; + else + effect.mDuration = static_cast(effectIt->mDuration); effect.mMagnitude = magnitude; targetEffects.add(MWMechanics::EffectKey(*effectIt), MWMechanics::EffectParam(effect.mMagnitude)); @@ -497,13 +500,13 @@ namespace MWMechanics { if (effectIt->mEffectID == ESM::MagicEffect::AbsorbAttribute+i) { - std::vector effects; + std::vector absorbEffects; ActiveSpells::ActiveEffect effect_ = effect; effect_.mMagnitude *= -1; - effects.push_back(effect_); + absorbEffects.push_back(effect_); // Also make sure to set casterActorId = target, so that the effect on the caster gets purged when the target dies caster.getClass().getCreatureStats(caster).getActiveSpells().addSpell("", true, - effects, mSourceName, target.getClass().getCreatureStats(target).getActorId()); + absorbEffects, mSourceName, target.getClass().getCreatureStats(target).getActorId()); } } } @@ -514,11 +517,11 @@ namespace MWMechanics if (isSummoningEffect(effectIt->mEffectID) && !target.isEmpty() && target.getClass().isActor()) { CreatureStats& targetStats = target.getClass().getCreatureStats(target); - std::map::iterator found = targetStats.getSummonedCreatureMap().find(std::make_pair(effectIt->mEffectID, mId)); - if (found != targetStats.getSummonedCreatureMap().end()) + std::map::iterator findCreature = targetStats.getSummonedCreatureMap().find(std::make_pair(effectIt->mEffectID, mId)); + if (findCreature != targetStats.getSummonedCreatureMap().end()) { - MWBase::Environment::get().getMechanicsManager()->cleanupSummonedCreature(target, found->second); - targetStats.getSummonedCreatureMap().erase(found); + MWBase::Environment::get().getMechanicsManager()->cleanupSummonedCreature(target, findCreature->second); + targetStats.getSummonedCreatureMap().erase(findCreature); } } @@ -612,36 +615,8 @@ namespace MWMechanics return true; } } - else if (target.getClass().isActor()) + else if (target.getClass().isActor() && target == getPlayer()) { - switch (effectId) - { - case ESM::MagicEffect::CurePoison: - target.getClass().getCreatureStats(target).getActiveSpells().purgeEffect(ESM::MagicEffect::Poison); - return true; - case ESM::MagicEffect::CureParalyzation: - target.getClass().getCreatureStats(target).getActiveSpells().purgeEffect(ESM::MagicEffect::Paralyze); - return true; - case ESM::MagicEffect::CureCommonDisease: - target.getClass().getCreatureStats(target).getSpells().purgeCommonDisease(); - return true; - case ESM::MagicEffect::CureBlightDisease: - target.getClass().getCreatureStats(target).getSpells().purgeBlightDisease(); - return true; - case ESM::MagicEffect::CureCorprusDisease: - target.getClass().getCreatureStats(target).getSpells().purgeCorprusDisease(); - return true; - case ESM::MagicEffect::Dispel: - target.getClass().getCreatureStats(target).getActiveSpells().purgeAll(magnitude); - return true; - case ESM::MagicEffect::RemoveCurse: - target.getClass().getCreatureStats(target).getSpells().purgeCurses(); - return true; - } - - if (target != getPlayer()) - return false; - MWRender::Animation* anim = MWBase::Environment::get().getWorld()->getAnimation(mCaster); if (effectId == ESM::MagicEffect::DivineIntervention) @@ -664,7 +639,6 @@ namespace MWMechanics anim->addEffect("meshes\\" + fx->mModel, -1); return true; } - else if (effectId == ESM::MagicEffect::Mark) { MWBase::Environment::get().getWorld()->getPlayer().markPosition( @@ -1176,6 +1150,27 @@ namespace MWMechanics break; } + case ESM::MagicEffect::CurePoison: + actor.getClass().getCreatureStats(actor).getActiveSpells().purgeEffect(ESM::MagicEffect::Poison); + break; + case ESM::MagicEffect::CureParalyzation: + actor.getClass().getCreatureStats(actor).getActiveSpells().purgeEffect(ESM::MagicEffect::Paralyze); + break; + case ESM::MagicEffect::CureCommonDisease: + actor.getClass().getCreatureStats(actor).getSpells().purgeCommonDisease(); + break; + case ESM::MagicEffect::CureBlightDisease: + actor.getClass().getCreatureStats(actor).getSpells().purgeBlightDisease(); + break; + case ESM::MagicEffect::CureCorprusDisease: + actor.getClass().getCreatureStats(actor).getSpells().purgeCorprusDisease(); + break; + case ESM::MagicEffect::Dispel: + actor.getClass().getCreatureStats(actor).getActiveSpells().purgeAll(magnitude); + break; + case ESM::MagicEffect::RemoveCurse: + actor.getClass().getCreatureStats(actor).getSpells().purgeCurses(); + break; } if (receivedMagicDamage && actor == getPlayer()) diff --git a/apps/openmw/mwrender/actoranimation.cpp b/apps/openmw/mwrender/actoranimation.cpp new file mode 100644 index 000000000..5dcd5212c --- /dev/null +++ b/apps/openmw/mwrender/actoranimation.cpp @@ -0,0 +1,131 @@ +#include "actoranimation.hpp" + +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" +#include "../mwworld/ptr.hpp" +#include "../mwworld/class.hpp" +#include "../mwworld/cellstore.hpp" +#include "../mwmechanics/actorutil.hpp" + +#include "vismask.hpp" + +namespace MWRender +{ + +ActorAnimation::ActorAnimation(const MWWorld::Ptr& ptr, osg::ref_ptr parentNode, Resource::ResourceSystem* resourceSystem, + bool disableListener) + : Animation(ptr, parentNode, resourceSystem), + mListenerDisabled(disableListener) +{ + MWWorld::ContainerStore& store = mPtr.getClass().getContainerStore(mPtr); + + for (MWWorld::ContainerStoreIterator iter = store.begin(MWWorld::ContainerStore::Type_Light); iter != store.end(); ++iter) + { + const ESM::Light* light = iter->get()->mBase; + if (!(light->mData.mFlags & ESM::Light::Carry)) + { + addHiddenItemLight(*iter, light); + } + } + + if (!mListenerDisabled) + store.setContListener(this); +} + +ActorAnimation::~ActorAnimation() +{ + if (!mListenerDisabled && mPtr.getRefData().getCustomData() && mPtr.getClass().getContainerStore(mPtr).getContListener() == this) + mPtr.getClass().getContainerStore(mPtr).setContListener(NULL); + + for (ItemLightMap::iterator iter = mItemLights.begin(); iter != mItemLights.end(); ++iter) + { + mInsert->removeChild(iter->second); + } +} + +void ActorAnimation::itemAdded(const MWWorld::ConstPtr& item, int /*count*/) +{ + if (item.getTypeName() == typeid(ESM::Light).name()) + { + const ESM::Light* light = item.get()->mBase; + if (!(light->mData.mFlags & ESM::Light::Carry)) + { + addHiddenItemLight(item, light); + } + } +} + +void ActorAnimation::itemRemoved(const MWWorld::ConstPtr& item, int /*count*/) +{ + if (item.getTypeName() == typeid(ESM::Light).name()) + { + ItemLightMap::iterator iter = mItemLights.find(item); + if (iter != mItemLights.end()) + { + if (!item.getRefData().getCount()) + { + removeHiddenItemLight(item); + } + } + } +} + +void ActorAnimation::addHiddenItemLight(const MWWorld::ConstPtr& item, const ESM::Light* esmLight) +{ + if (mItemLights.find(item) != mItemLights.end()) + return; + + const Fallback::Map* fallback = MWBase::Environment::get().getWorld()->getFallback(); + static bool outQuadInLin = fallback->getFallbackBool("LightAttenuation_OutQuadInLin"); + static bool useQuadratic = fallback->getFallbackBool("LightAttenuation_UseQuadratic"); + static float quadraticValue = fallback->getFallbackFloat("LightAttenuation_QuadraticValue"); + static float quadraticRadiusMult = fallback->getFallbackFloat("LightAttenuation_QuadraticRadiusMult"); + static bool useLinear = fallback->getFallbackBool("LightAttenuation_UseLinear"); + static float linearRadiusMult = fallback->getFallbackFloat("LightAttenuation_LinearRadiusMult"); + static float linearValue = fallback->getFallbackFloat("LightAttenuation_LinearValue"); + bool exterior = mPtr.isInCell() && mPtr.getCell()->getCell()->isExterior(); + + osg::Vec4f ambient(1,1,1,1); + osg::ref_ptr lightSource = SceneUtil::createLightSource(esmLight, Mask_Lighting, exterior, outQuadInLin, + useQuadratic, quadraticValue, quadraticRadiusMult, useLinear, linearRadiusMult, linearValue, ambient); + + mInsert->addChild(lightSource); + + if (mLightListCallback && mPtr == MWMechanics::getPlayer()) + mLightListCallback->getIgnoredLightSources().insert(lightSource.get()); + + mItemLights.insert(std::make_pair(item, lightSource)); +} + +void ActorAnimation::removeHiddenItemLight(const MWWorld::ConstPtr& item) +{ + ItemLightMap::iterator iter = mItemLights.find(item); + if (iter == mItemLights.end()) + return; + + if (mLightListCallback && mPtr == MWMechanics::getPlayer()) + { + std::set::iterator ignoredIter = mLightListCallback->getIgnoredLightSources().find(iter->second.get()); + if (ignoredIter != mLightListCallback->getIgnoredLightSources().end()) + mLightListCallback->getIgnoredLightSources().erase(ignoredIter); + } + + mInsert->removeChild(iter->second); + mItemLights.erase(iter); +} + +} diff --git a/apps/openmw/mwrender/actoranimation.hpp b/apps/openmw/mwrender/actoranimation.hpp new file mode 100644 index 000000000..6922603e1 --- /dev/null +++ b/apps/openmw/mwrender/actoranimation.hpp @@ -0,0 +1,53 @@ +#ifndef GAME_RENDER_ACTORANIMATION_H +#define GAME_RENDER_ACTORANIMATION_H + +#include + +#include + +#include "../mwworld/containerstore.hpp" + +#include "animation.hpp" + +namespace osg +{ + class Node; +} + +namespace MWWorld +{ + class ConstPtr; +} + +namespace SceneUtil +{ + class LightSource; + class LightListCallback; +} + +namespace MWRender +{ + +class ActorAnimation : public Animation, public MWWorld::ContainerStoreListener +{ + public: + ActorAnimation(const MWWorld::Ptr &ptr, osg::ref_ptr parentNode, Resource::ResourceSystem* resourceSystem, + bool disableListener=false); + virtual ~ActorAnimation(); + + virtual void itemAdded(const MWWorld::ConstPtr& item, int count); + virtual void itemRemoved(const MWWorld::ConstPtr& item, int count); + + private: + void addHiddenItemLight(const MWWorld::ConstPtr& item, const ESM::Light* esmLight); + void removeHiddenItemLight(const MWWorld::ConstPtr& item); + + typedef std::map > ItemLightMap; + ItemLightMap mItemLights; + + bool mListenerDisabled; +}; + +} + +#endif diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 709780307..6091bee71 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -429,6 +429,8 @@ namespace MWRender { for(size_t i = 0;i < sNumBlendMasks;i++) mAnimationTimePtr[i].reset(new AnimationTime); + + mLightListCallback = new SceneUtil::LightListCallback; } Animation::~Animation() @@ -1095,6 +1097,8 @@ namespace MWRender osg::ref_ptr previousStateset; if (mObjectRoot) { + if (mLightListCallback) + mObjectRoot->removeCullCallback(mLightListCallback); previousStateset = mObjectRoot->getStateSet(); mObjectRoot->getParent(0)->removeChild(mObjectRoot); } @@ -1150,7 +1154,9 @@ namespace MWRender removeTriBipVisitor.remove(); } - mObjectRoot->addCullCallback(new SceneUtil::LightListCallback); + if (!mLightListCallback) + mLightListCallback = new SceneUtil::LightListCallback; + mObjectRoot->addCullCallback(mLightListCallback); } osg::Group* Animation::getObjectRoot() diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 089d0d85b..b99464014 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -25,6 +25,7 @@ namespace NifOsg namespace SceneUtil { class LightSource; + class LightListCallback; class Skeleton; } @@ -273,6 +274,8 @@ protected: float mAlpha; + osg::ref_ptr mLightListCallback; + const NodeMap& getNodeMap() const; /* Sets the appropriate animations on the bone groups based on priority. diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index 669d0d8a1..a095d5dd4 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -18,7 +18,7 @@ namespace MWRender CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr, const std::string& model, Resource::ResourceSystem* resourceSystem) - : Animation(ptr, osg::ref_ptr(ptr.getRefData().getBaseNode()), resourceSystem) + : ActorAnimation(ptr, osg::ref_ptr(ptr.getRefData().getBaseNode()), resourceSystem) { MWWorld::LiveCellRef *ref = mPtr.get(); @@ -34,7 +34,7 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr, CreatureWeaponAnimation::CreatureWeaponAnimation(const MWWorld::Ptr &ptr, const std::string& model, Resource::ResourceSystem* resourceSystem) - : Animation(ptr, osg::ref_ptr(ptr.getRefData().getBaseNode()), resourceSystem) + : ActorAnimation(ptr, osg::ref_ptr(ptr.getRefData().getBaseNode()), resourceSystem) , mShowWeapons(false) , mShowCarriedLeft(false) { @@ -48,7 +48,7 @@ CreatureWeaponAnimation::CreatureWeaponAnimation(const MWWorld::Ptr &ptr, const addAnimSource("meshes\\xbase_anim.nif"); addAnimSource(model); - mPtr.getClass().getInventoryStore(mPtr).setListener(this, mPtr); + mPtr.getClass().getInventoryStore(mPtr).setInvListener(this, mPtr); updateParts(); } diff --git a/apps/openmw/mwrender/creatureanimation.hpp b/apps/openmw/mwrender/creatureanimation.hpp index a62160253..bf813075e 100644 --- a/apps/openmw/mwrender/creatureanimation.hpp +++ b/apps/openmw/mwrender/creatureanimation.hpp @@ -1,7 +1,7 @@ #ifndef GAME_RENDER_CREATUREANIMATION_H #define GAME_RENDER_CREATUREANIMATION_H -#include "animation.hpp" +#include "actoranimation.hpp" #include "weaponanimation.hpp" #include "../mwworld/inventorystore.hpp" @@ -12,7 +12,7 @@ namespace MWWorld namespace MWRender { - class CreatureAnimation : public Animation + class CreatureAnimation : public ActorAnimation { public: CreatureAnimation(const MWWorld::Ptr &ptr, const std::string& model, Resource::ResourceSystem* resourceSystem); @@ -22,7 +22,7 @@ namespace MWRender // For creatures with weapons and shields // Animation is already virtual anyway, so might as well make a separate class. // Most creatures don't need weapons/shields, so this will save some memory. - class CreatureWeaponAnimation : public Animation, public WeaponAnimation, public MWWorld::InventoryStoreListener + class CreatureWeaponAnimation : public ActorAnimation, public WeaponAnimation, public MWWorld::InventoryStoreListener { public: CreatureWeaponAnimation(const MWWorld::Ptr &ptr, const std::string& model, Resource::ResourceSystem* resourceSystem); diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 64cc6d26c..8574939af 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include // TextKeyMapHolder @@ -272,8 +273,8 @@ NpcAnimation::~NpcAnimation() // No need to getInventoryStore() to reset, if none exists // This is to avoid triggering the listener via ensureCustomData()->autoEquip()->fireEquipmentChanged() // all from within this destructor. ouch! - && mPtr.getRefData().getCustomData() && mPtr.getClass().getInventoryStore(mPtr).getListener() == this) - mPtr.getClass().getInventoryStore(mPtr).setListener(NULL, mPtr); + && mPtr.getRefData().getCustomData() && mPtr.getClass().getInventoryStore(mPtr).getInvListener() == this) + mPtr.getClass().getInventoryStore(mPtr).setInvListener(NULL, mPtr); // do not detach (delete) parts yet, this is done so the background thread can handle the deletion for(size_t i = 0;i < ESM::PRT_Count;i++) @@ -285,7 +286,7 @@ NpcAnimation::~NpcAnimation() NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, osg::ref_ptr parentNode, Resource::ResourceSystem* resourceSystem, bool disableListener, bool disableSounds, ViewMode viewMode, float firstPersonFieldOfView) - : Animation(ptr, parentNode, resourceSystem), + : ActorAnimation(ptr, parentNode, resourceSystem, disableListener), mListenerDisabled(disableListener), mViewMode(viewMode), mShowWeapons(false), @@ -310,7 +311,7 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, osg::ref_ptr par updateNpcBase(); if (!disableListener) - mPtr.getClass().getInventoryStore(mPtr).setListener(this, mPtr); + mPtr.getClass().getInventoryStore(mPtr).setInvListener(this, mPtr); } void NpcAnimation::setViewMode(NpcAnimation::ViewMode viewMode) diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 9134f8f5f..892851890 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -5,6 +5,7 @@ #include "../mwworld/inventorystore.hpp" +#include "actoranimation.hpp" #include "weaponanimation.hpp" namespace ESM @@ -19,7 +20,7 @@ namespace MWRender class NeckController; class HeadAnimationTime; -class NpcAnimation : public Animation, public WeaponAnimation, public MWWorld::InventoryStoreListener +class NpcAnimation : public ActorAnimation, public WeaponAnimation, public MWWorld::InventoryStoreListener { public: virtual void equipmentChanged(); diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 2408d1ba0..b9ed4fb98 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -112,12 +112,12 @@ bool Objects::removeObject (const MWWorld::Ptr& ptr) PtrAnimationMap::iterator iter = mObjects.find(ptr); if(iter != mObjects.end()) { + if (mUnrefQueue.get()) + mUnrefQueue->push(iter->second->getObjectRoot()); + delete iter->second; mObjects.erase(iter); - if (mUnrefQueue.get()) - mUnrefQueue->push(ptr.getRefData().getBaseNode()); - ptr.getRefData().getBaseNode()->getParent(0)->removeChild(ptr.getRefData().getBaseNode()); ptr.getRefData().setBaseNode(NULL); diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 71459e18c..f94cf9b43 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -3,12 +3,16 @@ #include #include #include +#include #include #include -#include +#include +#include +#include +#include #include "openal_output.hpp" #include "sound_decoder.hpp" @@ -243,31 +247,31 @@ const ALfloat OpenAL_SoundStream::sBufferLength = 0.125f; // // A background streaming thread (keeps active streams processed) // -struct OpenAL_Output::StreamThread { +struct OpenAL_Output::StreamThread : public OpenThreads::Thread { typedef std::vector StreamVec; StreamVec mStreams; volatile bool mQuitNow; - boost::mutex mMutex; - boost::condition_variable mCondVar; - boost::thread mThread; + OpenThreads::Mutex mMutex; + OpenThreads::Condition mCondVar; StreamThread() - : mQuitNow(false), mThread(boost::ref(*this)) + : mQuitNow(false) { + start(); } ~StreamThread() { mQuitNow = true; mMutex.lock(); mMutex.unlock(); - mCondVar.notify_all(); - mThread.join(); + mCondVar.broadcast(); + join(); } - // boost::thread entry point - void operator()() + // thread entry point + virtual void run() { - boost::unique_lock lock(mMutex); + OpenThreads::ScopedLock lock(mMutex); while(!mQuitNow) { StreamVec::iterator iter = mStreams.begin(); @@ -279,31 +283,30 @@ struct OpenAL_Output::StreamThread { ++iter; } - mCondVar.timed_wait(lock, boost::posix_time::milliseconds(50)); + mCondVar.wait(&mMutex, 50); } } void add(OpenAL_SoundStream *stream) { - boost::unique_lock lock(mMutex); + OpenThreads::ScopedLock lock(mMutex); if(std::find(mStreams.begin(), mStreams.end(), stream) == mStreams.end()) { mStreams.push_back(stream); - lock.unlock(); - mCondVar.notify_all(); + mCondVar.broadcast(); } } void remove(OpenAL_SoundStream *stream) { - boost::lock_guard lock(mMutex); + OpenThreads::ScopedLock lock(mMutex); StreamVec::iterator iter = std::find(mStreams.begin(), mStreams.end(), stream); if(iter != mStreams.end()) mStreams.erase(iter); } void removeAll() { - boost::lock_guard lock(mMutex); + OpenThreads::ScopedLock lock(mMutex); mStreams.clear(); } @@ -468,7 +471,7 @@ ALint OpenAL_SoundStream::refillQueue() if(got < data.size()) { mIsFinished = true; - memset(&data[got], mSilence, data.size()-got); + std::memset(&data[got], mSilence, data.size()-got); } if(got > 0) { @@ -1023,7 +1026,7 @@ double OpenAL_Output::getStreamOffset(MWBase::SoundStreamPtr sound) { if(!sound->mHandle) return 0.0; OpenAL_SoundStream *stream = reinterpret_cast(sound->mHandle); - boost::lock_guard lock(mStreamThread->mMutex); + OpenThreads::ScopedLock lock(mStreamThread->mMutex); return stream->getStreamOffset(); } @@ -1031,7 +1034,7 @@ float OpenAL_Output::getStreamLoudness(MWBase::SoundStreamPtr sound) { if(!sound->mHandle) return 0.0; OpenAL_SoundStream *stream = reinterpret_cast(sound->mHandle); - boost::lock_guard lock(mStreamThread->mMutex); + OpenThreads::ScopedLock lock(mStreamThread->mMutex); return stream->getCurrentLoudness(); } @@ -1039,7 +1042,7 @@ bool OpenAL_Output::isStreamPlaying(MWBase::SoundStreamPtr sound) { if(!sound->mHandle) return false; OpenAL_SoundStream *stream = reinterpret_cast(sound->mHandle); - boost::lock_guard lock(mStreamThread->mMutex); + OpenThreads::ScopedLock lock(mStreamThread->mMutex); return stream->isPlaying(); } diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 7ac0d9d4e..54b612a1e 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -113,7 +113,7 @@ void MWWorld::ContainerStore::storeStates (const CellRefList& collection, const std::string MWWorld::ContainerStore::sGoldId = "gold_001"; -MWWorld::ContainerStore::ContainerStore() : mCachedWeight (0), mWeightUpToDate (false) {} +MWWorld::ContainerStore::ContainerStore() : mListener(NULL), mCachedWeight (0), mWeightUpToDate (false) {} MWWorld::ContainerStore::~ContainerStore() {} @@ -136,6 +136,17 @@ int MWWorld::ContainerStore::count(const std::string &id) return total; } +MWWorld::ContainerStoreListener* MWWorld::ContainerStore::getContListener() const +{ + return mListener; +} + + +void MWWorld::ContainerStore::setContListener(MWWorld::ContainerStoreListener* listener) +{ + mListener = listener; +} + MWWorld::ContainerStoreIterator MWWorld::ContainerStore::unstack(const Ptr &ptr, const Ptr& container, int count) { if (ptr.getRefData().getCount() <= count) @@ -292,6 +303,9 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add (const Ptr& itemPtr item.getRefData().getLocals().setVarByInt(script, "onpcadd", 1); } + if (mListener) + mListener->itemAdded(item, count); + return it; } @@ -398,6 +412,9 @@ int MWWorld::ContainerStore::remove(const Ptr& item, int count, const Ptr& actor flagAsModified(); + if (mListener) + mListener->itemRemoved(item, count - toRemove); + // number of removed items return count - toRemove; } @@ -423,12 +440,12 @@ void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std:: if (ref.getPtr().getTypeName()==typeid (ESM::ItemLevList).name()) { - const ESM::ItemLevList* levItem = ref.getPtr().get()->mBase; + const ESM::ItemLevList* levItemList = ref.getPtr().get()->mBase; - if (topLevel && std::abs(count) > 1 && levItem->mFlags & ESM::ItemLevList::Each) + if (topLevel && std::abs(count) > 1 && levItemList->mFlags & ESM::ItemLevList::Each) { for (int i=0; i 0 ? 1 : -1, true, levItem->mId); + addInitialItem(id, owner, count > 0 ? 1 : -1, true, levItemList->mId); return; } else @@ -436,7 +453,7 @@ void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std:: std::string id = MWMechanics::getLevelledItem(ref.getPtr().get()->mBase, false); if (id.empty()) return; - addInitialItem(id, owner, count, false, levItem->mId); + addInitialItem(id, owner, count, false, levItemList->mId); } } else diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index 6a8fc4761..0c95d2dba 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -31,6 +31,13 @@ namespace MWWorld { class ContainerStoreIterator; + class ContainerStoreListener + { + public: + virtual void itemAdded(const ConstPtr& item, int count) {} + virtual void itemRemoved(const ConstPtr& item, int count) {} + }; + class ContainerStore { public: @@ -73,6 +80,8 @@ namespace MWWorld ///< Stores result of levelled item spawns. <(refId, spawningGroup), count> /// This is used to restock levelled items(s) if the old item was sold. + ContainerStoreListener* mListener; + mutable float mCachedWeight; mutable bool mWeightUpToDate; ContainerStoreIterator addImp (const Ptr& ptr, int count); @@ -143,6 +152,9 @@ namespace MWWorld /// @return How many items with refID \a id are in this container? int count (const std::string& id); + ContainerStoreListener* getContListener() const; + void setContListener(ContainerStoreListener* listener); + protected: ContainerStoreIterator addNewStack (const ConstPtr& ptr, int count); ///< Add the item to this container (do not try to stack it onto existing items) diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 2c25029da..aa6880a49 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -606,12 +606,12 @@ MWWorld::ContainerStoreIterator MWWorld::InventoryStore::unequipItemQuantity(con return unstack(item, actor, item.getRefData().getCount() - count); } -MWWorld::InventoryStoreListener* MWWorld::InventoryStore::getListener() +MWWorld::InventoryStoreListener* MWWorld::InventoryStore::getInvListener() { return mListener; } -void MWWorld::InventoryStore::setListener(InventoryStoreListener *listener, const Ptr& actor) +void MWWorld::InventoryStore::setInvListener(InventoryStoreListener *listener, const Ptr& actor) { mListener = listener; updateMagicEffects(actor); diff --git a/apps/openmw/mwworld/inventorystore.hpp b/apps/openmw/mwworld/inventorystore.hpp index 152176fbe..9e0a8d5b6 100644 --- a/apps/openmw/mwworld/inventorystore.hpp +++ b/apps/openmw/mwworld/inventorystore.hpp @@ -197,10 +197,10 @@ namespace MWWorld /// in the slot (they can be re-stacked so its count may be different /// than the requested count). - void setListener (InventoryStoreListener* listener, const Ptr& actor); + void setInvListener (InventoryStoreListener* listener, const Ptr& actor); ///< Set a listener for various events, see \a InventoryStoreListener - InventoryStoreListener* getListener(); + InventoryStoreListener* getInvListener(); void visitEffectSources (MWMechanics::EffectSourceVisitor& visitor); diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index baa90a0ec..b8eedec23 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -212,7 +212,7 @@ namespace MWWorld MWWorld::Ptr player = getPlayer(); const MWMechanics::NpcStats &playerStats = player.getClass().getNpcStats(player); - if (playerStats.isParalyzed() || playerStats.getKnockedDown()) + if (playerStats.isParalyzed() || playerStats.getKnockedDown() || playerStats.isDead()) return; MWWorld::Ptr toActivate = MWBase::Environment::get().getWorld()->getFacedObject(); diff --git a/components/compiler/extensions0.cpp b/components/compiler/extensions0.cpp index 353c35a0d..d8eeb05b5 100644 --- a/components/compiler/extensions0.cpp +++ b/components/compiler/extensions0.cpp @@ -48,7 +48,7 @@ namespace Compiler extensions.registerFunction ("getaipackagedone", 'l', "", opcodeGetAiPackageDone, opcodeGetAiPackageDoneExplicit); extensions.registerFunction ("getcurrentaipackage", 'l', "", opcodeGetCurrentAiPackage, - opcodeGetAiPackageDoneExplicit); + opcodeGetCurrentAiPackageExplicit); extensions.registerFunction ("getdetected", 'l', "c", opcodeGetDetected, opcodeGetDetectedExplicit); extensions.registerInstruction ("sethello", "l", opcodeSetHello, opcodeSetHelloExplicit); diff --git a/components/esm/loadappa.hpp b/components/esm/loadappa.hpp index 0590d33ed..74f8dd6ae 100644 --- a/components/esm/loadappa.hpp +++ b/components/esm/loadappa.hpp @@ -22,7 +22,7 @@ struct Apparatus enum AppaType { MortarPestle = 0, - Albemic = 1, + Alembic = 1, Calcinator = 2, Retort = 3 }; diff --git a/components/esm/loadmgef.cpp b/components/esm/loadmgef.cpp index e33bd3ab4..7568ebe7e 100644 --- a/components/esm/loadmgef.cpp +++ b/components/esm/loadmgef.cpp @@ -356,8 +356,7 @@ short MagicEffect::getWeaknessEffect(short effect) effects[Corprus] = WeaknessToCorprusDisease; effects[Poison] = WeaknessToPoison; - // Weakness to magicka or -1 ? - effects[Paralyze] = WeaknessToMagicka; + effects[Paralyze] = -1; if (effects.find(effect) != effects.end()) return effects[effect]; diff --git a/components/resource/imagemanager.cpp b/components/resource/imagemanager.cpp index ea3adc704..96c5c66f5 100644 --- a/components/resource/imagemanager.cpp +++ b/components/resource/imagemanager.cpp @@ -13,6 +13,9 @@ USE_OSGPLUGIN(png) USE_OSGPLUGIN(tga) USE_OSGPLUGIN(dds) USE_OSGPLUGIN(jpeg) +USE_OSGPLUGIN(bmp) +USE_OSGPLUGIN(osg) +USE_SERIALIZER_WRAPPER_LIBRARY(osg) #endif namespace diff --git a/components/sceneutil/lightmanager.cpp b/components/sceneutil/lightmanager.cpp index f7c0573a4..906da5967 100644 --- a/components/sceneutil/lightmanager.cpp +++ b/components/sceneutil/lightmanager.cpp @@ -359,6 +359,10 @@ namespace SceneUtil for (unsigned int i=0; i + #include #include @@ -157,16 +159,20 @@ namespace SceneUtil : osg::Object(copy, copyop), osg::NodeCallback(copy, copyop) , mLightManager(copy.mLightManager) , mLastFrameNumber(0) + , mIgnoredLightSources(copy.mIgnoredLightSources) {} META_Object(SceneUtil, LightListCallback) void operator()(osg::Node* node, osg::NodeVisitor* nv); + std::set& getIgnoredLightSources() { return mIgnoredLightSources; } + private: LightManager* mLightManager; unsigned int mLastFrameNumber; LightManager::LightList mLightList; + std::set mIgnoredLightSources; }; } diff --git a/components/sceneutil/lightutil.cpp b/components/sceneutil/lightutil.cpp index 6499c54b1..5ad9bd6dc 100644 --- a/components/sceneutil/lightutil.cpp +++ b/components/sceneutil/lightutil.cpp @@ -36,7 +36,6 @@ namespace SceneUtil light->setLinearAttenuation(linearAttenuation); light->setQuadraticAttenuation(quadraticAttenuation); light->setConstantAttenuation(0.f); - } void addLight (osg::Group* node, const ESM::Light* esmLight, unsigned int partsysMask, unsigned int lightMask, bool isExterior, bool outQuadInLin, bool useQuadratic, @@ -68,6 +67,14 @@ namespace SceneUtil attachTo = trans; } + osg::ref_ptr lightSource = createLightSource(esmLight, lightMask, isExterior, outQuadInLin, useQuadratic, quadraticValue, + quadraticRadiusMult, useLinear, linearRadiusMult, linearValue); + attachTo->addChild(lightSource); + } + + osg::ref_ptr createLightSource(const ESM::Light* esmLight, unsigned int lightMask, bool isExterior, bool outQuadInLin, bool useQuadratic, float quadraticValue, + float quadraticRadiusMult, bool useLinear, float linearRadiusMult, float linearValue, const osg::Vec4f& ambient) + { osg::ref_ptr lightSource (new SceneUtil::LightSource); osg::ref_ptr light (new osg::Light); lightSource->setNodeMask(lightMask); @@ -85,7 +92,7 @@ namespace SceneUtil diffuse.a() = 1; } light->setDiffuse(diffuse); - light->setAmbient(osg::Vec4f(0,0,0,1)); + light->setAmbient(ambient); light->setSpecular(osg::Vec4f(0,0,0,0)); lightSource->setLight(light); @@ -103,7 +110,6 @@ namespace SceneUtil lightSource->addUpdateCallback(ctrl); - attachTo->addChild(lightSource); + return lightSource; } - } diff --git a/components/sceneutil/lightutil.hpp b/components/sceneutil/lightutil.hpp index d6c970340..95172e239 100644 --- a/components/sceneutil/lightutil.hpp +++ b/components/sceneutil/lightutil.hpp @@ -1,6 +1,9 @@ #ifndef OPENMW_COMPONENTS_LIGHTUTIL_H #define OPENMW_COMPONENTS_LIGHTUTIL_H +#include +#include + namespace osg { class Group; @@ -13,6 +16,7 @@ namespace ESM namespace SceneUtil { + class LightSource; /// @brief Convert an ESM::Light to a SceneUtil::LightSource, and add it to a sub graph. /// @note If the sub graph contains a node named "AttachLight" (case insensitive), then the light is added to that. @@ -27,6 +31,15 @@ namespace SceneUtil float quadraticValue, float quadraticRadiusMult, bool useLinear, float linearRadiusMult, float linearValue); + /// @brief Convert an ESM::Light to a SceneUtil::LightSource, and return it. + /// @param esmLight The light definition coming from the game files containing radius, color, flicker, etc. + /// @param lightMask Mask to assign to the newly created LightSource. + /// @param isExterior Is the light outside? May be used for deciding which attenuation settings to use. + /// @param ambient Ambient component of the light. + /// @par Attenuation parameters come from the game INI file. + osg::ref_ptr createLightSource (const ESM::Light* esmLight, unsigned int lightMask, bool isExterior, bool outQuadInLin, bool useQuadratic, + float quadraticValue, float quadraticRadiusMult, bool useLinear, float linearRadiusMult, float linearValue, const osg::Vec4f& ambient=osg::Vec4f(0,0,0,1)); + } #endif diff --git a/extern/osg-ffmpeg-videoplayer/audiodecoder.cpp b/extern/osg-ffmpeg-videoplayer/audiodecoder.cpp index f095d1617..096a17a64 100644 --- a/extern/osg-ffmpeg-videoplayer/audiodecoder.cpp +++ b/extern/osg-ffmpeg-videoplayer/audiodecoder.cpp @@ -1,5 +1,6 @@ #include "audiodecoder.hpp" +#include extern "C" { diff --git a/extern/osg-ffmpeg-videoplayer/videostate.cpp b/extern/osg-ffmpeg-videoplayer/videostate.cpp index 5849e8718..6779f2472 100644 --- a/extern/osg-ffmpeg-videoplayer/videostate.cpp +++ b/extern/osg-ffmpeg-videoplayer/videostate.cpp @@ -1,6 +1,7 @@ #include "videostate.hpp" #include +#include #include @@ -102,14 +103,14 @@ void PacketQueue::put(AVPacket *pkt) this->last_pkt = pkt1; this->nb_packets++; this->size += pkt1->pkt.size; - this->cond.notify_one(); + this->cond.signal(); this->mutex.unlock(); } int PacketQueue::get(AVPacket *pkt, VideoState *is) { - boost::unique_lock lock(this->mutex); + OpenThreads::ScopedLock lock(this->mutex); while(!is->mQuit) { AVPacketList *pkt1 = this->first_pkt; @@ -129,7 +130,7 @@ int PacketQueue::get(AVPacket *pkt, VideoState *is) if(this->flushing) break; - this->cond.wait(lock); + this->cond.wait(&this->mutex); } return -1; @@ -138,7 +139,7 @@ int PacketQueue::get(AVPacket *pkt, VideoState *is) void PacketQueue::flush() { this->flushing = true; - this->cond.notify_one(); + this->cond.signal(); } void PacketQueue::clear() @@ -233,7 +234,7 @@ void VideoState::video_display(VideoPicture *vp) void VideoState::video_refresh() { - boost::mutex::scoped_lock lock(this->pictq_mutex); + OpenThreads::ScopedLock lock(this->pictq_mutex); if(this->pictq_size == 0) return; @@ -245,7 +246,7 @@ void VideoState::video_refresh() this->pictq_rindex = (pictq_rindex+1) % VIDEO_PICTURE_ARRAY_SIZE; this->frame_last_pts = vp->pts; this->pictq_size--; - this->pictq_cond.notify_one(); + this->pictq_cond.signal(); } else { @@ -275,7 +276,7 @@ void VideoState::video_refresh() // update queue for next picture this->pictq_size--; this->pictq_rindex = (this->pictq_rindex+1) % VIDEO_PICTURE_ARRAY_SIZE; - this->pictq_cond.notify_one(); + this->pictq_cond.signal(); } } @@ -286,9 +287,9 @@ int VideoState::queue_picture(AVFrame *pFrame, double pts) /* wait until we have a new pic */ { - boost::unique_lock lock(this->pictq_mutex); + OpenThreads::ScopedLock lock(this->pictq_mutex); while(this->pictq_size >= VIDEO_PICTURE_QUEUE_SIZE && !this->mQuit) - this->pictq_cond.timed_wait(lock, boost::posix_time::milliseconds(1)); + this->pictq_cond.wait(&this->pictq_mutex, 1); } if(this->mQuit) return -1; @@ -371,168 +372,196 @@ static void our_free_buffer(void *opaque, uint8_t *data) av_free(data); } - -void VideoState::video_thread_loop(VideoState *self) +class VideoThread : public OpenThreads::Thread { - AVPacket pkt1, *packet = &pkt1; - int frameFinished; - AVFrame *pFrame; +public: + VideoThread(VideoState* self) + : mVideoState(self) + { + start(); + } + + virtual void run() + { + VideoState* self = mVideoState; + AVPacket pkt1, *packet = &pkt1; + int frameFinished; + AVFrame *pFrame; - pFrame = av_frame_alloc(); + pFrame = av_frame_alloc(); - self->rgbaFrame = av_frame_alloc(); - avpicture_alloc((AVPicture*)self->rgbaFrame, AV_PIX_FMT_RGBA, (*self->video_st)->codec->width, (*self->video_st)->codec->height); + self->rgbaFrame = av_frame_alloc(); + avpicture_alloc((AVPicture*)self->rgbaFrame, AV_PIX_FMT_RGBA, (*self->video_st)->codec->width, (*self->video_st)->codec->height); - while(self->videoq.get(packet, self) >= 0) - { - if(packet->data == flush_pkt.data) + while(self->videoq.get(packet, self) >= 0) { - avcodec_flush_buffers((*self->video_st)->codec); + if(packet->data == flush_pkt.data) + { + avcodec_flush_buffers((*self->video_st)->codec); - self->pictq_mutex.lock(); - self->pictq_size = 0; - self->pictq_rindex = 0; - self->pictq_windex = 0; - self->pictq_mutex.unlock(); + self->pictq_mutex.lock(); + self->pictq_size = 0; + self->pictq_rindex = 0; + self->pictq_windex = 0; + self->pictq_mutex.unlock(); - self->frame_last_pts = packet->pts * av_q2d((*self->video_st)->time_base); - global_video_pkt_pts = static_cast(self->frame_last_pts); - continue; - } + self->frame_last_pts = packet->pts * av_q2d((*self->video_st)->time_base); + global_video_pkt_pts = static_cast(self->frame_last_pts); + continue; + } - // Save global pts to be stored in pFrame - global_video_pkt_pts = packet->pts; - // Decode video frame - if(avcodec_decode_video2((*self->video_st)->codec, pFrame, &frameFinished, packet) < 0) - throw std::runtime_error("Error decoding video frame"); + // Save global pts to be stored in pFrame + global_video_pkt_pts = packet->pts; + // Decode video frame + if(avcodec_decode_video2((*self->video_st)->codec, pFrame, &frameFinished, packet) < 0) + throw std::runtime_error("Error decoding video frame"); - double pts = 0; - if(packet->dts != AV_NOPTS_VALUE) - pts = static_cast(packet->dts); - else if(pFrame->opaque && *(int64_t*)pFrame->opaque != AV_NOPTS_VALUE) - pts = static_cast(*(int64_t*)pFrame->opaque); - pts *= av_q2d((*self->video_st)->time_base); + double pts = 0; + if(packet->dts != AV_NOPTS_VALUE) + pts = static_cast(packet->dts); + else if(pFrame->opaque && *(int64_t*)pFrame->opaque != AV_NOPTS_VALUE) + pts = static_cast(*(int64_t*)pFrame->opaque); + pts *= av_q2d((*self->video_st)->time_base); - av_free_packet(packet); + av_free_packet(packet); - // Did we get a video frame? - if(frameFinished) - { - pts = self->synchronize_video(pFrame, pts); - if(self->queue_picture(pFrame, pts) < 0) - break; + // Did we get a video frame? + if(frameFinished) + { + pts = self->synchronize_video(pFrame, pts); + if(self->queue_picture(pFrame, pts) < 0) + break; + } } - } - av_free(pFrame); + av_free(pFrame); - avpicture_free((AVPicture*)self->rgbaFrame); - av_free(self->rgbaFrame); -} + avpicture_free((AVPicture*)self->rgbaFrame); + av_free(self->rgbaFrame); + } + +private: + VideoState* mVideoState; +}; -void VideoState::decode_thread_loop(VideoState *self) +class ParseThread : public OpenThreads::Thread { - AVFormatContext *pFormatCtx = self->format_ctx; - AVPacket pkt1, *packet = &pkt1; +public: + ParseThread(VideoState* self) + : mVideoState(self) + { + start(); + } - try + virtual void run() { - if(!self->video_st && !self->audio_st) - throw std::runtime_error("No streams to decode"); + VideoState* self = mVideoState; - // main decode loop - while(!self->mQuit) + AVFormatContext *pFormatCtx = self->format_ctx; + AVPacket pkt1, *packet = &pkt1; + + try { - if(self->mSeekRequested) + if(!self->video_st && !self->audio_st) + throw std::runtime_error("No streams to decode"); + + // main decode loop + while(!self->mQuit) { - uint64_t seek_target = self->mSeekPos; - int streamIndex = -1; - - int videoStreamIndex = -1;; - int audioStreamIndex = -1; - if (self->video_st) - videoStreamIndex = self->video_st - self->format_ctx->streams; - if (self->audio_st) - audioStreamIndex = self->audio_st - self->format_ctx->streams; - - if(videoStreamIndex >= 0) - streamIndex = videoStreamIndex; - else if(audioStreamIndex >= 0) - streamIndex = audioStreamIndex; - - uint64_t timestamp = seek_target; - - // QtCreator's highlighter doesn't like AV_TIME_BASE_Q's {} initializer for some reason - AVRational avTimeBaseQ = AVRational(); // = AV_TIME_BASE_Q; - avTimeBaseQ.num = 1; - avTimeBaseQ.den = AV_TIME_BASE; - - if(streamIndex >= 0) - timestamp = av_rescale_q(seek_target, avTimeBaseQ, self->format_ctx->streams[streamIndex]->time_base); - - // AVSEEK_FLAG_BACKWARD appears to be needed, otherwise ffmpeg may seek to a keyframe *after* the given time - // we want to seek to any keyframe *before* the given time, so we can continue decoding as normal from there on - if(av_seek_frame(self->format_ctx, streamIndex, timestamp, AVSEEK_FLAG_BACKWARD) < 0) - std::cerr << "Error seeking " << self->format_ctx->filename << std::endl; - else + if(self->mSeekRequested) { - // Clear the packet queues and put a special packet with the new clock time - if(audioStreamIndex >= 0) - { - self->audioq.clear(); - flush_pkt.pts = av_rescale_q(seek_target, avTimeBaseQ, - self->format_ctx->streams[audioStreamIndex]->time_base); - self->audioq.put(&flush_pkt); - } + uint64_t seek_target = self->mSeekPos; + int streamIndex = -1; + + int videoStreamIndex = -1;; + int audioStreamIndex = -1; + if (self->video_st) + videoStreamIndex = self->video_st - self->format_ctx->streams; + if (self->audio_st) + audioStreamIndex = self->audio_st - self->format_ctx->streams; + if(videoStreamIndex >= 0) + streamIndex = videoStreamIndex; + else if(audioStreamIndex >= 0) + streamIndex = audioStreamIndex; + + uint64_t timestamp = seek_target; + + // QtCreator's highlighter doesn't like AV_TIME_BASE_Q's {} initializer for some reason + AVRational avTimeBaseQ = AVRational(); // = AV_TIME_BASE_Q; + avTimeBaseQ.num = 1; + avTimeBaseQ.den = AV_TIME_BASE; + + if(streamIndex >= 0) + timestamp = av_rescale_q(seek_target, avTimeBaseQ, self->format_ctx->streams[streamIndex]->time_base); + + // AVSEEK_FLAG_BACKWARD appears to be needed, otherwise ffmpeg may seek to a keyframe *after* the given time + // we want to seek to any keyframe *before* the given time, so we can continue decoding as normal from there on + if(av_seek_frame(self->format_ctx, streamIndex, timestamp, AVSEEK_FLAG_BACKWARD) < 0) + std::cerr << "Error seeking " << self->format_ctx->filename << std::endl; + else { - self->videoq.clear(); - flush_pkt.pts = av_rescale_q(seek_target, avTimeBaseQ, - self->format_ctx->streams[videoStreamIndex]->time_base); - self->videoq.put(&flush_pkt); + // Clear the packet queues and put a special packet with the new clock time + if(audioStreamIndex >= 0) + { + self->audioq.clear(); + flush_pkt.pts = av_rescale_q(seek_target, avTimeBaseQ, + self->format_ctx->streams[audioStreamIndex]->time_base); + self->audioq.put(&flush_pkt); + } + if(videoStreamIndex >= 0) + { + self->videoq.clear(); + flush_pkt.pts = av_rescale_q(seek_target, avTimeBaseQ, + self->format_ctx->streams[videoStreamIndex]->time_base); + self->videoq.put(&flush_pkt); + } + self->pictq_mutex.lock(); + self->pictq_size = 0; + self->pictq_rindex = 0; + self->pictq_windex = 0; + self->pictq_mutex.unlock(); + self->mExternalClock.set(seek_target); } - self->pictq_mutex.lock(); - self->pictq_size = 0; - self->pictq_rindex = 0; - self->pictq_windex = 0; - self->pictq_mutex.unlock(); - self->mExternalClock.set(seek_target); + self->mSeekRequested = false; } - self->mSeekRequested = false; - } - if((self->audio_st && self->audioq.size > MAX_AUDIOQ_SIZE) || - (self->video_st && self->videoq.size > MAX_VIDEOQ_SIZE)) - { - boost::this_thread::sleep(boost::posix_time::milliseconds(10)); - continue; - } + if((self->audio_st && self->audioq.size > MAX_AUDIOQ_SIZE) || + (self->video_st && self->videoq.size > MAX_VIDEOQ_SIZE)) + { + OpenThreads::Thread::microSleep(10 * 1000); + continue; + } - if(av_read_frame(pFormatCtx, packet) < 0) - { - if (self->audioq.nb_packets == 0 && self->videoq.nb_packets == 0 && self->pictq_size == 0) - self->mVideoEnded = true; - continue; - } - else - self->mVideoEnded = false; + if(av_read_frame(pFormatCtx, packet) < 0) + { + if (self->audioq.nb_packets == 0 && self->videoq.nb_packets == 0 && self->pictq_size == 0) + self->mVideoEnded = true; + continue; + } + else + self->mVideoEnded = false; - // Is this a packet from the video stream? - if(self->video_st && packet->stream_index == self->video_st-pFormatCtx->streams) - self->videoq.put(packet); - else if(self->audio_st && packet->stream_index == self->audio_st-pFormatCtx->streams) - self->audioq.put(packet); - else - av_free_packet(packet); + // Is this a packet from the video stream? + if(self->video_st && packet->stream_index == self->video_st-pFormatCtx->streams) + self->videoq.put(packet); + else if(self->audio_st && packet->stream_index == self->audio_st-pFormatCtx->streams) + self->audioq.put(packet); + else + av_free_packet(packet); + } } - } - catch(std::exception& e) { - std::cerr << "An error occurred playing the video: " << e.what () << std::endl; + catch(std::exception& e) { + std::cerr << "An error occurred playing the video: " << e.what () << std::endl; + } + + self->mQuit = true; } - self->mQuit = true; -} +private: + VideoState* mVideoState; +}; bool VideoState::update() @@ -587,7 +616,7 @@ int VideoState::stream_open(int stream_index, AVFormatContext *pFormatCtx) this->video_st = pFormatCtx->streams + stream_index; codecCtx->get_buffer2 = our_get_buffer; - this->video_thread = boost::thread(video_thread_loop, this); + this->video_thread.reset(new VideoThread(this)); break; default: @@ -669,7 +698,7 @@ void VideoState::init(boost::shared_ptr inputstream, const std::st } - this->parse_thread = boost::thread(decode_thread_loop, this); + this->parse_thread.reset(new ParseThread(this)); } void VideoState::deinit() @@ -681,10 +710,16 @@ void VideoState::deinit() mAudioDecoder.reset(); - if (this->parse_thread.joinable()) - this->parse_thread.join(); - if (this->video_thread.joinable()) - this->video_thread.join(); + if (this->parse_thread.get()) + { + this->parse_thread->join(); + this->parse_thread.reset(); + } + if (this->video_thread.get()) + { + this->video_thread->join(); + this->video_thread.reset(); + } if(this->audio_st) avcodec_close((*this->audio_st)->codec); @@ -779,7 +814,7 @@ ExternalClock::ExternalClock() void ExternalClock::setPaused(bool paused) { - boost::mutex::scoped_lock lock(mMutex); + OpenThreads::ScopedLock lock(mMutex); if (mPaused == paused) return; if (paused) @@ -793,7 +828,7 @@ void ExternalClock::setPaused(bool paused) uint64_t ExternalClock::get() { - boost::mutex::scoped_lock lock(mMutex); + OpenThreads::ScopedLock lock(mMutex); if (mPaused) return mPausedAt; else @@ -802,7 +837,7 @@ uint64_t ExternalClock::get() void ExternalClock::set(uint64_t time) { - boost::mutex::scoped_lock lock(mMutex); + OpenThreads::ScopedLock lock(mMutex); mTimeBase = av_gettime() - time; mPausedAt = time; } diff --git a/extern/osg-ffmpeg-videoplayer/videostate.hpp b/extern/osg-ffmpeg-videoplayer/videostate.hpp index 72a2aab18..2f0e8f30a 100644 --- a/extern/osg-ffmpeg-videoplayer/videostate.hpp +++ b/extern/osg-ffmpeg-videoplayer/videostate.hpp @@ -2,8 +2,14 @@ #define VIDEOPLAYER_VIDEOSTATE_H #include +#include +#include -#include +#include + +#include +#include +#include #include namespace osg @@ -34,6 +40,8 @@ struct VideoState; class MovieAudioFactory; class MovieAudioDecoder; +class VideoThread; +class ParseThread; struct ExternalClock { @@ -43,7 +51,7 @@ struct ExternalClock uint64_t mPausedAt; bool mPaused; - boost::mutex mMutex; + OpenThreads::Mutex mMutex; void setPaused(bool paused); uint64_t get(); @@ -62,8 +70,8 @@ struct PacketQueue { int nb_packets; int size; - boost::mutex mutex; - boost::condition_variable cond; + OpenThreads::Mutex mutex; + OpenThreads::Condition cond; void put(AVPacket *pkt); int get(AVPacket *pkt, VideoState *is); @@ -141,11 +149,11 @@ struct VideoState { VideoPicture pictq[VIDEO_PICTURE_ARRAY_SIZE]; AVFrame* rgbaFrame; // used as buffer for the frame converted from its native format to RGBA int pictq_size, pictq_rindex, pictq_windex; - boost::mutex pictq_mutex; - boost::condition_variable pictq_cond; + OpenThreads::Mutex pictq_mutex; + OpenThreads::Condition pictq_cond; - boost::thread parse_thread; - boost::thread video_thread; + std::auto_ptr parse_thread; + std::auto_ptr video_thread; volatile bool mSeekRequested; uint64_t mSeekPos; diff --git a/files/mygui/openmw_resources.xml b/files/mygui/openmw_resources.xml index ab6899341..6fa7e92d4 100644 --- a/files/mygui/openmw_resources.xml +++ b/files/mygui/openmw_resources.xml @@ -120,6 +120,10 @@ + + + + @@ -128,6 +132,10 @@ + + + + @@ -140,6 +148,10 @@ + + + +