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/global_objects.h"
30 #include "engines/icb/p4_generic_pc.h"
31 
32 namespace ICB {
33 
34 // This type is used by General_quad_draw_24_32().
35 typedef struct { int32 nX, nY; } Span;
36 
37 // This function is used only inside this file.
38 static void RawSpriteDraw(uint8 *pSurfaceBitmap, uint32 nPitch, uint32 nSurfaceWidth, uint32 nSurfaceHeight, _pxSprite *pSprite, uint8 *pPalette, int32 nX, int32 nY,
39 						  uint32 *nTransparencyRef, uint8 nOpacity);
40 
Draw_horizontal_line(int32 xx,int32 yy,uint32 len,_rgb * pen,uint8 * ad,uint32 pitch)41 void Draw_horizontal_line(int32 xx, int32 yy, uint32 len, _rgb *pen, uint8 *ad, uint32 pitch) {
42 	// viewport coordinates
43 	// 640*480 screen
44 	// 24 or 32but colour
45 
46 	uint32 j;
47 
48 	// check top and bottom
49 	if (yy < 0)
50 		return;
51 	if (yy > 479)
52 		return;
53 
54 	// line totaly off left
55 	if ((int32)(xx + len) < 0)
56 		return;
57 
58 	// line totally off right
59 	if (xx > 639)
60 		return;
61 
62 	// clip left
63 	if (xx < 0) {
64 		len -= (0 - xx); // 0 - -5 == 5 so len=len-5
65 		xx = 0;
66 	}
67 
68 	// clip right
69 	if ((xx + len) > 639) {
70 		len -= ((xx + len) - 639);
71 	}
72 
73 	// move to y
74 	ad += (yy * pitch);
75 
76 	//	move to x
77 	ad += (xx * 4);
78 
79 	for (j = 0; j < len; j++) {
80 		*(ad++) = pen->blue;
81 		*(ad++) = pen->green;
82 		*(ad++) = pen->red;
83 		ad++;
84 	}
85 }
86 
Draw_vertical_line(int32 xx,int32 yy,uint32 len,_rgb * pen,uint8 * ad,uint32 pitch)87 void Draw_vertical_line(int32 xx, int32 yy, uint32 len, _rgb *pen, uint8 *ad, uint32 pitch) {
88 	// viewport coordinates
89 	// 640*480 screen
90 	// 24 or 32but colour
91 
92 	uint32 j;
93 
94 	// check left/right
95 	if (xx < 0)
96 		return;
97 	if (xx > 639)
98 		return;
99 
100 	// line totaly off top
101 	if ((int32)(yy + len) < 0)
102 		return;
103 
104 	// line totally off bottom
105 	if (yy > 479)
106 		return;
107 
108 	// clip top
109 	if (yy < 0) {
110 		len -= (0 - yy); // 0 - -5 == 5 so len=len-5
111 		yy = 0;
112 	}
113 
114 	// clip bottom
115 	if ((yy + len) > 479) {
116 		len -= ((yy + len) - 479);
117 	}
118 
119 	// move to y
120 	ad += (yy * pitch);
121 
122 	// ove to x
123 	ad += (xx * 4);
124 
125 	for (j = 0; j < len; j++) {
126 		*(ad) = pen->blue;
127 		*(ad + 1) = pen->green;
128 		*(ad + 2) = pen->red;
129 		ad += pitch;
130 	}
131 }
132 
Fill_rect(int32 x,int32 y,int32 x2,int32 y2,uint32 pen,int32)133 void Fill_rect(int32 x, int32 y, int32 x2, int32 y2, uint32 pen, int32 /*z*/) {
134 	// put a filled rectangle on the screen
135 	// backbuffer must be unlocked
136 
137 	LRECT blank;
138 
139 	// completely off screen
140 	if ((x2 <= 0) || (x >= 640) || (y >= 480) || (y2 <= 0))
141 		return;
142 
143 	// clip
144 	if (x < 0)
145 		x = 0;
146 
147 	if (x2 > 640)
148 		x2 = 640;
149 
150 	if (y < 0)
151 		y = 0;
152 
153 	if (y2 > 480)
154 		y2 = 480;
155 
156 	// setup LRECT for bottom line of the screen
157 	blank.left = x;
158 	blank.right = x2;
159 	blank.top = y;
160 	blank.bottom = y2;
161 
162 	surface_manager->Blit_fillfx(working_buffer_id, &blank, pen);
163 }
164 
General_draw_line_24_32(int16 x0,int16 y0,int16 x1,int16 y1,_rgb * colour,uint8 * myScreenBuffer,uint32 pitch,int32 surface_width,int32 surface_height)165 void General_draw_line_24_32(int16 x0, int16 y0, int16 x1, int16 y1, _rgb *colour, uint8 *myScreenBuffer, uint32 pitch, int32 surface_width, int32 surface_height) {
166 	// Uses Bressnham's incremental algorithm!
167 	// we pass a colour
168 	// we pass the surface base
169 	// assume 640*480
170 
171 	int32 dx, dy;
172 	int32 dxmod, dymod;
173 	int32 ince, incne;
174 	int32 d;
175 	int32 x, y;
176 	int32 addTo;
177 	uint32 BYTEWIDE;
178 	uint32 vram = 4;
179 
180 	//#define  RENDERWIDE  640
181 	//#define  RENDERDEEP  480
182 	BYTEWIDE = pitch;
183 
184 	// Make sure we're going from left to right
185 	if (x1 < x0) {
186 		x = x1;
187 		x1 = x0;
188 		x0 = (int16)x;
189 		y = y1;
190 		y1 = y0;
191 		y0 = (int16)y;
192 	}
193 	dx = x1 - x0;
194 	dy = y1 - y0;
195 
196 	if (dx < 0)
197 		dxmod = -dx;
198 	else
199 		dxmod = dx;
200 
201 	if (dy < 0)
202 		dymod = -dy;
203 	else
204 		dymod = dy;
205 
206 	if (dxmod >= dymod) {
207 		if (dy > 0) {
208 			d = 2 * dy - dx;
209 			ince = 2 * dy;
210 			incne = 2 * (dy - dx);
211 			x = x0;
212 			y = y0;
213 			if ((x >= 0) && (x < surface_width) && (y >= 0) && (y < surface_height)) {
214 				myScreenBuffer[y * BYTEWIDE + (x * vram)] = colour->blue;
215 				myScreenBuffer[y * BYTEWIDE + (x * vram) + 1] = colour->green;
216 				myScreenBuffer[y * BYTEWIDE + (x * vram) + 2] = colour->red;
217 			}
218 
219 			while (x < x1) {
220 				if (d <= 0) {
221 					d += ince;
222 					x += 1;
223 				} else {
224 					d += incne;
225 					x += 1;
226 					y += 1;
227 				}
228 				if ((x >= 0) && (x < surface_width) && (y >= 0) && (y < surface_height)) {
229 					myScreenBuffer[y * BYTEWIDE + (x * vram)] = colour->blue;
230 					myScreenBuffer[y * BYTEWIDE + (x * vram) + 1] = colour->green;
231 					myScreenBuffer[y * BYTEWIDE + (x * vram) + 2] = colour->red;
232 				}
233 			}
234 		} else {
235 			addTo = y0;
236 			y0 = 0;
237 			y1 = (int16)(y1 - addTo);
238 			y1 = (int16)-y1;
239 			dy = y1 - y0;
240 
241 			d = 2 * dy - dx;
242 			ince = 2 * dy;
243 			incne = 2 * (dy - dx);
244 			x = x0;
245 			y = y0;
246 			if ((x >= 0) && (x < surface_width) && (addTo - y >= 0) && (addTo - y < surface_height)) {
247 				// myScreenBuffer[(addTo - y) * surface_width + x] = colour;
248 
249 				myScreenBuffer[(addTo - y) * BYTEWIDE + (x * vram)] = colour->blue;
250 				myScreenBuffer[(addTo - y) * BYTEWIDE + ((x * vram) + 1)] = colour->green;
251 				myScreenBuffer[(addTo - y) * BYTEWIDE + ((x * vram) + 2)] = colour->red;
252 			}
253 
254 			while (x < x1) {
255 				if (d <= 0) {
256 					d += ince;
257 					x += 1;
258 				} else {
259 					d += incne;
260 					x += 1;
261 					y += 1;
262 				}
263 				if ((x >= 0) && (x < surface_width) && (addTo - y >= 0) && (addTo - y < surface_height)) {
264 					// myScreenBuffer[(addTo - y) * surface_width + x] = colour;
265 
266 					myScreenBuffer[(addTo - y) * BYTEWIDE + (x * vram)] = colour->blue;
267 					myScreenBuffer[(addTo - y) * BYTEWIDE + ((x * vram) + 1)] = colour->green;
268 					myScreenBuffer[(addTo - y) * BYTEWIDE + ((x * vram) + 2)] = colour->red;
269 				}
270 			}
271 		}
272 	} else {
273 		// OK, y is now going to be the single increment.
274 		//  Ensure the line is going top to bottom
275 		if (y1 < y0) {
276 			x = x1;
277 			x1 = x0;
278 			x0 = (int16)x;
279 			y = y1;
280 			y1 = y0;
281 			y0 = (int16)y;
282 		}
283 		dx = x1 - x0;
284 		dy = y1 - y0;
285 
286 		if (dx > 0) {
287 			d = 2 * dx - dy;
288 			ince = 2 * dx;
289 			incne = 2 * (dx - dy);
290 			x = x0;
291 			y = y0;
292 			if ((x >= 0) && (x < surface_width) && (y >= 0) && (y < surface_height)) {
293 				myScreenBuffer[y * BYTEWIDE + (x * vram)] = colour->blue;
294 				myScreenBuffer[y * BYTEWIDE + (x * vram) + 1] = colour->green;
295 				myScreenBuffer[y * BYTEWIDE + (x * vram) + 2] = colour->red;
296 			}
297 			while (y < y1) {
298 				if (d <= 0) {
299 					d += ince;
300 					y += 1;
301 				} else {
302 					d += incne;
303 					x += 1;
304 					y += 1;
305 				}
306 				if ((x >= 0) && (x < surface_width) && (y >= 0) && (y < surface_height)) {
307 					myScreenBuffer[y * BYTEWIDE + (x * vram)] = colour->blue;
308 					myScreenBuffer[y * BYTEWIDE + (x * vram) + 1] = colour->green;
309 					myScreenBuffer[y * BYTEWIDE + (x * vram) + 2] = colour->red;
310 				}
311 			}
312 		} else {
313 			addTo = x0;
314 			x0 = 0;
315 			x1 = (int16)(x1 - addTo);
316 			x1 = (int16)-x1;
317 			dx = x1 - x0;
318 
319 			d = 2 * dx - dy;
320 			ince = 2 * dx;
321 			incne = 2 * (dx - dy);
322 			x = x0;
323 			y = y0;
324 			if ((addTo - x >= 0) && (addTo - x < surface_width) && (y >= 0) && (y < surface_height)) {
325 				// myScreenBuffer[y * surface_width + addTo - x] = colour;
326 
327 				myScreenBuffer[y * BYTEWIDE + ((addTo - x) * vram)] = colour->blue;
328 				myScreenBuffer[y * BYTEWIDE + (((addTo - x) * vram) + 1)] = colour->green;
329 				myScreenBuffer[y * BYTEWIDE + (((addTo - x) * vram) + 2)] = colour->red;
330 			}
331 
332 			while (y < y1) {
333 				if (d <= 0) {
334 					d += ince;
335 					y += 1;
336 				} else {
337 					d += incne;
338 					x += 1;
339 					y += 1;
340 				}
341 				if ((addTo - x >= 0) && (addTo - x < surface_width) && (y >= 0) && (y < surface_height)) {
342 					// myScreenBuffer[y * surface_width + addTo - x] = colour;
343 
344 					myScreenBuffer[y * BYTEWIDE + ((addTo - x) * vram)] = colour->blue;
345 					myScreenBuffer[y * BYTEWIDE + (((addTo - x) * vram) + 1)] = colour->green;
346 					myScreenBuffer[y * BYTEWIDE + (((addTo - x) * vram) + 2)] = colour->red;
347 				}
348 			}
349 		}
350 	}
351 }
352 
AdditiveGouraudLine(int16 x0,int16 y0,_rgb c0,int16 x1,int16 y1,_rgb c1,uint32 surface_id)353 void AdditiveGouraudLine(int16 x0, int16 y0, _rgb c0, int16 x1, int16 y1, _rgb c1, uint32 surface_id) {
354 	// Uses Bressnham's incremental algorithm!
355 	// We have a start colour and an end colour
356 	int32 dx, dy;
357 	int32 dxmod, dymod;
358 	int32 ince, incne;
359 	int32 d;
360 	int32 x, y;
361 	int32 addTo;
362 
363 	uint8 *surface = (uint8 *)surface_manager->Lock_surface(surface_id);
364 	uint32 pitch = surface_manager->Get_pitch(surface_id);
365 	int32 surface_width = surface_manager->Get_width(surface_id);
366 	int32 surface_height = surface_manager->Get_height(surface_id);
367 
368 	// Make sure we're going from left to right
369 	if (x1 < x0) {
370 		x = x1;
371 		x1 = x0;
372 		x0 = (int16)x;
373 		y = y1;
374 		y1 = y0;
375 		y0 = (int16)y;
376 
377 		_rgb tC = c1;
378 		c1 = c0;
379 		c0 = tC;
380 	}
381 	dx = x1 - x0;
382 	dy = y1 - y0;
383 
384 	if (dx < 0)
385 		dxmod = -dx;
386 	else
387 		dxmod = dx;
388 
389 	if (dy < 0)
390 		dymod = -dy;
391 	else
392 		dymod = dy;
393 
394 	if (dxmod >= dymod) {
395 		if (dy > 0) {
396 			d = 2 * dy - dx;
397 			ince = 2 * dy;
398 			incne = 2 * (dy - dx);
399 			x = x0;
400 			y = y0;
401 			uint8 r = c0.red;
402 			uint8 g = c0.green;
403 			uint8 b = c0.blue;
404 			int32 dr = (dx) ? (c1.red - c0.red) / dx : 0;
405 			int32 dg = (dx) ? (c1.green - c0.green) / dx : 0;
406 			int32 db = (dx) ? (c1.blue - c0.blue) / dx : 0;
407 			uint32 offset = y * pitch + (x << 2);
408 			if ((x >= 0) && (x < surface_width) && (y >= 0) && (y < surface_height)) {
409 				surface[offset] = ((surface[offset] + b) > 255) ? (uint8)255 : (uint8)(surface[offset] + b);
410 				surface[offset + 1] = ((surface[offset] + g) > 255) ? (uint8)255 : (uint8)(surface[offset + 1] + g);
411 				surface[offset + 2] = ((surface[offset] + r) > 255) ? (uint8)255 : (uint8)(surface[offset + 2] + r);
412 			}
413 
414 			while (x < x1) {
415 				r = (uint8)(r + dr);
416 				g = (uint8)(g + dg);
417 				b = (uint8)(b + db);
418 				offset += 4;
419 				x++;
420 
421 				if (d <= 0) {
422 					d += ince;
423 				} else {
424 					d += incne;
425 					y++;
426 					offset += pitch;
427 				}
428 				if ((x >= 0) && (x < surface_width) && (y >= 0) && (y < surface_height)) {
429 					surface[offset] = ((surface[offset] + b) > 255) ? (uint8)255 : (uint8)(surface[offset] + b);
430 					surface[offset + 1] = ((surface[offset] + g) > 255) ? (uint8)255 : (uint8)(surface[offset + 1] + g);
431 					surface[offset + 2] = ((surface[offset] + r) > 255) ? (uint8)255 : (uint8)(surface[offset + 2] + r);
432 				}
433 			}
434 		} else {
435 			addTo = y0;
436 			y0 = 0;
437 			y1 = (int16)(y1 - addTo);
438 			y1 = (int16)-y1;
439 			dy = y1 - y0;
440 
441 			d = 2 * dy - dx;
442 			ince = 2 * dy;
443 			incne = 2 * (dy - dx);
444 			x = x0;
445 			y = y0;
446 			uint8 r = c0.red;
447 			uint8 g = c0.green;
448 			uint8 b = c0.blue;
449 			int32 dr = (dx) ? (c1.red - c0.red) / dx : 0;
450 			int32 dg = (dx) ? (c1.green - c0.green) / dx : 0;
451 			int32 db = (dx) ? (c1.blue - c0.blue) / dx : 0;
452 
453 			uint32 offset = (addTo - y) * pitch + (x << 2);
454 			if ((x >= 0) && (x < surface_width) && (addTo - y >= 0) && (addTo - y < surface_height)) {
455 				surface[offset] = ((surface[offset] + b) > 255) ? (uint8)255 : (uint8)(surface[offset] + b);
456 				surface[offset + 1] = ((surface[offset] + g) > 255) ? (uint8)255 : (uint8)(surface[offset + 1] + g);
457 				surface[offset + 2] = ((surface[offset] + r) > 255) ? (uint8)255 : (uint8)(surface[offset + 2] + r);
458 			}
459 
460 			while (x < x1) {
461 				r = (uint8)(r + dr);
462 				g = (uint8)(g + dg);
463 				b = (uint8)(b + db);
464 
465 				x++;
466 				offset += 4;
467 				if (d <= 0) {
468 					d += ince;
469 				} else {
470 					d += incne;
471 					y++;
472 					offset -= pitch;
473 				}
474 				if ((x >= 0) && (x < surface_width) && (addTo - y >= 0) && (addTo - y < surface_height)) {
475 					surface[offset] = ((surface[offset] + b) > 255) ? (uint8)255 : (uint8)(surface[offset] + b);
476 					surface[offset + 1] = ((surface[offset] + g) > 255) ? (uint8)255 : (uint8)(surface[offset + 1] + g);
477 					surface[offset + 2] = ((surface[offset] + r) > 255) ? (uint8)255 : (uint8)(surface[offset + 2] + r);
478 				}
479 			}
480 		}
481 	} else {
482 		// OK, y is now going to be the single increment.
483 		//  Ensure the line is going top to bottom
484 		if (y1 < y0) {
485 			x = x1;
486 			x1 = x0;
487 			x0 = (int16)x;
488 			y = y1;
489 			y1 = y0;
490 			y0 = (int16)y;
491 
492 			_rgb tC = c1;
493 			c1 = c0;
494 			c0 = tC;
495 		}
496 		dx = x1 - x0;
497 		dy = y1 - y0;
498 
499 		if (dx > 0) {
500 			d = 2 * dx - dy;
501 			ince = 2 * dx;
502 			incne = 2 * (dx - dy);
503 			x = x0;
504 			y = y0;
505 
506 			uint8 r = c0.red;
507 			uint8 g = c0.green;
508 			uint8 b = c0.blue;
509 			int32 dr = (dy) ? (c1.red - c0.red) / dy : 0;
510 			int32 dg = (dy) ? (c1.green - c0.green) / dy : 0;
511 			int32 db = (dy) ? (c1.blue - c0.blue) / dy : 0;
512 
513 			uint32 offset = y * pitch + (x << 2);
514 
515 			if ((x >= 0) && (x < surface_width) && (y >= 0) && (y < surface_height)) {
516 				surface[offset] = ((surface[offset] + b) > 255) ? (uint8)255 : (uint8)(surface[offset] + b);
517 				surface[offset + 1] = ((surface[offset] + g) > 255) ? (uint8)255 : (uint8)(surface[offset + 1] + g);
518 				surface[offset + 2] = ((surface[offset] + r) > 255) ? (uint8)255 : (uint8)(surface[offset + 2] + r);
519 			}
520 			while (y < y1) {
521 				r = (uint8)(r + dr);
522 				g = (uint8)(g + dg);
523 				b = (uint8)(b + db);
524 
525 				offset += pitch;
526 				y++;
527 				if (d <= 0) {
528 					d += ince;
529 				} else {
530 					d += incne;
531 					x++;
532 					offset += 4;
533 				}
534 				if ((x >= 0) && (x < surface_width) && (y >= 0) && (y < surface_height)) {
535 					surface[offset] = ((surface[offset] + b) > 255) ? (uint8)255 : (uint8)(surface[offset] + b);
536 					surface[offset + 1] = ((surface[offset] + g) > 255) ? (uint8)255 : (uint8)(surface[offset + 1] + g);
537 					surface[offset + 2] = ((surface[offset] + r) > 255) ? (uint8)255 : (uint8)(surface[offset + 2] + r);
538 				}
539 			}
540 		} else {
541 			addTo = x0;
542 			x0 = 0;
543 			x1 = (int16)(x1 - addTo);
544 			x1 = (int16)-x1;
545 			dx = x1 - x0;
546 
547 			d = 2 * dx - dy;
548 			ince = 2 * dx;
549 			incne = 2 * (dx - dy);
550 			x = x0;
551 			y = y0;
552 
553 			uint8 r = c0.red;
554 			uint8 g = c0.green;
555 			uint8 b = c0.blue;
556 			int32 dr = (dy) ? (c1.red - c0.red) / dy : 0;
557 			int32 dg = (dy) ? (c1.green - c0.green) / dy : 0;
558 			int32 db = (dy) ? (c1.blue - c0.blue) / dy : 0;
559 
560 			uint32 offset = y * pitch + ((addTo - x) << 2);
561 
562 			if ((addTo - x >= 0) && (addTo - x < surface_width) && (y >= 0) && (y < surface_height)) {
563 				surface[offset] = ((surface[offset] + b) > 255) ? (uint8)255 : (uint8)(surface[offset] + b);
564 				surface[offset + 1] = ((surface[offset] + g) > 255) ? (uint8)255 : (uint8)(surface[offset + 1] + g);
565 				surface[offset + 2] = ((surface[offset] + r) > 255) ? (uint8)255 : (uint8)(surface[offset + 2] + r);
566 			}
567 
568 			while (y < y1) {
569 				r = (uint8)(r + dr);
570 				g = (uint8)(g + dg);
571 				b = (uint8)(b + db);
572 
573 				offset += pitch;
574 				y++;
575 				if (d <= 0) {
576 					d += ince;
577 
578 				} else {
579 					d += incne;
580 					x += 1;
581 					offset -= 4;
582 				}
583 				if ((addTo - x >= 0) && (addTo - x < surface_width) && (y >= 0) && (y < surface_height)) {
584 					surface[offset] = ((surface[offset] + b) > 255) ? (uint8)255 : (uint8)(surface[offset] + b);
585 					surface[offset + 1] = ((surface[offset] + g) > 255) ? (uint8)255 : (uint8)(surface[offset + 1] + g);
586 					surface[offset + 2] = ((surface[offset] + r) > 255) ? (uint8)255 : (uint8)(surface[offset + 2] + r);
587 				}
588 			}
589 		}
590 	}
591 
592 	surface_manager->Unlock_surface(surface_id);
593 }
594 
BlendedLine(int32 x0,int32 y0,int32 x1,int32 y1,_rgb c,uint32 surface_id)595 void BlendedLine(int32 x0, int32 y0, int32 x1, int32 y1, _rgb c, uint32 surface_id) {
596 	uint8 *surface = (uint8 *)surface_manager->Lock_surface(surface_id);
597 	uint32 pitch = surface_manager->Get_pitch(surface_id);
598 	int32 surface_width = surface_manager->Get_width(surface_id);
599 	int32 surface_height = surface_manager->Get_height(surface_id);
600 
601 	BlendedLine(x0, y0, x1, y1, c, surface_width, surface_height, pitch, surface);
602 
603 	surface_manager->Unlock_surface(surface_id);
604 }
605 
BlendedLine(int32 x0,int32 y0,int32 x1,int32 y1,_rgb c,int32 surface_width,int32 surface_height,uint32 pitch,uint8 * surface)606 void BlendedLine(int32 x0, int32 y0, int32 x1, int32 y1, _rgb c, int32 surface_width, int32 surface_height, uint32 pitch, uint8 *surface) {
607 	// Uses Bressnham's incremental algorithm!
608 	// We have a start colour and an end colour
609 	int32 dx, dy;
610 	int32 dxmod, dymod;
611 	int32 ince, incne;
612 	int32 d;
613 	int32 x, y;
614 	int32 addTo;
615 
616 	// Make sure we're going from left to right
617 	if (x1 < x0) {
618 		x = x1;
619 		x1 = x0;
620 		x0 = (int16)x;
621 		y = y1;
622 		y1 = y0;
623 		y0 = (int16)y;
624 	}
625 	dx = x1 - x0;
626 	dy = y1 - y0;
627 
628 	if (dx < 0)
629 		dxmod = -dx;
630 	else
631 		dxmod = dx;
632 
633 	if (dy < 0)
634 		dymod = -dy;
635 	else
636 		dymod = dy;
637 
638 	if (dxmod >= dymod) {
639 		if (dy > 0) {
640 			d = 2 * dy - dx;
641 			ince = 2 * dy;
642 			incne = 2 * (dy - dx);
643 			x = x0;
644 			y = y0;
645 			uint8 r = c.red;
646 			uint8 g = c.green;
647 			uint8 b = c.blue;
648 			uint32 offset = y * pitch + (x << 2);
649 
650 			while (x < 0 || y < 0) {
651 				offset += 4;
652 				x++;
653 
654 				if (d <= 0) {
655 					d += ince;
656 				} else {
657 					d += incne;
658 					y++;
659 					offset += pitch;
660 				}
661 			}
662 
663 			if (x1 >= surface_width)
664 				x1 = surface_width - 1;
665 
666 			while (x < x1) {
667 				offset += 4;
668 				x++;
669 
670 				if (d <= 0) {
671 					d += ince;
672 				} else {
673 					d += incne;
674 					y++;
675 					offset += pitch;
676 				}
677 				if (y < surface_height) {
678 					surface[offset] = (uint8)((surface[offset] + b) >> 1);
679 					surface[offset + 1] = (uint8)((surface[offset + 1] + g) >> 1);
680 					surface[offset + 2] = (uint8)((surface[offset + 2] + r) >> 1);
681 				}
682 			}
683 		} else {
684 			addTo = y0;
685 			y0 = 0;
686 			y1 = (int16)(y1 - addTo);
687 			y1 = (int16)-y1;
688 			dy = y1 - y0;
689 
690 			d = 2 * dy - dx;
691 			ince = 2 * dy;
692 			incne = 2 * (dy - dx);
693 			x = x0;
694 			y = y0;
695 			uint8 r = c.red;
696 			uint8 g = c.green;
697 			uint8 b = c.blue;
698 
699 			uint32 offset = (addTo - y) * pitch + (x << 2);
700 
701 			while ((x < 0) || ((addTo - y) >= surface_height)) {
702 				x++;
703 				offset += 4;
704 				if (d <= 0) {
705 					d += ince;
706 				} else {
707 					d += incne;
708 					y++;
709 					offset -= pitch;
710 				}
711 			}
712 
713 			if (x1 >= surface_width)
714 				x1 = surface_width - 1;
715 
716 			while (x < x1) {
717 				x++;
718 				offset += 4;
719 				if (d <= 0) {
720 					d += ince;
721 				} else {
722 					d += incne;
723 					y++;
724 					offset -= pitch;
725 				}
726 				if ((addTo - y) >= 0) {
727 					surface[offset] = (uint8)((surface[offset] + b) >> 1);
728 					surface[offset + 1] = (uint8)((surface[offset + 1] + g) >> 1);
729 					surface[offset + 2] = (uint8)((surface[offset + 2] + r) >> 1);
730 				}
731 			}
732 		}
733 	} else {
734 		// OK, y is now going to be the single increment.
735 		//  Ensure the line is going top to bottom
736 		if (y1 < y0) {
737 			x = x1;
738 			x1 = x0;
739 			x0 = (int16)x;
740 			y = y1;
741 			y1 = y0;
742 			y0 = (int16)y;
743 		}
744 		dx = x1 - x0;
745 		dy = y1 - y0;
746 
747 		if (dx > 0) {
748 			d = 2 * dx - dy;
749 			ince = 2 * dx;
750 			incne = 2 * (dx - dy);
751 			x = x0;
752 			y = y0;
753 
754 			uint8 r = c.red;
755 			uint8 g = c.green;
756 			uint8 b = c.blue;
757 			uint32 offset = y * pitch + (x << 2);
758 
759 			while ((y < 0) || (x < 0)) {
760 				offset += pitch;
761 				++y;
762 				if (d <= 0) {
763 					d += ince;
764 				} else {
765 					d += incne;
766 					++x;
767 					offset += 4;
768 				}
769 			}
770 
771 			if (y1 >= surface_height)
772 				y1 = surface_height - 1;
773 
774 			while (y < y1) {
775 				offset += pitch;
776 				++y;
777 				if (d <= 0) {
778 					d += ince;
779 				} else {
780 					d += incne;
781 					++x;
782 					offset += 4;
783 				}
784 				if (x < surface_width) {
785 					surface[offset] = (uint8)((surface[offset] + b) >> 1);
786 					surface[offset + 1] = (uint8)((surface[offset + 1] + g) >> 1);
787 					surface[offset + 2] = (uint8)((surface[offset + 2] + r) >> 1);
788 				}
789 			}
790 		} else {
791 			addTo = x0;
792 			x0 = 0;
793 			x1 = (int16)(x1 - addTo);
794 			x1 = (int16)-x1;
795 			dx = x1 - x0;
796 
797 			d = 2 * dx - dy;
798 			ince = 2 * dx;
799 			incne = 2 * (dx - dy);
800 			x = x0;
801 			y = y0;
802 
803 			uint8 r = c.red;
804 			uint8 g = c.green;
805 			uint8 b = c.blue;
806 			uint32 offset = y * pitch + ((addTo - x) << 2);
807 
808 			while ((y < 0) || (addTo - x >= surface_width)) {
809 				offset += pitch;
810 				++y;
811 				if (d <= 0) {
812 					d += ince;
813 
814 				} else {
815 					d += incne;
816 					++x;
817 					offset -= 4;
818 				}
819 			}
820 
821 			if (y1 >= surface_height)
822 				y1 = surface_height - 1;
823 
824 			while (y < y1) {
825 				offset += pitch;
826 				y++;
827 				if (d <= 0) {
828 					d += ince;
829 
830 				} else {
831 					d += incne;
832 					x += 1;
833 					offset -= 4;
834 				}
835 				if ((addTo - x) >= 0) {
836 					surface[offset] = (uint8)((surface[offset] + b) >> 1);
837 					surface[offset + 1] = (uint8)((surface[offset + 1] + g) >> 1);
838 					surface[offset + 2] = (uint8)((surface[offset + 2] + r) >> 1);
839 				}
840 			}
841 		}
842 	}
843 }
844 
SpriteFrameDraw(uint8 * pSurfaceBitmap,uint32 nPitch,uint32 nSurfaceWidth,uint32 nSurfaceHeight,_pxBitmap * pBitmap,uint32 nFrameNumber,uint32 * pnTransparencyRef,uint8 nOpacity)845 void SpriteFrameDraw(uint8 *pSurfaceBitmap,     // IN:  Pointer to the surface's drawing area.
846 					 uint32 nPitch,             // IN:  Pitch for the surface.
847 					 uint32 nSurfaceWidth,      // IN:  Width of the surface.
848 					 uint32 nSurfaceHeight,     // IN:  Height of the surface.
849 					 _pxBitmap *pBitmap,        // IN:  Pointer to the bitmap to render.
850 					 uint32 nFrameNumber,       // IN:  Frame to draw.
851 					 uint32 *pnTransparencyRef, // IN:  Colour to use for transparency.
852 					 uint8 nOpacity             // IN:  Opacity 0-255 to draw sprite into surface.
853 					 ) {
854 	uint8 *pPalette;
855 	_pxSprite *pSprite;
856 
857 	// Get to the sprite frame.
858 	pSprite = pBitmap->Fetch_item_by_number(nFrameNumber);
859 
860 	// Get the palette pointer.
861 	pPalette = pBitmap->Fetch_palette_pointer();
862 
863 	// Now do the actual drawing.
864 	RawSpriteDraw(pSurfaceBitmap, nPitch, nSurfaceWidth, nSurfaceHeight, pSprite, pPalette, pSprite->x, pSprite->y, pnTransparencyRef, nOpacity);
865 }
866 
SpriteXYFrameDraw(uint8 * pSurfaceBitmap,uint32 nPitch,uint32 nSurfaceWidth,uint32 nSurfaceHeight,_pxBitmap * pBitmap,int32 nX,int32 nY,uint32 nFrameNumber,bool8 bCenter,uint32 * pnTransparencyRef,uint8 nOpacity)867 void SpriteXYFrameDraw(uint8 *pSurfaceBitmap,     // IN:  Pointer to the surface's drawing area.
868 					   uint32 nPitch,             // IN:  Pitch for the surface.
869 					   uint32 nSurfaceWidth,      // IN:  Width of the surface.
870 					   uint32 nSurfaceHeight,     // IN:  Height of the surface.
871 					   _pxBitmap *pBitmap,        // IN:  Pointer to the bitmap to render.
872 					   int32 nX,                  // IN:  X-position to draw sprite at (relative to the surface).
873 					   int32 nY,                  // IN:  Y-position to draw sprite at (relative to the surface).
874 					   uint32 nFrameNumber,       // IN:  Frame to draw.
875 					   bool8 bCenter,             // IN:  If true, centre the sprite.
876 					   uint32 *pnTransparencyRef, // IN:  Colour to use for transparency.
877 					   uint8 nOpacity             // IN:  Opacity 0-255 to draw sprite into surface.
878 					   ) {
879 	uint8 *pPalette;
880 	_pxSprite *pSprite;
881 
882 	// Get to the sprite frame.
883 	pSprite = pBitmap->Fetch_item_by_number(nFrameNumber);
884 
885 	// Work out a new plotting position if it is to be centred.
886 	if (bCenter) {
887 		nX -= (pSprite->width >> 1);
888 		nY -= (pSprite->height >> 1);
889 	}
890 
891 	// Get the palette pointer.
892 	pPalette = pBitmap->Fetch_palette_pointer();
893 
894 	// Now do the actual drawing.
895 	RawSpriteDraw(pSurfaceBitmap, nPitch, nSurfaceWidth, nSurfaceHeight, pSprite, pPalette, nX, nY, pnTransparencyRef, nOpacity);
896 }
897 
RawSpriteDraw(uint8 * pSurfaceBitmap,uint32 nPitch,uint32 nSurfaceWidth,uint32 nSurfaceHeight,_pxSprite * pSprite,uint8 * pPalette,int32 nX,int32 nY,uint32 * pnTransparentRef,uint8 nOpacity)898 void RawSpriteDraw(uint8 *pSurfaceBitmap,    // IN:  Pointer to the surface's drawing area.
899 				   uint32 nPitch,            // IN:  Pitch for the surface.
900 				   uint32 nSurfaceWidth,     // IN:  Width of surface in pixels.
901 				   uint32 nSurfaceHeight,    // IN:  Height of surface in pixels.
902 				   _pxSprite *pSprite,       // IN:  Pointer to one frame of a sprite.
903 				   uint8 *pPalette,          // IN:  Pointer to the palette.
904 				   int32 nX,                 // IN:  X-position to draw sprite at (relative to the surface).
905 				   int32 nY,                 // IN:  Y-position to draw sprite at (relative to the surface).
906 				   uint32 *pnTransparentRef, // IN:  Colour to use for transparency.
907 				   uint8 nOpacity            // IN:  If true, pixels are blended into the surface.
908 				   ) {
909 	uint32 x, y;
910 	uint32 *pSurfaceRowStart32;
911 	uint8 *pSurfaceRowStart8;
912 	uint8 *pSpriteData;
913 	uint8 *pPaletteEntry;
914 	int32 nSpriteTop, nSpriteLeft;
915 	int32 nSurfaceTop, nSurfaceLeft;
916 	uint32 nNumRowsToRender, nNumColumnsToRender;
917 	uint32 nSurfaceSkipToNextRow, nSpriteSkipToNextRow;
918 	uint32 nSpriteRowStart;
919 	uint8 nExistingB, nExistingG, nExistingR;
920 	uint8 nNewB, nNewG, nNewR;
921 
922 	// This used to be variable; now it's fixed.
923 	const uint32 nBytesPerPixel = 4;
924 
925 	// If the start position of the sprite is below the bottom row of the surface or its end position
926 	// is before the first row of the surface, there can be nothing to display.
927 	if ((nY >= (int32)nSurfaceHeight) || ((nY + (int32)pSprite->height) <= 0))
928 		return;
929 
930 	// Now do the same check in the horizontal direction.
931 	if ((nX >= (int32)nSurfaceWidth) || ((nX + (int32)pSprite->width) <= 0))
932 		return;
933 
934 	// First work out what proportion of the height of the sprite we have to copy allowing
935 	// for clipping it where it overlaps the edges of the surface.
936 	nNumRowsToRender = pSprite->height;
937 
938 	if (nY < 0) {
939 		nSurfaceTop = 0;
940 		nSpriteTop = abs(nY);
941 		nNumRowsToRender -= nSpriteTop;
942 	} else {
943 		nSurfaceTop = nY;
944 		nSpriteTop = 0;
945 	}
946 
947 	if ((nY + pSprite->height) > nSurfaceHeight)
948 		nNumRowsToRender -= ((nY + pSprite->height) - nSurfaceHeight);
949 
950 	// Now do the same in the horizontal direction.
951 	nNumColumnsToRender = pSprite->width;
952 
953 	if (nX < 0) {
954 		nSurfaceLeft = 0;
955 		nSpriteLeft = abs(nX);
956 		nNumColumnsToRender -= nSpriteLeft;
957 	} else {
958 		nSurfaceLeft = nX;
959 		nSpriteLeft = 0;
960 	}
961 
962 	if ((nX + pSprite->width) > nSurfaceWidth)
963 		nNumColumnsToRender -= ((nX + pSprite->width) - nSurfaceWidth);
964 
965 	// Get to the sprite data.
966 	pSpriteData = pSprite->data;
967 
968 	// Work out the byte in the surface to start drawing at.
969 	pSurfaceRowStart32 = (uint32 *)(pSurfaceBitmap + (nSurfaceTop * nPitch) + (nBytesPerPixel * nSurfaceLeft));
970 	nSurfaceSkipToNextRow = (nPitch - (nBytesPerPixel * nNumColumnsToRender)) >> 2;
971 
972 	// Work out the pixel to start drawing and how much we need to jump when we get to the end of a row.
973 	nSpriteRowStart = nSpriteTop * pSprite->width + nSpriteLeft;
974 	nSpriteSkipToNextRow = pSprite->width - nNumColumnsToRender;
975 
976 	// Check if transparency support is required.
977 	if (pnTransparentRef) {
978 		// Check if pixel blending is required.
979 		if (nOpacity != 255) {
980 			for (y = 0; y < nNumRowsToRender; ++y) {
981 				// Now loop for one row of the image.
982 				for (x = 0; x < nNumColumnsToRender; ++x) {
983 					// Get the palette index for this pixel of the sprite.
984 					pPaletteEntry = pPalette + (pSpriteData[nSpriteRowStart++] << 2);
985 
986 					// Don't print anything if the pixel is transparent.
987 					if (*((uint32 *)pPaletteEntry) != *pnTransparentRef) {
988 						// We are doing pixel merging.
989 						pSurfaceRowStart8 = (uint8 *)pSurfaceRowStart32;
990 
991 						// Get the existing RGB in the surface.
992 						nExistingB = *pSurfaceRowStart8;
993 						nExistingG = *(pSurfaceRowStart8 + 1);
994 						nExistingR = *(pSurfaceRowStart8 + 2);
995 
996 						// Get the new RGB.
997 						nNewB = *pPaletteEntry;
998 						nNewG = *(pPaletteEntry + 1);
999 						nNewR = *(pPaletteEntry + 2);
1000 
1001 						// Merge the pixels.
1002 						nNewB = (uint8)((((nNewB - nExistingB) * nOpacity) >> 8) + nExistingB);
1003 						nNewG = (uint8)((((nNewG - nExistingG) * nOpacity) >> 8) + nExistingG);
1004 						nNewR = (uint8)((((nNewR - nExistingR) * nOpacity) >> 8) + nExistingR);
1005 
1006 						// Write the new colour back to the surface.
1007 						*pSurfaceRowStart8 = (uint8)nNewB;
1008 						*(pSurfaceRowStart8 + 1) = (uint8)nNewG;
1009 						*(pSurfaceRowStart8 + 2) = (uint8)nNewR;
1010 					}
1011 
1012 					++pSurfaceRowStart32;
1013 				}
1014 
1015 				// We have completed a row; need to jump to the start of the next one.
1016 				pSurfaceRowStart32 += nSurfaceSkipToNextRow;
1017 				nSpriteRowStart += nSpriteSkipToNextRow;
1018 			}
1019 		} else {
1020 			for (y = 0; y < nNumRowsToRender; ++y) {
1021 				// Now loop for one row of the image.
1022 				for (x = 0; x < nNumColumnsToRender; ++x) {
1023 					// Get the palette index for this pixel of the sprite.
1024 					pPaletteEntry = pPalette + (pSpriteData[nSpriteRowStart++] << 2);
1025 
1026 					// Don't print anything if the pixel is transparent.
1027 					if (*((uint32 *)pPaletteEntry) != *pnTransparentRef)
1028 						*pSurfaceRowStart32 = *((uint32 *)pPaletteEntry);
1029 
1030 					++pSurfaceRowStart32;
1031 				}
1032 
1033 				// We have completed a row; need to jump to the start of the next one.
1034 				pSurfaceRowStart32 += nSurfaceSkipToNextRow;
1035 				nSpriteRowStart += nSpriteSkipToNextRow;
1036 			}
1037 		}
1038 	} else {
1039 		// No transparency support required.  Check if pixel blending is required.
1040 		if (nOpacity != 255) {
1041 			// Pixel blending required.
1042 			for (y = 0; y < nNumRowsToRender; ++y) {
1043 				// Now loop for one row of the image.
1044 				for (x = 0; x < nNumColumnsToRender; ++x) {
1045 					// Get the palette index for this pixel of the sprite.
1046 					pPaletteEntry = pPalette + (pSpriteData[nSpriteRowStart++] << 2);
1047 
1048 					// We are doing pixel merging.
1049 					pSurfaceRowStart8 = (uint8 *)pSurfaceRowStart32;
1050 
1051 					// Get the existing RGB in the surface.
1052 					nExistingB = *pSurfaceRowStart8;
1053 					nExistingG = *(pSurfaceRowStart8 + 1);
1054 					nExistingR = *(pSurfaceRowStart8 + 2);
1055 
1056 					// Get the new RGB.
1057 					nNewB = *pPaletteEntry;
1058 					nNewG = *(pPaletteEntry + 1);
1059 					nNewR = *(pPaletteEntry + 2);
1060 
1061 					// Merge the pixels.
1062 					nNewB = (uint8)((((nNewB - nExistingB) * nOpacity) >> 8) + nExistingB);
1063 					nNewG = (uint8)((((nNewG - nExistingG) * nOpacity) >> 8) + nExistingG);
1064 					nNewR = (uint8)((((nNewR - nExistingR) * nOpacity) >> 8) + nExistingR);
1065 
1066 					// Write the new colour back to the surface.
1067 					*pSurfaceRowStart8 = (uint8)nNewB;
1068 					*(pSurfaceRowStart8 + 1) = (uint8)nNewG;
1069 					*(pSurfaceRowStart8 + 2) = (uint8)nNewR;
1070 
1071 					++pSurfaceRowStart32;
1072 				}
1073 
1074 				// We have completed a row; need to jump to the start of the next one.
1075 				pSurfaceRowStart32 += nSurfaceSkipToNextRow;
1076 				nSpriteRowStart += nSpriteSkipToNextRow;
1077 			}
1078 		} else {
1079 			// No pixel blending required - just a straight opaque copy.
1080 			for (y = 0; y < nNumRowsToRender; ++y) {
1081 				// Now loop for one row of the image.
1082 				for (x = 0; x < nNumColumnsToRender; ++x) {
1083 					// Get the palette index for this pixel of the sprite.
1084 					pPaletteEntry = pPalette + (pSpriteData[nSpriteRowStart++] << 2);
1085 
1086 					// 32-bit opaque copy is a straight assignment.
1087 					*pSurfaceRowStart32++ = *((uint32 *)pPaletteEntry);
1088 				}
1089 
1090 				// We have completed a row; need to jump to the start of the next one.
1091 				pSurfaceRowStart32 += nSurfaceSkipToNextRow;
1092 				nSpriteRowStart += nSpriteSkipToNextRow;
1093 			}
1094 		}
1095 	}
1096 }
1097 
ConvertPxBitmapRectToRECT(const _PxBitmapRect & sBitmapRect)1098 LRECT ConvertPxBitmapRectToRECT(const _PxBitmapRect &sBitmapRect) {
1099 	LRECT sRect;
1100 
1101 	sRect.left = sBitmapRect.nX;
1102 	sRect.right = (sBitmapRect.nX + sBitmapRect.nWidth) - 1;
1103 	sRect.top = sBitmapRect.nY;
1104 	sRect.bottom = (sBitmapRect.nY + sBitmapRect.nHeight) - 1;
1105 
1106 	return sRect;
1107 }
1108 
General_poly_draw_24_32(_point * pVerts,int32 nNumVerts,_rgb sColour,bool8 bFill,uint8 * pSurface,int32 nPitch,int32,int32)1109 void General_poly_draw_24_32(_point *pVerts, int32 nNumVerts, _rgb sColour, bool8 bFill, uint8 *pSurface, int32 nPitch, int32 /*nSurfaceWidth*/, int32 /*nSurfaceHeight*/) {
1110 	int32 i, j;
1111 	int32 x, y;
1112 	int32 nTopVert, nBottomVert, nLeftVert, nRightVert;
1113 	int32 nNextVert;
1114 	int32 nTopY, nBottomY, nSlope, nSpanTopY, nSpanBottomY;
1115 	int32 nX;
1116 	int32 nCount;
1117 	PXreal fTopY, fBottomY, fSlope, fHeight, fWidth, fPrestep;
1118 	Span pSpans[SCREEN_DEPTH];
1119 	Span *pSpan;
1120 	int32 nBytesPerPixel;
1121 	uint8 *pSurfaceAddress;
1122 
1123 	nTopVert = 0;
1124 	nBottomVert = 0;
1125 	nX = 0;
1126 
1127 	// Some initialisation.
1128 	nBytesPerPixel = 4;
1129 	fTopY = 999999.0f;
1130 	fBottomY = -999999.0f;
1131 
1132 	// Find the top and bottom vertices.
1133 	for (i = 0; i < (int32)nNumVerts; ++i) {
1134 		if (pVerts[i].z < fTopY) {
1135 			fTopY = pVerts[i].z;
1136 			nTopVert = i;
1137 		}
1138 
1139 		if (pVerts[i].z > fBottomY) {
1140 			fBottomY = pVerts[i].z;
1141 			nBottomVert = i;
1142 		}
1143 	}
1144 
1145 	nTopY = (int32)ceil(fTopY);
1146 	nBottomY = (int32)ceil(fBottomY);
1147 
1148 	// Polygon has to have a height to be drawn.
1149 	if (nBottomY == nTopY)
1150 		return;
1151 
1152 	// Scan out the left edge.
1153 	pSpan = pSpans;
1154 	nLeftVert = nTopVert;
1155 
1156 	do {
1157 		nNextVert = nLeftVert - 1;
1158 
1159 		if (nNextVert < 0)
1160 			nNextVert = nNumVerts - 1;
1161 
1162 		nSpanTopY = (int32)ceil(pVerts[nLeftVert].z);
1163 		nSpanBottomY = (int32)ceil(pVerts[nNextVert].z);
1164 
1165 		if (nSpanTopY < nSpanBottomY) {
1166 			fHeight = pVerts[nNextVert].z - pVerts[nLeftVert].z;
1167 			fWidth = pVerts[nNextVert].x - pVerts[nLeftVert].x;
1168 			fSlope = fWidth / fHeight;
1169 			fPrestep = nSpanTopY - pVerts[nLeftVert].z;
1170 			nX = (int32)((pVerts[nLeftVert].x + (fSlope * fPrestep)) * 65536.0f) + ((1 << 16) - 1);
1171 			nSlope = (int32)(fSlope * 65536.0f);
1172 
1173 			for (j = nSpanTopY; j < nSpanBottomY; ++j) {
1174 				pSpan->nX = nX >> 16;
1175 				nX += nSlope;
1176 				++pSpan;
1177 			}
1178 		}
1179 
1180 		--nLeftVert;
1181 		if (nLeftVert < 0)
1182 			nLeftVert = nNumVerts - 1;
1183 
1184 	} while (nLeftVert != nBottomVert);
1185 
1186 	// Scan out the right edge
1187 	pSpan = pSpans;
1188 	nRightVert = nTopVert;
1189 
1190 	do {
1191 		nNextVert = (nRightVert + 1) % nNumVerts;
1192 
1193 		nSpanTopY = (int32)ceil(pVerts[nRightVert].z);
1194 		nSpanBottomY = (int32)ceil(pVerts[nNextVert].z);
1195 
1196 		if (nSpanTopY < nSpanBottomY) {
1197 			fHeight = pVerts[nNextVert].z - pVerts[nRightVert].z;
1198 			fWidth = pVerts[nNextVert].x - pVerts[nRightVert].x;
1199 			fSlope = fWidth / fHeight;
1200 			fPrestep = nSpanTopY - pVerts[nRightVert].z;
1201 			nX = (int32)((pVerts[nRightVert].x + (fSlope * fPrestep)) * 65536.0f) + ((1 << 16) - 1);
1202 			nSlope = (int32)(fSlope * 65536.0f);
1203 
1204 			for (j = nSpanTopY; j < nSpanBottomY; ++j) {
1205 				pSpan->nY = nX >> 16;
1206 				nX += nSlope;
1207 				++pSpan;
1208 			}
1209 		}
1210 
1211 		nRightVert = (nRightVert + 1) % nNumVerts;
1212 
1213 	} while (nRightVert != nBottomVert);
1214 
1215 	// Draw the spans
1216 	pSpan = pSpans;
1217 
1218 	// How we draw depends on the bitmap.
1219 	// Drawing in 32-bit colour depth.  Fill or just outline?
1220 	if (bFill) {
1221 		// Fill the polygon (32-bit colour).
1222 		for (x = nTopY; x < nBottomY; ++x) {
1223 			// Work out the width of the line at this point in the height.
1224 			nCount = pSpan->nY - pSpan->nX;
1225 
1226 			if (nCount > 0) {
1227 				// Work out the start address of the row in our target surface.
1228 				pSurfaceAddress = pSurface + nPitch * x;
1229 
1230 				// Loop along the row.
1231 				for (y = 0; y < nCount; ++y) {
1232 					// Look up the actual colour.
1233 					*pSurfaceAddress++ = sColour.red;
1234 					*pSurfaceAddress++ = sColour.green;
1235 					*pSurfaceAddress++ = sColour.blue;
1236 					*pSurfaceAddress = 0x00;
1237 				}
1238 			}
1239 
1240 			// Move on to the next span we've stored.
1241 			++pSpan;
1242 		}
1243 	} else {
1244 		// Just draw outline (32-bit colour).
1245 		for (x = nTopY; x < nBottomY; ++x) {
1246 			// Work out the width of the line at this point in the height.
1247 			nCount = pSpan->nY - pSpan->nX;
1248 
1249 			if (nCount > 0) {
1250 				// Draw left edge.
1251 				pSurfaceAddress = pSurface + nPitch * x;
1252 				*pSurfaceAddress++ = sColour.red;
1253 				*pSurfaceAddress++ = sColour.green;
1254 				*pSurfaceAddress++ = sColour.blue;
1255 				*pSurfaceAddress = 0x00;
1256 
1257 				// Draw right edge.
1258 				pSurfaceAddress = (pSurface + nPitch * x) + ((nCount - 1) * nBytesPerPixel);
1259 				*pSurfaceAddress++ = sColour.red;
1260 				*pSurfaceAddress++ = sColour.green;
1261 				*pSurfaceAddress++ = sColour.blue;
1262 				*pSurfaceAddress = 0x00;
1263 			}
1264 
1265 			// Move on to the next span we've stored.
1266 			++pSpan;
1267 		}
1268 	}
1269 }
1270 
1271 } // End of namespace ICB
1272