app.go 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. package app
  2. import (
  3. "flag"
  4. "fmt"
  5. "runtime"
  6. "github.com/g3n/engine/audio/al"
  7. "github.com/g3n/engine/audio/ov"
  8. "github.com/g3n/engine/audio/vorbis"
  9. "github.com/g3n/engine/camera"
  10. "github.com/g3n/engine/core"
  11. "github.com/g3n/engine/gls"
  12. "github.com/g3n/engine/math32"
  13. "github.com/g3n/engine/renderer"
  14. "github.com/g3n/engine/util/logger"
  15. "github.com/g3n/engine/window"
  16. )
  17. type App struct {
  18. win window.IWindow // Application window
  19. gl *gls.GLS // Application OpenGL state
  20. log *logger.Logger // Application logger
  21. renderer *renderer.Renderer // Renderer object
  22. camPersp *camera.Perspective // Perspective camera
  23. camOrtho *camera.Orthographic // Orthographic camera
  24. audio bool // Audio available
  25. vorbis bool // Vorbis decoder available
  26. audioEFX bool // Audio effect extension support available
  27. audioDev *al.Device // Audio player device
  28. captureDev *al.Device // Audio capture device
  29. frameRater *FrameRater
  30. oCpuProfile *string
  31. scene *core.Node // Node container for 3D tests
  32. }
  33. type Options struct {
  34. WinHeight int // Initial window height. Uses screen width if 0
  35. WinWidth int // Initial window width. Uses screen height if 0
  36. VersionMajor int // Application version major
  37. VersionMinor int // Application version minor
  38. LogLevel int // Initial log level
  39. EnableFlags bool // Enable command line flags
  40. TargetFPS uint // Desired FPS
  41. }
  42. // appInstance points to the single Application instance
  43. var appInstance *App
  44. // Creates creates and returns the application object using the specified name for
  45. // the window title and log messages
  46. // This functions must be called only once.
  47. func Create(name string, ops Options) (*App, error) {
  48. if appInstance != nil {
  49. return nil, fmt.Errorf("Application already created")
  50. }
  51. app := new(App)
  52. if ops.EnableFlags {
  53. app.oCpuProfile = flag.String("cpuprofile", "", "Activate cpu profiling writing profile to the specified file")
  54. flag.Parse()
  55. }
  56. // Creates application logger
  57. log := logger.New(name, nil)
  58. log.AddWriter(logger.NewConsole(false))
  59. log.SetFormat(logger.FTIME | logger.FMICROS)
  60. log.SetLevel(ops.LogLevel)
  61. log.Info("%s v%d.%d starting", name, ops.VersionMajor, ops.VersionMinor)
  62. // Window event handling must run on the main OS thread
  63. runtime.LockOSThread()
  64. // Creates window and sets it as the current context
  65. win, err := window.New("glfw", 10, 10, name, false)
  66. if err != nil {
  67. return nil, err
  68. }
  69. // Sets the window size
  70. swidth, sheight := win.GetScreenResolution(nil)
  71. if ops.WinWidth != 0 {
  72. swidth = ops.WinWidth
  73. }
  74. if ops.WinHeight != 0 {
  75. sheight = ops.WinHeight
  76. }
  77. win.SetSize(swidth, sheight)
  78. // Create OpenGL state
  79. gl, err := gls.New()
  80. if err != nil {
  81. return nil, err
  82. }
  83. // Creates application object
  84. app.win = win
  85. app.gl = gl
  86. // Creates perspective camera
  87. width, height := app.win.GetSize()
  88. aspect := float32(width) / float32(height)
  89. app.camPersp = camera.NewPerspective(65, aspect, 0.01, 1000)
  90. // Creates orthographic camera
  91. app.camOrtho = camera.NewOrthographic(-2, 2, 2, -2, 0.01, 100)
  92. app.camOrtho.SetPosition(0, 0, 3)
  93. app.camOrtho.LookAt(&math32.Vector3{0, 0, 0})
  94. app.camOrtho.SetZoom(1.0)
  95. // Creates renderer
  96. app.renderer = renderer.NewRenderer(gl)
  97. err = app.renderer.AddDefaultShaders()
  98. if err != nil {
  99. return nil, fmt.Errorf("Error from AddDefaulShaders:%v", err)
  100. }
  101. // Creates scene for 3D objects
  102. app.scene = core.NewNode()
  103. // Create frame rater
  104. app.frameRater = NewFrameRater(60)
  105. // Subscribe to window resize events
  106. app.win.Subscribe(window.OnWindowSize, func(evname string, ev interface{}) {
  107. app.OnWindowResize()
  108. })
  109. return app, nil
  110. }
  111. // Returns the single application instance
  112. func Get() *App {
  113. return appInstance
  114. }
  115. // Window returns the application window
  116. func (a *App) Window() window.IWindow {
  117. return a.win
  118. }
  119. func (a *App) Run() {
  120. for !a.win.ShouldClose() {
  121. // Starts measuring this frame
  122. a.frameRater.Start()
  123. // Poll input events and process them
  124. a.win.PollEvents()
  125. a.win.SwapBuffers()
  126. // Controls the frame rate and updates the FPS for the user
  127. a.frameRater.Wait()
  128. }
  129. }
  130. // OnWindowResize is called when the window resize event is received
  131. func (app *App) OnWindowResize() {
  132. // Sets view port
  133. width, height := app.win.GetSize()
  134. app.gl.Viewport(0, 0, int32(width), int32(height))
  135. aspect := float32(width) / float32(height)
  136. // Sets camera aspect ratio
  137. app.camPersp.SetAspect(aspect)
  138. // Sets GUI root panel size
  139. //ctx.root.SetSize(float32(width), float32(height))
  140. }
  141. // LoadAudioLibs try to load audio libraries
  142. func (a *App) LoadAudioLibs() error {
  143. // Try to load OpenAL
  144. err := al.Load()
  145. if err != nil {
  146. return err
  147. }
  148. // Opens default audio device
  149. a.audioDev, err = al.OpenDevice("")
  150. if a.audioDev == nil {
  151. return fmt.Errorf("Error: %s opening OpenAL default device", err)
  152. }
  153. // Checks for OpenAL effects extension support
  154. if al.IsExtensionPresent("ALC_EXT_EFX") {
  155. a.audioEFX = true
  156. }
  157. // Creates audio context with auxiliary sends
  158. var attribs []int
  159. if a.audioEFX {
  160. attribs = []int{al.MAX_AUXILIARY_SENDS, 4}
  161. }
  162. acx, err := al.CreateContext(a.audioDev, attribs)
  163. if err != nil {
  164. return fmt.Errorf("Error creating audio context:%s", err)
  165. }
  166. // Makes the context the current one
  167. err = al.MakeContextCurrent(acx)
  168. if err != nil {
  169. return fmt.Errorf("Error setting audio context current:%s", err)
  170. }
  171. //log.Info("%s version: %s", al.GetString(al.Vendor), al.GetString(al.Version))
  172. a.audio = true
  173. // Ogg Vorbis support
  174. err = ov.Load()
  175. if err == nil {
  176. a.vorbis = true
  177. vorbis.Load()
  178. }
  179. return nil
  180. }