A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 1995 lines 56 kB view raw
1/*************************************************************************** 2 * __________ __ ___. 3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___ 4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / 5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 7 * \/ \/ \/ \/ \/ 8 * $Id$ 9 * 10 * Copyright (C) 2008 Dan Everton (safetydan) 11 * Copyright (C) 2009 Maurus Cuelenaere 12 * Copyright (C) 2017 William Wilgus 13 * 14 * This program is free software; you can redistribute it and/or 15 * modify it under the terms of the GNU General Public License 16 * as published by the Free Software Foundation; either version 2 17 * of the License, or (at your option) any later version. 18 * 19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 20 * KIND, either express or implied. 21 * 22 ****************************************************************************/ 23 24#define lrockimg_c 25#define LUA_LIB 26#define ICON_PADDING_S "1" 27 28 29 30#include "lua.h" 31#include "lauxlib.h" 32#include "rocklib.h" 33#include "rocklib_img.h" 34 35/* 36 * ----------------------------------------------------------------------------- 37 * 38 * Rockbox Lua image wrapper 39 * 40 * Some devices(1-bit / 2-bit displays) have packed bit formats that 41 * need to be unpacked in order to work on them at a pixel level. 42 * 43 * The internal formats of these devices do not follow the same paradigm 44 * for image sizes either; We still display the actual width and height to 45 * the user but store stride based on the native values 46 * 47 * Conversion between native addressing and per pixel addressing 48 * incurs extra overhead but it is much faster to do it 49 * on the 'C' side rather than in lua. 50 * 51 * ----------------------------------------------------------------------------- 52 */ 53 54#define ROCKLUA_IMAGE LUA_ROCKLIBNAME ".image" 55 56/* mark for RLI to LUA Interface functions (luaState *L) is the only argument */ 57#define RLI_LUA static int 58 59#ifndef ABS 60#define ABS(a)(((a) < 0) ? - (a) :(a)) 61#endif 62 63struct rocklua_image 64{ 65 int width; 66 int height; 67 int stride; 68 size_t elems; 69 fb_data *data; 70 fb_data dummy[1][1]; 71}; 72 73/* holds iterator data for rlimages */ 74struct rli_iter_d 75{ 76 int x , y; 77 int x1, y1; 78 int x2, y2; 79 int dx, dy; 80 fb_data *elem; 81 struct rocklua_image *img; 82}; 83 84/* viewport for rliimages to use rb functions */ 85static struct viewport img_vp = 86{ 87 .x = 0, 88 .y = 0, 89 .width = 0, 90 .height = 0, 91 .font = FONT_UI, 92 .drawmode = DRMODE_SOLID, 93#if LCD_DEPTH > 1 94 .fg_pattern = LCD_WHITE, 95 .bg_pattern = LCD_BLACK, 96#endif 97}; 98 99static void *img_address_fn(int x, int y) 100{ 101/* Address lookup function 102 * core will use this to get an address from x/y coord 103 * depending on the lcd function core sometimes uses this for 104 * only the first and last address 105 * and handles subsequent address based on stride */ 106 107 struct frame_buffer_t *fb = img_vp.buffer; 108/* LCD_STRIDEFORMAT & LCD_NATIVE_STRIDE macros allow Horiz screens to work with RB */ 109#if LCD_STRIDEFORMAT == VERTICAL_STRIDE 110 size_t element = (x * LCD_NATIVE_STRIDE(fb->stride)) + y; 111#else 112 size_t element = (y * LCD_NATIVE_STRIDE(fb->stride)) + x; 113#endif 114 /* use mod fb->elems to protect from buffer ovfl */ 115 return fb->fb_ptr + (element % fb->elems); 116} 117/* sets an image into a vp to be used by rockbox image functions */ 118static void img_set_as_vp(struct rocklua_image *img, struct viewport *vp) 119{ 120 int w = img->width; 121 int h = img->height; 122 vp->x = 0; 123 vp->y = 0; 124 vp->width = w; 125 vp->height = h; 126 127 static struct frame_buffer_t fb;/* warning passed to external fns */ 128 fb.elems = LCD_NBELEMS(w, h); /* recalculate these rb expects num pixels */ 129 fb.stride = STRIDE_MAIN(w, h); /* recalculate these */ 130 fb.data = img->data; 131 fb.get_address_fn = &img_address_fn; 132 rb->viewport_set_buffer(vp, &fb, SCREEN_MAIN); /* not multiscreen aware yet */ 133} 134 135/* __tostring information enums */ 136enum rli_info {RLI_INFO_ALL = 0, RLI_INFO_TYPE, RLI_INFO_WIDTH, 137 RLI_INFO_HEIGHT, RLI_INFO_ELEMS, RLI_INFO_BYTES, 138 RLI_INFO_DEPTH, RLI_INFO_FORMAT, RLI_INFO_ADDRESS}; 139 140#ifdef HAVE_LCD_COLOR 141 142static inline fb_data invert_color(fb_data rgb) 143{ 144 uint8_t r = 0xFFU - FB_UNPACK_RED(rgb); 145 uint8_t g = 0xFFU - FB_UNPACK_GREEN(rgb); 146 uint8_t b = 0xFFU - FB_UNPACK_BLUE(rgb); 147 148 return FB_RGBPACK(r, g, b); 149} 150#else /* !HAVE_LCD_COLOR */ 151 152#define invert_color(c) (~c) 153 154#endif /* HAVE_LCD_COLOR */ 155 156 157#if (LCD_DEPTH > 2) /* no native to pixel mapping needed */ 158 159#define pixel_to_fb(x, y, o, n) {(void) x; (void) y; do { } while (0);} 160#define pixel_to_native(x, y, xn, yn) {*xn = x; *yn = y;} 161#define init_pixelmask(x, y, m, p) do { } while (0) 162 163 164#else /* some devices need x | y coords shifted to match native format */ 165 166static fb_data x_shift = FB_SCALARPACK(0); 167static fb_data y_shift = FB_SCALARPACK(0); 168static fb_data xy_mask = FB_SCALARPACK(0); 169static const fb_data *pixelmask = NULL; 170 171/* conversion between packed native formats and individual pixel addressing */ 172static inline void init_pixelmask(fb_data *x_shift, fb_data *y_shift, 173 fb_data *xy_mask, const fb_data **pixelmask) 174{ 175 176#if(LCD_PIXELFORMAT == VERTICAL_PACKING) && LCD_DEPTH == 1 177 static const fb_data pixelmask_v1[8] = 178 {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80}; 179 *pixelmask = pixelmask_v1; 180 181 (void) x_shift; 182 *y_shift = 3U; 183 *xy_mask = ((1 << (*y_shift)) - 1); 184#elif(LCD_PIXELFORMAT == VERTICAL_PACKING) && LCD_DEPTH == 2 185 static const fb_data pixelmask_v2[4] = {0x03, 0x0C, 0x30, 0xC0}; 186 *pixelmask = pixelmask_v2; 187 188 (void) x_shift; 189 *y_shift = 2U; 190 *xy_mask = ((1 << (*y_shift)) - 1); 191#elif(LCD_PIXELFORMAT == VERTICAL_INTERLEAVED) && LCD_DEPTH == 2 192 static const fb_data pixelmask_vi2[8] = 193 {0x0101, 0x0202, 0x0404, 0x0808, 0x1010, 0x2020, 0x4040, 0x8080}; 194 *pixelmask = pixelmask_vi2; 195 196 (void) x_shift; 197 *y_shift = 3U; 198 *xy_mask = ((1 << (*y_shift)) - 1); 199#elif(LCD_PIXELFORMAT == HORIZONTAL_PACKING) && LCD_DEPTH == 2 200 /* MSB on left */ 201 static const fb_data pixelmask_h2[4] = {0x03, 0x0C, 0x30, 0xC0}; 202 *pixelmask = pixelmask_h2; 203 204 (void) y_shift; 205 *x_shift = 2U; 206 *xy_mask = ((1 << (*x_shift)) - 1); 207#else 208 #warning Unknown Pixel Format 209#endif /* LCD_PIXELFORMAT */ 210 211} /* init_pixelmask */ 212 213static inline void pixel_to_native(int x, int y, int *x_native, int *y_native) 214{ 215 *x_native = ((x - 1) >> x_shift) + 1; 216 *y_native = ((y - 1) >> y_shift) + 1; 217} /* pixel_to_native */ 218 219static inline fb_data set_masked_pixel(fb_data old, 220 fb_data new, 221 fb_data mask, 222 int bit_n) 223{ 224 /*equivalent of: (old & (~mask)) | ((new << bit_n) & mask);*/ 225 return old ^ ((old ^ (new << bit_n)) & mask); 226 227} /* set_masked_pixel */ 228 229static inline fb_data get_masked_pixel(fb_data val, fb_data mask, int bit_n) 230{ 231 val = val & mask; 232 return val >> bit_n; 233} /* get_masked_pixel */ 234 235/* conversion between packed native formats and individual pixel addressing */ 236static void pixel_to_fb(int x, int y, fb_data *oldv, fb_data *newv) 237{ 238 fb_data mask; 239 int bit_n; 240 241#if(LCD_PIXELFORMAT == VERTICAL_INTERLEAVED) && LCD_DEPTH == 2 242 (void) x; 243 const uint16_t greymap_vi2[4] = {0x0000, 0x0001, 0x0100, 0x0101}; 244 245 bit_n = (y - 1) & xy_mask; 246 mask = pixelmask[bit_n]; 247 248 *newv = greymap_vi2[*newv &(0x3)]; /* [0-3] => greymap */ 249 *newv = set_masked_pixel(*oldv, *newv, mask, bit_n); 250 251 *oldv = get_masked_pixel(*oldv, mask, bit_n); 252 253 if((*oldv) > 1) /* greymap => [0-3] */ 254 *oldv = ((*oldv) & 0x1U) + 2U; /* 2, 3 */ 255 else 256 *oldv &= 1U; /* 0, 1 */ 257 258#elif(LCD_DEPTH <= 2) 259 if(y_shift) 260 bit_n = (y - 1) & xy_mask; 261 else if(x_shift) 262 bit_n = xy_mask - ((x - 1) & xy_mask); /*MSB on left*/ 263 264 if(y_shift || x_shift) 265 { 266 mask = pixelmask[bit_n]; 267 bit_n *= LCD_DEPTH; 268 269 *newv = set_masked_pixel(*oldv, *newv, mask, bit_n); 270 271 *oldv = get_masked_pixel(*oldv, mask, bit_n); 272 } 273#else 274 #error Unknown Pixel Format 275#endif /* LCD_PIXELFORMAT == VERTICAL_INTERLEAVED && LCD_DEPTH == 2 */ 276} /* pixel_to_fb */ 277 278#endif /* (LCD_DEPTH > 2) no native to pixel mapping needed */ 279 280/* Internal worker functions for image data array *****************************/ 281static inline fb_data lua_to_fbscalar(lua_State *L, int narg) 282{ 283 lua_Integer luaint = lua_tointeger(L, narg); 284 fb_data val = FB_SCALARPACK((unsigned) luaint); 285 return val; 286} 287 288static inline void swap_int(bool swap, int *v1, int *v2) 289{ 290 if(swap) 291 { 292 int val = *v1; 293 *v1 = *v2; 294 *v2 = val; 295 } 296} /* swap_int */ 297 298/* Throws error if x or y are out of bounds notifies user which narg indice 299 the out of bound variable originated */ 300static void bounds_check_xy(lua_State *L, struct rocklua_image *img, 301 int nargx, int x, int nargy, int y) 302{ 303 int narg; 304 305 if(x > img->width || x < 1) 306 narg = nargx; 307 else if(y <= img->height && y > 0) 308 return; /* note -- return if no error */ 309 else 310 narg = nargy; 311 312 luaL_argerror(L, narg, ERR_IDX_RANGE); 313} /* bounds_check_xy */ 314 315static struct rocklua_image* rli_checktype_opt(lua_State *L, int arg) 316{ 317#if 0 318 return (struct rocklua_image*) luaL_checkudata(L, arg, ROCKLUA_IMAGE); 319#else /* cache result */ 320 static struct rocklua_image* last = NULL; 321 void *ud = lua_touserdata(L, arg); 322 323 if(ud != NULL) 324 { 325 if(ud == last) 326 return last; 327 else if (lua_getmetatable(L, arg)) 328 { /* does it have a metatable? */ 329 luaL_getmetatable(L, ROCKLUA_IMAGE); /* get correct metatable */ 330 if (lua_rawequal(L, -1, -2)) 331 { /* does it have the correct mt? */ 332 lua_pop(L, 2); /* remove both metatables */ 333 last = (struct rocklua_image*) ud; 334 return last; 335 } 336 } 337 } 338 /* Not a ROCKLUA IMAGE */ 339 return NULL; 340#endif 341} /* rli_checktype_opt*/ 342 343static struct rocklua_image* rli_checktype(lua_State *L, int arg) 344{ 345 struct rocklua_image *img = rli_checktype_opt(L, arg); 346 if (img == NULL) 347 luaL_typerror(L, arg, ROCKLUA_IMAGE); 348 return img; 349} /* rli_checktype */ 350 351static struct rocklua_image * alloc_rlimage(lua_State *L, bool alloc_data, 352 int width, int height) 353{ 354 /* rliimage is pushed on the stack it is up to you to pop it */ 355 struct rocklua_image *img; 356 357 const size_t sz_header = sizeof(struct rocklua_image); 358 size_t sz_data = 0; 359 size_t n_elems; 360 361 int w_native; 362 int h_native; 363 364 pixel_to_native(width, height, &w_native, &h_native); 365 366 n_elems = (size_t)(w_native * h_native); 367 368 if(alloc_data) /* if this a new image we need space for image data */ 369 sz_data = n_elems * sizeof(fb_data); 370 371 /* newuserdata pushes the userdata onto the stack */ 372 img = (struct rocklua_image *) lua_newuserdata(L, sz_header + sz_data); 373 374 luaL_getmetatable(L, ROCKLUA_IMAGE); 375 lua_setmetatable(L, -2); 376 377 /* apparent w/h is stored but behind the scenes native w/h is used */ 378 img->width = width; 379 img->height = height; 380 img->stride = STRIDE_MAIN(w_native, h_native); 381 img->elems = n_elems; 382 383 return img; 384} /* alloc_rlimage */ 385 386static inline void rli_wrap(lua_State *L, fb_data *src, int width, int height) 387{ 388 /* rliimage is pushed on the stack it is up to you to pop it */ 389 struct rocklua_image *a = alloc_rlimage(L, false, width, height); 390 391 a->data = src; 392} /* rli_wrap */ 393 394static inline fb_data* rli_alloc(lua_State *L, int width, int height) 395{ 396 /* rliimage is pushed on the stack it is up to you to pop it */ 397 struct rocklua_image *a = alloc_rlimage(L, true, width, height); 398 399 a->data = &a->dummy[0][0]; /* ref to beginning of alloc'd img data */ 400 401 return a->data; 402} /* rli_alloc */ 403 404static inline fb_data data_set(fb_data *elem, int x, int y, fb_data *val) 405{ 406 fb_data old_val; 407 fb_data new_val; 408 409 if(elem) 410 { 411 old_val = *elem; 412 413 if(val) 414 { 415 new_val = *val; 416 pixel_to_fb(x, y, &old_val, &new_val); 417 *elem = new_val; 418 } 419 else 420 pixel_to_fb(x, y, &old_val, &new_val); 421 } 422 else 423 old_val = FB_SCALARPACK(0); 424 425 return old_val; 426} /* data_set */ 427 428static inline fb_data data_get(fb_data *elem, int x, int y) 429{ 430 return data_set(elem, x, y, NULL); 431} /* data_get */ 432 433static inline fb_data* rli_get_element(struct rocklua_image* img, int x, int y) 434{ 435 int stride = img->stride; 436 size_t elements = img->elems; 437 fb_data *data = img->data; 438 439 pixel_to_native(x, y, &x, &y); 440 441#if LCD_STRIDEFORMAT == VERTICAL_STRIDE 442 /* column major address */ 443 size_t data_address = (stride * (x - 1)) + (y - 1); 444 445 /* y needs bound between 0 and stride otherwise overflow to prev/next x */ 446 if(y <= 0 || y > stride || data_address >= elements) 447 return NULL; /* data overflow */ 448#else 449 /* row major address */ 450 size_t data_address = (stride * (y - 1)) + (x - 1); 451 452 /* x needs bound between 0 and stride otherwise overflow to prev/next y */ 453 if(x <= 0 || x > stride || data_address >= elements) 454 return NULL; /* data overflow */ 455#endif 456 457 return &data[data_address]; /* return element address */ 458} /* rli_get_element */ 459 460/* Lua to C Interface for pixel set and get functions */ 461static int rli_setget(lua_State *L, bool is_get, int narg_clip) 462{ 463 /*(set) (dst*, [x1, y1, clr, clip]) */ 464 /*(get) (dst*, [x1, y1, clip]) */ 465 struct rocklua_image *a = rli_checktype(L, 1); 466 int x = lua_tointeger(L, 2); 467 int y = lua_tointeger(L, 3); 468 469 fb_data clr; /* Arg 4 is color if set element */ 470 471 fb_data *element = rli_get_element(a, x, y); 472 473 if(!element) 474 { 475 if(!lua_toboolean(L, narg_clip)) /* Error if !clip */ 476 bounds_check_xy(L, a, 2, x, 3, y); 477 478 lua_pushnil(L); 479 return 1; 480 } 481 482 if(is_get) /* get element */ 483 lua_pushinteger(L, FB_UNPACK_SCALAR_LCD(data_get(element, x, y))); 484 else /* set element */ 485 { 486 clr = lua_to_fbscalar(L, 4); 487 lua_pushinteger(L, FB_UNPACK_SCALAR_LCD(data_set(element, x, y, &clr))); 488 } 489 490 /* returns old value */ 491 return 1; 492} /* rli_setget */ 493 494#ifdef RLI_EXTENDED 495static bool rli_iter_init(struct rli_iter_d *d, 496 struct rocklua_image *img, 497 int x1, int y1, 498 int x2, int y2, 499 int dx, int dy, 500 bool swx, bool swy) 501{ 502 503 swap_int((swx), &x1, &x2); 504 swap_int((swy), &y1, &y2); 505 506 /* stepping in the correct x direction ? */ 507 if((dx ^ (x2 - x1)) < 0) 508 dx = -dx; 509 510 /* stepping in the correct y direction ? */ 511 if((dy ^ (y2 - y1)) < 0) 512 dy = -dy; 513 514 d->img = img; 515 d->x = x1; 516 d->y = y1; 517 d->x1 = x1; 518 d->y1 = y1; 519 d->x2 = x2; 520 d->y2 = y2; 521 d->dx = dx; 522 d->dy = dy; 523 d->elem = rli_get_element(img, d->x, d->y); 524 525 return(dx != 0 || dy != 0); 526} /* rli_iter_init */ 527 528static struct rli_iter_d * rli_iter_create(lua_State *L) 529{ 530 struct rocklua_image *a = rli_checktype(L, 1); 531 int x1 = luaL_optint(L, 2, 1); 532 int y1 = luaL_optint(L, 3, 1); 533 int x2 = luaL_optint(L, 4, a->width); 534 int y2 = luaL_optint(L, 5, a->height); 535 int dx = luaL_optint(L, 6, 1); 536 int dy = luaL_optint(L, 7, 1); 537 bool clip = lua_toboolean(L, 8); 538 539 if(!clip) 540 { 541 bounds_check_xy(L, a, 2, x1, 3, y1); 542 bounds_check_xy(L, a, 4, x2, 5, y2); 543 } 544 545 struct rli_iter_d *ds; 546 /* create new iter + pushed onto stack */ 547 ds = (struct rli_iter_d *) lua_newuserdata(L, sizeof(struct rli_iter_d)); 548 549 rli_iter_init(ds, a, x1, y1, x2, y2, dx, dy, false, false); 550 551 return ds; 552} 553 554/* steps to the next point(x, y) by delta x/y, stores pointer to element 555 returns true if x & y haven't reached x2 & y2 556 if limit reached - element set to NULL, deltas set to 0 & false returned 557*/ 558static bool next_rli_iter(struct rli_iter_d *d) 559{ 560 if((d->dx > 0 && d->x < d->x2) || (d->dx < 0 && d->x > d->x2)) 561 d->x += d->dx; 562 else if((d->dy > 0 && d->y < d->y2) || (d->dy < 0 && d->y > d->y2)) 563 { 564 d->x = d->x1; /* Reset x*/ 565 d->y += d->dy; 566 } 567 else 568 { 569 d->elem = NULL; 570 d->dx = 0; 571 d->dy = 0; 572 return false; 573 } 574 575 d->elem = rli_get_element(d->img, d->x, d->y); 576 577 return true; 578} /* next_rli_iter */ 579 580#if 0 581static void d_line(struct rocklua_image *img, 582 int x1, int y1, 583 int x2, int y2, 584 fb_data *clr) 585{ 586 /* NOTE! clr passed as pointer */ 587 /* Bresenham midpoint line algorithm */ 588 fb_data *element; 589 590 int r_a = x2 - x1; /* range of x direction called 'a' for now */ 591 int r_b = y2 - y1; /* range of y direction called 'b' for now */ 592 593 int s_a = (r_a > 0) - (r_a < 0); /* step of a direction -1, 0, 1 */ 594 int s_b = (r_b > 0) - (r_b < 0); /* step of b direction -1, 0, 1 */ 595 596 int d_err; 597 int numpixels; 598 599 int *a1 = &x1; /* pointer to the x var 'a' */ 600 int *b1 = &y1; /* pointer to the y var 'b' */ 601 602 r_a = ABS(r_a);/* instead of negative range we switch step */ 603 r_b = ABS(r_b);/* instead of negative range we switch step */ 604 605 if(r_b > r_a) /*if rangeY('b') > rangeX('a') swap their identities */ 606 { 607 a1 = &y1; /* pointer to the y var 'a' */ 608 b1 = &x1; /* pointer to the x var 'b' */ 609 swap_int((true), &r_a, &r_b); 610 swap_int((true), &s_a, &s_b); 611 } 612 613 d_err = ((r_b << 1) - r_a) >> 1; /* preload err of 1 step (px centered) */ 614 615 /* add 1 extra point to make the whole line */ 616 numpixels = r_a + 1; 617 618 r_a -= r_b; /* pre-subtract 'a' - 'b' */ 619 620 for(; numpixels > 0; numpixels--) 621 { 622 element = rli_get_element(img, x1, y1); 623 data_set(element, x1, y1, clr); 624 625 if(d_err >= 0) /* 0 is our target midpoint(exact point on the line) */ 626 { 627 *b1 += s_b; /* whichever axis is in 'b' stepped(-1 or +1) */ 628 d_err -= r_a; 629 } 630 else 631 d_err += r_b; /* only add 'b' when d_err < 0 */ 632 633 *a1 += s_a; /* whichever axis is in 'a' stepped(-1 or +1) */ 634 } 635 636} /* d_line */ 637#endif 638 639 640static void d_line(struct rocklua_image *img, 641 int x1, int y1, 642 int x2, int y2, 643 fb_data *clr) 644{ 645 /* NOTE! clr passed as pointer */ 646#if LCD_DEPTH == 2 647 img_vp.fg_pattern = 0x55 * (~(*clr) & 3); 648 img_vp.drawmode = DRMODE_FG; 649#elif LCD_DEPTH > 1 650 img_vp.fg_pattern = FB_UNPACK_SCALAR_LCD(*clr); 651 img_vp.drawmode = DRMODE_FG; 652#else /* bit of a hack to make sure lines show properly from lua */ 653 /* use rb.lcd_drawline if you want full control */ 654 655 img_vp.drawmode = *clr & (DRMODE_SOLID|DRMODE_INVERSEVID); 656 if (img_vp.drawmode != (DRMODE_SOLID|DRMODE_INVERSEVID)) 657 img_vp.drawmode = DRMODE_SOLID; 658#endif 659 660 img_set_as_vp(img, &img_vp); 661 662 struct viewport *oldvp = rb->screens[SCREEN_MAIN]->set_viewport(&img_vp); 663 664 rb->lcd_drawline(x1 - 1, y1 - 1 , x2 - 1, y2 - 1); 665 666 rb->screens[SCREEN_MAIN]->set_viewport(oldvp); 667 668} /* d_line */ 669 670/* ellipse worker function */ 671static void d_ellipse_elements(struct rocklua_image * img, 672 int x1, int y1, 673 int x2, int y2, 674 fb_data *clr, 675 fb_data *fillclr) 676{ 677 fb_data *element; 678 679 if(fillclr) 680 { 681 d_line(img, x1, y1, x2, y1, fillclr); /* I. II.*/ 682 d_line(img, x1, y2, x2, y2, fillclr); /* III.IV.*/ 683 } 684 685 element = rli_get_element(img, x2, y1); 686 data_set(element, x2, y1, clr); /* I. Quadrant +x +y */ 687 688 element = rli_get_element(img, x1, y1); 689 data_set(element, x1, y1, clr); /* II. Quadrant -x +y */ 690 691 element = rli_get_element(img, x1, y2); 692 data_set(element, x1, y2, clr); /* III. Quadrant -x -y */ 693 694 element = rli_get_element(img, x2, y2); 695 data_set(element, x2, y2, clr); /* IV. Quadrant +x -y */ 696 697} /* d_ellipse_elements */ 698 699static void d_ellipse(struct rocklua_image *img, 700 int x1, int y1, 701 int x2, int y2, 702 fb_data *clr, 703 fb_data *fillclr) 704{ 705 /* NOTE! clr and fillclr passed as pointers */ 706 /* Rasterizing algorithm derivative of work by Alois Zingl */ 707#if (LCD_WIDTH > 1024 || LCD_HEIGHT > 1024) && defined(INT64_MAX) 708 /* Prevents overflow on large screens */ 709 int64_t dx, dy, err, e1; 710#else 711 int32_t dx, dy, err, e1; 712#endif 713 /* if called with swapped points .. exchange them */ 714 swap_int((x1 > x2), &x1, &x2); 715 swap_int((y1 > y2), &y1, &y2); 716 717 int a = x2 - x1; /* diameter */ 718 int b = y2 - y1; /* diameter */ 719 720 if(a == 0 || b == 0) 721 return; /* not an error but nothing to display */ 722 723 int b1 = (b & 1); 724 b = b - (1 - b1); 725 726 int a2 = (a * a); 727 int b2 = (b * b); 728 729 dx = ((1 - a) * b2) >> 1; /* error increment */ 730 dy = (b1 * a2) >> 1; /* error increment */ 731 732 err = dx + dy + b1 * a2; /* error of 1.step */ 733 734 y1 += (b + 1) >> 1; 735 y2 = y1 - b1; 736 737 do 738 { 739 d_ellipse_elements(img, x1, y1, x2, y2, clr, fillclr); 740 741 e1 = err; 742 743 if(e1 <= (dy >> 1)) /* target midpoint - y step */ 744 { 745 y1++; 746 y2--; 747 dy += a2; 748 err += dy; 749 } 750 751 if(e1 >= (dx >> 1) || err > (dy >> 1)) /* target midpoint - x step */ 752 { 753 x1++; 754 x2--; 755 dx += b2; 756 err += dx; 757 } 758 759 } while(x1 <= x2); 760 761 if (fillclr && x1 - x2 <= 2) 762 fillclr = clr; 763 764 while (y1 - y2 < b) /* early stop of flat ellipse a=1 finish tip */ 765 { 766 d_ellipse_elements(img, x1, y1, x2, y2, clr, fillclr); 767 768 y1++; 769 y2--; 770 } 771 772} /* d_ellipse */ 773 774/* Lua to C Interface for line and ellipse */ 775static int rli_line_ellipse(lua_State *L, bool is_ellipse, int narg_clip) 776{ 777 struct rocklua_image *a = rli_checktype(L, 1); 778 779 int x1 = luaL_checkint(L, 2); 780 int y1 = luaL_checkint(L, 3); 781 int x2 = luaL_optint(L, 4, x1); 782 int y2 = luaL_optint(L, 5, y1); 783 784 fb_data clr = lua_to_fbscalar(L, 6); 785 786 fb_data fillclr; /* fill color is index 7 if is_ellipse */ 787 fb_data *p_fillclr = NULL; 788 789 bool clip = lua_toboolean(L, narg_clip); 790 791 if(!clip) 792 { 793 bounds_check_xy(L, a, 2, x1, 3, y1); 794 bounds_check_xy(L, a, 4, x2, 5, y2); 795 } 796 797 if(is_ellipse) 798 { 799 if(lua_type(L, 7) == LUA_TNUMBER) 800 { 801 fillclr = lua_to_fbscalar(L, 7); 802 p_fillclr = &fillclr; 803 } 804 805 d_ellipse(a, x1, y1, x2, y2, &clr, p_fillclr); 806 } 807 else 808 d_line(a, x1, y1, x2, y2, &clr); 809 810 return 0; 811} /* rli_line_ellipse */ 812 813static inline int rli_pushpixel(lua_State *L, fb_data color, int x, int y) 814{ 815 lua_pushinteger(L, FB_UNPACK_SCALAR_LCD(color)); 816 lua_pushinteger(L, x); 817 lua_pushinteger(L, y); 818 return 3; 819} 820 821/* User defined pixel manipulations through rli_copy, rli_marshal */ 822static void custom_transform(lua_State *L, 823 struct rli_iter_d *ds, 824 struct rli_iter_d *ss, 825 int op, 826 fb_data *color) 827{ 828 (void) color; 829 (void) op; 830 fb_data dst; 831 fb_data src; 832 833 int params; 834 bool done = true; 835 836 if (true)/*(lua_isfunction(L, -1))*/ 837 { 838 lua_pushvalue(L, -1); /* make a copy of the lua function */ 839 840 dst = data_get(ds->elem, ds->x, ds->y); 841 params = rli_pushpixel(L, dst, ds->x, ds->y); 842 843 if(ss) /* Allows src to be omitted */ 844 { 845 src = data_get(ss->elem, ss->x, ss->y); 846 params += rli_pushpixel(L, src, ss->x, ss->y); 847 } 848 849 lua_call(L, params, 2); /* call custom function w/ n-params & 2 ret */ 850 851 if(lua_type(L, -2) == LUA_TNUMBER) 852 { 853 done = false; 854 dst = lua_to_fbscalar(L, -2); 855 data_set(ds->elem, ds->x, ds->y, &dst); 856 } 857 858 if(ss && (lua_type(L, -1) == LUA_TNUMBER)) 859 { 860 done = false; 861 src = lua_to_fbscalar(L, -1); 862 data_set(ss->elem, ss->x, ss->y, &src); 863 } 864 865 lua_pop(L, 2); 866 } 867 868 if(done) /* signal iter to stop */ 869 { 870 ds->dx = 0; 871 ds->dy = 0; 872 } 873} /* custom_transform */ 874 875/* Pre defined pixel manipulations through rli_copy */ 876static void blit_transform(lua_State *L, 877 struct rli_iter_d *ds, 878 struct rli_iter_d *ss, 879 int op, 880 fb_data *color) 881{ 882 (void) L; 883 unsigned clr = FB_UNPACK_SCALAR_LCD(*color); 884 unsigned dst = FB_UNPACK_SCALAR_LCD(data_get(ds->elem, ds->x, ds->y)); 885 unsigned src; 886 887 /* Reuse 0 - 7 for src / clr blits*/ 888 if(op >= 30 && op <= 37) 889 { 890 op -= 30; 891 src = clr; 892 } 893 else 894 src = FB_UNPACK_SCALAR_LCD(data_get(ss->elem, ss->x, ss->y)); 895 896 switch(op) 897 { 898 default: 899 /* case 30: */ 900 case 0: { dst = src; break; }/* copyS/C */ 901 /* case 31: */ 902 case 1: { dst = src | dst; break; }/* DorS/C */ 903 /* case 32: */ 904 case 2: { dst = src ^ dst; break; }/* DxorS/C */ 905 /* case 33: */ 906 case 3: { dst = ~(src | dst); break; }/* nDorS/C */ 907 /* case 34: */ 908 case 4: { dst = (~src) | dst; break; }/* DornS/C */ 909 /* case 35: */ 910 case 5: { dst = src & dst; break; }/* DandS/C */ 911 /* case 36: */ 912 case 6: { dst = src & (~dst); break; }/* nDandS/C */ 913 /* case 37: */ 914 case 7: { dst = ~src; break; }/* notS/C */ 915 916 /* mask blits */ 917 case 8: { if(src != 0) { dst = clr; } break; }/* Sand */ 918 case 9: { if(src == 0) { dst = clr; } break; }/* Snot */ 919 920 case 10: { dst = src | clr; break; }/* SorC */ 921 case 11: { dst = src ^ clr; break; }/* SxorC */ 922 case 12: { dst = ~(src | clr); break; }/* nSorC */ 923 case 13: { dst = src | (~clr); break; }/* SornC */ 924 case 14: { dst = src & clr; break; }/* SandC */ 925 case 15: { dst = (~src) & clr; break; }/* nSandC */ 926 case 16: { dst |= (~src) | clr; break; }/* DornSorC */ 927 case 17: { dst ^= (src & (dst ^ clr)); break; }/* DxorSandDxorC */ 928 929 case 18: { if(src != clr) { dst = src; } break; } 930 case 19: { if(src == clr) { dst = src; } break; } 931 case 20: { if(src > clr) { dst = src; } break; } 932 case 21: { if(src < clr) { dst = src; } break; } 933 934 case 22: { if(dst != clr) { dst = src; } break; } 935 case 23: { if(dst == clr) { dst = src; } break; } 936 case 24: { if(dst > clr) { dst = src; } break; } 937 case 25: { if(dst < clr) { dst = src; } break; } 938 939 case 26: { if(dst != src) { dst = clr; } break; } 940 case 27: { if(dst == src) { dst = clr; } break; } 941 case 28: { if(dst > src) { dst = clr; } break; } 942 case 29: { if(dst < src) { dst = clr; } break; } 943#if 0 944 /* src unneeded */ 945 case 30: { dst = clr; break; }/* copyC */ 946 case 31: { dst = clr | dst; break; }/* DorC */ 947 case 32: { dst = clr ^ dst; break; }/* DxorC */ 948 case 33: { dst = ~(clr | dst); break; }/* nDorC */ 949 case 34: { dst = (~clr) | dst; break; }/* DornC */ 950 case 35: { dst = clr & dst; break; }/* DandC */ 951 case 36: { dst = clr & (~dst); break; }/* nDandC */ 952 case 37: { dst = ~clr; break; }/* notC */ 953#endif 954 955 }/*switch op*/ 956 fb_data val = FB_SCALARPACK(dst); 957 data_set(ds->elem, ds->x, ds->y, &val); 958} /* blit_transform */ 959 960static void invert_transform(lua_State *L, 961 struct rli_iter_d *ds, 962 struct rli_iter_d *ss, 963 int op, 964 fb_data *color) 965{ 966 (void) L; 967 (void) color; 968 (void) op; 969 (void) ss; 970 971 fb_data val = invert_color(data_get(ds->elem, ds->x, ds->y)); 972 data_set(ds->elem, ds->x, ds->y, &val); 973} /* invert_transform */ 974 975static void clear_transform(lua_State *L, 976 struct rli_iter_d *ds, 977 struct rli_iter_d *ss, 978 int op, 979 fb_data *color) 980{ 981 (void) L; 982 (void) op; 983 (void) ss; 984 985 data_set(ds->elem, ds->x, ds->y, color); 986} /* clear_transform */ 987 988#endif /* RLI_EXTENDED */ 989 990/* RLI to LUA Interface functions *********************************************/ 991RLI_LUA rli_new(lua_State *L) 992{ /* [width, height] */ 993 int width = luaL_optint(L, 1, LCD_WIDTH); 994 int height = luaL_optint(L, 2, LCD_HEIGHT); 995 996 luaL_argcheck(L, width > 0 && height > 0, (width <= 0) ? 1 : 2, ERR_IDX_RANGE); 997 998 rli_alloc(L, width, height); 999 1000 return 1; 1001} 1002 1003RLI_LUA rli_set(lua_State *L) 1004{ 1005 /*(set) (dst*, [x1, y1, clr, clip]) */ 1006 return rli_setget(L, false, 5); 1007} 1008 1009RLI_LUA rli_get(lua_State *L) 1010{ 1011 /*(get) (dst*, [x1, y1, clip]) */ 1012 return rli_setget(L, true, 4); 1013} 1014 1015RLI_LUA rli_equal(lua_State *L) 1016{ 1017 struct rocklua_image *a = rli_checktype(L, 1); 1018 struct rocklua_image *b = rli_checktype(L, 2); 1019 lua_pushboolean(L, a->data == b->data); 1020 return 1; 1021} 1022 1023RLI_LUA rli_height(lua_State *L) 1024{ 1025 struct rocklua_image *a = rli_checktype(L, 1); 1026 lua_pushinteger(L, a->height); 1027 return 1; 1028} 1029 1030RLI_LUA rli_width(lua_State *L) 1031{ 1032 struct rocklua_image *a = rli_checktype(L, 1); 1033 lua_pushinteger(L, a->width); 1034 return 1; 1035} 1036 1037RLI_LUA rli_size(lua_State *L) 1038{ 1039 struct rocklua_image *a = rli_checktype(L, 1); 1040 lua_pushinteger(L, a->elems); 1041 return 1; 1042} 1043 1044RLI_LUA rli_raw(lua_State *L) 1045{ 1046 /*val = (img*, index, [new_val]) */ 1047 struct rocklua_image *a = rli_checktype(L, 1); 1048 1049 size_t i = (unsigned) lua_tointeger(L, 2); 1050 1051 fb_data val; 1052 1053 luaL_argcheck(L, i > 0 && i <= (a->elems), 2, ERR_IDX_RANGE); 1054 1055 lua_pushinteger(L, FB_UNPACK_SCALAR_LCD(a->data[i-1])); 1056 1057 if(lua_type(L, 3) == LUA_TNUMBER) 1058 { 1059 val = lua_to_fbscalar(L, 3); 1060 a->data[i-1] = val; 1061 } 1062 1063 return 1; 1064} 1065 1066RLI_LUA rli_tostring(lua_State *L) 1067{ 1068 /* (img, [infoitem]) */ 1069 struct rocklua_image *a = rli_checktype(L, 1); 1070 1071 int item = lua_tointeger(L, 2); 1072 size_t bytes = a->elems * sizeof(fb_data); 1073 1074 switch(item) 1075 { 1076 default: 1077 case RLI_INFO_ALL: 1078 { 1079 lua_pushfstring(L, 1080 ROCKLUA_IMAGE ": %dx%d, %d elements, %d bytes, %d-bit depth, %d pack", 1081 a->width, a->height, a->elems, bytes, LCD_DEPTH, LCD_PIXELFORMAT); 1082 break; 1083 } 1084 case RLI_INFO_TYPE: { lua_pushfstring(L, ROCKLUA_IMAGE); break; } 1085 case RLI_INFO_WIDTH: { lua_pushinteger(L, a->width); break; } 1086 case RLI_INFO_HEIGHT: { lua_pushinteger(L, a->height); break; } 1087 case RLI_INFO_ELEMS: { lua_pushinteger(L, a->elems); break; } 1088 case RLI_INFO_BYTES: { lua_pushinteger(L, bytes); break; } 1089 case RLI_INFO_DEPTH: { lua_pushinteger(L, LCD_DEPTH ); break; } 1090 case RLI_INFO_FORMAT: { lua_pushinteger(L, LCD_PIXELFORMAT); break; } 1091 case RLI_INFO_ADDRESS: { lua_pushfstring(L, "%p", a->data); break; } 1092 } 1093 1094 /* lua_pushstring(L, lua_tostring(L, -1)); */ 1095 lua_tostring(L, -1); /* converts item at index to string */ 1096 1097 return 1; 1098} 1099 1100#ifdef RLI_EXTENDED 1101RLI_LUA rli_ellipse(lua_State *L) 1102{ 1103 /* (dst*, x1, y1, x2, y2, [clr, fillclr, clip]) */ 1104 /* line and ellipse share the same init function */ 1105 return rli_line_ellipse(L, true, 8); 1106} 1107 1108RLI_LUA rli_line(lua_State *L) 1109{ 1110 /* (dst*, x1, y1, [x2, y2, clr, clip]) */ 1111 /* line and ellipse share the same init function */ 1112 return rli_line_ellipse(L, false, 7); 1113} 1114 1115RLI_LUA rli_iterator(lua_State *L) { 1116 /* see rli_iterator_factory */ 1117 int params = 0; 1118 struct rli_iter_d *ds; 1119 ds = (struct rli_iter_d *) lua_touserdata(L, lua_upvalueindex(1)); 1120 1121 if(ds->dx != 0 || ds->dy != 0) 1122 { 1123 params = rli_pushpixel(L, data_get(ds->elem, ds->x, ds->y), ds->x, ds->y); 1124 1125 next_rli_iter(ds); /* load next element */ 1126 } 1127 return params; /* nothing left to do */ 1128} 1129 1130RLI_LUA rli_iterator_factory(lua_State *L) 1131{ 1132 /* (points) (img*, [x1, y1, x2, y2, dx, dy, clip]) */ 1133 /* (indices 1-8 are used by rli_iter_create) */ 1134 1135 /* create new iter + pushed onto stack */ 1136 rli_iter_create(L); 1137 1138 /* returns the iter function with embedded iter data(up values) */ 1139 lua_pushcclosure(L, &rli_iterator, 1); 1140 1141 return 1; 1142} 1143 1144RLI_LUA rli_marshal(lua_State *L) /* also invert, clear */ 1145{ 1146 /* (marshal/invert/clear) (img*, [x1, y1, x2, y2, dx, dy, clip, function]) */ 1147 /* (indices 1-8 are used by rli_iter_create) */ 1148 fb_data clr; 1149 1150 void (*rli_trans)(lua_State *, struct rli_iter_d *, struct rli_iter_d *, int, fb_data *); 1151 int ltype = lua_type (L, 9); 1152 1153 /* create new iter + pushed onto stack */ 1154 struct rli_iter_d *ds = rli_iter_create(L); 1155 1156 if (ltype == LUA_TNUMBER) 1157 { 1158 clr = lua_to_fbscalar(L, 9); 1159 rli_trans = clear_transform; 1160 } 1161 else if(ltype == LUA_TFUNCTION) /* custom function */ 1162 { 1163 rli_trans = custom_transform; 1164 lua_pushvalue(L, 9); /* ensure lua function on top of stack */ 1165 } 1166 else 1167 rli_trans = invert_transform; /* default transformation */ 1168 1169 do 1170 { 1171 (*rli_trans)(L, ds, NULL, 0, &clr); 1172 } while(next_rli_iter(ds)); 1173 1174 return 0; 1175} 1176 1177RLI_LUA rli_copy(lua_State *L) 1178{ 1179 /* (dst*, src*, [d_x, d_y, s_x, s_y, x_off, y_off, clip, [op, funct/clr]]) */ 1180 struct rocklua_image *dst = rli_checktype(L, 1); /* dst */ 1181 struct rocklua_image *src = rli_checktype(L, 2); /* src */ 1182 1183 struct rli_iter_d ds; /* dst */ 1184 struct rli_iter_d ss; /* src */ 1185 1186 /* copy whole image if possible */ 1187 if(src->elems == dst->elems && src->width == dst->width && lua_gettop(L) < 3) 1188 { 1189 rb->memcpy(dst->data, src->data, dst->elems * sizeof(fb_data)); 1190 return 0; 1191 } 1192 1193 int d_x = luaL_optint(L, 3, 1); 1194 int d_y = luaL_optint(L, 4, 1); 1195 int s_x = luaL_optint(L, 5, 1); 1196 int s_y = luaL_optint(L, 6, 1); 1197 1198 int w = MIN(dst->width - d_x, src->width - s_x); 1199 int h = MIN(dst->height - d_y, src->height - s_y); 1200 1201 int x_off = luaL_optint(L, 7, w); 1202 int y_off = luaL_optint(L, 8, h); 1203 1204 bool clip = lua_toboolean(L, 9); 1205 int op; /* 10 is operation for blit */ 1206 fb_data clr; /* 11 is custom function | color */ 1207 1208 bool d_swx = (x_off < 0); /* dest swap */ 1209 bool d_swy = (y_off < 0); 1210 bool s_swx = false; /* src swap */ 1211 bool s_swy = false; 1212 1213 void (*rli_trans)(lua_State *, struct rli_iter_d *, struct rli_iter_d *, int, fb_data *); 1214 1215 if(!clip) /* Out of bounds is not allowed */ 1216 { 1217 bounds_check_xy(L, dst, 3, d_x, 4, d_y); 1218 bounds_check_xy(L, src, 5, s_x, 6, s_y); 1219 w = MIN(w, ABS(x_off)); 1220 h = MIN(h, ABS(y_off)); 1221 bounds_check_xy(L, dst, 7, d_x + w, 8, d_y + h); 1222 bounds_check_xy(L, src, 7, s_x + w, 8, s_y + h); 1223 } 1224 else 1225 { 1226 if (w < 0 || h < 0) /* not an error but nothing to display */ 1227 return 0; 1228 w = MIN(w, ABS(x_off)); 1229 h = MIN(h, ABS(y_off)); 1230 } 1231 1232 /* if src->data == dst->data need to care about fill direction */ 1233 if(d_x > s_x) 1234 { 1235 d_swx = !d_swx; 1236 s_swx = !s_swx; 1237 } 1238 1239 if(d_y > s_y) 1240 { 1241 d_swy = !d_swy; 1242 s_swy = !s_swy; 1243 } 1244 1245 rli_iter_init(&ds, dst, d_x, d_y, d_x + w, d_y + h, 1, 1, d_swx, d_swy); 1246 1247 rli_iter_init(&ss, src, s_x, s_y, s_x + w, s_y + h, 1, 1, s_swx, s_swy); 1248 1249 if (lua_type(L, 11) == LUA_TFUNCTION) /* custom function supplied.. */ 1250 { 1251 rli_trans = custom_transform; 1252 lua_settop(L, 11); /* ensure lua function on top of stack */ 1253 clr = FB_SCALARPACK(0); 1254 op = 0; 1255 } 1256 else 1257 { 1258 rli_trans = blit_transform; /* default transformation */ 1259 clr = lua_to_fbscalar(L, 11); 1260 op = lua_tointeger(L, 10); 1261 } 1262 1263 do 1264 { 1265 (*rli_trans)(L, &ds, &ss, op, &clr); 1266 } while(next_rli_iter(&ds) && next_rli_iter(&ss)); 1267 1268 return 0; 1269} 1270 1271RLI_LUA rli_clear(lua_State *L) 1272{ 1273 /* (clear) (dst*, [color, x1, y1, x2, y2, clip, dx, dy]) */ 1274 lua_settop(L, 9); 1275 1276 lua_pushvalue(L, 7); /* clip -- index 8 */ 1277 lua_remove(L, 7); 1278 1279 lua_pushinteger(L, lua_tointeger(L, 2)); /*color -- index 9*/ 1280 lua_remove(L, 2); 1281 1282 return rli_marshal(L); /* (img*, [x1, y1, x2, y2, dx, dy, clip, function]) */ 1283} 1284#endif /* RLI_EXTENDED */ 1285 1286/* Rli Image methods exported to lua */ 1287static const struct luaL_reg rli_lib [] = 1288{ 1289 {"__tostring", rli_tostring}, 1290 {"_data", rli_raw}, 1291 {"__len", rli_size}, 1292 {"__eq", rli_equal}, 1293 {"width", rli_width}, 1294 {"height", rli_height}, 1295 {"set", rli_set}, 1296 {"get", rli_get}, 1297 1298#ifdef RLI_EXTENDED 1299 {"copy", rli_copy}, 1300 {"clear", rli_clear}, 1301 {"invert", rli_marshal}, 1302 {"marshal", rli_marshal}, 1303 {"points", rli_iterator_factory}, 1304 {"line", rli_line}, 1305 {"ellipse", rli_ellipse}, 1306#endif /* RLI_EXTENDED */ 1307 1308 {NULL, NULL} 1309}; 1310 1311/* 1312 * ----------------------------- 1313 * 1314 * Rockbox wrappers start here! 1315 * 1316 * ----------------------------- 1317 */ 1318 1319#define RB_WRAP(func) static int rock_##func(lua_State UNUSED_ATTR *L) 1320 1321#if defined NB_SCREENS && (NB_SCREENS > 1) 1322#define RB_SCREEN_STRUCT(luastate, narg) \ 1323 rb->screens[get_screen(luastate, narg)] 1324#define RB_SCREENS(luastate, narg, func, ...) \ 1325 rb->screens[get_screen(luastate, narg)]->func(__VA_ARGS__) 1326 1327static int get_screen(lua_State *L, int narg) 1328{ 1329 int screen = luaL_optint(L, narg, SCREEN_MAIN); 1330 1331 if(screen < SCREEN_MAIN) 1332 screen = SCREEN_MAIN; 1333 else if(screen > NB_SCREENS) 1334 screen = NB_SCREENS; 1335 1336 return screen; 1337} 1338#else /* only SCREEN_MAIN exists */ 1339#define get_screen(a,b) (SCREEN_MAIN) 1340#define RB_SCREEN_STRUCT(luastate, narg) \ 1341 rb->screens[SCREEN_MAIN] 1342#define RB_SCREENS(luastate, narg, func, ...) \ 1343 rb->screens[SCREEN_MAIN]->func(__VA_ARGS__) 1344#endif 1345 1346RB_WRAP(lcd_update) 1347{ 1348 RB_SCREENS(L, 1, update); 1349 return 0; 1350} 1351 1352RB_WRAP(lcd_clear_display) 1353{ 1354 RB_SCREENS(L, 1, clear_display); 1355 return 0; 1356} 1357 1358RB_WRAP(lcd_set_drawmode) 1359{ 1360 int previous; 1361 int mode = (int) luaL_checkint(L, 1); 1362 if (rli_checktype_opt(L, 2) != NULL) /* is rliimage? */ 1363 { 1364 previous = img_vp.drawmode; 1365 img_vp.drawmode = mode; 1366 } 1367 else 1368 { 1369 struct viewport *vp = *(RB_SCREEN_STRUCT(L, 2)->current_viewport); 1370 previous = vp->drawmode; 1371 RB_SCREENS(L, 2, set_drawmode, mode); 1372 } 1373 lua_pushinteger(L, previous); 1374 return 1; 1375} 1376 1377/* helper function for lcd_puts functions */ 1378static const unsigned char * lcd_putshelper(lua_State *L, int *x, int *y) 1379{ 1380 *x = (int) luaL_checkint(L, 1); 1381 *y = (int) luaL_checkint(L, 2); 1382 return luaL_checkstring(L, 3); 1383} 1384 1385RB_WRAP(lcd_putsxy) 1386{ 1387 int x, y; 1388 const unsigned char *string = lcd_putshelper(L, &x, &y); 1389 RB_SCREENS(L, 4, putsxy, x, y, string); 1390 return 0; 1391} 1392 1393RB_WRAP(lcd_puts) 1394{ 1395 int x, y; 1396 const unsigned char * string = lcd_putshelper(L, &x, &y); 1397 RB_SCREENS(L, 4, puts, x, y, string); 1398 return 0; 1399} 1400 1401/* Helper function for opt_viewport lcd_put_line */ 1402static int check_tablevalue_def(lua_State *L, const char* key, int tablepos, int def) 1403{ 1404 lua_getfield(L, tablepos, key); /* Find table[key] */ 1405 1406 int val; 1407 1408 if (lua_isboolean(L, -1)) 1409 val = lua_toboolean (L, -1); /*True = 1 and False = 0*/ 1410 else 1411 val = luaL_optinteger(L, -1, def); 1412 1413 lua_pop(L, 1); /* Pop the value off the stack */ 1414 return val; 1415} 1416 1417/* Helper function for opt_viewport lcd_put_line */ 1418static int check_tablevalue(lua_State *L, const char* key, int tablepos) 1419{ 1420 /* returns 0 if key doesn't exist */ 1421 return check_tablevalue_def(L, key, tablepos, 0); 1422} 1423 1424RB_WRAP(lcd_put_line) 1425{ 1426 /*x, y, text, t_linedesc, [screen = MAIN]*/ 1427 1428#if 0 1429 /* height of the line (in pixels). -1 to inherit the height 1430 * from the font. The text will be centered if the height is larger, 1431 * but the decorations will span the entire height */ 1432 int height; 1433 /* multiline support: For some decorations (e.g. gradient) to work 1434 * across multiple lines (e.g. to draw a line selector across 2 lines) 1435 * the line index and line count must be known. For normal, single 1436 * lines specify nlines=1 and line=0 */ 1437 /* line count of a group */ 1438 int16_t nlines; 1439 /* index of the line in the group */ 1440 int16_t line; 1441 /* line text color if STYLE_COLORED is specified, in native 1442 * lcd format (convert with LCD_RGBPACK() if necessary) */ 1443 unsigned text_color; 1444 /* line color if STYLE_COLORBAR or STYLE_GRADIENT is specified, in native 1445 * lcd format (convert with LCD_RGBPACK() if necessary) */ 1446 unsigned line_color, line_end_color; 1447 /* line decorations, see STYLE_DEFAULT etc. */ 1448 enum line_styles style; 1449 /* whether the line can scroll */ 1450 bool scroll; 1451 /* height of the line separator (in pixels). 0 to disable drawing 1452 * of the separator */ 1453 int8_t separator_height; 1454#endif 1455 1456/*LINE_DESC_DEFINIT { .style = STYLE_DEFAULT, .height = -1, .separator_height = 0, .line = 0, .nlines = 1, .scroll = false }*/ 1457 1458 struct line_desc linedes = LINE_DESC_DEFINIT; 1459 1460 bool is_selected = false; 1461 bool show_icons = false; 1462 bool show_cursor = false; 1463 1464 int line_indent = 0; 1465 int item_offset = 0; 1466 1467 int x = (int) luaL_checkint(L, 1); 1468 int y = (int) luaL_checkint(L, 2); 1469 1470 const unsigned char * string = luaL_checkstring(L, 3); 1471 int icon = Icon_NOICON; 1472 const int narg = 4; 1473 1474 if(lua_type(L, narg) == LUA_TTABLE) 1475 { 1476 /* check_tablevalue only returns INTS */ 1477 linedes.line = check_tablevalue(L, "line", narg); 1478 linedes.height = check_tablevalue_def(L, "height", narg, -1); 1479 linedes.nlines = check_tablevalue_def(L, "nlines", narg, 1); 1480 linedes.style = check_tablevalue_def(L, "style", narg, STYLE_DEFAULT); 1481 linedes.separator_height = check_tablevalue(L, "separator_height", narg); 1482 linedes.scroll = check_tablevalue(L, "scroll", narg) > 0; 1483 1484 linedes.text_color = check_tablevalue(L, "text_color", narg); 1485 linedes.line_color = check_tablevalue(L, "line_color", narg); 1486 linedes.line_end_color = check_tablevalue(L, "line_end_color", narg); 1487 1488 icon = check_tablevalue_def(L, "icon", narg, Icon_NOICON); 1489 show_icons = check_tablevalue(L, "show_icons", narg) > 0 && icon > Icon_NOICON; 1490 show_cursor = check_tablevalue(L, "show_cursor", narg) > 0; 1491 is_selected = check_tablevalue(L, "selected", narg) > 0; 1492 1493 line_indent = check_tablevalue(L, "indent", narg); 1494 item_offset = check_tablevalue(L, "offset", narg); 1495 1496 } 1497 1498 while (*string == '\t') 1499 { 1500 line_indent++; 1501 string++; 1502 } 1503 1504 /* mask out gradient and colorbar styles for non-color displays */ 1505 if (RB_SCREEN_STRUCT(L, 5)->depth < 16) 1506 { 1507 if (linedes.style & (STYLE_COLORBAR|STYLE_GRADIENT)) 1508 { 1509 linedes.style &= ~(STYLE_COLORBAR|STYLE_GRADIENT); 1510 linedes.style |= STYLE_INVERT; 1511 } 1512 linedes.style &= ~STYLE_COLORED; 1513 } 1514 1515 if (show_cursor && (show_icons && icon > Icon_NOICON)) 1516 RB_SCREENS(L, 5, put_line, x, y, &linedes, 1517 "$*s$"ICON_PADDING_S"I$i$"ICON_PADDING_S"s$*t", 1518 line_indent, is_selected ? Icon_Cursor : Icon_NOICON, 1519 icon, item_offset, string); 1520 else if (show_cursor || (show_icons && icon > Icon_NOICON)) 1521 RB_SCREENS(L, 5, put_line, x, y, &linedes, 1522 "$*s$"ICON_PADDING_S"I$*t", line_indent, 1523 show_cursor ? (is_selected ? Icon_Cursor:Icon_NOICON):icon, 1524 item_offset, string); 1525 else 1526 RB_SCREENS(L, 5, put_line, x, y, &linedes, "$*s$*t", line_indent, item_offset, string); 1527 1528 1529 return 0; 1530} 1531 1532RB_WRAP(lcd_puts_scroll) 1533{ 1534 int x, y; 1535 const unsigned char * string = lcd_putshelper(L, &x, &y); 1536 bool result = RB_SCREENS(L, 4, puts_scroll, x, y, string); 1537 lua_pushboolean(L, result); 1538 return 1; 1539} 1540 1541RB_WRAP(lcd_scroll_stop) 1542{ 1543 RB_SCREENS(L, 1, scroll_stop); 1544 return 0; 1545} 1546 1547static inline struct viewport* opt_viewport(lua_State *L, 1548 int narg, 1549 bool set_coords, 1550 struct viewport* vp, 1551 struct viewport* alt) 1552{ 1553 if(lua_isnoneornil(L, narg)) 1554 return alt; 1555 1556 luaL_checktype(L, narg, LUA_TTABLE); 1557 if (set_coords) 1558 { 1559 vp->x = check_tablevalue(L, "x", narg); 1560 vp->y = check_tablevalue(L, "y", narg); 1561 vp->width = check_tablevalue(L, "width", narg); 1562 vp->height = check_tablevalue(L, "height", narg); 1563 } 1564 vp->font = check_tablevalue_def(L, "font", narg, FONT_UI); 1565 vp->drawmode = check_tablevalue_def(L, "drawmode", narg, DRMODE_SOLID); 1566 1567#if LCD_DEPTH == 2 1568 unsigned int fg = check_tablevalue(L, "fg_pattern", narg); 1569 unsigned int bg = check_tablevalue(L, "bg_pattern", narg); 1570 /*invert fg and bg patterns (3-)*/ 1571 vp->fg_pattern = 0x55 * (3 - (~(fg) & 3)); 1572 vp->bg_pattern = 0x55 * (3 - (~(bg) & 3)); 1573#elif LCD_DEPTH > 1 1574 vp->fg_pattern = (unsigned int) check_tablevalue(L, "fg_pattern", narg); 1575 vp->bg_pattern = (unsigned int) check_tablevalue(L, "bg_pattern", narg); 1576#endif 1577 1578 return vp; 1579} 1580 1581RB_WRAP(set_viewport) 1582{ 1583 void *ud = rli_checktype_opt(L, 1); 1584 if (ud != NULL) 1585 { 1586 img_set_as_vp((struct rocklua_image*) ud, &img_vp); 1587 RB_SCREENS(L, 3, set_viewport, opt_viewport(L, 2, false, &img_vp, &img_vp)); 1588 return 0; 1589 } 1590 static struct viewport vp; 1591 RB_SCREENS(L, 2, set_viewport, opt_viewport(L, 1, true, &vp, NULL)); 1592 return 0; 1593} 1594 1595RB_WRAP(clear_viewport) 1596{ 1597 RB_SCREENS(L, 1, clear_viewport); 1598 return 0; 1599} 1600 1601RB_WRAP(font_getstringsize) 1602{ 1603 const unsigned char* str = luaL_checkstring(L, 1); 1604 int fontnumber = lua_tointeger(L, 2); 1605 int w, h, result; 1606 1607 if (fontnumber == FONT_UI) 1608 fontnumber = rb->global_status->font_id[SCREEN_MAIN]; 1609 else 1610 fontnumber = FONT_SYSFIXED; 1611 1612 if lua_isnoneornil(L, 2) 1613 result = RB_SCREENS(L, 3, getstringsize, str, &w, &h); 1614 else 1615 result = rb->font_getstringsize(str, &w, &h, fontnumber); 1616 1617 lua_pushinteger(L, result); 1618 lua_pushinteger(L, w); 1619 lua_pushinteger(L, h); 1620 1621 return 3; 1622} 1623 1624RB_WRAP(lcd_framebuffer) 1625{ 1626 int screen = get_screen(L, 1); 1627 static struct viewport vp; 1628 rb->viewport_set_fullscreen(&vp, screen); 1629 rli_wrap(L, vp.buffer->data, 1630 RB_SCREEN_STRUCT(L, 1)->lcdwidth, 1631 RB_SCREEN_STRUCT(L, 1)->lcdheight); 1632 return 1; 1633} 1634 1635RB_WRAP(lcd_setfont) 1636{ 1637 int font = (int) luaL_checkint(L, 1); 1638 RB_SCREENS(L, 2, setfont, font); 1639 return 0; 1640} 1641 1642/* helper function for lcd_xxx_bitmap/rect functions */ 1643static void checkint_arr(lua_State *L, int *val, int narg, int elems) 1644{ 1645 /* fills passed array of integers with lua integers from stack */ 1646 for (int i = 0; i < elems; i++) 1647 val[i] = luaL_checkint(L, narg + i); 1648} 1649 1650RB_WRAP(gui_scrollbar_draw) 1651{ 1652 enum {x = 0, y, w, h, items, min_shown, max_shown, flags, eCNT}; 1653 int v[eCNT]; 1654 checkint_arr(L, v, 1, eCNT); 1655 1656 rb->gui_scrollbar_draw(RB_SCREEN_STRUCT(L, 9), v[x], v[y], v[w], v[h], 1657 v[items], v[min_shown], v[max_shown], (unsigned) v[flags]); 1658return 0; 1659} 1660 1661RB_WRAP(lcd_mono_bitmap_part) 1662{ 1663 struct rocklua_image *src = rli_checktype(L, 1); 1664 enum {src_x = 0, src_y, stride, x, y, w, h, eCNT}; 1665 int v[eCNT]; 1666 checkint_arr(L, v, 2, eCNT);; 1667 1668 RB_SCREENS(L, 9, mono_bitmap_part, (const unsigned char *)src->data, 1669 v[src_x], v[src_y], v[stride], v[x], v[y], v[w], v[h]); 1670 return 0; 1671} 1672 1673RB_WRAP(lcd_mono_bitmap) 1674{ 1675 struct rocklua_image *src = rli_checktype(L, 1); 1676 enum {x = 0, y, w, h, eCNT}; 1677 int v[eCNT]; 1678 checkint_arr(L, v, 2, eCNT); 1679 1680 RB_SCREENS(L, 6, mono_bitmap, (const unsigned char *)src->data, 1681 v[x], v[y], v[w], v[h]); 1682 return 0; 1683} 1684 1685#if LCD_DEPTH > 1 1686RB_WRAP(lcd_bitmap_part) 1687{ 1688 struct rocklua_image *src = rli_checktype(L, 1); 1689 enum {src_x = 0, src_y, stride, x, y, w, h, eCNT}; 1690 int v[eCNT]; 1691 checkint_arr(L, v, 2, eCNT); 1692 1693 RB_SCREENS(L, 9, bitmap_part, src->data, 1694 v[src_x], v[src_y], v[stride], v[x], v[y], v[w], v[h]); 1695 return 0; 1696} 1697 1698RB_WRAP(lcd_bitmap) 1699{ 1700 struct rocklua_image *src = rli_checktype(L, 1); 1701 enum {x = 0, y, w, h, eCNT}; 1702 int v[eCNT]; 1703 checkint_arr(L, v, 2, eCNT); 1704 1705 RB_SCREENS(L, 6, bitmap, src->data, v[x], v[y], v[w], v[h]); 1706 return 0; 1707} 1708 1709RB_WRAP(lcd_get_backdrop) 1710{ 1711 fb_data* backdrop = rb->lcd_get_backdrop(); 1712 if(backdrop == NULL) 1713 lua_pushnil(L); 1714 else 1715 rli_wrap(L, backdrop, LCD_WIDTH, LCD_HEIGHT); 1716 1717 return 1; 1718} 1719 1720RB_WRAP(lcd_set_foreground) 1721{ 1722 unsigned foreground = (unsigned) luaL_checkint(L, 1); 1723 RB_SCREENS(L, 2, set_foreground, foreground); 1724 return 0; 1725} 1726 1727RB_WRAP(lcd_get_foreground) 1728{ 1729 unsigned result = RB_SCREENS(L, 1, get_foreground); 1730 lua_pushinteger(L, result); 1731 return 1; 1732} 1733 1734RB_WRAP(lcd_set_background) 1735{ 1736 unsigned background = (unsigned) luaL_checkint(L, 1); 1737 RB_SCREENS(L, 2, set_background, background); 1738 return 0; 1739} 1740 1741RB_WRAP(lcd_get_background) 1742{ 1743 unsigned result = RB_SCREENS(L, 1, get_background); 1744 lua_pushinteger(L, result); 1745 return 1; 1746} 1747#endif /* LCD_DEPTH > 1 */ 1748 1749#if (LCD_DEPTH < 4) && (CONFIG_PLATFORM & PLATFORM_NATIVE) 1750RB_WRAP(lcd_blit_grey_phase) 1751{ 1752 /* note that by and bheight are in 8-pixel units! */ 1753 unsigned char * values = (unsigned char *) luaL_checkstring(L, 1); 1754 unsigned char * phases = (unsigned char *) luaL_checkstring(L, 2); 1755 enum {bx = 0, by, bw, bh, stride, eCNT}; 1756 int v[eCNT]; 1757 checkint_arr(L, v, 3, eCNT); 1758 1759 rb->lcd_blit_grey_phase(values, phases, v[bx], v[by], v[bw], v[bh], v[stride]); 1760 return 0; 1761} 1762 1763RB_WRAP(lcd_blit_mono) 1764{ 1765 /* note that by and bheight are in 8-pixel units! */ 1766 const unsigned char * data = (const unsigned char *) luaL_checkstring(L, 1); 1767 enum {x = 0, by, w, bh, stride, eCNT}; 1768 int v[eCNT]; 1769 checkint_arr(L, v, 3, eCNT); 1770 1771 rb->lcd_blit_mono(data, v[x], v[by], v[w], v[bh], v[stride]); 1772 return 0; 1773} 1774#endif /* LCD_DEPTH < 4 && CONFIG_PLATFORM & PLATFORM_NATIVE */ 1775 1776#if LCD_DEPTH == 16 1777RB_WRAP(lcd_bitmap_transparent_part) 1778{ 1779 struct rocklua_image *src = rli_checktype(L, 1); 1780 enum {src_x = 0, src_y, stride, x, y, w, h, eCNT}; 1781 int v[eCNT]; 1782 checkint_arr(L, v, 2, eCNT); 1783 1784 RB_SCREENS(L, 9, transparent_bitmap_part, src->data, 1785 v[src_x], v[src_y], v[stride], v[x], v[y], v[w], v[h]); 1786 return 0; 1787} 1788 1789RB_WRAP(lcd_bitmap_transparent) 1790{ 1791 struct rocklua_image *src = rli_checktype(L, 1); 1792 enum {x = 0, y, w, h, eCNT}; 1793 int v[eCNT]; 1794 checkint_arr(L, v, 2, eCNT); 1795 1796 RB_SCREENS(L, 6, transparent_bitmap, src->data, v[x], v[y], v[w], v[h]); 1797 return 0; 1798} 1799#endif /* LCD_DEPTH == 16 */ 1800 1801RB_WRAP(lcd_update_rect) 1802{ 1803 enum {x = 0, y, w, h, eCNT}; 1804 int v[eCNT]; 1805 checkint_arr(L, v, 1, eCNT); 1806 1807 RB_SCREENS(L, 5, update_rect, v[x], v[y], v[w], v[h]); 1808 return 0; 1809} 1810 1811RB_WRAP(lcd_drawrect) 1812{ 1813 enum {x = 0, y, w, h, eCNT}; 1814 int v[eCNT]; 1815 checkint_arr(L, v, 1, eCNT); 1816 1817 RB_SCREENS(L, 5, drawrect, v[x], v[y], v[w], v[h]); 1818 return 0; 1819} 1820 1821RB_WRAP(lcd_fillrect) 1822{ 1823 enum {x = 0, y, w, h, eCNT}; 1824 int v[eCNT]; 1825 checkint_arr(L, v, 1, eCNT); 1826 1827 RB_SCREENS(L, 5, fillrect, v[x], v[y], v[w], v[h]); 1828 return 0; 1829} 1830 1831RB_WRAP(lcd_drawline) 1832{ 1833 enum {x1 = 0, y1, x2, y2, eCNT}; 1834 int v[eCNT]; 1835 checkint_arr(L, v, 1, eCNT); 1836 1837 RB_SCREENS(L, 5, drawline, v[x1], v[y1], v[x2], v[y2]); 1838 return 0; 1839} 1840 1841RB_WRAP(lcd_hline) 1842{ 1843 enum {x1 = 0, x2, y, eCNT}; 1844 int v[eCNT]; 1845 checkint_arr(L, v, 1, eCNT); 1846 1847 RB_SCREENS(L, 4, hline, v[x1], v[x2], v[y]); 1848 return 0; 1849} 1850 1851RB_WRAP(lcd_vline) 1852{ 1853 enum {x = 0, y1, y2, eCNT}; 1854 int v[eCNT]; 1855 checkint_arr(L, v, 1, eCNT); 1856 1857 RB_SCREENS(L, 4, vline, v[x], v[y1], v[y2]); 1858 return 0; 1859} 1860 1861RB_WRAP(lcd_drawpixel) 1862{ 1863 int x = (int) luaL_checkint(L, 1); 1864 int y = (int) luaL_checkint(L, 2); 1865 RB_SCREENS(L, 3, drawpixel, x, y); 1866 return 0; 1867} 1868 1869#ifdef HAVE_LCD_COLOR 1870RB_WRAP(lcd_rgbpack) 1871{ 1872 enum {r = 0, g, b, eCNT}; 1873 int v[eCNT]; 1874 checkint_arr(L, v, 1, eCNT); 1875 1876 int result = LCD_RGBPACK(v[r], v[g], v[b]); 1877 lua_pushinteger(L, result); 1878 return 1; 1879} 1880 1881RB_WRAP(lcd_rgbunpack) 1882{ 1883 int rgb = luaL_checkint(L, 1); 1884 lua_pushinteger(L, RGB_UNPACK_RED(rgb)); 1885 lua_pushinteger(L, RGB_UNPACK_GREEN(rgb)); 1886 lua_pushinteger(L, RGB_UNPACK_BLUE(rgb)); 1887 return 3; 1888} 1889#endif 1890 1891RB_WRAP(read_bmp_file) 1892{ 1893 struct bitmap bm; 1894 const char* filename = luaL_checkstring(L, 1); 1895 bool dither = luaL_optboolean(L, 2, true); 1896 bool transparent = luaL_optboolean(L, 3, false); 1897 int format = FORMAT_NATIVE; 1898 1899 if(dither) 1900 format |= FORMAT_DITHER; 1901 1902 if(transparent) 1903 format |= FORMAT_TRANSPARENT; 1904 1905 int result = rb->read_bmp_file(filename, &bm, 0, format | FORMAT_RETURN_SIZE, NULL); 1906 1907 if(result > 0) 1908 { 1909 bm.data = (unsigned char*) rli_alloc(L, bm.width, bm.height); 1910 if(rb->read_bmp_file(filename, &bm, result, format, NULL) < 0) 1911 { 1912 /* Error occured, drop newly allocated image from stack */ 1913 lua_pop(L, 1); 1914 lua_pushnil(L); 1915 } 1916 } 1917 else 1918 lua_pushnil(L); 1919 1920 return 1; 1921} 1922 1923#define R(NAME) {#NAME, rock_##NAME} 1924static const luaL_Reg rocklib_img[] = 1925{ 1926 /* Graphics */ 1927 R(lcd_update), 1928 R(lcd_clear_display), 1929 R(lcd_set_drawmode), 1930 R(lcd_putsxy), 1931 R(lcd_puts), 1932 R(lcd_put_line), 1933 R(lcd_puts_scroll), 1934 R(lcd_scroll_stop), 1935 R(set_viewport), 1936 R(clear_viewport), 1937 R(font_getstringsize), 1938 R(lcd_framebuffer), 1939 R(lcd_setfont), 1940 R(gui_scrollbar_draw), 1941 R(lcd_mono_bitmap_part), 1942 R(lcd_mono_bitmap), 1943#if LCD_DEPTH > 1 1944 R(lcd_get_backdrop), 1945 R(lcd_bitmap_part), 1946 R(lcd_bitmap), 1947 R(lcd_set_foreground), 1948 R(lcd_get_foreground), 1949 R(lcd_set_background), 1950 R(lcd_get_background), 1951#endif /* LCD_DEPTH > 1 */ 1952#if (LCD_DEPTH < 4) && (CONFIG_PLATFORM & PLATFORM_NATIVE) 1953 R(lcd_blit_grey_phase), 1954 R(lcd_blit_mono), 1955#endif /* LCD_DEPTH < 4 && CONFIG_PLATFORM & PLATFORM_NATIVE */ 1956#if LCD_DEPTH == 16 1957 R(lcd_bitmap_transparent_part), 1958 R(lcd_bitmap_transparent), 1959#endif 1960 R(lcd_update_rect), 1961 R(lcd_drawrect), 1962 R(lcd_fillrect), 1963 R(lcd_drawline), 1964 R(lcd_hline), 1965 R(lcd_vline), 1966 R(lcd_drawpixel), 1967 1968#ifdef HAVE_LCD_COLOR 1969 R(lcd_rgbpack), 1970 R(lcd_rgbunpack), 1971#endif 1972 R(read_bmp_file), 1973 {"new_image", rli_new}, 1974 1975 {NULL, NULL} 1976}; 1977#undef R 1978 1979LUALIB_API int luaopen_rock_img(lua_State *L) 1980{ 1981 /* some devices need x | y coords shifted to match native format */ 1982 /* conversion between packed native formats and individual pixel addressing */ 1983 init_pixelmask(&x_shift, &y_shift, &xy_mask, &pixelmask); 1984 1985 luaL_newmetatable(L, ROCKLUA_IMAGE); 1986 1987 lua_pushvalue(L, -1); /* pushes the metatable */ 1988 lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */ 1989 luaL_register(L, NULL, rli_lib); /*add rli_lib to the image metatable*/ 1990 1991 luaL_register(L, LUA_ROCKLIBNAME, rocklib_img); 1992 1993 return 1; 1994} 1995