module Render.Lit.Colored.Code
  ( vert
  , frag
  ) where

import RIO

import Render.Code (Code, glsl)
import Render.Code.Lit (litMain, shadowFuns, structLight, brdfSpecular)
import Render.DescSets.Set0.Code (set0binding0, set0binding1, set0binding2, set0binding3, set0binding4, set0binding5)

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

    invariant gl_Position;

    ${set0binding0}

    layout(location = 0) in vec3 vPosition;
    layout(location = 1) in vec4 vBaseColor;
    layout(location = 2) in vec4 vEmissiveColor;
    layout(location = 3) in vec2 vMetallicRoughness;
    layout(location = 4) in vec3 vNormal;

    layout(location = 5) in mat4 iModel;

    layout(location = 0) out vec4 fPosition;
    layout(location = 1) out vec4 fColor;
    layout(location = 2) out vec4 fEmissiveColor;
    layout(location = 3) out vec2 fMetallicRoughness;
    layout(location = 4) out vec3 fNormal;

    void main() {
      fPosition = iModel * vec4(vPosition, 1.0);

      gl_Position
        = scene.projection
        * scene.view
        * fPosition;

      fNormal = transpose(mat3(inverse(iModel))) * vNormal; // TODO: use modelInv

      fColor = vBaseColor;
      fColor.rgb *= vBaseColor.a;

      fEmissiveColor = vEmissiveColor;
      fMetallicRoughness = vMetallicRoughness;
    }
  |]

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

    layout(early_fragment_tests) in;

    // TODO: move to spec constant
    const uint MAX_LIGHTS = 255;
    const float PCF_STEP = 1.5 / 4096;

    // TODO: move to material
    const float reflectivity = 1.0/256.0;

    ${structLight}

    ${set0binding0}
    ${set0binding1}
    ${set0binding2}
    ${set0binding3}
    ${set0binding4}
    ${set0binding5}

    layout(location = 0) in vec4 fPosition;
    layout(location = 1) in vec4 fColor;
    layout(location = 2) in vec4 fEmissiveColor;
    layout(location = 3) in vec2 fMetallicRoughness;
    layout(location = 4) in vec3 fNormal;

    layout(location = 0) out vec4 oColor;

    ${shadowFuns}
    ${brdfSpecular}

    void main() {
      vec4 baseColor = fColor; // XXX: assuming premultiplied alpha
      float metallic = fMetallicRoughness[0];
      float roughness = fMetallicRoughness[1];
      float nonOcclusion = 1.0;

      vec3 normal = normalize(fNormal);

      ${litMain}

      oColor.rgb += pow(fEmissiveColor.rgb, vec3(2.2));
    }
  |]