When compiling Smalltalk methods in the system interactively, i.e. accepting in a browser or doing a do-it in a Workspace, the compiler will use the InteractiveCompilerErrorHandler to warn you about any problems. There are a number of useful warnings that the InteractiveCompilerErrorHandler can tell you about. For example, a temporary variable that is declared and not referenced or a message is being sent that does not exist yet.
Sometimes, all of these helpful warnings simply get in the way.
I've published a package, InteractiveCompilerSettings, to the public repository that overrides the InteractiveCompilerErrorHandler in such a way that allows you to turn these warnings on and off. The settings will appear in the VisualWorks settings tool. The warnings that can be turned on and off are:
Never Read - A variable has been defined, assigned a value and that value is never used.
Never Used - A variable has been defined and is never used
Read before written -A variable has been defined, and before it is assigned a value a message is sent to it.
New Message - A message is being sent that does not exist in the system
Unknown Pragma - The method being compiled has a pragma that is not defined by the class
A couple of days ago, I received an email that got me thinking about popular music back from the late 80s and early 90s. I remembered watching a video for the song, Opposites Attract, on MTV. That is the video where Paula Abdul is dancing with MC Skat Kat while singing about taking two steps forward and two steps back. I'll use that song lyric as inspiration for this blog entry, and show you another step forward with the Doom port before I start blogging about the translation and implementation effort (the steps back).
I've done a few tweaks to get the rendering to be a little faster than the last screencast. One of the things slowing down the last screencast was the conversion of a Depth8Image (Doom has a small palette) to a Depth32Image for displaying. Dave Wallen made some suggestions that improved this specific conversion from one palette to another one. Another fairly big slowdown can only be blamed on me being dope, which I will explain at a later time, because frankly it is embarassing.
I still have the same fixed lighting (it does not get darker as you look into the distance) issue. However, I've added the message displaying ("Picked up a clip") and added the part where the palette shifts when you pick something up or are attacked. Because this is the second screencast of the port, I've decided to show the second demo (demo2) in the ultimate doom.wad file. This screencast is on a window rendering the 320x200 bitmap. It is a little long (nearly two minutes and half minutes) and a little violent. If you don't like seeing imps being berserkedpunched, then you might want to skip this one.
Click through the DOOM title picture above to see a screencast of the port as it plays the second demo in the Ultimate DoomWAD file.
Last weekend my brother was giving me some grief about not blogging enough. Hopefully this one will keep me on his iGoogle front page a little while longer. After all, if I can't keep my family readership numbers up then what is the point of blogging?
To pick up where I left off, I was put into a position where I felt I could not publish the Elite code because of what looked like copyright issues. So, a little more than a year ago, I was forced to find something else to port. It did not take me very long to decide it had to be DOOM. After all, DOOM has been ported to all sorts of things, including the iPod. I'm sure it will be on the iPhone soon. However, I don't believe anyone has ported it to VisualWorks (or Smalltalk). Perhaps I'm wrong.
I think instead of writing some rambling blog entries about what I did to get the port going, which eventually lead to the lamest screencast you've ever seen. I will start at the end and end at the start and show you my current work in progress.
Click through the DOOM title picture above to see a screencast of the port as it plays the first demo in the Ultimate DoomWAD file.
I find myself often needing to compare two different methods in two different class hierarchies. I mostly have the desire to do this when using the ChangeList and am viewing changes. For a while, I've had a little hack in my private database that gives me this feature in the ChangeList. Back in May I cleaned it up a bit and published it to the public repository. I'll have to thank Eliot for the suggestion of enumerating the system with #allBehaviorsDo:, instead of using #allInstances on CompiliedMethod. Also, thanks to Vassili for writing the Tool-Modules framework which makes it easier to add these sorts of things. You have no idea how delighted I was when I found the #extent: method to change the opening size of the window.
This package, CompareDifferentMethods, extends the ChangeList, the Browser and the Store comparison browser so that you can compare a selected method with any other method in the system (a new menu item called "Differator this with..."). Admittedly, this is a little limited and painful to use. However, it can sometimes be useful when methods that exist in different hierarchies.
The package extends the IncrementalSearchDialog and IncrementalSearchDialog to allow for incremental searching on all methods in the system. For example the following do-it will open up a method browser on a selected method (if any):
(IncrementalSearchDialogrequestSpecificSelector:'Specify specific selector:'initialEntry:'send*th')ifNotNil:[:md |
MethodCollectornewopenListBrowserOn:(Arraywith:md)label:'Method Browser']
It dawned on me the other day, I'd like the behavior of clicking in URLs in the browser without having to load the development stream of the Tools-RefactoringBrowser bundle. It would also be nice to have the feature on the published items tool and Workspace. So, I've published the ExternalWebBrowser-ToolOverrides package to the Cincom public repository which by overriding three methods adds this functionality.
Back in November of 2005, I was chatting with Vassili and the topic of games (as usual) came up. I mentioned to him that I had starting porting Elite the New Kind to VisualWorks, but it was broken because of a broken laptop. He seemed interested, so I decided to dig up the work around and show him.
Quite some time had passed since I last looked at the code. One thing became immediately clear, I could not easily tell which functions I had finished porting. It was obvious if a function was not ported at all, because there was no corresponding method. However, for methods that had code that looked like the C function, it was not clear if the translation bugs were fixed yet. I found myself wanting a way to compare the method source with the corresponding source in the C source file.
Finally, it occurred to me that if could annotate a method with a pragma that described the location of the original C function (which C file and where in the file), I could then use the Differator to compare the Smalltalk with the original C source. Using a pragma was a huge leap for me. I had been aware for pragmas as long as they had been in VisualWorks. However, for some reason (probably one reason: I'm a dope), I never found the need to create my own.
I re-parented all my Elite classes under a new superclass, which I called CFileThing. On the class side, I created the following method:
Then it is a trivial exercise to use the Differator to compare the two implementations side by side. Here's how one method comparison looks in the differator:
With a little more work, it was not too hard to integrate this behavior into a new subclass of the CodeCompareTool:
Before I knew it, I was in position where I could publish a work in progress to the public repository. However, it was also the same time I noticed the copyright problemsChristian Pinder was having with having released Elite the new Kind. The wikipedia entry on Elite claims: "The dispute has since been settled and Elite: The New Kind can be downloaded once more". However, I can't find a reference confirming this. So, I'm reluctant to publish to the public repository.
In the meantime, I have a screencast showing the port in VisualWorks. Here you'll see me leave the space station, show the different views, turn around and dock back in the station. The docking was courtesy of the docking computer which I added so I would not have to buy it first.
After the Java Asteroids experience, I was eager to try to port something else. Around this time I had stumbled across Elite the New Kind, by Christan Pinder. This was a reverse engineering of the classic space trading game Elite, by Ian Bell and David Braben. I used to play this game for hours on my Commodore 64 and I still remember being amazed at the real-time 3D wireframe display. Converting Elite the New Kind had to be experiment number two. I already had a plan for the first change I would make to the game: give myself the auto docking computer.
Elite the New Kind was written in C. For this blog entry, I ran SLOCCount over the source and it told me that it had 11,051 lines of code all contained in 21 .c files and 25 .h files. The game was using the Allegro game programming library for graphics and sound.
I decided to take a similar approach I took with Java Asteroids. I'd create a class for each C source file and a class for each structure used in the C Source. Classes that came from C Structures would simply have instance variables for each member in the structure, and all these instance variables had getters and setters. Functions would end up as similar named methods, with an initial body being the C source code in a Smalltalk comment. My plan was to do the same manual translation along with copy, paste, search and replace.
As an example, here is the original C source for finishing rendering the polylines that have been queued up in C:
if (total_polys == 0)
return;
for (i = start_poly; i != -1; i = poly_chain[i].next)
{
num_points = poly_chain[i].no_points;
pl = poly_chain[i].point_list;
col = poly_chain[i].face_colour;
if (num_points == 2)
{
gfx_draw_colour_line (pl[0], pl[1], pl[2], pl[3], col);
continue;
}
gfx_polygon (num_points, pl, col);
};
Remarkably, for being such tedious way to convert the C code to Smalltalk, I felt I made pretty good progress. At some point, I managed get the Cobra MK III to display at the beginning of the game just like the original. Once I reached this point, I felt the urge to refactor.
A few days later, I had a small failure lap-top failure. Nothing too serious, I didn't loose everything. Just enough to not show you the results. I hadn't published to my local database for quite some time and the changes file was truncated in a poor place. Fortunately, the story with this conversion doesn't end there. However, I'll save that for the next blog entry.
Update: I was playing around with Camtasia Studio and used that to create a embedded flash animation to replace the compressed AVI file below.
Micheal Lucas-Smith commented in a previous blog post that now would a good time to refactor. I agree with him. Once the game was completely ported and running it is a great time to refactor. So, if anyone wants to refactor it, you can find it in your contributed directory in your VisualWorks installation.
I have never done any refactoring on it, mostly because a few other things caught my interest after the port to VisualWorks. I've always thought that the goody would make a good example of live-refactoring with the game running. As an example of that here are a sequence of steps that you can follow that will refactor out the bit in Asteroids>>#paint: that paints the asteroid into the Asteroid class as its own paint method.
Start up VisualWorks and Load Steroids. You can find it in the parcel manager.
Once it is loaded you can open it by clicking on one of the Play Throtted Asteroids toolbar button on the launcher or do:
Steroids.ThrottledAsteroidsAppModel open
in a workspace.
Play the game for a while! Once you are done, leave Steroids running so that you can see the asteroids moving around
Open up a browser on the class Steroids.Asteroids and select the method #paint:
Scroll down to where the asteroids are drawn, here is the code:
"Draw the asteroids."1to:MAX_ROCKSdo:[:i| | asteroid |
(asteroid:=asteroidsat:i)activeifTrue:[detailifTrue:[gcpaint:ColorValueblack.
gcdisplayPolygon:asteroidspritepoints].
gcpaint:ColorValuewhite.
gcdisplayPolyline:(asteroid:=asteroidsat:i)spritepoints]].
Edit the method to change the last line in the #ifTrue: block argument to be:
Select asteroid as the variable to move the method into
Select Steroids.AsteroidsSprite in the next dialog
For the next dialog, supply a name to replace self, I use game
You'll be asked to create getters and setters for direct variable references, answer yes to the dialog
You'll be told that the method contains references to variables which are inaccessible in the namespace of the destination. Answer yes
You'll be asked how to handle references to ColorValue, select "Specific Import"
You'll be asked to supply a the new method name (a default is provided), type something like: #displayOn:game: then click OK
You're watching the game right? If you missed it, then just undo the changes by clicking on "undo the last action" in the tool bar twice (once for the method to component refactoring, the other for the first change we did above). Then click redo the last action toolbar button and watch the method and game change.
There are two interesting things being shown here. First, the only bit of actually typing of Smalltalk code was replacing (asteroids at: i) with asteroid. Writing the new method with what was selected from step seven above, putting it into a different class and fixing up the original method was all taken care of by the refactoring engine that the browser uses. The second interesting thing is the game was still running while the changes were being made.