mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-26 11:48:55 +01:00
e7ad5c52fe
This also changes APIs in internal/glfw to return errors. Updates #2703
275 lines
5.9 KiB
Go
275 lines
5.9 KiB
Go
// SPDX-License-Identifier: Apache-2.0
|
|
// SPDX-FileCopyrightText: 2002-2006 Marcus Geelnard
|
|
// SPDX-FileCopyrightText: 2006-2019 Camilla Löwy <elmindreda@glfw.org>
|
|
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
|
|
|
|
package glfw
|
|
|
|
import (
|
|
"sort"
|
|
)
|
|
|
|
func abs(x int) uint {
|
|
if x < 0 {
|
|
return uint(-x)
|
|
}
|
|
return uint(x)
|
|
}
|
|
|
|
func (v *VidMode) equals(other *VidMode) bool {
|
|
if v.RedBits+v.GreenBits+v.BlueBits != other.RedBits+other.GreenBits+other.BlueBits {
|
|
return false
|
|
}
|
|
|
|
if v.Width != other.Width {
|
|
return false
|
|
}
|
|
|
|
if v.Height != other.Height {
|
|
return false
|
|
}
|
|
|
|
if v.RefreshRate != other.RefreshRate {
|
|
return false
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
func (m *Monitor) refreshVideoModes() error {
|
|
m.modes = m.modes[:0]
|
|
modes, err := m.platformAppendVideoModes(m.modes)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
sort.Slice(modes, func(i, j int) bool {
|
|
a := modes[i]
|
|
b := modes[j]
|
|
abpp := a.RedBits + a.GreenBits + a.BlueBits
|
|
bbpp := b.RedBits + b.GreenBits + b.BlueBits
|
|
if abpp != bbpp {
|
|
return abpp < bbpp
|
|
}
|
|
aarea := a.Width * a.Height
|
|
barea := b.Width * b.Height
|
|
if aarea != barea {
|
|
return aarea < barea
|
|
}
|
|
if a.Width != b.Width {
|
|
return a.Width < b.Width
|
|
}
|
|
return a.RefreshRate < b.RefreshRate
|
|
})
|
|
m.modes = modes
|
|
return nil
|
|
}
|
|
|
|
func inputMonitor(monitor *Monitor, action PeripheralEvent, placement int) error {
|
|
switch action {
|
|
case Connected:
|
|
switch placement {
|
|
case _GLFW_INSERT_FIRST:
|
|
_glfw.monitors = append(_glfw.monitors, nil)
|
|
copy(_glfw.monitors[1:], _glfw.monitors)
|
|
_glfw.monitors[0] = monitor
|
|
case _GLFW_INSERT_LAST:
|
|
_glfw.monitors = append(_glfw.monitors, monitor)
|
|
}
|
|
case Disconnected:
|
|
for _, window := range _glfw.windows {
|
|
if window.monitor == monitor {
|
|
width, height, err := window.platformGetWindowSize()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if err := window.platformSetWindowMonitor(nil, 0, 0, width, height, 0); err != nil {
|
|
return err
|
|
}
|
|
xoff, yoff, _, _, err := window.platformGetWindowFrameSize()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if err := window.platformSetWindowPos(xoff, yoff); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
for i, m := range _glfw.monitors {
|
|
if m == monitor {
|
|
copy(_glfw.monitors[i:], _glfw.monitors[i+1:])
|
|
_glfw.monitors[len(_glfw.monitors)-1] = nil
|
|
_glfw.monitors = _glfw.monitors[:len(_glfw.monitors)-1]
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
if _glfw.callbacks.monitor != nil {
|
|
_glfw.callbacks.monitor(monitor, action)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (m *Monitor) inputMonitorWindow(window *Window) {
|
|
m.window = window
|
|
}
|
|
|
|
func (m *Monitor) chooseVideoMode(desired *VidMode) (*VidMode, error) {
|
|
if err := m.refreshVideoModes(); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// math.MaxUint was added at Go 1.17. See https://github.com/golang/go/issues/28538
|
|
const (
|
|
intSize = 32 << (^uint(0) >> 63)
|
|
maxUint = 1<<intSize - 1
|
|
)
|
|
|
|
var (
|
|
leastColorDiff uint = maxUint
|
|
leastSizeDiff uint = maxUint
|
|
leastRateDiff uint = maxUint
|
|
)
|
|
|
|
var closest *VidMode
|
|
for _, v := range m.modes {
|
|
var colorDiff uint
|
|
if desired.RedBits != DontCare {
|
|
colorDiff += abs(v.RedBits - desired.RedBits)
|
|
}
|
|
if desired.GreenBits != DontCare {
|
|
colorDiff += abs(v.GreenBits - desired.GreenBits)
|
|
}
|
|
if desired.BlueBits != DontCare {
|
|
colorDiff += abs(v.BlueBits - desired.BlueBits)
|
|
}
|
|
|
|
sizeDiff := abs((v.Width-desired.Width)*(v.Width-desired.Width) +
|
|
(v.Height-desired.Height)*(v.Height-desired.Height))
|
|
|
|
var rateDiff uint
|
|
if desired.RefreshRate != DontCare {
|
|
rateDiff = abs(v.RefreshRate - desired.RefreshRate)
|
|
} else {
|
|
rateDiff = maxUint - uint(v.RefreshRate)
|
|
}
|
|
|
|
if colorDiff < leastColorDiff ||
|
|
colorDiff == leastColorDiff && sizeDiff < leastSizeDiff ||
|
|
colorDiff == leastColorDiff && sizeDiff == leastSizeDiff && rateDiff < leastRateDiff {
|
|
closest = v
|
|
leastColorDiff = colorDiff
|
|
leastSizeDiff = sizeDiff
|
|
leastRateDiff = rateDiff
|
|
}
|
|
}
|
|
|
|
return closest, nil
|
|
}
|
|
|
|
func splitBPP(bpp int) (red, green, blue int) {
|
|
// We assume that by 32 the user really meant 24
|
|
if bpp == 32 {
|
|
bpp = 24
|
|
}
|
|
|
|
// Convert "bits per pixel" to red, green & blue sizes
|
|
red = bpp / 3
|
|
green = bpp / 3
|
|
blue = bpp / 3
|
|
delta := bpp - (red * 3)
|
|
if delta >= 1 {
|
|
green++
|
|
}
|
|
if delta == 2 {
|
|
red++
|
|
}
|
|
return
|
|
}
|
|
|
|
// GLFW public APIs
|
|
|
|
func GetMonitors() ([]*Monitor, error) {
|
|
if !_glfw.initialized {
|
|
return nil, NotInitialized
|
|
}
|
|
return _glfw.monitors, nil
|
|
}
|
|
|
|
func GetPrimaryMonitor() (*Monitor, error) {
|
|
if !_glfw.initialized {
|
|
return nil, NotInitialized
|
|
}
|
|
if len(_glfw.monitors) == 0 {
|
|
return nil, nil
|
|
}
|
|
return _glfw.monitors[0], nil
|
|
}
|
|
|
|
func (m *Monitor) GetPos() (xpos, ypos int, err error) {
|
|
if !_glfw.initialized {
|
|
return 0, 0, NotInitialized
|
|
}
|
|
xpos, ypos, ok := m.platformGetMonitorPos()
|
|
if !ok {
|
|
return 0, 0, nil
|
|
}
|
|
return xpos, ypos, nil
|
|
}
|
|
|
|
func (m *Monitor) GetWorkarea() (xpos, ypos, width, height int, err error) {
|
|
if !_glfw.initialized {
|
|
return 0, 0, 0, 0, NotInitialized
|
|
}
|
|
xpos, ypos, width, height = m.platformGetMonitorWorkarea()
|
|
return
|
|
}
|
|
|
|
// GetPhysicalSize is not implemented.
|
|
|
|
func (m *Monitor) GetContentScale() (xscale, yscale float32, err error) {
|
|
if !_glfw.initialized {
|
|
return 0, 0, NotInitialized
|
|
}
|
|
xscale, yscale, err = m.platformGetMonitorContentScale()
|
|
return
|
|
}
|
|
|
|
func (m *Monitor) GetName() (string, error) {
|
|
if !_glfw.initialized {
|
|
return "", NotInitialized
|
|
}
|
|
return m.name, nil
|
|
}
|
|
|
|
// SetUserPointer is not implemented.
|
|
// GetUserPointer is not implemented.
|
|
|
|
func SetMonitorCallback(cbfun MonitorCallback) (MonitorCallback, error) {
|
|
if !_glfw.initialized {
|
|
return nil, NotInitialized
|
|
}
|
|
old := _glfw.callbacks.monitor
|
|
_glfw.callbacks.monitor = cbfun
|
|
return old, nil
|
|
}
|
|
|
|
func (m *Monitor) GetVideoModes() ([]*VidMode, error) {
|
|
if !_glfw.initialized {
|
|
return nil, NotInitialized
|
|
}
|
|
return m.modes, nil
|
|
}
|
|
|
|
func (m *Monitor) GetVideoMode() (*VidMode, error) {
|
|
if !_glfw.initialized {
|
|
return nil, NotInitialized
|
|
}
|
|
return m.platformGetVideoMode(), nil
|
|
}
|
|
|
|
// SetGamma is not implemented.
|
|
// GetGammaRamp is not implemented.
|
|
// SetGammaRamp is not implemented.
|