app.go 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  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/camera/control"
  11. "github.com/g3n/engine/core"
  12. "github.com/g3n/engine/gls"
  13. "github.com/g3n/engine/gui"
  14. "github.com/g3n/engine/light"
  15. "github.com/g3n/engine/math32"
  16. "github.com/g3n/engine/renderer"
  17. "github.com/g3n/engine/util/logger"
  18. "github.com/g3n/engine/window"
  19. )
  20. type App struct {
  21. win window.IWindow // Application window
  22. gl *gls.GLS // OpenGL state
  23. log *logger.Logger // Default application logger
  24. renderer *renderer.Renderer // Renderer object
  25. camPersp *camera.Perspective // Perspective camera
  26. camOrtho *camera.Orthographic // Orthographic camera
  27. camera camera.ICamera // Current camera
  28. orbit *control.OrbitControl // Camera orbit controller
  29. ambLight *light.Ambient // Default ambient light
  30. audio bool // Audio available
  31. vorbis bool // Vorbis decoder available
  32. audioEFX bool // Audio effect extension support available
  33. audioDev *al.Device // Audio player device
  34. captureDev *al.Device // Audio capture device
  35. frameRater *FrameRater // Render loop frame rater
  36. scene *core.Node // Node container for 3D tests
  37. guiroot *gui.Root // Gui root panel
  38. oCpuProfile *string
  39. }
  40. type Options struct {
  41. WinHeight int // Initial window height. Uses screen width if 0
  42. WinWidth int // Initial window width. Uses screen height if 0
  43. VersionMajor int // Application version major
  44. VersionMinor int // Application version minor
  45. LogLevel int // Initial log level
  46. EnableFlags bool // Enable command line flags
  47. TargetFPS uint // Desired FPS
  48. }
  49. // appInstance contains the pointer to the single Application instance
  50. var appInstance *App
  51. // Creates creates and returns the application object using the specified name for
  52. // the window title and log messages
  53. // This functions must be called only once.
  54. func Create(name string, ops Options) (*App, error) {
  55. if appInstance != nil {
  56. return nil, fmt.Errorf("Application already created")
  57. }
  58. app := new(App)
  59. if ops.EnableFlags {
  60. app.oCpuProfile = flag.String("cpuprofile", "", "Activate cpu profiling writing profile to the specified file")
  61. flag.Parse()
  62. }
  63. // Creates application logger
  64. app.log = logger.New(name, nil)
  65. app.log.AddWriter(logger.NewConsole(false))
  66. app.log.SetFormat(logger.FTIME | logger.FMICROS)
  67. app.log.SetLevel(ops.LogLevel)
  68. app.log.Info("%s v%d.%d starting", name, ops.VersionMajor, ops.VersionMinor)
  69. // Window event handling must run on the main OS thread
  70. runtime.LockOSThread()
  71. // Creates window and sets it as the current context
  72. win, err := window.New("glfw", 10, 10, name, false)
  73. if err != nil {
  74. return nil, err
  75. }
  76. // Sets the window size
  77. swidth, sheight := win.GetScreenResolution(nil)
  78. if ops.WinWidth != 0 {
  79. swidth = ops.WinWidth
  80. }
  81. if ops.WinHeight != 0 {
  82. sheight = ops.WinHeight
  83. }
  84. win.SetSize(swidth, sheight)
  85. app.win = win
  86. // Create OpenGL state
  87. gl, err := gls.New()
  88. if err != nil {
  89. return nil, err
  90. }
  91. app.gl = gl
  92. cc := math32.NewColor("gray")
  93. app.gl.ClearColor(cc.R, cc.G, cc.B, 1)
  94. app.gl.Clear(gls.DEPTH_BUFFER_BIT | gls.STENCIL_BUFFER_BIT | gls.COLOR_BUFFER_BIT)
  95. // Creates perspective camera
  96. width, height := app.win.GetSize()
  97. aspect := float32(width) / float32(height)
  98. app.camPersp = camera.NewPerspective(65, aspect, 0.01, 1000)
  99. // Creates orthographic camera
  100. app.camOrtho = camera.NewOrthographic(-2, 2, 2, -2, 0.01, 100)
  101. app.camOrtho.SetPosition(0, 0, 3)
  102. app.camOrtho.LookAt(&math32.Vector3{0, 0, 0})
  103. app.camOrtho.SetZoom(1.0)
  104. // Default camera is perspective
  105. app.camera = app.camPersp
  106. // Creates orbit camera control
  107. // It is important to do this after the root panel subscription
  108. // to avoid GUI events being propagated to the orbit control.
  109. app.orbit = control.NewOrbitControl(app.camera, app.win)
  110. // Creates scene for 3D objects
  111. app.scene = core.NewNode()
  112. // Creates gui root panel
  113. app.guiroot = gui.NewRoot(app.gl, app.win)
  114. // Creates renderer
  115. app.renderer = renderer.NewRenderer(gl)
  116. err = app.renderer.AddDefaultShaders()
  117. if err != nil {
  118. return nil, fmt.Errorf("Error from AddDefaulShaders:%v", err)
  119. }
  120. app.renderer.SetScene(app.scene)
  121. app.renderer.SetGui(app.guiroot)
  122. // Adds white ambient light to the scene
  123. app.ambLight = light.NewAmbient(&math32.Color{1.0, 1.0, 1.0}, 0.5)
  124. app.scene.Add(app.ambLight)
  125. // Create frame rater
  126. app.frameRater = NewFrameRater(60)
  127. // Subscribe to window resize events
  128. app.win.Subscribe(window.OnWindowSize, func(evname string, ev interface{}) {
  129. app.OnWindowResize()
  130. })
  131. return app, nil
  132. }
  133. // App returns the application single instance or nil
  134. // if the application was not created yet
  135. func Get() *App {
  136. return appInstance
  137. }
  138. // Log returns the application logger
  139. func (a *App) Log() *logger.Logger {
  140. return a.log
  141. }
  142. // Window returns the application window
  143. func (a *App) Window() window.IWindow {
  144. return a.win
  145. }
  146. // Gui returns the current application Gui root panel
  147. func (app *App) Gui() *gui.Root {
  148. return app.guiroot
  149. }
  150. // Scene returns the current application 3D scene
  151. func (a *App) Scene() *core.Node {
  152. return a.scene
  153. }
  154. // SetScene sets the 3D scene to be rendered
  155. func (a *App) SetScene(scene *core.Node) {
  156. a.renderer.SetScene(scene)
  157. }
  158. // SetGui sets the root panel of th3 gui to be rendered
  159. func (app *App) SetGui(root *gui.Root) {
  160. app.guiroot = root
  161. app.renderer.SetGui(app.guiroot)
  162. }
  163. // CameraPersp returns the application perspective camera
  164. func (app *App) CameraPersp() *camera.Perspective {
  165. return app.camPersp
  166. }
  167. // Camera returns the current application camera
  168. func (app *App) Camera() camera.ICamera {
  169. return app.camera
  170. }
  171. func (app *App) Renderer() *renderer.Renderer {
  172. return app.renderer
  173. }
  174. // Runs runs the application render loop
  175. func (app *App) Run() error {
  176. for !app.win.ShouldClose() {
  177. // Starts measuring this frame
  178. app.frameRater.Start()
  179. // Renders the current scene and/or gui
  180. rendered, err := app.renderer.Render(app.camera)
  181. if err != nil {
  182. return err
  183. }
  184. app.log.Error("render stats:%+v", app.renderer.Stats())
  185. // Poll input events and process them
  186. app.win.PollEvents()
  187. if rendered {
  188. app.win.SwapBuffers()
  189. }
  190. // Controls the frame rate and updates the FPS for the user
  191. app.frameRater.Wait()
  192. }
  193. return nil
  194. }
  195. // Quit ends the application
  196. func (app *App) Quit() {
  197. app.win.SetShouldClose(true)
  198. }
  199. // OnWindowResize is called when the window resize event is received
  200. func (app *App) OnWindowResize() {
  201. // Get window size and sets the viewport to the same size
  202. width, height := app.win.GetSize()
  203. app.gl.Viewport(0, 0, int32(width), int32(height))
  204. // Sets perspective camera aspect ratio
  205. aspect := float32(width) / float32(height)
  206. app.camPersp.SetAspect(aspect)
  207. app.log.Error("app window resize:%v", aspect)
  208. // Sets the size of GUI root panel size to the size of the screen
  209. if app.guiroot != nil {
  210. app.guiroot.SetSize(float32(width), float32(height))
  211. }
  212. }
  213. // LoadAudioLibs try to load audio libraries
  214. func (a *App) LoadAudioLibs() error {
  215. // Try to load OpenAL
  216. err := al.Load()
  217. if err != nil {
  218. return err
  219. }
  220. // Opens default audio device
  221. a.audioDev, err = al.OpenDevice("")
  222. if a.audioDev == nil {
  223. return fmt.Errorf("Error: %s opening OpenAL default device", err)
  224. }
  225. // Checks for OpenAL effects extension support
  226. if al.IsExtensionPresent("ALC_EXT_EFX") {
  227. a.audioEFX = true
  228. }
  229. // Creates audio context with auxiliary sends
  230. var attribs []int
  231. if a.audioEFX {
  232. attribs = []int{al.MAX_AUXILIARY_SENDS, 4}
  233. }
  234. acx, err := al.CreateContext(a.audioDev, attribs)
  235. if err != nil {
  236. return fmt.Errorf("Error creating audio context:%s", err)
  237. }
  238. // Makes the context the current one
  239. err = al.MakeContextCurrent(acx)
  240. if err != nil {
  241. return fmt.Errorf("Error setting audio context current:%s", err)
  242. }
  243. //log.Info("%s version: %s", al.GetString(al.Vendor), al.GetString(al.Version))
  244. a.audio = true
  245. // Ogg Vorbis support
  246. err = ov.Load()
  247. if err == nil {
  248. a.vorbis = true
  249. vorbis.Load()
  250. }
  251. return nil
  252. }