app.go 5.2 KB

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