packages feed

keid-render-basic 0.1.6.1 → 0.1.7.0

raw patch · 29 files changed

+2088/−1248 lines, 29 filesdep ~keid-corePVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependency ranges changed: keid-core

API changes (from Hackage documentation)

- Render.Basic: data Pipelines
+ Render.Basic: [$sel:pSceneLayout:Pipelines] :: PipelinesF (f :: Type -> Type) -> Tagged '[Scene] DescriptorSetLayout
+ Render.Basic: [$sel:pShadowBinds:Pipelines] :: PipelinesF (f :: Type -> Type) -> Tagged Sun DsBindings
+ Render.Basic: [$sel:pShadowLayout:Pipelines] :: PipelinesF (f :: Type -> Type) -> Tagged '[Sun] DescriptorSetLayout
+ Render.Basic: allocateObservers :: RenderPasses -> PipelineWorkers -> ResourceT (StageRIO rs) PipelineObservers
+ Render.Basic: allocateWorkers :: Tagged Scene DsBindings -> SampleCountFlagBits -> RenderPasses -> ResourceT (StageRIO st) PipelineWorkers
+ Render.Basic: data PipelinesF (f :: Type -> Type)
+ Render.Basic: observePipelines :: RenderPasses -> PipelineWorkers -> PipelineObservers -> StageFrameRIO rp p fr rs ()
+ Render.Basic: rendering_ :: Rendering st
+ Render.Basic: shaderDir :: FilePath
+ Render.Basic: stageSources :: Map Text StageCode
+ Render.Basic: type PipelineObservers = PipelinesF Observers
+ Render.Basic: type PipelineWorkers = PipelinesF ConfigureGraphics
+ Render.Basic: type Pipelines = PipelinesF Identity
+ Render.Basic: type Rendering = Rendering RenderPasses Pipelines
+ Render.Debug.Code: frag :: Code
+ Render.Debug.Code: vert :: Code
+ Render.Debug.Pipeline: config :: Mode -> Tagged Scene DsBindings -> Config
+ Render.Debug.Pipeline: stageCode :: StageCode
+ Render.Debug.Pipeline: stageSpirv :: StageSpirv
+ Render.Debug.Pipeline: type Config = Configure Pipeline
+ Render.DepthOnly.Code: vert :: Code
+ Render.DepthOnly.Pipeline: stageCode :: StageCode
+ Render.DepthOnly.Pipeline: stageSpirv :: StageSpirv
+ Render.Font.EvanwSdf.Code: frag :: Code
+ Render.Font.EvanwSdf.Code: vert :: Code
+ Render.Font.EvanwSdf.Pipeline: config :: Tagged Scene DsBindings -> Config
+ Render.Font.EvanwSdf.Pipeline: stageCode :: StageCode
+ Render.Font.EvanwSdf.Pipeline: stageSpirv :: StageSpirv
+ Render.Font.EvanwSdf.Pipeline: type Config = Configure Pipeline
+ Render.Lit.Colored.Code: frag :: Code
+ Render.Lit.Colored.Code: vert :: Code
+ Render.Lit.Colored.Pipeline: stageCode :: StageCode
+ Render.Lit.Colored.Pipeline: stageSpirv :: StageSpirv
+ Render.Lit.Material.Code: frag :: Code
+ Render.Lit.Material.Code: vert :: Code
+ Render.Lit.Material.Pipeline: stageCode :: StageCode
+ Render.Lit.Material.Pipeline: stageSpirv :: StageSpirv
+ Render.Lit.Textured.Code: frag :: Code
+ Render.Lit.Textured.Code: vert :: Code
+ Render.Lit.Textured.Pipeline: stageCode :: StageCode
+ Render.Lit.Textured.Pipeline: stageSpirv :: StageSpirv
+ Render.ShadowMap.Code: vert :: Code
+ Render.ShadowMap.Pipeline: stageCode :: StageCode
+ Render.ShadowMap.Pipeline: stageSpirv :: StageSpirv
+ Render.Skybox.Code: frag :: Code
+ Render.Skybox.Code: vert :: Code
+ Render.Skybox.Pipeline: config :: Tagged Scene DsBindings -> Config
+ Render.Skybox.Pipeline: stageCode :: StageCode
+ Render.Skybox.Pipeline: stageSpirv :: StageSpirv
+ Render.Skybox.Pipeline: type Config = Configure Pipeline
+ Render.Unlit.Colored.Code: frag :: Code
+ Render.Unlit.Colored.Code: vert :: Code
+ Render.Unlit.Colored.Pipeline: stageCode :: StageCode
+ Render.Unlit.Colored.Pipeline: stageSpirv :: StageSpirv
+ Render.Unlit.Sprite.Code: frag :: Code
+ Render.Unlit.Sprite.Code: vert :: Code
+ Render.Unlit.Sprite.Pipeline: config :: Maybe Float -> Bool -> Tagged Scene DsBindings -> Config
+ Render.Unlit.Sprite.Pipeline: stageCode :: StageCode
+ Render.Unlit.Sprite.Pipeline: stageSpirv :: StageSpirv
+ Render.Unlit.Sprite.Pipeline: type Config = Configure Pipeline
+ Render.Unlit.Textured.Code: frag :: Code
+ Render.Unlit.Textured.Code: vert :: Code
+ Render.Unlit.Textured.Pipeline: stageCode :: StageCode
+ Render.Unlit.Textured.Pipeline: stageSpirv :: StageSpirv
+ Render.Unlit.TileMap.Code: frag :: Code
+ Render.Unlit.TileMap.Code: vert :: Code
+ Render.Unlit.TileMap.Pipeline: stageCode :: StageCode
- Render.Basic: Pipelines :: SampleCountFlagBits -> Tagged Scene DsBindings -> Pipeline -> Pipeline -> Pipeline -> Pipeline -> Pipeline -> Pipeline -> Pipeline -> Pipeline -> Pipeline -> Pipeline -> Pipeline -> Pipeline -> Pipeline -> Pipeline -> Pipeline -> Pipeline -> Pipeline -> Pipeline -> Pipeline -> Pipeline -> Pipeline -> Pipeline -> Pipeline -> Pipelines
+ Render.Basic: Pipelines :: SampleCountFlagBits -> Tagged Scene DsBindings -> Tagged '[Scene] DescriptorSetLayout -> Tagged Sun DsBindings -> Tagged '[Sun] DescriptorSetLayout -> (f ^ Pipeline) -> (f ^ Pipeline) -> (f ^ Pipeline) -> (f ^ Pipeline) -> (f ^ Pipeline) -> (f ^ Pipeline) -> (f ^ Pipeline) -> (f ^ Pipeline) -> (f ^ Pipeline) -> (f ^ Pipeline) -> (f ^ Pipeline) -> (f ^ Pipeline) -> (f ^ Pipeline) -> (f ^ Pipeline) -> (f ^ Pipeline) -> (f ^ Pipeline) -> (f ^ Pipeline) -> (f ^ Pipeline) -> (f ^ Pipeline) -> (f ^ Pipeline) -> (f ^ Pipeline) -> (f ^ Pipeline) -> (f ^ Pipeline) -> PipelinesF (f :: Type -> Type)
- Render.Basic: [$sel:pDebugShadow:Pipelines] :: Pipelines -> Pipeline
+ Render.Basic: [$sel:pDebugShadow:Pipelines] :: PipelinesF (f :: Type -> Type) -> f ^ Pipeline
- Render.Basic: [$sel:pDebugTexture:Pipelines] :: Pipelines -> Pipeline
+ Render.Basic: [$sel:pDebugTexture:Pipelines] :: PipelinesF (f :: Type -> Type) -> f ^ Pipeline
- Render.Basic: [$sel:pDebugUV:Pipelines] :: Pipelines -> Pipeline
+ Render.Basic: [$sel:pDebugUV:Pipelines] :: PipelinesF (f :: Type -> Type) -> f ^ Pipeline
- Render.Basic: [$sel:pDepthOnly:Pipelines] :: Pipelines -> Pipeline
+ Render.Basic: [$sel:pDepthOnly:Pipelines] :: PipelinesF (f :: Type -> Type) -> f ^ Pipeline
- Render.Basic: [$sel:pEvanwSdf:Pipelines] :: Pipelines -> Pipeline
+ Render.Basic: [$sel:pEvanwSdf:Pipelines] :: PipelinesF (f :: Type -> Type) -> f ^ Pipeline
- Render.Basic: [$sel:pLitColored:Pipelines] :: Pipelines -> Pipeline
+ Render.Basic: [$sel:pLitColored:Pipelines] :: PipelinesF (f :: Type -> Type) -> f ^ Pipeline
- Render.Basic: [$sel:pLitColoredBlend:Pipelines] :: Pipelines -> Pipeline
+ Render.Basic: [$sel:pLitColoredBlend:Pipelines] :: PipelinesF (f :: Type -> Type) -> f ^ Pipeline
- Render.Basic: [$sel:pLitMaterial:Pipelines] :: Pipelines -> Pipeline
+ Render.Basic: [$sel:pLitMaterial:Pipelines] :: PipelinesF (f :: Type -> Type) -> f ^ Pipeline
- Render.Basic: [$sel:pLitMaterialBlend:Pipelines] :: Pipelines -> Pipeline
+ Render.Basic: [$sel:pLitMaterialBlend:Pipelines] :: PipelinesF (f :: Type -> Type) -> f ^ Pipeline
- Render.Basic: [$sel:pLitTextured:Pipelines] :: Pipelines -> Pipeline
+ Render.Basic: [$sel:pLitTextured:Pipelines] :: PipelinesF (f :: Type -> Type) -> f ^ Pipeline
- Render.Basic: [$sel:pLitTexturedBlend:Pipelines] :: Pipelines -> Pipeline
+ Render.Basic: [$sel:pLitTexturedBlend:Pipelines] :: PipelinesF (f :: Type -> Type) -> f ^ Pipeline
- Render.Basic: [$sel:pMSAA:Pipelines] :: Pipelines -> SampleCountFlagBits
+ Render.Basic: [$sel:pMSAA:Pipelines] :: PipelinesF (f :: Type -> Type) -> SampleCountFlagBits
- Render.Basic: [$sel:pSceneBinds:Pipelines] :: Pipelines -> Tagged Scene DsBindings
+ Render.Basic: [$sel:pSceneBinds:Pipelines] :: PipelinesF (f :: Type -> Type) -> Tagged Scene DsBindings
- Render.Basic: [$sel:pShadowCast:Pipelines] :: Pipelines -> Pipeline
+ Render.Basic: [$sel:pShadowCast:Pipelines] :: PipelinesF (f :: Type -> Type) -> f ^ Pipeline
- Render.Basic: [$sel:pSkybox:Pipelines] :: Pipelines -> Pipeline
+ Render.Basic: [$sel:pSkybox:Pipelines] :: PipelinesF (f :: Type -> Type) -> f ^ Pipeline
- Render.Basic: [$sel:pSprite:Pipelines] :: Pipelines -> Pipeline
+ Render.Basic: [$sel:pSprite:Pipelines] :: PipelinesF (f :: Type -> Type) -> f ^ Pipeline
- Render.Basic: [$sel:pSpriteOutline:Pipelines] :: Pipelines -> Pipeline
+ Render.Basic: [$sel:pSpriteOutline:Pipelines] :: PipelinesF (f :: Type -> Type) -> f ^ Pipeline
- Render.Basic: [$sel:pTileMap:Pipelines] :: Pipelines -> Pipeline
+ Render.Basic: [$sel:pTileMap:Pipelines] :: PipelinesF (f :: Type -> Type) -> f ^ Pipeline
- Render.Basic: [$sel:pTileMapBlend:Pipelines] :: Pipelines -> Pipeline
+ Render.Basic: [$sel:pTileMapBlend:Pipelines] :: PipelinesF (f :: Type -> Type) -> f ^ Pipeline
- Render.Basic: [$sel:pUnlitColored:Pipelines] :: Pipelines -> Pipeline
+ Render.Basic: [$sel:pUnlitColored:Pipelines] :: PipelinesF (f :: Type -> Type) -> f ^ Pipeline
- Render.Basic: [$sel:pUnlitColoredNoDepth:Pipelines] :: Pipelines -> Pipeline
+ Render.Basic: [$sel:pUnlitColoredNoDepth:Pipelines] :: PipelinesF (f :: Type -> Type) -> f ^ Pipeline
- Render.Basic: [$sel:pUnlitTextured:Pipelines] :: Pipelines -> Pipeline
+ Render.Basic: [$sel:pUnlitTextured:Pipelines] :: PipelinesF (f :: Type -> Type) -> f ^ Pipeline
- Render.Basic: [$sel:pUnlitTexturedBlend:Pipelines] :: Pipelines -> Pipeline
+ Render.Basic: [$sel:pUnlitTexturedBlend:Pipelines] :: PipelinesF (f :: Type -> Type) -> f ^ Pipeline
- Render.Basic: [$sel:pWireframe:Pipelines] :: Pipelines -> Pipeline
+ Render.Basic: [$sel:pWireframe:Pipelines] :: PipelinesF (f :: Type -> Type) -> f ^ Pipeline
- Render.Basic: [$sel:pWireframeNoDepth:Pipelines] :: Pipelines -> Pipeline
+ Render.Basic: [$sel:pWireframeNoDepth:Pipelines] :: PipelinesF (f :: Type -> Type) -> f ^ Pipeline
- Render.Basic: getSceneLayout :: Pipelines -> Tagged '[Scene] DescriptorSetLayout
+ Render.Basic: getSceneLayout :: PipelinesF f -> Tagged '[Scene] DescriptorSetLayout
- Render.DepthOnly.Pipeline: type Config = Configure Pipeline ()
+ Render.DepthOnly.Pipeline: type Config = Configure Pipeline
- Render.Lit.Colored.Pipeline: type Config = Configure Pipeline ()
+ Render.Lit.Colored.Pipeline: type Config = Configure Pipeline
- Render.Lit.Material.Pipeline: type Config = Configure Pipeline ()
+ Render.Lit.Material.Pipeline: type Config = Configure Pipeline
- Render.Lit.Textured.Pipeline: type Config = Configure Pipeline ()
+ Render.Lit.Textured.Pipeline: type Config = Configure Pipeline
- Render.ShadowMap.Pipeline: type Config = Configure Pipeline ()
+ Render.ShadowMap.Pipeline: type Config = Configure Pipeline
- Render.Unlit.Colored.Pipeline: type Config = Configure Pipeline ()
+ Render.Unlit.Colored.Pipeline: type Config = Configure Pipeline
- Render.Unlit.Textured.Pipeline: type Config = Configure Pipeline ()
+ Render.Unlit.Textured.Pipeline: type Config = Configure Pipeline
- Render.Unlit.TileMap.Pipeline: type Config = Configure Pipeline ()
+ Render.Unlit.TileMap.Pipeline: type Config = Configure Pipeline

Files

