Files
WickedEngine/Editor/VideoWindow.cpp
T

309 lines
9.8 KiB
C++

#include "stdafx.h"
#include "VideoWindow.h"
using namespace wi::graphics;
using namespace wi::ecs;
using namespace wi::scene;
void VideoPreview::Render(const wi::Canvas& canvas, wi::graphics::CommandList cmd) const
{
if (video == nullptr)
return;
GraphicsDevice* device = wi::graphics::GetDevice();
device->EventBegin("Video Preview", cmd);
wi::image::Params params;
params.pos = translation;
params.siz = XMFLOAT2(scale.x, scale.y);
params.blendFlag = wi::enums::BLENDMODE_OPAQUE;
if (!video->videoinstance.output.texture.IsValid())
{
params.color = wi::Color::Black();
}
wi::image::Draw(&video->videoinstance.output.texture, params, cmd);
device->EventEnd(cmd);
}
void VideoWindow::Create(EditorComponent* _editor)
{
editor = _editor;
wi::gui::Window::Create(ICON_VIDEO " Video", wi::gui::Window::WindowControls::COLLAPSE | wi::gui::Window::WindowControls::CLOSE | wi::gui::Window::WindowControls::FIT_ALL_WIDGETS_VERTICAL);
SetSize(XMFLOAT2(440, 840));
closeButton.SetTooltip("Delete VideoComponent");
OnClose([=](wi::gui::EventArgs args) {
wi::Archive& archive = editor->AdvanceHistory();
archive << EditorComponent::HISTORYOP_COMPONENT_DATA;
editor->RecordEntity(archive, entity);
editor->GetCurrentScene().videos.Remove(entity);
editor->RecordEntity(archive, entity);
editor->componentsWnd.RefreshEntityTree();
});
float x = 60;
float y = 0;
float hei = 18;
float step = hei + 2;
float wid = 200;
openButton.Create("Open File " ICON_OPEN);
openButton.SetTooltip("Open video file.\nSupported extensions: MP4");
openButton.SetPos(XMFLOAT2(x, y));
openButton.SetSize(XMFLOAT2(wid, hei));
openButton.OnClick([&](wi::gui::EventArgs args) {
VideoComponent* video = editor->GetCurrentScene().videos.GetComponent(entity);
if (video != nullptr)
{
wi::helper::FileDialogParams params;
params.type = wi::helper::FileDialogParams::OPEN;
params.description = "Video (.mp4)";
params.extensions = wi::resourcemanager::GetSupportedVideoExtensions();
wi::helper::FileDialog(params, [=](std::string fileName) {
wi::eventhandler::Subscribe_Once(wi::eventhandler::EVENT_THREAD_SAFE_POINT, [=](uint64_t userdata) {
video->filename = fileName;
video->videoResource = wi::resourcemanager::Load(fileName);
wi::video::CreateVideoInstance(&video->videoResource.GetVideo(), &video->videoinstance);
filenameLabel.SetText(wi::helper::GetFileNameFromPath(video->filename));
});
});
}
});
AddWidget(&openButton);
filenameLabel.Create("Filename");
filenameLabel.SetPos(XMFLOAT2(x, y += step));
filenameLabel.SetSize(XMFLOAT2(wid, hei));
AddWidget(&filenameLabel);
playpauseButton.Create(ICON_PLAY);
playpauseButton.SetTooltip("Play/Pause selected video instance.");
playpauseButton.SetPos(XMFLOAT2(x, y += step));
playpauseButton.SetSize(XMFLOAT2(wid, hei));
playpauseButton.OnClick([&](wi::gui::EventArgs args) {
VideoComponent* video = editor->GetCurrentScene().videos.GetComponent(entity);
if (video != nullptr)
{
if (video->IsPlaying())
{
video->Stop();
playpauseButton.SetText(ICON_PLAY);
}
else
{
video->Play();
playpauseButton.SetText(ICON_PAUSE);
}
}
});
AddWidget(&playpauseButton);
stopButton.Create(ICON_STOP);
stopButton.SetTooltip("Stop selected video instance.");
stopButton.SetPos(XMFLOAT2(x, y += step));
stopButton.SetSize(XMFLOAT2(hei, hei));
stopButton.OnClick([&](wi::gui::EventArgs args) {
VideoComponent* video = editor->GetCurrentScene().videos.GetComponent(entity);
if (video != nullptr)
{
video->Stop();
video->videoinstance.current_frame = 0;
video->videoinstance.flags &= ~wi::video::VideoInstance::Flags::InitialFirstFrameDecoded;
video->videoinstance.flags &= ~wi::video::VideoInstance::Flags::Playing;
}
});
AddWidget(&stopButton);
loopedCheckbox.Create("Looped: ");
loopedCheckbox.SetTooltip("Enable looping for the selected video instance.");
loopedCheckbox.SetPos(XMFLOAT2(x, y += step));
loopedCheckbox.SetSize(XMFLOAT2(hei, hei));
loopedCheckbox.SetCheckText(ICON_LOOP);
loopedCheckbox.OnClick([&](wi::gui::EventArgs args) {
VideoComponent* video = editor->GetCurrentScene().videos.GetComponent(entity);
if (video != nullptr)
{
video->SetLooped(args.bValue);
}
});
AddWidget(&loopedCheckbox);
timerSlider.Create(0, 1, 0, 100000, "Timer: ");
timerSlider.SetSize(XMFLOAT2(hei, hei));
timerSlider.OnSlide([&](wi::gui::EventArgs args) {
VideoComponent* video = editor->GetCurrentScene().videos.GetComponent(entity);
if (video != nullptr && video->videoResource.IsValid())
{
const wi::video::Video& videofile = video->videoResource.GetVideo();
int target_frame = int(float(args.fValue / videofile.duration_seconds) * videofile.frames_infos.size());
for (size_t i = 0; i < videofile.frames_infos.size(); ++i)
{
auto& frame_info = videofile.frames_infos[i];
if (i >= target_frame && frame_info.type == wi::graphics::VideoFrameType::Intra)
{
target_frame = (int)i;
break;
}
}
video->videoinstance.current_frame = target_frame;
video->videoinstance.flags |= wi::video::VideoInstance::Flags::DecoderReset;
video->videoinstance.flags &= ~wi::video::VideoInstance::Flags::InitialFirstFrameDecoded;
}
});
AddWidget(&timerSlider);
preview.SetSize(XMFLOAT2(160, 90));
AddWidget(&preview);
infoLabel.Create("");
infoLabel.SetSize(XMFLOAT2(800, 500));
AddWidget(&infoLabel);
SetMinimized(true);
SetVisible(false);
SetEntity(INVALID_ENTITY);
}
void VideoWindow::SetEntity(Entity entity)
{
this->entity = entity;
Scene& scene = editor->GetCurrentScene();
VideoComponent* video = scene.videos.GetComponent(entity);
NameComponent* name = scene.names.GetComponent(entity);
preview.video = video;
if (video != nullptr)
{
filenameLabel.SetText(wi::helper::GetFileNameFromPath(video->filename));
playpauseButton.SetEnabled(true);
stopButton.SetEnabled(true);
loopedCheckbox.SetEnabled(true);
loopedCheckbox.SetCheck(video->IsLooped());
if (video->IsPlaying())
{
playpauseButton.SetText(ICON_PAUSE);
}
else
{
playpauseButton.SetText(ICON_PLAY);
}
if (video->videoResource.IsValid())
{
const wi::video::Video& videofile = video->videoResource.GetVideo();
std::string str;
if (GetDevice()->CheckCapability(wi::graphics::GraphicsDeviceCapability::VIDEO_DECODE_H264))
{
str += "GPU decode: Supported\n";
}
else
{
str += "GPU decode: Not supported\n";
}
str += "Audio track: not implemented\n";
str += "Display buffers in use: " + std::to_string(video->videoinstance.output_textures_used.size()) + "\n\n";
str += "Tip: if you have a material on this entity, the material textures will be replaced by video. This way you can set video textures into the 3D scene.\n\n";
str += "title : " + videofile.title + "\n";
str += "album : " + videofile.album + "\n";
str += "artist : " + videofile.artist + "\n";
str += "year : " + videofile.year + "\n";
str += "comment : " + videofile.comment + "\n";
str += "genre : " + videofile.genre + "\n";
str += "width : " + std::to_string(videofile.width) + "\n";
str += "height : " + std::to_string(videofile.height) + "\n";
str += "duration : " + std::to_string(videofile.duration_seconds) + " seconds\n";
str += "FPS : " + std::to_string(videofile.average_frames_per_second) + "\n";
str += "bit rate : " + std::to_string(videofile.bit_rate) + "\n";
str += "Picture Parameter Sets: " + std::to_string(videofile.pps_count) + "\n";
str += "Sequence Parameter Sets: " + std::to_string(videofile.sps_count) + "\n";
str += "Decode Picture Buffers: " + std::to_string(video->videoinstance.dpb.texture.desc.array_size) + "\n";
infoLabel.SetText(str);
timerSlider.SetRange(0, videofile.duration_seconds);
timerSlider.SetValue(float(video->videoinstance.current_frame) / float(videofile.frames_infos.size()) * videofile.duration_seconds);
}
}
else
{
filenameLabel.SetText("");
playpauseButton.SetEnabled(false);
stopButton.SetEnabled(false);
loopedCheckbox.SetEnabled(false);
infoLabel.SetText("");
}
}
void VideoWindow::ResizeLayout()
{
wi::gui::Window::ResizeLayout();
const float padding = 4;
const float width = GetWidgetAreaSize().x;
float y = padding;
float jump = 20;
auto add = [&](wi::gui::Widget& widget) {
if (!widget.IsVisible())
return;
const float margin_left = 80;
const float margin_right = 40;
widget.SetPos(XMFLOAT2(margin_left, y));
widget.SetSize(XMFLOAT2(width - margin_left - margin_right, widget.GetScale().y));
y += widget.GetSize().y;
y += padding;
};
auto add_right = [&](wi::gui::Widget& widget) {
if (!widget.IsVisible())
return;
const float margin_right = 40;
widget.SetPos(XMFLOAT2(width - margin_right - widget.GetSize().x, y));
y += widget.GetSize().y;
y += padding;
};
auto add_fullwidth = [&](wi::gui::Widget& widget) {
if (!widget.IsVisible())
return;
const float margin_left = padding;
const float margin_right = padding;
widget.SetPos(XMFLOAT2(margin_left, y));
widget.SetSize(XMFLOAT2(width - margin_left - margin_right, widget.GetScale().y));
y += widget.GetSize().y;
y += padding;
};
add_fullwidth(openButton);
add_fullwidth(filenameLabel);
add_fullwidth(preview);
float h_aspect = 9.0f / 16.0f;
if (preview.video != nullptr && preview.video->videoResource.IsValid())
{
const wi::video::Video& video = preview.video->videoResource.GetVideo();
h_aspect = (float)video.height / (float)video.width;
}
preview.SetSize(XMFLOAT2(preview.GetSize().x, preview.GetSize().x * h_aspect));
add(playpauseButton);
loopedCheckbox.SetPos(XMFLOAT2(playpauseButton.GetPos().x - loopedCheckbox.GetSize().x - 2, playpauseButton.GetPos().y));
stopButton.SetPos(XMFLOAT2(playpauseButton.GetPos().x + playpauseButton.GetSize().x + 2, playpauseButton.GetPos().y));
stopButton.SetSize(XMFLOAT2(width - stopButton.GetPos().x - padding, playpauseButton.GetSize().y));
add(timerSlider);
y += jump;
add_fullwidth(infoLabel);
}