ui: Scale is now float64 (#236)

This commit is contained in:
Hajime Hoshi 2016-06-19 02:59:17 +09:00
parent 42332c7b49
commit bb511b2c13
11 changed files with 59 additions and 60 deletions

View File

@ -107,7 +107,7 @@ func main() {
} }
canvasImage.Fill(color.White) canvasImage.Fill(color.White)
if err := ebiten.Run(update, screenWidth, screenHeight, 2, "Paint (Ebiten Demo)"); err != nil { if err := ebiten.Run(update, screenWidth, screenHeight, 1.5, "Paint (Ebiten Demo)"); err != nil {
log.Fatal(err) log.Fatal(err)
} }
} }

View File

@ -30,11 +30,11 @@ type graphicsContext struct {
f func(*Image) error f func(*Image) error
offscreen *Image offscreen *Image
screen *Image screen *Image
screenScale int screenScale float64
initialized bool initialized bool
} }
func (c *graphicsContext) SetSize(screenWidth, screenHeight, screenScale int) error { func (c *graphicsContext) SetSize(screenWidth, screenHeight int, screenScale float64) error {
if c.screen != nil { if c.screen != nil {
c.screen.Dispose() c.screen.Dispose()
} }
@ -45,7 +45,9 @@ func (c *graphicsContext) SetSize(screenWidth, screenHeight, screenScale int) er
if err != nil { if err != nil {
return err return err
} }
c.screen, err = newImageWithScreenFramebuffer(screenWidth*screenScale, screenHeight*screenScale) w := int(float64(screenWidth) * screenScale)
h := int(float64(screenHeight) * screenScale)
c.screen, err = newImageWithScreenFramebuffer(w, h)
if err != nil { if err != nil {
return err return err
} }

View File

@ -98,12 +98,12 @@ func (c *runContext) setRunningSlowly(isRunningSlowly bool) {
} }
type GraphicsContext interface { type GraphicsContext interface {
SetSize(width, height, scale int) error SetSize(width, height int, scale float64) error
UpdateAndDraw() error UpdateAndDraw() error
Draw() error Draw() error
} }
func Run(g GraphicsContext, width, height, scale int, title string, fps int) error { func Run(g GraphicsContext, width, height int, scale float64, title string, fps int) error {
if currentRunContext != nil { if currentRunContext != nil {
return errors.New("loop: The game is already running") return errors.New("loop: The game is already running")
} }

View File

@ -20,7 +20,7 @@ type CloseEvent struct {
type ScreenSizeEvent struct { type ScreenSizeEvent struct {
Width int Width int
Height int Height int
ActualScale int ActualScale float64
} }
type RenderEvent struct { type RenderEvent struct {

View File

@ -20,8 +20,6 @@
package ui package ui
import ( import (
"math"
glfw "github.com/go-gl/glfw/v3.1/glfw" glfw "github.com/go-gl/glfw/v3.1/glfw"
) )
@ -31,7 +29,7 @@ var glfwMouseButtonToMouseButton = map[glfw.MouseButton]MouseButton{
glfw.MouseButtonMiddle: MouseButtonMiddle, glfw.MouseButtonMiddle: MouseButtonMiddle,
} }
func (i *input) update(window *glfw.Window, scale int) error { func (i *input) update(window *glfw.Window, scale float64) error {
i.m.Lock() i.m.Lock()
defer i.m.Unlock() defer i.m.Unlock()
@ -42,8 +40,8 @@ func (i *input) update(window *glfw.Window, scale int) error {
i.mouseButtonPressed[e] = window.GetMouseButton(g) == glfw.Press i.mouseButtonPressed[e] = window.GetMouseButton(g) == glfw.Press
} }
x, y := window.GetCursorPos() x, y := window.GetCursorPos()
i.cursorX = int(math.Floor(x)) / scale i.cursorX = int(x / scale)
i.cursorY = int(math.Floor(y)) / scale i.cursorY = int(y / scale)
for id := glfw.Joystick(0); id < glfw.Joystick(len(i.gamepads)); id++ { for id := glfw.Joystick(0); id < glfw.Joystick(len(i.gamepads)); id++ {
if !glfw.JoystickPresent(id) { if !glfw.JoystickPresent(id) {
continue continue

View File

@ -15,11 +15,11 @@
package ui package ui
type UserInterface interface { type UserInterface interface {
Start(width, height, scale int, title string) error Start(width, height int, scale float64, title string) error
Update() (interface{}, error) Update() (interface{}, error)
SwapBuffers() error SwapBuffers() error
Terminate() error Terminate() error
ScreenScale() int ScreenScale() float64
SetScreenSize(width, height int) bool SetScreenSize(width, height int) bool
SetScreenScale(scale int) bool SetScreenScale(scale float64) bool
} }

View File

@ -32,9 +32,9 @@ type userInterface struct {
window *glfw.Window window *glfw.Window
width int width int
height int height int
scale int scale float64
deviceScale float64 deviceScale float64
framebufferScale int framebufferScale float64
context *opengl.Context context *opengl.Context
funcs chan func() funcs chan func()
sizeChanged bool sizeChanged bool
@ -125,7 +125,7 @@ func (u *userInterface) SetScreenSize(width, height int) bool {
return r return r
} }
func (u *userInterface) SetScreenScale(scale int) bool { func (u *userInterface) SetScreenScale(scale float64) bool {
r := false r := false
u.runOnMainThread(func() { u.runOnMainThread(func() {
r = u.setScreenSize(u.width, u.height, scale) r = u.setScreenSize(u.width, u.height, scale)
@ -133,22 +133,21 @@ func (u *userInterface) SetScreenScale(scale int) bool {
return r return r
} }
func (u *userInterface) ScreenScale() int { func (u *userInterface) ScreenScale() float64 {
s := 0 s := 0.0
u.runOnMainThread(func() { u.runOnMainThread(func() {
s = u.scale s = u.scale
}) })
return s return s
} }
func (u *userInterface) Start(width, height, scale int, title string) error { func (u *userInterface) Start(width, height int, scale float64, title string) error {
var err error var err error
u.runOnMainThread(func() { u.runOnMainThread(func() {
m := glfw.GetPrimaryMonitor() m := glfw.GetPrimaryMonitor()
v := m.GetVideoMode() v := m.GetVideoMode()
u.deviceScale = deviceScale() u.deviceScale = deviceScale()
u.framebufferScale = 1 u.framebufferScale = 1
if !u.setScreenSize(width, height, scale) { if !u.setScreenSize(width, height, scale) {
err = errors.New("ui: Fail to set the screen size") err = errors.New("ui: Fail to set the screen size")
return return
@ -156,18 +155,18 @@ func (u *userInterface) Start(width, height, scale int, title string) error {
u.window.SetTitle(title) u.window.SetTitle(title)
u.window.Show() u.window.Show()
x := (v.Width - width*u.windowScale()) / 2 x := (v.Width - int(float64(width)*u.windowScale())) / 2
y := (v.Height - height*u.windowScale()) / 3 y := (v.Height - int(float64(height)*u.windowScale())) / 3
u.window.SetPos(x, y) u.window.SetPos(x, y)
}) })
return err return err
} }
func (u *userInterface) windowScale() int { func (u *userInterface) windowScale() float64 {
return u.scale * int(u.deviceScale) return u.scale * u.deviceScale
} }
func (u *userInterface) actualScreenScale() int { func (u *userInterface) actualScreenScale() float64 {
return u.windowScale() * u.framebufferScale return u.windowScale() * u.framebufferScale
} }
@ -260,7 +259,7 @@ func (u *userInterface) FinishRendering() error {
return nil return nil
} }
func (u *userInterface) setScreenSize(width, height, scale int) bool { func (u *userInterface) setScreenSize(width, height int, scale float64) bool {
if u.width == width && u.height == height && u.scale == scale { if u.width == width && u.height == height && u.scale == scale {
return false return false
} }
@ -273,7 +272,7 @@ func (u *userInterface) setScreenSize(width, height, scale int) bool {
// To prevent hanging up, return asap if the width is too small. // To prevent hanging up, return asap if the width is too small.
// 252 is an arbitrary number and I guess this is small enough. // 252 is an arbitrary number and I guess this is small enough.
const minWindowWidth = 252 const minWindowWidth = 252
if width*u.actualScreenScale() < minWindowWidth { if int(float64(width)*u.actualScreenScale()) < minWindowWidth {
u.scale = origScale u.scale = origScale
return false return false
} }
@ -290,7 +289,7 @@ func (u *userInterface) setScreenSize(width, height, scale int) bool {
window.SetFramebufferSizeCallback(nil) window.SetFramebufferSizeCallback(nil)
close(ch) close(ch)
}) })
window.SetSize(width*u.windowScale(), height*u.windowScale()) window.SetSize(int(float64(width)*u.windowScale()), int(float64(height)*u.windowScale()))
event: event:
for { for {
@ -303,7 +302,7 @@ event:
} }
// This is usually 1, but sometimes more than 1 (e.g. Retina Mac) // This is usually 1, but sometimes more than 1 (e.g. Retina Mac)
fw, _ := window.GetFramebufferSize() fw, _ := window.GetFramebufferSize()
u.framebufferScale = fw / width / u.windowScale() u.framebufferScale = float64(fw) / float64(width) / u.windowScale()
u.sizeChanged = true u.sizeChanged = true
return true return true
} }

View File

@ -26,7 +26,7 @@ import (
var canvas *js.Object var canvas *js.Object
type userInterface struct { type userInterface struct {
scale int scale float64
deviceScale float64 deviceScale float64
sizeChanged bool sizeChanged bool
} }
@ -66,17 +66,17 @@ func (u *userInterface) SetScreenSize(width, height int) bool {
return u.setScreenSize(width, height, u.scale) return u.setScreenSize(width, height, u.scale)
} }
func (u *userInterface) SetScreenScale(scale int) bool { func (u *userInterface) SetScreenScale(scale float64) bool {
width, height := u.size() width, height := u.size()
return u.setScreenSize(width, height, scale) return u.setScreenSize(width, height, scale)
} }
func (u *userInterface) ScreenScale() int { func (u *userInterface) ScreenScale() float64 {
return u.scale return u.scale
} }
func (u *userInterface) ActualScreenScale() int { func (u *userInterface) ActualScreenScale() float64 {
return u.scale * int(u.deviceScale) return u.scale * u.deviceScale
} }
func (u *userInterface) Update() (interface{}, error) { func (u *userInterface) Update() (interface{}, error) {
@ -122,8 +122,8 @@ func touchEventToTouches(e *js.Object) []touch {
for i := 0; i < len(t); i++ { for i := 0; i < len(t); i++ {
jj := j.Call("item", i) jj := j.Call("item", i)
t[i].id = jj.Get("identifier").Int() t[i].id = jj.Get("identifier").Int()
t[i].x = (jj.Get("clientX").Int() - left) / scale t[i].x = int(float64(jj.Get("clientX").Int()-left) / scale)
t[i].y = (jj.Get("clientY").Int() - top) / scale t[i].y = int(float64(jj.Get("clientY").Int()-top) / scale)
} }
return t return t
} }
@ -242,7 +242,7 @@ func setMouseCursorFromEvent(e *js.Object) {
x, y := e.Get("clientX").Int(), e.Get("clientY").Int() x, y := e.Get("clientX").Int(), e.Get("clientY").Int()
x -= rect.Get("left").Int() x -= rect.Get("left").Int()
y -= rect.Get("top").Int() y -= rect.Get("top").Int()
currentInput.setMouseCursor(x/scale, y/scale) currentInput.setMouseCursor(int(float64(x)/scale), int(float64(y)/scale))
} }
func devicePixelRatio() float64 { func devicePixelRatio() float64 {
@ -258,7 +258,7 @@ func Main() error {
return nil return nil
} }
func (u *userInterface) Start(width, height, scale int, title string) error { func (u *userInterface) Start(width, height int, scale float64, title string) error {
doc := js.Global.Get("document") doc := js.Global.Get("document")
doc.Set("title", title) doc.Set("title", title)
u.setScreenSize(width, height, scale) u.setScreenSize(width, height, scale)
@ -277,7 +277,7 @@ func (u *userInterface) size() (width, height int) {
return return
} }
func (u *userInterface) setScreenSize(width, height, scale int) bool { func (u *userInterface) setScreenSize(width, height int, scale float64) bool {
w, h := u.size() w, h := u.size()
s := u.scale s := u.scale
if w == width && h == height && s == scale { if w == width && h == height && s == scale {
@ -285,12 +285,12 @@ func (u *userInterface) setScreenSize(width, height, scale int) bool {
} }
u.scale = scale u.scale = scale
u.deviceScale = devicePixelRatio() u.deviceScale = devicePixelRatio()
canvas.Set("width", width*u.ActualScreenScale()) canvas.Set("width", int(float64(width)*u.ActualScreenScale()))
canvas.Set("height", height*u.ActualScreenScale()) canvas.Set("height", int(float64(height)*u.ActualScreenScale()))
canvasStyle := canvas.Get("style") canvasStyle := canvas.Get("style")
cssWidth := width * scale cssWidth := int(float64(width) * scale)
cssHeight := height * scale cssHeight := int(float64(height) * scale)
canvasStyle.Set("width", strconv.Itoa(cssWidth)+"px") canvasStyle.Set("width", strconv.Itoa(cssWidth)+"px")
canvasStyle.Set("height", strconv.Itoa(cssHeight)+"px") canvasStyle.Set("height", strconv.Itoa(cssHeight)+"px")
// CSS calc requires space chars. // CSS calc requires space chars.

View File

@ -76,7 +76,7 @@ loop:
type userInterface struct { type userInterface struct {
width int width int
height int height int
scale int scale float64
sizeChanged bool sizeChanged bool
} }
@ -94,7 +94,7 @@ func CurrentUI() UserInterface {
return currentUI return currentUI
} }
func (u *userInterface) Start(width, height, scale int, title string) error { func (u *userInterface) Start(width, height int, scale float64, title string) error {
u.width = width u.width = width
u.height = height u.height = height
u.scale = scale u.scale = scale
@ -135,17 +135,17 @@ func (u *userInterface) SetScreenSize(width, height int) bool {
return false return false
} }
func (u *userInterface) SetScreenScale(scale int) bool { func (u *userInterface) SetScreenScale(scale float64) bool {
// TODO: Implement // TODO: Implement
return false return false
} }
func (u *userInterface) ScreenScale() int { func (u *userInterface) ScreenScale() float64 {
return u.scale return u.scale
} }
func (u *userInterface) actualScreenScale() int { func (u *userInterface) actualScreenScale() float64 {
return u.scale * int(deviceScale()) return u.scale * deviceScale()
} }
func UpdateTouches(touches []Touch) { func UpdateTouches(touches []Touch) {

View File

@ -29,7 +29,7 @@ var chError <-chan error
type EventDispatcher interface { type EventDispatcher interface {
SetScreenSize(width, height int) SetScreenSize(width, height int)
SetScreenScale(scale int) SetScreenScale(scale float64)
Render() error Render() error
UpdateTouchesOnAndroid(action int, id int, x, y int) UpdateTouchesOnAndroid(action int, id int, x, y int)
UpdateTouchesOnIOS(phase int, ptr int, x, y int) UpdateTouchesOnIOS(phase int, ptr int, x, y int)
@ -38,7 +38,7 @@ type EventDispatcher interface {
// Start starts the game and returns immediately. // Start starts the game and returns immediately.
// //
// Different from ebiten.Run, this invokes only the game loop and not the main (UI) loop. // Different from ebiten.Run, this invokes only the game loop and not the main (UI) loop.
func Start(f func(*ebiten.Image) error, width, height, scale int, title string) (EventDispatcher, error) { func Start(f func(*ebiten.Image) error, width, height int, scale float64, title string) (EventDispatcher, error) {
chError = ebiten.RunWithoutMainLoop(f, width, height, scale, title) chError = ebiten.RunWithoutMainLoop(f, width, height, scale, title)
return &eventDispatcher{ return &eventDispatcher{
touches: map[int]position{}, touches: map[int]position{},
@ -58,7 +58,7 @@ func (e *eventDispatcher) SetScreenSize(width, height int) {
ui.CurrentUI().SetScreenSize(width, height) ui.CurrentUI().SetScreenSize(width, height)
} }
func (e *eventDispatcher) SetScreenScale(scale int) { func (e *eventDispatcher) SetScreenScale(scale float64) {
ui.CurrentUI().SetScreenScale(scale) ui.CurrentUI().SetScreenScale(scale)
} }
@ -81,8 +81,8 @@ func (t touch) ID() int {
func (t touch) Position() (int, int) { func (t touch) Position() (int, int) {
// TODO: Is this OK to adjust the position here? // TODO: Is this OK to adjust the position here?
return t.position.x / ui.CurrentUI().ScreenScale(), return int(float64(t.position.x) / ui.CurrentUI().ScreenScale()),
t.position.y / ui.CurrentUI().ScreenScale() int(float64(t.position.y) / ui.CurrentUI().ScreenScale())
} }
// UpdateTouchesOnAndroid updates the touch state on Android. // UpdateTouchesOnAndroid updates the touch state on Android.

8
run.go
View File

@ -53,7 +53,7 @@ func IsRunningSlowly() bool {
// The given function f is guaranteed to be called 60 times a second // The given function f is guaranteed to be called 60 times a second
// even if a rendering frame is skipped. // even if a rendering frame is skipped.
// f is not called when the screen is not shown. // f is not called when the screen is not shown.
func Run(f func(*Image) error, width, height, scale int, title string) error { func Run(f func(*Image) error, width, height int, scale float64, title string) error {
ch := make(chan error) ch := make(chan error)
go func() { go func() {
g := newGraphicsContext(f) g := newGraphicsContext(f)
@ -68,7 +68,7 @@ func Run(f func(*Image) error, width, height, scale int, title string) error {
// //
// Typically, Ebiten users don't have to call this directly. // Typically, Ebiten users don't have to call this directly.
// Instead, functions in github.com/hajimehoshi/ebiten/mobile module call this. // Instead, functions in github.com/hajimehoshi/ebiten/mobile module call this.
func RunWithoutMainLoop(f func(*Image) error, width, height, scale int, title string) <-chan error { func RunWithoutMainLoop(f func(*Image) error, width, height int, scale float64, title string) <-chan error {
ch := make(chan error) ch := make(chan error)
go func() { go func() {
g := newGraphicsContext(f) g := newGraphicsContext(f)
@ -94,7 +94,7 @@ func SetScreenSize(width, height int) {
// SetScreenScale changes the scale of the screen. // SetScreenScale changes the scale of the screen.
// //
// This function is concurrent-safe. // This function is concurrent-safe.
func SetScreenScale(scale int) { func SetScreenScale(scale float64) {
if scale <= 0 { if scale <= 0 {
panic("ebiten: scale must be positive") panic("ebiten: scale must be positive")
} }
@ -104,6 +104,6 @@ func SetScreenScale(scale int) {
// ScreenScale returns the current screen scale. // ScreenScale returns the current screen scale.
// //
// This function is concurrent-safe. // This function is concurrent-safe.
func ScreenScale() int { func ScreenScale() float64 {
return ui.CurrentUI().ScreenScale() return ui.CurrentUI().ScreenScale()
} }