diff --git a/internal/uidriver/glfw/input.go b/internal/uidriver/glfw/input.go index d1833be7c..f3ecd7269 100644 --- a/internal/uidriver/glfw/input.go +++ b/internal/uidriver/glfw/input.go @@ -47,6 +47,8 @@ type Input struct { touches map[int]pos // This is not updated until GLFW 3.3 is available (#417) runeBuffer []rune ui *UserInterface + + m sync.RWMutex } type pos struct { @@ -55,15 +57,15 @@ type pos struct { } func (i *Input) CursorPosition() (x, y int) { - i.ui.m.RLock() + i.m.RLock() cx, cy := i.cursorX, i.cursorY - i.ui.m.RUnlock() + i.m.RUnlock() return i.ui.adjustPosition(cx, cy) } func (i *Input) GamepadIDs() []int { - i.ui.m.RLock() - defer i.ui.m.RUnlock() + i.m.RLock() + defer i.m.RUnlock() if len(i.gamepads) == 0 { return nil } @@ -77,8 +79,8 @@ func (i *Input) GamepadIDs() []int { } func (i *Input) GamepadAxisNum(id int) int { - i.ui.m.RLock() - defer i.ui.m.RUnlock() + i.m.RLock() + defer i.m.RUnlock() if len(i.gamepads) <= id { return 0 } @@ -86,8 +88,8 @@ func (i *Input) GamepadAxisNum(id int) int { } func (i *Input) GamepadAxis(id int, axis int) float64 { - i.ui.m.RLock() - defer i.ui.m.RUnlock() + i.m.RLock() + defer i.m.RUnlock() if len(i.gamepads) <= id { return 0 } @@ -95,8 +97,8 @@ func (i *Input) GamepadAxis(id int, axis int) float64 { } func (i *Input) GamepadButtonNum(id int) int { - i.ui.m.RLock() - defer i.ui.m.RUnlock() + i.m.RLock() + defer i.m.RUnlock() if len(i.gamepads) <= id { return 0 } @@ -104,8 +106,8 @@ func (i *Input) GamepadButtonNum(id int) int { } func (i *Input) IsGamepadButtonPressed(id int, button driver.GamepadButton) bool { - i.ui.m.RLock() - defer i.ui.m.RUnlock() + i.m.RLock() + defer i.m.RUnlock() if len(i.gamepads) <= id { return false } @@ -113,8 +115,8 @@ func (i *Input) IsGamepadButtonPressed(id int, button driver.GamepadButton) bool } func (i *Input) TouchIDs() []int { - i.ui.m.RLock() - defer i.ui.m.RUnlock() + i.m.RLock() + defer i.m.RUnlock() if len(i.touches) == 0 { return nil @@ -128,7 +130,7 @@ func (i *Input) TouchIDs() []int { } func (i *Input) TouchPosition(id int) (x, y int) { - i.ui.m.RLock() + i.m.RLock() found := false var p pos for tid, pos := range i.touches { @@ -138,7 +140,7 @@ func (i *Input) TouchPosition(id int) (x, y int) { break } } - i.ui.m.RUnlock() + i.m.RUnlock() if !found { return 0, 0 @@ -147,21 +149,21 @@ func (i *Input) TouchPosition(id int) (x, y int) { } func (i *Input) RuneBuffer() []rune { - i.ui.m.RLock() - defer i.ui.m.RUnlock() + i.m.RLock() + defer i.m.RUnlock() return i.runeBuffer } func (i *Input) ResetForFrame() { - i.ui.m.RLock() - defer i.ui.m.RUnlock() + i.m.RLock() + defer i.m.RUnlock() i.runeBuffer = i.runeBuffer[:0] i.scrollX, i.scrollY = 0, 0 } func (i *Input) IsKeyPressed(key driver.Key) bool { - i.ui.m.RLock() - defer i.ui.m.RUnlock() + i.m.RLock() + defer i.m.RUnlock() if i.keyPressed == nil { i.keyPressed = map[glfw.Key]bool{} } @@ -177,8 +179,8 @@ func (i *Input) IsKeyPressed(key driver.Key) bool { } func (i *Input) IsMouseButtonPressed(button driver.MouseButton) bool { - i.ui.m.RLock() - defer i.ui.m.RUnlock() + i.m.RLock() + defer i.m.RUnlock() if i.mouseButtonPressed == nil { i.mouseButtonPressed = map[glfw.MouseButton]bool{} } @@ -194,8 +196,8 @@ func (i *Input) IsMouseButtonPressed(button driver.MouseButton) bool { } func (i *Input) Wheel() (xoff, yoff float64) { - i.ui.m.RLock() - defer i.ui.m.RUnlock() + i.m.RLock() + defer i.m.RUnlock() return i.scrollX, i.scrollY } @@ -209,21 +211,21 @@ func (i *Input) appendRuneBuffer(char rune) { if !unicode.IsPrint(char) { return } - i.ui.m.Lock() + i.m.Lock() i.runeBuffer = append(i.runeBuffer, char) - i.ui.m.Unlock() + i.m.Unlock() } func (i *Input) setWheel(xoff, yoff float64) { - i.ui.m.Lock() + i.m.Lock() i.scrollX = xoff i.scrollY = yoff - i.ui.m.Unlock() + i.m.Unlock() } -func (i *Input) update(window *glfw.Window, scale float64) { - i.ui.m.Lock() - defer i.ui.m.Unlock() +func (i *Input) update(window *glfw.Window) { + i.m.Lock() + defer i.m.Unlock() i.onceCallback.Do(func() { window.SetCharModsCallback(func(w *glfw.Window, char rune, mods glfw.ModifierKey) { @@ -246,8 +248,8 @@ func (i *Input) update(window *glfw.Window, scale float64) { i.mouseButtonPressed[gb] = window.GetMouseButton(gb) == glfw.Press } x, y := window.GetCursorPos() - i.cursorX = int(x / scale) - i.cursorY = int(y / scale) + i.cursorX = int(i.ui.toDeviceIndependentPixel(x) / i.ui.getScale()) + i.cursorY = int(i.ui.toDeviceIndependentPixel(y) / i.ui.getScale()) for id := glfw.Joystick(0); id < glfw.Joystick(len(i.gamepads)); id++ { i.gamepads[id].valid = false if !id.Present() { diff --git a/internal/uidriver/glfw/ui.go b/internal/uidriver/glfw/ui.go index 200f45692..169d73362 100644 --- a/internal/uidriver/glfw/ui.go +++ b/internal/uidriver/glfw/ui.go @@ -134,9 +134,8 @@ func initialize() error { theUI.window = w theUI.initMonitor = theUI.currentMonitorFromPosition() v := theUI.initMonitor.GetVideoMode() - s := theUI.glfwScale() - theUI.initFullscreenWidth = int(float64(v.Width) / s) - theUI.initFullscreenHeight = int(float64(v.Height) / s) + theUI.initFullscreenWidth = int(theUI.toDeviceIndependentPixel(float64(v.Width))) + theUI.initFullscreenHeight = int(theUI.toDeviceIndependentPixel(float64(v.Height))) theUI.window.Destroy() theUI.window = nil @@ -306,19 +305,29 @@ func (u *UserInterface) setInitWindowPosition(x, y int) { u.initWindowPositionY = y } +// toDeviceIndependentPixel must be called from the main thread. +func (u *UserInterface) toDeviceIndependentPixel(x float64) float64 { + return x / u.glfwScale() +} + +// toDeviceDependentPixel must be called from the main thread. +func (u *UserInterface) toDeviceDependentPixel(x float64) float64 { + return x * u.glfwScale() +} + func (u *UserInterface) ScreenSizeInFullscreen() (int, int) { if !u.isRunning() { return u.initFullscreenWidth, u.initFullscreenHeight } - var v *glfw.VidMode - s := 0.0 + var w, h int _ = u.t.Call(func() error { - v = u.currentMonitor().GetVideoMode() - s = u.glfwScale() + v := u.currentMonitor().GetVideoMode() + w = int(u.toDeviceIndependentPixel(float64(v.Width))) + h = int(u.toDeviceIndependentPixel(float64(v.Height))) return nil }) - return int(float64(v.Width) / s), int(float64(v.Height) / s) + return w, h } func (u *UserInterface) SetScreenSize(width, height int) { @@ -446,21 +455,18 @@ func (u *UserInterface) ScreenPadding() (x0, y0, x1, y1 float64) { d := 0.0 sx := 0.0 sy := 0.0 - gs := 0.0 - vw := 0.0 - vh := 0.0 + mx := 0.0 + my := 0.0 _ = u.t.Call(func() error { - d = u.deviceScaleFactor() sx = float64(u.width) * u.actualScreenScale() sy = float64(u.height) * u.actualScreenScale() - gs = u.glfwScale() - v := u.window.GetMonitor().GetVideoMode() - vw, vh = float64(v.Width), float64(v.Height) + v := u.currentMonitor().GetVideoMode() + d = u.deviceScaleFactor() + mx = u.toDeviceIndependentPixel(float64(v.Width)) * d + my = u.toDeviceIndependentPixel(float64(v.Height)) * d return nil }) - mx := vw * d / gs - my := vh * d / gs ox := (mx - sx) / 2 oy := (my - sy) / 2 @@ -659,9 +665,8 @@ func (u *UserInterface) createWindow() error { return } - s := u.glfwScale() - w := int(float64(width) / u.scale / s) - h := int(float64(height) / u.scale / s) + w := int(u.toDeviceIndependentPixel(float64(width)) / u.scale) + h := int(u.toDeviceIndependentPixel(float64(height)) / u.scale) u.reqWidth = w u.reqHeight = h }) @@ -745,8 +750,8 @@ func (u *UserInterface) run(width, height int, scale float64, title string, cont _ = u.t.Call(func() error { // Get the window size before showing since window.Show might change the current - // monitor which affects glfwSize result. - w, h := u.glfwSize() + // monitor which affects deviceDependentWindowSize result. + w, h := u.deviceDependentWindowSize() u.title = title u.window.SetTitle(title) @@ -774,10 +779,10 @@ func (u *UserInterface) run(width, height int, scale float64, title string, cont return u.loop(context) } -// getSize must be called from the main thread. -func (u *UserInterface) glfwSize() (int, int) { - w := int(float64(u.windowWidth) * u.getScale() * u.glfwScale()) - h := int(float64(u.height) * u.getScale() * u.glfwScale()) +// deviceDependentWindowSize must be called from the main thread. +func (u *UserInterface) deviceDependentWindowSize() (int, int) { + w := int(u.toDeviceDependentPixel(float64(u.windowWidth) * u.getScale())) + h := int(u.toDeviceDependentPixel(float64(u.height) * u.getScale())) return w, h } @@ -787,9 +792,9 @@ func (u *UserInterface) getScale() float64 { return u.scale } if u.fullscreenScale == 0 { - v := u.window.GetMonitor().GetVideoMode() - sw := float64(v.Width) / u.glfwScale() / float64(u.width) - sh := float64(v.Height) / u.glfwScale() / float64(u.height) + v := u.currentMonitor().GetVideoMode() + sw := u.toDeviceIndependentPixel(float64(v.Width)) / float64(u.width) + sh := u.toDeviceIndependentPixel(float64(v.Height)) / float64(u.height) s := sw if s > sh { s = sh @@ -848,7 +853,7 @@ func (u *UserInterface) update(context driver.UIContext) error { _ = u.t.Call(func() error { glfw.PollEvents() - u.input.update(u.window, u.getScale()*u.glfwScale()) + u.input.update(u.window) defer hooks.ResumeAudio() @@ -1018,14 +1023,14 @@ func (u *UserInterface) setScreenSize(width, height int, scale float64, fullscre } oldW, oldH := u.window.GetSize() - newW, newH := u.glfwSize() + newW, newH := u.deviceDependentWindowSize() if oldW != newW || oldH != newH { ch := make(chan struct{}) u.window.SetFramebufferSizeCallback(func(_ *glfw.Window, _, _ int) { u.window.SetFramebufferSizeCallback(nil) close(ch) }) - u.window.SetSize(u.glfwSize()) + u.window.SetSize(newW, newH) event: for { glfw.PollEvents()