Newer
Older
kotlin-webgl-test / src / main / kotlin / games / perses / game / Game.kt
rnentjes on 21 Mar 2018 5 KB Update kotlin version
package games.perses.game

import games.perses.texture.Textures
import org.khronos.webgl.WebGLRenderingContext
import org.w3c.dom.CanvasRenderingContext2D
import org.w3c.dom.HTMLCanvasElement
import org.w3c.dom.HTMLElement
import kotlin.browser.document
import kotlin.browser.window
import kotlin.js.Date

/**
 * Created by rnentjes on 19-4-16.
 */

enum class DrawMode {
  LINEAR,
  NEAREST
}

class HTMLElements {
  var container: HTMLElement
  var webgl: WebGLRenderingContext
  var canvas2d: CanvasRenderingContext2D

  init {
    container = document.createElement("div") as HTMLElement

    val webGlCanvas = document.createElement("canvas") as HTMLCanvasElement
    val canvas = document.createElement("canvas") as HTMLCanvasElement

    container.setAttribute("style", "position: absolute; left: 0px; top: 0px;")
    webGlCanvas.setAttribute("style", "position: absolute; left: 0px; top: 0px;")
    canvas.setAttribute("style", "position: absolute; left: 0px; top: 0px; z-index: 10; width: 1000px; height: 500px;")

    document.body!!.appendChild(container)
    container.appendChild(webGlCanvas)
    container.appendChild(canvas)

    val canvas2dcanvas = canvas.getContext("2d")

    var webglcanvas = webGlCanvas.getContext("webgl")
    if (webglcanvas == null) {
      console.log("webgl context not found, trying experimental-webgl.")
      webglcanvas = webGlCanvas.getContext("experimental-webgl")
    }

    if (webglcanvas != null) {
      webgl = webglcanvas as WebGLRenderingContext
    } else {
      console.log("webgl?", webglcanvas)
      window.alert("Your browser doesn't seem to support webgl!")

      throw IllegalStateException("Your browser doesn't seem to support webgl!")
    }

    if (canvas2dcanvas != null) {
      canvas2d = canvas2dcanvas as CanvasRenderingContext2D
    } else {
      console.log("canvas2d?", canvas2dcanvas)
      window.alert("Your browser doesn't seem to support 2d canvas!")

      throw IllegalStateException("Your browser doesn't seem to support webgl!")
    }
  }
}

object Game {
  var started = false
  val view: View = View()
  val html: HTMLElements by lazy { HTMLElements() }
  var currentScreen: Screen = DefaultScreen()
  var start = Date().getTime()
  var currentTime = start
  var currentDelta = 0f
  var pause: Boolean = false
  var clearScreenEveryFrame = true

  var clearRed = 0f
  var clearGreen = 0f
  var clearBlue = 0f
  var clearAlpha = 1f

  var fps = 0
  var fpsCount = 0
  var fpsCountTime = 0f

  var borderLeft = 0
  var borderTop = 0

  var focus = true

  init {
    window.onfocus = {
      //println("GOT FOCUS!")

      focus = true
      ""
    }
    window.onblur = {
      //println("LOST FOCUS!")

      focus = false
      ""
    }

  }

  fun gl() = html.webgl

  fun resize() {
    val canvas = gl().canvas

    // Check if the canvas is not the same size.
    val windowWidth = window.innerWidth.toInt()
    val windowHeight = window.innerHeight.toInt()

    if (view.lastWindowWidth != windowWidth ||
        view.lastWindowHeight != windowHeight) {
      view.lastWindowWidth = windowWidth
      view.lastWindowHeight = windowHeight
      view.windowWidth = windowWidth
      view.windowHeight = windowHeight

      view.updateView()

      val textCanvas = html.canvas2d.canvas

      // Make the canvas the same size
      canvas.width = view.width.toInt()
      canvas.height = view.height.toInt()

      textCanvas.width = view.width.toInt()
      textCanvas.height = view.height.toInt()

      gl().viewport(0, 0, view.width.toInt(), view.height.toInt())

      borderLeft = (windowWidth - view.windowWidth) / 2
      borderTop = (windowHeight - view.windowHeight) / 2

      canvas.setAttribute("style", "position: absolute; left: ${borderLeft}px; top: ${borderTop}px; z-index: 5; width: ${view.windowWidth}px; height: ${view.windowHeight}px;")
      textCanvas.setAttribute("style", "position: absolute; left: ${borderLeft}px; top: ${borderTop}px; z-index: 10; width: ${view.windowWidth}px; height: ${view.windowHeight}px;")
    }
  }

  fun start(startScreen: Screen) {
    if (started) {
      throw IllegalStateException("You can only start a game once!")
    }

    setScreen(startScreen)

    // start game loop
    started = true
    gameLoop()
  }

  fun setScreen(screen: Screen) {
    currentScreen.unloadResources()

    currentScreen = screen

    screen.loadResources()
  }

  fun setClearColor(r: Float, g: Float, b: Float, a: Float) {
    clearRed = r
    clearGreen = g
    clearBlue = b
    clearAlpha = a
  }

  fun gameLoop() {
    try {
      if (!Textures.ready()) {
        gl().clearColor(1f, 1f, 1f, 1f)
        gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT)
      } else {
        resize()

        if (!pause) {
          html.canvas2d.clearRect(0.0, 0.0, view.width.toDouble(), view.height.toDouble());

          if (clearScreenEveryFrame) {
            gl().clearColor(clearRed, clearGreen, clearBlue, clearAlpha)
            gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT)
          }

          gl().enable(WebGLRenderingContext.BLEND)
          gl().blendFunc(WebGLRenderingContext.SRC_ALPHA, WebGLRenderingContext.ONE_MINUS_SRC_ALPHA) //ONE_MINUS_DST_ALPHA);

          val time = Date().getTime()
          currentDelta = ((time - currentTime) / 1000f).toFloat()
          currentTime = time

          val timeInSeconds = (currentTime - start) / 1000f

          fpsCountTime += currentDelta
          fpsCount++
          while (fpsCountTime > 1f) {
            fps = fpsCount
            fpsCountTime -= 1f
            fpsCount = 0
          }

          if (focus) {
            currentScreen.update(timeInSeconds.toFloat(), currentDelta)
          }

          currentScreen.render()
        }
      }
    } catch (e: Exception) {
      println("Some error...")
      console.log(e)
    }

    window.requestAnimationFrame {
      gameLoop()
    }
  }

}