glfw.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502
  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. mods ModifierKey // Current modifier keys
  198. // Cursors
  199. cursors map[Cursor]*glfw.Cursor
  200. lastCursorKey Cursor
  201. }
  202. // Init initializes the GlfwWindow singleton with the specified width, height, and title.
  203. func Init(width, height int, title string) error {
  204. // Panic if already created
  205. if win != nil {
  206. panic(fmt.Errorf("can only call window.Init() once"))
  207. }
  208. // OpenGL functions must be executed in the same thread where
  209. // the context was created (by wmgr.CreateWindow())
  210. runtime.LockOSThread()
  211. // Create wrapper window with dispatcher
  212. w := new(GlfwWindow)
  213. w.Dispatcher.Initialize()
  214. var err error
  215. // Initialize GLFW
  216. err = glfw.Init()
  217. if err != nil {
  218. return err
  219. }
  220. // Set window hints
  221. glfw.WindowHint(glfw.ContextVersionMajor, 3)
  222. glfw.WindowHint(glfw.ContextVersionMinor, 3)
  223. glfw.WindowHint(glfw.OpenGLProfile, glfw.OpenGLCoreProfile)
  224. glfw.WindowHint(glfw.Samples, 8)
  225. // Set OpenGL forward compatible context only for OSX because it is required for OSX.
  226. // When this is set, glLineWidth(width) only accepts width=1.0 and generates an error
  227. // for any other values although the spec says it should ignore unsupported widths
  228. // and generate an error only when width <= 0.
  229. if runtime.GOOS == "darwin" {
  230. glfw.WindowHint(glfw.OpenGLForwardCompatible, glfw.True)
  231. }
  232. // Create window and set it as the current context.
  233. // The window is created always as not full screen because if it is
  234. // created as full screen it not possible to revert it to windowed mode.
  235. // At the end of this function, the window will be set to full screen if requested.
  236. w.Window, err = glfw.CreateWindow(width, height, title, nil, nil)
  237. if err != nil {
  238. return err
  239. }
  240. w.MakeContextCurrent()
  241. // Create OpenGL state
  242. w.gls, err = gls.New()
  243. if err != nil {
  244. return err
  245. }
  246. // Compute and store scale
  247. fbw, fbh := w.GetFramebufferSize()
  248. w.scaleX = float64(fbw) / float64(width)
  249. w.scaleY = float64(fbh) / float64(height)
  250. // Create map for cursors
  251. w.cursors = make(map[Cursor]*glfw.Cursor)
  252. w.lastCursorKey = CursorLast
  253. // Preallocate GLFW standard cursors
  254. w.cursors[ArrowCursor] = glfw.CreateStandardCursor(glfw.ArrowCursor)
  255. w.cursors[IBeamCursor] = glfw.CreateStandardCursor(glfw.IBeamCursor)
  256. w.cursors[CrosshairCursor] = glfw.CreateStandardCursor(glfw.CrosshairCursor)
  257. w.cursors[HandCursor] = glfw.CreateStandardCursor(glfw.HandCursor)
  258. w.cursors[HResizeCursor] = glfw.CreateStandardCursor(glfw.HResizeCursor)
  259. w.cursors[VResizeCursor] = glfw.CreateStandardCursor(glfw.VResizeCursor)
  260. // Preallocate extra G3N standard cursors (diagonal resize cursors)
  261. cursorDiag1Png := assets.MustAsset("cursors/diag1.png") // [/]
  262. cursorDiag2Png := assets.MustAsset("cursors/diag2.png") // [\]
  263. diag1Img, _, err := image.Decode(bytes.NewReader(cursorDiag1Png))
  264. diag2Img, _, err := image.Decode(bytes.NewReader(cursorDiag2Png))
  265. if err != nil {
  266. return err
  267. }
  268. w.cursors[DiagResize1Cursor] = glfw.CreateCursor(diag1Img, 8, 8) // [/]
  269. w.cursors[DiagResize2Cursor] = glfw.CreateCursor(diag2Img, 8, 8) // [\]
  270. // Set up key callback to dispatch event
  271. w.SetKeyCallback(func(x *glfw.Window, key glfw.Key, scancode int, action glfw.Action, mods glfw.ModifierKey) {
  272. w.keyEv.Key = Key(key)
  273. w.keyEv.Mods = ModifierKey(mods)
  274. w.mods = w.keyEv.Mods
  275. if action == glfw.Press {
  276. w.Dispatch(OnKeyDown, &w.keyEv)
  277. } else if action == glfw.Release {
  278. w.Dispatch(OnKeyUp, &w.keyEv)
  279. } else if action == glfw.Repeat {
  280. w.Dispatch(OnKeyRepeat, &w.keyEv)
  281. }
  282. })
  283. // Set up char callback to dispatch event
  284. w.SetCharModsCallback(func(x *glfw.Window, char rune, mods glfw.ModifierKey) {
  285. w.charEv.Char = char
  286. w.charEv.Mods = ModifierKey(mods)
  287. w.Dispatch(OnChar, &w.charEv)
  288. })
  289. // Set up mouse button callback to dispatch event
  290. w.SetMouseButtonCallback(func(x *glfw.Window, button glfw.MouseButton, action glfw.Action, mods glfw.ModifierKey) {
  291. xpos, ypos := x.GetCursorPos()
  292. w.mouseEv.Button = MouseButton(button)
  293. w.mouseEv.Mods = ModifierKey(mods)
  294. w.mouseEv.Xpos = float32(xpos) //* float32(w.scaleX) TODO
  295. w.mouseEv.Ypos = float32(ypos) //* float32(w.scaleY)
  296. if action == glfw.Press {
  297. w.Dispatch(OnMouseDown, &w.mouseEv)
  298. } else if action == glfw.Release {
  299. w.Dispatch(OnMouseUp, &w.mouseEv)
  300. }
  301. })
  302. // Set up window size callback to dispatch event
  303. w.SetSizeCallback(func(x *glfw.Window, width int, height int) {
  304. fbw, fbh := x.GetFramebufferSize()
  305. w.sizeEv.Width = width
  306. w.sizeEv.Height = height
  307. w.scaleX = float64(fbw) / float64(width)
  308. w.scaleY = float64(fbh) / float64(height)
  309. w.Dispatch(OnWindowSize, &w.sizeEv)
  310. })
  311. // Set up window position callback to dispatch event
  312. w.SetPosCallback(func(x *glfw.Window, xpos int, ypos int) {
  313. w.posEv.Xpos = xpos
  314. w.posEv.Ypos = ypos
  315. w.Dispatch(OnWindowPos, &w.posEv)
  316. })
  317. // Set up window cursor position callback to dispatch event
  318. w.SetCursorPosCallback(func(x *glfw.Window, xpos float64, ypos float64) {
  319. w.cursorEv.Xpos = float32(xpos)
  320. w.cursorEv.Ypos = float32(ypos)
  321. w.cursorEv.Mods = w.mods
  322. w.Dispatch(OnCursor, &w.cursorEv)
  323. })
  324. // Set up mouse wheel scroll callback to dispatch event
  325. w.SetScrollCallback(func(x *glfw.Window, xoff float64, yoff float64) {
  326. w.scrollEv.Xoffset = float32(xoff)
  327. w.scrollEv.Yoffset = float32(yoff)
  328. w.scrollEv.Mods = w.mods
  329. w.Dispatch(OnScroll, &w.scrollEv)
  330. })
  331. win = w // Set singleton
  332. return nil
  333. }
  334. // Gls returns the associated OpenGL state.
  335. func (w *GlfwWindow) Gls() *gls.GLS {
  336. return w.gls
  337. }
  338. // FullScreen returns whether this windows is currently fullscreen.
  339. func (w *GlfwWindow) FullScreen() bool {
  340. return w.fullscreen
  341. }
  342. // SetFullScreen sets this window as fullscreen on the primary monitor
  343. // TODO allow for fullscreen with resolutions different than the monitor's
  344. func (w *GlfwWindow) SetFullScreen(full bool) {
  345. // If already in the desired state, nothing to do
  346. if w.fullscreen == full {
  347. return
  348. }
  349. // Set window fullscreen on the primary monitor
  350. if full {
  351. // Save current position and size of the window
  352. w.lastX, w.lastY = w.GetPos()
  353. w.lastWidth, w.lastHeight = w.GetSize()
  354. // Get size of primary monitor
  355. mon := glfw.GetPrimaryMonitor()
  356. vmode := mon.GetVideoMode()
  357. width := vmode.Width
  358. height := vmode.Height
  359. // Set as fullscreen on the primary monitor
  360. w.SetMonitor(mon, 0, 0, width, height, vmode.RefreshRate)
  361. w.fullscreen = true
  362. } else {
  363. // Restore window to previous position and size
  364. w.SetMonitor(nil, w.lastX, w.lastY, w.lastWidth, w.lastHeight, glfw.DontCare)
  365. w.fullscreen = false
  366. }
  367. }
  368. // Destroy destroys this window and its context
  369. func (w *GlfwWindow) Destroy() {
  370. w.Window.Destroy()
  371. glfw.Terminate()
  372. runtime.UnlockOSThread() // Important when using the execution tracer
  373. }
  374. // Scale returns this window's DPI scale factor (FramebufferSize / Size)
  375. func (w *GlfwWindow) GetScale() (x float64, y float64) {
  376. return w.scaleX, w.scaleY
  377. }
  378. // ScreenResolution returns the screen resolution
  379. func (w *GlfwWindow) ScreenResolution(p interface{}) (width, height int) {
  380. mon := glfw.GetPrimaryMonitor()
  381. vmode := mon.GetVideoMode()
  382. return vmode.Width, vmode.Height
  383. }
  384. // PollEvents process events in the event queue
  385. func (w *GlfwWindow) PollEvents() {
  386. glfw.PollEvents()
  387. }
  388. // SetSwapInterval sets the number of screen updates to wait from the time SwapBuffer()
  389. // is called before swapping the buffers and returning.
  390. func (w *GlfwWindow) SetSwapInterval(interval int) {
  391. glfw.SwapInterval(interval)
  392. }
  393. // SetCursor sets the window's cursor.
  394. func (w *GlfwWindow) SetCursor(cursor Cursor) {
  395. cur, ok := w.cursors[cursor]
  396. if !ok {
  397. panic("Invalid cursor")
  398. }
  399. w.Window.SetCursor(cur)
  400. }
  401. // CreateCursor creates a new custom cursor and returns an int handle.
  402. func (w *GlfwWindow) CreateCursor(imgFile string, xhot, yhot int) (Cursor, error) {
  403. // Open image file
  404. file, err := os.Open(imgFile)
  405. if err != nil {
  406. return 0, err
  407. }
  408. defer file.Close()
  409. // Decode image
  410. img, _, err := image.Decode(file)
  411. if err != nil {
  412. return 0, err
  413. }
  414. // Create and store cursor
  415. w.lastCursorKey += 1
  416. w.cursors[Cursor(w.lastCursorKey)] = glfw.CreateCursor(img, xhot, yhot)
  417. return w.lastCursorKey, nil
  418. }
  419. // DisposeCursor deletes the existing custom cursor with the provided int handle.
  420. func (w *GlfwWindow) DisposeCursor(cursor Cursor) {
  421. if cursor <= CursorLast {
  422. panic("Can't dispose standard cursor")
  423. }
  424. w.cursors[cursor].Destroy()
  425. delete(w.cursors, cursor)
  426. }
  427. // DisposeAllCursors deletes all existing custom cursors.
  428. func (w *GlfwWindow) DisposeAllCustomCursors() {
  429. // Destroy and delete all custom cursors
  430. for key := range w.cursors {
  431. if key > CursorLast {
  432. w.cursors[key].Destroy()
  433. delete(w.cursors, key)
  434. }
  435. }
  436. // Set the next cursor key as the last standard cursor key + 1
  437. w.lastCursorKey = CursorLast
  438. }
  439. // Center centers the window on the screen.
  440. //func (w *GlfwWindow) Center() {
  441. //
  442. // // TODO
  443. //}