A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
2
fork

Configure Feed

Select the types of activity you want to include in your feed.

lua use lcd_drawline to draw lines inside rliimages

rewrite draw_text to use new viewport buffer

set_viewport now accepts rliimage to allowe interfacing with rb. functions

fix long standing 2-bit bug with text drawing in lua
fix 2-bit img
saving bug (i'm guessing just a one off, just enabled clipping)

fix font_getstringsize bug

fix shape of numbers draw_num.lua also add auto centering

add page scrolling to printtable

add a new demo script 'stars'

Change-Id: I866905cee82ee89ebc0eb020a56a7ecdb101bf5e

authored by

William Wilgus and committed by
William Wilgus
a6570b7d 7f1b4969

+431 -106
+5 -16
apps/plugins/lua/include_lua/draw_num.lua
··· 20 20 * 21 21 ****************************************************************************/ 22 22 ]] 23 - 24 23 --[[ Exposed Functions 25 24 _draw_nums.print; binary (base = 2) , octal (base = 8), hexadecimal (base = 16) 26 25 _draw_nums.nums; table of number characters 27 26 ]] 28 - 29 27 if not rb.lcd_framebuffer then rb.splash(rb.HZ, "No Support!") return nil end 30 - 31 28 local _draw_nums = {} do 32 29 local _poly = require "draw_poly" 33 - 34 30 -- every 2 elements is an x, y coord pair 35 31 -- n[?] = {x,y,x,y,x,y} 36 32 local nums = { ··· 43 39 [2] = {1,1,3,1,4,2,4,3,3,4,1,5,1,7,4,7}, 44 40 [3] = {1,1,3,1,4,2,4,3,3,4,2,4,3,4,4,5,4,6,3,7,1,7}, 45 41 [4] = {1,1,1,3,2,4,4,4,4,1,4,7}, 46 - [5] = {1,1,4,1,1,1,1,4,3,4,4,5,4,7,1,7}, 47 - [6] = {1,2,1,4,1,6,2,7,3,7,4,6,4,4,1,4,1,2,2,1,4,1}, 42 + [5] = {1,1,4,1,1,1,1,4,3,4,4,5,4,6,3,7,1,7}, 43 + [6] = {1,2,1,4,1,6,2,7,3,7,4,6,4,5,3,4,1,4,1,2,2,1,3,1,4,2}, 48 44 [7] = {1,1,4,1,4,2,1,7}, 49 - [8] = {1,2,1,6,2,7,3,7,4,6,4,4,1,4,4,4,4,2,3,1,2,1,1,2}, 50 - [9] = {4,6,4,4,4,2,3,1,2,1,1,2,1,4,4,4,4,6,3,7,1,7}, 45 + [8] = {1,2,4,5,4,6,3,7,2,7,1,6,1,5,4,2,3,1,2,1,1,2}, 46 + [9] = {4,6,4,4,4,2,3,1,2,1,1,2,1,3,2,4,4,4,4,6,3,7,2,7,1,6}, 51 47 [10] = {1,7,1,4,4,4,4,7,4,2,3,1,2,1,1,2,1,4}, 52 48 [11] = {1,1,1,7,3,7,4,6,4,5,3,4,1,4,3,4,4,3,4,2,3,1,1,1}, 53 49 [12] = {4,2,3,1,2,1,1,2,1,6,2,7,3,7,4,6}, ··· 56 52 [15] = {4,1,1,1,1,4,3,4,1,4,1,7}, 57 53 } 58 54 _draw_nums.nums = nums 59 - 60 - 61 55 _draw_nums.print = function(img, num, x, y, chrw, color, base, prefix, bClip, scale_x, scale_y, t_nums) 62 56 scale_x = scale_x or 1 63 57 scale_y = scale_y or 1 ··· 65 59 prefix = (prefix == nil or prefix == true) and true or false 66 60 t_nums = t_nums or nums 67 61 local max_x, max_y, digits = 0, 0, {} 68 - 69 62 if num <= 0 then 70 63 if num < 0 then 71 64 digits[-3] = -1 ··· 74 67 digits[0] = 0 75 68 end 76 69 end 77 - 78 70 if not prefix and (base == 2 or base == 8 or base == 16) then 79 71 -- no prefix 80 72 elseif base == 2 then ··· 92 84 error("unknown number base: " .. base) 93 85 return nil 94 86 end 95 - 96 87 while num > 0 do -- get each digit (LeastSignificant) 97 88 digits[#digits + 1] = num % base; 98 89 num=num/base; 99 90 end 100 - 101 91 digits[#digits + 1] = digits[0] -- zero 102 92 digits[#digits + 1] = digits[-1] -- base prefix 103 93 digits[#digits + 1] = digits[-2] -- base prefix (hex) 104 94 digits[#digits + 1] = digits[-3] -- neg sign 105 - 106 95 for i = #digits, 1, -1 do 107 96 max_x, max_y = _poly.polyline(img, x, y, t_nums[digits[i]], 108 97 color, false, bClip, scale_x, scale_y) 98 + if chrw == 0 then chrw = max_x end 109 99 x = x + chrw 110 100 end 111 - 112 101 return x, y + max_y, chrw 113 102 end 114 103 end
+19 -66
apps/plugins/lua/include_lua/draw_text.lua
··· 23 23 -- draw text onto image if width/height are supplied text is centered 24 24 25 25 if not rb.lcd_framebuffer then rb.splash(rb.HZ, "No Support!") return nil end 26 - 27 26 do 28 27 -- Internal Constants 29 28 local rocklib_image = getmetatable(rb.lcd_framebuffer()) ··· 40 39 return function(img, x, y, width, height, font, color, text) 41 40 font = font or rb.FONT_UI 42 41 43 - local opts = {x = 0, y = 0, width = LCD_W - 1, height = LCD_H - 1, 44 - font = font, drawmode = 3, fg_pattern = 0x1, bg_pattern = 0} 45 42 46 - if rb.LCD_DEPTH == 2 then -- invert 2-bit screens 47 - --vp.drawmode = bit.bxor(vp.drawmode, 4) 48 - opts.fg_pattern = 3 - opts.fg_pattern 49 - opts.bg_pattern = 3 - opts.bg_pattern 50 - end 51 - rb.set_viewport(opts) 52 - 53 - local res, w, h = rb.font_getstringsize(text, font) 54 - 55 - if not width then 56 - width = 0 43 + if rb.lcd_rgbpack ~= _NIL then -- Color target 44 + rb.set_viewport(img, {fg_pattern = color, font = font, drawmode = 2})--DRMODE_FG 57 45 else 58 - width = (width - w) / 2 46 + if color ~= 0 then color = 3 end--DRMODE_SOLID 47 + rb.set_viewport(img, {font = font, drawmode = color}) 59 48 end 60 49 61 - if not height then 62 - height = 0 63 - else 64 - height = (height - h) / 2 65 - end 50 + if width or height then 51 + local res, w, h = rb.font_getstringsize(text, font) 66 52 67 - -- make a copy of the current screen for later 68 - --local screen_img = _newimg(LCD_W, LCD_H) 69 - local screen_img = _newimg(LCD_W, h * 2) 70 - _copy(screen_img, _LCD) 53 + if not width then 54 + width = 0 55 + else 56 + width = (width - w) / 2 57 + end 71 58 72 - -- check if the screen buffer is supplied image if so set img to the copy 73 - if img == _LCD then 74 - img = screen_img 75 - end 76 - 77 - -- we will be printing the text to the screen then blitting into img 78 - --rb.lcd_clear_display() 79 - _clear(_LCD, opts.bg_pattern or 0, 1, 1, LCD_W, h * 2) 80 - 81 - if w > LCD_W then -- text is too long for the screen do it in chunks 82 - local l = 1 83 - local resp, wp, hp 84 - local lenr = text:len() 85 - 86 - while lenr > 1 do 87 - l = lenr 88 - resp, wp, hp = rb.font_getstringsize(text:sub(1, l), font) 89 - 90 - while wp >= LCD_W and l > 1 do 91 - l = l - 1 92 - resp, wp, hp = rb.font_getstringsize(text:sub( 1, l), font) 93 - end 94 - 95 - rb.lcd_putsxy(0, 0, text:sub(1, l)) 96 - text = text:sub(l) 97 - 98 - if x + width > img:width() or y + height > img:height() then 99 - break 100 - end 101 - 102 - -- using the mask we made blit color into img 103 - _copy(img, _LCD, x + width, y + height, _NIL, _NIL, _NIL, _NIL, false, BSAND, color) 104 - x = x + wp 105 - --rb.lcd_clear_display() 106 - _clear(_LCD, opts.bg_pattern or 0, 1, 1, LCD_W, h * 2) 107 - 108 - lenr = text:len() 59 + if not height then 60 + height = 0 61 + else 62 + height = (height - h) / 2 109 63 end 110 - else --w <= LCD_W 111 - rb.lcd_putsxy(0, 0, text) 64 + x = width + x 65 + y = height + y 112 66 113 - -- using the mask we made blit color into img 114 - _copy(img, _LCD, x + width, y + height, _NIL, _NIL, _NIL, _NIL, false, BSAND, color) 115 67 end 116 68 117 - _copy(_LCD, screen_img) -- restore screen 69 + rb.lcd_putsxy(x, y, text) 70 + 118 71 rb.set_viewport() -- set viewport default 119 72 return res, w, h 120 73 end
+1 -1
apps/plugins/lua/include_lua/image_save.lua
··· 198 198 end 199 199 200 200 -- Bitmap lines start at bottom unless biHeight is negative 201 - for point in _points(img, 1, h, w + bytesleft, 1) do 201 + for point in _points(img, 1, h, w + bytesleft, 1, 1, 1, true) do 202 202 imgdata[#imgdata + 1] = fs_bytes_E(bpp, point or 0) 203 203 204 204 if #fbuffer >= 31 then -- buffered write, increase # for performance
+8 -1
apps/plugins/lua/include_lua/printtable.lua
··· 145 145 146 146 local wrap, justify, start, curpos, co_routine, hasheader, m_sel 147 147 local header_fgc, header_bgc, item_fgc, item_bgc, item_selc 148 - local table_linedesc, drawsep, overflow, dpad_fn 148 + local table_linedesc, drawsep, overflow, dpad_fn, pagescroll 149 149 do 150 150 local s = settings or _print.get_settings() 151 151 wrap, justify = s.wrap, s.justify 152 152 start, curpos = s.start, s.curpos 153 153 co_routine = s.co_routine 154 154 hasheader = s.hasheader 155 + pagescroll = s.pagescroll 155 156 drawsep = s.drawsep 156 157 sb_width = s.sb_width or sb_width 157 158 m_sel = false ··· 234 235 dpad_fn(t_p.col, -1, -t_p.col_scrl, t_p.row, -1, -t_p.row_scrl, 235 236 nil, overflow, (t_p.row + t_p.vcursor - 1)) 236 237 238 + 239 + if pagescroll == true then 240 + t_p.row = t_p.row + y_chg * maxline - 1 241 + end 237 242 t_p.vcursor = t_p.vcursor + y_chg 243 + 238 244 239 245 if t_p.vcursor > maxline or t_p.vcursor < t_p.vcursor_min then 240 246 t_p.row = yi ··· 268 274 elseif y_chg ~= 0 then 269 275 --t_p.col = 0 -- reset column to the beginning 270 276 _print.clear() 277 + 271 278 _print.opt.sel_line(t_p.vcursor) 272 279 273 280 t_p.row_scrl = set_accel(timeb, t_p.row_scrl, t_p)
+135 -15
apps/plugins/lua/rocklib_img.c
··· 81 81 struct rocklua_image *img; 82 82 }; 83 83 84 + /* viewport for rliimages to use rb functions */ 85 + static 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 + 99 + static 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 */ 118 + static 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 + 84 135 /* __tostring information enums */ 85 136 enum rli_info {RLI_INFO_ALL = 0, RLI_INFO_TYPE, RLI_INFO_WIDTH, 86 137 RLI_INFO_HEIGHT, RLI_INFO_ELEMS, RLI_INFO_BYTES, ··· 261 312 luaL_argerror(L, narg, ERR_IDX_RANGE); 262 313 } /* bounds_check_xy */ 263 314 264 - static struct rocklua_image* rli_checktype(lua_State *L, int arg) 315 + static struct rocklua_image* rli_checktype_opt(lua_State *L, int arg) 265 316 { 266 317 #if 0 267 318 return (struct rocklua_image*) luaL_checkudata(L, arg, ROCKLUA_IMAGE); ··· 284 335 } 285 336 } 286 337 } 338 + /* Not a ROCKLUA IMAGE */ 339 + return NULL; 340 + #endif 341 + } /* rli_checktype_opt*/ 287 342 288 - luaL_typerror(L, arg, ROCKLUA_IMAGE); /* else error */ 289 - return NULL; /* to avoid warnings */ 290 - #endif 343 + static 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; 291 349 } /* rli_checktype */ 292 350 293 351 static struct rocklua_image * alloc_rlimage(lua_State *L, bool alloc_data, ··· 519 577 return true; 520 578 } /* next_rli_iter */ 521 579 580 + #if 0 522 581 static void d_line(struct rocklua_image *img, 523 582 int x1, int y1, 524 583 int x2, int y2, ··· 575 634 } 576 635 577 636 } /* d_line */ 637 + #endif 638 + 639 + 640 + static 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 = *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 */ 578 669 579 670 /* ellipse worker function */ 580 671 static void d_ellipse_elements(struct rocklua_image * img, ··· 1266 1357 1267 1358 RB_WRAP(lcd_set_drawmode) 1268 1359 { 1360 + int previous; 1269 1361 int mode = (int) luaL_checkint(L, 1); 1270 - RB_SCREENS(L, 2, set_drawmode, mode); 1271 - return 0; 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; 1272 1375 } 1273 1376 1274 1377 /* helper function for lcd_puts functions */ ··· 1443 1546 1444 1547 static inline struct viewport* opt_viewport(lua_State *L, 1445 1548 int narg, 1549 + bool set_coords, 1446 1550 struct viewport* vp, 1447 1551 struct viewport* alt) 1448 1552 { ··· 1450 1554 return alt; 1451 1555 1452 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); 1453 1566 1454 - vp->x = check_tablevalue(L, "x", narg); 1455 - vp->y = check_tablevalue(L, "y", narg); 1456 - vp->width = check_tablevalue(L, "width", narg); 1457 - vp->height = check_tablevalue(L, "height", narg); 1458 - vp->font = check_tablevalue(L, "font", narg); 1459 - vp->drawmode = check_tablevalue_def(L, "drawmode", narg, DRMODE_SOLID); 1460 - #if LCD_DEPTH > 1 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 1461 1574 vp->fg_pattern = (unsigned int) check_tablevalue(L, "fg_pattern", narg); 1462 1575 vp->bg_pattern = (unsigned int) check_tablevalue(L, "bg_pattern", narg); 1463 1576 #endif ··· 1467 1580 1468 1581 RB_WRAP(set_viewport) 1469 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 + } 1470 1590 static struct viewport vp; 1471 - RB_SCREENS(L, 2, set_viewport, opt_viewport(L, 1, &vp, NULL)); 1591 + RB_SCREENS(L, 2, set_viewport, opt_viewport(L, 1, true, &vp, NULL)); 1472 1592 return 0; 1473 1593 } 1474 1594 ··· 1489 1609 else 1490 1610 fontnumber = FONT_SYSFIXED; 1491 1611 1492 - if lua_isnil(L, 2) 1612 + if lua_isnoneornil(L, 2) 1493 1613 result = RB_SCREENS(L, 3, getstringsize, str, &w, &h); 1494 1614 else 1495 1615 result = rb->font_getstringsize(str, &w, &h, fontnumber);
+7 -7
apps/plugins/lua_scripts/rlimg.lua
··· 76 76 ------------------------------------------- 77 77 local clrs 78 78 local CANCEL_BUTTON = rb.actions.PLA_CANCEL 79 - 79 + local LCD_DEPTH = rb.LCD_DEPTH 80 80 -- EXAMPLES ---------------------------------------------------------------------- EXAMPLES--------------------------------------------------------------------- 81 81 function my_blit(dst_val, dx, dy, src_val, sx, sy) 82 82 -- user defined blit operation ··· 84 84 --you may change pixels in both the source and dest image 85 85 --return nil to stop early 86 86 87 - if _lcd.DEPTH < 2 then 87 + if LCD_DEPTH < 2 then 88 88 return src_val 89 89 end 90 90 ··· 518 518 for ix = 1, _lcd.W, w do 519 519 y_col = y_col + 1 520 520 y = ims.y_pos[(y_col % 2) + 1] 521 - if _lcd.DEPTH > 1 then 521 + if LCD_DEPTH > 1 then 522 522 _lcd:copy(ims.strip, ix, 1, 1, y, w, h, false, _blit.BDEQC, colors[1]) 523 523 else 524 524 _lcd:copy(ims.strip, ix, 1, 1, y, w, h, false, _blit.BSAND) ··· 767 767 local wait = 0 768 768 w = w + wp * 3 769 769 h = h + 4 770 - local img = _img.new(w + 1, h) 770 + local img = _img.new(w + 1, h + 1) 771 771 img:clear(BLACK) 772 772 _draw.rounded_rect_filled(img, 1, 1, w, h, 15, WHITE) 773 - _draw_text(img, 1, 2, nil, nil, nil, BLACK, txt) 773 + _draw_text(img, 1, 1, nil, nil, nil, BLACK, txt) 774 774 775 775 for p = -w + 1, w - 1 do 776 776 wait = 0 ··· 858 858 [14] = function(EXIT_) return true end 859 859 } 860 860 861 - if _lcd.DEPTH < 2 then 861 + if LCD_DEPTH < 2 then 862 862 table.remove(mt, 10) 863 863 table.remove(ft, 10) 864 864 end ··· 880 880 -- Clear the screen 881 881 _lcd:clear(BLACK) 882 882 883 - if _lcd.DEPTH > 1 then 883 + if LCD_DEPTH > 1 then 884 884 --draw a gradient using available colors 885 885 if IS_COLOR_TARGET == true then 886 886 clrs = {
+256
apps/plugins/lua_scripts/stars.lua
··· 1 + --[[ 2 + __________ __ ___. 3 + Open \______ \ ____ ____ | | _\_ |__ _______ ___ 4 + Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / 5 + Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 6 + Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 7 + \/ \/ \/ \/ \/ 8 + $Id$ 9 + 10 + Copyright (C) 2024 William Wilgus 11 + This program is free software; you can redistribute it and/or 12 + modify it under the terms of the GNU General Public License 13 + as published by the Free Software Foundation; either version 2 14 + of the License, or (at your option) any later version. 15 + This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 16 + KIND, either express or implied. 17 + ]]-- 18 + --https://nullprogram.com/blog/2011/06/13/ [Infinite Parallax Starfield] 19 + 20 + -- Imports 21 + local _clr = require("color") -- clrset, clrinc provides device independent colors 22 + local _lcd = require("lcd") -- lcd helper functions 23 + local _draw = require("draw") -- draw all the things (primitives) 24 + local _poly = require("draw_poly") -- vector drawing with tables of coords 25 + require("actions") 26 + --'CONSTANTS' (in lua there really is no such thing as all vars are mutable) 27 + -------------------------------------------------------- 28 + --colors for fg/bg ------------------------ 29 + --first number of each quad is fallback for monochrome devices, excluded columns default to 0 30 + local WHITE = _clr.set(-1, 255, 255, 255) 31 + local BLACK = _clr.set(0, 0, 0, 0) 32 + local RED = _clr.set(WHITE, 100) 33 + local GREEN = _clr.set(WHITE, 0, 100) 34 + local BGREEN = _clr.set(WHITE, 0, 255) 35 + local BLUE = _clr.set(WHITE, 0, 0, 100) 36 + 37 + local STAR_SEED = 0x9d2c5680; 38 + local STAR_TILE_SIZE = math.max(rb.LCD_WIDTH, rb.LCD_HEIGHT) * 4; 39 + local bxor, band, rshift, lshift, arshift = bit.bxor, bit.band, bit.rshift, bit.lshift, bit.arshift 40 + local random, randomseed = math.random, math.randomseed 41 + local start_x, start_y, start_z 42 + 43 + -- load users coords from file if it exists 44 + local fname = rb.PLUGIN_DATA_DIR .. "/stars.pos" 45 + file = io.open(fname, "r") 46 + if file then 47 + local v = 0 48 + for line in file:lines() do 49 + v = v + 1 50 + if v == 1 then 51 + start_x = tonumber(line) or 0 52 + elseif v == 2 then 53 + start_y = tonumber(line) or 0 54 + elseif v == 3 then 55 + start_z = tonumber(line) or 0 56 + else 57 + break; 58 + end 59 + end 60 + io.close( file ) 61 + end 62 + 63 + -- Robert Jenkins' 96 bit Mix Function. 64 + local function mix (a, b, c) 65 + a=a-b; a=a-c; a=bxor(a, (rshift(c, 13))); 66 + b=b-c; b=b-a; b=bxor(b, (lshift(a, 8))); 67 + c=c-a; c=c-b; c=bxor(c, (rshift(b, 13))); 68 + a=a-b; a=a-c; a=bxor(a, (rshift(c, 12))); 69 + b=b-c; b=b-a; b=bxor(b, (lshift(a, 16))); 70 + c=c-a; c=c-b; c=bxor(c, (rshift(b, 5))); 71 + a=a-b; a=a-c; a=bxor(a, (rshift(c, 3))); 72 + b=b-c; b=b-a; b=bxor(b, (lshift(a, 10))); 73 + c=c-a; c=c-b; c=bxor(c, (rshift(b, 15))); 74 + 75 + return c 76 + end 77 + 78 + -- given 32 bit number returns a table of 8 nibbles (4 bits) 79 + local function s_bytes_nib(bits, value) 80 + -- bits must be multiples of 8 (sizeof byte) 81 + local bbuffer = {} 82 + local byte 83 + local nbytes = bit.rshift(bits, 3) 84 + for b = 1, nbytes do 85 + if value > 0 then 86 + byte = value % 256 87 + value = (value - byte) / 256 88 + else 89 + byte = 0 90 + end 91 + bbuffer[#bbuffer + 1] = band(byte,0xF) 92 + bbuffer[#bbuffer + 1] = band(rshift(byte, 2), 0xF) 93 + end 94 + return bbuffer 95 + end 96 + 97 + --[[ given table t and total elems desired uses random elems of t 98 + and random numbers between 1 and max_v if #t < total_elems]] 99 + function randomize_table(t, total_elems, max_v) 100 + local rand_t = {} 101 + local i = 1 102 + repeat 103 + local v = t[random(1, total_elems)] 104 + if v then 105 + rand_t[i] = v 106 + else 107 + rand_t[i] = random(1, max_v) 108 + end 109 + i = i + 1 110 + until i > total_elems 111 + return rand_t 112 + end 113 + 114 + local function drawship(img, x, y, color, ship_t) 115 + --_poly.polyline(img, x, y, ship_t, color, true, true) 116 + _poly.polygon(img, x, y, ship_t, color, BLACK, true) 117 + end 118 + 119 + local function draw_astroid(img, x, y, size, shape, color, scale_x, scale_y) 120 + --the random number generator gets seeded with the hash so we get the same figure each time 121 + randomseed(shape) 122 + -- we also use the 4 bytes of the hash as 4 coord pairs and randomly generate 8 more (16) half the size (8) 123 + local uniq_t = randomize_table(s_bytes_nib(32, shape), 16, 8) 124 + _poly.polyline(img, x, y, uniq_t, color, true, true, scale_x or 1, scale_y or 1) 125 + --_poly.polygon(img, x, y, uniq_t, color, color, true, scale_x or 1, scale_y or 1) --filled figures 126 + end 127 + 128 + local function drawStars (img, xoff, yoff, starscale, color, scale_x, scale_y) 129 + local size = STAR_TILE_SIZE / starscale 130 + local s_x, s_y = scale_x, scale_y 131 + local w, h = rb.LCD_WIDTH, rb.LCD_HEIGHT 132 + 133 + -- Top-left tile's top-left position 134 + local sx = ((xoff - w/2) / size) * size - size; 135 + local sy = ((yoff - h/2) / size) * size - size; 136 + 137 + --Draw each tile currently in view. 138 + for i = sx, w + sx + size*3, size do 139 + for j = sy, h + sy + size*3, size do 140 + local hash = mix(STAR_SEED, (i / size), (j / size)) 141 + for n = 0, 2 do 142 + local px = (hash % size) + (i - xoff); 143 + hash = arshift(hash, 3) 144 + 145 + local py = (hash % size) + (j - yoff); 146 + hash = arshift(hash, 3) 147 + 148 + if px > 0 and px < w and py > 0 and py < h then 149 + if n > 0 and starscale < 5 then 150 + draw_astroid(img, px, py, n, hash, color, s_x, s_y) 151 + else 152 + if scale_x > 1 then 153 + img:set(px, py, color) 154 + img:set(px + 1, py, color) 155 + elseif scale_y > 1 then 156 + img:set(px, py, color) 157 + img:set(px, py + 1, color) 158 + else 159 + img:set(px, py, color) 160 + end 161 + end 162 + end 163 + end 164 + end 165 + end 166 + end 167 + 168 + do 169 + local act = rb.actions 170 + local quit = false 171 + local last_action = 0 172 + local x,y,z = start_x or 0, start_y or 0, start_z or 8 173 + local x_fast = rb.LCD_WIDTH / 4 174 + local y_fast = rb.LCD_HEIGHT / 4 175 + local ship_x = (rb.LCD_WIDTH - 0xF) / 2 176 + local ship_y = rb.LCD_HEIGHT - (rb.LCD_HEIGHT / 3) 177 + local scale_x, scale_y = 1, 1 178 + -- vector draw the ship points for each direction (<>^v) 179 + local ship_lt_t = {0,7, 15,0, 9,7, 15,15, 0,7} 180 + local ship_rt_t = {0,0, 5,7, 0,15, 15,7, 0,0} 181 + local ship_up_t = {0,15, 7,0, 15,15, 7,9, 0,15} 182 + local ship_dn_t = {0,0, 7,15, 15,0, 7,5, 0,0} 183 + local ship_t = ship_up_t 184 + 185 + function action_event(action) 186 + if action == act.PLA_EXIT or action == act.PLA_CANCEL then 187 + quit = true 188 + start_x, start_y, start_z = x, y, z 189 + elseif action == act.PLA_RIGHT_REPEAT then 190 + x = x + x_fast 191 + scale_x = scale_x + 1 192 + scale_y = 1 193 + elseif action == act.PLA_LEFT_REPEAT then 194 + x = x - x_fast 195 + scale_x = scale_x + 1 196 + scale_y = 1 197 + elseif action == act.PLA_UP_REPEAT then 198 + y = y - y_fast 199 + scale_y = scale_y + 1 200 + scale_x = 1 201 + elseif action == act.PLA_DOWN_REPEAT then 202 + y = y + y_fast 203 + scale_y = scale_y + 1 204 + scale_x = 1 205 + elseif action == act.PLA_RIGHT then 206 + x = x + 1 207 + ship_t = ship_rt_t 208 + elseif action == act.PLA_LEFT then 209 + x = x - 1 210 + ship_t = ship_lt_t 211 + elseif action == act.PLA_UP then 212 + y = y - 1 213 + ship_t = ship_up_t 214 + elseif action == act.PLA_DOWN then 215 + y = y + 1 216 + ship_t = ship_dn_t 217 + elseif action == act.PLA_SELECT then 218 + z = z + 4 219 + if z > 16 then z = 0 end 220 + elseif action == act.ACTION_NONE then 221 + scale_x = 1 222 + scale_y = 1 223 + end 224 + 225 + _lcd:clear(BLACK) 226 + for i = 0, z, 4 do 227 + drawStars(_LCD, x, y, i+1, RED, scale_x, scale_y) 228 + drawStars(_LCD, x, y, i+2, GREEN, scale_x, scale_y) 229 + drawStars(_LCD, x, y, i+3, BLUE, scale_x, scale_y) 230 + drawStars(_LCD, x, y, i+4, WHITE, scale_x, scale_y) 231 + end 232 + drawship(_LCD, ship_x, ship_y, BGREEN, ship_t) 233 + _lcd:update() 234 + 235 + last_action = action 236 + end 237 + 238 + function action_set_quit(bQuit) 239 + quit = bQuit 240 + end 241 + 242 + function action_quit() 243 + return quit 244 + end 245 + end 246 + 247 + action_event(rb.actions.ACTION_NONE) -- we can call this now but not after registering.. 248 + local eva = rockev.register("action", action_event) 249 + 250 + while not action_quit() do rb.sleep(rb.HZ) end 251 + 252 + if start_x and start_y then 253 + file = io.open(fname, "w") 254 + file:write(start_x, "\n", start_y, "\n", start_z, "\n") 255 + io.close( file ) 256 + end