Resolve conflicts in pull request #75

# Conflicts:
#	CMakeLists.txt
#	apps/openmw/CMakeLists.txt
pull/78/head
David Cernat 8 years ago
commit 3136a12051

@ -217,27 +217,28 @@ if(NOT HAVE_STDINT_H)
endif() 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) IF(BUILD_OPENMW OR BUILD_OPENCS)
find_package(OpenSceneGraph 3.3.4 REQUIRED osgDB osgViewer osgText osgGA osgAnimation osgParticle osgUtil osgFX) find_package(OpenSceneGraph 3.3.4 REQUIRED osgDB osgViewer osgText osgGA osgAnimation osgParticle osgUtil osgFX)
include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS}) 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) get_filename_component(OSG_LIB_DIR ${OSGDB_LIBRARY} DIRECTORY)
set(OSGPlugins_LIB_DIR "${OSG_LIB_DIR}/osgPlugins-${OPENSCENEGRAPH_VERSION}") set(OSGPlugins_LIB_DIR "${OSG_LIB_DIR}/osgPlugins-${OPENSCENEGRAPH_VERSION}")
if(OSG_STATIC) if(OSG_STATIC)
add_definitions(-DOSG_LIBRARY_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}) list(APPEND OPENSCENEGRAPH_LIBRARIES ${OSGPlugins_LIBRARIES})
endif() endif()
@ -258,6 +259,16 @@ IF(BUILD_OPENMW OR BUILD_OPENCS)
ENDIF(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}) find_package(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS})
include_directories("." include_directories("."
@ -769,12 +780,6 @@ if (APPLE)
" COMPONENT Runtime) " COMPONENT Runtime)
set(ABSOLUTE_PLUGINS "") set(ABSOLUTE_PLUGINS "")
set(USED_OSG_PLUGINS
osgdb_dds
osgdb_jpeg
osgdb_png
osgdb_tga
)
foreach (PLUGIN_NAME ${USED_OSG_PLUGINS}) foreach (PLUGIN_NAME ${USED_OSG_PLUGINS})
set(PLUGIN_ABS "${OSGPlugins_LIB_DIR}/${PLUGIN_NAME}.so") 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); verifyCell(topicInfo.mCell, id, messages);
} }
if (!topicInfo.mFaction.empty()) if (!topicInfo.mFaction.empty() && !topicInfo.mFactionLess)
{ {
if (verifyId(topicInfo.mFaction, mFactions, id, messages)) if (verifyId(topicInfo.mFaction, mFactions, id, messages))
{ {

@ -371,7 +371,6 @@ void CSMWorld::ConstInfoSelectWrapper::updateComparisonType()
case Function_NotClass: case Function_NotClass:
case Function_NotRace: case Function_NotRace:
case Function_NotCell: case Function_NotCell:
case Function_NotLocal:
case Function_PcExpelled: case Function_PcExpelled:
case Function_PcCommonDisease: case Function_PcCommonDisease:
case Function_PcBlightDisease: case Function_PcBlightDisease:
@ -454,6 +453,7 @@ void CSMWorld::ConstInfoSelectWrapper::updateComparisonType()
// Numeric // Numeric
case Function_Global: case Function_Global:
case Function_Local: case Function_Local:
case Function_NotLocal:
case Function_Health_Percent: case Function_Health_Percent:
case Function_PcHealthPercent: case Function_PcHealthPercent:
@ -560,7 +560,6 @@ std::pair<int, int> CSMWorld::ConstInfoSelectWrapper::getValidIntRange() const
case Function_NotClass: case Function_NotClass:
case Function_NotRace: case Function_NotRace:
case Function_NotCell: case Function_NotCell:
case Function_NotLocal:
case Function_PcExpelled: case Function_PcExpelled:
case Function_PcCommonDisease: case Function_PcCommonDisease:
case Function_PcBlightDisease: case Function_PcBlightDisease:
@ -657,6 +656,7 @@ std::pair<int, int> CSMWorld::ConstInfoSelectWrapper::getValidIntRange() const
// Numeric // Numeric
case Function_Global: case Function_Global:
case Function_Local: case Function_Local:
case Function_NotLocal:
return std::pair<int, int>(IntMin, IntMax); return std::pair<int, int>(IntMin, IntMax);
case Function_PcMagicka: case Function_PcMagicka:

@ -10,6 +10,7 @@
#include <osgViewer/CompositeViewer> #include <osgViewer/CompositeViewer>
#include <osgViewer/ViewerEventHandlers> #include <osgViewer/ViewerEventHandlers>
#include <osg/LightModel> #include <osg/LightModel>
#include <osg/Version>
#include <components/resource/scenemanager.hpp> #include <components/resource/scenemanager.hpp>
#include <components/resource/resourcesystem.hpp> #include <components/resource/resourcesystem.hpp>
@ -130,6 +131,10 @@ CompositeViewer::CompositeViewer()
setThreadingModel(threadingModel); setThreadingModel(threadingModel);
#if OSG_VERSION_GREATER_OR_EQUAL(3,5,5)
setUseConfigureAffinity(false);
#endif
// disable the default setting of viewer.done() by pressing Escape. // disable the default setting of viewer.done() by pressing Escape.
setKeyEventSetsDone(0); setKeyEventSetsDone(0);

@ -23,7 +23,7 @@ add_openmw_dir (mwrender
actors objects renderingmanager animation rotatecontroller sky npcanimation vismask actors objects renderingmanager animation rotatecontroller sky npcanimation vismask
creatureanimation effectmanager util renderinginterface pathgrid rendermode weaponanimation creatureanimation effectmanager util renderinginterface pathgrid rendermode weaponanimation
bulletdebugdraw globalmap characterpreview camera localmap water terrainstorage ripplesimulation bulletdebugdraw globalmap characterpreview camera localmap water terrainstorage ripplesimulation
renderbin renderbin actoranimation
) )
add_openmw_dir (mwinput add_openmw_dir (mwinput
@ -145,14 +145,15 @@ target_link_libraries(tes3mp
if (ANDROID) if (ANDROID)
set (OSG_PLUGINS set (OSG_PLUGINS
-Wl,--whole-archive -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 target_link_libraries(tes3mp
EGL EGL
android android

@ -448,6 +448,11 @@ namespace MWDialogue
{ {
MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Dialogue); 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 // Apply disposition change to NPC's base disposition
if (mActor.getClass().isNpc()) if (mActor.getClass().isNpc())
{ {

@ -159,6 +159,39 @@ bool MWDialogue::Filter::testDisposition (const ESM::DialInfo& info, bool invert
: (actorDisposition >= info.mData.mDisposition); : (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 bool MWDialogue::Filter::testSelectStruct (const SelectWrapper& select) const
{ {
if (select.isNpcOnly() && (mActor.getTypeName() != typeid (ESM::NPC).name())) 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: case SelectWrapper::Function_Local:
{ {
std::string scriptName = mActor.getClass().getScript (mActor); return testFunctionLocal(select);
}
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"); case SelectWrapper::Function_NotLocal:
{
return !testFunctionLocal(select);
} }
case SelectWrapper::Function_PcHealthPercent: 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()) return !Misc::StringUtils::ciEqual(MWBase::Environment::get().getWorld()->getCellName(mActor.getCell())
, select.getName()); , 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: case SelectWrapper::Function_SameGender:
return (player.get<ESM::NPC>()->mBase->mFlags & ESM::NPC::Female)== 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; 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)? ///< 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 testSelectStruct (const SelectWrapper& select) const;
bool testSelectStructNumeric (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); 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()) if (!info->mResultScript.empty())
{ {
bool success = true; bool success = true;

@ -210,7 +210,7 @@ MWDialogue::SelectWrapper::Type MWDialogue::SelectWrapper::getType() const
static const Function numericFunctions[] = static const Function numericFunctions[] =
{ {
Function_Global, Function_Local, Function_Global, Function_Local, Function_NotLocal,
Function_PcDynamicStat, Function_PcHealthPercent, Function_PcDynamicStat, Function_PcHealthPercent,
Function_HealthPercent, Function_HealthPercent,
Function_None // end marker Function_None // end marker
@ -232,7 +232,7 @@ MWDialogue::SelectWrapper::Type MWDialogue::SelectWrapper::getType() const
static const Function invertedBooleanFunctions[] = static const Function invertedBooleanFunctions[] =
{ {
Function_NotId, Function_NotFaction, Function_NotClass, Function_NotId, Function_NotFaction, Function_NotClass,
Function_NotRace, Function_NotCell, Function_NotLocal, Function_NotRace, Function_NotCell,
Function_None // end marker Function_None // end marker
}; };

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

@ -28,6 +28,7 @@ namespace MWGui
ItemWidget::ItemWidget() ItemWidget::ItemWidget()
: mItem(NULL) : mItem(NULL)
, mItemShadow(NULL)
, mFrame(NULL) , mFrame(NULL)
, mText(NULL) , mText(NULL)
{ {
@ -44,6 +45,9 @@ namespace MWGui
assignWidget(mItem, "Item"); assignWidget(mItem, "Item");
if (mItem) if (mItem)
mItem->setNeedMouseFocus(false); mItem->setNeedMouseFocus(false);
assignWidget(mItemShadow, "ItemShadow");
if (mItemShadow)
mItemShadow->setNeedMouseFocus(false);
assignWidget(mFrame, "Frame"); assignWidget(mFrame, "Frame");
if (mFrame) if (mFrame)
mFrame->setNeedMouseFocus(false); mFrame->setNeedMouseFocus(false);
@ -63,6 +67,8 @@ namespace MWGui
void ItemWidget::setIcon(const std::string &icon) void ItemWidget::setIcon(const std::string &icon)
{ {
if (mItemShadow)
mItemShadow->setImageTexture(icon);
if (mItem) if (mItem)
mItem->setImageTexture(icon); mItem->setImageTexture(icon);
} }
@ -79,7 +85,10 @@ namespace MWGui
void ItemWidget::setIcon(const MWWorld::Ptr &ptr) 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(); virtual void initialiseOverride();
MyGUI::ImageBox* mItem; MyGUI::ImageBox* mItem;
MyGUI::ImageBox* mItemShadow;
MyGUI::ImageBox* mFrame; MyGUI::ImageBox* mFrame;
MyGUI::TextBox* mText; MyGUI::TextBox* mText;
}; };

@ -559,8 +559,8 @@ namespace MWGui
std::vector<std::string> destNotes; std::vector<std::string> destNotes;
CustomMarkerCollection::RangeType markers = mCustomMarkers.getMarkers(marker.dest); CustomMarkerCollection::RangeType markers = mCustomMarkers.getMarkers(marker.dest);
for (CustomMarkerCollection::ContainerType::const_iterator it = markers.first; it != markers.second; ++it) for (CustomMarkerCollection::ContainerType::const_iterator iter = markers.first; iter != markers.second; ++iter)
destNotes.push_back(it->second.mNote); destNotes.push_back(iter->second.mNote);
MarkerUserData data (mLocalMapRender); MarkerUserData data (mLocalMapRender);
data.notes = destNotes; data.notes = destNotes;

@ -476,16 +476,16 @@ namespace MWGui
MWWorld::Ptr player = MWMechanics::getPlayer(); MWWorld::Ptr player = MWMechanics::getPlayer();
MWWorld::InventoryStore& store = player.getClass().getInventoryStore(player); MWWorld::InventoryStore& store = player.getClass().getInventoryStore(player);
MWWorld::Ptr item; 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() || if (item.isEmpty() ||
// Prefer the stack with the lowest remaining uses // Prefer the stack with the lowest remaining uses
!item.getClass().hasItemHealth(*it) || !item.getClass().hasItemHealth(*iter) ||
it->getClass().getItemHealth(*it) < item.getClass().getItemHealth(item)) 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); std::sort(items.begin(), items.end(), sortRaces);
int index = 0; 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); mRaceList->addItem(iter->second, iter->first);
if (Misc::StringUtils::ciEqual(it->first, mCurrentRaceId)) if (Misc::StringUtils::ciEqual(iter->first, mCurrentRaceId))
mRaceList->setIndexSelected(index); mRaceList->setIndexSelected(index);
++index; ++index;
} }

@ -1046,8 +1046,9 @@ namespace MWMechanics
if (!iter->first.getClass().getCreatureStats(iter->first).isDead()) 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 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); 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 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 // 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) if (package == it)
{ {
AiPackage* package = *it; AiPackage* packagePtr = *it;
delete package; delete packagePtr;
return mPackages.erase(it); return mPackages.erase(it);
} }
} }

@ -73,7 +73,7 @@ void MWMechanics::Alchemy::applyTools (int flags, float& value) const
bool duration = !(flags & ESM::MagicEffect::NoDuration); bool duration = !(flags & ESM::MagicEffect::NoDuration);
bool negative = (flags & ESM::MagicEffect::Harmful) != 0; 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; int setup = 0;

@ -478,28 +478,28 @@ void CharacterController::refreshIdleAnims(const WeaponInfo* weap, CharacterStat
mIdleState = idle; mIdleState = idle;
size_t numLoops = ~0ul; size_t numLoops = ~0ul;
std::string idle; std::string idleGroup;
MWRender::Animation::AnimPriority idlePriority (Priority_Default); MWRender::Animation::AnimPriority idlePriority (Priority_Default);
// Only play "idleswim" or "idlesneak" if they exist. Otherwise, fallback to // Only play "idleswim" or "idlesneak" if they exist. Otherwise, fallback to
// "idle"+weapon or "idle". // "idle"+weapon or "idle".
if(mIdleState == CharState_IdleSwim && mAnimation->hasAnimation("idleswim")) if(mIdleState == CharState_IdleSwim && mAnimation->hasAnimation("idleswim"))
{ {
idle = "idleswim"; idleGroup = "idleswim";
idlePriority = Priority_SwimIdle; idlePriority = Priority_SwimIdle;
} }
else if(mIdleState == CharState_IdleSneak && mAnimation->hasAnimation("idlesneak")) else if(mIdleState == CharState_IdleSneak && mAnimation->hasAnimation("idlesneak"))
{ {
idle = "idlesneak"; idleGroup = "idlesneak";
idlePriority[MWRender::Animation::BoneGroup_LowerBody] = Priority_SneakIdleLowerBody; idlePriority[MWRender::Animation::BoneGroup_LowerBody] = Priority_SneakIdleLowerBody;
} }
else if(mIdleState != CharState_None) else if(mIdleState != CharState_None)
{ {
idle = "idle"; idleGroup = "idle";
if(weap != sWeaponTypeListEnd) if(weap != sWeaponTypeListEnd)
{ {
idle += weap->shortgroup; idleGroup += weap->shortgroup;
if(!mAnimation->hasAnimation(idle)) if(!mAnimation->hasAnimation(idleGroup))
idle = "idle"; idleGroup = "idle";
// play until the Loop Stop key 2 to 5 times, then play until the Stop key // 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 // 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); mAnimation->disable(mCurrentIdle);
mCurrentIdle = idle; mCurrentIdle = idleGroup;
if(!mCurrentIdle.empty()) if(!mCurrentIdle.empty())
mAnimation->play(mCurrentIdle, idlePriority, MWRender::Animation::BlendMask_All, false, mAnimation->play(mCurrentIdle, idlePriority, MWRender::Animation::BlendMask_All, false,
1.0f, "start", "stop", 0.0f, numLoops, true); 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()) else if(type == typeid(ESM::Weapon).name())
{ {
MWWorld::LiveCellRef<ESM::Weapon> *ref = weapon->get<ESM::Weapon>(); MWWorld::LiveCellRef<ESM::Weapon> *ref = weapon->get<ESM::Weapon>();
ESM::Weapon::Type type = (ESM::Weapon::Type)ref->mBase->mData.mType; ESM::Weapon::Type weaponType = (ESM::Weapon::Type)ref->mBase->mData.mType;
switch(type) switch(weaponType)
{ {
case ESM::Weapon::ShortBladeOneHand: case ESM::Weapon::ShortBladeOneHand:
case ESM::Weapon::LongBladeOneHand: case ESM::Weapon::LongBladeOneHand:
@ -1745,14 +1745,12 @@ void CharacterController::update(float duration)
cls.skillUsageSucceeded(mPtr, ESM::Skill::Acrobatics, 0); cls.skillUsageSucceeded(mPtr, ESM::Skill::Acrobatics, 0);
// decrease fatigue // decrease fatigue
const MWWorld::Store<ESM::GameSetting> &gmst = world->getStore().get<ESM::GameSetting>();
const float fatigueJumpBase = gmst.find("fFatigueJumpBase")->getFloat(); const float fatigueJumpBase = gmst.find("fFatigueJumpBase")->getFloat();
const float fatigueJumpMult = gmst.find("fFatigueJumpMult")->getFloat(); const float fatigueJumpMult = gmst.find("fFatigueJumpMult")->getFloat();
float normalizedEncumbrance = mPtr.getClass().getNormalizedEncumbrance(mPtr); float normalizedEncumbrance = mPtr.getClass().getNormalizedEncumbrance(mPtr);
if (normalizedEncumbrance > 1) if (normalizedEncumbrance > 1)
normalizedEncumbrance = 1; normalizedEncumbrance = 1;
const float fatigueDecrease = fatigueJumpBase + (1 - normalizedEncumbrance) * fatigueJumpMult; const float fatigueDecrease = fatigueJumpBase + (1 - normalizedEncumbrance) * fatigueJumpMult;
DynamicStat<float> fatigue = cls.getCreatureStats(mPtr).getFatigue();
fatigue.setCurrent(fatigue.getCurrent() - fatigueDecrease); fatigue.setCurrent(fatigue.getCurrent() - fatigueDecrease);
cls.getCreatureStats(mPtr).setFatigue(fatigue); cls.getCreatureStats(mPtr).setFatigue(fatigue);
} }

@ -83,8 +83,8 @@ void MWMechanics::NpcStats::raiseRank(const std::string &faction)
if (it != mFactionRank.end()) if (it != mFactionRank.end())
{ {
// Does the next rank exist? // Does the next rank exist?
const ESM::Faction* faction = MWBase::Environment::get().getWorld()->getStore().get<ESM::Faction>().find(lower); const ESM::Faction* factionPtr = MWBase::Environment::get().getWorld()->getStore().get<ESM::Faction>().find(lower);
if (it->second+1 < 10 && !faction->mRanks[it->second+1].empty()) if (it->second+1 < 10 && !factionPtr->mRanks[it->second+1].empty())
it->second += 1; it->second += 1;
} }
} }

@ -482,7 +482,10 @@ namespace MWMechanics
ActiveSpells::ActiveEffect effect; ActiveSpells::ActiveEffect effect;
effect.mEffectId = effectIt->mEffectID; effect.mEffectId = effectIt->mEffectID;
effect.mArg = MWMechanics::EffectKey(*effectIt).mArg; 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; effect.mMagnitude = magnitude;
targetEffects.add(MWMechanics::EffectKey(*effectIt), MWMechanics::EffectParam(effect.mMagnitude)); targetEffects.add(MWMechanics::EffectKey(*effectIt), MWMechanics::EffectParam(effect.mMagnitude));
@ -497,13 +500,13 @@ namespace MWMechanics
{ {
if (effectIt->mEffectID == ESM::MagicEffect::AbsorbAttribute+i) if (effectIt->mEffectID == ESM::MagicEffect::AbsorbAttribute+i)
{ {
std::vector<ActiveSpells::ActiveEffect> effects; std::vector<ActiveSpells::ActiveEffect> absorbEffects;
ActiveSpells::ActiveEffect effect_ = effect; ActiveSpells::ActiveEffect effect_ = effect;
effect_.mMagnitude *= -1; 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 // 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, 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()) if (isSummoningEffect(effectIt->mEffectID) && !target.isEmpty() && target.getClass().isActor())
{ {
CreatureStats& targetStats = target.getClass().getCreatureStats(target); CreatureStats& targetStats = target.getClass().getCreatureStats(target);
std::map<CreatureStats::SummonKey, int>::iterator found = targetStats.getSummonedCreatureMap().find(std::make_pair(effectIt->mEffectID, mId)); std::map<CreatureStats::SummonKey, int>::iterator findCreature = targetStats.getSummonedCreatureMap().find(std::make_pair(effectIt->mEffectID, mId));
if (found != targetStats.getSummonedCreatureMap().end()) if (findCreature != targetStats.getSummonedCreatureMap().end())
{ {
MWBase::Environment::get().getMechanicsManager()->cleanupSummonedCreature(target, found->second); MWBase::Environment::get().getMechanicsManager()->cleanupSummonedCreature(target, findCreature->second);
targetStats.getSummonedCreatureMap().erase(found); targetStats.getSummonedCreatureMap().erase(findCreature);
} }
} }
@ -612,36 +615,8 @@ namespace MWMechanics
return true; 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); MWRender::Animation* anim = MWBase::Environment::get().getWorld()->getAnimation(mCaster);
if (effectId == ESM::MagicEffect::DivineIntervention) if (effectId == ESM::MagicEffect::DivineIntervention)
@ -664,7 +639,6 @@ namespace MWMechanics
anim->addEffect("meshes\\" + fx->mModel, -1); anim->addEffect("meshes\\" + fx->mModel, -1);
return true; return true;
} }
else if (effectId == ESM::MagicEffect::Mark) else if (effectId == ESM::MagicEffect::Mark)
{ {
MWBase::Environment::get().getWorld()->getPlayer().markPosition( MWBase::Environment::get().getWorld()->getPlayer().markPosition(
@ -1176,6 +1150,27 @@ namespace MWMechanics
break; 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()) 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++) for(size_t i = 0;i < sNumBlendMasks;i++)
mAnimationTimePtr[i].reset(new AnimationTime); mAnimationTimePtr[i].reset(new AnimationTime);
mLightListCallback = new SceneUtil::LightListCallback;
} }
Animation::~Animation() Animation::~Animation()
@ -1095,6 +1097,8 @@ namespace MWRender
osg::ref_ptr<osg::StateSet> previousStateset; osg::ref_ptr<osg::StateSet> previousStateset;
if (mObjectRoot) if (mObjectRoot)
{ {
if (mLightListCallback)
mObjectRoot->removeCullCallback(mLightListCallback);
previousStateset = mObjectRoot->getStateSet(); previousStateset = mObjectRoot->getStateSet();
mObjectRoot->getParent(0)->removeChild(mObjectRoot); mObjectRoot->getParent(0)->removeChild(mObjectRoot);
} }
@ -1150,7 +1154,9 @@ namespace MWRender
removeTriBipVisitor.remove(); removeTriBipVisitor.remove();
} }
mObjectRoot->addCullCallback(new SceneUtil::LightListCallback); if (!mLightListCallback)
mLightListCallback = new SceneUtil::LightListCallback;
mObjectRoot->addCullCallback(mLightListCallback);
} }
osg::Group* Animation::getObjectRoot() osg::Group* Animation::getObjectRoot()

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

@ -18,7 +18,7 @@ namespace MWRender
CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr, CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr,
const std::string& model, Resource::ResourceSystem* resourceSystem) 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>(); 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) 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) , mShowWeapons(false)
, mShowCarriedLeft(false) , mShowCarriedLeft(false)
{ {
@ -48,7 +48,7 @@ CreatureWeaponAnimation::CreatureWeaponAnimation(const MWWorld::Ptr &ptr, const
addAnimSource("meshes\\xbase_anim.nif"); addAnimSource("meshes\\xbase_anim.nif");
addAnimSource(model); addAnimSource(model);
mPtr.getClass().getInventoryStore(mPtr).setListener(this, mPtr); mPtr.getClass().getInventoryStore(mPtr).setInvListener(this, mPtr);
updateParts(); updateParts();
} }

@ -1,7 +1,7 @@
#ifndef GAME_RENDER_CREATUREANIMATION_H #ifndef GAME_RENDER_CREATUREANIMATION_H
#define GAME_RENDER_CREATUREANIMATION_H #define GAME_RENDER_CREATUREANIMATION_H
#include "animation.hpp" #include "actoranimation.hpp"
#include "weaponanimation.hpp" #include "weaponanimation.hpp"
#include "../mwworld/inventorystore.hpp" #include "../mwworld/inventorystore.hpp"
@ -12,7 +12,7 @@ namespace MWWorld
namespace MWRender namespace MWRender
{ {
class CreatureAnimation : public Animation class CreatureAnimation : public ActorAnimation
{ {
public: public:
CreatureAnimation(const MWWorld::Ptr &ptr, const std::string& model, Resource::ResourceSystem* resourceSystem); CreatureAnimation(const MWWorld::Ptr &ptr, const std::string& model, Resource::ResourceSystem* resourceSystem);
@ -22,7 +22,7 @@ namespace MWRender
// For creatures with weapons and shields // For creatures with weapons and shields
// Animation is already virtual anyway, so might as well make a separate class. // 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. // 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: public:
CreatureWeaponAnimation(const MWWorld::Ptr &ptr, const std::string& model, Resource::ResourceSystem* resourceSystem); CreatureWeaponAnimation(const MWWorld::Ptr &ptr, const std::string& model, Resource::ResourceSystem* resourceSystem);

@ -16,6 +16,7 @@
#include <components/sceneutil/attach.hpp> #include <components/sceneutil/attach.hpp>
#include <components/sceneutil/visitor.hpp> #include <components/sceneutil/visitor.hpp>
#include <components/sceneutil/skeleton.hpp> #include <components/sceneutil/skeleton.hpp>
#include <components/sceneutil/lightmanager.hpp>
#include <components/nifosg/nifloader.hpp> // TextKeyMapHolder #include <components/nifosg/nifloader.hpp> // TextKeyMapHolder
@ -272,8 +273,8 @@ NpcAnimation::~NpcAnimation()
// No need to getInventoryStore() to reset, if none exists // No need to getInventoryStore() to reset, if none exists
// This is to avoid triggering the listener via ensureCustomData()->autoEquip()->fireEquipmentChanged() // This is to avoid triggering the listener via ensureCustomData()->autoEquip()->fireEquipmentChanged()
// all from within this destructor. ouch! // all from within this destructor. ouch!
&& mPtr.getRefData().getCustomData() && mPtr.getClass().getInventoryStore(mPtr).getListener() == this) && mPtr.getRefData().getCustomData() && mPtr.getClass().getInventoryStore(mPtr).getInvListener() == this)
mPtr.getClass().getInventoryStore(mPtr).setListener(NULL, mPtr); mPtr.getClass().getInventoryStore(mPtr).setInvListener(NULL, mPtr);
// do not detach (delete) parts yet, this is done so the background thread can handle the deletion // 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++) 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, NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, osg::ref_ptr<osg::Group> parentNode, Resource::ResourceSystem* resourceSystem,
bool disableListener, bool disableSounds, ViewMode viewMode, float firstPersonFieldOfView) bool disableListener, bool disableSounds, ViewMode viewMode, float firstPersonFieldOfView)
: Animation(ptr, parentNode, resourceSystem), : ActorAnimation(ptr, parentNode, resourceSystem, disableListener),
mListenerDisabled(disableListener), mListenerDisabled(disableListener),
mViewMode(viewMode), mViewMode(viewMode),
mShowWeapons(false), mShowWeapons(false),
@ -310,7 +311,7 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, osg::ref_ptr<osg::Group> par
updateNpcBase(); updateNpcBase();
if (!disableListener) if (!disableListener)
mPtr.getClass().getInventoryStore(mPtr).setListener(this, mPtr); mPtr.getClass().getInventoryStore(mPtr).setInvListener(this, mPtr);
} }
void NpcAnimation::setViewMode(NpcAnimation::ViewMode viewMode) void NpcAnimation::setViewMode(NpcAnimation::ViewMode viewMode)

@ -5,6 +5,7 @@
#include "../mwworld/inventorystore.hpp" #include "../mwworld/inventorystore.hpp"
#include "actoranimation.hpp"
#include "weaponanimation.hpp" #include "weaponanimation.hpp"
namespace ESM namespace ESM
@ -19,7 +20,7 @@ namespace MWRender
class NeckController; class NeckController;
class HeadAnimationTime; class HeadAnimationTime;
class NpcAnimation : public Animation, public WeaponAnimation, public MWWorld::InventoryStoreListener class NpcAnimation : public ActorAnimation, public WeaponAnimation, public MWWorld::InventoryStoreListener
{ {
public: public:
virtual void equipmentChanged(); virtual void equipmentChanged();

@ -112,12 +112,12 @@ bool Objects::removeObject (const MWWorld::Ptr& ptr)
PtrAnimationMap::iterator iter = mObjects.find(ptr); PtrAnimationMap::iterator iter = mObjects.find(ptr);
if(iter != mObjects.end()) if(iter != mObjects.end())
{ {
if (mUnrefQueue.get())
mUnrefQueue->push(iter->second->getObjectRoot());
delete iter->second; delete iter->second;
mObjects.erase(iter); mObjects.erase(iter);
if (mUnrefQueue.get())
mUnrefQueue->push(ptr.getRefData().getBaseNode());
ptr.getRefData().getBaseNode()->getParent(0)->removeChild(ptr.getRefData().getBaseNode()); ptr.getRefData().getBaseNode()->getParent(0)->removeChild(ptr.getRefData().getBaseNode());
ptr.getRefData().setBaseNode(NULL); ptr.getRefData().setBaseNode(NULL);

@ -3,12 +3,16 @@
#include <iostream> #include <iostream>
#include <vector> #include <vector>
#include <memory> #include <memory>
#include <cstring>
#include <stdint.h> #include <stdint.h>
#include <components/vfs/manager.hpp> #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 "openal_output.hpp"
#include "sound_decoder.hpp" #include "sound_decoder.hpp"
@ -243,31 +247,31 @@ const ALfloat OpenAL_SoundStream::sBufferLength = 0.125f;
// //
// A background streaming thread (keeps active streams processed) // 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; typedef std::vector<OpenAL_SoundStream*> StreamVec;
StreamVec mStreams; StreamVec mStreams;
volatile bool mQuitNow; volatile bool mQuitNow;
boost::mutex mMutex; OpenThreads::Mutex mMutex;
boost::condition_variable mCondVar; OpenThreads::Condition mCondVar;
boost::thread mThread;
StreamThread() StreamThread()
: mQuitNow(false), mThread(boost::ref(*this)) : mQuitNow(false)
{ {
start();
} }
~StreamThread() ~StreamThread()
{ {
mQuitNow = true; mQuitNow = true;
mMutex.lock(); mMutex.unlock(); mMutex.lock(); mMutex.unlock();
mCondVar.notify_all(); mCondVar.broadcast();
mThread.join(); join();
} }
// boost::thread entry point // thread entry point
void operator()() virtual void run()
{ {
boost::unique_lock<boost::mutex> lock(mMutex); OpenThreads::ScopedLock<OpenThreads::Mutex> lock(mMutex);
while(!mQuitNow) while(!mQuitNow)
{ {
StreamVec::iterator iter = mStreams.begin(); StreamVec::iterator iter = mStreams.begin();
@ -279,31 +283,30 @@ struct OpenAL_Output::StreamThread {
++iter; ++iter;
} }
mCondVar.timed_wait(lock, boost::posix_time::milliseconds(50)); mCondVar.wait(&mMutex, 50);
} }
} }
void add(OpenAL_SoundStream *stream) 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()) if(std::find(mStreams.begin(), mStreams.end(), stream) == mStreams.end())
{ {
mStreams.push_back(stream); mStreams.push_back(stream);
lock.unlock(); mCondVar.broadcast();
mCondVar.notify_all();
} }
} }
void remove(OpenAL_SoundStream *stream) 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); StreamVec::iterator iter = std::find(mStreams.begin(), mStreams.end(), stream);
if(iter != mStreams.end()) mStreams.erase(iter); if(iter != mStreams.end()) mStreams.erase(iter);
} }
void removeAll() void removeAll()
{ {
boost::lock_guard<boost::mutex> lock(mMutex); OpenThreads::ScopedLock<OpenThreads::Mutex> lock(mMutex);
mStreams.clear(); mStreams.clear();
} }
@ -468,7 +471,7 @@ ALint OpenAL_SoundStream::refillQueue()
if(got < data.size()) if(got < data.size())
{ {
mIsFinished = true; mIsFinished = true;
memset(&data[got], mSilence, data.size()-got); std::memset(&data[got], mSilence, data.size()-got);
} }
if(got > 0) if(got > 0)
{ {
@ -1023,7 +1026,7 @@ double OpenAL_Output::getStreamOffset(MWBase::SoundStreamPtr sound)
{ {
if(!sound->mHandle) return 0.0; if(!sound->mHandle) return 0.0;
OpenAL_SoundStream *stream = reinterpret_cast<OpenAL_SoundStream*>(sound->mHandle); 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(); return stream->getStreamOffset();
} }
@ -1031,7 +1034,7 @@ float OpenAL_Output::getStreamLoudness(MWBase::SoundStreamPtr sound)
{ {
if(!sound->mHandle) return 0.0; if(!sound->mHandle) return 0.0;
OpenAL_SoundStream *stream = reinterpret_cast<OpenAL_SoundStream*>(sound->mHandle); 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(); return stream->getCurrentLoudness();
} }
@ -1039,7 +1042,7 @@ bool OpenAL_Output::isStreamPlaying(MWBase::SoundStreamPtr sound)
{ {
if(!sound->mHandle) return false; if(!sound->mHandle) return false;
OpenAL_SoundStream *stream = reinterpret_cast<OpenAL_SoundStream*>(sound->mHandle); 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(); return stream->isPlaying();
} }

@ -113,7 +113,7 @@ void MWWorld::ContainerStore::storeStates (const CellRefList<T>& collection,
const std::string MWWorld::ContainerStore::sGoldId = "gold_001"; 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() {} MWWorld::ContainerStore::~ContainerStore() {}
@ -136,6 +136,17 @@ int MWWorld::ContainerStore::count(const std::string &id)
return total; 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) MWWorld::ContainerStoreIterator MWWorld::ContainerStore::unstack(const Ptr &ptr, const Ptr& container, int count)
{ {
if (ptr.getRefData().getCount() <= 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); item.getRefData().getLocals().setVarByInt(script, "onpcadd", 1);
} }
if (mListener)
mListener->itemAdded(item, count);
return it; return it;
} }
@ -398,6 +412,9 @@ int MWWorld::ContainerStore::remove(const Ptr& item, int count, const Ptr& actor
flagAsModified(); flagAsModified();
if (mListener)
mListener->itemRemoved(item, count - toRemove);
// number of removed items // number of removed items
return count - toRemove; 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()) 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) 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; return;
} }
else 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); std::string id = MWMechanics::getLevelledItem(ref.getPtr().get<ESM::ItemLevList>()->mBase, false);
if (id.empty()) if (id.empty())
return; return;
addInitialItem(id, owner, count, false, levItem->mId); addInitialItem(id, owner, count, false, levItemList->mId);
} }
} }
else else

