diff options
Diffstat (limited to 'Spear/GL.hs')
| -rw-r--r-- | Spear/GL.hs | 164 | 
1 files changed, 89 insertions, 75 deletions
diff --git a/Spear/GL.hs b/Spear/GL.hs index d3a42f0..65f985b 100644 --- a/Spear/GL.hs +++ b/Spear/GL.hs  | |||
| @@ -1,24 +1,11 @@ | |||
| 1 | module Spear.GL | 1 | module Spear.GL | 
| 2 | ( | 2 | ( | 
| 3 | -- * General Management | 3 | -- * Programs | 
| 4 | GLSLShader | 4 | GLSLProgram | 
| 5 | , GLSLProgram | ||
| 6 | , ShaderType(..) | ||
| 7 | -- ** Programs | ||
| 8 | , newProgram | 5 | , newProgram | 
| 9 | , linkProgram | 6 | , linkProgram | 
| 10 | , useProgram | 7 | , useProgram | 
| 11 | , withGLSLProgram | 8 | , withGLSLProgram | 
| 12 | -- ** Shaders | ||
| 13 | , attachShader | ||
| 14 | , detachShader | ||
| 15 | , loadShader | ||
| 16 | , newShader | ||
| 17 | -- *** Source loading | ||
| 18 | , loadSource | ||
| 19 | , shaderSource | ||
| 20 | , readSource | ||
| 21 | , compile | ||
| 22 | -- ** Locations | 9 | -- ** Locations | 
| 23 | , attribLocation | 10 | , attribLocation | 
| 24 | , fragLocation | 11 | , fragLocation | 
| @@ -29,16 +16,25 @@ module Spear.GL | |||
| 29 | , uniformVec4 | 16 | , uniformVec4 | 
| 30 | , uniformMat3 | 17 | , uniformMat3 | 
| 31 | , uniformMat4 | 18 | , uniformMat4 | 
| 32 | , uniformfl | 19 | , LoadUniforms(..) | 
| 33 | , uniformil | 20 | -- * Shaders | 
| 34 | -- ** Helper functions | 21 | , GLSLShader | 
| 22 | , ShaderType(..) | ||
| 23 | , attachShader | ||
| 24 | , detachShader | ||
| 25 | , loadShader | ||
| 26 | , newShader | ||
| 27 | -- ** Source loading | ||
| 28 | , loadSource | ||
| 29 | , shaderSource | ||
| 30 | , readSource | ||
| 31 | , compile | ||
| 32 | -- * Helper functions | ||
| 35 | , ($=) | 33 | , ($=) | 
| 36 | , Data.StateVar.get | 34 | , Data.StateVar.get | 
| 37 | -- * VAOs | 35 | -- * VAOs | 
| 38 | , VAO | 36 | , VAO | 
| 39 | -- ** Creation and destruction | ||
| 40 | , newVAO | 37 | , newVAO | 
| 41 | -- ** Manipulation | ||
| 42 | , bindVAO | 38 | , bindVAO | 
| 43 | , enableVAOAttrib | 39 | , enableVAOAttrib | 
| 44 | , attribVAOPointer | 40 | , attribVAOPointer | 
| @@ -49,12 +45,10 @@ module Spear.GL | |||
| 49 | , GLBuffer | 45 | , GLBuffer | 
| 50 | , TargetBuffer(..) | 46 | , TargetBuffer(..) | 
| 51 | , BufferUsage(..) | 47 | , BufferUsage(..) | 
| 52 | -- ** Creation and destruction | ||
| 53 | , newBuffer | 48 | , newBuffer | 
| 54 | -- ** Manipulation | ||
| 55 | , bindBuffer | 49 | , bindBuffer | 
| 56 | , bufferData | 50 | , BufferData(..) | 
| 57 | , bufferDatal | 51 | , bufferData' | 
| 58 | , withGLBuffer | 52 | , withGLBuffer | 
| 59 | -- * Textures | 53 | -- * Textures | 
| 60 | , Texture | 54 | , Texture | 
| @@ -92,7 +86,9 @@ import Control.Monad.Trans.Error | |||
| 92 | import Control.Monad.Trans.State as State | 86 | import Control.Monad.Trans.State as State | 
| 93 | import qualified Data.ByteString.Char8 as B | 87 | import qualified Data.ByteString.Char8 as B | 
| 94 | import Data.StateVar | 88 | import Data.StateVar | 
| 89 | import Data.Word | ||
| 95 | import Foreign.C.String | 90 | import Foreign.C.String | 
| 91 | import Foreign.C.Types | ||
| 96 | import Foreign.Ptr | 92 | import Foreign.Ptr | 
| 97 | import Foreign.Storable | 93 | import Foreign.Storable | 
| 98 | import Foreign.Marshal.Utils as Foreign (with) | 94 | import Foreign.Marshal.Utils as Foreign (with) | 
| @@ -140,9 +136,8 @@ withGLSLProgram prog f = f $ getProgram prog | |||
| 140 | 136 | ||
| 141 | -- | Get the location of the given uniform variable within the given program. | 137 | -- | Get the location of the given uniform variable within the given program. | 
| 142 | uniformLocation :: GLSLProgram -> String -> GettableStateVar GLint | 138 | uniformLocation :: GLSLProgram -> String -> GettableStateVar GLint | 
| 143 | uniformLocation prog var = makeGettableStateVar get | 139 | uniformLocation prog var = makeGettableStateVar $ | 
| 144 | where | 140 | withCString var $ \str -> glGetUniformLocation (getProgram prog) (unsafeCoerce str) | 
| 145 | get = withCString var $ \str -> glGetUniformLocation (getProgram prog) (unsafeCoerce str) | ||
| 146 | 141 | ||
| 147 | -- | Get or set the location of the given variable to a fragment shader colour number. | 142 | -- | Get or set the location of the given variable to a fragment shader colour number. | 
| 148 | fragLocation :: GLSLProgram -> String -> StateVar GLint | 143 | fragLocation :: GLSLProgram -> String -> StateVar GLint | 
| @@ -167,10 +162,10 @@ newProgram shaders = do | |||
| 167 | when (h == 0) $ gameError "glCreateProgram failed" | 162 | when (h == 0) $ gameError "glCreateProgram failed" | 
| 168 | rkey <- register $ deleteProgram h | 163 | rkey <- register $ deleteProgram h | 
| 169 | let program = GLSLProgram h rkey | 164 | let program = GLSLProgram h rkey | 
| 170 | 165 | ||
| 171 | mapM_ (gameIO . attachShader program) shaders | 166 | mapM_ (gameIO . attachShader program) shaders | 
| 172 | linkProgram program | 167 | linkProgram program | 
| 173 | 168 | ||
| 174 | return program | 169 | return program | 
| 175 | 170 | ||
| 176 | -- | Delete the program. | 171 | -- | Delete the program. | 
| @@ -192,7 +187,7 @@ linkProgram prog = do | |||
| 192 | case status of | 187 | case status of | 
| 193 | 0 -> getStatus glGetProgramiv glGetProgramInfoLog h | 188 | 0 -> getStatus glGetProgramiv glGetProgramInfoLog h | 
| 194 | _ -> return "" | 189 | _ -> return "" | 
| 195 | 190 | ||
| 196 | case length err of | 191 | case length err of | 
| 197 | 0 -> return () | 192 | 0 -> return () | 
| 198 | _ -> gameError err | 193 | _ -> gameError err | 
| @@ -258,10 +253,10 @@ shaderSource shader str = | |||
| 258 | compile :: FilePath -> GLSLShader -> Game s () | 253 | compile :: FilePath -> GLSLShader -> Game s () | 
| 259 | compile file shader = do | 254 | compile file shader = do | 
| 260 | let h = getShader shader | 255 | let h = getShader shader | 
| 261 | 256 | ||
| 262 | -- Compile | 257 | -- Compile | 
| 263 | gameIO $ glCompileShader h | 258 | gameIO $ glCompileShader h | 
| 264 | 259 | ||
| 265 | -- Verify status | 260 | -- Verify status | 
| 266 | err <- gameIO $ alloca $ \statusPtr -> do | 261 | err <- gameIO $ alloca $ \statusPtr -> do | 
| 267 | glGetShaderiv h gl_COMPILE_STATUS statusPtr | 262 | glGetShaderiv h gl_COMPILE_STATUS statusPtr | 
| @@ -269,11 +264,11 @@ compile file shader = do | |||
| 269 | case result of | 264 | case result of | 
| 270 | 0 -> getStatus glGetShaderiv glGetShaderInfoLog h | 265 | 0 -> getStatus glGetShaderiv glGetShaderInfoLog h | 
| 271 | _ -> return "" | 266 | _ -> return "" | 
| 272 | 267 | ||
| 273 | case length err of | 268 | case length err of | 
| 274 | 0 -> return () | 269 | 0 -> return () | 
| 275 | _ -> gameError $ "Unable to compile shader " ++ file ++ ":\n" ++ err | 270 | _ -> gameError $ "Unable to compile shader " ++ file ++ ":\n" ++ err | 
| 276 | 271 | ||
| 277 | type StatusCall = GLuint -> GLenum -> Ptr GLint -> IO () | 272 | type StatusCall = GLuint -> GLenum -> Ptr GLint -> IO () | 
| 278 | type LogCall = GLuint -> GLsizei -> Ptr GLsizei -> Ptr GLchar -> IO () | 273 | type LogCall = GLuint -> GLsizei -> Ptr GLsizei -> Ptr GLchar -> IO () | 
| 279 | 274 | ||
| @@ -314,16 +309,16 @@ readSource' file = do | |||
| 314 | if isInclude l | 309 | if isInclude l | 
| 315 | then readSource' $ B.unpack . clean . cleanInclude $ l | 310 | then readSource' $ B.unpack . clean . cleanInclude $ l | 
| 316 | else return l | 311 | else return l | 
| 317 | 312 | ||
| 318 | contents <- B.readFile file | 313 | contents <- B.readFile file | 
| 319 | 314 | ||
| 320 | dir <- getCurrentDirectory | 315 | dir <- getCurrentDirectory | 
| 321 | let dir' = dir ++ "/" ++ (reverse . dropWhile (\c -> c /= '/') . reverse) file | 316 | let dir' = dir ++ "/" ++ (reverse . dropWhile (\c -> c /= '/') . reverse) file | 
| 322 | 317 | ||
| 323 | setCurrentDirectory dir' | 318 | setCurrentDirectory dir' | 
| 324 | code <- parse contents | 319 | code <- parse contents | 
| 325 | setCurrentDirectory dir | 320 | setCurrentDirectory dir | 
| 326 | 321 | ||
| 327 | return code | 322 | return code | 
| 328 | 323 | ||
| 329 | -- | Load a 2D vector. | 324 | -- | Load a 2D vector. | 
| @@ -338,7 +333,7 @@ uniformVec3 loc v = glUniform3f loc x' y' z' | |||
| 338 | where x' = unsafeCoerce $ x v | 333 | where x' = unsafeCoerce $ x v | 
| 339 | y' = unsafeCoerce $ y v | 334 | y' = unsafeCoerce $ y v | 
| 340 | z' = unsafeCoerce $ z v | 335 | z' = unsafeCoerce $ z v | 
| 341 | 336 | ||
| 342 | -- | Load a 4D vector. | 337 | -- | Load a 4D vector. | 
| 343 | uniformVec4 :: GLint -> Vector4 -> IO () | 338 | uniformVec4 :: GLint -> Vector4 -> IO () | 
| 344 | uniformVec4 loc v = glUniform4f loc x' y' z' w' | 339 | uniformVec4 loc v = glUniform4f loc x' y' z' w' | 
| @@ -359,23 +354,25 @@ uniformMat4 loc mat = | |||
| 359 | with mat $ \ptrMat -> | 354 | with mat $ \ptrMat -> | 
| 360 | glUniformMatrix4fv loc 1 (toEnum 0) (unsafeCoerce ptrMat) | 355 | glUniformMatrix4fv loc 1 (toEnum 0) (unsafeCoerce ptrMat) | 
| 361 | 356 | ||
| 362 | -- | Load a list of floats. | 357 | class LoadUniforms a where | 
| 363 | uniformfl :: GLint -> [GLfloat] -> IO () | 358 | -- | Load a list of uniform values. | 
| 364 | uniformfl loc vals = withArray vals $ \ptr -> | 359 | uniforml :: GLint -> [a] -> IO () | 
| 365 | case length vals of | 360 | |
| 366 | 1 -> glUniform1fv loc 1 ptr | 361 | instance LoadUniforms Float where | 
| 367 | 2 -> glUniform2fv loc 1 ptr | 362 | uniforml loc vals = withArray (map unsafeCoerce vals) $ \ptr -> | 
| 368 | 3 -> glUniform3fv loc 1 ptr | 363 | case length vals of | 
| 369 | 4 -> glUniform4fv loc 1 ptr | 364 | 1 -> glUniform1fv loc 1 ptr | 
| 370 | 365 | 2 -> glUniform2fv loc 1 ptr | |
| 371 | -- | Load a list of integers. | 366 | 3 -> glUniform3fv loc 1 ptr | 
| 372 | uniformil :: GLint -> [GLint] -> IO () | 367 | 4 -> glUniform4fv loc 1 ptr | 
| 373 | uniformil loc vals = withArray vals $ \ptr -> | 368 | |
| 374 | case length vals of | 369 | instance LoadUniforms Int where | 
| 375 | 1 -> glUniform1iv loc 1 ptr | 370 | uniforml loc vals = withArray (map fromIntegral vals) $ \ptr -> | 
| 376 | 2 -> glUniform2iv loc 1 ptr | 371 | case length vals of | 
| 377 | 3 -> glUniform3iv loc 1 ptr | 372 | 1 -> glUniform1iv loc 1 ptr | 
| 378 | 4 -> glUniform4iv loc 1 ptr | 373 | 2 -> glUniform2iv loc 1 ptr | 
| 374 | 3 -> glUniform3iv loc 1 ptr | ||
| 375 | 4 -> glUniform4iv loc 1 ptr | ||
| 379 | 376 | ||
| 380 | -- | 377 | -- | 
| 381 | -- VAOs | 378 | -- VAOs | 
| @@ -402,7 +399,7 @@ newVAO = do | |||
| 402 | h <- gameIO . alloca $ \ptr -> do | 399 | h <- gameIO . alloca $ \ptr -> do | 
| 403 | glGenVertexArrays 1 ptr | 400 | glGenVertexArrays 1 ptr | 
| 404 | peek ptr | 401 | peek ptr | 
| 405 | 402 | ||
| 406 | rkey <- register $ deleteVAO h | 403 | rkey <- register $ deleteVAO h | 
| 407 | return $ VAO h rkey | 404 | return $ VAO h rkey | 
| 408 | 405 | ||
| @@ -415,7 +412,7 @@ bindVAO :: VAO -> IO () | |||
| 415 | bindVAO = glBindVertexArray . getVAO | 412 | bindVAO = glBindVertexArray . getVAO | 
| 416 | 413 | ||
| 417 | -- | Enable the given vertex attribute of the bound vao. | 414 | -- | Enable the given vertex attribute of the bound vao. | 
| 418 | -- | 415 | -- | 
| 419 | -- See also 'bindVAO'. | 416 | -- See also 'bindVAO'. | 
| 420 | enableVAOAttrib :: GLuint -- ^ Attribute index. | 417 | enableVAOAttrib :: GLuint -- ^ Attribute index. | 
| 421 | -> IO () | 418 | -> IO () | 
| @@ -445,7 +442,7 @@ drawArrays mode first count = glDrawArrays mode (unsafeCoerce first) (unsafeCoer | |||
| 445 | drawElements | 442 | drawElements | 
| 446 | :: GLenum -- ^ The kind of primitives to render. | 443 | :: GLenum -- ^ The kind of primitives to render. | 
| 447 | -> Int -- ^ The number of elements to be rendered. | 444 | -> Int -- ^ The number of elements to be rendered. | 
| 448 | -> GLenum -- ^ The type of the index values. Must be one of gl_UNSIGNED_BYTE, gl_UNSIGNED_SHORT, or gl_UNSIGNED_INT. | 445 | -> GLenum -- ^ The type of the index values. Must be one of gl_UNSIGNED_BYTE, gl_UNSIGNED_SHORT, or gl_UNSIGNED_INT. | 
| 449 | -> Ptr a -- ^ Pointer to the location where indices are stored, or offset into the index array when there is a bound ElementArrayBuffer. | 446 | -> Ptr a -- ^ Pointer to the location where indices are stored, or offset into the index array when there is a bound ElementArrayBuffer. | 
| 450 | -> IO () | 447 | -> IO () | 
| 451 | drawElements mode count t idxs = glDrawElements mode (unsafeCoerce count) t idxs | 448 | drawElements mode count t idxs = glDrawElements mode (unsafeCoerce count) t idxs | 
| @@ -470,7 +467,7 @@ data TargetBuffer | |||
| 470 | | PixelPackBuffer | 467 | | PixelPackBuffer | 
| 471 | | PixelUnpackBuffer | 468 | | PixelUnpackBuffer | 
| 472 | deriving (Eq, Show) | 469 | deriving (Eq, Show) | 
| 473 | 470 | ||
| 474 | fromTarget :: TargetBuffer -> GLenum | 471 | fromTarget :: TargetBuffer -> GLenum | 
| 475 | fromTarget ArrayBuffer = gl_ARRAY_BUFFER | 472 | fromTarget ArrayBuffer = gl_ARRAY_BUFFER | 
| 476 | fromTarget ElementArrayBuffer = gl_ELEMENT_ARRAY_BUFFER | 473 | fromTarget ElementArrayBuffer = gl_ELEMENT_ARRAY_BUFFER | 
| @@ -507,7 +504,7 @@ newBuffer = do | |||
| 507 | h <- gameIO . alloca $ \ptr -> do | 504 | h <- gameIO . alloca $ \ptr -> do | 
| 508 | glGenBuffers 1 ptr | 505 | glGenBuffers 1 ptr | 
| 509 | peek ptr | 506 | peek ptr | 
| 510 | 507 | ||
| 511 | rkey <- register $ deleteBuffer h | 508 | rkey <- register $ deleteBuffer h | 
| 512 | return $ GLBuffer h rkey | 509 | return $ GLBuffer h rkey | 
| 513 | 510 | ||
| @@ -519,23 +516,40 @@ deleteBuffer buf = Foreign.with buf $ glDeleteBuffers 1 | |||
| 519 | bindBuffer :: GLBuffer -> TargetBuffer -> IO () | 516 | bindBuffer :: GLBuffer -> TargetBuffer -> IO () | 
| 520 | bindBuffer buf target = glBindBuffer (fromTarget target) $ getBuffer buf | 517 | bindBuffer buf target = glBindBuffer (fromTarget target) $ getBuffer buf | 
| 521 | 518 | ||
| 522 | -- | Set the buffer's data. | 519 | class Storable a => BufferData a where | 
| 523 | bufferData :: TargetBuffer | 520 | -- | Set the buffer's data. | 
| 524 | -> Int -- ^ Buffer size in bytes. | 521 | bufferData :: TargetBuffer -> [a] -> BufferUsage -> IO () | 
| 525 | -> Ptr a | 522 | bufferData tgt vals usage = | 
| 523 | let n = sizeOf (undefined :: Word8) * length vals | ||
| 524 | in withArray vals $ \ptr -> bufferData' tgt n ptr usage | ||
| 525 | |||
| 526 | instance BufferData Word8 | ||
| 527 | instance BufferData Word16 | ||
| 528 | instance BufferData Word32 | ||
| 529 | instance BufferData CChar | ||
| 530 | instance BufferData CInt | ||
| 531 | instance BufferData CFloat | ||
| 532 | instance BufferData CDouble | ||
| 533 | instance BufferData Int | ||
| 534 | instance BufferData Float | ||
| 535 | instance BufferData Double | ||
| 536 | |||
| 537 | {-bufferData :: Storable a | ||
| 538 | => TargetBuffer | ||
| 539 | -> Int -- ^ The size in bytes of an element in the data list. | ||
| 540 | -> [a] -- ^ The data list. | ||
| 526 | -> BufferUsage | 541 | -> BufferUsage | 
| 527 | -> IO () | 542 | -> IO () | 
| 528 | bufferData target n bufData usage = glBufferData (fromTarget target) (unsafeCoerce n) bufData (fromUsage usage) | 543 | bufferData target n bufData usage = withArray bufData $ | 
| 544 | \ptr -> bufferData target (n * length bufData) ptr usage-} | ||
| 529 | 545 | ||
| 530 | -- | Set the buffer's data. | 546 | -- | Set the buffer's data. | 
| 531 | bufferDatal :: Storable a | 547 | bufferData' :: TargetBuffer | 
| 532 | => TargetBuffer | 548 | -> Int -- ^ Buffer size in bytes. | 
| 533 | -> Int -- ^ The size in bytes of an element in the data list. | 549 | -> Ptr a | 
| 534 | -> [a] -- ^ The data list. | ||
| 535 | -> BufferUsage | 550 | -> BufferUsage | 
| 536 | -> IO () | 551 | -> IO () | 
| 537 | bufferDatal target n bufData usage = withArray bufData $ | 552 | bufferData' target n bufData usage = glBufferData (fromTarget target) (unsafeCoerce n) bufData (fromUsage usage) | 
| 538 | \ptr -> bufferData target (n * length bufData) ptr usage | ||
| 539 | 553 | ||
| 540 | -- | Apply the given function the buffer's id. | 554 | -- | Apply the given function the buffer's id. | 
| 541 | withGLBuffer :: GLBuffer -> (GLuint -> a) -> a | 555 | withGLBuffer :: GLBuffer -> (GLuint -> a) -> a | 
| @@ -566,7 +580,7 @@ newTexture = do | |||
| 566 | tex <- gameIO . alloca $ \ptr -> do | 580 | tex <- gameIO . alloca $ \ptr -> do | 
| 567 | glGenTextures 1 ptr | 581 | glGenTextures 1 ptr | 
| 568 | peek ptr | 582 | peek ptr | 
| 569 | 583 | ||
| 570 | rkey <- register $ deleteTexture tex | 584 | rkey <- register $ deleteTexture tex | 
| 571 | return $ Texture tex rkey | 585 | return $ Texture tex rkey | 
| 572 | 586 | ||
| @@ -590,12 +604,12 @@ loadTextureImage file minFilter magFilter = do | |||
| 590 | h = height image | 604 | h = height image | 
| 591 | pix = pixels image | 605 | pix = pixels image | 
| 592 | rgb = fromIntegral . fromEnum $ gl_RGB | 606 | rgb = fromIntegral . fromEnum $ gl_RGB | 
| 593 | 607 | ||
| 594 | bindTexture tex | 608 | bindTexture tex | 
| 595 | loadTextureData gl_TEXTURE_2D 0 rgb w h 0 gl_RGB gl_UNSIGNED_BYTE pix | 609 | loadTextureData gl_TEXTURE_2D 0 rgb w h 0 gl_RGB gl_UNSIGNED_BYTE pix | 
| 596 | texParami gl_TEXTURE_2D gl_TEXTURE_MIN_FILTER $= minFilter | 610 | texParami gl_TEXTURE_2D gl_TEXTURE_MIN_FILTER $= minFilter | 
| 597 | texParami gl_TEXTURE_2D gl_TEXTURE_MAG_FILTER $= magFilter | 611 | texParami gl_TEXTURE_2D gl_TEXTURE_MAG_FILTER $= magFilter | 
| 598 | 612 | ||
| 599 | return tex | 613 | return tex | 
| 600 | 614 | ||
| 601 | -- | Bind the texture. | 615 | -- | Bind the texture. | 
