package pixel import "time" import "golang.org/x/image/font" import "github.com/faiface/pixel" import "github.com/faiface/pixel/pixelgl" import "golang.org/x/image/font/basicfont" import "git.tebibyte.media/sashakoshka/stone" type Backend struct { window *pixelgl.Window boundsDirty bool previousBounds pixel.Vec fontFace font.Face application *stone.Application config *stone.Config metrics struct { cellWidth int cellHeight int } } func (backend *Backend) Run (callback func (application *stone.Application)) { if backend.fontFace == nil { backend.fontFace = basicfont.Face7x13 } faceMetrics := backend.fontFace.Metrics() backend.metrics.cellHeight = faceMetrics.Height.Round() // FIXME?: this might not be the best way to get the cell width faceAdvance, ok := backend.fontFace.GlyphAdvance('M') if ok { backend.metrics.cellWidth = faceAdvance.Round() } else { backend.metrics.cellWidth = backend.metrics.cellHeight / 2 } pixelgl.Run (func () { var err error backend.window, err = pixelgl.NewWindow (pixelgl.WindowConfig { Resizable: true, Undecorated: true, VSync: true, NoIconify: true, Title: backend.application.Title(), Bounds: backend.calculateWindowSize(), }) backend.Poll() if err != nil { panic(err.Error()) } callback(backend.application) }) } func (backend *Backend) Await (timeout time.Duration) (keepRunning bool) { if backend.window == nil { panic("call to Backend.Await before window exists") } backend.draw() backend.window.UpdateInputWait(timeout) backend.processEvents() keepRunning = !backend.window.Closed() return } func (backend *Backend) Poll () (keepRunning bool) { if backend.window == nil { panic("call to Backend.Poll before window exists") } backend.draw() backend.window.UpdateInput() backend.processEvents() keepRunning = !backend.window.Closed() return } func (backend *Backend) SetTitle (title string) { if backend.window != nil { backend.window.SetTitle(title) } } func (backend *Backend) draw () { didDrawing := false if backend.boundsDirty { backend.window.Clear ( backend.config.Color(stone.ColorApplication)) backend.boundsDirty = false didDrawing = true } else { // TODO: clear out dirty cells before drawing them (we don't // want to clear them out if we have already just cleared // everything out) } // TODO: draw dirty cells. width, height := backend.application.Size() for x := 0; x < width; x ++ { for y := 0; y < height; y ++ { clean := backend.application.Clean(x, y) // cell := application.content[index] if clean { continue } // draw cell didDrawing = true // TODO: set didDrawing up there ^ backend.application.MarkClean(x, y) } } if didDrawing { backend.window.SwapBuffers() } } func (backend *Backend) processEvents () { } func (backend *Backend) calculateWindowSize () (bounds pixel.Rect) { width, height := backend.application.Size() bounds = pixel.R ( 0, 0, float64(width * backend.metrics.cellWidth), float64(height * backend.metrics.cellHeight)) return } func factory (application *stone.Application) (output stone.Backend, err error) { backend := &Backend { application: application, config: application.Config(), } output = backend return } func init () { stone.RegisterBackend(factory) }