glfw.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509
  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. // +build !wasm
  5. package window
  6. import (
  7. "bytes"
  8. "fmt"
  9. "image"
  10. _ "image/png"
  11. "os"
  12. "runtime"
  13. "github.com/g3n/engine/core"
  14. "github.com/g3n/engine/gls"
  15. "github.com/g3n/engine/gui/assets"
  16. "github.com/go-gl/glfw/v3.3/glfw"
  17. )
  18. // Keycodes
  19. const (
  20. KeyUnknown = Key(glfw.KeyUnknown)
  21. KeySpace = Key(glfw.KeySpace)
  22. KeyApostrophe = Key(glfw.KeyApostrophe)
  23. KeyComma = Key(glfw.KeyComma)
  24. KeyMinus = Key(glfw.KeyMinus)
  25. KeyPeriod = Key(glfw.KeyPeriod)
  26. KeySlash = Key(glfw.KeySlash)
  27. Key0 = Key(glfw.Key0)
  28. Key1 = Key(glfw.Key1)
  29. Key2 = Key(glfw.Key2)
  30. Key3 = Key(glfw.Key3)
  31. Key4 = Key(glfw.Key4)
  32. Key5 = Key(glfw.Key5)
  33. Key6 = Key(glfw.Key6)
  34. Key7 = Key(glfw.Key7)
  35. Key8 = Key(glfw.Key8)
  36. Key9 = Key(glfw.Key9)
  37. KeySemicolon = Key(glfw.KeySemicolon)
  38. KeyEqual = Key(glfw.KeyEqual)
  39. KeyA = Key(glfw.KeyA)
  40. KeyB = Key(glfw.KeyB)
  41. KeyC = Key(glfw.KeyC)
  42. KeyD = Key(glfw.KeyD)
  43. KeyE = Key(glfw.KeyE)
  44. KeyF = Key(glfw.KeyF)
  45. KeyG = Key(glfw.KeyG)
  46. KeyH = Key(glfw.KeyH)
  47. KeyI = Key(glfw.KeyI)
  48. KeyJ = Key(glfw.KeyJ)
  49. KeyK = Key(glfw.KeyK)
  50. KeyL = Key(glfw.KeyL)
  51. KeyM = Key(glfw.KeyM)
  52. KeyN = Key(glfw.KeyN)
  53. KeyO = Key(glfw.KeyO)
  54. KeyP = Key(glfw.KeyP)
  55. KeyQ = Key(glfw.KeyQ)
  56. KeyR = Key(glfw.KeyR)
  57. KeyS = Key(glfw.KeyS)
  58. KeyT = Key(glfw.KeyT)
  59. KeyU = Key(glfw.KeyU)
  60. KeyV = Key(glfw.KeyV)
  61. KeyW = Key(glfw.KeyW)
  62. KeyX = Key(glfw.KeyX)
  63. KeyY = Key(glfw.KeyY)
  64. KeyZ = Key(glfw.KeyZ)
  65. KeyLeftBracket = Key(glfw.KeyLeftBracket)
  66. KeyBackslash = Key(glfw.KeyBackslash)
  67. KeyRightBracket = Key(glfw.KeyRightBracket)
  68. KeyGraveAccent = Key(glfw.KeyGraveAccent)
  69. KeyWorld1 = Key(glfw.KeyWorld1)
  70. KeyWorld2 = Key(glfw.KeyWorld2)
  71. KeyEscape = Key(glfw.KeyEscape)
  72. KeyEnter = Key(glfw.KeyEnter)
  73. KeyTab = Key(glfw.KeyTab)
  74. KeyBackspace = Key(glfw.KeyBackspace)
  75. KeyInsert = Key(glfw.KeyInsert)
  76. KeyDelete = Key(glfw.KeyDelete)
  77. KeyRight = Key(glfw.KeyRight)
  78. KeyLeft = Key(glfw.KeyLeft)
  79. KeyDown = Key(glfw.KeyDown)
  80. KeyUp = Key(glfw.KeyUp)
  81. KeyPageUp = Key(glfw.KeyPageUp)
  82. KeyPageDown = Key(glfw.KeyPageDown)
  83. KeyHome = Key(glfw.KeyHome)
  84. KeyEnd = Key(glfw.KeyEnd)
  85. KeyCapsLock = Key(glfw.KeyCapsLock)
  86. KeyScrollLock = Key(glfw.KeyScrollLock)
  87. KeyNumLock = Key(glfw.KeyNumLock)
  88. KeyPrintScreen = Key(glfw.KeyPrintScreen)
  89. KeyPause = Key(glfw.KeyPause)
  90. KeyF1 = Key(glfw.KeyF1)
  91. KeyF2 = Key(glfw.KeyF2)
  92. KeyF3 = Key(glfw.KeyF3)
  93. KeyF4 = Key(glfw.KeyF4)
  94. KeyF5 = Key(glfw.KeyF5)
  95. KeyF6 = Key(glfw.KeyF6)
  96. KeyF7 = Key(glfw.KeyF7)
  97. KeyF8 = Key(glfw.KeyF8)
  98. KeyF9 = Key(glfw.KeyF9)
  99. KeyF10 = Key(glfw.KeyF10)
  100. KeyF11 = Key(glfw.KeyF11)
  101. KeyF12 = Key(glfw.KeyF12)
  102. KeyF13 = Key(glfw.KeyF13)
  103. KeyF14 = Key(glfw.KeyF14)
  104. KeyF15 = Key(glfw.KeyF15)
  105. KeyF16 = Key(glfw.KeyF16)
  106. KeyF17 = Key(glfw.KeyF17)
  107. KeyF18 = Key(glfw.KeyF18)
  108. KeyF19 = Key(glfw.KeyF19)
  109. KeyF20 = Key(glfw.KeyF20)
  110. KeyF21 = Key(glfw.KeyF21)
  111. KeyF22 = Key(glfw.KeyF22)
  112. KeyF23 = Key(glfw.KeyF23)
  113. KeyF24 = Key(glfw.KeyF24)
  114. KeyF25 = Key(glfw.KeyF25)
  115. KeyKP0 = Key(glfw.KeyKP0)
  116. KeyKP1 = Key(glfw.KeyKP1)
  117. KeyKP2 = Key(glfw.KeyKP2)
  118. KeyKP3 = Key(glfw.KeyKP3)
  119. KeyKP4 = Key(glfw.KeyKP4)
  120. KeyKP5 = Key(glfw.KeyKP5)
  121. KeyKP6 = Key(glfw.KeyKP6)
  122. KeyKP7 = Key(glfw.KeyKP7)
  123. KeyKP8 = Key(glfw.KeyKP8)
  124. KeyKP9 = Key(glfw.KeyKP9)
  125. KeyKPDecimal = Key(glfw.KeyKPDecimal)
  126. KeyKPDivide = Key(glfw.KeyKPDivide)
  127. KeyKPMultiply = Key(glfw.KeyKPMultiply)
  128. KeyKPSubtract = Key(glfw.KeyKPSubtract)
  129. KeyKPAdd = Key(glfw.KeyKPAdd)
  130. KeyKPEnter = Key(glfw.KeyKPEnter)
  131. KeyKPEqual = Key(glfw.KeyKPEqual)
  132. KeyLeftShift = Key(glfw.KeyLeftShift)
  133. KeyLeftControl = Key(glfw.KeyLeftControl)
  134. KeyLeftAlt = Key(glfw.KeyLeftAlt)
  135. KeyLeftSuper = Key(glfw.KeyLeftSuper)
  136. KeyRightShift = Key(glfw.KeyRightShift)
  137. KeyRightControl = Key(glfw.KeyRightControl)
  138. KeyRightAlt = Key(glfw.KeyRightAlt)
  139. KeyRightSuper = Key(glfw.KeyRightSuper)
  140. KeyMenu = Key(glfw.KeyMenu)
  141. KeyLast = Key(glfw.KeyLast)
  142. )
  143. // Modifier keys
  144. const (
  145. ModShift = ModifierKey(glfw.ModShift)
  146. ModControl = ModifierKey(glfw.ModControl)
  147. ModAlt = ModifierKey(glfw.ModAlt)
  148. ModSuper = ModifierKey(glfw.ModSuper)
  149. )
  150. // Mouse buttons
  151. const (
  152. MouseButton1 = MouseButton(glfw.MouseButton1)
  153. MouseButton2 = MouseButton(glfw.MouseButton2)
  154. MouseButton3 = MouseButton(glfw.MouseButton3)
  155. MouseButton4 = MouseButton(glfw.MouseButton4)
  156. MouseButton5 = MouseButton(glfw.MouseButton5)
  157. MouseButton6 = MouseButton(glfw.MouseButton6)
  158. MouseButton7 = MouseButton(glfw.MouseButton7)
  159. MouseButton8 = MouseButton(glfw.MouseButton8)
  160. MouseButtonLast = MouseButton(glfw.MouseButtonLast)
  161. MouseButtonLeft = MouseButton(glfw.MouseButtonLeft)
  162. MouseButtonRight = MouseButton(glfw.MouseButtonRight)
  163. MouseButtonMiddle = MouseButton(glfw.MouseButtonMiddle)
  164. )
  165. // Input modes
  166. const (
  167. CursorInputMode = InputMode(glfw.CursorMode) // See Cursor mode values
  168. StickyKeysInputMode = InputMode(glfw.StickyKeysMode) // Value can be either 1 or 0
  169. StickyMouseButtonsInputMode = InputMode(glfw.StickyMouseButtonsMode) // Value can be either 1 or 0
  170. )
  171. // Cursor mode values
  172. const (
  173. CursorNormal = CursorMode(glfw.CursorNormal)
  174. CursorHidden = CursorMode(glfw.CursorHidden)
  175. CursorDisabled = CursorMode(glfw.CursorDisabled)
  176. )
  177. // GlfwWindow describes one glfw window
  178. type GlfwWindow struct {
  179. *glfw.Window // Embedded GLFW window
  180. core.Dispatcher // Embedded event dispatcher
  181. gls *gls.GLS // Associated OpenGL State
  182. fullscreen bool
  183. lastX int
  184. lastY int
  185. lastWidth int
  186. lastHeight int
  187. scaleX float64
  188. scaleY float64
  189. // Events
  190. keyEv KeyEvent
  191. charEv CharEvent
  192. mouseEv MouseEvent
  193. posEv PosEvent
  194. sizeEv SizeEvent
  195. cursorEv CursorEvent
  196. scrollEv ScrollEvent
  197. focusEv FocusEvent
  198. mods ModifierKey // Current modifier keys
  199. // Cursors
  200. cursors map[Cursor]*glfw.Cursor
  201. lastCursorKey Cursor
  202. }
  203. // Init initializes the GlfwWindow singleton with the specified width, height, and title.
  204. func Init(width, height int, title string) error {
  205. // Panic if already created
  206. if win != nil {
  207. panic(fmt.Errorf("can only call window.Init() once"))
  208. }
  209. // OpenGL functions must be executed in the same thread where
  210. // the context was created (by wmgr.CreateWindow())
  211. runtime.LockOSThread()
  212. // Create wrapper window with dispatcher
  213. w := new(GlfwWindow)
  214. w.Dispatcher.Initialize()
  215. var err error
  216. // Initialize GLFW
  217. err = glfw.Init()
  218. if err != nil {
  219. return err
  220. }
  221. // Set window hints
  222. glfw.WindowHint(glfw.ContextVersionMajor, 3)
  223. glfw.WindowHint(glfw.ContextVersionMinor, 3)
  224. glfw.WindowHint(glfw.OpenGLProfile, glfw.OpenGLCoreProfile)
  225. glfw.WindowHint(glfw.Samples, 8)
  226. // Set OpenGL forward compatible context only for OSX because it is required for OSX.
  227. // When this is set, glLineWidth(width) only accepts width=1.0 and generates an error
  228. // for any other values although the spec says it should ignore unsupported widths
  229. // and generate an error only when width <= 0.
  230. if runtime.GOOS == "darwin" {
  231. glfw.WindowHint(glfw.OpenGLForwardCompatible, glfw.True)
  232. }
  233. // Create window and set it as the current context.
  234. // The window is created always as not full screen because if it is
  235. // created as full screen it not possible to revert it to windowed mode.
  236. // At the end of this function, the window will be set to full screen if requested.
  237. w.Window, err = glfw.CreateWindow(width, height, title, nil, nil)
  238. if err != nil {
  239. return err
  240. }
  241. w.MakeContextCurrent()
  242. // Create OpenGL state
  243. w.gls, err = gls.New()
  244. if err != nil {
  245. return err
  246. }
  247. // Compute and store scale
  248. fbw, fbh := w.GetFramebufferSize()
  249. w.scaleX = float64(fbw) / float64(width)
  250. w.scaleY = float64(fbh) / float64(height)
  251. // Create map for cursors
  252. w.cursors = make(map[Cursor]*glfw.Cursor)
  253. w.lastCursorKey = CursorLast
  254. // Preallocate GLFW standard cursors
  255. w.cursors[ArrowCursor] = glfw.CreateStandardCursor(glfw.ArrowCursor)
  256. w.cursors[IBeamCursor] = glfw.CreateStandardCursor(glfw.IBeamCursor)
  257. w.cursors[CrosshairCursor] = glfw.CreateStandardCursor(glfw.CrosshairCursor)
  258. w.cursors[HandCursor] = glfw.CreateStandardCursor(glfw.HandCursor)
  259. w.cursors[HResizeCursor] = glfw.CreateStandardCursor(glfw.HResizeCursor)
  260. w.cursors[VResizeCursor] = glfw.CreateStandardCursor(glfw.VResizeCursor)
  261. // Preallocate extra G3N standard cursors (diagonal resize cursors)
  262. cursorDiag1Png := assets.MustAsset("cursors/diag1.png") // [/]
  263. cursorDiag2Png := assets.MustAsset("cursors/diag2.png") // [\]
  264. diag1Img, _, err := image.Decode(bytes.NewReader(cursorDiag1Png))
  265. diag2Img, _, err := image.Decode(bytes.NewReader(cursorDiag2Png))
  266. if err != nil {
  267. return err
  268. }
  269. w.cursors[DiagResize1Cursor] = glfw.CreateCursor(diag1Img, 8, 8) // [/]
  270. w.cursors[DiagResize2Cursor] = glfw.CreateCursor(diag2Img, 8, 8) // [\]
  271. // Set up key callback to dispatch event
  272. w.SetKeyCallback(func(x *glfw.Window, key glfw.Key, scancode int, action glfw.Action, mods glfw.ModifierKey) {
  273. w.keyEv.Key = Key(key)
  274. w.keyEv.Mods = ModifierKey(mods)
  275. w.mods = w.keyEv.Mods
  276. if action == glfw.Press {
  277. w.Dispatch(OnKeyDown, &w.keyEv)
  278. } else if action == glfw.Release {
  279. w.Dispatch(OnKeyUp, &w.keyEv)
  280. } else if action == glfw.Repeat {
  281. w.Dispatch(OnKeyRepeat, &w.keyEv)
  282. }
  283. })
  284. // Set up char callback to dispatch event
  285. w.SetCharModsCallback(func(x *glfw.Window, char rune, mods glfw.ModifierKey) {
  286. w.charEv.Char = char
  287. w.charEv.Mods = ModifierKey(mods)
  288. w.Dispatch(OnChar, &w.charEv)
  289. })
  290. // Set up mouse button callback to dispatch event
  291. w.SetMouseButtonCallback(func(x *glfw.Window, button glfw.MouseButton, action glfw.Action, mods glfw.ModifierKey) {
  292. xpos, ypos := x.GetCursorPos()
  293. w.mouseEv.Button = MouseButton(button)
  294. w.mouseEv.Mods = ModifierKey(mods)
  295. w.mouseEv.Xpos = float32(xpos) //* float32(w.scaleX) TODO
  296. w.mouseEv.Ypos = float32(ypos) //* float32(w.scaleY)
  297. if action == glfw.Press {
  298. w.Dispatch(OnMouseDown, &w.mouseEv)
  299. } else if action == glfw.Release {
  300. w.Dispatch(OnMouseUp, &w.mouseEv)
  301. }
  302. })
  303. // Set up window size callback to dispatch event
  304. w.SetSizeCallback(func(x *glfw.Window, width int, height int) {
  305. fbw, fbh := x.GetFramebufferSize()
  306. w.sizeEv.Width = width
  307. w.sizeEv.Height = height
  308. w.scaleX = float64(fbw) / float64(width)
  309. w.scaleY = float64(fbh) / float64(height)
  310. w.Dispatch(OnWindowSize, &w.sizeEv)
  311. })
  312. // Set up window position callback to dispatch event
  313. w.SetPosCallback(func(x *glfw.Window, xpos int, ypos int) {
  314. w.posEv.Xpos = xpos
  315. w.posEv.Ypos = ypos
  316. w.Dispatch(OnWindowPos, &w.posEv)
  317. })
  318. // Set up window focus callback to dispatch event
  319. w.SetFocusCallback(func(x *glfw.Window, focused bool) {
  320. w.focusEv.Focused = focused
  321. w.Dispatch(OnWindowFocus, &w.focusEv)
  322. })
  323. // Set up window cursor position callback to dispatch event
  324. w.SetCursorPosCallback(func(x *glfw.Window, xpos float64, ypos float64) {
  325. w.cursorEv.Xpos = float32(xpos)
  326. w.cursorEv.Ypos = float32(ypos)
  327. w.cursorEv.Mods = w.mods
  328. w.Dispatch(OnCursor, &w.cursorEv)
  329. })
  330. // Set up mouse wheel scroll callback to dispatch event
  331. w.SetScrollCallback(func(x *glfw.Window, xoff float64, yoff float64) {
  332. w.scrollEv.Xoffset = float32(xoff)
  333. w.scrollEv.Yoffset = float32(yoff)
  334. w.scrollEv.Mods = w.mods
  335. w.Dispatch(OnScroll, &w.scrollEv)
  336. })
  337. win = w // Set singleton
  338. return nil
  339. }
  340. // Gls returns the associated OpenGL state.
  341. func (w *GlfwWindow) Gls() *gls.GLS {
  342. return w.gls
  343. }
  344. // FullScreen returns whether this windows is currently fullscreen.
  345. func (w *GlfwWindow) FullScreen() bool {
  346. return w.fullscreen
  347. }
  348. // SetFullScreen sets this window as fullscreen on the primary monitor
  349. // TODO allow for fullscreen with resolutions different than the monitor's
  350. func (w *GlfwWindow) SetFullScreen(full bool) {
  351. // If already in the desired state, nothing to do
  352. if w.fullscreen == full {
  353. return
  354. }
  355. // Set window fullscreen on the primary monitor
  356. if full {
  357. // Save current position and size of the window
  358. w.lastX, w.lastY = w.GetPos()
  359. w.lastWidth, w.lastHeight = w.GetSize()
  360. // Get size of primary monitor
  361. mon := glfw.GetPrimaryMonitor()
  362. vmode := mon.GetVideoMode()
  363. width := vmode.Width
  364. height := vmode.Height
  365. // Set as fullscreen on the primary monitor
  366. w.SetMonitor(mon, 0, 0, width, height, vmode.RefreshRate)
  367. w.fullscreen = true
  368. } else {
  369. // Restore window to previous position and size
  370. w.SetMonitor(nil, w.lastX, w.lastY, w.lastWidth, w.lastHeight, glfw.DontCare)
  371. w.fullscreen = false
  372. }
  373. }
  374. // Destroy destroys this window and its context
  375. func (w *GlfwWindow) Destroy() {
  376. w.Window.Destroy()
  377. glfw.Terminate()
  378. runtime.UnlockOSThread() // Important when using the execution tracer
  379. }
  380. // Scale returns this window's DPI scale factor (FramebufferSize / Size)
  381. func (w *GlfwWindow) GetScale() (x float64, y float64) {
  382. return w.scaleX, w.scaleY
  383. }
  384. // ScreenResolution returns the screen resolution
  385. func (w *GlfwWindow) ScreenResolution(p interface{}) (width, height int) {
  386. mon := glfw.GetPrimaryMonitor()
  387. vmode := mon.GetVideoMode()
  388. return vmode.Width, vmode.Height
  389. }
  390. // PollEvents process events in the event queue
  391. func (w *GlfwWindow) PollEvents() {
  392. glfw.PollEvents()
  393. }
  394. // SetSwapInterval sets the number of screen updates to wait from the time SwapBuffer()
  395. // is called before swapping the buffers and returning.
  396. func (w *GlfwWindow) SetSwapInterval(interval int) {
  397. glfw.SwapInterval(interval)
  398. }
  399. // SetCursor sets the window's cursor.
  400. func (w *GlfwWindow) SetCursor(cursor Cursor) {
  401. cur, ok := w.cursors[cursor]
  402. if !ok {
  403. panic("Invalid cursor")
  404. }
  405. w.Window.SetCursor(cur)
  406. }
  407. // CreateCursor creates a new custom cursor and returns an int handle.
  408. func (w *GlfwWindow) CreateCursor(imgFile string, xhot, yhot int) (Cursor, error) {
  409. // Open image file
  410. file, err := os.Open(imgFile)
  411. if err != nil {
  412. return 0, err
  413. }
  414. defer file.Close()
  415. // Decode image
  416. img, _, err := image.Decode(file)
  417. if err != nil {
  418. return 0, err
  419. }
  420. // Create and store cursor
  421. w.lastCursorKey += 1
  422. w.cursors[Cursor(w.lastCursorKey)] = glfw.CreateCursor(img, xhot, yhot)
  423. return w.lastCursorKey, nil
  424. }
  425. // DisposeCursor deletes the existing custom cursor with the provided int handle.
  426. func (w *GlfwWindow) DisposeCursor(cursor Cursor) {
  427. if cursor <= CursorLast {
  428. panic("Can't dispose standard cursor")
  429. }
  430. w.cursors[cursor].Destroy()
  431. delete(w.cursors, cursor)
  432. }
  433. // DisposeAllCursors deletes all existing custom cursors.
  434. func (w *GlfwWindow) DisposeAllCustomCursors() {
  435. // Destroy and delete all custom cursors
  436. for key := range w.cursors {
  437. if key > CursorLast {
  438. w.cursors[key].Destroy()
  439. delete(w.cursors, key)
  440. }
  441. }
  442. // Set the next cursor key as the last standard cursor key + 1
  443. w.lastCursorKey = CursorLast
  444. }
  445. // Center centers the window on the screen.
  446. //func (w *GlfwWindow) Center() {
  447. //
  448. // // TODO
  449. //}