ChangeLog.md view
@@ -1,5 +1,16 @@ # Changelog for keid-render-basic +## 0.1.7.0++- Pipelines updated to use `Engine.Vulkan.Pipeline.Graphics`.+- Pipelines wrapped in a HKD.+  * The `Pipelines`  is now an alias for `Identity` wrapper.+  * The data type is now `PipelinesF f` with a hole for HKD parameter.+  * The constructor name is still `Pipelines`, with all the fields intact.+- Added a bunch of functions to work with runtime-reloadable pipelines.+- Expose `stageCode` and `stageSpirv` for all pipelines.+- Added `Render.Basic.rendering` reusable stage component.+ ## 0.1.6.1  - `withFrozenCallStack` fixes for GHC-9.0.
keid-render-basic.cabal view
@@ -5,7 +5,7 @@ -- see: https://github.com/sol/hpack  name:           keid-render-basic-version:        0.1.6.1+version:        0.1.7.0 synopsis:       Basic rendering programs for Keid engine. category:       Game Engine homepage:       https://keid.haskell-game.dev@@ -37,32 +37,44 @@       Global.Resource.Texture.Base.Paths       Render.Basic       Render.Code.Lit+      Render.Debug.Code       Render.Debug.Model       Render.Debug.Pipeline+      Render.DepthOnly.Code       Render.DepthOnly.Pipeline       Render.DescSets.Set0       Render.DescSets.Set0.Code       Render.DescSets.Sun+      Render.Font.EvanwSdf.Code       Render.Font.EvanwSdf.Model       Render.Font.EvanwSdf.Pipeline       Render.ForwardMsaa+      Render.Lit.Colored.Code       Render.Lit.Colored.Model       Render.Lit.Colored.Pipeline       Render.Lit.Material+      Render.Lit.Material.Code       Render.Lit.Material.Collect       Render.Lit.Material.Model       Render.Lit.Material.Pipeline+      Render.Lit.Textured.Code       Render.Lit.Textured.Model       Render.Lit.Textured.Pipeline+      Render.ShadowMap.Code       Render.ShadowMap.Pipeline       Render.ShadowMap.RenderPass+      Render.Skybox.Code       Render.Skybox.Pipeline+      Render.Unlit.Colored.Code       Render.Unlit.Colored.Model       Render.Unlit.Colored.Pipeline+      Render.Unlit.Sprite.Code       Render.Unlit.Sprite.Model       Render.Unlit.Sprite.Pipeline+      Render.Unlit.Textured.Code       Render.Unlit.Textured.Model       Render.Unlit.Textured.Pipeline+      Render.Unlit.TileMap.Code       Render.Unlit.TileMap.Model       Render.Unlit.TileMap.Pipeline       Resource.Font@@ -143,7 +155,7 @@     , derive-storable-plugin     , file-embed >=0.0.10     , geomancy-    , keid-core >=0.1.6.1+    , keid-core >=0.1.7.0     , keid-geometry     , neat-interpolation     , resourcet
src/Render/Basic.hs view
@@ -1,3 +1,6 @@+{-# LANGUAGE AllowAmbiguousTypes #-}+{-# LANGUAGE OverloadedLists #-}+ {- |   All the provided render passes and pipelines packaged and delivered. -}@@ -7,18 +10,27 @@ import RIO  import Control.Monad.Trans.Resource (ResourceT)+import Data.Kind (Type) import Data.Tagged (Tagged(..))+import RIO.FilePath ((</>), (<.>)) import RIO.Vector.Partial as Vector (headM) import Vulkan.Core10 qualified as Vk import Vulkan.Zero (Zero(..))  -- keid-core +import Engine.Stage.Component qualified as Stage import Engine.Types (StageRIO) import Engine.Types qualified as Engine import Engine.Vulkan.Pipeline qualified as Pipeline+import Engine.Vulkan.Pipeline.External (type (^))+import Engine.Vulkan.Pipeline.External qualified as External+import Engine.Vulkan.Pipeline.Graphics qualified as Graphics+import Engine.Vulkan.Shader qualified as Shader import Engine.Vulkan.Swapchain qualified as Swapchain import Engine.Vulkan.Types (DsBindings, HasSwapchain, HasVulkan, RenderPass(..))+import Engine.Worker qualified as Worker+import Resource.Region qualified as Region  -- keid-render-basic @@ -48,6 +60,16 @@ type Frame = Engine.Frame RenderPasses Pipelines type StageFrameRIO r s a = Engine.StageFrameRIO RenderPasses Pipelines r s a +-- |  Basic rendering component without any extensions.+type Rendering = Stage.Rendering RenderPasses Pipelines++-- |  Basic rendering component without any extensions and resources.+rendering_ :: Rendering st+rendering_ = Stage.Rendering+  { rAllocateRP = allocate_+  , rAllocateP = allocatePipelines_+  }+ data RenderPasses = RenderPasses   { rpForwardMsaa :: ForwardMsaa   , rpShadowPass  :: ShadowMap@@ -102,39 +124,47 @@   -> ResourceT (RIO env) RenderPasses allocate_ = allocate zero -data Pipelines = Pipelines+type Pipelines = PipelinesF Identity+type PipelineObservers = PipelinesF External.Observers+type PipelineWorkers = PipelinesF External.ConfigureGraphics++data PipelinesF (f :: Type -> Type) = Pipelines   { pMSAA       :: Vk.SampleCountFlagBits   , pSceneBinds :: Tagged Scene DsBindings+  , pSceneLayout :: Tagged '[Scene] Vk.DescriptorSetLayout -  , pEvanwSdf :: EvanwSdf.Pipeline-  , pSkybox   :: Skybox.Pipeline+  , pShadowBinds :: Tagged Sun DsBindings+  , pShadowLayout :: Tagged '[Sun] Vk.DescriptorSetLayout -  , pDebugUV      :: Debug.Pipeline-  , pDebugTexture :: Debug.Pipeline-  , pDebugShadow  :: Debug.Pipeline+  , pEvanwSdf :: f ^ EvanwSdf.Pipeline+  , pSkybox   :: f ^ Skybox.Pipeline -  , pDepthOnly :: DepthOnly.Pipeline+  , pDebugUV      :: f ^ Debug.Pipeline+  , pDebugTexture :: f ^ Debug.Pipeline+  , pDebugShadow  :: f ^ Debug.Pipeline -  , pLitColored       :: LitColored.Pipeline-  , pLitColoredBlend  :: LitColored.Pipeline-  , pLitMaterial      :: LitMaterial.Pipeline-  , pLitMaterialBlend :: LitMaterial.Pipeline-  , pLitTextured      :: LitTextured.Pipeline-  , pLitTexturedBlend :: LitTextured.Pipeline+  , pDepthOnly :: f ^ DepthOnly.Pipeline -  , pUnlitColored        :: UnlitColored.Pipeline-  , pUnlitColoredNoDepth :: UnlitColored.Pipeline-  , pUnlitTextured       :: UnlitTextured.Pipeline-  , pUnlitTexturedBlend  :: UnlitTextured.Pipeline+  , pLitColored       :: f ^ LitColored.Pipeline+  , pLitColoredBlend  :: f ^ LitColored.Pipeline+  , pLitMaterial      :: f ^ LitMaterial.Pipeline+  , pLitMaterialBlend :: f ^ LitMaterial.Pipeline+  , pLitTextured      :: f ^ LitTextured.Pipeline+  , pLitTexturedBlend :: f ^ LitTextured.Pipeline -  , pSprite              :: UnlitSprite.Pipeline-  , pSpriteOutline       :: UnlitSprite.Pipeline-  , pTileMap             :: UnlitTileMap.Pipeline-  , pTileMapBlend        :: UnlitTileMap.Pipeline-  , pWireframe           :: UnlitColored.Pipeline-  , pWireframeNoDepth    :: UnlitColored.Pipeline+  , pUnlitColored        :: f ^ UnlitColored.Pipeline+  , pUnlitColoredNoDepth :: f ^ UnlitColored.Pipeline+  , pUnlitTextured       :: f ^ UnlitTextured.Pipeline+  , pUnlitTexturedBlend  :: f ^ UnlitTextured.Pipeline -  , pShadowCast :: ShadowPipe.Pipeline+  , pSprite              :: f ^ UnlitSprite.Pipeline+  , pSpriteOutline       :: f ^ UnlitSprite.Pipeline+  , pTileMap             :: f ^ UnlitTileMap.Pipeline+  , pTileMapBlend        :: f ^ UnlitTileMap.Pipeline+  , pWireframe           :: f ^ UnlitColored.Pipeline+  , pWireframeNoDepth    :: f ^ UnlitColored.Pipeline++  , pShadowCast :: f ^ ShadowPipe.Pipeline   }  allocatePipelines_@@ -157,13 +187,13 @@   -> RenderPasses   -> ResourceT (StageRIO st) Pipelines allocatePipelines pSceneBinds pMSAA RenderPasses{..} = do+  pEvanwSdf <- EvanwSdf.allocate pMSAA pSceneBinds rpForwardMsaa+  pSkybox   <- Skybox.allocate pMSAA pSceneBinds rpForwardMsaa+   pDebugUV      <- Debug.allocate Debug.UV         pMSAA pSceneBinds rpForwardMsaa   pDebugTexture <- Debug.allocate Debug.Texture    pMSAA pSceneBinds rpForwardMsaa   pDebugShadow  <- Debug.allocate (Debug.Shadow 1) pMSAA pSceneBinds rpForwardMsaa -  pEvanwSdf <- EvanwSdf.allocate pMSAA pSceneBinds rpForwardMsaa-  pSkybox   <- Skybox.allocate pMSAA pSceneBinds rpForwardMsaa-   pDepthOnly <- DepthOnly.allocate pMSAA pSceneBinds rpForwardMsaa    pLitColored       <- LitColored.allocate pMSAA pSceneBinds rpForwardMsaa@@ -184,23 +214,527 @@   pWireframe           <- UnlitColored.allocateWireframe True pMSAA pSceneBinds rpForwardMsaa   pWireframeNoDepth    <- UnlitColored.allocateWireframe False pMSAA pSceneBinds rpForwardMsaa -  let sunBinds = Sun.set0-  pShadowCast <- ShadowPipe.allocate sunBinds rpShadowPass ShadowPipe.defaults+  let pShadowBinds = Sun.set0+  pShadowCast <- ShadowPipe.allocate pShadowBinds rpShadowPass ShadowPipe.defaults +  let+    pSceneLayout =+      case Vector.headM (unTagged $ Pipeline.pDescLayouts pLitColored) of+        Nothing ->+          error "pLitColored has at least set0 in layout"+        Just set0layout ->+          Tagged set0layout++    pShadowLayout =+      case Vector.headM (unTagged $ Pipeline.pDescLayouts pShadowCast) of+        Nothing ->+          error "pShadowCast has at least set0 in layout"+        Just set0layout ->+          Tagged set0layout+   pure Pipelines{..} -getSceneLayout :: Pipelines -> Tagged '[Scene] Vk.DescriptorSetLayout-getSceneLayout Pipelines{pLitColored} =-  case Vector.headM (unTagged $ Pipeline.pDescLayouts pLitColored) of-    Nothing ->-      error "pLitColored has at least set0 in layout"-    Just set0layout ->-      Tagged set0layout+allocateWorkers+  :: Tagged Scene DsBindings+  -> Vk.SampleCountFlagBits+  -> RenderPasses+  -> ResourceT (StageRIO st) PipelineWorkers+allocateWorkers sceneBinds pMSAA renderPasses = do+  builtin <- allocatePipelines sceneBinds pMSAA renderPasses +  let+    evanwSdfFiles =+      Graphics.basicStages+        (shaderDir </> "evanw-sdf" <.> "vert" <.> "spv")+        (shaderDir </> "evanw-sdf" <.> "frag" <.> "spv")++  evanwSdfWorker <- Region.local . Worker.registered $+    External.spawnReflect "evanw-sdf" evanwSdfFiles \(stageCode, reflect) ->+      (EvanwSdf.config sceneBinds)+        { Graphics.cStages = stageCode+        , Graphics.cReflect = Just reflect+        }++  let+    skyboxFiles =+      Graphics.basicStages+        (shaderDir </> "skybox" <.> "vert" <.> "spv")+        (shaderDir </> "skybox" <.> "frag" <.> "spv")++  skyboxWorker <- Region.local . Worker.registered $+    External.spawnReflect "skybox" skyboxFiles \(stageCode, reflect) ->+      (Skybox.config sceneBinds)+        { Graphics.cStages = stageCode+        , Graphics.cReflect = Just reflect+        }++  let+    debugFiles =+      Graphics.basicStages+        (shaderDir </> "debug" <.> "vert" <.> "spv")+        (shaderDir </> "debug" <.> "frag" <.> "spv")++  debugUVWorker <- Region.local . Worker.registered $+    External.spawnReflect "debug-uv" debugFiles \(stageCode, reflect) ->+      (Debug.config Debug.UV sceneBinds)+        { Graphics.cStages = stageCode+        , Graphics.cReflect = Just reflect+        }++  debugTextureWorker <- Region.local . Worker.registered $+    External.spawnReflect "debug-texture" debugFiles \(stageCode, reflect) ->+      (Debug.config Debug.Texture sceneBinds)+        { Graphics.cStages = stageCode+        , Graphics.cReflect = Just reflect+        }++  debugShadowWorker <- Region.local . Worker.registered $+    External.spawnReflect "debug-shadow" debugFiles \(stageCode, reflect) ->+      (Debug.config (Debug.Shadow 1) sceneBinds)+        { Graphics.cStages = stageCode+        , Graphics.cReflect = Just reflect+        }++  let+    depthOnlyFiles = Graphics.vertexOnly+      (shaderDir </> "depth-only" <.> "vert" <.> "spv")++  depthOnlyWorker <- Region.local . Worker.registered $+    External.spawnReflect "debug" depthOnlyFiles \(stageCode, reflect) ->+      (DepthOnly.config sceneBinds)+        { Graphics.cStages = stageCode+        , Graphics.cReflect = Just reflect+        }++  let+    litColoredFiles =+      Graphics.basicStages+        (shaderDir </> "lit-colored" <.> "vert" <.> "spv")+        (shaderDir </> "lit-colored" <.> "frag" <.> "spv")++  litColoredWorker <- Region.local . Worker.registered $+    External.spawnReflect "lit-colored" litColoredFiles \(stageCode, reflect) ->+      (LitColored.config sceneBinds)+        { Graphics.cStages = stageCode+        , Graphics.cReflect = Just reflect+        }++  litColoredBlendWorker <- Region.local . Worker.registered $+    External.spawnReflect "lit-colored-blend" litColoredFiles \(stageCode, reflect) ->+      (LitColored.configBlend sceneBinds)+        { Graphics.cStages = stageCode+        , Graphics.cReflect = Just reflect+        }++  let+    litMaterialFiles =+      Graphics.basicStages+        (shaderDir </> "lit-material" <.> "vert" <.> "spv")+        (shaderDir </> "lit-material" <.> "frag" <.> "spv")++  litMaterialWorker <- Region.local . Worker.registered $+    External.spawnReflect "lit-material" litMaterialFiles \(stageCode, reflect) ->+      (LitMaterial.config sceneBinds)+        { Graphics.cStages = stageCode+        , Graphics.cReflect = Just reflect+        }++  litMaterialBlendWorker <- Region.local . Worker.registered $+    External.spawnReflect "lit-material-blend" litMaterialFiles \(stageCode, reflect) ->+      (LitMaterial.configBlend sceneBinds)+        { Graphics.cStages = stageCode+        , Graphics.cReflect = Just reflect+        }++  let+    litTexturedFiles =+      Graphics.basicStages+        (shaderDir </> "lit-textured" <.> "vert" <.> "spv")+        (shaderDir </> "lit-textured" <.> "frag" <.> "spv")++  litTexturedWorker <- Region.local . Worker.registered $+    External.spawnReflect "lit-textured" litTexturedFiles \(stageCode, reflect) ->+      (LitTextured.config sceneBinds)+        { Graphics.cStages = stageCode+        , Graphics.cReflect = Just reflect+        }++  litTexturedBlendWorker <- Region.local . Worker.registered $+    External.spawnReflect "lit-textured-blend" litTexturedFiles \(stageCode, reflect) ->+      (LitTextured.configBlend sceneBinds)+        { Graphics.cStages = stageCode+        , Graphics.cReflect = Just reflect+        }++  let+    unlitColoredFiles =+      Graphics.basicStages+        (shaderDir </> "unlit-colored" <.> "vert" <.> "spv")+        (shaderDir </> "unlit-colored" <.> "frag" <.> "spv")++  unlitColoredWorker <- Region.local . Worker.registered $+    External.spawnReflect "unlit-colored" unlitColoredFiles \(stageCode, reflect) ->+      (UnlitColored.config True sceneBinds)+        { Graphics.cStages = stageCode+        , Graphics.cReflect = Just reflect+        }++  unlitColoredNoDepthWorker <- Region.local . Worker.registered $+    External.spawnReflect "unlit-colored-nodepth" unlitColoredFiles \(stageCode, reflect) ->+      (UnlitColored.config False sceneBinds)+        { Graphics.cStages = stageCode+        , Graphics.cReflect = Just reflect+        }++  let+    unlitTexturedFiles =+      Graphics.basicStages+        (shaderDir </> "unlit-textured" <.> "vert" <.> "spv")+        (shaderDir </> "unlit-textured" <.> "frag" <.> "spv")++  unlitTexturedWorker <- Region.local . Worker.registered $+    External.spawnReflect "unlit-textured" unlitTexturedFiles \(stageCode, reflect) ->+      (UnlitTextured.config sceneBinds)+        { Graphics.cStages = stageCode+        , Graphics.cReflect = Just reflect+        }++  unlitTexturedBlendWorker <- Region.local . Worker.registered $+    External.spawnReflect "unlit-textured" unlitTexturedFiles \(stageCode, reflect) ->+      (UnlitTextured.configBlend sceneBinds)+        { Graphics.cStages = stageCode+        , Graphics.cReflect = Just reflect+        }++  let+    spriteFiles =+      Graphics.basicStages+        (shaderDir </> "sprite" <.> "vert" <.> "spv")+        (shaderDir </> "sprite" <.> "frag" <.> "spv")++  spriteWorker <- Region.local . Worker.registered $+    External.spawnReflect "sprite" spriteFiles \(stageCode, reflect) ->+      (UnlitSprite.config Nothing False sceneBinds)+        { Graphics.cStages = stageCode+        , Graphics.cReflect = Just reflect+        }++  spriteOutlineWorker <- Region.local . Worker.registered $+    External.spawnReflect "sprite" spriteFiles \(stageCode, reflect) ->+      (UnlitSprite.config Nothing True sceneBinds)+        { Graphics.cStages = stageCode+        , Graphics.cReflect = Just reflect+        }++  let+    tileMapFiles =+      Graphics.basicStages+        (shaderDir </> "tilemap" <.> "vert" <.> "spv")+        (shaderDir </> "tilemap" <.> "frag" <.> "spv")++  tileMapWorker <- Region.local . Worker.registered $+    External.spawnReflect "tilemap" tileMapFiles \(stageCode, reflect) ->+      (UnlitTileMap.config sceneBinds)+        { Graphics.cStages = stageCode+        , Graphics.cReflect = Just reflect+        }++  tileMapBlendWorker <- Region.local . Worker.registered $+    External.spawnReflect "tilemap" tileMapFiles \(stageCode, reflect) ->+      (UnlitTileMap.configBlend sceneBinds)+        { Graphics.cStages = stageCode+        , Graphics.cReflect = Just reflect+        }++  wireframeWorker <- Region.local . Worker.registered $+    External.spawnReflect "wireframe" unlitColoredFiles \(stageCode, reflect) ->+      (UnlitColored.configWireframe True sceneBinds)+        { Graphics.cStages = stageCode+        , Graphics.cReflect = Just reflect+        }++  wireframeNoDepthWorker <- Region.local . Worker.registered $+    External.spawnReflect "wireframe-nodepth" unlitColoredFiles \(stageCode, reflect) ->+      (UnlitColored.configWireframe False sceneBinds)+        { Graphics.cStages = stageCode+        , Graphics.cReflect = Just reflect+        }++  let+    shadowCastFiles =+      Graphics.vertexOnly+        (shaderDir </> "shadow-cast" <.> "vert" <.> "spv")++  shadowCastWorker <- Region.local . Worker.registered $+    External.spawnReflect "shadow-cast" shadowCastFiles \(stageCode, reflect) ->+      (ShadowPipe.config (pShadowBinds builtin) ShadowPipe.defaults)+        { Graphics.cStages = stageCode+        , Graphics.cReflect = Just reflect+        }++  pure builtin+    { pEvanwSdf = evanwSdfWorker+    , pSkybox = skyboxWorker+    , pDebugUV = debugUVWorker+    , pDebugTexture = debugTextureWorker+    , pDebugShadow = debugShadowWorker+    , pDepthOnly = depthOnlyWorker+    , pLitColored = litColoredWorker+    , pLitColoredBlend = litColoredBlendWorker+    , pLitMaterial = litMaterialWorker+    , pLitMaterialBlend = litMaterialBlendWorker+    , pLitTextured = litTexturedWorker+    , pLitTexturedBlend = litTexturedBlendWorker+    , pUnlitColored = unlitColoredWorker+    , pUnlitColoredNoDepth = unlitColoredNoDepthWorker+    , pUnlitTextured = unlitTexturedWorker+    , pUnlitTexturedBlend = unlitTexturedBlendWorker+    , pSprite = spriteWorker+    , pSpriteOutline = spriteOutlineWorker+    , pTileMap = tileMapWorker+    , pTileMapBlend = tileMapBlendWorker+    , pWireframe = wireframeWorker+    , pWireframeNoDepth = wireframeNoDepthWorker+    , pShadowCast = shadowCastWorker+    }++allocateObservers+  :: RenderPasses+  -> PipelineWorkers+  -> ResourceT (Engine.StageRIO rs) PipelineObservers+allocateObservers renderPasses Pipelines{..} = do+  evanwSdfExt <- External.newObserverGraphics+    forward+    pMSAA+    pEvanwSdf++  skyboxExt <- External.newObserverGraphics+    forward+    pMSAA+    pSkybox++  debugUVExt <- External.newObserverGraphics+    forward+    pMSAA+    pDebugUV++  debugTextureExt <- External.newObserverGraphics+    forward+    pMSAA+    pDebugTexture++  debugShadowExt <- External.newObserverGraphics+    forward+    pMSAA+    pDebugShadow++  depthOnlyExt <- External.newObserverGraphics+    forward+    pMSAA+    pDepthOnly++  litColoredExt <- External.newObserverGraphics+    forward+    pMSAA+    pLitColored++  litColoredBlendExt <- External.newObserverGraphics+    forward+    pMSAA+    pLitColoredBlend++  litMaterialExt <- External.newObserverGraphics+    forward+    pMSAA+    pLitMaterial++  litMaterialBlendExt <- External.newObserverGraphics+    forward+    pMSAA+    pLitMaterialBlend++  litTexturedExt <- External.newObserverGraphics+    forward+    pMSAA+    pLitTextured++  litTexturedBlendExt <- External.newObserverGraphics+    forward+    pMSAA+    pLitTexturedBlend++  unlitColoredExt <- External.newObserverGraphics+    forward+    pMSAA+    pUnlitColored++  unlitColoredNoDepthExt <- External.newObserverGraphics+    forward+    pMSAA+    pUnlitColoredNoDepth++  unlitTexturedExt <- External.newObserverGraphics+    forward+    pMSAA+    pUnlitTextured++  unlitTexturedBlendExt <- External.newObserverGraphics+    forward+    pMSAA+    pUnlitTexturedBlend++  spriteExt <- External.newObserverGraphics+    forward+    pMSAA+    pSprite++  spriteOutlineExt <- External.newObserverGraphics+    forward+    pMSAA+    pSpriteOutline++  tileMapExt <- External.newObserverGraphics+    forward+    pMSAA+    pTileMap++  tileMapBlendExt <- External.newObserverGraphics+    forward+    pMSAA+    pTileMapBlend++  wireframeExt <- External.newObserverGraphics+    forward+    pMSAA+    pWireframe++  wireframeNoDepthExt <- External.newObserverGraphics+    forward+    pMSAA+    pWireframeNoDepth++  shadowCastExt <- External.newObserverGraphics+    forward+    pMSAA+    pShadowCast++  pure Pipelines+    { pEvanwSdf = evanwSdfExt+    , pSkybox = skyboxExt+    , pDebugUV = debugUVExt+    , pDebugTexture = debugTextureExt+    , pDebugShadow = debugShadowExt+    , pDepthOnly = depthOnlyExt+    , pLitColored = litColoredExt+    , pLitColoredBlend = litColoredBlendExt+    , pLitMaterial = litMaterialExt+    , pLitMaterialBlend = litMaterialBlendExt+    , pLitTextured = litTexturedExt+    , pLitTexturedBlend = litTexturedBlendExt+    , pUnlitColored = unlitColoredExt+    , pUnlitColoredNoDepth = unlitColoredNoDepthExt+    , pUnlitTextured = unlitTexturedExt+    , pUnlitTexturedBlend = unlitTexturedBlendExt+    , pSprite = spriteExt+    , pSpriteOutline = spriteOutlineExt+    , pTileMap = tileMapExt+    , pTileMapBlend = tileMapBlendExt+    , pWireframe = wireframeExt+    , pWireframeNoDepth = wireframeNoDepthExt+    , pShadowCast = shadowCastExt+    , ..+    }+  where+    forward = rpForwardMsaa renderPasses++observePipelines+  :: RenderPasses+  -> PipelineWorkers+  -> PipelineObservers+  -> Engine.StageFrameRIO rp p fr rs ()+observePipelines fRenderpass workers pipelines = do+  observe @EvanwSdf.Pipeline pEvanwSdf++  observe @Skybox.Pipeline pSkybox++  observe @Debug.Pipeline pDebugUV+  observe @Debug.Pipeline pDebugTexture+  observe @Debug.Pipeline pDebugShadow++  observe @DepthOnly.Pipeline pDepthOnly++  observe @LitColored.Pipeline pLitColored+  observe @LitColored.Pipeline pLitColoredBlend++  observe @LitTextured.Pipeline pLitTextured+  observe @LitTextured.Pipeline pLitTexturedBlend++  observe @LitMaterial.Pipeline pLitMaterial+  observe @LitMaterial.Pipeline pLitMaterialBlend++  observe @UnlitColored.Pipeline pUnlitColored+  observe @UnlitColored.Pipeline pUnlitColoredNoDepth++  observe @UnlitTextured.Pipeline pUnlitTextured+  observe @UnlitTextured.Pipeline pUnlitTexturedBlend++  observe @UnlitSprite.Pipeline pSprite+  observe @UnlitSprite.Pipeline pSpriteOutline++  observe @UnlitTileMap.Pipeline pTileMap+  observe @UnlitTileMap.Pipeline pTileMapBlend++  observe @UnlitColored.Pipeline pWireframe+  observe @UnlitColored.Pipeline pWireframeNoDepth++  External.observeGraphics+    (rpShadowPass fRenderpass) -- XXX: different RP here+    (pMSAA workers)+    (Tagged [unTagged $ pSceneBinds pipelines])+    (pShadowCast workers)+    (pShadowCast pipelines)+  where+    observe+      :: forall+         p+         s vs is+         rps ps fr rs+      .  ( p ~ Graphics.Pipeline s vs is+         , Shader.Specialization (Graphics.Specialization p)+         )+      => (forall a . PipelinesF a -> a ^ p)+      -> Engine.StageFrameRIO rps ps fr rs ()+    observe =+      External.observeField+        @PipelinesF+        @p+        (rpForwardMsaa fRenderpass)+        (pMSAA workers)+        (pSceneBinds pipelines)+        workers+        pipelines++getSceneLayout :: PipelinesF f -> Tagged '[Scene] Vk.DescriptorSetLayout+getSceneLayout = pSceneLayout+ getSunLayout :: Pipelines -> Tagged '[Sun] Vk.DescriptorSetLayout-getSunLayout Pipelines{pShadowCast} =-  case Vector.headM (unTagged $ Pipeline.pDescLayouts pShadowCast) of-    Nothing ->-      error "pShadowCast has at least set0 in layout"-    Just set0layout ->-      Tagged set0layout+getSunLayout = pShadowLayout++shaderDir :: FilePath+shaderDir = "data" </> "shaders" </> "basic"++stageSources :: Map Text Graphics.StageCode+stageSources =+  [ ("evanw-sdf", EvanwSdf.stageCode)+  , ("skybox", Skybox.stageCode)+  , ("debug", Debug.stageCode)+  , ("depth-only", DepthOnly.stageCode)+  , ("lit-colored", LitColored.stageCode)+  , ("lit-material", LitMaterial.stageCode)+  , ("lit-textured", LitTextured.stageCode)+  , ("unlit-colored", UnlitColored.stageCode)+  , ("unlit-textured", UnlitTextured.stageCode)+  , ("sprite", UnlitSprite.stageCode)+  , ("tilemap", UnlitTileMap.stageCode)+  , ("shadow-cast", ShadowPipe.stageCode)+  ]
+ src/Render/Debug/Code.hs view
@@ -0,0 +1,123 @@+module Render.Debug.Code+  ( vert+  , frag+  ) where++import RIO++import Render.Code (Code, glsl)+import Render.DescSets.Set0.Code (set0binding0, set0binding1, set0binding2, set0binding3, set0binding5color)++vert :: Code+vert = fromString+  [glsl|+    #version 450++    ${set0binding0}++    // vertexPos+    layout(location = 0) in vec3 vPosition;+    // vertexAttrs+    layout(location = 1) in vec2 vTexCoord;+    // textureParams+    layout(location = 2) in  vec4 iTextureScaleOffset;+    layout(location = 3) in  vec4 iTextureGamma;+    layout(location = 4) in ivec2 iTextureIds;++    // transformMat+    layout(location = 5) in mat4 iModel;++    layout(location = 0)      out  vec2 fTexCoord;+    layout(location = 1) flat out  vec4 fTextureGamma;+    layout(location = 2) flat out ivec2 fTextureIds;++    void main() {+      vec4 fPosition = iModel * vec4(vPosition, 1.0);++      gl_Position+        = scene.projection+        * scene.view+        * fPosition;++      fTexCoord     = vTexCoord * iTextureScaleOffset.st + iTextureScaleOffset.pq;+      fTextureGamma = iTextureGamma;+      fTextureIds   = iTextureIds;+    }+  |]++frag :: Code+frag = fromString+  [glsl|+    #version 450+    #extension GL_EXT_nonuniform_qualifier : enable++    ${set0binding1}+    ${set0binding2}+    ${set0binding3}+    ${set0binding5color}++    layout(location = 0)      in  vec2 fTexCoord;+    layout(location = 1) flat in  vec4 fTextureGamma;+    layout(location = 2) flat in ivec2 fTextureIds;++    layout(location = 0) out vec4 oColor;++    layout (constant_id=0) const uint mode = 0;+    layout (constant_id=1) const uint shadow_mask = 0;++    void main() {+      vec4 texel = vec4(0);++      switch(mode) {+        case 0:+          texel = vec4(fTexCoord, 0, 1);+          break;++        case 1:+          if ((fTextureIds.t < 0) || (fTextureIds.s < 0)) break;++          texel = texture(+            sampler2D(+              textures[nonuniformEXT(fTextureIds.t)],+              samplers[nonuniformEXT(fTextureIds.s)]+            ),+            fTexCoord+          );+          break;++        case 2:+          float d0 = 1.0;+          if ((shadow_mask & 1) == 1)+            d0 = texture(+              shadowmaps,+              vec3(fTexCoord, 0.0)+            ).x;++          float d1 = 1.0;+          if ((shadow_mask & 2) == 2)+            d1 = texture(+              shadowmaps,+              vec3(fTexCoord, 1.0)+            ).x;++          float d2 = 1.0;+          if ((shadow_mask & 4) == 4)+            d2 = texture(+              shadowmaps,+              vec3(fTexCoord, 2.0)+            ).x;++          texel = vec4(1-d0, 1-d1, 1-d2, 1.0);+          break;++        default:+          break;+      }++      vec3 color = pow(texel.rgb, fTextureGamma.rgb);+      float combinedAlpha = texel.a * fTextureGamma.a;++      // XXX: premultiply alpha due to additive blending+      oColor = vec4(color * combinedAlpha, combinedAlpha);+    }+  |]
src/Render/Debug/Pipeline.hs view
@@ -1,7 +1,11 @@ module Render.Debug.Pipeline-  ( Pipeline+  ( Config+  , config+  , Pipeline   , allocate   , Mode(..)+  , stageCode+  , stageSpirv   ) where  import RIO@@ -10,15 +14,17 @@ import Data.Tagged (Tagged(..)) import Vulkan.Core10 qualified as Vk -import Engine.Vulkan.Pipeline qualified as Pipeline+import Engine.Vulkan.Pipeline.Graphics qualified as Graphics import Engine.Vulkan.Shader qualified as Shader import Engine.Vulkan.Types (HasVulkan, HasRenderPass(..), DsBindings)-import Render.Code (compileVert, compileFrag, glsl)+import Render.Code (compileVert, compileFrag)+import Render.Debug.Code qualified as Code import Render.Debug.Model qualified as Model import Render.DescSets.Set0 (Scene, vertexPos, instanceTransform)-import Render.DescSets.Set0.Code (set0binding0, set0binding1, set0binding2, set0binding3, set0binding5color) -type Pipeline = Pipeline.Pipeline '[Scene] Model.VertexAttrs Model.InstanceAttrs+type Pipeline = Graphics.Pipeline '[Scene] Model.VertexAttrs Model.InstanceAttrs+type Config = Graphics.Configure Pipeline+type instance Graphics.Specialization Pipeline = Mode  data Mode   = UV@@ -44,136 +50,32 @@   -> Tagged Scene DsBindings   -> renderpass   -> ResourceT (RIO env) Pipeline-allocate mode multisample (Tagged set0) = do-  fmap snd . Pipeline.allocate Nothing multisample config-  where-    config = Pipeline.baseConfig-      { Pipeline.cDescLayouts    = Tagged @'[Scene] [set0]-      , Pipeline.cVertexCode     = Just vertCode-      , Pipeline.cVertexInput    = vertexInput-      , Pipeline.cFragmentCode   = Just fragCode-      , Pipeline.cSpecialization = mode-      }+allocate mode multisample tset0 = do+  fmap snd . Graphics.allocate Nothing multisample (config mode tset0) -    vertexInput = Pipeline.vertexInput+config :: Mode -> Tagged Scene DsBindings -> Config+config mode (Tagged set0) = Graphics.baseConfig+  { Graphics.cDescLayouts    = Tagged @'[Scene] [set0]+  , Graphics.cStages         = stageSpirv+  , Graphics.cVertexInput    = vertexInput+  , Graphics.cSpecialization = mode+  }+  where+    vertexInput = Graphics.vertexInput       [ vertexPos -- vPosition       , (Vk.VERTEX_INPUT_RATE_VERTEX,   Model.vkVertexAttrs)       , (Vk.VERTEX_INPUT_RATE_INSTANCE, Model.vkInstanceTexture)       , instanceTransform       ] -vertCode :: ByteString-vertCode =-  $(compileVert [glsl|-    #version 450-    #extension GL_ARB_separate_shader_objects : enable--    ${set0binding0}--    // vertexPos-    layout(location = 0) in vec3 vPosition;-    // vertexAttrs-    layout(location = 1) in vec2 vTexCoord;-    // textureParams-    layout(location = 2) in  vec4 iTextureScaleOffset;-    layout(location = 3) in  vec4 iTextureGamma;-    layout(location = 4) in ivec2 iTextureIds;--    // transformMat-    layout(location = 5) in mat4 iModel;--    layout(location = 0)      out  vec2 fTexCoord;-    layout(location = 1) flat out  vec4 fTextureGamma;-    layout(location = 2) flat out ivec2 fTextureIds;--    void main() {-      vec4 fPosition = iModel * vec4(vPosition, 1.0);--      gl_Position-        = scene.projection-        * scene.view-        * fPosition;--      fTexCoord     = vTexCoord * iTextureScaleOffset.st + iTextureScaleOffset.pq;-      fTextureGamma = iTextureGamma;-      fTextureIds   = iTextureIds;-    }-  |])--fragCode :: ByteString-fragCode =-  $(compileFrag [glsl|-    #version 450-    #extension GL_ARB_separate_shader_objects : enable-    #extension GL_EXT_nonuniform_qualifier : enable--    ${set0binding1}-    ${set0binding2}-    ${set0binding3}-    ${set0binding5color}--    layout(location = 0)      in  vec2 fTexCoord;-    layout(location = 1) flat in  vec4 fTextureGamma;-    layout(location = 2) flat in ivec2 fTextureIds;--    layout(location = 0) out vec4 oColor;--    layout (constant_id=0) const uint mode = 0;-    layout (constant_id=1) const uint shadow_mask = 0;--    void main() {-      vec4 texel = vec4(0);--      switch(mode) {-        case 0:-          texel = vec4(fTexCoord, 0, 1);-          break;--        case 1:-          if ((fTextureIds.t < 0) || (fTextureIds.s < 0)) break;--          texel = texture(-            sampler2D(-              textures[nonuniformEXT(fTextureIds.t)],-              samplers[nonuniformEXT(fTextureIds.s)]-            ),-            fTexCoord-          );-          break;--        case 2:-          float d0 = 1.0;-          if ((shadow_mask & 1) == 1)-            d0 = texture(-              shadowmaps,-              vec3(fTexCoord, 0.0)-            ).x;--          float d1 = 1.0;-          if ((shadow_mask & 2) == 2)-            d1 = texture(-              shadowmaps,-              vec3(fTexCoord, 1.0)-            ).x;--          float d2 = 1.0;-          if ((shadow_mask & 4) == 4)-            d2 = texture(-              shadowmaps,-              vec3(fTexCoord, 2.0)-            ).x;--          texel = vec4(1-d0, 1-d1, 1-d2, 1.0);-          break;+stageCode :: Graphics.StageCode+stageCode = Graphics.basicStages Code.vert Code.frag -        default:-          break;-      }+stageSpirv :: Graphics.StageSpirv+stageSpirv = Graphics.basicStages vertSpirv fragSpirv -      vec3 color = pow(texel.rgb, fTextureGamma.rgb);-      float combinedAlpha = texel.a * fTextureGamma.a;+vertSpirv :: ByteString+vertSpirv = $(compileVert Code.vert) -      // XXX: premultiply alpha due to additive blending-      oColor = vec4(color * combinedAlpha, combinedAlpha);-    }-  |])+fragSpirv :: ByteString+fragSpirv = $(compileFrag Code.frag)
+ src/Render/DepthOnly/Code.hs view
@@ -0,0 +1,37 @@+module Render.DepthOnly.Code+  ( vert+  ) where++import RIO++import Render.Code (Code, glsl)+import Render.DescSets.Set0.Code (set0binding0)++vert :: Code+vert = fromString+  [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;+    }+  |]
src/Render/DepthOnly/Pipeline.hs view
@@ -4,6 +4,9 @@    , Config   , config++  , stageCode+  , stageSpirv   ) where  import RIO@@ -13,14 +16,15 @@ import Vulkan.Core10 qualified as Vk  import Geomancy (Transform)-import Engine.Vulkan.Pipeline qualified as Pipeline+import Engine.Vulkan.Pipeline.Graphics qualified as Graphics import Engine.Vulkan.Types (HasVulkan, HasRenderPass(..), DsBindings)-import Render.Code (compileVert, {- compileFrag, -} glsl)+import Render.Code (compileVert)+import Render.DepthOnly.Code qualified as Code import Render.DescSets.Set0 (Scene, vertexPos, instanceTransform)-import Render.DescSets.Set0.Code (set0binding0) -type Config = Pipeline.Configure Pipeline ()-type Pipeline = Pipeline.Pipeline '[Scene] () Transform+type Pipeline = Graphics.Pipeline '[Scene] () Transform+type Config = Graphics.Configure Pipeline+type instance Graphics.Specialization Pipeline = ()  allocate   :: ( HasVulkan env@@ -31,7 +35,7 @@   -> renderpass   -> ResourceT (RIO env) Pipeline allocate multisample tset0 rp = do-  (_, p) <- Pipeline.allocate+  (_, p) <- Graphics.allocate     Nothing     multisample     (config tset0)@@ -39,43 +43,22 @@   pure p  config :: Tagged Scene DsBindings -> Config-config (Tagged set0) = Pipeline.baseConfig-  { Pipeline.cDescLayouts  = Tagged @'[Scene] [set0]-  , Pipeline.cVertexCode   = Just vertCode-  , Pipeline.cVertexInput  = vertexInput-  , Pipeline.cFragmentCode = Nothing -- XXX: needed for alpha cut-outs+config (Tagged set0) = Graphics.baseConfig+  { Graphics.cDescLayouts  = Tagged @'[Scene] [set0]+  , Graphics.cStages       = stageSpirv+  , Graphics.cVertexInput  = vertexInput   }   where-    vertexInput = Pipeline.vertexInput+    vertexInput = Graphics.vertexInput       [ vertexPos       , instanceTransform       ] -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);+stageCode  :: Graphics.StageCode+stageCode = Graphics.vertexOnly Code.vert -      gl_Position-        = scene.projection-        * scene.view-        * fPosition;+stageSpirv :: Graphics.StageSpirv+stageSpirv = Graphics.vertexOnly vertSpirv -      // XXX: needed for alpha cut-outs-      // fColor = vColor;-      // fColor.rgb * fColor.a;-    }-  |])+vertSpirv :: ByteString+vertSpirv = $(compileVert Code.vert)
+ src/Render/Font/EvanwSdf/Code.hs view
@@ -0,0 +1,114 @@+module Render.Font.EvanwSdf.Code+  ( vert+  , frag+  ) where++import RIO++import Render.Code (Code, glsl)+import Render.DescSets.Set0.Code (set0binding0, set0binding1, set0binding2)++vert :: Code+vert = fromString+  [glsl|+    #version 450++    ${set0binding0}++    layout(location = 0) in  vec4 iVert;+    layout(location = 1) in  vec4 iFrag;+    layout(location = 2) in  vec4 iColor;+    layout(location = 3) in  vec4 iOutlineColor;+    layout(location = 4) in ivec2 iTextureIds;+    layout(location = 5) in  vec2 iSdf;++    layout(location = 0)      out  vec2 fTexCoord;+    layout(location = 1) flat out  vec4 fColor;+    layout(location = 2) flat out  vec4 fOutlineColor;+    layout(location = 3) flat out ivec2 fTextureIds;+    layout(location = 4) flat out  vec2 fSdf;++    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() {+      vec2 pos = positions[gl_VertexIndex];++      gl_Position+        = scene.projection+        * scene.view+      // TODO: * iModel+        * vec4(iVert.xy + pos * iVert.zw, 0, 1.0);++      vec2 uv = texCoords[gl_VertexIndex];+      fTexCoord = iFrag.xy + uv * iFrag.zw;++      fColor = iColor;+      fOutlineColor = iOutlineColor;+      fTextureIds = iTextureIds;+      fSdf = iSdf;+    }+  |]++frag :: Code+frag = fromString+  [glsl|+    #version 450+    #extension GL_EXT_nonuniform_qualifier : enable++    ${set0binding1}+    ${set0binding2}++    layout(location = 0)      in  vec2 fTexCoord;+    layout(location = 1) flat in  vec4 fColor;+    layout(location = 2) flat in  vec4 fOutlineColor;+    layout(location = 3) flat in ivec2 fTextureIds;+    layout(location = 4) flat in  vec2 fSdf;++    layout(location = 0) out vec4 outColor;++    void main() {+      float sdf = texture(+        sampler2D(+          textures[nonuniformEXT(fTextureIds.t)],+          samplers[nonuniformEXT(fTextureIds.s)]+        ),+        fTexCoord+      ).r;++      float smoothing    = fSdf[0];+      float outlineWidth = fSdf[1];++      float outerEdgeCenter = 0.5 - outlineWidth;++      float alpha = smoothstep(+        outerEdgeCenter - smoothing,+        outerEdgeCenter + smoothing,+        sdf+      );+      float border = smoothstep(+        0.5 - smoothing,+        0.5 + smoothing,+        sdf+      );+      outColor = mix(fOutlineColor, fColor, border);+      outColor *= alpha;+    }+  |]
src/Render/Font/EvanwSdf/Pipeline.hs view
@@ -1,8 +1,12 @@ {-# LANGUAGE OverloadedLists #-}  module Render.Font.EvanwSdf.Pipeline-  ( Pipeline+  ( Config+  , config+  , Pipeline   , allocate+  , stageCode+  , stageSpirv   ) where  import RIO@@ -11,14 +15,16 @@ import Data.Tagged (Tagged(..)) import Vulkan.Core10 qualified as Vk -import Engine.Vulkan.Pipeline qualified as Pipeline+import Engine.Vulkan.Pipeline.Graphics qualified as Graphics import Engine.Vulkan.Types (HasVulkan, HasRenderPass(..), DsBindings)-import Render.Code (compileVert, compileFrag, glsl)+import Render.Code (compileVert, compileFrag) import Render.DescSets.Set0 (Scene)-import Render.DescSets.Set0.Code (set0binding0, set0binding1, set0binding2)+import Render.Font.EvanwSdf.Code qualified as Code import Render.Font.EvanwSdf.Model qualified as Model -type Pipeline = Pipeline.Pipeline '[Scene] () Model.InstanceAttrs+type Pipeline = Graphics.Pipeline '[Scene] () Model.InstanceAttrs+type Config = Graphics.Configure Pipeline+type instance Graphics.Specialization Pipeline = ()  allocate   :: ( HasVulkan env@@ -28,128 +34,35 @@   -> Tagged Scene DsBindings   -> renderpass   -> ResourceT (RIO env) Pipeline-allocate multisample (Tagged set0) = do-  fmap snd . Pipeline.allocate+allocate multisample tset0 = do+  fmap snd . Graphics.allocate     Nothing     multisample-    Pipeline.baseConfig-      { Pipeline.cVertexCode     = Just vertCode-      , Pipeline.cFragmentCode   = Just fragCode-      , Pipeline.cDescLayouts    = Tagged @'[Scene] [set0]-      , Pipeline.cVertexInput    = vertexInput-      , Pipeline.cDepthTest      = False-      , Pipeline.cDepthWrite     = False-      , Pipeline.cBlend          = True-      , Pipeline.cCull           = Vk.CULL_MODE_NONE-      }+    (config tset0)++config :: Tagged Scene DsBindings -> Config+config (Tagged set0) = Graphics.baseConfig+  { Graphics.cDescLayouts = Tagged @'[Scene] [set0]+  , Graphics.cStages      = stageSpirv+  , Graphics.cVertexInput = vertexInput+  , Graphics.cDepthTest   = False+  , Graphics.cDepthWrite  = False+  , Graphics.cBlend       = True+  , Graphics.cCull        = Vk.CULL_MODE_NONE+  }   where-    vertexInput = Pipeline.vertexInput+    vertexInput = Graphics.vertexInput       [ (Vk.VERTEX_INPUT_RATE_INSTANCE, Model.vkInstanceAttrs)       ] -vertCode :: ByteString-vertCode =-  $(compileVert [glsl|-    #version 450-    #extension GL_ARB_separate_shader_objects : enable--    ${set0binding0}--    layout(location = 0) in  vec4 iVert;-    layout(location = 1) in  vec4 iFrag;-    layout(location = 2) in  vec4 iColor;-    layout(location = 3) in  vec4 iOutlineColor;-    layout(location = 4) in ivec2 iTextureIds;-    layout(location = 5) in  vec2 iSdf;--    layout(location = 0)      out  vec2 fTexCoord;-    layout(location = 1) flat out  vec4 fColor;-    layout(location = 2) flat out  vec4 fOutlineColor;-    layout(location = 3) flat out ivec2 fTextureIds;-    layout(location = 4) flat out  vec2 fSdf;--    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() {-      vec2 pos = positions[gl_VertexIndex];--      gl_Position-        = scene.projection-        * scene.view-      // TODO: * iModel-        * vec4(iVert.xy + pos * iVert.zw, 0, 1.0);--      vec2 uv = texCoords[gl_VertexIndex];-      fTexCoord = iFrag.xy + uv * iFrag.zw;--      fColor = iColor;-      fOutlineColor = iOutlineColor;-      fTextureIds = iTextureIds;-      fSdf = iSdf;-    }-  |])--fragCode :: ByteString-fragCode =-  $(compileFrag [glsl|-    #version 450-    #extension GL_ARB_separate_shader_objects : enable-    #extension GL_EXT_nonuniform_qualifier : enable--    ${set0binding1}-    ${set0binding2}--    layout(location = 0)      in  vec2 fTexCoord;-    layout(location = 1) flat in  vec4 fColor;-    layout(location = 2) flat in  vec4 fOutlineColor;-    layout(location = 3) flat in ivec2 fTextureIds;-    layout(location = 4) flat in  vec2 fSdf;--    layout(location = 0) out vec4 outColor;--    void main() {-      float sdf = texture(-        sampler2D(-          textures[nonuniformEXT(fTextureIds.t)],-          samplers[nonuniformEXT(fTextureIds.s)]-        ),-        fTexCoord-      ).r;+stageCode :: Graphics.StageCode+stageCode = Graphics.basicStages Code.vert Code.frag -      float smoothing    = fSdf[0];-      float outlineWidth = fSdf[1];+stageSpirv :: Graphics.StageSpirv+stageSpirv = Graphics.basicStages vertSpirv fragSpirv -      float outerEdgeCenter = 0.5 - outlineWidth;+vertSpirv :: ByteString+vertSpirv = $(compileVert Code.vert) -      float alpha = smoothstep(-        outerEdgeCenter - smoothing,-        outerEdgeCenter + smoothing,-        sdf-      );-      float border = smoothstep(-        0.5 - smoothing,-        0.5 + smoothing,-        sdf-      );-      outColor = mix(fOutlineColor, fColor, border);-      outColor *= alpha;-    }-  |])+fragSpirv :: ByteString+fragSpirv = $(compileFrag Code.frag)
+ src/Render/Lit/Colored/Code.hs view
@@ -0,0 +1,100 @@+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 = 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 = 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));+    }+  |]
src/Render/Lit/Colored/Pipeline.hs view
@@ -6,6 +6,9 @@   , Config   , config   , configBlend++  , stageCode+  , stageSpirv   ) where  import RIO@@ -14,16 +17,16 @@ import Data.Tagged (Tagged(..)) import Vulkan.Core10 qualified as Vk -import Engine.Vulkan.Pipeline qualified as Pipeline+import Engine.Vulkan.Pipeline.Graphics qualified as Graphics import Engine.Vulkan.Types (HasVulkan, HasRenderPass(..), DsBindings)-import Render.Code (compileVert, compileFrag, glsl)-import Render.Code.Lit (litMain, structLight, shadowFuns, brdfSpecular)+import Render.Code (compileVert, compileFrag) import Render.DescSets.Set0 (Scene, vertexPos, instanceTransform)-import Render.DescSets.Set0.Code (set0binding0, set0binding1, set0binding2, set0binding3, set0binding4, set0binding5)+import Render.Lit.Colored.Code qualified as Code import Render.Lit.Colored.Model qualified as Model -type Config = Pipeline.Configure Pipeline ()-type Pipeline = Pipeline.Pipeline '[Scene] Model.VertexAttrs Model.InstanceAttrs+type Pipeline = Graphics.Pipeline '[Scene] Model.VertexAttrs Model.InstanceAttrs+type Config = Graphics.Configure Pipeline+type instance Graphics.Specialization Pipeline = ()  allocate   :: ( HasVulkan env@@ -34,7 +37,7 @@   -> renderpass   -> ResourceT (RIO env) Pipeline allocate multisample tset0 rp = do-  (_, p) <- Pipeline.allocate+  (_, p) <- Graphics.allocate     Nothing     multisample     (config tset0)@@ -50,7 +53,7 @@   -> renderpass   -> ResourceT (RIO env) Pipeline allocateBlend multisample tset0 rp = do-  (_, p) <- Pipeline.allocate+  (_, p) <- Graphics.allocate     Nothing     multisample     (configBlend tset0)@@ -58,14 +61,13 @@   pure p  config :: Tagged Scene DsBindings -> Config-config (Tagged set0) = Pipeline.baseConfig-  { Pipeline.cDescLayouts  = Tagged @'[Scene] [set0]-  , Pipeline.cVertexCode   = Just vertCode-  , Pipeline.cVertexInput  = vertexInput-  , Pipeline.cFragmentCode = Just fragCode+config (Tagged set0) = Graphics.baseConfig+  { Graphics.cDescLayouts  = Tagged @'[Scene] [set0]+  , Graphics.cStages       = stageSpirv+  , Graphics.cVertexInput  = vertexInput   }   where-    vertexInput = Pipeline.vertexInput+    vertexInput = Graphics.vertexInput       [ vertexPos       , (Vk.VERTEX_INPUT_RATE_VERTEX, Model.vkVertexAttrs)       , instanceTransform@@ -73,97 +75,17 @@  configBlend :: Tagged Scene DsBindings -> Config configBlend tset0 = (config tset0)-  { Pipeline.cBlend = True+  { Graphics.cBlend = True   } -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 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;-    }-  |])--fragCode :: ByteString-fragCode =-  $(compileFrag [glsl|-    #version 450-    #extension GL_ARB_separate_shader_objects : enable-    #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;+stageCode :: Graphics.StageCode+stageCode = Graphics.basicStages Code.vert Code.frag -      vec3 normal = normalize(fNormal);+stageSpirv :: Graphics.StageSpirv+stageSpirv = Graphics.basicStages vertSpirv fragSpirv -      ${litMain}+vertSpirv :: ByteString+vertSpirv = $(compileVert Code.vert) -      oColor.rgb += pow(fEmissiveColor.rgb, vec3(2.2));-    }-  |])+fragSpirv :: ByteString+fragSpirv = $(compileFrag Code.frag)
+ src/Render/Lit/Material/Code.hs view
@@ -0,0 +1,175 @@+module Render.Lit.Material.Code+  ( vert+  , frag+  ) where++import RIO++import Render.Code (Code, glsl)+import Render.Code.Lit (litMain, shadowFuns, structLight, structMaterial, brdfSpecular)+import Render.DescSets.Set0.Code (set0binding0, set0binding1, set0binding2, set0binding3, set0binding4, set0binding5, set0binding6)++vert :: Code+vert = fromString+  [glsl|+    #version 450++    invariant gl_Position;++    ${set0binding0}++    // vertexPos+    layout(location = 0) in vec3 vPosition;+    // vertexAttrs+    layout(location = 1) in vec2 vTexCoord0;+    layout(location = 2) in vec2 vTexCoord1;+    layout(location = 3) in vec3 vNormal;+    layout(location = 4) in vec3 vTangent;+    layout(location = 5) in uint vMaterial;++    // transformMat+    layout(location = 6) in mat4 iModel;++    layout(location = 0)      out  vec4 fPosition;+    layout(location = 1)      out  vec2 fTexCoord0;+    layout(location = 2)      out  vec2 fTexCoord1;+    layout(location = 3) flat out  uint fMaterial;+    layout(location = 4)      out  mat3 fTBN;++    void main() {+      fPosition = iModel * vec4(vPosition, 1.0);++      gl_Position+        = scene.projection+        * scene.view+        * fPosition;++      fTexCoord0 = vTexCoord0;+      fTexCoord1 = vTexCoord1;++      vec3 t = normalize(vec3(iModel * vec4(vTangent, 0.0)));+      vec3 n = normalize(vec3(iModel * vec4(vNormal, 0.0)));+      vec3 to = normalize(t - dot(t, n) * n); // re-orthogonalize T with respect to N+      fTBN = mat3(to, cross(n, to), n);++      fMaterial = vMaterial;+    }+  |]++frag :: Code+frag = fromString+  [glsl|+    #version 450+    #extension GL_EXT_nonuniform_qualifier : enable++    layout(early_fragment_tests) in;++    // XXX: copypasta from Lit.Colored+    // TODO: move to spec constant+    const uint MAX_LIGHTS = 255;+    const float PCF_STEP = 1.5 / 4096;++    const uint MAX_MATERIALS = 2048;++    ${structLight}+    ${structMaterial}++    ${set0binding0}+    ${set0binding1}+    ${set0binding2}+    ${set0binding3}+    ${set0binding4} // lights+    ${set0binding5} // shadowmap+    ${set0binding6} // materials++    layout(location = 0)      in vec4 fPosition;+    layout(location = 1)      in vec2 fTexCoord0;+    layout(location = 2)      in vec2 fTexCoord1;+    layout(location = 3) flat in uint fMaterial;+    layout(location = 4)      in mat3 fTBN;++    layout(location = 0) out vec4 oColor;++    ${shadowFuns}+    ${brdfSpecular}++    void main() {+      Material material = materials[fMaterial];+      vec4 baseColor = material.baseColor;+      float metallic = material.metallicRoughness[0];+      float roughness = material.metallicRoughness[1];+      float nonOcclusion = 1.0;+      vec4 emissive = material.emissive;++      if (material.baseColorTex > -1) {+        baseColor *= texture(+          sampler2D(+            textures[nonuniformEXT(material.baseColorTex)],+            samplers[0]+          ),+          fTexCoord0+        );+      }++      if (baseColor.a < material.alphaCutoff) {+        discard;+      }++      baseColor.rgb *= baseColor.a;++      if (material.metallicRoughnessTex > -1) {+        vec3 packed = texture(+          sampler2D(+            textures[nonuniformEXT(material.metallicRoughnessTex)],+            samplers[0]+          ),+          fTexCoord0+        ).rgb;+        // XXX: assuming sRGB textures, even for AMR+        packed = pow(packed, vec3(1.0/2.2));+        nonOcclusion -= packed.r;+        metallic *= packed.b;+        roughness *= packed.g;+      }++      // // TODO: combine with MR as channel R.+      // float occlusion = texture(+      //   sampler2D(+      //     textures[nonuniformEXT(max(0, material.ambientOcclusionTex))],+      //     samplers[0]+      //   ),+      //   fTexCoord0+      // ).r;+      // nonOcclusion -= pow(occlusion, 1.0/2.2);++      if (material.emissiveTex > -1) {+        emissive *= texture(+          sampler2D(+            textures[nonuniformEXT(material.emissiveTex)],+            samplers[0]+          ),+          fTexCoord0+        );+      }++      vec3 normal = fTBN[2];+      if (material.normalTex > -1) {+        vec3 normalsColor = texture(+          sampler2D(+            textures[nonuniformEXT(material.normalTex)],+            samplers[0]+          ),+          fTexCoord0+        ).rgb;++        // XXX: convert normal non-colors to linear values from sRGB texture colorspace+        vec3 normals = pow(normalsColor, vec3(1.0/2.2)) * 2.0 - 1.0;++        normal = normalize(fTBN * normals);+      }++      ${litMain}++      oColor.rgb += pow(emissive.rgb, vec3(2.2));+    }+  |]
src/Render/Lit/Material/Pipeline.hs view
@@ -6,6 +6,9 @@   , Config   , config   , configBlend++  , stageCode+  , stageSpirv   ) where  import RIO@@ -14,16 +17,16 @@ import Data.Tagged (Tagged(..)) import Vulkan.Core10 qualified as Vk -import Engine.Vulkan.Pipeline qualified as Pipeline+import Engine.Vulkan.Pipeline.Graphics qualified as Graphics import Engine.Vulkan.Types (HasVulkan, HasRenderPass(..), DsBindings)-import Render.Code (compileVert, compileFrag, glsl)+import Render.Code (compileVert, compileFrag) import Render.DescSets.Set0 (Scene, vertexPos, instanceTransform)-import Render.DescSets.Set0.Code (set0binding0, set0binding1, set0binding2, set0binding3, set0binding4, set0binding5, set0binding6)-import Render.Code.Lit (litMain, shadowFuns, structLight, structMaterial, brdfSpecular)+import Render.Lit.Material.Code qualified as Code import Render.Lit.Material.Model qualified as Model -type Config = Pipeline.Configure Pipeline ()-type Pipeline = Pipeline.Pipeline '[Scene] Model.VertexAttrs Model.InstanceAttrs+type Pipeline = Graphics.Pipeline '[Scene] Model.VertexAttrs Model.InstanceAttrs+type Config = Graphics.Configure Pipeline+type instance Graphics.Specialization Pipeline = ()  allocate   :: ( HasVulkan env@@ -34,7 +37,7 @@   -> renderpass   -> ResourceT (RIO env) Pipeline allocate multisample tset0 rp = do-  (_, p) <- Pipeline.allocate+  (_, p) <- Graphics.allocate     Nothing     multisample     (config tset0)@@ -50,7 +53,7 @@   -> renderpass   -> ResourceT (RIO env) Pipeline allocateBlend multisample tset0 rp = do-  (_, p) <- Pipeline.allocate+  (_, p) <- Graphics.allocate     Nothing     multisample     (configBlend tset0)@@ -58,16 +61,15 @@   pure p  config :: Tagged Scene DsBindings -> Config-config (Tagged set0) = Pipeline.baseConfig-  { Pipeline.cDescLayouts  = Tagged @'[Scene] [set0]-  , Pipeline.cVertexCode   = Just vertCode-  , Pipeline.cVertexInput  = vertexInput-  , Pipeline.cFragmentCode = Just fragCode-  , Pipeline.cDepthWrite   = False -- XXX: Lit pipelines require depth pre-pass-  , Pipeline.cDepthCompare = Vk.COMPARE_OP_EQUAL+config (Tagged set0) = Graphics.baseConfig+  { Graphics.cDescLayouts  = Tagged @'[Scene] [set0]+  , Graphics.cStages       = stageSpirv+  , Graphics.cVertexInput  = vertexInput+  , Graphics.cDepthWrite   = False -- XXX: Lit pipelines require depth pre-pass+  , Graphics.cDepthCompare = Vk.COMPARE_OP_EQUAL   }   where-    vertexInput = Pipeline.vertexInput+    vertexInput = Graphics.vertexInput       [ vertexPos -- vPosition       , (Vk.VERTEX_INPUT_RATE_VERTEX, Model.vkVertexAttrs)       , instanceTransform@@ -75,176 +77,21 @@  configBlend :: Tagged Scene DsBindings -> Config configBlend tset0 = (config tset0)-  { Pipeline.cBlend =+  { Graphics.cBlend =       True-  , Pipeline.cDepthCompare =+  , Graphics.cDepthCompare =       -- XXX: blended objects aren't a part of depth prepass       Vk.COMPARE_OP_LESS_OR_EQUAL   } -vertCode :: ByteString-vertCode =-  $(compileVert [glsl|-    #version 450-    #extension GL_ARB_separate_shader_objects : enable--    invariant gl_Position;--    ${set0binding0}--    // vertexPos-    layout(location = 0) in vec3 vPosition;-    // vertexAttrs-    layout(location = 1) in vec2 vTexCoord0;-    layout(location = 2) in vec2 vTexCoord1;-    layout(location = 3) in vec3 vNormal;-    layout(location = 4) in vec3 vTangent;-    layout(location = 5) in uint vMaterial;--    // transformMat-    layout(location = 6) in mat4 iModel;--    layout(location = 0)      out  vec4 fPosition;-    layout(location = 1)      out  vec2 fTexCoord0;-    layout(location = 2)      out  vec2 fTexCoord1;-    layout(location = 3) flat out  uint fMaterial;-    layout(location = 4)      out  mat3 fTBN;--    void main() {-      fPosition = iModel * vec4(vPosition, 1.0);--      gl_Position-        = scene.projection-        * scene.view-        * fPosition;--      fTexCoord0 = vTexCoord0;-      fTexCoord1 = vTexCoord1;--      vec3 t = normalize(vec3(iModel * vec4(vTangent, 0.0)));-      vec3 n = normalize(vec3(iModel * vec4(vNormal, 0.0)));-      vec3 to = normalize(t - dot(t, n) * n); // re-orthogonalize T with respect to N-      fTBN = mat3(to, cross(n, to), n);--      fMaterial = vMaterial;-    }-  |])--fragCode :: ByteString-fragCode =-  $(compileFrag [glsl|-    #version 450-    #extension GL_ARB_separate_shader_objects : enable-    #extension GL_EXT_nonuniform_qualifier : enable--    layout(early_fragment_tests) in;--    // XXX: copypasta from Lit.Colored-    // TODO: move to spec constant-    const uint MAX_LIGHTS = 255;-    const float PCF_STEP = 1.5 / 4096;--    const uint MAX_MATERIALS = 2048;--    ${structLight}-    ${structMaterial}--    ${set0binding0}-    ${set0binding1}-    ${set0binding2}-    ${set0binding3}-    ${set0binding4} // lights-    ${set0binding5} // shadowmap-    ${set0binding6} // materials--    layout(location = 0)      in vec4 fPosition;-    layout(location = 1)      in vec2 fTexCoord0;-    layout(location = 2)      in vec2 fTexCoord1;-    layout(location = 3) flat in uint fMaterial;-    layout(location = 4)      in mat3 fTBN;--    layout(location = 0) out vec4 oColor;--    ${shadowFuns}-    ${brdfSpecular}--    void main() {-      Material material = materials[fMaterial];-      vec4 baseColor = material.baseColor;-      float metallic = material.metallicRoughness[0];-      float roughness = material.metallicRoughness[1];-      float nonOcclusion = 1.0;-      vec4 emissive = material.emissive;--      if (material.baseColorTex > -1) {-        baseColor *= texture(-          sampler2D(-            textures[nonuniformEXT(material.baseColorTex)],-            samplers[0]-          ),-          fTexCoord0-        );-      }--      if (baseColor.a < material.alphaCutoff) {-        discard;-      }--      baseColor.rgb *= baseColor.a;--      if (material.metallicRoughnessTex > -1) {-        vec3 packed = texture(-          sampler2D(-            textures[nonuniformEXT(material.metallicRoughnessTex)],-            samplers[0]-          ),-          fTexCoord0-        ).rgb;-        // XXX: assuming sRGB textures, even for AMR-        packed = pow(packed, vec3(1.0/2.2));-        nonOcclusion -= packed.r;-        metallic *= packed.b;-        roughness *= packed.g;-      }--      // // TODO: combine with MR as channel R.-      // float occlusion = texture(-      //   sampler2D(-      //     textures[nonuniformEXT(max(0, material.ambientOcclusionTex))],-      //     samplers[0]-      //   ),-      //   fTexCoord0-      // ).r;-      // nonOcclusion -= pow(occlusion, 1.0/2.2);--      if (material.emissiveTex > -1) {-        emissive *= texture(-          sampler2D(-            textures[nonuniformEXT(material.emissiveTex)],-            samplers[0]-          ),-          fTexCoord0-        );-      }--      vec3 normal = fTBN[2];-      if (material.normalTex > -1) {-        vec3 normalsColor = texture(-          sampler2D(-            textures[nonuniformEXT(material.normalTex)],-            samplers[0]-          ),-          fTexCoord0-        ).rgb;--        // XXX: convert normal non-colors to linear values from sRGB texture colorspace-        vec3 normals = pow(normalsColor, vec3(1.0/2.2)) * 2.0 - 1.0;+stageCode :: Graphics.StageCode+stageCode = Graphics.basicStages Code.vert Code.frag -        normal = normalize(fTBN * normals);-      }+stageSpirv :: Graphics.StageSpirv+stageSpirv = Graphics.basicStages vertSpirv fragSpirv -      ${litMain}+vertSpirv :: ByteString+vertSpirv = $(compileVert Code.vert) -      oColor.rgb += pow(emissive.rgb, vec3(2.2));-    }-  |])+fragSpirv :: ByteString+fragSpirv = $(compileFrag Code.frag)
+ src/Render/Lit/Textured/Code.hs view
@@ -0,0 +1,120 @@+module Render.Lit.Textured.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 = fromString+  [glsl|+    #version 450++    invariant gl_Position;++    ${set0binding0}++    // vertexPos+    layout(location = 0) in vec3 vPosition;+    // vertexAttrs+    layout(location = 1) in vec2 vTexCoord;+    layout(location = 2) in vec3 vNormal;+    // textureParams+    layout(location = 3) in  vec4 iTextureScaleOffset;+    layout(location = 4) in  vec4 iTextureGamma;+    layout(location = 5) in ivec2 iTextureIds;++    // transformMat+    layout(location = 6) in mat4 iModel;++    layout(location = 0)      out  vec4 fPosition;+    layout(location = 1)      out  vec3 fNormal;+    layout(location = 2)      out  vec2 fTexCoord;+    layout(location = 3) flat out  vec4 fTextureGamma;+    layout(location = 4) flat out ivec2 fTextureIds;++    void main() {+      fPosition = iModel * vec4(vPosition, 1.0);++      gl_Position+        = scene.projection+        * scene.view+        * fPosition;++      fNormal = transpose(mat3(inverse(iModel))) * vNormal; // TODO: use modelInv++      fTexCoord     = vTexCoord * iTextureScaleOffset.st + iTextureScaleOffset.pq;+      fTextureGamma = iTextureGamma;+      fTextureIds   = iTextureIds;+    }+  |]++frag :: Code+frag = fromString+  [glsl|+    #version 450+    #extension GL_EXT_nonuniform_qualifier : enable++    layout(early_fragment_tests) in;++    // XXX: copypasta from Lit.Colored+    // 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  vec3 fNormal;+    layout(location = 2)      in  vec2 fTexCoord;+    layout(location = 3) flat in  vec4 fTextureGamma;+    layout(location = 4) flat in ivec2 fTextureIds;++    layout(location = 0) out vec4 oColor;++    ${shadowFuns}+    ${brdfSpecular}++    void main() {+      // XXX: fall back to solid color+      vec4 baseColor = fTextureGamma;+      if ((fTextureIds.t > -1) && (fTextureIds.s > -1)) {+        vec4 texel = texture(+          sampler2D(+            textures[nonuniformEXT(fTextureIds.t)],+            samplers[nonuniformEXT(fTextureIds.s)]+          ),+          fTexCoord+        );++        if (texel.a < 0.5) discard;++        vec3 color = pow(texel.rgb, fTextureGamma.rgb);+        float combinedAlpha = texel.a * fTextureGamma.a;+        baseColor = vec4(color * combinedAlpha, combinedAlpha);+      }++      // TODO: get from textures+      float metallic = 0.0;+      float roughness = 0.6;+      float nonOcclusion = 1.0;++      vec3 normal = normalize(fNormal);++      ${litMain}+    }+  |]
src/Render/Lit/Textured/Pipeline.hs view
@@ -6,6 +6,9 @@   , Config   , config   , configBlend++  , stageCode+  , stageSpirv   ) where  import RIO@@ -14,16 +17,16 @@ import Data.Tagged (Tagged(..)) import Vulkan.Core10 qualified as Vk -import Engine.Vulkan.Pipeline qualified as Pipeline+import Engine.Vulkan.Pipeline.Graphics qualified as Graphics import Engine.Vulkan.Types (HasVulkan, HasRenderPass(..), DsBindings)-import Render.Code (compileVert, compileFrag, glsl)+import Render.Code (compileVert, compileFrag) import Render.DescSets.Set0 (Scene, vertexPos, instanceTransform)-import Render.DescSets.Set0.Code (set0binding0, set0binding1, set0binding2, set0binding3, set0binding4, set0binding5)-import Render.Code.Lit (litMain, shadowFuns, structLight, brdfSpecular)+import Render.Lit.Textured.Code qualified as Code import Render.Lit.Textured.Model qualified as Model -type Config = Pipeline.Configure Pipeline ()-type Pipeline = Pipeline.Pipeline '[Scene] Model.VertexAttrs Model.InstanceAttrs+type Pipeline = Graphics.Pipeline '[Scene] Model.VertexAttrs Model.InstanceAttrs+type Config = Graphics.Configure Pipeline+type instance Graphics.Specialization Pipeline = ()  allocate   :: ( HasVulkan env@@ -34,7 +37,7 @@   -> renderpass   -> ResourceT (RIO env) Pipeline allocate multisample tset0 rp = do-  (_, p) <- Pipeline.allocate+  (_, p) <- Graphics.allocate     Nothing     multisample     (config tset0)@@ -50,7 +53,7 @@   -> renderpass   -> ResourceT (RIO env) Pipeline allocateBlend multisample tset0 rp = do-  (_, p) <- Pipeline.allocate+  (_, p) <- Graphics.allocate     Nothing     multisample     (configBlend tset0)@@ -58,16 +61,15 @@   pure p  config :: Tagged Scene DsBindings -> Config-config (Tagged set0) = Pipeline.baseConfig-  { Pipeline.cDescLayouts  = Tagged @'[Scene] [set0]-  , Pipeline.cVertexCode   = Just vertCode-  , Pipeline.cVertexInput  = vertexInput-  , Pipeline.cFragmentCode = Just fragCode-  , Pipeline.cDepthWrite   = False -- XXX: Lit pipelines require depth pre-pass-  , Pipeline.cDepthCompare = Vk.COMPARE_OP_EQUAL+config (Tagged set0) = Graphics.baseConfig+  { Graphics.cDescLayouts  = Tagged @'[Scene] [set0]+  , Graphics.cStages       = stageSpirv+  , Graphics.cVertexInput  = vertexInput+  , Graphics.cDepthWrite   = False -- XXX: Lit pipelines require depth pre-pass+  , Graphics.cDepthCompare = Vk.COMPARE_OP_EQUAL   }   where-    vertexInput = Pipeline.vertexInput+    vertexInput = Graphics.vertexInput       [ vertexPos -- vPosition       , (Vk.VERTEX_INPUT_RATE_VERTEX,   Model.vkVertexAttrs)       , (Vk.VERTEX_INPUT_RATE_INSTANCE, Model.vkInstanceTexture)@@ -76,118 +78,18 @@  configBlend :: Tagged Scene DsBindings -> Config configBlend tset0 = (config tset0)-  { Pipeline.cBlend      = True-  , Pipeline.cDepthCompare = Vk.COMPARE_OP_LESS_OR_EQUAL+  { Graphics.cBlend      = True+  , Graphics.cDepthCompare = Vk.COMPARE_OP_LESS_OR_EQUAL   } -vertCode :: ByteString-vertCode =-  $(compileVert [glsl|-    #version 450-    #extension GL_ARB_separate_shader_objects : enable--    invariant gl_Position;--    ${set0binding0}--    // vertexPos-    layout(location = 0) in vec3 vPosition;-    // vertexAttrs-    layout(location = 1) in vec2 vTexCoord;-    layout(location = 2) in vec3 vNormal;-    // textureParams-    layout(location = 3) in  vec4 iTextureScaleOffset;-    layout(location = 4) in  vec4 iTextureGamma;-    layout(location = 5) in ivec2 iTextureIds;--    // transformMat-    layout(location = 6) in mat4 iModel;--    layout(location = 0)      out  vec4 fPosition;-    layout(location = 1)      out  vec3 fNormal;-    layout(location = 2)      out  vec2 fTexCoord;-    layout(location = 3) flat out  vec4 fTextureGamma;-    layout(location = 4) flat out ivec2 fTextureIds;--    void main() {-      fPosition = iModel * vec4(vPosition, 1.0);--      gl_Position-        = scene.projection-        * scene.view-        * fPosition;--      fNormal = transpose(mat3(inverse(iModel))) * vNormal; // TODO: use modelInv--      fTexCoord     = vTexCoord * iTextureScaleOffset.st + iTextureScaleOffset.pq;-      fTextureGamma = iTextureGamma;-      fTextureIds   = iTextureIds;-    }-  |])--fragCode :: ByteString-fragCode =-  $(compileFrag [glsl|-    #version 450-    #extension GL_ARB_separate_shader_objects : enable-    #extension GL_EXT_nonuniform_qualifier : enable--    layout(early_fragment_tests) in;--    // XXX: copypasta from Lit.Colored-    // 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  vec3 fNormal;-    layout(location = 2)      in  vec2 fTexCoord;-    layout(location = 3) flat in  vec4 fTextureGamma;-    layout(location = 4) flat in ivec2 fTextureIds;--    layout(location = 0) out vec4 oColor;--    ${shadowFuns}-    ${brdfSpecular}--    void main() {-      // XXX: fall back to solid color-      vec4 baseColor = fTextureGamma;-      if ((fTextureIds.t > -1) && (fTextureIds.s > -1)) {-        vec4 texel = texture(-          sampler2D(-            textures[nonuniformEXT(fTextureIds.t)],-            samplers[nonuniformEXT(fTextureIds.s)]-          ),-          fTexCoord-        );--        if (texel.a < 0.5) discard;--        vec3 color = pow(texel.rgb, fTextureGamma.rgb);-        float combinedAlpha = texel.a * fTextureGamma.a;-        baseColor = vec4(color * combinedAlpha, combinedAlpha);-      }+stageCode :: Graphics.StageCode+stageCode = Graphics.basicStages Code.vert Code.frag -      // TODO: get from textures-      float metallic = 0.0;-      float roughness = 0.6;-      float nonOcclusion = 1.0;+stageSpirv :: Graphics.StageSpirv+stageSpirv = Graphics.basicStages vertSpirv fragSpirv -      vec3 normal = normalize(fNormal);+vertSpirv :: ByteString+vertSpirv = $(compileVert Code.vert) -      ${litMain}-    }-  |])+fragSpirv :: ByteString+fragSpirv = $(compileFrag Code.frag)
+ src/Render/ShadowMap/Code.hs view
@@ -0,0 +1,33 @@+module Render.ShadowMap.Code+  ( vert+  ) where++import RIO++import Render.Code (Code, glsl)+import Render.Code.Lit (structLight)+import Render.DescSets.Sun (pattern MAX_VIEWS)++vert :: Code+vert = fromString+  [glsl|+    #version 450+    #extension GL_EXT_multiview : enable++    ${structLight}++    layout(set=0, binding=0, std140) uniform Globals {+      Light lights[${MAX_VIEWS}];+    };++    layout(location = 0) in vec3 vPosition;++    layout(location = 1) in mat4 iModel;++    void main() {+      gl_Position+        = lights[gl_ViewIndex].viewProjection+        * iModel+        * vec4(vPosition, 1.0);+    }+  |]
src/Render/ShadowMap/Pipeline.hs view
@@ -7,6 +7,9 @@    , Config   , config++  , stageCode+  , stageSpirv   ) where  import RIO@@ -16,15 +19,16 @@ import Geomancy (Transform) import Vulkan.Core10 qualified as Vk -import Engine.Vulkan.Pipeline qualified as Pipeline+import Engine.Vulkan.Pipeline.Graphics qualified as Graphics import Engine.Vulkan.Types (HasVulkan, HasRenderPass(..), DsBindings)-import Render.Code (compileVert, glsl)-import Render.Code.Lit (structLight)+import Render.Code (compileVert) import Render.DescSets.Set0 (vertexPos, instanceTransform)-import Render.DescSets.Sun (Sun, pattern MAX_VIEWS)+import Render.DescSets.Sun (Sun)+import Render.ShadowMap.Code qualified as Code -type Config = Pipeline.Configure Pipeline ()-type Pipeline = Pipeline.Pipeline '[Sun] () Transform+type Pipeline = Graphics.Pipeline '[Sun] () Transform+type Config = Graphics.Configure Pipeline+type instance Graphics.Specialization Pipeline = ()  data Settings = Settings   { cull      :: Vk.CullModeFlagBits@@ -46,7 +50,7 @@   -> Settings   -> ResourceT (RIO env) Pipeline allocate tset0 rp settings = do-  (_, p) <- Pipeline.allocate+  (_, p) <- Graphics.allocate     Nothing     Vk.SAMPLE_COUNT_1_BIT     (config tset0 settings)@@ -54,40 +58,24 @@   pure p  config :: Tagged Sun DsBindings -> Settings -> Config-config (Tagged set0) Settings{..} = Pipeline.baseConfig-  { Pipeline.cDescLayouts  = Tagged @'[Sun] [set0]-  , Pipeline.cVertexCode   = Just vertCode-  , Pipeline.cVertexInput  = vertexInput-  , Pipeline.cDepthBias    = depthBias-  , Pipeline.cCull         = cull+config (Tagged set0) Settings{..} = Graphics.baseConfig+  { Graphics.cDescLayouts  = Tagged @'[Sun] [set0]+  , Graphics.cStages       = stageSpirv+  , Graphics.cVertexInput  = vertexInput+  , Graphics.cDepthBias    = depthBias+  , Graphics.cCull         = cull   }   where-    vertexInput = Pipeline.vertexInput+    vertexInput = Graphics.vertexInput       [ vertexPos       , instanceTransform       ] -vertCode :: ByteString-vertCode =-  $(compileVert [glsl|-    #version 450-    #extension GL_ARB_separate_shader_objects : enable-    #extension GL_EXT_multiview : enable--    ${structLight}--    layout(set=0, binding=0, std140) uniform Globals {-      Light lights[${MAX_VIEWS}];-    };--    layout(location = 0) in vec3 vPosition;+stageSpirv :: Graphics.StageSpirv+stageSpirv = Graphics.vertexOnly vertSpirv -    layout(location = 1) in mat4 iModel;+vertSpirv :: ByteString+vertSpirv = $(compileVert Code.vert) -    void main() {-      gl_Position-        = lights[gl_ViewIndex].viewProjection-        * iModel-        * vec4(vPosition, 1.0);-    }-  |])+stageCode :: Graphics.StageCode+stageCode = Graphics.vertexOnly Code.vert
+ src/Render/Skybox/Code.hs view
@@ -0,0 +1,64 @@+module Render.Skybox.Code+  ( vert+  , frag+  ) where++import RIO++import Render.Code (Code, glsl)+import Render.DescSets.Set0.Code (set0binding0, set0binding1, set0binding3)++vert :: Code+vert = fromString+  [glsl|+    #version 450++    ${set0binding0}++    layout(location = 0) out vec3 fragUVW;++    float farZ = 0.9999; // 1 - 1e-7;++    void main() {+      vec4 pos = vec4(0.0);+      switch(gl_VertexIndex) {+          case 0: pos = vec4(-1.0,  3.0, farZ, 1.0); break;+          case 1: pos = vec4(-1.0, -1.0, farZ, 1.0); break; // XXX: swapped with 2. culling?+          case 2: pos = vec4( 3.0, -1.0, farZ, 1.0); break;+      }++      vec3 unProjected = (scene.invProjection * pos).xyz;+      unProjected *= -1;+      fragUVW = mat3(scene.invView) * unProjected;++      gl_Position = pos;+    }+  |]++frag :: Code+frag = fromString+  [glsl|+    #version 450+    #extension GL_EXT_nonuniform_qualifier : enable++    ${set0binding0}++    ${set0binding1}+    ${set0binding3}++    layout(location = 0) in vec3 fragUVW;++    layout(location = 0) out vec4 outColor;++    void main() {+      if (scene.envCubeId > -1) {+        outColor = texture(+          samplerCube(+            cubes[nonuniformEXT(scene.envCubeId)],+            samplers[3] // XXX: linear+          ),+          fragUVW+        );+      }+    }+  |]
src/Render/Skybox/Pipeline.hs view
@@ -1,8 +1,13 @@ {-# LANGUAGE OverloadedLists #-}  module Render.Skybox.Pipeline-  ( Pipeline+  ( Config+  , config+  , Pipeline   , allocate++  , stageCode+  , stageSpirv   ) where  import RIO@@ -11,13 +16,15 @@ import Data.Tagged (Tagged(..)) import Vulkan.Core10 qualified as Vk -import Engine.Vulkan.Pipeline qualified as Pipeline+import Engine.Vulkan.Pipeline.Graphics qualified as Graphics import Engine.Vulkan.Types (HasVulkan, HasRenderPass(..), DsBindings)-import Render.Code (compileVert, compileFrag, glsl)+import Render.Code (compileVert, compileFrag) import Render.DescSets.Set0 (Scene)-import Render.DescSets.Set0.Code (set0binding0, set0binding1, set0binding3)+import Render.Skybox.Code qualified as Code -type Pipeline = Pipeline.Pipeline '[Scene] () ()+type Pipeline = Graphics.Pipeline '[Scene] () ()+type Config = Graphics.Configure Pipeline+type instance Graphics.Specialization Pipeline = ()  allocate   :: ( HasVulkan env@@ -27,70 +34,27 @@   -> Tagged Scene DsBindings   -> renderpass   -> ResourceT (RIO env) Pipeline-allocate multisample (Tagged set0) = do-  fmap snd . Pipeline.allocate+allocate multisample tset0 = do+  fmap snd . Graphics.allocate     Nothing     multisample-    Pipeline.baseConfig-      { Pipeline.cVertexCode   = Just vertCode-      , Pipeline.cFragmentCode = Just fragCode-      , Pipeline.cDescLayouts  = Tagged @'[Scene] [set0]-      , Pipeline.cCull         = Vk.CULL_MODE_NONE-      }--vertCode :: ByteString-vertCode =-  $(compileVert [glsl|-    #version 450-    #extension GL_ARB_separate_shader_objects : enable--    ${set0binding0}--    layout(location = 0) out vec3 fragUVW;--    float farZ = 0.9999; // 1 - 1e-7;--    void main() {-      vec4 pos = vec4(0.0);-      switch(gl_VertexIndex) {-          case 0: pos = vec4(-1.0,  3.0, farZ, 1.0); break;-          case 1: pos = vec4(-1.0, -1.0, farZ, 1.0); break; // XXX: swapped with 2. culling?-          case 2: pos = vec4( 3.0, -1.0, farZ, 1.0); break;-      }--      vec3 unProjected = (scene.invProjection * pos).xyz;-      unProjected *= -1;-      fragUVW = mat3(scene.invView) * unProjected;--      gl_Position = pos;-    }-  |])--fragCode :: ByteString-fragCode =-  $(compileFrag [glsl|-    #version 450-    #extension GL_ARB_separate_shader_objects : enable-    #extension GL_EXT_nonuniform_qualifier : enable+    (config tset0) -    ${set0binding0}+config :: Tagged Scene DsBindings -> Config+config (Tagged set0) = Graphics.baseConfig+  { Graphics.cStages      = stageSpirv+  , Graphics.cDescLayouts = Tagged @'[Scene] [set0]+  , Graphics.cCull        = Vk.CULL_MODE_NONE+  } -    ${set0binding1}-    ${set0binding3}+stageCode :: Graphics.StageCode+stageCode = Graphics.basicStages Code.vert Code.frag -    layout(location = 0) in vec3 fragUVW;+stageSpirv :: Graphics.StageSpirv+stageSpirv = Graphics.basicStages vertSpirv fragSpirv -    layout(location = 0) out vec4 outColor;+vertSpirv :: ByteString+vertSpirv = $(compileVert Code.vert) -    void main() {-      if (scene.envCubeId > -1) {-        outColor = texture(-          samplerCube(-            cubes[nonuniformEXT(scene.envCubeId)],-            samplers[3] // XXX: linear-          ),-          fragUVW-        );-      }-    }-  |])+fragSpirv :: ByteString+fragSpirv = $(compileFrag Code.frag)
+ src/Render/Unlit/Colored/Code.hs view
@@ -0,0 +1,50 @@+module Render.Unlit.Colored.Code+  ( vert+  , frag+  ) where++import RIO++import Render.Code (Code, glsl)+import Render.DescSets.Set0.Code (set0binding0)++vert :: Code+vert = fromString+  [glsl|+    #version 450++    ${set0binding0}++    layout(location = 0) in vec3 vPosition;+    layout(location = 1) in vec4 vColor;++    layout(location = 2) 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;++      fColor = vColor;+      fColor.rgb * fColor.a;+    }+  |]++frag :: Code+frag = fromString+  [glsl|+    #version 450++    layout(location = 0) in vec4 fragColor;++    layout(location = 0) out vec4 outColor;++    void main() {+      outColor = fragColor;+    }+  |]
src/Render/Unlit/Colored/Pipeline.hs view
@@ -6,6 +6,9 @@   , Config   , config   , configWireframe++  , stageCode+  , stageSpirv   ) where  import RIO@@ -14,15 +17,16 @@ import Data.Tagged (Tagged(..)) import Vulkan.Core10 qualified as Vk -import Engine.Vulkan.Pipeline qualified as Pipeline+import Engine.Vulkan.Pipeline.Graphics qualified as Graphics import Engine.Vulkan.Types (HasVulkan, HasRenderPass(..), DsBindings)-import Render.Code (compileVert, compileFrag, glsl)+import Render.Code (compileVert, compileFrag) import Render.DescSets.Set0 (Scene, vertexPos, instanceTransform)-import Render.DescSets.Set0.Code (set0binding0)+import Render.Unlit.Colored.Code qualified as Code import Render.Unlit.Colored.Model qualified as Model -type Config = Pipeline.Configure Pipeline ()-type Pipeline = Pipeline.Pipeline '[Scene] Model.VertexAttrs Model.InstanceAttrs+type Pipeline = Graphics.Pipeline '[Scene] Model.VertexAttrs Model.InstanceAttrs+type Config = Graphics.Configure Pipeline+type instance Graphics.Specialization Pipeline = ()  allocate   :: ( HasVulkan env@@ -34,7 +38,7 @@   -> renderpass   -> ResourceT (RIO env) Pipeline allocate useDepth multisample tset0 rp = do-  (_, p) <- Pipeline.allocate+  (_, p) <- Graphics.allocate     Nothing     multisample     (config useDepth tset0)@@ -51,7 +55,7 @@   -> renderpass   -> ResourceT (RIO env) Pipeline allocateWireframe useDepth multisample tset0 rp = do-  (_, p) <- Pipeline.allocate+  (_, p) <- Graphics.allocate     Nothing     multisample     (configWireframe useDepth tset0)@@ -59,66 +63,34 @@   pure p  config :: Bool -> Tagged Scene DsBindings -> Config-config useDepth (Tagged set0) = Pipeline.baseConfig-  { Pipeline.cDescLayouts  = Tagged @'[Scene] [set0]-  , Pipeline.cVertexCode   = Just vertCode-  , Pipeline.cVertexInput  = vertexInput-  , Pipeline.cFragmentCode = Just fragCode-  , Pipeline.cBlend        = True-  , Pipeline.cDepthTest    = useDepth-  , Pipeline.cDepthWrite   = useDepth+config useDepth (Tagged set0) = Graphics.baseConfig+  { Graphics.cDescLayouts  = Tagged @'[Scene] [set0]+  , Graphics.cStages       = stageSpirv+  , Graphics.cVertexInput  = vertexInput+  , Graphics.cBlend        = True+  , Graphics.cDepthTest    = useDepth+  , Graphics.cDepthWrite   = useDepth   }   where-    vertexInput = Pipeline.vertexInput+    vertexInput = Graphics.vertexInput       [ vertexPos       , (Vk.VERTEX_INPUT_RATE_VERTEX, Model.vkVertexAttrs)       , instanceTransform       ] -configWireframe :: Bool -> Tagged Scene DsBindings -> Config-configWireframe useDepth tset0 = (config useDepth tset0)-  { Pipeline.cTopology = Vk.PRIMITIVE_TOPOLOGY_LINE_LIST-  }--vertCode :: ByteString-vertCode =-  $(compileVert [glsl|-    #version 450-    #extension GL_ARB_separate_shader_objects : enable--    ${set0binding0}--    layout(location = 0) in vec3 vPosition;-    layout(location = 1) in vec4 vColor;--    layout(location = 2) 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;--      fColor = vColor;-      fColor.rgb * fColor.a;-    }-  |])+stageCode  :: Graphics.StageCode+stageCode = Graphics.basicStages Code.vert Code.frag -fragCode :: ByteString-fragCode =-  $(compileFrag [glsl|-    #version 450-    #extension GL_ARB_separate_shader_objects : enable+stageSpirv :: Graphics.StageSpirv+stageSpirv = Graphics.basicStages vertSpirv fragSpirv -    layout(location = 0) in vec4 fragColor;+vertSpirv :: ByteString+vertSpirv = $(compileVert Code.vert) -    layout(location = 0) out vec4 outColor;+fragSpirv :: ByteString+fragSpirv = $(compileFrag Code.frag) -    void main() {-      outColor = fragColor;-    }-  |])+configWireframe :: Bool -> Tagged Scene DsBindings -> Config+configWireframe useDepth tset0 = (config useDepth tset0)+  { Graphics.cTopology = Vk.PRIMITIVE_TOPOLOGY_LINE_LIST+  }
+ src/Render/Unlit/Sprite/Code.hs view
@@ -0,0 +1,125 @@+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 = 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 ivec2 iTextureIds;+    layout(location = 5) in uvec2 iTextureSize;++    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 ivec2 fTextureIds;+    layout(location = 4) flat out uvec2 fTextureSize;++    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() {+      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;++      fTint = iTint;+      fOutline = iOutline;+      fTextureIds = iTextureIds;+      fTextureSize = iTextureSize;+    }+  |]++frag :: Code+frag = 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 ivec2 fTextureIds;+    layout(location = 4) flat in uvec2 fTextureSize;++    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 texture(+        sampler2D(+          textures[nonuniformEXT(fTextureIds.t)],+          samplers[nonuniformEXT(fTextureIds.s)]+        ),+        fTexCoord + uv+      );+    }++    vec2 step_size = 1.0 / vec2(fTextureSize);++    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(step_size.x,  0.0)         ).a / 4.0;+          alpha += tap(vec2(-step_size.x, 0.0)         ).a / 4.0;+          alpha += tap(vec2(0.0,          step_size.y) ).a / 4.0;+          alpha += tap(vec2(0.0,          -step_size.y)).a / 4.0;++          outColor += fOutline * alpha;+        }+      }+    }+  |]
src/Render/Unlit/Sprite/Pipeline.hs view
@@ -2,8 +2,12 @@  module Render.Unlit.Sprite.Pipeline   ( Pipeline+  , Config+  , config   , allocate   -- , allocateOutline+  , stageCode+  , stageSpirv   ) where  import RIO@@ -12,15 +16,16 @@ import Data.Tagged (Tagged(..)) import Vulkan.Core10 qualified as Vk -import Engine.Vulkan.Pipeline qualified as Pipeline+import Engine.Vulkan.Pipeline.Graphics qualified as Graphics import Engine.Vulkan.Types (HasVulkan, HasRenderPass(..), DsBindings)-import Render.Code (compileVert, compileFrag, glsl)+import Render.Code (compileVert, compileFrag) import Render.DescSets.Set0 (Scene)-import Render.DescSets.Set0.Code (set0binding0, set0binding1, set0binding2)+import Render.Unlit.Sprite.Code qualified as Code import Render.Unlit.Sprite.Model qualified as Model -type Config = Pipeline.Configure Pipeline (Float, Bool)-type Pipeline = Pipeline.Pipeline '[Scene] () Model.InstanceAttrs+type Pipeline = Graphics.Pipeline '[Scene] () Model.InstanceAttrs+type Config = Graphics.Configure Pipeline+type instance Graphics.Specialization Pipeline = (Float, Bool)  allocate   :: ( HasVulkan env@@ -33,7 +38,7 @@   -> renderpass   -> ResourceT (RIO env) Pipeline allocate multisample discardAlpha outline set0 = do-  fmap snd . Pipeline.allocate+  fmap snd . Graphics.allocate     Nothing     multisample     (config discardAlpha outline set0)@@ -44,19 +49,18 @@   -> Tagged Scene DsBindings   -> Config config discardAlpha outline (Tagged set0) =-  Pipeline.baseConfig-    { Pipeline.cVertexCode     = Just vertCode-    , Pipeline.cFragmentCode   = Just fragCode-    , Pipeline.cDescLayouts    = Tagged @'[Scene] [set0]-    , Pipeline.cVertexInput    = vertexInput-    , Pipeline.cDepthTest      = False-    , Pipeline.cDepthWrite     = False-    , Pipeline.cBlend          = True-    , Pipeline.cCull           = Vk.CULL_MODE_NONE-    , Pipeline.cSpecialization = specs+  Graphics.baseConfig+    { Graphics.cStages         = stageSpirv+    , Graphics.cDescLayouts    = Tagged @'[Scene] [set0]+    , Graphics.cVertexInput    = vertexInput+    , Graphics.cDepthTest      = False+    , Graphics.cDepthWrite     = False+    , Graphics.cBlend          = True+    , Graphics.cCull           = Vk.CULL_MODE_NONE+    , Graphics.cSpecialization = specs     }   where-    vertexInput = Pipeline.vertexInput+    vertexInput = Graphics.vertexInput       [ (Vk.VERTEX_INPUT_RATE_INSTANCE, Model.vkInstanceAttrs)       ] @@ -65,120 +69,14 @@       , outline       ) -vertCode :: ByteString-vertCode =-  $(compileVert [glsl|-    #version 450-    #extension GL_ARB_separate_shader_objects : enable--    ${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 ivec2 iTextureIds;-    layout(location = 5) in uvec2 iTextureSize;--    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 ivec2 fTextureIds;-    layout(location = 4) flat out uvec2 fTextureSize;--    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() {-      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;--      fTint = iTint;-      fOutline = iOutline;-      fTextureIds = iTextureIds;-      fTextureSize = iTextureSize;-    }-  |])--fragCode :: ByteString-fragCode =-  $(compileFrag [glsl|-    #version 450-    #extension GL_ARB_separate_shader_objects : enable-    #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 ivec2 fTextureIds;-    layout(location = 4) flat in uvec2 fTextureSize;--    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 texture(-        sampler2D(-          textures[nonuniformEXT(fTextureIds.t)],-          samplers[nonuniformEXT(fTextureIds.s)]-        ),-        fTexCoord + uv-      );-    }--    vec2 step_size = 1.0 / vec2(fTextureSize);--    void main() {-      vec4 texel = tap(vec2(0));--      if (discardAlpha != 0.0) {-        if (texel.a < discardAlpha) {-          discard;-        }-      }--      outColor = texel * fTint * texel.a;+stageCode :: Graphics.StageCode+stageCode = Graphics.basicStages Code.vert Code.frag -      if (doOutline) {-        if (fOutline.a > 0.0 && texel.a < 1.0) {-          float alpha = 0.0;+stageSpirv :: Graphics.StageSpirv+stageSpirv = Graphics.basicStages vertSpirv fragSpirv -          alpha += tap(vec2(step_size.x,  0.0)         ).a / 4.0;-          alpha += tap(vec2(-step_size.x, 0.0)         ).a / 4.0;-          alpha += tap(vec2(0.0,          step_size.y) ).a / 4.0;-          alpha += tap(vec2(0.0,          -step_size.y)).a / 4.0;+vertSpirv :: ByteString+vertSpirv = $(compileVert Code.vert) -          outColor += fOutline * alpha;-        }-      }-    }-  |])+fragSpirv :: ByteString+fragSpirv = $(compileFrag Code.frag)
+ src/Render/Unlit/Textured/Code.hs view
@@ -0,0 +1,83 @@+module Render.Unlit.Textured.Code+  ( vert+  , frag+  ) where++import RIO++import Render.Code (Code, glsl)+import Render.DescSets.Set0.Code (set0binding0, set0binding1, set0binding2)++vert :: Code+vert = fromString+  [glsl|+    #version 450++    ${set0binding0}++    // vertexPos+    layout(location = 0) in vec3 vPosition;+    // vertexAttrs+    layout(location = 1) in vec2 vTexCoord;+    // textureParams+    layout(location = 2) in  vec4 iTextureScaleOffset;+    layout(location = 3) in  vec4 iTextureGamma;+    layout(location = 4) in ivec2 iTextureIds;++    // transformMat+    layout(location = 5) in mat4 iModel;++    layout(location = 0)      out  vec2 fTexCoord;+    layout(location = 1) flat out  vec4 fTextureGamma;+    layout(location = 2) flat out ivec2 fTextureIds;++    void main() {+      vec4 fPosition = iModel * vec4(vPosition, 1.0);++      gl_Position+        = scene.projection+        * scene.view+        * fPosition;++      fTexCoord     = vTexCoord * iTextureScaleOffset.st + iTextureScaleOffset.pq;+      fTextureGamma = iTextureGamma;+      fTextureIds   = iTextureIds;+    }+  |]++frag :: Code+frag = fromString+  [glsl|+    #version 450+    #extension GL_ARB_separate_shader_objects : enable+    #extension GL_EXT_nonuniform_qualifier : enable++    ${set0binding1}+    ${set0binding2}++    layout(location = 0)      in  vec2 fTexCoord;+    layout(location = 1) flat in  vec4 fTextureGamma;+    layout(location = 2) flat in ivec2 fTextureIds;++    layout(location = 0) out vec4 oColor;++    void main() {+      vec3 color = vec3(0);+      float combinedAlpha = 0;++      if (fTextureIds.t > -1 && fTextureIds.s > -1) {+        vec4 texel = texture(+          sampler2D(+            textures[nonuniformEXT(fTextureIds.t)],+            samplers[nonuniformEXT(fTextureIds.s)]+          ),+          fTexCoord+        );+        color = pow(texel.rgb, fTextureGamma.rgb);+        combinedAlpha = texel.a * fTextureGamma.a;+      }++      // XXX: premultiply alpha due to additive blending+      oColor = vec4(color * combinedAlpha, combinedAlpha);+    }+  |]
src/Render/Unlit/Textured/Pipeline.hs view
@@ -6,23 +6,27 @@   , Config   , config   , configBlend++  , stageCode+  , stageSpirv   ) where  import RIO-import Render.DescSets.Set0.Code  import Control.Monad.Trans.Resource (ResourceT) import Data.Tagged (Tagged(..)) import Vulkan.Core10 qualified as Vk -import Engine.Vulkan.Pipeline qualified as Pipeline+import Engine.Vulkan.Pipeline.Graphics qualified as Graphics import Engine.Vulkan.Types (HasVulkan, HasRenderPass(..), DsBindings)-import Render.Code (compileVert, compileFrag, glsl)+import Render.Code (compileVert, compileFrag) import Render.DescSets.Set0 (Scene, vertexPos, instanceTransform)+import Render.Unlit.Textured.Code qualified as Code import Render.Unlit.Textured.Model qualified as Model -type Config = Pipeline.Configure Pipeline ()-type Pipeline = Pipeline.Pipeline '[Scene] Model.VertexAttrs Model.InstanceAttrs+type Pipeline = Graphics.Pipeline '[Scene] Model.VertexAttrs Model.InstanceAttrs+type Config = Graphics.Configure Pipeline+type instance Graphics.Specialization Pipeline = ()  allocate   :: ( HasVulkan env@@ -33,7 +37,7 @@   -> renderpass   -> ResourceT (RIO env) Pipeline allocate multisample tset0 rp = do-  (_, p) <- Pipeline.allocate+  (_, p) <- Graphics.allocate     Nothing     multisample     (config tset0)@@ -49,7 +53,7 @@   -> renderpass   -> ResourceT (RIO env) Pipeline allocateBlend multisample tset0 rp = do-  (_, p) <- Pipeline.allocate+  (_, p) <- Graphics.allocate     Nothing     multisample     (configBlend tset0)@@ -57,14 +61,13 @@   pure p  config :: Tagged Scene DsBindings -> Config-config (Tagged set0) = Pipeline.baseConfig-  { Pipeline.cDescLayouts  = Tagged @'[Scene] [set0]-  , Pipeline.cVertexCode   = Just vertCode-  , Pipeline.cVertexInput  = vertexInput-  , Pipeline.cFragmentCode = Just fragCode+config (Tagged set0) = Graphics.baseConfig+  { Graphics.cDescLayouts  = Tagged @'[Scene] [set0]+  , Graphics.cStages       = stageSpirv+  , Graphics.cVertexInput  = vertexInput   }   where-    vertexInput = Pipeline.vertexInput+    vertexInput = Graphics.vertexInput       [ vertexPos -- vPosition       , (Vk.VERTEX_INPUT_RATE_VERTEX,   Model.vkVertexAttrs)       , (Vk.VERTEX_INPUT_RATE_INSTANCE, Model.vkInstanceTexture)@@ -73,81 +76,18 @@  configBlend :: Tagged Scene DsBindings -> Config configBlend tset0 = (config tset0)-  { Pipeline.cBlend      = True-  , Pipeline.cDepthWrite = False+  { Graphics.cBlend      = True+  , Graphics.cDepthWrite = False   } -vertCode :: ByteString-vertCode =-  $(compileVert [glsl|-    #version 450-    #extension GL_ARB_separate_shader_objects : enable--    ${set0binding0}--    // vertexPos-    layout(location = 0) in vec3 vPosition;-    // vertexAttrs-    layout(location = 1) in vec2 vTexCoord;-    // textureParams-    layout(location = 2) in  vec4 iTextureScaleOffset;-    layout(location = 3) in  vec4 iTextureGamma;-    layout(location = 4) in ivec2 iTextureIds;--    // transformMat-    layout(location = 5) in mat4 iModel;--    layout(location = 0)      out  vec2 fTexCoord;-    layout(location = 1) flat out  vec4 fTextureGamma;-    layout(location = 2) flat out ivec2 fTextureIds;--    void main() {-      vec4 fPosition = iModel * vec4(vPosition, 1.0);--      gl_Position-        = scene.projection-        * scene.view-        * fPosition;--      fTexCoord     = vTexCoord * iTextureScaleOffset.st + iTextureScaleOffset.pq;-      fTextureGamma = iTextureGamma;-      fTextureIds   = iTextureIds;-    }-  |])--fragCode :: ByteString-fragCode =-  $(compileFrag [glsl|-    #version 450-    #extension GL_ARB_separate_shader_objects : enable-    #extension GL_EXT_nonuniform_qualifier : enable--    ${set0binding1}-    ${set0binding2}--    layout(location = 0)      in  vec2 fTexCoord;-    layout(location = 1) flat in  vec4 fTextureGamma;-    layout(location = 2) flat in ivec2 fTextureIds;--    layout(location = 0) out vec4 oColor;+stageCode :: Graphics.StageCode+stageCode = Graphics.basicStages Code.vert Code.frag -    void main() {-      vec3 color = vec3(0);-      float combinedAlpha = 0;+stageSpirv :: Graphics.StageSpirv+stageSpirv = Graphics.basicStages vertSpirv fragSpirv -      if (fTextureIds.t > -1 && fTextureIds.s > -1) {-        vec4 texel = texture(-          sampler2D(-            textures[nonuniformEXT(fTextureIds.t)],-            samplers[nonuniformEXT(fTextureIds.s)]-          ),-          fTexCoord-        );-        color = pow(texel.rgb, fTextureGamma.rgb);-        combinedAlpha = texel.a * fTextureGamma.a;-      }+vertSpirv :: ByteString+vertSpirv = $(compileVert Code.vert) -      // XXX: premultiply alpha due to additive blending-      oColor = vec4(color * combinedAlpha, combinedAlpha);-    }-  |])+fragSpirv :: ByteString+fragSpirv = $(compileFrag Code.frag)
+ src/Render/Unlit/TileMap/Code.hs view
@@ -0,0 +1,111 @@+module Render.Unlit.TileMap.Code+  ( vert+  , frag+  ) where++import RIO++import Render.Code (Code, glsl)+import Render.Samplers qualified as Samplers+import Render.DescSets.Set0.Code (set0binding0, set0binding1, set0binding2)++vert :: Code+vert = fromString+  [glsl|+    #version 450++    ${set0binding0}++    // vertexPos+    layout(location = 0) in vec3 vPosition;+    // vertexAttrs+    layout(location = 1) in vec2 vTexCoord;+    // tilemapParams+    layout(location = 2) in ivec4 iTextureIds; // combined: tileset, tileset sampler, map, repeat+    layout(location = 3) in vec2  iViewOffset;+    layout(location = 4) in vec2  iViewportSize;+    layout(location = 5) in vec2  iMapTextureSize;+    layout(location = 6) in vec2  iTilesetTextureSize;+    layout(location = 7) in vec2  iTileSize;++    // transformMat+    layout(location = 8) in mat4 iModel;++    layout(location = 0)      out  vec2 fTexCoord;+    layout(location = 1)      out  vec2 fPixCoord;+    layout(location = 2) flat out ivec4 fTextureIds;+    layout(location = 3) flat out  vec2 fTilesetTextureSize;+    layout(location = 4) flat out  vec2 fTileSize;++    void main() {+      vec4 fPosition = iModel * vec4(vPosition, 1.0);++      gl_Position+        = scene.projection+        * scene.view+        * fPosition;++      fPixCoord = (vTexCoord * iViewportSize) + iViewOffset;+      fTexCoord = fPixCoord / iMapTextureSize / iTileSize;++      fTextureIds = iTextureIds;+      fTilesetTextureSize = iTilesetTextureSize;+      fTileSize = iTileSize;+    }+  |]++frag :: Code+frag = fromString+  [glsl|+    #version 450+    #extension GL_EXT_nonuniform_qualifier : enable++    ${set0binding1}+    ${set0binding2}++    layout(location = 0) in vec2 fTexCoord;+    layout(location = 1) in vec2 fPixCoord;++    // combined: tileset, tileset sampler, map, repeat+    layout(location = 2) flat in ivec4 fTextureIds;+    layout(location = 3) flat in vec2 fTilesetTextureSize;+    layout(location = 4) flat in vec2 fTileSize;++    layout(location = 0) out vec4 oColor;++    int tilesetTextureIx = fTextureIds[0];+    int tilesetSamplerIx = fTextureIds[1];+    int mapTextureIx     = fTextureIds[2];+    int repeatTiles      = fTextureIds[3];++    // TODO+    // const vec4 fTextureGamma = vec4(1.0);++    void main() {+      if (repeatTiles == 0 && (fTexCoord.x < 0.0 || fTexCoord.y < 0.0 || fTexCoord.x > 1.0 || fTexCoord.y > 1.0)) {+        discard;+      }++      vec4 map = texture(+        sampler2D(+          textures[nonuniformEXT(mapTextureIx)],+          samplers[$samplerId]+        ),+        fTexCoord+      );++      vec2 spriteOffset = floor(map.xy * 256.0) * fTileSize;+      vec2 spriteCoord = mod(fPixCoord, fTileSize);+      vec2 spriteUV = round(spriteOffset + spriteCoord) / fTilesetTextureSize;++      oColor = texture(+        sampler2D(+          textures[nonuniformEXT(tilesetTextureIx)],+          samplers[nonuniformEXT(tilesetSamplerIx)]+        ),+        spriteUV+      );+    }+  |]+  where+    samplerId = Samplers.nearest Samplers.indices
src/Render/Unlit/TileMap/Pipeline.hs view
@@ -6,23 +6,26 @@   , Config   , config   , configBlend++  , stageCode   ) where  import RIO-import Render.DescSets.Set0.Code  import Control.Monad.Trans.Resource (ResourceT) import Data.Tagged (Tagged(..)) import Vulkan.Core10 qualified as Vk -import Engine.Vulkan.Pipeline qualified as Pipeline+import Engine.Vulkan.Pipeline.Graphics qualified as Graphics import Engine.Vulkan.Types (HasVulkan, HasRenderPass(..), DsBindings)-import Render.Code (compileVert, compileFrag, glsl)+import Render.Code (compileVert, compileFrag) import Render.DescSets.Set0 (Scene, vertexPos, instanceTransform)+import Render.Unlit.TileMap.Code qualified as Code import Render.Unlit.TileMap.Model qualified as Model -type Config = Pipeline.Configure Pipeline ()-type Pipeline = Pipeline.Pipeline '[Scene] Model.VertexAttrs Model.InstanceAttrs+type Pipeline = Graphics.Pipeline '[Scene] Model.VertexAttrs Model.InstanceAttrs+type Config = Graphics.Configure Pipeline+type instance Graphics.Specialization Pipeline = ()  allocate   :: ( HasVulkan env@@ -33,7 +36,7 @@   -> renderpass   -> ResourceT (RIO env) Pipeline allocate multisample tset0 rp = do-  (_, p) <- Pipeline.allocate+  (_, p) <- Graphics.allocate     Nothing     multisample     (config tset0)@@ -49,7 +52,7 @@   -> renderpass   -> ResourceT (RIO env) Pipeline allocateBlend multisample tset0 rp = do-  (_, p) <- Pipeline.allocate+  (_, p) <- Graphics.allocate     Nothing     multisample     (configBlend tset0)@@ -57,14 +60,13 @@   pure p  config :: Tagged Scene DsBindings -> Config-config (Tagged set0) = Pipeline.baseConfig-  { Pipeline.cDescLayouts  = Tagged @'[Scene] [set0]-  , Pipeline.cVertexCode   = Just vertCode-  , Pipeline.cVertexInput  = vertexInput-  , Pipeline.cFragmentCode = Just fragCode+config (Tagged set0) = Graphics.baseConfig+  { Graphics.cDescLayouts  = Tagged @'[Scene] [set0]+  , Graphics.cStages       = stageSpirv+  , Graphics.cVertexInput  = vertexInput   }   where-    vertexInput = Pipeline.vertexInput+    vertexInput = Graphics.vertexInput       [ vertexPos       , (Vk.VERTEX_INPUT_RATE_VERTEX,   Model.vkVertexAttrs)       , (Vk.VERTEX_INPUT_RATE_INSTANCE, Model.vkInstanceTileMap)@@ -73,107 +75,18 @@  configBlend :: Tagged Scene DsBindings -> Config configBlend tset0 = (config tset0)-  { Pipeline.cBlend      = True-  , Pipeline.cDepthWrite = False+  { Graphics.cBlend      = True+  , Graphics.cDepthWrite = False   } -vertCode :: ByteString-vertCode =-  $(compileVert [glsl|-    #version 450-    #extension GL_ARB_separate_shader_objects : enable--    ${set0binding0}--    // vertexPos-    layout(location = 0) in vec3 vPosition;-    // vertexAttrs-    layout(location = 1) in vec2 vTexCoord;-    // tilemapParams-    layout(location = 2) in ivec4 iTextureIds; // combined: tileset, tileset sampler, map, repeat-    layout(location = 3) in vec2  iViewOffset;-    layout(location = 4) in vec2  iViewportSize;-    layout(location = 5) in vec2  iMapTextureSize;-    layout(location = 6) in vec2  iTilesetTextureSize;-    layout(location = 7) in vec2  iTileSize;--    // transformMat-    layout(location = 8) in mat4 iModel;--    layout(location = 0)      out  vec2 fTexCoord;-    layout(location = 1)      out  vec2 fPixCoord;-    layout(location = 2) flat out ivec4 fTextureIds;-    layout(location = 3) flat out  vec2 fTilesetTextureSize;-    layout(location = 4) flat out  vec2 fTileSize;--    void main() {-      vec4 fPosition = iModel * vec4(vPosition, 1.0);--      gl_Position-        = scene.projection-        * scene.view-        * fPosition;--      fPixCoord = (vTexCoord * iViewportSize) + iViewOffset;-      fTexCoord = fPixCoord / iMapTextureSize / iTileSize;--      fTextureIds = iTextureIds;-      fTilesetTextureSize = iTilesetTextureSize;-      fTileSize = iTileSize;-    }-  |])--fragCode :: ByteString-fragCode =-  $(compileFrag [glsl|-    #version 450-    #extension GL_ARB_separate_shader_objects : enable-    #extension GL_EXT_nonuniform_qualifier : enable--    ${set0binding1}-    ${set0binding2}--    layout(location = 0) in vec2 fTexCoord;-    layout(location = 1) in vec2 fPixCoord;--    // combined: tileset, tileset sampler, map, repeat-    layout(location = 2) flat in ivec4 fTextureIds;-    layout(location = 3) flat in vec2 fTilesetTextureSize;-    layout(location = 4) flat in vec2 fTileSize;--    layout(location = 0) out vec4 oColor;--    int tilesetTextureIx = fTextureIds[0];-    int tilesetSamplerIx = fTextureIds[1];-    int mapTextureIx     = fTextureIds[2];-    int repeatTiles      = fTextureIds[3];--    // TODO-    // const vec4 fTextureGamma = vec4(1.0);--    void main() {-      if (repeatTiles == 0 && (fTexCoord.x < 0.0 || fTexCoord.y < 0.0 || fTexCoord.x > 1.0 || fTexCoord.y > 1.0)) {-        discard;-      }+stageCode  :: Graphics.StageCode+stageCode = Graphics.basicStages Code.vert Code.frag -      vec4 map = texture(-        sampler2D(-          textures[nonuniformEXT(mapTextureIx)],-          samplers[7] // nearest-        ),-        fTexCoord-      );+stageSpirv :: Graphics.StageSpirv+stageSpirv = Graphics.basicStages vertSpirv fragSpirv -      vec2 spriteOffset = floor(map.xy * 256.0) * fTileSize;-      vec2 spriteCoord = mod(fPixCoord, fTileSize);-      vec2 spriteUV = (spriteOffset + spriteCoord) / fTilesetTextureSize;+vertSpirv :: ByteString+vertSpirv = $(compileVert Code.vert) -      oColor = texture(-        sampler2D(-          textures[nonuniformEXT(tilesetTextureIx)],-          samplers[nonuniformEXT(tilesetSamplerIx)]-        ),-        spriteUV-      );-    }-  |])+fragSpirv :: ByteString+fragSpirv = $(compileFrag Code.frag)
src/Stage/Loader/Render.hs view
@@ -8,7 +8,7 @@ import RIO  import Engine.Types qualified as Engine-import Engine.Vulkan.Pipeline qualified as Pipeline+import Engine.Vulkan.Pipeline.Graphics qualified as Graphics import Engine.Vulkan.Swapchain qualified as Swapchain import Engine.Worker qualified as Worker import Render.Draw qualified as Draw@@ -48,9 +48,9 @@      Set0.withBoundSet0 frSceneUi pWireframe cb do       -- Render UI-      Pipeline.bind cb pUnlitTexturedBlend do+      Graphics.bind cb pUnlitTexturedBlend do         Draw.indexed cb (UI.quadUV ui) background         Draw.indexed cb (UI.quadUV ui) spinner -      Pipeline.bind cb pEvanwSdf $+      Graphics.bind cb pEvanwSdf $         traverse_ (Draw.quads cb) uiMessages
src/Stage/Loader/Setup.hs view
@@ -9,8 +9,9 @@  import Control.Monad.Trans.Resource (ResourceT) import Engine.Camera qualified as Camera+import Engine.Stage.Component qualified as Stage import Engine.StageSwitch (trySwitchStage)-import Engine.Types (StackStage(..), Stage(..), StageSetupRIO)+import Engine.Types (StackStage(..), StageSetupRIO) import Engine.Types qualified as Engine import Engine.UI.Layout qualified as Layout import Engine.UI.Message qualified as Message@@ -120,21 +121,13 @@   -> (loaded -> StackStage)   -> UI.Settings textures fonts   -> Basic.Stage FrameResources RunState-loaderStage loadAction nextStage uiSettings = Stage-  { sTitle = "Loader"--  , sAllocateRP = allocateRenderPass-  , sAllocateP  = allocatePipelines-  , sInitialRS  = initialRunState loadAction nextStage uiSettings-  , sInitialRR  = initialFrameResources uiSettings-  , sBeforeLoop = pure ()--  , sUpdateBuffers  = Render.updateBuffers-  , sRecordCommands = Render.recordCommands--  , sAfterLoop    = pure-  }+loaderStage loadAction nextStage uiSettings = Stage.assemble "Loader" rendering resources (Just scene)   where+    rendering = Stage.Rendering+      { rAllocateRP = allocateRenderPass+      , rAllocateP = allocatePipelines+      }+     allocateRenderPass swapchain = do       Basic.allocate         Basic.Settings@@ -157,6 +150,17 @@       (UI.combined uiSettings)       Nothing       0++    resources = Stage.Resources+      { rInitialRS = initialRunState loadAction nextStage uiSettings+      , rInitialRR = initialFrameResources uiSettings+      }++    scene = Stage.Scene+      { scBeforeLoop = pure ()+      , scUpdateBuffers = Render.updateBuffers+      , scRecordCommands = Render.recordCommands+      }  initialRunState   :: ((Text -> StageSetupRIO ()) -> StageSetupRIO loaded)