Merge branch 'vector_clip_actions' into feature

This commit is contained in:
arch1t3cht 2023-01-26 23:34:27 +01:00
commit 57572e5686
62 changed files with 1739 additions and 49 deletions

View file

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
version="1.0"
width="64"
height="64"
id="svg2385"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs2387" />
<path
d="M 21.534604,6.1472094 51.814439,14.337199 58.897111,53.851308 5.1215609,57.175696 Z"
id="rect2387"
style="display:inline;fill:none;stroke:#80b3ff;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" />
<path
d="m 26.619476,19.563308 17.90644,3.127764 1.752386,21.835103 -25.106058,0.109689 z"
id="rect2387-8"
style="display:inline;fill:#ff0000;stroke:#803300;stroke-width:2.32035;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none" />
</svg>

After

Width:  |  Height:  |  Size: 836 B

View file

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
version="1.0"
width="64"
height="64"
id="svg2385"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs2387" />
<path
d="M 32,4 V 60 M 48,4 V 60 M 16,4 v 56"
id="rect2387"
style="display:inline;fill:none;stroke:#803300;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
<path
d="M 60,32 H 4 M 60,48 H 4 M 60,16 H 4"
id="rect2387-5"
style="display:inline;fill:none;stroke:#803300;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
</svg>

After

Width:  |  Height:  |  Size: 791 B

View file

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
version="1.0"
width="64"
height="64"
id="svg2385"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs2387" />
<path
d="M 21.534604,6.1472094 51.814439,14.337199 58.897111,53.851308 5.1215609,57.175696 Z"
id="rect2387"
style="display:inline;fill:none;stroke:#ff0000;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:6, 9;stroke-dashoffset:0;stroke-opacity:1" />
<g
id="g4605"
transform="matrix(1.2858376,0,0,1.2858376,-8.5433316,-7.7280751)">
<path
d="M 41.542973,29.070062 V 43.827625 L 25.457027,43.82747 V 29.070062 Z"
id="rect2387-8"
style="display:inline;fill:#80b3ff;fill-opacity:1;stroke:#002060;stroke-width:2.2344;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" />
<path
d="m 28.77085,28.13212 c 0,-5.027712 1.267775,-8.633444 5.083463,-8.633444 3.815688,0 4.57289,3.490135 4.57289,8.763711"
style="display:inline;fill:none;fill-opacity:1;stroke:#002060;stroke-width:3.11081;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
id="path2399" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View file

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
version="1.0"
width="64"
height="64"
id="svg2385"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs2387" />
<path
d="M 21.534604,6.1472094 51.814439,14.337199 58.897111,53.851308 5.1215609,57.175696 Z"
id="rect2387"
style="display:inline;fill:none;stroke:#ff0000;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:6, 9;stroke-dashoffset:0;stroke-opacity:1" />
<path
d="M 30.272664,27.88368 H 42.773336 L 36.523,40.384351 v 0 z"
id="rect3294"
style="fill:#ff0000;stroke:#803300;stroke-width:2.50013;stroke-linecap:round;stroke-linejoin:round" />
</svg>

After

Width:  |  Height:  |  Size: 794 B

View file

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
version="1.0"
width="64"
height="64"
id="svg2385"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs2387" />
<path
d="M 21.534604,6.1472094 51.814439,14.337199 58.897111,53.851308 5.1215609,57.175696 Z"
id="rect2387"
style="display:inline;fill:none;stroke:#ff0000;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:6, 9;stroke-dashoffset:0;stroke-opacity:1" />
<path
d="m 37.858975,14.096991 h 12.50005 L 44.109,26.59704 v 0 z"
id="rect3294"
style="fill:#ff0000;stroke:#803300;stroke-width:2.50001;stroke-linecap:round;stroke-linejoin:round" />
</svg>

After

Width:  |  Height:  |  Size: 793 B

View file

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
version="1.0"
width="64"
height="64"
id="svg2385"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs2387" />
<path
d="M 8,8 H 56 V 56 H 8 Z"
id="rect2391"
style="fill:none;stroke:#ff0000;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:6, 9;stroke-dashoffset:0;stroke-opacity:1" />
<path
d="m 37.858519,14.096401 h 12.500872 l -6.250436,12.500871 v 0 z"
id="rect3294"
style="fill:#ff0000;stroke:#803300;stroke-width:2.50017;stroke-linecap:round;stroke-linejoin:round" />
</svg>

