///|
fn advanced_layer_vertices(
size : @core.Size,
layer : NativeLayerRun,
) -> Array[AdvancedVertex] {
let frame = match layer.mask {
Some(mask) => mask.rect
None => @core.Rect::new(x=0.0, y=0.0, width=size.width, height=size.height)
}
let mask_radius = match layer.mask {
Some(mask) => if mask.rounded { mask.radius } else { 0.0 }
None => 0.0
}
let mask_kind = match layer.mask {
Some(mask) => if mask.rounded { 1.0 } else { 0.0 }
None => 0.0
}
advanced_rect_vertices(
size,
frame,
opacity=layer.opacity,
blend_mode=layer.blend_mode,
shader_kind=0.0,
effect_amount=0.0,
filter=layer.filter,
color0=@core.Color::white(),
color1=@core.Color::white(),
uv_rect=Some(frame),
mask_radius~,
mask_kind~,
)
}
///|
fn advanced_rect_vertices(
size : @core.Size,
rect : @core.Rect,
opacity~ : Double,
blend_mode~ : @core.BlendMode,
shader_kind~ : Double,
effect_amount~ : Double,
filter~ : @core.FilterEffect?,
color0~ : @core.Color,
color1~ : @core.Color,
uv_rect? : @core.Rect? = None,
mask_radius? : Double = 0.0,
mask_kind? : Double = 0.0,
transform? : @core.Transform2D = @core.Transform2D::identity(),
) -> Array[AdvancedVertex] {
let vertices : Array[AdvancedVertex] = []
let x0 = rect.origin.x
let y0 = rect.origin.y
let x1 = rect.origin.x + rect.size.width
let y1 = rect.origin.y + rect.size.height
let uv0 = advanced_uv_for_point(size, uv_rect, x0, y0, 0.0, 0.0)
let uv1 = advanced_uv_for_point(size, uv_rect, x0, y1, 0.0, 1.0)
let uv2 = advanced_uv_for_point(size, uv_rect, x1, y1, 1.0, 1.0)
let uv3 = advanced_uv_for_point(size, uv_rect, x1, y0, 1.0, 0.0)
push_advanced_vertex(
vertices,
size,
rect,
x0,
y0,
uv0.x,
uv0.y,
opacity~,
blend_mode~,
shader_kind~,
effect_amount~,
filter~,
color0~,
color1~,
mask_radius~,
mask_kind~,
transform~,
)
push_advanced_vertex(
vertices,
size,
rect,
x0,
y1,
uv1.x,
uv1.y,
opacity~,
blend_mode~,
shader_kind~,
effect_amount~,
filter~,
color0~,
color1~,
mask_radius~,
mask_kind~,
transform~,
)
push_advanced_vertex(
vertices,
size,
rect,
x1,
y1,
uv2.x,
uv2.y,
opacity~,
blend_mode~,
shader_kind~,
effect_amount~,
filter~,
color0~,
color1~,
mask_radius~,
mask_kind~,
transform~,
)
push_advanced_vertex(
vertices,
size,
rect,
x0,
y0,
uv0.x,
uv0.y,
opacity~,
blend_mode~,
shader_kind~,
effect_amount~,
filter~,
color0~,
color1~,
mask_radius~,
mask_kind~,
transform~,
)
push_advanced_vertex(
vertices,
size,
rect,
x1,
y1,
uv2.x,
uv2.y,
opacity~,
blend_mode~,
shader_kind~,
effect_amount~,
filter~,
color0~,
color1~,
mask_radius~,
mask_kind~,
transform~,
)
push_advanced_vertex(
vertices,
size,
rect,
x1,
y0,
uv3.x,
uv3.y,
opacity~,
blend_mode~,
shader_kind~,
effect_amount~,
filter~,
color0~,
color1~,
mask_radius~,
mask_kind~,
transform~,
)
vertices
}
///|
fn advanced_uv_for_point(
size : @core.Size,
uv_rect : @core.Rect?,
x : Double,
y : Double,
fallback_u : Double,
fallback_v : Double,
) -> @core.Point {
match uv_rect {
Some(_) =>
@core.Point::new(
x=x / size.width.max(0.0001),
y=y / size.height.max(0.0001),
)
None => @core.Point::new(x=fallback_u, y=fallback_v)
}
}
///|
fn push_advanced_vertex(
vertices : Array[AdvancedVertex],
size : @core.Size,
rect : @core.Rect,
x : Double,
y : Double,
u : Double,
v : Double,
opacity~ : Double,
blend_mode~ : @core.BlendMode,
shader_kind~ : Double,
effect_amount~ : Double,
filter~ : @core.FilterEffect?,
color0~ : @core.Color,
color1~ : @core.Color,
mask_radius~ : Double,
mask_kind~ : Double,
transform~ : @core.Transform2D,
) -> Unit {
let transformed = transform_point(transform, x, y)
let filter_payload = native_filter_payload(filter)
vertices.push({
x: visual_pixel_x_to_ndc(transformed.x, size.width),
y: visual_pixel_y_to_ndc(transformed.y, size.height),
u,
v,
opacity: clamp_opacity(opacity),
blend_mode: native_blend_mode_code(blend_mode),
shader_kind,
effect_amount,
local_x: (x - rect.origin.x) / rect.size.width.max(0.0001),
local_y: (y - rect.origin.y) / rect.size.height.max(0.0001),
filter_kind: filter_payload.kind,
filter_amount: filter_payload.amount,
r0: color0.r,
g0: color0.g,
b0: color0.b,
a0: color0.a,
r1: color1.r,
g1: color1.g,
b1: color1.b,
a1: color1.a,
matrix: filter_payload.matrix,
rect_width: rect.size.width.max(0.0),
rect_height: rect.size.height.max(0.0),
mask_radius: mask_radius.max(0.0),
mask_kind,
})
}
///|
priv struct NativeFilterPayload {
kind : Double
amount : Double
matrix : Array[Double]
}
///|
fn native_filter_payload(filter : @core.FilterEffect?) -> NativeFilterPayload {
match filter {
Some(@core.FilterEffect::Blur(radius)) =>
{
kind: 1.0,
amount: radius.max(0.0),
matrix: native_identity_color_matrix(),
}
Some(@core.FilterEffect::Saturate(amount)) =>
{ kind: 2.0, amount, matrix: native_identity_color_matrix() }
Some(@core.FilterEffect::Brightness(amount)) =>
{ kind: 3.0, amount, matrix: native_identity_color_matrix() }
Some(@core.FilterEffect::Contrast(amount)) =>
{ kind: 4.0, amount, matrix: native_identity_color_matrix() }
Some(@core.FilterEffect::ColorMatrix(values)) =>
{ kind: 5.0, amount: 1.0, matrix: native_color_matrix(values) }
None => { kind: 0.0, amount: 0.0, matrix: native_identity_color_matrix() }
}
}
///|
fn native_identity_color_matrix() -> Array[Double] {
[
1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0,
0.0, 0.0, 0.0, 0.0,
]
}
///|
fn native_color_matrix(values : Array[Double]) -> Array[Double] {
let matrix = native_identity_color_matrix()
let count = values.length().min(20)
for index in 0.. Double {
match mode {
@core.BlendMode::SourceOver => 0.0
@core.BlendMode::Multiply => 1.0
@core.BlendMode::Screen => 2.0
@core.BlendMode::Overlay => 3.0
@core.BlendMode::Darken => 4.0
@core.BlendMode::Lighten => 5.0
}
}
///|
fn native_shader_kind(name : String) -> Double {
match name {
"checker" => 1.0
"solid" => 2.0
"linear-gradient-debug" => 3.0
"vignette" => 4.0
_ => 5.0
}
}
///|
fn native_shader_effect_amount(effect : NativeShaderEffectRun) -> Double {
match effect.uniforms.get(0) {
Some(value) => value
None => 8.0
}
}
///|
fn native_shader_effect_colors(
effect : NativeShaderEffectRun,
) -> (@core.Color, @core.Color) {
match effect.fallback {
@core.Brush::Solid(color) => (color, color)
@core.Brush::LinearGradient(gradient) =>
(gradient.start_color, gradient.end_color)
@core.Brush::RadialGradient(gradient) =>
(gradient.center_color, gradient.edge_color)
}
}