6502's cornerFree Span Buffer [2]
2002-12-28
Index

Welcome!
Who am I
Demo
Documents
Small ones
Problems
Chess
Images
Music
My blog
Write me

Versione italiana 


Algorithm description

The algorithm I'm going to illustrate requires perfect sorting like the painter's algorithm (z-buffer doesn't require that) but computes the final image much faster, avoiding to compute data about back polygons (for z-buffer every pixel of every polygon is always considered, at least for the depth check).

Note:There's another algorithm for which the inventor claims to be my friend Paul Nette (Midnight) that's called "s-buffer". That algorithm doesn't require any sorting (like z-buffer) and is a big improvement over z-buffer for simple scenes (small number of polygons). However complexity increases when more polygons are added and in my opinion, excluding a few very special situations, that s-buffer solution isn't a good choice. The algorithm described in this text is NOT the one described by Paul Nette.

The main idea is to draw the polygons on the screen starting from the nearest and finishing with the farthest one, keeping track of which areas of the screen have been already covered by a polygon and which ones are still available. This map of available areas is maintained in a list of "span" (intervals) for each scanline:

/*
** Every span is defined by the initial and ending
** x coordinate and by a pointer to the next span
** on the same scanline.
**
**   x0   = starting X for the span
**   x1   = ending X for the span
**   next = next span on the same scanline
*/
typedef struct SPAN
{
  int x0;
  int x1;
  struct SPAN *next;
} Span;

/*
** For every scanline there's a pointer to the
** first span for that scanline. MAXYRES is the
** maximum vertical resolution admissible for
** the screen.
*/
Span *FirstSpan[MAXYRES];

During initialization it will be created a single span for every scanline as large as the screen, to mark the scanline completely available. During the rendering those span lists will be kept updated with new insertion or deletion. Since during the redering of a scene there will be a lot of creation/deletion of spans it's better to implement a reuse logic to avoid the overhead a general memory manager would add.

/*
** List of reusable spans
*/
static Span *FirstUnusedSpan;

/*
** Allocation of a new span: before asking a real
** allocation to the memory manager the reusable
** span list is checked.
*/
static Span *NewSpan(void)
{
  Span *s;
  if ((s=FirstUnusedSpan)==NULL)
    s=(Span *)Malloc(sizeof(Span));
  else
    FirstUnusedSpan=s->next;
  return s;
}

/*
** Deallocation of a span: it's not a true
** memory manager deallocation but just an
** insertion in the list of reusable spans.
*/
static void FreeSpan(Span *s)
{
  s->next=FirstUnusedSpan;
  FirstUnusedSpan=s;
}