/*************************************************************************** vidhrdw.c Functions to emulate the video hardware of the machine. ***************************************************************************/ #include #include #include #include "z80.h" #include "machine.h" #include "gfxdecod.h" #include "vidhrdw.h" #include "roms.h" #include "memmap.h" #include "osdepend.h" /* Phoenix has 32x32 video ram */ #define H_CHARS 32 #define V_CHARS 32 #define BITMAP_WIDTH (8*H_CHARS) #define BITMAP_HEIGHT (8*V_CHARS) unsigned char chars[2*256*8*8]; /* 32k for character bitmaps */ unsigned char tmpbitmap[BITMAP_WIDTH * BITMAP_HEIGHT]; /* temporarys bitmap used to hold the */ /* character mapped part of the screen */ unsigned char *scrbitmap; const unsigned char *palette; const unsigned char *colortable; unsigned char remappedtable[4*COLOR_CODES]; unsigned char backgroundpen; /* use these to draw charset B */ unsigned char scrollupd = 1; unsigned char scrollreg = 0; /* use this to select palette */ unsigned char palreg = 0; /* may use this to select video bank - is this ever used?*/ unsigned char bankreg = 0; /*************************************************************************** Initialize the video hardware. Returns 0 if successful. This usually involves no more than loading the graphics roms, decoding them and store the graphics somewhere. ***************************************************************************/ int vh_init(const char *gamename) { char *tmpstorage; int i; if ((tmpstorage = malloc(0x4000)) == 0) return 1; i = 0; while (gamevidinfo[i].name && stricmp(gamename,gamevidinfo[i].name) != 0) i++; if (readroms(tmpstorage,gamevidinfo[i].gfxrom,gamename) != 0) { free(tmpstorage); return 1; } decodechars(tmpstorage,chars); free(tmpstorage); palette = gamevidinfo[i].palette; colortable = gamevidinfo[i].colortable; return 0; } /*************************************************************************** Start the video hardware emulation, that is set up a gfx mode, load the appropriate palette, and return. Returns 0 if successful. ***************************************************************************/ int vh_start(void) { int i; unsigned char pens[TOTAL_COLORS]; if ((scrbitmap = osd_create_display(BITMAP_WIDTH,BITMAP_HEIGHT)) == 0) return 1; for (i = 0;i < TOTAL_COLORS;i++) pens[i] = osd_obtain_pen(palette[3*i],palette[3*i+1],palette[3*i+2]); backgroundpen = pens[0]; for (i = 0;i < 4*COLOR_CODES;i++) remappedtable[i] = pens[colortable[i]]; return 0; } /*************************************************************************** Stop the video hardware emulation. ***************************************************************************/ void vh_stop(void) { osd_close_display(); } /*************************************************************************** Handle a write to memory. This function is called when the emulated code writes to RAM. Arguments: dword A - Memory address to write to. byte V - Value to write into memory. If the address given concerns the video hardware, the write is performed (together with additional operations which might be required by the video hardware) and the function returns non zero. Otherwise, it returns 0. ***************************************************************************/ int vh_wrmem(dword A,byte V) { if (A >= SCROLL_REG_START && A < SCROLL_REG_START + SCROLL_REG_SIZE) { if (RAM[A] != V) { scrollupd = 1; scrollreg = V; RAM[A] = V; return 1; } } else if (A >= VIDEO_REG_START && A < VIDEO_REG_START + VIDEO_REG_SIZE) { if (RAM[A] != V) { palreg = (V << 6) >> 7; /* there must be a better way! */ bankreg = (V << 7) >> 7; RAM[A] = V; return 1; } } return 0; } void drawcharA(unsigned char *bitmap,int charcode,int color,int sx,int sy) { int x,y; unsigned char *chardata; const unsigned char *paldata; unsigned char *bm; /* prevent drawing unseen part of video ram */ if (sx < 6 || sx >= H_CHARS || sy < 0 || sy >= V_CHARS) return; sx -= 3; /* centre drawing area */ charcode &= 0xff; /* select color palette */ paldata = &remappedtable[(4 * (charcode >> 5)) + (32 * color)]; chardata = &chars[8*8 * charcode]; bm = &bitmap[8 * (BITMAP_WIDTH * sy + sx)]; for (y = 0;y < 8;y++) { for (x = 0;x < 8;x++) { /* Overlay char like a sprite */ if (paldata[*chardata] != backgroundpen) *bm = paldata[*chardata]; chardata++; bm++; } bm += BITMAP_WIDTH - 8; } } void drawcharB(unsigned char *bitmap,int charcode,int color,int scroll, int sx,int sy) { int x,y,drawpos; unsigned char *chardata; const unsigned char *paldata; unsigned char *bm; /* prevent drawing unseen part of video ram */ if (sx < 6 || sx >= H_CHARS || sy < 0 || sy >= V_CHARS) return; sx -= 3; /* centre drawing area */ charcode &= 0xff; /* select color palette*/ paldata = &remappedtable[(4 * (charcode >> 5)) + (32 * color) + 64]; charcode += 256; chardata = &chars[8*8 * charcode]; /* use scroll register */ drawpos = 8 * (BITMAP_WIDTH * sy + sx) + ((256 - scroll) * BITMAP_WIDTH); if (drawpos >= BITMAP_WIDTH * BITMAP_HEIGHT) drawpos -= BITMAP_WIDTH * BITMAP_HEIGHT; bm = &bitmap[drawpos]; for (y = 0;y < 8;y++) { for (x = 0;x < 8;x++) { /* Prevent drawing the scroll buffer */ if (drawpos + (y * BITMAP_WIDTH) + (x * 8) > 8 * BITMAP_WIDTH) *bm = paldata[*chardata]; bm++; chardata++; } bm += BITMAP_WIDTH - 8; } } /*************************************************************************** Redraw the screen. ***************************************************************************/ void vh_screenrefresh(void) { int offs; /* Even if Phoenix's screen is 26x36, the memory layout is 32x32. We therefore */ /* have to convert the memory coordinates into screen coordinates. */ /* Note that 32*32 = 1024, while 26*36 = 832: therefore 192 bytes of Video RAM */ /* don't map to a screen position. We don't check that here, however: range */ /* checking is performed by drawchar(). */ /* Last resort - draw each charset, every frame ! */ for (offs = 0;offs < VIDEO_RAM_SIZE;offs++) { int sx,sy,mx,my; mx = offs / 32; my = 31 - offs % 32; sx = 31 - mx; sy = 31 - my; drawcharB(tmpbitmap,RAM[VIDEO_RAM_B_START + offs],palreg,scrollreg,sx,sy); } for (offs = 0;offs < 0x340;offs++) { int sx,sy,mx,my; mx = offs / 32; my = 31 - offs % 32; sx = 31 - mx; sy = 31 - my; drawcharA(tmpbitmap,RAM[VIDEO_RAM_A_START + offs],palreg,sx,sy); } memcpy(scrbitmap,tmpbitmap,BITMAP_WIDTH * BITMAP_HEIGHT); osd_update_display(); }