module Graphics.Rendering.OpenGL.GL.Shaders.ProgramObjects (
   
   Program, createProgram, programDeleteStatus,
   attachShader, detachShader, attachedShaders,
   linkProgram, linkStatus,
   validateProgram, validateStatus,
   programInfoLog,
   currentProgram,
   programSeparable, programBinaryRetrievableHint,
   
   
   
   
   
   
   
   
   
   
   bindFragDataLocation, getFragDataLocation
) where
import Data.List
import Data.Maybe
import Data.StateVar
import Foreign.Marshal.Array
import Foreign.Ptr
import Graphics.Rendering.OpenGL.GL.ByteString
import Graphics.Rendering.OpenGL.GL.Framebuffer
import Graphics.Rendering.OpenGL.GL.GLboolean
import Graphics.Rendering.OpenGL.GL.QueryUtils
import Graphics.Rendering.OpenGL.GL.Shaders.Program
import Graphics.Rendering.OpenGL.GL.Shaders.Shader
import Graphics.GL
createProgram :: IO Program
createProgram = fmap Program glCreateProgram
attachShader :: Program -> Shader -> IO ()
attachShader p s = glAttachShader (programID p) (shaderID s)
detachShader :: Program -> Shader -> IO ()
detachShader p s = glDetachShader (programID p) (shaderID s)
attachedShaders :: Program -> StateVar [Shader]
attachedShaders program =
   makeStateVar (getAttachedShaders program) (setAttachedShaders program)
getAttachedShaders :: Program -> IO [Shader]
getAttachedShaders program = do
   numShaders <- get (numAttachedShaders program)
   ids <- allocaArray (fromIntegral numShaders) $ \buf -> do
      glGetAttachedShaders (programID program) numShaders nullPtr buf
      peekArray (fromIntegral numShaders) buf
   return $ map Shader ids
setAttachedShaders :: Program -> [Shader] -> IO ()
setAttachedShaders program newShaders = do
   currentShaders <- getAttachedShaders program
   mapM_ (attachShader program) (newShaders \\ currentShaders)
   mapM_ (detachShader program) (currentShaders \\ newShaders)
linkProgram :: Program -> IO ()
linkProgram = glLinkProgram . programID
currentProgram :: StateVar (Maybe Program)
currentProgram =
   makeStateVar
      (do p <- fmap Program $ getInteger1 fromIntegral GetCurrentProgram
          return $ if p == noProgram then Nothing else Just p)
      (glUseProgram . programID . fromMaybe noProgram)
noProgram :: Program
noProgram = Program 0
validateProgram :: Program -> IO ()
validateProgram = glValidateProgram . programID
programInfoLog :: Program -> GettableStateVar String
programInfoLog =
   makeGettableStateVar .
      fmap unpackUtf8 .
         stringQuery programInfoLogLength (glGetProgramInfoLog . programID)
programSeparable :: Program -> StateVar Bool
programSeparable = programStateVarBool ProgramSeparable
programBinaryRetrievableHint :: Program -> StateVar Bool
programBinaryRetrievableHint = programStateVarBool ProgramBinaryRetrievableHint
programStateVarBool :: GetProgramPName -> Program -> StateVar Bool
programStateVarBool pname program =
   makeStateVar
      (get (programVar1 unmarshalGLboolean pname program))
      (glProgramParameteri (programID program)
                           (marshalGetProgramPName pname) . marshalGLboolean)
programDeleteStatus :: Program -> GettableStateVar Bool
programDeleteStatus = programVar1 unmarshalGLboolean ProgramDeleteStatus
linkStatus :: Program -> GettableStateVar Bool
linkStatus = programVar1 unmarshalGLboolean LinkStatus
validateStatus :: Program -> GettableStateVar Bool
validateStatus = programVar1 unmarshalGLboolean ValidateStatus
programInfoLogLength :: Program -> GettableStateVar GLsizei
programInfoLogLength = programVar1 fromIntegral ProgramInfoLogLength
numAttachedShaders :: Program -> GettableStateVar GLsizei
numAttachedShaders = programVar1 fromIntegral AttachedShaders
bindFragDataLocation :: Program -> String -> SettableStateVar DrawBufferIndex
bindFragDataLocation (Program program) varName = makeSettableStateVar $ \ind ->
   withGLstring varName $ glBindFragDataLocation program ind
getFragDataLocation :: Program -> String -> IO (Maybe DrawBufferIndex)
getFragDataLocation (Program program) varName = do
   r <- withGLstring varName $ glGetFragDataLocation program
   if r < 0
    then return Nothing
    else return . Just $ fromIntegral r