1 #include "toaplan.h"
2
3 INT32 ToaOpaquePriority;
4
5 static UINT8* pTile;
6 static UINT32* pTileData;
7 static UINT32* pTilePalette;
8
9 INT32 Rallybik = 0;
10 INT32 Hellfire = 0;
11
12 typedef void (*RenderTileFunction)();
13 static RenderTileFunction* RenderTile;
14
15 static INT32 nTileXPos, nTileYPos;
16
17 // Include the tile rendering functions
18 #include "toa_gp9001_func.h"
19
20 static INT32 nLastBPP = 0;
21
22 struct ToaTile {
23 UINT32 nTileAttrib;
24 INT16 nTileXPos;
25 INT16 nTileYPos;
26 };
27
28 extern UINT32* ToaPalette2;
29
30 // ----------------------------------------------------------------------------
31 // Rally Bike custom sprite function
32
rallybik_draw_sprites(INT32 priority)33 static void rallybik_draw_sprites(INT32 priority)
34 {
35 UINT16 *sprite = (UINT16*)FCU2RAM;
36
37 for (INT32 offs = 0; offs < (0x1000/2); offs += 4)
38 {
39 INT32 attrib = sprite[offs + 1];
40
41 if ((attrib & 0x0c00) == priority)
42 {
43 INT32 sy = (sprite[offs + 3] >> 7) & 0x1ff;
44
45 if (sy != 0x0100)
46 {
47 INT32 code = sprite[offs] & 0x7ff;
48 INT32 color = attrib & 0x3f;
49 INT32 sx = (sprite[offs + 2] >> 7) & 0x1ff;
50 INT32 flipx = attrib & 0x100;
51 INT32 flipy = attrib & 0x200;
52 if (flipx) sx -= 15;
53
54 sx -= 31;
55 sy -= 16;
56
57 if (sy < -15 || sx < -15 || sy >= 240 || sx >= 320) continue;
58
59 {
60 INT32 flip = 0;
61 if (flipx) flip |= 0x0f;
62 if (flipy) flip |= 0xf0;
63 UINT8 *gfx = FCU2ROM + (code * 0x100);
64
65 pTilePalette = &ToaPalette2[color << 4];
66
67 for (INT32 y = 0; y < 16; y++, sy++) {
68 if (sy < 0 || sy >= 240) continue;
69
70 for (INT32 x = 0; x < 16; x++, sx++) {
71 if (sx < 0 || sx >= 320) continue;
72
73 INT32 pxl = gfx[((y * 16) + x) ^ flip];
74
75 if (pxl) {
76 PutPix(pBurnDraw + ((sy * 320) + sx) * nBurnBpp, pTilePalette[pxl]);
77 }
78 }
79 sx -= 16;
80 }
81 }
82 }
83 }
84 }
85 }
86
87
88 // ----------------------------------------------------------------------------
89 // FCU-2 functions
90
91 UINT8* FCU2ROM;
92 UINT32 nFCU2ROMSize;
93 static UINT8* FCU2TileAttrib;
94
95 static UINT32 nFCU2MaxSprite;
96
97 UINT8* FCU2RAM;
98 UINT8* FCU2RAMSize;
99 UINT32 FCU2Pointer;
100
101 static UINT8* pFCU2SpriteBuffer;
102
103 static UINT16** pFCU2SpriteQueue[16];
104 static UINT16** pFCU2SpriteQueueData = NULL;
105
106 INT32 nFCU2SpriteXOffset = 0, nFCU2SpriteYOffset = 0;
107
FCU2PrepareSprites()108 static void FCU2PrepareSprites()
109 {
110 UINT16* pSpriteInfo;
111 INT32 nSprite;
112
113 for (INT32 nPriority = 0; nPriority < 16; nPriority++) {
114 pFCU2SpriteQueue[nPriority] = &pFCU2SpriteQueueData[(nPriority << 8) + nPriority];
115 }
116
117 for (nSprite = 0, pSpriteInfo = (UINT16*)pFCU2SpriteBuffer; nSprite < 0x0100; nSprite++, pSpriteInfo += 4) {
118 if (!(pSpriteInfo[0] & 0x8000)) { // Sprite is enabled
119 *pFCU2SpriteQueue[pSpriteInfo[1] >> 12]++ = pSpriteInfo;
120 }
121 }
122 }
123
FCU2RenderSpriteQueue(INT32 nPriority)124 static void FCU2RenderSpriteQueue(INT32 nPriority)
125 {
126 UINT16* pSpriteInfo;
127 UINT8* pSpriteData;
128 INT32 nSpriteXPos, nSpriteYPos;
129 INT32 nSpriteXSize, nSpriteYSize;
130 UINT32 nSpriteNumber;
131 INT32 x, y, s;
132
133 *pFCU2SpriteQueue[nPriority] = NULL;
134 pFCU2SpriteQueue[nPriority] = &pFCU2SpriteQueueData[(nPriority << 8) + nPriority];
135
136 while ((pSpriteInfo = *pFCU2SpriteQueue[nPriority]++) != NULL) {
137
138 pTilePalette = &ToaPalette2[(pSpriteInfo[1] & 0x3F) << 4];
139 nSpriteNumber = pSpriteInfo[0] & nFCU2MaxSprite;
140
141 pSpriteData = FCU2ROM + (nSpriteNumber << 5);
142
143 s = (pSpriteInfo[1] & 0x0FC0) >> 6;
144
145 nSpriteXSize = ((((UINT16*)FCU2RAMSize)[s] >> 0) & 0x0F);
146 nSpriteYSize = ((((UINT16*)FCU2RAMSize)[s] >> 4) & 0x0F);
147
148 nSpriteXPos = (pSpriteInfo[2] >> 7) + nFCU2SpriteXOffset;
149 nSpriteXPos &= 0x01FF;
150 nSpriteYPos = (pSpriteInfo[3] >> 7) + nFCU2SpriteYOffset;
151 nSpriteYPos &= 0x01FF;
152
153 if (Hellfire) nSpriteYPos -= 16;
154
155 if (nSpriteXPos > 384) {
156 nSpriteXPos -= 0x0200;
157 }
158 if (nSpriteYPos > 384) {
159 nSpriteYPos -= 0x0200;
160 }
161
162 // if (nSpriteNumber) {
163 // printf("Sprite\t0x%04X\n", nSpriteNumber);
164 // printf("xp: %4i, yp: %4i\n", nSpriteXPos, nSpriteYPos);
165 // printf("xs: %4i, ys: %4i\n", nSpriteXSize, nSpriteYSize);
166 // }
167
168 for (y = 0, nTileYPos = nSpriteYPos; y < nSpriteYSize; y++, nTileYPos += 8) {
169 for (x = 0, nTileXPos = nSpriteXPos; x < nSpriteXSize; x++, nTileXPos += 8, nSpriteNumber++, pSpriteData += 32) {
170 if (nSpriteNumber > nFCU2MaxSprite) {
171 break;
172 }
173 if (FCU2TileAttrib[nSpriteNumber]) {
174 // Skip tile if it's completely off the screen
175 if (!(nTileXPos <= -8 || nTileXPos >= 320 || nTileYPos <= -8 || nTileYPos >= 240)) {
176 pTileData = (UINT32*)pSpriteData;
177 pTile = pBurnBitmap + (nTileXPos * nBurnColumn) + (nTileYPos * nBurnRow);
178 if (nTileXPos < 0 || nTileXPos > 312 || nTileYPos < 0 || nTileYPos > 232) {
179 RenderTile[1]();
180 } else {
181 RenderTile[0]();
182 }
183 }
184 }
185 }
186 }
187 }
188 }
189
190 // ----------------------------------------------------------------------------
191 // BCU-2 functions
192
193 UINT8* BCU2ROM;
194 UINT32 nBCU2ROMSize;
195 static UINT8* BCU2TileAttrib;
196
197 static UINT32 nBCU2MaxTile;
198
199 UINT8* BCU2RAM;
200
201 UINT16 BCU2Reg[8];
202
203 UINT32 BCU2Pointer;
204
205 static ToaTile* pBCU2TileQueue[16];
206 static ToaTile* pBCU2TileQueueData = NULL;
207
208 INT32 nBCU2TileXOffset = 0, nBCU2TileYOffset = 0;
209
BCU2QueueLayer(UINT16 * pTilemap,INT32 nXPos,INT32 nYPos)210 static void BCU2QueueLayer(UINT16* pTilemap, INT32 nXPos, INT32 nYPos)
211 {
212 if (Hellfire) nYPos += 16;
213
214 INT32 x, y;
215 INT32 nTileRow, nTileColumn;
216 UINT32 nTileNumber, nTileAttrib;
217
218 for (y = 0; y < 31; y++) {
219
220 nTileRow = (((nYPos >> 3) + y) << 7) & 0x1F80;
221
222 for (x = 0; x < 41; x++) {
223 nTileColumn = (((nXPos >> 3) + x) << 1) & 0x7E;
224 nTileNumber = pTilemap[nTileRow + nTileColumn + 1];
225 nTileAttrib = pTilemap[nTileRow + nTileColumn];
226
227 // Rallybik uses hidden tiles to do the background fades on the titlescreen.
228 if ((!(nTileNumber & 0x8000) && (nTileAttrib & 0xF000)) || Rallybik) {
229 pBCU2TileQueue[nTileAttrib >> 12]->nTileAttrib = (nTileAttrib << 16) | nTileNumber;
230 pBCU2TileQueue[nTileAttrib >> 12]->nTileXPos = (x << 3) - (nXPos & 7);
231 pBCU2TileQueue[nTileAttrib >> 12]->nTileYPos = (y << 3) - (nYPos & 7);
232 pBCU2TileQueue[nTileAttrib >> 12]++;
233 }
234 }
235 }
236 }
237
BCU2PrepareTiles()238 static void BCU2PrepareTiles()
239 {
240 for (INT32 nPriority = 0; nPriority < 16; nPriority++) {
241 pBCU2TileQueue[nPriority] = &pBCU2TileQueueData[nPriority * 1280 * 4];
242 }
243
244 BCU2QueueLayer((UINT16*)(BCU2RAM + 0xC000), (BCU2Reg[6] >> 7) - nBCU2TileXOffset + nLayer3XOffset, (BCU2Reg[7] >> 7) - nBCU2TileYOffset + nLayer3YOffset);
245 BCU2QueueLayer((UINT16*)(BCU2RAM + 0x8000), (BCU2Reg[4] >> 7) - nBCU2TileXOffset + nLayer2XOffset, (BCU2Reg[5] >> 7) - nBCU2TileYOffset + nLayer2YOffset);
246 BCU2QueueLayer((UINT16*)(BCU2RAM + 0x4000), (BCU2Reg[2] >> 7) - nBCU2TileXOffset + nLayer1XOffset, (BCU2Reg[3] >> 7) - nBCU2TileYOffset + nLayer1YOffset);
247 BCU2QueueLayer((UINT16*)(BCU2RAM + 0x0000), (BCU2Reg[0] >> 7) - nBCU2TileXOffset + nLayer0XOffset, (BCU2Reg[1] >> 7) - nBCU2TileYOffset + nLayer0YOffset);
248 }
249
BCU2RenderTileQueue(INT32 nPriority)250 static void BCU2RenderTileQueue(INT32 nPriority)
251 {
252 UINT32 nTileNumber, nTileAttrib;
253 UINT8* pTileStart;
254 UINT8 nOpacity;
255
256 pBCU2TileQueue[nPriority]->nTileAttrib = 0;
257 pBCU2TileQueue[nPriority] = &pBCU2TileQueueData[nPriority * 1280 * 4];
258
259 while ((nTileAttrib = pBCU2TileQueue[nPriority]->nTileAttrib) != 0) {
260 nTileXPos = pBCU2TileQueue[nPriority]->nTileXPos;
261 nTileYPos = pBCU2TileQueue[nPriority]->nTileYPos;
262 pBCU2TileQueue[nPriority]++;
263
264 nTileNumber = nTileAttrib & nBCU2MaxTile;
265
266 pTileStart = BCU2ROM + (nTileNumber << 5);
267 pTilePalette = &ToaPalette[(nTileAttrib >> 12) & 0x03F0];
268
269 pTile = pBurnBitmap + (nTileXPos * nBurnColumn) + (nTileYPos * nBurnRow);
270
271 if ((nOpacity = BCU2TileAttrib[nTileNumber]) != 0 || nPriority < ToaOpaquePriority) {
272 if (nPriority < ToaOpaquePriority) nOpacity = 9;
273
274 pTileData = (UINT32*)pTileStart;
275 if (nTileXPos >= 0 && nTileXPos < 312 && nTileYPos >= 0 && nTileYPos < 232) {
276 RenderTile[nOpacity - 1]();
277 } else {
278 if (nTileXPos > -8 && nTileXPos < 320 && nTileYPos > -8 && nTileYPos < 240) {
279 RenderTile[nOpacity]();
280 }
281 }
282 }
283 }
284 }
285
ToaBufferFCU2Sprites()286 void ToaBufferFCU2Sprites()
287 {
288 memcpy(pFCU2SpriteBuffer, FCU2RAM, 0x0800);
289 }
290
ToaRenderBCU2()291 INT32 ToaRenderBCU2()
292 {
293 if (nLastBPP != nBurnBpp ) {
294 nLastBPP = nBurnBpp;
295
296 #ifdef DRIVER_ROTATION
297 if (bRotatedScreen) {
298 RenderTile = RenderTile_ROT270[nBurnBpp - 2];
299 } else {
300 RenderTile = RenderTile_ROT0[nBurnBpp - 2];
301 }
302 #else
303 RenderTile = RenderTile_ROT0[nBurnBpp - 2];
304 #endif
305 }
306
307 BCU2PrepareTiles();
308 if (!Rallybik) {
309 FCU2PrepareSprites();
310 }
311
312 for (INT32 nPriority = 0; nPriority < 16; nPriority++) {
313 if (Rallybik) {
314 rallybik_draw_sprites(nPriority << 8);
315 } else {
316 FCU2RenderSpriteQueue(nPriority);
317 }
318 BCU2RenderTileQueue(nPriority);
319 }
320
321 return 0;
322 }
323
ToaInitBCU2()324 INT32 ToaInitBCU2()
325 {
326 INT32 nSize;
327
328 nLastBPP = 0;
329
330 nBCU2MaxTile = (nBCU2ROMSize - 1) >> 5;
331
332 nSize = 1280 * 4 * 0x10 * sizeof(ToaTile);
333 pBCU2TileQueueData = (ToaTile*)BurnMalloc(nSize);
334 memset(pBCU2TileQueueData, 0, nSize);
335
336 BCU2TileAttrib = (UINT8*)BurnMalloc(32768);
337 memset(BCU2TileAttrib, 0, 32768);
338 for (UINT32 j = 0; j < (nBCU2ROMSize >> 5); j++) {
339 bool bTransparent = true, bSolid = true;
340 INT32 nTwoPixels;
341 for (UINT32 k = (j << 5); k < ((j << 5) + 32); k++) {
342 if ((nTwoPixels = BCU2ROM[k]) != 0) {
343 bTransparent = false;
344 }
345 if ((nTwoPixels & 0xF0) == 0 || (nTwoPixels & 0x0F) == 0) {
346 bSolid = false;
347 }
348 }
349 if (bTransparent) {
350 BCU2TileAttrib[j] = 0;
351 } else {
352 if (bSolid) {
353 BCU2TileAttrib[j] = 9;
354 } else {
355 BCU2TileAttrib[j] = 1;
356 }
357 }
358 }
359
360 nFCU2MaxSprite = (nFCU2ROMSize - 1) >> 5;
361
362 nSize = 0x10 * 0x101 * sizeof(UINT16*);
363 pFCU2SpriteQueueData = (UINT16**)BurnMalloc(nSize);
364 memset(pFCU2SpriteQueueData, 0, nSize);
365
366 pFCU2SpriteBuffer = (UINT8*)BurnMalloc(0x0800);
367
368 FCU2TileAttrib = (UINT8*)BurnMalloc(32768);
369 memset(FCU2TileAttrib, 0, 32768);
370 for (UINT32 j = 0; j < (nFCU2ROMSize >> 5); j++) {
371 bool bTransparent = true, bSolid = true;
372 INT32 nTwoPixels;
373 for (UINT32 k = (j << 5); k < ((j << 5) + 32); k++) {
374 if ((nTwoPixels = FCU2ROM[k]) != 0) {
375 bTransparent = false;
376 }
377 if ((nTwoPixels & 0xF0) == 0 || (nTwoPixels & 0x0F) == 0) {
378 bSolid = false;
379 }
380 }
381 if (bTransparent) {
382 FCU2TileAttrib[j] = 0;
383 } else {
384 if (bSolid) {
385 FCU2TileAttrib[j] = 9;
386 } else {
387 FCU2TileAttrib[j] = 1;
388 }
389 }
390 }
391
392 if (!nLayer0XOffset) {
393 nLayer0XOffset = 0x01EF + 6;
394 }
395 if (!nLayer1XOffset) {
396 nLayer1XOffset = 0x01EF + 4;
397 }
398 if (!nLayer2XOffset) {
399 nLayer2XOffset = 0x01EF + 2;
400 }
401 if (!nLayer3XOffset) {
402 nLayer3XOffset = 0x01EF + 0;
403 }
404
405 if (!nLayer0YOffset) {
406 nLayer0YOffset = 0x0101;
407 }
408 if (!nLayer1YOffset) {
409 nLayer1YOffset = 0x0101;
410 }
411 if (!nLayer2YOffset) {
412 nLayer2YOffset = 0x0101;
413 }
414 if (!nLayer3YOffset) {
415 nLayer3YOffset = 0x0101;
416 }
417
418 ToaOpaquePriority = 0;
419
420 return 0;
421 }
422
ToaExitBCU2()423 INT32 ToaExitBCU2()
424 {
425 nLayer0XOffset = 0;
426 nLayer1XOffset = 0;
427 nLayer2XOffset = 0;
428 nLayer3XOffset = 0;
429 nLayer0YOffset = 0;
430 nLayer1YOffset = 0;
431 nLayer2YOffset = 0;
432 nLayer3YOffset = 0;
433
434 nFCU2SpriteXOffset = 0;
435 nFCU2SpriteYOffset = 0;
436
437 BurnFree(pBCU2TileQueueData);
438 BurnFree(BCU2TileAttrib);
439 BurnFree(pFCU2SpriteQueueData);
440 BurnFree(pFCU2SpriteBuffer);
441 BurnFree(FCU2TileAttrib);
442
443 return 0;
444 }
445
ToaScanBCU2(INT32 nAction,INT32 * pnMin)446 INT32 ToaScanBCU2(INT32 nAction, INT32* pnMin)
447 {
448 if (nAction & ACB_VOLATILE) { // Scan volatile data
449 if (pnMin) {
450 *pnMin = 0x029496;
451 }
452
453 SCAN_VAR(BCU2Pointer);
454 SCAN_VAR(FCU2Pointer);
455 SCAN_VAR(BCU2Reg);
456 SCAN_VAR(ToaOpaquePriority);
457 SCAN_VAR(nLayer0XOffset);
458 SCAN_VAR(nLayer1XOffset);
459 SCAN_VAR(nLayer2XOffset);
460 SCAN_VAR(nLayer3XOffset);
461 SCAN_VAR(nLayer0YOffset);
462 SCAN_VAR(nLayer1YOffset);
463 SCAN_VAR(nLayer2YOffset);
464 SCAN_VAR(nLayer3YOffset);
465 SCAN_VAR(nBCU2TileXOffset);
466 SCAN_VAR(nBCU2TileYOffset);
467 SCAN_VAR(nSpriteXOffset);
468 SCAN_VAR(nSpriteYOffset);
469 SCAN_VAR(nSpritePriority);
470 }
471
472 return 0;
473 }
474