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