[plt-scheme] FrTime implementation

From: Dave Griffiths (dave at pawfal.org)
Date: Sat Jan 12 09:31:26 EST 2008

Hi Greg,

I've had a go at implementing this, and it seems to hang inside
(do-in-manager-after (channel-put frtime-chan #t))
Presumably because the channel-put is being run straight away and
blocking rather than being deferred... I looked at the macro but got a
bit lost :)

My code is still very trivial (mostly copy pasted from your email):

(module frtest mzscheme
  
  (require 
   (lib "lang-ext.ss" "frtime")
   (all-except (lib "frp-core.ss" "frtime") undefined?))
  
  (provide
   set-scene
   clock)
     
  (define frtime-chan (make-channel))
  (define fluxus-pulse (event-receiver))
  (define scene-list '())

  (define (set-scene s) 
    (set! scene-list s))
 
  (define clock 
    (hold 
     (map-e 
      (lambda (e) 
        (current-milliseconds)) 
      fluxus-pulse)))
  
  (define (draw-a-frame lst)
    (for-each 
     (lambda (b)
       (display (value-now b))(newline))
     lst))
  
  (define (loop)
    ;; emit the next pulse
    (send-event fluxus-pulse #t)
    ;; have frtime send a message when it's done updating everything    
    (do-in-manager-after (channel-put frtime-chan #t))
    ;; wait for the message from frtime
    (channel-get frtime-chan)
    ;; draw the frame from a consistent state
    (draw-a-frame scene-list)
    (loop))
  
  (thread (loop))
  
  )

(require frtest)

(set-scene (list clock))


On Sun, 2007-12-09 at 06:43 -0500, Gregory Cooper wrote:
> Ah.  Now I think I understand the problem a bit better.  It sounds
> like what you'll want is a mechanism for synchronizing FrTime and the
> Fluxus render loop.  Here's how I'd recommend doing it:
> 
> 1.  Define an event stream called something like fluxus-pulse:
> 
>   (define fluxus-pulse (event-receiver))
> 
> 2.  Define your own versions of the primitive input behaviors you
> need, which only update on these pulses.  E.g.:
> 
>   (define clock (hold (map-e (lambda (e) (current-milliseconds)) fluxus-pulse)))
> 
> 3.  Each time through the render loop, emit a pulse, then wait for
> FrTime to stabilize, and finally draw.  Here's a rough sketch:
> 
> (define frtime-chan (make-channel))
> 
> (let loop ()
>   ;; emit the next pulse
>   (send-event fluxus-pulse #t)
>   ;; have frtime send a message when it's done updating everything
>   (do-in-manager-after (channel-put frtime-chan #t))
>   ;; wait for the message from frtime
>   (channel-get frtime-chan)
>   ;; draw the frame from a consistent state
>   (draw-a-frame <reactive scene description data structure>)
>   (loop))
> 
> 4.  Note that with this approach, there is no lifting at all
> (regardless of DrScheme version).  Instead, as you traverse the
> reactive structure, you'll just test whether each value you encounter
> is a behavior, and if so, you'll call "value-now" on it before
> proceeding.
> 
> Let me know whether this helps or not.
> 
> Cheers,
> Greg
> 
> On Dec 9, 2007 5:57 AM, Dave Griffiths <dave at pawfal.org> wrote:
> >
> > On Sat, 2007-12-08 at 22:52 -0500, Gregory Cooper wrote:
> > > Hi Dave,
> > >
> > > It looks like you have the right idea.  :-)
> > >
> > > Are you running a pre-v371 version of DrScheme / FrTime?  (From the
> > > code and description you give, it sounds like you are...)  I ask
> > > because around July I changed the way FrTime deals with lists and
> > > other data structures, and this change makes it a bit more complicated
> > > to lift over data structures containing behaviors.
> > >
> > > In pre-v371, all data constructors (including "cons") are lifted, so
> > > any reactivity inside a data structure spreads to the structure
> > > itself.  When you lift a procedure over a reactive structure, the
> > > procedure gets called repeatedly with snapshots of the structure
> > > (computed each time anything inside the structure changes).  This is
> > > why the second (make-torus ...) gets redrawn every millisecond, even
> > > though it only changes once a second: draw-list processes the entire
> > > list whenever anything inside it changes.
> > >
> > > In v371 and later, data constructors are not lifted, so behaviors can
> > > hide inside structures.  In order to lift over such structures, you'll
> > > first need to use "raise-reactivity" to make the reactivity spread to
> > > the top of the structure, or use "compound-lift" (like the new
> > > animation.ss does), which lets your procedure find the reactivity
> > > while traversing the structure.  (This avoids the work of constructing
> > > a deep snapshot each time something changes.)  If you decide to
> > > upgrade to v371 at some point, let me know and I'll be happy to help
> > > explain this.
> >
> > That makes sense. I'm running 370 - time to upgrade :)
> >
> > > A couple of small comments: I'm surprised that you don't have code to
> > > clear the buffer before rendering the list of shapes, like
> > > animation.ss does.
> >
> > This is the nub of the problem for me really ;)
> >
> > When running in drscheme, the render loop is running in a different
> > (plt) thread.
> >
> > This is due to the way fluxus works - you don't drive the render loop
> > yourself, but you can optionally hook into it to get a function called
> > by the engine every frame to animate/update things. (using frtime even
> > this wont be needed)
> >
> > This is a Good Thing - the framerate can be detached from the script
> > update (you can always interactively move the camera around with the
> > mouse etc)
> >
> > The problem with this naive frtime script is that the primitives strobe
> > as they are drawing once per millisecond, rather than once per frame.
> > This is fixed by using retained mode primitives (rather than the
> > immediate mode (draw-*) ones it uses at the moment), which are
> > maintained inside the render engine and rendered every frame for you,
> > optimised for speed. then frtime can just update them whenever it wants
> > to.
> >
> > This has implications to how I implement the frtime interface - I'll
> > need to do some work to make this stateful (for reasons of speed)
> > situation appear stateless.
> >
> > One option is to require the 'user' to name each object, so the frtime
> > implementation can infer some historical information - first time it
> > appears build it, other times update it, when it doesn't appear in the
> > list delete it.
> >
> > How does animation.ss cope with this? If a shape only updates once a
> > second, how does it get redrawn when other things are updating more
> > quickly?
> >
> > > Also, I'm not sure why you don't just write:
> > >
> > >   (define clock milliseconds)
> >
> > Ah, I was just playing with changing it, but left it as * 1 :)
> >
> > cheers,
> >
> > dave
> >
> >



Posted on the users mailing list.