1 /* ResidualVM - A 3D game interpreter
2 *
3 * ResidualVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the AUTHORS
5 * file distributed with this source distribution.
6 *
7 * Additional copyright for this file:
8 * Copyright (C) 1999-2000 Revolution Software Ltd.
9 * This code is based on source code created by Revolution Software,
10 * used with permission.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
25 *
26 */
27
28 #include "engines/icb/common/px_common.h"
29 #include "engines/icb/gfx/gfxstub_dutch.h"
30 #include "engines/icb/gfx/gfxstub_rev_dutch.h"
31
32 namespace ICB {
33
34 typedef struct {
35 int32 x0, x1;
36 int32 count;
37 int32 a0, r0, g0, b0;
38 int32 a1, r1, g1, b1;
39 int32 u0, v0;
40 int32 u1, v1;
41 } span_t;
42
43 #define MAX_SCREEN_HEIGHT 4096
44 span_t spans[MAX_SCREEN_HEIGHT];
45
46 #define GETBValue(rgb) ((uint8)(rgb))
47 #define GETGValue(rgb) ((uint8)(((uint16)(rgb)) >> 8))
48 #define GETRValue(rgb) ((uint8)((rgb) >> 16))
49 #define GETAValue(rgb) ((uint8)((rgb) >> 24))
50
51 extern int32 mip_map_level;
52
53 typedef struct {
54 char *pRGB;
55 int32 RGBPitch;
56 int32 RGBBytesPerPixel;
57
58 char *pZ;
59 int32 ZPitch;
60 int32 ZBytesPerPixel;
61 } MyRenderDevice;
62
63 MyRenderDevice myRenDev = {NULL, 0, 0, NULL, 0, 0};
64 RevRenderDevice *lastRevRenDev = NULL;
65
SetRenderDevice(RevRenderDevice * renderDev)66 int32 SetRenderDevice(RevRenderDevice *renderDev) {
67 lastRevRenDev = NULL;
68 if (renderDev->RGBdata == NULL)
69 return 1;
70 if (renderDev->Zdata == NULL)
71 return 1;
72 if (renderDev->width <= 0)
73 return 1;
74 if (renderDev->width > 2048)
75 return 1;
76 if (renderDev->height <= 0)
77 return 1;
78 if (renderDev->height > 2048)
79 return 1;
80
81 myRenDev.pRGB = (char *)(renderDev->RGBdata);
82 myRenDev.pZ = (char *)(renderDev->Zdata);
83 myRenDev.RGBBytesPerPixel = 4;
84 myRenDev.RGBPitch = renderDev->stride;
85 myRenDev.ZBytesPerPixel = 2;
86 myRenDev.ZPitch = renderDev->width * myRenDev.ZBytesPerPixel;
87 lastRevRenDev = renderDev;
88 return 0;
89 }
90
91 TextureHandle myTexHan;
92
SetTextureState(TextureHandle * texture)93 int32 SetTextureState(TextureHandle *texture) {
94 myTexHan = *texture;
95 return 0;
96 }
97
UnregisterTexture(TextureHandle * texture)98 int32 UnregisterTexture(TextureHandle *texture) {
99 int32 i;
100
101 for (i = 0; i < 9; i++)
102 if ((texture->pRGBA[i]) != NULL)
103 delete[](texture->pRGBA[i]);
104
105 if (texture->palette != NULL)
106 delete[](texture->palette);
107
108 delete texture;
109
110 // always return zero
111 return 0;
112 }
113
RegisterTexture(const RevTexture * revInput)114 TextureHandle *RegisterTexture(const RevTexture *revInput) {
115 int32 i;
116 TextureHandle *th = new TextureHandle();
117
118 th->w = revInput->width;
119 th->h = revInput->height;
120
121 for (i = 0; i < 9; i++)
122 th->pRGBA[i] = NULL;
123
124 if (revInput->palette[0] == 0xDEADBEAF) {
125 th->bpp = 4;
126 th->palette = NULL;
127 th->pRGBA[0] = revInput->level[0];
128 } else {
129 // Complain if width or height > 256 < 1
130 if ((th->w < 1) || (th->w > 256)) {
131 delete th;
132 return NULL;
133 }
134 if ((th->h < 1) || (th->h > 256)) {
135 delete th;
136 return NULL;
137 }
138
139 // Complain if the width or height are not powers of 2
140 for (i = 0; i < 8; i++) {
141 // ERROR
142 if (((th->w >> i) << i) != th->w) {
143 if ((th->w >> i) != 0) {
144 delete th;
145 return NULL;
146 }
147 }
148 // ERROR
149 if (((th->h >> i) << i) != th->h) {
150 if ((th->h >> i) != 0) {
151 delete th;
152 return NULL;
153 }
154 }
155 }
156
157 th->bpp = 1;
158 th->palette = new uint32[256];
159 for (i = 0; i < 256; i++)
160 th->palette[i] = revInput->palette[i];
161
162 int32 size = th->w * th->h * th->bpp;
163 for (i = 0; i < 9; i++) {
164 th->pRGBA[i] = new uint8[size];
165 memcpy(th->pRGBA[i], revInput->level[i], size);
166 size /= 4;
167 if (size / th->bpp == 0)
168 break;
169 }
170 }
171
172 return th;
173 }
174
ClearProcessorState()175 void ClearProcessorState() { return; }
176
DrawGouraudTexturedPolygon(const vertex2D * verts,int32 nVerts,uint16 z)177 int32 DrawGouraudTexturedPolygon(const vertex2D *verts, int32 nVerts, uint16 z) {
178 int32 i, j, topvert, bottomvert, leftvert, rightvert, nextvert;
179 int32 itopy, ibottomy, spantopy, spanbottomy, count;
180 int32 x, a, r, g, b, u, v;
181 int32 ixslope, iaslope, irslope, igslope, ibslope, iuslope, ivslope;
182 float topy, bottomy, height, width, prestep;
183 float xslope, aslope, rslope, gslope, bslope, uslope, vslope;
184 float y;
185 span_t *pspan;
186
187 if (myRenDev.pRGB == NULL)
188 return 0;
189 if (myTexHan.pRGBA[mip_map_level] == NULL)
190 return 0;
191
192 // Test for clockwise polygons
193 int32 l0x = (verts[0].x - verts[1].x) >> 16;
194 int32 l0y = (verts[0].y - verts[1].y) >> 16;
195 int32 l1x = (verts[2].x - verts[1].x) >> 16;
196 int32 l1y = (verts[2].y - verts[1].y) >> 16;
197 if (l0x * l1y > l0y * l1x) {
198 return 0;
199 }
200
201 topy = 999999.0f;
202 bottomy = -999999.0f;
203 topvert = 0;
204 bottomvert = 0;
205 for (i = 0; i < nVerts; i++) {
206 y = (float)(verts[i].y / 65536.0f);
207 if (y < topy) {
208 topy = y;
209 topvert = i;
210 }
211 if (y > bottomy) {
212 bottomy = y;
213 bottomvert = i;
214 }
215 }
216
217 itopy = (int32)ceil(topy);
218 ibottomy = (int32)ceil(bottomy);
219
220 // reject polygons that don't cross a scan
221 if (ibottomy == itopy)
222 return 1;
223
224 // Scan out the left edge
225 pspan = spans;
226 leftvert = topvert;
227
228 do {
229 nextvert = leftvert - 1;
230 if (nextvert < 0)
231 nextvert = nVerts - 1;
232 y = (float)(verts[leftvert].y / 65536.0f);
233 spantopy = (int32)ceil(y);
234 y = (float)(verts[nextvert].y / 65536.0f);
235 spanbottomy = (int32)ceil(y);
236 if (spantopy < spanbottomy) {
237 height = (float)((verts[nextvert].y - verts[leftvert].y) / 65536.0f);
238 width = (float)((verts[nextvert].x - verts[leftvert].x) / 65536.0f);
239
240 xslope = width / height;
241 uslope = (float)((verts[nextvert].u - verts[leftvert].u) / 65536.0f) / height;
242 vslope = (float)((verts[nextvert].v - verts[leftvert].v) / 65536.0f) / height;
243 aslope = (GETAValue(verts[nextvert].colour) - GETAValue(verts[leftvert].colour)) / height;
244 rslope = (GETRValue(verts[nextvert].colour) - GETRValue(verts[leftvert].colour)) / height;
245 gslope = (GETGValue(verts[nextvert].colour) - GETGValue(verts[leftvert].colour)) / height;
246 bslope = (GETBValue(verts[nextvert].colour) - GETBValue(verts[leftvert].colour)) / height;
247
248 prestep = spantopy - (float)(verts[leftvert].y / 65536.0f);
249
250 x = (int32)((((verts[leftvert].x) / 65536.0f) + (xslope * prestep)) * 65536.0) + ((1 << 16) - 1);
251 u = (int32)((((verts[leftvert].u) / 65536.0f) + (uslope * prestep)) * 65536.0) + ((1 << 16) - 1);
252 v = (int32)((((verts[leftvert].v) / 65536.0f) + (vslope * prestep)) * 65536.0) + ((1 << 16) - 1);
253 a = (int32)((GETAValue(verts[leftvert].colour) + (aslope * prestep)) * 65536.0) + ((1 << 16) - 1);
254 r = (int32)((GETRValue(verts[leftvert].colour) + (rslope * prestep)) * 65536.0) + ((1 << 16) - 1);
255 g = (int32)((GETGValue(verts[leftvert].colour) + (gslope * prestep)) * 65536.0) + ((1 << 16) - 1);
256 b = (int32)((GETBValue(verts[leftvert].colour) + (bslope * prestep)) * 65536.0) + ((1 << 16) - 1);
257
258 ixslope = (int32)(xslope * 65536.0);
259 iuslope = (int32)(uslope * 65536.0);
260 ivslope = (int32)(vslope * 65536.0);
261 iaslope = (int32)(aslope * 65536.0);
262 irslope = (int32)(rslope * 65536.0);
263 igslope = (int32)(gslope * 65536.0);
264 ibslope = (int32)(bslope * 65536.0);
265
266 for (j = spantopy; j < spanbottomy; j++) {
267 pspan->x0 = x >> 16;
268 pspan->u0 = u >> 16;
269 pspan->v0 = v >> 16;
270 pspan->a0 = a >> 16;
271 pspan->r0 = r >> 16;
272 pspan->g0 = g >> 16;
273 pspan->b0 = b >> 16;
274 x += ixslope;
275 u += iuslope;
276 v += ivslope;
277 a += iaslope;
278 r += irslope;
279 g += igslope;
280 b += ibslope;
281 pspan++;
282 }
283 }
284
285 leftvert--;
286 if (leftvert < 0)
287 leftvert = nVerts - 1;
288 } while (leftvert != bottomvert);
289
290 // Scan out the right edge
291 pspan = spans;
292 rightvert = topvert;
293
294 do {
295 nextvert = (rightvert + 1) % nVerts;
296 y = (float)(verts[rightvert].y / 65536.0f);
297 spantopy = (int32)ceil(y);
298 y = (float)(verts[nextvert].y / 65536.0f);
299 spanbottomy = (int32)ceil(y);
300 if (spantopy < spanbottomy) {
301 height = (float)((verts[nextvert].y - verts[rightvert].y) / 65536.0f);
302 width = (float)((verts[nextvert].x - verts[rightvert].x) / 65536.0f);
303
304 xslope = width / height;
305 uslope = (float)((verts[nextvert].u - verts[rightvert].u) / 65536.0f) / height;
306 vslope = (float)((verts[nextvert].v - verts[rightvert].v) / 65536.0f) / height;
307 aslope = (GETAValue(verts[nextvert].colour) - GETAValue(verts[rightvert].colour)) / height;
308 rslope = (GETRValue(verts[nextvert].colour) - GETRValue(verts[rightvert].colour)) / height;
309 gslope = (GETGValue(verts[nextvert].colour) - GETGValue(verts[rightvert].colour)) / height;
310 bslope = (GETBValue(verts[nextvert].colour) - GETBValue(verts[rightvert].colour)) / height;
311
312 prestep = spantopy - (float)(verts[rightvert].y / 65536.0f);
313
314 x = (int32)((((verts[rightvert].x) / 65536.0f) + (xslope * prestep)) * 65536.0) + ((1 << 16) - 1);
315 u = (int32)((((verts[rightvert].u) / 65536.0f) + (uslope * prestep)) * 65536.0) + ((1 << 16) - 1);
316 v = (int32)((((verts[rightvert].v) / 65536.0f) + (vslope * prestep)) * 65536.0) + ((1 << 16) - 1);
317 a = (int32)((GETAValue(verts[rightvert].colour) + (aslope * prestep)) * 65536.0) + ((1 << 16) - 1);
318 r = (int32)((GETRValue(verts[rightvert].colour) + (rslope * prestep)) * 65536.0) + ((1 << 16) - 1);
319 g = (int32)((GETGValue(verts[rightvert].colour) + (gslope * prestep)) * 65536.0) + ((1 << 16) - 1);
320 b = (int32)((GETBValue(verts[rightvert].colour) + (bslope * prestep)) * 65536.0) + ((1 << 16) - 1);
321
322 ixslope = (int32)(xslope * 65536.0);
323 iuslope = (int32)(uslope * 65536.0);
324 ivslope = (int32)(vslope * 65536.0);
325 iaslope = (int32)(aslope * 65536.0);
326 irslope = (int32)(rslope * 65536.0);
327 igslope = (int32)(gslope * 65536.0);
328 ibslope = (int32)(bslope * 65536.0);
329
330 for (j = spantopy; j < spanbottomy; j++) {
331 pspan->x1 = x >> 16;
332 pspan->u1 = u >> 16;
333 pspan->v1 = v >> 16;
334 pspan->a1 = a >> 16;
335 pspan->r1 = r >> 16;
336 pspan->g1 = g >> 16;
337 pspan->b1 = b >> 16;
338 x += ixslope;
339 u += iuslope;
340 v += ivslope;
341 a += iaslope;
342 r += irslope;
343 g += igslope;
344 b += ibslope;
345 pspan++;
346 }
347 }
348
349 rightvert = (rightvert + 1) % nVerts;
350 } while (rightvert != bottomvert);
351
352 // Draw the spans
353 pspan = spans;
354
355 int32 mipw = myTexHan.w >> mip_map_level;
356 int32 miph = myTexHan.h >> mip_map_level;
357
358 for (i = itopy; i < ibottomy; i++) {
359 count = pspan->x1 - pspan->x0;
360 if (count > 0) {
361 x = pspan->x0;
362 u = (pspan->u0 << 8);
363 v = (pspan->v0 << 8);
364 a = pspan->a0 << 8;
365 r = pspan->r0 << 8;
366 g = pspan->g0 << 8;
367 b = pspan->b0 << 8;
368
369 iuslope = ((pspan->u1 << 8) - u) / count;
370 ivslope = ((pspan->v1 << 8) - v) / count;
371 iaslope = ((pspan->a1 << 8) - a) / count;
372 irslope = ((pspan->r1 << 8) - r) / count;
373 igslope = ((pspan->g1 << 8) - g) / count;
374 ibslope = ((pspan->b1 << 8) - b) / count;
375
376 char *left = myRenDev.pRGB + (myRenDev.RGBPitch * i) + myRenDev.RGBBytesPerPixel * x;
377 char *zleft = myRenDev.pZ + (myRenDev.ZPitch * i) + myRenDev.ZBytesPerPixel * pspan->x0;
378 do {
379 int32 pu = (u >> (8 + mip_map_level));
380 int32 pv = (v >> (8 + mip_map_level));
381
382 if (pu < 0)
383 pu = 0;
384 if (pu >= mipw)
385 pu = mipw - 1;
386
387 if (pv < 0)
388 pv = 0;
389 if (pv >= miph)
390 pv = miph - 1;
391
392 uint32 toff = (pu + (pv * mipw)) * myTexHan.bpp;
393 uint8 *texel = ((uint8 *)(myTexHan.pRGBA[mip_map_level])) + toff;
394
395 // RGB data
396 int32 ta, tr, tg, tb;
397 if (myTexHan.bpp > 3) {
398 ta = *(texel + 3);
399 tr = *(texel + 2);
400 tg = *(texel + 1);
401 tb = *(texel + 0);
402 } else {
403 // Palette data
404 uint8 index = *texel;
405 uint32 colour = myTexHan.palette[index];
406 ta = ((colour >> 24) & 0xFF);
407 tr = ((colour >> 16) & 0xFF);
408 tg = ((colour >> 8) & 0xFF);
409 tb = ((colour >> 0) & 0xFF);
410 }
411
412 // BGR : 128 = scale of 1.0
413 int32 pr = ((r >> 8) * tr);
414 int32 pg = ((g >> 8) * tg);
415 int32 pb = ((b >> 8) * tb);
416
417 if (pr < 0)
418 pr = 0;
419 if (pg < 0)
420 pg = 0;
421 if (pb < 0)
422 pb = 0;
423
424 pr = pr >> 7;
425 pg = pg >> 7;
426 pb = pb >> 7;
427
428 if (pr > 255)
429 pr = 255;
430 if (pg > 255)
431 pg = 255;
432 if (pb > 255)
433 pb = 255;
434
435 *(left + 0) = (char)pb;
436 *(left + 1) = (char)pg;
437 *(left + 2) = (char)pr;
438 *(left + 3) = (char)ta; // use the texture alpha value
439 *(uint16 *)(zleft + 0) = z;
440
441 left += myRenDev.RGBBytesPerPixel;
442 zleft += myRenDev.ZBytesPerPixel;
443 x++;
444 u += iuslope;
445 v += ivslope;
446 r += irslope;
447 g += igslope;
448 b += ibslope;
449 count--;
450 } while (count > 0);
451 }
452 pspan++;
453 }
454 return 1;
455 }
456
DrawFlatUnTexturedPolygon(const vertex2D * verts,int32 nVerts,uint16 z)457 int32 DrawFlatUnTexturedPolygon(const vertex2D *verts, int32 nVerts, uint16 z) {
458 int32 i, j, topvert, bottomvert, leftvert, rightvert, nextvert;
459 int32 itopy, ibottomy, ixslope, spantopy, spanbottomy, x, count;
460 float topy, bottomy, xslope, height, width, prestep;
461 float y;
462 span_t *pspan;
463
464 if (myRenDev.pRGB == NULL)
465 return 0;
466
467 // Test for clockwise polygons
468 int32 l0x = (verts[0].x - verts[1].x) >> 16;
469 int32 l0y = (verts[0].y - verts[1].y) >> 16;
470 int32 l1x = (verts[2].x - verts[1].x) >> 16;
471 int32 l1y = (verts[2].y - verts[1].y) >> 16;
472 if (l0x * l1y > l0y * l1x) {
473 return 0;
474 }
475
476 // The colour is in vertex 0
477 uint8 a0 = GETAValue(verts[0].colour);
478 uint8 r0 = GETRValue(verts[0].colour);
479 uint8 g0 = GETGValue(verts[0].colour);
480 uint8 b0 = GETBValue(verts[0].colour);
481
482 topy = 999999.0f;
483 bottomy = -999999.0f;
484 topvert = 0;
485 bottomvert = 0;
486 for (i = 0; i < nVerts; i++) {
487 y = (float)(verts[i].y / 65536.0f);
488 if (y < topy) {
489 topy = y;
490 topvert = i;
491 }
492 if (y > bottomy) {
493 bottomy = y;
494 bottomvert = i;
495 }
496 }
497
498 itopy = (int32)ceil(topy);
499 ibottomy = (int32)ceil(bottomy);
500
501 // reject polygons that don't cross a scan
502 if (ibottomy == itopy)
503 return 1;
504
505 // Scan out the left edge
506 pspan = spans;
507 leftvert = topvert;
508
509 do {
510 nextvert = leftvert - 1;
511 if (nextvert < 0)
512 nextvert = nVerts - 1;
513 y = (float)(verts[leftvert].y / 65536.0f);
514 spantopy = (int32)ceil(y);
515 y = (float)(verts[nextvert].y / 65536.0f);
516 spanbottomy = (int32)ceil(y);
517 if (spantopy < spanbottomy) {
518 height = (float)((int32)(verts[nextvert].y - verts[leftvert].y) / 65536.0f);
519 width = (float)((int32)(verts[nextvert].x - verts[leftvert].x) / 65536.0f);
520
521 xslope = width / height;
522
523 prestep = spantopy - (float)((verts[leftvert].y) / 65536.0f);
524
525 x = (int32)((((verts[leftvert].x) / 65536.0f) + (xslope * prestep)) * 65536.0) + ((1 << 16) - 1);
526
527 ixslope = (int32)(xslope * 65536.0);
528
529 for (j = spantopy; j < spanbottomy; j++) {
530 pspan->x0 = x >> 16;
531 x += ixslope;
532 pspan++;
533 }
534 }
535
536 leftvert--;
537 if (leftvert < 0)
538 leftvert = nVerts - 1;
539 } while (leftvert != bottomvert);
540
541 // Scan out the right edge
542 pspan = spans;
543 rightvert = topvert;
544
545 do {
546 nextvert = (rightvert + 1) % nVerts;
547 y = (float)(verts[rightvert].y / 65536.0f);
548 spantopy = (int32)ceil(y);
549 y = (float)(verts[nextvert].y / 65536.0f);
550 spanbottomy = (int32)ceil(y);
551 if (spantopy < spanbottomy) {
552 height = (float)((verts[nextvert].y - verts[rightvert].y) / 65536.0f);
553 width = (float)((verts[nextvert].x - verts[rightvert].x) / 65536.0f);
554
555 xslope = width / height;
556
557 prestep = spantopy - (float)((verts[rightvert].y) / 65536.0f);
558
559 x = (int32)((((verts[rightvert].x) / 65536.0f) + (xslope * prestep)) * 65536.0) + ((1 << 16) - 1);
560
561 ixslope = (int32)(xslope * 65536.0);
562
563 for (j = spantopy; j < spanbottomy; j++) {
564 pspan->x1 = x >> 16;
565 x += ixslope;
566 pspan++;
567 }
568 }
569
570 rightvert = (rightvert + 1) % nVerts;
571 } while (rightvert != bottomvert);
572
573 // Draw the spans
574 pspan = spans;
575
576 for (i = itopy; i < ibottomy; i++) {
577 count = pspan->x1 - pspan->x0;
578 if (count > 0) {
579 char *left = myRenDev.pRGB + (myRenDev.RGBPitch * i) + myRenDev.RGBBytesPerPixel * pspan->x0;
580 char *zleft = myRenDev.pZ + (myRenDev.ZPitch * i) + myRenDev.ZBytesPerPixel * pspan->x0;
581 do {
582 *(left + 0) = b0;
583 *(left + 1) = g0;
584 *(left + 2) = r0;
585 *(left + 3) = a0;
586 left += myRenDev.RGBBytesPerPixel;
587 *(uint16 *)(zleft + 0) = z;
588 zleft += myRenDev.ZBytesPerPixel;
589 count--;
590 } while (count > 0);
591 }
592 pspan++;
593 }
594 return 1;
595 }
596
DrawGouraudUnTexturedPolygon(const vertex2D * verts,int32 nVerts,uint16 z)597 int32 DrawGouraudUnTexturedPolygon(const vertex2D *verts, int32 nVerts, uint16 z) {
598 int32 i, j, topvert, bottomvert, leftvert, rightvert, nextvert;
599 int32 itopy, ibottomy, spantopy, spanbottomy, count;
600 int32 ixslope, iaslope, irslope, igslope, ibslope;
601 int32 x, a, r, g, b;
602 float topy, bottomy, xslope, aslope, rslope, gslope, bslope;
603 float height, width, prestep;
604 float y;
605 span_t *pspan;
606
607 if (myRenDev.pRGB == NULL)
608 return 0;
609
610 // Test for clockwise polygons
611 int32 l0x = (verts[0].x - verts[1].x) >> 16;
612 int32 l0y = (verts[0].y - verts[1].y) >> 16;
613 int32 l1x = (verts[2].x - verts[1].x) >> 16;
614 int32 l1y = (verts[2].y - verts[1].y) >> 16;
615 if (l0x * l1y > l0y * l1x) {
616 return 0;
617 }
618
619 topy = 999999.0f;
620 bottomy = -999999.0f;
621 topvert = 0;
622 bottomvert = 0;
623 for (i = 0; i < nVerts; i++) {
624 y = (float)((verts[i].y) / 65536.0f);
625 if (y < topy) {
626 topy = y;
627 topvert = i;
628 }
629 if (y > bottomy) {
630 bottomy = y;
631 bottomvert = i;
632 }
633 }
634
635 itopy = (int32)ceil(topy);
636 ibottomy = (int32)ceil(bottomy);
637
638 if (ibottomy == itopy)
639 return 1; // reject polygons that don't cross a scan
640
641 // Scan out the left edge
642 pspan = spans;
643 leftvert = topvert;
644
645 do {
646 nextvert = leftvert - 1;
647 if (nextvert < 0)
648 nextvert = nVerts - 1;
649 y = (float)((verts[leftvert].y) / 65536.0f);
650 spantopy = (int32)ceil(y);
651 y = (float)((verts[nextvert].y) / 65536.0f);
652 spanbottomy = (int32)ceil(y);
653 if (spantopy < spanbottomy) {
654 height = (float)((verts[nextvert].y - verts[leftvert].y) / 65536.0f);
655 width = (float)((verts[nextvert].x - verts[leftvert].x) / 65536.0f);
656
657 xslope = width / height;
658 aslope = (GETAValue(verts[nextvert].colour) - GETAValue(verts[leftvert].colour)) / height;
659 rslope = (GETRValue(verts[nextvert].colour) - GETRValue(verts[leftvert].colour)) / height;
660 gslope = (GETGValue(verts[nextvert].colour) - GETGValue(verts[leftvert].colour)) / height;
661 bslope = (GETBValue(verts[nextvert].colour) - GETBValue(verts[leftvert].colour)) / height;
662
663 prestep = spantopy - (float)((verts[leftvert].y) / 65536.0f);
664
665 x = (int32)((((verts[leftvert].x) / 65536.0f) + (xslope * prestep)) * 65536.0) + ((1 << 16) - 1);
666 a = (int32)((GETAValue(verts[leftvert].colour) + (aslope * prestep)) * 65536.0) + ((1 << 16) - 1);
667 r = (int32)((GETRValue(verts[leftvert].colour) + (rslope * prestep)) * 65536.0) + ((1 << 16) - 1);
668 g = (int32)((GETGValue(verts[leftvert].colour) + (gslope * prestep)) * 65536.0) + ((1 << 16) - 1);
669 b = (int32)((GETBValue(verts[leftvert].colour) + (bslope * prestep)) * 65536.0) + ((1 << 16) - 1);
670
671 ixslope = (int32)(xslope * 65536.0);
672 iaslope = (int32)(aslope * 65536.0);
673 irslope = (int32)(rslope * 65536.0);
674 igslope = (int32)(gslope * 65536.0);
675 ibslope = (int32)(bslope * 65536.0);
676
677 for (j = spantopy; j < spanbottomy; j++) {
678 pspan->x0 = x >> 16;
679 pspan->a0 = a >> 16;
680 pspan->r0 = r >> 16;
681 pspan->g0 = g >> 16;
682 pspan->b0 = b >> 16;
683 x += ixslope;
684 a += iaslope;
685 r += irslope;
686 g += igslope;
687 b += ibslope;
688 pspan++;
689 }
690 }
691
692 leftvert--;
693 if (leftvert < 0)
694 leftvert = nVerts - 1;
695 } while (leftvert != bottomvert);
696
697 // Scan out the right edge
698 pspan = spans;
699 rightvert = topvert;
700
701 do {
702 nextvert = (rightvert + 1) % nVerts;
703 y = (float)((verts[rightvert].y) / 65536.0f);
704 spantopy = (int32)ceil(y);
705 y = (float)((verts[nextvert].y) / 65536.0f);
706 spanbottomy = (int32)ceil(y);
707 if (spantopy < spanbottomy) {
708 height = (float)((verts[nextvert].y - verts[rightvert].y) / 65536.0f);
709 width = (float)((verts[nextvert].x - verts[rightvert].x) / 65536.0f);
710
711 xslope = width / height;
712 aslope = (GETAValue(verts[nextvert].colour) - GETAValue(verts[rightvert].colour)) / height;
713 rslope = (GETRValue(verts[nextvert].colour) - GETRValue(verts[rightvert].colour)) / height;
714 gslope = (GETGValue(verts[nextvert].colour) - GETGValue(verts[rightvert].colour)) / height;
715 bslope = (GETBValue(verts[nextvert].colour) - GETBValue(verts[rightvert].colour)) / height;
716
717 prestep = spantopy - (float)((verts[rightvert].y) / 65536.0f);
718
719 x = (int32)((((verts[rightvert].x) / 65536.0f) + (xslope * prestep)) * 65536.0) + ((1 << 16) - 1);
720 a = (int32)((GETAValue(verts[rightvert].colour) + (aslope * prestep)) * 65536.0) + ((1 << 16) - 1);
721 r = (int32)((GETRValue(verts[rightvert].colour) + (rslope * prestep)) * 65536.0) + ((1 << 16) - 1);
722 g = (int32)((GETGValue(verts[rightvert].colour) + (gslope * prestep)) * 65536.0) + ((1 << 16) - 1);
723 b = (int32)((GETBValue(verts[rightvert].colour) + (bslope * prestep)) * 65536.0) + ((1 << 16) - 1);
724
725 ixslope = (int32)(xslope * 65536.0);
726 iaslope = (int32)(aslope * 65536.0);
727 irslope = (int32)(rslope * 65536.0);
728 igslope = (int32)(gslope * 65536.0);
729 ibslope = (int32)(bslope * 65536.0);
730
731 for (j = spantopy; j < spanbottomy; j++) {
732 pspan->x1 = x >> 16;
733 pspan->a1 = a >> 16;
734 pspan->r1 = r >> 16;
735 pspan->g1 = g >> 16;
736 pspan->b1 = b >> 16;
737 x += ixslope;
738 a += iaslope;
739 r += irslope;
740 g += igslope;
741 b += ibslope;
742 pspan++;
743 }
744 }
745
746 rightvert = (rightvert + 1) % nVerts;
747 } while (rightvert != bottomvert);
748
749 // Draw the spans
750 pspan = spans;
751
752 for (i = itopy; i < ibottomy; i++) {
753 count = pspan->x1 - pspan->x0;
754 if (count > 0) {
755 x = pspan->x0;
756 a = pspan->a0 << 8;
757 r = pspan->r0 << 8;
758 g = pspan->g0 << 8;
759 b = pspan->b0 << 8;
760 iaslope = ((pspan->a1 << 8) - a) / count;
761 irslope = ((pspan->r1 << 8) - r) / count;
762 igslope = ((pspan->g1 << 8) - g) / count;
763 ibslope = ((pspan->b1 << 8) - b) / count;
764 char *left = myRenDev.pRGB + (myRenDev.RGBPitch * i) + myRenDev.RGBBytesPerPixel * x;
765 char *zleft = myRenDev.pZ + (myRenDev.ZPitch * i) + myRenDev.ZBytesPerPixel * pspan->x0;
766 do {
767 *(left + 0) = (char)(b >> 8);
768 *(left + 1) = (char)(g >> 8);
769 *(left + 2) = (char)(r >> 8);
770 *(left + 3) = (char)(a >> 8);
771 *(uint16 *)(zleft + 0) = z;
772 zleft += myRenDev.ZBytesPerPixel;
773 left += myRenDev.RGBBytesPerPixel;
774 x++;
775 r += irslope;
776 g += igslope;
777 b += ibslope;
778 count--;
779 } while (count > 0);
780 }
781 pspan++;
782 }
783 return 1;
784 }
785
DrawFlatTexturedPolygon(const vertex2D * verts,int32 nVerts,uint16 z)786 int32 DrawFlatTexturedPolygon(const vertex2D *verts, int32 nVerts, uint16 z) {
787 int32 i, j, topvert, bottomvert, leftvert, rightvert, nextvert;
788 int32 itopy, ibottomy, spantopy, spanbottomy, count;
789 int32 x, u, v;
790 int32 ixslope, iuslope, ivslope;
791 float topy, bottomy, height, width, prestep;
792 float xslope, uslope, vslope;
793 float y;
794 span_t *pspan;
795
796 if (myRenDev.pRGB == NULL)
797 return 0;
798 if (myTexHan.pRGBA[mip_map_level] == NULL)
799 return 0;
800
801 // Test for clockwise polygons
802 int32 l0x = (verts[0].x - verts[1].x) >> 16;
803 int32 l0y = (verts[0].y - verts[1].y) >> 16;
804 int32 l1x = (verts[2].x - verts[1].x) >> 16;
805 int32 l1y = (verts[2].y - verts[1].y) >> 16;
806 if (l0x * l1y > l0y * l1x) {
807 return 0;
808 }
809
810 // uint8 a0 = GETAValue(verts[0].colour);
811 uint8 r0 = GETRValue(verts[0].colour);
812 uint8 g0 = GETGValue(verts[0].colour);
813 uint8 b0 = GETBValue(verts[0].colour);
814
815 topy = 999999.0f;
816 bottomy = -999999.0f;
817 topvert = 0;
818 bottomvert = 0;
819 for (i = 0; i < nVerts; i++) {
820 y = (float)((verts[i].y) / 65536.0f);
821 if (y < topy) {
822 topy = y;
823 topvert = i;
824 }
825 if (y > bottomy) {
826 bottomy = y;
827 bottomvert = i;
828 }
829 }
830
831 itopy = (int32)ceil(topy);
832 ibottomy = (int32)ceil(bottomy);
833
834 if (ibottomy == itopy)
835 return 1; // reject polygons that don't cross a scan
836
837 // Scan out the left edge
838 pspan = spans;
839 leftvert = topvert;
840
841 do {
842 nextvert = leftvert - 1;
843 if (nextvert < 0)
844 nextvert = nVerts - 1;
845 y = (float)((verts[leftvert].y) / 65536.0f);
846 spantopy = (int32)ceil(y);
847 y = (float)((verts[nextvert].y) / 65536.0f);
848 spanbottomy = (int32)ceil(y);
849 if (spantopy < spanbottomy) {
850 height = (float)((verts[nextvert].y - verts[leftvert].y) / 65536.0f);
851 width = (float)((verts[nextvert].x - verts[leftvert].x) / 65536.0f);
852
853 xslope = width / height;
854 uslope = (float)((verts[nextvert].u - verts[leftvert].u) / 65536.0f) / height;
855 vslope = (float)((verts[nextvert].v - verts[leftvert].v) / 65536.0f) / height;
856
857 prestep = spantopy - (float)((verts[leftvert].y) / 65536.0f);
858
859 x = (int32)((((verts[leftvert].x) / 65536.0f) + (xslope * prestep)) * 65536.0) + ((1 << 16) - 1);
860 u = (int32)((((verts[leftvert].u) / 65536.0f) + (uslope * prestep)) * 65536.0) + ((1 << 16) - 1);
861 v = (int32)((((verts[leftvert].v) / 65536.0f) + (vslope * prestep)) * 65536.0) + ((1 << 16) - 1);
862
863 ixslope = (int32)(xslope * 65536.0);
864 iuslope = (int32)(uslope * 65536.0);
865 ivslope = (int32)(vslope * 65536.0);
866
867 for (j = spantopy; j < spanbottomy; j++) {
868 pspan->x0 = x >> 16;
869 pspan->u0 = u >> 16;
870 pspan->v0 = v >> 16;
871 x += ixslope;
872 u += iuslope;
873 v += ivslope;
874 pspan++;
875 }
876 }
877
878 leftvert--;
879 if (leftvert < 0)
880 leftvert = nVerts - 1;
881 } while (leftvert != bottomvert);
882
883 // Scan out the right edge
884 pspan = spans;
885 rightvert = topvert;
886
887 do {
888 nextvert = (rightvert + 1) % nVerts;
889 y = (float)((verts[rightvert].y) / 65536.0f);
890 spantopy = (int32)ceil(y);
891 y = (float)((verts[nextvert].y) / 65536.0f);
892 spanbottomy = (int32)ceil(y);
893 if (spantopy < spanbottomy) {
894 height = (float)((verts[nextvert].y - verts[rightvert].y) / 65536.0f);
895 width = (float)((verts[nextvert].x - verts[rightvert].x) / 65536.0f);
896
897 xslope = width / height;
898 uslope = (float)((verts[nextvert].u - verts[rightvert].u) / 65536.0f) / height;
899 vslope = (float)((verts[nextvert].v - verts[rightvert].v) / 65536.0f) / height;
900
901 prestep = spantopy - (float)((verts[rightvert].y) / 65536.0f);
902
903 x = (int32)((((verts[rightvert].x) / 65536.0f) + (xslope * prestep)) * 65536.0) + ((1 << 16) - 1);
904 u = (int32)((((verts[rightvert].u) / 65536.0f) + (uslope * prestep)) * 65536.0) + ((1 << 16) - 1);
905 v = (int32)((((verts[rightvert].v) / 65536.0f) + (vslope * prestep)) * 65536.0) + ((1 << 16) - 1);
906
907 ixslope = (int32)(xslope * 65536.0);
908 iuslope = (int32)(uslope * 65536.0);
909 ivslope = (int32)(vslope * 65536.0);
910
911 for (j = spantopy; j < spanbottomy; j++) {
912 pspan->x1 = x >> 16;
913 pspan->u1 = u >> 16;
914 pspan->v1 = v >> 16;
915 x += ixslope;
916 u += iuslope;
917 v += ivslope;
918 pspan++;
919 }
920 }
921
922 rightvert = (rightvert + 1) % nVerts;
923 } while (rightvert != bottomvert);
924
925 // Draw the spans
926 pspan = spans;
927
928 int32 mipw = myTexHan.w >> mip_map_level;
929 int32 miph = myTexHan.h >> mip_map_level;
930
931 for (i = itopy; i < ibottomy; i++) {
932 count = pspan->x1 - pspan->x0;
933 if (count > 0) {
934 x = pspan->x0;
935 u = (pspan->u0 << 8);
936 v = (pspan->v0 << 8);
937
938 iuslope = ((pspan->u1 << 8) - u) / count;
939 ivslope = ((pspan->v1 << 8) - v) / count;
940
941 char *left = myRenDev.pRGB + (myRenDev.RGBPitch * i) + myRenDev.RGBBytesPerPixel * x;
942 char *zleft = myRenDev.pZ + (myRenDev.ZPitch * i) + myRenDev.ZBytesPerPixel * pspan->x0;
943 do {
944 int32 pu = (u >> (8 + mip_map_level));
945 int32 pv = (v >> (8 + mip_map_level));
946
947 if (pu < 0)
948 pu = 0;
949 if (pu >= mipw)
950 pu = mipw - 1;
951
952 if (pv < 0)
953 pv = 0;
954 if (pv >= miph)
955 pv = miph - 1;
956
957 uint32 toff = (pu + (pv * mipw)) * myTexHan.bpp;
958 uint8 *texel = ((uint8 *)(myTexHan.pRGBA[mip_map_level])) + toff;
959
960 // RGB data
961 int32 ta, tr, tg, tb;
962 if (myTexHan.bpp > 3) {
963 ta = *(texel + 3);
964 tr = *(texel + 2);
965 tg = *(texel + 1);
966 tb = *(texel + 0);
967 } else {
968 // Palette data
969 uint8 index = *texel;
970 uint32 colour = myTexHan.palette[index];
971 ta = (uint8)((colour >> 24) & 0xFF);
972 tr = (uint8)((colour >> 16) & 0xFF);
973 tg = (uint8)((colour >> 8) & 0xFF);
974 tb = (uint8)((colour >> 0) & 0xFF);
975 }
976 // BGR : 128 = scale of 1.0
977 // int32 a = a0;
978 int32 r = r0;
979 int32 g = g0;
980 int32 b = b0;
981
982 r = (r * tr);
983 g = (g * tg);
984 b = (b * tb);
985
986 if (r < 0)
987 r = 0;
988 if (g < 0)
989 g = 0;
990 if (b < 0)
991 b = 0;
992
993 r = r >> 7;
994 g = g >> 7;
995 b = b >> 7;
996
997 if (r > 255)
998 r = 255;
999 if (g > 255)
1000 g = 255;
1001 if (b > 255)
1002 b = 255;
1003
1004 *(left + 0) = (char)b;
1005 *(left + 1) = (char)g;
1006 *(left + 2) = (char)r;
1007 *(left + 3) = (char)ta; // use the texture alpha value
1008
1009 *(uint16 *)(zleft + 0) = z;
1010 left += myRenDev.RGBBytesPerPixel;
1011 zleft += myRenDev.ZBytesPerPixel;
1012 x++;
1013 u += iuslope;
1014 v += ivslope;
1015 count--;
1016 } while (count > 0);
1017 }
1018 pspan++;
1019 }
1020 return 1;
1021 }
1022
1023 } // End of namespace ICB
1024