lambdacube-engine-0.1.1: Graphics/LambdaCube/HardwareVertexBuffer.hs
module Graphics.LambdaCube.HardwareVertexBuffer where
import Data.Word
import Data.IntMap
import Foreign.Marshal.Alloc
import Foreign.Marshal.Utils
import Foreign.Storable
import Foreign.C.Types
import Foreign.Ptr
import Data.IORef
import Control.Monad
import Graphics.LambdaCube.HardwareBuffer
class (HardwareBuffer a) => HardwareVertexBuffer a where
getVertexSize :: a -> Int -- ^ Gets the size in bytes of a single vertex in this buffer
getNumVertices :: a -> Int -- ^ Get the number of vertices in this buffer
-- | Vertex element semantics, used to identify the meaning of vertex buffer contents
data VertexElementSemantic
= VES_POSITION -- ^ Position, 3 reals per vertex
| VES_BLEND_WEIGHTS -- ^ Blending weights
| VES_BLEND_INDICES -- ^ Blending indices
| VES_NORMAL -- ^ Normal, 3 reals per vertex
| VES_DIFFUSE -- ^ Diffuse colours
| VES_SPECULAR -- ^ Specular colours
| VES_TEXTURE_COORDINATES -- ^ Texture coordinates
| VES_BINORMAL -- ^ Binormal (Y axis if normal is Z)
| VES_TANGENT -- ^ Tangent (X axis if normal is Z)
deriving (Enum,Eq,Ord,Show)
-- | Vertex element type, used to identify the base types of the vertex contents
data VertexElementType
= VET_FLOAT1
| VET_FLOAT2
| VET_FLOAT3
| VET_FLOAT4
-- -- | alias to more specific colour type - use the current rendersystem's colour packing
-- | VET_COLOUR -- Deprecated by Ogre
| VET_SHORT1
| VET_SHORT2
| VET_SHORT3
| VET_SHORT4
| VET_UBYTE4
-- | D3D style compact colour
| VET_COLOUR_ARGB
-- | GL style compact colour
| VET_COLOUR_ABGR
deriving (Eq,Ord,Show)
{-| This class declares the usage of a single vertex buffer as a component
of a complete VertexDeclaration.
@remarks
Several vertex buffers can be used to supply the input geometry for a
rendering operation, and in each case a vertex buffer can be used in
different ways for different operations; the buffer itself does not
define the semantics (position, normal etc), the VertexElement
class does.
-}
data VertexElement
= VertexElement
{ veSource :: Int -- ^ The source vertex buffer, as bound to an index using VertexBufferBinding
, veOffset :: Int -- ^ The offset in the buffer that this element starts at
, veType :: VertexElementType -- ^ The type of element
, veSemantic :: VertexElementSemantic -- ^ The meaning of the element
, veIndex :: Int -- ^ Index of the item, only applicable for some elements like texture coords
}
deriving (Eq,Ord,Show)
-- | Utility method for helping to calculate offsets
getTypeSize :: VertexElementType -> Int
getTypeSize etype = case etype of
{ VET_COLOUR_ABGR -> sizeOf (undefined::Word32) -- sizeof(RGBA);
; VET_COLOUR_ARGB -> sizeOf (undefined::Word32) -- sizeof(RGBA);
; VET_FLOAT1 -> sizeOf (undefined::CFloat) -- sizeof(float);
; VET_FLOAT2 -> 2 * sizeOf (undefined::CFloat) -- sizeof(float)*2;
; VET_FLOAT3 -> 3 * sizeOf (undefined::CFloat) -- sizeof(float)*3;
; VET_FLOAT4 -> 4 * sizeOf (undefined::CFloat) -- sizeof(float)*4;
; VET_SHORT1 -> sizeOf (undefined::CShort) -- sizeof(short);
; VET_SHORT2 -> 2 * sizeOf (undefined::CShort) -- sizeof(short)*2;
; VET_SHORT3 -> 3 * sizeOf (undefined::CShort) -- sizeof(short)*3;
; VET_SHORT4 -> 4 * sizeOf (undefined::CShort) -- sizeof(short)*4;
; VET_UBYTE4 -> 4 * sizeOf (undefined::CUChar) -- sizeof(unsigned char)*4;
}
-- | Utility method which returns the count of values in a given type
getTypeCount :: VertexElementType -> Int
getTypeCount etype = case etype of
{ VET_COLOUR_ABGR -> 1
; VET_COLOUR_ARGB -> 1
; VET_FLOAT1 -> 1
; VET_FLOAT2 -> 2
; VET_FLOAT3 -> 3
; VET_FLOAT4 -> 4
; VET_SHORT1 -> 1
; VET_SHORT2 -> 2
; VET_SHORT3 -> 3
; VET_SHORT4 -> 4
; VET_UBYTE4 -> 4
}
{-| Simple converter function which will turn a single-value type into a
multi-value type based on a parameter.
-}
multiplyTypeCount :: VertexElementType -> Int -> VertexElementType
multiplyTypeCount baseType count = case baseType of
{ VET_FLOAT1 -> case count of
{ 1 -> VET_FLOAT1
; 2 -> VET_FLOAT2
; 3 -> VET_FLOAT3
; 4 -> VET_FLOAT4
; _ -> error "Invalid type"
}
; VET_SHORT1 -> case count of
{ 1 -> VET_SHORT1
; 2 -> VET_SHORT2
; 3 -> VET_SHORT3
; 4 -> VET_SHORT4
; _ -> error "Invalid type"
}
; _ -> error "Invalid type"
}
{-| Simple converter function which will a type into it's single-value
equivalent - makes switches on type easier.
-}
getBaseType :: VertexElementType -> VertexElementType
getBaseType multiType = case multiType of
{ VET_FLOAT1 -> VET_FLOAT1
; VET_FLOAT2 -> VET_FLOAT2
; VET_FLOAT3 -> VET_FLOAT3
; VET_FLOAT4 -> VET_FLOAT4
; VET_COLOUR_ABGR -> VET_COLOUR_ABGR
; VET_COLOUR_ARGB -> VET_COLOUR_ARGB
; VET_SHORT1 -> VET_SHORT1
; VET_SHORT2 -> VET_SHORT2
; VET_SHORT3 -> VET_SHORT3
; VET_SHORT4 -> VET_SHORT4
; VET_UBYTE4 -> VET_UBYTE4
}
{-| Utility method for converting colour from
one packed 32-bit colour type to another.
@param srcType The source type
@param dstType The destination type
@param ptr Read / write value to change
-}
--static void convertColourValue(VertexElementType srcType,
-- VertexElementType dstType, uint32* ptr);
{-| Utility method for converting colour to
a packed 32-bit colour type.
@param src source colour
@param dst The destination type
-}
--static uint32 convertColourValue(const ColourValue& src,
-- VertexElementType dst);
{-| Utility method to get the most appropriate packed colour vertex element format. -}
--static VertexElementType getBestColourVertexElementType(void);
data VertexDeclaration
= VertexDeclaration
{ vdElementList :: [VertexElement] -- ^ Defines the list of vertex elements that makes up this declaration
}
deriving (Eq,Show)
{-| Records the state of all the vertex buffer bindings required to provide a vertex declaration
with the input data it needs for the vertex elements.
@remarks
Why do we have this binding list rather than just have VertexElement referring to the
vertex buffers direct? Well, in the underlying APIs, binding the vertex buffers to an
index (or 'stream') is the way that vertex data is linked, so this structure better
reflects the realities of that. In addition, by separating the vertex declaration from
the list of vertex buffer bindings, it becomes possible to reuse bindings between declarations
and vice versa, giving opportunities to reduce the state changes required to perform rendering.
@par
Like the other classes in this functional area, these binding maps should be created and
destroyed using the HardwareBufferManager.
-}
data HardwareVertexBuffer vb => VertexBufferBinding vb
= VertexBufferBinding
{ vbbBindingMap :: IntMap vb
}
deriving Eq