More3D -- Allegro WIP Add-On
Tom St Denis (tomstdenis@yahoo.com)

Latest copies are at:  http://tomstdenis.dhs.org

Intro
------

    More3D is an Allegro addon that provides simple 3D rendering functions.
The idea is that More3D takes care of how to actually render the faces of
the objects and you just provide the objects.

    More3D is triangle based so a FACE is three verteces, a texture and
a shading mode.  Each vertex can have a 24-bit RGB color assigned to it
or a 8-bit level (for lit textures).

    An OBJECT is a collection of faces and CHILD objects.  By rendering
an object you render all the faces that it contains.  Objects also have
X/Y/Z rotations and translation vectors.  So you can easily move all the
faces of a child about.

    A CAMERA is a matrix used to rotate all objects into "CAMERA Space".
"Camera Space" is the space all objects are drawn to the screen from.  It
has -x to the left, -y to the top and -z to the inside of the screen.  By
moving the camera about you focus on different parts of the WORLD SPACE.

    I will be updating more3d quite a bit so if there any bugs please email
 me.  To build this under DJGPP/MINGW32 simply type "make install".

Setting Up More3D
------------------

    You have to include "m3d.h" in your program.

#include "m3d.h"

    Then let's make a simple function to setup the screen:

MATRIX_f camera;        /* the camera we use for rendering */
BITMAP  *backbuffer;    /* Render to this then blit to the screen */

int setup(int width, int height, int depth)
{
    /* Setup allegro */
    allegro_init();
    set_color_depth(depth);
    if (set_gfx_mode(GFX_SAFE, width, height, 0, 0) != 0) return 0;

    /* get our camera */
    get_camera_matrix_f(&camera,
                        0,0,0,      /* Position */
                        0,0,1,      /* Facing towards -1 */
                        0,-1,0,     /* up vector */
                        45,         /* field of view  */
                        1.0);       /* aspect ratio */

    /* You must set the blender if you use 8/15/16 bit color depths or
     * the zbuffered rasterizers.  This call will set it to a default of
     * no additional blending */
    set_trans_blender(0,0,0,128);
    
    /* Make the back buffer */
    backbuffer = create_bitmap(width, height);

    /* setup viewport */
    set_projection_viewport(0, 0, width, height);

    /* move the clip distance to 250 units */
    clipdist = 250.0;

    return 1;
}

Objects
--------

    Next we want to load objects.  We can use the VTX loader (or perhaps
a 3DS loader when I get around to doing one...) as so:

obj *myobject;
myobject = m3d_LoadVTX("mymesh.vtx");

    That was simple.  Now we may want to apply a texture to it.

BITMAP *mytexture;

mytexture = load_bitmap(...);
m3d_ApplyTexture(myobject, mytexture);

    Then we have to switch the rasterizer being used.  In this case a texture
based on.

m3d_ChangeShading(myobject, POLYTYPE_ATEX);

    Let's say we want to rotate the entire object around the Y axis by
45 degrees.  We use

myobject.Ya = 45;

    Simple right?  (hint:  Look at m3d.h for the details)

Lights
-------

    Lights are good for illuminating scenes.  (duh).  They can be used for
creating world lights (points everywhere), spot lights (big falloff,
directional) or even shadows (buggy).  To use a light declare a light
variable

light mylight;

    Then set the parameters of it

memset(&mylight, 0, sizeof(light));
mylight.intensity = 1.0;                /* full intensity */
mylight.falloff   = 2.0;                /* normal light with slow falloff */
mylight.fadedist  = 10.0;               /* half the intensity every 10 units */
mylight.flags     = LIGHT_FADE;         /* A simple fading light*/

    Simple right?

Scenes
-------

    Rendering an entire scene now becomes a simple loop

do {
    /* start the scene */
    m3d_Begin(backbuffer, &camera);
    clear(backbuffer);

    /* Render Lights in order */
    m3d_RenderLight(&mylight);

    /* Render the objects */
    m3d_RenderObj(myobject);

    /* draw all objects (1 == zbuffered, 0 = sort) */
    m3d_Draw(0);

    /* blit em to the screen */
    vsync();
    blit(backbuffer, screen, 0, 0, 0, 0, width, height);
} while (!done);

Misc
-----

1)  If you want to use zbuffered objects you have to change the shading
value to include POLYTYPE_ZBUF.  When you call m3d_Draw() pass a "1" instead
of a "0" to indicate that the object is zbuffered.   Only pass a "1" if ALL
your objects are zbuffered otherwise it won't work right.  

m3d_ChangeShading(myobject, POLYTYPE_ATEX_LIT | POLYTYPE_ZBUF);

2)  You must normalize the direction vector for lights and cameras for
them to work properly.

3)  If I am not mistaken verteces are stored counter clockwise in the list.
And if you make up your own verteces you must calculate the normals using
m3d_CalcNormals().

4)  If you need a simple plane or sphere you can use the supplied VTX files
"plane.vtx" and "sphere.vtx" they are a unit plane and a unit sphere centered
about (0,0,0).  You can stretch the verteces to the desired size as required.