@ -31,6 +31,13 @@ namespace MWWorld
{ {
class ContainerStoreIterator; class ContainerStoreIterator;
class ContainerStoreListener
{
public:
virtual void itemAdded(const ConstPtr& item, int count) {}
virtual void itemRemoved(const ConstPtr& item, int count) {}
};
class ContainerStore class ContainerStore
{ {
public: public:
@ -73,6 +80,8 @@ namespace MWWorld
///< Stores result of levelled item spawns. <(refId, spawningGroup), count> ///< Stores result of levelled item spawns. <(refId, spawningGroup), count>
/// This is used to restock levelled items(s) if the old item was sold. /// This is used to restock levelled items(s) if the old item was sold.
ContainerStoreListener* mListener;
mutable float mCachedWeight; mutable float mCachedWeight;
mutable bool mWeightUpToDate; mutable bool mWeightUpToDate;
ContainerStoreIterator addImp (const Ptr& ptr, int count); 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? /// @return How many items with refID \a id are in this container?
int count (const std::string& id); int count (const std::string& id);
ContainerStoreListener* getContListener() const;
void setContListener(ContainerStoreListener* listener);
protected: protected:
ContainerStoreIterator addNewStack (const ConstPtr& ptr, int count); ContainerStoreIterator addNewStack (const ConstPtr& ptr, int count);
///< Add the item to this container (do not try to stack it onto existing items) ///< 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); return unstack(item, actor, item.getRefData().getCount() - count);
} }
MWWorld::InventoryStoreListener* MWWorld::InventoryStore::getListener() MWWorld::InventoryStoreListener* MWWorld::InventoryStore::getInvListener()
{ {
return mListener; return mListener;
} }
void MWWorld::InventoryStore::setListener(InventoryStoreListener *listener, const Ptr& actor) void MWWorld::InventoryStore::setInvListener(InventoryStoreListener *listener, const Ptr& actor)
{ {
mListener = listener; mListener = listener;
updateMagicEffects(actor); updateMagicEffects(actor);

@ -197,10 +197,10 @@ namespace MWWorld
/// in the slot (they can be re-stacked so its count may be different /// in the slot (they can be re-stacked so its count may be different
/// than the requested count). /// 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 ///< Set a listener for various events, see \a InventoryStoreListener
InventoryStoreListener* getListener(); InventoryStoreListener* getInvListener();
void visitEffectSources (MWMechanics::EffectSourceVisitor& visitor); void visitEffectSources (MWMechanics::EffectSourceVisitor& visitor);

@ -212,7 +212,7 @@ namespace MWWorld
MWWorld::Ptr player = getPlayer(); MWWorld::Ptr player = getPlayer();
const MWMechanics::NpcStats &playerStats = player.getClass().getNpcStats(player); const MWMechanics::NpcStats &playerStats = player.getClass().getNpcStats(player);
if (playerStats.isParalyzed() || playerStats.getKnockedDown()) if (playerStats.isParalyzed() || playerStats.getKnockedDown() || playerStats.isDead())
return; return;
MWWorld::Ptr toActivate = MWBase::Environment::get().getWorld()->getFacedObject(); MWWorld::Ptr toActivate = MWBase::Environment::get().getWorld()->getFacedObject();

@ -48,7 +48,7 @@ namespace Compiler
extensions.registerFunction ("getaipackagedone", 'l', "", opcodeGetAiPackageDone, extensions.registerFunction ("getaipackagedone", 'l', "", opcodeGetAiPackageDone,
opcodeGetAiPackageDoneExplicit); opcodeGetAiPackageDoneExplicit);
extensions.registerFunction ("getcurrentaipackage", 'l', "", opcodeGetCurrentAiPackage, extensions.registerFunction ("getcurrentaipackage", 'l', "", opcodeGetCurrentAiPackage,
opcodeGetAiPackageDoneExplicit); opcodeGetCurrentAiPackageExplicit);
extensions.registerFunction ("getdetected", 'l', "c", opcodeGetDetected, extensions.registerFunction ("getdetected", 'l', "c", opcodeGetDetected,
opcodeGetDetectedExplicit); opcodeGetDetectedExplicit);
extensions.registerInstruction ("sethello", "l", opcodeSetHello, opcodeSetHelloExplicit); extensions.registerInstruction ("sethello", "l", opcodeSetHello, opcodeSetHelloExplicit);

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

@ -356,8 +356,7 @@ short MagicEffect::getWeaknessEffect(short effect)
effects[Corprus] = WeaknessToCorprusDisease; effects[Corprus] = WeaknessToCorprusDisease;
effects[Poison] = WeaknessToPoison; effects[Poison] = WeaknessToPoison;
// Weakness to magicka or -1 ? effects[Paralyze] = -1;
effects[Paralyze] = WeaknessToMagicka;
if (effects.find(effect) != effects.end()) if (effects.find(effect) != effects.end())
return effects[effect]; return effects[effect];

@ -13,6 +13,9 @@ USE_OSGPLUGIN(png)
USE_OSGPLUGIN(tga) USE_OSGPLUGIN(tga)
USE_OSGPLUGIN(dds) USE_OSGPLUGIN(dds)
USE_OSGPLUGIN(jpeg) USE_OSGPLUGIN(jpeg)
USE_OSGPLUGIN(bmp)
USE_OSGPLUGIN(osg)
USE_SERIALIZER_WRAPPER_LIBRARY(osg)
#endif #endif
namespace namespace

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

@ -1,6 +1,8 @@
#ifndef OPENMW_COMPONENTS_SCENEUTIL_LIGHTMANAGER_H #ifndef OPENMW_COMPONENTS_SCENEUTIL_LIGHTMANAGER_H
#define OPENMW_COMPONENTS_SCENEUTIL_LIGHTMANAGER_H #define OPENMW_COMPONENTS_SCENEUTIL_LIGHTMANAGER_H
#include <set>
#include <osg/Light> #include <osg/Light>
#include <osg/Group> #include <osg/Group>
@ -157,16 +159,20 @@ namespace SceneUtil
: osg::Object(copy, copyop), osg::NodeCallback(copy, copyop) : osg::Object(copy, copyop), osg::NodeCallback(copy, copyop)
, mLightManager(copy.mLightManager) , mLightManager(copy.mLightManager)
, mLastFrameNumber(0) , mLastFrameNumber(0)
, mIgnoredLightSources(copy.mIgnoredLightSources)
{} {}
META_Object(SceneUtil, LightListCallback) META_Object(SceneUtil, LightListCallback)
void operator()(osg::Node* node, osg::NodeVisitor* nv); void operator()(osg::Node* node, osg::NodeVisitor* nv);
std::set<SceneUtil::LightSource*>& getIgnoredLightSources() { return mIgnoredLightSources; }
private: private:
LightManager* mLightManager; LightManager* mLightManager;
unsigned int mLastFrameNumber; unsigned int mLastFrameNumber;
LightManager::LightList mLightList; LightManager::LightList mLightList;
std::set<SceneUtil::LightSource*> mIgnoredLightSources;
}; };
} }

