Allegro バージョン4で各種の3次元シェーディング法を見てみる
 Allegro サンプルプログラムです。
cd /tmp
emacs ex3d.c
# 以下のように作成
----------------------------------------------------------------------------
/*
* Example program for the Allegro library, by Shawn Hargreaves.
*
* This program demonstrates how to use the 3d matrix functions.
* It isn't a very elegant or efficient piece of code, but it
* does show the stuff in action. It is left to the reader as
* an exercise to design a proper model structure and rendering
* pipeline: after all, the best way to do that sort of stuff
* varies hugely from one game to another.
*
* The example first shows a screen resolution selection dialog.
* Then, a number of bouncing 3d cubes are animated. Pressing
* a key modifies the rendering of the cubes, which can be
* wireframe, the more complex transparent perspective correct
* texture mapped version, and many other.
*/
#include<allegro.h>
#define NUM_SHAPES 8 /* number of bouncing cubes */
#define NUM_VERTICES 8 /* a cube has eight corners */
#define NUM_FACES 6 /* a cube has six faces */
typedef struct VTX
{
fixed x, y, z;
} VTX;
typedef struct QUAD /* four vertices makes a quad */
{
VTX *vtxlist;
int v1, v2, v3, v4;
} QUAD;
typedef struct SHAPE /* store position of a shape */
{
fixed x, y, z; /* x, y, z position */
fixed rx, ry, rz; /* rotations */
fixed dz; /* speed of movement */
fixed drx, dry, drz; /* speed of rotation */
} SHAPE;
VTX points[] = /* a cube, centered on the origin */
{
/* vertices of the cube */
{ -32 << 16, -32 << 16, -32 << 16 },
{ -32 << 16, 32 << 16, -32 << 16 },
{ 32 << 16, 32 << 16, -32 << 16 },
{ 32 << 16, -32 << 16, -32 << 16 },
{ -32 << 16, -32 << 16, 32 << 16 },
{ -32 << 16, 32 << 16, 32 << 16 },
{ 32 << 16, 32 << 16, 32 << 16 },
{ 32 << 16, -32 << 16, 32 << 16 },
};
QUAD faces[] = /* group the vertices into polygons */
{
{ points, 0, 3, 2, 1 },
{ points, 4, 5, 6, 7 },
{ points, 0, 1, 5, 4 },
{ points, 2, 3, 7, 6 },
{ points, 0, 4, 7, 3 },
{ points, 1, 2, 6, 5 }
};
SHAPE shapes[NUM_SHAPES]; /* a list of shapes */
/* somewhere to put translated vertices */
VTX output_points[NUM_VERTICES * NUM_SHAPES];
QUAD output_faces[NUM_FACES * NUM_SHAPES];
enum {
wireframe,
flat,
gcol,
grgb,
last_mode
} render_mode = wireframe;
int render_type[] =
{
0,
POLYTYPE_FLAT,
POLYTYPE_GCOL,
POLYTYPE_GRGB,
};
char *mode_desc[] =
{
"Wireframe",
"Flat shaded",
"Single color gouraud shaded",
"Gouraud shaded",
};
/* initialise shape positions */
void init_shapes(void)
{
int c;
for (c=0; c<NUM_SHAPES; c++) {
shapes[c].x = ((AL_RAND() & 255) - 128) << 16;
shapes[c].y = ((AL_RAND() & 255) - 128) << 16;
shapes[c].z = 768 << 16;
shapes[c].rx = 0;
shapes[c].ry = 0;
shapes[c].rz = 0;
shapes[c].dz = ((AL_RAND() & 255) - 8) << 12;
shapes[c].drx = ((AL_RAND() & 31) - 16) << 12;
shapes[c].dry = ((AL_RAND() & 31) - 16) << 12;
shapes[c].drz = ((AL_RAND() & 31) - 16) << 12;
}
}
/* update shape positions */
void animate_shapes(void)
{
int c;
for (c=0; c<NUM_SHAPES; c++) {
shapes[c].z += shapes[c].dz;
if ((shapes[c].z > itofix(1024)) ||
(shapes[c].z < itofix(192)))
shapes[c].dz = -shapes[c].dz;
shapes[c].rx += shapes[c].drx;
shapes[c].ry += shapes[c].dry;
shapes[c].rz += shapes[c].drz;
}
}
/* translate shapes from 3d world space to 2d screen space */
void translate_shapes(void)
{
int c, d;
MATRIX matrix;
VTX *outpoint = output_points;
QUAD *outface = output_faces;
for (c=0; c<NUM_SHAPES; c++) {
/* build a transformation matrix */
get_transformation_matrix(&matrix, itofix(1),
shapes[c].rx, shapes[c].ry, shapes[c].rz,
shapes[c].x, shapes[c].y, shapes[c].z);
/* output the vertices */
for (d=0; d<NUM_VERTICES; d++) {
apply_matrix(&matrix, points[d].x, points[d].y, points[d].z,
&outpoint[d].x, &outpoint[d].y, &outpoint[d].z);
persp_project(outpoint[d].x, outpoint[d].y, outpoint[d].z,
&outpoint[d].x, &outpoint[d].y);
}
/* output the faces */
for (d=0; d<NUM_FACES; d++) {
outface[d] = faces[d];
outface[d].vtxlist = outpoint;
}
outpoint += NUM_VERTICES;
outface += NUM_FACES;
}
}
/* draw a line (for wireframe display) */
void wire(BITMAP *b, VTX *v1, VTX *v2)
{
int col = MID(128, 255 - fixtoi(v1->z+v2->z) / 16, 255);
line(b, fixtoi(v1->x), fixtoi(v1->y), fixtoi(v2->x), fixtoi(v2->y),
palette_color[col]);
}
/* draw a quad */
void draw_quad(BITMAP *b, VTX *v1, VTX *v2, VTX *v3, VTX *v4, int mode)
{
int col;
/* four vertices */
V3D vtx1 = { 0, 0, 0, 0, 0, 0 };
V3D vtx2 = { 0, 0, 0, 32<<16, 0, 0 };
V3D vtx3 = { 0, 0, 0, 32<<16, 32<<16, 0 };
V3D vtx4 = { 0, 0, 0, 0, 32<<16, 0 };
vtx1.x = v1->x; vtx1.y = v1->y; vtx1.z = v1->z;
vtx2.x = v2->x; vtx2.y = v2->y; vtx2.z = v2->z;
vtx3.x = v3->x; vtx3.y = v3->y; vtx3.z = v3->z;
vtx4.x = v4->x; vtx4.y = v4->y; vtx4.z = v4->z;
if ( (polygon_z_normal(&vtx1, &vtx2, &vtx3) < 0) )
return;
/* set up the vertex color, differently for each rendering mode */
switch (mode) {
case POLYTYPE_FLAT:
col = MID(128, 255 - fixtoi(v1->z+v2->z) / 16, 255);
vtx1.c = vtx2.c = vtx3.c = vtx4.c = palette_color[col];
break;
case POLYTYPE_GCOL:
vtx1.c = palette_color[0xD0];
vtx2.c = palette_color[0x80];
vtx3.c = palette_color[0xB0];
vtx4.c = palette_color[0xFF];
break;
case POLYTYPE_GRGB:
vtx1.c = 0x000000;
vtx2.c = 0x7F0000;
vtx3.c = 0xFF0000;
vtx4.c = 0x7F0000;
break;
}
/* draw the quad */
quad3d(b, mode, /* texture */ NULL, &vtx1, &vtx2, &vtx3, &vtx4);
}
/* callback for qsort() */
int quad_cmp(const void *e1, const void *e2)
{
QUAD *q1 = (QUAD *)e1;
QUAD *q2 = (QUAD *)e2;
fixed d1 = q1->vtxlist[q1->v1].z + q1->vtxlist[q1->v2].z +
q1->vtxlist[q1->v3].z + q1->vtxlist[q1->v4].z;
fixed d2 = q2->vtxlist[q2->v1].z + q2->vtxlist[q2->v2].z +
q2->vtxlist[q2->v3].z + q2->vtxlist[q2->v4].z;
return d2 - d1;
}
/* draw the shapes calculated by translate_shapes() */
void draw_shapes(BITMAP *b)
{
int c;
QUAD *face = output_faces;
VTX *v1, *v2, *v3, *v4;
/* depth sort */
qsort(output_faces, NUM_FACES * NUM_SHAPES, sizeof(QUAD), quad_cmp);
for (c=0; c < NUM_FACES * NUM_SHAPES; c++) {
/* find the vertices used by the face */
v1 = face->vtxlist + face->v1;
v2 = face->vtxlist + face->v2;
v3 = face->vtxlist + face->v3;
v4 = face->vtxlist + face->v4;
/* draw the face */
if (render_mode == wireframe) {
wire(b, v1, v2);
wire(b, v2, v3);
wire(b, v3, v4);
wire(b, v4, v1);
}
else {
draw_quad(b, v1, v2, v3, v4, render_type[render_mode]);
}
face++;
}
}
/* RGB -> color mapping table. Not needed, but speeds things up */
RGB_MAP rgb_table;
/* lighting color mapping table */
COLOR_MAP light_table;
/* transparency color mapping table */
COLOR_MAP trans_table;
int main(void)
{
BITMAP *buffer;
PALETTE pal;
int c, w, h, bpp;
int last_retrace_count;
if (allegro_init() != 0)
return 1;
install_keyboard();
install_mouse();
install_timer();
/* color 0 = black */
pal[0].r = pal[0].g = pal[0].b = 0;
/* copy the desktop palette */
for (c=1; c<64; c++)
pal[c] = desktop_palette[c];
/* make a red gradient */
for (c=64; c<96; c++) {
pal[c].r = (c-64)*2;
pal[c].g = pal[c].b = 0;
}
/* make a green gradient */
for (c=96; c<128; c++) {
pal[c].g = (c-96)*2;
pal[c].r = pal[c].b = 0;
}
/* set up a greyscale in the top half of the palette */
for (c=128; c<256; c++)
pal[c].r = pal[c].g = pal[c].b = (c-128)/2;
/* build rgb_map table */
create_rgb_table(&rgb_table, pal, NULL);
rgb_map = &rgb_table;
/* build a lighting table */
create_light_table(&light_table, pal, 0, 0, 0, NULL);
color_map = &light_table;
/* set the graphics mode */
if (set_gfx_mode(GFX_SAFE, 320, 200, 0, 0) != 0) {
set_gfx_mode(GFX_text, 0, 0, 0, 0);
allegro_message("Unable to set any graphic mode\n%s\n", allegro_error);
return 1;
}
set_palette(desktop_palette);
c = GFX_AUTODETECT;
w = SCREEN_W;
h = SCREEN_H;
bpp = bitmap_color_depth(screen);
if (!gfx_mode_select_ex(&c, &w, &h, &bpp)) {
allegro_exit();
return 1;
}
set_color_depth(bpp);
if (set_gfx_mode(c, w, h, 0, 0) != 0) {
set_gfx_mode(GFX_text, 0, 0, 0, 0);
allegro_message("Error setting graphics mode\n%s\n", allegro_error);
return 1;
}
set_palette(pal);
/* double buffer the animation */
buffer = create_bitmap(SCREEN_W, SCREEN_H);
/* set up the viewport for the perspective projection */
set_projection_viewport(0, 0, SCREEN_W, SCREEN_H);
/* initialise the bouncing shapes */
init_shapes();
last_retrace_count = retrace_count;
for (;;) {
clear_bitmap(buffer);
while (last_retrace_count < retrace_count) {
animate_shapes();
last_retrace_count++;
}
translate_shapes();
draw_shapes(buffer);
textprintf_ex(buffer, font, 0, 0, palette_color[192], -1, "%s, %d bpp",
mode_desc[render_mode], bitmap_color_depth(screen));
textout_ex(buffer, font, "Press a key to change", 0, 12,
palette_color[192], -1);
vsync();
blit(buffer, screen, 0, 0, 0, 0, SCREEN_W, SCREEN_H);
if (keypressed()) {
if ((readkey() & 0xFF) == 27)
break;
else {
render_mode++;
if (render_mode >= last_mode) {
render_mode = wireframe;
color_map = &light_table;
}
}
}
}
destroy_bitmap(buffer);
return 0;
}
END_OF_MAIN()
次の手順でコンパイル
cd /tmp gcc -o ex3d ex3d.c -L/usr/local/lib -lalleg-4.2.0 -lalleg_unsharable -lm
次の手順で実行
./keyboard