diff --git a/client/media/CEmptyVideoPlayer.h b/client/media/CEmptyVideoPlayer.h index 619591c9b..6497f20a2 100644 --- a/client/media/CEmptyVideoPlayer.h +++ b/client/media/CEmptyVideoPlayer.h @@ -14,10 +14,6 @@ class CEmptyVideoPlayer final : public IVideoPlayer { public: - void playSpellbookAnimation(const VideoPath & name, const Point & position) override - { - } - /// Load video from specified path std::unique_ptr open(const VideoPath & name, float scaleFactor) override { diff --git a/client/media/CVideoHandler.cpp b/client/media/CVideoHandler.cpp index a2a0ef939..7853c9f1b 100644 --- a/client/media/CVideoHandler.cpp +++ b/client/media/CVideoHandler.cpp @@ -637,68 +637,6 @@ std::pair, si64> CAudioInstance::extractAudio(const Vide return dat; } -bool CVideoPlayer::openAndPlayVideoImpl(const VideoPath & name, const Point & position, bool useOverlay, bool stopOnKey) -{ - CVideoInstance instance; - - auto extractedAudio = getAudio(name); - int audioHandle = CCS->soundh->playSound(extractedAudio); - - if (!instance.openInput(name)) - return true; - - instance.openVideo(); - instance.prepareOutput(1, true); - - auto lastTimePoint = boost::chrono::steady_clock::now(); - - while(instance.loadNextFrame()) - { - if(stopOnKey) - { - GH.input().fetchEvents(); - if(GH.input().ignoreEventsUntilInput()) - { - CCS->soundh->stopSound(audioHandle); - return false; - } - } - - SDL_Rect rect; - rect.x = position.x; - rect.y = position.y; - rect.w = instance.dimensions.x; - rect.h = instance.dimensions.y; - - SDL_RenderFillRect(mainRenderer, &rect); - - if(instance.textureYUV) - SDL_RenderCopy(mainRenderer, instance.textureYUV, nullptr, &rect); - else - SDL_RenderCopy(mainRenderer, instance.textureRGB, nullptr, &rect); - - SDL_RenderPresent(mainRenderer); - - // Framerate delay - double targetFrameTimeSeconds = instance.getCurrentFrameDuration(); - auto targetFrameTime = boost::chrono::milliseconds(static_cast(1000 * targetFrameTimeSeconds)); - - auto timePointAfterPresent = boost::chrono::steady_clock::now(); - auto timeSpentBusy = boost::chrono::duration_cast(timePointAfterPresent - lastTimePoint); - - if(targetFrameTime > timeSpentBusy) - boost::this_thread::sleep_for(targetFrameTime - timeSpentBusy); - - lastTimePoint = boost::chrono::steady_clock::now(); - } - return true; -} - -void CVideoPlayer::playSpellbookAnimation(const VideoPath & name, const Point & position) -{ - openAndPlayVideoImpl(name, position * GH.screenHandler().getScalingFactor(), false, false); -} - std::unique_ptr CVideoPlayer::open(const VideoPath & name, float scaleFactor) { auto result = std::make_unique(); diff --git a/client/media/CVideoHandler.h b/client/media/CVideoHandler.h index 63e4a6176..591f83b74 100644 --- a/client/media/CVideoHandler.h +++ b/client/media/CVideoHandler.h @@ -103,11 +103,9 @@ public: class CVideoPlayer final : public IVideoPlayer { - bool openAndPlayVideoImpl(const VideoPath & name, const Point & position, bool useOverlay, bool stopOnKey); void openVideoFile(CVideoInstance & state, const VideoPath & fname); public: - void playSpellbookAnimation(const VideoPath & name, const Point & position) final; std::unique_ptr open(const VideoPath & name, float scaleFactor) final; std::pair, si64> getAudio(const VideoPath & videoToOpen) final; }; diff --git a/client/media/IVideoPlayer.h b/client/media/IVideoPlayer.h index 3f2784c16..35f385bc1 100644 --- a/client/media/IVideoPlayer.h +++ b/client/media/IVideoPlayer.h @@ -45,9 +45,6 @@ public: class IVideoPlayer : boost::noncopyable { public: - /// Plays video on top of the screen, returns only after playback is over - virtual void playSpellbookAnimation(const VideoPath & name, const Point & position) = 0; - /// Load video from specified path. Returns nullptr on failure virtual std::unique_ptr open(const VideoPath & name, float scaleFactor) = 0; diff --git a/client/widgets/VideoWidget.cpp b/client/widgets/VideoWidget.cpp index 35fe4adcb..4c8b786f3 100644 --- a/client/widgets/VideoWidget.cpp +++ b/client/widgets/VideoWidget.cpp @@ -16,6 +16,7 @@ #include "../media/ISoundPlayer.h" #include "../media/IVideoPlayer.h" #include "../render/Canvas.h" +#include "../render/IScreenHandler.h" #include "../../lib/filesystem/Filesystem.h" @@ -45,7 +46,26 @@ void VideoWidgetBase::playVideo(const VideoPath & fileToPlay) else if(CResourceHandler::get()->existsResource(subTitlePathVideoDir)) subTitleData = JsonNode(subTitlePathVideoDir); - videoInstance = CCS->videoh->open(fileToPlay, scaleFactor); + float preScaleFactor = 1; + VideoPath videoFile = fileToPlay; + if(GH.screenHandler().getScalingFactor() > 1) + { + std::vector factorsToCheck = {GH.screenHandler().getScalingFactor(), 4, 3, 2}; + for(auto factorToCheck : factorsToCheck) + { + std::string name = boost::algorithm::to_upper_copy(videoFile.getName()); + boost::replace_all(name, "VIDEO/", std::string("VIDEO") + std::to_string(factorToCheck) + std::string("X/")); + auto p = VideoPath::builtin(name).addPrefix("VIDEO" + std::to_string(factorToCheck) + "X/"); + if(CResourceHandler::get()->existsResource(p)) + { + preScaleFactor = 1.0 / static_cast(factorToCheck); + videoFile = p; + break; + } + } + } + + videoInstance = CCS->videoh->open(videoFile, scaleFactor * preScaleFactor); if (videoInstance) { pos.w = videoInstance->size().x; diff --git a/client/windows/CSpellWindow.cpp b/client/windows/CSpellWindow.cpp index 6f810a2fa..ff531c0f3 100644 --- a/client/windows/CSpellWindow.cpp +++ b/client/windows/CSpellWindow.cpp @@ -30,6 +30,7 @@ #include "../widgets/CTextInput.h" #include "../widgets/TextControls.h" #include "../widgets/Buttons.h" +#include "../widgets/VideoWidget.h" #include "../adventureMap/AdventureMapInterface.h" #include "../render/AssetGenerator.h" @@ -395,6 +396,8 @@ void CSpellWindow::fRcornerb() void CSpellWindow::show(Canvas & to) { + if(video) + video->show(to); statusBar->show(to); } @@ -493,14 +496,22 @@ void CSpellWindow::setCurrentPage(int value) void CSpellWindow::turnPageLeft() { + OBJECT_CONSTRUCTION; if(settings["video"]["spellbookAnimation"].Bool() && !isBigSpellbook) - CCS->videoh->playSpellbookAnimation(VideoPath::builtin("PGTRNLFT.SMK"), pos.topLeft() + Point(13, 14)); + video = std::make_shared(Point(13, 14), VideoPath::builtin("PGTRNLFT.SMK"), false, [this](){ + video.reset(); + redraw(); + }); } void CSpellWindow::turnPageRight() { + OBJECT_CONSTRUCTION; if(settings["video"]["spellbookAnimation"].Bool() && !isBigSpellbook) - CCS->videoh->playSpellbookAnimation(VideoPath::builtin("PGTRNRGH.SMK"), pos.topLeft() + Point(13, 14)); + video = std::make_shared(Point(13, 14), VideoPath::builtin("PGTRNRGH.SMK"), false, [this](){ + video.reset(); + redraw(); + }); } void CSpellWindow::keyPressed(EShortcut key) diff --git a/client/windows/CSpellWindow.h b/client/windows/CSpellWindow.h index 29293faa4..70b495055 100644 --- a/client/windows/CSpellWindow.h +++ b/client/windows/CSpellWindow.h @@ -28,6 +28,7 @@ class CSpellWindow; class CTextInput; class TransparentFilledRectangle; class CToggleButton; +class VideoWidgetOnce; /// The spell window class CSpellWindow : public CWindowObject @@ -86,6 +87,8 @@ class CSpellWindow : public CWindowObject std::shared_ptr showAllSpells; std::shared_ptr showAllSpellsDescription; + std::shared_ptr video; + bool isBigSpellbook; int spellsPerPage; int offL; diff --git a/docs/modders/HD_Graphics.md b/docs/modders/HD_Graphics.md index d16b53d44..c5a8d3d2a 100644 --- a/docs/modders/HD_Graphics.md +++ b/docs/modders/HD_Graphics.md @@ -12,12 +12,13 @@ If user for example selects 3x resolution and only 2x exists in mod then the 2x ## Mod -For upscaled images you have to use following folders (next to `sprites` and `data` folders): +For upscaled images you have to use following folders (next to `sprites`, `data` and `video` folders): - `sprites2x`, `sprites3x`, `sprites4x` for sprites - `data2x`, `data3x`, `data4x` for images +- `video2x`, `video3x`, `video4x` for videos -The sprites should have the same name and folder structure as in `sprites` and `data` folder. All images that are missing in the upscaled folders are scaled with the selected upscaling filter instead of using prescaled images. +The sprites should have the same name and folder structure as in `sprites`, `data` and `video` folder. All images that are missing in the upscaled folders are scaled with the selected upscaling filter instead of using prescaled images. ### Shadows / Overlays @@ -34,4 +35,4 @@ Same for overlays with `-overlay`. But overlays are **necessary** for some anima Currently needed for: - Flaggable adventure map objects. Overlay must contain a transparent image with white flags on it and will be used to colorize flags to owning player -- Creature battle animations, idle and mouse hover group. Overlay must contain a transparent image with white outline of creature for highlighting on mouse hover) +- Creature battle animations, idle and mouse hover group. Overlay must contain a transparent image with white outline of creature for highlighting on mouse hover