pwm_display: add support for multi-state outputs per brightness level

This commit is contained in:
hap 2022-02-25 19:51:30 +01:00
parent d196d072ff
commit fd45e9cfad
3 changed files with 53 additions and 75 deletions

View File

@ -15,8 +15,12 @@ or write_row to set them.
Display element states are sent to output tags "y.x" where y is the matrix row Display element states are sent to output tags "y.x" where y is the matrix row
number, x is the row bit. It is also sent to "y.a" for all rows. The output state number, x is the row bit. It is also sent to "y.a" for all rows. The output state
is 0 for off, and >0 for on, depending on brightness level. If segmask is defined, is 0 for off, and >0 for on, depending on brightness level.
it is also sent to "digity", for use with multi-state elements, eg. 7seg leds.
If segmask is defined, it is also sent to "multiy.b" where b is brightness level,
for use with multi-state elements. This usecase is not common though (one example
is Coleco Quarterback where some digit segments are brighter). And when brightness
level does not matter, it is also sent to "digity", for common 7seg leds.
If you use this device in a slot, or use multiple of them (or just don't want If you use this device in a slot, or use multiple of them (or just don't want
to use the default output tags), set a callback. to use the default output tags), set a callback.
@ -25,9 +29,9 @@ Brightness tresholds (0.0 to 1.0) indicate how long an element was powered on
in the last frame, eg. 0.01 means a minimum on-time for 1%. Some games use two in the last frame, eg. 0.01 means a minimum on-time for 1%. Some games use two
levels of brightness by strobing elements longer. levels of brightness by strobing elements longer.
TODO: TODO:
- SVG screens and rendlay digit elements don't support multiple brightness levels - SVG screens and rendlay digit elements don't support multiple brightness levels,
the latter can be worked around with by stacking digits on top of eachother
*/ */
@ -47,9 +51,11 @@ pwm_display_device::pwm_display_device(const machine_config &mconfig, const char
device_t(mconfig, PWM_DISPLAY, tag, owner, clock), device_t(mconfig, PWM_DISPLAY, tag, owner, clock),
m_out_x(*this, "%u.%u", 0U, 0U), m_out_x(*this, "%u.%u", 0U, 0U),
m_out_a(*this, "%u.a", 0U), m_out_a(*this, "%u.a", 0U),
m_out_multi(*this, "multi%u.%u", 0U, 0U),
m_out_digit(*this, "digit%u", 0U), m_out_digit(*this, "digit%u", 0U),
m_output_x_cb(*this), m_output_x_cb(*this),
m_output_a_cb(*this), m_output_a_cb(*this),
m_output_multi_cb(*this),
m_output_digit_cb(*this) m_output_digit_cb(*this)
{ {
// set defaults // set defaults
@ -70,15 +76,17 @@ pwm_display_device::pwm_display_device(const machine_config &mconfig, const char
void pwm_display_device::device_start() void pwm_display_device::device_start()
{ {
// resolve handlers // resolve handlers
m_external_output = !m_output_x_cb.isnull() || !m_output_a_cb.isnull() || !m_output_digit_cb.isnull(); m_external_output = !m_output_x_cb.isnull() || !m_output_a_cb.isnull() || !m_output_multi_cb.isnull() || !m_output_digit_cb.isnull();
m_output_x_cb.resolve_safe(); m_output_x_cb.resolve_safe();
m_output_a_cb.resolve_safe(); m_output_a_cb.resolve_safe();
m_output_multi_cb.resolve_safe();
m_output_digit_cb.resolve_safe(); m_output_digit_cb.resolve_safe();
if (!m_external_output) if (!m_external_output)
{ {
m_out_x.resolve(); m_out_x.resolve();
m_out_a.resolve(); m_out_a.resolve();
m_out_multi.resolve();
m_out_digit.resolve(); m_out_digit.resolve();
} }
@ -191,13 +199,12 @@ TIMER_CALLBACK_MEMBER(pwm_display_device::frame_tick)
const double factor1 = 1.0 - factor0; const double factor1 = 1.0 - factor0;
// determine brightness cutoff // determine brightness cutoff
u8 max_levels = 1;
for (; m_levels[max_levels] < 1.0; max_levels++) { ; }
double cutoff = m_level_max; double cutoff = m_level_max;
if (cutoff == 0.0) if (cutoff == 0.0)
{ cutoff = 4 * m_levels[max_levels - 1];
u8 level;
for (level = 1; m_levels[level] < 1.0; level++) { ; }
cutoff = 4 * m_levels[level - 1];
}
if (cutoff > 1.0) if (cutoff > 1.0)
cutoff = 1.0; cutoff = 1.0;
@ -205,7 +212,8 @@ TIMER_CALLBACK_MEMBER(pwm_display_device::frame_tick)
for (int y = 0; y < m_height; y++) for (int y = 0; y < m_height; y++)
{ {
u64 row = 0; u64 multi_row[0x40];
std::fill(std::begin(multi_row), std::end(multi_row), 0);
for (int x = 0; x <= m_width; x++) for (int x = 0; x <= m_width; x++)
{ {
@ -221,8 +229,7 @@ TIMER_CALLBACK_MEMBER(pwm_display_device::frame_tick)
// output to y.x, or y.a when always-on // output to y.x, or y.a when always-on
if (x != m_width) if (x != m_width)
{ {
if (level > m_level_min) multi_row[level] |= (u64(1) << x);
row |= (u64(1) << x);
if (m_external_output) if (m_external_output)
m_output_x_cb(x << 6 | y, level); m_output_x_cb(x << 6 | y, level);
@ -238,15 +245,29 @@ TIMER_CALLBACK_MEMBER(pwm_display_device::frame_tick)
} }
} }
// output to digity (does not support multiple brightness levels) // multi-state outputs
if (m_segmask[y] != 0) if (m_segmask[y] != 0)
{ {
row &= m_segmask[y]; u64 digit_row = 0;
for (int b = 0; b <= max_levels; b++)
{
multi_row[b] &= m_segmask[y];
if (b > m_level_min)
digit_row |= multi_row[b];
// output to multiy.b
if (m_external_output)
m_output_multi_cb(b << 6 | y, digit_row);
else
m_out_multi[y][b] = multi_row[b];
}
// output to digity (single brightness level)
if (m_external_output) if (m_external_output)
m_output_digit_cb(y, row); m_output_digit_cb(y, digit_row);
else else
m_out_digit[y] = row; m_out_digit[y] = digit_row;
} }
} }

View File

@ -29,6 +29,7 @@ public:
// output callbacks when not using the default output tags // output callbacks when not using the default output tags
auto output_x() { return m_output_x_cb.bind(); } // x = offset >> 6, y = offset & 0x3f auto output_x() { return m_output_x_cb.bind(); } // x = offset >> 6, y = offset & 0x3f
auto output_a() { return m_output_a_cb.bind(); } auto output_a() { return m_output_a_cb.bind(); }
auto output_multi() { return m_output_multi_cb.bind(); } // b = offset >> 6, y = offset & 0x3f
auto output_digit() { return m_output_digit_cb.bind(); } auto output_digit() { return m_output_digit_cb.bind(); }
void reset_bri_levels() { std::fill(std::begin(m_levels), std::end(m_levels), 1.0); } void reset_bri_levels() { std::fill(std::begin(m_levels), std::end(m_levels), 1.0); }
@ -68,10 +69,12 @@ protected:
private: private:
output_finder<0x40, 0x40> m_out_x; output_finder<0x40, 0x40> m_out_x;
output_finder<0x40> m_out_a; output_finder<0x40> m_out_a;
output_finder<0x40, 0x40> m_out_multi;
output_finder<0x40> m_out_digit; output_finder<0x40> m_out_digit;
devcb_write8 m_output_x_cb; devcb_write8 m_output_x_cb;
devcb_write8 m_output_a_cb; devcb_write8 m_output_a_cb;
devcb_write64 m_output_multi_cb;
devcb_write64 m_output_digit_cb; devcb_write64 m_output_digit_cb;
bool m_external_output; bool m_external_output;

View File

@ -57,15 +57,15 @@ license:CC0
</element> </element>
<element name="digit" defstate="0"> <element name="digit" defstate="0">
<led7seg><color red="1.0" green="0.25" blue="0.26" /></led7seg> <led7seg alpha="0.0833"><color red="1.0" green="0.25" blue="0.26" /></led7seg>
</element> </element>
<element name="seg" defstate="0"> <element name="seg" defstate="0">
<rect state="0"><color red="0.13" green="0.0325" blue="0.0338" /></rect> <rect state="0"><color red="0.13" green="0.0325" blue="0.0338" /></rect>
<rect state="1"><color red="0.5" green="0.125" blue="0.13" /></rect> <rect state="1"><color red="0.5" green="0.125" blue="0.13" /></rect>
<rect state="2"><color red="1.0" green="0.25" blue="0.26" /></rect> <rect state="2"><color red="1.0" green="0.25" blue="0.26" /></rect>
</element> </element>
<element name="mask" defstate="0"> <element name="mask">
<disk state="1"><color red="0" green="0" blue="0" /></disk> <rect><color red="0" green="0" blue="0" /></rect>
</element> </element>
@ -141,62 +141,16 @@ license:CC0
<element ref="static_white"><bounds x="344" y="56" width="4" height="1" /></element> <element ref="static_white"><bounds x="344" y="56" width="4" height="1" /></element>
<!-- leds --> <!-- leds -->
<element name="digit0" ref="digit"><bounds x="3" y="-15.5" width="24" height="32" /></element> <repeat count="9">
<element name="0.8" ref="seg"><bounds x="7" y="42.5" width="15" height="3" /></element> <param name="xd" start="3" increment="44" />
<element name="0.9" ref="seg"><bounds x="7" y="71.5" width="15" height="3" /></element> <param name="xs" start="7" increment="44" />
<param name="i" start="0" increment="1" />
<element name="digit1" ref="digit"><bounds x="47" y="-15.5" width="24" height="32" /></element> <element name="multi~i~.1" ref="digit"><bounds x="~xd~" y="-15.5" width="24" height="32" /><color alpha="0.5" /></element>
<element name="1.8" ref="seg"><bounds x="51" y="42.5" width="15" height="3" /></element> <element name="multi~i~.2" ref="digit"><bounds x="~xd~" y="-15.5" width="24" height="32" /></element>
<element name="1.9" ref="seg"><bounds x="51" y="71.5" width="15" height="3" /></element> <element name="~i~.8" ref="seg"><bounds x="~xs~" y="42.5" width="15" height="3" /></element>
<element name="~i~.9" ref="seg"><bounds x="~xs~" y="71.5" width="15" height="3" /></element>
<element name="digit2" ref="digit"><bounds x="91" y="-15.5" width="24" height="32" /></element> </repeat>
<element name="2.8" ref="seg"><bounds x="95" y="42.5" width="15" height="3" /></element>
<element name="2.9" ref="seg"><bounds x="95" y="71.5" width="15" height="3" /></element>
<element name="digit3" ref="digit"><bounds x="135" y="-15.5" width="24" height="32" /></element>
<element name="3.8" ref="seg"><bounds x="139" y="42.5" width="15" height="3" /></element>
<element name="3.9" ref="seg"><bounds x="139" y="71.5" width="15" height="3" /></element>
<element name="digit4" ref="digit"><bounds x="179" y="-15.5" width="24" height="32" /></element>
<element name="4.8" ref="seg"><bounds x="183" y="42.5" width="15" height="3" /></element>
<element name="4.9" ref="seg"><bounds x="183" y="71.5" width="15" height="3" /></element>
<element name="digit5" ref="digit"><bounds x="223" y="-15.5" width="24" height="32" /></element>
<element name="5.8" ref="seg"><bounds x="227" y="42.5" width="15" height="3" /></element>
<element name="5.9" ref="seg"><bounds x="227" y="71.5" width="15" height="3" /></element>
<element name="digit6" ref="digit"><bounds x="267" y="-15.5" width="24" height="32" /></element>
<element name="6.8" ref="seg"><bounds x="271" y="42.5" width="15" height="3" /></element>
<element name="6.9" ref="seg"><bounds x="271" y="71.5" width="15" height="3" /></element>
<element name="digit7" ref="digit"><bounds x="311" y="-15.5" width="24" height="32" /></element>
<element name="7.8" ref="seg"><bounds x="315" y="42.5" width="15" height="3" /></element>
<element name="7.9" ref="seg"><bounds x="315" y="71.5" width="15" height="3" /></element>
<element name="digit8" ref="digit"><bounds x="355" y="-15.5" width="24" height="32" /></element>
<element name="8.8" ref="seg"><bounds x="359" y="42.5" width="15" height="3" /></element>
<element name="8.9" ref="seg"><bounds x="359" y="71.5" width="15" height="3" /></element>
<!-- digit masks -->
<element name="0.0" ref="mask"><bounds x="8" y="-17" width="17" height="6" /><color alpha="0.5" /></element>
<element name="1.0" ref="mask"><bounds x="52" y="-17" width="17" height="6" /><color alpha="0.5" /></element>
<element name="2.0" ref="mask"><bounds x="96" y="-17" width="17" height="6" /><color alpha="0.5" /></element>
<element name="3.0" ref="mask"><bounds x="140" y="-17" width="17" height="6" /><color alpha="0.5" /></element>
<element name="4.0" ref="mask"><bounds x="184" y="-17" width="17" height="6" /><color alpha="0.5" /></element>
<element name="5.0" ref="mask"><bounds x="228" y="-17" width="17" height="6" /><color alpha="0.5" /></element>
<element name="6.0" ref="mask"><bounds x="272" y="-17" width="17" height="6" /><color alpha="0.5" /></element>
<element name="7.0" ref="mask"><bounds x="316" y="-17" width="17" height="6" /><color alpha="0.5" /></element>
<element name="8.0" ref="mask"><bounds x="360" y="-17" width="17" height="6" /><color alpha="0.5" /></element>
<element name="0.3" ref="mask"><bounds x="5" y="12" width="17" height="6" /><color alpha="0.5" /></element>
<element name="1.3" ref="mask"><bounds x="49" y="12" width="17" height="6" /><color alpha="0.5" /></element>
<element name="2.3" ref="mask"><bounds x="93" y="12" width="17" height="6" /><color alpha="0.5" /></element>
<element name="3.3" ref="mask"><bounds x="137" y="12" width="17" height="6" /><color alpha="0.5" /></element>
<element name="4.3" ref="mask"><bounds x="181" y="12" width="17" height="6" /><color alpha="0.5" /></element>
<element name="5.3" ref="mask"><bounds x="225" y="12" width="17" height="6" /><color alpha="0.5" /></element>
<element name="6.3" ref="mask"><bounds x="269" y="12" width="17" height="6" /><color alpha="0.5" /></element>
<element name="7.3" ref="mask"><bounds x="313" y="12" width="17" height="6" /><color alpha="0.5" /></element>
<element name="8.3" ref="mask"><bounds x="357" y="12" width="17" height="6" /><color alpha="0.5" /></element>
</view> </view>
</mamelayout> </mamelayout>