2024-05-02 21:14:50 +02:00
|
|
|
/*
|
|
|
|
* TextControls.cpp, part of VCMI engine
|
|
|
|
*
|
|
|
|
* Authors: listed in file AUTHORS in main folder
|
|
|
|
*
|
|
|
|
* License: GNU General Public License v2.0 or later
|
|
|
|
* Full text of license available in license.txt file, in main folder
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
#include "StdInc.h"
|
|
|
|
#include "VideoWidget.h"
|
2024-10-16 02:36:26 +02:00
|
|
|
#include "TextControls.h"
|
2024-05-02 21:14:50 +02:00
|
|
|
|
|
|
|
#include "../CGameInfo.h"
|
|
|
|
#include "../gui/CGuiHandler.h"
|
2024-05-03 18:07:00 +02:00
|
|
|
#include "../media/ISoundPlayer.h"
|
|
|
|
#include "../media/IVideoPlayer.h"
|
|
|
|
#include "../render/Canvas.h"
|
2024-05-02 21:14:50 +02:00
|
|
|
|
2024-10-16 03:48:14 +02:00
|
|
|
#include "../../lib/filesystem/Filesystem.h"
|
|
|
|
|
2024-05-15 18:34:23 +02:00
|
|
|
VideoWidgetBase::VideoWidgetBase(const Point & position, const VideoPath & video, bool playAudio)
|
2024-09-12 23:06:33 +02:00
|
|
|
: VideoWidgetBase(position, video, playAudio, 1.0)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
VideoWidgetBase::VideoWidgetBase(const Point & position, const VideoPath & video, bool playAudio, float scaleFactor)
|
|
|
|
: playAudio(playAudio), scaleFactor(scaleFactor)
|
2024-05-02 21:14:50 +02:00
|
|
|
{
|
2024-05-03 18:07:00 +02:00
|
|
|
addUsedEvents(TIME);
|
2024-05-15 18:34:23 +02:00
|
|
|
pos += position;
|
|
|
|
playVideo(video);
|
2024-05-02 21:14:50 +02:00
|
|
|
}
|
|
|
|
|
2024-05-15 18:34:23 +02:00
|
|
|
VideoWidgetBase::~VideoWidgetBase() = default;
|
|
|
|
|
|
|
|
void VideoWidgetBase::playVideo(const VideoPath & fileToPlay)
|
2024-05-02 21:14:50 +02:00
|
|
|
{
|
2024-10-16 02:36:26 +02:00
|
|
|
OBJECT_CONSTRUCTION;
|
|
|
|
|
2024-10-16 22:37:18 +02:00
|
|
|
JsonPath subTitlePath = fileToPlay.toType<EResType::JSON>();
|
|
|
|
JsonPath subTitlePathVideoDir = subTitlePath.addPrefix("VIDEO/");
|
2024-10-16 03:48:14 +02:00
|
|
|
if(CResourceHandler::get()->existsResource(subTitlePath))
|
2024-10-16 22:37:18 +02:00
|
|
|
subTitleData = JsonNode(subTitlePath);
|
|
|
|
else if(CResourceHandler::get()->existsResource(subTitlePathVideoDir))
|
|
|
|
subTitleData = JsonNode(subTitlePathVideoDir);
|
2024-10-16 03:48:14 +02:00
|
|
|
|
2024-09-12 23:06:33 +02:00
|
|
|
videoInstance = CCS->videoh->open(fileToPlay, scaleFactor);
|
2024-05-15 18:34:23 +02:00
|
|
|
if (videoInstance)
|
|
|
|
{
|
|
|
|
pos.w = videoInstance->size().x;
|
|
|
|
pos.h = videoInstance->size().y;
|
2024-10-30 01:35:50 +02:00
|
|
|
if(!subTitleData.isNull())
|
|
|
|
subTitle = std::make_unique<CMultiLineLabel>(Rect(0, (pos.h / 5) * 4, pos.w, pos.h / 5), EFonts::FONT_HIGH_SCORE, ETextAlignment::CENTER, Colors::WHITE);
|
2024-05-15 18:34:23 +02:00
|
|
|
}
|
2024-05-02 21:14:50 +02:00
|
|
|
|
2024-05-15 18:34:23 +02:00
|
|
|
if (playAudio)
|
|
|
|
{
|
|
|
|
loadAudio(fileToPlay);
|
|
|
|
if (isActive())
|
|
|
|
startAudio();
|
|
|
|
}
|
|
|
|
}
|
2024-05-02 21:14:50 +02:00
|
|
|
|
2024-05-15 18:34:23 +02:00
|
|
|
void VideoWidgetBase::show(Canvas & to)
|
2024-05-02 21:14:50 +02:00
|
|
|
{
|
2024-05-03 18:07:00 +02:00
|
|
|
if(videoInstance)
|
|
|
|
videoInstance->show(pos.topLeft(), to);
|
2024-10-16 02:36:26 +02:00
|
|
|
if(subTitle)
|
|
|
|
subTitle->showAll(to);
|
2024-05-02 21:14:50 +02:00
|
|
|
}
|
|
|
|
|
2024-05-15 18:34:23 +02:00
|
|
|
void VideoWidgetBase::loadAudio(const VideoPath & fileToPlay)
|
|
|
|
{
|
|
|
|
if (!playAudio)
|
|
|
|
return;
|
|
|
|
|
|
|
|
audioData = CCS->videoh->getAudio(fileToPlay);
|
|
|
|
}
|
|
|
|
|
|
|
|
void VideoWidgetBase::startAudio()
|
2024-05-02 21:14:50 +02:00
|
|
|
{
|
2024-05-15 18:34:23 +02:00
|
|
|
if(audioData.first == nullptr)
|
|
|
|
return;
|
|
|
|
|
|
|
|
audioHandle = CCS->soundh->playSound(audioData);
|
2024-05-02 21:14:50 +02:00
|
|
|
|
2024-05-15 18:34:23 +02:00
|
|
|
if(audioHandle != -1)
|
2024-05-02 21:14:50 +02:00
|
|
|
{
|
2024-05-03 18:07:00 +02:00
|
|
|
CCS->soundh->setCallback(
|
2024-05-15 18:34:23 +02:00
|
|
|
audioHandle,
|
2024-05-03 18:07:00 +02:00
|
|
|
[this]()
|
|
|
|
{
|
2024-05-15 18:34:23 +02:00
|
|
|
this->audioHandle = -1;
|
2024-05-03 18:07:00 +02:00
|
|
|
}
|
2024-10-16 03:48:14 +02:00
|
|
|
);
|
2024-05-02 21:14:50 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-05-15 18:34:23 +02:00
|
|
|
void VideoWidgetBase::stopAudio()
|
2024-05-02 21:14:50 +02:00
|
|
|
{
|
2024-05-15 18:34:23 +02:00
|
|
|
if(audioHandle != -1)
|
|
|
|
{
|
|
|
|
CCS->soundh->resetCallback(audioHandle);
|
|
|
|
CCS->soundh->stopSound(audioHandle);
|
|
|
|
audioHandle = -1;
|
|
|
|
}
|
2024-05-02 21:14:50 +02:00
|
|
|
}
|
|
|
|
|
2024-10-16 03:48:14 +02:00
|
|
|
std::string VideoWidgetBase::getSubTitleLine(double timestamp)
|
|
|
|
{
|
2024-10-16 22:37:18 +02:00
|
|
|
if(subTitleData.isNull())
|
|
|
|
return {};
|
|
|
|
|
|
|
|
for(auto & segment : subTitleData.Vector())
|
|
|
|
if(timestamp > segment["timeStart"].Float() && timestamp < segment["timeEnd"].Float())
|
|
|
|
return segment["text"].String();
|
2024-10-16 03:48:14 +02:00
|
|
|
|
2024-10-16 22:37:18 +02:00
|
|
|
return {};
|
2024-10-16 03:48:14 +02:00
|
|
|
}
|
|
|
|
|
2024-05-15 18:34:23 +02:00
|
|
|
void VideoWidgetBase::activate()
|
|
|
|
{
|
|
|
|
CIntObject::activate();
|
2024-10-30 01:35:50 +02:00
|
|
|
if(audioHandle != -1)
|
|
|
|
CCS->soundh->resumeSound(audioHandle);
|
|
|
|
else
|
|
|
|
startAudio();
|
|
|
|
if(videoInstance)
|
|
|
|
videoInstance->activate();
|
2024-05-15 18:34:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void VideoWidgetBase::deactivate()
|
|
|
|
{
|
|
|
|
CIntObject::deactivate();
|
2024-10-30 01:35:50 +02:00
|
|
|
CCS->soundh->pauseSound(audioHandle);
|
|
|
|
if(videoInstance)
|
|
|
|
videoInstance->deactivate();
|
2024-05-15 18:34:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void VideoWidgetBase::showAll(Canvas & to)
|
2024-05-02 21:14:50 +02:00
|
|
|
{
|
2024-05-03 18:07:00 +02:00
|
|
|
if(videoInstance)
|
|
|
|
videoInstance->show(pos.topLeft(), to);
|
2024-10-16 02:36:26 +02:00
|
|
|
if(subTitle)
|
|
|
|
subTitle->showAll(to);
|
2024-05-02 21:14:50 +02:00
|
|
|
}
|
|
|
|
|
2024-05-15 18:34:23 +02:00
|
|
|
void VideoWidgetBase::tick(uint32_t msPassed)
|
2024-05-02 21:14:50 +02:00
|
|
|
{
|
2024-05-03 18:07:00 +02:00
|
|
|
if(videoInstance)
|
|
|
|
{
|
|
|
|
videoInstance->tick(msPassed);
|
2024-05-02 21:14:50 +02:00
|
|
|
|
2024-05-03 18:07:00 +02:00
|
|
|
if(videoInstance->videoEnded())
|
2024-05-15 18:34:23 +02:00
|
|
|
{
|
|
|
|
videoInstance.reset();
|
|
|
|
stopAudio();
|
|
|
|
onPlaybackFinished();
|
|
|
|
}
|
2024-05-03 18:07:00 +02:00
|
|
|
}
|
2024-10-16 02:36:26 +02:00
|
|
|
if(subTitle && videoInstance)
|
2024-10-16 03:48:14 +02:00
|
|
|
subTitle->setText(getSubTitleLine(videoInstance->timeStamp()));
|
2024-05-02 21:14:50 +02:00
|
|
|
}
|
2024-05-15 18:34:23 +02:00
|
|
|
|
|
|
|
VideoWidget::VideoWidget(const Point & position, const VideoPath & prologue, const VideoPath & looped, bool playAudio)
|
|
|
|
: VideoWidgetBase(position, prologue, playAudio)
|
|
|
|
, loopedVideo(looped)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
VideoWidget::VideoWidget(const Point & position, const VideoPath & looped, bool playAudio)
|
|
|
|
: VideoWidgetBase(position, looped, playAudio)
|
|
|
|
, loopedVideo(looped)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void VideoWidget::onPlaybackFinished()
|
|
|
|
{
|
|
|
|
playVideo(loopedVideo);
|
|
|
|
}
|
|
|
|
|
|
|
|
VideoWidgetOnce::VideoWidgetOnce(const Point & position, const VideoPath & video, bool playAudio, const std::function<void()> & callback)
|
|
|
|
: VideoWidgetBase(position, video, playAudio)
|
|
|
|
, callback(callback)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2024-09-12 23:06:33 +02:00
|
|
|
VideoWidgetOnce::VideoWidgetOnce(const Point & position, const VideoPath & video, bool playAudio, float scaleFactor, const std::function<void()> & callback)
|
|
|
|
: VideoWidgetBase(position, video, playAudio, scaleFactor)
|
|
|
|
, callback(callback)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2024-05-15 18:34:23 +02:00
|
|
|
void VideoWidgetOnce::onPlaybackFinished()
|
|
|
|
{
|
|
|
|
callback();
|
|
|
|
}
|