Thanks for these mails, that's actually very helpful!
I am working on a shorter syntax for animations at the moment (than 
GLMAnimation, Viva, Bloc-Animation), and could not find a proper equivalent to 
requestAnimationFrame (i.e. that would be independent of any UI yet in sync 
with display, and as simple as possible).
My solution was to repeatedly register to deferredUIMessages, implementing an 
intermediate block to add a timestamp like requestAnimationFrame (works wonders 
http://smalltalkhub.com/#!/~ThibaultRaffaillac/Animation)

Cheers,
Thibault

ps: I'll ask Guille asap for the state of ReactiveExtensions (lacks comments)

> Also, check
> 
> MorphicUIManager>>#spawnNewProcess
> 
> UIProcess := [
> [World doOneCycle.  Processor yield.  false] whileFalse: [].
> ] newProcess priority: Processor userSchedulingPriority.
> UIProcess name: 'Morphic UI Process'.
> UIProcess resume
> 
> digging into doOneCycle, you'll find:
> 
> #doOneCycleFor: aWorld
> "Do one cycle of the interaction loop. This method is called *repeatedly
> *when
> the world is running. This is a moderately private method; a better
> alternative is usually either to wait for events or to check the state of
> things from #step methods."
> 
> self interCyclePause: MinCycleLapse.
> self doOneCycleNowFor: aWorld.
> 
> 
> The interCyclePause is what make the UI timing alignment proper (notice
> serverMode) [and some Squeak remnant mention]:
> 
> interCyclePause: milliSecs
> "delay enough that the previous cycle plus the amount of delay will equal
> milliSecs.  If the cycle is already expensive, then no delay occurs.
> However, if the system is idly waiting for interaction from the user, the
> method will delay for a proportionally long time and cause the overall CPU
> usage of *Squeak* to be low.
> If self serverMode returns true then, always do a complete delay of 50ms,
> independant of my argument. This prevents the freezing problem described in
> Mantis #6581"
> 
> | wait wait2 |
>         "*a very long assignment*"
> wait := self serverMode
>     ifTrue: [ 50 ]
>     ifFalse:
> [ wait2 := (lastCycleTime notNil and: [CanSurrenderToOS ~~ false])
>         ifFalse: [ 0 ]
>         ifTrue: [ lastCycleTime + milliSecs - Time millisecondClockValue ].
> 
>       self flag: 'Issue 14754 - wait2>millisecs is only True for clock
> rollover. Remove it once DelayScheduler based on microsecondClock - Ben
> Coman 19.01.2015'.  "*<---- maybe we want this #flag: not to be called all
> the time* "
>       wait2 > milliSecs
>         ifTrue: [ 0 ]
>         ifFalse: [ wait2 ].
> ].
> wait > 0 ifTrue: [ (Delay forMilliseconds: wait) wait ].   "<------- wait
> is not #>>wait"
> 
> lastCycleTime := Time millisecondClockValue.
> CanSurrenderToOS := true.
> 
> Now, yeah, how do get stuff to be painted on the  screen?
> 
> Like this:
> 
> displayWorld: aWorld submorphs: submorphs
> "Update this world's display."
> 
> | deferredUpdateMode handsToDraw allDamage |
> 
> submorphs do: [:m | m fullBounds].  "force re-layout if needed"
> self checkIfUpdateNeeded ifFalse: [^ self].  "display is already up-to-date"
> 
> deferredUpdateMode := self doDeferredUpdatingFor: aWorld.
> deferredUpdateMode ifFalse: [self assuredCanvas].
> canvas roundCornersOf: aWorld during:[ | worldDamageRects handDamageRects |
> worldDamageRects := self drawWorld: aWorld submorphs: submorphs
> invalidAreasOn: canvas.  "repair world's damage on canvas"
> "self handsDo:[:h| h noticeDamageRects: worldDamageRects]."
> handsToDraw := self selectHandsToDrawForDamage: worldDamageRects.
> handDamageRects := handsToDraw collect: [:h | h savePatchFrom: canvas].
> allDamage := worldDamageRects, handDamageRects.
> 
> handsToDraw reverseDo: [:h | canvas fullDrawMorph: h].  "draw hands onto
> world canvas"
> ].
> "*make this true to flash damaged areas for testing*"
> self class debugShowDamage ifTrue: [aWorld flashRects: allDamage color:
> Color black].
> 
> canvas finish.
> "quickly copy altered rects of canvas to Display:"
> deferredUpdateMode
> ifTrue: [self forceDamageToScreen: allDamage]
> ifFalse: [canvas showAt: aWorld viewBox origin invalidRects: allDamage].
> handsToDraw do: [:h | h restoreSavedPatchOn: canvas].  "restore world
> canvas under hands"
> Display deferUpdates: false; forceDisplayUpdate.
> 
> The VM will take care of throwing the bits to the display in various ways.
> Interesting to look how it is done for Windows, OSX, and Linux.
> 
> So you have about a full view now.
> 
> Timing wise, there is also some interaction with the VM occuring elsewhere.
> Pharo is still polling deep inside.  epoll etc isn't there yet, hence the
> little idle CPU usage when doing nothing.
> 
> Good luck doing this UI trip with other platforms, not to mention change or
> instrument it the way you like.
> 
> Pharo is really cool for this as it helps in learning about a lot of things.
> 
> Want to do sockets?
> Do the high level stuff in Pharo and dig in the VM to see how it is done
> down under for a set of platforms.
> 
> Enjoy.
> 
> Phil

Reply via email to