x-backend #2
@ -1,321 +0,0 @@
|
||||
package pixel
|
||||
|
||||
import "time"
|
||||
import "golang.org/x/image/font"
|
||||
import "github.com/faiface/pixel"
|
||||
import "github.com/faiface/pixel/text"
|
||||
import "github.com/faiface/pixel/imdraw"
|
||||
import "github.com/faiface/pixel/pixelgl"
|
||||
import "golang.org/x/image/font/basicfont"
|
||||
import "git.tebibyte.media/sashakoshka/stone"
|
||||
|
||||
// Backend represents an instance of the pixel backend
|
||||
type Backend struct {
|
||||
window *pixelgl.Window
|
||||
boundsDirty bool
|
||||
windowBounds pixel.Vec
|
||||
fontFace font.Face
|
||||
application *stone.Application
|
||||
config *stone.Config
|
||||
backgroundStamper *imdraw.IMDraw
|
||||
fontAtlas *text.Atlas
|
||||
textDrawer *text.Text
|
||||
showBounds bool
|
||||
showCellBounds bool
|
||||
|
||||
metrics struct {
|
||||
cellWidth int
|
||||
cellHeight int
|
||||
padding int
|
||||
paddingX int
|
||||
paddingY int
|
||||
descent int
|
||||
}
|
||||
}
|
||||
|
||||
// Run satisfies the Run method of the Backend interface. Due to the nature of
|
||||
// pixel, this will forcibly bind to the main thread.
|
||||
func (backend *Backend) Run (callback func (application *stone.Application)) {
|
||||
// backend.showBounds = true
|
||||
// backend.showCellBounds = true
|
||||
|
||||
if backend.fontFace == nil {
|
||||
backend.fontFace = basicfont.Face7x13
|
||||
}
|
||||
|
||||
backend.backgroundStamper = imdraw.New(nil)
|
||||
backend.fontAtlas = text.NewAtlas(backend.fontFace, text.ASCII)
|
||||
backend.textDrawer = text.New(pixel.V(0, 0), backend.fontAtlas)
|
||||
|
||||
backend.metrics.descent = int(backend.fontAtlas.Descent())
|
||||
backend.metrics.cellHeight = int(backend.fontAtlas.LineHeight())
|
||||
// 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 () {
|
||||
// construct the window, and all that
|
||||
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()
|
||||
|
||||
// TODO: this should return the error and not panic
|
||||
if err != nil { panic(err.Error()) }
|
||||
callback(backend.application)
|
||||
})
|
||||
}
|
||||
|
||||
// Await fulfills the Await method of the Backend interface.
|
||||
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
|
||||
}
|
||||
|
||||
// Poll fulfills the Poll method of the Backend interface.
|
||||
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
|
||||
}
|
||||
|
||||
// SetTitle fulfills the SetTitle method of the Backend interface.
|
||||
func (backend *Backend) SetTitle (title string) {
|
||||
if backend.window != nil {
|
||||
backend.window.SetTitle(title)
|
||||
}
|
||||
}
|
||||
|
||||
// JustPressed fulfills the JustPressed method of the Backend interface.
|
||||
func (backend *Backend) JustPressed (button stone.Button) (pressed bool) {
|
||||
pressed = backend.window.JustPressed(pixelgl.Button(button))
|
||||
return
|
||||
}
|
||||
|
||||
// JustReleased fulfills the JustReleased method of the Backend interface.
|
||||
func (backend *Backend) JustReleased (button stone.Button) (released bool) {
|
||||
released = backend.window.JustReleased(pixelgl.Button(button))
|
||||
return
|
||||
}
|
||||
|
||||
// Pressed fulfills the Pressed method of the Backend interface.
|
||||
func (backend *Backend) Pressed (button stone.Button) (pressed bool) {
|
||||
pressed = backend.window.Pressed(pixelgl.Button(button))
|
||||
return
|
||||
}
|
||||
|
||||
// Repeated fulfills the Repeated method of the Backend interface.
|
||||
func (backend *Backend) Repeated (button stone.Button) (repeated bool) {
|
||||
repeated = backend.window.Repeated(pixelgl.Button(button))
|
||||
return
|
||||
}
|
||||
|
||||
// Typed fulfills the Typed method of the Backend interface.
|
||||
func (backend *Backend) Typed () (text string) {
|
||||
text = backend.window.Typed()
|
||||
return
|
||||
}
|
||||
|
||||
// Resized fulfills the Resized method of the Backend interface.
|
||||
func (backend *Backend) Resized () (resized bool) {
|
||||
resized = backend.boundsDirty
|
||||
return
|
||||
}
|
||||
|
||||
// MousePosition fulfills the MousePosition method of the Backend interface.
|
||||
func (backend *Backend) MousePosition () (x, y int) {
|
||||
vector := backend.window.MousePosition()
|
||||
x = int (
|
||||
(vector.X - float64(backend.metrics.paddingX)) /
|
||||
float64(backend.metrics.cellWidth))
|
||||
y = int (
|
||||
(backend.windowBounds.Y -
|
||||
vector.Y -
|
||||
float64(backend.metrics.paddingY)) /
|
||||
float64(backend.metrics.cellHeight))
|
||||
return
|
||||
}
|
||||
|
||||
// draw renders updates to the screen.
|
||||
func (backend *Backend) draw () {
|
||||
// didDrawing := false
|
||||
width, height := backend.application.Size()
|
||||
|
||||
if backend.boundsDirty {
|
||||
backend.window.Clear (
|
||||
backend.config.Color(stone.ColorApplication))
|
||||
backend.boundsDirty = false
|
||||
// didDrawing = true
|
||||
} else {
|
||||
// clear out dirty cells before drawing them. this is in an else
|
||||
// block because if the bounds were dirty, we have already
|
||||
// cleared the entire screen.
|
||||
|
||||
backend.backgroundStamper.Clear()
|
||||
backend.backgroundStamper.Color =
|
||||
backend.config.Color(stone.ColorApplication)
|
||||
for x := 0; x < width; x ++ {
|
||||
for y := 0; y < height; y ++ {
|
||||
clean := backend.application.Clean(x, y)
|
||||
if clean { continue }
|
||||
|
||||
backend.backgroundStamper.Push (
|
||||
backend.vectorAtPosition(x, y),
|
||||
backend.vectorAtPosition(x + 1, y + 1))
|
||||
backend.backgroundStamper.Rectangle(0)
|
||||
// didDrawing = true
|
||||
|
||||
if backend.showCellBounds {
|
||||
backend.backgroundStamper.Color =
|
||||
backend.config.Color(stone.ColorForeground)
|
||||
backend.backgroundStamper.Push (
|
||||
backend.vectorAtPosition(x, y),
|
||||
backend.vectorAtPosition(x + 1, y + 1))
|
||||
backend.backgroundStamper.Rectangle(1)
|
||||
backend.backgroundStamper.Color =
|
||||
backend.config.Color(stone.ColorApplication)
|
||||
}
|
||||
}
|
||||
}
|
||||
backend.backgroundStamper.Draw(backend.window)
|
||||
}
|
||||
|
||||
backend.textDrawer.Clear()
|
||||
backend.textDrawer.Color =
|
||||
backend.config.Color(stone.ColorForeground)
|
||||
for x := 0; x < width; x ++ {
|
||||
for y := 0; y < height; y ++ {
|
||||
clean := backend.application.Clean(x, y)
|
||||
if clean { continue }
|
||||
backend.application.MarkClean(x, y)
|
||||
|
||||
cell := backend.application.Cell(x, y)
|
||||
content := cell.Rune()
|
||||
if content < 32 { continue }
|
||||
|
||||
// draw cell
|
||||
backend.textDrawer.Dot = pixel.V (
|
||||
float64 (
|
||||
x * backend.metrics.cellWidth +
|
||||
backend.metrics.paddingX),
|
||||
backend.windowBounds.Y - float64 (
|
||||
(y + 1) * backend.metrics.cellHeight +
|
||||
backend.metrics.paddingY -
|
||||
backend.metrics.descent))
|
||||
|
||||
backend.textDrawer.WriteRune(content)
|
||||
backend.textDrawer.Draw(backend.window, pixel.IM)
|
||||
}
|
||||
}
|
||||
|
||||
// draw a rectangle around the buffer if we are showing bounds
|
||||
if backend.showBounds {
|
||||
backend.backgroundStamper.Clear()
|
||||
backend.backgroundStamper.Color =
|
||||
backend.config.Color(stone.ColorBackground)
|
||||
backend.backgroundStamper.Push (
|
||||
backend.vectorAtPosition(0, 0),
|
||||
backend.vectorAtPosition(width, height))
|
||||
backend.backgroundStamper.Rectangle(1)
|
||||
backend.backgroundStamper.Draw(backend.window)
|
||||
}
|
||||
|
||||
backend.window.SwapBuffers()
|
||||
}
|
||||
|
||||
// processEvents reacts to events recieved from pixel, resizing and
|
||||
// recalculating things as need be.
|
||||
func (backend *Backend) processEvents () {
|
||||
newBounds := backend.window.Bounds().Max
|
||||
backend.boundsDirty = backend.windowBounds != newBounds
|
||||
backend.windowBounds = newBounds
|
||||
|
||||
if backend.boundsDirty {
|
||||
// calculate padding
|
||||
backend.metrics.padding =
|
||||
backend.config.Padding() *
|
||||
backend.metrics.cellWidth
|
||||
deadArea := float64(backend.metrics.padding * 2)
|
||||
|
||||
// calculate new width and height for buffer
|
||||
width := int (
|
||||
(backend.windowBounds.X - deadArea) /
|
||||
float64(backend.metrics.cellWidth))
|
||||
height := int (
|
||||
(backend.windowBounds.Y - deadArea) /
|
||||
float64(backend.metrics.cellHeight))
|
||||
backend.application.SetSize(width, height)
|
||||
|
||||
// position buffer in center of screen
|
||||
frameWidth := width * backend.metrics.cellWidth
|
||||
frameHeight := height * backend.metrics.cellHeight
|
||||
backend.metrics.paddingX = (int(backend.windowBounds.X) - frameWidth) / 2
|
||||
backend.metrics.paddingY = (int(backend.windowBounds.Y) - frameHeight) / 2
|
||||
}
|
||||
}
|
||||
|
||||
// vectorAtPosition generates a pixel vector at the top left of the specified
|
||||
// cell.
|
||||
func (backend *Backend) vectorAtPosition (x, y int) (vector pixel.Vec) {
|
||||
vector = pixel.V (
|
||||
float64 (
|
||||
x * backend.metrics.cellWidth +
|
||||
backend.metrics.paddingX),
|
||||
backend.windowBounds.Y - float64 (
|
||||
y * backend.metrics.cellHeight +
|
||||
backend.metrics.paddingY))
|
||||
return
|
||||
}
|
||||
|
||||
// calculateWindowSize calculates window bounds based on the internal buffer
|
||||
// size.
|
||||
func (backend *Backend) calculateWindowSize () (bounds pixel.Rect) {
|
||||
width, height := backend.application.Size()
|
||||
bounds = pixel.R (
|
||||
0, 0,
|
||||
float64 (
|
||||
width * backend.metrics.cellWidth +
|
||||
backend.metrics.padding * 2),
|
||||
float64 (
|
||||
height * backend.metrics.cellHeight +
|
||||
backend.metrics.padding * 2))
|
||||
return
|
||||
}
|
||||
|
||||
// factory instantiates a pixel backend.
|
||||
func factory (application *stone.Application) (output stone.Backend, err error) {
|
||||
backend := &Backend {
|
||||
application: application,
|
||||
config: application.Config(),
|
||||
}
|
||||
output = backend
|
||||
return
|
||||
}
|
||||
|
||||
// init registers this backend when the program starts.
|
||||
func init () {
|
||||
stone.RegisterBackend(factory)
|
||||
}
|
7
go.mod
7
go.mod
@ -3,7 +3,6 @@ module git.tebibyte.media/sashakoshka/stone
|
||||
go 1.18
|
||||
|
||||
require (
|
||||
github.com/faiface/pixel v0.10.0
|
||||
github.com/flopp/go-findfont v0.1.0
|
||||
github.com/jezek/xgb v1.1.0
|
||||
github.com/jezek/xgbutil v0.0.0-20210302171758-530099784e66
|
||||
@ -13,11 +12,5 @@ require (
|
||||
require (
|
||||
github.com/BurntSushi/freetype-go v0.0.0-20160129220410-b763ddbfe298 // indirect
|
||||
github.com/BurntSushi/graphics-go v0.0.0-20160129215708-b43f31a4a966 // indirect
|
||||
github.com/faiface/glhf v0.0.0-20181018222622-82a6317ac380 // indirect
|
||||
github.com/faiface/mainthread v0.0.0-20171120011319-8b78f0a41ae3 // indirect
|
||||
github.com/go-gl/gl v0.0.0-20190320180904-bf2b1f2f34d7 // indirect
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72 // indirect
|
||||
github.com/go-gl/mathgl v0.0.0-20190416160123-c4601bc793c7 // indirect
|
||||
github.com/pkg/errors v0.8.1 // indirect
|
||||
golang.org/x/text v0.4.0 // indirect
|
||||
)
|
||||
|
25
go.sum
25
go.sum
@ -2,40 +2,15 @@ github.com/BurntSushi/freetype-go v0.0.0-20160129220410-b763ddbfe298 h1:1qlsVAQJ
|
||||
github.com/BurntSushi/freetype-go v0.0.0-20160129220410-b763ddbfe298/go.mod h1:D+QujdIlUNfa0igpNMk6UIvlb6C252URs4yupRUV4lQ=
|
||||
github.com/BurntSushi/graphics-go v0.0.0-20160129215708-b43f31a4a966 h1:lTG4HQym5oPKjL7nGs+csTgiDna685ZXjxijkne828g=
|
||||
github.com/BurntSushi/graphics-go v0.0.0-20160129215708-b43f31a4a966/go.mod h1:Mid70uvE93zn9wgF92A/r5ixgnvX8Lh68fxp9KQBaI0=
|
||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/faiface/glhf v0.0.0-20181018222622-82a6317ac380 h1:FvZ0mIGh6b3kOITxUnxS3tLZMh7yEoHo75v3/AgUqg0=
|
||||
github.com/faiface/glhf v0.0.0-20181018222622-82a6317ac380/go.mod h1:zqnPFFIuYFFxl7uH2gYByJwIVKG7fRqlqQCbzAnHs9g=
|
||||
github.com/faiface/mainthread v0.0.0-20171120011319-8b78f0a41ae3 h1:baVdMKlASEHrj19iqjARrPbaRisD7EuZEVJj6ZMLl1Q=
|
||||
github.com/faiface/mainthread v0.0.0-20171120011319-8b78f0a41ae3/go.mod h1:VEPNJUlxl5KdWjDvz6Q1l+rJlxF2i6xqDeGuGAxa87M=
|
||||
github.com/faiface/pixel v0.10.0 h1:EHm3ZdQw2Ck4y51cZqFfqQpwLqNHOoXwbNEc9Dijql0=
|
||||
github.com/faiface/pixel v0.10.0/go.mod h1:lU0YYcW77vL0F1CG8oX51GXurymL45MXd57otHNLK7A=
|
||||
github.com/flopp/go-findfont v0.1.0 h1:lPn0BymDUtJo+ZkV01VS3661HL6F4qFlkhcJN55u6mU=
|
||||
github.com/flopp/go-findfont v0.1.0/go.mod h1:wKKxRDjD024Rh7VMwoU90i6ikQRCr+JTHB5n4Ejkqvw=
|
||||
github.com/go-gl/gl v0.0.0-20190320180904-bf2b1f2f34d7 h1:SCYMcCJ89LjRGwEa0tRluNRiMjZHalQZrVrvTbPh+qw=
|
||||
github.com/go-gl/gl v0.0.0-20190320180904-bf2b1f2f34d7/go.mod h1:482civXOzJJCPzJ4ZOX/pwvXBWSnzD4OKMdH4ClKGbk=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72 h1:b+9H1GAsx5RsjvDFLoS5zkNBzIQMuVKUYQDmxU3N5XE=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-gl/mathgl v0.0.0-20190416160123-c4601bc793c7 h1:THttjeRn1iiz69E875U6gAik8KTWk/JYAHoSVpUxBBI=
|
||||
github.com/go-gl/mathgl v0.0.0-20190416160123-c4601bc793c7/go.mod h1:yhpkQzEiH9yPyxDUGzkmgScbaBVlhC06qodikEM0ZwQ=
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
|
||||
github.com/jezek/xgb v1.1.0 h1:wnpxJzP1+rkbGclEkmwpVFQWpuE2PUGNUzP8SbfFobk=
|
||||
github.com/jezek/xgb v1.1.0/go.mod h1:nrhwO0FX/enq75I7Y7G8iN1ubpSGZEiA3v9e9GyRFlk=
|
||||
github.com/jezek/xgbutil v0.0.0-20210302171758-530099784e66 h1:+wPhoJD8EH0/bXipIq8Lc2z477jfox9zkXPCJdhvHj8=
|
||||
github.com/jezek/xgbutil v0.0.0-20210302171758-530099784e66/go.mod h1:KACeV+k6b+aoLTVrrurywEbu3UpqoQcQywj4qX8aQKM=
|
||||
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/image v0.0.0-20190321063152-3fc05d484e9f/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190523035834-f03afa92d3ff/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.1.0 h1:r8Oj8ZA2Xy12/b5KZYj3tuv7NG/fBz3TwQVvpJ9l8Rk=
|
||||
golang.org/x/image v0.1.0/go.mod h1:iyPr49SD/G/TBxYVB/9RRtGUT5eNbo2u4NamWeQcD5c=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
|
Loading…
Reference in New Issue
Block a user