From f29c4086cd575a83c1ef29b078c64e052bde3468 Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Sun, 12 Oct 2014 15:18:37 +0200 Subject: [PATCH 01/30] Fixes #1982: Long class names are cut off in the UI Increased length of text filed for race, class name in stats window, and class name cation in chargen create class window. Signed-off-by: Lukasz Gromanowski --- files/mygui/openmw_chargen_create_class.layout | 2 +- files/mygui/openmw_stats_window.layout | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/files/mygui/openmw_chargen_create_class.layout b/files/mygui/openmw_chargen_create_class.layout index dee2f4fcf7..1d071e6217 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 6cdd4c02ae..0b8dee5c8d 100644 --- a/files/mygui/openmw_stats_window.layout +++ b/files/mygui/openmw_stats_window.layout @@ -89,11 +89,11 @@ - + - + From 02f0b7caa38a7d2342c9dcf0fa6798b3fc507244 Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Thu, 16 Oct 2014 23:22:22 +0200 Subject: [PATCH 02/30] Fixes #1982: Long class names are cut off in the UI Added HBox widget with AutoSizedTextBox, spacer, and TextBox for level, race, class caption and text pairs. Signed-off-by: Lukasz Gromanowski --- files/mygui/openmw_stats_window.layout | 66 ++++++++++++++++---------- 1 file changed, 42 insertions(+), 24 deletions(-) diff --git a/files/mygui/openmw_stats_window.layout b/files/mygui/openmw_stats_window.layout index 0b8dee5c8d..df0a3f39ff 100644 --- a/files/mygui/openmw_stats_window.layout +++ b/files/mygui/openmw_stats_window.layout @@ -70,32 +70,50 @@ - - - - + + + + + + + + + + + + + + - - - - + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + From 6ff41c6a0063d1a2ea149c63bb6725eeea95c158 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 23 Oct 2014 11:28:58 +0200 Subject: [PATCH 03/30] intercept shift/ctrl double-clicks in tables --- apps/opencs/view/world/table.cpp | 13 +++++++++++++ apps/opencs/view/world/table.hpp | 4 ++++ 2 files changed, 17 insertions(+) diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index 6adf3e0c13..168a06356a 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -177,6 +177,19 @@ void CSVWorld::Table::contextMenuEvent (QContextMenuEvent *event) menu.exec (event->globalPos()); } +void CSVWorld::Table::mouseDoubleClickEvent (QMouseEvent *event) +{ + Qt::KeyboardModifiers modifiers = + event->modifiers() & (Qt::ShiftModifier | Qt::ControlModifier); + + if (!modifiers) + DragRecordTable::mouseDoubleClickEvent (event); + else + { + + } +} + CSVWorld::Table::Table (const CSMWorld::UniversalId& id, bool createAndDelete, bool sorting, CSMDoc::Document& document) : mCreateAction (0), mCloneAction(0), mRecordStatusDisplay (0), diff --git a/apps/opencs/view/world/table.hpp b/apps/opencs/view/world/table.hpp index a80a0b3620..9bd561bdac 100644 --- a/apps/opencs/view/world/table.hpp +++ b/apps/opencs/view/world/table.hpp @@ -64,6 +64,10 @@ namespace CSVWorld void dropEvent(QDropEvent *event); + protected: + + virtual void mouseDoubleClickEvent (QMouseEvent *event); + public: Table (const CSMWorld::UniversalId& id, bool createAndDelete, From e2bad395e573b62ac1c836b97e37e44f1da59fca Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 24 Oct 2014 18:07:17 +0200 Subject: [PATCH 04/30] Leak fix --- apps/openmw/mwgui/windowmanagerimp.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index f431bc8f16..6ab8b94c5c 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(); From 925fa8d1931b909d688e95246e96c056fd82b46e Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Fri, 24 Oct 2014 12:46:14 +0200 Subject: [PATCH 05/30] Reset ownership of items dropped via 'drop' instruction (Fixes #2053) --- apps/openmw/mwscript/miscextensions.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 0de8f3b919..c7d221139c 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; From fa746b8e54a54c3ba9fb9399d21795791dc28f3c Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Fri, 24 Oct 2014 13:05:39 +0200 Subject: [PATCH 06/30] Do not display weight or value in tooltip for zero-weight items (Fixes #2047) --- apps/openmw/mwclass/light.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 7b2d7e132e..e6d266de25 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()); From ed3a3f717f3387fdf8978862d78d50a0e0cc5dbd Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Fri, 24 Oct 2014 18:49:38 +0200 Subject: [PATCH 07/30] Handle getdistance on objects inside a container (Fixes #2046) --- apps/openmw/mwbase/world.hpp | 4 ++ apps/openmw/mwscript/interpretercontext.cpp | 11 ++++++ apps/openmw/mwworld/cellstore.hpp | 11 ++++++ apps/openmw/mwworld/containerstore.cpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 41 +++++++++++++++++++++ apps/openmw/mwworld/worldimp.hpp | 4 ++ 6 files changed, 72 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 71a45a92cc..c1a889913a 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/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index cb02a6c978..52021839d9 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/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index ba6fad7baa..e322ef4a40 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 085b079d9d..45728371bf 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 d8e0d52b8b..5d07a26a09 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 334e799f23..fef2797050 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 From b39d69e98c859a78b813abc70099372763a07bc8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 24 Oct 2014 21:19:17 +0200 Subject: [PATCH 08/30] Videoplayer fixes, play/pause & seeking - Fix rindex overflow - Fix audio sample size bugs (was using sample_fmt and channel count of the decoder, instead of the resampled settings). We didn't notice this bug before, because the OpenAL MovieAudioFactory tries to resample to a format of the same byte size. - Add support for play/pause and seeking controls (not used by cutscenes in OpenMW) - Closing the video when arriving at the stream end is now handled by the user (we may also want to keep the video open and seek back) The video player now has a standalone demo, at https://github.com/scrawl/ogre-ffmpeg-videoplayer --- apps/openmw/mwgui/videowidget.cpp | 3 +- apps/openmw/mwsound/ffmpeg_decoder.cpp | 6 +- apps/openmw/mwsound/movieaudiofactory.cpp | 4 +- extern/ogre-ffmpeg-videoplayer/CMakeLists.txt | 15 +- .../ogre-ffmpeg-videoplayer/audiodecoder.cpp | 40 +++- .../ogre-ffmpeg-videoplayer/audiodecoder.hpp | 5 +- .../ogre-ffmpeg-videoplayer/videoplayer.cpp | 58 +++-- .../ogre-ffmpeg-videoplayer/videoplayer.hpp | 19 +- extern/ogre-ffmpeg-videoplayer/videostate.cpp | 216 +++++++++++++++--- extern/ogre-ffmpeg-videoplayer/videostate.hpp | 33 ++- 10 files changed, 319 insertions(+), 80 deletions(-) diff --git a/apps/openmw/mwgui/videowidget.cpp b/apps/openmw/mwgui/videowidget.cpp index 76fdd52878..f8054925b6 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/mwsound/ffmpeg_decoder.cpp b/apps/openmw/mwsound/ffmpeg_decoder.cpp index a2998ad03d..b086d4aedf 100644 --- a/apps/openmw/mwsound/ffmpeg_decoder.cpp +++ b/apps/openmw/mwsound/ffmpeg_decoder.cpp @@ -148,7 +148,7 @@ size_t FFmpeg_Decoder::readAVAudioData(void *data, size_t length) break; mFramePos = 0; mFrameSize = mFrame->nb_samples * (*mStream)->codec->channels * - av_get_bytes_per_sample((*mStream)->codec->sample_fmt); + av_get_bytes_per_sample(mOutputSampleFormat); } /* Get the amount of bytes remaining to be written, and clamp to @@ -384,7 +384,7 @@ 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); + av_get_bytes_per_sample(mOutputSampleFormat); const char *inbuf = reinterpret_cast(mFrameData[0]); output.insert(output.end(), inbuf, inbuf+got); } @@ -403,7 +403,7 @@ 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); + av_get_bytes_per_sample(mOutputSampleFormat); return (int)(mNextPts*(*mStream)->codec->sample_rate) - delay; } diff --git a/apps/openmw/mwsound/movieaudiofactory.cpp b/apps/openmw/mwsound/movieaudiofactory.cpp index bc7bb80234..97925c7c51 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; } diff --git a/extern/ogre-ffmpeg-videoplayer/CMakeLists.txt b/extern/ogre-ffmpeg-videoplayer/CMakeLists.txt index f34ffa64bf..299a57799b 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 54fe2b24f9..41313d5d5d 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 88406d51d3..b05b16d428 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/videoplayer.cpp b/extern/ogre-ffmpeg-videoplayer/videoplayer.cpp index 434b676ee0..d80449199d 100644 --- a/extern/ogre-ffmpeg-videoplayer/videoplayer.cpp +++ b/extern/ogre-ffmpeg-videoplayer/videoplayer.cpp @@ -38,19 +38,17 @@ void VideoPlayer::playVideo(const std::string &resourceName) } } -void VideoPlayer::update () +bool VideoPlayer::update () { if(mState) - { - if(!mState->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 +56,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 +64,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 +80,48 @@ void VideoPlayer::close() } } -bool VideoPlayer::isPlaying () -{ - return mState != NULL; -} - bool VideoPlayer::hasAudioStream() { return mState && mState->audio_st != NULL; } +void VideoPlayer::play() +{ + if (mState) + mState->setPaused(false); +} + +void VideoPlayer::pause() +{ + 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 750ad02e57..2727ac6f08 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 c77723421f..7ac7a122cb 100644 --- a/extern/ogre-ffmpeg-videoplayer/videostate.cpp +++ b/extern/ogre-ffmpeg-videoplayer/videostate.cpp @@ -31,6 +31,18 @@ extern "C" } +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 +58,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 +93,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 +120,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 +159,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; @@ -205,6 +222,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,12 +230,11 @@ 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 { @@ -236,19 +253,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 +276,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 +310,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 +370,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 +426,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 +495,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 +511,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 +519,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 +593,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 +647,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); @@ -598,13 +681,13 @@ void VideoState::init(const std::string& resourceName) void VideoState::deinit() { - this->quit = true; + this->mQuit = true; + + this->audioq.flush(); + this->videoq.flush(); mAudioDecoder.reset(); - this->audioq.cond.notify_one(); - this->videoq.cond.notify_one(); - if (this->parse_thread.joinable()) this->parse_thread.join(); if (this->video_thread.joinable()) @@ -643,7 +726,7 @@ void VideoState::deinit() 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 +750,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 90ebec0a38..cdeb2d0e39 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; /// Date: Sat, 25 Oct 2014 00:14:51 +0200 Subject: [PATCH 09/30] Add possibly missing include for av_rescale_q --- extern/ogre-ffmpeg-videoplayer/videostate.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/extern/ogre-ffmpeg-videoplayer/videostate.cpp b/extern/ogre-ffmpeg-videoplayer/videostate.cpp index 7ac7a122cb..cc6308b146 100644 --- a/extern/ogre-ffmpeg-videoplayer/videostate.cpp +++ b/extern/ogre-ffmpeg-videoplayer/videostate.cpp @@ -25,6 +25,8 @@ extern "C" #include #endif + #include + #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(55,28,1) #define av_frame_alloc avcodec_alloc_frame #endif From dbe30e31b935dbdf60136e3121b7b67cd17d93fb Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 25 Oct 2014 00:56:43 +0200 Subject: [PATCH 10/30] Make creature's model take priority over base_anim.nif (Fixes #2055) --- apps/openmw/mwrender/creatureanimation.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index 247a0ba146..fef9fa644f 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); From e01795556f3a04b4e5ff202e7c154df09b85080d Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 25 Oct 2014 10:37:57 +1100 Subject: [PATCH 11/30] Suppress some warnings for MSVC. --- apps/openmw/mwgui/formatting.hpp | 1 + extern/ogre-ffmpeg-videoplayer/audiofactory.hpp | 1 + extern/ogre-ffmpeg-videoplayer/videostate.cpp | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/formatting.hpp b/apps/openmw/mwgui/formatting.hpp index 3e21b62e27..5b79250577 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/extern/ogre-ffmpeg-videoplayer/audiofactory.hpp b/extern/ogre-ffmpeg-videoplayer/audiofactory.hpp index cf1ff46a85..06abd6a741 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/videostate.cpp b/extern/ogre-ffmpeg-videoplayer/videostate.cpp index c77723421f..ece491edc1 100644 --- a/extern/ogre-ffmpeg-videoplayer/videostate.cpp +++ b/extern/ogre-ffmpeg-videoplayer/videostate.cpp @@ -221,7 +221,7 @@ void VideoState::video_refresh() } 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 From 69d0c7fd7090b84729fbd3ca48870b0501f1ffb4 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 25 Oct 2014 10:40:33 +1100 Subject: [PATCH 12/30] Cleanup leftover from previous osx support attempts. --- cmake/FindOGRE.cmake | 1 - 1 file changed, 1 deletion(-) diff --git a/cmake/FindOGRE.cmake b/cmake/FindOGRE.cmake index 51589698f2..f2acf9d337 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 From ea67cf0ebeb87e29db96c555c2be217bdd91bba0 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 25 Oct 2014 15:37:09 +1100 Subject: [PATCH 13/30] Try the fix again. --- extern/ogre-ffmpeg-videoplayer/audiofactory.hpp | 1 - extern/ogre-ffmpeg-videoplayer/videoplayer.cpp | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/extern/ogre-ffmpeg-videoplayer/audiofactory.hpp b/extern/ogre-ffmpeg-videoplayer/audiofactory.hpp index 06abd6a741..cf1ff46a85 100644 --- a/extern/ogre-ffmpeg-videoplayer/audiofactory.hpp +++ b/extern/ogre-ffmpeg-videoplayer/audiofactory.hpp @@ -12,7 +12,6 @@ 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 434b676ee0..5487e916a2 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 From d7716e7314a4054038a5c7119d1c1f128608fa57 Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Sat, 25 Oct 2014 09:37:51 +0200 Subject: [PATCH 14/30] Fixes #1982: Long class names are cut off in the UI Corrected HBox, AutoSizedTextBox and TextBox positions and alignment. Signed-off-by: Lukasz Gromanowski --- files/mygui/openmw_stats_window.layout | 30 ++++++++++---------------- 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/files/mygui/openmw_stats_window.layout b/files/mygui/openmw_stats_window.layout index df0a3f39ff..ef6db8323b 100644 --- a/files/mygui/openmw_stats_window.layout +++ b/files/mygui/openmw_stats_window.layout @@ -69,47 +69,39 @@ - - - + + + - - - - + + - - + + - - - - + - - + + - - - - + From a9f5632afdbdd5360626318090595387f5044dc6 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 25 Oct 2014 16:27:36 +0200 Subject: [PATCH 15/30] extended double click functionality in tables --- apps/opencs/view/world/table.cpp | 76 +++++++++++++++++++++++-- apps/opencs/view/world/table.hpp | 16 +++++- apps/opencs/view/world/tablesubview.cpp | 7 +++ apps/opencs/view/world/tablesubview.hpp | 2 + 4 files changed, 96 insertions(+), 5 deletions(-) diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index 168a06356a..0502e7bbf3 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -182,11 +182,71 @@ void CSVWorld::Table::mouseDoubleClickEvent (QMouseEvent *event) Qt::KeyboardModifiers modifiers = event->modifiers() & (Qt::ShiftModifier | Qt::ControlModifier); - if (!modifiers) - DragRecordTable::mouseDoubleClickEvent (event); - else - { + QModelIndex index = currentIndex(); + selectionModel()->select (index, + QItemSelectionModel::Clear | QItemSelectionModel::Select | QItemSelectionModel::Rows); + + std::map::iterator iter = + mDoubleClickActions.find (modifiers); + + if (iter==mDoubleClickActions.end()) + { + event->accept(); + return; + } + + switch (iter->second) + { + case Action_None: + + event->accept(); + break; + + case Action_InPlaceEdit: + + DragRecordTable::mouseDoubleClickEvent (event); + break; + + case Action_EditRecord: + + event->accept(); + editRecord(); + break; + + case Action_View: + + event->accept(); + viewRecord(); + break; + + case Action_Revert: + + event->accept(); + if (mDispatcher->canRevert()) + mDispatcher->executeRevert(); + break; + + case Action_Delete: + + event->accept(); + if (mDispatcher->canDelete()) + mDispatcher->executeDelete(); + break; + + case Action_EditRecordAndClose: + + event->accept(); + editRecord(); + emit closeRequest(); + break; + + case Action_ViewAndClose: + + event->accept(); + viewRecord(); + emit closeRequest(); + break; } } @@ -297,6 +357,11 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id, this, SLOT (selectionSizeUpdate ())); setAcceptDrops(true); + + mDoubleClickActions.insert (std::make_pair (0, Action_InPlaceEdit)); + mDoubleClickActions.insert (std::make_pair (Qt::ShiftModifier, Action_EditRecord)); + mDoubleClickActions.insert (std::make_pair (Qt::ControlModifier, Action_View)); + mDoubleClickActions.insert (std::make_pair (Qt::ShiftModifier | Qt::ControlModifier, Action_EditRecordAndClose)); } void CSVWorld::Table::setEditLock (bool locked) @@ -417,6 +482,9 @@ void CSVWorld::Table::editCell() void CSVWorld::Table::viewRecord() { + if (!(mModel->getFeatures() & CSMWorld::IdTableBase::Feature_View)) + return; + QModelIndexList selectedRows = selectionModel()->selectedRows(); if (selectedRows.size()==1) diff --git a/apps/opencs/view/world/table.hpp b/apps/opencs/view/world/table.hpp index 9bd561bdac..75161b8b65 100644 --- a/apps/opencs/view/world/table.hpp +++ b/apps/opencs/view/world/table.hpp @@ -36,6 +36,18 @@ namespace CSVWorld { Q_OBJECT + enum DoubleClickAction + { + Action_None, + Action_InPlaceEdit, + Action_EditRecord, + Action_View, + Action_Revert, + Action_Delete, + Action_EditRecordAndClose, + Action_ViewAndClose + }; + std::vector mDelegates; QAction *mEditAction; QAction *mCreateAction; @@ -53,8 +65,8 @@ namespace CSVWorld CSMWorld::IdTableBase *mModel; int mRecordStatusDisplay; CSMWorld::CommandDispatcher *mDispatcher; - CSMWorld::UniversalId mEditCellId; + std::map mDoubleClickActions; private: @@ -98,6 +110,8 @@ namespace CSVWorld void cloneRequest(const CSMWorld::UniversalId&); + void closeRequest(); + private slots: void editCell(); diff --git a/apps/opencs/view/world/tablesubview.cpp b/apps/opencs/view/world/tablesubview.cpp index e2c8d5c1e3..8374da35d0 100644 --- a/apps/opencs/view/world/tablesubview.cpp +++ b/apps/opencs/view/world/tablesubview.cpp @@ -69,6 +69,8 @@ CSVWorld::TableSubView::TableSubView (const CSMWorld::UniversalId& id, CSMDoc::D connect(mFilterBox, SIGNAL(recordDropped(std::vector&, Qt::DropAction)), this, SLOT(createFilterRequest(std::vector&, Qt::DropAction))); + + connect (mTable, SIGNAL (closeRequest()), this, SLOT (closeRequest())); } void CSVWorld::TableSubView::setEditLock (bool locked) @@ -150,3 +152,8 @@ bool CSVWorld::TableSubView::eventFilter (QObject* object, QEvent* event) } return false; } + +void CSVWorld::TableSubView::closeRequest() +{ + deleteLater(); +} diff --git a/apps/opencs/view/world/tablesubview.hpp b/apps/opencs/view/world/tablesubview.hpp index 9d86c32e40..ad5f334bfc 100644 --- a/apps/opencs/view/world/tablesubview.hpp +++ b/apps/opencs/view/world/tablesubview.hpp @@ -63,6 +63,8 @@ namespace CSVWorld void cloneRequest (const CSMWorld::UniversalId& toClone); void createFilterRequest(std::vector< CSMWorld::UniversalId >& types, Qt::DropAction action); + + void closeRequest(); }; } From c9750dc7c69fc9d792a020a5c08c7d8abaff8d1c Mon Sep 17 00:00:00 2001 From: sylar Date: Sat, 25 Oct 2014 19:00:23 +0400 Subject: [PATCH 16/30] fixes shadows on glsles --- files/materials/objects.shader | 8 ++++---- files/materials/shadows.h | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/files/materials/objects.shader b/files/materials/objects.shader index 87330e34e2..2368d99616 100644 --- a/files/materials/objects.shader +++ b/files/materials/objects.shader @@ -499,7 +499,7 @@ #if SHADOWS || SHADOWS_PSSM float fadeRange = shadowFar_fadeStart.x - shadowFar_fadeStart.y; - float fade = 1-((depthPassthrough - shadowFar_fadeStart.y) / fadeRange); + float fade = 1.0-((depthPassthrough - shadowFar_fadeStart.y) / fadeRange); shadow = (depthPassthrough > 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 65dffe4923..eba3a3ea74 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; } From 55c9c0a26634d0e4742eb562197ab2d1d39aee29 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 25 Oct 2014 17:17:57 +0200 Subject: [PATCH 17/30] Audio resampling fixes - Don't try to use float audio or extended channel layouts if the hardware does not support them - Add channel layout resampling support to ffmpeg_decoder --- apps/openmw/mwsound/ffmpeg_decoder.cpp | 85 ++++++++++++----------- apps/openmw/mwsound/ffmpeg_decoder.hpp | 1 + apps/openmw/mwsound/movieaudiofactory.cpp | 21 +++--- 3 files changed, 56 insertions(+), 51 deletions(-) diff --git a/apps/openmw/mwsound/ffmpeg_decoder.cpp b/apps/openmw/mwsound/ffmpeg_decoder.cpp index b086d4aedf..b4307e3956 100644 --- a/apps/openmw/mwsound/ffmpeg_decoder.cpp +++ b/apps/openmw/mwsound/ffmpeg_decoder.cpp @@ -5,6 +5,8 @@ #include +#include "al.h" + extern "C" { #ifndef HAVE_LIBSWRESAMPLE // FIXME: remove this section once libswresample is packaged for Debian @@ -112,7 +114,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,7 +149,7 @@ size_t FFmpeg_Decoder::readAVAudioData(void *data, size_t length) if(!getAVAudioData()) break; mFramePos = 0; - mFrameSize = mFrame->nb_samples * (*mStream)->codec->channels * + mFrameSize = mFrame->nb_samples * av_get_channel_layout_nb_channels(mOutputChannelLayout) * av_get_bytes_per_sample(mOutputSampleFormat); } @@ -285,47 +287,32 @@ 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) + && alIsExtensionPresent("AL_EXT_FLOAT32")) + mOutputSampleFormat = AV_SAMPLE_FMT_FLT; 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) - *type = SampleType_Int16; - else if((*mStream)->codec->sample_fmt == AV_SAMPLE_FMT_FLTP) - *type = SampleType_Float32; + mOutputSampleFormat = AV_SAMPLE_FMT_S16; else - fail(std::string("Unsupported sample format: ")+ - av_get_sample_fmt_name((*mStream)->codec->sample_fmt)); + 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(mOutputSampleFormat == AV_SAMPLE_FMT_FLT) + *type = SampleType_Float32; 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 +320,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) && !alIsExtensionPresent("AL_EXT_MCFORMATS")) + 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 +349,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,7 +383,7 @@ void FFmpeg_Decoder::readAll(std::vector &output) while(getAVAudioData()) { - size_t got = mFrame->nb_samples * (*mStream)->codec->channels * + 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,7 +402,7 @@ void FFmpeg_Decoder::rewind() size_t FFmpeg_Decoder::getSampleOffset() { - int delay = (mFrameSize-mFramePos) / (*mStream)->codec->channels / + 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 +416,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 796f173508..2cdbbf363d 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 97925c7c51..2a978b115c 100644 --- a/apps/openmw/mwsound/movieaudiofactory.cpp +++ b/apps/openmw/mwsound/movieaudiofactory.cpp @@ -6,6 +6,8 @@ #include "../mwbase/environment.hpp" #include "../mwbase/soundmanager.hpp" +#include "al.h" + #include "sound_decoder.hpp" #include "sound.hpp" @@ -64,20 +66,21 @@ 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) + else if ((sampleFormat == AV_SAMPLE_FMT_FLTP || sampleFormat == AV_SAMPLE_FMT_FLT) + && alIsExtensionPresent("AL_EXT_FLOAT32")) sampleFormat = AV_SAMPLE_FMT_FLT; 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) && !alIsExtensionPresent("AL_EXT_MCFORMATS")) + channelLayout = AV_CH_LAYOUT_STEREO; + else if (channelLayout != AV_CH_LAYOUT_MONO + && channelLayout != AV_CH_LAYOUT_STEREO) channelLayout = AV_CH_LAYOUT_STEREO; } From 6126b3b84a33186ebe3d7230c71bb3ffc963878a Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 25 Oct 2014 17:26:20 +0200 Subject: [PATCH 18/30] Videoplayer: wait until we have the first picture before returning from playVideo() --- .../ogre-ffmpeg-videoplayer/videoplayer.cpp | 7 ++++ extern/ogre-ffmpeg-videoplayer/videostate.cpp | 41 ++++++++----------- 2 files changed, 23 insertions(+), 25 deletions(-) diff --git a/extern/ogre-ffmpeg-videoplayer/videoplayer.cpp b/extern/ogre-ffmpeg-videoplayer/videoplayer.cpp index d80449199d..ac759804b4 100644 --- a/extern/ogre-ffmpeg-videoplayer/videoplayer.cpp +++ b/extern/ogre-ffmpeg-videoplayer/videoplayer.cpp @@ -31,6 +31,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: "<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(); @@ -657,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); } @@ -724,6 +709,12 @@ 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() From aad13e6bffa332e4a497c42e61f4837e2e9fca2d Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 25 Oct 2014 18:13:56 +0200 Subject: [PATCH 19/30] close view when closing last sub-view unless this view is the last view --- apps/opencs/view/doc/subview.cpp | 5 +++++ apps/opencs/view/doc/subview.hpp | 6 ++++++ apps/opencs/view/doc/view.cpp | 12 +++++++++++- apps/opencs/view/doc/view.hpp | 2 ++ apps/opencs/view/world/previewsubview.cpp | 5 ----- apps/opencs/view/world/previewsubview.hpp | 2 -- apps/opencs/view/world/scenesubview.cpp | 5 ----- apps/opencs/view/world/scenesubview.hpp | 2 -- apps/opencs/view/world/scriptsubview.cpp | 2 +- apps/opencs/view/world/tablesubview.cpp | 4 ---- apps/opencs/view/world/tablesubview.hpp | 2 -- 11 files changed, 25 insertions(+), 22 deletions(-) diff --git a/apps/opencs/view/doc/subview.cpp b/apps/opencs/view/doc/subview.cpp index ab4325cfc6..1af6a7a2f3 100644 --- a/apps/opencs/view/doc/subview.cpp +++ b/apps/opencs/view/doc/subview.cpp @@ -35,3 +35,8 @@ void CSVDoc::SubView::closeEvent (QCloseEvent *event) if(mParent) mParent->updateSubViewIndicies(this); } + +void CSVDoc::SubView::closeRequest() +{ + emit closeRequest (this); +} \ No newline at end of file diff --git a/apps/opencs/view/doc/subview.hpp b/apps/opencs/view/doc/subview.hpp index 6a3ddd8bd7..60478f0bc7 100644 --- a/apps/opencs/view/doc/subview.hpp +++ b/apps/opencs/view/doc/subview.hpp @@ -57,6 +57,12 @@ namespace CSVDoc void focusId (const CSMWorld::UniversalId& universalId, const std::string& hint); + void closeRequest (SubView *subView); + + protected slots: + + void closeRequest(); + public slots: virtual void updateUserSetting (const QString &, const QStringList &); diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index d36e019015..299c078056 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -323,7 +323,7 @@ void CSVDoc::View::updateSubViewIndicies(SubView *view) if(view && mSubViews.contains(view)) mSubViews.removeOne(view); - if(mSubViews.size() == 1) + if (mSubViews.size() == 1) { if(!mSubViews.at(0)->isFloating()) { @@ -518,6 +518,8 @@ void CSVDoc::View::addSubView (const CSMWorld::UniversalId& id, const std::strin view, SLOT (updateUserSetting (const QString &, const QStringList &))); + connect (view, SIGNAL (closeRequest (SubView *)), this, SLOT (closeRequest (SubView *))); + view->show(); } @@ -761,3 +763,11 @@ void CSVDoc::View::stop() { mDocument->stopRunning(); } + +void CSVDoc::View::closeRequest (SubView *subView) +{ + if (mSubViews.size()>1 || mViewTotal<=1) + subView->deleteLater(); + else if (mViewManager.closeRequest (this)) + mViewManager.removeDocAndView (mDocument); +} \ No newline at end of file diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index e3ada1f2e4..32ef8071d0 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -222,6 +222,8 @@ namespace CSVDoc void run (const std::string& profile, const std::string& startupInstruction = ""); void stop(); + + void closeRequest (SubView *subView); }; } diff --git a/apps/opencs/view/world/previewsubview.cpp b/apps/opencs/view/world/previewsubview.cpp index 1e106c69fe..dd94a00e01 100644 --- a/apps/opencs/view/world/previewsubview.cpp +++ b/apps/opencs/view/world/previewsubview.cpp @@ -52,11 +52,6 @@ CSVWorld::PreviewSubView::PreviewSubView (const CSMWorld::UniversalId& id, CSMDo void CSVWorld::PreviewSubView::setEditLock (bool locked) {} -void CSVWorld::PreviewSubView::closeRequest() -{ - deleteLater(); -} - void CSVWorld::PreviewSubView::referenceableIdChanged (const std::string& id) { if (id.empty()) diff --git a/apps/opencs/view/world/previewsubview.hpp b/apps/opencs/view/world/previewsubview.hpp index 4ca25c3cbe..fb57ce7a34 100644 --- a/apps/opencs/view/world/previewsubview.hpp +++ b/apps/opencs/view/world/previewsubview.hpp @@ -29,8 +29,6 @@ namespace CSVWorld private slots: - void closeRequest(); - void referenceableIdChanged (const std::string& id); }; } diff --git a/apps/opencs/view/world/scenesubview.cpp b/apps/opencs/view/world/scenesubview.cpp index d10eebb308..4cb6088cca 100644 --- a/apps/opencs/view/world/scenesubview.cpp +++ b/apps/opencs/view/world/scenesubview.cpp @@ -150,11 +150,6 @@ void CSVWorld::SceneSubView::useHint (const std::string& hint) mScene->useViewHint (hint); } -void CSVWorld::SceneSubView::closeRequest() -{ - deleteLater(); -} - void CSVWorld::SceneSubView::cellSelectionChanged (const CSMWorld::UniversalId& id) { setUniversalId(id); diff --git a/apps/opencs/view/world/scenesubview.hpp b/apps/opencs/view/world/scenesubview.hpp index c0905f0d6a..acb7944d81 100644 --- a/apps/opencs/view/world/scenesubview.hpp +++ b/apps/opencs/view/world/scenesubview.hpp @@ -75,8 +75,6 @@ namespace CSVWorld private slots: - void closeRequest(); - void cellSelectionChanged (const CSMWorld::CellSelection& selection); void cellSelectionChanged (const CSMWorld::UniversalId& id); diff --git a/apps/opencs/view/world/scriptsubview.cpp b/apps/opencs/view/world/scriptsubview.cpp index df3fd87be5..22d8e7e51e 100644 --- a/apps/opencs/view/world/scriptsubview.cpp +++ b/apps/opencs/view/world/scriptsubview.cpp @@ -81,6 +81,6 @@ void CSVWorld::ScriptSubView::rowsAboutToBeRemoved (const QModelIndex& parent, i QModelIndex index = mModel->getModelIndex (getUniversalId().getId(), mColumn); if (!parent.isValid() && index.row()>=start && index.row()<=end) - deleteLater(); + emit closeRequest(); } diff --git a/apps/opencs/view/world/tablesubview.cpp b/apps/opencs/view/world/tablesubview.cpp index 8374da35d0..54518023b4 100644 --- a/apps/opencs/view/world/tablesubview.cpp +++ b/apps/opencs/view/world/tablesubview.cpp @@ -153,7 +153,3 @@ bool CSVWorld::TableSubView::eventFilter (QObject* object, QEvent* event) return false; } -void CSVWorld::TableSubView::closeRequest() -{ - deleteLater(); -} diff --git a/apps/opencs/view/world/tablesubview.hpp b/apps/opencs/view/world/tablesubview.hpp index ad5f334bfc..9d86c32e40 100644 --- a/apps/opencs/view/world/tablesubview.hpp +++ b/apps/opencs/view/world/tablesubview.hpp @@ -63,8 +63,6 @@ namespace CSVWorld void cloneRequest (const CSMWorld::UniversalId& toClone); void createFilterRequest(std::vector< CSMWorld::UniversalId >& types, Qt::DropAction action); - - void closeRequest(); }; } From c8a273f5527fc654cf43ba3bf14e191a3fcf4d95 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 25 Oct 2014 19:57:01 +0200 Subject: [PATCH 20/30] Stats window layout fix --- files/mygui/openmw_stats_window.layout | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/files/mygui/openmw_stats_window.layout b/files/mygui/openmw_stats_window.layout index ef6db8323b..11119c4044 100644 --- a/files/mygui/openmw_stats_window.layout +++ b/files/mygui/openmw_stats_window.layout @@ -70,8 +70,8 @@ - - + + @@ -80,10 +80,11 @@ + - + @@ -93,9 +94,10 @@ + - + @@ -105,6 +107,7 @@ + From dc6a99d32a86dc25cf8b891c2770b093e804d807 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 25 Oct 2014 20:00:10 +0200 Subject: [PATCH 21/30] Add missing virtual destructor --- extern/ogre-ffmpeg-videoplayer/audiofactory.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/extern/ogre-ffmpeg-videoplayer/audiofactory.hpp b/extern/ogre-ffmpeg-videoplayer/audiofactory.hpp index cf1ff46a85..06abd6a741 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() {} }; } From ac067564eabc654a8f8c1abfc46b4d46e86e9cfc Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 25 Oct 2014 20:50:41 +0200 Subject: [PATCH 22/30] Don't include al.h in decoder classes, format support check will need to be redone later. For now, resample all formats that might not be supported on any hardware. --- apps/openmw/mwsound/ffmpeg_decoder.cpp | 11 ++++------- apps/openmw/mwsound/movieaudiofactory.cpp | 11 ++++------- 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwsound/ffmpeg_decoder.cpp b/apps/openmw/mwsound/ffmpeg_decoder.cpp index b4307e3956..2002bded7c 100644 --- a/apps/openmw/mwsound/ffmpeg_decoder.cpp +++ b/apps/openmw/mwsound/ffmpeg_decoder.cpp @@ -5,8 +5,6 @@ #include -#include "al.h" - extern "C" { #ifndef HAVE_LIBSWRESAMPLE // FIXME: remove this section once libswresample is packaged for Debian @@ -287,9 +285,8 @@ void FFmpeg_Decoder::getInfo(int *samplerate, ChannelConfig *chans, SampleType * if(!mStream) fail("No audio stream info"); - if(((*mStream)->codec->sample_fmt == AV_SAMPLE_FMT_FLT || (*mStream)->codec->sample_fmt == AV_SAMPLE_FMT_FLTP) - && alIsExtensionPresent("AL_EXT_FLOAT32")) - mOutputSampleFormat = AV_SAMPLE_FMT_FLT; + 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) mOutputSampleFormat = AV_SAMPLE_FMT_U8; else if((*mStream)->codec->sample_fmt == AV_SAMPLE_FMT_S16P) @@ -322,8 +319,8 @@ void FFmpeg_Decoder::getInfo(int *samplerate, ChannelConfig *chans, SampleType * } mOutputChannelLayout = ch_layout; - if ((ch_layout == AV_CH_LAYOUT_5POINT1 || ch_layout == AV_CH_LAYOUT_7POINT1 - || ch_layout == AV_CH_LAYOUT_QUAD) && !alIsExtensionPresent("AL_EXT_MCFORMATS")) + 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) diff --git a/apps/openmw/mwsound/movieaudiofactory.cpp b/apps/openmw/mwsound/movieaudiofactory.cpp index 2a978b115c..468f8c82c7 100644 --- a/apps/openmw/mwsound/movieaudiofactory.cpp +++ b/apps/openmw/mwsound/movieaudiofactory.cpp @@ -6,8 +6,6 @@ #include "../mwbase/environment.hpp" #include "../mwbase/soundmanager.hpp" -#include "al.h" - #include "sound_decoder.hpp" #include "sound.hpp" @@ -70,14 +68,13 @@ namespace MWSound sampleFormat = AV_SAMPLE_FMT_U8; 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) - && alIsExtensionPresent("AL_EXT_FLOAT32")) - 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_S16; - if ((channelLayout == AV_CH_LAYOUT_5POINT1 || channelLayout == AV_CH_LAYOUT_7POINT1 - || channelLayout == AV_CH_LAYOUT_QUAD) && !alIsExtensionPresent("AL_EXT_MCFORMATS")) + 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) From dab05471be3fb1408116ec2e68516140b4e6b340 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 25 Oct 2014 21:09:37 +0200 Subject: [PATCH 23/30] Reset crime when bounty is reset to 0 by a script (Fixes #2057) --- apps/openmw/mwscript/statsextensions.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index 170c5fe946..befb8d82ea 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(); } }; From 450e951b2dad4dd70d904b49fc14648d19dae757 Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Sun, 26 Oct 2014 01:54:25 +0200 Subject: [PATCH 24/30] Adjusted book layout to better match vanilla --- files/mygui/openmw_book.layout | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/files/mygui/openmw_book.layout b/files/mygui/openmw_book.layout index 3b1cfea641..2336d5b2ca 100644 --- a/files/mygui/openmw_book.layout +++ b/files/mygui/openmw_book.layout @@ -2,47 +2,51 @@ - + - + - + - - + + - - + + - + - + - + + + - + + + - - + + From 95683bc8c33b5496d83e86ec3f79c47a191ef2d8 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 26 Oct 2014 15:04:52 +1000 Subject: [PATCH 25/30] Add user interface for top level window status-bar setting (implementation already existed). For feature #854. --- apps/opencs/model/settings/usersettings.cpp | 5 +++++ apps/opencs/view/doc/view.cpp | 2 +- apps/opencs/view/doc/viewmanager.cpp | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/settings/usersettings.cpp b/apps/opencs/model/settings/usersettings.cpp index 1813a97ff7..7d277f8149 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 d36e019015..bef0c170d2 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 4229ab5311..5f6b6b46a4 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(); From 925f1487b0cbf6fc90dbce7bd03cd033a7f7baee Mon Sep 17 00:00:00 2001 From: sylar Date: Wed, 26 Nov 2014 06:55:41 +0400 Subject: [PATCH 26/30] fix for world_matrix error --- files/materials/core.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/materials/core.h b/files/materials/core.h index a912e23562..e6cde4bdae 100644 --- a/files/materials/core.h +++ b/files/materials/core.h @@ -68,7 +68,7 @@ @version 120 #endif -#if SH_GLSLES == 1 && SH_FRAGMENT_SHADER +#if SH_GLSLES == 1 precision mediump int; precision mediump float; #endif From 275bf854edcf35963dd9c6584c34c212dfef955c Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 27 Oct 2014 08:57:18 +0100 Subject: [PATCH 27/30] added new user setting: window/hide-subview (hide subview titlebar if there is only one subview in the window) --- apps/opencs/model/settings/usersettings.cpp | 6 +++ apps/opencs/view/doc/subview.cpp | 5 ++ apps/opencs/view/doc/subview.hpp | 4 ++ apps/opencs/view/doc/view.cpp | 58 +++++++++++++-------- apps/opencs/view/doc/view.hpp | 4 +- apps/opencs/view/world/previewsubview.cpp | 15 ++++-- apps/opencs/view/world/previewsubview.hpp | 3 ++ apps/opencs/view/world/scenesubview.cpp | 14 +++-- apps/opencs/view/world/scenesubview.hpp | 3 ++ 9 files changed, 82 insertions(+), 30 deletions(-) diff --git a/apps/opencs/model/settings/usersettings.cpp b/apps/opencs/model/settings/usersettings.cpp index 1813a97ff7..170d1021eb 100644 --- a/apps/opencs/model/settings/usersettings.cpp +++ b/apps/opencs/model/settings/usersettings.cpp @@ -127,6 +127,12 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() maxSubView->setToolTip ("If the maximum number is reached and a new subview is opened " "it will be placed into a new top-level window."); + Setting *hide = createSetting (Type_CheckBox, "hide-subview", "Hide single subview"); + hide->setDefaultValue ("false"); + hide->setToolTip ("When a view contains only a single subview, hide the subview title " + "bar and if this subview is closed also close the view (unless it is the last " + "view for this document)"); + Setting *minWidth = createSetting (Type_SpinBox, "minimum-width", "Minimum subview width"); minWidth->setDefaultValue (325); diff --git a/apps/opencs/view/doc/subview.cpp b/apps/opencs/view/doc/subview.cpp index 1af6a7a2f3..e78f8bef4c 100644 --- a/apps/opencs/view/doc/subview.cpp +++ b/apps/opencs/view/doc/subview.cpp @@ -36,6 +36,11 @@ void CSVDoc::SubView::closeEvent (QCloseEvent *event) mParent->updateSubViewIndicies(this); } +std::string CSVDoc::SubView::getTitle() const +{ + return mUniversalId.toString(); +} + void CSVDoc::SubView::closeRequest() { emit closeRequest (this); diff --git a/apps/opencs/view/doc/subview.hpp b/apps/opencs/view/doc/subview.hpp index 60478f0bc7..384019e8bf 100644 --- a/apps/opencs/view/doc/subview.hpp +++ b/apps/opencs/view/doc/subview.hpp @@ -49,6 +49,8 @@ namespace CSVDoc void setParent(View *parent) { mParent = parent; } + virtual std::string getTitle() const; + private: void closeEvent (QCloseEvent *event); @@ -59,6 +61,8 @@ namespace CSVDoc void closeRequest (SubView *subView); + void updateTitle(); + protected slots: void closeRequest(); diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 299c078056..3b81e6dac7 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -300,7 +300,7 @@ void CSVDoc::View::setupUi() setupDebugMenu(); } -void CSVDoc::View::updateTitle(const std::string subview) +void CSVDoc::View::updateTitle() { std::ostringstream stream; @@ -312,8 +312,13 @@ void CSVDoc::View::updateTitle(const std::string subview) if (mViewTotal>1) stream << " [" << (mViewIndex+1) << "/" << mViewTotal << "]"; - if (subview != "") - stream << " - " << subview; + CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); + + bool hideTitle = userSettings.setting ("window/hide-subview", QString ("false"))=="true" && + mSubViews.size()==1 && !mSubViews.at (0)->isFloating(); + + if (hideTitle) + stream << " - " << mSubViews.at (0)->getTitle(); setWindowTitle (stream.str().c_str()); } @@ -323,24 +328,26 @@ void CSVDoc::View::updateSubViewIndicies(SubView *view) if(view && mSubViews.contains(view)) mSubViews.removeOne(view); - if (mSubViews.size() == 1) + CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); + + bool hideTitle = userSettings.setting ("window/hide-subview", QString ("false"))=="true" && + mSubViews.size()==1 && !mSubViews.at (0)->isFloating(); + + updateTitle(); + + foreach (SubView *subView, mSubViews) { - if(!mSubViews.at(0)->isFloating()) + if (!subView->isFloating()) { - mSubViews.at(0)->setTitleBarWidget(new QWidget(this)); - updateTitle(mSubViews.at(0)->getUniversalId().getTypeName().c_str()); - } - } - else - { - updateTitle(); - if(mSubViews.size() > 1) - { - foreach(SubView * sb, mSubViews) + if (hideTitle) { - QWidget * tb = sb->titleBarWidget(); - if(tb) delete tb; - sb->setTitleBarWidget(0); + subView->setTitleBarWidget (new QWidget (this)); + subView->setWindowTitle (QString::fromUtf8 (subView->getTitle().c_str())); + } + else + { + delete subView->titleBarWidget(); + subView->setTitleBarWidget (0); } } } @@ -520,6 +527,8 @@ void CSVDoc::View::addSubView (const CSMWorld::UniversalId& id, const std::strin connect (view, SIGNAL (closeRequest (SubView *)), this, SLOT (closeRequest (SubView *))); + connect (view, SIGNAL (updateTitle()), this, SLOT (updateTitle())); + view->show(); } @@ -731,9 +740,11 @@ void CSVDoc::View::resizeViewHeight (int height) resize (geometry().width(), height); } -void CSVDoc::View::updateUserSetting - (const QString &name, const QStringList &list) -{} +void CSVDoc::View::updateUserSetting (const QString &name, const QStringList &list) +{ + if (name=="window/hide-subview") + updateSubViewIndicies (0); +} void CSVDoc::View::toggleShowStatusBar (bool show) { @@ -766,7 +777,10 @@ void CSVDoc::View::stop() void CSVDoc::View::closeRequest (SubView *subView) { - if (mSubViews.size()>1 || mViewTotal<=1) + CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); + + if (mSubViews.size()>1 || mViewTotal<=1 || + userSettings.setting ("window/hide-subview", QString ("false"))!="true") subView->deleteLater(); else if (mViewManager.closeRequest (this)) mViewManager.removeDocAndView (mDocument); diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index 32ef8071d0..ee062f7252 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -75,8 +75,6 @@ namespace CSVDoc void setupUi(); - void updateTitle(const std::string subview = ""); - void updateActions(); void exitApplication(); @@ -139,6 +137,8 @@ namespace CSVDoc void updateUserSetting (const QString &, const QStringList &); + void updateTitle(); + private slots: void newView(); diff --git a/apps/opencs/view/world/previewsubview.cpp b/apps/opencs/view/world/previewsubview.cpp index dd94a00e01..1ae466f42b 100644 --- a/apps/opencs/view/world/previewsubview.cpp +++ b/apps/opencs/view/world/previewsubview.cpp @@ -9,7 +9,7 @@ #include "../widget/scenetoolmode.hpp" CSVWorld::PreviewSubView::PreviewSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) -: SubView (id) +: SubView (id), mTitle (id.toString().c_str()) { QHBoxLayout *layout = new QHBoxLayout; @@ -52,10 +52,19 @@ CSVWorld::PreviewSubView::PreviewSubView (const CSMWorld::UniversalId& id, CSMDo void CSVWorld::PreviewSubView::setEditLock (bool locked) {} +std::string CSVWorld::PreviewSubView::getTitle() const +{ + return mTitle; +} + void CSVWorld::PreviewSubView::referenceableIdChanged (const std::string& id) { if (id.empty()) - setWindowTitle ("Preview: Reference to "); + mTitle = "Preview: Reference to "; else - setWindowTitle (("Preview: Reference to " + id).c_str()); + mTitle = "Preview: Reference to " + id; + + setWindowTitle (QString::fromUtf8 (mTitle.c_str())); + + emit updateTitle(); } \ No newline at end of file diff --git a/apps/opencs/view/world/previewsubview.hpp b/apps/opencs/view/world/previewsubview.hpp index fb57ce7a34..a28be5c36d 100644 --- a/apps/opencs/view/world/previewsubview.hpp +++ b/apps/opencs/view/world/previewsubview.hpp @@ -20,6 +20,7 @@ namespace CSVWorld Q_OBJECT CSVRender::PreviewWidget *mScene; + std::string mTitle; public: @@ -27,6 +28,8 @@ namespace CSVWorld virtual void setEditLock (bool locked); + virtual std::string getTitle() const; + private slots: void referenceableIdChanged (const std::string& id); diff --git a/apps/opencs/view/world/scenesubview.cpp b/apps/opencs/view/world/scenesubview.cpp index 4cb6088cca..ce68da3623 100644 --- a/apps/opencs/view/world/scenesubview.cpp +++ b/apps/opencs/view/world/scenesubview.cpp @@ -150,16 +150,22 @@ void CSVWorld::SceneSubView::useHint (const std::string& hint) mScene->useViewHint (hint); } +std::string CSVWorld::SceneSubView::getTitle() const +{ + return mTitle; +} + void CSVWorld::SceneSubView::cellSelectionChanged (const CSMWorld::UniversalId& id) { setUniversalId(id); std::ostringstream stream; stream << "Scene: " << getUniversalId().getId(); - setWindowTitle (QString::fromUtf8 (stream.str().c_str())); + mTitle = stream.str(); + setWindowTitle (QString::fromUtf8 (mTitle.c_str())); + emit updateTitle(); } - void CSVWorld::SceneSubView::cellSelectionChanged (const CSMWorld::CellSelection& selection) { setUniversalId(CSMWorld::UniversalId(CSMWorld::UniversalId::Type_Scene, "sys::default")); @@ -184,7 +190,9 @@ void CSVWorld::SceneSubView::cellSelectionChanged (const CSMWorld::CellSelection stream << "cell around it)"; } - setWindowTitle (QString::fromUtf8 (stream.str().c_str())); + mTitle = stream.str(); + setWindowTitle (QString::fromUtf8 (mTitle.c_str())); + emit updateTitle(); } void CSVWorld::SceneSubView::handleDrop (const std::vector< CSMWorld::UniversalId >& data) diff --git a/apps/opencs/view/world/scenesubview.hpp b/apps/opencs/view/world/scenesubview.hpp index acb7944d81..fc45347d0b 100644 --- a/apps/opencs/view/world/scenesubview.hpp +++ b/apps/opencs/view/world/scenesubview.hpp @@ -44,6 +44,7 @@ namespace CSVWorld QHBoxLayout* mLayout; CSMDoc::Document& mDocument; CSVWidget::SceneToolbar* mToolbar; + std::string mTitle; public: @@ -57,6 +58,8 @@ namespace CSVWorld virtual void useHint (const std::string& hint); + virtual std::string getTitle() const; + private: void makeConnections(CSVRender::PagedWorldspaceWidget* widget); From b0a7b457f7e7adca3c8d320c2cbefaf890749d90 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 27 Oct 2014 09:32:02 +0100 Subject: [PATCH 28/30] made double click actions in tables configurable --- apps/opencs/model/settings/usersettings.cpp | 46 ++++++++++++++++ apps/opencs/view/world/table.cpp | 60 +++++++++++++++++---- 2 files changed, 96 insertions(+), 10 deletions(-) diff --git a/apps/opencs/model/settings/usersettings.cpp b/apps/opencs/model/settings/usersettings.cpp index 170d1021eb..121ba7c765 100644 --- a/apps/opencs/model/settings/usersettings.cpp +++ b/apps/opencs/model/settings/usersettings.cpp @@ -156,6 +156,52 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() ritd->setDeclaredValues (values); } + declareSection ("table-input", "Table Input"); + { + QString inPlaceEdit ("Edit in Place"); + QString editRecord ("Edit Record"); + QString view ("View"); + QString editRecordAndClose ("Edit Record and Close"); + + QStringList values; + values + << "None" << inPlaceEdit << editRecord << view << "Revert" << "Delete" + << editRecordAndClose << "View and Close"; + + QString toolTip = "
    " + "
  • None
  • " + "
  • Edit in Place: Edit the clicked cell
  • " + "
  • Edit Record: Open a dialogue subview for the clicked record
  • " + "
  • View: Open a scene subview for the clicked record (not available everywhere)
  • " + "
  • Revert: Revert record
  • " + "
  • Delete: Delete recordy
  • " + "
  • Edit Record and Close: Open a dialogue subview for the clicked record and close the table subview
  • " + "
  • View And Close: Open a scene subview for the clicked record and close the table subview
  • " + "
