summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author Vincent-Halver <Vincent.Halver@gmail.com>2025-08-09 06:55:55 -0700
committer GitHub <noreply@github.com>2025-08-09 09:55:55 -0400
commitdf793d30aae479a7a19abd09dfb90644d8bf3c67 (patch)
tree2e17ff098156dfd9d55159929ab653e39af53deb
parentf3a665ce23ba9e40282d530554c9a73c0947e3da (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.cpp2
-rw-r--r--src/mame/philips/mcd212.cpp47
-rw-r--r--src/mame/philips/mcd212.h3
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;