chip8-emulator/main.go
2022-03-01 21:45:06 -03:00

140 lines
2.4 KiB
Go

package main
import (
"bytes"
_ "embed"
"log"
"time"
"github.com/hajimehoshi/ebiten/v2"
"github.com/hajimehoshi/ebiten/v2/audio"
"github.com/hajimehoshi/ebiten/v2/audio/wav"
"github.com/tangzero/chip8-emulator/chip8"
)
//go:embed test_opcode.ch8
var DefaultROM []byte
const (
ScreenScale = 20
Width = chip8.Width * ScreenScale
Height = chip8.Height * ScreenScale
)
type State = int
const (
LoadingState State = iota
RunningState
)
// Keyboard Layout
// 1 2 3 C
// 4 5 6 D
// 7 8 9 E
// A 0 B F
var KeyMapping = []ebiten.Key{
ebiten.KeyX,
ebiten.Key1,
ebiten.Key2,
ebiten.Key3,
ebiten.KeyQ,
ebiten.KeyW,
ebiten.KeyE,
ebiten.KeyA,
ebiten.KeyS,
ebiten.KeyD,
ebiten.KeyZ,
ebiten.KeyC,
ebiten.Key4,
ebiten.KeyR,
ebiten.KeyF,
ebiten.KeyV,
}
type GUI struct {
State State
Emulator *chip8.Emulator
}
func (gui *GUI) Run() {
for {
gui.Emulator.Cycle()
time.Sleep(time.Millisecond * 2)
}
}
func (gui *GUI) Update() error {
if ebiten.IsKeyPressed(ebiten.KeyEscape) {
gui.Emulator.Reset()
}
switch gui.State {
case LoadingState:
go gui.Run()
gui.State = RunningState
case RunningState:
gui.Emulator.UpdateTimers()
}
return nil
}
func (gui *GUI) Draw(screen *ebiten.Image) {
frame := ebiten.NewImageFromImage(gui.Emulator.Display)
operation := new(ebiten.DrawImageOptions)
operation.GeoM.Scale(ScreenScale, ScreenScale)
screen.DrawImage(frame, operation)
}
func (gui *GUI) Layout(int, int) (int, int) {
return Width, Height
}
func KeyPressed(key uint8) bool {
return ebiten.IsKeyPressed(KeyMapping[key])
}
func SoundPlayer(sound []byte) (func(), func()) {
stream, err := wav.DecodeWithSampleRate(chip8.SampleRate, bytes.NewReader(sound))
assert(err)
player, err := audio.NewContext(chip8.SampleRate).NewPlayer(stream)
assert(err)
player.SetVolume(0.5)
return PlaySound(player), StopSound(player)
}
func PlaySound(player *audio.Player) func() {
return func() {
if player.IsPlaying() {
return
}
player.Play()
}
}
func StopSound(player *audio.Player) func() {
return func() {
player.Pause()
assert(player.Rewind())
}
}
func main() {
rom := LoadROM()
gui := GUI{}
gui.State = LoadingState
gui.Emulator = chip8.NewEmulator(KeyPressed, SoundPlayer)
gui.Emulator.LoadROM(rom)
ebiten.SetWindowSize(Width, Height)
ebiten.SetWindowTitle("CHIP-8 : " + rom.Name)
assert(ebiten.RunGame(&gui))
}
func assert(err error) {
if err != nil {
log.Panic(err)
}
}