GNUGoS60 is a port of the FSF's GNU Go game engine to Nokia's S60 smartphone platform running on SymbianOS.

It is Free Software.

Friday, September 22, 2006

ECompXL: Epoc Compressed Executable Loader

I found this interesting project ECompXL, yesterday. It's basically a replacement loader for your Symbian application. What's interesting from my point of view is that it also adds support for global data. From the text:

Support for global data and global C++ objects in applications

Symbian OS executables (.exes) already have full support for global modifiable data and global C++ objects, and ECompXL allows you to have them in your applications (.apps) as well. If you have built your application as described in the previous section, support for global modifiable data in your application comes for free.
This is cool if it works as advertised. I'll have to give it a try out.

Wednesday, September 20, 2006

Application Icons in S60 v2.0

I created icons for the S60 v2.0 version now also. These are just bitmaps and masks for them. I ended up using GIMP to downscale the icons from the one on the gnugo website. MS Paint and MS Photo Editor seen to just do nearest neighbour or something similar algorithm when downscaling images. This results are pretty poor quality. GIMP at least supports some sort of interpolation which gives a reasonable quality (as much as can be expected in 44x44 bitmap).
Making a mask was a pain though. There didn't seem to be any automatic way to do it, so I ended up doing by hand using the icon as the starting point. I am presuming that there is some automated way to do it somewhere out there. Otherwise it would be a huge waste of people's time. The SVG system in S60 v3.0 is far superior.

Anyway, now it's done, at least I don't have to do again!

Tuesday, September 19, 2006

GnuGoS60 Sourceforge.net Project Page

I have created a sourceforge.net project for hosting the gnugos60 code.
Alternatively here are the plain URLs:
I haven't uploaded anything except screenshots yet though. I need to install CVS or SVN on my PC. (I use Perforce up to now). Then I need to figure out how to use them...

Sunday, September 17, 2006

GNU Go for S60 v2.0

Finally got the S60 second edition to stop crashing enough to draw the board. Maaaan that was hard work! Basically I have been working on it for the whole weekend trying to get it to compile once all the global variables I could spot have been stripped out and moved to a dynamic structure stored in Tls().

Really, whoever decided that not supporting global variables was a good idea needs a right good sla^H^H^H *ahem* ... talking to. It is positively the worst OS misfeature I have ever come across. Using Tls() is not even a good solution because there is no migration path to speak of. Basically you have to:

  • go through the code and look for a writable variable (the compiler only accurately warns about some tiny minority of them, so keep your eyes peeled)
  • move the declaration to one place
  • mov the initialization to a different place that doesn't support the previous type of initialization
  • make the runtime inialization work
  • define a macro for the old variable name
  • add the macro to however many dozen files need it
  • workaround any issues in the code that conflict with the macro
Congratulations! You have now migrated one writable static variable to SymbianOS. Now repeat a few hundred times. And if you missed any of them be prepared for this message and some long hours with the debugger:

Friday, September 15, 2006

It's Alive! (briefly :)

It Lives! It Lives Still! Game On! Oops!

Exciting stuff. Got enough of the GNU Go back end linked with the GUI so that I can display the actual GNU Go board rather than an dummy one, and rather than just me toggling black and white stones on, the GNU Go AI responds to my moves, and makes it's own moves. (And then crashes :)

Anyway, the important point is that all the white stones on the board shown were not put there by me. They were put there by GNU Go. It's a big step forward.

Well, things are looking up. Can't be too far from playing a full game vs gnugo on the S60 emulator, once I get all the crashing sorted out.

Tuesday, September 12, 2006

Memory Limits

In the 3rd edition port (the one that compiles :), I am starting to link the gui and the gnugo engine together at the moment. I ran into a memory problem pretty soon once I had got all my zero pointer dereferencing errors out of the way. The default max heap size is too small for GNU Go. "epocheapsize min max" to the rescue.

I am not really sure how much memory GNU Go needs to be able to run well. It tries to allocate 14 MB for some cache initally. I reduced that down to 2MB with no obvious ill effect in the startup, though maybe it will complain loudly at a later point. I may have to add some more intelligent code to that to allocate different sizes depending on what's available. Allocating 14MB out of the box on all S60 devices is obviously not so feasable :)

Writable static data in SymbianOS

One thing that the S60 3.0 SDK brings is the ability to have (partial support for) writable static data (global variables). Symbian, never ones to implement what they can push onto the 3rd party devs, finally got around to supporting what they should have had in from the beginning. Bit of a shame about all the millions of devices already sold that don't support it though, isn't it?

While it's addition means that porting software to S60 3 series devices is much easier than before, for anyone who considers the 2nd edition a viable platform, is still in for a hard time when porting any "traditional" software to SymbianOS.

