Skip to content

Commit

Permalink
Support LayoutRes
Browse files Browse the repository at this point in the history
Initial support for LayoutRes. Allow editing the values in the
properties and respect them in the visual tools. However, resolution
resampling and the resolution mismatch dialogs still need to be
adjusted.
  • Loading branch information
arch1t3cht committed Dec 2, 2024
1 parent f03bcab commit 694a8d6
Show file tree
Hide file tree
Showing 10 changed files with 111 additions and 26 deletions.
20 changes: 20 additions & 0 deletions src/ass_file.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@
#include "ass_info.h"
#include "ass_style.h"
#include "ass_style_storage.h"
#include "async_video_provider.h"
#include "options.h"
#include "project.h"
#include "include/aegisub/context.h"

#include <algorithm>
#include <boost/algorithm/string/case_conv.hpp>
Expand Down Expand Up @@ -153,6 +156,23 @@ void AssFile::GetResolution(int &sw, int &sh) const {
sh = sw == 1280 ? 1024 : sw * 3 / 4;
}

void AssFile::GetLayoutResolution(int &lw, int &lh) const {
lw = GetScriptInfoAsInt("LayoutResX");
lh = GetScriptInfoAsInt("LayoutResY");
}

void AssFile::GetEffectiveLayoutResolution(agi::Context *c, int &lw, int &lh) const {
GetLayoutResolution(lw, lh);
if (lw == 0 || lh == 0) {
if (c->project->VideoProvider()) {
lw = c->project->VideoProvider()->GetWidth();
lh = c->project->VideoProvider()->GetHeight();
} else {
GetResolution(lw, lh);
}
}
}

