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 |