//////////////////////////////////////////////////////////// //~ Rects ////////////////////////////// //- Vertex shader ImplVertexShader(UI_DRectVS, UI_DRectPSInput) { UI_GpuParams params = G_SDeref(UI_GpuConst_Params)[0]; StructuredBuffer rects = G_SDeref(params.rects); UI_GpuRect rect = rects[SV_InstanceID]; Vec2 rect_uv = RectUvFromIdx(SV_VertexID); Vec2 tex_uv = lerp(rect.tex_slice_uv.p0, rect.tex_slice_uv.p1, rect_uv); Vec2 target_pos = lerp(rect.bounds.p0, rect.bounds.p1, rect_uv); UI_DRectPSInput result; { result.sv_position = Vec4(NdcFromPos(target_pos, Vec2(params.target_size).xy), 0, 1); result.base_background_premul = Premul(rect.background_lin); result.base_border_premul = Premul(rect.border_lin); result.tint_premul = Premul(rect.tint_lin); result.debug_premul = Premul(rect.debug_lin); result.rect_uv = rect_uv; result.tex_uv = tex_uv; result.rect = rect; } return result; } ////////////////////////////// //- Pixel shader ImplPixelShader(UI_DRectPS, UI_DRectPSOutput, UI_DRectPSInput input) { UI_GpuParams params = G_SDeref(UI_GpuConst_Params)[0]; SamplerState sampler = G_SDeref(params.sampler); UI_GpuRect rect = input.rect; Vec2 rect_uv = input.rect_uv; Vec2 p = input.sv_position.xy; Vec2 p0 = rect.bounds.p0; Vec2 p1 = rect.bounds.p1; //- Compute rect dist (negative means pixel is inside of rect) f32 rect_dist = min(min(p.x - p0.x, p1.x - p.x), min(p.y - p0.y, p1.y - p.y)); { f32 tl_radius = rect.tl_rounding; f32 tr_radius = rect.tr_rounding; f32 br_radius = rect.br_rounding; f32 bl_radius = rect.bl_rounding; Vec2 tl = Vec2(p0.x + tl_radius, p0.y + tl_radius); Vec2 tr = Vec2(p1.x - tr_radius, p0.y + tr_radius); Vec2 br = Vec2(p1.x - br_radius, p1.y - br_radius); Vec2 bl = Vec2(p0.x + bl_radius, p1.y - bl_radius); if (p.x < tl.x && p.y < tl.y) { rect_dist = min(rect_dist, tl_radius - length(tl - p)); } if (p.x > tr.x && p.y < tr.y) { rect_dist = min(rect_dist, tr_radius - length(tr - p)); } if (p.x > br.x && p.y > br.y) { rect_dist = min(rect_dist, br_radius - length(br - p)); } if (p.x < bl.x && p.y > bl.y) { rect_dist = min(rect_dist, bl_radius - length(bl - p)); } } rect_dist = -rect_dist; f32 rect_dist_fwidth = saturate(fwidth(rect_dist)); bool is_inside = rect_dist < 0; //- Compute background color Vec4 background_premul = 0; if (is_inside) { if (G_IsRefNil(rect.tex)) { background_premul = input.base_background_premul; } else { Texture2D tex = G_VDeref(rect.tex); background_premul = tex.SampleLevel(sampler, input.tex_uv, 0); background_premul.rgb *= background_premul.a; } } //- Compute borer color Vec4 border_premul = input.base_border_premul; //- Compute border dist f32 border_dist = 0; border_dist = abs(rect_dist); if (is_inside) { border_dist -= rect.border_size; } //- Compute anti-aliased border-over-background color Vec4 composite_premul = 0; { f32 smoothness = rect_dist_fwidth * params.aa * 0.5; f32 border_coverage = smoothstep(smoothness, -smoothness, border_dist); composite_premul = lerp(background_premul, border_premul, border_coverage); } //- Finalize Vec4 result = composite_premul * input.tint_premul; if (UI_GpuConst_DebugDraw) { result = input.debug_premul; } UI_DRectPSOutput output; output.sv_target0 = result; return output; } //////////////////////////////////////////////////////////// //~ Blit ////////////////////////////// //- Vertex shader ImplVertexShader(UI_BlitVS, UI_BlitPSInput) { Vec2 uv = RectUvFromIdx(SV_VertexID); UI_BlitPSInput result; result.sv_position = Vec4(NdcFromUv(uv).xy, 0, 1); result.src_uv = uv; return result; } ////////////////////////////// //- Pixel shader ImplPixelShader(UI_BlitPS, UI_BlitPSOutput, UI_BlitPSInput input) { UI_GpuParams params = G_SDeref(UI_GpuConst_Params)[0]; Texture2D tex = G_SDeref(params.target_ro); SamplerState sampler = G_SDeref(params.sampler); Vec2 uv = input.src_uv; Vec4 result = tex.Sample(sampler, uv); UI_BlitPSOutput output; output.sv_target0 = result; return output; }