Monday, December 12, 2005

Simplified TeaTime

The next Croquet release, code-named "Hedgehog", will be centered around a real replicated object model, rather than the ad-hoc meta sends in Jasmine. See Andreas' and David's OOPSLA presentation (PDF) for an overview.

Wednesday, October 19, 2005

Tweak Interview

Andreas gave an interesting interview about Tweak.

Monday, August 15, 2005

Easy as Pie

Children "discover" Croquet's collaboration model called TeaTime.

Thursday, May 12, 2005

Connecting fields

Quick Recipe

To connect field a in obj1 to field b in obj2, use this:
obj2 startScript: #b: when: {obj1. #aChanged}
Now for the whole story ...

Problem

A colleague of mine wanted to make a drop-down list, where the options are not just set once, but provided and updated by the application. So, of course, when the options in the application changes, the items of the list widget have to be set to this new value. Nothing easier than that, just write a handler:
onOptionsChanged
    <on: optionsChanged in: app>
    listWidget items: app options
HOWEVER, he wanted to build this programmatically, not using a separate method. So, he easily came up with the following:
listWidget startScript : #items: withArguments: {app options} when: {app. #optionsChanged}
HOWEVER, this does not work as intended because the arguments to the script are evaluated only once, rather than every time the script is triggered. Well, this is what blocks are for, right? So this indeed works as intended:
listWidget startScript: [listWidget items: app options] when: {app. #optionsChanged}
HOWEVER, using blocks as long-lived scripts is discouraged. They're hard to identify in inspectors, hard to debug, etc. Alas, there seems to be no easy way around them. Or is there?

Solution

I've seen this problem a few times now, and the solution is so simple that I keep forgetting about it (which is why I spell it out here). This is how to wire the two fields:
listWidget startScript: #items: when: {app. #optionsChanged}
Doh! Where are the arguments? Well, the current value of a field is actually a parameter of the field change event (the previous value is the second one). Most of the time we just ignore it, since it's easy to get at the current value, but nevertheless, it's there. So, when #items: is triggered by the change event, its argument is the current value of the changed field, options. (This, btw, is a difference between #startScript: and #perform:, script arguments are optional, whereas method arguments are mandatory).

Of course, you can use the same technique in a regular method:
onOptionsChanged: newOptions
    <on: optionsChanged in: app>
    listWidget items: newOptions
But the earlier version at the top seems a bit more readable to me.

Thursday, April 21, 2005

Scripts in Croquet

Tao asked for a "Tweak & Croquet" tutorial. I don't have time right now to actually write one, but here's some sample code anyway.

Using scripts is easy and useful, even without the Tweak GUI. Just use #startScript: to run some method as a script. Inside a script, you can use loops and anything you like, just throw in a wait to account for time. Like, to animate the color of a frame, you could use this method (just add it to your TeapotMorph):
animateColorFor: aFrame
[
0 to: 360 do: [:hue |
aFrame material color: (Color h: hue s: 1.0 v: 1.0).
self wait: 0.01]
] repeat
This changes the color every 10 ms, and you can start it from the initializeDefaultSpace method:
    self startScript: #animateColorFor: withArguments: {someFrame}.
Here is something that does not loop forever, but finishes after one cycle:
jump: aFrame
| v g |
v := 0@1@0.
g := 0@-0.05@0.
[aFrame translation y >= 0] whileTrue: [
aFrame translation: aFrame translation + v.
v := v + g.
self waitTick.
].
aFrame translation: 0@0@0
Here we wait for the end of the frame - waiting is essential, because we do want to change the position only once in a frame. This can be run in response to a pointer click like this:
    self startScript: #jump: withArguments: {someFrame} when: {someFrame. #pointerDown}.
Or, if you wish, you could make a Tweak button for it. Here's the whole initializeDefaultSpace method doing it all:
initializeDefaultSpace
| space cube |
space := TSpace new.
space addChild: TLight new.
self makeFloor: space fileName:'floor.BMP'.

cube := TCube new.
cube material: TMaterial new.
space addChild: cube.

self startScript: #animateColorFor: withArguments: {cube}.

self startScript: #jump: withArguments: {cube} when: {cube. #pointerDown}.

self initializeTweakWorld: [
| button |
button := CButton new.
button label: 'Jump'.
button openAt: 100@100.
self startScript: #jump: withArguments: {cube} when: {button. #fire}.
].

^space
Hope that helps ...

Sunday, March 13, 2005

Tweak Tutorial

Andreas posted a BankAccount and ATM tutorial. This nicely demonstrates some of the basic Tweak concepts such as fields, events, triggers, and handlers, as well as introducing UI aspects like players, costumes, updating etc.

Monday, March 07, 2005

Print-Quality Screenshots

For high-quality prints you need high-quality screenshots. This means very high resolution, and nice anti-aliasing. Just grabbing the screen produces rather unpleasant results (screenshot, 80 KB, 800x600 pixels). With normal OpenGL rendering you get rarely more than screen resolution, and anti-aliasing quality very much depends on your graphics board. So what to do?

Tiled Rendering comes to the rescue. Instead of rendering the whole image at once, we render smaller portions of the scene, and then arrange the tiles into a large picture. However, just pointing the camera at each tile will not work as intended, the perspective would change from tile to tile. What is needed instead is to construct partial viewing frustums that together exactly recreate the whole frustum. This sounds like a lot of math, but actually it is quite simple:
gluPerspective: fov aspect: aspect zNear: near zFar: far tile: rect
| cotangent radians w h |
radians := (fov/2.0) degreesToRadians.
cotangent := radians cos / radians sin.
h := near / cotangent.
w := h * aspect.
self glFrustum(rect left*w, rect right*w, rect bottom*h, rect top*h, near, far).
So I just extended the existing gluPerspective:aspect:zNear:zFar: method with a tile argument that gives the sub-rectangle in the viewing plane, where the whole picture ranges from -1 to 1. The only problem is to hand down that extra argument into the method. I ended up copying all the methods in the call chain, adding a tile: parameter. With the methods in place and a utility method to construct the right sub-rectangles, I could render the image from the first screenshot again:
| m c f |
m := CroquetGlobals theTeapotMorph.
c := m activeCamera.
f := c root snapShot: m ogl camera: c tiled: 12.
f := f magnify: f boundingBox by: 0.5 smoothing: 4.
JPEGReadWriter2 putForm: f quality: 90 progressiveJPEG: false onFileNamed: 'croquet-bf-4800.jpg'.
Instead of 800x600, this renders 12x12 tiles, creating a 9600x7200 pixels image. The result is scaled down with smoothing to yield an anti-aliased 4800x3600 image, finally compressing as JPEG gives a 1.5 MB hires screenshot.

Beauty, eh? Never noticed that guy on the bridge before ;-)

