Notes on the Gloom source - Swizpig/ZGloom GitHub Wiki
Maths
Gloom makes heavy use of 16.16 fixed-point maths (old Amiga Blitz Basic users will recognise this as the "Quick" data type). But going through the code caused my to scratch my head on occasion - sometimes some fields seemed to being used as an integer, and sometimes as a Quick. For instance, there's a "frame" field that holds the animation frame of objects.
ob_frame rs.l 1 ;anim frame
ob_framespeed rs.l 1 ;anim frame
Framespeed is added onto frame to animate things as you'd expect:
move.l ob_framespeed(a5),d0
add.l d0,ob_frame(a5)
And is clearly a Quick if you look at how it's been set up for the objects:
.ob_framespeed dc.l $7000
.ob_framespeed dc.l $08000
.ob_framespeed dc.l $08000
.ob_framespeed dc.l $08000
.ob_framespeed dc.l $08000
.ob_framespeed dc.l $08000
...
But sometimes frame
would be set up directly, and looked like an integer:
move #1,ob_frame(a5)
move.l #$2000,ob_framespeed(a5)
The answer is the difference between move
and move.l
. 68K has 32bit .l, 16bit .w, and 8bit .b operations. The assembler used assumes anything without an explicit type is .w. By doing 16bit .w operation on Quick types in memory, the integer part of a Quick can be directly manipulated.
The integer part is used because 68K is big-endian. Note a .w move from a register, rather than memory, would get the fractional part. This is used less often, but does have its place:
mulu.l #92681,d4:d3 ;mult by sqr(2)
move d4,d3
swap d3
This is multiplying 2 16.16 Quicks together to get a 32.32 fixed point value in the d4:d3 register pair (a 68020+ instruction, incidentally). To quickly turn this back into a 16.16 Quick, a 16bit word move is done from the LSBs of d4 into the LSBs of d3. This leaves d3 with the least significant 16 bits of the integer part in its LSBs, and the most significant 16 bits of the fractional part in its MSBs. The swap instruction, which swaps the 16bit halfs of a register around, then gets everything in the correct place.
d4 : d3
I31 I30 I29 ... I02 I01 I00 : F31 F30 F29 ... F02 F01 F00
16 bit word move, d3 becomes
F31 F30 F29 ... F17 F16 I15 I14 ... I02 I01 I00
After swap becomes
I15 I14 ... I01 I00 F31 F30 ... F18 F17 F16
Values that will never exceed 1.0, such as normalised direction vectors and sine lookup tables, are often stored as 15bit fraction fixed point values due to the need for a sign bit. This leads to a lot "add.l d0, d0" cases in the code to bump them up to 16 bit fracs and use them in Quick maths.
Versions
- gloom.s is the one I've most used for reference. It's the original copper-chunky Gloom. It also bakes a few more things into the executable than later versions, such as the title screen.
- gloom2.s is the - apparently incomplete - Gloom Deluxe source, which moved to a more conventional 256 colour planar display. I say incomplete as there's no code for handling the new gun graphics.
- ap.s is, I suspect, the Amiga Power demo. It contains a "onedemo" define to presumably switch it into the demo for The One magazine, but it's not actually used as far as I can see.
Speaking of, the "quezzies" and "theone" files in the source drop are from an interview with The One.
It's weird, like Amiga programmers think Doom is all about walking around buildings, twiddling your thumbs, going 'ahhh, that's a nice wall'.
Amiga Specifics
I largely sidestepped this as the backend of the renderer is my own. Some Amiga knowledge was still needed though:
- Audio was reasonably easy. XMP handles all music, and a bit of Googling reveals how Paula's period-setting converts to a samplerate. Amiga raw audio samples are converted to a faked-up WAV in memory then fed to SDL_Mixer.
- IFFs needed decoding for the title/inter-level screens. Not a huge problem as the decompression is well documented. Biggest gotcha - the palette colours are encoded with the top 4 bits of the RGB triplet, then the bottom 4. Presumably for AGA backwards compatibility with OCS/ECS. Gloom 3 / Zombie Massacre use some odd-sized images so padding/clipping is needed. This also required writing planar-to-chunky code, which was pleasing in a "the times, they have a-changed" way.
- The font, of all the damn things. I think it's a Blitz Basic "Shapes" file, but couldn't find decent documentation so had to go back-and-forth to the source and go "Ah, this value in the file is written to this Blitter register, therefore it is the width" and so on.