Resolve conflicts in pull request #75

# Conflicts:
#	CMakeLists.txt
#	apps/openmw/CMakeLists.txt
coverity_scan^2
David Cernat 8 years ago
commit 3136a12051

@ -217,27 +217,28 @@ if(NOT HAVE_STDINT_H)
endif()
set(BOOST_COMPONENTS system filesystem program_options thread)
if(WIN32)
set(BOOST_COMPONENTS ${BOOST_COMPONENTS} locale)
endif(WIN32)
IF(BOOST_STATIC)
set(Boost_USE_STATIC_LIBS ON)
endif()
IF(BUILD_OPENMW OR BUILD_OPENCS)
find_package(OpenSceneGraph 3.3.4 REQUIRED osgDB osgViewer osgText osgGA osgAnimation osgParticle osgUtil osgFX)
include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS})
set(USED_OSG_PLUGINS
osgdb_bmp
osgdb_dds
osgdb_jpeg
osgdb_osg
osgdb_png
osgdb_serializers_osg
osgdb_tga
)
get_filename_component(OSG_LIB_DIR ${OSGDB_LIBRARY} DIRECTORY)
set(OSGPlugins_LIB_DIR "${OSG_LIB_DIR}/osgPlugins-${OPENSCENEGRAPH_VERSION}")
if(OSG_STATIC)
add_definitions(-DOSG_LIBRARY_STATIC)
find_package(OSGPlugins REQUIRED COMPONENTS osgdb_png osgdb_tga osgdb_dds osgdb_jpeg)
find_package(OSGPlugins REQUIRED COMPONENTS ${USED_OSG_PLUGINS})
list(APPEND OPENSCENEGRAPH_LIBRARIES ${OSGPlugins_LIBRARIES})
endif()
@ -258,6 +259,16 @@ IF(BUILD_OPENMW OR BUILD_OPENCS)
ENDIF(BUILD_OPENMW OR BUILD_OPENCS)
set(BOOST_COMPONENTS system filesystem program_options)
if(WIN32)
set(BOOST_COMPONENTS ${BOOST_COMPONENTS} locale)
endif(WIN32)
IF(BOOST_STATIC)
set(Boost_USE_STATIC_LIBS ON)
endif()
find_package(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS})
include_directories("."
@ -769,12 +780,6 @@ if (APPLE)
" COMPONENT Runtime)
set(ABSOLUTE_PLUGINS "")
set(USED_OSG_PLUGINS
osgdb_dds
osgdb_jpeg
osgdb_png
osgdb_tga
)
foreach (PLUGIN_NAME ${USED_OSG_PLUGINS})
set(PLUGIN_ABS "${OSGPlugins_LIB_DIR}/${PLUGIN_NAME}.so")

@ -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))
{

@ -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<int, int> 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<int, int> CSMWorld::ConstInfoSelectWrapper::getValidIntRange() const
// Numeric
case Function_Global:
case Function_Local:
case Function_NotLocal:
return std::pair<int, int>(IntMin, IntMax);
case Function_PcMagicka:

@ -10,6 +10,7 @@
#include <osgViewer/CompositeViewer>
#include <osgViewer/ViewerEventHandlers>
#include <osg/LightModel>
#include <osg/Version>
#include <components/resource/scenemanager.hpp>
#include <components/resource/resourcesystem.hpp>
@ -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);

