module Graphics.GL.Low (
VAO,
newVAO,
bindVAO,
deleteVAO,
VBO,
UsageHint(..),
newVBO,
bindVBO,
updateVBO,
deleteVBO,
ElementArray,
IndexFormat(..),
newElementArray,
bindElementArray,
updateElementArray,
deleteElementArray,
Program,
ProgramError(..),
newProgram,
newProgramSafe,
useProgram,
deleteProgram,
VertexAttributeLayout(..),
LayoutElement(..),
ComponentFormat(..),
setVertexAttributeLayout,
setUniform1f,
setUniform2f,
setUniform3f,
setUniform4f,
setUniform1i,
setUniform2i,
setUniform3i,
setUniform4i,
setUniform22,
setUniform33,
setUniform44,
Tex2D,
CubeMap,
Dimensions(..),
Cube(..),
Side,
newTexture2D,
newCubeMap,
newEmptyTexture2D,
newEmptyCubeMap,
deleteTexture,
setActiveTextureUnit,
bindTexture2D,
bindTextureCubeMap,
Filtering(..),
setTex2DFiltering,
setCubeMapFiltering,
Wrapping(..),
setTex2DWrapping,
setCubeMapWrapping,
drawPoints,
drawLines,
drawLineStrip,
drawLineLoop,
drawTriangles,
drawTriangleStrip,
drawTriangleFan,
drawIndexedPoints,
drawIndexedLines,
drawIndexedLineStrip,
drawIndexedLineLoop,
drawIndexedTriangles,
drawIndexedTriangleStrip,
drawIndexedTriangleFan,
enableColorWriting,
disableColorWriting,
clearColorBuffer,
enableDepthTest,
disableDepthTest,
clearDepthBuffer,
enableDepthWriting,
disableDepthWriting,
enableStencilTest,
disableStencilTest,
clearStencilBuffer,
enableStencilWriting,
disableStencilWriting,
setScissorBox,
enableScissorTest,
disableScissorTest,
Culling(..),
enableCulling,
disableCulling,
BlendFactor(..),
BlendEquation(..),
enableBlending,
disableBlending,
setBlendFactors,
setBlendEquation,
Viewport(..),
setViewport,
DefaultFramebuffer,
FBO,
bindFramebuffer,
newFBO,
attachTex2D,
attachCubeMap,
attachRBO,
deleteFBO,
RBO,
newRBO,
deleteRBO,
GLError(..),
getGLError,
Alpha,
Luminance,
LuminanceAlpha,
RGB,
RGBA,
Depth24,
Depth24Stencil8,
InternalFormat(..),
Framebuffer(..),
Texture(..),
Attachable(..)
) where
import Prelude hiding (sum)
import Control.Exception
import Data.Typeable
import Foreign.Ptr
import Foreign.Storable
import Foreign.Marshal
import Foreign.C.String
import Data.Vector.Storable (Vector, unsafeWith)
import qualified Data.Vector.Storable as V (length)
import Control.Monad hiding (forM_)
import Data.Word
import Data.Int
import Data.Functor
import Control.Applicative
import Data.Traversable
import Data.Foldable
import Data.Default
import Linear
import Graphics.GL
newtype VAO = VAO GLuint deriving Show
newtype Program = Program GLuint deriving Show
data VBO = VBO GLuint deriving Show
data ElementArray = ElementArray GLuint deriving Show
newtype Tex2D a = Tex2D GLuint deriving Show
newtype CubeMap a = CubeMap GLuint deriving Show
newtype FBO = FBO GLuint deriving Show
data Filtering =
Nearest |
Linear
deriving Show
instance ToGL Filtering where
toGL Nearest = GL_NEAREST
toGL Linear = GL_LINEAR
data Wrapping =
Repeat |
MirroredRepeat |
ClampToEdge
deriving Show
instance ToGL Wrapping where
toGL Repeat = GL_REPEAT
toGL MirroredRepeat = GL_MIRRORED_REPEAT
toGL ClampToEdge = GL_CLAMP_TO_EDGE
data Culling =
CullFront |
CullBack |
CullFrontAndBack
deriving Show
instance ToGL Culling where
toGL CullFront = GL_FRONT
toGL CullBack = GL_BACK
toGL CullFrontAndBack = GL_FRONT_AND_BACK
data LayoutElement =
Attrib String Int ComponentFormat |
Unused Int
deriving Show
type VertexAttributeLayout = [LayoutElement]
data ComponentFormat =
VFloat |
VByte |
VUByte |
VByteNormalized |
VUByteNormalized |
VShort |
VUShort |
VShortNormalized |
VUShortNormalized |
VInt |
VUInt |
VIntNormalized |
VUIntNormalized
deriving (Eq, Show)
instance ToGL ComponentFormat where
toGL VFloat = GL_FLOAT
toGL VByte = GL_BYTE
toGL VUByte = GL_UNSIGNED_BYTE
toGL VByteNormalized = GL_BYTE
toGL VUByteNormalized = GL_UNSIGNED_BYTE
toGL VShort = GL_SHORT
toGL VUShort = GL_UNSIGNED_SHORT
toGL VShortNormalized = GL_SHORT
toGL VUShortNormalized = GL_UNSIGNED_SHORT
toGL VInt = GL_INT
toGL VUInt = GL_UNSIGNED_INT
toGL VIntNormalized = GL_INT
toGL VUIntNormalized = GL_UNSIGNED_INT
data UsageHint = StaticDraw
| DynamicDraw
| StreamDraw
deriving Show
instance ToGL UsageHint where
toGL StaticDraw = GL_STATIC_DRAW
toGL DynamicDraw = GL_DYNAMIC_DRAW
toGL StreamDraw = GL_STREAM_DRAW
data Alpha = Alpha deriving Show
data Luminance = Luminance deriving Show
data LuminanceAlpha = Luminancealpha deriving Show
data RGB = RGB deriving Show
data RGBA = RGBA deriving Show
data Depth24 = Depth24 deriving Show
data Depth24Stencil8 = Depth24Stencil8 deriving Show
class InternalFormat a where
internalFormat :: (Eq b, Num b) => proxy a -> b
instance InternalFormat RGB where
internalFormat _ = GL_RGB8
instance InternalFormat RGBA where
internalFormat _ = GL_RGBA
instance InternalFormat Alpha where
internalFormat _ = GL_ALPHA
instance InternalFormat Luminance where
internalFormat _ = GL_LUMINANCE
instance InternalFormat LuminanceAlpha where
internalFormat _ = GL_LUMINANCE_ALPHA
instance InternalFormat Depth24 where
internalFormat _ = GL_DEPTH_COMPONENT24
instance InternalFormat Depth24Stencil8 where
internalFormat _ = GL_DEPTH24_STENCIL8
class InternalFormat a => Attachable a where
attachPoint :: (Eq b, Num b) => proxy a -> b
instance Attachable RGB where
attachPoint _ = GL_COLOR_ATTACHMENT0
instance Attachable RGBA where
attachPoint _ = GL_COLOR_ATTACHMENT0
instance Attachable Luminance where
attachPoint _ = GL_COLOR_ATTACHMENT0
instance Attachable LuminanceAlpha where
attachPoint _ = GL_COLOR_ATTACHMENT0
instance Attachable Alpha where
attachPoint _ = GL_COLOR_ATTACHMENT0
instance Attachable Depth24 where
attachPoint _ = GL_DEPTH_ATTACHMENT
instance Attachable Depth24Stencil8 where
attachPoint _ = GL_DEPTH_STENCIL_ATTACHMENT
data IndexFormat =
UByteIndices |
UShortIndices |
UIntIndices
deriving Show
instance ToGL IndexFormat where
toGL UByteIndices = GL_UNSIGNED_BYTE
toGL UShortIndices = GL_UNSIGNED_SHORT
toGL UIntIndices = GL_UNSIGNED_INT
data RBO a = RBO { unRBO :: GLuint } deriving Show
data Viewport = Viewport
{ viewportX :: Int
, viewportY :: Int
, viewportW :: Int
, viewportH :: Int }
deriving (Eq, Show)
data Dimensions = Dimensions
{ imageWidth :: Int
, imageHeight :: Int }
deriving (Show)
data Cube a = Cube
{ cubeRight :: a
, cubeLeft :: a
, cubeTop :: a
, cubeBottom :: a
, cubeFront :: a
, cubeBack :: a }
deriving (Show, Functor, Foldable, Traversable)
type Side = forall a . Cube a -> a
instance Applicative Cube where
pure x = Cube x x x x x x
(Cube f1 f2 f3 f4 f5 f6) <*> (Cube x1 x2 x3 x4 x5 x6) =
Cube (f1 x1) (f2 x2) (f3 x3) (f4 x4) (f5 x5) (f6 x6)
data ShaderType = VertexShader | FragmentShader deriving Show
instance ToGL ShaderType where
toGL VertexShader = GL_VERTEX_SHADER
toGL FragmentShader = GL_FRAGMENT_SHADER
data ProgramError =
VertexShaderError String |
FragmentShaderError String |
LinkError String
deriving (Show, Typeable)
instance Exception ProgramError
data GLError =
InvalidEnum |
InvalidValue |
InvalidOperation |
InvalidFramebufferOperation |
OutOfMemory
deriving Typeable
instance Exception GLError
instance Show GLError where
show InvalidEnum = "INVALID_ENUM enum argument out of range"
show InvalidValue = "INVALID_VALUE Numeric argument out of range"
show InvalidOperation = "INVALID_OPERATION Illegal in current state"
show InvalidFramebufferOperation = "INVALID_FRAMEBUFFER_OPERATION Framebuffer object is not complete"
show OutOfMemory = "Not enough memory left to execute command"
class ToGL a where
toGL :: (Num b, Eq b) => a -> b
class Texture a where
textureName :: Num b => a -> b
instance Texture (Tex2D a) where
textureName (Tex2D n) = fromIntegral n
instance Texture (CubeMap a) where
textureName (CubeMap n) = fromIntegral n
data BlendEquation =
FuncAdd |
FuncSubtract |
FuncReverseSubtract
deriving Show
instance Default BlendEquation where
def = FuncAdd
instance ToGL BlendEquation where
toGL FuncAdd = GL_FUNC_ADD
toGL FuncSubtract = GL_FUNC_SUBTRACT
toGL FuncReverseSubtract = GL_FUNC_REVERSE_SUBTRACT
data BlendFactor =
BlendOne |
BlendZero |
BlendSourceAlpha |
BlendOneMinusSourceAlpha
deriving Show
instance ToGL BlendFactor where
toGL BlendOne = GL_ONE
toGL BlendZero = GL_ZERO
toGL BlendSourceAlpha = GL_SRC_ALPHA
toGL BlendOneMinusSourceAlpha = GL_ONE_MINUS_SRC_ALPHA
data DefaultFramebuffer = DefaultFramebuffer deriving Show
instance Default DefaultFramebuffer where
def = DefaultFramebuffer
class Framebuffer a where
framebufferName :: Num b => a -> b
instance Framebuffer DefaultFramebuffer where
framebufferName _ = 0
instance Framebuffer FBO where
framebufferName (FBO n) = fromIntegral n
newVAO :: IO VAO
newVAO = do
n <- alloca (\ptr -> glGenVertexArrays 1 ptr >> peek ptr)
return (VAO n)
deleteVAO :: VAO -> IO ()
deleteVAO (VAO n) = withArray [n] (\ptr -> glDeleteVertexArrays 1 ptr)
bindVAO :: VAO -> IO ()
bindVAO (VAO n) = glBindVertexArray n
newVBO :: Vector Word8 -> UsageHint -> IO VBO
newVBO src usage = do
n <- alloca (\ptr -> glGenBuffers 1 ptr >> peek ptr)
let len = V.length src
glBindBuffer GL_ARRAY_BUFFER n
unsafeWith src $ \ptr -> glBufferData
GL_ARRAY_BUFFER
(fromIntegral len)
(castPtr ptr)
(toGL usage)
return (VBO n)
deleteVBO :: VBO -> IO ()
deleteVBO (VBO n) = withArray [n] (\ptr -> glDeleteBuffers 1 ptr)
updateVBO :: Vector Word8 -> Int -> IO ()
updateVBO src offset = do
let len = V.length src
unsafeWith src $ \ptr -> glBufferSubData
GL_ARRAY_BUFFER
(fromIntegral offset)
(fromIntegral len)
(castPtr ptr)
bindVBO :: VBO -> IO ()
bindVBO (VBO n) = glBindBuffer GL_ARRAY_BUFFER n
newElementArray :: Vector Word8 -> UsageHint -> IO ElementArray
newElementArray bytes usage = do
n <- alloca (\ptr -> glGenBuffers 1 ptr >> peek ptr)
glBindBuffer GL_ELEMENT_ARRAY_BUFFER n
let len = V.length bytes
unsafeWith bytes $ \ptr -> do
glBufferData
GL_ELEMENT_ARRAY_BUFFER
(fromIntegral len)
(castPtr ptr)
(toGL usage)
return (ElementArray n)
deleteElementArray :: ElementArray -> IO ()
deleteElementArray (ElementArray n) = withArray [n] (\ptr -> glDeleteBuffers 1 ptr)
updateElementArray :: Vector Word8 -> Int -> IO ()
updateElementArray bytes offset = unsafeWith bytes $ \ptr -> do
glBufferSubData
GL_ELEMENT_ARRAY_BUFFER
(fromIntegral offset)
(fromIntegral (V.length bytes))
(castPtr ptr)
bindElementArray :: ElementArray -> IO ()
bindElementArray (ElementArray n) = glBindBuffer GL_ELEMENT_ARRAY_BUFFER n
newProgramSafe :: String -> String -> IO (Either ProgramError Program)
newProgramSafe vcode fcode = try $ newProgram vcode fcode
deleteProgram :: Program -> IO ()
deleteProgram (Program n) = glDeleteProgram n
newProgram :: String
-> String
-> IO Program
newProgram vcode fcode = do
vertexShaderId <- compileShader vcode VertexShader
fragmentShaderId <- compileShader fcode FragmentShader
programId <- glCreateProgram
glAttachShader programId vertexShaderId
glAttachShader programId fragmentShaderId
glLinkProgram programId
result <- alloca $ \ptr ->
glGetProgramiv programId GL_LINK_STATUS ptr >> peek ptr
when (result == GL_FALSE) $ do
len <- fmap fromIntegral $ alloca $ \ptr ->
glGetProgramiv programId GL_INFO_LOG_LENGTH ptr >> peek ptr
errors <- allocaArray len $ \ptr -> do
glGetProgramInfoLog programId (fromIntegral len) nullPtr ptr
peekCString ptr
throwIO (LinkError errors)
glDeleteShader vertexShaderId
glDeleteShader fragmentShaderId
return (Program programId)
useProgram :: Program -> IO ()
useProgram (Program n) = glUseProgram n
compileShader :: String -> ShaderType -> IO GLuint
compileShader code vertOrFrag = do
shaderId <- glCreateShader (toGL vertOrFrag)
withCString code $ \ptr -> with ptr $ \pptr -> do
glShaderSource shaderId 1 pptr nullPtr
glCompileShader shaderId
result <- with GL_FALSE $ \ptr ->
glGetShaderiv shaderId GL_COMPILE_STATUS ptr >> peek ptr
when (result == GL_FALSE) $ do
len <- fmap fromIntegral $ alloca $ \ptr ->
glGetShaderiv shaderId GL_INFO_LOG_LENGTH ptr >> peek ptr
errors <- allocaArray len $ \ptr -> do
glGetShaderInfoLog shaderId (fromIntegral len) nullPtr ptr
peekCString ptr
case vertOrFrag of
VertexShader -> throwIO (VertexShaderError errors)
FragmentShader -> throwIO (FragmentShaderError errors)
return shaderId
setVertexAttributeLayout :: Program -> VertexAttributeLayout -> IO ()
setVertexAttributeLayout (Program p) layout = do
let layout' = elaborateLayout 0 layout
let total = totalLayout layout
forM_ layout' $ \(name, size, offset, fmt) -> do
attrib <- withCString name $ \ptr -> glGetAttribLocation p (castPtr ptr)
let norm = isNormalized fmt
glVertexAttribPointer
(fromIntegral attrib)
(fromIntegral size)
(toGL fmt)
(fromIntegral . fromEnum $ norm)
(fromIntegral offset)
(castPtr (nullPtr `plusPtr` offset))
glEnableVertexAttribArray (fromIntegral attrib)
elaborateLayout :: Int -> VertexAttributeLayout -> [(String, Int, Int, ComponentFormat)]
elaborateLayout here layout = case layout of
[] -> []
(Unused n):xs -> elaborateLayout (here+n) xs
(Attrib name n fmt):xs ->
let size = n * sizeOfVertexComponent fmt in
(name, n, here, fmt) : elaborateLayout (here+size) xs
totalLayout :: VertexAttributeLayout -> Int
totalLayout layout = sum (map arraySize layout) where
arraySize (Unused n) = n
arraySize (Attrib _ n fmt) = n * sizeOfVertexComponent fmt
sizeOfVertexComponent :: ComponentFormat -> Int
sizeOfVertexComponent c = case c of
VByte -> 1
VUByte -> 1
VByteNormalized -> 1
VUByteNormalized -> 1
VShort -> 2
VUShort -> 2
VShortNormalized -> 2
VUShortNormalized -> 2
VInt -> 4
VUInt -> 4
VIntNormalized -> 4
VUIntNormalized -> 4
VFloat -> 4
isNormalized :: ComponentFormat -> Bool
isNormalized c = case c of
VByte -> False
VUByte -> False
VByteNormalized -> True
VUByteNormalized -> True
VShort -> False
VUShort -> False
VShortNormalized -> True
VUShortNormalized -> True
VInt -> False
VUInt -> False
VIntNormalized -> True
VUIntNormalized -> True
VFloat -> False
setUniform1f :: Program -> String -> [Float] -> IO ()
setUniform1f = setUniform glUniform1fv
setUniform2f :: Program -> String -> [V2 Float] -> IO ()
setUniform2f = setUniform
(\loc cnt val -> glUniform2fv loc cnt (castPtr val))
setUniform3f :: Program -> String -> [V3 Float] -> IO ()
setUniform3f = setUniform
(\loc cnt val -> glUniform3fv loc cnt (castPtr val))
setUniform4f :: Program -> String -> [V4 Float] -> IO ()
setUniform4f = setUniform
(\loc cnt val -> glUniform4fv loc cnt (castPtr val))
setUniform1i :: Program -> String -> [Int] -> IO ()
setUniform1i = setUniform
(\loc cnt val -> glUniform1iv loc cnt (castPtr val))
setUniform2i :: Program -> String -> [V2 Int] -> IO ()
setUniform2i = setUniform
(\loc cnt val -> glUniform2iv loc cnt (castPtr val))
setUniform3i :: Program -> String -> [V3 Int] -> IO ()
setUniform3i = setUniform
(\loc cnt val -> glUniform3iv loc cnt (castPtr val))
setUniform4i :: Program -> String -> [V4 Int] -> IO ()
setUniform4i = setUniform
(\loc cnt val -> glUniform4iv loc cnt (castPtr val))
setUniform44 :: Program -> String -> [M44 Float] -> IO ()
setUniform44 = setUniform
(\loc cnt val -> glUniformMatrix4fv loc cnt GL_FALSE (castPtr val))
setUniform33 :: Program -> String -> [M33 Float] -> IO ()
setUniform33 = setUniform
(\loc cnt val -> glUniformMatrix3fv loc cnt GL_FALSE (castPtr val))
setUniform22 :: Program -> String -> [M22 Float] -> IO ()
setUniform22 = setUniform
(\loc cnt val -> glUniformMatrix2fv loc cnt GL_FALSE (castPtr val))
setUniform :: Storable a => (GLint -> GLsizei -> Ptr a -> IO ())
-> Program -> String -> [a]
-> IO ()
setUniform glAction (Program p) name xs = withArrayLen xs $ \n bytes -> do
loc <- withCString name (\ptr -> glGetUniformLocation p ptr)
glAction loc (fromIntegral n) bytes
drawPoints :: Int -> IO ()
drawPoints = drawArrays GL_POINTS
drawLines :: Int -> IO ()
drawLines = drawArrays GL_LINES
drawLineStrip :: Int -> IO ()
drawLineStrip = drawArrays GL_LINE_STRIP
drawLineLoop :: Int -> IO ()
drawLineLoop = drawArrays GL_LINE_LOOP
drawTriangles :: Int -> IO ()
drawTriangles = drawArrays GL_TRIANGLES
drawTriangleStrip :: Int -> IO ()
drawTriangleStrip = drawArrays GL_TRIANGLE_STRIP
drawTriangleFan :: Int -> IO ()
drawTriangleFan = drawArrays GL_TRIANGLE_FAN
drawArrays :: GLenum -> Int -> IO ()
drawArrays mode n = glDrawArrays mode (fromIntegral n) 0
drawIndexedPoints :: Int -> IndexFormat -> IO ()
drawIndexedPoints = drawIndexed GL_POINTS
drawIndexedLines :: Int -> IndexFormat -> IO ()
drawIndexedLines = drawIndexed GL_LINES
drawIndexedLineStrip :: Int -> IndexFormat -> IO ()
drawIndexedLineStrip = drawIndexed GL_LINE_STRIP
drawIndexedLineLoop :: Int -> IndexFormat -> IO ()
drawIndexedLineLoop = drawIndexed GL_LINE_LOOP
drawIndexedTriangles :: Int -> IndexFormat -> IO ()
drawIndexedTriangles = drawIndexed GL_TRIANGLES
drawIndexedTriangleStrip :: Int -> IndexFormat -> IO ()
drawIndexedTriangleStrip = drawIndexed GL_TRIANGLE_STRIP
drawIndexedTriangleFan :: Int -> IndexFormat -> IO ()
drawIndexedTriangleFan = drawIndexed GL_TRIANGLE_FAN
drawIndexed :: GLenum -> Int -> IndexFormat -> IO ()
drawIndexed mode n fmt = glDrawElements mode (fromIntegral n) (toGL fmt) nullPtr
newTexture2D :: InternalFormat a => Vector Word8 -> Dimensions -> IO (Tex2D a)
newTexture2D bytes (Dimensions w h) = do
n <- alloca (\ptr -> glGenTextures 1 ptr >> peek ptr)
glBindTexture GL_TEXTURE_2D n
tex <- return (Tex2D n)
unsafeWith bytes $ \ptr -> glTexImage2D
GL_TEXTURE_2D
0
(internalFormat tex)
(fromIntegral w)
(fromIntegral h)
0
(internalFormat tex)
GL_UNSIGNED_BYTE
(castPtr ptr)
return tex
deleteTexture :: Texture a => a -> IO ()
deleteTexture x = withArray [textureName x] (\ptr -> glDeleteTextures 1 ptr)
newCubeMap :: InternalFormat a
=> Cube (Vector Word8, Dimensions)
-> IO (CubeMap a)
newCubeMap images = do
n <- alloca (\ptr -> glGenTextures 1 ptr >> peek ptr)
glBindTexture GL_TEXTURE_CUBE_MAP n
cm <- return (CubeMap n)
let fmt = internalFormat cm
sequenceA (liftA2 (loadCubeMapSide fmt) images cubeSideCodes)
return cm
loadCubeMapSide :: GLenum -> (Vector Word8, Dimensions) -> GLenum -> IO ()
loadCubeMapSide fmt (bytes, (Dimensions w h)) side = do
unsafeWith bytes $ \ptr -> glTexImage2D
side
0
(fromIntegral fmt)
(fromIntegral w)
(fromIntegral h)
0
fmt
GL_UNSIGNED_BYTE
(castPtr ptr)
newEmptyTexture2D :: InternalFormat a => Int -> Int -> IO (Tex2D a)
newEmptyTexture2D w h = do
let w' = fromIntegral w
let h' = fromIntegral h
n <- alloca (\ptr -> glGenTextures 1 ptr >> peek ptr)
tex <- return (Tex2D n)
let fmt = internalFormat tex
let fmt' = internalFormat tex
glBindTexture GL_TEXTURE_2D n
glTexImage2D GL_TEXTURE_2D 0 fmt w' h' 0 fmt' GL_UNSIGNED_BYTE nullPtr
return tex
newEmptyCubeMap :: InternalFormat a => Int -> Int -> IO (CubeMap a)
newEmptyCubeMap w h = do
let w' = fromIntegral w
let h' = fromIntegral h
n <- alloca (\ptr -> glGenTextures 1 ptr >> peek ptr)
tex <- return (CubeMap n)
let fmt = internalFormat tex
let fmt' = internalFormat tex
glBindTexture GL_TEXTURE_CUBE_MAP n
glTexImage2D GL_TEXTURE_CUBE_MAP_POSITIVE_X 0 fmt w' h' 0 fmt' GL_UNSIGNED_BYTE nullPtr
glTexImage2D GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0 fmt w' h' 0 fmt' GL_UNSIGNED_BYTE nullPtr
glTexImage2D GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0 fmt w' h' 0 fmt' GL_UNSIGNED_BYTE nullPtr
glTexImage2D GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0 fmt w' h' 0 fmt' GL_UNSIGNED_BYTE nullPtr
glTexImage2D GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0 fmt w' h' 0 fmt' GL_UNSIGNED_BYTE nullPtr
glTexImage2D GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0 fmt w' h' 0 fmt' GL_UNSIGNED_BYTE nullPtr
return tex
bindTexture2D :: Tex2D a -> IO ()
bindTexture2D (Tex2D n) = glBindTexture GL_TEXTURE_2D n
bindTextureCubeMap :: CubeMap a -> IO ()
bindTextureCubeMap (CubeMap n) = glBindTexture GL_TEXTURE_CUBE_MAP n
setActiveTextureUnit :: Enum a => a -> IO ()
setActiveTextureUnit n =
(glActiveTexture . fromIntegral) (GL_TEXTURE0 + fromEnum n)
setTex2DFiltering :: Filtering -> IO ()
setTex2DFiltering filt = do
glTexParameteri GL_TEXTURE_2D GL_TEXTURE_MIN_FILTER (toGL filt)
glTexParameteri GL_TEXTURE_2D GL_TEXTURE_MAG_FILTER (toGL filt)
setCubeMapFiltering :: Filtering -> IO ()
setCubeMapFiltering filt = do
glTexParameteri GL_TEXTURE_CUBE_MAP GL_TEXTURE_MIN_FILTER (toGL filt)
glTexParameteri GL_TEXTURE_CUBE_MAP GL_TEXTURE_MAG_FILTER (toGL filt)
setTex2DWrapping :: Wrapping -> IO ()
setTex2DWrapping wrap = do
glTexParameteri GL_TEXTURE_2D GL_TEXTURE_WRAP_S (toGL wrap)
glTexParameteri GL_TEXTURE_2D GL_TEXTURE_WRAP_T (toGL wrap)
setCubeMapWrapping :: Wrapping -> IO ()
setCubeMapWrapping wrap = do
glTexParameteri GL_TEXTURE_CUBE_MAP GL_TEXTURE_WRAP_S (toGL wrap)
glTexParameteri GL_TEXTURE_CUBE_MAP GL_TEXTURE_WRAP_T (toGL wrap)
glTexParameteri GL_TEXTURE_CUBE_MAP GL_TEXTURE_WRAP_R (toGL wrap)
enableColorWriting :: IO ()
enableColorWriting = glColorMask GL_TRUE GL_TRUE GL_TRUE GL_TRUE
disableColorWriting :: IO ()
disableColorWriting = glColorMask GL_FALSE GL_FALSE GL_FALSE GL_FALSE
clearColorBuffer :: (Float, Float, Float) -> IO ()
clearColorBuffer (r, g, b) = do
glClearColor (realToFrac r) (realToFrac g) (realToFrac b) 1.0
glClear GL_COLOR_BUFFER_BIT
enableDepthTest :: IO ()
enableDepthTest = glEnable GL_DEPTH_TEST
disableDepthTest :: IO ()
disableDepthTest = glDisable GL_DEPTH_TEST
enableDepthWriting :: IO ()
enableDepthWriting = glDepthMask GL_TRUE
disableDepthWriting :: IO ()
disableDepthWriting = glDepthMask GL_FALSE
clearDepthBuffer :: IO ()
clearDepthBuffer = glClear GL_DEPTH_BUFFER_BIT
enableStencilTest :: IO ()
enableStencilTest = do
glStencilFunc GL_LESS 1 maxBound
glStencilOp GL_KEEP GL_KEEP GL_KEEP
glEnable GL_STENCIL_TEST
disableStencilTest :: IO ()
disableStencilTest = glDisable GL_STENCIL_TEST
clearStencilBuffer :: IO ()
clearStencilBuffer = glClear GL_STENCIL_BUFFER_BIT
enableStencilWriting :: IO ()
enableStencilWriting = do
glStencilFunc GL_ALWAYS 1 maxBound
glStencilOp GL_KEEP GL_KEEP GL_REPLACE
glStencilMask 1
disableStencilWriting :: IO ()
disableStencilWriting = glStencilMask 0
setScissorBox :: Viewport -> IO ()
setScissorBox (Viewport x y w h) =
glScissor (fromIntegral x) (fromIntegral y) (fromIntegral w) (fromIntegral h)
enableScissorTest :: IO ()
enableScissorTest = glEnable GL_SCISSOR_TEST
disableScissorTest :: IO ()
disableScissorTest = glDisable GL_SCISSOR_TEST
enableCulling :: Culling -> IO ()
enableCulling c = do
case c of
CullFront -> glCullFace GL_FRONT
CullBack -> glCullFace GL_BACK
CullFrontAndBack -> glCullFace GL_FRONT_AND_BACK
glEnable GL_CULL_FACE
disableCulling :: IO ()
disableCulling = glDisable GL_CULL_FACE
setViewport :: Viewport -> IO ()
setViewport (Viewport x y w h) =
glViewport (fromIntegral x) (fromIntegral y) (fromIntegral w) (fromIntegral h)
bindFramebuffer :: Framebuffer a => a -> IO ()
bindFramebuffer x = glBindFramebuffer GL_FRAMEBUFFER (framebufferName x)
newFBO :: IO FBO
newFBO = do
n <- alloca (\ptr -> glGenFramebuffers 1 ptr >> peek ptr)
return (FBO n)
deleteFBO :: FBO -> IO ()
deleteFBO (FBO n) = withArray [n] (\ptr -> glDeleteFramebuffers 1 ptr)
attachTex2D :: Attachable a => Tex2D a -> IO ()
attachTex2D t@(Tex2D n) =
glFramebufferTexture2D GL_FRAMEBUFFER (attachPoint t) GL_TEXTURE_2D n 0
attachCubeMap :: Attachable a => CubeMap a -> Side -> IO ()
attachCubeMap cm@(CubeMap n) side =
glFramebufferTexture2D
GL_FRAMEBUFFER
(attachPoint cm)
(side cubeSideCodes)
n
0
cubeSideCodes :: Cube GLenum
cubeSideCodes = Cube
{ cubeLeft = GL_TEXTURE_CUBE_MAP_NEGATIVE_X
, cubeRight = GL_TEXTURE_CUBE_MAP_POSITIVE_X
, cubeTop = GL_TEXTURE_CUBE_MAP_POSITIVE_Y
, cubeBottom = GL_TEXTURE_CUBE_MAP_NEGATIVE_Y
, cubeFront = GL_TEXTURE_CUBE_MAP_POSITIVE_Z
, cubeBack = GL_TEXTURE_CUBE_MAP_NEGATIVE_Z }
attachRBO :: Attachable a => RBO a -> IO ()
attachRBO rbo = glFramebufferRenderbuffer
GL_FRAMEBUFFER (attachPoint rbo) GL_RENDERBUFFER (unRBO rbo)
newRBO :: InternalFormat a => Int -> Int -> IO (RBO a)
newRBO w h = do
n <- alloca (\ptr -> glGenRenderbuffers 1 ptr >> peek ptr)
rbo <- return (RBO n)
glBindRenderbuffer GL_RENDERBUFFER n
glRenderbufferStorage
GL_RENDERBUFFER
(internalFormat rbo)
(fromIntegral w)
(fromIntegral h)
return rbo
deleteRBO :: RBO a -> IO ()
deleteRBO (RBO n) = withArray [n] (\ptr -> glDeleteRenderbuffers 1 ptr)
enableBlending :: IO ()
enableBlending = glEnable GL_BLEND
disableBlending :: IO ()
disableBlending = glDisable GL_BLEND
setBlendFactors :: BlendFactor -> BlendFactor -> IO ()
setBlendFactors s d = glBlendFunc (toGL s) (toGL d)
setBlendEquation :: BlendEquation -> IO ()
setBlendEquation e = glBlendEquation (toGL e)
getGLError :: IO (Maybe GLError)
getGLError = do
n <- glGetError
return $ case n of
GL_NO_ERROR -> Nothing
GL_INVALID_ENUM -> Just InvalidEnum
GL_INVALID_VALUE -> Just InvalidValue
GL_INVALID_OPERATION -> Just InvalidOperation
GL_INVALID_FRAMEBUFFER_OPERATION -> Just InvalidFramebufferOperation
GL_OUT_OF_MEMORY -> Just OutOfMemory
_ -> error ("unknown GL error " ++ show n)