void dassault_state::mixdassaultlayer(bitmap_rgb32 &bitmap, bitmap_ind16* sprite_bitmap, const rectangle &cliprect, uint16_t pri, uint16_t primask, uint16_t penbase, uint8_t alpha) { int y, x; const pen_t *paldata = &m_palette->pen(0); uint16_t* srcline; uint32_t* dstline; for (y=cliprect.top();y<=cliprect.bottom();y++) { srcline=&sprite_bitmap->pix16(y,0); dstline=&bitmap.pix32(y,0); for (x=cliprect.left();x<=cliprect.right();x++) { uint16_t pix = srcline[x]; if ((pix & primask) != pri) continue; if (pix&0xf) { uint16_t pen = pix&0x1ff; if (pix & 0x800) pen += 0x200; if (alpha!=0xff) { if (pix&0x400) // TODO, Additive/Subtractive Blending? { uint32_t base = dstline[x]; dstline[x] = alpha_blend_r32(base, paldata[pen+penbase], alpha); } else if (pix&0x200) { uint32_t base = dstline[x]; dstline[x] = alpha_blend_r32(base, paldata[pen+penbase], alpha); } else { dstline[x] = paldata[pen+penbase]; } } else { dstline[x] = paldata[pen+penbase]; } } } } }
static void mixdassaultlayer(running_machine &machine, bitmap_rgb32 &bitmap, bitmap_ind16* sprite_bitmap, const rectangle &cliprect, UINT16 pri, UINT16 primask, UINT16 penbase, UINT8 alpha) { int y, x; const pen_t *paldata = machine.pens; UINT16* srcline; UINT32* dstline; for (y=cliprect.min_y;y<=cliprect.max_y;y++) { srcline=&sprite_bitmap->pix16(y,0); dstline=&bitmap.pix32(y,0); for (x=cliprect.min_x;x<=cliprect.max_x;x++) { UINT16 pix = srcline[x]; if ((pix & primask) != pri) continue; if (pix&0xf) { UINT16 pen = pix&0x1ff; if (pix & 0x800) pen += 0x200; if (alpha!=0xff) { if (pix&0x600) { UINT32 base = dstline[x]; dstline[x] = alpha_blend_r32(base, paldata[pen+penbase], alpha); } else { dstline[x] = paldata[pen+penbase]; } } else { dstline[x] = paldata[pen+penbase]; } } } } }
// not amazingly efficient, called multiple times to pull a layer out of the sprite bitmaps, but keeps correct sprite<->sprite priorities void rohga_state::mixwizdfirelayer(bitmap_rgb32 &bitmap, const rectangle &cliprect, uint16_t pri, uint16_t primask) { int y, x; const pen_t *paldata = m_palette->pens(); bitmap_ind16* sprite_bitmap; int penbase; sprite_bitmap = &m_sprgen[1]->get_sprite_temp_bitmap(); penbase = 0x600; uint16_t* srcline; uint32_t* dstline; for (y=cliprect.top();y<=cliprect.bottom();y++) { srcline=&sprite_bitmap->pix16(y,0); dstline=&bitmap.pix32(y,0); for (x=cliprect.left();x<=cliprect.right();x++) { uint16_t pix = srcline[x]; if ((pix & primask) != pri) continue; if (pix&0xf) { uint16_t pen = pix&0x1ff; if (pen&0x100) { uint32_t base = dstline[x]; pen &=0xff; dstline[x] = alpha_blend_r32(base, paldata[pen+penbase], 0x80); } else { dstline[x] = paldata[pen+penbase]; } } } } }
/* Mix the 2 sprite planes with the already rendered tilemaps.. note, if we implement tilemap blending etc. too we'll probably have to mix those in here as well.. this is just a reimplementation of the old priority system used before conversion but to work with the bitmaps. It could probably be simplified / improved greatly, along with the long-standing bugs fixed, with manual mixing you have full control. apparently priority is based on a PROM, that should be used if possible. */ void boogwing_state::mix_boogwing(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) { int y, x; const pen_t *paldata = &m_palette->pen(0); bitmap_ind16 *sprite_bitmap1, *sprite_bitmap2; bitmap_ind8* priority_bitmap; address_space &space = machine().driver_data()->generic_space(); UINT16 priority = m_decocomn->priority_r(space, 0, 0xffff); sprite_bitmap1 = &m_sprgen1->get_sprite_temp_bitmap(); sprite_bitmap2 = &m_sprgen2->get_sprite_temp_bitmap(); priority_bitmap = &screen.priority(); UINT32* dstline; UINT16 *srcline1, *srcline2; UINT8 *srcpriline; for (y=cliprect.min_y;y<=cliprect.max_y;y++) { srcline1=&sprite_bitmap1->pix16(y,0); srcline2=&sprite_bitmap2->pix16(y,0); srcpriline=&priority_bitmap->pix8(y,0); dstline=&bitmap.pix32(y,0); for (x=cliprect.min_x;x<=cliprect.max_x;x++) { UINT16 pix1 = srcline1[x]; UINT16 pix2 = srcline2[x]; /* Here we have pix1 - raw pixel / colour / priority data from first 1sdt chip pix2 - raw pixel / colour / priority data from first 2nd chip */ int pri1, pri2; int spri1, spri2, alpha2; alpha2 = 0xff; // pix1 sprite vs pix2 sprite if (pix1 & 0x400) // todo - check only in pri mode 2?? spri1 = 8; else spri1 = 32; // pix1 sprite vs playfield switch (priority) { case 0x01: { if ((pix1 & 0x600)) pri1 = 16; else pri1 = 64; } break; default: { if ((pix1 & 0x600) == 0x600) pri1 = 4; else if ((pix1 & 0x600) == 0x400) pri1 = 16; else pri1 = 64; } break; } // pix2 sprite vs pix1 sprite if ((pix2 & 0x600) == 0x600) spri2 = 4; else if ((pix2 & 0x600)) spri2 = 16; else spri2 = 64; // Transparency if (pix2 & 0x100) alpha2 = 0x80; // pix2 sprite vs playfield switch (priority) { case 0x02: { // Additional sprite alpha in this mode if (pix2 & 0x400) alpha2 = 0x80; // Sprite vs playfield if ((pix2 & 0x600) == 0x600) pri2 = 4; else if ((pix2 & 0x600) == 0x400) pri2 = 16; else pri2 = 64; } break; default: { if ((pix2 & 0x400) == 0x400) pri2 = 16; else pri2 = 64; } break; } UINT8 bgpri = srcpriline[x]; /* once we get here we have pri1 - 4/16/64 (sprite chip 1 pixel priority relative to bg) pri2 - 4/16/64 (sprite chip 2 pixel priority relative to bg) spri1 - 8/32 (priority of sprite chip 1 relative to other sprite chip) spri2 - 4/16/64 (priority of sprite chip 2 relative to other sprite chip) alpha2 - 0x80/0xff alpha level of sprite chip 2 pixels (0x80 if enabled, 0xff if not) bgpri - 0 / 8 / 32 (from drawing tilemaps earlier, to compare above pri1/pri2 priorities against) pix1 - same as before (ready to extract just colour data from) pix2 - same as before ^^ */ int drawnpixe1 = 0; if (pix1 & 0xf) { if (pri1 > bgpri) { dstline[x] = paldata[(pix1&0x1ff)+0x500]; drawnpixe1 = 1; } } if (pix2 & 0xf) { if (pri2 > bgpri) { if ((!drawnpixe1) || (spri2 > spri1)) { if (alpha2==0xff) { dstline[x] = paldata[(pix2&0xff)+0x700]; } else { UINT32 base = dstline[x]; dstline[x] = alpha_blend_r32(base, paldata[(pix2&0xff)+0x700], alpha2); } } } } } } }
inline void deco_zoomspr_device::dragngun_drawgfxzoom( bitmap_rgb32 &dest_bmp,const rectangle &clip,gfx_element *gfx, UINT32 code,UINT32 color,int flipx,int flipy,int sx,int sy, int transparent_color, int scalex, int scaley,bitmap_ind8 *pri_buffer,UINT32 pri_mask, int sprite_screen_width, int sprite_screen_height, UINT8 alpha, bitmap_ind8 &pri_bitmap, bitmap_rgb32 &temp_bitmap, int priority) { 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 */ myclip = clip; myclip &= temp_bitmap.cliprect(); { if( gfx ) { const pen_t *pal = &m_palette->pen(gfx->colorbase() + gfx->granularity() * (color % gfx->colors())); const UINT8 *code_base = gfx->get_data(code % gfx->elements()); 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( 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: no alpha */ if (alpha == 0xff) { { for( y=sy; y<ey; y++ ) { const UINT8 *source = code_base + (y_index>>16) * gfx->rowbytes(); UINT32 *dest = &temp_bitmap.pix32(y); UINT8 *pri = &pri_bitmap.pix8(y); int x, x_index = x_index_base; for( x=sx; x<ex; x++ ) { int c = source[x_index>>16]; if (c != transparent_color) { if (priority >= pri[x]) { dest[x] = pal[c]; dest[x] |= 0xff000000; } else // sprites can have a 'masking' effect on other sprites { dest[x] = 0x00000000; } } x_index += dx; } y_index += dy; } } } /* alpha-blended */ else { { for( y=sy; y<ey; y++ ) { const UINT8 *source = code_base + (y_index>>16) * gfx->rowbytes(); UINT32 *dest = &temp_bitmap.pix32(y); UINT8 *pri = &pri_bitmap.pix8(y); UINT32 *tmapcolor = &dest_bmp.pix32(y); int x, x_index = x_index_base; for( x=sx; x<ex; x++ ) { int c = source[x_index>>16]; if (c != transparent_color) { if (priority >= pri[x]) { // this logic doesn't seem correct. Sprites CAN blend other sprites (needed in many places) but based on videos of the character select screen it appears that sprites can't blend already blended sprites // I'm not sure which colour gets used but the video shows a single shade of yellow rather than the yellow blending the yellow) if ((dest[x] & 0xff000000) == 0x00000000) dest[x] = alpha_blend_r32(tmapcolor[x] & 0x00ffffff, pal[c] & 0x00ffffff, alpha); // if nothing has been drawn pull the pixel from the tilemap to blend with else dest[x] = alpha_blend_r32(dest[x] & 0x00ffffff, pal[c] & 0x00ffffff, alpha); // otherwise blend with what was previously drawn dest[x] |= 0xff000000; } else // sprites can have a 'masking' effect on other sprites { dest[x] = 0x00000000; } } x_index += dx; } y_index += dy; } } } }
static inline void K053936GP_copyroz32clip( running_machine &machine, bitmap_rgb32 &dst_bitmap, bitmap_ind16 &src_bitmap, const rectangle &dst_cliprect, const rectangle &src_cliprect, UINT32 _startx,UINT32 _starty,int _incxx,int _incxy,int _incyx,int _incyy, int tilebpp, int blend, int alpha, int clip, int pixeldouble_output, palette_device *palette ) { static const int colormask[8]={1,3,7,0xf,0x1f,0x3f,0x7f,0xff}; int cy, cx; int ecx; int src_pitch, incxy, incxx; int src_minx, src_maxx, src_miny, src_maxy, cmask; UINT16 *src_base; size_t src_size; const pen_t *pal_base; int dst_ptr; int dst_size; int dst_base2; int tx, dst_pitch; UINT32 *dst_base; int starty, incyy, startx, incyx, ty, sx, sy; incxy = _incxy; incxx = _incxx; incyy = _incyy; incyx = _incyx; starty = _starty; startx = _startx; if (clip) // set source clip range to some extreme values when disabled { src_minx = src_cliprect.min_x; src_maxx = src_cliprect.max_x; src_miny = src_cliprect.min_y; src_maxy = src_cliprect.max_y; } // this simply isn't safe to do! else { src_minx = src_miny = -0x10000; src_maxx = src_maxy = 0x10000; } // set target clip range sx = dst_cliprect.min_x; tx = dst_cliprect.max_x - sx + 1; sy = dst_cliprect.min_y; ty = dst_cliprect.max_y - sy + 1; startx += sx * incxx + sy * incyx; starty += sx * incxy + sy * incyy; // adjust entry points and other loop constants dst_pitch = dst_bitmap.rowpixels(); dst_base = &dst_bitmap.pix32(0); dst_base2 = sy * dst_pitch + sx + tx; ecx = tx = -tx; tilebpp = (tilebpp-1) & 7; pal_base = palette->pens(); cmask = colormask[tilebpp]; src_pitch = src_bitmap.rowpixels(); src_base = &src_bitmap.pix16(0); src_size = src_bitmap.width() * src_bitmap.height(); dst_size = dst_bitmap.width() * dst_bitmap.height(); dst_ptr = 0;//dst_base; cy = starty; cx = startx; if (blend > 0) { dst_ptr += dst_pitch; // draw blended starty += incyy; startx += incyx; do { do { int srcx = (cx >> 16) & 0x1fff; int srcy = (cy >> 16) & 0x1fff; int pixel; UINT32 offs; offs = srcy * src_pitch + srcx; cx += incxx; cy += incxy; if (offs>=src_size) continue; if (srcx < src_minx || srcx > src_maxx || srcy < src_miny || srcy > src_maxy) continue; pixel = src_base[offs]; if (!(pixel & cmask)) continue; if ((dst_ptr+ecx+dst_base2)<dst_size) dst_base[dst_ptr+ecx+dst_base2] = alpha_blend_r32(pal_base[pixel], dst_base[dst_ptr+ecx+dst_base2], alpha); if (pixeldouble_output) { ecx++; if ((dst_ptr+ecx+dst_base2)<dst_size) dst_base[dst_ptr+ecx+dst_base2] = alpha_blend_r32(pal_base[pixel], dst_base[dst_ptr+ecx+dst_base2], alpha); } } while (++ecx < 0); ecx = tx; dst_ptr += dst_pitch; cy = starty; starty += incyy; cx = startx; startx += incyx; } while (--ty); }
void rohga_state::mixnitroballlayer(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) { int y, x; const pen_t *paldata = &m_palette->pen(0); bitmap_ind16 *sprite_bitmap1, *sprite_bitmap2; bitmap_ind8* priority_bitmap; uint16_t priority = m_decocomn->priority_r(); sprite_bitmap1 = &m_sprgen[0]->get_sprite_temp_bitmap(); sprite_bitmap2 = &m_sprgen[1]->get_sprite_temp_bitmap(); priority_bitmap = &screen.priority(); uint32_t* dstline; uint16_t *srcline1, *srcline2; uint8_t *srcpriline; for (y=cliprect.top();y<=cliprect.bottom();y++) { srcline1=&sprite_bitmap1->pix16(y,0); srcline2=&sprite_bitmap2->pix16(y,0); srcpriline=&priority_bitmap->pix8(y,0); dstline=&bitmap.pix32(y,0); for (x=cliprect.left();x<=cliprect.right();x++) { uint16_t pix1 = srcline1[x]; uint16_t pix2 = srcline2[x]; /* Here we have pix1 - raw pixel / colour / priority data from first 1st chip pix2 - raw pixel / colour / priority data from first 2nd chip */ int pri1, pri2; // pix1 sprite vs playfield switch (priority) // TODO : Verify this from real pcb { case 0x00: default: { switch (pix1 & 0xe00) { case 0x000: default: pri1 = 0x200; break; case 0x200: pri1 = 0x020; break; case 0x400: pri1 = 0x008; break; case 0x600: pri1 = 0x002; break; case 0x800: pri1 = 0x100; break; case 0xa00: pri1 = 0x040; break; case 0xc00: pri1 = 0x004; break; case 0xe00: pri1 = 0x001; break; } } break; case 0x20: { switch (pix1 & 0xe00) { case 0x000: default: pri1 = 0x080; break; case 0x200: pri1 = 0x004; break; case 0x400: pri1 = 0x002; break; case 0x600: pri1 = 0x001; break; case 0x800: pri1 = 0x100; break; case 0xa00: pri1 = 0x020; break; case 0xc00: pri1 = 0x008; break; case 0xe00: pri1 = 0x200; break; } } break; } // pix2 sprite vs pix1 sprite pri2 = 0x080; switch (priority) { case 0x00: default: pri2 = 0x080; break; case 0x20: pri2 = 0x010; break; } uint8_t bgpri = srcpriline[x]; /* once we get here we have pri1 - 0x001/0x002/0x004/0x008/0x010/0x020/0x040/0x080/0x100/0x200 (sprite chip 1 pixel priority relative to bg) pri2 - 0x080/0x010 (sprite chip 2 pixel priority relative to bg) bgpri - 0x008/0x040 (from drawing tilemaps earlier, to compare above pri1/pri2 priorities against) pix1 - same as before (ready to extract just colour data from) pix2 - same as before ^^ */ int drawnpixe1 = 0; if (pix1 & 0xf) { if (pri1 > bgpri) { dstline[x] = paldata[(pix1&0x1ff)+0x400]; drawnpixe1 = 1; } } if (pix2 & 0xf) { if (pri2 > bgpri) { if ((!drawnpixe1) || (pri2 > pri1)) { if (pix2 & 0x100) { uint32_t base = dstline[x]; dstline[x] = alpha_blend_r32(base, paldata[(pix2&0xff)+0x600], 0x80); } else { dstline[x] = paldata[(pix2&0xff)+0x600]; } } } } } } }
static void mlc_drawgfxzoomline(deco_mlc_state *state, uint32_t* dest,const rectangle &clip,gfx_element *gfx, uint32_t code1,uint32_t code2, uint32_t color,int flipx,int sx, int transparent_color,int use8bpp, int scalex, int alpha, int srcline ) { if (!scalex) 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 */ int sprite_screen_width = (scalex*16+(sx&0xffff))>>16; sx>>=16; if (sprite_screen_width) { /* compute sprite increment per screen pixel */ int dx = (16<<16)/sprite_screen_width; int ex = sx+sprite_screen_width; int x_index_base; if( flipx ) { x_index_base = (sprite_screen_width-1)*dx; dx = -dx; } else { x_index_base = 0; } if( sx < clip.min_x) { /* clip left */ int pixels = clip.min_x-sx; sx += pixels; x_index_base += pixels*dx; } /* NS 980211 - fixed incorrect clipping */ if( ex > clip.max_x+1 ) { /* clip right */ int pixels = ex-clip.max_x-1; ex -= pixels; } if( ex>sx ) { /* skip if inner loop doesn't draw anything */ const pen_t *pal = &state->m_palette->pen(gfx->colorbase() + gfx->granularity() * (color % gfx->colors())); const uint8_t *code_base1 = gfx->get_data(code1 % gfx->elements()); /* no alpha */ if (alpha == 0xff) { const uint8_t *code_base2 = gfx->get_data(code2 % gfx->elements()); const uint8_t *source1 = code_base1 + (srcline) * gfx->rowbytes(); const uint8_t *source2 = code_base2 + (srcline) * gfx->rowbytes(); 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; } } else { const uint8_t *source = code_base1 + (srcline) * gfx->rowbytes(); 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_blend_r32(dest[x], 0, alpha); //pal[c]); x_index += dx; } } } }
static void mlc_drawgfxzoom( bitmap_t *dest_bmp,const rectangle *clip,const gfx_element *gfx, UINT32 code1,UINT32 code2, UINT32 color,int flipx,int flipy,int sx,int sy, int transparent_color,int use8bpp, int scalex, int scaley,int alpha) { 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 = &gfx->machine().pens[gfx->color_base + gfx->color_granularity * (color % gfx->total_colors)]; const UINT8 *code_base1 = gfx_element_get_data(gfx, code1 % gfx->total_elements); const UINT8 *code_base2 = gfx_element_get_data(gfx, code2 % gfx->total_elements); 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: no alpha */ if (alpha == 0xff) { { for( y=sy; y<ey; y++ ) { const UINT8 *source1 = code_base1 + (y_index>>16) * gfx->line_modulo; const UINT8 *source2 = code_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: alpha blended */ else { { for( y=sy; y<ey; y++ ) { const UINT8 *source = code_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_blend_r32(dest[x], 0, alpha); //pal[c]); x_index += dx; } y_index += dy; } } } }
/* This function mimics the priority PROM/circuit on the pcb. It takes the tilemaps & sprite bitmaps as inputs, and outputs a final pixel based on alpha & priority values. Rendering sprites to temporary bitmaps is the only reasonable way to implement proper priority & blending support - it can't be done in-place on the final framebuffer without a lot of support bitmaps. */ void nslasher_state::mixDualAlphaSprites(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect, gfx_element *gfx0, gfx_element *gfx1, int mixAlphaTilemap) { const pen_t *pens = m_deco_ace->pens(); const pen_t *pal0 = &pens[gfx0->colorbase()]; const pen_t *pal1 = &pens[gfx1->colorbase()]; const pen_t *pal2 = &pens[m_gfxdecode->gfx((m_pri & 1) ? 1 : 2)->colorbase()]; bitmap_ind16& sprite0_mix_bitmap = m_sprgen[0]->get_sprite_temp_bitmap(); bitmap_ind16& sprite1_mix_bitmap = m_sprgen[1]->get_sprite_temp_bitmap(); /* Mix sprites into main bitmap, based on priority & alpha */ for (int y = cliprect.top(); y <= cliprect.bottom(); y++) { uint8_t* tilemapPri = &screen.priority().pix8(y); uint16_t* sprite0 = &sprite0_mix_bitmap.pix16(y); uint16_t* sprite1 = &sprite1_mix_bitmap.pix16(y); uint32_t* destLine = &bitmap.pix32(y); uint16_t* alphaTilemap = &m_tilemap_alpha_bitmap->pix16(y); for (int x = cliprect.left(); x <= cliprect.right(); x++) { uint16_t const priColAlphaPal0 = sprite0[x]; uint16_t const priColAlphaPal1 = sprite1[x]; uint16_t const pri0 = (priColAlphaPal0 & 0x6000) >> 13; uint16_t const pri1 = (priColAlphaPal1 & 0x6000) >> 13; uint16_t const col0 = (((priColAlphaPal0 & 0x1f00) >> 8) % gfx0->colors()) * gfx0->granularity(); uint16_t const col1 = (((priColAlphaPal1 & 0x0f00) >> 8) % gfx1->colors()) * gfx1->granularity(); uint16_t const alpha1 = priColAlphaPal1 & 0x8000; // Apply sprite bitmap 0 according to priority rules if ((priColAlphaPal0 & 0xff) != 0) { /* Sprite 0 priority rules: 0 = Sprite above all layers 1 = Sprite under top playfield 2 = Sprite under top two playfields 3 = Sprite under all playfields */ if ((pri0 & 0x3) == 0 || (pri0 & 0x3) == 1 || ((pri0 & 0x3) == 2 && mixAlphaTilemap)) // Spri0 on top of everything, or under alpha playfield { destLine[x] = pal0[(priColAlphaPal0 & 0xff) + col0]; } else if ((pri0 & 0x3) == 2) // Spri0 under top playfield { if (tilemapPri[x] < 4) destLine[x] = pal0[(priColAlphaPal0 & 0xff) + col0]; } else // Spri0 under top & middle playfields { if (tilemapPri[x] < 2) destLine[x] = pal0[(priColAlphaPal0 & 0xff) + col0]; } } // Apply sprite bitmap 1 according to priority rules if ((priColAlphaPal1 & 0xff) != 0) { // Apply alpha for this pixel based on Ace setting if (alpha1) { /* Alpha rules: Pri 0 - Over all tilemaps, but under sprite 0 pri 0, pri 1, pri 2 Pri 1 - Pri 2 - Pri 3 - */ /* Alpha values are tied to ACE ram... */ //int alpha = m_deco_ace->get_alpha(((priColAlphaPal1 & 0xf0) >> 4) / 2); //if (alpha < 0) // alpha = 0; /* I don't really understand how object ACE ram is really hooked up, the only obvious place in Night Slashers is the stagecoach in level 2 */ if (pri1 == 0 && (((priColAlphaPal0 & 0xff) == 0 || ((pri0 & 0x3) != 0 && (pri0 & 0x3) != 1 && (pri0 & 0x3) != 2)))) { if ((m_pri & 1) == 0 || ((m_pri & 1) == 1 && tilemapPri[x] < 4) || ((m_pri & 1) == 1 && mixAlphaTilemap)) destLine[x] = alpha_blend_r32(destLine[x], pal1[(priColAlphaPal1 & 0xff) + col1], 0x80); } else if (pri1 == 1 && ((priColAlphaPal0 & 0xff) == 0 || ((pri0 & 0x3) != 0 && (pri0 & 0x3) != 1 && (pri0 & 0x3) != 2))) destLine[x] = alpha_blend_r32(destLine[x], pal1[(priColAlphaPal1 & 0xff) + col1], 0x80); else if (pri1 == 2) // TOdo destLine[x] = alpha_blend_r32(destLine[x], pal1[(priColAlphaPal1 & 0xff) + col1], 0x80); else if (pri1 == 3) // TOdo destLine[x] = alpha_blend_r32(destLine[x], pal1[(priColAlphaPal1 & 0xff) + col1], 0x80); } else { /* Non alpha rules: Pri 0 - Under sprite 0 pri 0, over all tilemaps */ if (pri1 == 0 && ((priColAlphaPal0 & 0xff) == 0 || ((pri0 & 0x3) != 0))) destLine[x] = pal1[(priColAlphaPal1 & 0xff) + col1]; else if (pri1 == 1) // todo destLine[x] = pal1[(priColAlphaPal1 & 0xff) + col1]; else if (pri1 == 2) // todo destLine[x] = pal1[(priColAlphaPal1 & 0xff) + col1]; else if (pri1 == 3) // todo destLine[x] = pal1[(priColAlphaPal1 & 0xff) + col1]; } } /* Optionally mix in alpha tilemap */ if (mixAlphaTilemap) { uint16_t p = alphaTilemap[x]; if (p & 0xf) { /* Alpha tilemap under top two sprite 0 priorities */ if (((priColAlphaPal0 & 0xff) == 0 || (pri0 & 0x3) == 2 || (pri0 & 0x3) == 3) && ((priColAlphaPal1 & 0xff) == 0 || (pri1 & 0x3) == 2 || (pri1 & 0x3) == 3 || alpha1)) { /* Alpha values are tied to ACE ram */ int alpha = m_deco_ace->get_alpha(0x17 + (((p & 0xf0) >> 4) / 2)); if (alpha < 0) alpha = 0; destLine[x] = alpha_blend_r32(destLine[x], pal2[p], alpha); } } } } }