Thibault

you should talk also with Glenn and Alain to get feedback. They will visit us in Nov.


Stef


Le 7/10/16 à 15:14, Thibault Raffaillac a écrit :
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