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