SHOW:
|
|
- or go back to the newest paste.
1 | grid = {}; | |
2 | iodispatch = {}; | |
3 | vspacing = 4; | |
4 | hspacing = 4; | |
5 | cursor = 0; | |
6 | cellcount = 0; | |
7 | pageofs = 0; | |
8 | ||
9 | vertex_shader = [[ | |
10 | uniform int n_ticks; | |
11 | ||
12 | void main(void) | |
13 | { | |
14 | gl_TexCoord[0] = gl_MultiTexCoord0; | |
15 | gl_TexCoord[0].s = gl_TexCoord[0].s + fract(n_ticks / 64.0); | |
16 | gl_TexCoord[0].t = gl_TexCoord[0].t + fract(n_ticks / 64.0); | |
17 | gl_Position = ftransform(); | |
18 | }]]; | |
19 | ||
20 | fragment_shader = [[ | |
21 | #version 120 | |
22 | uniform sampler2D tex; | |
23 | ||
24 | void main() { | |
25 | vec4 color = texture2D(tex, gl_TexCoord[0].st); | |
26 | gl_FragColor = color; | |
27 | } | |
28 | ]]; | |
29 | ||
30 | local function ledconfig_iofun(iotbl) | |
31 | local restbl = keyconfig:match(iotbl); | |
32 | ||
33 | if (iotbl.active and restbl and restbl[1] and | |
34 | ledconfig:input(restbl[1]) == true) then | |
35 | gridle_input = keyconfig.iofun; | |
36 | end | |
37 | end | |
38 | ||
39 | function gridle() | |
40 | system_load("scripts/keyconf.lua")(); | |
41 | system_load("scripts/keyconf_mame.lua")(); | |
42 | system_load("scripts/ledconf.lua")(); | |
43 | ||
44 | games = list_games( {} ); | |
45 | if (#games == 0) then | |
46 | error "No games found"; | |
47 | shutdown(); | |
48 | end | |
49 | ||
50 | keyconfig = keyconf_create(1, { | |
51 | "rMENU_ESCAPE", "rMENU_LEFT", "rMENU_RIGHT", "rMENU_UP", | |
52 | "rMENU_DOWN", "rMENU_SELECT", "rGROW_ICONS", "rSHRINK_ICONS" } ); | |
53 | keyconfig.iofun = gridle_input; | |
54 | if (keyconfig.active == false) then | |
55 | gridle_input = function(iotbl) -- keyconfig io function hook | |
56 | if (keyconfig:input(iotbl) == true) then | |
57 | keyconf_tomame(keyconfig, "_mame/cfg/default.cfg"); | |
58 | ||
59 | ledconfig = ledconf_create( keyconfig:labels() ); | |
60 | if (ledconfig.active == false) then | |
61 | gridle_input = ledconfig_iofun; | |
62 | else -- no LED controller present, or LED configuration already exists | |
63 | gridle_input = keyconfig.iofun; | |
64 | end | |
65 | end | |
66 | end | |
67 | else | |
68 | ledconfig = ledconf_create( keyconfig:labels() ); | |
69 | if (ledconfig.active == false) then | |
70 | gridle_input = ledconf_iofun; | |
71 | end | |
72 | end | |
73 | ||
74 | iodispatch["GROW_ICONS"] = function(iotbl) resize_grid(16); end | |
75 | iodispatch["SHRINK_ICONS"] = function(iotbl) resize_grid(-16); end | |
76 | iodispatch["MENU_UP"] = function(iotbl) play_sample("click.wav"); move_cursor( -1 * ncw); end | |
77 | iodispatch["MENU_DOWN"] = function(iotbl) play_sample("click.wav"); move_cursor( ncw ); end | |
78 | iodispatch["MENU_LEFT"] = function(iotbl) play_sample("click.wav"); move_cursor( -1 ); end | |
79 | iodispatch["MENU_RIGHT"] = function(iotbl) play_sample("click.wav"); move_cursor( 1 ); end | |
80 | iodispatch["MENU_ESCAPE"] = function(iotbl) shutdown(); end | |
81 | iodispatch["MENU_SELECT"] = function(iotbl) if (games[cursor + pageofs + 1]) then | |
82 | launch_target( games[cursor + pageofs + 1].title, LAUNCH_EXTERNAL); end end | |
83 | ||
84 | build_grid(128, 128); | |
85 | ||
86 | switch_default_texmode( TEX_REPEAT, TEX_REPEAT ); | |
87 | bgimage = load_image("background.png"); | |
88 | resize_image(bgimage, VRESW, VRESH); | |
89 | image_scale_txcos(bgimage, VRESW / 32, VRESH / 32); | |
90 | image_program(bgimage, vertex_shader, fragment_shader); | |
91 | ||
92 | show_image(bgimage); | |
93 | switch_default_texmode( TEX_CLAMP, TEX_CLAMP ); | |
94 | end | |
95 | ||
96 | function cell_coords(x, y) | |
97 | return (0.5 * borderw) + x * (cell_width + hspacing), (0.5 * borderh) + y * (cell_height + vspacing); | |
98 | end | |
99 | ||
100 | function blend_gridcell(val, dt) | |
101 | local cursor_row = math.floor(cursor / ncw); | |
102 | gridcell_vid = grid[ cursor_row ][ cursor - cursor_row * ncw ]; | |
103 | ||
104 | if (gridcell_vid) then | |
105 | instant_image_transform(gridcell_vid); | |
106 | blend_image(gridcell_vid, val, dt); | |
107 | end | |
108 | end | |
109 | ||
110 | function resize_grid(step) | |
111 | local new_cellw = cell_width; local new_cellh = cell_width; | |
112 | ||
113 | -- find the next grid size that would involve a density change | |
114 | repeat | |
115 | new_cellw = new_cellw + step; | |
116 | until math.floor(VRESW / (new_cellw + hspacing)) ~= ncw; | |
117 | ||
118 | repeat | |
119 | new_cellh = new_cellh + step; | |
120 | until math.floor(VRESH / (new_cellh + vspacing)) ~= nch; | |
121 | ||
122 | -- safety checks | |
123 | if (new_cellw < 64 or new_cellw > VRESW * 0.75) then return; end | |
124 | if (new_cellh < 64 or new_cellh > VRESH * 0.75) then return; end | |
125 | ||
126 | cell_width = new_cellw; | |
127 | cell_height = new_cellh; | |
128 | ||
129 | local currgame = pageofs + cursor; | |
130 | local new_ncc = math.floor( VRESW / (new_cellw + hspacing) ) * math.floor( VRESH / (new_cellh + vspacing) ); | |
131 | pageofs = math.floor( currgame / new_ncc ) * new_ncc; | |
132 | cursor = currgame - pageofs; | |
133 | if (cursor < 0) then cursor = 0; end | |
134 | ||
135 | -- remove the old grid | |
136 | erase_grid(true); | |
137 | build_grid(cell_width, cell_height); | |
138 | end | |
139 | ||
140 | function move_cursor( ofs ) | |
141 | blend_gridcell(0.3, 10); | |
142 | local pageofs_cur = pageofs; | |
143 | cursor = cursor + ofs; | |
144 | ||
145 | -- paging calculations | |
146 | if (ofs > 0) then -- right/forward | |
147 | if (cursor >= ncc) then -- move right or "forward" | |
148 | cursor = cursor - ncc; | |
149 | pageofs_cur = pageofs_cur + ncc; | |
150 | end | |
151 | ||
152 | -- wrap around on overflow | |
153 | if (pageofs_cur + cursor >= #games) then | |
154 | pageofs_cur = 0; | |
155 | cursor = 0; | |
156 | end | |
157 | elseif (ofs < 0) then -- left/backward | |
158 | if (cursor < 0) then -- step back a page | |
159 | pageofs_cur = pageofs_cur - ncc; | |
160 | cursor = ncc - ( -1 * cursor); | |
161 | ||
162 | if (pageofs_cur < 0) then -- wrap page around | |
163 | pageofs_cur = math.floor(#games / ncc) * ncc; | |
164 | end | |
165 | ||
166 | if (cursor < 0 or cursor >= #games - pageofs_cur) then | |
167 | cursor = #games - pageofs_cur - 1; | |
168 | end | |
169 | end | |
170 | end | |
171 | ||
172 | local x,y = cell_coords(math.floor(cursor % ncw), math.floor(cursor / ncw)); | |
173 | ||
174 | -- reload images of the page has changed | |
175 | if (pageofs_cur ~= pageofs) then | |
176 | erase_grid(false); | |
177 | pageofs = pageofs_cur; | |
178 | build_grid(cell_width, cell_height); | |
179 | end | |
180 | ||
181 | blend_gridcell(1.0, 10); | |
182 | local game = games[cursor + pageofs + 1]; | |
183 | setname = game and game.setname or nil; | |
184 | ||
185 | if (movievid) then | |
186 | expire_image(movievid, 40); | |
187 | blend_image(movievid, 0.0, 40); | |
188 | audio_gain(movieaid, 0.0, 40); | |
189 | end | |
190 | ||
191 | if (game and ledconfig) then | |
192 | ledconfig:toggle(game.players, game.buttons); | |
193 | end | |
194 | ||
195 | -- look for a movie, if one exists, enable a timer that we'll check for later | |
196 | if (setname and resource( "movies/" .. setname .. ".avi")) then | |
197 | movievid, movieaid = load_movie( "movies/" .. setname .. ".avi" ); | |
198 | if (movievid and movieaid and movievid ~= BADID and movieaid ~= BADID) then | |
199 | audio_gain(movieaid, 0.0); | |
200 | move_image(movievid, x, y); | |
201 | hide_image(movievid); | |
202 | order_image(movievid, 3); | |
203 | resize_image(movievid, cell_width, cell_height); | |
204 | movietimer = 10; | |
205 | end | |
206 | else | |
207 | moviefile = ""; | |
208 | movietimer = nil; | |
209 | end | |
210 | ||
211 | end | |
212 | ||
213 | function get_image(romset) | |
214 | local rvid = BADID; | |
215 | ||
216 | if resource("screenshots/" .. romset .. ".png") then | |
217 | rvid = load_image("screenshots/" .. romset .. ".png"); | |
218 | end | |
219 | ||
220 | if (rvid == BADID) then | |
221 | rvid = render_text( [[\#000088\ffonts/default.ttf,96 ]] .. romset ); | |
222 | end | |
223 | ||
224 | return rvid; | |
225 | end | |
226 | ||
227 | function erase_grid(rebuild) | |
228 | cellcount = 0; | |
229 | ||
230 | for row=0, nch-1 do | |
231 | for col=0, ncw-1 do | |
232 | if (grid[row][col]) then | |
233 | ||
234 | if (rebuild) then | |
235 | delete_image(grid[row][col]); | |
236 | else | |
237 | local delay = 10 + math.random(10, 30); | |
238 | local x, y = cell_coords(row, col); | |
239 | expire_image(grid[row][col], delay); | |
240 | rotate_image(grid[row][col], 270.0, delay); | |
241 | scale_image(grid[row][col], 0.01, 0.01, delay); | |
242 | end | |
243 | ||
244 | grid[row][col] = nil; | |
245 | end | |
246 | end | |
247 | end | |
248 | ||
249 | end | |
250 | ||
251 | function gridle_clock_pulse() | |
252 | if (movietimer) then | |
253 | movietimer = movietimer - 1; | |
254 | if (movietimer <= 0) then | |
255 | play_movie(movievid); | |
256 | blend_image(movievid, 1.0, 10); | |
257 | audio_gain(movieaid, 1.0, 40); | |
258 | movietimer = nil; | |
259 | end | |
260 | end | |
261 | end | |
262 | ||
263 | function build_grid(width, height) | |
264 | -- figure out how many full cells we can fit with the current resolution | |
265 | ncw = math.floor(VRESW / (width + hspacing)); | |
266 | nch = math.floor(VRESH / (height + vspacing)); | |
267 | ncc = ncw * nch; | |
268 | cell_width = width; | |
269 | cell_height = height; | |
270 | ||
271 | -- figure out how much "empty" space we'll have to pad with | |
272 | borderw = VRESW % (width + hspacing); | |
273 | borderh = VRESH % (height + vspacing); | |
274 | ||
275 | for row=0, nch-1 do | |
276 | grid[row] = {}; | |
277 | for col=0, ncw-1 do | |
278 | local gameno = (row * ncw + col + pageofs + 1); -- games is 1 indexed | |
279 | if (games[gameno] == nil) then break; end | |
280 | local vid = get_image(games[gameno]["setname"]); | |
281 | resize_image(vid, cell_width, cell_height); | |
282 | move_image(vid,cell_coords(col, row)); | |
283 | order_image(vid, 2); | |
284 | blend_image(vid, 0.3); | |
285 | -- | |
286 | local whitebg = fill_surface(cell_width, cell_height, 255, 255, 255); | |
287 | order_image(whitebg, 1); | |
288 | show_image(whitebg); | |
289 | link_image(whitebg, vid); | |
290 | image_mask_clear(whitebg, MASK_SCALE); | |
291 | image_mask_clear(whitebg, MASK_ORIENTATION); | |
292 | image_mask_clear(whitebg, MASK_OPACITY); | |
293 | ||
294 | grid[row][col] = vid; | |
295 | cellcount = cellcount + 1; | |
296 | end | |
297 | end | |
298 | ||
299 | move_cursor(0); | |
300 | end | |
301 | ||
302 | function gridle_input(iotbl) | |
303 | local restbl = keyconfig:match(iotbl); | |
304 | if (restbl and iotbl.active) then | |
305 | for ind,val in pairs(restbl) do | |
306 | if (iodispatch[val]) then | |
307 | iodispatch[val](restbl); | |
308 | end | |
309 | end | |
310 | end | |
311 | end |