packages feed

reflex-vty-1.0.0.1: src-bin/Example/CellBuffer.hs

-- |
--   Description: An animated plasma field rendered cell-by-cell, à la the
--   cellbuffer example.
module Example.CellBuffer (cellBuffer) where

import Control.Monad.IO.Class (liftIO)
import Data.Time (getCurrentTime)
import qualified Graphics.Vty as V
import Reflex

import Example.Common
import Reflex.Vty

-- | A classic plasma effect: each cell's character and color are a pure
-- function of its position and the frame, summed over a few sine waves.
cellBuffer :: Demo t m => m (Event t ())
cellBuffer = do
  t0 <- liftIO getCurrentTime
  tick <- tickLossy 0.06 t0
  n <- foldDyn (\_ i -> i + 1) (0 :: Int) tick
  dw <- displayWidth
  dh <- displayHeight
  tellImages $ (\w h i -> [plasma w h i]) <$> current dw <*> current dh <*> current n
  quit
  where
    ramp = " .:-=+*#%@"
    grad =
      gradient1D
        [ (0, RGB 25 20 70)
        , (0.4, RGB 190 40 140)
        , (0.7, RGB 255 150 40)
        , (1, RGB 255 240 150)
        ]
    plasma w h i =
      let t = fromIntegral i * 0.12 :: Double
          cell x y =
            let fx = fromIntegral x
                fy = fromIntegral y
                v =
                  sin (fx * 0.18 + t)
                    + sin (fy * 0.27 + t * 1.2)
                    + sin ((fx + fy) * 0.12 + t * 0.8)
                    + sin (sqrt (fx * fx + fy * fy) * 0.2 - t)
                u = (v + 4) / 8 -- normalize roughly to [0,1]
                ci = max 0 $ min (length ramp - 1) $ floor (u * fromIntegral (length ramp))
                clr = fromRGB $ sampleGradient1D grad u
            in V.char (V.withForeColor V.defAttr clr) (ramp !! ci)
      in V.vertCat [V.horizCat [cell x y | x <- [0 .. w - 1]] | y <- [0 .. h - 1]]