1 #include "lua/internal.hpp"
2 #include "core/framebuffer.hpp"
3 #include "library/framebuffer.hpp"
4 #include "library/png-decoder.hpp"
5 #include "library/string.hpp"
6 #include "library/threadtypes.hpp"
7 #include "library/zip.hpp"
8 #include "lua/bitmap.hpp"
25 lua_obj_pin
<lua_bitmap
> b
;
26 lua_obj_pin
<lua_dbitmap
> d
;
27 lua_obj_pin
<lua_palette
> p
;
32 tilemap(lua_state
& L
, size_t _width
, size_t _height
, size_t _cwidth
, size_t _cheight
);
35 umutex_class
h(mutex
);
36 render_kill_request(this);
38 int draw(lua_state
& L
, const std::string
& fname
);
39 int get(lua_state
& L
, const std::string
& fname
)
41 umutex_class
h(mutex
);
42 uint32_t x
= L
.get_numeric_argument
<uint32_t>(2, fname
.c_str());
43 uint32_t y
= L
.get_numeric_argument
<uint32_t>(3, fname
.c_str());
44 if(x
>= width
|| y
>= height
)
46 tilemap_entry
& e
= map
[y
* width
+ x
];
57 int set(lua_state
& L
, const std::string
& fname
)
59 umutex_class
h(mutex
);
60 uint32_t x
= L
.get_numeric_argument
<uint32_t>(2, fname
.c_str());
61 uint32_t y
= L
.get_numeric_argument
<uint32_t>(3, fname
.c_str());
62 if(x
>= width
|| y
>= height
)
64 tilemap_entry
& e
= map
[y
* width
+ x
];
65 if(lua_class
<lua_dbitmap
>::is(L
, 4)) {
66 auto d
= lua_class
<lua_dbitmap
>::pin(L
, 4, fname
.c_str());
69 } else if(lua_class
<lua_bitmap
>::is(L
, 4)) {
70 auto b
= lua_class
<lua_bitmap
>::pin(L
, 4, fname
.c_str());
71 auto p
= lua_class
<lua_palette
>::pin(L
, 5, fname
.c_str());
75 } else if(L
.type(4) == LUA_TNIL
|| L
.type(4) == LUA_TNONE
) {
78 throw std::runtime_error("Expected BITMAP, DBITMAP or nil as argument 4 to "
82 int getsize(lua_state
& L
, const std::string
& fname
)
88 int getcsize(lua_state
& L
, const std::string
& fname
)
91 L
.pushnumber(cheight
);
94 size_t calcshift(size_t orig
, int32_t shift
, size_t dimension
, size_t offset
, bool circular
)
98 //Now the widow is scaled [0,dimension).
100 orig
= (orig
+ shift
) % dimension
;
103 while(orig
> dimension
) {
113 int scroll(lua_state
& L
, const std::string
& fname
)
115 umutex_class
mh(mutex
);
116 int32_t ox
= -L
.get_numeric_argument
<int32_t>(2, fname
.c_str());
117 int32_t oy
= -L
.get_numeric_argument
<int32_t>(3, fname
.c_str());
118 size_t x0
= 0, y0
= 0, w
= width
, h
= height
;
119 L
.get_numeric_argument
<size_t>(4, x0
, fname
.c_str());
120 L
.get_numeric_argument
<size_t>(5, y0
, fname
.c_str());
121 L
.get_numeric_argument
<size_t>(6, w
, fname
.c_str());
122 L
.get_numeric_argument
<size_t>(7, h
, fname
.c_str());
123 bool circx
= (L
.type(8) == LUA_TBOOLEAN
&& L
.toboolean(8));
124 bool circy
= (L
.type(9) == LUA_TBOOLEAN
&& L
.toboolean(9));
125 if(x0
> width
|| x0
+ w
> width
|| x0
+ w
< x0
|| y0
> height
|| y0
+ h
> height
||
127 throw std::runtime_error("Scroll window out of range");
128 if(!ox
&& !oy
) return 0;
129 std::vector
<tilemap_entry
> tmp
;
131 for(size_t _y
= 0; _y
< h
; _y
++) {
133 size_t sy
= calcshift(y
, oy
, h
, y0
, circy
);
134 if(sy
< y0
|| sy
>= y0
+ h
)
136 for(size_t _x
= 0; _x
< w
; _x
++) {
138 size_t sx
= calcshift(x
, ox
, w
, x0
, circx
);
139 if(sx
< x0
|| sx
>= x0
+ w
)
142 tmp
[_y
* w
+ _x
] = map
[sy
* width
+ sx
];
145 for(size_t _y
= 0; _y
< h
; _y
++)
146 for(size_t _x
= 0; _x
< w
; _x
++)
147 map
[(_y
+ y0
) * width
+ (_x
+ x0
)] = tmp
[_y
* w
+ _x
];
152 return (stringfmt() << width
<< "*" << height
<< " (cell " << cwidth
<< "*" << cheight
159 std::vector
<tilemap_entry
> map
;
163 struct render_object_tilemap
: public render_object
165 render_object_tilemap(int32_t _x
, int32_t _y
, int32_t _x0
, int32_t _y0
, uint32_t _w
,
166 uint32_t _h
, lua_obj_pin
<tilemap
> _map
)
167 : x(_x
), y(_y
), x0(_x0
), y0(_y0
), w(_w
), h(_h
), map(_map
) {}
168 ~render_object_tilemap() throw()
171 bool kill_request(void* obj
) throw()
173 return kill_request_ifeq(map
.object(), obj
);
175 template<bool T
> void composite_op(struct framebuffer
<T
>& scr
) throw()
177 tilemap
& _map
= *map
;
178 umutex_class
h(_map
.mutex
);
179 for(size_t ty
= 0; ty
< _map
.height
; ty
++) {
180 size_t basey
= _map
.cheight
* ty
;
181 for(size_t tx
= 0; tx
< _map
.width
; tx
++) {
182 size_t basex
= _map
.cwidth
* tx
;
183 composite_op(scr
, _map
.map
[ty
* _map
.width
+ tx
], basex
, basey
);
187 template<bool T
> void composite_op(struct framebuffer
<T
>& scr
, int32_t xp
,
188 int32_t yp
, int32_t xmin
, int32_t xmax
, int32_t ymin
, int32_t ymax
, lua_dbitmap
& d
) throw()
190 if(xmin
>= xmax
|| ymin
>= ymax
) return;
191 for(auto& c
: d
.pixels
)
194 for(int32_t r
= ymin
; r
< ymax
; r
++) {
195 typename framebuffer
<T
>::element_t
* rptr
= scr
.rowptr(yp
+ r
);
196 size_t eptr
= xp
+ xmin
;
197 for(int32_t c
= xmin
; c
< xmax
; c
++, eptr
++)
198 d
.pixels
[r
* d
.width
+ c
].apply(rptr
[eptr
]);
201 template<bool T
> void composite_op(struct framebuffer
<T
>& scr
, int32_t xp
,
202 int32_t yp
, int32_t xmin
, int32_t xmax
, int32_t ymin
, int32_t ymax
, lua_bitmap
& b
,
206 if(xmin
>= xmax
|| ymin
>= ymax
) return;
207 p
.palette_mutex
.lock();
208 premultiplied_color
* palette
= &p
.colors
[0];
209 for(auto& c
: p
.colors
)
211 size_t pallim
= p
.colors
.size();
213 for(int32_t r
= ymin
; r
< ymax
; r
++) {
214 typename framebuffer
<T
>::element_t
* rptr
= scr
.rowptr(yp
+ r
);
215 size_t eptr
= xp
+ xmin
;
216 for(int32_t c
= xmin
; c
< xmax
; c
++, eptr
++) {
217 uint16_t i
= b
.pixels
[r
* b
.width
+ c
];
219 palette
[i
].apply(rptr
[eptr
]);
222 p
.palette_mutex
.unlock();
224 template<bool T
> void composite_op(struct framebuffer
<T
>& scr
, tilemap_entry
& e
, int32_t bx
,
236 //Calculate notional screen coordinates for the tile.
237 int32_t scrx
= x
+ scr
.get_origin_x() + bx
- x0
;
238 int32_t scry
= y
+ scr
.get_origin_y() + by
- y0
;
239 int32_t scrw
= scr
.get_width();
240 int32_t scrh
= scr
.get_height();
245 clip(scrx
, scrw
, x
+ scr
.get_origin_x(), w
, xmin
, xmax
);
246 clip(scry
, scrh
, y
+ scr
.get_origin_y(), h
, ymin
, ymax
);
248 composite_op(scr
, scrx
, scry
, xmin
, xmax
, ymin
, ymax
, *e
.b
, *e
.p
);
250 composite_op(scr
, scrx
, scry
, xmin
, xmax
, ymin
, ymax
, *e
.d
);
252 //scrc + cmin >= 0 and scrc + cmax <= scrd (Clip on screen).
253 //scrc + cmin >= bc and scrc + cmax <= bc + d (Clip on texture).
254 void clip(int32_t scrc
, int32_t scrd
, int32_t bc
, int32_t d
, int32_t& cmin
, int32_t& cmax
)
258 if(scrc
+ cmax
> scrd
)
262 if(scrc
+ cmax
> bc
+ d
)
263 cmax
= bc
+ d
- scrc
;
265 void operator()(struct framebuffer
<false>& x
) throw() { composite_op(x
); }
266 void operator()(struct framebuffer
<true>& x
) throw() { composite_op(x
); }
267 void clone(render_queue
& q
) const throw(std::bad_alloc
) { q
.clone_helper(this); }
275 lua_obj_pin
<tilemap
> map
;
278 int tilemap::draw(lua_state
& L
, const std::string
& fname
)
282 uint32_t x
= L
.get_numeric_argument
<int32_t>(2, fname
.c_str());
283 uint32_t y
= L
.get_numeric_argument
<int32_t>(3, fname
.c_str());
284 int32_t x0
= 0, y0
= 0;
285 uint32_t w
= width
* cwidth
, h
= height
* cheight
;
286 L
.get_numeric_argument
<int32_t>(4, x0
, fname
.c_str());
287 L
.get_numeric_argument
<int32_t>(5, y0
, fname
.c_str());
288 L
.get_numeric_argument
<uint32_t>(6, w
, fname
.c_str());
289 L
.get_numeric_argument
<uint32_t>(7, h
, fname
.c_str());
290 auto t
= lua_class
<tilemap
>::pin(L
, 1, fname
.c_str());
291 lua_render_ctx
->queue
->create_add
<render_object_tilemap
>(x
, y
, x0
, y0
, w
, h
, t
);
295 function_ptr_luafun
gui_ctilemap(lua_func_misc
, "gui.tilemap", [](lua_state
& LS
, const std::string
& fname
) ->
297 uint32_t w
= LS
.get_numeric_argument
<uint32_t>(1, fname
.c_str());
298 uint32_t h
= LS
.get_numeric_argument
<uint32_t>(2, fname
.c_str());
299 uint32_t px
= LS
.get_numeric_argument
<uint32_t>(3, fname
.c_str());
300 uint32_t py
= LS
.get_numeric_argument
<uint32_t>(4, fname
.c_str());
301 tilemap
* t
= lua_class
<tilemap
>::create(LS
, w
, h
, px
, py
);
306 DECLARE_LUACLASS(tilemap
, "TILEMAP");
310 tilemap::tilemap(lua_state
& L
, size_t _width
, size_t _height
, size_t _cwidth
, size_t _cheight
)
311 : width(_width
), height(_height
), cwidth(_cwidth
), cheight(_cheight
)
313 objclass
<tilemap
>().bind_multi(L
, {
314 {"draw", &tilemap::draw
},
315 {"set", &tilemap::set
},
316 {"get", &tilemap::get
},
317 {"scroll", &tilemap::scroll
},
318 {"getsize", &tilemap::getsize
},
319 {"getcsize", &tilemap::getcsize
},
321 if(width
* height
/ height
!= width
)
322 throw std::bad_alloc();
323 map
.resize(width
* height
);