mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-22 22:13:35 +02:00
commit
150f4904ab
@ -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
|
||||
{
|
||||
|
@ -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>();
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user