app-desktop.go 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  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 app
  6. import (
  7. "fmt"
  8. "github.com/g3n/engine/audio/al"
  9. "github.com/g3n/engine/audio/vorbis"
  10. "github.com/g3n/engine/renderer"
  11. "github.com/g3n/engine/window"
  12. "time"
  13. )
  14. // Desktop application defaults
  15. const (
  16. title = "G3N Application"
  17. width = 800
  18. height = 600
  19. )
  20. // OnExit is the event generated by Application when the user
  21. // tries to close the window or the Exit() method is called.
  22. const OnExit = "app.OnExit"
  23. // Application
  24. type Application struct {
  25. window.IWindow // Embedded GlfwWindow
  26. keyState *window.KeyState // Keep track of keyboard state
  27. renderer *renderer.Renderer // Renderer object
  28. audioDev *al.Device // Default audio device
  29. frameStart time.Time // Frame start time
  30. frameDelta time.Duration // Duration of last frame
  31. }
  32. // Application singleton
  33. var app *Application
  34. // App returns the Application singleton, creating it the first time.
  35. func App() *Application {
  36. // Return singleton if already created
  37. if app != nil {
  38. return app
  39. }
  40. app = new(Application)
  41. // Initialize window
  42. err := window.Init(width, height, title)
  43. if err != nil {
  44. panic(err)
  45. }
  46. app.IWindow = window.Get()
  47. app.openDefaultAudioDevice() // Set up audio
  48. app.keyState = window.NewKeyState(app) // Create KeyState
  49. // Create renderer and add default shaders
  50. app.renderer = renderer.NewRenderer(app.Gls())
  51. err = app.renderer.AddDefaultShaders()
  52. if err != nil {
  53. panic(fmt.Errorf("AddDefaultShaders:%v", err))
  54. }
  55. return app
  56. }
  57. // Run starts the update loop.
  58. // It calls the user-provided update function every frame.
  59. func (app *Application) Run(update func(renderer *renderer.Renderer, deltaTime time.Duration)) {
  60. // Initialize frame time
  61. app.frameStart = time.Now()
  62. // Set up recurring calls to user's update function
  63. for true {
  64. // If Exit() was called or there was an attempt to close the window dispatch OnExit event for subscribers.
  65. // If no subscriber cancelled the event, terminates the application.
  66. if app.IWindow.(*window.GlfwWindow).ShouldClose() {
  67. canceled := app.Dispatch(OnExit, nil) // TODO implement the same in app-browser
  68. if canceled {
  69. app.IWindow.(*window.GlfwWindow).SetShouldClose(false)
  70. } else {
  71. break
  72. }
  73. }
  74. // Update frame start and frame delta
  75. now := time.Now()
  76. app.frameDelta = now.Sub(app.frameStart)
  77. app.frameStart = now
  78. // Call user's update function
  79. update(app.renderer, app.frameDelta)
  80. // Swap buffers and poll events
  81. app.IWindow.(*window.GlfwWindow).SwapBuffers()
  82. app.IWindow.(*window.GlfwWindow).PollEvents()
  83. }
  84. // Close default audio device
  85. if app.audioDev != nil {
  86. al.CloseDevice(app.audioDev)
  87. }
  88. // Destroy window
  89. app.Destroy()
  90. }
  91. // Exit requests to terminate the application
  92. // Application will dispatch OnQuit events to registered subscribers which
  93. // can cancel the process by calling CancelDispatch().
  94. func (app *Application) Exit() {
  95. app.IWindow.(*window.GlfwWindow).SetShouldClose(true)
  96. }
  97. // Renderer returns the application's renderer.
  98. func (app *Application) Renderer() *renderer.Renderer {
  99. return app.renderer
  100. }
  101. // KeyState returns the application's KeyState.
  102. func (app *Application) KeyState() *window.KeyState {
  103. return app.keyState
  104. }
  105. // openDefaultAudioDevice opens the default audio device setting it to the current context
  106. func (app *Application) openDefaultAudioDevice() error {
  107. // Opens default audio device
  108. var err error
  109. app.audioDev, err = al.OpenDevice("")
  110. if err != nil {
  111. return fmt.Errorf("opening OpenAL default device: %s", err)
  112. }
  113. // Check for OpenAL effects extension support
  114. var attribs []int
  115. if al.IsExtensionPresent("ALC_EXT_EFX") {
  116. attribs = []int{al.MAX_AUXILIARY_SENDS, 4}
  117. }
  118. // Create audio context
  119. acx, err := al.CreateContext(app.audioDev, attribs)
  120. if err != nil {
  121. return fmt.Errorf("creating OpenAL context: %s", err)
  122. }
  123. // Makes the context the current one
  124. err = al.MakeContextCurrent(acx)
  125. if err != nil {
  126. return fmt.Errorf("setting OpenAL context current: %s", err)
  127. }
  128. // Logs audio library versions
  129. fmt.Println("LOGGING")
  130. log.Info("%s version: %s", al.GetString(al.Vendor), al.GetString(al.Version))
  131. log.Info("%s", vorbis.VersionString())
  132. return nil
  133. }