Monday, January 24, 2005

On vs. Off

English is weird. Even the word "weird" is weird, as it violates the "i" before "e" except after "c" rule.

In the previous post, I wrote "On to Japan". I thought about this and realized that I should have written "Off to Japan", and started wondering why either one is appropriate to some degree. We say "on to Japan" when we mean we are continuing our travels "onward". And we say "off to Japan" when we are talking about leaving the current location as in "I am off (from here) to Japan. They are very nuanced differences, but they use exact opposite words to denote these differences - on vs. off.

On to Japan

I leave tomorrow morning for Japan and the C5 conference. I will need to write a lot of my demo on the plane. There was just a lot of support code to write before I could actually work on the real thing. However, I think the end result will be nice. There are a lot of nifty new ideas in this. More to come...

Sunday, January 23, 2005

Now the real work begins

I have completed everything I need to be able to start actually writing the object creation/edit code in Wicket. All of the support infrastructure is in place and looks very good. So now all I have to do is generate a few tasks based upon the state of the buttons and the user's actions. Should be pretty easy...

And it has to be done by Tuesday.

Saturday, January 22, 2005

Radio Buttons

In writing the new task based CAD system, I have had to create a number of extensions to Croquet. One of these is radio buttons. These are used to specify that only one button can be selected at a time. This requires that you use the two state button mode, because it switches between them to signify what button is selected. I may update this later to do something different for one state buttons with shading, but I don't have time right now. To use this, do the following:

extrudeButtons := TButtonHolder new.
extrudeButtons buttonWidth: buttonWidth.
extrudeButtons extent:1.0@1.0.
extrudeButtons radioOn.
self addChild:extrudeButtons. "add the button holder to the current frame"

bttn := self button:'extrude90.bmp' with: 'extrude90Invert.bmp'.
bttn objectName:#extrude90.
extrudeButtons addChild: bttn.

bttn := self button:'extrudePoint.bmp' with: 'extrudePointInvert.bmp'.
bttn objectName:#extrudePoint.
extrudeButtons addChild: bttn.

bttn := self button:'extrudeRound.bmp' with: 'extrudeRoundInvert.bmp'.
bttn objectName:#extrudeRound.
extrudeButtons addChild: bttn.

bttn := self button:'extrudeCurve.bmp' with: 'extrudeCurveInvert.bmp'.
bttn objectName:#extrudeCurve.
extrudeButtons addChild: bttn.

extrudeButtons extent: buttonWidth@(buttonWidth*4).

This code will create a button holder that is four buttons tall and one wide. You can query which button is currently selected by sending:

bttn := extrudeButtons radioButton.

Here I have set the name of the button to be a token, so I actually use it this way:

extrude := extrudeButtons radioButton objectName.

This code has been posted as change set 0205RadioButtons.

Thursday, January 20, 2005

Picking Overlays

I just added the ability to pick through an overlay portal. You can try it out with the rear view mirror (ctrl-R to turn it on/off). I will generalize this after the C5 conference so that you will be able to manage multiple Croquet sessions in the same world. You can look at how to do this right now by examining the TOverlayRearView class, which is actually quite small.

Monday, January 17, 2005

Serious Play

I am reading a very interesting book called Serious Play by Michael Schrage, a research associate at the MIT Media Lab. It really defines the opportunity for Croquet inside of the corporation. It speaks to the idea of prototyping as the basis of a groups communicating and understanding and presents this as critical for innovation. More to come...

Saturday, January 15, 2005

Need for speed

There was a very bad bug in Jasmine which caused the performance of the system to degrade pretty rapidly whenever you were connected. This problem has been around for some time. I was worried that it might be something having to do with the basic architecture of the system, which could be a very bad thing. On Thursday, Andreas and I decided to figure out the problem and fix it.

We could literally watch the frames per second drop over time, especially when both users were wandering around. Interestingly, a full garbage collect would clean up the problem for a short time, then it would begin to get slower again. We performed a number of message tallies on the system and we found that the system was spending more and more time inside of the garbage collection. It would get so bad that we could see it spending as much as 60-70% of its time performing a GC.

