⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 system16.c

📁 这个是延伸mame的在wince平台下的游戏模拟器的代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/***************************************************************************

Sega System 16 Video Hardware

There are three logical layers of tile-mapped graphics:
- playfield background layer (bg_scroll_x, bg_scroll_y)
- playfield foreground layer (fg_scroll_x, fg_scroll_y)
- fixed text layer (sys16_textram)

Each scrolling layer (foreground, background) is an arrangement
of 4 pages selected from 16 available pages, laid out as follows:

	Page0  Page1
	Page2  Page3

A page is an arrangement of 8x8 tiles, 64 tiles wide, and 32 tiles high.

sys16_tileram contains data describing the 16 selectable pages.

Sprites are drawn between layers, depending on their priority.

Each tile in the foreground layer has a priority bit, that controls
whether it is drawn in front or behind priority 1 sprites.

The rendering order is, from back to front:

	background playfield layer
	sprites (priority 0)
	foreground playfield layer (low priority)
	sprites (priority 1)
	foreground playfield layer (high priority)
	sprites (priority 2)
	fixed text layer
	sprites (priority 3)

***************************************************************************

The following optimizations are used:

- totally obscured tiles are skipped while drawing the background

- totally transparent tiles are skipped when drawing the foreground

- a fatbitmask (one byte per pixel) is used to blit the non-transparent tiles
  (thanks to Neil Bradley and Nicola Salmoria for suggesting this)

***************************************************************************/

#include "driver.h"
#include "vidhrdw/generic.h"
#include "vidhrdw/s16sprit.c"

#define TILEMAP_ROWS 32
#define TILEMAP_COLS 64
#define TILEMAP_HEIGHT (TILEMAP_ROWS*8)
#define TILEMAP_WIDTH (TILEMAP_COLS*8)
#define MAX_SPRITES 64
#define SCREENWIDTH 320
#define SCREENHEIGHT 224
#define SCREENCOLS (SCREENWIDTH/8)

static unsigned long screenwise_opacity[SCREENCOLS];
/*
	each unsigned long corresponds to a vertical strip of 8x8 tiles:
	(screenwise_opacity[col]>>row)&1
*/
static unsigned char fg_transparency[4][2][TILEMAP_ROWS][TILEMAP_COLS];
/*
	fg_transparency[quadrant][priority][row][col] = 1 or 0
*/

/* video ram */
extern unsigned char *sys16_textram;
extern unsigned char *sys16_spriteram;
extern unsigned char *sys16_tileram; /* contains tilemaps for 16 pages */

/* video driver constants (potentially different for each game) */
int sys16_spritesystem;
int sys16_sprxoffset;
int *sys16_obj_bank;
extern void (* sys16_update_proc)( void );

/* video registers */
int sys16_tile_bank1;
int sys16_tile_bank0;
int sys16_refreshenable;
int sys16_bg_scrollx, sys16_bg_scrolly;
int sys16_bg_page[4];
int sys16_fg_scrollx, sys16_fg_scrolly;
int sys16_fg_page[4];

/* cached graphics layers */
static int old_bg_page[4];
static int old_fg_page[4];
static unsigned short *fg_page_buffer[4];
static unsigned short *bg_page_buffer[4];
static struct osd_bitmap *bg_bitmap[4];
static struct osd_bitmap *fg_bitmap[4];
static struct osd_bitmap *fg_fatmask[4];

/***************************************************************************/

#define min(a,b) ((a<b)?a:b)
#define max(a,b) ((a>b)?a:b)

void memcpy0( unsigned char *dest, const unsigned char *source,
				const unsigned char *mask, int numbytes ){

	/*
		mask contains one byte per pixel
		0xFF indicates the corresponding source pixel is transparent
		0x00 indicates the corresponding source pixel is opaque
	*/

	const unsigned char *finish = source+numbytes;
	const unsigned char *finishw = finish-(numbytes&0x3);

#ifdef ACORN
	while( source<finishw ){
		if( *mask )
			*dest = ( *dest++ & *mask ) | ( *source++ & ~*mask++ );
		else
		{
			*dest++ = *source++;
			mask++;
		}
	}
#else
	while( source<finishw ){
		int m = *(int *)mask;
		if( m )
			*(int *)dest = ( *(int *)dest & m ) | ( *(int *)source & ~m );
		else
			*(int *)dest = *(int *)source;

		dest += 4; source += 4; mask += 4;
	}
#endif
	while( source<finish ){
		if( *mask==0 ) *dest = *source;
		dest++; source++; mask++;
	}
}

