cbuffer CmdGlobals : register(b0)
{
  float2 viewport_size_px;
  float2 albedo_t2d_size_px;
  row_major float3x3 transform;
}

Texture2D albedo_t2d : register(t0);
SamplerState albedo_t2d_sampler : register(s0);

struct CPU2Vertex
{
  float4 dst_rect_px     : POS; // Here we have two sets of 2D points, first is the top left corner of the rectnagle, and second is the bottom right corner.
  float4 src_rect_px     : TEX;
  float4 color00         : COL0;
  float4 color01         : COL1;
  float4 color10         : COL2;
  float4 color11         : COL3;
  float4 corner_radii_px : CRAD;
  float4 style_params    : STY; // border_thickness_px, softness_px, omit_texture, unused
  uint vertex_id         : SV_VertexID;
};

struct Vertex2Pixel
{
  float4 position           : SV_POSITION;
  float2 rect_half_size_px  : PSIZE;
  float2 texcoord_pct       : TEX;
  float2 cornercoord_pct    : CORC;
  float4 color00            : COL0;
  float4 color01            : COL1;
  float4 color10            : COL2;
  float4 color11            : COL3;
  float corner_radius_px    : CRAD;
  float border_thickness_px : BTHC;
  float softness_px         : SFT;
  float omit_texture        : OTX;
};

//- Helpers

float rect_SDF(float2 sample_pos, float2 rect_half_size, float radius)
{
  return length(max(abs(sample_pos) - rect_half_size + radius, 0.0)) - radius;
}

//~ Vertex shader
Vertex2Pixel 
vs_main(CPU2Vertex cpu2vertex) 
{
  // Here we statically define the vertex as a rectangle over the entire NDC space [-1, 1] for x and y, I think?
  // From debugging in RenderDoc I can confirm that -1,-1 is top left corner, and 1,1 bottom right corner.
  // Then we can use the input data to scale these points to get proper screen space vertex coordinates for what we want to render.
  static float2 vertices[] = 
  {
    {-1, -1},
    {-1, +1},
    {+1, -1},
    {+1, +1},
  };
  
  // Unpack input
  float2 dst_p0_px   = cpu2vertex.dst_rect_px.xy; // top left corner
  float2 dst_p1_px   = cpu2vertex.dst_rect_px.zw; // bottom right corner
  float2 src_p0_px   = cpu2vertex.src_rect_px.xy;
  float2 src_p1_px   = cpu2vertex.src_rect_px.zw;
  float2 dst_size_px = abs(dst_p1_px - dst_p0_px); 
  
  // unpack style
  float border_thickness_px = cpu2vertex.style_params.x;
  float softness_px         = cpu2vertex.style_params.y;
  float omit_texture        = cpu2vertex.style_params.z;

  // Transform input points to screen destination coordinates
  float2 dst_half_size = (dst_p1_px - dst_p0_px) / 2;
  float2 dst_center = (dst_p1_px + dst_p0_px) / 2;
  // transform the vertex according to the input points
  float2 dst_pos = (vertices[cpu2vertex.vertex_id] * dst_half_size + dst_center);

  // Swap y-coordinate to have -1,-1 in top left
  dst_pos.y = viewport_size_px.y - dst_pos.y;

  float2 src_pos[] = 
  {
    float2(src_p0_px.x/albedo_t2d_size_px.x, src_p0_px.y/albedo_t2d_size_px.y),
    float2(src_p0_px.x/albedo_t2d_size_px.x, src_p1_px.y/albedo_t2d_size_px.y),
    float2(src_p1_px.x/albedo_t2d_size_px.x, src_p0_px.y/albedo_t2d_size_px.y),
    float2(src_p1_px.x/albedo_t2d_size_px.x, src_p1_px.y/albedo_t2d_size_px.y),
  };
  
  float2 dst_c_verts_pct[] = 
  {
    float2(0, 0),
    float2(0, 1),
    float2(1, 0),
    float2(1, 1),
  };
  
  float dst_r_verts_px[] =
  {
    cpu2vertex.corner_radii_px.x,
    cpu2vertex.corner_radii_px.y,
    cpu2vertex.corner_radii_px.z,
    cpu2vertex.corner_radii_px.w,
  };
     
  // Package output
  Vertex2Pixel vertex2pixel;
  {
    vertex2pixel.position.x          = 2 * dst_pos.x / viewport_size_px.x - 1.f;
    vertex2pixel.position.y          = 2 * dst_pos.y / viewport_size_px.y - 1.f;
    vertex2pixel.position.z          = 0.f;
    vertex2pixel.position.w          = 1.f;
    vertex2pixel.rect_half_size_px   = dst_size_px/2.0f;
    vertex2pixel.texcoord_pct.x      = src_pos[cpu2vertex.vertex_id].x;
    vertex2pixel.texcoord_pct.y      = src_pos[cpu2vertex.vertex_id].y;
    vertex2pixel.cornercoord_pct     = dst_c_verts_pct[cpu2vertex.vertex_id];
    vertex2pixel.color00             = cpu2vertex.color00;
    vertex2pixel.color01             = cpu2vertex.color01;
    vertex2pixel.color10             = cpu2vertex.color10;
    vertex2pixel.color11             = cpu2vertex.color11;
    vertex2pixel.corner_radius_px    = dst_r_verts_px[cpu2vertex.vertex_id];
    vertex2pixel.border_thickness_px = border_thickness_px;
    vertex2pixel.softness_px         = softness_px;
    vertex2pixel.omit_texture        = omit_texture;
  }
  return vertex2pixel;
}

