diff options
author | William Wilgus <me.theuser@yahoo.com> | 2019-08-04 09:48:09 -0500 |
---|---|---|
committer | William Wilgus <me.theuser@yahoo.com> | 2019-08-04 16:57:02 +0200 |
commit | f85df30e3e7da55c6880a321b3d8dc737f7af5b2 (patch) | |
tree | c778d743feef43162f53df9c1b642912822f664e /apps/plugins/lua_scripts | |
parent | 4209c097705ce474f955bf1d73ca6ccf1ac6786a (diff) | |
download | rockbox-f85df30e3e7da55c6880a321b3d8dc737f7af5b2.tar.gz rockbox-f85df30e3e7da55c6880a321b3d8dc737f7af5b2.zip |
lua add rlimg.lua example script split large includes to separate files
Change-Id: I67cac5bc4ce5525ab30abf9443f6cc1a33190512
Diffstat (limited to 'apps/plugins/lua_scripts')
-rwxr-xr-x | apps/plugins/lua_scripts/rlimg.lua | 919 |
1 files changed, 919 insertions, 0 deletions
diff --git a/apps/plugins/lua_scripts/rlimg.lua b/apps/plugins/lua_scripts/rlimg.lua new file mode 100755 index 0000000000..801d0c5fac --- /dev/null +++ b/apps/plugins/lua_scripts/rlimg.lua | |||
@@ -0,0 +1,919 @@ | |||
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) | ||