func main() { flags := flag.Args() if len(flags) != 1 { fmt.Println("Chippy - CHIP8 Emulator") fmt.Println("Copyright (C) 2016 Andreas T Jonsson") fmt.Printf("Version: %v\n\n", chip8.Version) fmt.Printf("usage: chippy [program]\n\n") return } if err := termbox.Init(); err != nil { panic(err) } defer termbox.Close() termbox.SetOutputMode(termbox.OutputNormal) termbox.Clear(termbox.ColorDefault, termbox.ColorDefault) termbox.Sync() m := machine{programPath: flags[0], cpuSpeedHz: defaultCPUSpeed} sys := chip8.NewSystem(&m) go func() { for _ = range time.Tick(time.Second / m.cpuSpeedHz) { termbox.Interrupt() } }() for { switch ev := termbox.PollEvent(); ev.Type { case termbox.EventKey: switch ev.Key { case termbox.KeyEsc: return } case termbox.EventInterrupt: sys.Refresh() if err := sys.Step(); err != nil { panic(err) } } } }
func start() { name, buffer := openFile() document := js.Global.Get("document") document.Set("onkeydown", func(e *js.Object) { kb.Lock() kb.keys[e.Get("keyCode").Int()] = true kb.Unlock() }) document.Set("onkeyup", func(e *js.Object) { kb.Lock() kb.keys[e.Get("keyCode").Int()] = false kb.Unlock() }) // Create canvas. canvas := document.Call("createElement", "canvas") canvas.Call("setAttribute", "width", strconv.Itoa(imgWidth)) canvas.Call("setAttribute", "height", strconv.Itoa(imgHeight)) canvas.Get("style").Set("width", strconv.Itoa(imgWidth*3)+"px") canvas.Get("style").Set("height", strconv.Itoa(imgHeight*3)+"px") document.Get("body").Call("appendChild", canvas) m := machine{programName: name, program: buffer, canvas: canvas, cpuSpeedHz: defaultCPUSpeed} updateTitle(&m) // Create audio. audioClass := js.Global.Get("AudioContext") if audioClass.String() == "undefined" { audioClass = js.Global.Get("webkitAudioContext") } if audioClass.String() != "undefined" { audioContext := audioClass.New() oscillator := audioContext.Call("createOscillator") gain := audioContext.Call("createGain") oscillator.Call("connect", gain) oscillator.Set("type", "square") oscillator.Get("frequency").Set("value", 500) oscillator.Call("start", "0") m.muteAudio = func(mute bool) { if audioClass != nil { dest := audioContext.Get("destination") if mute { gain.Call("disconnect", dest) } else { gain.Call("connect", dest) } } } } else { m.muteAudio = func(mute bool) {} } go func() { sys := chip8.NewSystem(&m) tickRender := time.Tick(time.Second / 32) tickCPU := time.Tick(time.Second / m.cpuSpeedHz) for { select { case <-tickRender: sys.Refresh() case <-tickCPU: if err := sys.Step(); err != nil { js.Global.Call("alert", err.Error()) } } } }() }
func main() { flags := flag.Args() if len(flags) != 1 { fmt.Println("Chippy - CHIP8 Emulator") fmt.Println("Copyright (C) 2016 Andreas T Jonsson") fmt.Printf("Version: %v\n\n", chip8.Version) fmt.Printf("usage: chippy [program]\n\n") return } sdl.Init(sdl.INIT_EVERYTHING) defer sdl.Quit() window, err := sdl.CreateWindow("", sdl.WINDOWPOS_UNDEFINED, sdl.WINDOWPOS_UNDEFINED, 800, 600, sdl.WINDOW_SHOWN) if err != nil { log.Fatalln(err) } defer window.Destroy() renderer, err := sdl.CreateRenderer(window, -1, sdl.RENDERER_ACCELERATED) if err != nil { log.Fatalln(err) } defer renderer.Destroy() renderer.SetLogicalSize(800, 600) renderer.SetDrawColor(0, 0, 0, 255) texture, err := renderer.CreateTexture(sdl.PIXELFORMAT_BGR24, sdl.TEXTUREACCESS_STREAMING, 64, 32) if err != nil { log.Fatalln(err) } var specIn sdl.AudioSpec specIn.Channels = 1 specIn.Format = sdl.AUDIO_U8 specIn.Freq = 11025 specIn.Samples = 4096 specIn.Callback = sdl.AudioCallback(C.audioCallback) if err := sdl.OpenAudio(&specIn, nil); err != nil { log.Fatalln(err) } defer sdl.CloseAudio() m := &machine{ programPath: flags[0], cpuSpeedHz: defaultCPUSpeed, texture: texture, renderer: renderer, videoWidth: 64, video: make([]byte, 64*32*3), } defer func() { m.texture.Destroy() }() updateTitle(window, m) sys := chip8.NewSystem(m) cpuSpeedHz := m.cpuSpeedHz tickRender := time.Tick(time.Second / 65) tickCPU := time.Tick(time.Second / cpuSpeedHz) for { select { case <-tickRender: for event := sdl.PollEvent(); event != nil; event = sdl.PollEvent() { switch t := event.(type) { case *sdl.QuitEvent: return case *sdl.KeyUpEvent: switch t.Keysym.Sym { case sdl.K_ESCAPE: return case sdl.K_BACKSPACE: sys.Reset() case sdl.K_g: toggleFullscreen(window) case sdl.K_p: if m.cpuSpeedHz < 2000 { m.cpuSpeedHz += 100 } case sdl.K_m: if m.cpuSpeedHz > 100 { m.cpuSpeedHz -= 100 } case sdl.K_d: if t.Keysym.Mod&sdl.KMOD_CTRL != 0 { dumpSystem(sys, flags[0]) } } } } if cpuSpeedHz != m.cpuSpeedHz { cpuSpeedHz = m.cpuSpeedHz updateTitle(window, m) tickCPU = time.Tick(time.Second / m.cpuSpeedHz) } sys.Refresh() renderer.Clear() texture.Update(nil, unsafe.Pointer(&m.video[0]), m.videoWidth*3) renderer.Copy(m.texture, nil, nil) renderer.Present() case <-tickCPU: if err := sys.Step(); err != nil { dumpSystem(sys, flags[0]) log.Fatalln(err) } } } }