//~ Pixel shader
float4
ps_main(Vertex2Pixel vertex2pixel) : SV_TARGET
{
  float4 top_color = (1 - vertex2pixel.cornercoord_pct.x)*vertex2pixel.color00 + (vertex2pixel.cornercoord_pct.x)*vertex2pixel.color10;
  float4 bot_color = (1 - vertex2pixel.cornercoord_pct.x)*vertex2pixel.color01 + (vertex2pixel.cornercoord_pct.x)*vertex2pixel.color11;
  float4 tint      = (1 - vertex2pixel.cornercoord_pct.y)*top_color + (vertex2pixel.cornercoord_pct.y)*bot_color;
  
  float4 albedo_sample = float4(1, 1, 1, 1);
  albedo_sample = albedo_t2d.Sample(albedo_t2d_sampler, vertex2pixel.texcoord_pct) * albedo_sample;  
  
  
  // Corners
  float2 sdf_sample_pos = float2(
                                 (2*vertex2pixel.cornercoord_pct.x - 1)*vertex2pixel.rect_half_size_px.x,
                                 (2*vertex2pixel.cornercoord_pct.y - 1)*vertex2pixel.rect_half_size_px.y
                                 );
  
  float2 half_size = vertex2pixel.rect_half_size_px - float2(vertex2pixel.softness_px*2.f, vertex2pixel.softness_px*2.f);
  float corner_sdf_s = rect_SDF(sdf_sample_pos, half_size, vertex2pixel.corner_radius_px);
  float corner_sdf_t = 1-smoothstep(0, 2*vertex2pixel.softness_px, corner_sdf_s);
  
  // Borders
  float border_radius = max(vertex2pixel.corner_radius_px-vertex2pixel.border_thickness_px, 0);
  float border_sdf_s = rect_SDF(sdf_sample_pos, half_size - vertex2pixel.border_thickness_px, border_radius);
  float border_sdf_t = smoothstep(0, 2*vertex2pixel.softness_px, border_sdf_s);
  
  if(vertex2pixel.border_thickness_px == 0)
  {
    border_sdf_t = 1;
  }
  
  float4 final_color = float4(1, 1, 1, 1);
  final_color *= tint;
  final_color *= corner_sdf_t;
  final_color *= border_sdf_t;
  if(vertex2pixel.omit_texture < 1)
  {
    final_color = float4(1, 1, 1, albedo_sample.r);
  }
  //float4 final_color = vertex2pixel.color;
  return final_color;
}

