Change scripting language to Lua

This commit is contained in:
David Capello 2018-08-20 11:25:08 -03:00
parent 70629d6f89
commit 4fe66f2ffb
45 changed files with 1178 additions and 1747 deletions

6
.gitmodules vendored
View File

@ -51,9 +51,6 @@
[submodule "third_party/benchmark"]
path = third_party/benchmark
url = https://github.com/aseprite/benchmark.git
[submodule "third_party/mujs"]
path = third_party/mujs
url = https://github.com/aseprite/mujs.git
[submodule "third_party/giflib"]
path = third_party/giflib
url = https://github.com/aseprite/giflib.git
@ -63,3 +60,6 @@
[submodule "third_party/tinyexpr"]
path = third_party/tinyexpr
url = https://github.com/aseprite/tinyexpr.git
[submodule "third_party/lua"]
path = third_party/lua
url = https://github.com/aseprite/lua

View File

@ -668,7 +668,7 @@
<item command="PasteText" text="@.edit_insert_text" />
<!--menu text="Scripts">
<item command="RunScript" text="Transparency from White Background">
<param name="filename" value="white_to_alpha.js" />
<param name="filename" value="white_to_alpha.lua" />
</item>
</menu-->
<separator />

View File

@ -1,20 +0,0 @@
// Aseprite
// Copyright (C) 2015-2017 by David Capello
var col = app.pixelColor
var img = app.activeImage
for (var y=0; y<img.height; ++y) {
for (var x=0; x<img.width; ++x) {
var c = img.getPixel(x, y)
var v = (col.rgbaR(c)+
col.rgbaG(c)+
col.rgbaB(c))/3
img.putPixel(x, y,
col.rgba(col.rgbaR(c),
col.rgbaG(c),
col.rgbaB(c),
255-v))
}
}

View File

@ -0,0 +1,17 @@
-- Aseprite
-- Copyright (C) 2015-2018 by David Capello
local pc = app.pixelColor
local img = app.activeImage
for y=0,img.height-1 do
for x=0,img.width-1 do
local c = img:getPixel(x, y)
local r = pc.rgbaR(c)
local g = pc.rgbaG(c)
local b = pc.rgbaB(c)
local a = pc.rgbaA(c)
if a > 0 then a = 255 - (r+g+b)/3 end
img:putPixel(x, y, pc.rgba(r, g, b, a))
end
end

View File