@ -36,7 +36,6 @@ namespace SceneUtil
light->setLinearAttenuation(linearAttenuation); light->setLinearAttenuation(linearAttenuation);
light->setQuadraticAttenuation(quadraticAttenuation); light->setQuadraticAttenuation(quadraticAttenuation);
light->setConstantAttenuation(0.f); 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, 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; 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<SceneUtil::LightSource> lightSource (new SceneUtil::LightSource);
osg::ref_ptr<osg::Light> light (new osg::Light); osg::ref_ptr<osg::Light> light (new osg::Light);
lightSource->setNodeMask(lightMask); lightSource->setNodeMask(lightMask);
@ -85,7 +92,7 @@ namespace SceneUtil
diffuse.a() = 1; diffuse.a() = 1;
} }
light->setDiffuse(diffuse); light->setDiffuse(diffuse);
light->setAmbient(osg::Vec4f(0,0,0,1)); light->setAmbient(ambient);
light->setSpecular(osg::Vec4f(0,0,0,0)); light->setSpecular(osg::Vec4f(0,0,0,0));
lightSource->setLight(light); lightSource->setLight(light);
@ -103,7 +110,6 @@ namespace SceneUtil
lightSource->addUpdateCallback(ctrl); lightSource->addUpdateCallback(ctrl);
attachTo->addChild(lightSource); return lightSource;
} }
} }

