mirror of https://github.com/odrling/Aegisub
Merge branch 'vector_clip_actions' into feature
This commit is contained in:
commit
bd4e79fdf9
|
@ -23,6 +23,7 @@
|
|||
#include "../visual_tool_clip.h"
|
||||
#include "../visual_tool_cross.h"
|
||||
#include "../visual_tool_drag.h"
|
||||
#include "../visual_tool_perspective.h"
|
||||
#include "../visual_tool_rotatexy.h"
|
||||
#include "../visual_tool_rotatez.h"
|
||||
#include "../visual_tool_scale.h"
|
||||
|
@ -100,6 +101,14 @@ namespace {
|
|||
STR_HELP("Rotate subtitles on their X and Y axes")
|
||||
};
|
||||
|
||||
struct visual_mode_perspective final : public visual_tool_command<VisualToolPerspective> {
|
||||
CMD_NAME("video/tool/perspective")
|
||||
CMD_ICON(visual_vector_clip_drag) //TODO
|
||||
STR_MENU("Apply 3D Perspective")
|
||||
STR_DISP("Apply 3D Perspective")
|
||||
STR_HELP("Rotate and shear subtitles to make them fit a given quad's perspective")
|
||||
};
|
||||
|
||||
struct visual_mode_scale final : public visual_tool_command<VisualToolScale> {
|
||||
CMD_NAME("video/tool/scale")
|
||||
CMD_ICON(visual_scale)
|
||||
|
@ -191,6 +200,7 @@ namespace cmd {
|
|||
reg(agi::make_unique<visual_mode_drag>());
|
||||
reg(agi::make_unique<visual_mode_rotate_z>());
|
||||
reg(agi::make_unique<visual_mode_rotate_xy>());
|
||||
reg(agi::make_unique<visual_mode_perspective>());
|
||||
reg(agi::make_unique<visual_mode_scale>());
|
||||
reg(agi::make_unique<visual_mode_clip>());
|
||||
reg(agi::make_unique<visual_mode_vector_clip>());
|
||||
|
|
|
@ -73,6 +73,7 @@
|
|||
"video/tool/drag",
|
||||
"video/tool/rotate/z",
|
||||
"video/tool/rotate/xy",
|
||||
"video/tool/perspective",
|
||||
"video/tool/scale",
|
||||
"video/tool/clip",
|
||||
"video/tool/vector_clip",
|
||||
|
|
|
@ -144,6 +144,7 @@ aegisub_src = files(
|
|||
'utils.cpp',
|
||||
'validators.cpp',
|
||||
'vector2d.cpp',
|
||||
'vector3d.cpp',
|
||||
'version.cpp',
|
||||
'video_box.cpp',
|
||||
'video_controller.cpp',
|
||||
|
@ -160,6 +161,7 @@ aegisub_src = files(
|
|||
'visual_tool_clip.cpp',
|
||||
'visual_tool_cross.cpp',
|
||||
'visual_tool_drag.cpp',
|
||||
'visual_tool_perspective.cpp',
|
||||
'visual_tool_rotatexy.cpp',
|
||||
'visual_tool_rotatez.cpp',
|
||||
'visual_tool_scale.cpp',
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
// Copyright (c) 2022, arch1t3cht <arch1t3cht@gmail.com>
|
||||
//
|
||||
// Permission to use, copy, modify, and distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
//
|
||||
// Aegisub Project http://www.aegisub.org/
|
||||
|
||||
/// @file vector3d.cpp
|
||||
/// @brief 3D mathematical vector used in visual typesetting
|
||||
/// @ingroup utility visual_ts
|
||||
///
|
||||
|
||||
#include "vector3d.h"
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
#include <libaegisub/format.h>
|
||||
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
|
||||
Vector3D::Vector3D()
|
||||
: x(std::numeric_limits<float>::min())
|
||||
, y(std::numeric_limits<float>::min())
|
||||
, z(std::numeric_limits<float>::min())
|
||||
{
|
||||
}
|
||||
|
||||
Vector3D operator *(float f, Vector3D v) {
|
||||
return Vector3D(v.X() * f, v.Y() * f, v.Z() * f);
|
||||
}
|
||||
|
||||
Vector3D operator /(float f, Vector3D v) {
|
||||
return Vector3D(f / v.X(), f / v.Y(), f / v.Z());
|
||||
}
|
||||
|
||||
Vector3D operator +(float f, Vector3D v) {
|
||||
return Vector3D(v.X() + f, v.Y() + f, v.Z() + f);
|
||||
}
|
||||
|
||||
Vector3D operator -(float f, Vector3D v) {
|
||||
return Vector3D(f - v.X(), f - v.Y(), f - v.Z());
|
||||
}
|
||||
|
||||
Vector3D Vector3D::Unit() const {
|
||||
float len = Len();
|
||||
if (len == 0)
|
||||
return Vector3D(0, 0, 0);
|
||||
return *this / len;
|
||||
}
|
||||
|
||||
Vector3D Vector3D::RotateX(float angle) const {
|
||||
return Vector3D(x, y * cos(angle) - z * sin(angle), y * sin(angle) + z * cos(angle));
|
||||
}
|
||||
|
||||
Vector3D Vector3D::RotateY(float angle) const {
|
||||
return Vector3D(x * cos(angle) - z * sin(angle), y, x * sin(angle) + z * cos(angle));
|
||||
}
|
||||
|
||||
Vector3D Vector3D::RotateZ(float angle) const {
|
||||
return Vector3D(x * cos(angle) - y * sin(angle), x * sin(angle) + y * cos(angle), z);
|
||||
}
|
||||
|
||||
Vector3D Vector3D::Max(Vector3D param) const {
|
||||
return Vector3D(std::max(x, param.x), std::max(y, param.y), std::max(z, param.z));
|
||||
}
|
||||
|
||||
Vector3D Vector3D::Min(Vector3D param) const {
|
||||
return Vector3D(std::min(x, param.x), std::min(y, param.y), std::max(z, param.z));
|
||||
}
|
||||
|
||||
Vector3D Vector3D::Round(float step) const {
|
||||
return Vector3D(floorf(x / step + .5f) * step, floorf(y / step + .5f) * step, floorf(z / step + .5f));
|
||||
}
|
||||
|
||||
Vector3D::operator bool() const {
|
||||
return *this != Vector3D();
|
||||
}
|
||||
|
||||
std::string Vector3D::PStr(char sep) const {
|
||||
return "(" + Str(sep) + ")";
|
||||
}
|
||||
|
||||
std::string Vector3D::DStr(char sep) const {
|
||||
return agi::format("%d%c%d%c%d", (int)x, sep, (int)y, sep, (int)z);
|
||||
}
|
||||
|
||||
std::string Vector3D::Str(char sep) const {
|
||||
return float_to_string(x,2) + sep + float_to_string(y,2) + sep + float_to_string(z, 2);
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
// Copyright (c) 2022, arch1t3cht <arch1t3cht@gmail.com>
|
||||
//
|
||||
// Permission to use, copy, modify, and distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
//
|
||||
// Aegisub Project http://www.aegisub.org/
|
||||
|
||||
/// @file vector3d.h
|
||||
/// @see vector3d.cpp
|
||||
/// @ingroup utility visual_ts
|
||||
///
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cmath>
|
||||
#include <string>
|
||||
#include "vector2d.h"
|
||||
|
||||
class Vector3D {
|
||||
float x, y, z;
|
||||
|
||||
public:
|
||||
float X() const { return x; }
|
||||
float Y() const { return y; }
|
||||
float Z() const { return z; }
|
||||
Vector2D XY() const { return Vector2D(x, y); }
|
||||
|
||||
Vector3D();
|
||||
Vector3D(Vector2D xy) : x(xy.X()), y(xy.Y()), z(0.) { }
|
||||
Vector3D(Vector2D xy, float z) : x(xy.X()), y(xy.Y()), z(z) { }
|
||||
Vector3D(float x, float y, float z) : x(x), y(y), z(z) { }
|
||||
|
||||
bool operator ==(const Vector3D r) const { return x == r.x && y == r.y; }
|
||||
bool operator !=(const Vector3D r) const { return x != r.x || y != r.y; }
|
||||
explicit operator bool() const;
|
||||
|
||||
Vector3D operator -() const { return Vector3D(-x, -y, -z); }
|
||||
Vector3D operator +(const Vector3D r) const { return Vector3D(x + r.x, y + r.y, z + r.z); }
|
||||
Vector3D operator -(const Vector3D r) const { return Vector3D(x - r.x, y - r.y, z - r.z); }
|
||||
Vector3D operator *(const Vector3D r) const { return Vector3D(x * r.x, y * r.y, z * r.z); }
|
||||
Vector3D operator /(const Vector3D r) const { return Vector3D(x / r.x, y / r.y, z / r.z); }
|
||||
Vector3D operator +(float param) const { return Vector3D(x + param, y + param, z + param); }
|
||||
Vector3D operator -(float param) const { return Vector3D(x - param, y - param, z - param); }
|
||||
Vector3D operator *(float param) const { return Vector3D(x * param, y * param, z * param); }
|
||||
Vector3D operator /(float param) const { return Vector3D(x / param, y / param, z / param); }
|
||||
|
||||
Vector3D Unit() const;
|
||||
|
||||
Vector3D RotateX(float angle) const;
|
||||
Vector3D RotateY(float angle) const;
|
||||
Vector3D RotateZ(float angle) const;
|
||||
|
||||
Vector3D Max(Vector3D param) const;
|
||||
Vector3D Min(Vector3D param) const;
|
||||
Vector3D Round(float step) const;
|
||||
|
||||
Vector3D Cross(const Vector3D param) const { return Vector3D(y * param.z - z * param.y, z * param.x - x * param.z, x * param.y - y * param.x); }
|
||||
float Dot(const Vector3D param) const { return x * param.x + y * param.y + z * param.z; }
|
||||
|
||||
float Len() const { return sqrt(x*x + y*y + z*z); }
|
||||
float SquareLen() const { return x*x + y*y + z*z; }
|
||||
|
||||
/// Get as string with given separator
|
||||
std::string Str(char sep = ',') const;
|
||||
/// Get as string surrounded by parentheses with given separator
|
||||
std::string PStr(char sep = ',') const;
|
||||
/// Get as string with given separator with values rounded to ints
|
||||
std::string DStr(char sep = ',') const;
|
||||
};
|
||||
|
||||
Vector3D operator * (float f, Vector3D v);
|
||||
Vector3D operator / (float f, Vector3D v);
|
||||
Vector3D operator + (float f, Vector3D v);
|
||||
Vector3D operator - (float f, Vector3D v);
|
|
@ -23,6 +23,7 @@
|
|||
#include "ass_dialogue.h"
|
||||
#include "ass_file.h"
|
||||
#include "ass_style.h"
|
||||
#include "auto4_base.h"
|
||||
#include "compat.h"
|
||||
#include "include/aegisub/context.h"
|
||||
#include "options.h"
|
||||
|
@ -475,6 +476,57 @@ void VisualToolBase::GetLineScale(AssDialogue *diag, Vector2D &scale) {
|
|||
scale = Vector2D(x, y);
|
||||
}
|
||||
|
||||
float VisualToolBase::GetLineFontSize(AssDialogue *diag) {
|
||||
float fs = 0.f;
|
||||
|
||||
if (AssStyle *style = c->ass->GetStyle(diag->Style))
|
||||
fs = style->fontsize;
|
||||
auto blocks = diag->ParseTags();
|
||||
if (param_vec tag = find_tag(blocks, "\\fs"))
|
||||
fs = tag->front().Get(fs);
|
||||
|
||||
return fs;
|
||||
}
|
||||
|
||||
int VisualToolBase::GetLineAlignment(AssDialogue *diag) {
|
||||
int an = 0;
|
||||
|
||||
if (AssStyle *style = c->ass->GetStyle(diag->Style))
|
||||
an = style->alignment;
|
||||
auto blocks = diag->ParseTags();
|
||||
if (param_vec tag = find_tag(blocks, "\\an"))
|
||||
an = tag->front().Get(an);
|
||||
|
||||
return an;
|
||||
}
|
||||
|
||||
void VisualToolBase::GetLineBaseExtents(AssDialogue *diag, double &width, double &height, double &descent, double &extlead) {
|
||||
width = 0.;
|
||||
height = 0.;
|
||||
descent = 0.;
|
||||
extlead = 0.;
|
||||
|
||||
AssStyle style;
|
||||
if (AssStyle *basestyle = c->ass->GetStyle(diag->Style)) {
|
||||
style = AssStyle(basestyle->GetEntryData());
|
||||
style.scalex = 100.;
|
||||
style.scaley = 100.;
|
||||
}
|
||||
|
||||
auto blocks = diag->ParseTags();
|
||||
if (param_vec tag = find_tag(blocks, "\\fs"))
|
||||
style.fontsize = tag->front().Get(style.fontsize);
|
||||
if (param_vec tag = find_tag(blocks, "\\fn"))
|
||||
style.font = tag->front().Get(style.font);
|
||||
|
||||
std::string text = diag->GetStrippedText();
|
||||
if (!Automation4::CalculateTextExtents(&style, text, width, height, descent, extlead)) {
|
||||
// meh... let's make some ballpark estimates
|
||||
width = style.fontsize * text.length();
|
||||
height = style.fontsize;
|
||||
}
|
||||
}
|
||||
|
||||
void VisualToolBase::GetLineClip(AssDialogue *diag, Vector2D &p1, Vector2D &p2, bool &inverse) {
|
||||
inverse = false;
|
||||
|
||||
|
|
|
@ -128,6 +128,14 @@ protected:
|
|||
void GetLineRotation(AssDialogue *diag, float &rx, float &ry, float &rz);
|
||||
void GetLineShear(AssDialogue *diag, float& fax, float& fay);
|
||||
void GetLineScale(AssDialogue *diag, Vector2D &scale);
|
||||
float GetLineFontSize(AssDialogue *diag);
|
||||
int GetLineAlignment(AssDialogue *diag);
|
||||
/// @brief Compute text extents of the given line without any formatting
|
||||
///
|
||||
/// Formatting tags are stripped and \fs tags are respected, but \fscx and \fscy are kept as 100 even if
|
||||
/// they are different in the style.
|
||||
/// Returns a rough estimate when getting the precise extents fails
|
||||
void GetLineBaseExtents(AssDialogue *diag, double &width, double &height, double &descent, double &extlead);
|
||||
void GetLineClip(AssDialogue *diag, Vector2D &p1, Vector2D &p2, bool &inverse);
|
||||
std::string GetLineVectorClip(AssDialogue *diag, int &scale, bool &inverse);
|
||||
|
||||
|
|
|
@ -0,0 +1,271 @@
|
|||
// Copyright (c) 2022, arch1t3cht <arch1t3cht@gmail.com>
|
||||
//
|
||||
// Permission to use, copy, modify, and distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
//
|
||||
// Aegisub Project http://www.aegisub.org/
|
||||
|
||||
/// @file visual_tool_perspective.cpp
|
||||
/// @brief 3D perspective visual typesetting tool
|
||||
/// @ingroup visual_ts
|
||||
|
||||
#include "visual_tool_perspective.h"
|
||||
|
||||
#include "compat.h"
|
||||
#include "include/aegisub/context.h"
|
||||
#include "options.h"
|
||||
#include "selection_controller.h"
|
||||
#include "vector3d.h"
|
||||
|
||||
#include <libaegisub/format.h>
|
||||
|
||||
#include <cmath>
|
||||
#include <wx/colour.h>
|
||||
|
||||
static const float deg2rad = 3.1415926536f / 180.f;
|
||||
static const float rad2deg = 180.f / 3.1415926536f;
|
||||
static const float screen_z = 312.5;
|
||||
|
||||
void VisualToolPerspective::Solve2x2Proper(float a11, float a12, float a21, float a22, float b1, float b2, float &x1, float &x2) {
|
||||
// LU decomposition
|
||||
// i = 1
|
||||
a21 = a21 / a11;
|
||||
// i = 2
|
||||
a22 = a22 - a21 * a12;
|
||||
// forward substitution
|
||||
float z1 = b1;
|
||||
float z2 = b2 - a21 * z1;
|
||||
// backward substitution
|
||||
x2 = z2 / a22;
|
||||
x1 = (z1 - a12 * x2) / a11;
|
||||
}
|
||||
|
||||
|
||||
void VisualToolPerspective::Solve2x2(float a11, float a12, float a21, float a22, float b1, float b2, float &x1, float &x2) {
|
||||
// Simple pivoting
|
||||
if (abs(a11) >= abs(a21))
|
||||
Solve2x2Proper(a11, a12, a21, a22, b1, b2, x1, x2);
|
||||
else
|
||||
Solve2x2Proper(a21, a22, a11, a12, b2, b1, x1, x2);
|
||||
}
|
||||
|
||||
|
||||
VisualToolPerspective::VisualToolPerspective(VideoDisplay *parent, agi::Context *context)
|
||||
: VisualTool<VisualDraggableFeature>(parent, context)
|
||||
{
|
||||
orgf = new Feature;
|
||||
orgf->type = DRAG_BIG_TRIANGLE;
|
||||
features.push_back(*orgf);
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
quad_corners.push_back(new Feature);
|
||||
old_positions.push_back(Vector2D());
|
||||
quad_corners.back()->type = DRAG_SMALL_CIRCLE;
|
||||
features.push_back(*quad_corners.back());
|
||||
}
|
||||
}
|
||||
|
||||
void VisualToolPerspective::Draw() {
|
||||
if (!active_line) return;
|
||||
|
||||
wxColour line_color = to_wx(line_color_primary_opt->GetColor());
|
||||
gl.SetLineColour(line_color);
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
gl.DrawDashedLine(quad_corners[i]->pos, quad_corners[(i + 1) % 4]->pos, 6);
|
||||
}
|
||||
|
||||
DrawAllFeatures();
|
||||
}
|
||||
|
||||
void VisualToolPerspective::UpdateDrag(Feature *feature) {
|
||||
if (feature == orgf) {
|
||||
Vector2D diff = orgf->pos - old_orgf;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
quad_corners[i]->pos = quad_corners[i]->pos + diff;
|
||||
}
|
||||
}
|
||||
Vector2D q1 = ToScriptCoords(quad_corners[0]->pos);
|
||||
Vector2D q2 = ToScriptCoords(quad_corners[1]->pos);
|
||||
Vector2D q3 = ToScriptCoords(quad_corners[2]->pos);
|
||||
Vector2D q4 = ToScriptCoords(quad_corners[3]->pos);
|
||||
|
||||
Vector2D diag1 = q3 - q1;
|
||||
Vector2D diag2 = q2 - q4;
|
||||
Vector2D b = q4 - q1;
|
||||
float center_la1, center_la2;
|
||||
Solve2x2(diag1.X(), diag2.X(), diag1.Y(), diag2.Y(), b.X(), b.Y(), center_la1, center_la2);
|
||||
if (center_la1 < 0 || center_la1 > 1 || -center_la2 < 0 || -center_la2 > 1) {
|
||||
ResetFeaturePositions();
|
||||
return;
|
||||
}
|
||||
Vector2D center = q1 + center_la1 * diag1;
|
||||
|
||||
// Normalize to center
|
||||
q1 = q1 - center;
|
||||
q2 = q2 - center;
|
||||
q3 = q3 - center;
|
||||
q4 = q4 - center;
|
||||
|
||||
// Find a parallelogram projecting to the quad
|
||||
float z2, z4;
|
||||
Vector2D side1 = q2 - q3;
|
||||
Vector2D side2 = q4 - q3;
|
||||
Solve2x2(side1.X(), side2.X(), side1.Y(), side2.Y(), -diag1.X(), -diag1.Y(), z2, z4);
|
||||
|
||||
float scalefactor = (z2 + z4) / 2;
|
||||
Vector3D r1 = Vector3D(q1, screen_z) / scalefactor;
|
||||
Vector3D r2 = z2 * Vector3D(q2, screen_z) / scalefactor;
|
||||
Vector3D r4 = z4 * Vector3D(q4, screen_z) / scalefactor;
|
||||
|
||||
// Find the rotations
|
||||
Vector3D n = (r2 - r1).Cross(r4 - r1);
|
||||
float roty = atan(n.X() / n.Z());
|
||||
n = n.RotateY(roty);
|
||||
float rotx = atan(n.Y() / n.Z());
|
||||
|
||||
Vector3D ab = (r2 - r1).RotateY(roty).RotateX(rotx);
|
||||
float rotz = atan(ab.Y() / ab.X());
|
||||
|
||||
Vector3D ad = (r4 - r1).RotateY(roty).RotateX(rotx).RotateZ(-rotz);
|
||||
float fax = ad.X() / ad.Y();
|
||||
|
||||
float scalex = ab.Len() / textwidth;
|
||||
float scaley = ad.Y() / textheight;
|
||||
|
||||
for (auto line : c->selectionController->GetSelectedSet()) {
|
||||
angle_x = rotx * rad2deg;
|
||||
angle_y = -roty * rad2deg;
|
||||
angle_z = -rotz * rad2deg;
|
||||
orgf->pos = FromScriptCoords(center);
|
||||
SetOverride(line, "\\fax", agi::format("%.6f", fax * scaley / scalex));
|
||||
SetOverride(line, "\\fay", agi::format("%.4f", 0)); // TODO just kill the tag
|
||||
SetOverride(line, "\\fscx", agi::format("%.2f", 100 * scalex));
|
||||
SetOverride(line, "\\fscy", agi::format("%.2f", 100 * scaley));
|
||||
SetOverride(line, "\\frz", agi::format("%.4f", angle_z));
|
||||
SetOverride(line, "\\frx", agi::format("%.4f", angle_x));
|
||||
SetOverride(line, "\\fry", agi::format("%.4f", angle_y));
|
||||
SetOverride(line, "\\pos", (center - Vector2D(fax_shift_factor * fax * scaley, 0)).PStr());
|
||||
SetOverride(line, "\\org", center.PStr());
|
||||
}
|
||||
SaveFeaturePositions();
|
||||
}
|
||||
|
||||
void VisualToolPerspective::ResetFeaturePositions() {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
quad_corners[i]->pos = old_positions[i];
|
||||
}
|
||||
orgf->pos = old_orgf;
|
||||
}
|
||||
|
||||
void VisualToolPerspective::SaveFeaturePositions() {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
old_positions[i] = quad_corners[i]->pos;
|
||||
}
|
||||
old_orgf = orgf->pos;
|
||||
}
|
||||
|
||||
void VisualToolPerspective::SetFeaturePositions() {
|
||||
double textleft, texttop = 0.;
|
||||
|
||||
switch ((align - 1) % 3) {
|
||||
case 1:
|
||||
textleft = -textwidth / 2;
|
||||
break;
|
||||
case 2:
|
||||
textleft = -textwidth;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
switch ((align - 1) / 3) {
|
||||
case 0:
|
||||
texttop = -textheight;
|
||||
break;
|
||||
case 1:
|
||||
texttop = -textheight / 2;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
Vector2D textrect[] = {
|
||||
Vector2D(0, 0),
|
||||
Vector2D(textwidth, 0),
|
||||
Vector2D(textwidth, textheight),
|
||||
Vector2D(0, textheight),
|
||||
};
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
Vector2D p = textrect[i];
|
||||
// Apply \fax and \fay
|
||||
p = Vector2D(p.X() + p.Y() * fax, p.X() * fay + p.Y());
|
||||
// Translate to alignment point
|
||||
p = p + Vector2D(textleft, texttop);
|
||||
// Apply scaling
|
||||
p = Vector2D(p.X() * fsc.X() / 100., p.Y() * fsc.Y() / 100.);
|
||||
// Translate relative to origin
|
||||
p = p + pos - org;
|
||||
// Rotate ZXY
|
||||
Vector3D q(p);
|
||||
q = q.RotateZ(-angle_z * deg2rad);
|
||||
q = q.RotateX(-angle_x * deg2rad);
|
||||
q = q.RotateY(angle_y * deg2rad);
|
||||
// Project
|
||||
q = (screen_z / (q.Z() + screen_z)) * q;
|
||||
// Move to origin
|
||||
Vector2D r = q.XY() + org;
|
||||
|
||||
quad_corners[i]->pos = FromScriptCoords(r);
|
||||
}
|
||||
|
||||
if (!(orgf->pos = org))
|
||||
orgf->pos = pos;
|
||||
orgf->pos = FromScriptCoords(orgf->pos);
|
||||
SaveFeaturePositions();
|
||||
}
|
||||
|
||||
void VisualToolPerspective::DoRefresh() {
|
||||
if (!active_line) return;
|
||||
|
||||
org = GetLineOrigin(active_line);
|
||||
pos = GetLinePosition(active_line);
|
||||
if (!org)
|
||||
org = pos;
|
||||
|
||||
GetLineRotation(active_line, angle_x, angle_y, angle_z);
|
||||
GetLineShear(active_line, fax, fay);
|
||||
GetLineScale(active_line, fsc);
|
||||
|
||||
float fs = GetLineFontSize(active_line);
|
||||
align = GetLineAlignment(active_line);
|
||||
|
||||
switch (align) {
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
fax_shift_factor = fs;
|
||||
break;
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
fax_shift_factor = fs / 2;
|
||||
break;
|
||||
default:
|
||||
fax_shift_factor = 0.;
|
||||
break;
|
||||
}
|
||||
|
||||
double descend, extlead;
|
||||
GetLineBaseExtents(active_line, textwidth, textheight, descend, extlead);
|
||||
SetFeaturePositions();
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
// Copyright (c) 2022, arch1t3cht <arch1t3cht@gmail.com>
|
||||
//
|
||||
// Permission to use, copy, modify, and distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
//
|
||||
// Aegisub Project http://www.aegisub.org/
|
||||
|
||||
/// @file visual_tool_perspective.h
|
||||
/// @see visual_tool_perspective.cpp
|
||||
/// @ingroup visual_ts
|
||||
///
|
||||
|
||||
#include "visual_feature.h"
|
||||
#include "visual_tool.h"
|
||||
|
||||
class VisualToolPerspective final : public VisualTool<VisualDraggableFeature> {
|
||||
float angle_x = 0.f; /// Current x rotation
|
||||
float angle_y = 0.f; /// Current y rotation
|
||||
float angle_z = 0.f; /// Current z rotation
|
||||
|
||||
float fax = 0.f;
|
||||
float fay = 0.f;
|
||||
|
||||
int align = 0;
|
||||
float fax_shift_factor = 0.f;
|
||||
|
||||
double textwidth = 0.f;
|
||||
double textheight = 0.f;
|
||||
|
||||
Vector2D fsc;
|
||||
|
||||
Vector2D org;
|
||||
Vector2D pos;
|
||||
|
||||
Feature *orgf;
|
||||
Vector2D old_orgf;
|
||||
|
||||
std::vector<Vector2D> old_positions;
|
||||
std::vector<Feature *> quad_corners;
|
||||
|
||||
void Solve2x2Proper(float a11, float a12, float a21, float a22, float b1, float b2, float &x1, float &x2);
|
||||
void Solve2x2(float a11, float a12, float a21, float a22, float b1, float b2, float &x1, float &x2);
|
||||
|
||||
void DoRefresh() override;
|
||||
void Draw() override;
|
||||
void UpdateDrag(Feature *feature) override;
|
||||
void SetFeaturePositions();
|
||||
void ResetFeaturePositions();
|
||||
void SaveFeaturePositions();
|
||||
public:
|
||||
VisualToolPerspective(VideoDisplay *parent, agi::Context *context);
|
||||
};
|
Loading…
Reference in New Issue