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.

Clean up rocklib_img

optimize both size and speed
fix invert for color screens

Change-Id: I7edecae32dcb3daf5b3ed984a0e5b3d463269e60

+513 -602
+1 -1
apps/plugins/lua/include_lua/blit.lua
··· 36 36 37 37 local _blit ={} do 38 38 39 - _blit.CUSTOM = 0xFF --user defined blit function func(dst_val, x, y, src_val, x, y) 39 + _blit.CUSTOM = nil --user defined blit function func(dst_val, x, y, src_val, x, y) 40 40 _blit.BCOPY = 0x0 --copy (use :copy() instead it is slightly faster 41 41 _blit.BOR = 0x1 --OR source and dest pixels 42 42 _blit.BXOR = 0x2 --XOR source and dest pixels
+10 -21
apps/plugins/lua/include_lua/color.lua
··· 49 49 maxstate = (bit.lshift(1, 24) - 1) 50 50 end 51 51 52 - local function init(v) 53 - return v or 0 54 - end 55 - 56 52 -- clamps value to >= min and <= max rolls over to opposite 57 53 local function clamp_roll(val, min, max) 58 - if min > max then 59 - local swap = min 60 - min, max = max, swap 61 - end 62 - 54 + -- Warning doesn't check if min < max 63 55 if val < min then 64 56 val = max 65 57 elseif val > max then ··· 72 64 -- sets color -- monochrome / greyscale use 'set' -- color targets 'r,b,g' 73 65 -- on monochrome/ greyscale targets: 74 66 -- '-1' sets the highest 'color' state & 0 is the minimum 'color' state 75 - local function clrset(set, r, g, b) 67 + _clr.set = function(set, r, g, b) 76 68 local color = set or 0 77 69 78 70 if IS_COLOR_TARGET then 79 - if (r ~= _NIL or g ~= _NIL or b ~= _NIL) then 80 - r, g, b = init(r), init(g), init(b) 71 + if (r or g or b) then 72 + r, g, b = (r or 0), (g or 0), (b or 0) 81 73 color = rb.lcd_rgbpack(r, g, b) 82 74 end 83 75 end ··· 86 78 end -- clrset 87 79 88 80 -- de/increments current color by 'inc' -- optionally color targets by 'r,g,b' 89 - local function clrinc(current, inc, r, g, b) 81 + _clr.inc = function(current, inc, r, g, b) 90 82 local color = 0 91 83 current = current or color 92 84 inc = inc or 1 93 85 94 86 if IS_COLOR_TARGET then 95 87 local ru, gu, bu = rb.lcd_rgbunpack(current); 96 - if (r ~= _NIL or g ~= _NIL or b ~= _NIL) then 97 - r, g, b = init(r), init(g), init(b) 88 + if (r or g or b) then 89 + r, g, b = (r or 0), (g or 0), (b or 0) 98 90 ru = ru + r; gu = gu + g; bu = bu + b 99 - color = rb.lcd_rgbpack(ru, gu, bu) 100 91 else 101 - ru = ru + inc; gu = gu + inc; bu = bu + inc 102 - color = rb.lcd_rgbpack(ru, gu, bu) 92 + ru = ru + inc; gu = gu + inc; bu = bu + inc 103 93 end 94 + 95 + color = rb.lcd_rgbpack(ru, gu, bu) 104 96 else 105 97 color = current + inc 106 98 end ··· 108 100 return clamp_roll(color, 0, maxstate) 109 101 end -- clrinc 110 102 111 - -- expose functions to the outside through _clr table 112 - _clr.set = clrset 113 - _clr.inc = clrinc 114 103 end -- color functions 115 104 116 105 return _clr
+96 -133
apps/plugins/lua/include_lua/draw.lua
··· 52 52 53 53 local _draw = {} do 54 54 55 + local rocklib_image = getmetatable(rb.lcd_framebuffer()) 56 + setmetatable(_draw, rocklib_image) 57 + 55 58 -- Internal Constants 56 59 local _LCD = rb.lcd_framebuffer() 57 60 local LCD_W, LCD_H = rb.LCD_WIDTH, rb.LCD_HEIGHT 58 61 local BSAND = 8 -- blits color to dst if src <> 0 59 62 local _NIL = nil -- nil placeholder 60 63 61 - local function set_viewport(vp) 62 - if not vp then rb.set_viewport() return end 63 - if rb.LCD_DEPTH == 2 then -- invert 2-bit screens 64 - --vp.drawmode = bit.bxor(vp.drawmode, 4) 65 - vp.fg_pattern = 3 - vp.fg_pattern 66 - vp.bg_pattern = 3 - vp.bg_pattern 67 - end 68 - rb.set_viewport(vp) 69 - end 64 + local _abs = math.abs 65 + local _clear = rocklib_image.clear 66 + local _copy = rocklib_image.copy 67 + local _ellipse = rocklib_image.ellipse 68 + local _get = rocklib_image.get 69 + local _line = rocklib_image.line 70 + local _marshal = rocklib_image.marshal 71 + local _min = math.min 72 + local _newimg = rb.new_image 73 + local _points = rocklib_image.points 70 74 71 75 -- line 72 - local function line(img, x1, y1, x2, y2, color, bClip) 73 - img:line(x1, y1, x2, y2, color, bClip) 76 + _draw.line = function(img, x1, y1, x2, y2, color, bClip) 77 + _line(img, x1, y1, x2, y2, color, bClip) 74 78 end 75 79 76 80 -- horizontal line; x, y define start point; length in horizontal direction 77 81 local function hline(img, x, y , length, color, bClip) 78 - img:line(x, y, x + length, _NIL, color, bClip) 82 + _line(img, x, y, x + length, _NIL, color, bClip) 79 83 end 80 84 81 85 -- vertical line; x, y define start point; length in vertical direction 82 86 local function vline(img, x, y , length, color, bClip) 83 - img:line(x, y, _NIL, y + length, color, bClip) 87 + _line(img, x, y, _NIL, y + length, color, bClip) 84 88 end 85 89 86 90 -- draws a non-filled figure based on points in t-points ··· 100 104 101 105 local pt2 = t_points[i + 1] or pt_first_last-- first and last point 102 106 103 - img:line(pt1[1] + x, pt1[2] + y, pt2[1]+x, pt2[2]+y, color, bClip) 107 + _line(img, pt1[1] + x, pt1[2] + y, pt2[1] + x, pt2[2] + y, color, bClip) 104 108 end 105 109 106 110 end ··· 109 113 local function rect(img, x, y, width, height, color, bClip) 110 114 if width == 0 or height == 0 then return end 111 115 112 - local ppt = {{0, 0}, {width, 0}, {width, height}, {0, height}} 113 - polyline(img, x, y, ppt, color, true, bClip) 114 - --[[ 115 - vline(img, x, y, height, color, bClip); 116 - vline(img, x + width, y, height, color, bClip); 117 - hline(img, x, y, width, color, bClip); 118 - hline(img, x, y + height, width, color, bClip);]] 116 + polyline(img, x, y, {{0, 0}, {width, 0}, {width, height}, {0, height}}, color, true, bClip) 117 + 119 118 end 120 119 121 120 -- filled rect, fillcolor is color if left empty 122 - local function rect_filled(img, x, y, width, height, color, fillcolor, bClip) 121 + _draw.rect_filled = function(img, x, y, width, height, color, fillcolor, bClip) 123 122 if width == 0 or height == 0 then return end 124 123 125 124 if not fillcolor then 126 - img:clear(color, x, y, x + width, y + height, bClip) 125 + _clear(img, color, x, y, x + width, y + height, bClip) 127 126 else 128 - img:clear(fillcolor, x, y, x + width, y + height, bClip) 127 + _clear(img, fillcolor, x, y, x + width, y + height, bClip) 129 128 rect(img, x, y, width, height, color, bClip) 130 129 end 131 130 end 132 131 133 132 -- circle cx,cy define center point 134 - local function circle(img, cx, cy, radius, color, bClip) 133 + _draw.circle = function(img, cx, cy, radius, color, bClip) 135 134 local r = radius 136 - img:ellipse(cx - r, cy - r, cx + r, cy + r, color, _NIL, bClip) 135 + _ellipse(img, cx - r, cy - r, cx + r, cy + r, color, _NIL, bClip) 137 136 end 138 137 139 138 -- filled circle cx,cy define center, fillcolor is color if left empty 140 - local function circle_filled(img, cx, cy, radius, color, fillcolor, bClip) 139 + _draw.circle_filled = function(img, cx, cy, radius, color, fillcolor, bClip) 141 140 fillcolor = fillcolor or color 142 141 local r = radius 143 - img:ellipse(cx - r, cy - r, cx + r, cy + r, color, fillcolor, bClip) 142 + _ellipse(img, cx - r, cy - r, cx + r, cy + r, color, fillcolor, bClip) 144 143 end 145 144 146 145 -- ellipse that fits into defined rect 147 - local function ellipse_rect(img, x1, y1, x2, y2, color, bClip) 148 - img:ellipse(x1, y1, x2, y2, color, _NIL, bClip) 146 + _draw.ellipse_rect = function(img, x1, y1, x2, y2, color, bClip) 147 + _ellipse(img, x1, y1, x2, y2, color, _NIL, bClip) 149 148 end 150 149 151 150 --ellipse that fits into defined rect, fillcolor is color if left empty 152 - local function ellipse_rect_filled(img, x1, y1, x2, y2, color, fillcolor, bClip) 151 + _draw.ellipse_rect_filled = function(img, x1, y1, x2, y2, color, fillcolor, bClip) 153 152 if not fillcolor then fillcolor = color end 154 153 155 - img:ellipse(x1, y1, x2, y2, color, fillcolor, bClip) 154 + _ellipse(img, x1, y1, x2, y2, color, fillcolor, bClip) 156 155 end 157 156 158 157 -- ellipse cx, cy define center point; a, b the major/minor axis 159 - local function ellipse(img, cx, cy, a, b, color, bClip) 160 - img:ellipse(cx - a, cy - b, cx + a, cy + b, color, _NIL, bClip) 158 + _draw.ellipse = function(img, cx, cy, a, b, color, bClip) 159 + _ellipse(img, cx - a, cy - b, cx + a, cy + b, color, _NIL, bClip) 161 160 end 162 161 163 162 -- filled ellipse cx, cy define center point; a, b the major/minor axis 164 163 -- fillcolor is color if left empty 165 - local function ellipse_filled(img, cx, cy, a, b, color, fillcolor, bClip) 164 + _draw.ellipse_filled = function(img, cx, cy, a, b, color, fillcolor, bClip) 166 165 if not fillcolor then fillcolor = color end 167 166 168 - img:ellipse(cx - a, cy - b, cx + a, cy + b, color, fillcolor, bClip) 167 + _ellipse(img, cx - a, cy - b, cx + a, cy + b, color, fillcolor, bClip) 169 168 end 170 169 171 170 -- rounded rectangle 172 171 local function rounded_rect(img, x, y, w, h, radius, color, bClip) 173 172 local c_img 174 - 175 - local function blit(dx, dy, sx, sy, ox, oy) 176 - img:copy(c_img, dx, dy, sx, sy, ox, oy, bClip, BSAND, color) 177 - end 178 - 179 173 if w == 0 or h == 0 then return end 180 174 181 175 -- limit the radius of the circle otherwise it will overtake the rect 182 - radius = math.min(w / 2, radius) 183 - radius = math.min(h / 2, radius) 176 + radius = _min(w / 2, radius) 177 + radius = _min(h / 2, radius) 184 178 185 179 local r = radius 186 180 187 - c_img = rb.new_image(r * 2 + 1, r * 2 + 1) 188 - c_img:clear(0) 189 - circle(c_img, r + 1, r + 1, r, 0xFFFFFF) 181 + c_img = _newimg(r * 2 + 1, r * 2 + 1) 182 + _clear(c_img, 0) 183 + _ellipse(c_img, 1, 1, 1 + r + r, 1 + r + r, 0x1, _NIL, bClip) 190 184 191 185 -- copy 4 pieces of circle to their respective corners 192 - blit(x, y, _NIL, _NIL, r + 1, r + 1) --TL 193 - blit(x + w - r - 2, y, r, _NIL, r + 1, r + 1) --TR 194 - blit(x , y + h - r - 2, _NIL, r, r + 1, _NIL) --BL 195 - blit(x + w - r - 2, y + h - r - 2, r, r, r + 1, r + 1)--BR 186 + _copy(img, c_img, x, y, _NIL, _NIL, r + 1, r + 1, bClip, BSAND, color) --TL 187 + _copy(img, c_img, x + w - r - 2, y, r, _NIL, r + 1, r + 1, bClip, BSAND, color) --TR 188 + _copy(img, c_img, x , y + h - r - 2, _NIL, r, r + 1, _NIL, bClip, BSAND, color) --BL 189 + _copy(img, c_img, x + w - r - 2, y + h - r - 2, r, r, r + 1, r + 1, bClip, BSAND, color)--BR 196 190 c_img = _NIL 197 191 198 192 vline(img, x, y + r, h - r * 2, color, bClip); ··· 202 196 end 203 197 204 198 -- rounded rectangle fillcolor is color if left empty 205 - local function rounded_rect_filled(img, x, y, w, h, radius, color, fillcolor, bClip) 199 + _draw.rounded_rect_filled = function(img, x, y, w, h, radius, color, fillcolor, bClip) 206 200 local c_img 207 201 208 - local function blit(dx, dy, sx, sy, ox, oy) 209 - img:copy(c_img, dx, dy, sx, sy, ox, oy, bClip, BSAND, fillcolor) 210 - end 211 - 212 202 if w == 0 or h == 0 then return end 213 203 214 204 if not fillcolor then fillcolor = color end 215 205 216 206 -- limit the radius of the circle otherwise it will overtake the rect 217 - radius = math.min(w / 2, radius) 218 - radius = math.min(h / 2, radius) 207 + radius = _min(w / 2, radius) 208 + radius = _min(h / 2, radius) 219 209 220 210 local r = radius 221 211 222 - c_img = rb.new_image(r * 2 + 1, r * 2 + 1) 223 - c_img:clear(0) 224 - circle_filled(c_img, r + 1, r + 1, r, fillcolor) 212 + c_img = _newimg(r * 2 + 1, r * 2 + 1) 213 + _clear(c_img, 0) 214 + _ellipse(c_img, 1, 1, 1 + r + r, 1 + r + r, 0x1, 0x1, bClip) 225 215 226 216 -- copy 4 pieces of circle to their respective corners 227 - blit(x, y, _NIL, _NIL, r + 1, r + 1) --TL 228 - blit(x + w - r - 2, y, r, _NIL, r + 1, r + 1) --TR 229 - blit(x, y + h - r - 2, _NIL, r, r + 1, _NIL) --BL 230 - blit(x + w - r - 2, y + h - r - 2, r, r, r + 1, r + 1) --BR 217 + _copy(img, c_img, x, y, _NIL, _NIL, r + 1, r + 1, bClip, BSAND, fillcolor) --TL 218 + _copy(img, c_img, x + w - r - 2, y, r, _NIL, r + 1, r + 1, bClip, BSAND, fillcolor) --TR 219 + _copy(img, c_img, x, y + h - r - 2, _NIL, r, r + 1, _NIL, bClip, BSAND, fillcolor) --BL 220 + _copy(img, c_img, x + w - r - 2, y + h - r - 2, r, r, r + 1, r + 1, bClip, BSAND, fillcolor) --BR 231 221 c_img = _NIL 232 222 233 223 -- finish filling areas circles didn't cover 234 - img:clear(fillcolor, x + r, y, x + w - r, y + h - 1, bClip) 235 - img:clear(fillcolor, x, y + r, x + r, y + h - r, bClip) 236 - img:clear(fillcolor, x + w - r, y + r, x + w - 1, y + h - r - 1, bClip) 224 + _clear(img, fillcolor, x + r, y, x + w - r, y + h - 1, bClip) 225 + _clear(img, fillcolor, x, y + r, x + r, y + h - r, bClip) 226 + _clear(img, fillcolor, x + w - r, y + r, x + w - 1, y + h - r - 1, bClip) 237 227 238 228 if fillcolor ~= color then 239 229 rounded_rect(img, x, y, w, h, r, color, bClip) ··· 241 231 end 242 232 243 233 -- draws an image at xy coord in dest image 244 - local function image(dst, src, x, y, bClip) 234 + _draw.image = function(dst, src, x, y, bClip) 245 235 if not src then --make sure an image was passed, otherwise bail 246 236 rb.splash(rb.HZ, "No Image!") 247 237 return _NIL 248 238 end 249 239 250 - dst:copy(src, x, y, 1, 1, _NIL, _NIL, bClip) 240 + _copy(dst, src, x, y, 1, 1, _NIL, _NIL, bClip) 251 241 end 252 242 253 243 -- floods an area of targetclr with fillclr x, y specifies the start seed 254 - function flood_fill(img, x, y, targetclr, fillclr) 244 + _draw.flood_fill = function(img, x, y, targetclr, fillclr) 255 245 -- scanline 4-way flood algorithm 256 246 -- ^ 257 247 -- <--------x---> 258 248 -- v 259 249 -- check that target color doesn't = fill and the first point is target color 260 - if targetclr == fillclr or targetclr ~= img:get(x,y, true) then return end 250 + if targetclr == fillclr or targetclr ~= _get(img, x, y, true) then return end 261 251 local max_w = img:width() 262 252 local max_h = img:height() 263 253 ··· 271 261 -- y coordinates are in even indices 272 262 273 263 local qtail = 0 274 - local iter_n; -- North iteration 275 - local iter_s; -- South iteration 276 264 277 265 local function check_ns(val, x, y) 278 266 if targetclr == val then 279 - if targetclr == iter_n() then 267 + y = y - 1 268 + if targetclr == _get(img, x, y, true) then -- north 280 269 qtail = qtail + 2 281 270 qpt[qtail - 1] = x 282 - qpt[qtail] = (y - 1) 271 + qpt[qtail] = y 283 272 end 284 - 285 - if targetclr == iter_s() then 273 + y = y + 2 274 + if targetclr == _get(img, x, y, true) then -- south 286 275 qtail = qtail + 2 287 276 qpt[qtail - 1] = x 288 - qpt[qtail] = (y + 1) 277 + qpt[qtail] = y 289 278 end 290 279 return fillclr 291 280 end ··· 293 282 end 294 283 295 284 local function seed_pt(x, y) 296 - -- will never hit max_w * max_h^2 but make sure not to end early 297 - for qhead = 2, max_w * max_h * max_w * max_h, 2 do 298 - 299 - if targetclr == img:get(x, y, true) then 300 - iter_n = img:points(x, y - 1, 1, y - 1) 301 - iter_s = img:points(x, y + 1, 1, y + 1) 302 - img:marshal(x, y, 1, y, _NIL, _NIL, true, check_ns) 285 + -- should never hit max but make sure not to end early 286 + for qhead = 2, 0x40000000, 2 do 303 287 304 - iter_n = img:points(x + 1, y - 1, max_w, y - 1) 305 - iter_s = img:points(x + 1, y + 1, max_w, y + 1) 306 - img:marshal(x + 1, y, max_w, y, _NIL, _NIL, true, check_ns) 288 + if targetclr == _get(img, x, y, true) then 289 + _marshal(img, x, y, 1, y, _NIL, _NIL, true, check_ns) -- west 290 + _marshal(img, x + 1, y, max_w, y, _NIL, _NIL, true, check_ns) -- east 307 291 end 308 292 309 293 x = qpt[qhead - 1] ··· 320 304 end -- flood_fill 321 305 322 306 -- draws a closed figure based on points in t_points 323 - local function polygon(img, x, y, t_points, color, fillcolor, bClip) 307 + _draw.polygon = function(img, x, y, t_points, color, fillcolor, bClip) 324 308 if #t_points < 2 then error("not enough points", 3) end 325 309 326 310 if fillcolor then ··· 335 319 if pt[2] < y_min then y_min = pt[2] end 336 320 if pt[2] > y_max then y_max = pt[2] end 337 321 end 338 - w = math.abs(x_max) + math.abs(x_min) 339 - h = math.abs(y_max) + math.abs(y_min) 322 + w = _abs(x_max) + _abs(x_min) 323 + h = _abs(y_max) + _abs(y_min) 340 324 x_min = x_min - 2 -- leave a border to use flood_fill 341 325 y_min = y_min - 2 342 326 343 - local fill_img = rb.new_image(w + 3, h + 3) 344 - fill_img:clear(0xFFFFFF) 327 + local fill_img = _newimg(w + 3, h + 3) 328 + _clear(fill_img, 0x1) 345 329 346 330 for i = 1, #t_points, 1 do 347 331 local pt1 = t_points[i] 348 332 local pt2 = t_points[i + 1] or t_points[1]-- first and last point 349 - fill_img:line(pt1[1] - x_min, pt1[2] - y_min, 333 + _line(fill_img, pt1[1] - x_min, pt1[2] - y_min, 350 334 pt2[1]- x_min, pt2[2] - y_min, 0) 351 335 352 336 end 353 - flood_fill(fill_img, fill_img:width(), fill_img:height() , 1, 0) 354 - img:copy(fill_img, x - 1, y - 1, _NIL, _NIL, _NIL, _NIL, bClip, BSAND, fillcolor) 337 + _draw.flood_fill(fill_img, fill_img:width(), fill_img:height() , 0x1, 0x0) 338 + _copy(img, fill_img, x - 1, y - 1, _NIL, _NIL, _NIL, _NIL, bClip, BSAND, fillcolor) 355 339 end 356 340 357 341 polyline(img, x, y, t_points, color, true, bClip) 358 342 end 359 343 360 344 -- draw text onto image if width/height are supplied text is centered 361 - local function text(img, x, y, width, height, font, color, text) 345 + _draw.text = function(img, x, y, width, height, font, color, text) 362 346 font = font or rb.FONT_UI 363 347 364 348 local opts = {x = 0, y = 0, width = LCD_W - 1, height = LCD_H - 1, 365 - font = font, drawmode = 3, fg_pattern = 0xFFFFFF, bg_pattern = 0} 366 - set_viewport(opts) 349 + font = font, drawmode = 3, fg_pattern = 0x1, bg_pattern = 0} 350 + 351 + if rb.LCD_DEPTH == 2 then -- invert 2-bit screens 352 + --vp.drawmode = bit.bxor(vp.drawmode, 4) 353 + vp.fg_pattern = 3 - vp.fg_pattern 354 + vp.bg_pattern = 3 - vp.bg_pattern 355 + end 356 + rb.set_viewport(opts) 367 357 368 358 local res, w, h = rb.font_getstringsize(text, font) 369 359 ··· 380 370 end 381 371 382 372 -- make a copy of the current screen for later 383 - local screen_img = rb.new_image(LCD_W, LCD_H) 384 - screen_img:copy(_LCD) 373 + local screen_img = _newimg(LCD_W, LCD_H) 374 + _copy(screen_img, _LCD) 385 375 386 376 -- check if the screen buffer is supplied image if so set img to the copy 387 377 if img == _LCD then ··· 391 381 -- we will be printing the text to the screen then blitting into img 392 382 rb.lcd_clear_display() 393 383 394 - local function blit(dx, dy) 395 - img:copy(_LCD, dx, dy, _NIL, _NIL, _NIL, _NIL, false, BSAND, color) 396 - end 397 - 398 384 if w > LCD_W then -- text is too long for the screen do it in chunks 399 385 local l = 1 400 386 local resp, wp, hp ··· 417 403 end 418 404 419 405 -- using the mask we made blit color into img 420 - blit(x + width, y + height) 406 + _copy(img, _LCD, x + width, y + height, _NIL, _NIL, _NIL, _NIL, false, BSAND, color) 421 407 x = x + wp 422 408 rb.lcd_clear_display() 423 409 lenr = text:len() ··· 426 412 rb.lcd_putsxy(0, 0, text) 427 413 428 414 -- using the mask we made blit color into img 429 - blit(x + width, y + height) 415 + _copy(img, _LCD, x + width, y + height, _NIL, _NIL, _NIL, _NIL, false, BSAND, color) 430 416 end 431 417 432 - _LCD:copy(screen_img) -- restore screen 433 - set_viewport() -- set viewport default 418 + _copy(_LCD, screen_img) -- restore screen 419 + rb.set_viewport() -- set viewport default 434 420 return res, w, h 435 421 end 436 422 437 - -- expose functions to the outside through _draw table 438 - _draw.image = image 439 - _draw.text = text 440 - _draw.line = line 423 + -- expose internal functions to the outside through _draw table 441 424 _draw.hline = hline 442 425 _draw.vline = vline 443 - _draw.polygon = polygon 444 426 _draw.polyline = polyline 445 427 _draw.rect = rect 446 - _draw.circle = circle 447 - _draw.ellipse = ellipse 448 - _draw.flood_fill = flood_fill 449 - _draw.ellipse_rect = ellipse_rect 450 428 _draw.rounded_rect = rounded_rect 451 - -- filled functions use color as fillcolor if fillcolor is left empty... 452 - _draw.rect_filled = rect_filled 453 - _draw.circle_filled = circle_filled 454 - _draw.ellipse_filled = ellipse_filled 455 - _draw.ellipse_rect_filled = ellipse_rect_filled 456 - _draw.rounded_rect_filled = rounded_rect_filled 457 - 458 - -- adds the above _draw functions into the metatable for RLI_IMAGE 459 - local ex = getmetatable(rb.lcd_framebuffer()) 460 - for k, v in pairs(_draw) do 461 - if ex[k] == _NIL then 462 - ex[k] = v 463 - end 464 - end 465 - 466 429 end -- _draw functions 467 430 468 431 return _draw
+51 -66
apps/plugins/lua/include_lua/image.lua
··· 65 65 66 66 local _img = {} do 67 67 68 + local rocklib_image = getmetatable(rb.lcd_framebuffer()) 69 + setmetatable(_img, rocklib_image) 70 + 68 71 -- internal constants 69 72 local _NIL = nil -- _NIL placeholder 70 73 local _math = require("math_ex") -- math functions needed 71 74 local LCD_W, LCD_H = rb.LCD_WIDTH, rb.LCD_HEIGHT 75 + 76 + local _copy = rocklib_image.copy 77 + local _get = rocklib_image.get 78 + local _marshal = rocklib_image.marshal 79 + local _points = rocklib_image.points 72 80 73 81 -- returns new image -of- img sized to fit w/h tiling to fit if needed 74 - local function tile(img, w, h) 82 + _img.tile = function(img, w, h) 75 83 local hs , ws = img:height(), img:width() 76 84 local t_img = rb.new_image(w, h) 77 85 78 - for x = 1, w, ws do t_img:copy(img, x, 1, 1, 1) end 79 - for y = hs, h, hs do t_img:copy(t_img, 1, y, 1, 1, w, hs) end 86 + for x = 1, w, ws do _copy(t_img, img, x, 1, 1, 1) end 87 + for y = hs, h, hs do _copy(t_img, t_img, 1, y, 1, 1, w, hs) end 80 88 return t_img 81 89 end 82 90 83 91 -- resizes src to size of dst 84 - local function resize(dst, src) 92 + _img.resize = function(dst, src) 85 93 -- simple nearest neighbor resize derived from rockbox - pluginlib_bmp.c 86 94 -- pretty rough results highly recommend building one more suited.. 87 95 local dw, dh = dst:width(), dst:height() 88 96 89 - local xstep = (bit.lshift(src:width(),8) / (dw)) + 1 90 - local ystep = (bit.lshift(src:height(),8) / (dh)) 97 + local xstep = (bit.lshift(src:width(), 8) / (dw)) + 1 98 + local ystep = (bit.lshift(src:height(), 8) / (dh)) 91 99 92 100 local xpos, ypos = 0, 0 93 101 local src_x, src_y 94 102 95 103 -- walk the dest get src pixel 96 - function rsz_trans(val, x, y) 104 + local function rsz_trans(val, x, y) 97 105 if x == 1 then 98 106 src_y = bit.rshift(ypos,8) + 1 99 107 xpos = xstep - bit.rshift(xstep,4) + 1 ··· 101 109 end 102 110 src_x = bit.rshift(xpos,8) + 1 103 111 xpos = xpos + xstep 104 - return (src:get(src_x, src_y, true) or 0) 112 + return (_get(src, src_x, src_y, true) or 0) 105 113 end 106 114 --/* (dst*, [x1, y1, x2, y2, dx, dy, clip, function]) */ 107 - dst:marshal(1, 1, dw, dh, _NIL, _NIL, false, rsz_trans) 115 + _marshal(dst, 1, 1, dw, dh, _NIL, _NIL, false, rsz_trans) 108 116 end 109 117 110 118 -- returns new image -of- img rotated in whole degrees 0 - 360 111 - local function rotate(img, degrees) 119 + _img.rotate = function(img, degrees) 112 120 -- we do this backwards as if dest was the unrotated object 113 121 degrees = 360 - degrees 114 122 local c, s = _math.d_cos(degrees), _math.d_sin(degrees) ··· 133 141 |_____| |_______| |_______| ]] 134 142 135 143 -- walk the dest get translated src pixel, oversamples src to fill gaps 136 - function rot_trans(val, x, y) 144 + local function rot_trans(val, x, y) 137 145 -- move center x/y to the origin 138 146 local xtran = x - d_xctr; 139 147 local ytran = y - d_yctr; ··· 142 150 local yrot = ((xtran * s) + (ytran * c)) / 10000 + s_yctr 143 151 local xrot = ((xtran * c) - (ytran * s)) / 10000 + s_xctr 144 152 -- upper left of src image back to origin, copy src pixel 145 - return img:get(xrot, yrot, true) or 0 153 + return _get(img, xrot, yrot, true) or 0 146 154 end 147 - r_img:marshal(1, 1, dw, dh, _NIL, _NIL, false, rot_trans) 155 + _marshal(r_img, 1, 1, dw, dh, _NIL, _NIL, false, rot_trans) 148 156 return r_img 149 157 end 150 158 151 159 -- saves img to file: name 152 - local function save(img, name) 160 + _img.save = function(img, name) 153 161 -- bmp saving derived from rockbox - screendump.c 154 162 -- bitdepth is limited by the device 155 163 -- eg. device displays greyscale, rgb images are saved greyscale 156 164 local file 157 - 165 + local bbuffer = {} -- concat buffer for s_bytes 158 166 local fbuffer = {} -- concat buffer for file writes, reused 159 - 160 - local function dump_fbuffer(thresh) 161 - if #fbuffer >= thresh then 162 - file:write(table.concat(fbuffer)) 163 - for i=1, #fbuffer do fbuffer[i] = _NIL end -- reuse table 164 - end 165 - end 166 167 167 168 local function s_bytesLE(bits, value) 168 169 -- bits must be multiples of 8 (sizeof byte) 169 170 local byte 170 - local result = "" 171 - for b = 1, bit.rshift(bits, 3) do 171 + local nbytes = bit.rshift(bits, 3) 172 + for b = 1, nbytes do 172 173 if value > 0 then 173 174 byte = value % 256 174 175 value = (value - byte) / 256 175 - result = result .. string.char(byte) 176 176 else 177 - result = result .. string.char(0) 177 + byte = 0 178 178 end 179 + bbuffer[b] = string.char(byte) 179 180 end 180 - return result 181 + return table.concat(bbuffer, _NIL, 1, nbytes) 181 182 end 182 183 183 184 local function s_bytesBE(bits, value) 184 185 -- bits must be multiples of 8 (sizeof byte) 185 186 local byte 186 - local result = "" 187 - for b = 1, bit.rshift(bits, 3) do 187 + local nbytes = bit.rshift(bits, 3) 188 + for b = nbytes, 1, -1 do 188 189 if value > 0 then 189 190 byte = value % 256 190 191 value = (value - byte) / 256 191 - result = string.char(byte) .. result 192 192 else 193 - result = string.char(0) .. result 193 + byte = 0 194 194 end 195 + bbuffer[b] = string.char(byte) 195 196 end 196 - return result 197 + return table.concat(bbuffer, _NIL, 1, nbytes) 197 198 end 198 199 199 - local function c_cmp(color, shift) 200 - -- [RR][GG][BB] 201 - return bit.band(bit.rshift(color, shift), 0xFF) 202 - end 203 - 204 - local cmp = {["r"] = function(c) return c_cmp(c, 16) end, 205 - ["g"] = function(c) return c_cmp(c, 08) end, 206 - ["b"] = function(c) return c_cmp(c, 00) end} 200 + local cmp = {["r"] = function(c) return bit.band(bit.rshift(c, 16), 0xFF) end, 201 + ["g"] = function(c) return bit.band(bit.rshift(c, 08), 0xFF) end, 202 + ["b"] = function(c) return bit.band(c, 0xFF) end} 207 203 208 204 local function bmp_color(color) 209 205 return s_bytesLE(8, cmp.b(color)).. ··· 314 310 end 315 311 end 316 312 317 - dump_fbuffer(0) -- write the header to the file now 313 + file:write(table.concat(fbuffer))-- write the header to the file now 314 + for i=1, #fbuffer do fbuffer[i] = _NIL end -- reuse table 318 315 319 316 local imgdata = fbuffer 320 317 -- pad rows to a multiple of 4 bytes ··· 327 324 end 328 325 329 326 -- Bitmap lines start at bottom unless biHeight is negative 330 - for point in img:points(1, h, w + bytesleft, 1) do 327 + for point in _points(img, 1, h, w + bytesleft, 1) do 331 328 imgdata[#imgdata + 1] = fs_bytes_E(bpp, point or 0) 332 - dump_fbuffer(31) -- buffered write, increase # for performance 329 + 330 + if #fbuffer >= 31 then -- buffered write, increase # for performance 331 + file:write(table.concat(fbuffer)) 332 + for i=1, #fbuffer do fbuffer[i] = _NIL end -- reuse table 333 + end 334 + 333 335 end 334 - 335 - dump_fbuffer(0) --write leftovers to file 336 + file:write(table.concat(fbuffer)) --write leftovers to file 337 + fbuffer = _NIL 336 338 337 339 file:close() 338 340 end -- save(img, name) 339 341 340 342 --searches an image for target color 341 - local function search(img, x1, y1, x2, y2, targetclr, variation, stepx, stepy) 343 + _img.search = function(img, x1, y1, x2, y2, targetclr, variation, stepx, stepy) 342 344 343 345 if variation > 128 then variation = 128 end 344 346 if variation < -128 then variation = -128 end ··· 352 354 targetl = swap 353 355 end 354 356 355 - for point, x, y in img:points(x1, y1, x2, y2, stepx, stepy) do 357 + for point, x, y in _points(img, x1, y1, x2, y2, stepx, stepy) do 356 358 if point >= targetl and point <= targeth then 357 359 return point, x, y 358 360 end ··· 362 364 363 365 --[[ we won't be extending these into RLI_IMAGE]] 364 366 -- creates a new rbimage size w x h 365 - local function new(w, h) 367 + _img.new = function(w, h) 366 368 return rb.new_image(w, h) 367 369 end 368 370 369 371 -- returns new image -of- file: name (_NIL if error) 370 - local function load(name) 372 + _img.load = function(name) 371 373 return rb.read_bmp_file("/" .. name) 372 374 end 373 375 ··· 381 383 _img.RLI_INFO_DEPTH = 0x6 382 384 _img.RLI_INFO_FORMAT = 0x7 383 385 _img.RLI_INFO_ADDRESS = 0x8 384 - 385 - -- expose functions to the outside through _img table 386 - _img.save = save 387 - _img.search = search 388 - _img.rotate = rotate 389 - _img.resize = resize 390 - _img.tile = tile 391 - 392 - -- adds the above _img functions into the metatable for RLI_IMAGE 393 - local ex = getmetatable(rb.lcd_framebuffer()) 394 - for k, v in pairs(_img) do 395 - if ex[k] == _NIL then ex[k] = v end 396 - end 397 - -- not exposed through RLI_IMAGE 398 - _img.new = new 399 - _img.load = load 400 - 401 386 end -- _img functions 402 387 403 388 return _img
+13 -11
apps/plugins/lua/include_lua/lcd.lua
··· 51 51 52 52 --internal constants 53 53 local _NIL = nil -- _NIL placeholder 54 - local LCD_W, LCD_H = rb.LCD_WIDTH, rb.LCD_HEIGHT 55 54 56 55 -- clamps value to >= min and <= max 57 56 local function clamp(val, min, max) ··· 65 64 end 66 65 67 66 -- return a copy of lcd screen 68 - local function duplicate(t, screen_img) 67 + _lcd.duplicate = function(t, screen_img) 69 68 screen_img = screen_img or rb.new_image() 70 69 screen_img:copy(rb.lcd_framebuffer()) 71 70 return screen_img 72 71 end 73 72 74 73 -- updates screen in specified rectangle 75 - local function update_rect(t, x, y, w, h) 74 + _lcd.update_rect = function(t, x, y, w, h) 76 75 rb.lcd_update_rect(x - 1, y - 1, 77 - clamp(x + w, 1, LCD_W) - 1, 78 - clamp(y + h, 1, LCD_H) - 1) 76 + clamp(x + w, 1, rb.LCD_WIDTH) - 1, 77 + clamp(y + h, 1, rb.LCD_HEIGHT) - 1) 79 78 end 80 79 81 80 -- clears lcd, optional.. ([color, x1, y1, x2, y2, clip]) 82 - local function clear(t, clr, ...) 81 + _lcd.clear = function(t, clr, ...) 83 82 rb.lcd_scroll_stop() --rb really doesn't like bg change while scroll 84 83 if clr == _NIL and ... == _NIL then 85 84 rb.lcd_clear_display() ··· 89 88 end 90 89 91 90 -- loads an image to the screen 92 - local function image(t, src, x, y) 91 + _lcd.image = function(t, src, x, y) 93 92 if not src then --make sure an image was passed, otherwise bail 94 93 rb.splash(rb.HZ, "No Image!") 95 94 return _NIL ··· 98 97 end 99 98 100 99 -- Formattable version of splash 101 - local function splashf(t, timeout, ...) 100 + _lcd.splashf = function(t, timeout, ...) 102 101 rb.splash(timeout, string.format(...)) 103 102 end 104 103 105 104 -- Gets size of text 106 - local function text_extent(t, msg, font) 105 + _lcd.text_extent = function(t, msg, font) 107 106 font = font or rb.FONT_UI 108 107 109 108 return rb.font_getstringsize(msg, font) 110 109 end 111 110 112 111 -- Sets viewport size 113 - local function set_viewport(t, vp) 112 + _lcd.set_viewport = function(t, vp) 114 113 if not vp then rb.set_viewport() return end 115 114 if rb.LCD_DEPTH == 2 then -- invert 2-bit screens 116 115 --vp.drawmode = bit.bxor(vp.drawmode, 4) ··· 133 132 end 134 133 135 134 --expose functions to the outside through _lcd table 135 + --[[ 136 136 _lcd.text_extent = text_extent 137 137 _lcd.set_viewport = set_viewport 138 138 _lcd.duplicate = duplicate 139 - _lcd.update = rb.lcd_update 139 + _lcd.update = _update 140 140 _lcd.update_rect = update_rect 141 141 _lcd.clear = clear 142 142 _lcd.splashf = splashf 143 143 _lcd.image = image 144 + ]] 145 + _lcd.update = rb.lcd_update 144 146 _lcd.DEPTH = rb.LCD_DEPTH 145 147 _lcd.W = rb.LCD_WIDTH 146 148 _lcd.H = rb.LCD_HEIGHT
+36 -44
apps/plugins/lua/include_lua/print.lua
··· 49 49 50 50 local _NIL = nil -- _NIL placeholder 51 51 local _LCD = rb.lcd_framebuffer() 52 - local LCD_W, LCD_H = rb.LCD_WIDTH, rb.LCD_HEIGHT 53 52 local WHITE = _clr.set(-1, 255, 255, 255) 54 53 local BLACK = _clr.set(0, 0, 0, 0) 55 54 local DRMODE_SOLID = 3 56 55 local col_buf, s_lines = {}, {} 57 56 local _p_opts = _NIL 58 - 57 + local tabstring = string.rep(" ", 2) 59 58 -- print internal helper functions 60 59 -------------------------------------------------------------------------------- 61 60 -- clamps value to >= min and <= max ··· 67 66 return val 68 67 end 69 68 return max 70 - end 71 - 72 - -- updates screen in specified rectangle 73 - local function update_rect(x, y, w, h) 74 - rb.lcd_update_rect(x - 1, y - 1, 75 - clamp(x + w, 1, LCD_W) - 1, 76 - clamp(y + h, 1, LCD_H) - 1) 77 69 end 78 70 79 71 -- Gets size of text 80 72 local function text_extent(msg, font) 81 - font = font or rb.FONT_UI 82 73 -- res, w, h 83 - return rb.font_getstringsize(msg, font) 84 - end 85 - 86 - -- Sets viewport size 87 - local function set_viewport(vp) 88 - if not vp then rb.set_viewport() return end 89 - 90 - if rb.LCD_DEPTH == 2 then -- invert 2-bit screens 91 - --vp.drawmode = bit.bxor(vp.drawmode, 4) 92 - vp.fg_pattern = 3 - vp.fg_pattern 93 - vp.bg_pattern = 3 - vp.bg_pattern 94 - end 95 - rb.set_viewport(vp) 96 - end 97 - 98 - -- shallow copy of table 99 - function table_clone(t) 100 - local copy = {} 101 - for k, v in pairs(t) do 102 - copy[k] = v 103 - end 104 - return copy 74 + return rb.font_getstringsize(msg, font or rb.FONT_UI) 105 75 end 106 76 107 77 -- Updates a single line on the screen 108 78 local function update_line(enabled, opts, line, h) 109 79 if enabled ~= true then return end 110 80 local o = opts or _p_opts 111 - update_rect(o.x, o.y + line * h + 1, o.width, h) 81 + -- updates screen in specified rectangle 82 + rb.lcd_update_rect(o.x - 1, o.y + line * h, 83 + clamp(o.x + o.width, 1, rb.LCD_WIDTH) - 1, 84 + clamp(o.y + line * h + 1 + h, 1, rb.LCD_HEIGHT) - 1) 112 85 end 113 86 114 87 -- Clears a single line on the screen ··· 129 102 local function col_buf_insert(msg, line, _p_opts) 130 103 --if _p_opts.line <= 1 then col_buf = {} end 131 104 if not col_buf[line] then 132 - table.insert(col_buf, line, msg) end 105 + table.insert(col_buf, line, msg) 106 + end 133 107 end 134 108 135 - --replaces / strips escape characters 109 + --replaces / strips tab characters 136 110 local function check_escapes(o, msg) 111 + --[[ --for replacing a variety of escapes 137 112 local tabsz = 2 138 113 local tabstr = string.rep(" ", tabsz) 139 - 140 114 local function repl(esc) 141 115 local ret = "" 142 116 if esc:sub(1,1) == "\t" then ret = string.rep(tabstr, esc:len()) end 143 117 return ret 144 118 end 145 - 146 119 msg = msg:gsub("(%c+)", repl) 147 - 120 + ]] 121 + msg = msg:gsub("\t", tabstring) 148 122 local res, w, h = text_extent(msg, o.font) 149 123 return w, h, msg 150 124 end ··· 154 128 local function set_defaults() 155 129 _p_opts = { x = 1, 156 130 y = 1, 157 - width = LCD_W - 1, 158 - height = LCD_H - 1, 131 + width = rb.LCD_WIDTH - 1, 132 + height = rb.LCD_HEIGHT - 1, 159 133 font = rb.FONT_UI, 160 134 drawmode = DRMODE_SOLID, 161 135 fg_pattern = WHITE, ··· 178 152 -- if bByRef is _NIL or false then a copy is returned 179 153 local function get_settings(bByRef) 180 154 _p_opts = _p_opts or set_defaults() 181 - if not bByRef then return table_clone(_p_opts) end 155 + if not bByRef then 156 + -- shallow copy of table 157 + local copy = {} 158 + for k, v in pairs(_p_opts) do 159 + copy[k] = v 160 + end 161 + return copy 162 + end 163 + 182 164 return _p_opts 183 165 end 184 166 ··· 216 198 -- alternative selection method 217 199 --msg = "> " .. msg 218 200 end 219 - set_viewport(o) 201 + 202 + if not o then rb.set_viewport() return end 203 + 204 + if rb.LCD_DEPTH == 2 then -- invert 2-bit screens 205 + o.fg_pattern = 3 - o.fg_pattern 206 + o.bg_pattern = 3 - o.bg_pattern 207 + end 208 + 209 + rb.set_viewport(o) 210 + 220 211 o = _NIL 221 212 end 222 213 ··· 251 242 -- sets print area 252 243 local function set_area(x, y, w, h) 253 244 local o = get_settings(true) 254 - o.x, o.y = clamp(x, 1, LCD_W), clamp(y, 1, LCD_H) 255 - o.width, o.height = clamp(w, 1, LCD_W - o.x), clamp(h, 1, LCD_H - o.y) 245 + o.x, o.y = clamp(x, 1, rb.LCD_WIDTH), clamp(y, 1, rb.LCD_HEIGHT) 246 + o.width, o.height = clamp(w, 1, rb.LCD_WIDTH - o.x), clamp(h, 1, rb.LCD_HEIGHT - o.y) 256 247 o.max_line = max_lines(_p_opts) 257 248 258 249 clear() ··· 312 303 local o = get_settings(true) 313 304 local w, h, msg 314 305 local line = o.line - 1 -- rb is 0-based lua is 1-based 306 + 315 307 if not (...) or (...) == "\n" then -- handles blank line / single '\n' 316 308 local res, w, h = text_extent(" ", o.font) 317 309
+306 -326
apps/plugins/lua/rocklib_img.c
··· 57 57 #define ABS(a)(((a) < 0) ? - (a) :(a)) 58 58 #endif 59 59 60 - #ifndef LCD_BLACK 61 - #define LCD_BLACK 0x0 62 - #endif 63 - 64 60 struct rocklua_image 65 61 { 66 62 int width; ··· 68 64 int stride; 69 65 size_t elems; 70 66 fb_data *data; 71 - fb_data dummy[1]; 67 + fb_data dummy[1][1]; 72 68 }; 73 69 74 70 /* holds iterator data for rlimages */ 75 71 struct rli_iter_d 76 72 { 77 - struct rocklua_image *img; 78 - fb_data *elem; 79 73 int x , y; 80 74 int x1, y1; 81 75 int x2, y2; 82 76 int dx, dy; 77 + fb_data *elem; 78 + struct rocklua_image *img; 83 79 }; 84 80 85 81 /* __tostring information enums */ ··· 92 88 static inline fb_data invert_color(fb_data rgb) 93 89 { 94 90 uint8_t r = 0xFFU - FB_UNPACK_RED(rgb); 95 - uint8_t g = 0xFFU - FB_UNPACK_RED(rgb); 96 - uint8_t b = 0xFFU - FB_UNPACK_RED(rgb); 91 + uint8_t g = 0xFFU - FB_UNPACK_GREEN(rgb); 92 + uint8_t b = 0xFFU - FB_UNPACK_BLUE(rgb); 97 93 98 94 return FB_RGBPACK(r, g, b); 99 95 } ··· 244 240 static void bounds_check_xy(lua_State *L, struct rocklua_image *img, 245 241 int nargx, int x, int nargy, int y) 246 242 { 247 - luaL_argcheck(L, x <= img->width && x > 0, nargx, ERR_IDX_RANGE); 248 - luaL_argcheck(L, y <= img->height && y > 0, nargy, ERR_IDX_RANGE); 243 + int narg; 244 + 245 + if(x > img->width || x < 1) 246 + narg = nargx; 247 + else if(y <= img->height && y > 0) 248 + return; /* note -- return if no error */ 249 + else 250 + narg = nargy; 251 + 252 + luaL_argerror(L, narg, ERR_IDX_RANGE); 249 253 } /* bounds_check_xy */ 250 254 251 255 static struct rocklua_image* rli_checktype(lua_State *L, int arg) 252 256 { 253 - void *ud = luaL_checkudata(L, arg, ROCKLUA_IMAGE); 257 + #if 0 258 + return (struct rocklua_image*) luaL_checkudata(L, arg, ROCKLUA_IMAGE); 259 + #else /* cache result */ 260 + static struct rocklua_image* last = NULL; 261 + void *ud = lua_touserdata(L, arg); 254 262 255 - luaL_argcheck(L, ud != NULL, arg, "'" ROCKLUA_IMAGE "' expected"); 263 + if(ud != NULL) 264 + { 265 + if(ud == last) 266 + return last; 267 + else if (lua_getmetatable(L, arg)) 268 + { /* does it have a metatable? */ 269 + luaL_getmetatable(L, ROCKLUA_IMAGE); /* get correct metatable */ 270 + if (lua_rawequal(L, -1, -2)) 271 + { /* does it have the correct mt? */ 272 + lua_pop(L, 2); /* remove both metatables */ 273 + last = (struct rocklua_image*) ud; 274 + return last; 275 + } 276 + } 277 + } 256 278 257 - return (struct rocklua_image*) ud; 279 + luaL_typerror(L, arg, ROCKLUA_IMAGE); /* else error */ 280 + return NULL; /* to avoid warnings */ 281 + #endif 258 282 } /* rli_checktype */ 259 283 260 284 static struct rocklua_image * alloc_rlimage(lua_State *L, bool alloc_data, ··· 286 310 /* apparent w/h is stored but behind the scenes native w/h is used */ 287 311 img->width = width; 288 312 img->height = height; 289 - img->stride = w_native; 313 + img->stride = STRIDE_MAIN(w_native, h_native); 290 314 img->elems = n_elems; 291 315 292 316 return img; ··· 305 329 /* rliimage is pushed on the stack it is up to you to pop it */ 306 330 struct rocklua_image *a = alloc_rlimage(L, true, width, height); 307 331 308 - a->data = &a->dummy[0]; /* ref to beginning of alloc'd img data */ 332 + a->data = &a->dummy[0][0]; /* ref to beginning of alloc'd img data */ 309 333 310 334 return a->data; 311 335 } /* rli_alloc */ 312 336 313 - static inline fb_data data_setget(fb_data *elem, int x, int y, fb_data *val) 337 + static inline fb_data data_set(fb_data *elem, int x, int y, fb_data *val) 314 338 { 315 - fb_data old_val = FB_SCALARPACK(0); 339 + fb_data old_val; 316 340 fb_data new_val; 317 341 318 342 if(elem) ··· 328 352 else 329 353 pixel_to_fb(x, y, &old_val, &new_val); 330 354 } 355 + else 356 + old_val = FB_SCALARPACK(0); 331 357 332 358 return old_val; 333 - } /* data_setget */ 334 - 335 - static inline fb_data data_set(fb_data *elem, int x, int y, fb_data *new_val) 336 - { 337 - /* get and set share the same underlying function */ 338 - return data_setget(elem, x, y, new_val); 339 359 } /* data_set */ 340 360 341 361 static inline fb_data data_get(fb_data *elem, int x, int y) 342 362 { 343 - /* get and set share the same underlying function */ 344 - return data_setget(elem, x, y, NULL); 363 + return data_set(elem, x, y, NULL); 345 364 } /* data_get */ 346 365 347 - static fb_data* rli_get_element(struct rocklua_image* img, int x, int y) 366 + static inline fb_data* rli_get_element(struct rocklua_image* img, int x, int y) 348 367 { 349 368 int stride = img->stride; 350 369 size_t elements = img->elems; ··· 352 371 353 372 pixel_to_native(x, y, &x, &y); 354 373 374 + #if defined(LCD_STRIDEFORMAT) && LCD_STRIDEFORMAT == VERTICAL_STRIDE 375 + /* column major address */ 376 + size_t data_address = (stride * (x - 1)) + (y - 1); 377 + 378 + /* y needs bound between 0 and stride otherwise overflow to prev/next x */ 379 + if(y <= 0 || y > stride || data_address >= elements) 380 + return NULL; /* data overflow */ 381 + #else 355 382 /* row major address */ 356 383 size_t data_address = (stride * (y - 1)) + (x - 1); 357 384 358 385 /* x needs bound between 0 and stride otherwise overflow to prev/next y */ 359 386 if(x <= 0 || x > stride || data_address >= elements) 360 387 return NULL; /* data overflow */ 388 + #endif 361 389 362 390 return &data[data_address]; /* return element address */ 363 391 } /* rli_get_element */ 364 392 365 393 /* Lua to C Interface for pixel set and get functions */ 366 - static int rli_setget(lua_State *L, bool is_get) 394 + static int rli_setget(lua_State *L, bool is_get, int narg_clip) 367 395 { 368 396 /*(set) (dst*, [x1, y1, clr, clip]) */ 369 397 /*(get) (dst*, [x1, y1, clip]) */ 370 398 struct rocklua_image *a = rli_checktype(L, 1); 371 - int x = luaL_checkint(L, 2); 372 - int y = luaL_checkint(L, 3); 373 - 374 - fb_data clr = FB_SCALARPACK(0); /* Arg 4 is color if set element */ 375 - fb_data *p_clr = &clr; 399 + int x = lua_tointeger(L, 2); 400 + int y = lua_tointeger(L, 3); 376 401 377 - int clip_narg; 378 - 379 - if(is_get) /* get element */ 380 - { 381 - p_clr = NULL; 382 - clip_narg = 4; 383 - } 384 - else /* set element */ 385 - { 386 - clr = FB_SCALARPACK((unsigned) luaL_checknumber(L, 4)); 387 - clip_narg = 5; 388 - } 402 + fb_data clr; /* Arg 4 is color if set element */ 389 403 390 404 fb_data *element = rli_get_element(a, x, y); 391 405 392 406 if(!element) 393 407 { 394 - if(!luaL_optboolean(L, clip_narg, false)) /* Error if !clip */ 408 + if(!lua_toboolean(L, narg_clip)) /* Error if !clip */ 395 409 bounds_check_xy(L, a, 2, x, 3, y); 396 410 397 411 lua_pushnil(L); 398 412 return 1; 399 413 } 400 414 401 - lua_pushnumber(L, FB_UNPACK_SCALAR_LCD(data_setget(element, x, y, p_clr))); 415 + if(is_get) /* get element */ 416 + lua_pushinteger(L, FB_UNPACK_SCALAR_LCD(data_get(element, x, y))); 417 + else /* set element */ 418 + { 419 + clr = FB_SCALARPACK((unsigned) lua_tointeger(L, 4)); 420 + lua_pushinteger(L, FB_UNPACK_SCALAR_LCD(data_set(element, x, y, &clr))); 421 + } 402 422 403 423 /* returns old value */ 404 424 return 1; 405 425 } /* rli_setget */ 406 426 407 427 #ifdef RLI_EXTENDED 408 - static bool init_rli_iter(struct rli_iter_d *d, 428 + static bool rli_iter_init(struct rli_iter_d *d, 409 429 struct rocklua_image *img, 410 430 int x1, int y1, 411 431 int x2, int y2, ··· 417 437 swap_int((swy), &y1, &y2); 418 438 419 439 /* stepping in the correct x direction ? */ 420 - if((dx > 0 && x1 > x2) || (dx < 0 && x1 < x2)) 440 + if((dx ^ (x2 - x1)) < 0) 421 441 dx = -dx; 422 442 423 443 /* stepping in the correct y direction ? */ 424 - if((dy > 0 && y1 > y2) || (dy < 0 && y1 < y2)) 444 + if((dy ^ (y2 - y1)) < 0) 425 445 dy = -dy; 426 446 427 447 d->img = img; ··· 436 456 d->elem = rli_get_element(img, d->x, d->y); 437 457 438 458 return(dx != 0 || dy != 0); 439 - } /* init_rli_iter */ 459 + } /* rli_iter_init */ 460 + 461 + static struct rli_iter_d * rli_iter_create(lua_State *L) 462 + { 463 + struct rocklua_image *a = rli_checktype(L, 1); 464 + int x1 = luaL_optint(L, 2, 1); 465 + int y1 = luaL_optint(L, 3, 1); 466 + int x2 = luaL_optint(L, 4, a->width); 467 + int y2 = luaL_optint(L, 5, a->height); 468 + int dx = luaL_optint(L, 6, 1); 469 + int dy = luaL_optint(L, 7, 1); 470 + bool clip = lua_toboolean(L, 8); 471 + 472 + if(!clip) 473 + { 474 + bounds_check_xy(L, a, 2, x1, 3, y1); 475 + bounds_check_xy(L, a, 4, x2, 5, y2); 476 + } 477 + 478 + struct rli_iter_d *ds; 479 + /* create new iter + pushed onto stack */ 480 + ds = (struct rli_iter_d *) lua_newuserdata(L, sizeof(struct rli_iter_d)); 481 + 482 + rli_iter_init(ds, a, x1, y1, x2, y2, dx, dy, false, false); 483 + 484 + return ds; 485 + } 440 486 441 487 /* steps to the next point(x, y) by delta x/y, stores pointer to element 442 488 returns true if x & y haven't reached x2 & y2 ··· 464 510 return true; 465 511 } /* next_rli_iter */ 466 512 467 - static int d_line(struct rocklua_image *img, 468 - int x1, int y1, 469 - int x2, int y2, 470 - fb_data *clr, 471 - bool clip) 513 + static void d_line(struct rocklua_image *img, 514 + int x1, int y1, 515 + int x2, int y2, 516 + fb_data *clr) 472 517 { 473 518 /* NOTE! clr passed as pointer */ 474 519 /* Bresenham midpoint line algorithm */ ··· 477 522 int r_a = x2 - x1; /* range of x direction called 'a' for now */ 478 523 int r_b = y2 - y1; /* range of y direction called 'b' for now */ 479 524 480 - int s_a = 1; /* step of a direction */ 481 - int s_b = 1; /* step of b direction */ 525 + int s_a = (r_a > 0) - (r_a < 0); /* step of a direction -1, 0, 1 */ 526 + int s_b = (r_b > 0) - (r_b < 0); /* step of b direction -1, 0, 1 */ 482 527 483 528 int d_err; 484 529 int numpixels; ··· 486 531 int *a1 = &x1; /* pointer to the x var 'a' */ 487 532 int *b1 = &y1; /* pointer to the y var 'b' */ 488 533 489 - if(r_a < 0) /* instead of negative range we will switch step instead */ 490 - { 491 - r_a = -r_a; 492 - s_a = -s_a; 493 - } 494 - 495 - if(r_b < 0) /* instead of negative range we will switch step instead */ 496 - { 497 - r_b = -r_b; 498 - s_b = -s_b; 499 - } 500 - 501 - x2 += s_a; /* add 1 extra point to make the whole line */ 502 - y2 += s_b; /* add 1 extra point */ 534 + r_a = ABS(r_a);/* instead of negative range we switch step */ 535 + r_b = ABS(r_b);/* instead of negative range we switch step */ 503 536 504 537 if(r_b > r_a) /*if rangeY('b') > rangeX('a') swap their identities */ 505 538 { 506 - a1 = &y1; 507 - b1 = &x1; 539 + a1 = &y1; /* pointer to the y var 'a' */ 540 + b1 = &x1; /* pointer to the x var 'b' */ 508 541 swap_int((true), &r_a, &r_b); 509 542 swap_int((true), &s_a, &s_b); 510 543 } 511 544 512 545 d_err = ((r_b << 1) - r_a) >> 1; /* preload err of 1 step (px centered) */ 513 546 547 + /* add 1 extra point to make the whole line */ 514 548 numpixels = r_a + 1; 515 549 516 550 r_a -= r_b; /* pre-subtract 'a' - 'b' */ 517 551 518 - for(;numpixels > 0; numpixels--) 552 + for(; numpixels > 0; numpixels--) 519 553 { 520 554 element = rli_get_element(img, x1, y1); 521 - if(element || clip) 522 - data_set(element, x1, y1, clr); 523 - else 524 - return numpixels + 1; /* Error */ 555 + data_set(element, x1, y1, clr); 525 556 526 557 if(d_err >= 0) /* 0 is our target midpoint(exact point on the line) */ 527 558 { ··· 534 565 *a1 += s_a; /* whichever axis is in 'a' stepped(-1 or +1) */ 535 566 } 536 567 537 - return 0; 538 568 } /* d_line */ 539 569 540 570 /* ellipse worker function */ 541 - static int d_ellipse_elements(struct rocklua_image * img, 542 - int x1, int y1, 543 - int x2, int y2, 544 - int sx, int sy, 545 - fb_data *clr, 546 - fb_data *fillclr, 547 - bool clip) 571 + static void d_ellipse_elements(struct rocklua_image * img, 572 + int x1, int y1, 573 + int x2, int y2, 574 + fb_data *clr, 575 + fb_data *fillclr) 548 576 { 549 - int ret = 0; 550 - fb_data *element1, *element2, *element3, *element4; 577 + fb_data *element; 551 578 552 - if(fillclr && x1 - sx != x2 + sx) 579 + if(fillclr) 553 580 { 554 - ret |= d_line(img, x1, y1, x2, y1, fillclr, clip); /* I. II.*/ 555 - ret |= d_line(img, x1, y2, x2, y2, fillclr, clip); /* III.IV.*/ 581 + d_line(img, x1, y1, x2, y1, fillclr); /* I. II.*/ 582 + d_line(img, x1, y2, x2, y2, fillclr); /* III.IV.*/ 556 583 } 557 584 558 - x1 -= sx; /* shift x & y */ 559 - y1 -= sy; 560 - x2 += sx; 561 - y2 += sy; 585 + element = rli_get_element(img, x2, y1); 586 + data_set(element, x2, y1, clr); /* I. Quadrant +x +y */ 562 587 563 - element1 = rli_get_element(img, x2, y1); 564 - element2 = rli_get_element(img, x1, y1); 565 - element3 = rli_get_element(img, x1, y2); 566 - element4 = rli_get_element(img, x2, y2); 588 + element = rli_get_element(img, x1, y1); 589 + data_set(element, x1, y1, clr); /* II. Quadrant -x +y */ 567 590 568 - if(clip || (element1 && element2 && element3 && element4)) 569 - { 570 - data_set(element1, x2, y1, clr); /* I. Quadrant +x +y */ 571 - data_set(element2, x1, y1, clr); /* II. Quadrant -x +y */ 572 - data_set(element3, x1, y2, clr); /* III. Quadrant -x -y */ 573 - data_set(element4, x2, y2, clr); /* IV. Quadrant +x -y */ 574 - } 575 - else 576 - ret = 2; /* ERROR */ 591 + element = rli_get_element(img, x1, y2); 592 + data_set(element, x1, y2, clr); /* III. Quadrant -x -y */ 577 593 578 - return ret; 594 + element = rli_get_element(img, x2, y2); 595 + data_set(element, x2, y2, clr); /* IV. Quadrant +x -y */ 596 + 579 597 } /* d_ellipse_elements */ 580 598 581 - static int d_ellipse(struct rocklua_image *img, 599 + static void d_ellipse(struct rocklua_image *img, 582 600 int x1, int y1, 583 601 int x2, int y2, 584 602 fb_data *clr, 585 - fb_data *fillclr, 586 - bool clip) 603 + fb_data *fillclr) 587 604 { 588 605 /* NOTE! clr and fillclr passed as pointers */ 589 606 /* Rasterizing algorithm derivative of work by Alois Zingl */ 590 - #if LCD_WIDTH > 1024 || LCD_HEIGHT > 1024 607 + #if (LCD_WIDTH > 1024 || LCD_HEIGHT > 1024) && defined(INT64_MAX) 591 608 /* Prevents overflow on large screens */ 592 - double dx, dy, err, e2; 609 + int64_t dx, dy, err, e1; 593 610 #else 594 - long dx, dy, err, e2; 611 + int32_t dx, dy, err, e1; 595 612 #endif 596 - 597 - int ret = 0; 613 + /* if called with swapped points .. exchange them */ 614 + swap_int((x1 > x2), &x1, &x2); 615 + swap_int((y1 > y2), &y1, &y2); 598 616 599 - int a = ABS(x2 - x1); /* diameter */ 600 - int b = ABS(y2 - y1); /* diameter */ 617 + int a = x2 - x1; /* diameter */ 618 + int b = y2 - y1; /* diameter */ 601 619 602 - if(a == 0 || b == 0 || !clr) 603 - return ret; /* not an error but nothing to display */ 620 + if(a == 0 || b == 0) 621 + return; /* not an error but nothing to display */ 604 622 605 623 int b1 = (b & 1); 606 624 b = b - (1 - b1); ··· 613 631 614 632 err = dx + dy + b1 * a2; /* error of 1.step */ 615 633 616 - /* if called with swapped points .. exchange them */ 617 - swap_int((x1 > x2), &x1, &x2); 618 - swap_int((y1 > y2), &y1, &y2); 619 - 620 634 y1 += (b + 1) >> 1; 621 635 y2 = y1 - b1; 622 636 623 637 do 624 638 { 625 - ret = d_ellipse_elements(img, x1, y1, x2, y2, 0, 0, clr, fillclr, clip); 639 + d_ellipse_elements(img, x1, y1, x2, y2, clr, fillclr); 626 640 627 - e2 = err; 641 + e1 = err; 628 642 629 - /* using division because you can't use bit shift on doubles.. */ 630 - if(e2 <= (dy / 2)) /* target midpoint - y step */ 643 + if(e1 <= (dy >> 1)) /* target midpoint - y step */ 631 644 { 632 645 y1++; 633 646 y2--; ··· 635 648 err += dy; 636 649 } 637 650 638 - if(e2 >= (dx / 2) || err > (dy / 2)) /* target midpoint - x step */ 651 + if(e1 >= (dx >> 1) || err > (dy >> 1)) /* target midpoint - x step */ 639 652 { 640 653 x1++; 641 654 x2--; ··· 643 656 err += dx; 644 657 } 645 658 646 - } while(ret == 0 && x1 <= x2); 659 + } while(x1 <= x2); 660 + 661 + if (fillclr && x1 - x2 <= 2) 662 + fillclr = clr; 647 663 648 - while (ret == 0 && y1 - y2 < b) /* early stop of flat ellipse a=1 finish tip */ 664 + while (y1 - y2 < b) /* early stop of flat ellipse a=1 finish tip */ 649 665 { 650 - ret = d_ellipse_elements(img, x1, y1, x2, y2, 1, 0, clr, fillclr, clip); 666 + d_ellipse_elements(img, x1, y1, x2, y2, clr, fillclr); 651 667 652 668 y1++; 653 669 y2--; 654 670 } 655 671 656 - return ret; 657 672 } /* d_ellipse */ 658 673 659 674 /* Lua to C Interface for line and ellipse */ 660 - static int rli_line_ellipse(lua_State *L, bool is_ellipse) 675 + static int rli_line_ellipse(lua_State *L, bool is_ellipse, int narg_clip) 661 676 { 662 677 struct rocklua_image *a = rli_checktype(L, 1); 663 678 ··· 666 681 int x2 = luaL_optint(L, 4, x1); 667 682 int y2 = luaL_optint(L, 5, y1); 668 683 669 - fb_data clr = FB_SCALARPACK((unsigned) luaL_checknumber(L, 6)); 684 + fb_data clr = FB_SCALARPACK((unsigned) lua_tointeger(L, 6)); 670 685 671 686 fb_data fillclr; /* fill color is index 7 if is_ellipse */ 672 687 fb_data *p_fillclr = NULL; 673 688 674 - bool clip; 675 - int clip_narg; 676 - 677 - if(is_ellipse) 678 - clip_narg = 8; 679 - else 680 - clip_narg = 7; 681 - 682 - clip = luaL_optboolean(L, clip_narg, false); 689 + bool clip = lua_toboolean(L, narg_clip); 683 690 684 691 if(!clip) 685 692 { ··· 689 696 690 697 if(is_ellipse) 691 698 { 692 - if(!lua_isnoneornil(L, 7)) 699 + if(lua_type(L, 7) == LUA_TNUMBER) 693 700 { 694 - fillclr = FB_SCALARPACK((unsigned) luaL_checkint(L, 7)); 701 + fillclr = FB_SCALARPACK((unsigned) lua_tointeger(L, 7)); 695 702 p_fillclr = &fillclr; 696 703 } 697 704 698 - luaL_argcheck(L, d_ellipse(a, x1, y1, x2, y2, &clr, p_fillclr, clip) == 0, 699 - 1, ERR_DATA_OVF); 705 + d_ellipse(a, x1, y1, x2, y2, &clr, p_fillclr); 700 706 } 701 707 else 702 - luaL_argcheck(L, d_line(a, x1, y1, x2, y2, &clr, clip) == 0, 703 - 1, ERR_DATA_OVF); 708 + d_line(a, x1, y1, x2, y2, &clr); 704 709 705 710 return 0; 706 711 } /* rli_line_ellipse */ 707 712 708 - /* Pushes lua function from Stack at position narg to top of stack 709 - and puts a reference in the global registry for later use */ 710 - static inline int register_luafunc(lua_State *L, int narg_funct) 713 + static inline int rli_pushpixel(lua_State *L, fb_data color, int x, int y) 711 714 { 712 - lua_pushvalue(L, narg_funct); /* lua function */ 713 - int lf_ref = luaL_ref(L, LUA_REGISTRYINDEX); 714 - lua_settop(L, 0); /* clear C stack for use by lua function */ 715 - return lf_ref; 716 - } /* register_luafunc */ 715 + lua_pushinteger(L, FB_UNPACK_SCALAR_LCD(color)); 716 + lua_pushinteger(L, x); 717 + lua_pushinteger(L, y); 718 + return 3; 719 + } 717 720 718 721 /* User defined pixel manipulations through rli_copy, rli_marshal */ 719 722 static int custom_transform(lua_State *L, ··· 723 726 fb_data *color) 724 727 { 725 728 (void) color; 726 - 729 + (void) op; 727 730 fb_data dst; 728 731 fb_data src; 729 732 730 - unsigned int params = 3; 733 + int params; 731 734 int ret = 0; 732 735 733 - lua_rawgeti(L, LUA_REGISTRYINDEX, op); 736 + if (!lua_isfunction(L, -1)) 737 + return ret; /* error */ 738 + 739 + lua_pushvalue(L, -1); /* make a copy of the lua function */ 734 740 735 741 dst = data_get(ds->elem, ds->x, ds->y); 736 - lua_pushnumber(L, FB_UNPACK_SCALAR_LCD(dst)); 737 - lua_pushnumber(L, ds->x); 738 - lua_pushnumber(L, ds->y); 742 + params = rli_pushpixel(L, dst, ds->x, ds->y); 739 743 740 744 if(ss) /* Allows src to be omitted */ 741 745 { 742 - params += 3; 743 746 src = data_get(ss->elem, ss->x, ss->y); 744 - lua_pushnumber(L, FB_UNPACK_SCALAR_LCD(src)); 745 - lua_pushnumber(L, ss->x); 746 - lua_pushnumber(L, ss->y); 747 + params += rli_pushpixel(L, src, ss->x, ss->y); 747 748 } 748 749 749 750 lua_call(L, params, 2); /* call custom function w/ n-params & 2 ret */ 750 751 751 - if(!lua_isnoneornil(L, -2)) 752 + if(lua_type(L, -2) == LUA_TNUMBER) 752 753 { 753 - ret = 1; 754 - dst = FB_SCALARPACK((unsigned) luaL_checknumber(L, -2)); 754 + ret |= 1; 755 + dst = FB_SCALARPACK((unsigned) lua_tointeger(L, -2)); 755 756 data_set(ds->elem, ds->x, ds->y, &dst); 756 757 } 757 758 758 - if(!lua_isnoneornil(L, -1) && ss) 759 + if(ss && (lua_type(L, -1) == LUA_TNUMBER)) 759 760 { 760 761 ret |= 2; 761 - src = FB_SCALARPACK((unsigned) luaL_checknumber(L, -1)); 762 + src = FB_SCALARPACK((unsigned) lua_tointeger(L, -1)); 762 763 data_set(ss->elem, ss->x, ss->y, &src); 763 764 } 764 765 ··· 834 835 case 27: { if(dst == src) { dst = clr; } break; } 835 836 case 28: { if(dst > src) { dst = clr; } break; } 836 837 case 29: { if(dst < src) { dst = clr; } break; } 838 + #if 0 839 + /* src unneeded */ 840 + case 30: { dst = clr; break; }/* copyC */ 841 + case 31: { dst = clr | dst; break; }/* DorC */ 842 + case 32: { dst = clr ^ dst; break; }/* DxorC */ 843 + case 33: { dst = ~(clr | dst); break; }/* nDorC */ 844 + case 34: { dst = (~clr) | dst; break; }/* DornC */ 845 + case 35: { dst = clr & dst; break; }/* DandC */ 846 + case 36: { dst = clr & (~dst); break; }/* nDandC */ 847 + case 37: { dst = ~clr; break; }/* notC */ 848 + #endif 837 849 838 850 }/*switch op*/ 839 - fb_data data = FB_SCALARPACK(dst); 840 - data_set(ds->elem, ds->x, ds->y, &data); 851 + fb_data val = FB_SCALARPACK(dst); 852 + data_set(ds->elem, ds->x, ds->y, &val); 841 853 return 1; 842 854 } /* blit_transform */ 843 855 ··· 857 869 858 870 return 1; 859 871 } /* invert_transform */ 872 + 873 + static int clear_transform(lua_State *L, 874 + struct rli_iter_d *ds, 875 + struct rli_iter_d *ss, 876 + int op, 877 + fb_data *color) 878 + { 879 + (void) L; 880 + (void) op; 881 + (void) ss; 882 + 883 + data_set(ds->elem, ds->x, ds->y, color); 884 + 885 + return 1; 886 + } /* clear_transform */ 887 + 860 888 #endif /* RLI_EXTENDED */ 861 889 862 890 /* RLI to LUA Interface functions *********************************************/ ··· 865 893 int width = luaL_optint(L, 1, LCD_WIDTH); 866 894 int height = luaL_optint(L, 2, LCD_HEIGHT); 867 895 868 - luaL_argcheck(L, width > 0, 1, ERR_IDX_RANGE); 869 - luaL_argcheck(L, height > 0, 2, ERR_IDX_RANGE); 896 + luaL_argcheck(L, width > 0 && height > 0, (width <= 0) ? 1 : 2, ERR_IDX_RANGE); 870 897 871 898 rli_alloc(L, width, height); 872 899 ··· 876 903 RLI_LUA rli_set(lua_State *L) 877 904 { 878 905 /*(set) (dst*, [x1, y1, clr, clip]) */ 879 - /* get and set share the same underlying function */ 880 - return rli_setget(L, false); 906 + return rli_setget(L, false, 5); 881 907 } 882 908 883 909 RLI_LUA rli_get(lua_State *L) 884 910 { 885 911 /*(get) (dst*, [x1, y1, clip]) */ 886 - /* get and set share the same underlying function */ 887 - return rli_setget(L, true); 912 + return rli_setget(L, true, 4); 888 913 } 889 914 890 - RLI_LUA rli_height(lua_State *L) 915 + RLI_LUA rli_equal(lua_State *L) 891 916 { 892 917 struct rocklua_image *a = rli_checktype(L, 1); 893 - lua_pushnumber(L, a->height); 918 + struct rocklua_image *b = rli_checktype(L, 2); 919 + lua_pushboolean(L, a->data == b->data); 894 920 return 1; 895 921 } 896 922 897 - RLI_LUA rli_width(lua_State *L) 923 + RLI_LUA rli_height(lua_State *L) 898 924 { 899 925 struct rocklua_image *a = rli_checktype(L, 1); 900 - lua_pushnumber(L, a->width); 926 + lua_pushinteger(L, a->height); 901 927 return 1; 902 928 } 903 929 904 - RLI_LUA rli_equal(lua_State *L) 930 + RLI_LUA rli_width(lua_State *L) 905 931 { 906 932 struct rocklua_image *a = rli_checktype(L, 1); 907 - struct rocklua_image *b = rli_checktype(L, 2); 908 - lua_pushboolean(L, a->data == b->data); 933 + lua_pushinteger(L, a->width); 909 934 return 1; 910 935 } 911 936 912 937 RLI_LUA rli_size(lua_State *L) 913 938 { 914 939 struct rocklua_image *a = rli_checktype(L, 1); 915 - lua_pushnumber(L, a->elems); 940 + lua_pushinteger(L, a->elems); 916 941 return 1; 917 942 } 918 943 ··· 921 946 /*val = (img*, index, [new_val]) */ 922 947 struct rocklua_image *a = rli_checktype(L, 1); 923 948 924 - size_t i = (unsigned) luaL_checkint(L, 2); 949 + size_t i = (unsigned) lua_tointeger(L, 2); 925 950 926 951 fb_data val; 927 952 928 953 luaL_argcheck(L, i > 0 && i <= (a->elems), 2, ERR_IDX_RANGE); 929 954 930 - lua_pushnumber(L, FB_UNPACK_SCALAR_LCD(a->data[i-1])); 955 + lua_pushinteger(L, FB_UNPACK_SCALAR_LCD(a->data[i-1])); 931 956 932 - if(!lua_isnoneornil(L, 3)) 957 + if(lua_type(L, 3) == LUA_TNUMBER) 933 958 { 934 - val = FB_SCALARPACK((unsigned) luaL_checknumber(L, 3)); 959 + val = FB_SCALARPACK((unsigned) lua_tointeger(L, 3)); 935 960 a->data[i-1] = val; 936 961 } 937 962 ··· 943 968 /* (img, [infoitem]) */ 944 969 struct rocklua_image *a = rli_checktype(L, 1); 945 970 946 - int item = (unsigned) luaL_optint(L, 2, 0); 971 + int item = lua_tointeger(L, 2); 947 972 size_t bytes = a->elems * sizeof(fb_data); 948 973 949 974 switch(item) ··· 956 981 a->width, a->height, a->elems, bytes, LCD_DEPTH, LCD_PIXELFORMAT); 957 982 break; 958 983 } 959 - case RLI_INFO_TYPE: { lua_pushfstring(L, ROCKLUA_IMAGE ); break; } 960 - case RLI_INFO_WIDTH: { lua_pushfstring(L, "%d", a->width ); break; } 961 - case RLI_INFO_HEIGHT: { lua_pushfstring(L, "%d", a->height ); break; } 962 - case RLI_INFO_ELEMS: { lua_pushfstring(L, "%d", a->elems ); break; } 963 - case RLI_INFO_BYTES: { lua_pushfstring(L, "%d", bytes ); break; } 964 - case RLI_INFO_DEPTH: { lua_pushfstring(L, "%d", LCD_DEPTH ); break; } 965 - case RLI_INFO_FORMAT: { lua_pushfstring(L, "%d", LCD_PIXELFORMAT); break; } 966 - case RLI_INFO_ADDRESS: { lua_pushfstring(L, "%p", a->data); break; } 984 + case RLI_INFO_TYPE: { lua_pushfstring(L, ROCKLUA_IMAGE); break; } 985 + case RLI_INFO_WIDTH: { lua_pushinteger(L, a->width); break; } 986 + case RLI_INFO_HEIGHT: { lua_pushinteger(L, a->height); break; } 987 + case RLI_INFO_ELEMS: { lua_pushinteger(L, a->elems); break; } 988 + case RLI_INFO_BYTES: { lua_pushinteger(L, bytes); break; } 989 + case RLI_INFO_DEPTH: { lua_pushinteger(L, LCD_DEPTH ); break; } 990 + case RLI_INFO_FORMAT: { lua_pushinteger(L, LCD_PIXELFORMAT); break; } 991 + case RLI_INFO_ADDRESS: { lua_pushfstring(L, "%p", a->data); break; } 967 992 } 968 993 994 + /* lua_pushstring(L, lua_tostring(L, -1)); */ 995 + lua_tostring(L, -1); /* converts item at index to string */ 996 + 969 997 return 1; 970 998 } 971 999 ··· 974 1002 { 975 1003 /* (dst*, x1, y1, x2, y2, [clr, fillclr, clip]) */ 976 1004 /* line and ellipse share the same init function */ 977 - return rli_line_ellipse(L, true); 1005 + return rli_line_ellipse(L, true, 8); 978 1006 } 979 1007 980 1008 RLI_LUA rli_line(lua_State *L) 981 1009 { 982 1010 /* (dst*, x1, y1, [x2, y2, clr, clip]) */ 983 1011 /* line and ellipse share the same init function */ 984 - return rli_line_ellipse(L, false); 1012 + return rli_line_ellipse(L, false, 7); 985 1013 } 986 1014 987 1015 RLI_LUA rli_iterator(lua_State *L) { 988 1016 /* see rli_iterator_factory */ 1017 + int params = 0; 989 1018 struct rli_iter_d *ds; 990 1019 ds = (struct rli_iter_d *) lua_touserdata(L, lua_upvalueindex(1)); 991 1020 992 1021 if(ds->dx != 0 || ds->dy != 0) 993 1022 { 994 - lua_pushnumber(L, FB_UNPACK_SCALAR_LCD(data_get(ds->elem, ds->x, ds->y))); 995 - 996 - lua_pushinteger(L, ds->x); 997 - lua_pushinteger(L, ds->y); 1023 + params = rli_pushpixel(L, data_get(ds->elem, ds->x, ds->y), ds->x, ds->y); 998 1024 999 1025 next_rli_iter(ds); /* load next element */ 1000 - 1001 - return 3; 1002 1026 } 1003 - return 0; /* nothing left to do */ 1027 + return params; /* nothing left to do */ 1004 1028 } 1005 1029 1006 - RLI_LUA rli_iterator_factory(lua_State *L) { 1007 - /* (src*, [x1, y1, x2, y2, dx, dy]) */ 1008 - struct rocklua_image *a = rli_checktype(L, 1); /*image we wish to iterate*/ 1009 - 1010 - struct rli_iter_d *ds; 1011 - 1012 - int x1 = luaL_optint(L, 2, 1); 1013 - int y1 = luaL_optint(L, 3, 1); 1014 - int x2 = luaL_optint(L, 4, a->width - x1 + 1); 1015 - int y2 = luaL_optint(L, 5, a->height - y1 + 1); 1016 - int dx = luaL_optint(L, 6, 1); 1017 - int dy = luaL_optint(L, 7, 1); 1030 + RLI_LUA rli_iterator_factory(lua_State *L) 1031 + { 1032 + /* (points) (img*, [x1, y1, x2, y2, dx, dy, clip]) */ 1033 + /* (indices 1-8 are used by rli_iter_create) */ 1018 1034 1019 1035 /* create new iter + pushed onto stack */ 1020 - ds = (struct rli_iter_d *) lua_newuserdata(L, sizeof(struct rli_iter_d)); 1021 - 1022 - init_rli_iter(ds, a, x1, y1, x2, y2, dx, dy, false, false); 1036 + rli_iter_create(L); 1023 1037 1024 1038 /* returns the iter function with embedded iter data(up values) */ 1025 1039 lua_pushcclosure(L, &rli_iterator, 1); ··· 1027 1041 return 1; 1028 1042 } 1029 1043 1030 - RLI_LUA rli_marshal(lua_State *L) /* also invert */ 1044 + RLI_LUA rli_marshal(lua_State *L) /* also invert, clear */ 1031 1045 { 1032 - /* (img*, [x1, y1, x2, y2, dx, dy, clip, function]) */ 1033 - struct rocklua_image *a = rli_checktype(L, 1); 1034 - 1035 - struct rli_iter_d ds; 1036 - 1037 - int x1 = luaL_optint(L, 2, 1); 1038 - int y1 = luaL_optint(L, 3, 1); 1039 - int x2 = luaL_optint(L, 4, a->width); 1040 - int y2 = luaL_optint(L, 5, a->height); 1041 - int dx = luaL_optint(L, 6, 1); 1042 - int dy = luaL_optint(L, 7, 1); 1043 - bool clip = luaL_optboolean(L, 8, false); 1044 - 1045 - int lf_ref = LUA_NOREF; /* de-ref'd without consequence */ 1046 + /* (marshal/invert/clear) (img*, [x1, y1, x2, y2, dx, dy, clip, function]) */ 1047 + /* (indices 1-8 are used by rli_iter_create) */ 1048 + fb_data clr; 1046 1049 1047 1050 int (*rli_trans)(lua_State *, struct rli_iter_d *, struct rli_iter_d *, int, fb_data *); 1048 - rli_trans = invert_transform; /* default transformation */ 1051 + int ltype = lua_type (L, 9); 1049 1052 1050 - if(!clip) 1053 + /* create new iter + pushed onto stack */ 1054 + struct rli_iter_d *ds = rli_iter_create(L); 1055 + 1056 + if (ltype == LUA_TNUMBER) 1051 1057 { 1052 - bounds_check_xy(L, a, 2, x1, 3, y1); 1053 - bounds_check_xy(L, a, 4, x2, 5, y2); 1058 + clr = FB_SCALARPACK((unsigned) lua_tointeger(L, 9)); 1059 + rli_trans = clear_transform; 1054 1060 } 1055 - 1056 - init_rli_iter(&ds, a, x1, y1, x2, y2, dx, dy, false, false); 1057 - 1058 - if(lua_isfunction(L, 9)) /* custom function */ 1061 + else if(ltype == LUA_TFUNCTION) /* custom function */ 1059 1062 { 1060 1063 rli_trans = custom_transform; 1061 - lf_ref = register_luafunc(L, 9); 1064 + lua_pushvalue(L, 9); /* ensure lua function on top of stack */ 1062 1065 } 1066 + else 1067 + rli_trans = invert_transform; /* default transformation */ 1063 1068 1064 1069 do 1065 1070 { 1066 - luaL_argcheck(L, clip || (ds.elem != NULL), 1, ERR_DATA_OVF); 1067 - 1068 - if(!(*rli_trans)(L, &ds, NULL, lf_ref, NULL)) 1071 + if(!(*rli_trans)(L, ds, NULL, 0, &clr)) 1069 1072 break; /* Custom op can quit early */ 1070 1073 1071 - } while(next_rli_iter(&ds)); 1074 + } while(next_rli_iter(ds)); 1072 1075 1073 - luaL_unref(L, LUA_REGISTRYINDEX, lf_ref); /* de-reference custom function */ 1074 1076 return 0; 1075 1077 } 1076 1078 1077 1079 RLI_LUA rli_copy(lua_State *L) 1078 1080 { 1079 1081 /* (dst*, src*, [d_x, d_y, s_x, s_y, x_off, y_off, clip, [op, funct/clr]]) */ 1080 - struct rocklua_image *d = rli_checktype(L, 1); /*dst*/ 1081 - struct rocklua_image *s = rli_checktype(L, 2); /*src*/ 1082 + struct rocklua_image *dst = rli_checktype(L, 1); /* dst */ 1083 + struct rocklua_image *src = rli_checktype(L, 2); /* src */ 1082 1084 1083 - struct rli_iter_d ds; /*dst*/ 1084 - struct rli_iter_d ss; /*src*/ 1085 + struct rli_iter_d ds; /* dst */ 1086 + struct rli_iter_d ss; /* src */ 1085 1087 1086 1088 /* copy whole image if possible */ 1087 - if(s->elems == d->elems && s->width == d->width && lua_gettop(L) < 3) 1089 + if(src->elems == dst->elems && src->width == dst->width && lua_gettop(L) < 3) 1088 1090 { 1089 - rb->memcpy(d->data, s->data, d->elems * sizeof(fb_data)); 1091 + rb->memcpy(dst->data, src->data, dst->elems * sizeof(fb_data)); 1090 1092 return 0; 1091 1093 } 1092 1094 ··· 1095 1097 int s_x = luaL_optint(L, 5, 1); 1096 1098 int s_y = luaL_optint(L, 6, 1); 1097 1099 1098 - int w = MIN(d->width - d_x, s->width - s_x); 1099 - int h = MIN(d->height - d_y, s->height - s_y); 1100 + int w = MIN(dst->width - d_x, src->width - s_x); 1101 + int h = MIN(dst->height - d_y, src->height - s_y); 1100 1102 1101 1103 int x_off = luaL_optint(L, 7, w); 1102 1104 int y_off = luaL_optint(L, 8, h); 1103 1105 1104 - bool clip = luaL_optboolean(L, 9, false); 1105 - int op = luaL_optint(L, 10, 0); 1106 - fb_data clr = FB_SCALARPACK(0); /* 11 is custom function | color */ 1106 + bool clip = lua_toboolean(L, 9); 1107 + int op; /* 10 is operation for blit */ 1108 + fb_data clr; /* 11 is custom function | color */ 1107 1109 1108 1110 bool d_swx = (x_off < 0); /* dest swap */ 1109 1111 bool d_swy = (y_off < 0); 1110 - bool s_swx = false; /* src swap */ 1112 + bool s_swx = false; /* src swap */ 1111 1113 bool s_swy = false; 1112 1114 1113 1115 int (*rli_trans)(lua_State *, struct rli_iter_d *, struct rli_iter_d *, int, fb_data *); 1114 - rli_trans = blit_transform; /* default transformation */ 1115 - 1116 - int lf_ref = LUA_NOREF; /* de-ref'd without consequence */ 1117 1116 1118 1117 if(!clip) /* Out of bounds is not allowed */ 1119 1118 { 1120 - bounds_check_xy(L, d, 3, d_x, 4, d_y); 1121 - bounds_check_xy(L, s, 5, s_x, 6, s_y); 1119 + bounds_check_xy(L, dst, 3, d_x, 4, d_y); 1120 + bounds_check_xy(L, src, 5, s_x, 6, s_y); 1121 + w = MIN(w, ABS(x_off)); 1122 + h = MIN(h, ABS(y_off)); 1123 + bounds_check_xy(L, dst, 7, d_x + w, 8, d_y + h); 1124 + bounds_check_xy(L, src, 7, s_x + w, 8, s_y + h); 1122 1125 } 1123 - else if (w < 0 || h < 0) /* not an error but nothing to display */ 1124 - return 0; 1125 - 1126 - w = MIN(w, ABS(x_off)); 1127 - h = MIN(h, ABS(y_off)); 1126 + else 1127 + { 1128 + if (w < 0 || h < 0) /* not an error but nothing to display */ 1129 + return 0; 1130 + w = MIN(w, ABS(x_off)); 1131 + h = MIN(h, ABS(y_off)); 1132 + } 1128 1133 1129 - /* if(s->data == d->data) need to care about fill direction */ 1134 + /* if src->data == dst->data need to care about fill direction */ 1130 1135 if(d_x > s_x) 1131 1136 { 1132 1137 d_swx = !d_swx; ··· 1139 1144 s_swy = !s_swy; 1140 1145 } 1141 1146 1142 - init_rli_iter(&ds, d, d_x, d_y, d_x + w, d_y + h, 1, 1, d_swx, d_swy); 1147 + rli_iter_init(&ds, dst, d_x, d_y, d_x + w, d_y + h, 1, 1, d_swx, d_swy); 1143 1148 1144 - init_rli_iter(&ss, s, s_x, s_y, s_x + w, s_y + h, 1, 1, s_swx, s_swy); 1149 + rli_iter_init(&ss, src, s_x, s_y, s_x + w, s_y + h, 1, 1, s_swx, s_swy); 1145 1150 1146 - if (op == 0xFF && lua_isfunction(L, 11)) /* custom function specified.. */ 1151 + if (lua_type(L, 11) == LUA_TFUNCTION) /* custom function supplied.. */ 1147 1152 { 1148 1153 rli_trans = custom_transform; 1149 - lf_ref = register_luafunc(L, 11); 1150 - op = lf_ref; 1154 + lua_settop(L, 11); /* ensure lua function on top of stack */ 1155 + clr = 0; 1156 + op = 0; 1151 1157 } 1152 1158 else 1153 - clr = FB_SCALARPACK((unsigned) luaL_optnumber(L, 11, LCD_BLACK)); 1159 + { 1160 + rli_trans = blit_transform; /* default transformation */ 1161 + clr = FB_SCALARPACK((unsigned) lua_tointeger(L, 11)); 1162 + op = lua_tointeger(L, 10); 1163 + } 1154 1164 1155 1165 do 1156 1166 { 1157 - if(!clip) 1158 - { 1159 - luaL_argcheck(L, ss.elem != NULL, 2, ERR_DATA_OVF); 1160 - luaL_argcheck(L, ds.elem != NULL, 1, ERR_DATA_OVF); 1161 - } 1162 - 1163 1167 if(!(*rli_trans)(L, &ds, &ss, op, &clr)) 1164 1168 break; /* Custom op can quit early */ 1165 1169 1166 1170 } while(next_rli_iter(&ds) && next_rli_iter(&ss)); 1167 1171 1168 - luaL_unref(L, LUA_REGISTRYINDEX, lf_ref); /* de-reference custom function */ 1169 1172 return 0; 1170 1173 } 1171 1174 1172 1175 RLI_LUA rli_clear(lua_State *L) 1173 1176 { 1174 - /* (dst*, [color, x1, y1, x2, y2, clip]) */ 1175 - struct rocklua_image *a = rli_checktype(L, 1); 1177 + /* (clear) (dst*, [color, x1, y1, x2, y2, clip, dx, dy]) */ 1178 + lua_settop(L, 9); 1176 1179 1177 - struct rli_iter_d ds; 1178 - 1179 - fb_data clr = FB_SCALARPACK((unsigned) luaL_optnumber(L, 2, LCD_BLACK)); 1180 - int x1 = luaL_optint(L, 3, 1); 1181 - int y1 = luaL_optint(L, 4, 1); 1182 - int x2 = luaL_optint(L, 5, a->width); 1183 - int y2 = luaL_optint(L, 6, a->height); 1184 - bool clip = luaL_optboolean(L, 7, false); 1185 - 1186 - if(!clip) 1187 - { 1188 - bounds_check_xy(L, a, 3, x1, 4, y1); 1189 - bounds_check_xy(L, a, 5, x2, 6, y2); 1190 - } 1180 + lua_pushvalue(L, 7); /* clip -- index 8 */ 1181 + lua_remove(L, 7); 1191 1182 1192 - init_rli_iter(&ds, a, x1, y1, x2, y2, 1, 1, false, false); 1183 + lua_pushinteger(L, lua_tointeger(L, 2)); /*color -- index 9*/ 1184 + lua_remove(L, 2); 1193 1185 1194 - do 1195 - { 1196 - luaL_argcheck(L, clip || (ds.elem != NULL), 1, ERR_DATA_OVF); 1197 - 1198 - data_set(ds.elem, ds.x, ds.y, &clr); 1199 - 1200 - } while(next_rli_iter(&ds)); 1201 - 1202 - return 0; 1186 + return rli_marshal(L); /* (img*, [x1, y1, x2, y2, dx, dy, clip, function]) */ 1203 1187 } 1204 1188 #endif /* RLI_EXTENDED */ 1205 1189 ··· 1236 1220 1237 1221 luaL_newmetatable(L, ROCKLUA_IMAGE); 1238 1222 1239 - lua_pushstring(L, "__index"); 1240 - lua_pushvalue(L, -2); /* pushes the metatable */ 1241 - lua_settable(L, -3); /* metatable.__index = metatable */ 1223 + lua_pushvalue(L, -1); /* pushes the metatable */ 1224 + lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */ 1242 1225 1243 1226 luaL_register(L, NULL, rli_lib); 1244 1227 1245 - #ifdef RLI_EXTENDED 1246 - luaL_register(L, ROCKLUA_IMAGE, rli_lib); 1247 - #endif 1248 1228 return 1; 1249 1229 } 1250 1230 ··· 1256 1236 * ----------------------------- 1257 1237 */ 1258 1238 1259 - #define RB_WRAP(M) static int rock_##M(lua_State UNUSED_ATTR *L) 1239 + #define RB_WRAP(func) static int rock_##func(lua_State UNUSED_ATTR *L) 1260 1240 #ifdef HAVE_LCD_BITMAP 1261 1241 RB_WRAP(lcd_framebuffer) 1262 1242 {