|
|
@@ -0,0 +1,67 @@
|
|
|
+const SCREEN_WIDTH = 256;
|
|
|
+const SCREEN_HEIGHT = 240;
|
|
|
+const SAMPLE_REDUCTION = 4;
|
|
|
+
|
|
|
+const EventEmitter = require('events')
|
|
|
+const fs = require('fs')
|
|
|
+const jsnes = require('jsnes')
|
|
|
+const move = require('move-terminal-cursor')
|
|
|
+
|
|
|
+const chunk = (a, l) => Array(Math.ceil(a.length / l)).fill().map((_, i) => (a.slice ? a.slice(i * l, i * l + l) : a.substr(i * l, i * l + 1)))
|
|
|
+const sample = (a, n) => Array(Math.floor(a.length / n)).fill().map((_, i) => a[i * n])
|
|
|
+
|
|
|
+class Game extends EventEmitter {
|
|
|
+ constructor() {
|
|
|
+ super()
|
|
|
+ const rom = fs.readFileSync('./Super Mario Bros. (World).nes', 'binary')
|
|
|
+ this.nes = new jsnes.NES({
|
|
|
+ onFrame: this.onFrame.bind(this)
|
|
|
+ })
|
|
|
+ this.nes.loadROM(rom)
|
|
|
+ this.frameCount = 0
|
|
|
+ this.packetBuffer = new ArrayBuffer(256 * 4 + SCREEN_WIDTH * SCREEN_HEIGHT)
|
|
|
+ this.paletteBuffer = new Uint32Array(this.packetBuffer)
|
|
|
+ this.pixelBuffer = new Uint8ClampedArray(this.packetBuffer, 256 * 4)
|
|
|
+ this.frameBuffer = new ArrayBuffer(SCREEN_WIDTH * SCREEN_HEIGHT * 4)
|
|
|
+ this.screen32 = new Uint32Array(this.frameBuffer)
|
|
|
+ this.nes.ppu.buffer = this.screen32
|
|
|
+ this.frameBytes = new Uint8ClampedArray(this.frameBuffer)
|
|
|
+ }
|
|
|
+
|
|
|
+ onFrame(frameBuffer) {
|
|
|
+// if (this.frameCount++ % SAMPLE_REDUCTION) {
|
|
|
+ const colorMap = new Map()
|
|
|
+ for (let i = 0; i < 256; i++) {
|
|
|
+ this.paletteBuffer[i] = this.nes.ppu.palTable.curTable[i]
|
|
|
+ colorMap.set(this.nes.ppu.palTable.curTable[i], i)
|
|
|
+ }
|
|
|
+ for (let i = 0; i < this.screen32.length; i++) {
|
|
|
+ this.pixelBuffer[i] = colorMap.get(this.screen32[i])
|
|
|
+ }
|
|
|
+ this.emit('frame', this.packetBuffer)
|
|
|
+// }
|
|
|
+
|
|
|
+
|
|
|
+ // if (true) {//(frameCount++ % 32 === 0) {
|
|
|
+ // //move('toPos', {row: 1, col: 1})
|
|
|
+ // const lines = sample(chunk(frameBuffer, SCREEN_WIDTH), SAMPLE_REDUCTION)
|
|
|
+ // .map(line => sample(line, SAMPLE_REDUCTION))
|
|
|
+ // //console.log(lines.map(l => Buffer.from(l).toString('hex')).join('\n'))
|
|
|
+
|
|
|
+ // // console.log('\n\n\n' + chunk(Buffer.from(frameBuffer).toString('hex'), SCREEN_WIDTH * 2).join('\n'))
|
|
|
+ // }
|
|
|
+ }
|
|
|
+
|
|
|
+ start() {
|
|
|
+ if (!this.timer) this.timer = setInterval(() => this.nes.frame(), 1000 / 60)
|
|
|
+ }
|
|
|
+
|
|
|
+ stop() {
|
|
|
+ if (this.timer) {
|
|
|
+ clearInterval(this.timer)
|
|
|
+ this.timer = null
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+module.exports = Game
|