summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatarGravatar couriersud <couriersud@gmx.org>2019-12-30 17:44:37 +0100
committerGravatarGravatar couriersud <couriersud@gmx.org>2019-12-30 17:44:37 +0100
commita1ca4208026708c80e673138a69e1e81981d7c7f (patch) (github)
tree38f0b94d1fef1966363ff95052dde1af87eb5be2
parent2318d7750bff0a71a5d75a435d04dabf1bf6234d (diff)
downloadmame-a1ca4208026708c80e673138a69e1e81981d7c7f.tar.bz2
mame-a1ca4208026708c80e673138a69e1e81981d7c7f.zip
fixedfreq: Add machine configuration. [Couriersud]
This commit also fixes a crash on Windows/bgfx by limiting screen refresh rates. Adds machine configuration switches for netlist drivers using the fixed frequency monitor. These are intended for debugging and setting up new netlist drivers. As a side effect one can emulate e.g. loss of synchronization. This commit may trigger false positives on regression testing.
-rw-r--r--src/devices/video/fixfreq.cpp396
-rw-r--r--src/devices/video/fixfreq.h160
-rw-r--r--src/mame/drivers/pong.cpp75
-rw-r--r--src/mame/layout/breakout.lay16
4 files changed, 482 insertions, 165 deletions
diff --git a/src/devices/video/fixfreq.cpp b/src/devices/video/fixfreq.cpp
index 4957a0343fa..adfcc03cdac 100644
--- a/src/devices/video/fixfreq.cpp
+++ b/src/devices/video/fixfreq.cpp
@@ -4,7 +4,7 @@
fixfreq.h
- 2013 Couriersud
+ 2013-2019 Couriersud
Fixed frequency monochrome monitor emulation
@@ -14,24 +14,51 @@
***************************************************************************/
#include "emu.h"
+#include "ui/uimain.h"
#include "rendutil.h"
#include "fixfreq.h"
-//#define VERBOSE 1
+// for quick and dirty debugging
+#define VERBOSE 0
+#define LOG_OUTPUT_FUNC printf
#include "logmacro.h"
#include <algorithm>
-/***************************************************************************
+// --------------------------------------------------------------------------
+// Fixed frequency monitor
+// --------------------------------------------------------------------------
- Fixed frequency monitor
+// device type definition
+DEFINE_DEVICE_TYPE(FIXFREQ, fixedfreq_device, "fixfreq", "Fixed-Frequency Monochrome Monitor")
-***************************************************************************/
+// --------------------------------------------------------------------------
+// Port adjuster support
+// --------------------------------------------------------------------------
+#define PORT_ADJUSTERX(_id, _name, _min, _max) \
+ PORT_START(# _id) \
+ configurer.field_alloc(IPT_ADJUSTER, (static_cast<fixedfreq_device &>(owner).monitor_val(_id)), 0xffff, ("Monitor - " _name)); \
+ PORT_MINMAX(_min, _max) PORT_CHANGED_MEMBER(DEVICE_SELF, fixedfreq_device, port_changed, _id) \
+ PORT_CONDITION("ENABLE", 0x01, EQUALS, 0x01)
+#define IOPORT_ID(_id) ioport(# _id)
-// device type definition
-DEFINE_DEVICE_TYPE(FIXFREQ, fixedfreq_device, "fixfreq", "Fixed-Frequency Monochrome Monitor")
+enum fixedfreq_tag_id_e
+{
+ HVISIBLE,
+ HFRONTPORCH,
+ HSYNC,
+ HBACKPORCH,
+ VVISIBLE,
+ VFRONTPORCH,
+ VSYNC,
+ VBACKPORCH,
+ SYNCTHRESHOLD,
+ VSYNCTHRESHOLD,
+ GAIN,
+ SCANLINE_HEIGHT
+};
void fixedfreq_monitor_state::update_sync_channel(const time_type &time, const double newval)
{
@@ -40,59 +67,77 @@ void fixedfreq_monitor_state::update_sync_channel(const time_type &time, const d
const int last_vsync = m_sig_vsync;
const int last_comp = m_sig_composite;
- m_vsync_filter += ((double) last_comp - m_vsync_filter) * (1.0 - exp(-delta_time * m_vsync_filter_timeconst));
+ m_vsync_filter += ((double) last_comp - m_vsync_filter) * (1.0 - exp(-delta_time * m_desc.vsync_filter_timeconst()));
m_sig_composite = (newval < m_desc.m_sync_threshold) ? 1 : 0 ;
- m_sig_vsync = (m_vsync_filter > m_vsync_threshold) ? 1 : 0;
+ m_sig_vsync = (m_vsync_filter > m_desc.m_vsync_threshold) ? 1 : 0;
if (!last_vsync && m_sig_vsync)
{
- //LOG("VSYNC %d %d\n", m_last_x, m_last_y + m_sig_field);
- m_last_y = m_desc.m_vbackporch - m_desc.m_vsync;
- m_intf.vsync_start_cb(std::max(time - m_last_vsync_time, m_min_frame_period));
+ LOG("VSYNC UP %f %d\n", m_last_x, m_last_y);
+ m_intf.vsync_end_cb(time - m_last_vsync_time);
+ //auto d=time - m_last_vsync_time;
+ //printf("%f\n", 1.0 / d);
m_last_vsync_time = time;
+ // FIXME: this is wrong: we need to count lines with half-scanline width
+ // to determine the field.
+ m_sig_field = last_comp; /* force false-progressive */
+ m_sig_field = (m_sig_field ^ 1) ^ last_comp; /* if there is no field switch, auto switch */
+ m_last_y = 0; //m_desc.vbackporch_width();
+
+ // discharge
+ //m_vsync_filter = 0.0;
}
else if (last_vsync && !m_sig_vsync)
{
- m_sig_field = last_comp; /* force false-progressive */
- m_sig_field = (m_sig_field ^ 1) ^ last_comp; /* if there is no field switch, auto switch */
+ LOG("VSYNC DOWN %f %d\n", m_last_x, m_last_y);
//LOG("Field: %d\n", m_sig_field);
}
if (!last_comp && m_sig_composite)
{
+ if (m_sig_vsync)
+ LOG("Hsync in vsync\n");
/* TODO - time since last hsync and field detection */
//LOG("HSYNC up %d\n", m_last_x);
- // FIXME: pixels > 50 filters some spurious hysnc on line 27 in breakout
+ // FIXME: pixels > 50 filters some spurious hysnc on line 23/24 in breakout
+ // The hsync signal transition from high to low is 7 pixels too
+ // early, goes up again after 6.8 pix and down after 7.2 pix.
+ // Therefore we need to filter early low to high transitions
+ // and base hsync on the start of the hsync signal.
if (!m_sig_vsync && (m_last_x > m_desc.m_hscale * 100))
{
m_last_y += m_desc.m_fieldcount;
m_last_x = 0;
- m_line_time = time;
+ m_line_time = time + 1.0 / m_desc.hsync_filter_timeconst();
}
- //if (m_last_y == 27) printf("HSYNC up %d %d\n", m_last_y, pixels);
+ //if (!m_sig_vsync && (m_last_x < m_desc.m_hscale * 100))
+ // printf("HSYNC up %d %f\n", m_last_y, m_last_x);
}
else if (last_comp && !m_sig_composite)
{
/* falling composite */
//LOG("HSYNC down %f %d %f\n", time * 1e6, m_last_x, m_sync_signal);
}
-
- m_sync_signal = newval;
+ m_last_sync = newval;
m_last_sync_time = time;
}
void fixedfreq_monitor_state::update_bm(const time_type &time)
{
- const float pixels = (time - m_line_time) * static_cast<time_type>(m_desc.m_hscale) / m_clock_period;
+ const float pixels = (time - m_line_time) * (double) m_desc.monitor_clock();
const int has_fields = (m_desc.m_fieldcount > 1) ? 1: 0;
+ const float fhscale(static_cast<float>(m_desc.m_hscale));
- uint32_t col(0xffff0000); // Mark sync areas
-
- if (m_sync_signal >= m_desc.m_sync_threshold)
- col = m_col;
+ //uint32_t col(0xffff0000); // Mark sync areas
+ //if (m_last_sync >= m_desc.m_sync_threshold)
+ // col = m_col;
- m_fragments.push_back({static_cast<float>(m_last_y + m_sig_field * has_fields), m_last_x, pixels, col});
+ if (!m_sig_vsync && !m_sig_composite)
+ {
+ m_fragments.push_back({static_cast<float>(m_last_y + m_sig_field * has_fields),
+ m_last_x * fhscale, pixels * fhscale, m_col});
+ }
//m_intf.plot_hline(m_last_x, m_last_y + m_sig_field * has_fields, pixels, col);
m_last_x = pixels;
}
@@ -102,11 +147,13 @@ void fixedfreq_monitor_state::update_composite_monochrome(const time_type &time,
update_bm(time);
update_sync_channel(time, data);
- int colv = (int) ((data - m_desc.m_sync_threshold) * m_desc.m_gain * 255.0);
+ //int colv = (int) ((data - m_desc.m_sync_threshold) * m_desc.m_gain * 255.0);
+ int colv = (int) ((data - 1.5) * m_desc.m_gain * 255.0);
if (colv > 255)
colv = 255;
if (colv < 0)
- m_col = 0xffff0000;
+ //m_col = 0xffff0000;
+ m_col = 0x0000000;
else
m_col = 0xff000000 | (colv<<16) | (colv<<8) | colv;
}
@@ -159,9 +206,9 @@ void fixedfreq_monitor_state::update_sync(const time_type &time, const double da
fixedfreq_device::fixedfreq_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, type, tag, owner, clock),
device_video_interface(mconfig, *this, false),
- m_htotal(0),
- m_vtotal(0),
- m_refresh_period(time_type(0)),
+ m_enable(*this, "ENABLE"),
+ m_vector(*this, "VECTOR"),
+ m_scanline_height(1.0),
m_monitor(),
m_state(m_monitor, *this)
{
@@ -176,103 +223,193 @@ void fixedfreq_device::device_config_complete()
{
if (!has_screen())
return;
-
if (!screen().refresh_attoseconds())
- screen().set_raw(m_monitor.m_monitor_clock, m_monitor.m_hbackporch, 0,
- m_monitor.m_hbackporch, m_monitor.m_vbackporch, 0,
- m_monitor.m_vbackporch);
-
+ screen().set_raw(m_monitor.m_monitor_clock, m_monitor.htotal(), 0,
+ m_monitor.htotal(), m_monitor.vtotal(), 0,
+ m_monitor.vtotal());
if (!screen().has_screen_update())
screen().set_screen_update(*this, FUNC(fixedfreq_device::screen_update));
+ LOG("config complete\n");
}
void fixedfreq_device::device_start()
{
-
- m_refresh_period = time_type(0);
-
- m_htotal = m_monitor.m_hbackporch;
- m_vtotal = m_monitor.m_vbackporch;
-
m_state.start();
// FIXME: will be done by netlist going forward
- save_item(NAME(m_state.m_sync_signal));
+ save_item(NAME(m_state.m_last_sync));
save_item(NAME(m_state.m_last_x));
save_item(NAME(m_state.m_last_y));
save_item(NAME(m_state.m_last_sync_time));
save_item(NAME(m_state.m_line_time));
save_item(NAME(m_state.m_last_hsync_time));
save_item(NAME(m_state.m_last_vsync_time));
- save_item(NAME(m_refresh_period));
- save_item(NAME(m_state.m_clock_period));
/* sync separator */
save_item(NAME(m_state.m_vsync_filter));
- save_item(NAME(m_state.m_vsync_threshold));
- save_item(NAME(m_state.m_vsync_filter_timeconst));
save_item(NAME(m_state.m_sig_vsync));
save_item(NAME(m_state.m_sig_composite));
save_item(NAME(m_state.m_sig_field));
+ LOG("start\n");
}
void fixedfreq_device::device_reset()
{
m_state.reset();
+ LOG("Reset\n");
+ //ioport("YYY")->field(0xffff)->live().value = 20;
+#if 0
+ //IOPORT_ID(HVISIBLE)->field(~0)->set_value(m_monitor.m_hvisible);
+ //IOPORT_ID(HVISIBLE)->update_defvalue(false);
+ IOPORT_ID(HVISIBLE)->live().defvalue = m_monitor.m_hvisible;
+ IOPORT_ID(HFRONTPORCH)->write(m_monitor.m_hsync);
+ IOPORT_ID(HSYNC)->write(m_monitor.m_hfrontporch);
+ IOPORT_ID(HBACKPORCH)->write(m_monitor.m_hbackporch);
+ IOPORT_ID(VVISIBLE)->write(m_monitor.m_vvisible);
+ IOPORT_ID(VFRONTPORCH)->write(m_monitor.m_vfrontporch);
+ IOPORT_ID(VSYNC)->write(m_monitor.m_vsync);
+ IOPORT_ID(VBACKPORCH)->write(m_monitor.m_vbackporch);
+ IOPORT_ID(SYNCTHRESHOLD)->write(m_monitor.m_sync_threshold * 1000.0);
+ IOPORT_ID(GAIN)->write(m_monitor.m_gain * 1000.0);
+#endif
}
void fixedfreq_device::device_post_load()
{
//recompute_parameters();
+ LOG("post load\n");
+}
+
+static uint32_t nom_col(uint32_t col)
+{
+ float r = ((col >> 16) & 0xff);
+ float g = ((col >> 8) & 0xff);
+ float b = ((col >> 0) & 0xff);
+
+ float m = std::max(r, std::max(g,b));
+ if (m == 0.0f)
+ return 0;
+ return (((uint32_t) m ) << 24) | (((uint32_t) (r/m*255.0f) ) << 16)
+ | (((uint32_t) (g/m*255.0f) ) << 8) | (((uint32_t) (b/m*255.0f) ) << 0);
+}
+
+static void draw_testpat(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
+{
+ // Test pattern Grey scale
+ const int stripes = 255;
+ //auto va(screen.visible_area());
+ auto &va(cliprect);
+
+ for (int i = 0; i < stripes; i++)
+ {
+ int l = va.left() + (i * va.width() / stripes);
+ int w = (va.left() + (i+1) * va.width() / stripes) - l;
+ int v = (255 * i) / stripes;
+ bitmap.plot_box(l, va.top()+20, w, va.height()/2-20, rgb_t(0xff, v, v, v));
+ }
+
+ int l(va.left() + va.width() / 4);
+ int w(va.width() / 4);
+ int t(va.top() + va.height() / 2);
+ int h(va.height() / 2);
+ // 50% Test pattern
+ for (int i = t; i < t + h; i += 2)
+ {
+ bitmap.plot_box(l, i, w, i, rgb_t(0xff, 0xff, 0xff, 0xff));
+ bitmap.plot_box(l, i + 1, w, i + 1, rgb_t(0xff, 0, 0, 0));
+ }
+ l += va.width() / 4;
+ bitmap.plot_box(l, t, w, h, rgb_t(0xff, 0xc3, 0xc3, 0xc3)); // 195
}
uint32_t fixedfreq_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
+ //printf("%f %f\n", m_state.m_fragments[0].y, m_state.m_fragments[m_state.m_fragments.size()-1].y);
+ bool force_vector = screen.screen_type() == SCREEN_TYPE_VECTOR || (m_vector->read() & 1);
+ bool debug_timing = (m_enable->read() & 2) == 2;
+ bool test_pat = (m_enable->read() & 4) == 4;
+ rgb_t backcol = debug_timing ? rgb_t(0xff, 0xff, 0x00, 0x00) : rgb_t(0xff, 0x00, 0x00, 0x00);
- if (screen.screen_type() == SCREEN_TYPE_RASTER)
+ if (!force_vector)
{
+ screen.set_video_attributes(0);
+ bitmap.fill(backcol);
for (auto &f : m_state.m_fragments)
if (f.y < bitmap.height())
bitmap.plot_box(f.x, f.y, f.xr - f.x, 1, f.col);
+
+ if (test_pat)
+ draw_testpat(screen, bitmap, cliprect);
}
- else if (screen.screen_type() == SCREEN_TYPE_VECTOR)
+ else
{
- constexpr const uint32_t flags(PRIMFLAG_ANTIALIAS(1) | PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_VECTOR(1));
+ screen.set_video_attributes(VIDEO_SELF_RENDER);
+
+ const uint32_t flags(PRIMFLAG_ANTIALIAS(1)
+ | PRIMFLAG_BLENDMODE(BLENDMODE_ADD)
+ | (screen.screen_type() == SCREEN_TYPE_VECTOR ? PRIMFLAG_VECTOR(1) : 0));
const rectangle &visarea = screen.visible_area();
- float xscale = 1.0f / visarea.width();
- float yscale = 1.0f / visarea.height();
+ float xscale = 1.0f / (float)visarea.width();
+ float yscale = 1.0f / (float)visarea.height();
float xoffs = (float)visarea.min_x;
float yoffs = (float)visarea.min_y;
screen.container().empty();
- screen.container().add_rect(0.0f, 0.0f, 1.0f, 1.0f, rgb_t(0xff,0x00,0x00,0x00), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_VECTORBUF(1));
+ screen.container().add_rect(0.0f, 0.0f, 1.0f, 1.0f, rgb_t(0xff,0x00,0x00,0x00),
+ PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)
+ | (screen.screen_type() == SCREEN_TYPE_VECTOR ? PRIMFLAG_VECTORBUF(1) : 0));
+ float last_y = -1e6;
for (auto &f : m_state.m_fragments)
{
const float x0((f.x - xoffs) * xscale);
const float y0((f.y - yoffs) * yscale);
const float x1((f.xr - xoffs) * xscale);
- const float y1((f.y + 1.0f - yoffs) * yscale);
- screen.container().add_rect(
- x0, y0, x1, y1,
- (0xff << 24) | (f.col & 0xffffff),
- flags);
+ rgb_t col = (debug_timing && f.y < last_y) ? backcol : (rgb_t) f.col;
+ // FIXME: Debug check for proper vsync timing
+#if 0
+ auto w = m_scanline_height * xscale * 0.5;
+ screen.container().add_line(
+ x0+w, y0, x1-w, y0, m_scanline_height*yscale,
+ nom_col(f.col),
+// (0xff << 24) | (f.col & 0xffffff),
+ flags);
+#elif 1
+ const float y1((f.y + m_scanline_height - yoffs) * yscale);
+ screen.container().add_rect(
+ x0, y0, x1, y1,
+ nom_col(col),
+// (0xaf << 24) | (f.col & 0xffffff),
+ flags);
+#else
+ const float y1((f.y + m_scanline_height - yoffs) * yscale);
+ // Crashes with bgfx
+ screen.container().add_quad(
+ x0, y0, x1, y1,
+ rgb_t(nom_col(f.col)),
+// (0xaf << 24) | (f.col & 0xffffff),
+ m_texture,
+ flags);
+#endif
+ last_y = f.y;
}
}
m_state.m_fragments.clear();
return 0;
}
-void fixedfreq_device::vsync_start_cb(double refresh_time)
+void fixedfreq_device::vsync_end_cb(double refresh_time)
{
- // toggle bitmap
- //m_cur_bm ^= 1;
+ const auto expected_frame_period(m_monitor.clock_period() * m_monitor.vtotal() * m_monitor.htotal());
+
+ const auto refresh_limited(std::min(4.0 * expected_frame_period,
+ std::max(refresh_time, 0.25 * expected_frame_period)));
rectangle visarea(m_monitor.minh(), m_monitor.maxh(), m_monitor.minv(), m_monitor.maxv());
- m_refresh_period = refresh_time;
- screen().configure(m_htotal * m_monitor.m_hscale, m_vtotal, visarea, DOUBLE_TO_ATTOSECONDS(m_refresh_period));
+ screen().configure(m_monitor.htotal_scaled(), m_monitor.vtotal(), visarea, DOUBLE_TO_ATTOSECONDS(refresh_limited));
+ screen().reset_origin(m_state.m_last_y-(m_monitor.vsync_width() + m_monitor.vbackporch_width()), 0);
}
NETDEV_ANALOG_CALLBACK_MEMBER(fixedfreq_device::update_composite_monochrome)
@@ -316,3 +453,138 @@ NETDEV_ANALOG_CALLBACK_MEMBER(fixedfreq_device::update_sync)
}
/***************************************************************************/
+
+static INPUT_PORTS_START(fixedfreq_base_ports)
+ PORT_START("ENABLE")
+ PORT_CONFNAME( 0x01, 0x00, "Display Monitor sliders" )
+ PORT_CONFSETTING( 0x00, DEF_STR( Off ) )
+ PORT_CONFSETTING( 0x01, DEF_STR( On ) )
+ PORT_CONFNAME( 0x02, 0x00, "Visual Timing Debug" )
+ PORT_CONFSETTING( 0x00, DEF_STR( Off ) )
+ PORT_CONFSETTING( 0x02, DEF_STR( On ) )
+ PORT_CONFNAME( 0x04, 0x00, "Display gray test pattern" ) PORT_CONDITION("VECTOR", 0x01, EQUALS, 0x00)
+ PORT_CONFSETTING( 0x00, DEF_STR( Off ) )
+ PORT_CONFSETTING( 0x04, DEF_STR( On ) )
+
+ PORT_ADJUSTERX(HVISIBLE, "H Visible", 10, 1000)
+ PORT_ADJUSTERX(HFRONTPORCH, "H Front porch width", 1, 100)
+ PORT_ADJUSTERX(HSYNC, "H Sync width", 1, 100)
+ PORT_ADJUSTERX(HBACKPORCH, "H Back porch width", 1, 1000)
+ PORT_ADJUSTERX(VVISIBLE, "V Visible", 1, 1000)
+ PORT_ADJUSTERX(VFRONTPORCH, "V Front porch width", 0, 100)
+ PORT_ADJUSTERX(VSYNC, "V Sync width", 1, 100)
+ PORT_ADJUSTERX(VBACKPORCH, "V Back porch width", 1, 100)
+ PORT_ADJUSTERX(SYNCTHRESHOLD, "Sync threshold mV", 10, 2000)
+ PORT_ADJUSTERX(VSYNCTHRESHOLD, "V Sync threshold mV", 10, 1000)
+ PORT_ADJUSTERX(GAIN, "Signal Gain", 10, 1000)
+ PORT_ADJUSTERX(SCANLINE_HEIGHT, "Scanline Height", 10, 300)
+INPUT_PORTS_END
+
+
+static INPUT_PORTS_START(fixedfreq_raster_ports)
+ PORT_START("VECTOR")
+ PORT_CONFNAME( 0x01, 0x00, "Use vector rendering" )
+ PORT_CONFSETTING( 0x00, DEF_STR( Off ) )
+ PORT_CONFSETTING( 0x01, DEF_STR( On ) )
+
+ PORT_INCLUDE(fixedfreq_base_ports)
+
+INPUT_PORTS_END
+
+static INPUT_PORTS_START(fixedfreq_vector_ports)
+ PORT_INCLUDE(fixedfreq_base_ports)
+INPUT_PORTS_END
+
+ioport_constructor fixedfreq_device::device_input_ports() const
+{
+ LOG("input ports\n");
+ if (has_screen())
+ {
+ if (screen().screen_type() == SCREEN_TYPE_RASTER)
+ return INPUT_PORTS_NAME(fixedfreq_raster_ports);
+ else
+ return INPUT_PORTS_NAME(fixedfreq_vector_ports);
+ }
+ else
+ return nullptr;
+}
+
+unsigned fixedfreq_device::monitor_val(unsigned param) const
+{
+ switch (param)
+ {
+ case HVISIBLE:
+ return m_monitor.hvisible_width();
+ case HFRONTPORCH:
+ return m_monitor.hfrontporch_width();
+ case HSYNC:
+ return m_monitor.hsync_width();
+ case HBACKPORCH:
+ return m_monitor.hbackporch_width();
+ case VVISIBLE:
+ return m_monitor.vvisible_width();
+ case VFRONTPORCH:
+ return m_monitor.vfrontporch_width();
+ case VSYNC:
+ return m_monitor.vsync_width();
+ case VBACKPORCH:
+ return m_monitor.vbackporch_width();
+ case SYNCTHRESHOLD:
+ return m_monitor.m_sync_threshold * 1000.0;
+ case VSYNCTHRESHOLD:
+ return m_monitor.m_vsync_threshold * 1000.0;
+ case GAIN:
+ return m_monitor.m_gain * 100.0;
+ case SCANLINE_HEIGHT:
+ return m_scanline_height * 100.0;
+ }
+ return 0;
+}
+
+INPUT_CHANGED_MEMBER(fixedfreq_device::port_changed)
+{
+ auto &m(m_monitor);
+
+ LOG("%d %d\n", param, newval);
+ switch (param)
+ {
+ case HVISIBLE:
+ m.set_h_rel(newval, m.hfrontporch_width(), m.hsync_width(), m.hbackporch_width());
+ break;
+ case HFRONTPORCH:
+ m.set_h_rel(m.hvisible_width(), newval, m.hsync_width(), m.hbackporch_width());
+ break;
+ case HSYNC:
+ m.set_h_rel(m.hvisible_width(), m.hfrontporch_width(), newval, m.hbackporch_width());
+ break;
+ case HBACKPORCH:
+ m.set_h_rel(m.hvisible_width(), m.hfrontporch_width(), m.hsync_width(), newval);
+ break;
+ case VVISIBLE:
+ m.set_v_rel(newval, m.vfrontporch_width(), m.vsync_width(), m.vbackporch_width());
+ break;
+ case VFRONTPORCH:
+ m.set_v_rel(m.vvisible_width(), newval, m.vsync_width(), m.vbackporch_width());
+ break;
+ case VSYNC:
+ m.set_v_rel(m.vvisible_width(), m.vfrontporch_width(), newval, m.vbackporch_width());
+ break;
+ case VBACKPORCH:
+ m.set_v_rel(m.vvisible_width(), m.vfrontporch_width(), m.vsync_width(), newval);
+ break;
+ case SYNCTHRESHOLD:
+ m.m_sync_threshold = static_cast<double>(newval) / 1000.0;
+ break;
+ case VSYNCTHRESHOLD:
+ m.m_vsync_threshold = static_cast<double>(newval) / 1000.0;
+ break;
+ case GAIN:
+ m.m_gain = static_cast<double>(newval) / 100.0;
+ break;
+ case SCANLINE_HEIGHT:
+ m_scanline_height = static_cast<double>(newval) / 100.0;
+ break;
+ }
+ machine().ui().popup_time(5, "Screen Dim %d x %d\n", m.htotal(), m.vtotal());
+ //ioport("YYY")->update_defvalue(true);
+}
diff --git a/src/devices/video/fixfreq.h b/src/devices/video/fixfreq.h
index fdbf728f04a..6d1da4f22f7 100644
--- a/src/devices/video/fixfreq.h
+++ b/src/devices/video/fixfreq.h
@@ -22,6 +22,11 @@ struct fixedfreq_monitor_desc
fixedfreq_monitor_desc()
// default to NTSC "704x480@30i"
: m_monitor_clock(13500000),
+ m_fieldcount(2),
+ m_sync_threshold(0.3),
+ m_gain(1.0 / 3.7),
+ m_hscale(1),
+ m_vsync_threshold(0.600), // trigger at 91% of vsync length 1-exp(-0.6)
m_hvisible(704),
m_hfrontporch(728),
m_hsync(791),
@@ -29,19 +34,64 @@ struct fixedfreq_monitor_desc
m_vvisible(480),
m_vfrontporch(486),
m_vsync(492),
- m_vbackporch(525),
- m_fieldcount(2),
- m_sync_threshold(0.3),
- m_gain(1.0 / 3.7),
- m_hscale(1)
+ m_vbackporch(525)
{}
- int minh() const { return (m_hbackporch - m_hfrontporch) * m_hscale; }
- int maxh() const { return (m_hbackporch - m_hfrontporch + m_hvisible) * m_hscale - 1; }
- int minv() const { return m_vbackporch - m_vfrontporch; }
- int maxv() const { return m_vbackporch - m_vfrontporch + m_vvisible - 1; }
+ uint32_t monitor_clock() const noexcept { return m_monitor_clock; }
+ double clock_period() const noexcept { return 1.0 / (double) m_monitor_clock; };
+
+ int minh() const noexcept { return (m_hbackporch - m_hsync) * m_hscale; }
+ int maxh() const noexcept { return (m_hbackporch - m_hsync + m_hvisible) * m_hscale - 1; }
+ int minv() const noexcept { return m_vbackporch - m_vsync; }
+ int maxv() const noexcept { return m_vbackporch - m_vsync + m_vvisible - 1; }
+
+ int htotal_scaled() const noexcept { return m_hbackporch * m_hscale; }
+
+ int vbackporch_width() const noexcept { return m_vbackporch - m_vsync; }
+ int vsync_width() const noexcept { return m_vsync - m_vfrontporch; }
+ int vfrontporch_width() const noexcept { return m_vfrontporch - m_vvisible; }
+ int vvisible_width() const noexcept { return m_vvisible; }
+ int vtotal() const noexcept { return m_vbackporch; }
+
+ int hbackporch_width() const noexcept { return m_hbackporch - m_hsync; }
+ int hsync_width() const noexcept { return m_hsync - m_hfrontporch; }
+ int hfrontporch_width() const noexcept { return m_hfrontporch - m_hvisible; }
+ int hvisible_width() const noexcept { return m_hvisible; }
+ int htotal() const noexcept { return m_hbackporch; }
+
+ void set_h_rel(int vw, int fpw, int sw, int bpw)
+ {
+ m_hvisible = vw;
+ m_hfrontporch = m_hvisible + fpw;
+ m_hsync = m_hfrontporch + sw;
+ m_hbackporch = m_hsync + bpw;
+ }
+
+ void set_v_rel(int vw, int fpw, int sw, int bpw)
+ {
+ m_vvisible = vw;
+ m_vfrontporch = m_vvisible + fpw;
+ m_vsync = m_vfrontporch + sw;
+ m_vbackporch = m_vsync + bpw;
+ }
+
+ double vsync_filter_timeconst() const noexcept
+ {
+ return (double) (m_monitor_clock) / ((double) m_hbackporch * vsync_width());
+ }
+
+ double hsync_filter_timeconst() const noexcept
+ {
+ return (double) m_monitor_clock / (double) hsync_width();
+ }
uint32_t m_monitor_clock;
+ int m_fieldcount;
+ double m_sync_threshold;
+ double m_gain;
+ int m_hscale;
+ double m_vsync_threshold;
+private:
int m_hvisible;
int m_hfrontporch;
int m_hsync;
@@ -50,16 +100,12 @@ struct fixedfreq_monitor_desc
int m_vfrontporch;
int m_vsync;
int m_vbackporch;
- int m_fieldcount;
- double m_sync_threshold;
- double m_gain;
- int m_hscale;
};
struct fixedfreq_monitor_intf
{
virtual ~fixedfreq_monitor_intf() = default;
- virtual void vsync_start_cb(double refresh_time) = 0;
+ virtual void vsync_end_cb(double refresh_time) = 0;
};
struct fixedfreq_monitor_line
@@ -77,7 +123,7 @@ struct fixedfreq_monitor_state
fixedfreq_monitor_state(fixedfreq_monitor_desc &desc, fixedfreq_monitor_intf &intf)
: m_desc(desc),
m_intf(intf),
- m_sync_signal(0),
+ m_last_sync(0),
m_col(0),
m_last_x(0),
m_last_y(0),
@@ -85,14 +131,10 @@ struct fixedfreq_monitor_state
m_line_time(time_type(0)),
m_last_hsync_time(time_type(0)),
m_last_vsync_time(time_type(0)),
- m_clock_period(time_type(0)),
m_vsync_filter(0),
- m_vsync_threshold(0),
- m_vsync_filter_timeconst(0),
m_sig_vsync(0),
m_sig_composite(0),
- m_sig_field(0),
- m_min_frame_period(time_type(0))
+ m_sig_field(0)
{}
/***
@@ -103,7 +145,7 @@ struct fixedfreq_monitor_state
// FIXME: once moved to netlist this may no longer be necessary.
// Only copies constructor init
- m_sync_signal = 0.0;
+ m_last_sync = 0.0;
m_col = rgb_t(0,0,0);
m_last_x = 0;
m_last_y = 0;
@@ -111,12 +153,9 @@ struct fixedfreq_monitor_state
m_line_time = time_type(0);
m_last_hsync_time = time_type(0);
m_last_vsync_time = time_type(0);
- m_clock_period = time_type(0);
/* sync separator */
m_vsync_filter = 0.0;
- m_vsync_threshold = 0.0;
- m_vsync_filter_timeconst = 0.0;
m_sig_vsync = 0;
m_sig_composite = 0;
@@ -127,22 +166,18 @@ struct fixedfreq_monitor_state
/* sync separator */
- m_vsync_threshold = (exp(- 3.0/(3.0+3.0))) - exp(-1.0);
- m_vsync_filter_timeconst = (double) (m_desc.m_monitor_clock) / (double) m_desc.m_hbackporch * 1.0; // / (3.0 + 3.0);
- //LOG("trigger %f with len %f\n", m_vsync_threshold, 1e6 / m_vsync_filter_timeconst);
-
- m_clock_period = 1.0 / m_desc.m_monitor_clock;
+ //m_vsync_threshold = (exp(- 3.0/(3.0+3.0))) - exp(-1.0);
+ //printf("trigger %f with len %f\n", m_vsync_threshold, 1e6 / m_vsync_filter_timeconst);
// Minimum frame period to be passed to video system ?
- m_min_frame_period = 0.25 * m_clock_period * m_desc.m_vbackporch * m_desc.m_hbackporch;
m_fragments.clear();
- m_intf.vsync_start_cb(m_min_frame_period);
+ m_intf.vsync_end_cb(m_desc.clock_period() * m_desc.vtotal() * m_desc.htotal());
}
void reset()
{
- m_sync_signal = 0;
+ m_last_sync = 0;
m_col = 0;
m_last_x = 0;
m_last_y = 0;
@@ -171,7 +206,7 @@ struct fixedfreq_monitor_state
const fixedfreq_monitor_desc &m_desc;
fixedfreq_monitor_intf &m_intf;
- double m_sync_signal;
+ double m_last_sync;
uint32_t m_col;
float m_last_x;
int m_last_y;
@@ -179,17 +214,13 @@ struct fixedfreq_monitor_state
time_type m_line_time;
time_type m_last_hsync_time;
time_type m_last_vsync_time;
- time_type m_clock_period;
/* sync separator */
double m_vsync_filter;
- double m_vsync_threshold;
- double m_vsync_filter_timeconst;
int m_sig_vsync;
int m_sig_composite;
int m_sig_field;
- time_type m_min_frame_period;
std::vector<fixedfreq_monitor_line> m_fragments;
};
@@ -206,42 +237,48 @@ public:
fixedfreq_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
// inline configuration helpers
- void set_monitor_clock(uint32_t clock) { m_monitor.m_monitor_clock = clock; }
- void set_fieldcount(int count) { m_monitor.m_fieldcount = count; }
- void set_threshold(double threshold) { m_monitor.m_sync_threshold = threshold; }
- void set_gain(double gain) { m_monitor.m_gain = gain; }
- void set_horz_params(int visible, int frontporch, int sync, int backporch)
+ fixedfreq_device &set_monitor_clock(uint32_t clock) { m_monitor.m_monitor_clock = clock; return *this;}
+ fixedfreq_device &set_fieldcount(int count) { m_monitor.m_fieldcount = count; return *this; }
+ fixedfreq_device &set_threshold(double threshold) { m_monitor.m_sync_threshold = threshold; return *this; }
+ fixedfreq_device &set_gain(double gain) { m_monitor.m_gain = gain; return *this; }
+ fixedfreq_device &set_horz_params(int visible, int frontporch, int sync, int backporch)
{
- m_monitor.m_hvisible = visible;
- m_monitor.m_hfrontporch = frontporch;
- m_monitor.m_hsync = sync;
- m_monitor.m_hbackporch = backporch;
+ m_monitor.set_h_rel(
+ visible,
+ frontporch - visible,
+ sync - frontporch,
+ backporch - sync);
+ return *this;
}
- void set_vert_params(int visible, int frontporch, int sync, int backporch)
+ fixedfreq_device &set_vert_params(int visible, int frontporch, int sync, int backporch)
{
- m_monitor.m_vvisible = visible;
- m_monitor.m_vfrontporch = frontporch;
- m_monitor.m_vsync = sync;
- m_monitor.m_vbackporch = backporch;
+ m_monitor.set_v_rel(
+ visible,
+ frontporch - visible,
+ sync - frontporch,
+ backporch - sync);
+ return *this;
}
- void set_horz_scale(int hscale) { m_monitor.m_hscale = hscale; }
+ fixedfreq_device &set_horz_scale(int hscale) { m_monitor.m_hscale = hscale; return *this;}
// pre-defined configurations
- void set_mode_ntsc720() //ModeLine "720x480@30i" 13.5 720 736 799 858 480 486 492 525 interlace -hsync -vsync
+ fixedfreq_device &set_mode_ntsc720() //ModeLine "720x480@30i" 13.5 720 736 799 858 480 486 492 525 interlace -hsync -vsync
{
set_monitor_clock(13500000);
set_horz_params(720, 736, 799, 858);
set_vert_params(480, 486, 492, 525);
set_fieldcount(2);
set_threshold(0.3);
+ return *this;
}
- void set_mode_ntsc704() //ModeLine "704x480@30i" 13.5 704 728 791 858 480 486 492 525
+ fixedfreq_device &set_mode_ntsc704() //ModeLine "704x480@30i" 13.5 704 728 791 858 480 486 492 525
{
set_monitor_clock(13500000);
set_horz_params(704, 728, 791, 858);
set_vert_params(480, 486, 492, 525);
set_fieldcount(2);
set_threshold(0.3);
+ return *this;
}
virtual uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
@@ -252,6 +289,9 @@ public:
NETDEV_ANALOG_CALLBACK_MEMBER(update_blue);
NETDEV_ANALOG_CALLBACK_MEMBER(update_sync);
+ INPUT_CHANGED_MEMBER(port_changed);
+
+ unsigned monitor_val(unsigned param) const;
protected:
@@ -264,14 +304,14 @@ protected:
virtual void device_post_load() override;
//virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
- void vsync_start_cb(double refresh_time) override;
-
-private:
+ virtual ioport_constructor device_input_ports() const override;
- int m_htotal;
- int m_vtotal;
+ void vsync_end_cb(double refresh_time) override;
- time_type m_refresh_period;
+private:
+ required_ioport m_enable;
+ required_ioport m_vector;
+ float m_scanline_height;
/* adjustable by drivers */
fixedfreq_monitor_desc m_monitor;
diff --git a/src/mame/drivers/pong.cpp b/src/mame/drivers/pong.cpp
index ea4ad14e7ab..7699b460935 100644
--- a/src/mame/drivers/pong.cpp
+++ b/src/mame/drivers/pong.cpp
@@ -109,7 +109,7 @@ static const int NS_PER_CLOCK_PONG = static_cast<int>((double) NETLIST_INTERNAL
static const int MASTER_CLOCK_PONG = static_cast<int>((double) NETLIST_INTERNAL_RES / (double) NS_PER_CLOCK_PONG + 0.5);
#define V_TOTAL_PONG (0x105+1) // 262
-#define H_TOTAL_PONG (0x1C6+1) // 454
+#define H_TOTAL_PONG (0x1C5+1) // 454
/*
* Breakout's H1 signal:
@@ -490,14 +490,15 @@ void pong_state::pong(machine_config &config)
/* video hardware */
SCREEN(config, "screen", SCREEN_TYPE_RASTER);
//SCREEN(config, "screen", SCREEN_TYPE_VECTOR);
- FIXFREQ(config, m_video).set_screen("screen");
- m_video->set_monitor_clock(MASTER_CLOCK_PONG);
- m_video->set_horz_params(H_TOTAL_PONG-67,H_TOTAL_PONG-40,H_TOTAL_PONG-8,H_TOTAL_PONG);
- m_video->set_vert_params(V_TOTAL_PONG-22,V_TOTAL_PONG-19,V_TOTAL_PONG-12,V_TOTAL_PONG);
- m_video->set_fieldcount(1);
- m_video->set_threshold(0.11);
- m_video->set_horz_scale(4);
-
+ FIXFREQ(config, m_video)
+ .set_monitor_clock(MASTER_CLOCK_PONG)
+ .set_horz_params(H_TOTAL_PONG-66,H_TOTAL_PONG-40,H_TOTAL_PONG-8,H_TOTAL_PONG)
+ .set_vert_params(V_TOTAL_PONG-22,V_TOTAL_PONG-10,V_TOTAL_PONG-8,V_TOTAL_PONG)
+ .set_fieldcount(1)
+ .set_threshold(0.11)
+ .set_gain(2.37)
+ .set_horz_scale(4)
+ .set_screen("screen");
/* sound hardware */
SPEAKER(config, "speaker").front_center();
DAC_16BIT_R2R_TWOS_COMPLEMENT(config, m_dac, 0).add_route(ALL_OUTPUTS, "speaker", 0.5); // unknown DAC
@@ -540,19 +541,20 @@ void breakout_state::breakout(machine_config &config)
NETLIST_ANALOG_OUTPUT(config, "maincpu:coin_counter", 0).set_params("CON_T", FUNC(breakout_state::coin_counter_cb));
/* video hardware */
- FIXFREQ(config, m_video).set_screen("screen");
- SCREEN(config, "screen", SCREEN_TYPE_RASTER);
- //SCREEN(config, "screen", SCREEN_TYPE_VECTOR);
/* The Pixel width is a 2,1,2,1,2,1,1,1 repeating pattern
* Thus we must use double resolution horizontally
*/
- m_video->set_monitor_clock(MASTER_CLOCK_BREAKOUT);
- m_video->set_horz_params((H_TOTAL_BREAKOUT-208),(H_TOTAL_BREAKOUT-144),(H_TOTAL_BREAKOUT-16), (H_TOTAL_BREAKOUT));
- m_video->set_vert_params(V_TOTAL_BREAKOUT-22,V_TOTAL_BREAKOUT-23,V_TOTAL_BREAKOUT-4, V_TOTAL_BREAKOUT);
- m_video->set_fieldcount(1);
- m_video->set_threshold(1.0);
- m_video->set_gain(1.5);
- m_video->set_horz_scale(2);
+ SCREEN(config, "screen", SCREEN_TYPE_RASTER);
+ //SCREEN(config, "screen", SCREEN_TYPE_VECTOR);
+ FIXFREQ(config, m_video)
+ .set_monitor_clock(MASTER_CLOCK_BREAKOUT)
+ .set_horz_params((H_TOTAL_BREAKOUT-176),(H_TOTAL_BREAKOUT-144),(H_TOTAL_BREAKOUT-80), (H_TOTAL_BREAKOUT))
+ .set_vert_params(V_TOTAL_BREAKOUT-24,V_TOTAL_BREAKOUT-24,V_TOTAL_BREAKOUT-20, V_TOTAL_BREAKOUT)
+ .set_fieldcount(1)
+ .set_threshold(1.0)
+ .set_gain(2.66)
+ .set_horz_scale(2)
+ .set_screen("screen");
/* sound hardware */
SPEAKER(config, "speaker").front_center();
@@ -594,12 +596,15 @@ void pong_state::pongd(machine_config &config)
/* video hardware */
SCREEN(config, "screen", SCREEN_TYPE_RASTER);
- FIXFREQ(config, m_video).set_screen("screen");
- m_video->set_monitor_clock(MASTER_CLOCK_PONG);
- m_video->set_horz_params(H_TOTAL_PONG-67,H_TOTAL_PONG-52,H_TOTAL_PONG-8,H_TOTAL_PONG);
- m_video->set_vert_params(V_TOTAL_PONG-22,V_TOTAL_PONG-19,V_TOTAL_PONG-12,V_TOTAL_PONG);
- m_video->set_fieldcount(1);
- m_video->set_threshold(0.11);
+ FIXFREQ(config, m_video)
+ .set_monitor_clock(MASTER_CLOCK_PONG)
+ .set_horz_params(H_TOTAL_PONG-76,H_TOTAL_PONG-56,H_TOTAL_PONG-8,H_TOTAL_PONG)
+ .set_vert_params(V_TOTAL_PONG-22,V_TOTAL_PONG-10,V_TOTAL_PONG-8,V_TOTAL_PONG)
+ .set_fieldcount(1)
+ .set_threshold(0.11)
+ .set_gain(2.7)
+ .set_horz_scale(2)
+ .set_screen("screen");
/* sound hardware */
SPEAKER(config, "speaker").front_center();
@@ -633,15 +638,15 @@ void rebound_state::rebound(machine_config &config)
/* video hardware */
SCREEN(config, "screen", SCREEN_TYPE_RASTER);
- FIXFREQ(config, m_video).set_screen("screen");
- m_video->set_monitor_clock(MASTER_CLOCK_PONG);
- //m_video->set_horz_params(H_TOTAL_PONG-67,H_TOTAL_PONG-40,H_TOTAL_PONG-8,H_TOTAL_PONG);
- m_video->set_horz_params(H_TOTAL_PONG-51,H_TOTAL_PONG-40,H_TOTAL_PONG-8,H_TOTAL_PONG);
- m_video->set_vert_params(V_TOTAL_PONG-22,V_TOTAL_PONG-19,V_TOTAL_PONG-12,V_TOTAL_PONG);
- m_video->set_fieldcount(1);
- m_video->set_threshold(1.0);
- m_video->set_gain(0.6);
- m_video->set_horz_scale(2);
+ FIXFREQ(config, m_video)
+ .set_monitor_clock(MASTER_CLOCK_PONG)
+ .set_horz_params(H_TOTAL_PONG-66,H_TOTAL_PONG-56,H_TOTAL_PONG-8,H_TOTAL_PONG)
+ .set_vert_params(V_TOTAL_PONG-22,V_TOTAL_PONG-12,V_TOTAL_PONG-8,V_TOTAL_PONG)
+ .set_fieldcount(1)
+ .set_threshold(1.0)
+ .set_gain(1.8)
+ .set_horz_scale(2)
+ .set_screen("screen");
/* sound hardware */
SPEAKER(config, "speaker").front_center();
@@ -721,7 +726,7 @@ ROM_END
*/
GAME( 1972, pong, 0, pong, pong, pong_state, empty_init, ROT0, "Atari", "Pong (Rev E) external [TTL]", MACHINE_SUPPORTS_SAVE)
-GAME( 1972, pongf, 0, pongf, pong, pong_state, empty_init, ROT0, "Atari", "Pong (Rev E) [TTL]", MACHINE_SUPPORTS_SAVE)
+GAME( 1972, pongf, pong, pongf, pong, pong_state, empty_init, ROT0, "Atari", "Pong (Rev E) [TTL]", MACHINE_SUPPORTS_SAVE)
GAME( 1973, pongd, 0, pongd, pongd, pong_state, empty_init, ROT0, "Atari", "Pong Doubles [TTL]", MACHINE_SUPPORTS_SAVE)
GAMEL( 1974, rebound, 0, rebound, rebound, rebound_state, empty_init, ROT0, "Atari", "Rebound (Rev B) [TTL]", MACHINE_SUPPORTS_SAVE, layout_rebound)
GAMEL( 1976, breakout, 0, breakout, breakout, breakout_state, empty_init, ROT90, "Atari", "Breakout [TTL]", MACHINE_SUPPORTS_SAVE, layout_breakout)
diff --git a/src/mame/layout/breakout.lay b/src/mame/layout/breakout.lay
index 1d656beb018..891854ce5b3 100644
--- a/src/mame/layout/breakout.lay
+++ b/src/mame/layout/breakout.lay
@@ -2,35 +2,35 @@
<mamelayout version="2">
<element name="overlay">
<rect>
- <bounds left="0" top="0" right="192" bottom="47" />
+ <bounds left="0" top="0" right="192" bottom="44" />
<color red="1" green="1" blue="1" />
</rect>
<rect>
- <bounds left="0" top="47" right="192" bottom="57" />
+ <bounds left="0" top="44" right="192" bottom="54" />
<color red="1" green="0.125" blue="0.125" />
</rect>
<rect>
- <bounds left="0" top="57" right="192" bottom="67" />
+ <bounds left="0" top="54" right="192" bottom="64" />
<color red="1" green="0.5" blue="0.0625" />
</rect>
<rect>
- <bounds left="0" top="67" right="192" bottom="77" />
+ <bounds left="0" top="64" right="192" bottom="74" />
<color red="0.25" green="1" blue="0.25" />
</rect>
<rect>
- <bounds left="0" top="77" right="192" bottom="88" />
+ <bounds left="0" top="74" right="192" bottom="84" />
<color red="1" green="1" blue="0.25" />
</rect>
<rect>
- <bounds left="0" top="88" right="192" bottom="231" />
+ <bounds left="0" top="84" right="192" bottom="231" />
<color red="1" green="1" blue="1" />
</rect>
<rect>
- <bounds left="0" top="231" right="192" bottom="238" />
+ <bounds left="0" top="221" right="192" bottom="228" />
<color red="0.125" green="0.125" blue="1" />
</rect>
<rect>
- <bounds left="0" top="238" right="192" bottom="244" />
+ <bounds left="0" top="228" right="192" bottom="244" />
<color red="1" green="1" blue="1" />
</rect>
</element>