Thursday, February 17, 2005

Change events are special

I just spent a few hours chasing a very mysterious bug, where an event handler was properly called the first time, but never again. This was a rather unspecial on:in: handler:
onFooInBar
<on: foo in: bar>
...
After initialization it was properly registered in the event map, but at some point the event map entry just vanished.

There also was another on: handler which did some stuff whenever bar changed. To "call" that stuff, we just signaled a barChanged event somewhere else:
self signal: #barChanged.
It turned out this innocuously looking line was responsible for the trashed on:in: handler! What happened?

Well, an on:in: handler must always be registered to the object that currently is occupying the bar field. But what if bar changes? Then we must unregister the foo handler in the old bar, and re-register it with the new bar. That's why the system installs a barChanged handler behind the scenes, which normally receives the new and old values of bar as arguments.

Now, can you see what happened? If we just signal #barChanged, then the arguments are nil! The current handler will be unregistered, but no new handler gets registered instead!

Lesson learned:
Do not signal a change event by hand!
Of course, we could have constructed a proper change signal like this:
self signalChanged: #barChanged from: bar to: bar
but why bother? It's much cleaner to not misuse the system-defined change event. I ended up defining another event, #barModified with a proper handler, which is signaled from both the #barChanged handler and other places.

Wednesday, February 09, 2005

About Scripts

We were looking into another Croquet performance problem the other day so we fired up a message tally (world menu - debug - start MessageTally). Curiously enough, 70 percent was taken by ScriptScheduler>>runActiveScripts! Unfortunately, the tally did not further differentiate this item.

But what are scripts, anyway? Everyone knows that Smalltalk is all about objects and messages, so what the heck are scripts?

Well, Croquet and Tweak are not just using Smalltalk as you know it (and the underlying Squeak still is pretty much vanilla Smalltalk-80), but instead improve on it by implementing a new enriched object system. There still are objects (the entities of the system) and messages (their means of communication). But where in Smalltalk methods are invoked synchronously by a message send, we now have asynchronous method invocations as well, which are called "scripts".

