mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-25 11:18:54 +01:00
glfw: Implement DLL version of the binding
This commit is contained in:
parent
a9455d1c32
commit
a21a4c75b0
@ -14,8 +14,13 @@
|
||||
|
||||
package glfw
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type (
|
||||
Action int
|
||||
ErrorCode int
|
||||
Hint int
|
||||
InputMode int
|
||||
Joystick int
|
||||
@ -88,3 +93,43 @@ const (
|
||||
CursorNormal = 0x00034001
|
||||
NoAPI = 0
|
||||
)
|
||||
|
||||
const (
|
||||
NotInitialized = ErrorCode(0x00010001)
|
||||
NoCurrentContext = ErrorCode(0x00010002)
|
||||
InvalidEnum = ErrorCode(0x00010003)
|
||||
InvalidValue = ErrorCode(0x00010004)
|
||||
OutOfMemory = ErrorCode(0x00010005)
|
||||
APIUnavailable = ErrorCode(0x00010006)
|
||||
VersionUnavailable = ErrorCode(0x00010007)
|
||||
PlatformError = ErrorCode(0x00010008)
|
||||
FormatUnavailable = ErrorCode(0x00010009)
|
||||
NoWindowContext = ErrorCode(0x0001000A)
|
||||
)
|
||||
|
||||
func (e ErrorCode) String() string {
|
||||
switch e {
|
||||
case NotInitialized:
|
||||
return "not initialized"
|
||||
case NoCurrentContext:
|
||||
return "no current context"
|
||||
case InvalidEnum:
|
||||
return "invalid enum"
|
||||
case InvalidValue:
|
||||
return "invalid value"
|
||||
case OutOfMemory:
|
||||
return "out of memory"
|
||||
case APIUnavailable:
|
||||
return "API unavailable"
|
||||
case VersionUnavailable:
|
||||
return "version unavailable"
|
||||
case PlatformError:
|
||||
return "platform error"
|
||||
case FormatUnavailable:
|
||||
return "format unavailable"
|
||||
case NoWindowContext:
|
||||
return "no window context"
|
||||
default:
|
||||
return fmt.Sprintf("GLFW error code (%d)", e)
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,8 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// +build !windows
|
||||
|
||||
package glfw
|
||||
|
||||
import (
|
371
internal/glfw/glfw_windows.go
Normal file
371
internal/glfw/glfw_windows.go
Normal file
@ -0,0 +1,371 @@
|
||||
// Copyright 2018 The Ebiten Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package glfw
|
||||
|
||||
import (
|
||||
"image"
|
||||
"runtime"
|
||||
"sync"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
type glfwWindows map[uintptr]*Window
|
||||
|
||||
var (
|
||||
theGLFWWindows = glfwWindows{}
|
||||
glfwWindowsM sync.Mutex
|
||||
)
|
||||
|
||||
func (w glfwWindows) add(win uintptr) *Window {
|
||||
if win == 0 {
|
||||
return nil
|
||||
}
|
||||
ww := &Window{win}
|
||||
glfwWindowsM.Lock()
|
||||
w[win] = ww
|
||||
glfwWindowsM.Unlock()
|
||||
return ww
|
||||
}
|
||||
|
||||
func (w glfwWindows) remove(win uintptr) {
|
||||
glfwWindowsM.Lock()
|
||||
delete(w, win)
|
||||
glfwWindowsM.Unlock()
|
||||
}
|
||||
|
||||
func (w glfwWindows) get(win uintptr) *Window {
|
||||
if win == 0 {
|
||||
return nil
|
||||
}
|
||||
glfwWindowsM.Lock()
|
||||
ww := w[win]
|
||||
glfwWindowsM.Unlock()
|
||||
return ww
|
||||
}
|
||||
|
||||
type glfwVidMode struct {
|
||||
width int32
|
||||
height int32
|
||||
redBits int32
|
||||
greenBits int32
|
||||
blueBits int32
|
||||
refreshRate int32
|
||||
}
|
||||
|
||||
type Monitor struct {
|
||||
m uintptr
|
||||
}
|
||||
|
||||
func (m *Monitor) GetPos() (x, y int) {
|
||||
glfwDLL.call("glfwGetMonitorPos", m.m, uintptr(unsafe.Pointer(&x)), uintptr(unsafe.Pointer(&y)))
|
||||
panicError()
|
||||
return
|
||||
}
|
||||
|
||||
func (m *Monitor) GetVideoMode() *VidMode {
|
||||
v := glfwDLL.call("glfwGetVideoMode", m.m)
|
||||
panicError()
|
||||
vv := (*glfwVidMode)(unsafe.Pointer(v))
|
||||
return &VidMode{
|
||||
Width: int(vv.width),
|
||||
Height: int(vv.height),
|
||||
RedBits: int(vv.redBits),
|
||||
GreenBits: int(vv.greenBits),
|
||||
RefreshRate: int(vv.refreshRate),
|
||||
}
|
||||
}
|
||||
|
||||
type Window struct {
|
||||
w uintptr
|
||||
}
|
||||
|
||||
func (w *Window) Destroy() {
|
||||
glfwDLL.call("glfwDestroyWindow", w.w)
|
||||
panicError()
|
||||
theGLFWWindows.remove(w.w)
|
||||
}
|
||||
|
||||
func (w *Window) GetAttrib(attrib Hint) int {
|
||||
r := glfwDLL.call("glfwGetWindowAttrib", w.w, uintptr(attrib))
|
||||
panicError()
|
||||
return int(r)
|
||||
}
|
||||
|
||||
func (w *Window) GetCursorPos() (x, y float64) {
|
||||
glfwDLL.call("glfwGetCursorPos", w.w, uintptr(unsafe.Pointer(&x)), uintptr(unsafe.Pointer(&y)))
|
||||
panicError()
|
||||
return
|
||||
}
|
||||
|
||||
func (w *Window) GetInputMode(mode InputMode) int {
|
||||
r := glfwDLL.call("glfwGetInputMode", w.w, uintptr(mode))
|
||||
panicError()
|
||||
return int(r)
|
||||
}
|
||||
|
||||
func (w *Window) GetKey(key Key) Action {
|
||||
r := glfwDLL.call("glfwGetKey", w.w, uintptr(key))
|
||||
panicError()
|
||||
return Action(r)
|
||||
}
|
||||
|
||||
func (w *Window) GetMonitor() *Monitor {
|
||||
m := glfwDLL.call("glfwGetWindowMonitor", w.w)
|
||||
panicError()
|
||||
if m == 0 {
|
||||
return nil
|
||||
}
|
||||
return &Monitor{m}
|
||||
}
|
||||
|
||||
func (w *Window) GetMouseButton(button MouseButton) Action {
|
||||
r := glfwDLL.call("glfwGetMouseButton", w.w, uintptr(button))
|
||||
panicError()
|
||||
return Action(r)
|
||||
}
|
||||
|
||||
func (w *Window) GetPos() (x, y int) {
|
||||
glfwDLL.call("glfwGetWindowPos", w.w, uintptr(unsafe.Pointer(&x)), uintptr(unsafe.Pointer(&y)))
|
||||
panicError()
|
||||
return
|
||||
}
|
||||
|
||||
func (w *Window) GetSize() (width, height int) {
|
||||
glfwDLL.call("glfwGetWindowSize", w.w, uintptr(unsafe.Pointer(&width)), uintptr(unsafe.Pointer(&height)))
|
||||
panicError()
|
||||
return
|
||||
}
|
||||
|
||||
func (w *Window) MakeContextCurrent() {
|
||||
glfwDLL.call("glfwMakeContextCurrent", w.w)
|
||||
panicError()
|
||||
}
|
||||
|
||||
func (w *Window) SetCharModsCallback(cbfun CharModsCallback) (previous CharModsCallback) {
|
||||
var gcb uintptr
|
||||
if cbfun != nil {
|
||||
gcb = windows.NewCallbackCDecl(func(window uintptr, char rune, mods ModifierKey) uintptr {
|
||||
cbfun(theGLFWWindows.get(window), char, mods)
|
||||
return 0
|
||||
})
|
||||
}
|
||||
glfwDLL.call("glfwSetCharModsCallback", w.w, gcb)
|
||||
panicError()
|
||||
return nil // TODO
|
||||
}
|
||||
|
||||
func (w *Window) SetFramebufferSizeCallback(cbfun FramebufferSizeCallback) (previous FramebufferSizeCallback) {
|
||||
var gcb uintptr
|
||||
if cbfun != nil {
|
||||
gcb = windows.NewCallbackCDecl(func(window uintptr, width int, height int) uintptr {
|
||||
cbfun(theGLFWWindows.get(window), width, height)
|
||||
return 0
|
||||
})
|
||||
}
|
||||
glfwDLL.call("glfwSetFramebufferSizeCallback", w.w, gcb)
|
||||
panicError()
|
||||
return nil // TODO
|
||||
}
|
||||
|
||||
func (w *Window) SetScrollCallback(cbfun ScrollCallback) (previous ScrollCallback) {
|
||||
var gcb uintptr
|
||||
if cbfun != nil {
|
||||
gcb = windows.NewCallbackCDecl(func(window uintptr, xoff *float64, yoff *float64) uintptr {
|
||||
// xoff and yoff were originally float64, but there is no good way to pass them on 32bit
|
||||
// machines via NewCallback. We've fixed GLFW side to use pointer values.
|
||||
cbfun(theGLFWWindows.get(window), *xoff, *yoff)
|
||||
return 0
|
||||
})
|
||||
}
|
||||
glfwDLL.call("glfwSetScrollCallback", w.w, gcb)
|
||||
panicError()
|
||||
return nil // TODO
|
||||
}
|
||||
|
||||
func (w *Window) SetIcon(images []image.Image) {
|
||||
// TODO: Implement this
|
||||
|
||||
// glfwDLL.call("glfwSetWindowIcon", w.w, l, p)
|
||||
// panicError()
|
||||
}
|
||||
|
||||
func (w *Window) SetInputMode(mode InputMode, value int) {
|
||||
glfwDLL.call("glfwSetInputMode", w.w, uintptr(mode), uintptr(value))
|
||||
panicError()
|
||||
}
|
||||
|
||||
func (w *Window) SetMonitor(monitor *Monitor, xpos, ypos, width, height, refreshRate int) {
|
||||
var m uintptr
|
||||
if monitor != nil {
|
||||
m = monitor.m
|
||||
}
|
||||
glfwDLL.call("glfwSetWindowMonitor", w.w, m, uintptr(xpos), uintptr(ypos), uintptr(width), uintptr(height), uintptr(refreshRate))
|
||||
panicError()
|
||||
}
|
||||
|
||||
func (w *Window) SetPos(xpos, ypos int) {
|
||||
glfwDLL.call("glfwSetWindowPos", w.w, uintptr(xpos), uintptr(ypos))
|
||||
panicError()
|
||||
}
|
||||
|
||||
func (w *Window) SetSize(width, height int) {
|
||||
glfwDLL.call("glfwSetWindowSize", w.w, uintptr(width), uintptr(height))
|
||||
panicError()
|
||||
}
|
||||
|
||||
func (w *Window) SetTitle(title string) {
|
||||
s := []byte(title)
|
||||
s = append(s, 0)
|
||||
defer runtime.KeepAlive(s)
|
||||
glfwDLL.call("glfwSetWindowTitle", w.w, uintptr(unsafe.Pointer(&s[0])))
|
||||
panicError()
|
||||
}
|
||||
|
||||
func (w *Window) ShouldClose() bool {
|
||||
r := glfwDLL.call("glfwWindowShouldClose", w.w)
|
||||
panicError()
|
||||
return r == True
|
||||
}
|
||||
|
||||
func (w *Window) Show() {
|
||||
glfwDLL.call("glfwShowWindow", w.w)
|
||||
panicError()
|
||||
}
|
||||
|
||||
func (w *Window) SwapBuffers() {
|
||||
glfwDLL.call("glfwSwapBuffers", w.w)
|
||||
panicError()
|
||||
}
|
||||
|
||||
func CreateWindow(width, height int, title string, monitor *Monitor, share *Window) (*Window, error) {
|
||||
s := []byte(title)
|
||||
s = append(s, 0)
|
||||
defer runtime.KeepAlive(s)
|
||||
|
||||
var gm uintptr
|
||||
if monitor != nil {
|
||||
gm = monitor.m
|
||||
}
|
||||
var gw uintptr
|
||||
if share != nil {
|
||||
gw = share.w
|
||||
}
|
||||
|
||||
w := glfwDLL.call("glfwCreateWindow", uintptr(width), uintptr(height), uintptr(unsafe.Pointer(&s[0])), gm, gw)
|
||||
if w == 0 {
|
||||
return nil, acceptError(APIUnavailable, VersionUnavailable)
|
||||
}
|
||||
return theGLFWWindows.add(w), nil
|
||||
}
|
||||
|
||||
func GetJoystickAxes(joy Joystick) []float32 {
|
||||
l := 0
|
||||
ptr := glfwDLL.call("glfwGetJoystickAxes", uintptr(joy), uintptr(unsafe.Pointer(&l)))
|
||||
panicError()
|
||||
as := make([]float32, l)
|
||||
for i := 0; i < l; i++ {
|
||||
as[i] = *(*float32)(unsafe.Pointer(ptr))
|
||||
ptr += unsafe.Sizeof(float32(0))
|
||||
}
|
||||
return as
|
||||
}
|
||||
|
||||
func GetJoystickButtons(joy Joystick) []byte {
|
||||
l := 0
|
||||
ptr := glfwDLL.call("glfwGetJoystickButtons", uintptr(joy), uintptr(unsafe.Pointer(&l)))
|
||||
panicError()
|
||||
bs := make([]byte, l)
|
||||
for i := 0; i < l; i++ {
|
||||
bs[i] = *(*byte)(unsafe.Pointer(ptr))
|
||||
ptr++
|
||||
}
|
||||
return bs
|
||||
}
|
||||
|
||||
func GetMonitors() []*Monitor {
|
||||
l := 0
|
||||
ptr := glfwDLL.call("glfwGetMonitors", uintptr(unsafe.Pointer(&l)))
|
||||
panicError()
|
||||
ms := make([]*Monitor, l)
|
||||
for i := 0; i < l; i++ {
|
||||
m := *(*unsafe.Pointer)(unsafe.Pointer(ptr))
|
||||
if m != nil {
|
||||
ms[i] = &Monitor{uintptr(m)}
|
||||
}
|
||||
ptr += unsafe.Sizeof(unsafe.Pointer(uintptr(0)))
|
||||
}
|
||||
return ms
|
||||
}
|
||||
|
||||
func GetPrimaryMonitor() *Monitor {
|
||||
m := glfwDLL.call("glfwGetPrimaryMonitor")
|
||||
panicError()
|
||||
if m == 0 {
|
||||
return nil
|
||||
}
|
||||
return &Monitor{m}
|
||||
}
|
||||
|
||||
func Init() error {
|
||||
glfwDLL.call("glfwInit")
|
||||
return acceptError(APIUnavailable)
|
||||
}
|
||||
|
||||
func JoystickPresent(joy Joystick) bool {
|
||||
r := glfwDLL.call("glfwJoystickPresent", uintptr(joy))
|
||||
panicError()
|
||||
return r == True
|
||||
}
|
||||
|
||||
func PollEvents() {
|
||||
glfwDLL.call("glfwPollEvents")
|
||||
panicError()
|
||||
}
|
||||
|
||||
func SetMonitorCallback(cbfun func(monitor *Monitor, event MonitorEvent)) {
|
||||
var gcb uintptr
|
||||
if cbfun != nil {
|
||||
gcb = windows.NewCallbackCDecl(func(monitor uintptr, event MonitorEvent) uintptr {
|
||||
var m *Monitor
|
||||
if monitor != 0 {
|
||||
m = &Monitor{monitor}
|
||||
}
|
||||
cbfun(m, event)
|
||||
return 0
|
||||
})
|
||||
}
|
||||
glfwDLL.call("glfwSetMonitorCallback", gcb)
|
||||
panicError()
|
||||
}
|
||||
|
||||
func SwapInterval(interval int) {
|
||||
glfwDLL.call("glfwSwapInterval", uintptr(interval))
|
||||
panicError()
|
||||
}
|
||||
|
||||
func Terminate() {
|
||||
flushErrors()
|
||||
glfwDLL.call("glfwTerminate")
|
||||
if err := glfwDLL.unload(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func WindowHint(target Hint, hint int) {
|
||||
glfwDLL.call("glfwWindowHint", uintptr(target), uintptr(hint))
|
||||
panicError()
|
||||
}
|
@ -17,16 +17,33 @@ package glfw
|
||||
import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
type dll struct {
|
||||
d *windows.LazyDLL
|
||||
path string
|
||||
d *windows.LazyDLL
|
||||
path string
|
||||
procs map[string]*windows.LazyProc
|
||||
}
|
||||
|
||||
func (d *dll) call(name string, args ...uintptr) uintptr {
|
||||
if d.procs == nil {
|
||||
d.procs = map[string]*windows.LazyProc{}
|
||||
}
|
||||
if _, ok := d.procs[name]; !ok {
|
||||
d.procs[name] = d.d.NewProc(name)
|
||||
}
|
||||
r, _, err := d.procs[name].Call(args...)
|
||||
if err != nil && err.(windows.Errno) != 0 {
|
||||
panic(err)
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func createTempDLL(content io.Reader) (string, error) {
|
||||
@ -73,8 +90,91 @@ func (d *dll) unload() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
if _, err := loadDLL(); err != nil {
|
||||
func uintptrToString(ptr uintptr) string {
|
||||
var bs []byte
|
||||
for {
|
||||
b := *(*byte)(unsafe.Pointer(ptr))
|
||||
if b == 0 {
|
||||
break
|
||||
}
|
||||
bs = append(bs, b)
|
||||
ptr++
|
||||
}
|
||||
return string(bs)
|
||||
}
|
||||
|
||||
type glfwError struct {
|
||||
code ErrorCode
|
||||
desc string
|
||||
}
|
||||
|
||||
func (e *glfwError) Error() string {
|
||||
return fmt.Sprintf("glfw: %s: %s", e.code.String(), e.desc)
|
||||
}
|
||||
|
||||
var lastErr = make(chan *glfwError, 1)
|
||||
|
||||
func fetchError() error {
|
||||
select {
|
||||
case err := <-lastErr:
|
||||
return err
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func panicError() {
|
||||
if err := acceptError(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func flushErrors() {
|
||||
if err := fetchError(); err != nil {
|
||||
panic(fmt.Sprintf("glfw: uncaught error: %s", err))
|
||||
}
|
||||
}
|
||||
|
||||
func acceptError(codes ...ErrorCode) error {
|
||||
err := fetchError()
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
for _, c := range codes {
|
||||
if err.(*glfwError).code == c {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
if err.(*glfwError).code == PlatformError {
|
||||
// PlatformError is not handled here (See github.com/go-gl/glfw's implementation).
|
||||
// TODO: Should we log this error?
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func goGLFWErrorCallback(code uintptr, desc uintptr) uintptr {
|
||||
flushErrors()
|
||||
err := &glfwError{
|
||||
code: ErrorCode(code),
|
||||
desc: uintptrToString(desc),
|
||||
}
|
||||
select {
|
||||
case lastErr <- err:
|
||||
default:
|
||||
panic(fmt.Sprintf("glfw: uncaught error: %s", err))
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
var glfwDLL *dll
|
||||
|
||||
func init() {
|
||||
dll, err := loadDLL()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
glfwDLL = dll
|
||||
|
||||
glfwDLL.call("glfwSetErrorCallback", windows.NewCallbackCDecl(goGLFWErrorCallback))
|
||||
}
|
||||
|
@ -14,10 +14,8 @@
|
||||
|
||||
package glfw
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func (w *Window) GetWin32Window() uintptr {
|
||||
return uintptr(unsafe.Pointer(w.w.GetWin32Window()))
|
||||
r := glfwDLL.call("glfwGetWin32Window", w.w)
|
||||
panicError()
|
||||
return r
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user