static void fast_blit_transparent( struct osd_bitmap *dest_bitmap,
	const struct osd_bitmap *source_bitmap, const struct osd_bitmap *mask_bitmap,
	int sx, int sy,
	const struct rectangle *clip,
	unsigned char layer_transparency[TILEMAP_ROWS][TILEMAP_COLS] ){

	int x1 = max(sx,clip->min_x)-sx;
	int x2 = min(sx+source_bitmap->width,clip->max_x+1)-sx;
	int y1 = max(sy,clip->min_y)-sy;
	int y2 = min(sy+source_bitmap->height,clip->max_y+1)-sy;

	if( x1<x2 && y1<y2 ){
		/* x1,x2,y1,y2 are in source_bitmap coordinates */

		int c1 = x1/8;					/* round down */
		int c2 = (x2+7)/8;				/* round up */

		int align_y1 = (y1+7)&0xfff8;	/* round up */
		int align_y2 = y2&0xfff8;		/* round down */

		int dest_line_offset = dest_bitmap->line[1] - dest_bitmap->line[0];
		int source_line_offset = source_bitmap->line[1] - source_bitmap->line[0];
		int mask_line_offset = mask_bitmap->line[1] - mask_bitmap->line[0];

		int dest_row_offset = dest_line_offset*8;
		int source_row_offset = source_line_offset*8;
		int mask_row_offset = mask_line_offset*8;

		unsigned char *dest_baseaddr = dest_bitmap->line[sy+y1]+sx;
		const unsigned char *source_baseaddr = source_bitmap->line[y1];
		const unsigned char *mask_baseaddr = mask_bitmap->line[y1];

		unsigned char *dest_next;
		const unsigned char *source_next;
		const unsigned char *mask_next;

		int lines;

		int y = y1;
		int y_next = align_y1;
		if( y_next==y1 ) y_next += 8;
		if( y_next>y2 ) y_next = y2;

		lines = y_next-y;
		dest_next = dest_baseaddr+lines*dest_line_offset;
		source_next = source_baseaddr+lines*source_line_offset;
		mask_next = mask_baseaddr+lines*mask_line_offset;


		while( y<y2 ){
			unsigned char *row_transparency = layer_transparency[y/8];
			int col;
			for( col=c1; col<c2; col++ ){
				if( row_transparency[col]==0 ){
					int x_start = col*8;
					int x_end;
					do { col++; } while( col<c2 && row_transparency[col]==0 );
					x_end = col*8;

					/* horizontal clipping */
					if( x_start<x1 ) x_start = x1;
					if( x_end>x2 ) x_end = x2;

					{
						unsigned char *dest0 = dest_baseaddr+x_start;
						const unsigned char *source0 = source_baseaddr+x_start;
						const unsigned char *mask0 = mask_baseaddr+x_start;

						int num_pixels = x_end - x_start;

						int i = y;
						for(;;){
							memcpy0( dest0, source0, mask0, num_pixels );
							if( ++i == y_next ) break;

							dest0 += dest_line_offset;
							source0 += source_line_offset;
							mask0 += mask_line_offset;
						}
					}
				}
			}

			/* next row */
			dest_baseaddr = dest_next;
			source_baseaddr = source_next;
			mask_baseaddr = mask_next;

			y = y_next;
			y_next += 8;

			if( y_next>y2 ){
				y_next = y2;
			}
			else {
				dest_next += dest_row_offset;
				source_next += source_row_offset;
				mask_next += mask_row_offset;
			}
		}
	}
}

