--
-- 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 Criterion.Main
import System.Environment
import Graphics.Gloss.Interface.IO.Game
import Prelude as P
import Data.Array.Accelerate as A
main :: IO ()
main = do
(opt,noms) <- processArgs =<< getArgs
let -- configuration parameters
--
width = get simulationWidth opt * get displayScale opt
height = get simulationHeight opt * get displayScale opt
fps = get displayFramerate opt
dp = get viscosity opt
dn = get diffusion opt
-- Prepare user-input density and velocity sources
--
sources s = let (ix, ss) = P.unzip s
sh = Z :. length ix
in ( A.fromList sh ix, A.fromList sh ss )
-- 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.
--
simulate timestep world =
let step = run1 opt (fluid dp dn)
dt = A.fromList Z [timestep]
ds = sources (densitySource world)
vs = sources (velocitySource world)
(df', vf') = step ( dt, ds, vs, densityField world, velocityField world )
in
return $ world { densityField = df', velocityField = vf'
, densitySource = [], velocitySource = [] }
-- warming up...
initialWorld <- initialise opt
_ <- simulate 0.1 initialWorld
if get optBench opt
-- benchmark
then withArgs noms $ defaultMain
[ bench "fluid" $ whnfIO (simulate 1.0 initialWorld) ]
-- simulate
else playIO
(InWindow "accelerate-fluid" (width, height) (10, 20))
black -- background colour
fps -- display framerate
initialWorld -- initial state of the simulation
(render opt) -- render world state into a picture
(react opt) -- handle user events
simulate -- one step of the simulation