Skip to content

Commit 56e55ea

Browse files
authored
popobear.cpp: support different height tilemaps + rowscroll modes on other layers (fixes qiwang piece display, popo bear ending) (mamedev#15551)
1 parent bcf9f42 commit 56e55ea

1 file changed

Lines changed: 123 additions & 85 deletions

File tree

src/mame/bmc/popobear.cpp

Lines changed: 123 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ class popobear_state : public driver_device
164164
int m_tilemap_base[4]{}; // configuration. TODO: shouldn't be needed
165165
std::vector<u16> m_vram_rearranged;
166166

167-
tilemap_t *m_bg_tilemap[4]{};
167+
tilemap_t *m_bg_tilemap[4][2]{};
168168

169169
u8 m_irq_enable = 0;
170170
u8 m_dsw_select = 0;
@@ -176,6 +176,9 @@ class popobear_state : public driver_device
176176

177177
template <u8 Number> TILE_GET_INFO_MEMBER(get_tile_info);
178178

179+
u8 get_tilemap_size(int which);
180+
u8 get_tilemap_enable(int which);
181+
void mark_tilemaps_dirty();
179182
int tilemap_base_words(u8 number) const;
180183

181184
void irq_ack_w(u8 data);
@@ -189,6 +192,7 @@ class popobear_state : public driver_device
189192
u8 idchip_r();
190193
void idchip_w(u8 data);
191194

195+
void draw_tilemap(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, int which, int basereg, int hireg, int xreg);
192196
u32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
193197
void draw_sprites(bitmap_ind16 &bitmap, const rectangle &cliprect);
194198

@@ -200,6 +204,13 @@ class popobear_state : public driver_device
200204
void magkengo_main_map(address_map &map) ATTR_COLD;
201205
};
202206

207+
void popobear_state::mark_tilemaps_dirty()
208+
{
209+
// unfortunately tilemaps and tilegfx share the same RAM so we're always dirty if we write to RAM
210+
for (int i = 0; i < 2; i++)
211+
for (int j = 0; j < 4; j++)
212+
m_bg_tilemap[j][i]->mark_all_dirty();
213+
}
203214

204215
void popobear_state::vram_w(offs_t offset, u16 data, u16 mem_mask)
205216
{
@@ -217,11 +228,7 @@ void popobear_state::vram_w(offs_t offset, u16 data, u16 mem_mask)
217228
COMBINE_DATA(&m_vram_rearranged[swapped_offset]);
218229
m_gfxdecode->gfx(0)->mark_dirty((swapped_offset) / 32);
219230

220-
// unfortunately tilemaps and tilegfx share the same RAM so we're always dirty if we write to RAM
221-
m_bg_tilemap[0]->mark_all_dirty();
222-
m_bg_tilemap[1]->mark_all_dirty();
223-
m_bg_tilemap[2]->mark_all_dirty();
224-
m_bg_tilemap[3]->mark_all_dirty();
231+
mark_tilemaps_dirty();
225232
}
226233

227234
static const gfx_layout char_layout =
@@ -263,15 +270,23 @@ void popobear_state::video_start()
263270

264271
m_gfxdecode->gfx(0)->set_source(reinterpret_cast<u8 *>(&m_vram_rearranged[0]));
265272

