summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDr.Smile <vabnick@gmail.com>2017-10-22 07:21:34 +0300
committerDr.Smile <vabnick@gmail.com>2019-05-20 01:07:41 +0300
commitf6982a04037b9a935a2e52e8e4d6186fac912ca8 (patch)
treee4d9078f39b97bead4ee9146a54401bdce980dd9
parent0aabe2f9a33c92543b4e62f9f17171992b1e9313 (diff)
downloadlibass-f6982a04037b9a935a2e52e8e4d6186fac912ca8.tar.bz2
libass-f6982a04037b9a935a2e52e8e4d6186fac912ca8.tar.xz
Move outline transformations to ass_outline.c
This also potentially improves performance by copying and transforming in a single operation rather than copying first and then transforming the result. Also transformation function is specialized for case where expensive perspective division is not necessary.
-rw-r--r--libass/ass_outline.c64
-rw-r--r--libass/ass_outline.h8
-rw-r--r--libass/ass_render.c29
3 files changed, 72 insertions, 29 deletions
diff --git a/libass/ass_outline.c b/libass/ass_outline.c
index 109e09a..fd7e4ed 100644
--- a/libass/ass_outline.c
+++ b/libass/ass_outline.c
@@ -201,7 +201,8 @@ fail:
return false;
}
-bool outline_copy(ASS_Outline *outline, const ASS_Outline *source)
+bool outline_scale_pow2(ASS_Outline *outline, const ASS_Outline *source,
+ int scale_ord_x, int scale_ord_y)
{
if (!source || !source->n_points) {
outline_clear(outline);
@@ -211,24 +212,75 @@ bool outline_copy(ASS_Outline *outline, const ASS_Outline *source)
if (!outline_alloc(outline, source->n_points, source->n_segments))
return false;
- memcpy(outline->points, source->points, sizeof(ASS_Vector) * source->n_points);
+ int sx = scale_ord_x + 32;
+ int sy = scale_ord_y + 32;
+ const ASS_Vector *pt = source->points;
+ for (size_t i = 0; i < source->n_points; i++) {
+ // that's equivalent to pt[i].x << scale_ord_x,
+ // but works even for negative coordinate and/or shift amount
+ outline->points[i].x = pt[i].x * ((int64_t) 1 << sx) >> 32;
+ outline->points[i].y = pt[i].y * ((int64_t) 1 << sy) >> 32;
+ }
memcpy(outline->segments, source->segments, source->n_segments);
outline->n_points = source->n_points;
outline->n_segments = source->n_segments;
return true;
}
-void outline_move(ASS_Outline *outline, ASS_Outline *source)
+bool outline_transform_2d(ASS_Outline *outline, const ASS_Outline *source,
+ const double m[2][3])
{
if (!source || !source->n_points) {
outline_clear(outline);
- return;
+ return true;
+ }
+
+ if (!outline_alloc(outline, source->n_points, source->n_segments))
+ return false;
+
+ const ASS_Vector *pt = source->points;
+ for (size_t i = 0; i < source->n_points; i++) {
+ double v[2];
+ for (int k = 0; k < 2; k++)
+ v[k] = m[k][0] * pt[i].x + m[k][1] * pt[i].y + m[k][2];
+
+ outline->points[i].x = lrint(v[0]);
+ outline->points[i].y = lrint(v[1]);
+ }
+ memcpy(outline->segments, source->segments, source->n_segments);
+ outline->n_points = source->n_points;
+ outline->n_segments = source->n_segments;
+ return true;
+}
+
+bool outline_transform_3d(ASS_Outline *outline, const ASS_Outline *source,
+ const double m[3][3])
+{
+ if (!source || !source->n_points) {
+ outline_clear(outline);
+ return true;
}
- memcpy(outline, source, sizeof(*outline));
- outline_clear(source);
+ if (!outline_alloc(outline, source->n_points, source->n_segments))
+ return false;
+
+ const ASS_Vector *pt = source->points;
+ for (size_t i = 0; i < source->n_points; i++) {
+ double v[3];
+ for (int k = 0; k < 3; k++)
+ v[k] = m[k][0] * pt[i].x + m[k][1] * pt[i].y + m[k][2];
+
+ double w = 1 / FFMAX(v[2], 0.1);
+ outline->points[i].x = lrint(v[0] * w);
+ outline->points[i].y = lrint(v[1] * w);
+ }
+ memcpy(outline->segments, source->segments, source->n_segments);
+ outline->n_points = source->n_points;
+ outline->n_segments = source->n_segments;
+ return true;
}
+
void outline_free(ASS_Outline *outline)
{
if (!outline)
diff --git a/libass/ass_outline.h b/libass/ass_outline.h
index 0a45589..414103a 100644
--- a/libass/ass_outline.h
+++ b/libass/ass_outline.h
@@ -88,8 +88,12 @@ typedef struct {
bool outline_alloc(ASS_Outline *outline, size_t n_points, size_t n_segments);
bool outline_convert(ASS_Outline *outline, const FT_Outline *source);
-bool outline_copy(ASS_Outline *outline, const ASS_Outline *source);
-void outline_move(ASS_Outline *outline, ASS_Outline *source);
+bool outline_scale_pow2(ASS_Outline *outline, const ASS_Outline *source,
+ int scale_ord_x, int scale_ord_y);
+bool outline_transform_2d(ASS_Outline *outline, const ASS_Outline *source,
+ const double m[2][3]);
+bool outline_transform_3d(ASS_Outline *outline, const ASS_Outline *source,
+ const double m[3][3]);
void outline_free(ASS_Outline *outline);
bool outline_add_point(ASS_Outline *outline, ASS_Vector pt, char segment);
diff --git a/libass/ass_render.c b/libass/ass_render.c
index 1fb7f29..eb0a407 100644
--- a/libass/ass_render.c
+++ b/libass/ass_render.c
@@ -1187,14 +1187,9 @@ size_t ass_outline_construct(void *key, void *value, void *priv)
break;
ASS_Outline src;
- if (!outline_copy(&src, &k->outline->outline[0]))
+ if (!outline_scale_pow2(&src, &k->outline->outline[0],
+ k->scale_ord_x, k->scale_ord_y))
return 1;
- for (size_t i = 0; i < src.n_points; i++) {
- // that's equivalent to src.points[i].x << k->scale_ord_x,
- // but works even for negative coordinate and/or shift amount
- src.points[i].x = src.points[i].x * ((int64_t) 1 << (32 + k->scale_ord_x)) >> 32;
- src.points[i].y = src.points[i].y * ((int64_t) 1 << (32 + k->scale_ord_y)) >> 32;
- }
outline_alloc(&v->outline[0], 2 * src.n_points, 2 * src.n_segments);
outline_alloc(&v->outline[1], 2 * src.n_points, 2 * src.n_segments);
@@ -1456,20 +1451,12 @@ size_t ass_bitmap_construct(void *key, void *value, void *priv)
restore_transform(m, k);
ASS_Outline outline[2];
- outline_copy(&outline[0], &k->outline->outline[0]);
- outline_copy(&outline[1], &k->outline->outline[1]);
-
- for (int i = 0; i < 2; i++) {
- ASS_Vector *p = outline[i].points;
- for (size_t j = 0; j < outline[i].n_points; ++j) {
- double v[3];
- for (int k = 0; k < 3; k++)
- v[k] = m[k][0] * p[j].x + m[k][1] * p[j].y + m[k][2];
-
- double w = 1 / FFMAX(v[2], 0.1);
- p[j].x = lrint(v[0] * w);
- p[j].y = lrint(v[1] * w);
- }
+ if (k->matrix_z.x || k->matrix_z.y) {
+ outline_transform_3d(&outline[0], &k->outline->outline[0], m);
+ outline_transform_3d(&outline[1], &k->outline->outline[1], m);
+ } else {
+ outline_transform_2d(&outline[0], &k->outline->outline[0], m);
+ outline_transform_2d(&outline[1], &k->outline->outline[1], m);
}
if (!outline_to_bitmap(render_priv, bm, &outline[0], &outline[1]))