2007-04-14

Porting the Code - First Steps

Started work on porting the code across. As previously mentioned, this is rendered more difficult than it should be by the lack of comments or useful variable/function names. Here’s a snippet of code I ported across today:

NEWTYPE.glow
;
c.q[3]
;
a.q
cn.q
;
End NEWTYPE

So what’s that do, then? What’s a.q do? How about cn.q? You have to dig a lot deeper to work out what it all means (I’m commenting the Blitz code as I go along). This is the main bit of code that works in tandem with the snippet above:

hueadd
USEPATH g(g)
;
cn2=\cn
c2=\c[cn2]+\a:\c[cn2]=c2
;
If c2>=15 OR c2<=3
  If \a>0
    \cn=QWrap(cn2-1,0,3)
  Else
    \cn=QWrap(cn2+2,0,3)
  EndIf
  \a=-\a
EndIf
Return

What this code actually does is perform a palette cycle on an individual palette index. The first chunk of code (the “NEWTYPE”) works in basically the same way as a struct in C. It contains an array of 3 colour components (“c.q”, where “c” stands for “colour” and “q” is the variable type “quick”, or “byte”); the elements in the array represent the red, green and blue components of the colour. “a.q” is a single byte to add to the component each time the subroutine is called, so that basically works as the speed of the cycle. “cn.q” stands for “colour number”, or something similar, and refers to the component that we’re working with at the moment.

The subroutine “hueadd” performs the palette cycle. The “USEPATH” command is equivalent to the VB.NET “With” statement - it just saves typing “g(g)” on every line. Anything starting with a backslash, such as “\cn”, refers to a property of the struct we’re dealing with. The code does this:

  • Get the current component;
  • Increase the component by the cycle speed (“a.q”);
  • Check if we’ve exceeded the bounds of the value of this component (work on the assumption that the OCS Amiga has a range of 16 values in each RGB component, and we don’t want to go to a value that’s too dark to see);
  • If so, check if we’re currently increasing or decreasing the component;
  • If we’re increasing, move to the previous component (or wrap around if necessary);
  • If we’re decreasing, move to the component two slots after this one (or wrap);
  • Switch from increasing to decreasing, or vice-versa.

The second to last step in this function (move two component slots after the current) makes no sense. I’m not entirely sure how the palette fades in Defender can work with this in place, because the logic is broken. Stripping this step out does not in any way mar the cycling effect.

The upshot of all of this is that the red component will increase, then the blue component will decrease; then the green component will increase, and the red component will decrease; etc. It produces a palette cycle effect that runs through the majority of the colours that the Amiga can produce.

I’ve ported this code to C++, into another class (“CyclingPalette”), and tidied up the weirdness. I had to work around the fact that the original routine relies on fractional values - to slow the speed of the fade, “a.q” could be set to a value between 0 and 1. I’ve emulated this by multiplying the RGB values inside the class by 10, then dividing by 10 before exposing them outside of the class or processing them. Much faster than trying to use floats.

The second thing I’ve ported over today is the background mountain generation code. The original Blitz code loaded a binary file and used each char as the Y position of a pixel on the mountain range. The mountains are 2048 pixels wide, and the original coders simply created a bitmap that size and drew the mountain to it. I’ve pinched that binary file and included it in my C++ project, and I’ve duplicated their mountain generation code. Currently, the program re-draws the mountain every frame; I’m sure there’s a more optimal way of doing this.

I also duplicated the code for drawing the small representation of the mountains used in the scanner - it does some neat bitshifting to reduce the size of the image by 8 times (the original reduces it by 16 times, but I’ve got an extra screen to play with).

The Blitz bitshifting caused some problems - consider this code:

32 LSL 2+1

The “LSL” command is an m68k assembly instruction meaning “Logical Shift Left”. On first glance, it would seem to translate to C++ like this:

32 &lt;&lt; (2 + 1)

However, for some reason the Blitz coders decided that LSL wasn’t going to work like that. What it actually does is this:

(32 &lt;&lt; 2) + 1

Bonkers.

Anyway, got a few things done today - palette cycling, the mountain range, the start of the scanner code, and I’ve even got scrolling working.