Merge branch 'vector_clip_actions' into feature

This commit is contained in:
arch1t3cht 2023-04-29 01:16:08 +02:00
commit ff20805ae6
10 changed files with 107 additions and 49 deletions

View File

@ -178,7 +178,7 @@ namespace {
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.") 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 { bool Validate(const agi::Context *c) override {
return c->videoDisplay->ToolIsType(typeid(VisualToolPerspective)) && c->videoDisplay->GetSubTool() | PERSP_OUTER; return c->videoDisplay->ToolIsType(typeid(VisualToolPerspective)) && c->videoDisplay->GetSubTool() & PERSP_OUTER;
} }
}; };

View File

@ -41,17 +41,22 @@
#include <limits> #include <limits>
Spline::Spline(const VisualToolBase &tl) Spline::Spline(const VisualToolBase *tl)
: coord_translator(tl) : coord_translator(tl)
{ {
} }
Vector2D Spline::ToScript(Vector2D vec) const { Vector2D Spline::ToScript(Vector2D vec) const {
return coord_translator.ToScriptCoords(vec) * scale; if (coord_translator)
vec = coord_translator->ToScriptCoords(vec);
return vec * scale;
} }
Vector2D Spline::FromScript(Vector2D vec) const { Vector2D Spline::FromScript(Vector2D vec) const {
return coord_translator.FromScriptCoords(vec / scale); vec = vec / scale;
if (coord_translator)
vec = coord_translator->FromScriptCoords(vec);
return vec;
} }
void Spline::SetScale(int new_scale) { void Spline::SetScale(int new_scale) {

View File

@ -36,7 +36,7 @@ class VisualToolBase;
class Spline final : private std::vector<SplineCurve> { class Spline final : private std::vector<SplineCurve> {
/// Visual tool to do the conversion between script and video pixels /// Visual tool to do the conversion between script and video pixels
const VisualToolBase &coord_translator; const VisualToolBase *coord_translator = nullptr;
/// Spline scale /// Spline scale
int scale = 0; int scale = 0;
int raw_scale = 0; int raw_scale = 0;
@ -47,7 +47,8 @@ class Spline final : private std::vector<SplineCurve> {
/// Script coordinates -> Video coordinates /// Script coordinates -> Video coordinates
Vector2D FromScript(Vector2D vec) const; Vector2D FromScript(Vector2D vec) const;
public: public:
Spline(const VisualToolBase &scale); Spline() {};
Spline(const VisualToolBase *scale);
/// Encode to an ASS vector drawing /// Encode to an ASS vector drawing
std::string EncodeToAss() const; std::string EncodeToAss() const;

View File

@ -115,6 +115,15 @@ Vector2D& SplineCurve::EndPoint() {
} }
} }
std::vector<Vector2D> SplineCurve::AnchorPoints() {
switch (type) {
case POINT: return std::vector<Vector2D>({p1});
case LINE: return std::vector<Vector2D>({p1, p2});
case BICUBIC: return std::vector<Vector2D>({p1, p2, p3, p4});
default: return std::vector<Vector2D>();
}
}
Vector2D SplineCurve::GetClosestPoint(Vector2D ref) const { Vector2D SplineCurve::GetClosestPoint(Vector2D ref) const {
return GetPoint(GetClosestParam(ref)); return GetPoint(GetClosestParam(ref));
} }

View File

@ -73,6 +73,7 @@ public:
Vector2D GetPoint(float t) const; Vector2D GetPoint(float t) const;
Vector2D& EndPoint(); Vector2D& EndPoint();
std::vector<Vector2D> AnchorPoints();
/// Get point on the curve closest to reference /// Get point on the curve closest to reference
Vector2D GetClosestPoint(Vector2D ref) const; Vector2D GetClosestPoint(Vector2D ref) const;
/// Get t value for the closest point to reference /// Get t value for the closest point to reference

View File

@ -40,6 +40,8 @@
#include <libaegisub/of_type_adaptor.h> #include <libaegisub/of_type_adaptor.h>
#include <libaegisub/split.h> #include <libaegisub/split.h>
#include <boost/algorithm/string/join.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/algorithm/string/replace.hpp> #include <boost/algorithm/string/replace.hpp>
#include <algorithm> #include <algorithm>
@ -540,11 +542,9 @@ int VisualToolBase::GetLineAlignment(AssDialogue *diag) {
return an; return an;
} }
void VisualToolBase::GetLineBaseExtents(AssDialogue *diag, double &width, double &height, double &descent, double &extlead) { std::pair<Vector2D, Vector2D> VisualToolBase::GetLineBaseExtents(AssDialogue *diag) {
width = 0.; double width = 0.;
height = 0.; double height = 0.;
descent = 0.;
extlead = 0.;
AssStyle style; AssStyle style;
if (AssStyle *basestyle = c->ass->GetStyle(diag->Style)) { if (AssStyle *basestyle = c->ass->GetStyle(diag->Style)) {
@ -554,25 +554,57 @@ void VisualToolBase::GetLineBaseExtents(AssDialogue *diag, double &width, double
} }
auto blocks = diag->ParseTags(); auto blocks = diag->ParseTags();
if (param_vec tag = find_tag(blocks, "\\fs")) param_vec ptag = find_tag(blocks, "\\p");
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 (ptag && ptag->front().Get(0)) { // A drawing
std::vector<std::string> textlines; Spline spline;
boost::replace_all(text, "\\N", "\n"); spline.SetScale(ptag->front().Get(1));
agi::Split(textlines, text, '\n'); std::string drawing_text = join(blocks | agi::of_type<AssDialogueBlockDrawing>() | boost::adaptors::transformed([&](AssDialogueBlock *d) { return d->GetText(); }), "");
for (std::string line : textlines) { spline.DecodeFromAss(drawing_text);
double linewidth = 0;
double lineheight = 0; if (!spline.size())
if (!Automation4::CalculateTextExtents(&style, line, linewidth, lineheight, descent, extlead)) { return std::make_pair(Vector2D(0, 0), Vector2D(0, 0));
// meh... let's make some ballpark estimates
linewidth = style.fontsize * line.length(); float left = FLT_MAX;
lineheight = style.fontsize; float top = FLT_MAX;
float right = -FLT_MAX;
float bot = -FLT_MAX;
for (SplineCurve curve : spline) {
for (Vector2D pt : curve.AnchorPoints()) {
left = std::min(left, pt.X());
top = std::min(top, pt.Y());
right = std::max(right, pt.X());
bot = std::max(bot, pt.Y());
}
} }
width = std::max(width, linewidth);
height += lineheight; return std::make_pair(Vector2D(left, top), Vector2D(right, bot));
} else {
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;
double descent;
double extlead;
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;
}
return std::make_pair(Vector2D(0, 0), Vector2D(width, height));
} }
} }

View File

@ -133,11 +133,18 @@ protected:
float GetLineFontSize(AssDialogue *diag); float GetLineFontSize(AssDialogue *diag);
int GetLineAlignment(AssDialogue *diag); int GetLineAlignment(AssDialogue *diag);
/// @brief Compute text extents of the given line without any formatting /// @brief Compute text extents of the given line without any formatting
/// @param diag The dialogue line
/// @return The top left and bottom right corners of the line's bounding box respectively.
/// ///
/// Formatting tags are stripped and \fs tags are respected, but \fscx and \fscy are kept as 100 even if /// 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. /// they are different in the style.
/// For text the top left corner of the bounding box will always be at the origin, but this needn't be
/// the case for drawings. The width and height of the bounding box are the shifts used for text alignment.
///
/// This function works for most common line formats, but can be inaccurate for more complex cases such as lines
/// containing both text and drawings.
/// Returns a rough estimate when getting the precise extents fails /// Returns a rough estimate when getting the precise extents fails
void GetLineBaseExtents(AssDialogue *diag, double &width, double &height, double &descent, double &extlead); std::pair<Vector2D, Vector2D> GetLineBaseExtents(AssDialogue *diag);
void GetLineClip(AssDialogue *diag, Vector2D &p1, Vector2D &p2, bool &inverse); void GetLineClip(AssDialogue *diag, Vector2D &p1, Vector2D &p2, bool &inverse);
std::string GetLineVectorClip(AssDialogue *diag, int &scale, bool &inverse); std::string GetLineVectorClip(AssDialogue *diag, int &scale, bool &inverse);

View File

@ -35,6 +35,8 @@
#include <libaegisub/split.h> #include <libaegisub/split.h>
#include <libaegisub/util.h> #include <libaegisub/util.h>
#include <libaegisub/log.h>
#include <cmath> #include <cmath>
#include <wx/colour.h> #include <wx/colour.h>
@ -332,7 +334,7 @@ void VisualToolPerspective::Draw() {
gl.SetRotation(angle_x, angle_y, angle_z); gl.SetRotation(angle_x, angle_y, angle_z);
gl.SetScale(fsc); gl.SetScale(fsc);
gl.SetShear(fax, fay); gl.SetShear(fax, fay);
Vector2D glScale = textheight * Vector2D(1, 1) / spacing / 4; Vector2D glScale = (bbox.second.Y() - bbox.first.Y()) * Vector2D(1, 1) / spacing / 4;
gl.SetScale(100 * glScale); gl.SetScale(100 * glScale);
// Draw grid // Draw grid
@ -678,17 +680,18 @@ bool VisualToolPerspective::InnerToText() {
float quadwidth = ab.Len(); float quadwidth = ab.Len();
float quadheight = abs(ad.Y()); float quadheight = abs(ad.Y());
float scalex = quadwidth / textwidth; float scalex = quadwidth / std::max(bbox.second.X() - bbox.first.X(), 1.0f);
float scaley = quadheight / textheight; float scaley = quadheight / std::max(bbox.second.Y() - bbox.first.Y(), 1.0f);
Vector2D scale = Vector2D(scalex, scaley);
float shiftv = align <= 3 ? 1 : (align <= 6 ? 0.5 : 0); float shiftv = align <= 3 ? 1 : (align <= 6 ? 0.5 : 0);
float shifth = align % 3 == 0 ? 1 : (align % 3 == 2 ? 0.5 : 0); float shifth = align % 3 == 0 ? 1 : (align % 3 == 2 ? 0.5 : 0);
pos = org + r[0].XY() + Vector2D(quadwidth * shifth, quadheight * shiftv); pos = org + r[0].XY() - bbox.first * scale + Vector2D(quadwidth * shifth, quadheight * shiftv);
angle_x = rotx * rad2deg; angle_x = rotx * rad2deg;
angle_y = -roty * rad2deg; angle_y = -roty * rad2deg;
angle_z = -rotz * rad2deg; angle_z = -rotz * rad2deg;
Vector2D oldfsc = fsc; Vector2D oldfsc = fsc;
fsc = 100 * Vector2D(scalex, scaley); fsc = 100 * scale;
fax = rawfax * scaley / scalex; fax = rawfax * scaley / scalex;
fay = 0; fay = 0;
@ -779,40 +782,39 @@ void VisualToolPerspective::TextToPersp() {
align = GetLineAlignment(active_line); align = GetLineAlignment(active_line);
double descend, extlead; bbox = GetLineBaseExtents(active_line);
GetLineBaseExtents(active_line, textwidth, textheight, descend, extlead); float textwidth = std::max(bbox.second.X() - bbox.first.X(), 1.f);
textwidth = std::max(textwidth, 1.); float textheight = std::max(bbox.second.Y() - bbox.first.Y(), 1.f);
textheight = std::max(textheight, 1.); double shiftx = 0., shifty = 0.;
double textleft, texttop = 0.;
switch ((align - 1) % 3) { switch ((align - 1) % 3) {
case 1: case 1:
textleft = -textwidth / 2; shiftx = -textwidth / 2;
break; break;
case 2: case 2:
textleft = -textwidth; shiftx = -textwidth;
break; break;
default: default:
break; break;
} }
switch ((align - 1) / 3) { switch ((align - 1) / 3) {
case 0: case 0:
texttop = -textheight; shifty = -textheight;
break; break;
case 1: case 1:
texttop = -textheight / 2; shifty = -textheight / 2;
break; break;
default: default:
break; break;
} }
std::vector<Vector2D> textrect = MakeRect(Vector2D(0, 0), Vector2D(textwidth, textheight)); std::vector<Vector2D> textrect = MakeRect(bbox.first, bbox.second);
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
Vector2D p = textrect[i]; Vector2D p = textrect[i];
// Apply \fax and \fay // Apply \fax and \fay
p = Vector2D(p.X() + p.Y() * fax, p.X() * fay + p.Y()); p = Vector2D(p.X() + p.Y() * fax, p.X() * fay + p.Y());
// Translate to alignment point // Translate to alignment point
p = p + Vector2D(textleft, texttop); p = p + Vector2D(shiftx, shifty);
// Apply scaling // Apply scaling
p = Vector2D(p.X() * fsc.X() / 100., p.Y() * fsc.Y() / 100.); p = Vector2D(p.X() * fsc.X() / 100., p.Y() * fsc.Y() / 100.);
// Translate relative to origin // Translate relative to origin

View File

@ -52,7 +52,7 @@ public:
class VisualToolPerspective final : public VisualTool<VisualToolPerspectiveDraggableFeature> { class VisualToolPerspective final : public VisualTool<VisualToolPerspectiveDraggableFeature> {
wxToolBar *toolBar = nullptr; /// The subtoolbar wxToolBar *toolBar = nullptr; /// The subtoolbar
int settings = 0; int settings = 0;
agi::OptionValue* optOuter; agi::OptionValue* optOuter;
agi::OptionValue* optOuterLocked; agi::OptionValue* optOuterLocked;
@ -69,8 +69,9 @@ class VisualToolPerspective final : public VisualTool<VisualToolPerspectiveDragg
int align = 0; int align = 0;
double textwidth = 0.f; // Corners of the bounding box of the event without any formatting.
double textheight = 0.f; // The top left corner is the zero vector for text but might not be for drawings.
std::pair<Vector2D, Vector2D> bbox;
Vector2D fsc; Vector2D fsc;

View File

@ -34,7 +34,7 @@ int BUTTON_ID_BASE = 1300;
VisualToolVectorClip::VisualToolVectorClip(VideoDisplay *parent, agi::Context *context) VisualToolVectorClip::VisualToolVectorClip(VideoDisplay *parent, agi::Context *context)
: VisualTool<VisualToolVectorClipDraggableFeature>(parent, context) : VisualTool<VisualToolVectorClipDraggableFeature>(parent, context)
, spline(*this) , spline(this)
{ {
} }