static void fast_blit_opaque( struct osd_bitmap *dest_bitmap,
	const struct osd_bitmap *source_bitmap,
	int sx, int sy,
	const struct rectangle *clip ){

	int x1 = sx;
	int y1 = sy;
	int x2 = sx+source_bitmap->width;
	int y2 = sy+source_bitmap->height;

	if( x1 < clip->min_x ) x1 = clip->min_x;
	if( y1 < clip->min_y ) y1 = clip->min_y;
	if( x2 > clip->max_x+1 ) x2 = clip->max_x+1;
	if( y2 > clip->max_y+1 ) y2 = clip->max_y+1;

	if( x1<x2 && y1<y2 ){
		/* x1,x2,y1,y2 are in screen (dest_bitmap) coordinates */

		int c1 = x1/8;					/* round down */
		int c2 = (x2+7)/8;				/* round up */

		int align_y1 = (y1+7)&0xfff8;	/* round up */
		int align_y2 = y2&0xfff8;		/* round down */

		int dest_line_offset = dest_bitmap->line[1] - dest_bitmap->line[0];
		int source_line_offset = source_bitmap->line[1] - source_bitmap->line[0];

		int dest_row_offset = dest_line_offset*8;
		int source_row_offset = source_line_offset*8;

		unsigned char *dest_baseaddr = dest_bitmap->line[y1];
		const unsigned char *source_baseaddr = source_bitmap->line[y1-sy]-sx;

		unsigned char *dest_next;
		const unsigned char *source_next;

		int lines;

		int y = y1;
		int y_next = align_y1;
		if( y_next==y1 ) y_next += 8;
		if( y_next>y2 ) y_next = y2;

		lines = y_next-y;
		dest_next = dest_baseaddr+lines*dest_line_offset;
		source_next = source_baseaddr+lines*source_line_offset;

		while( y<y2 ){
			int row_mask = 1<<(y/8);
			int col;
			for( col=c1; col<c2; col++ ){
				if( screenwise_opacity[col]&row_mask ){
					int x_start = col*8;
					int x_end;
					do { col++; } while( col<c2 && (screenwise_opacity[col]&row_mask) );
					x_end = col*8;

					/* horizontal clipping */
					if( x_start<x1 ) x_start = x1;
					if( x_end>x2 ) x_end = x2;

					{
						unsigned char *dest0 = dest_baseaddr+x_start;
						const unsigned char *source0 = source_baseaddr+x_start;

						int num_pixels = x_end - x_start;

						int i = y;
						for(;;){
							memcpy( dest0, source0, num_pixels );
							if( ++i == y_next ) break;

							dest0 += dest_line_offset;
							source0 += source_line_offset;
						}
					}
				}
			}

			/* next row */
			dest_baseaddr = dest_next;
			source_baseaddr = source_next;

			y = y_next;
			y_next += 8;

			if( y_next>y2 ){
				y_next = y2;
			}
			else {
				dest_next += dest_row_offset;
				source_next += source_row_offset;
			}
		}
	}
}

/***************************************************************************/

static void draw_background(struct osd_bitmap *bitmap){
	const struct rectangle *clip = &Machine->drv->visible_area;

	int page;
	int scrollx = 320+sys16_bg_scrollx;
	int scrolly = 256-sys16_bg_scrolly;
	static int old_scrollx = -1, old_scrolly = -1;

    if (scrollx < 0) scrollx = 1024 - (-scrollx) % 1024;
	else scrollx = scrollx % 1024;

	if (scrolly < 0) scrolly = 512 - (-scrolly) % 512;
	else scrolly = scrolly % 512;

	if (old_scrollx != scrollx || old_scrolly != scrolly)
	{
		old_scrollx = scrollx;
		old_scrolly = scrolly;
		/*osd_mark_dirty(clip->min_x, clip->min_y, clip->max_x, clip->max_y, 0);*/
	}

    for (page=0; page < 4; page++){
		int sx = (page&1)*512+scrollx;
		int sy = (page>>1)*256+scrolly;

		if( sx>320 ) sx-=1024;	/* wraparound */
		if( sy>224 ) sy-=512;	/* wraparound */

		fast_blit_opaque( bitmap, bg_bitmap[page],
			sx,sy,
			clip );
	}
}

