2018-08-20 22:25:08 +08:00
|
|
|
// Aseprite
|
2023-01-07 06:50:04 +08:00
|
|
|
// Copyright (C) 2018-2023 Igara Studio S.A.
|
2018-08-20 22:25:08 +08:00
|
|
|
// Copyright (C) 2001-2018 David Capello
|
|
|
|
//
|
|
|
|
// This program is distributed under the terms of
|
|
|
|
// the End-User License Agreement for Aseprite.
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include "config.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "app/script/engine.h"
|
|
|
|
|
|
|
|
#include "app/app.h"
|
|
|
|
#include "app/console.h"
|
2019-01-09 03:42:01 +08:00
|
|
|
#include "app/doc_exporter.h"
|
2018-11-23 23:56:30 +08:00
|
|
|
#include "app/doc_range.h"
|
2021-04-23 00:00:13 +08:00
|
|
|
#include "app/pref/preferences.h"
|
2018-08-20 22:25:08 +08:00
|
|
|
#include "app/script/luacpp.h"
|
2018-09-18 00:14:56 +08:00
|
|
|
#include "app/script/security.h"
|
2019-01-09 03:42:01 +08:00
|
|
|
#include "app/sprite_sheet_type.h"
|
2020-07-15 04:27:40 +08:00
|
|
|
#include "app/tilemap_mode.h"
|
2019-03-30 02:57:10 +08:00
|
|
|
#include "app/tileset_mode.h"
|
2020-05-22 22:15:15 +08:00
|
|
|
#include "app/tools/ink_type.h"
|
2018-09-04 00:29:10 +08:00
|
|
|
#include "base/chrono.h"
|
2018-09-14 03:55:53 +08:00
|
|
|
#include "base/file_handle.h"
|
2018-09-06 22:48:18 +08:00
|
|
|
#include "base/fs.h"
|
2018-08-20 22:25:08 +08:00
|
|
|
#include "base/fstream_path.h"
|
2018-09-12 05:29:15 +08:00
|
|
|
#include "doc/anidir.h"
|
|
|
|
#include "doc/blend_mode.h"
|
2018-08-20 22:25:08 +08:00
|
|
|
#include "doc/color_mode.h"
|
2019-07-16 06:12:44 +08:00
|
|
|
#include "filters/target.h"
|
2022-12-27 02:33:14 +08:00
|
|
|
#include "ui/cursor_type.h"
|
2020-03-28 03:14:00 +08:00
|
|
|
#include "ui/mouse_button.h"
|
2018-08-20 22:25:08 +08:00
|
|
|
|
|
|
|
#include <fstream>
|
|
|
|
#include <sstream>
|
2018-11-22 04:42:47 +08:00
|
|
|
#include <stack>
|
|
|
|
#include <string>
|
2018-08-20 22:25:08 +08:00
|
|
|
|
|
|
|
namespace app {
|
|
|
|
namespace script {
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
2018-09-04 00:29:10 +08:00
|
|
|
// High precision clock.
|
|
|
|
base::Chrono luaClock;
|
|
|
|
|
2018-11-22 04:42:47 +08:00
|
|
|
// Stack of script filenames that are being executed.
|
|
|
|
std::stack<std::string> current_script_dirs;
|
|
|
|
|
2021-10-05 08:17:33 +08:00
|
|
|
// Just one debugger delegate is possible.
|
|
|
|
DebuggerDelegate* g_debuggerDelegate = nullptr;
|
|
|
|
|
2018-11-22 04:42:47 +08:00
|
|
|
class AddScriptFilename {
|
|
|
|
public:
|
|
|
|
AddScriptFilename(const std::string& fn) {
|
|
|
|
current_script_dirs.push(fn);
|
|
|
|
}
|
|
|
|
~AddScriptFilename() {
|
|
|
|
current_script_dirs.pop();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2018-08-20 22:25:08 +08:00
|
|
|
int print(lua_State* L)
|
|
|
|
{
|
|
|
|
std::string output;
|
|
|
|
int n = lua_gettop(L); /* number of arguments */
|
|
|
|
int i;
|
|
|
|
lua_getglobal(L, "tostring");
|
|
|
|
for (i=1; i<=n; i++) {
|
|
|
|
lua_pushvalue(L, -1); // function to be called
|
|
|
|
lua_pushvalue(L, i); // value to print
|
|
|
|
lua_call(L, 1, 1);
|
|
|
|
size_t l;
|
|
|
|
const char* s = lua_tolstring(L, -1, &l); // get result
|
|
|
|
if (s == nullptr)
|
|
|
|
return luaL_error(L, "'tostring' must return a string to 'print'");
|
|
|
|
if (i > 1)
|
|
|
|
output.push_back('\t');
|
|
|
|
output.insert(output.size(), s, l);
|
|
|
|
lua_pop(L, 1); // pop result
|
|
|
|
}
|
|
|
|
if (!output.empty()) {
|
2019-12-12 10:46:33 +08:00
|
|
|
auto app = App::instance();
|
|
|
|
if (app && app->scriptEngine())
|
|
|
|
app->scriptEngine()->consolePrint(output.c_str());
|
|
|
|
else {
|
|
|
|
std::printf("%s\n", output.c_str());
|
|
|
|
std::fflush(stdout);
|
|
|
|
}
|
2018-08-20 22:25:08 +08:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-11-22 04:42:47 +08:00
|
|
|
static int dofilecont(lua_State *L, int d1, lua_KContext d2)
|
|
|
|
{
|
|
|
|
(void)d1;
|
|
|
|
(void)d2;
|
|
|
|
return lua_gettop(L) - 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int dofile(lua_State *L)
|
|
|
|
{
|
|
|
|
const char* argFname = luaL_optstring(L, 1, NULL);
|
|
|
|
std::string fname = argFname;
|
|
|
|
|
|
|
|
if (!base::is_file(fname) &&
|
|
|
|
!current_script_dirs.empty()) {
|
|
|
|
// Try to complete a relative filename
|
|
|
|
std::string altFname =
|
|
|
|
base::join_path(base::get_file_path(current_script_dirs.top()),
|
|
|
|
fname);
|
|
|
|
if (base::is_file(altFname))
|
|
|
|
fname = altFname;
|
|
|
|
}
|
|
|
|
|
|
|
|
lua_settop(L, 1);
|
|
|
|
if (luaL_loadfile(L, fname.c_str()) != LUA_OK)
|
|
|
|
return lua_error(L);
|
|
|
|
{
|
|
|
|
AddScriptFilename add(fname);
|
|
|
|
lua_callk(L, 0, LUA_MULTRET, 0, dofilecont);
|
|
|
|
}
|
|
|
|
return dofilecont(L, 0, 0);
|
|
|
|
}
|
|
|
|
|
2018-09-04 00:29:10 +08:00
|
|
|
int os_clock(lua_State* L)
|
|
|
|
{
|
|
|
|
lua_pushnumber(L, luaClock.elapsed());
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2018-09-03 23:08:47 +08:00
|
|
|
int unsupported(lua_State* L)
|
|
|
|
{
|
|
|
|
// debug.getinfo(1, "n").name
|
|
|
|
lua_getglobal(L, "debug");
|
|
|
|
lua_getfield(L, -1, "getinfo");
|
|
|
|
lua_remove(L, -2);
|
|
|
|
lua_pushinteger(L, 1);
|
|
|
|
lua_pushstring(L, "n");
|
|
|
|
lua_call(L, 2, 1);
|
|
|
|
lua_getfield(L, -1, "name");
|
|
|
|
return luaL_error(L, "unsupported function '%s'",
|
|
|
|
lua_tostring(L, -1));
|
|
|
|
}
|
|
|
|
|
2018-08-20 22:25:08 +08:00
|
|
|
} // anonymous namespace
|
|
|
|
|
|
|
|
void register_app_object(lua_State* L);
|
|
|
|
void register_app_pixel_color_object(lua_State* L);
|
2019-12-12 02:39:40 +08:00
|
|
|
void register_app_fs_object(lua_State* L);
|
2018-09-05 04:21:33 +08:00
|
|
|
void register_app_command_object(lua_State* L);
|
2019-04-25 08:14:20 +08:00
|
|
|
void register_app_preferences_object(lua_State* L);
|
2018-08-20 22:25:08 +08:00
|
|
|
|
2019-04-19 09:23:33 +08:00
|
|
|
void register_brush_class(lua_State* L);
|
2018-09-05 03:10:32 +08:00
|
|
|
void register_cel_class(lua_State* L);
|
|
|
|
void register_cels_class(lua_State* L);
|
|
|
|
void register_color_class(lua_State* L);
|
2019-01-04 04:17:10 +08:00
|
|
|
void register_color_space_class(lua_State* L);
|
2020-07-28 21:35:38 +08:00
|
|
|
#ifdef ENABLE_UI
|
2018-10-11 23:01:21 +08:00
|
|
|
void register_dialog_class(lua_State* L);
|
2022-12-15 04:04:50 +08:00
|
|
|
void register_graphics_context_class(lua_State* L);
|
2023-03-14 05:18:44 +08:00
|
|
|
void register_paint_class(lua_State* L);
|
2020-07-28 21:35:38 +08:00
|
|
|
#endif
|
2021-10-08 05:56:39 +08:00
|
|
|
void register_events_class(lua_State* L);
|
2018-09-05 03:10:32 +08:00
|
|
|
void register_frame_class(lua_State* L);
|
|
|
|
void register_frames_class(lua_State* L);
|
2019-03-30 02:57:10 +08:00
|
|
|
void register_grid_class(lua_State* L);
|
2018-08-20 22:25:08 +08:00
|
|
|
void register_image_class(lua_State* L);
|
2018-09-04 05:04:44 +08:00
|
|
|
void register_image_iterator_class(lua_State* L);
|
2018-09-12 07:31:37 +08:00
|
|
|
void register_image_spec_class(lua_State* L);
|
2018-11-23 23:56:30 +08:00
|
|
|
void register_images_class(lua_State* L);
|
2018-09-05 03:10:32 +08:00
|
|
|
void register_layer_class(lua_State* L);
|
|
|
|
void register_layers_class(lua_State* L);
|
|
|
|
void register_palette_class(lua_State* L);
|
|
|
|
void register_palettes_class(lua_State* L);
|
2020-04-03 02:47:12 +08:00
|
|
|
void register_plugin_class(lua_State* L);
|
2018-08-20 22:25:08 +08:00
|
|
|
void register_point_class(lua_State* L);
|
2022-12-31 01:51:43 +08:00
|
|
|
void register_properties_class(lua_State* L);
|
2018-11-23 23:56:30 +08:00
|
|
|
void register_range_class(lua_State* L);
|
2018-08-20 22:25:08 +08:00
|
|
|
void register_rect_class(lua_State* L);
|
|
|
|
void register_selection_class(lua_State* L);
|
|
|
|
void register_site_class(lua_State* L);
|
|
|
|
void register_size_class(lua_State* L);
|
2018-09-05 03:10:32 +08:00
|
|
|
void register_slice_class(lua_State* L);
|
|
|
|
void register_slices_class(lua_State* L);
|
2018-08-20 22:25:08 +08:00
|
|
|
void register_sprite_class(lua_State* L);
|
2018-09-12 23:55:56 +08:00
|
|
|
void register_sprites_class(lua_State* L);
|
2018-09-05 03:10:32 +08:00
|
|
|
void register_tag_class(lua_State* L);
|
|
|
|
void register_tags_class(lua_State* L);
|
2022-12-16 20:50:36 +08:00
|
|
|
void register_theme_classes(lua_State* L);
|
2023-01-07 06:50:04 +08:00
|
|
|
void register_tile_class(lua_State* L);
|
2019-03-30 02:57:10 +08:00
|
|
|
void register_tileset_class(lua_State* L);
|
|
|
|
void register_tilesets_class(lua_State* L);
|
2023-02-23 07:00:07 +08:00
|
|
|
void register_timer_class(lua_State* L);
|
2019-03-23 20:18:59 +08:00
|
|
|
void register_tool_class(lua_State* L);
|
2019-04-21 11:04:49 +08:00
|
|
|
void register_version_class(lua_State* L);
|
2021-09-30 23:13:16 +08:00
|
|
|
void register_websocket_class(lua_State* L);
|
2018-08-20 22:25:08 +08:00
|
|
|
|
2018-12-11 03:44:49 +08:00
|
|
|
void set_app_params(lua_State* L, const Params& params);
|
|
|
|
|
2018-09-14 03:55:53 +08:00
|
|
|
// We use our own fopen() that supports Unicode filename on Windows
|
|
|
|
extern "C" FILE* lua_user_fopen(const char* fname,
|
|
|
|
const char* mode)
|
|
|
|
{
|
|
|
|
return base::open_file_raw(fname, mode);
|
|
|
|
}
|
|
|
|
|
2018-09-01 01:30:32 +08:00
|
|
|
Engine::Engine()
|
2018-08-20 22:25:08 +08:00
|
|
|
: L(luaL_newstate())
|
2018-09-01 01:30:32 +08:00
|
|
|
, m_delegate(nullptr)
|
2018-08-20 22:25:08 +08:00
|
|
|
, m_printLastResult(false)
|
|
|
|
{
|
2018-09-11 01:35:54 +08:00
|
|
|
#if _DEBUG
|
2018-08-20 22:25:08 +08:00
|
|
|
int top = lua_gettop(L);
|
2018-09-11 01:35:54 +08:00
|
|
|
#endif
|
2018-08-20 22:25:08 +08:00
|
|
|
|
|
|
|
// Standard Lua libraries
|
|
|
|
luaL_requiref(L, LUA_GNAME, luaopen_base, 1);
|
2018-09-03 23:08:47 +08:00
|
|
|
luaL_requiref(L, LUA_COLIBNAME, luaopen_coroutine, 1);
|
2018-08-20 22:25:08 +08:00
|
|
|
luaL_requiref(L, LUA_TABLIBNAME, luaopen_table, 1);
|
2018-09-14 03:55:53 +08:00
|
|
|
luaL_requiref(L, LUA_IOLIBNAME, luaopen_io, 1);
|
2018-09-03 23:08:47 +08:00
|
|
|
luaL_requiref(L, LUA_OSLIBNAME, luaopen_os, 1);
|
|
|
|
luaL_requiref(L, LUA_STRLIBNAME, luaopen_string, 1);
|
|
|
|
luaL_requiref(L, LUA_MATHLIBNAME, luaopen_math, 1);
|
|
|
|
luaL_requiref(L, LUA_UTF8LIBNAME, luaopen_utf8, 1);
|
|
|
|
luaL_requiref(L, LUA_DBLIBNAME, luaopen_debug, 1);
|
2018-09-14 03:55:53 +08:00
|
|
|
lua_pop(L, 9);
|
2018-08-20 22:25:08 +08:00
|
|
|
|
2018-09-03 23:08:47 +08:00
|
|
|
// Overwrite Lua functions
|
2018-08-20 22:25:08 +08:00
|
|
|
lua_register(L, "print", print);
|
2018-11-22 04:42:47 +08:00
|
|
|
lua_register(L, "dofile", dofile);
|
2018-08-20 22:25:08 +08:00
|
|
|
|
2018-09-03 23:08:47 +08:00
|
|
|
lua_getglobal(L, "os");
|
2018-09-18 00:14:56 +08:00
|
|
|
for (const char* name : { "remove", "rename", "exit", "tmpname" }) {
|
2018-09-03 23:08:47 +08:00
|
|
|
lua_pushcfunction(L, unsupported);
|
|
|
|
lua_setfield(L, -2, name);
|
|
|
|
}
|
2018-09-04 00:29:10 +08:00
|
|
|
lua_pushcfunction(L, os_clock);
|
|
|
|
lua_setfield(L, -2, "clock");
|
2018-09-03 23:08:47 +08:00
|
|
|
lua_pop(L, 1);
|
|
|
|
|
2018-09-18 00:14:56 +08:00
|
|
|
// Wrap io.open()
|
|
|
|
lua_getglobal(L, "io");
|
|
|
|
lua_getfield(L, -1, "open");
|
|
|
|
lua_pushcclosure(L, secure_io_open, 1);
|
|
|
|
lua_setfield(L, -2, "open");
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
|
|
|
// Wrap os.execute()
|
|
|
|
lua_getglobal(L, "os");
|
|
|
|
lua_getfield(L, -1, "execute");
|
|
|
|
lua_pushcclosure(L, secure_os_execute, 1);
|
|
|
|
lua_setfield(L, -2, "execute");
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
2018-08-20 22:25:08 +08:00
|
|
|
// Generic code used by metatables
|
|
|
|
run_mt_index_code(L);
|
|
|
|
|
|
|
|
// Register global app object
|
|
|
|
register_app_object(L);
|
|
|
|
register_app_pixel_color_object(L);
|
2019-12-12 02:39:40 +08:00
|
|
|
register_app_fs_object(L);
|
2018-09-05 04:21:33 +08:00
|
|
|
register_app_command_object(L);
|
2019-04-25 08:14:20 +08:00
|
|
|
register_app_preferences_object(L);
|
2018-08-20 22:25:08 +08:00
|
|
|
|
|
|
|
// Register constants
|
|
|
|
lua_newtable(L);
|
|
|
|
lua_pushvalue(L, -1);
|
|
|
|
lua_setglobal(L, "ColorMode");
|
|
|
|
setfield_integer(L, "RGB", doc::ColorMode::RGB);
|
2018-11-14 08:04:31 +08:00
|
|
|
setfield_integer(L, "GRAY", doc::ColorMode::GRAYSCALE);
|
2018-08-20 22:25:08 +08:00
|
|
|
setfield_integer(L, "GRAYSCALE", doc::ColorMode::GRAYSCALE);
|
|
|
|
setfield_integer(L, "INDEXED", doc::ColorMode::INDEXED);
|
2019-03-30 02:57:10 +08:00
|
|
|
setfield_integer(L, "TILEMAP", doc::ColorMode::TILEMAP);
|
2018-08-20 22:25:08 +08:00
|
|
|
lua_pop(L, 1);
|
2018-09-11 02:11:59 +08:00
|
|
|
|
2018-09-12 05:29:15 +08:00
|
|
|
lua_newtable(L);
|
|
|
|
lua_pushvalue(L, -1);
|
|
|
|
lua_setglobal(L, "AniDir");
|
|
|
|
setfield_integer(L, "FORWARD", doc::AniDir::FORWARD);
|
|
|
|
setfield_integer(L, "REVERSE", doc::AniDir::REVERSE);
|
|
|
|
setfield_integer(L, "PING_PONG", doc::AniDir::PING_PONG);
|
2022-10-19 23:09:27 +08:00
|
|
|
setfield_integer(L, "PING_PONG_REVERSE", doc::AniDir::PING_PONG_REVERSE);
|
2018-09-12 05:29:15 +08:00
|
|
|
lua_pop(L, 1);
|
|
|
|
|
2018-09-11 02:11:59 +08:00
|
|
|
lua_newtable(L);
|
|
|
|
lua_pushvalue(L, -1);
|
|
|
|
lua_setglobal(L, "BlendMode");
|
|
|
|
setfield_integer(L, "NORMAL", doc::BlendMode::NORMAL);
|
|
|
|
setfield_integer(L, "MULTIPLY", doc::BlendMode::MULTIPLY);
|
|
|
|
setfield_integer(L, "SCREEN", doc::BlendMode::SCREEN);
|
|
|
|
setfield_integer(L, "OVERLAY", doc::BlendMode::OVERLAY);
|
|
|
|
setfield_integer(L, "DARKEN", doc::BlendMode::DARKEN);
|
|
|
|
setfield_integer(L, "LIGHTEN", doc::BlendMode::LIGHTEN);
|
|
|
|
setfield_integer(L, "COLOR_DODGE", doc::BlendMode::COLOR_DODGE);
|
|
|
|
setfield_integer(L, "COLOR_BURN", doc::BlendMode::COLOR_BURN);
|
|
|
|
setfield_integer(L, "HARD_LIGHT", doc::BlendMode::HARD_LIGHT);
|
|
|
|
setfield_integer(L, "SOFT_LIGHT", doc::BlendMode::SOFT_LIGHT);
|
|
|
|
setfield_integer(L, "DIFFERENCE", doc::BlendMode::DIFFERENCE);
|
|
|
|
setfield_integer(L, "EXCLUSION", doc::BlendMode::EXCLUSION);
|
|
|
|
setfield_integer(L, "HSL_HUE", doc::BlendMode::HSL_HUE);
|
|
|
|
setfield_integer(L, "HSL_SATURATION", doc::BlendMode::HSL_SATURATION);
|
|
|
|
setfield_integer(L, "HSL_COLOR", doc::BlendMode::HSL_COLOR);
|
|
|
|
setfield_integer(L, "HSL_LUMINOSITY", doc::BlendMode::HSL_LUMINOSITY);
|
|
|
|
setfield_integer(L, "ADDITION", doc::BlendMode::ADDITION);
|
|
|
|
setfield_integer(L, "SUBTRACT", doc::BlendMode::SUBTRACT);
|
|
|
|
setfield_integer(L, "DIVIDE", doc::BlendMode::DIVIDE);
|
|
|
|
lua_pop(L, 1);
|
2018-08-20 22:25:08 +08:00
|
|
|
|
2018-11-23 23:56:30 +08:00
|
|
|
lua_newtable(L);
|
|
|
|
lua_pushvalue(L, -1);
|
|
|
|
lua_setglobal(L, "RangeType");
|
|
|
|
setfield_integer(L, "EMPTY", DocRange::kNone);
|
|
|
|
setfield_integer(L, "LAYERS", DocRange::kLayers);
|
|
|
|
setfield_integer(L, "FRAMES", DocRange::kFrames);
|
|
|
|
setfield_integer(L, "CELS", DocRange::kCels);
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
2019-01-09 03:42:01 +08:00
|
|
|
lua_newtable(L);
|
|
|
|
lua_pushvalue(L, -1);
|
|
|
|
lua_setglobal(L, "SpriteSheetType");
|
|
|
|
setfield_integer(L, "HORIZONTAL", SpriteSheetType::Horizontal);
|
|
|
|
setfield_integer(L, "VERTICAL", SpriteSheetType::Vertical);
|
|
|
|
setfield_integer(L, "ROWS", SpriteSheetType::Rows);
|
|
|
|
setfield_integer(L, "COLUMNS", SpriteSheetType::Columns);
|
|
|
|
setfield_integer(L, "PACKED", SpriteSheetType::Packed);
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
|
|
|
lua_newtable(L);
|
|
|
|
lua_pushvalue(L, -1);
|
|
|
|
lua_setglobal(L, "SpriteSheetDataFormat");
|
2019-10-08 04:22:27 +08:00
|
|
|
setfield_integer(L, "JSON_HASH", SpriteSheetDataFormat::JsonHash);
|
|
|
|
setfield_integer(L, "JSON_ARRAY", SpriteSheetDataFormat::JsonArray);
|
2019-01-09 03:42:01 +08:00
|
|
|
lua_pop(L, 1);
|
|
|
|
|
2019-04-19 09:23:33 +08:00
|
|
|
lua_newtable(L);
|
|
|
|
lua_pushvalue(L, -1);
|
|
|
|
lua_setglobal(L, "BrushType");
|
|
|
|
setfield_integer(L, "CIRCLE", doc::kCircleBrushType);
|
|
|
|
setfield_integer(L, "SQUARE", doc::kSquareBrushType);
|
|
|
|
setfield_integer(L, "LINE", doc::kLineBrushType);
|
|
|
|
setfield_integer(L, "IMAGE", doc::kImageBrushType);
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
|
|
|
lua_newtable(L);
|
|
|
|
lua_pushvalue(L, -1);
|
|
|
|
lua_setglobal(L, "BrushPattern");
|
|
|
|
setfield_integer(L, "ORIGIN", doc::BrushPattern::ALIGNED_TO_SRC);
|
|
|
|
setfield_integer(L, "TARGET", doc::BrushPattern::ALIGNED_TO_DST);
|
|
|
|
setfield_integer(L, "NONE", doc::BrushPattern::PAINT_BRUSH);
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
2020-05-21 03:34:43 +08:00
|
|
|
lua_newtable(L);
|
|
|
|
lua_pushvalue(L, -1);
|
|
|
|
lua_setglobal(L, "Ink");
|
|
|
|
setfield_integer(L, "SIMPLE", app::tools::InkType::SIMPLE);
|
|
|
|
setfield_integer(L, "ALPHA_COMPOSITING", app::tools::InkType::ALPHA_COMPOSITING);
|
|
|
|
setfield_integer(L, "COPY_COLOR", app::tools::InkType::COPY_COLOR);
|
|
|
|
setfield_integer(L, "LOCK_ALPHA", app::tools::InkType::LOCK_ALPHA);
|
|
|
|
setfield_integer(L, "SHADING", app::tools::InkType::SHADING);
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
2019-07-16 06:12:44 +08:00
|
|
|
lua_newtable(L);
|
|
|
|
lua_pushvalue(L, -1);
|
2019-07-18 22:44:33 +08:00
|
|
|
lua_setglobal(L, "FilterChannels");
|
2019-07-16 06:12:44 +08:00
|
|
|
setfield_integer(L, "RED", TARGET_RED_CHANNEL);
|
|
|
|
setfield_integer(L, "GREEN", TARGET_GREEN_CHANNEL);
|
|
|
|
setfield_integer(L, "BLUE", TARGET_BLUE_CHANNEL);
|
|
|
|
setfield_integer(L, "ALPHA", TARGET_ALPHA_CHANNEL);
|
|
|
|
setfield_integer(L, "GRAY", TARGET_GRAY_CHANNEL);
|
|
|
|
setfield_integer(L, "INDEX", TARGET_INDEX_CHANNEL);
|
2019-07-18 22:44:33 +08:00
|
|
|
setfield_integer(L, "RGB", TARGET_RED_CHANNEL | TARGET_GREEN_CHANNEL | TARGET_BLUE_CHANNEL);
|
|
|
|
setfield_integer(L, "RGBA", TARGET_RED_CHANNEL | TARGET_GREEN_CHANNEL | TARGET_BLUE_CHANNEL | TARGET_ALPHA_CHANNEL);
|
|
|
|
setfield_integer(L, "GRAYA", TARGET_GRAY_CHANNEL | TARGET_ALPHA_CHANNEL);
|
2019-07-16 06:12:44 +08:00
|
|
|
lua_pop(L, 1);
|
|
|
|
|
2022-12-27 02:33:14 +08:00
|
|
|
lua_newtable(L);
|
|
|
|
lua_pushvalue(L, -1);
|
|
|
|
lua_setglobal(L, "MouseCursor");
|
2022-12-27 05:31:28 +08:00
|
|
|
setfield_integer(L, "NONE", (int)ui::kNoCursor);
|
2022-12-27 02:33:14 +08:00
|
|
|
setfield_integer(L, "ARROW", (int)ui::kArrowCursor);
|
|
|
|
setfield_integer(L, "CROSSHAIR", (int)ui::kCrosshairCursor);
|
|
|
|
setfield_integer(L, "POINTER", (int)ui::kHandCursor);
|
|
|
|
setfield_integer(L, "NOT_ALLOWED", (int)ui::kForbiddenCursor);
|
|
|
|
setfield_integer(L, "GRAB", (int)ui::kScrollCursor);
|
|
|
|
setfield_integer(L, "GRABBING", (int)ui::kScrollCursor);
|
|
|
|
setfield_integer(L, "MOVE", (int)ui::kMoveCursor);
|
|
|
|
setfield_integer(L, "NS_RESIZE", (int)ui::kSizeNSCursor);
|
|
|
|
setfield_integer(L, "WE_RESIZE", (int)ui::kSizeWECursor);
|
|
|
|
setfield_integer(L, "N_RESIZE", (int)ui::kSizeNCursor);
|
|
|
|
setfield_integer(L, "NE_RESIZE", (int)ui::kSizeNECursor);
|
|
|
|
setfield_integer(L, "E_RESIZE", (int)ui::kSizeECursor);
|
|
|
|
setfield_integer(L, "SE_RESIZE", (int)ui::kSizeSECursor);
|
|
|
|
setfield_integer(L, "S_RESIZE", (int)ui::kSizeSCursor);
|
|
|
|
setfield_integer(L, "SW_RESIZE", (int)ui::kSizeSWCursor);
|
|
|
|
setfield_integer(L, "W_RESIZE", (int)ui::kSizeWCursor);
|
|
|
|
setfield_integer(L, "NW_RESIZE", (int)ui::kSizeNWCursor);
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
2020-03-28 03:14:00 +08:00
|
|
|
lua_newtable(L);
|
|
|
|
lua_pushvalue(L, -1);
|
|
|
|
lua_setglobal(L, "MouseButton");
|
|
|
|
setfield_integer(L, "NONE", (int)ui::kButtonNone);
|
|
|
|
setfield_integer(L, "LEFT", (int)ui::kButtonLeft);
|
|
|
|
setfield_integer(L, "RIGHT", (int)ui::kButtonRight);
|
|
|
|
setfield_integer(L, "MIDDLE", (int)ui::kButtonMiddle);
|
|
|
|
setfield_integer(L, "X1", (int)ui::kButtonX1);
|
|
|
|
setfield_integer(L, "X2", (int)ui::kButtonX2);
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
2019-03-30 02:57:10 +08:00
|
|
|
lua_newtable(L);
|
|
|
|
lua_pushvalue(L, -1);
|
2020-07-15 04:27:40 +08:00
|
|
|
lua_setglobal(L, "TilemapMode");
|
|
|
|
setfield_integer(L, "PIXELS", TilemapMode::Pixels);
|
|
|
|
setfield_integer(L, "TILES", TilemapMode::Tiles);
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
|
|
|
lua_newtable(L);
|
|
|
|
lua_pushvalue(L, -1);
|
2019-03-30 02:57:10 +08:00
|
|
|
lua_setglobal(L, "TilesetMode");
|
2019-08-05 19:36:47 +08:00
|
|
|
setfield_integer(L, "MANUAL", TilesetMode::Manual);
|
|
|
|
setfield_integer(L, "AUTO", TilesetMode::Auto);
|
2019-11-16 04:10:29 +08:00
|
|
|
setfield_integer(L, "STACK", TilesetMode::Stack);
|
2019-03-30 02:57:10 +08:00
|
|
|
lua_pop(L, 1);
|
|
|
|
|
2021-04-23 00:00:13 +08:00
|
|
|
lua_newtable(L);
|
|
|
|
lua_pushvalue(L, -1);
|
|
|
|
lua_setglobal(L, "SelectionMode");
|
|
|
|
setfield_integer(L, "REPLACE", (int)gen::SelectionMode::REPLACE);
|
|
|
|
setfield_integer(L, "ADD", (int)gen::SelectionMode::ADD);
|
|
|
|
setfield_integer(L, "SUBTRACT", (int)gen::SelectionMode::SUBTRACT);
|
|
|
|
setfield_integer(L, "INTERSECT", (int)gen::SelectionMode::INTERSECT);
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
2018-08-20 22:25:08 +08:00
|
|
|
// Register classes/prototypes
|
2019-04-19 09:23:33 +08:00
|
|
|
register_brush_class(L);
|
2018-09-05 03:10:32 +08:00
|
|
|
register_cel_class(L);
|
|
|
|
register_cels_class(L);
|
|
|
|
register_color_class(L);
|
2019-01-04 04:17:10 +08:00
|
|
|
register_color_space_class(L);
|
2020-07-28 21:35:38 +08:00
|
|
|
#ifdef ENABLE_UI
|
2018-10-11 23:01:21 +08:00
|
|
|
register_dialog_class(L);
|
2022-12-15 04:04:50 +08:00
|
|
|
register_graphics_context_class(L);
|
2023-03-14 05:18:44 +08:00
|
|
|
register_paint_class(L);
|
2020-07-28 21:35:38 +08:00
|
|
|
#endif
|
2021-10-08 05:56:39 +08:00
|
|
|
register_events_class(L);
|
2018-09-05 03:10:32 +08:00
|
|
|
register_frame_class(L);
|
|
|
|
register_frames_class(L);
|
2019-03-30 02:57:10 +08:00
|
|
|
register_grid_class(L);
|
2018-08-20 22:25:08 +08:00
|
|
|
register_image_class(L);
|
2018-09-04 05:04:44 +08:00
|
|
|
register_image_iterator_class(L);
|
2018-09-12 07:31:37 +08:00
|
|
|
register_image_spec_class(L);
|
2018-11-23 23:56:30 +08:00
|
|
|
register_images_class(L);
|
2018-09-05 03:10:32 +08:00
|
|
|
register_layer_class(L);
|
|
|
|
register_layers_class(L);
|
|
|
|
register_palette_class(L);
|
|
|
|
register_palettes_class(L);
|
2020-04-03 02:47:12 +08:00
|
|
|
register_plugin_class(L);
|
2018-08-20 22:25:08 +08:00
|
|
|
register_point_class(L);
|
2022-12-31 01:51:43 +08:00
|
|
|
register_properties_class(L);
|
2018-11-23 23:56:30 +08:00
|
|
|
register_range_class(L);
|
2018-08-20 22:25:08 +08:00
|
|
|
register_rect_class(L);
|
|
|
|
register_selection_class(L);
|
|
|
|
register_site_class(L);
|
|
|
|
register_size_class(L);
|
2018-09-05 03:10:32 +08:00
|
|
|
register_slice_class(L);
|
|
|
|
register_slices_class(L);
|
2018-08-20 22:25:08 +08:00
|
|
|
register_sprite_class(L);
|
2018-09-12 23:55:56 +08:00
|
|
|
register_sprites_class(L);
|
2018-09-05 03:10:32 +08:00
|
|
|
register_tag_class(L);
|
|
|
|
register_tags_class(L);
|
2022-12-16 20:50:36 +08:00
|
|
|
register_theme_classes(L);
|
2023-01-07 06:50:04 +08:00
|
|
|
register_tile_class(L);
|
2019-03-30 02:57:10 +08:00
|
|
|
register_tileset_class(L);
|
|
|
|
register_tilesets_class(L);
|
2023-02-23 07:00:07 +08:00
|
|
|
register_timer_class(L);
|
2019-03-23 20:18:59 +08:00
|
|
|
register_tool_class(L);
|
2019-04-21 11:04:49 +08:00
|
|
|
register_version_class(L);
|
2021-10-03 13:40:29 +08:00
|
|
|
#if ENABLE_WEBSOCKET
|
2021-09-30 23:13:16 +08:00
|
|
|
register_websocket_class(L);
|
2021-10-03 13:40:29 +08:00
|
|
|
#endif
|
2018-08-20 22:25:08 +08:00
|
|
|
|
|
|
|
// Check that we have a clean start (without dirty in the stack)
|
|
|
|
ASSERT(lua_gettop(L) == top);
|
|
|
|
}
|
|
|
|
|
|
|
|
Engine::~Engine()
|
2022-04-06 10:57:36 +08:00
|
|
|
{
|
|
|
|
ASSERT(L == nullptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Engine::destroy()
|
2018-08-20 22:25:08 +08:00
|
|
|
{
|
2020-07-28 21:35:38 +08:00
|
|
|
#ifdef ENABLE_UI
|
|
|
|
close_all_dialogs();
|
|
|
|
#endif
|
2018-08-20 22:25:08 +08:00
|
|
|
lua_close(L);
|
2022-04-06 10:57:36 +08:00
|
|
|
L = nullptr;
|
2018-08-20 22:25:08 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void Engine::printLastResult()
|
|
|
|
{
|
|
|
|
m_printLastResult = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Engine::evalCode(const std::string& code,
|
|
|
|
const std::string& filename)
|
|
|
|
{
|
|
|
|
bool ok = true;
|
2018-11-21 06:42:53 +08:00
|
|
|
try {
|
|
|
|
if (luaL_loadbuffer(L, code.c_str(), code.size(), filename.c_str()) ||
|
|
|
|
lua_pcall(L, 0, 1, 0)) {
|
|
|
|
const char* s = lua_tostring(L, -1);
|
|
|
|
if (s)
|
2021-10-05 08:17:33 +08:00
|
|
|
onConsoleError(s);
|
2018-11-21 06:42:53 +08:00
|
|
|
ok = false;
|
2019-11-02 02:04:22 +08:00
|
|
|
m_returnCode = -1;
|
2018-11-21 06:42:53 +08:00
|
|
|
}
|
|
|
|
else {
|
2019-11-02 02:04:22 +08:00
|
|
|
// Return code
|
|
|
|
if (lua_isinteger(L, -1))
|
|
|
|
m_returnCode = lua_tointeger(L, -1);
|
|
|
|
else
|
|
|
|
m_returnCode = 0;
|
|
|
|
|
2018-11-21 06:42:53 +08:00
|
|
|
// Code was executed correctly
|
|
|
|
if (m_printLastResult) {
|
|
|
|
if (!lua_isnone(L, -1)) {
|
|
|
|
const char* result = lua_tostring(L, -1);
|
|
|
|
if (result)
|
|
|
|
onConsolePrint(result);
|
|
|
|
}
|
2018-08-20 22:25:08 +08:00
|
|
|
}
|
|
|
|
}
|
2018-11-21 06:42:53 +08:00
|
|
|
lua_pop(L, 1);
|
|
|
|
}
|
|
|
|
catch (const std::exception& ex) {
|
2021-10-05 08:17:33 +08:00
|
|
|
onConsoleError(ex.what());
|
2018-11-21 06:42:53 +08:00
|
|
|
ok = false;
|
2019-11-02 02:04:22 +08:00
|
|
|
m_returnCode = -1;
|
2018-08-20 22:25:08 +08:00
|
|
|
}
|
2018-10-11 23:01:21 +08:00
|
|
|
|
|
|
|
// Collect script garbage.
|
|
|
|
lua_gc(L, LUA_GCCOLLECT);
|
2018-08-20 22:25:08 +08:00
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
2018-12-11 03:44:49 +08:00
|
|
|
bool Engine::evalFile(const std::string& filename,
|
|
|
|
const Params& params)
|
2018-08-20 22:25:08 +08:00
|
|
|
{
|
|
|
|
std::stringstream buf;
|
|
|
|
{
|
|
|
|
std::ifstream s(FSTREAM_PATH(filename));
|
2019-11-02 02:04:22 +08:00
|
|
|
// Returns false if we cannot open the file
|
|
|
|
if (!s)
|
|
|
|
return false;
|
2018-08-20 22:25:08 +08:00
|
|
|
buf << s.rdbuf();
|
|
|
|
}
|
2018-09-18 00:14:56 +08:00
|
|
|
std::string absFilename = base::get_absolute_path(filename);
|
2018-11-22 04:42:47 +08:00
|
|
|
|
|
|
|
AddScriptFilename add(absFilename);
|
2018-12-11 03:44:49 +08:00
|
|
|
set_app_params(L, params);
|
2021-10-05 08:17:33 +08:00
|
|
|
|
|
|
|
if (g_debuggerDelegate)
|
|
|
|
g_debuggerDelegate->startFile(absFilename, buf.str());
|
|
|
|
|
|
|
|
bool result = evalCode(buf.str(), "@" + absFilename);
|
|
|
|
|
|
|
|
if (g_debuggerDelegate)
|
|
|
|
g_debuggerDelegate->endFile(absFilename);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Engine::startDebugger(DebuggerDelegate* debuggerDelegate)
|
|
|
|
{
|
|
|
|
g_debuggerDelegate = debuggerDelegate;
|
|
|
|
|
|
|
|
lua_Hook hook = [](lua_State* L, lua_Debug* ar) {
|
|
|
|
int ret = lua_getinfo(L, "l", ar);
|
|
|
|
if (ret == 0 || ar->currentline < 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
g_debuggerDelegate->hook(L, ar);
|
|
|
|
};
|
|
|
|
|
|
|
|
lua_sethook(L, hook, LUA_MASKCALL | LUA_MASKRET | LUA_MASKLINE | LUA_MASKCOUNT, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Engine::stopDebugger()
|
|
|
|
{
|
|
|
|
lua_sethook(L, nullptr, 0, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Engine::onConsoleError(const char* text)
|
|
|
|
{
|
|
|
|
if (text && m_delegate)
|
|
|
|
m_delegate->onConsoleError(text);
|
|
|
|
else
|
|
|
|
onConsolePrint(text);
|
2018-08-20 22:25:08 +08:00
|
|
|
}
|
|
|
|
|
2018-09-01 01:30:32 +08:00
|
|
|
void Engine::onConsolePrint(const char* text)
|
|
|
|
{
|
2019-12-12 10:46:33 +08:00
|
|
|
if (!text)
|
|
|
|
return;
|
|
|
|
|
2018-09-01 01:30:32 +08:00
|
|
|
if (m_delegate)
|
|
|
|
m_delegate->onConsolePrint(text);
|
2018-09-15 07:38:27 +08:00
|
|
|
else {
|
2018-09-01 01:30:32 +08:00
|
|
|
std::printf("%s\n", text);
|
2018-09-15 07:38:27 +08:00
|
|
|
std::fflush(stdout);
|
|
|
|
}
|
2018-09-01 01:30:32 +08:00
|
|
|
}
|
|
|
|
|
2018-08-20 22:25:08 +08:00
|
|
|
} // namespace script
|
|
|
|
} // namespace app
|