diff options
Diffstat (limited to 'cmd/gones')
| -rw-r--r-- | cmd/gones/main.go | 152 |
1 files changed, 0 insertions, 152 deletions
diff --git a/cmd/gones/main.go b/cmd/gones/main.go deleted file mode 100644 index 0a1fbe7..0000000 --- a/cmd/gones/main.go +++ /dev/null @@ -1,152 +0,0 @@ -package main - -import ( - "fmt" - "log" - "os" - "path/filepath" - "runtime" - "time" - - "github.com/veandco/go-sdl2/sdl" - - "crecher.net/gones/v2/cart" - "crecher.net/gones/v2/nes" - "crecher.net/gones/v2/ppu" -) - -const ( - windowScale = 3 - - // nes: 1789773 cpu cycles per sec / 29780.5 cycles per frame - framesPerSecond = 60.0988 -) - -func init() { - // sdl wants to be driven from the main thread - runtime.LockOSThread() -} - -func main() { - if len(os.Args) != 2 { - fmt.Fprintf(os.Stderr, "usage: %s <rom.nes>\n", os.Args[0]) - os.Exit(2) - } - if err := run(os.Args[1]); err != nil { - log.Fatal(err) - } -} - -func run(romPath string) error { - c, err := cart.Load(romPath) - if err != nil { - return err - } - console := nes.New(c) - name := filepath.Base(romPath) - - if err := sdl.Init(sdl.INIT_VIDEO); err != nil { - return err - } - defer sdl.Quit() - - window, err := sdl.CreateWindow("gones - "+name, - sdl.WINDOWPOS_CENTERED, sdl.WINDOWPOS_CENTERED, - ppu.ScreenWidth*windowScale, ppu.ScreenHeight*windowScale, - sdl.WINDOW_SHOWN|sdl.WINDOW_RESIZABLE) - if err != nil { - return err - } - defer window.Destroy() - - renderer, err := sdl.CreateRenderer(window, -1, sdl.RENDERER_ACCELERATED|sdl.RENDERER_PRESENTVSYNC) - if err != nil { - return err - } - defer renderer.Destroy() - - // the window can be resized freely, sdl scales (and letterboxes) the 256x240 picture - if err := renderer.SetLogicalSize(ppu.ScreenWidth, ppu.ScreenHeight); err != nil { - return err - } - - // framebuffer is ARGB8888, streaming since we rewrite it every frame - texture, err := renderer.CreateTexture(sdl.PIXELFORMAT_ARGB8888, sdl.TEXTUREACCESS_STREAMING, - ppu.ScreenWidth, ppu.ScreenHeight) - if err != nil { - return err - } - defer texture.Destroy() - - fps := framesPerSecond // a variable, a constant would have to be a whole number of nanoseconds - frameTime := time.Duration(float64(time.Second) / fps) - next := time.Now() - fpsStart, frames := next, 0 - jamShown := false - - for { - for e := sdl.PollEvent(); e != nil; e = sdl.PollEvent() { - switch ev := e.(type) { - case *sdl.QuitEvent: - return nil - case *sdl.KeyboardEvent: - if ev.Type == sdl.KEYDOWN && ev.Keysym.Sym == sdl.K_ESCAPE { - return nil - } - } - } - - console.SetButtons(0, heldButtons()) - console.StepFrame() - - // UpdateRGBA multiplies the pitch by 4 itself, so this is in pixels, not bytes - if err := texture.UpdateRGBA(nil, console.PPU.Framebuffer(), ppu.ScreenWidth); err != nil { - return err - } - renderer.Clear() - renderer.Copy(texture, nil, nil) - renderer.Present() - - if console.CPU.Jammed && !jamShown { - window.SetTitle("gones - " + name + " - CPU jammed (reset needed)") - jamShown = true - } - - frames++ - if elapsed := time.Since(fpsStart); elapsed >= time.Second && !jamShown { - window.SetTitle(fmt.Sprintf("gones - %s - %.1f fps", name, float64(frames)/elapsed.Seconds())) - fpsStart, frames = time.Now(), 0 - } - - // vsync alone would run too fast on a 120/144hz monitor, so pace to the nes frame rate - next = next.Add(frameTime) - if wait := time.Until(next); wait > 0 { - time.Sleep(wait) - } else if wait < -100*time.Millisecond { - next = time.Now() // fell far behind (window drag etc), don't try to catch up - } - } -} - -// keyboard layout for controller 1 -var keyMap = map[sdl.Scancode]uint8{ - sdl.SCANCODE_X: nes.ButtonA, - sdl.SCANCODE_Y: nes.ButtonB, - sdl.SCANCODE_RSHIFT: nes.ButtonSelect, - sdl.SCANCODE_RETURN: nes.ButtonStart, - sdl.SCANCODE_UP: nes.ButtonUp, - sdl.SCANCODE_DOWN: nes.ButtonDown, - sdl.SCANCODE_LEFT: nes.ButtonLeft, - sdl.SCANCODE_RIGHT: nes.ButtonRight, -} - -func heldButtons() uint8 { - keys := sdl.GetKeyboardState() - var b uint8 - for scancode, button := range keyMap { - if keys[scancode] != 0 { - b |= button - } - } - return b -} |