module Render.DepthOnly.Pipeline
  ( Pipeline
  , allocate

  , Config
  , config
  ) where

import RIO

import Control.Monad.Trans.Resource (ResourceT)
import Data.Tagged (Tagged(..))
import Vulkan.Core10 qualified as Vk

import Geomancy (Transform)
import Engine.Vulkan.Pipeline qualified as Pipeline
import Engine.Vulkan.Types (HasVulkan, HasRenderPass(..), DsBindings)
import Render.Code (compileVert, {- compileFrag, -} glsl)
import Render.DescSets.Set0 (Scene, vertexPos, instanceTransform)
import Render.DescSets.Set0.Code (set0binding0)

type Config = Pipeline.Configure Pipeline ()
type Pipeline = Pipeline.Pipeline '[Scene] () Transform

allocate
  :: ( HasVulkan env
     , HasRenderPass renderpass
     )
  => Vk.SampleCountFlagBits
  -> Tagged Scene DsBindings
  -> renderpass
  -> ResourceT (RIO env) Pipeline
allocate :: forall env renderpass.
(HasVulkan env, HasRenderPass renderpass) =>
SampleCountFlagBits
-> Tagged Scene DsBindings
-> renderpass
-> ResourceT (RIO env) Pipeline
allocate SampleCountFlagBits
multisample Tagged Scene DsBindings
tset0 renderpass
rp = do
  (ReleaseKey
_, Pipeline
p) <- Maybe Extent2D
-> SampleCountFlagBits
-> Config '[Scene] () Transform ()
-> renderpass
-> ResourceT (RIO env) (ReleaseKey, Pipeline)
forall env (m :: * -> *) renderpass spec (dsl :: [*]) vertices
       instances.
(MonadVulkan env m, MonadResource m, HasRenderPass renderpass,
 Specialization spec, HasCallStack) =>
Maybe Extent2D
-> SampleCountFlagBits
-> Config dsl vertices instances spec
-> renderpass
-> m (ReleaseKey, Pipeline dsl vertices instances)
Pipeline.allocate
    Maybe Extent2D
forall a. Maybe a
Nothing
    SampleCountFlagBits
multisample
    (Tagged Scene DsBindings -> Config
config Tagged Scene DsBindings
tset0)
    renderpass
rp
  Pipeline -> ResourceT (RIO env) Pipeline
forall (f :: * -> *) a. Applicative f => a -> f a
pure Pipeline
p

config :: Tagged Scene DsBindings -> Config
config :: Tagged Scene DsBindings -> Config
config (Tagged DsBindings
set0) = Config '[] Any Any ()
forall vertices instances. Config '[] vertices instances ()
Pipeline.baseConfig
  { $sel:cDescLayouts:Config :: Tagged '[Scene] [DsBindings]
Pipeline.cDescLayouts  = forall {s :: [*]} {b}. b -> Tagged s b
forall {k} (s :: k) b. b -> Tagged s b
Tagged @'[Scene] [DsBindings
set0]
  , $sel:cVertexCode:Config :: Maybe ByteString
Pipeline.cVertexCode   = ByteString -> Maybe ByteString
forall a. a -> Maybe a
Just ByteString
vertCode
  , $sel:cVertexInput:Config :: SomeStruct PipelineVertexInputStateCreateInfo
Pipeline.cVertexInput  = SomeStruct PipelineVertexInputStateCreateInfo
vertexInput
  , $sel:cFragmentCode:Config :: Maybe ByteString
Pipeline.cFragmentCode = Maybe ByteString
forall a. Maybe a
Nothing -- XXX: needed for alpha cut-outs
  }
  where
    vertexInput :: SomeStruct PipelineVertexInputStateCreateInfo
vertexInput = [(VertexInputRate, [Format])]
-> SomeStruct PipelineVertexInputStateCreateInfo
Pipeline.vertexInput
      [ (VertexInputRate, [Format])
vertexPos
      , (VertexInputRate, [Format])
instanceTransform
      ]

vertCode :: ByteString
vertCode :: ByteString
vertCode =
  $(compileVert [glsl|
    #version 450
    #extension GL_ARB_separate_shader_objects : enable

    invariant gl_Position;

    ${set0binding0}

    layout(location = 0) in vec3 vPosition;
    layout(location = 1) in mat4 iModel;

    // layout(location = 0) out vec4 fColor;

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

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

      // XXX: needed for alpha cut-outs
      // fColor = vColor;
      // fColor.rgb * fColor.a;
    }
  |])