Extend mame LUA api (nw)

This commit is contained in:
Jeffrey Clark 2016-02-14 16:58:51 -06:00
parent 94f44bbcea
commit 6db430bafc
4 changed files with 199 additions and 2 deletions

View File

@ -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
```

View File

@ -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)

View File

@ -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);

View File

@ -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