std::vector<std::string> AssFile::GetStyles() const {
std::vector<std::string> styles;
for (auto& style : Styles)
Expand Down
9 changes: 9 additions & 0 deletions src/ass_file.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ class AssDialogue;
class AssInfo;
class AssStyle;
class wxString;
namespace agi { struct Context; }

template<typename T>
using EntryList = typename boost::intrusive::make_list<T, boost::intrusive::constant_time_size<false>, boost::intrusive::base_hook<AssEntryListHook>>::type;
Expand Down Expand Up @@ -125,6 +126,14 @@ class AssFile {
/// @param[out] w Width
/// @param[in] h Height
void GetResolution(int &w,int &h) const;
/// @brief Get the specified layout resolution, if present, or 0 if it is not present
/// @param[out] w Width
/// @param[in] h Height
void GetLayoutResolution(int &w,int &h) const;
/// @brief Get the effective layout resolution (i.e. falling back to the video resolution, if present)
/// @param[out] w Width
/// @param[in] h Height
void GetEffectiveLayoutResolution(agi::Context *c, int &w,int &h) const;
/// Get the value in a [Script Info] key as int, or 0 if it is not present
int GetScriptInfoAsInt(std::string const& key) const;
/// Get the value in a [Script Info] key as string.
Expand Down
56 changes: 50 additions & 6 deletions src/dialog_properties.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
#include "project.h"
#include "resolution_resampler.h"
#include "validators.h"
#include "video_controller.h"

#include <boost/algorithm/string/predicate.hpp>
#include <vector>
Expand All @@ -59,13 +60,17 @@ class DialogProperties {
wxComboBox *WrapStyle; ///< Wrapping style for long lines
wxTextCtrl *ResX; ///< Script x resolution
wxTextCtrl *ResY; ///< Script y resolution
wxTextCtrl *LayoutResX; ///< Layout x resolution
wxTextCtrl *LayoutResY; ///< Layout y resolution
wxCheckBox *ScaleBorder; ///< If script resolution != video resolution how should borders be handled
wxComboBox *YCbCrMatrix;

/// OK button handler
void OnOK(wxCommandEvent &event);
/// Set script resolution to video resolution button
void OnSetFromVideo(wxCommandEvent &event);
/// Set layout resolution to video resolution button
void OnSetLayoutResFromVideo(wxCommandEvent &event);
/// Set a script info field
/// @param key Name of field
/// @param value New value
Expand Down Expand Up @@ -119,18 +124,36 @@ DialogProperties::DialogProperties(agi::Context *c)
ResX = new wxTextCtrl(&d,-1,"",wxDefaultPosition,wxDefaultSize,0,IntValidator(c->ass->GetScriptInfoAsInt("PlayResX")));
ResY = new wxTextCtrl(&d,-1,"",wxDefaultPosition,wxDefaultSize,0,IntValidator(c->ass->GetScriptInfoAsInt("PlayResY")));

LayoutResX = new wxTextCtrl(&d,-1,"",wxDefaultPosition,wxDefaultSize,0,IntValidator(c->ass->GetScriptInfoAsInt("LayoutResX")));
LayoutResY = new wxTextCtrl(&d,-1,"",wxDefaultPosition,wxDefaultSize,0,IntValidator(c->ass->GetScriptInfoAsInt("LayoutResY")));

wxButton *FromVideo = new wxButton(&d,-1,_("From &video"));
if (!c->project->VideoProvider())
FromVideo->Enable(false);
else
FromVideo->Bind(wxEVT_BUTTON, &DialogProperties::OnSetFromVideo, this);

auto res_sizer = new wxBoxSizer(wxHORIZONTAL);
res_sizer->Add(ResX, 1, wxRIGHT | wxALIGN_CENTER_VERTICAL, 5);
res_sizer->Add(new wxStaticText(&d, -1, "x"), 0, wxALIGN_CENTER | wxRIGHT, 5);
res_sizer->Add(ResY, 1, wxRIGHT | wxALIGN_CENTER_VERTICAL, 5);
auto res_sizer = new wxFlexGridSizer(5, 5, 5);
res_sizer->AddGrowableCol(1, 1);
res_sizer->AddGrowableCol(3, 1);
res_sizer->Add(new wxStaticText(&d, -1, _("Script: ")), wxSizerFlags().Center().Left());
res_sizer->Add(ResX, 1, wxRIGHT | wxALIGN_CENTER_VERTICAL | wxEXPAND, 2);
res_sizer->Add(new wxStaticText(&d, -1, "x"), 0, wxALIGN_CENTER | wxRIGHT, 2);
res_sizer->Add(ResY, 1, wxRIGHT | wxALIGN_CENTER_VERTICAL | wxEXPAND, 2);
res_sizer->Add(FromVideo, 1, 0, 0);

wxButton *LayoutResFromVideo = new wxButton(&d,-1,_("From video"));
if (!c->project->VideoProvider())
LayoutResFromVideo->Enable(false);
else
LayoutResFromVideo->Bind(wxEVT_BUTTON, &DialogProperties::OnSetLayoutResFromVideo, this);

res_sizer->Add(new wxStaticText(&d, -1, _("Layout: ")), wxSizerFlags().Center().Left());
res_sizer->Add(LayoutResX, 1, wxRIGHT | wxALIGN_CENTER_VERTICAL | wxEXPAND, 2);
res_sizer->Add(new wxStaticText(&d, -1, "x"), 0, wxALIGN_CENTER | wxRIGHT, 2);
res_sizer->Add(LayoutResY, 1, wxRIGHT | wxALIGN_CENTER_VERTICAL | wxEXPAND, 2);
res_sizer->Add(LayoutResFromVideo, 1, 0, 0);

YCbCrMatrix = new wxComboBox(&d, -1, to_wx(c->ass->GetScriptInfo("YCbCr Matrix")),
wxDefaultPosition, wxDefaultSize, to_wx(MatrixNames()), wxCB_READONLY);

Expand Down Expand Up @@ -189,6 +212,8 @@ void DialogProperties::OnOK(wxCommandEvent &) {

count += SetInfoIfDifferent("PlayResX", from_wx(ResX->GetValue()));
count += SetInfoIfDifferent("PlayResY", from_wx(ResY->GetValue()));
count += SetInfoIfDifferent("LayoutResX", from_wx(LayoutResX->GetValue()));
count += SetInfoIfDifferent("LayoutResY", from_wx(LayoutResY->GetValue()));
count += SetInfoIfDifferent("WrapStyle", std::to_string(WrapStyle->GetSelection()));
count += SetInfoIfDifferent("ScaledBorderAndShadow", ScaleBorder->GetValue() ? "yes" : "no");
count += SetInfoIfDifferent("YCbCr Matrix", from_wx(YCbCrMatrix->GetValue()));
Expand All @@ -206,9 +231,28 @@ int DialogProperties::SetInfoIfDifferent(std::string const& key, std::string con
return 0;
}

std::pair<int, int> GetVideoDisplayResolution(agi::Context *c) {
double dar = c->videoController->GetAspectRatioValue();
int width = c->project->VideoProvider()->GetWidth();
int height = c->project->VideoProvider()->GetHeight();
double sar = double(width) / double(height);

return std::make_pair(
width * std::max(1., dar / sar),
height * std::max(1., sar / dar)
);
}

void DialogProperties::OnSetFromVideo(wxCommandEvent &) {
ResX->SetValue(std::to_wstring(c->project->VideoProvider()->GetWidth()));
ResY->SetValue(std::to_wstring(c->project->VideoProvider()->GetHeight()));
auto [width, height] = GetVideoDisplayResolution(c);
ResX->SetValue(std::to_wstring(width));
ResY->SetValue(std::to_wstring(height));
}

void DialogProperties::OnSetLayoutResFromVideo(wxCommandEvent &) {
auto [width, height] = GetVideoDisplayResolution(c);
LayoutResX->SetValue(std::to_wstring(width));
LayoutResY->SetValue(std::to_wstring(height));
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/gl_wrap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -401,11 +401,11 @@ void OpenGLWrapper::SetScale(Vector2D scale) {
glScalef(scale.X() / 100.f, scale.Y() / 100.f, 1.f);
}

void OpenGLWrapper::SetRotation(float x, float y, float z) {
void OpenGLWrapper::SetRotation(float x, float y, float z, float zScale) {
PrepareTransform();
float matrix[16] = { 2500, 0, 0, 0, 0, 2500, 0, 0, 0, 0, 1, 1, 0, 0, 2500, 2500 };
glMultMatrixf(matrix);
glScalef(1.f, 1.f, 8.f);
glScalef(1.f, 1.f, 8.f / zScale);
glRotatef(y, 0.f, -1.f, 0.f);
glRotatef(x, -1.f, 0.f, 0.f);
glRotatef(z, 0.f, 0.f, -1.f);
Expand Down
2 changes: 1 addition & 1 deletion src/gl_wrap.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ class OpenGLWrapper {

void SetScale(Vector2D scale);
void SetOrigin(Vector2D origin);
void SetRotation(float x, float y, float z);
void SetRotation(float x, float y, float z, float zScale = 1);
void SetShear(float x, float y);
void ResetTransform();

Expand Down
16 changes: 10 additions & 6 deletions src/visual_tool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,23 +57,27 @@ VisualToolBase::VisualToolBase(VideoDisplay *parent, agi::Context *context)
, shaded_area_alpha_opt(OPT_GET("Colour/Visual Tools/Shaded Area Alpha"))
, file_changed_connection(c->ass->AddCommitListener(&VisualToolBase::OnCommit, this))
{
int script_w, script_h;
c->ass->GetResolution(script_w, script_h);
script_res = Vector2D(script_w, script_h);
SetResolutions();
active_line = GetActiveDialogueLine();
connections.push_back(c->selectionController->AddActiveLineListener(&VisualToolBase::OnActiveLineChanged, this));
connections.push_back(c->videoController->AddSeekListener(&VisualToolBase::OnSeek, this));
parent->Bind(wxEVT_MOUSE_CAPTURE_LOST, &VisualToolBase::OnMouseCaptureLost, this);
}

void VisualToolBase::SetResolutions() {
int script_w, script_h, layout_w, layout_h;
c->ass->GetResolution(script_w, script_h);
c->ass->GetEffectiveLayoutResolution(c, layout_w, layout_h);
script_res = Vector2D(script_w, script_h);
layout_res = Vector2D(layout_w, layout_h);
}

void VisualToolBase::OnCommit(int type) {
holding = false;
dragging = false;

if (type == AssFile::COMMIT_NEW || type & AssFile::COMMIT_SCRIPTINFO) {
int script_w, script_h;
c->ass->GetResolution(script_w, script_h);
script_res = Vector2D(script_w, script_h);
SetResolutions();
OnCoordinateSystemsChanged();
}

Expand Down
2 changes: 2 additions & 0 deletions src/visual_tool.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ namespace agi {
/// functionality as possible is implemented here to avoid having four copies
/// of each method for no good reason (and four times as many error messages)
class VisualToolBase {
void SetResolutions();
void OnCommit(int type);
void OnSeek(int new_frame);

Expand Down Expand Up @@ -102,6 +103,7 @@ class VisualToolBase {
Vector2D mouse_pos; ///< Last seen mouse position
Vector2D drag_start; ///< Mouse position at the beginning of the last drag
Vector2D script_res; ///< Script resolution
Vector2D layout_res; ///< Layout resolution
Vector2D video_pos; ///< Top-left corner of the video in the display area
Vector2D video_res; ///< Video resolution
Vector2D client_size; ///< The size of the display area
Expand Down
24 changes: 14 additions & 10 deletions src/visual_tool_perspective.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
static const float pi = 3.1415926536f;
static const float deg2rad = pi / 180.f;
static const float rad2deg = 180.f / pi;
static const float screen_z = 312.5;
static const float default_screen_z = 312.5;
static const char *ambient_plane_key = "_aegi_perspective_ambient_plane";

static const int BUTTON_ID_BASE = 1400;
Expand Down Expand Up @@ -127,6 +127,10 @@ std::vector<Vector2D> MakeRect(Vector2D a, Vector2D b) {
});
}

inline float VisualToolPerspective::screenZ() const {
return default_screen_z * script_res.Y() / layout_res.Y();
}

void VisualToolPerspective::AddTool(std::string command_name, VisualToolPerspectiveSetting setting) {
cmd::Command *command = cmd::get(command_name);
int icon_size = OPT_GET("App/Toolbar Icon Size")->GetInt();
Expand Down Expand Up @@ -331,7 +335,7 @@ void VisualToolPerspective::Draw() {
// Transform grid
gl.SetOrigin(FromScriptCoords(org));
gl.SetScale(100 * video_res / script_res);
gl.SetRotation(angle_x, angle_y, angle_z);
gl.SetRotation(angle_x, angle_y, angle_z, script_res.Y() / layout_res.Y());
gl.SetScale(fsc);
gl.SetShear(fax, fay);
Vector2D glScale = (bbox.second.Y() - bbox.first.Y()) * Vector2D(1, 1) / spacing / 4;
Expand Down Expand Up @@ -591,7 +595,7 @@ bool VisualToolPerspective::InnerToText() {
// with the following coefficients.
float a = (1 - z1) * (1 - z3);
Vector2D b = z1 * v1 + z3 * v3 - z1 * z3 * (v1 + v3);
float c = z1 * z3 * v1.Dot(v3) + (z1 - 1) * (z3 - 1) * screen_z * screen_z;
float c = z1 * z3 * v1.Dot(v3) + (z1 - 1) * (z3 - 1) * screenZ() * screenZ();

// Our default value for t, which would put \org at the center of the quad.
// We'll try to find a value for \org that's as close as possible to it.
Expand Down Expand Up @@ -635,10 +639,10 @@ bool VisualToolPerspective::InnerToText() {
q2 = q2 - org;
q3 = q3 - org;

Vector3D r0 = Vector3D(q0, screen_z);
Vector3D r1 = z1 * Vector3D(q1, screen_z);
Vector3D r2 = (z1 + z3 - 1) * Vector3D(q2, screen_z);
Vector3D r3 = z3 * Vector3D(q3, screen_z);
Vector3D r0 = Vector3D(q0, screenZ());
Vector3D r1 = z1 * Vector3D(q1, screenZ());
Vector3D r2 = (z1 + z3 - 1) * Vector3D(q2, screenZ());
Vector3D r3 = z3 * Vector3D(q3, screenZ());
std::vector<Vector3D> r({r0, r1, r2, r3});

// Find the z coordinate of the point projecting to the origin
Expand All @@ -648,9 +652,9 @@ bool VisualToolPerspective::InnerToText() {
Solve2x2(side0.X(), side1.X(), side0.Y(), side1.Y(), -r0.X(), -r0.Y(), orgla0, orgla1);
float orgz = (r0 + orgla0 * side0 + orgla1 * side1).Z();

// Normalize so the origin has z=screen_z, and move the screen plane to z=0
// Normalize so the origin has z=screenZ, and move the screen plane to z=0
for (int i = 0; i < 4; i++)
r[i] = r[i] * screen_z / orgz - Vector3D(0, 0, screen_z);
r[i] = r[i] * screenZ() / orgz - Vector3D(0, 0, screenZ());

// Find the rotations
Vector3D n = (r[1] - r[0]).Cross(r[3] - r[0]);
Expand Down Expand Up @@ -825,7 +829,7 @@ void VisualToolPerspective::TextToPersp() {
q = q.RotateX(-angle_x * deg2rad);
q = q.RotateY(angle_y * deg2rad);
// Project
q = (screen_z / (q.Z() + screen_z)) * q;
q = (screenZ() / (q.Z() + screenZ())) * q;
// Move to origin
Vector2D r = q.XY() + org;
inner_corners[i]->pos = FromScriptCoords(r);
Expand Down
2 changes: 2 additions & 0 deletions src/visual_tool_perspective.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@ class VisualToolPerspective final : public VisualTool<VisualToolPerspectiveDragg
std::vector<Feature *> inner_corners;
std::vector<Feature *> outer_corners;

inline float screenZ() const;

std::vector<Vector2D> FeaturePositions(std::vector<Feature *> features) const;
void UpdateInner();
void UpdateOuter();
Expand Down
2 changes: 1 addition & 1 deletion src/visual_tool_rotatexy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ void VisualToolRotateXY::Draw() {
// Transform grid
gl.SetOrigin(org->pos);
gl.SetScale(100 * video_res / script_res);
gl.SetRotation(angle_x, angle_y, angle_z);
gl.SetRotation(angle_x, angle_y, angle_z, script_res.Y() / layout_res.Y());
gl.SetScale(fsc);
gl.SetShear(fax, fay);

Expand Down

0 comments on commit 694a8d6

Please sign in to comment.