diff options
author | Dr.Smile <vabnick@gmail.com> | 2017-10-22 07:21:34 +0300 |
---|---|---|
committer | Dr.Smile <vabnick@gmail.com> | 2019-05-20 01:07:41 +0300 |
commit | f6982a04037b9a935a2e52e8e4d6186fac912ca8 (patch) | |
tree | e4d9078f39b97bead4ee9146a54401bdce980dd9 | |
parent | 0aabe2f9a33c92543b4e62f9f17171992b1e9313 (diff) | |
download | libass-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.c | 64 | ||||
-rw-r--r-- | libass/ass_outline.h | 8 | ||||
-rw-r--r-- | libass/ass_render.c | 29 |
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])) |