[plt-scheme] FrTime implementation
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
> > >
> > >
>
>