UNPKG

@soapbox.pub/wasmboy

Version:

Soapbox fork of Wasmboy.

1,441 lines (1,138 loc) 472 kB
(function () { 'use strict'; function getEventData(event) { if (event.data) { return event.data; } return event; } const isInBrowser = typeof self !== 'undefined'; // Function to read a base64 string as a buffer // Isomorphic worker api to be imported by web workers let parentPort; if (!isInBrowser) { parentPort = require('worker_threads').parentPort; } // https://nodejs.org/api/worker_threads.html#worker_threads_worker_postmessage_value_transferlist // https://developer.mozilla.org/en-US/docs/Web/API/Worker/postMessage function postMessage(message, transferArray) { // Can't bind parentPort.postMessage, so we need to kinda copy code here :p if (isInBrowser) { self.postMessage(message, transferArray); } else { parentPort.postMessage(message, transferArray); } } // https://nodejs.org/api/worker_threads.html#worker_threads_worker_parentport // https://developer.mozilla.org/en-US/docs/Web/API/Worker/onmessage function onMessage(callback, port) { if (!callback) { console.error('workerapi: No callback was provided to onMessage!'); } // If we passed a port, use that if (port) { if (isInBrowser) { // We are in the browser port.onmessage = callback; } else { // We are in Node port.on('message', callback); } return; } if (isInBrowser) { // We are in the browser self.onmessage = callback; } else { // We are in Node parentPort.on('message', callback); } } const WORKER_MESSAGE_TYPE = { CONNECT: 'CONNECT', INSTANTIATE_WASM: 'INSTANTIATE_WASM', CLEAR_MEMORY: 'CLEAR_MEMORY', CLEAR_MEMORY_DONE: 'CLEAR_MEMORY_DONE', GET_MEMORY: 'GET_MEMORY', SET_MEMORY: 'SET_MEMORY', SET_MEMORY_DONE: 'SET_MEMORY_DONE', GET_CONSTANTS: 'GET_CONSTANTS', GET_CONSTANTS_DONE: 'GET_CONSTANTS_DONE', CONFIG: 'CONFIG', RESET_AUDIO_QUEUE: 'RESET_AUDIO_QUEUE', PLAY: 'PLAY', BREAKPOINT: 'BREAKPOINT', PAUSE: 'PAUSE', UPDATED: 'UPDATED', CRASHED: 'CRASHED', SET_JOYPAD_STATE: 'SET_JOYPAD_STATE', AUDIO_LATENCY: 'AUDIO_LATENCY', RUN_WASM_EXPORT: 'RUN_WASM_EXPORT', GET_WASM_MEMORY_SECTION: 'GET_WASM_MEMORY_SECTION', GET_WASM_CONSTANT: 'GET_WASM_CONSTANT', FORCE_OUTPUT_FRAME: 'FORCE_OUTPUT_FRAME', SET_SPEED: 'SET_SPEED', IS_GBC: 'IS_GBC' }; const WORKER_ID = { LIB: 'LIB', GRAPHICS: 'GRAPHICS', MEMORY: 'MEMORY', CONTROLLER: 'CONTROLLER', AUDIO: 'AUDIO' }; const MEMORY_TYPE = { BOOT_ROM: 'BOOT_ROM', CARTRIDGE_RAM: 'CARTRIDGE_RAM', CARTRIDGE_ROM: 'CARTRIDGE_ROM', CARTRIDGE_HEADER: 'CARTRIDGE_HEADER', GAMEBOY_MEMORY: 'GAMEBOY_MEMORY', PALETTE_MEMORY: 'PALETTE_MEMORY', INTERNAL_STATE: 'INTERNAL_STATE' }; // Smarter workers. let idCounter = 0; const generateId = () => { const randomId = Math.random().toString(36).replace(/[^a-z]+/g, '').substr(2, 10); idCounter++; const id = `${randomId}-${idCounter}`; if (idCounter > 100000) { idCounter = 0; } return id; }; function getSmartWorkerMessage(message, messageId, workerId) { if (!messageId) { messageId = generateId(); } return { workerId, messageId, message }; } // to the lib worker function graphicsWorkerOnMessage(libWorker, event) { // Handle our messages from the main thread const eventData = getEventData(event); switch (eventData.message.type) { case WORKER_MESSAGE_TYPE.GET_CONSTANTS: { libWorker.WASMBOY_CURRENT_FRAME_OUTPUT_LOCATION = libWorker.wasmInstance.exports.FRAME_LOCATION.valueOf(); libWorker.WASMBOY_CURRENT_FRAME_SIZE = libWorker.wasmInstance.exports.FRAME_SIZE.valueOf(); // Forward to our lib worker libWorker.graphicsWorkerPort.postMessage(getSmartWorkerMessage({ type: WORKER_MESSAGE_TYPE.GET_CONSTANTS_DONE, WASMBOY_CURRENT_FRAME_OUTPUT_LOCATION: libWorker.wasmInstance.exports.FRAME_LOCATION.valueOf() }, eventData.messageId)); return; } } } function audioWorkerOnMessage(libWorker, event) { // Handle our messages from the main thread const eventData = getEventData(event); switch (eventData.message.type) { case WORKER_MESSAGE_TYPE.GET_CONSTANTS: { libWorker.WASMBOY_SOUND_OUTPUT_LOCATION = libWorker.wasmInstance.exports.AUDIO_BUFFER_LOCATION.valueOf(); libWorker.WASMBOY_CHANNEL_1_OUTPUT_LOCATION = libWorker.wasmInstance.exports.CHANNEL_1_BUFFER_LOCATION.valueOf(); libWorker.WASMBOY_CHANNEL_2_OUTPUT_LOCATION = libWorker.wasmInstance.exports.CHANNEL_2_BUFFER_LOCATION.valueOf(); libWorker.WASMBOY_CHANNEL_3_OUTPUT_LOCATION = libWorker.wasmInstance.exports.CHANNEL_3_BUFFER_LOCATION.valueOf(); libWorker.WASMBOY_CHANNEL_4_OUTPUT_LOCATION = libWorker.wasmInstance.exports.CHANNEL_4_BUFFER_LOCATION.valueOf(); // Forward to our lib worker libWorker.audioWorkerPort.postMessage(getSmartWorkerMessage({ type: WORKER_MESSAGE_TYPE.GET_CONSTANTS_DONE, WASMBOY_SOUND_OUTPUT_LOCATION: libWorker.wasmInstance.exports.AUDIO_BUFFER_LOCATION.valueOf() }, eventData.messageId)); return; } case WORKER_MESSAGE_TYPE.AUDIO_LATENCY: { libWorker.currentAudioLatencyInSeconds = eventData.message.latency; return; } } } function controllerWorkerOnMessage(libWorker, event) { // Handle our messages from the main thread const eventData = getEventData(event); switch (eventData.message.type) { case WORKER_MESSAGE_TYPE.SET_JOYPAD_STATE: { // Config will come in as an array, pass in values using apply // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply const setJoypadStateParamsAsArray = eventData.message.setJoypadStateParamsAsArray; libWorker.wasmInstance.exports.setJoypadState.apply(libWorker, setJoypadStateParamsAsArray); return; } } } // Function to get the boot ROM function getBootRom(libWorker) { if (!libWorker.wasmByteMemory) { return new Uint8Array(); } // Header is at 0x0134 - 0x014F // http://gbdev.gg8.se/wiki/articles/The_Cartridge_Header const bootRomLocation = libWorker.wasmInstance.exports.BOOT_ROM_LOCATION.valueOf(); const bootRomSize = libWorker.wasmInstance.exports.BOOT_ROM_SIZE.valueOf(); const bootRom = libWorker.wasmByteMemory.slice(bootRomLocation, bootRomLocation + bootRomSize); return bootRom; } // Private function to get the caretridge rom function getCartridgeRom(libWorker) { if (!libWorker.wasmByteMemory) { return new Uint8Array(); } // Depening on the rom type, we will have different rom sizes. // Due memory restrictions described in: // https://developers.google.com/web/fundamentals/instant-and-offline/web-storage/offline-for-pwa // We will make sure to only store as much as we need per ROM :) // Similar to `initializeCartridgeType()` in `wasm/memory/memory.ts` // We will determine our cartridge type // Get our game MBC type from the cartridge header // http://gbdev.gg8.se/wiki/articles/The_Cartridge_Header let cartridgeType = libWorker.wasmByteMemory[libWorker.WASMBOY_GAME_BYTES_LOCATION + 0x0147]; let romSize = undefined; if (cartridgeType === 0x00) { // ROM only, 32KB romSize = 0x8000; } else if (cartridgeType >= 0x01 && cartridgeType <= 0x03) { // MBC1 2MB of ROM romSize = 0x200000; } else if (cartridgeType >= 0x05 && cartridgeType <= 0x06) { // MBC2 256KB ROM romSize = 0x40000; } else if (cartridgeType >= 0x0f && cartridgeType <= 0x13) { // MBC3 2MB of ROM romSize = 0x200000; } else if (cartridgeType >= 0x19 && cartridgeType <= 0x1e) { // MBC5 8MB of ROM romSize = 0x800000; } if (!romSize) { return new Uint8Array(); } // Finally fill our cartridgeRam from the ram in memory const cartridgeRom = libWorker.wasmByteMemory.slice(libWorker.WASMBOY_GAME_BYTES_LOCATION, libWorker.WASMBOY_GAME_BYTES_LOCATION + romSize); return cartridgeRom; } // Private function to get the cartridge ram function getCartridgeRam(libWorker) { if (!libWorker.wasmByteMemory) { return new Uint8Array(); } // Depening on the rom type, we will have different ram sizes. // Due memory restrictions described in: // https://developers.google.com/web/fundamentals/instant-and-offline/web-storage/offline-for-pwa // We will make sure to only store as much as we need per ROM :) // Similar to `initializeCartridgeType()` in `wasm/memory/memory.ts` // We will determine our cartridge type // Get our game MBC type from the cartridge header // http://gbdev.gg8.se/wiki/articles/The_Cartridge_Header let cartridgeType = libWorker.wasmByteMemory[libWorker.WASMBOY_GAME_BYTES_LOCATION + 0x0147]; let ramSize = undefined; if (cartridgeType === 0x00) { // No memory for this rom type return new Uint8Array(); } else if (cartridgeType >= 0x01 && cartridgeType <= 0x03) { // MBC1 32KB of Ram ramSize = 0x8000; } else if (cartridgeType >= 0x05 && cartridgeType <= 0x06) { // MBC2 512X4 Bytes, 2KB ramSize = 0x800; } else if (cartridgeType >= 0x0f && cartridgeType <= 0x13) { // MBC3 32KB of Ram ramSize = 0x8000; } else if (cartridgeType >= 0x19 && cartridgeType <= 0x1e) { // MBC5 128KB of Ram ramSize = 0x20000; } if (!ramSize) { return new Uint8Array(); } // Finally fill our cartridgeRam from the ram in memory const cartridgeRam = libWorker.wasmByteMemory.slice(libWorker.WASMBOY_GAME_RAM_BANKS_LOCATION, libWorker.WASMBOY_GAME_RAM_BANKS_LOCATION + ramSize); return cartridgeRam; } // Function to get the cartridge header function getCartridgeHeader(libWorker) { if (!libWorker.wasmByteMemory) { return new Uint8Array(); } // Header is at 0x0134 - 0x014F // http://gbdev.gg8.se/wiki/articles/The_Cartridge_Header const headerLength = 0x014f - 0x0134; const headerLocation = libWorker.WASMBOY_GAME_BYTES_LOCATION + 0x0134; const headerArray = libWorker.wasmByteMemory.slice(headerLocation, headerLocation + headerLength); return headerArray; } // Returns the standard 0xFFFF gameboy memory // You will normally see in gameboy docs. // This is returned from the core, and represents // This wasmboy gameboy state function getGameBoyMemory(libWorker) { return libWorker.wasmByteMemory.slice(libWorker.WASMBOY_INTERNAL_MEMORY_LOCATION, libWorker.WASMBOY_INTERNAL_MEMORY_LOCATION + libWorker.WASMBOY_INTERNAL_MEMORY_SIZE); } // Function to get the current palette data for // GBC in memory. This is needed to load state with // The correct colors function getPaletteMemory(libWorker) { return libWorker.wasmByteMemory.slice(libWorker.WASMBOY_PALETTE_MEMORY_LOCATION, libWorker.WASMBOY_PALETTE_MEMORY_LOCATION + libWorker.WASMBOY_PALETTE_MEMORY_SIZE); } // Returns the internal savestate of the wasmboy core, // To save all soft values held in memory function getInternalState(libWorker) { libWorker.wasmInstance.exports.saveState(); return libWorker.wasmByteMemory.slice(libWorker.WASMBOY_INTERNAL_STATE_LOCATION, libWorker.WASMBOY_INTERNAL_STATE_LOCATION + libWorker.WASMBOY_INTERNAL_STATE_SIZE); } // posts to lib Worker function memoryWorkerOnMessage(libWorker, event) { // Handle our messages from the main thread const eventData = getEventData(event); switch (eventData.message.type) { case WORKER_MESSAGE_TYPE.CLEAR_MEMORY: { // Clear Wasm memory // https://docs.google.com/spreadsheets/d/17xrEzJk5-sCB9J2mMJcVnzhbE-XH_NvczVSQH9OHvRk/edit?usp=sharing for (let i = 0; i <= libWorker.wasmByteMemory.length; i++) { libWorker.wasmByteMemory[i] = 0; } const wasmByteMemory = libWorker.wasmByteMemory.slice(0); libWorker.memoryWorkerPort.postMessage(getSmartWorkerMessage({ type: WORKER_MESSAGE_TYPE.CLEAR_MEMORY_DONE, wasmByteMemory: wasmByteMemory.buffer }, eventData.messageId), [wasmByteMemory.buffer]); return; } case WORKER_MESSAGE_TYPE.GET_CONSTANTS: { libWorker.WASMBOY_BOOT_ROM_LOCATION = libWorker.wasmInstance.exports.BOOT_ROM_LOCATION.valueOf(); libWorker.WASMBOY_GAME_BYTES_LOCATION = libWorker.wasmInstance.exports.CARTRIDGE_ROM_LOCATION.valueOf(); libWorker.WASMBOY_GAME_RAM_BANKS_LOCATION = libWorker.wasmInstance.exports.CARTRIDGE_RAM_LOCATION.valueOf(), libWorker.WASMBOY_INTERNAL_STATE_SIZE = libWorker.wasmInstance.exports.WASMBOY_STATE_SIZE.valueOf(), libWorker.WASMBOY_INTERNAL_STATE_LOCATION = libWorker.wasmInstance.exports.WASMBOY_STATE_LOCATION.valueOf(), libWorker.WASMBOY_INTERNAL_MEMORY_SIZE = libWorker.wasmInstance.exports.GAMEBOY_INTERNAL_MEMORY_SIZE.valueOf(), libWorker.WASMBOY_INTERNAL_MEMORY_LOCATION = libWorker.wasmInstance.exports.GAMEBOY_INTERNAL_MEMORY_LOCATION.valueOf(), libWorker.WASMBOY_PALETTE_MEMORY_SIZE = libWorker.wasmInstance.exports.GBC_PALETTE_SIZE.valueOf(), libWorker.WASMBOY_PALETTE_MEMORY_LOCATION = libWorker.wasmInstance.exports.GBC_PALETTE_LOCATION.valueOf(); // Forward to our lib worker libWorker.memoryWorkerPort.postMessage(getSmartWorkerMessage({ type: WORKER_MESSAGE_TYPE.GET_CONSTANTS_DONE, WASMBOY_BOOT_ROM_LOCATION: libWorker.wasmInstance.exports.BOOT_ROM_LOCATION.valueOf(), WASMBOY_GAME_BYTES_LOCATION: libWorker.wasmInstance.exports.CARTRIDGE_ROM_LOCATION.valueOf(), WASMBOY_GAME_RAM_BANKS_LOCATION: libWorker.wasmInstance.exports.CARTRIDGE_RAM_LOCATION.valueOf(), WASMBOY_INTERNAL_STATE_SIZE: libWorker.wasmInstance.exports.WASMBOY_STATE_SIZE.valueOf(), WASMBOY_INTERNAL_STATE_LOCATION: libWorker.wasmInstance.exports.WASMBOY_STATE_LOCATION.valueOf(), WASMBOY_INTERNAL_MEMORY_SIZE: libWorker.wasmInstance.exports.GAMEBOY_INTERNAL_MEMORY_SIZE.valueOf(), WASMBOY_INTERNAL_MEMORY_LOCATION: libWorker.wasmInstance.exports.GAMEBOY_INTERNAL_MEMORY_LOCATION.valueOf(), WASMBOY_PALETTE_MEMORY_SIZE: libWorker.wasmInstance.exports.GBC_PALETTE_SIZE.valueOf(), WASMBOY_PALETTE_MEMORY_LOCATION: libWorker.wasmInstance.exports.GBC_PALETTE_LOCATION.valueOf() }, eventData.messageId)); return; } case WORKER_MESSAGE_TYPE.SET_MEMORY: { const memoryKeys = Object.keys(eventData.message); if (memoryKeys.includes(MEMORY_TYPE.BOOT_ROM)) { libWorker.wasmByteMemory.set(new Uint8Array(eventData.message[MEMORY_TYPE.BOOT_ROM]), libWorker.WASMBOY_BOOT_ROM_LOCATION); } if (memoryKeys.includes(MEMORY_TYPE.CARTRIDGE_ROM)) { libWorker.wasmByteMemory.set(new Uint8Array(eventData.message[MEMORY_TYPE.CARTRIDGE_ROM]), libWorker.WASMBOY_GAME_BYTES_LOCATION); } if (memoryKeys.includes(MEMORY_TYPE.CARTRIDGE_RAM)) { libWorker.wasmByteMemory.set(new Uint8Array(eventData.message[MEMORY_TYPE.CARTRIDGE_RAM]), libWorker.WASMBOY_GAME_RAM_BANKS_LOCATION); } if (memoryKeys.includes(MEMORY_TYPE.GAMEBOY_MEMORY)) { libWorker.wasmByteMemory.set(new Uint8Array(eventData.message[MEMORY_TYPE.GAMEBOY_MEMORY]), libWorker.WASMBOY_INTERNAL_MEMORY_LOCATION); } if (memoryKeys.includes(MEMORY_TYPE.PALETTE_MEMORY)) { libWorker.wasmByteMemory.set(new Uint8Array(eventData.message[MEMORY_TYPE.PALETTE_MEMORY]), libWorker.WASMBOY_PALETTE_MEMORY_LOCATION); } if (memoryKeys.includes(MEMORY_TYPE.INTERNAL_STATE)) { libWorker.wasmByteMemory.set(new Uint8Array(eventData.message[MEMORY_TYPE.INTERNAL_STATE]), libWorker.WASMBOY_INTERNAL_STATE_LOCATION); libWorker.wasmInstance.exports.loadState(); } libWorker.memoryWorkerPort.postMessage(getSmartWorkerMessage({ type: WORKER_MESSAGE_TYPE.SET_MEMORY_DONE }, eventData.messageId)); return; } case WORKER_MESSAGE_TYPE.GET_MEMORY: { // Construct our data object const responseMemory = { type: WORKER_MESSAGE_TYPE.GET_MEMORY }; const responseTransferrables = []; const memoryTypes = eventData.message.memoryTypes; if (memoryTypes.includes(MEMORY_TYPE.BOOT_ROM)) { const bootRom = getBootRom(libWorker).buffer; responseMemory[MEMORY_TYPE.BOOT_ROM] = bootRom; responseTransferrables.push(bootRom); } if (memoryTypes.includes(MEMORY_TYPE.CARTRIDGE_ROM)) { const cartridgeRom = getCartridgeRom(libWorker).buffer; responseMemory[MEMORY_TYPE.CARTRIDGE_ROM] = cartridgeRom; responseTransferrables.push(cartridgeRom); } if (memoryTypes.includes(MEMORY_TYPE.CARTRIDGE_RAM)) { const cartridgeRam = getCartridgeRam(libWorker).buffer; responseMemory[MEMORY_TYPE.CARTRIDGE_RAM] = cartridgeRam; responseTransferrables.push(cartridgeRam); } if (memoryTypes.includes(MEMORY_TYPE.CARTRIDGE_HEADER)) { const cartridgeHeader = getCartridgeHeader(libWorker).buffer; responseMemory[MEMORY_TYPE.CARTRIDGE_HEADER] = cartridgeHeader; responseTransferrables.push(cartridgeHeader); } if (memoryTypes.includes(MEMORY_TYPE.GAMEBOY_MEMORY)) { const gameboyMemory = getGameBoyMemory(libWorker).buffer; responseMemory[MEMORY_TYPE.GAMEBOY_MEMORY] = gameboyMemory; responseTransferrables.push(gameboyMemory); } if (memoryTypes.includes(MEMORY_TYPE.PALETTE_MEMORY)) { const paletteMemory = getPaletteMemory(libWorker).buffer; responseMemory[MEMORY_TYPE.PALETTE_MEMORY] = paletteMemory; responseTransferrables.push(paletteMemory); } if (memoryTypes.includes(MEMORY_TYPE.INTERNAL_STATE)) { libWorker.wasmInstance.exports.saveState(); const internalState = getInternalState(libWorker).buffer; responseMemory[MEMORY_TYPE.INTERNAL_STATE] = internalState; responseTransferrables.push(internalState); } libWorker.memoryWorkerPort.postMessage(getSmartWorkerMessage(responseMemory, eventData.messageId), responseTransferrables); return; } } } // Banner placed by rollup to mock out some items on our esm build // This is useful for things like wasmmemory const wasmboyMemorySize = 0x8b0000; // Simply initialized to the size we need const wasmByteMemory = new Uint8ClampedArray(wasmboyMemorySize); // Memory mock const memory = { size: () => { return wasmboyMemorySize; }, grow: () => {}, wasmByteMemory: wasmByteMemory }; const load = offset => { return wasmByteMemory[offset]; }; const store = (offset, value) => { wasmByteMemory[offset] = value; }; const abs = value => { return Math.abs(value); }; const ceil = value => { return Math.ceil(value); }; // Constants that will be shared by the wasm core of the emulator // And libraries built around the wasm (such as the official JS), or @CryZe wasmboy-rs // ---------------------------------- // Wasmboy Memory Map // https://docs.google.com/spreadsheets/d/17xrEzJk5-sCB9J2mMJcVnzhbE-XH_NvczVSQH9OHvRk/edit?usp=sharing // ---------------------------------- // AssemblyScript var ASSEMBLYSCRIPT_MEMORY_LOCATION = 0x000000; var ASSEMBLYSCRIPT_MEMORY_SIZE = 0x000400; // WasmBoy States var WASMBOY_STATE_LOCATION = ASSEMBLYSCRIPT_MEMORY_LOCATION + ASSEMBLYSCRIPT_MEMORY_SIZE; var WASMBOY_STATE_SIZE = 0x000400; // Gameboy Internal Memory var VIDEO_RAM_LOCATION = WASMBOY_STATE_LOCATION + WASMBOY_STATE_SIZE; var VIDEO_RAM_SIZE = 0x004000; var WORK_RAM_LOCATION = VIDEO_RAM_LOCATION + VIDEO_RAM_SIZE; var WORK_RAM_SIZE = 0x008000; var OTHER_GAMEBOY_INTERNAL_MEMORY_LOCATION = WORK_RAM_LOCATION + WORK_RAM_SIZE; var OTHER_GAMEBOY_INTERNAL_MEMORY_SIZE = 0x004000; // General Gameboy Internal Memory var GAMEBOY_INTERNAL_MEMORY_LOCATION = VIDEO_RAM_LOCATION; var GAMEBOY_INTERNAL_MEMORY_SIZE = OTHER_GAMEBOY_INTERNAL_MEMORY_LOCATION - VIDEO_RAM_LOCATION + OTHER_GAMEBOY_INTERNAL_MEMORY_SIZE; // Graphics Output var GBC_PALETTE_LOCATION = OTHER_GAMEBOY_INTERNAL_MEMORY_LOCATION + OTHER_GAMEBOY_INTERNAL_MEMORY_SIZE; var GBC_PALETTE_SIZE = 0x000080; var BG_PRIORITY_MAP_LOCATION = GBC_PALETTE_LOCATION + GBC_PALETTE_SIZE; var BG_PRIORITY_MAP_SIZE = 0x005c00; var FRAME_LOCATION = BG_PRIORITY_MAP_LOCATION + BG_PRIORITY_MAP_SIZE; var FRAME_SIZE = 0x016c00; var BACKGROUND_MAP_LOCATION = FRAME_LOCATION + FRAME_SIZE; var BACKGROUND_MAP_SIZE = 0x030000; var TILE_DATA_LOCATION = BACKGROUND_MAP_LOCATION + BACKGROUND_MAP_SIZE; var TILE_DATA_SIZE = 0x024000; var OAM_TILES_LOCATION = TILE_DATA_LOCATION + TILE_DATA_SIZE; var OAM_TILES_SIZE = 0x003c00; // General Graphics Output var GRAPHICS_OUTPUT_LOCATION = GBC_PALETTE_LOCATION; var GRAPHICS_OUTPUT_SIZE = OAM_TILES_LOCATION - GBC_PALETTE_LOCATION + OAM_TILES_SIZE; // Audio Output var CHANNEL_1_BUFFER_LOCATION = OAM_TILES_LOCATION + OAM_TILES_SIZE; var CHANNEL_1_BUFFER_SIZE = 0x020000; var CHANNEL_2_BUFFER_LOCATION = CHANNEL_1_BUFFER_LOCATION + CHANNEL_1_BUFFER_SIZE; var CHANNEL_2_BUFFER_SIZE = 0x020000; var CHANNEL_3_BUFFER_LOCATION = CHANNEL_2_BUFFER_LOCATION + CHANNEL_2_BUFFER_SIZE; var CHANNEL_3_BUFFER_SIZE = 0x020000; var CHANNEL_4_BUFFER_LOCATION = CHANNEL_3_BUFFER_LOCATION + CHANNEL_3_BUFFER_SIZE; var CHANNEL_4_BUFFER_SIZE = 0x020000; var AUDIO_BUFFER_LOCATION = CHANNEL_4_BUFFER_LOCATION + CHANNEL_4_BUFFER_SIZE; var AUDIO_BUFFER_SIZE = 0x020000; // Catridge Ram var CARTRIDGE_RAM_LOCATION = AUDIO_BUFFER_LOCATION + AUDIO_BUFFER_SIZE; var CARTRIDGE_RAM_SIZE = 0x020000; // Boot ROM // http://gbdev.gg8.se/files/roms/bootroms/ // Largest Boot rom is GBC, at 2.5KB var BOOT_ROM_LOCATION = CARTRIDGE_RAM_LOCATION + CARTRIDGE_RAM_SIZE; var BOOT_ROM_SIZE = 0x000a00; // Cartridge ROM var CARTRIDGE_ROM_LOCATION = BOOT_ROM_LOCATION + BOOT_ROM_SIZE; var CARTRIDGE_ROM_SIZE = 0x7e0400; // Debug Memory var DEBUG_GAMEBOY_MEMORY_LOCATION = CARTRIDGE_ROM_LOCATION + CARTRIDGE_ROM_SIZE; var DEBUG_GAMEBOY_MEMORY_SIZE = 0xffff; // Final General Size var WASMBOY_MEMORY_LOCATION = 0x000000; var WASMBOY_MEMORY_SIZE = DEBUG_GAMEBOY_MEMORY_LOCATION + DEBUG_GAMEBOY_MEMORY_SIZE + 1; var WASMBOY_WASM_PAGES = ceil(WASMBOY_MEMORY_SIZE / 1024 / 64) + 1; var Config = /** @class */ function () { function Config() {} // Boot Rom Config.enableBootRom = false; // GBC Options Config.useGbcWhenAvailable = true; // Batch Processing Config.audioBatchProcessing = false; Config.graphicsBatchProcessing = false; Config.timersBatchProcessing = false; // Scanline Rendering Config.graphicsDisableScanlineRendering = false; // Acumulate Sound Samples Config.audioAccumulateSamples = false; // Tile Rednering Config.tileRendering = false; Config.tileCaching = false; // Audio Debugging Config.enableAudioDebugging = false; return Config; }(); // Portable Code for JS Wasm Benchmarking // https://github.com/AssemblyScript/assemblyscript/wiki/Writing-portable-code // https://github.com/AssemblyScript/assemblyscript/blob/master/std/portable/index.js function u8Portable(param) { return param & 0xff; } function u16Portable(param) { return param & 0xffff; } function i8Portable(param) { return param << 24 >> 24; } function i32Portable(param) { return param | 0; } // Set flag bit on on register F. For instance set zero flag to zero -> (7, 0) function setFlagBit(flagBit, flagValue) { var bitwiseOperand = u8Portable(1 << flagBit); if (flagValue > 0) { Cpu.registerF = Cpu.registerF | bitwiseOperand; } else { // XOR out the two ones bitwiseOperand = 0xff ^ bitwiseOperand; Cpu.registerF = Cpu.registerF & bitwiseOperand; } return Cpu.registerF; } // Overload the set flag bit for ease of use function setZeroFlag$$1(value) { setFlagBit(7, value); } function setSubtractFlag(value) { setFlagBit(6, value); } function setHalfCarryFlag(value) { setFlagBit(5, value); } function setCarryFlag(value) { setFlagBit(4, value); } // Getters for flags function getZeroFlag$$1() { return Cpu.registerF >> 7 & 0x01; } function getSubtractFlag() { return Cpu.registerF >> 6 & 0x01; } function getHalfCarryFlag() { return Cpu.registerF >> 5 & 0x01; } function getCarryFlag$$1() { return Cpu.registerF >> 4 & 0x01; } // Must be run before the register actually performs the add // amountToAdd i16, since max number can be an u8 function checkAndSetEightBitHalfCarryFlag(value, amountToAdd) { if (amountToAdd >= 0) { // https://robdor.com/2016/08/10/gameboy-emulator-half-carry-flag/ var result = u8Portable((value & 0x0f) + (amountToAdd & 0x0f)) & 0x10; setHalfCarryFlag(result !== 0x00); } else { // From: https://github.com/djhworld/gomeboycolor/blob/master/src/cpu/index.go // CTRL+F "subBytes(a, b byte)" setHalfCarryFlag((abs(amountToAdd) & 0x0f) > (value & 0x0f)); } } function checkAndSetEightBitCarryFlag(value, amountToAdd) { if (amountToAdd >= 0) { var result = u8Portable(value + amountToAdd); setCarryFlag(value > result); } else { setCarryFlag(abs(amountToAdd) > value); } } // Function to handle 16 bit addition overflow, and set the carry flags accordingly // i32 on valueTwo to support passing signed immedaite values function checkAndSetSixteenBitFlagsAddOverflow(valueOne, valueTwo, useStackPointerBits) { // need to differentiate between HL and SP // HL carries are at 11 and 15, SP carries are at 3 and 7 :p if (useStackPointerBits) { // Logic from : https://github.com/nakardo/node-gameboy/blob/master/lib/cpu/opcodes.js // CTRL+F add_sp_n // using the stack pointer bits means we can safely assume the value is signed var signedValueOne = valueOne; var result = signedValueOne + valueTwo; var flagXor = signedValueOne ^ valueTwo ^ result; setHalfCarryFlag((flagXor & 0x10) !== 0); setCarryFlag((flagXor & 0x100) !== 0); } else { // Logic from: https://github.com/djhworld/gomeboycolor/blob/master/src/cpu/index.go // CTRL+F addWords // Value two is not signed var result = u16Portable(valueOne + valueTwo); // Check the carry flag by allowing the overflow setCarryFlag(result < valueOne); // To check for half carry flag (bit 15), by XOR'ing valyes, and and'ing the bit in question var halfCarryXor = valueOne ^ valueTwo ^ result; var halfCarryAnd = u16Portable(halfCarryXor & 0x1000); setHalfCarryFlag(halfCarryAnd !== 0x00); } } // File for all of the colors for different GB Palletes // https://i.imgur.com/HupBY.png // https://www.libretro.com/index.php/gambatte-progress-report/ // https://tcrf.net/Notes:Game_Boy_Color_Bootstrap_ROM // Our default wasmboy gb colors var WasmBoyGBColors = /** @class */ function () { function WasmBoyGBColors() {} //Bg WasmBoyGBColors.bgWhite = 0xf2f2f2; WasmBoyGBColors.bgLightGrey = 0xa0a0a0; WasmBoyGBColors.bgDarkGrey = 0x585858; WasmBoyGBColors.bgBlack = 0x080808; // Obj 0 WasmBoyGBColors.obj0White = 0xf2f2f2; WasmBoyGBColors.obj0LightGrey = 0xa0a0a0; WasmBoyGBColors.obj0DarkGrey = 0x585858; WasmBoyGBColors.obj0Black = 0x080808; // Obj1 WasmBoyGBColors.obj1White = 0xf2f2f2; WasmBoyGBColors.obj1LightGrey = 0xa0a0a0; WasmBoyGBColors.obj1DarkGrey = 0x585858; WasmBoyGBColors.obj1Black = 0x080808; return WasmBoyGBColors; }(); // Action Button: Right var GreenColors = /** @class */ function () { function GreenColors() {} //Bg GreenColors.bgWhite = 0xffffff; GreenColors.bgLightGrey = 0x52ff00; GreenColors.bgDarkGrey = 0xff4200; GreenColors.bgBlack = 0x000000; // Obj 0 GreenColors.obj0White = 0xffffff; GreenColors.obj0LightGrey = 0x52ff00; GreenColors.obj0DarkGrey = 0xff4200; GreenColors.obj0Black = 0x000000; // Obj1 GreenColors.obj1White = 0xffffff; GreenColors.obj1LightGrey = 0x52ff00; GreenColors.obj1DarkGrey = 0xff4200; GreenColors.obj1Black = 0x000000; return GreenColors; }(); // Action Button: A + Down var OrangeColors = /** @class */ function () { function OrangeColors() {} //Bg OrangeColors.bgWhite = 0xffffff; OrangeColors.bgLightGrey = 0xffff00; OrangeColors.bgDarkGrey = 0xff0000; OrangeColors.bgBlack = 0x000000; // Obj 0 OrangeColors.obj0White = 0xffffff; OrangeColors.obj0LightGrey = 0xffff00; OrangeColors.obj0DarkGrey = 0xff0000; OrangeColors.obj0Black = 0x000000; // Obj1 OrangeColors.obj1White = 0xffffff; OrangeColors.obj1LightGrey = 0xffff00; OrangeColors.obj1DarkGrey = 0xff0000; OrangeColors.obj1Black = 0x000000; return OrangeColors; }(); // Action Button: Up var BrownColors = /** @class */ function () { function BrownColors() {} //Bg BrownColors.bgWhite = 0xffffff; BrownColors.bgLightGrey = 0xffad63; BrownColors.bgDarkGrey = 0x843100; BrownColors.bgBlack = 0x000000; // Obj 0 BrownColors.obj0White = 0xffffff; BrownColors.obj0LightGrey = 0xffad63; BrownColors.obj0DarkGrey = 0x843100; BrownColors.obj0Black = 0x000000; // Obj1 BrownColors.obj1White = 0xffffff; BrownColors.obj1LightGrey = 0xffad63; BrownColors.obj1DarkGrey = 0x843100; BrownColors.obj1Black = 0x000000; return BrownColors; }(); // Action Button: B + Right var InvertedColors = /** @class */ function () { function InvertedColors() {} //Bg InvertedColors.bgWhite = 0x000000; InvertedColors.bgLightGrey = 0x008484; InvertedColors.bgDarkGrey = 0xffde00; InvertedColors.bgBlack = 0xffffff; // Obj 0 InvertedColors.obj0White = 0x000000; InvertedColors.obj0LightGrey = 0x008484; InvertedColors.obj0DarkGrey = 0xffde00; InvertedColors.obj0Black = 0xffffff; // Obj1 InvertedColors.obj1White = 0x000000; InvertedColors.obj1LightGrey = 0x008484; InvertedColors.obj1DarkGrey = 0xffde00; InvertedColors.obj1Black = 0xffffff; return InvertedColors; }(); // Action Button: B + Left var GrayscaleColors = /** @class */ function () { function GrayscaleColors() {} //Bg GrayscaleColors.bgWhite = 0xffffff; GrayscaleColors.bgLightGrey = 0xa5a5a5; GrayscaleColors.bgDarkGrey = 0x525252; GrayscaleColors.bgBlack = 0x000000; // Obj 0 GrayscaleColors.obj0White = 0xffffff; GrayscaleColors.obj0LightGrey = 0xa5a5a5; GrayscaleColors.obj0DarkGrey = 0x525252; GrayscaleColors.obj0Black = 0x000000; // Obj1 GrayscaleColors.obj1White = 0xffffff; GrayscaleColors.obj1LightGrey = 0xa5a5a5; GrayscaleColors.obj1DarkGrey = 0x525252; GrayscaleColors.obj1Black = 0x000000; return GrayscaleColors; }(); // Action Button: Down var PastelMixColors = /** @class */ function () { function PastelMixColors() {} //Bg PastelMixColors.bgWhite = 0xffffa5; PastelMixColors.bgLightGrey = 0xff9494; PastelMixColors.bgDarkGrey = 0x9494ff; PastelMixColors.bgBlack = 0x000000; // Obj 0 PastelMixColors.obj0White = 0xffffa5; PastelMixColors.obj0LightGrey = 0xff9494; PastelMixColors.obj0DarkGrey = 0x9494ff; PastelMixColors.obj0Black = 0x000000; // Obj1 PastelMixColors.obj1White = 0xffffa5; PastelMixColors.obj1LightGrey = 0xff9494; PastelMixColors.obj1DarkGrey = 0x9494ff; PastelMixColors.obj1Black = 0x000000; return PastelMixColors; }(); // Action Button: B + Up var DarkBrownColors = /** @class */ function () { function DarkBrownColors() {} //Bg DarkBrownColors.bgWhite = 0xffe6c5; DarkBrownColors.bgLightGrey = 0xce9c84; DarkBrownColors.bgDarkGrey = 0x846b29; DarkBrownColors.bgBlack = 0x5a3108; // Obj 0 DarkBrownColors.obj0White = 0xffffff; DarkBrownColors.obj0LightGrey = 0xffad63; DarkBrownColors.obj0DarkGrey = 0x843100; DarkBrownColors.obj0Black = 0x000000; // Obj1 DarkBrownColors.obj1White = 0xffffff; DarkBrownColors.obj1LightGrey = 0xffad63; DarkBrownColors.obj1DarkGrey = 0x843100; DarkBrownColors.obj1Black = 0x000000; return DarkBrownColors; }(); // Action Button: A + Right var DarkGreenColors = /** @class */ function () { function DarkGreenColors() {} //Bg DarkGreenColors.bgWhite = 0xffffff; DarkGreenColors.bgLightGrey = 0x7bff31; DarkGreenColors.bgDarkGrey = 0x0063c5; DarkGreenColors.bgBlack = 0x000000; // Obj 0 DarkGreenColors.obj0White = 0xffffff; DarkGreenColors.obj0LightGrey = 0xff8484; DarkGreenColors.obj0DarkGrey = 0x943a3a; DarkGreenColors.obj0Black = 0x000000; // Obj1 DarkGreenColors.obj1White = 0xffffff; DarkGreenColors.obj1LightGrey = 0xff8484; DarkGreenColors.obj1DarkGrey = 0x943a3a; DarkGreenColors.obj1Black = 0x000000; return DarkGreenColors; }(); // Action Button: A + Left var DarkBlueColors = /** @class */ function () { function DarkBlueColors() {} //Bg DarkBlueColors.bgWhite = 0xffffff; DarkBlueColors.bgLightGrey = 0x8c8cde; DarkBlueColors.bgDarkGrey = 0x52528c; DarkBlueColors.bgBlack = 0x000000; // Obj 0 DarkBlueColors.obj0White = 0xffffff; DarkBlueColors.obj0LightGrey = 0xff8484; DarkBlueColors.obj0DarkGrey = 0x943a3a; DarkBlueColors.obj0Black = 0x000000; // Obj1 DarkBlueColors.obj1White = 0xffffff; DarkBlueColors.obj1LightGrey = 0xffad63; DarkBlueColors.obj1DarkGrey = 0x843100; DarkBlueColors.obj1Black = 0x000000; return DarkBlueColors; }(); // Action Button: A + Up var RedColors = /** @class */ function () { function RedColors() {} //Bg RedColors.bgWhite = 0xffffff; RedColors.bgLightGrey = 0xff8484; RedColors.bgDarkGrey = 0x943a3a; RedColors.bgBlack = 0x000000; // Obj 0 RedColors.obj0White = 0xffffff; RedColors.obj0LightGrey = 0x7bff31; RedColors.obj0DarkGrey = 0x008400; RedColors.obj0Black = 0x000000; // Obj1 RedColors.obj1White = 0xffffff; RedColors.obj1LightGrey = 0x63a5ff; RedColors.obj1DarkGrey = 0x0000ff; RedColors.obj1Black = 0x000000; return RedColors; }(); // Action Button: Left var BlueColors = /** @class */ function () { function BlueColors() {} //Bg BlueColors.bgWhite = 0xffffff; BlueColors.bgLightGrey = 0x63a5ff; BlueColors.bgDarkGrey = 0x0000ff; BlueColors.bgBlack = 0x000000; // Obj 0 BlueColors.obj0White = 0xffffff; BlueColors.obj0LightGrey = 0xff8484; BlueColors.obj0DarkGrey = 0x943a3a; BlueColors.obj0Black = 0x000000; // Obj1 BlueColors.obj1White = 0xffffff; BlueColors.obj1LightGrey = 0x7bff31; BlueColors.obj1DarkGrey = 0x008400; BlueColors.obj1Black = 0x000000; return BlueColors; }(); // Action Button: B + Down var YellowColors = /** @class */ function () { function YellowColors() {} //Bg YellowColors.bgWhite = 0xffffff; YellowColors.bgLightGrey = 0xffff00; YellowColors.bgDarkGrey = 0x7b4a00; YellowColors.bgBlack = 0x000000; // Obj 0 YellowColors.obj0White = 0xffffff; YellowColors.obj0LightGrey = 0x63a5ff; YellowColors.obj0DarkGrey = 0x0000ff; YellowColors.obj0Black = 0x000000; // Obj1 YellowColors.obj1White = 0xffffff; YellowColors.obj1LightGrey = 0x7bff31; YellowColors.obj1DarkGrey = 0x008400; YellowColors.obj1Black = 0x000000; return YellowColors; }(); // Assigned Color Palettes // Alleyway var Table00Entry08Colors = /** @class */ function () { function Table00Entry08Colors() {} //Bg Table00Entry08Colors.bgWhite = 0xa59cff; Table00Entry08Colors.bgLightGrey = 0xffff00; Table00Entry08Colors.bgDarkGrey = 0x006300; Table00Entry08Colors.bgBlack = 0x000000; // Obj 0 Table00Entry08Colors.obj0White = 0xa59cff; Table00Entry08Colors.obj0LightGrey = 0xffff00; Table00Entry08Colors.obj0DarkGrey = 0x006300; Table00Entry08Colors.obj0Black = 0x000000; // Obj1 Table00Entry08Colors.obj1White = 0xa59cff; Table00Entry08Colors.obj1LightGrey = 0xffff00; Table00Entry08Colors.obj1DarkGrey = 0x006300; Table00Entry08Colors.obj1Black = 0x000000; return Table00Entry08Colors; }(); // Pokemon Blue var Table01Entry0BColors = /** @class */ function () { function Table01Entry0BColors() {} //Bg Table01Entry0BColors.bgWhite = 0xffffff; Table01Entry0BColors.bgLightGrey = 0x63a5ff; Table01Entry0BColors.bgDarkGrey = 0x0000ff; Table01Entry0BColors.bgBlack = 0x000000; // Obj 0 Table01Entry0BColors.obj0White = 0xffffff; Table01Entry0BColors.obj0LightGrey = 0xff8484; Table01Entry0BColors.obj0DarkGrey = 0x943a3a; Table01Entry0BColors.obj0Black = 0x000000; // Obj1 Table01Entry0BColors.obj1White = 0xffffff; Table01Entry0BColors.obj1LightGrey = 0x63a5ff; Table01Entry0BColors.obj1DarkGrey = 0x0000ff; Table01Entry0BColors.obj1Black = 0x000000; return Table01Entry0BColors; }(); // Pokemon Red var Table01Entry10Colors = /** @class */ function () { function Table01Entry10Colors() {} //Bg Table01Entry10Colors.bgWhite = 0xffffff; Table01Entry10Colors.bgLightGrey = 0xff8484; Table01Entry10Colors.bgDarkGrey = 0x943a3a; Table01Entry10Colors.bgBlack = 0x000000; // Obj 0 Table01Entry10Colors.obj0White = 0xffffff; Table01Entry10Colors.obj0LightGrey = 0x7bff31; Table01Entry10Colors.obj0DarkGrey = 0x008400; Table01Entry10Colors.obj0Black = 0x000000; // Obj1 Table01Entry10Colors.obj1White = 0xffffff; Table01Entry10Colors.obj1LightGrey = 0xff8484; Table01Entry10Colors.obj1DarkGrey = 0x943a3a; Table01Entry10Colors.obj1Black = 0x000000; return Table01Entry10Colors; }(); // Super Mario Land var Table03Entry0AColors = /** @class */ function () { function Table03Entry0AColors() {} //Bg Table03Entry0AColors.bgWhite = 0xb5b5ff; Table03Entry0AColors.bgLightGrey = 0xffff94; Table03Entry0AColors.bgDarkGrey = 0xad5a42; Table03Entry0AColors.bgBlack = 0x000000; // Obj 0 Table03Entry0AColors.obj0White = 0x000000; Table03Entry0AColors.obj0LightGrey = 0xffffff; Table03Entry0AColors.obj0DarkGrey = 0xff8484; Table03Entry0AColors.obj0Black = 0x943a3a; // Obj1 Table03Entry0AColors.obj1White = 0x000000; Table03Entry0AColors.obj1LightGrey = 0xffffff; Table03Entry0AColors.obj1DarkGrey = 0xff8484; Table03Entry0AColors.obj1Black = 0x943a3a; return Table03Entry0AColors; }(); // Super Mario Land 3 - WarioLand var Table05Entry00Colors = /** @class */ function () { function Table05Entry00Colors() {} //Bg Table05Entry00Colors.bgWhite = 0xffffff; Table05Entry00Colors.bgLightGrey = 0xadad84; Table05Entry00Colors.bgDarkGrey = 0x42737b; Table05Entry00Colors.bgBlack = 0x000000; // Obj 0 Table05Entry00Colors.obj0White = 0xffffff; Table05Entry00Colors.obj0LightGrey = 0xff7300; Table05Entry00Colors.obj0DarkGrey = 0x944200; Table05Entry00Colors.obj0Black = 0x000000; // Obj1 Table05Entry00Colors.obj1White = 0xffffff; Table05Entry00Colors.obj1LightGrey = 0x5abdff; Table05Entry00Colors.obj1DarkGrey = 0xff0000; Table05Entry00Colors.obj1Black = 0x0000ff; return Table05Entry00Colors; }(); // Donkey Kong var Table05Entry01Colors = /** @class */ function () { function Table05Entry01Colors() {} //Bg Table05Entry01Colors.bgWhite = 0xffff9c; Table05Entry01Colors.bgLightGrey = 0x94b5ff; Table05Entry01Colors.bgDarkGrey = 0x639473; Table05Entry01Colors.bgBlack = 0x003a3a; // Obj 0 Table05Entry01Colors.obj0White = 0xffc542; Table05Entry01Colors.obj0LightGrey = 0xffd600; Table05Entry01Colors.obj0DarkGrey = 0x943a00; Table05Entry01Colors.obj0Black = 0x4a0000; // Obj1 Table05Entry01Colors.obj1White = 0xffffff; Table05Entry01Colors.obj1LightGrey = 0xff8484; Table05Entry01Colors.obj1DarkGrey = 0x943a3a; Table05Entry01Colors.obj1Black = 0x000000; return Table05Entry01Colors; }(); // Tennis var Table05Entry02Colors = /** @class */ function () { function Table05Entry02Colors() {} //Bg Table05Entry02Colors.bgWhite = 0x6bff00; Table05Entry02Colors.bgLightGrey = 0xffffff; Table05Entry02Colors.bgDarkGrey = 0xff524a; Table05Entry02Colors.bgBlack = 0x000000; // Obj 0 Table05Entry02Colors.obj0White = 0xffffff; Table05Entry02Colors.obj0LightGrey = 0xffffff; Table05Entry02Colors.obj0DarkGrey = 0x63a5ff; Table05Entry02Colors.obj0Black = 0x0000ff; // Obj1 Table05Entry02Colors.obj1White = 0xffffff; Table05Entry02Colors.obj1LightGrey = 0xffad63; Table05Entry02Colors.obj1DarkGrey = 0x843100; Table05Entry02Colors.obj1Black = 0x000000; return Table05Entry02Colors; }(); // Kirby's Dream Land var Table05Entry08Colors = /** @class */ function () { function Table05Entry08Colors() {} //Bg Table05Entry08Colors.bgWhite = 0xa59cff; Table05Entry08Colors.bgLightGrey = 0xffff00; Table05Entry08Colors.bgDarkGrey = 0x006300; Table05Entry08Colors.bgBlack = 0x000000; // Obj 0 Table05Entry08Colors.obj0White = 0xff6352; Table05Entry08Colors.obj0LightGrey = 0xd60000; Table05Entry08Colors.obj0DarkGrey = 0x630000; Table05Entry08Colors.obj0Black = 0x000000; // Obj1 Table05Entry08Colors.obj1White = 0x0000ff; Table05Entry08Colors.obj1LightGrey = 0xffffff; Table05Entry08Colors.obj1DarkGrey = 0xffff7b; Table05Entry08Colors.obj1Black = 0x0084ff; return Table05Entry08Colors; }(); // Super Mario Land 2 BAYYYBEEE var Table05Entry09Colors = /** @class */ function () { function Table05Entry09Colors() {} //Bg Table05Entry09Colors.bgWhite = 0xffffce; Table05Entry09Colors.bgLightGrey = 0x63efef; Table05Entry09Colors.bgDarkGrey = 0x9c8431; Table05Entry09Colors.bgBlack = 0x5a5a5a; // Obj 0 Table05Entry09Colors.obj0White = 0xffffff; Table05Entry09Colors.obj0LightGrey = 0xff7300; Table05Entry09Colors.obj0DarkGrey = 0x944200; Table05Entry09Colors.obj0Black = 0x000000; // Obj1 Table05Entry09Colors.obj1White = 0xffffff; Table05Entry09Colors.obj1LightGrey = 0x63a5ff; Table05Entry09Colors.obj1DarkGrey = 0x0000ff; Table05Entry09Colors.obj1Black = 0x000000; return Table05Entry09Colors; }(); // Link's Awakening var Table05Entry11Colors = /** @class */ function () { function Table05Entry11Colors() {} // Bg Table05Entry11Colors.bgWhite = 0xffffff; Table05Entry11Colors.bgLightGrey = 0xff8484; Table05Entry11Colors.bgDarkGrey = 0x943a3a; Table05Entry11Colors.bgBlack = 0x000000; // Obj 0 Table05Entry11Colors.obj0White = 0xffffff; Table05Entry11Colors.obj0LightGrey = 0x00ff00; Table05Entry11Colors.obj0DarkGrey = 0x318400; Table05Entry11Colors.obj0Black = 0x004a00; // Obj1 Table05Entry11Colors.obj1White = 0xffffff; Table05Entry11Colors.obj1LightGrey = 0x63a5ff; Table05Entry11Colors.obj1DarkGrey = 0x0000ff; Table05Entry11Colors.obj1Black = 0x000000; return Table05Entry11Colors; }(); // Metroid 2 var Table05Entry14Colors = /** @class */ function () { function Table05Entry14Colors() {} //Bg Table05Entry14Colors.bgWhite = 0xffffff; Table05Entry14Colors.bgLightGrey = 0x63a5ff; Table05Entry14Colors.bgDarkGrey = 0x0000ff; Table05Entry14Colors.bgBlack = 0x000000; // Obj 0 Table05Entry14Colors.obj0White = 0xffff00; Table05Entry14Colors.obj0LightGrey = 0xff0000; Table05Entry14Colors.obj0DarkGrey = 0x630000; Table05Entry14Colors.obj0Black = 0x000000; // Obj1 Table05Entry14Colors.obj1White = 0xffffff; Table05Entry14Colors.obj1LightGrey = 0x7bff31; Table05Entry14Colors.obj1DarkGrey = 0x008400; Table05Entry14Colors.obj1Black = 0x000000; return Table05Entry14Colors; }(); // WarioLand 2 var Table05Entry15Colors = /** @class */ function () { function Table05Entry15Colors() {} //Bg Table05Entry15Colors.bgWhite = 0xffffff; Table05Entry15Colors.bgLightGrey = 0xadad84; Table05Entry15Colors.bgDarkGrey = 0x42737b; Table05Entry15Colors.bgBlack = 0x000000; // Obj 0 Table05Entry15Colors.obj0White = 0xffffff; Table05Entry15Colors.obj0LightGrey = 0xffad63; Table05Entry15Colors.obj0DarkGrey = 0xffad63; Table05Entry15Colors.obj0Black = 0x000000; // Obj1 Table05Entry15Colors.obj1White = 0xffffff; Table05Entry15Colors.obj1LightGrey = 0x63a5ff; Table05Entry15Colors.obj1DarkGrey = 0x0000ff; Table05Entry15Colors.obj1Black = 0x000000; return Table05Entry15Colors; }(); // File for all of the logic of setting gameboy color plaettes // Current / exported color var Colors = /** @class */ function () { function Colors() {} //Bg Colors.bgWhite = WasmBoyGBColors.bgWhite; Colors.bgLightGrey = WasmBoyGBColors.bgLightGrey; Colors.bgDarkGrey = WasmBoyGBColors.bgDarkGrey; Colors.bgBlack = WasmBoyGBColors.bgBlack; // Obj 0 Colors.obj0White = WasmBoyGBColors.obj0White; Colors.obj0LightGrey = WasmBoyGBColors.obj0LightGrey; Colors.obj0DarkGrey = WasmBoyGBColors.obj0DarkGrey; Colors.obj0Black = WasmBoyGBColors.obj0Black; // Obj1 Colors.obj1White = WasmBoyGBColors.obj1White; Colors.obj1LightGrey = WasmBoyGBColors.obj1LightGrey; Colors.obj1DarkGrey = WasmBoyGBColors.obj1DarkGrey; Colors.obj1Black = WasmBoyGBColors.obj1Black; return Colors; }(); // Inlined because closure compiler inlines function initializeColors() { setManualColorizationPalette(0); if (Cpu.GBCEnabled) { // Don't need to continue this if a GBC game return; } if (Cpu.BootROMEnabled) { if (!Cpu.GBCEnabled) { // GB return; } } // Do some automatic color palette swapping if we have a loaded ROM var titleChecksum = 0x00; for (var i = 0x0134; i <= 0x0143; i++) { titleChecksum += eightBitLoadFromGBMemory(i); } // Set the colorization for the game automatically if assigned // https://tcrf.net/Notes:Game_Boy_Color_Bootstrap_ROM var hash = titleChecksum & 0xff; setHashColorizationPalette(hash); } function getRedFromHexColor(color) { return (color & 0xff0000) >> 16; } function getGreenFromHexColor(color) { return (color & 0x00ff00) >> 8; } function getBlueFromHexColor(color) { return color & 0x0000ff; } // Function to set the colorization // By manually pressing buttons function setManualColorizationPalette(colorizationId) { // Set the colorizationId clockwise according to: // https://en.wikipedia.org/wiki/Game_Boy_Color switch (colorizationId) { case 0: Colors.bgWhite = WasmBoyGBColors.bgWhite; Colors.bgLightGrey = WasmBoyGBColors.bgLightGrey; Colors.bgDarkGrey = WasmBoyGBColors.bgDarkGrey; Colors.bgBlack = WasmBoyGBColors.bgBlack; Colors.obj0White = WasmBoyGBColors.obj0White; Colors.obj0LightGrey = WasmBoyGBColors.obj0LightGrey; Colors.obj0DarkGrey = WasmBoyGBColors.obj0DarkGrey; Colors.obj0Black = WasmBoyGBColors.obj0Black; Colors.obj1White = WasmBoyGBColors.obj1White; Colors.obj1LightGrey = WasmBoyGBColors.obj1LightGrey; Colors.obj1DarkGrey = WasmBoyGBColors.obj1DarkGrey; Colors.obj1Black = WasmBoyGBColors.obj1Black; break; case 1: // Up, Brown Colors.bgWhite = BrownColors.bgWhite; Colors.bgLightGrey = BrownColors.bgLightGrey; Colors.bgDarkGrey = BrownColors.bgDarkGrey; Colors.bgBlack = BrownColors.bgBlack; Colors.obj0White = BrownColors.obj0White; Colors.obj0LightGrey = BrownColors.obj0LightGrey; Colors.obj0DarkGrey = BrownColors.obj0DarkGrey; Colors.obj0Black = BrownColors.obj0Black; Colors.obj1White = BrownColors.obj1White; Colors.obj1LightGrey = BrownColors.obj1LightGrey; Colors.obj1DarkGrey = BrownColors.obj1DarkGrey; Colors.obj1Black = BrownColors.obj1Black; break; case 2: // Up + A, Red Colors.bgWhite = RedColors.bgWhite; Colors.bgLightGrey = RedColors.bgLightGrey; Colors.bgDarkGrey = RedColors.bgDarkGrey; Colors.bgBlack = RedColors.bgBlack; Colors.obj0White = RedColors.obj0White; Colors.obj0LightGrey = RedColors.obj0LightGrey; Colors.obj0DarkGrey = RedColors.obj0DarkGrey; Colors.obj0Black = RedColors.obj0Black; Colors.obj1White = RedColors.obj1White; Colors.obj1LightGrey = RedColors.obj1LightGrey; Colors.obj1DarkGrey = RedColors.obj1DarkGrey; Colors.obj1Black = RedColors.obj1Black; break; case 3: // Up + B, DarkBrown Colors.bgWhite = DarkBrownColors.bgWhite; Colors.bgLightGrey = DarkBrownColors.bgLightGrey; Colors.bgDarkGrey = DarkBrownColors.bgDarkGrey; Colors.bgBlack = DarkBrownColors.bgBlack; Colors.obj0White = DarkBrownColors.obj0White; Colors.o