-----------------------------------------------------------------------------
-- |
-- Module      :  Graphics.Rendering.OpenGL.GL.Shaders.Variables
-- Copyright   :
-- License     :  BSD3
--
-- Maintainer  :  Sven Panne <sven.panne@aedion.de>
-- Stability   :
-- Portability :
--
-- This internal module contains the functions and datatypes used by the
-- Uniform and Attribs modules.
--
-----------------------------------------------------------------------------

module Graphics.Rendering.OpenGL.GL.Shaders.Variables (
    VariableType(..), activeVars,
) where

import Graphics.Rendering.OpenGL.GL.GLstring

import Control.Monad
import Data.StateVar
import Foreign.Marshal.Alloc
import Foreign.Marshal.Array
import Foreign.Ptr
import Foreign.Storable
import Graphics.Rendering.OpenGL.Raw.Core31

import Graphics.Rendering.OpenGL.GL.Shaders.Program

-- Table 2.9 of the OpenGL 3.1 spec: OpenGL Shading Language type tokens
data VariableType =
     Float'
   | FloatVec2
   | FloatVec3
   | FloatVec4
   | Int'
   | IntVec2
   | IntVec3
   | IntVec4
   | UnsignedInt'
   | UnsignedIntVec2
   | UnsignedIntVec3
   | UnsignedIntVec4
   | Bool
   | BoolVec2
   | BoolVec3
   | BoolVec4
   | FloatMat2
   | FloatMat3
   | FloatMat4
   | FloatMat2x3
   | FloatMat2x4
   | FloatMat3x2
   | FloatMat3x4
   | FloatMat4x2
   | FloatMat4x3
   | Sampler1D
   | Sampler2D
   | Sampler3D
   | SamplerCube
   | Sampler1DShadow
   | Sampler2DShadow
   | Sampler1DArray
   | Sampler2DArray
   | Sampler1DArrayShadow
   | Sampler2DArrayShadow
   | SamplerCubeShadow
   | Sampler2DRect
   | Sampler2DRectShadow
   | IntSampler1D
   | IntSampler2D
   | IntSampler3D
   | IntSamplerCube
   | IntSampler1DArray
   | IntSampler2DArray
   | UnsignedIntSampler1D
   | UnsignedIntSampler2D
   | UnsignedIntSampler3D
   | UnsignedIntSamplerCube
   | UnsignedIntSampler1DArray
   | UnsignedIntSampler2DArray
   deriving ( Eq, Ord, Show )

unmarshalVariableType :: GLenum -> VariableType
unmarshalVariableType x
   | x == gl_FLOAT = Float'
   | x == gl_FLOAT_VEC2 = FloatVec2
   | x == gl_FLOAT_VEC3 = FloatVec3
   | x == gl_FLOAT_VEC4 = FloatVec4
   | x == gl_INT = Int'
   | x == gl_INT_VEC2 = IntVec2
   | x == gl_INT_VEC3 = IntVec3
   | x == gl_INT_VEC4 = IntVec4
   | x == gl_UNSIGNED_INT = UnsignedInt'
   | x == gl_UNSIGNED_INT_VEC2 = UnsignedIntVec2
   | x == gl_UNSIGNED_INT_VEC3 = UnsignedIntVec3
   | x == gl_UNSIGNED_INT_VEC4 = UnsignedIntVec4
   | x == gl_BOOL = Bool
   | x == gl_BOOL_VEC2 = BoolVec2
   | x == gl_BOOL_VEC3 = BoolVec3
   | x == gl_BOOL_VEC4 = BoolVec4
   | x == gl_FLOAT_MAT2 = FloatMat2
   | x == gl_FLOAT_MAT3 = FloatMat3
   | x == gl_FLOAT_MAT4 = FloatMat4
   | x == gl_FLOAT_MAT2x3 = FloatMat2x3
   | x == gl_FLOAT_MAT2x4 = FloatMat2x4
   | x == gl_FLOAT_MAT3x2 = FloatMat3x2
   | x == gl_FLOAT_MAT3x4 = FloatMat3x4
   | x == gl_FLOAT_MAT4x2 = FloatMat4x2
   | x == gl_FLOAT_MAT4x3 = FloatMat4x3
   | x == gl_SAMPLER_1D = Sampler1D
   | x == gl_SAMPLER_2D = Sampler2D
   | x == gl_SAMPLER_3D = Sampler3D
   | x == gl_SAMPLER_CUBE = SamplerCube
   | x == gl_SAMPLER_1D_SHADOW = Sampler1DShadow
   | x == gl_SAMPLER_2D_SHADOW = Sampler2DShadow
   | x == gl_SAMPLER_1D_ARRAY = Sampler1DArray
   | x == gl_SAMPLER_2D_ARRAY = Sampler2DArray
   | x == gl_SAMPLER_1D_ARRAY_SHADOW = Sampler1DArrayShadow
   | x == gl_SAMPLER_2D_ARRAY_SHADOW = Sampler2DArrayShadow
   | x == gl_SAMPLER_CUBE_SHADOW = SamplerCubeShadow
   | x == gl_SAMPLER_2D_RECT = Sampler2DRect
   | x == gl_SAMPLER_2D_RECT_SHADOW = Sampler2DRectShadow
   | x == gl_INT_SAMPLER_1D = IntSampler1D
   | x == gl_INT_SAMPLER_2D = IntSampler2D
   | x == gl_INT_SAMPLER_3D = IntSampler3D
   | x == gl_INT_SAMPLER_CUBE = IntSamplerCube
   | x == gl_INT_SAMPLER_1D_ARRAY = IntSampler1DArray
   | x == gl_INT_SAMPLER_2D_ARRAY = IntSampler2DArray
   | x == gl_UNSIGNED_INT_SAMPLER_1D = UnsignedIntSampler1D
   | x == gl_UNSIGNED_INT_SAMPLER_2D = UnsignedIntSampler2D
   | x == gl_UNSIGNED_INT_SAMPLER_3D = UnsignedIntSampler3D
   | x == gl_UNSIGNED_INT_SAMPLER_CUBE = UnsignedIntSamplerCube
   | x == gl_UNSIGNED_INT_SAMPLER_1D_ARRAY = UnsignedIntSampler1DArray
   | x == gl_UNSIGNED_INT_SAMPLER_2D_ARRAY = UnsignedIntSampler2DArray
   | otherwise = error ("unmarshalVariableType: illegal value " ++ show x)

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

activeVars :: (Program -> GettableStateVar GLuint)
           -> (Program -> GettableStateVar GLsizei)
           -> (GLuint -> GLuint -> GLsizei -> Ptr GLsizei -> Ptr GLint -> Ptr GLenum -> Ptr GLchar -> IO ())
           -> Program -> GettableStateVar [(GLint,VariableType,String)]
activeVars numVars maxLength getter p@(Program program) =
   makeGettableStateVar $ do
      numActiveVars <- get (numVars p)
      maxLen <- get (maxLength p)
      allocaArray (fromIntegral maxLen) $ \nameBuf ->
         alloca $ \nameLengthBuf ->
            alloca $ \sizeBuf ->
               alloca $ \typeBuf ->
                  forM [0 .. numActiveVars - 1] $ \i -> do
                    getter program i maxLen nameLengthBuf sizeBuf typeBuf nameBuf
                    l <- peek nameLengthBuf
                    s <- peek sizeBuf
                    t <- peek typeBuf
                    n <- peekGLstringLen (nameBuf, l)
                    return (s, unmarshalVariableType t, n)