Once I finish implementing the workaround for the S60 2nd edition port will be up to the same level pretty much as the 3rd edition version. Unfortunately, gnugo has of the order of 300 global variables, scattered throughout many files. Moving them all to a datastructure that I can access with Tls() has not been a fun experience let me tell you. (you'll notice the picture on the left only goes as far as the beginning of the letter "c". That's all that fits on my PC screen).

Saturday, September 09, 2006

Multiple Resolutions

S60 now supports lots of resolutions as you may be aware. It's easy to test these out in the emulator. For example here is the board in Double Resoluton Landscape mode , and below is the the old standard S60 resolution.

I had been worried about getting this working because of all the problems I have seen in applications handling this incorrectly, but turns out it's extermely simple to do (for a change), at least with the limited UI I have at the moment. Pretty much just implement the HandleResourceChange method in your view, and any controls that need to care about it. For gnugo so far it turns out that only the main view needs to handle it to reposition the board control, and any others I may add. The board itself gets away with just handling size change events.
void CgnugoAppView::HandleResourceChange( TInt aType )
// Call the baseclass handler
CCoeControl::HandleResourceChange( aType );

if ( aType==KEikDynamicLayoutVariantSwitch )
// If it's a layout switch, then recalculate the positions of the
// controls. In this case, only the go board control.
TRect rect = Rect ();

