summaryrefslogtreecommitdiffstatshomepage
path: root/src/mame/video/deco32.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mame/video/deco32.cpp')
-rw-r--r--src/mame/video/deco32.cpp228
1 files changed, 225 insertions, 3 deletions
diff --git a/src/mame/video/deco32.cpp b/src/mame/video/deco32.cpp
index 2ae5678448b..c79b6edd7c8 100644
--- a/src/mame/video/deco32.cpp
+++ b/src/mame/video/deco32.cpp
@@ -52,6 +52,25 @@ void deco32_state::palette_dma_w(u32 data)
/******************************************************************************/
+// sprite and BG2/3 color banks are changeable at run time
+void nslasher_state::tilemap_color_bank_w(u8 data)
+{
+ m_deco_tilegen[1]->set_tilemap_colour_bank(0, ((data >> 0) & 7) << 4);
+ m_deco_tilegen[1]->set_tilemap_colour_bank(1, ((data >> 3) & 7) << 4);
+}
+
+void nslasher_state::sprite1_color_bank_w(u8 data)
+{
+ m_gfxdecode->gfx(3)->set_colorbase((data & 7) << 8);
+}
+
+void nslasher_state::sprite2_color_bank_w(u8 data)
+{
+ m_gfxdecode->gfx(4)->set_colorbase((data & 7) << 8);
+}
+
+/******************************************************************************/
+
void deco32_state::video_start()
{
save_item(NAME(m_pri));
@@ -236,7 +255,7 @@ u32 fghthist_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, c
reference : https://www.youtube.com/watch?v=y73dJ6UQw8M (nslasher)
*/
-void nslasher_state::mixDualAlphaSprites(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect, gfx_element *gfx0, gfx_element *gfx1, int mixAlphaTilemap)
+void nslasher_state::mix_nslasher(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()];
@@ -303,6 +322,7 @@ void nslasher_state::mixDualAlphaSprites(screen_device &screen, bitmap_rgb32 &bi
coloffs = (((m_pri & 4) == 0) && sprite1_drawn) ? 0x800 : 0;
/* Alpha values are tied to ACE ram... */
+ // TODO : verify this from real hardware
int alpha = ((!alpha1) || alpha2) ? m_deco_ace->get_alpha((col1 & 0x8) ? (0x4 + ((col1 & 0x3) / 2)) : ((col1 & 0x7) / 2)) : 0xff;
/* I don't really understand how object ACE ram is really hooked up,
@@ -377,7 +397,209 @@ void nslasher_state::mixDualAlphaSprites(screen_device &screen, bitmap_rgb32 &bi
}
}
-u32 nslasher_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
+u32 nslasher_state::screen_update_nslasher(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
+{
+ bool alphaTilemap = false;
+ m_deco_tilegen[0]->pf_update(m_pf_rowscroll[0].get(), m_pf_rowscroll[1].get());
+ m_deco_tilegen[1]->pf_update(m_pf_rowscroll[2].get(), m_pf_rowscroll[3].get());
+
+ /* This is not a conclusive test for deciding if tilemap needs alpha blending */
+ if (m_deco_ace->get_aceram(0x17) != 0x0 && (m_pri & 3))
+ alphaTilemap = true;
+
+ screen.priority().fill(0, cliprect);
+
+ bitmap.fill(m_deco_ace->pen(0x300), cliprect); // TODO : verify this from real hardware
+
+ /* Draw sprites to temporary bitmaps, saving alpha & priority info for later mixing */
+ m_sprgen[0]->set_pix_raw_shift(8);
+ m_sprgen[1]->set_pix_raw_shift(8);
+
+ // sprites are flipped relative to tilemaps
+ m_sprgen[0]->set_flip_screen(true);
+ m_sprgen[1]->set_flip_screen(true);
+ m_sprgen[0]->draw_sprites(bitmap, cliprect, m_spriteram16_buffered[0].get(), 0x800);
+ m_sprgen[1]->draw_sprites(bitmap, cliprect, m_spriteram16_buffered[1].get(), 0x800);
+
+ /* Render alpha-blended tilemap to separate buffer for proper mixing */
+ m_tilemap_alpha_bitmap->fill(0, cliprect);
+
+ /* Draw playfields & sprites */
+ if (m_pri & 2)
+ {
+ m_deco_tilegen[1]->tilemap_12_combine_draw(screen, bitmap, cliprect, 0, 1, 1);
+ m_deco_tilegen[0]->tilemap_2_draw(screen, bitmap, cliprect, 0, 4);
+ }
+ else
+ {
+ m_deco_tilegen[1]->tilemap_2_draw(screen, bitmap, cliprect, 0, 1);
+ if (m_pri & 1)
+ {
+ m_deco_tilegen[0]->tilemap_2_draw(screen, bitmap, cliprect, 0, 2);
+ if (alphaTilemap)
+ m_deco_tilegen[1]->tilemap_1_draw(screen, *m_tilemap_alpha_bitmap, cliprect, 0, 4);
+ else
+ m_deco_tilegen[1]->tilemap_1_draw(screen, bitmap, cliprect, 0, 4);
+ }
+ else
+ {
+ m_deco_tilegen[1]->tilemap_1_draw(screen, bitmap, cliprect, 0, 2);
+ if (alphaTilemap)
+ m_deco_tilegen[0]->tilemap_2_draw(screen, *m_tilemap_alpha_bitmap, cliprect, 0, 4);
+ else
+ m_deco_tilegen[0]->tilemap_2_draw(screen, bitmap, cliprect, 0, 4);
+ }
+ }
+
+ mix_nslasher(screen, bitmap, cliprect, m_gfxdecode->gfx(3), m_gfxdecode->gfx(4), alphaTilemap);
+
+ m_deco_tilegen[0]->tilemap_1_draw(screen, bitmap, cliprect, 0, 0);
+ return 0;
+}
+
+// different alpha blending behavior, priority? TODO : verify behavior from real hardware
+// reference : https://www.youtube.com/watch?v=ax-_P3meUiA (review)
+void nslasher_state::mix_tattass(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++)
+ {
+ const u16* sprite0 = &sprite0_mix_bitmap.pix16(y);
+ const u16* sprite1 = &sprite1_mix_bitmap.pix16(y);
+ const u16* alphaTilemap = &m_tilemap_alpha_bitmap->pix16(y);
+ const u8* tilemapPri = &screen.priority().pix8(y);
+ u32* destLine = &bitmap.pix32(y);
+
+ for (int x = cliprect.left(); x <= cliprect.right(); x++)
+ {
+ const u16 priColAlphaPal0 = sprite0[x];
+ const u16 priColAlphaPal1 = sprite1[x];
+ const u16 pri0 = (priColAlphaPal0 & 0x6000) >> 13;
+ const u16 pri1 = (priColAlphaPal1 & 0x6000) >> 13;
+ const u16 col0 = (((priColAlphaPal0 & 0x0f00) >> 8) % gfx0->colors()) * gfx0->granularity();
+ u16 col1 = ((priColAlphaPal1 & 0x3f00) >> 8);
+ const bool alpha1 = (priColAlphaPal1 & 0x8000); // Unknown behavior, just priority?
+
+ // Apply sprite bitmap 0 according to priority rules
+ u16 coloffs = ((m_pri & 4) == 4) ? 0x800 : 0;
+ bool sprite1_drawn = false;
+ 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[coloffs | ((priColAlphaPal0 & 0xff) + col0)];
+ sprite1_drawn = true;
+ }
+ else if ((pri0 & 0x3) == 2) // Spri0 under top playfield
+ {
+ if (tilemapPri[x] < 4)
+ {
+ destLine[x] = pal0[coloffs | ((priColAlphaPal0 & 0xff) + col0)];
+ sprite1_drawn = true;
+ }
+ }
+ else // Spri0 under top & middle playfields
+ {
+ if (tilemapPri[x] < 2)
+ {
+ destLine[x] = pal0[coloffs | ((priColAlphaPal0 & 0xff) + col0)];
+ sprite1_drawn = true;
+ }
+ }
+ }
+
+ coloffs = (((m_pri & 4) == 4) && sprite1_drawn) ? 0x800 : 0;
+ /* Alpha values are tied to ACE ram... */
+ int alpha = m_deco_ace->get_alpha(col1 / 8);
+
+ /* 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 */
+
+ col1 = ((col1 & 0xf) % gfx1->colors()) * gfx1->granularity();
+ // 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 - Under uppermost tilemap, sprite 0 pri 0, pri 1?
+ Pri 2 -
+ Pri 3 -
+ */
+
+ 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 && ((alphaTilemap[x] & 0xf) == 0))))
+ destLine[x] = alpha_blend_r32(destLine[x], pal1[coloffs | ((priColAlphaPal1 & 0xff) + col1)], alpha);
+ }
+ else if (pri1 == 1 && ((m_pri & 1) == 0 || tilemapPri[x] < 4)
+ && ((priColAlphaPal0 & 0xff) == 0 || ((pri0 & 0x3) != 0 && (pri0 & 0x3) != 1)))
+ destLine[x] = alpha_blend_r32(destLine[x], pal1[coloffs | ((priColAlphaPal1 & 0xff) + col1)], alpha);
+ else if (pri1 == 2) // TODO
+ destLine[x] = alpha_blend_r32(destLine[x], pal1[coloffs | ((priColAlphaPal1 & 0xff) + col1)], alpha);
+ else if (pri1 == 3) // TODO
+ destLine[x] = alpha_blend_r32(destLine[x], pal1[coloffs | ((priColAlphaPal1 & 0xff) + col1)], alpha);
+ }
+ 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] = alpha_blend_r32(destLine[x], pal1[coloffs | ((priColAlphaPal1 & 0xff) + col1)], alpha);
+ else if (pri1 == 1) // TODO
+ destLine[x] = alpha_blend_r32(destLine[x], pal1[coloffs | ((priColAlphaPal1 & 0xff) + col1)], alpha);
+ else if (pri1 == 2) // TODO
+ destLine[x] = alpha_blend_r32(destLine[x], pal1[coloffs | ((priColAlphaPal1 & 0xff) + col1)], alpha);
+ else if (pri1 == 3) // TODO
+ destLine[x] = alpha_blend_r32(destLine[x], pal1[coloffs | ((priColAlphaPal1 & 0xff) + col1)], alpha);
+ }
+ }
+
+ /* Optionally mix in alpha tilemap */
+ if (mixAlphaTilemap)
+ {
+ const u16 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));
+
+ destLine[x] = alpha_blend_r32(destLine[x], pal2[coloffs | p], alpha);
+ }
+ }
+ }
+ }
+ }
+}
+
+u32 nslasher_state::screen_update_tattass(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
bool alphaTilemap = false;
m_deco_tilegen[0]->pf_update(m_pf_rowscroll[0].get(), m_pf_rowscroll[1].get());
@@ -431,7 +653,7 @@ u32 nslasher_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, c
}
}
- mixDualAlphaSprites(screen, bitmap, cliprect, m_gfxdecode->gfx(3), m_gfxdecode->gfx(4), alphaTilemap);
+ mix_tattass(screen, bitmap, cliprect, m_gfxdecode->gfx(3), m_gfxdecode->gfx(4), alphaTilemap);
m_deco_tilegen[0]->tilemap_1_draw(screen, bitmap, cliprect, 0, 0);
return 0;