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/range.hpp"
10 #include "library/sha256.hpp"
11 #include "library/serialization.hpp"
12 #include "library/string.hpp"
13 #include "library/zip.hpp"
14 #include "lua/bitmap.hpp"
15 #include "library/threads.hpp"
19 std::vector
<char> lua_dbitmap::save_png() const
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
];
31 img
.data
[i
] = c
.orig
+ ((uint32_t)(c
.origa
- (c
.origa
>> 7) + (c
.origa
>> 8)) << 24);
33 std::ostringstream 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
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
];
55 img
.palette
[i
] = c
.orig
+ ((uint32_t)(c
.origa
- (c
.origa
>> 7) + (c
.origa
>> 8)) << 24);
57 std::ostringstream tmp1
;
59 std::string tmp2
= tmp1
.str();
60 return std::vector
<char>(tmp2
.begin(), tmp2
.end());
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()
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()
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()
111 p
->palette_mutex
.lock();
112 uint32_t oX
= x
+ scr
.get_origin_x() - x0
;
113 uint32_t oY
= y
+ scr
.get_origin_y() - y0
;
116 framebuffer::color
* palette
;
119 pallim
= p
->color_count
;
123 palette
= NULL
; //Won't be accessed.
128 range bX
= ((range::make_w(scr
.get_width()) - oX
) & range::make_w(w
) &
129 range::make_s(x0
, dw
));
130 range bY
= ((range::make_w(scr
.get_height()) - oY
) & range::make_w(h
) &
131 range::make_s(y0
, dh
));
132 range sX
= range::make_s(-x
+ x0
, scr
.get_last_blit_width());
133 range sY
= range::make_s(-y
+ y0
, scr
.get_last_blit_height());
135 for(uint32_t r
= bY
.low(); r
< bY
.high(); r
++) {
136 typename
framebuffer::fb
<T
>::element_t
* rptr
= scr
.rowptr(oY
+ r
);
137 size_t eptr
= oX
+ bX
.low();
138 uint32_t xmin
= bX
.low();
139 bool cut
= outside
&& sY
.in(r
);
140 if(cut
&& sX
.in(xmin
)) {
142 eptr
+= (sX
.high() - bX
.low());
145 for(uint32_t c
= xmin
; c
< bX
.high(); c
++, eptr
++) {
146 if(__builtin_expect(cut
&& c
== sX
.low(), 0)) {
148 if(c
>= bX
.high()) break;
151 uint16_t i
= b
->pixels
[r
* b
->width
+ c
];
153 palette
[i
].apply(rptr
[eptr
]);
156 for(uint32_t c
= xmin
; c
< bX
.high(); c
++, eptr
++) {
157 if(__builtin_expect(cut
&& c
== sX
.low(), 0)) {
159 if(c
>= bX
.high()) break;
162 b2
->pixels
[r
* b2
->width
+ c
].apply(rptr
[eptr
]);
166 p
->palette_mutex
.unlock();
168 void operator()(struct framebuffer::fb
<false>& x
) throw() { composite_op(x
); }
169 void operator()(struct framebuffer::fb
<true>& x
) throw() { composite_op(x
); }
170 void clone(framebuffer::queue
& q
) const throw(std::bad_alloc
) { q
.clone_helper(this); }
174 lua::objpin
<lua_bitmap
> b
;
175 lua::objpin
<lua_dbitmap
> b2
;
176 lua::objpin
<lua_palette
> p
;
184 struct operand_dbitmap
186 typedef framebuffer::color pixel_t
;
187 typedef framebuffer::color rpixel_t
;
188 operand_dbitmap(lua_dbitmap
& _bitmap
)
189 : bitmap(_bitmap
), _transparent(-1)
191 pixels
= bitmap
.pixels
;
193 size_t get_width() { return bitmap
.width
; }
194 size_t get_height() { return bitmap
.height
; }
195 const rpixel_t
& read(size_t idx
) { return pixels
[idx
]; }
196 const pixel_t
& lookup(const rpixel_t
& p
) { return p
; }
197 void write(size_t idx
, const pixel_t
& v
) { pixels
[idx
] = v
; }
198 bool is_opaque(const rpixel_t
& p
) { return p
.origa
> 0; }
199 const pixel_t
& transparent() { return _transparent
; }
203 framebuffer::color _transparent
;
206 struct operand_bitmap
208 typedef uint16_t pixel_t
;
209 typedef uint16_t rpixel_t
;
210 operand_bitmap(lua_bitmap
& _bitmap
)
213 pixels
= bitmap
.pixels
;
215 size_t get_width() { return bitmap
.width
; }
216 size_t get_height() { return bitmap
.height
; }
217 const rpixel_t
& read(size_t idx
) { return pixels
[idx
]; }
218 const pixel_t
& lookup(const rpixel_t
& p
) { return p
; }
219 void write(size_t idx
, const pixel_t
& v
) { pixels
[idx
] = v
; }
220 bool is_opaque(const rpixel_t
& p
) { return p
> 0; }
221 pixel_t
transparent() { return 0; }
227 struct operand_bitmap_pal
229 typedef framebuffer::color pixel_t
;
230 typedef uint16_t rpixel_t
;
231 operand_bitmap_pal(lua_bitmap
& _bitmap
, lua_palette
& _palette
)
232 : bitmap(_bitmap
), palette(_palette
), _transparent(-1)
234 pixels
= bitmap
.pixels
;
235 limit
= palette
.color_count
;
236 pal
= palette
.colors
;
238 size_t get_width() { return bitmap
.width
; }
239 size_t get_height() { return bitmap
.height
; }
240 const rpixel_t
& read(size_t idx
) { return pixels
[idx
]; }
241 const pixel_t
& lookup(const rpixel_t
& p
) { return *((p
< limit
) ? pal
+ p
: &_transparent
); }
242 bool is_opaque(const rpixel_t
& p
) { return p
> 0; }
243 const pixel_t
& transparent() { return _transparent
; }
246 lua_palette
& palette
;
248 framebuffer::color
* pal
;
250 framebuffer::color _transparent
;
255 bool iskey(uint16_t& c
) const { return false; }
256 bool iskey(framebuffer::color
& c
) const { return false; }
259 struct colorkey_direct
261 colorkey_direct(uint64_t _ck
)
263 framebuffer::color
c(_ck
);
267 bool iskey(framebuffer::color
& c
) const { return (c
.orig
== ck
&& c
.origa
== cka
); }
272 struct colorkey_palette
274 colorkey_palette(uint64_t _ck
) { ck
= _ck
; }
275 bool iskey(uint16_t& c
) const { return (c
== ck
); }
279 template<class _src
, class _dest
, class colorkey
> struct srcdest
281 srcdest(_dest Xdest
, _src Xsrc
, const colorkey
& _ckey
)
282 : dest(Xdest
), src(Xsrc
), ckey(_ckey
)
284 swidth
= src
.get_width();
285 sheight
= src
.get_height();
286 dwidth
= dest
.get_width();
287 dheight
= dest
.get_height();
289 void copy(size_t didx
, size_t sidx
)
291 typename
_src::rpixel_t c
= src
.read(sidx
);
293 dest
.write(didx
, src
.lookup(c
));
295 size_t swidth
, sheight
, dwidth
, dheight
;
302 template<class _src
, class _dest
, class colorkey
> srcdest
<_src
, _dest
, colorkey
> mk_srcdest(_dest dest
,
303 _src src
, const colorkey
& ckey
)
305 return srcdest
<_src
, _dest
, colorkey
>(dest
, src
, ckey
);
308 struct srcdest_priority
310 srcdest_priority(lua_bitmap
& dest
, lua_bitmap
& src
)
312 darray
= dest
.pixels
;
315 sheight
= src
.height
;
317 dheight
= dest
.height
;
319 void copy(size_t didx
, size_t sidx
)
321 uint16_t c
= sarray
[sidx
];
325 size_t swidth
, sheight
, dwidth
, dheight
;
347 porterduff_oper
get_pd_oper(const std::string
& oper
)
349 if(oper
== "Src") return PD_SRC
;
350 if(oper
== "Atop") return PD_ATOP
;
351 if(oper
== "Over") return PD_OVER
;
352 if(oper
== "In") return PD_IN
;
353 if(oper
== "Out") return PD_OUT
;
354 if(oper
== "Dest") return PD_DEST
;
355 if(oper
== "DestAtop") return PD_DEST_ATOP
;
356 if(oper
== "DestOver") return PD_DEST_OVER
;
357 if(oper
== "DestIn") return PD_DEST_IN
;
358 if(oper
== "DestOut") return PD_DEST_OUT
;
359 if(oper
== "Clear") return PD_CLEAR
;
360 if(oper
== "Xor") return PD_XOR
;
361 (stringfmt() << "Bad Porter-Duff operator '" << oper
<< "'").throwex();
362 return PD_SRC
; //NOTREACHED
365 template<porterduff_oper oper
, class _src
, class _dest
> struct srcdest_porterduff
367 srcdest_porterduff(_dest Xdest
, _src Xsrc
)
368 : dest(Xdest
), src(Xsrc
)
370 swidth
= src
.get_width();
371 sheight
= src
.get_height();
372 dwidth
= dest
.get_width();
373 dheight
= dest
.get_height();
375 void copy(size_t didx
, size_t sidx
)
377 typename
_dest::rpixel_t vd
= dest
.read(didx
);
378 typename
_src::rpixel_t vs
= src
.read(sidx
);
379 bool od
= dest
.is_opaque(vd
);
380 bool os
= src
.is_opaque(vs
);
381 typename
_dest::pixel_t ld
= dest
.lookup(vd
);
382 typename
_src::pixel_t ls
= src
.lookup(vs
);
383 typename
_dest::pixel_t t
= dest
.transparent();
384 typename
_dest::pixel_t r
;
386 case PD_SRC
: r
= ls
; break;
387 case PD_ATOP
: r
= od
? (os
? ls
: ld
) : t
; break;
388 case PD_OVER
: r
= os
? ls
: ld
; break;
389 case PD_IN
: r
= (od
& os
) ? ls
: t
; break;
390 case PD_OUT
: r
= (!od
&& os
) ? ls
: t
; break;
391 case PD_DEST
: r
= ld
; break;
392 case PD_DEST_ATOP
: r
= os
? (od
? ld
: ls
) : t
; break;
393 case PD_DEST_OVER
: r
= od
? ld
: ls
; break;
394 case PD_DEST_IN
: r
= (od
& os
) ? ld
: t
; break;
395 case PD_DEST_OUT
: r
= (od
& !os
) ? ld
: t
; break;
396 case PD_CLEAR
: r
= t
; break;
397 case PD_XOR
: r
= od
? (os
? t
: ld
) : ls
; break;
401 size_t swidth
, sheight
, dwidth
, dheight
;
407 template<porterduff_oper oper
, class _src
, class _dest
> srcdest_porterduff
<oper
, _src
, _dest
>
408 mk_porterduff(_dest dest
, _src src
)
410 return srcdest_porterduff
<oper
, _src
, _dest
>(dest
, src
);
413 template<class srcdest
>
414 void xblit_copy(srcdest sd
, uint32_t dx
, uint32_t dy
, uint32_t sx
, uint32_t sy
, uint32_t w
, uint32_t h
)
416 while((dx
+ w
> sd
.dwidth
|| sx
+ w
> sd
.swidth
) && w
> 0)
418 while((dy
+ h
> sd
.dheight
|| sy
+ h
> sd
.sheight
) && h
> 0)
420 if(dx
+ w
< w
|| dy
+ h
< h
) return; //Don't do overflowing blits.
421 if(sx
+ w
< w
|| sy
+ h
< h
) return; //Don't do overflowing blits.
422 size_t sidx
= sy
* sd
.swidth
+ sx
;
423 size_t didx
= dy
* sd
.dwidth
+ dx
;
424 size_t srskip
= sd
.swidth
- w
;
425 size_t drskip
= sd
.dwidth
- w
;
426 for(uint32_t j
= 0; j
< h
; j
++) {
427 for(uint32_t i
= 0; i
< w
; i
++) {
437 template<class srcdest
>
438 void xblit_scaled(srcdest sd
, uint32_t dx
, uint32_t dy
, uint32_t sx
, uint32_t sy
, uint32_t w
, uint32_t h
,
439 uint32_t hscl
, uint32_t vscl
)
441 if(!hscl
|| !vscl
) return;
442 w
= max(static_cast<uint32_t>(sd
.dwidth
/ hscl
), w
);
443 h
= max(static_cast<uint32_t>(sd
.dheight
/ vscl
), h
);
444 while((dx
+ hscl
* w
> sd
.dwidth
|| sx
+ w
> sd
.swidth
) && w
> 0)
446 while((dy
+ vscl
* h
> sd
.dheight
|| sy
+ h
> sd
.sheight
) && h
> 0)
448 if(dx
+ hscl
* w
< dx
|| dy
+ vscl
* h
< dy
) return; //Don't do overflowing blits.
449 if(sx
+ w
< w
|| sy
+ h
< h
) return; //Don't do overflowing blits.
450 size_t sidx
= sy
* sd
.swidth
+ sx
;
451 size_t didx
= dy
* sd
.dwidth
+ dx
;
452 size_t drskip
= sd
.dwidth
- hscl
* w
;
453 uint32_t _w
= hscl
* w
;
454 for(uint32_t j
= 0; j
< vscl
* h
; j
++) {
455 uint32_t _sidx
= sidx
;
456 for(uint32_t i
= 0; i
< _w
; i
+= hscl
) {
457 for(uint32_t k
= 0; k
< hscl
; k
++)
458 sd
.copy(didx
+ k
, _sidx
);
462 if((j
% vscl
) == vscl
- 1)
468 template<bool scaled
, class srcdest
>
469 inline void xblit(srcdest sd
, uint32_t dx
, uint32_t dy
, uint32_t sx
, uint32_t sy
, uint32_t w
, uint32_t h
,
470 uint32_t hscl
, uint32_t vscl
)
473 xblit_scaled(sd
, dx
, dy
, sx
, sy
, w
, h
, hscl
, vscl
);
475 xblit_copy(sd
, dx
, dy
, sx
, sy
, w
, h
);
478 template<bool scaled
, class src
, class dest
>
479 inline void xblit_pal(dest _dest
, src _src
, uint64_t ck
, uint32_t dx
, uint32_t dy
, uint32_t sx
,
480 uint32_t sy
, uint32_t w
, uint32_t h
, uint32_t hscl
, uint32_t vscl
)
483 xblit
<scaled
>(mk_srcdest(_dest
, _src
, colorkey_none()), dx
, dy
, sx
, sy
, w
, h
,
486 xblit
<scaled
>(mk_srcdest(_dest
, _src
, colorkey_palette(ck
)), dx
, dy
, sx
, sy
, w
, h
,
490 template<bool scaled
, class src
, class dest
>
491 inline void xblit_dir(dest _dest
, src _src
, uint64_t ck
, uint32_t dx
, uint32_t dy
, uint32_t sx
,
492 uint32_t sy
, uint32_t w
, uint32_t h
, uint32_t hscl
, uint32_t vscl
)
494 if(ck
== 0x100000000ULL
)
495 xblit
<scaled
>(mk_srcdest(_dest
, _src
, colorkey_none()), dx
, dy
, sx
, sy
, w
, h
,
498 xblit
<scaled
>(mk_srcdest(_dest
, _src
, colorkey_direct(ck
)), dx
, dy
, sx
, sy
, w
, h
,
502 template<bool scaled
, porterduff_oper oper
, class src
, class dest
>
503 inline void xblit_pduff2(dest _dest
, src _src
, uint32_t dx
, uint32_t dy
, uint32_t sx
,
504 uint32_t sy
, uint32_t w
, uint32_t h
, uint32_t hscl
, uint32_t vscl
)
506 xblit
<scaled
>(mk_porterduff
<oper
>(_dest
, _src
), dx
, dy
, sx
, sy
, w
, h
, hscl
, vscl
);
509 template<bool scaled
, class src
, class dest
>
510 inline void xblit_pduff(dest _dest
, src _src
, uint32_t dx
, uint32_t dy
, uint32_t sx
,
511 uint32_t sy
, uint32_t w
, uint32_t h
, uint32_t hscl
, uint32_t vscl
, porterduff_oper oper
)
515 xblit_pduff2
<scaled
, PD_ATOP
>(_dest
, _src
, dx
, dy
, sx
, sy
, w
, h
, hscl
, vscl
);
518 xblit_pduff2
<scaled
, PD_CLEAR
>(_dest
, _src
, dx
, dy
, sx
, sy
, w
, h
, hscl
, vscl
);
521 xblit_pduff2
<scaled
, PD_DEST
>(_dest
, _src
, dx
, dy
, sx
, sy
, w
, h
, hscl
, vscl
);
524 xblit_pduff2
<scaled
, PD_DEST_ATOP
>(_dest
, _src
, dx
, dy
, sx
, sy
, w
, h
, hscl
, vscl
);
527 xblit_pduff2
<scaled
, PD_DEST_IN
>(_dest
, _src
, dx
, dy
, sx
, sy
, w
, h
, hscl
, vscl
);
530 xblit_pduff2
<scaled
, PD_DEST_OUT
>(_dest
, _src
, dx
, dy
, sx
, sy
, w
, h
, hscl
, vscl
);
533 xblit_pduff2
<scaled
, PD_DEST_OVER
>(_dest
, _src
, dx
, dy
, sx
, sy
, w
, h
, hscl
, vscl
);
536 xblit_pduff2
<scaled
, PD_IN
>(_dest
, _src
, dx
, dy
, sx
, sy
, w
, h
, hscl
, vscl
);
539 xblit_pduff2
<scaled
, PD_OUT
>(_dest
, _src
, dx
, dy
, sx
, sy
, w
, h
, hscl
, vscl
);
542 xblit_pduff2
<scaled
, PD_OVER
>(_dest
, _src
, dx
, dy
, sx
, sy
, w
, h
, hscl
, vscl
);
545 xblit_pduff2
<scaled
, PD_SRC
>(_dest
, _src
, dx
, dy
, sx
, sy
, w
, h
, hscl
, vscl
);
548 xblit_pduff2
<scaled
, PD_XOR
>(_dest
, _src
, dx
, dy
, sx
, sy
, w
, h
, hscl
, vscl
);
553 int bitmap_load_fn(lua::state
& L
, std::function
<lua_loaded_bitmap()> src
)
557 lua_dbitmap
* b
= lua::_class
<lua_dbitmap
>::create(L
, bitmap
.w
, bitmap
.h
);
558 for(size_t i
= 0; i
< bitmap
.w
* bitmap
.h
; i
++)
559 b
->pixels
[i
] = framebuffer::color(bitmap
.bitmap
[i
]);
562 lua_bitmap
* b
= lua::_class
<lua_bitmap
>::create(L
, bitmap
.w
, bitmap
.h
);
563 lua_palette
* p
= lua::_class
<lua_palette
>::create(L
);
564 for(size_t i
= 0; i
< bitmap
.w
* bitmap
.h
; i
++)
565 b
->pixels
[i
] = bitmap
.bitmap
[i
];
566 p
->adjust_palette_size(bitmap
.palette
.size());
567 for(size_t i
= 0; i
< bitmap
.palette
.size(); i
++)
568 p
->colors
[i
] = framebuffer::color(bitmap
.palette
[i
]);
573 inline int64_t mangle_color(uint32_t c
)
578 return ((256 - (c
>> 24) - (c
>> 31)) << 24) | (c
& 0xFFFFFF);
581 int base64val(char ch
)
583 if(ch
>= 'A' && ch
<= 'Z')
585 if(ch
>= 'a' && ch
<= 'z')
587 if(ch
>= '0' && ch
<= '9')
593 if(ch
== ' ' || ch
== '\t' || ch
== '\r' || ch
== '\n')
600 std::string
base64_encode(const std::string
& str
)
602 std::ostringstream x
;
606 mem
= (mem
<< 8) + (unsigned char)i
;
608 uint8_t c1
= (mem
>> 18) & 0x3F;
609 uint8_t c2
= (mem
>> 12) & 0x3F;
610 uint8_t c3
= (mem
>> 6) & 0x3F;
611 uint8_t c4
= mem
& 0x3F;
612 x
<< CONST_base64chars
[c1
];
613 x
<< CONST_base64chars
[c2
];
614 x
<< CONST_base64chars
[c3
];
615 x
<< CONST_base64chars
[c4
];
621 uint8_t c1
= (mem
>> 10) & 0x3F;
622 uint8_t c2
= (mem
>> 4) & 0x3F;
623 uint8_t c3
= (mem
<< 2) & 0x3F;
624 x
<< CONST_base64chars
[c1
];
625 x
<< CONST_base64chars
[c2
];
626 x
<< CONST_base64chars
[c3
];
630 uint8_t c1
= (mem
>> 2) & 0x3F;
631 uint8_t c2
= (mem
<< 4) & 0x3F;
632 x
<< CONST_base64chars
[c1
];
633 x
<< CONST_base64chars
[c2
];
639 std::string
base64_decode(const std::string
& str
)
643 uint32_t memsize
= 1;
645 std::ostringstream x
;
647 int v
= base64val(i
);
650 posmod
= (posmod
+ 1) & 3;
651 if(v
== -2 && (posmod
== 1 || posmod
== 2))
652 throw std::runtime_error("Invalid Base64");
658 throw std::runtime_error("Invalid Base64");
659 memory
= memory
* 64 + v
;
660 memsize
= memsize
* 64;
663 x
<< static_cast<uint8_t>(memory
/ memsize
);
671 int bitmap_load_png_fn(lua::state
& L
, T
& src
)
673 png::decoder
img(src
);
674 if(img
.has_palette
) {
675 lua_bitmap
* b
= lua::_class
<lua_bitmap
>::create(L
, img
.width
, img
.height
);
676 lua_palette
* p
= lua::_class
<lua_palette
>::create(L
);
677 for(size_t i
= 0; i
< img
.width
* img
.height
; i
++)
678 b
->pixels
[i
] = img
.data
[i
];
679 p
->adjust_palette_size(img
.palette
.size());
680 for(size_t i
= 0; i
< img
.palette
.size(); i
++)
681 p
->colors
[i
] = framebuffer::color(mangle_color(img
.palette
[i
]));
684 lua_dbitmap
* b
= lua::_class
<lua_dbitmap
>::create(L
, img
.width
, img
.height
);
685 for(size_t i
= 0; i
< img
.width
* img
.height
; i
++)
686 b
->pixels
[i
] = framebuffer::color(mangle_color(img
.data
[i
]));
691 int bitmap_palette_fn(lua::state
& L
, std::istream
& s
)
693 lua_palette
* p
= lua::_class
<lua_palette
>::create(L
);
696 std::getline(s
, line
);
699 if(!regex_match("[ \t]*(#.*)?", line
)) {
701 } else if(r
= regex("[ \t]*([0-9]+)[ \t]+([0-9]+)[ \t]+([0-9]+)[ \t]+([0-9]+)[ \t]*", line
)) {
702 int64_t cr
, cg
, cb
, ca
;
703 cr
= parse_value
<uint8_t>(r
[1]);
704 cg
= parse_value
<uint8_t>(r
[2]);
705 cb
= parse_value
<uint8_t>(r
[3]);
706 ca
= 256 - parse_value
<uint16_t>(r
[4]);
708 p
->push_back(framebuffer::color(-1));
710 p
->push_back(framebuffer::color((ca
<< 24) | (cr
<< 16)
712 } else if(r
= regex("[ \t]*([0-9]+)[ \t]+([0-9]+)[ \t]+([0-9]+)[ \t]*", line
)) {
714 cr
= parse_value
<uint8_t>(r
[1]);
715 cg
= parse_value
<uint8_t>(r
[2]);
716 cb
= parse_value
<uint8_t>(r
[3]);
717 p
->push_back(framebuffer::color((cr
<< 16) | (cg
<< 8) | cb
));
718 } else if(r
= regex("[ \t]*([^ \t]|[^ \t].*[^ \t])[ \t]*", line
)) {
719 p
->push_back(framebuffer::color(r
[1]));
721 throw std::runtime_error("Invalid line format (" + line
+ ")");
726 inline framebuffer::color
tadjust(framebuffer::color c
, uint16_t adj
)
728 uint32_t rgb
= c
.orig
;
729 uint32_t a
= c
.origa
;
734 return framebuffer::color(-1);
736 return framebuffer::color(rgb
| ((uint32_t)(256 - a
) << 24));
739 lua::_class
<lua_loaded_bitmap
> LUA_class_loaded_bitmap(lua_class_gui
, "IMAGELOADER", {
740 {"load", lua_loaded_bitmap::load
<false>},
741 {"load_str", lua_loaded_bitmap::load_str
<false>},
742 {"load_png", lua_loaded_bitmap::load
<true>},
743 {"load_png_str", lua_loaded_bitmap::load_str
<true>},
746 lua::_class
<lua_palette
> LUA_class_palette(lua_class_gui
, "PALETTE", {
747 {"new", lua_palette::create
},
748 {"load", lua_palette::load
},
749 {"load_str", lua_palette::load_str
},
751 {"set", &lua_palette::set
},
752 {"get", &lua_palette::get
},
753 {"hash", &lua_palette::hash
},
754 {"debug", &lua_palette::debug
},
755 {"adjust_transparency", &lua_palette::adjust_transparency
},
756 }, &lua_palette::print
);
758 lua::_class
<lua_bitmap
> LUA_class_bitmap(lua_class_gui
, "BITMAP", {
759 {"new", lua_bitmap::create
},
761 {"draw", &lua_bitmap::draw
<false, false>},
762 {"draw_clip", &lua_bitmap::draw
<false, true>},
763 {"draw_outside", &lua_bitmap::draw
<true, false>},
764 {"draw_clip_outside", &lua_bitmap::draw
<true, true>},
765 {"pset", &lua_bitmap::pset
},
766 {"pget", &lua_bitmap::pget
},
767 {"size", &lua_bitmap::size
},
768 {"hash", &lua_bitmap::hash
},
769 {"blit", &lua_bitmap::blit
<false, false>},
770 {"blit_priority", &lua_bitmap::blit_priority
<false>},
771 {"blit_scaled", &lua_bitmap::blit
<true, false>},
772 {"blit_scaled_priority", &lua_bitmap::blit_priority
<true>},
773 {"blit_porterduff", &lua_bitmap::blit
<false, true>},
774 {"blit_scaled_porterduff", &lua_bitmap::blit
<true, true>},
775 {"save_png", &lua_bitmap::save_png
},
776 }, &lua_bitmap::print
);
778 lua::_class
<lua_dbitmap
> LUA_class_dbitmap(lua_class_gui
, "DBITMAP", {
779 {"new", lua_dbitmap::create
},
781 {"draw", &lua_dbitmap::draw
<false, false>},
782 {"draw_clip", &lua_dbitmap::draw
<false, true>},
783 {"draw_outside", &lua_dbitmap::draw
<true, false>},
784 {"draw_clip_outside", &lua_dbitmap::draw
<true, true>},
785 {"pset", &lua_dbitmap::pset
},
786 {"pget", &lua_dbitmap::pget
},
787 {"size", &lua_dbitmap::size
},
788 {"hash", &lua_dbitmap::hash
},
789 {"blit", &lua_dbitmap::blit
<false, false>},
790 {"blit_scaled", &lua_dbitmap::blit
<true, false>},
791 {"blit_porterduff", &lua_dbitmap::blit
<false, true>},
792 {"blit_scaled_porterduff", &lua_dbitmap::blit
<true, true>},
793 {"save_png", &lua_dbitmap::save_png
},
794 {"adjust_transparency", &lua_dbitmap::adjust_transparency
},
795 }, &lua_dbitmap::print
);
799 lua_palette::lua_palette(lua::state
& L
)
802 scolors
= colors
= lua::align_overcommit
<lua_palette
, framebuffer::color
>(this);
803 for(unsigned i
= 0; i
< reserved_colors
; i
++)
804 scolors
[i
] = framebuffer::color(-1);
807 lua_palette::~lua_palette()
809 CORE().fbuf
->render_kill_request(this);
812 std::string
lua_palette::print()
814 size_t s
= color_count
;
815 return (stringfmt() << s
<< " " << ((s
!= 1) ? "colors" : "color")).str();
818 int lua_palette::create(lua::state
& L
, lua::parameters
& P
)
820 lua::_class
<lua_palette
>::create(L
);
824 int lua_palette::load(lua::state
& L
, lua::parameters
& P
)
826 std::string name
, name2
;
828 P(name
, P
.optional(name2
, ""));
830 std::istream
& s
= zip::openrel(name
, name2
);
832 int r
= bitmap_palette_fn(L
, s
);
841 int lua_palette::load_str(lua::state
& L
, lua::parameters
& P
)
847 std::istringstream
s(content
);
848 return bitmap_palette_fn(L
, s
);
851 int lua_palette::set(lua::state
& L
, lua::parameters
& P
)
853 framebuffer::color nc
;
856 P(P
.skipped(), c
, nc
);
858 if(this->color_count
<= c
) {
859 this->adjust_palette_size(static_cast<uint32_t>(c
) + 1);
861 this->colors
[c
] = nc
;
865 int lua_palette::get(lua::state
& L
, lua::parameters
& P
)
867 framebuffer::color nc
;
873 if(this->color_count
<= c
) {
876 nc
= this->colors
[c
];
877 uint32_t rgb
= nc
.orig
;
878 uint32_t a
= nc
.origa
;
882 _nc
= ((256 - a
) << 24) | rgb
;
887 int lua_palette::hash(lua::state
& L
, lua::parameters
& P
)
890 const int buffersize
= 256;
892 char buf
[buffersize
];
893 unsigned realsize
= 0;
894 for(unsigned i
= 0; i
< this->color_count
; i
++)
895 if(this->colors
[i
].origa
) realsize
= i
+ 1;
896 for(unsigned i
= 0; i
< realsize
; i
++) {
897 if(bufferuse
+ 6 > buffersize
) {
898 h
.write(buf
, bufferuse
);
901 serialization::u32b(buf
+ bufferuse
+ 0, this->colors
[i
].orig
);
902 serialization::u16b(buf
+ bufferuse
+ 4, this->colors
[i
].origa
);
905 if(bufferuse
> 0) h
.write(buf
, bufferuse
);
906 L
.pushlstring(h
.read());
910 int lua_palette::debug(lua::state
& L
, lua::parameters
& P
)
912 for(size_t i
= 0; i
< color_count
; i
++)
913 messages
<< "Color #" << i
<< ": " << colors
[i
].orig
<< ":" << colors
[i
].origa
<< std::endl
;
917 int lua_palette::adjust_transparency(lua::state
& L
, lua::parameters
& P
)
921 P(P
.skipped(), tadj
);
923 for(size_t i
= 0; i
< color_count
; i
++)
924 colors
[i
] = tadjust(colors
[i
], tadj
);
928 void lua_palette::adjust_palette_size(size_t newsize
)
930 threads::alock
h(palette_mutex
);
931 if(newsize
> reserved_colors
) {
932 lcolors
.resize(newsize
);
933 if(color_count
<= reserved_colors
) {
934 for(unsigned i
= 0; i
< color_count
; i
++)
935 lcolors
[i
] = colors
[i
];
937 colors
= &lcolors
[0];
939 if(color_count
> reserved_colors
) {
940 for(unsigned i
= 0; i
< color_count
; i
++)
941 scolors
[i
] = lcolors
[i
];
945 color_count
= newsize
;
948 void lua_palette::push_back(const framebuffer::color
& cx
)
950 size_t c
= color_count
;
951 adjust_palette_size(c
+ 1);
956 lua_bitmap::lua_bitmap(lua::state
& L
, uint32_t w
, uint32_t h
)
958 if(overcommit(w
, h
) / h
/ sizeof(uint16_t) < w
) throw std::bad_alloc();
961 pixels
= lua::align_overcommit
<lua_bitmap
, uint16_t>(this);
962 memset(pixels
, 0, 2 * width
* height
);
965 lua_bitmap::~lua_bitmap()
967 CORE().fbuf
->render_kill_request(this);
970 std::string
lua_bitmap::print()
972 return (stringfmt() << width
<< "*" << height
).str();
975 int lua_bitmap::create(lua::state
& L
, lua::parameters
& P
)
980 P(w
, h
, P
.optional(c
, 0));
982 lua_bitmap
* b
= lua::_class
<lua_bitmap
>::create(L
, w
, h
);
983 for(size_t i
= 0; i
< b
->width
* b
->height
; i
++)
988 template<bool outside
, bool clip
>
989 int lua_bitmap::draw(lua::state
& L
, lua::parameters
& P
)
993 lua::objpin
<lua_bitmap
> b
;
994 lua::objpin
<lua_palette
> p
;
996 if(!core
.lua2
->render_ctx
) return 0;
1000 int32_t x0
= 0, y0
= 0, dw
= b
->width
, dh
= b
->height
;
1001 if(clip
) P(x0
, y0
, dw
, dh
);
1003 core
.lua2
->render_ctx
->queue
->create_add
<render_object_bitmap
>(x
, y
, b
, p
, x0
, y0
, dw
, dh
, outside
);
1007 int lua_bitmap::pset(lua::state
& L
, lua::parameters
& P
)
1012 P(P
.skipped(), x
, y
, c
);
1014 if(x
>= this->width
|| y
>= this->height
)
1016 this->pixels
[y
* this->width
+ x
] = c
;
1020 int lua_bitmap::pget(lua::state
& L
, lua::parameters
& P
)
1024 P(P
.skipped(), x
, y
);
1026 if(x
>= this->width
|| y
>= this->height
)
1028 L
.pushnumber(this->pixels
[y
* this->width
+ x
]);
1032 int lua_bitmap::size(lua::state
& L
, lua::parameters
& P
)
1034 L
.pushnumber(this->width
);
1035 L
.pushnumber(this->height
);
1039 int lua_bitmap::hash(lua::state
& L
, lua::parameters
& P
)
1042 const int buffersize
= 256;
1044 char buf
[buffersize
];
1045 memset(buf
, 0, buffersize
);
1046 serialization::u64b(buf
+ 0, this->width
);
1047 serialization::u64b(buf
+ 8, this->height
);
1049 for(unsigned i
= 0; i
< this->width
* this->height
; i
++) {
1050 if(bufferuse
+ 2 > buffersize
) {
1051 h
.write(buf
, bufferuse
);
1054 serialization::u16b(buf
+ bufferuse
+ 0, this->pixels
[i
]);
1057 if(bufferuse
> 0) h
.write(buf
, bufferuse
);
1058 L
.pushlstring(h
.read());
1062 template<bool scaled
, bool porterduff
> int lua_bitmap::blit(lua::state
& L
, lua::parameters
& P
)
1064 uint32_t dx
, dy
, sx
, sy
, w
, h
, hscl
, vscl
;
1067 P(P
.skipped(), dx
, dy
, src_p
, sx
, sy
, w
, h
);
1069 P(hscl
, P
.optional2(vscl
, hscl
));
1072 porterduff_oper pd_oper
= get_pd_oper(P
.arg
<std::string
>());
1073 xblit_pduff
<scaled
>(operand_bitmap(*this), operand_bitmap(*src_p
), dx
, dy
, sx
, sy
, w
, h
, hscl
, vscl
,
1076 int64_t ck
= P
.arg_opt
<uint64_t>(65536);
1077 xblit_pal
<scaled
>(operand_bitmap(*this), operand_bitmap(*src_p
), ck
, dx
, dy
, sx
, sy
, w
, h
,
1083 template<bool scaled
> int lua_bitmap::blit_priority(lua::state
& L
, lua::parameters
& P
)
1085 uint32_t dx
, dy
, sx
, sy
, w
, h
, hscl
, vscl
;
1088 P(P
.skipped(), dx
, dy
, src_p
, sx
, sy
, w
, h
);
1090 P(hscl
, P
.optional2(vscl
, hscl
));
1092 xblit
<scaled
>(srcdest_priority(*this, *src_p
), dx
, dy
, sx
, sy
, w
, h
, hscl
, vscl
);
1096 int lua_bitmap::save_png(lua::state
& L
, lua::parameters
& P
)
1098 std::string name
, name2
;
1103 if((was_filename
= P
.is_string())) P(name
);
1104 if(P
.is_string()) P(name2
);
1107 auto buf
= this->save_png(*p
);
1109 std::string filename
= zip::resolverel(name
, name2
);
1110 std::ofstream
strm(filename
, std::ios::binary
);
1112 throw std::runtime_error("Can't open output file");
1113 strm
.write(&buf
[0], buf
.size());
1115 throw std::runtime_error("Can't write output file");
1118 std::ostringstream strm
;
1119 strm
.write(&buf
[0], buf
.size());
1120 L
.pushlstring(base64_encode(strm
.str()));
1126 lua_dbitmap::lua_dbitmap(lua::state
& L
, uint32_t w
, uint32_t h
)
1128 if(overcommit(w
, h
) / h
/ sizeof(framebuffer::color
) < w
) throw std::bad_alloc();
1131 pixels
= lua::align_overcommit
<lua_dbitmap
, framebuffer::color
>(this);
1132 //Initialize the bitmap data.
1133 framebuffer::color
transparent(-1);
1134 for(size_t i
= 0; i
< (size_t)width
* height
; i
++)
1135 new(pixels
+ i
) framebuffer::color(transparent
);
1138 lua_dbitmap::~lua_dbitmap()
1140 CORE().fbuf
->render_kill_request(this);
1143 std::string
lua_dbitmap::print()
1145 return (stringfmt() << width
<< "*" << height
).str();
1148 int lua_dbitmap::create(lua::state
& L
, lua::parameters
& P
)
1151 framebuffer::color c
;
1153 P(w
, h
, P
.optional(c
, -1));
1155 lua_dbitmap
* b
= lua::_class
<lua_dbitmap
>::create(L
, w
, h
);
1156 for(size_t i
= 0; i
< b
->width
* b
->height
; i
++)
1161 template<bool outside
, bool clip
>
1162 int lua_dbitmap::draw(lua::state
& L
, lua::parameters
& P
)
1164 auto& core
= CORE();
1166 lua::objpin
<lua_dbitmap
> b
;
1168 if(!core
.lua2
->render_ctx
) return 0;
1172 int32_t x0
= 0, y0
= 0, dw
= b
->width
, dh
= b
->height
;
1173 if(clip
) P(x0
, y0
, dw
, dh
);
1175 core
.lua2
->render_ctx
->queue
->create_add
<render_object_bitmap
>(x
, y
, b
, x0
, y0
, dw
, dh
, outside
);
1179 int lua_dbitmap::pset(lua::state
& L
, lua::parameters
& P
)
1182 framebuffer::color c
;
1184 P(P
.skipped(), x
, y
, c
);
1186 if(x
>= this->width
|| y
>= this->height
)
1188 this->pixels
[y
* this->width
+ x
] = c
;
1192 int lua_dbitmap::pget(lua::state
& L
, lua::parameters
& P
)
1196 P(P
.skipped(), x
, y
);
1198 if(x
>= this->width
|| y
>= this->height
)
1200 L
.pushnumber((this->pixels
[y
* this->width
+ x
]).asnumber());
1204 int lua_dbitmap::size(lua::state
& L
, lua::parameters
& P
)
1206 L
.pushnumber(this->width
);
1207 L
.pushnumber(this->height
);
1211 int lua_dbitmap::hash(lua::state
& L
, lua::parameters
& P
)
1214 const int buffersize
= 256;
1216 char buf
[buffersize
];
1217 memset(buf
, 0, buffersize
);
1218 serialization::u64b(buf
+ 0, this->width
);
1219 serialization::u64b(buf
+ 4, this->height
);
1221 for(unsigned i
= 0; i
< this->width
* this->height
; i
++) {
1222 if(bufferuse
+ 6 > buffersize
) {
1223 h
.write(buf
, bufferuse
);
1226 serialization::u32b(buf
+ bufferuse
+ 0, this->pixels
[i
].orig
);
1227 serialization::u16b(buf
+ bufferuse
+ 4, this->pixels
[i
].origa
);
1230 if(bufferuse
> 0) h
.write(buf
, bufferuse
);
1231 L
.pushlstring(h
.read());
1235 template<bool scaled
, bool porterduff
> int lua_dbitmap::blit(lua::state
& L
, lua::parameters
& P
)
1237 uint32_t dx
, dy
, sx
, sy
, w
, h
, hscl
, vscl
;
1239 P(P
.skipped(), dx
, dy
);
1241 //DBitmap or Bitmap+Palette.
1242 bool src_d
= P
.is
<lua_dbitmap
>();
1243 bool src_p
= P
.is
<lua_bitmap
>();
1244 int sidx
= P
.skip();
1245 if(!src_d
&& !src_p
)
1246 P
.expected("BITMAP or DBITMAP", sidx
);
1249 spal
= P
.skip(); //Reserve for palette.
1254 P(hscl
, P
.optional2(vscl
, hscl
));
1256 int64_t ckx
= 0x100000000ULL
;
1257 porterduff_oper pd_oper
;
1259 pd_oper
= get_pd_oper(P
.arg
<std::string
>());
1261 //Hack: Direct-color bitmaps should take color spec, with special NONE value.
1263 ckx
= P
.arg_opt
<int64_t>(0x10000);
1264 else if(P
.is_novalue())
1267 ckx
= P
.arg
<framebuffer::color
>().asnumber();
1270 operand_dbitmap
dest(*this);
1272 operand_dbitmap
src(*P
.arg
<lua_dbitmap
*>(sidx
));
1274 xblit_pduff
<scaled
>(dest
, src
, dx
, dy
, sx
, sy
, w
, h
, hscl
, vscl
, pd_oper
);
1276 xblit_dir
<scaled
>(dest
, src
, ckx
, dx
, dy
, sx
, sy
, w
, h
, hscl
, vscl
);
1278 operand_bitmap_pal
src(*P
.arg
<lua_bitmap
*>(sidx
), *P
.arg
<lua_palette
*>(spal
));
1280 xblit_pduff
<scaled
>(dest
, src
, dx
, dy
, sx
, sy
, w
, h
, hscl
, vscl
, pd_oper
);
1282 xblit_pal
<scaled
>(dest
, src
, ckx
, dx
, dy
, sx
, sy
, w
, h
, hscl
, vscl
);
1287 int lua_dbitmap::save_png(lua::state
& L
, lua::parameters
& P
)
1289 std::string name
, name2
;
1293 if((was_filename
= P
.is_string())) P(name
);
1294 if(P
.is_string()) P(name2
);
1296 auto buf
= this->save_png();
1298 std::string filename
= zip::resolverel(name
, name2
);
1299 std::ofstream
strm(filename
, std::ios::binary
);
1301 throw std::runtime_error("Can't open output file");
1302 strm
.write(&buf
[0], buf
.size());
1304 throw std::runtime_error("Can't write output file");
1307 std::ostringstream strm
;
1308 strm
.write(&buf
[0], buf
.size());
1309 L
.pushlstring(base64_encode(strm
.str()));
1314 int lua_dbitmap::adjust_transparency(lua::state
& L
, lua::parameters
& P
)
1318 P(P
.skipped(), tadj
);
1320 for(size_t i
= 0; i
< width
* height
; i
++)
1321 pixels
[i
] = tadjust(pixels
[i
], tadj
);
1326 template<bool png
> int lua_loaded_bitmap::load(lua::state
& L
, lua::parameters
& P
)
1328 std::string name
, name2
;
1330 P(name
, P
.optional(name2
, ""));
1333 std::string filename
= zip::resolverel(name
, name2
);
1334 return bitmap_load_png_fn(L
, filename
);
1336 return bitmap_load_fn(L
, [&name
, &name2
]() -> lua_loaded_bitmap
{
1337 std::string name3
= zip::resolverel(name
, name2
);
1338 return lua_loaded_bitmap::load(name3
);
1342 template<bool png
> int lua_loaded_bitmap::load_str(lua::state
& L
, lua::parameters
& P
)
1344 std::string contents
;
1349 contents
= base64_decode(contents
);
1350 std::istringstream
strm(contents
);
1351 return bitmap_load_png_fn(L
, strm
);
1353 return bitmap_load_fn(L
, [&contents
]() -> lua_loaded_bitmap
{
1354 std::istringstream
strm(contents
);
1355 return lua_loaded_bitmap::load(strm
);