diff options
author | 3gg <3gg@shellblade.net> | 2025-01-02 16:25:55 -0800 |
---|---|---|
committer | 3gg <3gg@shellblade.net> | 2025-01-02 16:25:55 -0800 |
commit | c639a9002f883a182c851b2bc0ae8f79e097c75b (patch) | |
tree | 40f36cad93682e282bbab87cb9de84dec2c712a7 | |
parent | 9fcbd69c0e2ffc13d092db2656b5f28692980dd9 (diff) |
Embed shaders in library.
-rw-r--r-- | Spear.cabal | 3 | ||||
-rw-r--r-- | Spear/Render/Core/Shader.hs | 45 | ||||
-rw-r--r-- | Spear/Render/Immediate.hs | 8 | ||||
-rw-r--r-- | Spear/Render/Shaders.hs | 12 | ||||
-rw-r--r-- | Spear/Render/Shaders/immediate_mode.frag | 10 | ||||
-rw-r--r-- | Spear/Render/Shaders/immediate_mode.vert | 11 |
6 files changed, 65 insertions, 24 deletions
diff --git a/Spear.cabal b/Spear.cabal index ed37d66..0859a5c 100644 --- a/Spear.cabal +++ b/Spear.cabal | |||
@@ -23,9 +23,11 @@ library | |||
23 | bytestring -any, | 23 | bytestring -any, |
24 | directory -any, | 24 | directory -any, |
25 | exceptions -any, | 25 | exceptions -any, |
26 | file-embed -any, | ||
26 | hashable -any, | 27 | hashable -any, |
27 | hashmap -any, | 28 | hashmap -any, |
28 | mtl -any, | 29 | mtl -any, |
30 | text -any, | ||
29 | transformers -any, | 31 | transformers -any, |
30 | resourcet -any, | 32 | resourcet -any, |
31 | parsec >= 3, | 33 | parsec >= 3, |
@@ -79,6 +81,7 @@ library | |||
79 | Spear.Render.Material | 81 | Spear.Render.Material |
80 | Spear.Render.Model | 82 | Spear.Render.Model |
81 | Spear.Render.Program | 83 | Spear.Render.Program |
84 | Spear.Render.Shaders | ||
82 | Spear.Render.StaticModel | 85 | Spear.Render.StaticModel |
83 | Spear.Scene.Graph | 86 | Spear.Scene.Graph |
84 | Spear.Scene.Loader | 87 | 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 @@ | |||
1 | {-# LANGUAGE OverloadedStrings #-} | ||
2 | |||
1 | module Spear.Render.Core.Shader | 3 | module Spear.Render.Core.Shader |
2 | ( | 4 | ( |
3 | Define(..) | 5 | Define(..) |
@@ -22,10 +24,13 @@ import Spear.Render.Core.State | |||
22 | import Control.Monad (mapM_) | 24 | import Control.Monad (mapM_) |
23 | import Control.Monad.IO.Class | 25 | import Control.Monad.IO.Class |
24 | import Data.Bits | 26 | import Data.Bits |
27 | import Data.ByteString as B | ||
25 | import Data.Hashable | 28 | import Data.Hashable |
26 | import Data.HashMap as HashMap | 29 | import Data.HashMap as HashMap |
27 | import Data.IORef | 30 | import Data.IORef |
28 | import Data.List (deleteBy, foldl', intercalate) | 31 | import Data.List as List (deleteBy, foldl', intercalate) |
32 | import Data.Text as T | ||
33 | import Data.Text.Encoding as T | ||
29 | import Foreign.C.String | 34 | import Foreign.C.String |
30 | import Foreign.Marshal.Alloc | 35 | import Foreign.Marshal.Alloc |
31 | import Foreign.Marshal.Array | 36 | import Foreign.Marshal.Array |
@@ -36,11 +41,12 @@ import Graphics.GL.Core46 | |||
36 | import Unsafe.Coerce | 41 | import Unsafe.Coerce |
37 | 42 | ||
38 | 43 | ||
39 | type Define = (String, String) | 44 | type Define = (ByteString, ByteString) |
40 | 45 | ||
41 | data ShaderSource | 46 | data ShaderSource |
42 | = ShaderFromString String | 47 | = ShaderFromString String |
43 | | ShaderFromFile FilePath | 48 | | ShaderFromByteString ByteString |
49 | | ShaderFromFile FilePath | ||
44 | deriving Show | 50 | deriving Show |
45 | 51 | ||
46 | data ShaderDesc = ShaderDesc | 52 | data ShaderDesc = ShaderDesc |
@@ -49,12 +55,16 @@ data ShaderDesc = ShaderDesc | |||
49 | , shaderDescDefines :: [Define] | 55 | , shaderDescDefines :: [Define] |
50 | } | 56 | } |
51 | 57 | ||
58 | -- Header prepended to all shaders. | ||
59 | header = "#version 400 core\n" | ||
60 | |||
52 | 61 | ||
53 | compileShader :: ShaderDesc -> Game RenderCoreState Shader | 62 | compileShader :: ShaderDesc -> Game RenderCoreState Shader |
54 | compileShader (ShaderDesc shaderType source defines) = do | 63 | compileShader (ShaderDesc shaderType source defines) = do |
55 | code <- case source of | 64 | code <- case source of |
56 | ShaderFromString code -> return code | 65 | ShaderFromString code -> return (T.encodeUtf8 . T.pack $ code) |
57 | ShaderFromFile file -> liftIO $ readFile file | 66 | ShaderFromByteString code -> return code |
67 | ShaderFromFile file -> liftIO $ B.readFile file | ||
58 | state <- get | 68 | state <- get |
59 | let shaderHash = hash code -- TODO: Should also include defines. | 69 | let shaderHash = hash code -- TODO: Should also include defines. |
60 | case HashMap.lookup shaderHash (shaders state) of | 70 | case HashMap.lookup shaderHash (shaders state) of |
@@ -62,8 +72,8 @@ compileShader (ShaderDesc shaderType source defines) = do | |||
62 | Nothing -> do | 72 | Nothing -> do |
63 | let definesString = makeDefinesString defines | 73 | let definesString = makeDefinesString defines |
64 | handle <- liftIO $ glCreateShader (toGLShaderType shaderType) | 74 | handle <- liftIO $ glCreateShader (toGLShaderType shaderType) |
65 | liftIO $ withCStringLen code $ \(codeCString, codeLen) -> | 75 | liftIO $ B.useAsCStringLen code $ \(codeCString, codeLen) -> |
66 | withCStringLen definesString $ \(definesCString, definesLen) -> | 76 | B.useAsCStringLen definesString $ \(definesCString, definesLen) -> |
67 | withCStringLen header $ \(headerCString, headerLen) -> | 77 | withCStringLen header $ \(headerCString, headerLen) -> |
68 | withArray [headerCString, definesCString, codeCString] $ \strPtrs -> | 78 | withArray [headerCString, definesCString, codeCString] $ \strPtrs -> |
69 | withArray (fromIntegral <$> [headerLen, definesLen, codeLen] :: [GLint]) | 79 | withArray (fromIntegral <$> [headerLen, definesLen, codeLen] :: [GLint]) |
@@ -80,7 +90,7 @@ compileShader (ShaderDesc shaderType source defines) = do | |||
80 | len <- peek lenPtr | 90 | len <- peek lenPtr |
81 | case len of | 91 | case len of |
82 | 0 -> return $ Just "" | 92 | 0 -> return $ Just "" |
83 | _ -> withCString (replicate (fromIntegral len) '\0') $ \logPtr -> do | 93 | _ -> withCString (Prelude.replicate (fromIntegral len) '\0') $ \logPtr -> do |
84 | glGetShaderInfoLog handle len nullPtr logPtr | 94 | glGetShaderInfoLog handle len nullPtr logPtr |
85 | Just <$> peekCString logPtr | 95 | Just <$> peekCString logPtr |
86 | _ -> return Nothing | 96 | _ -> return Nothing |
@@ -118,7 +128,7 @@ compileShaderProgram shaders = do | |||
118 | len <- peek lenPtr | 128 | len <- peek lenPtr |
119 | case len of | 129 | case len of |
120 | 0 -> return $ Just "Unknown error" | 130 | 0 -> return $ Just "Unknown error" |
121 | _ -> withCString (replicate (fromIntegral len) '\0') $ \logPtr -> do | 131 | _ -> withCString (Prelude.replicate (fromIntegral len) '\0') $ \logPtr -> do |
122 | glGetShaderInfoLog handle len nullPtr logPtr | 132 | glGetShaderInfoLog handle len nullPtr logPtr |
123 | Just <$> peekCString logPtr | 133 | Just <$> peekCString logPtr |
124 | _ -> return Nothing | 134 | _ -> return Nothing |
@@ -133,7 +143,7 @@ compileShaderProgram shaders = do | |||
133 | return program | 143 | return program |
134 | Just err -> gameError $ | 144 | Just err -> gameError $ |
135 | "Failed to compile shader program: " ++ err ++ "; shaders: " ++ | 145 | "Failed to compile shader program: " ++ err ++ "; shaders: " ++ |
136 | intercalate ", " (show . shaderHandle <$> shaders) | 146 | List.intercalate ", " (show . shaderHandle <$> shaders) |
137 | 147 | ||
138 | deleteShader :: Shader -> Game RenderCoreState () | 148 | deleteShader :: Shader -> Game RenderCoreState () |
139 | deleteShader shader = do | 149 | deleteShader shader = do |
@@ -180,7 +190,7 @@ applyUniforms program = | |||
180 | update (Mat4ArrayUniform name mat4s) = | 190 | update (Mat4ArrayUniform name mat4s) = |
181 | glGetUniformLocation' handle name >>= | 191 | glGetUniformLocation' handle name >>= |
182 | \location -> withArray mat4s $ \ptrMat4s -> | 192 | \location -> withArray mat4s $ \ptrMat4s -> |
183 | glUniformMatrix4fv location (fromIntegral $ length mat4s) GL_FALSE (unsafeCoerce ptrMat4s) | 193 | glUniformMatrix4fv location (fromIntegral $ Prelude.length mat4s) GL_FALSE (unsafeCoerce ptrMat4s) |
184 | handle = shaderProgramHandle program | 194 | handle = shaderProgramHandle program |
185 | in liftIO $ do | 195 | in liftIO $ do |
186 | uniforms <- readIORef (shaderProgramUniforms program) | 196 | uniforms <- readIORef (shaderProgramUniforms program) |
@@ -201,7 +211,7 @@ deleteShaderProgram' :: GLuint -> IO () | |||
201 | deleteShaderProgram' = glDeleteProgram | 211 | deleteShaderProgram' = glDeleteProgram |
202 | 212 | ||
203 | hashShaders :: [Shader] -> Int | 213 | hashShaders :: [Shader] -> Int |
204 | hashShaders = foldl' hashF 0 | 214 | hashShaders = List.foldl' hashF 0 |
205 | where hashF hash shader = (hash `shiftL` 32) .|. fromIntegral (shaderHandle shader) | 215 | where hashF hash shader = (hash `shiftL` 32) .|. fromIntegral (shaderHandle shader) |
206 | 216 | ||
207 | toGLShaderType :: ShaderType -> GLenum | 217 | toGLShaderType :: ShaderType -> GLenum |
@@ -209,9 +219,6 @@ toGLShaderType VertexShader = GL_VERTEX_SHADER | |||
209 | toGLShaderType FragmentShader = GL_FRAGMENT_SHADER | 219 | toGLShaderType FragmentShader = GL_FRAGMENT_SHADER |
210 | toGLShaderType ComputeShader = GL_COMPUTE_SHADER | 220 | toGLShaderType ComputeShader = GL_COMPUTE_SHADER |
211 | 221 | ||
212 | makeDefinesString :: [Define] -> String | 222 | makeDefinesString :: [Define] -> ByteString |
213 | makeDefinesString defines = intercalate "\n" body ++ "\n" | 223 | makeDefinesString defines = B.concat[B.intercalate "\n" body, "\n"] |
214 | where body = (\(name, value) -> "#define " ++ name ++ " " ++ value) <$> defines | 224 | where body = (\(name, value) -> B.concat["#define ", name, " ", value]) <$> defines |
215 | |||
216 | -- Header prepended to all shaders. | ||
217 | header = "#version 400 core\n" | ||
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 | |||
32 | import Spear.Render.Core.Geometry | 32 | import Spear.Render.Core.Geometry |
33 | import Spear.Render.Core.Shader | 33 | import Spear.Render.Core.Shader |
34 | import Spear.Render.Core.State hiding (shaders) | 34 | import Spear.Render.Core.State hiding (shaders) |
35 | import Spear.Render.Shaders as Shaders | ||
35 | 36 | ||
36 | import Control.Monad (unless) | 37 | import Control.Monad (unless) |
37 | import Data.List (foldl') | 38 | import Data.List (foldl') |
@@ -47,11 +48,8 @@ data ImmRenderState = ImmRenderState | |||
47 | 48 | ||
48 | newImmRenderer :: Game RenderCoreState ImmRenderState | 49 | newImmRenderer :: Game RenderCoreState ImmRenderState |
49 | newImmRenderer = do | 50 | newImmRenderer = do |
50 | -- TODO: Move shaders to Spear project. | 51 | vs <- compileShader $ ShaderDesc VertexShader (ShaderFromByteString Shaders.immediateModeVert) [] |
51 | vs <- compileShader $ ShaderDesc VertexShader | 52 | ps <- compileShader $ ShaderDesc FragmentShader (ShaderFromByteString Shaders.immediateModeFrag) [] |
52 | (ShaderFromFile "/home/jeanne/src/gfx/gfx/shaders/immediate_mode.vert") [] | ||
53 | ps <- compileShader $ ShaderDesc FragmentShader | ||
54 | (ShaderFromFile "/home/jeanne/src/gfx/gfx/shaders/immediate_mode.frag") [] | ||
55 | shader <- compileShaderProgram [vs, ps] | 53 | shader <- compileShaderProgram [vs, ps] |
56 | 54 | ||
57 | triangles <- makeGeometry $ newGeometryDesc | 55 | 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 @@ | |||
1 | {-# LANGUAGE TemplateHaskell #-} | ||
2 | |||
3 | module Spear.Render.Shaders where | ||
4 | |||
5 | import Data.ByteString | ||
6 | import Data.FileEmbed | ||
7 | |||
8 | immediateModeFrag :: ByteString | ||
9 | immediateModeFrag = $(embedFile "Spear/Render/Shaders/immediate_mode.frag") | ||
10 | |||
11 | immediateModeVert :: ByteString | ||
12 | 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 @@ | |||
1 | precision highp float; | ||
2 | |||
3 | uniform vec4 Colour; | ||
4 | |||
5 | out vec4 FragColour; | ||
6 | |||
7 | void main() | ||
8 | { | ||
9 | FragColour = vec4(pow(Colour.rgb, vec3(1.0/2.2)), Colour.a); | ||
10 | } | ||
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 @@ | |||
1 | precision highp float; | ||
2 | |||
3 | uniform mat4 Model; | ||
4 | uniform mat4 ViewProjection; | ||
5 | |||
6 | layout (location = 0) in vec3 vPosition; | ||
7 | |||
8 | void main() | ||
9 | { | ||
10 | gl_Position = ViewProjection * Model * vec4(vPosition, 1.0); | ||
11 | } | ||