在屏幕上绘制缓冲区时绑定的不匹配(golang.org/x/exp/shiny/screen)

在屏幕上绘制缓冲区时绑定的不匹配(golang.org/x/exp/shiny/screen)

问题描述:

I am trying to use golang.org/x/exp/shiny/screen to create a windows and then paint a buffer on the screen.

I have assigned same bounds (height and width) to the window and the buffer I am publishing on the window, but there seems to be a mismatch when I see the results.

You can see in the picture, that the blue buffer which is uploaded to the window is not covering it completely.

enter image description here

package main

import (
    "image"
    "image/color"
    "log"

    "golang.org/x/exp/shiny/driver"
    "golang.org/x/exp/shiny/screen"
    "golang.org/x/mobile/event/key"
    "golang.org/x/mobile/event/lifecycle"
)

const (
    Row = 32
    Col = 64
)

// Colors
var (
    Black = color.RGBA{0, 0, 0, 1.0}
    White = color.RGBA{255, 255, 255, 1.0}
    Blue  = color.RGBA{0, 0, 255, 1.0}
)

func main() {

    go driver.Main(func(s screen.Screen) {
        opts := screen.NewWindowOptions{
            Height: Row,
            Width:  Col,
            Title:  "Chip-8 VM",
        }

        window, err := s.NewWindow(&opts)
        if err != nil {
            log.Print("Unable to create display window: ")
            log.Fatal(err)
            return
        }

        defer window.Release()

        dim := image.Point{Col, Row}
        drawBuff, err := s.NewBuffer(dim)
        if err != nil {
            log.Fatal(err)
        }

        defaultDrawToBuffer(drawBuff.RGBA())

        log.Print("Window bounds: ", opts)
        log.Printf("Buffer bounds: %s", drawBuff.Bounds())
        log.Printf("Buffer size: %s", drawBuff.Size())

        window.Upload(image.Point{}, drawBuff, drawBuff.Bounds())
        window.Publish()

        for {
            e := window.NextEvent()
            switch e := e.(type) {

            case lifecycle.Event:
                if e.To == lifecycle.StageDead {
                    return
                } else if e.To == lifecycle.StageFocused {
                    log.Print("Focus back on the screen!")
                }

            case key.Event:
                log.Print("pressed key: ", e.Code)
                // exit game
                if e.Code == key.CodeEscape {
                    return
                }
            case error:
                log.Print(e)
            }

        }
    })

    for {
    }

}

// Bounds: (0,0)-(64,32)
func defaultDrawToBuffer(img *image.RGBA) {
    b := img.Bounds()

    log.Printf("Bounds: %s", b.String())

    for x := b.Min.X; x < b.Max.X; x++ {
        for y := b.Min.Y; y < b.Max.Y; y++ {
            img.SetRGBA(x, y, Blue)
        }
    }
}

You specify an initial size of width=62, height=32, these are sizes in pixels. Which means you want your window to be "tiny". Windows usually have a minimum size (often dictated by window controls), and seemingly this minimum size is bigger than your intended size. So the blue rectangle you draw will not will the whole window (which will not be less than the minimum size).

If you increase the size, e.g. Rows = 300, Cols = 600, then it will fill your window.

Also, drop the go keyword when calling driver.Main(), some OS-specific libraries require it to be called from the main goroutine. And so remove the empty for from main(), driver.Main() blocks until your app should exit.

Also, this still won't guarantee you see the blue rectangle, as if the window (screen) is refreshed / cleared, a redraw might be necessary.

So instead move your drawing logic to the event loop, and execute it for the paint.Event events:

case paint.Event:
    defaultDrawToBuffer(drawBuff.RGBA())
    window.Upload(image.Point{}, drawBuff, drawBuff.Bounds())
    window.Publish()