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/gfx/psx_pcdefines.h"
29 #include "engines/icb/gfx/psx_pcgpu.h"
30 #include "engines/icb/gfx/psx_poly.h"
31 #include "engines/icb/gfx/gfxstub.h"
32 
33 #include "common/textconsole.h"
34 
35 namespace ICB {
36 
37 // Defaults for the OT list
38 #define UNLINKED_ADDR (void *)(0xDEADBEAF)
39 #define UNLINKED_LEN (0x6666)
40 
41 // For storing user data in the OT entry e.g. texture pointer
42 void *OTusrData;
43 
44 // No ABR support : at the moment
45 uint16 psxTP;
46 
47 // The emulation of VRAM : 16-bit pixels 1024x512 big
48 uint16 psxVRAM[VRAM_WIDTH * VRAM_HEIGHT];
49 
50 // Set VRAM to a certain colour
ClearImage(RECT16 * rect,uint8 r,uint8 g,uint8 b)51 int32 ClearImage(RECT16 *rect, uint8 r, uint8 g, uint8 b) {
52 	uint16 colour;
53 	int32 x, y;
54 	int32 i;
55 
56 	// Convert 24-bit colour to 15-bit
57 	colour = (uint16)((r >> 3) | ((g >> 3) << 5) | ((b >> 3) << 10));
58 
59 	for (y = rect->y; y < rect->y + rect->h; y++) {
60 		for (x = rect->x; x < rect->x + rect->w; x++) {
61 			i = x + y * VRAM_WIDTH;
62 			psxVRAM[i] = colour;
63 		}
64 	}
65 	return 1;
66 }
67 
68 // Fill VRAM with data
LoadClut(uint32 * clut,int32 x,int32 y)69 uint16 LoadClut(uint32 *clut, int32 x, int32 y) {
70 	RECT16 rect;
71 	setRECT(&rect, (int16)x, (int16)y, 256, 1);
72 	LoadImage(&rect, clut);
73 	return (uint16)getClut(x, y);
74 }
75 
76 // Fill VRAM with data
LoadImage(RECT16 * rect,uint32 * p)77 int32 LoadImage(RECT16 *rect, uint32 *p) {
78 	int32 x, y, i;
79 	uint16 *p16 = (uint16 *)p;
80 
81 	for (y = rect->y; y < rect->y + rect->h; y++) {
82 		for (x = rect->x; x < rect->x + rect->w; x++) {
83 			i = x + y * VRAM_WIDTH;
84 			psxVRAM[i] = *p16;
85 			p16++;
86 		}
87 	}
88 	return 1;
89 }
90 
91 // Move data around within VRAM
MoveImage(RECT16 * rect,int32 x,int32 y)92 int32 MoveImage(RECT16 *rect, int32 x, int32 y) {
93 	int32 x0, y0, i0;
94 	int32 x1, y1, i1;
95 
96 	y1 = y;
97 	for (y0 = rect->y; y0 < rect->y + rect->h; y0++) {
98 		x1 = x;
99 		for (x0 = rect->x; x0 < rect->x + rect->w; x0++) {
100 			i0 = x0 + y0 * VRAM_WIDTH;
101 			i1 = x1 + y1 * VRAM_WIDTH;
102 			psxVRAM[i1] = psxVRAM[i0];
103 			x1++;
104 		}
105 		y1++;
106 	}
107 	return 1;
108 }
109 
110 // Setup the linked list for the OT tags from back to the front
ClearOTagR(OT_tag * ot,uint32 size)111 OT_tag *ClearOTagR(OT_tag *ot, uint32 size) {
112 	int32 i = size - 1;
113 	while (i > 0) {
114 		ot[i].addr = (void *)&ot[i - 1];
115 		ot[i].len = UNLINKED_LEN;
116 		i--;
117 	}
118 	ot[0].addr = UNLINKED_ADDR;
119 	ot[0].len = UNLINKED_LEN;
120 	return ot;
121 }
122 
123 // Setup the linked list for the OT tags from front to back
ClearOTag(OT_tag * ot,uint32 size)124 OT_tag *ClearOTag(OT_tag *ot, uint32 size) {
125 	uint32 i = 0;
126 	while (i < (size - 1)) {
127 		ot[i].addr = (void *)&ot[i + 1];
128 		ot[i].len = UNLINKED_LEN;
129 	}
130 	ot[size - 1].addr = UNLINKED_ADDR;
131 	ot[size - 1].len = UNLINKED_LEN;
132 	return ot;
133 }
134 
135 int32 nPrims;
136 
137 // Draw the damm things
DrawOTag(OT_tag * ot)138 void DrawOTag(OT_tag *ot) {
139 	OT_tag *prim = ot;
140 	nPrims = 0;
141 
142 	while (prim->addr != UNLINKED_ADDR) {
143 		if (prim->len != UNLINKED_LEN) {
144 			DrawPrim((void *)prim);
145 		}
146 		// Move to the next link in the chain
147 		prim = (OT_tag *)(prim->addr);
148 	}
149 }
150 
151 // Draw the base primitive
152 
153 // Should also be checking the lengths to make sure we haven't
154 // got corrupt data
DrawPrim(void * prim)155 void DrawPrim(void *prim) {
156 	P_TAG *p = (P_TAG *)prim;
157 	uint32 code = p->code;
158 	uint32 len = p->len;
159 	uint16 z0 = p->z0;
160 	void *usr = p->usr;
161 	uint8 alpha = 0x00;
162 
163 	// Catch special primitives
164 	// DR_TPAGE
165 	if ((code & 0xe1) == 0xe1) {
166 		psxTP = (uint16)(*((uint32 *)&(p->r0)) & 0xFFFF);
167 		len -= GPUSIZE_DR_TPAGE; // we have used one word of data up
168 		// Move the pointer onto the correct place
169 		p++; // move past the P_TAG
170 
171 		// handle multiple primitives in one block
172 		code = p->code;
173 		if (len > 0) {
174 			len -= GPUSIZE_TAG;
175 		}
176 
177 		// Get the base alpha value
178 		alpha = ((P_HEADER *)(p))->code;
179 		// Modify that based on tbe ABR value
180 		uint8 abr = (uint8)((psxTP >> 5) & 0x3);
181 		if (abr == 0) {
182 			// alpha is 0-64, so 32 is average
183 			alpha = 0xC0 | 0x20; // average of background + foreground
184 		} else if (abr == 1)
185 			alpha = 0x40; // additive
186 		else if (abr == 2)
187 			alpha = 0x80; // subtractive
188 		else if (abr == 3)
189 			// alpha is 0-64 : no error checking
190 			alpha |= 0xC0; // alpha blend
191 		else
192 			alpha = 0x00; // ignore any other modes
193 	}
194 
195 	nPrims++;
196 	// Decode the primitive type and then respond appropiately
197 	// Mask off the primitive modifiers (bottom two bits)
198 	// bit 0 = shade text
199 	// bit 1 = semi-trans
200 	switch (code & 0xFC) {
201 	// Flat Coloured Rectangle
202 	// TILE: code:0x60 length:4
203 	case GPUCODE_TILE: {
204 		TILE *pr = (TILE *)p;
205 		if (len != GPUSIZE_TILE) {
206 			warning("Primitive %p length %d != TILE length %d\n", prim, (uint32)len, GPUSIZE_TILE);
207 			return;
208 		}
209 		DrawTile(pr->x0, pr->y0, pr->w, pr->h, pr->r0, pr->g0, pr->b0, alpha, z0);
210 		break;
211 	}
212 	// Flat Coloured Rectangle 1 pixel width & height
213 	// TILE_1: code:0x68 length:3
214 	case GPUCODE_TILE_1: {
215 		TILE_1 *pr = (TILE_1 *)p;
216 		if (len != GPUSIZE_TILE_1) {
217 			warning("Primitive %p length %d != TILE_1 length %d\n", prim, (uint32)len, GPUSIZE_TILE_1);
218 			return;
219 		}
220 		DrawTile(pr->x0, pr->y0, 1, 1, pr->r0, pr->g0, pr->b0, alpha, z0);
221 		break;
222 	}
223 	// Flat Coloured Rectangle 8 pixel width & height
224 	// TILE_8: code:0x70 length:3
225 	case GPUCODE_TILE_8: {
226 		TILE_8 *pr = (TILE_8 *)p;
227 		if (len != GPUSIZE_TILE_8) {
228 			warning("Primitive %p length %d != TILE_8 length %d\n", prim, (uint32)len, GPUSIZE_TILE_8);
229 			return;
230 		}
231 		DrawTile(pr->x0, pr->y0, 8, 8, pr->r0, pr->g0, pr->b0, alpha, z0);
232 		break;
233 	}
234 	// Flat Coloured Rectangle 16 pixel width & height
235 	// TILE_16: code:0x78 length:3
236 	case GPUCODE_TILE_16: {
237 		TILE_16 *pr = (TILE_16 *)p;
238 		if (len != GPUSIZE_TILE_16) {
239 			warning("Primitive %p length %d != TILE_16 length %d\n", prim, (uint32)len, GPUSIZE_TILE_16);
240 			return;
241 		}
242 		DrawTile(pr->x0, pr->y0, 16, 16, pr->r0, pr->g0, pr->b0, alpha, z0);
243 		break;
244 	}
245 	// Flat Coloured single line
246 	// LineF2 = code: 0x40 length:4
247 	case GPUCODE_LINE_F2: {
248 		LINE_F2 *pr = (LINE_F2 *)p;
249 		if (len != GPUSIZE_LINE_F2) {
250 			warning("Primitive %p length %d != LineF2 length %d\n", prim, (uint32)len, GPUSIZE_LINE_F2);
251 			return;
252 		}
253 		/*
254 		         printf( "LineF2: (%d,%d) (%d,%d) RGB0:%d %d %d\n",
255 		                 pr->x0, pr->y0, pr->x1, pr->y1, pr->r0, pr->g0, pr->b0 );
256 		*/
257 		DrawLineF2(pr->x0, pr->y0, pr->x1, pr->y1, pr->r0, pr->g0, pr->b0, alpha, z0);
258 		break;
259 	}
260 	// Flat Coloured double line (not closed)
261 	// LineF3 = code: 0x48 length:6
262 	case GPUCODE_LINE_F3: {
263 		LINE_F3 *pr = (LINE_F3 *)p;
264 		if (len != GPUSIZE_LINE_F3) {
265 			warning("Primitive %p length %d != LineF3 length %d\n", prim, (uint32)len, GPUSIZE_LINE_F3);
266 			return;
267 		}
268 		/*
269 		         printf( "LineF3: (%d,%d) (%d,%d) (%d,%d) RGB0:%d %d %d\n",
270 		                 pr->x0, pr->y0, pr->x1, pr->y1, pr->x2, pr->y2,
271 		                 pr->r0, pr->g0, pr->b0 );
272 		*/
273 		DrawLineF3(pr->x0, pr->y0, pr->x1, pr->y1, pr->x2, pr->y2, pr->r0, pr->g0, pr->b0, alpha, z0);
274 		break;
275 	}
276 	// Flat Coloured triple line (not closed)
277 	// LineF4 = code: 0x4c length:7
278 	case GPUCODE_LINE_F4: {
279 		LINE_F4 *pr = (LINE_F4 *)p;
280 		if (len != GPUSIZE_LINE_F4) {
281 			warning("Primitive %p length %d != LineF4 length %d\n", prim, (uint32)len, GPUSIZE_LINE_F4);
282 			return;
283 		}
284 		/*
285 		         printf( "LineF4: (%d,%d) (%d,%d) (%d,%d) (%d %d) RGB0:%d %d %d\n",
286 		                 pr->x0, pr->y0, pr->x1, pr->y1,
287 		                 pr->x2, pr->y2, pr->x3, pr->y3,
288 		                 pr->r0, pr->g0, pr->b0 );
289 		*/
290 		DrawLineF4(pr->x0, pr->y0, pr->x1, pr->y1, pr->x2, pr->y2, pr->x3, pr->y3, pr->r0, pr->g0, pr->b0, alpha, z0);
291 		break;
292 	}
293 
294 	// Gouraud Coloured single line
295 	// LineG2 = code: 0x50 length:5
296 	case GPUCODE_LINE_G2: {
297 		LINE_G2 *pr = (LINE_G2 *)p;
298 		if (len != GPUSIZE_LINE_G2) {
299 			warning("Primitive %p length %d != LineG2 length %d\n", prim, (uint32)len, GPUSIZE_LINE_G2);
300 			return;
301 		}
302 		/*
303 		         printf( "LineG2: (%d,%d) (%d,%d) RGB0:%d %d %d RGB1:%d %d %d\n",
304 		                 pr->x0, pr->y0, pr->x1, pr->y1,
305 		                 pr->r0, pr->g0, pr->b0, pr->r1, pr->g1, pr->b1 );
306 		*/
307 		DrawLineG2(pr->x0, pr->y0, pr->x1, pr->y1, pr->r0, pr->g0, pr->b0, pr->r1, pr->g1, pr->b1, alpha, z0);
308 		break;
309 	}
310 	// Gouraud Coloured double line (not closed)
311 	// LineG3 = code: 0x58 length:8
312 	case GPUCODE_LINE_G3: {
313 		LINE_G3 *pr = (LINE_G3 *)p;
314 		if (len != GPUSIZE_LINE_G3) {
315 			warning("Primitive %p length %d != LineG3 length %d\n", prim, (uint32)len, GPUSIZE_LINE_G3);
316 			return;
317 		}
318 		/*
319 		         printf( "LineG3: (%d,%d) (%d,%d) (%d,%d) RGB0:%d %d %d RGB1:%d %d %d\n",
320 		                 pr->x0, pr->y0, pr->x1, pr->y1, pr->x2, pr->y2,
321 		                 pr->r0, pr->g0, pr->b0, pr->r1, pr->g1, pr->b1 );
322 		*/
323 		DrawLineG3(pr->x0, pr->y0, pr->x1, pr->y1, pr->x2, pr->y2, pr->r0, pr->g0, pr->b0, pr->r1, pr->g1, pr->b1, pr->r2, pr->g2, pr->b2, alpha, z0);
324 		break;
325 	}
326 	// Gouraud Coloured triple line (not closed)
327 	// LineG4 = code: 0x5c length:10
328 	case GPUCODE_LINE_G4: {
329 		LINE_G4 *pr = (LINE_G4 *)p;
330 		if (len != GPUSIZE_LINE_G4) {
331 			warning("Primitive %p length %d != LineG4 length %d\n", prim, (uint32)len, GPUSIZE_LINE_G4);
332 			return;
333 		}
334 		/*
335 		         printf( "LineG4: (%d,%d) (%d,%d) (%d,%d) (%d %d) \
336 		RGB0:%d %d %d RGB1:%d %d %d RGB2:%d %d %d RGB3:%d %d %d\n",
337 		                 pr->x0, pr->y0, pr->x1, pr->y1,
338 		                 pr->x2, pr->y2, pr->x3, pr->y3,
339 		                 pr->r0, pr->g0, pr->b0, pr->r1, pr->g1, pr->b1,
340 		                 pr->r2, pr->g2, pr->b2, pr->r3, pr->g3, pr->b3 );
341 		*/
342 		DrawLineG4(pr->x0, pr->y0, pr->x1, pr->y1, pr->x2, pr->y2, pr->x3, pr->y3, pr->r0, pr->g0, pr->b0, pr->r1, pr->g1, pr->b1, pr->r2, pr->g2, pr->b2, pr->r3, pr->g3,
343 		           pr->b3, alpha, z0);
344 		break;
345 	}
346 
347 	// Flat Coloured Non-textured triangle
348 	// PolyF3 = code:0x20 length:5
349 	case GPUCODE_POLY_F3: {
350 		POLY_F3 *pr = (POLY_F3 *)p;
351 		if (len != GPUSIZE_POLY_F3) {
352 			warning("Primitive %p length %d != PolyF3 length %d\n", prim, (uint32)len, GPUSIZE_POLY_F3);
353 			return;
354 		}
355 		/*
356 		         printf( "PolyF3: (%d,%d) (%d,%d) (%d,%d) RGB0:%d %d %d\n",
357 		                 pr->x0, pr->y0, pr->x1, pr->y1, pr->x2, pr->y2,
358 		                 pr->r0, pr->g0, pr->b0 );
359 		*/
360 		DrawFlatTriangle(pr->x0, pr->y0, pr->x1, pr->y1, pr->x2, pr->y2, pr->r0, pr->g0, pr->b0, alpha, z0);
361 		break;
362 	}
363 
364 	// Flat Coloured Non-textured quad
365 	// PolyF4 = code:0x28 length:6
366 	case GPUCODE_POLY_F4: {
367 		POLY_F4 *pr = (POLY_F4 *)p;
368 		if (len != GPUSIZE_POLY_F4) {
369 			warning("Primitive %p length %d != PolyF4 length %d\n", prim, (uint32)len, GPUSIZE_POLY_F4);
370 			return;
371 		}
372 		/*
373 		         printf( "PolyF4: (%d,%d) (%d,%d) (%d,%d) (%d %d) RGB0:%d %d %d\n",
374 		                 pr->x0, pr->y0, pr->x1, pr->y1,
375 		                 pr->x2, pr->y2, pr->x3, pr->y3,
376 		                 pr->r0, pr->g0, pr->b0 );
377 		*/
378 		DrawFlatQuad(pr->x0, pr->y0, pr->x1, pr->y1, pr->x2, pr->y2, pr->x3, pr->y3, pr->r0, pr->g0, pr->b0, alpha, z0);
379 		break;
380 	}
381 
382 	// Gouraud Coloured Non-textured triangle
383 	// PolyG3 = code:0x30 length:7
384 	case GPUCODE_POLY_G3: {
385 		POLY_G3 *pr = (POLY_G3 *)p;
386 		if (len != GPUSIZE_POLY_G3) {
387 			warning("Primitive %p length %d != PolyG3 length %d\n", prim, (uint32)len, GPUSIZE_POLY_G3);
388 			return;
389 		}
390 		/*
391 		         printf( "PolyG3: (%d,%d) (%d,%d) (%d,%d) \
392 		RGB0:%d %d %d RGB1:%d %d %d RGB2:%d %d %d\n",
393 		                 pr->x0, pr->y0, pr->x1, pr->y1, pr->x2, pr->y2,
394 		                 pr->r0, pr->g0, pr->b0, pr->r1, pr->g1, pr->b1,
395 		                 pr->r2, pr->g2, pr->b2 );
396 		*/
397 		DrawGouraudTriangle(pr->x0, pr->y0, pr->x1, pr->y1, pr->x2, pr->y2, pr->r0, pr->g0, pr->b0, pr->r1, pr->g1, pr->b1, pr->r2, pr->g2, pr->b2, alpha, z0);
398 		break;
399 	}
400 	// Gouraud Coloured Non-textured quad
401 	// PolyG4 = code:0x38 length:9
402 	case GPUCODE_POLY_G4: {
403 		POLY_G4 *pr = (POLY_G4 *)p;
404 		if (len != GPUSIZE_POLY_G4) {
405 			warning("Primitive %p length %d != PolyG4 length %d\n", prim, (uint32)len, GPUSIZE_POLY_G4);
406 			return;
407 		}
408 		/*
409 		         printf( "PolyG4: (%d,%d) (%d,%d) (%d,%d) (%d %d) \
410 		RGB0:%d %d %d RGB1:%d %d %d RGB2:%d %d %d RGB3:%d %d %d\n",
411 		                 pr->x0, pr->y0, pr->x1, pr->y1,
412 		                 pr->x2, pr->y2, pr->x3, pr->y3,
413 		                 pr->r0, pr->g0, pr->b0, pr->r1, pr->g1, pr->b1,
414 		                 pr->r2, pr->g2, pr->b2, pr->r3, pr->g3, pr->b3 );
415 		*/
416 		DrawGouraudQuad(pr->x0, pr->y0, pr->x1, pr->y1, pr->x2, pr->y2, pr->x3, pr->y3, pr->r0, pr->g0, pr->b0, pr->r1, pr->g1, pr->b1, pr->r2, pr->g2, pr->b2, pr->r3,
417 		                pr->g3, pr->b3, alpha, z0);
418 		break;
419 	}
420 	// Flat Coloured Textured triangle
421 	// PolyFT3 = code:0x24 length:8
422 	case GPUCODE_POLY_FT3: {
423 		POLY_FT3 *pr = (POLY_FT3 *)p;
424 		if (len != GPUSIZE_POLY_FT3) {
425 			warning("Primitive %p length %d != PolyFT3 length %d\n", prim, (uint32)len, GPUSIZE_POLY_FT3);
426 			return;
427 		}
428 		/*
429 		         printf( "PolyFT3: (%d,%d) (%d,%d) (%d,%d)\n(%d,%d) (%d,%d) (%d,%d)\nRGB0:%d %d %d\n",
430 		                 pr->x0, pr->y0, pr->x1, pr->y1, pr->x2, pr->y2,
431 		                 pr->u0, pr->v0, pr->u1, pr->v1, pr->u2, pr->v2,
432 		                 pr->r0, pr->g0, pr->b0 );
433 		*/
434 		DrawFlatTriangleTextured(pr->x0, pr->y0, pr->x1, pr->y1, pr->x2, pr->y2, pr->r0, pr->g0, pr->b0, pr->u0, pr->v0, pr->u1, pr->v1, pr->u2, pr->v2, alpha, z0, usr);
435 		break;
436 	}
437 	// Flat Coloured Textured quad
438 	// PolyFT4 = code:0x2c length:10
439 	case GPUCODE_POLY_FT4: {
440 		POLY_FT4 *pr = (POLY_FT4 *)p;
441 		if (len != GPUSIZE_POLY_FT4) {
442 			warning("Primitive %p length %d != PolyFT4 length %d\n", prim, (uint32)len, GPUSIZE_POLY_FT4);
443 			return;
444 		}
445 		/*
446 		         printf( "PolyFT4: (%d,%d) (%d,%d) (%d,%d) (%d,%d)\n(%d,%d) (%d,%d) (%d,%d) (%d,%d)\nRGB0:%d %d %d\n",
447 		                 pr->x0, pr->y0, pr->x1, pr->y1,
448 		                 pr->x2, pr->y2, pr->x3, pr->y3,
449 		                 pr->u0, pr->v0, pr->u1, pr->v1,
450 		                 pr->u2, pr->u2, pr->u3, pr->u3,
451 		                 pr->r0, pr->g0, pr->b0 );
452 		*/
453 
454 		DrawFlatQuadTextured(pr->x0, pr->y0, pr->x1, pr->y1, pr->x2, pr->y2, pr->x3, pr->y3, pr->r0, pr->g0, pr->b0, pr->u0, pr->v0, pr->u1, pr->v1, pr->u2, pr->v2, pr->u3,
455 		                     pr->v3, alpha, z0, usr);
456 		break;
457 	}
458 	// Gouraud Coloured Textured triangle
459 	// PolyGT3 = code:0x34 length:10
460 	case GPUCODE_POLY_GT3: {
461 		POLY_GT3 *pr = (POLY_GT3 *)p;
462 		if (len != GPUSIZE_POLY_GT3) {
463 			warning("Primitive %p length %d != PolyGT3 length %d\n", prim, (uint32)len, GPUSIZE_POLY_GT3);
464 			return;
465 		}
466 		/*
467 		         printf( "PolyGT3: (%d,%d) (%d,%d) (%d,%d)\n(%d,%d) (%d,%d) (%d,%d)\nRGB0:%d %d %d RGB1:%d %d %d RGB2:%d %d %d\n",
468 		                 pr->x0, pr->y0, pr->x1, pr->y1, pr->x2, pr->y2,
469 		                 pr->u0, pr->v0, pr->u1, pr->v1, pr->u2, pr->v2,
470 		                 pr->r0, pr->g0, pr->b0, pr->r1, pr->g1, pr->b1,
471 		                 pr->r2, pr->g2, pr->b2 );
472 		*/
473 
474 		DrawGouraudTriangleTextured(pr->x0, pr->y0, pr->x1, pr->y1, pr->x2, pr->y2, pr->r0, pr->g0, pr->b0, pr->r1, pr->g1, pr->b1, pr->r2, pr->g2, pr->b2, pr->u0, pr->v0,
475 		                            pr->u1, pr->v1, pr->u2, pr->v2, alpha, z0, usr);
476 		break;
477 	}
478 	// Gouraud Coloured Textured quad
479 	// PolyGT4 = code:0x3c length:13
480 	case GPUCODE_POLY_GT4: {
481 		POLY_GT4 *pr = (POLY_GT4 *)p;
482 		if (len != GPUSIZE_POLY_GT4) {
483 			warning("Primitive %p length %d != PolyGT4 length %d\n", prim, (uint32)len, GPUSIZE_POLY_GT4);
484 			return;
485 		}
486 		/*
487 		         printf( "PolyGT4: (%d,%d) (%d,%d) (%d,%d) (%d,%d)\n(%d,%d) (%d,%d) (%d,%d) (%d,%d)\nRGB0:%d %d %d RGB1:%d %d %d RGB2:%d %d $d RGB3:%d %d %d\n",
488 		                 pr->x0, pr->y0, pr->x1, pr->y1,
489 		                 pr->x2, pr->y2, pr->x3, pr->y3,
490 		                 pr->u0, pr->v0, pr->u1, pr->v1,
491 		                 pr->u2, pr->u2, pr->u3, pr->u3,
492 		                 pr->r0, pr->g0, pr->b0,
493 		                 pr->r1, pr->g1, pr->b1,
494 		                 pr->r2, pr->g2, pr->b2,
495 		                 pr->r3, pr->g3, pr->b3 );
496 		*/
497 		DrawGouraudQuadTextured(pr->x0, pr->y0, pr->x1, pr->y1, pr->x2, pr->y2, pr->x3, pr->y3, pr->r0, pr->g0, pr->b0, pr->r1, pr->g1, pr->b1, pr->r2, pr->g2, pr->b2,
498 		                        pr->r3, pr->g3, pr->b3, pr->u0, pr->v0, pr->u1, pr->v1, pr->u2, pr->v2, pr->u3, pr->v3, alpha, z0, usr);
499 		break;
500 	}
501 	// Flat Coloured Textured Tile
502 	// SPRT = code:0x64 length:5
503 	case GPUCODE_SPRT: {
504 		SPRT *pr = (SPRT *)p;
505 		if (len != GPUSIZE_SPRT) {
506 			warning("Primitive %p length %d != SPRT length %d\n", prim, (uint32)len, GPUSIZE_SPRT);
507 			return;
508 		}
509 		DrawSprite(pr->x0, pr->y0, pr->w, pr->h, pr->r0, pr->g0, pr->b0, pr->u0, pr->v0, alpha, z0, usr);
510 		break;
511 	}
512 	// Flat Coloured Textured Tile 8 pixels x 8 pixels
513 	// SPRT_8 = code:0x74 length:4
514 	case GPUCODE_SPRT_8: {
515 		SPRT_8 *pr = (SPRT_8 *)p;
516 		if (len != GPUSIZE_SPRT_8) {
517 			warning("Primitive %p length %d != SPRT_8 length %d\n", prim, (uint32)len, GPUSIZE_SPRT_8);
518 			return;
519 		}
520 		DrawSprite(pr->x0, pr->y0, 8, 8, pr->r0, pr->g0, pr->b0, pr->u0, pr->v0, alpha, z0, usr);
521 		break;
522 	}
523 	// Flat Coloured Textured Tile 16 pixels x 16 pixels
524 	// SPRT_16 = code:0x7c length:4
525 	case GPUCODE_SPRT_16: {
526 		SPRT_16 *pr = (SPRT_16 *)p;
527 		if (len != GPUSIZE_SPRT_16) {
528 			warning("Primitive %p length %d != SPRT_16 length %d\n", prim, (uint32)len, GPUSIZE_SPRT_16);
529 			return;
530 		}
531 		DrawSprite(pr->x0, pr->y0, 16, 16, pr->r0, pr->g0, pr->b0, pr->u0, pr->v0, alpha, z0, usr);
532 		break;
533 	}
534 	default: {
535 		warning("Unknown Primitive\n");
536 		break;
537 	}
538 	}
539 }
540 
541 } // End of namespace ICB
542