Site hosted by Angelfire.com: Build your free website today!
The C-buffer


First of all, the C stands for coverage, meaning it's a buffer that keeps track of what parts of the screen have already been drawn on. As such, you'll need to have all your triangles sorted from front to back, because you'll essentially be drawing 'behind' everything currently on the screen. Keep in mind though that it's slower than brute-force back-to-front rendering, unless you have a lot of per-pixel calculations (ex. perspective texturing) and/or a lot of overdraw.

Unlike the S-buffer, you don't have to store texture coords or anything, just starting/ending values for the already-drawn spans. You just check against spans, draw a strip of triangle to the screen, and then add/merge the newly covered area into the buffer before going down to the next line. If done right, it doesn't take anywhere near the memory of an S-buffer, and you don't have to go traversing the whole thing at the end of the frame to draw it, since you just draw as you go.

The way I do it in my GBA engine is just a linked list of bit-packed values. It will have to be a bit different if you're working on a system with higher resolutions than about 320x240 or so, but just using 8 bytes per entry instead of 4.
First, you take an area of memory (I use 16K), and each entry is a 32 bit value set up like bit0-11 is the index into the memory area, divided by 4, so you can reach all 4096 entries of the 16K block, then bit12-21 is the starting x value, so you shift left 10, and then ASR 22 to sign extend it, and bit22-31 is the end value, so ASR 22 to load it. Then you check if spanStart is greater than cBufEnd, and if so, go to the next C-buffer entry and repeat.

For inserting new spans in to the C-buffer, you keep entry 0 in the block as the head of the linked list of free blocks. So to get a new span, you just set the previous span's 'next index' to the index entry 0 points to (0.next), then set 0's next to the entry that it's pointing to's next (that would be 0.next = 0.next.next), and then take that one you set prevSpan.next to, and set it up with the span's start/ending values, and prevSpan's old next index. The only hitch in the plan is when you have a span that starts before a c-buf entry, and ends past the end of the entry, so you have to deal with the first half, and then take cBufEnd as spanStart, and spanEnd as the end, and keep loop through the whole thing again. So it's not really a problem after all.

As long as you set it up each frame to have one entry for -512 to 0, and one for 240 to 511 (maximum values for the 10-bit x start/end), then as long as you check if you polygons are fully offscreen before drawing them, and don't have any crazily large ones that have one corner on the screen and one past -512 or 511, then you get x-clipping for free, and also don't have to worry about hitting the end of the C-buffer spans while drawing, cause you'll just merge with the last span.
You can also go through filling span.xEnd through nextSpan.xStart with a background color after everything is drawn, that way you get 0% overdraw, not even for screen clearing. And resetting the buffer for the next frame is easy too. Just loop through each of the 160 lines, keeping the first entry (since 0 is used for the free list, the start of each line's linked list will always be 1 + line (you initially set up the buffer that way, and link all the rest of the 4096 into the free list)), so the first entry for the line will be set back to -512-0, and link each entry of that line back into the free list, until you hit one with next index 0, which is just the flag I use to indicate the last one of the line (not anything to do with the free list), and set it back to 240-511 (don't forget to set lineStart.next to this one!). And since spans are getting merged together all the time, there probably won't be that many left at the end of the frame.

It takes a while to explain, but it's really not that hard to implement. Just work out each of the cases of how lines will intersect the buffer spans on paper before you start, and what tests you'll need to do for each of those cases. That saved me a world of confusion for writing the actual tri fillers. Email me at dekutree64 'at' hotmail 'dot' com if you want explanations of all the cases, and I'll add them here.

And for more coolness, you can set up the C-buffer by hand to have pre-covered areas, which I think is what a stencil buffer does, by rendering stuff, loading a new C-buffer, rendering more stuff, etc. You can also do screen transitions. like iris out, horizontal bars coming from the sides, and pretty much anything else you can do with the GBA's window regs in tiled modes. Don't forget to clear any pre-covered areas to black though. Actually if you're just filling it in with black, you might as well still use the window regs anyway, unless you want to do vertical strips or something (or are working on a different system). Copying in 16K at a time might be a little slow though, but since most of the time you won't have more than a few spans per line of screen, you could easily get away with more like 4 or 8K of total C-buffer data. 8K would give you 2048 entries, so an average of 12.8 spans per line of screen (though it's just one big pool, so one line could have 100 spans, as long as all of them total to less than 2048), so of course 4K would give you 6.4 spans/line. Depends on how many triangles you'll be drawing, and how scattered around they'll be, cause if they touch, the spans merge so you don't use any extras, so it's just in the middle of drawing while there's still lots of empty space that a lot of spans would be used. The actual drawing code won't change for the pool size, just the number of spans you link into the free list in the initialization.