lua: add functions to create layers/frames/cels/tags/slices

Some extra additions:
* Layer.cels
* AniDir constants
* Slice property setters
* Tag.sprite
* Fixed frame numbers in Tag properties
This commit is contained in:
David Capello 2018-09-11 18:29:15 -03:00
parent 4c5637f636
commit 03c663da21
9 changed files with 390 additions and 34 deletions

View File

@ -10,9 +10,11 @@
#include "app/script/luacpp.h"
#include "doc/cels_range.h"
#include "doc/layer.h"
#include "doc/sprite.h"
#include <algorithm>
#include <iterator>
namespace app {
namespace script {
@ -22,8 +24,11 @@ using namespace doc;
namespace {
struct CelsObj {
Sprite* sprite;
CelsObj(Sprite* sprite) : sprite(sprite) { }
CelList cels;
CelsObj(CelsRange&& range) {
std::copy(range.begin(), range.end(), std::back_inserter(cels));
}
CelsObj(CelList&& cels) : cels(std::move(cels)) { }
CelsObj(const CelsObj&) = delete;
CelsObj& operator=(const CelsObj&) = delete;
};
@ -37,7 +42,7 @@ int Cels_gc(lua_State* L)
int Cels_len(lua_State* L)
{
auto obj = get_obj<CelsObj>(L, 1);
lua_pushinteger(L, obj->sprite->cels().size());
lua_pushinteger(L, obj->cels.size());
return 1;
}
@ -45,13 +50,9 @@ int Cels_index(lua_State* L)
{
auto obj = get_obj<CelsObj>(L, 1);
const int i = lua_tointeger(L, 2);
if (i < 1 || i > obj->sprite->cels().size())
if (i < 1 || i > obj->cels.size())
return luaL_error(L, "index out of bounds %d", i);
auto it = obj->sprite->cels().begin();
std::advance(it, i-1); // TODO improve this
push_ptr<Cel>(L, *it);
push_ptr<Cel>(L, obj->cels[i-1]);
return 1;
}
@ -74,7 +75,15 @@ void register_cels_class(lua_State* L)
void push_sprite_cels(lua_State* L, Sprite* sprite)
{
push_new<CelsObj>(L, sprite);
push_new<CelsObj>(L, sprite->cels());
}
void push_layer_cels(lua_State* L, Layer* layer)
{
CelList cels;
if (layer->isImage())
static_cast<LayerImage*>(layer)->getCels(cels);
push_new<CelsObj>(L, std::move(cels));
}
} // namespace script

View File

@ -16,6 +16,8 @@
#include "base/chrono.h"
#include "base/fs.h"
#include "base/fstream_path.h"
#include "doc/anidir.h"
#include "doc/blend_mode.h"
#include "doc/color_mode.h"
#include <fstream>
@ -154,6 +156,14 @@ Engine::Engine()
setfield_integer(L, "INDEXED", doc::ColorMode::INDEXED);
lua_pop(L, 1);
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);
lua_pop(L, 1);
lua_newtable(L);
lua_pushvalue(L, -1);
lua_setglobal(L, "BlendMode");

View File

@ -85,6 +85,7 @@ namespace app {
void push_cel_image(lua_State* L, doc::Cel* cel);
void push_sprite_cel(lua_State* L, doc::Cel* cel);
void push_sprite_cels(lua_State* L, doc::Sprite* sprite);
void push_layer_cels(lua_State* L, doc::Layer* layer);
void push_sprite_frame(lua_State* L, doc::Sprite* sprite, doc::frame_t frame);
void push_sprite_frames(lua_State* L, doc::Sprite* sprite);
void push_sprite_layers(lua_State* L, doc::Sprite* sprite);
@ -101,6 +102,7 @@ namespace app {
app::Color convert_args_into_color(lua_State* L, int index);
doc::color_t convert_args_into_pixel_color(lua_State* L, int index);
doc::Palette* get_palette_from_arg(lua_State* L, int index);
doc::Image* may_get_image_from_arg(lua_State* L, int index);
} // namespace script
} // namespace app

View File

@ -172,5 +172,14 @@ void push_cel_image(lua_State* L, doc::Cel* cel)
push_new<ImageObj>(L, cel->imageRef(), cel);
}
doc::Image* may_get_image_from_arg(lua_State* L, int index)
{
auto obj = may_get_obj<ImageObj>(L, index);
if (obj)
return obj->image.get();
else
return nullptr;
}
} // namespace script
} // namespace app

