32
32
/// @ingroup video main_ui
37
35
#include "video_display.h"
39
37
#include "ass_file.h"
38
#include "async_video_provider.h"
40
39
#include "command/command.h"
41
40
#include "compat.h"
42
42
#include "include/aegisub/context.h"
43
43
#include "include/aegisub/hotkey.h"
44
44
#include "include/aegisub/menu.h"
45
45
#include "options.h"
47
#include "retina_helper.h"
46
48
#include "spline_curve.h"
47
#include "subs_controller.h"
48
#include "threaded_frame_source.h"
50
50
#include "video_out_gl.h"
51
#include "video_context.h"
52
#include "video_frame.h"
51
#include "video_controller.h"
53
52
#include "visual_tool.h"
55
#include <libaegisub/util.h>
54
#include <libaegisub/make_unique.h>
57
56
#include <algorithm>
59
57
#include <wx/combobox.h>
60
#include <wx/dataobj.h>
61
#include <wx/dcclient.h>
62
58
#include <wx/menu.h>
63
59
#include <wx/textctrl.h>
64
60
#include <wx/toolbar.h>
72
68
/// Attribute list for gl canvases; set the canvases to doublebuffered rgba with an 8 bit stencil buffer
73
69
int attribList[] = { WX_GL_RGBA , WX_GL_DOUBLEBUFFER, WX_GL_STENCIL_SIZE, 8, 0 };
75
/// @class VideoOutRenderException
76
/// @extends VideoOutException
77
/// @brief An OpenGL error occurred while uploading or displaying a frame
78
class OpenGlException : public agi::Exception {
71
/// An OpenGL error occurred while uploading or displaying a frame
72
class OpenGlException final : public agi::Exception {
80
74
OpenGlException(const char *func, int err)
81
: agi::Exception(from_wx(wxString::Format("%s failed with error code %d", func, err)))
75
: agi::Exception(agi::format("%s failed with error code %d", func, err))
83
const char * GetName() const override { return "video/opengl"; }
84
Exception * Copy() const override { return new OpenGlException(*this); }
87
79
#define E(cmd) cmd; if (GLenum err = glGetError()) throw OpenGlException(#cmd, err)
89
VideoDisplay::VideoDisplay(
90
wxToolBar *visualSubToolBar,
81
VideoDisplay::VideoDisplay(wxToolBar *toolbar, bool freeSize, wxComboBox *zoomBox, wxWindow *parent, agi::Context *c)
95
82
: wxGLCanvas(parent, -1, attribList)
96
83
, autohideTools(OPT_GET("Tool/Visual/Autohide"))
98
85
, zoomValue(OPT_GET("Video/Default Zoom")->GetInt() * .125 + .125)
99
, toolBar(visualSubToolBar)
100
87
, zoomBox(zoomBox)
101
88
, freeSize(freeSize)
89
, retina_helper(agi::make_unique<RetinaHelper>(this))
90
, scale_factor(retina_helper->GetScaleFactor())
91
, scale_factor_connection(retina_helper->AddScaleFactorListener([=](int new_scale_factor) {
92
double new_zoom = zoomValue * new_scale_factor / scale_factor;
93
scale_factor = new_scale_factor;
103
zoomBox->SetValue(wxString::Format("%g%%", zoomValue * 100.));
97
zoomBox->SetValue(fmt_wx("%g%%", zoomValue * 100.));
104
98
zoomBox->Bind(wxEVT_COMBOBOX, &VideoDisplay::SetZoomFromBox, this);
105
99
zoomBox->Bind(wxEVT_TEXT_ENTER, &VideoDisplay::SetZoomFromBoxText, this);
107
101
con->videoController->Bind(EVT_FRAME_READY, &VideoDisplay::UploadFrameData, this);
108
slots.push_back(con->videoController->AddVideoOpenListener(&VideoDisplay::UpdateSize, this));
109
slots.push_back(con->videoController->AddARChangeListener(&VideoDisplay::UpdateSize, this));
111
slots.push_back(con->subsController->AddFileSaveListener(&VideoDisplay::OnSubtitlesSave, this));
102
connections = agi::signal::make_vector({
103
con->project->AddVideoProviderListener(&VideoDisplay::UpdateSize, this),
104
con->videoController->AddARChangeListener(&VideoDisplay::UpdateSize, this),
113
107
Bind(wxEVT_PAINT, std::bind(&VideoDisplay::Render, this));
114
108
Bind(wxEVT_SIZE, &VideoDisplay::OnSizeEvent, this);
200
195
E(glMatrixMode(GL_PROJECTION));
201
196
E(glLoadIdentity());
202
E(glOrtho(0.0f, videoSize.GetWidth(), videoSize.GetHeight(), 0.0f, -1000.0f, 1000.0f));
197
E(glOrtho(0.0f, videoSize.GetWidth() / scale_factor, videoSize.GetHeight() / scale_factor, 0.0f, -1000.0f, 1000.0f));
204
199
if (OPT_GET("Video/Overscan Mask")->GetBool()) {
205
200
double ar = con->videoController->GetAspectRatioValue();
271
266
void VideoDisplay::PositionVideo() {
272
if (!con->videoController->IsLoaded() || !IsShownOnScreen()) return;
267
auto provider = con->project->VideoProvider();
268
if (!provider || !IsShownOnScreen()) return;
274
270
viewport_left = 0;
275
viewport_bottom = GetClientSize().GetHeight() - videoSize.GetHeight();
271
viewport_bottom = GetClientSize().GetHeight() * scale_factor - videoSize.GetHeight();
276
272
viewport_top = 0;
277
273
viewport_width = videoSize.GetWidth();
278
274
viewport_height = videoSize.GetHeight();
281
int vidW = con->videoController->GetWidth();
282
int vidH = con->videoController->GetHeight();
277
int vidW = provider->GetWidth();
278
int vidH = provider->GetHeight();
284
280
AspectRatio arType = con->videoController->GetAspectRatioType();
285
281
double displayAr = double(viewport_width) / viewport_height;
303
tool->SetDisplayArea(viewport_left, viewport_top, viewport_width, viewport_height);
299
tool->SetDisplayArea(viewport_left / scale_factor, viewport_top / scale_factor,
300
viewport_width / scale_factor, viewport_height / scale_factor);
308
305
void VideoDisplay::UpdateSize() {
309
if (!con->videoController->IsLoaded() || !IsShownOnScreen()) return;
306
auto provider = con->project->VideoProvider();
307
if (!provider || !IsShownOnScreen()) return;
311
videoSize.Set(con->videoController->GetWidth(), con->videoController->GetHeight());
309
videoSize.Set(provider->GetWidth(), provider->GetHeight());
312
310
videoSize *= zoomValue;
313
311
if (con->videoController->GetAspectRatioType() != AspectRatio::Default)
314
312
videoSize.SetWidth(videoSize.GetHeight() * con->videoController->GetAspectRatioValue());
321
319
wxSize cs = GetClientSize();
322
320
wxSize oldSize = top->GetSize();
323
top->SetSize(top->GetSize() + videoSize - cs);
321
top->SetSize(top->GetSize() + videoSize / scale_factor - cs);
324
322
SetClientSize(cs + top->GetSize() - oldSize);
327
SetMinClientSize(videoSize);
328
SetMaxClientSize(videoSize);
325
SetMinClientSize(videoSize / scale_factor);
326
SetMaxClientSize(videoSize / scale_factor);
330
328
GetGrandParent()->Layout();
336
334
void VideoDisplay::OnSizeEvent(wxSizeEvent &event) {
338
videoSize = GetClientSize();
336
videoSize = GetClientSize() * scale_factor;
340
zoomValue = double(viewport_height) / con->videoController->GetHeight();
341
zoomBox->ChangeValue(wxString::Format("%g%%", zoomValue * 100.));
338
zoomValue = double(viewport_height) / con->project->VideoProvider()->GetHeight();
339
zoomBox->ChangeValue(fmt_wx("%g%%", zoomValue * 100.));
340
con->ass->Properties.video_zoom = zoomValue;
381
380
void VideoDisplay::SetZoom(double value) {
381
if (value == 0) return;
382
382
zoomValue = std::max(value, .125);
383
383
size_t selIndex = zoomValue / .125 - 1;
384
384
if (selIndex < zoomBox->GetCount())
385
385
zoomBox->SetSelection(selIndex);
386
zoomBox->ChangeValue(wxString::Format("%g%%", zoomValue * 100.));
386
zoomBox->ChangeValue(fmt_wx("%g%%", zoomValue * 100.));
387
con->ass->Properties.video_zoom = zoomValue;