Refactor Lua support
[lsnes.git] / src / lua / gui-bitmap.cpp
blob206444085d3d9f6f9a78800f2ee6e4f27adea806
1 #include "lua/internal.hpp"
2 #include "library/framebuffer.hpp"
3 #include "lua/bitmap.hpp"
4 #include <vector>
6 lua_bitmap::lua_bitmap(uint32_t w, uint32_t h)
8 width = w;
9 height = h;
10 pixels.resize(width * height);
11 memset(&pixels[0], 0, width * height);
14 lua_dbitmap::lua_dbitmap(uint32_t w, uint32_t h)
16 width = w;
17 height = h;
18 pixels.resize(width * height);
21 lua_palette::lua_palette()
23 palette_mutex = &mutex::aquire();
26 lua_palette::~lua_palette()
28 delete palette_mutex;
31 namespace
33 struct render_object_bitmap : public render_object
35 render_object_bitmap(int32_t _x, int32_t _y, lua_obj_pin<lua_bitmap>* _bitmap,
36 lua_obj_pin<lua_palette>* _palette) throw()
38 x = _x;
39 y = _y;
40 b = _bitmap;
41 b2 = NULL;
42 p = _palette;
45 render_object_bitmap(int32_t _x, int32_t _y, lua_obj_pin<lua_dbitmap>* _bitmap) throw()
47 x = _x;
48 y = _y;
49 b = NULL;
50 b2 = _bitmap;
51 p = NULL;
54 ~render_object_bitmap() throw()
56 delete b;
57 delete b2;
58 delete p;
61 template<bool T> void composite_op(struct framebuffer<T>& scr) throw()
63 if(p)
64 p->object()->palette_mutex->lock();
65 uint32_t originx = scr.get_origin_x();
66 uint32_t originy = scr.get_origin_y();
67 size_t pallim = 0;
68 size_t w, h;
69 premultiplied_color* palette;
70 if(b) {
71 palette = &p->object()->colors[0];
72 for(auto& c : p->object()->colors)
73 c.set_palette(scr);
74 pallim = p->object()->colors.size();
75 w = b->object()->width;
76 h = b->object()->height;
77 } else {
78 for(auto& c : b2->object()->pixels)
79 c.set_palette(scr);
80 w = b2->object()->width;
81 h = b2->object()->height;
84 int32_t xmin = 0;
85 int32_t xmax = w;
86 int32_t ymin = 0;
87 int32_t ymax = h;
88 clip_range(originx, scr.get_width(), x, xmin, xmax);
89 clip_range(originy, scr.get_height(), y, ymin, ymax);
90 for(int32_t r = ymin; r < ymax; r++) {
91 typename framebuffer<T>::element_t* rptr = scr.rowptr(y + r + originy);
92 size_t eptr = x + xmin + originx;
93 if(b)
94 for(int32_t c = xmin; c < xmax; c++, eptr++) {
95 uint16_t i = b->object()->pixels[r * b->object()->width + c];
96 if(i < pallim)
97 palette[i].apply(rptr[eptr]);
99 else
100 for(int32_t c = xmin; c < xmax; c++, eptr++)
101 b2->object()->pixels[r * b2->object()->width + c].apply(rptr[eptr]);
103 if(p)
104 p->object()->palette_mutex->unlock();
106 void operator()(struct framebuffer<false>& x) throw() { composite_op(x); }
107 void operator()(struct framebuffer<true>& x) throw() { composite_op(x); }
108 private:
109 int32_t x;
110 int32_t y;
111 lua_obj_pin<lua_bitmap>* b;
112 lua_obj_pin<lua_dbitmap>* b2;
113 lua_obj_pin<lua_palette>* p;
116 function_ptr_luafun gui_bitmap(LS, "gui.bitmap_draw", [](lua_state& L, const std::string& fname) -> int {
117 if(!lua_render_ctx)
118 return 0;
119 int32_t x = L.get_numeric_argument<int32_t>(1, fname.c_str());
120 int32_t y = L.get_numeric_argument<int32_t>(2, fname.c_str());
121 if(lua_class<lua_bitmap>::is(L, 3)) {
122 lua_class<lua_bitmap>::get(L, 3, fname.c_str());
123 lua_class<lua_palette>::get(L, 4, fname.c_str());
124 auto b = lua_class<lua_bitmap>::pin(L, 3, fname.c_str());
125 auto p = lua_class<lua_palette>::pin(L, 4, fname.c_str());
126 lua_render_ctx->queue->create_add<render_object_bitmap>(x, y, b, p);
127 } else if(lua_class<lua_dbitmap>::is(L, 3)) {
128 lua_class<lua_dbitmap>::get(L, 3, fname.c_str());
129 auto b = lua_class<lua_dbitmap>::pin(L, 3, fname.c_str());
130 lua_render_ctx->queue->create_add<render_object_bitmap>(x, y, b);
131 } else {
132 L.pushstring("Expected BITMAP or DBITMAP as argument 3 for gui.bitmap_draw.");
133 L.error();
135 return 0;
138 function_ptr_luafun gui_cpalette(LS, "gui.palette_new", [](lua_state& L, const std::string& fname) -> int {
139 lua_class<lua_palette>::create(L);
140 return 1;
143 function_ptr_luafun gui_cbitmap(LS, "gui.bitmap_new", [](lua_state& L, const std::string& fname) -> int {
144 uint32_t w = L.get_numeric_argument<uint32_t>(1, fname.c_str());
145 uint32_t h = L.get_numeric_argument<uint32_t>(2, fname.c_str());
146 bool d = L.get_bool(3, fname.c_str());
147 if(d) {
148 int64_t c = -1;
149 L.get_numeric_argument<int64_t>(4, c, fname.c_str());
150 lua_dbitmap* b = lua_class<lua_dbitmap>::create(L, w, h);
151 for(size_t i = 0; i < b->width * b->height; i++)
152 b->pixels[i] = premultiplied_color(c);
153 } else {
154 uint16_t c = 0;
155 L.get_numeric_argument<uint16_t>(4, c, fname.c_str());
156 lua_bitmap* b = lua_class<lua_bitmap>::create(L, w, h);
157 for(size_t i = 0; i < b->width * b->height; i++)
158 b->pixels[i] = c;
160 return 1;
163 function_ptr_luafun gui_epalette(LS, "gui.palette_set", [](lua_state& L, const std::string& fname) -> int {
164 lua_palette* p = lua_class<lua_palette>::get(L, 1, fname.c_str());
165 uint16_t c = L.get_numeric_argument<uint16_t>(2, fname.c_str());
166 int64_t nval = L.get_numeric_argument<int64_t>(3, fname.c_str());
167 premultiplied_color nc(nval);
168 //The mutex lock protects only the internals of colors array.
169 if(p->colors.size() <= c) {
170 p->palette_mutex->lock();
171 p->colors.resize(static_cast<uint32_t>(c) + 1);
172 p->palette_mutex->unlock();
174 p->colors[c] = nc;
175 return 0;
178 function_ptr_luafun pset_bitmap(LS, "gui.bitmap_pset", [](lua_state& L, const std::string& fname) -> int {
179 uint32_t x = L.get_numeric_argument<uint32_t>(2, fname.c_str());
180 uint32_t y = L.get_numeric_argument<uint32_t>(3, fname.c_str());
181 if(lua_class<lua_bitmap>::is(L, 1)) {
182 lua_bitmap* b = lua_class<lua_bitmap>::get(L, 1, fname.c_str());
183 uint16_t c = L.get_numeric_argument<uint16_t>(4, fname.c_str());
184 if(x >= b->width || y >= b->height)
185 return 0;
186 b->pixels[y * b->width + x] = c;
187 } else if(lua_class<lua_dbitmap>::is(L, 1)) {
188 lua_dbitmap* b = lua_class<lua_dbitmap>::get(L, 1, fname.c_str());
189 int64_t c = L.get_numeric_argument<int64_t>(4, fname.c_str());
190 if(x >= b->width || y >= b->height)
191 return 0;
192 b->pixels[y * b->width + x] = premultiplied_color(c);
193 } else {
194 L.pushstring("Expected BITMAP or DBITMAP as argument 1 for gui.bitmap_pset.");
195 L.error();
197 return 0;
200 function_ptr_luafun size_bitmap(LS, "gui.bitmap_size", [](lua_state& L, const std::string& fname) -> int {
201 if(lua_class<lua_bitmap>::is(L, 1)) {
202 lua_bitmap* b = lua_class<lua_bitmap>::get(L, 1, fname.c_str());
203 L.pushnumber(b->width);
204 L.pushnumber(b->height);
205 } else if(lua_class<lua_dbitmap>::is(L, 1)) {
206 lua_dbitmap* b = lua_class<lua_dbitmap>::get(L, 1, fname.c_str());
207 L.pushnumber(b->width);
208 L.pushnumber(b->height);
209 } else {
210 L.pushstring("Expected BITMAP or DBITMAP as argument 1 for gui.bitmap_size.");
211 L.error();
213 return 2;
216 function_ptr_luafun blit_bitmap(LS, "gui.bitmap_blit", [](lua_state& L, const std::string& fname) -> int {
217 uint32_t dx = L.get_numeric_argument<uint32_t>(2, fname.c_str());
218 uint32_t dy = L.get_numeric_argument<uint32_t>(3, fname.c_str());
219 uint32_t sx = L.get_numeric_argument<uint32_t>(5, fname.c_str());
220 uint32_t sy = L.get_numeric_argument<uint32_t>(6, fname.c_str());
221 uint32_t w = L.get_numeric_argument<uint32_t>(7, fname.c_str());
222 uint32_t h = L.get_numeric_argument<uint32_t>(8, fname.c_str());
223 int64_t ck = 0x100000000ULL;
224 L.get_numeric_argument<int64_t>(9, ck, fname.c_str());
225 bool nck = false;
226 premultiplied_color pck(ck);
227 uint32_t ckorig = pck.orig;
228 uint16_t ckoriga = pck.origa;
229 if(ck == 0x100000000ULL)
230 nck = true;
231 if(lua_class<lua_bitmap>::is(L, 1) && lua_class<lua_bitmap>::is(L, 4)) {
232 lua_bitmap* db = lua_class<lua_bitmap>::get(L, 1, fname.c_str());
233 lua_bitmap* sb = lua_class<lua_bitmap>::get(L, 4, fname.c_str());
234 while((dx + w > db->width || sx + w > sb->width) && w > 0)
235 w--;
236 while((dy + h > db->height || sy + h > sb->height) && h > 0)
237 h--;
238 size_t sidx = sy * sb->width + sx;
239 size_t didx = dy * db->width + dx;
240 size_t srskip = sb->width - w;
241 size_t drskip = db->width - w;
242 for(uint32_t j = 0; j < h; j++) {
243 for(uint32_t i = 0; i < w; i++) {
244 uint16_t pix = sb->pixels[sidx];
245 if(pix != ck) //No need to check nck, as that value is out of range.
246 db->pixels[didx] = pix;
247 sidx++;
248 didx++;
250 sidx += srskip;
251 didx += drskip;
253 } else if(lua_class<lua_dbitmap>::is(L, 1) && lua_class<lua_dbitmap>::is(L, 1)) {
254 lua_dbitmap* db = lua_class<lua_dbitmap>::get(L, 1, fname.c_str());
255 lua_dbitmap* sb = lua_class<lua_dbitmap>::get(L, 4, fname.c_str());
256 while((dx + w > db->width || sx + w > sb->width) && w > 0)
257 w--;
258 while((dy + h > db->height || sy + h > sb->height) && h > 0)
259 h--;
260 size_t sidx = sy * sb->width + sx;
261 size_t didx = dy * db->width + dx;
262 size_t srskip = sb->width - w;
263 size_t drskip = db->width - w;
264 for(uint32_t j = 0; j < h; j++) {
265 for(uint32_t i = 0; i < w; i++) {
266 premultiplied_color pix = sb->pixels[sidx];
267 if(pix.orig != ckorig || pix.origa != ckoriga || nck)
268 db->pixels[didx] = pix;
269 sidx++;
270 didx++;
272 sidx += srskip;
273 didx += drskip;
275 } else {
276 L.pushstring("Expected BITMAP or DBITMAP as arguments 1&4 for gui.bitmap_pset.");
277 L.error();
279 return 0;
282 function_ptr_luafun gui_loadbitmap(LS, "gui.bitmap_load", [](lua_state& L, const std::string& fname) -> int {
283 std::string name = L.get_string(1, fname.c_str());
284 uint32_t w, h;
285 auto bitmap = lua_loaded_bitmap::load(name);
286 if(bitmap.d) {
287 lua_dbitmap* b = lua_class<lua_dbitmap>::create(L, bitmap.w, bitmap.h);
288 for(size_t i = 0; i < bitmap.w * bitmap.h; i++)
289 b->pixels[i] = premultiplied_color(bitmap.bitmap[i]);
290 return 1;
291 } else {
292 lua_bitmap* b = lua_class<lua_bitmap>::create(L, bitmap.w, bitmap.h);
293 lua_palette* p = lua_class<lua_palette>::create(L);
294 for(size_t i = 0; i < bitmap.w * bitmap.h; i++)
295 b->pixels[i] = bitmap.bitmap[i];
296 p->colors.resize(bitmap.palette.size());
297 for(size_t i = 0; i < bitmap.palette.size(); i++)
298 p->colors[i] = premultiplied_color(bitmap.palette[i]);
299 return 2;
303 function_ptr_luafun gui_dpalette(LS, "gui.palette_debug", [](lua_state& L, const std::string& fname) -> int {
304 lua_palette* p = lua_class<lua_palette>::get(L, 1, fname.c_str());
305 size_t i = 0;
306 for(auto c : p->colors)
307 messages << "Color #" << (i++) << ": " << c.orig << ":" << c.origa << std::endl;
308 return 0;
312 DECLARE_LUACLASS(lua_palette, "PALETTE");
313 DECLARE_LUACLASS(lua_bitmap, "BITMAP");
314 DECLARE_LUACLASS(lua_dbitmap, "DBITMAP");