Skip to content

Commit

Permalink
slideshow: animation color: improving color substitution
Browse files Browse the repository at this point in the history
Since color animation implementation is based on substituting the original color
with a new one, some pixel could be missed since they don't match the original
color because of anti-aliasing.
This new implementation improves this issue by checking the distance btw the
current pixel color and the color segment in the RGBA space with end points the
line color and the fill color.

Signed-off-by: Marco Cecchetti <marco.cecchetti@collabora.com>
Change-Id: I14831553e3eae1a5510bfa855a3e9375b4e3de94
  • Loading branch information
mcecchetti committed Dec 18, 2024
1 parent 9073b75 commit 5e8fced
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 27 deletions.
19 changes: 10 additions & 9 deletions browser/src/slideshow/LayerRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ interface LayerRenderer {

class LayerRendererGl implements LayerRenderer {
private static readonly DefaultVertices = [-1, -1, 1, -1, -1, 1, 1, 1];
private static readonly InvalidColor = new Float32Array([-1, -1, -1, -1]);
private static readonly ErrorColor = new Float32Array([1, 0, 0, 1]);
private static readonly DefaultFromColor = new Float32Array([0, 0, 0, 0]);
private static readonly DefaultToColor = new Float32Array([0, 0, 0, 0]);
private offscreenCanvas: OffscreenCanvas;
private glContext: RenderContextGl;
private gl: WebGL2RenderingContext;
Expand Down Expand Up @@ -93,11 +93,12 @@ class LayerRendererGl implements LayerRenderer {
varying vec2 v_texCoord;
uniform sampler2D u_sampler;
${GlHelpers.nearestPointOnSegment}
${GlHelpers.computeColor}
void main() {
vec4 color = texture2D(u_sampler, v_texCoord);
color = mix(mix(color, toLineColor, float(distance(color, fromLineColor) < 0.03)),
toFillColor,
float(distance(color, fromFillColor) < 0.03));
color = computeColor(color);
color = color * alpha;
gl_FragColor = color;
}
Expand Down Expand Up @@ -191,10 +192,10 @@ class LayerRendererGl implements LayerRenderer {

let bounds: BoundsType = null;
let alpha = 1.0;
let fromFillColor = LayerRendererGl.InvalidColor;
let toFillColor = LayerRendererGl.ErrorColor;
let fromLineColor = LayerRendererGl.InvalidColor;
let toLineColor = LayerRendererGl.ErrorColor;
let fromFillColor = LayerRendererGl.DefaultFromColor;
let toFillColor = LayerRendererGl.DefaultToColor;
let fromLineColor = LayerRendererGl.DefaultFromColor;
let toLineColor = LayerRendererGl.DefaultToColor;
if (properties) {
bounds = properties.bounds;
alpha = properties.alpha;
Expand Down
12 changes: 6 additions & 6 deletions browser/src/slideshow/Transition2d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,8 @@ abstract class TransitionBase extends SlideChangeGl {
}

class Transition2d extends TransitionBase {
private static readonly InvalidColor = new Float32Array([-1, -1, -1, -1]);
private static readonly ErrorColor = new Float32Array([1, 0, 0, 1]);
private static readonly DefaultFromColor = new Float32Array([0, 0, 0, 0]);
private static readonly DefaultToColor = new Float32Array([0, 0, 0, 0]);

constructor(transitionParameters: TransitionParameters) {
super(transitionParameters);
Expand Down Expand Up @@ -172,10 +172,10 @@ class Transition2d extends TransitionBase {
// jscpd:ignore-start
let bounds: BoundsType = null;
let alpha = 1.0;
let fromFillColor = Transition2d.InvalidColor;
let toFillColor = Transition2d.ErrorColor;
let fromLineColor = Transition2d.InvalidColor;
let toLineColor = Transition2d.ErrorColor;
let fromFillColor = Transition2d.DefaultFromColor;
let toFillColor = Transition2d.DefaultToColor;
let fromLineColor = Transition2d.DefaultFromColor;
let toLineColor = Transition2d.DefaultToColor;
if (properties) {
bounds = properties.bounds;
alpha = properties.alpha;
Expand Down
17 changes: 8 additions & 9 deletions browser/src/slideshow/engine/AnimatedElement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -789,15 +789,14 @@ class AnimatedElement {
colorMap.fromFillColor = this.aBaseFontColor;
colorMap.toFillColor = this.aFontColor;
}
} else {
if (!this.aFillColor.equal(this.aBaseFillColor)) {
colorMap.fromFillColor = this.aBaseFillColor;
colorMap.toFillColor = this.aFillColor;
}
if (!this.aLineColor.equal(this.aBaseLineColor)) {
colorMap.fromLineColor = this.aBaseLineColor;
colorMap.toLineColor = this.aLineColor;
}
} else if (
!this.aFillColor.equal(this.aBaseFillColor) ||
!this.aLineColor.equal(this.aBaseLineColor)
) {
colorMap.fromFillColor = this.aBaseFillColor;
colorMap.toFillColor = this.aFillColor;
colorMap.fromLineColor = this.aBaseLineColor;
colorMap.toLineColor = this.aLineColor;
}

const properties: AnimatedElementRenderProperties = {
Expand Down
41 changes: 41 additions & 0 deletions browser/src/slideshow/engine/tools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,47 @@ class PriorityQueue {
}
}

namespace GlHelpers {
export const nearestPointOnSegment = `
float nearestPointOnSegment(vec4 CF, vec4 CT, vec4 C) {
// Compute the vector along the segment (CT - CF)
vec4 segment = CT - CF;
// Compute the vector from the endpoint CF to the point C
vec4 toC = C - CF;
float length2 = dot(segment, segment);
// Project C onto the segment, finding the scalar 't'
float t = dot(toC, segment) / length2;
// Clamp 't' to [0, 1] range to ensure the nearest point lies on the segment
t = clamp(t, 0.0, 1.0);
return t;
}
`;

export const computeColor = `
vec4 computeColor(vec4 color) {
if (fromLineColor != toLineColor || fromFillColor != toFillColor) {
vec4 colorSegment = fromFillColor - fromLineColor;
float length2 = dot(colorSegment, colorSegment);
if (length2 < 1e-6) {
return toFillColor;
}
else {
float t = nearestPointOnSegment(fromLineColor, fromFillColor, color);
vec4 fromColor = fromLineColor + t * colorSegment;
vec4 toColor = toLineColor + t * (toFillColor - toLineColor);
return mix(color, toColor, float(distance(color, fromColor) < 0.01));
}
}
return color;
}
`;
}

/** class PriorityEntry
* It provides an entry type for priority queues.
* Higher is the value of nPriority higher is the priority of the created entry.
Expand Down
11 changes: 8 additions & 3 deletions browser/src/slideshow/transition/ClippingTransition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,13 @@ class ClippingTransition extends Transition2d {
return (c - 0.5) * s + 0.5;
}
${!isSlideTransition
? `
${GlHelpers.nearestPointOnSegment}
${GlHelpers.computeColor}
`
: ''}
void main() {
// reverse direction / mode out ?
float progress = ${
Expand All @@ -162,9 +169,7 @@ class ClippingTransition extends Transition2d {
vec4 color2 = texture(enteringSlideTexture, v_texCoord);
${!isSlideTransition
? `
color2 = mix(mix(color2, toLineColor, float(distance(color2, fromLineColor) < 0.03)),
toFillColor,
float(distance(color2, fromFillColor) < 0.03));
color2 = computeColor(color2);
color2 *= alpha;
`
: ''}
Expand Down

0 comments on commit 5e8fced

Please sign in to comment.