Allow optional initial fill color for bitmaps
[lsnes.git] / src / lua / gui-bitmap.cpp
blobb501b401a09319c7d98c348de28e90949d0b6709
1 #include "core/lua-int.hpp"
2 #include "core/render.hpp"
3 #include "lua/bitmap.hpp"
4 #include <vector>
6 lua_bitmap::lua_bitmap(uint32_t w, uint32_t h)
8 width = w;
9 height = h;
10 pixels.resize(width * height);
11 memset(&pixels[0], 0, width * height);
14 lua_dbitmap::lua_dbitmap(uint32_t w, uint32_t h)
16 width = w;
17 height = h;
18 pixels.resize(width * height);
21 namespace
23 struct render_object_bitmap : public render_object
25 render_object_bitmap(int32_t _x, int32_t _y, lua_obj_pin<lua_bitmap>* _bitmap,
26 lua_obj_pin<lua_palette>* _palette) throw()
28 x = _x;
29 y = _y;
30 b = _bitmap;
31 b2 = NULL;
32 p = _palette;
35 render_object_bitmap(int32_t _x, int32_t _y, lua_obj_pin<lua_dbitmap>* _bitmap) throw()
37 x = _x;
38 y = _y;
39 b = NULL;
40 b2 = _bitmap;
41 p = NULL;
44 ~render_object_bitmap() throw()
46 delete b;
47 delete b2;
48 delete p;
51 void operator()(struct screen& scr) throw()
53 size_t pallim = 0;
54 size_t w, h;
55 premultiplied_color* palette;
56 if(b) {
57 palette = &p->object()->colors[0];
58 for(auto& c : p->object()->colors)
59 c.set_palette(scr);
60 pallim = p->object()->colors.size();
61 w = b->object()->width;
62 h = b->object()->height;
63 } else {
64 for(auto& c : b2->object()->pixels)
65 c.set_palette(scr);
66 w = b2->object()->width;
67 h = b2->object()->height;
70 int32_t xmin = 0;
71 int32_t xmax = w;
72 int32_t ymin = 0;
73 int32_t ymax = h;
74 clip_range(scr.originx, scr.width, x, xmin, xmax);
75 clip_range(scr.originy, scr.height, y, ymin, ymax);
76 for(int32_t r = ymin; r < ymax; r++) {
77 uint32_t* rptr = scr.rowptr(y + r + scr.originy);
78 size_t eptr = x + xmin + scr.originx;
79 if(b)
80 for(int32_t c = xmin; c < xmax; c++, eptr++) {
81 uint16_t i = b->object()->pixels[r * b->object()->width + c];
82 if(i < pallim)
83 palette[i].apply(rptr[eptr]);
85 else
86 for(int32_t c = xmin; c < xmax; c++, eptr++)
87 b2->object()->pixels[r * b2->object()->width + c].apply(rptr[eptr]);
90 private:
91 int32_t x;
92 int32_t y;
93 lua_obj_pin<lua_bitmap>* b;
94 lua_obj_pin<lua_dbitmap>* b2;
95 lua_obj_pin<lua_palette>* p;
98 function_ptr_luafun gui_bitmap("gui.bitmap_draw", [](lua_State* LS, const std::string& fname) -> int {
99 if(!lua_render_ctx)
100 return 0;
101 int32_t x = get_numeric_argument<int32_t>(LS, 1, fname.c_str());
102 int32_t y = get_numeric_argument<int32_t>(LS, 2, fname.c_str());
103 if(lua_class<lua_bitmap>::is(LS, 3)) {
104 lua_class<lua_bitmap>::get(LS, 3, fname.c_str());
105 lua_class<lua_palette>::get(LS, 4, fname.c_str());
106 auto b = lua_class<lua_bitmap>::pin(LS, 3, fname.c_str());
107 auto p = lua_class<lua_palette>::pin(LS, 4, fname.c_str());
108 lua_render_ctx->queue->create_add<render_object_bitmap>(x, y, b, p);
109 } else if(lua_class<lua_dbitmap>::is(LS, 3)) {
110 lua_class<lua_dbitmap>::get(LS, 3, fname.c_str());
111 auto b = lua_class<lua_dbitmap>::pin(LS, 3, fname.c_str());
112 lua_render_ctx->queue->create_add<render_object_bitmap>(x, y, b);
113 } else {
114 lua_pushstring(LS, "Expected BITMAP or DBITMAP as argument 3 for gui.bitmap_draw.");
115 lua_error(LS);
117 return 0;
120 function_ptr_luafun gui_cpalette("gui.palette_new", [](lua_State* LS, const std::string& fname) -> int {
121 lua_class<lua_palette>::create(LS);
122 return 1;
125 function_ptr_luafun gui_cbitmap("gui.bitmap_new", [](lua_State* LS, const std::string& fname) -> int {
126 uint32_t w = get_numeric_argument<uint32_t>(LS, 1, fname.c_str());
127 uint32_t h = get_numeric_argument<uint32_t>(LS, 2, fname.c_str());
128 bool d = get_boolean_argument(LS, 3, fname.c_str());
129 if(d) {
130 int64_t c = -1;
131 get_numeric_argument<int64_t>(LS, 4, c, fname.c_str());
132 lua_dbitmap* b = lua_class<lua_dbitmap>::create(LS, w, h);
133 for(size_t i = 0; i < b->width * b->height; i++)
134 b->pixels[i] = premultiplied_color(c);
135 } else {
136 uint16_t c = 0;
137 get_numeric_argument<uint16_t>(LS, 4, c, fname.c_str());
138 lua_bitmap* b = lua_class<lua_bitmap>::create(LS, w, h);
139 for(size_t i = 0; i < b->width * b->height; i++)
140 b->pixels[i] = c;
142 return 1;
145 function_ptr_luafun gui_epalette("gui.palette_set", [](lua_State* LS, const std::string& fname) -> int {
146 lua_palette* p = lua_class<lua_palette>::get(LS, 1, fname.c_str());
147 uint16_t c = get_numeric_argument<uint16_t>(LS, 2, fname.c_str());
148 int64_t nval = get_numeric_argument<int64_t>(LS, 3, fname.c_str());
149 premultiplied_color nc(nval);
150 if(p->colors.size() <= c);
151 p->colors.resize(static_cast<uint32_t>(c) + 1);
152 p->colors[c] = nc;
153 return 0;
156 function_ptr_luafun pset_bitmap("gui.bitmap_pset", [](lua_State* LS, const std::string& fname) -> int {
157 uint32_t x = get_numeric_argument<uint32_t>(LS, 2, fname.c_str());
158 uint32_t y = get_numeric_argument<uint32_t>(LS, 3, fname.c_str());
159 if(lua_class<lua_bitmap>::is(LS, 1)) {
160 lua_bitmap* b = lua_class<lua_bitmap>::get(LS, 1, fname.c_str());
161 uint16_t c = get_numeric_argument<uint16_t>(LS, 4, fname.c_str());
162 if(x >= b->width || y >= b->height)
163 return 0;
164 b->pixels[y * b->width + x] = c;
165 } else if(lua_class<lua_dbitmap>::is(LS, 1)) {
166 lua_dbitmap* b = lua_class<lua_dbitmap>::get(LS, 1, fname.c_str());
167 int64_t c = get_numeric_argument<int64_t>(LS, 4, fname.c_str());
168 if(x >= b->width || y >= b->height)
169 return 0;
170 b->pixels[y * b->width + x] = premultiplied_color(c);
171 } else {
172 lua_pushstring(LS, "Expected BITMAP or DBITMAP as argument 1 for gui.bitmap_pset.");
173 lua_error(LS);
175 return 0;
178 function_ptr_luafun size_bitmap("gui.bitmap_size", [](lua_State* LS, const std::string& fname) -> int {
179 if(lua_class<lua_bitmap>::is(LS, 1)) {
180 lua_bitmap* b = lua_class<lua_bitmap>::get(LS, 1, fname.c_str());
181 lua_pushnumber(LS, b->width);
182 lua_pushnumber(LS, b->height);
183 } else if(lua_class<lua_dbitmap>::is(LS, 1)) {
184 lua_dbitmap* b = lua_class<lua_dbitmap>::get(LS, 1, fname.c_str());
185 lua_pushnumber(LS, b->width);
186 lua_pushnumber(LS, b->height);
187 } else {
188 lua_pushstring(LS, "Expected BITMAP or DBITMAP as argument 1 for gui.bitmap_size.");
189 lua_error(LS);
191 return 2;
194 function_ptr_luafun blit_bitmap("gui.bitmap_blit", [](lua_State* LS, const std::string& fname) -> int {
195 uint32_t dx = get_numeric_argument<uint32_t>(LS, 2, fname.c_str());
196 uint32_t dy = get_numeric_argument<uint32_t>(LS, 3, fname.c_str());
197 uint32_t sx = get_numeric_argument<uint32_t>(LS, 5, fname.c_str());
198 uint32_t sy = get_numeric_argument<uint32_t>(LS, 6, fname.c_str());
199 uint32_t w = get_numeric_argument<uint32_t>(LS, 7, fname.c_str());
200 uint32_t h = get_numeric_argument<uint32_t>(LS, 8, fname.c_str());
201 int64_t ck = 0x100000000ULL;
202 get_numeric_argument<int64_t>(LS, 9, ck, fname.c_str());
203 bool nck = false;
204 premultiplied_color pck(ck);
205 uint32_t ckorig = pck.orig;
206 uint16_t ckoriga = pck.origa;
207 if(ck == 0x100000000ULL)
208 nck = true;
209 if(lua_class<lua_bitmap>::is(LS, 1) && lua_class<lua_bitmap>::is(LS, 4)) {
210 lua_bitmap* db = lua_class<lua_bitmap>::get(LS, 1, fname.c_str());
211 lua_bitmap* sb = lua_class<lua_bitmap>::get(LS, 4, fname.c_str());
212 while((dx + w > db->width || sx + w > sb->width) && w > 0)
213 w--;
214 while((dy + h > db->height || sy + h > sb->height) && h > 0)
215 h--;
216 size_t sidx = sy * sb->width + sx;
217 size_t didx = dy * db->width + dx;
218 size_t srskip = sb->width - w;
219 size_t drskip = db->width - w;
220 for(uint32_t j = 0; j < h; j++) {
221 for(uint32_t i = 0; i < w; i++) {
222 uint16_t pix = sb->pixels[sidx];
223 if(pix != ck) //No need to check nck, as that value is out of range.
224 db->pixels[didx] = pix;
225 sidx++;
226 didx++;
228 sidx += srskip;
229 didx += drskip;
231 } else if(lua_class<lua_dbitmap>::is(LS, 1) && lua_class<lua_dbitmap>::is(LS, 1)) {
232 lua_dbitmap* db = lua_class<lua_dbitmap>::get(LS, 1, fname.c_str());
233 lua_dbitmap* sb = lua_class<lua_dbitmap>::get(LS, 4, fname.c_str());
234 while((dx + w > db->width || sx + w > sb->width) && w > 0)
235 w--;
236 while((dy + h > db->height || sy + h > sb->height) && h > 0)
237 h--;
238 size_t sidx = sy * sb->width + sx;
239 size_t didx = dy * db->width + dx;
240 size_t srskip = sb->width - w;
241 size_t drskip = db->width - w;
242 for(uint32_t j = 0; j < h; j++) {
243 for(uint32_t i = 0; i < w; i++) {
244 premultiplied_color pix = sb->pixels[sidx];
245 if(pix.orig != ckorig || pix.origa != ckoriga || nck)
246 db->pixels[didx] = pix;
247 sidx++;
248 didx++;
250 sidx += srskip;
251 didx += drskip;
253 } else {
254 lua_pushstring(LS, "Expected BITMAP or DBITMAP as arguments 1&4 for gui.bitmap_pset.");
255 lua_error(LS);
257 return 0;
260 function_ptr_luafun gui_loadbitmap("gui.bitmap_load", [](lua_State* LS, const std::string& fname) -> int {
261 std::string name = get_string_argument(LS, 1, fname.c_str());
262 uint32_t w, h;
263 auto bitmap = lua_loaded_bitmap::load(name);
264 if(bitmap.d) {
265 lua_dbitmap* b = lua_class<lua_dbitmap>::create(LS, bitmap.w, bitmap.h);
266 for(size_t i = 0; i < bitmap.w * bitmap.h; i++)
267 b->pixels[i] = premultiplied_color(bitmap.bitmap[i]);
268 return 1;
269 } else {
270 lua_bitmap* b = lua_class<lua_bitmap>::create(LS, bitmap.w, bitmap.h);
271 lua_palette* p = lua_class<lua_palette>::create(LS);
272 for(size_t i = 0; i < bitmap.w * bitmap.h; i++)
273 b->pixels[i] = bitmap.bitmap[i];
274 p->colors.resize(bitmap.palette.size());
275 for(size_t i = 0; i < bitmap.palette.size(); i++)
276 p->colors[i] = premultiplied_color(bitmap.palette[i]);
277 return 2;
281 function_ptr_luafun gui_dpalette("gui.palette_debug", [](lua_State* LS, const std::string& fname) -> int {
282 lua_palette* p = lua_class<lua_palette>::get(LS, 1, fname.c_str());
283 size_t i = 0;
284 for(auto c : p->colors)
285 messages << "Color #" << (i++) << ": " << c.orig << ":" << c.origa << std::endl;
286 return 0;
290 DECLARE_LUACLASS(lua_palette, "PALETTE");
291 DECLARE_LUACLASS(lua_bitmap, "BITMAP");
292 DECLARE_LUACLASS(lua_dbitmap, "DBITMAP");