if (rect.Width () > rect.Height ()) {
rect.SetWidth (rect.Height ());
} else {
rect.SetHeight (rect.Width ());
if (iBoardControl) iBoardControl->SetRect (rect);

// call the (default) handler in the control.
if (iBoardControl) iBoardControl->HandleResourceChange (aType);
I found that as I was experimenting with various things that it was better if the main view also implemented both of the PositionChanged and SizeChanged methods.
void CgnugoAppView::PositionChanged( )
// call the baseclass handler
CCoeControl::PositionChanged ();

TPoint position = Position ();

// call the sub control handler
if (iBoardControl) iBoardControl->SetPosition (position);
The Position Changed one is not really needed so much, but better to implement it now, than start worndering why something doesn't work in the future.
void CgnugoAppView::SizeChanged( )
// call the baseclass handler
CCoeControl::SizeChanged ();

TSize size = Size ();

if (size.iWidth > size.iHeight) {
size.iWidth = size.iHeight;
} else {
size.iHeight = size.iWidth;
// call the sub control handler
if (iBoardControl) iBoardControl->SetSize (size);
The SizeChanged one is needed, since the layout change affects directly to the size of the sub controls.

This gives me a nice resolution and layout independant GUI, at least on S60 3rd edition devices. I think I may have to revisit it again for the 2nd edition port.

The Go Board

Here is the Go board. How do you like it? I think it's pretty much what I want, with the exception of the cursor for selecting your position. I'll have to work on the design of that a bit.

Porting GNU Go is pretty much my first GUI application coding in S60 or Symbian. Mostly I have been doing at lower level code. What GUI experience I have is all in Win32 and the X Window System.

To begin with I started out doing the board as part of the main view, and while this worked, I knew that would be better to create a new widget to handle specialized tasks like drawing the Go board. It simplifies the drawing calculations & key event handling if nothing else.

This is pretty easy in Symbian as it turns out, just create your class like this:

class CBoardControl : public CCoeControl
static CBoardControl* NewL(const CCoeControl &aContainer, const TRect &aRect);
static CBoardControl* NewLC(const CCoeControl &aContainer, const TRect &aRect);

// Handle drawing of the control
void Draw(const TRect& aRect) const;


// Handle changing the size of the control.
// Particularly needed to handle redrawing after the screen mode changes.
virtual void SizeChanged();

void ConstructL(const CCoeControl &aContainer, const TRect &aRect);
The SizeChanged is needed for recalculating things when the layout changes. Everything else is standard Symbian boilerplate, and the only interesting stuff is done in the Draw function.

One thing I found is that your drawing coordinates are not re-origined for your control, and also not limited to the size that was specified for it. They are all still relative to the parent control. This makes calculations difficult, and makes it easy to inadvertently draw outside your control's area (as i was found I was doing in the first few revisions of my the control code). There is an easy solution to this however. I added the following to the start of the Draw function, and things are as I want it:
void CBoardControl::Draw(const TRect& /* aRect */) const
// Get the standard graphics context
CWindowGc& gc = SystemGc();

// make sure we don't draw outside of control's own area
gc.SetClippingRect (Rect ());

// put the origin at the top left of the control's area
gc.SetOrigin (Rect().iTl);

// TODO: your drawing code here
// ...
Another annoying thing about drawing in Symbian is the way that it doesn't draw the last pixel of what you specify. Is there a way around that? It sure makes life difficult having to add one pixel to sometimes X coordinate, sometimes Y coordinate, and sometimes both.

There are a lot of things that I need to change in the control though. At the moment those handicap spots are just hardcoded in place, and so is the 19x19 layout. I need to make it accept the range of board sizes that GNU Go supports, and to read the positions of the handicap spots from the engine. At the moment the GUI is not even linked against the GNU Go codebase, so I'm some way away from getting that in place.

One thing I discovered when I read the Wikipedia entry on Go was that the board is not square, but in 15:14 aspect ratio. Don't know if I'll implement that ever. It's debatable if it would be noticeable on the larger S60 screens, never mind the smaller (previously standard) ones.

Anyway, I am quite happy with the board control now. It is coming along nicely. I think it ought to be more or less reusable if I ever decide to port GNU Chess :)

Well, still lots to do for GNU Go first...

Friday, September 08, 2006

Application Icons

As mentioned previously, I'm going to add a gui to gnugo, the textshell being an inappropriate way to interface on a mobile phone.

That means putting it in the applicaiton shell, and that means having an icon. Luckily for me, and my mediocre artistic skills, GNU Go already has one.

Here is GNU Go in the applicaiton menu. The icons in S60 3.0 is an SVG. GNU Go doesn't actually have such an SVG in it's package, so I was wondering what to do. Perhaps just create a dummy icon in Inkscape? No good, Inkscape doesn't seem to be able to generate the SVGT needed by the S60 mifconv.exe tool, and even if you somehow make one that is parsable, it looks bad. If you can see it at all that is.

What I should do, of course, is run it through the SVG to SVGT converter that ships with the SDK. Well, that's what I would do, if I could install the damn thing, but it flat out refuses to install. It keeps insisting that I have the wrong version of Java installed, no matter how many JRE's I install or uninstall. I spent many hours trying to get that to work all to no avail. I chickened out at manually going and deleting every reference to Java in the registry, so the converter remains uninstalled. "Write once, run anywhere" indeed.

Luckily all is not lost, as you can tell from the nice SVG displayed in the picture. Turns out there is a pretty nice application called potrace that takes a bitmap as input and then does a kind of freehand drawing of what it sees, and outputs the result to the vector format of your choice. The SVG it generates seems to work fine with mifconv.exe. So, I feed in the existing GNU Go logo bitmap, potrace outputs a nice SVG of it. Problem solved.

The resulting SVG looks quite nice in my opinion. It's not exactly the same, since the input is a fairly low resolution bitmap, but the smooth SVG is none the worse for the minor differences in my opinion.

Anyway, this icon thing was pretty much the first thing I did once I had got the GUI past the "Hello Cruel Symbian World" stage. I always think it's a shame when you install some application and it puts that default jigsaw piece icon there. It spoils the "total user experience" :-)

Thursday, September 07, 2006

Stderr in S60

One thing that I noticed in the S60 3.0 port (the only one that runs anyhow at all so far) is the output to stderr. GNU Go seems to have several places (not in the interface code) where it prints out warning or error messages to stderr.

This has the unfortunate effect of opening up a console window like the one shown on top of the GUI. You can swich back using the app switcher, but it's annoying, and obviously can't be like that in the final version.

For the moment I am just going to #ifdef out the offending sections, but it seems like an inelegant solution. I wonder if there is a better way. Perhaps something like closing stderr will work, though I suppose it depends on where the console is automagically initiated.

Getting Started

First things first, how to build gnugo for S60? Well, GNU Go is divided into 5 dlls, so I'll follow that structure. The existing structure is like this:

+- interface/ (.EXE)
+- engine/ (.DLL)
+- patterns/ (.DLL)
+- sgf/ (.DLL)
+- utils/ (.DLL)

Firstly I want to keep everything related to the S60 port out of the main gnugo directory structure unless it's unavoidable (e.g. code changes). So, "mkdir S60" it is.

I will swap out the text interface, and replace with a GUI. However, it may be that need to keep some the code in the interface around because there is not a very clear seperation between purely presentation code and functional code in the interface aera. Anyway, that will go to a DLL.

Each of those folders also contains .DSP project files for Microsoft Visual C++, and I'll use those as the basis for my .MMP files. Since I intend to add a GUI, I'll need to add a folder for that, and also some place for the traditional Symbian build structure. Here is how I'm going to lay out the project:
+- S60/
+- group/ (.INF, .MMP)
+- gui/ (.APP, .EXE)
+- engine/ (.DLL)
+- interface/ (.DLL)
+- patterns/ (.DLL)
+- sgf/ (.DLL)
+- utils/ (.DLL)

For the moment I am going to steer clear of using any IDE. I may use Visual C++ to help identify the code structure, but mostly I'll stick to gvim and the dos command prompt.

So, with that in place, all that's left is to "bldmake bldfiles" and "abld build", and watch the compile errors flow by...