static void draw_foreground(struct osd_bitmap *bitmap, int priority ){
	const struct rectangle *clip = &Machine->drv->visible_area;

	int page;

	int scrollx = 320+sys16_fg_scrollx;
	int scrolly = 256-sys16_fg_scrolly;
	static int old_scrollx = -1, old_scrolly = -1;

	if (scrollx < 0) scrollx = 1024 - (-scrollx) % 1024;
	else scrollx = scrollx % 1024;

	if (scrolly < 0) scrolly = 512 - (-scrolly) % 512;
	else scrolly = scrolly % 512;

	if (old_scrollx != scrollx || old_scrolly != scrolly)
	{
		old_scrollx = scrollx;
        old_scrolly = scrolly;
        /*osd_mark_dirty(clip->min_x, clip->min_y, clip->max_x, clip->max_y, 0);*/
	}

    for (page=0; page < 4; page++){
		int sx = (page&1)*512+scrollx;
		int sy = (page>>1)*256+scrolly;
		if( sx>320 ) sx-=1024;	/* wraparound */
		if( sy>224 ) sy-=512;	/* wraparound */

		fast_blit_transparent( bitmap, fg_bitmap[page], fg_fatmask[page],
			sx,sy,
			clip, fg_transparency[page][priority] );
	}
}


static void dirty_all( void ){
	/* mark each cached layer as invalid */
	int page;
	for( page=0; page<4; page++ ) old_bg_page[page] = old_fg_page[page] = -1;
}

/***************************************************************************/

static void update_background( void ){
	const struct GfxElement *gfx = Machine->gfx[0];

	int page;
	for( page=0; page<4; page++ ){
		struct osd_bitmap *bitmap = bg_bitmap[page];
		int all = (old_bg_page[page]!=sys16_bg_page[page]);

		const unsigned short *new_source = ((unsigned short *)sys16_tileram) + sys16_bg_page[page]*0x800;
		unsigned short *old_source = bg_page_buffer[page];

		int sx,sy;
		for( sy=0; sy<TILEMAP_HEIGHT; sy+=8 ){
			for( sx=0; sx<TILEMAP_WIDTH; sx+=8 ){
				unsigned short data = *new_source++;
				if( all || data!=*old_source ){
					int tile_number = (data&0xfff) +
						0x1000*((data&0x1000)?sys16_tile_bank1:sys16_tile_bank0);

					drawgfx( bitmap, gfx,
						tile_number,
						(data>>6)&0x7f, /* color */
						0, 0, /* no need to flip */
						sx, sy,
						0, /* no need to clip */
						TRANSPARENCY_NONE, 0);
					/*osd_mark_dirty(sx, sy, sx+TILEMAP_WIDTH-1, sy+TILEMAP_HEIGHT-1, 0);*/

					*old_source = data;
				}
				old_source++;
			} /* x */
		} /* y */
		old_bg_page[page]=sys16_bg_page[page];
	} /* page */
}

static void update_foreground( void ){
	const struct GfxElement *gfx = Machine->gfx[0];
	struct rectangle rect;

	int page;
	for( page=0; page<4; page++ ){
		struct osd_bitmap *bitmap = fg_bitmap[page];
		struct osd_bitmap *fatmask = fg_fatmask[page];

		int all = (old_fg_page[page]!=sys16_fg_page[page]);

		const unsigned short *new_source = ((unsigned short *)sys16_tileram) + sys16_fg_page[page]*0x800;
		unsigned short *old_source = fg_page_buffer[page];

		int sx,sy;
		for( sy=0; sy<TILEMAP_HEIGHT; sy+=8 ){
			for( sx=0; sx<TILEMAP_WIDTH; sx+=8 ){
				unsigned short data = *new_source++;
				if( all || data!=*old_source ){
					int col = sx/8;
					int row = sy/8;

					int tile_number = (data&0xfff) +
						0x1000*((data&0x1000)?sys16_tile_bank1:sys16_tile_bank0);

					int pen_usage = gfx->pen_usage[tile_number];

					/*osd_mark_dirty(sx, sy, sx+TILEMAP_WIDTH-1, sy+TILEMAP_HEIGHT-1, 0);*/

					if( pen_usage==1 ){
						fg_transparency[page][0][row][col] = 1;
						fg_transparency[page][1][row][col] = 1;
					}
					else {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -