catnmous: better approximation of colours, should be pretty close now

This commit is contained in:
Vas Crabb 2016-02-08 15:38:02 +11:00
parent f489eeaaef
commit 695febb4ac
3 changed files with 119 additions and 63 deletions

View File

@ -74,9 +74,6 @@
TODO: TODO:
- work out where all the magic layer offsets come from - work out where all the magic layer offsets come from
- need to confirm colour weight resistors on catnmous (detailed photo required):
R58, R59, R60, R61, R62, R65, R66, R67, R68, R69, R72, R73, R74, R75
(network connected between 11M, 12M, Q5, Q7, Q8)
- sound in laserbat (with schematics) and in catnmous - sound in laserbat (with schematics) and in catnmous
*/ */
@ -497,9 +494,6 @@ static MACHINE_CONFIG_START( laserbat_base, laserbat_state_base )
MCFG_SCREEN_UPDATE_DRIVER(laserbat_state_base, screen_update_laserbat) MCFG_SCREEN_UPDATE_DRIVER(laserbat_state_base, screen_update_laserbat)
MCFG_SCREEN_PALETTE("palette") MCFG_SCREEN_PALETTE("palette")
MCFG_PALETTE_ADD("palette", 256)
MCFG_PALETTE_INIT_OWNER(laserbat_state_base, laserbat)
MCFG_PLS100_ADD("gfxmix") MCFG_PLS100_ADD("gfxmix")
MCFG_DEVICE_ADD("pvi1", S2636, XTAL_14_31818MHz/3) MCFG_DEVICE_ADD("pvi1", S2636, XTAL_14_31818MHz/3)
@ -520,6 +514,10 @@ MACHINE_CONFIG_END
static MACHINE_CONFIG_DERIVED_CLASS( laserbat, laserbat_base, laserbat_state ) static MACHINE_CONFIG_DERIVED_CLASS( laserbat, laserbat_base, laserbat_state )
// video hardware
MCFG_PALETTE_ADD("palette", 256)
MCFG_PALETTE_INIT_OWNER(laserbat_state, laserbat)
// sound board devices // sound board devices
MCFG_SPEAKER_STANDARD_MONO("mono") MCFG_SPEAKER_STANDARD_MONO("mono")
@ -548,6 +546,10 @@ MACHINE_CONFIG_END
static MACHINE_CONFIG_DERIVED_CLASS( catnmous, laserbat_base, catnmous_state ) static MACHINE_CONFIG_DERIVED_CLASS( catnmous, laserbat_base, catnmous_state )
// video hardware
MCFG_PALETTE_ADD("palette", 256)
MCFG_PALETTE_INIT_OWNER(catnmous_state, catnmous)
// sound board devices // sound board devices
MCFG_CPU_ADD("audiocpu", M6802, 3580000) // ? MCFG_CPU_ADD("audiocpu", M6802, 3580000) // ?
MCFG_CPU_PROGRAM_MAP(catnmous_sound_map) MCFG_CPU_PROGRAM_MAP(catnmous_sound_map)
@ -758,5 +760,5 @@ ROM_END
GAME( 1981, laserbat, 0, laserbat, laserbat, laserbat_state_base, laserbat, ROT0, "Zaccaria", "Laser Battle", MACHINE_IMPERFECT_SOUND | MACHINE_SUPPORTS_SAVE ) GAME( 1981, laserbat, 0, laserbat, laserbat, laserbat_state_base, laserbat, ROT0, "Zaccaria", "Laser Battle", MACHINE_IMPERFECT_SOUND | MACHINE_SUPPORTS_SAVE )
GAME( 1981, lazarian, laserbat, laserbat, lazarian, laserbat_state_base, laserbat, ROT0, "Zaccaria (Bally Midway license)", "Lazarian", MACHINE_IMPERFECT_SOUND | MACHINE_SUPPORTS_SAVE ) GAME( 1981, lazarian, laserbat, laserbat, lazarian, laserbat_state_base, laserbat, ROT0, "Zaccaria (Bally Midway license)", "Lazarian", MACHINE_IMPERFECT_SOUND | MACHINE_SUPPORTS_SAVE )
GAME( 1982, catnmous, 0, catnmous, catnmous, laserbat_state_base, laserbat, ROT90, "Zaccaria", "Cat and Mouse (set 1)", MACHINE_IMPERFECT_COLORS | MACHINE_IMPERFECT_SOUND | MACHINE_SUPPORTS_SAVE ) GAME( 1982, catnmous, 0, catnmous, catnmous, laserbat_state_base, laserbat, ROT90, "Zaccaria", "Cat and Mouse (set 1)", MACHINE_IMPERFECT_SOUND | MACHINE_SUPPORTS_SAVE )
GAME( 1982, catnmousa, catnmous, catnmous, catnmous, laserbat_state_base, laserbat, ROT90, "Zaccaria", "Cat and Mouse (set 2)", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_COLORS | MACHINE_IMPERFECT_SOUND | MACHINE_SUPPORTS_SAVE ) GAME( 1982, catnmousa, catnmous, catnmous, catnmous, laserbat_state_base, laserbat, ROT90, "Zaccaria", "Cat and Mouse (set 2)", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND | MACHINE_SUPPORTS_SAVE )