After

Width:  |  Height:  |  Size: 721 B

View file

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
version="1.0"
width="64"
height="64"
id="svg2385"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs2387" />
<path
d="M 21.534604,6.1472094 51.814439,14.337199 58.897111,53.851308 5.1215609,57.175696 Z"
id="rect2387"
style="display:inline;fill:none;stroke:#ff0000;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:6, 9;stroke-dashoffset:0;stroke-opacity:1" />
<path
d="m 26.619476,19.563308 17.90644,3.127764 1.752386,21.835103 -25.106058,0.109689 z"
id="rect2387-8"
style="display:inline;fill:#80b3ff;fill-opacity:1;stroke:#002060;stroke-width:2.32035;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" />
</svg>

After

Width:  |  Height:  |  Size: 888 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 629 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 947 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 226 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 265 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 257 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 391 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 467 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 543 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 755 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 987 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 456 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 634 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 824 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 430 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 629 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 820 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 393 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 556 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 558 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 860 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 822 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 554 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 824 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

View file

@ -541,6 +541,41 @@ button/visual_move_conv_pos_24.png
button/visual_move_conv_pos_32.png
button/visual_move_conv_pos_48.png
button/visual_move_conv_pos_64.png
button/visual_perspective_16.png
button/visual_perspective_24.png
button/visual_perspective_32.png
button/visual_perspective_48.png
button/visual_perspective_64.png
button/visual_perspective_grid_16.png
button/visual_perspective_grid_24.png
button/visual_perspective_grid_32.png
button/visual_perspective_grid_48.png
button/visual_perspective_grid_64.png
button/visual_perspective_lock_outer_16.png
button/visual_perspective_lock_outer_24.png
button/visual_perspective_lock_outer_32.png
button/visual_perspective_lock_outer_48.png
button/visual_perspective_lock_outer_64.png
button/visual_perspective_orgmode_center_16.png
button/visual_perspective_orgmode_center_24.png
button/visual_perspective_orgmode_center_32.png
button/visual_perspective_orgmode_center_48.png
button/visual_perspective_orgmode_center_64.png
button/visual_perspective_orgmode_keep_16.png
button/visual_perspective_orgmode_keep_24.png
button/visual_perspective_orgmode_keep_32.png
button/visual_perspective_orgmode_keep_48.png
button/visual_perspective_orgmode_keep_64.png
button/visual_perspective_orgmode_nofax_16.png
button/visual_perspective_orgmode_nofax_24.png
button/visual_perspective_orgmode_nofax_32.png
button/visual_perspective_orgmode_nofax_48.png
button/visual_perspective_orgmode_nofax_64.png
button/visual_perspective_plane_16.png
button/visual_perspective_plane_24.png
button/visual_perspective_plane_32.png
button/visual_perspective_plane_48.png
button/visual_perspective_plane_64.png
button/visual_rotatexy_16.png
button/visual_rotatexy_24.png
button/visual_rotatexy_32.png

View file

