diff --git a/apps/opencs/model/settings/usersettings.cpp b/apps/opencs/model/settings/usersettings.cpp index 9fe947b68..80893cf21 100644 --- a/apps/opencs/model/settings/usersettings.cpp +++ b/apps/opencs/model/settings/usersettings.cpp @@ -120,6 +120,11 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() reuse->setToolTip ("When a new subview is requested and a matching subview already " " exist, do not open a new subview and use the existing one instead."); + Setting *statusBar = createSetting (Type_CheckBox, "show-statusbar", "Show Status Bar"); + statusBar->setDefaultValue ("true"); + statusBar->setToolTip ("If a newly open top level window is showing status bars or not. " + " Note that this does not affect existing windows."); + Setting *maxSubView = createSetting (Type_SpinBox, "max-subviews", "Maximum number of subviews per top-level window"); maxSubView->setDefaultValue (256); diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index d36e01901..bef0c170d 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -105,7 +105,7 @@ void CSVDoc::View::setupViewMenu() mShowStatusBar->setCheckable (true); connect (mShowStatusBar, SIGNAL (toggled (bool)), this, SLOT (toggleShowStatusBar (bool))); std::string showStatusBar = - CSMSettings::UserSettings::instance().settingValue("Display/show statusbar").toStdString(); + CSMSettings::UserSettings::instance().settingValue("window/show-statusbar").toStdString(); if(showStatusBar == "true") mShowStatusBar->setChecked(true); view->addAction (mShowStatusBar); diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 4229ab531..5f6b6b46a 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -144,7 +144,7 @@ CSVDoc::View *CSVDoc::ViewManager::addView (CSMDoc::Document *document) mViews.push_back (view); std::string showStatusBar = - CSMSettings::UserSettings::instance().settingValue("Display/show statusbar").toStdString(); + CSMSettings::UserSettings::instance().settingValue("window/show-statusbar").toStdString(); view->toggleStatusBar (showStatusBar == "true"); view->show(); diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 71a45a92c..c1a889913 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -199,6 +199,10 @@ namespace MWBase virtual MWWorld::Ptr searchPtrViaActorId (int actorId) = 0; ///< Search is limited to the active cells. + virtual MWWorld::Ptr findContainer (const MWWorld::Ptr& ptr) = 0; + ///< Return a pointer to a liveCellRef which contains \a ptr. + /// \note Search is limited to the active cells. + /// \todo enable reference in the OGRE scene virtual void enable (const MWWorld::Ptr& ptr) = 0; diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 7b2d7e132..e6d266de2 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -191,8 +191,11 @@ namespace MWClass std::string text; - text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->mBase->mData.mWeight); - text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}"); + if (ref->mBase->mData.mWeight != 0) + { + text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->mBase->mData.mWeight); + text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}"); + } if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { text += MWGui::ToolTips::getCellRefString(ptr.getCellRef()); diff --git a/apps/openmw/mwgui/formatting.hpp b/apps/openmw/mwgui/formatting.hpp index 3e21b62e2..5b7925057 100644 --- a/apps/openmw/mwgui/formatting.hpp +++ b/apps/openmw/mwgui/formatting.hpp @@ -132,6 +132,7 @@ namespace MWGui virtual int pageSplit(); protected: + virtual ~GraphicElement() {} MyGUI::Widget * mParent; Paginator & mPaginator; BlockStyle mBlockStyle; diff --git a/apps/openmw/mwgui/videowidget.cpp b/apps/openmw/mwgui/videowidget.cpp index 76fdd5287..f8054925b 100644 --- a/apps/openmw/mwgui/videowidget.cpp +++ b/apps/openmw/mwgui/videowidget.cpp @@ -30,8 +30,7 @@ int VideoWidget::getVideoHeight() bool VideoWidget::update() { - mPlayer.update(); - return mPlayer.isPlaying(); + return mPlayer.update(); } void VideoWidget::stop() diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index f431bc8f1..6ab8b94c5 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -377,6 +377,7 @@ namespace MWGui delete mHitFader; delete mWerewolfFader; delete mScreenFader; + delete mBlindnessFader; delete mDebugWindow; cleanupGarbage(); diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index 247a0ba14..fef9fa644 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -27,9 +27,9 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr) setObjectRoot(model, false); setRenderProperties(mObjectRoot, RV_Actors, RQG_Main, RQG_Alpha); - addAnimSource(model); if((ref->mBase->mFlags&ESM::Creature::Bipedal)) addAnimSource("meshes\\base_anim.nif"); + addAnimSource(model); } } @@ -47,9 +47,9 @@ CreatureWeaponAnimation::CreatureWeaponAnimation(const MWWorld::Ptr &ptr) setObjectRoot(model, false); setRenderProperties(mObjectRoot, RV_Actors, RQG_Main, RQG_Alpha); - addAnimSource(model); if((ref->mBase->mFlags&ESM::Creature::Bipedal)) addAnimSource("meshes\\base_anim.nif"); + addAnimSource(model); mPtr.getClass().getInventoryStore(mPtr).setListener(this, mPtr); diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index cb02a6c97..52021839d 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -21,6 +21,7 @@ #include "../mwworld/class.hpp" #include "../mwworld/cellstore.hpp" +#include "../mwworld/containerstore.hpp" #include "../mwmechanics/npcstats.hpp" @@ -434,6 +435,16 @@ namespace MWScript else ref2 = MWBase::Environment::get().getWorld()->getPtr(id, false); + if (ref2.getContainerStore()) // is the object contained? + { + MWWorld::Ptr container = MWBase::Environment::get().getWorld()->findContainer(ref2); + + if (!container.isEmpty()) + ref2 = container; + else + throw std::runtime_error("failed to find container ptr"); + } + const MWWorld::Ptr ref = MWBase::Environment::get().getWorld()->getPtr(name, false); // If the objects are in different worldspaces, return a large value (just like vanilla) diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 0de8f3b91..c7d221139 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -454,7 +454,8 @@ namespace MWScript if (::Misc::StringUtils::ciEqual(iter->getCellRef().getRefId(), item)) { int removed = store.remove(*iter, toRemove, ptr); - MWBase::Environment::get().getWorld()->dropObjectOnGround(ptr, *iter, removed); + MWWorld::Ptr dropped = MWBase::Environment::get().getWorld()->dropObjectOnGround(ptr, *iter, removed); + dropped.getCellRef().setOwner(""); toRemove -= removed; diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index 170c5fe94..befb8d82e 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -20,6 +20,7 @@ #include "../mwbase/windowmanager.hpp" #include "../mwworld/class.hpp" +#include "../mwworld/player.hpp" #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/npcstats.hpp" @@ -416,8 +417,12 @@ namespace MWScript MWBase::World *world = MWBase::Environment::get().getWorld(); MWWorld::Ptr player = world->getPlayerPtr(); - player.getClass().getNpcStats (player).setBounty(runtime[0].mFloat); + int bounty = runtime[0].mFloat; runtime.pop(); + player.getClass().getNpcStats (player).setBounty(bounty); + + if (bounty == 0) + MWBase::Environment::get().getWorld()->getPlayer().recordCrimeId(); } }; diff --git a/apps/openmw/mwsound/ffmpeg_decoder.cpp b/apps/openmw/mwsound/ffmpeg_decoder.cpp index a2998ad03..2002bded7 100644 --- a/apps/openmw/mwsound/ffmpeg_decoder.cpp +++ b/apps/openmw/mwsound/ffmpeg_decoder.cpp @@ -112,7 +112,7 @@ bool FFmpeg_Decoder::getAVAudioData() if(!mDataBuf || mDataBufLen < mFrame->nb_samples) { av_freep(&mDataBuf); - if(av_samples_alloc(&mDataBuf, NULL, (*mStream)->codec->channels, + if(av_samples_alloc(&mDataBuf, NULL, av_get_channel_layout_nb_channels(mOutputChannelLayout), mFrame->nb_samples, mOutputSampleFormat, 0) < 0) break; else @@ -147,8 +147,8 @@ size_t FFmpeg_Decoder::readAVAudioData(void *data, size_t length) if(!getAVAudioData()) break; mFramePos = 0; - mFrameSize = mFrame->nb_samples * (*mStream)->codec->channels * - av_get_bytes_per_sample((*mStream)->codec->sample_fmt); + mFrameSize = mFrame->nb_samples * av_get_channel_layout_nb_channels(mOutputChannelLayout) * + av_get_bytes_per_sample(mOutputSampleFormat); } /* Get the amount of bytes remaining to be written, and clamp to @@ -285,47 +285,31 @@ void FFmpeg_Decoder::getInfo(int *samplerate, ChannelConfig *chans, SampleType * if(!mStream) fail("No audio stream info"); - if((*mStream)->codec->sample_fmt == AV_SAMPLE_FMT_U8) - *type = SampleType_UInt8; - else if((*mStream)->codec->sample_fmt == AV_SAMPLE_FMT_S16) - *type = SampleType_Int16; - else if((*mStream)->codec->sample_fmt == AV_SAMPLE_FMT_FLT) - *type = SampleType_Float32; + if((*mStream)->codec->sample_fmt == AV_SAMPLE_FMT_FLT || (*mStream)->codec->sample_fmt == AV_SAMPLE_FMT_FLTP) + mOutputSampleFormat = AV_SAMPLE_FMT_S16; // FIXME: Check for AL_EXT_FLOAT32 support else if((*mStream)->codec->sample_fmt == AV_SAMPLE_FMT_U8P) - *type = SampleType_UInt8; + mOutputSampleFormat = AV_SAMPLE_FMT_U8; else if((*mStream)->codec->sample_fmt == AV_SAMPLE_FMT_S16P) + mOutputSampleFormat = AV_SAMPLE_FMT_S16; + else + mOutputSampleFormat = AV_SAMPLE_FMT_S16; + + if(mOutputSampleFormat == AV_SAMPLE_FMT_U8) + *type = SampleType_UInt8; + else if(mOutputSampleFormat == AV_SAMPLE_FMT_S16) *type = SampleType_Int16; - else if((*mStream)->codec->sample_fmt == AV_SAMPLE_FMT_FLTP) + else if(mOutputSampleFormat == AV_SAMPLE_FMT_FLT) *type = SampleType_Float32; - else - fail(std::string("Unsupported sample format: ")+ - av_get_sample_fmt_name((*mStream)->codec->sample_fmt)); int64_t ch_layout = (*mStream)->codec->channel_layout; - if((*mStream)->codec->channel_layout == AV_CH_LAYOUT_MONO) - *chans = ChannelConfig_Mono; - else if((*mStream)->codec->channel_layout == AV_CH_LAYOUT_STEREO) - *chans = ChannelConfig_Stereo; - else if((*mStream)->codec->channel_layout == AV_CH_LAYOUT_QUAD) - *chans = ChannelConfig_Quad; - else if((*mStream)->codec->channel_layout == AV_CH_LAYOUT_5POINT1) - *chans = ChannelConfig_5point1; - else if((*mStream)->codec->channel_layout == AV_CH_LAYOUT_7POINT1) - *chans = ChannelConfig_7point1; - else if((*mStream)->codec->channel_layout == 0) + if(ch_layout == 0) { /* Unknown channel layout. Try to guess. */ if((*mStream)->codec->channels == 1) - { - *chans = ChannelConfig_Mono; ch_layout = AV_CH_LAYOUT_MONO; - } else if((*mStream)->codec->channels == 2) - { - *chans = ChannelConfig_Stereo; ch_layout = AV_CH_LAYOUT_STEREO; - } else { std::stringstream sstr("Unsupported raw channel count: "); @@ -333,6 +317,25 @@ void FFmpeg_Decoder::getInfo(int *samplerate, ChannelConfig *chans, SampleType * fail(sstr.str()); } } + + mOutputChannelLayout = ch_layout; + if (ch_layout == AV_CH_LAYOUT_5POINT1 || ch_layout == AV_CH_LAYOUT_7POINT1 + || ch_layout == AV_CH_LAYOUT_QUAD) // FIXME: check for AL_EXT_MCFORMATS support + mOutputChannelLayout = AV_CH_LAYOUT_STEREO; + else if (ch_layout != AV_CH_LAYOUT_MONO + && ch_layout != AV_CH_LAYOUT_STEREO) + mOutputChannelLayout = AV_CH_LAYOUT_STEREO; + + if(mOutputChannelLayout == AV_CH_LAYOUT_MONO) + *chans = ChannelConfig_Mono; + else if(mOutputChannelLayout == AV_CH_LAYOUT_STEREO) + *chans = ChannelConfig_Stereo; + else if(mOutputChannelLayout == AV_CH_LAYOUT_QUAD) + *chans = ChannelConfig_Quad; + else if(mOutputChannelLayout == AV_CH_LAYOUT_5POINT1) + *chans = ChannelConfig_5point1; + else if(mOutputChannelLayout == AV_CH_LAYOUT_7POINT1) + *chans = ChannelConfig_7point1; else { char str[1024]; @@ -343,17 +346,11 @@ void FFmpeg_Decoder::getInfo(int *samplerate, ChannelConfig *chans, SampleType * *samplerate = (*mStream)->codec->sample_rate; - if((*mStream)->codec->sample_fmt == AV_SAMPLE_FMT_U8P) - mOutputSampleFormat = AV_SAMPLE_FMT_U8; - else if((*mStream)->codec->sample_fmt == AV_SAMPLE_FMT_S16P) - mOutputSampleFormat = AV_SAMPLE_FMT_S16; - else if((*mStream)->codec->sample_fmt == AV_SAMPLE_FMT_FLTP) - mOutputSampleFormat = AV_SAMPLE_FMT_FLT; - - if(mOutputSampleFormat != AV_SAMPLE_FMT_NONE) + if(mOutputSampleFormat != (*mStream)->codec->sample_fmt + || mOutputChannelLayout != ch_layout) { mSwr = swr_alloc_set_opts(mSwr, // SwrContext - ch_layout, // output ch layout + mOutputChannelLayout, // output ch layout mOutputSampleFormat, // output sample format (*mStream)->codec->sample_rate, // output sample rate ch_layout, // input ch layout @@ -383,8 +380,8 @@ void FFmpeg_Decoder::readAll(std::vector &output) while(getAVAudioData()) { - size_t got = mFrame->nb_samples * (*mStream)->codec->channels * - av_get_bytes_per_sample((*mStream)->codec->sample_fmt); + size_t got = mFrame->nb_samples * av_get_channel_layout_nb_channels(mOutputChannelLayout) * + av_get_bytes_per_sample(mOutputSampleFormat); const char *inbuf = reinterpret_cast(mFrameData[0]); output.insert(output.end(), inbuf, inbuf+got); } @@ -402,8 +399,8 @@ void FFmpeg_Decoder::rewind() size_t FFmpeg_Decoder::getSampleOffset() { - int delay = (mFrameSize-mFramePos) / (*mStream)->codec->channels / - av_get_bytes_per_sample((*mStream)->codec->sample_fmt); + int delay = (mFrameSize-mFramePos) / av_get_channel_layout_nb_channels(mOutputChannelLayout) / + av_get_bytes_per_sample(mOutputSampleFormat); return (int)(mNextPts*(*mStream)->codec->sample_rate) - delay; } @@ -416,6 +413,7 @@ FFmpeg_Decoder::FFmpeg_Decoder() , mNextPts(0.0) , mSwr(0) , mOutputSampleFormat(AV_SAMPLE_FMT_NONE) + , mOutputChannelLayout(0) , mDataBuf(NULL) , mFrameData(NULL) , mDataBufLen(0) diff --git a/apps/openmw/mwsound/ffmpeg_decoder.hpp b/apps/openmw/mwsound/ffmpeg_decoder.hpp index 796f17350..2cdbbf363 100644 --- a/apps/openmw/mwsound/ffmpeg_decoder.hpp +++ b/apps/openmw/mwsound/ffmpeg_decoder.hpp @@ -59,6 +59,7 @@ namespace MWSound SwrContext *mSwr; enum AVSampleFormat mOutputSampleFormat; + int64_t mOutputChannelLayout; uint8_t *mDataBuf; uint8_t **mFrameData; int mDataBufLen; diff --git a/apps/openmw/mwsound/movieaudiofactory.cpp b/apps/openmw/mwsound/movieaudiofactory.cpp index bc7bb8023..468f8c82c 100644 --- a/apps/openmw/mwsound/movieaudiofactory.cpp +++ b/apps/openmw/mwsound/movieaudiofactory.cpp @@ -44,8 +44,8 @@ namespace MWSound size_t getSampleOffset() { - ssize_t clock_delay = (mFrameSize-mFramePos) / mAVStream->codec->channels / - av_get_bytes_per_sample(mAVStream->codec->sample_fmt); + ssize_t clock_delay = (mFrameSize-mFramePos) / av_get_channel_layout_nb_channels(mOutputChannelLayout) / + av_get_bytes_per_sample(mOutputSampleFormat); return (size_t)(mAudioClock*mAVStream->codec->sample_rate) - clock_delay; } @@ -64,20 +64,20 @@ namespace MWSound virtual void adjustAudioSettings(AVSampleFormat& sampleFormat, uint64_t& channelLayout, int& sampleRate) { - if (sampleFormat == AV_SAMPLE_FMT_U8P) + if (sampleFormat == AV_SAMPLE_FMT_U8P || sampleFormat == AV_SAMPLE_FMT_U8) sampleFormat = AV_SAMPLE_FMT_U8; - else if (sampleFormat == AV_SAMPLE_FMT_S16P) + else if (sampleFormat == AV_SAMPLE_FMT_S16P || sampleFormat == AV_SAMPLE_FMT_S16) sampleFormat = AV_SAMPLE_FMT_S16; - else if (sampleFormat == AV_SAMPLE_FMT_FLTP) - sampleFormat = AV_SAMPLE_FMT_FLT; + else if (sampleFormat == AV_SAMPLE_FMT_FLTP || sampleFormat == AV_SAMPLE_FMT_FLT) + sampleFormat = AV_SAMPLE_FMT_S16; // FIXME: check for AL_EXT_FLOAT32 support else - sampleFormat = AV_SAMPLE_FMT_FLT; + sampleFormat = AV_SAMPLE_FMT_S16; - if (channelLayout != AV_CH_LAYOUT_MONO - && channelLayout != AV_CH_LAYOUT_5POINT1 - && channelLayout != AV_CH_LAYOUT_7POINT1 - && channelLayout != AV_CH_LAYOUT_STEREO - && channelLayout != AV_CH_LAYOUT_QUAD) + if (channelLayout == AV_CH_LAYOUT_5POINT1 || channelLayout == AV_CH_LAYOUT_7POINT1 + || channelLayout == AV_CH_LAYOUT_QUAD) // FIXME: check for AL_EXT_MCFORMATS support + channelLayout = AV_CH_LAYOUT_STEREO; + else if (channelLayout != AV_CH_LAYOUT_MONO + && channelLayout != AV_CH_LAYOUT_STEREO) channelLayout = AV_CH_LAYOUT_STEREO; } diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index ba6fad7ba..e322ef4a4 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -149,6 +149,17 @@ namespace MWWorld forEachImp (functor, mCreatureLists); } + template + bool forEachContainer (Functor& functor) + { + mHasState = true; + + return + forEachImp (functor, mContainers) && + forEachImp (functor, mCreatures) && + forEachImp (functor, mNpcs); + } + bool isExterior() const; Ptr searchInContainer (const std::string& id); diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 085b079d9..45728371b 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -272,7 +272,7 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add (const Ptr& itemPtr item.mCell = actorPtr.getCell(); } - item.mContainerStore = 0; + item.mContainerStore = this; MWBase::Environment::get().getWorld()->getLocalScripts().add(script, item); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index d8e0d52b8..5d07a26a0 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -657,6 +657,47 @@ namespace MWWorld return mWorldScene->searchPtrViaActorId (actorId); } + struct FindContainerFunctor + { + Ptr mContainedPtr; + Ptr mResult; + + FindContainerFunctor(const Ptr& containedPtr) : mContainedPtr(containedPtr) {} + + bool operator() (Ptr ptr) + { + if (mContainedPtr.getContainerStore() == &ptr.getClass().getContainerStore(ptr)) + { + mResult = ptr; + return false; + } + + return true; + } + }; + + Ptr World::findContainer(const Ptr& ptr) + { + if (ptr.isInCell()) + return Ptr(); + + Ptr player = getPlayerPtr(); + if (ptr.getContainerStore() == &player.getClass().getContainerStore(player)) + return player; + + const Scene::CellStoreCollection& collection = mWorldScene->getActiveCells(); + for (Scene::CellStoreCollection::const_iterator cellIt = collection.begin(); cellIt != collection.end(); ++cellIt) + { + FindContainerFunctor functor(ptr); + (*cellIt)->forEachContainer(functor); + + if (!functor.mResult.isEmpty()) + return functor.mResult; + } + + return Ptr(); + } + void World::addContainerScripts(const Ptr& reference, CellStore * cell) { if( reference.getTypeName()==typeid (ESM::Container).name() || diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 334e799f2..fef279705 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -260,6 +260,10 @@ namespace MWWorld virtual Ptr searchPtrViaActorId (int actorId); ///< Search is limited to the active cells. + virtual MWWorld::Ptr findContainer (const MWWorld::Ptr& ptr); + ///< Return a pointer to a liveCellRef which contains \a ptr. + /// \note Search is limited to the active cells. + virtual void adjustPosition (const Ptr& ptr, bool force); ///< Adjust position after load to be on ground. Must be called after model load. /// @param force do this even if the ptr is flying diff --git a/cmake/FindOGRE.cmake b/cmake/FindOGRE.cmake index 51589698f..f2acf9d33 100644 --- a/cmake/FindOGRE.cmake +++ b/cmake/FindOGRE.cmake @@ -382,7 +382,6 @@ endmacro() ogre_find_component(Paging OgrePaging.h) # look for Overlay component ogre_find_component(Overlay OgreOverlaySystem.h) -ogre_find_component(Overlay OgreOverlay.h) # look for Terrain component ogre_find_component(Terrain OgreTerrain.h) # look for Property component diff --git a/extern/ogre-ffmpeg-videoplayer/CMakeLists.txt b/extern/ogre-ffmpeg-videoplayer/CMakeLists.txt index f34ffa64b..299a57799 100644 --- a/extern/ogre-ffmpeg-videoplayer/CMakeLists.txt +++ b/extern/ogre-ffmpeg-videoplayer/CMakeLists.txt @@ -3,15 +3,14 @@ set(OGRE_FFMPEG_VIDEOPLAYER_LIBRARY "ogre-ffmpeg-videoplayer") # Sources set(OGRE_FFMPEG_VIDEOPLAYER_SOURCE_FILES - videoplayer.cpp - videostate.cpp - videodefs.hpp + videoplayer.cpp + videostate.cpp + videodefs.hpp libavwrapper.cpp audiodecoder.cpp audiofactory.hpp ) - # Find FFMPEG set(FFmpeg_FIND_COMPONENTS AVCODEC AVFORMAT AVUTIL SWSCALE SWRESAMPLE AVRESAMPLE) unset(FFMPEG_LIBRARIES CACHE) @@ -30,10 +29,14 @@ else() message(FATAL_ERROR "Install either libswresample (FFmpeg) or libavresample (Libav).") endif() endif() - include_directories(${FFMPEG_INCLUDE_DIRS}) +# Find Boost +set(BOOST_COMPONENTS thread) +find_package(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS}) +include_directories(${Boost_INCLUDE_DIRS}) + add_library(${OGRE_FFMPEG_VIDEOPLAYER_LIBRARY} STATIC ${OGRE_FFMPEG_VIDEOPLAYER_SOURCE_FILES}) -target_link_libraries(${OGRE_FFMPEG_VIDEOPLAYER_LIBRARY} ${VIDEO_FFMPEG_LIBRARIES}) +target_link_libraries(${OGRE_FFMPEG_VIDEOPLAYER_LIBRARY} ${VIDEO_FFMPEG_LIBRARIES} ${Boost_LIBRARIES}) link_directories(${CMAKE_CURRENT_BINARY_DIR}) diff --git a/extern/ogre-ffmpeg-videoplayer/audiodecoder.cpp b/extern/ogre-ffmpeg-videoplayer/audiodecoder.cpp index 54fe2b24f..41313d5d5 100644 --- a/extern/ogre-ffmpeg-videoplayer/audiodecoder.cpp +++ b/extern/ogre-ffmpeg-videoplayer/audiodecoder.cpp @@ -152,8 +152,8 @@ int MovieAudioDecoder::synchronize_audio() double avg_diff = mAudioDiffAccum * (1.0 - mAudioDiffAvgCoef); if(fabs(avg_diff) >= mAudioDiffThreshold) { - int n = av_get_bytes_per_sample(mAVStream->codec->sample_fmt) * - mAVStream->codec->channels; + int n = av_get_bytes_per_sample(mOutputSampleFormat) * + av_get_channel_layout_nb_channels(mOutputChannelLayout); sample_skip = ((int)(diff * mAVStream->codec->sample_rate) * n); } } @@ -161,7 +161,7 @@ int MovieAudioDecoder::synchronize_audio() return sample_skip; } -int MovieAudioDecoder::audio_decode_frame(AVFrame *frame) +int MovieAudioDecoder::audio_decode_frame(AVFrame *frame, int &sample_skip) { AVPacket *pkt = &mPacket; @@ -191,7 +191,7 @@ int MovieAudioDecoder::audio_decode_frame(AVFrame *frame) if(!mDataBuf || mDataBufLen < frame->nb_samples) { av_freep(&mDataBuf); - if(av_samples_alloc(&mDataBuf, NULL, mAVStream->codec->channels, + if(av_samples_alloc(&mDataBuf, NULL, av_get_channel_layout_nb_channels(mOutputChannelLayout), frame->nb_samples, mOutputSampleFormat, 0) < 0) break; else @@ -212,8 +212,8 @@ int MovieAudioDecoder::audio_decode_frame(AVFrame *frame) (double)mAVStream->codec->sample_rate; /* We have data, return it and come back for more later */ - return frame->nb_samples * mAVStream->codec->channels * - av_get_bytes_per_sample(mAVStream->codec->sample_fmt); + return frame->nb_samples * av_get_channel_layout_nb_channels(mOutputChannelLayout) * + av_get_bytes_per_sample(mOutputSampleFormat); } av_free_packet(pkt); @@ -221,6 +221,18 @@ int MovieAudioDecoder::audio_decode_frame(AVFrame *frame) if(mVideoState->audioq.get(pkt, mVideoState) < 0) return -1; + if(pkt->data == mVideoState->mFlushPktData) + { + avcodec_flush_buffers(mAVStream->codec); + mAudioDiffAccum = 0.0; + mAudioDiffAvgCount = 0; + mAudioClock = av_q2d(mAVStream->time_base)*pkt->pts; + sample_skip = 0; + + if(mVideoState->audioq.get(pkt, mVideoState) < 0) + return -1; + } + /* if update, update the audio clock w/pts */ if((uint64_t)pkt->pts != AV_NOPTS_VALUE) mAudioClock = av_q2d(mAVStream->time_base)*pkt->pts; @@ -229,6 +241,16 @@ int MovieAudioDecoder::audio_decode_frame(AVFrame *frame) size_t MovieAudioDecoder::read(char *stream, size_t len) { + if (mVideoState->mPaused) + { + // fill the buffer with silence + size_t sampleSize = av_get_bytes_per_sample(mOutputSampleFormat); + char* data[1]; + data[0] = stream; + av_samples_set_silence((uint8_t**)data, 0, len/sampleSize, 1, mOutputSampleFormat); + return len; + } + int sample_skip = synchronize_audio(); size_t total = 0; @@ -237,7 +259,7 @@ size_t MovieAudioDecoder::read(char *stream, size_t len) if(mFramePos >= mFrameSize) { /* We have already sent all our data; get more */ - mFrameSize = audio_decode_frame(mFrame); + mFrameSize = audio_decode_frame(mFrame, sample_skip); if(mFrameSize < 0) { /* If error, we're done */ @@ -260,8 +282,8 @@ size_t MovieAudioDecoder::read(char *stream, size_t len) { len1 = std::min(len1, -mFramePos); - int n = av_get_bytes_per_sample(mAVStream->codec->sample_fmt) * - mAVStream->codec->channels; + int n = av_get_bytes_per_sample(mOutputSampleFormat) + * av_get_channel_layout_nb_channels(mOutputChannelLayout); /* add samples by copying the first sample*/ if(n == 1) diff --git a/extern/ogre-ffmpeg-videoplayer/audiodecoder.hpp b/extern/ogre-ffmpeg-videoplayer/audiodecoder.hpp index 88406d51d..b05b16d42 100644 --- a/extern/ogre-ffmpeg-videoplayer/audiodecoder.hpp +++ b/extern/ogre-ffmpeg-videoplayer/audiodecoder.hpp @@ -77,7 +77,8 @@ private: * skip (negative means to duplicate). */ int synchronize_audio(); - int audio_decode_frame(AVFrame *frame); + /// @param sample_skip If seeking happened, the sample_skip variable will be reset to 0. + int audio_decode_frame(AVFrame *frame, int &sample_skip); public: MovieAudioDecoder(VideoState *is); @@ -101,6 +102,8 @@ public: virtual double getAudioClock(); /// This is the main interface to be used by the user's audio library. + /// @par Request filling the \a stream with \a len number of bytes. + /// @return The number of bytes read (may not be the requested number if we arrived at the end of the audio stream) size_t read(char *stream, size_t len); }; diff --git a/extern/ogre-ffmpeg-videoplayer/audiofactory.hpp b/extern/ogre-ffmpeg-videoplayer/audiofactory.hpp index cf1ff46a8..06abd6a74 100644 --- a/extern/ogre-ffmpeg-videoplayer/audiofactory.hpp +++ b/extern/ogre-ffmpeg-videoplayer/audiofactory.hpp @@ -12,6 +12,7 @@ class MovieAudioFactory { public: virtual boost::shared_ptr createDecoder(VideoState* videoState) = 0; + virtual ~MovieAudioFactory() {} }; } diff --git a/extern/ogre-ffmpeg-videoplayer/videoplayer.cpp b/extern/ogre-ffmpeg-videoplayer/videoplayer.cpp index 434b676ee..c2daf3579 100644 --- a/extern/ogre-ffmpeg-videoplayer/videoplayer.cpp +++ b/extern/ogre-ffmpeg-videoplayer/videoplayer.cpp @@ -1,5 +1,6 @@ #include "videoplayer.hpp" +#include "audiofactory.hpp" #include "videostate.hpp" namespace Video @@ -31,6 +32,13 @@ void VideoPlayer::playVideo(const std::string &resourceName) mState = new VideoState; mState->setAudioFactory(mAudioFactory.get()); mState->init(resourceName); + + // wait until we have the first picture + while (mState->video_st && mState->mTexture.isNull()) + { + if (!mState->update()) + break; + } } catch(std::exception& e) { std::cerr<< "Failed to play video: "<update()) - close(); - } + return mState->update(); + return false; } std::string VideoPlayer::getTextureName() { std::string name; - if (mState) + if (mState && !mState->mTexture.isNull()) name = mState->mTexture->getName(); return name; } @@ -58,7 +64,7 @@ std::string VideoPlayer::getTextureName() int VideoPlayer::getVideoWidth() { int width=0; - if (mState) + if (mState && !mState->mTexture.isNull()) width = mState->mTexture->getWidth(); return width; } @@ -66,7 +72,7 @@ int VideoPlayer::getVideoWidth() int VideoPlayer::getVideoHeight() { int height=0; - if (mState) + if (mState && !mState->mTexture.isNull()) height = mState->mTexture->getHeight(); return height; } @@ -82,14 +88,48 @@ void VideoPlayer::close() } } -bool VideoPlayer::isPlaying () +bool VideoPlayer::hasAudioStream() +{ + return mState && mState->audio_st != NULL; +} + +void VideoPlayer::play() { - return mState != NULL; + if (mState) + mState->setPaused(false); } -bool VideoPlayer::hasAudioStream() +void VideoPlayer::pause() { - return mState && mState->audio_st != NULL; + if (mState) + mState->setPaused(true); +} + +bool VideoPlayer::isPaused() +{ + if (mState) + return mState->mPaused; + return true; +} + +double VideoPlayer::getCurrentTime() +{ + if (mState) + return mState->get_master_clock(); + return 0.0; +} + +void VideoPlayer::seek(double time) +{ + if (mState) + mState->seekTo(time); +} + +double VideoPlayer::getDuration() +{ + if (mState) + return mState->getDuration(); + return 0.0; } } diff --git a/extern/ogre-ffmpeg-videoplayer/videoplayer.hpp b/extern/ogre-ffmpeg-videoplayer/videoplayer.hpp index 750ad02e5..2727ac6f0 100644 --- a/extern/ogre-ffmpeg-videoplayer/videoplayer.hpp +++ b/extern/ogre-ffmpeg-videoplayer/videoplayer.hpp @@ -29,16 +29,29 @@ namespace Video bool hasAudioStream(); /// Play the given video. If a video is already playing, the old video is closed first. + /// @note The video will be unpaused by default. Use the pause() and play() methods to control pausing. void playVideo (const std::string& resourceName); + /// Get the current playback time position in the video, in seconds + double getCurrentTime(); + + /// Get the duration of the video in seconds + double getDuration(); + + /// Seek to the specified time position in the video + void seek(double time); + + void play(); + void pause(); + bool isPaused(); + /// This should be called every frame by the user to update the video texture. - void update(); + /// @return Returns true if the video is still playing, false if we have reached the end of the video stream. + bool update(); /// Stop the currently playing video, if a video is playing. void close(); - bool isPlaying(); - /// Return the texture name of the currently playing video, or "" if no video is playing. std::string getTextureName(); /// Return the width of the currently playing video, or 0 if no video is playing. diff --git a/extern/ogre-ffmpeg-videoplayer/videostate.cpp b/extern/ogre-ffmpeg-videoplayer/videostate.cpp index c77723421..b36543880 100644 --- a/extern/ogre-ffmpeg-videoplayer/videostate.cpp +++ b/extern/ogre-ffmpeg-videoplayer/videostate.cpp @@ -25,12 +25,26 @@ extern "C" #include #endif + #include + #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(55,28,1) #define av_frame_alloc avcodec_alloc_frame #endif } +static const char* flushString = "FLUSH"; +struct FlushPacket : AVPacket +{ + FlushPacket() + : AVPacket() + { + data = ( (uint8_t*)flushString); + } +}; + +static FlushPacket flush_pkt; + #include "videoplayer.hpp" #include "audiodecoder.hpp" #include "audiofactory.hpp" @@ -46,14 +60,18 @@ namespace Video VideoState::VideoState() : format_ctx(NULL), av_sync_type(AV_SYNC_DEFAULT) - , external_clock_base(0.0) , audio_st(NULL) , video_st(NULL), frame_last_pts(0.0) , video_clock(0.0), sws_context(NULL), rgbaFrame(NULL), pictq_size(0) , pictq_rindex(0), pictq_windex(0) - , quit(false) + , mQuit(false), mPaused(false) , mAudioFactory(NULL) + , mSeekRequested(false) + , mSeekPos(0) + , mVideoEnded(false) { + mFlushPktData = flush_pkt.data; + // Register all formats and codecs av_register_all(); } @@ -77,7 +95,7 @@ void PacketQueue::put(AVPacket *pkt) pkt1->pkt = *pkt; pkt1->next = NULL; - if(pkt1->pkt.destruct == NULL) + if(pkt->data != flush_pkt.data && pkt1->pkt.destruct == NULL) { if(av_dup_packet(&pkt1->pkt) < 0) { @@ -104,7 +122,7 @@ void PacketQueue::put(AVPacket *pkt) int PacketQueue::get(AVPacket *pkt, VideoState *is) { boost::unique_lock lock(this->mutex); - while(!is->quit) + while(!is->mQuit) { AVPacketList *pkt1 = this->first_pkt; if(pkt1) @@ -143,7 +161,8 @@ void PacketQueue::clear() for(pkt = this->first_pkt; pkt != NULL; pkt = pkt1) { pkt1 = pkt->next; - av_free_packet(&pkt->pkt); + if (pkt->pkt.data != flush_pkt.data) + av_free_packet(&pkt->pkt); av_freep(&pkt); } this->last_pkt = NULL; @@ -188,14 +207,17 @@ void VideoState::video_display(VideoPicture *vp) { if((*this->video_st)->codec->width != 0 && (*this->video_st)->codec->height != 0) { - - if(static_cast(mTexture->getWidth()) != (*this->video_st)->codec->width || - static_cast(mTexture->getHeight()) != (*this->video_st)->codec->height) + if (mTexture.isNull()) { - mTexture->unload(); - mTexture->setWidth((*this->video_st)->codec->width); - mTexture->setHeight((*this->video_st)->codec->height); - mTexture->createInternalResources(); + static int i = 0; + mTexture = Ogre::TextureManager::getSingleton().createManual( + "ffmpeg/VideoTexture" + Ogre::StringConverter::toString(++i), + Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, + Ogre::TEX_TYPE_2D, + (*this->video_st)->codec->width, (*this->video_st)->codec->height, + 0, + Ogre::PF_BYTE_RGBA, + Ogre::TU_DYNAMIC_WRITE_ONLY_DISCARDABLE); } Ogre::PixelBox pb((*this->video_st)->codec->width, (*this->video_st)->codec->height, 1, Ogre::PF_BYTE_RGBA, &vp->data[0]); Ogre::HardwarePixelBufferSharedPtr buffer = mTexture->getBuffer(); @@ -205,6 +227,7 @@ void VideoState::video_display(VideoPicture *vp) void VideoState::video_refresh() { + boost::mutex::scoped_lock lock(this->pictq_mutex); if(this->pictq_size == 0) return; @@ -212,16 +235,15 @@ void VideoState::video_refresh() { VideoPicture* vp = &this->pictq[this->pictq_rindex]; this->video_display(vp); + this->pictq_rindex = (pictq_rindex+1) % VIDEO_PICTURE_QUEUE_SIZE; this->frame_last_pts = vp->pts; - this->pictq_mutex.lock(); this->pictq_size--; this->pictq_cond.notify_one(); - this->pictq_mutex.unlock(); } else { - const float threshold = 0.03; + const float threshold = 0.03f; if (this->pictq[pictq_rindex].pts > this->get_master_clock() + threshold) return; // not ready yet to show this picture @@ -236,19 +258,18 @@ void VideoState::video_refresh() break; } + assert (this->pictq_rindex < VIDEO_PICTURE_QUEUE_SIZE); VideoPicture* vp = &this->pictq[this->pictq_rindex]; this->video_display(vp); this->frame_last_pts = vp->pts; - this->pictq_mutex.lock(); this->pictq_size -= i; // update queue for next picture this->pictq_size--; - this->pictq_rindex++; + this->pictq_rindex = (this->pictq_rindex+1) % VIDEO_PICTURE_QUEUE_SIZE; this->pictq_cond.notify_one(); - this->pictq_mutex.unlock(); } } @@ -260,12 +281,14 @@ int VideoState::queue_picture(AVFrame *pFrame, double pts) /* wait until we have a new pic */ { boost::unique_lock lock(this->pictq_mutex); - while(this->pictq_size >= VIDEO_PICTURE_QUEUE_SIZE && !this->quit) + while(this->pictq_size >= VIDEO_PICTURE_QUEUE_SIZE && !this->mQuit) this->pictq_cond.timed_wait(lock, boost::posix_time::milliseconds(1)); } - if(this->quit) + if(this->mQuit) return -1; + this->pictq_mutex.lock(); + // windex is set to 0 initially vp = &this->pictq[this->pictq_windex]; @@ -292,7 +315,6 @@ int VideoState::queue_picture(AVFrame *pFrame, double pts) // now we inform our display thread that we have a pic ready this->pictq_windex = (this->pictq_windex+1) % VIDEO_PICTURE_QUEUE_SIZE; - this->pictq_mutex.lock(); this->pictq_size++; this->pictq_mutex.unlock(); @@ -353,6 +375,21 @@ void VideoState::video_thread_loop(VideoState *self) while(self->videoq.get(packet, self) >= 0) { + 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 = self->frame_last_pts; + continue; + } + // Save global pts to be stored in pFrame global_video_pkt_pts = packet->pts; // Decode video frame @@ -394,8 +431,67 @@ void VideoState::decode_thread_loop(VideoState *self) throw std::runtime_error("No streams to decode"); // main decode loop - while(!self->quit) + while(!self->mQuit) { + if(self->mSeekRequested) + { + 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 + { + // 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->mSeekRequested = false; + } + + if((self->audio_st && self->audioq.size > MAX_AUDIOQ_SIZE) || (self->video_st && self->videoq.size > MAX_VIDEOQ_SIZE)) { @@ -404,7 +500,13 @@ void VideoState::decode_thread_loop(VideoState *self) } if(av_read_frame(pFormatCtx, packet) < 0) - break; + { + 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) @@ -414,17 +516,6 @@ void VideoState::decode_thread_loop(VideoState *self) else av_free_packet(packet); } - - /* all done - wait for it */ - self->videoq.flush(); - self->audioq.flush(); - while(!self->quit) - { - // EOF reached, all packets processed, we can exit now - if(self->audioq.nb_packets == 0 && self->videoq.nb_packets == 0 && self->pictq_size == 0) - break; - boost::this_thread::sleep(boost::posix_time::milliseconds(100)); - } } catch(std::runtime_error& e) { std::cerr << "An error occured playing the video: " << e.what () << std::endl; @@ -433,17 +524,14 @@ void VideoState::decode_thread_loop(VideoState *self) std::cerr << "An error occured playing the video: " << e.getFullDescription () << std::endl; } - self->quit = true; + self->mQuit = true; } bool VideoState::update() { - if(this->quit) - return false; - this->video_refresh(); - return true; + return !this->mVideoEnded; } @@ -510,7 +598,7 @@ void VideoState::init(const std::string& resourceName) unsigned int i; this->av_sync_type = AV_SYNC_DEFAULT; - this->quit = false; + this->mQuit = false; this->stream = Ogre::ResourceGroupManager::getSingleton().openResource(resourceName); if(this->stream.isNull()) @@ -564,7 +652,7 @@ void VideoState::init(const std::string& resourceName) audio_index = i; } - this->external_clock_base = av_gettime(); + mExternalClock.set(0); if(audio_index >= 0) this->stream_open(audio_index, this->format_ctx); @@ -572,24 +660,6 @@ void VideoState::init(const std::string& resourceName) if(video_index >= 0) { this->stream_open(video_index, this->format_ctx); - - int width = (*this->video_st)->codec->width; - int height = (*this->video_st)->codec->height; - static int i = 0; - this->mTexture = Ogre::TextureManager::getSingleton().createManual( - "ffmpeg/VideoTexture" + Ogre::StringConverter::toString(++i), - Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - Ogre::TEX_TYPE_2D, - width, height, - 0, - Ogre::PF_BYTE_RGBA, - Ogre::TU_DYNAMIC_WRITE_ONLY_DISCARDABLE); - - // initialize to (0,0,0,0) - std::vector buffer; - buffer.resize(width * height, 0); - Ogre::PixelBox pb(width, height, 1, Ogre::PF_BYTE_RGBA, &buffer[0]); - this->mTexture->getBuffer()->blitFromMemory(pb); } @@ -598,12 +668,12 @@ void VideoState::init(const std::string& resourceName) void VideoState::deinit() { - this->quit = true; + this->mQuit = true; - mAudioDecoder.reset(); + this->audioq.flush(); + this->videoq.flush(); - this->audioq.cond.notify_one(); - this->videoq.cond.notify_one(); + mAudioDecoder.reset(); if (this->parse_thread.joinable()) this->parse_thread.join(); @@ -639,11 +709,17 @@ void VideoState::deinit() } avformat_close_input(&this->format_ctx); } + + if (!mTexture.isNull()) + { + Ogre::TextureManager::getSingleton().remove(mTexture->getName()); + mTexture.setNull(); + } } double VideoState::get_external_clock() { - return ((uint64_t)av_gettime()-this->external_clock_base) / 1000000.0; + return mExternalClock.get() / 1000000.0; } double VideoState::get_master_clock() @@ -667,5 +743,62 @@ double VideoState::get_audio_clock() return mAudioDecoder->getAudioClock(); } +void VideoState::setPaused(bool isPaused) +{ + this->mPaused = isPaused; + mExternalClock.setPaused(isPaused); +} + +void VideoState::seekTo(double time) +{ + time = std::max(0.0, time); + time = std::min(getDuration(), time); + mSeekPos = (uint64_t) (time * AV_TIME_BASE); + mSeekRequested = true; +} + +double VideoState::getDuration() +{ + return this->format_ctx->duration / 1000000.0; +} + + +ExternalClock::ExternalClock() + : mTimeBase(av_gettime()) + , mPausedAt(0) + , mPaused(false) +{ +} + +void ExternalClock::setPaused(bool paused) +{ + boost::mutex::scoped_lock lock(mMutex); + if (mPaused == paused) + return; + if (paused) + { + mPausedAt = av_gettime() - mTimeBase; + } + else + mTimeBase = av_gettime() - mPausedAt; + mPaused = paused; +} + +uint64_t ExternalClock::get() +{ + boost::mutex::scoped_lock lock(mMutex); + if (mPaused) + return mPausedAt; + else + return av_gettime() - mTimeBase; +} + +void ExternalClock::set(uint64_t time) +{ + boost::mutex::scoped_lock lock(mMutex); + mTimeBase = av_gettime() - time; + mPausedAt = time; +} + } diff --git a/extern/ogre-ffmpeg-videoplayer/videostate.hpp b/extern/ogre-ffmpeg-videoplayer/videostate.hpp index 90ebec0a3..cdeb2d0e3 100644 --- a/extern/ogre-ffmpeg-videoplayer/videostate.hpp +++ b/extern/ogre-ffmpeg-videoplayer/videostate.hpp @@ -27,6 +27,21 @@ struct VideoState; class MovieAudioFactory; class MovieAudioDecoder; +struct ExternalClock +{ + ExternalClock(); + + uint64_t mTimeBase; + uint64_t mPausedAt; + bool mPaused; + + boost::mutex mMutex; + + void setPaused(bool paused); + uint64_t get(); + void set(uint64_t time); +}; + struct PacketQueue { PacketQueue() : first_pkt(NULL), last_pkt(NULL), flushing(false), nb_packets(0), size(0) @@ -66,6 +81,11 @@ struct VideoState { void init(const std::string& resourceName); void deinit(); + void setPaused(bool isPaused); + void seekTo(double time); + + double getDuration(); + int stream_open(int stream_index, AVFormatContext *pFormatCtx); bool update(); @@ -93,15 +113,18 @@ struct VideoState { MovieAudioFactory* mAudioFactory; boost::shared_ptr mAudioDecoder; + ExternalClock mExternalClock; + Ogre::DataStreamPtr stream; AVFormatContext* format_ctx; int av_sync_type; - uint64_t external_clock_base; AVStream** audio_st; PacketQueue audioq; + uint8_t* mFlushPktData; + AVStream** video_st; double frame_last_pts; double video_clock; /// shadowFar_fadeStart.x) ? 1.0 : ((depthPassthrough > shadowFar_fadeStart.y) ? 1.0-((1.0-shadow)*fade) : shadow); #endif @@ -514,11 +514,11 @@ #endif #if UNDERWATER - float3 waterEyePos = intercept(worldPos, cameraPos.xyz - worldPos, float3(0,0,1), waterLevel); + float3 waterEyePos = intercept(worldPos, cameraPos.xyz - worldPos, float3(0.0,0.0,1.0), waterLevel); #endif #if SHADOWS || SHADOWS_PSSM - shOutputColour(0) *= (lightResult - float4(directionalResult * (1.0-shadow),0)); + shOutputColour(0) *= (lightResult - float4(directionalResult * (1.0-shadow),0.0)); #else shOutputColour(0) *= lightResult; #endif @@ -574,7 +574,7 @@ #endif // prevent negative colour output (for example with negative lights) - shOutputColour(0).xyz = max(shOutputColour(0).xyz, float3(0,0,0)); + shOutputColour(0).xyz = max(shOutputColour(0).xyz, float3(0.0,0.0,0.0)); } #endif diff --git a/files/materials/shadows.h b/files/materials/shadows.h index 65dffe492..eba3a3ea7 100644 --- a/files/materials/shadows.h +++ b/files/materials/shadows.h @@ -6,11 +6,11 @@ float depthShadowPCF (shTexture2D shadowMap, float4 shadowMapPos, float2 offset) shadowMapPos /= shadowMapPos.w; float3 o = float3(offset.xy, -offset.x) * 0.3; //float3 o = float3(0,0,0); - float c = (shadowMapPos.z <= FIXED_BIAS + shSample(shadowMap, shadowMapPos.xy - o.xy).r) ? 1 : 0; // top left - c += (shadowMapPos.z <= FIXED_BIAS + shSample(shadowMap, shadowMapPos.xy + o.xy).r) ? 1 : 0; // bottom right - c += (shadowMapPos.z <= FIXED_BIAS + shSample(shadowMap, shadowMapPos.xy + o.zy).r) ? 1 : 0; // bottom left - c += (shadowMapPos.z <= FIXED_BIAS + shSample(shadowMap, shadowMapPos.xy - o.zy).r) ? 1 : 0; // top right - return c / 4; + float c = (shadowMapPos.z <= FIXED_BIAS + shSample(shadowMap, shadowMapPos.xy - o.xy).r) ? 1.0 : 0.0; // top left + c += (shadowMapPos.z <= FIXED_BIAS + shSample(shadowMap, shadowMapPos.xy + o.xy).r) ? 1.0 : 0.0; // bottom right + c += (shadowMapPos.z <= FIXED_BIAS + shSample(shadowMap, shadowMapPos.xy + o.zy).r) ? 1.0 : 0.0; // bottom left + c += (shadowMapPos.z <= FIXED_BIAS + shSample(shadowMap, shadowMapPos.xy - o.zy).r) ? 1.0 : 0.0; // top right + return c / 4.0; } diff --git a/files/mygui/openmw_book.layout b/files/mygui/openmw_book.layout index 3b1cfea64..2336d5b2c 100644 --- a/files/mygui/openmw_book.layout +++ b/files/mygui/openmw_book.layout @@ -2,47 +2,51 @@ - + - + - + - - + + - - + + - + - + - + + + - + + + - - + + diff --git a/files/mygui/openmw_chargen_create_class.layout b/files/mygui/openmw_chargen_create_class.layout index dee2f4fcf..1d071e621 100644 --- a/files/mygui/openmw_chargen_create_class.layout +++ b/files/mygui/openmw_chargen_create_class.layout @@ -3,7 +3,7 @@ - + diff --git a/files/mygui/openmw_stats_window.layout b/files/mygui/openmw_stats_window.layout index 6cdd4c02a..11119c404 100644 --- a/files/mygui/openmw_stats_window.layout +++ b/files/mygui/openmw_stats_window.layout @@ -69,33 +69,46 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +