visual tools: Add perspective tool
21
docs/art-sources/buttons/visual_perspective.svg
Normal 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 |
21
docs/art-sources/buttons/visual_perspective_grid.svg
Normal 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 |
29
docs/art-sources/buttons/visual_perspective_lock_outer.svg
Normal 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 |
|
@ -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 |
21
docs/art-sources/buttons/visual_perspective_orgmode_keep.svg
Normal 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 |
|
@ -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 |
21
docs/art-sources/buttons/visual_perspective_plane.svg
Normal 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 |
BIN
src/bitmaps/button/visual_perspective_16.png
Normal file
After Width: | Height: | Size: 629 B |
BIN
src/bitmaps/button/visual_perspective_24.png
Normal file
After Width: | Height: | Size: 947 B |
BIN
src/bitmaps/button/visual_perspective_32.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
src/bitmaps/button/visual_perspective_48.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
src/bitmaps/button/visual_perspective_64.png
Normal file
After Width: | Height: | Size: 2.4 KiB |
BIN
src/bitmaps/button/visual_perspective_grid_16.png
Normal file
After Width: | Height: | Size: 226 B |
BIN
src/bitmaps/button/visual_perspective_grid_24.png
Normal file
After Width: | Height: | Size: 265 B |
BIN
src/bitmaps/button/visual_perspective_grid_32.png
Normal file
After Width: | Height: | Size: 257 B |
BIN
src/bitmaps/button/visual_perspective_grid_48.png
Normal file
After Width: | Height: | Size: 391 B |
BIN
src/bitmaps/button/visual_perspective_grid_64.png
Normal file
After Width: | Height: | Size: 467 B |
BIN
src/bitmaps/button/visual_perspective_lock_outer_16.png
Normal file
After Width: | Height: | Size: 543 B |
BIN
src/bitmaps/button/visual_perspective_lock_outer_24.png
Normal file
After Width: | Height: | Size: 755 B |
BIN
src/bitmaps/button/visual_perspective_lock_outer_32.png
Normal file
After Width: | Height: | Size: 987 B |
BIN
src/bitmaps/button/visual_perspective_lock_outer_48.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
src/bitmaps/button/visual_perspective_lock_outer_64.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
src/bitmaps/button/visual_perspective_orgmode_center_16.png
Normal file
After Width: | Height: | Size: 456 B |
BIN
src/bitmaps/button/visual_perspective_orgmode_center_24.png
Normal file
After Width: | Height: | Size: 634 B |
BIN
src/bitmaps/button/visual_perspective_orgmode_center_32.png
Normal file
After Width: | Height: | Size: 824 B |
BIN
src/bitmaps/button/visual_perspective_orgmode_center_48.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
src/bitmaps/button/visual_perspective_orgmode_center_64.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
src/bitmaps/button/visual_perspective_orgmode_keep_16.png
Normal file
After Width: | Height: | Size: 430 B |
BIN
src/bitmaps/button/visual_perspective_orgmode_keep_24.png
Normal file
After Width: | Height: | Size: 629 B |
BIN
src/bitmaps/button/visual_perspective_orgmode_keep_32.png
Normal file
After Width: | Height: | Size: 820 B |
BIN
src/bitmaps/button/visual_perspective_orgmode_keep_48.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
src/bitmaps/button/visual_perspective_orgmode_keep_64.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
src/bitmaps/button/visual_perspective_orgmode_nofax_16.png
Normal file
After Width: | Height: | Size: 393 B |
BIN
src/bitmaps/button/visual_perspective_orgmode_nofax_24.png
Normal file
After Width: | Height: | Size: 556 B |
BIN
src/bitmaps/button/visual_perspective_orgmode_nofax_32.png
Normal file
After Width: | Height: | Size: 558 B |
BIN
src/bitmaps/button/visual_perspective_orgmode_nofax_48.png
Normal file
After Width: | Height: | Size: 860 B |
BIN
src/bitmaps/button/visual_perspective_orgmode_nofax_64.png
Normal file
After Width: | Height: | Size: 822 B |
BIN
src/bitmaps/button/visual_perspective_plane_16.png
Normal file
After Width: | Height: | Size: 554 B |
BIN
src/bitmaps/button/visual_perspective_plane_24.png
Normal file
After Width: | Height: | Size: 824 B |
BIN
src/bitmaps/button/visual_perspective_plane_32.png
Normal file
After Width: | Height: | Size: 1 KiB |
BIN
src/bitmaps/button/visual_perspective_plane_48.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
src/bitmaps/button/visual_perspective_plane_64.png
Normal file
After Width: | Height: | Size: 2 KiB |
|
@ -536,6 +536,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
|
||||
|
|
|
@ -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"
|
||||
|
@ -68,6 +69,33 @@ namespace {
|
|||
}
|
||||
};
|
||||
|
||||
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()));
|
||||
}
|
||||
};
|
||||
|
||||
struct visual_mode_cross final : public visual_tool_command<VisualToolCross> {
|
||||
CMD_NAME("video/tool/cross")
|
||||
CMD_ICON(visual_standard)
|
||||
|
@ -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>());
|
||||
|
|
|
@ -574,6 +574,12 @@
|
|||
"Skip Whitespace" : true
|
||||
},
|
||||
"Visual" : {
|
||||
"Perspective": {
|
||||
"Outer": false,
|
||||
"Outer Locked": false,
|
||||
"Grid": false,
|
||||
"Org Mode": 0
|
||||
},
|
||||
"Autohide": false
|
||||
}
|
||||
},
|
||||
|
|
|
@ -338,7 +338,7 @@
|
|||
"Alt-Left"
|
||||
],
|
||||
"video/tool/clip" : [
|
||||
"H"
|
||||
"J"
|
||||
],
|
||||
"video/tool/cross" : [
|
||||
"A"
|
||||
|
@ -346,6 +346,9 @@
|
|||
"video/tool/drag" : [
|
||||
"S"
|
||||
],
|
||||
"video/tool/perspective": [
|
||||
"G"
|
||||
],
|
||||
"video/tool/rotate/xy" : [
|
||||
"F"
|
||||
],
|
||||
|
@ -353,10 +356,10 @@
|
|||
"D"
|
||||
],
|
||||
"video/tool/scale" : [
|
||||
"G"
|
||||
"H"
|
||||
],
|
||||
"video/tool/vector_clip" : [
|
||||
"J"
|
||||
"K"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -72,6 +72,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",
|
||||
|
|
|
@ -574,6 +574,12 @@
|
|||
"Skip Whitespace" : true
|
||||
},
|
||||
"Visual" : {
|
||||
"Perspective": {
|
||||
"Outer": false,
|
||||
"Outer Locked": false,
|
||||
"Grid": false,
|
||||
"Org Mode": 0
|
||||
},
|
||||
"Autohide": false
|
||||
}
|
||||
},
|
||||
|
|
|
@ -348,7 +348,7 @@
|
|||
"Alt-Left"
|
||||
],
|
||||
"video/tool/clip" : [
|
||||
"H"
|
||||
"J"
|
||||
],
|
||||
"video/tool/cross" : [
|
||||
"A"
|
||||
|
@ -356,6 +356,9 @@
|
|||
"video/tool/drag" : [
|
||||
"S"
|
||||
],
|
||||
"video/tool/perspective": [
|
||||
"G"
|
||||
],
|
||||
"video/tool/rotate/xy" : [
|
||||
"F"
|
||||
],
|
||||
|
@ -363,10 +366,10 @@
|
|||
"D"
|
||||
],
|
||||
"video/tool/scale" : [
|
||||
"G"
|
||||
"H"
|
||||
],
|
||||
"video/tool/vector_clip" : [
|
||||
"J"
|
||||
"K"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -141,6 +141,7 @@ aegisub_src = files(
|
|||
'utils.cpp',
|
||||
'validators.cpp',
|
||||
'vector2d.cpp',
|
||||
'vector3d.cpp',
|
||||
'version.cpp',
|
||||
'video_box.cpp',
|
||||
'video_controller.cpp',
|
||||
|
@ -157,6 +158,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
|
@ -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
|
@ -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);
|
|
@ -680,4 +680,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>;
|
||||
|
|
894
src/visual_tool_perspective.cpp
Normal file
|
@ -0,0 +1,894 @@
|
|||
// 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 "command/command.h"
|
||||
#include "compat.h"
|
||||
#include "include/aegisub/context.h"
|
||||
#include "options.h"
|
||||
#include "selection_controller.h"
|
||||
#include "vector3d.h"
|
||||
#include "ass_file.h"
|
||||
#include "ass_dialogue.h"
|
||||
#include "ass_style.h"
|
||||
#include "video_display.h"
|
||||
|
||||
#include <libaegisub/format.h>
|
||||
#include <libaegisub/split.h>
|
||||
#include <libaegisub/util.h>
|
||||
|
||||
#include <cmath>
|
||||
#include <wx/colour.h>
|
||||
|
||||
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 char *ambient_plane_key = "_aegi_perspective_ambient_plane";
|
||||
|
||||
static const int BUTTON_ID_BASE = 1400;
|
||||
|
||||
enum VisualToolPerspectiveFeatureType {
|
||||
FEATURE_INNER = 0,
|
||||
FEATURE_OUTER = 1,
|
||||
FEATURE_CENTER = 2,
|
||||
FEATURE_ORG = 3,
|
||||
};
|
||||
|
||||
void Solve2x2(float a11, float a12, float a21, float a22, float b1, float b2, float &x1, float &x2) {
|
||||
// Simple pivoting
|
||||
if (abs(a11) < abs(a21)) {
|
||||
std::swap(b1, b2);
|
||||
std::swap(a11, a21);
|
||||
std::swap(a12, a22);
|
||||
}
|
||||
// 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;
|
||||
}
|
||||
|
||||
Vector2D QuadMidpoint(std::vector<Vector2D> quad) {
|
||||
Vector2D diag1 = quad[2] - quad[0];
|
||||
Vector2D diag2 = quad[1] - quad[3];
|
||||
Vector2D b = quad[3] - quad[0];
|
||||
float center_la1, center_la2;
|
||||
Solve2x2(diag1.X(), diag2.X(), diag1.Y(), diag2.Y(), b.X(), b.Y(), center_la1, center_la2);
|
||||
return quad[0] + center_la1 * diag1;
|
||||
}
|
||||
|
||||
void UnwrapQuadRel(std::vector<Vector2D> quad, float &x1, float &x2, float &x3, float &x4, float &y1, float &y2, float &y3, float &y4) {
|
||||
x1 = quad[0].X();
|
||||
x2 = quad[1].X() - x1;
|
||||
x3 = quad[2].X() - x1;
|
||||
x4 = quad[3].X() - x1;
|
||||
y1 = quad[0].Y();
|
||||
y2 = quad[1].Y() - y1;
|
||||
y3 = quad[2].Y() - y1;
|
||||
y4 = quad[3].Y() - y1;
|
||||
}
|
||||
|
||||
Vector2D XYToUV(std::vector<Vector2D> quad, Vector2D xy) {
|
||||
float x1, x2, x3, x4, y1, y2, y3, y4;
|
||||
UnwrapQuadRel(quad, x1, x2, x3, x4, y1, y2, y3, y4);
|
||||
float x = xy.X() - x1;
|
||||
float y = xy.Y() - y1;
|
||||
// Dumped from Mathematica
|
||||
float u = -(((x3*y2 - x2*y3)*(x4*y - x*y4)*(x4*(-y2 + y3) + x3*(y2 - y4) + x2*(-y3 + y4)))/(x3*x3*(x4*y2*y2*(-y + y4) + y4*(x*y2*(y2 - y4) + x2*(y - y2)*y4)) + x3*(x4*x4*y2*y2*(y - y3) + 2*x4*(x2*y*y3*(y2 - y4) + x*y2*(-y2 + y3)*y4) + x2*y4*(x2*(-y + y3)*y4 + 2*x*y2*(-y3 + y4))) + y3*(x*x4*x4*y2*(y2 - y3) + x2*x4*x4*(y2*y3 + y*(-2*y2 + y3)) - x2*x2*(x4*y*(y3 - 2*y4) + x4*y3*y4 + x*y4*(-y3 + y4)))));
|
||||
float v = ((x2*y - x*y2)*(x4*y3 - x3*y4)*(x4*(y2 - y3) + x2*(y3 - y4) + x3*(-y2 + y4)))/(x3*(x4*x4*y2*y2*(-y + y3) + x2*y4*(2*x*y2*(y3 - y4) + x2*(y - y3)*y4) - 2*x4*(x2*y*y3*(y2 - y4) + x*y2*(-y2 + y3)*y4)) + x3*x3*(x4*y2*y2*(y - y4) + y4*(x2*(-y + y2)*y4 + x*y2*(-y2 + y4))) + y3*(x*x4*x4*y2*(-y2 + y3) + x2*x4*x4*(2*y*y2 - y*y3 - y2*y3) + x2*x2*(x4*y*(y3 - 2*y4) + x4*y3*y4 + x*y4*(-y3 + y4))));
|
||||
return Vector2D(u, v);
|
||||
}
|
||||
|
||||
Vector2D UVToXY(std::vector<Vector2D> quad, Vector2D uv) {
|
||||
float x1, x2, x3, x4, y1, y2, y3, y4;
|
||||
UnwrapQuadRel(quad, x1, x2, x3, x4, y1, y2, y3, y4);
|
||||
float u = uv.X();
|
||||
float v = uv.Y();
|
||||
// Also dumped from Mathematica
|
||||
float d = (x4*((-1 + u + v)*y2 + y3 - v*y3) + x3*(y2 - u*y2 + (-1 + v)*y4) + x2*((-1 + u)*y3 - (-1 + u + v)*y4));
|
||||
float x = (v*x4*(x3*y2 - x2*y3) + u*x2*(x4*y3 - x3*y4)) / d;
|
||||
float y = (v*y4*(x3*y2 - x2*y3) + u*y2*(x4*y3 - x3*y4)) / d;
|
||||
return Vector2D(x + x1, y + y1);
|
||||
}
|
||||
|
||||
std::vector<Vector2D> MakeRect(Vector2D a, Vector2D b) {
|
||||
return std::vector<Vector2D>({
|
||||
Vector2D(a.X(), a.Y()),
|
||||
Vector2D(b.X(), a.Y()),
|
||||
Vector2D(b.X(), b.Y()),
|
||||
Vector2D(a.X(), b.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();
|
||||
toolBar->AddTool(BUTTON_ID_BASE + setting, command->StrDisplay(c), command->Icon(icon_size), command->GetTooltip("Video"), wxITEM_CHECK);
|
||||
}
|
||||
|
||||
VisualToolPerspective::VisualToolPerspective(VideoDisplay *parent, agi::Context *context)
|
||||
: VisualTool<VisualToolPerspectiveDraggableFeature>(parent, context)
|
||||
, optOuter(OPT_SET("Tool/Visual/Perspective/Outer"))
|
||||
, optOuterLocked(OPT_SET("Tool/Visual/Perspective/Outer Locked"))
|
||||
, optGrid(OPT_SET("Tool/Visual/Perspective/Grid"))
|
||||
, optOrgMode(OPT_SET("Tool/Visual/Perspective/Org Mode"))
|
||||
{
|
||||
old_outer.resize(4);
|
||||
old_inner.resize(4);
|
||||
|
||||
settings = 0;
|
||||
if (optOuter->GetBool()) settings |= PERSP_OUTER;
|
||||
if (optOuterLocked->GetBool()) settings |= PERSP_LOCK_OUTER;
|
||||
if (optGrid->GetBool()) settings |= PERSP_GRID;
|
||||
settings |= optOrgMode->GetInt();
|
||||
|
||||
MakeFeatures();
|
||||
}
|
||||
|
||||
void VisualToolPerspective::SetToolbar(wxToolBar *toolBar) {
|
||||
this->toolBar = toolBar;
|
||||
|
||||
toolBar->AddSeparator();
|
||||
|
||||
AddTool("video/tool/perspective/plane", PERSP_OUTER);
|
||||
AddTool("video/tool/perspective/lock_outer", PERSP_LOCK_OUTER);
|
||||
AddTool("video/tool/perspective/grid", PERSP_GRID);
|
||||
AddTool("video/tool/perspective/orgmode/center", PERSP_ORGMODE);
|
||||
|
||||
SetSubTool(settings);
|
||||
|
||||
toolBar->Realize();
|
||||
toolBar->Show(true);
|
||||
toolBar->Bind(wxEVT_TOOL, &VisualToolPerspective::OnSubTool, this);
|
||||
}
|
||||
|
||||
void VisualToolPerspective::OnSubTool(wxCommandEvent &e) {
|
||||
int id = e.GetId() - BUTTON_ID_BASE;
|
||||
if (id == PERSP_ORGMODE) {
|
||||
cmd::call("video/tool/perspective/orgmode/cycle", c);
|
||||
} else {
|
||||
SetSubTool(GetSubTool() ^ id);
|
||||
}
|
||||
}
|
||||
|
||||
void VisualToolPerspective::SetSubTool(int subtool) {
|
||||
if (toolBar == nullptr) {
|
||||
throw agi::InternalError("Vector clip toolbar hasn't been set yet!");
|
||||
}
|
||||
for (int i = 1; i < PERSP_LAST; i <<= 1)
|
||||
toolBar->ToggleTool(BUTTON_ID_BASE + i, i & subtool);
|
||||
|
||||
toolBar->EnableTool(BUTTON_ID_BASE + PERSP_LOCK_OUTER, subtool & PERSP_OUTER);
|
||||
|
||||
cmd::Command *orgmode;
|
||||
switch (subtool & PERSP_ORGMODE) {
|
||||
case PERSP_ORGMODE_CENTER:
|
||||
orgmode = cmd::get("video/tool/perspective/orgmode/center");
|
||||
break;
|
||||
case PERSP_ORGMODE_NOFAX:
|
||||
orgmode = cmd::get("video/tool/perspective/orgmode/nofax");
|
||||
break;
|
||||
case PERSP_ORGMODE_KEEP:
|
||||
orgmode = cmd::get("video/tool/perspective/orgmode/keep");
|
||||
break;
|
||||
default:
|
||||
throw agi::InternalError("Invalid perspective subtool");
|
||||
}
|
||||
wxString orgmodehelp = orgmode->StrDisplay(c) + wxString(". Click to cycle.\n") + orgmode->GetTooltip("Video");
|
||||
toolBar->SetToolShortHelp(BUTTON_ID_BASE + PERSP_ORGMODE, orgmodehelp);
|
||||
toolBar->SetToolLongHelp(BUTTON_ID_BASE + PERSP_ORGMODE, orgmodehelp);
|
||||
toolBar->SetToolNormalBitmap(BUTTON_ID_BASE + PERSP_ORGMODE, orgmode->Icon(OPT_GET("App/Toolbar Icon Size")->GetInt()));
|
||||
toolBar->ToggleTool(BUTTON_ID_BASE + PERSP_ORGMODE, false);
|
||||
|
||||
settings = subtool;
|
||||
|
||||
optOuter->SetBool(HasOuter());
|
||||
optOuterLocked->SetBool(OuterLocked());
|
||||
optGrid->SetBool(settings & PERSP_GRID);
|
||||
optOrgMode->SetInt(GetOrgMode());
|
||||
|
||||
MakeFeatures();
|
||||
parent->Render();
|
||||
}
|
||||
|
||||
int VisualToolPerspective::GetSubTool() {
|
||||
return settings;
|
||||
}
|
||||
|
||||
bool VisualToolPerspective::HasOuter() {
|
||||
return GetSubTool() & PERSP_OUTER;
|
||||
}
|
||||
|
||||
bool VisualToolPerspective::OuterLocked() {
|
||||
return HasOuter() && (GetSubTool() & PERSP_LOCK_OUTER);
|
||||
}
|
||||
|
||||
int VisualToolPerspective::GetOrgMode() {
|
||||
return GetSubTool() & PERSP_ORGMODE;
|
||||
}
|
||||
|
||||
bool VisualToolPerspective::HasOrgf() {
|
||||
return GetOrgMode() == PERSP_ORGMODE_KEEP;
|
||||
}
|
||||
|
||||
std::vector<Vector2D> VisualToolPerspective::FeaturePositions(std::vector<Feature *> features) const {
|
||||
std::vector<Vector2D> result;
|
||||
for (size_t i = 0; i < 4; i++) {
|
||||
result.push_back(features[i]->pos);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void VisualToolPerspective::UpdateInner() {
|
||||
std::vector<Vector2D> uv = MakeRect(c1, c2);
|
||||
std::vector<Vector2D> quad = FeaturePositions(outer_corners);
|
||||
for (int i = 0; i < 4; i++)
|
||||
inner_corners[i]->pos = UVToXY(quad, uv[i]);
|
||||
}
|
||||
|
||||
void VisualToolPerspective::UpdateOuter() {
|
||||
if (!HasOuter())
|
||||
return;
|
||||
std::vector<Vector2D> uv = MakeRect(-c1 / (c2 - c1), (1 - c1) / (c2 - c1));
|
||||
std::vector<Vector2D> quad = FeaturePositions(inner_corners);
|
||||
for (int i = 0; i < 4; i++)
|
||||
outer_corners[i]->pos = UVToXY(quad, uv[i]);
|
||||
}
|
||||
|
||||
void VisualToolPerspective::MakeFeatures() {
|
||||
sel_features.clear();
|
||||
features.clear();
|
||||
active_feature = nullptr;
|
||||
|
||||
inner_corners.clear();
|
||||
outer_corners.clear();
|
||||
orgf = nullptr;
|
||||
|
||||
centerf = new Feature(this, FEATURE_CENTER, 0);
|
||||
centerf->type = DRAG_BIG_TRIANGLE;
|
||||
features.push_back(*centerf);
|
||||
|
||||
if (HasOrgf()) {
|
||||
orgf = new Feature(this, FEATURE_ORG, 0);
|
||||
orgf->type = DRAG_BIG_TRIANGLE;
|
||||
features.push_back(*orgf);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
inner_corners.push_back(new Feature(this, FEATURE_INNER, i));
|
||||
inner_corners.back()->type = DRAG_SMALL_CIRCLE;
|
||||
features.push_back(*inner_corners.back());
|
||||
|
||||
if (HasOuter()) {
|
||||
outer_corners.push_back(new Feature(this, FEATURE_OUTER, i));
|
||||
outer_corners.back()->type = DRAG_SMALL_CIRCLE;
|
||||
features.push_back(*outer_corners.back());
|
||||
}
|
||||
}
|
||||
|
||||
DoRefresh();
|
||||
}
|
||||
|
||||
void VisualToolPerspective::Draw() {
|
||||
if (!active_line) return;
|
||||
|
||||
wxColour line_color = to_wx(line_color_primary_opt->GetColor());
|
||||
wxColour line_color_secondary = to_wx(line_color_secondary_opt->GetColor());
|
||||
|
||||
// Draw Quad
|
||||
gl.SetLineColour(line_color);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (HasOuter()) {
|
||||
gl.DrawDashedLine(outer_corners[i]->pos, outer_corners[(i + 1) % 4]->pos, 6);
|
||||
gl.DrawLine(inner_corners[i]->pos, inner_corners[(i + 1) % 4]->pos);
|
||||
} else {
|
||||
gl.DrawDashedLine(inner_corners[i]->pos, inner_corners[(i + 1) % 4]->pos, 6);
|
||||