aboutsummaryrefslogtreecommitdiff
path: root/Graphics/Glyph/Shaders.hs
diff options
context:
space:
mode:
Diffstat (limited to 'Graphics/Glyph/Shaders.hs')
-rw-r--r--Graphics/Glyph/Shaders.hs109
1 files changed, 109 insertions, 0 deletions
diff --git a/Graphics/Glyph/Shaders.hs b/Graphics/Glyph/Shaders.hs
new file mode 100644
index 0000000..01f27b6
--- /dev/null
+++ b/Graphics/Glyph/Shaders.hs
@@ -0,0 +1,109 @@
+module Graphics.Glyph.Shaders where
+
+import Graphics.Rendering.OpenGL
+import qualified Data.ByteString as BS
+import qualified Data.ByteString.Lazy as BSL
+import Control.Monad
+import Data.Maybe
+import Data.List as List
+import Graphics.Glyph.Util
+
+{- Load a shader from a file giving the type of the shader
+ - to load.
+ - This function returns the shader log as a string and
+ - a shader as a maybe. Nothing if the shader didn't complie
+ - and Just if the shader did compile
+ -}
+class IsShaderSource a where
+ loadShader :: ShaderType -> a -> IO (String, Maybe Shader)
+
+instance IsShaderSource FilePath where
+ loadShader typ path = loadShader typ =<< BS.readFile path
+
+instance IsShaderSource BS.ByteString where
+ loadShader typ src = do
+ shader <- createShader typ
+ shaderSourceBS shader $= src
+ compileShader shader
+
+ ok <- get (compileStatus shader)
+ infoLog <- get (shaderInfoLog shader)
+
+ unless ok $
+ deleteObjectNames [shader]
+
+ return ( infoLog, if not ok then Nothing else Just shader );
+
+instance IsShaderSource BSL.ByteString where
+ loadShader typ = loadShader typ . toStrict
+ where toStrict = BS.concat . BSL.toChunks
+
+
+{- Load multiple shaders -}
+loadShaders :: (IsShaderSource a) => [(ShaderType,a)] -> IO [(String, Maybe Shader)]
+loadShaders = mapM ( uncurry loadShader )
+
+{- Return the sucessfully complied shaders
+ - as a new array of working shaders -}
+workingShaders :: [(a, Maybe Shader)] -> [Shader]
+workingShaders = mapMaybe snd
+
+{- Create a program from a list of working shaders -}
+createShaderProgram :: [Shader] -> IO (String, Maybe Program)
+createShaderProgram shaders = do
+ p <- createProgram
+ mapM_ (attachShader p) shaders
+ linkProgram p
+
+ ok <- get $ linkStatus p
+ info <- get $ programInfoLog p
+
+ unless ok $
+ deleteObjectNames [p]
+
+ return ( info, not ok ? Nothing $ Just p )
+
+{- Creates a shader program, but will only build the program if all the
+ - shaders compiled correctly -}
+createShaderProgramSafe :: [(String,Maybe Shader)] -> IO (String, Maybe Program)
+createShaderProgramSafe shaders =
+ not (List.all (isJust.snd) shaders) ?
+ return (concatMap fst shaders, Nothing) $
+ createShaderProgram $ workingShaders shaders
+
+
+{- Get the uniform form a program. -}
+getUniform :: Uniform a => String -> IO (Maybe (StateVar a))
+getUniform name =
+ get currentProgram >>= (\pr -> case pr of
+ Just p -> liftM (Just . uniform) (get $ uniformLocation p name)
+ Nothing -> return Nothing )
+
+getUniformForProgram :: Uniform a => String -> Program -> IO (StateVar a)
+getUniformForProgram name prog =
+ liftM uniform (get $ uniformLocation prog name)
+
+
+getUniformLocation :: String -> IO (Maybe UniformLocation)
+getUniformLocation name =
+ get currentProgram >>= maybe (return Nothing) (\prog ->
+ liftM Just (get $ uniformLocation prog name) )
+
+loadProgramSafe ::
+ (IsShaderSource a,
+ IsShaderSource b,
+ IsShaderSource c) =>
+ a -> b -> Maybe c -> IO (Maybe Program)
+loadProgramSafe vert frag geom = do
+ shaders <- sequence $ catMaybes [
+ Just $ loadShader VertexShader vert,
+ Just $ loadShader FragmentShader frag,
+ liftM (loadShader GeometryShader) geom]
+ -- mapM_ (putStrLn . fst) shaders
+ (linklog, maybeProg) <- createShaderProgramSafe shaders
+
+ if isNothing maybeProg then do
+ putStrLn "Failed to link program"
+ putStrLn linklog
+ return Nothing
+ else return maybeProg