summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/rendlay.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/emu/rendlay.cpp')
-rw-r--r--src/emu/rendlay.cpp982
1 files changed, 633 insertions, 349 deletions
diff --git a/src/emu/rendlay.cpp b/src/emu/rendlay.cpp
index 789c7c15a7c..be5413f99ae 100644
--- a/src/emu/rendlay.cpp
+++ b/src/emu/rendlay.cpp
@@ -13,14 +13,17 @@
#include "rendlay.h"
#include "emuopts.h"
+#include "fileio.h"
+#include "main.h"
#include "rendfont.h"
#include "rendutil.h"
#include "video/rgbutil.h"
-#include "nanosvg.h"
-#include "unicode.h"
-#include "vecstream.h"
-#include "xmlfile.h"
+#include "util/nanosvg.h"
+#include "util/path.h"
+#include "util/unicode.h"
+#include "util/vecstream.h"
+#include "util/xmlfile.h"
#include <cctype>
#include <algorithm>
@@ -57,6 +60,9 @@
// screenless layouts
#include "noscreens.lh"
+// single screen layouts
+#include "monitors.lh"
+
// dual screen layouts
#include "dualhsxs.lh"
#include "dualhovu.lh"
@@ -219,12 +225,18 @@ private:
{
if (m_float_valid)
{
- m_text = std::to_string(m_float);
+ std::ostringstream stream;
+ stream.imbue(std::locale::classic());
+ stream << m_float;
+ m_text = std::move(stream).str();
m_text_valid = true;
}
else if (m_int_valid)
{
- m_text = std::to_string(m_int);
+ std::ostringstream stream;
+ stream.imbue(std::locale::classic());
+ stream << m_int;
+ m_text = std::move(stream).str();
m_text_valid = true;
}
}
@@ -530,6 +542,7 @@ private:
// variable found
if (start == 0)
m_buffer.seekp(0);
+ assert(start < str.length());
m_buffer.write(&str[start], pos - start);
m_buffer.write(text.first.data(), text.first.length());
start = term - str.begin() + 1;
@@ -550,7 +563,8 @@ private:
}
else
{
- m_buffer.write(&str[start], str.length() - start);
+ if (start < str.length())
+ m_buffer.write(&str[start], str.length() - start);
return util::buf_to_string_view(m_buffer);
}
}
@@ -1117,6 +1131,121 @@ inline render_color interpolate_color(emu::render::detail::color_vector const &s
}
}
+
+unsigned get_state_shift(ioport_value mask)
+{
+ // get shift to right-align LSB
+ unsigned result(0U);
+ while (mask && !BIT(mask, 0))
+ {
+ ++result;
+ mask >>= 1;
+ }
+ return result;
+}
+
+std::string make_child_output_tag(
+ emu::render::detail::view_environment &env,
+ util::xml::data_node const &itemnode,
+ char const *child)
+{
+ util::xml::data_node const *const childnode(itemnode.get_child(child));
+ if (childnode)
+ return std::string(env.get_attribute_string(*childnode, "name"));
+ else
+ return std::string();
+}
+
+std::string make_child_input_tag(
+ emu::render::detail::view_environment &env,
+ util::xml::data_node const &itemnode,
+ char const *child)
+{
+ util::xml::data_node const *const childnode(itemnode.get_child(child));
+ return childnode ? env.get_attribute_subtag(*childnode, "inputtag") : std::string();
+}
+
+ioport_value make_child_mask(
+ emu::render::detail::view_environment &env,
+ util::xml::data_node const &itemnode,
+ char const *child)
+{
+ util::xml::data_node const *const childnode(itemnode.get_child(child));
+ return childnode ? env.get_attribute_int(*childnode, "mask", ~ioport_value(0)) : ~ioport_value(0);
+}
+
+bool make_child_wrap(
+ emu::render::detail::view_environment &env,
+ util::xml::data_node const &itemnode,
+ char const *child)
+{
+ util::xml::data_node const *const childnode(itemnode.get_child(child));
+ return childnode ? env.get_attribute_bool(*childnode, "wrap", false) : false;
+}
+
+float make_child_size(
+ emu::render::detail::view_environment &env,
+ util::xml::data_node const &itemnode,
+ char const *child)
+{
+ util::xml::data_node const *const childnode(itemnode.get_child(child));
+ return std::clamp(childnode ? env.get_attribute_float(*childnode, "size", 1.0f) : 1.0f, 0.01f, 1.0f);
+}
+
+ioport_value make_child_min(
+ emu::render::detail::view_environment &env,
+ util::xml::data_node const &itemnode,
+ char const *child)
+{
+ util::xml::data_node const *const childnode(itemnode.get_child(child));
+ return childnode ? env.get_attribute_int(*childnode, "min", ioport_value(0)) : ioport_value(0);
+}
+
+ioport_value make_child_max(
+ emu::render::detail::view_environment &env,
+ util::xml::data_node const &itemnode,
+ char const *child,
+ ioport_value mask)
+{
+ util::xml::data_node const *const childnode(itemnode.get_child(child));
+ ioport_value const dflt(mask >> get_state_shift(mask));
+ return childnode ? env.get_attribute_int(*childnode, "max", dflt) : dflt;
+}
+
+std::string make_input_tag(
+ emu::render::detail::view_environment &env,
+ util::xml::data_node const &itemnode)
+{
+ return env.get_attribute_subtag(itemnode, "inputtag");
+}
+
+int get_blend_mode(emu::render::detail::view_environment &env, util::xml::data_node const &itemnode)
+{
+ // see if there's a blend mode attribute
+ std::string const *const mode(itemnode.get_attribute_string_ptr("blend"));
+ if (mode)
+ {
+ if (*mode == "none")
+ return BLENDMODE_NONE;
+ else if (*mode == "alpha")
+ return BLENDMODE_ALPHA;
+ else if (*mode == "multiply")
+ return BLENDMODE_RGB_MULTIPLY;
+ else if (*mode == "add")
+ return BLENDMODE_ADD;
+ else
+ throw layout_syntax_error(util::string_format("unknown blend mode %s", *mode));
+ }
+
+ // fall back to implicit blend mode based on element type
+ if (!strcmp(itemnode.get_name(), "screen"))
+ return -1; // magic number recognised by render.cpp to allow per-element blend mode
+ else if (!strcmp(itemnode.get_name(), "overlay"))
+ return BLENDMODE_RGB_MULTIPLY;
+ else
+ return BLENDMODE_ALPHA;
+}
+
} // anonymous namespace
@@ -1128,13 +1257,9 @@ inline render_color interpolate_color(emu::render::detail::color_vector const &s
layout_element::make_component_map const layout_element::s_make_component{
{ "image", &make_component<image_component> },
{ "text", &make_component<text_component> },
- { "dotmatrix", &make_dotmatrix_component<8> },
- { "dotmatrix5dot", &make_dotmatrix_component<5> },
- { "dotmatrixdot", &make_dotmatrix_component<1> },
{ "simplecounter", &make_component<simplecounter_component> },
{ "reel", &make_component<reel_component> },
{ "led7seg", &make_component<led7seg_component> },
- { "led8seg_gts1", &make_component<led8seg_gts1_component> },
{ "led14seg", &make_component<led14seg_component> },
{ "led14segsc", &make_component<led14segsc_component> },
{ "led16seg", &make_component<led16seg_component> },
@@ -1152,6 +1277,7 @@ layout_element::layout_element(environment &env, util::xml::data_node const &ele
, m_defstate(env.get_attribute_int(elemnode, "defstate", -1))
, m_statemask(0)
, m_foldhigh(false)
+ , m_invalidated(false)
{
// parse components in order
bool first = true;
@@ -1522,6 +1648,17 @@ render_texture *layout_element::state_texture(int state)
//-------------------------------------------------
+// set_draw_callback - set handler called after
+// drawing components
+//-------------------------------------------------
+
+void layout_element::set_draw_callback(draw_delegate &&handler)
+{
+ m_draw = std::move(handler);
+}
+
+
+//-------------------------------------------------
// preload - perform expensive loading upfront
// for all components
//-------------------------------------------------
@@ -1534,6 +1671,25 @@ void layout_element::preload()
//-------------------------------------------------
+// prepare - perform additional tasks before
+// drawing a frame
+//-------------------------------------------------
+
+void layout_element::prepare()
+{
+ if (m_invalidated)
+ {
+ m_invalidated = false;
+ for (texture &tex : m_elemtex)
+ {
+ machine().render().texture_free(tex.m_texture);
+ tex.m_texture = nullptr;
+ }
+ }
+}
+
+
+//-------------------------------------------------
// element_scale - scale an element by rendering
// all the components at the appropriate
// resolution
@@ -1549,6 +1705,10 @@ void layout_element::element_scale(bitmap_argb32 &dest, bitmap_argb32 &source, c
if ((elemtex.m_state & curcomp->statemask()) == curcomp->stateval())
curcomp->draw(elemtex.m_element->machine(), dest, elemtex.m_state);
}
+
+ // if there's a callback for additional drawing, invoke it
+ if (!elemtex.m_element->m_draw.isnull())
+ elemtex.m_element->m_draw(elemtex.m_state, dest);
}
@@ -1630,10 +1790,10 @@ private:
{
u8 const *const src(reinterpret_cast<u8 const *>(dst));
rgb_t const d(
- u8((float(src[3]) * c.a) + 0.5),
- u8((float(src[0]) * c.r) + 0.5),
- u8((float(src[1]) * c.g) + 0.5),
- u8((float(src[2]) * c.b) + 0.5));
+ u8((float(src[3]) * c.a) + 0.5F),
+ u8((float(src[0]) * c.r) + 0.5F),
+ u8((float(src[1]) * c.g) + 0.5F),
+ u8((float(src[2]) * c.b) + 0.5F));
*dst = d;
havealpha = havealpha || (d.a() < 255U);
}
@@ -1711,12 +1871,10 @@ private:
std::string filename;
if (!m_searchpath.empty())
filename = m_dirname;
- if (!filename.empty() && !util::is_directory_separator(filename[filename.size() - 1]))
- filename.append(PATH_SEPARATOR);
- filename.append(m_imagefile);
+ util::path_append(filename, m_imagefile);
LOGMASKED(LOG_IMAGE_LOAD, "Image component attempt to load image file '%s'\n", filename);
- osd_file::error const imgerr = file.open(filename);
- if (osd_file::error::NONE == imgerr)
+ std::error_condition const imgerr = file.open(filename);
+ if (!imgerr)
{
if (!load_bitmap(file))
{
@@ -1727,7 +1885,8 @@ private:
}
else
{
- LOGMASKED(LOG_IMAGE_LOAD, "Image component unable to open image file '%s'\n", filename);
+ LOGMASKED(LOG_IMAGE_LOAD, "Image component unable to open image file '%s' (%s:%d %s)\n",
+ filename, imgerr.category().name(), imgerr.value(), imgerr.message());
}
}
else if (!m_data.empty())
@@ -1743,12 +1902,10 @@ private:
std::string filename;
if (!m_searchpath.empty())
filename = m_dirname;
- if (!filename.empty() && !util::is_directory_separator(filename[filename.size() - 1]))
- filename.append(PATH_SEPARATOR);
- filename.append(m_alphafile);
+ util::path_append(filename, m_alphafile);
LOGMASKED(LOG_IMAGE_LOAD, "Image component attempt to load alpha channel from file '%s'\n", filename);
- osd_file::error const alferr = file.open(filename);
- if (osd_file::error::NONE == alferr)
+ std::error_condition const alferr = file.open(filename);
+ if (!alferr)
{
// TODO: no way to detect corner case where we had alpha from the image but the alpha PNG makes it entirely opaque
if (render_load_png(m_bitmap, file, true))
@@ -1757,7 +1914,8 @@ private:
}
else
{
- LOGMASKED(LOG_IMAGE_LOAD, "Image component unable to open alpha channel file '%s'\n", filename);
+ LOGMASKED(LOG_IMAGE_LOAD, "Image component unable to open alpha channel file '%s' (%s:%d %s)\n",
+ filename, alferr.category().name(), alferr.value(), alferr.message());
}
}
else if (m_svg)
@@ -1839,8 +1997,8 @@ private:
// make a file wrapper for the data and see if it looks like a bitmap
util::core_file::ptr file;
- osd_file::error const filerr(util::core_file::open_ram(m_data.c_str(), m_data.size(), OPEN_FLAG_READ, file));
- bool const bitmapdata((osd_file::error::NONE == filerr) && file && load_bitmap(*file));
+ std::error_condition const filerr(util::core_file::open_ram(m_data.c_str(), m_data.size(), OPEN_FLAG_READ, file));
+ bool const bitmapdata(!filerr && file && load_bitmap(*file));
file.reset();
// if it didn't look like a bitmap, see if it looks like it might be XML and hence SVG
@@ -1859,7 +2017,7 @@ private:
}
}
- bool load_bitmap(util::core_file &file)
+ bool load_bitmap(util::random_read &file)
{
ru_imgformat const format = render_detect_image(file);
switch (format)
@@ -1889,9 +2047,16 @@ private:
}
}
- void load_svg(util::core_file &file)
+ void load_svg(util::random_read &file)
{
- u64 len(file.size());
+ std::error_condition filerr;
+ u64 len;
+ filerr = file.length(len);
+ if (filerr)
+ {
+ osd_printf_warning("Error getting length of component image '%s'\n", m_imagefile);
+ return;
+ }
if ((std::numeric_limits<size_t>::max() - 1) < len)
{
osd_printf_warning("Component image '%s' is too large to read into memory\n", m_imagefile);
@@ -1904,17 +2069,12 @@ private:
return;
}
svgbuf[len] = '\0';
- for (char *ptr = svgbuf.get(); len; )
+ size_t actual;
+ std::tie(filerr, actual) = read(file, svgbuf.get(), len);
+ if (filerr || (actual < len))
{
- u32 const block(u32(std::min<u64>(std::numeric_limits<u32>::max(), len)));
- u32 const read(file.read(ptr, block));
- if (!read)
- {
- osd_printf_warning("Error reading component image '%s'\n", m_imagefile);
- return;
- }
- ptr += read;
- len -= read;
+ osd_printf_warning("Error reading component image '%s'\n", m_imagefile);
+ return;
}
parse_svg(svgbuf.get());
}
@@ -1989,7 +2149,7 @@ protected:
}
else if (c.a)
{
- // compute premultiplied colors
+ // compute premultiplied color
u32 const a(c.a * 255.0F);
u32 const r(u32(c.r * (255.0F * 255.0F)) * a);
u32 const g(u32(c.g * (255.0F * 255.0F)) * a);
@@ -2025,9 +2185,9 @@ public:
render_color const c(color(state));
u32 const f(rgb_t(u8(c.r * 255), u8(c.g * 255), u8(c.b * 255)));
u32 const a(c.a * 255.0F);
- u32 const r(c.r * c.a * (255.0F * 255.0F * 255.0F));
- u32 const g(c.g * c.a * (255.0F * 255.0F * 255.0F));
- u32 const b(c.b * c.a * (255.0F * 255.0F * 255.0F));
+ u32 const r(c.r * (255.0F * 255.0F) * a);
+ u32 const g(c.g * (255.0F * 255.0F) * a);
+ u32 const b(c.b * (255.0F * 255.0F) * a);
u32 const inva(255 - a);
if (!a)
return;
@@ -2138,17 +2298,13 @@ public:
if ((x >= minfill) && (x <= maxfill))
{
if (255 <= a)
- {
dst = std::fill_n(dst, maxfill - x + 1, f);
- x = maxfill;
- }
else
- {
while (x++ <= maxfill)
alpha_blend(*dst++, a, r, g, b, inva);
- --x;
- }
+
--dst;
+ x = maxfill;
}
else
{
@@ -2250,17 +2406,13 @@ public:
if ((x >= minfill) && (x <= maxfill))
{
if (255 <= a)
- {
dst = std::fill_n(dst, maxfill - x + 1, f);
- x = maxfill;
- }
else
- {
while (x++ <= maxfill)
alpha_blend(*dst++, a, r, g, b, inva);
- --x;
- }
+
--dst;
+ x = maxfill;
}
else
{
@@ -2345,6 +2497,7 @@ public:
led7seg_component(environment &env, util::xml::data_node const &compnode)
: component(env, compnode)
{
+ m_invert = env.get_attribute_int(compnode, "invert", 0);
}
protected:
@@ -2353,8 +2506,8 @@ protected:
virtual void draw_aligned(running_machine &machine, bitmap_argb32 &dest, const rectangle &bounds, int state) override
{
- rgb_t const onpen = rgb_t(0xff, 0xff, 0xff, 0xff);
- rgb_t const offpen = rgb_t(0x20, 0xff, 0xff, 0xff);
+ rgb_t const onpen = rgb_t(m_invert ? 0x20 : 0xff, 0xff, 0xff, 0xff);
+ rgb_t const offpen = rgb_t(m_invert ? 0xff : 0x20, 0xff, 0xff, 0xff);
// sizes for computation
int const bmwidth = 250;
@@ -2396,74 +2549,8 @@ protected:
// resample to the target size
render_resample_argb_bitmap_hq(dest, tempbitmap, color(state));
}
-};
-
-
-// 8-segment fluorescent (Gottlieb System 1)
-class layout_element::led8seg_gts1_component : public component
-{
-public:
- // construction/destruction
- led8seg_gts1_component(environment &env, util::xml::data_node const &compnode)
- : component(env, compnode)
- {
- }
-
-protected:
- // overrides
- virtual int maxstate() const override { return 255; }
-
- virtual void draw_aligned(running_machine &machine, bitmap_argb32 &dest, const rectangle &bounds, int state) override
- {
- rgb_t const onpen = rgb_t(0xff, 0xff, 0xff, 0xff);
- rgb_t const offpen = rgb_t(0x20, 0xff, 0xff, 0xff);
- rgb_t const backpen = rgb_t(0x00, 0x00, 0x00, 0x00);
-
- // sizes for computation
- int const bmwidth = 250;
- int const bmheight = 400;
- int const segwidth = 40;
- int const skewwidth = 40;
-
- // allocate a temporary bitmap for drawing
- bitmap_argb32 tempbitmap(bmwidth + skewwidth, bmheight);
- tempbitmap.fill(backpen);
-
- // top bar
- draw_segment_horizontal(tempbitmap, 0 + 2*segwidth/3, bmwidth - 2*segwidth/3, 0 + segwidth/2, segwidth, (state & (1 << 0)) ? onpen : offpen);
-
- // top-right bar
- draw_segment_vertical(tempbitmap, 0 + 2*segwidth/3, bmheight/2 - segwidth/3, bmwidth - segwidth/2, segwidth, (state & (1 << 1)) ? onpen : offpen);
-
- // bottom-right bar
- draw_segment_vertical(tempbitmap, bmheight/2 + segwidth/3, bmheight - 2*segwidth/3, bmwidth - segwidth/2, segwidth, (state & (1 << 2)) ? onpen : offpen);
-
- // bottom bar
- draw_segment_horizontal(tempbitmap, 0 + 2*segwidth/3, bmwidth - 2*segwidth/3, bmheight - segwidth/2, segwidth, (state & (1 << 3)) ? onpen : offpen);
-
- // bottom-left bar
- draw_segment_vertical(tempbitmap, bmheight/2 + segwidth/3, bmheight - 2*segwidth/3, 0 + segwidth/2, segwidth, (state & (1 << 4)) ? onpen : offpen);
-
- // top-left bar
- draw_segment_vertical(tempbitmap, 0 + 2*segwidth/3, bmheight/2 - segwidth/3, 0 + segwidth/2, segwidth, (state & (1 << 5)) ? onpen : offpen);
-
- // horizontal bars
- draw_segment_horizontal(tempbitmap, 0 + 2*segwidth/3, 2*bmwidth/3 - 2*segwidth/3, bmheight/2, segwidth, (state & (1 << 6)) ? onpen : offpen);
- draw_segment_horizontal(tempbitmap, 0 + 2*segwidth/3 + bmwidth/2, bmwidth - 2*segwidth/3, bmheight/2, segwidth, (state & (1 << 6)) ? onpen : offpen);
-
- // vertical bars
- draw_segment_vertical(tempbitmap, 0 + segwidth/3 - 8, bmheight/2 - segwidth/3 + 2, 2*bmwidth/3 - segwidth/2 - 4, segwidth + 8, backpen);
- draw_segment_vertical(tempbitmap, 0 + segwidth/3, bmheight/2 - segwidth/3, 2*bmwidth/3 - segwidth/2 - 4, segwidth, (state & (1 << 7)) ? onpen : offpen);
-
- draw_segment_vertical(tempbitmap, bmheight/2 + segwidth/3 - 2, bmheight - segwidth/3 + 8, 2*bmwidth/3 - segwidth/2 - 4, segwidth + 8, backpen);
- draw_segment_vertical(tempbitmap, bmheight/2 + segwidth/3, bmheight - segwidth/3, 2*bmwidth/3 - segwidth/2 - 4, segwidth, (state & (1 << 7)) ? onpen : offpen);
-
- // apply skew
- apply_skew(tempbitmap, 40);
-
- // resample to the target size
- render_resample_argb_bitmap_hq(dest, tempbitmap, color(state));
- }
+private:
+ int m_invert = 0;
};
@@ -2956,47 +3043,6 @@ protected:
};
-// row of dots for a dotmatrix
-class layout_element::dotmatrix_component : public component
-{
-public:
- // construction/destruction
- dotmatrix_component(int dots, environment &env, util::xml::data_node const &compnode)
- : component(env, compnode)
- , m_dots(dots)
- {
- }
-
-protected:
- // overrides
- virtual int maxstate() const override { return (1 << m_dots) - 1; }
-
- virtual void draw_aligned(running_machine &machine, bitmap_argb32 &dest, const rectangle &bounds, int state) override
- {
- const rgb_t onpen = rgb_t(0xff, 0xff, 0xff, 0xff);
- const rgb_t offpen = rgb_t(0xff, 0x20, 0x20, 0x20);
-
- // sizes for computation
- int bmheight = 300;
- int dotwidth = 250;
-
- // allocate a temporary bitmap for drawing
- bitmap_argb32 tempbitmap(dotwidth*m_dots, bmheight);
- tempbitmap.fill(rgb_t(0xff, 0x00, 0x00, 0x00));
-
- for (int i = 0; i < m_dots; i++)
- draw_segment_decimal(tempbitmap, ((dotwidth / 2) + (i * dotwidth)), bmheight / 2, dotwidth, BIT(state, i) ? onpen : offpen);
-
- // resample to the target size
- render_resample_argb_bitmap_hq(dest, tempbitmap, color(state));
- }
-
-private:
- // internal state
- int m_dots;
-};
-
-
// simple counter
class layout_element::simplecounter_component : public component
{
@@ -3040,6 +3086,8 @@ public:
, m_searchpath(env.search_path() ? env.search_path() : "")
, m_dirname(env.directory_name() ? env.directory_name() : "")
{
+ osd_printf_warning("Warning: layout file contains deprecated reel component\n");
+
std::string_view symbollist = env.get_attribute_string(compnode, "symbollist", "0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15");
// split out position names from string and figure out our number of symbols
@@ -3096,7 +3144,7 @@ protected:
// shift the reels a bit based on this param, allows fine tuning
int use_state = (state + m_stateoffset) % max_state_used;
- // compute premultiplied colors
+ // compute premultiplied color
render_color const c(color(state));
u32 const r = c.r * 255.0f;
u32 const g = c.g * 255.0f;
@@ -3178,10 +3226,10 @@ protected:
width = font->string_width(ourheight / num_shown, aspect, m_stopnames[fruit]);
if (width < bounds.width())
break;
- aspect *= 0.9f;
+ aspect *= 0.95f;
}
- s32 curx = bounds.left() + (bounds.width() - width) / 2;
+ float curx = bounds.left() + (bounds.width() - width) / 2.0f;
// loop over characters
std::string_view s = m_stopnames[fruit];
@@ -3208,7 +3256,7 @@ protected:
u32 *const d = &dest.pix(effy);
for (int x = 0; x < chbounds.width(); x++)
{
- int effx = curx + x + chbounds.left();
+ int effx = int(curx) + x + chbounds.left();
if (effx >= bounds.left() && effx <= bounds.right())
{
u32 spix = rgb_t(src[x]).a();
@@ -3248,7 +3296,7 @@ private:
// shift the reels a bit based on this param, allows fine tuning
int use_state = (state + m_stateoffset) % max_state_used;
- // compute premultiplied colors
+ // compute premultiplied color
render_color const c(color(state));
u32 const r = c.r * 255.0f;
u32 const g = c.g * 255.0f;
@@ -3326,10 +3374,10 @@ private:
width = font->string_width(dest.height(), aspect, m_stopnames[fruit]);
if (width < bounds.width())
break;
- aspect *= 0.9f;
+ aspect *= 0.95f;
}
- s32 curx = bounds.left();
+ float curx = bounds.left();
// allocate a temporary bitmap
bitmap_argb32 tempbitmap(dest.width(), dest.height());
@@ -3359,7 +3407,7 @@ private:
u32 *const d = &dest.pix(effy);
for (int x = 0; x < chbounds.width(); x++)
{
- int effx = basex + curx + x;
+ int effx = basex + int(curx) + x;
if (effx >= bounds.left() && effx <= bounds.right())
{
u32 spix = rgb_t(src[x]).a();
@@ -3396,12 +3444,10 @@ private:
std::string filename;
if (!m_searchpath.empty())
filename = m_dirname;
- if (!filename.empty() && !util::is_directory_separator(filename[filename.size() - 1]))
- filename.append(PATH_SEPARATOR);
- filename.append(m_imagefile[number]);
+ util::path_append(filename, m_imagefile[number]);
// load the basic bitmap
- if (file.open(filename) == osd_file::error::NONE)
+ if (!file.open(filename))
render_load_png(m_bitmap[number], file);
// if we can't load the bitmap just use text rendering
@@ -3437,18 +3483,6 @@ layout_element::component::ptr layout_element::make_component(environment &env,
}
-//-------------------------------------------------
-// make_component - create dotmatrix component
-// with given vertical resolution
-//-------------------------------------------------
-
-template <int D>
-layout_element::component::ptr layout_element::make_dotmatrix_component(environment &env, util::xml::data_node const &compnode)
-{
- return std::make_unique<dotmatrix_component>(D, env, compnode);
-}
-
-
//**************************************************************************
// LAYOUT ELEMENT TEXTURE
@@ -3478,7 +3512,7 @@ layout_element::texture::texture(texture &&that) : texture()
layout_element::texture::~texture()
{
- if (m_element != nullptr)
+ if (m_element)
m_element->machine().render().texture_free(m_texture);
}
@@ -3680,12 +3714,6 @@ void layout_element::component::draw_text(
int align,
const render_color &color)
{
- // compute premultiplied colors
- u32 const r(color.r * 255.0f);
- u32 const g(color.g * 255.0f);
- u32 const b(color.b * 255.0f);
- u32 const a(color.a * 255.0f);
-
// get the width of the string
float aspect = 1.0f;
s32 width;
@@ -3695,11 +3723,11 @@ void layout_element::component::draw_text(
width = font.string_width(bounds.height(), aspect, str);
if (width < bounds.width())
break;
- aspect *= 0.9f;
+ aspect *= 0.95f;
}
// get alignment
- s32 curx;
+ float curx;
switch (align)
{
// left
@@ -3714,7 +3742,7 @@ void layout_element::component::draw_text(
// default to center
default:
- curx = bounds.left() + (bounds.width() - width) / 2;
+ curx = bounds.left() + (bounds.width() - width) / 2.0f;
break;
}
@@ -3744,18 +3772,13 @@ void layout_element::component::draw_text(
u32 *const d = &dest.pix(effy);
for (int x = 0; x < chbounds.width(); x++)
{
- int effx = curx + x + chbounds.left();
+ int effx = int(curx) + x + chbounds.left();
if (effx >= bounds.left() && effx <= bounds.right())
{
u32 spix = rgb_t(src[x]).a();
if (spix != 0)
{
- rgb_t dpix = d[effx];
- u32 ta = (a * (spix + 1)) >> 8;
- u32 tr = (r * ta + dpix.r() * (0x100 - ta)) >> 8;
- u32 tg = (g * ta + dpix.g() * (0x100 - ta)) >> 8;
- u32 tb = (b * ta + dpix.b() * (0x100 - ta)) >> 8;
- d[effx] = rgb_t(tr, tg, tb);
+ alpha_blend(d[effx], color, spix / 255.0);
}
}
}
@@ -3974,9 +3997,20 @@ layout_view::layout_view(
: m_effaspect(1.0f)
, m_name(make_name(env, viewnode))
, m_unqualified_name(env.get_attribute_string(viewnode, "name"))
+ , m_elemmap(elemmap)
, m_defvismask(0U)
, m_has_art(false)
+ , m_show_ptr(false)
+ , m_ptr_time_out(true) // FIXME: add attribute for this
+ , m_exp_show_ptr(-1)
{
+ // check for explicit pointer display setting
+ if (viewnode.get_attribute_string_ptr("showpointers"))
+ {
+ m_show_ptr = env.get_attribute_bool(viewnode, "showpointers", false);
+ m_exp_show_ptr = m_show_ptr ? 1 : 0;
+ }
+
// parse the layout
m_expbounds.x0 = m_expbounds.y0 = m_expbounds.x1 = m_expbounds.y1 = 0;
view_environment local(env, m_name.c_str());
@@ -4090,7 +4124,7 @@ layout_view::~layout_view()
// get_item - get item by ID
//-------------------------------------------------
-layout_view::item *layout_view::get_item(std::string const &id)
+layout_view_item *layout_view::get_item(std::string const &id)
{
auto const found(m_items_by_id.find(id));
return (m_items_by_id.end() != found) ? &found->second : nullptr;
@@ -4120,6 +4154,21 @@ bool layout_view::has_visible_screen(screen_device const &screen) const
//-------------------------------------------------
+// prepare_items - perform additional tasks
+// before rendering a frame
+//-------------------------------------------------
+
+void layout_view::prepare_items()
+{
+ if (!m_prepare_items.isnull())
+ m_prepare_items();
+
+ for (auto &[name, element] : m_elemmap)
+ element.prepare();
+}
+
+
+//-------------------------------------------------
// recompute - recompute the bounds and aspect
// ratio of a view and all of its contained items
//-------------------------------------------------
@@ -4139,6 +4188,7 @@ void layout_view::recompute(u32 visibility_mask, bool zoom_to_screen)
// loop over items and filter by visibility mask
bool first = true;
bool scrfirst = true;
+ bool haveinput = false;
for (item &curitem : m_items)
{
if ((visibility_mask & curitem.visibility_mask()) == curitem.visibility_mask())
@@ -4170,9 +4220,15 @@ void layout_view::recompute(u32 visibility_mask, bool zoom_to_screen)
// accumulate interactive elements
if (!curitem.clickthrough() || curitem.has_input())
m_interactive_items.emplace_back(curitem);
+ if (curitem.has_input())
+ haveinput = true;
}
}
+ // if show pointers isn't explicitly, update it based on visible items
+ if (0 > m_exp_show_ptr)
+ m_show_ptr = haveinput;
+
// if we have an explicit bounds, override it
if (m_expbounds.x1 > m_expbounds.x0)
m_bounds = m_expbounds;
@@ -4212,6 +4268,7 @@ void layout_view::recompute(u32 visibility_mask, bool zoom_to_screen)
// sort edges of interactive items
LOGMASKED(LOG_INTERACTIVE_ITEMS, "Recalculated view '%s' with %u interactive items\n",
name(), m_interactive_items.size());
+ //std::reverse(m_interactive_items.begin(), m_interactive_items.end()); TODO: flip hit test order to match visual order
m_interactive_edges_x.reserve(m_interactive_items.size() * 2);
m_interactive_edges_y.reserve(m_interactive_items.size() * 2);
for (unsigned i = 0; m_interactive_items.size() > i; ++i)
@@ -4243,6 +4300,29 @@ void layout_view::recompute(u32 visibility_mask, bool zoom_to_screen)
//-------------------------------------------------
+// set_show_pointers - set whether pointers
+// should be displayed
+//-------------------------------------------------
+
+void layout_view::set_show_pointers(bool value) noexcept
+{
+ m_show_ptr = value;
+ m_exp_show_ptr = value ? 1 : 0;
+}
+
+
+//-------------------------------------------------
+// set_pointers_time_out - set whether pointers
+// should be hidden after inactivity
+//-------------------------------------------------
+
+void layout_view::set_hide_inactive_pointers(bool value) noexcept
+{
+ m_ptr_time_out = value;
+}
+
+
+//-------------------------------------------------
// set_prepare_items_callback - set handler called
// before adding items to render target
//-------------------------------------------------
@@ -4276,6 +4356,50 @@ void layout_view::set_recomputed_callback(recomputed_delegate &&handler)
//-------------------------------------------------
+// set_pointer_updated_callback - set handler
+// called for pointer input
+//-------------------------------------------------
+
+void layout_view::set_pointer_updated_callback(pointer_updated_delegate &&handler)
+{
+ m_pointer_updated = std::move(handler);
+}
+
+
+//-------------------------------------------------
+// set_pointer_left_callback - set handler for
+// pointer leaving normally
+//-------------------------------------------------
+
+void layout_view::set_pointer_left_callback(pointer_left_delegate &&handler)
+{
+ m_pointer_left = std::move(handler);
+}
+
+
+//-------------------------------------------------
+// set_pointer_aborted_callback - set handler for
+// pointer leaving abnormally
+//-------------------------------------------------
+
+void layout_view::set_pointer_aborted_callback(pointer_left_delegate &&handler)
+{
+ m_pointer_aborted = std::move(handler);
+}
+
+
+//-------------------------------------------------
+// set_forget_pointers_callback - set handler for
+// abandoning pointer input
+//-------------------------------------------------
+
+void layout_view::set_forget_pointers_callback(forget_pointers_delegate &&handler)
+{
+ m_forget_pointers = std::move(handler);
+}
+
+
+//-------------------------------------------------
// preload - perform expensive loading upfront
// for visible elements
//-------------------------------------------------
@@ -4496,10 +4620,10 @@ std::string layout_view::make_name(layout_environment &env, util::xml::data_node
//**************************************************************************
//-------------------------------------------------
-// item - constructor
+// layout_view_item - constructor
//-------------------------------------------------
-layout_view::item::item(
+layout_view_item::layout_view_item(
view_environment &env,
util::xml::data_node const &itemnode,
element_map &elemmap,
@@ -4508,11 +4632,29 @@ layout_view::item::item(
render_color const &color)
: m_element(find_element(env, itemnode, elemmap))
, m_output(env.device(), std::string(env.get_attribute_string(itemnode, "name")))
- , m_animoutput(env.device(), make_animoutput_tag(env, itemnode))
+ , m_animoutput(env.device(), make_child_output_tag(env, itemnode, "animate"))
+ , m_scrollxoutput(env.device(), make_child_output_tag(env, itemnode, "xscroll"))
+ , m_scrollyoutput(env.device(), make_child_output_tag(env, itemnode, "yscroll"))
, m_animinput_port(nullptr)
+ , m_scrollxinput_port(nullptr)
+ , m_scrollyinput_port(nullptr)
+ , m_scrollwrapx(make_child_wrap(env, itemnode, "xscroll"))
+ , m_scrollwrapy(make_child_wrap(env, itemnode, "yscroll"))
, m_elem_state(m_element ? m_element->default_state() : 0)
- , m_animmask(make_animmask(env, itemnode))
+ , m_scrollsizex(make_child_size(env, itemnode, "xscroll"))
+ , m_scrollsizey(make_child_size(env, itemnode, "yscroll"))
+ , m_scrollposx(0.0f)
+ , m_scrollposy(0.0f)
+ , m_animmask(make_child_mask(env, itemnode, "animate"))
+ , m_scrollxmask(make_child_mask(env, itemnode, "xscroll"))
+ , m_scrollymask(make_child_mask(env, itemnode, "yscroll"))
+ , m_scrollxmin(make_child_min(env, itemnode, "xscroll"))
+ , m_scrollymin(make_child_min(env, itemnode, "yscroll"))
+ , m_scrollxmax(make_child_max(env, itemnode, "xscroll", m_scrollxmask))
+ , m_scrollymax(make_child_max(env, itemnode, "yscroll", m_scrollymask))
, m_animshift(get_state_shift(m_animmask))
+ , m_scrollxshift(get_state_shift(m_scrollxmask))
+ , m_scrollyshift(get_state_shift(m_scrollymask))
, m_input_port(nullptr)
, m_input_field(nullptr)
, m_input_mask(env.get_attribute_int(itemnode, "inputmask", 0))
@@ -4525,11 +4667,15 @@ layout_view::item::item(
, m_visibility_mask(env.visibility_mask())
, m_id(env.get_attribute_string(itemnode, "id"))
, m_input_tag(make_input_tag(env, itemnode))
- , m_animinput_tag(make_animinput_tag(env, itemnode))
+ , m_animinput_tag(make_child_input_tag(env, itemnode, "animate"))
+ , m_scrollxinput_tag(make_child_input_tag(env, itemnode, "xscroll"))
+ , m_scrollyinput_tag(make_child_input_tag(env, itemnode, "yscroll"))
, m_rawbounds(make_bounds(env, itemnode, trans))
, m_have_output(!env.get_attribute_string(itemnode, "name").empty())
, m_input_raw(env.get_attribute_bool(itemnode, "inputraw", 0))
- , m_have_animoutput(!make_animoutput_tag(env, itemnode).empty())
+ , m_have_animoutput(!make_child_output_tag(env, itemnode, "animate").empty())
+ , m_have_scrollxoutput(!make_child_output_tag(env, itemnode, "xscroll").empty())
+ , m_have_scrollyoutput(!make_child_output_tag(env, itemnode, "yscroll").empty())
, m_has_clickthrough(!env.get_attribute_string(itemnode, "clickthrough").empty())
{
// fetch common data
@@ -4556,6 +4702,14 @@ layout_view::item::item(
{
throw layout_syntax_error(util::string_format("item of type %s requires an element tag", itemnode.get_name()));
}
+ else if (m_scrollxmin == m_scrollxmax)
+ {
+ throw layout_syntax_error(util::string_format("item X scroll minimum and maximum both equal to %u", m_scrollxmin));
+ }
+ else if (m_scrollymin == m_scrollymax)
+ {
+ throw layout_syntax_error(util::string_format("item Y scroll minimum and maximum both equal to %u", m_scrollymin));
+ }
// this can be called before resolving tags, make it return something valid
m_bounds = m_rawbounds;
@@ -4564,10 +4718,10 @@ layout_view::item::item(
//-------------------------------------------------
-// item - destructor
+// layout_view_item - destructor
//-------------------------------------------------
-layout_view::item::~item()
+layout_view_item::~layout_view_item()
{
}
@@ -4577,7 +4731,7 @@ layout_view::item::~item()
// obtain element state value
//-------------------------------------------------
-void layout_view::item::set_element_state_callback(state_delegate &&handler)
+void layout_view_item::set_element_state_callback(state_delegate &&handler)
{
if (!handler.isnull())
m_get_elem_state = std::move(handler);
@@ -4591,7 +4745,7 @@ void layout_view::item::set_element_state_callback(state_delegate &&handler)
// obtain animation state
//-------------------------------------------------
-void layout_view::item::set_animation_state_callback(state_delegate &&handler)
+void layout_view_item::set_animation_state_callback(state_delegate &&handler)
{
if (!handler.isnull())
m_get_anim_state = std::move(handler);
@@ -4605,7 +4759,7 @@ void layout_view::item::set_animation_state_callback(state_delegate &&handler)
// bounds
//-------------------------------------------------
-void layout_view::item::set_bounds_callback(bounds_delegate &&handler)
+void layout_view_item::set_bounds_callback(bounds_delegate &&handler)
{
if (!handler.isnull())
m_get_bounds = std::move(handler);
@@ -4619,7 +4773,7 @@ void layout_view::item::set_bounds_callback(bounds_delegate &&handler)
// color
//-------------------------------------------------
-void layout_view::item::set_color_callback(color_delegate &&handler)
+void layout_view_item::set_color_callback(color_delegate &&handler)
{
if (!handler.isnull())
m_get_color = std::move(handler);
@@ -4629,10 +4783,66 @@ void layout_view::item::set_color_callback(color_delegate &&handler)
//-------------------------------------------------
+// set_scroll_size_x_callback - set callback to
+// obtain horizontal scroll window size
+//-------------------------------------------------
+
+void layout_view_item::set_scroll_size_x_callback(scroll_size_delegate &&handler)
+{
+ if (!handler.isnull())
+ m_get_scroll_size_x = std::move(handler);
+ else
+ m_get_scroll_size_x = default_get_scroll_size_x();
+}
+
+
+//-------------------------------------------------
+// set_scroll_size_y_callback - set callback to
+// obtain vertical scroll window size
+//-------------------------------------------------
+
+void layout_view_item::set_scroll_size_y_callback(scroll_size_delegate &&handler)
+{
+ if (!handler.isnull())
+ m_get_scroll_size_y = std::move(handler);
+ else
+ m_get_scroll_size_y = default_get_scroll_size_y();
+}
+
+
+//-------------------------------------------------
+// set_scroll_pos_x_callback - set callback to
+// obtain horizontal scroll position
+//-------------------------------------------------
+
+void layout_view_item::set_scroll_pos_x_callback(scroll_pos_delegate &&handler)
+{
+ if (!handler.isnull())
+ m_get_scroll_pos_x = std::move(handler);
+ else
+ m_get_scroll_pos_x = default_get_scroll_pos_x();
+}
+
+
+//-------------------------------------------------
+// set_scroll_pos_y_callback - set callback to
+// obtain vertical scroll position
+//-------------------------------------------------
+
+void layout_view_item::set_scroll_pos_y_callback(scroll_pos_delegate &&handler)
+{
+ if (!handler.isnull())
+ m_get_scroll_pos_y = std::move(handler);
+ else
+ m_get_scroll_pos_y = default_get_scroll_pos_y();
+}
+
+
+//-------------------------------------------------
// resolve_tags - resolve tags, if any are set
//-------------------------------------------------
-void layout_view::item::resolve_tags()
+void layout_view_item::resolve_tags()
{
// resolve element state output and set default value
if (m_have_output)
@@ -4642,13 +4852,21 @@ void layout_view::item::resolve_tags()
m_output = m_element->default_state();
}
- // resolve animation state output
+ // resolve animation state and scroll outputs
if (m_have_animoutput)
m_animoutput.resolve();
+ if (m_have_scrollxoutput)
+ m_scrollxoutput.resolve();
+ if (m_have_scrollyoutput)
+ m_scrollyoutput.resolve();
- // resolve animation state input
+ // resolve animation state and scroll inputs
if (!m_animinput_tag.empty())
m_animinput_port = m_element->machine().root_device().ioport(m_animinput_tag);
+ if (!m_scrollxinput_tag.empty())
+ m_scrollxinput_port = m_element->machine().root_device().ioport(m_scrollxinput_tag);
+ if (!m_scrollyinput_tag.empty())
+ m_scrollyinput_port = m_element->machine().root_device().ioport(m_scrollyinput_tag);
// resolve element state input
if (!m_input_tag.empty())
@@ -4657,7 +4875,7 @@ void layout_view::item::resolve_tags()
if (m_input_port)
{
// if there's a matching unconditional field, cache it
- for (ioport_field &field : m_input_port->fields())
+ for (ioport_field const &field : m_input_port->fields())
{
if (field.mask() & m_input_mask)
{
@@ -4678,6 +4896,10 @@ void layout_view::item::resolve_tags()
m_get_anim_state = default_get_anim_state();
m_get_bounds = default_get_bounds();
m_get_color = default_get_color();
+ m_get_scroll_size_x = default_get_scroll_size_x();
+ m_get_scroll_size_y = default_get_scroll_size_y();
+ m_get_scroll_pos_x = default_get_scroll_pos_x();
+ m_get_scroll_pos_y = default_get_scroll_pos_y();
}
@@ -4686,18 +4908,18 @@ void layout_view::item::resolve_tags()
// state handler
//-------------------------------------------------
-layout_view::item::state_delegate layout_view::item::default_get_elem_state()
+layout_view_item::state_delegate layout_view_item::default_get_elem_state()
{
if (m_have_output)
- return state_delegate(&item::get_output, this);
+ return state_delegate(&layout_view_item::get_output, this);
else if (!m_input_port)
- return state_delegate(&item::get_state, this);
+ return state_delegate(&layout_view_item::get_state, this);
else if (m_input_raw)
- return state_delegate(&item::get_input_raw, this);
+ return state_delegate(&layout_view_item::get_input_raw, this);
else if (m_input_field)
- return state_delegate(&item::get_input_field_cached, this);
+ return state_delegate(&layout_view_item::get_input_field_cached, this);
else
- return state_delegate(&item::get_input_field_conditional, this);
+ return state_delegate(&layout_view_item::get_input_field_conditional, this);
}
@@ -4706,12 +4928,12 @@ layout_view::item::state_delegate layout_view::item::default_get_elem_state()
// state handler
//-------------------------------------------------
-layout_view::item::state_delegate layout_view::item::default_get_anim_state()
+layout_view_item::state_delegate layout_view_item::default_get_anim_state()
{
if (m_have_animoutput)
- return state_delegate(&item::get_anim_output, this);
+ return state_delegate(&layout_view_item::get_anim_output, this);
else if (m_animinput_port)
- return state_delegate(&item::get_anim_input, this);
+ return state_delegate(&layout_view_item::get_anim_input, this);
else
return default_get_elem_state();
}
@@ -4721,11 +4943,11 @@ layout_view::item::state_delegate layout_view::item::default_get_anim_state()
// default_get_bounds - get default bounds handler
//-------------------------------------------------
-layout_view::item::bounds_delegate layout_view::item::default_get_bounds()
+layout_view_item::bounds_delegate layout_view_item::default_get_bounds()
{
return (m_bounds.size() == 1U)
? bounds_delegate(&emu::render::detail::bounds_step::get, &m_bounds.front())
- : bounds_delegate(&item::get_interpolated_bounds, this);
+ : bounds_delegate(&layout_view_item::get_interpolated_bounds, this);
}
@@ -4733,11 +4955,65 @@ layout_view::item::bounds_delegate layout_view::item::default_get_bounds()
// default_get_color - get default color handler
//-------------------------------------------------
-layout_view::item::color_delegate layout_view::item::default_get_color()
+layout_view_item::color_delegate layout_view_item::default_get_color()
{
return (m_color.size() == 1U)
? color_delegate(&emu::render::detail::color_step::get, &const_cast<emu::render::detail::color_step &>(m_color.front()))
- : color_delegate(&item::get_interpolated_color, this);
+ : color_delegate(&layout_view_item::get_interpolated_color, this);
+}
+
+
+//-------------------------------------------------
+// default_get_scroll_size_x - get default
+// horizontal scroll window size handler
+//-------------------------------------------------
+
+layout_view_item::scroll_size_delegate layout_view_item::default_get_scroll_size_x()
+{
+ return scroll_size_delegate(&layout_view_item::get_scrollsizex, this);
+}
+
+
+//-------------------------------------------------
+// default_get_scroll_size_y - get default
+// vertical scroll window size handler
+//-------------------------------------------------
+
+layout_view_item::scroll_size_delegate layout_view_item::default_get_scroll_size_y()
+{
+ return scroll_size_delegate(&layout_view_item::get_scrollsizey, this);
+}
+
+
+//-------------------------------------------------
+// default_get_scroll_pos_x - get default
+// horizontal scroll position handler
+//-------------------------------------------------
+
+layout_view_item::scroll_pos_delegate layout_view_item::default_get_scroll_pos_x()
+{
+ if (m_have_scrollxoutput)
+ return scroll_pos_delegate(m_scrollwrapx ? &layout_view_item::get_scrollx_output<true> : &layout_view_item::get_scrollx_output<false>, this);
+ else if (m_scrollxinput_port)
+ return scroll_pos_delegate(m_scrollwrapx ? &layout_view_item::get_scrollx_input<true> : &layout_view_item::get_scrollx_input<false>, this);
+ else
+ return scroll_pos_delegate(&layout_view_item::get_scrollposx, this);
+}
+
+
+//-------------------------------------------------
+// default_get_scroll_pos_y - get default
+// vertical scroll position handler
+//-------------------------------------------------
+
+layout_view_item::scroll_pos_delegate layout_view_item::default_get_scroll_pos_y()
+{
+ if (m_have_scrollyoutput)
+ return scroll_pos_delegate(m_scrollwrapy ? &layout_view_item::get_scrolly_output<true> : &layout_view_item::get_scrolly_output<false>, this);
+ else if (m_scrollyinput_port)
+ return scroll_pos_delegate(m_scrollwrapy ? &layout_view_item::get_scrolly_input<true> : &layout_view_item::get_scrolly_input<false>, this);
+ else
+ return scroll_pos_delegate(&layout_view_item::get_scrollposy, this);
}
@@ -4745,7 +5021,7 @@ layout_view::item::color_delegate layout_view::item::default_get_color()
// get_state - get state when no bindings
//-------------------------------------------------
-int layout_view::item::get_state() const
+int layout_view_item::get_state() const
{
return m_elem_state;
}
@@ -4755,7 +5031,7 @@ int layout_view::item::get_state() const
// get_output - get element state output
//-------------------------------------------------
-int layout_view::item::get_output() const
+int layout_view_item::get_output() const
{
assert(m_have_output);
return int(s32(m_output));
@@ -4766,7 +5042,7 @@ int layout_view::item::get_output() const
// get_input_raw - get element state input
//-------------------------------------------------
-int layout_view::item::get_input_raw() const
+int layout_view_item::get_input_raw() const
{
assert(m_input_port);
return int(std::make_signed_t<ioport_value>((m_input_port->read() & m_input_mask) >> m_input_shift));
@@ -4777,7 +5053,7 @@ int layout_view::item::get_input_raw() const
// get_input_field_cached - element state
//-------------------------------------------------
-int layout_view::item::get_input_field_cached() const
+int layout_view_item::get_input_field_cached() const
{
assert(m_input_port);
assert(m_input_field);
@@ -4789,7 +5065,7 @@ int layout_view::item::get_input_field_cached() const
// get_input_field_conditional - element state
//-------------------------------------------------
-int layout_view::item::get_input_field_conditional() const
+int layout_view_item::get_input_field_conditional() const
{
assert(m_input_port);
assert(!m_input_field);
@@ -4802,7 +5078,7 @@ int layout_view::item::get_input_field_conditional() const
// get_anim_output - get animation output
//-------------------------------------------------
-int layout_view::item::get_anim_output() const
+int layout_view_item::get_anim_output() const
{
assert(m_have_animoutput);
return int(unsigned((u32(s32(m_animoutput) & m_animmask) >> m_animshift)));
@@ -4813,7 +5089,7 @@ int layout_view::item::get_anim_output() const
// get_anim_input - get animation input
//-------------------------------------------------
-int layout_view::item::get_anim_input() const
+int layout_view_item::get_anim_input() const
{
assert(m_animinput_port);
return int(std::make_signed_t<ioport_value>((m_animinput_port->read() & m_animmask) >> m_animshift));
@@ -4821,13 +5097,116 @@ int layout_view::item::get_anim_input() const
//-------------------------------------------------
+// get_scrollsizex - get horizontal scroll window
+// size
+//-------------------------------------------------
+
+float layout_view_item::get_scrollsizex() const
+{
+ return m_scrollsizex;
+}
+
+
+//-------------------------------------------------
+// get_scrollsizey - get vertical scroll window
+// size
+//-------------------------------------------------
+
+float layout_view_item::get_scrollsizey() const
+{
+ return m_scrollsizey;
+}
+
+
+//-------------------------------------------------
+// get_scrollposx - get horizontal scroll
+// position
+//-------------------------------------------------
+
+float layout_view_item::get_scrollposx() const
+{
+ return m_scrollposx;
+}
+
+
+//-------------------------------------------------
+// get_scrollposy - get vertical scroll position
+//-------------------------------------------------
+
+float layout_view_item::get_scrollposy() const
+{
+ return m_scrollposy;
+}
+
+
+//-------------------------------------------------
+// get_scrollx_output - get scaled horizontal
+// scroll output
+//-------------------------------------------------
+
+template <bool Wrap>
+float layout_view_item::get_scrollx_output() const
+{
+ assert(m_have_scrollxoutput);
+ u32 const unscaled(((u32(s32(m_scrollxoutput)) & m_scrollxmask) >> m_scrollxshift) - m_scrollxmin);
+ float const range(std::make_signed_t<ioport_value>(m_scrollxmax - m_scrollxmin) + (!Wrap ? 0 : (m_scrollxmin < m_scrollxmax) ? 1 : -1));
+ return float(s32(unscaled)) / range;
+}
+
+
+//-------------------------------------------------
+// get_scrollx_input - get scaled horizontal
+// scroll input
+//-------------------------------------------------
+
+template <bool Wrap>
+float layout_view_item::get_scrollx_input() const
+{
+ assert(m_scrollxinput_port);
+ ioport_value const unscaled(((m_scrollxinput_port->read() & m_scrollxmask) >> m_scrollxshift) - m_scrollxmin);
+ float const range(std::make_signed_t<ioport_value>(m_scrollxmax - m_scrollxmin) + (!Wrap ? 0 : (m_scrollxmin < m_scrollxmax) ? 1 : -1));
+ return float(std::make_signed_t<ioport_value>(unscaled)) / range;
+}
+
+
+//-------------------------------------------------
+// get_scrolly_output - get scaled vertical
+// scroll output
+//-------------------------------------------------
+
+template <bool Wrap>
+float layout_view_item::get_scrolly_output() const
+{
+ assert(m_have_scrollyoutput);
+ u32 const unscaled(((u32(s32(m_scrollyoutput)) & m_scrollymask) >> m_scrollyshift) - m_scrollymin);
+ float const range(std::make_signed_t<ioport_value>(m_scrollymax - m_scrollymin) + (!Wrap ? 0 : (m_scrollymin < m_scrollymax) ? 1 : -1));
+ return float(s32(unscaled)) / range;
+}
+
+
+//-------------------------------------------------
+// get_scrolly_input - get scaled vertical scroll
+// input
+//-------------------------------------------------
+
+template <bool Wrap>
+float layout_view_item::get_scrolly_input() const
+{
+ assert(m_scrollyinput_port);
+ ioport_value const unscaled(((m_scrollyinput_port->read() & m_scrollymask) >> m_scrollyshift) - m_scrollymin);
+ float const range(std::make_signed_t<ioport_value>(m_scrollymax - m_scrollymin) + (!Wrap ? 0 : (m_scrollymin < m_scrollymax) ? 1 : -1));
+ return float(std::make_signed_t<ioport_value>(unscaled)) / range;
+}
+
+
+//-------------------------------------------------
// get_interpolated_bounds - animated bounds
//-------------------------------------------------
-void layout_view::item::get_interpolated_bounds(render_bounds &result) const
+render_bounds layout_view_item::get_interpolated_bounds() const
{
assert(m_bounds.size() > 1U);
- result = interpolate_bounds(m_bounds, m_get_anim_state());
+ return interpolate_bounds(m_bounds, m_get_anim_state());
}
@@ -4835,10 +5214,10 @@ void layout_view::item::get_interpolated_bounds(render_bounds &result) const
// get_interpolated_color - animated color
//-------------------------------------------------
-void layout_view::item::get_interpolated_color(render_color &result) const
+render_color layout_view_item::get_interpolated_color() const
{
assert(m_color.size() > 1U);
- result = interpolate_color(m_color, m_get_anim_state());
+ return interpolate_color(m_color, m_get_anim_state());
}
@@ -4846,7 +5225,7 @@ void layout_view::item::get_interpolated_color(render_color &result) const
// find_element - find element definition
//-------------------------------------------------
-layout_element *layout_view::item::find_element(view_environment &env, util::xml::data_node const &itemnode, element_map &elemmap)
+layout_element *layout_view_item::find_element(view_environment &env, util::xml::data_node const &itemnode, element_map &elemmap)
{
std::string const name(env.get_attribute_string(itemnode, !strcmp(itemnode.get_name(), "element") ? "ref" : "element"));
if (name.empty())
@@ -4865,7 +5244,7 @@ layout_element *layout_view::item::find_element(view_environment &env, util::xml
// make_bounds - get transformed bounds
//-------------------------------------------------
-layout_view::item::bounds_vector layout_view::item::make_bounds(
+layout_view_item::bounds_vector layout_view_item::make_bounds(
view_environment &env,
util::xml::data_node const &itemnode,
layout_group::transform const &trans)
@@ -4898,7 +5277,7 @@ layout_view::item::bounds_vector layout_view::item::make_bounds(
// make_color - get color inflection points
//-------------------------------------------------
-layout_view::item::color_vector layout_view::item::make_color(
+layout_view_item::color_vector layout_view_item::make_color(
view_environment &env,
util::xml::data_node const &itemnode,
render_color const &mult)
@@ -4928,101 +5307,6 @@ layout_view::item::color_vector layout_view::item::make_color(
}
-//-------------------------------------------------
-// make_animoutput_tag - get animation output tag
-//-------------------------------------------------
-
-std::string layout_view::item::make_animoutput_tag(view_environment &env, util::xml::data_node const &itemnode)
-{
- util::xml::data_node const *const animate(itemnode.get_child("animate"));
- if (animate)
- return std::string(env.get_attribute_string(*animate, "name"));
- else
- return std::string();
-}
-
-
-//-------------------------------------------------
-// make_animmask - get animation state mask
-//-------------------------------------------------
-
-ioport_value layout_view::item::make_animmask(view_environment &env, util::xml::data_node const &itemnode)
-{
- util::xml::data_node const *const animate(itemnode.get_child("animate"));
- return animate ? env.get_attribute_int(*animate, "mask", ~ioport_value(0)) : ~ioport_value(0);
-}
-
-
-//-------------------------------------------------
-// make_animinput_tag - get absolute tag for
-// animation input
-//-------------------------------------------------
-
-std::string layout_view::item::make_animinput_tag(view_environment &env, util::xml::data_node const &itemnode)
-{
- util::xml::data_node const *const animate(itemnode.get_child("animate"));
- return animate ? env.get_attribute_subtag(*animate, "inputtag") : std::string();
-}
-
-
-//-------------------------------------------------
-// make_input_tag - get absolute input tag
-//-------------------------------------------------
-
-std::string layout_view::item::make_input_tag(view_environment &env, util::xml::data_node const &itemnode)
-{
- return env.get_attribute_subtag(itemnode, "inputtag");
-}
-
-
-//-------------------------------------------------
-// get_blend_mode - explicit or implicit blend
-//-------------------------------------------------
-
-int layout_view::item::get_blend_mode(view_environment &env, util::xml::data_node const &itemnode)
-{
- // see if there's a blend mode attribute
- std::string const *const mode(itemnode.get_attribute_string_ptr("blend"));
- if (mode)
- {
- if (*mode == "none")
- return BLENDMODE_NONE;
- else if (*mode == "alpha")
- return BLENDMODE_ALPHA;
- else if (*mode == "multiply")
- return BLENDMODE_RGB_MULTIPLY;
- else if (*mode == "add")
- return BLENDMODE_ADD;
- else
- throw layout_syntax_error(util::string_format("unknown blend mode %s", *mode));
- }
-
- // fall back to implicit blend mode based on element type
- if (!strcmp(itemnode.get_name(), "screen"))
- return -1; // magic number recognised by render.cpp to allow per-element blend mode
- else if (!strcmp(itemnode.get_name(), "overlay"))
- return BLENDMODE_RGB_MULTIPLY;
- else
- return BLENDMODE_ALPHA;
-}
-
-
-//-------------------------------------------------
-// get_state_shift - shift to right-align LSB
-//-------------------------------------------------
-
-unsigned layout_view::item::get_state_shift(ioport_value mask)
-{
- unsigned result(0U);
- while (mask && !BIT(mask, 0))
- {
- ++result;
- mask >>= 1;
- }
- return result;
-}
-
-
//**************************************************************************
// LAYOUT VIEW VISIBILITY TOGGLE