// slide changes rendered by an SkSL transition shader (gl-transitions "cube")
SkiaShaderCarousel carousel = null;
var topics = new[] { "mountain", "city", "forest", "ocean", "desert", "flower", "street", "architecture" };
var images = topics
.Select(t => $"https://loremflickr.com/600/600/{t}?random=1")
.ToList();
var cube = @"
// Author: gre (gl-transitions), cube
float persp = 0.7;
float unzoom = 0.3;
float reflection = 0.4;
float floating = 3.0;
vec2 project (vec2 p) {
return p * vec2(1.0, -1.2) + vec2(0.0, -floating/100.);
}
bool inBounds (vec2 p) {
return all(lessThan(vec2(0.0), p)) && all(lessThan(p, vec2(1.0)));
}
vec4 bgColor (vec2 p, vec2 pfr, vec2 pto) {
vec4 c = vec4(0.0, 0.0, 0.0, 1.0);
pfr = project(pfr);
if (inBounds(pfr)) {
c += mix(vec4(0.0), getToColor(pfr), reflection * mix(1.0, 0.0, pfr.y));
}
pto = project(pto);
if (inBounds(pto)) {
c += mix(vec4(0.0), getFromColor(pto), reflection * mix(1.0, 0.0, pto.y));
}
return c;
}
vec2 xskew (vec2 p, float persp, float center) {
float x = mix(p.x, 1.0-p.x, center);
return (
(
vec2( x, (p.y - 0.5*(1.0-persp) * x) / (1.0+(persp-1.0)*x) )
- vec2(0.5-distance(center, 0.5), 0.0)
)
* vec2(0.5 / distance(center, 0.5) * (center<0.5 ? 1.0 : -1.0), 1.0)
+ vec2(center<0.5 ? 0.0 : 1.0, 0.0)
);
}
vec4 transition(vec2 op) {
float invProgress = 1.0 - progress;
float uz = unzoom * 2.0*(0.5-distance(0.5, invProgress));
vec2 p = -uz*0.5+(1.0+uz) * op;
vec2 fromP = xskew(
(p - vec2(invProgress, 0.0)) / vec2(1.0-invProgress, 1.0),
1.0-mix(invProgress, 0.0, persp),
0.0
);
vec2 toP = xskew(
p / vec2(invProgress, 1.0),
mix(pow(invProgress, 2.0), 1.0, persp),
1.0
);
if (inBounds(fromP)) {
return getToColor(fromP);
}
else if (inBounds(toP)) {
return getFromColor(toP);
}
return bgColor(op, fromP, toP);
}
half4 main(float2 fragCoord) {
float2 normCoord = (fragCoord - iOffset) / iResolution;
normCoord.y = 1.0 - normCoord.y;
return transition(normCoord);
}";
return new SkiaStack
{
Spacing = 12,
Padding = new Thickness(16),
VerticalOptions = LayoutOptions.Center,
Children =
{
new SkiaShaderCarousel
{
IsLooped = true,
LinearSpeedMs = 750,
TransitionShaderCode = cube,
HeightRequest = 340,
WidthRequest=600,
HorizontalOptions = LayoutOptions.Center,
BackgroundColor = Colors.Black,
ItemsSource = images,
ItemTemplate = new DataTemplate(() =>
{
SkiaImage img = null;
var cell = new SkiaLayer
{
UseCache = SkiaCacheType.Image, // the shader samples this cell cache
BackgroundColor = Colors.Black,
Children =
{
new SkiaImage
{
Aspect = TransformAspect.AspectCover,
LoadSourceOnFirstDraw = false,
HorizontalOptions = LayoutOptions.Fill,
VerticalOptions = LayoutOptions.Fill,
}.Assign(out img),
}
};
return cell.ObserveSelf((me, prop) =>
{
if (prop == nameof(me.BindingContext))
img.Source = me.BindingContext as string;
});
}),
}.Assign(out carousel),
new SkiaRow
{
Spacing = 12,
HorizontalOptions = LayoutOptions.Center,
Children =
{
new SkiaButton("👈 Prev").OnTapped(me => carousel.GoPrev()),
new SkiaButton("Next 👉").OnTapped(me => carousel.GoNext()),
}
},
new SkiaLabel("Easily use `SkiaShaderCarousel` for transitions, use your own shader!")
{
FontSize = 13,
TextColor = Color.FromHex("#94A3B8"),
HorizontalOptions = LayoutOptions.Center,
},
}
};