-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Support loading ROM files through the UI
- Loading branch information
Showing
14 changed files
with
365 additions
and
163 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
import { Joypad } from "../../main"; | ||
import { Screen } from "../screen"; | ||
import { Store, store } from "../store"; | ||
import { Text } from "./text"; | ||
|
||
export const ControllerMapping = (button: Joypad) => { | ||
let buttonName: keyof Store['controls']; | ||
let isListening = false; | ||
|
||
switch (button) { | ||
case Joypad.UP: | ||
buttonName = 'up'; | ||
break; | ||
case Joypad.LEFT: | ||
buttonName = 'left'; | ||
break; | ||
case Joypad.DOWN: | ||
buttonName = 'down'; | ||
break; | ||
case Joypad.RIGHT: | ||
buttonName = 'right'; | ||
break; | ||
case Joypad.A: | ||
buttonName = 'a'; | ||
break; | ||
case Joypad.B: | ||
buttonName = 'b'; | ||
break; | ||
case Joypad.START: | ||
buttonName = 'start'; | ||
break; | ||
case Joypad.SELECT: | ||
buttonName = 'select'; | ||
break; | ||
} | ||
|
||
const getText = () => { | ||
const btnName = `${Joypad[button].padEnd(6, ' ')}`; | ||
|
||
if (isListening) { | ||
return `${btnName} > ...`; | ||
} | ||
|
||
let keyName = store.ref.controls[buttonName]; | ||
if (keyName === ' ') { | ||
keyName = 'space'; | ||
} | ||
|
||
|
||
return `${btnName} > ${keyName.toUpperCase()}`; | ||
}; | ||
|
||
const text = Text(getText()); | ||
|
||
return { | ||
...text, | ||
render(x: number, y: number, screen: Screen): void { | ||
text.update(getText()); | ||
text.render(x, y, screen); | ||
}, | ||
onKeyDown(key: string) { | ||
if (isListening) { | ||
store.ref.controls[buttonName] = key; | ||
isListening = false; | ||
text.update(getText()); | ||
} else if (key === 'Enter') { | ||
isListening = true; | ||
} | ||
}, | ||
}; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import { Joypad } from "../../main"; | ||
import { ControllerMapping } from "./ControllerMapping"; | ||
import { VMenu } from "./VMenu"; | ||
|
||
export const Controls = () => { | ||
const ctrls = [ | ||
Joypad.UP, | ||
Joypad.LEFT, | ||
Joypad.DOWN, | ||
Joypad.RIGHT, | ||
Joypad.A, | ||
Joypad.B, | ||
Joypad.START, | ||
Joypad.SELECT, | ||
].map(ControllerMapping); | ||
|
||
const controlsList = VMenu(ctrls); | ||
|
||
const onKeyDown = (key: string) => { | ||
if (controlsList.state.activeIndex !== -1) { | ||
ctrls[controlsList.state.activeIndex].onKeyDown(key); | ||
} | ||
}; | ||
|
||
return { | ||
...controlsList, | ||
onKeyDown, | ||
}; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
import { Component } from "./component"; | ||
|
||
const HStack = (x: number, y: number, items: Component[]): Component => { | ||
|
||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
import { Component, WIDTH } from "./component"; | ||
import { drawText } from "./text"; | ||
|
||
export const HMenu = ( | ||
items: Component<{ active: boolean }>[], | ||
initialIndex = 0, | ||
): Component<{ active: boolean, activeIndex: number }> & { | ||
next(): void, | ||
prev(): void, | ||
} => { | ||
const state = { active: true, activeIndex: initialIndex }; | ||
items[initialIndex].state.active = true; | ||
// compute the x offset for each item so that they are centered | ||
// on the screen | ||
const xOffsets: number[] = []; | ||
let maxLength = 0; | ||
let x0 = 0; | ||
|
||
for (let i = 0; i < items.length; i++) { | ||
const item = items[i]; | ||
xOffsets.push(Math.round(x0 + item.width / 2)); | ||
x0 += item.width + 1; | ||
maxLength = Math.max(maxLength, item.width); | ||
} | ||
|
||
const setActiveIndex = (index: number): void => { | ||
if (state.active && index !== state.activeIndex) { | ||
items[state.activeIndex].state.active = false; | ||
items[index].state.active = true; | ||
state.activeIndex = index; | ||
} | ||
}; | ||
|
||
setActiveIndex(initialIndex); | ||
|
||
return { | ||
state, | ||
width: WIDTH, | ||
height: 1, | ||
render(_x, y, screen): void { | ||
let x0 = WIDTH / 2 - xOffsets[state.activeIndex]; | ||
|
||
for (let i = 0; i < items.length; i++) { | ||
const item = items[i]; | ||
item.render(x0, y, screen); | ||
x0 += item.width + 1; | ||
} | ||
|
||
if (state.activeIndex > 0) { | ||
drawText(0, y, '< ', screen); | ||
} | ||
|
||
if (state.activeIndex < items.length - 1) { | ||
drawText(WIDTH - 2, y, ' >', screen); | ||
} | ||
}, | ||
next(): void { | ||
setActiveIndex(Math.min(state.activeIndex + 1, items.length - 1)); | ||
}, | ||
prev(): void { | ||
setActiveIndex(Math.max(state.activeIndex - 1, 0)); | ||
}, | ||
}; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import { directoryOpen, fileOpen } from "browser-fs-access"; | ||
import { VMenu } from "./VMenu"; | ||
import { Text } from "./text"; | ||
import { store } from "../store"; | ||
|
||
export const Library = () => { | ||
const list = VMenu([ | ||
Text('Load ROM file'), | ||
Text('Load ROM dir.'), | ||
]); | ||
|
||
const loadRomFile = async () => { | ||
const file = await fileOpen({ | ||
description: 'NES ROM file', | ||
extensions: ['.nes'], | ||
mimeTypes: ['application/octet-stream'], | ||
multiple: false, | ||
startIn: 'downloads', | ||
}); | ||
|
||
const bytes = Array.from(new Uint8Array(await file.arrayBuffer())); | ||
store.set('rom', bytes); | ||
}; | ||
|
||
const loadRomDir = async () => { | ||
const dir = await directoryOpen({ | ||
recursive: false, | ||
mode: 'read', | ||
startIn: 'downloads', | ||
}); | ||
|
||
console.log(dir); | ||
}; | ||
|
||
const onClickMappings = [ | ||
loadRomFile, | ||
loadRomDir, | ||
]; | ||
|
||
const onKeyDown = (key: string): void => { | ||
if (list.state.activeIndex !== -1 && key === 'Enter') { | ||
onClickMappings[list.state.activeIndex](); | ||
} | ||
}; | ||
|
||
return { | ||
...list, | ||
onKeyDown, | ||
}; | ||
}; |
Oops, something went wrong.