| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121 |
- // Copyright 2016 The G3N Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style
- // license that can be found in the LICENSE file.
- // +build wasm
- package app
- import (
- "fmt"
- "github.com/g3n/engine/renderer"
- "github.com/g3n/engine/window"
- "syscall/js"
- "time"
- )
- // Default canvas id
- const canvasId = "g3n-canvas"
- // Application
- type Application struct {
- window.IWindow // Embedded WebGLCanvas
- keyState *window.KeyState // Keep track of keyboard state
- renderer *renderer.Renderer // Renderer object
- startTime time.Time // Application start time
- frameStart time.Time // Frame start time
- frameDelta time.Duration // Duration of last frame
- exit bool
- cbid js.Value
- }
- // App returns the Application singleton, creating it the first time.
- func App() *Application {
- // Return singleton if already created
- if a != nil {
- return a
- }
- a = new(Application)
- // Initialize window
- err := window.Init(canvasId)
- if err != nil {
- panic(err)
- }
- a.IWindow = window.Get()
- // TODO audio setup here
- a.keyState = window.NewKeyState(a) // Create KeyState
- // Create renderer and add default shaders
- a.renderer = renderer.NewRenderer(a.Gls())
- err = a.renderer.AddDefaultShaders()
- if err != nil {
- panic(fmt.Errorf("AddDefaultShaders:%v", err))
- }
- return a
- }
- // Run starts the update loop.
- // It calls the user-provided update function every frame.
- func (a *Application) Run(update func(rend *renderer.Renderer, deltaTime time.Duration)) {
- // Create channel so later we can prevent application from finishing while we wait for callbacks
- done := make(chan bool)
- // Initialize start and frame time
- a.startTime = time.Now()
- a.frameStart = time.Now()
- // Set up recurring calls to user's update function
- var tick js.Func
- tick = js.FuncOf(func(this js.Value, args []js.Value) interface{} {
- // Update frame start and frame delta
- now := time.Now()
- a.frameDelta = now.Sub(a.frameStart)
- a.frameStart = now
- // Call user's update function
- update(a.renderer, a.frameDelta)
- // Set up new callback if not exiting
- if !a.exit {
- a.cbid = js.Global().Call("requestAnimationFrame", tick)
- } else {
- a.Dispatch(OnExit, nil)
- done <- true // Write to done channel to exit the app
- }
- return nil
- })
- defer tick.Release()
- a.cbid = js.Global().Call("requestAnimationFrame", tick)
- // Read from done channel
- // This channel will be empty (except when we want to exit the app)
- // It keeps the app from finishing while we wait for the next call to tick()
- <-done
- // Destroy the window
- a.IWindow.Destroy()
- }
- // Exit exits the app.
- func (a *Application) Exit() {
- a.exit = true
- }
- // Renderer returns the application's renderer.
- func (a *Application) Renderer() *renderer.Renderer {
- return a.renderer
- }
- // KeyState returns the application's KeyState.
- func (a *Application) KeyState() *window.KeyState {
- return a.keyState
- }
- // RunTime returns the elapsed duration since the call to Run().
- func (a *Application) RunTime() time.Duration {
- return time.Now().Sub(a.startTime)
- }
|