module Graphics.Rendering.OpenGL.GLU.ErrorsInternal (
Error(..), ErrorCategory(..), getErrors,
recordErrorCode, recordInvalidEnum, recordInvalidValue, recordOutOfMemory
) where
import Foreign.Ptr ( castPtr )
import Foreign.C.String ( peekCString )
import Data.IORef ( IORef, newIORef, readIORef, writeIORef )
import System.IO.Unsafe ( unsafePerformIO )
import Graphics.Rendering.GLU.Raw
import Graphics.Rendering.OpenGL.Raw.ARB.Compatibility
import Graphics.Rendering.OpenGL.Raw.Core31
data Error = Error ErrorCategory String
deriving ( Eq, Ord, Show )
data ErrorCategory
= InvalidEnum
| InvalidValue
| InvalidOperation
| InvalidFramebufferOperation
| OutOfMemory
| StackOverflow
| StackUnderflow
| TableTooLarge
| TesselatorError
| NURBSError
deriving ( Eq, Ord, Show )
unmarshalErrorCategory :: GLenum -> ErrorCategory
unmarshalErrorCategory c
| isInvalidEnum c = InvalidEnum
| isInvalidValue c = InvalidValue
| isInvalidOperation c = InvalidOperation
| isInvalidFramebufferOperation c = InvalidFramebufferOperation
| isOutOfMemory c = OutOfMemory
| isStackOverflow c = StackOverflow
| isStackUnderflow c = StackUnderflow
| isTableTooLarge c = TableTooLarge
| isTesselatorError c = TesselatorError
| isNURBSError c = NURBSError
| otherwise = error "unmarshalErrorCategory"
isInvalidEnum :: GLenum -> Bool
isInvalidEnum c = c == gl_INVALID_ENUM || c == glu_INVALID_ENUM
isInvalidValue :: GLenum -> Bool
isInvalidValue c = c == gl_INVALID_VALUE || c == glu_INVALID_VALUE
isInvalidOperation :: GLenum -> Bool
isInvalidOperation c = c == gl_INVALID_OPERATION || c == glu_INVALID_OPERATION
isInvalidFramebufferOperation :: GLenum -> Bool
isInvalidFramebufferOperation c = c == gl_INVALID_FRAMEBUFFER_OPERATION
isOutOfMemory :: GLenum -> Bool
isOutOfMemory c = c == gl_OUT_OF_MEMORY || c == glu_OUT_OF_MEMORY
isStackOverflow :: GLenum -> Bool
isStackOverflow c = c == gl_STACK_OVERFLOW
isStackUnderflow :: GLenum -> Bool
isStackUnderflow c = c == gl_STACK_UNDERFLOW
isTableTooLarge :: GLenum -> Bool
isTableTooLarge c = c == gl_TABLE_TOO_LARGE
isTesselatorError :: GLenum -> Bool
isTesselatorError c = glu_TESS_ERROR1 <= c && c <= glu_TESS_ERROR8
isNURBSError :: GLenum -> Bool
isNURBSError c = glu_NURBS_ERROR1 <= c && c <= glu_NURBS_ERROR37
makeError :: GLenum -> IO Error
makeError e = do
let category = unmarshalErrorCategory e
ptr <- gluErrorString e
description <- peekCString (castPtr ptr)
return $ Error category description
theRecordedErrors :: IORef ([GLenum],Bool)
theRecordedErrors = unsafePerformIO (newIORef ([], True))
getRecordedErrors :: IO ([GLenum],Bool)
getRecordedErrors = readIORef theRecordedErrors
setRecordedErrors :: ([GLenum],Bool) -> IO ()
setRecordedErrors = writeIORef theRecordedErrors
getGLErrors :: IO [GLenum]
getGLErrors = getGLErrorsAux []
where getGLErrorsAux acc = do
errorCode <- glGetError
if isError errorCode
then getGLErrorsAux (errorCode : acc)
else return $ reverse acc
isError :: GLenum -> Bool
isError = (/= gl_NO_ERROR)
getErrors :: IO [Error]
getErrors = do
es <- getErrorCodesAux (const ([], True))
mapM makeError es
recordErrorCode :: GLenum -> IO ()
recordErrorCode e = do
_ <- getErrorCodesAux (\es -> (if null es then [e] else [], False))
return ()
recordInvalidEnum :: IO ()
recordInvalidEnum = recordErrorCode gl_INVALID_ENUM
recordInvalidValue :: IO ()
recordInvalidValue = recordErrorCode gl_INVALID_VALUE
recordOutOfMemory :: IO ()
recordOutOfMemory = recordErrorCode gl_OUT_OF_MEMORY
getErrorCodesAux :: ([GLenum] -> ([GLenum],Bool)) -> IO [GLenum]
getErrorCodesAux f = do
(recordedErrors, useGLErrors) <- getRecordedErrors
glErrors <- getGLErrors
let es = if useGLErrors then recordedErrors ++ glErrors else recordedErrors
setRecordedErrors (f es)
return es