1 // Cave hardware sprites
2 #include "cave.h"
3 
4 INT32 CaveSpriteVisibleXOffset;
5 
6 UINT8* CaveSpriteROM = NULL;
7 UINT8* CaveSpriteRAM = NULL;
8 
9 INT32 nCaveSpriteBank;
10 INT32 nCaveSpriteBankDelay;
11 
12 static INT32 nSpriteAddressMask;
13 
14 struct CaveSprite {
15 	INT8 flip;
16 	INT8 priority;
17 	INT16 palette;
18 	INT32 x; INT32 y;
19 	INT32 xsize; INT32 ysize;
20 	INT32 xzoom; INT32 yzoom;
21 	INT32 address;
22 };
23 
24 static CaveSprite* pSpriteList = NULL;
25 
26 INT32 (*CaveSpriteBuffer)();
27 
28 static UINT8* pRow;
29 static UINT8* pPixel;
30 static UINT32* pSpriteData;
31 static UINT32* pSpritePalette;
32 
33 static UINT16* pZBuffer = NULL;
34 static UINT16* pZRow;
35 static UINT16* pZPixel;
36 
37 static INT32 nSpriteRow, nSpriteRowSize;
38 static INT32 nXPos, nYPos, nZPos;
39 static INT32 nXSize, nYSize;
40 static INT32 nSpriteXZoomSize, nSpriteYZoomSize;
41 static INT32 nSpriteXOffset, nSpriteYOffset;
42 
43 static INT32 nFirstSprite[4], nLastSprite[4];
44 
45 static INT32 nTopSprite;
46 static INT32 nZOffset;
47 
48 typedef void (*RenderSpriteFunction)();
49 static RenderSpriteFunction* RenderSprite;
50 
51 // Include the sprite rendering functions
52 #include "cave_sprite_func.h"
53 
CaveSpriteRender(INT32 nLowPriority,INT32 nHighPriority)54 INT32 CaveSpriteRender(INT32 nLowPriority, INT32 nHighPriority)
55 {
56 	static INT32 nMaskLeft, nMaskRight, nMaskTop, nMaskBottom;
57 	CaveSprite* pBuffer;
58 
59 	INT32 nPriorityMask = 0;
60 	INT32 nMaxZPos = -1;
61 	INT32 nCurrentZPos = 0x00010000;
62 	INT32 nUseBuffer = 0x00010000;
63 	INT32 nFunction;
64 
65 	if (nLowPriority == 0) {
66 		nZPos = -1;
67 		nTopSprite = -1;
68 
69 		nMaskLeft = nMaskTop = 9999;
70 		nMaskRight = nMaskBottom = -1;
71 	}
72 
73 	if ((nBurnLayer & 1) == 0) {
74 		return 0;
75 	}
76 
77 	if (nHighPriority < 3) {
78 		for (INT32 i = nHighPriority + 1; i < 4; i++) {
79 			if (nUseBuffer > nFirstSprite[i]) {
80 				nUseBuffer = nFirstSprite[i];
81 			}
82 		}
83 	}
84 
85 	for (INT32 i = nLowPriority; i <= nHighPriority; i++) {
86 		if (nCurrentZPos > nFirstSprite[i]) {
87 			nCurrentZPos = nFirstSprite[i];
88 		}
89 		if (nMaxZPos < nLastSprite[i]) {
90 			nMaxZPos = nLastSprite[i];
91 		}
92 		nPriorityMask |= 8 >> i;
93 	}
94 
95 	nPriorityMask &= nSpriteEnable;
96 	if (nPriorityMask == 0) {
97 		return 0;
98 	}
99 
100 	for (pBuffer = pSpriteList + nCurrentZPos; nCurrentZPos <= nMaxZPos; pBuffer++, nCurrentZPos++) {
101 
102 		if ((pBuffer->priority & nPriorityMask) == 0) {
103 			continue;
104 		}
105 
106 		nXPos = pBuffer->x;
107 		nYPos = pBuffer->y;
108 
109 		pSpriteData = (UINT32*)(CaveSpriteROM + ((pBuffer->address << 8) & nSpriteAddressMask));
110 		pSpritePalette = CavePalette + pBuffer->palette;
111 
112 		nXSize = pBuffer->xsize;
113 		nYSize = pBuffer->ysize;
114 
115 		if (pBuffer->xzoom == 0x0100 && pBuffer->yzoom == 0x0100) {					// This sprite doesn't use zooming
116 
117 			nSpriteRowSize = pBuffer->xsize >> 2;
118 
119 			if (pBuffer->flip & 1) {												// Y Flip
120 				pSpriteData += nSpriteRowSize * (nYSize - 1);
121 				nSpriteRowSize = -nSpriteRowSize;
122 			}
123 
124 			if (nYPos >= 0x0200) {
125 				nYPos -= 0x0400;
126 			}
127 
128 			if (nYPos < 0) {
129 				pSpriteData += nSpriteRowSize * -nYPos;
130 				nYSize += nYPos;
131 				nYPos = 0;
132 			}
133 
134 			if ((nYPos + nYSize) > nCaveYSize) {
135 				nYSize -= (nYPos + nYSize) - nCaveYSize;
136 			}
137 
138 			if (nXPos >= 0x0200) {
139 				nXPos -= 0x0400;
140 			}
141 
142 			if (nXPos < 0) {
143 				if ((pBuffer->flip & 2) == 0) {
144 					pSpriteData += (-nXPos >> 4) << 2;
145 				}
146 				nXSize -= -nXPos & 0xFFF0;
147 				nXPos += -nXPos & 0xFFF0;
148 			}
149 
150 			if (nXPos + nXSize >= nCaveXSize) {
151 				if (pBuffer->flip & 2) {
152 					pSpriteData += ((nXPos + nXSize - nCaveXSize) >> 4) << 2;
153 				}
154 				nXSize -= (nXPos + nXSize - nCaveXSize) & 0xFFF0;
155 			}
156 
157 			pRow = pBurnDraw + (nYPos * nBurnPitch) + (nXPos * nBurnBpp);
158 
159 			nFunction = (pBuffer->flip & 2) << 1;									// X Flip
160 
161 			if (nTopSprite > nCurrentZPos) {										// Test ZBuffer
162 				if (nXPos < nMaskRight && (nXPos + nXSize) >= nMaskLeft && nYPos < nMaskBottom && (nYPos + nYSize) >= nMaskTop) {
163 					nFunction |= 1;
164 				}
165 			}
166 
167 			if (nUseBuffer < nCurrentZPos) {										// Write ZBuffer
168 				nFunction |= 2;
169 
170 				if (nXPos < nMaskLeft) {
171 					nMaskLeft = nXPos;
172 				}
173 				if ((nXPos + nXSize) > nMaskRight) {
174 					nMaskRight = nXPos + nXSize;
175 				}
176 				if (nYPos < nMaskTop) {
177 					nMaskTop = nYPos;
178 				}
179 				if ((nYPos + nYSize) > nMaskBottom) {
180 					nMaskBottom = nYPos + nYSize;
181 				}
182 			}
183 
184 			if (nFunction & 3) {
185 				pZRow = pZBuffer + (nYPos * 320) + nXPos;
186 				nZPos = nCurrentZPos + nZOffset;
187 			}
188 
189 			nXSize = nXSize >> 2;
190 
191 			RenderSprite[nFunction]();
192 		} else {																	// This sprite uses zooming
193 			nSpriteXZoomSize = 0x01000000;											// * zoom factor = size of each screen pixel
194 
195 			nXSize *= pBuffer->xzoom;
196 			nXSize >>= 8;															// Round to multiple of whole pixel
197 			if (nXSize < 1) {														// Make sure the sprite is at least one pixel wide
198 				nXSize = 1;
199 			} else {
200 				nSpriteXZoomSize /= pBuffer->xzoom;
201 			}
202 			if (nSpriteXZoomSize > (pBuffer->xsize << 16)) {
203 				nSpriteXZoomSize = pBuffer->xsize << 16;
204 			}
205 			nSpriteXOffset = nSpriteXZoomSize >> 1;									// Make certain the pixels displayed are centered
206 
207 			if (pBuffer->flip & 2) {												// X Flip
208 				nXPos += pBuffer->xsize - nXSize;
209 
210 				nSpriteXOffset = (pBuffer->xsize << 16) - nSpriteXOffset;
211 				nSpriteXZoomSize = -nSpriteXZoomSize;
212 			}
213 
214 			if (nXPos >= 0x0200) {
215 				nXPos -= 0x0400;
216 			}
217 
218 			if (nXPos < 0) {
219 				if (nXPos + nXSize <= 0) {
220 					continue;
221 				}
222 				nXPos = -nXPos;
223 				nSpriteXOffset += nXPos * nSpriteXZoomSize;
224 				nXSize -= nXPos;
225 				nXPos = 0;
226 			}
227 
228 			if (nXPos + nXSize >= nCaveXSize) {
229 				if (nXPos >= nCaveXSize) {
230 					continue;
231 				}
232 				nXSize = nCaveXSize - nXPos;
233 			}
234 
235 			nSpriteRowSize = pBuffer->xsize;										// Size of each sprite row in memory
236 			nSpriteYZoomSize = 0x01000000;											// * zoom factor = size of each screen pixel
237 
238 			nYSize *= pBuffer->yzoom;
239 			nYSize >>= 8;															// Round to multiple of whole pixel
240 			if (nYSize < 1) {														// Make certain the sprite is at least one pixel high
241 				nYSize = 1;
242 			} else {
243 				nSpriteYZoomSize /= pBuffer->yzoom;
244 			}
245 			if (nSpriteYZoomSize > (pBuffer->ysize << 16)) {
246 				nSpriteYZoomSize = pBuffer->ysize << 16;
247 			}
248 			nSpriteYOffset = nSpriteYZoomSize >> 1;									// Make certain the pixels displayed are centered
249 
250 			if (pBuffer->flip & 1) {												// Y Flip
251 				nYPos += pBuffer->ysize - nYSize;
252 
253 				nSpriteYOffset = (pBuffer->ysize << 16) - nSpriteYOffset;
254 				nSpriteYZoomSize = -nSpriteYZoomSize;
255 			}
256 
257 			if (nYPos >= 0x0200) {
258 				nYPos -= 0x0400;
259 			}
260 
261 			if (nYPos < 0) {
262 				if (nYPos + nYSize <= 0) {
263 					continue;
264 				}
265 				nYPos = -nYPos;
266 				nSpriteYOffset += nYPos * nSpriteYZoomSize;
267 				nYSize -= nYPos;
268 				nYPos = 0;
269 			}
270 
271 			if (nYPos + nYSize >= nCaveYSize) {
272 				if (nYPos >= nCaveYSize) {
273 					continue;
274 				}
275 				nYSize = nCaveYSize - nYPos;
276 			}
277 
278 			pRow = pBurnDraw + (nYPos * nBurnPitch) + (nXPos * nBurnBpp);
279 
280 			nFunction = 8;
281 
282 			if (pBuffer->xzoom > 0x0100 || pBuffer->yzoom > 0x0100) {
283 				nFunction |= 4;
284 			}
285 
286 			if (nTopSprite > nCurrentZPos) {										// Test ZBuffer
287 				if (nXPos < nMaskRight && nXPos + nXSize >= nMaskLeft && nYPos < nMaskBottom && nYPos + nYSize >= nMaskTop) {
288 					nFunction |= 1;
289 				}
290 			}
291 
292 			if (nUseBuffer < nCurrentZPos) {										// Write ZBuffer
293 				nFunction |= 2;
294 
295 				if (nXPos < nMaskLeft) {
296 					nMaskLeft = nXPos;
297 				}
298 				if (nXPos + nXSize > nMaskRight) {
299 					nMaskRight = nXPos + nXSize;
300 				}
301 				if (nYPos < nMaskTop) {
302 					nMaskTop = nYPos;
303 				}
304 				if (nYPos + nYSize > nMaskBottom) {
305 					nMaskBottom = nYPos + nYSize;
306 				}
307 			}
308 
309 			if (nFunction & 3) {
310 				pZRow = pZBuffer + (nYPos * nCaveXSize) + nXPos;
311 				nZPos = nCurrentZPos + nZOffset;
312 			}
313 
314 			nXSize <<= 16;
315 			nYSize <<= 16;
316 
317 			RenderSprite[nFunction]();
318 		}
319 	}
320 
321 	if (nMaxZPos > nTopSprite) {
322 		nTopSprite = nMaxZPos;
323 	}
324 
325 	if (nHighPriority == 3) {
326 		if (nZPos >= 0) {
327 			nZOffset += nTopSprite;
328 			if (nZOffset > 0xFC00) {
329 				memset(pZBuffer, 0, nCaveXSize * nCaveYSize * sizeof(UINT16));
330 				nZOffset = 0;
331 			}
332 		}
333 	}
334 
335 	return 0;
336 }
337 
338 // Donpachi/DoDonpachi sprite format (no zooming)
CaveSpriteBuffer_NoZoom()339 static INT32 CaveSpriteBuffer_NoZoom()
340 {
341 	UINT16* pSprite = (UINT16*)(CaveSpriteRAM + (nCaveSpriteBank << 14));
342 	CaveSprite* pBuffer = pSpriteList;
343 	INT32 nPriority;
344 
345 	nFirstSprite[0] = 0x00010000;
346 	nFirstSprite[1] = 0x00010000;
347 	nFirstSprite[2] = 0x00010000;
348 	nFirstSprite[3] = 0x00010000;
349 
350 	nLastSprite[0] = -1;
351 	nLastSprite[1] = -1;
352 	nLastSprite[2] = -1;
353 	nLastSprite[3] = -1;
354 
355 	INT16 word;
356 	INT32 x, y, xs, ys;
357 
358 	for (INT32 i = 0, z = 0; i < 0x0400; i++, pSprite += 8) {
359 
360 		word = BURN_ENDIAN_SWAP_INT16(pSprite[4]);
361 
362 		xs = (word >> 4) & 0x01F0;
363 		ys = (word << 4) & 0x01F0;
364 		if (ys == 0 || xs == 0) {
365 			continue;
366 		}
367 
368 #if 0
369 		x = (BURN_ENDIAN_SWAP_INT16(pSprite[2]) + nCaveExtraXOffset) & 0x03FF;
370 #else
371 		x = (BURN_ENDIAN_SWAP_INT16(pSprite[2]) + CaveSpriteVisibleXOffset) & 0x03FF;
372 #endif
373 		if (x >= 320) {
374 			if (x + xs <= 0x0400) {
375 				continue;
376 			}
377 		}
378 
379 #if 0
380 		y = (BURN_ENDIAN_SWAP_INT16(pSprite[3]) + nCaveExtraYOffset) & 0x03FF;
381 #else
382 		y = BURN_ENDIAN_SWAP_INT16(pSprite[3]) & 0x03FF;
383 #endif
384 		if (y >= 240) {
385 			if (y + ys <= 0x0400) {
386 				continue;
387 			}
388 		}
389 
390 		// Sprite is both active and onscreen, so add it to the buffer
391 
392 		word = BURN_ENDIAN_SWAP_INT16(pSprite[0]);
393 
394 		nPriority = (word >> 4) & 0x03;
395 		if (nLastSprite[nPriority] == -1) {
396 			nFirstSprite[nPriority] = z;
397 		}
398 		nLastSprite[nPriority] = z;
399 
400 		pBuffer->priority = 8 >> nPriority;
401 
402 		pBuffer->flip = (word >> 2) & 0x03;
403 		pBuffer->palette = word & 0x3F00;
404 
405 		pBuffer->address = BURN_ENDIAN_SWAP_INT16(pSprite[1]) | ((word & 3) << 16);
406 
407 		pBuffer->x = x;
408 		pBuffer->y = y;
409 
410 		pBuffer->xsize = xs;
411 		pBuffer->ysize = ys;
412 
413 		pBuffer++;
414 		z++;
415 	}
416 
417 	return 0;
418 }
419 
420 // Normal sprite format (zooming)
CaveSpriteBuffer_ZoomA()421 static INT32 CaveSpriteBuffer_ZoomA()
422 {
423 	UINT16* pSprite = (UINT16*)(CaveSpriteRAM + (nCaveSpriteBank << 14));
424 	CaveSprite* pBuffer = pSpriteList;
425 	INT32 nPriority;
426 
427 	nFirstSprite[0] = 0x00010000;
428 	nFirstSprite[1] = 0x00010000;
429 	nFirstSprite[2] = 0x00010000;
430 	nFirstSprite[3] = 0x00010000;
431 
432 	nLastSprite[0] = -1;
433 	nLastSprite[1] = -1;
434 	nLastSprite[2] = -1;
435 	nLastSprite[3] = -1;
436 
437 	INT16 word;
438 	INT32 x, y, xs, ys;
439 
440 	for (INT32 i = 0, z = 0; i < 0x0400; i++, pSprite += 8) {
441 
442 		word = BURN_ENDIAN_SWAP_INT16(pSprite[6]);
443 
444 		xs = (word >> 4) & 0x01F0;
445 		ys = (word << 4) & 0x01F0;
446 		if (ys == 0 || xs == 0) {
447 			continue;
448 		}
449 
450 		word = BURN_ENDIAN_SWAP_INT16(pSprite[2]);
451 
452 		nPriority = (word >> 4) & 0x03;
453 
454 		x = ((BURN_ENDIAN_SWAP_INT16(pSprite[0]) >> 6) + CaveSpriteVisibleXOffset) & 0x03FF;
455 #if 0
456 		y = ((BURN_ENDIAN_SWAP_INT16(pSprite[1]) >> 6) + nCaveExtraYOffset) & 0x03FF;
457 #else
458 		y = (BURN_ENDIAN_SWAP_INT16(pSprite[1]) >> 6) & 0x03FF;
459 #endif
460 
461 		if (BURN_ENDIAN_SWAP_INT16(pSprite[4]) <= 0x0100 && BURN_ENDIAN_SWAP_INT16(pSprite[5]) <= 0x0100) {
462 			if (x >= 320) {
463 				if (x + xs <= 0x0400) {
464 					continue;
465 				}
466 			}
467 			if (y >= 240) {
468 				if (y + ys <= 0x0400) {
469 					continue;
470 				}
471 			}
472 		}
473 
474 		// Sprite is active and most likely on screen, so add it to the buffer
475 
476 		if (nLastSprite[nPriority] == -1) {
477 			nFirstSprite[nPriority] = z;
478 		}
479 		nLastSprite[nPriority] = z;
480 
481 		pBuffer->priority = 8 >> nPriority;
482 
483 		pBuffer->xzoom = BURN_ENDIAN_SWAP_INT16(pSprite[4]);
484 		pBuffer->yzoom = BURN_ENDIAN_SWAP_INT16(pSprite[5]);
485 
486 		pBuffer->xsize = xs;
487 		pBuffer->ysize = ys;
488 
489 		pBuffer->x = x;
490 		pBuffer->y = y;
491 
492 		pBuffer->flip = (word >> 2) & 0x03;
493 		pBuffer->palette = word & 0x3F00;
494 
495 		pBuffer->address = BURN_ENDIAN_SWAP_INT16(pSprite[3]) | ((word & 3) << 16);
496 
497 		pBuffer++;
498 		z++;
499 	}
500 
501 	return 0;
502 }
503 
504 // Normal sprite format (zooming, alternate position handling)
CaveSpriteBuffer_ZoomB()505 static INT32 CaveSpriteBuffer_ZoomB()
506 {
507 	UINT16* pSprite = (UINT16*)(CaveSpriteRAM + (nCaveSpriteBank << 14));
508 	CaveSprite* pBuffer = pSpriteList;
509 	INT32 nPriority;
510 
511 	nFirstSprite[0] = 0x00010000;
512 	nFirstSprite[1] = 0x00010000;
513 	nFirstSprite[2] = 0x00010000;
514 	nFirstSprite[3] = 0x00010000;
515 
516 	nLastSprite[0] = -1;
517 	nLastSprite[1] = -1;
518 	nLastSprite[2] = -1;
519 	nLastSprite[3] = -1;
520 
521 	INT16 word;
522 	INT32 x, y, xs, ys;
523 
524 	for (INT32 i = 0, z = 0; i < 0x0400; i++, pSprite += 8) {
525 
526 		word = BURN_ENDIAN_SWAP_INT16(pSprite[6]);
527 
528 		xs = (word >> 4) & 0x01F0;
529 		ys = (word << 4) & 0x01F0;
530 		if (ys == 0 || xs == 0) {
531 			continue;
532 		}
533 
534 		word = BURN_ENDIAN_SWAP_INT16(pSprite[2]);
535 
536 		nPriority = (word >> 4) & 0x03;
537 
538 #if 0
539 		x = (BURN_ENDIAN_SWAP_INT16(pSprite[0]) + nCaveExtraXOffset) & 0x03FF;
540 # else
541 		x = (BURN_ENDIAN_SWAP_INT16(pSprite[0]) + CaveSpriteVisibleXOffset) & 0x03FF;
542 #endif
543 #if 0
544 		y = (BURN_ENDIAN_SWAP_INT16(pSprite[1]) + nCaveExtraYOffset) & 0x03FF;
545 #else
546 		y = BURN_ENDIAN_SWAP_INT16(pSprite[1]) & 0x03FF;
547 #endif
548 
549 		if (BURN_ENDIAN_SWAP_INT16(pSprite[4]) <= 0x0100 && BURN_ENDIAN_SWAP_INT16(pSprite[5]) <= 0x0100) {
550 			if (x >= nCaveXSize) {
551 				if (x + xs <= 0x0400) {
552 					continue;
553 				}
554 			}
555 			if (y >= nCaveYSize) {
556 				if (y + ys <= 0x0400) {
557 					continue;
558 				}
559 			}
560 		}
561 
562 		// Sprite is active and most likely on screen, so add it to the buffer
563 
564 		if (nLastSprite[nPriority] == -1) {
565 			nFirstSprite[nPriority] = z;
566 		}
567 		nLastSprite[nPriority] = z;
568 
569 		pBuffer->priority = 8 >> nPriority;
570 
571 		pBuffer->xzoom = BURN_ENDIAN_SWAP_INT16(pSprite[4]);
572 		pBuffer->yzoom = BURN_ENDIAN_SWAP_INT16(pSprite[5]);
573 
574 		pBuffer->xsize = xs;
575 		pBuffer->ysize = ys;
576 
577 		pBuffer->x = x;
578 		pBuffer->y = y;
579 
580 		pBuffer->flip = (word >> 2) & 0x03;
581 		pBuffer->palette = word & 0x3F00;
582 
583 		pBuffer->address = BURN_ENDIAN_SWAP_INT16(pSprite[3]) | ((word & 3) << 16);
584 
585 		pBuffer++;
586 		z++;
587 	}
588 
589 	return 0;
590 }
591 
592 // Power Instinct 2 sprite format (no zooming)
CaveSpriteBuffer_PowerInstinct()593 static INT32 CaveSpriteBuffer_PowerInstinct()
594 {
595 	UINT16* pSprite = (UINT16*)(CaveSpriteRAM + (nCaveSpriteBank << 14));
596 	CaveSprite* pBuffer = pSpriteList;
597 	INT32 nPriority;
598 
599 	nFirstSprite[0] = 0x00010000;
600 	nFirstSprite[1] = 0x00010000;
601 	nFirstSprite[2] = 0x00010000;
602 	nFirstSprite[3] = 0x00010000;
603 
604 	nLastSprite[0] = -1;
605 	nLastSprite[1] = -1;
606 	nLastSprite[2] = -1;
607 	nLastSprite[3] = -1;
608 
609 	INT16 word;
610 	INT32 x, y, xs, ys;
611 
612 	for (INT32 i = 0, z = 0; i < 0x0400; i++, pSprite += 8) {
613 
614 		word = BURN_ENDIAN_SWAP_INT16(pSprite[4]);
615 
616 		xs = (word >> 4) & 0x01F0;
617 		ys = (word << 4) & 0x01F0;
618 		if (ys == 0 || xs == 0) {
619 			continue;
620 		}
621 
622 		x = (BURN_ENDIAN_SWAP_INT16(pSprite[2]) + nCaveExtraXOffset) & 0x03FF;
623 		if (x >= 320) {
624 			if (x + xs <= 0x0400) {
625 				continue;
626 			}
627 		}
628 
629 		y = (BURN_ENDIAN_SWAP_INT16(pSprite[3]) + nCaveExtraYOffset) & 0x03FF;
630 		if (y >= 240) {
631 			if (y + ys <= 0x0400) {
632 				continue;
633 			}
634 		}
635 
636 		// Sprite is both active and onscreen, so add it to the buffer
637 
638 		word = BURN_ENDIAN_SWAP_INT16(pSprite[0]);
639 
640 		nPriority = ((word >> 4) & 0x01) | 2;
641 		if (nLastSprite[nPriority] == -1) {
642 			nFirstSprite[nPriority] = z;
643 		}
644 		nLastSprite[nPriority] = z;
645 
646 		pBuffer->priority = 8 >> nPriority;
647 
648 		pBuffer->flip = (word >> 2) & 0x03;
649 		pBuffer->palette = ((word >> 4) & 0x03F0) + ((word << 5) & 0xC00);
650 
651 		pBuffer->address = BURN_ENDIAN_SWAP_INT16(pSprite[1]) | ((word & 3) << 16);
652 
653 		pBuffer->x = x;
654 		pBuffer->y = y;
655 
656 		pBuffer->xsize = xs;
657 		pBuffer->ysize = ys;
658 
659 		pBuffer++;
660 		z++;
661 	}
662 
663 	return 0;
664 }
665 
CaveSpriteExit()666 void CaveSpriteExit()
667 {
668 	BurnFree(pSpriteList);
669 	BurnFree(pZBuffer);
670 
671 	CaveSpriteVisibleXOffset = 0;
672 
673 	return;
674 }
675 
CaveSpriteInit(INT32 nType,INT32 nROMSize)676 INT32 CaveSpriteInit(INT32 nType, INT32 nROMSize)
677 {
678 	if (pSpriteList) {
679 		BurnFree(pSpriteList);
680 	}
681 	pSpriteList = (CaveSprite*)BurnMalloc(0x0401 * sizeof(CaveSprite));
682 	if (pSpriteList == NULL) {
683 		CaveSpriteExit();
684 		return 1;
685 	}
686 
687 	for (INT32 i = 0; i < 0x0400; i++) {
688 		pSpriteList[i].xzoom = 0x0100;
689 		pSpriteList[i].yzoom = 0x0100;
690 	}
691 	for (INT32 i = 0; i < 4; i++) {
692 		nFirstSprite[i] = 0x00010000;
693 		nLastSprite[i] = -1;
694 	}
695 
696 	if (pZBuffer) {
697 		BurnFree(pZBuffer);
698 	}
699 	pZBuffer = (UINT16*)BurnMalloc(nCaveXSize * nCaveYSize * sizeof(UINT16));
700 	if (pZBuffer == NULL) {
701 		CaveSpriteExit();
702 		return 1;
703 	}
704 
705 	memset(pZBuffer, 0, nCaveXSize * nCaveYSize * sizeof(UINT16));
706 	nZOffset = 0;
707 
708 	for (nSpriteAddressMask = 1; nSpriteAddressMask < nROMSize; nSpriteAddressMask <<= 1) {}
709 	nSpriteAddressMask--;
710 
711 	switch (nType) {
712 		case 0:
713 			CaveSpriteBuffer = &CaveSpriteBuffer_NoZoom;
714 			break;
715 		case 1:
716 			CaveSpriteBuffer = &CaveSpriteBuffer_ZoomA;
717 			break;
718 		case 2:
719 			CaveSpriteBuffer = &CaveSpriteBuffer_ZoomB;
720 			break;
721 		case 3:
722 			CaveSpriteBuffer = &CaveSpriteBuffer_PowerInstinct;
723 			break;
724 		default:
725 			CaveSpriteExit();
726 			return 1;
727 	}
728 
729 	nCaveSpriteBank = 0;
730 	nCaveSpriteBankDelay = 0;
731 
732 	RenderSprite = RenderSprite_ROT0[(nCaveXSize == 320) ? 0 : 1];
733 
734 	return 0;
735 }
736