keid-render-basic 0.1.6.0 → 0.1.6.1
raw patch · 10 files changed
+351/−33 lines, 10 filesdep −adjunctionsdep −distributivedep ~keid-corePVP: major bump suggested
API removals or changes: PVP suggests a major version bump
Dependencies removed: adjunctions, distributive
Dependency ranges changed: keid-core
API changes (from Hackage documentation)
- Global.Resource.CubeMap.Base: instance Data.Distributive.Distributive Global.Resource.CubeMap.Base.Collection
- Global.Resource.CubeMap.Base: instance Data.Functor.Rep.Representable Global.Resource.CubeMap.Base.Collection
- Global.Resource.CubeMap.Base: instance GHC.Generics.Generic (Global.Resource.CubeMap.Base.Collection a)
- Global.Resource.Texture.Base: instance Data.Distributive.Distributive Global.Resource.Texture.Base.Collection
- Global.Resource.Texture.Base: instance Data.Functor.Rep.Representable Global.Resource.Texture.Base.Collection
- Global.Resource.Texture.Base: instance GHC.Generics.Generic (Global.Resource.Texture.Base.Collection a)
+ Render.Basic: [$sel:pSprite:Pipelines] :: Pipelines -> Pipeline
+ Render.Basic: [$sel:pSpriteOutline:Pipelines] :: Pipelines -> Pipeline
+ Render.Unlit.Colored.Model: black :: VertexAttrs
+ Render.Unlit.Colored.Model: rgbF :: Float -> Float -> Float -> VertexAttrs
+ Render.Unlit.Colored.Model: white :: VertexAttrs
+ Render.Unlit.Sprite.Model: InstanceAttrs :: Vec4 -> Vec4 -> Vec4 -> Vec4 -> Int32 -> Int32 -> UVec2 -> InstanceAttrs
+ Render.Unlit.Sprite.Model: [$sel:fragRect:InstanceAttrs] :: InstanceAttrs -> Vec4
+ Render.Unlit.Sprite.Model: [$sel:outline:InstanceAttrs] :: InstanceAttrs -> Vec4
+ Render.Unlit.Sprite.Model: [$sel:samplerId:InstanceAttrs] :: InstanceAttrs -> Int32
+ Render.Unlit.Sprite.Model: [$sel:textureId:InstanceAttrs] :: InstanceAttrs -> Int32
+ Render.Unlit.Sprite.Model: [$sel:textureSize:InstanceAttrs] :: InstanceAttrs -> UVec2
+ Render.Unlit.Sprite.Model: [$sel:tint:InstanceAttrs] :: InstanceAttrs -> Vec4
+ Render.Unlit.Sprite.Model: [$sel:vertRect:InstanceAttrs] :: InstanceAttrs -> Vec4
+ Render.Unlit.Sprite.Model: data InstanceAttrs
+ Render.Unlit.Sprite.Model: fromAtlas :: Int32 -> Atlas -> Vec2 -> Vec2 -> Vec2 -> InstanceAttrs
+ Render.Unlit.Sprite.Model: fromTexture :: Int32 -> Int32 -> Vec2 -> Vec2 -> InstanceAttrs
+ Render.Unlit.Sprite.Model: instance Foreign.Storable.Generic.Internal.GStorable Render.Unlit.Sprite.Model.InstanceAttrs
+ Render.Unlit.Sprite.Model: instance GHC.Generics.Generic Render.Unlit.Sprite.Model.InstanceAttrs
+ Render.Unlit.Sprite.Model: instance GHC.Show.Show Render.Unlit.Sprite.Model.InstanceAttrs
+ Render.Unlit.Sprite.Model: instance Vulkan.Zero.Zero Render.Unlit.Sprite.Model.InstanceAttrs
+ Render.Unlit.Sprite.Model: type InstanceBuffer stage = Allocated stage InstanceAttrs
+ Render.Unlit.Sprite.Model: type StorableAttrs = Vector InstanceAttrs
+ Render.Unlit.Sprite.Model: vkInstanceAttrs :: [Format]
+ Render.Unlit.Sprite.Pipeline: allocate :: (HasVulkan env, HasRenderPass renderpass) => SampleCountFlagBits -> Maybe Float -> Bool -> Tagged Scene DsBindings -> renderpass -> ResourceT (RIO env) Pipeline
+ Render.Unlit.Sprite.Pipeline: type Pipeline = Pipeline '[Scene] () InstanceAttrs
- 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 -> Pipelines
+ 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
Files
- ChangeLog.md +7/−0
- keid-render-basic.cabal +5/−5
- src/Global/Resource/CubeMap/Base.hs +3/−9
- src/Global/Resource/Texture/Base.hs +3/−9
- src/Render/Basic.hs +8/−2
- src/Render/Unlit/Colored/Model.hs +19/−1
- src/Render/Unlit/Sprite/Model.hs +113/−0
- src/Render/Unlit/Sprite/Pipeline.hs +184/−0
- src/Resource/Font.hs +1/−1
- src/Resource/Font/EvanW.hs +8/−6
ChangeLog.md view
@@ -1,5 +1,12 @@ # Changelog for keid-render-basic +## 0.1.6.1++- `withFrozenCallStack` fixes for GHC-9.0.+- Added color helpers to `Render.Unlit.Colored`.+- Added `Render.Unlit.Sprite` pipeline.+ * Available as `pSprite` and `pSpriteOutline`.+ ## 0.1.6.0 - Updated `Loader` stage to camera changes in core.
keid-render-basic.cabal view
@@ -5,7 +5,7 @@ -- see: https://github.com/sol/hpack name: keid-render-basic-version: 0.1.6.0+version: 0.1.6.1 synopsis: Basic rendering programs for Keid engine. category: Game Engine homepage: https://keid.haskell-game.dev@@ -59,6 +59,8 @@ Render.Skybox.Pipeline Render.Unlit.Colored.Model Render.Unlit.Colored.Pipeline+ Render.Unlit.Sprite.Model+ Render.Unlit.Sprite.Pipeline Render.Unlit.Textured.Model Render.Unlit.Textured.Pipeline Render.Unlit.TileMap.Model@@ -134,16 +136,14 @@ ViewPatterns ghc-options: -Wall -Wcompat -Widentities -Wincomplete-record-updates -Wincomplete-uni-patterns -Wpartial-fields -Wredundant-constraints build-depends:- adjunctions- , aeson+ aeson , base >=4.7 && <5 , bytestring , derive-storable , derive-storable-plugin- , distributive , file-embed >=0.0.10 , geomancy- , keid-core >=0.1.6.0+ , keid-core >=0.1.6.1 , keid-geometry , neat-interpolation , resourcet
src/Global/Resource/CubeMap/Base.hs view
@@ -9,24 +9,18 @@ import RIO -import Data.Distributive (Distributive(..))-import Data.Distributive.Generic (genericCollect)-import Data.Functor.Rep (Co(..), Representable) import GHC.Generics (Generic1) import Resource.Source (Source) import Resource.Source qualified as Source+import Resource.Collection (Generically1(..)) import Global.Resource.CubeMap.Base.Paths qualified as Paths data Collection a = Collection { black :: a }- deriving stock (Show, Functor, Foldable, Traversable, Generic, Generic1)- deriving Applicative via (Co Collection)- deriving anyclass (Representable)--instance Distributive Collection where- collect = genericCollect+ deriving stock (Show, Functor, Foldable, Traversable, Generic1)+ deriving Applicative via Generically1 Collection sources :: Collection Source sources = Collection
src/Global/Resource/Texture/Base.hs view
@@ -9,10 +9,8 @@ import RIO -import Data.Distributive (Distributive(..))-import Data.Distributive.Generic (genericCollect)-import Data.Functor.Rep (Co(..), Representable) import GHC.Generics (Generic1)+import Resource.Collection (Generically1(..)) import Resource.Source (Source) import Resource.Source qualified as Source @@ -23,12 +21,8 @@ , flat :: a , ibl_brdf_lut :: a }- deriving stock (Show, Functor, Foldable, Traversable, Generic, Generic1)- deriving Applicative via (Co Collection)- deriving anyclass (Representable)--instance Distributive Collection where- collect = genericCollect+ deriving stock (Show, Functor, Foldable, Traversable, Generic1)+ deriving Applicative via Generically1 Collection sources :: Collection Source sources = Collection
src/Render/Basic.hs view
@@ -40,6 +40,7 @@ import Render.ShadowMap.RenderPass qualified as ShadowPass import Render.Skybox.Pipeline qualified as Skybox import Render.Unlit.Colored.Pipeline qualified as UnlitColored+import Render.Unlit.Sprite.Pipeline qualified as UnlitSprite import Render.Unlit.Textured.Pipeline qualified as UnlitTextured import Render.Unlit.TileMap.Pipeline qualified as UnlitTileMap @@ -125,6 +126,9 @@ , pUnlitColoredNoDepth :: UnlitColored.Pipeline , pUnlitTextured :: UnlitTextured.Pipeline , pUnlitTexturedBlend :: UnlitTextured.Pipeline++ , pSprite :: UnlitSprite.Pipeline+ , pSpriteOutline :: UnlitSprite.Pipeline , pTileMap :: UnlitTileMap.Pipeline , pTileMapBlend :: UnlitTileMap.Pipeline , pWireframe :: UnlitColored.Pipeline@@ -169,12 +173,14 @@ pLitTextured <- LitTextured.allocate pMSAA pSceneBinds rpForwardMsaa pLitTexturedBlend <- LitTextured.allocateBlend pMSAA pSceneBinds rpForwardMsaa + pSprite <- UnlitSprite.allocate pMSAA Nothing False pSceneBinds rpForwardMsaa+ pSpriteOutline <- UnlitSprite.allocate pMSAA Nothing True pSceneBinds rpForwardMsaa+ pTileMap <- UnlitTileMap.allocate pMSAA pSceneBinds rpForwardMsaa+ pTileMapBlend <- UnlitTileMap.allocateBlend pMSAA pSceneBinds rpForwardMsaa pUnlitColored <- UnlitColored.allocate True pMSAA pSceneBinds rpForwardMsaa pUnlitColoredNoDepth <- UnlitColored.allocate False pMSAA pSceneBinds rpForwardMsaa pUnlitTextured <- UnlitTextured.allocate pMSAA pSceneBinds rpForwardMsaa pUnlitTexturedBlend <- UnlitTextured.allocateBlend pMSAA pSceneBinds rpForwardMsaa- pTileMap <- UnlitTileMap.allocate pMSAA pSceneBinds rpForwardMsaa- pTileMapBlend <- UnlitTileMap.allocateBlend pMSAA pSceneBinds rpForwardMsaa pWireframe <- UnlitColored.allocateWireframe True pMSAA pSceneBinds rpForwardMsaa pWireframeNoDepth <- UnlitColored.allocateWireframe False pMSAA pSceneBinds rpForwardMsaa
src/Render/Unlit/Colored/Model.hs view
@@ -4,10 +4,16 @@ , VertexAttrs , vkVertexAttrs + , rgbF+ , black+ , white+ , InstanceAttrs ) where -import Geomancy (Transform, Vec4)+import RIO++import Geomancy (Transform, Vec4, vec4) import Geomancy.Vec3 qualified as Vec3 import Resource.Model qualified as Model import Vulkan.Core10 qualified as Vk@@ -23,3 +29,15 @@ vkVertexAttrs = [ Vk.FORMAT_R32G32B32A32_SFLOAT -- vColor :: vec4 ]++{-# INLINE rgbF #-}+rgbF :: Float -> Float -> Float -> VertexAttrs+rgbF r g b = vec4 r g b 1++{-# INLINE black #-}+black :: VertexAttrs+black = rgbF 0 0 0++{-# INLINE white #-}+white :: VertexAttrs+white = rgbF 1 1 1
+ src/Render/Unlit/Sprite/Model.hs view
@@ -0,0 +1,113 @@+{-# OPTIONS_GHC -fplugin Foreign.Storable.Generic.Plugin #-}++module Render.Unlit.Sprite.Model+ ( InstanceAttrs(..)+ , StorableAttrs+ , InstanceBuffer+ , fromTexture+ , fromAtlas++ , vkInstanceAttrs+ ) where++import RIO++import Foreign.Storable.Generic (GStorable)+import Geomancy (Vec2, Vec4, UVec2, withUVec2, vec2)+import Geomancy.Vec4 qualified as Vec4+import Render.Samplers qualified as Samplers+import Resource.Buffer qualified as Buffer+import Resource.Image.Atlas (Atlas)+import Resource.Image.Atlas qualified as Atlas+import RIO.Vector.Storable qualified as Storable+import Vulkan.Core10 qualified as Vk+import Vulkan.Zero (Zero(..))++type StorableAttrs = Storable.Vector InstanceAttrs++data InstanceAttrs = InstanceAttrs+ { vertRect :: Vec4+ , fragRect :: Vec4++ , tint :: Vec4+ , outline :: Vec4++ , samplerId :: Int32+ , textureId :: Int32+ , textureSize :: UVec2+ }+ deriving (Show, Generic)++instance GStorable InstanceAttrs++instance Zero InstanceAttrs where+ zero = InstanceAttrs+ { vertRect = 0+ , fragRect = 0++ , tint = 0+ , outline = 0++ , samplerId = 0+ , textureId = 0+ , textureSize = 0+ }++vkInstanceAttrs :: [Vk.Format]+vkInstanceAttrs =+ [ Vk.FORMAT_R32G32B32A32_SFLOAT -- Quad scale+offset+ , Vk.FORMAT_R32G32B32A32_SFLOAT -- UV scale+offset+ , Vk.FORMAT_R32G32B32A32_SFLOAT -- Tint+ , Vk.FORMAT_R32G32B32A32_SFLOAT -- Outline (when enabled)++ , Vk.FORMAT_R32G32_SINT -- Sampler + texture IDs+ , Vk.FORMAT_R32G32_UINT -- Texture size+ ]++type InstanceBuffer stage = Buffer.Allocated stage InstanceAttrs++fromTexture+ :: Int32 -- ^ Sampler index.+ -> Int32 -- ^ Texture index.+ -> Vec2 -- ^ Sprite size.+ -> Vec2 -- ^ Sprite position.+ -> InstanceAttrs+fromTexture sampler texture wh pos =+ InstanceAttrs+ { vertRect = Vec4.fromVec22 pos wh+ , fragRect = Vec4.fromVec22 0 1++ , tint = 1+ , outline = 0++ , samplerId = sampler+ , textureId = texture+ , textureSize = 0+ }++fromAtlas+ :: Int32 -- ^ Texture ID.+ -> Atlas+ -> Vec2 -- ^ Sprite scale, wrt. to native tile size+ -> Vec2 -- ^ Tile position in atlas tiles. Can be fractional when using subgrids.+ -> Vec2 -- ^ Sprite position.+ -> InstanceAttrs+fromAtlas texture atlas scale atlasPos worldPos =+ InstanceAttrs+ { vertRect = Vec4.fromVec22 worldPos (tileSize * scale)+ , fragRect = Vec4.fromVec22 (atlasPos * uvScale) uvScale++ , tint = 1+ , outline = 0++ , samplerId = Samplers.nearest Samplers.indices+ , textureId = texture+ , textureSize = Atlas.sizePx atlas+ }++ where+ uvScale = Atlas.uvScale atlas++ tileSize =+ withUVec2 (Atlas.tileSizePx atlas) \tw th ->+ vec2 (fromIntegral tw) (fromIntegral th)
+ src/Render/Unlit/Sprite/Pipeline.hs view
@@ -0,0 +1,184 @@+{-# LANGUAGE OverloadedLists #-}++module Render.Unlit.Sprite.Pipeline+ ( Pipeline+ , allocate+ -- , allocateOutline+ ) where++import RIO++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.Types (HasVulkan, HasRenderPass(..), DsBindings)+import Render.Code (compileVert, compileFrag, glsl)+import Render.DescSets.Set0 (Scene)+import Render.DescSets.Set0.Code (set0binding0, set0binding1, set0binding2)+import Render.Unlit.Sprite.Model qualified as Model++type Config = Pipeline.Configure Pipeline (Float, Bool)+type Pipeline = Pipeline.Pipeline '[Scene] () Model.InstanceAttrs++allocate+ :: ( HasVulkan env+ , HasRenderPass renderpass+ )+ => Vk.SampleCountFlagBits+ -> Maybe Float+ -> Bool+ -> Tagged Scene DsBindings+ -> renderpass+ -> ResourceT (RIO env) Pipeline+allocate multisample discardAlpha outline set0 = do+ fmap snd . Pipeline.allocate+ Nothing+ multisample+ (config discardAlpha outline set0)++config+ :: Maybe Float+ -> Bool+ -> 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+ }+ where+ vertexInput = Pipeline.vertexInput+ [ (Vk.VERTEX_INPUT_RATE_INSTANCE, Model.vkInstanceAttrs)+ ]++ specs =+ ( fromMaybe 0.0 discardAlpha+ , 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;++ 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/Resource/Font.hs view
@@ -73,7 +73,7 @@ container <- withFrozenCallStack $ EvanW.load configContainer - createTexture <- toIO . withFrozenCallStack $+ createTexture <- toIO $ withFrozenCallStack $ Ktx1.load pools configTexture (textureKey, texture) <- Resource.allocate
src/Resource/Font/EvanW.hs view
@@ -68,12 +68,14 @@ , HasCallStack ) => Source -> m Container-load = withFrozenCallStack . Source.load \bytes ->- case eitherDecodeStrict' bytes of- Left err ->- liftIO . throwIO . FontError $ Text.pack err- Right res ->- pure res+load =+ withFrozenCallStack $+ Source.load \bytes ->+ case eitherDecodeStrict' bytes of+ Left err ->+ liftIO . throwIO . FontError $ Text.pack err+ Right res ->+ pure res -- * Typesetting