Major rework to draw rendering system. We are making a SDF first rendering system with tesselated stuff only as a fallback strategy for specific situations where SDF is particularly poorly suited Co-authored-by: Zachary Levy <zachary@sunforge.is> Reviewed-on: #17
248 lines
7.5 KiB
Metal
248 lines
7.5 KiB
Metal
#pragma clang diagnostic ignored "-Wmissing-prototypes"
|
|
|
|
#include <metal_stdlib>
|
|
#include <simd/simd.h>
|
|
|
|
using namespace metal;
|
|
|
|
// Implementation of the GLSL mod() function, which is slightly different than Metal fmod()
|
|
template<typename Tx, typename Ty>
|
|
inline Tx mod(Tx x, Ty y)
|
|
{
|
|
return x - y * floor(x / y);
|
|
}
|
|
|
|
struct main0_out
|
|
{
|
|
float4 out_color [[color(0)]];
|
|
};
|
|
|
|
struct main0_in
|
|
{
|
|
float4 f_color [[user(locn0)]];
|
|
float2 f_local_or_uv [[user(locn1)]];
|
|
float4 f_params [[user(locn2)]];
|
|
float4 f_params2 [[user(locn3)]];
|
|
uint f_flags [[user(locn4)]];
|
|
uint f_rotation_sc [[user(locn5)]];
|
|
uint4 f_uv_or_effects [[user(locn6)]];
|
|
};
|
|
|
|
static inline __attribute__((always_inline))
|
|
float sdRoundedBox(thread const float2& p, thread const float2& b, thread const float4& r)
|
|
{
|
|
float2 _48;
|
|
if (p.x > 0.0)
|
|
{
|
|
_48 = r.xy;
|
|
}
|
|
else
|
|
{
|
|
_48 = r.zw;
|
|
}
|
|
float2 rxy = _48;
|
|
float _62;
|
|
if (p.y > 0.0)
|
|
{
|
|
_62 = rxy.x;
|
|
}
|
|
else
|
|
{
|
|
_62 = rxy.y;
|
|
}
|
|
float rr = _62;
|
|
float2 q = abs(p) - b;
|
|
if (rr == 0.0)
|
|
{
|
|
return fast::max(q.x, q.y);
|
|
}
|
|
q += float2(rr);
|
|
return (fast::min(fast::max(q.x, q.y), 0.0) + length(fast::max(q, float2(0.0)))) - rr;
|
|
}
|
|
|
|
static inline __attribute__((always_inline))
|
|
float sdRegularPolygon(thread const float2& p, thread const float& r, thread const float& n)
|
|
{
|
|
float an = 3.1415927410125732421875 / n;
|
|
float bn = mod(precise::atan2(p.y, p.x), 2.0 * an) - an;
|
|
return (length(p) * cos(bn)) - r;
|
|
}
|
|
|
|
static inline __attribute__((always_inline))
|
|
float sdEllipseApprox(thread const float2& p, thread const float2& ab)
|
|
{
|
|
float k0 = length(p / ab);
|
|
float k1 = length(p / (ab * ab));
|
|
return (k0 * (k0 - 1.0)) / k1;
|
|
}
|
|
|
|
static inline __attribute__((always_inline))
|
|
float4 gradient_2color(thread const float4& start_color, thread const float4& end_color, thread const float& t)
|
|
{
|
|
return mix(start_color, end_color, float4(fast::clamp(t, 0.0, 1.0)));
|
|
}
|
|
|
|
static inline __attribute__((always_inline))
|
|
float sdf_alpha(thread const float& d, thread const float& h)
|
|
{
|
|
return 1.0 - smoothstep(-h, h, d);
|
|
}
|
|
|
|
fragment main0_out main0(main0_in in [[stage_in]], texture2d<float> tex [[texture(0)]], sampler texSmplr [[sampler(0)]])
|
|
{
|
|
main0_out out = {};
|
|
uint kind = in.f_flags & 255u;
|
|
uint flags = (in.f_flags >> 8u) & 255u;
|
|
if (kind == 0u)
|
|
{
|
|
float4 t = tex.sample(texSmplr, in.f_local_or_uv);
|
|
float _195 = t.w;
|
|
float4 _197 = t;
|
|
float3 _199 = _197.xyz * _195;
|
|
t.x = _199.x;
|
|
t.y = _199.y;
|
|
t.z = _199.z;
|
|
out.out_color = in.f_color * t;
|
|
return out;
|
|
}
|
|
float d = 1000000015047466219876688855040.0;
|
|
float h = 0.5;
|
|
float2 half_size = in.f_params.xy;
|
|
float2 p_local = in.f_local_or_uv;
|
|
if ((flags & 16u) != 0u)
|
|
{
|
|
float2 sc = float2(as_type<half2>(in.f_rotation_sc));
|
|
p_local = float2((sc.y * p_local.x) + (sc.x * p_local.y), ((-sc.x) * p_local.x) + (sc.y * p_local.y));
|
|
}
|
|
if (kind == 1u)
|
|
{
|
|
float4 corner_radii = float4(in.f_params.zw, in.f_params2.xy);
|
|
h = in.f_params2.z;
|
|
float2 param = p_local;
|
|
float2 param_1 = half_size;
|
|
float4 param_2 = corner_radii;
|
|
d = sdRoundedBox(param, param_1, param_2);
|
|
}
|
|
else
|
|
{
|
|
if (kind == 2u)
|
|
{
|
|
float radius = in.f_params.x;
|
|
float sides = in.f_params.y;
|
|
h = in.f_params.z;
|
|
float2 param_3 = p_local;
|
|
float param_4 = radius;
|
|
float param_5 = sides;
|
|
d = sdRegularPolygon(param_3, param_4, param_5);
|
|
half_size = float2(radius);
|
|
}
|
|
else
|
|
{
|
|
if (kind == 3u)
|
|
{
|
|
float2 ab = in.f_params.xy;
|
|
h = in.f_params.z;
|
|
float2 param_6 = p_local;
|
|
float2 param_7 = ab;
|
|
d = sdEllipseApprox(param_6, param_7);
|
|
half_size = ab;
|
|
}
|
|
else
|
|
{
|
|
if (kind == 4u)
|
|
{
|
|
float inner = in.f_params.x;
|
|
float outer = in.f_params.y;
|
|
float2 n_start = in.f_params.zw;
|
|
float2 n_end = in.f_params2.xy;
|
|
uint arc_bits = (flags >> 5u) & 3u;
|
|
h = in.f_params2.z;
|
|
float r = length(p_local);
|
|
d = fast::max(inner - r, r - outer);
|
|
if (arc_bits != 0u)
|
|
{
|
|
float d_start = dot(p_local, n_start);
|
|
float d_end = dot(p_local, n_end);
|
|
float _372;
|
|
if (arc_bits == 1u)
|
|
{
|
|
_372 = fast::max(d_start, d_end);
|
|
}
|
|
else
|
|
{
|
|
_372 = fast::min(d_start, d_end);
|
|
}
|
|
float d_wedge = _372;
|
|
d = fast::max(d, d_wedge);
|
|
}
|
|
half_size = float2(outer);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
float grad_magnitude = fast::max(fwidth(d), 9.9999999747524270787835121154785e-07);
|
|
d /= grad_magnitude;
|
|
h /= grad_magnitude;
|
|
float4 shape_color;
|
|
if ((flags & 2u) != 0u)
|
|
{
|
|
float4 gradient_start = in.f_color;
|
|
float4 gradient_end = unpack_unorm4x8_to_float(in.f_uv_or_effects.x);
|
|
if ((flags & 4u) != 0u)
|
|
{
|
|
float t_1 = length(p_local / half_size);
|
|
float4 param_8 = gradient_start;
|
|
float4 param_9 = gradient_end;
|
|
float param_10 = t_1;
|
|
shape_color = gradient_2color(param_8, param_9, param_10);
|
|
}
|
|
else
|
|
{
|
|
float2 direction = float2(as_type<half2>(in.f_uv_or_effects.z));
|
|
float t_2 = (dot(p_local / half_size, direction) * 0.5) + 0.5;
|
|
float4 param_11 = gradient_start;
|
|
float4 param_12 = gradient_end;
|
|
float param_13 = t_2;
|
|
shape_color = gradient_2color(param_11, param_12, param_13);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ((flags & 1u) != 0u)
|
|
{
|
|
float4 uv_rect = as_type<float4>(in.f_uv_or_effects);
|
|
float2 local_uv = ((p_local / half_size) * 0.5) + float2(0.5);
|
|
float2 uv = mix(uv_rect.xy, uv_rect.zw, local_uv);
|
|
shape_color = in.f_color * tex.sample(texSmplr, uv);
|
|
}
|
|
else
|
|
{
|
|
shape_color = in.f_color;
|
|
}
|
|
}
|
|
if ((flags & 8u) != 0u)
|
|
{
|
|
float4 ol_color = unpack_unorm4x8_to_float(in.f_uv_or_effects.y);
|
|
float ol_width = float2(as_type<half2>(in.f_uv_or_effects.w)).x / grad_magnitude;
|
|
float param_14 = d;
|
|
float param_15 = h;
|
|
float fill_cov = sdf_alpha(param_14, param_15);
|
|
float param_16 = d - ol_width;
|
|
float param_17 = h;
|
|
float total_cov = sdf_alpha(param_16, param_17);
|
|
float outline_cov = fast::max(total_cov - fill_cov, 0.0);
|
|
float3 rgb_pm = ((shape_color.xyz * shape_color.w) * fill_cov) + ((ol_color.xyz * ol_color.w) * outline_cov);
|
|
float alpha_pm = (shape_color.w * fill_cov) + (ol_color.w * outline_cov);
|
|
out.out_color = float4(rgb_pm, alpha_pm);
|
|
}
|
|
else
|
|
{
|
|
float param_18 = d;
|
|
float param_19 = h;
|
|
float alpha = sdf_alpha(param_18, param_19);
|
|
out.out_color = float4((shape_color.xyz * shape_color.w) * alpha, shape_color.w * alpha);
|
|
}
|
|
return out;
|
|
}
|
|
|