diff options
| author | 2025-08-09 06:55:55 -0700 | |
|---|---|---|
| committer | 2025-08-09 09:55:55 -0400 | |
| commit | df793d30aae479a7a19abd09dfb90644d8bf3c67 (patch) | |
| tree | 2e17ff098156dfd9d55159929ab653e39af53deb | |
| parent | f3a665ce23ba9e40282d530554c9a73c0947e3da (diff) | |
CD-i: Add Interlace Graphics (#13997)
* CD-i: Doubles Vertical Resolution
Minimal code to double the vertical resolution for #13231 . The result is a slightly crisper looking image on most monitors due to better upscaling on images are have less oblique pixels.
This was tested minimally and seems stable.
Something closer to a proper interlaced image can be accomplished using the _PA bit, however current screen blanks between frames preventing the parity bit from being able to produce a correct interlace image yet.
* CD-i: Remove excess vertical resolution
* Use 2x clock multiplier
* CD-i: Add Interlaced Graphics
Fixes #13231
* CD-i: Toggle Interlace Effect
When the interlace bit is off, line-duplication is re-enabled. This ensures the interlace effect is only visible when the game declares the output to be interlaced.
* CD-i: Fix interlaced line offset
In some cases, such as during startup, the line length of the interlaced line is impacted. This corrects the offset.
* CD-i: Fix Interlace Clock Speed
| -rw-r--r-- | src/mame/philips/cdi.cpp | 2 | ||||
| -rw-r--r-- | src/mame/philips/mcd212.cpp | 47 | ||||
| -rw-r--r-- | src/mame/philips/mcd212.h | 3 |
3 files changed, 38 insertions, 14 deletions
diff --git a/src/mame/philips/cdi.cpp b/src/mame/philips/cdi.cpp index 37f74a9b004..6dd4e64162b 100644 --- a/src/mame/philips/cdi.cpp +++ b/src/mame/philips/cdi.cpp @@ -434,7 +434,7 @@ void cdi_state::cdimono1_base(machine_config &config) m_mcd212->int_callback().set(m_maincpu, FUNC(scc68070_device::int1_w)); screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER)); - screen.set_raw(14976000, 960, 0, 768, 312, 32, 312); + screen.set_raw(960*(312*2-32)*50, 960, 0, 768, 312*2-32, 32, 312*2-32); screen.set_video_attributes(VIDEO_UPDATE_SCANLINE); screen.set_screen_update(m_mcd212, FUNC(mcd212_device::screen_update)); diff --git a/src/mame/philips/mcd212.cpp b/src/mame/philips/mcd212.cpp index 1b0691c89ea..b332f06cad5 100644 --- a/src/mame/philips/mcd212.cpp +++ b/src/mame/philips/mcd212.cpp @@ -6,7 +6,7 @@ CD-i MCD212 Video Decoder and System Controller emulation ------------------- - written by Ryan Holtz + written by Ryan Holtz, Vincent.Halver ******************************************************************************* @@ -330,13 +330,13 @@ template <int Path> void mcd212_device::process_ica() { uint16_t *ica = Path ? m_planeb.target() : m_planea.target(); - uint32_t addr = 0x200; - uint32_t cmd = 0; - const int max_to_process = m_ica_height * 120; + // LCT depends on the current frame parity + uint32_t addr = (BIT(m_csrr[0], CSR1R_PA_BIT) == 0) ? 0x200 : 0x202; + for (int i = 0; i < max_to_process; i++) { - cmd = ica[addr++] << 16; + uint32_t cmd = ica[addr++] << 16; cmd |= ica[addr++]; switch ((cmd & 0xff000000) >> 24) { @@ -666,6 +666,11 @@ void mcd212_device::mix_lines(uint32_t *plane_a, bool *transparent_a, uint32_t * if (icmB == ICM_CLUT4) mosaic_count_b >>= 1; + // If PAL and 'Standard' bit set, insert a 24px border on the left/right + uint32_t offset = (!BIT(m_dcr[0], DCR_CF_BIT) || BIT(m_csrw[0], CSR1W_ST_BIT)) ? 24 : 0; + std::fill_n(out, offset, s_4bpp_color[0]); + out += offset; + for (int x = 0; x < width; x++) { if (transparent_a[x] && transparent_b[x]) @@ -963,12 +968,19 @@ uint32_t mcd212_device::screen_update(screen_device &screen, bitmap_rgb32 &bitma bool transparent_a[768]; bool transparent_b[768]; - int scanline = screen.vpos(); + if (screen.vpos() >= m_total_height) + { + return 0; // Do nothing on the extended rows. + } + int scanline = screen.vpos(); + // Process VSR and mix if we're in the visible region if (scanline >= m_ica_height) { - uint32_t *out = &bitmap.pix(scanline); + uint32_t bitmap_line = ((scanline - m_ica_height) << 1) + m_ica_height; + uint32_t *out = &bitmap.pix(bitmap_line + (!BIT(m_csrr[0], CSR1R_PA_BIT))); + uint32_t* out2 = &bitmap.pix(bitmap_line + (BIT(m_csrr[0], CSR1R_PA_BIT))); bool draw_line = true; if (!BIT(m_dcr[0], DCR_FD_BIT) && BIT(m_csrw[0], CSR1W_ST_BIT)) @@ -985,12 +997,6 @@ uint32_t mcd212_device::screen_update(screen_device &screen, bitmap_rgb32 &bitma if (draw_line) { - // If PAL and 'Standard' bit set, insert a 24px border on the left/right - if (!BIT(m_dcr[0], DCR_CF_BIT) || BIT(m_csrw[0], CSR1W_ST_BIT)) - { - std::fill_n(out, 24, s_4bpp_color[0]); - out += 24; - } process_vsr<0>(plane_a, transparent_a); process_vsr<1>(plane_b, transparent_b); @@ -1028,6 +1034,16 @@ uint32_t mcd212_device::screen_update(screen_device &screen, bitmap_rgb32 &bitma draw_cursor(out); } + + if (BIT(m_dcr[0], DCR_SM_BIT)) { + // Interlace Output + memcpy(out2, m_interlace_field[scanline], 768 * sizeof(uint32_t)); + memcpy(m_interlace_field[scanline], out, 768 * sizeof(uint32_t)); + } + else { + // Single Field Output (duplicate lines) + memcpy(out2, out, 768 * sizeof(uint32_t)); + } } // Toggle frame parity at the end of the visible frame (even in non-interlaced mode). @@ -1118,6 +1134,9 @@ void mcd212_device::device_reset() m_ica_height = 32; m_total_height = 312; m_blink_time = 0; + for (int i = 0; i < 312; i++) { + std::fill_n(m_interlace_field[i], 768, 0); + } m_int_callback(CLEAR_LINE); @@ -1197,6 +1216,8 @@ void mcd212_device::device_start() save_item(NAME(m_blink_time)); save_item(NAME(m_blink_active)); + save_item(NAME(m_interlace_field)); + m_dca_timer = timer_alloc(FUNC(mcd212_device::dca_tick), this); m_dca_timer->adjust(attotime::never); diff --git a/src/mame/philips/mcd212.h b/src/mame/philips/mcd212.h index fe81045abec..0158c64c88c 100644 --- a/src/mame/philips/mcd212.h +++ b/src/mame/philips/mcd212.h @@ -139,6 +139,7 @@ protected: MC_OP_SHIFT = 20, CSR1R_PA = 0x20, // Parity + CSR1R_PA_BIT = 5, CSR1R_DA = 0x80, // Display Active CSR1W_BE = 0x0001, // Bus Error @@ -231,6 +232,8 @@ protected: required_shared_ptr<uint16_t> m_planea; required_shared_ptr<uint16_t> m_planeb; + uint32_t m_interlace_field[312][768]; + // internal state bool m_matte_flag[2][768]{}; int m_ica_height = 0; |
