app-browser.go 2.9 KB

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