dx9d3d-0.1: DirectX9/D3D/Utility/FVF.hs
module DirectX9.D3D.Utility.FVF
where
import Foreign.Marshal.Array ( pokeArray )
import Foreign.Ptr ( Ptr, plusPtr )
import Foreign.Storable ( pokeByteOff )
import DirectX9.Types
import DirectX9.D3D.Raw
import DirectX9.D3D.Format
import DirectX9.D3D.Constant
import DirectX9.D3D.Device
import DirectX9.D3D.Resource
class FVF a where
sizeOfOne :: a -> Int
sizeOfAll :: a -> Int
fvfFlags :: a -> D3DFVF
writeFVF :: a -> Ptr b -> IO (Ptr b)
-- todo: optimise indexes that can fit into 16-bits
fvfCreateIndexBuffer :: (Num a, Storable a) => Device -> DWORD -> D3DPOOL -> [a] -> IO IndexBuffer
fvfCreateIndexBuffer dev usage pool arr = do
ib <- devCreateIndexBuffer dev bytes usage format pool
withLockedIndexBuffer ib 0 bytes 0 $ flip pokeArray arr
return ib
where
(format,bytes) = case (sizeOf (arr!!0)) of
4 -> (d3DFMT_INDEX32, 4*(length arr))
2 -> (d3DFMT_INDEX16, 2*(length arr))
_ -> (0,0)
fvfToVertexElems :: D3DFVF -> [D3DVERTEXELEMENT9]
fvfToVertexElems fvf = reverse $ foldl offset [] $ concat $ snd $ foldl fun (fvf,[]) fields
where
fun :: (D3DFVF, [[a]]) -> (D3DFVF,[a]) -> (D3DFVF,[[a]])
fun (fvf, old) (f, d)
| f<=fvf = ((fvf-f),d:old)
| otherwise = (fvf,old)
nextOffset [] = 0
nextOffset (x:_) =
d3DVERTEXELEMENT9_Offset x
+ case lookup (d3DVERTEXELEMENT9_Type x) sizes of
Just x -> x
Nothing -> 999
sizes =
[(d3DDECLTYPE_FLOAT2 ,8)
,(d3DDECLTYPE_FLOAT3 ,12)
,(d3DDECLTYPE_FLOAT4 ,16)
,(d3DDECLTYPE_D3DCOLOR ,4)
]
offset old (t,u) = (D3DVERTEXELEMENT9 0 (nextOffset old) t d3DDECLMETHOD_DEFAULT u 0 ):old
fields =
[(d3DFVF_TEX8, replicate 8 (d3DDECLTYPE_FLOAT2,d3DDECLUSAGE_TEXCOORD))
,(d3DFVF_TEX7, replicate 7 (d3DDECLTYPE_FLOAT2,d3DDECLUSAGE_TEXCOORD))
,(d3DFVF_TEX6, replicate 6 (d3DDECLTYPE_FLOAT2,d3DDECLUSAGE_TEXCOORD))
,(d3DFVF_TEX5, replicate 5 (d3DDECLTYPE_FLOAT2,d3DDECLUSAGE_TEXCOORD))
,(d3DFVF_TEX4, replicate 4 (d3DDECLTYPE_FLOAT2,d3DDECLUSAGE_TEXCOORD))
,(d3DFVF_TEX3, replicate 3 (d3DDECLTYPE_FLOAT2,d3DDECLUSAGE_TEXCOORD))
,(d3DFVF_TEX2, replicate 2 (d3DDECLTYPE_FLOAT2,d3DDECLUSAGE_TEXCOORD))
,(d3DFVF_TEX1, replicate 1 (d3DDECLTYPE_FLOAT2,d3DDECLUSAGE_TEXCOORD))
,(d3DFVF_SPECULAR, [(d3DDECLTYPE_D3DCOLOR,d3DDECLUSAGE_COLOR)])
,(d3DFVF_DIFFUSE, [(d3DDECLTYPE_D3DCOLOR,d3DDECLUSAGE_COLOR)])
,(d3DFVF_NORMAL, [(d3DDECLTYPE_FLOAT3,d3DDECLUSAGE_NORMAL)])
,(d3DFVF_XYZRHW, [(d3DDECLTYPE_FLOAT4,d3DDECLUSAGE_POSITION)])
,(d3DFVF_XYZ, [(d3DDECLTYPE_FLOAT3,d3DDECLUSAGE_POSITION)])
]
fvfCreateVertexBuffer :: (FVF a) => Device -> DWORD -> D3DPOOL -> a -> IO VertexBuffer
fvfCreateVertexBuffer dev usage pool o = do
vb <- devCreateVertexBuffer dev bytes usage (fvfFlags o) pool
withLockedVertexBuffer vb 0 bytes 0 (writeFVF o)
return vb
where bytes = sizeOfAll o
fvfCreateVertexDeclaration :: (FVF a) => Device -> Int -> a -> IO VertexDeclaration
fvfCreateVertexDeclaration dev stream fvf = devCreateVertexDeclaration dev decl
where
setStream x = x { d3DVERTEXELEMENT9_Stream = fromIntegral stream}
decl = map setStream $ fvfToVertexElems $ fvfFlags fvf
type FVFVector4 = (Float,Float,Float,Float)
type FVFVector3 = (Float,Float,Float)
type FVFVector2 = (Float,Float)
writeFVFV4 :: FVFVector4 -> Ptr a -> IO (Ptr a)
writeFVFV4 (v1,v2,v3,v4) b = do
pokeByteOff b 0 v1
pokeByteOff b 4 v2
pokeByteOff b 8 v3
pokeByteOff b 12 v4
return $ plusPtr b 16
writeFVFV3 :: FVFVector3 -> Ptr a -> IO (Ptr a)
writeFVFV3 (v1,v2,v3) b = do
pokeByteOff b 0 v1
pokeByteOff b 4 v2
pokeByteOff b 8 v3
return $ plusPtr b 12
writeFVFV2 :: FVFVector2 -> Ptr a -> IO (Ptr a)
writeFVFV2 (v1,v2) b = do
pokeByteOff b 0 v1
pokeByteOff b 4 v2
return $ plusPtr b 8
writeFVFD :: D3DCOLOR -> Ptr a -> IO (Ptr a)
writeFVFD v b = do
pokeByteOff b 0 v
return $ plusPtr b 4
writeFVF' :: (a -> Ptr b -> IO (Ptr b)) -> [a] -> Ptr b -> IO (Ptr b)
writeFVF' f a s = foldl (\x y -> x >>= f y) (return s) a
newtype PosF = PosF [FVFVector3]
newtype PosNormF = PosNormF [(FVFVector3,FVFVector3)]
newtype PosDiffF = PosDiffF [(FVFVector3, D3DCOLOR)]
newtype PosNormDiffF = PosNormDiffF [(FVFVector3, FVFVector3, D3DCOLOR)]
newtype PosTexF = PosTexF [(FVFVector3, FVFVector2)]
newtype PosNormTexF = PosNormTexF [(FVFVector3, FVFVector3, FVFVector2)]
instance FVF PosF where
sizeOfOne _ = 4*3
sizeOfAll (PosF a) = (4*3) * length a
fvfFlags _ = d3DFVF_XYZ
writeFVF (PosF v) = writeFVF' w v
where w v b = writeFVFV3 v b
instance FVF PosNormF where
sizeOfOne _ = 4*3+4*3
sizeOfAll (PosNormF v) = (4*3+4*3) * length v
fvfFlags _ = d3DFVF_XYZ + d3DFVF_NORMAL
writeFVF (PosNormF v) = writeFVF' w v
where w (v,n) b = return b >>= writeFVFV3 v >>= writeFVFV3 n
instance FVF PosDiffF where
sizeOfOne _ = 4*3+4
sizeOfAll (PosDiffF v) = (4*3+3) * length v
fvfFlags _ = d3DFVF_XYZ + d3DFVF_DIFFUSE
writeFVF (PosDiffF v) = writeFVF' w v
where w (v,d) b = return b >>= writeFVFV3 v >>= writeFVFD d
instance FVF PosNormDiffF where
sizeOfOne _ = 4*3+4*3+4
sizeOfAll (PosNormDiffF v) = (4*3+4*3+4) * length v
fvfFlags _ = d3DFVF_XYZ+d3DFVF_NORMAL+d3DFVF_DIFFUSE
writeFVF (PosNormDiffF v) = writeFVF' w v
where w (v,n,d) b = return b >>= writeFVFV3 v >>= writeFVFV3 n >>= writeFVFD d
instance FVF PosTexF where
sizeOfOne _ = 4*3+4*2
sizeOfAll (PosTexF v) = (4*3+4*2) * length v
fvfFlags _ = d3DFVF_XYZ+d3DFVF_TEX1
writeFVF (PosTexF v) = writeFVF' w v
where w (v,t) b = return b >>= writeFVFV3 v >>= writeFVFV2 t
instance FVF PosNormTexF where
sizeOfOne _ = 4*3+4*3+4*2
sizeOfAll (PosNormTexF v) = (4*3+4*3+4*2) * length v
fvfFlags _ = d3DFVF_XYZ+d3DFVF_NORMAL+d3DFVF_TEX1
writeFVF (PosNormTexF v) = writeFVF' w v
where w (v,n,t) b = return b >>= writeFVFV3 v >>= writeFVFV3 n >>= writeFVFV2 t