glfw_windows.go (10594B)
1 // Copyright 2018 The Ebiten Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package glfw 16 17 import ( 18 "image" 19 "image/draw" 20 "math/bits" 21 "runtime" 22 "sync" 23 "unsafe" 24 25 "golang.org/x/sys/windows" 26 ) 27 28 type glfwImage struct { 29 width int32 30 height int32 31 pixels uintptr 32 } 33 34 type glfwWindows map[uintptr]*Window 35 36 var ( 37 theGLFWWindows = glfwWindows{} 38 glfwWindowsM sync.Mutex 39 ) 40 41 func (w glfwWindows) add(win uintptr) *Window { 42 if win == 0 { 43 return nil 44 } 45 ww := &Window{win} 46 glfwWindowsM.Lock() 47 w[win] = ww 48 glfwWindowsM.Unlock() 49 return ww 50 } 51 52 func (w glfwWindows) remove(win uintptr) { 53 glfwWindowsM.Lock() 54 delete(w, win) 55 glfwWindowsM.Unlock() 56 } 57 58 func (w glfwWindows) get(win uintptr) *Window { 59 if win == 0 { 60 return nil 61 } 62 glfwWindowsM.Lock() 63 ww := w[win] 64 glfwWindowsM.Unlock() 65 return ww 66 } 67 68 type Monitor struct { 69 m uintptr 70 } 71 72 func (m *Monitor) GetPos() (int, int) { 73 var x, y int32 74 glfwDLL.call("glfwGetMonitorPos", m.m, uintptr(unsafe.Pointer(&x)), uintptr(unsafe.Pointer(&y))) 75 panicError() 76 return int(x), int(y) 77 } 78 79 func (m *Monitor) GetVideoMode() *VidMode { 80 v := glfwDLL.call("glfwGetVideoMode", m.m) 81 panicError() 82 return &VidMode{ 83 Width: int(*(*int32)(unsafe.Pointer(v))), 84 Height: int(*(*int32)(unsafe.Pointer(v + 4))), 85 RedBits: int(*(*int32)(unsafe.Pointer(v + 8))), 86 GreenBits: int(*(*int32)(unsafe.Pointer(v + 12))), 87 BlueBits: int(*(*int32)(unsafe.Pointer(v + 16))), 88 RefreshRate: int(*(*int32)(unsafe.Pointer(v + 20))), 89 } 90 } 91 92 type Window struct { 93 w uintptr 94 } 95 96 func (w *Window) Destroy() { 97 glfwDLL.call("glfwDestroyWindow", w.w) 98 panicError() 99 theGLFWWindows.remove(w.w) 100 } 101 102 func (w *Window) GetAttrib(attrib Hint) int { 103 r := glfwDLL.call("glfwGetWindowAttrib", w.w, uintptr(attrib)) 104 panicError() 105 return int(r) 106 } 107 108 func (w *Window) SetAttrib(attrib Hint, value int) { 109 glfwDLL.call("glfwSetWindowAttrib", w.w, uintptr(attrib), uintptr(value)) 110 panicError() 111 } 112 113 func (w *Window) GetCursorPos() (x, y float64) { 114 glfwDLL.call("glfwGetCursorPos", w.w, uintptr(unsafe.Pointer(&x)), uintptr(unsafe.Pointer(&y))) 115 panicError() 116 return 117 } 118 119 func (w *Window) GetInputMode(mode InputMode) int { 120 r := glfwDLL.call("glfwGetInputMode", w.w, uintptr(mode)) 121 panicError() 122 return int(r) 123 } 124 125 func (w *Window) GetKey(key Key) Action { 126 r := glfwDLL.call("glfwGetKey", w.w, uintptr(key)) 127 panicError() 128 return Action(r) 129 } 130 131 func (w *Window) GetMonitor() *Monitor { 132 m := glfwDLL.call("glfwGetWindowMonitor", w.w) 133 panicError() 134 if m == 0 { 135 return nil 136 } 137 return &Monitor{m} 138 } 139 140 func (w *Window) GetMouseButton(button MouseButton) Action { 141 r := glfwDLL.call("glfwGetMouseButton", w.w, uintptr(button)) 142 panicError() 143 return Action(r) 144 } 145 146 func (w *Window) GetPos() (int, int) { 147 var x, y int32 148 glfwDLL.call("glfwGetWindowPos", w.w, uintptr(unsafe.Pointer(&x)), uintptr(unsafe.Pointer(&y))) 149 panicError() 150 return int(x), int(y) 151 } 152 153 func (w *Window) GetSize() (int, int) { 154 var width, height int32 155 glfwDLL.call("glfwGetWindowSize", w.w, uintptr(unsafe.Pointer(&width)), uintptr(unsafe.Pointer(&height))) 156 panicError() 157 return int(width), int(height) 158 } 159 160 func (w *Window) Iconify() { 161 glfwDLL.call("glfwIconifyWindow", w.w) 162 panicError() 163 } 164 165 func (w *Window) MakeContextCurrent() { 166 glfwDLL.call("glfwMakeContextCurrent", w.w) 167 panicError() 168 } 169 170 func (w *Window) Maximize() { 171 glfwDLL.call("glfwMaximizeWindow", w.w) 172 panicError() 173 } 174 175 func (w *Window) Restore() { 176 glfwDLL.call("glfwRestoreWindow", w.w) 177 panicError() 178 } 179 180 func (w *Window) SetCharModsCallback(cbfun CharModsCallback) (previous CharModsCallback) { 181 var gcb uintptr 182 if cbfun != nil { 183 gcb = windows.NewCallbackCDecl(func(window uintptr, char rune, mods ModifierKey) uintptr { 184 cbfun(theGLFWWindows.get(window), char, mods) 185 return 0 186 }) 187 } 188 glfwDLL.call("glfwSetCharModsCallback", w.w, gcb) 189 panicError() 190 return nil // TODO 191 } 192 193 func (w *Window) SetFramebufferSizeCallback(cbfun FramebufferSizeCallback) (previous FramebufferSizeCallback) { 194 var gcb uintptr 195 if cbfun != nil { 196 gcb = windows.NewCallbackCDecl(func(window uintptr, width int, height int) uintptr { 197 cbfun(theGLFWWindows.get(window), width, height) 198 return 0 199 }) 200 } 201 glfwDLL.call("glfwSetFramebufferSizeCallback", w.w, gcb) 202 panicError() 203 return nil // TODO 204 } 205 206 func (w *Window) SetScrollCallback(cbfun ScrollCallback) (previous ScrollCallback) { 207 var gcb uintptr 208 if cbfun != nil { 209 gcb = windows.NewCallbackCDecl(func(window uintptr, xoff *float64, yoff *float64) uintptr { 210 // xoff and yoff were originally float64, but there is no good way to pass them on 32bit 211 // machines via NewCallback. We've fixed GLFW side to use pointer values. 212 cbfun(theGLFWWindows.get(window), *xoff, *yoff) 213 return 0 214 }) 215 } 216 glfwDLL.call("glfwSetScrollCallback", w.w, gcb) 217 panicError() 218 return nil // TODO 219 } 220 221 func (w *Window) SetSizeCallback(cbfun SizeCallback) (previous FramebufferSizeCallback) { 222 var gcb uintptr 223 if cbfun != nil { 224 gcb = windows.NewCallbackCDecl(func(window uintptr, width int, height int) uintptr { 225 cbfun(theGLFWWindows.get(window), width, height) 226 return 0 227 }) 228 } 229 glfwDLL.call("glfwSetWindowSizeCallback", w.w, gcb) 230 panicError() 231 return nil // TODO 232 } 233 234 func (w *Window) SetIcon(images []image.Image) { 235 gimgs := make([]glfwImage, len(images)) 236 defer runtime.KeepAlive(gimgs) 237 238 for i, img := range images { 239 b := img.Bounds() 240 m := image.NewNRGBA(image.Rect(0, 0, b.Dx(), b.Dy())) 241 draw.Draw(m, m.Bounds(), img, b.Min, draw.Src) 242 gimgs[i].width = int32(b.Dx()) 243 gimgs[i].height = int32(b.Dy()) 244 gimgs[i].pixels = uintptr(unsafe.Pointer(&m.Pix[0])) 245 } 246 247 glfwDLL.call("glfwSetWindowIcon", w.w, uintptr(len(gimgs)), uintptr(unsafe.Pointer(&gimgs[0]))) 248 panicError() 249 } 250 251 func (w *Window) SetInputMode(mode InputMode, value int) { 252 glfwDLL.call("glfwSetInputMode", w.w, uintptr(mode), uintptr(value)) 253 panicError() 254 } 255 256 func (w *Window) SetMonitor(monitor *Monitor, xpos, ypos, width, height, refreshRate int) { 257 var m uintptr 258 if monitor != nil { 259 m = monitor.m 260 } 261 glfwDLL.call("glfwSetWindowMonitor", w.w, m, uintptr(xpos), uintptr(ypos), uintptr(width), uintptr(height), uintptr(refreshRate)) 262 panicError() 263 } 264 265 func (w *Window) SetPos(xpos, ypos int) { 266 glfwDLL.call("glfwSetWindowPos", w.w, uintptr(xpos), uintptr(ypos)) 267 panicError() 268 } 269 270 func (w *Window) SetSize(width, height int) { 271 glfwDLL.call("glfwSetWindowSize", w.w, uintptr(width), uintptr(height)) 272 panicError() 273 } 274 275 func (w *Window) SetTitle(title string) { 276 s := []byte(title) 277 s = append(s, 0) 278 defer runtime.KeepAlive(s) 279 glfwDLL.call("glfwSetWindowTitle", w.w, uintptr(unsafe.Pointer(&s[0]))) 280 panicError() 281 } 282 283 func (w *Window) ShouldClose() bool { 284 r := glfwDLL.call("glfwWindowShouldClose", w.w) 285 panicError() 286 return r == True 287 } 288 289 func (w *Window) Show() { 290 glfwDLL.call("glfwShowWindow", w.w) 291 panicError() 292 } 293 294 func (w *Window) SwapBuffers() { 295 glfwDLL.call("glfwSwapBuffers", w.w) 296 panicError() 297 } 298 299 func CreateWindow(width, height int, title string, monitor *Monitor, share *Window) (*Window, error) { 300 s := []byte(title) 301 s = append(s, 0) 302 defer runtime.KeepAlive(s) 303 304 var gm uintptr 305 if monitor != nil { 306 gm = monitor.m 307 } 308 var gw uintptr 309 if share != nil { 310 gw = share.w 311 } 312 313 w := glfwDLL.call("glfwCreateWindow", uintptr(width), uintptr(height), uintptr(unsafe.Pointer(&s[0])), gm, gw) 314 if w == 0 { 315 return nil, acceptError(APIUnavailable, VersionUnavailable) 316 } 317 return theGLFWWindows.add(w), nil 318 } 319 320 func (j Joystick) GetGUID() string { 321 ptr := glfwDLL.call("glfwGetJoystickGUID", uintptr(j)) 322 panicError() 323 var backed [256]byte 324 as := backed[:0] 325 for i := int32(0); ; i++ { 326 b := *(*byte)(unsafe.Pointer(ptr)) 327 ptr += unsafe.Sizeof(byte(0)) 328 if b == 0 { 329 break 330 } 331 as = append(as, b) 332 } 333 r := string(as) 334 return r 335 } 336 337 func (j Joystick) GetName() string { 338 ptr := glfwDLL.call("glfwGetJoystickName", uintptr(j)) 339 panicError() 340 var backed [256]byte 341 as := backed[:0] 342 for i := int32(0); ; i++ { 343 b := *(*byte)(unsafe.Pointer(ptr)) 344 ptr += unsafe.Sizeof(byte(0)) 345 if b == 0 { 346 break 347 } 348 as = append(as, b) 349 } 350 r := string(as) 351 return r 352 } 353 354 func (j Joystick) GetAxes() []float32 { 355 var l int32 356 ptr := glfwDLL.call("glfwGetJoystickAxes", uintptr(j), uintptr(unsafe.Pointer(&l))) 357 panicError() 358 as := make([]float32, l) 359 for i := int32(0); i < l; i++ { 360 as[i] = *(*float32)(unsafe.Pointer(ptr)) 361 ptr += unsafe.Sizeof(float32(0)) 362 } 363 return as 364 } 365 366 func (j Joystick) GetButtons() []byte { 367 var l int32 368 ptr := glfwDLL.call("glfwGetJoystickButtons", uintptr(j), uintptr(unsafe.Pointer(&l))) 369 panicError() 370 bs := make([]byte, l) 371 for i := int32(0); i < l; i++ { 372 bs[i] = *(*byte)(unsafe.Pointer(ptr)) 373 ptr++ 374 } 375 return bs 376 } 377 378 func GetMonitors() []*Monitor { 379 var l int32 380 ptr := glfwDLL.call("glfwGetMonitors", uintptr(unsafe.Pointer(&l))) 381 panicError() 382 ms := make([]*Monitor, l) 383 for i := int32(0); i < l; i++ { 384 m := *(*unsafe.Pointer)(unsafe.Pointer(ptr)) 385 if m != nil { 386 ms[i] = &Monitor{uintptr(m)} 387 } 388 ptr += bits.UintSize / 8 389 } 390 return ms 391 } 392 393 func GetPrimaryMonitor() *Monitor { 394 m := glfwDLL.call("glfwGetPrimaryMonitor") 395 panicError() 396 if m == 0 { 397 return nil 398 } 399 return &Monitor{m} 400 } 401 402 func Init() error { 403 glfwDLL.call("glfwInit") 404 return acceptError(APIUnavailable) 405 } 406 407 func (j Joystick) Present() bool { 408 r := glfwDLL.call("glfwJoystickPresent", uintptr(j)) 409 panicError() 410 return r == True 411 } 412 413 func PollEvents() { 414 glfwDLL.call("glfwPollEvents") 415 panicError() 416 } 417 418 func SetMonitorCallback(cbfun func(monitor *Monitor, event PeripheralEvent)) { 419 var gcb uintptr 420 if cbfun != nil { 421 gcb = windows.NewCallbackCDecl(func(monitor uintptr, event PeripheralEvent) uintptr { 422 var m *Monitor 423 if monitor != 0 { 424 m = &Monitor{monitor} 425 } 426 cbfun(m, event) 427 return 0 428 }) 429 } 430 glfwDLL.call("glfwSetMonitorCallback", gcb) 431 panicError() 432 } 433 434 func SwapInterval(interval int) { 435 glfwDLL.call("glfwSwapInterval", uintptr(interval)) 436 panicError() 437 } 438 439 func Terminate() { 440 flushErrors() 441 glfwDLL.call("glfwTerminate") 442 if err := glfwDLL.unload(); err != nil { 443 panic(err) 444 } 445 } 446 447 func WindowHint(target Hint, hint int) { 448 glfwDLL.call("glfwWindowHint", uintptr(target), uintptr(hint)) 449 panicError() 450 }