POST MORTEM: Links Championship Edition and Links Course Designer

Links Championship Edition and the Links Course Designer have just gone off to duplication. This is probably the only line of this text that most people will want to read, but if you'd like a better insight into this project and the problems we had to overcome along the way, please read on.

This project began towards the start of 2001 and finally finished during the summer of 2002. This was the most difficult conversion we have ever worked on. Our initial plan was to build Links with Carbon so that it would run native on both MacOS 8/9 and MacOS X. Once the Links code was compiling and the core code was working we would then start work on the Course Designer using Carbon as well.

Our first problem was that one of the programmers who had worked on previous versions of Links was not available for this project. Since Mac programmers are rare (and good Mac programmers are even more rare) it took us a couple of months to find someone we felt could help us with this project. The new programmer came up to speed quickly and his knowledge of OpenGL helped get the rendering up and running.

 

The Original Code

As with any conversion that we do, we always try to modify the original code as little as possible and make our changes in our own files. We write code using the routine names which the original code is already calling and link them in. Leaving the original code alone as much as possible also minimizes the chances that we will introduce a bug into the original code.

This was especially important on this project because the original code was not yet finished when we began working on the conversion and we wanted to be able to get updates of the original code and merge them back into our conversion.

Links LS 98 and Links LS 2000 were already mature code bases when we started working on those projects. The Links Championship Edition code base used both a new rendering engine (using Direct3D) as well as a whole new program architecture. It was nearly an entire rewrite. As a code base matures, more programmers look at it, different compilers are used to build it, and it is made to support more hardware, different OS versions, and new platforms. As all of this happens, bugs are found and fixed.

Since we were using a new compiler and converting Links Championship Edition to work on new platforms (MacOS 8/9 and MacOS X) we ran into many problems with the original code. While some of this is normal when doing a conversion, the fact that the code was much younger meant that there were more of these kinds of problems.

 

OpenGL

We had worked with OpenGL on previous projects, but the Links projects were far more complex than any of our previous uses of OpenGL and we had some new things to learn. This was also our first conversion of anything which used Direct3D and although there is a significant amount of documentation on the web, there were many things which we had to learn on our own or determine through trial and error.

We got past the smaller problems like the fact that Direct3D uses a left handed coordinate system and OpenGL uses a right handed coordinate system and the fact that OpenGL uses a 0,0 coordinate which is at the bottom left corner of the screen.

There were also larger differences which were more subtle that we had to track down. There are some operations which need to be performed in a different order in OpenGL than in Direct3D. In Direct3D a texture map can be set and it uses the current settings for things like the way the texture wraps and the texture filtering. In OpenGL, the texture map must be set first and then the wrapping and filtering must be applied. Before we solved this problem, things looked almost right as each texture used the next textures settings because the original code made the calls in the order that worked for Direct3D. Fixing this one problem made the graphics look a whole lot better.

Links also uses OpenGL in ways which many other games do not. Most games which use OpenGL are designed to render the entire scene in real time. The scenes in Links are far too complex to be rendering in real time. The Links code would render the scene and then display dialog boxes and menus over the scene. When the dialogs and menus were dismissed, the contents of the scene would need to be destroyed.

In order to make this work fast enough for good user response, the scene could not be rendered again, so the Links code uses a dirty rectangle system which can save areas of the scene and restore them later. While this is a normal graphics process, it is not something normally done with OpenGL. We chose to use glReadPixels and glDrawPixels to make this work. There were other ways to do this, but this was the only one which would allow us to save and restore both the pixel data and the depth buffer data.

Since we used glReadPixels and glDrawPixels more than most other OpenGL applications, we ran into several problems. Before I go into detail I'd like to thank the people at ATI and Apple who helped us with some of these issues. The people at ATI sent us many test versions of their drivers so we could make sure that everything worked correctly.

The first thing we ran into was a problem with older ATI video cards (using older drivers) which didn't correctly support the GL_UNPACK_ROW_LENGTH setting when using glDrawPixels to copy pixel data and depth buffer data back to the screen. We found a quick way to work around this problem in our code and then ATI fixed this problem with a new driver release.

We ran into several other problems (mostly relating to the depth buffer) which took longer to sort out, but once the problem was narrowed down, ATI was always quick to suggest a fix in our code or supply us with a driver which had the problem resolved.

