diff options
author | 2021-11-18 10:34:38 +1100 | |
---|---|---|
committer | 2021-11-18 10:34:38 +1100 | |
commit | 5afce6cfab6320ee062da5f7b7438294672f9af1 (patch) | |
tree | 5902ddf0b74f27e3d43bc0556dcfd29198e86efd /src | |
parent | ded9ecfc1cf7864f206b92480eaebf32092ef8f2 (diff) |
emu/render.cpp, emu/rendlay.cpp: Added scroll support for all elements.
Diffstat (limited to 'src')
-rw-r--r-- | src/emu/emufwd.h | 9 | ||||
-rw-r--r-- | src/emu/render.cpp | 85 | ||||
-rw-r--r-- | src/emu/render.h | 2 | ||||
-rw-r--r-- | src/emu/rendlay.cpp | 547 | ||||
-rw-r--r-- | src/emu/rendlay.h | 295 | ||||
-rw-r--r-- | src/frontend/mame/luaengine_render.cpp | 72 |
6 files changed, 711 insertions, 299 deletions
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); |