From 53e94b7c3f1128ccaaa0ea11b4cabadbc54b095e Mon Sep 17 00:00:00 2001 From: Allofich Date: Thu, 6 Oct 2016 01:12:06 +0900 Subject: [PATCH 01/30] Fix shadowing warnings --- apps/openmw/mwdialogue/scripttest.cpp | 4 ++-- apps/openmw/mwgui/birth.cpp | 2 +- apps/openmw/mwgui/mapwindow.cpp | 4 ++-- apps/openmw/mwgui/quickkeysmenu.cpp | 10 +++++----- apps/openmw/mwgui/race.cpp | 6 +++--- apps/openmw/mwmechanics/aisequence.cpp | 4 ++-- apps/openmw/mwmechanics/character.cpp | 22 ++++++++++------------ apps/openmw/mwmechanics/npcstats.cpp | 4 ++-- apps/openmw/mwmechanics/spellcasting.cpp | 14 +++++++------- apps/openmw/mwworld/containerstore.cpp | 8 ++++---- 10 files changed, 38 insertions(+), 40 deletions(-) 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/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/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/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/character.cpp b/apps/openmw/mwmechanics/character.cpp index 6aaba9635..5ca9b09aa 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: @@ -1740,14 +1740,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 8bea109d0..0b016e69d 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 ad05ca41f..1fc800a7c 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -495,13 +495,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()); } } } @@ -512,11 +512,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); } } diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 7ac0d9d4e..7eb7c31c7 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -423,12 +423,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 +436,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 From 0c981b6fe558f171ad485994949ff3a6fd3a9ddf Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 6 Oct 2016 17:36:50 +0200 Subject: [PATCH 02/30] Fix typo in script opcode (Fixes #3583) --- components/compiler/extensions0.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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); From 498976775aef151d20727f2207fa961dfeb709f6 Mon Sep 17 00:00:00 2001 From: Allofich Date: Fri, 7 Oct 2016 01:38:50 +0900 Subject: [PATCH 03/30] Fix reversed use of alembics and retorts --- apps/openmw/mwmechanics/alchemy.cpp | 2 +- components/esm/loadappa.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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/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 }; From f6f16b68de1376580828f38505b954b0aba52932 Mon Sep 17 00:00:00 2001 From: Allofich Date: Sat, 8 Oct 2016 17:56:12 +0900 Subject: [PATCH 04/30] Don't let Weakness to Magicka affect paralysis --- components/esm/loadmgef.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) 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]; From 3019d70986256fce9ff29e75ca152b572922124f Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 8 Oct 2016 16:05:20 +0200 Subject: [PATCH 05/30] Use 'default icon' for items with no icon specified --- apps/openmw/mwgui/itemwidget.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/itemwidget.cpp b/apps/openmw/mwgui/itemwidget.cpp index 75436e797..fa8383ace 100644 --- a/apps/openmw/mwgui/itemwidget.cpp +++ b/apps/openmw/mwgui/itemwidget.cpp @@ -79,7 +79,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)); } From 661533043047426c3bf51b02cd6b0c4944fbdc4b Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 8 Oct 2016 16:41:17 +0200 Subject: [PATCH 06/30] Fix use of UnrefQueue in removeObject --- apps/openmw/mwrender/objects.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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); From 4815938de2a69806fcab5bfc0aa51903a15852ce Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Sat, 8 Oct 2016 17:07:06 +0200 Subject: [PATCH 07/30] [OS X] Add missing plugins to packaging script Source: https://wiki.openmw.org/index.php?title=Development_Environment_Setup#OSG_plugins Issue: https://bugs.openmw.org/issues/3585 --- CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 71e85068c..559e4a850 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -741,9 +741,12 @@ if (APPLE) set(ABSOLUTE_PLUGINS "") set(USED_OSG_PLUGINS + osgdb_bmp osgdb_dds osgdb_jpeg + osgdb_osg osgdb_png + osgdb_serializers_osg osgdb_tga ) From 50bcb65ee0c01ead148010f42b66c74eb1a56ccd Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 8 Oct 2016 19:20:10 +0200 Subject: [PATCH 08/30] Move USED_OSG_PLUGINS to the top of the CMakeLists to be used by all platforms --- CMakeLists.txt | 21 +++++++++++---------- apps/openmw/CMakeLists.txt | 15 ++++++++------- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 559e4a850..8f60b80e8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -223,13 +223,23 @@ endif() 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() @@ -740,15 +750,6 @@ if (APPLE) " COMPONENT Runtime) set(ABSOLUTE_PLUGINS "") - set(USED_OSG_PLUGINS - osgdb_bmp - osgdb_dds - osgdb_jpeg - osgdb_osg - osgdb_png - osgdb_serializers_osg - osgdb_tga - ) foreach (PLUGIN_NAME ${USED_OSG_PLUGINS}) set(PLUGIN_ABS "${OSGPlugins_LIB_DIR}/${PLUGIN_NAME}.so") diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 5423322e8..aba2a6af4 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -142,14 +142,15 @@ target_link_libraries(openmw 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(openmw EGL android From 5c94e2324fefdfe69f19baa6c1389ef446e127c0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 8 Oct 2016 19:20:44 +0200 Subject: [PATCH 09/30] Add missing use plugin macro for static build --- components/resource/imagemanager.cpp | 3 +++ 1 file changed, 3 insertions(+) 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 From 11565b59665bab0824801e296a4386163842fd94 Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Sat, 8 Oct 2016 03:49:50 +0200 Subject: [PATCH 10/30] Make actors with non-portable lights in inventory glow (Closes #2042, #3338) --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwrender/actoranimation.cpp | 155 +++++++++++++++++++++ apps/openmw/mwrender/actoranimation.hpp | 58 ++++++++ apps/openmw/mwrender/animation.cpp | 2 + apps/openmw/mwrender/animation.hpp | 2 + apps/openmw/mwrender/creatureanimation.cpp | 6 +- apps/openmw/mwrender/creatureanimation.hpp | 6 +- apps/openmw/mwrender/npcanimation.cpp | 9 +- apps/openmw/mwrender/npcanimation.hpp | 3 +- apps/openmw/mwworld/containerstore.cpp | 17 +++ apps/openmw/mwworld/containerstore.hpp | 12 ++ apps/openmw/mwworld/inventorystore.cpp | 4 +- apps/openmw/mwworld/inventorystore.hpp | 4 +- components/sceneutil/lightmanager.cpp | 4 + components/sceneutil/lightmanager.hpp | 6 + components/sceneutil/lightutil.cpp | 14 +- components/sceneutil/lightutil.hpp | 13 ++ 17 files changed, 297 insertions(+), 20 deletions(-) create mode 100644 apps/openmw/mwrender/actoranimation.cpp create mode 100644 apps/openmw/mwrender/actoranimation.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index aba2a6af4..58dc2e8e5 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 diff --git a/apps/openmw/mwrender/actoranimation.cpp b/apps/openmw/mwrender/actoranimation.cpp new file mode 100644 index 000000000..1a3285713 --- /dev/null +++ b/apps/openmw/mwrender/actoranimation.cpp @@ -0,0 +1,155 @@ +#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 "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::objectRootReset() +{ + if (SceneUtil::LightListCallback* callback = findLightListCallback()) + { + for (ItemLightMap::iterator iter = mItemLights.begin(); iter != mItemLights.end(); ++iter) + { + callback->getIgnoredLightSources().insert(iter->second); + } + } +} + +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 (SceneUtil::LightListCallback* callback = findLightListCallback()) + callback->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 (SceneUtil::LightListCallback* callback = findLightListCallback()) + { + std::set::iterator ignoredIter = callback->getIgnoredLightSources().find(iter->second.get()); + if (ignoredIter != callback->getIgnoredLightSources().end()) + callback->getIgnoredLightSources().erase(ignoredIter); + } + + mInsert->removeChild(iter->second); + mItemLights.erase(iter); +} + +SceneUtil::LightListCallback* ActorAnimation::findLightListCallback() +{ + if (osg::Callback* callback = mObjectRoot->getCullCallback()) + { + do + { + if (SceneUtil::LightListCallback* lightListCallback = dynamic_cast(callback)) + return lightListCallback; + } + while ((callback = callback->getNestedCallback())); + } + return NULL; +} + +} diff --git a/apps/openmw/mwrender/actoranimation.hpp b/apps/openmw/mwrender/actoranimation.hpp new file mode 100644 index 000000000..e08df54f2 --- /dev/null +++ b/apps/openmw/mwrender/actoranimation.hpp @@ -0,0 +1,58 @@ +#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); + + protected: + virtual void objectRootReset(); + + private: + void addHiddenItemLight(const MWWorld::ConstPtr& item, const ESM::Light* esmLight); + void removeHiddenItemLight(const MWWorld::ConstPtr& item); + + SceneUtil::LightListCallback* findLightListCallback(); + + 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..e4855064a 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -1151,6 +1151,8 @@ namespace MWRender } mObjectRoot->addCullCallback(new SceneUtil::LightListCallback); + + objectRootReset(); } osg::Group* Animation::getObjectRoot() diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 089d0d85b..cf6afd613 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -307,6 +307,8 @@ protected: */ void setObjectRoot(const std::string &model, bool forceskeleton, bool baseonly, bool isCreature); + virtual void objectRootReset() {} + /** Adds the keyframe controllers in the specified model as a new animation source. Note that the .nif * file extension will be replaced with .kf. * @note Later added animation sources have the highest priority when it comes to finding a particular animation. 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/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 7eb7c31c7..112325892 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -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; } 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/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 From 1893617ec98491c5729c9d5bd59d24814d7567e8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 8 Oct 2016 23:59:28 +0200 Subject: [PATCH 11/30] Improvements to ignored light list setting The pointer to the LightListCallback is now stored in the Animation, which eliminates the need for dynamic_cast. Also, when the object root is recreated, the previously used LightListCallback will be reused, so we no longer need the objectRootReset() notifier. Finally, there was a bug when saving and reloading the game, the getIgnoredLightSources() were not being set, as the ActorAnimation constructor completes before the NpcAnimation sets the ObjectRoot. This was solved by creating the LightListCallback in advance in the Animation constructor. --- apps/openmw/mwrender/actoranimation.cpp | 29 ++----------------------- apps/openmw/mwrender/actoranimation.hpp | 5 ----- apps/openmw/mwrender/animation.cpp | 8 ++++++- apps/openmw/mwrender/animation.hpp | 3 +++ 4 files changed, 12 insertions(+), 33 deletions(-) diff --git a/apps/openmw/mwrender/actoranimation.cpp b/apps/openmw/mwrender/actoranimation.cpp index 1a3285713..c16fbfd50 100644 --- a/apps/openmw/mwrender/actoranimation.cpp +++ b/apps/openmw/mwrender/actoranimation.cpp @@ -83,17 +83,6 @@ void ActorAnimation::itemRemoved(const MWWorld::ConstPtr& item, int /*count*/) } } -void ActorAnimation::objectRootReset() -{ - if (SceneUtil::LightListCallback* callback = findLightListCallback()) - { - for (ItemLightMap::iterator iter = mItemLights.begin(); iter != mItemLights.end(); ++iter) - { - callback->getIgnoredLightSources().insert(iter->second); - } - } -} - void ActorAnimation::addHiddenItemLight(const MWWorld::ConstPtr& item, const ESM::Light* esmLight) { if (mItemLights.find(item) != mItemLights.end()) @@ -115,7 +104,7 @@ void ActorAnimation::addHiddenItemLight(const MWWorld::ConstPtr& item, const ESM mInsert->addChild(lightSource); - if (SceneUtil::LightListCallback* callback = findLightListCallback()) + if (SceneUtil::LightListCallback* callback = mLightListCallback) callback->getIgnoredLightSources().insert(lightSource.get()); mItemLights.insert(std::make_pair(item, lightSource)); @@ -127,7 +116,7 @@ void ActorAnimation::removeHiddenItemLight(const MWWorld::ConstPtr& item) if (iter == mItemLights.end()) return; - if (SceneUtil::LightListCallback* callback = findLightListCallback()) + if (SceneUtil::LightListCallback* callback = mLightListCallback) { std::set::iterator ignoredIter = callback->getIgnoredLightSources().find(iter->second.get()); if (ignoredIter != callback->getIgnoredLightSources().end()) @@ -138,18 +127,4 @@ void ActorAnimation::removeHiddenItemLight(const MWWorld::ConstPtr& item) mItemLights.erase(iter); } -SceneUtil::LightListCallback* ActorAnimation::findLightListCallback() -{ - if (osg::Callback* callback = mObjectRoot->getCullCallback()) - { - do - { - if (SceneUtil::LightListCallback* lightListCallback = dynamic_cast(callback)) - return lightListCallback; - } - while ((callback = callback->getNestedCallback())); - } - return NULL; -} - } diff --git a/apps/openmw/mwrender/actoranimation.hpp b/apps/openmw/mwrender/actoranimation.hpp index e08df54f2..6922603e1 100644 --- a/apps/openmw/mwrender/actoranimation.hpp +++ b/apps/openmw/mwrender/actoranimation.hpp @@ -38,15 +38,10 @@ class ActorAnimation : public Animation, public MWWorld::ContainerStoreListener virtual void itemAdded(const MWWorld::ConstPtr& item, int count); virtual void itemRemoved(const MWWorld::ConstPtr& item, int count); - protected: - virtual void objectRootReset(); - private: void addHiddenItemLight(const MWWorld::ConstPtr& item, const ESM::Light* esmLight); void removeHiddenItemLight(const MWWorld::ConstPtr& item); - SceneUtil::LightListCallback* findLightListCallback(); - typedef std::map > ItemLightMap; ItemLightMap mItemLights; diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index e4855064a..e6a72f74c 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); objectRootReset(); } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index cf6afd613..6c4f18a0f 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. From 028db21c8aa73e5889d964960c92619f9398e2f4 Mon Sep 17 00:00:00 2001 From: Allofich Date: Sat, 8 Oct 2016 21:18:38 +0900 Subject: [PATCH 12/30] Don't let disposition at end of dialogue be below 0 (Fixes #3584) --- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 578b5b9a4..14210099f 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -448,6 +448,12 @@ 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()) { From 105fcc5e20535c7a313591fc5caa0f2ee735c52c Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 10 Oct 2016 15:59:59 +0200 Subject: [PATCH 13/30] Move the setting of BOOST_COMPONENTS closer to where it's actually used --- CMakeLists.txt | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8f60b80e8..939c27310 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -211,15 +211,6 @@ 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() - find_package(OpenSceneGraph 3.3.4 REQUIRED osgDB osgViewer osgText osgGA osgAnimation osgParticle osgUtil osgFX) include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS}) @@ -253,8 +244,18 @@ if(QT_STATIC) endif() endif() -find_package(MyGUI 3.2.1 REQUIRED) + +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}) +find_package(MyGUI 3.2.1 REQUIRED) find_package(SDL2 REQUIRED) find_package(OpenAL REQUIRED) find_package(Bullet 283 REQUIRED COMPONENTS BulletCollision LinearMath) From 530fb61ad03ada7ba00f70faffe165586e43b763 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 10 Oct 2016 16:06:22 +0200 Subject: [PATCH 14/30] Use OpenThreads instead of boost thread This should allow OpenMW to work better with git versions of openscenegraph. OSG dev version 3.5.5 added the setting of thread affinity for the main thread. The problem is that in the boost/standard threading libraries, the affinity of a thread is inherited by any further threads launched from that thread, leading to these threads always running on the same core as the main thread unless you tell them not to. With OpenThreads, the default affinity of a thread is none, no matter what parent thread it was launched from. So, when using custom threading with OSG 3.6+, we have these options: 1. explicitely tell OSG to *not* set the thread affinity or 2. explicitely set the thread affinity of additional threads created (possible with boost, but not possible with std::thread) or 3. use OpenThreads or 4. accept the suboptimal performance of non-OSG threads (in OpenMW's case the sound streaming & video threads) running on the same core as the main thread This patch opts for 3.) Reference: http://forum.openscenegraph.org/viewtopic.php?t=16158 --- apps/openmw/mwsound/openal_output.cpp | 45 +-- .../osg-ffmpeg-videoplayer/audiodecoder.cpp | 1 + extern/osg-ffmpeg-videoplayer/videostate.cpp | 329 ++++++++++-------- extern/osg-ffmpeg-videoplayer/videostate.hpp | 24 +- 4 files changed, 223 insertions(+), 176 deletions(-) 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/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; From 95a67bf0c24d5c0923b0e8df9415e1a720a62982 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 10 Oct 2016 18:17:40 +0200 Subject: [PATCH 15/30] Disable OSG 3.5.5 thread affinity setting in the scenewidget due to the interference with QT threads Reference: http://forum.openscenegraph.org/viewtopic.php?t=16158 --- apps/opencs/view/render/scenewidget.cpp | 5 +++++ 1 file changed, 5 insertions(+) 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); From 14468262a75309b98d9795e781234725aebce9a2 Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Tue, 11 Oct 2016 02:46:23 +0200 Subject: [PATCH 16/30] Fix "Not Local" dialog test to also test variable value instead of just its existence (Fixes #3577) --- apps/openmw/mwdialogue/filter.cpp | 80 +++++++++++------------- apps/openmw/mwdialogue/filter.hpp | 2 + apps/openmw/mwdialogue/selectwrapper.cpp | 4 +- 3 files changed, 42 insertions(+), 44 deletions(-) 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/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 }; From 8be8c7ca66384c8583a02b919b245e0674c86327 Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Tue, 11 Oct 2016 02:47:03 +0200 Subject: [PATCH 17/30] OpenMW-CS: Fix verification of "Not Local" info conditions (Bug #3564) --- apps/opencs/model/world/infoselectwrapper.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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: From 3dce155d9649b9a67ebf66a51a68affdc63385d2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 11 Oct 2016 14:50:13 +0200 Subject: [PATCH 18/30] Fix uninitialized variable --- apps/openmw/mwworld/containerstore.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 112325892..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() {} From 53b006eccb28ab80fd6c5d7f10ea37fcd4ffb2be Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Tue, 11 Oct 2016 19:36:44 +0200 Subject: [PATCH 19/30] OpenMW-CS: Recognize special faction ID "FFFF" (no faction) during topic info verification (Fixes #3564) --- apps/opencs/model/tools/topicinfocheck.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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)) { From 1906d96064d2cec61cbef517faeb2f1633a60287 Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Tue, 11 Oct 2016 22:15:51 +0200 Subject: [PATCH 20/30] Non-player actors emitting light from a non-portable light item should be illuminated (Fixes #3588) --- apps/openmw/mwrender/actoranimation.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwrender/actoranimation.cpp b/apps/openmw/mwrender/actoranimation.cpp index c16fbfd50..5dcd5212c 100644 --- a/apps/openmw/mwrender/actoranimation.cpp +++ b/apps/openmw/mwrender/actoranimation.cpp @@ -19,6 +19,7 @@ #include "../mwworld/ptr.hpp" #include "../mwworld/class.hpp" #include "../mwworld/cellstore.hpp" +#include "../mwmechanics/actorutil.hpp" #include "vismask.hpp" @@ -104,8 +105,8 @@ void ActorAnimation::addHiddenItemLight(const MWWorld::ConstPtr& item, const ESM mInsert->addChild(lightSource); - if (SceneUtil::LightListCallback* callback = mLightListCallback) - callback->getIgnoredLightSources().insert(lightSource.get()); + if (mLightListCallback && mPtr == MWMechanics::getPlayer()) + mLightListCallback->getIgnoredLightSources().insert(lightSource.get()); mItemLights.insert(std::make_pair(item, lightSource)); } @@ -116,11 +117,11 @@ void ActorAnimation::removeHiddenItemLight(const MWWorld::ConstPtr& item) if (iter == mItemLights.end()) return; - if (SceneUtil::LightListCallback* callback = mLightListCallback) + if (mLightListCallback && mPtr == MWMechanics::getPlayer()) { - std::set::iterator ignoredIter = callback->getIgnoredLightSources().find(iter->second.get()); - if (ignoredIter != callback->getIgnoredLightSources().end()) - callback->getIgnoredLightSources().erase(ignoredIter); + std::set::iterator ignoredIter = mLightListCallback->getIgnoredLightSources().find(iter->second.get()); + if (ignoredIter != mLightListCallback->getIgnoredLightSources().end()) + mLightListCallback->getIgnoredLightSources().erase(ignoredIter); } mInsert->removeChild(iter->second); From 611d02ad43e0457d5298ee8e7616dd4e5258c4fb Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Tue, 11 Oct 2016 22:16:17 +0200 Subject: [PATCH 21/30] Remove unused code --- apps/openmw/mwrender/animation.cpp | 2 -- apps/openmw/mwrender/animation.hpp | 2 -- 2 files changed, 4 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index e6a72f74c..6091bee71 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -1157,8 +1157,6 @@ namespace MWRender if (!mLightListCallback) mLightListCallback = new SceneUtil::LightListCallback; mObjectRoot->addCullCallback(mLightListCallback); - - objectRootReset(); } osg::Group* Animation::getObjectRoot() diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 6c4f18a0f..b99464014 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -310,8 +310,6 @@ protected: */ void setObjectRoot(const std::string &model, bool forceskeleton, bool baseonly, bool isCreature); - virtual void objectRootReset() {} - /** Adds the keyframe controllers in the specified model as a new animation source. Note that the .nif * file extension will be replaced with .kf. * @note Later added animation sources have the highest priority when it comes to finding a particular animation. From 612c3e995f4fa39c3800795d9f1d34a2e32f97a8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 13 Oct 2016 01:42:50 +0200 Subject: [PATCH 22/30] Add drop shadow to ItemWidget (Fixes #3545) --- apps/openmw/mwgui/itemwidget.cpp | 6 ++++++ apps/openmw/mwgui/itemwidget.hpp | 1 + files/mygui/openmw_resources.xml | 4 ++++ 3 files changed, 11 insertions(+) diff --git a/apps/openmw/mwgui/itemwidget.cpp b/apps/openmw/mwgui/itemwidget.cpp index fa8383ace..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); } 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/files/mygui/openmw_resources.xml b/files/mygui/openmw_resources.xml index ab6899341..d6a4f1b45 100644 --- a/files/mygui/openmw_resources.xml +++ b/files/mygui/openmw_resources.xml @@ -120,6 +120,10 @@ + + + + From e7154c3f7c888451dbbe8210ad3885e6914f6faf Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 13 Oct 2016 01:46:57 +0200 Subject: [PATCH 23/30] Add the ItemShadow to various other skins --- files/mygui/openmw_resources.xml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/files/mygui/openmw_resources.xml b/files/mygui/openmw_resources.xml index d6a4f1b45..6fa7e92d4 100644 --- a/files/mygui/openmw_resources.xml +++ b/files/mygui/openmw_resources.xml @@ -132,6 +132,10 @@ + + + + @@ -144,6 +148,10 @@ + + + + From d7acec74fdd03de00ce6a9a7c0e107f29020ba0c Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 13 Oct 2016 14:38:35 +0200 Subject: [PATCH 24/30] Fix the cell changed flag no longer being reset after the player dies --- apps/openmw/engine.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 62457cae6..c6cabffa3 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -120,16 +120,21 @@ void OMW::Engine::frame(float frametime) // global scripts mEnvironment.getScriptManager()->getGlobalScripts().run(); } - - mEnvironment.getWorld()->markCellAsUnchanged(); } + } + mEnvironment.getWorld()->markCellAsUnchanged(); + + if (mEnvironment.getStateManager()->getState()== + MWBase::StateManager::State_Running) + { if (!guiActive) { double hours = (frametime * mEnvironment.getWorld()->getTimeScaleFactor()) / 3600.0; mEnvironment.getWorld()->advanceTime(hours, true); } } + osg::Timer_t afterScriptTick = osg::Timer::instance()->tick(); // update actors From 454d1ffaef38b28f23b45ffbe45171549d097583 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 13 Oct 2016 14:39:58 +0200 Subject: [PATCH 25/30] Make the cell change check during actor update more robust --- apps/openmw/mwmechanics/actors.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 2a313df15..1a6a62fc3 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1035,8 +1035,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 From db09858f5962f35c807463203469187c998dfe16 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 13 Oct 2016 14:42:10 +0200 Subject: [PATCH 26/30] Don't allow the player to activate objects when dead --- apps/openmw/mwworld/player.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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(); From 675bd094624b2d43c0a6db55aa4e090f1a9404d3 Mon Sep 17 00:00:00 2001 From: Allofich Date: Thu, 13 Oct 2016 20:16:13 +0900 Subject: [PATCH 27/30] Change several instant effects to be non-instant (Fixes #2054) --- apps/openmw/mwmechanics/spellcasting.cpp | 55 ++++++++++-------------- 1 file changed, 23 insertions(+), 32 deletions(-) diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 1fc800a7c..6ab7c6699 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -463,8 +463,7 @@ namespace MWMechanics } else // target.getClass().isActor() == true { - bool hasDuration = !(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration); - if (hasDuration && effectIt->mDuration == 0) + if (effectIt->mDuration == 0) { // duration 0 means apply full magnitude instantly bool wasDead = target.getClass().getCreatureStats(target).isDead(); @@ -610,36 +609,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) @@ -662,7 +633,6 @@ namespace MWMechanics anim->addEffect("meshes\\" + fx->mModel, -1); return true; } - else if (effectId == ESM::MagicEffect::Mark) { MWBase::Environment::get().getWorld()->getPlayer().markPosition( @@ -1149,6 +1119,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()) From 1c2e04747d3b7157b3950f393a4a575c39c6a381 Mon Sep 17 00:00:00 2001 From: Allofich Date: Thu, 13 Oct 2016 20:20:39 +0900 Subject: [PATCH 28/30] Remove stray line --- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 14210099f..ee6e24938 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -448,8 +448,7 @@ 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) - + // 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; From 610f36f47b1e2ac02f7c7f919c8fe9b0932e2247 Mon Sep 17 00:00:00 2001 From: Allofich Date: Fri, 14 Oct 2016 00:05:21 +0900 Subject: [PATCH 29/30] Set magic effects that don't support variable durations to use duration of 1 --- apps/openmw/mwmechanics/spellcasting.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 6ab7c6699..aaed6712e 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -463,7 +463,8 @@ namespace MWMechanics } else // target.getClass().isActor() == true { - if (effectIt->mDuration == 0) + bool hasDuration = !(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration); + if (hasDuration && effectIt->mDuration == 0) { // duration 0 means apply full magnitude instantly bool wasDead = target.getClass().getCreatureStats(target).isDead(); @@ -479,7 +480,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)); From 9d2e0124dcfe0b1249e31517295fe958c91cc3fb Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 13 Oct 2016 17:44:03 +0200 Subject: [PATCH 30/30] Revert "Fix the cell changed flag no longer being reset after the player dies" This reverts commit d7acec74fdd03de00ce6a9a7c0e107f29020ba0c. --- apps/openmw/engine.cpp | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index c6cabffa3..62457cae6 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -120,21 +120,16 @@ void OMW::Engine::frame(float frametime) // global scripts mEnvironment.getScriptManager()->getGlobalScripts().run(); } - } - } - mEnvironment.getWorld()->markCellAsUnchanged(); + mEnvironment.getWorld()->markCellAsUnchanged(); + } - if (mEnvironment.getStateManager()->getState()== - MWBase::StateManager::State_Running) - { if (!guiActive) { double hours = (frametime * mEnvironment.getWorld()->getTimeScaleFactor()) / 3600.0; mEnvironment.getWorld()->advanceTime(hours, true); } } - osg::Timer_t afterScriptTick = osg::Timer::instance()->tick(); // update actors