Newer
Older
import {
default as wasm,
Chip8Neo
} from "./chip_ahoyto.js";
const PIXEL_SET_COLOR = 0x50cb93ff;
const PIXEL_UNSET_COLOR = 0x1b1a17ff;
const LOGIC_HZ = 480;
const TIMER_HZ = 60;
const VISUAL_HZ = 60;
const ROM = "res/roms/pong.ch8";
canvas: null,
canvasScaled: null,
canvasCtx: null,
canvasScaledCtx: null,
image: null,
videoBuff: null
};
(async () => {
// initializes the WASM module, this is required
// so that the global symbols become available
await wasm();
// initializes the canvas sub-sytem
initCanvas();
registerDrop();
// loads the ROM data and converts it into the
// target u8 array bufffer
const response = await fetch(ROM);
const blob = await response.blob();
const arrayBuffer = await blob.arrayBuffer();
const data = new Uint8Array(arrayBuffer);
// creates the CHIP-8 instance and resets it
state.chip8 = new Chip8Neo();
state.chip8.reset_hard_ws();
state.chip8.load_rom_ws(data);
// runs the sequence as an infinite loop, running
// the associated CPU cycles accordingly
while (true) {
const ratioLogic = LOGIC_HZ / VISUAL_HZ;
for(let i = 0; i < ratioLogic; i++) {
state.chip8.clock_ws();
}
const ratioTimer = TIMER_HZ / VISUAL_HZ;
for(let i = 0; i < ratioTimer; i++) {
state.chip8.clock_dt_ws();
state.chip8.clock_st_ws();
}
// updates the canvas object with the new
// visual information comming in
updateCanvas(state.chip8.vram_ws());
// waits a little bit for the next frame to be draw
// @todo need to define target time for draw
await new Promise((resolve, reject) => {
setTimeout(resolve, 1000 / VISUAL_HZ);
const registerDrop = () => {
document.addEventListener("drop", async (e) => {
e.preventDefault();
e.stopPropagation();
if (!e.dataTransfer.files) return;
const file = e.dataTransfer.files[0];
const arrayBuffer = await file.arrayBuffer();
const data = new Uint8Array(arrayBuffer);
state.chip8.reset_hard_ws();
state.chip8.load_rom_ws(data);
});
document.addEventListener("dragover", async (e) => {
e.preventDefault();
e.stopPropagation();
console.info("draging over");
});
}
const initCanvas = () => {
// initializes the off-screen canvas that is going to be
// used in the drawing proces
state.canvas = document.createElement("canvas");
state.canvas.width = 64;
state.canvas.height = 32;
state.canvasCtx = state.canvas.getContext("2d");
state.canvasScaled = document.getElementById("chip-canvas");
state.canvasScaledCtx = state.canvasScaled.getContext("2d");
state.canvasScaledCtx.scale(state.canvasScaled.width / state.canvas.width, state.canvasScaled.height / state.canvas.height);
state.canvasScaledCtx.imageSmoothingEnabled = false;
state.image = state.canvasCtx.createImageData(state.canvas.width, state.canvas.height);
state.videoBuff = new DataView(state.image.data.buffer);
}
const updateCanvas = (pixels) => {
for (let i = 0; i < pixels.length; i++) {
state.videoBuff.setUint32(i * 4, pixels[i] ? PIXEL_SET_COLOR : PIXEL_UNSET_COLOR);
}
state.canvasCtx.putImageData(state.image, 0, 0);
state.canvasScaledCtx.drawImage(state.canvas, 0, 0);
}