| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114 |
- // 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
- frameStart time.Time // Frame start time
- frameDelta time.Duration // Duration of last frame
- exit bool
- cbid js.Value
- }
- // Application singleton
- var app *Application
- // App returns the Application singleton, creating it the first time.
- func App() *Application {
- // Return singleton if already created
- if app != nil {
- return app
- }
- app = new(Application)
- // Initialize window
- err := window.Init(canvasId)
- if err != nil {
- panic(err)
- }
- app.IWindow = window.Get()
- // TODO audio setup here
- app.keyState = window.NewKeyState(app) // Create KeyState
- // Create renderer and add default shaders
- app.renderer = renderer.NewRenderer(app.Gls())
- err = app.renderer.AddDefaultShaders()
- if err != nil {
- panic(fmt.Errorf("AddDefaultShaders:%v", err))
- }
- return app
- }
- // Run starts the update loop.
- // It calls the user-provided update function every frame.
- func (app *Application) Run(update func(renderer *renderer.Renderer, deltaTime time.Duration)) {
- // Create channel so later we can prevent application from finishing while we wait for callbacks
- done := make(chan bool, 0)
- // Initialize frame time
- app.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()
- app.frameDelta = now.Sub(app.frameStart)
- app.frameStart = now
- // Call user's update function
- update(app.renderer, app.frameDelta)
- // Set up new callback if not exiting
- if !app.exit {
- app.cbid = js.Global().Call("requestAnimationFrame", tick)
- } else {
- app.Dispatch(OnExit, nil)
- done <- true // Write to done channel to exit the app
- }
- return nil
- })
- app.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
- app.IWindow.Destroy()
- }
- // Exit exits the app.
- func (app *Application) Exit() {
- app.exit = true
- }
- // Renderer returns the application's renderer.
- func (app *Application) Renderer() *renderer.Renderer {
- return app.renderer
- }
- // KeyState returns the application's KeyState.
- func (app *Application) KeyState() *window.KeyState {
- return app.keyState
- }
|