1 | // Aseprite |
2 | // Copyright (C) 2019 Igara Studio S.A. |
3 | // Copyright (C) 2017-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/script/luacpp.h" |
13 | #include "fmt/format.h" |
14 | #include "gfx/size.h" |
15 | |
16 | #include <cmath> |
17 | |
18 | namespace app { |
19 | namespace script { |
20 | |
21 | namespace { |
22 | |
23 | gfx::Size Size_new(lua_State* L, int index) |
24 | { |
25 | gfx::Size sz(0, 0); |
26 | // Copy other size |
27 | if (auto sz2 = may_get_obj<gfx::Size>(L, index)) { |
28 | sz = *sz2; |
29 | } |
30 | // Convert {x=int,y=int} or {int,int} into a Size |
31 | else if (lua_istable(L, index)) { |
32 | const int type = lua_getfield(L, index, "width" ); |
33 | if (VALID_LUATYPE(type)) { |
34 | lua_getfield(L, index, "height" ); |
35 | sz.w = lua_tointeger(L, -2); |
36 | sz.h = lua_tointeger(L, -1); |
37 | lua_pop(L, 2); |
38 | } |
39 | else { |
40 | lua_pop(L, 1); |
41 | lua_geti(L, index, 1); |
42 | lua_geti(L, index, 2); |
43 | sz.w = lua_tointeger(L, -2); |
44 | sz.h = lua_tointeger(L, -1); |
45 | lua_pop(L, 2); |
46 | } |
47 | } |
48 | else { |
49 | sz.w = lua_tointeger(L, index); |
50 | sz.h = lua_tointeger(L, index+1); |
51 | } |
52 | return sz; |
53 | } |
54 | |
55 | int Size_new(lua_State* L) |
56 | { |
57 | push_obj(L, Size_new(L, 1)); |
58 | return 1; |
59 | } |
60 | |
61 | int Size_gc(lua_State* L) |
62 | { |
63 | get_obj<gfx::Size>(L, 1)->~SizeT(); |
64 | return 0; |
65 | } |
66 | |
67 | int Size_eq(lua_State* L) |
68 | { |
69 | const auto a = get_obj<gfx::Size>(L, 1); |
70 | const auto b = get_obj<gfx::Size>(L, 2); |
71 | lua_pushboolean(L, *a == *b); |
72 | return 1; |
73 | } |
74 | |
75 | int Size_tostring(lua_State* L) |
76 | { |
77 | const auto sz = get_obj<gfx::Size>(L, 1); |
78 | lua_pushstring(L, fmt::format("Size{{ width={}, height={} }}" , |
79 | sz->w, sz->h).c_str()); |
80 | return 1; |
81 | } |
82 | |
83 | int Size_unm(lua_State* L) |
84 | { |
85 | const auto sz = get_obj<gfx::Size>(L, 1); |
86 | push_obj(L, -(*sz)); |
87 | return 1; |
88 | } |
89 | |
90 | int Size_add(lua_State* L) |
91 | { |
92 | gfx::Size result(0, 0); |
93 | if (lua_isuserdata(L, 1)) |
94 | result += *get_obj<gfx::Size>(L, 1); |
95 | else |
96 | result += lua_tointeger(L, 1); |
97 | if (lua_isuserdata(L, 2)) |
98 | result += *get_obj<gfx::Size>(L, 2); |
99 | else |
100 | result += lua_tointeger(L, 2); |
101 | push_obj(L, result); |
102 | return 1; |
103 | } |
104 | |
105 | int Size_sub(lua_State* L) |
106 | { |
107 | gfx::Size result = *get_obj<gfx::Size>(L, 1); |
108 | if (lua_isuserdata(L, 2)) |
109 | result -= *get_obj<gfx::Size>(L, 2); |
110 | else |
111 | result -= lua_tointeger(L, 2); |
112 | push_obj(L, result); |
113 | return 1; |
114 | } |
115 | |
116 | int Size_mul(lua_State* L) |
117 | { |
118 | gfx::Size result = *get_obj<gfx::Size>(L, 1); |
119 | result *= lua_tointeger(L, 2); |
120 | push_obj(L, result); |
121 | return 1; |
122 | } |
123 | |
124 | int Size_div(lua_State* L) |
125 | { |
126 | gfx::Size result = *get_obj<gfx::Size>(L, 1); |
127 | const int value = lua_tointeger(L, 2); |
128 | if (value == 0) |
129 | return luaL_error(L, "attempt to divide by zero" ); |
130 | result /= value; |
131 | push_obj(L, result); |
132 | return 1; |
133 | } |
134 | |
135 | int Size_mod(lua_State* L) |
136 | { |
137 | gfx::Size result = *get_obj<gfx::Size>(L, 1); |
138 | const int value = lua_tointeger(L, 2); |
139 | if (value == 0) |
140 | return luaL_error(L, "attempt to divide by zero" ); |
141 | result.w %= value; |
142 | result.h %= value; |
143 | push_obj(L, result); |
144 | return 1; |
145 | } |
146 | |
147 | int Size_pow(lua_State* L) |
148 | { |
149 | gfx::Size result = *get_obj<gfx::Size>(L, 1); |
150 | const int value = lua_tointeger(L, 2); |
151 | result.w = std::pow(result.w, value); |
152 | result.h = std::pow(result.h, value); |
153 | push_obj(L, result); |
154 | return 1; |
155 | } |
156 | |
157 | int Size_get_width(lua_State* L) |
158 | { |
159 | const auto sz = get_obj<gfx::Size>(L, 1); |
160 | ASSERT(sz); |
161 | lua_pushinteger(L, sz->w); |
162 | return 1; |
163 | } |
164 | |
165 | int Size_get_height(lua_State* L) |
166 | { |
167 | const auto sz = get_obj<gfx::Size>(L, 1); |
168 | ASSERT(sz); |
169 | lua_pushinteger(L, sz->h); |
170 | return 1; |
171 | } |
172 | |
173 | int Size_set_width(lua_State* L) |
174 | { |
175 | auto sz = get_obj<gfx::Size>(L, 1); |
176 | ASSERT(sz); |
177 | sz->w = lua_tointeger(L, 2); |
178 | return 0; |
179 | } |
180 | |
181 | int Size_set_height(lua_State* L) |
182 | { |
183 | auto sz = get_obj<gfx::Size>(L, 1); |
184 | ASSERT(sz); |
185 | sz->h = lua_tointeger(L, 2); |
186 | return 0; |
187 | } |
188 | |
189 | const luaL_Reg Size_methods[] = { |
190 | { "__gc" , Size_gc }, |
191 | { "__eq" , Size_eq }, |
192 | { "__tostring" , Size_tostring }, |
193 | { "__unm" , Size_unm }, |
194 | { "__add" , Size_add }, |
195 | { "__sub" , Size_sub }, |
196 | { "__mul" , Size_mul }, |
197 | { "__div" , Size_div }, |
198 | { "__mod" , Size_mod }, |
199 | { "__pow" , Size_pow }, |
200 | { "__idiv" , Size_div }, |
201 | { nullptr, nullptr } |
202 | }; |
203 | |
204 | const Property Size_properties[] = { |
205 | { "width" , Size_get_width, Size_set_width }, |
206 | { "height" , Size_get_height, Size_set_height }, |
207 | { nullptr, nullptr, nullptr } |
208 | }; |
209 | |
210 | } // anonymous namespace |
211 | |
212 | DEF_MTNAME(gfx::Size); |
213 | |
214 | void register_size_class(lua_State* L) |
215 | { |
216 | using gfx::Size; |
217 | REG_CLASS(L, Size); |
218 | REG_CLASS_NEW(L, Size); |
219 | REG_CLASS_PROPERTIES(L, Size); |
220 | } |
221 | |
222 | gfx::Size convert_args_into_size(lua_State* L, int index) |
223 | { |
224 | return Size_new(L, index); |
225 | } |
226 | |
227 | } // namespace script |
228 | } // namespace app |
229 | |