This makes menus display more correctly, and also fixes trees and other objects on the main map, although it messes up bounds clipping (sigh).
122 lines
2.6 KiB
Go
122 lines
2.6 KiB
Go
package ui
|
|
|
|
import (
|
|
"flag"
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
"runtime/pprof"
|
|
|
|
"github.com/hajimehoshi/ebiten"
|
|
"github.com/hajimehoshi/ebiten/ebitenutil"
|
|
"github.com/hajimehoshi/ebiten/inpututil"
|
|
)
|
|
|
|
var (
|
|
screenScale = flag.Float64("screen-scale", 1.0, "Scale the window by this factor")
|
|
|
|
winX = flag.Int("win-x", 1280, "Pre-scaled window X dimension")
|
|
winY = flag.Int("win-y", 1024, "Pre-scaled window Y dimension")
|
|
|
|
cpuprofile = flag.String("cpuprofile", "", "write cpu profile to `file`")
|
|
)
|
|
|
|
type Window struct {
|
|
Title string
|
|
KeyUpHandlers map[ebiten.Key]func()
|
|
MouseWheelHandler func(float64, float64)
|
|
|
|
// User-provided update actions
|
|
updateFn func() error
|
|
drawFn func(*ebiten.Image) error
|
|
|
|
debug bool
|
|
firstRun bool
|
|
}
|
|
|
|
// 0,0 is the *top left* of the window
|
|
//
|
|
// ebiten assumes a single window, so only call this once...
|
|
func NewWindow(title string) (*Window, error) {
|
|
ebiten.SetRunnableInBackground(true)
|
|
|
|
return &Window{
|
|
Title: title,
|
|
KeyUpHandlers: make(map[ebiten.Key]func()),
|
|
debug: true,
|
|
firstRun: true,
|
|
}, nil
|
|
}
|
|
|
|
// TODO: multiple handlers for the same key?
|
|
func (w *Window) OnKeyUp(key ebiten.Key, f func()) {
|
|
w.KeyUpHandlers[key] = f
|
|
}
|
|
|
|
func (w *Window) OnMouseWheel(f func(x, y float64)) {
|
|
w.MouseWheelHandler = f
|
|
}
|
|
|
|
func (w *Window) run(screen *ebiten.Image) error {
|
|
if w.firstRun {
|
|
ebiten.SetScreenScale(*screenScale)
|
|
w.firstRun = false
|
|
}
|
|
|
|
if err := w.updateFn(); err != nil {
|
|
return err
|
|
}
|
|
|
|
// Process keys
|
|
// TODO: efficient set operations
|
|
|
|
for key, cb := range w.KeyUpHandlers {
|
|
if inpututil.IsKeyJustReleased(key) {
|
|
cb()
|
|
}
|
|
}
|
|
|
|
if w.MouseWheelHandler != nil {
|
|
x, y := ebiten.Wheel()
|
|
if x != 0 || y != 0 {
|
|
w.MouseWheelHandler(x, y)
|
|
}
|
|
}
|
|
|
|
if !ebiten.IsDrawingSkipped() {
|
|
if err := w.drawFn(screen); err != nil {
|
|
return err
|
|
}
|
|
|
|
if w.debug {
|
|
// Draw FPS, etc, to the screen
|
|
msg := fmt.Sprintf("tps=%0.2f fps=%0.2f", ebiten.CurrentTPS(), ebiten.CurrentFPS())
|
|
ebitenutil.DebugPrint(screen, msg)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// TODO: a stop or other cancellation mechanism
|
|
//
|
|
// Note that this must be called on the main OS thread
|
|
func (w *Window) Run(updateFn func() error, drawFn func(*ebiten.Image) error) error {
|
|
w.updateFn = updateFn
|
|
w.drawFn = drawFn
|
|
|
|
if *cpuprofile != "" {
|
|
f, err := os.Create(*cpuprofile)
|
|
if err != nil {
|
|
log.Fatal("could not create CPU profile: ", err)
|
|
}
|
|
defer f.Close() // error handling omitted for example
|
|
if err := pprof.StartCPUProfile(f); err != nil {
|
|
log.Fatal("could not start CPU profile: ", err)
|
|
}
|
|
defer pprof.StopCPUProfile()
|
|
}
|
|
|
|
return ebiten.Run(w.run, *winX, *winY, 1, w.Title) // Native game resolution: 640x480
|
|
}
|