1 /*
2  *    Example program for the Allegro library, by Bertrand Coconnier.
3  *
4  *    This program demonstrates how to use Z-buffered polygons and
5  *    floating point 3D math routines. It also provides a simple
6  *    way to compute fps (frames per second) using a timer. After
7  *    selecting a screen resolution through the standard GUI dialog,
8  *    the example shows two 3D cubes rotating and intersecting each
9  *    other. Rather than having full polygons incorrectly overlap
10  *    other polygons due to per-polygon sorting, each pixel is drawn
11  *    at the correct depth.
12  */
13 
14 
15 #include <allegro.h>
16 
17 
18 
19 typedef struct FACE
20 {
21   int v1, v2, v3, v4;
22 } FACE;
23 
24 
25 V3D_f cube1[] =
26 {
27    { -32., -32., -32., 0., 0., 72},
28    { -32.,  32., -32., 0., 0., 80},
29    {  32.,  32., -32., 0., 0., 95},
30    {  32., -32., -32., 0., 0., 88},
31    { -32., -32.,  32., 0., 0., 72},
32    { -32.,  32.,  32., 0., 0., 80},
33    {  32.,  32.,  32., 0., 0., 95},
34    {  32., -32.,  32., 0., 0., 88}
35 };
36 
37 
38 V3D_f cube2[] =
39 {
40    { -32., -32., -32., 0., 0., 104},
41    { -32.,  32., -32., 0., 0., 112},
42    {  32.,  32., -32., 0., 0., 127},
43    {  32., -32., -32., 0., 0., 120},
44    { -32., -32.,  32., 0., 0., 104},
45    { -32.,  32.,  32., 0., 0., 112},
46    {  32.,  32.,  32., 0., 0., 127},
47    {  32., -32.,  32., 0., 0., 120}
48 };
49 
50 
51 FACE faces[] =
52 {
53    { 2, 1, 0, 3 },
54    { 4, 5, 6, 7 },
55    { 0, 1, 5, 4 },
56    { 2, 3, 7, 6 },
57    { 4, 7, 3, 0 },
58    { 1, 2, 6, 5 }
59 };
60 
61 
62 
63 volatile int t;
64 
65 
66 /* timer interrupt handler */
tick(void)67 void tick(void)
68 {
69    t++;
70 }
71 
END_OF_FUNCTION(tick)72 END_OF_FUNCTION(tick)
73 
74 
75 
76 /* update cube positions */
77 void anim_cube(MATRIX_f* matrix1, MATRIX_f* matrix2, V3D_f x1[], V3D_f x2[])
78 {
79    int i;
80 
81    for (i=0; i<8; i++) {
82       apply_matrix_f(matrix1, cube1[i].x, cube1[i].y, cube1[i].z,
83 		     &(x1[i].x), &(x1[i].y), &(x1[i].z));
84       apply_matrix_f(matrix2, cube2[i].x, cube2[i].y, cube2[i].z,
85 		     &(x2[i].x), &(x2[i].y), &(x2[i].z));
86       persp_project_f(x1[i].x, x1[i].y, x1[i].z, &(x1[i].x), &(x1[i].y));
87       persp_project_f(x2[i].x, x2[i].y, x2[i].z, &(x2[i].x), &(x2[i].y));
88    }
89 }
90 
91 
92 
93 /* cull backfaces and draw cubes */
draw_cube(BITMAP * buffer,V3D_f x1[],V3D_f x2[])94 void draw_cube(BITMAP* buffer, V3D_f x1[], V3D_f x2[])
95 {
96    int i;
97 
98    for (i=0; i<6; i++) {
99       V3D_f vtx1, vtx2, vtx3, vtx4;
100 
101       vtx1 = x1[faces[i].v1];
102       vtx2 = x1[faces[i].v2];
103       vtx3 = x1[faces[i].v3];
104       vtx4 = x1[faces[i].v4];
105       if (polygon_z_normal_f(&vtx1, &vtx2, &vtx3) > 0)
106          quad3d_f(buffer, POLYTYPE_GCOL | POLYTYPE_ZBUF, NULL,
107 		  &vtx1, &vtx2, &vtx3, &vtx4);
108 
109       vtx1 = x2[faces[i].v1];
110       vtx2 = x2[faces[i].v2];
111       vtx3 = x2[faces[i].v3];
112       vtx4 = x2[faces[i].v4];
113       if (polygon_z_normal_f(&vtx1, &vtx2, &vtx3) > 0)
114          quad3d_f(buffer, POLYTYPE_GCOL | POLYTYPE_ZBUF, NULL,
115 		  &vtx1, &vtx2, &vtx3, &vtx4);
116    }
117 }
118 
119 
120 
main(void)121 int main(void)
122 {
123    ZBUFFER *zbuf;
124    BITMAP *buffer;
125    PALETTE pal;
126    MATRIX_f matrix1, matrix2;
127    V3D_f x1[8], x2[8];
128 
129    int i;
130    int c = GFX_AUTODETECT;
131    int w, h, bpp;
132 
133    int frame = 0;
134    float fps = 0.;
135 
136    float rx1, ry1, rz1;		/* cube #1 rotations */
137    float drx1, dry1, drz1;	/* cube #1 rotation speed */
138    float rx2, ry2, rz2;		/* cube #2 rotations */
139    float drx2, dry2, drz2;	/* cube #1 rotation speed */
140    float tx = 16.;		/* x shift between cubes */
141    float tz1 = 100.;		/* cube #1 z coordinate */
142    float tz2 = 105.;		/* cube #2 z coordinate */
143 
144    if (allegro_init() != 0)
145       return 1;
146    install_keyboard();
147    install_mouse();
148    install_timer();
149 
150    LOCK_VARIABLE(t);
151    LOCK_FUNCTION(tick);
152 
153    install_int(tick, 10);
154 
155    /* color 0 = black */
156    pal[0].r = pal[0].g = pal[0].b = 0;
157    /* color 1 = red */
158    pal[1].r = 255;
159    pal[1].g = pal[1].b = 0;
160 
161    /* copy the desktop palette */
162    for (i=1; i<64; i++)
163       pal[i] = desktop_palette[i];
164 
165    /* make a blue gradient */
166    for (i=64; i<96; i++) {
167       pal[i].b = (i-64)*2;
168       pal[i].g = pal[i].r = 0;
169    }
170 
171    /* make a green gradient */
172    for (i=96; i<128; i++) {
173       pal[i].g = (i-96)*2;
174       pal[i].r = pal[i].b = 0;
175    }
176 
177    /* set the graphics mode */
178    if (set_gfx_mode(GFX_SAFE, 320, 200, 0, 0) != 0) {
179       set_gfx_mode(GFX_TEXT, 0, 0, 0, 0);
180       allegro_message("Unable to set any graphic mode\n%s\n", allegro_error);
181       return 1;
182    }
183    set_palette(desktop_palette);
184 
185    w = SCREEN_W;
186    h = SCREEN_H;
187    bpp = bitmap_color_depth(screen);
188    if (!gfx_mode_select_ex(&c, &w, &h, &bpp)) {
189       allegro_exit();
190       return 1;
191    }
192 
193    set_color_depth(bpp);
194 
195    if (set_gfx_mode(c, w, h, 0, 0) != 0) {
196       set_gfx_mode(GFX_TEXT, 0, 0, 0, 0);
197       allegro_message("Error setting graphics mode\n%s\n", allegro_error);
198       return 1;
199    }
200 
201    set_palette_range(pal, 0, 127, FALSE);
202 
203    /* double buffer the animation and create the Z-buffer */
204    buffer = create_bitmap(SCREEN_W, SCREEN_H);
205    zbuf = create_zbuffer(buffer);
206    set_zbuffer(zbuf);
207 
208    /* set up the viewport for the perspective projection */
209    set_projection_viewport(0, 0, SCREEN_W, SCREEN_H);
210 
211    /* compute rotations and speed rotation */
212    rx1 = ry1 = rz1 = 0.;
213    rx2 = ry2 = rz2 = 0.;
214 
215    drx1 = ((AL_RAND() & 31) - 16) / 4.;
216    dry1 = ((AL_RAND() & 31) - 16) / 4.;
217    drz1 = ((AL_RAND() & 31) - 16) / 4.;
218 
219    drx2 = ((AL_RAND() & 31) - 16) / 4.;
220    dry2 = ((AL_RAND() & 31) - 16) / 4.;
221    drz2 = ((AL_RAND() & 31) - 16) / 4.;
222 
223    /* set the transformation matrices */
224    get_transformation_matrix_f(&matrix1, 1., rx1, ry1, rz1, tx, 0., tz1);
225    get_transformation_matrix_f(&matrix2, 1., rx2, ry2, rz2, -tx, 0., tz2);
226 
227    /* set colors */
228    for (i=0; i<8; i++) {
229       x1[i].c = palette_color[cube1[i].c];
230       x2[i].c = palette_color[cube2[i].c];
231    }
232 
233    /* main loop */
234    while(1) {
235       clear_bitmap(buffer);
236       clear_zbuffer(zbuf, 0.);
237 
238       anim_cube(&matrix1, &matrix2, x1, x2);
239       draw_cube(buffer, x1, x2);
240 
241       /* update transformation matrices */
242       rx1 += drx1;
243       ry1 += dry1;
244       rz1 += drz1;
245       rx2 += drx2;
246       ry2 += dry2;
247       rz2 += drz2;
248       get_transformation_matrix_f(&matrix1, 1., rx1, ry1, rz1, tx, 0., tz1);
249       get_transformation_matrix_f(&matrix2, 1., rx2, ry2, rz2, -tx, 0., tz2);
250 
251       textprintf_ex(buffer, font, 10, 1, palette_color[1], 0,
252 		    "Z-buffered polygons (%.1f fps)", fps);
253 
254       vsync();
255       blit(buffer, screen, 0, 0, 0, 0, SCREEN_W, SCREEN_H);
256       frame++;
257 
258       if (t > 100) {
259 	 fps = (100. * frame) / t;
260 	 t = 0;
261 	 frame = 0;
262       }
263 
264       if (keypressed()){
265 	 if ((readkey() & 0xFF) == 27)
266 	    break;
267       }
268    }
269 
270    destroy_bitmap(buffer);
271    destroy_zbuffer(zbuf);
272 
273    return 0;
274 }
275 
276 END_OF_MAIN()
277