View File

@ -97,6 +97,13 @@ int Layer_get_isBackground(lua_State* L)
return 1;
}
int Layer_get_cels(lua_State* L)
{
auto layer = get_ptr<Layer>(L, 1);
push_layer_cels(L, layer);
return 1;
}
int Layer_set_name(lua_State* L)
{
auto layer = get_ptr<Layer>(L, 1);
@ -148,6 +155,7 @@ const Property Layer_properties[] = {
{ "isGroup", Layer_get_isGroup, nullptr },
{ "isTransparent", Layer_get_isTransparent, nullptr },
{ "isBackground", Layer_get_isBackground, nullptr },
{ "cels", Layer_get_cels, nullptr },
{ "color", UserData_get_color<Layer>, UserData_set_color<Layer> },
{ "data", UserData_get_text<Layer>, UserData_set_text<Layer> },
{ nullptr, nullptr, nullptr }

View File

@ -58,6 +58,15 @@ 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_ptr(lua_State* L, int index) {
T** ptr = (T**)luaL_testudata(L, index, get_mtname<T>());
if (ptr)
return *ptr;
else
return nullptr;
}
// 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>());

View File

@ -8,6 +8,8 @@
#include "config.h"
#endif
#include "app/cmd/set_slice_key.h"
#include "app/cmd/set_slice_name.h"
#include "app/script/engine.h"
#include "app/script/luacpp.h"
#include "app/script/userdata.h"
@ -37,20 +39,6 @@ int Slice_get_sprite(lua_State* L)
return 1;
}
int Slice_get_fromFrame(lua_State* L)
{
auto slice = get_ptr<Slice>(L, 1);
lua_pushinteger(L, slice->fromFrame());
return 1;
}
int Slice_get_toFrame(lua_State* L)
{
auto slice = get_ptr<Slice>(L, 1);
lua_pushinteger(L, slice->toFrame());
return 1;
}
int Slice_get_name(lua_State* L)
{
auto slice = get_ptr<Slice>(L, 1);
@ -88,6 +76,60 @@ int Slice_get_pivot(lua_State* L)
return 1;
}
int Slice_set_name(lua_State* L)
{
auto slice = get_ptr<Slice>(L, 1);
const char* name = lua_tostring(L, 2);
if (name) {
Tx tx;
tx(new cmd::SetSliceName(slice, name));
tx.commit();
}
return 0;
}
int Slice_set_bounds(lua_State* L)
{
auto slice = get_ptr<Slice>(L, 1);
gfx::Rect bounds = convert_args_into_rect(L, 2);
SliceKey key;
if (const SliceKey* srcKey = slice->getByFrame(0))
key = *srcKey;
key.setBounds(bounds);
Tx tx;
tx(new cmd::SetSliceKey(slice, 0, key));
tx.commit();
return 0;
}
int Slice_set_center(lua_State* L)
{
auto slice = get_ptr<Slice>(L, 1);
gfx::Rect center = convert_args_into_rect(L, 2);
SliceKey key;
if (const SliceKey* srcKey = slice->getByFrame(0))
key = *srcKey;
key.setCenter(center);
Tx tx;
tx(new cmd::SetSliceKey(slice, 0, key));
tx.commit();
return 0;
}
int Slice_set_pivot(lua_State* L)
{
auto slice = get_ptr<Slice>(L, 1);
gfx::Point pivot = convert_args_into_point(L, 2);
SliceKey key;
if (const SliceKey* srcKey = slice->getByFrame(0))
key = *srcKey;
key.setPivot(pivot);
Tx tx;
tx(new cmd::SetSliceKey(slice, 0, key));
tx.commit();
return 0;
}
const luaL_Reg Slice_methods[] = {
{ "__eq", Slice_eq },
{ nullptr, nullptr }
@ -95,12 +137,10 @@ const luaL_Reg Slice_methods[] = {
const Property Slice_properties[] = {
{ "sprite", Slice_get_sprite, nullptr },
{ "fromFrame", Slice_get_fromFrame, nullptr },
{ "toFrame", Slice_get_toFrame, nullptr },
{ "name", Slice_get_name, nullptr },
{ "bounds", Slice_get_bounds, nullptr },
{ "center", Slice_get_center, nullptr },
{ "pivot", Slice_get_pivot, nullptr },
{ "name", Slice_get_name, Slice_set_name },
{ "bounds", Slice_get_bounds, Slice_set_bounds },
{ "center", Slice_get_center, Slice_set_center },
{ "pivot", Slice_get_pivot, Slice_set_pivot },
{ "color", UserData_get_color<Slice>, UserData_set_color<Slice> },
{ "data", UserData_get_text<Slice>, UserData_set_text<Slice> },
{ nullptr, nullptr, nullptr }

View File

@ -9,6 +9,11 @@
#endif
#include "app/app.h"
#include "app/cmd/add_layer.h"
#include "app/cmd/clear_cel.h"
#include "app/cmd/remove_frame_tag.h"
#include "app/cmd/remove_layer.h"
#include "app/cmd/remove_slice.h"
#include "app/cmd/set_sprite_size.h"
#include "app/cmd/set_transparent_color.h"
#include "app/commands/commands.h"
@ -23,9 +28,11 @@
#include "app/transaction.h"
#include "app/tx.h"
#include "app/ui/doc_view.h"
#include "doc/frame_tag.h"
#include "doc/layer.h"
#include "doc/mask.h"
#include "doc/palette.h"
#include "doc/slice.h"
#include "doc/sprite.h"
namespace app {
@ -178,6 +185,243 @@ int Sprite_setPalette(lua_State* L)
return 0;
}
int Sprite_newLayer(lua_State* L)
{
auto sprite = get_ptr<Sprite>(L, 1);
doc::Layer* newLayer = new doc::LayerImage(sprite);
Tx tx;
tx(new cmd::AddLayer(sprite->root(), newLayer, sprite->root()->lastLayer()));
tx.commit();
push_ptr(L, newLayer);
return 1;
}
int Sprite_newGroup(lua_State* L)
{
auto sprite = get_ptr<Sprite>(L, 1);
doc::Layer* newGroup = new doc::LayerGroup(sprite);
Tx tx;
tx(new cmd::AddLayer(sprite->root(), newGroup, sprite->root()->lastLayer()));
tx.commit();
push_ptr(L, newGroup);
return 1;
}
int Sprite_deleteLayer(lua_State* L)
{
auto sprite = get_ptr<Sprite>(L, 1);
auto layer = may_get_ptr<Layer>(L, 2);
if (!layer && lua_isstring(L, 2)) {
const char* layerName = lua_tostring(L, 2);
if (layerName) {
for (Layer* child : sprite->allLayers()) {
if (child->name() == layerName) {
layer = child;
break;
}
}
}
}
if (layer) {
Tx tx;
tx(new cmd::RemoveLayer(layer));
tx.commit();
return 0;
}
else {
return luaL_error(L, "layer not found");
}
}
int Sprite_newFrame(lua_State* L)
{
auto sprite = get_ptr<Sprite>(L, 1);
doc::frame_t frame = sprite->lastFrame()+1;
if (lua_gettop(L) >= 2) {
frame = lua_tointeger(L, 2)-1;
if (frame < 0)
return luaL_error(L, "frame index out of bounds %d", frame+1);
}
Doc* doc = static_cast<Doc*>(sprite->document());
Tx tx;
doc->getApi(tx).addFrame(sprite, frame);
tx.commit();
push_sprite_frame(L, sprite, frame);
return 1;
}
int Sprite_newEmptyFrame(lua_State* L)
{
auto sprite = get_ptr<Sprite>(L, 1);
doc::frame_t frame = sprite->lastFrame()+1;
if (lua_gettop(L) >= 1) {
frame = lua_tointeger(L, 2)-1;
if (frame < 0)
return luaL_error(L, "frame index out of bounds %d", frame+1);
}
Doc* doc = static_cast<Doc*>(sprite->document());
Tx tx;
DocApi(doc, tx).addEmptyFrame(sprite, frame);
tx.commit();
push_sprite_frame(L, sprite, frame);
return 1;
}
int Sprite_deleteFrame(lua_State* L)
{
auto sprite = get_ptr<Sprite>(L, 1);
doc::frame_t frame = lua_tointeger(L, 2)-1;
if (frame < 0 || frame > sprite->lastFrame())
return luaL_error(L, "frame index out of bounds %d", frame+1);
Doc* doc = static_cast<Doc*>(sprite->document());
Tx tx;
doc->getApi(tx).removeFrame(sprite, frame);
tx.commit();
return 0;
}
int Sprite_newCel(lua_State* L)
{
auto sprite = get_ptr<Sprite>(L, 1);
auto layerBase = get_ptr<Layer>(L, 2);
if (!layerBase->isImage())
return luaL_error(L, "unexpected kinf of layer in Sprite:newCel()");
frame_t frame = lua_tointeger(L, 3)-1;
if (frame < 0 || frame > sprite->lastFrame())
return luaL_error(L, "frame index out of bounds %d", frame+1);
LayerImage* layer = static_cast<LayerImage*>(layerBase);
ImageRef image(nullptr);
gfx::Point pos(0, 0);
Image* srcImage = may_get_image_from_arg(L, 4);
if (srcImage) {
image.reset(Image::createCopy(srcImage));
pos = convert_args_into_point(L, 5);
}
else {
image.reset(Image::create(sprite->spec()));
}
auto cel = new Cel(frame, image);
cel->setPosition(pos);
Doc* doc = static_cast<Doc*>(sprite->document());
Tx tx;
DocApi api = doc->getApi(tx);
if (layer->cel(frame))
api.clearCel(layer, frame);
api.addCel(layer, cel);
tx.commit();
push_ptr(L, cel);
return 1;
}
int Sprite_deleteCel(lua_State* L)
{
auto sprite = get_ptr<Sprite>(L, 1);
(void)sprite; // unused
auto cel = may_get_ptr<doc::Cel>(L, 2);
if (!cel) {
if (auto layer = may_get_ptr<doc::Layer>(L, 2)) {
doc::frame_t frame = lua_tointeger(L, 3);
if (layer->isImage())
cel = static_cast<doc::LayerImage*>(layer)->cel(frame);
}
}
if (cel) {
Tx tx;
tx(new cmd::ClearCel(cel));
tx.commit();
return 0;
}
else {
return luaL_error(L, "cel not found");
}
}
int Sprite_newTag(lua_State* L)
{
auto sprite = get_ptr<doc::Sprite>(L, 1);
auto from = lua_tointeger(L, 2)-1;
auto to = lua_tointeger(L, 3)-1;
auto tag = new doc::FrameTag(from, to);
sprite->frameTags().add(tag);
push_ptr(L, tag);
return 1;
}
int Sprite_deleteTag(lua_State* L)
{
auto sprite = get_ptr<Sprite>(L, 1);
auto tag = may_get_ptr<FrameTag>(L, 2);
if (!tag && lua_isstring(L, 2)) {
const char* tagName = lua_tostring(L, 2);
if (tagName)
tag = sprite->frameTags().getByName(tagName);
}
if (tag) {
Tx tx;
tx(new cmd::RemoveFrameTag(sprite, tag));
tx.commit();
return 0;
}
else {
return luaL_error(L, "tag not found");
}
}
int Sprite_newSlice(lua_State* L)
{
auto sprite = get_ptr<doc::Sprite>(L, 1);
auto slice = new doc::Slice();
gfx::Rect bounds = convert_args_into_rect(L, 2);
if (!bounds.isEmpty())
slice->insert(0, doc::SliceKey(bounds));
sprite->slices().add(slice);
push_ptr(L, slice);
return 1;
}
int Sprite_deleteSlice(lua_State* L)
{
auto sprite = get_ptr<Sprite>(L, 1);
doc::Slice* slice = may_get_ptr<Slice>(L, 2);
if (!slice && lua_isstring(L, 2)) {
const char* sliceName = lua_tostring(L, 2);
if (sliceName)
slice = sprite->slices().getByName(sliceName);
}
if (slice) {
Tx tx;
tx(new cmd::RemoveSlice(sprite, slice));
tx.commit();
return 0;
}
else {
return luaL_error(L, "slice not found");
}
}
int Sprite_get_filename(lua_State* L)
{
auto sprite = get_ptr<Sprite>(L, 1);
@ -312,6 +556,23 @@ const luaL_Reg Sprite_methods[] = {
{ "saveCopyAs", Sprite_saveCopyAs },
{ "loadPalette", Sprite_loadPalette },
{ "setPalette", Sprite_setPalette },
// Layers
{ "newLayer", Sprite_newLayer },
{ "newGroup", Sprite_newGroup },
{ "deleteLayer", Sprite_deleteLayer },
// Frames
{ "newFrame", Sprite_newFrame },
{ "newEmptyFrame", Sprite_newEmptyFrame },
{ "deleteFrame", Sprite_deleteFrame },
// Cel
{ "newCel", Sprite_newCel },
{ "deleteCel", Sprite_deleteCel },
// Tag
{ "newTag", Sprite_newTag },
{ "deleteTag", Sprite_deleteTag },
// Slices
{ "newSlice", Sprite_newSlice },
{ "deleteSlice", Sprite_deleteSlice },
{ nullptr, nullptr }
};

View File

@ -31,17 +31,24 @@ int Tag_eq(lua_State* L)
return 1;
}
int Tag_get_sprite(lua_State* L)
{
auto tag = get_ptr<FrameTag>(L, 1);
push_ptr(L, tag->owner()->sprite());
return 1;
}
int Tag_get_fromFrame(lua_State* L)
{
auto tag = get_ptr<FrameTag>(L, 1);
lua_pushinteger(L, tag->fromFrame());
lua_pushinteger(L, tag->fromFrame()+1);
return 1;
}
int Tag_get_toFrame(lua_State* L)
{
auto tag = get_ptr<FrameTag>(L, 1);
lua_pushinteger(L, tag->toFrame());
lua_pushinteger(L, tag->toFrame()+1);
return 1;
}
@ -69,7 +76,7 @@ int Tag_get_aniDir(lua_State* L)
int Tag_set_fromFrame(lua_State* L)
{
auto tag = get_ptr<FrameTag>(L, 1);
const int fromFrame = lua_tointeger(L, 2);
const int fromFrame = lua_tointeger(L, 2)-1;
Tx tx;
tx(new cmd::SetFrameTagRange(tag, fromFrame,
std::max(fromFrame, tag->toFrame())));
@ -80,7 +87,7 @@ int Tag_set_fromFrame(lua_State* L)
int Tag_set_toFrame(lua_State* L)
{
auto tag = get_ptr<FrameTag>(L, 1);
const int toFrame = lua_tointeger(L, 2);
const int toFrame = lua_tointeger(L, 2)-1;
Tx tx;
tx(new cmd::SetFrameTagRange(tag,
std::min(tag->fromFrame(), toFrame),
@ -117,6 +124,7 @@ const luaL_Reg Tag_methods[] = {
};
const Property Tag_properties[] = {
{ "sprite", Tag_get_sprite, nullptr },
{ "fromFrame", Tag_get_fromFrame, Tag_set_fromFrame },
{ "toFrame", Tag_get_toFrame, Tag_set_toFrame },
{ "frames", Tag_get_frames, nullptr },