266-
m_bg_tilemap[0] = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(popobear_state::get_tile_info<0>)), TILEMAP_SCAN_ROWS, 8, 8, 128, 64);
267-
m_bg_tilemap[1] = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(popobear_state::get_tile_info<1>)), TILEMAP_SCAN_ROWS, 8, 8, 128, 64);
268-
m_bg_tilemap[2] = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(popobear_state::get_tile_info<2>)), TILEMAP_SCAN_ROWS, 8, 8, 128, 64);
269-
m_bg_tilemap[3] = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(popobear_state::get_tile_info<3>)), TILEMAP_SCAN_ROWS, 8, 8, 128, 64);
273+
// full height (drawn when enable bits are 0x0d / 0x1d / 0x1f?)
274+
m_bg_tilemap[0][0] = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(popobear_state::get_tile_info<0>)), TILEMAP_SCAN_ROWS, 8, 8, 128, 64);
275+
m_bg_tilemap[1][0] = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(popobear_state::get_tile_info<1>)), TILEMAP_SCAN_ROWS, 8, 8, 128, 64);
276+
m_bg_tilemap[2][0] = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(popobear_state::get_tile_info<2>)), TILEMAP_SCAN_ROWS, 8, 8, 128, 64);
277+
m_bg_tilemap[3][0] = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(popobear_state::get_tile_info<3>)), TILEMAP_SCAN_ROWS, 8, 8, 128, 64);
278+
279+
// half height (drawn when enable bits are 0x05)
280+
m_bg_tilemap[0][1] = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(popobear_state::get_tile_info<0>)), TILEMAP_SCAN_ROWS, 8, 8, 128, 32);
281+
m_bg_tilemap[1][1] = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(popobear_state::get_tile_info<1>)), TILEMAP_SCAN_ROWS, 8, 8, 128, 32);
282+
m_bg_tilemap[2][1] = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(popobear_state::get_tile_info<2>)), TILEMAP_SCAN_ROWS, 8, 8, 128, 32);
283+
m_bg_tilemap[3][1] = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(popobear_state::get_tile_info<3>)), TILEMAP_SCAN_ROWS, 8, 8, 128, 32);
270284

271-
m_bg_tilemap[0]->set_transparent_pen(0);
272-
m_bg_tilemap[1]->set_transparent_pen(0);
273-
m_bg_tilemap[2]->set_transparent_pen(0);
274-
m_bg_tilemap[3]->set_transparent_pen(0);
285+
for (int i = 0; i < 2; i++)
286+
for (int j = 0; j < 4; j++)
287+
m_bg_tilemap[j][i]->set_transparent_pen(0);
288+
289+
save_item(NAME(m_vram_rearranged));
275290
}
276291

277292

