1// Aseprite
2// Copyright (C) 2018-2020 Igara Studio S.A.
3// Copyright (C) 2018 David Capello
4//
5// This program is distributed under the terms of
6// the End-User License Agreement for Aseprite.
7
8#ifdef HAVE_CONFIG_H
9#include "config.h"
10#endif
11
12#include "app/cmd/set_frame_duration.h"
13#include "app/script/docobj.h"
14#include "app/script/engine.h"
15#include "app/script/luacpp.h"
16#include "app/tx.h"
17#include "doc/frame.h"
18#include "doc/sprite.h"
19
20namespace app {
21namespace script {
22
23using namespace doc;
24
25namespace {
26
27struct FrameObj {
28 ObjectId spriteId;
29 frame_t frame;
30 FrameObj(Sprite* sprite, frame_t frame)
31 : spriteId(sprite ? sprite->id(): 0),
32 frame(frame) {
33 }
34 FrameObj(const FrameObj&) = delete;
35 FrameObj& operator=(const FrameObj&) = delete;
36
37 Sprite* sprite(lua_State* L) { return check_docobj(L, doc::get<Sprite>(spriteId)); }
38};
39
40int Frame_gc(lua_State* L)
41{
42 get_obj<FrameObj>(L, 1)->~FrameObj();
43 return 0;
44}
45
46int Frame_eq(lua_State* L)
47{
48 const auto a = get_obj<FrameObj>(L, 1);
49 const auto b = get_obj<FrameObj>(L, 2);
50 lua_pushboolean(L,
51 (a->spriteId == b->spriteId &&
52 a->frame == b->frame));
53 return 1;
54}
55
56int Frame_get_sprite(lua_State* L)
57{
58 auto obj = get_obj<FrameObj>(L, 1);
59 push_docobj<Sprite>(L, obj->spriteId);
60 return 1;
61}
62
63int Frame_get_frameNumber(lua_State* L)
64{
65 auto obj = get_obj<FrameObj>(L, 1);
66 lua_pushinteger(L, obj->frame+1);
67 return 1;
68}
69
70int Frame_get_duration(lua_State* L)
71{
72 auto obj = get_obj<FrameObj>(L, 1);
73 auto sprite = obj->sprite(L);
74 lua_pushnumber(L, sprite->frameDuration(obj->frame) / 1000.0);
75 return 1;
76}
77
78int Frame_get_previous(lua_State* L)
79{
80 auto obj = get_obj<FrameObj>(L, 1);
81 auto sprite = obj->sprite(L);
82 auto frame = obj->frame-1;
83 if (frame >= 0 && frame < sprite->totalFrames())
84 push_sprite_frame(L, sprite, frame);
85 else
86 lua_pushnil(L);
87 return 1;
88}
89
90int Frame_get_next(lua_State* L)
91{
92 auto obj = get_obj<FrameObj>(L, 1);
93 auto sprite = obj->sprite(L);
94 auto frame = obj->frame+1;
95 if (frame >= 0 && frame < sprite->totalFrames())
96 push_sprite_frame(L, sprite, frame);
97 else
98 lua_pushnil(L);
99 return 1;
100}
101
102int Frame_set_duration(lua_State* L)
103{
104 auto obj = get_obj<FrameObj>(L, 1);
105 auto sprite = obj->sprite(L);
106 double duration = lua_tonumber(L, 2) * 1000.0;
107 Tx tx;
108 tx(new cmd::SetFrameDuration(sprite, obj->frame, int(duration)));
109 tx.commit();
110 return 1;
111}
112
113const luaL_Reg Frame_methods[] = {
114 { "__gc", Frame_gc },
115 { "__eq", Frame_eq },
116 { nullptr, nullptr }
117};
118
119const Property Frame_properties[] = {
120 { "sprite", Frame_get_sprite, nullptr },
121 { "frameNumber", Frame_get_frameNumber, nullptr },
122 { "duration", Frame_get_duration, Frame_set_duration },
123 { "previous", Frame_get_previous, nullptr },
124 { "next", Frame_get_next, nullptr },
125 { nullptr, nullptr, nullptr }
126};
127
128} // anonymous namespace
129
130DEF_MTNAME(FrameObj);
131
132void register_frame_class(lua_State* L)
133{
134 using Frame = FrameObj;
135 REG_CLASS(L, Frame);
136 REG_CLASS_PROPERTIES(L, Frame);
137}
138
139void push_sprite_frame(lua_State* L, Sprite* sprite, frame_t frame)
140{
141 push_new<FrameObj>(L, sprite, frame);
142}
143
144doc::frame_t get_frame_number_from_arg(lua_State* L, int index)
145{
146 auto obj = may_get_obj<FrameObj>(L, index);
147 if (obj)
148 return obj->frame;
149 else if (lua_isnil(L, index) || lua_isnone(L, index))
150 return 0;
151 else
152 return lua_tointeger(L, index)-1;
153}
154
155} // namespace script
156} // namespace app
157