1 #include "lua/internal.hpp"
2 #include "core/framebuffer.hpp"
3 #include "core/instance.hpp"
4 #include "library/png.hpp"
5 #include "library/range.hpp"
6 #include "library/string.hpp"
7 #include "library/threads.hpp"
8 #include "library/lua-framebuffer.hpp"
9 #include "library/zip.hpp"
10 #include "lua/bitmap.hpp"
27 lua::objpin
<lua_bitmap
> b
;
28 lua::objpin
<lua_dbitmap
> d
;
29 lua::objpin
<lua_palette
> p
;
34 tilemap(lua::state
& L
, size_t _width
, size_t _height
, size_t _cwidth
, size_t _cheight
);
35 static size_t overcommit(size_t _width
, size_t _height
, size_t _cwidth
, size_t _cheight
) {
36 return lua::overcommit_std_align
+ 2 * sizeof(tilemap_entry
) * (size_t)_width
* _height
;
40 threads::alock
h(lock
);
41 CORE().fbuf
->render_kill_request(this);
43 static int create(lua::state
& L
, lua::parameters
& P
);
44 template<bool outside
> int draw(lua::state
& L
, lua::parameters
& P
);
45 int get(lua::state
& L
, lua::parameters
& P
)
51 threads::alock
h(lock
);
52 if(x
>= width
|| y
>= height
)
54 tilemap_entry
& e
= map
[y
* width
+ x
];
65 int set(lua::state
& L
, lua::parameters
& P
)
72 threads::alock
h(lock
);
73 if(x
>= width
|| y
>= height
)
75 tilemap_entry
& e
= map
[y
* width
+ x
];
76 if(P
.is
<lua_dbitmap
>(oidx
)) {
77 auto d
= P
.arg
<lua::objpin
<lua_dbitmap
>>(oidx
);
80 } else if(P
.is
<lua_bitmap
>(oidx
)) {
81 auto b
= P
.arg
<lua::objpin
<lua_bitmap
>>(oidx
);
82 auto p
= P
.arg
<lua::objpin
<lua_palette
>>(oidx
+ 1);
86 } else if(P
.is_novalue(oidx
)) {
89 P
.expected("BITMAP, DBITMAP or nil", oidx
);
92 int getsize(lua::state
& L
, lua::parameters
& P
)
98 int getcsize(lua::state
& L
, lua::parameters
& P
)
100 L
.pushnumber(cwidth
);
101 L
.pushnumber(cheight
);
104 size_t calcshift(size_t orig
, int32_t shift
, size_t dimension
, size_t offset
, bool circular
)
108 //Now the widow is scaled [0,dimension).
110 orig
= (orig
+ shift
) % dimension
;
113 while(orig
> dimension
) {
123 int scroll(lua::state
& L
, lua::parameters
& P
)
129 P(P
.skipped(), ox
, oy
, P
.optional(x0
, 0), P
.optional(y0
, 0), P
.optional(w
, width
),
130 P
.optional(h
, height
), P
.optional(circx
, false), P
.optional(circy
, false));
132 threads::alock
mh(lock
);
133 if(x0
> width
|| x0
+ w
> width
|| x0
+ w
< x0
|| y0
> height
|| y0
+ h
> height
||
135 throw std::runtime_error("Scroll window out of range");
136 if(!ox
&& !oy
) return 0;
137 tilemap_entry
* tmp
= tmpmap
;
138 for(size_t _y
= 0; _y
< h
; _y
++) {
140 size_t sy
= calcshift(y
, oy
, h
, y0
, circy
);
141 if(sy
< y0
|| sy
>= y0
+ h
)
143 for(size_t _x
= 0; _x
< w
; _x
++) {
145 size_t sx
= calcshift(x
, ox
, w
, x0
, circx
);
146 if(sx
< x0
|| sx
>= x0
+ w
)
149 tmp
[_y
* w
+ _x
] = map
[sy
* width
+ sx
];
152 for(size_t _y
= 0; _y
< h
; _y
++)
153 for(size_t _x
= 0; _x
< w
; _x
++)
154 map
[(_y
+ y0
) * width
+ (_x
+ x0
)] = tmp
[_y
* w
+ _x
];
159 return (stringfmt() << width
<< "*" << height
<< " (cell " << cwidth
<< "*" << cheight
167 tilemap_entry
* tmpmap
;
171 struct render_object_tilemap
: public framebuffer::object
173 render_object_tilemap(int32_t _x
, int32_t _y
, int32_t _x0
, int32_t _y0
, uint32_t _w
,
174 uint32_t _h
, bool _outside
, lua::objpin
<tilemap
>& _map
)
175 : x(_x
), y(_y
), x0(_x0
), y0(_y0
), w(_w
), h(_h
), outside(_outside
), map(_map
) {}
176 ~render_object_tilemap() throw()
179 bool kill_request(void* obj
) throw()
181 return kill_request_ifeq(map
.object(), obj
);
183 template<bool T
> void composite_op(struct framebuffer::fb
<T
>& scr
) throw()
185 tilemap
& _map
= *map
;
186 threads::alock
h(_map
.lock
);
187 for(size_t ty
= 0; ty
< _map
.height
; ty
++) {
188 size_t basey
= _map
.cheight
* ty
;
189 for(size_t tx
= 0; tx
< _map
.width
; tx
++) {
190 size_t basex
= _map
.cwidth
* tx
;
191 composite_op(scr
, _map
.map
[ty
* _map
.width
+ tx
], basex
, basey
);
195 template<bool T
> void composite_op(struct framebuffer::fb
<T
>& scr
, int32_t xp
,
196 int32_t yp
, const range
& X
, const range
& Y
, const range
& sX
, const range
& sY
,
197 lua_dbitmap
& d
) throw()
199 if(!X
.size() || !Y
.size()) return;
201 for(uint32_t r
= Y
.low(); r
!= Y
.high(); r
++) {
202 typename
framebuffer::fb
<T
>::element_t
* rptr
= scr
.rowptr(yp
+ r
);
203 size_t eptr
= xp
+ X
.low();
204 uint32_t xmin
= X
.low();
205 bool cut
= outside
&& sY
.in(r
);
206 if(cut
&& sX
.in(xmin
)) {
208 //FIXME: This may overrun buffer (but the overrun pointer is not accessed.)
209 eptr
+= (sX
.high() - X
.low());
211 for(uint32_t c
= xmin
; c
< X
.high(); c
++, eptr
++) {
212 if(__builtin_expect(cut
&& c
== sX
.low(), 0)) {
216 d
.pixels
[r
* d
.width
+ c
].apply(rptr
[eptr
]);
220 template<bool T
> void composite_op(struct framebuffer::fb
<T
>& scr
, int32_t xp
,
221 int32_t yp
, const range
& X
, const range
& Y
, const range
& sX
, const range
& sY
, lua_bitmap
& b
,
222 lua_palette
& p
) throw()
224 if(!X
.size() || !Y
.size()) return;
226 p
.palette_mutex
.lock();
227 framebuffer::color
* palette
= p
.colors
;
228 size_t pallim
= p
.color_count
;
230 for(uint32_t r
= Y
.low(); r
!= Y
.high(); r
++) {
231 typename
framebuffer::fb
<T
>::element_t
* rptr
= scr
.rowptr(yp
+ r
);
232 size_t eptr
= xp
+ X
.low();
233 uint32_t xmin
= X
.low();
234 bool cut
= outside
&& sY
.in(r
);
235 if(cut
&& sX
.in(xmin
)) {
237 //FIXME: This may overrun buffer (but the overrun pointer is not accessed.)
238 eptr
+= (sX
.high() - X
.low());
240 for(uint32_t c
= xmin
; c
< X
.high(); c
++, eptr
++) {
241 if(__builtin_expect(cut
&& c
== sX
.low(), 0)) {
245 uint16_t i
= b
.pixels
[r
* b
.width
+ c
];
247 palette
[i
].apply(rptr
[eptr
]);
250 p
.palette_mutex
.unlock();
252 template<bool T
> void composite_op(struct framebuffer::fb
<T
>& scr
, tilemap_entry
& e
, int32_t bx
,
265 uint32_t oX
= x
+ scr
.get_origin_x() - x0
;
266 uint32_t oY
= y
+ scr
.get_origin_y() - y0
;
267 range bX
= ((range::make_w(scr
.get_width()) - oX
) & range::make_s(bx
, _w
) &
268 range::make_s(x0
, w
)) - bx
;
269 range bY
= ((range::make_w(scr
.get_height()) - oY
) & range::make_s(by
, _h
) &
270 range::make_s(y0
, h
)) - by
;
271 range sX
= range::make_s(-x
- bx
+ x0
, scr
.get_last_blit_width());
272 range sY
= range::make_s(-y
- by
+ y0
, scr
.get_last_blit_height());
275 composite_op(scr
, oX
+ bx
, oY
+ by
, bX
, bY
, sX
, sY
, *e
.b
, *e
.p
);
277 composite_op(scr
, oX
+ bx
, oY
+ by
, bX
, bY
, sX
, sY
, *e
.d
);
279 void operator()(struct framebuffer::fb
<false>& x
) throw() { composite_op(x
); }
280 void operator()(struct framebuffer::fb
<true>& x
) throw() { composite_op(x
); }
281 void clone(framebuffer::queue
& q
) const throw(std::bad_alloc
) { q
.clone_helper(this); }
290 lua::objpin
<tilemap
> map
;
293 template<bool outside
> int tilemap::draw(lua::state
& L
, lua::parameters
& P
)
298 lua::objpin
<tilemap
> t
;
300 if(!core
.lua2
->render_ctx
) return 0;
302 P(t
, x
, y
, P
.optional(x0
, 0), P
.optional(y0
, 0), P
.optional(w
, width
* cwidth
),
303 P
.optional(h
, height
* cheight
));
305 core
.lua2
->render_ctx
->queue
->create_add
<render_object_tilemap
>(x
, y
, x0
, y0
, w
, h
, outside
, t
);
309 int tilemap::create(lua::state
& L
, lua::parameters
& P
)
311 uint32_t w
, h
, px
, py
;
315 lua::_class
<tilemap
>::create(L
, w
, h
, px
, py
);
319 lua::_class
<tilemap
> LUA_class_tilemap(lua_class_gui
, "TILEMAP", {
320 {"new", tilemap::create
},
322 {"draw", &tilemap::draw
<false>},
323 {"draw_outside", &tilemap::draw
<true>},
324 {"set", &tilemap::set
},
325 {"get", &tilemap::get
},
326 {"scroll", &tilemap::scroll
},
327 {"getsize", &tilemap::getsize
},
328 {"getcsize", &tilemap::getcsize
},
331 tilemap::tilemap(lua::state
& L
, size_t _width
, size_t _height
, size_t _cwidth
, size_t _cheight
)
332 : width(_width
), height(_height
), cwidth(_cwidth
), cheight(_cheight
)
334 if(overcommit(width
, height
, cwidth
, cheight
) / height
/ sizeof(tilemap_entry
) < width
)
335 throw std::bad_alloc();
337 map
= lua::align_overcommit
<tilemap
, tilemap_entry
>(this);
338 tmpmap
= &map
[width
* height
];
339 //Initialize the map!
340 for(size_t i
= 0; i
< 2 * width
* height
; i
++)
341 new(map
+ i
) tilemap_entry();