Right, let’s just pick it back up where I left off. Last time, I spoke of the polygon fill routines that I had developed for CGA, EGA and VGA. At the time they weren’t much more than that, so there wasn’t really anything to look at. In order to actually show an object in 3d, you’d need to have the object geometry itself, some rotation routines, perspective projection, and backface culling so it will be drawn properly. Some flatshading would also be nice, while we’re at it.
So I spent a bit more time on the code, and made a simple rotating cube with it. The DOS binaries can be found here. They include the VGA renderer in unchained mode:
The EGA renderer:
And the CGA renderer:
While I’m at it, I would also like to share another link. In the previous blog I already linked to the original IBM programming reference for CGA and EGA. I would have loved to have the VGA documentation as well, but at the time I could not find it. I have found an IBM manual for VGA now, but it is from 1992, so already in the SVGA/XGA era. Still, it appears that the VGA portion of this manual is still close to what the original VGA manual would have looked like. It is a good reference for VGA programming at any rate.
Right, I suppose that about wraps up the PC platform for me, as far as graphics are concerned. Things have come full circle now. The next step up from the flatshaded mode X poly filler would be more advanced shading and texturing. Which would not really benefit from mode X, so you would probably do it in a regular chunky mode anyway. Which is where I started programming graphics on PCs. So there are only two ‘open ends’ left: the Commodore 64, and the Amiga.
Only Amiga makes it possible.
Right, well, the choice of doing PC first was because I already had some experience programming in DOS, and with VGA in mode 13h and whatnot. So I figured I could start from my comfort zone and ease into mode X and CGA/EGA from there. The EGA would give me some experience with planar graphics. And that would give me a starting point on the Amiga, which uses a very similar planar setup. So Amiga is the next platform of choice.
Let’s start with a few Amiga demos first, to show what it is that I will be trying to do.
Here’s a nice one that should demonstrate what I mean:
And another one for good measure:
As you can see, Amiga demos feature some nice and smooth polygon graphics, including flatshading and sometimes even transparency. And there is no problem with relatively large objects either, the system has enough fillrate. In fact, YouTube does not do the demos justice. The videos are not perfectly smooth, scrolling text looks a bit wobbly. These are artifacts caused by framerate conversion (PAL Amiga runs at 50 fps, and YouTube only does 30 fps max) and video compression. On a real Amiga it would be perfectly smooth.
In fact, I’d like to show a legendary Amiga demo which used the Amiga’s fillrate for something other than conventional 3D. In this demo they used it for video compression, fitting an entire ‘music video’ on a single floppy:
The next year they released an even more impressive sequel (although this time it took 2 floppies):
That is what made the Amiga special. This was a standard home computer from 1985, doing smoothly animated 3d, video and music. It only had a simple Motorola 68000 processor at 7 MHz. It would take PCs years to catch up to this level of music and graphics. And they’d require much newer and more expensive hardware to do the effects that the Amiga does here. The PC demos I mentioned in the previous blog were from the early 90s. But they also required a PC from the early 90s to run these demos. You’d need a 386 or 486 CPU, a fast VGA card and a sound card. Most of these weren’t even available back when the Amiga debuted.
So how did the Amiga do it? The answer is: custom hardware. Arcade game machines would often have the latest in audio and video hardware, with special trickery for smoothly scrolling the screen and hardware sprites for efficient movement of characters on screen, and for collision detection (and at a later time, arcade machines would employ 3d acceleration hardware). For game consoles and home computers, the designers tried to put in some of this special hardware, so that popular arcade games could be played at home, and still look reasonably close to the arcade version. Because they had to keep the machines affordable, they generally were not as good as the real arcade machines, but it was a big difference nonetheless with machines that did not have any kind of specific hardware at all, like PCs. On a PC, the CPU has to do all the graphics work, move every single pixel around. It wasn’t until the introduction of 3d accelerator cards in the mid-to-late 90s that custom graphics hardware became commonplace in PCs, and CPUs were finally relieved of some of the graphics work.
The Amiga stood out at the time, because it had the most advanced custom hardware on the market. It could have something to do with the fact that in the early stages, the designers wanted to make a next generation game platform. They decided at a later stage that the machines would be sold as general purpose home/business computers. Because of its unique design, the custom chips relieved the CPU of many duties. This made it possible to do efficient pre-emptive multitasking on a personal computer for the first time. Something that wouldn’t become commonplace on PCs or Macintosh computers until much later. The Amiga also had very powerful multimedia capabilities, making things like animation or even video editing possible. Again something that just wasn’t possible on most other machines until much later. For example, if you want to play an animation on a PC, the CPU has to copy every single frame of the animation into video memory. With the first generations of PC hardware, the copy-speed simply was not fast enough to make full-screen animation possible at all.
Opening up the third dimension
A big factor in the Amiga’s excellent graphics performance is a processor known as the ‘blitter’. The name comes from “BLock Image Transfer”, which is a common term for moving images from one place in memory to another. The basic operation of moving objects around on screen. Having a special chip has two advantages:
- The CPU is free to do other things while the blitter is busy moving memory around.
- The blitter can move memory around much faster than the 7 MHz 68000 CPU in an Amiga could (This is in fact much like the situation with GPUs today: when dualcore processors arrived, this didn’t mean that one core could now be used to render graphics, leaving the other core free for other tasks. The specialized GPU hardware is far faster at rendering graphics than any CPU. It is designed and optimized specifically for that task).
This is all aimed at 2D bitmap graphics. The Amiga blitter could do more than just copying images around though. For example, it could also draw lines, and it could perform a flood-fill. With these two features combined, you could draw the outline of a polygon, and then fill it. Technically the lines and the polygons were still drawn as 2D-shapes, but 3D graphics are always drawn as a projection in 2D, so they could be used for 3D animations. The blitter accelerated the most time-consuming part of filling the polygons, so the CPU only needed to do the 3D transforms and projection. In fact, early 3D accelerator cards also required the CPU to do the transforms and projections. It wasn’t until the introduction of the nVidia GeForce that the 3D accelerator would take care of this workload as well (hardware Transform & Lighting).
So, the blitter gave the Amiga a head start in 3D graphics, with what could be described as an early form of 3D acceleration. This probably has a lot to do with the fact that the Amiga was embraced as a demoscene platform, and demos quickly evolved from 2D to 3D effects. Demo coders would try to mimic these 3D effects on other platforms, but they would struggle to keep up with the Amiga’s speed. The Amiga had no problem with polygons that covered the entire screen, where on other platforms the objects generally had to be kept relatively small, to avoid too much of a drop in framerate.
Time for the hands-on approach
My goal then, is to write a simple 3D renderer, much like the earlier CGA/EGA/VGA renderers, which in this case uses the Amiga’s blitter to accelerate the polygon drawing. I have used an Amiga for many years, so I am familiar with what it can do. However, I had never programmed it at the hardware level, so I didn’t know exactly HOW it does it. So the first step is to find some documentation on the Amiga’s hardware and OS.
I had already set up WinUAE with some development tools at an earlier time… I used to talk to Kalms (of Amiga demogroup The Black Lotus) on IRC regularly. At the time I already wanted to get into some Amiga development, and he helped me to set up an assembler (DevPac), a C/C++ compiler (SAS/C), the Native Developer Kit, and some documentation. I managed to write a Hello World in 68k assembly, and some other simple routines. However, when I wanted to take the next step, and start coding graphics, it was quite difficult to even get started by setting up a graphics mode. I didn’t really have the time to get it all figured out, and lost interest.
This time however, I was determined to get graphics working on the Amiga. I figured the best thing to start with was some actual working graphics code, study it, and go from there. The first thing that I found was an old Danish course from 1989, which had recently been translated into English. This seemed to be nice enough at first sight. It also comes with some disk images with example code and prebuilt binaries. I tried to run them in WinUAE, and at least some of them seemed to work okay: they set up a graphics screen, rendered something, and exited to Workbench (the Amiga GUI) when you clicked the left mouse button.
So now I had a reasonable starting point. I read through the accompanying text, and tried to understand what the code was doing exactly. I figured that a good way to understand the code was to rewrite it with SAS/C. This turned out to be harder than I thought, because the code used quite a few ‘magic numbers’: offsets into memory with no description whatsoever. My C translation would require some nice structures with data members at the proper offsets. I had the header files with all the OS and hardware structures predefined, but I could not tell which structures were used from the assembly code. So in some cases I just had to use some pointer arithmetic or build fake structures in C, so at least I could get the code working. Some other problems were in some ‘unwritten rules’: not everything was explained in detail in the tutorial. In translation, I had to be careful to do everything exactly the right way, because in some cases the order appeared to make a difference, although it was not clear why.
So although I did get my C code working in the end, I still was not entirely happy, since there were still some things I did not understand. I noticed that the Danish course referred to some “Amiga bibles” in the epilog:
We recommend to obtain the so-called “Amiga Bibles” – as we mentioned in the introduction in this chapter, they are rather expensive, but you’ll get far with these four books (Amiga Rom Kernel Reference Manuals). We used the HARDWARE REFERENCE MANUAL when we took our first faltering steps into the unknown “wilderness” called Amiga. It therefore should be also a good tool for you.
So that was exactly what I was going to do: I tried to find some Amiga books in electronic form. In fact, Kalms had already given me a text version of the Amiga Hardware Reference Manual earlier. I started to read it once, but I found it to be quite terse at the time. This time however, I stumbled upon a site called “Amiga Manuals“. Wow! A pure gold mine of Amiga books! Firstly, I found a nice PDF version of the Amiga Hardware Reference Manual, including all the images and such, which made it easier to read and understand than the text-only version that I had earlier. Secondly, I had spoken to another old Amiga developer by the nickname of ‘med’, and he mentioned a book that he used at the time. It was the Amiga System Programmers Guide, and this site carried a PDF of that as well.
Now I had all the documentation I needed, and plenty of sample code to help me along. This blogpost is getting pretty lengthy by now, so I will start a new blogpost where I will start discussing the actual blitter programming.