module Graphics.Rendering.OpenGL.GL.CoordTrans (
depthRange,
Position(..), Size(..), viewport, maxViewportDims,
MatrixMode(..), matrixMode,
Vector2(..), Vector3(..),
MatrixOrder(..), MatrixComponent(rotate,translate,scale), Matrix(..),
currentMatrix, matrix, multMatrix, GLmatrix, loadIdentity,
ortho, frustum, depthClamp,
activeTexture,
preservingMatrix, unsafePreservingMatrix,
stackDepth, maxStackDepth,
rescaleNormal, normalize,
Plane(..), TextureCoordName(..), TextureGenMode(..), textureGenMode
) where
import Foreign.ForeignPtr ( ForeignPtr, mallocForeignPtrArray, withForeignPtr )
import Foreign.Marshal.Alloc ( alloca )
import Foreign.Marshal.Array ( allocaArray, peekArray, pokeArray, withArray )
import Foreign.Marshal.Utils ( with )
import Foreign.Ptr ( Ptr, castPtr )
import Foreign.Storable ( Storable(..) )
import Graphics.Rendering.OpenGL.GL.Capability (
EnableCap(CapRescaleNormal, CapNormalize,CapDepthClamp,
CapTextureGenS, CapTextureGenT,
CapTextureGenR, CapTextureGenQ),
makeCapability, makeStateVarMaybe )
import Graphics.Rendering.OpenGL.GL.BasicTypes (
GLenum, GLint, GLsizei, GLfloat, GLdouble, GLclampd, Capability(..) )
import Graphics.Rendering.OpenGL.GL.Exception ( bracket, unsafeBracket_ )
import Graphics.Rendering.OpenGL.GL.Extensions (
FunPtr, unsafePerformIO, Invoker, getProcAddress )
import Graphics.Rendering.OpenGL.GL.PeekPoke (
peek1, peek2, peek3, peek4, poke2, poke3, poke4 )
import Graphics.Rendering.OpenGL.GL.QueryUtils (
GetPName(GetDepthRange,GetViewport,GetMaxViewportDims,GetMatrixMode,
GetModelviewMatrix,GetProjectionMatrix,
GetTextureMatrix, GetColorMatrix,GetMatrixPalette,GetActiveTexture,
GetCurrentMatrixStackDepth,GetModelviewStackDepth,
GetMaxModelviewStackDepth,GetProjectionStackDepth,
GetMaxProjectionStackDepth,GetTextureStackDepth,
GetMaxTextureStackDepth,GetColorMatrixStackDepth,
GetMaxColorMatrixStackDepth,GetMaxMatrixPaletteStackDepth),
getInteger2, getInteger4, getEnum1, getSizei1, getFloatv,
getDouble2, getDoublev, modelviewIndexToEnum, modelviewEnumToIndex )
import Graphics.Rendering.OpenGL.GL.StateVar (
GettableStateVar, makeGettableStateVar, HasGetter(get), HasSetter(($=)),
StateVar, makeStateVar )
import Graphics.Rendering.OpenGL.GL.Texturing.TextureUnit (
marshalTextureUnit, unmarshalTextureUnit )
import Graphics.Rendering.OpenGL.GL.VertexSpec ( TextureUnit )
import Graphics.Rendering.OpenGL.GLU.ErrorsInternal (
recordInvalidEnum, recordInvalidValue )
#include "HsOpenGLExt.h"
#include "HsOpenGLTypes.h"
depthRange :: StateVar (GLclampd, GLclampd)
depthRange = makeStateVar (getDouble2 (,) GetDepthRange) (uncurry glDepthRange)
foreign import CALLCONV unsafe "glDepthRange" glDepthRange ::
GLclampd -> GLclampd -> IO ()
data Position = Position !GLint !GLint
deriving ( Eq, Ord, Show )
data Size = Size !GLsizei !GLsizei
deriving ( Eq, Ord, Show )
viewport :: StateVar (Position, Size)
viewport = makeStateVar (getInteger4 makeVp GetViewport)
(\(Position x y, Size w h) -> glViewport x y w h)
where makeVp x y w h = (Position x y, Size (fromIntegral w) (fromIntegral h))
foreign import CALLCONV unsafe "glViewport" glViewport ::
GLint -> GLint -> GLsizei -> GLsizei -> IO ()
maxViewportDims :: GettableStateVar Size
maxViewportDims = makeGettableStateVar (getInteger2 Size GetMaxViewportDims)
data MatrixMode =
Modelview GLsizei
| Projection
| Texture
| Color
| MatrixPalette
deriving ( Eq, Ord, Show )
marshalMatrixMode :: MatrixMode -> Maybe GLenum
marshalMatrixMode x = case x of
Modelview i -> modelviewIndexToEnum i
Projection -> Just 0x1701
Texture -> Just 0x1702
Color -> Just 0x1800
MatrixPalette -> Just 0x8840
unmarshalMatrixMode :: GLenum -> MatrixMode
unmarshalMatrixMode x
| x == 0x1701 = Projection
| x == 0x1702 = Texture
| x == 0x1800 = Color
| x == 0x8840 = MatrixPalette
| otherwise =
case modelviewEnumToIndex x of
Just i -> Modelview i
Nothing -> error ("unmarshalMatrixMode: illegal value " ++ show x)
matrixModeToGetMatrix :: MatrixMode -> GetPName
matrixModeToGetMatrix x = case x of
Modelview _ -> GetModelviewMatrix
Projection -> GetProjectionMatrix
Texture -> GetTextureMatrix
Color -> GetColorMatrix
MatrixPalette -> GetMatrixPalette
matrixModeToGetStackDepth :: MatrixMode -> GetPName
matrixModeToGetStackDepth x = case x of
Modelview _ -> GetModelviewStackDepth
Projection -> GetProjectionStackDepth
Texture -> GetTextureStackDepth
Color -> GetColorMatrixStackDepth
MatrixPalette -> error "matrixModeToGetStackDepth: impossible"
matrixModeToGetMaxStackDepth :: MatrixMode -> GetPName
matrixModeToGetMaxStackDepth x = case x of
Modelview _ -> GetMaxModelviewStackDepth
Projection -> GetMaxProjectionStackDepth
Texture -> GetMaxTextureStackDepth
Color -> GetMaxColorMatrixStackDepth
MatrixPalette -> GetMaxMatrixPaletteStackDepth
matrixMode :: StateVar MatrixMode
matrixMode =
makeStateVar (getEnum1 unmarshalMatrixMode GetMatrixMode)
(maybe recordInvalidValue glMatrixMode . marshalMatrixMode)
foreign import CALLCONV unsafe "glMatrixMode" glMatrixMode :: GLenum -> IO ()
data Vector2 a = Vector2 !a !a
deriving ( Eq, Ord, Show )
instance Storable a => Storable (Vector2 a) where
sizeOf ~(Vector2 x _) = 2 * sizeOf x
alignment ~(Vector2 x _) = alignment x
peek = peek2 Vector2 . castPtr
poke ptr (Vector2 x y) = poke2 (castPtr ptr) x y
data Vector3 a = Vector3 !a !a !a
deriving ( Eq, Ord, Show )
instance Storable a => Storable (Vector3 a) where
sizeOf ~(Vector3 x _ _) = 3 * sizeOf x
alignment ~(Vector3 x _ _) = alignment x
peek = peek3 Vector3 . castPtr
poke ptr (Vector3 x y z) = poke3 (castPtr ptr) x y z
data MatrixOrder = ColumnMajor | RowMajor
deriving ( Eq, Ord, Show )
class Storable c => MatrixComponent c where
getMatrix :: GetPName -> Ptr c -> IO ()
loadMatrix :: Ptr c -> IO ()
loadTransposeMatrix :: Ptr c -> IO ()
multMatrix_ :: Ptr c -> IO ()
multTransposeMatrix :: Ptr c -> IO ()
rotate :: c -> Vector3 c -> IO ()
translate :: Vector3 c -> IO ()
scale :: c -> c -> c -> IO ()
instance MatrixComponent GLfloat_ where
getMatrix = getFloatv
loadMatrix = glLoadMatrixf
loadTransposeMatrix = glLoadTransposeMatrixfARB
multMatrix_ = glMultMatrixf
multTransposeMatrix = glMultTransposeMatrixfARB
rotate a (Vector3 x y z) = glRotatef a x y z
translate (Vector3 x y z) = glTranslatef x y z
scale = glScalef
instance MatrixComponent GLdouble_ where
getMatrix = getDoublev
loadMatrix = glLoadMatrixd
loadTransposeMatrix = glLoadTransposeMatrixdARB
multMatrix_ = glMultMatrixd
multTransposeMatrix = glMultTransposeMatrixdARB
rotate a (Vector3 x y z) = glRotated a x y z
translate (Vector3 x y z) = glTranslated x y z
scale = glScaled
foreign import CALLCONV unsafe "glLoadMatrixf" glLoadMatrixf :: Ptr GLfloat -> IO ()
foreign import CALLCONV unsafe "glLoadMatrixd" glLoadMatrixd :: Ptr GLdouble -> IO ()
EXTENSION_ENTRY("GL_ARB_transpose_matrix or OpenGL 1.3",glLoadTransposeMatrixfARB,Ptr GLfloat -> IO ())
EXTENSION_ENTRY("GL_ARB_transpose_matrix or OpenGL 1.3",glLoadTransposeMatrixdARB,Ptr GLdouble -> IO ())
foreign import CALLCONV unsafe "glMultMatrixf" glMultMatrixf :: Ptr GLfloat -> IO ()
foreign import CALLCONV unsafe "glMultMatrixd" glMultMatrixd :: Ptr GLdouble -> IO ()
EXTENSION_ENTRY("GL_ARB_transpose_matrix or OpenGL 1.3",glMultTransposeMatrixfARB,Ptr GLfloat -> IO ())
EXTENSION_ENTRY("GL_ARB_transpose_matrix or OpenGL 1.3",glMultTransposeMatrixdARB,Ptr GLdouble -> IO ())
foreign import CALLCONV unsafe "glRotatef" glRotatef :: GLfloat -> GLfloat -> GLfloat -> GLfloat -> IO ()
foreign import CALLCONV unsafe "glRotated" glRotated :: GLdouble -> GLdouble -> GLdouble -> GLdouble -> IO ()
foreign import CALLCONV unsafe "glTranslatef" glTranslatef :: GLfloat -> GLfloat -> GLfloat -> IO ()
foreign import CALLCONV unsafe "glTranslated" glTranslated :: GLdouble -> GLdouble -> GLdouble -> IO ()
foreign import CALLCONV unsafe "glScalef" glScalef :: GLfloat -> GLfloat -> GLfloat -> IO ()
foreign import CALLCONV unsafe "glScaled" glScaled :: GLdouble -> GLdouble -> GLdouble -> IO ()
class Matrix m where
withNewMatrix ::
MatrixComponent c => MatrixOrder -> (Ptr c -> IO ()) -> IO (m c)
withMatrix ::
MatrixComponent c => m c -> (MatrixOrder -> Ptr c -> IO a) -> IO a
newMatrix :: MatrixComponent c => MatrixOrder -> [c] -> IO (m c)
getMatrixComponents :: MatrixComponent c => MatrixOrder -> m c -> IO [c]
withNewMatrix order act =
allocaArray 16 $ \p -> do
act p
components <- peekArray 16 p
newMatrix order components
withMatrix mat act = do
components <- getMatrixComponents ColumnMajor mat
withArray components $ act ColumnMajor
newMatrix order components =
withNewMatrix order $ flip pokeArray (take 16 components)
getMatrixComponents desiredOrder mat =
withMatrix mat $ \order p ->
if desiredOrder == order
then peekArray 16 p
else mapM (peekElemOff p) [ 0, 4, 8, 12,
1, 5, 9, 13,
2, 6, 10, 14,
3, 7, 11, 15 ]
currentMatrix :: (Matrix m, MatrixComponent c) => StateVar (m c)
currentMatrix = matrix Nothing
matrix :: (Matrix m, MatrixComponent c) => Maybe MatrixMode -> StateVar (m c)
matrix maybeMode =
makeStateVar
(maybe (get matrixMode) return maybeMode >>= (getMatrix' . matrixModeToGetMatrix))
(maybe id withMatrixMode maybeMode . setMatrix)
withMatrixMode :: MatrixMode -> IO a -> IO a
withMatrixMode mode act =
preservingMatrixMode $ do
matrixMode $= mode
act
getMatrix' :: (Matrix m, MatrixComponent c) => GetPName -> IO (m c)
getMatrix' = withNewMatrix ColumnMajor . getMatrix
setMatrix :: (Matrix m, MatrixComponent c) => m c -> IO ()
setMatrix mat =
withMatrix mat $ \order ->
case order of
ColumnMajor -> loadMatrix
RowMajor -> loadTransposeMatrix
multMatrix :: (Matrix m, MatrixComponent c) => m c -> IO ()
multMatrix mat =
withMatrix mat $ \order ->
case order of
ColumnMajor -> multMatrix_
RowMajor -> multTransposeMatrix
data GLmatrix a = GLmatrix MatrixOrder (ForeignPtr a)
#ifdef __HADDOCK__
instance Eq (GLmatrix a)
instance Ord (GLmatrix a)
instance Show (GLmatrix a)
#else
deriving ( Eq, Ord, Show )
#endif
instance Matrix GLmatrix where
withNewMatrix order f = do
fp <- mallocForeignPtrArray 16
withForeignPtr fp f
return $ GLmatrix order fp
withMatrix (GLmatrix order fp) f = withForeignPtr fp (f order)
foreign import CALLCONV unsafe "glLoadIdentity" loadIdentity :: IO ()
foreign import CALLCONV unsafe "glOrtho" ortho ::
GLdouble -> GLdouble -> GLdouble -> GLdouble -> GLdouble -> GLdouble -> IO ()
foreign import CALLCONV unsafe "glFrustum" frustum ::
GLdouble -> GLdouble -> GLdouble -> GLdouble -> GLdouble -> GLdouble -> IO ()
depthClamp :: StateVar Capability
depthClamp = makeCapability CapDepthClamp
activeTexture :: StateVar TextureUnit
activeTexture = makeStateVar (getEnum1 unmarshalTextureUnit GetActiveTexture)
(glActiveTextureARB . marshalTextureUnit)
EXTENSION_ENTRY("GL_ARB_multitexture or OpenGL 1.3",glActiveTextureARB,GLenum -> IO ())
preservingMatrix :: IO a -> IO a
preservingMatrix = unsafePreservingMatrix . preservingMatrixMode
preservingMatrixMode :: IO a -> IO a
preservingMatrixMode = bracket (getEnum1 id GetMatrixMode) glMatrixMode . const
unsafePreservingMatrix :: IO a -> IO a
unsafePreservingMatrix = unsafeBracket_ glPushMatrix glPopMatrix
foreign import CALLCONV unsafe "glPushMatrix" glPushMatrix :: IO ()
foreign import CALLCONV unsafe "glPopMatrix" glPopMatrix :: IO ()
stackDepth :: Maybe MatrixMode -> GettableStateVar GLsizei
stackDepth maybeMode =
makeGettableStateVar $
case maybeMode of
Nothing -> getSizei1 id GetCurrentMatrixStackDepth
Just MatrixPalette -> do recordInvalidEnum ; return 0
Just mode -> getSizei1 id (matrixModeToGetStackDepth mode)
maxStackDepth :: MatrixMode -> GettableStateVar GLsizei
maxStackDepth =
makeGettableStateVar . getSizei1 id . matrixModeToGetMaxStackDepth
rescaleNormal :: StateVar Capability
rescaleNormal = makeCapability CapRescaleNormal
normalize :: StateVar Capability
normalize = makeCapability CapNormalize
data Plane a = Plane !a !a !a !a
deriving ( Eq, Ord, Show )
instance Storable a => Storable (Plane a) where
sizeOf ~(Plane a _ _ _) = 4 * sizeOf a
alignment ~(Plane a _ _ _) = alignment a
peek = peek4 Plane . castPtr
poke ptr (Plane a b c d) = poke4 (castPtr ptr) a b c d
data TextureCoordName =
S
| T
| R
| Q
deriving ( Eq, Ord, Show )
marshalTextureCoordName :: TextureCoordName -> GLenum
marshalTextureCoordName x = case x of
S -> 0x2000
T -> 0x2001
R -> 0x2002
Q -> 0x2003
data TextureGenParameter =
TextureGenMode
| ObjectPlane
| EyePlane
marshalTextureGenParameter :: TextureGenParameter -> GLenum
marshalTextureGenParameter x = case x of
TextureGenMode -> 0x2500
ObjectPlane -> 0x2501
EyePlane -> 0x2502
data TextureGenMode' =
EyeLinear'
| ObjectLinear'
| SphereMap'
| NormalMap'
| ReflectionMap'
marshalTextureGenMode' :: TextureGenMode' -> GLint
marshalTextureGenMode' x = case x of
EyeLinear' -> 0x2400
ObjectLinear' -> 0x2401
SphereMap' -> 0x2402
NormalMap' -> 0x8511
ReflectionMap' -> 0x8512
unmarshalTextureGenMode' :: GLint -> TextureGenMode'
unmarshalTextureGenMode' x
| x == 0x2400 = EyeLinear'
| x == 0x2401 = ObjectLinear'
| x == 0x2402 = SphereMap'
| x == 0x8511 = NormalMap'
| x == 0x8512 = ReflectionMap'
| otherwise = error ("unmarshalTextureGenMode': illegal value " ++ show x)
data TextureGenMode =
EyeLinear (Plane GLdouble)
| ObjectLinear (Plane GLdouble)
| SphereMap
| NormalMap
| ReflectionMap
deriving ( Eq, Ord, Show )
marshalTextureGenMode :: TextureGenMode -> GLint
marshalTextureGenMode = marshalTextureGenMode' . convertMode
where convertMode (EyeLinear _) = EyeLinear'
convertMode (ObjectLinear _) = ObjectLinear'
convertMode SphereMap = SphereMap'
convertMode NormalMap = NormalMap'
convertMode ReflectionMap = ReflectionMap'
textureGenMode :: TextureCoordName -> StateVar (Maybe TextureGenMode)
textureGenMode coord =
makeStateVarMaybe
(return $ textureCoordNameToEnableCap coord)
(do mode <- getMode coord
case mode of
EyeLinear' -> fmap EyeLinear $ getPlane coord EyePlane
ObjectLinear' -> fmap ObjectLinear $ getPlane coord ObjectPlane
SphereMap' -> return SphereMap
NormalMap' -> return NormalMap
ReflectionMap' -> return ReflectionMap)
(\mode -> do
setMode coord mode
case mode of
EyeLinear plane -> setPlane coord EyePlane plane
ObjectLinear plane -> setPlane coord ObjectPlane plane
_ -> return ())
textureCoordNameToEnableCap :: TextureCoordName -> EnableCap
textureCoordNameToEnableCap coord = case coord of
S -> CapTextureGenS
T -> CapTextureGenT
R -> CapTextureGenR
Q -> CapTextureGenQ
getMode :: TextureCoordName -> IO TextureGenMode'
getMode coord = alloca $ \buf -> do
glGetTexGeniv (marshalTextureCoordName coord)
(marshalTextureGenParameter TextureGenMode)
buf
peek1 unmarshalTextureGenMode' buf
foreign import CALLCONV unsafe "glGetTexGeniv" glGetTexGeniv ::
GLenum -> GLenum -> Ptr GLint -> IO ()
setMode :: TextureCoordName -> TextureGenMode -> IO ()
setMode coord mode =
glTexGeni (marshalTextureCoordName coord)
(marshalTextureGenParameter TextureGenMode)
(marshalTextureGenMode mode)
foreign import CALLCONV unsafe "glTexGeni" glTexGeni ::
GLenum -> GLenum -> GLint -> IO ()
getPlane :: TextureCoordName -> TextureGenParameter -> IO (Plane GLdouble)
getPlane coord param = alloca $ \planeBuffer -> do
glGetTexGendv (marshalTextureCoordName coord)
(marshalTextureGenParameter param)
planeBuffer
peek planeBuffer
foreign import CALLCONV unsafe "glGetTexGendv" glGetTexGendv ::
GLenum -> GLenum -> Ptr (Plane GLdouble) -> IO ()
setPlane :: TextureCoordName -> TextureGenParameter -> Plane GLdouble -> IO ()
setPlane coord param plane =
with plane $ \planeBuffer ->
glTexGendv (marshalTextureCoordName coord)
(marshalTextureGenParameter param)
planeBuffer
foreign import CALLCONV unsafe "glTexGendv" glTexGendv ::
GLenum -> GLenum -> Ptr (Plane GLdouble) -> IO ()