glfw.go 16 KB

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