app-browser.go 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  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/renderer"
  9. "github.com/g3n/engine/window"
  10. "syscall/js"
  11. "time"
  12. )
  13. // Default canvas id
  14. const canvasId = "g3n-canvas"
  15. // Application
  16. type Application struct {
  17. window.IWindow // Embedded WebGLCanvas
  18. keyState *window.KeyState // Keep track of keyboard state
  19. renderer *renderer.Renderer // Renderer object
  20. startTime time.Time // Application start time
  21. frameStart time.Time // Frame start time
  22. frameDelta time.Duration // Duration of last frame
  23. exit bool
  24. cbid js.Value
  25. }
  26. // App returns the Application singleton, creating it the first time.
  27. func App() *Application {
  28. // Return singleton if already created
  29. if a != nil {
  30. return a
  31. }
  32. a = new(Application)
  33. // Initialize window
  34. err := window.Init(canvasId)
  35. if err != nil {
  36. panic(err)
  37. }
  38. a.IWindow = window.Get()
  39. // TODO audio setup here
  40. a.keyState = window.NewKeyState(a) // Create KeyState
  41. // Create renderer and add default shaders
  42. a.renderer = renderer.NewRenderer(a.Gls())
  43. err = a.renderer.AddDefaultShaders()
  44. if err != nil {
  45. panic(fmt.Errorf("AddDefaultShaders:%v", err))
  46. }
  47. return a
  48. }
  49. // Run starts the update loop.
  50. // It calls the user-provided update function every frame.
  51. func (a *Application) Run(update func(rend *renderer.Renderer, deltaTime time.Duration)) {
  52. // Create channel so later we can prevent application from finishing while we wait for callbacks
  53. done := make(chan bool)
  54. // Initialize start and frame time
  55. a.startTime = time.Now()
  56. a.frameStart = time.Now()
  57. // Set up recurring calls to user's update function
  58. var tick js.Func
  59. tick = js.FuncOf(func(this js.Value, args []js.Value) interface{} {
  60. // Update frame start and frame delta
  61. now := time.Now()
  62. a.frameDelta = now.Sub(a.frameStart)
  63. a.frameStart = now
  64. // Call user's update function
  65. update(a.renderer, a.frameDelta)
  66. // Set up new callback if not exiting
  67. if !a.exit {
  68. a.cbid = js.Global().Call("requestAnimationFrame", tick)
  69. } else {
  70. a.Dispatch(OnExit, nil)
  71. done <- true // Write to done channel to exit the app
  72. }
  73. return nil
  74. })
  75. defer tick.Release()
  76. a.cbid = js.Global().Call("requestAnimationFrame", tick)
  77. // Read from done channel
  78. // This channel will be empty (except when we want to exit the app)
  79. // It keeps the app from finishing while we wait for the next call to tick()
  80. <-done
  81. // Destroy the window
  82. a.IWindow.Destroy()
  83. }
  84. // Exit exits the app.
  85. func (a *Application) Exit() {
  86. a.exit = true
  87. }
  88. // Renderer returns the application's renderer.
  89. func (a *Application) Renderer() *renderer.Renderer {
  90. return a.renderer
  91. }
  92. // KeyState returns the application's KeyState.
  93. func (a *Application) KeyState() *window.KeyState {
  94. return a.keyState
  95. }
  96. // RunTime returns the elapsed duration since the call to Run().
  97. func (a *Application) RunTime() time.Duration {
  98. return time.Now().Sub(a.startTime)
  99. }