summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--docs/source/techspecs/layout_files.rst57
-rw-r--r--docs/source/techspecs/layout_script.rst64
-rw-r--r--docs/source/techspecs/luareference.rst76
-rwxr-xr-xscripts/build/complay.py28
-rw-r--r--src/emu/emufwd.h9
-rw-r--r--src/emu/render.cpp85
-rw-r--r--src/emu/render.h2
-rw-r--r--src/emu/rendlay.cpp547
-rw-r--r--src/emu/rendlay.h295
-rw-r--r--src/frontend/mame/luaengine_render.cpp72
10 files changed, 916 insertions, 319 deletions
diff --git a/docs/source/techspecs/layout_files.rst b/docs/source/techspecs/layout_files.rst
index be4965a9e95..c43a7df8e1b 100644
--- a/docs/source/techspecs/layout_files.rst
+++ b/docs/source/techspecs/layout_files.rst
@@ -406,8 +406,8 @@ usually comes from an I/O port field or an emulated output (see
:ref:`layfile-interact-elemstate` for information on connecting an element to an
emulated I/O port or output). Any component of an element may be restricted to
only drawing when the element’s state is a particular value. Some components
-(e.g. multi-segment displays and reels) use the state directly to determine
-their appearance.
+(e.g. multi-segment displays) use the state directly to determine their
+appearance.
Each element has its own internal coordinate system. The bounds of the
element’s coordinate system are computed as the union of the bounds of the
@@ -591,10 +591,6 @@ simplecounter
to set text alignment. If present, the ``align`` attribute must be an
integer, where 0 (zero) means centred, 1 (one) means left-aligned, and 2
(two) means right-aligned; if absent, the text will be centred.
-reel
- Used for drawing slot machine reels. Supported attributes include
- ``symbollist``, ``stateoffset``, ``numsymbolsvisible``, ``reelreversed``,
- and ``beltreel``.
An example element that draws a static left-aligned text string:
@@ -839,6 +835,48 @@ have their colour and position/size animated by supplying multiple ``color``
and/or ``bounds`` child elements with ``state`` attributes. See
:ref:`layfile-interact-itemanim` for details.
+Layout elements (``element`` elements) may be configured to show only part of
+the element’s width or height using ``xscroll`` and/or ``yscroll`` child
+elements. This can be used for devices like slot machine reels. The
+``xscroll`` and ``yscroll`` elements support the same attributes:
+
+size
+ The size of the horizontal or vertical scroll window, as a proportion of the
+ element’s width or height, respectively. Must be in the range 0.01 to 1.0,
+ inclusive, if present (1% of the width/height to the full width/height). By
+ default, the entire width and height of the element is shown.
+wrap
+ Whether the element should wrap horizontally or vertically. Must be either
+ ``yes`` or ``no`` if present. By default, items do not wrap horizontally or
+ vertically.
+inputtag
+ If present, the horizontal or vertical scroll position will be taken from
+ the value of the corresponding I/O port. Specifies the tag path of an I/O
+ port relative to the device that caused the layout file to be loaded. The
+ raw value from the input port is used, active-low switch values are not
+ normalised.
+name
+ If present, the horizontal or vertical scroll position will be taken from
+ the correspondingly named output.
+mask
+ If present, the horizontal or vertical scroll position will be masked with
+ the value and shifted to the right to remove trailing zeroes (for example a
+ mask of 0x05 will result in no shift, while a mask of 0x68 will result in
+ the value being shifted three bits to the right). Note that this applies to
+ output values (specified with the ``name`` attribute) as well as input port
+ values (specified with the ``inputtag`` attribute). Must be an integer
+ value if present. If not present, it is equivalent to all 32 bits being
+ set.
+min
+ Minimum horizontal or vertical scroll position value. When the horizontal
+ or vertical scroll position has this value, the left or top edge or the
+ scroll window will be aligned with the left or top edge of the element.
+ Must be an integer value if present. Defaults to zero.
+max
+ Maximum horizontal or vertical scroll position value. Must be an integer
+ value if present. Defaults to the ``mask`` value shifted to the right to
+ remove trailing zeroes.
+
.. _layfile-parts-collections:
@@ -1149,9 +1187,8 @@ Clickable items
item will activate the emulated switch.
State-dependent components
Some components will be drawn differently depending on the containing
- element’s state. These include the dot matrix, multi-segment LED display,
- simple counter and reel elements. See :ref:`layfile-parts-elements` for
- details.
+ element’s state. These include the dot matrix, multi-segment LED display
+ and simple counter elements. See :ref:`layfile-parts-elements` for details.
Conditionally-drawn components
Components may be conditionally drawn or hidden depending on the containing
element’s state by supplying ``state`` and/or ``statemask`` attributes. See
@@ -1298,7 +1335,7 @@ If the ``animate`` child element has a ``mask`` attribute, the item’s animatio
state will be masked with the ``mask`` value and shifted to the right to remove
trailing zeroes (for example a mask of 0x05 will result in no shift, while a
mask of 0xb0 will result in the value being shifted four bits to the right).
-Note that the ``mask`` attribute applies to output value (specified with the
+Note that the ``mask`` attribute applies to output values (specified with the
``name`` attribute) as well as input port values (specified with the
``inputtag`` attribute). If the ``mask`` attribute is present, it must be an
integer value. If the ``mask`` attribute is not present, it is equivalent to
diff --git a/docs/source/techspecs/layout_script.rst b/docs/source/techspecs/layout_script.rst
index 7602de6f7f4..f2b8ef1cbc3 100644
--- a/docs/source/techspecs/layout_script.rst
+++ b/docs/source/techspecs/layout_script.rst
@@ -259,7 +259,7 @@ Here’s our layout file:
<bounds x="0" y="0" width="0.1" height="0.1" />
<color alpha="0" />
</rect>
- <!-- draw the outlined of a square -->
+ <!-- draw the outline of a square -->
<rect><bounds x="0.02" y="0.02" width="0.06" height="0.01" /></rect>
<rect><bounds x="0.02" y="0.07" width="0.06" height="0.01" /></rect>
<rect><bounds x="0.02" y="0.02" width="0.01" height="0.06" /></rect>
@@ -289,7 +289,7 @@ Here’s our layout file:
<element id="vertical" ref="line">
<!-- element draws a vertical line, no need to rotate it -->
<orientation rotate="0" />
- <!-- centre it in the square horizotnally, using the full height -->
+ <!-- centre it in the square horizontally, using the full height -->
<bounds x="4.55" y="1.9" width="0.1" height="1" />
</element>
@@ -301,7 +301,7 @@ Here’s our layout file:
<bounds x="4.1" y="2.35" width="1" height="0.1" />
</element>
- <!-- draw a small box at the intersection of the vertical and horiztonal lines -->
+ <!-- draw a small box at the intersection of the vertical and horizontal lines -->
<element id="box" ref="box">
<bounds x="4.55" y="2.35" width="0.1" height="0.1" />
</element>
@@ -595,7 +595,7 @@ Get item bounds
argument to restore the default bounds handler (based on the item’s
animation state and ``bounds`` child elements).
Get item colour
- ``item::set_color_callback(cb)``
+ ``item:set_color_callback(cb)``
Set callback for getting the item’s colour (the element texture’s colours
multiplied by this colour). Do not attempt to access the item’s ``color``
@@ -605,3 +605,59 @@ Get item colour
ARGB colour (usually created by calling ``emu.render_color``), and takes no
parameters. Call with ``nil`` as the argument to restore the default colour
handler (based on the item’s animation state and ``color`` child elements).
+Get item horizontal scroll window size
+ ``item:set_scroll_size_x_callback(cb)``
+
+ Set callback for getting the item’s horizontal scroll window size. This
+ allows the script to control how much of the element is displayed by the
+ item. Do not attempt to access the item’s ``scroll_size_x`` property from
+ the callback, as it will result in infinite recursion.
+
+ The callback function must return a floating-point number representing the
+ horizontal window size as a proportion of the associated element’s width,
+ and takes no parameters. A value of 1.0 will display the entire width of
+ the element; smaller values will display proportionally smaller parts of the
+ element. Call with ``nil`` as the argument to to restore the default
+ horizontal scroll window size handler (based on the ``xscroll`` child
+ element).
+Get item vertical scroll window size
+ ``item:set_scroll_size_y_callback(cb)``
+
+ Set callback for getting the item’s vertical scroll window size. This
+ allows the script to control how much of the element is displayed by the
+ item. Do not attempt to access the item’s ``scroll_size_y`` property from
+ the callback, as it will result in infinite recursion.
+
+ The callback function must return a floating-point number representing the
+ vertical window size as a proportion of the associated element’s height, and
+ takes no parameters. A value of 1.0 will display the entire height of the
+ element; smaller values will display proportionally smaller parts of the
+ element. Call with ``nil`` as the argument to to restore the default
+ vertical scroll window size handler (based on the ``xscroll`` child
+ element).
+Get item horizontal scroll position
+ ``item:set_scroll_pos_x_callback(cb)``
+
+ Set callback for getting the item’s horizontal scroll position. This allows
+ the script to control which part of the element is displayed by the item.
+ Do not attempt to access the item’s ``scroll_pos_x`` property from the
+ callback, as this will result in infinite recursion.
+
+ The callback must return a floating-point number, and takes no parameters.
+ A value of 0.0 aligns the left edge of the element with the left edge of the
+ item; larger values pan right. Call with ``nil`` as the argument to restore
+ the default horizontal scroll position handler (based on bindings in the
+ ``xscroll`` child element).
+Get item vertical scroll position
+ ``item:set_scroll_pos_y_callback(cb)``
+
+ Set callback for getting the item’s vertical scroll position. This allows
+ the script to control which part of the element is displayed by the item.
+ Do not attempt to access the item’s ``scroll_pos_y`` property from the
+ callback, as this will result in infinite recursion.
+
+ The callback must return a floating-point number, and takes no parameters.
+ A value of 0.0 aligns the top edge of the element with the top edge of the
+ item; larger values pan down. Call with ``nil`` as the argument to restore
+ the default vertical scroll position handler (based on bindings in the
+ ``yscroll`` child element).
diff --git a/docs/source/techspecs/luareference.rst b/docs/source/techspecs/luareference.rst
index 3cea683f547..85c7ea8cb8a 100644
--- a/docs/source/techspecs/luareference.rst
+++ b/docs/source/techspecs/luareference.rst
@@ -2815,7 +2815,7 @@ view.has_art
Layout view item
~~~~~~~~~~~~~~~~
-Wraps MAME’s ``layout_view::item`` class, representing an item in a view. An
+Wraps MAME’s ``layout_view_item`` class, representing an item in a view. An
item is drawn as a rectangular textured surface. The texture is supplied by an
emulated screen or a layout element.
@@ -2832,7 +2832,7 @@ Methods
item:set_state(state)
Set the value used as the element state and animation state in the absence
of bindings. The argument must be an integer.
-item.set_element_state_callback(cb)
+item:set_element_state_callback(cb)
Set a function to call to obtain the element state for the item. The
function must accept no arguments and return an integer. Call with ``nil``
to restore the default element state callback (based on bindings in the XML
@@ -2844,7 +2844,7 @@ item.set_element_state_callback(cb)
This callback will not be used to obtain the animation state for the item,
even if the item lacks explicit animation state bindings in the XML layout
file.
-item.set_animation_state_callback(cb)
+item:set_animation_state_callback(cb)
Set a function to call to obtain the animation state for the item. The
function must accept no arguments and return an integer. Call with ``nil``
to restore the default animation state callback (based on bindings in the
@@ -2852,7 +2852,7 @@ item.set_animation_state_callback(cb)
Note that the function must not access the item’s ``animation_state``
property, as this will result in infinite recursion.
-item.set_bounds_callback(cb)
+item:set_bounds_callback(cb)
Set a function to call to obtain the bounds for the item. The function must
accept no arguments and return a
:ref:`render bounds <luareference-render-bounds>` object in render target
@@ -2862,7 +2862,7 @@ item.set_bounds_callback(cb)
Note that the function must not access the item’s ``bounds`` property, as
this will result in infinite recursion.
-item.set_color_callback(cb)
+item:set_color_callback(cb)
Set a function to call to obtain the multiplier colour for the item. The
function must accept no arguments and return a
:ref:`render colour <luareference-render-color>` object. Call with ``nil``
@@ -2871,6 +2871,50 @@ item.set_color_callback(cb)
Note that the function must not access the item’s ``color`` property, as
this will result in infinite recursion.
+item:set_scroll_size_x_callback(cb)
+ Set a function to call to obtain the size of the horizontal scroll window as
+ a proportion of the associated element’s width. The function must accept no
+ arguments and return a floating-point value. Call with ``nil`` to restore
+ the default horizontal scroll window size callback (based on the ``xscroll``
+ child element in the XML layout file).
+
+ Note that the function must not access the item’s ``scroll_size_x``
+ property, as this will result in infinite recursion.
+item:set_scroll_size_y_callback(cb)
+ Set a function to call to obtain the size of the vertical scroll window as a
+ proportion of the associated element’s height. The function must accept no
+ arguments and return a floating-point value. Call with ``nil`` to restore
+ the default vertical scroll window size callback (based on the ``yscroll``
+ child element in the XML layout file).
+
+ Note that the function must not access the item’s ``scroll_size_y``
+ property, as this will result in infinite recursion.
+item:set_scroll_pos_x_callback(cb)
+ Set a function to call to obtain the horizontal scroll position. A value of
+ zero places the horizontal scroll window at the left edge of the associated
+ element. If the item does not wrap horizontally, a value of 1.0 places the
+ horizontal scroll window at the right edge of the associated element; if the
+ item wraps horizontally, a value of 1.0 corresponds to wrapping back to the
+ left edge of the associated element. The function must accept no arguments
+ and return a floating-point value. Call with ``nil`` to restore the default
+ horizontal scroll position callback (based on bindings in the ``xscroll``
+ child element in the XML layout file).
+
+ Note that the function must not access the item’s ``scroll_pos_x`` property,
+ as this will result in infinite recursion.
+item:set_scroll_pos_y_callback(cb)
+ Set a function to call to obtain the vertical scroll position. A value of
+ zero places the vertical scroll window at the top edge of the associated
+ element. If the item does not wrap vertically, a value of 1.0 places the
+ vertical scroll window at the bottom edge of the associated element; if the
+ item wraps vertically, a value of 1.0 corresponds to wrapping back to the
+ left edge of the associated element. The function must accept no arguments
+ and return a floating-point value. Call with ``nil`` to restore the default
+ vertical scroll position callback (based on bindings in the ``yscroll``
+ child element in the XML layout file).
+
+ Note that the function must not access the item’s ``scroll_pos_y`` property,
+ as this will result in infinite recursion.
Properties
^^^^^^^^^^
@@ -2892,6 +2936,28 @@ item.color (read-only)
The item’s colour for the current state. The colour of the screen or
element texture is multiplied by this colour. This is a
:ref:`render colour <luareference-render-color>` object.
+item.scroll_wrap_x (read-only)
+ A Boolean indicating whether the item wraps horizontally.
+item.scroll_wrap_y (read-only)
+ A Boolean indicating whether the item wraps vertically.
+item.scroll_size_x (read/write)
+ Get the item’s horizontal scroll window size for the current state, or set
+ the horizontal scroll window size to use in the absence of bindings. This
+ is a floating-point value representing a proportion of the associated
+ element’s width.
+item.scroll_size_y (read/write)
+ Get the item’s vertical scroll window size for the current state, or set the
+ vertical scroll window size to use in the absence of bindings. This is a
+ floating-point value representing a proportion of the associated element’s
+ height.
+item.scroll_pos_x (read/write)
+ Get the item’s horizontal scroll position for the current state, or set the
+ horizontal scroll position size to use in the absence of bindings. This is
+ a floating-point value.
+item.scroll_pos_y (read/write)
+ Get the item’s vertical scroll position for the current state, or set the
+ vertical position size to use in the absence of bindings. This is a
+ floating-point value.
item.blend_mode (read-only)
Get the item’s blend mode. This is an integer value, where 0 means no
blending, 1 means alpha blending, 2 means RGB multiplication, 3 means
diff --git a/scripts/build/complay.py b/scripts/build/complay.py
index 81516bc3ee7..996908ecde0 100755
--- a/scripts/build/complay.py
+++ b/scripts/build/complay.py
@@ -253,7 +253,7 @@ class LayoutChecker(Minifyer):
if self.checkIntAttribute('orientation', attrs, 'rotate', 0) not in self.ORIENTATIONS:
self.handleError('Element orientation attribute rotate "%s" is unsupported' % (attrs['rotate'], ))
for name in ('swapxy', 'flipx', 'flipy'):
- if (attrs.get(name, 'no') not in self.YESNO) and (not self.VARPATTERN.match(attrs['yesno'])):
+ if (attrs.get(name, 'no') not in self.YESNO) and (not self.VARPATTERN.match(attrs[name])):
self.handleError('Element orientation attribute %s "%s" is not "yes" or "no"' % (name, attrs[name]))
def checkColor(self, attrs):
@@ -332,6 +332,8 @@ class LayoutChecker(Minifyer):
self.have_bounds.append(None if 'group' == name else { })
self.have_orientation.append(False)
self.have_color.append(None if 'group' == name else { })
+ self.have_xscroll.append(None if ('group' == name) or ('screen' == name) else False)
+ self.have_yscroll.append(None if ('group' == name) or ('screen' == name) else False)
def rootStartHandler(self, name, attrs):
if 'mamelayout' != name:
@@ -665,6 +667,24 @@ class LayoutChecker(Minifyer):
else:
self.handleError('Duplicate element color (previous %s)' % (self.have_color[-1], ))
self.checkColor(attrs)
+ elif ('xscroll' == name) or ('yscroll' == name):
+ have_scroll = self.have_xscroll if 'xscroll' == name else self.have_yscroll
+ if have_scroll[-1] is None:
+ self.handleError('Encountered unexpected element %s' % (name, ))
+ elif have_scroll[-1]:
+ self.handleError('Duplicate element %s' % (name, ))
+ else:
+ have_scroll[-1] = self.formatLocation()
+ self.checkFloatAttribute(name, attrs, 'size', 1.0)
+ if (attrs.get('wrap', 'no') not in self.YESNO) and (not self.VARPATTERN.match(attrs['wrap'])):
+ self.handleError('Element %s attribute wrap "%s" is not "yes" or "no"' % (name, attrs['wrap']))
+ if 'inputtag' in attrs:
+ if 'name' in attrs:
+ self.handleError('Element %s has both attribute inputtag and attribute name' % (name, ))
+ self.checkTag(attrs['inputtag'], name, 'inputtag')
+ self.checkIntAttribute(name, attrs, 'mask', None)
+ self.checkIntAttribute(name, attrs, 'min', None)
+ self.checkIntAttribute(name, attrs, 'max', None)
else:
self.handleError('Encountered unexpected element %s' % (name, ))
self.ignored_depth = 1
@@ -673,6 +693,8 @@ class LayoutChecker(Minifyer):
self.have_bounds.pop()
self.have_orientation.pop()
self.have_color.pop()
+ self.have_xscroll.pop()
+ self.have_yscroll.pop()
self.handlers.pop()
def setDocumentLocator(self, locator):
@@ -688,6 +710,8 @@ class LayoutChecker(Minifyer):
self.have_bounds = [ ]
self.have_orientation = [ ]
self.have_color = [ ]
+ self.have_xscroll = [ ]
+ self.have_yscroll = [ ]
self.generated_element_names = False
self.generated_group_names = False
super(LayoutChecker, self).startDocument()
@@ -709,6 +733,8 @@ class LayoutChecker(Minifyer):
del self.have_bounds
del self.have_orientation
del self.have_color
+ del self.have_xscroll
+ del self.have_yscroll
del self.generated_element_names
del self.generated_group_names
super(LayoutChecker, self).endDocument()
diff --git a/src/emu/emufwd.h b/src/emu/emufwd.h
index b3969a8fc99..8b8e59b9250 100644
--- a/src/emu/emufwd.h
+++ b/src/emu/emufwd.h
@@ -193,9 +193,6 @@ class network_manager;
class output_manager;
// declared in render.h
-class layout_element;
-class layout_view;
-class layout_file;
class render_container;
class render_manager;
class render_target;
@@ -204,6 +201,12 @@ class render_texture;
// declared in rendfont.h
class render_font;
+// declared in rendlay.h
+class layout_element;
+class layout_view_item;
+class layout_view;
+class layout_file;
+
// declared in romentry.h
class rom_entry;
diff --git a/src/emu/render.cpp b/src/emu/render.cpp
index 0fef6bafe41..42a837062a3 100644
--- a/src/emu/render.cpp
+++ b/src/emu/render.cpp
@@ -1097,7 +1097,7 @@ unsigned render_target::configured_view(const char *viewname, int targetindex, i
screen_device const &screen = screens[index() % screens.size()];
for (unsigned i = 0; !view && (m_views.size() > i); ++i)
{
- for (layout_view::item &viewitem : m_views[i].first.items())
+ for (layout_view_item &viewitem : m_views[i].first.items())
{
screen_device const *const viewscreen(viewitem.screen());
if (viewscreen == &screen)
@@ -1286,7 +1286,7 @@ void render_target::compute_minimum_size(s32 &minwidth, s32 &minheight)
throw emu_fatalerror("Mandatory artwork is missing");
// scan the current view for all screens
- for (layout_view::item &curitem : current_view().items())
+ for (layout_view_item &curitem : current_view().items())
{
screen_device const *const screen = curitem.screen();
if (screen)
@@ -1370,7 +1370,7 @@ render_primitive_list &render_target::get_primitives()
{
// we're running - iterate over items in the view
current_view().prepare_items();
- for (layout_view::item &curitem : current_view().visible_items())
+ for (layout_view_item &curitem : current_view().visible_items())
{
// first apply orientation to the bounds
render_bounds bounds = curitem.bounds();
@@ -1391,7 +1391,7 @@ render_primitive_list &render_target::get_primitives()
if (curitem.screen())
add_container_primitives(list, root_xform, item_xform, curitem.screen()->container(), curitem.blend_mode());
else
- add_element_primitives(list, item_xform, *curitem.element(), curitem.element_state(), curitem.blend_mode());
+ add_element_primitives(list, item_xform, curitem);
}
}
else
@@ -1494,10 +1494,10 @@ bool render_target::map_point_container(s32 target_x, s32 target_y, render_conta
auto const found(std::find_if(
items.begin(),
items.end(),
- [&container] (layout_view::item &item) { return &item.screen()->container() == &container; }));
+ [&container] (layout_view_item &item) { return &item.screen()->container() == &container; }));
if (items.end() != found)
{
- layout_view::item &item(*found);
+ layout_view_item &item(*found);
render_bounds const bounds(item.bounds());
if (bounds.includes(target_f.first, target_f.second))
{
@@ -1555,7 +1555,7 @@ bool render_target::map_point_input(s32 target_x, s32 target_y, ioport_port *&in
{
if (m_hit_test[i] && m_hit_test[items.size() + i])
{
- layout_view::item &item(items[i]);
+ layout_view_item &item(items[i]);
render_bounds const bounds(item.bounds());
if (bounds.includes(target_f.first, target_f.second))
{
@@ -2523,11 +2523,13 @@ void render_target::add_container_primitives(render_primitive_list &list, const
// for an element in the current state
//-------------------------------------------------
-void render_target::add_element_primitives(render_primitive_list &list, const object_transform &xform, layout_element &element, int state, int blendmode)
+void render_target::add_element_primitives(render_primitive_list &list, const object_transform &xform, layout_view_item &item)
{
+ layout_element &element(*item.element());
+ int const blendmode(item.blend_mode());
+
// limit state range to non-negative values
- if (state < 0)
- state = 0;
+ int const state((std::max)(item.element_state(), 0));
// get a pointer to the relevant texture
render_texture *texture = element.state_texture(state);
@@ -2537,29 +2539,70 @@ void render_target::add_element_primitives(render_primitive_list &list, const ob
// configure the basics
prim->color = xform.color;
- prim->flags = PRIMFLAG_TEXORIENT(xform.orientation) | PRIMFLAG_BLENDMODE(blendmode) | PRIMFLAG_TEXFORMAT(texture->format());
+ prim->flags =
+ PRIMFLAG_TEXORIENT(xform.orientation) |
+ PRIMFLAG_TEXFORMAT(texture->format()) |
+ PRIMFLAG_BLENDMODE(blendmode) |
+ PRIMFLAG_TEXWRAP((item.scroll_wrap_x() || item.scroll_wrap_y()) ? 1 : 0);
// compute the bounds
- s32 width = render_round_nearest(xform.xscale);
- s32 height = render_round_nearest(xform.yscale);
- prim->bounds.set_wh(render_round_nearest(xform.xoffs), render_round_nearest(xform.yoffs), float(width), float(height));
+ float const primwidth(render_round_nearest(xform.xscale));
+ float const primheight(render_round_nearest(xform.yscale));
+ prim->bounds.set_wh(render_round_nearest(xform.xoffs), render_round_nearest(xform.yoffs), primwidth, primheight);
prim->full_bounds = prim->bounds;
- if (xform.orientation & ORIENTATION_SWAP_XY)
- std::swap(width, height);
- width = (std::min)(width, m_maxtexwidth);
- height = (std::min)(height, m_maxtexheight);
// get the scaled texture and append it
- texture->get_scaled(width, height, prim->texture, list, prim->flags);
+ float const xsize(item.scroll_size_x());
+ float const ysize(item.scroll_size_y());
+ s32 texwidth = render_round_nearest(((xform.orientation & ORIENTATION_SWAP_XY) ? primwidth : primheight) / xsize);
+ s32 texheight = render_round_nearest(((xform.orientation & ORIENTATION_SWAP_XY) ? primheight : primwidth) / ysize);
+ texwidth = (std::min)(texwidth, m_maxtexwidth);
+ texheight = (std::min)(texheight, m_maxtexheight);
+ texture->get_scaled(texwidth, texheight, prim->texture, list, prim->flags);
// compute the clip rect
render_bounds cliprect = prim->bounds & m_bounds;
// determine UV coordinates and apply clipping
- prim->texcoords = oriented_texcoords[xform.orientation];
- bool clipped = render_clip_quad(&prim->bounds, &cliprect, &prim->texcoords);
+ float const xwindow((xform.orientation & ORIENTATION_SWAP_XY) ? primwidth : primheight);
+ float const ywindow((xform.orientation & ORIENTATION_SWAP_XY) ? primheight : primwidth);
+ float const xrange(float(texwidth) - (item.scroll_wrap_x() ? 0.0f : xwindow));
+ float const yrange(float(texheight) - (item.scroll_wrap_y() ? 0.0f : ywindow));
+ float const xoffset(render_round_nearest(item.scroll_pos_x() * xrange) / float(texwidth));
+ float const yoffset(render_round_nearest(item.scroll_pos_y() * yrange) / float(texheight));
+ float const xend(xoffset + (xwindow / float(texwidth)));
+ float const yend(yoffset + (ywindow / float(texheight)));
+ switch (xform.orientation)
+ {
+ default:
+ case 0:
+ prim->texcoords = render_quad_texuv{ { xoffset, yoffset }, { xend, yoffset }, { xoffset, yend }, { xend, yend } };
+ break;
+ case ORIENTATION_FLIP_X:
+ prim->texcoords = render_quad_texuv{ { xend, yoffset }, { xoffset, yoffset }, { xend, yend }, { xoffset, yend } };
+ break;
+ case ORIENTATION_FLIP_Y:
+ prim->texcoords = render_quad_texuv{ { xoffset, yend }, { xend, yend }, { xoffset, yoffset }, { xend, yoffset } };
+ break;
+ case ORIENTATION_FLIP_X | ORIENTATION_FLIP_Y:
+ prim->texcoords = render_quad_texuv{ { xend, yend }, { xoffset, yend }, { xend, yoffset }, { xoffset, yoffset } };
+ break;
+ case ORIENTATION_SWAP_XY:
+ prim->texcoords = render_quad_texuv{ { xoffset, yoffset }, { xoffset, yend }, { xend, yoffset }, { xend, yend } };
+ break;
+ case ORIENTATION_SWAP_XY | ORIENTATION_FLIP_X:
+ prim->texcoords = render_quad_texuv{ { xoffset, yend }, { xoffset, yoffset }, { xend, yend }, { xend, yoffset } };
+ break;
+ case ORIENTATION_SWAP_XY | ORIENTATION_FLIP_Y:
+ prim->texcoords = render_quad_texuv{ { xend, yoffset }, { xend, yend }, { xoffset, yoffset }, { xoffset, yend } };
+ break;
+ case ORIENTATION_SWAP_XY | ORIENTATION_FLIP_X | ORIENTATION_FLIP_Y:
+ prim->texcoords = render_quad_texuv{ { xend, yend }, { xend, yoffset }, { xoffset, yend }, { xoffset, yoffset } };
+ break;
+ }
// add to the list or free if we're clipped out
+ bool const clipped = render_clip_quad(&prim->bounds, &cliprect, &prim->texcoords);
list.append_or_return(*prim, clipped);
}
}
diff --git a/src/emu/render.h b/src/emu/render.h
index 5833a036077..d1d8987ea9b 100644
--- a/src/emu/render.h
+++ b/src/emu/render.h
@@ -590,7 +590,7 @@ private:
bool load_layout_file(const char *dirname, const internal_layout &layout_data, device_t *device = nullptr);
bool load_layout_file(device_t &device, util::xml::data_node const &rootnode, const char *searchpath, const char *dirname);
void add_container_primitives(render_primitive_list &list, const object_transform &root_xform, const object_transform &xform, render_container &container, int blendmode);
- void add_element_primitives(render_primitive_list &list, const object_transform &xform, layout_element &element, int state, int blendmode);
+ void add_element_primitives(render_primitive_list &list, const object_transform &xform, layout_view_item &item);
std::pair<float, float> map_point_internal(s32 target_x, s32 target_y);
// config callbacks
diff --git a/src/emu/rendlay.cpp b/src/emu/rendlay.cpp
index b6709626d97..41075c2573b 100644
--- a/src/emu/rendlay.cpp
+++ b/src/emu/rendlay.cpp
@@ -1120,6 +1120,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
@@ -4096,7 +4211,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;
@@ -4502,10 +4617,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,
@@ -4514,11 +4629,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))
@@ -4531,11 +4664,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
@@ -4562,6 +4699,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;
@@ -4570,10 +4715,10 @@ layout_view::item::item(
//-------------------------------------------------
-// item - destructor
+// layout_view_item - destructor
//-------------------------------------------------
-layout_view::item::~item()
+layout_view_item::~layout_view_item()
{
}
@@ -4583,7 +4728,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);
@@ -4597,7 +4742,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);
@@ -4611,7 +4756,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);
@@ -4625,7 +4770,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);
@@ -4635,10 +4780,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)
@@ -4648,13 +4849,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())
@@ -4684,6 +4893,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();
}
@@ -4692,18 +4905,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);
}
@@ -4712,12 +4925,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();
}
@@ -4727,11 +4940,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);
}
@@ -4739,11 +4952,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);
}
@@ -4751,7 +5018,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;
}
@@ -4761,7 +5028,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));
@@ -4772,7 +5039,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));
@@ -4783,7 +5050,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);
@@ -4795,7 +5062,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);
@@ -4808,7 +5075,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)));
@@ -4819,7 +5086,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));
@@ -4827,10 +5094,113 @@ 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
//-------------------------------------------------
-render_bounds layout_view::item::get_interpolated_bounds() const
+render_bounds layout_view_item::get_interpolated_bounds() const
{
assert(m_bounds.size() > 1U);
return interpolate_bounds(m_bounds, m_get_anim_state());
@@ -4841,7 +5211,7 @@ render_bounds layout_view::item::get_interpolated_bounds() const
// get_interpolated_color - animated color
//-------------------------------------------------
-render_color layout_view::item::get_interpolated_color() const
+render_color layout_view_item::get_interpolated_color() const
{
assert(m_color.size() > 1U);
return interpolate_color(m_color, m_get_anim_state());
@@ -4852,7 +5222,7 @@ render_color layout_view::item::get_interpolated_color() 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())
@@ -4871,7 +5241,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)
@@ -4904,7 +5274,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)
@@ -4934,101 +5304,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
diff --git a/src/emu/rendlay.h b/src/emu/rendlay.h
index 5b121d18880..befae560bcd 100644
--- a/src/emu/rendlay.h
+++ b/src/emu/rendlay.h
@@ -233,6 +233,178 @@ private:
};
+/// \brief A single item in a view
+///
+/// Each view has a list of item structures describing the visual
+/// elements to draw, where they are located, additional blending modes,
+/// and bindings for inputs and outputs.
+class layout_view_item
+{
+ friend class layout_view;
+
+public:
+ using view_environment = emu::render::detail::view_environment;
+ using element_map = std::unordered_map<std::string, layout_element>;
+ using state_delegate = delegate<int ()>;
+ using bounds_delegate = delegate<render_bounds ()>;
+ using color_delegate = delegate<render_color ()>;
+ using scroll_size_delegate = delegate<float ()>;
+ using scroll_pos_delegate = delegate<float ()>;
+
+ // construction/destruction
+ layout_view_item(
+ view_environment &env,
+ util::xml::data_node const &itemnode,
+ element_map &elemmap,
+ int orientation,
+ layout_group::transform const &trans,
+ render_color const &color);
+ ~layout_view_item();
+
+ // getters
+ std::string const &id() const { return m_id; }
+ layout_element *element() const { return m_element; }
+ screen_device *screen() const { return m_screen; }
+ bool bounds_animated() const { return m_bounds.size() > 1U; }
+ bool color_animated() const { return m_color.size() > 1U; }
+ render_bounds bounds() const { return m_get_bounds(); }
+ render_color color() const { return m_get_color(); }
+ bool scroll_wrap_x() const { return m_scrollwrapx; }
+ bool scroll_wrap_y() const { return m_scrollwrapy; }
+ float scroll_size_x() const { return m_get_scroll_size_x(); }
+ float scroll_size_y() const { return m_get_scroll_size_y(); }
+ float scroll_pos_x() const { return m_get_scroll_pos_x(); }
+ float scroll_pos_y() const { return m_get_scroll_pos_y(); }
+ int blend_mode() const { return m_blend_mode; }
+ u32 visibility_mask() const { return m_visibility_mask; }
+ int orientation() const { return m_orientation; }
+ render_container *screen_container() const { return m_screen ? &m_screen->container() : nullptr; }
+
+ // interactivity
+ bool has_input() const { return bool(m_input_port); }
+ std::pair<ioport_port *, ioport_value> input_tag_and_mask() const { return std::make_pair(m_input_port, m_input_mask); };
+ bool clickthrough() const { return m_clickthrough; }
+
+ // fetch state based on configured source
+ int element_state() const { return m_get_elem_state(); }
+ int animation_state() const { return m_get_anim_state(); }
+
+ // set state
+ void set_state(int state) { m_elem_state = state; }
+ void set_scroll_size_x(float size) { m_scrollsizex = std::clamp(size, 0.01f, 1.0f); }
+ void set_scroll_size_y(float size) { m_scrollsizey = std::clamp(size, 0.01f, 1.0f); }
+ void set_scroll_pos_x(float pos) { m_scrollposx = pos; }
+ void set_scroll_pos_y(float pos) { m_scrollposy = pos; }
+
+ // set handlers
+ void set_element_state_callback(state_delegate &&handler);
+ void set_animation_state_callback(state_delegate &&handler);
+ void set_bounds_callback(bounds_delegate &&handler);
+ void set_color_callback(color_delegate &&handler);
+ void set_scroll_size_x_callback(scroll_size_delegate &&handler);
+ void set_scroll_size_y_callback(scroll_size_delegate &&handler);
+ void set_scroll_pos_x_callback(scroll_pos_delegate &&handler);
+ void set_scroll_pos_y_callback(scroll_pos_delegate &&handler);
+
+ // resolve tags, if any
+ void resolve_tags();
+
+private:
+ using bounds_vector = emu::render::detail::bounds_vector;
+ using color_vector = emu::render::detail::color_vector;
+
+ state_delegate default_get_elem_state();
+ state_delegate default_get_anim_state();
+ bounds_delegate default_get_bounds();
+ color_delegate default_get_color();
+ scroll_size_delegate default_get_scroll_size_x();
+ scroll_size_delegate default_get_scroll_size_y();
+ scroll_pos_delegate default_get_scroll_pos_x();
+ scroll_pos_delegate default_get_scroll_pos_y();
+ int get_state() const;
+ int get_output() const;
+ int get_input_raw() const;
+ int get_input_field_cached() const;
+ int get_input_field_conditional() const;
+ int get_anim_output() const;
+ int get_anim_input() const;
+ float get_scrollsizex() const;
+ float get_scrollsizey() const;
+ float get_scrollposx() const;
+ float get_scrollposy() const;
+ template <bool Wrap> float get_scrollx_output() const;
+ template <bool Wrap> float get_scrolly_output() const;
+ template <bool Wrap> float get_scrollx_input() const;
+ template <bool Wrap> float get_scrolly_input() const;
+ render_bounds get_interpolated_bounds() const;
+ render_color get_interpolated_color() const;
+
+ static layout_element *find_element(view_environment &env, util::xml::data_node const &itemnode, element_map &elemmap);
+ static bounds_vector make_bounds(view_environment &env, util::xml::data_node const &itemnode, layout_group::transform const &trans);
+ static color_vector make_color(view_environment &env, util::xml::data_node const &itemnode, render_color const &mult);
+
+ // internal state
+ layout_element *const m_element; // pointer to the associated element (non-screens only)
+ state_delegate m_get_elem_state; // resolved element state function
+ state_delegate m_get_anim_state; // resolved animation state function
+ bounds_delegate m_get_bounds; // resolved bounds function
+ color_delegate m_get_color; // resolved color function
+ scroll_size_delegate m_get_scroll_size_x; // resolved horizontal scroll window size function
+ scroll_size_delegate m_get_scroll_size_y; // resolved vertical scroll window size function
+ scroll_pos_delegate m_get_scroll_pos_x; // resolved horizontal scroll position function
+ scroll_pos_delegate m_get_scroll_pos_y; // resolved vertical scroll position function
+ output_finder<> m_output; // associated output
+ output_finder<> m_animoutput; // associated output for animation if different
+ output_finder<> m_scrollxoutput; // associated output for horizontal scroll position
+ output_finder<> m_scrollyoutput; // associated output for vertical scroll position
+ ioport_port * m_animinput_port; // input port used for animation
+ ioport_port * m_scrollxinput_port; // input port used for horizontal scrolling
+ ioport_port * m_scrollyinput_port; // input port used for vertical scrolling
+ bool const m_scrollwrapx; // whether horizontal scrolling works like a loop
+ bool const m_scrollwrapy; // whether vertical scrolling works like a loop
+ int m_elem_state; // element state used in absence of bindings
+ float m_scrollsizex; // horizontal scroll window size used in absence of bindings
+ float m_scrollsizey; // vertical scroll window size used in absence of bindings
+ float m_scrollposx; // horizontal scroll position used in absence of bindings
+ float m_scrollposy; // vertical scroll position used in absence of bindings
+ ioport_value const m_animmask; // mask for animation state
+ ioport_value const m_scrollxmask; // mask for horizontal scroll position
+ ioport_value const m_scrollymask; // mask for vertical scroll position
+ ioport_value const m_scrollxmin; // minimum value for horizontal scroll position
+ ioport_value const m_scrollymin; // minimum value for vertical scroll position
+ ioport_value const m_scrollxmax; // maximum value for horizontal scroll position
+ ioport_value const m_scrollymax; // maximum value for vertical scroll position
+ u8 const m_animshift; // shift for animation state
+ u8 const m_scrollxshift; // shift for horizontal scroll position
+ u8 const m_scrollyshift; // shift for vertical scroll position
+ ioport_port * m_input_port; // input port of this item
+ ioport_field const * m_input_field; // input port field of this item
+ ioport_value const m_input_mask; // input mask of this item
+ u8 const m_input_shift; // input mask rightshift for raw (trailing 0s)
+ bool m_clickthrough; // should click pass through to lower elements
+ screen_device * m_screen; // pointer to screen
+ int const m_orientation; // orientation of this item
+ bounds_vector m_bounds; // bounds of the item
+ color_vector const m_color; // color of the item
+ int m_blend_mode; // blending mode to use when drawing
+ u32 m_visibility_mask; // combined mask of parent visibility groups
+
+ // cold items
+ std::string const m_id; // optional unique item identifier
+ std::string const m_input_tag; // input tag of this item
+ std::string const m_animinput_tag; // tag of input port for animation state
+ std::string const m_scrollxinput_tag; // tag of input port for horizontal scroll position
+ std::string const m_scrollyinput_tag; // tag of input port for vertical scroll position
+ bounds_vector const m_rawbounds; // raw (original) bounds of the item
+ bool const m_have_output; // whether we actually have an output
+ bool const m_input_raw; // get raw data from input port
+ bool const m_have_animoutput; // whether we actually have an output for animation
+ bool const m_have_scrollxoutput; // whether we actually have an output for horizontal scroll
+ bool const m_have_scrollyoutput; // whether we actually have an output for vertical scroll
+ bool const m_has_clickthrough; // whether clickthrough was explicitly configured
+};
+
+
/// \brief A single view within a #layout_file
///
/// The view is described using arbitrary coordinates that are scaled to
@@ -243,133 +415,14 @@ class layout_view
public:
using layout_environment = emu::render::detail::layout_environment;
using view_environment = emu::render::detail::view_environment;
- using element_map = std::unordered_map<std::string, layout_element>;
+ using element_map = layout_view_item::element_map;
using group_map = std::unordered_map<std::string, layout_group>;
using screen_ref_vector = std::vector<std::reference_wrapper<screen_device const>>;
using prepare_items_delegate = delegate<void ()>;
using preload_delegate = delegate<void ()>;
using recomputed_delegate = delegate<void ()>;
- /// \brief A single item in a view
- ///
- /// Each view has a list of item structures describing the visual
- /// elements to draw, where they are located, additional blending
- /// modes, and bindings for inputs and outputs.
- class item
- {
- friend class layout_view;
-
- public:
- using state_delegate = delegate<int ()>;
- using bounds_delegate = delegate<render_bounds ()>;
- using color_delegate = delegate<render_color ()>;
-
- // construction/destruction
- item(
- view_environment &env,
- util::xml::data_node const &itemnode,
- element_map &elemmap,
- int orientation,
- layout_group::transform const &trans,
- render_color const &color);
- ~item();
-
- // getters
- std::string const &id() const { return m_id; }
- layout_element *element() const { return m_element; }
- screen_device *screen() const { return m_screen; }
- bool bounds_animated() const { return m_bounds.size() > 1U; }
- bool color_animated() const { return m_color.size() > 1U; }
- render_bounds bounds() const { return m_get_bounds(); }
- render_color color() const { return m_get_color(); }
- int blend_mode() const { return m_blend_mode; }
- u32 visibility_mask() const { return m_visibility_mask; }
- int orientation() const { return m_orientation; }
- render_container *screen_container() const { return m_screen ? &m_screen->container() : nullptr; }
-
- // interactivity
- bool has_input() const { return bool(m_input_port); }
- std::pair<ioport_port *, ioport_value> input_tag_and_mask() const { return std::make_pair(m_input_port, m_input_mask); };
- bool clickthrough() const { return m_clickthrough; }
-
- // fetch state based on configured source
- int element_state() const { return m_get_elem_state(); }
- int animation_state() const { return m_get_anim_state(); }
-
- // set state
- void set_state(int state) { m_elem_state = state; }
-
- // set handlers
- void set_element_state_callback(state_delegate &&handler);
- void set_animation_state_callback(state_delegate &&handler);
- void set_bounds_callback(bounds_delegate &&handler);
- void set_color_callback(color_delegate &&handler);
-
- // resolve tags, if any
- void resolve_tags();
-
- private:
- using bounds_vector = emu::render::detail::bounds_vector;
- using color_vector = emu::render::detail::color_vector;
-
- state_delegate default_get_elem_state();
- state_delegate default_get_anim_state();
- bounds_delegate default_get_bounds();
- color_delegate default_get_color();
- int get_state() const;
- int get_output() const;
- int get_input_raw() const;
- int get_input_field_cached() const;
- int get_input_field_conditional() const;
- int get_anim_output() const;
- int get_anim_input() const;
- render_bounds get_interpolated_bounds() const;
- render_color get_interpolated_color() const;
-
- static layout_element *find_element(view_environment &env, util::xml::data_node const &itemnode, element_map &elemmap);
- static bounds_vector make_bounds(view_environment &env, util::xml::data_node const &itemnode, layout_group::transform const &trans);
- static color_vector make_color(view_environment &env, util::xml::data_node const &itemnode, render_color const &mult);
- static std::string make_animoutput_tag(view_environment &env, util::xml::data_node const &itemnode);
- static std::string make_animinput_tag(view_environment &env, util::xml::data_node const &itemnode);
- static ioport_value make_animmask(view_environment &env, util::xml::data_node const &itemnode);
- static std::string make_input_tag(view_environment &env, util::xml::data_node const &itemnode);
- static int get_blend_mode(view_environment &env, util::xml::data_node const &itemnode);
- static unsigned get_state_shift(ioport_value mask);
-
- // internal state
- layout_element *const m_element; // pointer to the associated element (non-screens only)
- state_delegate m_get_elem_state; // resolved element state function
- state_delegate m_get_anim_state; // resolved animation state function
- bounds_delegate m_get_bounds; // resolved bounds function
- color_delegate m_get_color; // resolved color function
- output_finder<> m_output; // associated output
- output_finder<> m_animoutput; // associated output for animation if different
- ioport_port * m_animinput_port; // input port used for animation
- int m_elem_state; // element state used in absence of bindings
- ioport_value const m_animmask; // mask for animation state
- u8 const m_animshift; // shift for animation state
- ioport_port * m_input_port; // input port of this item
- ioport_field const * m_input_field; // input port field of this item
- ioport_value const m_input_mask; // input mask of this item
- u8 const m_input_shift; // input mask rightshift for raw (trailing 0s)
- bool m_clickthrough; // should click pass through to lower elements
- screen_device * m_screen; // pointer to screen
- int const m_orientation; // orientation of this item
- bounds_vector m_bounds; // bounds of the item
- color_vector const m_color; // color of the item
- int m_blend_mode; // blending mode to use when drawing
- u32 m_visibility_mask; // combined mask of parent visibility groups
-
- // cold items
- std::string const m_id; // optional unique item identifier
- std::string const m_input_tag; // input tag of this item
- std::string const m_animinput_tag; // tag of input port for animation state
- bounds_vector const m_rawbounds; // raw (original) bounds of the item
- bool const m_have_output; // whether we actually have an output
- bool const m_input_raw; // get raw data from input port
- bool const m_have_animoutput; // whether we actually have an output for animation
- bool const m_has_clickthrough; // whether clickthrough was explicitly configured
- };
+ using item = layout_view_item;
using item_list = std::list<item>;
using item_ref_vector = std::vector<std::reference_wrapper<item> >;
diff --git a/src/frontend/mame/luaengine_render.cpp b/src/frontend/mame/luaengine_render.cpp
index ea40a34c02a..21a68dc65cb 100644
--- a/src/frontend/mame/luaengine_render.cpp
+++ b/src/frontend/mame/luaengine_render.cpp
@@ -39,7 +39,7 @@ struct layout_view_items
layout_view_items(layout_view &v) : view(v) { }
layout_view::item_list &items() { return view.items(); }
- static layout_view::item &unwrap(layout_view::item_list::iterator const &it) { return *it; }
+ static layout_view_item &unwrap(layout_view::item_list::iterator const &it) { return *it; }
static int push_key(lua_State *L, layout_view::item_list::iterator const &it, std::size_t ix) { return sol::stack::push(L, ix + 1); }
layout_view &view;
@@ -97,7 +97,7 @@ public:
{
layout_view_items &self(get_self(L));
char const *const id(stack::unqualified_get<char const *>(L));
- layout_view::item *const item(self.view.get_item(id));
+ layout_view_item *const item(self.view.get_item(id));
if (item)
return stack::push_reference(L, *item);
else
@@ -279,48 +279,86 @@ void lua_engine::initialize_render(sol::table &emu)
layout_view_type["has_art"] = sol::property(&layout_view::has_art);
- auto layout_view_item_type = sol().registry().new_usertype<layout_view::item>("layout_item", sol::no_constructor);
- layout_view_item_type["set_state"] = &layout_view::item::set_state;
+ auto layout_view_item_type = sol().registry().new_usertype<layout_view_item>("layout_item", sol::no_constructor);
+ layout_view_item_type["set_state"] = &layout_view_item::set_state;
layout_view_item_type["set_element_state_callback"] =
make_simple_callback_setter<int>(
- &layout_view::item::set_element_state_callback,
+ &layout_view_item::set_element_state_callback,
[] () { return 0; },
"set_element_state_callback",
"element state");
layout_view_item_type["set_animation_state_callback"] =
make_simple_callback_setter<int>(
- &layout_view::item::set_animation_state_callback,
+ &layout_view_item::set_animation_state_callback,
[] () { return 0; },
"set_animation_state_callback",
"animation state");
layout_view_item_type["set_bounds_callback"] =
make_simple_callback_setter<render_bounds>(
- &layout_view::item::set_bounds_callback,
+ &layout_view_item::set_bounds_callback,
[] () { return render_bounds{ 0.0f, 0.0f, 1.0f, 1.0f }; },
"set_bounds_callback",
"bounds");
layout_view_item_type["set_color_callback"] =
make_simple_callback_setter<render_color>(
- &layout_view::item::set_color_callback,
+ &layout_view_item::set_color_callback,
[] () { return render_color{ 1.0f, 1.0f, 1.0f, 1.0f }; },
"set_color_callback",
"color");
+ layout_view_item_type["set_scroll_size_x_callback"] =
+ make_simple_callback_setter<float>(
+ &layout_view_item::set_scroll_size_x_callback,
+ [] () { return 1.0f; },
+ "set_scroll_size_x_callback",
+ "horizontal scroll window size");
+ layout_view_item_type["set_scroll_size_y_callback"] =
+ make_simple_callback_setter<float>(
+ &layout_view_item::set_scroll_size_y_callback,
+ [] () { return 1.0f; },
+ "set_scroll_size_y_callback",
+ "vertical scroll window size");
+ layout_view_item_type["set_scroll_pos_x_callback"] =
+ make_simple_callback_setter<float>(
+ &layout_view_item::set_scroll_pos_x_callback,
+ [] () { return 1.0f; },
+ "set_scroll_pos_x_callback",
+ "horizontal scroll position");
+ layout_view_item_type["set_scroll_pos_y_callback"] =
+ make_simple_callback_setter<float>(
+ &layout_view_item::set_scroll_pos_y_callback,
+ [] () { return 1.0f; },
+ "set_scroll_pos_y_callback",
+ "vertical scroll position");
layout_view_item_type["id"] = sol::property(
- [] (layout_view::item &i, sol::this_state s) -> sol::object
+ [] (layout_view_item &i, sol::this_state s) -> sol::object
{
if (i.id().empty())
return sol::lua_nil;
else
return sol::make_object(s, i.id());
});
- layout_view_item_type["bounds_animated"] = sol::property(&layout_view::item::bounds_animated);
- layout_view_item_type["color_animated"] = sol::property(&layout_view::item::color_animated);
- layout_view_item_type["bounds"] = sol::property(&layout_view::item::bounds);
- layout_view_item_type["color"] = sol::property(&layout_view::item::color);
- layout_view_item_type["blend_mode"] = sol::property(&layout_view::item::blend_mode);
- layout_view_item_type["orientation"] = sol::property(&layout_view::item::orientation);
- layout_view_item_type["element_state"] = sol::property(&layout_view::item::element_state);
- layout_view_item_type["animation_state"] = sol::property(&layout_view::item::animation_state);
+ layout_view_item_type["bounds_animated"] = sol::property(&layout_view_item::bounds_animated);
+ layout_view_item_type["color_animated"] = sol::property(&layout_view_item::color_animated);
+ layout_view_item_type["bounds"] = sol::property(&layout_view_item::bounds);
+ layout_view_item_type["color"] = sol::property(&layout_view_item::color);
+ layout_view_item_type["scroll_wrap_x"] = sol::property(&layout_view_item::scroll_wrap_x);
+ layout_view_item_type["scroll_wrap_y"] = sol::property(&layout_view_item::scroll_wrap_y);
+ layout_view_item_type["scroll_size_x"] = sol::property(
+ &layout_view_item::scroll_size_x,
+ &layout_view_item::set_scroll_size_x);
+ layout_view_item_type["scroll_size_y"] = sol::property(
+ &layout_view_item::scroll_size_y,
+ &layout_view_item::set_scroll_size_y);
+ layout_view_item_type["scroll_pos_x"] = sol::property(
+ &layout_view_item::scroll_pos_x,
+ &layout_view_item::set_scroll_pos_y);
+ layout_view_item_type["scroll_pos_y"] = sol::property(
+ &layout_view_item::scroll_pos_y,
+ &layout_view_item::set_scroll_pos_y);
+ layout_view_item_type["blend_mode"] = sol::property(&layout_view_item::blend_mode);
+ layout_view_item_type["orientation"] = sol::property(&layout_view_item::orientation);
+ layout_view_item_type["element_state"] = sol::property(&layout_view_item::element_state);
+ layout_view_item_type["animation_state"] = sol::property(&layout_view_item::animation_state);
auto layout_file_type = sol().registry().new_usertype<layout_file>("layout_file", sol::no_constructor);