"; + + Setting *doubleClick = createSetting (Type_ComboBox, "double", "Double Click"); + doubleClick->setDeclaredValues (values); + doubleClick->setDefaultValue (inPlaceEdit); + doubleClick->setToolTip ("Action on double click in table:

" + toolTip); + + Setting *shiftDoubleClick = createSetting (Type_ComboBox, "double-s", + "Shift Double Click"); + shiftDoubleClick->setDeclaredValues (values); + shiftDoubleClick->setDefaultValue (editRecord); + shiftDoubleClick->setToolTip ("Action on shift double click in table:

" + toolTip); + + Setting *ctrlDoubleClick = createSetting (Type_ComboBox, "double-c", + "Control Double Click"); + ctrlDoubleClick->setDeclaredValues (values); + ctrlDoubleClick->setDefaultValue (view); + ctrlDoubleClick->setToolTip ("Action on control double click in table:

" + toolTip); + + Setting *shiftCtrlDoubleClick = createSetting (Type_ComboBox, "double-sc", + "Shift Control Double Click"); + shiftCtrlDoubleClick->setDeclaredValues (values); + shiftCtrlDoubleClick->setDefaultValue (editRecordAndClose); + shiftCtrlDoubleClick->setToolTip ("Action on shift control double click in table:

" + toolTip); + } { /****************************************************************** diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index 0502e7bbf3..ce53dcf5cb 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -520,18 +520,59 @@ void CSVWorld::Table::previewRecord() void CSVWorld::Table::updateUserSetting (const QString &name, const QStringList &list) { - int columns = mModel->columnCount(); + if (name=="records/type-format" || name=="records/status-format") + { + int columns = mModel->columnCount(); - for (int i=0; i - (*delegate).updateUserSetting (name, list); + for (int i=0; iindex (0, i), - mModel->index (mModel->rowCount()-1, i)); + dynamic_cast + (*delegate).updateUserSetting (name, list); + { + emit dataChanged (mModel->index (0, i), + mModel->index (mModel->rowCount()-1, i)); + } } - } + return; + } + + QString base ("table-input/double"); + if (name.startsWith (base)) + { + QString modifierString = name.mid (base.size()); + Qt::KeyboardModifiers modifiers = 0; + + if (modifierString=="-s") + modifiers = Qt::ShiftModifier; + else if (modifierString=="-c") + modifiers = Qt::ControlModifier; + else if (modifierString=="-sc") + modifiers = Qt::ShiftModifier | Qt::ControlModifier; + + DoubleClickAction action = Action_None; + + QString value = list.at (0); + + if (value=="Edit in Place") + action = Action_InPlaceEdit; + else if (value=="Edit Record") + action = Action_EditRecord; + else if (value=="View") + action = Action_View; + else if (value=="Revert") + action = Action_Revert; + else if (value=="Delete") + action = Action_Delete; + else if (value=="Edit Record and Close") + action = Action_EditRecordAndClose; + else if (value=="View and Close") + action = Action_ViewAndClose; + + mDoubleClickActions[modifiers] = action; + + return; + } } void CSVWorld::Table::tableSizeUpdate() @@ -648,7 +689,6 @@ std::vector CSVWorld::Table::getColumnsWithDisplay(CSMWorld::Column std::vector< CSMWorld::UniversalId > CSVWorld::Table::getDraggedRecords() const { - QModelIndexList selectedRows = selectionModel()->selectedRows(); std::vector idToDrag; From 1aef9304e99a6e2af8ef817ff90f51178d8dd193 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 27 Oct 2014 09:44:18 +0100 Subject: [PATCH 29/30] replaced the signal/slot user settings update with a regular function call --- apps/opencs/view/doc/subview.hpp | 6 ++---- apps/opencs/view/doc/view.cpp | 10 +++++----- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/apps/opencs/view/doc/subview.hpp b/apps/opencs/view/doc/subview.hpp index 384019e8bf..e1331750a0 100644 --- a/apps/opencs/view/doc/subview.hpp +++ b/apps/opencs/view/doc/subview.hpp @@ -51,6 +51,8 @@ namespace CSVDoc virtual std::string getTitle() const; + virtual void updateUserSetting (const QString& name, const QStringList& value); + private: void closeEvent (QCloseEvent *event); @@ -66,10 +68,6 @@ namespace CSVDoc protected slots: void closeRequest(); - - public slots: - virtual void updateUserSetting - (const QString &, const QStringList &); }; } diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 3b81e6dac7..d065631cb3 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -520,11 +520,6 @@ void CSVDoc::View::addSubView (const CSMWorld::UniversalId& id, const std::strin connect (view, SIGNAL (focusId (const CSMWorld::UniversalId&, const std::string&)), this, SLOT (addSubView (const CSMWorld::UniversalId&, const std::string&))); - connect (&CSMSettings::UserSettings::instance(), - SIGNAL (userSettingUpdated (const QString &, const QStringList &)), - view, - SLOT (updateUserSetting (const QString &, const QStringList &))); - connect (view, SIGNAL (closeRequest (SubView *)), this, SLOT (closeRequest (SubView *))); connect (view, SIGNAL (updateTitle()), this, SLOT (updateTitle())); @@ -744,6 +739,11 @@ void CSVDoc::View::updateUserSetting (const QString &name, const QStringList &li { if (name=="window/hide-subview") updateSubViewIndicies (0); + + foreach (SubView *subView, mSubViews) + { + subView->updateUserSetting (name, list); + } } void CSVDoc::View::toggleShowStatusBar (bool show) From 6f4b75375003ddb07d69fea8b0b9f4bcfdcd40ae Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 27 Oct 2014 09:51:55 +0100 Subject: [PATCH 30/30] replaced regular function call from SubView to View with signal-slot-connection --- apps/opencs/view/doc/subview.cpp | 6 ++---- apps/opencs/view/doc/subview.hpp | 7 ++++--- apps/opencs/view/doc/view.cpp | 3 +++ apps/opencs/view/doc/view.hpp | 6 +++--- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/apps/opencs/view/doc/subview.cpp b/apps/opencs/view/doc/subview.cpp index e78f8bef4c..a9dce25bec 100644 --- a/apps/opencs/view/doc/subview.cpp +++ b/apps/opencs/view/doc/subview.cpp @@ -3,7 +3,7 @@ #include "view.hpp" CSVDoc::SubView::SubView (const CSMWorld::UniversalId& id) - : mUniversalId (id), mParent (NULL) + : mUniversalId (id) { /// \todo add a button to the title bar that clones this sub view @@ -31,9 +31,7 @@ void CSVDoc::SubView::setUniversalId (const CSMWorld::UniversalId& id) void CSVDoc::SubView::closeEvent (QCloseEvent *event) { - // update title bars of view and subviews - if(mParent) - mParent->updateSubViewIndicies(this); + emit updateSubViewIndicies (this); } std::string CSVDoc::SubView::getTitle() const diff --git a/apps/opencs/view/doc/subview.hpp b/apps/opencs/view/doc/subview.hpp index e1331750a0..a8aa3cda1e 100644 --- a/apps/opencs/view/doc/subview.hpp +++ b/apps/opencs/view/doc/subview.hpp @@ -25,12 +25,13 @@ namespace CSVDoc Q_OBJECT CSMWorld::UniversalId mUniversalId; - View *mParent; // not implemented SubView (const SubView&); SubView& operator= (SubView&); + protected: + void setUniversalId(const CSMWorld::UniversalId& id); public: @@ -47,8 +48,6 @@ namespace CSVDoc virtual void useHint (const std::string& hint); ///< Default implementation: ignored - void setParent(View *parent) { mParent = parent; } - virtual std::string getTitle() const; virtual void updateUserSetting (const QString& name, const QStringList& value); @@ -65,6 +64,8 @@ namespace CSVDoc void updateTitle(); + void updateSubViewIndicies (SubView *view = 0); + protected slots: void closeRequest(); diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index d065631cb3..23bd0a9413 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -524,6 +524,9 @@ void CSVDoc::View::addSubView (const CSMWorld::UniversalId& id, const std::strin connect (view, SIGNAL (updateTitle()), this, SLOT (updateTitle())); + connect (view, SIGNAL (updateSubViewIndicies (SubView *)), + this, SLOT (updateSubViewIndicies (SubView *))); + view->show(); } diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index ee062f7252..55ea5ee515 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -112,9 +112,6 @@ namespace CSVDoc /// Function called by view manager when user preferences are updated void updateEditorSetting (const QString &, const QString &); - // called when subviews are added or removed - void updateSubViewIndicies(SubView *view = 0); - signals: void newGameRequest(); @@ -139,6 +136,9 @@ namespace CSVDoc void updateTitle(); + // called when subviews are added or removed + void updateSubViewIndicies (SubView *view = 0); + private slots: void newView();