View File

@ -65,9 +65,6 @@ public:
DECLARE_DRIVER_INIT(laserbat); DECLARE_DRIVER_INIT(laserbat);
INTERRUPT_GEN_MEMBER(laserbat_interrupt); INTERRUPT_GEN_MEMBER(laserbat_interrupt);
// video initialisation
DECLARE_PALETTE_INIT(laserbat);
// video memory and control ports // video memory and control ports
DECLARE_WRITE8_MEMBER(videoram_w); DECLARE_WRITE8_MEMBER(videoram_w);
DECLARE_WRITE8_MEMBER(wcoh_w); DECLARE_WRITE8_MEMBER(wcoh_w);
@ -162,6 +159,9 @@ public:
{ {
} }
// video initialisation
DECLARE_PALETTE_INIT(laserbat);
// sound control ports // sound control ports
virtual DECLARE_WRITE8_MEMBER(csound2_w) override; virtual DECLARE_WRITE8_MEMBER(csound2_w) override;
@ -193,6 +193,9 @@ public:
{ {
} }
// video initialisation
DECLARE_PALETTE_INIT(catnmous);
// sound control ports // sound control ports
virtual DECLARE_WRITE8_MEMBER(csound1_w) override; virtual DECLARE_WRITE8_MEMBER(csound1_w) override;
virtual DECLARE_WRITE8_MEMBER(csound2_w) override; virtual DECLARE_WRITE8_MEMBER(csound2_w) override;

View File

