Dear All,

I'm trying to get my hands wet with the reactive library,
but already the simplest example I cooked up is failing
to work properly (and leaks memory, and uses relatively
lots of cpu time).

The problem appears when I try to merge my two events
with `mappend`. One event should exit on pressing ESC,
the other draws colored circles on pressing the left mouse
button. They work correctly separately.

Could somebody explain me what's happening, or
whether I'm making a basic mistake?

The code is below, I hope the formatting survives the
various email systems. I don't know if that matters or
not, but I'm using OS X.

Thanks,
Balazs


module Main where

import Control.Monad
import Data.Monoid

import FRP.Reactive
import FRP.Reactive.GLUT.Adapter

import Graphics.Rendering.OpenGL hiding (normalize)
import Graphics.UI.GLUT hiding (normalize,Char)

import System.Exit

-------------------------------------------------------

nop :: Monad m => m ()
nop = return ()

data Vec2 = Vec2 !Float !Float

(&+) (Vec2 x1 y1) (Vec2 x2 y2) = Vec2 (x1+x2) (y1+y2)

sinCosRadius a r = Vec2 (r * cos a) (r * sin a)

instance Vertex Vec2 where
  vertex (Vec2 x y) = vertex (Vertex2 x y)
 
-------------------------------------------------------

display :: Action -> Action
display action = do
  clear [ ColorBuffer , DepthBuffer ]
 
  siz@(Size xs ys) <- get windowSize
  matrixMode $= Projection
  loadIdentity
  let q = fromIntegral xs / fromIntegral ys
      r = 1 / q
  if q >= 1
    then ortho 0 1 r 0 (-1) 1
    else ortho 0 q 1 0 (-1) 1
  viewport $= ( Position 0 0 , siz )
  matrixMode $= Modelview 0
  loadIdentity
    
  action
  postRedisplay Nothing
  swapBuffers
 
data Col = RR | GG | BB 

nextCol RR = GG
nextCol GG = BB
nextCol BB = RR

setCol RR = color (Color3 1 0 (0::Float))
setCol GG = color (Color3 0 1 (0::Float))
setCol BB = color (Color3 0 0 (1::Float))

drawWithCol col = do
  setCol col
  let center = Vec2 0.25 0.25
      radius = 0.1
      n = 32
  renderPrimitive TriangleFan $ do
    vertex center
    let phi j = 2*pi * fromIntegral j / fromIntegral n
    forM_ [0..n] $ \i ->
      vertex (center &+ sinCosRadius (phi i) radius)
       
myUI :: UI -> Behaviour Action
myUI ui = uiB where

  mp = mousePosition ui
  lb = leftButtonPressed ui
  rb = leftButtonPressed ui
  ky = keyPressed ui

  colE = mealy_ RR nextCol lb
  drawE = fmap drawWithCol colE
 
  exitE = justE (fmap esc ky) where
    esc k = case k of
      Char '\ESC' -> Just exitSuccess
      _           -> Nothing
     
  uiE = fmap display drawE `mappend` exitE
  uiB = stepper nop uiE
 
-------------------------------------------------------

main = do
  initialize "alma" []
  initialWindowSize $= Size 512 384
  initialDisplayMode $= [ RGBAMode , WithDepthBuffer , DoubleBuffered ]
  createWindow "reactive test"
  adapt myUI