glfw.go 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. // Copyright 2016 The G3N Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package window
  5. import (
  6. "runtime"
  7. "github.com/g3n/engine/core"
  8. "github.com/go-gl/glfw/v3.2/glfw"
  9. )
  10. type GLFW struct {
  11. core.Dispatcher
  12. win *glfw.Window
  13. keyEv KeyEvent
  14. charEv CharEvent
  15. mouseEv MouseEvent
  16. posEv PosEvent
  17. sizeEv SizeEvent
  18. cursorEv CursorEvent
  19. scrollEv ScrollEvent
  20. arrowCursor *glfw.Cursor
  21. ibeamCursor *glfw.Cursor
  22. crosshairCursor *glfw.Cursor
  23. handCursor *glfw.Cursor
  24. hresizeCursor *glfw.Cursor
  25. vresizeCursor *glfw.Cursor
  26. fullScreen bool
  27. lastX int
  28. lastY int
  29. lastWidth int
  30. lastHeight int
  31. }
  32. // Global GLFW initialization flag
  33. // is initialized when the first window is created
  34. var initialized bool = false
  35. func newGLFW(width, height int, title string, full bool) (*GLFW, error) {
  36. // Initialize GLFW once before the first window is created
  37. if !initialized {
  38. err := glfw.Init()
  39. if err != nil {
  40. return nil, err
  41. }
  42. // Sets window hints
  43. glfw.WindowHint(glfw.ContextVersionMajor, 3)
  44. glfw.WindowHint(glfw.ContextVersionMinor, 3)
  45. glfw.WindowHint(glfw.OpenGLProfile, glfw.OpenGLCoreProfile)
  46. glfw.WindowHint(glfw.Samples, 8)
  47. // Sets OpenGL forward compatible context only for OSX because it is required for OSX.
  48. // When this is set glLineWidth(width) only accepts width=1.0 and generates error
  49. // for any other values although the spec says it should ignore non supported widths
  50. // and generate error only when width <= 0.
  51. if runtime.GOOS == "darwin" {
  52. glfw.WindowHint(glfw.OpenGLForwardCompatible, glfw.True)
  53. }
  54. initialized = true
  55. }
  56. // Creates window and sets it as the current context.
  57. // The window is created always as not full screen because if it is
  58. // created as full screen it not possible to revert it to windowed mode.
  59. // At the end of this function, the window will be set to full screen if requested.
  60. win, err := glfw.CreateWindow(width, height, title, nil, nil)
  61. if err != nil {
  62. return nil, err
  63. }
  64. win.MakeContextCurrent()
  65. // Create wrapper window with dispacher
  66. w := new(GLFW)
  67. w.win = win
  68. w.Dispatcher.Initialize()
  69. // Set key callback to dispatch event
  70. win.SetKeyCallback(func(x *glfw.Window, key glfw.Key, scancode int, action glfw.Action, mods glfw.ModifierKey) {
  71. w.keyEv.W = w
  72. w.keyEv.Keycode = Key(key)
  73. w.keyEv.Scancode = scancode
  74. w.keyEv.Action = Action(action)
  75. w.keyEv.Mods = ModifierKey(mods)
  76. if action == glfw.Press {
  77. w.Dispatch(OnKeyDown, &w.keyEv)
  78. return
  79. }
  80. if action == glfw.Release {
  81. w.Dispatch(OnKeyUp, &w.keyEv)
  82. return
  83. }
  84. if action == glfw.Repeat {
  85. w.Dispatch(OnKeyRepeat, &w.keyEv)
  86. return
  87. }
  88. })
  89. // Set char callback
  90. win.SetCharModsCallback(func(x *glfw.Window, char rune, mods glfw.ModifierKey) {
  91. w.charEv.W = w
  92. w.charEv.Char = char
  93. w.charEv.Mods = ModifierKey(mods)
  94. w.Dispatch(OnChar, &w.charEv)
  95. })
  96. // Set mouse button callback to dispatch event
  97. win.SetMouseButtonCallback(func(x *glfw.Window, button glfw.MouseButton, action glfw.Action, mods glfw.ModifierKey) {
  98. xpos, ypos := x.GetCursorPos()
  99. w.mouseEv.W = w
  100. w.mouseEv.Button = MouseButton(button)
  101. w.mouseEv.Action = Action(action)
  102. w.mouseEv.Mods = ModifierKey(mods)
  103. w.mouseEv.Xpos = float32(xpos)
  104. w.mouseEv.Ypos = float32(ypos)
  105. if action == glfw.Press {
  106. w.Dispatch(OnMouseDown, &w.mouseEv)
  107. return
  108. }
  109. if action == glfw.Release {
  110. w.Dispatch(OnMouseUp, &w.mouseEv)
  111. return
  112. }
  113. })
  114. // Set window size callback to dispatch event
  115. win.SetSizeCallback(func(x *glfw.Window, width int, height int) {
  116. w.sizeEv.W = w
  117. w.sizeEv.Width = width
  118. w.sizeEv.Height = height
  119. w.Dispatch(OnWindowSize, &w.sizeEv)
  120. })
  121. // Set window position event callback to dispatch event
  122. win.SetPosCallback(func(x *glfw.Window, xpos int, ypos int) {
  123. w.posEv.W = w
  124. w.posEv.Xpos = xpos
  125. w.posEv.Ypos = ypos
  126. w.Dispatch(OnWindowPos, &w.posEv)
  127. })
  128. // Set window cursor position event callback to dispatch event
  129. win.SetCursorPosCallback(func(x *glfw.Window, xpos float64, ypos float64) {
  130. w.cursorEv.W = w
  131. w.cursorEv.Xpos = float32(xpos)
  132. w.cursorEv.Ypos = float32(ypos)
  133. w.Dispatch(OnCursor, &w.cursorEv)
  134. })
  135. // Set mouse wheel scroll event callback to dispatch event
  136. win.SetScrollCallback(func(x *glfw.Window, xoff float64, yoff float64) {
  137. w.scrollEv.W = w
  138. w.scrollEv.Xoffset = float32(xoff)
  139. w.scrollEv.Yoffset = float32(yoff)
  140. w.Dispatch(OnScroll, &w.scrollEv)
  141. })
  142. // Preallocate standard cursors
  143. w.arrowCursor = glfw.CreateStandardCursor(glfw.ArrowCursor)
  144. w.ibeamCursor = glfw.CreateStandardCursor(glfw.IBeamCursor)
  145. w.crosshairCursor = glfw.CreateStandardCursor(glfw.CrosshairCursor)
  146. w.handCursor = glfw.CreateStandardCursor(glfw.HandCursor)
  147. w.hresizeCursor = glfw.CreateStandardCursor(glfw.HResizeCursor)
  148. w.vresizeCursor = glfw.CreateStandardCursor(glfw.VResizeCursor)
  149. // Sets full screen if requested
  150. if full {
  151. w.SetFullScreen(true)
  152. }
  153. return w, nil
  154. }
  155. // GetScreenResolution returns the resolution of the primary screen in pixels.
  156. // The parameter is currently ignored
  157. func (w *GLFW) GetScreenResolution(p interface{}) (width, height int) {
  158. mon := glfw.GetPrimaryMonitor()
  159. vmode := mon.GetVideoMode()
  160. return vmode.Width, vmode.Height
  161. }
  162. func (w *GLFW) SwapInterval(interval int) {
  163. glfw.SwapInterval(interval)
  164. }
  165. func (w *GLFW) MakeContextCurrent() {
  166. w.win.MakeContextCurrent()
  167. }
  168. func (w *GLFW) GetSize() (width int, height int) {
  169. return w.win.GetSize()
  170. }
  171. func (w *GLFW) SetSize(width int, height int) {
  172. w.win.SetSize(width, height)
  173. }
  174. func (w *GLFW) GetPos() (xpos, ypos int) {
  175. return w.win.GetPos()
  176. }
  177. func (w *GLFW) SetPos(xpos, ypos int) {
  178. w.win.SetPos(xpos, ypos)
  179. }
  180. func (w *GLFW) SetTitle(title string) {
  181. w.win.SetTitle(title)
  182. }
  183. func (w *GLFW) SetStandardCursor(cursor StandardCursor) {
  184. switch cursor {
  185. case ArrowCursor:
  186. w.win.SetCursor(w.arrowCursor)
  187. case IBeamCursor:
  188. w.win.SetCursor(w.ibeamCursor)
  189. case CrosshairCursor:
  190. w.win.SetCursor(w.crosshairCursor)
  191. case HandCursor:
  192. w.win.SetCursor(w.handCursor)
  193. case HResizeCursor:
  194. w.win.SetCursor(w.hresizeCursor)
  195. case VResizeCursor:
  196. w.win.SetCursor(w.vresizeCursor)
  197. default:
  198. panic("Invalid cursor")
  199. }
  200. }
  201. // FullScreen returns this window full screen state for the primary monitor
  202. func (w *GLFW) FullScreen() bool {
  203. return w.fullScreen
  204. }
  205. // SetFullScreen sets this window full screen state for the primary monitor
  206. func (w *GLFW) SetFullScreen(full bool) {
  207. // If already in the desired state, nothing to do
  208. if w.fullScreen == full {
  209. return
  210. }
  211. // Sets this window full screen for the primary monitor
  212. if full {
  213. // Get primary monitor
  214. mon := glfw.GetPrimaryMonitor()
  215. vmode := mon.GetVideoMode()
  216. width := vmode.Width
  217. height := vmode.Height
  218. // Saves current position and size of the window
  219. w.lastX, w.lastY = w.win.GetPos()
  220. w.lastWidth, w.lastHeight = w.win.GetSize()
  221. // Sets monitor for full screen
  222. w.win.SetMonitor(mon, 0, 0, width, height, vmode.RefreshRate)
  223. w.fullScreen = true
  224. } else {
  225. // Restore window to previous position and size
  226. w.win.SetMonitor(nil, w.lastX, w.lastY, w.lastWidth, w.lastHeight, glfw.DontCare)
  227. w.fullScreen = false
  228. }
  229. }
  230. // ShouldClose returns the current state of this window should close flag
  231. func (w *GLFW) ShouldClose() bool {
  232. return w.win.ShouldClose()
  233. }
  234. // SetShouldClose sets the state of this windows should close flag
  235. func (w *GLFW) SetShouldClose(v bool) {
  236. w.win.SetShouldClose(v)
  237. }
  238. func (w *GLFW) SwapBuffers() {
  239. w.win.SwapBuffers()
  240. }
  241. func (w *GLFW) Destroy() {
  242. w.win.Destroy()
  243. w.win = nil
  244. }
  245. func (w *GLFW) PollEvents() {
  246. glfw.PollEvents()
  247. }
  248. func (w *GLFW) GetTime() float64 {
  249. return glfw.GetTime()
  250. }