@ -904,24 +904,29 @@ freely, subject to the following restrictions:
distribution.
```
# [mujs](http://mujs.com/)
# [Lua](https://www.lua.org/)
```
ISC License
Copyright (C) 1994-2018 Lua.org, PUC-Rio.
Copyright (c) 2013, 2017, Artifex Software
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
```
# [pixman](http://www.pixman.org/)

View File

@ -115,11 +115,6 @@ add_subdirectory(ft)
add_subdirectory(she)
add_subdirectory(ui)
if(ENABLE_SCRIPTING)
add_subdirectory(script)
add_definitions(-DENABLE_SCRIPTING)
endif()
if(ENABLE_UPDATER)
add_subdirectory(updater)
endif()

View File

@ -140,6 +140,7 @@ endif()
set(scripting_files)
if(ENABLE_SCRIPTING)
add_definitions(-DENABLE_SCRIPTING)
set(scripting_files_ui)
if(ENABLE_UI)
set(scripting_files_ui
@ -149,10 +150,10 @@ if(ENABLE_SCRIPTING)
set(scripting_files
commands/cmd_run_script.cpp
script/app_object.cpp
script/app_scripting.cpp
script/console_object.cpp
script/engine.cpp
script/image_class.cpp
script/pixel_color_class.cpp
script/luacpp.cpp
script/pixel_color_object.cpp
script/point_class.cpp
script/rectangle_class.cpp
script/selection_class.cpp
@ -595,7 +596,7 @@ target_link_libraries(app-lib
tinyexpr)
if(ENABLE_SCRIPTING)
target_link_libraries(app-lib script-lib)
target_link_libraries(app-lib lua lauxlib lualib)
endif()
if(ENABLE_UPDATER)

View File

@ -70,9 +70,8 @@
#include <memory>
#ifdef ENABLE_SCRIPTING
#include "app/script/app_scripting.h"
#include "app/script/engine.h"
#include "app/shell.h"
#include "script/engine_delegate.h"
#endif
#ifdef ENABLE_STEAM
@ -353,7 +352,7 @@ void App::run()
// Start shell to execute scripts.
if (m_isShell) {
script::StdoutEngineDelegate delegate;
AppScripting engine(&delegate);
script::Engine engine(&delegate);
engine.printLastResult();
Shell shell;
shell.run(engine);

View File

@ -27,8 +27,7 @@
#include "doc/sprite.h"
#ifdef ENABLE_SCRIPTING
#include "app/script/app_scripting.h"
#include "script/engine_delegate.h"
#include "app/script/engine.h"
#endif
#include <iostream>
@ -128,7 +127,7 @@ void DefaultCliDelegate::execScript(const std::string& filename)
{
#ifdef ENABLE_SCRIPTING
script::StdoutEngineDelegate delegate;
AppScripting engine(&delegate);
script::Engine engine(&delegate);
if (!engine.evalFile(filename))
throw std::runtime_error("Error executing script");
#endif

View File

@ -16,9 +16,8 @@
#include "app/commands/params.h"
#include "app/console.h"
#include "app/resource_finder.h"
#include "app/script/app_scripting.h"
#include "app/script/engine.h"
#include "base/fs.h"
#include "script/engine_delegate.h"
#include "ui/manager.h"
#include <cstdio>
@ -67,7 +66,7 @@ void RunScriptCommand::onLoadParams(const Params& params)
void RunScriptCommand::onExecute(Context* context)
{
ConsoleEngineDelegate delegate;
AppScripting engine(&delegate);
script::Engine engine(&delegate);
engine.evalFile(m_filename);
ui::Manager::getDefault()->invalidate();

View File

@ -13,154 +13,155 @@
#include "app/commands/params.h"
#include "app/context.h"
#include "app/doc.h"
#include "app/script/app_scripting.h"
#include "app/script/engine.h"
#include "app/script/luacpp.h"
#include "app/site.h"
#include "app/site.h"
#include "app/tx.h"
#include "script/engine.h"
#include <iostream>
namespace app {
namespace script {
namespace {
void App_open(script::ContextHandle handle)
int App_open(lua_State* L)
{
script::Context ctx(handle);
const char* filename = ctx.requireString(1);
const char* filename = luaL_checkstring(L, 1);
app::Context* appCtx = App::instance()->context();
Doc* oldDoc = appCtx->activeDocument();
app::Context* ctx = App::instance()->context();
Doc* oldDoc = ctx->activeDocument();
Command* openCommand =
Commands::instance()->byId(CommandId::OpenFile());
Params params;
params.set("filename", filename);
appCtx->executeCommand(openCommand, params);
ctx->executeCommand(openCommand, params);
Doc* newDoc = appCtx->activeDocument();
Doc* newDoc = ctx->activeDocument();
if (newDoc != oldDoc)
push_sprite(ctx, newDoc->sprite());
push_ptr(L, newDoc->sprite());
else
ctx.pushNull();
lua_pushnil(L);
return 1;
}
void App_exit(script::ContextHandle handle)
int App_exit(lua_State* L)
{
script::Context ctx(handle);
app::Context* appCtx = App::instance()->context();
if (appCtx && appCtx->isUIAvailable()) {
app::Context* ctx = App::instance()->context();
if (ctx && ctx->isUIAvailable()) {
Command* exitCommand =
Commands::instance()->byId(CommandId::Exit());
appCtx->executeCommand(exitCommand);
ctx->executeCommand(exitCommand);
}
ctx.pushUndefined();
return 0;
}
void App_transaction(script::ContextHandle handle)
int App_transaction(lua_State* L)
{
script::Context ctx(handle);
if (ctx.isCallable(1)) {
int top = lua_gettop(L);
int nresults = 0;
if (lua_isfunction(L, 1)) {
Tx tx; // Create a new transaction so it exists in the whole
// duration of the argument function call.
ctx.copy(1);
ctx.call(0);
tx.commit();
lua_pushvalue(L, -1);
if (lua_pcall(L, 0, LUA_MULTRET, 0) == LUA_OK)
tx.commit();
nresults = lua_gettop(L) - top;
}
else
ctx.pushUndefined();
return nresults;
}
void App_undo(script::ContextHandle handle)
int App_undo(lua_State* L)
{
script::Context ctx(handle);
app::Context* appCtx = App::instance()->context();
if (appCtx) {
app::Context* ctx = App::instance()->context();
if (ctx) {
Command* undo = Commands::instance()->byId(CommandId::Undo());
appCtx->executeCommand(undo);
ctx->executeCommand(undo);
}
ctx.pushUndefined();
return 0;
}
void App_redo(script::ContextHandle handle)
int App_redo(lua_State* L)
{
script::Context ctx(handle);
app::Context* appCtx = App::instance()->context();
if (appCtx) {
app::Context* ctx = App::instance()->context();
if (ctx) {
Command* redo = Commands::instance()->byId(CommandId::Redo());
appCtx->executeCommand(redo);
ctx->executeCommand(redo);
}
ctx.pushUndefined();
return 0;
}
void App_get_activeSprite(script::ContextHandle handle)
int App_get_activeSprite(lua_State* L)
{
script::Context ctx(handle);
app::Context* appCtx = App::instance()->context();
Doc* doc = appCtx->activeDocument();
app::Context* ctx = App::instance()->context();
Doc* doc = ctx->activeDocument();
if (doc)
push_sprite(ctx, doc->sprite());
push_ptr(L, doc->sprite());
else
ctx.pushNull();
lua_pushnil(L);
return 1;
}
void App_get_activeImage(script::ContextHandle handle)
int App_get_activeImage(lua_State* L)
{
script::Context ctx(handle);
app::Context* appCtx = App::instance()->context();
Site site = appCtx->activeSite();
app::Context* ctx = App::instance()->context();
Site site = ctx->activeSite();
if (site.image())
push_image(ctx, site.image());
push_ptr(L, site.image());
else
ctx.pushNull();
lua_pushnil(L);
return 1;
}
void App_get_site(script::ContextHandle handle)
int App_get_site(lua_State* L)
{
script::Context ctx(handle);
app::Context* appCtx = App::instance()->context();
Site site = appCtx->activeSite();
push_site(ctx, site);
app::Context* ctx = App::instance()->context();
Site site = ctx->activeSite();
push_obj(L, site);
return 1;
}
void App_get_pixelColor(script::ContextHandle handle)
int App_get_version(lua_State* L)
{
script::Context ctx(handle);
ctx.newObject("PixelColor", nullptr, nullptr);
lua_pushstring(L, VERSION);
return 1;
}
void App_get_version(script::ContextHandle handle)
{
script::Context ctx(handle);
ctx.pushString(VERSION);
}
const script::FunctionEntry App_methods[] = {
{ "open", App_open, 1 },
{ "exit", App_exit, 0 },
{ "transaction", App_transaction, 1 },
{ "undo", App_undo, 0 },
{ "redo", App_redo, 0 },
{ nullptr, nullptr, 0 }
const luaL_Reg App_methods[] = {
{ "open", App_open },
{ "exit", App_exit },
{ "transaction", App_transaction },
{ "undo", App_undo },
{ "redo", App_redo },
{ nullptr, nullptr }
};
const script::PropertyEntry App_props[] = {
const Property App_properties[] = {
{ "activeSprite", App_get_activeSprite, nullptr },
{ "activeImage", App_get_activeImage, nullptr },
{ "pixelColor", App_get_pixelColor, nullptr },
{ "version", App_get_version, nullptr },
{ "site", App_get_site, nullptr },
{ nullptr, nullptr, 0 }
{ nullptr, nullptr, nullptr }
};
} // anonymous namespace
void register_app_object(script::Context& ctx)
DEF_MTNAME(App);
void register_app_object(lua_State* L)
{
ctx.pushGlobalObject();
ctx.registerObject(-1, "app", App_methods, App_props);
ctx.pop();
REG_CLASS(L, App);
REG_CLASS_PROPERTIES(L, App);
lua_newtable(L); // Create a table which will be the "app" object
lua_pushvalue(L, -1);
luaL_getmetatable(L, get_mtname<App>());
lua_setmetatable(L, -2);
lua_setglobal(L, "app");
lua_pop(L, 1); // Pop app table
}
} // namespace script
} // namespace app

View File

@ -1,78 +0,0 @@
// Aseprite
// 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/app_scripting.h"
#include "app/doc.h"
namespace app {
namespace {
const script::ConstantEntry ColorMode_constants[] = {
{ "RGB", double(IMAGE_RGB) },
{ "GRAYSCALE", double(IMAGE_GRAYSCALE) },
{ "INDEXED", double(IMAGE_INDEXED) },
{ nullptr, 0.0 }
};
}
void register_app_object(script::Context& ctx);
void register_console_object(script::Context& ctx);
void register_image_class(script::index_t idx, script::Context& ctx);
void register_pixel_color_class(script::index_t idx, script::Context& ctx);
void register_point_class(script::index_t idx, script::Context& ctx);
void register_rectangle_class(script::index_t idx, script::Context& ctx);
void register_selection_class(script::index_t idx, script::Context& ctx);
void register_site_class(script::index_t idx, script::Context& ctx);
void register_size_class(script::index_t idx, script::Context& ctx);
void register_sprite_class(script::index_t idx, script::Context& ctx);
AppScripting::AppScripting(script::EngineDelegate* delegate)
: script::Engine(delegate)
{
auto& ctx = context();
ctx.setContextUserData(this);
// Register global objects (app and console)
register_app_object(ctx);
register_console_object(ctx);
ctx.pushGlobalObject();
// Register constants
{
ctx.newObject();
ctx.registerConstants(-1, ColorMode_constants);
ctx.setProp(-2, "ColorMode");
}
// Register classes/prototypes
register_image_class(-1, ctx);
register_pixel_color_class(-1, ctx);
register_point_class(-1, ctx);
register_rectangle_class(-1, ctx);
register_selection_class(-1, ctx);
register_site_class(-1, ctx);
register_size_class(-1, ctx);
register_sprite_class(-1, ctx);
ctx.pop(1);
}
AppScripting* get_engine(script::Context& ctx)
{
return (AppScripting*)ctx.getContextUserData();
}
}

View File

@ -1,50 +0,0 @@
// Aseprite
// Copyright (C) 2001-2018 David Capello
//
// This program is distributed under the terms of
// the End-User License Agreement for Aseprite.
#ifndef APP_SCRIPTING_H_INCLUDED
#define APP_SCRIPTING_H_INCLUDED
#pragma once
#ifndef ENABLE_SCRIPTING
#error ENABLE_SCRIPTING must be defined
#endif
#include "doc/object_id.h"
#include "gfx/fwd.h"
#include "script/engine.h"
#include <map>
namespace doc {
class Image;
class Sprite;
}
namespace app {
class Site;
class AppScripting : public script::Engine {
public:
AppScripting(script::EngineDelegate* delegate);
};
AppScripting* get_engine(script::Context& ctx);
void push_image(script::Context& ctx, doc::Image* image);
void push_new_point(script::Context& ctx, const gfx::Point& pt);
void push_new_rectangle(script::Context& ctx, const gfx::Rect& rc);
void push_new_size(script::Context& ctx, const gfx::Size& rc);
void push_site(script::Context& ctx, app::Site& site);
void push_sprite(script::Context& ctx, doc::Sprite* sprite);
void push_sprite_selection(script::Context& ctx, doc::Sprite* sprite);
gfx::Point convert_args_into_point(script::Context& ctx);
gfx::Rect convert_args_into_rectangle(script::Context& ctx);
gfx::Size convert_args_into_size(script::Context& ctx);
} // namespace app
#endif

View File

@ -1,74 +0,0 @@
// Aseprite
// Copyright (C) 2001-2017 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/app.h"
#include "app/console.h"
#include "script/engine.h"
#include <iostream>
namespace app {
namespace {
void print(const char* str)
{
if (str) {
std::cout << str << std::endl; // New line + flush
if (App::instance()->isGui()) {
Console().printf("%s\n", str);
}
}
}
void Console_assert(script::ContextHandle handle)
{
script::Context ctx(handle);
if (!ctx.toBool(1))
ctx.error(ctx.toString(1));
ctx.pushUndefined();
}
void Console_log(script::ContextHandle handle)
{
script::Context ctx(handle);
std::string output;
int top = ctx.top();
const char* s;
for (int n=1; n<top; ++n) {
s = ctx.toString(n);
if (s == nullptr)
break;
if (n > 1)
output += " ";
output += s;
}
if (!output.empty())
print(output.c_str());
ctx.pushUndefined();
}
const script::FunctionEntry Console_methods[] = {
{ "assert", Console_assert, 2 },
{ "log", Console_log, 1 },
{ nullptr, nullptr, 0 }
};
} // anonymous namespace
void register_console_object(script::Context& ctx)
{
ctx.pushGlobalObject();
ctx.registerObject(-1, "console", Console_methods, nullptr);
ctx.pop();
}
} // namespace app

162
src/app/script/engine.cpp Normal file
View File

@ -0,0 +1,162 @@
// Aseprite
// 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"
#include "app/script/luacpp.h"
#include "base/fstream_path.h"
#include "doc/color_mode.h"
#include <fstream>
#include <sstream>
namespace app {
namespace script {
namespace {
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()) {
std::printf("%s\n", output.c_str());
std::fflush(stdout);
if (App::instance()->isGui())
Console().printf("%s\n", output.c_str());
}
return 0;
}
} // anonymous namespace
void register_app_object(lua_State* L);
void register_app_pixel_color_object(lua_State* L);
void register_image_class(lua_State* L);
void register_point_class(lua_State* L);
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);
void register_sprite_class(lua_State* L);
Engine::Engine(EngineDelegate* delegate)
: L(luaL_newstate())
, m_delegate(delegate)
, m_printLastResult(false)
{
int top = lua_gettop(L);
// Standard Lua libraries
luaL_requiref(L, LUA_GNAME, luaopen_base, 1);
luaL_requiref(L, LUA_MATHLIBNAME, luaopen_math, 1);
luaL_requiref(L, LUA_STRLIBNAME, luaopen_string, 1);
luaL_requiref(L, LUA_TABLIBNAME, luaopen_table, 1);
lua_pop(L, 4);
// Our print() impl
lua_register(L, "print", print);
// Generic code used by metatables
run_mt_index_code(L);
// Register global app object
register_app_object(L);
register_app_pixel_color_object(L);
// Register constants
lua_newtable(L);
lua_pushvalue(L, -1);
lua_setglobal(L, "ColorMode");
setfield_integer(L, "RGB", doc::ColorMode::RGB);
setfield_integer(L, "GRAYSCALE", doc::ColorMode::GRAYSCALE);
setfield_integer(L, "INDEXED", doc::ColorMode::INDEXED);
lua_pop(L, 1);
// Register classes/prototypes
register_image_class(L);
register_point_class(L);
register_rect_class(L);
register_selection_class(L);
register_site_class(L);
register_size_class(L);
register_sprite_class(L);
// Check that we have a clean start (without dirty in the stack)
ASSERT(lua_gettop(L) == top);
}
Engine::~Engine()
{
lua_close(L);
}
void Engine::printLastResult()
{
m_printLastResult = true;
}
bool Engine::evalCode(const std::string& code,
const std::string& filename)
{
bool ok = true;
if (luaL_loadbuffer(L, code.c_str(), code.size(), filename.c_str()) ||
lua_pcall(L, 0, 1, 0)) {
// Error case
std::string err;
const char* s = lua_tostring(L, -1);
if (s)
m_delegate->onConsolePrint(s);
ok = false;
}
else {
// Code was executed correctly
if (m_printLastResult) {
if (!lua_isnone(L, -1)) {
const char* result = lua_tostring(L, -1);
if (result)
m_delegate->onConsolePrint(result);
}
}
}
lua_pop(L, 1);
return ok;
}
bool Engine::evalFile(const std::string& filename)
{
std::stringstream buf;
{
std::ifstream s(FSTREAM_PATH(filename));
buf << s.rdbuf();
}
return evalCode(buf.str(), filename);
}
} // namespace script
} // namespace app

72
src/app/script/engine.h Normal file
View File

@ -0,0 +1,72 @@
// Aseprite
// Copyright (C) 2001-2018 David Capello
//
// This program is distributed under the terms of
// the End-User License Agreement for Aseprite.
#ifndef APP_SCRIPTING_H_INCLUDED
#define APP_SCRIPTING_H_INCLUDED
#pragma once
#ifndef ENABLE_SCRIPTING
#error ENABLE_SCRIPTING must be defined
#endif
#include "doc/object_id.h"
#include "gfx/fwd.h"
#include <cstdio>
#include <string>
#include <map>
struct lua_State;
namespace doc {
class Image;
class Sprite;
}
namespace app {
class Site;
namespace script {
class EngineDelegate {
public:
virtual ~EngineDelegate() { }
virtual void onConsolePrint(const char* text) = 0;
};
class StdoutEngineDelegate : public EngineDelegate {
public:
void onConsolePrint(const char* text) override {
std::printf("%s\n", text);
}
};
class Engine {
public:
Engine(EngineDelegate* delegate);
~Engine();
void printLastResult();
bool evalCode(const std::string& code,
const std::string& filename = std::string());
bool evalFile(const std::string& filename);
private:
lua_State* L;
EngineDelegate* m_delegate;
bool m_printLastResult;
};
void push_sprite_selection(lua_State* L, doc::Sprite* sprite);
gfx::Point convert_args_into_point(lua_State* L, int index);
gfx::Rect convert_args_into_rect(lua_State* L, int index);
gfx::Size convert_args_into_size(lua_State* L, int index);
} // namespace script
} // namespace app
#endif

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2015-2017 David Capello
// Copyright (C) 2015-2018 David Capello
//
// This program is distributed under the terms of
// the End-User License Agreement for Aseprite.
@ -8,95 +8,78 @@
#include "config.h"
#endif
#include "app/script/luacpp.h"
#include "doc/image.h"
#include "script/engine.h"
#include "doc/primitives.h"
namespace app {
namespace script {
namespace {
const char* kTag = "Image";
void Image_new(script::ContextHandle handle)
int Image_new(lua_State* L)
{
script::Context ctx(handle);
ctx.pushNull(); // TODO
lua_pushnil(L); // TODO
return 1;
}
void Image_putPixel(script::ContextHandle handle)
int Image_putPixel(lua_State* L)
{
script::Context ctx(handle);
auto image = (doc::Image*)ctx.toUserData(0, kTag);
int x = ctx.requireInt(1);
int y = ctx.requireInt(2);
doc::color_t color = ctx.requireUInt(3);
if (image) {
image->putPixel(x, y, color);
}
ctx.pushUndefined();
auto image = get_ptr<doc::Image>(L, 1);
const int x = lua_tointeger(L, 2);
const int y = lua_tointeger(L, 3);
const doc::color_t color = lua_tointeger(L, 4);
doc::put_pixel(image, x, y, color);
return 0;
}
void Image_getPixel(script::ContextHandle handle)
int Image_getPixel(lua_State* L)
{
script::Context ctx(handle);
auto image = (doc::Image*)ctx.toUserData(0, kTag);
int x = ctx.requireInt(1);
int y = ctx.requireInt(2);
if (image) {
doc::color_t color = image->getPixel(x, y);
ctx.pushUInt(color);
}
else
ctx.pushUndefined();
const auto image = get_ptr<doc::Image>(L, 1);
const int x = lua_tointeger(L, 2);
const int y = lua_tointeger(L, 3);
const doc::color_t color = doc::get_pixel(image, x, y);
lua_pushinteger(L, color);
return 1;
}
void Image_get_width(script::ContextHandle handle)
int Image_get_width(lua_State* L)
{
script::Context ctx(handle);
auto image = (doc::Image*)ctx.toUserData(0, kTag);
if (image)
ctx.pushInt(image->width());
else
ctx.pushUndefined();
const auto image = get_ptr<doc::Image>(L, 1);
lua_pushinteger(L, image->width());
return 1;
}
void Image_get_height(script::ContextHandle handle)
int Image_get_height(lua_State* L)
{
script::Context ctx(handle);
auto image = (doc::Image*)ctx.toUserData(0, kTag);
if (image)
ctx.pushInt(image->height());
else
ctx.pushUndefined();
const auto image = get_ptr<doc::Image>(L, 1);
lua_pushinteger(L, image->height());
return 1;
}
const script::FunctionEntry Image_methods[] = {
{ "getPixel", Image_getPixel, 2 },
{ "putPixel", Image_putPixel, 3 },
{ nullptr, nullptr, 0 }
const luaL_Reg Image_methods[] = {
{ "getPixel", Image_getPixel },
{ "putPixel", Image_putPixel },
{ nullptr, nullptr }
};
const script::PropertyEntry Image_props[] = {
const Property Image_properties[] = {
{ "width", Image_get_width, nullptr },
{ "height", Image_get_height, nullptr },
{ nullptr, nullptr, 0 }
{ nullptr, nullptr, nullptr }
};
} // anonymous namespace
void register_image_class(script::index_t idx, script::Context& ctx)
DEF_MTNAME(doc::Image);
void register_image_class(lua_State* L)
{
ctx.registerClass(idx, kTag,
Image_new, 0,
Image_methods, Image_props);
}
void push_image(script::Context& ctx, doc::Image* image)
{
ctx.newObject(kTag, image, nullptr);
using doc::Image;
REG_CLASS(L, Image);
REG_CLASS_NEW(L, Image);
REG_CLASS_PROPERTIES(L, Image);
}
} // namespace script
} // namespace app

86
src/app/script/luacpp.cpp Normal file
View File

@ -0,0 +1,86 @@
// Aseprite
// Copyright (C) 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/luacpp.h"
namespace app {
namespace script {
static const char* mt_index_code =
"__generic_mt_index = function(t, k) "
" local mt = getmetatable(t) "
" local f = mt[k] "
" if f then return f end "
" f = mt.__getters[k] "
" if f then return f(t) end "
" if type(t) == 'table' then return rawget(t, k) end "
" error('Field '..tostring(k)..' does not exist')"
"end "
"__generic_mt_newindex = function(t, k, v) "
" local mt = getmetatable(t) "
" local f = mt[k] "
" if f then return f end "
" f = mt.__setters[k] "
" if f then return f(t, v) end "
" if type(t) == 'table' then return rawset(t, k, v) end "
" error('Cannot set field '..tostring(k))"
"end";
void run_mt_index_code(lua_State* L)
{
luaL_dostring(L, mt_index_code);
}
void create_mt_getters_setters(lua_State* L,
const char* tname,
const Property* properties)
{
const int top = lua_gettop(L);
bool withGetters = false;
bool withSetters = false;
for (auto p=properties; p->name; ++p) {
if (p->getter) withGetters = true;
if (p->setter) withSetters = true;
}
ASSERT(withGetters || withSetters);
luaL_getmetatable(L, tname);
if (withGetters) {
lua_newtable(L);
lua_pushvalue(L, -1);
lua_setfield(L, -3, "__getters");
for (auto p=properties; p->name; ++p) {
if (p->getter) {
lua_pushcclosure(L, p->getter, 0);
lua_setfield(L, -2, p->name);
}
}
lua_pop(L, 1);
}
if (withSetters) {
lua_newtable(L);
lua_pushvalue(L, -1);
lua_setfield(L, -3, "__setters");
for (auto p=properties; p->name; ++p) {
if (p->setter) {
lua_pushcclosure(L, p->setter, 0);
lua_setfield(L, -2, p->name);
}
}
lua_pop(L, 1);
}
lua_pop(L, 1);
ASSERT(lua_gettop(L) == top);
}
} // namespace script
} // namespace app

118
src/app/script/luacpp.h Normal file
View File

@ -0,0 +1,118 @@
// Aseprite
// Copyright (C) 2018 David Capello
//
// This program is distributed under the terms of
// the End-User License Agreement for Aseprite.
#ifndef APP_SCRIPT_LUACPP_H_INCLUDED
#define APP_SCRIPT_LUACPP_H_INCLUDED
#pragma once
extern "C" {
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
}
#include <functional>
#include <type_traits>
namespace app {
namespace script {
// Some of these auxiliary methods are based on code from the Skia
// library (SkLua.cpp file) by Google Inc.
template <typename T> const char* get_mtname();
#define DEF_MTNAME(T) \
template <> const char* get_mtname<T>() { \
return #T "_Metatable"; \
}
template <typename T, typename... Args> T* push_new(lua_State* L, Args&&... args) {
T* addr = (T*)lua_newuserdata(L, sizeof(T));
new (addr) T(std::forward<Args>(args)...);
luaL_getmetatable(L, get_mtname<T>());
lua_setmetatable(L, -2);
return addr;
}
template <typename T> void push_obj(lua_State* L, const T& obj) {
new (lua_newuserdata(L, sizeof(T))) T(obj);
luaL_getmetatable(L, get_mtname<T>());
lua_setmetatable(L, -2);
}
template <typename T> void push_obj(lua_State* L, T&& obj) {
using RRT = typename std::remove_reference<T>::type;
new (lua_newuserdata(L, sizeof(RRT))) RRT(std::move(obj));
luaL_getmetatable(L, get_mtname<RRT>());
lua_setmetatable(L, -2);
}
template <typename T> T* push_ptr(lua_State* L, T* ptr) {
*(T**)lua_newuserdata(L, sizeof(T*)) = ptr;
luaL_getmetatable(L, get_mtname<T>());
lua_setmetatable(L, -2);
return ptr;
}
template <typename T> T* get_ptr(lua_State* L, int index) {
return *(T**)luaL_checkudata(L, index, get_mtname<T>());
}
template <typename T> T* get_obj(lua_State* L, int index) {
return (T*)luaL_checkudata(L, index, get_mtname<T>());
}
// Returns nil if the index doesn't have the given metatable
template <typename T> T* may_get_obj(lua_State* L, int index) {
return (T*)luaL_testudata(L, index, get_mtname<T>());
}
inline bool lua2bool(lua_State* L, int index) {
return !!lua_toboolean(L, index);
}
template<typename T>
inline void setfield_integer(lua_State* L, const char* key, const T& value) {
lua_pushinteger(L, int(value));
lua_setfield(L, -2, key);
}
#define REG_CLASS(L, T) { \
luaL_newmetatable(L, get_mtname<T>()); \
lua_getglobal(L, "__generic_mt_index"); \
lua_setfield(L, -2, "__index"); \
lua_getglobal(L, "__generic_mt_newindex"); \
lua_setfield(L, -2, "__newindex"); \
luaL_setfuncs(L, T##_methods, 0); \
lua_pop(L, 1); \
}
#define REG_CLASS_NEW(L, T) { \
lua_pushcfunction(L, T##_new); \
lua_setglobal(L, #T); \
}
struct Property {
const char* name;
lua_CFunction getter;
lua_CFunction setter;
};
void run_mt_index_code(lua_State* L);
void create_mt_getters_setters(lua_State* L,
const char* tname,
const Property* properties);
#define REG_CLASS_PROPERTIES(L, T) { \
luaL_getmetatable(L, get_mtname<T>()); \
create_mt_getters_setters(L, get_mtname<T>(), T##_properties); \
lua_pop(L, 1); \
}
} // namespace script
} // namespace app
#endif

View File

@ -1,101 +0,0 @@
// Aseprite
// Copyright (C) 2017 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 "doc/color.h"
#include "script/engine.h"
namespace app {
namespace {
const char* kTag = "PixelColor";
void PixelColor_new(script::ContextHandle handle)
{
script::Context ctx(handle);
ctx.pushUndefined(); // Cannot create new pixel colors (just subobject of "app")
}
void PixelColor_rgba(script::ContextHandle handle)
{
script::Context ctx(handle);
const int r = ctx.requireUInt(1);
const int g = ctx.requireUInt(2);
const int b = ctx.requireUInt(3);
const int a = (ctx.isUndefined(4) ? 255: ctx.requireUInt(4));
ctx.pushUInt(doc::rgba(r, g, b, a));
}
void PixelColor_rgbaR(script::ContextHandle handle)
{
script::Context ctx(handle);
ctx.pushUInt(doc::rgba_getr(ctx.requireUInt(1)));
}
void PixelColor_rgbaG(script::ContextHandle handle)
{
script::Context ctx(handle);
ctx.pushUInt(doc::rgba_getg(ctx.requireUInt(1)));
}
void PixelColor_rgbaB(script::ContextHandle handle)
{
script::Context ctx(handle);
ctx.pushUInt(doc::rgba_getb(ctx.requireUInt(1)));
}
void PixelColor_rgbaA(script::ContextHandle handle)
{
script::Context ctx(handle);
ctx.pushUInt(doc::rgba_geta(ctx.requireUInt(1)));
}
void PixelColor_graya(script::ContextHandle handle)
{
script::Context ctx(handle);
int v = ctx.requireUInt(1);
int a = (ctx.isUndefined(2) ? 255: ctx.requireUInt(2));
ctx.pushUInt(doc::graya(v, a));
}
void PixelColor_grayaV(script::ContextHandle handle)
{
script::Context ctx(handle);
ctx.pushUInt(doc::graya_getv(ctx.requireUInt(1)));
}
void PixelColor_grayaA(script::ContextHandle handle)
{
script::Context ctx(handle);
ctx.pushUInt(doc::graya_geta(ctx.requireUInt(1)));
}
const script::FunctionEntry PixelColor_methods[] = {
{ "rgba", PixelColor_rgba, 4 },
{ "rgbaR", PixelColor_rgbaR, 1 },
{ "rgbaG", PixelColor_rgbaG, 1 },
{ "rgbaB", PixelColor_rgbaB, 1 },
{ "rgbaA", PixelColor_rgbaA, 1 },
{ "graya", PixelColor_graya, 2 },
{ "grayaV", PixelColor_grayaV, 1 },
{ "grayaA", PixelColor_grayaA, 1 },
{ nullptr, nullptr, 0 }
};
} // anonymous namespace
void register_pixel_color_class(script::index_t idx, script::Context& ctx)
{
ctx.registerClass(idx, kTag,
PixelColor_new, 0,
PixelColor_methods, nullptr);
}
} // namespace app

View File

@ -0,0 +1,99 @@
// Aseprite
// Copyright (C) 2017-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/luacpp.h"
#include "doc/color.h"
namespace app {
namespace script {
namespace {
int PixelColor_rgba(lua_State* L)
{
const int r = lua_tointeger(L, 1);
const int g = lua_tointeger(L, 2);
const int b = lua_tointeger(L, 3);
const int a = (lua_isnoneornil(L, 4) ? 255: lua_tointeger(L, 4));
lua_pushinteger(L, doc::rgba(r, g, b, a));
return 1;
}
int PixelColor_rgbaR(lua_State* L)
{
lua_pushinteger(L, doc::rgba_getr(lua_tointeger(L, 1)));
return 1;
}
int PixelColor_rgbaG(lua_State* L)
{
lua_pushinteger(L, doc::rgba_getg(lua_tointeger(L, 1)));
return 1;
}
int PixelColor_rgbaB(lua_State* L)
{
lua_pushinteger(L, doc::rgba_getb(lua_tointeger(L, 1)));
return 1;
}
int PixelColor_rgbaA(lua_State* L)
{
lua_pushinteger(L, doc::rgba_geta(lua_tointeger(L, 1)));
return 1;
}
int PixelColor_graya(lua_State* L)
{
int v = lua_tointeger(L, 1);
int a = (lua_isnoneornil(L, 2) ? 255: lua_tointeger(L, 2));
lua_pushinteger(L, doc::graya(v, a));
return 1;
}
int PixelColor_grayaV(lua_State* L)
{
lua_pushinteger(L, doc::graya_getv(lua_tointeger(L, 1)));
return 1;
}
int PixelColor_grayaA(lua_State* L)
{
lua_pushinteger(L, doc::graya_geta(lua_tointeger(L, 1)));
return 1;
}
const luaL_Reg PixelColor_methods[] = {
{ "rgba", PixelColor_rgba },
{ "rgbaR", PixelColor_rgbaR },
{ "rgbaG", PixelColor_rgbaG },
{ "rgbaB", PixelColor_rgbaB },
{ "rgbaA", PixelColor_rgbaA },
{ "graya", PixelColor_graya },
{ "grayaV", PixelColor_grayaV },
{ "grayaA", PixelColor_grayaA },
{ nullptr, nullptr }
};
} // anonymous namespace
void register_app_pixel_color_object(lua_State* L)
{
lua_getglobal(L, "app");
lua_newtable(L); // New table for pixelColor
lua_pushstring(L, "pixelColor");
lua_pushvalue(L, -2); // Copy table
lua_rawset(L, -4);
luaL_setfuncs(L, PixelColor_methods, 0);
lua_pop(L, 2); // Pop table & app global
}
} // namespace script
} // namespace app

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2017 David Capello
// Copyright (C) 2017-2018 David Capello
//
// This program is distributed under the terms of
// the End-User License Agreement for Aseprite.
@ -8,111 +8,96 @@
#include "config.h"
#endif
#include "app/script/luacpp.h"
#include "gfx/point.h"
#include "script/engine.h"
namespace app {
namespace script {
namespace {
const char* kTag = "Point";
void Point_finalize(script::ContextHandle handle, void* data)
gfx::Point Point_new(lua_State* L, int index)
{
auto pt = (gfx::Point*)data;
delete pt;
}
void Point_new(script::ContextHandle handle)
{
script::Context ctx(handle);
auto pt = new gfx::Point(0, 0);
gfx::Point pt(0, 0);
// Copy other rectangle
if (ctx.isUserData(1, kTag)) {
auto pt2 = (gfx::Point*)ctx.toUserData(1, kTag);
*pt = *pt2;
if (auto pt2 = may_get_obj<gfx::Point>(L, index)) {
pt = *pt2;
}
// Convert { x, y } into a Point
else if (ctx.isObject(1)) {
ctx.getProp(1, "x");
ctx.getProp(1, "y");
pt->x = ctx.toInt(-2);
pt->y = ctx.toInt(-1);
ctx.pop(2);
else if (lua_istable(L, index)) {
lua_getfield(L, index, "x");
lua_getfield(L, index, "y");
pt.x = lua_tointeger(L, -2);
pt.y = lua_tointeger(L, -1);
lua_pop(L, 2);
}
else if (ctx.isNumber(1)) {
pt->x = ctx.toInt(1);
pt->y = ctx.toInt(2);
else {
pt.x = lua_tointeger(L, index);
pt.y = lua_tointeger(L, index+1);
}
ctx.newObject(kTag, pt, Point_finalize);
return pt;
}
void Point_get_x(script::ContextHandle handle)
int Point_new(lua_State* L)
{
script::Context ctx(handle);
auto pt = (gfx::Point*)ctx.toUserData(0, kTag);
ASSERT(pt);
ctx.pushInt(pt->x);
push_obj(L, Point_new(L, 1));
return 1;
}
void Point_get_y(script::ContextHandle handle)
int Point_get_x(lua_State* L)
{
script::Context ctx(handle);
auto pt = (gfx::Point*)ctx.toUserData(0, kTag);
ctx.pushInt(pt->y);
const auto pt = get_obj<gfx::Point>(L, 1);
lua_pushinteger(L, pt->x);
return 1;
}
void Point_set_x(script::ContextHandle handle)
int Point_get_y(lua_State* L)
{
script::Context ctx(handle);
auto pt = (gfx::Point*)ctx.toUserData(0, kTag);
ASSERT(pt);
pt->x = ctx.toInt(1);
const auto pt = get_obj<gfx::Point>(L, 1);
lua_pushinteger(L, pt->y);
return 1;
}
void Point_set_y(script::ContextHandle handle)
int Point_set_x(lua_State* L)
{
script::Context ctx(handle);
auto pt = (gfx::Point*)ctx.toUserData(0, kTag);
pt->y = ctx.toInt(1);
auto pt = get_obj<gfx::Point>(L, 1);
pt->x = lua_tointeger(L, 2);
return 0;
}
const script::FunctionEntry Point_methods[] = {
{ nullptr, nullptr, 0 }
int Point_set_y(lua_State* L)
{
auto pt = get_obj<gfx::Point>(L, 1);
pt->y = lua_tointeger(L, 2);
return 0;
}
const luaL_Reg Point_methods[] = {
{ nullptr, nullptr }
};
const script::PropertyEntry Point_props[] = {
const Property Point_properties[] = {
{ "x", Point_get_x, Point_set_x },
{ "y", Point_get_y, Point_set_y },
{ nullptr, nullptr, 0 }
{ nullptr, nullptr, nullptr }
};
} // anonymous namespace
void register_point_class(script::index_t idx, script::Context& ctx)
DEF_MTNAME(gfx::Point);
void register_point_class(lua_State* L)
{
ctx.registerClass(idx, kTag,
Point_new, 3,
Point_methods,
Point_props);
using gfx::Point;
REG_CLASS(L, Point);
REG_CLASS_NEW(L, Point);
REG_CLASS_PROPERTIES(L, Point);
}
void push_new_point(script::Context& ctx, const gfx::Point& pt)
gfx::Point convert_args_into_point(lua_State* L, int index)
{
ctx.newObject(kTag, new gfx::Point(pt), Point_finalize);
}
gfx::Point convert_args_into_point(script::Context& ctx)
{
gfx::Point result;
Point_new(ctx.handle());
auto pt = (gfx::Point*)ctx.toUserData(-1, kTag);
if (pt)
result = *pt;
ctx.pop(1);
return result;
return Point_new(L, index);
}
} // namespace script
} // namespace app

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2017 David Capello
// Copyright (C) 2017-2018 David Capello
//
// This program is distributed under the terms of
// the End-User License Agreement for Aseprite.
@ -8,151 +8,132 @@
#include "config.h"
#endif
#include "app/script/luacpp.h"
#include "gfx/rect.h"
#include "script/engine.h"
namespace app {
namespace script {
namespace {
const char* kTag = "Rectangle";
void Rectangle_finalize(script::ContextHandle handle, void* data)
gfx::Rect Rectangle_new(lua_State* L, int index)
{
auto rc = (gfx::Rect*)data;
delete rc;
}
void Rectangle_new(script::ContextHandle handle)
{
script::Context ctx(handle);
auto rc = new gfx::Rect(0, 0, 0, 0);
gfx::Rect rc(0, 0, 0, 0);
// Copy other rectangle
if (ctx.isUserData(1, kTag)) {
auto rc2 = (gfx::Rect*)ctx.toUserData(1, kTag);
*rc = *rc2;
if (auto rc2 = may_get_obj<gfx::Rect>(L, index)) {
rc = *rc2;
}
// Convert { x, y, width, height } into a Rectangle
else if (ctx.isObject(1)) {
ctx.getProp(1, "x");
ctx.getProp(1, "y");
ctx.getProp(1, "width");
ctx.getProp(1, "height");
rc->x = ctx.toInt(-4);
rc->y = ctx.toInt(-3);
rc->w = ctx.toInt(-2);
rc->h = ctx.toInt(-1);
ctx.pop(4);
else if (lua_istable(L, index)) {
lua_getfield(L, index, "x");
lua_getfield(L, index, "y");
lua_getfield(L, index, "width");
lua_getfield(L, index, "height");
rc.x = lua_tointeger(L, -4);
rc.y = lua_tointeger(L, -3);
rc.w = lua_tointeger(L, -2);
rc.h = lua_tointeger(L, -1);
lua_pop(L, 4);
}
else if (ctx.isNumber(1)) {
rc->x = ctx.toInt(1);
rc->y = ctx.toInt(2);
rc->w = ctx.toInt(3);
rc->h = ctx.toInt(4);
else {
rc.x = lua_tointeger(L, index);
rc.y = lua_tointeger(L, index+1);
rc.w = lua_tointeger(L, index+2);
rc.h = lua_tointeger(L, index+3);
}
ctx.newObject(kTag, rc, Rectangle_finalize);
return rc;
}
void Rectangle_get_x(script::ContextHandle handle)
int Rectangle_new(lua_State* L)
{
script::Context ctx(handle);
auto rc = (gfx::Rect*)ctx.toUserData(0, kTag);
ASSERT(rc);
ctx.pushInt(rc->x);
push_obj(L, Rectangle_new(L, 1));
return 1;
}
void Rectangle_get_y(script::ContextHandle handle)
int Rectangle_get_x(lua_State* L)
{
script::Context ctx(handle);
auto rc = (gfx::Rect*)ctx.toUserData(0, kTag);
ctx.pushInt(rc->y);
const auto rc = get_obj<gfx::Rect>(L, 1);
lua_pushinteger(L, rc->x);
return 1;
}
void Rectangle_get_width(script::ContextHandle handle)
int Rectangle_get_y(lua_State* L)
{
script::Context ctx(handle);
auto rc = (gfx::Rect*)ctx.toUserData(0, kTag);
ASSERT(rc);
ctx.pushInt(rc->w);
const auto rc = get_obj<gfx::Rect>(L, 1);
lua_pushinteger(L, rc->y);
return 1;
}
void Rectangle_get_height(script::ContextHandle handle)
int Rectangle_get_width(lua_State* L)
{
script::Context ctx(handle);
auto rc = (gfx::Rect*)ctx.toUserData(0, kTag);
ASSERT(rc);
ctx.pushInt(rc->h);
const auto rc = get_obj<gfx::Rect>(L, 1);
lua_pushinteger(L, rc->w);
return 1;
}
void Rectangle_set_x(script::ContextHandle handle)
int Rectangle_get_height(lua_State* L)
{
script::Context ctx(handle);
auto rc = (gfx::Rect*)ctx.toUserData(0, kTag);
ASSERT(rc);
rc->x = ctx.toInt(1);
const auto rc = get_obj<gfx::Rect>(L, 1);
lua_pushinteger(L, rc->h);
return 1;
}
void Rectangle_set_y(script::ContextHandle handle)
int Rectangle_set_x(lua_State* L)
{
script::Context ctx(handle);
auto rc = (gfx::Rect*)ctx.toUserData(0, kTag);
rc->y = ctx.toInt(1);
auto rc = get_obj<gfx::Rect>(L, 1);
rc->x = lua_tointeger(L, 2);
return 0;
}
void Rectangle_set_width(script::ContextHandle handle)
int Rectangle_set_y(lua_State* L)
{
script::Context ctx(handle);
auto rc = (gfx::Rect*)ctx.toUserData(0, kTag);
ASSERT(rc);
rc->w = ctx.toInt(1);
auto rc = get_obj<gfx::Rect>(L, 1);
rc->y = lua_tointeger(L, 2);
return 0;
}
void Rectangle_set_height(script::ContextHandle handle)
int Rectangle_set_width(lua_State* L)
{
script::Context ctx(handle);
auto rc = (gfx::Rect*)ctx.toUserData(0, kTag);
ASSERT(rc);
rc->h = ctx.toInt(1);
auto rc = get_obj<gfx::Rect>(L, 1);
rc->w = lua_tointeger(L, 2);
return 0;
}
const script::FunctionEntry Rectangle_methods[] = {
{ nullptr, nullptr, 0 }
int Rectangle_set_height(lua_State* L)
{
auto rc = get_obj<gfx::Rect>(L, 1);
rc->h = lua_tointeger(L, 2);
return 0;
}
const luaL_Reg Rectangle_methods[] = {
{ nullptr, nullptr }
};
const script::PropertyEntry Rectangle_props[] = {
const Property Rectangle_properties[] = {
{ "x", Rectangle_get_x, Rectangle_set_x },
{ "y", Rectangle_get_y, Rectangle_set_y },
{ "width", Rectangle_get_width, Rectangle_set_width },
{ "height", Rectangle_get_height, Rectangle_set_height },
{ nullptr, nullptr, 0 }
{ nullptr, nullptr, nullptr }
};
} // anonymous namespace
void register_rectangle_class(script::index_t idx, script::Context& ctx)
DEF_MTNAME(gfx::Rect);
void register_rect_class(lua_State* L)
{
ctx.registerClass(idx, kTag,
Rectangle_new, 3,
Rectangle_methods,
Rectangle_props);
using Rectangle = gfx::Rect;
REG_CLASS(L, Rectangle);
REG_CLASS_NEW(L, Rectangle);
REG_CLASS_PROPERTIES(L, Rectangle);
}
void push_new_rectangle(script::Context& ctx, const gfx::Rect& rc)
gfx::Rect convert_args_into_rect(lua_State* L, int index)
{
ctx.newObject(kTag, new gfx::Rect(rc), Rectangle_finalize);
}
gfx::Rect convert_args_into_rectangle(script::Context& ctx)
{
gfx::Rect result;
Rectangle_new(ctx.handle());
auto rc = (gfx::Rect*)ctx.toUserData(-1, kTag);
if (rc)
result = *rc;
ctx.pop(1);
return result;
return Rectangle_new(L, index);
}
} // namespace script
} // namespace app

View File

@ -11,20 +11,19 @@
#include "app/cmd/deselect_mask.h"
#include "app/cmd/set_mask.h"
#include "app/doc.h"
#include "app/script/app_scripting.h"
#include "app/script/engine.h"
#include "app/script/luacpp.h"
#include "app/transaction.h"
#include "app/tx.h"
#include "doc/mask.h"
#include "script/engine.h"
namespace app {
namespace script {
using namespace doc;
namespace {
const char* kTag = "Selection";
struct SelectionObject {
Mask* mask;
Sprite* sprite;
@ -32,29 +31,35 @@ struct SelectionObject {
: mask(mask)
, sprite(sprite) {
}
SelectionObject(SelectionObject&& that)
: mask(that.mask)
, sprite(that.sprite) {
that.mask = nullptr;
that.sprite = nullptr;
}
~SelectionObject() {
if (!sprite && mask)
delete mask;
}
SelectionObject(const SelectionObject&) = delete;
SelectionObject& operator=(const SelectionObject&) = delete;
};
void Selection_finalize(script::ContextHandle handle, void* data)
int Selection_new(lua_State* L)
{
auto obj = (SelectionObject*)data;
delete obj;
push_obj(L, SelectionObject(new Mask, nullptr));
return 1;
}
void Selection_new(script::ContextHandle handle)
int Selection_gc(lua_State* L)
{
script::Context ctx(handle);
ctx.newObject(kTag, new SelectionObject(new Mask, nullptr), Selection_finalize);
get_obj<SelectionObject>(L, 1)->~SelectionObject();
return 0;
}
void Selection_deselect(script::ContextHandle handle)
int Selection_deselect(lua_State* L)
{
script::Context ctx(handle);
auto obj = (SelectionObject*)ctx.toUserData(0, kTag);
auto obj = get_obj<SelectionObject>(L, 1);
if (obj) {
if (obj->sprite) {
Doc* doc = static_cast<Doc*>(obj->sprite->document());
@ -69,114 +74,101 @@ void Selection_deselect(script::ContextHandle handle)
obj->mask->clear();
}
}
ctx.pushUndefined();
return 0;
}
void Selection_select(script::ContextHandle handle)
int Selection_select(lua_State* L)
{
script::Context ctx(handle);
auto obj = (SelectionObject*)ctx.toUserData(0, kTag);
gfx::Rect bounds = convert_args_into_rectangle(ctx);
gfx::Rect bounds = convert_args_into_rect(L, 2);
if (bounds.isEmpty())
return Selection_deselect(L);
if (obj) {
if (bounds.isEmpty()) {
Selection_deselect(handle);
return;
auto obj = get_obj<SelectionObject>(L, 1);
if (obj->sprite) {
Doc* doc = static_cast<Doc*>(obj->sprite->document());
ASSERT(doc);
Mask newMask;
newMask.replace(bounds);
Tx tx;
tx(new cmd::SetMask(doc, &newMask));
tx.commit();
}
else {
obj->mask->replace(bounds);
}
return 0;
}
int Selection_selectAll(lua_State* L)
{
auto obj = get_obj<SelectionObject>(L, 1);
if (obj->sprite) {
Doc* doc = static_cast<Doc*>(obj->sprite->document());
Mask newMask;
newMask.replace(obj->sprite->bounds());
Tx tx;
tx(new cmd::SetMask(doc, &newMask));
tx.commit();
}
else {
gfx::Rect bounds = obj->mask->bounds();
if (!bounds.isEmpty())
obj->mask->replace(bounds);
}
return 0;
}
int Selection_get_bounds(lua_State* L)
{
auto obj = get_obj<SelectionObject>(L, 1);
if (obj->sprite) {
Doc* doc = static_cast<Doc*>(obj->sprite->document());
if (doc->isMaskVisible()) {
push_obj(L, doc->mask()->bounds());
}
else {
if (obj->sprite) {
Doc* doc = static_cast<Doc*>(obj->sprite->document());
ASSERT(doc);
Mask newMask;
newMask.replace(bounds);
Tx tx;
tx(new cmd::SetMask(doc, &newMask));
tx.commit();
}
else {
obj->mask->replace(bounds);
}
else { // Empty rectangle
push_obj(L, gfx::Rect(0, 0, 0, 0));
}
}
ctx.pushUndefined();
}
void Selection_selectAll(script::ContextHandle handle)
{
script::Context ctx(handle);
auto obj = (SelectionObject*)ctx.toUserData(0, kTag);
if (obj) {
if (obj->sprite) {
Doc* doc = static_cast<Doc*>(obj->sprite->document());
Mask newMask;
newMask.replace(obj->sprite->bounds());
Tx tx;
tx(new cmd::SetMask(doc, &newMask));
tx.commit();
}
else {
gfx::Rect bounds = obj->mask->bounds();
if (!bounds.isEmpty())
obj->mask->replace(bounds);
}
else {
push_obj(L, obj->mask->bounds());
}
ctx.pushUndefined();
return 1;
}
void Selection_get_bounds(script::ContextHandle handle)
{
script::Context ctx(handle);
auto obj = (SelectionObject*)ctx.toUserData(0, kTag);
if (obj) {
if (obj->sprite) {
Doc* doc = static_cast<Doc*>(obj->sprite->document());
if (doc->isMaskVisible()) {
push_new_rectangle(ctx, doc->mask()->bounds());
}
else { // Empty rectangle
push_new_rectangle(ctx, gfx::Rect(0, 0, 0, 0));
}
}
else {
push_new_rectangle(ctx, obj->mask->bounds());
}
}
else
ctx.pushUndefined();
}
const script::FunctionEntry Selection_methods[] = {
{ "deselect", Selection_deselect, 1 },
{ "select", Selection_select, 4 },
{ "selectAll", Selection_selectAll, 0 },
{ nullptr, nullptr, 0 }
const luaL_Reg Selection_methods[] = {
{ "deselect", Selection_deselect },
{ "select", Selection_select },
{ "selectAll", Selection_selectAll },
{ "__gc", Selection_gc },
{ nullptr, nullptr }
};
const script::PropertyEntry Selection_props[] = {
const Property Selection_properties[] = {
{ "bounds", Selection_get_bounds, nullptr },
{ nullptr, nullptr, 0 }
{ nullptr, nullptr, nullptr }
};
} // anonymous namespace
void register_selection_class(script::index_t idx, script::Context& ctx)
DEF_MTNAME(SelectionObject);
void register_selection_class(lua_State* L)
{
ctx.registerClass(idx, kTag,
Selection_new, 3,
Selection_methods,
Selection_props);
using Selection = SelectionObject;
REG_CLASS(L, Selection);
REG_CLASS_NEW(L, Selection);
REG_CLASS_PROPERTIES(L, Selection);
}
void push_sprite_selection(script::Context& ctx, Sprite* sprite)
void push_sprite_selection(lua_State* L, Sprite* sprite)
{
ctx.newObject(kTag,
new SelectionObject(nullptr, sprite),
Selection_finalize);
push_obj(L, SelectionObject(nullptr, sprite));
}
} // namespace script
} // namespace app

View File

@ -8,64 +8,54 @@
#include "config.h"
#endif
#include "app/script/app_scripting.h"
#include "app/script/engine.h"
#include "app/script/luacpp.h"
#include "app/site.h"
namespace app {
namespace script {
namespace {
const char* kTag = "Site";
void Site_finalize(script::ContextHandle handle, void* data)
int Site_get_sprite(lua_State* L)
{
auto site = (app::Site*)data;
delete site;
}
void Site_get_sprite(script::ContextHandle handle)
{
script::Context ctx(handle);
auto site = (app::Site*)ctx.toUserData(0, kTag);
auto site = get_obj<Site>(L, 1);
if (site->sprite())
push_sprite(ctx, site->sprite());
push_ptr(L, site->sprite());
else
ctx.pushNull();
lua_pushnil(L);
return 1;
}
void Site_get_image(script::ContextHandle handle)
int Site_get_image(lua_State* L)
{
script::Context ctx(handle);
auto site = (app::Site*)ctx.toUserData(0, kTag);
auto site = get_obj<Site>(L, 1);
if (site->image())
push_image(ctx, site->image());
push_ptr(L, site->image());
else
ctx.pushNull();
lua_pushnil(L);
return 1;
}
const script::FunctionEntry Site_methods[] = {
{ nullptr, nullptr, 0 }
const luaL_Reg Site_methods[] = {
{ nullptr, nullptr }
};
const script::PropertyEntry Site_props[] = {
const Property Site_properties[] = {
{ "sprite", Site_get_sprite, nullptr },
{ "image", Site_get_image, nullptr },
{ nullptr, nullptr, 0 }
{ nullptr, nullptr, nullptr }
};
} // anonymous namespace
void register_site_class(script::index_t idx, script::Context& ctx)
DEF_MTNAME(app::Site);
void register_site_class(lua_State* L)
{
ctx.registerClass(idx, kTag,
nullptr, 0,
Site_methods,
Site_props);
}
void push_site(script::Context& ctx, app::Site& site)
{
ctx.newObject(kTag, new app::Site(site), Site_finalize);
REG_CLASS(L, Site);
REG_CLASS_PROPERTIES(L, Site);
}
} // namespace script
} // namespace app

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2017 David Capello
// Copyright (C) 2017-2018 David Capello
//
// This program is distributed under the terms of
// the End-User License Agreement for Aseprite.
@ -8,113 +8,100 @@
#include "config.h"
#endif
#include "app/script/luacpp.h"
#include "gfx/size.h"
#include "script/engine.h"
namespace app {
namespace script {
namespace {
const char* kTag = "Size";
void Size_finalize(script::ContextHandle handle, void* data)
gfx::Size Size_new(lua_State* L, int index)
{
auto sz = (gfx::Size*)data;
delete sz;
}
void Size_new(script::ContextHandle handle)
{
script::Context ctx(handle);
auto sz = new gfx::Size(0, 0);
gfx::Size sz(0, 0);
// Copy other size
if (ctx.isUserData(1, kTag)) {
auto sz2 = (gfx::Size*)ctx.toUserData(1, kTag);
*sz = *sz2;
if (auto sz2 = may_get_obj<gfx::Size>(L, index)) {
sz = *sz2;
}
// Convert { width, height } into a Size
else if (ctx.isObject(1)) {
ctx.getProp(1, "width");
ctx.getProp(1, "height");
sz->w = ctx.toInt(-2);
sz->h = ctx.toInt(-1);
ctx.pop(4);
else if (lua_istable(L, index)) {
lua_getfield(L, index, "width");
lua_getfield(L, index, "height");
sz.w = lua_tointeger(L, -2);
sz.h = lua_tointeger(L, -1);
lua_pop(L, 2);
}
else if (ctx.isNumber(1)) {
sz->w = ctx.toInt(1);
sz->h = ctx.toInt(2);
else {
sz.w = lua_tointeger(L, index);
sz.h = lua_tointeger(L, index+1);
}
ctx.newObject(kTag, sz, Size_finalize);
return sz;
}
void Size_get_width(script::ContextHandle handle)
int Size_new(lua_State* L)
{
script::Context ctx(handle);
auto sz = (gfx::Size*)ctx.toUserData(0, kTag);
ASSERT(sz);
ctx.pushInt(sz->w);
push_obj(L, Size_new(L, 1));
return 1;
}
void Size_get_height(script::ContextHandle handle)
int Size_get_width(lua_State* L)
{
script::Context ctx(handle);
auto sz = (gfx::Size*)ctx.toUserData(0, kTag);
const auto sz = get_obj<gfx::Size>(L, 1);
ASSERT(sz);
ctx.pushInt(sz->h);
lua_pushinteger(L, sz->w);
return 1;
}
void Size_set_width(script::ContextHandle handle)
int Size_get_height(lua_State* L)
{
script::Context ctx(handle);
auto sz = (gfx::Size*)ctx.toUserData(0, kTag);
const auto sz = get_obj<gfx::Size>(L, 1);
ASSERT(sz);
sz->w = ctx.toInt(1);
lua_pushinteger(L, sz->h);
return 1;
}
void Size_set_height(script::ContextHandle handle)
int Size_set_width(lua_State* L)
{
script::Context ctx(handle);
auto sz = (gfx::Size*)ctx.toUserData(0, kTag);
auto sz = get_obj<gfx::Size>(L, 1);
ASSERT(sz);
sz->h = ctx.toInt(1);
sz->w = lua_tointeger(L, 2);
return 0;
}
const script::FunctionEntry Size_methods[] = {
{ nullptr, nullptr, 0 }
int Size_set_height(lua_State* L)
{
auto sz = get_obj<gfx::Size>(L, 1);
ASSERT(sz);
sz->h = lua_tointeger(L, 2);
return 0;
}
const luaL_Reg Size_methods[] = {
{ nullptr, nullptr }
};
const script::PropertyEntry Size_props[] = {
const Property Size_properties[] = {
{ "width", Size_get_width, Size_set_width },
{ "height", Size_get_height, Size_set_height },
{ nullptr, nullptr, 0 }
{ nullptr, nullptr, nullptr }
};
} // anonymous namespace
void register_size_class(script::index_t idx, script::Context& ctx)
DEF_MTNAME(gfx::Size);
void register_size_class(lua_State* L)
{
ctx.registerClass(idx, kTag,
Size_new, 3,
Size_methods,
Size_props);
using gfx::Size;
REG_CLASS(L, Size);
REG_CLASS_NEW(L, Size);
REG_CLASS_PROPERTIES(L, Size);
}
void push_new_size(script::Context& ctx, const gfx::Size& sz)
gfx::Size convert_args_into_size(lua_State* L, int index)
{
ctx.newObject(kTag, new gfx::Size(sz), Size_finalize);
}
gfx::Size convert_args_into_size(script::Context& ctx)
{
gfx::Size result;
Size_new(ctx.handle());
auto sz = (gfx::Size*)ctx.toUserData(-1, kTag);
if (sz)
result = *sz;
ctx.pop(1);
return result;
return Size_new(L, index);
}
} // namespace script
} // namespace app

View File

@ -16,7 +16,8 @@
#include "app/doc.h"
#include "app/doc_api.h"
#include "app/file/palette_file.h"
#include "app/script/app_scripting.h"
#include "app/script/engine.h"
#include "app/script/luacpp.h"
#include "app/site.h"
#include "app/transaction.h"
#include "app/tx.h"
@ -24,80 +25,70 @@
#include "doc/mask.h"
#include "doc/palette.h"
#include "doc/sprite.h"
#include "script/engine.h"
namespace app {
namespace script {
namespace {
const char* kTag = "Sprite";
void Sprite_new(script::ContextHandle handle)
int Sprite_new(lua_State* L)
{
script::Context ctx(handle);
int w = ctx.requireInt(1);
int h = ctx.requireInt(2);
int colorMode = (ctx.isUndefined(3) ? IMAGE_RGB: ctx.requireInt(3));
const int w = lua_tointeger(L, 1);
const int h = lua_tointeger(L, 2);
const int colorMode = (lua_isnone(L, 3) ? IMAGE_RGB: lua_tointeger(L, 3));
std::unique_ptr<Sprite> sprite(
Sprite::createBasicSprite((doc::PixelFormat)colorMode, w, h, 256));
std::unique_ptr<Doc> doc(new Doc(sprite.get()));
sprite.release();
app::Context* appCtx = App::instance()->context();
doc->setContext(appCtx);
app::Context* ctx = App::instance()->context();
doc->setContext(ctx);
ctx.newObject(kTag, doc->sprite(), nullptr);
push_ptr(L, doc->sprite());
doc.release();
return 1;
}
void Sprite_resize(script::ContextHandle handle)
int Sprite_resize(lua_State* L)
{
script::Context ctx(handle);
Sprite* sprite = (Sprite*)ctx.toUserData(0, kTag);
gfx::Size size = convert_args_into_size(ctx);
auto sprite = get_ptr<Sprite>(L, 1);
const gfx::Size size = convert_args_into_size(L, 2);
Doc* doc = static_cast<Doc*>(sprite->document());
Tx tx;
DocApi(doc, tx).setSpriteSize(doc->sprite(), size.w, size.h);
tx.commit();
return 0;
}
if (sprite) {
Doc* doc = static_cast<Doc*>(sprite->document());
int Sprite_crop(lua_State* L)
{
auto sprite = get_ptr<Sprite>(L, 1);
Doc* doc = static_cast<Doc*>(sprite->document());
gfx::Rect bounds;
// Use mask bounds
if (lua_isnone(L, 2)) {
if (doc->isMaskVisible())
bounds = doc->mask()->bounds();
else
bounds = sprite->bounds();
}
else {
bounds = convert_args_into_rect(L, 2);
}
if (!bounds.isEmpty()) {
Tx tx;
DocApi(doc, tx).setSpriteSize(doc->sprite(), size.w, size.h);
DocApi(doc, tx).cropSprite(sprite, bounds);
tx.commit();
}
ctx.pushUndefined();
return 0;
}
void Sprite_crop(script::ContextHandle handle)
int Sprite_save(lua_State* L)
{
script::Context ctx(handle);
auto sprite = (doc::Sprite*)ctx.toUserData(0, kTag);
if (sprite) {
Doc* doc = static_cast<Doc*>(sprite->document());
gfx::Rect bounds;
// Use mask bounds
if (ctx.isUndefined(1)) {
if (doc->isMaskVisible())
bounds = doc->mask()->bounds();
else
bounds = sprite->bounds();
}
else {
bounds = convert_args_into_rectangle(ctx);
}
if (!bounds.isEmpty()) {
Tx tx;
DocApi(doc, tx).cropSprite(sprite, bounds);
tx.commit();
}
}
ctx.pushUndefined();
}
void Sprite_save(script::ContextHandle handle)
{
script::Context ctx(handle);
auto sprite = (Sprite*)ctx.toUserData(0, kTag);
auto sprite = get_ptr<Sprite>(L, 1);
if (sprite) {
Doc* doc = static_cast<Doc*>(sprite->document());
app::Context* appCtx = App::instance()->context();
@ -106,16 +97,13 @@ void Sprite_save(script::ContextHandle handle)
Commands::instance()->byId(CommandId::SaveFile());
appCtx->executeCommand(saveCommand);
}
ctx.pushUndefined();
return 0;
}
void Sprite_saveAs(script::ContextHandle handle)
int Sprite_saveAs(lua_State* L)
{
script::Context ctx(handle);
auto sprite = (Sprite*)ctx.toUserData(0, kTag);
const char* fn = ctx.requireString(1);
auto sprite = get_ptr<Sprite>(L, 1);
const char* fn = luaL_checkstring(L, 2);
if (fn && sprite) {
Doc* doc = static_cast<Doc*>(sprite->document());
app::Context* appCtx = App::instance()->context();
@ -128,16 +116,13 @@ void Sprite_saveAs(script::ContextHandle handle)
doc->setFilename(fn);
appCtx->executeCommand(saveCommand, params);
}
ctx.pushUndefined();
return 0;
}
void Sprite_saveCopyAs(script::ContextHandle handle)
int Sprite_saveCopyAs(lua_State* L)
{
script::Context ctx(handle);
auto sprite = (Sprite*)ctx.toUserData(0, kTag);
const char* fn = ctx.requireString(1);
auto sprite = get_ptr<Sprite>(L, 1);
const char* fn = luaL_checkstring(L, 2);
if (fn && sprite) {
Doc* doc = static_cast<Doc*>(sprite->document());
app::Context* appCtx = App::instance()->context();
@ -150,16 +135,13 @@ void Sprite_saveCopyAs(script::ContextHandle handle)
params.set("filename", fn);
appCtx->executeCommand(saveCommand, params);
}
ctx.pushUndefined();
return 0;
}
void Sprite_loadPalette(script::ContextHandle handle)
int Sprite_loadPalette(lua_State* L)
{
script::Context ctx(handle);
auto sprite = (doc::Sprite*)ctx.toUserData(0, kTag);
const char* fn = ctx.toString(1);
auto sprite = get_ptr<Sprite>(L, 1);
const char* fn = luaL_checkstring(L, 2);
if (fn && sprite) {
Doc* doc = static_cast<Doc*>(sprite->document());
std::unique_ptr<doc::Palette> palette(load_palette(fn));
@ -170,100 +152,94 @@ void Sprite_loadPalette(script::ContextHandle handle)
tx.commit();
}
}
ctx.pushUndefined();
return 0;
}
void Sprite_get_filename(script::ContextHandle handle)
int Sprite_get_filename(lua_State* L)
{
script::Context ctx(handle);
auto sprite = (doc::Sprite*)ctx.toUserData(0, kTag);
ctx.pushString(sprite->document()->filename().c_str());
auto sprite = get_ptr<Sprite>(L, 1);
lua_pushstring(L, sprite->document()->filename().c_str());
return 1;
}
void Sprite_get_width(script::ContextHandle handle)
int Sprite_get_width(lua_State* L)
{
script::Context ctx(handle);
auto sprite = (doc::Sprite*)ctx.toUserData(0, kTag);
ctx.pushInt(sprite->width());
auto sprite = get_ptr<Sprite>(L, 1);
lua_pushinteger(L, sprite->width());
return 1;
}
void Sprite_set_width(script::ContextHandle handle)
int Sprite_get_height(lua_State* L)
{
script::Context ctx(handle);
auto sprite = (Sprite*)ctx.toUserData(0, kTag);
const int width = ctx.requireInt(1);
auto sprite = get_ptr<Sprite>(L, 1);
lua_pushinteger(L, sprite->height());
return 1;
}
int Sprite_get_colorMode(lua_State* L)
{
auto sprite = get_ptr<Sprite>(L, 1);
lua_pushinteger(L, sprite->pixelFormat());
return 1;
}
int Sprite_get_selection(lua_State* L)
{
auto sprite = get_ptr<Sprite>(L, 1);
push_sprite_selection(L, sprite);
return 1;
}
int Sprite_set_width(lua_State* L)
{
auto sprite = get_ptr<Sprite>(L, 1);
const int width = lua_tointeger(L, 2);
Tx tx;
tx(new cmd::SetSpriteSize(sprite,
width, sprite->height()));
tx(new cmd::SetSpriteSize(sprite, width, sprite->height()));
tx.commit();
ctx.pushUndefined();
return 0;
}
void Sprite_get_height(script::ContextHandle handle)
int Sprite_set_height(lua_State* L)
{
script::Context ctx(handle);
auto sprite = (doc::Sprite*)ctx.toUserData(0, kTag);
ctx.pushInt(sprite->height());
}
void Sprite_set_height(script::ContextHandle handle)
{
script::Context ctx(handle);
auto sprite = (Sprite*)ctx.toUserData(0, kTag);
const int height = ctx.requireInt(1);
auto sprite = get_ptr<Sprite>(L, 1);
const int height = lua_tointeger(L, 2);
Tx tx;
tx(new cmd::SetSpriteSize(sprite,
sprite->width(), height));
tx(new cmd::SetSpriteSize(sprite, sprite->width(), height));
tx.commit();
ctx.pushUndefined();
return 0;
}
void Sprite_get_colorMode(script::ContextHandle handle)
{
script::Context ctx(handle);
auto sprite = (doc::Sprite*)ctx.toUserData(0, kTag);
ctx.pushInt(sprite->pixelFormat());
}
void Sprite_get_selection(script::ContextHandle handle)
{
script::Context ctx(handle);
auto sprite = (doc::Sprite*)ctx.toUserData(0, kTag);
push_sprite_selection(ctx, sprite);
}
const script::FunctionEntry Sprite_methods[] = {
{ "resize", Sprite_resize, 2 },
{ "crop", Sprite_crop, 4 },
{ "save", Sprite_save, 2 },
{ "saveAs", Sprite_saveAs, 2 },
{ "saveCopyAs", Sprite_saveCopyAs, 2 },
{ "loadPalette", Sprite_loadPalette, 1 },
{ nullptr, nullptr, 0 }
const luaL_Reg Sprite_methods[] = {
{ "resize", Sprite_resize },
{ "crop", Sprite_crop },
{ "save", Sprite_save },
{ "saveAs", Sprite_saveAs },
{ "saveCopyAs", Sprite_saveCopyAs },
{ "loadPalette", Sprite_loadPalette },
{ nullptr, nullptr }
};
const script::PropertyEntry Sprite_props[] = {
const Property Sprite_properties[] = {
{ "filename", Sprite_get_filename, nullptr },
{ "width", Sprite_get_width, Sprite_set_width },
{ "height", Sprite_get_height, Sprite_set_height },
{ "colorMode", Sprite_get_colorMode, nullptr },
{ "selection", Sprite_get_selection, nullptr },
{ nullptr, nullptr, 0 }
{ nullptr, nullptr, nullptr }
};
} // anonymous namespace
void register_sprite_class(script::index_t idx, script::Context& ctx)
DEF_MTNAME(doc::Sprite);
void register_sprite_class(lua_State* L)
{
ctx.registerClass(idx, kTag,
Sprite_new, 3,
Sprite_methods, Sprite_props);
}
void push_sprite(script::Context& ctx, Sprite* sprite)
{
ctx.newObject(kTag, sprite, nullptr);
using doc::Sprite;
REG_CLASS(L, Sprite);
REG_CLASS_NEW(L, Sprite);
REG_CLASS_PROPERTIES(L, Sprite);
}
} // namespace script
} // namespace app

View File

@ -31,10 +31,10 @@ Shell::~Shell()
void Shell::run(script::Engine& engine)
{
std::cout << "Welcome to " PACKAGE " v" VERSION " interactive console" << std::endl;
std::cout << "Welcome to " PACKAGE " v" VERSION " Interactive Console" << std::endl;
std::string line;
while (std::getline(std::cin, line)) {
engine.eval(line);
engine.evalCode(line);
}
std::cout << "Done\n";
}

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2001-2016 David Capello
// Copyright (C) 2001-2018 David Capello
//
// This program is distributed under the terms of
// the End-User License Agreement for Aseprite.
@ -12,11 +12,10 @@
#error ENABLE_SCRIPTING must be defined
#endif
namespace script {
class Engine;
}
namespace app {
namespace script {
class Engine;
}
class Shell {
public:

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2001-2017 David Capello
// Copyright (C) 2001-2018 David Capello
//
// This program is distributed under the terms of
// the End-User License Agreement for Aseprite.
@ -63,7 +63,7 @@ protected:
DevConsoleView::DevConsoleView()
: Box(VERTICAL)
, m_textBox("Welcome to Aseprite JavaScript Console\n(Experimental)", LEFT)
, m_textBox("Welcome to " PACKAGE " v" VERSION " Console\n(Experimental)", LEFT)
, m_label(">")
, m_entry(new CommmandEntry)
, m_engine(this)
@ -137,7 +137,7 @@ bool DevConsoleView::onProcessMessage(Message* msg)
void DevConsoleView::onExecuteCommand(const std::string& cmd)
{
m_engine.printLastResult();
m_engine.eval(cmd);
m_engine.evalCode(cmd);
}
void DevConsoleView::onConsolePrint(const char* text)

View File

@ -12,10 +12,9 @@
#error ENABLE_SCRIPTING must be defined
#endif
#include "app/script/app_scripting.h"
#include "app/script/engine.h"
#include "app/ui/tabs.h"
#include "app/ui/workspace_view.h"
#include "script/engine_delegate.h"
#include "ui/box.h"
#include "ui/label.h"
#include "ui/textbox.h"
@ -57,7 +56,7 @@ namespace app {
ui::HBox m_bottomBox;
ui::Label m_label;
CommmandEntry* m_entry;
AppScripting m_engine;
script::Engine m_engine;
};
} // namespace app

View File

@ -1,8 +0,0 @@
# Aseprite Scripting Library
# Copyright (C) 2015-2017 David Capello
add_library(script-lib engine.cpp engine_delegate.cpp)
target_link_libraries(script-lib
laf-base
mujs)

View File

@ -1,20 +0,0 @@
Copyright (c) 2015-2016 David Capello
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -1,4 +0,0 @@
# Aseprite Scripting Library
*Copyright (C) 2015-2017 David Capello*
> Distributed under [MIT license](LICENSE.txt)

View File

@ -1,460 +0,0 @@
// Aseprite Scripting Library
// Copyright (c) 2015-2017 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "script/engine.h"
#include "base/convert_to.h"
#include "base/exception.h"
#include "base/file_handle.h"
#include "base/fstream_path.h"
#include "base/memory.h"
#include "script/engine_delegate.h"
#include <fstream>
#include <iostream>
#include <map>
#include <sstream>
extern "C" {
#include <mujs/mujs.h>
}
namespace script {
static const char* stacktrace_js =
"Error.prototype.toString = function() {\n"
" if (this.stackTrace)\n"
" return this.name + ': ' + this.message + this.stackTrace;\n"
" return this.name + ': ' + this.message;\n"
"}";
void Context::setContextUserData(void* userData)
{
js_setcontext(m_handle, userData);
}
void* Context::getContextUserData()
{
return js_getcontext(m_handle);
}
void Context::error(const char* err)
{
js_error(m_handle, "%s", err);
}
void Context::pop()
{
js_pop(m_handle, 1);
}
void Context::pop(index_t count)
{
js_pop(m_handle, count);
}
void Context::remove(index_t idx)
{
js_remove(m_handle, idx);
}
void Context::duplicateTop()
{
js_dup(m_handle);
}
index_t Context::top()
{
return js_gettop(m_handle);
}
void Context::copy(index_t i)
{
js_copy(m_handle, i);
}
void Context::call(index_t args)
{
js_call(m_handle, args);
}
bool Context::isUndefined(index_t i)
{
return (js_isundefined(m_handle, i) ? true: false);
}
bool Context::isNull(index_t i)
{
return (js_isnull(m_handle, i) ? true: false);
}
bool Context::isNullOrUndefined(index_t i)
{
return (js_isnull(m_handle, i) ||
js_isundefined(m_handle, i)? true: false);
}
bool Context::isBool(index_t i)
{
return (js_isboolean(m_handle, i) ? true: false);
}
bool Context::isNumber(index_t i)
{
return (js_isnumber(m_handle, i) ? true: false);
}
bool Context::isString(index_t i)
{
return (js_isstring(m_handle, i) ? true: false);
}
bool Context::isObject(index_t i)
{
return (js_isobject(m_handle, i) ? true: false);
}
bool Context::isArray(index_t i)
{
return (js_isarray(m_handle, i) ? true: false);
}
bool Context::isCallable(index_t i)
{
return (js_iscallable(m_handle, i) ? true: false);
}
bool Context::isUserData(index_t i, const char* tag)
{
return (js_isuserdata(m_handle, i, tag) ? true: false);
}
bool Context::toBool(index_t i)
{
return (js_toboolean(m_handle, i) ? true: false);
}
double Context::toNumber(index_t i)
{
return js_tonumber(m_handle, i);
}
int Context::toInt(index_t i)
{
return js_toint32(m_handle, i);
}
unsigned int Context::toUInt(index_t i)
{
return js_touint32(m_handle, i);
}
const char* Context::toString(index_t i)
{
return js_tostring(m_handle, i);
}
void* Context::toUserData(index_t i, const char* tag)
{
return js_touserdata(m_handle, i, tag);
}
bool Context::requireBool(index_t i)
{
if (js_isboolean(m_handle, i))
return true;
else {
js_typeerror(m_handle, "not a boolean (index %d)\n", i);
return false;
}
}
double Context::requireNumber(index_t i)
{
if (js_isnumber(m_handle, i))
return js_tonumber(m_handle, i);
else {
js_typeerror(m_handle, "not a number (index %d)\n", i);
return 0.0;
}
}
int Context::requireInt(index_t i)
{
return (int)requireNumber(i);
}
unsigned int Context::requireUInt(index_t i)
{
return (unsigned int)requireNumber(i);
}
const char* Context::requireString(index_t i)
{
if (js_isstring(m_handle, i))
return js_tostring(m_handle, i);
else {
js_typeerror(m_handle, "not a string (index %d)\n", i);
return nullptr;
}
}
void* Context::requireUserData(index_t i, const char* tag)
{
if (js_isuserdata(m_handle, i, tag))
return js_touserdata(m_handle, i, tag);
else {
js_typeerror(m_handle, "not a user data (index %d, tag %s)\n", i, tag);
return nullptr;
}
}
void Context::pushUndefined()
{
js_pushundefined(m_handle);
}
void Context::pushNull()
{
js_pushnull(m_handle);
}
void Context::pushBool(bool val)
{
js_pushboolean(m_handle, val);
}
void Context::pushNumber(double val)
{
js_pushnumber(m_handle, val);
}
void Context::pushInt(int val)
{
js_pushnumber(m_handle, double(val));
}
void Context::pushUInt(unsigned int val)
{
js_pushnumber(m_handle, double(val));
}
void Context::pushString(const char* str)
{
js_pushstring(m_handle, str);
}
void Context::pushGlobalObject()
{
js_pushglobal(m_handle);
}
void Context::newObject()
{
js_newobject(m_handle);
}
void Context::newObject(const char* className,
void* userData,
FinalizeFunction finalize)
{
js_getglobal(m_handle, className); // class
js_getproperty(m_handle, -1, "prototype"); // class prototype
js_newuserdata(m_handle, className, userData, finalize); // class userdata
js_rot2(m_handle); // userdata class
js_pop(m_handle, 1); // userdata
}
void Context::newUserData(const char* tag,
void* userData,
FinalizeFunction finalize)
{
js_newuserdata(m_handle, tag, userData, finalize);
}
void Context::registerConstants(index_t idx,
const ConstantEntry* consts)
{
if (idx < 0)
--idx;
for (; consts->id; ++consts) {
js_pushnumber(m_handle, consts->value);
js_defproperty(m_handle, idx, consts->id, JS_DONTENUM);
}
}
void Context::registerProp(index_t idx,
const char* id,
Function getter,
Function setter)
{
if (idx < 0)
idx -= 2;
if (getter)
js_newcfunction(m_handle, getter,
(std::string(id) + ".getter").c_str(), 0);
else
js_pushnull(m_handle);
if (setter)
js_newcfunction(m_handle, setter,
(std::string(id) + ".setter").c_str(), 1);
else
js_pushnull(m_handle);
js_defaccessor(m_handle, idx, id, JS_DONTENUM);
}
void Context::registerProps(index_t idx, const PropertyEntry* props)
{
for (int i=0; props[i].id; ++i) {
registerProp(idx,
props[i].id,
props[i].getter,
props[i].setter);
}
}
void Context::registerFunc(index_t idx,
const char* id,
const Function func,
index_t nargs)
{
js_newcfunction(m_handle, func, id, nargs);
js_defproperty(m_handle, idx, id, JS_DONTENUM);
}
void Context::registerFuncs(index_t idx, const FunctionEntry* methods)
{
if (idx < 0)
--idx;
for (; methods->id; ++methods) {
registerFunc(idx,
methods->id,
methods->value,
methods->nargs);
}
}
void Context::registerObject(index_t idx,
const char* id,
const FunctionEntry* methods,
const PropertyEntry* props)
{
if (idx < 0)
--idx;
newObject();
if (methods) registerFuncs(-1, methods);
if (props) registerProps(-1, props);
js_defproperty(m_handle, idx, id, JS_DONTENUM);
}
void Context::registerClass(index_t idx,
const char* id,
Function ctorFunc, int ctorNargs,
const FunctionEntry* methods,
const PropertyEntry* props)
{
if (idx < 0)
idx -= 2;
js_getglobal(m_handle, "Object");
js_getproperty(m_handle, -1, "prototype");
js_newuserdata(m_handle, id, nullptr, nullptr);
if (methods) registerFuncs(-1, methods);
if (props) registerProps(-1, props);
js_newcconstructor(m_handle, ctorFunc, ctorFunc, id, ctorNargs);
js_defproperty(m_handle, idx, id, JS_DONTENUM);
js_pop(m_handle, 1); // pop Object
}
bool Context::hasProp(index_t i, const char* propName)
{
return (js_hasproperty(m_handle, i, propName) ? true: false);
}
void Context::getProp(index_t i, const char* propName)
{
js_getproperty(m_handle, i, propName);
}
void Context::setProp(index_t i, const char* propName)
{
js_defproperty(m_handle, i, propName, JS_DONTENUM);
}
Engine::Engine(EngineDelegate* delegate)
: m_ctx(js_newstate(NULL, NULL, JS_STRICT))
, m_delegate(delegate)
, m_printLastResult(false)
{
// Pre-scripts
js_dostring(m_ctx.handle(), stacktrace_js);
}
Engine::~Engine()
{
js_freestate(m_ctx.handle());
}
void Engine::printLastResult()
{
m_printLastResult = true;
}
bool Engine::eval(const std::string& jsCode,
const std::string& filename)
{
bool errFlag = true;
onBeforeEval();
ContextHandle handle = m_ctx.handle();
if (js_ploadstring(handle, filename.c_str(), jsCode.c_str()) == 0) {
js_pushundefined(handle);
if (js_pcall(handle, 0) == 0) {
if (m_printLastResult) {
if (!js_isundefined(handle, -1)) {
const char* result = js_tostring(handle, -1);
if (result)
m_delegate->onConsolePrint(result);
}
}
errFlag = false;
}
}
// Print error message
if (errFlag) {
std::string err;
const char* s = js_trystring(handle, -1, "Error");
if (s)
m_delegate->onConsolePrint(s);
}
js_pop(handle, 1);
onAfterEval(errFlag);
return !errFlag;
}
bool Engine::evalFile(const std::string& filename)
{
std::stringstream buf;
{
std::ifstream s(FSTREAM_PATH(filename));
buf << s.rdbuf();
}
return eval(buf.str(), filename);
}
} // namespace script

View File

@ -1,165 +0,0 @@
// Aseprite Scripting Library
// Copyright (c) 2015-2017 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifndef SCRIPT_ENGINE_H_INCLUDED
#define SCRIPT_ENGINE_H_INCLUDED
#pragma once
#include <string>
struct js_State;
namespace script {
class Context;
class EngineDelegate;
typedef int result_t;
typedef int index_t;
typedef js_State* ContextHandle;
typedef void (*Function)(ContextHandle);
typedef void (*FinalizeFunction)(ContextHandle, void*);
struct FunctionEntry {
const char* id;
Function value;
index_t nargs;
};
struct PropertyEntry {
const char* id;
Function getter;
Function setter;
};
struct ConstantEntry {
const char* id;
double value;
};
class Module {
public:
virtual ~Module() { }
virtual const char* id() const = 0;
virtual int registerModule(Context& ctx) = 0;
};
class Context {
public:
Context(ContextHandle handle) : m_handle(handle) { }
ContextHandle handle() { return m_handle; }
void setContextUserData(void* userData);
void* getContextUserData();
void error(const char* err);
void pop();
void pop(index_t count);
void remove(index_t idx);
void duplicateTop();
index_t top();
void copy(index_t i);
void call(index_t args);
bool isUndefined(index_t i);
bool isNull(index_t i);
bool isNullOrUndefined(index_t i);
bool isBool(index_t i);
bool isNumber(index_t i);
bool isString(index_t i);
bool isObject(index_t i);
bool isArray(index_t i);
bool isUserData(index_t i, const char* tag);
bool isCallable(index_t i);
bool toBool(index_t i);
double toNumber(index_t i);
int toInt(index_t i);
unsigned int toUInt(index_t i);
const char* toString(index_t i);
void* toUserData(index_t i, const char* tag);
bool hasProp(index_t i, const char* propName);
void getProp(index_t i, const char* propName);
void setProp(index_t i, const char* propName);
bool requireBool(index_t i);
double requireNumber(index_t i);
int requireInt(index_t i);
unsigned int requireUInt(index_t i);
const char* requireString(index_t i);
void* requireUserData(index_t i, const char* tag);
void pushUndefined();
void pushNull();
void pushBool(bool val);
void pushNumber(double val);
void pushInt(int val);
void pushUInt(unsigned int val);
void pushString(const char* str);
void pushGlobalObject();
void newObject();
void newObject(const char* className,
void* userData,
FinalizeFunction finalize);
void newUserData(const char* tag,
void* userData,
FinalizeFunction finalize);
void registerConstants(index_t idx,
const ConstantEntry* consts);
void registerProp(index_t idx,
const char* id,
Function getter,
Function setter);
void registerProps(index_t idx,
const PropertyEntry* props);
void registerFunc(index_t idx,
const char* id,
const Function func,
index_t nargs);
void registerFuncs(index_t idx,
const FunctionEntry* methods);
void registerObject(index_t idx,
const char* id,
const FunctionEntry* methods,
const PropertyEntry* props);
void registerClass(index_t idx,
const char* id,
Function ctorFunc, int ctorNargs,
const FunctionEntry* methods,
const PropertyEntry* props);
private:
ContextHandle m_handle;
};
class Engine {
public:
Engine(EngineDelegate* delegate);
~Engine();
void printLastResult();
bool eval(const std::string& jsCode,
const std::string& filename = std::string());
bool evalFile(const std::string& filename);
Context& context() { return m_ctx; }
protected:
virtual void onBeforeEval() { }
virtual void onAfterEval(bool err) { }
private:
Context m_ctx;
EngineDelegate* m_delegate;
bool m_printLastResult;
};
}
#endif

View File

@ -1,22 +0,0 @@
// Aseprite Scripting Library
// Copyright (c) 2015-2016 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "script/engine_delegate.h"
#include <cstdio>
namespace script {
void StdoutEngineDelegate::onConsolePrint(const char* text)
{
std::printf("%s\n", text);
}
} // namespace script

View File

@ -1,26 +0,0 @@
// Aseprite Scripting Library
// Copyright (c) 2015-2016 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifndef SCRIPT_ENGINE_DELEGATE_H_INCLUDED
#define SCRIPT_ENGINE_DELEGATE_H_INCLUDED
#pragma once
namespace script {
class EngineDelegate {
public:
virtual ~EngineDelegate() { }
virtual void onConsolePrint(const char* text) = 0;
};
class StdoutEngineDelegate : public EngineDelegate {
public:
void onConsolePrint(const char* text) override;
};
}
#endif

View File

@ -134,10 +134,6 @@ public:
allegro_exit();
}
void dispose() override {
delete this;
}
void activateApp() override {
// Do nothing
}

View File

@ -49,6 +49,7 @@ public:
}
void dispose() override {
set_instance(nullptr);
delete this;
}

View File

@ -28,4 +28,9 @@ System* instance()
return g_system;
}
void set_instance(System* system)
{
g_system = system;
}
} // namespace she

View File

@ -82,6 +82,7 @@ namespace she {
System* create_system();
System* instance();
void set_instance(System* system);
} // namespace she

View File

@ -140,36 +140,47 @@ if(ENABLE_BENCHMARKS)
add_subdirectory(benchmark)
endif()
# mujs
add_library(mujs
mujs/jsarray.c
mujs/jsboolean.c
mujs/jsbuiltin.c
mujs/jscompile.c
mujs/jsdate.c
mujs/jsdtoa.c
mujs/jsdump.c
mujs/jserror.c
mujs/jsfunction.c
mujs/jsgc.c
mujs/jsintern.c
mujs/jslex.c
mujs/jsmath.c
mujs/jsnumber.c
mujs/jsobject.c
mujs/json.c
mujs/jsparse.c
mujs/jsproperty.c
mujs/jsregexp.c
mujs/jsrun.c
mujs/jsstate.c
mujs/jsstring.c
mujs/jsvalue.c
mujs/regexp.c
mujs/utf.c
mujs/utftype.c)
target_include_directories(mujs PUBLIC .)
# tinyexpr
add_library(tinyexpr tinyexpr/tinyexpr.c)
target_include_directories(tinyexpr PUBLIC tinyexpr)
# lua
add_library(lua
lua/lapi.c
lua/lcode.c
lua/lctype.c
lua/ldebug.c
lua/ldo.c
lua/ldump.c
lua/lfunc.c
lua/lgc.c
lua/llex.c
lua/lmem.c
lua/lobject.c
lua/lopcodes.c
lua/lparser.c
lua/lstate.c
lua/lstring.c
lua/ltable.c
lua/ltm.c
lua/lundump.c
lua/lvm.c
lua/lzio.c
lua/ltests.c)
add_library(lauxlib lua/lauxlib.c)
add_library(lualib
lua/lbaselib.c
lua/lcorolib.c
lua/ldblib.c
lua/linit.c
lua/liolib.c
lua/lmathlib.c
lua/loadlib.c
lua/loslib.c
lua/lstrlib.c
lua/ltablib.c
lua/lutf8lib.c)
target_include_directories(lua PUBLIC lua)
target_include_directories(lauxlib PUBLIC lua)
target_include_directories(lualib PUBLIC lua)
target_link_libraries(lauxlib lua)

1
third_party/lua vendored Submodule

@ -0,0 +1 @@
Subproject commit f59e6a93c0ad38a27a420e51abf8f13d962446b5

1
third_party/mujs vendored

@ -1 +0,0 @@
Subproject commit 34cb61711fe29934dfa82ab55ea59ed85ae62642