@ -23,7 +23,7 @@ add_openmw_dir (mwrender
actors objects renderingmanager animation rotatecontroller sky npcanimation vismask
creatureanimation effectmanager util renderinginterface pathgrid rendermode weaponanimation
bulletdebugdraw globalmap characterpreview camera localmap water terrainstorage ripplesimulation
renderbin
renderbin actoranimation
)
add_openmw_dir (mwinput
@ -145,14 +145,15 @@ target_link_libraries(tes3mp
if (ANDROID)
set (OSG_PLUGINS
-Wl,--whole-archive
${OSG_PLUGINS_DIR}/libosgdb_dds.a
${OSG_PLUGINS_DIR}/libosgdb_bmp.a
${OSG_PLUGINS_DIR}/libosgdb_tga.a
${OSG_PLUGINS_DIR}/libosgdb_gif.a
${OSG_PLUGINS_DIR}/libosgdb_jpeg.a
${OSG_PLUGINS_DIR}/libosgdb_png.a
-Wl,--no-whole-archive
)
foreach(PLUGIN_NAME ${USED_OSG_PLUGINS})
set(OSG_PLUGINS ${OSG_PLUGINS} ${OSG_PLUGINS_DIR}/lib${PLUGIN_NAME}.a)
endforeach()
set (OSG_PLUGINS
${OSG_PLUGINS} -Wl,--no-whole-archive
)
target_link_libraries(tes3mp
EGL
android

@ -448,6 +448,11 @@ namespace MWDialogue
{
MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Dialogue);
// Clamp permanent disposition change so that final disposition doesn't go below 0 (could happen with intimidate)
float curDisp = static_cast<float>(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())
{

@ -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<int> (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<int> (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<ESM::NPC>()->mBase->mFlags & ESM::NPC::Female)==

@ -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;

@ -39,9 +39,9 @@ void test(const MWWorld::Ptr& actor, int &compiled, int &total, const Compiler::
{
std::vector<const ESM::DialInfo*> infos = filter.listAll(*it);
for (std::vector<const ESM::DialInfo*>::iterator it = infos.begin(); it != infos.end(); ++it)
for (std::vector<const ESM::DialInfo*>::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;

@ -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
};

@ -225,7 +225,7 @@ namespace MWGui
mSpellItems.push_back(label);
coord.top += lineHeight;
std::vector<std::string>::const_iterator end = categories[category].spells.end();
end = categories[category].spells.end();
for (std::vector<std::string>::const_iterator it = categories[category].spells.begin(); it != end; ++it)
{
const std::string &spellId = *it;

@ -28,6 +28,7 @@ namespace MWGui
ItemWidget::ItemWidget()
: mItem(NULL)
, mItemShadow(NULL)
, mFrame(NULL)
, mText(NULL)
{
@ -44,6 +45,9 @@ namespace MWGui
assignWidget(mItem, "Item");
if (mItem)
mItem->setNeedMouseFocus(false);
assignWidget(mItemShadow, "ItemShadow");
if (mItemShadow)
mItemShadow->setNeedMouseFocus(false);
assignWidget(mFrame, "Frame");
if (mFrame)
mFrame->setNeedMouseFocus(false);
@ -63,6 +67,8 @@ namespace MWGui
void ItemWidget::setIcon(const std::string &icon)
{
if (mItemShadow)
mItemShadow->setImageTexture(icon);
if (mItem)
mItem->setImageTexture(icon);
}
@ -79,7 +85,10 @@ namespace MWGui
void ItemWidget::setIcon(const MWWorld::Ptr &ptr)
{
setIcon(MWBase::Environment::get().getWindowManager()->correctIconPath(ptr.getClass().getInventoryIcon(ptr)));
std::string invIcon = ptr.getClass().getInventoryIcon(ptr);
if (invIcon.empty())
invIcon = "default icon.tga";
setIcon(MWBase::Environment::get().getWindowManager()->correctIconPath(invIcon));
}

@ -44,6 +44,7 @@ namespace MWGui
virtual void initialiseOverride();
MyGUI::ImageBox* mItem;
MyGUI::ImageBox* mItemShadow;
MyGUI::ImageBox* mFrame;
MyGUI::TextBox* mText;
};

@ -559,8 +559,8 @@ namespace MWGui
std::vector<std::string> 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;

@ -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;
}
}
}

@ -362,10 +362,10 @@ namespace MWGui
std::sort(items.begin(), items.end(), sortRaces);
int index = 0;
for (std::vector<std::pair<std::string, std::string> >::const_iterator it = items.begin(); it != items.end(); ++it)
for (std::vector<std::pair<std::string, std::string> >::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;
}

@ -1046,8 +1046,9 @@ namespace MWMechanics
if (!iter->first.getClass().getCreatureStats(iter->first).isDead())
{
MWWorld::Ptr actor = iter->first; // make a copy of the map key to avoid it being invalidated when the player teleports
bool cellChanged = MWBase::Environment::get().getWorld()->hasCellChanged();
updateActor(actor, duration);
if (MWBase::Environment::get().getWorld()->hasCellChanged())
if (!cellChanged && MWBase::Environment::get().getWorld()->hasCellChanged())
{
return; // for now abort update of the old cell when cell changes by teleportation magic effect
// a better solution might be to apply cell changes at the end of the frame

@ -91,8 +91,8 @@ std::list<AiPackage*>::const_iterator AiSequence::erase(std::list<AiPackage*>::c
{
if (package == it)
{
AiPackage* package = *it;
delete package;
AiPackage* packagePtr = *it;
delete packagePtr;
return mPackages.erase(it);
}
}

@ -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;

@ -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<ESM::Weapon> *ref = weapon->get<ESM::Weapon>();
ESM::Weapon::Type type = (ESM::Weapon::Type)ref->mBase->mData.mType;
switch(type)
ESM::Weapon::Type weaponType = (ESM::Weapon::Type)ref->mBase->mData.mType;
switch(weaponType)
{
case ESM::Weapon::ShortBladeOneHand:
case ESM::Weapon::LongBladeOneHand:
@ -1745,14 +1745,12 @@ void CharacterController::update(float duration)
cls.skillUsageSucceeded(mPtr, ESM::Skill::Acrobatics, 0);
// decrease fatigue
const MWWorld::Store<ESM::GameSetting> &gmst = world->getStore().get<ESM::GameSetting>();
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<float> fatigue = cls.getCreatureStats(mPtr).getFatigue();
fatigue.setCurrent(fatigue.getCurrent() - fatigueDecrease);
cls.getCreatureStats(mPtr).setFatigue(fatigue);
}

@ -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<ESM::Faction>().find(lower);
if (it->second+1 < 10 && !faction->mRanks[it->second+1].empty())
const ESM::Faction* factionPtr = MWBase::Environment::get().getWorld()->getStore().get<ESM::Faction>().find(lower);
if (it->second+1 < 10 && !factionPtr->mRanks[it->second+1].empty())
it->second += 1;
}
}

@ -482,7 +482,10 @@ namespace MWMechanics
ActiveSpells::ActiveEffect effect;
effect.mEffectId = effectIt->mEffectID;
effect.mArg = MWMechanics::EffectKey(*effectIt).mArg;
effect.mDuration = static_cast<float>(effectIt->mDuration);
if (!hasDuration)
effect.mDuration = 1.0f;
else
effect.mDuration = static_cast<float>(effectIt->mDuration);
effect.mMagnitude = magnitude;
targetEffects.add(MWMechanics::EffectKey(*effectIt), MWMechanics::EffectParam(effect.mMagnitude));
@ -497,13 +500,13 @@ namespace MWMechanics
{
if (effectIt->mEffectID == ESM::MagicEffect::AbsorbAttribute+i)
{
std::vector<ActiveSpells::ActiveEffect> effects;
std::vector<ActiveSpells::ActiveEffect> absorbEffects;
ActiveSpells::ActiveEffect effect_ = effect;
effect_.mMagnitude *= -1;
effects.push_back(effect_);
absorbEffects.push_back(effect_);
// Also make sure to set casterActorId = target, so that the effect on the caster gets purged when the target dies
caster.getClass().getCreatureStats(caster).getActiveSpells().addSpell("", true,
effects, mSourceName, target.getClass().getCreatureStats(target).getActorId());
absorbEffects, mSourceName, target.getClass().getCreatureStats(target).getActorId());
}
}
}
@ -514,11 +517,11 @@ namespace MWMechanics
if (isSummoningEffect(effectIt->mEffectID) && !target.isEmpty() && target.getClass().isActor())
{
CreatureStats& targetStats = target.getClass().getCreatureStats(target);
std::map<CreatureStats::SummonKey, int>::iterator found = targetStats.getSummonedCreatureMap().find(std::make_pair(effectIt->mEffectID, mId));
if (found != targetStats.getSummonedCreatureMap().end())
std::map<CreatureStats::SummonKey, int>::iterator findCreature = targetStats.getSummonedCreatureMap().find(std::make_pair(effectIt->mEffectID, mId));
if (findCreature != targetStats.getSummonedCreatureMap().end())
{
MWBase::Environment::get().getMechanicsManager()->cleanupSummonedCreature(target, found->second);
targetStats.getSummonedCreatureMap().erase(found);
MWBase::Environment::get().getMechanicsManager()->cleanupSummonedCreature(target, findCreature->second);
targetStats.getSummonedCreatureMap().erase(findCreature);
}
}
@ -612,36 +615,8 @@ namespace MWMechanics
return true;
}
}
else if (target.getClass().isActor())
else if (target.getClass().isActor() && target == getPlayer())
{
switch (effectId)
{
case ESM::MagicEffect::CurePoison:
target.getClass().getCreatureStats(target).getActiveSpells().purgeEffect(ESM::MagicEffect::Poison);
return true;
case ESM::MagicEffect::CureParalyzation:
target.getClass().getCreatureStats(target).getActiveSpells().purgeEffect(ESM::MagicEffect::Paralyze);
return true;
case ESM::MagicEffect::CureCommonDisease:
target.getClass().getCreatureStats(target).getSpells().purgeCommonDisease();
return true;
case ESM::MagicEffect::CureBlightDisease:
target.getClass().getCreatureStats(target).getSpells().purgeBlightDisease();
return true;
case ESM::MagicEffect::CureCorprusDisease:
target.getClass().getCreatureStats(target).getSpells().purgeCorprusDisease();
return true;
case ESM::MagicEffect::Dispel:
target.getClass().getCreatureStats(target).getActiveSpells().purgeAll(magnitude);
return true;
case ESM::MagicEffect::RemoveCurse:
target.getClass().getCreatureStats(target).getSpells().purgeCurses();
return true;
}
if (target != getPlayer())
return false;
MWRender::Animation* anim = MWBase::Environment::get().getWorld()->getAnimation(mCaster);
if (effectId == ESM::MagicEffect::DivineIntervention)
@ -664,7 +639,6 @@ namespace MWMechanics
anim->addEffect("meshes\\" + fx->mModel, -1);
return true;
}
else if (effectId == ESM::MagicEffect::Mark)
{
MWBase::Environment::get().getWorld()->getPlayer().markPosition(
@ -1176,6 +1150,27 @@ namespace MWMechanics
break;
}
case ESM::MagicEffect::CurePoison:
actor.getClass().getCreatureStats(actor).getActiveSpells().purgeEffect(ESM::MagicEffect::Poison);
break;
case ESM::MagicEffect::CureParalyzation:
actor.getClass().getCreatureStats(actor).getActiveSpells().purgeEffect(ESM::MagicEffect::Paralyze);
break;
case ESM::MagicEffect::CureCommonDisease:
actor.getClass().getCreatureStats(actor).getSpells().purgeCommonDisease();
break;
case ESM::MagicEffect::CureBlightDisease:
actor.getClass().getCreatureStats(actor).getSpells().purgeBlightDisease();
break;
case ESM::MagicEffect::CureCorprusDisease:
actor.getClass().getCreatureStats(actor).getSpells().purgeCorprusDisease();
break;
case ESM::MagicEffect::Dispel:
actor.getClass().getCreatureStats(actor).getActiveSpells().purgeAll(magnitude);
break;
case ESM::MagicEffect::RemoveCurse:
actor.getClass().getCreatureStats(actor).getSpells().purgeCurses();
break;
}
if (receivedMagicDamage && actor == getPlayer())

@ -0,0 +1,131 @@
#include "actoranimation.hpp"
#include <utility>
#include <osg/Node>
#include <osg/Group>
#include <osg/Vec4f>
#include <components/esm/loadligh.hpp>
#include <components/esm/loadcell.hpp>
#include <components/sceneutil/lightmanager.hpp>
#include <components/sceneutil/lightutil.hpp>
#include <components/fallback/fallback.hpp>
#include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"
#include "../mwworld/ptr.hpp"
#include "../mwworld/class.hpp"
#include "../mwworld/cellstore.hpp"
#include "../mwmechanics/actorutil.hpp"
#include "vismask.hpp"
namespace MWRender
{
ActorAnimation::ActorAnimation(const MWWorld::Ptr& ptr, osg::ref_ptr<osg::Group> 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<ESM::Light>()->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<ESM::Light>()->mBase;
if (!(light->mData.mFlags & ESM::Light::Carry))
{
addHiddenItemLight(item, light);
}
}
}
void ActorAnimation::itemRemoved(const MWWorld::ConstPtr& item, int /*count*/)
{
if (item.getTypeName() == typeid(ESM::Light).name())
{
ItemLightMap::iterator iter = mItemLights.find(item);
if (iter != mItemLights.end())
{
if (!item.getRefData().getCount())
{
removeHiddenItemLight(item);
}
}
}
}
void ActorAnimation::addHiddenItemLight(const MWWorld::ConstPtr& item, const ESM::Light* esmLight)
{
if (mItemLights.find(item) != mItemLights.end())
return;
const Fallback::Map* fallback = MWBase::Environment::get().getWorld()->getFallback();
static bool outQuadInLin = fallback->getFallbackBool("LightAttenuation_OutQuadInLin");
static bool useQuadratic = fallback->getFallbackBool("LightAttenuation_UseQuadratic");
static float quadraticValue = fallback->getFallbackFloat("LightAttenuation_QuadraticValue");
static float quadraticRadiusMult = fallback->getFallbackFloat("LightAttenuation_QuadraticRadiusMult");
static bool useLinear = fallback->getFallbackBool("LightAttenuation_UseLinear");
static float linearRadiusMult = fallback->getFallbackFloat("LightAttenuation_LinearRadiusMult");
static float linearValue = fallback->getFallbackFloat("LightAttenuation_LinearValue");
bool exterior = mPtr.isInCell() && mPtr.getCell()->getCell()->isExterior();
osg::Vec4f ambient(1,1,1,1);
osg::ref_ptr<SceneUtil::LightSource> lightSource = SceneUtil::createLightSource(esmLight, Mask_Lighting, exterior, outQuadInLin,
useQuadratic, quadraticValue, quadraticRadiusMult, useLinear, linearRadiusMult, linearValue, ambient);
mInsert->addChild(lightSource);
if (mLightListCallback && mPtr == MWMechanics::getPlayer())
mLightListCallback->getIgnoredLightSources().insert(lightSource.get());
mItemLights.insert(std::make_pair(item, lightSource));
}
void ActorAnimation::removeHiddenItemLight(const MWWorld::ConstPtr& item)
{
ItemLightMap::iterator iter = mItemLights.find(item);
if (iter == mItemLights.end())
return;
if (mLightListCallback && mPtr == MWMechanics::getPlayer())
{
std::set<SceneUtil::LightSource*>::iterator ignoredIter = mLightListCallback->getIgnoredLightSources().find(iter->second.get());
if (ignoredIter != mLightListCallback->getIgnoredLightSources().end())
mLightListCallback->getIgnoredLightSources().erase(ignoredIter);
}
mInsert->removeChild(iter->second);
mItemLights.erase(iter);
}
}

@ -0,0 +1,53 @@
#ifndef GAME_RENDER_ACTORANIMATION_H
#define GAME_RENDER_ACTORANIMATION_H
#include <map>
#include <osg/ref_ptr>
#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<osg::Group> parentNode, Resource::ResourceSystem* resourceSystem,
bool disableListener=false);
virtual ~ActorAnimation();
virtual void itemAdded(const MWWorld::ConstPtr& item, int count);
virtual void itemRemoved(const MWWorld::ConstPtr& item, int count);
private:
void addHiddenItemLight(const MWWorld::ConstPtr& item, const ESM::Light* esmLight);
void removeHiddenItemLight(const MWWorld::ConstPtr& item);
typedef std::map<MWWorld::ConstPtr, osg::ref_ptr<SceneUtil::LightSource> > ItemLightMap;
ItemLightMap mItemLights;
bool mListenerDisabled;
};
}
#endif