@ -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"
@ -59,12 +60,39 @@ namespace {
}
bool IsActive(const agi::Context *c) override {
return c->videoDisplay->ToolIsVectorClipTool(M);
return c->videoDisplay->ToolIsType(typeid(VisualToolVectorClip)) && c->videoDisplay->GetSubTool() == M;
}
void operator()(agi::Context *c) override {
c->videoDisplay->SetTool(agi::make_unique<VisualToolVectorClip>(c->videoDisplay, c));
c->videoDisplay->SetVectorClipTool(M);
c->videoDisplay->SetSubTool(M);
}
};
template<VisualToolPerspectiveSetting M>
struct visual_tool_persp_setting : public Command {
CMD_TYPE(COMMAND_VALIDATE | COMMAND_TOGGLE)
bool Validate(const agi::Context *c) override {
return c->videoDisplay->ToolIsType(typeid(VisualToolPerspective));
}
virtual const bool CheckActive(int subtool) {
return subtool & M;
}
virtual const int UpdateSubTool(int subtool) {
return subtool ^ M;
}
bool IsActive(const agi::Context *c) override {
return Validate(c) && CheckActive(c->videoDisplay->GetSubTool());
}
void operator()(agi::Context *c) override {
if (!c->videoDisplay->ToolIsType(typeid(VisualToolPerspective)))
c->videoDisplay->SetTool(agi::make_unique<VisualToolPerspective>(c->videoDisplay, c));
c->videoDisplay->SetSubTool(UpdateSubTool(c->videoDisplay->GetSubTool()));
}
};
@ -100,6 +128,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_perspective)
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)
@ -124,6 +160,113 @@ namespace {
STR_HELP("Clip subtitles to a vectorial area")
};
// Perspective settings
struct visual_mode_perspective_plane final : public visual_tool_persp_setting<PERSP_OUTER> {
CMD_NAME("video/tool/perspective/plane")
CMD_ICON(visual_perspective_plane)
STR_MENU("Show Surrounding Plane")
STR_DISP("Show Surrounding Plane")
STR_HELP("Toggles showing a second quad for the ambient 3D plane.")
};
// Perspective settings
struct visual_mode_perspective_lock_inner final : public visual_tool_persp_setting<PERSP_LOCK_OUTER> {
CMD_NAME("video/tool/perspective/lock_outer")
CMD_ICON(visual_perspective_lock_outer)
STR_MENU("Lock Outer Quad")
STR_DISP("Lock Outer Quad")
STR_HELP("When the surrounding plane is also visible, switches which quad is locked. If inactive, the inner quad can only be resized without changing the perspective plane. If active, this holds for the outer quad instead.")
bool Validate(const agi::Context *c) override {
return c->videoDisplay->ToolIsType(typeid(VisualToolPerspective)) && c->videoDisplay->GetSubTool() | PERSP_OUTER;
}
};
struct visual_mode_perspective_grid final : public visual_tool_persp_setting<PERSP_GRID> {
CMD_NAME("video/tool/perspective/grid")
CMD_ICON(visual_perspective_grid)
STR_MENU("Show Grid")
STR_DISP("Show Grid")
STR_HELP("Toggles showing a 3D grid in the visual perspective tool")
};
struct visual_mode_perspective_orgmode_center : public visual_tool_persp_setting<PERSP_ORGMODE_CENTER> {
CMD_NAME("video/tool/perspective/orgmode/center")
CMD_ICON(visual_perspective_orgmode_center)
STR_MENU("\\org Mode: Center")
STR_DISP("\\org Mode: Center")
STR_HELP("Puts \\org at the center of the perspective quad")
const bool CheckActive(int subtool) override {
return (subtool & PERSP_ORGMODE) == PERSP_ORGMODE_CENTER;
}
const int UpdateSubTool(int subtool) override {
return (subtool & ~PERSP_ORGMODE) | PERSP_ORGMODE_CENTER;
}
};
struct visual_mode_perspective_orgmode_nofax : public visual_tool_persp_setting<PERSP_ORGMODE_NOFAX> {
CMD_NAME("video/tool/perspective/orgmode/nofax")
CMD_ICON(visual_perspective_orgmode_nofax)
STR_MENU("\\org Mode: No \\fax")
STR_DISP("\\org Mode: No \\fax")
STR_HELP("Finds a value for \\org where \\fax can be zero, if possible. Use this mode if your event contains line breaks.")
const bool CheckActive(int subtool) override {
return (subtool & PERSP_ORGMODE) == PERSP_ORGMODE_NOFAX;
}
const int UpdateSubTool(int subtool) override {
return (subtool & ~PERSP_ORGMODE) | PERSP_ORGMODE_NOFAX;
}
};
struct visual_mode_perspective_orgmode_keep : public visual_tool_persp_setting<PERSP_ORGMODE_KEEP> {
CMD_NAME("video/tool/perspective/orgmode/keep")
CMD_ICON(visual_perspective_orgmode_keep)
STR_MENU("\\org Mode: Keep")
STR_DISP("\\org Mode: Keep")
STR_HELP("Fixes the position of \\org")
const bool CheckActive(int subtool) override {
return (subtool & PERSP_ORGMODE) == PERSP_ORGMODE_KEEP;
}
const int UpdateSubTool(int subtool) override {
return (subtool & ~PERSP_ORGMODE) | PERSP_ORGMODE_KEEP;
}
};
struct visual_mode_perspective_orgmode_cycle : public visual_tool_persp_setting<PERSP_ORGMODE> {
CMD_NAME("video/tool/perspective/orgmode/cycle")
STR_MENU("Cycle \\org mode")
STR_DISP("Cycle \\org mode")
STR_HELP("Cycles through the three \\org modes")
const bool CheckActive(int subtool) override {
return false;
}
const int UpdateSubTool(int subtool) override {
int newtool = 0;
switch (subtool & PERSP_ORGMODE) {
case PERSP_ORGMODE_CENTER:
newtool = PERSP_ORGMODE_NOFAX;
break;
case PERSP_ORGMODE_NOFAX:
newtool = PERSP_ORGMODE_KEEP;
break;
case PERSP_ORGMODE_KEEP:
newtool = PERSP_ORGMODE_CENTER;
break;
default:
break;
}
return (subtool & ~PERSP_ORGMODE) | newtool;
}
};
// Vector clip tools
struct visual_mode_vclip_drag final : public visual_tool_vclip_command<VCLIP_DRAG> {
@ -191,10 +334,19 @@ 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>());
reg(agi::make_unique<visual_mode_perspective_plane>());
reg(agi::make_unique<visual_mode_perspective_lock_inner>());
reg(agi::make_unique<visual_mode_perspective_grid>());
reg(agi::make_unique<visual_mode_perspective_orgmode_center>());
reg(agi::make_unique<visual_mode_perspective_orgmode_nofax>());
reg(agi::make_unique<visual_mode_perspective_orgmode_keep>());
reg(agi::make_unique<visual_mode_perspective_orgmode_cycle>());
reg(agi::make_unique<visual_mode_vclip_drag>());
reg(agi::make_unique<visual_mode_vclip_line>());
reg(agi::make_unique<visual_mode_vclip_bicubic>());

