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