diff --git a/gb/console.go b/gb/console.go index e66ebe6..6397a4a 100644 --- a/gb/console.go +++ b/gb/console.go @@ -1,17 +1,40 @@ package gb +import ( + "image" + "image/color" +) + +const ( + ConsoleWidth = 160 + ConsoleHeight = 144 +) + type Console struct { Cartridge *Cartridge + front *image.RGBA } func NewConsole(path string) (*Console, error) { cartridge := InsertCartridge(path) + buffer := image.NewRGBA(image.Rect(0, 0, ConsoleWidth, ConsoleHeight)) - console := Console{cartridge} + console := Console{Cartridge: cartridge, front: buffer} return &console, nil } -func (console *Console) Update(dt uint64) { - console.StepSeconds(dt) +func (console *Console) StepMilliSeconds(ms uint64) { + speed := int(ms / 3) + for y := 0; y < ConsoleHeight; y++ { + for x := 0; x < ConsoleWidth; x++ { + console.front.Set(x, y, color.RGBA{0, uint8(y + speed), uint8(x + speed), 255}) + } + } + +} + +func (console *Console) Buffer() *image.RGBA { + + return console.front } diff --git a/ui/controller.go b/ui/controller.go index 5679ce1..4e27e39 100644 --- a/ui/controller.go +++ b/ui/controller.go @@ -1,25 +1,37 @@ package ui import ( - "gb-player/gb" + "fmt" + "log" "github.com/veandco/go-sdl2/sdl" + "github.com/veandco/go-sdl2/ttf" + + "gb-player/gb" ) type Controller struct { + window *sdl.Window renderer *sdl.Renderer + font *ttf.Font view *View timestamp uint64 } -func NewController(renderer *sdl.Renderer) *Controller { +func NewController(window *sdl.Window, renderer *sdl.Renderer, font *ttf.Font) *Controller { controller := Controller{} + controller.window = window controller.renderer = renderer + controller.font = font return &controller } func (c *Controller) Start(path string) { - console := gb.NewConsole(path) + console, err := gb.NewConsole(path) + if err != nil { + log.Fatal(err) + } + c.view = NewView(c, console) c.Run() } @@ -27,17 +39,14 @@ func (c *Controller) Start(path string) { func (c *Controller) Step() { timestamp := sdl.GetTicks64() dt := timestamp - c.timestamp - c.view.Update(timestamp, dt) + c.timestamp = timestamp + c.view.Update(dt) } func (c *Controller) Run() { var fps float64 var frameCount uint32 - var startTicks = sdl.GetTicks64() - var now, last uint64 - - // cartridge := gb.Insert(romPath) - // fmt.Println(cartridge) + var frameStart = sdl.GetTicks64() running := true for running { @@ -49,38 +58,49 @@ func (c *Controller) Run() { } } - last = now - now = sdl.GetPerformanceCounter() - deltaTime := float64((now - last) * 1000.0 / sdl.GetPerformanceFrequency()) - _ = deltaTime - // Clear screen - renderer.SetDrawColor(0x63, 0x94, 0xED, 0xff) - renderer.Clear() + c.renderer.SetDrawColor(0x63, 0x94, 0xED, 0xff) + c.renderer.Clear() // Update state c.Step() - rect := sdl.Rect{X: 100, Y: 100, W: 200, H: 150} - renderer.SetDrawColor(0, 0, 255, 255) - renderer.FillRect(&rect) - - drawDebugWindow(fps) + c.drawDebugWindow(fps) // Present to screen - renderer.Present() + c.renderer.Present() // Calculate framerate frameCount++ - currentTicks := sdl.GetTicks64() - elapsed := currentTicks - startTicks + frameEnd := sdl.GetTicks64() + elapsed := frameEnd - frameStart if elapsed >= 1000 { fps = float64(frameCount) / (float64(elapsed) / 1000.0) - // Reset counters + // Reset framerate counters frameCount = 0 - startTicks = currentTicks + frameStart = frameEnd } } - +} + +func (c *Controller) drawDebugWindow(fps float64) { + renderer := c.renderer + font := c.font + + // FPS + textSurface, err := font.RenderUTF8Blended(fmt.Sprintf("FPS: %.2f", fps), sdl.Color{R: 0, G: 0, B: 0, A: 255}) + if err != nil { + log.Fatal(err) + } + defer textSurface.Free() + + textTexture, err := renderer.CreateTextureFromSurface(textSurface) + if err != nil { + log.Fatal(err) + } + defer textTexture.Destroy() + + textRect := sdl.Rect{X: 0, Y: 0, W: textSurface.W, H: textSurface.H} + renderer.Copy(textTexture, nil, &textRect) } diff --git a/ui/run.go b/ui/run.go index 4b328d7..944625c 100644 --- a/ui/run.go +++ b/ui/run.go @@ -1,7 +1,6 @@ package ui import ( - "fmt" "log" "runtime" @@ -9,8 +8,10 @@ import ( "github.com/veandco/go-sdl2/ttf" ) -var renderer *sdl.Renderer -var font *ttf.Font +const ( + windowWidth = 800 + windowHeight = 600 +) func init() { runtime.LockOSThread() @@ -31,45 +32,27 @@ func Run(romPath string) { "GB Player", sdl.WINDOWPOS_UNDEFINED, sdl.WINDOWPOS_UNDEFINED, - 800, 600, + windowWidth, windowHeight, sdl.WINDOW_SHOWN) if err != nil { panic(err) } defer window.Destroy() - renderer, err = sdl.CreateRenderer(window, -1, 0) + renderer, err := sdl.CreateRenderer(window, -1, 0) if err != nil { panic(err) } defer renderer.Destroy() renderer.RenderSetVSync(true) - font, err = ttf.OpenFont("SourceCodePro.ttf", 18) + font, err := ttf.OpenFont("SourceCodePro.ttf", 18) if err != nil { log.Fatal(err) } defer font.Close() font.SetStyle(ttf.STYLE_BOLD) - controller := NewController(renderer) + controller := NewController(window, renderer, font) controller.Start(romPath) } - -func drawDebugWindow(fps float64) { - // FPS - textSurface, err := font.RenderUTF8Blended(fmt.Sprintf("FPS: %.2f", fps), sdl.Color{R: 0, G: 0, B: 0, A: 255}) - if err != nil { - log.Fatal(err) - } - defer textSurface.Free() - - textTexture, err := renderer.CreateTextureFromSurface(textSurface) - if err != nil { - log.Fatal(err) - } - defer textTexture.Destroy() - - textRect := sdl.Rect{X: 0, Y: 0, W: textSurface.W, H: textSurface.H} - renderer.Copy(textTexture, nil, &textRect) -} diff --git a/ui/view.go b/ui/view.go index 499b478..d27d0d9 100644 --- a/ui/view.go +++ b/ui/view.go @@ -1,6 +1,11 @@ package ui import ( + "image" + "log" + + "github.com/veandco/go-sdl2/sdl" + "gb-player/gb" ) @@ -12,3 +17,45 @@ type View struct { func NewView(controller *Controller, console *gb.Console) *View { return &View{controller, console} } + +func (view *View) Update(dt uint64) { + console := view.console + renderer := view.controller.renderer + + // console.StepMilliSeconds(dt) + console.StepMilliSeconds(sdl.GetTicks64()) + + buffer := console.Buffer() + + drawBuffer(renderer, buffer) +} + +func drawBuffer(renderer *sdl.Renderer, buffer *image.RGBA) { + width, height := gb.ConsoleWidth, gb.ConsoleHeight + + imageTexture, err := renderer.CreateTexture( + uint32(sdl.PIXELFORMAT_RGBA32), + sdl.TEXTUREACCESS_STREAMING, + int32(width), int32(height)) + if err != nil { + log.Fatal(err) + } + defer imageTexture.Destroy() + + pixels, pitch, err := imageTexture.Lock(nil) + if err != nil { + log.Fatal(err) + } + for y := range height { + start := y * buffer.Stride + end := start + width*4 + copy(pixels[y*pitch:y*pitch+width*4], buffer.Pix[start:end]) + } + imageTexture.Unlock() + + x := (windowWidth / 2) - width + y := (windowHeight / 2) - height + imageRect := sdl.Rect{X: int32(x), Y: int32(y), W: 2 * int32(width), H: 2 * int32(height)} + + renderer.Copy(imageTexture, nil, &imageRect) +}