summaryrefslogtreecommitdiff
path: root/apps/plugins/lua/rocklib.c
diff options
context:
space:
mode:
authorWilliam Wilgus <me.theuser@yahoo.com>2018-05-28 17:56:06 +0200
committerWilliam Wilgus <me.theuser@yahoo.com>2018-07-22 18:05:02 +0200
commit2daec3d3c3d84e7176a22bc073ca5530e8e44c6d (patch)
tree0f7e64ed5abd305fe80a7fbfabf79d2a9374ed4f /apps/plugins/lua/rocklib.c
parent19b2964d78b2ad6624a0e7cddd0ac6a49082cca4 (diff)
downloadrockbox-2daec3d3c3d84e7176a22bc073ca5530e8e44c6d.tar.gz
rockbox-2daec3d3c3d84e7176a22bc073ca5530e8e44c6d.zip
Rocklua -- Extend / Fix rliImage
Some devices(1-bit / 2-bit displays) have packed bit formats that need to be unpacked in order to work on them at a pixel level. This caused a few issues on 1 & 2-bit devices: Greatly Oversized data arrays for bitmaps Improper handling of native image data Framebuffer data was near unusable without jumping through hoops Conversion between native addressing and per pixel addressing incurs extra overhead but it is much faster to do it on the 'C' side rather than in lua. Not to mention the advantage of a unified interface for the end programer ------------------------------------------------------------------- Adds a sane way to access each pixel of image data Adds: -------------------------------------------------------------------- img:clear([color],[x1],[y1],[x2],[y2]) (set whole image or a portion to a particular value) -------------------------------------------------------------------- img:invert([x1],[y1],[x2],[y2]) (inverts whole image or a portion) -------------------------------------------------------------------- img:marshal([x1],[y1],[x2],[y2],[funct]) (calls funct for each point defined by rect of x1,y1 x2,y2 returns value and allows setting value of each point return nil to terminate early) -------------------------------------------------------------------- img:points([x1],[y1],[x2],[y2],[dx],[dy]) (returns iterator function that steps delta-x and delta-y pixels each call returns value of pixel each call but doesn't allow setting to a new value compare to lua pairs method) -------------------------------------------------------------------- img:copy(src,[x1],[y1],[x2],[y2],[w],[h],[clip][operation][clr/funct]) (copies all or part of an image -- straight copy or special ops optionally calls funct for each point defined by rect of x1, y1, w, h and x2, y2, w, h for dest and src images returns value of dst and src and allows setting value of each point return nil to terminate early) -------------------------------------------------------------------- img:line(x1, y1, x2, y2, color) -------------------------------------------------------------------- img:ellipse(x1, y1, x2, y2, color, [fillcolor] -------------------------------------------------------------------- Fixed handling of 2-bit vertical integrated screens Added direct element access for saving / restoring native image etc. Added more data to tostring() handler and a way to access individual items Added equals method to see if two variables reference the same image address (doesn't check if two separate images contain the same 'picture') Optimized get and set routines Fixed out of bound x coord access shifting to next line Added lua include files to expose new functionality Finished image saving routine Static allocation of set_viewport struct faster + saves ram over dynamic Cleaned up code Fixed pixel get/set for 1/2 bit devices ------------------------------------------------------------------------- Example lua script to follow on forums ------------------------------------------------------------------------- Change-Id: I7b9c1fd699442fb683760f781021091786c18509
Diffstat (limited to 'apps/plugins/lua/rocklib.c')
-rw-r--r--apps/plugins/lua/rocklib.c1253
1 files changed, 1165 insertions, 88 deletions
diff --git a/apps/plugins/lua/rocklib.c b/apps/plugins/lua/rocklib.c
index 2268063d3f..ced83a51df 100644
--- a/apps/plugins/lua/rocklib.c
+++ b/apps/plugins/lua/rocklib.c
@@ -9,6 +9,7 @@
9 * 9 *
10 * Copyright (C) 2008 Dan Everton (safetydan) 10 * Copyright (C) 2008 Dan Everton (safetydan)
11 * Copyright (C) 2009 Maurus Cuelenaere 11 * Copyright (C) 2009 Maurus Cuelenaere
12 * Copyright (C) 2017 William Wilgus
12 * 13 *
13 * This program is free software; you can redistribute it and/or 14 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License 15 * modify it under the terms of the GNU General Public License
@@ -47,127 +48,1215 @@
47 48
48 49
49/* 50/*
50 * ----------------------------- 51 * -----------------------------------------------------------------------------
51 * 52 *
52 * Rockbox Lua image wrapper 53 * Rockbox Lua image wrapper
53 * 54 *
54 * ----------------------------- 55 * Some devices(1-bit / 2-bit displays) have packed bit formats that
56 * need to be unpacked in order to work on them at a pixel level.
57 *
58 * The internal formats of these devices do not follow the same paradigm
59 * for image sizes either; We still display the actual width and height to
60 * the user but store stride based on the native values
61 *
62 * Conversion between native addressing and per pixel addressing
63 * incurs extra overhead but it is much faster to do it
64 * on the 'C' side rather than in lua.
65 *
66 * -----------------------------------------------------------------------------
55 */ 67 */
56 68
69#ifdef HAVE_LCD_BITMAP
70#define RLI_EXTENDED
71#endif
72
57#define ROCKLUA_IMAGE "rb.image" 73#define ROCKLUA_IMAGE "rb.image"
74#define ERR_IDX_RANGE "index out of range"
75#define ERR_DATA_OVF "data overflow"
76
77/* mark for RLI to LUA Interface functions (luaState *L) is the only argument */
78#define RLI_LUA static int
79
80#ifndef ABS
81#define ABS(a)(((a) < 0) ? - (a) :(a))
82#endif
83
84#ifndef LCD_BLACK
85#define LCD_BLACK 0x0
86#endif
87
58struct rocklua_image 88struct rocklua_image
59{ 89{
60 int width; 90 int width;
61 int height; 91 int height;
92 int stride;
93 size_t elems;
62 fb_data *data; 94 fb_data *data;
63 fb_data dummy[1][1]; 95 fb_data dummy[1];
64}; 96};
65 97
66static void rli_wrap(lua_State *L, fb_data *src, int width, int height) 98/* holds iterator data for rlimages */
99struct rli_iter_d
67{ 100{
68 struct rocklua_image *a = (struct rocklua_image *)lua_newuserdata(L, sizeof(struct rocklua_image)); 101 struct rocklua_image *img;
102 fb_data *elem;
103 int x , y;
104 int x1, y1;
105 int x2, y2;
106 int dx, dy;
107};
69 108
70 luaL_getmetatable(L, ROCKLUA_IMAGE); 109/* __tostring information enums */
71 lua_setmetatable(L, -2); 110enum rli_info {RLI_INFO_ALL = 0, RLI_INFO_TYPE, RLI_INFO_WIDTH,
111 RLI_INFO_HEIGHT, RLI_INFO_ELEMS, RLI_INFO_BYTES,
112 RLI_INFO_DEPTH, RLI_INFO_FORMAT, RLI_INFO_ADDRESS};
72 113
73 a->width = width; 114#ifdef HAVE_LCD_COLOR
74 a->height = height; 115
75 a->data = src; 116static inline unsigned invert_color(unsigned rgb)
117{
118 uint8_t r = 0xFFU - RGB_UNPACK_RED((unsigned) rgb);
119 uint8_t g = 0xFFU - RGB_UNPACK_GREEN((unsigned) rgb);
120 uint8_t b = 0xFFU - RGB_UNPACK_BLUE((unsigned) rgb);
121
122 return LCD_RGBPACK(r, g, b);
76} 123}
124#else /* !HAVE_LCD_COLOR */
125
126#define invert_color(c) (~c)
127
128#endif /* HAVE_LCD_COLOR */
129
130
131#if (LCD_DEPTH > 2) /* no native to pixel mapping needed */
132
133#define pixel_to_fb(x, y, o, n) {(void) x; (void) y; do { } while (0);}
134#define pixel_to_native(x, y, xn, yn) {*xn = x; *yn = y;}
135#define init_pixelmask(x, y, m, p) do { } while (0)
136
137
138#else /* some devices need x | y coords shifted to match native format */
139
140static fb_data x_shift = 0;
141static fb_data y_shift = 0;
142static fb_data xy_mask = 0;
143static const fb_data *pixelmask = NULL;
144
145/* conversion between packed native formats and individual pixel addressing */
146static inline void init_pixelmask(fb_data *x_shift, fb_data *y_shift,
147 fb_data *xy_mask, const fb_data **pixelmask)
148{
149
150#if(LCD_PIXELFORMAT == VERTICAL_PACKING) && LCD_DEPTH == 1
151 static const fb_data pixelmask_v1[8] =
152 {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};
153 *pixelmask = pixelmask_v1;
154
155 (void) x_shift;
156 *y_shift = 3U;
157 *xy_mask = ((1 << (*y_shift)) - 1);
158#elif(LCD_PIXELFORMAT == VERTICAL_PACKING) && LCD_DEPTH == 2
159 static const fb_data pixelmask_v2[4] = {0x03, 0x0C, 0x30, 0xC0};
160 *pixelmask = pixelmask_v2;
161
162 (void) x_shift;
163 *y_shift = 2U;
164 *xy_mask = ((1 << (*y_shift)) - 1);
165#elif(LCD_PIXELFORMAT == VERTICAL_INTERLEAVED) && LCD_DEPTH == 2
166 static const fb_data pixelmask_vi2[8] =
167 {0x0101, 0x0202, 0x0404, 0x0808, 0x1010, 0x2020, 0x4040, 0x8080};
168 *pixelmask = pixelmask_vi2;
169
170 (void) x_shift;
171 *y_shift = 3U;
172 *xy_mask = ((1 << (*y_shift)) - 1);
173#elif(LCD_PIXELFORMAT == HORIZONTAL_PACKING) && LCD_DEPTH == 2
174 /* MSB on left */
175 static const fb_data pixelmask_h2[4] = {0x03, 0x0C, 0x30, 0xC0};
176 *pixelmask = pixelmask_h2;
177
178 (void) y_shift;
179 *x_shift = 2U;
180 *xy_mask = ((1 << (*x_shift)) - 1);
181#else
182 #warning Unknown Pixel Format
183#endif /* LCD_PIXELFORMAT */
184
185} /* init_pixelmask */
186
187static inline void pixel_to_native(int x, int y, int *x_native, int *y_native)
188{
189 *x_native = ((x - 1) >> x_shift) + 1;
190 *y_native = ((y - 1) >> y_shift) + 1;
191} /* pixel_to_native */
192
193static inline fb_data set_masked_pixel(fb_data old,
194 fb_data new,
195 fb_data mask,
196 int bit_n)
197{
198 /*equivalent of: (old & (~mask)) | ((new << bit_n) & mask);*/
199 return old ^ ((old ^ (new << bit_n)) & mask);
200
201} /* set_masked_pixel */
202
203static inline fb_data get_masked_pixel(fb_data val, fb_data mask, int bit_n)
204{
205 val = val & mask;
206 return val >> bit_n;
207} /* get_masked_pixel */
208
209/* conversion between packed native formats and individual pixel addressing */
210static void pixel_to_fb(int x, int y, fb_data *oldv, fb_data *newv)
211{
212 fb_data mask;
213 int bit_n;
214
215#if(LCD_PIXELFORMAT == VERTICAL_INTERLEAVED) && LCD_DEPTH == 2
216 (void) x;
217 const uint16_t greymap_vi2[4] = {0x0000, 0x0001, 0x0100, 0x0101};
218
219 bit_n = (y - 1) & xy_mask;
220 mask = pixelmask[bit_n];
221
222 *newv = greymap_vi2[*newv &(0x3)]; /* [0-3] => greymap */
223 *newv = set_masked_pixel(*oldv, *newv, mask, bit_n);
224
225 *oldv = get_masked_pixel(*oldv, mask, bit_n);
226
227 if((*oldv) > 1) /* greymap => [0-3] */
228 *oldv = ((*oldv) & 0x1U) + 2U; /* 2, 3 */
229 else
230 *oldv &= 1U; /* 0, 1 */
231
232#elif(LCD_DEPTH <= 2)
233 if(y_shift)
234 bit_n = (y - 1) & xy_mask;
235 else if(x_shift)
236 bit_n = xy_mask - ((x - 1) & xy_mask); /*MSB on left*/
237
238 if(y_shift || x_shift)
239 {
240 mask = pixelmask[bit_n];
241 bit_n *= LCD_DEPTH;
242
243 *newv = set_masked_pixel(*oldv, *newv, mask, bit_n);
77 244
78static fb_data* rli_alloc(lua_State *L, int width, int height) 245 *oldv = get_masked_pixel(*oldv, mask, bit_n);
246 }
247#else
248 #error Unknown Pixel Format
249#endif /* LCD_PIXELFORMAT == VERTICAL_INTERLEAVED && LCD_DEPTH == 2 */
250} /* pixel_to_fb */
251
252#endif /* (LCD_DEPTH > 2) no native to pixel mapping needed */
253
254/* Internal worker functions for image data array *****************************/
255
256static inline void swap_int(bool swap, int *v1, int *v2)
79{ 257{
80 size_t nbytes = sizeof(struct rocklua_image) + ((width*height) - 1) * sizeof(fb_data); 258 if(swap)
81 struct rocklua_image *a = (struct rocklua_image *)lua_newuserdata(L, nbytes); 259 {
260 int val = *v1;
261 *v1 = *v2;
262 *v2 = val;
263 }
264} /* swap_int */
265
266/* Throws error if x or y are out of bounds notifies user which narg indice
267 the out of bound variable originated */
268static void bounds_check_xy(lua_State *L, struct rocklua_image *img,
269 int nargx, int x, int nargy, int y)
270{
271 luaL_argcheck(L, x <= img->width && x > 0, nargx, ERR_IDX_RANGE);
272 luaL_argcheck(L, y <= img->height && y > 0, nargy, ERR_IDX_RANGE);
273} /* bounds_check_xy */
274
275static struct rocklua_image* rli_checktype(lua_State *L, int arg)
276{
277 void *ud = luaL_checkudata(L, arg, ROCKLUA_IMAGE);
278
279 luaL_argcheck(L, ud != NULL, arg, "'" ROCKLUA_IMAGE "' expected");
280
281 return (struct rocklua_image*) ud;
282} /* rli_checktype */
283
284static struct rocklua_image * alloc_rlimage(lua_State *L, bool alloc_data,
285 int width, int height)
286{
287 /* rliimage is pushed on the stack it is up to you to pop it */
288 struct rocklua_image *img;
289
290 const size_t sz_header = sizeof(struct rocklua_image);
291 size_t sz_data = 0;
292 size_t n_elems;
293
294 int w_native;
295 int h_native;
296
297 pixel_to_native(width, height, &w_native, &h_native);
298
299 n_elems = (size_t)(w_native * h_native);
300
301 if(alloc_data) /* if this a new image we need space for image data */
302 sz_data = n_elems * sizeof(fb_data);
303
304 /* newuserdata pushes the userdata onto the stack */
305 img = (struct rocklua_image *) lua_newuserdata(L, sz_header + sz_data);
82 306
83 luaL_getmetatable(L, ROCKLUA_IMAGE); 307 luaL_getmetatable(L, ROCKLUA_IMAGE);
84 lua_setmetatable(L, -2); 308 lua_setmetatable(L, -2);
85 309
86 a->width = width; 310 /* apparent w/h is stored but behind the scenes native w/h is used */
87 a->height = height; 311 img->width = width;
88 a->data = &a->dummy[0][0]; 312 img->height = height;
313 img->stride = w_native;
314 img->elems = n_elems;
315
316 return img;
317} /* alloc_rlimage */
318
319static inline void rli_wrap(lua_State *L, fb_data *src, int width, int height)
320{
321 /* rliimage is pushed on the stack it is up to you to pop it */
322 struct rocklua_image *a = alloc_rlimage(L, false, width, height);
323
324 a->data = src;
325} /* rli_wrap */
326
327static inline fb_data* rli_alloc(lua_State *L, int width, int height)
328{
329 /* rliimage is pushed on the stack it is up to you to pop it */
330 struct rocklua_image *a = alloc_rlimage(L, true, width, height);
331
332 a->data = &a->dummy[0]; /* ref to beginning of alloc'd img data */
89 333
90 return a->data; 334 return a->data;
91} 335} /* rli_alloc */
336
337static inline fb_data data_setget(fb_data *elem, int x, int y, fb_data *val)
338{
339 fb_data old_val = 0;
340 fb_data new_val = 0;
341
342 if(elem)
343 {
344 old_val = *elem;
345
346 if(val)
347 {
348 new_val = *val;
349 pixel_to_fb(x, y, &old_val, &new_val);
350 *elem = new_val;
351 }
352 else
353 pixel_to_fb(x, y, &old_val, &new_val);
354 }
355
356 return old_val;
357} /* data_setget */
358
359static inline fb_data data_set(fb_data *elem, int x, int y, fb_data *new_val)
360{
361 /* get and set share the same underlying function */
362 return data_setget(elem, x, y, new_val);
363} /* data_set */
364
365static inline fb_data data_get(fb_data *elem, int x, int y)
366{
367 /* get and set share the same underlying function */
368 return data_setget(elem, x, y, NULL);
369} /* data_get */
370
371static fb_data* rli_get_element(struct rocklua_image* img, int x, int y)
372{
373 int stride = img->stride;
374 size_t elements = img->elems;
375 fb_data *data = img->data;
376
377 pixel_to_native(x, y, &x, &y);
378
379 /* row major address */
380 size_t data_address = (stride * (y - 1)) + (x - 1);
381
382 /* x needs bound between 0 and stride otherwise overflow to prev/next y */
383 if(x <= 0 || x > stride || data_address >= elements)
384 return NULL; /* data overflow */
385
386 return &data[data_address]; /* return element address */
387} /* rli_get_element */
388
389/* Lua to C Interface for pixel set and get functions */
390static int rli_setget(lua_State *L, bool is_get)
391{
392 /*(set) (dst*, [x1, y1, clr, clip]) */
393 /*(get) (dst*, [x1, y1, clip]) */
394 struct rocklua_image *a = rli_checktype(L, 1);
395 int x = luaL_checkint(L, 2);
396 int y = luaL_checkint(L, 3);
397
398 fb_data clr = 0; /* Arg 4 is color if set element */
399 fb_data *p_clr = &clr;
400
401 int clip_narg;
402
403 if(is_get) /* get element */
404 {
405 p_clr = NULL;
406 clip_narg = 4;
407 }
408 else /* set element */
409 {
410 clr = FB_SCALARPACK((unsigned) luaL_checknumber(L, 4));
411 clip_narg = 5;
412 }
413
414 fb_data *element = rli_get_element(a, x, y);
415
416 if(!element)
417 {
418 if(!luaL_optboolean(L, clip_narg, false)) /* Error if !clip */
419 bounds_check_xy(L, a, 2, x, 3, y);
420
421 lua_pushnil(L);
422 return 1;
423 }
424
425 lua_pushnumber(L, FB_UNPACK_SCALAR_LCD(data_setget(element, x, y, p_clr)));
426
427 /* returns old value */
428 return 1;
429} /* rli_setget */
430
431#ifdef RLI_EXTENDED
432static bool init_rli_iter(struct rli_iter_d *d,
433 struct rocklua_image *img,
434 int x1, int y1,
435 int x2, int y2,
436 int dx, int dy,
437 bool swx, bool swy)
438{
439
440 swap_int((swx), &x1, &x2);
441 swap_int((swy), &y1, &y2);
442
443 /* stepping in the correct x direction ? */
444 if((dx > 0 && x1 > x2) || (dx < 0 && x1 < x2))
445 dx = -dx;
446
447 /* stepping in the correct y direction ? */
448 if((dy > 0 && y1 > y2) || (dy < 0 && y1 < y2))
449 dy = -dy;
450
451 d->img = img;
452 d->x = x1;
453 d->y = y1;
454 d->x1 = x1;
455 d->y1 = y1;
456 d->x2 = x2;
457 d->y2 = y2;
458 d->dx = dx;
459 d->dy = dy;
460 d->elem = rli_get_element(img, d->x, d->y);
461
462 return(dx != 0 || dy != 0);
463} /* init_rli_iter */
464
465/* steps to the next point(x, y) by delta x/y, stores pointer to element
466 returns true if x & y haven't reached x2 & y2
467 if limit reached - element set to NULL, deltas set to 0 & false returned
468*/
469static bool next_rli_iter(struct rli_iter_d *d)
470{
471 if((d->dx > 0 && d->x < d->x2) || (d->dx < 0 && d->x > d->x2))
472 d->x += d->dx;
473 else if((d->dy > 0 && d->y < d->y2) || (d->dy < 0 && d->y > d->y2))
474 {
475 d->x = d->x1; /* Reset x*/
476 d->y += d->dy;
477 }
478 else
479 {
480 d->elem = NULL;
481 d->dx = 0;
482 d->dy = 0;
483 return false;
484 }
485
486 d->elem = rli_get_element(d->img, d->x, d->y);
487
488 return true;
489} /* next_rli_iter */
490
491static int d_line(struct rocklua_image *img,
492 int x1, int y1,
493 int x2, int y2,
494 fb_data *clr,
495 bool clip)
496{
497 /* NOTE! clr passed as pointer */
498 /* Bresenham midpoint line algorithm */
499 fb_data *element;
500
501 int r_a = x2 - x1; /* range of x direction called 'a' for now */
502 int r_b = y2 - y1; /* range of y direction called 'b' for now */
503
504 int s_a = 1; /* step of a direction */
505 int s_b = 1; /* step of b direction */
506
507 int d_err;
508 int numpixels;
509
510 int *a1 = &x1; /* pointer to the x var 'a' */
511 int *b1 = &y1; /* pointer to the y var 'b' */
512
513 if(r_a < 0) /* instead of negative range we will switch step instead */
514 {
515 r_a = -r_a;
516 s_a = -s_a;
517 }
518
519 if(r_b < 0) /* instead of negative range we will switch step instead */
520 {
521 r_b = -r_b;
522 s_b = -s_b;
523 }
524
525 x2 += s_a; /* add 1 extra point to make the whole line */
526 y2 += s_b; /* add 1 extra point */
527
528 if(r_b > r_a) /*if rangeY('b') > rangeX('a') swap their identities */
529 {
530 a1 = &y1;
531 b1 = &x1;
532 swap_int((true), &r_a, &r_b);
533 swap_int((true), &s_a, &s_b);
534 }
535
536 d_err = ((r_b << 1) - r_a) >> 1; /* preload err of 1 step (px centered) */
537
538 numpixels = r_a + 1;
539
540 r_a -= r_b; /* pre-subtract 'a' - 'b' */
541
542 for(;numpixels > 0; numpixels--)
543 {
544 element = rli_get_element(img, x1, y1);
545 if(element || clip)
546 data_set(element, x1, y1, clr);
547 else
548 return numpixels + 1; /* Error */
549
550 if(d_err >= 0) /* 0 is our target midpoint(exact point on the line) */
551 {
552 *b1 += s_b; /* whichever axis is in 'b' stepped(-1 or +1) */
553 d_err -= r_a;
554 }
555 else
556 d_err += r_b; /* only add 'b' when d_err < 0 */
557
558 *a1 += s_a; /* whichever axis is in 'a' stepped(-1 or +1) */
559 }
560
561 return 0;
562} /* d_line */
563
564/* ellipse worker function */
565static int d_ellipse_elements(struct rocklua_image * img,
566 int x1, int y1,
567 int x2, int y2,
568 int sx, int sy,
569 fb_data *clr,
570 fb_data *fillclr,
571 bool clip)
572{
573 int ret = 0;
574 fb_data *element1, *element2, *element3, *element4;
575
576 if(fillclr && x1 - sx != x2 + sx)
577 {
578 ret |= d_line(img, x1, y1, x2, y1, fillclr, clip); /* I. II.*/
579 ret |= d_line(img, x1, y2, x2, y2, fillclr, clip); /* III.IV.*/
580 }
581
582 x1 -= sx; /* shift x & y */
583 y1 -= sy;
584 x2 += sx;
585 y2 += sy;
586
587 element1 = rli_get_element(img, x2, y1);
588 element2 = rli_get_element(img, x1, y1);
589 element3 = rli_get_element(img, x1, y2);
590 element4 = rli_get_element(img, x2, y2);
591
592 if(clip || (element1 && element2 && element3 && element4))
593 {
594 data_set(element1, x2, y1, clr); /* I. Quadrant +x +y */
595 data_set(element2, x1, y1, clr); /* II. Quadrant -x +y */
596 data_set(element3, x1, y2, clr); /* III. Quadrant -x -y */
597 data_set(element4, x2, y2, clr); /* IV. Quadrant +x -y */
598 }
599 else
600 ret = 2; /* ERROR */
601
602 return ret;
603} /* d_ellipse_elements */
604
605static int d_ellipse(struct rocklua_image *img,
606 int x1, int y1,
607 int x2, int y2,
608 fb_data *clr,
609 fb_data *fillclr,
610 bool clip)
611{
612 /* NOTE! clr and fillclr passed as pointers */
613 /* Rasterizing algorithm derivative of work by Alois Zing */
614#if LCD_WIDTH > 1024 || LCD_HEIGHT > 1024
615 /* Prevents overflow on large screens */
616 double dx, dy, err, e2;
617#else
618 long dx, dy, err, e2;
619#endif
620
621 int ret = 0;
622
623 int a = ABS(x2 - x1); /* diameter */
624 int b = ABS(y2 - y1); /* diameter */
625
626 if(a == 0 || b == 0 || !clr)
627 return ret; /* not an error but nothing to display */
628
629 int b1 = (b & 1);
630 b = b - (1 - b1);
631
632 int a2 = (a * a);
633 int b2 = (b * b);
634
635 dx = ((1 - a) * b2) >> 1; /* error increment */
636 dy = (b1 * a2) >> 1; /* error increment */
637
638 err = dx + dy + b1 * a2; /* error of 1.step */
639
640 /* if called with swapped points .. exchange them */
641 swap_int((x1 > x2), &x1, &x2);
642 swap_int((y1 > y2), &y1, &y2);
643
644 y1 += (b + 1) >> 1;
645 y2 = y1 - b1;
646
647 do
648 {
649 ret = d_ellipse_elements(img, x1, y1, x2, y2, 0, 0, clr, fillclr, clip);
650
651 e2 = err;
652
653 /* using division because you can't use bit shift on doubles.. */
654 if(e2 <= (dy / 2)) /* target midpoint - y step */
655 {
656 y1++;
657 y2--;
658 dy += a2;
659 err += dy;
660 }
661
662 if(e2 >= (dx / 2) || err > (dy / 2)) /* target midpoint - x step */
663 {
664 x1++;
665 x2--;
666 dx += b2;
667 err += dx;
668 }
669
670 } while(ret == 0 && x1 <= x2);
671
672 while (ret == 0 && y1 - y2 < b) /* early stop of flat ellipse a=1 finish tip */
673 {
674 ret = d_ellipse_elements(img, x1, y1, x2, y2, 1, 0, clr, fillclr, clip);
675
676 y1++;
677 y2--;
678 }
679
680 return ret;
681} /* d_ellipse */
682
683/* Lua to C Interface for line and ellipse */
684static int rli_line_ellipse(lua_State *L, bool is_ellipse)
685{
686 struct rocklua_image *a = rli_checktype(L, 1);
687
688 int x1 = luaL_checkint(L, 2);
689 int y1 = luaL_checkint(L, 3);
690 int x2 = luaL_optint(L, 4, x1);
691 int y2 = luaL_optint(L, 5, y1);
692
693 fb_data clr = FB_SCALARPACK((unsigned) luaL_checknumber(L, 6));
694
695 fb_data fillclr; /* fill color is index 7 if is_ellipse */
696 fb_data *p_fillclr = NULL;
697
698 bool clip;
699 int clip_narg;
700
701 if(is_ellipse)
702 clip_narg = 8;
703 else
704 clip_narg = 7;
705
706 clip = luaL_optboolean(L, clip_narg, false);
707
708 if(!clip)
709 {
710 bounds_check_xy(L, a, 2, x1, 3, y1);
711 bounds_check_xy(L, a, 4, x2, 5, y2);
712 }
713
714 if(is_ellipse)
715 {
716 if(!lua_isnoneornil(L, 7))
717 {
718 fillclr = FB_SCALARPACK((unsigned) luaL_checkint(L, 7));
719 p_fillclr = &fillclr;
720 }
721
722 luaL_argcheck(L, d_ellipse(a, x1, y1, x2, y2, &clr, p_fillclr, clip) == 0,
723 1, ERR_DATA_OVF);
724 }
725 else
726 luaL_argcheck(L, d_line(a, x1, y1, x2, y2, &clr, clip) == 0,
727 1, ERR_DATA_OVF);
728
729 return 0;
730} /* rli_line_ellipse */
731
732/* Pushes lua function from Stack at position narg to top of stack
733 and puts a reference in the global registry for later use */
734static inline int register_luafunc(lua_State *L, int narg_funct)
735{
736 lua_pushvalue(L, narg_funct); /* lua function */
737 int lf_ref = luaL_ref(L, LUA_REGISTRYINDEX);
738 lua_settop(L, 0); /* clear C stack for use by lua function */
739 return lf_ref;
740} /* register_luafunc */
741
742/* User defined pixel manipulations through rli_copy, rli_marshal */
743static int custom_transform(lua_State *L,
744 struct rli_iter_d *ds,
745 struct rli_iter_d *ss,
746 int op,
747 fb_data *color)
748{
749 (void) color;
750
751 fb_data dst;
752 fb_data src;
753
754 unsigned int params = 3;
755 int ret = 0;
756
757 lua_rawgeti(L, LUA_REGISTRYINDEX, op);
758
759 dst = data_get(ds->elem, ds->x, ds->y);
760 lua_pushnumber(L, FB_UNPACK_SCALAR_LCD(dst));
761 lua_pushnumber(L, ds->x);
762 lua_pushnumber(L, ds->y);
763
764 if(ss) /* Allows src to be omitted */
765 {
766 params += 3;
767 src = data_get(ss->elem, ss->x, ss->y);
768 lua_pushnumber(L, FB_UNPACK_SCALAR_LCD(src));
769 lua_pushnumber(L, ss->x);
770 lua_pushnumber(L, ss->y);
771 }
772
773 lua_call(L, params, 2); /* call custom function w/ n-params & 2 ret */
774
775 if(!lua_isnoneornil(L, -2))
776 {
777 ret = 1;
778 dst = FB_SCALARPACK((unsigned) luaL_checknumber(L, -2));
779 data_set(ds->elem, ds->x, ds->y, &dst);
780 }
781
782 if(!lua_isnoneornil(L, -1) && ss)
783 {
784 ret |= 2;
785 src = FB_SCALARPACK((unsigned) luaL_checknumber(L, -1));
786 data_set(ss->elem, ss->x, ss->y, &src);
787 }
788
789 lua_pop(L, 2);
790 return ret; /* 0 signals iterator to stop */
791} /* custom_transform */
792
793/* Pre defined pixel manipulations through rli_copy */
794static int blit_transform(lua_State *L,
795 struct rli_iter_d *ds,
796 struct rli_iter_d *ss,
797 int op,
798 fb_data *color)
799{
800 (void) L;
801 fb_data clr = *color;
802 fb_data dst = data_get(ds->elem, ds->x, ds->y);
803 fb_data src;
804
805 /* Reuse 0 - 7 for src / clr blits*/
806 if(op >= 30 && op <= 37)
807 {
808 op -= 30;
809 src = clr;
810 }
811 else
812 src = data_get(ss->elem, ss->x, ss->y);
813
814 switch(op)
815 {
816 default:
817 /* case 30: */
818 case 0: { dst = src; break; }/* copyS/C */
819 /* case 31: */
820 case 1: { dst = src | dst; break; }/* DorS/C */
821 /* case 32: */
822 case 2: { dst = src ^ dst; break; }/* DxorS/C */
823 /* case 33: */
824 case 3: { dst = ~(src | dst); break; }/* nDorS/C */
825 /* case 34: */
826 case 4: { dst = (~src) | dst; break; }/* DornS/C */
827 /* case 35: */
828 case 5: { dst = src & dst; break; }/* DandS/C */
829 /* case 36: */
830 case 6: { dst = src & (~dst); break; }/* nDandS/C */
831 /* case 37: */
832 case 7: { dst = ~src; break; }/* notS/C */
833
834 /* mask blits */
835 case 8: { if(src != 0) { dst = clr; } break; }/* Sand */
836 case 9: { if(src == 0) { dst = clr; } break; }/* Snot */
837
838 case 10: { dst = src | clr; break; }/* SorC */
839 case 11: { dst = src ^ clr; break; }/* SxorC */
840 case 12: { dst = ~(src | clr); break; }/* nSorC */
841 case 13: { dst = src | (~clr); break; }/* SornC */
842 case 14: { dst = src & clr; break; }/* SandC */
843 case 15: { dst = (~src) & clr; break; }/* nSandC */
844 case 16: { dst |= (~src) | clr; break; }/* DornSorC */
845 case 17: { dst ^= (src & (dst ^ clr)); break; }/* DxorSandDxorC */
846
847 case 18: { if(src != clr) { dst = src; } break; }
848 case 19: { if(src == clr) { dst = src; } break; }
849 case 20: { if(src > clr) { dst = src; } break; }
850 case 21: { if(src < clr) { dst = src; } break; }
851
852 case 22: { if(dst != clr) { dst = src; } break; }
853 case 23: { if(dst == clr) { dst = src; } break; }
854 case 24: { if(dst > clr) { dst = src; } break; }
855 case 25: { if(dst < clr) { dst = src; } break; }
856
857 case 26: { if(dst != src) { dst = clr; } break; }
858 case 27: { if(dst == src) { dst = clr; } break; }
859 case 28: { if(dst > src) { dst = clr; } break; }
860 case 29: { if(dst < src) { dst = clr; } break; }
861
862 }/*switch op*/
863
864 data_set(ds->elem, ds->x, ds->y, &dst);
865 return 1;
866} /* blit_transform */
92 867
93static int rli_new(lua_State *L) 868static int invert_transform(lua_State *L,
869 struct rli_iter_d *ds,
870 struct rli_iter_d *ss,
871 int op,
872 fb_data *color)
94{ 873{
95 int width = luaL_checkint(L, 1); 874 (void) L;
96 int height = luaL_checkint(L, 2); 875 (void) color;
876 (void) op;
877 (void) ss;
878
879 fb_data val = invert_color(data_get(ds->elem, ds->x, ds->y));
880 data_set(ds->elem, ds->x, ds->y, &val);
881
882 return 1;
883} /* invert_transform */
884#endif /* RLI_EXTENDED */
885
886/* RLI to LUA Interface functions *********************************************/
887RLI_LUA rli_new(lua_State *L)
888{ /* [width, height] */
889 int width = luaL_optint(L, 1, LCD_WIDTH);
890 int height = luaL_optint(L, 2, LCD_HEIGHT);
891
892 luaL_argcheck(L, width > 0, 1, ERR_IDX_RANGE);
893 luaL_argcheck(L, height > 0, 2, ERR_IDX_RANGE);
97 894
98 rli_alloc(L, width, height); 895 rli_alloc(L, width, height);
99 896
100 return 1; 897 return 1;
101} 898}
102 899
103static struct rocklua_image* rli_checktype(lua_State *L, int arg) 900RLI_LUA rli_set(lua_State *L)
104{ 901{
105 void *ud = luaL_checkudata(L, arg, ROCKLUA_IMAGE); 902 /*(set) (dst*, [x1, y1, clr, clip]) */
106 luaL_argcheck(L, ud != NULL, arg, "'" ROCKLUA_IMAGE "' expected"); 903 /* get and set share the same underlying function */
107 return (struct rocklua_image*) ud; 904 return rli_setget(L, false);
905}
906
907RLI_LUA rli_get(lua_State *L)
908{
909 /*(get) (dst*, [x1, y1, clip]) */
910 /* get and set share the same underlying function */
911 return rli_setget(L, true);
108} 912}
109 913
110static int rli_width(lua_State *L) 914RLI_LUA rli_height(lua_State *L)
915{
916 struct rocklua_image *a = rli_checktype(L, 1);
917 lua_pushnumber(L, a->height);
918 return 1;
919}
920
921RLI_LUA rli_width(lua_State *L)
111{ 922{
112 struct rocklua_image *a = rli_checktype(L, 1); 923 struct rocklua_image *a = rli_checktype(L, 1);
113 lua_pushnumber(L, a->width); 924 lua_pushnumber(L, a->width);
114 return 1; 925 return 1;
115} 926}
116 927
117static int rli_height(lua_State *L) 928RLI_LUA rli_equal(lua_State *L)
118{ 929{
119 struct rocklua_image *a = rli_checktype(L, 1); 930 struct rocklua_image *a = rli_checktype(L, 1);
120 lua_pushnumber(L, a->height); 931 struct rocklua_image *b = rli_checktype(L, 2);
932 lua_pushboolean(L, a->data == b->data);
121 return 1; 933 return 1;
122} 934}
123 935
124static fb_data* rli_element(lua_State *L) 936RLI_LUA rli_size(lua_State *L)
125{ 937{
126 struct rocklua_image *a = rli_checktype(L, 1); 938 struct rocklua_image *a = rli_checktype(L, 1);
127 int x = luaL_checkint(L, 2); 939 lua_pushnumber(L, a->elems);
128 int y = luaL_checkint(L, 3); 940 return 1;
941}
942
943RLI_LUA rli_raw(lua_State *L)
944{
945 /*val = (img*, index, [new_val]) */
946 struct rocklua_image *a = rli_checktype(L, 1);
947
948 size_t i = (unsigned) luaL_checkint(L, 2);
949
950 fb_data val;
129 951
130 luaL_argcheck(L, 1 <= x && x <= a->width, 2, 952 luaL_argcheck(L, i > 0 && i <= (a->elems), 2, ERR_IDX_RANGE);
131 "index out of range");
132 luaL_argcheck(L, 1 <= y && y <= a->height, 3,
133 "index out of range");
134 953
135 /* return element address */ 954 lua_pushnumber(L, FB_UNPACK_SCALAR_LCD(a->data[i-1]));
136 return &a->data[a->width * (y - 1) + (x - 1)]; 955
956 if(!lua_isnoneornil(L, 3))
957 {
958 val = FB_SCALARPACK((unsigned) luaL_checknumber(L, 3));
959 a->data[i-1] = val;
960 }
961
962 return 1;
137} 963}
138 964
139static int rli_set(lua_State *L) 965RLI_LUA rli_tostring(lua_State *L)
140{ 966{
141 fb_data newvalue = FB_SCALARPACK((unsigned)luaL_checknumber(L, 4)); 967 /* (img, [infoitem]) */
142 *rli_element(L) = newvalue; 968 struct rocklua_image *a = rli_checktype(L, 1);
143 return 0; 969
970 int item = (unsigned) luaL_optint(L, 2, 0);
971 size_t bytes = a->elems * sizeof(fb_data);
972
973 switch(item)
974 {
975 default:
976 case RLI_INFO_ALL:
977 {
978 lua_pushfstring(L,
979 ROCKLUA_IMAGE ": %dx%d, %d elements, %d bytes, %d-bit depth, %d pack",
980 a->width, a->height, a->elems, bytes, LCD_DEPTH, LCD_PIXELFORMAT);
981 break;
982 }
983 case RLI_INFO_TYPE: { lua_pushfstring(L, ROCKLUA_IMAGE ); break; }
984 case RLI_INFO_WIDTH: { lua_pushfstring(L, "%d", a->width ); break; }
985 case RLI_INFO_HEIGHT: { lua_pushfstring(L, "%d", a->height ); break; }
986 case RLI_INFO_ELEMS: { lua_pushfstring(L, "%d", a->elems ); break; }
987 case RLI_INFO_BYTES: { lua_pushfstring(L, "%d", bytes ); break; }
988 case RLI_INFO_DEPTH: { lua_pushfstring(L, "%d", LCD_DEPTH ); break; }
989 case RLI_INFO_FORMAT: { lua_pushfstring(L, "%d", LCD_PIXELFORMAT); break; }
990 case RLI_INFO_ADDRESS: { lua_pushfstring(L, "%p", a->data); break; }
991 }
992
993 return 1;
994}
995
996#ifdef RLI_EXTENDED
997RLI_LUA rli_ellipse(lua_State *L)
998{
999 /* (dst*, x1, y1, x2, y2, [clr, fillclr, clip]) */
1000 /* line and ellipse share the same init function */
1001 return rli_line_ellipse(L, true);
144} 1002}
145 1003
146static int rli_get(lua_State *L) 1004RLI_LUA rli_line(lua_State *L)
147{ 1005{
148 lua_pushnumber(L, FB_UNPACK_SCALAR_LCD(*rli_element(L))); 1006 /* (dst*, x1, y1, [x2, y2, clr, clip]) */
1007 /* line and ellipse share the same init function */
1008 return rli_line_ellipse(L, false);
1009}
1010
1011RLI_LUA rli_iterator(lua_State *L) {
1012 /* see rli_iterator_factory */
1013 struct rli_iter_d *ds;
1014 ds = (struct rli_iter_d *) lua_touserdata(L, lua_upvalueindex(1));
1015
1016 if(ds->dx != 0 || ds->dy != 0)
1017 {
1018 lua_pushnumber(L, FB_UNPACK_SCALAR_LCD(data_get(ds->elem, ds->x, ds->y)));
1019
1020 lua_pushinteger(L, ds->x);
1021 lua_pushinteger(L, ds->y);
1022
1023 next_rli_iter(ds); /* load next element */
1024
1025 return 3;
1026 }
1027 return 0; /* nothing left to do */
1028}
1029
1030RLI_LUA rli_iterator_factory(lua_State *L) {
1031 /* (src*, [x1, y1, x2, y2, dx, dy]) */
1032 struct rocklua_image *a = rli_checktype(L, 1); /*image we wish to iterate*/
1033
1034 struct rli_iter_d *ds;
1035
1036 int x1 = luaL_optint(L, 2, 1);
1037 int y1 = luaL_optint(L, 3, 1);
1038 int x2 = luaL_optint(L, 4, a->width - x1 + 1);
1039 int y2 = luaL_optint(L, 5, a->height - y1 + 1);
1040 int dx = luaL_optint(L, 6, 1);
1041 int dy = luaL_optint(L, 7, 1);
1042
1043 /* create new iter + pushed onto stack */
1044 ds = (struct rli_iter_d *) lua_newuserdata(L, sizeof(struct rli_iter_d));
1045
1046 init_rli_iter(ds, a, x1, y1, x2, y2, dx, dy, false, false);
1047
1048 /* returns the iter function with embedded iter data(up values) */
1049 lua_pushcclosure(L, &rli_iterator, 1);
1050
149 return 1; 1051 return 1;
150} 1052}
151 1053
152static int rli_tostring(lua_State *L) 1054RLI_LUA rli_marshal(lua_State *L) /* also invert */
153{ 1055{
1056 /* (img*, [x1, y1, x2, y2, dx, dy, clip, function]) */
154 struct rocklua_image *a = rli_checktype(L, 1); 1057 struct rocklua_image *a = rli_checktype(L, 1);
155 lua_pushfstring(L, ROCKLUA_IMAGE ": %dx%d", a->width, a->height); 1058
156 return 1; 1059 struct rli_iter_d ds;
1060
1061 int x1 = luaL_optint(L, 2, 1);
1062 int y1 = luaL_optint(L, 3, 1);
1063 int x2 = luaL_optint(L, 4, a->width);
1064 int y2 = luaL_optint(L, 5, a->height);
1065 int dx = luaL_optint(L, 6, 1);
1066 int dy = luaL_optint(L, 7, 1);
1067 bool clip = luaL_optboolean(L, 8, false);
1068
1069 int lf_ref = LUA_NOREF; /* de-ref'd without consequence */
1070
1071 int (*rli_trans)(lua_State *, struct rli_iter_d *, struct rli_iter_d *, int, fb_data *);
1072 rli_trans = invert_transform; /* default transformation */
1073
1074 if(!clip)
1075 {
1076 bounds_check_xy(L, a, 2, x1, 3, y1);
1077 bounds_check_xy(L, a, 4, x2, 5, y2);
1078 }
1079
1080 init_rli_iter(&ds, a, x1, y1, x2, y2, dx, dy, false, false);
1081
1082 if(lua_isfunction(L, 9)) /* custom function */
1083 {
1084 rli_trans = custom_transform;
1085 lf_ref = register_luafunc(L, 9);
1086 }
1087
1088 do
1089 {
1090 luaL_argcheck(L, clip || (ds.elem != NULL), 1, ERR_DATA_OVF);
1091
1092 if(!(*rli_trans)(L, &ds, NULL, lf_ref, NULL))
1093 break; /* Custom op can quit early */
1094
1095 } while(next_rli_iter(&ds));
1096
1097 luaL_unref(L, LUA_REGISTRYINDEX, lf_ref); /* de-reference custom function */
1098 return 0;
1099}
1100
1101RLI_LUA rli_copy(lua_State *L)
1102{
1103 /* (dst*, src*, [d_x, d_y, s_x, s_y, x_off, y_off, clip, [op, funct/clr]]) */
1104 struct rocklua_image *d = rli_checktype(L, 1); /*dst*/
1105 struct rocklua_image *s = rli_checktype(L, 2); /*src*/
1106
1107 struct rli_iter_d ds; /*dst*/
1108 struct rli_iter_d ss; /*src*/
1109
1110 /* copy whole image if possible */
1111 if(s->elems == d->elems && s->width == d->width && lua_gettop(L) < 3)
1112 {
1113 memcpy(d->data, s->data, d->elems * sizeof(fb_data));
1114 return 0;
1115 }
1116
1117 int d_x = luaL_optint(L, 3, 1);
1118 int d_y = luaL_optint(L, 4, 1);
1119 int s_x = luaL_optint(L, 5, 1);
1120 int s_y = luaL_optint(L, 6, 1);
1121
1122 int w = MIN(d->width - d_x, s->width - s_x);
1123 int h = MIN(d->height - d_y, s->height - s_y);
1124
1125 int x_off = luaL_optint(L, 7, w);
1126 int y_off = luaL_optint(L, 8, h);
1127
1128 bool clip = luaL_optboolean(L, 9, false);
1129 int op = luaL_optint(L, 10, 0);
1130 fb_data clr = 0; /* 11 is custom function | color */
1131
1132 bool d_swx = (x_off < 0); /* dest swap */
1133 bool d_swy = (y_off < 0);
1134 bool s_swx = false; /* src swap */
1135 bool s_swy = false;
1136
1137 int (*rli_trans)(lua_State *, struct rli_iter_d *, struct rli_iter_d *, int, fb_data *);
1138 rli_trans = blit_transform; /* default transformation */
1139
1140 int lf_ref = LUA_NOREF; /* de-ref'd without consequence */
1141
1142 if(!clip) /* Out of bounds is not allowed */
1143 {
1144 bounds_check_xy(L, d, 3, d_x, 4, d_y);
1145 bounds_check_xy(L, s, 5, s_x, 6, s_y);
1146 }
1147 else if (w < 0 || h < 0) /* not an error but nothing to display */
1148 return 0;
1149
1150 w = MIN(w, ABS(x_off));
1151 h = MIN(h, ABS(y_off));
1152
1153 /* if(s->data == d->data) need to care about fill direction */
1154 if(d_x > s_x)
1155 {
1156 d_swx = !d_swx;
1157 s_swx = !s_swx;
1158 }
1159
1160 if(d_y > s_y)
1161 {
1162 d_swy = !d_swy;
1163 s_swy = !s_swy;
1164 }
1165
1166 init_rli_iter(&ds, d, d_x, d_y, d_x + w, d_y + h, 1, 1, d_swx, d_swy);
1167
1168 init_rli_iter(&ss, s, s_x, s_y, s_x + w, s_y + h, 1, 1, s_swx, s_swy);
1169
1170 if (op == 0xFF && lua_isfunction(L, 11)) /* custom function specified.. */
1171 {
1172 rli_trans = custom_transform;
1173 lf_ref = register_luafunc(L, 11);
1174 op = lf_ref;
1175 }
1176 else
1177 clr = FB_SCALARPACK((unsigned) luaL_optnumber(L, 11, LCD_BLACK));
1178
1179 do
1180 {
1181 if(!clip)
1182 {
1183 luaL_argcheck(L, ss.elem != NULL, 2, ERR_DATA_OVF);
1184 luaL_argcheck(L, ds.elem != NULL, 1, ERR_DATA_OVF);
1185 }
1186
1187 if(!(*rli_trans)(L, &ds, &ss, op, &clr))
1188 break; /* Custom op can quit early */
1189
1190 } while(next_rli_iter(&ds) && next_rli_iter(&ss));
1191
1192 luaL_unref(L, LUA_REGISTRYINDEX, lf_ref); /* de-reference custom function */
1193 return 0;
1194}
1195
1196RLI_LUA rli_clear(lua_State *L)
1197{
1198 /* (dst*, [color, x1, y1, x2, y2, clip]) */
1199 struct rocklua_image *a = rli_checktype(L, 1);
1200
1201 struct rli_iter_d ds;
1202
1203 fb_data clr = FB_SCALARPACK((unsigned) luaL_optnumber(L, 2, LCD_BLACK));
1204 int x1 = luaL_optint(L, 3, 1);
1205 int y1 = luaL_optint(L, 4, 1);
1206 int x2 = luaL_optint(L, 5, a->width);
1207 int y2 = luaL_optint(L, 6, a->height);
1208 bool clip = luaL_optboolean(L, 7, false);
1209
1210 if(!clip)
1211 {
1212 bounds_check_xy(L, a, 3, x1, 4, y1);
1213 bounds_check_xy(L, a, 5, x2, 6, y2);
1214 }
1215
1216 init_rli_iter(&ds, a, x1, y1, x2, y2, 1, 1, false, false);
1217
1218 do
1219 {
1220 luaL_argcheck(L, clip || (ds.elem != NULL), 1, ERR_DATA_OVF);
1221
1222 data_set(ds.elem, ds.x, ds.y, &clr);
1223
1224 } while(next_rli_iter(&ds));
1225
1226 return 0;
157} 1227}
1228#endif /* RLI_EXTENDED */
158 1229
1230/* Rli Image methods exported to lua */
159static const struct luaL_reg rli_lib [] = 1231static const struct luaL_reg rli_lib [] =
160{ 1232{
161 {"__tostring", rli_tostring}, 1233 {"__tostring", rli_tostring},
162 {"set", rli_set}, 1234 {"_data", rli_raw},
163 {"get", rli_get}, 1235 {"__len", rli_size},
164 {"width", rli_width}, 1236 {"__eq", rli_equal},
165 {"height", rli_height}, 1237 {"width", rli_width},
1238 {"height", rli_height},
1239 {"set", rli_set},
1240 {"get", rli_get},
1241
1242#ifdef RLI_EXTENDED
1243 {"copy", rli_copy},
1244 {"clear", rli_clear},
1245 {"invert", rli_marshal},
1246 {"marshal", rli_marshal},
1247 {"points", rli_iterator_factory},
1248 {"line", rli_line},
1249 {"ellipse", rli_ellipse},
1250#endif /* RLI_EXTENDED */
166 {NULL, NULL} 1251 {NULL, NULL}
167}; 1252};
168 1253
169static inline void rli_init(lua_State *L) 1254static inline void rli_init(lua_State *L)
170{ 1255{
1256 /* some devices need x | y coords shifted to match native format */
1257 /* conversion between packed native formats and individual pixel addressing */
1258 init_pixelmask(&x_shift, &y_shift, &xy_mask, &pixelmask);
1259
171 luaL_newmetatable(L, ROCKLUA_IMAGE); 1260 luaL_newmetatable(L, ROCKLUA_IMAGE);
172 1261
173 lua_pushstring(L, "__index"); 1262 lua_pushstring(L, "__index");
@@ -189,57 +1278,45 @@ static inline void rli_init(lua_State *L)
189#define SIMPLE_VOID_WRAPPER(func) RB_WRAP(func) { (void)L; func(); return 0; } 1278#define SIMPLE_VOID_WRAPPER(func) RB_WRAP(func) { (void)L; func(); return 0; }
190 1279
191/* Helper function for opt_viewport */ 1280/* Helper function for opt_viewport */
192static void check_tablevalue(lua_State *L, const char* key, int tablepos, void* res, bool unsigned_val) 1281static void check_tablevalue(lua_State *L,
1282 const char* key,
1283 int tablepos,
1284 void* res,
1285 bool is_unsigned)
193{ 1286{
194 lua_getfield(L, tablepos, key); /* Find table[key] */ 1287 lua_getfield(L, tablepos, key); /* Find table[key] */
195 1288
196 if(!lua_isnoneornil(L, -1)) 1289 int val = luaL_optint(L, -1, 0);
197 { 1290
198 if(unsigned_val) 1291 if(is_unsigned)
199 *(unsigned*)res = luaL_checkint(L, -1); 1292 *(unsigned*)res = (unsigned) val;
200 else 1293 else
201 *(int*)res = luaL_checkint(L, -1); 1294 *(int*)res = val;
202 }
203 1295
204 lua_pop(L, 1); /* Pop the value off the stack */ 1296 lua_pop(L, 1); /* Pop the value off the stack */
205} 1297}
206 1298
207static struct viewport* opt_viewport(lua_State *L, int narg, struct viewport* alt) 1299static inline struct viewport* opt_viewport(lua_State *L,
1300 int narg,
1301 struct viewport* vp,
1302 struct viewport* alt)
208{ 1303{
209 if(lua_isnoneornil(L, narg)) 1304 if(lua_isnoneornil(L, narg))
210 return alt; 1305 return alt;
211 1306
212 int tablepos = lua_gettop(L);
213 struct viewport *vp;
214
215 lua_getfield(L, tablepos, "vp"); /* get table['vp'] */
216 if(lua_isnoneornil(L, -1))
217 {
218 lua_pop(L, 1); /* Pop nil off stack */
219
220 vp = (struct viewport*) lua_newuserdata(L, sizeof(struct viewport)); /* Allocate memory and push it as udata on the stack */
221 memset(vp, 0, sizeof(struct viewport)); /* Init viewport values to 0 */
222 lua_setfield(L, tablepos, "vp"); /* table['vp'] = vp (pops value off the stack) */
223 }
224 else
225 {
226 vp = (struct viewport*) lua_touserdata(L, -1); /* Reuse viewport struct */
227 lua_pop(L, 1); /* We don't need the value on stack */
228 }
229
230 luaL_checktype(L, narg, LUA_TTABLE); 1307 luaL_checktype(L, narg, LUA_TTABLE);
231 1308
232 check_tablevalue(L, "x", tablepos, &vp->x, false); 1309 check_tablevalue(L, "x", narg, &vp->x, false);
233 check_tablevalue(L, "y", tablepos, &vp->y, false); 1310 check_tablevalue(L, "y", narg, &vp->y, false);
234 check_tablevalue(L, "width", tablepos, &vp->width, false); 1311 check_tablevalue(L, "width", narg, &vp->width, false);
235 check_tablevalue(L, "height", tablepos, &vp->height, false); 1312 check_tablevalue(L, "height", narg, &vp->height, false);
236#ifdef HAVE_LCD_BITMAP 1313#ifdef HAVE_LCD_BITMAP
237 check_tablevalue(L, "font", tablepos, &vp->font, false); 1314 check_tablevalue(L, "font", narg, &vp->font, false);
238 check_tablevalue(L, "drawmode", tablepos, &vp->drawmode, false); 1315 check_tablevalue(L, "drawmode", narg, &vp->drawmode, false);
239#endif 1316#endif
240#if LCD_DEPTH > 1 1317#if LCD_DEPTH > 1
241 check_tablevalue(L, "fg_pattern", tablepos, &vp->fg_pattern, true); 1318 check_tablevalue(L, "fg_pattern", narg, &vp->fg_pattern, true);
242 check_tablevalue(L, "bg_pattern", tablepos, &vp->bg_pattern, true); 1319 check_tablevalue(L, "bg_pattern", narg, &vp->bg_pattern, true);
243#endif 1320#endif
244 1321
245 return vp; 1322 return vp;
@@ -247,9 +1324,9 @@ static struct viewport* opt_viewport(lua_State *L, int narg, struct viewport* al
247 1324
248RB_WRAP(set_viewport) 1325RB_WRAP(set_viewport)
249{ 1326{
250 struct viewport *vp = opt_viewport(L, 1, NULL); 1327 static struct viewport vp;
251 int screen = luaL_optint(L, 2, SCREEN_MAIN); 1328 int screen = luaL_optint(L, 2, SCREEN_MAIN);
252 rb->screens[screen]->set_viewport(vp); 1329 rb->screens[screen]->set_viewport(opt_viewport(L, 1, &vp, NULL));
253 return 0; 1330 return 0;
254} 1331}
255 1332