1 // license:BSD-3-Clause
2 // copyright-holders:David Haywood, Paul Priest
3 /*
4 Psikyo PS6406B (PS3v1/PS5/PS5v2):
5 See src/mame/drivers/psikyosh.cpp for more info
6
7 Hardware is extremely flexible (and luckily underused, although we now have a relatively complete implementation :). Many effects are subtle (e.g. fades, scanline effects).
8
9 Banks:
10 There are 32 data banks of 0x800 bytes starting at 0x3000000 (ps3) / 0x4000000 (ps5/ps5v2)
11
12 Can be one of:
13 * a set of adjacent banks for sprites (we always use the first 7 banks currently, looks to be configurable in vidregs
14 * a sprite draw list (max 1024 sprites, always in bank 07?)
15 * pre (i.e. screen clear) + post (i.e. drawn with a non-zero priority) line-fill/blend layer (usually bank 08)
16 * tilemap tiles (or 2 adjacent banks for large tilemaps) (usually banks 0c-1f)
17 * xscroll/yscroll, pri/xzoom/alpha/bank per-layer (of which there are four) -> which points to another tilebank per-layer (usually bank 0a/0b)
18 * xscroll/yscroll, pri/xzoom/alpha/bank per-scanline (typically 224) -> which points to another tilebank per-line (usually bank 0c/0d)
19
20 Most games use bank 0x0a and 0x0b for the registers for double-buffering, which then refer to other banks for the tiles. If they use line-effects, they tend to populate the per-line registers into one of the other banks e.g. daraku or S1945II test+level 7+level8 boss and S1945III levels 7+8, soldivid final boss.
21 */
22
23 /*
24 BG Scroll/Priority/Zoom/Alpha/Tilebank registers:
25 Either at 0x30053f0/4/8 (For 0a), 0x3005bf0/4/8 (For 0b) etc. (i.e. in the middle of a bank) Or per-line in a bank
26 0x?vvv?xxx - v = vertical scroll - x = x scroll
27 Either at 0x30057f0/4/8 (For 0a), 0x3005ff0/4/8 (For 0b) etc. (i.e. at the end of the bank) Or per-line in a bank
28 0xppzzaabb - p = priority, z = zoom/expand(00 is none), a = alpha value/effect, b = tilebank
29
30 Video Registers: at 0x305ffe0 for ps3 or 0x405ffe0 for ps5/ps5v2:
31 0x00 -- ffffffff alpha values for sprites, 8-bits per value (0-0x3f, 0x80 indicates per-pen alpha). sbomberb = 0000 3830 2820 1810
32 0x04 -- ffffffff above continued.
33 0x08 -- ffff0000 priority values for sprites, 4-bits per value
34 0000ff00 unknown. always 20. number of addressable banks? boards are populated with 20.
35 000000f0 unknown. s1945ii/s1945iii/gunbird2/gnbarich/tgm2 sets to c. soldivid/daraku is 0. another bank select?
36 0000000f is priority for per-line post-blending
37 0x0c -- 3f3f3f3f unknown. A table of 4 6-bit values. usually 0f102038. tgm2 is 0a172838.
38 c0c00000 unknown. unused?
39 0000c000 is flipscreen (currently ignored). presumably flipy<<1|flipx.
40 000000c0 is screen size select. 0 is 224 lines, c is 240 (see tgm2, not confirmed).
41 0x10 -- ffff0000 is always 00aa
42 0000f000 number of banks for sprites (not confirmed). mjgtaste/tgm2/sbomberb/s1945ii is 3, gunbird2/s1945iii is 2, soldivid/daraku is b.
43 00000fff Controls gfx data bank available to be read by SH-2 for verification.
44 0x14 -- ffffffff always 83ff000e
45 0x18 -- ffffffff bank for tilemaps. As follows for the different tilemaps: 11223344. Bit 0x80 indicates use of line effects and the bank should be used to look up the tile-bank per line.
46 0x1c -- ff000000 controls bank for 'pre'/'post' values
47 00ff0000 unknown, always 0?
48 0000ffff enable bits for 4 tilemaps. 8 is enable. 4 indicates 8bpp tiles. 1 is size select for tilemap
49 */
50
51 /*
52 TODO:
53 * Correct sprite-sprite priority? Currently this is strictly in the order of the sprites in the sprite list. However, there's an additional priority parameter which looks to split the sprites into 4 discrete sets with decreasing priority. In addition to the sprite-tilemap mixing the only way I can think to emulate this is how the hardware would work. Iterate over the sprite list 4 times rendering the sprites to a bitmap, and then mix each pixel against the tilemaps and other elements with comparable priority. This will be pretty slow though. Justification: The unknown priority bits are used to separate score/enemy bullets from ships/enemies from incidental effects. daraku appears to have a black, screen-filling srite which it uses for a flash immediately efore the screen fade/white flash when doing special moves. Currently obscured behind the other sprites.
54 * Perform tests on real hardware to document limits and remaining registers
55 ** Fix background line zoom to be pixel-correct. There must be an internal LUT.
56 ** Confirm existence of 4th tilemap layer on real hw by configuring it. No games ever get as far as enabling it.
57 ** Confirm sprite-sprite priority behaviours (two overlapping sprites in sprite list order, with differing priorities etc.)
58 ** Figure out why the sprite zoom is not 100% when we even have a lookup table. See TGM2 MT report. Possibly we should offset calcs by half a pixel (i.e. start in the middle of the first source pixel rather than corner).
59 ** Figure out screen size registers and xflip/yflip
60 * Hookup configurable sprite banks (not needed? reports of tgm2 dropping sprites when busy on real hw)
61 * Hookup screen size select
62 * Flip screen, located but not implemented. wait until tilemaps.
63 * The stuff might be converted to use the tilemaps once all the features is worked out ...
64 The only viable way to do this is to have one tilemap per bank (0x0a-0x20), and every pair of adjacent banks for large tilemaps. This is rather than having one per background layer, due to the line effects. Would also need to support all of the logic relating to alpha table blending, row and column scroll/zoom etc.
65 */
66
67 #include "emu.h"
68 #include "drawgfxt.ipp"
69 #include "includes/psikyosh.h"
70
71 #include <algorithm>
72
73 static constexpr u32 BG_TRANSPEN = 0x00ff00ff; // used for representing transparency in temporary bitmaps
74
75 //#define DEBUG_KEYS
76 //#define DEBUG_MESSAGE
77
78 // take ARGB pixel with stored alpha and blend in to RGB32 bitmap
79 #define PIXEL_OP_COPY_TRANSPEN_ARGBRENDER32(DEST, SOURCE) \
80 do \
81 { \
82 const rgb_t srcdata = (SOURCE); \
83 if (srcdata != transpen) \
84 (DEST) = alpha_blend_r32((DEST), srcdata, srcdata.a()); \
85 } \
86 while (0)
87 // take RGB pixel with separate alpha and blend in to RGB32 bitmap
88 #define PIXEL_OP_COPY_TRANSPEN_ALPHARENDER32(DEST, SOURCE) \
89 do \
90 { \
91 const u32 srcdata = (SOURCE); \
92 if (srcdata != transpen) \
93 (DEST) = alpha_blend_r32((DEST), srcdata, alpha); \
94 } \
95 while (0)
96 // take ARGB pixel with stored alpha and copy in to RGB32 bitmap, scipping BG_TRANSPEN
97 #define PIXEL_OP_COPY_TRANSPEN_RENDER32(DEST, SOURCE) \
98 do \
99 { \
100 const u32 srcdata = (SOURCE); \
101 if (srcdata != transpen) \
102 (DEST) = srcdata; \
103 } \
104 while (0)
105
pixop_transparent_priority(u8 source,u32 * dest,u16 * pri,const pen_t * pal,u16 z)106 static inline void pixop_transparent_priority(u8 source, u32 *dest, u16 *pri, const pen_t *pal, u16 z)
107 {
108 if (z >= *pri)
109 {
110 if (source != 0)
111 {
112 *dest = pal[source];
113 *pri = z;
114 }
115 }
116 }
117
pixop_transparent(u8 source,u32 * dest,const pen_t * pal)118 static inline void pixop_transparent(u8 source, u32 *dest, const pen_t *pal)
119 {
120 if (source != 0)
121 *dest = pal[source];
122 }
123
pixop_transparent_alpha_priority(u8 source,u32 * dest,u16 * pri,const pen_t * pal,u16 z,s16 alpha)124 static inline void pixop_transparent_alpha_priority(u8 source, u32 *dest, u16 *pri, const pen_t *pal, u16 z, s16 alpha)
125 {
126 if (z >= *pri)
127 {
128 if (source != 0)
129 {
130 *dest = alpha_blend_r32(*dest, pal[source], alpha);
131 *pri = z;
132 }
133 }
134 }
135
pixop_transparent_alpha(u8 source,u32 * dest,const pen_t * pal,s16 alpha)136 static inline void pixop_transparent_alpha(u8 source, u32 *dest, const pen_t *pal, s16 alpha)
137 {
138 if (source != 0)
139 *dest = alpha_blend_r32(*dest, pal[source], alpha);
140 }
141
pixop_transparent_alphatable_priority(u8 source,u32 * dest,u16 * pri,const pen_t * pal,u16 z,u8 * alphatable)142 static inline void pixop_transparent_alphatable_priority(u8 source, u32 *dest, u16 *pri, const pen_t *pal, u16 z, u8 *alphatable)
143 {
144 if (z >= *pri)
145 {
146 if (source != 0)
147 {
148 if (alphatable[source] == 0xff)
149 *dest = pal[source];
150 else
151 *dest = alpha_blend_r32(*dest, pal[source], alphatable[source]);
152
153 *pri = z;
154 }
155 }
156 }
157
pixop_transparent_alphatable(u8 source,u32 * dest,const pen_t * pal,u8 * alphatable)158 static inline void pixop_transparent_alphatable(u8 source, u32 *dest, const pen_t *pal, u8 *alphatable)
159 {
160 if (source != 0)
161 {
162 if (alphatable[source] == 0xff)
163 *dest = pal[source];
164 else
165 *dest = alpha_blend_r32(*dest, pal[source], alphatable[source]);
166 }
167 }
168 /*-------------------------------------------------
169 draw_scanline32_alpha - take an RGB-encoded u32
170 scanline and alpha-blend it into the destination bitmap
171 -------------------------------------------------*/
draw_scanline32_alpha(bitmap_rgb32 & bitmap,s32 destx,s32 desty,s32 length,const u32 * srcptr,int alpha)172 void psikyosh_state::draw_scanline32_alpha(bitmap_rgb32 &bitmap, s32 destx, s32 desty, s32 length, const u32 *srcptr, int alpha)
173 {
174 drawscanline_core(bitmap, destx, desty, length, srcptr, [alpha, transpen = BG_TRANSPEN](u32 &destp, const u32 &srcp) { PIXEL_OP_COPY_TRANSPEN_ALPHARENDER32(destp, srcp); });
175 }
176
177 /*-------------------------------------------------
178 draw_scanline32_argb - take an ARGB-encoded u32
179 scanline and alpha-blend it into the destination bitmap
180 -------------------------------------------------*/
draw_scanline32_argb(bitmap_rgb32 & bitmap,s32 destx,s32 desty,s32 length,const u32 * srcptr)181 void psikyosh_state::draw_scanline32_argb(bitmap_rgb32 &bitmap, s32 destx, s32 desty, s32 length, const u32 *srcptr)
182 {
183 drawscanline_core(bitmap, destx, desty, length, srcptr, [transpen = BG_TRANSPEN](u32 &destp, const u32 &srcp) { PIXEL_OP_COPY_TRANSPEN_ARGBRENDER32(destp, srcp); });
184 }
185
186 /*-------------------------------------------------
187 draw_scanline32_tranpens - take an RGB-encoded u32
188 scanline and copy it into the destination bitmap, testing for the special ARGB transpen
189 -------------------------------------------------*/
draw_scanline32_transpen(bitmap_rgb32 & bitmap,s32 destx,s32 desty,s32 length,const u32 * srcptr)190 void psikyosh_state::draw_scanline32_transpen(bitmap_rgb32 &bitmap, s32 destx, s32 desty, s32 length, const u32 *srcptr)
191 {
192 drawscanline_core(bitmap, destx, desty, length, srcptr, [transpen = BG_TRANSPEN](u32 &destp, const u32 &srcp) { PIXEL_OP_COPY_TRANSPEN_RENDER32(destp, srcp); });
193 }
194
195
196 /* Psikyo PS6406B */
197 /* --- BACKGROUNDS --- */
198
199 /* 'Normal' layers, no line/columnscroll. No per-line effects.
200 Zooming isn't supported just because it's not used and it would be slow */
draw_bglayer(u8 const layer,bitmap_rgb32 & bitmap,const rectangle & cliprect,u8 const req_pri)201 void psikyosh_state::draw_bglayer(u8 const layer, bitmap_rgb32 &bitmap, const rectangle &cliprect, u8 const req_pri)
202 {
203 assert(!BG_LINE(layer));
204
205 gfx_element *gfx = BG_DEPTH_8BPP(layer) ? m_gfxdecode->gfx(1) : m_gfxdecode->gfx(0);
206 u8 const size = BG_LARGE(layer) ? 32 : 16;
207 u16 const height = 16 * size;
208
209 u8 const regbank = BG_TYPE(layer);
210
211 u16 const scrollx = (m_spriteram[(regbank * 0x800) / 4 + 0x3f0 / 4 + (layer * 0x04) / 4] & 0x000001ff) >> 0;
212 u16 const scrolly = (m_spriteram[(regbank * 0x800) / 4 + 0x3f0 / 4 + (layer * 0x04) / 4] & 0x03ff0000) >> 16;
213
214 u8 const tilebank = (m_spriteram[(regbank * 0x800) / 4 + 0x7f0 / 4 + (layer * 0x04) / 4] & 0x000000ff) >> 0;
215 s16 alpha = (m_spriteram[(regbank * 0x800) / 4 + 0x7f0 / 4 + (layer * 0x04) / 4] & 0x00003f00) >> 8;
216 u8 const alphamap = (m_spriteram[(regbank * 0x800) / 4 + 0x7f0 / 4 + (layer * 0x04) / 4] & 0x00008000) >> 15;
217 u8 const zoom = (m_spriteram[(regbank * 0x800) / 4 + 0x7f0 / 4 + (layer * 0x04) / 4] & 0x00ff0000) >> 16;
218 u8 const pri = (m_spriteram[(regbank * 0x800) / 4 + 0x7f0 / 4 + (layer * 0x04) / 4] & 0xff000000) >> 24;
219
220 if (pri != req_pri)
221 return;
222
223 if (alphamap) /* alpha values are per-pen */
224 alpha = -1;
225 else
226 alpha = pal6bit(0x3f - alpha); /* 0x3f-0x00 maps to 0x00-0xff */
227
228 if (zoom)
229 popmessage("draw_bglayer() zoom not implemented\nContact MAMEDEV");
230
231 if ((tilebank >= 0x0a) && (tilebank <= 0x1f)) /* 20 banks of 0x800 bytes. filter garbage. */
232 {
233 u8 basey = ((0x400 - scrolly + cliprect.top() - 1) & (height - 1)) >> 4;
234 for (int sy = (cliprect.top() - 1) >> 4; sy <= cliprect.bottom() >> 4; sy++)
235 {
236 u8 basex = ((0x200 - scrollx + cliprect.left() - 1) & 0x1ff) >> 4;
237 for (int sx = (cliprect.left() - 1) >> 4; sx <= cliprect.right() >> 4; sx++)
238 {
239 u32 const tileno = (m_spriteram[(tilebank * 0x800) / 4 + (((basey & 0x1f) << 5) | (basex & 0x1f))] & 0x0007ffff);
240 u8 const colour = (m_spriteram[(tilebank * 0x800) / 4 + (((basey & 0x1f) << 5) | (basex & 0x1f))] & 0xff000000) >> 24;
241
242 gfx->alphatable(bitmap, cliprect, tileno, colour, 0, 0, (16 * sx) + (scrollx & 0xf), (16 * sy) + (scrolly & 0xf), alpha, m_alphatable.get()); /* normal */
243
244 basex++;
245 }
246 basey = ((basey + 1) & ((height >> 4) - 1));
247 }
248 }
249 }
250
251
252 /* populate bg_bitmap for the given bank if it's not already */
cache_bitmap(s16 const scanline,gfx_element * gfx,u8 const size,u8 const tilebank,s16 const alpha,u8 * last_bank)253 void psikyosh_state::cache_bitmap(s16 const scanline, gfx_element *gfx, u8 const size, u8 const tilebank, s16 const alpha, u8 *last_bank)
254 {
255 // test if the tile row is the cached one or not
256 u8 const sy = scanline / 16;
257
258 assert(sy >= 0 && sy < 32);
259
260 if (tilebank != last_bank[sy])
261 {
262 rectangle cliprect;
263 u16 const minsy = sy * 16;
264 u16 const maxsy = minsy + 16 - 1;
265
266 cliprect.set(0, m_bg_bitmap.width() - 1, minsy, maxsy );
267 cliprect &= m_bg_bitmap.cliprect();
268
269 m_bg_bitmap.fill(BG_TRANSPEN, cliprect);
270 u16 const height = size * 16;
271
272 u32 offs = 32 * sy;
273 for (int sx = 0; sx < 32; sx++)
274 {
275 u32 const tileno = (m_spriteram[(tilebank * 0x800) / 4 + offs] & 0x0007ffff);
276 u32 const colour = (m_spriteram[(tilebank * 0x800) / 4 + offs] & 0xff000000) >> 24;
277 int need_alpha = alpha < 0 ? -1 : 0xff; // store per-pen alpha in bitmap, otherwise don't since we'll need it per-line
278
279 if (tileno) // valid tile, but blank in all games?
280 gfx->alphastore(m_bg_bitmap, m_bg_bitmap.cliprect(), tileno, colour, 0, 0, (16 * sx) & 0x1ff, ((16 * sy) & (height - 1)), need_alpha, m_alphatable.get());
281
282 offs++;
283 }
284 last_bank[sy] = tilebank;
285 }
286 }
287
288
289 /* Row Scroll/Zoom and/or Column Zoom, has per-column Alpha/Bank/Priority
290 Bitmap is first rendered to an ARGB image, taking into account the per-pen alpha (if used).
291 From there we extract data as we compose the image, one scanline at a time, blending the ARGB pixels
292 into the RGB32 bitmap (with either the alpha information from the ARGB, or per-line alpha */
draw_bglayerscroll(u8 const layer,bitmap_rgb32 & bitmap,const rectangle & cliprect,u8 const req_pri)293 void psikyosh_state::draw_bglayerscroll(u8 const layer, bitmap_rgb32 &bitmap, const rectangle &cliprect, u8 const req_pri)
294 {
295 assert(BG_LINE(layer));
296
297 gfx_element *gfx = BG_DEPTH_8BPP(layer) ? m_gfxdecode->gfx(1) : m_gfxdecode->gfx(0);
298 u8 const size = BG_LARGE(layer) ? 32 : 16;
299 u16 const height = size * 16;
300
301 u8 const linebank = BG_TYPE(layer);
302
303 /* cache rendered bitmap */
304 u8 last_bank[32]; // corresponds to bank of bitmap in m_bg_bitmap. bg_bitmap is split into 16/32-rows of one-tile high each
305 for (auto & elem : last_bank) elem = -1;
306
307 int const scr_width = cliprect.width();
308 u32 *scroll_reg = &m_spriteram[(linebank * 0x800) / 4 + cliprect.top()];
309 u32 *pzab_reg = &m_spriteram[(linebank * 0x800) / 4 + cliprect.top() + 0x400 / 4]; // pri, zoom, alpha, bank
310
311 // now, for each scanline, check priority,
312 // extract the relevant scanline from the bitmap, after applying per-scanline vscroll,
313 // stretch it and scroll it into another buffer
314 // write it with alpha
315 for (int scanline = cliprect.top(); scanline <= cliprect.bottom(); scanline++)
316 {
317 u8 const pri = (*pzab_reg & 0xff000000) >> 24;
318
319 if (pri == req_pri)
320 {
321 u16 const scrollx = (*scroll_reg & 0x000001ff) >> 0;
322 u16 const scrolly = (*scroll_reg & 0x03ff0000) >> 16;
323
324 u8 const zoom = (*pzab_reg & 0x00ff0000) >> 16;
325 u8 const alphamap = (*pzab_reg & 0x00008000) >> 15;
326 s16 alpha = (*pzab_reg & 0x00003f00) >> 8;
327 u8 const tilebank = (*pzab_reg & 0x000000ff) >> 0;
328
329 if (alphamap) /* alpha values are per-pen */
330 alpha = -1;
331 else
332 alpha = pal6bit(0x3f - alpha);
333
334 if ((tilebank >= 0x0a) && (tilebank <= 0x1f)) /* 20 banks of 0x800 bytes. filter garbage. */
335 {
336 u16 const tilemap_scanline = (scanline - scrolly + 0x400) & (height - 1);
337
338 // render reelvant tiles to temp bitmap, assume bank changes infrequently/never. render alpha as per-pen
339 cache_bitmap(tilemap_scanline, gfx, size, tilebank, alpha, last_bank);
340
341 /* zoomy and 'wibbly' effects - extract an entire row from tilemap */
342 g_profiler.start(PROFILER_USER2);
343 u32 tilemap_line[32 * 16];
344 u32 scr_line[64 * 8];
345 std::copy_n(&m_bg_bitmap.pix(tilemap_scanline, 0), 0x200, tilemap_line);
346 g_profiler.stop();
347
348 /* slow bit, needs optimising. apply scrollx and zoomx by assembling scanline from row */
349 g_profiler.start(PROFILER_USER3);
350 if (zoom)
351 {
352 u16 const step = m_bg_zoom[zoom];
353 int jj = (0x400 << 10) + (step * cliprect.left()); // ensure +ve for mod
354 for (int ii = cliprect.left(); ii <= cliprect.right(); ii++)
355 {
356 scr_line[ii] = tilemap_line[((jj>>10) - scrollx) & 0x1ff];
357 jj += step;
358 }
359 }
360 else
361 {
362 for (int ii = cliprect.left(); ii <= cliprect.right(); ii++)
363 scr_line[ii] = tilemap_line[(ii - scrollx + 0x400) & 0x1ff];
364 }
365 g_profiler.stop();
366
367 /* blend line into output */
368 g_profiler.start(PROFILER_USER4);
369 if (alpha == 0xff)
370 draw_scanline32_transpen(bitmap, cliprect.left(), scanline, scr_width, &scr_line[cliprect.left()]);
371 else if (alpha > 0)
372 draw_scanline32_alpha(bitmap, cliprect.left(), scanline, scr_width, &scr_line[cliprect.left()], alpha);
373 else if (alpha < 0)
374 draw_scanline32_argb(bitmap, cliprect.left(), scanline, scr_width, &scr_line[cliprect.left()]);
375
376 g_profiler.stop();
377 }
378 }
379
380 scroll_reg++;
381 pzab_reg++;
382 }
383 }
384
385 /* 3 BG layers, with priority */
draw_background(bitmap_rgb32 & bitmap,const rectangle & cliprect,u8 const req_pri)386 void psikyosh_state::draw_background(bitmap_rgb32 &bitmap, const rectangle &cliprect, u8 const req_pri)
387 {
388 int i;
389
390 #ifdef DEBUG_KEYS
391 const int lay_keys[8] = {KEYCODE_Q, KEYCODE_W, KEYCODE_E, KEYCODE_R};
392 bool lay_debug = false;
393 for (i = 0; i <= 3; i++)
394 {
395 if (machine().input().code_pressed(lay_keys[i]))
396 lay_debug = true;
397
398 }
399 #endif
400
401 /* 1st-4th layers */
402 for (i = 0; i <= 3; i++)
403 {
404 #ifdef DEBUG_KEYS
405 if (lay_debug && !machine().input().code_pressed(lay_keys[i]))
406 continue;
407 #endif
408
409 if (!BG_LAYER_ENABLE(i))
410 continue;
411
412 if (BG_LINE(i)) /* per-line alpha, scroll, zoom etc. check the priority for the first scanline */
413 draw_bglayerscroll(i, bitmap, cliprect, req_pri);
414 else /* not per-line alpha, scroll, zoom etc. */
415 draw_bglayer(i, bitmap, cliprect, req_pri);
416
417 }
418 }
419
420 /* --- SPRITES --- */
421
422 /* 32-bit ONLY */
423 /* zoomx/y are pixel slopes in 6.10 fixed point, not scale. 0x400 is 1:1. drawgfx zoom algorithm doesn't produce identical results to hardware. */
424 /* high/wide are number of tiles wide/high up to max size of zoom_bitmap in either direction */
425 /* code is index of first tile and incremented across rows then down columns (adjusting for flip obviously) */
426 /* sx and sy is top-left of entire sprite regardless of flip */
427 /* Note that Level 5-4 of sbomberb boss is perfect! (Alpha blended zoomed) as well as S1945II logo */
428 /* pixel is only plotted if z is >= priority_buffer[y][x] */
psikyosh_drawgfxzoom(bitmap_rgb32 & dest_bmp,const rectangle & clip,gfx_element * gfx,u32 const code,u16 const color,u8 const flipx,u8 const flipy,s32 const offsx,s32 const offsy,s16 const alpha,u32 const zoomx,u32 const zoomy,u8 const wide,u8 const high,u16 const z)429 void psikyosh_state::psikyosh_drawgfxzoom(bitmap_rgb32 &dest_bmp, const rectangle &clip, gfx_element *gfx,
430 u32 const code, u16 const color, u8 const flipx, u8 const flipy, s32 const offsx, s32 const offsy,
431 s16 const alpha, u32 const zoomx, u32 const zoomy, u8 const wide, u8 const high, u16 const z)
432 {
433 rectangle myclip; /* Clip to screen boundaries */
434 int code_offset = 0;
435
436 if (!zoomx || !zoomy)
437 return;
438
439 g_profiler.start(PROFILER_DRAWGFX);
440
441 assert(dest_bmp.bpp() == 32);
442
443 /* KW 991012 -- Added code to force clip to bitmap boundary */
444 myclip = clip;
445 myclip &= dest_bmp.cliprect();
446
447 /* Temporary fallback for non-zoomed, needs z-buffer. Note that this is probably a lot slower than drawgfx.c, especially if there was separate code for flipped cases */
448 if (zoomx == 0x400 && zoomy == 0x400)
449 {
450 int xstart, ystart, xend, yend, xinc, yinc;
451
452 if (flipx) { xstart = wide - 1; xend = -1; xinc = -1; }
453 else { xstart = 0; xend = wide; xinc = +1; }
454
455 if (flipy) { ystart = high - 1; yend = -1; yinc = -1; }
456 else { ystart = 0; yend = high; yinc = +1; }
457
458 /* Start drawing */
459 if (gfx)
460 {
461 for (int ytile = ystart; ytile != yend; ytile += yinc)
462 {
463 for (int xtile = xstart; xtile != xend; xtile += xinc)
464 {
465 const pen_t *pal = &m_palette->pen(gfx->colorbase() + gfx->granularity() * (color % gfx->colors()));
466 const u8 *code_base = gfx->get_data((code + code_offset++) % gfx->elements());
467
468 int x_index_base, y_index;
469
470 if (flipx) { x_index_base = gfx->width() - 1; }
471 else { x_index_base = 0; }
472
473 if (flipy) { y_index = gfx->height()-1; }
474 else { y_index = 0; }
475
476 /* start coordinates */
477 int sx = offsx + xtile * gfx->width();
478 int sy = offsy + ytile * gfx->height();
479
480 /* end coordinates */
481 int ex = sx + gfx->width();
482 int ey = sy + gfx->height();
483
484 if (sx < myclip.left())
485 { /* clip left */
486 const int pixels = myclip.left() - sx;
487 sx += pixels;
488 x_index_base += xinc * pixels;
489 }
490 if (sy < myclip.top())
491 { /* clip top */
492 const int pixels = myclip.top() - sy;
493 sy += pixels;
494 y_index += yinc * pixels;
495 }
496 /* NS 980211 - fixed incorrect clipping */
497 if (ex > myclip.right() + 1)
498 { /* clip right */
499 const int pixels = ex - myclip.right() - 1;
500 ex -= pixels;
501 }
502 if (ey > myclip.bottom() + 1)
503 { /* clip bottom */
504 const int pixels = ey - myclip.bottom() - 1;
505 ey -= pixels;
506 }
507
508 if (ex > sx)
509 { /* skip if inner loop doesn't draw anything */
510
511 /* case 1: no alpha */
512 if (alpha == 0xff)
513 {
514 if (z > 0)
515 {
516 const u8 *source = code_base + (y_index) * gfx->rowbytes() + x_index_base;
517 u32 *dest = &dest_bmp.pix(sy, sx);
518 u16 *pri = &m_z_bitmap.pix(sy, sx);
519 const int src_modulo = yinc * gfx->rowbytes() - xinc * (ex - sx);
520 const int dst_modulo = dest_bmp.rowpixels() - (ex - sx);
521
522 for (int y = sy; y < ey; y++)
523 {
524 for (int x = sx; x < ex; x++)
525 {
526 pixop_transparent_priority(*source, dest, pri, pal, z);
527 dest++;
528 pri++;
529 source += xinc;
530 }
531 dest += dst_modulo;
532 pri += dst_modulo;
533 source += src_modulo;
534 }
535 }
536 else
537 {
538 const u8 *source = code_base + y_index * gfx->rowbytes() + x_index_base;
539 u32 *dest = &dest_bmp.pix(sy, sx);
540 const int src_modulo = yinc * gfx->rowbytes() - xinc * (ex - sx);
541 const int dst_modulo = dest_bmp.rowpixels() - (ex - sx);
542
543 for (int y = sy; y < ey; y++)
544 {
545 for (int x = sx; x < ex; x++)
546 {
547 pixop_transparent(*source, dest, pal);
548 dest++;
549 source += xinc;
550 }
551 dest += dst_modulo;
552 source += src_modulo;
553 }
554 }
555 }
556
557 /* case 6: alpha-blended */
558 else if (alpha >= 0)
559 {
560 if (z > 0)
561 {
562 const u8 *source = code_base + y_index * gfx->rowbytes() + x_index_base;
563 u32 *dest = &dest_bmp.pix(sy, sx);
564 u16 *pri = &m_z_bitmap.pix(sy, sx);
565 const int src_modulo = yinc * gfx->rowbytes() - xinc * (ex - sx);
566 const int dst_modulo = dest_bmp.rowpixels() - (ex - sx);
567
568 for (int y = sy; y < ey; y++)
569 {
570 for (int x = sx; x < ex; x++)
571 {
572 pixop_transparent_alpha_priority(*source, dest, pri, pal, z, alpha);
573 dest++;
574 pri++;
575 source += xinc;
576 }
577 dest += dst_modulo;
578 pri += dst_modulo;
579 source += src_modulo;
580 }
581 }
582 else
583 {
584 const u8 *source = code_base + y_index * gfx->rowbytes() + x_index_base;
585 u32 *dest = &dest_bmp.pix(sy, sx);
586 const int src_modulo = yinc * gfx->rowbytes() - xinc * (ex - sx);
587 const int dst_modulo = dest_bmp.rowpixels() - (ex - sx);
588
589 for (int y = sy; y < ey; y++)
590 {
591 for (int x = sx; x < ex; x++)
592 {
593 pixop_transparent_alpha(*source, dest, pal, alpha);
594 dest++;
595 source += xinc;
596 }
597 dest += dst_modulo;
598 source += src_modulo;
599 }
600 }
601 }
602
603 /* pjp 31/5/02 */
604 /* case 7: TRANSPARENCY_ALPHARANGE */
605 else
606 {
607 if (z > 0)
608 {
609 const u8 *source = code_base + y_index * gfx->rowbytes() + x_index_base;
610 u32 *dest = &dest_bmp.pix(sy, sx);
611 u16 *pri = &m_z_bitmap.pix(sy, sx);
612 const int src_modulo = yinc * gfx->rowbytes() - xinc * (ex - sx);
613 const int dst_modulo = dest_bmp.rowpixels() - (ex - sx);
614
615 for (int y = sy; y < ey; y++)
616 {
617 for (int x = sx; x < ex; x++)
618 {
619 pixop_transparent_alphatable_priority(*source, dest, pri, pal, z, m_alphatable.get());
620 dest++;
621 pri++;
622 source += xinc;
623 }
624 dest += dst_modulo;
625 pri += dst_modulo;
626 source += src_modulo;
627 }
628 }
629 else
630 {
631 const u8 *source = code_base + y_index * gfx->rowbytes() + x_index_base;
632 u32 *dest = &dest_bmp.pix(sy, sx);
633 const int src_modulo = yinc * gfx->rowbytes() - xinc * (ex - sx);
634 const int dst_modulo = dest_bmp.rowpixels() - (ex - sx);
635
636 for (int y = sy; y < ey; y++)
637 {
638 for (int x = sx; x < ex; x++)
639 {
640 pixop_transparent_alphatable(*source, dest, pal, m_alphatable.get());
641 dest++;
642 source += xinc;
643 }
644 dest += dst_modulo;
645 source += src_modulo;
646 }
647 }
648 }
649
650 }
651 }
652 }
653 }
654 }
655 else /* Zoomed */
656 {
657 /* Make a copy of complete sprite at top-left of zoom_bitmap */
658 /* Because I'm too slow to get it to work on the fly */
659 for (int ytile = 0; ytile < high; ytile++)
660 {
661 for (int xtile = 0; xtile < wide; xtile++)
662 {
663 const u8 *code_base = gfx->get_data((code + code_offset++) % gfx->elements());
664 for (int ypixel = 0; ypixel < gfx->height(); ypixel++)
665 {
666 const u8 *source = code_base + ypixel * gfx->rowbytes();
667 u8 *dest = &m_zoom_bitmap.pix(ypixel + ytile*gfx->height());
668
669 for (int xpixel = 0; xpixel < gfx->width(); xpixel++)
670 {
671 dest[xpixel + xtile*gfx->width()] = source[xpixel];
672 }
673 }
674 }
675 }
676
677 /* Start drawing */
678 if (gfx)
679 {
680 const pen_t *pal = &m_palette->pen(gfx->colorbase() + gfx->granularity() * (color % gfx->colors()));
681
682 const int sprite_screen_height = ((high * gfx->height() * (0x400 * 0x400)) / zoomy + 0x200) >> 10; /* Round up to nearest pixel */
683 const int sprite_screen_width = ((wide * gfx->width() * (0x400 * 0x400)) / zoomx + 0x200) >> 10;
684
685 if (sprite_screen_width && sprite_screen_height)
686 {
687 /* start coordinates */
688 int sx = offsx;
689 int sy = offsy;
690
691 /* end coordinates */
692 int ex = sx + sprite_screen_width;
693 int ey = sy + sprite_screen_height;
694
695 int x_index_base;
696 int y_index;
697
698 int dx, dy;
699
700 if (flipx) { x_index_base = (sprite_screen_width - 1) * zoomx; dx = -zoomx; }
701 else { x_index_base = 0; dx = zoomx; }
702
703 if (flipy) { y_index = (sprite_screen_height - 1) * zoomy; dy = -zoomy; }
704 else { y_index = 0; dy = zoomy; }
705
706 if (sx < myclip.left())
707 { /* clip left */
708 const int pixels = myclip.left() - sx;
709 sx += pixels;
710 x_index_base += pixels * dx;
711 }
712 if (sy < myclip.top())
713 { /* clip top */
714 const int pixels = myclip.top() - sy;
715 sy += pixels;
716 y_index += pixels * dy;
717 }
718 /* NS 980211 - fixed incorrect clipping */
719 if (ex > myclip.right() + 1)
720 { /* clip right */
721 const int pixels = ex-myclip.right() - 1;
722 ex -= pixels;
723 }
724 if (ey > myclip.bottom() + 1)
725 { /* clip bottom */
726 const int pixels = ey-myclip.bottom() - 1;
727 ey -= pixels;
728 }
729
730 if (ex > sx)
731 { /* skip if inner loop doesn't draw anything */
732
733 /* case 1: no alpha */
734 /* Note: adjusted to >>10 and draws from zoom_bitmap not gfx */
735 if (alpha == 0xff)
736 {
737 if (z > 0)
738 {
739 for (int y = sy; y < ey; y++)
740 {
741 const u8 *source = &m_zoom_bitmap.pix(y_index >> 10);
742 u32 *dest = &dest_bmp.pix(y);
743 u16 *pri = &m_z_bitmap.pix(y);
744
745 int x_index = x_index_base;
746 for (int x = sx; x < ex; x++)
747 {
748 pixop_transparent_priority(source[x_index >> 10], &dest[x], &pri[x], pal, z);
749 x_index += dx;
750 }
751
752 y_index += dy;
753 }
754 }
755 else
756 {
757 for (int y = sy; y < ey; y++)
758 {
759 const u8 *source = &m_zoom_bitmap.pix(y_index >> 10);
760 u32 *dest = &dest_bmp.pix(y);
761
762 int x_index = x_index_base;
763 for (int x = sx; x < ex; x++)
764 {
765 pixop_transparent(source[x_index >> 10], &dest[x], pal);
766 x_index += dx;
767 }
768
769 y_index += dy;
770 }
771 }
772 }
773
774 /* case 6: alpha-blended */
775 else if (alpha >= 0)
776 {
777 if (z > 0)
778 {
779 for (int y = sy; y < ey; y++)
780 {
781 const u8 *source = &m_zoom_bitmap.pix(y_index >> 10);
782 u32 *dest = &dest_bmp.pix(y);
783 u16 *pri = &m_z_bitmap.pix(y);
784
785 int x_index = x_index_base;
786 for (int x = sx; x < ex; x++)
787 {
788 pixop_transparent_alpha_priority(source[x_index >> 10], &dest[x], &pri[x], pal, z, alpha);
789 x_index += dx;
790 }
791
792 y_index += dy;
793 }
794 }
795 else
796 {
797 for (int y = sy; y < ey; y++)
798 {
799 const u8 *source = &m_zoom_bitmap.pix(y_index >> 10);
800 u32 *dest = &dest_bmp.pix(y);
801
802 int x_index = x_index_base;
803 for (int x = sx; x < ex; x++)
804 {
805 pixop_transparent_alpha(source[x_index >> 10], &dest[x], pal, alpha);
806 x_index += dx;
807 }
808
809 y_index += dy;
810 }
811 }
812 }
813
814 /* case 7: TRANSPARENCY_ALPHARANGE */
815 else
816 {
817 if (z > 0)
818 {
819 for (int y = sy; y < ey; y++)
820 {
821 const u8 *source = &m_zoom_bitmap.pix(y_index >> 10);
822 u32 *dest = &dest_bmp.pix(y);
823 u16 *pri = &m_z_bitmap.pix(y);
824
825 int x_index = x_index_base;
826 for (int x = sx; x < ex; x++)
827 {
828 pixop_transparent_alphatable_priority(source[x_index >> 10], &dest[x], &pri[x], pal, z, m_alphatable.get());
829 x_index += dx;
830 }
831
832 y_index += dy;
833 }
834 }
835 else
836 {
837 for (int y = sy; y < ey; y++)
838 {
839 const u8 *source = &m_zoom_bitmap.pix(y_index >> 10);
840 u32 *dest = &dest_bmp.pix(y);
841
842 int x_index = x_index_base;
843 for (int x = sx; x < ex; x++)
844 {
845 pixop_transparent_alphatable(source[x_index >> 10], &dest[x], pal, m_alphatable.get());
846 x_index += dx;
847 }
848
849 y_index += dy;
850 }
851 }
852 }
853 }
854 }
855 }
856 }
857 g_profiler.stop();
858 }
859
860
get_sprites()861 void psikyosh_state::get_sprites()
862 {
863 /*- Sprite Format 0x0000 - 0x37ff -**
864
865 0 ---- --yy yyyy yyyy | ---- --xx xxxx xxxx 1 F-?? hhhh ZZZZ ZZZZ | f-PP wwww zzzz zzzz
866 2 pppp pppp -aaa -nnn | nnnn nnnn nnnn nnnn 3 ---- ---- ---- ---- | ---- ---- ---- ----
867
868 y = ypos
869 x = xpos
870
871 h = height
872 w = width
873
874 F = flip (y)
875 f = flip (x)
876
877 Z = zoom (y)
878 z = zoom (x)
879
880 n = tile number
881
882 p = palette
883
884 a = alpha blending, selects which of the 8 alpha values in vid_regs[0-1] to use
885
886 P = priority
887 Points to a 4-bit entry in vid_regs[2] which provides a priority comparable with the bg layer's priorities.
888 However, sprite-sprite priority needs to be preserved.
889 daraku and soldivid only use the lsb
890
891 ? = unknown
892 Could be a sprite-sprite priority, tests seem to back this up
893
894 **- End Sprite Format -*/
895
896 const u16 *list = (u16 *)(m_spriteram.target()) + 0x3800 / 2;
897 u16 const listlen = 0x800 / 2;
898
899 struct sprite_t *sprite_ptr = m_spritelist.get();
900 u16 listcntr = 0;
901 while (listcntr < listlen)
902 {
903 u16 const listdat = list[BYTE_XOR_BE(listcntr)];
904 u16 const sprnum = (listdat & 0x03ff) * 4;
905
906 s32 ypos = (m_spriteram[sprnum + 0] & 0x03ff0000) >> 16;
907 s32 xpos = (m_spriteram[sprnum + 0] & 0x000003ff) >> 00;
908
909 if (ypos & 0x200) ypos -= 0x400;
910 if (xpos & 0x200) xpos -= 0x400;
911
912 sprite_ptr->ypos = ypos;
913 sprite_ptr->xpos = xpos;
914 sprite_ptr->high = ((m_spriteram[sprnum + 1] & 0x0f000000) >> 24) + 1;
915 sprite_ptr->wide = ((m_spriteram[sprnum + 1] & 0x00000f00) >> 8) + 1;
916
917 sprite_ptr->flpy = (m_spriteram[sprnum + 1] & 0x80000000) >> 31;
918 sprite_ptr->spr_pri = (m_spriteram[sprnum + 1] & 0x30000000) >> 28;
919 sprite_ptr->flpx = (m_spriteram[sprnum + 1] & 0x00008000) >> 15;
920 sprite_ptr->bg_pri = (m_spriteram[sprnum + 1] & 0x00003000) >> 12;
921
922 sprite_ptr->zoomy = (m_spriteram[sprnum + 1] & 0x00ff0000) >> 16;
923 sprite_ptr->zoomx = (m_spriteram[sprnum + 1] & 0x000000ff) >> 00;
924
925 sprite_ptr->tnum = (m_spriteram[sprnum + 2] & 0x0007ffff) >> 00;
926 sprite_ptr->dpth = (m_spriteram[sprnum + 2] & 0x00800000) >> 23;
927 sprite_ptr->colr = (m_spriteram[sprnum + 2] & 0xff000000) >> 24;
928
929 sprite_ptr->alpha = (m_spriteram[sprnum + 2] & 0x00700000) >> 20;
930
931 sprite_ptr++;
932 listcntr++;
933 if (listdat & 0x4000) break;
934 }
935 m_sprite_end = sprite_ptr;
936 }
937
draw_sprites(bitmap_rgb32 & bitmap,const rectangle & cliprect,u8 const req_pri)938 void psikyosh_state::draw_sprites(bitmap_rgb32 &bitmap, const rectangle &cliprect, u8 const req_pri)
939 {
940 const input_code spr_keys[8] = {KEYCODE_Y, KEYCODE_U, KEYCODE_I, KEYCODE_O};
941 bool spr_debug = false;
942 #ifdef DEBUG_KEYS
943 for (int i = 0; i <= 3; i++)
944 {
945 if (machine().input().code_pressed(spr_keys[i]))
946 spr_debug = true;
947
948 }
949 #endif
950
951 gfx_element *gfx;
952 const u16 *zoom_table = (u16 *)m_zoomram.target();
953 const u8 *alpha_table = (u8 *)&(m_vidregs[0]);
954
955 int i = 0;
956 struct sprite_t *sprite_ptr = m_spritelist.get();
957
958 while (sprite_ptr != m_sprite_end)
959 {
960 u8 const bg_pri = SPRITE_PRI(sprite_ptr->bg_pri);
961 // sprite vs backgrounds pri
962 if (bg_pri == req_pri)
963 {
964 u32 const zoomy = zoom_table[BYTE_XOR_BE(sprite_ptr->zoomy)];
965 u32 const zoomx = zoom_table[BYTE_XOR_BE(sprite_ptr->zoomx)];
966 s16 alpha = sprite_ptr->alpha;
967
968 u8 const alphamap = (alpha_table[BYTE4_XOR_BE(alpha)] & 0x80)? 1:0;
969 alpha = alpha_table[BYTE4_XOR_BE(alpha)] & 0x3f;
970
971 gfx = sprite_ptr->dpth ? m_gfxdecode->gfx(1) : m_gfxdecode->gfx(0);
972
973 if (alphamap) /* alpha values are per-pen */
974 alpha = -1;
975 else
976 alpha = pal6bit(0x3f - alpha); /* 0x3f-0x00 maps to 0x00-0xff */
977
978 if (!spr_debug || machine().input().code_pressed(spr_keys[sprite_ptr->spr_pri]))
979 {
980 /* start drawing */
981 if (zoomy && zoomx) /* Avoid division-by-zero when table contains 0 (Uninitialised/Bug) */
982 {
983 psikyosh_drawgfxzoom(bitmap, cliprect, gfx,
984 sprite_ptr->tnum, sprite_ptr->colr,
985 sprite_ptr->flpx, sprite_ptr->flpy,
986 sprite_ptr->xpos, sprite_ptr->ypos, alpha,
987 zoomx, zoomy, sprite_ptr->wide, sprite_ptr->high, i);
988 }
989 /* end drawing */
990 }
991 }
992 i++;
993 sprite_ptr++;
994 }
995 }
996
prelineblend(bitmap_rgb32 & bitmap,const rectangle & cliprect)997 void psikyosh_state::prelineblend(bitmap_rgb32 &bitmap, const rectangle &cliprect )
998 {
999 /* There are 224 values for pre-lineblending. Using one for every row currently */
1000 /* I suspect that it should be blended against black by the amount specified as
1001 gnbarich sets the 0x000000ff to 0x7f in test mode whilst the others use 0x80.
1002 tgm2 sets it to 0x00 on warning screen. Likely has no effect. */
1003 u8 const bank = (m_vidregs[7] & 0xff000000) >> 24; /* bank is always 8 (0x4000) except for daraku/soldivid */
1004 u32 const *linefill = &m_spriteram[(bank * 0x800) / 4]; /* Per row */
1005
1006 assert(bitmap.bpp() == 32);
1007
1008 g_profiler.start(PROFILER_USER8);
1009 for (int y = cliprect.top(); y <= cliprect.bottom(); y++)
1010 {
1011 u32 *dstline = &bitmap.pix(y);
1012
1013 /* linefill[y] & 0xff does what? */
1014 for (int x = cliprect.left(); x <= cliprect.right(); x++)
1015 dstline[x] = linefill[y] >> 8;
1016 }
1017 g_profiler.stop();
1018 }
1019
1020
postlineblend(bitmap_rgb32 & bitmap,const rectangle & cliprect,u8 const req_pri)1021 void psikyosh_state::postlineblend(bitmap_rgb32 &bitmap, const rectangle &cliprect, u8 const req_pri)
1022 {
1023 /* There are 224 values for post-lineblending. Using one for every row currently */
1024 u8 const bank = (m_vidregs[7] & 0xff000000) >> 24; /* bank is always 8 (i.e. 0x4000) except for daraku/soldivid */
1025 u32 const *lineblend = &m_spriteram[(bank * 0x800) / 4 + 0x400 / 4]; /* Per row */
1026
1027 assert(bitmap.bpp() == 32);
1028
1029 if ((m_vidregs[2] & 0xf) != req_pri)
1030 return;
1031
1032 g_profiler.start(PROFILER_USER8);
1033 for (int y = cliprect.top(); y <= cliprect.bottom(); y++)
1034 {
1035 u32 *dstline = &bitmap.pix(y);
1036
1037 if (lineblend[y] & 0x80) /* solid */
1038 {
1039 for (int x = cliprect.left(); x <= cliprect.right(); x++)
1040 dstline[x] = lineblend[y] >> 8;
1041 }
1042 else if (lineblend[y] & 0x7f) /* blended */
1043 {
1044 for (int x = cliprect.left(); x <= cliprect.right(); x++)
1045 dstline[x] = alpha_blend_r32(dstline[x], lineblend[y] >> 8, 2 * (lineblend[y] & 0x7f));
1046 }
1047 }
1048 g_profiler.stop();
1049 }
1050
1051
video_start()1052 void psikyosh_state::video_start()
1053 {
1054 m_spritelist = std::make_unique<struct sprite_t []>(0x800/2);
1055 m_sprite_end = m_spritelist.get();
1056
1057 m_screen->register_screen_bitmap(m_z_bitmap); /* z-buffer */
1058 m_zoom_bitmap.allocate(16*16, 16*16); /* temp buffer for assembling sprites */
1059 m_bg_bitmap.allocate(32*16, 32*16); /* temp buffer for assembling tilemaps */
1060 m_bg_zoom = std::make_unique<u16[]>(256);
1061 m_alphatable = std::make_unique<u8[]>(256);
1062
1063 m_gfxdecode->gfx(1)->set_granularity(16); /* 256 colour sprites with palette selectable on 16 colour boundaries */
1064
1065 /* Pens 0xc0-0xff have a gradient of alpha values associated with them */
1066 int i;
1067 for (i = 0; i < 0xc0; i++)
1068 {
1069 m_alphatable[i] = 0xff;
1070 }
1071 for (i = 0; i < 0x40; i++)
1072 {
1073 int const alpha = pal6bit(0x3f - i);
1074 m_alphatable[i + 0xc0] = alpha;
1075 }
1076
1077 /* precompute the background zoom table. verified against hardware.
1078 unsure of the precision, we use .10 fixed point like the sprites */
1079 for (i = 0; i < 0x100; i++)
1080 {
1081 m_bg_zoom[i] = (64 * 0x400) / (i + 64);
1082 }
1083
1084 save_item(NAME(m_z_bitmap));
1085 save_item(NAME(m_zoom_bitmap));
1086 save_item(NAME(m_bg_bitmap));
1087 save_pointer(NAME(m_bg_zoom), 256);
1088 }
1089
1090
screen_update(screen_device & screen,bitmap_rgb32 & bitmap,const rectangle & cliprect)1091 u32 psikyosh_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)/* Note the z-buffer on each sprite to get correct priority */
1092 {
1093 int i;
1094
1095 // show only the priority associated with a given keypress(s) and/or hide sprites/tilemaps
1096 int pri_debug = false;
1097 int sprites = true;
1098 int backgrounds = true;
1099 const input_code pri_keys[8] = {KEYCODE_Z, KEYCODE_X, KEYCODE_C, KEYCODE_V, KEYCODE_B, KEYCODE_N, KEYCODE_M, KEYCODE_K};
1100 #ifdef DEBUG_KEYS
1101 for (i = 0; i <= 7; i++)
1102 {
1103 if (machine().input().code_pressed(pri_keys[i]))
1104 pri_debug = true;
1105
1106 }
1107 if (machine().input().code_pressed(KEYCODE_G))
1108 sprites = false;
1109
1110 if (machine().input().code_pressed(KEYCODE_H))
1111 backgrounds = false;
1112
1113 #endif
1114
1115 #ifdef DEBUG_MESSAGE
1116 popmessage ("%08x %08x %08x %08x\n%08x %08x %08x %08x",
1117 m_vidregs[0], m_vidregs[1],
1118 m_vidregs[2], m_vidregs[3],
1119 m_vidregs[4], m_vidregs[5],
1120 m_vidregs[6], m_vidregs[7]);
1121 #endif
1122
1123 m_z_bitmap.fill(0, cliprect); /* z-buffer */
1124
1125 prelineblend(bitmap, cliprect); // fills screen
1126 for (i = 0; i <= 7; i++)
1127 {
1128 if (!pri_debug || machine().input().code_pressed(pri_keys[i]))
1129 {
1130 if (sprites)
1131 draw_sprites(bitmap, cliprect, i); // When same priority bg's have higher pri
1132
1133 if (backgrounds)
1134 draw_background(bitmap, cliprect, i);
1135
1136 postlineblend(bitmap, cliprect, i); // assume this has highest priority at same priority level
1137 }
1138 }
1139 return 0;
1140 }
1141
WRITE_LINE_MEMBER(psikyosh_state::screen_vblank)1142 WRITE_LINE_MEMBER(psikyosh_state::screen_vblank)
1143 {
1144 if (state)
1145 {
1146 get_sprites();
1147 }
1148 }
1149