1 /*
2 * Example program for the Allegro library, by Shawn Hargreaves.
3 *
4 * This program demonstrates how to use the 3d matrix functions.
5 * It isn't a very elegant or efficient piece of code, but it
6 * does show the stuff in action. It is left to the reader as
7 * an exercise to design a proper model structure and rendering
8 * pipeline: after all, the best way to do that sort of stuff
9 * varies hugely from one game to another.
10 *
11 * The example first shows a screen resolution selection dialog.
12 * Then, a number of bouncing 3d cubes are animated. Pressing
13 * a key modifies the rendering of the cubes, which can be
14 * wireframe, the more complex transparent perspective correct
15 * texture mapped version, and many other.
16 */
17
18
19 #include <allegro.h>
20
21
22
23 #define NUM_SHAPES 8 /* number of bouncing cubes */
24
25 #define NUM_VERTICES 8 /* a cube has eight corners */
26 #define NUM_FACES 6 /* a cube has six faces */
27
28
29 typedef struct VTX
30 {
31 fixed x, y, z;
32 } VTX;
33
34
35 typedef struct QUAD /* four vertices makes a quad */
36 {
37 VTX *vtxlist;
38 int v1, v2, v3, v4;
39 } QUAD;
40
41
42 typedef struct SHAPE /* store position of a shape */
43 {
44 fixed x, y, z; /* x, y, z position */
45 fixed rx, ry, rz; /* rotations */
46 fixed dz; /* speed of movement */
47 fixed drx, dry, drz; /* speed of rotation */
48 } SHAPE;
49
50
51 VTX points[] = /* a cube, centered on the origin */
52 {
53 /* vertices of the cube */
54 { -32 << 16, -32 << 16, -32 << 16 },
55 { -32 << 16, 32 << 16, -32 << 16 },
56 { 32 << 16, 32 << 16, -32 << 16 },
57 { 32 << 16, -32 << 16, -32 << 16 },
58 { -32 << 16, -32 << 16, 32 << 16 },
59 { -32 << 16, 32 << 16, 32 << 16 },
60 { 32 << 16, 32 << 16, 32 << 16 },
61 { 32 << 16, -32 << 16, 32 << 16 },
62 };
63
64
65 QUAD faces[] = /* group the vertices into polygons */
66 {
67 { points, 0, 3, 2, 1 },
68 { points, 4, 5, 6, 7 },
69 { points, 0, 1, 5, 4 },
70 { points, 2, 3, 7, 6 },
71 { points, 0, 4, 7, 3 },
72 { points, 1, 2, 6, 5 }
73 };
74
75
76 SHAPE shapes[NUM_SHAPES]; /* a list of shapes */
77
78
79 /* somewhere to put translated vertices */
80 VTX output_points[NUM_VERTICES * NUM_SHAPES];
81 QUAD output_faces[NUM_FACES * NUM_SHAPES];
82
83
84 enum {
85 wireframe,
86 flat,
87 gcol,
88 grgb,
89 atex,
90 ptex,
91 atex_mask,
92 ptex_mask,
93 atex_lit,
94 ptex_lit,
95 atex_mask_lit,
96 ptex_mask_lit,
97 atex_trans,
98 ptex_trans,
99 atex_mask_trans,
100 ptex_mask_trans,
101 last_mode
102 } render_mode = wireframe;
103
104
105 int render_type[] =
106 {
107 0,
108 POLYTYPE_FLAT,
109 POLYTYPE_GCOL,
110 POLYTYPE_GRGB,
111 POLYTYPE_ATEX,
112 POLYTYPE_PTEX,
113 POLYTYPE_ATEX_MASK,
114 POLYTYPE_PTEX_MASK,
115 POLYTYPE_ATEX_LIT,
116 POLYTYPE_PTEX_LIT,
117 POLYTYPE_ATEX_MASK_LIT,
118 POLYTYPE_PTEX_MASK_LIT,
119 POLYTYPE_ATEX_TRANS,
120 POLYTYPE_PTEX_TRANS,
121 POLYTYPE_ATEX_MASK_TRANS,
122 POLYTYPE_PTEX_MASK_TRANS
123 };
124
125
126 char *mode_desc[] =
127 {
128 "Wireframe",
129 "Flat shaded",
130 "Single color Gouraud shaded",
131 "Gouraud shaded",
132 "Texture mapped",
133 "Perspective correct texture mapped",
134 "Masked texture mapped",
135 "Masked persp. correct texture mapped",
136 "Lit texture map",
137 "Lit persp. correct texture map",
138 "Masked lit texture map",
139 "Masked lit persp. correct texture map",
140 "Transparent texture mapped",
141 "Transparent perspective correct texture mapped",
142 "Transparent masked texture mapped",
143 "Transparent masked persp. correct texture mapped",
144 };
145
146
147 BITMAP *texture;
148
149
150
151 /* initialise shape positions */
init_shapes(void)152 void init_shapes(void)
153 {
154 int c;
155
156 for (c=0; c<NUM_SHAPES; c++) {
157 shapes[c].x = ((AL_RAND() & 255) - 128) << 16;
158 shapes[c].y = ((AL_RAND() & 255) - 128) << 16;
159 shapes[c].z = 768 << 16;
160 shapes[c].rx = 0;
161 shapes[c].ry = 0;
162 shapes[c].rz = 0;
163 shapes[c].dz = ((AL_RAND() & 255) - 8) << 12;
164 shapes[c].drx = ((AL_RAND() & 31) - 16) << 12;
165 shapes[c].dry = ((AL_RAND() & 31) - 16) << 12;
166 shapes[c].drz = ((AL_RAND() & 31) - 16) << 12;
167 }
168 }
169
170
171
172 /* update shape positions */
animate_shapes(void)173 void animate_shapes(void)
174 {
175 int c;
176
177 for (c=0; c<NUM_SHAPES; c++) {
178 shapes[c].z += shapes[c].dz;
179
180 if ((shapes[c].z > itofix(1024)) ||
181 (shapes[c].z < itofix(192)))
182 shapes[c].dz = -shapes[c].dz;
183
184 shapes[c].rx += shapes[c].drx;
185 shapes[c].ry += shapes[c].dry;
186 shapes[c].rz += shapes[c].drz;
187 }
188 }
189
190
191
192 /* translate shapes from 3d world space to 2d screen space */
translate_shapes(void)193 void translate_shapes(void)
194 {
195 int c, d;
196 MATRIX matrix;
197 VTX *outpoint = output_points;
198 QUAD *outface = output_faces;
199
200 for (c=0; c<NUM_SHAPES; c++) {
201 /* build a transformation matrix */
202 get_transformation_matrix(&matrix, itofix(1),
203 shapes[c].rx, shapes[c].ry, shapes[c].rz,
204 shapes[c].x, shapes[c].y, shapes[c].z);
205
206 /* output the vertices */
207 for (d=0; d<NUM_VERTICES; d++) {
208 apply_matrix(&matrix, points[d].x, points[d].y, points[d].z,
209 &outpoint[d].x, &outpoint[d].y, &outpoint[d].z);
210 persp_project(outpoint[d].x, outpoint[d].y, outpoint[d].z,
211 &outpoint[d].x, &outpoint[d].y);
212 }
213
214 /* output the faces */
215 for (d=0; d<NUM_FACES; d++) {
216 outface[d] = faces[d];
217 outface[d].vtxlist = outpoint;
218 }
219
220 outpoint += NUM_VERTICES;
221 outface += NUM_FACES;
222 }
223 }
224
225
226
227 /* draw a line (for wireframe display) */
wire(BITMAP * b,VTX * v1,VTX * v2)228 void wire(BITMAP *b, VTX *v1, VTX *v2)
229 {
230 int col = CLAMP(128, 255 - fixtoi(v1->z+v2->z) / 16, 255);
231 line(b, fixtoi(v1->x), fixtoi(v1->y), fixtoi(v2->x), fixtoi(v2->y),
232 palette_color[col]);
233 }
234
235
236
237 /* draw a quad */
draw_quad(BITMAP * b,VTX * v1,VTX * v2,VTX * v3,VTX * v4,int mode)238 void draw_quad(BITMAP *b, VTX *v1, VTX *v2, VTX *v3, VTX *v4, int mode)
239 {
240 int col;
241
242 /* four vertices */
243 V3D vtx1 = { 0, 0, 0, 0, 0, 0 };
244 V3D vtx2 = { 0, 0, 0, 32<<16, 0, 0 };
245 V3D vtx3 = { 0, 0, 0, 32<<16, 32<<16, 0 };
246 V3D vtx4 = { 0, 0, 0, 0, 32<<16, 0 };
247
248 vtx1.x = v1->x; vtx1.y = v1->y; vtx1.z = v1->z;
249 vtx2.x = v2->x; vtx2.y = v2->y; vtx2.z = v2->z;
250 vtx3.x = v3->x; vtx3.y = v3->y; vtx3.z = v3->z;
251 vtx4.x = v4->x; vtx4.y = v4->y; vtx4.z = v4->z;
252
253 /* cull backfaces */
254 if ((mode != POLYTYPE_ATEX_MASK) && (mode != POLYTYPE_PTEX_MASK) &&
255 (mode != POLYTYPE_ATEX_MASK_LIT) && (mode != POLYTYPE_PTEX_MASK_LIT) &&
256 (polygon_z_normal(&vtx1, &vtx2, &vtx3) < 0))
257 return;
258
259 /* set up the vertex color, differently for each rendering mode */
260 switch (mode) {
261
262 case POLYTYPE_FLAT:
263 col = CLAMP(128, 255 - fixtoi(v1->z+v2->z) / 16, 255);
264 vtx1.c = vtx2.c = vtx3.c = vtx4.c = palette_color[col];
265 break;
266
267 case POLYTYPE_GCOL:
268 vtx1.c = palette_color[0xD0];
269 vtx2.c = palette_color[0x80];
270 vtx3.c = palette_color[0xB0];
271 vtx4.c = palette_color[0xFF];
272 break;
273
274 case POLYTYPE_GRGB:
275 vtx1.c = 0x000000;
276 vtx2.c = 0x7F0000;
277 vtx3.c = 0xFF0000;
278 vtx4.c = 0x7F0000;
279 break;
280
281 case POLYTYPE_ATEX_LIT:
282 case POLYTYPE_PTEX_LIT:
283 case POLYTYPE_ATEX_MASK_LIT:
284 case POLYTYPE_PTEX_MASK_LIT:
285 vtx1.c = CLAMP(0, 255 - fixtoi(v1->z) / 4, 255);
286 vtx2.c = CLAMP(0, 255 - fixtoi(v2->z) / 4, 255);
287 vtx3.c = CLAMP(0, 255 - fixtoi(v3->z) / 4, 255);
288 vtx4.c = CLAMP(0, 255 - fixtoi(v4->z) / 4, 255);
289 break;
290 }
291
292 /* draw the quad */
293 quad3d(b, mode, texture, &vtx1, &vtx2, &vtx3, &vtx4);
294 }
295
296
297
298 /* callback for qsort() */
quad_cmp(const void * e1,const void * e2)299 int quad_cmp(const void *e1, const void *e2)
300 {
301 QUAD *q1 = (QUAD *)e1;
302 QUAD *q2 = (QUAD *)e2;
303
304 fixed d1 = q1->vtxlist[q1->v1].z + q1->vtxlist[q1->v2].z +
305 q1->vtxlist[q1->v3].z + q1->vtxlist[q1->v4].z;
306
307 fixed d2 = q2->vtxlist[q2->v1].z + q2->vtxlist[q2->v2].z +
308 q2->vtxlist[q2->v3].z + q2->vtxlist[q2->v4].z;
309
310 return d2 - d1;
311 }
312
313
314
315 /* draw the shapes calculated by translate_shapes() */
draw_shapes(BITMAP * b)316 void draw_shapes(BITMAP *b)
317 {
318 int c;
319 QUAD *face = output_faces;
320 VTX *v1, *v2, *v3, *v4;
321
322 /* depth sort */
323 qsort(output_faces, NUM_FACES * NUM_SHAPES, sizeof(QUAD), quad_cmp);
324
325 for (c=0; c < NUM_FACES * NUM_SHAPES; c++) {
326 /* find the vertices used by the face */
327 v1 = face->vtxlist + face->v1;
328 v2 = face->vtxlist + face->v2;
329 v3 = face->vtxlist + face->v3;
330 v4 = face->vtxlist + face->v4;
331
332 /* draw the face */
333 if (render_mode == wireframe) {
334 wire(b, v1, v2);
335 wire(b, v2, v3);
336 wire(b, v3, v4);
337 wire(b, v4, v1);
338 }
339 else {
340 draw_quad(b, v1, v2, v3, v4, render_type[render_mode]);
341 }
342
343 face++;
344 }
345 }
346
347
348
349 /* RGB -> color mapping table. Not needed, but speeds things up */
350 RGB_MAP rgb_table;
351
352
353 /* lighting color mapping table */
354 COLOR_MAP light_table;
355
356 /* transparency color mapping table */
357 COLOR_MAP trans_table;
358
359
360
main(void)361 int main(void)
362 {
363 BITMAP *buffer;
364 PALETTE pal;
365 int c, w, h, bpp;
366 int last_retrace_count;
367
368 if (allegro_init() != 0)
369 return 1;
370 install_keyboard();
371 install_mouse();
372 install_timer();
373
374 /* color 0 = black */
375 pal[0].r = pal[0].g = pal[0].b = 0;
376
377 /* copy the desktop palette */
378 for (c=1; c<64; c++)
379 pal[c] = desktop_palette[c];
380
381 /* make a red gradient */
382 for (c=64; c<96; c++) {
383 pal[c].r = (c-64)*2;
384 pal[c].g = pal[c].b = 0;
385 }
386
387 /* make a green gradient */
388 for (c=96; c<128; c++) {
389 pal[c].g = (c-96)*2;
390 pal[c].r = pal[c].b = 0;
391 }
392
393 /* set up a greyscale in the top half of the palette */
394 for (c=128; c<256; c++)
395 pal[c].r = pal[c].g = pal[c].b = (c-128)/2;
396
397 /* build rgb_map table */
398 create_rgb_table(&rgb_table, pal, NULL);
399 rgb_map = &rgb_table;
400
401 /* build a lighting table */
402 create_light_table(&light_table, pal, 0, 0, 0, NULL);
403 color_map = &light_table;
404
405 /* build a transparency table */
406 /* textures are 25% transparent (75% opaque) */
407 create_trans_table(&trans_table, pal, 192, 192, 192, NULL);
408
409 /* set up the truecolor blending functions */
410 /* textures are 25% transparent (75% opaque) */
411 set_trans_blender(0, 0, 0, 192);
412
413 /* set the graphics mode */
414 if (set_gfx_mode(GFX_SAFE, 320, 200, 0, 0) != 0) {
415 set_gfx_mode(GFX_TEXT, 0, 0, 0, 0);
416 allegro_message("Unable to set any graphic mode\n%s\n", allegro_error);
417 return 1;
418 }
419 set_palette(desktop_palette);
420
421 c = GFX_AUTODETECT;
422 w = SCREEN_W;
423 h = SCREEN_H;
424 bpp = bitmap_color_depth(screen);
425 if (!gfx_mode_select_ex(&c, &w, &h, &bpp)) {
426 allegro_exit();
427 return 1;
428 }
429
430 set_color_depth(bpp);
431
432 if (set_gfx_mode(c, w, h, 0, 0) != 0) {
433 set_gfx_mode(GFX_TEXT, 0, 0, 0, 0);
434 allegro_message("Error setting graphics mode\n%s\n", allegro_error);
435 return 1;
436 }
437
438 set_palette(pal);
439
440 /* make a bitmap for use as a texture map */
441 texture = create_bitmap(32, 32);
442 clear_to_color(texture, bitmap_mask_color(texture));
443 line(texture, 0, 0, 31, 31, palette_color[1]);
444 line(texture, 0, 31, 31, 0, palette_color[1]);
445 rect(texture, 0, 0, 31, 31, palette_color[1]);
446 textout_ex(texture, font, "dead", 0, 0, palette_color[2], -1);
447 textout_ex(texture, font, "pigs", 0, 8, palette_color[2], -1);
448 textout_ex(texture, font, "cant", 0, 16, palette_color[2], -1);
449 textout_ex(texture, font, "fly.", 0, 24, palette_color[2], -1);
450
451 /* double buffer the animation */
452 buffer = create_bitmap(SCREEN_W, SCREEN_H);
453
454 /* set up the viewport for the perspective projection */
455 set_projection_viewport(0, 0, SCREEN_W, SCREEN_H);
456
457 /* initialise the bouncing shapes */
458 init_shapes();
459
460 last_retrace_count = retrace_count;
461
462 for (;;) {
463 clear_bitmap(buffer);
464
465 while (last_retrace_count < retrace_count) {
466 animate_shapes();
467 last_retrace_count++;
468 }
469
470 translate_shapes();
471 draw_shapes(buffer);
472
473 textprintf_ex(buffer, font, 0, 0, palette_color[192], -1, "%s, %d bpp",
474 mode_desc[render_mode], bitmap_color_depth(screen));
475 textout_ex(buffer, font, "Press a key to change", 0, 12,
476 palette_color[192], -1);
477
478 vsync();
479 blit(buffer, screen, 0, 0, 0, 0, SCREEN_W, SCREEN_H);
480
481 if (keypressed()) {
482 if ((readkey() & 0xFF) == 27)
483 break;
484 else {
485 render_mode++;
486 if (render_mode >= last_mode) {
487 render_mode = wireframe;
488 color_map = &light_table;
489 }
490 if (render_type[render_mode] >= POLYTYPE_ATEX_TRANS)
491 color_map = &trans_table;
492 }
493 }
494 }
495
496 destroy_bitmap(buffer);
497 destroy_bitmap(texture);
498
499 return 0;
500 }
501
502 END_OF_MAIN()
503