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/point.h" |
15 | |
16 | #include <cmath> |
17 | |
18 | namespace app { |
19 | namespace script { |
20 | |
21 | namespace { |
22 | |
23 | gfx::Point Point_new(lua_State* L, int index) |
24 | { |
25 | gfx::Point pt(0, 0); |
26 | // Copy other rectangle |
27 | if (auto pt2 = may_get_obj<gfx::Point>(L, index)) { |
28 | pt = *pt2; |
29 | } |
30 | // Convert {x=int,y=int} or {int,int} into a Point |
31 | else if (lua_istable(L, index)) { |
32 | const int type = lua_getfield(L, index, "x" ); |
33 | if (VALID_LUATYPE(type)) { |
34 | lua_getfield(L, index, "y" ); |
35 | pt.x = lua_tointeger(L, -2); |
36 | pt.y = lua_tointeger(L, -1); |
37 | lua_pop(L, 2); |
38 | } |
39 | else { |
40 | lua_pop(L, 1); |
41 | |
42 | // TODO Investigate this further: why we cannot use two |
43 | // lua_geti() calls and then lua_pop(L, 2) when we are iterating |
44 | // points in a table defined like {{0,0},{32,32}} |
45 | |
46 | lua_geti(L, index, 1); |
47 | pt.x = lua_tointeger(L, -1); |
48 | lua_pop(L, 1); |
49 | |
50 | lua_geti(L, index, 2); |
51 | pt.y = lua_tointeger(L, -1); |
52 | lua_pop(L, 1); |
53 | } |
54 | } |
55 | else { |
56 | pt.x = lua_tointeger(L, index); |
57 | pt.y = lua_tointeger(L, index+1); |
58 | } |
59 | return pt; |
60 | } |
61 | |
62 | int Point_new(lua_State* L) |
63 | { |
64 | push_obj(L, Point_new(L, 1)); |
65 | return 1; |
66 | } |
67 | |
68 | int Point_gc(lua_State* L) |
69 | { |
70 | get_obj<gfx::Point>(L, 1)->~PointT(); |
71 | return 0; |
72 | } |
73 | |
74 | int Point_eq(lua_State* L) |
75 | { |
76 | const auto a = get_obj<gfx::Point>(L, 1); |
77 | const auto b = get_obj<gfx::Point>(L, 2); |
78 | lua_pushboolean(L, *a == *b); |
79 | return 1; |
80 | } |
81 | |
82 | int Point_tostring(lua_State* L) |
83 | { |
84 | const auto pt = get_obj<gfx::Point>(L, 1); |
85 | lua_pushstring(L, fmt::format("Point{{ x={}, y={} }}" , |
86 | pt->x, pt->y).c_str()); |
87 | return 1; |
88 | } |
89 | |
90 | int Point_unm(lua_State* L) |
91 | { |
92 | const auto pt = get_obj<gfx::Point>(L, 1); |
93 | push_obj(L, -(*pt)); |
94 | return 1; |
95 | } |
96 | |
97 | int Point_add(lua_State* L) |
98 | { |
99 | gfx::Point result(0, 0); |
100 | if (lua_isuserdata(L, 1)) |
101 | result += *get_obj<gfx::Point>(L, 1); |
102 | else |
103 | result += lua_tointeger(L, 1); |
104 | if (lua_isuserdata(L, 2)) |
105 | result += *get_obj<gfx::Point>(L, 2); |
106 | else |
107 | result += lua_tointeger(L, 2); |
108 | push_obj(L, result); |
109 | return 1; |
110 | } |
111 | |
112 | int Point_sub(lua_State* L) |
113 | { |
114 | gfx::Point result = *get_obj<gfx::Point>(L, 1); |
115 | if (lua_isuserdata(L, 2)) |
116 | result -= *get_obj<gfx::Point>(L, 2); |
117 | else |
118 | result -= lua_tointeger(L, 2); |
119 | push_obj(L, result); |
120 | return 1; |
121 | } |
122 | |
123 | int Point_mul(lua_State* L) |
124 | { |
125 | gfx::Point result = *get_obj<gfx::Point>(L, 1); |
126 | result *= lua_tointeger(L, 2); |
127 | push_obj(L, result); |
128 | return 1; |
129 | } |
130 | |
131 | int Point_div(lua_State* L) |
132 | { |
133 | gfx::Point result = *get_obj<gfx::Point>(L, 1); |
134 | const int value = lua_tointeger(L, 2); |
135 | if (value == 0) |
136 | return luaL_error(L, "attempt to divide by zero" ); |
137 | result /= value; |
138 | push_obj(L, result); |
139 | return 1; |
140 | } |
141 | |
142 | int Point_mod(lua_State* L) |
143 | { |
144 | gfx::Point result = *get_obj<gfx::Point>(L, 1); |
145 | const int value = lua_tointeger(L, 2); |
146 | if (value == 0) |
147 | return luaL_error(L, "attempt to divide by zero" ); |
148 | result.x %= value; |
149 | result.y %= value; |
150 | push_obj(L, result); |
151 | return 1; |
152 | } |
153 | |
154 | int Point_pow(lua_State* L) |
155 | { |
156 | gfx::Point result = *get_obj<gfx::Point>(L, 1); |
157 | const int value = lua_tointeger(L, 2); |
158 | result.x = std::pow(result.x, value); |
159 | result.y = std::pow(result.y, value); |
160 | push_obj(L, result); |
161 | return 1; |
162 | } |
163 | |
164 | int Point_get_x(lua_State* L) |
165 | { |
166 | const auto pt = get_obj<gfx::Point>(L, 1); |
167 | lua_pushinteger(L, pt->x); |
168 | return 1; |
169 | } |
170 | |
171 | int Point_get_y(lua_State* L) |
172 | { |
173 | const auto pt = get_obj<gfx::Point>(L, 1); |
174 | lua_pushinteger(L, pt->y); |
175 | return 1; |
176 | } |
177 | |
178 | int Point_set_x(lua_State* L) |
179 | { |
180 | auto pt = get_obj<gfx::Point>(L, 1); |
181 | pt->x = lua_tointeger(L, 2); |
182 | return 0; |
183 | } |
184 | |
185 | int Point_set_y(lua_State* L) |
186 | { |
187 | auto pt = get_obj<gfx::Point>(L, 1); |
188 | pt->y = lua_tointeger(L, 2); |
189 | return 0; |
190 | } |
191 | |
192 | const luaL_Reg Point_methods[] = { |
193 | { "__gc" , Point_gc }, |
194 | { "__eq" , Point_eq }, |
195 | { "__tostring" , Point_tostring }, |
196 | { "__unm" , Point_unm }, |
197 | { "__add" , Point_add }, |
198 | { "__sub" , Point_sub }, |
199 | { "__mul" , Point_mul }, |
200 | { "__div" , Point_div }, |
201 | { "__mod" , Point_mod }, |
202 | { "__pow" , Point_pow }, |
203 | { "__idiv" , Point_div }, |
204 | { nullptr, nullptr } |
205 | }; |
206 | |
207 | const Property Point_properties[] = { |
208 | { "x" , Point_get_x, Point_set_x }, |
209 | { "y" , Point_get_y, Point_set_y }, |
210 | { nullptr, nullptr, nullptr } |
211 | }; |
212 | |
213 | } // anonymous namespace |
214 | |
215 | DEF_MTNAME(gfx::Point); |
216 | |
217 | void register_point_class(lua_State* L) |
218 | { |
219 | using gfx::Point; |
220 | REG_CLASS(L, Point); |
221 | REG_CLASS_NEW(L, Point); |
222 | REG_CLASS_PROPERTIES(L, Point); |
223 | } |
224 | |
225 | gfx::Point convert_args_into_point(lua_State* L, int index) |
226 | { |
227 | return Point_new(L, index); |
228 | } |
229 | |
230 | } // namespace script |
231 | } // namespace app |
232 | |