diff options
Diffstat (limited to 'src/LambdaCube/GL/Input')
-rw-r--r-- | src/LambdaCube/GL/Input/Type.hs | 527 |
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) | ||
57 | module LambdaCube.GL.Input.Type where | ||
58 | |||
59 | import Control.Monad | ||
60 | import Control.Monad.State | ||
61 | import Data.Functor.Identity | ||
62 | import Data.Typeable | ||
63 | import Foreign | ||
64 | import GHC.TypeLits | ||
65 | |||
66 | import Data.Dependent.Map as DMap | ||
67 | import Data.Dependent.Sum | ||
68 | import Data.GADT.Compare | ||
69 | |||
70 | import Graphics.GL.Core33 | ||
71 | import 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. | ||
86 | class 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. | ||
91 | contexts :: State (DMap TypeTag (UniformContext a)) () -> DMap TypeTag (UniformContext a) | ||
92 | contexts = flip execState DMap.empty | ||
93 | |||
94 | -- | Inserts an instance into the 'uniformContexts' DMap. See 'floatMatrices' | ||
95 | -- for an example. | ||
96 | supports :: GLData a c => TypeTag c -> State (DMap TypeTag (UniformContext a)) () | ||
97 | supports 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'. | ||
114 | floatMatrices :: (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)) () | ||
124 | floatMatrices = 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. | ||
138 | data UniformContext a c = GLData a c => UniformContext | ||
139 | |||
140 | -- | Type-check (at runtime) a specific GLData instance. | ||
141 | knownContext :: (GLData a have, Typeable have, Typeable want) => TypeTag have -> TypeTag want -> Maybe (UniformContext a want) | ||
142 | knownContext known ty = do | ||
143 | Refl <- withTypes known ty <$> eqT | ||
144 | return UniformContext | ||
145 | |||
146 | -- | Lookup a GLData instance, given a Uniformable value. | ||
147 | resolveContext :: Uniformable a => a -> TypeTag want -> Maybe (UniformContext a want) | ||
148 | resolveContext 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. | ||
164 | data 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 | |||
194 | instance 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 | |||
200 | instance 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. | ||
211 | isBoolTag :: TypeTag t -> Bool | ||
212 | isBoolTag TypeBool = True | ||
213 | isBoolTag TypeV2B = True | ||
214 | isBoolTag TypeV3B = True | ||
215 | isBoolTag TypeV4B = True | ||
216 | isBoolTag _ = False | ||
217 | |||
218 | |||
219 | -- | Obtain a type-level description of a uniform type context. | ||
220 | -- | ||
221 | -- See 'unwitnessType' for the inverse operation. | ||
222 | witnessType :: InputType -> Maybe (Some TypeTag) | ||
223 | witnessType Bool = Just $ This TypeBool | ||
224 | witnessType V2B = Just $ This TypeV2B | ||
225 | witnessType V3B = Just $ This TypeV3B | ||
226 | witnessType V4B = Just $ This TypeV4B | ||
227 | witnessType Word = Just $ This TypeWord | ||
228 | witnessType V2U = Just $ This TypeV2U | ||
229 | witnessType V3U = Just $ This TypeV3U | ||
230 | witnessType V4U = Just $ This TypeV4U | ||
231 | witnessType Int = Just $ This TypeInt | ||
232 | witnessType V2I = Just $ This TypeV2I | ||
233 | witnessType V3I = Just $ This TypeV3I | ||
234 | witnessType V4I = Just $ This TypeV4I | ||
235 | witnessType Float = Just $ This TypeFloat | ||
236 | witnessType V2F = Just $ This TypeV2F | ||
237 | witnessType V3F = Just $ This TypeV3F | ||
238 | witnessType V4F = Just $ This TypeV4F | ||
239 | witnessType M22F = Just $ This TypeM22F | ||
240 | witnessType M23F = Just $ This TypeM23F | ||
241 | witnessType M24F = Just $ This TypeM24F | ||
242 | witnessType M32F = Just $ This TypeM32F | ||
243 | witnessType M33F = Just $ This TypeM33F | ||
244 | witnessType M34F = Just $ This TypeM34F | ||
245 | witnessType M42F = Just $ This TypeM42F | ||
246 | witnessType M43F = Just $ This TypeM43F | ||
247 | witnessType M44F = Just $ This TypeM44F | ||
248 | witnessType _ = Nothing | ||
249 | |||
250 | -- | Discard type-level input information. Inverse of 'witnessType'. | ||
251 | unwitnessType :: TypeTag c -> InputType | ||
252 | unwitnessType TypeBool = Bool | ||
253 | unwitnessType TypeV2B = V2B | ||
254 | unwitnessType TypeV3B = V3B | ||
255 | unwitnessType TypeV4B = V4B | ||
256 | unwitnessType TypeWord = Word | ||
257 | unwitnessType TypeV2U = V2U | ||
258 | unwitnessType TypeV3U = V3U | ||
259 | unwitnessType TypeV4U = V4U | ||
260 | unwitnessType TypeInt = Int | ||
261 | unwitnessType TypeV2I = V2I | ||
262 | unwitnessType TypeV3I = V3I | ||
263 | unwitnessType TypeV4I = V4I | ||
264 | unwitnessType TypeFloat = Float | ||
265 | unwitnessType TypeV2F = V2F | ||
266 | unwitnessType TypeV3F = V3F | ||
267 | unwitnessType TypeV4F = V4F | ||
268 | unwitnessType TypeM22F = M22F | ||
269 | unwitnessType TypeM23F = M23F | ||
270 | unwitnessType TypeM24F = M24F | ||
271 | unwitnessType TypeM32F = M32F | ||
272 | unwitnessType TypeM33F = M33F | ||
273 | unwitnessType TypeM34F = M34F | ||
274 | unwitnessType TypeM42F = M42F | ||
275 | unwitnessType TypeM43F = M43F | ||
276 | unwitnessType 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. | ||
293 | data 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. | ||
318 | data 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. | ||
323 | glUniform :: TypeTag a -> a | ||
324 | glUniform TypeBool = GLVector glUniform1uiv | ||
325 | glUniform TypeWord = GLVector glUniform1uiv | ||
326 | glUniform TypeInt = GLVector glUniform1iv | ||
327 | glUniform TypeFloat = GLVector glUniform1fv | ||
328 | glUniform TypeV2B = GLVector glUniform2uiv | ||
329 | glUniform TypeV2U = GLVector glUniform2uiv | ||
330 | glUniform TypeV2I = GLVector glUniform2iv | ||
331 | glUniform TypeV2F = GLVector glUniform2fv | ||
332 | glUniform TypeV3B = GLVector glUniform3uiv | ||
333 | glUniform TypeV3U = GLVector glUniform3uiv | ||
334 | glUniform TypeV3I = GLVector glUniform3iv | ||
335 | glUniform TypeV3F = GLVector glUniform3fv | ||
336 | glUniform TypeV4B = GLVector glUniform4uiv | ||
337 | glUniform TypeV4U = GLVector glUniform4uiv | ||
338 | glUniform TypeV4I = GLVector glUniform4iv | ||
339 | glUniform TypeV4F = GLVector glUniform4fv | ||
340 | glUniform TypeM22F = GLMatrix glUniformMatrix2fv | ||
341 | glUniform TypeM23F = GLMatrix glUniformMatrix2x3fv | ||
342 | glUniform TypeM24F = GLMatrix glUniformMatrix2x4fv | ||
343 | glUniform TypeM32F = GLMatrix glUniformMatrix3x2fv | ||
344 | glUniform TypeM33F = GLMatrix glUniformMatrix3fv | ||
345 | glUniform TypeM34F = GLMatrix glUniformMatrix3x4fv | ||
346 | glUniform TypeM42F = GLMatrix glUniformMatrix4x2fv | ||
347 | glUniform TypeM43F = GLMatrix glUniformMatrix4x3fv | ||
348 | glUniform 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. | ||
357 | class (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. | ||
369 | marshalUniformStorable :: Storable a => a -> MarshalGL (GLVector n typ) | ||
370 | marshalUniformStorable 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. | ||
375 | marshalColumnMajor :: Storable a => a -> MarshalGL (GLMatrix r c typ) | ||
376 | marshalColumnMajor 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'. | ||
384 | data 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 | |||
388 | instance 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 | |||
402 | instance 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. | ||
427 | data GLPointerType typ where | ||
428 | GLPrimUInt :: GLPointerType Word32 | ||
429 | GLPrimInt :: GLPointerType Int32 | ||
430 | GLPrimFloat :: GLPointerType Float | ||
431 | |||
432 | deriving instance Show (GLPointerType typ) | ||
433 | |||
434 | instance GEq GLPointerType where | ||
435 | geq GLPrimUInt GLPrimUInt = Just Refl | ||
436 | geq GLPrimInt GLPrimInt = Just Refl | ||
437 | geq GLPrimFloat GLPrimFloat = Just Refl | ||
438 | |||
439 | instance 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. | ||
449 | data VectorLength (n :: Nat) = VectorLength | ||
450 | |||
451 | -- | Extract the number of dimensions in a vector from a 'GLABI'. | ||
452 | vectorLength :: GLABI (GLVector n typ) -> VectorLength n | ||
453 | vectorLength IsGLVector{} = VectorLength | ||
454 | |||
455 | -- | Convenience proxy for the number of rows in a matrix. | ||
456 | data RowCount (n :: Nat) = RowCount | ||
457 | |||
458 | -- | Convenience proxy for the number of columns in a matrix. | ||
459 | data ColumnCount (n :: Nat) = ColumnCount | ||
460 | |||
461 | -- | Extract row and column counts from a 'GLABI'. | ||
462 | matrixDimensions :: GLABI (GLMatrix r c typ) -> (RowCount r, ColumnCount c) | ||
463 | matrixDimensions IsGLMatrix{} = (RowCount,ColumnCount) | ||
464 | |||
465 | -- | Convenience accessor for the pointer type proxy of a 'GLABI'. | ||
466 | ptrType :: GLABI (f t) -> GLPointerType t | ||
467 | ptrType (IsGLVector p) = p | ||
468 | ptrType (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.) | ||
476 | data 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. | ||
488 | glABI :: TypeTag a -> GLABI a | ||
489 | glABI TypeBool = IsGLVector GLPrimUInt | ||
490 | glABI TypeWord = IsGLVector GLPrimUInt | ||
491 | glABI TypeInt = IsGLVector GLPrimInt | ||
492 | glABI TypeFloat = IsGLVector GLPrimFloat | ||
493 | glABI TypeV2B = IsGLVector GLPrimUInt | ||
494 | glABI TypeV2U = IsGLVector GLPrimUInt | ||
495 | glABI TypeV2I = IsGLVector GLPrimInt | ||
496 | glABI TypeV2F = IsGLVector GLPrimFloat | ||
497 | glABI TypeV3B = IsGLVector GLPrimUInt | ||
498 | glABI TypeV3U = IsGLVector GLPrimUInt | ||
499 | glABI TypeV3I = IsGLVector GLPrimInt | ||
500 | glABI TypeV3F = IsGLVector GLPrimFloat | ||
501 | glABI TypeV4B = IsGLVector GLPrimUInt | ||
502 | glABI TypeV4U = IsGLVector GLPrimUInt | ||
503 | glABI TypeV4I = IsGLVector GLPrimInt | ||
504 | glABI TypeV4F = IsGLVector GLPrimFloat | ||
505 | glABI TypeM22F = IsGLMatrix GLPrimFloat | ||
506 | glABI TypeM23F = IsGLMatrix GLPrimFloat | ||
507 | glABI TypeM24F = IsGLMatrix GLPrimFloat | ||
508 | glABI TypeM32F = IsGLMatrix GLPrimFloat | ||
509 | glABI TypeM33F = IsGLMatrix GLPrimFloat | ||
510 | glABI TypeM34F = IsGLMatrix GLPrimFloat | ||
511 | glABI TypeM42F = IsGLMatrix GLPrimFloat | ||
512 | glABI TypeM43F = IsGLMatrix GLPrimFloat | ||
513 | glABI 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. | ||
525 | withTypes :: p (a::k) -> q (b::k) -> f a b -> f a b | ||
526 | withTypes _ _ x = x | ||
527 | |||