summaryrefslogtreecommitdiff
path: root/apps/plugins/lua_scripts/stars.lua
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/lua_scripts/stars.lua')
-rw-r--r--apps/plugins/lua_scripts/stars.lua256
1 files changed, 256 insertions, 0 deletions
diff --git a/apps/plugins/lua_scripts/stars.lua b/apps/plugins/lua_scripts/stars.lua
new file mode 100644
index 0000000000..14fae0c4b7
--- /dev/null
+++ b/apps/plugins/lua_scripts/stars.lua
@@ -0,0 +1,256 @@
1--[[
2 __________ __ ___.
3 Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 \/ \/ \/ \/ \/
8 $Id$
9
10 Copyright (C) 2024 William Wilgus
11 This program is free software; you can redistribute it and/or
12 modify it under the terms of the GNU General Public License
13 as published by the Free Software Foundation; either version 2
14 of the License, or (at your option) any later version.
15 This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 KIND, either express or implied.
17]]--
18--https://nullprogram.com/blog/2011/06/13/ [Infinite Parallax Starfield]
19
20-- Imports
21local _clr = require("color") -- clrset, clrinc provides device independent colors
22local _lcd = require("lcd") -- lcd helper functions
23local _draw = require("draw") -- draw all the things (primitives)
24local _poly = require("draw_poly") -- vector drawing with tables of coords
25require("actions")
26--'CONSTANTS' (in lua there really is no such thing as all vars are mutable)
27--------------------------------------------------------
28--colors for fg/bg ------------------------
29--first number of each quad is fallback for monochrome devices, excluded columns default to 0
30local WHITE = _clr.set(-1, 255, 255, 255)
31local BLACK = _clr.set(0, 0, 0, 0)
32local RED = _clr.set(WHITE, 100)
33local GREEN = _clr.set(WHITE, 0, 100)
34local BGREEN = _clr.set(WHITE, 0, 255)
35local BLUE = _clr.set(WHITE, 0, 0, 100)
36
37local STAR_SEED = 0x9d2c5680;
38local STAR_TILE_SIZE = math.max(rb.LCD_WIDTH, rb.LCD_HEIGHT) * 4;
39local bxor, band, rshift, lshift, arshift = bit.bxor, bit.band, bit.rshift, bit.lshift, bit.arshift
40local random, randomseed = math.random, math.randomseed
41local start_x, start_y, start_z
42
43-- load users coords from file if it exists
44local fname = rb.PLUGIN_DATA_DIR .. "/stars.pos"
45file = io.open(fname, "r")
46if file then
47 local v = 0
48 for line in file:lines() do
49 v = v + 1
50 if v == 1 then
51 start_x = tonumber(line) or 0
52 elseif v == 2 then
53 start_y = tonumber(line) or 0
54 elseif v == 3 then
55 start_z = tonumber(line) or 0
56 else
57 break;
58 end
59 end
60 io.close( file )
61end
62
63-- Robert Jenkins' 96 bit Mix Function.
64local function mix (a, b, c)
65 a=a-b; a=a-c; a=bxor(a, (rshift(c, 13)));
66 b=b-c; b=b-a; b=bxor(b, (lshift(a, 8)));
67 c=c-a; c=c-b; c=bxor(c, (rshift(b, 13)));
68 a=a-b; a=a-c; a=bxor(a, (rshift(c, 12)));
69 b=b-c; b=b-a; b=bxor(b, (lshift(a, 16)));
70 c=c-a; c=c-b; c=bxor(c, (rshift(b, 5)));
71 a=a-b; a=a-c; a=bxor(a, (rshift(c, 3)));
72 b=b-c; b=b-a; b=bxor(b, (lshift(a, 10)));
73 c=c-a; c=c-b; c=bxor(c, (rshift(b, 15)));
74
75 return c
76end
77
78-- given 32 bit number returns a table of 8 nibbles (4 bits)
79local function s_bytes_nib(bits, value)
80 -- bits must be multiples of 8 (sizeof byte)
81 local bbuffer = {}
82 local byte
83 local nbytes = bit.rshift(bits, 3)
84 for b = 1, nbytes do
85 if value > 0 then
86 byte = value % 256
87 value = (value - byte) / 256
88 else
89 byte = 0
90 end
91 bbuffer[#bbuffer + 1] = band(byte,0xF)
92 bbuffer[#bbuffer + 1] = band(rshift(byte, 2), 0xF)
93 end
94 return bbuffer
95end
96
97--[[ given table t and total elems desired uses random elems of t
98 and random numbers between 1 and max_v if #t < total_elems]]
99function randomize_table(t, total_elems, max_v)
100 local rand_t = {}
101 local i = 1
102 repeat
103 local v = t[random(1, total_elems)]
104 if v then
105 rand_t[i] = v
106 else
107 rand_t[i] = random(1, max_v)
108 end
109 i = i + 1
110 until i > total_elems
111 return rand_t
112end
113
114local function drawship(img, x, y, color, ship_t)
115 --_poly.polyline(img, x, y, ship_t, color, true, true)
116 _poly.polygon(img, x, y, ship_t, color, BLACK, true)
117end
118
119local function draw_astroid(img, x, y, size, shape, color, scale_x, scale_y)
120 --the random number generator gets seeded with the hash so we get the same figure each time
121 randomseed(shape)
122 -- we also use the 4 bytes of the hash as 4 coord pairs and randomly generate 8 more (16) half the size (8)
123 local uniq_t = randomize_table(s_bytes_nib(32, shape), 16, 8)
124 _poly.polyline(img, x, y, uniq_t, color, true, true, scale_x or 1, scale_y or 1)
125 --_poly.polygon(img, x, y, uniq_t, color, color, true, scale_x or 1, scale_y or 1) --filled figures
126end
127
128local function drawStars (img, xoff, yoff, starscale, color, scale_x, scale_y)
129 local size = STAR_TILE_SIZE / starscale
130 local s_x, s_y = scale_x, scale_y
131 local w, h = rb.LCD_WIDTH, rb.LCD_HEIGHT
132
133 -- Top-left tile's top-left position
134 local sx = ((xoff - w/2) / size) * size - size;
135 local sy = ((yoff - h/2) / size) * size - size;
136
137 --Draw each tile currently in view.
138 for i = sx, w + sx + size*3, size do
139 for j = sy, h + sy + size*3, size do
140 local hash = mix(STAR_SEED, (i / size), (j / size))
141 for n = 0, 2 do
142 local px = (hash % size) + (i - xoff);
143 hash = arshift(hash, 3)
144
145 local py = (hash % size) + (j - yoff);
146 hash = arshift(hash, 3)
147
148 if px > 0 and px < w and py > 0 and py < h then
149 if n > 0 and starscale < 5 then
150 draw_astroid(img, px, py, n, hash, color, s_x, s_y)
151 else
152 if scale_x > 1 then
153 img:set(px, py, color)
154 img:set(px + 1, py, color)
155 elseif scale_y > 1 then
156 img:set(px, py, color)
157 img:set(px, py + 1, color)
158 else
159 img:set(px, py, color)
160 end
161 end
162 end
163 end
164 end
165 end
166end
167
168do
169 local act = rb.actions
170 local quit = false
171 local last_action = 0
172 local x,y,z = start_x or 0, start_y or 0, start_z or 8
173 local x_fast = rb.LCD_WIDTH / 4
174 local y_fast = rb.LCD_HEIGHT / 4
175 local ship_x = (rb.LCD_WIDTH - 0xF) / 2
176 local ship_y = rb.LCD_HEIGHT - (rb.LCD_HEIGHT / 3)
177 local scale_x, scale_y = 1, 1
178 -- vector draw the ship points for each direction (<>^v)
179 local ship_lt_t = {0,7, 15,0, 9,7, 15,15, 0,7}
180 local ship_rt_t = {0,0, 5,7, 0,15, 15,7, 0,0}
181 local ship_up_t = {0,15, 7,0, 15,15, 7,9, 0,15}
182 local ship_dn_t = {0,0, 7,15, 15,0, 7,5, 0,0}
183 local ship_t = ship_up_t
184
185 function action_event(action)
186 if action == act.PLA_EXIT or action == act.PLA_CANCEL then
187 quit = true
188 start_x, start_y, start_z = x, y, z
189 elseif action == act.PLA_RIGHT_REPEAT then
190 x = x + x_fast
191 scale_x = scale_x + 1
192 scale_y = 1
193 elseif action == act.PLA_LEFT_REPEAT then
194 x = x - x_fast
195 scale_x = scale_x + 1
196 scale_y = 1
197 elseif action == act.PLA_UP_REPEAT then
198 y = y - y_fast
199 scale_y = scale_y + 1
200 scale_x = 1
201 elseif action == act.PLA_DOWN_REPEAT then
202 y = y + y_fast
203 scale_y = scale_y + 1
204 scale_x = 1
205 elseif action == act.PLA_RIGHT then
206 x = x + 1
207 ship_t = ship_rt_t
208 elseif action == act.PLA_LEFT then
209 x = x - 1
210 ship_t = ship_lt_t
211 elseif action == act.PLA_UP then
212 y = y - 1
213 ship_t = ship_up_t
214 elseif action == act.PLA_DOWN then
215 y = y + 1
216 ship_t = ship_dn_t
217 elseif action == act.PLA_SELECT then
218 z = z + 4
219 if z > 16 then z = 0 end
220 elseif action == act.ACTION_NONE then
221 scale_x = 1
222 scale_y = 1
223 end
224
225 _lcd:clear(BLACK)
226 for i = 0, z, 4 do
227 drawStars(_LCD, x, y, i+1, RED, scale_x, scale_y)
228 drawStars(_LCD, x, y, i+2, GREEN, scale_x, scale_y)
229 drawStars(_LCD, x, y, i+3, BLUE, scale_x, scale_y)
230 drawStars(_LCD, x, y, i+4, WHITE, scale_x, scale_y)
231 end
232 drawship(_LCD, ship_x, ship_y, BGREEN, ship_t)
233 _lcd:update()
234
235 last_action = action
236 end
237
238 function action_set_quit(bQuit)
239 quit = bQuit
240 end
241
242 function action_quit()
243 return quit
244 end
245end
246
247action_event(rb.actions.ACTION_NONE) -- we can call this now but not after registering..
248local eva = rockev.register("action", action_event)
249
250while not action_quit() do rb.sleep(rb.HZ) end
251
252if start_x and start_y then
253 file = io.open(fname, "w")
254 file:write(start_x, "\n", start_y, "\n", start_z, "\n")
255 io.close( file )
256end