1 /*
2 *
3 * Copyright (C) 2006-2019 Christopho, Solarus - http://www.solarus-games.org
4 *
5 * Solarus is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * Solarus is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include "solarus/core/CurrentQuest.h"
20 #include "solarus/graphics/Color.h"
21 #include "solarus/graphics/Sprite.h"
22 #include "solarus/graphics/Surface.h"
23 #include "solarus/graphics/TransitionFade.h"
24 #include "solarus/graphics/Video.h"
25 #include "solarus/lua/LuaContext.h"
26 #include "solarus/lua/LuaTools.h"
27 #include "solarus/movements/Movement.h"
28
29 namespace Solarus {
30
31 /**
32 * Name of the Lua table representing the surface module.
33 */
34 const std::string LuaContext::surface_module_name = "sol.surface";
35
36 /**
37 * \brief Initializes the surface features provided to Lua.
38 */
register_surface_module()39 void LuaContext::register_surface_module() {
40
41 const std::vector<luaL_Reg> functions = {
42 { "create", surface_api_create }
43 };
44
45 std::vector<luaL_Reg> methods = {
46 { "get_size", surface_api_get_size },
47 { "clear", surface_api_clear },
48 { "fill_color", surface_api_fill_color },
49 { "draw", drawable_api_draw },
50 { "draw_region", drawable_api_draw_region },
51 { "get_blend_mode", drawable_api_get_blend_mode },
52 { "set_blend_mode", drawable_api_set_blend_mode },
53 { "get_opacity", drawable_api_get_opacity },
54 { "set_opacity", drawable_api_set_opacity },
55 { "fade_in", drawable_api_fade_in },
56 { "fade_out", drawable_api_fade_out },
57 { "get_xy", drawable_api_get_xy },
58 { "set_xy", drawable_api_set_xy },
59 { "get_movement", drawable_api_get_movement },
60 { "stop_movement", drawable_api_stop_movement },
61 { "get_pixels", surface_api_get_pixels } //Was already present in 1.5.x
62 };
63
64 if (CurrentQuest::is_format_at_least({ 1, 6 })) {
65 methods.insert(methods.end(), {
66 { "set_color_modulation", drawable_api_set_color_modulation },
67 { "get_color_modulation", drawable_api_get_color_modulation },
68 { "set_pixels", surface_api_set_pixels },
69 { "set_shader", drawable_api_set_shader },
70 { "get_shader", drawable_api_get_shader },
71 { "set_rotation", drawable_api_set_rotation },
72 { "get_rotation", drawable_api_get_rotation },
73 { "set_scale", drawable_api_set_scale },
74 { "get_scale", drawable_api_get_scale },
75 { "set_transformation_origin", drawable_api_set_transformation_origin },
76 { "get_transformation_origin", drawable_api_get_transformation_origin },
77 { "gl_bind_as_texture", surface_api_gl_bind_as_texture},
78 { "gl_bind_as_target", surface_api_gl_bind_as_target}
79 });
80 }
81
82 const std::vector<luaL_Reg> metamethods = {
83 { "__gc", drawable_meta_gc },
84 { "__newindex", userdata_meta_newindex_as_table },
85 { "__index", userdata_meta_index_as_table }
86 };
87
88 register_type(surface_module_name, functions, methods, metamethods);
89 }
90
91 /**
92 * \brief Returns whether a value is a userdata of type surface.
93 * \param l A Lua context.
94 * \param index An index in the stack.
95 * \return true if the value at this index is a surface.
96 */
is_surface(lua_State * l,int index)97 bool LuaContext::is_surface(lua_State* l, int index) {
98 return is_userdata(l, index, surface_module_name);
99 }
100
101 /**
102 * \brief Checks that the userdata at the specified index of the stack is a
103 * surface and returns it.
104 * \param l a Lua context
105 * \param index an index in the stack
106 * \return the surface
107 */
check_surface(lua_State * l,int index)108 SurfacePtr LuaContext::check_surface(lua_State* l, int index) {
109 return std::static_pointer_cast<Surface>(check_userdata(
110 l, index, surface_module_name
111 ));
112 }
113
114 /**
115 * \brief Pushes a surface userdata onto the stack.
116 * \param l a Lua context
117 * \param surface a surface
118 */
push_surface(lua_State * l,Surface & surface)119 void LuaContext::push_surface(lua_State* l, Surface& surface) {
120 push_userdata(l, surface);
121 }
122
123 /**
124 * \brief Implementation of sol.surface.create().
125 * \param l The Lua context that is calling this function.
126 * \return Number of values to return to Lua.
127 */
surface_api_create(lua_State * l)128 int LuaContext::surface_api_create(lua_State* l) {
129
130 return state_boundary_handle(l, [&] {
131 SurfacePtr surface;
132 if (lua_gettop(l) == 0) {
133 // create an empty surface with the screen size
134 surface = Surface::create(Video::get_quest_size());
135 }
136 else if (lua_type(l, 1) == LUA_TNUMBER) {
137 // create an empty surface with the specified size
138 int width = LuaTools::check_int(l, 1);
139 int height = LuaTools::check_int(l, 2);
140 surface = Surface::create(width, height);
141 }
142 else if (lua_type(l, 1) == LUA_TSTRING) {
143 // load from a file
144 const std::string& file_name = lua_tostring(l, 1);
145 bool language_specific = LuaTools::opt_boolean(l, 2, false);
146 surface = Surface::create(file_name, language_specific ?
147 Surface::DIR_LANGUAGE : Surface::DIR_SPRITES);
148 }
149 else {
150 LuaTools::type_error(l, 1, "number, string or no value");
151 }
152
153 if (surface == nullptr) {
154 // Image file not found or not valid.
155 lua_pushnil(l);
156 }
157 else {
158 get().add_drawable(surface);
159 push_surface(l, *surface);
160 }
161 return 1;
162 });
163 }
164
165 /**
166 * \brief Implementation of surface:get_size().
167 * \param l The Lua context that is calling this function.
168 * \return Number of values to return to Lua.
169 */
surface_api_get_size(lua_State * l)170 int LuaContext::surface_api_get_size(lua_State* l) {
171
172 return state_boundary_handle(l, [&] {
173 Surface& surface = *check_surface(l, 1);
174
175 lua_pushinteger(l, surface.get_width());
176 lua_pushinteger(l, surface.get_height());
177 return 2;
178 });
179 }
180
181 /**
182 * \brief Implementation of surface:clear().
183 * \param l The Lua context that is calling this function.
184 * \return Number of values to return to Lua.
185 */
surface_api_clear(lua_State * l)186 int LuaContext::surface_api_clear(lua_State* l) {
187
188 return state_boundary_handle(l, [&] {
189 Surface& surface = *check_surface(l, 1);
190
191 surface.clear();
192
193 return 0;
194 });
195 }
196
197 /**
198 * \brief Implementation of surface:fill_color().
199 * \param l The Lua context that is calling this function.
200 * \return Number of values to return to Lua.
201 */
surface_api_fill_color(lua_State * l)202 int LuaContext::surface_api_fill_color(lua_State* l) {
203
204 return state_boundary_handle(l, [&] {
205 Surface& surface = *check_surface(l, 1);
206 Color color = LuaTools::check_color(l, 2);
207
208 if (lua_gettop(l) >= 3) {
209 int x = LuaTools::check_int(l, 3);
210 int y = LuaTools::check_int(l, 4);
211 int width = LuaTools::check_int(l, 5);
212 int height = LuaTools::check_int(l, 6);
213 Rectangle where(x, y, width, height);
214 surface.fill_with_color(color, where);
215 }
216 else {
217 surface.fill_with_color(color);
218 }
219
220 return 0;
221 });
222 }
223
224 /**
225 * \brief Implementation of surface:get_pixels().
226 * \param l The Lua context that is calling this function.
227 * \return Number of values to return to Lua.
228 */
surface_api_get_pixels(lua_State * l)229 int LuaContext::surface_api_get_pixels(lua_State* l) {
230
231 return state_boundary_handle(l, [&] {
232 Surface& surface = *check_surface(l, 1);
233 // TODO optional parameters x, y, width, height
234
235 push_string(l, surface.get_pixels());
236 return 1;
237 });
238 }
239
240 /**
241 * \brief Implementation of surface:set_pixels().
242 * \param l The Lua context that is calling this function.
243 * \return Number of values to return to Lua.
244 */
surface_api_set_pixels(lua_State * l)245 int LuaContext::surface_api_set_pixels(lua_State* l) {
246 return state_boundary_handle(l, [&] {
247 Surface& surface = *check_surface(l,1);
248 const std::string& buffer = LuaTools::check_string(l,2);
249 surface.set_pixels(buffer);
250 return 0;
251 });
252 }
253
254 /**
255 * \brief Implementation of surface:gl_bind_as_texture().
256 * \param l The Lua context that is calling this function.
257 * \return Number of values to return to Lua.
258 */
surface_api_gl_bind_as_texture(lua_State * l)259 int LuaContext::surface_api_gl_bind_as_texture(lua_State* l) {
260 return state_boundary_handle(l, [&] {
261 const Surface& surface = *check_surface(l,1);
262 surface.bind_as_texture();
263 return 0;
264 });
265 }
266
267 /**
268 * \brief Implementation of surface:gl_bind_as_target().
269 * \param l The Lua context that is calling this function.
270 * \return Number of values to return to Lua.
271 */
surface_api_gl_bind_as_target(lua_State * l)272 int LuaContext::surface_api_gl_bind_as_target(lua_State* l) {
273 return state_boundary_handle(l, [&] {
274 Surface& surface = *check_surface(l,1);
275 surface.bind_as_target();
276 return 0;
277 });
278 }
279
280 }
281
282