From 198696996f7325173f7f82f868499d3554d203c9 Mon Sep 17 00:00:00 2001 From: hap Date: Tue, 12 Jan 2021 21:34:19 +0100 Subject: i8244: changed character layer priorities --- hash/videopac.xml | 2 + src/devices/video/i8244.cpp | 162 +++++++++++++++++++----------------------- src/devices/video/i8244.h | 4 ++ src/mame/drivers/odyssey2.cpp | 15 ++-- 4 files changed, 91 insertions(+), 92 deletions(-) diff --git a/hash/videopac.xml b/hash/videopac.xml index 9dc4bb2f0b9..c27fc747a5d 100644 --- a/hash/videopac.xml +++ b/hash/videopac.xml @@ -1801,6 +1801,7 @@ Newer releases don't follow this numbering scheme anymore. Spider-Man (Europe, prototype, set 1) 198? Parker Brothers + @@ -1813,6 +1814,7 @@ Newer releases don't follow this numbering scheme anymore. Spider-Man (Europe, prototype, set 2) 198? Parker Brothers + diff --git a/src/devices/video/i8244.cpp b/src/devices/video/i8244.cpp index 9b49c633561..fb4f181a998 100644 --- a/src/devices/video/i8244.cpp +++ b/src/devices/video/i8244.cpp @@ -136,7 +136,9 @@ void i8244_device::device_start() save_pointer(NAME(m_vdc.reg), 0x100); memset(m_collision_map, 0, sizeof(m_collision_map)); + memset(m_priority_map, 0, sizeof(m_priority_map)); save_item(NAME(m_collision_map)); + save_item(NAME(m_priority_map)); save_item(NAME(m_x_beam_pos)); save_item(NAME(m_y_beam_pos)); @@ -448,7 +450,7 @@ void i8244_device::write_cx(int x, bool cx) { u8 colx = m_collision_map[x] & 0x3f; - // Check if we collide with an already drawn source object + // check if we collide with an already drawn source object if (colx) { // external overlap interrupt @@ -461,7 +463,7 @@ void i8244_device::write_cx(int x, bool cx) if (colx & m_vdc.s.collision) m_collision_status |= 0x40; } - // Check if an already drawn object would collide with us + // check if an already drawn object would collide with us if (m_vdc.s.collision & 0x40) { m_collision_status |= colx; @@ -470,17 +472,56 @@ void i8244_device::write_cx(int x, bool cx) } +void i8244_device::draw_char(u8 index, int x, int y, u8 pixel, u16 color, bitmap_ind16 &bitmap, const rectangle &cliprect) +{ + for (int px = x; px < x + 2; px++) + { + if (cliprect.contains(px, y)) + { + u8 colx = m_collision_map[px]; + + // check collision with self + if (index < m_priority_map[px]) + { + m_control_status |= 0x80; + + // TODO: much more complex on actual console (weird glitches happen) + if (colx & 0x80) + continue; + } + else + m_priority_map[px] = index; + + if (pixel) + { + // check if we collide with an already drawn source object + if (m_vdc.s.collision & colx) + m_collision_status |= 0x80; + + // check if an already drawn object would collide with us + if (m_vdc.s.collision & 0x80) + m_collision_status |= colx; + + m_collision_map[px] |= 0x80; + bitmap.pix(y, px) = color; + } + } + } +} + + u32 i8244_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) { - /* Draw background color */ + // draw background color bitmap.fill(bitswap<3>(m_vdc.s.color,3,4,5), cliprect); for (int scanline = cliprect.min_y; scanline <= cliprect.max_y; scanline++) { - /* Clear collision map */ + // clear collision maps memset(m_collision_map, 0, sizeof(m_collision_map)); + memset(m_priority_map, 0, sizeof(m_priority_map)); - /* Display grid if enabled */ + // display grid if enabled if (m_vdc.s.control & 0x08) { u16 color = bitswap<4>(m_vdc.s.color,6,0,1,2); @@ -490,7 +531,7 @@ u32 i8244_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, con int height = 24; int w = (m_vdc.s.control & 0x80) ? width : 2; - /* Draw horizontal part of the grid */ + // draw horizontal part of the grid for (int y = 0; y < 9; y++) { if (y_grid_offset + y * height <= scanline && scanline < y_grid_offset + y * height + 3) @@ -517,7 +558,7 @@ u32 i8244_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, con } } - /* Draw dots part of the grid */ + // draw dots part of the grid if (m_vdc.s.control & 0x40) { for (int y = 0; y < 9; y++) @@ -544,7 +585,7 @@ u32 i8244_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, con } } - /* Draw vertical part of the grid */ + // draw vertical part of the grid for (int j = 1, y = 0; y < 8; y++, j <<= 1) { if (y_grid_offset + y * height <= scanline && scanline < y_grid_offset + (y + 1) * height) @@ -572,17 +613,19 @@ u32 i8244_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, con } } - /* Display objects if enabled */ + // display objects if enabled if (m_vdc.s.control & 0x20 && scanline <= 242) { - /* Quad objects */ + // quad objects for (int i = ARRAY_LENGTH(m_vdc.s.quad) - 1; i >= 0; i--) { int y = m_vdc.s.quad[i].single[0].y; + if (is_ntsc() && y < 0xe) + continue; - // Character height is always determined by the height of the 4th character - int height = 8 - (((y >> 1) + m_vdc.s.quad[i].single[3].ptr) & 7); - if (height == 1) height = 8; + // character height is always determined by the height of the 4th character + int height = 7 - (((y >> 1) + m_vdc.s.quad[i].single[3].ptr) & 7); + if (height == 0) height = 8; if (y <= scanline && scanline < y + height * 2) { @@ -590,92 +633,37 @@ u32 i8244_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, con for (int j = 0; j < ARRAY_LENGTH(m_vdc.s.quad[0].single); j++, x += 16) { - u16 color = 8 + ((m_vdc.s.quad[i].single[j].color >> 1) & 0x07); int offset = (m_vdc.s.quad[i].single[j].ptr | ((m_vdc.s.quad[i].single[j].color & 0x01) << 8)) + (y >> 1) + ((scanline - y) >> 1); - u8 chr = m_charset[offset & 0x1ff]; - for (u8 m = 0x80; m > 0; m >>= 1, x += 2) - { - if (chr & m) - { - for (int px = x; px < x + 2; px++) - { - if (cliprect.contains(px, scanline)) - { - // Check collision with self - u8 colx = m_collision_map[px]; - if (colx & 0x80) - { - colx &= ~0x80; - m_control_status |= 0x80; - } - - // Check if we collide with an already drawn source object - if (m_vdc.s.collision & colx) - m_collision_status |= 0x80; - - // Check if an already drawn object would collide with us - if (m_vdc.s.collision & 0x80) - m_collision_status |= colx; - - m_collision_map[px] |= 0x80; - bitmap.pix(scanline, px) = color; - } - } - } - } + u16 color = 8 + ((m_vdc.s.quad[i].single[j].color >> 1) & 0x07); + for (int cx = 0; cx < 8; cx++, x += 2) + draw_char(4 * j + 16 * i + 0x40, x, scanline, BIT(m_charset[offset & 0x1ff], cx ^ 7), color, bitmap, cliprect); } } } - /* Regular foreground objects */ + // regular foreground objects for (int i = ARRAY_LENGTH(m_vdc.s.foreground) - 1; i >= 0; i--) { int y = m_vdc.s.foreground[i].y; - int height = 8 - (((y >> 1) + m_vdc.s.foreground[i].ptr) & 7); - if (height == 1) height = 8; + if (is_ntsc() && y < 0xe) + continue; + + int height = 7 - (((y >> 1) + m_vdc.s.foreground[i].ptr) & 7); + if (height == 0) height = 8; if (y <= scanline && scanline < y + height * 2) { - u16 color = 8 + ((m_vdc.s.foreground[i].color >> 1) & 0x07); int offset = (m_vdc.s.foreground[i].ptr | ((m_vdc.s.foreground[i].color & 0x01) << 8)) + (y >> 1) + ((scanline - y) >> 1); - u8 chr = m_charset[offset & 0x1ff]; - int x = (m_vdc.s.foreground[i].x + 5) * 2; - for (u8 m = 0x80; m > 0; m >>= 1, x += 2) - { - if (chr & m) - { - for (int px = x; px < x + 2; px++) - { - if (cliprect.contains(px, scanline)) - { - // Check collision with self - u8 colx = m_collision_map[px]; - if (colx & 0x80) - { - colx &= ~0x80; - m_control_status |= 0x80; - } - - // Check if we collide with an already drawn source object - if (m_vdc.s.collision & colx) - m_collision_status |= 0x80; - - // Check if an already drawn object would collide with us - if (m_vdc.s.collision & 0x80) - m_collision_status |= colx; - - m_collision_map[px] |= 0x80; - bitmap.pix(scanline, px) = color; - } - } - } - } + int x = (m_vdc.s.foreground[i].x + 5) * 2; + u16 color = 8 + ((m_vdc.s.foreground[i].color >> 1) & 0x07); + for (int cx = 0; cx < 8; cx++, x += 2) + draw_char(4 * i + 0x10, x, scanline, BIT(m_charset[offset & 0x1ff], cx ^ 7), color, bitmap, cliprect); } } - /* Sprites */ + // sprites for (int i = ARRAY_LENGTH(m_vdc.s.sprites) - 1; i >= 0; i--) { int y = m_vdc.s.sprites[i].y; @@ -692,13 +680,13 @@ u32 i8244_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, con switch (m_vdc.s.sprites[i].color & 0x03) { - case 1: // Xg attribute set + case 1: // Xg attribute set x_shift = 1; break; - case 2: // S attribute set + case 2: // S attribute set x_shift = (((scanline - y) / zoom_px) & 0x01) ^ 0x01; break; - case 3: // Xg and S attributes set + case 3: // Xg and S attributes set x_shift = ((scanline - y) / zoom_px) & 0x01; break; default: @@ -717,11 +705,11 @@ u32 i8244_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, con { u8 mask = 1 << i; - // Check if we collide with an already drawn source object + // check if we collide with an already drawn source object if (m_vdc.s.collision & m_collision_map[px]) m_collision_status |= mask; - // Check if an already drawn object would collide with us + // check if an already drawn object would collide with us if (m_vdc.s.collision & mask) m_collision_status |= m_collision_map[px]; diff --git a/src/devices/video/i8244.h b/src/devices/video/i8244.h index d5ad74f832d..5facb28a5a8 100644 --- a/src/devices/video/i8244.h +++ b/src/devices/video/i8244.h @@ -117,12 +117,15 @@ protected: virtual void sound_stream_update(sound_stream &stream, std::vector const &inputs, std::vector &outputs) override; virtual void set_default_params(); + inline bool is_ntsc() { return m_vtotal == 263; } int get_y_beam(); int get_x_beam(); offs_t fix_register_mirrors(offs_t offset); bool invalid_register(offs_t offset, bool rw); + void draw_char(u8 index, int x, int y, u8 pixel, u16 color, bitmap_ind16 &bitmap, const rectangle &cliprect); + /* timers */ static constexpr device_timer_id TIMER_VBLANK_START = 0; static constexpr device_timer_id TIMER_HBLANK_START = 1; @@ -153,6 +156,7 @@ protected: vdc_t m_vdc; u8 m_collision_map[0x200]; + u8 m_priority_map[0x200]; u8 m_x_beam_pos = 0; u8 m_y_beam_pos = 0; diff --git a/src/mame/drivers/odyssey2.cpp b/src/mame/drivers/odyssey2.cpp index 0410f492b3a..c8b6f8a0576 100644 --- a/src/mame/drivers/odyssey2.cpp +++ b/src/mame/drivers/odyssey2.cpp @@ -22,7 +22,7 @@ Videopac consoles: - Radiola Jet 25 (France) - Siera Videopac Computer G7000 (France) - Schneider Videopac 7000 (Germany) -- Philips Videopac G7200 (Europe, Videopac with built-in screen) +- Philips Videopac G7200 (Europe, Videopac with built-in B/W screen) - Philips Videojeu N60 (France) Videopac+ consoles: @@ -56,10 +56,13 @@ TODO: and writes to the ptr/color registers, but does not increment the Y regs - screen resolution is not strictly defined, height(243) is correct, but horizontal overscan differs depending on monitor/tv? see syracuse for overscan -- 824x on the real console, overlapping characters on eachother will cause - glitches (it is used to an advantage in some as-of-yet undumped homebrews) -- 8244(NTSC) is not supposed to show characters near the upper border, but - hiding them will cause bugs in some Euro games +- 824x on the real console, overlapping major system characters with eachother + (including transparent pixels) will cause glitches and instability, it can even + overwrite the VDC color and pointer registers + * gunfight: accidental usage, sometimes causes 1-frame glitches near bullet + * powerlrd: occurs at pink mountain on the right, it's not 1:1 identical on MAME + * several homebrews by Rafael: precisely placed overlap to force character + color to change to white, see for example Piggyback Planet and Mean Santa - 8245(PAL) video timing is not 100% accurate, though vtotal and htotal should be correct. The 8245 is put into slave mode at vblank, timing signals and vblank IRQ are taken over during it (the Videopac pcb even has extra TTL to @@ -89,6 +92,8 @@ TODO: BTANB: - a lot of PAL games have problems on NTSC (the other way around, not so much) + * most-common cause is due to shorter vblank, less time to prepare frame + * characters are not rendered near upper border on 8244 (eg. tutank, chezmxme) - g7400 games don't look correct on odyssey3 and vice versa: ef934x graphics are placed lower on odyssey3 - Blackjack (Videopac 5) does not work on G7400, caused by a removed BIOS routine -- cgit v1.2.3