Polygon rendering
All the 3d functions that accept a `type' parameter are asking for a polygon
rendering mode, which can be any of the following POLYTYPE_* values. If the
CPU_MMX flag of the cpu_capabilities global variable is set, the GRGB and
truecolor *LIT routines will be optimised using MMX instructions. If the
CPU_3DNOW flag is set, the truecolor PTEX*LIT routines will take advantage of
the 3DNow! CPU extensions.
Using MMX for *LIT routines has a side effect: normally (without MMX), these
routines use the blender functions used also for other lighting functions,
set with set_trans_blender() or set_blender_mode(). The MMX versions only use
the RGB value passed to set_trans_blender() and do the linear interpolation
themselves. Therefore a new set of blender functions passed to
set_blender_mode() is ignored.
Zbuffered rendering
A Z-buffer stores the depth of each pixel that is drawn on a viewport.
When a 3D object is rendered, the depth of each of its pixels is compared
against the value stored into the Z-buffer: if the pixel is closer it is
drawn, otherwise it is skipped.
No polygon sorting is needed. However, backface culling should be done
because it prevents many invisible polygons being compared against the
Z-buffer. Z-buffered rendering is the only algorithm supported by Allegro
that directly solves penetrating shapes (see example exzbuf.c, for instance).
The price to pay is more complex (and slower) routines.
Z-buffered polygons are designed as an extension of the normal POLYTYPE_*
rendering styles. Just OR the POLYTYPE with the value POLYTYPE_ZBUF, and
the normal polygon3d(), polygon3d_f(), quad3d(), etc. functions will
render z-buffered polygons.
Example:
polygon3d(bmp, POLYTYPE_ATEX | POLYTYPE_ZBUF, tex, vc, vtx);
Of course, the z coordinates have to be valid regardless of rendering style.
A Z-buffered rendering procedure looks like a double-buffered rendering
procedure. You should follow four steps: create a Z-buffer at the beginning
of the program and make the library use it by calling set_zbuffer(). Then,
for each frame, clear the Z-buffer and draw polygons with
POLYTYPE_* | POLYTYPE_ZBUF and finally destroy the Z-buffer when leaving the
program.
Notes on Z-buffered renderers:
-
Unlike the normal POLYTYPE_FLAT renderers, the Z-buffered ones don't use
the hline() routine. Therefore DRAW_MODE has no effect.
-
The *LIT* routines work the traditional way - through the set of
blender routines.
-
All the Z-buffered routines are much slower than their normal counterparts
(they all use the FPU to interpolate and test 1/z values).
Scene rendering
Allegro provides two simple approaches to remove hidden surfaces:
-
Z-buffering - (see above)
-
Scan-line algorithms - along each scanline on your screen, you keep
track of what polygons you are "in" and which is the nearest. This
status changes only where the scanline crosses some polygon edge. So you
have to juggle an edge list and a polygon list. And you have to sort the
edges for each scanline (this can be countered by keeping the order of
the previous scanline - it won't change much). The BIG advantage is that
you write each pixel only once. If you have a lot of overlapping
polygons you can get incredible speeds compared to any of the previous
algorithms. This algorithm is covered by the *_scene routines.
The scene rendering has approximately the following steps:
-
Initialize the scene (set the clip area, clear the bitmap, blit a
background, etc.)
-
Call clear_scene().
-
Transform all your points to camera space.
-
Clip polygons.
-
Project with persp_project() or persp_project_f().
-
"Draw" polygons with scene_polygon3d() and/or scene_polygon3d_f().
This doesn't do any actual drawing, only initializes tables.
-
Render all the polygons defined previously to the bitmap with
render_scene().
-
Overlay some non-3D graphics.
-
Show the bitmap (blit it to screen, flip the page, etc).
For each horizontal line in the viewport an x-sorted edge list is used to
keep track of what polygons are "in" and which is the nearest. Vertical
coherency is used - the edge list for a scanline is sorted starting from
the previous one - it won't change much. The scene rendering routines use
the same low-level asm routines as normal polygon3d().
Notes on scene rendering:
-
Unlike polygon3d(), scene_polygon3d() requires valid z coordinates
for all vertices, regardless of rendering style (unlike
polygon3d(), which only uses z coordinate for *PTEX*).
-
All polygons passed to scene_polygon3d() have to be
persp_project()'ed.
-
After render_scene() the mode is reset to SOLID.
Using a lot of *MASK* polygons drastically reduces performance, because
when a MASKed polygon is the first in line of sight, the polygons
underneath have to be drawn too. The same applies to FLAT polygons drawn
with DRAW_MODE_TRANS.
Z-buffered rendering works also within the scene renderer. It may be
helpful when you have a few intersecting polygons, but most of the
polygons may be safely rendered by the normal scanline sorting algo.
Same as before: just OR the POLYTYPE with POLYTYPE_ZBUF. Also, you
have to clear the z-buffer at the start of the frame. Example:
clear_scene(buffer);
if (some_polys_are_zbuf) clear_zbuffer(0.);
while (polygons) {
...
if (this_poly_is_zbuf) type |= POLYTYPE_ZBUF;
scene_polygon3d(type, tex, vc, vtx);
}
render_scene();