1 /***************************************************************************
2 
3 	Ninja Gaiden / Tecmo Knights Video Hardware
4 
5 ***************************************************************************/
6 
7 #include "driver.h"
8 #include "vidhrdw/generic.h"
9 
10 data16_t *gaiden_videoram,*gaiden_videoram2,*gaiden_videoram3;
11 int gaiden_sprite_sizey;
12 int raiga_alpha;
13 
14 static struct tilemap *text_layer,*foreground,*background;
15 static struct mame_bitmap *sprite_bitmap, *tile_bitmap_bg, *tile_bitmap_fg;
16 
17 /***************************************************************************
18 
19   Callbacks for the TileMap code
20 
21 ***************************************************************************/
22 
get_bg_tile_info(int tile_index)23 static void get_bg_tile_info(int tile_index)
24 {
25 	UINT16 *videoram1 = &gaiden_videoram3[0x0800];
26 	UINT16 *videoram2 = gaiden_videoram3;
27 	SET_TILE_INFO(
28 			1,
29 			videoram1[tile_index] & 0x0fff,
30 			(videoram2[tile_index] & 0xf0) >> 4,
31 			0)
32 }
33 
get_fg_tile_info(int tile_index)34 static void get_fg_tile_info(int tile_index)
35 {
36 	UINT16 *videoram1 = &gaiden_videoram2[0x0800];
37 	UINT16 *videoram2 = gaiden_videoram2;
38 	SET_TILE_INFO(
39 			2,
40 			videoram1[tile_index] & 0x0fff,
41 			(videoram2[tile_index] & 0xf0) >> 4,
42 			0)
43 }
44 
get_fg_tile_info_raiga(int tile_index)45 static void get_fg_tile_info_raiga(int tile_index)
46 {
47 	UINT16 *videoram1 = &gaiden_videoram2[0x0800];
48 	UINT16 *videoram2 = gaiden_videoram2;
49 
50 	/* bit 3 controls blending */
51 	tile_info.priority = (videoram2[tile_index] & 0x08) >> 3;
52 
53 	SET_TILE_INFO(
54 			2,
55 			videoram1[tile_index] & 0x0fff,
56 			((videoram2[tile_index] & 0xf0) >> 4) | (tile_info.priority ? 0x80 : 0x00),
57 			0)
58 }
59 
get_tx_tile_info(int tile_index)60 static void get_tx_tile_info(int tile_index)
61 {
62 	UINT16 *videoram1 = &gaiden_videoram[0x0400];
63 	UINT16 *videoram2 = gaiden_videoram;
64 	SET_TILE_INFO(
65 			0,
66 			videoram1[tile_index] & 0x07ff,
67 			(videoram2[tile_index] & 0xf0) >> 4,
68 			0)
69 }
70 
71 
72 /***************************************************************************
73 
74   Start the video hardware emulation.
75 
76 ***************************************************************************/
77 
VIDEO_START(gaiden)78 VIDEO_START( gaiden )
79 {
80 	/* set up tile layers */
81 	background = tilemap_create(get_bg_tile_info, tilemap_scan_rows, TILEMAP_TRANSPARENT, 16, 16, 64, 32);
82 	foreground = tilemap_create(get_fg_tile_info, tilemap_scan_rows, TILEMAP_TRANSPARENT, 16, 16, 64, 32);
83 	text_layer = tilemap_create(get_tx_tile_info, tilemap_scan_rows, TILEMAP_TRANSPARENT,  8,  8, 32, 32);
84 
85 	if (!text_layer || !foreground || !background)
86 		return 1;
87 
88 	tilemap_set_transparent_pen(background, 0);
89 	tilemap_set_transparent_pen(foreground, 0);
90 	tilemap_set_transparent_pen(text_layer, 0);
91 
92 	return 0;
93 }
94 
VIDEO_START(raiga)95 VIDEO_START( raiga )
96 {
97 	/* set up tile layers */
98 	tile_bitmap_bg = auto_bitmap_alloc_depth(Machine->drv->screen_width, Machine->drv->screen_height, 16);
99 	tile_bitmap_fg = auto_bitmap_alloc_depth(Machine->drv->screen_width, Machine->drv->screen_height, 16);
100 
101 	if (!tile_bitmap_bg || !tile_bitmap_fg)
102 		return 1;
103 
104 	background = tilemap_create(get_bg_tile_info,	   tilemap_scan_rows,TILEMAP_TRANSPARENT,16,16,64,32);
105 	foreground = tilemap_create(get_fg_tile_info_raiga,tilemap_scan_rows,TILEMAP_TRANSPARENT,16,16,64,32);
106 	text_layer = tilemap_create(get_tx_tile_info,	   tilemap_scan_rows,TILEMAP_TRANSPARENT, 8, 8,32,32);
107 
108 	if (!text_layer || !foreground || !background)
109 		return 1;
110 
111 	tilemap_set_transparent_pen(background,0);
112 	tilemap_set_transparent_pen(foreground,0);
113 	tilemap_set_transparent_pen(text_layer,0);
114 
115 	/* set up sprites */
116 	sprite_bitmap = auto_bitmap_alloc_depth(Machine->drv->screen_width, Machine->drv->screen_height, 16);
117 
118 	if (!sprite_bitmap)
119 		return 1;
120 
121 	return 0;
122 }
123 
124 
125 
126 /***************************************************************************
127 
128   Memory handlers
129 
130 ***************************************************************************/
131 
WRITE16_HANDLER(gaiden_txscrollx_w)132 WRITE16_HANDLER( gaiden_txscrollx_w )
133 {
134 	static data16_t scroll;
135 	COMBINE_DATA(&scroll);
136 	tilemap_set_scrollx(text_layer, 0, scroll);
137 }
138 
WRITE16_HANDLER(gaiden_txscrolly_w)139 WRITE16_HANDLER( gaiden_txscrolly_w )
140 {
141 	static data16_t scroll;
142 	COMBINE_DATA(&scroll);
143 	tilemap_set_scrolly(text_layer, 0, scroll);
144 }
145 
WRITE16_HANDLER(gaiden_fgscrollx_w)146 WRITE16_HANDLER( gaiden_fgscrollx_w )
147 {
148 	static data16_t scroll;
149 	COMBINE_DATA(&scroll);
150 	tilemap_set_scrollx(foreground, 0, scroll);
151 }
152 
WRITE16_HANDLER(gaiden_fgscrolly_w)153 WRITE16_HANDLER( gaiden_fgscrolly_w )
154 {
155 	static data16_t scroll;
156 	COMBINE_DATA(&scroll);
157 	tilemap_set_scrolly(foreground, 0, scroll);
158 }
159 
WRITE16_HANDLER(gaiden_bgscrollx_w)160 WRITE16_HANDLER( gaiden_bgscrollx_w )
161 {
162 	static data16_t scroll;
163 	COMBINE_DATA(&scroll);
164 	tilemap_set_scrollx(background, 0, scroll);
165 }
166 
WRITE16_HANDLER(gaiden_bgscrolly_w)167 WRITE16_HANDLER( gaiden_bgscrolly_w )
168 {
169 	static data16_t scroll;
170 	COMBINE_DATA(&scroll);
171 	tilemap_set_scrolly(background, 0, scroll);
172 }
173 
WRITE16_HANDLER(gaiden_videoram3_w)174 WRITE16_HANDLER( gaiden_videoram3_w )
175 {
176 	int oldword = gaiden_videoram3[offset];
177 	COMBINE_DATA(&gaiden_videoram3[offset]);
178 	if (oldword != gaiden_videoram3[offset])
179 		tilemap_mark_tile_dirty(background,offset & 0x07ff);
180 }
181 
WRITE16_HANDLER(gaiden_flip_w)182 WRITE16_HANDLER( gaiden_flip_w )
183 {
184 	if (ACCESSING_LSB)
185 		flip_screen_set(data & 1);
186 }
187 
188 
READ16_HANDLER(gaiden_videoram3_r)189 READ16_HANDLER( gaiden_videoram3_r )
190 {
191    return gaiden_videoram3[offset];
192 }
193 
WRITE16_HANDLER(gaiden_videoram2_w)194 WRITE16_HANDLER( gaiden_videoram2_w )
195 {
196 	int oldword = gaiden_videoram2[offset];
197 	COMBINE_DATA(&gaiden_videoram2[offset]);
198 	if (oldword != gaiden_videoram2[offset])
199 		tilemap_mark_tile_dirty(foreground,offset & 0x07ff);
200 }
201 
READ16_HANDLER(gaiden_videoram2_r)202 READ16_HANDLER( gaiden_videoram2_r )
203 {
204    return gaiden_videoram2[offset];
205 }
206 
WRITE16_HANDLER(gaiden_videoram_w)207 WRITE16_HANDLER( gaiden_videoram_w )
208 {
209 	int oldword = gaiden_videoram[offset];
210 	COMBINE_DATA(&gaiden_videoram[offset]);
211 	if (oldword != gaiden_videoram[offset])
212 		tilemap_mark_tile_dirty(text_layer,offset & 0x03ff);
213 }
214 
215 
216 
217 /***************************************************************************
218 
219   Display refresh
220 
221 ***************************************************************************/
222 
223 /* mix & blend the paletted 16-bit tile and sprite bitmaps into an RGB 32-bit bitmap */
blendbitmaps(struct mame_bitmap * dest,struct mame_bitmap * src1,struct mame_bitmap * src2,struct mame_bitmap * src3,int sx,int sy,const struct rectangle * clip)224 static void blendbitmaps(
225 		struct mame_bitmap *dest,struct mame_bitmap *src1,struct mame_bitmap *src2,struct mame_bitmap *src3,
226 		int sx,int sy,const struct rectangle *clip)
227 {
228 	int ox;
229 	int oy;
230 	int ex;
231 	int ey;
232 
233 	/* check bounds */
234 	ox = sx;
235 	oy = sy;
236 
237 	ex = sx + src1->width - 1;
238 	if (sx < 0) sx = 0;
239 	if (sx < clip->min_x) sx = clip->min_x;
240 	if (ex >= dest->width) ex = dest->width - 1;
241 	if (ex > clip->max_x) ex = clip->max_x;
242 	if (sx > ex) return;
243 
244 	ey = sy + src1->height - 1;
245 	if (sy < 0) sy = 0;
246 	if (sy < clip->min_y) sy = clip->min_y;
247 	if (ey >= dest->height) ey = dest->height - 1;
248 	if (ey > clip->max_y) ey = clip->max_y;
249 	if (sy > ey) return;
250 
251 	{
252 		pen_t *paldata = Machine->pens;
253 		UINT32 *end;
254 
255 		UINT16 *sd1 = ((UINT16 *)src1->line[0]);								/* source data   */
256 		UINT16 *sd2 = ((UINT16 *)src2->line[0]);
257 		UINT16 *sd3 = ((UINT16 *)src3->line[0]);
258 
259 		int sw = ex-sx+1;														/* source width  */
260 		int sh = ey-sy+1;														/* source height */
261 		int sm = ((UINT16 *)src1->line[1]) - ((UINT16 *)src1->line[0]);			/* source modulo */
262 
263 		UINT32 *dd = ((UINT32 *)dest->line[sy]) + sx;							/* dest data     */
264 		int dm = ((UINT32 *)dest->line[1]) - ((UINT32 *)dest->line[0]);			/* dest modulo   */
265 
266 		sd1 += (sx-ox);
267 		sd1 += sm * (sy-oy);
268 		sd2 += (sx-ox);
269 		sd2 += sm * (sy-oy);
270 		sd3 += (sx-ox);
271 		sd3 += sm * (sy-oy);
272 
273 		sm -= sw;
274 		dm -= sw;
275 
276 		while (sh)
277 		{
278 
279 #define BLENDPIXEL(x)	if (sd3[x]) {														\
280 							if (sd2[x]) {													\
281 								dd[x] = paldata[sd2[x] | 0x0400] + paldata[sd3[x]];			\
282 							} else {														\
283 								dd[x] = paldata[sd1[x] | 0x0400] + paldata[sd3[x]];			\
284 							}																\
285 						} else {															\
286 							if (sd2[x]) {													\
287 								if (sd2[x] & 0x0800) {										\
288 									dd[x] = paldata[sd1[x] | 0x0400] + paldata[sd2[x]];		\
289 								} else {													\
290 									dd[x] = paldata[sd2[x]];								\
291 								}															\
292 							} else {														\
293 								dd[x] = paldata[sd1[x]];									\
294 							}																\
295 						}
296 
297 			end = dd + sw;
298 			while (dd <= end - 8)
299 			{
300 				BLENDPIXEL(0);
301 				BLENDPIXEL(1);
302 				BLENDPIXEL(2);
303 				BLENDPIXEL(3);
304 				BLENDPIXEL(4);
305 				BLENDPIXEL(5);
306 				BLENDPIXEL(6);
307 				BLENDPIXEL(7);
308 				dd += 8;
309 				sd1 += 8;
310 				sd2 += 8;
311 				sd3 += 8;
312 			}
313 			while (dd < end)
314 			{
315 				BLENDPIXEL(0);
316 				dd++;
317 				sd1++;
318 				sd2++;
319 				sd3++;
320 			}
321 			dd += dm;
322 			sd1 += sm;
323 			sd2 += sm;
324 			sd3 += sm;
325 			sh--;
326 
327 #undef BLENDPIXEL
328 
329 		}
330 	}
331 }
332 
333 /* sprite format:
334  *
335  *	word		bit					usage
336  * --------+-fedcba9876543210-+----------------
337  *    0    | ---------------x | flip x
338  *         | --------------x- | flip y
339  *         | -------------x-- | enable
340  *         | ----------x----- | blend
341  *         | --------xx------ | sprite-tile priority
342  *    1    | xxxxxxxxxxxxxxxx | number
343  *    2    | --------xxxx---- | palette
344  *         | --------------xx | size: 8x8, 16x16, 32x32, 64x64
345  *    3    | xxxxxxxxxxxxxxxx | y position
346  *    4    | xxxxxxxxxxxxxxxx | x position
347  *    5,6,7|                  | unused
348  */
349 
350 #define NUM_SPRITES 256
351 
draw_sprites(struct mame_bitmap * bitmap_bg,struct mame_bitmap * bitmap_fg,struct mame_bitmap * bitmap_sp,const struct rectangle * cliprect)352 static void draw_sprites(struct mame_bitmap *bitmap_bg, struct mame_bitmap *bitmap_fg, struct mame_bitmap *bitmap_sp, const struct rectangle *cliprect)
353 {
354 	const UINT8 layout[8][8] =
355 	{
356 		{ 0, 1, 4, 5,16,17,20,21},
357 		{ 2, 3, 6, 7,18,19,22,23},
358 		{ 8, 9,12,13,24,25,28,29},
359 		{10,11,14,15,26,27,30,31},
360 		{32,33,36,37,48,49,52,53},
361 		{34,35,38,39,50,51,54,55},
362 		{40,41,44,45,56,57,60,61},
363 		{42,43,46,47,58,59,62,63}
364 	};
365 
366 	const struct GfxElement *gfx = Machine->gfx[3];
367 	struct mame_bitmap *bitmap = bitmap_bg;
368 	const UINT16 *source = (NUM_SPRITES - 1) * 8 + spriteram16;
369 	const UINT8 blend_support = (bitmap_fg && bitmap_sp);
370 	int count = NUM_SPRITES;
371 
372 	/* draw all sprites from front to back */
373 	while (count--)
374 	{
375 		UINT32 attributes = source[0];
376 		UINT32 priority_mask;
377 		int col,row;
378 
379 		if (attributes & 0x04)
380 		{
381 			UINT32 priority = (attributes >> 6) & 3;
382 			UINT32 flipx = (attributes & 1);
383 			UINT32 flipy = (attributes & 2);
384 
385 			UINT32 color = source[2];
386 			UINT32 sizex = 1 << ((color >> 0) & 3);						/* 1,2,4,8 */
387 			UINT32 sizey = 1 << ((color >> gaiden_sprite_sizey) & 3);	/* 1,2,4,8 */
388 
389 			/* raiga needs something like this */
390 			UINT32 number = (source[1] & (sizex > 2 ? 0x7ff8 : 0x7ffc));
391 
392 			int ypos = source[3] & 0x01ff;
393 			int xpos = source[4] & 0x01ff;
394 
395 			if (!blend_support && (attributes & 0x20) && (cpu_getcurrentframe() & 1))
396 				goto skip_sprite;
397 
398 			color = (color >> 4) & 0x0f;
399 
400 			/* wraparound */
401 			if (xpos >= 256)
402 				xpos -= 512;
403 			if (ypos >= 256)
404 				ypos -= 512;
405 
406 			if (flip_screen)
407 			{
408 				flipx = !flipx;
409 				flipy = !flipy;
410 
411 				xpos = 256 - (8 * sizex) - xpos;
412 				ypos = 256 - (8 * sizey) - ypos;
413 
414 				if (xpos <= -256)
415 					xpos += 512;
416 				if (ypos <= -256)
417 					ypos += 512;
418 			}
419 
420 			/* bg: 1; fg:2; text: 4 */
421 			switch( priority )
422 			{
423 				default:
424 				case 0x0: priority_mask = 0;					break;
425 				case 0x1: priority_mask = 0xf0;					break;	/* obscured by text layer */
426 				case 0x2: priority_mask = 0xf0 | 0xcc;			break;	/* obscured by foreground */
427 				case 0x3: priority_mask = 0xf0 | 0xcc | 0xaa;	break;	/* obscured by bg and fg  */
428 			}
429 
430 			/* blending */
431 			if (blend_support && (attributes & 0x20))
432 			{
433 				color |= 0x80;
434 
435 				for (row = 0; row < sizey; row++)
436 				{
437 					for (col = 0; col < sizex; col++)
438 					{
439 						int sx = xpos + 8 * (flipx ? (sizex - 1 - col) : col);
440 						int sy = ypos + 8 * (flipy ? (sizey - 1 - row) : row);
441 
442 						pdrawgfx(bitmap_sp, gfx,
443 							number + layout[row][col],
444 							color,
445 							flipx, flipy,
446 							sx, sy,
447 							cliprect, TRANSPARENCY_PEN, 0,
448 							priority_mask);
449 					}
450 				}
451 			}
452 			else
453 			{
454 				if (blend_support)
455 					bitmap = (priority >= 2) ? bitmap_bg : bitmap_fg;
456 
457 				for (row = 0; row < sizey; row++)
458 				{
459 					for (col = 0; col < sizex; col++)
460 					{
461 						int sx = xpos + 8 * (flipx ? (sizex - 1 - col) : col);
462 						int sy = ypos + 8 * (flipy ? (sizey - 1 - row) : row);
463 
464 						pdrawgfx(bitmap, gfx,
465 							number + layout[row][col],
466 							color,
467 							flipx, flipy,
468 							sx, sy,
469 							cliprect, TRANSPARENCY_PEN, 0,
470 							priority_mask);
471 					}
472 				}
473 			}
474 		}
475 skip_sprite:
476 		source -= 8;
477 	}
478 }
479 
VIDEO_UPDATE(gaiden)480 VIDEO_UPDATE( gaiden )
481 {
482 	fillbitmap(priority_bitmap,                    0, cliprect);
483 	fillbitmap(bitmap,          Machine->pens[0x200], cliprect);
484 
485 	tilemap_draw(bitmap, cliprect, background, 0, 1);
486 	tilemap_draw(bitmap, cliprect, foreground, 0, 2);
487 	tilemap_draw(bitmap, cliprect, text_layer, 0, 4);
488 
489 	draw_sprites(bitmap, NULL, NULL, cliprect);
490 }
491 
VIDEO_UPDATE(raiga)492 VIDEO_UPDATE( raiga )
493 {
494 	fillbitmap(priority_bitmap,    0, cliprect);
495 
496 	fillbitmap(tile_bitmap_bg, 0x200, cliprect);
497 	fillbitmap(tile_bitmap_fg,     0, cliprect);
498 	fillbitmap(sprite_bitmap,      0, cliprect);
499 
500 	/* draw tilemaps into a 16-bit bitmap */
501 	tilemap_draw(tile_bitmap_bg, cliprect,background, 0, 1);
502 	tilemap_draw(tile_bitmap_fg, cliprect,foreground, 0, 2);
503 	/* draw the blended tiles at a lower priority
504 	   so sprites covered by them will still be drawn */
505 	tilemap_draw(tile_bitmap_fg, cliprect,foreground, 1, 0);
506 	tilemap_draw(tile_bitmap_fg, cliprect,text_layer, 0, 4);
507 
508 	/* draw sprites into a 16-bit bitmap */
509 	draw_sprites(tile_bitmap_bg, tile_bitmap_fg, sprite_bitmap, cliprect);
510 
511 	/* mix & blend the tilemaps and sprites into a 32-bit bitmap */
512 	blendbitmaps(bitmap, tile_bitmap_bg, tile_bitmap_fg, sprite_bitmap, 0, 0, cliprect);
513 }
514