@ -82,58 +82,6 @@
#include "includes/laserbat.h" #include "includes/laserbat.h"
PALETTE_INIT_MEMBER(laserbat_state_base, laserbat)
{
/*
Uses GRBGRBGR pixel format. The two topmost bist are the LSBs
for red and green. LSB for blue is always effectively 1. The
middle group is the MSB. Yet another crazy thing they did.
Each colour channel has an emitter follower buffer amlpifier
biased with a 1k resistor to +5V and a 3k3 resistor to ground.
Output is adjusted by connecting additional resistors across the
leg to ground using an open collector buffer - 270R, 820R and
1k0 for unset MSB to LSB, respectively (blue has no LSB so it
has no 1k0 resistor).
Assuming 0.7V drop across the emitter follower and no drop
across the open collector buffer, these are the approximate
output voltages:
0.0000, 0.1031, 0.1324, 0.2987 , 0.7194, 1.2821, 1.4711, 3.1372
The game never sets the colour to any value above 4, effectively
treating it as 5-level red and green, and 3-level blue, for a
total of 75 usable colours.
From the fact that there's no DC offset on red and green, and
the highest value used is just over 0.7V, I'm guessing the game
expects to drive a standard 0.7V RGB monitor, and higher colour
values would simply saturate the input. To make it not look
like the inside of a coal mine, I've applied gamma decoding at
2.2
However there's that nasty DC offset on the blue caused by the
fact that it has no LSB, but it's eliminated at the AC-coupling
of the input and output of the buffer amplifier on the monitor
interface board. I'm treating it as though it has the same gain
as the other channels. After gamma adjustment, medium red and
medium blue as used by the game have almost the same intensity.
*/
int const weights[] = { 0, 107, 120, 173, 255, 255, 255, 255 };
int const blue_weights[] = { 0, 0, 60, 121, 241, 255, 255, 255, 255 };
for (int entry = 0; palette.entries() > entry; entry++)
{
UINT8 const bits(entry & 0xff);
UINT8 const r(((bits & 0x01) << 1) | ((bits & 0x08) >> 1) | ((bits & 0x40) >> 6));
UINT8 const g(((bits & 0x02) >> 0) | ((bits & 0x10) >> 2) | ((bits & 0x80) >> 7));
UINT8 const b(((bits & 0x04) >> 1) | ((bits & 0x20) >> 3) | 0x01);
palette.set_pen_color(entry, rgb_t(weights[r], weights[g], blue_weights[b]));
}
}
WRITE8_MEMBER(laserbat_state_base::videoram_w) WRITE8_MEMBER(laserbat_state_base::videoram_w)
{ {
if (!m_mpx_bkeff) if (!m_mpx_bkeff)
@ -375,3 +323,106 @@ TIMER_CALLBACK_MEMBER(laserbat_state_base::video_line)
} }
} }
} }
PALETTE_INIT_MEMBER(laserbat_state, laserbat)
{
/*
Uses GRBGRBGR pixel format. The two topmost bist are the LSBs
for red and green. LSB for blue is always effectively 1. The
middle group is the MSB. Yet another crazy thing they did.
Each colour channel has an emitter follower buffer amlpifier
biased with a 1k resistor to +5V and a 3k3 resistor to ground.
Output is adjusted by connecting additional resistors across the
leg to ground using an open collector buffer - 270R, 820R and
1k0 for unset MSB to LSB, respectively (blue has no LSB so it
has no 1k0 resistor).
Assuming 0.7V drop across the emitter follower and no drop
across the open collector buffer, these are the approximate
output voltages:
0.0000, 0.1031, 0.1324, 0.2987, 0.7194, 1.2821, 1.4711, 3.1372
The game never sets the colour to any value above 4, effectively
treating it as 5-level red and green, and 3-level blue, for a
total of 75 usable colours.
From the fact that there's no DC offset on red and green, and
the highest value used is just over 0.7V, I'm guessing the game
expects to drive a standard 0.7V RGB monitor, and higher colour
values would simply saturate the input. To make it not look
like the inside of a coal mine, I've applied gamma decoding at
2.2
However there's that nasty DC offset on the blue caused by the
fact that it has no LSB, but it's eliminated at the AC-coupling
of the input and output of the buffer amplifier on the monitor
interface board. I'm treating it as though it has the same gain
as the other channels. After gamma adjustment, medium red and
medium blue as used by the game have almost the same intensity.
*/
int const weights[] = { 0, 107, 120, 173, 255, 255, 255, 255 };
int const blue_weights[] = { 0, 0, 60, 121, 241, 255, 255, 255 };
for (int entry = 0; palette.entries() > entry; entry++)
{
UINT8 const bits(entry & 0xff);
UINT8 const r(((bits & 0x01) << 1) | ((bits & 0x08) >> 1) | ((bits & 0x40) >> 6));
UINT8 const g(((bits & 0x02) >> 0) | ((bits & 0x10) >> 2) | ((bits & 0x80) >> 7));
UINT8 const b(((bits & 0x04) >> 1) | ((bits & 0x20) >> 3) | 0x01);
palette.set_pen_color(entry, rgb_t(weights[r], weights[g], blue_weights[b]));
}
}
PALETTE_INIT_MEMBER(catnmous_state, catnmous)
{
/*
Uses GRBGRBGR pixel format. The two topmost bist are the LSBs
for red and green. The middle group is the MSB. Yet another
crazy thing they did.
Each colour channel has an emitter follower buffer amlpifier
biased with a 1k resistor to +5V and a 3k3 resistor to ground.
Output is adjusted by connecting additional resistors across the
leg to ground using an open collector buffer. Red and green use
560R, 820R and 1k0 for unset MSB to LSB, respectively. Blue
uses 47R and 820R on the PCB we have a photo of, although the
47R resistor looks like it could be a bad repair (opposite
orientation and burn marks on PCB).
Assuming 0.7V drop across the emitter follower and no drop
across the open collector buffer, these are the approximate
output voltages for red and green:
0.2419, 0.4606, 0.5229, 0.7194, 0.9188, 1.2821, 1.4711, 3.1372
The game uses all colour values except 4. The DC offset will be
eliminated by the AC coupling on the monitor interface board.
The differences steps aren't very linear, they vary from 0.06V
to 0.36V with no particular order. The input would be expected
to saturate somewhere inside the big jump to the highest level.
Let's assume the 47R resistor is a bad repair and it's supposed
to be 470R. That gives us these output voltages for blue:
0.3752, 0.7574, 1.2821, 3.1372
To make life easier, I'll assume the monitor is expected to have
half the gain of a standard monitor and no gamma decoding is
necessary.
*/
int const weights[] = { 0, 40, 51, 87, 123, 189, 224, 255 };
int const blue_weights[] = { 0, 70, 165, 255 };
for (int entry = 0; palette.entries() > entry; entry++)
{
UINT8 const bits(entry & 0xff);
UINT8 const r(((bits & 0x01) << 1) | ((bits & 0x08) >> 1) | ((bits & 0x40) >> 6));
UINT8 const g(((bits & 0x02) >> 0) | ((bits & 0x10) >> 2) | ((bits & 0x80) >> 7));
UINT8 const b(((bits & 0x04) >> 2) | ((bits & 0x20) >> 4));
palette.set_pen_color(entry, rgb_t(weights[r], weights[g], blue_weights[b]));
}
}