diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/frontend/mame/luaengine.cpp | 53 | ||||
-rw-r--r-- | src/frontend/mame/luaengine_render.cpp | 320 | ||||
-rw-r--r-- | src/lib/util/bitmap.cpp | 54 |
3 files changed, 394 insertions, 33 deletions
diff --git a/src/frontend/mame/luaengine.cpp b/src/frontend/mame/luaengine.cpp index 43449a62184..1d0bfca5e76 100644 --- a/src/frontend/mame/luaengine.cpp +++ b/src/frontend/mame/luaengine.cpp @@ -720,6 +720,9 @@ void lua_engine::initialize() emu["device_enumerator"] = sol::overload( [] (device_t &dev) { return devenum<device_enumerator>(dev); }, [] (device_t &dev, int maxdepth) { return devenum<device_enumerator>(dev, maxdepth); }); + emu["palette_enumerator"] = sol::overload( + [] (device_t &dev) { return devenum<palette_interface_enumerator>(dev); }, + [] (device_t &dev, int maxdepth) { return devenum<palette_interface_enumerator>(dev, maxdepth); }); emu["screen_enumerator"] = sol::overload( [] (device_t &dev) { return devenum<screen_device_enumerator>(dev); }, [] (device_t &dev, int maxdepth) { return devenum<screen_device_enumerator>(dev, maxdepth); }); @@ -1271,6 +1274,7 @@ void lua_engine::initialize() machine_type["exit_pending"] = sol::property(&running_machine::exit_pending); machine_type["hard_reset_pending"] = sol::property(&running_machine::hard_reset_pending); machine_type["devices"] = sol::property([] (running_machine &m) { return devenum<device_enumerator>(m.root_device()); }); + machine_type["palettes"] = sol::property([] (running_machine &m) { return devenum<palette_interface_enumerator>(m.root_device()); }); machine_type["screens"] = sol::property([] (running_machine &m) { return devenum<screen_device_enumerator>(m.root_device()); }); machine_type["cassettes"] = sol::property([] (running_machine &m) { return devenum<cassette_device_enumerator>(m.root_device()); }); machine_type["images"] = sol::property([] (running_machine &m) { return devenum<image_interface_enumerator>(m.root_device()); }); @@ -1432,6 +1436,54 @@ void lua_engine::initialize() }); + auto dipalette_type = sol().registry().new_usertype<device_palette_interface>("dipalette", sol::no_constructor); + dipalette_type.set_function("pen", &device_palette_interface::pen); + dipalette_type.set_function( + "pen_color", + [] (device_palette_interface const &pal, pen_t pen) + { + return uint32_t(pal.pen_color(pen)); + }); + dipalette_type.set_function("pen_contrast", &device_palette_interface::pen_contrast); + dipalette_type.set_function("pen_indirect", &device_palette_interface::pen_indirect); + dipalette_type.set_function( + "indirect_color", + [] (device_palette_interface const &pal, int index) + { + return uint32_t(pal.indirect_color(index)); + }); + dipalette_type["set_pen_color"] = sol::overload( + [] (device_palette_interface &pal, pen_t pen, uint32_t color) + { + pal.set_pen_color(pen, rgb_t(color)); + }, + static_cast<void (device_palette_interface::*)(pen_t, uint8_t, uint8_t, uint8_t)>(&device_palette_interface::set_pen_color)); + dipalette_type.set_function("set_pen_red_level", &device_palette_interface::set_pen_red_level); + dipalette_type.set_function("set_pen_green_level", &device_palette_interface::set_pen_green_level); + dipalette_type.set_function("set_pen_blue_level", &device_palette_interface::set_pen_blue_level); + dipalette_type.set_function("set_pen_contrast", &device_palette_interface::set_pen_contrast); + dipalette_type.set_function("set_pen_indirect", &device_palette_interface::set_pen_indirect); + dipalette_type["set_indirect_color"] = sol::overload( + [] (device_palette_interface &pal, int index, uint32_t color) + { + pal.set_indirect_color(index, rgb_t(color)); + }, + [] (device_palette_interface &pal, int index, uint8_t r, uint8_t g, uint8_t b) + { + pal.set_indirect_color(index, rgb_t(r, g, b)); + }); + dipalette_type.set_function("set_shadow_factor", &device_palette_interface::set_shadow_factor); + dipalette_type.set_function("set_highlight_factor", &device_palette_interface::set_highlight_factor); + dipalette_type.set_function("set_shadow_mode", &device_palette_interface::set_shadow_mode); + dipalette_type["entries"] = sol::property(&device_palette_interface::entries); + dipalette_type["indirect_entries"] = sol::property(&device_palette_interface::indirect_entries); + dipalette_type["black_pen"] = sol::property(&device_palette_interface::black_pen); + dipalette_type["white_pen"] = sol::property(&device_palette_interface::white_pen); + dipalette_type["shadows_enabled"] = sol::property(&device_palette_interface::shadows_enabled); + dipalette_type["highlights_enabled"] = sol::property(&device_palette_interface::hilights_enabled); + dipalette_type["device"] = sol::property(static_cast<device_t & (device_palette_interface::*)()>(&device_palette_interface::device)); + + auto screen_dev_type = sol().registry().new_usertype<screen_device>( "screen_dev", sol::no_constructor, @@ -1589,6 +1641,7 @@ void lua_engine::initialize() screen_dev_type["frame_period"] = sol::property([] (screen_device &sdev) { return sdev.frame_period().as_double(); }); screen_dev_type["frame_number"] = &screen_device::frame_number; screen_dev_type["container"] = sol::property(&screen_device::container); + screen_dev_type["palette"] = sol::property([] (screen_device const &sdev) { return sdev.has_palette() ? &sdev.palette() : nullptr; }); auto cass_type = sol().registry().new_usertype<cassette_image_device>( diff --git a/src/frontend/mame/luaengine_render.cpp b/src/frontend/mame/luaengine_render.cpp index 893412a4b30..ed56d7470b2 100644 --- a/src/frontend/mame/luaengine_render.cpp +++ b/src/frontend/mame/luaengine_render.cpp @@ -17,11 +17,181 @@ #include "render.h" #include "rendlay.h" +#include <atomic> #include <iterator> namespace { +template <typename T> +class bitmap_helper : public T +{ +public: + using ptr = std::shared_ptr<bitmap_helper>; + + bitmap_helper(bitmap_helper const &) = delete; + bitmap_helper(bitmap_helper &&) = delete; + bitmap_helper &operator=(bitmap_helper const &) = delete; + bitmap_helper &operator=(bitmap_helper &&) = delete; + + bitmap_helper(sol::this_state s, int width, int height, int xslop, int yslop) + : T(width, height, xslop, yslop) + , lock_count(0) + , storage() + { + if ((0 < width) && (0 < height) && !this->valid()) + luaL_error(s, "Error allocating bitmap storage"); + } + + bitmap_helper(ptr const &source, rectangle const &subrect) + : T(*source, subrect) + , lock_count(0) + , storage(source->storage ? source->storage : source) + { + ++storage->lock_count; + } + + ~bitmap_helper() + { + assert(!lock_count); + release_storage(); + } + + bool locked() const + { + return bool(lock_count); + } + + void reset(sol::this_state s) + { + if (lock_count) + luaL_error(s, "Cannot reset bitmap while in use"); + T::reset(); + release_storage(); + } + + void allocate(sol::this_state s, int width, int height, int xslop, int yslop) + { + if (lock_count) + luaL_error(s, "Cannot reallocate bitmap while in use"); + T::allocate(width, height, xslop, yslop); + release_storage(); + if ((0 < width) && (0 < height) && !this->valid()) + luaL_error(s, "Error allocating bitmap storage"); + } + + void resize(sol::this_state s, int width, int height, int xslop, int yslop) + { + if (lock_count) + luaL_error(s, "Cannot resize bitmap while in use"); + T::resize(width, height, xslop, yslop); + release_storage(); + if ((0 < width) && (0 < height) && !this->valid()) + luaL_error(s, "Error allocating bitmap storage"); + } + + void wrap(sol::this_state s, ptr const &source, rectangle const &subrect) + { + if (source.get() == this) + luaL_error(s, "Bitmap cannot wrap itself"); + if (lock_count) + luaL_error(s, "Cannot free bitmap storage while in use"); + if (!source->cliprect().contains(subrect)) + luaL_error(s, "Bounds exceed source clipping rectangle"); + T::wrap(*source, subrect); + release_storage(); + storage = source->storage ? source->storage : source; + ++storage->lock_count; + } + + std::atomic<unsigned> lock_count; + +private: + void release_storage() + { + if (storage) + { + assert(storage->lock_count); + --storage->lock_count; + storage.reset(); + } + } + + ptr storage; +}; + + +class render_texture_helper +{ +public: + render_texture_helper(render_texture_helper const &) = delete; + + render_texture_helper(render_texture_helper &&that) + : texture(that.texture) + , bitmap(that.bitmap) + , manager(that.manager) + , lock_count(that.lock_count) + { + that.texture = nullptr; + that.bitmap.reset(); + } + + template <typename T> + render_texture_helper(sol::this_state s, render_manager &m, std::shared_ptr<T> const &b, texture_format f) + : texture(nullptr) + , bitmap(b) + , manager(m) + , lock_count(b->lock_count) + { + if (bitmap) + { + texture = manager.texture_alloc(); + if (texture) + { + ++lock_count; + texture->set_bitmap(*bitmap, bitmap->cliprect(), f); + } + else + { + luaL_error(s, "Error allocating texture"); + } + } + } + + ~render_texture_helper() + { + free(); + } + + bool valid() const + { + return texture && bitmap; + } + + void free() + { + if (texture) + { + manager.texture_free(texture); + texture = nullptr; + } + if (bitmap) + { + assert(lock_count); + --lock_count; + bitmap.reset(); + } + } + + render_texture *texture; + std::shared_ptr<bitmap_t> bitmap; + +private: + render_manager &manager; + std::atomic<unsigned> &lock_count; +}; + + struct layout_file_views { layout_file_views(layout_file &f) : file(f) { } @@ -54,6 +224,84 @@ struct render_target_view_names int count; }; + +template <typename T> +auto make_bitmap_specific_type(sol::table registry, char const *name) +{ + auto result = registry.new_usertype<T>( + name, + sol::no_constructor, + sol::base_classes, sol::bases<bitmap_t>()); + result.set_function("pix", [] (T &bitmap, int32_t x, int32_t y) { return bitmap.pix(y, x); }); + result["fill"] = sol::overload( + static_cast<void (T::*)(typename T::pixel_t)>(&T::fill), + [] (T &bitmap, typename T::pixel_t color, int32_t minx, int32_t miny, int32_t maxx, int32_t maxy) + { + bitmap.fill(color, rectangle(minx, maxx, miny, maxy)); + }); + result.set_function( + "plot", + [] (T &bitmap, int32_t x, int32_t y, typename T::pixel_t color) + { + if (bitmap.cliprect().contains(x, y)) + bitmap.pix(y, x) = color; + }); + result.set_function("plot_box", &T::plot_box); + result["bpp"] = sol::property(&T::bpp); + return result; +} + + +template <typename T, typename B> +auto make_bitmap_type(sol::table ®istry, char const *name) +{ + auto result = registry.new_usertype<T>( + name, + sol::call_constructor, sol::factories( + [] (sol::this_state s) + { + return std::make_shared<T>(s, 0, 0, 0, 0); + }, + [] (sol::this_state s, int width, int height) + { + return std::make_shared<T>(s, width, height, 0, 0); + }, + [] (sol::this_state s, int width, int height, int xslop, int yslop) + { + return std::make_shared<T>(s, width, height, xslop, yslop); + }, + [] (typename T::ptr const &source) + { + return std::make_shared<T>(source, source->cliprect()); + }, + [] (sol::this_state s, typename T::ptr const &source, int32_t minx, int32_t miny, int32_t maxx, int32_t maxy) + { + rectangle const subrect(minx, maxx, miny, maxy); + if (!source->cliprect().contains(subrect)) + luaL_error(s, "Bounds exceed source clipping rectangle"); + return std::make_shared<T>(source, subrect); + }), + sol::base_classes, sol::bases<B, bitmap_t>()); + result.set_function("reset", &T::reset); + result["allocate"] = sol::overload( + &T::allocate, + [] (T &bitmap, sol::this_state s, int width, int height) { bitmap.allocate(s, width, height, 0, 0); }); + result["resize"] = sol::overload( + &T::resize, + [] (T &bitmap, sol::this_state s, int width, int height) { bitmap.resize(s, width, height, 0, 0); }); + result["wrap"] = sol::overload( + [] (T &bitmap, sol::this_state s, typename T::ptr const &source) + { + bitmap.wrap(s, source, source->cliprect()); + }, + [] (T &bitmap, sol::this_state s, typename T::ptr const &source, int32_t minx, int32_t miny, int32_t maxx, int32_t maxy) + { + bitmap.wrap(s, source, rectangle(minx, maxx, miny, maxy)); + }); + result["locked"] = sol::property(&T::locked); + return result; +} + } // anonymous namespace @@ -226,9 +474,9 @@ void lua_engine::initialize_render(sol::table &emu) 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::set_xy; - bounds_type["set_wh"] = &render_bounds::set_wh; + bounds_type.set_function("includes", &render_bounds::includes); + bounds_type.set_function("set_xy", &render_bounds::set_xy); + bounds_type.set_function("set_wh", &render_bounds::set_wh); bounds_type["x0"] = &render_bounds::x0; bounds_type["y0"] = &render_bounds::y0; bounds_type["x1"] = &render_bounds::x1; @@ -243,13 +491,43 @@ void lua_engine::initialize_render(sol::table &emu) 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; + color_type.set_function("set", &render_color::set); color_type["a"] = &render_color::a; color_type["r"] = &render_color::r; color_type["g"] = &render_color::g; color_type["b"] = &render_color::b; + auto bitmap_type = sol().registry().new_usertype<bitmap_t>("bitmap", sol::no_constructor); + bitmap_type["fill"] = sol::overload( + static_cast<void (bitmap_t::*)(uint64_t)>(&bitmap_t::fill), + [] (bitmap_t &bitmap, uint64_t color, int32_t minx, int32_t miny, int32_t maxx, int32_t maxy) + { + bitmap.fill(color, rectangle(minx, maxx, miny, maxy)); + }); + bitmap_type.set_function("plot_box", &bitmap_t::plot_box); + bitmap_type["width"] = sol::property(&bitmap_t::width); + bitmap_type["height"] = sol::property(&bitmap_t::height); + bitmap_type["rowpixels"] = sol::property(&bitmap_t::rowpixels); + bitmap_type["rowbytes"] = sol::property(&bitmap_t::rowbytes); + bitmap_type["bpp"] = sol::property(&bitmap_t::bpp); + bitmap_type["valid"] = sol::property(&bitmap_t::valid); + + make_bitmap_specific_type<bitmap8_t>(sol().registry(), "bitmap8"); + make_bitmap_specific_type<bitmap16_t>(sol().registry(), "bitmap16"); + make_bitmap_specific_type<bitmap32_t>(sol().registry(), "bitmap32"); + make_bitmap_specific_type<bitmap64_t>(sol().registry(), "bitmap64"); + + make_bitmap_type<bitmap_helper<bitmap_yuy16>, bitmap16_t>(emu, "bitmap_yuy16"); + make_bitmap_type<bitmap_helper<bitmap_rgb32>, bitmap32_t>(emu, "bitmap_rgb32"); + make_bitmap_type<bitmap_helper<bitmap_argb32>, bitmap32_t>(emu, "bitmap_argb32"); + + + auto render_texture_type = emu.new_usertype<render_texture_helper>("render_texture", sol::no_constructor); + render_texture_type.set_function("free", &render_texture_helper::free); + render_texture_type["valid"] = sol::property(&render_texture_helper::valid); + + 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"] = @@ -392,7 +670,8 @@ void lua_engine::initialize_render(sol::table &emu) auto render_container_type = sol().registry().new_usertype<render_container>("render_container", sol::no_constructor); - render_container_type["draw_box"] = + render_container_type.set_function( + "draw_box", [] (render_container &ctnr, float x1, float y1, float x2, float y2, std::optional<uint32_t> fgcolor, std::optional<uint32_t> bgcolor) { x1 = std::clamp(x1, 0.0f, 1.0f); @@ -405,8 +684,9 @@ void lua_engine::initialize_render(sol::table &emu) if (!bgcolor) bgcolor = ui.colors().background_color(); ui.draw_outlined_box(ctnr, x1, y1, x2, y2, *fgcolor, *bgcolor); - }; - render_container_type["draw_line"] = + }); + render_container_type.set_function( + "draw_line", [] (render_container &ctnr, float x1, float y1, float x2, float y2, std::optional<uint32_t> color) { x1 = std::clamp(x1, 0.0f, 1.0f); @@ -416,8 +696,15 @@ void lua_engine::initialize_render(sol::table &emu) if (!color) color = mame_machine_manager::instance()->ui().colors().text_color(); ctnr.add_line(x1, y1, x2, y2, UI_LINE_WIDTH, rgb_t(*color), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)); - }; - render_container_type["draw_text"] = + }); + render_container_type.set_function( + "draw_quad", + [] (render_container &cntr, render_texture_helper const &tex, float x1, float y1, float x2, float y2, std::optional<uint32_t> color) + { + cntr.add_quad(x1, y1, x2, y2, color ? *color : uint32_t(0xffffffff), tex.texture, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)); + }); + render_container_type.set_function( + "draw_text", [] (render_container &ctnr, sol::this_state s, sol::object xobj, float y, char const *msg, std::optional<uint32_t> fgcolor, std::optional<uint32_t> bgcolor) { auto justify = ui::text_layout::text_justify::LEFT; @@ -453,7 +740,7 @@ void lua_engine::initialize_render(sol::table &emu) x, y, (1.0f - x), justify, ui::text_layout::word_wrapping::WORD, mame_ui_manager::OPAQUE_, *fgcolor, *bgcolor); - }; + }); render_container_type["user_settings"] = sol::property(&render_container::get_user_settings, &render_container::set_user_settings); render_container_type["orientation"] = sol::property( &render_container::orientation, @@ -510,6 +797,19 @@ void lua_engine::initialize_render(sol::table &emu) auto render_type = sol().registry().new_usertype<render_manager>("render", sol::no_constructor); + render_type["texture_alloc"] = sol::overload( + [] (render_manager &manager, sol::this_state s, bitmap_helper<bitmap_yuy16>::ptr const &bitmap) + { + return render_texture_helper(s, manager, bitmap, TEXFORMAT_YUY16); + }, + [] (render_manager &manager, sol::this_state s, bitmap_helper<bitmap_rgb32>::ptr const &bitmap) + { + return render_texture_helper(s, manager, bitmap, TEXFORMAT_RGB32); + }, + [] (render_manager &manager, sol::this_state s, bitmap_helper<bitmap_argb32>::ptr const &bitmap) + { + return render_texture_helper(s, manager, bitmap, TEXFORMAT_ARGB32); + }); render_type["max_update_rate"] = sol::property(&render_manager::max_update_rate); render_type["ui_target"] = sol::property(&render_manager::ui_target); render_type["ui_container"] = sol::property(&render_manager::ui_container); diff --git a/src/lib/util/bitmap.cpp b/src/lib/util/bitmap.cpp index 8757d928fff..5f4d2adfacb 100644 --- a/src/lib/util/bitmap.cpp +++ b/src/lib/util/bitmap.cpp @@ -36,7 +36,7 @@ inline int32_t bitmap_t::compute_rowpixels(int width, int xslop) inline void bitmap_t::compute_base(int xslop, int yslop) { - m_base = m_alloc.get() + (m_rowpixels * yslop + xslop) * (m_bpp / 8); + m_base = &m_alloc[(m_rowpixels * yslop + xslop) * (m_bpp / 8)]; } @@ -234,24 +234,28 @@ void bitmap_t::allocate(int width, int height, int xslop, int yslop) reset(); // handle empty requests cleanly - if (width <= 0 || height <= 0) - return; - - // initialize fields - m_rowpixels = compute_rowpixels(width, xslop); - m_width = width; - m_height = height; - m_cliprect.set(0, width - 1, 0, height - 1); - - // allocate memory for the bitmap itself - m_allocbytes = m_rowpixels * (m_height + 2 * yslop) * m_bpp / 8; - m_alloc.reset(new uint8_t[m_allocbytes]); - - // clear to 0 by default - memset(m_alloc.get(), 0, m_allocbytes); - - // compute the base - compute_base(xslop, yslop); + if ((0 < width) && (0 < height)) + { + // allocate memory for the bitmap itself + int32_t const new_rowpixels = compute_rowpixels(width, xslop); + uint32_t const new_allocbytes = new_rowpixels * (height + 2 * yslop) * m_bpp / 8; + m_alloc.reset(new (std::nothrow) uint8_t[new_allocbytes]); + if (m_alloc) + { + // initialize fields + m_allocbytes = new_allocbytes; + m_rowpixels = new_rowpixels; + m_width = width; + m_height = height; + m_cliprect.set(0, width - 1, 0, height - 1); + + // clear to 0 by default + memset(m_alloc.get(), 0, m_allocbytes); + + // compute the base + compute_base(xslop, yslop); + } + } } /** @@ -274,12 +278,12 @@ void bitmap_t::resize(int width, int height, int xslop, int yslop) assert(m_bpp == 8 || m_bpp == 16 || m_bpp == 32 || m_bpp == 64); // handle empty requests cleanly - if (width <= 0 || height <= 0) + if ((width <= 0) || (height <= 0)) width = height = 0; // determine how much memory we need for the new bitmap - int new_rowpixels = compute_rowpixels(width, xslop); - uint32_t new_allocbytes = new_rowpixels * (height + 2 * yslop) * m_bpp / 8; + int32_t const new_rowpixels = compute_rowpixels(width, xslop); + uint32_t const new_allocbytes = new_rowpixels * (height + 2 * yslop) * m_bpp / 8; if (new_allocbytes > m_allocbytes) { @@ -290,7 +294,6 @@ void bitmap_t::resize(int width, int height, int xslop, int yslop) } else { - // otherwise, reconfigure m_rowpixels = new_rowpixels; m_width = width; @@ -318,6 +321,7 @@ void bitmap_t::reset() m_base = nullptr; // reset all fields + m_allocbytes = 0; m_rowpixels = 0; m_width = 0; m_height = 0; @@ -339,6 +343,9 @@ void bitmap_t::reset() void bitmap_t::wrap(void *base, int width, int height, int rowpixels) { + assert(base || (!width && !height)); + assert(!m_alloc || (&m_alloc[0] > base) || (&m_alloc[m_allocbytes] <= base)); + // delete any existing stuff reset(); @@ -364,6 +371,7 @@ void bitmap_t::wrap(void *base, int width, int height, int rowpixels) void bitmap_t::wrap(bitmap_t &source, const rectangle &subrect) { + assert(&source != this); assert(m_format == source.m_format); assert(m_bpp == source.m_bpp); assert(source.cliprect().contains(subrect)); |