There is a problem on MacOS 8/9 which we ran into and at least one of our testers ran into which was never resolved to our satisfaction. This only happens with NVidia 2 MX cards and may only happen with early cards of that type. It appears that every time an OpenGL application is run, the system gets slower. Sometimes it is just a slight slowdown and was only noticed when we were doing performance analysis. Other times, things would slow to a crawl. It could take minutes to render something which had been taking only 5 to 10 seconds. Our only solution to this was to restart the machine. This already clears the problem up.

Tuning the performance for both MacOS 8/9 and MacOS X was a challenge. Things which worked great on MacOS X, made the MacOS 8/9 version slower. Things which made the MacOS 8/9 perform great. didn't work well on MacOS X.

We had a great deal of testing help from those who are members of the Links Golf Community (http://www.linksgolfcommunity.com/). While we had a variety of different machines and OS versions to test on, those in the Links Golf Community provided a far wider set of hardware to test on. They also have far more knowledge of golf than we have.

This helped us narrow problems down to certain video cards and/or certain versions of MacOS. This made it much easier to tell if the problem was in our code or in one of the many video drivers. And, since these are the people who love the game, they were able to tell us where it was too slow and where it was performing well.

We could not have gotten the project finished without their help and I am glad that they will now have a chance to play courses other than one that they did all of their testing with.

 

NetSprocket

We chose to convert the DirectPlay calls in the application to use NetSprocket for the Mac version. This was mostly painless and went well. The latest version of NetSprocket is built on top of OpenPlay so all of the source was available for us to modify as we found places where DirectPlay and NetSprocket had different architectures. Sometimes it was easier to make a change to our version of NetSprocket than it was to make a change to the application's network architecture.

As we were about to ship the final CDs, we found a network bug which took days to track down. It turned out to be a data loss problem in the original code which was easy to fix once we found it.

 

MacOS

Carbon was being worked on heavily by Apple when we started this project. This meant that things were always changing. Like most developers, we watch the various Apple mailing lists to see what issues other developers are having so we know what to expect.

But the truth is that while Carbon is amazing in that it allows the same application to work on two very different platforms (MacOS 8/9 and MacOS X), it is not complete. There are things missing which we had become used to using over the years and there were new things which only worked on MacOS X. This means that we had to find a way to use one code path for MacOS X and then write our own code to handle those cases on MacOS 8/9. This added to both the development time and to the testing and debugging time.

Doing a conversion to MacOS 8/9 and to MacOS X was like doing two conversions at the same time.

The change in how Apple is releasing OS versions has also changed how we had to do testing at our end. MacOS 9 was usually only updated once or twice a year while MacOS X had 5 updates during the time we were developing Links. Each one had new features and many bug fixes. Some of the releases included new video drivers as well which forced us to go back to re-test and in some cases, re-implement some of our OpenGL code to make sure Links worked on all versions of MacOS X.

 

Links Course Designer

Although the Course Designer shared some code with the game, it turned out to share less than we originally thought. Some base classes were shared but subclassed differently for each application. The functional code was in the subclasses and used different parts of DirectX in each application.

Once we got the first part of the rendering up and running we determined that the rendering path of the course designer code used things we had yet to implement in our version of DirectX because the game hadn't needed those things.

We got rendering to work and started working on the functional aspects of the course designer until we realized that our rendering solution would not work on OS X. In MacOS 9 it is possible to draw 2d shapes using quickdraw on top of the area of the screen which OpenGL is drawing to. In OS X, it simply didn't work. None of the 2d drawing would show up because OpenGL "owned" that part of the screen and would not let anything else touch those pixels.

This was important because in DirectX, 2d and 3d drawing can draw into the same context and be mixed without penalty. This was not to be the case with OS X. We ended up re-writing our low end rendering to use off screen drawing areas for the OpenGL (thereby losing hardware acceleration) and using quickdraw to composite the offscreen drawing area with the OpenGL content with the 2d content.

MacOS X once again forced us to spend more time in an area of the code we didn't expect to have to worry about. Many User Interface items take up more space on OS X and since we did most of our work laying everything out in OS 9, we had to go back and get things to be the right size in OS X. There are even things which we could not get to look the same. The main tabs are centered in OS X and left justified in OS 9.

We also had to implement our own version of the Microsoft Foundation Classes (MFC) because the course designer code was built on top of it. The functional part of this code was straightforward and we built it on top of PowerPlant, but the numerous macros and dispatch system took some time to figure out.