1 // license:BSD-3-Clause
2 // copyright-holders:Nicola Salmoria
3 /***************************************************************************
4 
5   video.c
6 
7   Functions to emulate the video hardware of the machine.
8 
9 ***************************************************************************/
10 
11 #include "emu.h"
12 #include "video/resnet.h"
13 #include "includes/taitosj.h"
14 
15 
16 #define GLOBAL_FLIP_X           (*m_video_mode & 0x01)
17 #define GLOBAL_FLIP_Y           (*m_video_mode & 0x02)
18 #define SPRITE_RAM_PAGE_OFFSET  ((*m_video_mode & 0x04) ? 0x80 : 0x00)
19 #define SPRITES_ON              (*m_video_mode & 0x80)
20 #define TRANSPARENT_PEN         (0x40)
21 
22 
23 
24 static const int layer_enable_mask[3] = { 0x10, 0x20, 0x40 };
25 
26 
27 /***************************************************************************
28 
29   I call the three layers with the conventional names "front", "middle" and
30   "back", because that's their default order, but they can be arranged,
31   together with the sprites, in any order. The priority is selected by
32   register 0xd300, which works as follow:
33 
34   bits 0-3 go to A4-A7 of a 256x4 PROM
35   bit 4 selects D0/D1 or D2/D3 of the PROM
36   bit 5-7 n.c.
37   A0-A3 of the PROM is fed with a mask of the inactive layers
38   (i.e. all-zero) in the order sprites-front-middle-back
39   the 2-bit code which comes out from the PROM selects the layer
40   to display.
41 
42   Here is a dump of one of these PROMs; on the right is the resulting order
43   (s = sprites f = front m = middle b = back). Note that, in theory, the
44   PROM could encode some really funky priority schemes which couldn't be
45   reconducted to the simple layer order given here. Luckily, none of the
46   games seem to do that. Actually, all of them seem to use the same PROM,
47   with the exception of Wild Western.
48 
49                                                         d300 pri    d300 pri
50   00: 08 09 08 0A 00 05 00 0F 08 09 08 0A 00 05 00 0F |  00  sfmb    10  msfb
51   10: 08 09 08 0B 00 0D 00 0F 08 09 08 0A 00 05 00 0F |  01  sfbm    11  msbf
52   20: 08 0A 08 0A 04 05 00 0F 08 0A 08 0A 04 05 00 0F |  02  smfb    12  mfsb
53   30: 08 0A 08 0A 04 07 0C 0F 08 0A 08 0A 04 05 00 0F |  03  smbf    13  mfbs
54   40: 08 0B 08 0B 0C 0F 0C 0F 08 09 08 0A 00 05 00 0F |  04  sbfm    14  mbsf
55   50: 08 0B 08 0B 0C 0F 0C 0F 08 0A 08 0A 04 05 00 0F |  05  sbmf    15  mbfs
56   60: 0D 0D 0C 0E 0D 0D 0C 0F 01 05 00 0A 01 05 00 0F |  06  fsmb    16  bsfm
57   70: 0D 0D 0C 0F 0D 0D 0C 0F 01 09 00 0A 01 05 00 0F |  07  fsbm    17  bsmf
58   80: 0D 0D 0E 0E 0D 0D 0C 0F 05 05 02 0A 05 05 00 0F |  08  fmsb    18  bfsm
59   90: 0D 0D 0E 0E 0D 0D 0F 0F 05 05 0A 0A 05 05 00 0F |  09  fmbs    19  bfms
60   A0: 0D 0D 0F 0F 0D 0D 0F 0F 09 09 08 0A 01 05 00 0F |  0A  fbsm    1A  bmsf
61   B0: 0D 0D 0F 0F 0D 0D 0F 0F 09 09 0A 0A 05 05 00 0F |  0B  fbms    1B  bmfs
62   C0: 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F |  0C   -      1C   -
63   D0: 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F |  0D   -      1D   -
64   E0: 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F |  0E   -      1E   -
65   F0: 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F |  0F   -      1F   -
66 
67 ***************************************************************************/
68 
69 
70 
71 /***************************************************************************
72 
73   Convert the color PROMs into a more useable format.
74 
75   The Taito games don't have a color PROM. They use RAM to dynamically
76   create the palette. The resolution is 9 bit (3 bits per gun).
77 
78   The RAM is connected to the RGB output this way:
79 
80   bit 0 -- inverter -- 270 ohm resistor  -- RED
81   bit 7 -- inverter -- 470 ohm resistor  -- RED
82         -- inverter -- 1  kohm resistor  -- RED
83         -- inverter -- 270 ohm resistor  -- GREEN
84         -- inverter -- 470 ohm resistor  -- GREEN
85         -- inverter -- 1  kohm resistor  -- GREEN
86         -- inverter -- 270 ohm resistor  -- BLUE
87         -- inverter -- 470 ohm resistor  -- BLUE
88   bit 0 -- inverter -- 1  kohm resistor  -- BLUE
89 
90 ***************************************************************************/
91 
set_pens()92 void taitosj_state::set_pens()
93 {
94 	static const int resistances[3] = { 1000, 470, 270 };
95 	double rweights[3], gweights[3], bweights[3];
96 	int i;
97 
98 	/* compute the color output resistor weights */
99 	compute_resistor_weights(0, 255, -1.0,
100 			3, resistances, rweights, 0, 0,
101 			3, resistances, gweights, 0, 0,
102 			3, resistances, bweights, 0, 0);
103 
104 	for (i = 0; i < 0x40; i++)
105 	{
106 		int bit0, bit1, bit2;
107 		int r, g, b, val;
108 
109 		/* red component */
110 		val = m_paletteram[(i << 1) | 0x01];
111 		bit0 = (~val >> 6) & 0x01;
112 		bit1 = (~val >> 7) & 0x01;
113 		val = m_paletteram[(i << 1) | 0x00];
114 		bit2 = (~val >> 0) & 0x01;
115 		r = combine_weights(rweights, bit0, bit1, bit2);
116 
117 		/* green component */
118 		val = m_paletteram[(i << 1) | 0x01];
119 		bit0 = (~val >> 3) & 0x01;
120 		bit1 = (~val >> 4) & 0x01;
121 		bit2 = (~val >> 5) & 0x01;
122 		g = combine_weights(gweights, bit0, bit1, bit2);
123 
124 		/* blue component */
125 		val = m_paletteram[(i << 1) | 0x01];
126 		bit0 = (~val >> 0) & 0x01;
127 		bit1 = (~val >> 1) & 0x01;
128 		bit2 = (~val >> 2) & 0x01;
129 		b = combine_weights(bweights, bit0, bit1, bit2);
130 
131 		m_palette->set_pen_color(i, rgb_t(r, g, b));
132 	}
133 }
134 
135 /***************************************************************************
136 
137   Start the video hardware emulation.
138 
139 ***************************************************************************/
140 
compute_draw_order()141 void taitosj_state::compute_draw_order()
142 {
143 	int i;
144 	uint8_t *color_prom = memregion("proms")->base();
145 
146 	/* do a simple conversion of the PROM into layer priority order. Note that */
147 	/* this is a simplification, which assumes the PROM encodes a sensible priority */
148 	/* scheme. */
149 	for (i = 0; i < 32; i++)
150 	{
151 		int j;
152 		int mask = 0;   /* start with all four layers active, so we'll get the highest */
153 						/* priority one in the first loop */
154 		for (j = 3; j >= 0; j--)
155 		{
156 			int data = color_prom[0x10 * (i & 0x0f) + mask] & 0x0f;
157 
158 			if (i & 0x10)
159 				data = data >> 2;
160 			else
161 				data = data & 0x03;
162 
163 			mask |= (1 << data);    /* in next loop, we'll see which of the remaining */
164 									/* layers has top priority when this one is transparent */
165 			m_draw_order[i][j] = data;
166 		}
167 	}
168 }
169 
170 
video_start()171 void taitosj_state::video_start()
172 {
173 	int i;
174 
175 	m_sprite_layer_collbitmap1.allocate(16,16);
176 
177 	for (i = 0; i < 3; i++)
178 	{
179 		m_screen->register_screen_bitmap(m_layer_bitmap[i]);
180 		m_screen->register_screen_bitmap(m_sprite_layer_collbitmap2[i]);
181 	}
182 
183 	m_sprite_sprite_collbitmap1.allocate(32,32);
184 	m_sprite_sprite_collbitmap2.allocate(32,32);
185 
186 	m_gfxdecode->gfx(0)->set_source(m_characterram);
187 	m_gfxdecode->gfx(1)->set_source(m_characterram);
188 	m_gfxdecode->gfx(2)->set_source(m_characterram + 0x1800);
189 	m_gfxdecode->gfx(3)->set_source(m_characterram + 0x1800);
190 
191 	compute_draw_order();
192 }
193 
194 
195 
taitosj_gfxrom_r()196 uint8_t taitosj_state::taitosj_gfxrom_r()
197 {
198 	uint8_t ret;
199 
200 	offs_t offs = m_gfxpointer[0] | (m_gfxpointer[1] << 8);
201 
202 	if (offs < 0x8000)
203 		ret = memregion("gfx1")->base()[offs];
204 	else
205 		ret = 0;
206 
207 	offs = offs + 1;
208 
209 	m_gfxpointer[0] = offs & 0xff;
210 	m_gfxpointer[1] = offs >> 8;
211 
212 	return ret;
213 }
214 
215 
216 
taitosj_characterram_w(offs_t offset,uint8_t data)217 void taitosj_state::taitosj_characterram_w(offs_t offset, uint8_t data)
218 {
219 	if (m_characterram[offset] != data)
220 	{
221 		if (offset < 0x1800)
222 		{
223 			m_gfxdecode->gfx(0)->mark_dirty((offset / 8) & 0xff);
224 			m_gfxdecode->gfx(1)->mark_dirty((offset / 32) & 0x3f);
225 		}
226 		else
227 		{
228 			m_gfxdecode->gfx(2)->mark_dirty((offset / 8) & 0xff);
229 			m_gfxdecode->gfx(3)->mark_dirty((offset / 32) & 0x3f);
230 		}
231 
232 		m_characterram[offset] = data;
233 	}
234 }
235 
junglhbr_characterram_w(offs_t offset,uint8_t data)236 void taitosj_state::junglhbr_characterram_w(offs_t offset, uint8_t data)
237 {
238 	taitosj_characterram_w(offset, data ^ 0xfc);
239 }
240 
241 
taitosj_collision_reg_clear_w(uint8_t data)242 void taitosj_state::taitosj_collision_reg_clear_w(uint8_t data)
243 {
244 	m_collision_reg[0] = 0;
245 	m_collision_reg[1] = 0;
246 	m_collision_reg[2] = 0;
247 	m_collision_reg[3] = 0;
248 }
249 
250 
get_sprite_xy(uint8_t which,uint8_t * sx,uint8_t * sy)251 inline int taitosj_state::get_sprite_xy(uint8_t which, uint8_t* sx, uint8_t* sy)
252 {
253 	offs_t offs = which * 4;
254 
255 	*sx =       m_spriteram[SPRITE_RAM_PAGE_OFFSET + offs + 0] - 1;
256 	*sy = 240 - m_spriteram[SPRITE_RAM_PAGE_OFFSET + offs + 1];
257 
258 	return (*sy < 240);
259 }
260 
261 
get_sprite_gfx_element(uint8_t which)262 inline gfx_element * taitosj_state::get_sprite_gfx_element(uint8_t which)
263 {
264 	offs_t offs = which * 4;
265 
266 	return m_gfxdecode->gfx((m_spriteram[SPRITE_RAM_PAGE_OFFSET + offs + 3] & 0x40) ? 3 : 1);
267 }
268 
269 
check_sprite_sprite_bitpattern(int sx1,int sy1,int which1,int sx2,int sy2,int which2)270 int taitosj_state::check_sprite_sprite_bitpattern(int sx1, int sy1, int which1,int sx2, int sy2, int which2)
271 {
272 	int minx, miny, maxx = 16, maxy = 16;
273 
274 	offs_t offs1 = which1 * 4;
275 	offs_t offs2 = which2 * 4;
276 
277 	/* normalize coordinates to (0,0) and compute overlap */
278 	if (sx1 < sx2)
279 	{
280 		sx2 -= sx1;
281 		sx1 = 0;
282 		minx = sx2;
283 	}
284 	else
285 	{
286 		sx1 -= sx2;
287 		sx2 = 0;
288 		minx = sx1;
289 	}
290 
291 	if (sy1 < sy2)
292 	{
293 		sy2 -= sy1;
294 		sy1 = 0;
295 		miny = sy2;
296 	}
297 	else
298 	{
299 		sy1 -= sy2;
300 		sy2 = 0;
301 		miny = sy1;
302 	}
303 
304 	/* draw the sprites into separate bitmaps and check overlapping region */
305 	m_sprite_layer_collbitmap1.fill(TRANSPARENT_PEN);
306 		get_sprite_gfx_element(which1)->transpen(m_sprite_sprite_collbitmap1,m_sprite_sprite_collbitmap1.cliprect(),
307 			m_spriteram[SPRITE_RAM_PAGE_OFFSET + offs1 + 3] & 0x3f,
308 			0,
309 			m_spriteram[SPRITE_RAM_PAGE_OFFSET + offs1 + 2] & 0x01,
310 			m_spriteram[SPRITE_RAM_PAGE_OFFSET + offs1 + 2] & 0x02,
311 			sx1, sy1, 0);
312 
313 	m_sprite_sprite_collbitmap2.fill(TRANSPARENT_PEN);
314 		get_sprite_gfx_element(which2)->transpen(m_sprite_sprite_collbitmap2,m_sprite_sprite_collbitmap2.cliprect(),
315 			m_spriteram[SPRITE_RAM_PAGE_OFFSET + offs2 + 3] & 0x3f,
316 			0,
317 			m_spriteram[SPRITE_RAM_PAGE_OFFSET + offs2 + 2] & 0x01,
318 			m_spriteram[SPRITE_RAM_PAGE_OFFSET + offs2 + 2] & 0x02,
319 			sx2, sy2, 0);
320 
321 	for (int y = miny; y < maxy; y++)
322 		for (int x = minx; x < maxx; x++)
323 			if ((m_sprite_sprite_collbitmap1.pix(y, x) != TRANSPARENT_PEN) &&
324 				(m_sprite_sprite_collbitmap2.pix(y, x) != TRANSPARENT_PEN))
325 				return 1;  /* collided */
326 
327 	return 0;
328 }
329 
330 
check_sprite_sprite_collision()331 void taitosj_state::check_sprite_sprite_collision()
332 {
333 	if (SPRITES_ON)
334 	{
335 		int which1;
336 
337 		/* chech each pair of sprites */
338 		for (which1 = 0; which1 < 0x20; which1++)
339 		{
340 			int which2;
341 			uint8_t sx1, sy1;
342 
343 			if ((which1 >= 0x10) && (which1 <= 0x17)) continue; /* no sprites here */
344 
345 			if (!get_sprite_xy(which1, &sx1, &sy1)) continue;
346 
347 			for (which2 = which1 + 1; which2 < 0x20; which2++)
348 			{
349 				uint8_t sx2, sy2;
350 
351 				if ((which2 >= 0x10) && (which2 <= 0x17)) continue;   /* no sprites here */
352 
353 				if (!get_sprite_xy(which2, &sx2, &sy2)) continue;
354 
355 				/* quickly rule out any pairs that cannot be touching */
356 				if ((abs((int8_t)sx1 - (int8_t)sx2) < 16) &&
357 					(abs((int8_t)sy1 - (int8_t)sy2) < 16))
358 				{
359 					int reg;
360 
361 					if (!check_sprite_sprite_bitpattern(sx1, sy1, which1, sx2, sy2, which2))  continue;
362 
363 					/* mark sprite as collided */
364 					/* note that only the sprite with the higher number is marked */
365 					/* as collided. This is how the hardware works and required */
366 					/* by Pirate Pete to be able to finish the last round. */
367 
368 					/* the last sprite has to be moved at the start of the list */
369 					if (which2 == 0x1f)
370 					{
371 						reg = which1 >> 3;
372 						if (reg == 3)  reg = 2;
373 
374 						m_collision_reg[reg] |= (1 << (which1 & 0x07));
375 					}
376 					else
377 					{
378 						reg = which2 >> 3;
379 						if (reg == 3)  reg = 2;
380 
381 						m_collision_reg[reg] |= (1 << (which2 & 0x07));
382 					}
383 				}
384 			}
385 		}
386 	}
387 }
388 
389 
calculate_sprite_areas(int * sprites_on,rectangle * sprite_areas)390 void taitosj_state::calculate_sprite_areas(int *sprites_on, rectangle *sprite_areas)
391 {
392 	int which;
393 	int width = m_screen->width();
394 	int height = m_screen->height();
395 
396 	for (which = 0; which < 0x20; which++)
397 	{
398 		uint8_t sx, sy;
399 
400 		if ((which >= 0x10) && (which <= 0x17)) continue;   /* no sprites here */
401 
402 		if (get_sprite_xy(which, &sx, &sy))
403 		{
404 			int minx, miny, maxx, maxy;
405 
406 			if (GLOBAL_FLIP_X)
407 				sx = 238 - sx;
408 
409 			if (GLOBAL_FLIP_Y)
410 				sy = 242 - sy;
411 
412 			minx = sx;
413 			miny = sy;
414 
415 			maxx = minx + 15;
416 			maxy = miny + 15;
417 
418 			/* check for bitmap bounds to avoid illegal memory access */
419 			if (minx < 0) minx = 0;
420 			if (miny < 0) miny = 0;
421 			if (maxx >= width - 1)
422 				maxx = width - 1;
423 			if (maxy >= height - 1)
424 				maxy = height - 1;
425 
426 			sprite_areas[which].min_x = minx;
427 			sprite_areas[which].max_x = maxx;
428 			sprite_areas[which].min_y = miny;
429 			sprite_areas[which].max_y = maxy;
430 
431 			sprites_on[which] = 1;
432 		}
433 		/* sprite is off */
434 		else
435 			sprites_on[which] = 0;
436 	}
437 }
438 
439 
check_sprite_layer_bitpattern(int which,rectangle * sprite_areas)440 int taitosj_state::check_sprite_layer_bitpattern(int which, rectangle *sprite_areas)
441 {
442 	offs_t offs = which * 4;
443 	int result = 0;  /* no collisions */
444 
445 	int check_layer_1 = *m_video_mode & layer_enable_mask[0];
446 	int check_layer_2 = *m_video_mode & layer_enable_mask[1];
447 	int check_layer_3 = *m_video_mode & layer_enable_mask[2];
448 
449 	int minx = sprite_areas[which].min_x;
450 	int miny = sprite_areas[which].min_y;
451 	int maxx = sprite_areas[which].max_x + 1;
452 	int maxy = sprite_areas[which].max_y + 1;
453 
454 	int flip_x = (m_spriteram[SPRITE_RAM_PAGE_OFFSET + offs + 2] & 0x01) ^ GLOBAL_FLIP_X;
455 	int flip_y = (m_spriteram[SPRITE_RAM_PAGE_OFFSET + offs + 2] & 0x02) ^ GLOBAL_FLIP_Y;
456 
457 	/* draw sprite into a bitmap and check if layers collide */
458 	m_sprite_layer_collbitmap1.fill(TRANSPARENT_PEN);
459 	get_sprite_gfx_element(which)->transpen(m_sprite_layer_collbitmap1,m_sprite_layer_collbitmap1.cliprect(),
460 			m_spriteram[SPRITE_RAM_PAGE_OFFSET + offs + 3] & 0x3f,
461 			0,
462 			flip_x, flip_y,
463 			0,0,0);
464 
465 	for (int y = miny; y < maxy; y++)
466 		for (int x = minx; x < maxx; x++)
467 			if (m_sprite_layer_collbitmap1.pix(y - miny, x - minx) != TRANSPARENT_PEN) /* is there anything to check for ? */
468 			{
469 				if (check_layer_1 && (m_sprite_layer_collbitmap2[0].pix(y, x) != TRANSPARENT_PEN))
470 					result |= 0x01;  /* collided with layer 1 */
471 
472 				if (check_layer_2 && (m_sprite_layer_collbitmap2[1].pix(y, x) != TRANSPARENT_PEN))
473 					result |= 0x02;  /* collided with layer 2 */
474 
475 				if (check_layer_3 && (m_sprite_layer_collbitmap2[2].pix(y, x) != TRANSPARENT_PEN))
476 					result |= 0x04;  /* collided with layer 3 */
477 			}
478 
479 	return result;
480 }
481 
482 
check_sprite_layer_collision(int * sprites_on,rectangle * sprite_areas)483 void taitosj_state::check_sprite_layer_collision(int *sprites_on, rectangle *sprite_areas)
484 {
485 	if (SPRITES_ON)
486 	{
487 		/* check each sprite */
488 		for (int which = 0; which < 0x20; which++)
489 		{
490 			if ((which >= 0x10) && (which <= 0x17)) continue;   /* no sprites here */
491 
492 			if (sprites_on[which])
493 				m_collision_reg[3] |= check_sprite_layer_bitpattern(which, sprite_areas);
494 		}
495 	}
496 }
497 
498 
draw_layers()499 void taitosj_state::draw_layers()
500 {
501 	offs_t offs;
502 
503 	m_layer_bitmap[0].fill(TRANSPARENT_PEN);
504 	m_layer_bitmap[1].fill(TRANSPARENT_PEN);
505 	m_layer_bitmap[2].fill(TRANSPARENT_PEN);
506 
507 	for (offs = 0; offs < 0x0400; offs++)
508 	{
509 		int sx = offs % 32;
510 		int sy = offs / 32;
511 
512 		if (GLOBAL_FLIP_X) sx = 31 - sx;
513 		if (GLOBAL_FLIP_Y) sy = 31 - sy;
514 
515 		m_gfxdecode->gfx(m_colorbank[0] & 0x08 ? 2 : 0)->transpen(m_layer_bitmap[0],m_layer_bitmap[0].cliprect(),
516 				m_videoram_1[offs],
517 				m_colorbank[0] & 0x07,
518 				GLOBAL_FLIP_X,GLOBAL_FLIP_Y,
519 				8*sx,8*sy,0);
520 
521 		m_gfxdecode->gfx(m_colorbank[0] & 0x80 ? 2 : 0)->transpen(m_layer_bitmap[1],m_layer_bitmap[1].cliprect(),
522 				m_videoram_2[offs],
523 				(m_colorbank[0] >> 4) & 0x07,
524 				GLOBAL_FLIP_X,GLOBAL_FLIP_Y,
525 				8*sx,8*sy,0);
526 
527 		m_gfxdecode->gfx(m_colorbank[1] & 0x08 ? 2 : 0)->transpen(m_layer_bitmap[2],m_layer_bitmap[2].cliprect(),
528 				m_videoram_3[offs],
529 				m_colorbank[1] & 0x07,
530 				GLOBAL_FLIP_X,GLOBAL_FLIP_Y,
531 				8*sx,8*sy,0);
532 	}
533 }
534 
535 
draw_sprites(bitmap_ind16 & bitmap)536 void taitosj_state::draw_sprites(bitmap_ind16 &bitmap)
537 {
538 	/*
539 	   sprite visibility area is missing 4 pixels from the sides, surely to reduce
540 	   wraparound side effects. This was verified on a real Elevator Action.
541 	   Note that the clipping is asymmetrical. This matches the real thing.
542 	   I'm not sure of what should happen when the screen is flipped, though.
543 	 */
544 	const rectangle spritevisiblearea(0*8+3, 32*8-1-1, 2*8, 30*8-1);
545 	const rectangle spritevisibleareaflip(0*8+1, 32*8-3-1, 2*8, 30*8-1);
546 
547 	if (SPRITES_ON)
548 	{
549 		int sprite;
550 
551 		/* drawing order is a bit strange. The last sprite has to be moved at the start of the list. */
552 		for (sprite = 0x1f; sprite >= 0; sprite--)
553 		{
554 			uint8_t sx, sy;
555 
556 			int which = (sprite - 1) & 0x1f;    /* move last sprite at the head of the list */
557 			offs_t offs = which * 4;
558 
559 			if ((which >= 0x10) && (which <= 0x17)) continue;   /* no sprites here */
560 
561 			if (get_sprite_xy(which, &sx, &sy))
562 			{
563 				int code = m_spriteram[SPRITE_RAM_PAGE_OFFSET + offs + 3] & 0x3f;
564 				int color = 2 * ((m_colorbank[1] >> 4) & 0x03) + ((m_spriteram[SPRITE_RAM_PAGE_OFFSET + offs + 2] >> 2) & 0x01);
565 				int flip_x = m_spriteram[SPRITE_RAM_PAGE_OFFSET + offs + 2] & 0x01;
566 				int flip_y = m_spriteram[SPRITE_RAM_PAGE_OFFSET + offs + 2] & 0x02;
567 
568 				if (GLOBAL_FLIP_X)
569 				{
570 					sx = 238 - sx;
571 					flip_x = !flip_x;
572 				}
573 
574 				if (GLOBAL_FLIP_Y)
575 				{
576 					sy = 242 - sy;
577 					flip_y = !flip_y;
578 				}
579 
580 				get_sprite_gfx_element(which)->transpen(bitmap,GLOBAL_FLIP_X ? spritevisibleareaflip : spritevisiblearea, code, color,
581 						flip_x, flip_y, sx, sy,0);
582 
583 				/* draw with wrap around. The horizontal games (eg. sfposeid) need this */
584 				get_sprite_gfx_element(which)->transpen(bitmap,GLOBAL_FLIP_X ? spritevisibleareaflip : spritevisiblearea, code, color,
585 						flip_x, flip_y, sx - 0x100, sy,0);
586 			}
587 		}
588 	}
589 }
590 
591 
taitosj_copy_layer(bitmap_ind16 & bitmap,const rectangle & cliprect,int which,int * sprites_on,rectangle * sprite_areas)592 void taitosj_state::taitosj_copy_layer(bitmap_ind16 &bitmap, const rectangle &cliprect,int which, int *sprites_on, rectangle *sprite_areas)
593 {
594 	static const int fudge1[3] = { 3,  1, -1 };
595 	static const int fudge2[3] = { 8, 10, 12 };
596 
597 	if (*m_video_mode & layer_enable_mask[which])
598 	{
599 		int i, scrollx, scrolly[32];
600 
601 		scrollx = m_scroll[2 * which];
602 
603 		if (GLOBAL_FLIP_X)
604 			scrollx =  (scrollx & 0xf8) + ((scrollx + fudge1[which]) & 7) + fudge2[which];
605 		else
606 			scrollx = -(scrollx & 0xf8) + ((scrollx + fudge1[which]) & 7) + fudge2[which];
607 
608 		if (GLOBAL_FLIP_Y)
609 			for (i = 0;i < 32;i++)
610 				scrolly[31 - i] =  m_colscrolly[32 * which + i] + m_scroll[2 * which + 1];
611 		else
612 			for (i = 0;i < 32;i++)
613 				scrolly[i]      = -m_colscrolly[32 * which + i] - m_scroll[2 * which + 1];
614 
615 		copyscrollbitmap_trans(bitmap, m_layer_bitmap[which], 1, &scrollx, 32, scrolly, cliprect, TRANSPARENT_PEN);
616 
617 		/* store parts covered with sprites for sprites/layers collision detection */
618 		for (i = 0; i < 0x20; i++)
619 		{
620 			if ((i >= 0x10) && (i <= 0x17)) continue; /* no sprites here */
621 
622 			if (sprites_on[i])
623 				copyscrollbitmap(m_sprite_layer_collbitmap2[which], m_layer_bitmap[which], 1, &scrollx, 32, scrolly, sprite_areas[i]);
624 		}
625 	}
626 }
627 
628 
kikstart_copy_layer(bitmap_ind16 & bitmap,const rectangle & cliprect,int which,int * sprites_on,rectangle * sprite_areas)629 void taitosj_state::kikstart_copy_layer(bitmap_ind16 &bitmap, const rectangle &cliprect,int which, int *sprites_on, rectangle *sprite_areas)
630 {
631 	if (*m_video_mode & layer_enable_mask[which])
632 	{
633 		int i, scrolly, scrollx[32 * 8];
634 
635 		for (i = 1; i < 32*8; i++)  /* 1-255 ! */
636 			if (GLOBAL_FLIP_Y)
637 				switch (which)
638 				{
639 				case 0: scrollx[32 * 8 - i] = 0 ;break;
640 				case 1: scrollx[32 * 8 - i] = m_kikstart_scrollram[i] + ((m_scroll[2 * which] + 0x0a) & 0xff);break;
641 				case 2: scrollx[32 * 8 - i] = m_kikstart_scrollram[0x100 + i] + ((m_scroll[2 * which] + 0xc) & 0xff);break;
642 				}
643 			else
644 				switch (which)
645 				{
646 				case 0: scrollx[i] = 0 ;break;
647 				case 1: scrollx[i] = 0xff - m_kikstart_scrollram[i - 1] - ((m_scroll[2 * which] - 0x10) & 0xff);break;
648 				case 2: scrollx[i] = 0xff - m_kikstart_scrollram[0x100 + i - 1] - ((m_scroll[2 * which] - 0x12) & 0xff);break;
649 				}
650 
651 		scrolly = m_scroll[2 * which + 1];   /* always 0 */
652 		copyscrollbitmap_trans(bitmap, m_layer_bitmap[which], 32 * 8, scrollx, 1, &scrolly, cliprect, TRANSPARENT_PEN);
653 
654 		/* store parts covered with sprites for sprites/layers collision detection */
655 		for (i = 0; i < 0x20; i++)
656 		{
657 			if ((i >= 0x10) && (i <= 0x17)) continue; /* no sprites here */
658 
659 			if (sprites_on[i])
660 				copyscrollbitmap(m_sprite_layer_collbitmap2[which], m_layer_bitmap[which], 32 * 8, scrollx, 1, &scrolly, sprite_areas[i]);
661 		}
662 	}
663 }
664 
665 
copy_layer(bitmap_ind16 & bitmap,const rectangle & cliprect,copy_layer_func_t copy_layer_func,int which,int * sprites_on,rectangle * sprite_areas)666 void taitosj_state::copy_layer(bitmap_ind16 &bitmap, const rectangle &cliprect,copy_layer_func_t copy_layer_func, int which, int *sprites_on, rectangle *sprite_areas)
667 {
668 	if (which == 0)
669 		draw_sprites(bitmap);
670 	else
671 		(this->*copy_layer_func)(bitmap, cliprect, which - 1, sprites_on, sprite_areas);
672 }
673 
674 
copy_layers(bitmap_ind16 & bitmap,const rectangle & cliprect,copy_layer_func_t copy_layer_func,int * sprites_on,rectangle * sprite_areas)675 void taitosj_state::copy_layers(bitmap_ind16 &bitmap, const rectangle &cliprect,copy_layer_func_t copy_layer_func, int *sprites_on, rectangle *sprite_areas)
676 {
677 	int i = 0;
678 
679 	/* fill the screen with the background color */
680 	bitmap.fill(8 * (m_colorbank[1] & 0x07), cliprect);
681 
682 	for (i = 0; i < 4; i++)
683 	{
684 		int which = m_draw_order[*m_video_priority & 0x1f][i];
685 
686 		copy_layer(bitmap, cliprect, copy_layer_func, which, sprites_on, sprite_areas);
687 	}
688 }
689 
690 
check_collision(int * sprites_on,rectangle * sprite_areas)691 void taitosj_state::check_collision(int *sprites_on, rectangle *sprite_areas)
692 {
693 	check_sprite_sprite_collision();
694 
695 	check_sprite_layer_collision(sprites_on, sprite_areas);
696 
697 	/*check_layer_layer_collision();*/  /* not implemented !!! */
698 }
699 
700 
video_update_common(bitmap_ind16 & bitmap,const rectangle & cliprect,copy_layer_func_t copy_layer_func)701 int taitosj_state::video_update_common(bitmap_ind16 &bitmap, const rectangle &cliprect, copy_layer_func_t copy_layer_func)
702 {
703 	int sprites_on[0x20];           /* 1 if sprite is active */
704 	rectangle sprite_areas[0x20];   /* areas on bitmap (sprite locations) */
705 
706 	set_pens();
707 
708 	draw_layers();
709 
710 	calculate_sprite_areas(sprites_on, sprite_areas);
711 
712 	copy_layers(bitmap, cliprect, copy_layer_func, sprites_on, sprite_areas);
713 
714 	/*check_sprite_layer_collision() uses drawn bitmaps, so it must me called _AFTER_ draw_layers() */
715 	check_collision(sprites_on, sprite_areas);
716 
717 	return 0;
718 }
719 
720 
screen_update_taitosj(screen_device & screen,bitmap_ind16 & bitmap,const rectangle & cliprect)721 uint32_t taitosj_state::screen_update_taitosj(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
722 {
723 	return video_update_common(bitmap, cliprect, &taitosj_state::taitosj_copy_layer);
724 }
725 
726 
screen_update_kikstart(screen_device & screen,bitmap_ind16 & bitmap,const rectangle & cliprect)727 uint32_t taitosj_state::screen_update_kikstart(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
728 {
729 	return video_update_common(bitmap, cliprect, &taitosj_state::kikstart_copy_layer);
730 }
731