Lua: Refactor lots of stuff
[lsnes.git] / src / lua / gui-bitmap.cpp
blob1c5f436b3a5dda77750381c1af5c098f79105003
1 #include "lua/internal.hpp"
2 #include "core/framebuffer.hpp"
3 #include "library/framebuffer.hpp"
4 #include "library/lua-framebuffer.hpp"
5 #include "library/minmax.hpp"
6 #include "library/png.hpp"
7 #include "library/sha256.hpp"
8 #include "library/serialization.hpp"
9 #include "library/string.hpp"
10 #include "library/zip.hpp"
11 #include "lua/bitmap.hpp"
12 #include "library/threadtypes.hpp"
13 #include <vector>
14 #include <sstream>
16 std::vector<char> lua_dbitmap::save_png() const
18 png::encoder img;
19 img.width = width;
20 img.height = height;
21 img.has_palette = false;
22 img.has_alpha = false;
23 img.data.resize(width * height);
24 for(size_t i = 0; i < width * height; i++) {
25 const framebuffer::color& c = pixels[i];
26 if(c.origa != 256)
27 img.has_alpha = true;
28 img.data[i] = c.orig + ((uint32_t)(c.origa - (c.origa >> 7) + (c.origa >> 8)) << 24);
30 std::ostringstream tmp1;
31 img.encode(tmp1);
32 std::string tmp2 = tmp1.str();
33 return std::vector<char>(tmp2.begin(), tmp2.end());
36 std::vector<char> lua_bitmap::save_png(const lua_palette& pal) const
38 png::encoder img;
39 img.width = width;
40 img.height = height;
41 img.has_palette = true;
42 img.has_alpha = false;
43 img.data.resize(width * height);
44 img.palette.resize(pal.colors.size());
45 for(size_t i = 0; i < width * height; i++) {
46 img.data[i] = pixels[i];
48 for(size_t i = 0; i < pal.colors.size(); i++) {
49 const framebuffer::color& c = pal.colors[i];
50 if(c.origa != 256)
51 img.has_alpha = true;
52 img.palette[i] = c.orig + ((uint32_t)(c.origa - (c.origa >> 7) + (c.origa >> 8)) << 24);
54 std::ostringstream tmp1;
55 img.encode(tmp1);
56 std::string tmp2 = tmp1.str();
57 return std::vector<char>(tmp2.begin(), tmp2.end());
60 namespace
62 const char* base64chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
64 struct render_object_bitmap : public framebuffer::object
66 render_object_bitmap(int32_t _x, int32_t _y, lua::objpin<lua_bitmap> _bitmap,
67 lua::objpin<lua_palette> _palette) throw()
69 x = _x;
70 y = _y;
71 b = _bitmap;
72 p = _palette;
75 render_object_bitmap(int32_t _x, int32_t _y, lua::objpin<lua_dbitmap> _bitmap) throw()
77 x = _x;
78 y = _y;
79 b2 = _bitmap;
82 ~render_object_bitmap() throw()
86 bool kill_request(void* obj) throw()
88 return kill_request_ifeq(p.object(), obj) ||
89 kill_request_ifeq(b.object(), obj) ||
90 kill_request_ifeq(b2.object(), obj);
93 template<bool T> void composite_op(struct framebuffer::fb<T>& scr) throw()
95 if(p)
96 p->palette_mutex.lock();
97 uint32_t originx = scr.get_origin_x();
98 uint32_t originy = scr.get_origin_y();
99 size_t pallim = 0;
100 size_t w, h;
101 framebuffer::color* palette;
102 if(b) {
103 palette = &p->colors[0];
104 for(auto& c : p->colors)
105 c.set_palette(scr);
106 pallim = p->colors.size();
107 w = b->width;
108 h = b->height;
109 } else {
110 for(auto& c : b2->pixels)
111 c.set_palette(scr);
112 w = b2->width;
113 h = b2->height;
116 int32_t xmin = 0;
117 int32_t xmax = w;
118 int32_t ymin = 0;
119 int32_t ymax = h;
120 framebuffer::clip_range(originx, scr.get_width(), x, xmin, xmax);
121 framebuffer::clip_range(originy, scr.get_height(), y, ymin, ymax);
122 for(int32_t r = ymin; r < ymax; r++) {
123 typename framebuffer::fb<T>::element_t* rptr = scr.rowptr(y + r + originy);
124 size_t eptr = x + xmin + originx;
125 if(b)
126 for(int32_t c = xmin; c < xmax; c++, eptr++) {
127 uint16_t i = b->pixels[r * b->width + c];
128 if(i < pallim)
129 palette[i].apply(rptr[eptr]);
131 else
132 for(int32_t c = xmin; c < xmax; c++, eptr++)
133 b2->pixels[r * b2->width + c].apply(rptr[eptr]);
135 if(p)
136 p->palette_mutex.unlock();
138 void operator()(struct framebuffer::fb<false>& x) throw() { composite_op(x); }
139 void operator()(struct framebuffer::fb<true>& x) throw() { composite_op(x); }
140 void clone(framebuffer::queue& q) const throw(std::bad_alloc) { q.clone_helper(this); }
141 private:
142 int32_t x;
143 int32_t y;
144 lua::objpin<lua_bitmap> b;
145 lua::objpin<lua_dbitmap> b2;
146 lua::objpin<lua_palette> p;
149 lua::fnptr gui_bitmap(lua_func_misc, "gui.bitmap_draw", [](lua::state& L, const std::string& fname)
150 -> int {
151 if(lua::_class<lua_bitmap>::is(L, 3))
152 return lua::_class<lua_bitmap>::get(L, 3, fname.c_str())->_draw(L, fname, false);
153 else if(lua::_class<lua_dbitmap>::is(L, 3))
154 return lua::_class<lua_dbitmap>::get(L, 3, fname.c_str())->_draw(L, fname, false);
155 else
156 throw std::runtime_error("Expected BITMAP or DBITMAP as argument 3 for " + fname);
157 return 0;
160 lua::fnptr gui_cpalette(lua_func_misc, "gui.palette_new", [](lua::state& L, const std::string& fname)
161 -> int {
162 lua::_class<lua_palette>::create(L);
163 return 1;
166 lua::fnptr2 gui_cbitmap(lua_func_misc, "gui.bitmap_new", [](lua::state& L, lua::parameters& P)
167 -> int {
168 auto w = P.arg<uint32_t>();
169 auto h = P.arg<uint32_t>();
170 auto d = P.arg<bool>();
171 if(d) {
172 auto c = P.color(-1);
173 lua_dbitmap* b = lua::_class<lua_dbitmap>::create(L, w, h);
174 for(size_t i = 0; i < b->width * b->height; i++)
175 b->pixels[i] = c;
176 } else {
177 uint16_t c = P.arg_opt<uint16_t>(0);
178 lua_bitmap* b = lua::_class<lua_bitmap>::create(L, w, h);
179 for(size_t i = 0; i < b->width * b->height; i++)
180 b->pixels[i] = c;
182 return 1;
185 lua::fnptr gui_epalette(lua_func_misc, "gui.palette_set", [](lua::state& L, const std::string& fname)
186 -> int {
187 lua_palette* p = lua::_class<lua_palette>::get(L, 1, fname.c_str());
188 return p->set(L, fname);
191 lua::fnptr pset_bitmap(lua_func_misc, "gui.bitmap_pset", [](lua::state& L, const std::string& fname)
192 -> int {
193 if(lua::_class<lua_bitmap>::is(L, 1))
194 return lua::_class<lua_bitmap>::get(L, 1, fname.c_str())->pset(L, fname);
195 else if(lua::_class<lua_dbitmap>::is(L, 1))
196 return lua::_class<lua_dbitmap>::get(L, 1, fname.c_str())->pset(L, fname);
197 else
198 throw std::runtime_error("Expected BITMAP or DBITMAP as argument 1 for " + fname);
199 return 0;
202 lua::fnptr pget_bitmap(lua_func_misc, "gui.bitmap_pget", [](lua::state& L, const std::string& fname)
203 -> int {
204 if(lua::_class<lua_bitmap>::is(L, 1))
205 return lua::_class<lua_bitmap>::get(L, 1, fname.c_str())->pget(L, fname);
206 else if(lua::_class<lua_dbitmap>::is(L, 1))
207 return lua::_class<lua_dbitmap>::get(L, 1, fname.c_str())->pget(L, fname);
208 else
209 throw std::runtime_error("Expected BITMAP or DBITMAP as argument 1 for " + fname);
210 return 0;
213 lua::fnptr size_bitmap(lua_func_misc, "gui.bitmap_size", [](lua::state& L, const std::string& fname)
214 -> int {
215 if(lua::_class<lua_bitmap>::is(L, 1))
216 return lua::_class<lua_bitmap>::get(L, 1, fname.c_str())->size(L, fname);
217 else if(lua::_class<lua_dbitmap>::is(L, 1))
218 return lua::_class<lua_dbitmap>::get(L, 1, fname.c_str())->size(L, fname);
219 else
220 throw std::runtime_error("Expected BITMAP or DBITMAP as argument 1 for " + fname);
221 return 0;
224 lua::fnptr hash_bitmap(lua_func_misc, "gui.bitmap_hash", [](lua::state& L, const std::string& fname)
225 -> int {
226 if(lua::_class<lua_bitmap>::is(L, 1))
227 return lua::_class<lua_bitmap>::get(L, 1, fname.c_str())->hash(L, fname);
228 else if(lua::_class<lua_dbitmap>::is(L, 1))
229 return lua::_class<lua_dbitmap>::get(L, 1, fname.c_str())->hash(L, fname);
230 else
231 throw std::runtime_error("Expected BITMAP or DBITMAP as argument 1 for " + fname);
232 return 0;
235 lua::fnptr hash_palette(lua_func_misc, "gui.palette_hash", [](lua::state& L, const std::string& fname)
236 -> int {
237 lua_palette* p = lua::_class<lua_palette>::get(L, 1, fname.c_str());
238 return p->hash(L, fname);
241 struct operand_dbitmap
243 typedef framebuffer::color pixel_t;
244 typedef framebuffer::color rpixel_t;
245 operand_dbitmap(lua_dbitmap& _bitmap)
246 : bitmap(_bitmap), _transparent(-1)
248 pixels = &bitmap.pixels[0];
250 size_t get_width() { return bitmap.width; }
251 size_t get_height() { return bitmap.height; }
252 const rpixel_t& read(size_t idx) { return pixels[idx]; }
253 const pixel_t& lookup(const rpixel_t& p) { return p; }
254 void write(size_t idx, const pixel_t& v) { pixels[idx] = v; }
255 bool is_opaque(const rpixel_t& p) { return p.origa > 0; }
256 const pixel_t& transparent() { return _transparent; }
257 private:
258 lua_dbitmap& bitmap;
259 pixel_t* pixels;
260 framebuffer::color _transparent;
263 struct operand_bitmap
265 typedef uint16_t pixel_t;
266 typedef uint16_t rpixel_t;
267 operand_bitmap(lua_bitmap& _bitmap)
268 : bitmap(_bitmap)
270 pixels = &bitmap.pixels[0];
272 size_t get_width() { return bitmap.width; }
273 size_t get_height() { return bitmap.height; }
274 const rpixel_t& read(size_t idx) { return pixels[idx]; }
275 const pixel_t& lookup(const rpixel_t& p) { return p; }
276 void write(size_t idx, const pixel_t& v) { pixels[idx] = v; }
277 bool is_opaque(const rpixel_t& p) { return p > 0; }
278 pixel_t transparent() { return 0; }
279 private:
280 lua_bitmap& bitmap;
281 pixel_t* pixels;
284 struct operand_bitmap_pal
286 typedef framebuffer::color pixel_t;
287 typedef uint16_t rpixel_t;
288 operand_bitmap_pal(lua_bitmap& _bitmap, lua_palette& _palette)
289 : bitmap(_bitmap), palette(_palette), _transparent(-1)
291 pixels = &bitmap.pixels[0];
292 limit = palette.colors.size();
293 pal = &palette.colors[0];
295 size_t get_width() { return bitmap.width; }
296 size_t get_height() { return bitmap.height; }
297 const rpixel_t& read(size_t idx) { return pixels[idx]; }
298 const pixel_t& lookup(const rpixel_t& p) { return *((p < limit) ? pal + p : &_transparent); }
299 bool is_opaque(const rpixel_t& p) { return p > 0; }
300 const pixel_t& transparent() { return _transparent; }
301 private:
302 lua_bitmap& bitmap;
303 lua_palette& palette;
304 uint16_t* pixels;
305 framebuffer::color* pal;
306 uint32_t limit;
307 framebuffer::color _transparent;
310 struct colorkey_none
312 bool iskey(uint16_t& c) const { return false; }
313 bool iskey(framebuffer::color& c) const { return false; }
316 struct colorkey_direct
318 colorkey_direct(uint64_t _ck)
320 framebuffer::color c(_ck);
321 ck = c.orig;
322 cka = c.origa;
324 bool iskey(framebuffer::color& c) const { return (c.orig == ck && c.origa == cka); }
325 uint32_t ck;
326 uint16_t cka;
329 struct colorkey_palette
331 colorkey_palette(uint64_t _ck) { ck = _ck; }
332 bool iskey(uint16_t& c) const { return (c == ck); }
333 uint16_t ck;
336 template<class _src, class _dest, class colorkey> struct srcdest
338 srcdest(_dest Xdest, _src Xsrc, const colorkey& _ckey)
339 : dest(Xdest), src(Xsrc), ckey(_ckey)
341 swidth = src.get_width();
342 sheight = src.get_height();
343 dwidth = dest.get_width();
344 dheight = dest.get_height();
346 void copy(size_t didx, size_t sidx)
348 typename _src::rpixel_t c = src.read(sidx);
349 if(!ckey.iskey(c))
350 dest.write(didx, src.lookup(c));
352 size_t swidth, sheight, dwidth, dheight;
353 private:
354 _dest dest;
355 _src src;
356 colorkey ckey;
359 template<class _src, class _dest, class colorkey> srcdest<_src, _dest, colorkey> mk_srcdest(_dest dest,
360 _src src, const colorkey& ckey)
362 return srcdest<_src, _dest, colorkey>(dest, src, ckey);
365 struct srcdest_priority
367 srcdest_priority(lua_bitmap& dest, lua_bitmap& src)
369 darray = &dest.pixels[0];
370 sarray = &src.pixels[0];
371 swidth = src.width;
372 sheight = src.height;
373 dwidth = dest.width;
374 dheight = dest.height;
376 void copy(size_t didx, size_t sidx)
378 uint16_t c = sarray[sidx];
379 if(darray[didx] < c)
380 darray[didx] = c;
382 size_t swidth, sheight, dwidth, dheight;
383 private:
384 uint16_t* sarray;
385 uint16_t* darray;
388 enum porterduff_oper
390 PD_SRC,
391 PD_ATOP,
392 PD_OVER,
393 PD_IN,
394 PD_OUT,
395 PD_DEST,
396 PD_DEST_ATOP,
397 PD_DEST_OVER,
398 PD_DEST_IN,
399 PD_DEST_OUT,
400 PD_CLEAR,
401 PD_XOR
404 porterduff_oper get_pd_oper(const std::string& oper)
406 if(oper == "Src") return PD_SRC;
407 if(oper == "Atop") return PD_ATOP;
408 if(oper == "Over") return PD_OVER;
409 if(oper == "In") return PD_IN;
410 if(oper == "Out") return PD_OUT;
411 if(oper == "Dest") return PD_DEST;
412 if(oper == "DestAtop") return PD_DEST_ATOP;
413 if(oper == "DestOver") return PD_DEST_OVER;
414 if(oper == "DestIn") return PD_DEST_IN;
415 if(oper == "DestOut") return PD_DEST_OUT;
416 if(oper == "Clear") return PD_CLEAR;
417 if(oper == "Xor") return PD_XOR;
418 (stringfmt() << "Bad Porter-Duff operator '" << oper << "'").throwex();
421 template<porterduff_oper oper, class _src, class _dest> struct srcdest_porterduff
423 srcdest_porterduff(_dest Xdest, _src Xsrc)
424 : dest(Xdest), src(Xsrc)
426 swidth = src.get_width();
427 sheight = src.get_height();
428 dwidth = dest.get_width();
429 dheight = dest.get_height();
431 void copy(size_t didx, size_t sidx)
433 typename _dest::rpixel_t vd = dest.read(didx);
434 typename _src::rpixel_t vs = src.read(sidx);
435 bool od = dest.is_opaque(vd);
436 bool os = src.is_opaque(vs);
437 typename _dest::pixel_t ld = dest.lookup(vd);
438 typename _src::pixel_t ls = src.lookup(vs);
439 typename _dest::pixel_t t = dest.transparent();
440 typename _dest::pixel_t r;
441 switch(oper) {
442 case PD_SRC: r = ls; break;
443 case PD_ATOP: r = od ? (os ? ls : ld) : t; break;
444 case PD_OVER: r = os ? ls : ld; break;
445 case PD_IN: r = (od & os) ? ls : t; break;
446 case PD_OUT: r = (!od && os) ? ls : t; break;
447 case PD_DEST: r = ld; break;
448 case PD_DEST_ATOP: r = os ? (od ? ld : ls) : t; break;
449 case PD_DEST_OVER: r = od ? ld : ls; break;
450 case PD_DEST_IN: r = (od & os) ? ld : t; break;
451 case PD_DEST_OUT: r = (od & !os) ? ld : t; break;
452 case PD_CLEAR: r = t; break;
453 case PD_XOR: r = od ? (os ? t : ld) : ls; break;
455 dest.write(didx, r);
457 size_t swidth, sheight, dwidth, dheight;
458 private:
459 _dest dest;
460 _src src;
463 template<porterduff_oper oper, class _src, class _dest> srcdest_porterduff<oper, _src, _dest>
464 mk_porterduff(_dest dest, _src src)
466 return srcdest_porterduff<oper, _src, _dest>(dest, src);
469 template<class srcdest>
470 void xblit_copy(srcdest sd, uint32_t dx, uint32_t dy, uint32_t sx, uint32_t sy, uint32_t w, uint32_t h)
472 while((dx + w > sd.dwidth || sx + w > sd.swidth) && w > 0)
473 w--;
474 while((dy + h > sd.dheight || sy + h > sd.sheight) && h > 0)
475 h--;
476 if(dx + w < w || dy + h < h) return; //Don't do overflowing blits.
477 if(sx + w < w || sy + h < h) return; //Don't do overflowing blits.
478 size_t sidx = sy * sd.swidth + sx;
479 size_t didx = dy * sd.dwidth + dx;
480 size_t srskip = sd.swidth - w;
481 size_t drskip = sd.dwidth - w;
482 for(uint32_t j = 0; j < h; j++) {
483 for(uint32_t i = 0; i < w; i++) {
484 sd.copy(didx, sidx);
485 sidx++;
486 didx++;
488 sidx += srskip;
489 didx += drskip;
493 template<class srcdest>
494 void xblit_scaled(srcdest sd, uint32_t dx, uint32_t dy, uint32_t sx, uint32_t sy, uint32_t w, uint32_t h,
495 uint32_t hscl, uint32_t vscl)
497 w = max(static_cast<uint32_t>(sd.dwidth / hscl), w);
498 h = max(static_cast<uint32_t>(sd.dheight / vscl), h);
499 while((dx + hscl * w > sd.dwidth || sx + w > sd.swidth) && w > 0)
500 w--;
501 while((dy + vscl * h > sd.dheight || sy + h > sd.sheight) && h > 0)
502 h--;
503 if(dx + hscl * w < dx || dy + vscl * h < dy) return; //Don't do overflowing blits.
504 if(sx + w < w || sy + h < h) return; //Don't do overflowing blits.
505 size_t sidx = sy * sd.swidth + sx;
506 size_t didx = dy * sd.dwidth + dx;
507 size_t drskip = sd.dwidth - hscl * w;
508 uint32_t _w = hscl * w;
509 for(uint32_t j = 0; j < vscl * h; j++) {
510 uint32_t _sidx = sidx;
511 for(uint32_t i = 0; i < _w ; i += hscl) {
512 for(uint32_t k = 0; k < hscl; k++)
513 sd.copy(didx + k, _sidx);
514 _sidx++;
515 didx+=hscl;
517 if((j % vscl) == vscl - 1)
518 sidx += sd.swidth;
519 didx += drskip;
523 template<bool scaled, class srcdest>
524 inline void xblit(srcdest sd, uint32_t dx, uint32_t dy, uint32_t sx, uint32_t sy, uint32_t w, uint32_t h,
525 uint32_t hscl, uint32_t vscl)
527 if(scaled)
528 xblit_scaled(sd, dx, dy, sx, sy, w, h, hscl, vscl);
529 else
530 xblit_copy(sd, dx, dy, sx, sy, w, h);
533 template<bool scaled, class src, class dest>
534 inline void xblit_pal(dest _dest, src _src, uint64_t ck, uint32_t dx, uint32_t dy, uint32_t sx,
535 uint32_t sy, uint32_t w, uint32_t h, uint32_t hscl, uint32_t vscl)
537 if(ck > 65535)
538 xblit<scaled>(mk_srcdest(_dest, _src, colorkey_none()), dx, dy, sx, sy, w, h,
539 hscl, vscl);
540 else
541 xblit<scaled>(mk_srcdest(_dest, _src, colorkey_palette(ck)), dx, dy, sx, sy, w, h,
542 hscl, vscl);
545 template<bool scaled, class src, class dest>
546 inline void xblit_dir(dest _dest, src _src, uint64_t ck, uint32_t dx, uint32_t dy, uint32_t sx,
547 uint32_t sy, uint32_t w, uint32_t h, uint32_t hscl, uint32_t vscl)
549 if(ck == 0x100000000ULL)
550 xblit<scaled>(mk_srcdest(_dest, _src, colorkey_none()), dx, dy, sx, sy, w, h,
551 hscl, vscl);
552 else
553 xblit<scaled>(mk_srcdest(_dest, _src, colorkey_direct(ck)), dx, dy, sx, sy, w, h,
554 hscl, vscl);
557 template<bool scaled, porterduff_oper oper, class src, class dest>
558 inline void xblit_pduff2(dest _dest, src _src, uint32_t dx, uint32_t dy, uint32_t sx,
559 uint32_t sy, uint32_t w, uint32_t h, uint32_t hscl, uint32_t vscl)
561 xblit<scaled>(mk_porterduff<oper>(_dest, _src), dx, dy, sx, sy, w, h, hscl, vscl);
564 template<bool scaled, class src, class dest>
565 inline void xblit_pduff(dest _dest, src _src, uint32_t dx, uint32_t dy, uint32_t sx,
566 uint32_t sy, uint32_t w, uint32_t h, uint32_t hscl, uint32_t vscl, porterduff_oper oper)
568 switch(oper) {
569 case PD_ATOP:
570 xblit_pduff2<scaled, PD_ATOP>(_dest, _src, dx, dy, sx, sy, w, h, hscl, vscl);
571 break;
572 case PD_CLEAR:
573 xblit_pduff2<scaled, PD_CLEAR>(_dest, _src, dx, dy, sx, sy, w, h, hscl, vscl);
574 break;
575 case PD_DEST:
576 xblit_pduff2<scaled, PD_DEST>(_dest, _src, dx, dy, sx, sy, w, h, hscl, vscl);
577 break;
578 case PD_DEST_ATOP:
579 xblit_pduff2<scaled, PD_DEST_ATOP>(_dest, _src, dx, dy, sx, sy, w, h, hscl, vscl);
580 break;
581 case PD_DEST_IN:
582 xblit_pduff2<scaled, PD_DEST_IN>(_dest, _src, dx, dy, sx, sy, w, h, hscl, vscl);
583 break;
584 case PD_DEST_OUT:
585 xblit_pduff2<scaled, PD_DEST_OUT>(_dest, _src, dx, dy, sx, sy, w, h, hscl, vscl);
586 break;
587 case PD_DEST_OVER:
588 xblit_pduff2<scaled, PD_DEST_OVER>(_dest, _src, dx, dy, sx, sy, w, h, hscl, vscl);
589 break;
590 case PD_IN:
591 xblit_pduff2<scaled, PD_IN>(_dest, _src, dx, dy, sx, sy, w, h, hscl, vscl);
592 break;
593 case PD_OUT:
594 xblit_pduff2<scaled, PD_OUT>(_dest, _src, dx, dy, sx, sy, w, h, hscl, vscl);
595 break;
596 case PD_OVER:
597 xblit_pduff2<scaled, PD_OVER>(_dest, _src, dx, dy, sx, sy, w, h, hscl, vscl);
598 break;
599 case PD_SRC:
600 xblit_pduff2<scaled, PD_SRC>(_dest, _src, dx, dy, sx, sy, w, h, hscl, vscl);
601 break;
602 case PD_XOR:
603 xblit_pduff2<scaled, PD_XOR>(_dest, _src, dx, dy, sx, sy, w, h, hscl, vscl);
604 break;
608 lua::fnptr blit_bitmap(lua_func_misc, "gui.bitmap_blit", [](lua::state& L, const std::string& fname)
609 -> int {
610 if(lua::_class<lua_bitmap>::is(L, 1))
611 return lua::_class<lua_bitmap>::get(L, 1, fname.c_str())->blit<false, false>(L, fname);
612 else if(lua::_class<lua_dbitmap>::is(L, 1))
613 return lua::_class<lua_dbitmap>::get(L, 1, fname.c_str())->blit<false, false>(L, fname);
614 else
615 throw std::runtime_error("Expected BITMAP or DBITMAP as argument 1 for " + fname);
616 return 0;
619 lua::fnptr blit_bitmap_s(lua_func_misc, "gui.bitmap_blit_scaled", [](lua::state& L, const std::string& fname)
620 -> int {
621 if(lua::_class<lua_bitmap>::is(L, 1))
622 return lua::_class<lua_bitmap>::get(L, 1, fname.c_str())->blit<true, false>(L, fname);
623 else if(lua::_class<lua_dbitmap>::is(L, 1))
624 return lua::_class<lua_dbitmap>::get(L, 1, fname.c_str())->blit<true, false>(L, fname);
625 else
626 throw std::runtime_error("Expected BITMAP or DBITMAP as argument 1 for " + fname);
627 return 0;
630 lua::fnptr blit_bitmap_pd(lua_func_misc, "gui.bitmap_blit_porterduff", [](lua::state& L,
631 const std::string& fname) -> int {
632 if(lua::_class<lua_bitmap>::is(L, 1))
633 return lua::_class<lua_bitmap>::get(L, 1, fname.c_str())->blit<false, true>(L, fname);
634 else if(lua::_class<lua_dbitmap>::is(L, 1))
635 return lua::_class<lua_dbitmap>::get(L, 1, fname.c_str())->blit<false, true>(L, fname);
636 else
637 throw std::runtime_error("Expected BITMAP or DBITMAP as argument 1 for " + fname);
638 return 0;
641 lua::fnptr blit_bitmap_spd(lua_func_misc, "gui.bitmap_blit_scaled_porterduff", [](lua::state& L,
642 const std::string& fname) -> int {
643 if(lua::_class<lua_bitmap>::is(L, 1))
644 return lua::_class<lua_bitmap>::get(L, 1, fname.c_str())->blit<true, true>(L, fname);
645 else if(lua::_class<lua_dbitmap>::is(L, 1))
646 return lua::_class<lua_dbitmap>::get(L, 1, fname.c_str())->blit<true, true>(L, fname);
647 else
648 throw std::runtime_error("Expected BITMAP or DBITMAP as argument 1 for " + fname);
649 return 0;
652 lua::fnptr blit_bitmap_p(lua_func_misc, "gui.bitmap_blit_priority", [](lua::state& L,
653 const std::string& fname) -> int {
654 return lua::_class<lua_bitmap>::get(L, 1, fname.c_str())->blit_priority<false>(L, fname);
657 lua::fnptr blit_bitmap_sp(lua_func_misc, "gui.bitmap_blit_scaled_priority", [](lua::state& L,
658 const std::string& fname) -> int {
659 return lua::_class<lua_bitmap>::get(L, 1, fname.c_str())->blit_priority<true>(L, fname);
662 int bitmap_load_fn(lua::state& L, std::function<lua_loaded_bitmap()> src)
664 uint32_t w, h;
665 auto bitmap = src();
666 if(bitmap.d) {
667 lua_dbitmap* b = lua::_class<lua_dbitmap>::create(L, bitmap.w, bitmap.h);
668 for(size_t i = 0; i < bitmap.w * bitmap.h; i++)
669 b->pixels[i] = framebuffer::color(bitmap.bitmap[i]);
670 return 1;
671 } else {
672 lua_bitmap* b = lua::_class<lua_bitmap>::create(L, bitmap.w, bitmap.h);
673 lua_palette* p = lua::_class<lua_palette>::create(L);
674 for(size_t i = 0; i < bitmap.w * bitmap.h; i++)
675 b->pixels[i] = bitmap.bitmap[i];
676 p->colors.resize(bitmap.palette.size());
677 for(size_t i = 0; i < bitmap.palette.size(); i++)
678 p->colors[i] = framebuffer::color(bitmap.palette[i]);
679 return 2;
683 lua::fnptr gui_loadbitmap(lua_func_misc, "gui.bitmap_load", [](lua::state& L,
684 const std::string& fname) -> int {
685 std::string name2;
686 std::string name = L.get_string(1, fname.c_str());
687 if(L.type(2) != LUA_TNIL && L.type(2) != LUA_TNONE)
688 name2 = L.get_string(2, fname.c_str());
689 return bitmap_load_fn(L, [&name, &name2]() -> lua_loaded_bitmap {
690 std::string name3 = zip::resolverel(name, name2);
691 return lua_loaded_bitmap::load(name3);
695 lua::fnptr gui_loadbitmap2(lua_func_misc, "gui.bitmap_load_str", [](lua::state& L,
696 const std::string& fname) -> int {
697 std::string contents = L.get_string(1, fname.c_str());
698 return bitmap_load_fn(L, [&contents]() -> lua_loaded_bitmap {
699 std::istringstream strm(contents);
700 return lua_loaded_bitmap::load(strm);
704 inline int64_t mangle_color(uint32_t c)
706 if(c < 0x1000000)
707 return -1;
708 else
709 return ((256 - (c >> 24) - (c >> 31)) << 24) | (c & 0xFFFFFF);
712 int base64val(char ch)
714 if(ch >= 'A' && ch <= 'Z')
715 return ch - 65;
716 if(ch >= 'a' && ch <= 'z')
717 return ch - 97 + 26;
718 if(ch >= '0' && ch <= '9')
719 return ch - 48 + 52;
720 if(ch == '+')
721 return 62;
722 if(ch == '/')
723 return 63;
724 if(ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n')
725 return -1;
726 if(ch == '=')
727 return -2;
728 return -3;
731 std::string base64_encode(const std::string& str)
733 std::ostringstream x;
734 unsigned pos = 0;
735 uint32_t mem = 0;
736 for(auto i : str) {
737 mem = (mem << 8) + (unsigned char)i;
738 if(++pos == 3) {
739 uint8_t c1 = (mem >> 18) & 0x3F;
740 uint8_t c2 = (mem >> 12) & 0x3F;
741 uint8_t c3 = (mem >> 6) & 0x3F;
742 uint8_t c4 = mem & 0x3F;
743 x << base64chars[c1];
744 x << base64chars[c2];
745 x << base64chars[c3];
746 x << base64chars[c4];
747 mem = 0;
748 pos = 0;
751 if(pos == 2) {
752 uint8_t c1 = (mem >> 10) & 0x3F;
753 uint8_t c2 = (mem >> 4) & 0x3F;
754 uint8_t c3 = (mem << 2) & 0x3F;
755 x << base64chars[c1];
756 x << base64chars[c2];
757 x << base64chars[c3];
758 x << "=";
760 if(pos == 1) {
761 uint8_t c1 = (mem >> 2) & 0x3F;
762 uint8_t c2 = (mem << 4) & 0x3F;
763 x << base64chars[c1];
764 x << base64chars[c2];
765 x << "==";
767 return x.str();
770 std::string base64_decode(const std::string& str)
772 bool end = 0;
773 uint32_t memory = 0;
774 uint32_t memsize = 1;
775 int posmod = 0;
776 std::ostringstream x;
777 for(auto i : str) {
778 int v = base64val(i);
779 if(v == -1)
780 continue;
781 posmod = (posmod + 1) & 3;
782 if(v == -2 && (posmod == 1 || posmod == 2))
783 throw std::runtime_error("Invalid Base64");
784 if(v == -2) {
785 end = true;
786 continue;
788 if(v == -3 || end)
789 throw std::runtime_error("Invalid Base64");
790 memory = memory * 64 + v;
791 memsize = memsize * 64;
792 if(memsize >= 256) {
793 memsize >>= 8;
794 x << static_cast<uint8_t>(memory / memsize);
795 memory %= memsize;
798 return x.str();
801 template<typename T>
802 int bitmap_load_png_fn(lua::state& L, T& src)
804 png::decoder img(src);
805 if(img.has_palette) {
806 lua_bitmap* b = lua::_class<lua_bitmap>::create(L, img.width, img.height);
807 lua_palette* p = lua::_class<lua_palette>::create(L);
808 for(size_t i = 0; i < img.width * img.height; i++)
809 b->pixels[i] = img.data[i];
810 p->colors.resize(img.palette.size());
811 for(size_t i = 0; i < img.palette.size(); i++)
812 p->colors[i] = framebuffer::color(mangle_color(img.palette[i]));
813 return 2;
814 } else {
815 lua_dbitmap* b = lua::_class<lua_dbitmap>::create(L, img.width, img.height);
816 for(size_t i = 0; i < img.width * img.height; i++)
817 b->pixels[i] = framebuffer::color(mangle_color(img.data[i]));
818 return 1;
822 lua::fnptr gui_loadbitmappng(lua_func_misc, "gui.bitmap_load_png", [](lua::state& L,
823 const std::string& fname) -> int {
824 std::string name2;
825 std::string name = L.get_string(1, fname.c_str());
826 if(L.type(2) != LUA_TNIL && L.type(2) != LUA_TNONE)
827 name2 = L.get_string(2, fname.c_str());
828 std::string filename = zip::resolverel(name, name2);
829 return bitmap_load_png_fn(L, filename);
832 lua::fnptr gui_loadbitmappng2(lua_func_misc, "gui.bitmap_load_png_str", [](lua::state& L,
833 const std::string& fname) -> int {
834 std::string contents = base64_decode(L.get_string(1, fname.c_str()));
835 std::istringstream strm(contents);
836 return bitmap_load_png_fn(L, strm);
839 lua::fnptr gui_savebitmappng(lua_func_misc, "gui.bitmap_save_png", [](lua::state& L,
840 const std::string& fname) -> int {
841 int slot = 1;
842 while(L.type(slot) == LUA_TSTRING)
843 slot++;
844 if(lua::_class<lua_bitmap>::is(L, slot))
845 return lua::_class<lua_bitmap>::get(L, slot, fname.c_str())->_save_png(L, fname, false);
846 else if(lua::_class<lua_dbitmap>::is(L, slot))
847 return lua::_class<lua_dbitmap>::get(L, slot, fname.c_str())->_save_png(L, fname, false);
848 else
849 throw std::runtime_error("Expected BITMAP or DBITMAP as first non-string argument for " +
850 fname);
851 return 0;
854 int bitmap_palette_fn(lua::state& L, std::istream& s)
856 lua_palette* p = lua::_class<lua_palette>::create(L);
857 while(s) {
858 std::string line;
859 std::getline(s, line);
860 istrip_CR(line);
861 regex_results r;
862 if(!regex_match("[ \t]*(#.*)?", line)) {
863 //Nothing.
864 } else if(r = regex("[ \t]*([0-9]+)[ \t]+([0-9]+)[ \t]+([0-9]+)[ \t]+([0-9]+)[ \t]*", line)) {
865 int64_t cr, cg, cb, ca;
866 cr = parse_value<uint8_t>(r[1]);
867 cg = parse_value<uint8_t>(r[2]);
868 cb = parse_value<uint8_t>(r[3]);
869 ca = 256 - parse_value<uint16_t>(r[4]);
870 int64_t clr;
871 if(ca == 256)
872 p->colors.push_back(framebuffer::color(-1));
873 else
874 p->colors.push_back(framebuffer::color((ca << 24) | (cr << 16)
875 | (cg << 8) | cb));
876 } else if(r = regex("[ \t]*([0-9]+)[ \t]+([0-9]+)[ \t]+([0-9]+)[ \t]*", line)) {
877 int64_t cr, cg, cb;
878 cr = parse_value<uint8_t>(r[1]);
879 cg = parse_value<uint8_t>(r[2]);
880 cb = parse_value<uint8_t>(r[3]);
881 p->colors.push_back(framebuffer::color((cr << 16) | (cg << 8) | cb));
882 } else if(r = regex("[ \t]*([^ \t]|[^ \t].*[^ \t])[ \t]*", line)) {
883 p->colors.push_back(framebuffer::color(r[1]));
884 } else
885 throw std::runtime_error("Invalid line format (" + line + ")");
887 return 1;
890 lua::fnptr gui_loadpalette(lua_func_misc, "gui.bitmap_load_pal", [](lua::state& L,
891 const std::string& fname) -> int {
892 std::string name2;
893 std::string name = L.get_string(1, fname.c_str());
894 if(L.type(2) != LUA_TNIL && L.type(2) != LUA_TNONE)
895 name2 = L.get_string(2, fname.c_str());
896 std::istream& s = zip::openrel(name, name2);
897 try {
898 int r = bitmap_palette_fn(L, s);
899 delete &s;
900 return r;
901 } catch(...) {
902 delete &s;
903 throw;
907 lua::fnptr gui_loadpalette2(lua_func_misc, "gui.bitmap_load_pal_str", [](lua::state& L,
908 const std::string& fname) -> int {
909 std::string content = L.get_string(1, fname.c_str());
910 std::istringstream s(content);
911 return bitmap_palette_fn(L, s);
914 lua::fnptr gui_dpalette(lua_func_misc, "gui.palette_debug", [](lua::state& L,
915 const std::string& fname) -> int {
916 lua_palette* p = lua::_class<lua_palette>::get(L, 1, fname.c_str());
917 return p->debug(L, fname);
920 inline framebuffer::color tadjust(framebuffer::color c, uint16_t adj)
922 uint32_t rgb = c.orig;
923 uint32_t a = c.origa;
924 a = (a * adj) >> 8;
925 if(a > 256)
926 a = 256;
927 if(a == 0)
928 return framebuffer::color(-1);
929 else
930 return framebuffer::color(rgb | ((uint32_t)(256 - a) << 24));
933 lua::fnptr adjust_trans(lua_func_misc, "gui.adjust_transparency", [](lua::state& L,
934 const std::string& fname) -> int {
935 if(lua::_class<lua_dbitmap>::is(L, 1))
936 return lua::_class<lua_dbitmap>::get(L, 1, fname.c_str())->adjust_transparency(L, fname);
937 else if(lua::_class<lua_palette>::is(L, 1))
938 return lua::_class<lua_palette>::get(L, 1, fname.c_str())->adjust_transparency(L, fname);
939 else
940 throw std::runtime_error("Expected BITMAP or PALETTE as argument 1 for "
941 "gui.adjust_transparency");
942 return 0;
945 lua::_class<lua_palette> class_palette("PALETTE");
946 lua::_class<lua_bitmap> class_bitmap("BITMAP");
947 lua::_class<lua_dbitmap> class_dbitmap("DBITMAP");
950 /** Palette **/
951 lua_palette::lua_palette(lua::state& L)
953 lua::objclass<lua_palette>().bind_multi(L, {
954 {"set", &lua_palette::set},
955 {"hash", &lua_palette::hash},
956 {"debug", &lua_palette::debug},
957 {"adjust_transparency", &lua_palette::adjust_transparency},
961 lua_palette::~lua_palette()
965 std::string lua_palette::print()
967 size_t s = colors.size();
968 return (stringfmt() << s << " " << ((s != 1) ? "colors" : "color")).str();
971 int lua_palette::set(lua::state& L, const std::string& fname)
973 uint16_t c = L.get_numeric_argument<uint16_t>(2, fname.c_str());
974 auto nc = lua_get_fb_color(L, 3, fname);
975 //The mutex lock protects only the internals of colors array.
976 if(this->colors.size() <= c) {
977 this->palette_mutex.lock();
978 this->colors.resize(static_cast<uint32_t>(c) + 1);
979 this->palette_mutex.unlock();
981 this->colors[c] = nc;
982 return 0;
985 int lua_palette::hash(lua::state& L, const std::string& fname)
987 sha256 h;
988 const int buffersize = 256;
989 int bufferuse = 0;
990 char buf[buffersize];
991 unsigned realsize = 0;
992 for(unsigned i = 0; i < this->colors.size(); i++)
993 if(this->colors[i].origa) realsize = i + 1;
994 for(unsigned i = 0; i < realsize; i++) {
995 if(bufferuse + 6 > buffersize) {
996 h.write(buf, bufferuse);
997 bufferuse = 0;
999 serialization::u32b(buf + bufferuse + 0, this->colors[i].orig);
1000 serialization::u16b(buf + bufferuse + 4, this->colors[i].origa);
1001 bufferuse += 6;
1003 if(bufferuse > 0) h.write(buf, bufferuse);
1004 L.pushlstring(h.read());
1005 return 1;
1008 int lua_palette::debug(lua::state& L, const std::string& fname)
1010 size_t i = 0;
1011 for(auto c : this->colors)
1012 messages << "Color #" << (i++) << ": " << c.orig << ":" << c.origa << std::endl;
1013 return 0;
1016 int lua_palette::adjust_transparency(lua::state& L, const std::string& fname)
1018 uint16_t tadj = L.get_numeric_argument<uint16_t>(2, fname.c_str());
1019 for(auto& c : this->colors)
1020 c = tadjust(c, tadj);
1021 return 0;
1024 /** BITMAP **/
1025 lua_bitmap::lua_bitmap(lua::state& L, uint32_t w, uint32_t h)
1027 lua::objclass<lua_bitmap>().bind_multi(L, {
1028 {"draw", &lua_bitmap::draw},
1029 {"pset", &lua_bitmap::pset},
1030 {"pget", &lua_bitmap::pget},
1031 {"size", &lua_bitmap::size},
1032 {"hash", &lua_bitmap::hash},
1033 {"blit", &lua_bitmap::blit<false, false>},
1034 {"blit_priority", &lua_bitmap::blit_priority<false>},
1035 {"blit_scaled", &lua_bitmap::blit<true, false>},
1036 {"blit_scaled_priority", &lua_bitmap::blit_priority<true>},
1037 {"blit_porterduff", &lua_bitmap::blit<false, true>},
1038 {"blit_scaled_porterduff", &lua_bitmap::blit<true, true>},
1039 {"save_png", &lua_bitmap::save_png},
1041 width = w;
1042 height = h;
1043 pixels.resize(width * height);
1044 memset(&pixels[0], 0, width * height);
1047 lua_bitmap::~lua_bitmap()
1049 render_kill_request(this);
1052 std::string lua_bitmap::print()
1054 return (stringfmt() << width << "*" << height).str();
1057 int lua_bitmap::draw(lua::state& L, const std::string& fname)
1059 return _draw(L, fname, true);
1062 int lua_bitmap::_draw(lua::state& L, const std::string& fname, bool is_method)
1064 if(!lua_render_ctx)
1065 return 0;
1066 int arg_x = is_method ? 2 : 1;
1067 int arg_y = arg_x + 1;
1068 int arg_b = is_method ? 1 : 3;
1069 int32_t x = L.get_numeric_argument<int32_t>(arg_x, fname.c_str());
1070 int32_t y = L.get_numeric_argument<int32_t>(arg_y, fname.c_str());
1071 auto b = lua::_class<lua_bitmap>::pin(L, arg_b, fname.c_str());
1072 auto p = lua::_class<lua_palette>::pin(L, 4, fname.c_str());
1073 lua_render_ctx->queue->create_add<render_object_bitmap>(x, y, b, p);
1074 return 0;
1077 int lua_bitmap::pset(lua::state& L, const std::string& fname)
1079 uint32_t x = L.get_numeric_argument<uint32_t>(2, fname.c_str());
1080 uint32_t y = L.get_numeric_argument<uint32_t>(3, fname.c_str());
1081 uint16_t c = L.get_numeric_argument<uint16_t>(4, fname.c_str());
1082 if(x >= this->width || y >= this->height)
1083 return 0;
1084 this->pixels[y * this->width + x] = c;
1085 return 0;
1088 int lua_bitmap::pget(lua::state& L, const std::string& fname)
1090 uint32_t x = L.get_numeric_argument<uint32_t>(2, fname.c_str());
1091 uint32_t y = L.get_numeric_argument<uint32_t>(3, fname.c_str());
1092 if(x >= this->width || y >= this->height)
1093 return 0;
1094 L.pushnumber(this->pixels[y * this->width + x]);
1095 return 1;
1098 int lua_bitmap::size(lua::state& L, const std::string& fname)
1100 L.pushnumber(this->width);
1101 L.pushnumber(this->height);
1102 return 2;
1105 int lua_bitmap::hash(lua::state& L, const std::string& fname)
1107 sha256 h;
1108 const int buffersize = 256;
1109 int bufferuse = 0;
1110 char buf[buffersize];
1111 memset(buf, 0, buffersize);
1112 serialization::u64b(buf + 0, this->width);
1113 serialization::u64b(buf + 8, this->height);
1114 bufferuse = 16;
1115 for(unsigned i = 0; i < this->width * this->height; i++) {
1116 if(bufferuse + 2 > buffersize) {
1117 h.write(buf, bufferuse);
1118 bufferuse = 0;
1120 serialization::u16b(buf + bufferuse + 0, this->pixels[i]);
1121 bufferuse += 2;
1123 if(bufferuse > 0) h.write(buf, bufferuse);
1124 L.pushlstring(h.read());
1125 return 1;
1128 template<bool scaled, bool porterduff> int lua_bitmap::blit(lua::state& L, const std::string& fname)
1130 uint32_t dx = L.get_numeric_argument<uint32_t>(2, fname.c_str());
1131 uint32_t dy = L.get_numeric_argument<uint32_t>(3, fname.c_str());
1132 bool src_d = lua::_class<lua_dbitmap>::is(L, 4);
1133 bool src_p = lua::_class<lua_bitmap>::is(L, 4);
1134 if(!src_d && !src_p)
1135 throw std::runtime_error("Expected BITMAP or DBITMAP as argument 4 for " + fname);
1136 uint32_t sx = L.get_numeric_argument<uint32_t>(5, fname.c_str());
1137 uint32_t sy = L.get_numeric_argument<uint32_t>(6, fname.c_str());
1138 uint32_t w = L.get_numeric_argument<uint32_t>(7, fname.c_str());
1139 uint32_t h = L.get_numeric_argument<uint32_t>(8, fname.c_str());
1140 uint32_t hscl, vscl;
1141 if(scaled) {
1142 hscl = L.get_numeric_argument<uint32_t>(9, fname.c_str());
1143 vscl = hscl;
1144 L.get_numeric_argument<uint32_t>(10, vscl, fname.c_str());
1146 int64_t ck = 65536;
1147 porterduff_oper pd_oper;
1148 if(porterduff) {
1149 std::string oper = L.get_string(scaled ? 11 : 9, fname.c_str());
1150 pd_oper = get_pd_oper(oper);
1151 } else
1152 L.get_numeric_argument<int64_t>(scaled ? 11 : 9, ck, fname.c_str());
1153 if(src_p) {
1154 lua_bitmap* sb = lua::_class<lua_bitmap>::get(L, 4, fname.c_str());
1155 if(porterduff)
1156 xblit_pduff<scaled>(operand_bitmap(*this), operand_bitmap(*sb), dx, dy, sx, sy, w, h,
1157 hscl, vscl, pd_oper);
1158 else
1159 xblit_pal<scaled>(operand_bitmap(*this), operand_bitmap(*sb), ck, dx, dy, sx, sy, w, h,
1160 hscl, vscl);
1161 } else
1162 throw std::runtime_error("If parameter 1 to " + fname + " is paletted, parameter 4 must be "
1163 "too");
1164 return 0;
1167 template<bool scaled> int lua_bitmap::blit_priority(lua::state& L, const std::string& fname)
1169 uint32_t dx = L.get_numeric_argument<uint32_t>(2, fname.c_str());
1170 uint32_t dy = L.get_numeric_argument<uint32_t>(3, fname.c_str());
1171 lua_bitmap* sb = lua::_class<lua_bitmap>::get(L, 4, fname.c_str());
1172 uint32_t sx = L.get_numeric_argument<uint32_t>(5, fname.c_str());
1173 uint32_t sy = L.get_numeric_argument<uint32_t>(6, fname.c_str());
1174 uint32_t w = L.get_numeric_argument<uint32_t>(7, fname.c_str());
1175 uint32_t h = L.get_numeric_argument<uint32_t>(8, fname.c_str());
1176 uint32_t hscl, vscl;
1177 if(scaled) {
1178 hscl = L.get_numeric_argument<uint32_t>(9, fname.c_str());
1179 vscl = hscl;
1180 L.get_numeric_argument<uint32_t>(10, vscl, fname.c_str());
1182 xblit<scaled>(srcdest_priority(*this, *sb), dx, dy, sx, sy, w, h, hscl, vscl);
1183 return 0;
1186 int lua_bitmap::save_png(lua::state& L, const std::string& fname)
1188 return _save_png(L, fname, true);
1191 int lua_bitmap::_save_png(lua::state& L, const std::string& fname, bool is_method)
1193 int index = is_method ? 2 : 1;
1194 int oindex = index;
1195 std::string name, name2;
1196 if(L.type(index) == LUA_TSTRING) {
1197 name = L.get_string(index, fname.c_str());
1198 index++;
1200 if(L.type(index) == LUA_TSTRING) {
1201 name2 = L.get_string(index, fname.c_str());
1202 index++;
1204 lua_palette* p = lua::_class<lua_palette>::get(L, index + (is_method ? 0 : 1), fname.c_str());
1205 auto buf = this->save_png(*p);
1206 if(L.type(oindex) == LUA_TSTRING) {
1207 std::string filename = zip::resolverel(name, name2);
1208 std::ofstream strm(filename, std::ios::binary);
1209 if(!strm)
1210 throw std::runtime_error("Can't open output file");
1211 strm.write(&buf[0], buf.size());
1212 if(!strm)
1213 throw std::runtime_error("Can't write output file");
1214 return 0;
1215 } else {
1216 std::ostringstream strm;
1217 strm.write(&buf[0], buf.size());
1218 L.pushlstring(base64_encode(strm.str()));
1219 return 1;
1223 /** DBITMAP **/
1224 lua_dbitmap::lua_dbitmap(lua::state& L, uint32_t w, uint32_t h)
1226 lua::objclass<lua_dbitmap>().bind_multi(L, {
1227 {"draw", &lua_dbitmap::draw},
1228 {"pset", &lua_dbitmap::pset},
1229 {"pget", &lua_dbitmap::pget},
1230 {"size", &lua_dbitmap::size},
1231 {"hash", &lua_dbitmap::hash},
1232 {"blit", &lua_dbitmap::blit<false, false>},
1233 {"blit_scaled", &lua_dbitmap::blit<true, false>},
1234 {"blit_porterduff", &lua_dbitmap::blit<false, true>},
1235 {"blit_scaled_porterduff", &lua_dbitmap::blit<true, true>},
1236 {"save_png", &lua_dbitmap::save_png},
1237 {"adjust_transparency", &lua_dbitmap::adjust_transparency},
1239 width = w;
1240 height = h;
1241 pixels.resize(width * height);
1244 lua_dbitmap::~lua_dbitmap()
1246 render_kill_request(this);
1249 std::string lua_dbitmap::print()
1251 return (stringfmt() << width << "*" << height).str();
1254 int lua_dbitmap::draw(lua::state& L, const std::string& fname)
1256 return _draw(L, fname, true);
1259 int lua_dbitmap::_draw(lua::state& L, const std::string& fname, bool is_method)
1261 if(!lua_render_ctx)
1262 return 0;
1263 int arg_x = is_method ? 2 : 1;
1264 int arg_y = arg_x + 1;
1265 int arg_b = is_method ? 1 : 3;
1266 int32_t x = L.get_numeric_argument<int32_t>(arg_x, fname.c_str());
1267 int32_t y = L.get_numeric_argument<int32_t>(arg_y, fname.c_str());
1268 auto b = lua::_class<lua_dbitmap>::pin(L, arg_b, fname.c_str());
1269 lua_render_ctx->queue->create_add<render_object_bitmap>(x, y, b);
1270 return 0;
1273 int lua_dbitmap::pset(lua::state& L, const std::string& fname)
1275 uint32_t x = L.get_numeric_argument<uint32_t>(2, fname.c_str());
1276 uint32_t y = L.get_numeric_argument<uint32_t>(3, fname.c_str());
1277 auto c = lua_get_fb_color(L, 4, fname);
1278 if(x >= this->width || y >= this->height)
1279 return 0;
1280 this->pixels[y * this->width + x] = c;
1281 return 0;
1284 int lua_dbitmap::pget(lua::state& L, const std::string& fname)
1286 uint32_t x = L.get_numeric_argument<uint32_t>(2, fname.c_str());
1287 uint32_t y = L.get_numeric_argument<uint32_t>(3, fname.c_str());
1288 if(x >= this->width || y >= this->height)
1289 return 0;
1290 L.pushnumber((this->pixels[y * this->width + x]).asnumber());
1291 return 1;
1294 int lua_dbitmap::size(lua::state& L, const std::string& fname)
1296 L.pushnumber(this->width);
1297 L.pushnumber(this->height);
1298 return 2;
1301 int lua_dbitmap::hash(lua::state& L, const std::string& fname)
1303 sha256 h;
1304 const int buffersize = 256;
1305 int bufferuse = 0;
1306 char buf[buffersize];
1307 memset(buf, 0, buffersize);
1308 serialization::u64b(buf + 0, this->width);
1309 serialization::u64b(buf + 4, this->height);
1310 bufferuse = 16;
1311 for(unsigned i = 0; i < this->width * this->height; i++) {
1312 if(bufferuse + 6 > buffersize) {
1313 h.write(buf, bufferuse);
1314 bufferuse = 0;
1316 serialization::u32b(buf + bufferuse + 0, this->pixels[i].orig);
1317 serialization::u16b(buf + bufferuse + 4, this->pixels[i].origa);
1318 bufferuse += 6;
1320 if(bufferuse > 0) h.write(buf, bufferuse);
1321 L.pushlstring(h.read());
1322 return 1;
1325 template<bool scaled, bool porterduff> int lua_dbitmap::blit(lua::state& L, const std::string& fname)
1327 lua::parameters P(L, fname);
1328 P.skip(); //This.
1329 auto dx = P.arg<uint32_t>();
1330 auto dy = P.arg<uint32_t>();
1331 bool src_d = P.is<lua_dbitmap>();
1332 bool src_p = P.is<lua_bitmap>();
1333 int sidx = P.skip();
1334 if(!src_d && !src_p)
1335 P.expected("BITMAP or DBITMAP", sidx);
1336 int spal;
1337 if(src_p)
1338 spal = P.skip(); //Reserve for palette.
1339 auto sx = P.arg<uint32_t>();
1340 auto sy = P.arg<uint32_t>();
1341 auto w = P.arg<uint32_t>();
1342 auto h = P.arg<uint32_t>();
1343 uint32_t hscl, vscl;
1344 if(scaled) {
1345 hscl = P.arg_opt<uint32_t>(1);
1346 vscl = P.arg_opt<uint32_t>(hscl);
1348 int64_t ckx = 0x100000000ULL;
1349 porterduff_oper pd_oper;
1350 if(porterduff) {
1351 pd_oper = get_pd_oper(P.arg<std::string>());
1352 } else {
1353 //Hack: Direct-color bitmaps should take color spec, with special NONE value.
1354 if(src_p)
1355 ckx = P.arg_opt<int64_t>(0x10000);
1356 else if(P.is_novalue())
1357 ; //Do nothing.
1358 else
1359 ckx = P.color(0).asnumber();
1362 operand_dbitmap dest(*this);
1363 if(src_d) {
1364 operand_dbitmap src(*P.arg<lua_dbitmap*>(sidx));
1365 if(porterduff)
1366 xblit_pduff<scaled>(dest, src, dx, dy, sx, sy, w, h, hscl, vscl, pd_oper);
1367 else
1368 xblit_dir<scaled>(dest, src, ckx, dx, dy, sx, sy, w, h, hscl, vscl);
1369 } else {
1370 operand_bitmap_pal src(*P.arg<lua_bitmap*>(sidx), *P.arg<lua_palette*>(spal));
1371 if(porterduff)
1372 xblit_pduff<scaled>(dest, src, dx, dy, sx, sy, w, h, hscl, vscl, pd_oper);
1373 else
1374 xblit_pal<scaled>(dest, src, ckx, dx, dy, sx, sy, w, h, hscl, vscl);
1376 return 0;
1379 int lua_dbitmap::save_png(lua::state& L, const std::string& fname)
1381 return _save_png(L, fname, true);
1384 int lua_dbitmap::_save_png(lua::state& L, const std::string& fname, bool is_method)
1386 int index = is_method ? 2 : 1;
1387 std::string name, name2;
1388 if(L.type(index) == LUA_TSTRING)
1389 name = L.get_string(index, fname.c_str());
1390 if(L.type(index + 1) == LUA_TSTRING)
1391 name2 = L.get_string(index + 1, fname.c_str());
1392 auto buf = this->save_png();
1393 if(L.type(index) == LUA_TSTRING) {
1394 std::string filename = zip::resolverel(name, name2);
1395 std::ofstream strm(filename, std::ios::binary);
1396 if(!strm)
1397 throw std::runtime_error("Can't open output file");
1398 strm.write(&buf[0], buf.size());
1399 if(!strm)
1400 throw std::runtime_error("Can't write output file");
1401 return 0;
1402 } else {
1403 std::ostringstream strm;
1404 strm.write(&buf[0], buf.size());
1405 L.pushlstring(base64_encode(strm.str()));
1406 return 1;
1410 int lua_dbitmap::adjust_transparency(lua::state& L, const std::string& fname)
1412 uint16_t tadj = L.get_numeric_argument<uint16_t>(2, fname.c_str());
1413 for(auto& c : this->pixels)
1414 c = tadjust(c, tadj);
1415 return 0;