Here's my first attempt at some 3D vector graphics using the F18A: a spinning polyhedron.
Ascreenshot.png 3.48KB 8 downloads
You use the joystick to spin: left/right to spin around the y-axis, up/down to spin around the x-axis, and fire button to spin around the z-axis (one way only).
The demo is using the F18A 4 color bitmap layer to draw the graphics, and the F18A GPU for the 3D calculations and the polygon rendering routine. For each frame the GPU is performing the following steps:
- Clear the bitmap layer
- Draw the (up to 5) polygons that are currently visible
- Rotate the vertices to prepare for the next frame
- Translate the vertices to screen coordinates
Calculations are done using fixed point math, and sine and cosine values are looked up in a table.
The main CPU is only responsible for waiting for vertical retrace and activating the GPU at the right moment to draw a frame, it then reads the joystick (which the GPU cannot do) and stores the result in VDP RAM for the GPU to read. This goes on in a endless loop.
This all looks very well in the demo, but drawing on the visible screen would not be plausible in a game. With 6 polygons I can just manage to clear the screen and draw the polygons before the beam catches up. (I even had to change my scanline routine from one that was using the F18A GPU PIX instruction to draw a pixel, to a faster one that uses direct memory access in order to draw 8 pixels at a time, before it looked OK.)
So we need double buffering, which is fortunately very easy to do but is limited by the amount of VDP RAM. The demo is using a bitmap size of 192x192 pixels which takes up 9216 bytes of VDP RAM, so two of those would not fit. We also need room for the GPU code (which might fit into the additional 2K VDP RAM only accessible to the GPU), and we need room for the standard VDP tables. So this is already pretty crowded, but...
Perhaps we also need room for a third screen buffer: a depth buffer? In the demo I'm using a simple algorithm to remove polygons that are facing away from the 'camera' to remove the backside of the polyhedron. In another algorithm (Painter's) you sort polygons by their depth and draw them back to front, but this too only works for relatively simple scenes. So a standard solution is to calculate a depth value for every pixel you write, compare it to the value from the buffer of any pixel already drawn at the same place, and only draw the new pixel if it's closer to the camera than any pixel already written. Perhaps this is overkill for our level of graphics, I'm not sure what algorithm 8-bit games were using?
One question that perhaps Matthew can answer: Why is there a pixel at the bottom right corner of the bitmap on my hardware? It doesn't show up in emulation (js99er.net). Does anyone else see it?