Skip to content

CD-i: Add Interlace Graphics #13997

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Aug 9, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/mame/philips/cdi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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));

Expand Down
47 changes: 34 additions & 13 deletions src/mame/philips/mcd212.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
CD-i MCD212 Video Decoder and System Controller emulation
-------------------
written by Ryan Holtz
written by Ryan Holtz, Vincent.Halver
*******************************************************************************
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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])
Expand Down Expand Up @@ -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))
Expand All @@ -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);
Expand Down Expand Up @@ -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).
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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);

Expand Down
3 changes: 3 additions & 0 deletions src/mame/philips/mcd212.h
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ class mcd212_device : public device_t,
MC_OP_SHIFT = 20,

CSR1R_PA = 0x20, // Parity
CSR1R_PA_BIT = 5,
CSR1R_DA = 0x80, // Display Active

CSR1W_BE = 0x0001, // Bus Error
Expand Down Expand Up @@ -231,6 +232,8 @@ class mcd212_device : public device_t,
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;
Expand Down
Loading