----------------------------------------------------------------------------- -- -- Module : Graphics.GPipe.Collada -- Copyright : Tobias Bexelius -- License : BSD3 -- -- Maintainer : Tobias Bexelius -- Stability : Experimental -- Portability : Portable -- -- | -- This module contains the data types of the Collada scene graph. -- -- Orphan TypeableX instances are also provided for 'Vertex' and "Data.Vec" vectors (:.) . ----------------------------------------------------------------------------- module Graphics.GPipe.Collada ( Scene, Node(..), nodeMat, nodeAABB, Transform(..), transformMat, transformsMat, Camera(..), cameraMat, ViewSize(..), Z(..), Light(..), Attenuation(..), Geometry(..), Mesh(..), ID, SID, Semantic, AABB(..) ) where import Data.Tree import Data.Map (Map) import Data.Maybe import Data.Monoid import Graphics.GPipe.Stream.Primitive import Graphics.GPipe.Format import qualified Data.Vec as Vec import Data.Vec (Vec2, Vec3, Mat44, Mat33, (:.)(..), ) import Data.Vec.LinAlg import Data.Vec.AABB import Data.Vec.LinAlg.Transform3D import Data.Typeable import Data.Dynamic type Scene = Tree (SID, Node) data Node = Node { nodeId :: Maybe ID, nodeLayers :: [String], nodeTransformations :: [(SID, Transform)], nodeCameras :: [(SID, Camera)], nodeLights :: [(SID, Light)], nodeGeometries :: [(SID, Geometry)] } deriving (Show) data Transform = LookAt { lookAtEye:: Vec3 Float, lookAtInterest :: Vec3 Float, lookAtUp :: Vec3 Float } | Matrix (Mat44 Float) | Rotate (Vec3 Float) Float | Scale (Vec3 Float) | Skew { skewAngle :: Float, skewRotation :: Vec3 Float, skewTranslation :: Vec3 Float } | Translate (Vec3 Float) deriving (Show, Eq) data Camera = Perspective { perspectiveID :: ID, perspectiveFov :: ViewSize, perspectiveZ :: Z } | Orthographic { orthographicID :: ID, orthographicViewSize :: ViewSize, orthographicZ :: Z } deriving (Show, Eq) data ViewSize = ViewSizeX Float | ViewSizeY Float | ViewSizeXY (Vec2 Float) deriving (Show, Eq) data Z = Z { zNear :: Float, zFar :: Float } deriving (Show, Eq) data Light = Ambient { ambientID :: ID, ambientColor :: Color RGBFormat Float } | Directional { directionalID :: ID, directionalColor :: Color RGBFormat Float } | Point { pointID :: ID, pointColor :: Color RGBFormat Float, pointAttenuation :: Attenuation } | Spot { spotID :: ID, spotColor :: Color RGBFormat Float, spotAttenuation :: Attenuation, spotFallOffAngle :: Float, spotFallOffExponent :: Float } deriving (Show, Eq) data Attenuation = Attenuation { attenuationConstant :: Float, attenuationLinear :: Float, attenuationQuadratic :: Float } deriving (Show, Eq) data Geometry = Mesh { meshID :: ID, meshPrimitives :: [Mesh] } deriving (Show) data Mesh = TriangleMesh { meshMaterial :: String, meshDescription :: Map Semantic TypeRep, meshPrimitiveStream :: PrimitiveStream Triangle (Map Semantic Dynamic), meshAABB :: AABB } instance Show Mesh where show (TriangleMesh a b _ d) = "TriangleMesh {meshMaterial = " ++ show a ++ ", meshDescription = " ++ show b ++ ", meshPrimitiveStream = PrimitiveStream Triangle (Map String Dynamic), meshAABB = " ++ show d ++"}" type ID = String type SID = Maybe String type Semantic = String deriving instance Typeable1 Vertex deriving instance Typeable2 (:.) --------------------------------------------------- toRadians :: Floating a => a -> a toRadians d = d * pi / 180 -- | Gets the projection matrix of a 'Camera' element. cameraMat :: Float -> Camera -> Mat44 Float cameraMat asp (Perspective _ (ViewSizeX x) (Z near far)) = perspective near far (toRadians x / asp) asp cameraMat asp (Perspective _ (ViewSizeY y) (Z near far)) = perspective near far (toRadians y) asp cameraMat _ (Perspective _ (ViewSizeXY (x:.y:.())) (Z near far)) = perspective near far (toRadians y) (x/y) cameraMat asp (Orthographic _ (ViewSizeX x) (Z near far)) = orthogonal near far (x :. (x/asp) :. ()) cameraMat asp (Orthographic _ (ViewSizeY y) (Z near far)) = orthogonal near far ((y*asp) :. y :. ()) cameraMat _ (Orthographic _ (ViewSizeXY s) (Z near far)) = orthogonal near far s -- | Gets the transformation matrix of a 'Transform' element. transformMat :: Transform -> Mat44 Float transformMat (LookAt e i u) = rotationLookAt u e i transformMat (Matrix m) = m transformMat (Rotate v a) = rotationVec v (toRadians a) transformMat (Scale v) = scaling v transformMat (Skew a r t) = skew (toRadians a) r t transformMat (Translate v) = translation v -- | Gets the total transformation matrix of a list of 'Transform' element. transformsMat :: [Transform] -> Mat44 Float transformsMat = foldl multmm identity . map transformMat ---------------------------------- -- adopted from http://www.koders.com/cpp/fidA08C276050F880D11C2E49280DD9997478DC5BA1.aspx skew :: Float -> Vec3 Float -> Vec3 Float -> Mat44 Float skew angle a b = Vec.map homVec m `Vec.snoc` (homPoint 0) where n2 = normalize b a1 = Vec.map (* (a `dot` n2)) n2 a2 = a-a1 n1 = normalize a2 an1 = a `dot` n1 an2 = a `dot` n2 rx = an1 * cos angle - an2 * sin angle ry = an1 * sin angle + an2 * cos angle alpha = if abs an1 < 0.000001 then 0 else ry/rx-an2/an1 m = outerProd n1 (Vec.map (* alpha) n2) + identity outerProd :: Vec3 Float -> Vec3 Float -> Mat33 Float outerProd a b = Vec.map (* b) $ Vec.map (Vec.vec) a -- | The complete transform matrix of all 'Transform' elements in a node. nodeMat :: Node -> Mat44 Float nodeMat = transformsMat . map snd . nodeTransformations -- | The smallest 'AABB' that contains all 'Geometry' elements in a node. Note: This is not transformed using the nodes 'Transform' elements. nodeAABB :: Node -> AABB nodeAABB = mconcat . map (mconcat . map meshAABB . meshPrimitives . snd) . nodeGeometries