summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWilliam Wilgus <wilgus.william@gmail.com>2024-04-05 00:38:35 -0400
committerWilliam Wilgus <me.theuser@yahoo.com>2024-04-18 13:11:51 -0400
commita6570b7d378b6236c40d2e2bd983f7d53ad479e3 (patch)
tree6e1562a78c07a1fe0e05b36cf10542aff5ca7482
parent7f1b49693cd84b6e03e05d8a980fb99f26a781b1 (diff)
downloadrockbox-a6570b7d37.tar.gz
rockbox-a6570b7d37.zip
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
-rw-r--r--apps/plugins/lua/include_lua/draw_num.lua21
-rw-r--r--apps/plugins/lua/include_lua/draw_text.lua85
-rw-r--r--apps/plugins/lua/include_lua/image_save.lua2
-rw-r--r--apps/plugins/lua/include_lua/printtable.lua9
-rw-r--r--apps/plugins/lua/rocklib_img.c150
-rwxr-xr-xapps/plugins/lua_scripts/rlimg.lua14
-rw-r--r--apps/plugins/lua_scripts/stars.lua256
7 files changed, 431 insertions, 106 deletions
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,
@@ -575,6 +634,38 @@ static void d_line(struct rocklua_image *img,
}
} /* 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 */
static void d_ellipse_elements(struct rocklua_image * img,
@@ -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