-- -- A stable fluid simulation -- -- Jos Stam, "Real-time Fluid Dynamics for Games" -- module Main where import Config import World import Fluid import Event import Data.Label import Control.Exception import Graphics.Gloss.Interface.IO.Game import Prelude as P import Data.Array.Accelerate as A import Data.Array.Accelerate.Examples.Internal as A main :: IO () main = do beginMonitoring (conf, opts, rest) <- initialiseConfig =<< parseArgs options defaults header footer let -- configuration parameters -- width = get simulationWidth conf * get displayScale conf height = get simulationHeight conf * get displayScale conf steps = get simulationSteps conf fps = get displayFramerate conf dp = get viscosity conf dn = get diffusion conf dt = get timestep conf backend = get optBackend opts -- Prepare user-input density and velocity sources -- sources s = let (ix, ss) = P.unzip s sh = Z :. P.length ix in ( A.fromList sh ix, A.fromList sh ss ) -- for benchmarking -- force w = indexArray (densityField w) (Z:.0:.0) `seq` indexArray (velocityField w) (Z:.0:.0) `seq` w -- Prepare to execute the next step of the simulation. -- -- Critically, we use the run1 execution form to ensure we bypass all -- front-end conversion phases. -- step = run1 backend (fluid steps dt dp dn) simulate world = let ds = sources (densitySource world) vs = sources (velocitySource world) (df', vf') = step ( ds, vs, densityField world, velocityField world ) in force $ world { densityField = df', velocityField = vf' , densitySource = [], velocitySource = [] } -- warming up... -- initialWorld <- evaluate (initialise conf) _ <- evaluate (simulate initialWorld) runBenchmarks opts rest [ bench "fluid" $ whnf simulate initialWorld ] runInteractive opts rest $ playIO (InWindow "accelerate-fluid" (width, height) (10, 20)) black -- background colour fps -- display framerate initialWorld -- initial state of the simulation (render conf) -- render world state into a picture (react conf) -- handle user events (\_ -> return . simulate) -- one step of the simulation