1 /* Super Kaneko Nova System Sprites
2 
3    "CG24173 6186" & "CG24143 4181" (always used as a pair?)
4 
5   - used by suprnova.c
6             galpani3.c
7             jchan.c
8 
9   - ToDo:
10     Get rid of sprite position kludges
11     Fix zooming precision/rounding (most noticeable on jchan backgrounds)
12 
13 	Ported from MAME 0.144u4
14 	based on MAME sources by David Haywood
15 */
16 
17 #include "tiles_generic.h"
18 
19 #define cliprect_min_y 0
20 #define cliprect_max_y (nScreenHeight-1)
21 #define cliprect_min_x 0
22 #define cliprect_max_x (nScreenWidth - 1)
23 
24 #define SUPRNOVA_DECODE_BUFFER_SIZE	0x2000
25 
26 static INT32 sprite_kludge_x, sprite_kludge_y;
27 static UINT8 decodebuffer[0x2000];
28 
skns_rle_decode(INT32 romoffset,INT32 size,UINT8 * gfx_source,INT32 gfx_length)29 static INT32 skns_rle_decode ( INT32 romoffset, INT32 size, UINT8*gfx_source, INT32 gfx_length )
30 {
31 	UINT8 *src = gfx_source;
32 	INT32 srcsize = gfx_length;
33 	UINT8 *dst = decodebuffer;
34 	INT32 decodeoffset = 0;
35 
36 	while(size>0) {
37 		UINT8 code = src[(romoffset++)%srcsize];
38 		size -= (code & 0x7f) + 1;
39 		if(code & 0x80) { /* (code & 0x7f) normal values will follow */
40 			code &= 0x7f;
41 			do {
42 				dst[(decodeoffset++)%SUPRNOVA_DECODE_BUFFER_SIZE] = src[(romoffset++)%srcsize];
43 				code--;
44 			} while(code != 0xff);
45 		} else {  /* repeat next value (code & 0x7f) times */
46 			UINT8 val = src[(romoffset++)%srcsize];
47 			do {
48 				dst[(decodeoffset++)%SUPRNOVA_DECODE_BUFFER_SIZE] = val;
49 				code--;
50 			} while(code != 0xff);
51 		}
52 	}
53 	return &src[romoffset%srcsize]-gfx_source;
54 }
55 
skns_sprite_kludge(INT32 x,INT32 y)56 void skns_sprite_kludge(INT32 x, INT32 y)
57 {
58 #if defined FBNEO_DEBUG
59 	if (!DebugDev_SknsSprInitted) bprintf(PRINT_ERROR, _T("skns_sprite_kludge called without init\n"));
60 #endif
61 
62 	sprite_kludge_x = x;
63 	sprite_kludge_y = y;
64 }
65 
66 /* Zooming blitter, zoom is by way of both source and destination offsets */
67 /* We are working in .6 fixed point if you hadn't guessed */
68 
69 #define z_decls(step)				\
70 	UINT16 zxs = 0x40-(zx_m>>2);			\
71 	UINT16 zxd = 0x40-(zx_s>>2);		\
72 	UINT16 zys = 0x40-(zy_m>>2);			\
73 	UINT16 zyd = 0x40-(zy_s>>2);		\
74 	INT32 xs, ys, xd, yd, old, old2;		\
75 	INT32 step_spr = step;				\
76 	INT32 bxs = 0, bys = 0;				\
77 	INT32 clip_min_x = cliprect_min_x<<6;		\
78 	INT32 clip_max_x = (cliprect_max_x+1)<<6;	\
79 	INT32 clip_min_y = cliprect_min_y<<6;		\
80 	INT32 clip_max_y = (cliprect_max_y+1)<<6;	\
81 	sx <<= 6;					\
82 	sy <<= 6;					\
83 	x <<= 6;					\
84 	y <<= 6;
85 
86 #define z_clamp_x_min()			\
87 	if(x < clip_min_x) {					\
88 		do {					\
89 			bxs += zxs;				\
90 			x += zxd;					\
91 		} while(x < clip_min_x);				\
92 	}
93 
94 #define z_clamp_x_max()			\
95 	if(x > clip_max_x) {				\
96 		do {					\
97 			bxs += zxs;				\
98 			x -= zxd;					\
99 		} while(x > clip_max_x);				\
100 	}
101 
102 #define z_clamp_y_min()			\
103 	if(y < clip_min_y) {					\
104 		do {					\
105 			bys += zys;				\
106 			y += zyd;					\
107 		} while(y < clip_min_y);				\
108 		src += (bys>>6)*step_spr;			\
109 	}
110 
111 #define z_clamp_y_max()			\
112 	if(y > clip_max_y) {				\
113 		do {					\
114 			bys += zys;				\
115 			y -= zyd;					\
116 		} while(y > clip_max_y);				\
117 		src += (bys>>6)*step_spr;			\
118 	}
119 
120 #define z_loop_x()			\
121 	xs = bxs;					\
122 	xd = x;					\
123 	while(xs < sx && xd <= clip_max_x)
124 
125 #define z_loop_x_flip()			\
126 	xs = bxs;					\
127 	xd = x;					\
128 	while(xs < sx && xd >= clip_min_x)
129 
130 #define z_loop_y()			\
131 	ys = bys;					\
132 	yd = y;					\
133 	while(ys < sy && yd <= clip_max_y)
134 
135 #define z_loop_y_flip()			\
136 	ys = bys;					\
137 	yd = y;					\
138 	while(ys < sy && yd >= clip_min_y)
139 
140 #define z_draw_pixel()				\
141 	UINT8 val = src[xs >> 6];			\
142 	if(val)					\
143 		if ((yd>>6) < nScreenHeight && (xd>>6) < nScreenWidth)	\
144 			bitmap[(yd>>6) * nScreenWidth + (xd>>6)] = val + colour;
145 
146 #define z_x_dst(op)			\
147 	old = xd;					\
148 	do {						\
149 		xs += zxs;					\
150 		xd op zxd;					\
151 	} while(!((xd^old) & ~0x3f));
152 
153 #define z_y_dst(op)			\
154 	old = yd;					\
155 	old2 = ys;					\
156 	do {						\
157 		ys += zys;					\
158 		yd op zyd;					\
159 	} while(!((yd^old) & ~0x3f));			\
160 	while((ys^old2) & ~0x3f) {			\
161 		src += step_spr;				\
162 		old2 += 0x40;				\
163 	}
164 
blit_nf_z(UINT16 * bitmap,const UINT8 * src,INT32 x,INT32 y,INT32 sx,INT32 sy,UINT16 zx_m,UINT16 zx_s,UINT16 zy_m,UINT16 zy_s,INT32 colour)165 static void blit_nf_z(UINT16 *bitmap, const UINT8 *src, INT32 x, INT32 y, INT32 sx, INT32 sy, UINT16 zx_m, UINT16 zx_s, UINT16 zy_m, UINT16 zy_s, INT32 colour)
166 {
167 	z_decls(sx);
168 	z_clamp_x_min();
169 	z_clamp_y_min();
170 	z_loop_y() {
171 		z_loop_x() {
172 			z_draw_pixel();
173 			z_x_dst(+=);
174 		}
175 		z_y_dst(+=);
176 	}
177 }
178 
blit_fy_z(UINT16 * bitmap,const UINT8 * src,INT32 x,INT32 y,INT32 sx,INT32 sy,UINT16 zx_m,UINT16 zx_s,UINT16 zy_m,UINT16 zy_s,INT32 colour)179 static void blit_fy_z(UINT16 *bitmap, const UINT8 *src, INT32 x, INT32 y, INT32 sx, INT32 sy, UINT16 zx_m, UINT16 zx_s, UINT16 zy_m, UINT16 zy_s, INT32 colour)
180 {
181 	z_decls(sx);
182 	z_clamp_x_min();
183 	z_clamp_y_max();
184 	z_loop_y_flip() {
185 		z_loop_x() {
186 			z_draw_pixel();
187 			z_x_dst(+=);
188 		}
189 		z_y_dst(-=);
190 	}
191 }
192 
blit_fx_z(UINT16 * bitmap,const UINT8 * src,INT32 x,INT32 y,INT32 sx,INT32 sy,UINT16 zx_m,UINT16 zx_s,UINT16 zy_m,UINT16 zy_s,INT32 colour)193 static void blit_fx_z(UINT16 *bitmap, const UINT8 *src, INT32 x, INT32 y, INT32 sx, INT32 sy, UINT16 zx_m, UINT16 zx_s, UINT16 zy_m, UINT16 zy_s, INT32 colour)
194 {
195 	z_decls(sx);
196 	z_clamp_x_max();
197 	z_clamp_y_min();
198 	z_loop_y() {
199 		z_loop_x_flip() {
200 			z_draw_pixel();
201 			z_x_dst(-=);
202 		}
203 		z_y_dst(+=);
204 	}
205 }
206 
blit_fxy_z(UINT16 * bitmap,const UINT8 * src,INT32 x,INT32 y,INT32 sx,INT32 sy,UINT16 zx_m,UINT16 zx_s,UINT16 zy_m,UINT16 zy_s,INT32 colour)207 static void blit_fxy_z(UINT16 *bitmap, const UINT8 *src, INT32 x, INT32 y, INT32 sx, INT32 sy, UINT16 zx_m, UINT16 zx_s, UINT16 zy_m, UINT16 zy_s, INT32 colour)
208 {
209 	z_decls(sx);
210 	z_clamp_x_max();
211 	z_clamp_y_max();
212 	z_loop_y_flip() {
213 		z_loop_x_flip() {
214 			z_draw_pixel();
215 			z_x_dst(-=);
216 		}
217 		z_y_dst(-=);
218 	}
219 }
220 
221 static void (*const blit_z[4])(UINT16 *bitmap, const UINT8 *src, INT32 x, INT32 y, INT32 sx, INT32 sy, UINT16 zx_m, UINT16 zx_s, UINT16 zy_m, UINT16 zy_s, INT32 colour) = {
222 	blit_nf_z,
223 	blit_fy_z,
224 	blit_fx_z,
225 	blit_fxy_z,
226 };
227 
228 // disable_priority is a hack to make jchan drawing a bit quicker (rather than moving the sprites around different bitmaps and adding colors
skns_draw_sprites(UINT16 * bitmap,UINT32 * spriteram_source,INT32 spriteram_size,UINT8 * gfx_source,INT32 gfx_length,UINT32 * sprite_regs,INT32 disable_priority)229 void skns_draw_sprites(UINT16 *bitmap, UINT32* spriteram_source, INT32 spriteram_size, UINT8* gfx_source, INT32 gfx_length, UINT32* sprite_regs, INT32 disable_priority)
230 {
231 #if defined FBNEO_DEBUG
232 	if (!DebugDev_SknsSprInitted) bprintf(PRINT_ERROR, _T("skns_draw_sprites called without init\n"));
233 #endif
234 
235 	/*- SPR RAM Format -**
236 
237       16 bytes per sprite
238 
239 	0x00  --ss --SS  z--- ----  jjjg g-ff  ppcc cccc
240 
241       s = y size
242       S = x size
243       j = joint
244       g = group sprite is part of (if groups are enabled)
245       f = flip
246       p = priority
247       c = palette
248 
249 	0x04  ---- -aaa  aaaa aaaa  aaaa aaaa  aaaa aaaa
250 
251       a = ROM address of sprite data
252 
253 	0x08  ZZZZ ZZ--  zzzz zz--  xxxx xxxx  xx-- ----
254 
255       Z = horizontal zoom table
256       z = horizontal zoom subtable
257       x = x position
258 
259 	0x0C  ZZZZ ZZ--  zzzz zz--  yyyy yyyy  yy-- ----
260 
261       Z = vertical zoom table
262       z = vertical zoom subtable
263       x = y position
264 
265 	**- End of Comments -*/
266 
267 	UINT32 *source = spriteram_source;
268 	UINT32 *finish = source + spriteram_size/4;
269 
270 	INT32 group_x_offset[4];
271 	INT32 group_y_offset[4];
272 	INT32 group_enable;
273 	INT32 group_number;
274 	INT32 sprite_flip;
275 	INT32 sprite_x_scroll;
276 	INT32 sprite_y_scroll;
277 	INT32 disabled = sprite_regs[0x04/4] & 0x08; // RWR1
278 	INT32 xsize,ysize, size, xpos=0,ypos=0, pri=0, romoffset, colour=0, xflip,yflip, joint;
279 	INT32 sx,sy;
280 	INT32 endromoffs=0, gfxlen;
281 	INT32 grow;
282 	UINT16 zoomx_m, zoomx_s, zoomy_m, zoomy_s;
283 
284 	if ((!disabled)){
285 
286 		group_enable    = (sprite_regs[0x00/4] & 0x0040) >> 6; // RWR0
287 
288 		/* Sengekis uses global flip */
289 		sprite_flip = (sprite_regs[0x04/4] & 0x03); // RWR1
290 
291 		sprite_y_scroll = ((sprite_regs[0x08/4] & 0x7fc0) >> 6); // RWR2
292 		sprite_x_scroll = ((sprite_regs[0x10/4] & 0x7fc0) >> 6); // RWR4
293 		if (sprite_y_scroll&0x100) sprite_y_scroll -= 0x200; // Signed
294 		if (sprite_x_scroll&0x100) sprite_x_scroll -= 0x200; // Signed
295 
296 		group_x_offset[0] = (sprite_regs[0x18/4] & 0xffc0) >> 6; // RWR6
297 		group_y_offset[0] = (sprite_regs[0x1c/4] & 0xffc0) >> 6; // RWR7
298 		if (group_x_offset[0]&0x200) group_x_offset[0] -= 0x400; // Signed
299 		if (group_y_offset[0]&0x200) group_y_offset[0] -= 0x400; // Signed
300 
301 		group_x_offset[1] = (sprite_regs[0x20/4] & 0xffc0) >> 6; // RWR8
302 		group_y_offset[1] = (sprite_regs[0x24/4] & 0xffc0) >> 6; // RWR9
303 		if (group_x_offset[1]&0x200) group_x_offset[1] -= 0x400; // Signed
304 		if (group_y_offset[1]&0x200) group_y_offset[1] -= 0x400; // Signed
305 
306 		group_x_offset[2] = (sprite_regs[0x28/4] & 0xffc0) >> 6; // RWR10
307 		group_y_offset[2] = (sprite_regs[0x2c/4] & 0xffc0) >> 6; // RWR11
308 		if (group_x_offset[2]&0x200) group_x_offset[2] -= 0x400; // Signed
309 		if (group_y_offset[2]&0x200) group_y_offset[2] -= 0x400; // Signed
310 
311 		group_x_offset[3] = (sprite_regs[0x30/4] & 0xffc0) >> 6; // RWR12
312 		group_y_offset[3] = (sprite_regs[0x34/4] & 0xffc0) >> 6; // RWR13
313 		if (group_x_offset[3]&0x200) group_x_offset[3] -= 0x400; // Signed
314 		if (group_y_offset[3]&0x200) group_y_offset[3] -= 0x400; // Signed
315 
316 		/* Seems that sprites are consistently off by a fixed no. of pixels in different games
317            (Patterns emerge through Manufacturer/Date/Orientation) */
318 		sprite_x_scroll += sprite_kludge_x;
319 		sprite_y_scroll += sprite_kludge_y;
320 
321 
322 		gfxlen = gfx_length;
323 		while( source<finish )
324 		{
325 			xflip = (source[0] & 0x00000200) >> 9;
326 			yflip = (source[0] & 0x00000100) >> 8;
327 
328 			ysize = (source[0] & 0x30000000) >> 28;
329 			xsize = (source[0] & 0x03000000) >> 24;
330 			xsize ++;
331 			ysize ++;
332 
333 			xsize *= 16;
334 			ysize *= 16;
335 
336 			size = xsize * ysize;
337 
338 			joint = (source[0] & 0x0000e000) >> 13;
339 
340 			if (!(joint & 1))
341 			{
342 				xpos =  (source[2] & 0x0000ffc0) >> 6;
343 				ypos =  (source[3] & 0x0000ffc0) >> 6;
344 
345 				xpos += sprite_x_scroll; // Global offset
346 				ypos += sprite_y_scroll;
347 
348 				if (group_enable)
349 				{
350 					group_number = (source[0] & 0x00001800) >> 11;
351 
352 					/* the group positioning doesn't seem to be working as i'd expect,
353 					if I apply the x position the cursor on galpani4 ends up moving
354 					from the correct position to too far right, also the y offset
355 					seems to cause the position to be off by one in galpans2 even if
356 					it fixes the position in galpani4?
357 
358 					even if I take into account the global sprite scroll registers
359 					it isn't right
360 
361 					global offset kludged using game specific offset -pjp */
362 
363 					xpos += group_x_offset[group_number];
364 					ypos += group_y_offset[group_number];
365 				}
366 			}
367 			else
368 			{
369 				xpos +=  (source[2] & 0x0000ffc0) >> 6;
370 				ypos +=  (source[3] & 0x0000ffc0) >> 6;
371 			}
372 
373 			if (xpos > 0x1ff) xpos -= 0x400;
374 			if (ypos > 0x1ff) ypos -= 0x400;
375 
376 			/* Local sprite offset (for taking flip into account and drawing offset) */
377 			sx = xpos;
378 			sy = ypos;
379 
380 			/* Global Sprite Flip (sengekis) */
381 			if (sprite_flip&2)
382 			{
383 				xflip ^= 1;
384 				sx = nScreenWidth - sx;
385 			}
386 			if (sprite_flip&1)
387 			{
388 				yflip ^= 1;
389 				sy = nScreenHeight - sy;
390 			}
391 
392 			/* Palette linking */
393 			if (!(joint & 2))
394 			{
395 				colour = (source[0] & 0x0000003f) >> 0;
396 			}
397 
398 			/* Priority and Tile linking */
399 			if (!(joint & 4))
400 			{
401 				romoffset = (source[1] & 0x07ffffff) >> 0;
402 				pri = (source[0] & 0x000000c0) >> 6;
403 			} else {
404 				romoffset = endromoffs;
405 			}
406 
407 			grow = (source[0]>>23) & 1;
408 
409 			if (!grow)
410 			{
411 				zoomx_m = (source[2] >> 24)&0x00fc;
412 				zoomx_s = (source[2] >> 16)&0x00fc;
413 				zoomy_m = (source[3] >> 24)&0x00fc;
414 				zoomy_s = (source[3] >> 16)&0x00fc;
415 			}
416 			else
417 			{
418 				// sengekis uses this on sprites which are shrinking as they head towards the ground
419 				// it's also used on the input test of Gals Panic S2
420 				//
421 				// it appears to offer a higher precision 'shrink' mode (although I'm not entirely
422 				//  convinced this implementation is correct because we simply end up ignoring
423 				//  part of the data)
424 				zoomx_m = 0;
425 				zoomx_s = (source[2] >> 24)&0x00fc;
426 				zoomy_m = 0;
427 				zoomy_s = (source[3] >> 24)&0x00fc;
428 
429 
430 			}
431 
432 			romoffset &= gfxlen-1;
433 
434 			endromoffs = skns_rle_decode ( romoffset, size, gfx_source, gfx_length );
435 
436 			// in Cyvern
437 
438 			//  train in tunnel pri = 0x00
439 			//  nothing?         = 0x01
440 			//  players etc. pri = 0x02
441 			//  pickups etc. pri = 0x03
442 
443 			{
444 				INT32 NewColour = (colour<<8);
445 				if (disable_priority) {
446 					NewColour += disable_priority; // jchan hack
447 				} else {
448 					NewColour += (pri << 14);
449 				}
450 
451 				if(zoomx_m || zoomx_s || zoomy_m || zoomy_s)
452 				{
453 					blit_z[ (xflip<<1) | yflip ](bitmap, decodebuffer, sx, sy, xsize, ysize, zoomx_m, zoomx_s, zoomy_m, zoomy_s, NewColour);
454 				}
455 				else
456 				{
457 					if (!xflip && !yflip) {
458 						INT32 xx,yy;
459 
460 						for (xx = 0; xx<xsize; xx++)
461 						{
462 							if ((sx+xx < (cliprect_max_x+1)) && (sx+xx >= cliprect_min_x))
463 							{
464 								for (yy = 0; yy<ysize; yy++)
465 								{
466 									if ((sy+yy < (cliprect_max_y+1)) && (sy+yy >= cliprect_min_y))
467 									{
468 										INT32 pix;
469 										pix = decodebuffer[xsize*yy+xx];
470 										if (pix)
471 											bitmap[(sy+yy) * nScreenWidth + (sx+xx)] = pix+ NewColour; // change later
472 									}
473 								}
474 							}
475 						}
476 					} else if (!xflip && yflip) {
477 						INT32 xx,yy;
478 						sy -= ysize;
479 
480 						for (xx = 0; xx<xsize; xx++)
481 						{
482 							if ((sx+xx < (cliprect_max_x+1)) && (sx+xx >= cliprect_min_x))
483 							{
484 								for (yy = 0; yy<ysize; yy++)
485 								{
486 									if ((sy+(ysize-1-yy) < (cliprect_max_y+1)) && (sy+(ysize-1-yy) >= cliprect_min_y))
487 									{
488 										INT32 pix;
489 										pix = decodebuffer[xsize*yy+xx];
490 										if (pix)
491 											bitmap[(sy+(ysize-1-yy)) * nScreenWidth + (sx+xx)] = pix+ NewColour; // change later
492 									}
493 								}
494 							}
495 						}
496 					} else if (xflip && !yflip) {
497 						INT32 xx,yy;
498 						sx -= xsize;
499 
500 						for (xx = 0; xx<xsize; xx++)
501 						{
502 							if ( (sx+(xsize-1-xx) < (cliprect_max_x+1)) && (sx+(xsize-1-xx) >= cliprect_min_x))
503 							{
504 								for (yy = 0; yy<ysize; yy++)
505 								{
506 									if ((sy+yy < (cliprect_max_y+1)) && (sy+yy >= cliprect_min_y))
507 									{
508 										INT32 pix;
509 										pix = decodebuffer[xsize*yy+xx];
510 										if (pix)
511 											bitmap[(sy+yy) * nScreenWidth + (sx+(xsize-1-xx))] = pix+ NewColour; // change later
512 									}
513 								}
514 							}
515 						}
516 					} else if (xflip && yflip) {
517 						INT32 xx,yy;
518 						sx -= xsize;
519 						sy -= ysize;
520 
521 						for (xx = 0; xx<xsize; xx++)
522 						{
523 							if ((sx+(xsize-1-xx) < (cliprect_max_x+1)) && (sx+(xsize-1-xx) >= cliprect_min_x))
524 							{
525 								for (yy = 0; yy<ysize; yy++)
526 								{
527 									if ((sy+(ysize-1-yy) < (cliprect_max_y+1)) && (sy+(ysize-1-yy) >= cliprect_min_y))
528 									{
529 										INT32 pix;
530 										pix = decodebuffer[xsize*yy+xx];
531 										if (pix)
532 											bitmap[(sy+(ysize-1-yy)) * nScreenWidth + (sx+(xsize-1-xx))] = pix+ NewColour; // change later
533 									}
534 								}
535 							}
536 						}
537 					}
538 				}
539 			}
540 
541 			source+=4;
542 		}
543 	}
544 }
545 
skns_init()546 void skns_init()
547 {
548 	DebugDev_SknsSprInitted = 1;
549 }
550 
skns_exit()551 void skns_exit()
552 {
553 #if defined FBNEO_DEBUG
554 	if (!DebugDev_SknsSprInitted) bprintf(PRINT_ERROR, _T("skns_exit called without init\n"));
555 #endif
556 
557 	DebugDev_SknsSprInitted = 0;
558 }
559