-----------------------------------------------------------------------------
-- |
-- Module      :  Graphics.Rendering.OpenGL.GL.Shaders.ShaderObjects
-- Copyright   :  (c) Sven Panne 2006-2018
-- License     :  BSD3
--
-- Maintainer  :  Sven Panne <svenpanne@gmail.com>
-- Stability   :  stable
-- Portability :  portable
--
-- This module corresponds to section 7.1 (Shader Objects) and 7.13 (Shader,
-- Program, and Program Pipeline Queries) of the OpenGL 4.4 spec.
--
-----------------------------------------------------------------------------

module Graphics.Rendering.OpenGL.GL.Shaders.ShaderObjects (
   -- * Shader Objects
   shaderCompiler,
   ShaderType(..), Shader, createShader,
   shaderSourceBS, shaderSource, compileShader, releaseShaderCompiler,

   -- * Shader Queries
   shaderType, shaderDeleteStatus, compileStatus, shaderInfoLog,
   PrecisionType, shaderPrecisionFormat,

   -- * Bytestring utilities
   packUtf8, unpackUtf8
) where

import Control.Monad
import Data.StateVar
import Foreign.Marshal.Alloc
import Foreign.Marshal.Array
import Foreign.Marshal.Utils
import Foreign.Storable
import Graphics.Rendering.OpenGL.GL.ByteString
import Graphics.Rendering.OpenGL.GL.GLboolean
import Graphics.Rendering.OpenGL.GL.PeekPoke
import Graphics.Rendering.OpenGL.GL.QueryUtils
import Graphics.Rendering.OpenGL.GL.Shaders.Shader
import Graphics.GL

--------------------------------------------------------------------------------

shaderCompiler :: GettableStateVar Bool
shaderCompiler =
   makeGettableStateVar (getBoolean1 unmarshalGLboolean GetShaderCompiler)

--------------------------------------------------------------------------------

data ShaderType =
     VertexShader
   | TessControlShader
   | TessEvaluationShader
   | GeometryShader
   | FragmentShader
   | ComputeShader
   deriving ( Eq, Ord, Show )

marshalShaderType :: ShaderType -> GLenum
marshalShaderType x = case x of
   VertexShader -> GL_VERTEX_SHADER
   TessControlShader -> GL_TESS_CONTROL_SHADER
   TessEvaluationShader -> GL_TESS_EVALUATION_SHADER
   GeometryShader -> GL_GEOMETRY_SHADER
   FragmentShader -> GL_FRAGMENT_SHADER
   ComputeShader -> GL_COMPUTE_SHADER

unmarshalShaderType :: GLenum -> ShaderType
unmarshalShaderType x
   | x == GL_VERTEX_SHADER = VertexShader
   | x == GL_TESS_CONTROL_SHADER = TessControlShader
   | x == GL_TESS_EVALUATION_SHADER = TessEvaluationShader
   | x == GL_GEOMETRY_SHADER = GeometryShader
   | x == GL_FRAGMENT_SHADER = FragmentShader
   | x == GL_COMPUTE_SHADER = ComputeShader
   | otherwise = error ("unmarshalShaderType: illegal value " ++ show x)

--------------------------------------------------------------------------------

createShader :: ShaderType -> IO Shader
createShader = fmap Shader . glCreateShader . marshalShaderType

--------------------------------------------------------------------------------

-- | UTF8 encoded.
shaderSourceBS :: Shader -> StateVar ByteString
shaderSourceBS shader =
   makeStateVar (getShaderSource shader) (setShaderSource shader)

getShaderSource :: Shader -> IO ByteString
getShaderSource = stringQuery shaderSourceLength (glGetShaderSource . shaderID)

shaderSourceLength :: Shader -> GettableStateVar GLsizei
shaderSourceLength = shaderVar fromIntegral ShaderSourceLength

setShaderSource :: Shader -> ByteString -> IO ()
setShaderSource shader src =
   withByteString src $ \srcPtr srcLength ->
      with srcPtr $ \srcPtrBuf ->
         with srcLength $ \srcLengthBuf ->
            glShaderSource (shaderID shader)1 ring.OpenGL.GL.cal-6989586621679166508">messageIDsame="line-95">shader yass="hs-number">1 ring.OpenGL.GL.cal-6989586621679166508">shaderID-- * Byte>  ring.Opespan> ring.OpenGL.GL.cal-698959232">ring.OpenGL.GL.cal-6989586621679166508"> shaderID-- * Byte> shaderID-- * Byte>  ring.Opespan> ring.OpenGL.GL.cal-6989592354>ring.OpenGL.GL.cal-6989586621679172836"> shaderIDshaderID-- * Byte> shaderID-- * Byte>  ass="hs-identifilass="hs-special">, shadess="hs-spectype">GLfloinaries.html#bind4th">bind4th8/a> x x shaderIDuhaderIDTriangleStripTriangleStripshadess="hs-spectype"sp.Primitivg">ass="hs-identifilass="hs-special">/span>ass="hs-number">1 bind4th8/a> TriangleS"hs-identifier">x shaderIDuhaderID shaderIDshaderID-- * Bytef="#loc"10pass="hs-identifier">messageIDsame="line-95">shader ring.OpenGL.GL.cal-6989586621679166508">shaderID-- * Byte> -- spec.ar">getSizei1 id shaderID$ format
èC?./usr/share/doc/libghc-opengl-doc/html/src/Gran>ass="hs-identifilass="hs-special">, shadess="hs-spectt">-- spec.ar">getSizei1 id è./usr/share/doc/libghc-opengl-doc/html/src/Gran>ass="hs-identifilass="hs-special">, shadess="hs-spectt">-- spec.a./usr/share/doc/libghc-openg./usr/share/doc/libghc-èC?s-spectt">-- spame="local-dess="hs-spectt">-- spec.a./usr/sha- spec.-- spame="local-dess="hs-spectt">-- spec.a./usr/sha- spec.-- spame="local-dess="hs-spectt">-- spec.ad class="module">getInteger1 fromIntegral getInteger1ring.Opespan> ring.OpenGL.GL.cal-698959232">ring.OpenGL.GU.cal-6989varName = do <"Graphics-Rspan>-- sibaphics.Rendering.OpenGL.GL.QueryUtils.PName.html#GetNumS-- spg.sifier hs-var">getInteger1ring.Opespan> g.sifier hs-var">getInteger1 = do <"Graphics-Rspan>-- sibaphiame="marshalConring.OpenGL.GL.cal-698959232">rinlinpenGL.GU.cal-6989varName-- clearDepth-- spame="local-dess="hs-spectt">-- spec.ad class="module">, = do <"Gr ad class="module">,r hs-var">getInteger1an class="hs-span>-- spg.OpenGL.GLd class="motule">= do <"Gr getInteger1 fromIntegral -h">-> Just GL_ARRAY_ELEMENT_LOCK_COUNT_EXT Shader where Shader 9640"> 8ShaderBinaryFormat GLenum/span>where Shadene-689">Shader -- withByteString