summaryrefslogtreecommitdiff
path: root/src/LambdaCube/GL/Input
diff options
context:
space:
mode:
Diffstat (limited to 'src/LambdaCube/GL/Input')
-rw-r--r--src/LambdaCube/GL/Input/Type.hs527
1 files changed, 527 insertions, 0 deletions
diff --git a/src/LambdaCube/GL/Input/Type.hs b/src/LambdaCube/GL/Input/Type.hs
new file mode 100644
index 0000000..eaadce5
--- /dev/null
+++ b/src/LambdaCube/GL/Input/Type.hs
@@ -0,0 +1,527 @@
1{-# LANGUAGE DataKinds #-}
2{-# LANGUAGE DefaultSignatures #-}
3{-# LANGUAGE FlexibleContexts #-}
4{-# LANGUAGE FlexibleInstances #-}
5{-# LANGUAGE GADTs #-}
6{-# LANGUAGE KindSignatures #-}
7{-# LANGUAGE MultiParamTypeClasses #-}
8{-# LANGUAGE PolyKinds #-}
9{-# LANGUAGE RankNTypes #-}
10{-# LANGUAGE StandaloneDeriving #-}
11
12-- | Module : LambdaCube.GL.Input.Type
13--
14-- This module provides types for describing the matrix and vector ABI for
15-- passing vectors and matrices to OpenGL shaders as "uniforms".
16--
17-- For a given shader input 'InputType', there is associated (via
18-- 'witnessType') a type-level description of the GL calls necessary to upload
19-- pointers to the GPU.
20--
21-- To make it so that a Haskell value can be uploaded, instances of 'GLData'
22-- and 'Uniformable' should be provided. These describe how to marshall a
23-- haskell type into a suitable pointer for a given context.
24--
25-- For example, users of the hmatrix package, might find these instances useful:
26--
27-- > import GHC.TypeLits
28-- > import LambdaCube.GL.Input.Type
29-- > import Numeric.LinearAlgebra
30-- > import Numeric.LinearAlgebra.Devel
31-- >
32-- > instance Uniformable (Matrix Float) where
33-- > uniformContexts _ = contexts floatMatrices
34-- >
35-- > instance Uniformable (Vector Float) where
36-- > uniformContexts _ = contexts $ do
37-- > supports TypeFloat
38-- > supports TypeV2F
39-- > supports TypeV3F
40-- > supports TypeV4F
41-- >
42-- > instance (KnownNat r, KnownNat c) => GLData (Matrix Float) (GLMatrix r c Float) where
43-- > marshalUniform abi mat = case matrixDimensions abi of
44-- > (r,c) | fromIntegral (natVal r) /= rows mat -> Nothing
45-- > | fromIntegral (natVal c) /= cols mat -> Nothing
46-- > _ -> let isRowOrder = case orderOf mat of
47-- > RowMajor -> 1
48-- > ColumnMajor -> 0
49-- > in Just $ MarshalGLMatrix
50-- > $ \f -> apply mat (\ptr -> f 1 isRowOrder ptr) (\r c sr sc ptr -> ptr)
51-- >
52-- > instance KnownNat n => GLData (Vector Float) (GLVector n Float) where
53-- > marshalUniform abi vec
54-- > | natVal (vectorLength abi) /= fromIntegral (size vec) = Nothing
55-- > | otherwise = Just $ MarshalGLVector
56-- > $ \f -> apply vec (\ptr -> f 1 ptr) (\n ptr -> ptr)
57module LambdaCube.GL.Input.Type where
58
59import Control.Monad
60import Control.Monad.State
61import Data.Functor.Identity
62import Data.Typeable
63import Foreign
64import GHC.TypeLits
65
66import Data.Dependent.Map as DMap
67import Data.Dependent.Sum
68import Data.GADT.Compare
69
70import Graphics.GL.Core33
71import LambdaCube.IR (InputType(..))
72
73
74-- | A 'Uniformable' type /a/ has a runtime dictionary of available instances
75-- of 'GLData' /a/ /c/. For example, if you have a matrix type that does
76-- not include type-level dimension information, you may want to set
77--
78-- > uniformContexts _ = contexts floatMatrices
79--
80-- Use 'contexts' and 'supports' to list individual instances. Typically, for
81-- dimension-specific types, 'uniformContexts' will be a singleton map.
82--
83-- Note that if a context is known at compile-time, then the compiler can
84-- lookup an appropriate instance. This class is provided so that the lookup
85-- can happen at runtime instead.
86class Uniformable a where
87 uniformContexts :: proxy a -> DMap TypeTag (UniformContext a)
88
89-- | A light wrapper over 'execState' to make it easier to specify the
90-- 'uniformContexts' DMap.
91contexts :: State (DMap TypeTag (UniformContext a)) () -> DMap TypeTag (UniformContext a)
92contexts = flip execState DMap.empty
93
94-- | Inserts an instance into the 'uniformContexts' DMap. See 'floatMatrices'
95-- for an example.
96supports :: GLData a c => TypeTag c -> State (DMap TypeTag (UniformContext a)) ()
97supports ty = modify' (DMap.insert ty UniformContext)
98
99
100-- | A set of GLData instances for all Float matrix types. It is defined:
101--
102-- > floatMatrices = do
103-- > supports TypeM22F
104-- > supports TypeM23F
105-- > supports TypeM24F
106-- > supports TypeM32F
107-- > supports TypeM33F
108-- > supports TypeM34F
109-- > supports TypeM42F
110-- > supports TypeM43F
111-- > supports TypeM44F
112--
113-- Use 'contexts' to turn this into a 'DMap' suitable to implemented 'uniformContexts'.
114floatMatrices :: (GLData a (GLMatrix 2 2 Float),
115 GLData a (GLMatrix 2 3 Float),
116 GLData a (GLMatrix 2 4 Float),
117 GLData a (GLMatrix 3 2 Float),
118 GLData a (GLMatrix 3 3 Float),
119 GLData a (GLMatrix 3 4 Float),
120 GLData a (GLMatrix 4 2 Float),
121 GLData a (GLMatrix 4 3 Float),
122 GLData a (GLMatrix 4 4 Float)) =>
123 State (DMap TypeTag (UniformContext a)) ()
124floatMatrices = do
125 supports TypeM22F
126 supports TypeM23F
127 supports TypeM24F
128 supports TypeM32F
129 supports TypeM33F
130 supports TypeM34F
131 supports TypeM42F
132 supports TypeM43F
133 supports TypeM44F
134
135-- | A runtime witness for an instance of 'GLData' /a/ /c/. To obtain a
136-- witness given a specific context 'TypeTag' /c/, perform a lookup into the
137-- 'uniformContexts' DMap.
138data UniformContext a c = GLData a c => UniformContext
139
140-- | Type-check (at runtime) a specific GLData instance.
141knownContext :: (GLData a have, Typeable have, Typeable want) => TypeTag have -> TypeTag want -> Maybe (UniformContext a want)
142knownContext known ty = do
143 Refl <- withTypes known ty <$> eqT
144 return UniformContext
145
146-- | Lookup a GLData instance, given a Uniformable value.
147resolveContext :: Uniformable a => a -> TypeTag want -> Maybe (UniformContext a want)
148resolveContext val ty = DMap.lookup ty . uniformContexts . mkproxy $ val
149 where
150 mkproxy :: val -> Proxy val
151 mkproxy _ = Proxy
152
153
154-- | This type classifies a shader "uniform" input based on the OpenGL calls
155-- necessary to upload it to the GPU. The primitive types are described as if
156-- they are 1-vectors. Vector types are described by 'GLVector' and matrix
157-- types are described by 'GLMatrix'.
158--
159-- Currently, Texture uniforms are not described and there is a, probably
160-- useless, run-time distinction between Bool and Word which have the same
161-- OpenGL ABI.
162--
163-- Use 'witnessType' to obtain this from a runtime-only value.
164data TypeTag t where
165 TypeBool :: TypeTag (GLVector 1 Word32)
166 TypeV2B :: TypeTag (GLVector 2 Word32)
167 TypeV3B :: TypeTag (GLVector 3 Word32)
168 TypeV4B :: TypeTag (GLVector 4 Word32)
169 TypeWord :: TypeTag (GLVector 1 Word32)
170 TypeV2U :: TypeTag (GLVector 2 Word32)
171 TypeV3U :: TypeTag (GLVector 3 Word32)
172 TypeV4U :: TypeTag (GLVector 4 Word32)
173
174 TypeInt :: TypeTag (GLVector 1 Int32)
175 TypeV2I :: TypeTag (GLVector 2 Int32)
176 TypeV3I :: TypeTag (GLVector 3 Int32)
177 TypeV4I :: TypeTag (GLVector 4 Int32)
178
179 TypeFloat :: TypeTag (GLVector 1 Float)
180 TypeV2F :: TypeTag (GLVector 2 Float)
181 TypeV3F :: TypeTag (GLVector 3 Float)
182 TypeV4F :: TypeTag (GLVector 4 Float)
183
184 TypeM22F :: TypeTag (GLMatrix 2 2 Float)
185 TypeM23F :: TypeTag (GLMatrix 3 2 Float)
186 TypeM24F :: TypeTag (GLMatrix 4 2 Float)
187 TypeM32F :: TypeTag (GLMatrix 2 3 Float)
188 TypeM33F :: TypeTag (GLMatrix 3 3 Float)
189 TypeM34F :: TypeTag (GLMatrix 4 3 Float)
190 TypeM42F :: TypeTag (GLMatrix 2 4 Float)
191 TypeM43F :: TypeTag (GLMatrix 3 4 Float)
192 TypeM44F :: TypeTag (GLMatrix 4 4 Float)
193
194instance GEq TypeTag where
195 geq a b = do
196 Refl <- geq (glABI a) (glABI b)
197 guard $ isBoolTag a == isBoolTag b
198 return Refl
199
200instance GCompare TypeTag where
201 gcompare a b = case compare (isBoolTag a) (isBoolTag b) of
202 LT -> GLT
203 EQ -> gcompare (glABI a) (glABI b)
204 GT -> GGT
205
206-- | This function provides the only term-only information in the 'TypeTag'
207-- type. Booleans are treated similarly to unsigned ints by OpenGL, so the
208-- distinction is not made in the type of the tag and the 'GEq' instance of
209-- 'TypeTag' must use this helper to help distinguish based on on the runtime
210-- information.
211isBoolTag :: TypeTag t -> Bool
212isBoolTag TypeBool = True
213isBoolTag TypeV2B = True
214isBoolTag TypeV3B = True
215isBoolTag TypeV4B = True
216isBoolTag _ = False
217
218
219-- | Obtain a type-level description of a uniform type context.
220--
221-- See 'unwitnessType' for the inverse operation.
222witnessType :: InputType -> Maybe (Some TypeTag)
223witnessType Bool = Just $ This TypeBool
224witnessType V2B = Just $ This TypeV2B
225witnessType V3B = Just $ This TypeV3B
226witnessType V4B = Just $ This TypeV4B
227witnessType Word = Just $ This TypeWord
228witnessType V2U = Just $ This TypeV2U
229witnessType V3U = Just $ This TypeV3U
230witnessType V4U = Just $ This TypeV4U
231witnessType Int = Just $ This TypeInt
232witnessType V2I = Just $ This TypeV2I
233witnessType V3I = Just $ This TypeV3I
234witnessType V4I = Just $ This TypeV4I
235witnessType Float = Just $ This TypeFloat
236witnessType V2F = Just $ This TypeV2F
237witnessType V3F = Just $ This TypeV3F
238witnessType V4F = Just $ This TypeV4F
239witnessType M22F = Just $ This TypeM22F
240witnessType M23F = Just $ This TypeM23F
241witnessType M24F = Just $ This TypeM24F
242witnessType M32F = Just $ This TypeM32F
243witnessType M33F = Just $ This TypeM33F
244witnessType M34F = Just $ This TypeM34F
245witnessType M42F = Just $ This TypeM42F
246witnessType M43F = Just $ This TypeM43F
247witnessType M44F = Just $ This TypeM44F
248witnessType _ = Nothing
249
250-- | Discard type-level input information. Inverse of 'witnessType'.
251unwitnessType :: TypeTag c -> InputType
252unwitnessType TypeBool = Bool
253unwitnessType TypeV2B = V2B
254unwitnessType TypeV3B = V3B
255unwitnessType TypeV4B = V4B
256unwitnessType TypeWord = Word
257unwitnessType TypeV2U = V2U
258unwitnessType TypeV3U = V3U
259unwitnessType TypeV4U = V4U
260unwitnessType TypeInt = Int
261unwitnessType TypeV2I = V2I
262unwitnessType TypeV3I = V3I
263unwitnessType TypeV4I = V4I
264unwitnessType TypeFloat = Float
265unwitnessType TypeV2F = V2F
266unwitnessType TypeV3F = V3F
267unwitnessType TypeV4F = V4F
268unwitnessType TypeM22F = M22F
269unwitnessType TypeM23F = M23F
270unwitnessType TypeM24F = M24F
271unwitnessType TypeM32F = M32F
272unwitnessType TypeM33F = M33F
273unwitnessType TypeM34F = M34F
274unwitnessType TypeM42F = M42F
275unwitnessType TypeM43F = M43F
276unwitnessType TypeM44F = M44F
277
278
279-- | A function used to upload a "uniform" primitive value or vector to the
280-- GPU. If /n/ is 1, then it uploads a primitive value of type /typ/.
281-- Otherwise, it uploads a vector of length /n/.
282--
283-- The arguments to the function are:
284--
285-- * An integer naming the uniform input slot.
286--
287-- * An element count which, if greater than 1, will bulk-upload an array of
288-- values.
289--
290-- * A pointer to the value or values to be uploaded.
291--
292-- Use 'glUniform' to obtain this for a given type context.
293data GLVector (n :: Nat) typ
294 = GLVector (Int32 -> GLsizei -> Ptr typ -> IO ())
295
296
297-- | A function used to upload a "uniform" /r/ × /c/ matrix of /typ/ to the
298-- GPU. The arguments are:
299--
300-- * An integer naming the uniform input slot.
301--
302-- * An element count which, if greater than 1, will bulk-upload an array.
303--
304-- * A flag that is GL_TRUE if the values at the pointer are arranged in
305-- row-major order. Set this to GL_FALSE to indicate column-major ordering.
306-- Row-major means that the first /c/ contiguous values at the pointer
307-- constitute the first row of the matrix.
308--
309-- * A pointer to the matrix values.
310--
311-- IMPORTANT: This type flouts the usual graphics convention of width×height,
312-- which is used in the naming of the constructors for 'InputType' and
313-- 'TypeTag', and instead instead follows the opposite, matrix-math convention,
314-- of rows×columns. Thus, @'TypeM42F'@ is associated with @(GLMatrix 2 4
315-- Float)@.
316--
317-- Use 'glUniform' to obtain this for a given type context.
318data GLMatrix (r :: Nat) (c :: Nat) typ
319 = GLMatrix (Int32 -> GLsizei -> GLboolean -> Ptr typ -> IO ())
320
321-- | Obtain a suitable 'GLVector' or 'GLMatrix' OpenGL API function for a given
322-- uniform type.
323glUniform :: TypeTag a -> a
324glUniform TypeBool = GLVector glUniform1uiv
325glUniform TypeWord = GLVector glUniform1uiv
326glUniform TypeInt = GLVector glUniform1iv
327glUniform TypeFloat = GLVector glUniform1fv
328glUniform TypeV2B = GLVector glUniform2uiv
329glUniform TypeV2U = GLVector glUniform2uiv
330glUniform TypeV2I = GLVector glUniform2iv
331glUniform TypeV2F = GLVector glUniform2fv
332glUniform TypeV3B = GLVector glUniform3uiv
333glUniform TypeV3U = GLVector glUniform3uiv
334glUniform TypeV3I = GLVector glUniform3iv
335glUniform TypeV3F = GLVector glUniform3fv
336glUniform TypeV4B = GLVector glUniform4uiv
337glUniform TypeV4U = GLVector glUniform4uiv
338glUniform TypeV4I = GLVector glUniform4iv
339glUniform TypeV4F = GLVector glUniform4fv
340glUniform TypeM22F = GLMatrix glUniformMatrix2fv
341glUniform TypeM23F = GLMatrix glUniformMatrix2x3fv
342glUniform TypeM24F = GLMatrix glUniformMatrix2x4fv
343glUniform TypeM32F = GLMatrix glUniformMatrix3x2fv
344glUniform TypeM33F = GLMatrix glUniformMatrix3fv
345glUniform TypeM34F = GLMatrix glUniformMatrix3x4fv
346glUniform TypeM42F = GLMatrix glUniformMatrix4x2fv
347glUniform TypeM43F = GLMatrix glUniformMatrix4x3fv
348glUniform TypeM44F = GLMatrix glUniformMatrix4fv
349
350-- | 'GLData' /a/ /c/ is true when /a/ can be used as GL shader "uniform"
351-- input for a 'GLVector' or 'GLMatrix' uniform context /c/.
352--
353-- For simple (non-matrix) types that implement 'Storable', a default
354-- implementation, implemented by 'marshalUniformStorable', is provided, so in
355-- this case, simply declare the instance. If a 'Storable' column-major matrix
356-- type, 'marshalColumnMajor' can be used.
357class (Typeable c, Typeable a) => GLData a c where
358 -- | Provide a pointer suitable for passing to the OpenGL api.
359 marshalUniform :: GLABI c -- ^ Description of the variable type of the GL uniform.
360 -> a -- ^ The value to upload to the GPU.
361 -> Maybe (MarshalGL c)
362
363 default marshalUniform :: ( c ~ GLVector n typ
364 , Storable a
365 ) => GLABI c -> a -> Maybe (MarshalGL c)
366 marshalUniform _ a = Just (marshalUniformStorable a)
367
368-- | A suitable default for 'Storable' uniform non-matrix types.
369marshalUniformStorable :: Storable a => a -> MarshalGL (GLVector n typ)
370marshalUniformStorable a = MarshalGLVector $ \f -> with a (f 1 . castPtr)
371
372-- | A suitable default for 'Storable' uniform column-major matrix types.
373-- Column-major means that columns are stored as contiguous regions of memory
374-- at the pointer.
375marshalColumnMajor :: Storable a => a -> MarshalGL (GLMatrix r c typ)
376marshalColumnMajor a = MarshalGLMatrix $ \f -> with a (f 1 GL_FALSE . castPtr)
377
378
379-- | Run-time information about a "uniform" type context. A proxy for the
380-- pointer type is provided directly. You can use 'vectorLength' or
381-- 'matrixDimensions' to extract proxies for size information.
382--
383-- You can obtain this from a 'TypeTag' using 'glABI'.
384data GLABI m where
385 IsGLVector :: KnownNat n => GLPointerType typ -> GLABI (GLVector n typ)
386 IsGLMatrix :: (KnownNat r, KnownNat c) => GLPointerType typ -> GLABI (GLMatrix r c typ)
387
388instance GEq GLABI where
389 geq a@(IsGLVector x) b@(IsGLVector y) = do
390 Refl <- geq x y
391 Refl <- withTypes (vectorLength a) (vectorLength b) <$> eqT
392 return Refl
393 geq a@(IsGLMatrix x) b@(IsGLMatrix y) = do
394 Refl <- geq x y
395 let (ar,ac) = matrixDimensions a
396 (br,bc) = matrixDimensions b
397 Refl <- withTypes (asTypeOf ar RowCount) (asTypeOf br RowCount) <$> eqT
398 Refl <- withTypes (asTypeOf ac ColumnCount) (asTypeOf bc ColumnCount) <$> eqT
399 return Refl
400 geq _ _ = Nothing
401
402instance GCompare GLABI where
403 gcompare IsGLVector{} IsGLMatrix{} = GLT
404 gcompare IsGLMatrix{} IsGLVector{} = GGT
405 gcompare a@(IsGLVector x) b@(IsGLVector y) = case gcompare x y of
406 GLT -> GLT
407 GEQ -> case withTypes (vectorLength a) (vectorLength b) <$> eqT of
408 Just Refl -> GEQ
409 Nothing -> case compare (natVal $ vectorLength a) (natVal $ vectorLength b) of
410 LT -> GLT
411 GT -> GGT
412 GGT -> GGT
413 gcompare a@(IsGLMatrix x) b@(IsGLMatrix y) = case gcompare x y of
414 GLT -> GLT
415 GEQ -> case matrixDimensions a of
416 (ar,ac) -> case matrixDimensions b of
417 (br,bc) -> case withTypes ar br <$> eqT of
418 Just Refl -> case withTypes ac bc <$> eqT of
419 Just Refl -> GEQ
420 Nothing -> if natVal ac < natVal bc then GLT else GGT
421 Nothing -> if natVal ar < natVal br then GLT else GGT
422 GGT -> GGT
423
424
425-- | Run-time encoding of the type of passed pointer to the OpenGL api for a
426-- given uniform.
427data GLPointerType typ where
428 GLPrimUInt :: GLPointerType Word32
429 GLPrimInt :: GLPointerType Int32
430 GLPrimFloat :: GLPointerType Float
431
432deriving instance Show (GLPointerType typ)
433
434instance GEq GLPointerType where
435 geq GLPrimUInt GLPrimUInt = Just Refl
436 geq GLPrimInt GLPrimInt = Just Refl
437 geq GLPrimFloat GLPrimFloat = Just Refl
438
439instance GCompare GLPointerType where
440 gcompare GLPrimUInt GLPrimUInt = GEQ
441 gcompare GLPrimUInt _ = GLT
442 gcompare GLPrimFloat GLPrimFloat = GEQ
443 gcompare GLPrimFloat _ = GGT
444 gcompare GLPrimInt GLPrimUInt = GLT
445 gcompare GLPrimInt GLPrimInt = GEQ
446 gcompare GLPrimInt GLPrimFloat = GGT
447
448-- | Convenience proxy for the number of dimensions in a vector.
449data VectorLength (n :: Nat) = VectorLength
450
451-- | Extract the number of dimensions in a vector from a 'GLABI'.
452vectorLength :: GLABI (GLVector n typ) -> VectorLength n
453vectorLength IsGLVector{} = VectorLength
454
455-- | Convenience proxy for the number of rows in a matrix.
456data RowCount (n :: Nat) = RowCount
457
458-- | Convenience proxy for the number of columns in a matrix.
459data ColumnCount (n :: Nat) = ColumnCount
460
461-- | Extract row and column counts from a 'GLABI'.
462matrixDimensions :: GLABI (GLMatrix r c typ) -> (RowCount r, ColumnCount c)
463matrixDimensions IsGLMatrix{} = (RowCount,ColumnCount)
464
465-- | Convenience accessor for the pointer type proxy of a 'GLABI'.
466ptrType :: GLABI (f t) -> GLPointerType t
467ptrType (IsGLVector p) = p
468ptrType (IsGLMatrix p) = p
469
470
471-- | Provides a pointer and element count to a given continuation.
472--
473-- If the pointer refers to matrix data, then a 'GLboolean' is also passed.
474-- This is GL_TRUE when the matrix data is in row-major format (i.e. matrix
475-- rows are contiguous blocks of memory.)
476data MarshalGL c where
477
478 MarshalGLVector :: (forall b. (GLsizei -> Ptr typ -> IO b) -> IO b)
479 -> MarshalGL (GLVector n typ)
480
481 MarshalGLMatrix :: (forall b. (GLsizei -> GLboolean -> Ptr typ -> IO b) -> IO b)
482 -> MarshalGL (GLMatrix r c typ)
483
484
485-- | Obtain a type-level description for a given input context. This is
486-- similar to 'glUniform' except that it is used only as description and does
487-- not provide the actual OpenGL API function.
488glABI :: TypeTag a -> GLABI a
489glABI TypeBool = IsGLVector GLPrimUInt
490glABI TypeWord = IsGLVector GLPrimUInt
491glABI TypeInt = IsGLVector GLPrimInt
492glABI TypeFloat = IsGLVector GLPrimFloat
493glABI TypeV2B = IsGLVector GLPrimUInt
494glABI TypeV2U = IsGLVector GLPrimUInt
495glABI TypeV2I = IsGLVector GLPrimInt
496glABI TypeV2F = IsGLVector GLPrimFloat
497glABI TypeV3B = IsGLVector GLPrimUInt
498glABI TypeV3U = IsGLVector GLPrimUInt
499glABI TypeV3I = IsGLVector GLPrimInt
500glABI TypeV3F = IsGLVector GLPrimFloat
501glABI TypeV4B = IsGLVector GLPrimUInt
502glABI TypeV4U = IsGLVector GLPrimUInt
503glABI TypeV4I = IsGLVector GLPrimInt
504glABI TypeV4F = IsGLVector GLPrimFloat
505glABI TypeM22F = IsGLMatrix GLPrimFloat
506glABI TypeM23F = IsGLMatrix GLPrimFloat
507glABI TypeM24F = IsGLMatrix GLPrimFloat
508glABI TypeM32F = IsGLMatrix GLPrimFloat
509glABI TypeM33F = IsGLMatrix GLPrimFloat
510glABI TypeM34F = IsGLMatrix GLPrimFloat
511glABI TypeM42F = IsGLMatrix GLPrimFloat
512glABI TypeM43F = IsGLMatrix GLPrimFloat
513glABI TypeM44F = IsGLMatrix GLPrimFloat
514
515-- | This is a convenience utility to provide explicit context to
516-- type-equality. For example, to compare types denoted by proxies /a/ and
517-- /b/, use
518--
519-- > case withTypes a b <$> eqT of
520-- > Just Refl -> typesAreEqual
521-- > Nothing -> typesArenotEqual
522--
523-- This utility is not OpenGL related, but it is used by the GCompare instances
524-- implemented here.
525withTypes :: p (a::k) -> q (b::k) -> f a b -> f a b
526withTypes _ _ x = x
527