Andreas said that there were only a few things that could cause this kind of behavior - in particular having a large tenured object that referenced new objects that were in the youg object space. We did a number of additional profiles of the GC to get a better handle on what was going on and then we started turning off parts of the system to see where it was happening. This helped somewhat, but we did not return to our previous, unconnected performance. Finally, I had narrowed down the location of the problem sufficiently that I decided to just look through the code to see if anything might pop up that could be the culprit. Sure enough, there was an object called "selectorHistogram" that was used to keep track of the number of messages recieved from the remote user that would be sent to particular TObject targets. Croquet was running, but I had commented out this code. I removed the comments and allowed it to execute through and what I found was that instead of keeping track of the number of TObject/message pairs, which typically would not grow very fast, it was adding a new item for every single message sent. This meant that this array was growing in an unbounded way and was exactly the kind of object that would cause the problems with the garbage collector that we were seeing.

The reason this started happening with Jasmine, and why we never saw it with Solar, was that Solar would convert a TeaName into a TObject as soon as a message was received. Due to problems in ordering (and other things) we determined that it would be best to convert only when we were about to execute the TeaMessage. What this meant is that instead of adding a TObject and a corresponding message to the histogram, where there was only one TeaObject, we were adding TeaNames, which were constantly being generated for each message send. This meant that the histogram was constantly adding new objects with none of them matching any of the previous ones. Hence, unbounded growth of the IdentityDictionary. We were able to just look at this array as the system was running and watch it grow.

We decided to remove it completely from the system (we had never really used it much anyway) and we began looking for other similar large objects that could cause problems. It turned out that we had another similar histogram used for the message/object pairs that were SENT. This meant that this array was growing on both ends - the message send and recieve. Once we removed this one as well, we found the connected performance of Croquet to be quite similar to the unconnected speed of the system.

This was not an exercise in tuning - I really needed a working version of Jasmine for demonstration purposes. Now it seems to be working pretty well.

Thursday, January 06, 2005

Picking Portals

What I decided to do was just stop the ray at the portal itself instead of having it bounce through. There were a number of reasons I decided to do it this way instead of having it bounce around through the portals.

First, it just looks better. The bouncing rays, especially in the mirror, were distracting. They were certainly cool looking, but I could tell pretty quickly that this would get old soon.

Second, it was just fine from the user's point of view. The way the laser works locally, the point of the laser pointer is at the location that the camera pointer intersects the portal, but this is also where the point of the target object lives. So it looks like - from the perspective of the owner of the pointer - he is picking the actual object.

Third, I realized that I would have to perform the equivalent of an inverse kinematic computation when the mouse was down. The reason for this was I knew where the pointer stars in space 1, and I know where it ends in space n, and doing the forward computation is actually how I determine the location of the initial end point. The problem is, I stop doing this forward test when the pointer button is down, given that I already have the selected object and it is up to IT to determine what location on the object is hot. Thus, we need to compute it backwards. Why is this hard? You need to keep track of all the portals you jumped through going forward, then you have to compute a line back through these portals using the inverse transforms of each - but you need to ensure that the result is a straight line in this multi-portal transition space. This is an exercise left for the reader. And remember, I won't use it anyway, because I didn't think it was very pretty.


Originally uploaded by Croqueteer.
I have been working on portals for the past many weeks in preparation of working on the task and filter portals system and the new Wicket CAD tool in particular. Here is an example of a portal literally seeing into itself recursively, which was one of the fixes I made. This was not a critical piece of code to get working, but it does demonstrate that the math is accurate, which is crucial if we want to build something more complex on top of this system.

Monday, January 03, 2005

Bouncing Lasers

Well, I did it. I got the laser to bounce through the portals properly, even the mirrors. Problem is, I don't like it at all. The reason is that it simply confusing to look at. If you have a laser beam hit a mirror, you will have four seperate laser segments - the two in the space you are in consisting of the laser from the avatar and the bounce in the mirror, and then the reflection of this. It just looks too busy to me. Perhaps I can tone it down a bit. Of course, if you have a mirror in a mirror, which was my test case, it get's really bad. But it does work - except for one thing. I only really need this when the pointer button is down and an object is selected and being manipulated. But this is precisely when I am not testing the pointer hit, presuming that I already have the object in hand that I am targeting. Further, the laser point will change, but only based on the actions of the user and the response of the target. That is, instead of the user determining the interaction, the target object does. This means that I really need to do an inverse of the steps I take to find the object in the first place. This is often impossible. For example, when the target point is moved outside of the scope of the portal. Besides, the math is at least as complex, and I don't have the energy to attack it. Given my unhappiness with how it looks, I am not even certain it is worth the effort.

Well, at least I got the math right. Now I can focus on aesthetics.