diff options
author | 2020-12-05 21:04:22 +1100 | |
---|---|---|
committer | 2020-12-05 21:04:22 +1100 | |
commit | cac83ba5b1fec32513704e5cb1919efc35d15e0e (patch) | |
tree | e12482d7bc59320c5a0225bb17444735eab250e3 | |
parent | e4ed0ebf242daeca43d85fa3281978d9e6d1b4c6 (diff) |
Expose enough of the layout system to Lua to allow position and colour to be animated.
-rw-r--r-- | plugins/layout/init.lua | 7 | ||||
-rw-r--r-- | src/emu/render.cpp | 1 | ||||
-rw-r--r-- | src/emu/render.h | 14 | ||||
-rw-r--r-- | src/emu/rendlay.cpp | 41 | ||||
-rw-r--r-- | src/frontend/mame/luaengine.cpp | 19 | ||||
-rw-r--r-- | src/frontend/mame/luaengine.h | 53 | ||||
-rw-r--r-- | src/frontend/mame/luaengine.ipp | 47 | ||||
-rw-r--r-- | src/frontend/mame/luaengine_debug.cpp | 2 | ||||
-rw-r--r-- | src/frontend/mame/luaengine_input.cpp | 2 | ||||
-rw-r--r-- | src/frontend/mame/luaengine_mem.cpp | 2 | ||||
-rw-r--r-- | src/frontend/mame/luaengine_render.cpp | 124 | ||||
-rw-r--r-- | src/mame/layout/v4dbltak.lay | 55 |
12 files changed, 224 insertions, 143 deletions
diff --git a/plugins/layout/init.lua b/plugins/layout/init.lua index aeb0ad77e44..654df599bd3 100644 --- a/plugins/layout/init.lua +++ b/plugins/layout/init.lua @@ -16,6 +16,13 @@ function layout.startplugin() local function prepare_layout(file, script) local env = { machine = manager:machine(), + emu = { + render_bounds = emu.render_bounds, + render_color = emu.render_color, + print_verbose = emu.print_verbose, + print_error = emu.print_error, + print_info = emu.print_info, + print_debug = emu.print_debug }, file = file, print = print, pairs = pairs, diff --git a/src/emu/render.cpp b/src/emu/render.cpp index c81db6c78d8..b2e278a59ea 100644 --- a/src/emu/render.cpp +++ b/src/emu/render.cpp @@ -1343,6 +1343,7 @@ render_primitive_list &render_target::get_primitives() if (m_manager.machine().phase() >= machine_phase::RESET) { // we're running - iterate over items in the view + current_view().prepare_items(); for (layout_view::item &curitem : current_view().visible_items()) { // first apply orientation to the bounds diff --git a/src/emu/render.h b/src/emu/render.h index e24893033c6..a94a23a0c97 100644 --- a/src/emu/render.h +++ b/src/emu/render.h @@ -724,6 +724,9 @@ public: using element_map = std::unordered_map<std::string, layout_element>; using group_map = std::unordered_map<std::string, layout_group>; using screen_ref_vector = std::vector<std::reference_wrapper<screen_device> >; + using prepare_items_delegate = delegate<void ()>; + using preload_delegate = delegate<void ()>; + using recomputed_delegate = delegate<void ()>; /// \brief A single item in a view /// @@ -930,7 +933,13 @@ public: u32 default_visibility_mask() const { return m_defvismask; } bool has_art() const { return m_has_art; } + // set handlers + void set_prepare_items_callback(prepare_items_delegate &&handler); + void set_preload_callback(preload_delegate &&handler); + void set_recomputed_callback(recomputed_delegate &&handler); + // operations + void prepare_items() { if (!m_prepare_items.isnull()) m_prepare_items(); } void recompute(u32 visibility_mask, bool zoom_to_screens); void preload(); @@ -973,6 +982,11 @@ private: edge_vector m_interactive_edges_y; screen_ref_vector m_screens; // list screens visible in current configuration + // handlers + prepare_items_delegate m_prepare_items; // prepare items for adding to render container + preload_delegate m_preload; // additional actions when visible items change + recomputed_delegate m_recomputed; // additional actions on resizing/visibility change + // cold items std::string m_name; // display name for the view std::string m_unqualified_name; // the name exactly as specified in the layout file diff --git a/src/emu/rendlay.cpp b/src/emu/rendlay.cpp index 46124cf73f6..422b93e7268 100644 --- a/src/emu/rendlay.cpp +++ b/src/emu/rendlay.cpp @@ -4214,8 +4214,46 @@ void layout_view::recompute(u32 visibility_mask, bool zoom_to_screen) for (edge const &e : m_interactive_edges_y) LOGMASKED(LOG_INTERACTIVE_ITEMS, "y=%s %c%u\n", e.position(), e.trailing() ? ']' : '[', e.index()); } + + // additional actions typically supplied by script + if (!m_recomputed.isnull()) + m_recomputed(); +} + + +//------------------------------------------------- +// set_prepare_items_callback - set handler called +// before adding items to render target +//------------------------------------------------- + +void layout_view::set_prepare_items_callback(prepare_items_delegate &&handler) +{ + m_prepare_items = std::move(handler); +} + + +//------------------------------------------------- +// set_preload_callback - set handler called +// after preloading elements +//------------------------------------------------- + +void layout_view::set_preload_callback(preload_delegate &&handler) +{ + m_preload = std::move(handler); +} + + +//------------------------------------------------- +// set_recomputed_callback - set handler called +// after recomputing item bounds +//------------------------------------------------- + +void layout_view::set_recomputed_callback(recomputed_delegate &&handler) +{ + m_recomputed = std::move(handler); } + //------------------------------------------------- // preload - perform expensive loading upfront // for visible elements @@ -4228,6 +4266,9 @@ void layout_view::preload() if (curitem.element()) curitem.element()->preload(); } + + if (!m_preload.isnull()) + m_preload(); } diff --git a/src/frontend/mame/luaengine.cpp b/src/frontend/mame/luaengine.cpp index 6ff6dc0709c..e4da280e221 100644 --- a/src/frontend/mame/luaengine.cpp +++ b/src/frontend/mame/luaengine.cpp @@ -985,7 +985,7 @@ void lua_engine::initialize() * manager:options() * manager:machine():options() * - * options:slot_option() - retrieves a specific slot option + * options:slot_option(tag) - retrieves a specific slot option */ auto emu_options_type = sol().registry().new_usertype<emu_options>("emu_options", sol::no_constructor, sol::base_classes, sol::bases<core_options>()); @@ -1286,6 +1286,7 @@ void lua_engine::initialize() * device:memregion(tag) - get memory region * device:memshare(tag) - get memory share * device:membank(tag) - get memory bank + * device:ioport(tag) - get I/O port * device:subdevice(tag) - get subdevice * device:siblingdevice(tag) - get sibling device * device:debug() - debug interface, CPUs only @@ -1309,6 +1310,7 @@ void lua_engine::initialize() device_type["memregion"] = &device_t::memregion; device_type["memshare"] = &device_t::memshare; device_type["membank"] = &device_t::membank; + device_type["ioport"] = &device_t::ioport; device_type["subdevice"] = static_cast<device_t *(device_t::*)(char const *) const>(&device_t::subdevice); device_type["siblingdevice"] = static_cast<device_t *(device_t::*)(char const *) const>(&device_t::siblingdevice); device_type["debug"] = @@ -1873,7 +1875,7 @@ void lua_engine::initialize() auto cass_type = sol().registry().new_usertype<cassette_image_device>( "cassette", sol::no_constructor, - sol::base_classes, sol::bases<device_t>()); + sol::base_classes, sol::bases<device_t, device_image_interface>()); cass_type["stop"] = [] (cassette_image_device &c) { c.change_state(CASSETTE_STOPPED, CASSETTE_MASK_UISTATE); }; cass_type["play"] = [] (cassette_image_device &c) { c.change_state(CASSETTE_PLAY, CASSETTE_MASK_UISTATE); }; cass_type["record"] = [] (cassette_image_device &c) { c.change_state(CASSETTE_RECORD, CASSETTE_MASK_UISTATE); }; @@ -1886,11 +1888,10 @@ void lua_engine::initialize() cass_type["motor_state"] = sol::property(&cassette_image_device::motor_on, &cassette_image_device::set_motor); cass_type["speaker_state"] = sol::property(&cassette_image_device::speaker_on, &cassette_image_device::set_speaker); cass_type["position"] = sol::property(&cassette_image_device::get_position); - cass_type["length"] = sol::property([] (cassette_image_device &c) { if (c.exists()) return c.get_length(); return 0.0; }); - cass_type["image"] = sol::property([] (cassette_image_device &c) { return dynamic_cast<device_image_interface *>(&c); }); + cass_type["length"] = sol::property([] (cassette_image_device &c) { return c.exists() ? c.get_length() : 0.0; }); -/* mame_machine_manager library +/* mame_machine_manager library * * manager * mame_manager - alias of manager @@ -1924,10 +1925,10 @@ void lua_engine::initialize() // set up other user types - initialize_debug(); - initialize_input(); - initialize_memory(); - initialize_render(); + initialize_debug(emu); + initialize_input(emu); + initialize_memory(emu); + initialize_render(emu); } //------------------------------------------------- diff --git a/src/frontend/mame/luaengine.h b/src/frontend/mame/luaengine.h index e4a7ac2bdf6..14d47fbf89c 100644 --- a/src/frontend/mame/luaengine.h +++ b/src/frontend/mame/luaengine.h @@ -122,6 +122,26 @@ public: private: template<typename T, size_t SIZE> class enum_parser; + struct addr_space; + + struct save_item { + void *base; + unsigned int size; + unsigned int count; + unsigned int valcount; + unsigned int blockcount; + unsigned int stride; + }; + + struct context + { + context() { busy = false; yield = false; } + std::string result; + std::condition_variable sync; + bool busy; + bool yield; + }; + // internal state lua_State *m_lua_state; std::unique_ptr<sol::state_view> m_sol_state; @@ -130,6 +150,9 @@ private: std::vector<std::string> m_menu; + template <typename R, typename T, typename D> + auto make_simple_callback_setter(void (T::*setter)(delegate<R ()> &&), D &&dflt, const char *name, const char *desc); + running_machine &machine() const { return *m_machine; } void on_machine_prestart(); @@ -145,37 +168,17 @@ private: bool execute_function(const char *id); sol::object call_plugin(const std::string &name, sol::object in); - struct addr_space; - - struct save_item { - void *base; - unsigned int size; - unsigned int count; - unsigned int valcount; - unsigned int blockcount; - unsigned int stride; - }; - void close(); void run(sol::load_result res); - struct context - { - context() { busy = false; yield = false; } - std::string result; - std::condition_variable sync; - bool busy; - bool yield; - }; - - template<typename TFunc, typename... TArgs> + template <typename TFunc, typename... TArgs> sol::protected_function_result invoke(TFunc &&func, TArgs&&... args); - void initialize_debug(); - void initialize_input(); - void initialize_memory(); - void initialize_render(); + void initialize_debug(sol::table &emu); + void initialize_input(sol::table &emu); + void initialize_memory(sol::table &emu); + void initialize_render(sol::table &emu); }; #endif // MAME_FRONTEND_MAME_LUAENGINE_H diff --git a/src/frontend/mame/luaengine.ipp b/src/frontend/mame/luaengine.ipp index 16065ae5216..0024c0afb78 100644 --- a/src/frontend/mame/luaengine.ipp +++ b/src/frontend/mame/luaengine.ipp @@ -310,6 +310,53 @@ private: //------------------------------------------------- +// make_simple_callback_setter - make a callback +// setter for simple cases +//------------------------------------------------- + +template <typename R, typename T, typename D> +auto lua_engine::make_simple_callback_setter(void (T::*setter)(delegate<R ()> &&), D &&dflt, const char *name, const char *desc) +{ + return + [this, setter, dflt, name, desc] (T &self, sol::object cb) + { + if (cb == sol::lua_nil) + { + (self.*setter)(delegate<R ()>()); + } + else if (cb.is<sol::protected_function>()) + { + (self.*setter)(delegate<R ()>( + [this, dflt, name, desc, cbfunc = cb.as<sol::protected_function>()] () -> R + { + if constexpr (std::is_same_v<R, void>) + { + invoke(cbfunc); + } + else + { + auto result(invoke(cbfunc).get<sol::optional<R> >()); + if (result) + { + return *result; + } + else + { + osd_printf_error("[LUA ERROR] invalid return from %s callback\n", desc); + return dflt(); + } + } + })); + } + else + { + osd_printf_error("[LUA ERROR] must call %s with function or nil\n", name); + } + }; +} + + +//------------------------------------------------- // invoke - invokes a function, wrapping profiler //------------------------------------------------- diff --git a/src/frontend/mame/luaengine_debug.cpp b/src/frontend/mame/luaengine_debug.cpp index 4cbff8d799f..aec17ada89b 100644 --- a/src/frontend/mame/luaengine_debug.cpp +++ b/src/frontend/mame/luaengine_debug.cpp @@ -81,7 +81,7 @@ sol::object do_watchpoint_enable(lua_State *L, device_debug &dev, sol::object &i } // anonymous namespace -void lua_engine::initialize_debug() +void lua_engine::initialize_debug(sol::table &emu) { static const enum_parser<read_or_write, 4> s_read_or_write_parser = diff --git a/src/frontend/mame/luaengine_input.cpp b/src/frontend/mame/luaengine_input.cpp index f954038b70f..e135678a840 100644 --- a/src/frontend/mame/luaengine_input.cpp +++ b/src/frontend/mame/luaengine_input.cpp @@ -21,7 +21,7 @@ // initialize_input - register input user types //------------------------------------------------- -void lua_engine::initialize_input() +void lua_engine::initialize_input(sol::table &emu) { static const enum_parser<input_seq_type, 3> s_seq_type_parser = diff --git a/src/frontend/mame/luaengine_mem.cpp b/src/frontend/mame/luaengine_mem.cpp index 65db6becf6a..dc9abcbbb21 100644 --- a/src/frontend/mame/luaengine_mem.cpp +++ b/src/frontend/mame/luaengine_mem.cpp @@ -353,7 +353,7 @@ void lua_engine::addr_space::direct_mem_write(offs_t address, T val) // initialize_memory - register memory user types //------------------------------------------------- -void lua_engine::initialize_memory() +void lua_engine::initialize_memory(sol::table &emu) { /* addr_space library diff --git a/src/frontend/mame/luaengine_render.cpp b/src/frontend/mame/luaengine_render.cpp index 68113f0650b..5df401c9b17 100644 --- a/src/frontend/mame/luaengine_render.cpp +++ b/src/frontend/mame/luaengine_render.cpp @@ -316,7 +316,7 @@ public: // initialize_render - register render user types //------------------------------------------------- -void lua_engine::initialize_render() +void lua_engine::initialize_render(sol::table &emu) { /* render_bounds library @@ -333,12 +333,14 @@ void lua_engine::initialize_render() * bounds.height - get/set height * bounds.aspect - read-only aspect ratio width:height */ - auto bounds_type = sol().registry().new_usertype<render_bounds>("bounds", sol::call_constructor, sol::initializers( + auto bounds_type = emu.new_usertype<render_bounds>( + "render_bounds", + sol::call_constructor, sol::initializers( [] (render_bounds &b) { new (&b) render_bounds{ 0.0F, 0.0F, 1.0F, 1.0F }; }, [] (render_bounds &b, float x0, float y0, float x1, float y1) { new (&b) render_bounds{ x0, y0, x1, y1 }; })); bounds_type["includes"] = &render_bounds::includes; - bounds_type["set_xy"] = &render_bounds::includes; - bounds_type["set_wh"] = &render_bounds::includes; + bounds_type["set_xy"] = &render_bounds::set_xy; + bounds_type["set_wh"] = &render_bounds::set_wh; bounds_type["x0"] = &render_bounds::x0; bounds_type["y0"] = &render_bounds::y0; bounds_type["x1"] = &render_bounds::x1; @@ -357,7 +359,9 @@ void lua_engine::initialize_render() * color.g - green channel * color.b - blue channel */ - auto color_type = sol().registry().new_usertype<render_color>("color", sol::call_constructor, sol::initializers( + auto color_type = emu.new_usertype<render_color>( + "render_color", + sol::call_constructor, sol::initializers( [] (render_color &c) { new (&c) render_color{ 1.0F, 1.0F, 1.0F, 1.0F }; }, [] (render_color &c, float a, float r, float g, float b) { new (&c) render_color{ a, r, g, b }; })); color_type["set"] = &render_color::set; @@ -372,6 +376,9 @@ void lua_engine::initialize_render() * manager:machine():render().targets[target_index]:current_view() * * view:has_screen(screen) - returns whether a given screen is present in the view (including hidden screens) + * view:set_prepare_items_callback(cb) - set additional tasks before adding items to render target + * view:set_preload_callback(cb) - set additional tasks after preloading visible items + * view:set_recomputed_callback(cb) - set additional tasks after recomputing for resize or visibility change * * view.items - get the items in the view (including hidden items) * view.name - display name for the view @@ -384,6 +391,24 @@ void lua_engine::initialize_render() auto layout_view_type = sol().registry().new_usertype<layout_view>("layout_view", sol::no_constructor); layout_view_type["has_screen"] = &layout_view::has_screen; + layout_view_type["set_prepare_items_callback"] = + make_simple_callback_setter<void>( + &layout_view::set_prepare_items_callback, + nullptr, + "set_prepare_items_callback", + nullptr); + layout_view_type["set_preload_callback"] = + make_simple_callback_setter<void>( + &layout_view::set_preload_callback, + nullptr, + "set_preload_callback", + nullptr); + layout_view_type["set_recomputed_callback"] = + make_simple_callback_setter<void>( + &layout_view::set_recomputed_callback, + nullptr, + "set_recomputed_callback", + nullptr); layout_view_type["items"] = sol::property([] (layout_view &v) { return layout_view_items(v); }); layout_view_type["name"] = sol::property(&layout_view::name); layout_view_type["unqualified_name"] = sol::property(&layout_view::unqualified_name); @@ -415,63 +440,17 @@ void lua_engine::initialize_render() 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"] = - [this] (layout_view::item &i, sol::object cb) - { - if (cb == sol::lua_nil) - { - i.set_element_state_callback(layout_view::item::state_delegate()); - } - else if (cb.is<sol::protected_function>()) - { - i.set_element_state_callback(layout_view::item::state_delegate( - [this, cbfunc = cb.as<sol::protected_function>()] () -> int - { - auto result(invoke(cbfunc).get<sol::optional<int> >()); - if (result) - { - return *result; - } - else - { - osd_printf_error("[LUA ERROR] invalid return from element state callback\n"); - return 0; - } - })); - } - else - { - osd_printf_error("[LUA ERROR] must call set_element_state_callback with function or nil\n"); - } - }; + make_simple_callback_setter<int>( + &layout_view::item::set_element_state_callback, + [] () { return 0; }, + "set_element_state_callback", + "element state"); layout_view_item_type["set_animation_state_callback"] = - [this] (layout_view::item &i, sol::object cb) - { - if (cb == sol::lua_nil) - { - i.set_animation_state_callback(layout_view::item::state_delegate()); - } - else if (cb.is<sol::protected_function>()) - { - i.set_animation_state_callback(layout_view::item::state_delegate( - [this, cbfunc = cb.as<sol::protected_function>()] () -> int - { - auto result(invoke(cbfunc).get<sol::optional<int> >()); - if (result) - { - return *result; - } - else - { - osd_printf_error("[LUA ERROR] invalid return from animation state callback\n"); - return 0; - } - })); - } - else - { - osd_printf_error("[LUA ERROR] must call set_animation_state_callback with function or nil\n"); - } - }; + make_simple_callback_setter<int>( + &layout_view::item::set_animation_state_callback, + [] () { return 0; }, + "set_animation_state_callback", + "animation state"); layout_view_item_type["set_bounds_callback"] = [this] (layout_view::item &i, sol::object cb) { @@ -550,7 +529,7 @@ void lua_engine::initialize_render() /* layout_file library * - * file.set_resolve_tags_callback - set additional tasks after resolving tags + * file:set_resolve_tags_callback(cb) - set additional tasks after resolving tags * * file.device - get device that caused the file to be loaded * file.views[] - get view table (k=name, v=layout_view) @@ -558,22 +537,11 @@ void lua_engine::initialize_render() auto layout_file_type = sol().registry().new_usertype<layout_file>("layout_file", sol::no_constructor); layout_file_type["set_resolve_tags_callback"] = - [this] (layout_file &f, sol::object cb) - { - if (cb == sol::lua_nil) - { - f.set_resolve_tags_callback(layout_file::resolve_tags_delegate()); - } - else if (cb.is<sol::protected_function>()) - { - f.set_resolve_tags_callback(layout_file::resolve_tags_delegate( - [this, cbfunc = cb.as<sol::protected_function>()] () { invoke(cbfunc); })); - } - else - { - osd_printf_error("[LUA ERROR] must call set_resolve_tags_callback with function or nil\n"); - } - }; + make_simple_callback_setter<void>( + &layout_file::set_resolve_tags_callback, + nullptr, + "set_resolve_tags_callback", + nullptr); layout_file_type["device"] = sol::property(&layout_file::device); layout_file_type["views"] = sol::property([] (layout_file &f) { return layout_file_views(f); }); diff --git a/src/mame/layout/v4dbltak.lay b/src/mame/layout/v4dbltak.lay index 64b54f765fd..55d6f5345db 100644 --- a/src/mame/layout/v4dbltak.lay +++ b/src/mame/layout/v4dbltak.lay @@ -3,44 +3,43 @@ license:CC0 --> <mamelayout version="2"> - <!-- luascript (demo for plugin -layout) --> - <!-- this adds support for combining outputs to make an aggregated output--> + <!-- Lua script (demo for -plugin layout) --> + <!-- this adds support for combining outputs to make an aggregated output --> <script><![CDATA[ - local layout = { } - local ledlamps = { { 88, 89, 90, 91, 92, 93, 94 }, { 80, 81, 82, 83, 84, 85, 86, 87 }, { 72, 73, 74, 75, 76, 77, 78 }, { 64, 65, 66, 67, 68, 69, 70 } } - local views = { } - - for k, view in pairs(file.views) do - views[k] = { - view.items["compoundled0"], - view.items["compoundled1"], - view.items["compoundled2"], - view.items["compoundled3"] } + function configure_view(view) + local led_items = { + view.items["compoundled0"], + view.items["compoundled1"], + view.items["compoundled2"], + view.items["compoundled3"] } + view:set_prepare_items_callback( + function () + for ledno, lamps in pairs(ledlamps) do + local ledstate = 0 + for bit, lampno in pairs(lamps) do + if machine:outputs():get_indexed_value("lamp", lampno) > 0 then + ledstate = ledstate | (1 << (bit - 1)) + end + end + if led_items[ledno] ~= nil then + led_items[ledno]:set_state(ledstate) + end + end + end) end - function layout.frame() - for ledno, lamps in pairs(ledlamps) do - local ledstate = 0 - for bit, lampno in pairs(lamps) do - if machine:outputs():get_indexed_value("lamp", lampno) > 0 then - ledstate = ledstate | (1 << (bit - 1)) - end - end - for k, view in pairs(views) do - if view[ledno] ~= nil then - view[ledno]:set_state(ledstate) + file:set_resolve_tags_callback( + function () + for k, view in pairs(file.views) do + configure_view(view) end - end - end - end - - return layout + end) ]]></script> <element name="£"> |