View file

@ -602,6 +602,12 @@
"Skip Whitespace" : true
},
"Visual" : {
"Perspective": {
"Outer": false,
"Outer Locked": false,
"Grid": false,
"Org Mode": 0
},
"Autohide": false
},
"Align to Video" : {

View file

@ -344,7 +344,7 @@
"Alt-Left"
],
"video/tool/clip" : [
"H"
"J"
],
"video/tool/cross" : [
"A"
@ -352,6 +352,9 @@
"video/tool/drag" : [
"S"
],
"video/tool/perspective": [
"G"
],
"video/tool/rotate/xy" : [
"F"
],
@ -359,10 +362,10 @@
"D"
],
"video/tool/scale" : [
"G"
"H"
],
"video/tool/vector_clip" : [
"J"
"K"
]
}
}

View file

@ -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",

View file

@ -602,6 +602,12 @@
"Skip Whitespace" : true
},
"Visual" : {
"Perspective": {
"Outer": false,
"Outer Locked": false,
"Grid": false,
"Org Mode": 0
},
"Autohide": false
},
"Align to Video" : {

View file

@ -351,7 +351,7 @@
"Alt-Left"
],
"video/tool/clip" : [
"H"
"J"
],
"video/tool/cross" : [
"A"
@ -359,6 +359,9 @@
"video/tool/drag" : [
"S"
],
"video/tool/perspective": [
"G"
],
"video/tool/rotate/xy" : [
"F"
],
@ -366,10 +369,10 @@
"D"
],
"video/tool/scale" : [
"G"
"H"
],
"video/tool/vector_clip" : [
"J"
"K"
]
}
}

View file

@ -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',

99
src/vector3d.cpp Normal file
View file

@ -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);
}

83
src/vector3d.h Normal file
View file

@ -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);

View file