Synchronous in this context means that the sender sends a message, which invokes a method in the receiver that is immediately processed. Only after finishing the method the control returns to the sender. In contrast, an asynchronous send only schedules a method invocation for later processing, control is immediately returned to the sender. Here is an example (#perform: is synchronous, #startScript: asynchronous):
Transcript perform: #show: withArguments: #('1').
Transcript startScript: #show: withArguments: #('2').
Transcript perform: #show: withArguments: #('3').
If you execute this snippet from inside Tweak, it prints "132". Outside of it just "13" is printed because the second invocation is only started but never executed. There is no ScriptScheduler running to manage the execution of scripts. Inside Tweak there is one, and Croquet does it in a similar fashion.

Historically the term script in Squeak comes from the Etoys environment, where kids make objects and specify their behavior using scripts. One can have multiple objects and multiple scripts for each. All these scripts are running in parallel, at least from the user's point of view. Surprisingly enough kids don't have any problem with that, whereas concurrency normally is a hard problem even for seasoned programmers.

One reason why the parallel execution of interacting scripts is no problem in practice is the underlying scheduling policy: Scripts are never interrupted by other scripts. Other scripts are only executed when your script finished, or when it gives up control explicitly by waiting for an event. You can write your script almost as if it was the only process on the machine. Here's an example script:
| p |
p := CRectanglePlayer open.
1 to: 500 do: [:i |
    p x: i.
    self waitTick].
Looks just like how we did animations back when, right? Move a bit, wait for vsync, repeat. But the best part is this: While the loop is executing, you can perfectly well use anything else in the world! It's running "in parallel" to everything else on screen.

Another advantage is that you can easily have thread-local storage that way. Say, on mouse click you want to change an object's color to red, and on mouse up set it back to what the color was before. In most GUI frameworks you would have to implement both a mouse down and mouse up handler, and use an instance variable to store the previous color on mouse down. Not so in Tweak. The mouse down handler would look like this:
| oldColor |
oldColor := self color.
self color: Color red.
self waitUntil: #mouseUp.
self color: oldColor.
Much cleaner, in my book. Anyway, to get back to the original problem: So scripts are run as separate processes, but MessageTally's spyOn: method normally only takes samples in the process it was run in, which is the main UI process. Fortunately, there is a new method spyOnScript: which does the Right Thing. When starting the message tally from the Tweak project builder's debug menu, this new method is used, and indeed, we got a much more meaningful tally, and could spot the performance hog immediately.

Tuesday, February 08, 2005

Lend me a Hand

The last Tweak updates broke our Tweak-based Croquet application, objects did not respond to clicks anymore. I first suspected changes in Croquet, but the latest updates there didn't look suspicious. But neither did the last couple of Tweak updates. Investigating further and sprinkling debug output here and there I discovered that pointer events were offset. Moving the Croquet window to the upper left corner confirmed this, all of a sudden everything worked normally. What was happening?

Well, living in a shared world isn't easy. Morphic, Croquet, and Tweak interact very closely in the TeapotMorph, which bridges between those three worlds. Without Tweak (that is, without calling initializeTweakWorld in your initializeDefaultSpace method), the TeapotMorph uses the regular Morphic event dispatching mechanism which leads to calling the event handling methods keyDown:, mouseDown: etc. which in turn dispatch the events to the activeCamera, that is, into the Croquet world.

When using the Tweak overlay, this does not happen, but all events are translated into Tweak events and dispatched into the Tweak world. The initializeTweakWorld method not only sets up the Tweak world, but also registers event handlers (onKeyDown, onMouseDown etc.) that are called when no Tweak object handles the event itself, like when clicking outside a Tweak window. These event handlers translate the Tweak events back into a Morphic event and call the regular non-Tweak TeapotMorph event handling methods, from where processing continues as before.

Now translating the events back and forth also involves offseting them, because Tweak uses relative coordinates (every Tweak object defines its own coordinate system) whereas Morphs use global coordinates. Translating into Tweak was still working fine, the Tweak objects were acting just as expected. However, the back translation was wrong. In fact, the event we got back already was in Morphic coordinates, so when we applied the offset again it was way off. The problem is that events were not explicitely passed around, but rather we used the active hand's last event.

The Hand in Squeak is the object that injects user interface events into the world. Its visual representation is the mouse pointer, but keyboard events come from the hand, too. Because there can be multiple hands in a world, there's a global variable ActiveHand which is set to each hand while processing events initiated by that hand. Multiple hands, you ask? Yes, there was collaboration even before Croquet in Squeak (so each user in a shared Morphic world had a separate hand), and also multiple mice can be used independently, if that is supported by the VM (I once wrote a plugin for that using the XInput extension under Linux).

Now until last week, Tweak also did set ActiveHand to its current hand while processing an event. This had some odd side effects, for example, when some code expected ActiveHand to be a HandMorph (as is the case in Morphic) or a CHandPlayer (as in Tweak). In particular, when running a Tweak overlay in Croquet, which still largely assumes a Morphic environment, this led to confusion. But we pretty much ironed out all these wrinkles.

Except for the back-translation of events coming from the Tweak world, which happens in a Tweak process, so we fully expected the active hand to be a Tweak hand in this handler. But Andreas removed all references to ActiveHand from Tweak in an otherwise innocuously looking update (comment: "Various preps for upgrading to 3.8") so we did, in fact, by referencing ActiveHand get the original Morphic event instead of the expected Tweak event.

Just removing the offset would not work because you might have or might have not loaded that update. So we need to access the active Tweak hand, but without accessing the ActiveHand global. This is easiest if you are programming in Tweak, because every CPlayer has a field aptly named hand that refers to the active hand. Outside of Tweak you must do it the hard way, which is getting the hand from the active process. I'll talk about Tweak processes in another post, this one is already getting too long.

So, to make a long story short, if you fetch Croquet updates now, everything should be working fine again. There are two new methods in TeapotMorph, morphicHand and tweakHand, that return the right sort of hand (of course, the latter returns nil if Tweak is not running). They are used in the two methods I found where it actually matters, namely bringing up the halo which needs a morphic-hand, and back-translating events, which uses the tweak-hand.

That's all for today. Happy Tweakin'!

Friday, February 04, 2005

Wednesday, February 02, 2005

Dynamic Textures

We've been wondering for a while, why screen updates are more expensive than expected in the Tweak overlay. Now I debugged into this and it turns out we're uploading the whole texture even if only a small part was changed. The relevant code is in OGLTextureManager>>uploadTexture:dirtyRect:. A partial upload using glTexSubImage2D() is only performed if the texture in use is not static.

Having found out what's going on it's easy to fix, a one-line change in TeapotMorph>>glRenderTweakCostume:on: does the trick:
texCache isStatic: false.
As simple as that - I just posted the update.

Friday, January 28, 2005

Profiling + Vector Math = Performance

So there was a student who implemented a flocking simulation for a virtual fishtank using Croquet. Worked fine with 20 fishes. With 50 fishes it became rather sluggish. Putting in more than 100 fishes the framerate could be measured in seconds per frame. So the rendering in Croquet is too slow, right?

Not quite. There are two things you have to keep in mind when it comes to performance:
  1. When in doubt, measure.
  2. You are in doubt.
So we fired up a message tally (world menu - debug - start MessageTally). Turns out only 12 percent of the time were spent in rendering. So it's not the rendering at all. A whopping 80 percent was taken by the flock's step methods. The leaves of the message tally showed that 15 percent of the time went into each of the methods #x, #y, and #z!

So we looked at the code. Every fish was told to swim in the main direction of its neighbors, that is the fishes within a certain radius. Processing continued only for those fishes in range.

Sounds quite reasonable, doesn't it? The only problem was that to find the neighbors for a fish, the distance to each other fish was compared to the radius. Not only does this result in a quadratic complexity (every fish was tested against every other) but the distance check was this:
(((thisFish position x - otherFish position x) *
(thisFish position x - otherFish position x))+
((thisFish position y - otherFish position y) *
(thisFish position y - otherFish position y))+
((thisFish position z - otherFish position z) *
(thisFish position z - otherFish position z))) sqrt
This guy knows how to take the distance of two points in 3D, and he knows that the square is the product of a number with itself. Very well, but very slow, too.

Vectors in Croquet are represented as FloatArrays, and for a good reason. The reason is that you can compute sums, products, etc. of a zillion numbers very rapidly, just by invoking a single method. This is way faster than doing a component-wise computation on your own. There's a drawback too, which is that because the internal representation of a float in a FloatArray and the one in a normal Float object differs, it is rather expensive to read or write individual elements from such an array.

So to make your math go fast, use vectors instead of home-brew arithmetic. The whole mess above can be replaced by this:
(thisFish position - otherFish position) length
which is way faster.

Of course, one can further improve this by omitting the square root inside #length, by using #squaredLength and comparing to the squared radius, but that would be nit-picking. And of course one should reduce the overall algorithmic complexity from O(n²) to O(n log n), but that's just common sense.

The point I want to drive home is this: Use the class library wisely. If something is too slow, chances are you're doing it the wrong way. Look for examples in the image, there almost always is one. For a nice example of vector math look at the particle system (TParticle).