From a6570b7d378b6236c40d2e2bd983f7d53ad479e3 Mon Sep 17 00:00:00 2001 From: William Wilgus Date: Fri, 5 Apr 2024 00:38:35 -0400 Subject: 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 --- apps/plugins/lua/include_lua/draw_num.lua | 21 +-- apps/plugins/lua/include_lua/draw_text.lua | 85 +++------ apps/plugins/lua/include_lua/image_save.lua | 2 +- apps/plugins/lua/include_lua/printtable.lua | 9 +- apps/plugins/lua/rocklib_img.c | 150 ++++++++++++++-- apps/plugins/lua_scripts/rlimg.lua | 14 +- apps/plugins/lua_scripts/stars.lua | 256 ++++++++++++++++++++++++++++ 7 files changed, 431 insertions(+), 106 deletions(-) create mode 100644 apps/plugins/lua_scripts/stars.lua diff --git a/apps/plugins/lua/include_lua/draw_num.lua b/apps/plugins/lua/include_lua/draw_num.lua index 0f42c1f9f5..831e23e71e 100644 --- a/apps/plugins/lua/include_lua/draw_num.lua +++ b/apps/plugins/lua/include_lua/draw_num.lua @@ -20,17 +20,13 @@ * ****************************************************************************/ ]] - --[[ Exposed Functions _draw_nums.print; binary (base = 2) , octal (base = 8), hexadecimal (base = 16) _draw_nums.nums; table of number characters ]] - if not rb.lcd_framebuffer then rb.splash(rb.HZ, "No Support!") return nil end - local _draw_nums = {} do local _poly = require "draw_poly" - -- every 2 elements is an x, y coord pair -- n[?] = {x,y,x,y,x,y} local nums = { @@ -43,11 +39,11 @@ local _draw_nums = {} do [2] = {1,1,3,1,4,2,4,3,3,4,1,5,1,7,4,7}, [3] = {1,1,3,1,4,2,4,3,3,4,2,4,3,4,4,5,4,6,3,7,1,7}, [4] = {1,1,1,3,2,4,4,4,4,1,4,7}, - [5] = {1,1,4,1,1,1,1,4,3,4,4,5,4,7,1,7}, - [6] = {1,2,1,4,1,6,2,7,3,7,4,6,4,4,1,4,1,2,2,1,4,1}, + [5] = {1,1,4,1,1,1,1,4,3,4,4,5,4,6,3,7,1,7}, + [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}, [7] = {1,1,4,1,4,2,1,7}, - [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}, - [9] = {4,6,4,4,4,2,3,1,2,1,1,2,1,4,4,4,4,6,3,7,1,7}, + [8] = {1,2,4,5,4,6,3,7,2,7,1,6,1,5,4,2,3,1,2,1,1,2}, + [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}, [10] = {1,7,1,4,4,4,4,7,4,2,3,1,2,1,1,2,1,4}, [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}, [12] = {4,2,3,1,2,1,1,2,1,6,2,7,3,7,4,6}, @@ -56,8 +52,6 @@ local _draw_nums = {} do [15] = {4,1,1,1,1,4,3,4,1,4,1,7}, } _draw_nums.nums = nums - - _draw_nums.print = function(img, num, x, y, chrw, color, base, prefix, bClip, scale_x, scale_y, t_nums) scale_x = scale_x or 1 scale_y = scale_y or 1 @@ -65,7 +59,6 @@ local _draw_nums = {} do prefix = (prefix == nil or prefix == true) and true or false t_nums = t_nums or nums local max_x, max_y, digits = 0, 0, {} - if num <= 0 then if num < 0 then digits[-3] = -1 @@ -74,7 +67,6 @@ local _draw_nums = {} do digits[0] = 0 end end - if not prefix and (base == 2 or base == 8 or base == 16) then -- no prefix elseif base == 2 then @@ -92,23 +84,20 @@ local _draw_nums = {} do error("unknown number base: " .. base) return nil end - while num > 0 do -- get each digit (LeastSignificant) digits[#digits + 1] = num % base; num=num/base; end - digits[#digits + 1] = digits[0] -- zero digits[#digits + 1] = digits[-1] -- base prefix digits[#digits + 1] = digits[-2] -- base prefix (hex) digits[#digits + 1] = digits[-3] -- neg sign - for i = #digits, 1, -1 do max_x, max_y = _poly.polyline(img, x, y, t_nums[digits[i]], color, false, bClip, scale_x, scale_y) + if chrw == 0 then chrw = max_x end x = x + chrw end - return x, y + max_y, chrw end end diff --git a/apps/plugins/lua/include_lua/draw_text.lua b/apps/plugins/lua/include_lua/draw_text.lua index 3722931c2c..1d44954a5c 100644 --- a/apps/plugins/lua/include_lua/draw_text.lua +++ b/apps/plugins/lua/include_lua/draw_text.lua @@ -23,7 +23,6 @@ -- draw text onto image if width/height are supplied text is centered if not rb.lcd_framebuffer then rb.splash(rb.HZ, "No Support!") return nil end - do -- Internal Constants local rocklib_image = getmetatable(rb.lcd_framebuffer()) @@ -40,81 +39,35 @@ do return function(img, x, y, width, height, font, color, text) font = font or rb.FONT_UI - local opts = {x = 0, y = 0, width = LCD_W - 1, height = LCD_H - 1, - font = font, drawmode = 3, fg_pattern = 0x1, bg_pattern = 0} - - if rb.LCD_DEPTH == 2 then -- invert 2-bit screens - --vp.drawmode = bit.bxor(vp.drawmode, 4) - opts.fg_pattern = 3 - opts.fg_pattern - opts.bg_pattern = 3 - opts.bg_pattern - end - rb.set_viewport(opts) - local res, w, h = rb.font_getstringsize(text, font) - - if not width then - width = 0 + if rb.lcd_rgbpack ~= _NIL then -- Color target + rb.set_viewport(img, {fg_pattern = color, font = font, drawmode = 2})--DRMODE_FG else - width = (width - w) / 2 + if color ~= 0 then color = 3 end--DRMODE_SOLID + rb.set_viewport(img, {font = font, drawmode = color}) end - if not height then - height = 0 - else - height = (height - h) / 2 - end - - -- make a copy of the current screen for later - --local screen_img = _newimg(LCD_W, LCD_H) - local screen_img = _newimg(LCD_W, h * 2) - _copy(screen_img, _LCD) - - -- check if the screen buffer is supplied image if so set img to the copy - if img == _LCD then - img = screen_img - end + if width or height then + local res, w, h = rb.font_getstringsize(text, font) - -- we will be printing the text to the screen then blitting into img - --rb.lcd_clear_display() - _clear(_LCD, opts.bg_pattern or 0, 1, 1, LCD_W, h * 2) - - if w > LCD_W then -- text is too long for the screen do it in chunks - local l = 1 - local resp, wp, hp - local lenr = text:len() - - while lenr > 1 do - l = lenr - resp, wp, hp = rb.font_getstringsize(text:sub(1, l), font) - - while wp >= LCD_W and l > 1 do - l = l - 1 - resp, wp, hp = rb.font_getstringsize(text:sub( 1, l), font) - end - - rb.lcd_putsxy(0, 0, text:sub(1, l)) - text = text:sub(l) - - if x + width > img:width() or y + height > img:height() then - break - end - - -- using the mask we made blit color into img - _copy(img, _LCD, x + width, y + height, _NIL, _NIL, _NIL, _NIL, false, BSAND, color) - x = x + wp - --rb.lcd_clear_display() - _clear(_LCD, opts.bg_pattern or 0, 1, 1, LCD_W, h * 2) + if not width then + width = 0 + else + width = (width - w) / 2 + end - lenr = text:len() + if not height then + height = 0 + else + height = (height - h) / 2 end - else --w <= LCD_W - rb.lcd_putsxy(0, 0, text) + x = width + x + y = height + y - -- using the mask we made blit color into img - _copy(img, _LCD, x + width, y + height, _NIL, _NIL, _NIL, _NIL, false, BSAND, color) end - _copy(_LCD, screen_img) -- restore screen + rb.lcd_putsxy(x, y, text) + rb.set_viewport() -- set viewport default return res, w, h end diff --git a/apps/plugins/lua/include_lua/image_save.lua b/apps/plugins/lua/include_lua/image_save.lua index 4735af46d7..27e63ca65a 100644 --- a/apps/plugins/lua/include_lua/image_save.lua +++ b/apps/plugins/lua/include_lua/image_save.lua @@ -198,7 +198,7 @@ do end -- Bitmap lines start at bottom unless biHeight is negative - for point in _points(img, 1, h, w + bytesleft, 1) do + for point in _points(img, 1, h, w + bytesleft, 1, 1, 1, true) do imgdata[#imgdata + 1] = fs_bytes_E(bpp, point or 0) if #fbuffer >= 31 then -- buffered write, increase # for performance diff --git a/apps/plugins/lua/include_lua/printtable.lua b/apps/plugins/lua/include_lua/printtable.lua index c70fc1343f..02f3935ae6 100644 --- a/apps/plugins/lua/include_lua/printtable.lua +++ b/apps/plugins/lua/include_lua/printtable.lua @@ -145,13 +145,14 @@ function print_table(t, t_count, settings) local wrap, justify, start, curpos, co_routine, hasheader, m_sel local header_fgc, header_bgc, item_fgc, item_bgc, item_selc - local table_linedesc, drawsep, overflow, dpad_fn + local table_linedesc, drawsep, overflow, dpad_fn, pagescroll do local s = settings or _print.get_settings() wrap, justify = s.wrap, s.justify start, curpos = s.start, s.curpos co_routine = s.co_routine hasheader = s.hasheader + pagescroll = s.pagescroll drawsep = s.drawsep sb_width = s.sb_width or sb_width m_sel = false @@ -234,8 +235,13 @@ function print_table(t, t_count, settings) dpad_fn(t_p.col, -1, -t_p.col_scrl, t_p.row, -1, -t_p.row_scrl, nil, overflow, (t_p.row + t_p.vcursor - 1)) + + if pagescroll == true then + t_p.row = t_p.row + y_chg * maxline - 1 + end t_p.vcursor = t_p.vcursor + y_chg + if t_p.vcursor > maxline or t_p.vcursor < t_p.vcursor_min then t_p.row = yi end @@ -268,6 +274,7 @@ function print_table(t, t_count, settings) elseif y_chg ~= 0 then --t_p.col = 0 -- reset column to the beginning _print.clear() + _print.opt.sel_line(t_p.vcursor) t_p.row_scrl = set_accel(timeb, t_p.row_scrl, t_p) diff --git a/apps/plugins/lua/rocklib_img.c b/apps/plugins/lua/rocklib_img.c index 68e5325ce0..1857fbec5d 100644 --- a/apps/plugins/lua/rocklib_img.c +++ b/apps/plugins/lua/rocklib_img.c @@ -81,6 +81,57 @@ struct rli_iter_d struct rocklua_image *img; }; +/* viewport for rliimages to use rb functions */ +static struct viewport img_vp = +{ + .x = 0, + .y = 0, + .width = 0, + .height = 0, + .font = FONT_UI, + .drawmode = DRMODE_SOLID, +#if LCD_DEPTH > 1 + .fg_pattern = LCD_WHITE, + .bg_pattern = LCD_BLACK, +#endif +}; + +static void *img_address_fn(int x, int y) +{ +/* Address lookup function + * core will use this to get an address from x/y coord + * depending on the lcd function core sometimes uses this for + * only the first and last address + * and handles subsequent address based on stride */ + + struct frame_buffer_t *fb = img_vp.buffer; +/* LCD_STRIDEFORMAT & LCD_NATIVE_STRIDE macros allow Horiz screens to work with RB */ +#if LCD_STRIDEFORMAT == VERTICAL_STRIDE + size_t element = (x * LCD_NATIVE_STRIDE(fb->stride)) + y; +#else + size_t element = (y * LCD_NATIVE_STRIDE(fb->stride)) + x; +#endif + /* use mod fb->elems to protect from buffer ovfl */ + return fb->fb_ptr + (element % fb->elems); +} +/* sets an image into a vp to be used by rockbox image functions */ +static void img_set_as_vp(struct rocklua_image *img, struct viewport *vp) +{ + int w = img->width; + int h = img->height; + vp->x = 0; + vp->y = 0; + vp->width = w; + vp->height = h; + + static struct frame_buffer_t fb;/* warning passed to external fns */ + fb.elems = LCD_NBELEMS(w, h); /* recalculate these rb expects num pixels */ + fb.stride = STRIDE_MAIN(w, h); /* recalculate these */ + fb.data = img->data; + fb.get_address_fn = &img_address_fn; + rb->viewport_set_buffer(vp, &fb, SCREEN_MAIN); /* not multiscreen aware yet */ +} + /* __tostring information enums */ enum rli_info {RLI_INFO_ALL = 0, RLI_INFO_TYPE, RLI_INFO_WIDTH, RLI_INFO_HEIGHT, RLI_INFO_ELEMS, RLI_INFO_BYTES, @@ -261,7 +312,7 @@ static void bounds_check_xy(lua_State *L, struct rocklua_image *img, luaL_argerror(L, narg, ERR_IDX_RANGE); } /* bounds_check_xy */ -static struct rocklua_image* rli_checktype(lua_State *L, int arg) +static struct rocklua_image* rli_checktype_opt(lua_State *L, int arg) { #if 0 return (struct rocklua_image*) luaL_checkudata(L, arg, ROCKLUA_IMAGE); @@ -284,10 +335,17 @@ static struct rocklua_image* rli_checktype(lua_State *L, int arg) } } } - - luaL_typerror(L, arg, ROCKLUA_IMAGE); /* else error */ - return NULL; /* to avoid warnings */ + /* Not a ROCKLUA IMAGE */ + return NULL; #endif +} /* rli_checktype_opt*/ + +static struct rocklua_image* rli_checktype(lua_State *L, int arg) +{ + struct rocklua_image *img = rli_checktype_opt(L, arg); + if (img == NULL) + luaL_typerror(L, arg, ROCKLUA_IMAGE); + return img; } /* rli_checktype */ static struct rocklua_image * alloc_rlimage(lua_State *L, bool alloc_data, @@ -519,6 +577,7 @@ static bool next_rli_iter(struct rli_iter_d *d) return true; } /* next_rli_iter */ +#if 0 static void d_line(struct rocklua_image *img, int x1, int y1, int x2, int y2, @@ -574,6 +633,38 @@ static void d_line(struct rocklua_image *img, *a1 += s_a; /* whichever axis is in 'a' stepped(-1 or +1) */ } +} /* d_line */ +#endif + + +static void d_line(struct rocklua_image *img, + int x1, int y1, + int x2, int y2, + fb_data *clr) +{ + /* NOTE! clr passed as pointer */ +#if LCD_DEPTH == 2 + img_vp.fg_pattern = 0x55 * (~(*clr) & 3); + img_vp.drawmode = DRMODE_FG; +#elif LCD_DEPTH > 1 + img_vp.fg_pattern = *clr; + img_vp.drawmode = DRMODE_FG; +#else /* bit of a hack to make sure lines show properly from lua */ + /* use rb.lcd_drawline if you want full control */ + + img_vp.drawmode = *clr & (DRMODE_SOLID|DRMODE_INVERSEVID); + if (img_vp.drawmode != (DRMODE_SOLID|DRMODE_INVERSEVID)) + img_vp.drawmode = DRMODE_SOLID; +#endif + + img_set_as_vp(img, &img_vp); + + struct viewport *oldvp = rb->screens[SCREEN_MAIN]->set_viewport(&img_vp); + + rb->lcd_drawline(x1 - 1, y1 - 1 , x2 - 1, y2 - 1); + + rb->screens[SCREEN_MAIN]->set_viewport(oldvp); + } /* d_line */ /* ellipse worker function */ @@ -1266,9 +1357,21 @@ RB_WRAP(lcd_clear_display) RB_WRAP(lcd_set_drawmode) { + int previous; int mode = (int) luaL_checkint(L, 1); - RB_SCREENS(L, 2, set_drawmode, mode); - return 0; + if (rli_checktype_opt(L, 2) != NULL) /* is rliimage? */ + { + previous = img_vp.drawmode; + img_vp.drawmode = mode; + } + else + { + struct viewport *vp = *(RB_SCREEN_STRUCT(L, 2)->current_viewport); + previous = vp->drawmode; + RB_SCREENS(L, 2, set_drawmode, mode); + } + lua_pushinteger(L, previous); + return 1; } /* helper function for lcd_puts functions */ @@ -1443,6 +1546,7 @@ RB_WRAP(lcd_scroll_stop) static inline struct viewport* opt_viewport(lua_State *L, int narg, + bool set_coords, struct viewport* vp, struct viewport* alt) { @@ -1450,14 +1554,23 @@ static inline struct viewport* opt_viewport(lua_State *L, return alt; luaL_checktype(L, narg, LUA_TTABLE); - - vp->x = check_tablevalue(L, "x", narg); - vp->y = check_tablevalue(L, "y", narg); - vp->width = check_tablevalue(L, "width", narg); - vp->height = check_tablevalue(L, "height", narg); - vp->font = check_tablevalue(L, "font", narg); + if (set_coords) + { + vp->x = check_tablevalue(L, "x", narg); + vp->y = check_tablevalue(L, "y", narg); + vp->width = check_tablevalue(L, "width", narg); + vp->height = check_tablevalue(L, "height", narg); + } + vp->font = check_tablevalue_def(L, "font", narg, FONT_UI); vp->drawmode = check_tablevalue_def(L, "drawmode", narg, DRMODE_SOLID); -#if LCD_DEPTH > 1 + +#if LCD_DEPTH == 2 + unsigned int fg = check_tablevalue(L, "fg_pattern", narg); + unsigned int bg = check_tablevalue(L, "bg_pattern", narg); + /*invert fg and bg patterns (3-)*/ + vp->fg_pattern = 0x55 * (3 - (~(fg) & 3)); + vp->bg_pattern = 0x55 * (3 - (~(bg) & 3)); +#elif LCD_DEPTH > 1 vp->fg_pattern = (unsigned int) check_tablevalue(L, "fg_pattern", narg); vp->bg_pattern = (unsigned int) check_tablevalue(L, "bg_pattern", narg); #endif @@ -1467,8 +1580,15 @@ static inline struct viewport* opt_viewport(lua_State *L, RB_WRAP(set_viewport) { + void *ud = rli_checktype_opt(L, 1); + if (ud != NULL) + { + img_set_as_vp((struct rocklua_image*) ud, &img_vp); + RB_SCREENS(L, 3, set_viewport, opt_viewport(L, 2, false, &img_vp, &img_vp)); + return 0; + } static struct viewport vp; - RB_SCREENS(L, 2, set_viewport, opt_viewport(L, 1, &vp, NULL)); + RB_SCREENS(L, 2, set_viewport, opt_viewport(L, 1, true, &vp, NULL)); return 0; } @@ -1489,7 +1609,7 @@ RB_WRAP(font_getstringsize) else fontnumber = FONT_SYSFIXED; - if lua_isnil(L, 2) + if lua_isnoneornil(L, 2) result = RB_SCREENS(L, 3, getstringsize, str, &w, &h); else result = rb->font_getstringsize(str, &w, &h, fontnumber); diff --git a/apps/plugins/lua_scripts/rlimg.lua b/apps/plugins/lua_scripts/rlimg.lua index c9dde65ed4..c4eefc7aa9 100755 --- a/apps/plugins/lua_scripts/rlimg.lua +++ b/apps/plugins/lua_scripts/rlimg.lua @@ -76,7 +76,7 @@ local BLUE = _clr.set(WHITE, 0, 0, 255) ------------------------------------------- local clrs local CANCEL_BUTTON = rb.actions.PLA_CANCEL - +local LCD_DEPTH = rb.LCD_DEPTH -- EXAMPLES ---------------------------------------------------------------------- EXAMPLES--------------------------------------------------------------------- function my_blit(dst_val, dx, dy, src_val, sx, sy) -- user defined blit operation @@ -84,7 +84,7 @@ function my_blit(dst_val, dx, dy, src_val, sx, sy) --you may change pixels in both the source and dest image --return nil to stop early - if _lcd.DEPTH < 2 then + if LCD_DEPTH < 2 then return src_val end @@ -518,7 +518,7 @@ function twist(img) for ix = 1, _lcd.W, w do y_col = y_col + 1 y = ims.y_pos[(y_col % 2) + 1] - if _lcd.DEPTH > 1 then + if LCD_DEPTH > 1 then _lcd:copy(ims.strip, ix, 1, 1, y, w, h, false, _blit.BDEQC, colors[1]) else _lcd:copy(ims.strip, ix, 1, 1, y, w, h, false, _blit.BSAND) @@ -767,10 +767,10 @@ function long_text() local wait = 0 w = w + wp * 3 h = h + 4 - local img = _img.new(w + 1, h) + local img = _img.new(w + 1, h + 1) img:clear(BLACK) _draw.rounded_rect_filled(img, 1, 1, w, h, 15, WHITE) - _draw_text(img, 1, 2, nil, nil, nil, BLACK, txt) + _draw_text(img, 1, 1, nil, nil, nil, BLACK, txt) for p = -w + 1, w - 1 do wait = 0 @@ -858,7 +858,7 @@ function main_menu() [14] = function(EXIT_) return true end } - if _lcd.DEPTH < 2 then + if LCD_DEPTH < 2 then table.remove(mt, 10) table.remove(ft, 10) end @@ -880,7 +880,7 @@ _timer("main") -- keep track of how long the program ran -- Clear the screen _lcd:clear(BLACK) -if _lcd.DEPTH > 1 then +if LCD_DEPTH > 1 then --draw a gradient using available colors if IS_COLOR_TARGET == true then clrs = { diff --git a/apps/plugins/lua_scripts/stars.lua b/apps/plugins/lua_scripts/stars.lua new file mode 100644 index 0000000000..14fae0c4b7 --- /dev/null +++ b/apps/plugins/lua_scripts/stars.lua @@ -0,0 +1,256 @@ +--[[ + __________ __ ___. + Open \______ \ ____ ____ | | _\_ |__ _______ ___ + Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + \/ \/ \/ \/ \/ + $Id$ + + Copyright (C) 2024 William Wilgus + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + KIND, either express or implied. +]]-- +--https://nullprogram.com/blog/2011/06/13/ [Infinite Parallax Starfield] + +-- Imports +local _clr = require("color") -- clrset, clrinc provides device independent colors +local _lcd = require("lcd") -- lcd helper functions +local _draw = require("draw") -- draw all the things (primitives) +local _poly = require("draw_poly") -- vector drawing with tables of coords +require("actions") +--'CONSTANTS' (in lua there really is no such thing as all vars are mutable) +-------------------------------------------------------- +--colors for fg/bg ------------------------ +--first number of each quad is fallback for monochrome devices, excluded columns default to 0 +local WHITE = _clr.set(-1, 255, 255, 255) +local BLACK = _clr.set(0, 0, 0, 0) +local RED = _clr.set(WHITE, 100) +local GREEN = _clr.set(WHITE, 0, 100) +local BGREEN = _clr.set(WHITE, 0, 255) +local BLUE = _clr.set(WHITE, 0, 0, 100) + +local STAR_SEED = 0x9d2c5680; +local STAR_TILE_SIZE = math.max(rb.LCD_WIDTH, rb.LCD_HEIGHT) * 4; +local bxor, band, rshift, lshift, arshift = bit.bxor, bit.band, bit.rshift, bit.lshift, bit.arshift +local random, randomseed = math.random, math.randomseed +local start_x, start_y, start_z + +-- load users coords from file if it exists +local fname = rb.PLUGIN_DATA_DIR .. "/stars.pos" +file = io.open(fname, "r") +if file then + local v = 0 + for line in file:lines() do + v = v + 1 + if v == 1 then + start_x = tonumber(line) or 0 + elseif v == 2 then + start_y = tonumber(line) or 0 + elseif v == 3 then + start_z = tonumber(line) or 0 + else + break; + end + end + io.close( file ) +end + +-- Robert Jenkins' 96 bit Mix Function. +local function mix (a, b, c) + a=a-b; a=a-c; a=bxor(a, (rshift(c, 13))); + b=b-c; b=b-a; b=bxor(b, (lshift(a, 8))); + c=c-a; c=c-b; c=bxor(c, (rshift(b, 13))); + a=a-b; a=a-c; a=bxor(a, (rshift(c, 12))); + b=b-c; b=b-a; b=bxor(b, (lshift(a, 16))); + c=c-a; c=c-b; c=bxor(c, (rshift(b, 5))); + a=a-b; a=a-c; a=bxor(a, (rshift(c, 3))); + b=b-c; b=b-a; b=bxor(b, (lshift(a, 10))); + c=c-a; c=c-b; c=bxor(c, (rshift(b, 15))); + + return c +end + +-- given 32 bit number returns a table of 8 nibbles (4 bits) +local function s_bytes_nib(bits, value) + -- bits must be multiples of 8 (sizeof byte) + local bbuffer = {} + local byte + local nbytes = bit.rshift(bits, 3) + for b = 1, nbytes do + if value > 0 then + byte = value % 256 + value = (value - byte) / 256 + else + byte = 0 + end + bbuffer[#bbuffer + 1] = band(byte,0xF) + bbuffer[#bbuffer + 1] = band(rshift(byte, 2), 0xF) + end + return bbuffer +end + +--[[ given table t and total elems desired uses random elems of t + and random numbers between 1 and max_v if #t < total_elems]] +function randomize_table(t, total_elems, max_v) + local rand_t = {} + local i = 1 + repeat + local v = t[random(1, total_elems)] + if v then + rand_t[i] = v + else + rand_t[i] = random(1, max_v) + end + i = i + 1 + until i > total_elems + return rand_t +end + +local function drawship(img, x, y, color, ship_t) + --_poly.polyline(img, x, y, ship_t, color, true, true) + _poly.polygon(img, x, y, ship_t, color, BLACK, true) +end + +local function draw_astroid(img, x, y, size, shape, color, scale_x, scale_y) + --the random number generator gets seeded with the hash so we get the same figure each time + randomseed(shape) + -- we also use the 4 bytes of the hash as 4 coord pairs and randomly generate 8 more (16) half the size (8) + local uniq_t = randomize_table(s_bytes_nib(32, shape), 16, 8) + _poly.polyline(img, x, y, uniq_t, color, true, true, scale_x or 1, scale_y or 1) + --_poly.polygon(img, x, y, uniq_t, color, color, true, scale_x or 1, scale_y or 1) --filled figures +end + +local function drawStars (img, xoff, yoff, starscale, color, scale_x, scale_y) + local size = STAR_TILE_SIZE / starscale + local s_x, s_y = scale_x, scale_y + local w, h = rb.LCD_WIDTH, rb.LCD_HEIGHT + + -- Top-left tile's top-left position + local sx = ((xoff - w/2) / size) * size - size; + local sy = ((yoff - h/2) / size) * size - size; + + --Draw each tile currently in view. + for i = sx, w + sx + size*3, size do + for j = sy, h + sy + size*3, size do + local hash = mix(STAR_SEED, (i / size), (j / size)) + for n = 0, 2 do + local px = (hash % size) + (i - xoff); + hash = arshift(hash, 3) + + local py = (hash % size) + (j - yoff); + hash = arshift(hash, 3) + + if px > 0 and px < w and py > 0 and py < h then + if n > 0 and starscale < 5 then + draw_astroid(img, px, py, n, hash, color, s_x, s_y) + else + if scale_x > 1 then + img:set(px, py, color) + img:set(px + 1, py, color) + elseif scale_y > 1 then + img:set(px, py, color) + img:set(px, py + 1, color) + else + img:set(px, py, color) + end + end + end + end + end + end +end + +do + local act = rb.actions + local quit = false + local last_action = 0 + local x,y,z = start_x or 0, start_y or 0, start_z or 8 + local x_fast = rb.LCD_WIDTH / 4 + local y_fast = rb.LCD_HEIGHT / 4 + local ship_x = (rb.LCD_WIDTH - 0xF) / 2 + local ship_y = rb.LCD_HEIGHT - (rb.LCD_HEIGHT / 3) + local scale_x, scale_y = 1, 1 + -- vector draw the ship points for each direction (<>^v) + local ship_lt_t = {0,7, 15,0, 9,7, 15,15, 0,7} + local ship_rt_t = {0,0, 5,7, 0,15, 15,7, 0,0} + local ship_up_t = {0,15, 7,0, 15,15, 7,9, 0,15} + local ship_dn_t = {0,0, 7,15, 15,0, 7,5, 0,0} + local ship_t = ship_up_t + + function action_event(action) + if action == act.PLA_EXIT or action == act.PLA_CANCEL then + quit = true + start_x, start_y, start_z = x, y, z + elseif action == act.PLA_RIGHT_REPEAT then + x = x + x_fast + scale_x = scale_x + 1 + scale_y = 1 + elseif action == act.PLA_LEFT_REPEAT then + x = x - x_fast + scale_x = scale_x + 1 + scale_y = 1 + elseif action == act.PLA_UP_REPEAT then + y = y - y_fast + scale_y = scale_y + 1 + scale_x = 1 + elseif action == act.PLA_DOWN_REPEAT then + y = y + y_fast + scale_y = scale_y + 1 + scale_x = 1 + elseif action == act.PLA_RIGHT then + x = x + 1 + ship_t = ship_rt_t + elseif action == act.PLA_LEFT then + x = x - 1 + ship_t = ship_lt_t + elseif action == act.PLA_UP then + y = y - 1 + ship_t = ship_up_t + elseif action == act.PLA_DOWN then + y = y + 1 + ship_t = ship_dn_t + elseif action == act.PLA_SELECT then + z = z + 4 + if z > 16 then z = 0 end + elseif action == act.ACTION_NONE then + scale_x = 1 + scale_y = 1 + end + + _lcd:clear(BLACK) + for i = 0, z, 4 do + drawStars(_LCD, x, y, i+1, RED, scale_x, scale_y) + drawStars(_LCD, x, y, i+2, GREEN, scale_x, scale_y) + drawStars(_LCD, x, y, i+3, BLUE, scale_x, scale_y) + drawStars(_LCD, x, y, i+4, WHITE, scale_x, scale_y) + end + drawship(_LCD, ship_x, ship_y, BGREEN, ship_t) + _lcd:update() + + last_action = action + end + + function action_set_quit(bQuit) + quit = bQuit + end + + function action_quit() + return quit + end +end + +action_event(rb.actions.ACTION_NONE) -- we can call this now but not after registering.. +local eva = rockev.register("action", action_event) + +while not action_quit() do rb.sleep(rb.HZ) end + +if start_x and start_y then + file = io.open(fname, "w") + file:write(start_x, "\n", start_y, "\n", start_z, "\n") + io.close( file ) +end -- cgit v1.2.3