]> granicus.if.org Git - libass/commitdiff
Move outline transformations to ass_outline.c
authorDr.Smile <vabnick@gmail.com>
Sun, 22 Oct 2017 04:21:34 +0000 (07:21 +0300)
committerDr.Smile <vabnick@gmail.com>
Sun, 19 May 2019 22:07:41 +0000 (01:07 +0300)
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.

libass/ass_outline.c
libass/ass_outline.h
libass/ass_render.c

index 109e09a784b92f28dc61b0ba762838f24284e8c8..fd7e4ed70093b6ecb397aa746eb395cb5b28770a 100644 (file)
@@ -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)
index 0a45589977130695d8b4d132459087ea8613ce41..414103a1db26f5432bfe1a40b5f24b45336f11f3 100644 (file)
@@ -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);
index 1fb7f2978ea051e38f091c584e310dd7fb8e7249..eb0a407818843ca7e073b9e0823d21f79cef2390 100644 (file)
@@ -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]))