1
0
Fork 0
forked from len0rd/rockbox

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
This commit is contained in:
William Wilgus 2024-04-05 00:38:35 -04:00 committed by William Wilgus
parent 7f1b49693c
commit a6570b7d37
7 changed files with 432 additions and 107 deletions

View file

@ -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

View file

@ -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
if width or height then
local res, w, h = rb.font_getstringsize(text, font)
-- 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
-- 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)
lenr = text:len()
if not width then
width = 0
else
width = (width - w) / 2
end
else --w <= LCD_W
rb.lcd_putsxy(0, 0, text)
-- using the mask we made blit color into img
_copy(img, _LCD, x + width, y + height, _NIL, _NIL, _NIL, _NIL, false, BSAND, color)
if not height then
height = 0
else
height = (height - h) / 2
end
x = width + x
y = height + y
end
_copy(_LCD, screen_img) -- restore screen
rb.lcd_putsxy(x, y, text)
rb.set_viewport() -- set viewport default
return res, w, h
end

View file

@ -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

View file

@ -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)

View file

@ -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);