@ -519,23 +519,10 @@ void VideoDisplay::SetTool(std::unique_ptr<VisualToolBase> new_tool) {
}
}
bool VideoDisplay::SetVectorClipTool(VisualToolVectorClipMode vcliptoolmode) const {
if (ToolIsType(typeid(VisualToolVectorClip))) {
static_cast<VisualToolVectorClip*>(tool.get())->SetMode(vcliptoolmode);
return true;
} else {
return false;
}
}
bool VideoDisplay::ToolIsType(std::type_info const& type) const {
return tool && typeid(*tool) == type;
}
bool VideoDisplay::ToolIsVectorClipTool(VisualToolVectorClipMode vcliptoolmode) const {
return ToolIsType(typeid(VisualToolVectorClip)) && static_cast<VisualToolVectorClip*>(tool.get());
}
Vector2D VideoDisplay::GetMousePosition() const {
return last_mouse_pos ? tool->ToScriptCoords(last_mouse_pos) : last_mouse_pos;
}

View file

@ -181,13 +181,11 @@ public:
void SetTool(std::unique_ptr<VisualToolBase> new_tool);
/// Will only set the vector clip mode if the vector clip tool is active already,
/// otherwise it just returns false.
bool SetVectorClipTool(VisualToolVectorClipMode vcliptoolmode) const;
void SetSubTool(int subtool) const { tool->SetSubTool(subtool); };
bool ToolIsType(std::type_info const& type) const;
bool ToolIsVectorClipTool(VisualToolVectorClipMode vcliptoolmode) const;
int GetSubTool() const { return tool->GetSubTool(); };
/// Discard all OpenGL state
void Unload();

View file

