edbit/application/application.go

192 lines
4.1 KiB
Go

package application
import (
"fmt"
"image"
"image/color"
"math"
"os"
"github.com/hajimehoshi/ebiten/v2/ebitenutil"
"github.com/hajimehoshi/ebiten/v2"
"golang.org/x/image/colornames"
)
var spinner = []byte(`-\|/`)
type Application struct {
screenW, screenH int
cursorX, cursorY int
canvases []*canvas
spinnerIndex int
hoverImg *ebiten.Image
op *ebiten.DrawImageOptions
}
func NewApplication() *Application {
a := &Application{
op: &ebiten.DrawImageOptions{},
}
a.addCanvas(8, 8)
a.canvases[0].img.Fill(colornames.Purple)
a.activeCanvas().scale = 256
a.hoverImg = ebiten.NewImage(int(a.canvases[0].scale), int(a.canvases[0].scale)) // TODO
a.drawHoverImage()
return a
}
func (app *Application) addCanvas(w, h int) {
c := NewCanvas(w, h)
app.canvases = append(app.canvases, c)
}
func (app *Application) activeCanvas() *canvas {
return app.canvases[0]
}
func (app *Application) screenToCanvas(x, y int) (int, int) {
c := app.activeCanvas()
cx, cy := int(float64(x)/c.scale), int(float64(y)/c.scale)
return cx, cy
}
func (app *Application) Layout(outsideWidth, outsideHeight int) (screenWidth, screenHeight int) {
s := ebiten.DeviceScaleFactor()
outsideWidth, outsideHeight = int(float64(outsideWidth)*s), int(float64(outsideHeight)*s)
if app.screenW == outsideWidth && app.screenH == outsideHeight {
return outsideWidth, outsideHeight
}
app.screenW, app.screenH = outsideWidth, outsideHeight
return app.screenW, app.screenH
}
func (app *Application) Update() error {
if ebiten.IsWindowBeingClosed() {
app.Exit()
return nil
}
if _, y := ebiten.Wheel(); y != 0 {
scroll := math.Ceil(y)
if scroll < -1 {
scroll = -1
} else if scroll > 1 {
scroll = 1
}
offset := scroll * (app.canvases[0].scale / 7)
app.canvases[0].scale += offset
if app.canvases[0].scale < .001 {
app.canvases[0].scale = .001
} else if app.canvases[0].scale > 1000 {
app.canvases[0].scale = 1000
}
hoverSize := int(math.Ceil(app.canvases[0].scale))
if hoverSize < 1 {
hoverSize = 1
}
hoverSize += 2
app.hoverImg = ebiten.NewImage(hoverSize, hoverSize)
app.drawHoverImage()
}
app.cursorX, app.cursorY = ebiten.CursorPosition()
if ebiten.IsMouseButtonPressed(ebiten.MouseButtonLeft) {
cx, cy := app.screenToCanvas(app.cursorX, app.cursorY)
c := app.activeCanvas()
c.img.Set(cx, cy, colornames.White)
}
return nil
}
func (app *Application) Draw(screen *ebiten.Image) {
// TODO translate and scale by camera pos
c := app.activeCanvas()
app.op.GeoM.Reset()
app.op.GeoM.Scale(c.scale, c.scale)
screen.DrawImage(c.img, app.op)
cx, cy := app.screenToCanvas(app.cursorX, app.cursorY)
p := c.pixelScreenRect(cx, cy)
app.op.GeoM.Reset()
app.op.GeoM.Translate(float64(p.Min.X)-1, float64(p.Min.Y)-1)
screen.DrawImage(app.hoverImg, app.op)
debugInfo := fmt.Sprintf("SCA %0.2f\nFPS %c %0.0f", app.activeCanvas().scale, spinner[app.spinnerIndex], ebiten.CurrentFPS())
debugBox := image.NewRGBA(image.Rect(10, 20, 200, 200))
debugImg := ebiten.NewImageFromImage(debugBox)
ebitenutil.DebugPrint(debugImg, debugInfo)
app.op.GeoM.Reset()
app.op.GeoM.Translate(3, 0)
app.op.GeoM.Scale(2, 2)
screen.DrawImage(debugImg, app.op)
app.spinnerIndex++
if app.spinnerIndex == 4 {
app.spinnerIndex = 0
}
}
func (app *Application) drawHoverImage() {
var colorWhite bool
nextColor := func() color.Color {
colorWhite = !colorWhite
if colorWhite {
return color.White
} else {
return color.Black
}
}
img := app.hoverImg
img.Clear()
bounds := img.Bounds()
hoverSize := 2
if app.activeCanvas().scale >= 1000 {
hoverSize = 6
} else if app.activeCanvas().scale >= 200 {
hoverSize = 5
} else if app.activeCanvas().scale >= 100 {
hoverSize = 4
} else if app.activeCanvas().scale >= 10 {
hoverSize = 3
}
for y := 0; y < hoverSize; y++ {
for x := 0; x < bounds.Max.X; x++ {
c := nextColor()
img.Set(x, bounds.Min.Y+y, c)
img.Set(x, bounds.Max.Y-y, c)
}
}
for x := 0; x < hoverSize; x++ {
for y := 0; y < bounds.Max.Y; y++ {
c := nextColor()
img.Set(bounds.Min.X+x, y, c)
img.Set(bounds.Max.X-x, y, c)
}
}
}
func (app *Application) Exit() {
os.Exit(0)
}