halive-0.1.1: demo/Shader.hs
module Shader where
import Graphics.GL
import Control.Monad
import Control.Monad.Trans
import Foreign
import Foreign.C.String
import qualified Data.ByteString as BS
import qualified Data.Text.Encoding as Text
import qualified Data.Text.IO as Text
import Linear
import Data.Foldable
newtype GLProgram = GLProgram { unGLProgram :: GLuint }
newtype AttributeLocation = AttributeLocation { unAttributeLocation :: GLint }
newtype UniformLocation = UniformLocation { unUniformLocation :: GLint }
overPtr :: (MonadIO m, Storable a) => (Ptr a -> IO b) -> m a
overPtr f = liftIO (alloca (\p -> f p >> peek p))
useProgram :: MonadIO m => GLProgram -> m ()
useProgram (GLProgram program) = glUseProgram (fromIntegral program)
uniformM44 :: UniformLocation -> M44 GLfloat -> IO ()
uniformM44 uniform matrix = do
let mvpUniformLoc = fromIntegral (unUniformLocation uniform)
withArray (concatMap toList (transpose matrix)) (\matrixPtr ->
glUniformMatrix4fv mvpUniformLoc 1 GL_FALSE matrixPtr)
---------------
-- Load shaders
---------------
createShaderProgram :: FilePath -> FilePath -> IO GLProgram
createShaderProgram vertexShaderPath fragmentShaderPath =
do vertexShader <- glCreateShader GL_VERTEX_SHADER
compileShader vertexShaderPath vertexShader
fragmentShader <- glCreateShader GL_FRAGMENT_SHADER
compileShader fragmentShaderPath fragmentShader
shaderProg <- glCreateProgram
glAttachShader shaderProg vertexShader
glAttachShader shaderProg fragmentShader
glLinkProgram shaderProg
linked <- overPtr (glGetProgramiv shaderProg GL_LINK_STATUS)
when (linked == GL_FALSE)
(do maxLength <- overPtr (glGetProgramiv shaderProg GL_INFO_LOG_LENGTH)
logLines <- allocaArray
(fromIntegral maxLength)
(\p ->
alloca (\lenP ->
do glGetProgramInfoLog shaderProg maxLength lenP p
len <- peek lenP
peekCStringLen (p,fromIntegral len)))
putStrLn logLines)
return (GLProgram shaderProg)
where compileShader path shader =
do src <- Text.readFile path
BS.useAsCString
(Text.encodeUtf8 src)
(\ptr ->
withArray [ptr]
(\srcs ->
glShaderSource shader 1 srcs nullPtr))
glCompileShader shader
when True
(do maxLength <- overPtr (glGetShaderiv shader GL_INFO_LOG_LENGTH)
logLines <- allocaArray
(fromIntegral maxLength)
(\p ->
alloca (\lenP ->
do glGetShaderInfoLog shader maxLength lenP p
len <- peek lenP
peekCStringLen (p,fromIntegral len)))
when (length logLines > 0)
(do putStrLn ("In " ++ path ++ ":")
putStrLn logLines)
)
getShaderAttribute :: GLProgram -> String -> IO AttributeLocation
getShaderAttribute (GLProgram prog) attributeName = do
location <- withCString attributeName $ \attributeNameCString ->
glGetAttribLocation prog attributeNameCString
when (location == -1) $ error $ "Coudn't bind attribute: " ++ attributeName
return (AttributeLocation location)
getShaderUniform :: GLProgram -> String -> IO UniformLocation
getShaderUniform (GLProgram prog) uniformName = do
location <- withCString uniformName $ \uniformNameCString ->
glGetUniformLocation prog uniformNameCString
when (location == -1) $ error $ "Coudn't bind uniform: " ++ uniformName
return (UniformLocation location)
glGetErrors :: IO ()
glGetErrors = do
code <- glGetError
case code of
GL_NO_ERROR -> return ()
e -> do
case e of
GL_INVALID_ENUM -> putStrLn "* Invalid Enum"
GL_INVALID_VALUE -> putStrLn "* Invalid Value"
GL_INVALID_OPERATION -> putStrLn "* Invalid Operation"
GL_INVALID_FRAMEBUFFER_OPERATION -> putStrLn "* Invalid Framebuffer Operation"
GL_OUT_OF_MEMORY -> putStrLn "* OOM"
GL_STACK_UNDERFLOW -> putStrLn "* Stack underflow"
GL_STACK_OVERFLOW -> putStrLn "* Stack overflow"
_ -> return ()
glGetErrors