import { renderCart as rawRenderCart } from "./rawRenderCart"; type PicoCart = { name: string; data: string; // TODO: ideally, accept png data url as well (or even just actual url?) } type PlayerButtons = { left: boolean; right: boolean; up: boolean; down: boolean; o: boolean; x: boolean; menu: boolean; } type PicoPlayerHandle = { // external things readonly canvas: HTMLCanvasElement; // i/o setButtons: (buttons: PlayerButtons[]) => void; setMouse: (mouse: { x: number; y: number; leftClick: boolean; rightClick: boolean; }) => void; setGamepadCount: (count: number) => void; readonly gpio: number[]; // read + write (should be 256-tuple) // audio setAudioContext: (audioContext: AudioContext) => void; // state (all communicated out) readonly state: { readonly frameNumber: number; readonly isPaused: boolean; readonly hasFocus: boolean; readonly requestPointerLock: boolean; readonly requirePageNavigateConfirmation: boolean; readonly showDpad: boolean; readonly shutdownRequested: boolean; readonly soundVolume: number; }; // misc? setTouchDetected: (touchDetected: boolean) => void; dropCart: (cart: PicoCart) => void; } const imageToNumbers = async (url: string): Promise => { return []; } const bitfield = (...args: boolean[]): number => { if (!args.length) { return 0; } return (args[0]?1:0)+2*bitfield(...args.slice(1)); } export const makePlayer = async (carts: PicoCart[]): Promise => { const canvas = document.createElement("canvas"); canvas.style.imageRendering = "pixelated"; const Module = {canvas}; const handle = rawRenderCart(Module, carts.map(cart => cart.name), await Promise.all(carts.map(cart => imageToNumbers(cart.data)))); handle.pico8_state = {}; handle.pico8_buttons = [0,0,0,0,0,0,0,0]; handle.pico8_mouse = [0,0,0]; handle.pico8_gpio = [ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, ]; handle.pico8_gamepads = {count: 0}; return { canvas, state: { frameNumber: handle.pico8_state.frame_number!, isPaused: !!handle.pico8_state.is_paused!, hasFocus: !!handle.pico8_state.has_focus!, requestPointerLock: !!handle.pico8_state.request_pointer_lock!, requirePageNavigateConfirmation: !!handle.pico8_state.require_page_navigate_confirmation!, showDpad: !!handle.pico8_state.show_dpad!, shutdownRequested: !!handle.pico8_state.shutdown_requested!, soundVolume: handle.pico8_state.sound_volume!, }, gpio: handle.pico8_gpio, setMouse({x, y, leftClick, rightClick}) { handle.pico8_mouse = [x, y, bitfield(leftClick, rightClick)]; }, setButtons(buttons) { // TODO: pad this properly here instead of casting handle.pico8_buttons = buttons.map(({left, right, up, down, o, x, menu}) => bitfield(left, right, up, down, o, x, menu)) as any; }, setGamepadCount(count) { handle.pico8_gamepads = {count}; }, setTouchDetected(touchDetected) { handle.p8_touch_detected = touchDetected ? 1 : 0; }, dropCart(cart) { handle.p8_dropped_cart_name = cart.name; // TODO: make sure this is a dataURL first, and if not, load it and then pass it in handle.p8_dropped_cart = cart.data; }, setAudioContext(audioContext) { handle.pico8_audio_context = audioContext; } } }