roguestar-gl-0.6.0.0: src/AnimationTerrain.hs
{-# LANGUAGE Arrows, OverloadedStrings, TypeFamilies, FlexibleContexts #-}
module AnimationTerrain
(terrainThreadLauncher)
where
import Data.List
import RSAGL.Math.Types
import RSAGL.FRP
import RSAGL.Math
import RSAGL.Animation.InverseKinematics
import Animation
import Control.Arrow
import Control.Monad
import Control.Monad.Random
import Data.Maybe
import Models.LibraryData
import ProtocolTypes
import Scene
import AnimationExtras
type TerrainThreadSwitch m = RSwitch Enabled (Maybe ProtocolTypes.TerrainTile) () () m
-- | Thread that launches rendering threads for the terrain tiles.
terrainThreadLauncher :: (FRPModel m) => FRP e (TerrainThreadSwitch m) () ()
terrainThreadLauncher = spawnThreads <<<
arr (map (\x -> (Just x,terrainTile x))) <<<
newListElements <<< terrainElements
terrainTile :: (FRPModel m) => ProtocolTypes.TerrainTile ->
FRP e (TerrainThreadSwitch m) () ()
terrainTile (tid@(ProtocolTypes.TerrainTile terrain_type (x,y))) = proc () ->
do terrain_elements <- terrainElements -< ()
let still_here = isJust $ find (== tid) terrain_elements
let goal_size = if still_here then 1.25 else -0.25
actual_size <- arr (max 0 . min 1) <<<
approachFrom 0.5 (perSecond 1.0) 0 -< goal_size
killThreadIf -< actual_size <= 0.0 && not still_here
transformA (libraryA >>> terrainDecoration tid) -<
(Affine $ translate
(Vector3D (fromInteger x) 0 (negate $ fromInteger y)) .
scale' actual_size,
(scene_layer_local,Models.LibraryData.TerrainTile terrain_type))
returnA -< ()
terrainElements :: (FRPModel m, FRPModes m ~ RoguestarModes) =>
FRP e m () [ProtocolTypes.TerrainTile]
terrainElements = arr (maybe [] tableSelectTyped) <<< sticky isJust Nothing <<<
driverGetTableA <<< arr (const ("visible-terrain","0"))
terrainDecoration :: (FRPModel m, FRPModes m ~ RoguestarModes) =>
ProtocolTypes.TerrainTile ->
FRP e m () ()
terrainDecoration (ProtocolTypes.TerrainTile "forest" (x,y)) =
fst $ runRand (leafyTree 2 True)
(mkStdGen $ fromInteger $ x + 1000*y)
terrainDecoration (ProtocolTypes.TerrainTile "deepforest" (x,y)) =
fst $ runRand (leafyTree 3 True)
(mkStdGen $ fromInteger $ 2*x + 1001*y + 7)
terrainDecoration _ = proc () -> returnA -< ()
leafyTree :: (FRPModel m, FRPModes m ~ RoguestarModes) =>
Int -> Bool -> Rand StdGen (FRP e m () ())
leafyTree recursion has_leaves =
do dead_tree <- liftM (== 1) $ getRandomR (1,4 :: Integer)
(x:y:_) <- getRandomRs (-0.4,0.4)
thickness <- getRandomR (0.02*realToFrac recursion,
0.04*realToFrac recursion)
push_up <- getRandomR (1.5/realToFrac recursion,
3.0/realToFrac recursion)
leafyTreeBranch (Point3D x 0 y)
(Vector3D 0 push_up 0)
thickness
recursion
(has_leaves && not dead_tree)
leafyTreeBranch :: (FRPModel m, FRPModes m ~ RoguestarModes) =>
Point3D ->
Vector3D ->
RSdouble ->
Int ->
Bool ->
Rand StdGen (FRP e m () ())
leafyTreeBranch point vector thickness recursion has_leaves | recursion <= 0 =
do let leaves = translateToFrom point (Point3D 0 0 0) $
scale' (vectorLength vector + thickness) $
proc () -> libraryA -< (scene_layer_local,LeafyBlob)
return $ if has_leaves then leaves else proc () -> returnA -< ()
leafyTreeBranch point vector thickness recursion has_leaves =
do b <- getRandom
let branch_inset = min 0.25 $ thickness / vectorLength vector
takes <- getRandomR (1,recursion)
us <- liftM (take takes) $ getRandomRs (2*branch_inset,1.0-branch_inset)
other_branches <- mapM (leafyTreeBranchFrom $ b && has_leaves) us
continue_trunk <- leafyTreeBranchFrom has_leaves $ 1.0 - branch_inset
let this_branch = translateToFrom point (Point3D 0 0 0) $
rotateToFrom vector (Vector3D 0 1 0) $
scale (Vector3D thickness (vectorLength vector) thickness) $
proc () -> libraryA -< (scene_layer_local,TreeBranch)
return $ this_branch >>> continue_trunk >>> foldr1 (>>>) other_branches
where leafyTreeBranchFrom :: (FRPModel m, FRPModes m ~ RoguestarModes) =>
Bool -> RSdouble -> Rand StdGen (FRP e m () ())
leafyTreeBranchFrom pass_leaves u =
do let new_vector_constraint = vectorLength vector / 1.5
(x:y:z:_) <- getRandomRs (-new_vector_constraint,
new_vector_constraint)
t <- getRandomR (thickness/3,thickness/2)
leafyTreeBranch
(lerp u (point,translate vector point))
(vectorScaleTo new_vector_constraint $
vector `add` (Vector3D x y z))
t
(recursion - 1)
pass_leaves