1 /* ______ ___ ___
2 * /\ _ \ /\_ \ /\_ \
3 * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___
4 * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\
5 * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \
6 * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
7 * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
8 * /\____/
9 * \_/__/
10 *
11 * The 3d polygon rasteriser.
12 *
13 * By Shawn Hargreaves.
14 *
15 * Hicolor support added by Przemek Podsiadly. Complete support for
16 * all drawing modes in every color depth MMX optimisations and z-buffer
17 * added by Calin Andrian. Subpixel and subtexel accuracy, triangle
18 * functions and speed enhancements added by Bertrand Coconnier.
19 * Functions adapted to handle two coincident vertices by Ben Davis.
20 *
21 * See readme.txt for copyright information.
22 */
23
24
25 #include <limits.h>
26 #include <float.h>
27
28 #include "allegro.h"
29 #include "allegro/internal/aintern.h"
30
31 #if defined ALLEGRO_ASMCAPA_HEADER && !defined ALLEGRO_NO_ASM
32 #include ALLEGRO_ASMCAPA_HEADER
33 #endif
34
35 #ifdef ALLEGRO_MMX
36
37 /* for use by iscan.s */
38 uint32_t _mask_mmx_15[] = { 0x03E0001F, 0x007C };
39 uint32_t _mask_mmx_16[] = { 0x07E0001F, 0x00F8 };
40
41 #endif
42
43
_poly_scanline_dummy(uintptr_t addr,int w,POLYGON_SEGMENT * info)44 void _poly_scanline_dummy(uintptr_t addr, int w, POLYGON_SEGMENT *info) { }
45
46 ZBUFFER *_zbuffer = NULL;
47
48 SCANLINE_FILLER _optim_alternative_drawer;
49
50
51 /* _fill_3d_edge_structure:
52 * Polygon helper function: initialises an edge structure for the 3d
53 * rasterising code, using fixed point vertex structures. Returns 1 on
54 * success, or 0 if the edge is horizontal or clipped out of existence.
55 */
_fill_3d_edge_structure(POLYGON_EDGE * edge,AL_CONST V3D * v1,AL_CONST V3D * v2,int flags,BITMAP * bmp)56 int _fill_3d_edge_structure(POLYGON_EDGE *edge, AL_CONST V3D *v1, AL_CONST V3D *v2, int flags, BITMAP *bmp)
57 {
58 int r1, r2, g1, g2, b1, b2;
59 fixed h, step;
60
61 /* swap vertices if they are the wrong way up */
62 if (v2->y < v1->y) {
63 AL_CONST V3D *vt;
64
65 vt = v1;
66 v1 = v2;
67 v2 = vt;
68 }
69
70 /* set up screen rasterising parameters */
71 edge->top = fixceil(v1->y);
72 edge->bottom = fixceil(v2->y) - 1;
73
74 if (edge->bottom < edge->top) return 0;
75
76 h = v2->y - v1->y;
77 step = (edge->top << 16) - v1->y;
78
79 edge->dx = fixdiv(v2->x - v1->x, h);
80 edge->x = v1->x + fixmul(step, edge->dx);
81
82 edge->prev = NULL;
83 edge->next = NULL;
84 edge->w = 0;
85
86 if (flags & INTERP_Z) {
87 float h1 = 65536. / h;
88 float step_f = fixtof(step);
89
90 /* Z (depth) interpolation */
91 float z1 = 65536. / v1->z;
92 float z2 = 65536. / v2->z;
93
94 edge->dat.dz = (z2 - z1) * h1;
95 edge->dat.z = z1 + edge->dat.dz * step_f;
96
97 if (flags & INTERP_FLOAT_UV) {
98 /* floating point (perspective correct) texture interpolation */
99 float fu1 = v1->u * z1;
100 float fv1 = v1->v * z1;
101 float fu2 = v2->u * z2;
102 float fv2 = v2->v * z2;
103
104 edge->dat.dfu = (fu2 - fu1) * h1;
105 edge->dat.dfv = (fv2 - fv1) * h1;
106 edge->dat.fu = fu1 + edge->dat.dfu * step_f;
107 edge->dat.fv = fv1 + edge->dat.dfv * step_f;
108 }
109 }
110
111 if (flags & INTERP_FLAT) {
112 /* if clipping is enabled then clip edge */
113 if (bmp->clip) {
114 if (edge->top < bmp->ct) {
115 edge->x += (bmp->ct - edge->top) * edge->dx;
116 edge->top = bmp->ct;
117 }
118
119 if (edge->bottom >= bmp->cb)
120 edge->bottom = bmp->cb - 1;
121 }
122
123 return (edge->bottom >= edge->top);
124 }
125
126 if (flags & INTERP_1COL) {
127 /* single color shading interpolation */
128 edge->dat.dc = fixdiv(itofix(v2->c - v1->c), h);
129 edge->dat.c = itofix(v1->c) + fixmul(step, edge->dat.dc);
130 }
131
132 if (flags & INTERP_3COL) {
133 /* RGB shading interpolation */
134 if (flags & COLOR_TO_RGB) {
135 AL_CONST int coldepth = bitmap_color_depth(bmp);
136 r1 = getr_depth(coldepth, v1->c);
137 r2 = getr_depth(coldepth, v2->c);
138 g1 = getg_depth(coldepth, v1->c);
139 g2 = getg_depth(coldepth, v2->c);
140 b1 = getb_depth(coldepth, v1->c);
141 b2 = getb_depth(coldepth, v2->c);
142 }
143 else {
144 r1 = (v1->c >> 16) & 0xFF;
145 r2 = (v2->c >> 16) & 0xFF;
146 g1 = (v1->c >> 8) & 0xFF;
147 g2 = (v2->c >> 8) & 0xFF;
148 b1 = v1->c & 0xFF;
149 b2 = v2->c & 0xFF;
150 }
151
152 edge->dat.dr = fixdiv(itofix(r2 - r1), h);
153 edge->dat.dg = fixdiv(itofix(g2 - g1), h);
154 edge->dat.db = fixdiv(itofix(b2 - b1), h);
155 edge->dat.r = itofix(r1) + fixmul(step, edge->dat.dr);
156 edge->dat.g = itofix(g1) + fixmul(step, edge->dat.dg);
157 edge->dat.b = itofix(b1) + fixmul(step, edge->dat.db);
158 }
159
160 if (flags & INTERP_FIX_UV) {
161 /* fixed point (affine) texture interpolation */
162 edge->dat.du = fixdiv(v2->u - v1->u, h);
163 edge->dat.dv = fixdiv(v2->v - v1->v, h);
164 edge->dat.u = v1->u + fixmul(step, edge->dat.du);
165 edge->dat.v = v1->v + fixmul(step, edge->dat.dv);
166 }
167
168 /* if clipping is enabled then clip edge */
169 if (bmp->clip) {
170 if (edge->top < bmp->ct) {
171 int gap = bmp->ct - edge->top;
172 edge->top = bmp->ct;
173 edge->x += gap * edge->dx;
174 _clip_polygon_segment(&(edge->dat), itofix(gap), flags);
175 }
176
177 if (edge->bottom >= bmp->cb)
178 edge->bottom = bmp->cb - 1;
179 }
180
181 return (edge->bottom >= edge->top);
182 }
183
184
185
186 /* _fill_3d_edge_structure_f:
187 * Polygon helper function: initialises an edge structure for the 3d
188 * rasterising code, using floating point vertex structures. Returns 1 on
189 * success, or 0 if the edge is horizontal or clipped out of existence.
190 */
_fill_3d_edge_structure_f(POLYGON_EDGE * edge,AL_CONST V3D_f * v1,AL_CONST V3D_f * v2,int flags,BITMAP * bmp)191 int _fill_3d_edge_structure_f(POLYGON_EDGE *edge, AL_CONST V3D_f *v1, AL_CONST V3D_f *v2, int flags, BITMAP *bmp)
192 {
193 int r1, r2, g1, g2, b1, b2;
194 fixed h, step;
195 float h1;
196
197 /* swap vertices if they are the wrong way up */
198 if (v2->y < v1->y) {
199 AL_CONST V3D_f *vt;
200
201 vt = v1;
202 v1 = v2;
203 v2 = vt;
204 }
205
206 /* set up screen rasterising parameters */
207 edge->top = fixceil(ftofix(v1->y));
208 edge->bottom = fixceil(ftofix(v2->y)) - 1;
209
210 if (edge->bottom < edge->top) return 0;
211
212 h1 = 1.0 / (v2->y - v1->y);
213 h = ftofix(v2->y - v1->y);
214 step = (edge->top << 16) - ftofix(v1->y);
215
216 edge->dx = ftofix((v2->x - v1->x) * h1);
217 edge->x = ftofix(v1->x) + fixmul(step, edge->dx);
218
219 edge->prev = NULL;
220 edge->next = NULL;
221 edge->w = 0;
222
223 if (flags & INTERP_Z) {
224 float step_f = fixtof(step);
225
226 /* Z (depth) interpolation */
227 float z1 = 1. / v1->z;
228 float z2 = 1. / v2->z;
229
230 edge->dat.dz = (z2 - z1) * h1;
231 edge->dat.z = z1 + edge->dat.dz * step_f;
232
233 if (flags & INTERP_FLOAT_UV) {
234 /* floating point (perspective correct) texture interpolation */
235 float fu1 = v1->u * z1 * 65536.;
236 float fv1 = v1->v * z1 * 65536.;
237 float fu2 = v2->u * z2 * 65536.;
238 float fv2 = v2->v * z2 * 65536.;
239
240 edge->dat.dfu = (fu2 - fu1) * h1;
241 edge->dat.dfv = (fv2 - fv1) * h1;
242 edge->dat.fu = fu1 + edge->dat.dfu * step_f;
243 edge->dat.fv = fv1 + edge->dat.dfv * step_f;
244 }
245 }
246
247 if (flags & INTERP_FLAT) {
248 /* if clipping is enabled then clip edge */
249 if (bmp->clip) {
250 if (edge->top < bmp->ct) {
251 edge->x += (bmp->ct - edge->top) * edge->dx;
252 edge->top = bmp->ct;
253 }
254
255 if (edge->bottom >= bmp->cb)
256 edge->bottom = bmp->cb - 1;
257 }
258
259 return (edge->bottom >= edge->top);
260 }
261
262 if (flags & INTERP_1COL) {
263 /* single color shading interpolation */
264 edge->dat.dc = fixdiv(itofix(v2->c - v1->c), h);
265 edge->dat.c = itofix(v1->c) + fixmul(step, edge->dat.dc);
266 }
267
268 if (flags & INTERP_3COL) {
269 /* RGB shading interpolation */
270 if (flags & COLOR_TO_RGB) {
271 AL_CONST int coldepth = bitmap_color_depth(bmp);
272 r1 = getr_depth(coldepth, v1->c);
273 r2 = getr_depth(coldepth, v2->c);
274 g1 = getg_depth(coldepth, v1->c);
275 g2 = getg_depth(coldepth, v2->c);
276 b1 = getb_depth(coldepth, v1->c);
277 b2 = getb_depth(coldepth, v2->c);
278 }
279 else {
280 r1 = (v1->c >> 16) & 0xFF;
281 r2 = (v2->c >> 16) & 0xFF;
282 g1 = (v1->c >> 8) & 0xFF;
283 g2 = (v2->c >> 8) & 0xFF;
284 b1 = v1->c & 0xFF;
285 b2 = v2->c & 0xFF;
286 }
287
288 edge->dat.dr = fixdiv(itofix(r2 - r1), h);
289 edge->dat.dg = fixdiv(itofix(g2 - g1), h);
290 edge->dat.db = fixdiv(itofix(b2 - b1), h);
291 edge->dat.r = itofix(r1) + fixmul(step, edge->dat.dr);
292 edge->dat.g = itofix(g1) + fixmul(step, edge->dat.dg);
293 edge->dat.b = itofix(b1) + fixmul(step, edge->dat.db);
294 }
295
296 if (flags & INTERP_FIX_UV) {
297 /* fixed point (affine) texture interpolation */
298 edge->dat.du = ftofix((v2->u - v1->u) * h1);
299 edge->dat.dv = ftofix((v2->v - v1->v) * h1);
300 edge->dat.u = ftofix(v1->u) + fixmul(step, edge->dat.du);
301 edge->dat.v = ftofix(v1->v) + fixmul(step, edge->dat.dv);
302 }
303
304 /* if clipping is enabled then clip edge */
305 if (bmp->clip) {
306 if (edge->top < bmp->ct) {
307 int gap = bmp->ct - edge->top;
308 edge->top = bmp->ct;
309 edge->x += gap * edge->dx;
310 _clip_polygon_segment_f(&(edge->dat), gap, flags);
311 }
312
313 if (edge->bottom >= bmp->cb)
314 edge->bottom = bmp->cb - 1;
315 }
316
317 return (edge->bottom >= edge->top);
318 }
319
320
321
322 /* _get_scanline_filler:
323 * Helper function for deciding which rasterisation function and
324 * interpolation flags we should use for a specific polygon type.
325 */
_get_scanline_filler(int type,int * flags,POLYGON_SEGMENT * info,BITMAP * texture,BITMAP * bmp)326 SCANLINE_FILLER _get_scanline_filler(int type, int *flags, POLYGON_SEGMENT *info, BITMAP *texture, BITMAP *bmp)
327 {
328 typedef struct POLYTYPE_INFO
329 {
330 SCANLINE_FILLER filler;
331 SCANLINE_FILLER alternative;
332 } POLYTYPE_INFO;
333
334 static int polytype_interp_pal[] =
335 {
336 INTERP_FLAT,
337 INTERP_1COL,
338 INTERP_3COL,
339 INTERP_FIX_UV,
340 INTERP_Z | INTERP_FLOAT_UV | OPT_FLOAT_UV_TO_FIX,
341 INTERP_FIX_UV,
342 INTERP_Z | INTERP_FLOAT_UV | OPT_FLOAT_UV_TO_FIX,
343 INTERP_FIX_UV | INTERP_1COL,
344 INTERP_Z | INTERP_FLOAT_UV | INTERP_1COL | OPT_FLOAT_UV_TO_FIX,
345 INTERP_FIX_UV | INTERP_1COL,
346 INTERP_Z | INTERP_FLOAT_UV | INTERP_1COL | OPT_FLOAT_UV_TO_FIX,
347 INTERP_FIX_UV,
348 INTERP_Z | INTERP_FLOAT_UV | OPT_FLOAT_UV_TO_FIX,
349 INTERP_FIX_UV,
350 INTERP_Z | INTERP_FLOAT_UV | OPT_FLOAT_UV_TO_FIX
351 };
352
353 static int polytype_interp_tc[] =
354 {
355 INTERP_FLAT,
356 INTERP_3COL | COLOR_TO_RGB,
357 INTERP_3COL,
358 INTERP_FIX_UV,
359 INTERP_Z | INTERP_FLOAT_UV | OPT_FLOAT_UV_TO_FIX,
360 INTERP_FIX_UV,
361 INTERP_Z | INTERP_FLOAT_UV | OPT_FLOAT_UV_TO_FIX,
362 INTERP_FIX_UV | INTERP_1COL,
363 INTERP_Z | INTERP_FLOAT_UV | INTERP_1COL | OPT_FLOAT_UV_TO_FIX,
364 INTERP_FIX_UV | INTERP_1COL,
365 INTERP_Z | INTERP_FLOAT_UV | INTERP_1COL | OPT_FLOAT_UV_TO_FIX,
366 INTERP_FIX_UV,
367 INTERP_Z | INTERP_FLOAT_UV | OPT_FLOAT_UV_TO_FIX,
368 INTERP_FIX_UV,
369 INTERP_Z | INTERP_FLOAT_UV | OPT_FLOAT_UV_TO_FIX
370 };
371
372 #ifdef ALLEGRO_COLOR8
373 static POLYTYPE_INFO polytype_info8[] =
374 {
375 { _poly_scanline_dummy, NULL },
376 { _poly_scanline_gcol8, NULL },
377 { _poly_scanline_grgb8, NULL },
378 { _poly_scanline_atex8, NULL },
379 { _poly_scanline_ptex8, _poly_scanline_atex8 },
380 { _poly_scanline_atex_mask8, NULL },
381 { _poly_scanline_ptex_mask8, _poly_scanline_atex_mask8 },
382 { _poly_scanline_atex_lit8, NULL },
383 { _poly_scanline_ptex_lit8, _poly_scanline_atex_lit8 },
384 { _poly_scanline_atex_mask_lit8, NULL },
385 { _poly_scanline_ptex_mask_lit8, _poly_scanline_atex_mask_lit8 },
386 { _poly_scanline_atex_trans8, NULL },
387 { _poly_scanline_ptex_trans8, _poly_scanline_atex_trans8 },
388 { _poly_scanline_atex_mask_trans8, NULL },
389 { _poly_scanline_ptex_mask_trans8, _poly_scanline_atex_mask_trans8 }
390 };
391
392 #ifdef ALLEGRO_MMX
393 static POLYTYPE_INFO polytype_info8x[] =
394 {
395 { NULL, NULL },
396 { NULL, NULL },
397 { _poly_scanline_grgb8x, NULL },
398 { NULL, NULL },
399 { NULL, NULL },
400 { NULL, NULL },
401 { NULL, NULL },
402 { NULL, NULL },
403 { NULL, NULL },
404 { NULL, NULL },
405 { NULL, NULL },
406 { NULL, NULL },
407 { NULL, NULL },
408 { NULL, NULL },
409 { NULL, NULL }
410 };
411
412 static POLYTYPE_INFO polytype_info8d[] =
413 {
414 { NULL, NULL },
415 { NULL, NULL },
416 { NULL, NULL },
417 { NULL, NULL },
418 { NULL, NULL },
419 { NULL, NULL },
420 { NULL, NULL },
421 { NULL, NULL },
422 { NULL, NULL },
423 { NULL, NULL },
424 { NULL, NULL },
425 { NULL, NULL },
426 { NULL, NULL },
427 { NULL, NULL },
428 { NULL, NULL }
429 };
430 #endif
431 #endif
432
433 #ifdef ALLEGRO_COLOR16
434 static POLYTYPE_INFO polytype_info15[] =
435 {
436 { _poly_scanline_dummy, NULL },
437 { _poly_scanline_grgb15, NULL },
438 { _poly_scanline_grgb15, NULL },
439 { _poly_scanline_atex16, NULL },
440 { _poly_scanline_ptex16, _poly_scanline_atex16 },
441 { _poly_scanline_atex_mask15, NULL },
442 { _poly_scanline_ptex_mask15, _poly_scanline_atex_mask15 },
443 { _poly_scanline_atex_lit15, NULL },
444 { _poly_scanline_ptex_lit15, _poly_scanline_atex_lit15 },
445 { _poly_scanline_atex_mask_lit15, NULL },
446 { _poly_scanline_ptex_mask_lit15, _poly_scanline_atex_mask_lit15 },
447 { _poly_scanline_atex_trans15, NULL },
448 { _poly_scanline_ptex_trans15, _poly_scanline_atex_trans15 },
449 { _poly_scanline_atex_mask_trans15, NULL },
450 { _poly_scanline_ptex_mask_trans15, _poly_scanline_atex_mask_trans15 }
451 };
452
453 #ifdef ALLEGRO_MMX
454 static POLYTYPE_INFO polytype_info15x[] =
455 {
456 { NULL, NULL },
457 { _poly_scanline_grgb15x, NULL },
458 { _poly_scanline_grgb15x, NULL },
459 { NULL, NULL },
460 { NULL, NULL },
461 { NULL, NULL },
462 { NULL, NULL },
463 { _poly_scanline_atex_lit15x, NULL },
464 { _poly_scanline_ptex_lit15x, _poly_scanline_atex_lit15x },
465 { _poly_scanline_atex_mask_lit15x, NULL },
466 { _poly_scanline_ptex_mask_lit15x, _poly_scanline_atex_mask_lit15x },
467 { NULL, NULL },
468 { NULL, NULL },
469 { NULL, NULL },
470 { NULL, NULL }
471 };
472
473 static POLYTYPE_INFO polytype_info15d[] =
474 {
475 { NULL, NULL },
476 { NULL, NULL },
477 { NULL, NULL },
478 { NULL, NULL },
479 { NULL, NULL },
480 { NULL, NULL },
481 { NULL, NULL },
482 { NULL, NULL },
483 { _poly_scanline_ptex_lit15d, _poly_scanline_atex_lit15x },
484 { NULL, NULL },
485 { _poly_scanline_ptex_mask_lit15d, _poly_scanline_atex_mask_lit15x },
486 { NULL, NULL },
487 { NULL, NULL },
488 { NULL, NULL },
489 { NULL, NULL }
490 };
491 #endif
492
493 static POLYTYPE_INFO polytype_info16[] =
494 {
495 { _poly_scanline_dummy, NULL },
496 { _poly_scanline_grgb16, NULL },
497 { _poly_scanline_grgb16, NULL },
498 { _poly_scanline_atex16, NULL },
499 { _poly_scanline_ptex16, _poly_scanline_atex16 },
500 { _poly_scanline_atex_mask16, NULL },
501 { _poly_scanline_ptex_mask16, _poly_scanline_atex_mask16 },
502 { _poly_scanline_atex_lit16, NULL },
503 { _poly_scanline_ptex_lit16, _poly_scanline_atex_lit16 },
504 { _poly_scanline_atex_mask_lit16, NULL },
505 { _poly_scanline_ptex_mask_lit16, _poly_scanline_atex_mask_lit16 },
506 { _poly_scanline_atex_trans16, NULL },
507 { _poly_scanline_ptex_trans16, _poly_scanline_atex_trans16 },
508 { _poly_scanline_atex_mask_trans16, NULL },
509 { _poly_scanline_ptex_mask_trans16, _poly_scanline_atex_mask_trans16 }
510 };
511
512 #ifdef ALLEGRO_MMX
513 static POLYTYPE_INFO polytype_info16x[] =
514 {
515 { NULL, NULL },
516 { _poly_scanline_grgb16x, NULL },
517 { _poly_scanline_grgb16x, NULL },
518 { NULL, NULL },
519 { NULL, NULL },
520 { NULL, NULL },
521 { NULL, NULL },
522 { _poly_scanline_atex_lit16x, NULL },
523 { _poly_scanline_ptex_lit16x, _poly_scanline_atex_lit16x },
524 { _poly_scanline_atex_mask_lit16x, NULL },
525 { _poly_scanline_ptex_mask_lit16x, _poly_scanline_atex_mask_lit16x },
526 { NULL, NULL },
527 { NULL, NULL },
528 { NULL, NULL },
529 { NULL, NULL }
530 };
531
532 static POLYTYPE_INFO polytype_info16d[] =
533 {
534 { NULL, NULL },
535 { NULL, NULL },
536 { NULL, NULL },
537 { NULL, NULL },
538 { NULL, NULL },
539 { NULL, NULL },
540 { NULL, NULL },
541 { NULL, NULL },
542 { _poly_scanline_ptex_lit16d, _poly_scanline_atex_lit16x },
543 { NULL, NULL },
544 { _poly_scanline_ptex_mask_lit16d, _poly_scanline_atex_mask_lit16x },
545 { NULL, NULL },
546 { NULL, NULL },
547 { NULL, NULL },
548 { NULL, NULL }
549 };
550 #endif
551 #endif
552
553 #ifdef ALLEGRO_COLOR24
554 static POLYTYPE_INFO polytype_info24[] =
555 {
556 { _poly_scanline_dummy, NULL },
557 { _poly_scanline_grgb24, NULL },
558 { _poly_scanline_grgb24, NULL },
559 { _poly_scanline_atex24, NULL },
560 { _poly_scanline_ptex24, _poly_scanline_atex24 },
561 { _poly_scanline_atex_mask24, NULL },
562 { _poly_scanline_ptex_mask24, _poly_scanline_atex_mask24 },
563 { _poly_scanline_atex_lit24, NULL },
564 { _poly_scanline_ptex_lit24, _poly_scanline_atex_lit24 },
565 { _poly_scanline_atex_mask_lit24, NULL },
566 { _poly_scanline_ptex_mask_lit24, _poly_scanline_atex_mask_lit24 },
567 { _poly_scanline_atex_trans24, NULL },
568 { _poly_scanline_ptex_trans24, _poly_scanline_atex_trans24 },
569 { _poly_scanline_atex_mask_trans24, NULL },
570 { _poly_scanline_ptex_mask_trans24, _poly_scanline_atex_mask_trans24 }
571 };
572
573 #ifdef ALLEGRO_MMX
574 static POLYTYPE_INFO polytype_info24x[] =
575 {
576 { NULL, NULL },
577 { _poly_scanline_grgb24x, NULL },
578 { _poly_scanline_grgb24x, NULL },
579 { NULL, NULL },
580 { NULL, NULL },
581 { NULL, NULL },
582 { NULL, NULL },
583 { _poly_scanline_atex_lit24x, NULL },
584 { _poly_scanline_ptex_lit24x, _poly_scanline_atex_lit24x },
585 { _poly_scanline_atex_mask_lit24x, NULL },
586 { _poly_scanline_ptex_mask_lit24x, _poly_scanline_atex_mask_lit24x },
587 { NULL, NULL },
588 { NULL, NULL },
589 { NULL, NULL },
590 { NULL, NULL }
591 };
592
593 static POLYTYPE_INFO polytype_info24d[] =
594 {
595 { NULL, NULL },
596 { NULL, NULL },
597 { NULL, NULL },
598 { NULL, NULL },
599 { NULL, NULL },
600 { NULL, NULL },
601 { NULL, NULL },
602 { NULL, NULL },
603 { _poly_scanline_ptex_lit24d, _poly_scanline_atex_lit24x },
604 { NULL, NULL },
605 { _poly_scanline_ptex_mask_lit24d, _poly_scanline_atex_mask_lit24x },
606 { NULL, NULL },
607 { NULL, NULL },
608 { NULL, NULL },
609 { NULL, NULL }
610 };
611 #endif
612 #endif
613
614 #ifdef ALLEGRO_COLOR32
615 static POLYTYPE_INFO polytype_info32[] =
616 {
617 { _poly_scanline_dummy, NULL },
618 { _poly_scanline_grgb32, NULL },
619 { _poly_scanline_grgb32, NULL },
620 { _poly_scanline_atex32, NULL },
621 { _poly_scanline_ptex32, _poly_scanline_atex32 },
622 { _poly_scanline_atex_mask32, NULL },
623 { _poly_scanline_ptex_mask32, _poly_scanline_atex_mask32 },
624 { _poly_scanline_atex_lit32, NULL },
625 { _poly_scanline_ptex_lit32, _poly_scanline_atex_lit32 },
626 { _poly_scanline_atex_mask_lit32, NULL },
627 { _poly_scanline_ptex_mask_lit32, _poly_scanline_atex_mask_lit32 },
628 { _poly_scanline_atex_trans32, NULL },
629 { _poly_scanline_ptex_trans32, _poly_scanline_atex_trans32 },
630 { _poly_scanline_atex_mask_trans32, NULL },
631 { _poly_scanline_ptex_mask_trans32, _poly_scanline_atex_mask_trans32 }
632 };
633
634 #ifdef ALLEGRO_MMX
635 static POLYTYPE_INFO polytype_info32x[] =
636 {
637 { NULL, NULL },
638 { _poly_scanline_grgb32x, NULL },
639 { _poly_scanline_grgb32x, NULL },
640 { NULL, NULL },
641 { NULL, NULL },
642 { NULL, NULL },
643 { NULL, NULL },
644 { _poly_scanline_atex_lit32x, NULL },
645 { _poly_scanline_ptex_lit32x, _poly_scanline_atex_lit32x },
646 { _poly_scanline_atex_mask_lit32x, NULL },
647 { _poly_scanline_ptex_mask_lit32x, _poly_scanline_atex_mask_lit32x },
648 { NULL, NULL },
649 { NULL, NULL },
650 { NULL, NULL },
651 { NULL, NULL }
652 };
653
654 static POLYTYPE_INFO polytype_info32d[] =
655 {
656 { NULL, NULL },
657 { NULL, NULL },
658 { NULL, NULL },
659 { NULL, NULL },
660 { NULL, NULL },
661 { NULL, NULL },
662 { NULL, NULL },
663 { NULL, NULL },
664 { _poly_scanline_ptex_lit32d, _poly_scanline_atex_lit32x },
665 { NULL, NULL },
666 { _poly_scanline_ptex_mask_lit32d, _poly_scanline_atex_mask_lit32x },
667 { NULL, NULL },
668 { NULL, NULL },
669 { NULL, NULL },
670 { NULL, NULL }
671 };
672 #endif
673 #endif
674
675 #ifdef ALLEGRO_COLOR8
676 static POLYTYPE_INFO polytype_info8z[] =
677 {
678 { _poly_zbuf_flat8, NULL },
679 { _poly_zbuf_gcol8, NULL },
680 { _poly_zbuf_grgb8, NULL },
681 { _poly_zbuf_atex8, NULL },
682 { _poly_zbuf_ptex8, _poly_zbuf_atex8 },
683 { _poly_zbuf_atex_mask8, NULL },
684 { _poly_zbuf_ptex_mask8, _poly_zbuf_atex_mask8 },
685 { _poly_zbuf_atex_lit8, NULL },
686 { _poly_zbuf_ptex_lit8, _poly_zbuf_atex_lit8 },
687 { _poly_zbuf_atex_mask_lit8, NULL },
688 { _poly_zbuf_ptex_mask_lit8, _poly_zbuf_atex_mask_lit8 },
689 { _poly_zbuf_atex_trans8, NULL },
690 { _poly_zbuf_ptex_trans8, _poly_zbuf_atex_trans8 },
691 { _poly_zbuf_atex_mask_trans8, NULL },
692 { _poly_zbuf_ptex_mask_trans8, _poly_zbuf_atex_mask_trans8 }
693 };
694 #endif
695
696 #ifdef ALLEGRO_COLOR16
697 static POLYTYPE_INFO polytype_info15z[] =
698 {
699 { _poly_zbuf_flat16, NULL },
700 { _poly_zbuf_grgb15, NULL },
701 { _poly_zbuf_grgb15, NULL },
702 { _poly_zbuf_atex16, NULL },
703 { _poly_zbuf_ptex16, _poly_zbuf_atex16 },
704 { _poly_zbuf_atex_mask15, NULL },
705 { _poly_zbuf_ptex_mask15, _poly_zbuf_atex_mask15 },
706 { _poly_zbuf_atex_lit15, NULL },
707 { _poly_zbuf_ptex_lit15, _poly_zbuf_atex_lit15 },
708 { _poly_zbuf_atex_mask_lit15, NULL },
709 { _poly_zbuf_ptex_mask_lit15, _poly_zbuf_atex_mask_lit15 },
710 { _poly_zbuf_atex_trans15, NULL },
711 { _poly_zbuf_ptex_trans15, _poly_zbuf_atex_trans15 },
712 { _poly_zbuf_atex_mask_trans15, NULL },
713 { _poly_zbuf_ptex_mask_trans15, _poly_zbuf_atex_mask_trans15 }
714 };
715
716 static POLYTYPE_INFO polytype_info16z[] =
717 {
718 { _poly_zbuf_flat16, NULL },
719 { _poly_zbuf_grgb16, NULL },
720 { _poly_zbuf_grgb16, NULL },
721 { _poly_zbuf_atex16, NULL },
722 { _poly_zbuf_ptex16, _poly_zbuf_atex16 },
723 { _poly_zbuf_atex_mask16, NULL },
724 { _poly_zbuf_ptex_mask16, _poly_zbuf_atex_mask16 },
725 { _poly_zbuf_atex_lit16, NULL },
726 { _poly_zbuf_ptex_lit16, _poly_zbuf_atex_lit16 },
727 { _poly_zbuf_atex_mask_lit16, NULL },
728 { _poly_zbuf_ptex_mask_lit16, _poly_zbuf_atex_mask_lit16 },
729 { _poly_zbuf_atex_trans16, NULL },
730 { _poly_zbuf_ptex_trans16, _poly_zbuf_atex_trans16 },
731 { _poly_zbuf_atex_mask_trans16, NULL },
732 { _poly_zbuf_ptex_mask_trans16, _poly_zbuf_atex_mask_trans16 }
733 };
734 #endif
735
736 #ifdef ALLEGRO_COLOR24
737 static POLYTYPE_INFO polytype_info24z[] =
738 {
739 { _poly_zbuf_flat24, NULL },
740 { _poly_zbuf_grgb24, NULL },
741 { _poly_zbuf_grgb24, NULL },
742 { _poly_zbuf_atex24, NULL },
743 { _poly_zbuf_ptex24, _poly_zbuf_atex24 },
744 { _poly_zbuf_atex_mask24, NULL },
745 { _poly_zbuf_ptex_mask24, _poly_zbuf_atex_mask24 },
746 { _poly_zbuf_atex_lit24, NULL },
747 { _poly_zbuf_ptex_lit24, _poly_zbuf_atex_lit24 },
748 { _poly_zbuf_atex_mask_lit24, NULL },
749 { _poly_zbuf_ptex_mask_lit24, _poly_zbuf_atex_mask_lit24 },
750 { _poly_zbuf_atex_trans24, NULL },
751 { _poly_zbuf_ptex_trans24, _poly_zbuf_atex_trans24 },
752 { _poly_zbuf_atex_mask_trans24, NULL },
753 { _poly_zbuf_ptex_mask_trans24, _poly_zbuf_atex_mask_trans24 }
754 };
755 #endif
756
757 #ifdef ALLEGRO_COLOR32
758 static POLYTYPE_INFO polytype_info32z[] =
759 {
760 { _poly_zbuf_flat32, NULL },
761 { _poly_zbuf_grgb32, NULL },
762 { _poly_zbuf_grgb32, NULL },
763 { _poly_zbuf_atex32, NULL },
764 { _poly_zbuf_ptex32, _poly_zbuf_atex32 },
765 { _poly_zbuf_atex_mask32, NULL },
766 { _poly_zbuf_ptex_mask32, _poly_zbuf_atex_mask32 },
767 { _poly_zbuf_atex_lit32, NULL },
768 { _poly_zbuf_ptex_lit32, _poly_zbuf_atex_lit32 },
769 { _poly_zbuf_atex_mask_lit32, NULL },
770 { _poly_zbuf_ptex_mask_lit32, _poly_zbuf_atex_mask_lit32 },
771 { _poly_zbuf_atex_trans32, NULL },
772 { _poly_zbuf_ptex_trans32, _poly_zbuf_atex_trans32 },
773 { _poly_zbuf_atex_mask_trans32, NULL },
774 { _poly_zbuf_ptex_mask_trans32, _poly_zbuf_atex_mask_trans32 }
775 };
776 #endif
777
778 int zbuf = type & POLYTYPE_ZBUF;
779
780 int *interpinfo;
781 POLYTYPE_INFO *typeinfo, *typeinfo_zbuf;
782
783 #ifdef ALLEGRO_MMX
784 POLYTYPE_INFO *typeinfo_mmx, *typeinfo_3d;
785 #endif
786
787 switch (bitmap_color_depth(bmp)) {
788
789 #ifdef ALLEGRO_COLOR8
790
791 case 8:
792 interpinfo = polytype_interp_pal;
793 typeinfo = polytype_info8;
794 #ifdef ALLEGRO_MMX
795 typeinfo_mmx = polytype_info8x;
796 typeinfo_3d = polytype_info8d;
797 #endif
798 typeinfo_zbuf = polytype_info8z;
799 break;
800
801 #endif
802
803 #ifdef ALLEGRO_COLOR16
804
805 case 15:
806 interpinfo = polytype_interp_tc;
807 typeinfo = polytype_info15;
808 #ifdef ALLEGRO_MMX
809 typeinfo_mmx = polytype_info15x;
810 typeinfo_3d = polytype_info15d;
811 #endif
812 typeinfo_zbuf = polytype_info15z;
813 break;
814
815 case 16:
816 interpinfo = polytype_interp_tc;
817 typeinfo = polytype_info16;
818 #ifdef ALLEGRO_MMX
819 typeinfo_mmx = polytype_info16x;
820 typeinfo_3d = polytype_info16d;
821 #endif
822 typeinfo_zbuf = polytype_info16z;
823 break;
824
825 #endif
826
827 #ifdef ALLEGRO_COLOR24
828
829 case 24:
830 interpinfo = polytype_interp_tc;
831 typeinfo = polytype_info24;
832 #ifdef ALLEGRO_MMX
833 typeinfo_mmx = polytype_info24x;
834 typeinfo_3d = polytype_info24d;
835 #endif
836 typeinfo_zbuf = polytype_info24z;
837 break;
838
839 #endif
840
841 #ifdef ALLEGRO_COLOR32
842
843 case 32:
844 interpinfo = polytype_interp_tc;
845 typeinfo = polytype_info32;
846 #ifdef ALLEGRO_MMX
847 typeinfo_mmx = polytype_info32x;
848 typeinfo_3d = polytype_info32d;
849 #endif
850 typeinfo_zbuf = polytype_info32z;
851 break;
852
853 #endif
854
855 default:
856 return NULL;
857 }
858
859 type = CLAMP(0, type & ~POLYTYPE_ZBUF, POLYTYPE_MAX-1);
860 *flags = interpinfo[type];
861
862 if (texture) {
863 info->texture = texture->line[0];
864 info->umask = texture->w - 1;
865 info->vmask = texture->h - 1;
866 info->vshift = 0;
867 while ((1 << info->vshift) < texture->w)
868 info->vshift++;
869 }
870 else {
871 info->texture = NULL;
872 info->umask = info->vmask = info->vshift = 0;
873 }
874
875 info->seg = bmp->seg;
876 bmp_select(bmp);
877
878 if (zbuf) {
879 *flags |= INTERP_Z + INTERP_ZBUF;
880 _optim_alternative_drawer = typeinfo_zbuf[type].alternative;
881 return typeinfo_zbuf[type].filler;
882 }
883
884 #ifdef ALLEGRO_MMX
885 if ((cpu_capabilities & CPU_MMX) && (typeinfo_mmx[type].filler)) {
886 if ((cpu_capabilities & CPU_3DNOW) && (typeinfo_3d[type].filler)) {
887 _optim_alternative_drawer = typeinfo_3d[type].alternative;
888 return typeinfo_3d[type].filler;
889 }
890 _optim_alternative_drawer = typeinfo_mmx[type].alternative;
891 return typeinfo_mmx[type].filler;
892 }
893 #endif
894
895 _optim_alternative_drawer = typeinfo[type].alternative;
896
897 return typeinfo[type].filler;
898 }
899
900
901
902 /* _clip_polygon_segment_f:
903 * Updates interpolation state values when skipping several places, eg.
904 * clipping the first part of a scanline.
905 */
_clip_polygon_segment_f(POLYGON_SEGMENT * info,int gap,int flags)906 void _clip_polygon_segment_f(POLYGON_SEGMENT *info, int gap, int flags)
907 {
908 if (flags & INTERP_1COL)
909 info->c += info->dc * gap;
910
911 if (flags & INTERP_3COL) {
912 info->r += info->dr * gap;
913 info->g += info->dg * gap;
914 info->b += info->db * gap;
915 }
916
917 if (flags & INTERP_FIX_UV) {
918 info->u += info->du * gap;
919 info->v += info->dv * gap;
920 }
921
922 if (flags & INTERP_Z) {
923 info->z += info->dz * gap;
924
925 if (flags & INTERP_FLOAT_UV) {
926 info->fu += info->dfu * gap;
927 info->fv += info->dfv * gap;
928 }
929 }
930 }
931
932
933
934 /* draw_polygon_segment:
935 * Polygon helper function to fill a scanline. Calculates deltas for
936 * whichever values need interpolating, clips the segment, and then calls
937 * the lowlevel scanline filler.
938 */
draw_polygon_segment(BITMAP * bmp,int ytop,int ybottom,POLYGON_EDGE * e1,POLYGON_EDGE * e2,SCANLINE_FILLER drawer,int flags,int color,POLYGON_SEGMENT * info)939 static void draw_polygon_segment(BITMAP *bmp, int ytop, int ybottom, POLYGON_EDGE *e1, POLYGON_EDGE *e2, SCANLINE_FILLER drawer, int flags, int color, POLYGON_SEGMENT *info)
940 {
941 int x, y, w, gap;
942 fixed step, width;
943 POLYGON_SEGMENT *s1, *s2;
944 AL_CONST SCANLINE_FILLER save_drawer = drawer;
945
946 /* ensure that e1 is the left edge and e2 is the right edge */
947 if ((e2->x < e1->x) || ((e1->x == e2->x) && (e2->dx < e1->dx))) {
948 POLYGON_EDGE *et = e1;
949 e1 = e2;
950 e2 = et;
951 }
952
953 s1 = &(e1->dat);
954 s2 = &(e2->dat);
955
956 if (flags & INTERP_FLAT)
957 info->c = color;
958
959 /* for each scanline in the polygon... */
960 for (y=ytop; y<=ybottom; y++) {
961 x = fixceil(e1->x);
962 w = fixceil(e2->x) - x;
963 drawer = save_drawer;
964
965 if (drawer == _poly_scanline_dummy) {
966 if (w > 0)
967 bmp->vtable->hfill(bmp, x, y, x+w-1, color);
968 }
969 else {
970 step = (x << 16) - e1->x;
971 width = e2->x - e1->x;
972 /*
973 * Nasty trick :
974 * In order to avoid divisions by zero, width is set to -1. This way s1 and s2
975 * are still being updated but the scanline is not drawn since w == 0.
976 */
977 if (width == 0)
978 width = -1 << 16;
979 /*
980 * End of nasty trick.
981 */
982 if (flags & INTERP_1COL) {
983 info->dc = fixdiv(s2->c - s1->c, width);
984 info->c = s1->c + fixmul(step, info->dc);
985 s1->c += s1->dc;
986 s2->c += s2->dc;
987 }
988
989 if (flags & INTERP_3COL) {
990 info->dr = fixdiv(s2->r - s1->r, width);
991 info->dg = fixdiv(s2->g - s1->g, width);
992 info->db = fixdiv(s2->b - s1->b, width);
993 info->r = s1->r + fixmul(step, info->dr);
994 info->g = s1->g + fixmul(step, info->dg);
995 info->b = s1->b + fixmul(step, info->db);
996
997 s1->r += s1->dr;
998 s2->r += s2->dr;
999 s1->g += s1->dg;
1000 s2->g += s2->dg;
1001 s1->b += s1->db;
1002 s2->b += s2->db;
1003 }
1004
1005 if (flags & INTERP_FIX_UV) {
1006 info->du = fixdiv(s2->u - s1->u, width);
1007 info->dv = fixdiv(s2->v - s1->v, width);
1008 info->u = s1->u + fixmul(step, info->du);
1009 info->v = s1->v + fixmul(step, info->dv);
1010
1011 s1->u += s1->du;
1012 s2->u += s2->du;
1013 s1->v += s1->dv;
1014 s2->v += s2->dv;
1015 }
1016
1017 if (flags & INTERP_Z) {
1018 float step_f = fixtof(step);
1019 float w1 = 65536. / width;
1020
1021 info->dz = (s2->z - s1->z) * w1;
1022 info->z = s1->z + info->dz * step_f;
1023 s1->z += s1->dz;
1024 s2->z += s2->dz;
1025
1026 if (flags & INTERP_FLOAT_UV) {
1027 info->dfu = (s2->fu - s1->fu) * w1;
1028 info->dfv = (s2->fv - s1->fv) * w1;
1029 info->fu = s1->fu + info->dfu * step_f;
1030 info->fv = s1->fv + info->dfv * step_f;
1031
1032 s1->fu += s1->dfu;
1033 s2->fu += s2->dfu;
1034 s1->fv += s1->dfv;
1035 s2->fv += s2->dfv;
1036 }
1037 }
1038
1039 /* if clipping is enabled then clip the segment */
1040 if (bmp->clip) {
1041 if (x < bmp->cl) {
1042 gap = bmp->cl - x;
1043 x = bmp->cl;
1044 w -= gap;
1045 _clip_polygon_segment_f(info, gap, flags);
1046 }
1047
1048 if (x+w > bmp->cr)
1049 w = bmp->cr - x;
1050 }
1051
1052 if (w > 0) {
1053 int dx = x * BYTES_PER_PIXEL(bitmap_color_depth(bmp));
1054
1055 if ((flags & OPT_FLOAT_UV_TO_FIX) && (info->dz == 0)) {
1056 float z1 = 1. / info->z;
1057 info->u = info->fu * z1;
1058 info->v = info->fv * z1;
1059 info->du = info->dfu * z1;
1060 info->dv = info->dfv * z1;
1061 drawer = _optim_alternative_drawer;
1062 }
1063
1064 if (flags & INTERP_ZBUF)
1065 info->zbuf_addr = bmp_write_line(_zbuffer, y) + x * sizeof(float);
1066
1067 info->read_addr = bmp_read_line(bmp, y) + dx;
1068 drawer(bmp_write_line(bmp, y) + dx, w, info);
1069 }
1070 }
1071
1072 e1->x += e1->dx;
1073 e2->x += e2->dx;
1074 }
1075 }
1076
1077
1078
1079 /* do_polygon3d:
1080 * Helper function for rendering 3d polygon, used by both the fixed point
1081 * and floating point drawing functions.
1082 */
do_polygon3d(BITMAP * bmp,int top,int bottom,POLYGON_EDGE * left_edge,SCANLINE_FILLER drawer,int flags,int color,POLYGON_SEGMENT * info)1083 static void do_polygon3d(BITMAP *bmp, int top, int bottom, POLYGON_EDGE *left_edge, SCANLINE_FILLER drawer, int flags, int color, POLYGON_SEGMENT *info)
1084 {
1085 int ytop, ybottom;
1086 #ifdef ALLEGRO_DOS
1087 int old87 = 0;
1088 #endif
1089 POLYGON_EDGE *right_edge;
1090 ASSERT(bmp);
1091
1092 /* set fpu to single-precision, truncate mode */
1093 #ifdef ALLEGRO_DOS
1094 if (flags & (INTERP_Z | INTERP_FLOAT_UV))
1095 old87 = _control87(PC_24 | RC_CHOP, MCW_PC | MCW_RC);
1096 #endif
1097
1098 acquire_bitmap(bmp);
1099
1100 if ((left_edge->prev != left_edge->next) && (left_edge->prev->top == top))
1101 left_edge = left_edge->prev;
1102
1103 right_edge = left_edge->next;
1104
1105 ytop = top;
1106 for (;;) {
1107 if (right_edge->bottom <= left_edge->bottom)
1108 ybottom = right_edge->bottom;
1109 else
1110 ybottom = left_edge->bottom;
1111
1112 /* fill the scanline */
1113 draw_polygon_segment(bmp, ytop, ybottom, left_edge, right_edge, drawer, flags, color, info);
1114
1115 if (ybottom >= bottom) break;
1116
1117 /* update edges */
1118 if (ybottom >= left_edge->bottom)
1119 left_edge = left_edge->prev;
1120 if (ybottom >= right_edge->bottom)
1121 right_edge = right_edge->next;
1122
1123 ytop = ybottom + 1;
1124 }
1125
1126 bmp_unwrite_line(bmp);
1127 release_bitmap(bmp);
1128
1129 /* reset fpu mode */
1130 #ifdef ALLEGRO_DOS
1131 if (flags & (INTERP_Z | INTERP_FLOAT_UV))
1132 _control87(old87, MCW_PC | MCW_RC);
1133 #endif
1134 }
1135
1136
1137
1138 /* polygon3d:
1139 * Draws a 3d polygon in the specified mode. The vertices parameter should
1140 * be followed by that many pointers to V3D structures, which describe each
1141 * vertex of the polygon.
1142 */
_soft_polygon3d(BITMAP * bmp,int type,BITMAP * texture,int vc,V3D * vtx[])1143 void _soft_polygon3d(BITMAP *bmp, int type, BITMAP *texture, int vc, V3D *vtx[])
1144 {
1145 int c;
1146 int flags;
1147 int top = INT_MAX;
1148 int bottom = INT_MIN;
1149 V3D *v1, *v2;
1150 POLYGON_EDGE *edge, *edge0, *start_edge;
1151 POLYGON_EDGE *list_edges = NULL;
1152 POLYGON_SEGMENT info;
1153 SCANLINE_FILLER drawer;
1154 ASSERT(bmp);
1155
1156 if (vc < 3)
1157 return;
1158
1159 /* set up the drawing mode */
1160 drawer = _get_scanline_filler(type, &flags, &info, texture, bmp);
1161 if (!drawer)
1162 return;
1163
1164 /* allocate some space for the active edge table */
1165 _grow_scratch_mem(sizeof(POLYGON_EDGE) * vc);
1166 start_edge = edge0 = edge = (POLYGON_EDGE *)_scratch_mem;
1167
1168 /* fill the double-linked list of edges (order unimportant) */
1169 v2 = vtx[vc-1];
1170
1171 for (c=0; c<vc; c++) {
1172 v1 = v2;
1173 v2 = vtx[c];
1174
1175 if (_fill_3d_edge_structure(edge, v1, v2, flags, bmp)) {
1176 if (edge->top < top) {
1177 top = edge->top;
1178 start_edge = edge;
1179 }
1180
1181 if (edge->bottom > bottom)
1182 bottom = edge->bottom;
1183
1184 if (list_edges) {
1185 list_edges->next = edge;
1186 edge->prev = list_edges;
1187 }
1188
1189 list_edges = edge;
1190 edge++;
1191 }
1192 }
1193
1194 if (list_edges) {
1195 /* close the double-linked list */
1196 edge0->prev = --edge;
1197 edge->next = edge0;
1198
1199 /* render the polygon */
1200 do_polygon3d(bmp, top, bottom, start_edge, drawer, flags, vtx[0]->c, &info);
1201 }
1202 }
1203
1204
1205
1206 /* polygon3d_f:
1207 * Floating point version of polygon3d().
1208 */
_soft_polygon3d_f(BITMAP * bmp,int type,BITMAP * texture,int vc,V3D_f * vtx[])1209 void _soft_polygon3d_f(BITMAP *bmp, int type, BITMAP *texture, int vc, V3D_f *vtx[])
1210 {
1211 int c;
1212 int flags;
1213 int top = INT_MAX;
1214 int bottom = INT_MIN;
1215 V3D_f *v1, *v2;
1216 POLYGON_EDGE *edge, *edge0, *start_edge;
1217 POLYGON_EDGE *list_edges = NULL;
1218 POLYGON_SEGMENT info;
1219 SCANLINE_FILLER drawer;
1220 ASSERT(bmp);
1221
1222 if (vc < 3)
1223 return;
1224
1225 /* set up the drawing mode */
1226 drawer = _get_scanline_filler(type, &flags, &info, texture, bmp);
1227 if (!drawer)
1228 return;
1229
1230 /* allocate some space for the active edge table */
1231 _grow_scratch_mem(sizeof(POLYGON_EDGE) * vc);
1232 start_edge = edge0 = edge = (POLYGON_EDGE *)_scratch_mem;
1233
1234 /* fill the double-linked list of edges in clockwise order */
1235 v2 = vtx[vc-1];
1236
1237 for (c=0; c<vc; c++) {
1238 v1 = v2;
1239 v2 = vtx[c];
1240
1241 if (_fill_3d_edge_structure_f(edge, v1, v2, flags, bmp)) {
1242 if (edge->top < top) {
1243 top = edge->top;
1244 start_edge = edge;
1245 }
1246
1247 if (edge->bottom > bottom)
1248 bottom = edge->bottom;
1249
1250 if (list_edges) {
1251 list_edges->next = edge;
1252 edge->prev = list_edges;
1253 }
1254
1255 list_edges = edge;
1256 edge++;
1257 }
1258 }
1259
1260 if (list_edges) {
1261 /* close the double-linked list */
1262 edge0->prev = --edge;
1263 edge->next = edge0;
1264
1265 /* render the polygon */
1266 do_polygon3d(bmp, top, bottom, start_edge, drawer, flags, vtx[0]->c, &info);
1267 }
1268 }
1269
1270
1271
1272 /* draw_triangle_part:
1273 * Triangle helper function to fill a triangle part. Computes interpolation,
1274 * clips the segment, and then calls the lowlevel scanline filler.
1275 */
draw_triangle_part(BITMAP * bmp,int ytop,int ybottom,POLYGON_EDGE * left_edge,POLYGON_EDGE * right_edge,SCANLINE_FILLER drawer,int flags,int color,POLYGON_SEGMENT * info)1276 static void draw_triangle_part(BITMAP *bmp, int ytop, int ybottom, POLYGON_EDGE *left_edge, POLYGON_EDGE *right_edge, SCANLINE_FILLER drawer, int flags, int color, POLYGON_SEGMENT *info)
1277 {
1278 int x, y, w;
1279 int gap;
1280 AL_CONST int test_optim = (flags & OPT_FLOAT_UV_TO_FIX) && (info->dz == 0);
1281 fixed step;
1282 POLYGON_SEGMENT *s1;
1283
1284 /* ensure that left_edge and right_edge are the right way round */
1285 if ((right_edge->x < left_edge->x) ||
1286 ((left_edge->x == right_edge->x) && (right_edge->dx < left_edge->dx))) {
1287 POLYGON_EDGE *other_edge = left_edge;
1288 left_edge = right_edge;
1289 right_edge = other_edge;
1290 }
1291
1292 s1 = &(left_edge->dat);
1293
1294 if (flags & INTERP_FLAT)
1295 info->c = color;
1296
1297 for (y=ytop; y<=ybottom; y++) {
1298 x = fixceil(left_edge->x);
1299 w = fixceil(right_edge->x) - x;
1300 step = (x << 16) - left_edge->x;
1301
1302 if (drawer == _poly_scanline_dummy) {
1303 if (w > 0)
1304 bmp->vtable->hfill(bmp, x, y, x+w-1, color);
1305 }
1306 else {
1307 if (flags & INTERP_1COL) {
1308 info->c = s1->c + fixmul(step, info->dc);
1309 s1->c += s1->dc;
1310 }
1311
1312 if (flags & INTERP_3COL) {
1313 info->r = s1->r + fixmul(step, info->dr);
1314 info->g = s1->g + fixmul(step, info->dg);
1315 info->b = s1->b + fixmul(step, info->db);
1316
1317 s1->r += s1->dr;
1318 s1->g += s1->dg;
1319 s1->b += s1->db;
1320 }
1321
1322 if (flags & INTERP_FIX_UV) {
1323 info->u = s1->u + fixmul(step, info->du);
1324 info->v = s1->v + fixmul(step, info->dv);
1325
1326 s1->u += s1->du;
1327 s1->v += s1->dv;
1328 }
1329
1330 if (flags & INTERP_Z) {
1331 float step_f = fixtof(step);
1332
1333 info->z = s1->z + info->dz * step_f;
1334 s1->z += s1->dz;
1335
1336 if (flags & INTERP_FLOAT_UV) {
1337 info->fu = s1->fu + info->dfu * step_f;
1338 info->fv = s1->fv + info->dfv * step_f;
1339
1340 s1->fu += s1->dfu;
1341 s1->fv += s1->dfv;
1342 }
1343 }
1344
1345 /* if clipping is enabled then clip the segment */
1346 if (bmp->clip) {
1347 if (x < bmp->cl) {
1348 gap = bmp->cl - x;
1349 x = bmp->cl;
1350 w -= gap;
1351 _clip_polygon_segment_f(info, gap, flags);
1352 }
1353
1354 if (x+w > bmp->cr)
1355 w = bmp->cr - x;
1356 }
1357
1358 if (w > 0) {
1359 int dx = x * BYTES_PER_PIXEL(bitmap_color_depth(bmp));
1360
1361 if (test_optim) {
1362 float z1 = 1. / info->z;
1363 info->u = info->fu * z1;
1364 info->v = info->fv * z1;
1365 info->du = info->dfu * z1;
1366 info->dv = info->dfv * z1;
1367 drawer = _optim_alternative_drawer;
1368 }
1369
1370 if (flags & INTERP_ZBUF)
1371 info->zbuf_addr = bmp_write_line(_zbuffer, y) + x * sizeof(float);
1372
1373 info->read_addr = bmp_read_line(bmp, y) + dx;
1374 drawer(bmp_write_line(bmp, y) + dx, w, info);
1375 }
1376 }
1377
1378 left_edge->x += left_edge->dx;
1379 right_edge->x += right_edge->dx;
1380 }
1381 }
1382
1383
1384
1385 /* _triangle_deltas:
1386 * Triangle3d helper function to calculate the deltas. (For triangles,
1387 * deltas are constant over the whole triangle).
1388 */
_triangle_deltas(BITMAP * bmp,fixed w,POLYGON_SEGMENT * s1,POLYGON_SEGMENT * info,AL_CONST V3D * v,int flags)1389 static void _triangle_deltas(BITMAP *bmp, fixed w, POLYGON_SEGMENT *s1, POLYGON_SEGMENT *info, AL_CONST V3D *v, int flags)
1390 {
1391 if (flags & INTERP_1COL)
1392 info->dc = fixdiv(s1->c - itofix(v->c), w);
1393
1394 if (flags & INTERP_3COL) {
1395 int r, g, b;
1396
1397 if (flags & COLOR_TO_RGB) {
1398 AL_CONST int coldepth = bitmap_color_depth(bmp);
1399 r = getr_depth(coldepth, v->c);
1400 g = getg_depth(coldepth, v->c);
1401 b = getb_depth(coldepth, v->c);
1402 }
1403 else {
1404 r = (v->c >> 16) & 0xFF;
1405 g = (v->c >> 8) & 0xFF;
1406 b = v->c & 0xFF;
1407 }
1408
1409 info->dr = fixdiv(s1->r - itofix(r), w);
1410 info->dg = fixdiv(s1->g - itofix(g), w);
1411 info->db = fixdiv(s1->b - itofix(b), w);
1412 }
1413
1414 if (flags & INTERP_FIX_UV) {
1415 info->du = fixdiv(s1->u - v->u, w);
1416 info->dv = fixdiv(s1->v - v->v, w);
1417 }
1418
1419 if (flags & INTERP_Z) {
1420 float w1 = 65536. / w;
1421
1422 /* Z (depth) interpolation */
1423 float z1 = 65536. / v->z;
1424
1425 info->dz = (s1->z - z1) * w1;
1426
1427 if (flags & INTERP_FLOAT_UV) {
1428 /* floating point (perspective correct) texture interpolation */
1429 float fu1 = v->u * z1;
1430 float fv1 = v->v * z1;
1431
1432 info->dfu = (s1->fu - fu1) * w1;
1433 info->dfv = (s1->fv - fv1) * w1;
1434 }
1435 }
1436 }
1437
1438
1439 /* _triangle_deltas_f:
1440 * Floating point version of _triangle_deltas().
1441 */
_triangle_deltas_f(BITMAP * bmp,fixed w,POLYGON_SEGMENT * s1,POLYGON_SEGMENT * info,AL_CONST V3D_f * v,int flags)1442 static void _triangle_deltas_f(BITMAP *bmp, fixed w, POLYGON_SEGMENT *s1, POLYGON_SEGMENT *info, AL_CONST V3D_f *v, int flags)
1443 {
1444 if (flags & INTERP_1COL)
1445 info->dc = fixdiv(s1->c - itofix(v->c), w);
1446
1447 if (flags & INTERP_3COL) {
1448 int r, g, b;
1449
1450 if (flags & COLOR_TO_RGB) {
1451 AL_CONST int coldepth = bitmap_color_depth(bmp);
1452 r = getr_depth(coldepth, v->c);
1453 g = getg_depth(coldepth, v->c);
1454 b = getb_depth(coldepth, v->c);
1455 }
1456 else {
1457 r = (v->c >> 16) & 0xFF;
1458 g = (v->c >> 8) & 0xFF;
1459 b = v->c & 0xFF;
1460 }
1461
1462 info->dr = fixdiv(s1->r - itofix(r), w);
1463 info->dg = fixdiv(s1->g - itofix(g), w);
1464 info->db = fixdiv(s1->b - itofix(b), w);
1465 }
1466
1467 if (flags & INTERP_FIX_UV) {
1468 info->du = fixdiv(s1->u - ftofix(v->u), w);
1469 info->dv = fixdiv(s1->v - ftofix(v->v), w);
1470 }
1471
1472 if (flags & INTERP_Z) {
1473 float w1 = 65536. / w;
1474
1475 /* Z (depth) interpolation */
1476 float z1 = 1. / v->z;
1477
1478 info->dz = (s1->z - z1) * w1;
1479
1480 if (flags & INTERP_FLOAT_UV) {
1481 /* floating point (perspective correct) texture interpolation */
1482 float fu1 = v->u * z1 * 65536.;
1483 float fv1 = v->v * z1 * 65536.;
1484
1485 info->dfu = (s1->fu - fu1) * w1;
1486 info->dfv = (s1->fv - fv1) * w1;
1487 }
1488 }
1489 }
1490
1491
1492
1493 /* _clip_polygon_segment:
1494 * Fixed point version of _clip_polygon_segment_f().
1495 */
_clip_polygon_segment(POLYGON_SEGMENT * info,fixed gap,int flags)1496 void _clip_polygon_segment(POLYGON_SEGMENT *info, fixed gap, int flags)
1497 {
1498 if (flags & INTERP_1COL)
1499 info->c += fixmul(info->dc, gap);
1500
1501 if (flags & INTERP_3COL) {
1502 info->r += fixmul(info->dr, gap);
1503 info->g += fixmul(info->dg, gap);
1504 info->b += fixmul(info->db, gap);
1505 }
1506
1507 if (flags & INTERP_FIX_UV) {
1508 info->u += fixmul(info->du, gap);
1509 info->v += fixmul(info->dv, gap);
1510 }
1511
1512 if (flags & INTERP_Z) {
1513 float gap_f = fixtof(gap);
1514
1515 info->z += info->dz * gap_f;
1516
1517 if (flags & INTERP_FLOAT_UV) {
1518 info->fu += info->dfu * gap_f;
1519 info->fv += info->dfv * gap_f;
1520 }
1521 }
1522 }
1523
1524
1525
1526 /* triangle3d:
1527 * Draws a 3d triangle.
1528 */
_soft_triangle3d(BITMAP * bmp,int type,BITMAP * texture,V3D * v1,V3D * v2,V3D * v3)1529 void _soft_triangle3d(BITMAP *bmp, int type, BITMAP *texture, V3D *v1, V3D *v2, V3D *v3)
1530 {
1531 int flags;
1532
1533 #ifdef ALLEGRO_DOS
1534 int old87 = 0;
1535 #endif
1536
1537 int color = v1->c;
1538 V3D *vt1, *vt2, *vt3;
1539 POLYGON_EDGE edge1, edge2;
1540 POLYGON_SEGMENT info;
1541 SCANLINE_FILLER drawer;
1542 ASSERT(bmp);
1543
1544 /* set up the drawing mode */
1545 drawer = _get_scanline_filler(type, &flags, &info, texture, bmp);
1546 if (!drawer)
1547 return;
1548
1549 /* sort the vertices so that vt1->y <= vt2->y <= vt3->y */
1550 if (v1->y > v2->y) {
1551 vt1 = v2;
1552 vt2 = v1;
1553 }
1554 else {
1555 vt1 = v1;
1556 vt2 = v2;
1557 }
1558
1559 if (vt1->y > v3->y) {
1560 vt3 = vt1;
1561 vt1 = v3;
1562 }
1563 else
1564 vt3 = v3;
1565
1566 if (vt2->y > vt3->y) {
1567 V3D* vtemp = vt2;
1568 vt2 = vt3;
1569 vt3 = vtemp;
1570 }
1571
1572 /* set fpu to single-precision, truncate mode */
1573 #ifdef ALLEGRO_DOS
1574 if (flags & (INTERP_Z | INTERP_FLOAT_UV))
1575 old87 = _control87(PC_24 | RC_CHOP, MCW_PC | MCW_RC);
1576 #endif
1577
1578 /* do 3D triangle*/
1579 if (_fill_3d_edge_structure(&edge1, vt1, vt3, flags, bmp)) {
1580
1581 acquire_bitmap(bmp);
1582
1583 /* calculate deltas */
1584 if (drawer != _poly_scanline_dummy) {
1585 fixed w, h;
1586 POLYGON_SEGMENT s1 = edge1.dat;
1587
1588 h = vt2->y - (edge1.top << 16);
1589 _clip_polygon_segment(&s1, h, flags);
1590
1591 w = edge1.x + fixmul(h, edge1.dx) - vt2->x;
1592 if (w) _triangle_deltas(bmp, w, &s1, &info, vt2, flags);
1593 }
1594
1595 /* draws part between y1 and y2 */
1596 if (_fill_3d_edge_structure(&edge2, vt1, vt2, flags, bmp))
1597 draw_triangle_part(bmp, edge2.top, edge2.bottom, &edge1, &edge2, drawer, flags, color, &info);
1598
1599 /* draws part between y2 and y3 */
1600 if (_fill_3d_edge_structure(&edge2, vt2, vt3, flags, bmp))
1601 draw_triangle_part(bmp, edge2.top, edge2.bottom, &edge1, &edge2, drawer, flags, color, &info);
1602
1603 bmp_unwrite_line(bmp);
1604 release_bitmap(bmp);
1605 }
1606
1607 /* reset fpu mode */
1608 #ifdef ALLEGRO_DOS
1609 if (flags & (INTERP_Z | INTERP_FLOAT_UV))
1610 _control87(old87, MCW_PC | MCW_RC);
1611 #endif
1612 }
1613
1614
1615
1616 /* triangle3d_f:
1617 * Draws a 3d triangle.
1618 */
_soft_triangle3d_f(BITMAP * bmp,int type,BITMAP * texture,V3D_f * v1,V3D_f * v2,V3D_f * v3)1619 void _soft_triangle3d_f(BITMAP *bmp, int type, BITMAP *texture, V3D_f *v1, V3D_f *v2, V3D_f *v3)
1620 {
1621 int flags;
1622
1623 #ifdef ALLEGRO_DOS
1624 int old87 = 0;
1625 #endif
1626
1627 int color = v1->c;
1628 V3D_f *vt1, *vt2, *vt3;
1629 POLYGON_EDGE edge1, edge2;
1630 POLYGON_SEGMENT info;
1631 SCANLINE_FILLER drawer;
1632 ASSERT(bmp);
1633
1634 /* set up the drawing mode */
1635 drawer = _get_scanline_filler(type, &flags, &info, texture, bmp);
1636 if (!drawer)
1637 return;
1638
1639 /* sort the vertices so that vt1->y <= vt2->y <= vt3->y */
1640 if (v1->y > v2->y) {
1641 vt1 = v2;
1642 vt2 = v1;
1643 }
1644 else {
1645 vt1 = v1;
1646 vt2 = v2;
1647 }
1648
1649 if (vt1->y > v3->y) {
1650 vt3 = vt1;
1651 vt1 = v3;
1652 }
1653 else
1654 vt3 = v3;
1655
1656 if (vt2->y > vt3->y) {
1657 V3D_f* vtemp = vt2;
1658 vt2 = vt3;
1659 vt3 = vtemp;
1660 }
1661
1662 /* set fpu to single-precision, truncate mode */
1663 #ifdef ALLEGRO_DOS
1664 if (flags & (INTERP_Z | INTERP_FLOAT_UV))
1665 old87 = _control87(PC_24 | RC_CHOP, MCW_PC | MCW_RC);
1666 #endif
1667
1668 /* do 3D triangle*/
1669 if (_fill_3d_edge_structure_f(&edge1, vt1, vt3, flags, bmp)) {
1670
1671 acquire_bitmap(bmp);
1672
1673 /* calculate deltas */
1674 if (drawer != _poly_scanline_dummy) {
1675 fixed w, h;
1676 POLYGON_SEGMENT s1 = edge1.dat;
1677
1678 h = ftofix(vt2->y) - (edge1.top << 16);
1679 _clip_polygon_segment(&s1, h, flags);
1680
1681 w = edge1.x + fixmul(h, edge1.dx) - ftofix(vt2->x);
1682 if (w) _triangle_deltas_f(bmp, w, &s1, &info, vt2, flags);
1683 }
1684
1685 /* draws part between y1 and y2 */
1686 if (_fill_3d_edge_structure_f(&edge2, vt1, vt2, flags, bmp))
1687 draw_triangle_part(bmp, edge2.top, edge2.bottom, &edge1, &edge2, drawer, flags, color, &info);
1688
1689 /* draws part between y2 and y3 */
1690 if (_fill_3d_edge_structure_f(&edge2, vt2, vt3, flags, bmp))
1691 draw_triangle_part(bmp, edge2.top, edge2.bottom, &edge1, &edge2, drawer, flags, color, &info);
1692
1693 bmp_unwrite_line(bmp);
1694 release_bitmap(bmp);
1695 }
1696
1697 /* reset fpu mode */
1698 #ifdef ALLEGRO_DOS
1699 if (flags & (INTERP_Z | INTERP_FLOAT_UV))
1700 _control87(old87, MCW_PC | MCW_RC);
1701 #endif
1702 }
1703
1704
1705
1706 /* quad3d:
1707 * Draws a 3d quad.
1708 */
_soft_quad3d(BITMAP * bmp,int type,BITMAP * texture,V3D * v1,V3D * v2,V3D * v3,V3D * v4)1709 void _soft_quad3d(BITMAP *bmp, int type, BITMAP *texture, V3D *v1, V3D *v2, V3D *v3, V3D *v4)
1710 {
1711 #if (defined ALLEGRO_GCC) && (defined ALLEGRO_I386)
1712 ASSERT(bmp);
1713
1714 /* dodgy assumption alert! See comments for triangle() */
1715 polygon3d(bmp, type, texture, 4, &v1);
1716
1717 #else
1718
1719 V3D *vertex[4];
1720 ASSERT(bmp);
1721
1722 vertex[0] = v1;
1723 vertex[1] = v2;
1724 vertex[2] = v3;
1725 vertex[3] = v4;
1726 polygon3d(bmp, type, texture, 4, vertex);
1727
1728 #endif
1729 }
1730
1731
1732
1733 /* quad3d_f:
1734 * Draws a 3d quad.
1735 */
_soft_quad3d_f(BITMAP * bmp,int type,BITMAP * texture,V3D_f * v1,V3D_f * v2,V3D_f * v3,V3D_f * v4)1736 void _soft_quad3d_f(BITMAP *bmp, int type, BITMAP *texture, V3D_f *v1, V3D_f *v2, V3D_f *v3, V3D_f *v4)
1737 {
1738 #if (defined ALLEGRO_GCC) && (defined ALLEGRO_I386)
1739 ASSERT(bmp);
1740
1741 /* dodgy assumption alert! See comments for triangle() */
1742 polygon3d_f(bmp, type, texture, 4, &v1);
1743
1744 #else
1745
1746 V3D_f *vertex[4];
1747 ASSERT(bmp);
1748
1749 vertex[0] = v1;
1750 vertex[1] = v2;
1751 vertex[2] = v3;
1752 vertex[3] = v4;
1753 polygon3d_f(bmp, type, texture, 4, vertex);
1754
1755 #endif
1756 }
1757
1758
1759
1760 /* create_zbuffer:
1761 * Creates a new Z-buffer the size of the given bitmap.
1762 */
create_zbuffer(BITMAP * bmp)1763 ZBUFFER *create_zbuffer(BITMAP *bmp)
1764 {
1765 ASSERT(bmp);
1766 return create_bitmap_ex(32, bmp->w, bmp->h);
1767 }
1768
1769
1770
1771 /* clear_zbuffer:
1772 * Clears the given z-buffer, z is the value written in the z-buffer
1773 * - it is 1/(z coordinate), z=0 meaning far away.
1774 */
clear_zbuffer(ZBUFFER * zbuf,float z)1775 void clear_zbuffer(ZBUFFER *zbuf, float z)
1776 {
1777 union {
1778 float zf;
1779 long zi;
1780 } _zbuf_clip;
1781 ASSERT(zbuf);
1782
1783 _zbuf_clip.zf = z;
1784 clear_to_color(zbuf, _zbuf_clip.zi);
1785 }
1786
1787
1788
1789 /* destroy_zbuffer:
1790 * Destroys the given z-buffer.
1791 */
destroy_zbuffer(ZBUFFER * zbuf)1792 void destroy_zbuffer(ZBUFFER *zbuf)
1793 {
1794 if (zbuf) {
1795 if (zbuf == _zbuffer)
1796 _zbuffer = NULL;
1797 destroy_bitmap(zbuf);
1798 }
1799 }
1800
1801
1802
1803 /* set_zbuffer:
1804 * Makes polygon drawing routines use the given BITMAP as z-buffer.
1805 */
set_zbuffer(ZBUFFER * zbuf)1806 void set_zbuffer(ZBUFFER *zbuf)
1807 {
1808 ASSERT(zbuf);
1809 _zbuffer = zbuf;
1810 }
1811
1812
1813
1814 /* create_sub_zbuffer:
1815 * Creates a new sub-z-buffer of the given z-buffer. A sub-z-buffer is
1816 * exactly like a sub-bitmap, buf for z-buffers.
1817 */
create_sub_zbuffer(ZBUFFER * parent,int x,int y,int width,int height)1818 ZBUFFER *create_sub_zbuffer(ZBUFFER *parent, int x, int y, int width, int height)
1819 {
1820 ASSERT(parent);
1821 /* For now, just use the code for BITMAPs. */
1822 return create_sub_bitmap(parent, x, y, width, height);
1823 }
1824