@ -1,6 +1,9 @@
#ifndef OPENMW_COMPONENTS_LIGHTUTIL_H #ifndef OPENMW_COMPONENTS_LIGHTUTIL_H
#define OPENMW_COMPONENTS_LIGHTUTIL_H #define OPENMW_COMPONENTS_LIGHTUTIL_H
#include <osg/ref_ptr>
#include <osg/Vec4f>
namespace osg namespace osg
{ {
class Group; class Group;
@ -13,6 +16,7 @@ namespace ESM
namespace SceneUtil namespace SceneUtil
{ {
class LightSource;
/// @brief Convert an ESM::Light to a SceneUtil::LightSource, and add it to a sub graph. /// @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. /// @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 quadraticValue, float quadraticRadiusMult, bool useLinear, float linearRadiusMult,
float linearValue); 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 #endif

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

@ -1,6 +1,7 @@
#include "videostate.hpp" #include "videostate.hpp"
#include <iostream> #include <iostream>
#include <stdexcept>
#include <osg/Texture2D> #include <osg/Texture2D>
@ -102,14 +103,14 @@ void PacketQueue::put(AVPacket *pkt)
this->last_pkt = pkt1; this->last_pkt = pkt1;
this->nb_packets++; this->nb_packets++;
this->size += pkt1->pkt.size; this->size += pkt1->pkt.size;
this->cond.notify_one(); this->cond.signal();
this->mutex.unlock(); this->mutex.unlock();
} }
int PacketQueue::get(AVPacket *pkt, VideoState *is) 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) while(!is->mQuit)
{ {
AVPacketList *pkt1 = this->first_pkt; AVPacketList *pkt1 = this->first_pkt;
@ -129,7 +130,7 @@ int PacketQueue::get(AVPacket *pkt, VideoState *is)
if(this->flushing) if(this->flushing)
break; break;
this->cond.wait(lock); this->cond.wait(&this->mutex);
} }
return -1; return -1;
@ -138,7 +139,7 @@ int PacketQueue::get(AVPacket *pkt, VideoState *is)
void PacketQueue::flush() void PacketQueue::flush()
{ {
this->flushing = true; this->flushing = true;
this->cond.notify_one(); this->cond.signal();
} }
void PacketQueue::clear() void PacketQueue::clear()
@ -233,7 +234,7 @@ void VideoState::video_display(VideoPicture *vp)
void VideoState::video_refresh() 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) if(this->pictq_size == 0)
return; return;
@ -245,7 +246,7 @@ void VideoState::video_refresh()
this->pictq_rindex = (pictq_rindex+1) % VIDEO_PICTURE_ARRAY_SIZE; this->pictq_rindex = (pictq_rindex+1) % VIDEO_PICTURE_ARRAY_SIZE;
this->frame_last_pts = vp->pts; this->frame_last_pts = vp->pts;
this->pictq_size--; this->pictq_size--;
this->pictq_cond.notify_one(); this->pictq_cond.signal();
} }
else else
{ {
@ -275,7 +276,7 @@ void VideoState::video_refresh()
// update queue for next picture // update queue for next picture
this->pictq_size--; this->pictq_size--;
this->pictq_rindex = (this->pictq_rindex+1) % VIDEO_PICTURE_ARRAY_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 */ /* 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) 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) if(this->mQuit)
return -1; return -1;
@ -371,168 +372,196 @@ static void our_free_buffer(void *opaque, uint8_t *data)
av_free(data); av_free(data);
} }
class VideoThread : public OpenThreads::Thread
void VideoState::video_thread_loop(VideoState *self)
{ {
AVPacket pkt1, *packet = &pkt1; public:
int frameFinished; VideoThread(VideoState* self)
AVFrame *pFrame; : 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(); self->rgbaFrame = av_frame_alloc();
avpicture_alloc((AVPicture*)self->rgbaFrame, AV_PIX_FMT_RGBA, (*self->video_st)->codec->width, (*self->video_st)->codec->height); 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) while(self->videoq.get(packet, self) >= 0)
{
if(packet->data == flush_pkt.data)
{ {
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_mutex.lock();
self->pictq_size = 0; self->pictq_size = 0;
self->pictq_rindex = 0; self->pictq_rindex = 0;
self->pictq_windex = 0; self->pictq_windex = 0;
self->pictq_mutex.unlock(); self->pictq_mutex.unlock();
self->frame_last_pts = packet->pts * av_q2d((*self->video_st)->time_base); 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); global_video_pkt_pts = static_cast<int64_t>(self->frame_last_pts);
continue; continue;
} }
// Save global pts to be stored in pFrame // Save global pts to be stored in pFrame
global_video_pkt_pts = packet->pts; global_video_pkt_pts = packet->pts;
// Decode video frame // Decode video frame
if(avcodec_decode_video2((*self->video_st)->codec, pFrame, &frameFinished, packet) < 0) if(avcodec_decode_video2((*self->video_st)->codec, pFrame, &frameFinished, packet) < 0)
throw std::runtime_error("Error decoding video frame"); throw std::runtime_error("Error decoding video frame");
double pts = 0; double pts = 0;
if(packet->dts != AV_NOPTS_VALUE) if(packet->dts != AV_NOPTS_VALUE)
pts = static_cast<double>(packet->dts); pts = static_cast<double>(packet->dts);
else if(pFrame->opaque && *(int64_t*)pFrame->opaque != AV_NOPTS_VALUE) else if(pFrame->opaque && *(int64_t*)pFrame->opaque != AV_NOPTS_VALUE)
pts = static_cast<double>(*(int64_t*)pFrame->opaque); pts = static_cast<double>(*(int64_t*)pFrame->opaque);
pts *= av_q2d((*self->video_st)->time_base); pts *= av_q2d((*self->video_st)->time_base);
av_free_packet(packet); av_free_packet(packet);
// Did we get a video frame? // Did we get a video frame?
if(frameFinished) if(frameFinished)
{ {
pts = self->synchronize_video(pFrame, pts); pts = self->synchronize_video(pFrame, pts);
if(self->queue_picture(pFrame, pts) < 0) if(self->queue_picture(pFrame, pts) < 0)
break; break;
}
} }
}
av_free(pFrame); av_free(pFrame);
avpicture_free((AVPicture*)self->rgbaFrame); avpicture_free((AVPicture*)self->rgbaFrame);
av_free(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; public:
AVPacket pkt1, *packet = &pkt1; ParseThread(VideoState* self)
: mVideoState(self)
{
start();
}
try virtual void run()
{ {
if(!self->video_st && !self->audio_st) VideoState* self = mVideoState;
throw std::runtime_error("No streams to decode");
// main decode loop AVFormatContext *pFormatCtx = self->format_ctx;
while(!self->mQuit) 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; if(self->mSeekRequested)
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
{ {
// Clear the packet queues and put a special packet with the new clock time uint64_t seek_target = self->mSeekPos;
if(audioStreamIndex >= 0) int streamIndex = -1;
{
self->audioq.clear(); int videoStreamIndex = -1;;
flush_pkt.pts = av_rescale_q(seek_target, avTimeBaseQ, int audioStreamIndex = -1;
self->format_ctx->streams[audioStreamIndex]->time_base); if (self->video_st)
self->audioq.put(&flush_pkt); videoStreamIndex = self->video_st - self->format_ctx->streams;
} if (self->audio_st)
audioStreamIndex = self->audio_st - self->format_ctx->streams;
if(videoStreamIndex >= 0) 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(); // Clear the packet queues and put a special packet with the new clock time
flush_pkt.pts = av_rescale_q(seek_target, avTimeBaseQ, if(audioStreamIndex >= 0)
self->format_ctx->streams[videoStreamIndex]->time_base); {
self->videoq.put(&flush_pkt); 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->mSeekRequested = false;
self->pictq_size = 0;
self->pictq_rindex = 0;
self->pictq_windex = 0;
self->pictq_mutex.unlock();
self->mExternalClock.set(seek_target);
} }
self->mSeekRequested = false;
}
if((self->audio_st && self->audioq.size > MAX_AUDIOQ_SIZE) || if((self->audio_st && self->audioq.size > MAX_AUDIOQ_SIZE) ||
(self->video_st && self->videoq.size > MAX_VIDEOQ_SIZE)) (self->video_st && self->videoq.size > MAX_VIDEOQ_SIZE))
{ {
boost::this_thread::sleep(boost::posix_time::milliseconds(10)); OpenThreads::Thread::microSleep(10 * 1000);
continue; continue;
} }
if(av_read_frame(pFormatCtx, packet) < 0) if(av_read_frame(pFormatCtx, packet) < 0)
{ {
if (self->audioq.nb_packets == 0 && self->videoq.nb_packets == 0 && self->pictq_size == 0) if (self->audioq.nb_packets == 0 && self->videoq.nb_packets == 0 && self->pictq_size == 0)
self->mVideoEnded = true; self->mVideoEnded = true;
continue; continue;
} }
else else
self->mVideoEnded = false; self->mVideoEnded = false;
// Is this a packet from the video stream? // Is this a packet from the video stream?
if(self->video_st && packet->stream_index == self->video_st-pFormatCtx->streams) if(self->video_st && packet->stream_index == self->video_st-pFormatCtx->streams)
self->videoq.put(packet); self->videoq.put(packet);
else if(self->audio_st && packet->stream_index == self->audio_st-pFormatCtx->streams) else if(self->audio_st && packet->stream_index == self->audio_st-pFormatCtx->streams)
self->audioq.put(packet); self->audioq.put(packet);
else else
av_free_packet(packet); av_free_packet(packet);
}
} }
} catch(std::exception& e) {
catch(std::exception& e) { std::cerr << "An error occurred playing the video: " << e.what () << std::endl;
std::cerr << "An error occurred playing the video: " << e.what () << std::endl; }
self->mQuit = true;
} }
self->mQuit = true; private:
} VideoState* mVideoState;
};
bool VideoState::update() bool VideoState::update()
@ -587,7 +616,7 @@ int VideoState::stream_open(int stream_index, AVFormatContext *pFormatCtx)
this->video_st = pFormatCtx->streams + stream_index; this->video_st = pFormatCtx->streams + stream_index;
codecCtx->get_buffer2 = our_get_buffer; codecCtx->get_buffer2 = our_get_buffer;
this->video_thread = boost::thread(video_thread_loop, this); this->video_thread.reset(new VideoThread(this));
break; break;
default: 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() void VideoState::deinit()
@ -681,10 +710,16 @@ void VideoState::deinit()
mAudioDecoder.reset(); mAudioDecoder.reset();
if (this->parse_thread.joinable()) if (this->parse_thread.get())
this->parse_thread.join(); {
if (this->video_thread.joinable()) this->parse_thread->join();
this->video_thread.join(); this->parse_thread.reset();
}
if (this->video_thread.get())
{
this->video_thread->join();
this->video_thread.reset();
}
if(this->audio_st) if(this->audio_st)
avcodec_close((*this->audio_st)->codec); avcodec_close((*this->audio_st)->codec);
@ -779,7 +814,7 @@ ExternalClock::ExternalClock()
void ExternalClock::setPaused(bool paused) void ExternalClock::setPaused(bool paused)
{ {
boost::mutex::scoped_lock lock(mMutex); OpenThreads::ScopedLock<OpenThreads::Mutex> lock(mMutex);
if (mPaused == paused) if (mPaused == paused)
return; return;
if (paused) if (paused)
@ -793,7 +828,7 @@ void ExternalClock::setPaused(bool paused)
uint64_t ExternalClock::get() uint64_t ExternalClock::get()
{ {
boost::mutex::scoped_lock lock(mMutex); OpenThreads::ScopedLock<OpenThreads::Mutex> lock(mMutex);
if (mPaused) if (mPaused)
return mPausedAt; return mPausedAt;
else else
@ -802,7 +837,7 @@ uint64_t ExternalClock::get()
void ExternalClock::set(uint64_t time) void ExternalClock::set(uint64_t time)
{ {
boost::mutex::scoped_lock lock(mMutex); OpenThreads::ScopedLock<OpenThreads::Mutex> lock(mMutex);
mTimeBase = av_gettime() - time; mTimeBase = av_gettime() - time;
mPausedAt = time; mPausedAt = time;
} }

@ -2,8 +2,14 @@
#define VIDEOPLAYER_VIDEOSTATE_H #define VIDEOPLAYER_VIDEOSTATE_H
#include <stdint.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> #include <osg/ref_ptr>
namespace osg namespace osg
@ -34,6 +40,8 @@ struct VideoState;
class MovieAudioFactory; class MovieAudioFactory;
class MovieAudioDecoder; class MovieAudioDecoder;
class VideoThread;
class ParseThread;
struct ExternalClock struct ExternalClock
{ {
@ -43,7 +51,7 @@ struct ExternalClock
uint64_t mPausedAt; uint64_t mPausedAt;
bool mPaused; bool mPaused;
boost::mutex mMutex; OpenThreads::Mutex mMutex;
void setPaused(bool paused); void setPaused(bool paused);
uint64_t get(); uint64_t get();
@ -62,8 +70,8 @@ struct PacketQueue {
int nb_packets; int nb_packets;
int size; int size;
boost::mutex mutex; OpenThreads::Mutex mutex;
boost::condition_variable cond; OpenThreads::Condition cond;
void put(AVPacket *pkt); void put(AVPacket *pkt);
int get(AVPacket *pkt, VideoState *is); int get(AVPacket *pkt, VideoState *is);
@ -141,11 +149,11 @@ struct VideoState {
VideoPicture pictq[VIDEO_PICTURE_ARRAY_SIZE]; VideoPicture pictq[VIDEO_PICTURE_ARRAY_SIZE];
AVFrame* rgbaFrame; // used as buffer for the frame converted from its native format to RGBA AVFrame* rgbaFrame; // used as buffer for the frame converted from its native format to RGBA
int pictq_size, pictq_rindex, pictq_windex; int pictq_size, pictq_rindex, pictq_windex;
boost::mutex pictq_mutex; OpenThreads::Mutex pictq_mutex;
boost::condition_variable pictq_cond; OpenThreads::Condition pictq_cond;
boost::thread parse_thread; std::auto_ptr<ParseThread> parse_thread;
boost::thread video_thread; std::auto_ptr<VideoThread> video_thread;
volatile bool mSeekRequested; volatile bool mSeekRequested;
uint64_t mSeekPos; uint64_t mSeekPos;

@ -120,6 +120,10 @@
<Property key="TextShadow" value="true"/> <Property key="TextShadow" value="true"/>
</Widget> </Widget>
<Widget type="ImageBox" skin="ImageBox" position="5 5 32 32" align="Stretch" name="Item"/> <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>
</Widget> </Widget>
</Resource> </Resource>
@ -128,6 +132,10 @@
<Widget type="Widget" skin="" position="0 0 32 32" name="Root"> <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="Frame">
<Widget type="ImageBox" skin="ImageBox" position="0 0 32 32" align="Stretch" name="Item"/> <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>
</Widget> </Widget>
</Resource> </Resource>
@ -140,6 +148,10 @@
<Property key="TextShadow" value="true"/> <Property key="TextShadow" value="true"/>
</Widget> </Widget>
<Widget type="ImageBox" skin="ImageBox" position="5 5 32 32" align="Center" name="Item"/> <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>
<Widget type="Widget" skin="MW_Box_Overlay" position="0 0 50 50" align="Stretch"/> <Widget type="Widget" skin="MW_Box_Overlay" position="0 0 50 50" align="Stretch"/>

Loading…
Cancel
Save