gl-block-1.1: test/Spec/Types.hs
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE TypeFamilies #-}
{-| Minimal local copies of geomancy-0.3.0.1's @Vec*@/@Mat4@ 'Block' instances,
so the vec/mat cross-check needs no geomancy dependency (geomancy can't be
wired in while gl-block is the local package -- an inverted Hackage
dependency). The layouts mirror geomancy exactly, including that the default
'Vec3' writes a 4th lane (1.0) whereas 'Vec3Packed' writes only three floats.
-}
module Spec.Types
( Vec2 (..)
, Vec3 (..)
, Vec3Packed (..)
, Vec4 (..)
, Mat4 (..)
) where
import Foreign
import Foreign.Ptr.Diff (peekDiffOff, pokeDiffOff)
import Graphics.Gl.Block (Block (..))
data Vec2 = Vec2 Float Float
deriving stock (Eq, Show)
instance Storable Vec2 where
sizeOf _ = 8
alignment _ = 8
peek p = Vec2 <$> peekElemOff (castPtr p) 0 <*> peekElemOff (castPtr p) 1
poke p (Vec2 a b) = pokeElemOff (castPtr p) 0 a >> pokeElemOff (castPtr p) 1 b
instance Block Vec2 where
type PackedSize Vec2 = 8
alignment140 _ = 8
sizeOf140 _ = 8
alignment430 = alignment140
sizeOf430 = sizeOf140
isStruct _ = False
read140 = peekDiffOff
write140 = pokeDiffOff
read430 = read140
write430 = write140
readPacked = read140
writePacked = write140
-- | geomancy's default Vec3: a 16-byte host slot whose 'poke' writes a 4th lane.
data Vec3 = Vec3 Float Float Float
deriving stock (Eq, Show)
instance Storable Vec3 where
sizeOf _ = 16
alignment _ = 4
peek p =
Vec3
<$> peekElemOff (castPtr p) 0
<*> peekElemOff (castPtr p) 1
<*> peekElemOff (castPtr p) 2
poke p (Vec3 a b c) = do
let p' = castPtr p
pokeElemOff p' 0 a
pokeElemOff p' 1 b
pokeElemOff p' 2 c
pokeElemOff p' 3 (1.0 :: Float)
instance Block Vec3 where
type PackedSize Vec3 = 12
alignment140 _ = 16
sizeOf140 _ = 16
alignment430 = alignment140
sizeOf430 = sizeOf140
isStruct _ = False
read140 = peekDiffOff
write140 = pokeDiffOff
read430 = read140
write430 = write140
readPacked = read140
writePacked = write140
-- | geomancy's Vec3.Packed: a 12-byte host that writes exactly three floats.
newtype Vec3Packed = Vec3Packed Vec3
deriving stock (Eq, Show)
instance Storable Vec3Packed where
sizeOf _ = 12
alignment _ = 4
peek p =
(\a b c -> Vec3Packed (Vec3 a b c))
<$> peekElemOff (castPtr p) 0
<*> peekElemOff (castPtr p) 1
<*> peekElemOff (castPtr p) 2
poke p (Vec3Packed (Vec3 a b c)) = do
let p' = castPtr p
pokeElemOff p' 0 a
pokeElemOff p' 1 b
pokeElemOff p' 2 c
instance Block Vec3Packed where
type PackedSize Vec3Packed = 12
alignment140 _ = 16
sizeOf140 _ = 16
alignment430 = alignment140
sizeOf430 = sizeOf140
isStruct _ = False
read140 = peekDiffOff
write140 = pokeDiffOff
read430 = read140
write430 = write140
readPacked = read140
writePacked = write140
data Vec4 = Vec4 Float Float Float Float
deriving stock (Eq, Show)
instance Storable Vec4 where
sizeOf _ = 16
alignment _ = 16
peek p =
Vec4
<$> peekElemOff (castPtr p) 0
<*> peekElemOff (castPtr p) 1
<*> peekElemOff (castPtr p) 2
<*> peekElemOff (castPtr p) 3
poke p (Vec4 a b c d) = do
let p' = castPtr p
pokeElemOff p' 0 a
pokeElemOff p' 1 b
pokeElemOff p' 2 c
pokeElemOff p' 3 d
instance Block Vec4 where
type PackedSize Vec4 = 16
alignment140 _ = 16
sizeOf140 _ = 16
alignment430 = alignment140
sizeOf430 = sizeOf140
isStruct _ = False
read140 = peekDiffOff
write140 = pokeDiffOff
read430 = read140
write430 = write140
readPacked = read140
writePacked = write140
-- | mat4 as four column vec4s: 64 bytes, 16-byte aligned (column-major).
newtype Mat4 = Mat4 [Float]
deriving stock (Eq, Show)
instance Storable Mat4 where
sizeOf _ = 64
alignment _ = 16
peek p = Mat4 <$> traverse (peekElemOff (castPtr p)) [0 .. 15]
poke p (Mat4 xs) =
sequence_ [pokeElemOff (castPtr p) i x | (i, x) <- zip [0 ..] (take 16 (xs ++ repeat 0))]
instance Block Mat4 where
type PackedSize Mat4 = 64
alignment140 _ = 16
sizeOf140 _ = 64
alignment430 = alignment140
sizeOf430 = sizeOf140
isStruct _ = False
read140 = peekDiffOff
write140 = pokeDiffOff
read430 = read140
write430 = write140
readPacked = read140
writePacked = write140