[plt-scheme] FrTime implementation

From: Dave Griffiths (dave at pawfal.org)
Date: Sat Jan 12 11:14:40 EST 2008

All working now - thanks!

On Sat, 2008-01-12 at 10:15 -0500, Gregory Cooper wrote:
> Hi Dave,
> 
> Sorry.  I forgot that do-in-manager-after already waits for FrTime to
> finish processing, so the channels are unnecessary (and will cause a
> deadlock).  The loop code can just read:
> 
> (let loop ()
>  ;; emit the next pulse
>  (send-event fluxus-pulse #t)
>  ;; wait for frtime to finish updating everything
>  (do-in-manager-after (void))
>  ;; draw the frame from a consistent state
>  (draw-a-frame <reactive scene description data structure>)
>  (loop))
> 
> Greg
> 
> On Jan 12, 2008 9:31 AM, Dave Griffiths <dave at pawfal.org> wrote:
> > 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.