1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-22 22:13:35 +02:00

Merge pull request #5005 from Laserlicht/video

Video rework
This commit is contained in:
Ivan Savenko 2024-12-02 13:48:51 +02:00 committed by GitHub
commit 150f4904ab
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 41 additions and 77 deletions

View File

@ -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<IVideoInstance> open(const VideoPath & name, float scaleFactor) override
{

View File

@ -637,68 +637,6 @@ std::pair<std::unique_ptr<ui8 []>, 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<int>(1000 * targetFrameTimeSeconds));
auto timePointAfterPresent = boost::chrono::steady_clock::now();
auto timeSpentBusy = boost::chrono::duration_cast<boost::chrono::milliseconds>(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<IVideoInstance> CVideoPlayer::open(const VideoPath & name, float scaleFactor)
{
auto result = std::make_unique<CVideoInstance>();

View File

@ -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<IVideoInstance> open(const VideoPath & name, float scaleFactor) final;
std::pair<std::unique_ptr<ui8[]>, si64> getAudio(const VideoPath & videoToOpen) final;
};

View File

@ -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<IVideoInstance> open(const VideoPath & name, float scaleFactor) = 0;

View File

@ -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<int> 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<float>(factorToCheck);
videoFile = p;
break;
}
}
}
videoInstance = CCS->videoh->open(videoFile, scaleFactor * preScaleFactor);
if (videoInstance)
{
pos.w = videoInstance->size().x;

View File

@ -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<VideoWidgetOnce>(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<VideoWidgetOnce>(Point(13, 14), VideoPath::builtin("PGTRNRGH.SMK"), false, [this](){
video.reset();
redraw();
});
}
void CSpellWindow::keyPressed(EShortcut key)

View File

@ -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<CToggleButton> showAllSpells;
std::shared_ptr<CLabel> showAllSpellsDescription;
std::shared_ptr<VideoWidgetOnce> video;
bool isBigSpellbook;
int spellsPerPage;
int offL;

View File

@ -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