app-browser.go 2.8 KB

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