assimp-0.1: Graphics/Formats/Assimp/Fun.chs
{-# LANGUAGE ForeignFunctionInterface #-}
{-# LANGUAGE TypeSynonymInstances #-}
{-# LANGUAGE BangPatterns #-}
-- |
-- Module : Graphics.Formats.Assimp.Fun
-- Copyright : (c) Joel Burget 2011
-- License BSD3
--
-- Maintainer : Joel Burget <joelburget@gmail.com>
-- Stability : experimental
-- Portability : non-portable
--
-- Defines functions for interacting with assimp
module Graphics.Formats.Assimp.Fun (
-- * Basics
importFile
, applyPostProcessing
-- * Version information
, getVersionMinor
, getVersionMajor
, getVersionRevision
, isExtensionSupported
-- * Accessing materials
, get
, getArray
-- * Currently unused
, getErrorString
, setImportPropertyInteger
, setImportPropertyFloat
) where
import C2HS
import Foreign.Storable ()
import Control.Monad (liftM)
import Unsafe.Coerce (unsafeCoerce)
import Data.Vect (Vec3(Vec3), Vec4(Vec4))
import Data.List (foldl1')
import Graphics.Formats.Assimp.Types
import Graphics.Formats.Assimp.Storable ()
#include "assimp.h"
#include "aiVersion.h"
#include "aiMaterial.h"
#include "typedefs.h"
--withT = with -- http://blog.ezyang.com/2010/06/call-and-fun-marshalling-redux/
with' :: (Storable a) => a -> (Ptr b -> IO c) -> IO c
with' x y = with x (y . castPtr)
peek' :: (Storable b) => Ptr a -> IO b
peek' = peek . castPtr
-- aiImportFileEx
-- aiImportFileFromMemory
{#fun unsafe aiApplyPostProcessing as applyPostProcessing
{with'* `Scene', cFromEnum `PostProcessSteps'} -> `Scene' peek'*#}
--{#fun aiGetPredefinedLogStream as ^
-- {cFromEnum `DefaultLogStream', `String'} -> `LogStream' id#}
-- aiAttachLogStream
-- aiEnableVerboseLogging
-- aiDetachLogStream
-- aiDetachAllLogStreams
importFile :: String -> [PostProcessSteps] -> IO (Either String Scene)
importFile str psteps = do
let psteps' = foldl1' (.|.) $ map cFromEnum psteps
sceneptr <- withCString str $ \x -> {#call unsafe aiImportFile#} x psteps'
if sceneptr == nullPtr
then liftM Left getErrorString
else do
scene <- peek' sceneptr
{#call unsafe aiReleaseImport#} sceneptr
return $ Right scene
{#fun unsafe aiGetErrorString as getErrorString
{} -> `String'#}
{#fun unsafe aiIsExtensionSupported as isExtensionSupported
{`String'} -> `Bool'#}
-- {#fun unsafe aiGetExtensionList as getExtensionList
-- {alloca- `AiString' peek'*} -> `()'#}
-- aiGetMemoryRequirements
{#fun unsafe aiSetImportPropertyInteger as setImportPropertyInteger
{`String', `Int'} -> `()'#}
{#fun unsafe aiSetImportPropertyFloat as setImportPropertyFloat
{`String', `Float'} -> `()'#}
--{# fun aiSetImportPropertyString as ^
-- {`String', `String'} -> `()'#}
{#fun unsafe aiGetLegalString as getLegalString
{} -> `String'#}
{#fun unsafe aiGetVersionMinor as getVersionMinor
{} -> `CUInt' unsafeCoerce#}
{#fun unsafe aiGetVersionMajor as getVersionMajor
{} -> `CUInt' unsafeCoerce#}
{#fun unsafe aiGetVersionRevision as getVersionRevision
{} -> `CUInt' unsafeCoerce#}
{#fun unsafe aiGetCompileFlags as getCompileFlags
{} -> `CompileFlags' convert#}
where convert = toEnum . cIntConv
class ArrayGetter a where
getArray :: Material -> MatKey -> CUInt -> IO (Either String [a])
class SingleGetter a where
get :: Material -> MatKey -> IO (Either String a)
instance ArrayGetter Float where
getArray = getMaterialFloatArray
instance ArrayGetter Int where
getArray = getMaterialIntArray
instance SingleGetter Float where
get = getMaterialFloat
instance SingleGetter Int where
get = getMaterialInt
instance SingleGetter Vec3 where
-- Also another case?
get mat key = (liftM . liftM) (\(Vec4 r g b a) -> Vec3 r g b)
(getMaterialColor mat key)
instance SingleGetter Vec4 where
get = getMaterialColor
instance SingleGetter String where
get = getMaterialString
mCUInt = fromInteger . toInteger
mRet = toEnum . fromInteger . toInteger
-------------------------------------------------------------------------------
{- |
- Retrieve a material property with a specific key from the material
-}
getMaterialProperty :: Material -- ^ The material
-> MatKey -- ^ A key
-> IO (Either String MaterialProperty)
getMaterialProperty mat key = do
let (mKey, mType, mIndex) = matKeyToTuple key
(ret, prop) <- getMaterialProperty' mat mKey mType mIndex
case ret of
ReturnSuccess -> peekM prop
ReturnFailure -> return $ Left "Failed"
ReturnOutOfMemory -> return $ Left "Out of memory."
where
peekM :: Ptr MaterialProperty -> IO (Either String MaterialProperty)
peekM p =
if p == nullPtr
then return $ Left "No property found"
else liftM Right $ peek p
{#fun unsafe aiGetMaterialProperty as getMaterialProperty'
{with'* `Material',
`String' ,
mCUInt `CUInt' ,
mCUInt `CUInt' ,
alloca- `Ptr MaterialProperty' peek'*} -> `Return' mRet#}
-------------------------------------------------------------------------------
{- |
- Retrieve an array of float values with a specific key from the material
- Example:
- > getMaterialFloatArray mat (KeyUvTransform Diffuse 0) 4
-}
getMaterialFloatArray :: Material -- ^ The material
-> MatKey -- ^ A key
-> CUInt -- ^ Max number of values to retrieve
-> IO (Either String [Float])
getMaterialFloatArray mat key max = do
let (mKey, mType, mIndex) = matKeyToTuple key
(ret, arr, max) <- getMaterialFloatArray' mat mKey mType mIndex max
case ret of
ReturnSuccess -> liftM (Right . (map unsafeCoerce))
$ peekArray (fromIntegral max) arr
ReturnFailure -> return $ Left "Failed"
ReturnOutOfMemory -> return $ Left "Out of memory."
{#fun unsafe aiGetMaterialFloatArray as getMaterialFloatArray'
{with'* `Material' ,
`String' ,
mCUInt `CUInt' ,
mCUInt `CUInt' ,
alloca- `Ptr CFloat' id,
with'* `CUInt' peek'*} -> `Return' mRet#}
-------------------------------------------------------------------------------
getMaterialFloat :: Material -> MatKey -> IO (Either String Float)
getMaterialFloat mat key = do
arr <- getMaterialFloatArray mat key 1
return $ case arr of
Left err -> Left err
Right ans -> Right $ head ans
-------------------------------------------------------------------------------
getMaterialIntArray :: Material -> MatKey -> CUInt -> IO (Either String [Int])
getMaterialIntArray mat key max = do
let (mKey, mType, mIndex) = matKeyToTuple key
(ret, arr, max) <- getMaterialIntArray' mat mKey mType mIndex max
case ret of
ReturnSuccess -> liftM (Right . (map unsafeCoerce))
$ peekArray (fromIntegral max) arr
ReturnFailure -> return $ Left "Failed"
ReturnOutOfMemory -> return $ Left "Out of memory."
{#fun unsafe aiGetMaterialIntegerArray as getMaterialIntArray'
{with'* `Material' ,
`String' ,
mCUInt `CUInt' ,
mCUInt `CUInt' ,
alloca- `Ptr CInt' id,
with'* `CUInt' peek'*} -> `Return' mRet#}
-------------------------------------------------------------------------------
getMaterialInt :: Material -> MatKey -> IO (Either String Int)
getMaterialInt mat key = do
arr <- getMaterialIntArray mat key 1
return $ case arr of
Left err -> Left err
Right ans -> Right $ head ans
-------------------------------------------------------------------------------
getMaterialColor :: Material -> MatKey -> IO (Either String Vec4)
getMaterialColor mat key = do
let (mKey, mType, mIndex) = matKeyToTuple key
(ret, vec) <- getMaterialColor' mat mKey mType mIndex
return $ case ret of
ReturnSuccess -> Right vec
ReturnFailure -> Left "Failed"
ReturnOutOfMemory -> Left "Out of memory."
-- Can't get this to work :(
-- {#fun unsafe aiGetMaterialColor as getMaterialColor'
-- {with'* `Material',
-- `String' ,
-- mCUInt `CUInt' ,
-- mCUInt `CUInt' ,
-- alloca- `Vec4' peek'*} -> `Return' mRet#}
getMaterialColor' :: Material -> String -> CUInt -> CUInt -> IO (Return, Vec4)
getMaterialColor' a1 a2 a3 a4 =
with a1 $ \a1' ->
withCString a2 $ \a2' ->
alloca $ \a5' ->
getMaterialColor''_ a1' a2' (mCUInt a3) (mCUInt a4) a5' >>= \res ->
peek a5' >>= \a5'' ->
return (mRet res, a5'')
foreign import ccall unsafe "Graphics/Formats/Assimp/Fun.chs.h aiGetMaterialColor"
getMaterialColor''_ :: Ptr Material -> Ptr CChar -> CUInt -> CUInt -> Ptr Vec4 -> IO CInt
-------------------------------------------------------------------------------
getMaterialString :: Material -> MatKey -> IO (Either String String)
getMaterialString mat key = do
let (mKey, mType, mIndex) = matKeyToTuple key
(ret, (AiString str)) <- getMaterialString' mat mKey mType mIndex
return $ case ret of
ReturnSuccess -> Right str
ReturnFailure -> Left "Failed"
ReturnOutOfMemory -> Left "Out of memory."
-- {#fun unsafe aiGetMaterialString as getMaterialString
-- {with'* `Material',
-- `String' ,
-- mCUInt `CUInt' ,
-- mCUInt `CUInt' ,
-- alloca- `AiString' peek'*} -> `Return' mRet#}
getMaterialString' :: Material -> String -> CUInt -> CUInt -> IO (Return, AiString)
getMaterialString' a1 a2 a3 a4 =
with a1 $ \a1' ->
withCString a2 $ \a2' ->
alloca $ \a5' ->
getMaterialString''_ a1' a2' (mCUInt a3) (mCUInt a4) a5' >>= \res ->
peek a5' >>= \a5'' ->
return (mRet res, a5'')
foreign import ccall unsafe "Graphics/Formats/Assimp/Fun.chs.h aiGetMaterialString"
getMaterialString''_ :: Ptr Material -> Ptr CChar -> CUInt -> CUInt -> Ptr AiString -> IO CInt
-------------------------------------------------------------------------------
{#fun unsafe aiGetMaterialTextureCount as getTextureCount
{with'* `Material',
f `TextureType'} -> `CUInt' unsafeCoerce#}
where
f :: TextureType -> CInt
f = cIntConv . fromEnum
-------------------------------------------------------------------------------
-- getTexture ::
-- {#fun unsafe aiGetMaterialTexture as getTexture'
-- {with'* `Material' ,
-- f `TextureType',
-- mCUInt `CUInt'
-- `String' ,
-- alloca- `CUInt' peek'*} -> `Return' mRet#}
-- I'm not sure whether or not I will implement these or not. I guess I'll
-- check the source to see if they're pure. They could easily be implemented in
-- pure haskell.
-- aiCreateQuaternionFromMatrix
-- aiDecomposeMatrix
-- aiTransposematrix4
-- aiTransposematrix3
-- aiTransformVecByMatrix3
-- aiTransformVecByMatrix4
-- aiMultiplyMatrix3
-- aiMultiplyMatrix4
-- aiIdentityMatrix3
-- aiIdentityMatrix4