From c639a9002f883a182c851b2bc0ae8f79e097c75b Mon Sep 17 00:00:00 2001 From: 3gg <3gg@shellblade.net> Date: Thu, 2 Jan 2025 16:25:55 -0800 Subject: Embed shaders in library. --- Spear.cabal | 3 +++ Spear/Render/Core/Shader.hs | 45 ++++++++++++++++++-------------- Spear/Render/Immediate.hs | 8 +++--- Spear/Render/Shaders.hs | 12 +++++++++ Spear/Render/Shaders/immediate_mode.frag | 10 +++++++ Spear/Render/Shaders/immediate_mode.vert | 11 ++++++++ 6 files changed, 65 insertions(+), 24 deletions(-) create mode 100644 Spear/Render/Shaders.hs create mode 100644 Spear/Render/Shaders/immediate_mode.frag create mode 100644 Spear/Render/Shaders/immediate_mode.vert diff --git a/Spear.cabal b/Spear.cabal index ed37d66..0859a5c 100644 --- a/Spear.cabal +++ b/Spear.cabal @@ -23,9 +23,11 @@ library bytestring -any, directory -any, exceptions -any, + file-embed -any, hashable -any, hashmap -any, mtl -any, + text -any, transformers -any, resourcet -any, parsec >= 3, @@ -79,6 +81,7 @@ library Spear.Render.Material Spear.Render.Model Spear.Render.Program + Spear.Render.Shaders Spear.Render.StaticModel Spear.Scene.Graph Spear.Scene.Loader diff --git a/Spear/Render/Core/Shader.hs b/Spear/Render/Core/Shader.hs index 32a3cb1..ce29d4b 100644 --- a/Spear/Render/Core/Shader.hs +++ b/Spear/Render/Core/Shader.hs @@ -1,3 +1,5 @@ +{-# LANGUAGE OverloadedStrings #-} + module Spear.Render.Core.Shader ( Define(..) @@ -22,10 +24,13 @@ import Spear.Render.Core.State import Control.Monad (mapM_) import Control.Monad.IO.Class import Data.Bits +import Data.ByteString as B import Data.Hashable import Data.HashMap as HashMap import Data.IORef -import Data.List (deleteBy, foldl', intercalate) +import Data.List as List (deleteBy, foldl', intercalate) +import Data.Text as T +import Data.Text.Encoding as T import Foreign.C.String import Foreign.Marshal.Alloc import Foreign.Marshal.Array @@ -36,11 +41,12 @@ import Graphics.GL.Core46 import Unsafe.Coerce -type Define = (String, String) +type Define = (ByteString, ByteString) data ShaderSource - = ShaderFromString String - | ShaderFromFile FilePath + = ShaderFromString String + | ShaderFromByteString ByteString + | ShaderFromFile FilePath deriving Show data ShaderDesc = ShaderDesc @@ -49,12 +55,16 @@ data ShaderDesc = ShaderDesc , shaderDescDefines :: [Define] } +-- Header prepended to all shaders. +header = "#version 400 core\n" + compileShader :: ShaderDesc -> Game RenderCoreState Shader compileShader (ShaderDesc shaderType source defines) = do code <- case source of - ShaderFromString code -> return code - ShaderFromFile file -> liftIO $ readFile file + ShaderFromString code -> return (T.encodeUtf8 . T.pack $ code) + ShaderFromByteString code -> return code + ShaderFromFile file -> liftIO $ B.readFile file state <- get let shaderHash = hash code -- TODO: Should also include defines. case HashMap.lookup shaderHash (shaders state) of @@ -62,8 +72,8 @@ compileShader (ShaderDesc shaderType source defines) = do Nothing -> do let definesString = makeDefinesString defines handle <- liftIO $ glCreateShader (toGLShaderType shaderType) - liftIO $ withCStringLen code $ \(codeCString, codeLen) -> - withCStringLen definesString $ \(definesCString, definesLen) -> + liftIO $ B.useAsCStringLen code $ \(codeCString, codeLen) -> + B.useAsCStringLen definesString $ \(definesCString, definesLen) -> withCStringLen header $ \(headerCString, headerLen) -> withArray [headerCString, definesCString, codeCString] $ \strPtrs -> withArray (fromIntegral <$> [headerLen, definesLen, codeLen] :: [GLint]) @@ -80,7 +90,7 @@ compileShader (ShaderDesc shaderType source defines) = do len <- peek lenPtr case len of 0 -> return $ Just "" - _ -> withCString (replicate (fromIntegral len) '\0') $ \logPtr -> do + _ -> withCString (Prelude.replicate (fromIntegral len) '\0') $ \logPtr -> do glGetShaderInfoLog handle len nullPtr logPtr Just <$> peekCString logPtr _ -> return Nothing @@ -118,7 +128,7 @@ compileShaderProgram shaders = do len <- peek lenPtr case len of 0 -> return $ Just "Unknown error" - _ -> withCString (replicate (fromIntegral len) '\0') $ \logPtr -> do + _ -> withCString (Prelude.replicate (fromIntegral len) '\0') $ \logPtr -> do glGetShaderInfoLog handle len nullPtr logPtr Just <$> peekCString logPtr _ -> return Nothing @@ -133,7 +143,7 @@ compileShaderProgram shaders = do return program Just err -> gameError $ "Failed to compile shader program: " ++ err ++ "; shaders: " ++ - intercalate ", " (show . shaderHandle <$> shaders) + List.intercalate ", " (show . shaderHandle <$> shaders) deleteShader :: Shader -> Game RenderCoreState () deleteShader shader = do @@ -180,7 +190,7 @@ applyUniforms program = update (Mat4ArrayUniform name mat4s) = glGetUniformLocation' handle name >>= \location -> withArray mat4s $ \ptrMat4s -> - glUniformMatrix4fv location (fromIntegral $ length mat4s) GL_FALSE (unsafeCoerce ptrMat4s) + glUniformMatrix4fv location (fromIntegral $ Prelude.length mat4s) GL_FALSE (unsafeCoerce ptrMat4s) handle = shaderProgramHandle program in liftIO $ do uniforms <- readIORef (shaderProgramUniforms program) @@ -201,7 +211,7 @@ deleteShaderProgram' :: GLuint -> IO () deleteShaderProgram' = glDeleteProgram hashShaders :: [Shader] -> Int -hashShaders = foldl' hashF 0 +hashShaders = List.foldl' hashF 0 where hashF hash shader = (hash `shiftL` 32) .|. fromIntegral (shaderHandle shader) toGLShaderType :: ShaderType -> GLenum @@ -209,9 +219,6 @@ toGLShaderType VertexShader = GL_VERTEX_SHADER toGLShaderType FragmentShader = GL_FRAGMENT_SHADER toGLShaderType ComputeShader = GL_COMPUTE_SHADER -makeDefinesString :: [Define] -> String -makeDefinesString defines = intercalate "\n" body ++ "\n" - where body = (\(name, value) -> "#define " ++ name ++ " " ++ value) <$> defines - --- Header prepended to all shaders. -header = "#version 400 core\n" +makeDefinesString :: [Define] -> ByteString +makeDefinesString defines = B.concat[B.intercalate "\n" body, "\n"] + where body = (\(name, value) -> B.concat["#define ", name, " ", value]) <$> defines diff --git a/Spear/Render/Immediate.hs b/Spear/Render/Immediate.hs index 786e844..b9b72d2 100644 --- a/Spear/Render/Immediate.hs +++ b/Spear/Render/Immediate.hs @@ -32,6 +32,7 @@ import Spear.Render.Core.Buffer import Spear.Render.Core.Geometry import Spear.Render.Core.Shader import Spear.Render.Core.State hiding (shaders) +import Spear.Render.Shaders as Shaders import Control.Monad (unless) import Data.List (foldl') @@ -47,11 +48,8 @@ data ImmRenderState = ImmRenderState newImmRenderer :: Game RenderCoreState ImmRenderState newImmRenderer = do - -- TODO: Move shaders to Spear project. - vs <- compileShader $ ShaderDesc VertexShader - (ShaderFromFile "/home/jeanne/src/gfx/gfx/shaders/immediate_mode.vert") [] - ps <- compileShader $ ShaderDesc FragmentShader - (ShaderFromFile "/home/jeanne/src/gfx/gfx/shaders/immediate_mode.frag") [] + vs <- compileShader $ ShaderDesc VertexShader (ShaderFromByteString Shaders.immediateModeVert) [] + ps <- compileShader $ ShaderDesc FragmentShader (ShaderFromByteString Shaders.immediateModeFrag) [] shader <- compileShaderProgram [vs, ps] triangles <- makeGeometry $ newGeometryDesc diff --git a/Spear/Render/Shaders.hs b/Spear/Render/Shaders.hs new file mode 100644 index 0000000..bdf403d --- /dev/null +++ b/Spear/Render/Shaders.hs @@ -0,0 +1,12 @@ +{-# LANGUAGE TemplateHaskell #-} + +module Spear.Render.Shaders where + +import Data.ByteString +import Data.FileEmbed + +immediateModeFrag :: ByteString +immediateModeFrag = $(embedFile "Spear/Render/Shaders/immediate_mode.frag") + +immediateModeVert :: ByteString +immediateModeVert = $(embedFile "Spear/Render/Shaders/immediate_mode.vert") diff --git a/Spear/Render/Shaders/immediate_mode.frag b/Spear/Render/Shaders/immediate_mode.frag new file mode 100644 index 0000000..ac23b5c --- /dev/null +++ b/Spear/Render/Shaders/immediate_mode.frag @@ -0,0 +1,10 @@ +precision highp float; + +uniform vec4 Colour; + +out vec4 FragColour; + +void main() +{ + FragColour = vec4(pow(Colour.rgb, vec3(1.0/2.2)), Colour.a); +} diff --git a/Spear/Render/Shaders/immediate_mode.vert b/Spear/Render/Shaders/immediate_mode.vert new file mode 100644 index 0000000..65070bb --- /dev/null +++ b/Spear/Render/Shaders/immediate_mode.vert @@ -0,0 +1,11 @@ +precision highp float; + +uniform mat4 Model; +uniform mat4 ViewProjection; + +layout (location = 0) in vec3 vPosition; + +void main() +{ + gl_Position = ViewProjection * Model * vec4(vPosition, 1.0); +} -- cgit v1.2.3