@ -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<osg::StateSet> previousStateset;
if (mObjectRoot)
{
if (mLightListCallback)
mObjectRoot->removeCullCallback(mLightListCallback);
previousStateset = mObjectRoot->getStateSet();
mObjectRoot->getParent(0)->removeChild(mObjectRoot);
}
@ -1150,7 +1154,9 @@ namespace MWRender
removeTriBipVisitor.remove();
}
mObjectRoot->addCullCallback(new SceneUtil::LightListCallback);
if (!mLightListCallback)
mLightListCallback = new SceneUtil::LightListCallback;
mObjectRoot->addCullCallback(mLightListCallback);
}
osg::Group* Animation::getObjectRoot()

@ -25,6 +25,7 @@ namespace NifOsg
namespace SceneUtil
{
class LightSource;
class LightListCallback;
class Skeleton;
}
@ -273,6 +274,8 @@ protected:
float mAlpha;
osg::ref_ptr<SceneUtil::LightListCallback> mLightListCallback;
const NodeMap& getNodeMap() const;
/* Sets the appropriate animations on the bone groups based on priority.

@ -18,7 +18,7 @@ namespace MWRender
CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr,
const std::string& model, Resource::ResourceSystem* resourceSystem)
: Animation(ptr, osg::ref_ptr<osg::Group>(ptr.getRefData().getBaseNode()), resourceSystem)
: ActorAnimation(ptr, osg::ref_ptr<osg::Group>(ptr.getRefData().getBaseNode()), resourceSystem)
{
MWWorld::LiveCellRef<ESM::Creature> *ref = mPtr.get<ESM::Creature>();
@ -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<osg::Group>(ptr.getRefData().getBaseNode()), resourceSystem)
: ActorAnimation(ptr, osg::ref_ptr<osg::Group>(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();
}

@ -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);

@ -16,6 +16,7 @@
#include <components/sceneutil/attach.hpp>
#include <components/sceneutil/visitor.hpp>
#include <components/sceneutil/skeleton.hpp>
#include <components/sceneutil/lightmanager.hpp>
#include <components/nifosg/nifloader.hpp> // 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<osg::Group> 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<osg::Group> par
updateNpcBase();
if (!disableListener)
mPtr.getClass().getInventoryStore(mPtr).setListener(this, mPtr);
mPtr.getClass().getInventoryStore(mPtr).setInvListener(this, mPtr);
}
void NpcAnimation::setViewMode(NpcAnimation::ViewMode viewMode)

@ -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();

@ -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);

@ -3,12 +3,16 @@
#include <iostream>
#include <vector>
#include <memory>
#include <cstring>
#include <stdint.h>
#include <components/vfs/manager.hpp>
#include <boost/thread.hpp>
#include <OpenThreads/Thread>
#include <OpenThreads/Condition>
#include <OpenThreads/Mutex>
#include <OpenThreads/ScopedLock>
#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<OpenAL_SoundStream*> 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<boost::mutex> lock(mMutex);
OpenThreads::ScopedLock<OpenThreads::Mutex> 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<boost::mutex> lock(mMutex);
OpenThreads::ScopedLock<OpenThreads::Mutex> 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<boost::mutex> lock(mMutex);
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(mMutex);
StreamVec::iterator iter = std::find(mStreams.begin(), mStreams.end(), stream);
if(iter != mStreams.end()) mStreams.erase(iter);
}
void removeAll()
{
boost::lock_guard<boost::mutex> lock(mMutex);
OpenThreads::ScopedLock<OpenThreads::Mutex> 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<OpenAL_SoundStream*>(sound->mHandle);
boost::lock_guard<boost::mutex> lock(mStreamThread->mMutex);
OpenThreads::ScopedLock<OpenThreads::Mutex> 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<OpenAL_SoundStream*>(sound->mHandle);
boost::lock_guard<boost::mutex> lock(mStreamThread->mMutex);
OpenThreads::ScopedLock<OpenThreads::Mutex> 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<OpenAL_SoundStream*>(sound->mHandle);
boost::lock_guard<boost::mutex> lock(mStreamThread->mMutex);
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(mStreamThread->mMutex);
return stream->isPlaying();
}

@ -113,7 +113,7 @@ void MWWorld::ContainerStore::storeStates (const CellRefList<T>& collection,
const std::string MWWorld::ContainerStore::sGoldId = "gold_001";
MWWorld::ContainerStore::ContainerStore() : mCachedWeight (0), mWeightUpToDate (false) {}
MWWorld::ContainerStore::ContainerStore() : mListener(NULL), mCachedWeight (0), mWeightUpToDate (false) {}
MWWorld::ContainerStore::~ContainerStore() {}
@ -136,6 +136,17 @@ int MWWorld::ContainerStore::count(const std::string &id)
return total;
}
MWWorld::ContainerStoreListener* MWWorld::ContainerStore::getContListener() const
{
return mListener;
}
void MWWorld::ContainerStore::setContListener(MWWorld::ContainerStoreListener* listener)
{
mListener = listener;
}
MWWorld::ContainerStoreIterator MWWorld::ContainerStore::unstack(const Ptr &ptr, const Ptr& container, int count)
{
if (ptr.getRefData().getCount() <= count)
@ -292,6 +303,9 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add (const Ptr& itemPtr
item.getRefData().getLocals().setVarByInt(script, "onpcadd", 1);
}
if (mListener)
mListener->itemAdded(item, count);
return it;
}
@ -398,6 +412,9 @@ int MWWorld::ContainerStore::remove(const Ptr& item, int count, const Ptr& actor
flagAsModified();
if (mListener)
mListener->itemRemoved(item, count - toRemove);
// number of removed items
return count - toRemove;
}
@ -423,12 +440,12 @@ void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std::
if (ref.getPtr().getTypeName()==typeid (ESM::ItemLevList).name())
{
const ESM::ItemLevList* levItem = ref.getPtr().get<ESM::ItemLevList>()->mBase;
const ESM::ItemLevList* levItemList = ref.getPtr().get<ESM::ItemLevList>()->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<std::abs(count); ++i)
addInitialItem(id, owner, count > 0 ? 1 : -1, true, levItem->mId);
addInitialItem(id, owner, count > 0 ? 1 : -1, true, levItemList->mId);
return;
}
else
@ -436,7 +453,7 @@ void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std::
std::string id = MWMechanics::getLevelledItem(ref.getPtr().get<ESM::ItemLevList>()->mBase, false);
if (id.empty())
return;
addInitialItem(id, owner, count, false, levItem->mId);
addInitialItem(id, owner, count, false, levItemList->mId);
}
}
else

@ -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)

@ -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);

@ -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);

@ -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();

@ -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);

@ -22,7 +22,7 @@ struct Apparatus
enum AppaType
{
MortarPestle = 0,
Albemic = 1,
Alembic = 1,
Calcinator = 2,
Retort = 3
};

@ -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];

@ -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

@ -359,6 +359,10 @@ namespace SceneUtil
for (unsigned int i=0; i<lights.size(); ++i)
{
const LightManager::LightSourceViewBound& l = lights[i];
if (mIgnoredLightSources.count(l.mLightSource))
continue;
if (l.mViewBound.intersects(nodeBound))
mLightList.push_back(&l);
}

@ -1,6 +1,8 @@
#ifndef OPENMW_COMPONENTS_SCENEUTIL_LIGHTMANAGER_H
#define OPENMW_COMPONENTS_SCENEUTIL_LIGHTMANAGER_H
#include <set>
#include <osg/Light>
#include <osg/Group>
@ -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<SceneUtil::LightSource*>& getIgnoredLightSources() { return mIgnoredLightSources; }
private:
LightManager* mLightManager;
unsigned int mLastFrameNumber;
LightManager::LightList mLightList;
std::set<SceneUtil::LightSource*> mIgnoredLightSources;
};
}

@ -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> lightSource = createLightSource(esmLight, lightMask, isExterior, outQuadInLin, useQuadratic, quadraticValue,
quadraticRadiusMult, useLinear, linearRadiusMult, linearValue);
attachTo->addChild(lightSource);
}
osg::ref_ptr<LightSource> 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<SceneUtil::LightSource> lightSource (new SceneUtil::LightSource);
osg::ref_ptr<osg::Light> 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;
}
}

@ -1,6 +1,9 @@
#ifndef OPENMW_COMPONENTS_LIGHTUTIL_H
#define OPENMW_COMPONENTS_LIGHTUTIL_H
#include <osg/ref_ptr>
#include <osg/Vec4f>
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<LightSource> 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

@ -1,5 +1,6 @@
#include "audiodecoder.hpp"
#include <stdexcept>
extern "C"
{

@ -1,6 +1,7 @@
#include "videostate.hpp"
#include <iostream>
#include <stdexcept>
#include <osg/Texture2D>
@ -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<boost::mutex> lock(this->mutex);
OpenThreads::ScopedLock<OpenThreads::Mutex> 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<OpenThreads::Mutex> 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<boost::mutex> lock(this->pictq_mutex);
OpenThreads::ScopedLock<OpenThreads::Mutex> 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<int64_t>(self->frame_last_pts);
continue;
}
self->frame_last_pts = packet->pts * av_q2d((*self->video_st)->time_base);
global_video_pkt_pts = static_cast<int64_t>(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<double>(packet->dts);
else if(pFrame->opaque && *(int64_t*)pFrame->opaque != AV_NOPTS_VALUE)
pts = static_cast<double>(*(int64_t*)pFrame->opaque);
pts *= av_q2d((*self->video_st)->time_base);
double pts = 0;
if(packet->dts != AV_NOPTS_VALUE)
pts = static_cast<double>(packet->dts);
else if(pFrame->opaque && *(int64_t*)pFrame->opaque != AV_NOPTS_VALUE)
pts = static_cast<double>(*(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<std::istream> 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<OpenThreads::Mutex> 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<OpenThreads::Mutex> 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<OpenThreads::Mutex> lock(mMutex);
mTimeBase = av_gettime() - time;
mPausedAt = time;
}

@ -2,8 +2,14 @@
#define VIDEOPLAYER_VIDEOSTATE_H
#include <stdint.h>
#include <vector>
#include <memory>
#include <boost/thread.hpp>
#include <boost/shared_ptr.hpp>
#include <OpenThreads/Thread>
#include <OpenThreads/Mutex>
#include <OpenThreads/Condition>
#include <osg/ref_ptr>
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<ParseThread> parse_thread;
std::auto_ptr<VideoThread> video_thread;
volatile bool mSeekRequested;
uint64_t mSeekPos;

@ -120,6 +120,10 @@
<Property key="TextShadow" value="true"/>
</Widget>
<Widget type="ImageBox" skin="ImageBox" position="5 5 32 32" align="Stretch" name="Item"/>
<Widget type="ImageBox" skin="ImageBox" position="9 9 32 32" align="Stretch" name="ItemShadow">
<Property key="Colour" value="0 0 0"/>
<Property key="Alpha" value="0.5"/>
</Widget>
</Widget>
</Widget>
</Resource>
@ -128,6 +132,10 @@
<Widget type="Widget" skin="" position="0 0 32 32" name="Root">
<Widget type="ImageBox" skin="ImageBox" position="0 0 32 32" align="Stretch" name="Frame">
<Widget type="ImageBox" skin="ImageBox" position="0 0 32 32" align="Stretch" name="Item"/>
<Widget type="ImageBox" skin="ImageBox" position="4 4 32 32" align="Stretch" name="ItemShadow">
<Property key="Colour" value="0 0 0"/>
<Property key="Alpha" value="0.5"/>
</Widget>
</Widget>
</Widget>
</Resource>
@ -140,6 +148,10 @@
<Property key="TextShadow" value="true"/>
</Widget>
<Widget type="ImageBox" skin="ImageBox" position="5 5 32 32" align="Center" name="Item"/>
<Widget type="ImageBox" skin="ImageBox" position="9 9 32 32" align="Stretch" name="ItemShadow">
<Property key="Colour" value="0 0 0"/>
<Property key="Alpha" value="0.5"/>
</Widget>
</Widget>
<Widget type="Widget" skin="MW_Box_Overlay" position="0 0 50 50" align="Stretch"/>

Loading…
Cancel
Save