Skip to content

Commit

Permalink
feat(composition): Implement CrossFadeEffect + Sample
Browse files Browse the repository at this point in the history
  • Loading branch information
ahmed605 committed Mar 2, 2024
1 parent 85b301b commit c290e67
Show file tree
Hide file tree
Showing 3 changed files with 138 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,6 @@
<Grid x:Name="opacityGrid" Width="200" Height="200" VerticalAlignment="Top" HorizontalAlignment="Left" ToolTipService.ToolTip="OpacityEffect"/>
<Grid x:Name="contrastGrid" Width="200" Height="200" VerticalAlignment="Top" HorizontalAlignment="Left" ToolTipService.ToolTip="ContrastEffect"/>
<Grid x:Name="exposureGrid" Width="200" Height="200" VerticalAlignment="Top" HorizontalAlignment="Left" ToolTipService.ToolTip="ExposureEffect (Negative Value, -1)"/>
<Grid x:Name="crossfadeGrid" Width="200" Height="200" VerticalAlignment="Top" HorizontalAlignment="Left" ToolTipService.ToolTip="CrossFadeEffect"/>
</GridView>
</UserControl>
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,21 @@ private void EffectBrushTests_Loaded(object sender, RoutedEventArgs e)
var effectBrush12 = factory12.CreateBrush();

exposureGrid.Background = new EffectTesterBrush(effectBrush12);

var surface2 = LoadedImageSurface.StartLoadFromUri(new Uri("https://user-images.githubusercontent.com/34550324/266135095-71c9ce0a-4e49-408f-b2ff-670a53adef10.png"));
surface2.LoadCompleted += (s, o) =>
{
if (o.Status == LoadedImageSourceLoadStatus.Success)
{
var brush = compositor.CreateSurfaceBrush(surface2);

var effect13 = new SimpleCrossfadeEffect() { Source1 = new CompositionEffectSourceParameter("sourceBrush"), Source2 = new CompositionEffectSourceParameter("secondaryBrush"), CrossFade = 0.5f };
var factory13 = compositor.CreateEffectFactory(effect13);
var effectBrush13 = factory13.CreateBrush();

crossfadeGrid.Background = new EffectTesterBrushWithSecondaryBrush(effectBrush13, brush);
}
};
#endif
}

Expand Down Expand Up @@ -731,6 +746,63 @@ public object GetProperty(uint index)
public IGraphicsEffectSource GetSource(uint index) => Source;
public uint GetSourceCount() => 1;
}

[Guid("12F575E8-4DB1-485F-9A84-03A07DD3829F")]
private class SimpleCrossfadeEffect : IGraphicsEffect, IGraphicsEffectSource, IGraphicsEffectD2D1Interop
{
private string _name = "SimpleCrossfadeEffect";
private Guid _id = new Guid("12F575E8-4DB1-485F-9A84-03A07DD3829F");

public string Name
{
get => _name;
set => _name = value;
}

public float CrossFade { get; set; } = 0.5f;

public IGraphicsEffectSource Source1 { get; set; }

public IGraphicsEffectSource Source2 { get; set; }

public Guid GetEffectId() => _id;

public void GetNamedPropertyMapping(string name, out uint index, out GraphicsEffectPropertyMapping mapping)
{
switch (name)
{
case "Weight":
case "CrossFade":
case "Crossfade":
{
index = 0;
mapping = GraphicsEffectPropertyMapping.Direct;
break;
}
default:
{
index = 0xFF;
mapping = (GraphicsEffectPropertyMapping)0xFF;
break;
}
}
}

public object GetProperty(uint index)
{
switch (index)
{
case 0:
return CrossFade;
default:
return null;
}
}

public uint GetPropertyCount() => 1;
public IGraphicsEffectSource GetSource(uint index) => index is 0 ? Source1 : Source2;
public uint GetSourceCount() => 2;
}
#endif
}
}
65 changes: 65 additions & 0 deletions src/Uno.UI.Composition/Composition/CompositionEffectBrush.skia.cs
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,7 @@ half4 main()
if (skMode == (SKBlendMode)0xFF) // Unsupported mode
return null;

// We have to do this manually because SKImageFilter.CreateMerge(SKImageFilter, SKImageFilter, SKBlendMode, SKImageFilter.CropRect) is obsolete.
for (uint idx = 1; idx < effectInterop.GetSourceCount(); idx++)
{
SKImageFilter nextFilter = GenerateEffectFilter(effectInterop.GetSource(idx), bounds);
Expand Down Expand Up @@ -278,6 +279,7 @@ half4 main()
effectInterop.GetNamedPropertyMapping("Opacity", out uint opacityProp, out _);
float opacity = (float)effectInterop.GetProperty(opacityProp);


return SKImageFilter.CreateColorFilter(
SKColorFilter.CreateColorMatrix(
new float[] // Opacity Matrix
Expand Down Expand Up @@ -530,6 +532,69 @@ half4 main()
*/
}

return null;
}
case EffectType.CrossFadeEffect: // TODO: We should use SkColorFilters::Lerp instead once SkiaSharp includes it
{
if (effectInterop.GetSourceCount() == 2 && effectInterop.GetPropertyCount() == 1 && effectInterop.GetSource(0) is IGraphicsEffectSource sourceA && effectInterop.GetSource(1) is IGraphicsEffectSource sourceB)
{
SKImageFilter sourceFilter1 = GenerateEffectFilter(sourceB, bounds);
if (sourceFilter1 is null)
return null;

SKImageFilter sourceFilter2 = GenerateEffectFilter(sourceA, bounds);
if (sourceFilter2 is null)
return null;

effectInterop.GetNamedPropertyMapping("CrossFade", out uint crossfadeProp, out _);

float crossfade = (float)effectInterop.GetProperty(crossfadeProp);

if (crossfade <= 0.0f)
return sourceFilter1;
else if (crossfade >= 1.0f)
return sourceFilter2;

SKImageFilter fbFilter = SKImageFilter.CreateColorFilter(
SKColorFilter.CreateColorMatrix(
new float[]
{
crossfade, 0, 0, 0, 0,
0, crossfade, 0, 0, 0,
0, 0, crossfade, 0, 0,
0, 0, 0, crossfade, 0
}),
sourceFilter2);

string shader = $@"
uniform shader input;
uniform half crossfade;
half4 main()
{{
half4 inputColor = sample(input);
return inputColor - (inputColor * crossfade);
}}
";

SKRuntimeEffect runtimeEffect = SKRuntimeEffect.Create(shader, out string errors);
if (errors is not null)
return null;

SKRuntimeEffectUniforms uniforms = new(runtimeEffect)
{
{ "crossfade", crossfade }
};
SKRuntimeEffectChildren children = new(runtimeEffect)
{
{ "input", null }
};

SKImageFilter amafFilter = SKImageFilter.CreateColorFilter(runtimeEffect.ToColorFilter(uniforms, children), sourceFilter1);

return SKImageFilter.CreateBlendMode(SKBlendMode.Plus, fbFilter, amafFilter, new(bounds));
}

return null;
}
case EffectType.Unsupported:
Expand Down

0 comments on commit c290e67

Please sign in to comment.