forked from mirror/openmw-tes3mp
Resolve conflicts in pull request #75
# Conflicts: # CMakeLists.txt # apps/openmw/CMakeLists.txt
This commit is contained in:
commit
3136a12051
49 changed files with 692 additions and 360 deletions
|
@ -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);
|
||||
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:
|
||||
|
@ -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())
|
||||
|
|
131
apps/openmw/mwrender/actoranimation.cpp
Normal file
131
apps/openmw/mwrender/actoranimation.cpp
Normal file
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
53
apps/openmw/mwrender/actoranimation.hpp
Normal file
53
apps/openmw/mwrender/actoranimation.hpp
Normal file
|
@ -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"
|
||||
{
|
||||
|
|
349
extern/osg-ffmpeg-videoplayer/videostate.cpp
vendored
349
extern/osg-ffmpeg-videoplayer/videostate.cpp
vendored
|
@ -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;
|
||||
|
||||
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);
|
||||
|
||||
while(self->videoq.get(packet, self) >= 0)
|
||||
public:
|
||||
VideoThread(VideoState* self)
|
||||
: mVideoState(self)
|
||||
{
|
||||
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->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");
|
||||
|
||||
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);
|
||||
|
||||
// Did we get a video frame?
|
||||
if(frameFinished)
|
||||
{
|
||||
pts = self->synchronize_video(pFrame, pts);
|
||||
if(self->queue_picture(pFrame, pts) < 0)
|
||||
break;
|
||||
}
|
||||
start();
|
||||
}
|
||||
|
||||
av_free(pFrame);
|
||||
|
||||
avpicture_free((AVPicture*)self->rgbaFrame);
|
||||
av_free(self->rgbaFrame);
|
||||
}
|
||||
|
||||
void VideoState::decode_thread_loop(VideoState *self)
|
||||
{
|
||||
AVFormatContext *pFormatCtx = self->format_ctx;
|
||||
AVPacket pkt1, *packet = &pkt1;
|
||||
|
||||
try
|
||||
virtual void run()
|
||||
{
|
||||
if(!self->video_st && !self->audio_st)
|
||||
throw std::runtime_error("No streams to decode");
|
||||
VideoState* self = mVideoState;
|
||||
AVPacket pkt1, *packet = &pkt1;
|
||||
int frameFinished;
|
||||
AVFrame *pFrame;
|
||||
|
||||
// main decode loop
|
||||
while(!self->mQuit)
|
||||
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);
|
||||
|
||||
while(self->videoq.get(packet, self) >= 0)
|
||||
{
|
||||
if(self->mSeekRequested)
|
||||
if(packet->data == flush_pkt.data)
|
||||
{
|
||||
uint64_t seek_target = self->mSeekPos;
|
||||
int streamIndex = -1;
|
||||
avcodec_flush_buffers((*self->video_st)->codec);
|
||||
|
||||
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;
|
||||
self->pictq_mutex.lock();
|
||||
self->pictq_size = 0;
|
||||
self->pictq_rindex = 0;
|
||||
self->pictq_windex = 0;
|
||||
self->pictq_mutex.unlock();
|
||||
|
||||
if(videoStreamIndex >= 0)
|
||||
streamIndex = videoStreamIndex;
|
||||
else if(audioStreamIndex >= 0)
|
||||
streamIndex = audioStreamIndex;
|
||||
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;
|
||||
}
|
||||
|
||||
uint64_t timestamp = seek_target;
|
||||
// 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");
|
||||
|
||||
// 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;
|
||||
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);
|
||||
|
||||
if(streamIndex >= 0)
|
||||
timestamp = av_rescale_q(seek_target, avTimeBaseQ, self->format_ctx->streams[streamIndex]->time_base);
|
||||
av_free_packet(packet);
|
||||
|
||||
// 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
|
||||
// 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);
|
||||
|
||||
avpicture_free((AVPicture*)self->rgbaFrame);
|
||||
av_free(self->rgbaFrame);
|
||||
}
|
||||
|
||||
private:
|
||||
VideoState* mVideoState;
|
||||
};
|
||||
|
||||
class ParseThread : public OpenThreads::Thread
|
||||
{
|
||||
public:
|
||||
ParseThread(VideoState* self)
|
||||
: mVideoState(self)
|
||||
{
|
||||
start();
|
||||
}
|
||||
|
||||
virtual void run()
|
||||
{
|
||||
VideoState* self = mVideoState;
|
||||
|
||||
AVFormatContext *pFormatCtx = self->format_ctx;
|
||||
AVPacket pkt1, *packet = &pkt1;
|
||||
|
||||
try
|
||||
{
|
||||
if(!self->video_st && !self->audio_st)
|
||||
throw std::runtime_error("No streams to decode");
|
||||
|
||||
// main decode loop
|
||||
while(!self->mQuit)
|
||||
{
|
||||
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))
|
||||
{
|
||||
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;
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
|
||||
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(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);
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
|
24
extern/osg-ffmpeg-videoplayer/videostate.hpp
vendored
24
extern/osg-ffmpeg-videoplayer/videostate.hpp
vendored
|
@ -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…
Reference in a new issue