@@ -288,7 +303,7 @@ void popobear_state::video_start()
288303
*/
289304
void popobear_state::draw_sprites(bitmap_ind16 &bitmap, const rectangle &cliprect)
290305
{
291-
u8* vram = reinterpret_cast<u8 *>(m_spriteram.target());
306+
u8 *vram = reinterpret_cast<u8 *>(m_spriteram.target());
292307

293308
for (int drawpri = 0xf; drawpri >= 0x0; drawpri--)
294309
{
@@ -380,21 +395,9 @@ void popobear_state::draw_sprites(bitmap_ind16 &bitmap, const rectangle &cliprec
380395
}
381396
}
382397

383-
u32 popobear_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
398+
u8 popobear_state::get_tilemap_enable(int which)
384399
{
385-
bitmap.fill(0, cliprect);
386-
387400
u16 const *const vreg = m_vregs;
388-
// popmessage("%04x %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x",vreg[0x00],vreg[0x01],vreg[0x02],vreg[0x03],vreg[0x04],vreg[0x05],vreg[0x06], vreg[0x07],vreg[0x08],vreg[0x09],vreg[0x0a],vreg[0x0b],m_vregs[0x0c],m_vregs[0x0d],vreg[0x0e],vreg[0x0f]);
389-
390-
// vreg[0x00] also looks like it could be some enable registers
391-
// 0x82ff - BMC logo
392-
// 0x8aff - some attract scenes (no sprites)
393-
// 0x8bff - game attract scenes etc. (sprites)
394-
395-
// vreg[0x01] is always
396-
// 0xfefb
397-
398401
// Per-layer enable byte; a layer draws when non-zero. Value 0x1f selects the
399402
// per-line (line-scroll) mode on the upper two layers; every other non-zero
400403
// value is a plain layer.
@@ -405,10 +408,90 @@ u32 popobear_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, c
405408
(vreg[0x0d] & 0x00ff) // layer 3
406409
};
407410

411+
return enable[which];
412+
}
413+
414+
u8 popobear_state::get_tilemap_size(int which)
415+
{
416+
u8 enable = get_tilemap_enable(which);
417+
418+
// 0x0d / 0x1d / 0x1f = larger tilemap
419+
// 0x05 = smaller tilemap
420+
421+
if (enable & 0x08)
422+
return 0;
423+
else
424+
return 1;
425+
}
426+
427+
428+
void popobear_state::draw_tilemap(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, int which, int basereg, int hireg, int xreg)
429+
{
430+
int size = get_tilemap_size(which);
431+
rectangle clip = cliprect;
432+
if (get_tilemap_enable(which) & 0x02) // or & 0x10 (no, based on popobear ending)
433+
{
434+
int const base = m_vregs[basereg] << 9, hi = m_vregs[hireg] << 9;
435+
for (int line = cliprect.min_y; line <= cliprect.max_y; line++)
436+
{
437+
u16 const v = m_vram[base / 2 + line];
438+
u16 u;
439+
if (which & 1)
440+
u = (m_vram[hi / 2 + line] & 0xff00) >> 8;
441+
else
442+
u = (m_vram[hi / 2 + line] & 0x00ff);
443+
444+
clip.sety(line, line);
445+
m_bg_tilemap[which][size]->set_scrollx(0, (v & 0x00ff) | (u << 8));
446+
m_bg_tilemap[which][size]->set_scrolly(0, ((v & 0xff00) >> 8) - line);
447+
m_bg_tilemap[which][size]->draw(screen, bitmap, clip, 0, 0);
448+
}
449+
}
450+
else if (get_tilemap_enable(which))
451+
{
452+
m_bg_tilemap[which][size]->set_scrollx(0, m_vregs[xreg]);
453+
m_bg_tilemap[which][size]->set_scrolly(0, m_vregs[basereg] & 0x1ff);
454+
455+
m_bg_tilemap[which][size]->draw(screen, bitmap, cliprect, 0, 0);
456+
}
457+
}
458+
459+
460+
u32 popobear_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
461+
{
462+
bitmap.fill(0, cliprect);
463+
// popmessage("%04x %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x",vreg[0x00],vreg[0x01],vreg[0x02],vreg[0x03],vreg[0x04],vreg[0x05],vreg[0x06], vreg[0x07],vreg[0x08],vreg[0x09],vreg[0x0a],vreg[0x0b],m_vregs[0x0c],m_vregs[0x0d],vreg[0x0e],vreg[0x0f]);
464+
465+
// vreg[0x00] also looks like it could be some enable registers
466+
// 0x82ff - BMC logo
467+
// 0x8aff - some attract scenes (no sprites)
468+
// 0x8bff - game attract scenes etc. (sprites)
469+
470+
// vreg[0x01] is always
471+
// 0xfefb
472+
473+
// regs
474+
// 0 see above
475+
// 1
476+
// 2 tilemap 0 xscroll
477+
// 3 tilemap 0 yscroll
478+
// 4 tilemap 1 xscroll
479+
// 5 tilemap 1 yscroll
480+
// 6 tilemap 0/1 high base
481+
// 7 tilemap 2 xscroll
482+
// 8 tilemap 2 yscroll
483+
// 9 tilemap 3 xscroll
484+
// a tilemap 3 yscroll
485+
// b tilemap 2/3 high base
486+
// c enable 0/1
487+
// d enable 2/3
488+
// e
489+
// f
490+
408491
// pixram
409-
if (!enable[0] && !enable[1] && !enable[2] && !enable[3] && BIT(vreg[0x0e], 5))
492+
if (!get_tilemap_enable(0) && !get_tilemap_enable(1) && !get_tilemap_enable(2) && !get_tilemap_enable(3) && BIT(m_vregs[0x0e], 5))
410493
{
411-
u8 const *const fb = reinterpret_cast<u8 const *>(m_vram.target()) + ((vreg[0x0e] & 0x0f) << 16);
494+
u8 const *const fb = reinterpret_cast<u8 const *>(m_vram.target()) + ((m_vregs[0x0e] & 0x0f) << 16);
412495
for (int y = cliprect.min_y; y <= cliprect.max_y; y++)
413496
for (int x = cliprect.min_x; x <= cliprect.max_x; x++)
414497
{
@@ -420,64 +503,20 @@ u32 popobear_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, c
420503

421504
// Tile RAM and tile gfx share VRAM and the per-layer base can move at runtime,
422505
// so revalidate every frame (vram_w already marks dirty on write).
423-
for (auto &tm : m_bg_tilemap)
424-
tm->mark_all_dirty();
425-
426-
// Lower two layers: whole-layer scroll.
427-
m_bg_tilemap[2]->set_scrollx(0, vreg[0x07]);
428-
m_bg_tilemap[2]->set_scrolly(0, vreg[0x08]);
429-
m_bg_tilemap[3]->set_scrollx(0, vreg[0x09]);
430-
m_bg_tilemap[3]->set_scrolly(0, vreg[0x0a]);
431-
if (enable[3]) m_bg_tilemap[3]->draw(screen, bitmap, cliprect, 0, 0);
432-
if (enable[2]) m_bg_tilemap[2]->draw(screen, bitmap, cliprect, 0, 0);
433-
434-
// Upper two layers: line-scroll only in mode 0x1f (popobear). The line
435-
// tables live in VRAM at (scroll-pointer register << 9): layer0 = vreg[3],
436-
// layer1 = vreg[5], shared high-byte table = vreg[6] (e.g. 0x06fa -> 0xdf400).
506+
mark_tilemaps_dirty();
507+
508+
// line-scroll only in mode 0x1f (popobear). The line
509+
// tables live in VRAM at (scroll-pointer register << 9): layer0 = m_vregs[3],
510+
// layer1 = m_vregs[5], shared high-byte table = m_vregs[6] (e.g. 0x06fa -> 0xdf400).
437511
// Any other non-zero enable is a plain layer (magkengo uses 0x05/0x0d/0x1d).
438-
rectangle clip = cliprect;
439512

440-
if (enable[1] == 0x1f)
441-
{
442-
int const base = vreg[0x05] << 9, hi = vreg[0x06] << 9;
443-
for (int line = cliprect.min_y; line <= cliprect.max_y; line++)
444-
{
445-
u16 const v = m_vram[base / 2 + line];
446-
u16 const u = (m_vram[hi / 2 + line] & 0xff00) >> 8;
447-
clip.sety(line, line);
448-
m_bg_tilemap[1]->set_scrollx(0, (v & 0x00ff) | (u << 8));
449-
m_bg_tilemap[1]->set_scrolly(0, ((v & 0xff00) >> 8) - line);
450-
m_bg_tilemap[1]->draw(screen, bitmap, clip, 0, 0);
451-
}
452-
}
453-
else if (enable[1])
454-
{
455-
m_bg_tilemap[1]->set_scrollx(0, 0);
456-
m_bg_tilemap[1]->set_scrolly(0, 0);
457-
m_bg_tilemap[1]->draw(screen, bitmap, cliprect, 0, 0);
458-
}
513+
draw_tilemap(screen, bitmap, cliprect, 3, 0xa, 0xb, 0x9);
514+
draw_tilemap(screen, bitmap, cliprect, 2, 0x8, 0xb, 0x7);
459515

460-
if (enable[0] == 0x1f)
461-
{
462-
int const base = vreg[0x03] << 9, hi = vreg[0x06] << 9;
463-
for (int line = cliprect.min_y; line <= cliprect.max_y; line++)
464-
{
465-
u16 const v = m_vram[base / 2 + line];
466-
u16 const u = (m_vram[hi / 2 + line] & 0x00ff);
467-
clip.sety(line, line);
468-
m_bg_tilemap[0]->set_scrollx(0, (v & 0x00ff) | (u << 8));
469-
m_bg_tilemap[0]->set_scrolly(0, ((v & 0xff00) >> 8) - line);
470-
m_bg_tilemap[0]->draw(screen, bitmap, clip, 0, 0);
471-
}
472-
}
473-
else if (enable[0])
474-
{
475-
m_bg_tilemap[0]->set_scrollx(0, 0);
476-
m_bg_tilemap[0]->set_scrolly(0, 0);
477-
m_bg_tilemap[0]->draw(screen, bitmap, cliprect, 0, 0);
478-
}
516+
draw_tilemap(screen, bitmap, cliprect, 1, 0x5, 0x6, 0x4);
517+
draw_tilemap(screen, bitmap, cliprect, 0, 0x3, 0x6, 0x2);
479518

480-
if (BIT(vreg[0x00], 8))
519+
if (BIT(m_vregs[0x00], 8))
481520
draw_sprites(bitmap, cliprect);
482521

483522
return 0;
@@ -503,7 +542,6 @@ u8 popobear_state::_620000_r()
503542

504543
void popobear_state::machine_start()
505544
{
506-
save_item(NAME(m_vram_rearranged));
507545
save_item(NAME(m_dsw_select));
508546
save_item(NAME(m_irq_enable));
509547

0 commit comments

Comments
 (0)