aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author3gg <3gg@shellblade.net>2025-01-02 16:25:55 -0800
committer3gg <3gg@shellblade.net>2025-01-02 16:25:55 -0800
commitc639a9002f883a182c851b2bc0ae8f79e097c75b (patch)
tree40f36cad93682e282bbab87cb9de84dec2c712a7
parent9fcbd69c0e2ffc13d092db2656b5f28692980dd9 (diff)
Embed shaders in library.
-rw-r--r--Spear.cabal3
-rw-r--r--Spear/Render/Core/Shader.hs45
-rw-r--r--Spear/Render/Immediate.hs8
-rw-r--r--Spear/Render/Shaders.hs12
-rw-r--r--Spear/Render/Shaders/immediate_mode.frag10
-rw-r--r--Spear/Render/Shaders/immediate_mode.vert11
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
1module Spear.Render.Core.Shader 3module Spear.Render.Core.Shader
2( 4(
3 Define(..) 5 Define(..)
@@ -22,10 +24,13 @@ import Spear.Render.Core.State
22import Control.Monad (mapM_) 24import Control.Monad (mapM_)
23import Control.Monad.IO.Class 25import Control.Monad.IO.Class
24import Data.Bits 26import Data.Bits
27import Data.ByteString as B
25import Data.Hashable 28import Data.Hashable
26import Data.HashMap as HashMap 29import Data.HashMap as HashMap
27import Data.IORef 30import Data.IORef
28import Data.List (deleteBy, foldl', intercalate) 31import Data.List as List (deleteBy, foldl', intercalate)
32import Data.Text as T
33import Data.Text.Encoding as T
29import Foreign.C.String 34import Foreign.C.String
30import Foreign.Marshal.Alloc 35import Foreign.Marshal.Alloc
31import Foreign.Marshal.Array 36import Foreign.Marshal.Array
@@ -36,11 +41,12 @@ import Graphics.GL.Core46
36import Unsafe.Coerce 41import Unsafe.Coerce
37 42
38 43
39type Define = (String, String) 44type Define = (ByteString, ByteString)
40 45
41data ShaderSource 46data ShaderSource
42 = ShaderFromString String 47 = ShaderFromString String
43 | ShaderFromFile FilePath 48 | ShaderFromByteString ByteString
49 | ShaderFromFile FilePath
44 deriving Show 50 deriving Show
45 51
46data ShaderDesc = ShaderDesc 52data 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.
59header = "#version 400 core\n"
60
52 61
53compileShader :: ShaderDesc -> Game RenderCoreState Shader 62compileShader :: ShaderDesc -> Game RenderCoreState Shader
54compileShader (ShaderDesc shaderType source defines) = do 63compileShader (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
138deleteShader :: Shader -> Game RenderCoreState () 148deleteShader :: Shader -> Game RenderCoreState ()
139deleteShader shader = do 149deleteShader 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 ()
201deleteShaderProgram' = glDeleteProgram 211deleteShaderProgram' = glDeleteProgram
202 212
203hashShaders :: [Shader] -> Int 213hashShaders :: [Shader] -> Int
204hashShaders = foldl' hashF 0 214hashShaders = 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
207toGLShaderType :: ShaderType -> GLenum 217toGLShaderType :: ShaderType -> GLenum
@@ -209,9 +219,6 @@ toGLShaderType VertexShader = GL_VERTEX_SHADER
209toGLShaderType FragmentShader = GL_FRAGMENT_SHADER 219toGLShaderType FragmentShader = GL_FRAGMENT_SHADER
210toGLShaderType ComputeShader = GL_COMPUTE_SHADER 220toGLShaderType ComputeShader = GL_COMPUTE_SHADER
211 221
212makeDefinesString :: [Define] -> String 222makeDefinesString :: [Define] -> ByteString
213makeDefinesString defines = intercalate "\n" body ++ "\n" 223makeDefinesString 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.
217header = "#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
32import Spear.Render.Core.Geometry 32import Spear.Render.Core.Geometry
33import Spear.Render.Core.Shader 33import Spear.Render.Core.Shader
34import Spear.Render.Core.State hiding (shaders) 34import Spear.Render.Core.State hiding (shaders)
35import Spear.Render.Shaders as Shaders
35 36
36import Control.Monad (unless) 37import Control.Monad (unless)
37import Data.List (foldl') 38import Data.List (foldl')
@@ -47,11 +48,8 @@ data ImmRenderState = ImmRenderState
47 48
48newImmRenderer :: Game RenderCoreState ImmRenderState 49newImmRenderer :: Game RenderCoreState ImmRenderState
49newImmRenderer = do 50newImmRenderer = 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
3module Spear.Render.Shaders where
4
5import Data.ByteString
6import Data.FileEmbed
7
8immediateModeFrag :: ByteString
9immediateModeFrag = $(embedFile "Spear/Render/Shaders/immediate_mode.frag")
10
11immediateModeVert :: ByteString
12immediateModeVert = $(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 @@
1precision highp float;
2
3uniform vec4 Colour;
4
5out vec4 FragColour;
6
7void 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 @@
1precision highp float;
2
3uniform mat4 Model;
4uniform mat4 ViewProjection;
5
6layout (location = 0) in vec3 vPosition;
7
8void main()
9{
10 gl_Position = ViewProjection * Model * vec4(vPosition, 1.0);
11}