var $: (selector:string)=>HTMLElement = document.querySelector.bind(document); declare namespace Module { var noInitialRun: boolean; // Undocumented methods / attributes var canvas: HTMLElement; function setStatus(status: string): void; function monitorRunDependencies(left: number): void; function callMain(): void; } declare namespace FS { function writeFile(path: string, data: ArrayBufferView | string, opts?: {encoding?: string; flags?: string}): void; } namespace xsystem35 { export const Font = { url: 'fonts/MTLc3m.ttf', fname: 'MTLc3m.ttf'}; export const xsys35rc = [ 'font_device: ttf', 'ttfont_mincho: ' + Font.fname, 'ttfont_gothic: ' + Font.fname, '' ].join('\n'); export var cdPlayer: CDPlayer; export var shell: System35Shell; } class System35Shell { private imageLoader: ImageLoader; status: HTMLElement = document.getElementById('status'); private zoom:ZoomManager; constructor() { this.imageLoader = new ImageLoader(this); this.setStatus('Downloading...'); window.onerror = () => { this.setStatus('Exception thrown, see JavaScript console'); this.setStatus = (text: string) => { if (text) Module.printErr('[post-exception status] ' + text); }; }; // Initialize the Module object Module.print = Module.printErr = console.log.bind(console); Module.canvas = document.getElementById('canvas'); Module.noInitialRun = true; Module.setStatus = this.setStatus.bind(this); Module.preRun = [ function loadFont() { FS.createPreloadedFile('/', xsystem35.Font.fname, xsystem35.Font.url, true, false); }, function prepareSaveDir() { FS.mkdir('/save'); FS.mount(IDBFS, {}, '/save'); Module.addRunDependency('syncfs'); FS.syncfs(true, (err) => { Module.removeRunDependency('syncfs') }); } ]; xsystem35.cdPlayer = new CDPlayer(this.imageLoader); this.zoom = new ZoomManager(); } setStatus(text: string) { console.log(text); this.status.innerHTML = text; } windowSizeChanged() { this.zoom.handleZoom(); } private fsyncTimer: number; syncfs(fname: string) { window.clearTimeout(this.fsyncTimer); this.fsyncTimer = window.setTimeout(() => { FS.syncfs(false, (err) => { if (err) console.log("FS.syncfs error: ", err); }); }, 100); } } class CDPlayer { audio = $('audio'); private blobs: Blob[]; private currentTrack: number; constructor(private imageLoader:ImageLoader) { this.blobs = []; } play(track:number, loop:number) { this.currentTrack = track; if (this.blobs[track]) { this.startPlayback(this.blobs[track], loop); return; } this.imageLoader.getCDDA(track, (blob) => { this.blobs[track] = blob; this.startPlayback(blob, loop); }); } stop() { this.audio.pause(); this.currentTrack = null; } getPosition(): number { if (!this.currentTrack) return 0; var time = Math.round(this.audio.currentTime * 75); return this.currentTrack | time << 8; } private startPlayback(blob:Blob, loop:number) { this.audio.setAttribute('src', URL.createObjectURL(blob)); this.audio.loop = (loop != 0); this.audio.load(); this.audio.play(); } } class ZoomManager { private canvas: HTMLCanvasElement; private zoomSelect: HTMLInputElement; private smoothingCheckbox: HTMLInputElement; constructor() { this.canvas = $('#canvas'); this.zoomSelect = $('#zoom'); this.zoomSelect.addEventListener('change', this.handleZoom.bind(this)); this.zoomSelect.value = localStorage.getItem('zoom'); this.smoothingCheckbox = $('#smoothing'); this.smoothingCheckbox.addEventListener('change', this.handleSmoothing.bind(this)); if (localStorage.getItem('smoothing') == 'false') { this.smoothingCheckbox.checked = false; this.handleSmoothing(); } } handleZoom() { var value = this.zoomSelect.value; localStorage.setItem('zoom', value); var contentsStyle = $('.contents').style; if (value == 'fit') { contentsStyle.maxWidth = 'none'; contentsStyle.width = this.canvas.style.width = '100%'; } else { var ratio = Number(value); contentsStyle.maxWidth = 'none'; contentsStyle.width = this.canvas.style.width = this.canvas.width * ratio + 'px'; } } private handleSmoothing() { localStorage.setItem('smoothing', String(this.smoothingCheckbox.checked)); if (this.smoothingCheckbox.checked) this.canvas.classList.remove('pixelated'); else this.canvas.classList.add('pixelated'); } } xsystem35.shell = new System35Shell();