packages feed

affection-0.0.0.2: examples/example03.hs

{-# LANGUAGE RecordWildCards #-}

import Affection
import qualified SDL
import qualified GEGL as G
import qualified BABL as B

import qualified Data.Map.Strict as M

import Control.Monad (when)

import Foreign.C.Types

import System.Random (randomRIO)

import Debug.Trace

main :: IO ()
main = do
  conf <- return $ AffectionConfig
    { initComponents = All
    , windowTitle    = "Affection: example00"
    , windowConfig   = SDL.defaultWindow
    , preLoop        = drawInit
    , drawLoop       = draw
    , updateLoop     = update
    , loadState      = load
    , cleanUp        = clean
    }
  withAffection conf

data UserData = UserData
  { nodeGraph   :: M.Map String G.GeglNode
  , foreground  :: G.GeglBuffer
  , partsys     :: ParticleSystem
  }

load :: SDL.Surface -> IO UserData
load _ = do
  traceM "loading"
  root <- G.gegl_node_new
  traceM "new root node"
  checkerboard <- G.gegl_node_new_child root $ G.checkerboardOperation
    [ G.Property "color1" $ G.PropertyColor $ G.RGBA 0.4 0.4 0.4 1
    , G.Property "color2" $ G.PropertyColor $ G.RGBA 0.6 0.6 0.6 1
    ]
  traceM "checkerboard"
  over <- G.gegl_node_new_child root G.defaultOverOperation
  traceM "over"
  buffer <- G.gegl_buffer_new (Just $ G.GeglRectangle 0 0 800 600) =<<
    B.babl_format (B.PixelFormat B.RGBA B.CFfloat)
  sink <- G.gegl_node_new_child root $ G.Operation "gegl:copy-buffer"
    [G.Property "buffer" $ G.PropertyBuffer buffer
    ]
  traceM "buffer-sink"
  nop <- G.gegl_node_new_child root $ G.Operation "gegl:nop" []
  traceM "nop"
  crop <- G.gegl_node_new_child root $ G.Operation "gegl:crop"
    [ G.Property "width" $ G.PropertyDouble 800
    , G.Property "height" $ G.PropertyDouble 600
    ]
  traceM "crop"
  G.gegl_node_link_many [checkerboard, over, crop, sink]
  G.gegl_node_connect_to nop "output" over "aux"
  traceM "connections made"
  myMap <- return $ M.fromList
    [ ("root"        , root)
    , ("over"        , over)
    , ("background"  , checkerboard)
    , ("sink"        , sink)
    , ("nop"         , nop)
    , ("crop"        , crop)
    ]
  traceM "loading complete"
  return $ UserData
    { nodeGraph = myMap
    , foreground = buffer
    , partsys = ParticleSystem (ParticleStorage Nothing []) nop buffer
    }

drawInit :: Affection UserData ()
drawInit = do
  UserData{..} <- getAffection
  present (GeglRectangle 0 0 800 600) foreground True

draw :: Affection UserData ()
draw = do
  traceM "drawing"
  UserData{..} <- getAffection
  liftIO $ G.gegl_node_process $ nodeGraph M.! "sink"
  -- ad <- get
  -- ud <- getAffection
  -- drawParticles partDraw $ particles ud
  -- SDL.V2 (CInt rw) (CInt rh) <- SDL.surfaceDimensions $ drawSurface ad
  -- let (w, h) = (fromIntegral rw, fromIntegral rh)
  -- liftIO $ clearArea (foreground ud) (GeglRectangle 0 0 w h)
  -- maybe (return ()) (\(x, y) ->
  --   drawRect
  --     (foreground ud)
  --     (nodeGraph ud M.! "over")
  --     (G.RGBA 1 0 0 0.5)
  --     (Line 7)
  --     (G.GeglRectangle (x - 10) (y - 10) 20 20)
  --   ) $ coordinates ud

update :: Double -> [SDL.Event] -> Affection UserData ()
update sec evs = do
  traceM "updating"
  ad <- get
  ud <- getAffection
  -- let newPart = updateParticles sec partUpd $ particles ud
  -- putAffection $ ud { particles = newPart }
  traceM $ (show $ 1 / sec) ++ " FPS"
  -- ev <- liftIO $ SDL.pollEvents
  mapM_ (\e ->
    case SDL.eventPayload e of
      SDL.MouseMotionEvent dat ->
        if SDL.ButtonLeft `elem` SDL.mouseMotionEventState dat
        then do
          let (SDL.P (SDL.V2 x y)) = SDL.mouseMotionEventPos dat
          vx <- liftIO $ randomRIO (-20, 20)
          vy <- liftIO $ randomRIO (-20, 20)
          life <- liftIO $ randomRIO (1, 5)
          r <- liftIO $ randomRIO (0,1)
          g <- liftIO $ randomRIO (0,1)
          b <- liftIO $ randomRIO (0,1)
          tempRoot <- liftIO $ G.gegl_node_new
          tempOver <- liftIO $ G.gegl_node_new_child tempRoot
            G.defaultOverOperation
          tempRect <- liftIO $ G.gegl_node_new_child tempRoot $ G.Operation
            "gegl:rectangle"
            [ G.Property "x"      $ G.PropertyDouble $ fromIntegral x - 10
            , G.Property "y"      $ G.PropertyDouble $ fromIntegral y - 10
            , G.Property "width"  $ G.PropertyDouble 20
            , G.Property "height" $ G.PropertyDouble 20
            , G.Property "color"  $ G.PropertyColor  $ (G.RGBA r g b 0.5)
            ]
          liftIO $ G.gegl_node_connect_to tempRect "output" tempOver "aux"
          -- traceM $ "position is: " ++ show x ++ " " ++ show y
          -- traceM $ "velocity is: " ++ show vx ++ " " ++ show vy
          ips <- insertParticle (partsys ud) $
            Particle
              { particleTimeToLive = life
              , particleCreation   = elapsedTime ad
              , particlePosition   = (fromIntegral x, fromIntegral y)
              , particleRotation   = Rad 0
              , particleVelocity   = (vx, vy)
              , particlePitchRate  = Rad 0
              , particleRootNode   = tempRoot
              , particleNodeGraph  = M.fromList
                [ ("root", tempRoot)
                , ("over", tempOver)
                , ("rect", tempRect)
                ]
              , particleStackCont  = tempOver
              , particleDrawFlange = tempOver
              }
          putAffection $ ud
            { partsys = ips
            }
          -- when (not $ null $ psParts $ partsys ud) $
          --   liftIO $ G.gegl_node_link
          --     tempOver
          --     (particleStackCont $ head $ psParts $ partsys ud)
        else
          return ()
      SDL.WindowClosedEvent _ -> do
        traceM "seeya!"
        put $ ad
          { quitEvent = True
          }
      _ ->
        return ()
    ) evs
  ud2 <- getAffection
  nps <- updateParticleSystem (partsys ud2) sec partUpd partDraw
  putAffection $ ud2 { partsys = nps }

clean :: UserData -> IO ()
clean _ = return ()

partUpd :: Double -> Particle -> Affection UserData Particle
partUpd sec p@Particle{..} = do
  let newX = (fst particlePosition) + sec * (fromIntegral $ fst particleVelocity)
      newY = (snd particlePosition) + sec * (fromIntegral $ snd particleVelocity)
  liftIO $ G.gegl_node_set (particleNodeGraph M.! "rect") $ G.Operation "gegl:rectangle"
    [ G.Property "x" $ G.PropertyDouble $ newX - 10
    , G.Property "y" $ G.PropertyDouble $ newY - 10
    ]
  return p
    { particlePosition = (newX, newY)
    }

partDraw :: G.GeglBuffer -> G.GeglNode -> Particle -> Affection UserData ()
partDraw buf node Particle{..} = do
  present
    (G.GeglRectangle (floor $ fst particlePosition - 10) (floor $ snd particlePosition - 10) 20 20)
    buf
    False
  -- ud <- getAffection
  -- drawRect'
  --   particleDrawFlange
  --   (G.RGBA 1 0 0 0.5)
  --   (Fill)
  --   (G.GeglRectangle ((floor $ fst particlePosition) - 10) ((floor $ snd particlePosition) -10) 20 20)
  --   buf