mirror of
https://github.com/holub/mame
synced 2025-04-20 23:42:22 +03:00
Extend mame LUA api (nw)
This commit is contained in:
parent
94f44bbcea
commit
6db430bafc
@ -26,9 +26,10 @@ currently available to LUA scripts:
|
||||
* machine metadata (app version, current rom, rom details)
|
||||
* machine control (starting, pausing, resetting, stopping)
|
||||
* machine hooks (on frame painting and on user events)
|
||||
* machine options (hard reset required for options to take affect)
|
||||
* devices introspection (device tree listing, memory and register enumeration)
|
||||
* screens introspection (screens listing, screen details, frames counting)
|
||||
* screen HUD drawing (text, lines, boxes on multiple screens)
|
||||
* screen snaps and HUD drawing (text, lines, boxes on multiple screens)
|
||||
* memory read/write (8/16/32/64 bits, signed and unsigned)
|
||||
* registers and states control (states enumeration, get and set)
|
||||
|
||||
@ -155,3 +156,22 @@ program
|
||||
41
|
||||
```
|
||||
|
||||
manager:machine().options[]
|
||||
```
|
||||
> opts = manager:machine().options
|
||||
> for k, entry in pairs(opts) do print(string.format("%10s: %s\n%11s %s", k, entry:value(), "", entry:description())) end
|
||||
diff_directory: diff
|
||||
directory to save hard drive image differeVnce files
|
||||
joystick_contradictory: false
|
||||
enable contradictory direction digital joystick input at the same time
|
||||
scalemode: none
|
||||
Scale mode: none, hwblit, hwbest, yv12, yuy2, yv12x2, yuy2x2 (-video soft only)
|
||||
oslog: false
|
||||
output error.log data to the system debugger
|
||||
[...]
|
||||
> print(opts["sleep"]:value())
|
||||
true
|
||||
> print(opts["sleep"]:value("invalid"))
|
||||
Illegal boolean value for sleep: "invalid"; reverting to 0
|
||||
false
|
||||
```
|
||||
|
@ -373,6 +373,34 @@ void lua_engine::emu_set_hook(lua_State *L)
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// machine_options - return table of options
|
||||
// -> manager:machine().options[]
|
||||
//-------------------------------------------------
|
||||
|
||||
luabridge::LuaRef lua_engine::l_machine_get_options(const running_machine *r)
|
||||
{
|
||||
lua_State *L = luaThis->m_lua_state;
|
||||
luabridge::LuaRef options_table = luabridge::LuaRef::newTable(L);
|
||||
|
||||
int unadorned_index = 0;
|
||||
for (core_options::entry *curentry = r->options().first(); curentry != nullptr; curentry = curentry->next())
|
||||
{
|
||||
const char *name = curentry->name();
|
||||
bool is_unadorned = false;
|
||||
// check if it's unadorned
|
||||
if (name && strlen(name) && !strcmp(name, core_options::unadorned(unadorned_index)))
|
||||
{
|
||||
unadorned_index++;
|
||||
is_unadorned = true;
|
||||
}
|
||||
if (!curentry->is_header() && !curentry->is_command() && !curentry->is_internal() && !is_unadorned)
|
||||
options_table[name] = curentry;
|
||||
}
|
||||
|
||||
return options_table;
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// machine_get_screens - return table of available screens userdata
|
||||
// -> manager:machine().screens[":screen"]
|
||||
@ -591,6 +619,47 @@ int lua_engine::lua_addr_space::l_mem_write(lua_State *L)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lua_engine::lua_options_entry::l_entry_value(lua_State *L)
|
||||
{
|
||||
core_options::entry *e = luabridge::Stack<core_options::entry *>::get(L, 1);
|
||||
if(!e) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
luaL_argcheck(L, !lua_isfunction(L, 2), 2, "optional argument: unsupported value");
|
||||
|
||||
if (!lua_isnone(L, 2))
|
||||
{
|
||||
std::string error;
|
||||
luaThis->machine().options().set_value(e->name(),
|
||||
lua_isboolean(L, 2) ? (lua_toboolean(L, 2) ? "1" : "0") : lua_tostring(L, 2),
|
||||
OPTION_PRIORITY_CMDLINE, error);
|
||||
|
||||
if (!error.empty())
|
||||
{
|
||||
lua_writestringerror("%s", error.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
switch (e->type())
|
||||
{
|
||||
case OPTION_BOOLEAN:
|
||||
lua_pushboolean(L, (atoi(e->value()) != 0));
|
||||
break;
|
||||
case OPTION_INTEGER:
|
||||
lua_pushnumber(L, atoi(e->value()));
|
||||
break;
|
||||
case OPTION_FLOAT:
|
||||
lua_pushnumber(L, atof(e->value()));
|
||||
break;
|
||||
default:
|
||||
lua_pushstring(L, e->value());
|
||||
break;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// screen_height - return screen visible height
|
||||
// -> manager:machine().screens[":screen"]:height()
|
||||
@ -623,6 +692,86 @@ int lua_engine::lua_screen::l_width(lua_State *L)
|
||||
return 1;
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// screen_refresh - return screen refresh rate
|
||||
// -> manager:machine().screens[":screen"]:refresh()
|
||||
//-------------------------------------------------
|
||||
|
||||
int lua_engine::lua_screen::l_refresh(lua_State *L)
|
||||
{
|
||||
screen_device *sc = luabridge::Stack<screen_device *>::get(L, 1);
|
||||
if(!sc) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
lua_pushnumber(L, ATTOSECONDS_TO_HZ(sc->refresh_attoseconds()));
|
||||
return 1;
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// screen_snapshot - save png bitmap of screen to snapshots folder
|
||||
// -> manager:machine().screens[":screen"]:snapshot("filename.png")
|
||||
//-------------------------------------------------
|
||||
|
||||
int lua_engine::lua_screen::l_snapshot(lua_State *L)
|
||||
{
|
||||
screen_device *sc = luabridge::Stack<screen_device *>::get(L, 1);
|
||||
if(!sc || !sc->machine().render().is_live(*sc))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
luaL_argcheck(L, lua_isstring(L, 2) || lua_isnone(L, 2), 2, "optional argument: filename, string expected");
|
||||
|
||||
emu_file file(sc->machine().options().snapshot_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS);
|
||||
file_error filerr;
|
||||
|
||||
if (!lua_isnone(L, 5)) {
|
||||
const char *filename = lua_tostring(L, 2);
|
||||
std::string snapstr(filename);
|
||||
strreplace(snapstr, "/", PATH_SEPARATOR);
|
||||
strreplace(snapstr, "%g", sc->machine().basename());
|
||||
filerr = file.open(snapstr.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
filerr = sc->machine().video().open_next(file, "png");
|
||||
}
|
||||
|
||||
if (filerr != FILERR_NONE)
|
||||
{
|
||||
lua_writestringerror("Error creating snapshot, file_error=%d", filerr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
sc->machine().video().save_snapshot(sc, file);
|
||||
file.close();
|
||||
return 1;
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// screen_type - return human readable screen type
|
||||
// -> manager:machine().screens[":screen"]:type()
|
||||
//-------------------------------------------------
|
||||
|
||||
int lua_engine::lua_screen::l_type(lua_State *L)
|
||||
{
|
||||
screen_device *sc = luabridge::Stack<screen_device *>::get(L, 1);
|
||||
if(!sc) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (sc->screen_type())
|
||||
{
|
||||
case SCREEN_TYPE_RASTER: lua_pushliteral(L, "raster"); break;
|
||||
case SCREEN_TYPE_VECTOR: lua_pushliteral(L, "vector"); break;
|
||||
case SCREEN_TYPE_LCD: lua_pushliteral(L, "lcd"); break;
|
||||
default: lua_pushliteral(L, "unknown"); break;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// draw_box - draw a box on a screen container
|
||||
// -> manager:machine().screens[":screen"]:draw_box(x1, y1, x2, y2, bgcolor, linecolor)
|
||||
@ -1087,12 +1236,17 @@ void lua_engine::initialize()
|
||||
.addFunction ("system", &running_machine::system)
|
||||
.addProperty <luabridge::LuaRef, void> ("devices", &lua_engine::l_machine_get_devices)
|
||||
.addProperty <luabridge::LuaRef, void> ("screens", &lua_engine::l_machine_get_screens)
|
||||
.addProperty <luabridge::LuaRef, void> ("options", &lua_engine::l_machine_get_options)
|
||||
.endClass ()
|
||||
.beginClass <game_driver> ("game_driver")
|
||||
.addData ("source_file", &game_driver::source_file)
|
||||
.addData ("parent", &game_driver::parent)
|
||||
.addData ("name", &game_driver::name)
|
||||
.addData ("description", &game_driver::description)
|
||||
.addData ("year", &game_driver::year)
|
||||
.addData ("manufacturer", &game_driver::manufacturer)
|
||||
.addData ("compatible_with", &game_driver::compatible_with)
|
||||
.addData ("default_layout", &game_driver::default_layout)
|
||||
.endClass ()
|
||||
.beginClass <device_t> ("device")
|
||||
.addFunction ("name", &device_t::name)
|
||||
@ -1101,6 +1255,16 @@ void lua_engine::initialize()
|
||||
.addProperty <luabridge::LuaRef, void> ("spaces", &lua_engine::l_dev_get_memspaces)
|
||||
.addProperty <luabridge::LuaRef, void> ("state", &lua_engine::l_dev_get_states)
|
||||
.endClass()
|
||||
.beginClass <lua_options_entry> ("lua_options_entry")
|
||||
.addCFunction ("value", &lua_options_entry::l_entry_value)
|
||||
.endClass()
|
||||
.deriveClass <core_options::entry, lua_options_entry> ("core_options_entry")
|
||||
.addFunction ("description", &core_options::entry::description)
|
||||
.addFunction ("default_value", &core_options::entry::default_value)
|
||||
.addFunction ("minimum", &core_options::entry::minimum)
|
||||
.addFunction ("maximum", &core_options::entry::maximum)
|
||||
.addFunction ("has_range", &core_options::entry::has_range)
|
||||
.endClass()
|
||||
.beginClass <lua_addr_space> ("lua_addr_space")
|
||||
.addCFunction ("read_i8", &lua_addr_space::l_mem_read<INT8>)
|
||||
.addCFunction ("read_u8", &lua_addr_space::l_mem_read<UINT8>)
|
||||
@ -1128,12 +1292,17 @@ void lua_engine::initialize()
|
||||
.addCFunction ("draw_text", &lua_screen::l_draw_text)
|
||||
.addCFunction ("height", &lua_screen::l_height)
|
||||
.addCFunction ("width", &lua_screen::l_width)
|
||||
.addCFunction ("refresh", &lua_screen::l_refresh)
|
||||
.addCFunction ("snapshot", &lua_screen::l_snapshot)
|
||||
.addCFunction ("type", &lua_screen::l_type)
|
||||
.endClass()
|
||||
.deriveClass <screen_device, lua_screen> ("screen_dev")
|
||||
.addFunction ("frame_number", &screen_device::frame_number)
|
||||
.addFunction ("name", &screen_device::name)
|
||||
.addFunction ("shortname", &screen_device::shortname)
|
||||
.addFunction ("tag", &screen_device::tag)
|
||||
.addFunction ("xscale", &screen_device::xscale)
|
||||
.addFunction ("yscale", &screen_device::yscale)
|
||||
.endClass()
|
||||
.beginClass <device_state_entry> ("dev_space")
|
||||
.addFunction ("name", &device_state_entry::symbol)
|
||||
|
@ -118,6 +118,7 @@ private:
|
||||
static int register_function(lua_State *L, const char *id);
|
||||
|
||||
// "emu.machine" namespace
|
||||
static luabridge::LuaRef l_machine_get_options(const running_machine *r);
|
||||
static luabridge::LuaRef l_machine_get_devices(const running_machine *r);
|
||||
static luabridge::LuaRef devtree_dfs(device_t *root, luabridge::LuaRef dev_table);
|
||||
static luabridge::LuaRef l_dev_get_states(const device_t *d);
|
||||
@ -132,11 +133,18 @@ private:
|
||||
struct lua_screen {
|
||||
int l_height(lua_State *L);
|
||||
int l_width(lua_State *L);
|
||||
int l_refresh(lua_State *L);
|
||||
int l_type(lua_State *L);
|
||||
int l_snapshot(lua_State *L);
|
||||
int l_draw_box(lua_State *L);
|
||||
int l_draw_line(lua_State *L);
|
||||
int l_draw_text(lua_State *L);
|
||||
};
|
||||
|
||||
struct lua_options_entry {
|
||||
int l_entry_value(lua_State *L);
|
||||
};
|
||||
|
||||
void resume(void *L, INT32 param);
|
||||
void start();
|
||||
static int luaopen_ioport(lua_State *L);
|
||||
|
@ -76,6 +76,7 @@ public:
|
||||
// misc
|
||||
void toggle_throttle();
|
||||
void toggle_record_movie();
|
||||
file_error open_next(emu_file &file, const char *extension);
|
||||
|
||||
// render a frame
|
||||
void frame_update(bool debug = false);
|
||||
@ -127,7 +128,6 @@ private:
|
||||
|
||||
// snapshot/movie helpers
|
||||
void create_snapshot_bitmap(screen_device *screen);
|
||||
file_error open_next(emu_file &file, const char *extension);
|
||||
void record_frame();
|
||||
|
||||
// internal state
|
||||
|
Loading…
Reference in New Issue
Block a user