packages feed

lambdacube-engine-0.1.1: Graphics/LambdaCube/SceneGraph.hs

module Graphics.LambdaCube.SceneGraph where

import Data.Maybe
import Data.Map as Map hiding (map)
import qualified Data.IntMap as IntMap
import Data.List as List
import Control.Monad
import System.FilePath

import Data.Graph.Inductive

import Graphics.LambdaCube.Types
import Graphics.LambdaCube.Common
import Graphics.LambdaCube.Math
import Graphics.LambdaCube.Light
import Graphics.LambdaCube.Material
import Graphics.LambdaCube.Entity
import Graphics.LambdaCube.Resource
import Graphics.LambdaCube.RenderQueue
import Graphics.LambdaCube.World
import Graphics.LambdaCube.Texture
import Graphics.LambdaCube.RenderSystem
    
--type MkSceneObjectAction = World -> IO (World, SceneObject)
--type MkNodeAction = ResourceLibrary -> IO (ResourceLibrary,(String,String),SceneNode)

--simpleCamera :: String -> MkSceneObjectAction
simpleCamera name w = return (w,cam)
  where
    cam = SO_Camera Camera
        { cmName        = name
        , cmFov         = 45
        , cmNear        = 0.1
        , cmFar         = 5000
        , cmAspectRatio = Nothing
        , cmPolygonMode = PM_SOLID
        }

--wireCamera :: String -> MkSceneObjectAction
wireCamera name w = return (w,cam)
  where
    cam = SO_Camera Camera
        { cmName        = name
        , cmFov         = 45
        , cmNear        = 0.1
        , cmFar         = 5000
        , cmAspectRatio = Nothing
        , cmPolygonMode = PM_WIREFRAME
        }

--light :: MkSceneObjectAction
light w = return (w,SO_Light $ Light {})

--camera :: Camera -> MkSceneObjectAction
camera cam w = return (w,SO_Camera cam)

--mesh :: String -> MkSceneObjectAction
mesh name w = do
    (w',e) <- createEntity w name name
    return (w', SO_Entity e)

--meshMat :: String -> [String] -> MkSceneObjectAction
meshMat name mats w0 = do
    (w1,e0) <- createEntity w0 name name
    (w2,e1) <- setEntityMaterial w1 mats e0
    return (w2, SO_Entity e1)

--mkNode :: String -> String -> Matrix4 -> [MkSceneObjectAction] -> MkNodeAction
mkNode parent name t objActs w = do
    (w',o) <- foldM mkObjs (w,[]) objActs
    return (w',(parent,name),SceneNode name o t)
  where
    mkObjs (w,l) a = do
        (w',so) <- a w
        return (w',so:l)
{-
addSkyBox :: String -> World -> IO World
addSkyBox s w@World { wrResource = rl, wrScene = scene } = do
    (rl',mat) <- compileMaterial rl s
    return w { wrResource = rl', wrScene = scene{scSky = Just $ SkyBox mat} }
-}

{-
data Scene = Scene
    { scGraph :: Gr String ()
    -- use: bytestring-trie (efficient ByteString map)
    , scMap   :: Map String SceneNode
    , scSky   :: Maybe Sky
    -- Fog settings
    }
-}
--addScene :: [MkNodeAction] -> World -> IO World
addScene nodes w@World { wrResource = rl, wrScene = scene } = do
    -- done: create scene nodes
    let mkNodes (w,pl,nl) a = do
            (w',p,sn) <- a w
            return (w',p:pl,sn:nl)
    (w',p,nodel) <- foldM mkNodes (w,[],[]) nodes
    -- done: register node ids and names to bimap
    -- done: create graph nodes 
    -- done: create graph edges
    let namel = map snName nodel
        nodeids = newNodes (length nodes) $ scGraph scene
        m' = (scMap scene) `Map.union` (Map.fromList $ zip namel $ zip nodeids nodel)
        g = insEdges (map fe p) $ insNodes (zip nodeids namel) $ scGraph scene
        fe (p,c) = (fst $ m' ! p, fst $ m' ! c,())
        scene' = scene 
               { scGraph   = g
               , scMap     = m'
               --, scSky     :: Maybe Sky
               }

    return w' { wrScene = scene' }
    
--updateTransforms :: [(String,Matrix4)] -> World -> IO World
updateTransforms l = return . mapScene (\s -> foldr updateSceneNode s l)
  where
    updateSceneNode (name,mat) scene = scene { scMap = Map.insert name (n,sn') m}
      where
        m = scMap scene
        (n,sn) = m ! name
        sn' = sn {snTransform = mat}

--flattenScene :: Scene -> FlattenScene
flattenScene s = FlattenScene
                 { fsCamera     = [(m,c) | (m,SO_Camera c) <- fs]
                 , fsRenderable = [(m,prepare m e,rq,pr) | (m,SO_Entity e) <- fs]
                 , fsLight      = [(m,l) | (m,SO_Light l) <- fs]
                 }
  where
    rq = constRenderQueueMain
    pr = constRenderableDefaultPriority
    fs = visitNode s 0 $ transl 0 0 0

    --visitNode :: Scene -> Int -> Matrix4 -> [(Matrix4,SceneObject)]
    visitNode g n t = [(lt,e) | e <- snObject ln ] ++ (concat [ visitNode g sn lt | sn <- suc (scGraph g) n ])
      where
        Just name = lab (scGraph g) n
        ln = snd $ (scMap g) ! name
        lt = (snTransform ln) <> t