module Render.Unlit.Sprite.Code
  ( vert
  , frag
  ) where

import RIO

import Render.Code (Code, glsl)
import Render.DescSets.Set0.Code (set0binding0, set0binding1, set0binding2)

vert :: Code
vert :: Code
vert = forall a. IsString a => String -> a
fromString
  [glsl|
    #version 450

    ${set0binding0}

    layout(location = 0) in  vec4 iVert;
    layout(location = 1) in  vec4 iFrag;
    layout(location = 2) in  vec4 iTint;
    layout(location = 3) in  vec4 iOutline;
    layout(location = 4) in  vec4 iAnimation;
    layout(location = 5) in uvec2 iTextureSize;
    layout(location = 6) in ivec2 iTextureIds;

    layout(location = 0)      out  vec2 fTexCoord;
    layout(location = 1) flat out  vec4 fTint;
    layout(location = 2) flat out  vec4 fOutline;
    layout(location = 3) flat out  vec2 fStepSize;
    layout(location = 4) flat out ivec2 fTextureIds;

    vec2 positions[6] = vec2[](
      vec2(-0.5, -0.5),
      vec2(0.5, -0.5),
      vec2(-0.5, 0.5),

      vec2(0.5, 0.5),
      vec2(-0.5, 0.5),
      vec2(0.5, -0.5)
    );

    vec2 texCoords[6] = vec2[](
      vec2(0.0, 0.0),
      vec2(1.0, 0.0),
      vec2(0.0, 1.0),

      vec2(1.0, 1.0),
      vec2(0.0, 1.0),
      vec2(1.0, 0.0)
    );

    void main() {
      // pass-through
      fTint = iTint;
      fOutline = iOutline;
      fTextureIds = iTextureIds;
      fStepSize = 1.0 / vec2(iTextureSize);

      vec2 pos = positions[gl_VertexIndex];

      gl_Position
        = scene.projection
        * scene.view
        * vec4(iVert.xy + pos * iVert.zw, 0, 1.0);

      vec2 uv = texCoords[gl_VertexIndex];
      fTexCoord = iFrag.xy + uv * iFrag.zw;

      float time = 0;
      float frame = 0;
      if (iAnimation[0] > 1) {
        time = scene.tweaks.a + iAnimation[3];
        frame = mod(trunc(time * iAnimation[1]), iAnimation[0]) - 1.0;
        fTexCoord +=
          vec2(
            frame * iFrag.z + frame * iAnimation[2] / float(iTextureSize.x),
            0
          );
      }
    }
  |]

frag :: Code
frag :: Code
frag = forall a. IsString a => String -> a
fromString
  [glsl|
    #version 450
    #extension GL_EXT_nonuniform_qualifier : enable

    ${set0binding1}
    ${set0binding2}

    layout(location = 0)      in  vec2 fTexCoord;
    layout(location = 1) flat in  vec4 fTint;
    layout(location = 2) flat in  vec4 fOutline;
    layout(location = 3) flat in  vec2 fStepSize;
    layout(location = 4) flat in ivec2 fTextureIds;

    layout(location = 0) out vec4 outColor;

    layout(constant_id=0) const float discardAlpha = 0.0;
    layout(constant_id=1) const bool  doOutline = false;

    vec4 tap(vec2 uv) {
      return textureLod(
        sampler2D(
          textures[nonuniformEXT(fTextureIds.t)],
          samplers[nonuniformEXT(fTextureIds.s)]
        ),
        fTexCoord + uv,
        0
      );
    }

    void main() {
      vec4 texel = tap(vec2(0));

      if (discardAlpha != 0.0) {
        if (texel.a < discardAlpha) {
          discard;
        }
      }

      outColor = texel * fTint * texel.a;

      if (doOutline) {
        if (fOutline.a > 0.0 && texel.a < 1.0) {
          float alpha = 0.0;

          alpha += tap(vec2(fStepSize.x,  0.0)         ).a / 4.0;
          alpha += tap(vec2(-fStepSize.x, 0.0)         ).a / 4.0;
          alpha += tap(vec2(0.0,          fStepSize.y) ).a / 4.0;
          alpha += tap(vec2(0.0,          -fStepSize.y)).a / 4.0;

          outColor += fOutline * alpha;
        }
      }
    }
  |]