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

lua add rlimg.lua example script split large includes to separate files

Change-Id: I67cac5bc4ce5525ab30abf9443f6cc1a33190512

+1464 -393
+9 -207
apps/plugins/lua/include_lua/draw.lua
··· 29 29 _draw.ellipse_filled 30 30 _draw.ellipse_rect_filled 31 31 _draw.ellipse_rect 32 - _draw.flood_fill 33 32 _draw.hline 34 33 _draw.image 35 34 _draw.line ··· 39 38 _draw.rect_filled 40 39 _draw.rounded_rect 41 40 _draw.rounded_rect_filled 42 - _draw.text 43 41 _draw.vline 44 42 45 43 ]] ··· 56 54 setmetatable(_draw, rocklib_image) 57 55 58 56 -- Internal Constants 59 - local _LCD = rb.lcd_framebuffer() 60 - local LCD_W, LCD_H = rb.LCD_WIDTH, rb.LCD_HEIGHT 61 57 local BSAND = 8 -- blits color to dst if src <> 0 62 58 local _NIL = nil -- nil placeholder 63 59 64 - local _abs = math.abs 60 + 65 61 local _clear = rocklib_image.clear 66 62 local _copy = rocklib_image.copy 67 63 local _ellipse = rocklib_image.ellipse 68 64 local _get = rocklib_image.get 69 65 local _line = rocklib_image.line 70 - local _marshal = rocklib_image.marshal 71 66 local _min = math.min 72 67 local _newimg = rb.new_image 73 - local _points = rocklib_image.points 74 68 75 69 -- line 76 70 _draw.line = function(img, x1, y1, x2, y2, color, bClip) ··· 87 81 _line(img, x, y, _NIL, y + length, color, bClip) 88 82 end 89 83 90 - -- draws a non-filled figure based on points in t-points 91 - local function polyline(img, x, y, t_points, color, bClosed, bClip) 92 - if #t_points < 2 then error("not enough points", 3) end 93 - 94 - local pt_first_last 95 - 96 - if bClosed then 97 - pt_first_last = t_points[1] 98 - else 99 - pt_first_last = t_points[#t_points] 100 - end 101 - 102 - for i = 1, #t_points, 1 do 103 - local pt1 = t_points[i] 104 - 105 - local pt2 = t_points[i + 1] or pt_first_last-- first and last point 106 - 84 + -- draws a non-filled rect based on points in t-points 85 + local function polyrect(img, x, y, t_points, color, bClip) 86 + local pt_first_last = t_points[1] 87 + local pt1, pt2 88 + for i = 1, 4, 1 do 89 + pt1 = t_points[i] 90 + pt2 = t_points[i + 1] or pt_first_last-- first and last point 107 91 _line(img, pt1[1] + x, pt1[2] + y, pt2[1] + x, pt2[2] + y, color, bClip) 108 92 end 109 - 110 93 end 111 94 112 95 -- rectangle 113 96 local function rect(img, x, y, width, height, color, bClip) 114 97 if width == 0 or height == 0 then return end 115 98 116 - polyline(img, x, y, {{0, 0}, {width, 0}, {width, height}, {0, height}}, color, true, bClip) 99 + polyrect(img, x, y, {{0, 0}, {width, 0}, {width, height}, {0, height}}, color, bClip) 117 100 118 101 end 119 102 ··· 240 223 _copy(dst, src, x, y, 1, 1, _NIL, _NIL, bClip) 241 224 end 242 225 243 - -- floods an area of targetclr with fillclr x, y specifies the start seed 244 - _draw.flood_fill = function(img, x, y, targetclr, fillclr) 245 - -- scanline 4-way flood algorithm 246 - -- ^ 247 - -- <--------x---> 248 - -- v 249 - -- check that target color doesn't = fill and the first point is target color 250 - if targetclr == fillclr or targetclr ~= _get(img, x, y, true) then return end 251 - local max_w = img:width() 252 - local max_h = img:height() 253 - 254 - local qpt = {} -- FIFO queue 255 - -- rather than moving elements around in our FIFO queue 256 - -- for each read; increment 'qhead' by 2 257 - -- set both elements to nil and let the 258 - -- garbage collector worry about it 259 - -- for each write; increment 'qtail' by 2 260 - -- x coordinates are in odd indices while 261 - -- y coordinates are in even indices 262 - 263 - local qtail = 0 264 - 265 - local function check_ns(val, x, y) 266 - if targetclr == val then 267 - y = y - 1 268 - if targetclr == _get(img, x, y, true) then -- north 269 - qtail = qtail + 2 270 - qpt[qtail - 1] = x 271 - qpt[qtail] = y 272 - end 273 - y = y + 2 274 - if targetclr == _get(img, x, y, true) then -- south 275 - qtail = qtail + 2 276 - qpt[qtail - 1] = x 277 - qpt[qtail] = y 278 - end 279 - return fillclr 280 - end 281 - return _NIL -- signal marshal to stop 282 - end 283 - 284 - local function seed_pt(x, y) 285 - -- should never hit max but make sure not to end early 286 - for qhead = 2, 0x40000000, 2 do 287 - 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 291 - end 292 - 293 - x = qpt[qhead - 1] 294 - qpt[qhead - 1] = _NIL 295 - 296 - if not x then break end 297 - 298 - y = qpt[qhead] 299 - qpt[qhead] = _NIL 300 - end 301 - end 302 - 303 - seed_pt(x, y) -- Begin 304 - end -- flood_fill 305 - 306 - -- draws a closed figure based on points in t_points 307 - _draw.polygon = function(img, x, y, t_points, color, fillcolor, bClip) 308 - if #t_points < 2 then error("not enough points", 3) end 309 - 310 - if fillcolor then 311 - local x_min, x_max = 0, 0 312 - local y_min, y_max = 0, 0 313 - local w, h = 0, 0 314 - -- find boundries of polygon 315 - for i = 1, #t_points, 1 do 316 - local pt = t_points[i] 317 - if pt[1] < x_min then x_min = pt[1] end 318 - if pt[1] > x_max then x_max = pt[1] end 319 - if pt[2] < y_min then y_min = pt[2] end 320 - if pt[2] > y_max then y_max = pt[2] end 321 - end 322 - w = _abs(x_max) + _abs(x_min) 323 - h = _abs(y_max) + _abs(y_min) 324 - x_min = x_min - 2 -- leave a border to use flood_fill 325 - y_min = y_min - 2 326 - 327 - local fill_img = _newimg(w + 3, h + 3) 328 - _clear(fill_img, 0x1) 329 - 330 - for i = 1, #t_points, 1 do 331 - local pt1 = t_points[i] 332 - local pt2 = t_points[i + 1] or t_points[1]-- first and last point 333 - _line(fill_img, pt1[1] - x_min, pt1[2] - y_min, 334 - pt2[1]- x_min, pt2[2] - y_min, 0) 335 - 336 - end 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) 339 - end 340 - 341 - polyline(img, x, y, t_points, color, true, bClip) 342 - end 343 - 344 - -- draw text onto image if width/height are supplied text is centered 345 - _draw.text = function(img, x, y, width, height, font, color, text) 346 - font = font or rb.FONT_UI 347 - 348 - local opts = {x = 0, y = 0, width = LCD_W - 1, height = LCD_H - 1, 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 - opts.fg_pattern = 3 - opts.fg_pattern 354 - opts.bg_pattern = 3 - opts.bg_pattern 355 - end 356 - rb.set_viewport(opts) 357 - 358 - local res, w, h = rb.font_getstringsize(text, font) 359 - 360 - if not width then 361 - width = 0 362 - else 363 - width = (width - w) / 2 364 - end 365 - 366 - if not height then 367 - height = 0 368 - else 369 - height = (height - h) / 2 370 - end 371 - 372 - -- make a copy of the current screen for later 373 - local screen_img = _newimg(LCD_W, LCD_H) 374 - _copy(screen_img, _LCD) 375 - 376 - -- check if the screen buffer is supplied image if so set img to the copy 377 - if img == _LCD then 378 - img = screen_img 379 - end 380 - 381 - -- we will be printing the text to the screen then blitting into img 382 - rb.lcd_clear_display() 383 - 384 - if w > LCD_W then -- text is too long for the screen do it in chunks 385 - local l = 1 386 - local resp, wp, hp 387 - local lenr = text:len() 388 - 389 - while lenr > 1 do 390 - l = lenr 391 - resp, wp, hp = rb.font_getstringsize(text:sub(1, l), font) 392 - 393 - while wp >= LCD_W and l > 1 do 394 - l = l - 1 395 - resp, wp, hp = rb.font_getstringsize(text:sub( 1, l), font) 396 - end 397 - 398 - rb.lcd_putsxy(0, 0, text:sub(1, l)) 399 - text = text:sub(l) 400 - 401 - if x + width > img:width() or y + height > img:height() then 402 - break 403 - end 404 - 405 - -- using the mask we made blit color into img 406 - _copy(img, _LCD, x + width, y + height, _NIL, _NIL, _NIL, _NIL, false, BSAND, color) 407 - x = x + wp 408 - rb.lcd_clear_display() 409 - lenr = text:len() 410 - end 411 - else --w <= LCD_W 412 - rb.lcd_putsxy(0, 0, text) 413 - 414 - -- using the mask we made blit color into img 415 - _copy(img, _LCD, x + width, y + height, _NIL, _NIL, _NIL, _NIL, false, BSAND, color) 416 - end 417 - 418 - _copy(_LCD, screen_img) -- restore screen 419 - rb.set_viewport() -- set viewport default 420 - return res, w, h 421 - end 422 - 423 226 -- expose internal functions to the outside through _draw table 424 227 _draw.hline = hline 425 228 _draw.vline = vline 426 - _draw.polyline = polyline 427 229 _draw.rect = rect 428 230 _draw.rounded_rect = rounded_rect 429 231 end -- _draw functions
+95
apps/plugins/lua/include_lua/draw_floodfill.lua
··· 1 + --[[ Lua Floodfill function 2 + /*************************************************************************** 3 + * __________ __ ___. 4 + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ 5 + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / 6 + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 7 + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 8 + * \/ \/ \/ \/ \/ 9 + * $Id$ 10 + * 11 + * Copyright (C) 2017 William Wilgus 12 + * 13 + * This program is free software; you can redistribute it and/or 14 + * modify it under the terms of the GNU General Public License 15 + * as published by the Free Software Foundation; either version 2 16 + * of the License, or (at your option) any later version. 17 + * 18 + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 19 + * KIND, either express or implied. 20 + * 21 + ****************************************************************************/ 22 + ]] 23 + -- floods an area of targetclr with fillclr x, y specifies the start seed 24 + -- flood_fill(img, x, y, targetclr, fillclr) 25 + if not rb.lcd_framebuffer then rb.splash(rb.HZ, "No Support!") return nil end 26 + do 27 + 28 + local rocklib_image = getmetatable(rb.lcd_framebuffer()) 29 + local _NIL = nil -- nil placeholder 30 + local _get = rocklib_image.get 31 + local _line = rocklib_image.line 32 + local _marshal = rocklib_image.marshal 33 + 34 + return function(img, x, y, targetclr, fillclr) 35 + -- scanline 4-way flood algorithm 36 + -- ^ 37 + -- <--------x---> 38 + -- v 39 + -- check that target color doesn't = fill and the first point is target color 40 + if targetclr == fillclr or targetclr ~= _get(img, x, y, true) then return end 41 + local max_w = img:width() 42 + local max_h = img:height() 43 + 44 + local qpt = {} -- FIFO queue 45 + -- rather than moving elements around in our FIFO queue 46 + -- for each read; increment 'qhead' by 2 47 + -- set both elements to nil and let the 48 + -- garbage collector worry about it 49 + -- for each write; increment 'qtail' by 2 50 + -- x coordinates are in odd indices while 51 + -- y coordinates are in even indices 52 + 53 + local qtail = 0 54 + 55 + local function check_ns(val, x, y) 56 + if targetclr == val then 57 + y = y - 1 58 + if targetclr == _get(img, x, y, true) then -- north 59 + qtail = qtail + 2 60 + qpt[qtail - 1] = x 61 + qpt[qtail] = y 62 + end 63 + y = y + 2 64 + if targetclr == _get(img, x, y, true) then -- south 65 + qtail = qtail + 2 66 + qpt[qtail - 1] = x 67 + qpt[qtail] = y 68 + end 69 + return fillclr 70 + end 71 + return _NIL -- signal marshal to stop 72 + end 73 + 74 + local function seed_pt(x, y) 75 + -- should never hit max but make sure not to end early 76 + for qhead = 2, 0x40000000, 2 do 77 + 78 + if targetclr == _get(img, x, y, true) then 79 + _marshal(img, x, y, 1, y, _NIL, _NIL, true, check_ns) -- west 80 + _marshal(img, x + 1, y, max_w, y, _NIL, _NIL, true, check_ns) -- east 81 + end 82 + 83 + x = qpt[qhead - 1] 84 + qpt[qhead - 1] = _NIL 85 + 86 + if not x then break end 87 + 88 + y = qpt[qhead] 89 + qpt[qhead] = _NIL 90 + end 91 + end 92 + 93 + seed_pt(x, y) -- Begin 94 + end -- flood_fill 95 + end
+103
apps/plugins/lua/include_lua/draw_poly.lua
··· 1 + --[[ Lua Poly Drawing functions 2 + /*************************************************************************** 3 + * __________ __ ___. 4 + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ 5 + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / 6 + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 7 + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 8 + * \/ \/ \/ \/ \/ 9 + * $Id$ 10 + * 11 + * Copyright (C) 2017 William Wilgus 12 + * 13 + * This program is free software; you can redistribute it and/or 14 + * modify it under the terms of the GNU General Public License 15 + * as published by the Free Software Foundation; either version 2 16 + * of the License, or (at your option) any later version. 17 + * 18 + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 19 + * KIND, either express or implied. 20 + * 21 + ****************************************************************************/ 22 + ]] 23 + 24 + --[[ Exposed Functions 25 + _poly.polygon 26 + _poly.polyline 27 + ]] 28 + 29 + if not rb.lcd_framebuffer then rb.splash(rb.HZ, "No Support!") return nil end 30 + 31 + local _poly = {} do 32 + local BSAND = 8 -- blits color to dst if src <> 0 33 + local _NIL = nil -- nil placeholder 34 + 35 + local _abs = math.abs 36 + local _copy = rocklib_image.copy 37 + local _line = rocklib_image.line 38 + local flood_fill = require("draw_floodfill") 39 + 40 + -- draws a non-filled figure based on points in t-points 41 + local function polyline(img, x, y, t_points, color, bClosed, bClip) 42 + if #t_points < 2 then error("not enough points", 3) end 43 + 44 + local pt_first_last 45 + 46 + if bClosed then 47 + pt_first_last = t_points[1] 48 + else 49 + pt_first_last = t_points[#t_points] 50 + end 51 + 52 + for i = 1, #t_points, 1 do 53 + local pt1 = t_points[i] 54 + 55 + local pt2 = t_points[i + 1] or pt_first_last-- first and last point 56 + 57 + _line(img, pt1[1] + x, pt1[2] + y, pt2[1] + x, pt2[2] + y, color, bClip) 58 + end 59 + 60 + end 61 + 62 + -- draws a closed figure based on points in t_points 63 + _poly.polygon = function(img, x, y, t_points, color, fillcolor, bClip) 64 + if #t_points < 2 then error("not enough points", 3) end 65 + 66 + if fillcolor then 67 + local x_min, x_max = 0, 0 68 + local y_min, y_max = 0, 0 69 + local w, h = 0, 0 70 + -- find boundries of polygon 71 + for i = 1, #t_points, 1 do 72 + local pt = t_points[i] 73 + if pt[1] < x_min then x_min = pt[1] end 74 + if pt[1] > x_max then x_max = pt[1] end 75 + if pt[2] < y_min then y_min = pt[2] end 76 + if pt[2] > y_max then y_max = pt[2] end 77 + end 78 + w = _abs(x_max) + _abs(x_min) 79 + h = _abs(y_max) + _abs(y_min) 80 + x_min = x_min - 2 -- leave a border to use flood_fill 81 + y_min = y_min - 2 82 + 83 + local fill_img = _newimg(w + 3, h + 3) 84 + _clear(fill_img, 0x1) 85 + 86 + for i = 1, #t_points, 1 do 87 + local pt1 = t_points[i] 88 + local pt2 = t_points[i + 1] or t_points[1]-- first and last point 89 + _line(fill_img, pt1[1] - x_min, pt1[2] - y_min, 90 + pt2[1]- x_min, pt2[2] - y_min, 0) 91 + 92 + end 93 + flood_fill(fill_img, fill_img:width(), fill_img:height() , 0x1, 0x0) 94 + _copy(img, fill_img, x - 1, y - 1, _NIL, _NIL, _NIL, _NIL, bClip, BSAND, fillcolor) 95 + end 96 + 97 + polyline(img, x, y, t_points, color, true, bClip) 98 + end 99 + 100 + -- expose internal functions to the outside through _poly table 101 + _poly.polyline = polyline 102 + end 103 + return _poly
+121
apps/plugins/lua/include_lua/draw_text.lua
··· 1 + --[[ Lua Draw Text function 2 + /*************************************************************************** 3 + * __________ __ ___. 4 + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ 5 + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / 6 + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 7 + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 8 + * \/ \/ \/ \/ \/ 9 + * $Id$ 10 + * 11 + * Copyright (C) 2017 William Wilgus 12 + * 13 + * This program is free software; you can redistribute it and/or 14 + * modify it under the terms of the GNU General Public License 15 + * as published by the Free Software Foundation; either version 2 16 + * of the License, or (at your option) any later version. 17 + * 18 + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 19 + * KIND, either express or implied. 20 + * 21 + ****************************************************************************/ 22 + ]] 23 + -- draw text onto image if width/height are supplied text is centered 24 + 25 + if not rb.lcd_framebuffer then rb.splash(rb.HZ, "No Support!") return nil end 26 + 27 + do 28 + -- Internal Constants 29 + local rocklib_image = getmetatable(rb.lcd_framebuffer()) 30 + local _LCD = rb.lcd_framebuffer() 31 + local LCD_W, LCD_H = rb.LCD_WIDTH, rb.LCD_HEIGHT 32 + local BSAND = 8 -- blits color to dst if src <> 0 33 + local _NIL = nil -- nil placeholder 34 + 35 + local _clear = rocklib_image.clear 36 + local _copy = rocklib_image.copy 37 + local _newimg = rb.new_image 38 + 39 + 40 + return function(img, x, y, width, height, font, color, text) 41 + font = font or rb.FONT_UI 42 + 43 + local opts = {x = 0, y = 0, width = LCD_W - 1, height = LCD_H - 1, 44 + font = font, drawmode = 3, fg_pattern = 0x1, bg_pattern = 0} 45 + 46 + if rb.LCD_DEPTH == 2 then -- invert 2-bit screens 47 + --vp.drawmode = bit.bxor(vp.drawmode, 4) 48 + opts.fg_pattern = 3 - opts.fg_pattern 49 + opts.bg_pattern = 3 - opts.bg_pattern 50 + end 51 + rb.set_viewport(opts) 52 + 53 + local res, w, h = rb.font_getstringsize(text, font) 54 + 55 + if not width then 56 + width = 0 57 + else 58 + width = (width - w) / 2 59 + end 60 + 61 + if not height then 62 + height = 0 63 + else 64 + height = (height - h) / 2 65 + end 66 + 67 + -- make a copy of the current screen for later 68 + --local screen_img = _newimg(LCD_W, LCD_H) 69 + local screen_img = _newimg(LCD_W, h * 2) 70 + _copy(screen_img, _LCD) 71 + 72 + -- check if the screen buffer is supplied image if so set img to the copy 73 + if img == _LCD then 74 + img = screen_img 75 + end 76 + 77 + -- we will be printing the text to the screen then blitting into img 78 + --rb.lcd_clear_display() 79 + _clear(_LCD, opts.bg_pattern or 0, 1, 1, LCD_W, h * 2) 80 + 81 + if w > LCD_W then -- text is too long for the screen do it in chunks 82 + local l = 1 83 + local resp, wp, hp 84 + local lenr = text:len() 85 + 86 + while lenr > 1 do 87 + l = lenr 88 + resp, wp, hp = rb.font_getstringsize(text:sub(1, l), font) 89 + 90 + while wp >= LCD_W and l > 1 do 91 + l = l - 1 92 + resp, wp, hp = rb.font_getstringsize(text:sub( 1, l), font) 93 + end 94 + 95 + rb.lcd_putsxy(0, 0, text:sub(1, l)) 96 + text = text:sub(l) 97 + 98 + if x + width > img:width() or y + height > img:height() then 99 + break 100 + end 101 + 102 + -- using the mask we made blit color into img 103 + _copy(img, _LCD, x + width, y + height, _NIL, _NIL, _NIL, _NIL, false, BSAND, color) 104 + x = x + wp 105 + --rb.lcd_clear_display() 106 + _clear(_LCD, opts.bg_pattern or 0, 1, 1, LCD_W, h * 2) 107 + 108 + lenr = text:len() 109 + end 110 + else --w <= LCD_W 111 + rb.lcd_putsxy(0, 0, text) 112 + 113 + -- using the mask we made blit color into img 114 + _copy(img, _LCD, x + width, y + height, _NIL, _NIL, _NIL, _NIL, false, BSAND, color) 115 + end 116 + 117 + _copy(_LCD, screen_img) -- restore screen 118 + rb.set_viewport() -- set viewport default 119 + return res, w, h 120 + end 121 + end
-184
apps/plugins/lua/include_lua/image.lua
··· 23 23 24 24 --[[ Exposed Functions 25 25 26 - _img.save 27 26 _img.search 28 27 _img.rotate 29 28 _img.resize ··· 155 154 _marshal(r_img, 1, 1, dw, dh, _NIL, _NIL, false, rot_trans) 156 155 return r_img 157 156 end 158 - 159 - -- saves img to file: name 160 - _img.save = function(img, name) 161 - -- bmp saving derived from rockbox - screendump.c 162 - -- bitdepth is limited by the device 163 - -- eg. device displays greyscale, rgb images are saved greyscale 164 - local file 165 - local bbuffer = {} -- concat buffer for s_bytes 166 - local fbuffer = {} -- concat buffer for file writes, reused 167 - 168 - local function s_bytesLE(bits, value) 169 - -- bits must be multiples of 8 (sizeof byte) 170 - local byte 171 - local nbytes = bit.rshift(bits, 3) 172 - for b = 1, nbytes do 173 - if value > 0 then 174 - byte = value % 256 175 - value = (value - byte) / 256 176 - else 177 - byte = 0 178 - end 179 - bbuffer[b] = string.char(byte) 180 - end 181 - return table.concat(bbuffer, _NIL, 1, nbytes) 182 - end 183 - 184 - local function s_bytesBE(bits, value) 185 - -- bits must be multiples of 8 (sizeof byte) 186 - local byte 187 - local nbytes = bit.rshift(bits, 3) 188 - for b = nbytes, 1, -1 do 189 - if value > 0 then 190 - byte = value % 256 191 - value = (value - byte) / 256 192 - else 193 - byte = 0 194 - end 195 - bbuffer[b] = string.char(byte) 196 - end 197 - return table.concat(bbuffer, _NIL, 1, nbytes) 198 - end 199 - 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} 203 - 204 - local function bmp_color(color) 205 - return s_bytesLE(8, cmp.b(color)).. 206 - s_bytesLE(8, cmp.g(color)).. 207 - s_bytesLE(8, cmp.r(color)).. 208 - s_bytesLE(8, 0) .. "" 209 - end -- c_cmp(color, c.r)) 210 - 211 - local function bmp_color_mix(c1, c2, num, den) 212 - -- mixes c1 and c2 as ratio of numerator / denominator 213 - -- used 2x each save results 214 - local bc1, gc1, rc1 = cmp.b(c1), cmp.g(c1), cmp.r(c1) 215 - 216 - return s_bytesLE(8, cmp.b(c2) - bc1 * num / den + bc1).. 217 - s_bytesLE(8, cmp.g(c2) - gc1 * num / den + gc1).. 218 - s_bytesLE(8, cmp.r(c2) - rc1 * num / den + rc1).. 219 - s_bytesLE(8, 0) .. "" 220 - end 221 - 222 - local w, h = img:width(), img:height() 223 - local depth = tonumber(img:__tostring(6)) -- RLI_INFO_DEPTH = 0x6 224 - local format = tonumber(img:__tostring(7)) -- RLI_INFO_FORMAT = 0x7 225 - 226 - local bpp, bypl -- bits per pixel, bytes per line 227 - -- bypl, pad rows to a multiple of 4 bytes 228 - if depth <= 4 then 229 - bpp = 8 -- 256 color image 230 - bypl = (w + 3) 231 - elseif depth <= 16 then 232 - bpp = 16 233 - bypl = (w * 2 + 3) 234 - elseif depth <= 24 then 235 - bpp = 24 236 - bypl = (w * 3 + 3) 237 - else 238 - bpp = 32 239 - bypl = (w * 4 + 3) 240 - end 241 - 242 - local linebytes = bit.band(bypl, bit.bnot(3)) 243 - 244 - local bytesperpixel = bit.rshift(bpp, 3) 245 - local headersz = 54 246 - local imgszpad = h * linebytes 247 - 248 - local compression, n_colors = 0, 0 249 - local h_ppm, v_ppm = 0x00000EC4, 0x00000EC4 --Pixels Per Meter ~ 96 dpi 250 - 251 - if depth == 16 then 252 - compression = 3 -- BITFIELDS 253 - n_colors = 3 254 - elseif depth <= 8 then 255 - n_colors = bit.lshift(1, depth) 256 - end 257 - 258 - headersz = headersz + (4 * n_colors) 259 - 260 - file = io.open('/' .. name, "w+") -- overwrite, rb ignores the 'b' flag 261 - 262 - if not file then 263 - rb.splash(rb.HZ, "Error opening /" .. name) 264 - return 265 - end 266 - -- create a bitmap header 'rope' with image details -- concatenated at end 267 - local bmpheader = fbuffer 268 - 269 - bmpheader[01] = "BM" 270 - bmpheader[02] = s_bytesLE(32, headersz + imgszpad) 271 - bmpheader[03] = "\0\0\0\0" -- WORD reserved 1 & 2 272 - bmpheader[04] = s_bytesLE(32, headersz) -- BITMAPCOREHEADER size 273 - bmpheader[05] = s_bytesLE(32, 40) -- BITMAPINFOHEADER size 274 - 275 - bmpheader[06] = s_bytesLE(32, w) 276 - bmpheader[07] = s_bytesLE(32, h) 277 - bmpheader[08] = "\1\0" -- WORD color planes ALWAYS 1 278 - bmpheader[09] = s_bytesLE(16, bpp) -- bits/pixel 279 - bmpheader[10] = s_bytesLE(32, compression) 280 - bmpheader[11] = s_bytesLE(32, imgszpad) 281 - bmpheader[12] = s_bytesLE(32, h_ppm) -- biXPelsPerMeter 282 - bmpheader[13] = s_bytesLE(32, v_ppm) -- biYPelsPerMeter 283 - bmpheader[14] = s_bytesLE(32, n_colors) 284 - bmpheader[15] = s_bytesLE(32, n_colors) 285 - 286 - -- Color Table (#n_colors entries) 287 - if depth == 1 then -- assuming positive display 288 - bmpheader[#bmpheader + 1] = bmp_color(0xFFFFFF) 289 - bmpheader[#bmpheader + 1] = bmp_color(0x0) 290 - elseif depth == 2 then 291 - bmpheader[#bmpheader + 1] = bmp_color(0xFFFFFF) 292 - bmpheader[#bmpheader + 1] = bmp_color_mix(0xFFFFFF, 0, 1, 3) 293 - bmpheader[#bmpheader + 1] = bmp_color_mix(0xFFFFFF, 0, 2, 3) 294 - bmpheader[#bmpheader + 1] = bmp_color(0x0) 295 - elseif depth == 16 then 296 - if format == 555 then 297 - -- red bitfield mask 298 - bmpheader[#bmpheader + 1] = s_bytesLE(32, 0x00007C00) 299 - -- green bitfield mask 300 - bmpheader[#bmpheader + 1] = s_bytesLE(32, 0x000003E0) 301 - -- blue bitfield mask 302 - bmpheader[#bmpheader + 1] = s_bytesLE(32, 0x0000001F) 303 - else --565 304 - -- red bitfield mask 305 - bmpheader[#bmpheader + 1] = s_bytesLE(32, 0x0000F800) 306 - -- green bitfield mask 307 - bmpheader[#bmpheader + 1] = s_bytesLE(32, 0x000007E0) 308 - -- blue bitfield mask 309 - bmpheader[#bmpheader + 1] = s_bytesLE(32, 0x0000001F) 310 - end 311 - end 312 - 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 315 - 316 - local imgdata = fbuffer 317 - -- pad rows to a multiple of 4 bytes 318 - local bytesleft = linebytes - (bytesperpixel * w) 319 - local t_data = {} 320 - local fs_bytes_E = s_bytesLE -- default save in Little Endian 321 - 322 - if format == 3553 then -- RGB565SWAPPED 323 - fs_bytes_E = s_bytesBE -- Saves in Big Endian 324 - end 325 - 326 - -- Bitmap lines start at bottom unless biHeight is negative 327 - for point in _points(img, 1, h, w + bytesleft, 1) do 328 - imgdata[#imgdata + 1] = fs_bytes_E(bpp, point or 0) 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 - 335 - end 336 - file:write(table.concat(fbuffer)) --write leftovers to file 337 - fbuffer = _NIL 338 - 339 - file:close() 340 - end -- save(img, name) 341 157 342 158 --searches an image for target color 343 159 _img.search = function(img, x1, y1, x2, y2, targetclr, variation, stepx, stepy)
+215
apps/plugins/lua/include_lua/image_save.lua
··· 1 + --[[ Lua Image save 2 + /*************************************************************************** 3 + * __________ __ ___. 4 + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ 5 + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / 6 + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 7 + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 8 + * \/ \/ \/ \/ \/ 9 + * $Id$ 10 + * 11 + * Copyright (C) 2017 William Wilgus 12 + * 13 + * This program is free software; you can redistribute it and/or 14 + * modify it under the terms of the GNU General Public License 15 + * as published by the Free Software Foundation; either version 2 16 + * of the License, or (at your option) any later version. 17 + * 18 + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 19 + * KIND, either express or implied. 20 + * 21 + ****************************************************************************/ 22 + ]] 23 + -- save(img, path/name) 24 + -- bmp saving derived from rockbox - screendump.c 25 + -- bitdepth is limited by the device 26 + -- eg. device displays greyscale, rgb images are saved greyscale 27 + if not rb.lcd_framebuffer then rb.splash(rb.HZ, "No Support!") return nil end 28 + 29 + do 30 + local rocklib_image = getmetatable(rb.lcd_framebuffer()) 31 + 32 + -- internal constants 33 + local _NIL = nil -- _NIL placeholder 34 + local _points = rocklib_image.points 35 + 36 + -- saves img to file: name 37 + return function(img, name) 38 + local file 39 + local bbuffer = {} -- concat buffer for s_bytes 40 + local fbuffer = {} -- concat buffer for file writes, reused 41 + 42 + local function s_bytesLE(bits, value) 43 + -- bits must be multiples of 8 (sizeof byte) 44 + local byte 45 + local nbytes = bit.rshift(bits, 3) 46 + for b = 1, nbytes do 47 + if value > 0 then 48 + byte = value % 256 49 + value = (value - byte) / 256 50 + else 51 + byte = 0 52 + end 53 + bbuffer[b] = string.char(byte) 54 + end 55 + return table.concat(bbuffer, _NIL, 1, nbytes) 56 + end 57 + 58 + local function s_bytesBE(bits, value) 59 + -- bits must be multiples of 8 (sizeof byte) 60 + local byte 61 + local nbytes = bit.rshift(bits, 3) 62 + for b = nbytes, 1, -1 do 63 + if value > 0 then 64 + byte = value % 256 65 + value = (value - byte) / 256 66 + else 67 + byte = 0 68 + end 69 + bbuffer[b] = string.char(byte) 70 + end 71 + return table.concat(bbuffer, _NIL, 1, nbytes) 72 + end 73 + 74 + local cmp = {["r"] = function(c) return bit.band(bit.rshift(c, 16), 0xFF) end, 75 + ["g"] = function(c) return bit.band(bit.rshift(c, 08), 0xFF) end, 76 + ["b"] = function(c) return bit.band(c, 0xFF) end} 77 + 78 + local function bmp_color(color) 79 + return s_bytesLE(8, cmp.b(color)).. 80 + s_bytesLE(8, cmp.g(color)).. 81 + s_bytesLE(8, cmp.r(color)).. 82 + s_bytesLE(8, 0) .. "" 83 + end -- c_cmp(color, c.r)) 84 + 85 + local function bmp_color_mix(c1, c2, num, den) 86 + -- mixes c1 and c2 as ratio of numerator / denominator 87 + -- used 2x each save results 88 + local bc1, gc1, rc1 = cmp.b(c1), cmp.g(c1), cmp.r(c1) 89 + 90 + return s_bytesLE(8, cmp.b(c2) - bc1 * num / den + bc1).. 91 + s_bytesLE(8, cmp.g(c2) - gc1 * num / den + gc1).. 92 + s_bytesLE(8, cmp.r(c2) - rc1 * num / den + rc1).. 93 + s_bytesLE(8, 0) .. "" 94 + end 95 + 96 + local w, h = img:width(), img:height() 97 + local depth = tonumber(img:__tostring(6)) -- RLI_INFO_DEPTH = 0x6 98 + local format = tonumber(img:__tostring(7)) -- RLI_INFO_FORMAT = 0x7 99 + 100 + local bpp, bypl -- bits per pixel, bytes per line 101 + -- bypl, pad rows to a multiple of 4 bytes 102 + if depth <= 4 then 103 + bpp = 8 -- 256 color image 104 + bypl = (w + 3) 105 + elseif depth <= 16 then 106 + bpp = 16 107 + bypl = (w * 2 + 3) 108 + elseif depth <= 24 then 109 + bpp = 24 110 + bypl = (w * 3 + 3) 111 + else 112 + bpp = 32 113 + bypl = (w * 4 + 3) 114 + end 115 + 116 + local linebytes = bit.band(bypl, bit.bnot(3)) 117 + 118 + local bytesperpixel = bit.rshift(bpp, 3) 119 + local headersz = 54 120 + local imgszpad = h * linebytes 121 + 122 + local compression, n_colors = 0, 0 123 + local h_ppm, v_ppm = 0x00000EC4, 0x00000EC4 --Pixels Per Meter ~ 96 dpi 124 + 125 + if depth == 16 then 126 + compression = 3 -- BITFIELDS 127 + n_colors = 3 128 + elseif depth <= 8 then 129 + n_colors = bit.lshift(1, depth) 130 + end 131 + 132 + headersz = headersz + (4 * n_colors) 133 + 134 + file = io.open('/' .. name, "w+") -- overwrite, rb ignores the 'b' flag 135 + 136 + if not file then 137 + rb.splash(rb.HZ, "Error opening /" .. name) 138 + return 139 + end 140 + -- create a bitmap header 'rope' with image details -- concatenated at end 141 + local bmpheader = fbuffer 142 + 143 + bmpheader[01] = "BM" 144 + bmpheader[02] = s_bytesLE(32, headersz + imgszpad) 145 + bmpheader[03] = "\0\0\0\0" -- WORD reserved 1 & 2 146 + bmpheader[04] = s_bytesLE(32, headersz) -- BITMAPCOREHEADER size 147 + bmpheader[05] = s_bytesLE(32, 40) -- BITMAPINFOHEADER size 148 + 149 + bmpheader[06] = s_bytesLE(32, w) 150 + bmpheader[07] = s_bytesLE(32, h) 151 + bmpheader[08] = "\1\0" -- WORD color planes ALWAYS 1 152 + bmpheader[09] = s_bytesLE(16, bpp) -- bits/pixel 153 + bmpheader[10] = s_bytesLE(32, compression) 154 + bmpheader[11] = s_bytesLE(32, imgszpad) 155 + bmpheader[12] = s_bytesLE(32, h_ppm) -- biXPelsPerMeter 156 + bmpheader[13] = s_bytesLE(32, v_ppm) -- biYPelsPerMeter 157 + bmpheader[14] = s_bytesLE(32, n_colors) 158 + bmpheader[15] = s_bytesLE(32, n_colors) 159 + 160 + -- Color Table (#n_colors entries) 161 + if depth == 1 then -- assuming positive display 162 + bmpheader[#bmpheader + 1] = bmp_color(0xFFFFFF) 163 + bmpheader[#bmpheader + 1] = bmp_color(0x0) 164 + elseif depth == 2 then 165 + bmpheader[#bmpheader + 1] = bmp_color(0xFFFFFF) 166 + bmpheader[#bmpheader + 1] = bmp_color_mix(0xFFFFFF, 0, 1, 3) 167 + bmpheader[#bmpheader + 1] = bmp_color_mix(0xFFFFFF, 0, 2, 3) 168 + bmpheader[#bmpheader + 1] = bmp_color(0x0) 169 + elseif depth == 16 then 170 + if format == 555 then 171 + -- red bitfield mask 172 + bmpheader[#bmpheader + 1] = s_bytesLE(32, 0x00007C00) 173 + -- green bitfield mask 174 + bmpheader[#bmpheader + 1] = s_bytesLE(32, 0x000003E0) 175 + -- blue bitfield mask 176 + bmpheader[#bmpheader + 1] = s_bytesLE(32, 0x0000001F) 177 + else --565 178 + -- red bitfield mask 179 + bmpheader[#bmpheader + 1] = s_bytesLE(32, 0x0000F800) 180 + -- green bitfield mask 181 + bmpheader[#bmpheader + 1] = s_bytesLE(32, 0x000007E0) 182 + -- blue bitfield mask 183 + bmpheader[#bmpheader + 1] = s_bytesLE(32, 0x0000001F) 184 + end 185 + end 186 + 187 + file:write(table.concat(fbuffer))-- write the header to the file now 188 + for i=1, #fbuffer do fbuffer[i] = _NIL end -- reuse table 189 + 190 + local imgdata = fbuffer 191 + -- pad rows to a multiple of 4 bytes 192 + local bytesleft = linebytes - (bytesperpixel * w) 193 + local t_data = {} 194 + local fs_bytes_E = s_bytesLE -- default save in Little Endian 195 + 196 + if format == 3553 then -- RGB565SWAPPED 197 + fs_bytes_E = s_bytesBE -- Saves in Big Endian 198 + end 199 + 200 + -- Bitmap lines start at bottom unless biHeight is negative 201 + for point in _points(img, 1, h, w + bytesleft, 1) do 202 + imgdata[#imgdata + 1] = fs_bytes_E(bpp, point or 0) 203 + 204 + if #fbuffer >= 31 then -- buffered write, increase # for performance 205 + file:write(table.concat(fbuffer)) 206 + for i=1, #fbuffer do fbuffer[i] = _NIL end -- reuse table 207 + end 208 + 209 + end 210 + file:write(table.concat(fbuffer)) --write leftovers to file 211 + fbuffer = _NIL 212 + 213 + file:close() 214 + end -- save(img, name) 215 + end
+2 -2
apps/plugins/lua/lua.make
··· 16 16 OTHER_SRC += $(LUA_SRC) 17 17 18 18 LUA_INCLUDEDIR := $(LUA_SRCDIR)/include_lua 19 - LUA_INCLUDELIST := $(addprefix $(LUA_BUILDDIR)/,audio.lua blit.lua color.lua draw.lua \ 20 - image.lua lcd.lua math_ex.lua print.lua \ 19 + LUA_INCLUDELIST := $(addprefix $(LUA_BUILDDIR)/,audio.lua blit.lua color.lua draw.lua draw_floodfill.lua draw_poly.lua \ 20 + draw_text.lua image.lua image_save.lua lcd.lua math_ex.lua print.lua \ 21 21 timer.lua playlist.lua pcm.lua sound.lua \ 22 22 rbcompat.lua printtable.lua) 23 23
+919
apps/plugins/lua_scripts/rlimg.lua
··· 1 + --[[ 2 + __________ __ ___. 3 + Open \______ \ ____ ____ | | _\_ |__ _______ ___ 4 + Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / 5 + Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 6 + Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 7 + \/ \/ \/ \/ \/ 8 + $Id$ 9 + Example Lua RBIMAGE script 10 + Copyright (C) 2009 by Maurus Cuelenaere -- some prior work 11 + Copyright (C) 2017 William Wilgus 12 + This program is free software; you can redistribute it and/or 13 + modify it under the terms of the GNU General Public License 14 + as published by the Free Software Foundation; either version 2 15 + of the License, or (at your option) any later version. 16 + This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 17 + KIND, either express or implied. 18 + ]]-- 19 + 20 + require("actions") -- Contains rb.actions & rb.contexts 21 + -- require("buttons") -- Contains rb.buttons -- not needed for this example 22 + 23 + local _math = require("math_ex") -- missing math sine cosine, sqrt, clamp functions 24 + local _timer = require("timer") 25 + local _clr = require("color") -- clrset, clrinc provides device independent colors 26 + local _lcd = require("lcd") -- lcd helper functions 27 + local _print = require("print") -- advanced text printing 28 + local _img = require("image") -- image manipulation save, rotate, resize, tile, new, load 29 + local _img_save = require("image_save") 30 + local _blit = require("blit") -- handy list of blit operations 31 + local _draw = require("draw") -- draw all the things (primitives) 32 + local _draw_floodfill = require("draw_floodfill") 33 + local _draw_text = require("draw_text") 34 + 35 + --local scrpath = rb.current_path()" 36 + 37 + --package.path = scrpath .. "/?.lua;" .. package.path --add lua_scripts directory to path 38 + 39 + require("printmenu") --menu 40 + 41 + --[[ RBIMAGE library functions 42 + NOTE!! on x, y coordinates + width & height 43 + ---------------------------------------------- 44 + When making a new image you specify the width and height say (10, 20). 45 + Intutively (at least to me) (0,0) (offset addressing) would reference the first 46 + pixel (top left) and the last pixel (bottom, right) would be (w-1, h-1) or (9, 19) 47 + but the original rbimage library (like lua) uses 1-based arrays (ordinal addressing) 48 + for the image data so the first pixel is (1,1) and the last pixel is (w, h) 49 + this presents a bit of a problem when interfacing with the internal rockbox 50 + functions as you must remeber to convert all lua coordinates to 0 based coordinates. 51 + I have opted to not change this in the name of compatibility with old scripts 52 + 53 + NOTE2!! on width & height versus offset_x & offset_y :copy() 54 + ------------------------------------------------------------------------ 55 + The only place where RBIMAGE deviates from (ordinal addressing) is in the blit 56 + / copy function sx, sy and dx, dy still refer to the same pixel as all the 57 + other functions but offset_x, and offset_y are zero based 58 + Example (assuming same sized images) 59 + dst:copy(src, 1,1, 1,1, 0, 0) 60 + would copy the first pixel from src to the first pixel of dst 61 + dst:copy(src, 1,1, 1,1, dst:width()-1, dst:height()-1) would copy all of src to dst 62 + this might be a bit confusing but makes reversing images (negative offsets) easier. 63 + Since offsets are auto calculated if empty or out of range you could call it as 64 + dst:copy(src, 1,1, 1,1, dst:width(), dst:height()) or even 65 + dst:copy(src, 1,1, 1,1) if you prefered and get the same result 66 + ]] 67 + 68 + --'CONSTANTS' (in lua there really is no such thing as all vars are mutable) 69 + -------------------------------------------------------- 70 + --colors for fg/bg ------------------------ 71 + local WHITE = _clr.set(-1, 255, 255, 255) 72 + local BLACK = _clr.set(0, 0, 0, 0) 73 + local RED = _clr.set(WHITE, 255) 74 + local GREEN = _clr.set(WHITE, 0, 255) 75 + local BLUE = _clr.set(WHITE, 0, 0, 255) 76 + ------------------------------------------- 77 + local clrs 78 + local CANCEL_BUTTON = rb.actions.PLA_CANCEL 79 + 80 + -- EXAMPLES ---------------------------------------------------------------------- EXAMPLES--------------------------------------------------------------------- 81 + function my_blit(dst_val, dx, dy, src_val, sx, sy) 82 + -- user defined blit operation 83 + --this function gets called for every pixel you specify 84 + --you may change pixels in both the source and dest image 85 + --return nil to stop early 86 + 87 + if _lcd.DEPTH < 2 then 88 + return src_val 89 + end 90 + 91 + if dst_val == WHITE and bit.band(dx, 1) == 1 and bit.band(dy, 1) == 1 then 92 + return BLACK; 93 + elseif dst_val == WHITE then 94 + return src_val 95 + end 96 + 97 + return dst_val 98 + end 99 + 100 + function create_logo() 101 + --[[creates a small logo from data array]] 102 + 103 + -- moves scope of white and black from global to local 104 + local WHITE = WHITE 105 + local BLACK = BLACK 106 + 107 + --[[small array with 16 bits of data per element (16-bits in y direction) 108 + while the number of elements (32) is the x direction. 109 + in other words 16 rows X 32 columns, totally abritrary actually 110 + you could easily rotate or flip it by changing the for loops below ]] 111 + local logo = {0xFFFF, 0xFFFF, 0x8001, 0x8001, 0x9E7F, 0x9E7F, 0x9E7F, 0x9E7F, 112 + 0x9E3F, 0x9E3F, 0x804F, 0x804F, 0xC0E1, 0xC0F1, 0xFFFD, 0xFFFF, 113 + 0xFFFF, 0xFFFF, 0x8001, 0x8001, 0xFF01, 0xFF01, 0xFEFB, 0xFEFB, 114 + 0xFDFD, 0xFDFD, 0xFDFD, 0xFCF9, 0xFE03, 0xFE03, 0xFFFF, 0xFFFF} 115 + 116 + local img, img1, img2, img3 117 + 118 + img = _img.new(_lcd.W, _lcd.H) 119 + img:clear(BLACK) --[[always clear an image after you create it if you 120 + intend to do any thing besides copy something 121 + entirely to it as there is no guarantee what 122 + state the data within is in, it could be all 123 + 0's or it could be every digit of PI ]] 124 + 125 + -- check for an error condition bail if error 126 + if(not img or not logo) then 127 + return nil 128 + end 129 + 130 + local logosz = table.getn(logo) 131 + local bits = 16 -- each element contains 16 pixels 132 + local data = 0 133 + 134 + for i=1, math.min(logosz, _lcd.W) do 135 + for j=0, math.min(bits, _lcd.H) do 136 + 137 + if bit.band(bit.lshift(1, bits - j), logo[i]) > 0 then 138 + data = WHITE 139 + else 140 + data = BLACK 141 + end 142 + -- Set the pixel at position i, j+1 to the copied data 143 + img:set(i, j + 1, data) 144 + end 145 + end 146 + 147 + -- make a new image the size of our generated logo 148 + img1 = _img.new(logosz + 1, bits + 1) 149 + 150 + -- img.copy(dest, source, dx, dy, sx, sy, [w, h]) 151 + img1:copy(img, 1, 1, 1, 1) 152 + 153 + --[[lua does auto garbage collection, but it is still 154 + a good idea to set large items to nil when done anyways]] 155 + img = nil 156 + 157 + local sl -- new image size 158 + if _lcd.W < _lcd.H then 159 + sl = _lcd.W / 3 160 + else 161 + sl = _lcd.H / 3 162 + end 163 + 164 + -- make sl always even by subtracting 1 if needed 165 + sl = bit.band(sl, bit.bnot(1)) 166 + if sl < 16 then 167 + sl = 16 168 + end 169 + 170 + img2 = _img.new(sl, sl) 171 + --img2:clear(BLACK) -- doesn't need cleared since we copy to it entirely 172 + 173 + --[[we are going to resize the image since the data supplied is 32 x 16 174 + pixels its really tiny on most screens]] 175 + _img.resize(img2, img1) 176 + 177 + img1 = nil 178 + 179 + img3 = _img.new(sl, sl) 180 + img3:clear(BLACK) 181 + 182 + if IS_COLOR_TARGET == true then 183 + local c_yellow = _clr.set(WHITE, 0xFC, 0xC0, 0x00) 184 + local c_grey = _clr.set(WHITE, 0xD4, 0xE3, 0xF3) 185 + local c_dkgrey = _clr.set(WHITE, 0xB4, 0xC3, 0xD3) 186 + -- if dest pixel == source pixel make dest pixel yellow 187 + img3:copy(img2, 1, 1, 1, 1, nil, nil, false, _blit.BDEQS, c_yellow) 188 + -- xor src pixel to dest pixel if both are 0 or both are 1 dest = 0 189 + img2:copy(img3, 1, 1, 2, 1, nil, nil, false, _blit.BXOR) 190 + -- if dest pixel color > src pixel color copy grey to dest 191 + img2:copy(img3, 1, 1, 1, 1, nil, nil, false, _blit.BDGTS, c_grey) 192 + -- set img3 to grey 193 + img3:clear(c_dkgrey) 194 + end 195 + 196 + -- make a WHITE square in the middle 197 + 198 + img3:clear(WHITE, 4,4, img3:width() - 3, img3:height() - 3) 199 + 200 + img3:copy(img2, 1, 1, 1, 1, nil, nil, false, _blit.CUSTOM, my_blit) 201 + img2 = nil 202 + _img_save(img3, "pix.bmp") 203 + return img3 204 + end -- copy_logo 205 + 206 + -- draws an olive erm ball and returns it 207 + function create_ball() 208 + local sl -- image size 209 + if _lcd.W < _lcd.H then 210 + sl = _lcd.W / 5 211 + else 212 + sl = _lcd.H / 5 213 + end 214 + 215 + -- make sl always even by subtracting 1 if needed 216 + sl = bit.band(sl, bit.bnot(1)) 217 + if sl < 16 then 218 + sl = 16 219 + end 220 + local img = _img.new(sl, sl) 221 + img:clear(0) 222 + _draw.circle_filled(img, sl/2, sl/2, sl/2 - 1, _clr.set(-1, 255), _clr.set(0, 100)) 223 + _draw.circle_filled(img, sl/3, sl/3, sl/10, _clr.set(-1, 255, 0, 0)) 224 + return img 225 + end 226 + 227 + -- bounces img around on screen 228 + function bounce_image(img) 229 + local timer = _timer() -- creates a new timer -- saves index 230 + local wait 231 + -- make a copy of the current screen for later 232 + local screen_img = _lcd:duplicate() 233 + 234 + local img_sqy = _img.new(img:width() + img:width() / 8, img:height()) 235 + local img_sqx = _img.new(img:width(), img:height() + img:height() / 8) 236 + _img.resize(img_sqy, img) 237 + _img.resize(img_sqx, img) 238 + 239 + -- moves definition of CANCEL_BUTTON from global to local 240 + local CANCEL_BUTTON = CANCEL_BUTTON 241 + -------------------------------------------------------- 242 + local imgn = img 243 + local hold = 0 244 + local sx = 1 -- starting x 245 + local sy = 1 -- starting y 246 + 247 + local ex = _lcd.W - img:width() - 2 248 + local ey = _lcd.H - img:width() - 2 249 + 250 + -- threshold resets speed, inverts image 251 + local tx = ex / 5 252 + local ty = ey / 5 253 + 254 + local last_x = sx 255 + local last_y = sy 256 + 257 + local x = sx 258 + local y = sy 259 + 260 + local dx = 1 261 + local dy = 1 262 + -- negative width\height cause the image to be drawn from the opposite end 263 + local fx = _lcd.W 264 + local fy = _lcd.H 265 + 266 + local function invert_images() 267 + img:invert(); 268 + img_sqx:invert() 269 + img_sqy:invert() 270 + end 271 + 272 + local loops = (_lcd.W * _lcd.H) / 2 273 + while (loops > 0) do 274 + 275 + if IS_COLOR_TARGET then 276 + if bit.band(loops, 128) == 128 then 277 + _lcd:copy(imgn, x, y, 1, 1, fx, fy, false, _blit.BOR) 278 + _lcd:copy(screen_img, x, y, x, y, imgn:width(), imgn:height(), 279 + false, _blit.BDEQC, imgn:get(1,1)) 280 + else 281 + _lcd:copy(imgn, x, y, 1, 1, fx, fy, false, _blit.BSNEC, imgn:get(1,1)) 282 + end 283 + else 284 + local blitop 285 + 286 + if imgn:get(1,1) ~= 0 then 287 + blitop = _blit.BSNOT 288 + else 289 + blitop = _blit.BXOR 290 + end 291 + 292 + _lcd:copy(imgn, x, y, 1, 1, fx, fy, false, blitop, WHITE) 293 + end 294 + 295 + if hold < 1 then 296 + imgn = img 297 + else 298 + hold = hold - 1 299 + end 300 + _lcd:update() 301 + 302 + x = x + dx 303 + y = y + dy 304 + 305 + if y >= ey or y <= sy then 306 + dy = (-dy) 307 + fy = (-fy) 308 + imgn = img_sqy 309 + hold = 3 310 + if dx < 0 and y < 10 then 311 + dx = dx - 5 312 + end 313 + if dx > tx then 314 + dx = 5; 315 + dy = 5; 316 + invert_images() 317 + end 318 + end 319 + 320 + if x >= ex or x <= sx then 321 + dx = (-dx) 322 + fx = (-fx) 323 + imgn = img_sqx 324 + hold = 3 325 + if dy < 0 and x < 10 then 326 + dy = dy - 5 327 + end 328 + if dy > ty then 329 + dx = 5; 330 + dy = 5; 331 + invert_images() 332 + end 333 + end 334 + 335 + x = _math.clamp(x, sx, ex) 336 + y = _math.clamp(y, sy, ey) 337 + 338 + -- copy original image back to screen 339 + _lcd:copy(screen_img) 340 + 341 + loops = loops -1 342 + 343 + wait = timer:check(true) --checks timer and updates last time 344 + if wait >= 5 then 345 + wait = 0 346 + elseif wait < 5 then 347 + wait = 5 - wait 348 + end 349 + -- 0 = timeout immediately 350 + -- ( -1 would be never timeout, and >0 is amount of 'ticks' before timeout) 351 + if rb.get_plugin_action(wait) == CANCEL_BUTTON then 352 + break; 353 + end 354 + end 355 + 356 + timer:stop() -- destroys timer, also returns time since last time 357 + 358 + -- leave the screen how we found it 359 + _lcd:copy(screen_img) 360 + end -- image_bounce 361 + 362 + -- draws a gradient using available colors 363 + function draw_gradient(img, x, y, w, h, direction, clrs) 364 + x = x or 1 365 + y = y or 1 366 + w = w or img:width() - x 367 + h = h or img:height() - y 368 + local zstep = 0 369 + local step = 1 370 + if IS_COLOR_TARGET == true then -- Only do this when we're on a color target 371 + local z = 1 372 + local c = 1 373 + clrs = clrs or {255,255,255} 374 + local function gradient_rgb(p, c1, c2) 375 + -- tried squares of difference but blends were very abrupt 376 + local r = c1.r + (p * (c2.r - c1.r) / 10500) 377 + local g = c1.g + (p * (c2.g - c1.g) / 10000) 378 + local b = c1.b + (p * (c2.b - c1.b) / 09999) 379 + return _clr.set(nil, r, g, b) 380 + end 381 + local function check_z() 382 + if z > 10000 and c < #clrs - 1 then 383 + z = 1 384 + c = c + 1 385 + elseif z > 10000 then 386 + z = 10000 387 + end 388 + end 389 + if direction == "V" then 390 + zstep = math.max(1, (10000 / ((w - 1) / (#clrs - 1)) + bit.band(#clrs, 1))) 391 + for i=x, w + x do 392 + check_z() 393 + _draw.vline(img, i, y, h, gradient_rgb(z, clrs[c], clrs[c + 1])) 394 + z = z + zstep 395 + end 396 + else 397 + zstep = math.max(1, (10000 / ((h - 1) / (#clrs - 1)) + bit.band(#clrs, 1))) 398 + for j=y, h + y do 399 + check_z() 400 + _draw.hline(img, x, j, w, gradient_rgb(z, clrs[c], clrs[c + 1])) 401 + z = z + zstep 402 + end 403 + end 404 + else -- not a color target but might be greyscale 405 + local clr = _clr.set(-1) 406 + for i=x, w + x do 407 + for j=y, h + y do 408 + -- Set the pixel at position i, j to the specified color 409 + img:set(i, j, clr) 410 + end 411 + clr = _clr.inc(clr, 1) 412 + end 413 + end 414 + --rb.sleep(1000) 415 + end -- draw_gradient 416 + 417 + function twist(img) 418 + --[[ local fg 419 + if rb.lcd_get_foreground then 420 + fg = rb.lcd_get_foreground() 421 + end]] 422 + 423 + local ims = {} 424 + ims.strip = _img.tile(img, img:width(), _lcd.H + img:height()) 425 + ims.y_init = {img:height(), 1} 426 + ims.y_finl = {1, img:height()} 427 + ims.y_inc = {-2, 4} 428 + ims.y_pos = nil 429 + 430 + -- together define the width of the overall object 431 + local x_off=(_lcd.W/2) 432 + local m = _lcd.W 433 + local z = -m 434 + local zi = 1 435 + 436 + -- angles of rotation for each leaf 437 + local ANGLES = {0, 45, 90, 135, 180, 225, 270, 315} 438 + local elems = #ANGLES 439 + local _XCOORD = {} 440 + 441 + -- color alternates each leaf 442 + local colors = { WHITE, _clr.set(0, 0, 0, 0) } 443 + local c = 0 444 + 445 + -- calculated position of each point in the sine wave(s) 446 + local xs, xe 447 + 448 + --[[--Profiling code 449 + local timer = _timer.start()]] 450 + 451 + for rot = 0, 6000, 4 do 452 + _lcd:clear(BLACK) 453 + 454 + for y=1, _lcd.H do 455 + 456 + local function get_sines() 457 + local sc = m + z 458 + if sc == 0 then 459 + sc = 1 -- prevent divide by 0 460 + elseif sc + z > _lcd.W then 461 + zi = -1 462 + colors[2] = _clr.inc(colors[2], 1, 0, 50, 0) 463 + elseif sc + z < -(_lcd.W) then 464 + zi = 1 465 + colors[1] = _clr.inc(colors[1], -1, 0, 10, 0) 466 + end 467 + if colors[2] == colors[1] then 468 + colors[2] = _clr.inc(colors[2], 1) 469 + end 470 + for j = 1, elems do 471 + _XCOORD[j] = _math.d_sin(y + ANGLES[j] + rot) / sc + x_off 472 + end 473 + _XCOORD[0] = _XCOORD[elems] -- loop table for efficient wrap 474 + end 475 + 476 + get_sines() 477 + for k = 1, elems do 478 + xs = _XCOORD[k] 479 + xe = _XCOORD[(k+1) % elems] 480 + if xs < 1 or xe > _lcd.W then 481 + while xs < 1 or xe > _lcd.W do 482 + m = m + 1 -- shift m in order to scale object min/max 483 + get_sines() 484 + xs = _XCOORD[k] 485 + xe = _XCOORD[(k+1) % elems] 486 + end 487 + end 488 + c = (c % 2) + 1 489 + if xs < xe then 490 + -- defines the direction of leaves & fills them 491 + 492 + _lcd:set(xs, y, colors[c]) 493 + _lcd:set(xe, y, colors[c]) 494 + _lcd:line(xs + 1, y, xe - 1, y, colors[3 - c], true) 495 + end 496 + end 497 + 498 + end 499 + 500 + do -- stripes and shifts image strips; blits it into the colors(1) leaves 501 + local y 502 + local y_col = 1 503 + local w = ims.strip:width() - 1 504 + local h = ims.strip:height() - 1 505 + if ims.y_pos ~= nil then 506 + for i = 1, #ims.y_pos do 507 + ims.y_pos[i] = ims.y_pos[i] + ims.y_inc[i] 508 + 509 + if (ims.y_inc[i] > 0 and ims.y_pos[i] > ims.y_finl[i]) 510 + or (ims.y_inc[i] < 0 and ims.y_pos[i] < ims.y_finl[i]) then 511 + ims.y_pos[i] = ims.y_init[i] 512 + end 513 + end 514 + else 515 + ims.y_pos = {ims.y_init[1], ims.y_init[2]} 516 + end 517 + 518 + for ix = 1, _lcd.W, w do 519 + y_col = y_col + 1 520 + y = ims.y_pos[(y_col % 2) + 1] 521 + if _lcd.DEPTH > 1 then 522 + _lcd:copy(ims.strip, ix, 1, 1, y, w, h, false, _blit.BDEQC, colors[1]) 523 + else 524 + _lcd:copy(ims.strip, ix, 1, 1, y, w, h, false, _blit.BSAND) 525 + end 526 + end 527 + end 528 + 529 + _lcd:update() 530 + z = z + zi 531 + 532 + if rb.get_plugin_action(0) == CANCEL_BUTTON then 533 + break 534 + end 535 + collectgarbage("step") 536 + end 537 + --[[--Profiling code 538 + _print.f("%d", _timer.stop(timer)) 539 + rb.sleep(rb.HZ * 10)]] 540 + end -- twist 541 + 542 + function draw_target(img) 543 + 544 + local clr = _clr.set(0, 0, 0, 0) 545 + 546 + -- make a copy of original screen for restoration 547 + local screen_img = _lcd:duplicate() 548 + 549 + rad_m = math.min(_lcd.W, _lcd.H) 550 + 551 + for s = -_lcd.W /4, 16 do 552 + img:copy(screen_img) 553 + s = math.max(1, math.abs(s)) 554 + for r = 1, rad_m /2 - 10, s do 555 + clr = _clr.inc(clr, 1, r * 5, r * 10, r * 20) 556 + _draw.circle(img, _lcd.CX, _lcd.CY, r, clr) 557 + end 558 + 559 + _lcd:update() 560 + if rb.get_plugin_action( 20) == CANCEL_BUTTON then 561 + z = 16; 562 + break; 563 + end 564 + end 565 + 566 + end -- draw_target 567 + 568 + function draw_sweep(img, cx, cy, radius, color) 569 + local timer = _timer() --creates a new timer saves index 570 + local wait 571 + local x 572 + local y 573 + --make a copy of original screen for restoration 574 + local screen_img = _lcd:duplicate() 575 + _draw.circle(img, cx, cy, radius, color) 576 + for d = 630, 270, - 5 do 577 + if d % 45 == 0 then 578 + img:copy(screen_img) 579 + _draw.circle(img, cx, cy, radius, color) 580 + l = 0 581 + end 582 + x = cx + radius * _math.d_cos(d) / 10000 583 + y = cy + radius * _math.d_sin(d) / 10000 584 + 585 + 586 + _draw.line(img, cx, cy, x, y, color) 587 + l = l + 1 588 + if l > 1 then 589 + x1 = cx + (radius - 1) * _math.d_cos(d + 1) / 10000 590 + y1 = cy + (radius - 1) * _math.d_sin(d + 1) / 10000 591 + _draw_floodfill(img, x1, y1, BLACK, color) 592 + end 593 + _lcd:update() 594 + wait = timer:check(true) --checks timer and updates last time 595 + if wait >= 50 then 596 + wait = 0 597 + elseif wait < 50 then 598 + wait = 50 - wait 599 + end 600 + if rb.get_plugin_action( wait) == CANCEL_BUTTON then 601 + break 602 + end 603 + end 604 + timer:stop() --destroys timer, also returns time since last time 605 + screen_img = nil 606 + end -- draw_sweep 607 + 608 + function rotate_image(img) 609 + local blitop = _blit.BOR 610 + local i = 1 611 + local d = 0 612 + local ximg 613 + local x, y, w, h, xr, yr 614 + 615 + ximg = _img.rotate(img, 45) -- image will be largest at this point 616 + w = ximg:width() 617 + h = ximg:height() 618 + xr = (_lcd.W - w) / 2 619 + yr = (_lcd.H - h) / 2 620 + --make a copy of original screen for restoration 621 + local screen_img -- = _lcd:duplicate() 622 + screen_img =_img.new(w, h) 623 + screen_img :copy(_LCD, 1, 1, xr, yr, w, h) 624 + --_print.f("CW") 625 + 626 + --[[--Profiling code 627 + local timer = _timer.start()]] 628 + 629 + while d >= 0 do 630 + ximg = _img.rotate(img, d) 631 + w = ximg:width() 632 + h = ximg:height() 633 + x = (_lcd.W - w) / 2 634 + y = (_lcd.H - h) / 2 635 + 636 + -- copy our rotated image onto the background 637 + _lcd:copy(ximg, x, y, 1, 1, w, h, false, blitop) 638 + _lcd:update() 639 + --restore the portion of the background we destroyed 640 + _lcd:copy(screen_img, xr, yr, 1, 1) 641 + 642 + if d > 0 and d % 360 == 0 then 643 + _lcd:copy(ximg, x, y, 1, 1, w, h) 644 + _lcd:update() 645 + if i == 1 then i = 0 end 646 + if d == 1440 or i < 0 then 647 + if i < 0 then 648 + i = i - 5 649 + else 650 + i = - 5 651 + end 652 + blitop = _blit.BXOR 653 + --_print.f("CCW") 654 + --rb.sleep(rb.HZ) 655 + else 656 + i = i + 5 657 + --_print.f("CW") 658 + --rb.sleep(rb.HZ) 659 + end 660 + 661 + end 662 + d = d + i 663 + 664 + if rb.get_plugin_action(0) == CANCEL_BUTTON then 665 + break; 666 + end 667 + end 668 + 669 + _lcd:copy(ximg, x, y, 1, 1, w, h) 670 + --[[-- Profiling code 671 + _print.f("%d", _timer.stop(timer)) 672 + rb.sleep(rb.HZ * 10)]] 673 + end -- rotate_image 674 + 675 + -- shows blitting with a mask 676 + function blit_mask(dst) 677 + local timer = _timer() 678 + local r = math.min(_lcd.CX, _lcd.CY) / 5 679 + 680 + local bmask = _img.new(_lcd.W, _lcd.H) 681 + bmask:clear(0) 682 + 683 + _draw.circle_filled(bmask, _lcd.CX, _lcd.CY, r, WHITE) 684 + local color = _clr.set(0, 0, 0 ,0) 685 + for z = 0, 100 do 686 + z = z + timer:check(true) 687 + color = _clr.inc(color, 1, z * 5, z * 10, z * 20) 688 + dst:copy(bmask, 1, 1, 1, 1, nil, nil, false, _blit.BSAND, color) 689 + _lcd:update() 690 + 691 + if rb.get_plugin_action(0) == CANCEL_BUTTON then 692 + break 693 + end 694 + end 695 + end -- blit_mask 696 + 697 + -- draws an X on the screen 698 + function draw_x() 699 + _draw.line(_LCD, 1, 1, _lcd.W, _lcd.H, WHITE) 700 + _draw.line(_LCD, _lcd.W, 1, 1, _lcd.H, WHITE) 701 + 702 + _draw.hline(_LCD, 10, _lcd.CY , _lcd.W - 21, WHITE) 703 + 704 + _draw.vline(_LCD, _lcd.CX, 20 , _lcd.H - 41, WHITE) 705 + 706 + _draw.rect(_LCD, _lcd.CX - 17, _lcd.CY - 17, 34, 34, WHITE) 707 + _lcd:update() 708 + rb.sleep(100) 709 + end -- draw_x 710 + 711 + --fills an image with random colors 712 + function random_img(img) 713 + local min = _clr.set(0, 0, 0, 0) 714 + local max = _clr.set(-1, 255, 255, 255) 715 + math.randomseed(rb.current_tick()) 716 + for x = 1, img:width() do 717 + for y = 1, img:height() do 718 + img:set(x, y, math.random(min, max)) 719 + end 720 + end 721 + end -- random_img 722 + 723 + function rainbow_img(img) 724 + --draw a gradient using available colors 725 + if IS_COLOR_TARGET == true then 726 + --R O Y G B I V 727 + clrs = { 728 + {r = 255, g = 255, b = 255}, -- white 729 + {r = 000, g = 000, b = 000}, -- black 730 + {r = 200, g = 000, b = 000}, -- red 731 + {r = 255, g = 000, b = 000}, -- red 732 + {r = 255, g = 100, b = 033}, -- orange 733 + {r = 255, g = 127, b = 000}, -- orange 734 + {r = 255, g = 200, b = 033}, -- yellow 735 + {r = 255, g = 255, b = 000}, -- yellow 736 + {r = 050, g = 255, b = 000}, -- green 737 + {r = 000, g = 125, b = 125}, -- green 738 + {r = 000, g = 000, b = 255}, -- blue 739 + {r = 033, g = 025, b = 200}, -- indigo 740 + {r = 075, g = 000, b = 150}, -- indigo 741 + {r = 127, g = 000, b = 150}, -- violet 742 + {r = 150, g = 000, b = 255}, -- violet 743 + {r = 255, g = 255, b = 255}, -- white 744 + {r = 000, g = 000, b = 000}, -- black 745 + } 746 + else 747 + end 748 + draw_gradient(img, 1, 1, nil, nil, "V", clrs) 749 + end -- rainbow_img 750 + 751 + -- draws a rounded rectangle with text 752 + function rock_lua() 753 + local res, w, h = _lcd:text_extent("W", rb.FONT_UI) 754 + w = _lcd.W - 10 755 + h = h + 4 756 + _draw.rounded_rect_filled(_LCD, 5, 5, w, h, 15, WHITE) 757 + _draw_text(_LCD, 5, 5, w, h, nil, BLACK, "ROCKlua!") 758 + _lcd:update() 759 + rb.sleep(100) 760 + end -- rock_lua 761 + 762 + -- draws a rounded rectangle with long text 763 + function long_text() 764 + local txt = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890" 765 + local res, w, h = _lcd:text_extent(txt, rb.FONT_UI) 766 + local resp, wp, hp = _lcd:text_extent(" ", rb.FONT_UI) 767 + local wait = 0 768 + w = w + wp * 3 769 + h = h + 4 770 + local img = _img.new(w + 1, h) 771 + img:clear(BLACK) 772 + _draw.rounded_rect_filled(img, 1, 1, w, h, 15, WHITE) 773 + _draw_text(img, 1, 2, nil, nil, nil, BLACK, txt) 774 + 775 + for p = -w + 1, w - 1 do 776 + wait = 0 777 + p = math.abs(p) 778 + _lcd:copy(img, 1, _lcd.H - h, w - p, 1) 779 + _lcd:update() 780 + if p == 0 or w - p == 1 then wait = 100; rb.sleep(50) end 781 + if rb.get_plugin_action(wait) == CANCEL_BUTTON then 782 + break 783 + end 784 + end 785 + 786 + end -- long_text 787 + 788 + -- creates or loads an image to use as logo 789 + function get_logo() 790 + local logo_img = _img.load("/pix.bmp") --loads the previously saved image (if we saved it before) 791 + 792 + --create a logo if an image wasn't saved previously 793 + if(not logo_img) then 794 + logo_img = create_logo() 795 + end 796 + 797 + --fallback 798 + if(not logo_img) then 799 + -- Load a BMP file in the variable backdrop 800 + local base = "/.rockbox/icons/" 801 + local backdrop = _img.load("/image.bmp") --user supplied image 802 + or _img.load(base .. "tango_small_viewers.bmp") 803 + or _img.load(base .. "tango_small_viewers_mono.bmp") 804 + or _img.load(base .. "tango_small_mono.bmp") 805 + or _img.load(base .. "tango_icons.16x16.bmp") 806 + or _img.load(base .. "tango_icons_viewers.16x16.bmp") 807 + or _img.load(base .. "viewers.bmp") 808 + or _img.load(base .. "viewers.6x8x1.bmp") 809 + or _img.load(base .. "viewers.6x8x2.bmp") 810 + or _img.load(base .. "viewers.6x8x10.bmp") 811 + or _img.load(base .. "viewers.6x8x16.bmp") 812 + logo_img = backdrop 813 + end 814 + return logo_img 815 + end -- get_logo 816 + 817 + -- uses print_table to display a menu 818 + function main_menu() 819 + 820 + local mt = { 821 + [1] = "Rocklua RLI Example", 822 + [2] = "The X", 823 + [3] = "Blit Mask", 824 + [4] = "Target", 825 + [5] = "Sweep", 826 + [6] = "Bouncing Ball (olive)", 827 + [7] = "The Twist", 828 + [8] = "Image Rotation", 829 + [9] = "Long Text", 830 + [10] = "Rainbow Image", 831 + [11] = "Random Image", 832 + [12] = "Clear Screen", 833 + [13] = "Save Screen", 834 + [14] = "Exit" 835 + } 836 + local ft = { 837 + [0] = exit_now, --if user cancels do this function 838 + [1] = function(TITLE) return true end, -- shouldn't happen title occupies this slot 839 + [2] = function(THE_X) draw_x() end, 840 + [3] = function(BLITM) blit_mask(_lcd()) end, 841 + [4] = function(TARGT) draw_target(_lcd()) end, 842 + [5] = function(SWEEP) 843 + local r = math.min(_lcd.CX, _lcd.CY) - 20 844 + draw_sweep(_lcd(), _lcd.CX, _lcd.CY, r, _clr.set(-1, 0, 255, 0)) 845 + end, 846 + [6] = function(BOUNC) bounce_image(create_ball()) end, 847 + [7] = function(TWIST) twist(get_logo()) end, 848 + [8] = function(ROTAT) rotate_image(get_logo()) end, 849 + [9] = long_text, 850 + [10] = function(RAINB) 851 + rainbow_img(_lcd()); _lcd:update(); rb.sleep(rb.HZ) 852 + end, 853 + [11] = function(RANDM) 854 + random_img(_lcd()); _lcd:update(); rb.sleep(rb.HZ) 855 + end, 856 + [12] = function(CLEAR) _lcd:clear(BLACK); rock_lua() end, 857 + [13] = function(SAVEI) _LCD:invert(); _img_save(_LCD, "/rocklua.bmp") end, 858 + [14] = function(EXIT_) return true end 859 + } 860 + 861 + if _lcd.DEPTH < 2 then 862 + table.remove(mt, 10) 863 + table.remove(ft, 10) 864 + end 865 + 866 + print_menu(mt, ft) 867 + 868 + end 869 + -------------------------------------------------------------------------------- 870 + function exit_now() 871 + _lcd:update() 872 + _lcd:splashf(rb.HZ * 5, "ran for %d seconds", _timer.stop("main") / rb.HZ) 873 + os.exit() 874 + end -- exit_now 875 + -------------------------------------------------------------------------------- 876 + 877 + --MAIN PROGRAM------------------------------------------------------------------ 878 + _timer("main") -- keep track of how long the program ran 879 + 880 + -- Clear the screen 881 + _lcd:clear(BLACK) 882 + 883 + if _lcd.DEPTH > 1 then 884 + --draw a gradient using available colors 885 + if IS_COLOR_TARGET == true then 886 + clrs = { 887 + {r = 255, g = 000, b = 000}, -- red 888 + {r = 000, g = 255, b = 000}, -- green 889 + {r = 000, g = 000, b = 255}, -- blue 890 + } 891 + else 892 + end 893 + local w = bit.rshift(_lcd.W, 2) 894 + local h = bit.rshift(_lcd.H, 2) 895 + draw_gradient(_lcd(), (_lcd.W - w)/2 - 1, (_lcd.H - h)/3 - 1, w, h, "H", clrs) 896 + _lcd:update() 897 + rb.sleep(rb.HZ) 898 + end 899 + 900 + do 901 + local img = _img.load("/rocklua.bmp") 902 + if not img then 903 + rock_lua() 904 + else 905 + _lcd:image(img) 906 + end 907 + end 908 + _lcd:update() 909 + rb.sleep(rb.HZ / 2) 910 + 911 + if rb.cpu_boost then rb.cpu_boost(true) end 912 + 913 + main_menu() 914 + 915 + if rb.cpu_boost then rb.cpu_boost(false) end 916 + 917 + exit_now() 918 + 919 + -- For a reference list of all functions available, see apps/plugins/lua/rocklib.c (and apps/plugin.h)