summaryrefslogtreecommitdiffstatshomepage
path: root/src/mame/video/deco_mlc.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mame/video/deco_mlc.c')
-rw-r--r--src/mame/video/deco_mlc.c532
1 files changed, 532 insertions, 0 deletions
diff --git a/src/mame/video/deco_mlc.c b/src/mame/video/deco_mlc.c
new file mode 100644
index 00000000000..e8f32ec2bec
--- /dev/null
+++ b/src/mame/video/deco_mlc.c
@@ -0,0 +1,532 @@
+/*
+ The MLC graphics hardware is quite complicated - the usual method of having 'object ram' that
+ controls sprites is expanded into object ram that controls sprite blocks that may be stored
+ in RAM or ROM. Each tile in a block may be specified explicitly via a display list in ROM or
+ calculated as part of a block offset.
+
+ Blocks can be scaled and subpositioned, and are usually 4-6bpp but two 4bpp blocks can be
+ combined into 8bpp with a flag.
+*/
+
+#include "driver.h"
+
+extern int mlc_raster_table[9][256];
+extern UINT32 mlc_clipper[32];
+static mame_bitmap *temp_bitmap;
+static UINT32 colour_mask, *mlc_buffered_spriteram;
+UINT32 *mlc_vram, *mlc_clip_ram;
+
+/******************************************************************************/
+
+VIDEO_START( mlc )
+{
+ alpha_set_level(0x80);
+
+ if (machine->gfx[0]->color_granularity==16)
+ colour_mask=0x7f;
+ else if (machine->gfx[0]->color_granularity==32)
+ colour_mask=0x3f;
+ else
+ colour_mask=0x1f;
+
+ temp_bitmap = auto_bitmap_alloc( 512, 512, BITMAP_FORMAT_RGB32 );
+ mlc_buffered_spriteram = auto_malloc(0x3000);
+}
+
+#ifdef UNUSED_FUNCTION
+static void blitRaster(mame_bitmap *bitmap, int rasterMode)
+{
+ int x,y;
+ for (y=0; y<256; y++) //todo
+ {
+ UINT32* src=BITMAP_ADDR32(temp_bitmap, y&0x1ff, 0);
+ UINT32* dst=BITMAP_ADDR32(bitmap, y, 0);
+ UINT32 xptr=(mlc_raster_table[0][y]<<13);
+
+ if (input_code_pressed(KEYCODE_X))
+ xptr=0;
+
+ for (x=0; x<320; x++)
+ {
+ if (src[x])
+ dst[x]=src[(xptr>>16)&0x1ff];
+
+ //if (input_code_pressed(KEYCODE_X))
+ // xptr+=0x10000;
+ //else if(rasterHackTest[0][y]<0)
+ xptr+=0x10000 - ((mlc_raster_table[2][y]&0x3ff)<<5);
+ //else
+ // xptr+=0x10000 + (mlc_raster_table[0][y]<<5);
+ }
+ }
+}
+#endif
+
+static void mlc_drawgfxzoom( mame_bitmap *dest_bmp,const gfx_element *gfx,
+ UINT32 code1,UINT32 code2, UINT32 color,int flipx,int flipy,int sx,int sy,
+ const rectangle *clip,int transparency,int transparent_color,int use8bpp,
+ int scalex, int scaley)
+{
+ rectangle myclip;
+
+ if (!scalex || !scaley) return;
+
+ /*
+ scalex and scaley are 16.16 fixed point numbers
+ 1<<15 : shrink to 50%
+ 1<<16 : uniform scale
+ 1<<17 : double to 200%
+ */
+
+ /* KW 991012 -- Added code to force clip to bitmap boundary */
+ if(clip)
+ {
+ myclip.min_x = clip->min_x;
+ myclip.max_x = clip->max_x;
+ myclip.min_y = clip->min_y;
+ myclip.max_y = clip->max_y;
+
+ if (myclip.min_x < 0) myclip.min_x = 0;
+ if (myclip.max_x >= dest_bmp->width) myclip.max_x = dest_bmp->width-1;
+ if (myclip.min_y < 0) myclip.min_y = 0;
+ if (myclip.max_y >= dest_bmp->height) myclip.max_y = dest_bmp->height-1;
+
+ clip=&myclip;
+ }
+
+ {
+ if( gfx )
+ {
+ const pen_t *pal = &Machine->remapped_colortable[gfx->color_base + gfx->color_granularity * (color % gfx->total_colors)];
+ int source_base1 = (code1 % gfx->total_elements) * gfx->height;
+ int source_base2 = (code2 % gfx->total_elements) * gfx->height;
+
+ int sprite_screen_height = (scaley*gfx->height+(sy&0xffff))>>16;
+ int sprite_screen_width = (scalex*gfx->width+(sx&0xffff))>>16;
+
+ sx>>=16;
+ sy>>=16;
+
+ if (sprite_screen_width && sprite_screen_height)
+ {
+ /* compute sprite increment per screen pixel */
+ int dx = (gfx->width<<16)/sprite_screen_width;
+ int dy = (gfx->height<<16)/sprite_screen_height;
+
+ int ex = sx+sprite_screen_width;
+ int ey = sy+sprite_screen_height;
+
+ int x_index_base;
+ int y_index;
+
+ if( flipx )
+ {
+ x_index_base = (sprite_screen_width-1)*dx;
+ dx = -dx;
+ }
+ else
+ {
+ x_index_base = 0;
+ }
+
+ if( flipy )
+ {
+ y_index = (sprite_screen_height-1)*dy;
+ dy = -dy;
+ }
+ else
+ {
+ y_index = 0;
+ }
+
+ if( clip )
+ {
+ if( sx < clip->min_x)
+ { /* clip left */
+ int pixels = clip->min_x-sx;
+ sx += pixels;
+ x_index_base += pixels*dx;
+ }
+ if( sy < clip->min_y )
+ { /* clip top */
+ int pixels = clip->min_y-sy;
+ sy += pixels;
+ y_index += pixels*dy;
+ }
+ /* NS 980211 - fixed incorrect clipping */
+ if( ex > clip->max_x+1 )
+ { /* clip right */
+ int pixels = ex-clip->max_x-1;
+ ex -= pixels;
+ }
+ if( ey > clip->max_y+1 )
+ { /* clip bottom */
+ int pixels = ey-clip->max_y-1;
+ ey -= pixels;
+ }
+ }
+
+ if( ex>sx )
+ { /* skip if inner loop doesn't draw anything */
+ int y;
+
+ /* case 1: TRANSPARENCY_PEN */
+ if (transparency == TRANSPARENCY_PEN)
+ {
+ {
+ for( y=sy; y<ey; y++ )
+ {
+ UINT8 *source1 = gfx->gfxdata + (source_base1+(y_index>>16)) * gfx->line_modulo;
+ UINT8 *source2 = gfx->gfxdata + (source_base2+(y_index>>16)) * gfx->line_modulo;
+ UINT32 *dest = BITMAP_ADDR32(dest_bmp, y, 0);
+
+ int x, x_index = x_index_base;
+
+ for( x=sx; x<ex; x++ )
+ {
+ int c = source1[x_index>>16];
+ if (use8bpp)
+ c=(c<<4)|source2[x_index>>16];
+
+ if( c != transparent_color ) dest[x] = pal[c];
+
+ x_index += dx;
+ }
+
+ y_index += dy;
+ }
+ }
+ }
+
+ /* case 6: TRANSPARENCY_ALPHA */
+ if (transparency == TRANSPARENCY_ALPHA)
+ {
+ {
+ for( y=sy; y<ey; y++ )
+ {
+ UINT8 *source = gfx->gfxdata + (source_base1+(y_index>>16)) * gfx->line_modulo;
+ UINT32 *dest = BITMAP_ADDR32(dest_bmp, y, 0);
+
+ int x, x_index = x_index_base;
+ for( x=sx; x<ex; x++ )
+ {
+ int c = source[x_index>>16];
+ if( c != transparent_color ) dest[x] = alpha_blend32(dest[x], 0); //pal[c]);
+ x_index += dx;
+ }
+
+ y_index += dy;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+static void draw_sprites(running_machine* machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ UINT32 *index_ptr=0;
+ int offs,fx=0,fy=0,x,y,color,colorOffset,sprite,indx,h,w,bx,by,fx1,fy1;
+ int xmult,ymult,xoffs,yoffs;
+ UINT8 *rom = memory_region(REGION_GFX2) + 0x20000, *index_ptr8;
+ UINT8 *rawrom = memory_region(REGION_GFX2);
+ int blockIsTilemapIndex=0;
+ int sprite2=0,indx2=0,use8bppMode=0;
+ int yscale,xscale;
+ int ybase,yinc;
+ int trans;
+ int useIndicesInRom=0;
+ int hibits=0;
+ int tileFormat=0;
+ int rasterMode=0;
+ int lastRasterMode=0;
+ int rasterDirty=0;
+ int clipper=0;
+ rectangle user_clip;
+ UINT32* mlc_spriteram=mlc_buffered_spriteram; // spriteram32
+
+ for (offs = (0x3000/4)-8; offs>=0; offs-=8)
+ {
+ if ((mlc_spriteram[offs+0]&0x8000)==0)
+ continue;
+ if ((mlc_spriteram[offs+1]&0x2000) && (cpu_getcurrentframe() & 1))
+ continue;
+
+ /*
+ Spriteram (1) format (16 bit):
+
+ Word 0: 0x8000 - Sprite enable
+ 0x4000 - Use ROM or RAM for spriteram 2 (really top bit of index)
+ 0x3fff - Index into spriteram 2
+ Word 1: 0x8000 - X flip
+ 0x4000 - Y flip
+ 0x2000 - Auto-flicker (display sprite only every other frame)
+ 0x1000 - If set combine this 4bpp sprite & next one, into 8bpp sprite
+ 0x0800 - ? (Not seen used anywhere)
+ 0x0400 - Use raster IRQ lookup table when drawing object
+ 0x0300 - Selects clipping window to use
+ 0x00ff - Colour/alpha shadow enable
+ Word 2: 0x07ff - Y position
+ Word 3: 0x07ff - X position
+ Word 4: 0x03ff - X scale
+ Word 5: 0x03ff - Y scale
+
+ Spriteram (2) format (16 bit):
+
+ Word 0: 0xe000 - ? (Always 0x2000?)
+ 0x1000 - X flip
+ 0x0f00 - Width in tiles (0==16)
+ 0x00ff - X position offset
+ Word 1: 0xe000 - ? (Always 0x2000?)
+ 0x1000 - Y flip
+ 0x0f00 - Height in tiles (0==16)
+ 0x00ff - Y position offset
+ Word 2: 0xff00 - ? (Always 0?)
+ 0x00c0 - If set use tile index as pointer into tile index array, else use as tile index directly
+ 0x0080 - If set tile index array format is 12 bit tile, 4 bit colour
+ 0x0040 - If set tile index array is 16 bit tile, 0 bit colour
+ 0x003c - Hi-bits of tile index after array lookup
+ 0x0003 - Hi-bits of tile index, selects ROM or RAM for array
+ Word 3: 0xffff - Low-bits of tile index
+ */
+
+ y = mlc_spriteram[offs+2]&0x7ff;
+ x = mlc_spriteram[offs+3]&0x7ff;
+
+ if (x&0x400) x=-(0x400-(x&0x3ff));
+ if (y&0x400) y=-(0x400-(y&0x3ff));
+
+ fx = mlc_spriteram[offs+1]&0x8000;
+ fy = mlc_spriteram[offs+1]&0x4000;
+ color = mlc_spriteram[offs+1]&0xff;
+ rasterMode = (mlc_spriteram[offs+1]>>10)&0x1;
+ clipper = (mlc_spriteram[offs+1]>>8)&0x3;
+ indx = mlc_spriteram[offs+0]&0x3fff;
+ yscale = mlc_spriteram[offs+4]&0x3ff;
+ xscale = mlc_spriteram[offs+5]&0x3ff;
+ colorOffset = 0;
+
+ /* Clip windows - this mapping seems odd, but is correct for Skull Fang and StadHr96,
+ however there are space for 8 clipping windows, where is the high bit? (Or is it ~0x400?) */
+ clipper=((clipper&2)>>1)|((clipper&1)<<1); // Swap low two bits
+
+ user_clip.min_y=mlc_clip_ram[(clipper*4)+0];
+ user_clip.max_y=mlc_clip_ram[(clipper*4)+1];
+ user_clip.min_x=mlc_clip_ram[(clipper*4)+2];
+ user_clip.max_x=mlc_clip_ram[(clipper*4)+3];
+
+ if (user_clip.min_y < cliprect->min_y) user_clip.min_y=cliprect->min_y;
+ if (user_clip.max_y > cliprect->max_y) user_clip.max_y=cliprect->max_y;
+ if (user_clip.min_x < cliprect->min_x) user_clip.min_x=cliprect->min_x;
+ if (user_clip.max_x > cliprect->max_x) user_clip.max_x=cliprect->max_x;
+
+ /* Any colours out of range (for the bpp value) trigger 'shadow' mode */
+ if (color & (colour_mask+1))
+ trans=TRANSPARENCY_ALPHA;
+ else
+ trans=TRANSPARENCY_PEN;
+ color&=colour_mask;
+
+ /* If this bit is set, combine this block with the next one */
+ if (mlc_spriteram[offs+1]&0x1000) {
+ use8bppMode=1;
+ /* In 8bpp the palette base is stored in the next block */
+ if (offs-8>=0) {
+ color = (mlc_spriteram[offs+1-8]&0x7f);
+ indx2 = mlc_spriteram[offs+0-8]&0x3fff;
+ }
+ } else
+ use8bppMode=0;
+
+ /* Lookup tiles/size in sprite index ram OR in the lookup rom */
+ if (mlc_spriteram[offs+0]&0x4000) {
+ index_ptr8=rom + indx*8; /* Byte ptr */
+ h=(index_ptr8[1]>>0)&0xf;
+ w=(index_ptr8[3]>>0)&0xf;
+
+ if (!h) h=16;
+ if (!w) w=16;
+
+ sprite = (index_ptr8[7]<<8)|index_ptr8[6];
+ sprite |= (index_ptr8[4]&3)<<16;
+
+ if (use8bppMode) {
+ UINT8* index_ptr28=rom + indx2*8;
+ sprite2=(index_ptr28[7]<<8)|index_ptr28[6];
+ }
+ //unused byte 5
+ yoffs=index_ptr8[0]&0xff;
+ xoffs=index_ptr8[2]&0xff;
+
+ fy1=(index_ptr8[1]&0xf0)>>4;
+ fx1=(index_ptr8[3]&0xf0)>>4;
+
+ tileFormat=index_ptr8[4]&0x80;
+
+ if (index_ptr8[4]&0xc0)
+ blockIsTilemapIndex=1;
+ else
+ blockIsTilemapIndex=0;
+
+ useIndicesInRom=0;
+
+ } else {
+ indx&=0x1fff;
+ index_ptr=mlc_vram + indx*4;
+ h=(index_ptr[0]>>8)&0xf;
+ w=(index_ptr[1]>>8)&0xf;
+
+ if (!h) h=16;
+ if (!w) w=16;
+
+ if (use8bppMode) {
+ UINT32* index_ptr2=mlc_vram + ((indx2*4)&0x7fff);
+ sprite2=((index_ptr2[2]&0x3)<<16) | (index_ptr2[3]&0xffff);
+ }
+
+ sprite = ((index_ptr[2]&0x3)<<16) | (index_ptr[3]&0xffff);
+ if (index_ptr[2]&0xc0)
+ blockIsTilemapIndex=1;
+ else
+ blockIsTilemapIndex=0;
+
+ tileFormat=index_ptr[2]&0x80;
+
+ hibits=(index_ptr[2]&0x3c)<<10;
+ useIndicesInRom=index_ptr[2]&3;
+
+ yoffs=index_ptr[0]&0xff;
+ xoffs=index_ptr[1]&0xff;
+
+ fy1=(index_ptr[0]&0xf000)>>12;
+ fx1=(index_ptr[1]&0xf000)>>12;
+ }
+
+ if(fx1&1) fx^=0x8000;
+ if(fy1&1) fy^=0x4000;
+
+ if (fx) xmult=-1; else xmult=1;
+ if (fy) ymult=-1; else ymult=1;
+
+ ybase=y<<16;
+ if (fy)
+ ybase+=(yoffs-15) * (yscale<<8);
+ else
+ ybase-=yoffs * (yscale<<8);
+
+ yinc=(yscale<<8)*16;
+
+ if (fy) yinc=-yinc;
+
+ for (by=0; by<h; by++) {
+ int xbase=x<<16;
+ int xinc=(xscale<<8)*16;
+
+ if (fx)
+ xbase+=(xoffs-15) * (xscale<<8);
+ else
+ xbase-=xoffs * (xscale<<8);
+
+ if (fx) xinc=-xinc;
+
+ for (bx=0; bx<w; bx++) {
+ int tile=sprite;
+ int tile2=sprite2;
+
+ if (blockIsTilemapIndex) {
+ if (useIndicesInRom)
+ {
+ const UINT8* ptr=rawrom+(sprite*2);
+ tile=(*ptr) + ((*(ptr+1))<<8);
+
+ if (use8bppMode) {
+ const UINT8* ptr2=rawrom+(sprite2*2);
+ tile2=(*ptr2) + ((*(ptr2+1))<<8);
+ }
+ else
+ {
+ tile2=0;
+ }
+
+ if (tileFormat)
+ {
+ colorOffset=(tile&0xf000)>>12;
+ tile=(tile&0x0fff)|hibits;
+ tile2=(tile2&0x0fff)|hibits;
+ }
+ else
+ {
+ colorOffset=0;
+ tile=(tile&0xffff)|(hibits<<2);
+ tile2=(tile2&0xffff)|(hibits<<2);
+ }
+ }
+ else
+ {
+ const UINT32* ptr=mlc_vram + ((sprite)&0x7fff);
+ tile=(*ptr)&0xffff;
+
+ if (tileFormat)
+ {
+ colorOffset=(tile&0xf000)>>12;
+ tile=(tile&0x0fff)|hibits;
+ }
+ else
+ {
+ colorOffset=0;
+ tile=(tile&0xffff)|(hibits<<2);
+ }
+
+ tile2=0;
+ }
+ }
+
+ if (rasterMode)
+ rasterDirty=1;
+
+ mlc_drawgfxzoom(/*rasterMode ? temp_bitmap : */bitmap,machine->gfx[0],
+ tile,tile2,
+ color + colorOffset,fx,fy,xbase,ybase,
+ &user_clip,trans,0,
+ use8bppMode,(xscale<<8),(yscale<<8));
+
+ sprite++;
+ sprite2++;
+
+ xbase+=xinc;
+ }
+ ybase+=yinc;
+ }
+
+ if (lastRasterMode!=0 && rasterDirty)
+ {
+ // blitRaster(bitmap, rasterMode);
+// fillbitmap(temp_bitmap,0,cliprect);
+ rasterDirty=0;
+ }
+ lastRasterMode=rasterMode;
+
+ if (use8bppMode)
+ offs-=8;
+ }
+}
+
+VIDEO_EOF( mlc )
+{
+ /* Spriteram is definitely double buffered, as the vram lookup tables
+ are often updated a frame after spriteram is setup to point to a new
+ lookup table. Without buffering incorrect one frame glitches are seen
+ in several places, especially in Hoops.
+ */
+ memcpy(mlc_buffered_spriteram, spriteram32, 0x3000);
+}
+
+VIDEO_UPDATE( mlc )
+{
+// fillbitmap(temp_bitmap,0,cliprect);
+ fillbitmap(bitmap,machine->pens[0],cliprect); /* Pen 0 fill colour confirmed from Skull Fang level 2 */
+ draw_sprites(machine,bitmap,cliprect);
+ return 0;
+}