Add <functional> to files that use std::function
[lsnes.git] / src / lua / gui-bitmap.cpp
blob24e8901d45cf16fad55f58a2071c6e1619b7c3fd
1 #include "lua/internal.hpp"
2 #include "core/framebuffer.hpp"
3 #include "core/instance.hpp"
4 #include "core/messages.hpp"
5 #include "core/misc.hpp"
6 #include "library/lua-framebuffer.hpp"
7 #include "library/minmax.hpp"
8 #include "library/png.hpp"
9 #include "library/sha256.hpp"
10 #include "library/serialization.hpp"
11 #include "library/string.hpp"
12 #include "library/zip.hpp"
13 #include "lua/bitmap.hpp"
14 #include "library/threads.hpp"
15 #include <functional>
16 #include <vector>
17 #include <sstream>
19 std::vector<char> lua_dbitmap::save_png() const
21 png::encoder img;
22 img.width = width;
23 img.height = height;
24 img.has_palette = false;
25 img.has_alpha = false;
26 img.data.resize(width * height);
27 for(size_t i = 0; i < width * height; i++) {
28 const framebuffer::color& c = pixels[i];
29 if(c.origa != 256)
30 img.has_alpha = true;
31 img.data[i] = c.orig + ((uint32_t)(c.origa - (c.origa >> 7) + (c.origa >> 8)) << 24);
33 std::ostringstream tmp1;
34 img.encode(tmp1);
35 std::string tmp2 = tmp1.str();
36 return std::vector<char>(tmp2.begin(), tmp2.end());
39 std::vector<char> lua_bitmap::save_png(const lua_palette& pal) const
41 png::encoder img;
42 img.width = width;
43 img.height = height;
44 img.has_palette = true;
45 img.has_alpha = false;
46 img.data.resize(width * height);
47 img.palette.resize(pal.color_count);
48 for(size_t i = 0; i < width * height; i++) {
49 img.data[i] = pixels[i];
51 for(size_t i = 0; i < pal.color_count; i++) {
52 const framebuffer::color& c = pal.colors[i];
53 if(c.origa != 256)
54 img.has_alpha = true;
55 img.palette[i] = c.orig + ((uint32_t)(c.origa - (c.origa >> 7) + (c.origa >> 8)) << 24);
57 std::ostringstream tmp1;
58 img.encode(tmp1);
59 std::string tmp2 = tmp1.str();
60 return std::vector<char>(tmp2.begin(), tmp2.end());
63 namespace
65 const char* CONST_base64chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
67 struct render_object_bitmap : public framebuffer::object
69 render_object_bitmap(int32_t _x, int32_t _y, lua::objpin<lua_bitmap>& _bitmap,
70 lua::objpin<lua_palette>& _palette, int32_t _x0, int32_t _y0, uint32_t _dw, uint32_t _dh,
71 bool _outside) throw()
73 x = _x;
74 y = _y;
75 b = _bitmap;
76 p = _palette;
77 x0 = _x0;
78 y0 = _y0;
79 dw = _dw;
80 dh = _dh;
81 outside = _outside;
84 render_object_bitmap(int32_t _x, int32_t _y, lua::objpin<lua_dbitmap>& _bitmap, int32_t _x0,
85 int32_t _y0, uint32_t _dw, uint32_t _dh, bool _outside) throw()
87 x = _x;
88 y = _y;
89 b2 = _bitmap;
90 x0 = _x0;
91 y0 = _y0;
92 dw = _dw;
93 dh = _dh;
94 outside = _outside;
97 ~render_object_bitmap() throw()
101 bool kill_request(void* obj) throw()
103 return kill_request_ifeq(p.object(), obj) ||
104 kill_request_ifeq(b.object(), obj) ||
105 kill_request_ifeq(b2.object(), obj);
108 template<bool T> void composite_op(struct framebuffer::fb<T>& scr) throw()
110 uint32_t oX = x + scr.get_origin_x() - x0;
111 uint32_t oY = y + scr.get_origin_y() - y0;
112 size_t w, h;
113 if(b) {
114 w = b->width;
115 h = b->height;
116 } else {
117 w = b2->width;
118 h = b2->height;
121 range bX = ((range::make_w(scr.get_width()) - oX) & range::make_w(w) &
122 range::make_s(x0, dw));
123 range bY = ((range::make_w(scr.get_height()) - oY) & range::make_w(h) &
124 range::make_s(y0, dh));
125 range sX = range::make_s(-x + x0, scr.get_last_blit_width());
126 range sY = range::make_s(-y + y0, scr.get_last_blit_height());
128 if(b)
129 lua_bitmap_composite(scr, oX, oY, bX, bY, sX, sY, outside,
130 lua_bitmap_holder<T>(*b, *p));
131 else
132 lua_bitmap_composite(scr, oX, oY, bX, bY, sX, sY, outside,
133 lua_dbitmap_holder<T>(*b2));
135 void operator()(struct framebuffer::fb<false>& x) throw() { composite_op(x); }
136 void operator()(struct framebuffer::fb<true>& x) throw() { composite_op(x); }
137 void clone(framebuffer::queue& q) const throw(std::bad_alloc) { q.clone_helper(this); }
138 private:
139 int32_t x;
140 int32_t y;
141 lua::objpin<lua_bitmap> b;
142 lua::objpin<lua_dbitmap> b2;
143 lua::objpin<lua_palette> p;
144 int32_t x0;
145 int32_t y0;
146 uint32_t dw;
147 uint32_t dh;
148 bool outside;
151 struct operand_dbitmap
153 typedef framebuffer::color pixel_t;
154 typedef framebuffer::color rpixel_t;
155 operand_dbitmap(lua_dbitmap& _bitmap)
156 : bitmap(_bitmap), _transparent(-1)
158 pixels = bitmap.pixels;
160 size_t get_width() { return bitmap.width; }
161 size_t get_height() { return bitmap.height; }
162 const rpixel_t& read(size_t idx) { return pixels[idx]; }
163 const pixel_t& lookup(const rpixel_t& p) { return p; }
164 void write(size_t idx, const pixel_t& v) { pixels[idx] = v; }
165 bool is_opaque(const rpixel_t& p) { return p.origa > 0; }
166 const pixel_t& transparent() { return _transparent; }
167 private:
168 lua_dbitmap& bitmap;
169 pixel_t* pixels;
170 framebuffer::color _transparent;
173 struct operand_bitmap
175 typedef uint16_t pixel_t;
176 typedef uint16_t rpixel_t;
177 operand_bitmap(lua_bitmap& _bitmap)
178 : bitmap(_bitmap)
180 pixels = bitmap.pixels;
182 size_t get_width() { return bitmap.width; }
183 size_t get_height() { return bitmap.height; }
184 const rpixel_t& read(size_t idx) { return pixels[idx]; }
185 const pixel_t& lookup(const rpixel_t& p) { return p; }
186 void write(size_t idx, const pixel_t& v) { pixels[idx] = v; }
187 bool is_opaque(const rpixel_t& p) { return p > 0; }
188 pixel_t transparent() { return 0; }
189 private:
190 lua_bitmap& bitmap;
191 pixel_t* pixels;
194 struct operand_bitmap_pal
196 typedef framebuffer::color pixel_t;
197 typedef uint16_t rpixel_t;
198 operand_bitmap_pal(lua_bitmap& _bitmap, lua_palette& _palette)
199 : bitmap(_bitmap), palette(_palette), _transparent(-1)
201 pixels = bitmap.pixels;
202 limit = palette.color_count;
203 pal = palette.colors;
205 size_t get_width() { return bitmap.width; }
206 size_t get_height() { return bitmap.height; }
207 const rpixel_t& read(size_t idx) { return pixels[idx]; }
208 const pixel_t& lookup(const rpixel_t& p) { return *((p < limit) ? pal + p : &_transparent); }
209 bool is_opaque(const rpixel_t& p) { return p > 0; }
210 const pixel_t& transparent() { return _transparent; }
211 private:
212 lua_bitmap& bitmap;
213 lua_palette& palette;
214 uint16_t* pixels;
215 framebuffer::color* pal;
216 uint32_t limit;
217 framebuffer::color _transparent;
220 struct colorkey_none
222 bool iskey(uint16_t& c) const { return false; }
223 bool iskey(framebuffer::color& c) const { return false; }
226 struct colorkey_direct
228 colorkey_direct(uint64_t _ck)
230 framebuffer::color c(_ck);
231 ck = c.orig;
232 cka = c.origa;
234 bool iskey(framebuffer::color& c) const { return (c.orig == ck && c.origa == cka); }
235 uint32_t ck;
236 uint16_t cka;
239 struct colorkey_palette
241 colorkey_palette(uint64_t _ck) { ck = _ck; }
242 bool iskey(uint16_t& c) const { return (c == ck); }
243 uint16_t ck;
246 template<class _src, class _dest, class colorkey> struct srcdest
248 srcdest(_dest Xdest, _src Xsrc, const colorkey& _ckey)
249 : dest(Xdest), src(Xsrc), ckey(_ckey)
251 swidth = src.get_width();
252 sheight = src.get_height();
253 dwidth = dest.get_width();
254 dheight = dest.get_height();
256 void copy(size_t didx, size_t sidx)
258 typename _src::rpixel_t c = src.read(sidx);
259 if(!ckey.iskey(c))
260 dest.write(didx, src.lookup(c));
262 size_t swidth, sheight, dwidth, dheight;
263 private:
264 _dest dest;
265 _src src;
266 colorkey ckey;
269 template<class _src, class _dest, class colorkey> srcdest<_src, _dest, colorkey> mk_srcdest(_dest dest,
270 _src src, const colorkey& ckey)
272 return srcdest<_src, _dest, colorkey>(dest, src, ckey);
275 struct srcdest_priority
277 srcdest_priority(lua_bitmap& dest, lua_bitmap& src)
279 darray = dest.pixels;
280 sarray = src.pixels;
281 swidth = src.width;
282 sheight = src.height;
283 dwidth = dest.width;
284 dheight = dest.height;
286 void copy(size_t didx, size_t sidx)
288 uint16_t c = sarray[sidx];
289 if(darray[didx] < c)
290 darray[didx] = c;
292 size_t swidth, sheight, dwidth, dheight;
293 private:
294 uint16_t* sarray;
295 uint16_t* darray;
298 enum porterduff_oper
300 PD_SRC,
301 PD_ATOP,
302 PD_OVER,
303 PD_IN,
304 PD_OUT,
305 PD_DEST,
306 PD_DEST_ATOP,
307 PD_DEST_OVER,
308 PD_DEST_IN,
309 PD_DEST_OUT,
310 PD_CLEAR,
311 PD_XOR
314 porterduff_oper get_pd_oper(const std::string& oper)
316 if(oper == "Src") return PD_SRC;
317 if(oper == "Atop") return PD_ATOP;
318 if(oper == "Over") return PD_OVER;
319 if(oper == "In") return PD_IN;
320 if(oper == "Out") return PD_OUT;
321 if(oper == "Dest") return PD_DEST;
322 if(oper == "DestAtop") return PD_DEST_ATOP;
323 if(oper == "DestOver") return PD_DEST_OVER;
324 if(oper == "DestIn") return PD_DEST_IN;
325 if(oper == "DestOut") return PD_DEST_OUT;
326 if(oper == "Clear") return PD_CLEAR;
327 if(oper == "Xor") return PD_XOR;
328 (stringfmt() << "Bad Porter-Duff operator '" << oper << "'").throwex();
329 return PD_SRC; //NOTREACHED
332 template<porterduff_oper oper, class _src, class _dest> struct srcdest_porterduff
334 srcdest_porterduff(_dest Xdest, _src Xsrc)
335 : dest(Xdest), src(Xsrc)
337 swidth = src.get_width();
338 sheight = src.get_height();
339 dwidth = dest.get_width();
340 dheight = dest.get_height();
342 void copy(size_t didx, size_t sidx)
344 typename _dest::rpixel_t vd = dest.read(didx);
345 typename _src::rpixel_t vs = src.read(sidx);
346 bool od = dest.is_opaque(vd);
347 bool os = src.is_opaque(vs);
348 typename _dest::pixel_t ld = dest.lookup(vd);
349 typename _src::pixel_t ls = src.lookup(vs);
350 typename _dest::pixel_t t = dest.transparent();
351 typename _dest::pixel_t r;
352 switch(oper) {
353 case PD_SRC: r = ls; break;
354 case PD_ATOP: r = od ? (os ? ls : ld) : t; break;
355 case PD_OVER: r = os ? ls : ld; break;
356 case PD_IN: r = (od & os) ? ls : t; break;
357 case PD_OUT: r = (!od && os) ? ls : t; break;
358 case PD_DEST: r = ld; break;
359 case PD_DEST_ATOP: r = os ? (od ? ld : ls) : t; break;
360 case PD_DEST_OVER: r = od ? ld : ls; break;
361 case PD_DEST_IN: r = (od & os) ? ld : t; break;
362 case PD_DEST_OUT: r = (od & !os) ? ld : t; break;
363 case PD_CLEAR: r = t; break;
364 case PD_XOR: r = od ? (os ? t : ld) : ls; break;
366 dest.write(didx, r);
368 size_t swidth, sheight, dwidth, dheight;
369 private:
370 _dest dest;
371 _src src;
374 template<porterduff_oper oper, class _src, class _dest> srcdest_porterduff<oper, _src, _dest>
375 mk_porterduff(_dest dest, _src src)
377 return srcdest_porterduff<oper, _src, _dest>(dest, src);
380 template<class srcdest>
381 void xblit_copy(srcdest sd, uint32_t dx, uint32_t dy, uint32_t sx, uint32_t sy, uint32_t w, uint32_t h)
383 while((dx + w > sd.dwidth || sx + w > sd.swidth) && w > 0)
384 w--;
385 while((dy + h > sd.dheight || sy + h > sd.sheight) && h > 0)
386 h--;
387 if(dx + w < w || dy + h < h) return; //Don't do overflowing blits.
388 if(sx + w < w || sy + h < h) return; //Don't do overflowing blits.
389 size_t sidx = sy * sd.swidth + sx;
390 size_t didx = dy * sd.dwidth + dx;
391 size_t srskip = sd.swidth - w;
392 size_t drskip = sd.dwidth - w;
393 for(uint32_t j = 0; j < h; j++) {
394 for(uint32_t i = 0; i < w; i++) {
395 sd.copy(didx, sidx);
396 sidx++;
397 didx++;
399 sidx += srskip;
400 didx += drskip;
404 template<class srcdest>
405 void xblit_scaled(srcdest sd, uint32_t dx, uint32_t dy, uint32_t sx, uint32_t sy, uint32_t w, uint32_t h,
406 uint32_t hscl, uint32_t vscl)
408 if(!hscl || !vscl) return;
409 w = max(static_cast<uint32_t>(sd.dwidth / hscl), w);
410 h = max(static_cast<uint32_t>(sd.dheight / vscl), h);
411 while((dx + hscl * w > sd.dwidth || sx + w > sd.swidth) && w > 0)
412 w--;
413 while((dy + vscl * h > sd.dheight || sy + h > sd.sheight) && h > 0)
414 h--;
415 if(dx + hscl * w < dx || dy + vscl * h < dy) return; //Don't do overflowing blits.
416 if(sx + w < w || sy + h < h) return; //Don't do overflowing blits.
417 size_t sidx = sy * sd.swidth + sx;
418 size_t didx = dy * sd.dwidth + dx;
419 size_t drskip = sd.dwidth - hscl * w;
420 uint32_t _w = hscl * w;
421 for(uint32_t j = 0; j < vscl * h; j++) {
422 uint32_t _sidx = sidx;
423 for(uint32_t i = 0; i < _w ; i += hscl) {
424 for(uint32_t k = 0; k < hscl; k++)
425 sd.copy(didx + k, _sidx);
426 _sidx++;
427 didx+=hscl;
429 if((j % vscl) == vscl - 1)
430 sidx += sd.swidth;
431 didx += drskip;
435 template<bool scaled, class srcdest>
436 inline void xblit(srcdest sd, uint32_t dx, uint32_t dy, uint32_t sx, uint32_t sy, uint32_t w, uint32_t h,
437 uint32_t hscl, uint32_t vscl)
439 if(scaled)
440 xblit_scaled(sd, dx, dy, sx, sy, w, h, hscl, vscl);
441 else
442 xblit_copy(sd, dx, dy, sx, sy, w, h);
445 template<bool scaled, class src, class dest>
446 inline void xblit_pal(dest _dest, src _src, uint64_t ck, uint32_t dx, uint32_t dy, uint32_t sx,
447 uint32_t sy, uint32_t w, uint32_t h, uint32_t hscl, uint32_t vscl)
449 if(ck > 65535)
450 xblit<scaled>(mk_srcdest(_dest, _src, colorkey_none()), dx, dy, sx, sy, w, h,
451 hscl, vscl);
452 else
453 xblit<scaled>(mk_srcdest(_dest, _src, colorkey_palette(ck)), dx, dy, sx, sy, w, h,
454 hscl, vscl);
457 template<bool scaled, class src, class dest>
458 inline void xblit_dir(dest _dest, src _src, uint64_t ck, uint32_t dx, uint32_t dy, uint32_t sx,
459 uint32_t sy, uint32_t w, uint32_t h, uint32_t hscl, uint32_t vscl)
461 if(ck == 0x100000000ULL)
462 xblit<scaled>(mk_srcdest(_dest, _src, colorkey_none()), dx, dy, sx, sy, w, h,
463 hscl, vscl);
464 else
465 xblit<scaled>(mk_srcdest(_dest, _src, colorkey_direct(ck)), dx, dy, sx, sy, w, h,
466 hscl, vscl);
469 template<bool scaled, porterduff_oper oper, class src, class dest>
470 inline void xblit_pduff2(dest _dest, src _src, uint32_t dx, uint32_t dy, uint32_t sx,
471 uint32_t sy, uint32_t w, uint32_t h, uint32_t hscl, uint32_t vscl)
473 xblit<scaled>(mk_porterduff<oper>(_dest, _src), dx, dy, sx, sy, w, h, hscl, vscl);
476 template<bool scaled, class src, class dest>
477 inline void xblit_pduff(dest _dest, src _src, uint32_t dx, uint32_t dy, uint32_t sx,
478 uint32_t sy, uint32_t w, uint32_t h, uint32_t hscl, uint32_t vscl, porterduff_oper oper)
480 switch(oper) {
481 case PD_ATOP:
482 xblit_pduff2<scaled, PD_ATOP>(_dest, _src, dx, dy, sx, sy, w, h, hscl, vscl);
483 break;
484 case PD_CLEAR:
485 xblit_pduff2<scaled, PD_CLEAR>(_dest, _src, dx, dy, sx, sy, w, h, hscl, vscl);
486 break;
487 case PD_DEST:
488 xblit_pduff2<scaled, PD_DEST>(_dest, _src, dx, dy, sx, sy, w, h, hscl, vscl);
489 break;
490 case PD_DEST_ATOP:
491 xblit_pduff2<scaled, PD_DEST_ATOP>(_dest, _src, dx, dy, sx, sy, w, h, hscl, vscl);
492 break;
493 case PD_DEST_IN:
494 xblit_pduff2<scaled, PD_DEST_IN>(_dest, _src, dx, dy, sx, sy, w, h, hscl, vscl);
495 break;
496 case PD_DEST_OUT:
497 xblit_pduff2<scaled, PD_DEST_OUT>(_dest, _src, dx, dy, sx, sy, w, h, hscl, vscl);
498 break;
499 case PD_DEST_OVER:
500 xblit_pduff2<scaled, PD_DEST_OVER>(_dest, _src, dx, dy, sx, sy, w, h, hscl, vscl);
501 break;
502 case PD_IN:
503 xblit_pduff2<scaled, PD_IN>(_dest, _src, dx, dy, sx, sy, w, h, hscl, vscl);
504 break;
505 case PD_OUT:
506 xblit_pduff2<scaled, PD_OUT>(_dest, _src, dx, dy, sx, sy, w, h, hscl, vscl);
507 break;
508 case PD_OVER:
509 xblit_pduff2<scaled, PD_OVER>(_dest, _src, dx, dy, sx, sy, w, h, hscl, vscl);
510 break;
511 case PD_SRC:
512 xblit_pduff2<scaled, PD_SRC>(_dest, _src, dx, dy, sx, sy, w, h, hscl, vscl);
513 break;
514 case PD_XOR:
515 xblit_pduff2<scaled, PD_XOR>(_dest, _src, dx, dy, sx, sy, w, h, hscl, vscl);
516 break;
520 int bitmap_load_fn(lua::state& L, std::function<lua_loaded_bitmap()> src)
522 auto bitmap = src();
523 if(bitmap.d) {
524 lua_dbitmap* b = lua::_class<lua_dbitmap>::create(L, bitmap.w, bitmap.h);
525 for(size_t i = 0; i < bitmap.w * bitmap.h; i++)
526 b->pixels[i] = framebuffer::color(bitmap.bitmap[i]);
527 return 1;
528 } else {
529 lua_bitmap* b = lua::_class<lua_bitmap>::create(L, bitmap.w, bitmap.h);
530 lua_palette* p = lua::_class<lua_palette>::create(L);
531 for(size_t i = 0; i < bitmap.w * bitmap.h; i++)
532 b->pixels[i] = bitmap.bitmap[i];
533 p->adjust_palette_size(bitmap.palette.size());
534 for(size_t i = 0; i < bitmap.palette.size(); i++)
535 p->colors[i] = framebuffer::color(bitmap.palette[i]);
536 return 2;
540 //Similar as _sample_texture(), but for the s=2^n, n integer special case.
541 template<typename pixel>
542 inline void _sample_texture_log2(pixel* dest, uint32_t dwidth, uint32_t dheight, pixel* source,
543 uint32_t swidth, uint32_t sheight, int32_t xx, int32_t xy, int32_t x0, int32_t yx, int32_t yy,
544 int32_t y0, int32_t log2s, bool wrap, pixel transparent)
546 uint32_t th = (1 << log2s) >> 1; //Two shifts, as log2s=0 should give th=0.
547 uint32_t fsmask = (1u << log2s) - 1;
548 uint64_t bias = 1ull << (31 + log2s);
549 size_t didx = 0;
550 for(int32_t i = 0; i < (int32_t)dheight; i++) {
551 uint64_t ssx = (int64_t)xy * i + (int64_t)x0 + bias;
552 uint64_t ssy = (int64_t)yy * i + (int64_t)y0 + bias;
553 for(int32_t j = 0; j < (int32_t)dwidth; j++) {
554 //Compute whole and fractional parts.
555 uint32_t _isx = ssx >> log2s;
556 uint32_t fsx = ssx & fsmask;
557 uint32_t _isy = ssy >> log2s;
558 uint32_t fsy = ssy & fsmask;
559 //The above always give positive fractional parts.
560 //Round the whole parts.
561 _isx += fsx > th;
562 _isy += fsy > th;
563 //Remove biases.
564 int32_t isx = _isx - (1u << 31);
565 int32_t isy = _isy - (1u << 31);
566 //Compute color.
567 pixel p = transparent;
568 if(wrap) {
569 isx = isx % swidth;
570 if(isx < 0) isx += swidth;
571 isy = isy % sheight;
572 if(isy < 0) isy += sheight;
573 p = source[isy * swidth + isx];
574 } else if(isx >= 0 && isx < (int32_t)swidth && isy >= 0 && isy < (int32_t)sheight) {
575 p = source[isy * swidth + isx];
577 dest[didx] = p;
578 //Update values for next pixel.
579 ssx += (int64_t)xx;
580 ssy += (int64_t)yx;
581 didx++;
586 template<typename pixel>
587 inline void _sample_texture(pixel* dest, uint32_t dwidth, uint32_t dheight, pixel* source, uint32_t swidth,
588 uint32_t sheight, int32_t xx, int32_t xy, int32_t x0, int32_t yx, int32_t yy, int32_t y0, uint32_t s,
589 bool wrap, pixel transparent)
591 if((s & (s - 1)) == 0) {
592 //S is power of two. Compute the logarithm.
593 uint32_t log2s = 0;
594 while(s > 1) {
595 log2s++;
596 s >>= 1;
598 return _sample_texture_log2(dest, dwidth, dheight, source, swidth, sheight, xx, xy, x0, yx,
599 yy, y0, log2s, wrap, transparent);
601 int32_t th = s / 2;
602 size_t didx = 0;
603 for(int32_t i = 0; i < (int32_t)dheight; i++) {
604 int64_t ssx = (int64_t)xy * i + (int64_t)x0;
605 int64_t ssy = (int64_t)yy * i + (int64_t)y0;
606 for(int32_t j = 0; j < (int32_t)dwidth; j++) {
607 //Compute whole and fractional parts.
608 int64_t isx = ssx / (int32_t)s;
609 int32_t fsx = ssx % (int32_t)s;
610 int64_t isy = ssy / (int32_t)s;
611 int32_t fsy = ssy % (int32_t)s;
612 //Make the fractional parts always positive.
613 if(fsx < 0) { fsx += s; isx--; }
614 if(fsy < 0) { fsy += s; isy--; }
615 //Round the whole parts.
616 isx += fsx > th;
617 isy += fsy > th;
618 //Compute color.
619 pixel p = transparent;
620 if(wrap) {
621 isx = isx % swidth;
622 if(isx < 0) isx += swidth;
623 isy = isy % sheight;
624 if(isy < 0) isy += sheight;
625 p = source[isy * swidth + isx];
626 } else if(isx >= 0 && isx < (int32_t)swidth && isy >= 0 && isy < (int32_t)sheight) {
627 p = source[isy * swidth + isx];
629 dest[didx] = p;
630 //Update values for next pixel.
631 ssx += (int64_t)xx;
632 ssy += (int64_t)yx;
633 didx++;
638 template<typename pixel>
639 inline int _hflip(pixel* pixels, uint32_t width, uint32_t height)
641 uint32_t w = width, h = height;
643 for (uint32_t x = 0; x < w/2; x++) {
644 for (uint32_t y = 0; y < h; y++) {
645 std::swap(pixels[y * w + x], pixels[(y + 1) * w - x - 1]);
648 return 0;
651 template<typename pixel>
652 inline int _vflip(pixel* pixels, uint32_t width, uint32_t height)
654 uint32_t w = width, h = height;
656 for (uint32_t x = 0; x < w; x++) {
657 for (uint32_t y = 0; y < h/2; y++) {
658 std::swap(pixels[y * w + x], pixels[(h - y - 1) * w + x]);
661 return 0;
665 inline int64_t mangle_color(uint32_t c)
667 if(c < 0x1000000)
668 return -1;
669 else
670 return ((256 - (c >> 24) - (c >> 31)) << 24) | (c & 0xFFFFFF);
673 int base64val(char ch)
675 if(ch >= 'A' && ch <= 'Z')
676 return ch - 65;
677 if(ch >= 'a' && ch <= 'z')
678 return ch - 97 + 26;
679 if(ch >= '0' && ch <= '9')
680 return ch - 48 + 52;
681 if(ch == '+')
682 return 62;
683 if(ch == '/')
684 return 63;
685 if(ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n')
686 return -1;
687 if(ch == '=')
688 return -2;
689 return -3;
692 std::string base64_encode(const std::string& str)
694 std::ostringstream x;
695 unsigned pos = 0;
696 uint32_t mem = 0;
697 for(auto i : str) {
698 mem = (mem << 8) + (unsigned char)i;
699 if(++pos == 3) {
700 uint8_t c1 = (mem >> 18) & 0x3F;
701 uint8_t c2 = (mem >> 12) & 0x3F;
702 uint8_t c3 = (mem >> 6) & 0x3F;
703 uint8_t c4 = mem & 0x3F;
704 x << CONST_base64chars[c1];
705 x << CONST_base64chars[c2];
706 x << CONST_base64chars[c3];
707 x << CONST_base64chars[c4];
708 mem = 0;
709 pos = 0;
712 if(pos == 2) {
713 uint8_t c1 = (mem >> 10) & 0x3F;
714 uint8_t c2 = (mem >> 4) & 0x3F;
715 uint8_t c3 = (mem << 2) & 0x3F;
716 x << CONST_base64chars[c1];
717 x << CONST_base64chars[c2];
718 x << CONST_base64chars[c3];
719 x << "=";
721 if(pos == 1) {
722 uint8_t c1 = (mem >> 2) & 0x3F;
723 uint8_t c2 = (mem << 4) & 0x3F;
724 x << CONST_base64chars[c1];
725 x << CONST_base64chars[c2];
726 x << "==";
728 return x.str();
731 std::string base64_decode(const std::string& str)
733 bool end = 0;
734 uint32_t memory = 0;
735 uint32_t memsize = 1;
736 int posmod = 0;
737 std::ostringstream x;
738 for(auto i : str) {
739 int v = base64val(i);
740 if(v == -1)
741 continue;
742 posmod = (posmod + 1) & 3;
743 if(v == -2 && (posmod == 1 || posmod == 2))
744 throw std::runtime_error("Invalid Base64");
745 if(v == -2) {
746 end = true;
747 continue;
749 if(v == -3 || end)
750 throw std::runtime_error("Invalid Base64");
751 memory = memory * 64 + v;
752 memsize = memsize * 64;
753 if(memsize >= 256) {
754 memsize >>= 8;
755 x << static_cast<uint8_t>(memory / memsize);
756 memory %= memsize;
759 return x.str();
762 template<typename T>
763 int bitmap_load_png_fn(lua::state& L, T& src)
765 png::decoder img(src);
766 if(img.has_palette) {
767 lua_bitmap* b = lua::_class<lua_bitmap>::create(L, img.width, img.height);
768 lua_palette* p = lua::_class<lua_palette>::create(L);
769 for(size_t i = 0; i < img.width * img.height; i++)
770 b->pixels[i] = img.data[i];
771 p->adjust_palette_size(img.palette.size());
772 for(size_t i = 0; i < img.palette.size(); i++)
773 p->colors[i] = framebuffer::color(mangle_color(img.palette[i]));
774 return 2;
775 } else {
776 lua_dbitmap* b = lua::_class<lua_dbitmap>::create(L, img.width, img.height);
777 for(size_t i = 0; i < img.width * img.height; i++)
778 b->pixels[i] = framebuffer::color(mangle_color(img.data[i]));
779 return 1;
783 int bitmap_palette_fn(lua::state& L, std::istream& s)
785 lua_palette* p = lua::_class<lua_palette>::create(L);
786 while(s) {
787 std::string line;
788 std::getline(s, line);
789 istrip_CR(line);
790 regex_results r;
791 if(!regex_match("[ \t]*(#.*)?", line)) {
792 //Nothing.
793 } else if(r = regex("[ \t]*([0-9]+)[ \t]+([0-9]+)[ \t]+([0-9]+)[ \t]+([0-9]+)[ \t]*", line)) {
794 int64_t cr, cg, cb, ca;
795 cr = parse_value<uint8_t>(r[1]);
796 cg = parse_value<uint8_t>(r[2]);
797 cb = parse_value<uint8_t>(r[3]);
798 ca = 256 - parse_value<uint16_t>(r[4]);
799 if(ca == 256)
800 p->push_back(framebuffer::color(-1));
801 else
802 p->push_back(framebuffer::color((ca << 24) | (cr << 16)
803 | (cg << 8) | cb));
804 } else if(r = regex("[ \t]*([0-9]+)[ \t]+([0-9]+)[ \t]+([0-9]+)[ \t]*", line)) {
805 int64_t cr, cg, cb;
806 cr = parse_value<uint8_t>(r[1]);
807 cg = parse_value<uint8_t>(r[2]);
808 cb = parse_value<uint8_t>(r[3]);
809 p->push_back(framebuffer::color((cr << 16) | (cg << 8) | cb));
810 } else if(r = regex("[ \t]*([^ \t]|[^ \t].*[^ \t])[ \t]*", line)) {
811 p->push_back(framebuffer::color(r[1]));
812 } else
813 throw std::runtime_error("Invalid line format (" + line + ")");
815 return 1;
818 inline framebuffer::color tadjust(framebuffer::color c, uint16_t adj)
820 uint32_t rgb = c.orig;
821 uint32_t a = c.origa;
822 a = (a * adj) >> 8;
823 if(a > 256)
824 a = 256;
825 if(a == 0)
826 return framebuffer::color(-1);
827 else
828 return framebuffer::color(rgb | ((uint32_t)(256 - a) << 24));
831 lua::_class<lua_loaded_bitmap> LUA_class_loaded_bitmap(lua_class_gui, "IMAGELOADER", {
832 {"load", lua_loaded_bitmap::load<false>},
833 {"load_str", lua_loaded_bitmap::load_str<false>},
834 {"load_png", lua_loaded_bitmap::load<true>},
835 {"load_png_str", lua_loaded_bitmap::load_str<true>},
838 lua::_class<lua_palette> LUA_class_palette(lua_class_gui, "PALETTE", {
839 {"new", lua_palette::create},
840 {"load", lua_palette::load},
841 {"load_str", lua_palette::load_str},
842 }, {
843 {"set", &lua_palette::set},
844 {"get", &lua_palette::get},
845 {"hash", &lua_palette::hash},
846 {"debug", &lua_palette::debug},
847 {"adjust_transparency", &lua_palette::adjust_transparency},
848 }, &lua_palette::print);
850 lua::_class<lua_bitmap> LUA_class_bitmap(lua_class_gui, "BITMAP", {
851 {"new", lua_bitmap::create},
852 }, {
853 {"draw", &lua_bitmap::draw<false, false>},
854 {"draw_clip", &lua_bitmap::draw<false, true>},
855 {"draw_outside", &lua_bitmap::draw<true, false>},
856 {"draw_clip_outside", &lua_bitmap::draw<true, true>},
857 {"pset", &lua_bitmap::pset},
858 {"pget", &lua_bitmap::pget},
859 {"size", &lua_bitmap::size},
860 {"hflip", &lua_bitmap::hflip},
861 {"vflip", &lua_bitmap::vflip},
862 {"hash", &lua_bitmap::hash},
863 {"blit", &lua_bitmap::blit<false, false>},
864 {"blit_priority", &lua_bitmap::blit_priority<false>},
865 {"blit_scaled", &lua_bitmap::blit<true, false>},
866 {"blit_scaled_priority", &lua_bitmap::blit_priority<true>},
867 {"blit_porterduff", &lua_bitmap::blit<false, true>},
868 {"blit_scaled_porterduff", &lua_bitmap::blit<true, true>},
869 {"save_png", &lua_bitmap::save_png},
870 {"sample_texture", &lua_bitmap::sample_texture},
871 }, &lua_bitmap::print);
873 lua::_class<lua_dbitmap> LUA_class_dbitmap(lua_class_gui, "DBITMAP", {
874 {"new", lua_dbitmap::create},
875 }, {
876 {"draw", &lua_dbitmap::draw<false, false>},
877 {"draw_clip", &lua_dbitmap::draw<false, true>},
878 {"draw_outside", &lua_dbitmap::draw<true, false>},
879 {"draw_clip_outside", &lua_dbitmap::draw<true, true>},
880 {"pset", &lua_dbitmap::pset},
881 {"pget", &lua_dbitmap::pget},
882 {"size", &lua_dbitmap::size},
883 {"hflip", &lua_dbitmap::hflip},
884 {"vflip", &lua_dbitmap::vflip},
885 {"hash", &lua_dbitmap::hash},
886 {"blit", &lua_dbitmap::blit<false, false>},
887 {"blit_scaled", &lua_dbitmap::blit<true, false>},
888 {"blit_porterduff", &lua_dbitmap::blit<false, true>},
889 {"blit_scaled_porterduff", &lua_dbitmap::blit<true, true>},
890 {"save_png", &lua_dbitmap::save_png},
891 {"adjust_transparency", &lua_dbitmap::adjust_transparency},
892 {"sample_texture", &lua_dbitmap::sample_texture},
893 }, &lua_dbitmap::print);
896 /** Palette **/
897 lua_palette::lua_palette(lua::state& L)
899 color_count = 0;
900 scolors = colors = lua::align_overcommit<lua_palette, framebuffer::color>(this);
901 for(unsigned i = 0; i < reserved_colors; i++)
902 scolors[i] = framebuffer::color(-1);
905 lua_palette::~lua_palette()
907 CORE().fbuf->render_kill_request(this);
910 std::string lua_palette::print()
912 size_t s = color_count;
913 return (stringfmt() << s << " " << ((s != 1) ? "colors" : "color")).str();
916 int lua_palette::create(lua::state& L, lua::parameters& P)
918 lua::_class<lua_palette>::create(L);
919 return 1;
922 int lua_palette::load(lua::state& L, lua::parameters& P)
924 std::string name, name2;
926 P(name, P.optional(name2, ""));
928 std::istream& s = zip::openrel(name, name2);
929 try {
930 int r = bitmap_palette_fn(L, s);
931 delete &s;
932 return r;
933 } catch(...) {
934 delete &s;
935 throw;
939 int lua_palette::load_str(lua::state& L, lua::parameters& P)
941 std::string content;
943 P(content);
945 std::istringstream s(content);
946 return bitmap_palette_fn(L, s);
949 int lua_palette::set(lua::state& L, lua::parameters& P)
951 framebuffer::color nc;
952 uint16_t c;
954 P(P.skipped(), c, nc);
956 if(this->color_count <= c) {
957 this->adjust_palette_size(static_cast<uint32_t>(c) + 1);
959 this->colors[c] = nc;
960 return 0;
963 int lua_palette::get(lua::state& L, lua::parameters& P)
965 framebuffer::color nc;
966 uint16_t c;
967 int64_t _nc;
969 P(P.skipped(), c);
971 if(this->color_count <= c) {
972 return 0;
974 nc = this->colors[c];
975 uint32_t rgb = nc.orig;
976 uint32_t a = nc.origa;
977 if(a == 0)
978 _nc = -1;
979 else
980 _nc = ((256 - a) << 24) | rgb;
981 L.pushnumber(_nc);
982 return 1;
985 int lua_palette::hash(lua::state& L, lua::parameters& P)
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->color_count; 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, lua::parameters& P)
1010 for(size_t i = 0; i < color_count; i++)
1011 messages << "Color #" << i << ": " << colors[i].orig << ":" << colors[i].origa << std::endl;
1012 return 0;
1015 int lua_palette::adjust_transparency(lua::state& L, lua::parameters& P)
1017 uint16_t tadj;
1019 P(P.skipped(), tadj);
1021 for(size_t i = 0; i < color_count; i++)
1022 colors[i] = tadjust(colors[i], tadj);
1023 return 0;
1026 void lua_palette::adjust_palette_size(size_t newsize)
1028 threads::alock h(palette_mutex);
1029 if(newsize > reserved_colors) {
1030 lcolors.resize(newsize);
1031 if(color_count <= reserved_colors) {
1032 for(unsigned i = 0; i < color_count; i++)
1033 lcolors[i] = colors[i];
1035 colors = &lcolors[0];
1036 } else {
1037 if(color_count > reserved_colors) {
1038 for(unsigned i = 0; i < color_count; i++)
1039 scolors[i] = lcolors[i];
1041 colors = scolors;
1043 color_count = newsize;
1046 void lua_palette::push_back(const framebuffer::color& cx)
1048 size_t c = color_count;
1049 adjust_palette_size(c + 1);
1050 colors[c] = cx;
1053 /** BITMAP **/
1054 lua_bitmap::lua_bitmap(lua::state& L, uint32_t w, uint32_t h)
1056 if(h > 0 && overcommit(w, h) / h / sizeof(uint16_t) < w) throw std::bad_alloc();
1057 width = w;
1058 height = h;
1059 pixels = lua::align_overcommit<lua_bitmap, uint16_t>(this);
1060 memset(pixels, 0, 2 * width * height);
1063 lua_bitmap::~lua_bitmap()
1065 CORE().fbuf->render_kill_request(this);
1068 std::string lua_bitmap::print()
1070 return (stringfmt() << width << "*" << height).str();
1073 int lua_bitmap::create(lua::state& L, lua::parameters& P)
1075 uint32_t w, h;
1076 uint16_t c;
1078 P(w, h, P.optional(c, 0));
1080 lua_bitmap* b = lua::_class<lua_bitmap>::create(L, w, h);
1081 for(size_t i = 0; i < b->width * b->height; i++)
1082 b->pixels[i] = c;
1083 return 1;
1086 template<bool outside, bool clip>
1087 int lua_bitmap::draw(lua::state& L, lua::parameters& P)
1089 auto& core = CORE();
1090 int32_t x, y;
1091 lua::objpin<lua_bitmap> b;
1092 lua::objpin<lua_palette> p;
1094 if(!core.lua2->render_ctx) return 0;
1096 P(b, x, y, p);
1098 int32_t x0 = 0, y0 = 0, dw = b->width, dh = b->height;
1099 if(clip) P(x0, y0, dw, dh);
1101 core.lua2->render_ctx->queue->create_add<render_object_bitmap>(x, y, b, p, x0, y0, dw, dh, outside);
1102 return 0;
1105 int lua_bitmap::pset(lua::state& L, lua::parameters& P)
1107 uint32_t x, y;
1108 uint16_t c;
1110 P(P.skipped(), x, y, c);
1112 if(x >= this->width || y >= this->height)
1113 return 0;
1114 this->pixels[y * this->width + x] = c;
1115 return 0;
1118 int lua_bitmap::pget(lua::state& L, lua::parameters& P)
1120 uint32_t x, y;
1122 P(P.skipped(), x, y);
1124 if(x >= this->width || y >= this->height)
1125 return 0;
1126 L.pushnumber(this->pixels[y * this->width + x]);
1127 return 1;
1130 int lua_bitmap::size(lua::state& L, lua::parameters& P)
1132 L.pushnumber(this->width);
1133 L.pushnumber(this->height);
1134 return 2;
1137 int lua_bitmap::hflip(lua::state& L, lua::parameters& P)
1139 return _hflip(pixels, width, height);
1142 int lua_bitmap::vflip(lua::state& L, lua::parameters& P)
1144 return _vflip(pixels, width, height);
1147 int lua_bitmap::hash(lua::state& L, lua::parameters& P)
1149 sha256 h;
1150 const int buffersize = 256;
1151 int bufferuse = 0;
1152 char buf[buffersize];
1153 memset(buf, 0, buffersize);
1154 serialization::u64b(buf + 0, this->width);
1155 serialization::u64b(buf + 8, this->height);
1156 bufferuse = 16;
1157 for(unsigned i = 0; i < this->width * this->height; i++) {
1158 if(bufferuse + 2 > buffersize) {
1159 h.write(buf, bufferuse);
1160 bufferuse = 0;
1162 serialization::u16b(buf + bufferuse + 0, this->pixels[i]);
1163 bufferuse += 2;
1165 if(bufferuse > 0) h.write(buf, bufferuse);
1166 L.pushlstring(h.read());
1167 return 1;
1170 template<bool scaled, bool porterduff> int lua_bitmap::blit(lua::state& L, lua::parameters& P)
1172 uint32_t dx, dy, sx, sy, w, h, hscl, vscl;
1173 lua_bitmap* src_p;
1175 P(P.skipped(), dx, dy, src_p, sx, sy, w, h);
1176 if(scaled)
1177 P(hscl, P.optional2(vscl, hscl));
1179 if(porterduff) {
1180 porterduff_oper pd_oper = get_pd_oper(P.arg<std::string>());
1181 xblit_pduff<scaled>(operand_bitmap(*this), operand_bitmap(*src_p), dx, dy, sx, sy, w, h, hscl, vscl,
1182 pd_oper);
1183 } else {
1184 int64_t ck = P.arg_opt<uint64_t>(65536);
1185 xblit_pal<scaled>(operand_bitmap(*this), operand_bitmap(*src_p), ck, dx, dy, sx, sy, w, h,
1186 hscl, vscl);
1188 return 0;
1191 template<bool scaled> int lua_bitmap::blit_priority(lua::state& L, lua::parameters& P)
1193 uint32_t dx, dy, sx, sy, w, h, hscl, vscl;
1194 lua_bitmap* src_p;
1196 P(P.skipped(), dx, dy, src_p, sx, sy, w, h);
1197 if(scaled)
1198 P(hscl, P.optional2(vscl, hscl));
1200 xblit<scaled>(srcdest_priority(*this, *src_p), dx, dy, sx, sy, w, h, hscl, vscl);
1201 return 0;
1204 int lua_bitmap::save_png(lua::state& L, lua::parameters& P)
1206 std::string name, name2;
1207 lua_palette* p;
1208 bool was_filename;
1210 P(P.skipped());
1211 if((was_filename = P.is_string())) P(name);
1212 if(P.is_string()) P(name2);
1213 P(p);
1215 auto buf = this->save_png(*p);
1216 if(was_filename) {
1217 std::string filename = zip::resolverel(name, name2);
1218 std::ofstream strm(filename, std::ios::binary);
1219 if(!strm)
1220 throw std::runtime_error("Can't open output file");
1221 strm.write(&buf[0], buf.size());
1222 if(!strm)
1223 throw std::runtime_error("Can't write output file");
1224 return 0;
1225 } else {
1226 std::ostringstream strm;
1227 strm.write(&buf[0], buf.size());
1228 L.pushlstring(base64_encode(strm.str()));
1229 return 1;
1233 int lua_bitmap::sample_texture(lua::state& L, lua::parameters& P)
1235 lua_bitmap* src_p;
1236 int32_t xx, xy, yx, yy, x0, y0;
1237 uint32_t s;
1238 bool wrap;
1239 uint16_t trans = 0;
1241 P(P.skipped(), src_p, xx, xy, x0, yx, yy, y0, s, wrap);
1243 _sample_texture(pixels, width, height, src_p->pixels, src_p->width, src_p->height, xx, xy, x0, yx, yy, y0,
1244 s, wrap, trans);
1245 return 0;
1248 /** DBITMAP **/
1249 lua_dbitmap::lua_dbitmap(lua::state& L, uint32_t w, uint32_t h)
1251 if(h > 0 && overcommit(w, h) / h / sizeof(framebuffer::color) < w) throw std::bad_alloc();
1252 width = w;
1253 height = h;
1254 pixels = lua::align_overcommit<lua_dbitmap, framebuffer::color>(this);
1255 //Initialize the bitmap data.
1256 framebuffer::color transparent(-1);
1257 for(size_t i = 0; i < (size_t)width * height; i++)
1258 new(pixels + i) framebuffer::color(transparent);
1261 lua_dbitmap::~lua_dbitmap()
1263 CORE().fbuf->render_kill_request(this);
1266 std::string lua_dbitmap::print()
1268 return (stringfmt() << width << "*" << height).str();
1271 int lua_dbitmap::create(lua::state& L, lua::parameters& P)
1273 uint32_t w, h;
1274 framebuffer::color c;
1276 P(w, h, P.optional(c, -1));
1278 lua_dbitmap* b = lua::_class<lua_dbitmap>::create(L, w, h);
1279 for(size_t i = 0; i < b->width * b->height; i++)
1280 b->pixels[i] = c;
1281 return 1;
1284 template<bool outside, bool clip>
1285 int lua_dbitmap::draw(lua::state& L, lua::parameters& P)
1287 auto& core = CORE();
1288 int32_t x, y;
1289 lua::objpin<lua_dbitmap> b;
1291 if(!core.lua2->render_ctx) return 0;
1293 P(b, x, y);
1295 int32_t x0 = 0, y0 = 0, dw = b->width, dh = b->height;
1296 if(clip) P(x0, y0, dw, dh);
1298 core.lua2->render_ctx->queue->create_add<render_object_bitmap>(x, y, b, x0, y0, dw, dh, outside);
1299 return 0;
1302 int lua_dbitmap::pset(lua::state& L, lua::parameters& P)
1304 uint32_t x, y;
1305 framebuffer::color c;
1307 P(P.skipped(), x, y, c);
1309 if(x >= this->width || y >= this->height)
1310 return 0;
1311 this->pixels[y * this->width + x] = c;
1312 return 0;
1315 int lua_dbitmap::pget(lua::state& L, lua::parameters& P)
1317 uint32_t x, y;
1319 P(P.skipped(), x, y);
1321 if(x >= this->width || y >= this->height)
1322 return 0;
1323 L.pushnumber((this->pixels[y * this->width + x]).asnumber());
1324 return 1;
1327 int lua_dbitmap::size(lua::state& L, lua::parameters& P)
1329 L.pushnumber(this->width);
1330 L.pushnumber(this->height);
1331 return 2;
1334 int lua_dbitmap::hflip(lua::state& L, lua::parameters& P)
1336 return _hflip(pixels, width, height);
1339 int lua_dbitmap::vflip(lua::state& L, lua::parameters& P)
1341 return _vflip(pixels, width, height);
1344 int lua_dbitmap::hash(lua::state& L, lua::parameters& P)
1346 sha256 h;
1347 const int buffersize = 256;
1348 int bufferuse = 0;
1349 char buf[buffersize];
1350 memset(buf, 0, buffersize);
1351 serialization::u64b(buf + 0, this->width);
1352 serialization::u64b(buf + 4, this->height);
1353 bufferuse = 16;
1354 for(unsigned i = 0; i < this->width * this->height; i++) {
1355 if(bufferuse + 6 > buffersize) {
1356 h.write(buf, bufferuse);
1357 bufferuse = 0;
1359 serialization::u32b(buf + bufferuse + 0, this->pixels[i].orig);
1360 serialization::u16b(buf + bufferuse + 4, this->pixels[i].origa);
1361 bufferuse += 6;
1363 if(bufferuse > 0) h.write(buf, bufferuse);
1364 L.pushlstring(h.read());
1365 return 1;
1368 template<bool scaled, bool porterduff> int lua_dbitmap::blit(lua::state& L, lua::parameters& P)
1370 uint32_t dx, dy, sx, sy, w, h, hscl, vscl;
1372 P(P.skipped(), dx, dy);
1374 //DBitmap or Bitmap+Palette.
1375 bool src_d = P.is<lua_dbitmap>();
1376 bool src_p = P.is<lua_bitmap>();
1377 int sidx = P.skip();
1378 if(!src_d && !src_p)
1379 P.expected("BITMAP or DBITMAP", sidx);
1380 int spal = 0;
1381 if(src_p)
1382 spal = P.skip(); //Reserve for palette.
1384 P(sx, sy, w, h);
1386 if(scaled)
1387 P(hscl, P.optional2(vscl, hscl));
1389 int64_t ckx = 0x100000000ULL;
1390 porterduff_oper pd_oper;
1391 if(porterduff) {
1392 pd_oper = get_pd_oper(P.arg<std::string>());
1393 } else {
1394 //Hack: Direct-color bitmaps should take color spec, with special NONE value.
1395 if(src_p)
1396 ckx = P.arg_opt<int64_t>(0x10000);
1397 else if(P.is_novalue())
1398 ; //Do nothing.
1399 else
1400 ckx = P.arg<framebuffer::color>().asnumber();
1403 operand_dbitmap dest(*this);
1404 if(src_d) {
1405 operand_dbitmap src(*P.arg<lua_dbitmap*>(sidx));
1406 if(porterduff)
1407 xblit_pduff<scaled>(dest, src, dx, dy, sx, sy, w, h, hscl, vscl, pd_oper);
1408 else
1409 xblit_dir<scaled>(dest, src, ckx, dx, dy, sx, sy, w, h, hscl, vscl);
1410 } else if(src_p) {
1411 operand_bitmap_pal src(*P.arg<lua_bitmap*>(sidx), *P.arg<lua_palette*>(spal));
1412 if(porterduff)
1413 xblit_pduff<scaled>(dest, src, dx, dy, sx, sy, w, h, hscl, vscl, pd_oper);
1414 else
1415 xblit_pal<scaled>(dest, src, ckx, dx, dy, sx, sy, w, h, hscl, vscl);
1417 return 0;
1420 int lua_dbitmap::save_png(lua::state& L, lua::parameters& P)
1422 std::string name, name2;
1423 bool was_filename;
1425 P(P.skipped());
1426 if((was_filename = P.is_string())) P(name);
1427 if(P.is_string()) P(name2);
1429 auto buf = this->save_png();
1430 if(was_filename) {
1431 std::string filename = zip::resolverel(name, name2);
1432 std::ofstream strm(filename, std::ios::binary);
1433 if(!strm)
1434 throw std::runtime_error("Can't open output file");
1435 strm.write(&buf[0], buf.size());
1436 if(!strm)
1437 throw std::runtime_error("Can't write output file");
1438 return 0;
1439 } else {
1440 std::ostringstream strm;
1441 strm.write(&buf[0], buf.size());
1442 L.pushlstring(base64_encode(strm.str()));
1443 return 1;
1447 int lua_dbitmap::adjust_transparency(lua::state& L, lua::parameters& P)
1449 uint16_t tadj;
1451 P(P.skipped(), tadj);
1453 for(size_t i = 0; i < width * height; i++)
1454 pixels[i] = tadjust(pixels[i], tadj);
1455 return 0;
1458 int lua_dbitmap::sample_texture(lua::state& L, lua::parameters& P)
1460 lua_dbitmap* src_p;
1461 int32_t xx, xy, yx, yy, x0, y0;
1462 uint32_t s;
1463 bool wrap;
1465 P(P.skipped(), src_p, xx, xy, x0, yx, yy, y0, s, wrap);
1467 _sample_texture(pixels, width, height, src_p->pixels, src_p->width, src_p->height, xx, xy, x0, yx, yy, y0,
1468 s, wrap, framebuffer::color());
1469 return 0;
1472 template<bool png> int lua_loaded_bitmap::load(lua::state& L, lua::parameters& P)
1474 std::string name, name2;
1476 P(name, P.optional(name2, ""));
1478 if(png) {
1479 std::string filename = zip::resolverel(name, name2);
1480 return bitmap_load_png_fn(L, filename);
1481 } else
1482 return bitmap_load_fn(L, [&name, &name2]() -> lua_loaded_bitmap {
1483 std::string name3 = zip::resolverel(name, name2);
1484 return lua_loaded_bitmap::load(name3);
1488 template<bool png> int lua_loaded_bitmap::load_str(lua::state& L, lua::parameters& P)
1490 std::string contents;
1492 P(contents);
1494 if(png) {
1495 contents = base64_decode(contents);
1496 std::istringstream strm(contents);
1497 return bitmap_load_png_fn(L, strm);
1498 } else
1499 return bitmap_load_fn(L, [&contents]() -> lua_loaded_bitmap {
1500 std::istringstream strm(contents);
1501 return lua_loaded_bitmap::load(strm);