diff --git a/CHANGELOG.md b/CHANGELOG.md index c42a1d386..babe6168e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,6 +35,8 @@ Versioning](https://semver.org/spec/v2.0.0.html) for `libnopegl`. - `Render*` nodes are renamed to `Draw*` - `TextEffect.transform` now default to an anchor in the center of the characters instead of a distant bottom-left position +- `TextEffect.transform` are now combined on overlapping text effects instead of + replacing the previous one ### Removed - `Text.aspect_ratio`, it now matches the viewport aspect ratio diff --git a/libnopegl/src/text.c b/libnopegl/src/text.c index 7987798c9..76c2238fd 100644 --- a/libnopegl/src/text.c +++ b/libnopegl/src/text.c @@ -349,11 +349,13 @@ static int set_transform(float *dst, struct texteffect_opts *effect_opts, ngli_mat4_translate(tmreloc0, anchor_x, anchor_y, 0.f); ngli_mat4_translate(tmreloc1, -anchor_x, -anchor_y, 0.f); - float *tmp = tmreloc0; // go to anchor + NGLI_ALIGNED_MAT(tmp); + memcpy(tmp, dst, sizeof(tm)); // start from the existing position + ngli_mat4_mul(tmp, tmp, tmreloc0); // go to anchor ngli_mat4_mul(tmp, tmp, tm); // apply user transform matrix ngli_mat4_mul(tmp, tmp, tmreloc1); // go back from anchor - memcpy(dst, tmp, 4 * 4 * sizeof(*dst)); + memcpy(dst, tmp, sizeof(tmp)); return 0; } diff --git a/tests/texteffect.py b/tests/texteffect.py index e8d067b21..a43e921ad 100644 --- a/tests/texteffect.py +++ b/tests/texteffect.py @@ -205,6 +205,45 @@ def texteffect_vp_anchor(cfg: ngl.SceneCfg): return ngl.Text("ABC", bg_color=(1, 0, 0), box=(-1, 0, 2, 1), effects=effects) +@test_fingerprint(width=640, height=360, keyframes=10, tolerance=1) +@ngl.scene() +def texteffect_combined_diff_anchors(cfg: ngl.SceneCfg): + cfg.duration = 3 + + animkf_rotate = [ + ngl.AnimKeyFrameFloat(0, -180), + ngl.AnimKeyFrameFloat(0.5, 0, "linear"), + ] + animkf_scale = [ + ngl.AnimKeyFrameVec3(0, (0.0, 0.0, 1.0)), + ngl.AnimKeyFrameVec3(1, (1.0, 1.0, 1.0), "linear"), + ] + rotate = ngl.Rotate(ngl.Identity(), angle=ngl.AnimatedFloat(animkf_rotate)) + scale = ngl.Scale(ngl.Identity(), factors=ngl.AnimatedVec3(animkf_scale)) + effects = [ + ngl.TextEffect( + start=0, + end=cfg.duration, + target="char", + overlap=0.5, + transform=scale, + anchor=(0, -1), + anchor_ref="viewport", + ), + ngl.TextEffect( + start=0, + end=cfg.duration, + target="char", + overlap=0.0, + transform=rotate, + anchor=(0, 1), + anchor_ref="char", + ), + ] + + return ngl.Text("ABC", bg_color=(1, 0, 0), box=(-1, 0, 2, 1), effects=effects) + + @test_fingerprint(width=640, height=360, keyframes=10, tolerance=1) @ngl.scene() def texteffect_chars_space_nospace(cfg: ngl.SceneCfg):