diff options
40 files changed, 1635 insertions, 1159 deletions
diff --git a/docs/source/techspecs/luaengine.rst b/docs/source/techspecs/luaengine.rst index 22981fe79e6..68790f108ae 100644 --- a/docs/source/techspecs/luaengine.rst +++ b/docs/source/techspecs/luaengine.rst @@ -129,7 +129,7 @@ is tagged as ``:screen``, and we can further inspect it: [MAME]> -- keep a reference to the main screen in a variable [MAME]> s = manager:machine().screens[":screen"] - [MAME]> print(s:width() .. "x" .. s:height()) + [MAME]> print(s.width .. "x" .. s.height) 320x224 We have several methods to draw a HUD on the screen composed of lines, boxes and @@ -139,11 +139,11 @@ text: [MAME]> -- we define a HUD-drawing function, and then call it [MAME]> function draw_hud() - [MAME]>> s:draw_text(40, 40, "foo"); -- (x0, y0, msg) - [MAME]>> s:draw_box(20, 20, 80, 80, 0, 0xff00ffff); -- (x0, y0, x1, y1, fill-color, line-color) - [MAME]>> s:draw_line(20, 20, 80, 80, 0xff00ffff); -- (x0, y0, x1, y1, line-color) + [MAME]>> s:draw_text(40, 40, "foo") -- (x0, y0, msg) + [MAME]>> s:draw_box(20, 20, 80, 80, 0xff00ffff, 0) -- (x0, y0, x1, y1, line-color, fill-color) + [MAME]>> s:draw_line(20, 20, 80, 80, 0xff00ffff) -- (x0, y0, x1, y1, line-color) [MAME]>> end - [MAME]> draw_hud(); + [MAME]> draw_hud() This will draw some useless art on the screen. However, when resuming the game, your HUD needs to be refreshed otherwise it will just disappear. In order to do diff --git a/docs/source/techspecs/luareference.rst b/docs/source/techspecs/luareference.rst index c61939daf0b..cd3f6af4b73 100644 --- a/docs/source/techspecs/luareference.rst +++ b/docs/source/techspecs/luareference.rst @@ -58,6 +58,603 @@ c:index_of(v) value. +.. _luareference-dev: + +Devices +------- + +Several device classes and device mix-ins classes are exposed to Lua. Devices +can be looked up by tag or enumerated. + +.. _luareference-dev-enum: + +Device enumerators +~~~~~~~~~~~~~~~~~~ + +Device enumerators are special containers that allow iterating over devices and +looking up devices by tag. A device enumerator can be created to find any kind +of device, to find devices of a particular type, or to find devices that +implement a particular interface. When iterating using ``pairs`` or ``ipairs``, +devices are returned by walking the device tree depth-first in creation order. + +The index get operator looks up a device by tag. It returns ``nil`` no device +with the specified tag is found, or if the device with the specified tag does +not meet the type/interface requirements of the device enumerator. The +complexity is O(1) if the result is cached, but an uncached device lookup is +expensive. The ``at`` method has O(n) complexity. + +If you create a device enumerator with a starting point other than the root +machine device, passing an absolute tag or a tag containing parent references to +the index operator may return a device that would not be discovered by +iteration. If you create a device enumerator with restricted depth, devices +that would not be found due to being too deep in the hierarchy can still be +looked up by tag. + +Creating a device enumerator with depth restricted to zero can be used to +downcast a device or test whether a device implements a certain interface. For +example this will test whether a device implements the media image interface: + +.. code-block:: Lua + + image_intf = emu.image_enumerator(device, 0):at(1) + if image_intf then + print(string.format("Device %s mounts images", device.tag)) + end + +Instantiation +^^^^^^^^^^^^^ + +manager:machine().devices + Returns a device enumerator that will iterate over + :ref:`devices <luareference-dev-device>` in the system. +manager:machine().screens + Returns a device enumerator that will iterate over + :ref:`screen devices <luareference-dev-screen>` in the system. +manager:machine().cassettes + Returns a device enumerator that will iterate over + :ref:`cassette devices <luareference-dev-cass>` in the system. +manager:machine().images + Returns a device enumerator that will iterate over + :ref:`media image devices <luareference-dev-diimage>` in the system. +manager:machine().slots + Returns a device enumerator that will iterate over + :ref:`slot devices <luareference-dev-dislot>` in the system. +emu.device_enumerator(device, [depth]) + Returns a device enumerator that will iterate over + :ref:`devices <luareference-dev-device>` in the sub-tree starting at the + specified device. The specified device will be included. If the depth is + provided, it must be an integer specifying the maximum number of levels to + iterate below the specified device (i.e. 1 will limit iteration to the + device and its immediate children). +emu.screen_enumerator(device, [depth]) + Returns a device enumerator that will iterate over + :ref:`screen devices <luareference-dev-screen>` in the sub-tree starting at + the specified device. The specified device will be included if it is a + screen device. If the depth is provided, it must be an integer specifying + the maximum number of levels to iterate below the specified device (i.e. 1 + will limit iteration to the device and its immediate children). +emu.cassette_enumerator(device, [depth]) + Returns a device enumerator that will iterate over + :ref:`cassette devices <luareference-dev-cass>` in the sub-tree starting at + the specified device. The specified device will be included if it is a + cassette device. If the depth is provided, it must be an integer specifying + the maximum number of levels to iterate below the specified device (i.e. 1 + will limit iteration to the device and its immediate children). +emu.image_enumerator(device, [depth]) + Returns a device enumerator that will iterate over + :ref:`media image devices <luareference-dev-diimage>` in the sub-tree + starting at the specified device. The specified device will be included if + it is a media image device. If the depth is provided, it must be an integer + specifying the maximum number of levels to iterate below the specified + device (i.e. 1 will limit iteration to the device and its immediate + children). +emu.slot_enumerator(device, [depth]) + Returns a device enumerator that will iterate over + :ref:`slot devices <luareference-dev-dislot>` in the sub-tree starting at + the specified device. The specified device will be included if it is a + slot device. If the depth is provided, it must be an integer specifying the + maximum number of levels to iterate below the specified device (i.e. 1 will + limit iteration to the device and its immediate children). + +.. _luareference-dev-device: + +Device +~~~~~~ + +Wraps MAME’s ``device_t`` class, which is a base of all device classes. + +Instantiation +^^^^^^^^^^^^^ + +manager:machine().devices[tag] + Gets a device by tag relative to the root machine device, or ``nil`` if no + such device exists. +manager:machine().devices[tag]:subdevice(tag) + Gets a device by tag relative to another arbitrary device, or ``nil`` if no + such device exists. + +Methods +^^^^^^^ + +device:subtag(tag) + Converts a tag relative to the device to an absolute tag. +device:siblingtag(tag) + Converts a tag relative to the device’s parent device to an absolute tag. +device:memshare(tag) + Gets a :ref:`memory share <luareference-mem-share>` by tag relative to the + device, or ``nil`` if no such memory share exists. +device:membank(tag) + Gets a :ref:`memory bank <luareference-mem-bank>` by tag relative to the + device, or ``nil`` if no such memory bank exists. +device:memregion(tag) + Gets a :ref:`memory region <luareference-mem-region>` by tag relative to the + device, or ``nil`` if no such memory region exists. +device:ioport(tag) + Gets an :ref:`I/O port <luareference-input-ioport>` by tag relative to the + device, or ``nil`` if no such I/O port exists. +device:subdevice(tag) + Gets a device by tag relative to the device. +device:siblingdevice(tag) + Gets a device by tag relative to the device’s parent. + +Properties +^^^^^^^^^^ + +device.tag (read-only) + The device’s absolute tag in canonical form. +device.basetag (read-only) + The last component of the device’s tag (i.e. its tag relative to its + immediate parent), or ``"root"`` for the root machine device. +device.name (read-only) + The full display name for the device’s type. +device.shortname (read-only) + The short name of the devices type (this is used, e.g. on the command line, + when looking for resource like ROMs or artwork, and in various data files). +device.owner (read-only) + The device’s immediate parent in the device tree, or ``nil`` for the root + machine device. +device.configured (read-only) + A Boolean indicating whether the device has completed configuration. +device.started (read-only) + A Boolean indicating whether the device has completed starting. +device.debug (read-only) + The :ref:`debugger interface <luareference-debug-devdebug>` to the device if + it is a CPU device, or ``nil`` if it is not a CPU device or the debugger is + not enabled. +device.spaces[] (read-only) + A table of the device’s :ref:`address spaces <luareference-mem-space>`, + indexed by name. Only valid for devices that implement the memory + interface. Note that the names are specific to the device type and have no + special significance. + +.. _luareference-dev-screen: + +Screen device +~~~~~~~~~~~~~ + +Wraps MAME’s ``screen_device`` class, which represents an emulated video output. + +Instantiation +^^^^^^^^^^^^^ + +manager:machine().screens[tag] + Gets a screen device by tag relative to the root machine device, or ``nil`` + if no such device exists or it is not a screen device. + +Base classes +^^^^^^^^^^^^ + +* :ref:`luareference-dev-device` + +Methods +^^^^^^^ + +screen:orientation() + Returns the rotation angle in degrees (will be one of 0, 90, 180 or 270), + whether the screen is flipped left-to-right, and whether the screen is + flipped top-to-bottom. +screen:time_until_pos(v, [h]) + Gets the time remaining until the raster reaches the specified position. If + the horizontal component of the position is not specified, it defaults to + zero (0, i.e. the beginning of the line). The result is a floating-point + number in units of seconds. +screen:time_until_vblank_start() + Gets the time remaining until the start of the vertical blanking interval. + The result is a floating-point number in units of seconds. +screen:time_until_vblank_end() + Gets the time remaining until the end of the vertical blanking interval. + The result is a floating-point number in units of seconds. +screen:snapshot([filename]) + Saves a screen snapshot in PNG format. If no filename is supplied, the + configured snapshot path and name format will be used. If the supplied + filename is not an absolute path, it is interpreted relative to the first + configured snapshot path. The filename may contain conversion specifiers + that will be replaced by the system name or an incrementing number. + + Returns a file error if opening the snapshot file failed, or ``nil`` + otherwise. +screen:pixel(x, y) + Gets the pixel at the specified location. Coordinates are in pixels, with + the origin at the top left corner of the visible area, increasing to the + right and down. Returns either a palette index or a colour in RGB format + packed into a 32-bit integer. Returns zero (0) if the specified point is + outside the visible area. +screen:pixels() + Returns all visible pixels as 32-bit integers packed into a binary string in + host Endian order. Pixels are organised in row-major order, from left to + right then top to bottom. Pixels values are either palette indices or + colours in RGB format packed into 32-bit integers. +screen:draw_box(left, top, right, bottom, [line], [fill]) + Draws an outlined rectangle with edges at the specified positions. + + Coordinates are floating-point numbers in units of screen pixels, with the + origin at (0, 0). Note that screen pixels often aren’t square. The + coordinate system is rotated if the screen is rotated, which is usually the + case for vertical-format screens. Before rotation, the origin is at the top + left, and coordinates increase to the right and downwards. Coordinates are + limited to the screen area. + + The fill and line colours are in alpha/red/green/blue (ARGB) format. + Channel values are in the range 0 (transparent or off) to 255 (opaque or + full intensity), inclusive. Colour channel values are not pre-multiplied by + the alpha value. The channel values must be packed into the bytes of a + 32-bit unsigned integer, in the order alpha, red, green, blue from + most-significant to least-significant byte. If the line colour is not + provided, the UI text colour is used; if the fill colour is not provided, + the UI background colour is used. +screen:draw_line(x1, y1, x2, y2, bottom, [color]) + Draws a line from (x1, y1) to (x2, y2). + + Coordinates are floating-point numbers in units of screen pixels, with the + origin at (0, 0). Note that screen pixels often aren’t square. The + coordinate system is rotated if the screen is rotated, which is usually the + case for vertical-format screens. Before rotation, the origin is at the top + left, and coordinates increase to the right and downwards. Coordinates are + limited to the screen area. + + The line colour is in alpha/red/green/blue (ARGB) format. Channel values + are in the range 0 (transparent or off) to 255 (opaque or full intensity), + inclusive. Colour channel values are not pre-multiplied by the alpha value. + The channel values must be packed into the bytes of a 32-bit unsigned + integer, in the order alpha, red, green, blue from most-significant to + least-significant byte. If the line colour is not provided, the UI text + colour is used. +screen:draw_text(x|justify, y, text, [foreground], [background]) + Draws text at the specified position. If the screen is rotated the text + will be rotated. + + If the first argument is a number, the text will be left-aligned at this X + coordinate. If the first argument is a string, it must be ``"left"``, + ``"center"`` or ``"right"`` to draw the text left-aligned at the + left edge of the screen, horizontally centred on the screen, or + right-aligned at the right edge of the screen, respectively. The second + argument specifies the Y coordinate of the maximum ascent of the text. + + Coordinates are floating-point numbers in units of screen pixels, with the + origin at (0, 0). Note that screen pixels often aren’t square. The + coordinate system is rotated if the screen is rotated, which is usually the + case for vertical-format screens. Before rotation, the origin is at the top + left, and coordinates increase to the right and downwards. Coordinates are + limited to the screen area. + + The foreground and background colours is in alpha/red/green/blue (ARGB) + format. Channel values are in the range 0 (transparent or off) to 255 (opaque or full intensity), + inclusive. Colour channel values are not pre-multiplied by the alpha value. + The channel values must be packed into the bytes of a 32-bit unsigned + integer, in the order alpha, red, green, blue from most-significant to + least-significant byte. If the foreground colour is not provided, the UI + text colour is used; if the background colour is not provided, the UI + background colour is used. + +Properties +^^^^^^^^^^ + +screen.width (read-only) + The width of the bitmap produced by the emulated screen in pixels. +screen.height (read-only) + The height of the bitmap produced by the emulated screen in pixels. +screen.refresh (read-only) + The screen’s configured refresh rate in Hertz (this may not reflect the + current value). +screen.refresh_attoseconds (read-only) + The screen’s configured refresh interval in attoseconds (this may not + reflect the current value). +screen.xoffset (read-only) + The screen’s default X position offset. This is a floating-point number + where one (1) corresponds to the X size of the screen’s container. This may + be useful for restoring the default after adjusting the X offset via the + screen’s container. +screen.yoffset (read-only) + The screen’s default Y position offset. This is a floating-point number + where one (1) corresponds to the Y size of the screen’s container. This may + be useful for restoring the default after adjusting the Y offset via the + screen’s container. +screen.xscale (read-only) + The screen’s default X scale factor, as a floating-point number. This may + be useful for restoring the default after adjusting the X scale via the + screen’s container. +screen.yscale (read-only) + The screen’s default Y scale factor, as a floating-point number. This may + be useful for restoring the default after adjusting the Y scale via the + screen’s container. +screen.pixel_period (read-only) + The interval taken to draw a horizontal pixel, as a floating-point number in + units of seconds. +screen.scan_period (read-only) + The interval taken to draw a scan line (including the horizontal blanking + interval), as a floating-point number in units of seconds. +screen.pixel_period (read-only) + The interval taken to draw a complete frame (including blanking intervals), + as a floating-point number in units of seconds. +screen.frame_number (read-only) + The current frame number for the screen. This increments monotonically each + frame interval. +screen.container (read-only) + The :ref:`render container <luareference-render-container>` used to draw the + screen. + +.. _luareference-dev-cass: + +Cassette image device +~~~~~~~~~~~~~~~~~~~~~ + +Wraps MAME’s ``cassette_image_device`` class, representing a compact cassette +mechanism typically used by a home computer for program storage. + +Instantiation +^^^^^^^^^^^^^ + +manager:machine().cassettes[tag] + Gets a cassette image device by tag relative to the root machine device, or + ``nil`` if no such device exists or it is not a cassette image device. + +Base classes +^^^^^^^^^^^^ + +* :ref:`luareference-dev-device` +* :ref:`luareference-dev-diimage` + +Methods +^^^^^^^ + +cassette:stop() + Disables playback. +cassette:play() + Enables playback. The cassette will play if the motor is enabled. +cassette:forward() + Sets forward play direction. +cassette:reverse() + Sets reverse play direction. +cassette:seek(time, whence) + Jump to the specified position on the tape. The time is a floating-point + number in units of seconds, relative to the point specified by the whence + argument. The whence argument must be one of ``"set"``, ``"cur"`` or + ``"end"`` to seek relative to the start of the tape, the current position, + or the end of the tape, respectively. + +Properties +^^^^^^^^^^ + +cassette.is_stopped (read-only) + A Boolean indicating whether the cassette is stopped (i.e. not recording and + not playing). +cassette.is_playing (read-only) + A Boolean indicating whether playback is enabled (i.e. the cassette will + play if the motor is enabled). +cassette.is_recording (read-only) + A Boolean indicating whether recording is enabled (i.e. the cassette will + record if the motor is enabled). +cassette.motor_state (read/write) + A Boolean indicating whether the cassette motor is enabled. +cassette.speaker_state (read/write) + A Boolean indicating whether the cassette speaker is enabled. +cassette.position (read-only) + The current position as a floating-point number in units of seconds relative + to the start of the tape. +cassette.length (read-only) + The length of the tape as a floating-point number in units of seconds, or + zero (0) if no tape image is mounted. + +.. _luareference-dev-diimage: + +Image device interface +~~~~~~~~~~~~~~~~~~~~~~ + +Wraps MAME’s ``device_image_interface`` class which is a mix-in implemented by +devices that can load media image files. + +Instantiation +^^^^^^^^^^^^^ + +manager:machine().images[tag] + Gets an image device by tag relative to the root machine device, or ``nil`` + if no such device exists or it is not a media image device. + +Methods +^^^^^^^ + +image:load(filename) + Loads the specified file as a media image. Returns ``"pass"`` or + ``"fail"``. +image:load_software(name) + Loads a media image described in a software list. Returns ``"pass"`` or + ``"fail"``. +image:unload() + Unloads the mounted image. +image:create(filename) + Creates and mounts a media image file with the specified name. Returns + ``"pass"`` or ``"fail"``. +image:display() + Returns a “front panel display” string for the device, if supported. This + can be used to show status information, like the current head position or + motor state. + +Properties +^^^^^^^^^^ + +image.is_readable (read-only) + A Boolean indicating whether the device supports reading. +image.is_writeable (read-only) + A Boolean indicating whether the device supports writing. +image.must_be_loaded (read-only) + A Boolean indicating whether the device requires a media image to be loaded + in order to start. +image.is_reset_on_load (read-only) + A Boolean indicating whether the device requires a hard reset to change + media images (usually for cartridge slots that contain hardware in addition + to memory chips). +image.image_type_name (read-only) + A string for categorising the media device. +image.instance_name (read-only) + The instance name of the device in the current configuration. This is used + for setting the media image to load on the command line or in INI files. + This is not stable, it may have a number appended that may change depending + on slot configuration. +image.brief_instance_name (read-only) + The brief instance name of the device in the current configuration. This is + used for setting the media image to load on the command line or in INI + files. This is not stable, it may have a number appended that may change + depending on slot configuration. +image.formatlist[] (read-only) + The :ref:`media image formats <luareference-dev-imagefmt>` supported by the + device, indexed by name. The index operator and ``index_of`` methods have + O(n) complexity; all other supported operations have O(1) complexity. +image.exists (read-only) + A Boolean indicating whether a media image file is mounted. +image.readonly (read-only) + A Boolean indicating whether a media image file is mounted in read-only + mode. +image.filename (read-only) + The full path to the mounted media image file, or ``nil`` if no media image + is mounted. +image.crc (read-only) + The 32-bit cyclic redundancy check of the content of the mounted image file + if the mounted media image was not loaded from a software list, is mounted + read-only and is not a CD-ROM, or zero (0) otherwise. +image.loaded_through_softlist (read-only) + A Boolean indicating whether the mounted media image was loaded from a + software list, or ``false`` if no media image is mounted. +image.software_list_name (read-only) + The short name of the software list if the mounted media image was loaded + from a software list. +image.software_longname (read-only) + The full name of the software item if the mounted media image was loaded + from a software list, or ``nil`` otherwise. +image.software_publisher (read-only) + The publisher of the software item if the mounted media image was loaded + from a software list, or ``nil`` otherwise. +image.software_year (read-only) + The release year of the software item if the mounted media image was loaded + from a software list, or ``nil`` otherwise. +image.software_parent (read-only) + The short name of the parent software item if the mounted media image was + loaded from a software list, or ``nil`` otherwise. +image.device (read-only) + The underlying :ref:`device <luareference-dev-device>`. + +.. _luareference-dev-dislot: + +Slot device interface +~~~~~~~~~~~~~~~~~~~~~ + +Wraps MAME’s ``device_slot_interface`` class which is a mix-in implemented by +devices that instantiate a user-specified child device. + +Instantiation +^^^^^^^^^^^^^ + +manager:machine().slots[tag] + Gets an slot device by tag relative to the root machine device, or ``nil`` + if no such device exists or it is not a slot device. + +Properties +^^^^^^^^^^ + +slot.fixed (read-only) + A Boolean indicating whether this is a slot with a card specified in machine + configuration that cannot be changed by the user. +slot.has_selectable_options (read-only) + A Boolean indicating whether the slot has any user-selectable options (as + opposed to options that can only be selected programmatically, typically for + fixed slots or to load media images). +slot.options[] (read-only) + The :ref:`slot options <luareference-dev-slotopt>` describing the child + devices that can be instantiated by the slot, indexed by option value. The + ``at`` and ``index_of`` methods have O(n) complexity; all other supported + operations have O(1) complexity. +slot.device (read-only) + The underlying :ref:`device <luareference-dev-device>`. + +.. _luareference-dev-imagefmt: + +Media image format +~~~~~~~~~~~~~~~~~~ + +Wraps MAME’s ``image_device_format`` class, which describes a media file format +supported by a :ref:`media image device <luareference-dev-diimage>`. + +Instantiation +^^^^^^^^^^^^^ + +manager:machine().images[tag].formatlist[name] + Gets a media image format supported by a given device by name. + +Properties +^^^^^^^^^^ + +format.name (read-only) + An abbreviated name used to identify the format. This often matches the + primary filename extension used for the format. +format.description (read-only) + The full display name of the format. +format.extensions[] (read-only) + Yields a table of filename extensions used for the format. +format.option_spec (read-only) + A string describing options available when creating a media image using this + format. The string is not intended to be human-readable. + +.. _luareference-dev-slotopt: + +Slot option +~~~~~~~~~~~ + +Wraps MAME’s ``device_slot_interface::slot_option`` class, which represents a +child device that a :ref:`slot device <luareference-dev-dislot>` slot device can +be configured to instantiate. + +Instantiation +^^^^^^^^^^^^^ + +manager:machine().slots[tag].options[name] + Gets a slot option for a given :ref:`slot device <luareference-dev-dislot>` + by name (i.e. the value used to select the option). + +Properties +^^^^^^^^^^ + +option.name (read-only) + The name of the slot option. This is the value used to select this option + on the command line or in an INI file. +option.device_fullname (read-only) + The full display name of the device type instantiated by this option. +option.device_shortname (read-only) + The short name of the device type instantiated by this option. +option.selectable (read-only) + A Boolean indicating whether the option may be selected by the user (options + that are not user-selectable are typically used for fixed slots or to load + media images). +option.default_bios (read-only) + The default BIOS setting for the device instantiated using this option, or + ``nil`` if the default BIOS specified in the device’s ROM definitions will + be used. +option.clock (read-only) + The configured clock frequency for the device instantiated using this + option. This is an unsigned 32-bit integer. If the eight most-significant + bits are all set, it is a ratio of the parent device’s clock frequency, with + the numerator in bits 12-23 and the denominator in bits 0-11. If the eight + most-significant bits are not all set, it is a frequency in Hertz. + + .. _luareference-mem: Memory system @@ -172,7 +769,7 @@ Properties space.name (read-only) The display name for the address space. space.shift (read-only) - The address address granularity for the address space specified as the shift + The address granularity for the address space specified as the shift required to translate a byte address to a native address. Positive values shift towards the most significant bit (left) and negative values shift towards the least significant bit (right). @@ -243,7 +840,7 @@ entry.address_end (read-only) End address of the entry’s range (inclusive). entry.address_mirror (read-only) Address mirror bits. -entry.address_end (read-only) +entry.address_mask (read-only) Address mask bits. Only valid for handlers. entry.mask (read-only) Lane mask, indicating which data lines on the bus are connected to the @@ -258,8 +855,9 @@ entry.write (read-only) handler. entry.share (read-only) Memory share tag for making RAM entries accessible or ``nil``. -entry.address_end (read-only) - Explicit memory region tag for ROM entries, or ``nil``. +entry.region (read-only) + Explicit memory region tag for ROM entries, or ``nil``. For ROM entries, + ``nil`` infers the region from the device tag. entry.region_offset (read-only) Starting offset in memory region for ROM entries. @@ -1545,7 +2143,7 @@ item.bounds (read-only) coordinates. item.color (read-only) The item’s colour for the current state. The colour of the screen or - element texture is multiplied by this colour. This is a + element texture is multiplied by this colour. This is a :ref:`render colour <luareference-render-color>` object. item.blend_mode (read-only) Get the item’s blend mode. This is an integer value, where 0 means no diff --git a/plugins/cheat/init.lua b/plugins/cheat/init.lua index 2acb377192f..83dbdc7bfb1 100644 --- a/plugins/cheat/init.lua +++ b/plugins/cheat/init.lua @@ -295,7 +295,7 @@ function cheat.startplugin() error("bpset not permitted in oneshot cheat") return end - local idx = dev:debug():bpset(addr) + local idx = dev.debug:bpset(addr) breaks[idx] = {cheat = cheat, func = func, dev = dev} end @@ -308,7 +308,7 @@ function cheat.startplugin() error("bad space in wpset") return end - local idx = dev.debug():wpset(space, wptype, addr, len) + local idx = dev.debug:wpset(space, wptype, addr, len) watches[idx] = {cheat = cheat, func = func, dev = dev} end @@ -318,12 +318,12 @@ function cheat.startplugin() end for num, bp in pairs(breaks) do if cheat == bp.cheat then - bp.dev.debug():bpclr(num) + bp.dev.debug:bpclr(num) end end for num, wp in pairs(watches) do if cheat == wp.cheat then - wp.dev.debug():wpclr(num) + wp.dev.debug:wpclr(num) end end end @@ -485,7 +485,7 @@ function cheat.startplugin() for name, tag in pairs(cheat.cpu) do if manager:machine():debugger() then local dev = manager:machine().devices[tag] - if not dev or not dev:debug() then + if not dev or not dev.debug then cheat_error(cheat, "missing or invalid device " .. tag) return end @@ -895,7 +895,7 @@ function cheat.startplugin() elseif draw.type == "line" then draw.scr:draw_line(draw.x1, draw.y1, draw.x2, draw.y2, draw.color) elseif draw.type == "box" then - draw.scr:draw_box(draw.x1, draw.y1, draw.x2, draw.y2, draw.bgcolor, draw.linecolor) + draw.scr:draw_box(draw.x1, draw.y1, draw.x2, draw.y2, draw.linecolor, draw.bgcolor) end end output = {} diff --git a/plugins/gdbstub/init.lua b/plugins/gdbstub/init.lua index e850e62ae5b..afc5428dd22 100644 --- a/plugins/gdbstub/init.lua +++ b/plugins/gdbstub/init.lua @@ -195,7 +195,7 @@ function gdbstub.startplugin() end elseif cmd == "s" then if #packet == 1 then - cpu:debug():step() + cpu.debug:step() socket:write("+$OK#9a") socket:write("$S05#B8") running = false @@ -204,7 +204,7 @@ function gdbstub.startplugin() end elseif cmd == "c" then if #packet == 1 then - cpu:debug():go() + cpu.debug:go() socket:write("+$OK#9a") else socket:write("+$E00#a5") @@ -219,7 +219,7 @@ function gdbstub.startplugin() socket:write("+$E00#a5") return end - local idx = cpu:debug():bpset(addr) + local idx = cpu.debug:bpset(addr) breaks.byaddr[addr] = idx breaks.byidx[idx] = addr socket:write("+$OK#9a") @@ -228,7 +228,7 @@ function gdbstub.startplugin() socket:write("+$E00#a5") return end - local idx = cpu:debug():wpset(cpu.spaces["program"], "w", addr, 1) + local idx = cpu.debug:wpset(cpu.spaces["program"], "w", addr, 1) watches.byaddr[addr] = idx watches.byidx[idx] = {addr = addr, type = "watch"} socket:write("+$OK#9a") @@ -237,7 +237,7 @@ function gdbstub.startplugin() socket:write("+$E00#a5") return end - local idx = cpu:debug():wpset(cpu.spaces["program"], "r", addr, 1) + local idx = cpu.debug:wpset(cpu.spaces["program"], "r", addr, 1) watches.byaddr[addr] = idx watches.byidx[idx] = {addr = addr, type = "rwatch"} socket:write("+$OK#9a") @@ -246,7 +246,7 @@ function gdbstub.startplugin() socket:write("+$E00#a5") return end - local idx = cpu:debug():wpset(cpu.spaces["program"], "rw", addr, 1) + local idx = cpu.debug:wpset(cpu.spaces["program"], "rw", addr, 1) watches.byaddr[addr] = idx watches.byidx[idx] = {addr = addr, type = "awatch"} socket:write("+$OK#9a") @@ -262,7 +262,7 @@ function gdbstub.startplugin() return end local idx = breaks.byaddr[addr] - cpu:debug():bpclr(idx) + cpu.debug:bpclr(idx) breaks.byaddr[addr] = nil breaks.byidx[idx] = nil socket:write("+$OK#9a") @@ -272,7 +272,7 @@ function gdbstub.startplugin() return end local idx = watches.byaddr[addr] - cpu:debug():wpclr(idx) + cpu.debug:wpclr(idx) watches.byaddr[addr] = nil watches.byidx[idx] = nil socket:write("+$OK#9a") diff --git a/src/devices/cpu/arm7/arm7.h b/src/devices/cpu/arm7/arm7.h index 80757afe13b..b303d515a8c 100644 --- a/src/devices/cpu/arm7/arm7.h +++ b/src/devices/cpu/arm7/arm7.h @@ -368,17 +368,17 @@ protected: /* fast RAM info */ struct fast_ram_info { - offs_t start; /* start of the RAM block */ - offs_t end; /* end of the RAM block */ - bool readonly; /* true if read-only */ - void * base; /* base in memory where the RAM lives */ + offs_t start = 0; /* start of the RAM block */ + offs_t end = 0; /* end of the RAM block */ + bool readonly = false; /* true if read-only */ + void * base = nullptr; /* base in memory where the RAM lives */ }; struct hotspot_info { - uint32_t pc; - uint32_t opcode; - uint32_t cycles; + uint32_t pc = 0; + uint32_t opcode = 0; + uint32_t cycles = 0; }; /* internal compiler state */ @@ -386,9 +386,9 @@ protected: { compiler_state &operator=(compiler_state const &) = delete; - uint32_t cycles; /* accumulated cycles */ - uint8_t checkints; /* need to check interrupts before next instruction */ - uint8_t checksoftints; /* need to check software interrupts before next instruction */ + uint32_t cycles = 0; /* accumulated cycles */ + uint8_t checkints = 0; /* need to check interrupts before next instruction */ + uint8_t checksoftints = 0; /* need to check software interrupts before next instruction */ uml::code_label labelnum; /* index for local labels */ }; @@ -396,45 +396,45 @@ protected: struct arm7imp_state { /* core state */ - drc_cache * cache; /* pointer to the DRC code cache */ - drcuml_state * drcuml; /* DRC UML generator state */ - //arm7_frontend * drcfe; /* pointer to the DRC front-end state */ - uint32_t drcoptions; /* configurable DRC options */ + std::unique_ptr<drc_cache> cache; /* pointer to the DRC code cache */ + std::unique_ptr<drcuml_state> drcuml; /* DRC UML generator state */ + //arm7_frontend * drcfe = nullptr; /* pointer to the DRC front-end state */ + uint32_t drcoptions = 0; /* configurable DRC options */ /* internal stuff */ - uint8_t cache_dirty; /* true if we need to flush the cache */ - uint32_t jmpdest; /* destination jump target */ + uint8_t cache_dirty = 0; /* true if we need to flush the cache */ + uint32_t jmpdest = 0; /* destination jump target */ /* parameters for subroutines */ - uint64_t numcycles; /* return value from gettotalcycles */ - uint32_t mode; /* current global mode */ - const char * format; /* format string for print_debug */ - uint32_t arg0; /* print_debug argument 1 */ - uint32_t arg1; /* print_debug argument 2 */ + uint64_t numcycles = 0; /* return value from gettotalcycles */ + uint32_t mode = 0; /* current global mode */ + const char * format = nullptr; /* format string for print_debug */ + uint32_t arg0 = 0; /* print_debug argument 1 */ + uint32_t arg1 = 0; /* print_debug argument 2 */ /* register mappings */ - uml::parameter regmap[/*NUM_REGS*/37]; /* parameter to register mappings for all 16 integer registers */ + uml::parameter regmap[/*NUM_REGS*/37]; /* parameter to register mappings for all 16 integer registers */ /* subroutines */ - uml::code_handle * entry; /* entry point */ - uml::code_handle * nocode; /* nocode exception handler */ - uml::code_handle * out_of_cycles; /* out of cycles exception handler */ - uml::code_handle * tlb_translate; /* tlb translation handler */ - uml::code_handle * detect_fault; /* tlb fault detection handler */ - uml::code_handle * check_irq; /* irq check handler */ - uml::code_handle * read8; /* read byte */ - uml::code_handle * write8; /* write byte */ - uml::code_handle * read16; /* read half */ - uml::code_handle * write16; /* write half */ - uml::code_handle * read32; /* read word */ - uml::code_handle * write32; /* write word */ + uml::code_handle * entry = nullptr; /* entry point */ + uml::code_handle * nocode = nullptr; /* nocode exception handler */ + uml::code_handle * out_of_cycles = nullptr; /* out of cycles exception handler */ + uml::code_handle * tlb_translate = nullptr; /* tlb translation handler */ + uml::code_handle * detect_fault = nullptr; /* tlb fault detection handler */ + uml::code_handle * check_irq = nullptr; /* irq check handler */ + uml::code_handle * read8 = nullptr; /* read byte */ + uml::code_handle * write8 = nullptr; /* write byte */ + uml::code_handle * read16 = nullptr; /* read half */ + uml::code_handle * write16 = nullptr; /* write half */ + uml::code_handle * read32 = nullptr; /* read word */ + uml::code_handle * write32 = nullptr; /* write word */ /* fast RAM */ - uint32_t fastram_select; + uint32_t fastram_select = 0; fast_ram_info fastram[ARM7_MAX_FASTRAM]; /* hotspots */ - uint32_t hotspot_select; + uint32_t hotspot_select = 0; hotspot_info hotspot[ARM7_MAX_HOTSPOTS]; } m_impstate; diff --git a/src/devices/cpu/arm7/arm7drc.hxx b/src/devices/cpu/arm7/arm7drc.hxx index 621c0a7f0f8..8edd44438bd 100644 --- a/src/devices/cpu/arm7/arm7drc.hxx +++ b/src/devices/cpu/arm7/arm7drc.hxx @@ -127,21 +127,18 @@ void arm7_cpu_device::save_fast_iregs(drcuml_block &block) void arm7_cpu_device::arm7_drc_init() { - drc_cache *cache; drcbe_info beinfo; uint32_t flags = 0; /* allocate enough space for the cache and the core */ - cache = auto_alloc(machine(), drc_cache(CACHE_SIZE)); - if (cache == nullptr) - fatalerror("Unable to allocate cache of size %d\n", (uint32_t)(CACHE_SIZE)); /* allocate the implementation-specific state from the full cache */ - memset(&m_impstate, 0, sizeof(m_impstate)); - m_impstate.cache = cache; + m_impstate = arm7imp_state(); + try { m_impstate.cache = std::make_unique<drc_cache>(CACHE_SIZE); } + catch (std::bad_alloc const &) { throw emu_fatalerror("Unable to allocate cache of size %d\n", (uint32_t)(CACHE_SIZE)); } /* initialize the UML generator */ - m_impstate.drcuml = new drcuml_state(*this, *cache, flags, 1, 32, 1); + m_impstate.drcuml = std::make_unique<drcuml_state>(*this, *m_impstate.cache, flags, 1, 32, 1); /* add symbols for our stuff */ m_impstate.drcuml->symbol_add(&m_icount, sizeof(m_icount), "icount"); @@ -158,7 +155,7 @@ void arm7_cpu_device::arm7_drc_init() //m_impstate.drcuml->symbol_add(&m_impstate.fpmode, sizeof(m_impstate.fpmode), "fpmode"); // TODO /* initialize the front-end helper */ - //m_impstate.drcfe = auto_alloc(machine(), arm7_frontend(this, COMPILE_BACKWARDS_BYTES, COMPILE_FORWARDS_BYTES, SINGLE_INSTRUCTION_MODE ? 1 : COMPILE_MAX_SEQUENCE)); + //m_impstate.drcfe = std::make_unique<arm7_frontend>(this, COMPILE_BACKWARDS_BYTES, COMPILE_FORWARDS_BYTES, SINGLE_INSTRUCTION_MODE ? 1 : COMPILE_MAX_SEQUENCE); /* allocate memory for cache-local state and initialize it */ //memcpy(&m_impstate.fpmode, fpmode_source, sizeof(fpmode_source)); // TODO @@ -199,7 +196,7 @@ void arm7_cpu_device::arm7_drc_init() void arm7_cpu_device::execute_run_drc() { - drcuml_state *drcuml = m_impstate.drcuml; + drcuml_state &drcuml = *m_impstate.drcuml; int execute_result; /* reset the cache if dirty */ @@ -211,7 +208,7 @@ void arm7_cpu_device::execute_run_drc() do { /* run as much as we can */ - execute_result = drcuml->execute(*m_impstate.entry); + execute_result = drcuml.execute(*m_impstate.entry); /* if we need to recompile, do it */ if (execute_result == EXECUTE_MISSING_CODE) @@ -231,9 +228,9 @@ void arm7_cpu_device::execute_run_drc() void arm7_cpu_device::arm7_drc_exit() { /* clean up the DRC */ - //auto_free(machine(), m_impstate.drcfe); - delete m_impstate.drcuml; - auto_free(machine(), m_impstate.cache); + //m_impstate.drcfe.reset(); + m_impstate.drcuml.reset(); + m_impstate.cache.reset(); } @@ -328,7 +325,7 @@ void arm7_cpu_device::code_flush_cache() void arm7_cpu_device::code_compile_block(uint8_t mode, offs_t pc) { - drcuml_state *drcuml = m_impstate.drcuml; + drcuml_state &drcuml = *m_impstate.drcuml; compiler_state compiler = { 0 }; const opcode_desc *seqlast; bool override = false; @@ -338,7 +335,7 @@ void arm7_cpu_device::code_compile_block(uint8_t mode, offs_t pc) /* get a description of this sequence */ // TODO FIXME const opcode_desc *desclist = nullptr; //m_impstate.drcfe->describe_code(pc); // TODO -// if (drcuml->logging() || drcuml->logging_native()) +// if (drcuml.logging() || drcuml.logging_native()) // log_opcode_desc(drcuml, desclist, 0); /* if we get an error back, flush the cache and try again */ @@ -348,7 +345,7 @@ void arm7_cpu_device::code_compile_block(uint8_t mode, offs_t pc) try { /* start the block */ - drcuml_block &block(drcuml->begin_block(4096)); + drcuml_block &block(drcuml.begin_block(4096)); /* loop until we get through all instruction sequences */ for (const opcode_desc *seqhead = desclist; seqhead != nullptr; seqhead = seqlast->next()) @@ -357,7 +354,7 @@ void arm7_cpu_device::code_compile_block(uint8_t mode, offs_t pc) uint32_t nextpc; /* add a code log entry */ - if (drcuml->logging()) + if (drcuml.logging()) block.append_comment("-------------------------"); // comment /* determine the last instruction in this sequence */ @@ -367,7 +364,7 @@ void arm7_cpu_device::code_compile_block(uint8_t mode, offs_t pc) assert(seqlast != nullptr); /* if we don't have a hash for this mode/pc, or if we are overriding all, add one */ - if (override || !drcuml->hash_exists(mode, seqhead->pc)) + if (override || !drcuml.hash_exists(mode, seqhead->pc)) UML_HASH(block, mode, seqhead->pc); // hash mode,pc /* if we already have a hash, and this is the first sequence, assume that we */ @@ -470,17 +467,17 @@ void arm7_cpu_device::cfunc_unimplemented() void arm7_cpu_device::static_generate_entry_point() { - drcuml_state *drcuml = m_impstate.drcuml; + drcuml_state &drcuml = *m_impstate.drcuml; - drcuml_block &block(drcuml->begin_block(110)); + drcuml_block &block(drcuml.begin_block(110)); /* forward references */ - //alloc_handle(*drcuml, &m_impstate.exception_norecover[EXCEPTION_INTERRUPT], "interrupt_norecover"); - alloc_handle(*drcuml, m_impstate.nocode, "nocode"); - alloc_handle(*drcuml, m_impstate.detect_fault, "detect_fault"); - alloc_handle(*drcuml, m_impstate.tlb_translate, "tlb_translate"); + //alloc_handle(drcuml, &m_impstate.exception_norecover[EXCEPTION_INTERRUPT], "interrupt_norecover"); + alloc_handle(drcuml, m_impstate.nocode, "nocode"); + alloc_handle(drcuml, m_impstate.detect_fault, "detect_fault"); + alloc_handle(drcuml, m_impstate.tlb_translate, "tlb_translate"); - alloc_handle(*drcuml, m_impstate.entry, "entry"); + alloc_handle(drcuml, m_impstate.entry, "entry"); UML_HANDLE(block, *m_impstate.entry); // handle entry /* load fast integer registers */ @@ -501,7 +498,7 @@ void arm7_cpu_device::static_generate_entry_point() void arm7_cpu_device::static_generate_check_irq() { - drcuml_state *drcuml = m_impstate.drcuml; + drcuml_state &drcuml = *m_impstate.drcuml; uml::code_label noirq; int nodabt = 0; int nopabt = 0; @@ -513,10 +510,10 @@ void arm7_cpu_device::static_generate_check_irq() int label = 1; /* begin generating */ - drcuml_block &block(drcuml->begin_block(120)); + drcuml_block &block(drcuml.begin_block(120)); /* generate a hash jump via the current mode and PC */ - alloc_handle(*drcuml, m_impstate.check_irq, "check_irq"); + alloc_handle(drcuml, m_impstate.check_irq, "check_irq"); UML_HANDLE(block, *m_impstate.check_irq); // handle check_irq /* Exception priorities: @@ -669,13 +666,13 @@ void arm7_cpu_device::static_generate_check_irq() void arm7_cpu_device::static_generate_nocode_handler() { - drcuml_state *drcuml = m_impstate.drcuml; + drcuml_state &drcuml = *m_impstate.drcuml; /* begin generating */ - drcuml_block &block(drcuml->begin_block(10)); + drcuml_block &block(drcuml.begin_block(10)); /* generate a hash jump via the current mode and PC */ - alloc_handle(*drcuml, m_impstate.nocode, "nocode"); + alloc_handle(drcuml, m_impstate.nocode, "nocode"); UML_HANDLE(block, *m_impstate.nocode); // handle nocode UML_GETEXP(block, uml::I0); // getexp i0 UML_MOV(block, uml::mem(&R15), uml::I0); // mov [pc],i0 @@ -693,13 +690,13 @@ void arm7_cpu_device::static_generate_nocode_handler() void arm7_cpu_device::static_generate_out_of_cycles() { - drcuml_state *drcuml = m_impstate.drcuml; + drcuml_state &drcuml = *m_impstate.drcuml; /* begin generating */ - drcuml_block &block(drcuml->begin_block(10)); + drcuml_block &block(drcuml.begin_block(10)); /* generate a hash jump via the current mode and PC */ - alloc_handle(*drcuml, m_impstate.out_of_cycles, "out_of_cycles"); + alloc_handle(drcuml, m_impstate.out_of_cycles, "out_of_cycles"); UML_HANDLE(block, *m_impstate.out_of_cycles); // handle out_of_cycles UML_GETEXP(block, uml::I0); // getexp i0 UML_MOV(block, uml::mem(&R15), uml::I0); // mov <pc>,i0 @@ -718,16 +715,16 @@ void arm7_cpu_device::static_generate_detect_fault(uml::code_handle **handleptr) { /* on entry, flags are in I2, vaddr is in I3, desc_lvl1 is in I4, ap is in R5 */ /* on exit, fault result is in I6 */ - drcuml_state *drcuml = m_impstate.drcuml; + drcuml_state &drcuml = *m_impstate.drcuml; int donefault = 0; int checkuser = 0; int label = 1; /* begin generating */ - drcuml_block &block(drcuml->begin_block(1024)); + drcuml_block &block(drcuml.begin_block(1024)); /* add a global entry for this */ - alloc_handle(*drcuml, m_impstate.detect_fault, "detect_fault"); + alloc_handle(drcuml, m_impstate.detect_fault, "detect_fault"); UML_HANDLE(block, *m_impstate.detect_fault); // handle detect_fault UML_ROLAND(block, uml::I6, uml::I4, 32-4, 0x0f<<1); // roland i6, i4, 32-4, 0xf<<1 @@ -796,7 +793,7 @@ void arm7_cpu_device::static_generate_tlb_translate(uml::code_handle **handleptr /* on entry, address is in I0 and flags are in I2 */ /* on exit, translated address is in I0 and success/failure is in I2 */ /* routine trashes I4-I7 */ - drcuml_state *drcuml = m_impstate.drcuml; + drcuml_state &drcuml = *m_impstate.drcuml; uml::code_label smallfault; uml::code_label smallprefetch; int nopid = 0; @@ -815,9 +812,9 @@ void arm7_cpu_device::static_generate_tlb_translate(uml::code_handle **handleptr int label = 1; /* begin generating */ - drcuml_block &block(drcuml->begin_block(170)); + drcuml_block &block(drcuml.begin_block(170)); - alloc_handle(*drcuml, m_impstate.tlb_translate, "tlb_translate"); + alloc_handle(drcuml, m_impstate.tlb_translate, "tlb_translate"); UML_HANDLE(block, *m_impstate.tlb_translate); // handle tlb_translate // I3: vaddr @@ -1004,15 +1001,15 @@ void arm7_cpu_device::static_generate_memory_accessor(int size, bool istlb, bool /* on entry, address is in I0; data for writes is in I1, fetch type in I2 */ /* on exit, read result is in I0 */ /* routine trashes I0-I3 */ - drcuml_state *drcuml = m_impstate.drcuml; + drcuml_state &drcuml = *m_impstate.drcuml; //int tlbmiss = 0; int label = 1; /* begin generating */ - drcuml_block &block(drcuml->begin_block(1024)); + drcuml_block &block(drcuml.begin_block(1024)); /* add a global entry for this */ - alloc_handle(*drcuml, handleptr, name); + alloc_handle(drcuml, handleptr, name); UML_HANDLE(block, *handleptr); // handle *handleptr if (istlb) diff --git a/src/devices/imagedev/cassette.h b/src/devices/imagedev/cassette.h index 5310bb546d3..48e10cdbdb4 100644 --- a/src/devices/imagedev/cassette.h +++ b/src/devices/imagedev/cassette.h @@ -87,10 +87,10 @@ public: bool is_playing() { return (m_state & CASSETTE_MASK_UISTATE) == CASSETTE_PLAY; } bool is_recording() { return (m_state & CASSETTE_MASK_UISTATE) == CASSETTE_RECORD; } - void set_motor(int state) { change_state(state ? CASSETTE_MOTOR_ENABLED : CASSETTE_MOTOR_DISABLED, CASSETTE_MASK_MOTOR); } // aka remote control - int motor_on() { return ((m_state & CASSETTE_MASK_MOTOR) == CASSETTE_MOTOR_ENABLED) ? 1 : 0; } - void set_speaker(int state) { change_state(state ? CASSETTE_SPEAKER_ENABLED : CASSETTE_SPEAKER_MUTED, CASSETTE_MASK_SPEAKER); } - int speaker_on() { return ((m_state & CASSETTE_MASK_SPEAKER) == CASSETTE_SPEAKER_ENABLED) ? 1 : 0; } + void set_motor(bool state) { change_state(state ? CASSETTE_MOTOR_ENABLED : CASSETTE_MOTOR_DISABLED, CASSETTE_MASK_MOTOR); } // aka remote control + bool motor_on() { return (m_state & CASSETTE_MASK_MOTOR) == CASSETTE_MOTOR_ENABLED; } + void set_speaker(bool state) { change_state(state ? CASSETTE_SPEAKER_ENABLED : CASSETTE_SPEAKER_MUTED, CASSETTE_MASK_SPEAKER); } + bool speaker_on() { return (m_state & CASSETTE_MASK_SPEAKER) == CASSETTE_SPEAKER_ENABLED; } cassette_image *get_image() { return m_cassette.get(); } double get_position(); diff --git a/src/emu/devcb.h b/src/emu/devcb.h index fd966a7afc1..cdfa9321a5b 100644 --- a/src/emu/devcb.h +++ b/src/emu/devcb.h @@ -88,16 +88,16 @@ protected: template <typename Input, typename Result, typename Func, typename Enable = void> struct is_transform_form4 { static constexpr bool value = false; }; template <typename Input, typename Result, typename Func, typename Enable = void> struct is_transform_form5 { static constexpr bool value = false; }; template <typename Input, typename Result, typename Func, typename Enable = void> struct is_transform_form6 { static constexpr bool value = false; }; - template <typename Input, typename Result, typename Func> struct is_transform_form3<Input, Result, Func, std::enable_if_t<std::is_convertible<std::result_of_t<Func (offs_t &, Input, std::make_unsigned_t<Input> &)>, Result>::value> > { static constexpr bool value = true; }; - template <typename Input, typename Result, typename Func> struct is_transform_form4<Input, Result, Func, std::enable_if_t<std::is_convertible<std::result_of_t<Func (offs_t &, Input)>, Result>::value> > { static constexpr bool value = true; }; - template <typename Input, typename Result, typename Func> struct is_transform_form6<Input, Result, Func, std::enable_if_t<std::is_convertible<std::result_of_t<Func (Input)>, Result>::value> > { static constexpr bool value = true; }; + template <typename Input, typename Result, typename Func> struct is_transform_form3<Input, Result, Func, std::enable_if_t<std::is_convertible<std::invoke_result_t<Func, offs_t &, Input, std::make_unsigned_t<Input> &>, Result>::value> > { static constexpr bool value = true; }; + template <typename Input, typename Result, typename Func> struct is_transform_form4<Input, Result, Func, std::enable_if_t<std::is_convertible<std::invoke_result_t<Func, offs_t &, Input>, Result>::value> > { static constexpr bool value = true; }; + template <typename Input, typename Result, typename Func> struct is_transform_form6<Input, Result, Func, std::enable_if_t<std::is_convertible<std::invoke_result_t<Func, Input>, Result>::value> > { static constexpr bool value = true; }; template <typename Input, typename Result, typename Func> struct is_transform { static constexpr bool value = is_transform_form1<Input, Result, Func>::value || is_transform_form2<Input, Result, Func>::value || is_transform_form3<Input, Result, Func>::value || is_transform_form4<Input, Result, Func>::value || is_transform_form5<Input, Result, Func>::value || is_transform_form6<Input, Result, Func>::value; }; // Determining the result type of a transform function template <typename Input, typename Result, typename Func, typename Enable = void> struct transform_result; - template <typename Input, typename Result, typename Func> struct transform_result<Input, Result, Func, std::enable_if_t<is_transform_form3<Input, Result, Func>::value> > { using type = std::result_of_t<Func (offs_t &, Input, std::make_unsigned_t<Input> &)>; }; - template <typename Input, typename Result, typename Func> struct transform_result<Input, Result, Func, std::enable_if_t<is_transform_form4<Input, Result, Func>::value> > { using type = std::result_of_t<Func (offs_t &, Input)>; }; - template <typename Input, typename Result, typename Func> struct transform_result<Input, Result, Func, std::enable_if_t<is_transform_form6<Input, Result, Func>::value> > { using type = std::result_of_t<Func (Input)>; }; + template <typename Input, typename Result, typename Func> struct transform_result<Input, Result, Func, std::enable_if_t<is_transform_form3<Input, Result, Func>::value> > { using type = std::invoke_result_t<Func, offs_t &, Input, std::make_unsigned_t<Input> &>; }; + template <typename Input, typename Result, typename Func> struct transform_result<Input, Result, Func, std::enable_if_t<is_transform_form4<Input, Result, Func>::value> > { using type = std::invoke_result_t<Func, offs_t &, Input>; }; + template <typename Input, typename Result, typename Func> struct transform_result<Input, Result, Func, std::enable_if_t<is_transform_form6<Input, Result, Func>::value> > { using type = std::invoke_result_t<Func, Input>; }; template <typename Input, typename Result, typename Func> using transform_result_t = typename transform_result<Input, Result, Func>::type; // Mapping method types to delegate types @@ -214,16 +214,16 @@ protected: template <typename Result, typename Func, typename Enable = void> struct is_read_form1 { static constexpr bool value = false; }; template <typename Result, typename Func, typename Enable = void> struct is_read_form2 { static constexpr bool value = false; }; template <typename Result, typename Func, typename Enable = void> struct is_read_form3 { static constexpr bool value = false; }; - template <typename Result, typename Func> struct is_read_form1<Result, Func, std::enable_if_t<std::is_convertible<std::result_of_t<Func (offs_t, Result)>, Result>::value> > { static constexpr bool value = true; }; - template <typename Result, typename Func> struct is_read_form2<Result, Func, std::enable_if_t<std::is_convertible<std::result_of_t<Func (offs_t)>, Result>::value> > { static constexpr bool value = true; }; - template <typename Result, typename Func> struct is_read_form3<Result, Func, std::enable_if_t<std::is_convertible<std::result_of_t<Func ()>, Result>::value> > { static constexpr bool value = true; }; + template <typename Result, typename Func> struct is_read_form1<Result, Func, std::enable_if_t<std::is_convertible<std::invoke_result_t<Func, offs_t, Result>, Result>::value> > { static constexpr bool value = true; }; + template <typename Result, typename Func> struct is_read_form2<Result, Func, std::enable_if_t<std::is_convertible<std::invoke_result_t<Func, offs_t>, Result>::value> > { static constexpr bool value = true; }; + template <typename Result, typename Func> struct is_read_form3<Result, Func, std::enable_if_t<std::is_convertible<std::invoke_result_t<Func>, Result>::value> > { static constexpr bool value = true; }; template <typename Result, typename Func> struct is_read { static constexpr bool value = is_read_form1<Result, Func>::value || is_read_form2<Result, Func>::value || is_read_form3<Result, Func>::value; }; // Determining the result type of a read function template <typename Result, typename Func, typename Enable = void> struct read_result; - template <typename Result, typename Func> struct read_result<Result, Func, std::enable_if_t<is_read_form1<Result, Func>::value> > { using type = std::result_of_t<Func (offs_t, std::make_unsigned_t<Result>)>; }; - template <typename Result, typename Func> struct read_result<Result, Func, std::enable_if_t<is_read_form2<Result, Func>::value> > { using type = std::result_of_t<Func (offs_t)>; }; - template <typename Result, typename Func> struct read_result<Result, Func, std::enable_if_t<is_read_form3<Result, Func>::value> > { using type = std::result_of_t<Func ()>; }; + template <typename Result, typename Func> struct read_result<Result, Func, std::enable_if_t<is_read_form1<Result, Func>::value> > { using type = std::invoke_result_t<Func, offs_t, std::make_unsigned_t<Result>>; }; + template <typename Result, typename Func> struct read_result<Result, Func, std::enable_if_t<is_read_form2<Result, Func>::value> > { using type = std::invoke_result_t<Func, offs_t>; }; + template <typename Result, typename Func> struct read_result<Result, Func, std::enable_if_t<is_read_form3<Result, Func>::value> > { using type = std::invoke_result_t<Func>; }; template <typename Result, typename Func> using read_result_t = typename read_result<Result, Func>::type; // Detecting candidates for read delegates @@ -278,9 +278,9 @@ protected: template <typename Input, typename Func, typename Enable = void> struct is_write_form1 { static constexpr bool value = false; }; template <typename Input, typename Func, typename Enable = void> struct is_write_form2 { static constexpr bool value = false; }; template <typename Input, typename Func, typename Enable = void> struct is_write_form3 { static constexpr bool value = false; }; - template <typename Input, typename Func> struct is_write_form1<Input, Func, void_t<std::result_of_t<Func (offs_t, Input, std::make_unsigned_t<Input>)> > > { static constexpr bool value = true; }; - template <typename Input, typename Func> struct is_write_form2<Input, Func, void_t<std::result_of_t<Func (offs_t, Input)> > > { static constexpr bool value = true; }; - template <typename Input, typename Func> struct is_write_form3<Input, Func, void_t<std::result_of_t<Func (Input)> > > { static constexpr bool value = true; }; + template <typename Input, typename Func> struct is_write_form1<Input, Func, void_t<std::invoke_result_t<Func, offs_t, Input, std::make_unsigned_t<Input>> > > { static constexpr bool value = true; }; + template <typename Input, typename Func> struct is_write_form2<Input, Func, void_t<std::invoke_result_t<Func, offs_t, Input> > > { static constexpr bool value = true; }; + template <typename Input, typename Func> struct is_write_form3<Input, Func, void_t<std::invoke_result_t<Func, Input> > > { static constexpr bool value = true; }; template <typename Input, typename Func> struct is_write { static constexpr bool value = is_write_form1<Input, Func>::value || is_write_form2<Input, Func>::value || is_write_form3<Input, Func>::value; }; // Detecting candidates for write delegates diff --git a/src/emu/diimage.cpp b/src/emu/diimage.cpp index 0b78816c8e5..4a61fcdecc3 100644 --- a/src/emu/diimage.cpp +++ b/src/emu/diimage.cpp @@ -94,7 +94,6 @@ device_image_interface::device_image_interface(const machine_config &mconfig, de , m_file() , m_mame_file() , m_software_part_ptr(nullptr) - , m_supported(0) , m_readonly(false) , m_created(false) , m_create_format(0) @@ -576,7 +575,8 @@ u32 device_image_interface::crc() u32 crc = 0; image_checkhash(); - m_hash.crc(crc); + if (!m_hash.crc(crc)) + crc = 0; return crc; } @@ -1073,11 +1073,6 @@ image_init_result device_image_interface::load_software(const std::string &softw if (swinfo.longname().empty() || swinfo.publisher().empty() || swinfo.year().empty()) fatalerror("Each entry in an XML list must have all of the following fields: description, publisher, year!\n"); - // store - m_longname = swinfo.longname(); - m_manufacturer = swinfo.publisher(); - m_year = swinfo.year(); - // set file type std::string filename = (m_mame_file != nullptr) && (m_mame_file->filename() != nullptr) ? m_mame_file->filename() @@ -1204,9 +1199,6 @@ void device_image_interface::clear() m_create_format = 0; m_create_args = nullptr; - m_longname.clear(); - m_manufacturer.clear(); - m_year.clear(); m_basename.clear(); m_basename_noext.clear(); m_filetype.clear(); @@ -1214,6 +1206,8 @@ void device_image_interface::clear() m_full_software_name.clear(); m_software_part_ptr = nullptr; m_software_list_name.clear(); + + m_hash.reset(); } diff --git a/src/emu/diimage.h b/src/emu/diimage.h index 9ec748c3bed..e9292f2f472 100644 --- a/src/emu/diimage.h +++ b/src/emu/diimage.h @@ -175,11 +175,6 @@ public: void *ptr() {check_for_file(); return const_cast<void *>(m_file->buffer()); } // configuration access - const std::string &longname() const noexcept { return m_longname; } - const std::string &manufacturer() const noexcept { return m_manufacturer; } - const std::string &year() const noexcept { return m_year; } - u32 supported() const noexcept { return m_supported; } - const software_info *software_entry() const noexcept; const software_part *part_entry() const noexcept { return m_software_part_ptr; } const char *software_list_name() const noexcept { return m_software_list_name.c_str(); } @@ -301,12 +296,6 @@ private: // working directory; persists across mounts std::string m_working_directory; - // info read from the hash file/software list - std::string m_longname; - std::string m_manufacturer; - std::string m_year; - u32 m_supported; - // flags bool m_readonly; bool m_created; diff --git a/src/emu/emumem.h b/src/emu/emumem.h index 5e419241162..b51e0a25c97 100644 --- a/src/emu/emumem.h +++ b/src/emu/emumem.h @@ -167,7 +167,7 @@ namespace emu::detail { template <typename... T> struct void_wrapper { using type = void; }; template <typename... T> using void_t = typename void_wrapper<T...>::type; -template <typename D, typename T, typename Enable = void> struct rw_device_class { }; +template <typename D, typename T, typename Enable = void> struct rw_device_class { }; template <typename D, typename T, typename Ret, typename... Params> struct rw_device_class<D, Ret (T::*)(Params...), std::enable_if_t<std::is_constructible<D, device_t &, const char *, Ret (T::*)(Params...), const char *>::value> > { using type = T; }; diff --git a/src/emu/emuopts.cpp b/src/emu/emuopts.cpp index ceda32dbbcc..9885b42b880 100644 --- a/src/emu/emuopts.cpp +++ b/src/emu/emuopts.cpp @@ -74,7 +74,7 @@ const options_entry emu_options::s_option_entries[] = { OPTION_WAVWRITE, nullptr, OPTION_STRING, "optional filename to write a WAV file of the current session" }, { OPTION_SNAPNAME, "%g/%i", OPTION_STRING, "override of the default snapshot/movie naming; %g == gamename, %i == index" }, { OPTION_SNAPSIZE, "auto", OPTION_STRING, "specify snapshot/movie resolution (<width>x<height>) or 'auto' to use minimal size " }, - { OPTION_SNAPVIEW, "internal", OPTION_STRING, "specify snapshot/movie view or 'internal' to use internal pixel-aspect views" }, + { OPTION_SNAPVIEW, "", OPTION_STRING, "specify snapshot/movie view or 'native' to use internal pixel-aspect views" }, { OPTION_SNAPBILINEAR, "1", OPTION_BOOLEAN, "specify if the snapshot/movie should have bilinear filtering applied" }, { OPTION_STATENAME, "%g", OPTION_STRING, "override of the default state subfolder naming; %g == gamename" }, { OPTION_BURNIN, "0", OPTION_BOOLEAN, "create burn-in snapshots for each screen" }, diff --git a/src/emu/inpttype.ipp b/src/emu/inpttype.ipp index f16677cf5c9..ff7b17f757b 100644 --- a/src/emu/inpttype.ipp +++ b/src/emu/inpttype.ipp @@ -803,14 +803,14 @@ namespace { #define CORE_INPUT_TYPES_UI \ CORE_INPUT_TYPES_BEGIN(ui) \ - INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_ON_SCREEN_DISPLAY,"On Screen Display", input_seq(KEYCODE_TILDE, input_seq::not_code, KEYCODE_LSHIFT) ) \ - INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_DEBUG_BREAK, "Break in Debugger", input_seq(KEYCODE_TILDE, input_seq::not_code, KEYCODE_LSHIFT) ) \ + INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_ON_SCREEN_DISPLAY,"On Screen Display", input_seq(KEYCODE_TILDE, input_seq::not_code, KEYCODE_LSHIFT, input_seq::not_code, KEYCODE_RSHIFT) ) \ + INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_DEBUG_BREAK, "Break in Debugger", input_seq(KEYCODE_TILDE, input_seq::not_code, KEYCODE_LSHIFT, input_seq::not_code, KEYCODE_RSHIFT) ) \ INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_CONFIGURE, "Config Menu", input_seq(KEYCODE_TAB) ) \ INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_PAUSE, "Pause", input_seq(KEYCODE_P, input_seq::not_code, KEYCODE_LSHIFT, input_seq::not_code, KEYCODE_RSHIFT) ) \ - INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_PAUSE_SINGLE, "Pause - Single Step", input_seq(KEYCODE_P, KEYCODE_LSHIFT) ) \ + INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_PAUSE_SINGLE, "Pause - Single Step", input_seq(KEYCODE_P, KEYCODE_LSHIFT, input_seq::or_code, KEYCODE_P, KEYCODE_RSHIFT) ) \ INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_REWIND_SINGLE, "Rewind - Single Step", input_seq(KEYCODE_TILDE, KEYCODE_LSHIFT) ) \ - INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_RESET_MACHINE, "Reset Machine", input_seq(KEYCODE_F3, KEYCODE_LSHIFT) ) \ - INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_SOFT_RESET, "Soft Reset", input_seq(KEYCODE_F3, input_seq::not_code, KEYCODE_LSHIFT) ) \ + INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_RESET_MACHINE, "Reset Machine", input_seq(KEYCODE_F3, KEYCODE_LSHIFT, input_seq::or_code, KEYCODE_F3, KEYCODE_RSHIFT) ) \ + INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_SOFT_RESET, "Soft Reset", input_seq(KEYCODE_F3, input_seq::not_code, KEYCODE_LSHIFT, input_seq::not_code, KEYCODE_RSHIFT) ) \ INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_SHOW_GFX, "Show Gfx", input_seq(KEYCODE_F4) ) \ INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_FRAMESKIP_DEC, "Frameskip Dec", input_seq(KEYCODE_F8) ) \ INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_FRAMESKIP_INC, "Frameskip Inc", input_seq(KEYCODE_F9) ) \ @@ -830,8 +830,8 @@ namespace { INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_END, "UI End", input_seq(KEYCODE_END) ) \ INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_PAGE_UP, "UI Page Up", input_seq(KEYCODE_PGUP) ) \ INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_PAGE_DOWN, "UI Page Down", input_seq(KEYCODE_PGDN) ) \ - INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_FOCUS_NEXT, "UI Focus Next", input_seq(KEYCODE_TAB, input_seq::not_code, KEYCODE_LSHIFT) ) \ - INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_FOCUS_PREV, "UI Focus Previous", input_seq(KEYCODE_TAB, KEYCODE_LSHIFT) ) \ + INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_FOCUS_NEXT, "UI Focus Next", input_seq(KEYCODE_TAB, input_seq::not_code, KEYCODE_LSHIFT, input_seq::not_code, KEYCODE_RSHIFT) ) \ + INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_FOCUS_PREV, "UI Focus Previous", input_seq(KEYCODE_TAB, KEYCODE_LSHIFT, input_seq::or_code, KEYCODE_TAB, KEYCODE_RSHIFT) ) \ INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_SELECT, "UI Select", input_seq(KEYCODE_ENTER, input_seq::or_code, JOYCODE_BUTTON1_INDEXED(0), input_seq::or_code, KEYCODE_ENTER_PAD) ) \ INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_CANCEL, "UI Cancel", input_seq(KEYCODE_ESC) ) \ INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_DISPLAY_COMMENT, "UI Display Comment", input_seq(KEYCODE_SPACE) ) \ @@ -843,6 +843,7 @@ namespace { INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_ROTATE, "UI Rotate", input_seq(KEYCODE_R) ) \ INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_SHOW_PROFILER, "Show Profiler", input_seq(KEYCODE_F11, KEYCODE_LSHIFT) ) \ INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_TOGGLE_UI, "UI Toggle", input_seq(KEYCODE_SCRLOCK, input_seq::not_code, KEYCODE_LSHIFT) ) \ + INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_RELEASE_POINTER, "UI Release Pointer", input_seq(KEYCODE_RCONTROL, KEYCODE_RALT) ) \ INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_PASTE, "UI Paste Text", input_seq(KEYCODE_SCRLOCK, KEYCODE_LSHIFT) ) \ INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_TOGGLE_DEBUG, "Toggle Debugger", input_seq(KEYCODE_F5) ) \ INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_SAVE_STATE, "Save State", input_seq(KEYCODE_F7, KEYCODE_LSHIFT) ) \ diff --git a/src/emu/inputdev.cpp b/src/emu/inputdev.cpp index 4c2afdd7e7a..66a0794f6cd 100644 --- a/src/emu/inputdev.cpp +++ b/src/emu/inputdev.cpp @@ -31,7 +31,7 @@ public: virtual s32 read_as_switch(input_item_modifier modifier) override; virtual s32 read_as_relative(input_item_modifier modifier) override; virtual s32 read_as_absolute(input_item_modifier modifier) override; - virtual bool item_check_axis(input_item_modifier modifier) override; + virtual bool item_check_axis(input_item_modifier modifiers, s32 memory) override; // steadykey helper bool steadykey_changed(); @@ -57,7 +57,7 @@ public: virtual s32 read_as_switch(input_item_modifier modifier) override; virtual s32 read_as_relative(input_item_modifier modifier) override; virtual s32 read_as_absolute(input_item_modifier modifier) override; - virtual bool item_check_axis(input_item_modifier modifier) override; + virtual bool item_check_axis(input_item_modifier modifier, s32 memory) override; }; @@ -74,7 +74,7 @@ public: virtual s32 read_as_switch(input_item_modifier modifier) override; virtual s32 read_as_relative(input_item_modifier modifier) override; virtual s32 read_as_absolute(input_item_modifier modifier) override; - virtual bool item_check_axis(input_item_modifier modifier) override; + virtual bool item_check_axis(input_item_modifier modifier, s32 memory) override; }; @@ -675,16 +675,17 @@ input_device_item::input_device_item(input_device &device, const char *name, voi m_itemid(itemid), m_itemclass(itemclass), m_getstate(getstate), - m_current(0), - m_memory(0) + m_current(0) { - // use a standard token name for know item IDs const char *standard_token = manager().standard_token(itemid); - if (standard_token != nullptr) + if (standard_token) + { + // use a standard token name for know item IDs m_token.assign(standard_token); - - // otherwise, create a tokenized name - else { + } + else + { + // otherwise, create a tokenized name m_token.assign(name); strmakeupper(m_token); strdelchr(m_token, ' '); @@ -707,19 +708,10 @@ input_device_item::~input_device_item() // to trigger a read when polling //------------------------------------------------- -bool input_device_item::check_axis(input_item_modifier modifier) +bool input_device_item::check_axis(input_item_modifier modifier, s32 memory) { - // if we've already reported this one, don't bother - if (m_memory == INVALID_AXIS_VALUE) - return false; - - if (item_check_axis(modifier)) - { - m_memory = INVALID_AXIS_VALUE; - return true; - } - - return false; + // use INVALID_AXIS_VALUE as a short-circuit + return (memory != INVALID_AXIS_VALUE) && item_check_axis(modifier, memory); } @@ -801,7 +793,7 @@ s32 input_device_switch_item::read_as_absolute(input_item_modifier modifier) // enough to trigger a read when polling //------------------------------------------------- -bool input_device_switch_item::item_check_axis(input_item_modifier modifier) +bool input_device_switch_item::item_check_axis(input_item_modifier modifier, s32 memory) { return false; } @@ -889,12 +881,12 @@ s32 input_device_relative_item::read_as_absolute(input_item_modifier modifier) // enough to trigger a read when polling //------------------------------------------------- -bool input_device_relative_item::item_check_axis(input_item_modifier modifier) +bool input_device_relative_item::item_check_axis(input_item_modifier modifier, s32 memory) { - s32 curval = read_as_relative(modifier); + const s32 curval = read_as_relative(modifier); // for relative axes, look for ~20 pixels movement - return std::abs(curval - memory()) > 20 * INPUT_RELATIVE_PER_PIXEL; + return std::abs(curval - memory) > (20 * INPUT_RELATIVE_PER_PIXEL); } @@ -1002,15 +994,15 @@ s32 input_device_absolute_item::read_as_absolute(input_item_modifier modifier) // enough to trigger a read when polling //------------------------------------------------- -bool input_device_absolute_item::item_check_axis(input_item_modifier modifier) +bool input_device_absolute_item::item_check_axis(input_item_modifier modifier, s32 memory) { // ignore min/max for lightguns // so the selection will not be affected by a gun going out of range - s32 curval = read_as_absolute(modifier); + const s32 curval = read_as_absolute(modifier); if (m_device.devclass() == DEVICE_CLASS_LIGHTGUN && (curval == INPUT_ABSOLUTE_MAX || curval == INPUT_ABSOLUTE_MIN)) return false; // for absolute axes, look for 25% of maximum - return std::abs(curval - memory()) > (INPUT_ABSOLUTE_MAX - INPUT_ABSOLUTE_MIN) / 4; + return std::abs(curval - memory) > ((INPUT_ABSOLUTE_MAX - INPUT_ABSOLUTE_MIN) / 4); } diff --git a/src/emu/inputdev.h b/src/emu/inputdev.h index ecae0532be0..9c9f63c3961 100644 --- a/src/emu/inputdev.h +++ b/src/emu/inputdev.h @@ -105,18 +105,16 @@ public: input_code code() const; const char *token() const { return m_token.c_str(); } s32 current() const { return m_current; } - s32 memory() const { return m_memory; } // helpers s32 update_value(); - void set_memory(s32 value) { m_memory = value; } - bool check_axis(input_item_modifier modifier); + bool check_axis(input_item_modifier modifier, s32 memory); // readers virtual s32 read_as_switch(input_item_modifier modifier) = 0; virtual s32 read_as_relative(input_item_modifier modifier) = 0; virtual s32 read_as_absolute(input_item_modifier modifier) = 0; - virtual bool item_check_axis(input_item_modifier modifier) = 0; + virtual bool item_check_axis(input_item_modifier modifier, s32 memory) = 0; protected: // internal state @@ -130,7 +128,6 @@ protected: // live state s32 m_current; // current raw value - s32 m_memory; // "memory" value, to remember where we started during polling }; diff --git a/src/emu/ioport.h b/src/emu/ioport.h index 72add6abb41..376df1347be 100644 --- a/src/emu/ioport.h +++ b/src/emu/ioport.h @@ -358,6 +358,7 @@ enum ioport_type IPT_UI_ROTATE, IPT_UI_SHOW_PROFILER, IPT_UI_TOGGLE_UI, + IPT_UI_RELEASE_POINTER, IPT_UI_TOGGLE_DEBUG, IPT_UI_PASTE, IPT_UI_SAVE_STATE, diff --git a/src/emu/render.cpp b/src/emu/render.cpp index 26b7057ffb3..6b9a1e76f18 100644 --- a/src/emu/render.cpp +++ b/src/emu/render.cpp @@ -3366,17 +3366,21 @@ void render_manager::config_save(config_type cfg_type, util::xml::data_node *par } // iterate over targets - for (int targetnum = 0; targetnum < 1000; targetnum++) + for (int targetnum = 0; ; ++targetnum) { // get this target and break when we fail render_target *target = target_by_index(targetnum); - if (target == nullptr) + if (!target) + { break; - - // create a node - util::xml::data_node *const targetnode = parentnode->add_child("target", nullptr); - if (targetnode && !target->config_save(*targetnode)) - targetnode->delete_node(); + } + else if (!target->hidden()) + { + // create a node + util::xml::data_node *const targetnode = parentnode->add_child("target", nullptr); + if (targetnode && !target->config_save(*targetnode)) + targetnode->delete_node(); + } } // iterate over screen containers diff --git a/src/emu/video.cpp b/src/emu/video.cpp index 26b7fe1d2c2..3d6ffa43dea 100644 --- a/src/emu/video.cpp +++ b/src/emu/video.cpp @@ -120,7 +120,7 @@ video_manager::video_manager(running_machine &machine) // create a render target for snapshots const char *viewname = machine.options().snap_view(); - m_snap_native = !no_screens && (viewname[0] == 0 || strcmp(viewname, "native") == 0); + m_snap_native = !no_screens && !strcmp(viewname, "native"); if (m_snap_native) { @@ -426,13 +426,13 @@ void video_manager::begin_recording_screen(const std::string &filename, uint32_t // create the emu_file bool is_absolute_path = !filename.empty() && osd_is_absolute_path(filename); std::unique_ptr<emu_file> movie_file = std::make_unique<emu_file>( - is_absolute_path ? "" : machine().options().snapshot_directory(), - OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); + is_absolute_path ? "" : machine().options().snapshot_directory(), + OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); // and open the actual file osd_file::error filerr = filename.empty() - ? open_next(*movie_file, extension) - : movie_file->open(filename); + ? open_next(*movie_file, extension) + : movie_file->open(filename); if (filerr != osd_file::error::NONE) { osd_printf_error("Error creating movie, osd_file::error=%d\n", int(filerr)); @@ -554,16 +554,6 @@ void video_manager::postload() //------------------------------------------------- -// is_recording - returns whether or not any -// screen is currently recording -//------------------------------------------------- - -bool video_manager::is_recording() const -{ - return !m_movie_recordings.empty(); -} - -//------------------------------------------------- // effective_autoframeskip - return the effective // autoframeskip value, accounting for fast // forward diff --git a/src/emu/video.h b/src/emu/video.h index 0dec74fa5a7..bcd0d4e4394 100644 --- a/src/emu/video.h +++ b/src/emu/video.h @@ -51,7 +51,6 @@ public: bool throttled() const { return m_throttled; } float throttle_rate() const { return m_throttle_rate; } bool fastforward() const { return m_fastforward; } - bool is_recording() const; // setters void set_frameskip(int frameskip); @@ -76,6 +75,7 @@ public: int effective_frameskip() const; // snapshots + render_target &snapshot_target() { return *m_snap_target; } void save_snapshot(screen_device *screen, emu_file &file); void save_active_screen_snapshots(); void save_input_timecode(); @@ -84,6 +84,7 @@ public: void begin_recording(const char *name, movie_recording::format format); void end_recording(); void add_sound_to_recording(const s16 *sound, int numsamples); + bool is_recording() const { return !m_movie_recordings.empty(); } void set_timecode_enabled(bool value) { m_timecode_enabled = value; } bool get_timecode_enabled() { return m_timecode_enabled; } diff --git a/src/frontend/mame/iptseqpoll.cpp b/src/frontend/mame/iptseqpoll.cpp index 145c64f033a..83883e5d970 100644 --- a/src/frontend/mame/iptseqpoll.cpp +++ b/src/frontend/mame/iptseqpoll.cpp @@ -11,7 +11,8 @@ input_code_poller::input_code_poller(input_manager &manager) noexcept : - m_manager(manager) + m_manager(manager), + m_axis_memory() { } @@ -24,26 +25,31 @@ input_code_poller::~input_code_poller() void input_code_poller::reset() { // iterate over device classes and devices + m_axis_memory.clear(); for (input_device_class classno = DEVICE_CLASS_FIRST_VALID; DEVICE_CLASS_LAST_VALID >= classno; ++classno) { input_class &devclass(m_manager.device_class(classno)); - for (int devnum = 0; devclass.maxindex() >= devnum; ++devnum) + if (devclass.enabled()) { - // fetch the device; ignore if nullptr - input_device *const device(devclass.device(devnum)); - if (device) + for (int devnum = 0; devclass.maxindex() >= devnum; ++devnum) { - // iterate over items within each device - for (input_item_id itemid = ITEM_ID_FIRST_VALID; device->maxitem() >= itemid; ++itemid) + // fetch the device; ignore if nullptr + input_device *const device(devclass.device(devnum)); + if (device) { - // for any non-switch items, set memory to the current value - input_device_item *const item(device->item(itemid)); - if (item && (item->itemclass() != ITEM_CLASS_SWITCH)) - item->set_memory(m_manager.code_value(item->code())); + // iterate over items within each device + for (input_item_id itemid = ITEM_ID_FIRST_VALID; device->maxitem() >= itemid; ++itemid) + { + // for any non-switch items, set memory to the current value + input_device_item *const item(device->item(itemid)); + if (item && (item->itemclass() != ITEM_CLASS_SWITCH)) + m_axis_memory.emplace_back(item, m_manager.code_value(item->code())); + } } } } } + std::sort(m_axis_memory.begin(), m_axis_memory.end()); } @@ -62,7 +68,7 @@ void switch_code_poller_base::reset() } -bool switch_code_poller_base::code_pressed_once(input_code code) +bool switch_code_poller_base::code_pressed_once(input_code code, bool moved) { // look for the code in the memory bool const pressed(m_manager.code_pressed(code)); @@ -78,7 +84,7 @@ bool switch_code_poller_base::code_pressed_once(input_code code) } // if we get here, we were not previously pressed; if still not pressed, return false - if (!pressed) + if (!pressed || !moved) return false; // otherwise, add the code to the memory and return true @@ -96,31 +102,14 @@ axis_code_poller::axis_code_poller(input_manager &manager) noexcept : input_code axis_code_poller::poll() { - // iterate over device classes and devices, skipping disabled classes - for (input_device_class classno = DEVICE_CLASS_FIRST_VALID; DEVICE_CLASS_LAST_VALID >= classno; ++classno) + // iterate over the axis items we found + for (auto memory = m_axis_memory.begin(); m_axis_memory.end() != memory; ++memory) { - input_class &devclass(m_manager.device_class(classno)); - if (devclass.enabled()) + input_code const code = memory->first->code(); + if (memory->first->check_axis(code.item_modifier(), memory->second)) { - for (int devnum = 0; devclass.maxindex() >= devnum; ++devnum) - { - // fetch the device; ignore if nullptr - input_device *const device(devclass.device(devnum)); - if (device) - { - // iterate over items within each device - for (input_item_id itemid = ITEM_ID_FIRST_VALID; device->maxitem() >= itemid; ++itemid) - { - input_device_item *const item(device->item(itemid)); - if (item && (item->itemclass() != ITEM_CLASS_SWITCH)) - { - input_code const code = item->code(); - if (item->check_axis(code.item_modifier())) - return code; - } - } - } - } + m_axis_memory.erase(memory); + return code; } } @@ -142,64 +131,73 @@ input_code switch_code_poller::poll() for (input_device_class classno = DEVICE_CLASS_FIRST_VALID; DEVICE_CLASS_LAST_VALID >= classno; ++classno) { input_class &devclass(m_manager.device_class(classno)); - if (devclass.enabled()) + if (!devclass.enabled()) + continue; + + for (int devnum = 0; devclass.maxindex() >= devnum; ++devnum) { - for (int devnum = 0; devclass.maxindex() >= devnum; ++devnum) + // fetch the device; ignore if nullptr + input_device *const device(devclass.device(devnum)); + if (!device) + continue; + + // iterate over items within each device + for (input_item_id itemid = ITEM_ID_FIRST_VALID; device->maxitem() >= itemid; ++itemid) { - // fetch the device; ignore if nullptr - input_device *const device(devclass.device(devnum)); - if (device) + input_device_item *const item(device->item(itemid)); + if (!item) + continue; + + input_code code = item->code(); + if (item->itemclass() == ITEM_CLASS_SWITCH) { - // iterate over items within each device - for (input_item_id itemid = ITEM_ID_FIRST_VALID; device->maxitem() >= itemid; ++itemid) - { - input_device_item *const item(device->item(itemid)); - if (item) - { - input_code code = item->code(); - if (item->itemclass() == ITEM_CLASS_SWITCH) - { - // item is natively a switch, poll it - if (code_pressed_once(code)) - return code; - } - else if (item->check_axis(code.item_modifier())) - { - // poll axes digitally - code.set_item_class(ITEM_CLASS_SWITCH); - if ((classno == DEVICE_CLASS_JOYSTICK) && (code.item_id() == ITEM_ID_XAXIS)) - { - // joystick X axis - check with left/right modifiers - code.set_item_modifier(ITEM_MODIFIER_LEFT); - if (code_pressed_once(code)) - return code; - code.set_item_modifier(ITEM_MODIFIER_RIGHT); - if (code_pressed_once(code)) - return code; - } - else if ((classno == DEVICE_CLASS_JOYSTICK) && (code.item_id() == ITEM_ID_YAXIS)) - { - // if this is a joystick Y axis, check with up/down modifiers - code.set_item_modifier(ITEM_MODIFIER_UP); - if (code_pressed_once(code)) - return code; - code.set_item_modifier(ITEM_MODIFIER_DOWN); - if (code_pressed_once(code)) - return code; - } - else - { - // any other axis, check with pos/neg modifiers - code.set_item_modifier(ITEM_MODIFIER_POS); - if (code_pressed_once(code)) - return code; - code.set_item_modifier(ITEM_MODIFIER_NEG); - if (code_pressed_once(code)) - return code; - } - } - } - } + // item is natively a switch, poll it + if (code_pressed_once(code, true)) + return code; + else + continue; + } + + auto const memory(std::lower_bound( + m_axis_memory.begin(), + m_axis_memory.end(), + item, + [] (auto const &x, auto const &y) { return x.first < y; })); + if ((m_axis_memory.end() == memory) || (item != memory->first)) + continue; + + // poll axes digitally + bool const moved(item->check_axis(code.item_modifier(), memory->second)); + code.set_item_class(ITEM_CLASS_SWITCH); + if ((classno == DEVICE_CLASS_JOYSTICK) && (code.item_id() == ITEM_ID_XAXIS)) + { + // joystick X axis - check with left/right modifiers + code.set_item_modifier(ITEM_MODIFIER_LEFT); + if (code_pressed_once(code, moved)) + return code; + code.set_item_modifier(ITEM_MODIFIER_RIGHT); + if (code_pressed_once(code, moved)) + return code; + } + else if ((classno == DEVICE_CLASS_JOYSTICK) && (code.item_id() == ITEM_ID_YAXIS)) + { + // if this is a joystick Y axis, check with up/down modifiers + code.set_item_modifier(ITEM_MODIFIER_UP); + if (code_pressed_once(code, moved)) + return code; + code.set_item_modifier(ITEM_MODIFIER_DOWN); + if (code_pressed_once(code, moved)) + return code; + } + else + { + // any other axis, check with pos/neg modifiers + code.set_item_modifier(ITEM_MODIFIER_POS); + if (code_pressed_once(code, moved)) + return code; + code.set_item_modifier(ITEM_MODIFIER_NEG); + if (code_pressed_once(code, moved)) + return code; } } } @@ -237,7 +235,7 @@ input_code keyboard_code_poller::poll() if (item && (item->itemclass() == ITEM_CLASS_SWITCH)) { input_code const code = item->code(); - if (code_pressed_once(code)) + if (code_pressed_once(code, true)) return code; } } diff --git a/src/frontend/mame/iptseqpoll.h b/src/frontend/mame/iptseqpoll.h index 13c0d9c6484..b9f31f70477 100644 --- a/src/frontend/mame/iptseqpoll.h +++ b/src/frontend/mame/iptseqpoll.h @@ -12,6 +12,7 @@ #pragma once +#include <utility> #include <vector> @@ -27,6 +28,7 @@ protected: input_code_poller(input_manager &manager) noexcept; input_manager &m_manager; + std::vector<std::pair<input_device_item *, s32> > m_axis_memory; }; @@ -38,7 +40,7 @@ public: protected: switch_code_poller_base(input_manager &manager) noexcept; - bool code_pressed_once(input_code code); + bool code_pressed_once(input_code code, bool moved); private: std::vector<input_code> m_switch_memory; diff --git a/src/frontend/mame/luaengine.cpp b/src/frontend/mame/luaengine.cpp index 4e7fb5412da..98f00a219d0 100644 --- a/src/frontend/mame/luaengine.cpp +++ b/src/frontend/mame/luaengine.cpp @@ -47,7 +47,7 @@ int luaopen_lsqlite3(lua_State *L); template <typename T> struct lua_engine::devenum { - devenum(device_t &d) : device(d), iter(d) { } + template <typename... U> devenum(device_t &d, U &&... args) : device(d), iter(d, std::forward<U>(args)...) { } device_t &device; T iter; @@ -55,18 +55,85 @@ struct lua_engine::devenum }; -template <typename T> -struct lua_engine::object_ptr_vector_wrapper +namespace { + +void do_draw_box(screen_device &sdev, float x1, float y1, float x2, float y2, uint32_t fgcolor, uint32_t bgcolor) +{ + float const sc_width(sdev.visible_area().width()); + float const sc_height(sdev.visible_area().height()); + x1 = std::min(std::max(0.0f, x1), sc_width) / sc_width; + y1 = std::min(std::max(0.0f, y1), sc_height) / sc_height; + x2 = std::min(std::max(0.0f, x2), sc_width) / sc_width; + y2 = std::min(std::max(0.0f, y2), sc_height) / sc_height; + mame_machine_manager::instance()->ui().draw_outlined_box(sdev.container(), x1, y1, x2, y2, fgcolor, bgcolor); +} + +void do_draw_line(screen_device &sdev, float x1, float y1, float x2, float y2, uint32_t color) +{ + float const sc_width(sdev.visible_area().width()); + float const sc_height(sdev.visible_area().height()); + x1 = std::min(std::max(0.0f, x1), sc_width) / sc_width; + y1 = std::min(std::max(0.0f, y1), sc_height) / sc_height; + x2 = std::min(std::max(0.0f, x2), sc_width) / sc_width; + y2 = std::min(std::max(0.0f, y2), sc_height) / sc_height; + sdev.container().add_line(x1, y1, x2, y2, UI_LINE_WIDTH, rgb_t(color), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)); +} + +void do_draw_text(lua_State *L, screen_device &sdev, sol::object &xobj, float y, const char *msg, rgb_t fgcolor, rgb_t bgcolor) +{ + float const sc_width(sdev.visible_area().width()); + float const sc_height(sdev.visible_area().height()); + auto justify = ui::text_layout::LEFT; + float x = 0; + if (xobj.is<float>()) + { + x = std::min(std::max(0.0f, xobj.as<float>()), sc_width) / sc_width; + } + else if (xobj.is<char const *>()) + { + char const *const justifystr(xobj.as<char const *>()); + if (!strcmp(justifystr, "left")) + justify = ui::text_layout::LEFT; + else if (!strcmp(justifystr, "right")) + justify = ui::text_layout::RIGHT; + else if (!strcmp(justifystr, "center")) + justify = ui::text_layout::CENTER; + } + else + { + luaL_error(L, "Error in param 1 to draw_text"); + return; + } + y = std::min(std::max(0.0f, y), sc_height) / sc_height; + mame_machine_manager::instance()->ui().draw_text_full( + sdev.container(), + msg, + x, y, (1.0f - x), + justify, ui::text_layout::WORD, + mame_ui_manager::OPAQUE_, fgcolor, bgcolor); +} + + +struct image_interface_formats { - object_ptr_vector_wrapper(std::vector<std::unique_ptr<T>> const &v) : vec(v) { } + image_interface_formats(device_image_interface &i) : image(i) { } + device_image_interface::formatlist_type const &items() { return image.formatlist(); } + + static image_device_format const &unwrap(device_image_interface::formatlist_type::const_iterator const &it) { return **it; } + static int push_key(lua_State *L, device_image_interface::formatlist_type::const_iterator const &it, std::size_t ix) { return sol::stack::push_reference(L, (*it)->name()); } - std::vector<std::unique_ptr<T>> const &vec; + device_image_interface ℑ }; +} // anonymous namespace + namespace sol { +template <> struct is_container<image_interface_formats> : std::true_type { }; + + sol::buffer *sol_lua_get(sol::types<buffer *>, lua_State *L, int index, sol::stack::record &tracking) { return new sol::buffer(stack::get<int>(L, index), L); @@ -181,74 +248,30 @@ public: }; -template <typename T> -struct usertype_container<lua_engine::object_ptr_vector_wrapper<T> > : lua_engine::immutable_collection_helper<lua_engine::object_ptr_vector_wrapper<T>, std::vector<std::unique_ptr<T>> const, typename std::vector<std::unique_ptr<T>>::const_iterator> +template <> +struct usertype_container<image_interface_formats> : lua_engine::immutable_sequence_helper<image_interface_formats, device_image_interface::formatlist_type const, device_image_interface::formatlist_type::const_iterator> { private: - static int next_pairs(lua_State *L) - { - typename usertype_container::indexed_iterator &i(stack::unqualified_get<user<typename usertype_container::indexed_iterator> >(L, 1)); - if (i.src.end() == i.it) - return stack::push(L, lua_nil); - int result; - result = stack::push(L, i.ix + 1); - result += stack::push_reference(L, i.it->get()); - ++i; - return result; - } + using format_list = device_image_interface::formatlist_type; public: - static int at(lua_State *L) - { - lua_engine::object_ptr_vector_wrapper<T> &self(usertype_container::get_self(L)); - std::ptrdiff_t const index(stack::unqualified_get<std::ptrdiff_t>(L, 2)); - if ((0 >= index) || (self.vec.size() < index)) - return stack::push(L, lua_nil); - return stack::push_reference(L, self.vec[index - 1].get()); - } - - static int get(lua_State *L) { return at(L); } - static int index_get(lua_State *L) { return at(L); } - - static int index_of(lua_State *L) + static int get(lua_State *L) { - lua_engine::object_ptr_vector_wrapper<T> &self(usertype_container::get_self(L)); - T &target(stack::unqualified_get<T>(L, 2)); - auto it(self.vec.begin()); - std::ptrdiff_t ix(0); - while ((self.vec.end() != it) && (it->get() != &target)) - { - ++it; - ++ix; - } - if (self.vec.end() == it) - return stack::push(L, lua_nil); + image_interface_formats &self(get_self(L)); + char const *const name(stack::unqualified_get<char const *>(L)); + auto const found(std::find_if( + self.image.formatlist().begin(), + self.image.formatlist().end(), + [&name] (std::unique_ptr<image_device_format> const &v) { return v->name() == name; })); + if (self.image.formatlist().end() != found) + return stack::push_reference(L, **found); else - return stack::push(L, ix + 1); - } - - static int size(lua_State *L) - { - lua_engine::object_ptr_vector_wrapper<T> &self(usertype_container::get_self(L)); - return stack::push(L, self.vec.size()); - } - - static int empty(lua_State *L) - { - lua_engine::object_ptr_vector_wrapper<T> &self(usertype_container::get_self(L)); - return stack::push(L, self.vec.empty()); + return stack::push(L, lua_nil); } - static int next(lua_State *L) { return stack::push(L, next_pairs); } - static int pairs(lua_State *L) { return ipairs(L); } - - static int ipairs(lua_State *L) + static int index_get(lua_State *L) { - lua_engine::object_ptr_vector_wrapper<T> &self(usertype_container::get_self(L)); - stack::push(L, next_pairs); - stack::push<user<typename usertype_container::indexed_iterator> >(L, self.vec, self.vec.begin()); - stack::push(L, lua_nil); - return 3; + return get(L); } }; @@ -300,6 +323,40 @@ bool sol_lua_check(sol::types<osd_file::error>, lua_State *L, int index, Handler } +int sol_lua_push(sol::types<screen_type_enum>, lua_State *L, screen_type_enum &&value) +{ + switch (value) + { + case SCREEN_TYPE_INVALID: return sol::stack::push(L, "invalid"); + case SCREEN_TYPE_RASTER: return sol::stack::push(L, "raster"); + case SCREEN_TYPE_VECTOR: return sol::stack::push(L, "vector"); + case SCREEN_TYPE_LCD: return sol::stack::push(L, "svg"); + case SCREEN_TYPE_SVG: return sol::stack::push(L, "none"); + } + return sol::stack::push(L, "unknown"); +} + +int sol_lua_push(sol::types<image_init_result>, lua_State *L, image_init_result &&value) +{ + switch (value) + { + case image_init_result::PASS: return sol::stack::push(L, "pass"); + case image_init_result::FAIL: return sol::stack::push(L, "fail"); + } + return sol::stack::push(L, "invalid"); +} + +int sol_lua_push(sol::types<image_verify_result>, lua_State *L, image_verify_result &&value) +{ + switch (value) + { + case image_verify_result::PASS: return sol::stack::push(L, "pass"); + case image_verify_result::FAIL: return sol::stack::push(L, "fail"); + } + return sol::stack::push(L, "invalid"); +} + + //------------------------------------------------- // process_snapshot_filename - processes a snapshot // filename @@ -558,14 +615,6 @@ void lua_engine::initialize() }; - static const enum_parser<ui::text_layout::text_justify, 3> s_text_justify_parser = - { - { "left", ui::text_layout::LEFT }, - { "right", ui::text_layout::RIGHT }, - { "center", ui::text_layout::CENTER }, - }; - - static const enum_parser<int, 3> s_seek_parser = { { "set", SEEK_SET }, @@ -617,6 +666,7 @@ void lua_engine::initialize() * emu.device_enumerator(dev) - get device enumerator starting at arbitrary point in tree * emu.screen_enumerator(dev) - get screen device enumerator starting at arbitrary point in tree * emu.image_enumerator(dev) - get image interface enumerator starting at arbitrary point in tree + * emu.image_enumerator(dev) - get image interface enumerator starting at arbitrary point in tree */ sol::table emu = sol().create_named_table("emu"); @@ -712,9 +762,21 @@ void lua_engine::initialize() osd_subst_env(result, str); return result; }; - emu["device_enumerator"] = [] (device_t &d) { return devenum<device_enumerator>(d); }; - emu["screen_enumerator"] = [] (device_t &d) { return devenum<screen_device_enumerator>(d); }; - emu["image_enumerator"] = [] (device_t &d) { return devenum<image_interface_enumerator>(d); }; + 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["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); }); + emu["cassette_enumerator"] = sol::overload( + [] (device_t &dev) { return devenum<cassette_device_enumerator>(dev); }, + [] (device_t &dev, int maxdepth) { return devenum<cassette_device_enumerator>(dev, maxdepth); }); + emu["image_enumerator"] = sol::overload( + [] (device_t &dev) { return devenum<image_interface_enumerator>(dev); }, + [] (device_t &dev, int maxdepth) { return devenum<image_interface_enumerator>(dev, maxdepth); }); + emu["slot_enumerator"] = sol::overload( + [] (device_t &dev) { return devenum<slot_interface_enumerator>(dev); }, + [] (device_t &dev, int maxdepth) { return devenum<slot_interface_enumerator>(dev, maxdepth); }); /* emu_file library @@ -1313,33 +1375,6 @@ void lua_engine::initialize() game_driver_type["is_incomplete"] = sol::property([] (game_driver const &driver) { return (driver.flags & machine_flags::IS_INCOMPLETE) != 0; }); -/* device_t library - * - * manager:machine().devices[device_tag] - * - * device:subtag(tag) - get absolute tag relative to this device - * device:siblingtag(tag) - get absolute tag relative to this device - * 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 - * - * device.tag - device tree tag - * device.basetag - last component of tag ("root" for root device) - * device.name - device type full name - * device.shortname - device type short name - * device.owner - parent device (nil for root device) - * device.configured - whether configuration is complete - * device.started - whether the device has been started - * device.spaces[] - device address spaces table (k=name, v=addr_space) - * device.state[] - device state entries table (k=name, v=device_state_entry) - * device.items[] - device save state items table (k=name, v=index) - * device.roms[] - device rom entry table (k=name, v=rom_entry) - */ - auto device_type = sol().registry().new_usertype<device_t>("device", sol::no_constructor); device_type["subtag"] = &device_t::subtag; device_type["siblingtag"] = &device_t::siblingtag; @@ -1349,13 +1384,6 @@ void lua_engine::initialize() 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"] = - [this] (device_t &dev) -> sol::object - { - if (!(dev.machine().debug_flags & DEBUG_FLAG_ENABLED) || !dynamic_cast<cpu_device *>(&dev)) // debugger not enabled or not cpu - return sol::make_object(sol(), sol::lua_nil); - return sol::make_object(sol(), dev.debug()); - }; device_type["tag"] = sol::property(&device_t::tag); device_type["basetag"] = sol::property(&device_t::basetag); device_type["name"] = sol::property(&device_t::name); @@ -1363,20 +1391,28 @@ void lua_engine::initialize() device_type["owner"] = sol::property(&device_t::owner); device_type["configured"] = sol::property(&device_t::configured); device_type["started"] = sol::property(&device_t::started); + device_type["debug"] = sol::property( + [this] (device_t &dev) -> sol::object + { + if (!(dev.machine().debug_flags & DEBUG_FLAG_ENABLED) || !dynamic_cast<cpu_device *>(&dev)) // debugger not enabled or not cpu + return sol::make_object(sol(), sol::lua_nil); + return sol::make_object(sol(), dev.debug()); + }); device_type["spaces"] = sol::property( [this] (device_t &dev) { - device_memory_interface *memdev = dynamic_cast<device_memory_interface *>(&dev); + device_memory_interface *const memdev = dynamic_cast<device_memory_interface *>(&dev); sol::table sp_table = sol().create_table(); - if(!memdev) + if (!memdev) return sp_table; - for(int sp = 0; sp < memdev->max_space_count(); ++sp) + for (int sp = 0; sp < memdev->max_space_count(); ++sp) { - if(memdev->has_space(sp)) + if (memdev->has_space(sp)) sp_table[memdev->space(sp).name()] = addr_space(memdev->space(sp), *memdev); } return sp_table; }); + // FIXME: improve this device_type["state"] = sol::property( [this] (device_t &dev) { @@ -1388,41 +1424,246 @@ void lua_engine::initialize() st_table[s->symbol()] = s.get(); return st_table; }); + // FIXME: turn into a wrapper - it's stupid slow to walk on every property access + // also, this mixes up things like RAM areas with stuff saved by the device itself, so there's potential for key conflicts device_type["items"] = sol::property( [this] (device_t &dev) { sol::table table = sol().create_table(); - std::string tag = dev.tag(); - // 10000 is enough? - for(int i = 0; i < 10000; i++) + std::string const tag = dev.tag(); + for (int i = 0; ; i++) { - std::string name; - const char *item; + char const *item; void *base; uint32_t size, valcount, blockcount, stride; item = dev.machine().save().indexed_item(i, base, size, valcount, blockcount, stride); - if(!item) + if (!item) break; - name = &(strchr(item, '/')[1]); - if(name.substr(0, name.find('/')) == tag) - { - name = name.substr(name.find('/') + 1, std::string::npos); - table[name] = i; - } + + char const *name = &strchr(item, '/')[1]; + if (!strncmp(tag.c_str(), name, tag.length()) && (name[tag.length()] == '/')) + table[name + tag.length() + 1] = i; } return table; }); + // FIXME: this is useless in its current form device_type["roms"] = sol::property( [this] (device_t &dev) { sol::table table = sol().create_table(); - for(auto rom : dev.rom_region_vector()) - if(!rom.name().empty()) + for (auto rom : dev.rom_region_vector()) + if (!rom.name().empty()) table[rom.name()] = rom; return table; }); + auto screen_dev_type = sol().registry().new_usertype<screen_device>( + "screen_dev", + sol::no_constructor, + sol::base_classes, sol::bases<device_t>()); + screen_dev_type["draw_box"] = sol::overload( + [] (screen_device &sdev, float x1, float y1, float x2, float y2, uint32_t fgcolor, uint32_t bgcolor) + { do_draw_box(sdev, x1, y1, x2, y2, fgcolor, bgcolor); }, + [] (screen_device &sdev, float x1, float y1, float x2, float y2, uint32_t fgcolor) + { do_draw_box(sdev, x1, y1, x2, y2, fgcolor, mame_machine_manager::instance()->ui().colors().background_color()); }, + [] (screen_device &sdev, float x1, float y1, float x2, float y2) + { auto const &colors(mame_machine_manager::instance()->ui().colors()); do_draw_box(sdev, x1, y1, x2, y2, colors.text_color(), colors.background_color()); }); + screen_dev_type["draw_line"] = sol::overload( + &do_draw_line, + [] (screen_device &sdev, float x1, float y1, float x2, float y2) + { do_draw_line(sdev, x1, y1, x2, y2, mame_machine_manager::instance()->ui().colors().text_color()); }); + screen_dev_type["draw_text"] = sol::overload( + [this] (screen_device &sdev, sol::object xobj, float y, const char *msg, uint32_t fgcolor, uint32_t bgcolor) + { do_draw_text(m_lua_state, sdev, xobj, y, msg, fgcolor, bgcolor); }, + [this] (screen_device &sdev, sol::object xobj, float y, const char *msg, uint32_t fgcolor) + { do_draw_text(m_lua_state, sdev, xobj, y, msg, fgcolor, 0); }, + [this] (screen_device &sdev, sol::object xobj, float y, const char *msg) + { do_draw_text(m_lua_state, sdev, xobj, y, msg, mame_machine_manager::instance()->ui().colors().text_color(), 0); }); + screen_dev_type["orientation"] = + [] (screen_device &sdev) + { + uint32_t flags = sdev.orientation(); + int rotation_angle = 0; + switch (flags) + { + case ORIENTATION_SWAP_XY: + case ORIENTATION_SWAP_XY | ORIENTATION_FLIP_X: + rotation_angle = 90; + flags ^= ORIENTATION_FLIP_X; + break; + case ORIENTATION_FLIP_Y: + case ORIENTATION_FLIP_X | ORIENTATION_FLIP_Y: + rotation_angle = 180; + flags ^= ORIENTATION_FLIP_X | ORIENTATION_FLIP_Y; + break; + case ORIENTATION_SWAP_XY | ORIENTATION_FLIP_Y: + case ORIENTATION_SWAP_XY | ORIENTATION_FLIP_X | ORIENTATION_FLIP_Y: + rotation_angle = 270; + flags ^= ORIENTATION_FLIP_Y; + break; + } + return std::tuple<int, bool, bool>(rotation_angle, flags & ORIENTATION_FLIP_X, flags & ORIENTATION_FLIP_Y); + }; + screen_dev_type["time_until_pos"] = sol::overload( + [] (screen_device &sdev, int vpos) { return sdev.time_until_pos(vpos).as_double(); }, + [] (screen_device &sdev, int vpos, int hpos) { return sdev.time_until_pos(vpos, hpos).as_double(); }); + screen_dev_type["time_until_vblank_start"] = &screen_device::time_until_vblank_start; + screen_dev_type["time_until_vblank_end"] = &screen_device::time_until_vblank_end; + screen_dev_type["snapshot"] = + [this] (screen_device &sdev, char const *filename) -> sol::object + { + std::string snapstr; + bool is_absolute_path = false; + if (filename) + { + // a filename was specified; if it isn't absolute post-process it + snapstr = process_snapshot_filename(machine(), filename); + is_absolute_path = osd_is_absolute_path(snapstr); + } + + // open the file + emu_file file(is_absolute_path ? "" : machine().options().snapshot_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); + osd_file::error filerr; + if (!snapstr.empty()) + filerr = file.open(snapstr); + else + filerr = machine().video().open_next(file, "png"); + if (filerr != osd_file::error::NONE) + return sol::make_object(sol(), filerr); + + // and save the snapshot + machine().video().save_snapshot(&sdev, file); + return sol::make_object(sol(), sol::lua_nil); + }; + screen_dev_type["pixel"] = [] (screen_device &sdev, s32 x, s32 y) { return sdev.pixel(x, y); }; + screen_dev_type["pixels"] = + [] (screen_device &sdev, sol::this_state s) + { + lua_State *L = s; + const rectangle &visarea = sdev.visible_area(); + luaL_Buffer buff; + int size = visarea.height() * visarea.width() * 4; + u32 *ptr = (u32 *)luaL_buffinitsize(L, &buff, size); + sdev.pixels(ptr); + luaL_pushresultsize(&buff, size); + return sol::make_reference(L, sol::stack_reference(L, -1)); + }; + screen_dev_type["screen_type"] = sol::property(&screen_device::screen_type); + screen_dev_type["width"] = sol::property([] (screen_device &sdev) { return sdev.visible_area().width(); }); + screen_dev_type["height"] = sol::property([] (screen_device &sdev) { return sdev.visible_area().height(); }); + screen_dev_type["refresh"] = sol::property([] (screen_device &sdev) { return ATTOSECONDS_TO_HZ(sdev.refresh_attoseconds()); }); + screen_dev_type["refresh_attoseconds"] = sol::property([] (screen_device &sdev) { return sdev.refresh_attoseconds(); }); + screen_dev_type["xofffset"] = sol::property(&screen_device::xoffset); + screen_dev_type["yofffset"] = sol::property(&screen_device::yoffset); + screen_dev_type["xscale"] = sol::property(&screen_device::xscale); + screen_dev_type["yscale"] = sol::property(&screen_device::yscale); + screen_dev_type["pixel_period"] = sol::property([] (screen_device &sdev) { return sdev.pixel_period().as_double(); }); + screen_dev_type["scan_period"] = sol::property([] (screen_device &sdev) { return sdev.scan_period().as_double(); }); + 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); + + + auto cass_type = sol().registry().new_usertype<cassette_image_device>( + "cassette", + sol::no_constructor, + 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); }; + cass_type["forward"] = &cassette_image_device::go_forward; + cass_type["reverse"] = &cassette_image_device::go_reverse; + cass_type["seek"] = [] (cassette_image_device &c, double time, const char* origin) { if (c.exists()) c.seek(time, s_seek_parser(origin)); }; + cass_type["is_stopped"] = sol::property(&cassette_image_device::is_stopped); + cass_type["is_playing"] = sol::property(&cassette_image_device::is_playing); + cass_type["is_recording"] = sol::property(&cassette_image_device::is_recording); + 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) { return c.exists() ? c.get_length() : 0.0; }); + + + auto image_type = sol().registry().new_usertype<device_image_interface>("image", "new", sol::no_constructor); + image_type["load"] = &device_image_interface::load; + image_type["load_software"] = static_cast<image_init_result (device_image_interface::*)(const std::string &)>(&device_image_interface::load_software); + image_type["unload"] = &device_image_interface::unload; + image_type["create"] = static_cast<image_init_result (device_image_interface::*)(const std::string &)>(&device_image_interface::create); + image_type["display"] = &device_image_interface::call_display; + image_type["is_readable"] = sol::property(&device_image_interface::is_readable); + image_type["is_writeable"] = sol::property(&device_image_interface::is_writeable); + image_type["is_creatable"] = sol::property(&device_image_interface::is_creatable); + image_type["must_be_loaded"] = sol::property(&device_image_interface::must_be_loaded); + image_type["is_reset_on_load"] = sol::property(&device_image_interface::is_reset_on_load); + image_type["image_type_name"] = sol::property(&device_image_interface::image_type_name); + image_type["instance_name"] = sol::property(&device_image_interface::instance_name); + image_type["brief_instance_name"] = sol::property(&device_image_interface::brief_instance_name); + image_type["formatlist"] = sol::property([] (device_image_interface &image) { return image_interface_formats(image); }); + image_type["exists"] = sol::property(&device_image_interface::exists); + image_type["readonly"] = sol::property(&device_image_interface::is_readonly); + image_type["filename"] = sol::property(&device_image_interface::filename); + image_type["crc"] = sol::property(&device_image_interface::crc); + image_type["loaded_through_softlist"] = sol::property(&device_image_interface::loaded_through_softlist); + image_type["software_list_name"] = sol::property(&device_image_interface::software_list_name); + image_type["software_longname"] = sol::property( + [] (device_image_interface &di) + { + software_info const *const si(di.software_entry()); + return si ? si->longname().c_str() : nullptr; + }); + image_type["software_publisher"] = sol::property( + [] (device_image_interface &di) + { + software_info const *const si(di.software_entry()); + return si ? si->publisher().c_str() : nullptr; + }); + image_type["software_year"] = sol::property( + [] (device_image_interface &di) + { + software_info const *const si(di.software_entry()); + return si ? si->year().c_str() : nullptr; + }); + image_type["software_parent"] = sol::property( + [] (device_image_interface &di) + { + software_info const *const si(di.software_entry()); + return si ? si->parentname().c_str() : nullptr; + }); + image_type["device"] = sol::property(static_cast<device_t & (device_image_interface::*)()>(&device_image_interface::device)); + + + auto format_type = sol().registry().new_usertype<image_device_format>("image_format", sol::no_constructor); + format_type["name"] = sol::property(&image_device_format::name); + format_type["description"] = sol::property(&image_device_format::description); + format_type["extensions"] = sol::property( + [this] (image_device_format const &format) + { + int index = 1; + sol::table option_table = sol().create_table(); + for (std::string const &ext : format.extensions()) + option_table[index++] = ext; + return option_table; + }); + format_type["option_spec"] = sol::property(&image_device_format::optspec); + + + auto slot_type = sol().registry().new_usertype<device_slot_interface>("slot", sol::no_constructor); + slot_type["fixed"] = sol::property(&device_slot_interface::fixed); + slot_type["has_selectable_options"] = sol::property(&device_slot_interface::has_selectable_options); + slot_type["default_option"] = sol::property(&device_slot_interface::default_option); + slot_type["options"] = sol::property([] (device_slot_interface const &slot) { return standard_tag_object_ptr_map<device_slot_interface::slot_option>(slot.option_list()); }); + slot_type["device"] = sol::property(static_cast<device_t & (device_slot_interface::*)()>(&device_slot_interface::device)); + + + auto dislot_option_type = sol().registry().new_usertype<device_slot_interface::slot_option>("dislot_option", sol::no_constructor); + dislot_option_type["name"] = sol::property(&device_slot_interface::slot_option::name); + dislot_option_type["device_fullname"] = sol::property([] (device_slot_interface::slot_option &opt) { return opt.devtype().fullname(); }); + dislot_option_type["device_shortname"] = sol::property([] (device_slot_interface::slot_option &opt) { return opt.devtype().shortname(); }); + dislot_option_type["selectable"] = sol::property(&device_slot_interface::slot_option::selectable); + dislot_option_type["default_bios"] = sol::property(static_cast<char const * (device_slot_interface::slot_option::*)() const>(&device_slot_interface::slot_option::default_bios)); + dislot_option_type["clock"] = sol::property(static_cast<u32 (device_slot_interface::slot_option::*)() const>(&device_slot_interface::slot_option::clock)); + + /* parameters_manager library * * manager:machine():parameters() @@ -1537,160 +1778,6 @@ void lua_engine::initialize() sound_type.set("attenuation", sol::property(&sound_manager::attenuation, &sound_manager::set_attenuation)); -/* screen_device library - * - * manager:machine().screens[screen_tag] - * - * screen:draw_box(x1, y1, x2, y2, fillcol, linecol) - draw box from (x1, y1)-(x2, y2) colored linecol - * filled with fillcol, color is 32bit argb - * screen:draw_line(x1, y1, x2, y2, linecol) - draw line from (x1, y1)-(x2, y2) colored linecol - * screen:draw_text(x || justify, y, message, [opt] fgcolor, [opt] bgcolor) - draw message at (x, y) or at line y - * with left/right/center justification - * screen:height() - screen height - * screen:width() - screen width - * screen:orientation() - screen angle, flipx, flipy - * screen:refresh() - screen refresh rate in Hz - * screen:refresh_attoseconds() - screen refresh rate in attoseconds - * screen:snapshot([opt] filename) - save snap shot - * screen:type() - screen drawing type - * screen:frame_number() - screen frame count - * screen:xscale() - screen x scale factor - * screen:yscale() - screen y scale factor - * screen:pixel(x, y) - get pixel at (x, y) as packed RGB in a u32 - * screen:pixels() - get whole screen binary bitmap as string - * screen:time_until_pos(vpos, hpos) - get the time until this screen pos is reached - */ - - auto screen_dev_type = sol().registry().new_usertype<screen_device>( - "screen_dev", - sol::no_constructor, - sol::base_classes, sol::bases<device_t>()); - screen_dev_type.set("container", sol::property(&screen_device::container)); - screen_dev_type.set("draw_box", [](screen_device &sdev, float x1, float y1, float x2, float y2, uint32_t bgcolor, uint32_t fgcolor) { - int sc_width = sdev.visible_area().width(); - int sc_height = sdev.visible_area().height(); - x1 = std::min(std::max(0.0f, x1), float(sc_width-1)) / float(sc_width); - y1 = std::min(std::max(0.0f, y1), float(sc_height-1)) / float(sc_height); - x2 = std::min(std::max(0.0f, x2), float(sc_width-1)) / float(sc_width); - y2 = std::min(std::max(0.0f, y2), float(sc_height-1)) / float(sc_height); - mame_machine_manager::instance()->ui().draw_outlined_box(sdev.container(), x1, y1, x2, y2, fgcolor, bgcolor); - }); - screen_dev_type.set("draw_line", [](screen_device &sdev, float x1, float y1, float x2, float y2, uint32_t color) { - int sc_width = sdev.visible_area().width(); - int sc_height = sdev.visible_area().height(); - x1 = std::min(std::max(0.0f, x1), float(sc_width-1)) / float(sc_width); - y1 = std::min(std::max(0.0f, y1), float(sc_height-1)) / float(sc_height); - x2 = std::min(std::max(0.0f, x2), float(sc_width-1)) / float(sc_width); - y2 = std::min(std::max(0.0f, y2), float(sc_height-1)) / float(sc_height); - sdev.container().add_line(x1, y1, x2, y2, UI_LINE_WIDTH, rgb_t(color), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)); - }); - screen_dev_type.set("draw_text", [this](screen_device &sdev, sol::object xobj, float y, const char *msg, sol::object color, sol::object bcolor) { - int sc_width = sdev.visible_area().width(); - int sc_height = sdev.visible_area().height(); - auto justify = ui::text_layout::LEFT; - float x = 0; - if(xobj.is<float>()) - { - x = std::min(std::max(0.0f, xobj.as<float>()), float(sc_width-1)) / float(sc_width); - y = std::min(std::max(0.0f, y), float(sc_height-1)) / float(sc_height); - } - else if(xobj.is<const char *>()) - { - justify = s_text_justify_parser(xobj.as<const char *>()); - } - else - { - luaL_error(m_lua_state, "Error in param 1 to draw_text"); - return; - } - rgb_t textcolor = mame_machine_manager::instance()->ui().colors().text_color(); - rgb_t bgcolor = 0; - if(color.is<uint32_t>()) - textcolor = rgb_t(color.as<uint32_t>()); - if(bcolor.is<uint32_t>()) - bgcolor = rgb_t(bcolor.as<uint32_t>()); - mame_machine_manager::instance()->ui().draw_text_full(sdev.container(), msg, x, y, (1.0f - x), - justify, ui::text_layout::WORD, mame_ui_manager::OPAQUE_, textcolor, bgcolor); - }); - screen_dev_type.set("height", [](screen_device &sdev) { return sdev.visible_area().height(); }); - screen_dev_type.set("width", [](screen_device &sdev) { return sdev.visible_area().width(); }); - screen_dev_type.set("orientation", [](screen_device &sdev) { - uint32_t flags = sdev.orientation(); - int rotation_angle = 0; - switch (flags) - { - case ORIENTATION_FLIP_X: - rotation_angle = 0; - break; - case ORIENTATION_SWAP_XY: - case ORIENTATION_SWAP_XY|ORIENTATION_FLIP_X: - rotation_angle = 90; - break; - case ORIENTATION_FLIP_Y: - case ORIENTATION_FLIP_X|ORIENTATION_FLIP_Y: - rotation_angle = 180; - break; - case ORIENTATION_SWAP_XY|ORIENTATION_FLIP_Y: - case ORIENTATION_SWAP_XY|ORIENTATION_FLIP_X|ORIENTATION_FLIP_Y: - rotation_angle = 270; - break; - } - return std::tuple<int, bool, bool>(rotation_angle, flags & ORIENTATION_FLIP_X, flags & ORIENTATION_FLIP_Y); - }); - screen_dev_type.set("refresh", [](screen_device &sdev) { return ATTOSECONDS_TO_HZ(sdev.refresh_attoseconds()); }); - screen_dev_type.set("refresh_attoseconds", [](screen_device &sdev) { return sdev.refresh_attoseconds(); }); - screen_dev_type.set("snapshot", [this](screen_device &sdev, sol::object filename) -> sol::object { - std::string snapstr; - bool is_absolute_path = false; - if (filename.is<const char *>()) - { - // a filename was specified; if it isn't absolute postprocess it - snapstr = process_snapshot_filename(machine(), filename.as<const char *>()); - is_absolute_path = osd_is_absolute_path(snapstr); - } - - // open the file - emu_file file(is_absolute_path ? "" : machine().options().snapshot_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); - osd_file::error filerr; - if (!snapstr.empty()) - filerr = file.open(snapstr); - else - filerr = machine().video().open_next(file, "png"); - if (filerr != osd_file::error::NONE) - return sol::make_object(sol(), filerr); - - // and save the snapshot - machine().video().save_snapshot(&sdev, file); - return sol::make_object(sol(), sol::lua_nil); - }); - screen_dev_type.set("type", [](screen_device &sdev) { - switch (sdev.screen_type()) - { - case SCREEN_TYPE_RASTER: return "raster"; break; - case SCREEN_TYPE_VECTOR: return "vector"; break; - case SCREEN_TYPE_LCD: return "lcd"; break; - case SCREEN_TYPE_SVG: return "svg"; break; - default: break; - } - return "unknown"; - }); - screen_dev_type.set("frame_number", &screen_device::frame_number); - screen_dev_type.set("xscale", &screen_device::xscale); - screen_dev_type.set("yscale", &screen_device::yscale); - screen_dev_type.set("pixel", [](screen_device &sdev, float x, float y) { return sdev.pixel((s32)x, (s32)y); }); - screen_dev_type.set("pixels", [](screen_device &sdev, sol::this_state s) { - lua_State *L = s; - const rectangle &visarea = sdev.visible_area(); - luaL_Buffer buff; - int size = visarea.height() * visarea.width() * 4; - u32 *ptr = (u32 *)luaL_buffinitsize(L, &buff, size); - sdev.pixels(ptr); - luaL_pushresultsize(&buff, size); - return sol::make_reference(L, sol::stack_reference(L, -1)); - }); - screen_dev_type.set("time_until_pos", [](screen_device &sdev, int vpos, int hpos) { return sdev.time_until_pos(vpos, hpos).as_double(); }); - - /* mame_ui_manager library * * manager:ui() @@ -1799,160 +1886,6 @@ void lua_engine::initialize() output_type.set("id_to_name", &output_manager::id_to_name); -/* device_image_interface library - * - * manager:machine().images[image_type] - * - * image:exists() - * image:filename() - full path to the image file - * image:longname() - * image:manufacturer() - * image:year() - * image:software_list_name() - * image:image_type_name() - floppy/cart/cdrom/tape/hdd etc - * image:load(filename) - * image:load_software(softlist_name) - * image:unload() - * image:create() - * image:crc() - * image:display() - * - * image.device - get associated device_t - * image.instance_name - * image.brief_instance_name - * image.software_parent - * image.is_readable - * image.is_writeable - * image.is_creatable - * image.is_reset_on_load - * image.must_be_loaded - * image.formatlist - */ - - auto image_type = sol().registry().new_usertype<device_image_interface>("image", "new", sol::no_constructor); - image_type.set("exists", &device_image_interface::exists); - image_type.set("filename", &device_image_interface::filename); - image_type.set("longname", &device_image_interface::longname); - image_type.set("manufacturer", &device_image_interface::manufacturer); - image_type.set("year", &device_image_interface::year); - image_type.set("software_list_name", &device_image_interface::software_list_name); - image_type.set("software_parent", sol::property([](device_image_interface &di) { - const software_info *si = di.software_entry(); - return si ? si->parentname() : ""; - })); - image_type.set("image_type_name", &device_image_interface::image_type_name); - image_type.set("load", &device_image_interface::load); - image_type.set("load_software", static_cast<image_init_result (device_image_interface::*)(const std::string &)>(&device_image_interface::load_software)); - image_type.set("unload", &device_image_interface::unload); - image_type.set("create", [](device_image_interface &di, const std::string &filename) { return di.create(filename); }); - image_type.set("crc", &device_image_interface::crc); - image_type.set("display", [](device_image_interface &di) { return di.call_display(); }); - image_type.set("device", sol::property(static_cast<device_t & (device_image_interface::*)()>(&device_image_interface::device))); - image_type.set("instance_name", sol::property(&device_image_interface::instance_name)); - image_type.set("brief_instance_name", sol::property(&device_image_interface::brief_instance_name)); - image_type.set("is_readable", sol::property(&device_image_interface::is_readable)); - image_type.set("is_writeable", sol::property(&device_image_interface::is_writeable)); - image_type.set("is_creatable", sol::property(&device_image_interface::is_creatable)); - image_type.set("is_reset_on_load", sol::property(&device_image_interface::is_reset_on_load)); - image_type.set("must_be_loaded", sol::property(&device_image_interface::must_be_loaded)); - image_type.set("formatlist", sol::property([](const device_image_interface &image) { return object_ptr_vector_wrapper<image_device_format>(image.formatlist()); })); - - -/* image_device_format library - * - * manager:machine().images[tag].formatlist[index] - * - * format.name - name of the format (e.g. - "dsk") - * format.description - the description of the format - * format.extensions - all of the extensions, as an array - * format.optspec - the option spec associated with the format - * - */ - auto format_type = sol().registry().new_usertype<image_device_format>("image_format", sol::no_constructor); - format_type["name"] = sol::property(&image_device_format::name); - format_type["description"] = sol::property(&image_device_format::description); - format_type["optspec"] = sol::property(&image_device_format::optspec); - format_type["extensions"] = sol::property([this](const image_device_format &format) { - int index = 1; - sol::table option_table = sol().create_table(); - for (const std::string &ext : format.extensions()) - option_table[index++] = ext; - return option_table; - }); - - -/* device_slot_interface library - * - * manager:machine().slots[slot_name] - * - * slot.fixed - whether this slot is fixed, and hence not selectable by the user - * slot.has_selectable_options - does this slot have any selectable options at all? - * slot.default_option - returns the default option if one exists - * slot.options[] - get options table (k=name, v=device_slot_interface::slot_option) - */ - - auto slot_type = sol().registry().new_usertype<device_slot_interface>("slot", sol::no_constructor); - slot_type["fixed"] = sol::property(&device_slot_interface::fixed); - slot_type["has_selectable_options"] = sol::property(&device_slot_interface::has_selectable_options); - slot_type["default_option"] = sol::property(&device_slot_interface::default_option); - slot_type["options"] = sol::property([] (device_slot_interface const &slot) { return standard_tag_object_ptr_map<device_slot_interface::slot_option>(slot.option_list()); }); - - -/* device_slot_interface::slot_option library - * - * manager:machine().slots[slot_name].options[option_name] - * - * slot_option.selectable - is this item selectable by the user? - * slot_option.default_bios - the default bios for this option - * slot_option.clock - the clock speed associated with this option - */ - - auto dislot_option_type = sol().registry().new_usertype<device_slot_interface::slot_option>("dislot_option", sol::no_constructor); - dislot_option_type["selectable"] = sol::property(&device_slot_interface::slot_option::selectable); - dislot_option_type["default_bios"] = sol::property(static_cast<char const * (device_slot_interface::slot_option::*)() const>(&device_slot_interface::slot_option::default_bios)); - dislot_option_type["clock"] = sol::property(static_cast<u32 (device_slot_interface::slot_option::*)() const>(&device_slot_interface::slot_option::clock)); - - -/* cassette_image_device library - * - * manager:machine().cassettes[cass_name] - * - * cass:play() - * cass:stop() - * cass:record() - * cass:forward() - forward play direction - * cass:reverse() - reverse play direction - * cass:seek(time, origin) - seek time sec from origin: "set", "cur", "end" - * - * cass.is_stopped - * cass.is_playing - * cass.is_recording - * cass.motor_state - * cass.speaker_state - * cass.position - * cass.length - * cass.image - get the device_image_interface for this cassette device - */ - - auto cass_type = sol().registry().new_usertype<cassette_image_device>( - "cassette", - sol::no_constructor, - 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); }; - cass_type["forward"] = &cassette_image_device::go_forward; - cass_type["reverse"] = &cassette_image_device::go_reverse; - cass_type["seek"] = [] (cassette_image_device &c, double time, const char* origin) { if (c.exists()) c.seek(time, s_seek_parser(origin)); }; - cass_type["is_stopped"] = sol::property(&cassette_image_device::is_stopped); - cass_type["is_playing"] = sol::property(&cassette_image_device::is_playing); - cass_type["is_recording"] = sol::property(&cassette_image_device::is_recording); - 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) { return c.exists() ? c.get_length() : 0.0; }); - - /* mame_machine_manager library * * manager diff --git a/src/frontend/mame/luaengine.h b/src/frontend/mame/luaengine.h index b0bbf2210c3..973dfedfd89 100644 --- a/src/frontend/mame/luaengine.h +++ b/src/frontend/mame/luaengine.h @@ -34,11 +34,11 @@ public: // helper structures template <typename T> struct devenum; template <typename T> struct simple_list_wrapper; - template <typename T> struct object_ptr_vector_wrapper; template <typename T> struct tag_object_ptr_map; template <typename T> using standard_tag_object_ptr_map = tag_object_ptr_map<std::unordered_map<std::string, std::unique_ptr<T> > >; template <typename T> struct immutable_container_helper; template <typename T, typename C, typename I = typename C::iterator> struct immutable_collection_helper; + template <typename T, typename C, typename I = typename C::iterator> struct immutable_sequence_helper; // construction/destruction lua_engine(); diff --git a/src/frontend/mame/luaengine.ipp b/src/frontend/mame/luaengine.ipp index 8d51fb0a092..d532b8be1b4 100644 --- a/src/frontend/mame/luaengine.ipp +++ b/src/frontend/mame/luaengine.ipp @@ -89,7 +89,6 @@ int sol_lua_push(sol::types<buffer *>, lua_State *L, buffer *value); template <typename T> struct is_container<lua_engine::devenum<T> > : std::true_type { }; template <typename T> struct is_container<lua_engine::simple_list_wrapper<T> > : std::true_type { }; template <typename T> struct is_container<lua_engine::tag_object_ptr_map<T> > : std::true_type { }; -template <typename T> struct is_container<lua_engine::object_ptr_vector_wrapper<T> > : std::true_type { }; template <typename T> struct usertype_container<lua_engine::devenum<T> >; @@ -256,7 +255,6 @@ public: static int ipairs(lua_State *L) { return start_pairs<true>(L); } }; - } // namespace sol @@ -265,10 +263,10 @@ int sol_lua_push(sol::types<osd_file::error>, lua_State *L, osd_file::error &&va template <typename Handler> bool sol_lua_check(sol::types<osd_file::error>, lua_State *L, int index, Handler &&handler, sol::stack::record &tracking); -// map_handler_type customisation +// enums to automatically convert to strings int sol_lua_push(sol::types<map_handler_type>, lua_State *L, map_handler_type &&value); - -// endianness_t customisation +int sol_lua_push(sol::types<image_init_result>, lua_State *L, image_init_result &&value); +int sol_lua_push(sol::types<image_verify_result>, lua_State *L, image_verify_result &&value); int sol_lua_push(sol::types<endianness_t>, lua_State *L, endianness_t &&value); @@ -353,6 +351,83 @@ protected: }; +template <typename T, typename C, typename I> +struct lua_engine::immutable_sequence_helper : immutable_collection_helper<T, C, I> +{ +protected: + template <bool Indexed> + static int next_pairs(lua_State *L) + { + auto &i(sol::stack::unqualified_get<sol::user<typename immutable_sequence_helper::indexed_iterator> >(L, 1)); + if (i.src.end() == i.it) + return sol::stack::push(L, sol::lua_nil); + int result; + if constexpr (Indexed) + result = sol::stack::push(L, i.ix + 1); + else + result = T::push_key(L, i.it, i.ix); + result += sol::stack::push_reference(L, T::unwrap(i.it)); + ++i; + return result; + } + + template <bool Indexed> + static int start_pairs(lua_State *L) + { + T &self(immutable_sequence_helper::get_self(L)); + sol::stack::push(L, next_pairs<Indexed>); + sol::stack::push<sol::user<typename immutable_sequence_helper::indexed_iterator> >(L, self.items(), self.items().begin()); + sol::stack::push(L, sol::lua_nil); + return 3; + } + +public: + static int at(lua_State *L) + { + T &self(immutable_sequence_helper::get_self(L)); + std::ptrdiff_t const index(sol::stack::unqualified_get<std::ptrdiff_t>(L, 2)); + if ((0 >= index) || (self.items().size() < index)) + return sol::stack::push(L, sol::lua_nil); + else + return sol::stack::push_reference(L, T::unwrap(std::next(self.items().begin(), index - 1))); + } + + static int index_of(lua_State *L) + { + T &self(immutable_sequence_helper::get_self(L)); + auto it(self.items().begin()); + std::ptrdiff_t ix(0); + auto const &item(sol::stack::unqualified_get<decltype(T::unwrap(it))>(L, 2)); + while ((self.items().end() != it) && (&item != &T::unwrap(it))) + { + ++it; + ++ix; + } + if (self.items().end() == it) + return sol::stack::push(L, sol::lua_nil); + else + return sol::stack::push(L, ix + 1); + } + + static int size(lua_State *L) + { + T &self(immutable_sequence_helper::get_self(L)); + return sol::stack::push(L, self.items().size()); + } + + static int empty(lua_State *L) + { + T &self(immutable_sequence_helper::get_self(L)); + return sol::stack::push(L, self.items().empty()); + } + + static int next(lua_State *L) { return sol::stack::push(L, next_pairs<false>); } + static int pairs(lua_State *L) { return start_pairs<false>(L); } + static int ipairs(lua_State *L) { return start_pairs<true>(L); } +}; + + + struct lua_engine::addr_space { addr_space(address_space &s, device_memory_interface &d) : space(s), dev(d) { } diff --git a/src/frontend/mame/luaengine_render.cpp b/src/frontend/mame/luaengine_render.cpp index ca472dba675..b910a717561 100644 --- a/src/frontend/mame/luaengine_render.cpp +++ b/src/frontend/mame/luaengine_render.cpp @@ -21,6 +21,10 @@ namespace { struct layout_file_views { layout_file_views(layout_file &f) : file(f) { } + layout_file::view_list &items() { return file.views(); } + + static layout_view &unwrap(layout_file::view_list::iterator const &it) { return *it; } + static int push_key(lua_State *L, layout_file::view_list::iterator const &it, std::size_t ix) { return sol::stack::push_reference(L, it->unqualified_name()); } layout_file &file; }; @@ -29,6 +33,10 @@ struct layout_file_views 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 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; }; @@ -53,48 +61,9 @@ template <> struct is_container<render_target_view_names> : std::true_type { }; template <> -struct usertype_container<layout_file_views> : lua_engine::immutable_collection_helper<layout_file_views, layout_file::view_list> +struct usertype_container<layout_file_views> : lua_engine::immutable_sequence_helper<layout_file_views, layout_file::view_list> { -private: - using view_list = layout_file::view_list; - - template <bool Indexed> - static int next_pairs(lua_State *L) - { - indexed_iterator &i(stack::unqualified_get<user<indexed_iterator> >(L, 1)); - if (i.src.end() == i.it) - return stack::push(L, lua_nil); - int result; - if constexpr (Indexed) - result = stack::push(L, i.ix + 1); - else - result = stack::push_reference(L, i.it->unqualified_name()); - result += stack::push_reference(L, *i.it); - ++i; - return result; - } - - template <bool Indexed> - static int start_pairs(lua_State *L) - { - layout_file_views &self(get_self(L)); - stack::push(L, next_pairs<Indexed>); - stack::push<user<indexed_iterator> >(L, self.file.views(), self.file.views().begin()); - stack::push(L, lua_nil); - return 3; - } - public: - static int at(lua_State *L) - { - layout_file_views &self(get_self(L)); - std::ptrdiff_t const index(stack::unqualified_get<std::ptrdiff_t>(L, 2)); - if ((0 >= index) || (self.file.views().size() < index)) - return stack::push(L, lua_nil); - else - return stack::push_reference(L, *std::next(self.file.views().begin(), index - 1)); - } - static int get(lua_State *L) { layout_file_views &self(get_self(L)); @@ -113,72 +82,13 @@ public: { return get(L); } - - static int index_of(lua_State *L) - { - layout_file_views &self(get_self(L)); - layout_view &view(stack::unqualified_get<layout_view>(L, 2)); - auto it(self.file.views().begin()); - std::ptrdiff_t ix(0); - while ((self.file.views().end() != it) && (&view != &*it)) - { - ++it; - ++ix; - } - if (self.file.views().end() == it) - return stack::push(L, lua_nil); - else - return stack::push(L, ix + 1); - } - - static int size(lua_State *L) - { - layout_file_views &self(get_self(L)); - return stack::push(L, self.file.views().size()); - } - - static int empty(lua_State *L) - { - layout_file_views &self(get_self(L)); - return stack::push(L, self.file.views().empty()); - } - - static int next(lua_State *L) { return stack::push(L, next_pairs<false>); } - static int pairs(lua_State *L) { return start_pairs<false>(L); } - static int ipairs(lua_State *L) { return start_pairs<true>(L); } }; template <> -struct usertype_container<layout_view_items> : lua_engine::immutable_collection_helper<layout_view_items, layout_view::item_list> +struct usertype_container<layout_view_items> : lua_engine::immutable_sequence_helper<layout_view_items, layout_view::item_list> { -private: - using item_list = layout_view::item_list; - - static int next_pairs(lua_State *L) - { - indexed_iterator &i(stack::unqualified_get<user<indexed_iterator> >(L, 1)); - if (i.src.end() == i.it) - return stack::push(L, lua_nil); - int result; - result = stack::push(L, i.ix + 1); - result += stack::push_reference(L, *i.it); - ++i.it; - ++i.ix; - return result; - } - public: - static int at(lua_State *L) - { - layout_view_items &self(get_self(L)); - std::ptrdiff_t const index(stack::unqualified_get<std::ptrdiff_t>(L, 2)); - if ((0 >= index) || (self.view.items().size() < index)) - return stack::push(L, lua_nil); - else - return stack::push_reference(L, *std::next(self.view.items().begin(), index - 1)); - } - static int get(lua_State *L) { layout_view_items &self(get_self(L)); @@ -195,50 +105,10 @@ public: return get(L); } - static int index_of(lua_State *L) - { - layout_view_items &self(get_self(L)); - layout_view::item &item(stack::unqualified_get<layout_view::item>(L, 2)); - auto it(self.view.items().begin()); - std::ptrdiff_t ix(0); - while ((self.view.items().end() != it) && (&item != &*it)) - { - ++it; - ++ix; - } - if (self.view.items().end() == it) - return stack::push(L, lua_nil); - else - return stack::push(L, ix + 1); - } - - static int size(lua_State *L) - { - layout_view_items &self(get_self(L)); - return stack::push(L, self.view.items().size()); - } - - static int empty(lua_State *L) - { - layout_view_items &self(get_self(L)); - return stack::push(L, self.view.items().empty()); - } - - static int next(lua_State *L) { return stack::push(L, next_pairs); } - static int pairs(lua_State *L) { return luaL_error(L, "sol: cannot call 'pairs' on type '%s': not iterable by ID", sol::detail::demangle<layout_view_items>().c_str()); } - - static int ipairs(lua_State *L) - { - layout_view_items &self(get_self(L)); - stack::push(L, next_pairs); - stack::push<user<indexed_iterator> >(L, self.view.items(), self.view.items().begin()); - stack::push(L, lua_nil); - return 3; - } }; diff --git a/src/frontend/mame/ui/barcode.cpp b/src/frontend/mame/ui/barcode.cpp index fad2af9ffc6..846f2cc97c5 100644 --- a/src/frontend/mame/ui/barcode.cpp +++ b/src/frontend/mame/ui/barcode.cpp @@ -74,8 +74,8 @@ void menu_barcode_reader::populate(float &customtop, float &custombottom) item_append(_("New Barcode:"), new_barcode, 0, ITEMREF_NEW_BARCODE); // finish up the menu - item_append(menu_item_type::SEPARATOR); item_append(_("Enter Code"), 0, ITEMREF_ENTER_BARCODE); + item_append(menu_item_type::SEPARATOR); customtop = ui().get_line_height() + 3.0f * ui().box_tb_border(); } @@ -88,9 +88,6 @@ void menu_barcode_reader::populate(float &customtop, float &custombottom) void menu_barcode_reader::handle() { - // rebuild the menu (so to update the selected device, if the user has pressed L or R) - repopulate(reset_options::REMEMBER_POSITION); - // process the menu const event *event = process(PROCESS_LR_REPEAT); @@ -127,6 +124,14 @@ void menu_barcode_reader::handle() } break; + case IPT_UI_CLEAR: + if (get_selection_ref() == ITEMREF_NEW_BARCODE) + { + m_barcode_buffer.clear(); + reset(reset_options::REMEMBER_POSITION); + } + break; + case IPT_SPECIAL: if (get_selection_ref() == ITEMREF_NEW_BARCODE) { @@ -134,11 +139,6 @@ void menu_barcode_reader::handle() reset(reset_options::REMEMBER_POSITION); } break; - - case IPT_UI_CANCEL: - // reset the char buffer also in this case - m_barcode_buffer.clear(); - break; } } } diff --git a/src/frontend/mame/ui/devctrl.h b/src/frontend/mame/ui/devctrl.h index 1be2385a66f..ec9dc0d2928 100644 --- a/src/frontend/mame/ui/devctrl.h +++ b/src/frontend/mame/ui/devctrl.h @@ -84,8 +84,8 @@ int menu_device_control<DeviceType>::current_index() template<class DeviceType> void menu_device_control<DeviceType>::previous() { - // left arrow - rotate left through cassette devices - if (m_device != nullptr) + // left arrow - rotate left through devices + if (m_device && (1 < m_count)) { enumerator iter(machine().root_device()); int index = iter.indexof(*m_device); @@ -94,6 +94,7 @@ void menu_device_control<DeviceType>::previous() else index = m_count - 1; m_device = iter.byindex(index); + reset(reset_options::REMEMBER_POSITION); } } @@ -106,7 +107,7 @@ template<class DeviceType> void menu_device_control<DeviceType>::next() { // right arrow - rotate right through cassette devices - if (m_device != nullptr) + if (m_device && (1 < m_count)) { enumerator iter(machine().root_device()); int index = iter.indexof(*m_device); @@ -115,6 +116,7 @@ void menu_device_control<DeviceType>::next() else index = 0; m_device = iter.byindex(index); + reset(reset_options::REMEMBER_POSITION); } } @@ -129,7 +131,7 @@ std::string menu_device_control<DeviceType>::current_display_name() std::string display_name; display_name.assign(current_device()->name()); if (count() > 1) - display_name.append(string_format("%d", current_index() + 1)); + display_name.append(string_format(" %d", current_index() + 1)); return display_name; } diff --git a/src/frontend/mame/ui/devopt.cpp b/src/frontend/mame/ui/devopt.cpp index e423bfd4370..f5e73f290e0 100644 --- a/src/frontend/mame/ui/devopt.cpp +++ b/src/frontend/mame/ui/devopt.cpp @@ -9,12 +9,14 @@ *********************************************************************/ #include "emu.h" -#include "ui/ui.h" #include "ui/devopt.h" + +#include "ui/ui.h" #include "romload.h" namespace ui { + /*------------------------------------------------- device_config - handle the game information menu diff --git a/src/frontend/mame/ui/info.cpp b/src/frontend/mame/ui/info.cpp index 7d11970966f..3a57aac42c0 100644 --- a/src/frontend/mame/ui/info.cpp +++ b/src/frontend/mame/ui/info.cpp @@ -567,28 +567,30 @@ void menu_image_info::image_info(device_image_interface *image) // if image has been loaded through softlist, let's add some more info if (image->loaded_through_softlist()) { - // display long filename - item_append(image->longname(), FLAG_DISABLE, nullptr); + software_info const &swinfo(*image->software_entry()); - // display manufacturer and year - item_append(string_format("%s, %s", image->manufacturer(), image->year()), FLAG_DISABLE, nullptr); + // display full name, publisher and year + item_append(swinfo.longname(), FLAG_DISABLE, nullptr); + item_append(string_format("%1$s, %2$s", swinfo.publisher(), swinfo.year()), FLAG_DISABLE, nullptr); // display supported information, if available - switch (image->supported()) + switch (swinfo.supported()) { - case SOFTWARE_SUPPORTED_NO: - item_append(_("Not supported"), FLAG_DISABLE, nullptr); - break; - case SOFTWARE_SUPPORTED_PARTIAL: - item_append(_("Partially supported"), FLAG_DISABLE, nullptr); - break; - default: - break; + case SOFTWARE_SUPPORTED_NO: + item_append(_("Not supported"), FLAG_DISABLE, nullptr); + break; + case SOFTWARE_SUPPORTED_PARTIAL: + item_append(_("Partially supported"), FLAG_DISABLE, nullptr); + break; + default: + break; } } } else + { item_append(image->brief_instance_name(), _("[empty]"), 0, nullptr); + } item_append(std::string(), FLAG_DISABLE, nullptr); } diff --git a/src/frontend/mame/ui/inifile.cpp b/src/frontend/mame/ui/inifile.cpp index 253c52c07f3..77dfd1088dc 100644 --- a/src/frontend/mame/ui/inifile.cpp +++ b/src/frontend/mame/ui/inifile.cpp @@ -298,11 +298,11 @@ void favorite_manager::add_favorite(running_machine &machine) // start with simple stuff that can just be copied info.shortname = software->shortname(); - info.longname = imagedev->longname(); + info.longname = software->longname(); info.parentname = software->parentname(); - info.year = imagedev->year(); - info.publisher = imagedev->manufacturer(); - info.supported = imagedev->supported(); + info.year = software->year(); + info.publisher = software->publisher(); + info.supported = software->supported(); info.part = part->name(); info.driver = &driver; info.listname = imagedev->software_list_name(); diff --git a/src/frontend/mame/ui/mainmenu.cpp b/src/frontend/mame/ui/mainmenu.cpp index 23a68c979c5..1051b322d99 100644 --- a/src/frontend/mame/ui/mainmenu.cpp +++ b/src/frontend/mame/ui/mainmenu.cpp @@ -114,7 +114,7 @@ void menu_main::populate(float &customtop, float &custombottom) item_append(_("Slider Controls"), 0, (void *)SLIDERS); - item_append(_("Video Options"), 0, (machine().render().target_by_index(1) != nullptr) ? (void *)VIDEO_TARGETS : (void *)VIDEO_OPTIONS); + item_append(_("Video Options"), 0, (machine().render().target_by_index(1) || machine().video().snapshot_target().view_name(1)) ? (void *)VIDEO_TARGETS : (void *)VIDEO_OPTIONS); if (machine().crosshair().get_usage()) item_append(_("Crosshair Options"), 0, (void *)CROSSHAIR); @@ -229,7 +229,7 @@ void menu_main::handle() break; case VIDEO_OPTIONS: - menu::stack_push<menu_video_options>(ui(), container(), *machine().render().first_target()); + menu::stack_push<menu_video_options>(ui(), container(), *machine().render().first_target(), false); break; case CROSSHAIR: diff --git a/src/frontend/mame/ui/menu.cpp b/src/frontend/mame/ui/menu.cpp index 068780f2b6e..4fb9616c355 100644 --- a/src/frontend/mame/ui/menu.cpp +++ b/src/frontend/mame/ui/menu.cpp @@ -136,7 +136,6 @@ void menu::global_state::stack_push(std::unique_ptr<menu> &&menu) { menu->m_parent = std::move(m_stack); m_stack = std::move(menu); - m_stack->reset(reset_options::SELECT_FIRST); m_stack->machine().ui_input().reset(); } @@ -289,26 +288,6 @@ void menu::reset(reset_options options) m_items.clear(); m_visible_items = 0; m_selected = 0; - - // add an item to return - if (!m_parent) - { - item_append(_("Return to Machine"), 0, nullptr); - } - else if (m_parent->is_special_main_menu()) - { - if (machine().options().ui() == emu_options::UI_SIMPLE) - item_append(_("Exit"), 0, nullptr); - else - item_append(_("Exit"), FLAG_LEFT_ARROW | FLAG_RIGHT_ARROW, nullptr); - } - else - { - if (machine().options().ui() != emu_options::UI_SIMPLE && stack_has_special_main_menu()) - item_append(_("Return to Previous Menu"), FLAG_LEFT_ARROW | FLAG_RIGHT_ARROW, nullptr); - else - item_append(_("Return to Previous Menu"), 0, nullptr); - } } @@ -403,17 +382,6 @@ void menu::item_append_on_off(const std::string &text, bool state, uint32_t flag //------------------------------------------------- -// repopulate - repopulate menu items -//------------------------------------------------- - -void menu::repopulate(reset_options options) -{ - reset(options); - populate(m_customtop, m_custombottom); -} - - -//------------------------------------------------- // process - process a menu, drawing it // and returning any interesting events //------------------------------------------------- @@ -1201,8 +1169,31 @@ void menu::validate_selection(int scandir) void menu::do_handle() { - if (m_items.size() < 2) + if (m_items.empty()) + { + // add an item to return - this is a really hacky way of doing this + if (!m_parent) + { + item_append(_("Return to Machine"), 0, nullptr); + } + else if (m_parent->is_special_main_menu()) + { + if (machine().options().ui() == emu_options::UI_SIMPLE) + item_append(_("Exit"), 0, nullptr); + else + item_append(_("Exit"), FLAG_LEFT_ARROW | FLAG_RIGHT_ARROW, nullptr); + } + else + { + if (machine().options().ui() != emu_options::UI_SIMPLE && stack_has_special_main_menu()) + item_append(_("Return to Previous Menu"), FLAG_LEFT_ARROW | FLAG_RIGHT_ARROW, nullptr); + else + item_append(_("Return to Previous Menu"), 0, nullptr); + } + + // let implementation add other items populate(m_customtop, m_custombottom); + } handle(); } diff --git a/src/frontend/mame/ui/menu.h b/src/frontend/mame/ui/menu.h index eacbae32609..8cd0057fc58 100644 --- a/src/frontend/mame/ui/menu.h +++ b/src/frontend/mame/ui/menu.h @@ -182,9 +182,6 @@ protected: void add_cleanup_callback(cleanup_callback &&callback) { m_global_state->add_cleanup_callback(std::move(callback)); } - // repopulate the menu items - void repopulate(reset_options options); - // process a menu, drawing it and returning any interesting events const event *process(uint32_t flags, float x0 = 0.0f, float y0 = 0.0f); void process_parent() { m_parent->process(PROCESS_NOINPUT); } diff --git a/src/frontend/mame/ui/miscmenu.cpp b/src/frontend/mame/ui/miscmenu.cpp index 5de57de2ea6..dc5cc2ba9a3 100644 --- a/src/frontend/mame/ui/miscmenu.cpp +++ b/src/frontend/mame/ui/miscmenu.cpp @@ -176,33 +176,23 @@ void menu_network_devices::handle() information menu -------------------------------------------------*/ -void menu_bookkeeping::handle() +menu_bookkeeping::menu_bookkeeping(mame_ui_manager &mui, render_container &container) : menu(mui, container) { - attotime curtime; - - /* if the time has rolled over another second, regenerate */ - curtime = machine().time(); - if (prevtime.seconds() != curtime.seconds()) - { - prevtime = curtime; - repopulate(reset_options::SELECT_FIRST); - } - - /* process the menu */ - process(0); } - -/*------------------------------------------------- - menu_bookkeeping - handle the bookkeeping - information menu --------------------------------------------------*/ -menu_bookkeeping::menu_bookkeeping(mame_ui_manager &mui, render_container &container) : menu(mui, container) +menu_bookkeeping::~menu_bookkeeping() { } -menu_bookkeeping::~menu_bookkeeping() +void menu_bookkeeping::handle() { + /* process the menu */ + process(0); + + /* if the time has rolled over another second, regenerate */ + attotime const curtime = machine().time(); + if (prevtime.seconds() != curtime.seconds()) + reset(reset_options::REMEMBER_POSITION); } void menu_bookkeeping::populate(float &customtop, float &custombottom) @@ -212,6 +202,7 @@ void menu_bookkeeping::populate(float &customtop, float &custombottom) int ctrnum; /* show total time first */ + prevtime = machine().time(); if (prevtime.seconds() >= (60 * 60)) util::stream_format(tempstring, _("Uptime: %1$d:%2$02d:%3$02d\n\n"), prevtime.seconds() / (60 * 60), (prevtime.seconds() / 60) % 60, prevtime.seconds() % 60); else diff --git a/src/frontend/mame/ui/tapectrl.cpp b/src/frontend/mame/ui/tapectrl.cpp index 75d62038931..720622f0e81 100644 --- a/src/frontend/mame/ui/tapectrl.cpp +++ b/src/frontend/mame/ui/tapectrl.cpp @@ -116,14 +116,11 @@ void menu_tape_control::populate(float &customtop, float &custombottom) void menu_tape_control::handle() { - // rebuild the menu (so to update the selected device, if the user has pressed L or R, and the tape counter) - repopulate(reset_options::REMEMBER_POSITION); - // process the menu const event *event = process(PROCESS_LR_REPEAT); if (event != nullptr) { - switch(event->iptkey) + switch (event->iptkey) { case IPT_UI_LEFT: if (event->itemref == TAPECMD_SLIDER) @@ -155,6 +152,9 @@ void menu_tape_control::handle() break; } } + + // hacky way to update the tape counter by repopulating every frame + reset(reset_options::REMEMBER_POSITION); } diff --git a/src/frontend/mame/ui/videoopt.cpp b/src/frontend/mame/ui/videoopt.cpp index ccb39306208..21ba181ecb7 100644 --- a/src/frontend/mame/ui/videoopt.cpp +++ b/src/frontend/mame/ui/videoopt.cpp @@ -55,6 +55,10 @@ void menu_video_targets::populate(float &customtop, float &custombottom) // add a menu item item_append(util::string_format(_("Screen #%d"), targetnum), 0, target); } + + // add option for snapshot target if it has multiple views + if (machine().video().snapshot_target().view_name(1)) + item_append("Snapshot", 0, &machine().video().snapshot_target()); } /*------------------------------------------------- @@ -66,7 +70,15 @@ void menu_video_targets::handle() { event const *const menu_event = process(0); if (menu_event && (menu_event->iptkey == IPT_UI_SELECT)) - menu::stack_push<menu_video_options>(ui(), container(), *reinterpret_cast<render_target *>(menu_event->itemref)); + { + render_target *const target = reinterpret_cast<render_target *>(menu_event->itemref); + menu::stack_push<menu_video_options>( + ui(), + container(), + std::string(selected_item().text), + *target, + &machine().video().snapshot_target() == target); + } } @@ -75,10 +87,35 @@ void menu_video_targets::handle() video options menu -------------------------------------------------*/ -menu_video_options::menu_video_options(mame_ui_manager &mui, render_container &container, render_target &target) +menu_video_options::menu_video_options( + mame_ui_manager &mui, + render_container &container, + render_target &target, + bool snapshot) : menu(mui, container) , m_target(target) + , m_title() + , m_show_title(false) + , m_snapshot(snapshot) { + set_selected_index(target.view()); + reset(reset_options::REMEMBER_POSITION); +} + +menu_video_options::menu_video_options( + mame_ui_manager &mui, + render_container &container, + std::string &&title, + render_target &target, + bool snapshot) + : menu(mui, container) + , m_target(target) + , m_title(std::move(title)) + , m_show_title(true) + , m_snapshot(snapshot) +{ + set_selected_index(target.view() + 2); + reset(reset_options::REMEMBER_POSITION); } menu_video_options::~menu_video_options() @@ -89,6 +126,13 @@ void menu_video_options::populate(float &customtop, float &custombottom) { uintptr_t ref; + // add title if requested + if (m_show_title) + { + item_append(m_title, FLAG_DISABLE, nullptr); + item_append(menu_item_type::SEPARATOR); + } + // add items for each view for (char const *name = m_target.view_name(ref = 0); name; name = m_target.view_name(++ref)) item_append(name, 0, reinterpret_cast<void *>(ITEM_VIEW_FIRST + ref)); @@ -127,33 +171,36 @@ void menu_video_options::populate(float &customtop, float &custombottom) // cropping item_append_on_off(_("Zoom to Screen Area"), m_target.zoom_to_screen(), 0, reinterpret_cast<void *>(ITEM_ZOOM)); - // uneven stretch - switch (m_target.scale_mode()) + if (!m_snapshot) { - case SCALE_FRACTIONAL: - subtext = _("On"); - break; + // uneven stretch + switch (m_target.scale_mode()) + { + case SCALE_FRACTIONAL: + subtext = _("On"); + break; + + case SCALE_FRACTIONAL_X: + subtext = _("X Only"); + break; - case SCALE_FRACTIONAL_X: - subtext = _("X Only"); - break; + case SCALE_FRACTIONAL_Y: + subtext = _("Y Only"); + break; - case SCALE_FRACTIONAL_Y: - subtext = _("Y Only"); - break; + case SCALE_FRACTIONAL_AUTO: + subtext = _("X or Y (Auto)"); + break; - case SCALE_FRACTIONAL_AUTO: - subtext = _("X or Y (Auto)"); - break; + case SCALE_INTEGER: + subtext = _("Off"); + break; + } + item_append(_("Non-Integer Scaling"), subtext, FLAG_LEFT_ARROW | FLAG_RIGHT_ARROW, reinterpret_cast<void *>(ITEM_UNEVENSTRETCH)); - case SCALE_INTEGER: - subtext = _("Off"); - break; + // keep aspect + item_append_on_off(_("Maintain Aspect Ratio"), m_target.keepaspect(), 0, reinterpret_cast<void *>(ITEM_KEEPASPECT)); } - item_append(_("Non-Integer Scaling"), subtext, FLAG_LEFT_ARROW | FLAG_RIGHT_ARROW, reinterpret_cast<void *>(ITEM_UNEVENSTRETCH)); - - // keep aspect - item_append_on_off(_("Keep Aspect"), m_target.keepaspect(), 0, reinterpret_cast<void *>(ITEM_KEEPASPECT)); } @@ -164,6 +211,8 @@ void menu_video_options::populate(float &customtop, float &custombottom) void menu_video_options::handle() { + auto const lockout_popup([this] () { machine().popmessage(_("Cannot change options while recording!")); }); + bool const snap_lockout(m_snapshot && machine().video().is_recording()); bool changed(false); // process the menu @@ -176,6 +225,8 @@ void menu_video_options::handle() case ITEM_ROTATE: if (menu_event->iptkey == IPT_UI_LEFT || menu_event->iptkey == IPT_UI_RIGHT) { + if (snap_lockout) + return lockout_popup(); int const delta((menu_event->iptkey == IPT_UI_LEFT) ? ROT270 : ROT90); m_target.set_orientation(orientation_add(delta, m_target.orientation())); if (m_target.is_ui_target()) @@ -192,6 +243,8 @@ void menu_video_options::handle() case ITEM_ZOOM: if ((menu_event->iptkey == IPT_UI_LEFT) || (menu_event->iptkey == IPT_UI_RIGHT)) { + if (snap_lockout) + return lockout_popup(); m_target.set_zoom_to_screen(menu_event->iptkey == IPT_UI_RIGHT); changed = true; } @@ -201,6 +254,8 @@ void menu_video_options::handle() case ITEM_UNEVENSTRETCH: if (menu_event->iptkey == IPT_UI_LEFT) { + if (snap_lockout) + return lockout_popup(); switch (m_target.scale_mode()) { case SCALE_FRACTIONAL: @@ -227,6 +282,8 @@ void menu_video_options::handle() } else if (menu_event->iptkey == IPT_UI_RIGHT) { + if (snap_lockout) + return lockout_popup(); switch (m_target.scale_mode()) { case SCALE_FRACTIONAL: @@ -257,6 +314,8 @@ void menu_video_options::handle() case ITEM_KEEPASPECT: if ((menu_event->iptkey == IPT_UI_LEFT) || (menu_event->iptkey == IPT_UI_RIGHT)) { + if (snap_lockout) + return lockout_popup(); m_target.set_keepaspect(menu_event->iptkey == IPT_UI_RIGHT); changed = true; } @@ -266,6 +325,8 @@ void menu_video_options::handle() default: if (reinterpret_cast<uintptr_t>(menu_event->itemref) >= ITEM_VIEW_FIRST) { + if (snap_lockout) + return lockout_popup(); if (menu_event->iptkey == IPT_UI_SELECT) { m_target.set_view(reinterpret_cast<uintptr_t>(menu_event->itemref) - ITEM_VIEW_FIRST); @@ -274,6 +335,8 @@ void menu_video_options::handle() } else if (reinterpret_cast<uintptr_t>(menu_event->itemref) >= ITEM_TOGGLE_FIRST) { + if (snap_lockout) + return lockout_popup(); if ((menu_event->iptkey == IPT_UI_LEFT) || (menu_event->iptkey == IPT_UI_RIGHT)) { m_target.set_visibility_toggle(reinterpret_cast<uintptr_t>(menu_event->itemref) - ITEM_TOGGLE_FIRST, menu_event->iptkey == IPT_UI_RIGHT); @@ -284,7 +347,7 @@ void menu_video_options::handle() } } - /* if something changed, rebuild the menu */ + // if something changed, rebuild the menu if (changed) reset(reset_options::REMEMBER_REF); } diff --git a/src/frontend/mame/ui/videoopt.h b/src/frontend/mame/ui/videoopt.h index a70e7b8aa94..44a172cf8f5 100644 --- a/src/frontend/mame/ui/videoopt.h +++ b/src/frontend/mame/ui/videoopt.h @@ -32,7 +32,8 @@ private: class menu_video_options : public menu { public: - menu_video_options(mame_ui_manager &mui, render_container &container, render_target &target); + menu_video_options(mame_ui_manager &mui, render_container &container, render_target &target, bool snapshot); + menu_video_options(mame_ui_manager &mui, render_container &container, std::string &&title, render_target &target, bool snapshot); virtual ~menu_video_options() override; private: @@ -40,6 +41,9 @@ private: virtual void handle() override; render_target &m_target; + std::string const m_title; + bool const m_show_title; + bool const m_snapshot; }; } // namespace ui diff --git a/src/lib/util/strformat.h b/src/lib/util/strformat.h index 2ed90669284..0ce57606436 100644 --- a/src/lib/util/strformat.h +++ b/src/lib/util/strformat.h @@ -106,11 +106,12 @@ The format string type can be a pointer to a NUL-terminated string, an array containing a NUL-terminated or non-terminated string, or a STL contiguous container holding a string (e.g. std::string, - std::vector or std::array). Note that NUL characters characters are - only treated as terminators for pointers and arrays, they are - treated as normal characters for other containers. A non-contiguous - container (e.g. std::list or std::deque) will result in undesirable - behaviour likely culminating in a crash. + std::string_view, std::vector or std::array). Note that NUL + characters characters are only treated as terminators for pointers + and arrays, they are treated as normal characters for other + containers. Using a non-contiguous container (e.g. std::list or + std::deque) will result in undesirable behaviour likely culminating + in a crash. The value type of the format string and the character type of the output stream/string need to match. You can't use a wchar_t format @@ -184,6 +185,7 @@ #include <locale> #include <sstream> #include <string> +#include <string_view> #include <type_traits> #include <utility> @@ -576,10 +578,16 @@ template <typename Stream, typename T> class format_output { private: + template <typename U> struct string_semantics + { static constexpr bool value = false; }; + template <typename CharT, typename Traits, typename Allocator> struct string_semantics<std::basic_string<CharT, Traits, Allocator> > + { static constexpr bool value = true; }; + template <typename CharT, typename Traits> struct string_semantics<std::basic_string_view<CharT, Traits> > + { static constexpr bool value = true; }; template <typename U> struct signed_integer_semantics - { static constexpr bool value = std::is_integral<U>::value && std::is_signed<U>::value; }; + { static constexpr bool value = std::is_integral_v<U>&& std::is_signed_v<U>; }; template <typename U> struct unsigned_integer_semantics - { static constexpr bool value = std::is_integral<U>::value && !std::is_signed<U>::value; }; + { static constexpr bool value = std::is_integral_v<U>&& !std::is_signed_v<U>; }; static void apply_signed(Stream &str, char16_t const &value) { @@ -590,19 +598,14 @@ private: str << std::make_signed_t<std::uint_least32_t>(std::uint_least32_t(value)); } template <typename U> - static std::enable_if_t<std::is_same<std::make_signed_t<U>, std::make_signed_t<char> >::value> apply_signed(Stream &str, U const &value) - { - str << int(std::make_signed_t<U>(value)); - } - template <typename U> - static std::enable_if_t<!std::is_same<std::make_signed_t<U>, std::make_signed_t<char> >::value && signed_integer_semantics<U>::value> apply_signed(Stream &str, U const &value) - { - str << value; - } - template <typename U> - static std::enable_if_t<!std::is_same<std::make_signed_t<U>, std::make_signed_t<char> >::value && unsigned_integer_semantics<U>::value> apply_signed(Stream &str, U const &value) + static std::enable_if_t<std::is_same_v<std::make_signed_t<U>, std::make_signed_t<char> > || std::is_integral_v<U> > apply_signed(Stream &str, U const &value) { - str << std::make_signed_t<U>(value); + if constexpr (std::is_same_v<std::make_signed_t<U>, std::make_signed_t<char> >) + str << int(std::make_signed_t<U>(value)); + else if constexpr (std::is_signed_v<U>) + str << value; + else + str << std::make_signed_t<U>(value); } static void apply_unsigned(Stream &str, char16_t const &value) @@ -614,26 +617,49 @@ private: str << std::uint_least32_t(value); } template <typename U> - static std::enable_if_t<std::is_same<std::make_unsigned_t<U>, std::make_unsigned_t<char> >::value> apply_unsigned(Stream &str, U const &value) - { - str << unsigned(std::make_unsigned_t<U>(value)); - } - template <typename U> - static std::enable_if_t<!std::is_same<std::make_unsigned_t<U>, std::make_unsigned_t<char> >::value && signed_integer_semantics<U>::value> apply_unsigned(Stream &str, U const &value) + static std::enable_if_t<std::is_same_v<std::make_unsigned_t<U>, std::make_unsigned_t<char> > || std::is_integral_v<U> > apply_unsigned(Stream &str, U const &value) { - str << std::make_unsigned_t<U>(value); - } - template <typename U> - static std::enable_if_t<!std::is_same<std::make_unsigned_t<U>, std::make_unsigned_t<char> >::value && unsigned_integer_semantics<U>::value> apply_unsigned(Stream &str, U const &value) - { - str << value; + if constexpr (std::is_same_v<std::make_unsigned_t<U>, std::make_unsigned_t<char> >) + str << unsigned(std::make_unsigned_t<U>(value)); + else if constexpr (std::is_signed_v<U>) + str << std::make_unsigned_t<U>(value); + else + str << value; } public: template <typename U> static void apply(Stream &str, format_flags const &flags, U const &value) { - if constexpr (signed_integer_semantics<U>::value) + if constexpr (string_semantics<U>::value) + { + int const precision(flags.get_precision()); + if ((0 <= precision) && (value.size() > unsigned(precision))) + { + if constexpr (std::is_same_v<typename U::value_type, typename Stream::char_type>) + { + unsigned width(flags.get_field_width()); + bool const pad(unsigned(precision) < width); + typename Stream::fmtflags const adjust(str.flags() & Stream::adjustfield); + if (!pad || (Stream::left == adjust)) str.write(&*value.begin(), unsigned(precision)); + if (pad) + { + for (width -= precision; 0U < width; --width) str.put(str.fill()); + if (Stream::left != adjust) str.write(&*value.begin(), unsigned(precision)); + } + str.width(0); + } + else + { + str << value.substr(0, unsigned(precision)); + } + } + else + { + str << value; + } + } + else if constexpr (signed_integer_semantics<U>::value) { switch (flags.get_conversion()) { @@ -833,35 +859,6 @@ public: str << value; } } - template <typename CharT, typename Traits, typename Allocator> - static void apply(Stream &str, format_flags const &flags, std::basic_string<CharT, Traits, Allocator> const &value) - { - int const precision(flags.get_precision()); - if ((0 <= precision) && (value.size() > unsigned(precision))) - { - if constexpr (std::is_same_v<CharT, typename Stream::char_type>) - { - unsigned width(flags.get_field_width()); - bool const pad(unsigned(precision) < width); - typename Stream::fmtflags const adjust(str.flags() & Stream::adjustfield); - if (!pad || (Stream::left == adjust)) str.write(&*value.begin(), unsigned(precision)); - if (pad) - { - for (width -= precision; 0U < width; --width) str.put(str.fill()); - if (Stream::left != adjust) str.write(&*value.begin(), unsigned(precision)); - } - str.width(0); - } - else - { - str << value.substr(0, unsigned(precision)); - } - } - else - { - str << value; - } - } }; template <typename Stream, typename T> diff --git a/src/mame/drivers/goldnpkr.cpp b/src/mame/drivers/goldnpkr.cpp index e331c4e5630..76455b87f7e 100644 --- a/src/mame/drivers/goldnpkr.cpp +++ b/src/mame/drivers/goldnpkr.cpp @@ -2406,8 +2406,8 @@ SW4 OFF ON OFF ON PORT_DIPSETTING( 0x08, DEF_STR( Off ) ) PORT_DIPSETTING( 0x00, DEF_STR( On ) ) PORT_DIPNAME( 0x10, 0x00, "Minimal Hand" ) PORT_DIPLOCATION("SW2:5") - PORT_DIPSETTING( 0x10, "2 Paar" ) - PORT_DIPSETTING( 0x00, "1 Paar" ) + PORT_DIPSETTING( 0x10, "Two Pairs" ) + PORT_DIPSETTING( 0x00, "High Pair" ) PORT_DIPNAME( 0x20, 0x20, "Frequency" ) PORT_DIPLOCATION("SW2:6") PORT_DIPSETTING( 0x20, "50 Hz." ) PORT_DIPSETTING( 0x00, "60 Hz." ) @@ -2645,6 +2645,16 @@ static INPUT_PORTS_START( witchjol ) PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_OTHER ) PORT_CODE(KEYCODE_6_PAD) PORT_NAME("IN0-1-8") PORT_MODIFY("IN0-2") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_POKER_HOLD1 ) PORT_CONDITION("SW2", 0x08, EQUALS, 0x08) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_POKER_HOLD2 ) PORT_CONDITION("SW2", 0x08, EQUALS, 0x08) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_POKER_HOLD3 ) PORT_CONDITION("SW2", 0x08, EQUALS, 0x08) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_POKER_HOLD4 ) PORT_CONDITION("SW2", 0x08, EQUALS, 0x08) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_POKER_HOLD5 ) PORT_CONDITION("SW2", 0x08, EQUALS, 0x08) + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_POKER_HOLD1 ) PORT_NAME("Hold 1 / Take") PORT_CONDITION("SW2", 0x08, EQUALS, 0x00) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_POKER_HOLD2 ) PORT_NAME("Hold 2 / Small") PORT_CONDITION("SW2", 0x08, EQUALS, 0x00) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_POKER_HOLD3 ) PORT_NAME("Hold 3 / Bet") PORT_CONDITION("SW2", 0x08, EQUALS, 0x00) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_POKER_HOLD4 ) PORT_NAME("Hold 4 / Small") PORT_CONDITION("SW2", 0x08, EQUALS, 0x00) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_POKER_HOLD5 ) PORT_NAME("Hold 5 / Double Up") PORT_CONDITION("SW2", 0x08, EQUALS, 0x00) PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_OTHER ) PORT_CODE(KEYCODE_7_PAD) PORT_NAME("IN0-2-6") PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_OTHER ) PORT_CODE(KEYCODE_8_PAD) PORT_NAME("IN0-2-7") PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_OTHER ) PORT_CODE(KEYCODE_9_PAD) PORT_NAME("IN0-2-8") @@ -2712,12 +2722,12 @@ static INPUT_PORTS_START( witchjol ) PORT_DIPNAME( 0x04, 0x04, "Game Type" ) PORT_DIPLOCATION("SW2:3") PORT_DIPSETTING( 0x04, "Jolli Witch" ) PORT_DIPSETTING( 0x00, "Witch Card" ) - PORT_DIPNAME( 0x08, 0x08, "Taster?" ) PORT_DIPLOCATION("SW2:4") - PORT_DIPSETTING( 0x00, "6 Taster" ) - PORT_DIPSETTING( 0x08, "12 Taster" ) + PORT_DIPNAME( 0x08, 0x08, "Control Type" ) PORT_DIPLOCATION("SW2:4") + PORT_DIPSETTING( 0x00, "6-Button" ) + PORT_DIPSETTING( 0x08, "12-Button" ) PORT_DIPNAME( 0x10, 0x00, "Minimal Hand" ) PORT_DIPLOCATION("SW2:5") - PORT_DIPSETTING( 0x10, "2 Paar" ) - PORT_DIPSETTING( 0x00, "1 Paar" ) + PORT_DIPSETTING( 0x10, "Two Pairs" ) + PORT_DIPSETTING( 0x00, "High Pair" ) PORT_DIPNAME( 0x60, 0x20, "Uncommented 1" ) PORT_DIPLOCATION("SW2:6,7") PORT_DIPSETTING( 0x60, "1 DM - 1 PKT" ) PORT_DIPSETTING( 0x20, "1 DM - 10 PKT" ) @@ -2821,11 +2831,16 @@ static INPUT_PORTS_START( wldwitch ) PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNKNOWN ) PORT_START("IN0-2") - PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_POKER_HOLD1 ) PORT_NAME("Hold 1 / Take") - PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_POKER_HOLD2 ) - PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_POKER_HOLD3 ) - PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_POKER_HOLD4 ) - PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_POKER_HOLD5 ) PORT_NAME("Hold 5 / Double-Up") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_POKER_HOLD1 ) PORT_CONDITION("SW2", 0x08, EQUALS, 0x08) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_POKER_HOLD2 ) PORT_CONDITION("SW2", 0x08, EQUALS, 0x08) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_POKER_HOLD3 ) PORT_CONDITION("SW2", 0x08, EQUALS, 0x08) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_POKER_HOLD4 ) PORT_CONDITION("SW2", 0x08, EQUALS, 0x08) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_POKER_HOLD5 ) PORT_CONDITION("SW2", 0x08, EQUALS, 0x08) + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_POKER_HOLD1 ) PORT_NAME("Hold 1 / Take") PORT_CONDITION("SW2", 0x08, EQUALS, 0x00) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_POKER_HOLD2 ) PORT_NAME("Hold 2 / Small") PORT_CONDITION("SW2", 0x08, EQUALS, 0x00) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_POKER_HOLD3 ) PORT_NAME("Hold 3 / Bet") PORT_CONDITION("SW2", 0x08, EQUALS, 0x00) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_POKER_HOLD4 ) PORT_NAME("Hold 4 / Small") PORT_CONDITION("SW2", 0x08, EQUALS, 0x00) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_POKER_HOLD5 ) PORT_NAME("Hold 5 / Double Up") PORT_CONDITION("SW2", 0x08, EQUALS, 0x00) PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNKNOWN ) PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNKNOWN ) PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNKNOWN ) @@ -2921,11 +2936,11 @@ static INPUT_PORTS_START( wldwitch ) PORT_DIPSETTING( 0x04, "Wild Witch" ) PORT_DIPSETTING( 0x00, "Witch Game" ) PORT_DIPNAME( 0x08, 0x08, "Control Type" ) PORT_DIPLOCATION("SW2:4") - PORT_DIPSETTING( 0x00, "6 Taster" ) - PORT_DIPSETTING( 0x08, "12 Taster" ) + PORT_DIPSETTING( 0x00, "6-Button" ) + PORT_DIPSETTING( 0x08, "12-Button" ) PORT_DIPNAME( 0x10, 0x00, "Minimal Hand" ) PORT_DIPLOCATION("SW2:5") - PORT_DIPSETTING( 0x10, "2 Paar" ) - PORT_DIPSETTING( 0x00, "1 Paar" ) + PORT_DIPSETTING( 0x10, "Two Pairs" ) + PORT_DIPSETTING( 0x00, "High Pair" ) PORT_DIPNAME( 0x20, 0x20, "Uncommented 1" ) PORT_DIPLOCATION("SW2:6") PORT_DIPSETTING( 0x20, "64er" ) PORT_DIPSETTING( 0x00, "128er" ) @@ -3019,8 +3034,8 @@ static INPUT_PORTS_START( wupndown ) PORT_DIPSETTING( 0x08, DEF_STR( Off ) ) PORT_DIPSETTING( 0x00, DEF_STR( On ) ) PORT_DIPNAME( 0x10, 0x00, "Minimal Hand" ) PORT_DIPLOCATION("SW2:5") - PORT_DIPSETTING( 0x10, "2 Paar" ) - PORT_DIPSETTING( 0x00, "Hohes Paar" ) + PORT_DIPSETTING( 0x10, "Two Pairs" ) + PORT_DIPSETTING( 0x00, "High Pair" ) PORT_DIPNAME( 0x20, 0x20, DEF_STR( Unknown ) ) PORT_DIPLOCATION("SW2:6") PORT_DIPSETTING( 0x20, DEF_STR( Off ) ) PORT_DIPSETTING( 0x00, DEF_STR( On ) ) @@ -3211,8 +3226,8 @@ static INPUT_PORTS_START( wtchjack ) PORT_DIPSETTING( 0x08, DEF_STR( Off ) ) PORT_DIPSETTING( 0x00, DEF_STR( On ) ) PORT_DIPNAME( 0x10, 0x00, "Minimal Hand" ) PORT_DIPLOCATION("SW2:5") - PORT_DIPSETTING( 0x10, "2 Paar" ) - PORT_DIPSETTING( 0x00, "Hohes Paar" ) + PORT_DIPSETTING( 0x10, "Two Pairs" ) + PORT_DIPSETTING( 0x00, "High Pair" ) PORT_DIPNAME( 0x20, 0x20, DEF_STR( Unknown ) ) PORT_DIPLOCATION("SW2:6") PORT_DIPSETTING( 0x20, DEF_STR( Off ) ) PORT_DIPSETTING( 0x00, DEF_STR( On ) ) diff --git a/src/mame/layout/goldnpkr.lay b/src/mame/layout/goldnpkr.lay index 92d32275393..a5d11cbeb62 100644 --- a/src/mame/layout/goldnpkr.lay +++ b/src/mame/layout/goldnpkr.lay @@ -4,106 +4,74 @@ license:CC0 --> <mamelayout version="2"> <element name="BET" defstate="0"> - <rect state="1"> - <color red="1.0" green="0.0" blue="0.0" /> - </rect> - <rect state="0"> - <color red="0.3" green="0.0" blue="0.0" /> - </rect> + <rect state="1"><color red="1.0" green="0.0" blue="0.0" /></rect> + <rect state="0"><color red="0.3" green="0.0" blue="0.0" /></rect> <text string="BET"> <color red="0.0" green="0.0" blue="0.0" /> - <bounds x="0" y="0.1" width="1" height="0.8" /> + <bounds x="0.1" y="0.15" width="0.8" height="0.7" /> </text> </element> <element name="DEAL" defstate="0"> - <rect state="1"> - <color red="1.0" green="0.0" blue="0.0" /> - </rect> - <rect state="0"> - <color red="0.3" green="0.0" blue="0.0" /> - </rect> + <rect state="1"><color red="1.0" green="0.0" blue="0.0" /></rect> + <rect state="0"><color red="0.3" green="0.0" blue="0.0" /></rect> <text string="DEAL"> <color red="0.0" green="0.0" blue="0.0" /> - <bounds x="0" y="0.1" width="1" height="0.8" /> + <bounds x="0.1" y="0.15" width="0.8" height="0.7" /> </text> </element> <element name="HOLD" defstate="0"> - <rect state="1"> - <color red="1.0" green="0.5" blue="0.0" /> - </rect> - <rect state="0"> - <color red="0.3" green="0.1" blue="0.0" /> - </rect> + <rect state="1"><color red="1.0" green="0.5" blue="0.0" /></rect> + <rect state="0"><color red="0.3" green="0.1" blue="0.0" /></rect> <text string="HOLD"> <color red="0.0" green="0.0" blue="0.0" /> - <bounds x="0" y="0.1" width="1" height="0.8" /> + <bounds x="0.1" y="0.15" width="0.8" height="0.7" /> </text> </element> <element name="D-UP" defstate="0"> - <rect state="1"> - <color red="1.0" green="1.0" blue="1.0" /> - </rect> - <rect state="0"> - <color red="0.2" green="0.2" blue="0.2" /> - </rect> + <rect state="1"><color red="1.0" green="1.0" blue="1.0" /></rect> + <rect state="0"><color red="0.2" green="0.2" blue="0.2" /></rect> <text string="D-UP"> <color red="0.0" green="0.0" blue="0.0" /> - <bounds x="0" y="0.1" width="1" height="0.8" /> + <bounds x="0.1" y="0.15" width="0.8" height="0.7" /> </text> </element> <element name="TAKE" defstate="0"> - <rect state="1"> - <color red="1.0" green="1.0" blue="1.0" /> - </rect> - <rect state="0"> - <color red="0.2" green="0.2" blue="0.2" /> - </rect> + <rect state="1"><color red="1.0" green="1.0" blue="1.0" /></rect> + <rect state="0"><color red="0.2" green="0.2" blue="0.2" /></rect> <text string="TAKE"> <color red="0.0" green="0.0" blue="0.0" /> - <bounds x="0" y="0.1" width="1" height="0.8" /> + <bounds x="0.1" y="0.15" width="0.8" height="0.7" /> </text> </element> <element name="BIG" defstate="0"> - <rect state="1"> - <color red="1.0" green="1.0" blue="1.0" /> - </rect> - <rect state="0"> - <color red="0.2" green="0.2" blue="0.2" /> - </rect> + <rect state="1"><color red="1.0" green="1.0" blue="1.0" /></rect> + <rect state="0"><color red="0.2" green="0.2" blue="0.2" /></rect> <text string="BIG"> <color red="0.0" green="0.0" blue="0.0" /> - <bounds x="0" y="0.1" width="1" height="0.8" /> + <bounds x="0.1" y="0.15" width="0.8" height="0.7" /> </text> </element> <element name="SMALL" defstate="0"> - <rect state="1"> - <color red="1.0" green="1.0" blue="1.0" /> - </rect> - <rect state="0"> - <color red="0.2" green="0.2" blue="0.2" /> - </rect> + <rect state="1"><color red="1.0" green="1.0" blue="1.0" /></rect> + <rect state="0"><color red="0.2" green="0.2" blue="0.2" /></rect> <text string="SMALL"> <color red="0.0" green="0.0" blue="0.0" /> - <bounds x="0" y="0.1" width="1" height="0.8" /> + <bounds x="0.1" y="0.15" width="0.8" height="0.7" /> </text> </element> <element name="CANCEL" defstate="0"> - <rect state="1"> - <color red="1.0" green="0.0" blue="0.0" /> - </rect> - <rect state="0"> - <color red="0.3" green="0.0" blue="0.0" /> - </rect> + <rect state="1"><color red="1.0" green="0.0" blue="0.0" /></rect> + <rect state="0"><color red="0.3" green="0.0" blue="0.0" /></rect> <text string="CANCEL"> <color red="0.0" green="0.0" blue="0.0" /> - <bounds x="0" y="0.1" width="1" height="0.8" /> + <bounds x="0.1" y="0.15" width="0.8" height="0.7" /> </text> </element> @@ -111,41 +79,43 @@ license:CC0 <screen index="0"> <bounds left="0" top="0" right="4" bottom="3" /> </screen> - <element name="lamp0" ref="BET" inputtag="IN0-0" inputmask="0x01"> - <bounds x="3.0" y="3.45" width="0.40" height="0.24" /> - </element> - <element name="lamp1" ref="DEAL" inputtag="IN0-0" inputmask="0x08"> - <bounds x="2.5" y="3.45" width="0.40" height="0.24" /> - </element> + <element name="lamp2" ref="HOLD" inputtag="IN0-2" inputmask="0x01"> - <bounds x="0.0" y="3.13" width="0.40" height="0.24" /> - </element> - <element name="lamp3" ref="D-UP" inputtag="IN0-0" inputmask="0x04"> - <bounds x="1.5" y="3.45" width="0.40" height="0.24" /> - </element> - <element name="lamp4" ref="BIG" inputtag="IN0-1" inputmask="0x08"> - <bounds x="0.5" y="3.45" width="0.40" height="0.24" /> + <bounds x="0.25" y="3.13" width="0.50" height="0.24" /> </element> <element name="lamp2" ref="HOLD" inputtag="IN0-2" inputmask="0x02"> - <bounds x="0.5" y="3.13" width="0.40" height="0.24" /> + <bounds x="0.85" y="3.13" width="0.50" height="0.24" /> </element> <element name="lamp2" ref="HOLD" inputtag="IN0-2" inputmask="0x04"> - <bounds x="1.0" y="3.13" width="0.40" height="0.24" /> + <bounds x="1.45" y="3.13" width="0.50" height="0.24" /> </element> <element name="lamp2" ref="HOLD" inputtag="IN0-2" inputmask="0x08"> - <bounds x="1.5" y="3.13" width="0.40" height="0.24" /> + <bounds x="2.05" y="3.13" width="0.50" height="0.24" /> </element> <element name="lamp2" ref="HOLD" inputtag="IN0-2" inputmask="0x10"> - <bounds x="2.0" y="3.13" width="0.40" height="0.24" /> + <bounds x="2.65" y="3.13" width="0.50" height="0.24" /> + </element> + <element name="lamp2" ref="CANCEL" inputtag="IN0-0" inputmask="0x10"> + <bounds x="3.25" y="3.13" width="0.50" height="0.24" /> </element> + <element name="lamp3" ref="TAKE" inputtag="IN0-1" inputmask="0x04"> - <bounds x="2.0" y="3.45" width="0.40" height="0.24" /> + <bounds x="0.25" y="3.45" width="0.50" height="0.24" /> </element> <element name="lamp4" ref="SMALL" inputtag="IN0-1" inputmask="0x10"> - <bounds x="1.0" y="3.45" width="0.40" height="0.24" /> + <bounds x="0.85" y="3.45" width="0.50" height="0.24" /> </element> - <element name="lamp2" ref="CANCEL" inputtag="IN0-0" inputmask="0x10"> - <bounds x="0.0" y="3.45" width="0.40" height="0.24" /> + <element name="lamp0" ref="BET" inputtag="IN0-0" inputmask="0x01"> + <bounds x="1.45" y="3.45" width="0.50" height="0.24" /> + </element> + <element name="lamp4" ref="BIG" inputtag="IN0-1" inputmask="0x08"> + <bounds x="2.05" y="3.45" width="0.50" height="0.24" /> + </element> + <element name="lamp3" ref="D-UP" inputtag="IN0-0" inputmask="0x04"> + <bounds x="2.65" y="3.45" width="0.50" height="0.24" /> + </element> + <element name="lamp1" ref="DEAL" inputtag="IN0-0" inputmask="0x08"> + <bounds x="3.25" y="3.45" width="0.50" height="0.24" /> </element> </view> </mamelayout> |