@ -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"
@ -31,11 +32,15 @@
#include "video_display.h"
#include "visual_tool_clip.h"
#include "visual_tool_drag.h"
#include "visual_tool_perspective.h"
#include "visual_tool_vector_clip.h"
#include <libaegisub/ass/time.h>
#include <libaegisub/format.h>
#include <libaegisub/of_type_adaptor.h>
#include <libaegisub/split.h>
#include <boost/algorithm/string/replace.hpp>
#include <algorithm>
@ -212,6 +217,9 @@ void VisualTool<FeatureType>::OnMouseEvent(wxMouseEvent &event) {
else
SetSelection(active_feature, true);
}
} else {
for (auto sel : sel_features)
EndDrag(sel);
}
active_feature = nullptr;
@ -222,6 +230,7 @@ void VisualTool<FeatureType>::OnMouseEvent(wxMouseEvent &event) {
else if (holding) {
if (!event.LeftIsDown()) {
holding = false;
EndHold();
parent->ReleaseMouse();
parent->SetFocus();
@ -475,6 +484,98 @@ void VisualToolBase::GetLineScale(AssDialogue *diag, Vector2D &scale) {
scale = Vector2D(x, y);
}
void VisualToolBase::GetLineOutline(AssDialogue *diag, Vector2D &outline) {
float x = 0.f, y = 0.f;
if (AssStyle *style = c->ass->GetStyle(diag->Style)) {
x = style->outline_w;
y = style->outline_w;
}
auto blocks = diag->ParseTags();
if (param_vec tag = find_tag(blocks, "\\bord")) {
x = tag->front().Get(x);
y = tag->front().Get(y);
}
if (param_vec tag = find_tag(blocks, "\\xbord"))
x = tag->front().Get(x);
if (param_vec tag = find_tag(blocks, "\\ybord"))
y = tag->front().Get(y);
outline = Vector2D(x, y);
}
void VisualToolBase::GetLineShadow(AssDialogue *diag, Vector2D &shadow) {
float x = 0.f, y = 0.f;
if (AssStyle *style = c->ass->GetStyle(diag->Style)) {
x = style->shadow_w;
y = style->shadow_w;
}
auto blocks = diag->ParseTags();
if (param_vec tag = find_tag(blocks, "\\shad")) {
x = tag->front().Get(x);
y = tag->front().Get(y);
}
if (param_vec tag = find_tag(blocks, "\\xshad"))
x = tag->front().Get(x);
if (param_vec tag = find_tag(blocks, "\\yshad"))
y = tag->front().Get(y);
shadow = Vector2D(x, y);
}
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();
std::vector<std::string> textlines;
boost::replace_all(text, "\\N", "\n");
agi::Split(textlines, text, '\n');
for (std::string line : textlines) {
double linewidth = 0;
double lineheight = 0;
if (!Automation4::CalculateTextExtents(&style, line, linewidth, lineheight, descent, extlead)) {
// meh... let's make some ballpark estimates
linewidth = style.fontsize * line.length();
lineheight = style.fontsize;
}
width = std::max(width, linewidth);
height += lineheight;
}
}
void VisualToolBase::GetLineClip(AssDialogue *diag, Vector2D &p1, Vector2D &p2, bool &inverse) {
inverse = false;
@ -527,16 +628,35 @@ void VisualToolBase::SetSelectedOverride(std::string const& tag, std::string con
SetOverride(line, tag, value);
}
void VisualToolBase::RemoveOverride(AssDialogue *line, std::string const& tag) {
if (!line) return;
auto blocks = line->ParseTags();
for (auto ovr : blocks | agi::of_type<AssDialogueBlockOverride>()) {
for (size_t i = 0; i < ovr->Tags.size(); i++) {
if (tag == ovr->Tags[i].Name) {
ovr->Tags.erase(ovr->Tags.begin() + i);
i--;
}
}
}
line->UpdateText(blocks);
}
void VisualToolBase::SetOverride(AssDialogue* line, std::string const& tag, std::string const& value) {
if (!line) return;
std::string removeTag;
std::string removeTag2;
if (tag == "\\1c") removeTag = "\\c";
else if (tag == "\\frz") removeTag = "\\fr";
else if (tag == "\\pos") removeTag = "\\move";
else if (tag == "\\move") removeTag = "\\pos";
else if (tag == "\\clip") removeTag = "\\iclip";
else if (tag == "\\iclip") removeTag = "\\clip";
else if (tag == "\\xbord" || tag == "\\ybord") removeTag = "\\bord";
else if (tag == "\\xshad" || tag == "\\yshad") removeTag = "\\shad";
else if (tag == "\\bord") { removeTag = "\\xbord"; removeTag2 = "\\ybord"; }
else if (tag == "\\shad") { removeTag = "\\xshad"; removeTag2 = "\\yshad"; }
// Get block at start
auto blocks = line->ParseTags();
@ -547,7 +667,7 @@ void VisualToolBase::SetOverride(AssDialogue* line, std::string const& tag, std:
// Remove old of same
for (size_t i = 0; i < ovr->Tags.size(); i++) {
std::string const& name = ovr->Tags[i].Name;
if (tag == name || removeTag == name) {
if (tag == name || removeTag == name || removeTag2 == name) {
ovr->Tags.erase(ovr->Tags.begin() + i);
i--;
}
@ -564,4 +684,5 @@ void VisualToolBase::SetOverride(AssDialogue* line, std::string const& tag, std:
template class VisualTool<VisualDraggableFeature>;
template class VisualTool<ClipCorner>;
template class VisualTool<VisualToolDragDraggableFeature>;
template class VisualTool<VisualToolPerspectiveDraggableFeature>;
template class VisualTool<VisualToolVectorClipDraggableFeature>;

View file

@ -128,9 +128,20 @@ 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);
void GetLineOutline(AssDialogue *diag, Vector2D &outline);
void GetLineShadow(AssDialogue *diag, Vector2D &shadow);
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);
void RemoveOverride(AssDialogue *line, std::string const& tag);
void SetOverride(AssDialogue* line, std::string const& tag, std::string const& value);
void SetSelectedOverride(std::string const& tag, std::string const& value);
@ -148,6 +159,8 @@ public:
virtual void SetClientSize(int w, int h);
virtual void SetDisplayArea(int x, int y, int w, int h);
virtual void SetToolbar(wxToolBar *) { }
virtual void SetSubTool(int subtool) { }
virtual int GetSubTool() { return 0; }
virtual ~VisualToolBase() = default;
};
@ -166,6 +179,8 @@ private:
virtual bool InitializeHold() { return false; }
/// @brief Called on every mouse event during a hold
virtual void UpdateHold() { }
/// @brief Called when the hold ended
virtual void EndHold() { }
/// @brief Called at the beginning of a drag
/// @param feature The visual feature clicked on
@ -174,6 +189,9 @@ private:
/// @brief Called on every mouse event during a drag
/// @param feature The current feature to process; not necessarily the one clicked on
virtual void UpdateDrag(FeatureType *feature) { }
/// @brief Called at the end of a drag
/// @param feature The current feature to process; not necessarily the one clicked on
virtual void EndDrag(FeatureType *feature)