|
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.
|