diff --git a/lib/kotludens/com/persesgames/game/Game.kt b/lib/kotludens/com/persesgames/game/Game.kt index 0f32da7..365e999 100644 --- a/lib/kotludens/com/persesgames/game/Game.kt +++ b/lib/kotludens/com/persesgames/game/Game.kt @@ -3,7 +3,9 @@ import com.persesgames.math.Matrix4 import com.persesgames.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 @@ -17,8 +19,8 @@ override fun render() { // show loading message? - Game.webgl.clearColor(1f, 1f, 0f, 1f) - Game.webgl.clear(WebGLRenderingContext.COLOR_BUFFER_BIT) + Game.gl().clearColor(1f, 1f, 0f, 1f) + Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) } } @@ -68,31 +70,64 @@ } } +class HTMLElements { + var container: HTMLElement + var webgl: WebGLRenderingContext + var canvas2d: CanvasRenderingContext2D + + init { + container = document.createElement("div") as HTMLElement + + var webGlCanvas = document.createElement("canvas") as HTMLCanvasElement + var canvas = document.createElement("canvas") as HTMLCanvasElement + + container.setAttribute("style", "position: relative;") + 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) + + webgl = webGlCanvas.getContext("webgl") as WebGLRenderingContext + canvas2d = canvas.getContext("2d") as CanvasRenderingContext2D + + } +} + object Game { var started = false val view: View = View() - val webgl: WebGLRenderingContext by lazy { - var canvas = document.createElement("canvas") as HTMLCanvasElement - document.body!!.appendChild(canvas) - canvas.getContext("webgl") as WebGLRenderingContext - } - + val html: HTMLElements by lazy { HTMLElements() } var currentScreen: Screen = DefaultScreen() var start = Date().getTime() var currentTime = start var currentDelta = 0f + fun gl() = html.webgl + fun resize() { - var canvas = webgl.canvas + var canvas = gl().canvas + // Check if the canvas is not the same size. if (canvas.width != window.innerWidth.toInt() || canvas.height != window.innerHeight.toInt()) { + var textCanvas = html.canvas2d.canvas // Make the canvas the same size canvas.width = window.innerWidth.toInt() canvas.height = window.innerHeight.toInt() - webgl.viewport(0, 0, canvas.width, canvas.height) + textCanvas.width = 2000 + textCanvas.height = 1000 + + textCanvas.setAttribute("style", "position: absolute; left: 0px; top: 0px; z-index: 10; width: ${window.innerWidth.toInt()}px; height: ${window.innerHeight.toInt()}px;" ) + + html.canvas2d.fillStyle = "green" + html.canvas2d.font = "bold 36pt Arial" + html.canvas2d.fillText("Hello World!", 10.0, 40.0) + + gl().viewport(0, 0, canvas.width, canvas.height) } } @@ -118,8 +153,8 @@ fun gameLoop() { if (!Textures.ready()) { - Game.webgl.clearColor(1f, 0f, 0f, 1f) - Game.webgl.clear(WebGLRenderingContext.COLOR_BUFFER_BIT) + Game.gl().clearColor(1f, 0f, 0f, 1f) + Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) } else { resize(); diff --git a/lib/kotludens/com/persesgames/game/Game.kt b/lib/kotludens/com/persesgames/game/Game.kt index 0f32da7..365e999 100644 --- a/lib/kotludens/com/persesgames/game/Game.kt +++ b/lib/kotludens/com/persesgames/game/Game.kt @@ -3,7 +3,9 @@ import com.persesgames.math.Matrix4 import com.persesgames.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 @@ -17,8 +19,8 @@ override fun render() { // show loading message? - Game.webgl.clearColor(1f, 1f, 0f, 1f) - Game.webgl.clear(WebGLRenderingContext.COLOR_BUFFER_BIT) + Game.gl().clearColor(1f, 1f, 0f, 1f) + Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) } } @@ -68,31 +70,64 @@ } } +class HTMLElements { + var container: HTMLElement + var webgl: WebGLRenderingContext + var canvas2d: CanvasRenderingContext2D + + init { + container = document.createElement("div") as HTMLElement + + var webGlCanvas = document.createElement("canvas") as HTMLCanvasElement + var canvas = document.createElement("canvas") as HTMLCanvasElement + + container.setAttribute("style", "position: relative;") + 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) + + webgl = webGlCanvas.getContext("webgl") as WebGLRenderingContext + canvas2d = canvas.getContext("2d") as CanvasRenderingContext2D + + } +} + object Game { var started = false val view: View = View() - val webgl: WebGLRenderingContext by lazy { - var canvas = document.createElement("canvas") as HTMLCanvasElement - document.body!!.appendChild(canvas) - canvas.getContext("webgl") as WebGLRenderingContext - } - + val html: HTMLElements by lazy { HTMLElements() } var currentScreen: Screen = DefaultScreen() var start = Date().getTime() var currentTime = start var currentDelta = 0f + fun gl() = html.webgl + fun resize() { - var canvas = webgl.canvas + var canvas = gl().canvas + // Check if the canvas is not the same size. if (canvas.width != window.innerWidth.toInt() || canvas.height != window.innerHeight.toInt()) { + var textCanvas = html.canvas2d.canvas // Make the canvas the same size canvas.width = window.innerWidth.toInt() canvas.height = window.innerHeight.toInt() - webgl.viewport(0, 0, canvas.width, canvas.height) + textCanvas.width = 2000 + textCanvas.height = 1000 + + textCanvas.setAttribute("style", "position: absolute; left: 0px; top: 0px; z-index: 10; width: ${window.innerWidth.toInt()}px; height: ${window.innerHeight.toInt()}px;" ) + + html.canvas2d.fillStyle = "green" + html.canvas2d.font = "bold 36pt Arial" + html.canvas2d.fillText("Hello World!", 10.0, 40.0) + + gl().viewport(0, 0, canvas.width, canvas.height) } } @@ -118,8 +153,8 @@ fun gameLoop() { if (!Textures.ready()) { - Game.webgl.clearColor(1f, 0f, 0f, 1f) - Game.webgl.clear(WebGLRenderingContext.COLOR_BUFFER_BIT) + Game.gl().clearColor(1f, 0f, 0f, 1f) + Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) } else { resize(); diff --git a/lib/kotludens/com/persesgames/shader/ShaderProgram.kt b/lib/kotludens/com/persesgames/shader/ShaderProgram.kt index 1657c83..37f50c7 100644 --- a/lib/kotludens/com/persesgames/shader/ShaderProgram.kt +++ b/lib/kotludens/com/persesgames/shader/ShaderProgram.kt @@ -92,6 +92,15 @@ currentIndex += verts.length } + fun queueVertices(verts: Array) { + if((currentIndex + verts.size) >= verticesLength) { + flush(); + } + + vertices.set(verts, currentIndex) + currentIndex += verts.size + } + fun begin() { webgl.useProgram(shaderProgram); webgl.bindBuffer(WebGLRenderingContext.ARRAY_BUFFER, attribBuffer); diff --git a/lib/kotludens/com/persesgames/game/Game.kt b/lib/kotludens/com/persesgames/game/Game.kt index 0f32da7..365e999 100644 --- a/lib/kotludens/com/persesgames/game/Game.kt +++ b/lib/kotludens/com/persesgames/game/Game.kt @@ -3,7 +3,9 @@ import com.persesgames.math.Matrix4 import com.persesgames.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 @@ -17,8 +19,8 @@ override fun render() { // show loading message? - Game.webgl.clearColor(1f, 1f, 0f, 1f) - Game.webgl.clear(WebGLRenderingContext.COLOR_BUFFER_BIT) + Game.gl().clearColor(1f, 1f, 0f, 1f) + Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) } } @@ -68,31 +70,64 @@ } } +class HTMLElements { + var container: HTMLElement + var webgl: WebGLRenderingContext + var canvas2d: CanvasRenderingContext2D + + init { + container = document.createElement("div") as HTMLElement + + var webGlCanvas = document.createElement("canvas") as HTMLCanvasElement + var canvas = document.createElement("canvas") as HTMLCanvasElement + + container.setAttribute("style", "position: relative;") + 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) + + webgl = webGlCanvas.getContext("webgl") as WebGLRenderingContext + canvas2d = canvas.getContext("2d") as CanvasRenderingContext2D + + } +} + object Game { var started = false val view: View = View() - val webgl: WebGLRenderingContext by lazy { - var canvas = document.createElement("canvas") as HTMLCanvasElement - document.body!!.appendChild(canvas) - canvas.getContext("webgl") as WebGLRenderingContext - } - + val html: HTMLElements by lazy { HTMLElements() } var currentScreen: Screen = DefaultScreen() var start = Date().getTime() var currentTime = start var currentDelta = 0f + fun gl() = html.webgl + fun resize() { - var canvas = webgl.canvas + var canvas = gl().canvas + // Check if the canvas is not the same size. if (canvas.width != window.innerWidth.toInt() || canvas.height != window.innerHeight.toInt()) { + var textCanvas = html.canvas2d.canvas // Make the canvas the same size canvas.width = window.innerWidth.toInt() canvas.height = window.innerHeight.toInt() - webgl.viewport(0, 0, canvas.width, canvas.height) + textCanvas.width = 2000 + textCanvas.height = 1000 + + textCanvas.setAttribute("style", "position: absolute; left: 0px; top: 0px; z-index: 10; width: ${window.innerWidth.toInt()}px; height: ${window.innerHeight.toInt()}px;" ) + + html.canvas2d.fillStyle = "green" + html.canvas2d.font = "bold 36pt Arial" + html.canvas2d.fillText("Hello World!", 10.0, 40.0) + + gl().viewport(0, 0, canvas.width, canvas.height) } } @@ -118,8 +153,8 @@ fun gameLoop() { if (!Textures.ready()) { - Game.webgl.clearColor(1f, 0f, 0f, 1f) - Game.webgl.clear(WebGLRenderingContext.COLOR_BUFFER_BIT) + Game.gl().clearColor(1f, 0f, 0f, 1f) + Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) } else { resize(); diff --git a/lib/kotludens/com/persesgames/shader/ShaderProgram.kt b/lib/kotludens/com/persesgames/shader/ShaderProgram.kt index 1657c83..37f50c7 100644 --- a/lib/kotludens/com/persesgames/shader/ShaderProgram.kt +++ b/lib/kotludens/com/persesgames/shader/ShaderProgram.kt @@ -92,6 +92,15 @@ currentIndex += verts.length } + fun queueVertices(verts: Array) { + if((currentIndex + verts.size) >= verticesLength) { + flush(); + } + + vertices.set(verts, currentIndex) + currentIndex += verts.size + } + fun begin() { webgl.useProgram(shaderProgram); webgl.bindBuffer(WebGLRenderingContext.ARRAY_BUFFER, attribBuffer); diff --git a/lib/kotludens/com/persesgames/sprite/SpriteBatch.kt b/lib/kotludens/com/persesgames/sprite/SpriteBatch.kt index f8af424..09a80e7 100644 --- a/lib/kotludens/com/persesgames/sprite/SpriteBatch.kt +++ b/lib/kotludens/com/persesgames/sprite/SpriteBatch.kt @@ -3,6 +3,7 @@ import com.persesgames.game.Game import com.persesgames.shader.ShaderProgram import com.persesgames.shader.VertextAttributeInfo +import com.persesgames.texture.Textures import org.khronos.webgl.Float32Array import org.khronos.webgl.WebGLRenderingContext @@ -18,16 +19,14 @@ private val vertexShaderSource = """ attribute vec2 a_position; - attribute vec3 a_color; + attribute vec2 a_texCoord; uniform mat4 u_projectionView; - varying vec3 v_color; varying vec2 v_textCoord; void main(void) { - v_color = a_color; - v_textCoord = a_position.xy; + v_textCoord = a_texCoord; gl_Position = u_projectionView * vec4(a_position, -1, 1.0); } @@ -38,11 +37,10 @@ uniform sampler2D u_sampler; - varying vec3 v_color; varying vec2 v_textCoord; void main(void) { - gl_FragColor = texture2D(u_sampler, v_textCoord) * vec4(v_color, 1.0); + gl_FragColor = texture2D(u_sampler, v_textCoord); } """ @@ -50,13 +48,13 @@ val program: ShaderProgram; val vainfo = arrayOf( VertextAttributeInfo("a_position", 2), - VertextAttributeInfo("a_color", 3) + VertextAttributeInfo("a_texCoord", 2) ) // TODO: replace with Float32Array when it supports [] or set - private val spriteArray = Array(6, { 0f }) + private val spriteArray = Array(6 * 4, { 0f }) init { - program = ShaderProgram(Game.webgl, WebGLRenderingContext.TRIANGLES, vertexShaderSource, fragmentShaderSource, vainfo) + program = ShaderProgram(Game.gl(), WebGLRenderingContext.TRIANGLES, vertexShaderSource, fragmentShaderSource, vainfo) } fun begin() { @@ -66,6 +64,8 @@ fun draw(sprite: Sprite, x: Float, y: Float) { spriteArray[0] = 1f + Textures.get(sprite.textureName).bind() + program.queueVertices(Float32Array(spriteArray)) } diff --git a/lib/kotludens/com/persesgames/game/Game.kt b/lib/kotludens/com/persesgames/game/Game.kt index 0f32da7..365e999 100644 --- a/lib/kotludens/com/persesgames/game/Game.kt +++ b/lib/kotludens/com/persesgames/game/Game.kt @@ -3,7 +3,9 @@ import com.persesgames.math.Matrix4 import com.persesgames.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 @@ -17,8 +19,8 @@ override fun render() { // show loading message? - Game.webgl.clearColor(1f, 1f, 0f, 1f) - Game.webgl.clear(WebGLRenderingContext.COLOR_BUFFER_BIT) + Game.gl().clearColor(1f, 1f, 0f, 1f) + Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) } } @@ -68,31 +70,64 @@ } } +class HTMLElements { + var container: HTMLElement + var webgl: WebGLRenderingContext + var canvas2d: CanvasRenderingContext2D + + init { + container = document.createElement("div") as HTMLElement + + var webGlCanvas = document.createElement("canvas") as HTMLCanvasElement + var canvas = document.createElement("canvas") as HTMLCanvasElement + + container.setAttribute("style", "position: relative;") + 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) + + webgl = webGlCanvas.getContext("webgl") as WebGLRenderingContext + canvas2d = canvas.getContext("2d") as CanvasRenderingContext2D + + } +} + object Game { var started = false val view: View = View() - val webgl: WebGLRenderingContext by lazy { - var canvas = document.createElement("canvas") as HTMLCanvasElement - document.body!!.appendChild(canvas) - canvas.getContext("webgl") as WebGLRenderingContext - } - + val html: HTMLElements by lazy { HTMLElements() } var currentScreen: Screen = DefaultScreen() var start = Date().getTime() var currentTime = start var currentDelta = 0f + fun gl() = html.webgl + fun resize() { - var canvas = webgl.canvas + var canvas = gl().canvas + // Check if the canvas is not the same size. if (canvas.width != window.innerWidth.toInt() || canvas.height != window.innerHeight.toInt()) { + var textCanvas = html.canvas2d.canvas // Make the canvas the same size canvas.width = window.innerWidth.toInt() canvas.height = window.innerHeight.toInt() - webgl.viewport(0, 0, canvas.width, canvas.height) + textCanvas.width = 2000 + textCanvas.height = 1000 + + textCanvas.setAttribute("style", "position: absolute; left: 0px; top: 0px; z-index: 10; width: ${window.innerWidth.toInt()}px; height: ${window.innerHeight.toInt()}px;" ) + + html.canvas2d.fillStyle = "green" + html.canvas2d.font = "bold 36pt Arial" + html.canvas2d.fillText("Hello World!", 10.0, 40.0) + + gl().viewport(0, 0, canvas.width, canvas.height) } } @@ -118,8 +153,8 @@ fun gameLoop() { if (!Textures.ready()) { - Game.webgl.clearColor(1f, 0f, 0f, 1f) - Game.webgl.clear(WebGLRenderingContext.COLOR_BUFFER_BIT) + Game.gl().clearColor(1f, 0f, 0f, 1f) + Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) } else { resize(); diff --git a/lib/kotludens/com/persesgames/shader/ShaderProgram.kt b/lib/kotludens/com/persesgames/shader/ShaderProgram.kt index 1657c83..37f50c7 100644 --- a/lib/kotludens/com/persesgames/shader/ShaderProgram.kt +++ b/lib/kotludens/com/persesgames/shader/ShaderProgram.kt @@ -92,6 +92,15 @@ currentIndex += verts.length } + fun queueVertices(verts: Array) { + if((currentIndex + verts.size) >= verticesLength) { + flush(); + } + + vertices.set(verts, currentIndex) + currentIndex += verts.size + } + fun begin() { webgl.useProgram(shaderProgram); webgl.bindBuffer(WebGLRenderingContext.ARRAY_BUFFER, attribBuffer); diff --git a/lib/kotludens/com/persesgames/sprite/SpriteBatch.kt b/lib/kotludens/com/persesgames/sprite/SpriteBatch.kt index f8af424..09a80e7 100644 --- a/lib/kotludens/com/persesgames/sprite/SpriteBatch.kt +++ b/lib/kotludens/com/persesgames/sprite/SpriteBatch.kt @@ -3,6 +3,7 @@ import com.persesgames.game.Game import com.persesgames.shader.ShaderProgram import com.persesgames.shader.VertextAttributeInfo +import com.persesgames.texture.Textures import org.khronos.webgl.Float32Array import org.khronos.webgl.WebGLRenderingContext @@ -18,16 +19,14 @@ private val vertexShaderSource = """ attribute vec2 a_position; - attribute vec3 a_color; + attribute vec2 a_texCoord; uniform mat4 u_projectionView; - varying vec3 v_color; varying vec2 v_textCoord; void main(void) { - v_color = a_color; - v_textCoord = a_position.xy; + v_textCoord = a_texCoord; gl_Position = u_projectionView * vec4(a_position, -1, 1.0); } @@ -38,11 +37,10 @@ uniform sampler2D u_sampler; - varying vec3 v_color; varying vec2 v_textCoord; void main(void) { - gl_FragColor = texture2D(u_sampler, v_textCoord) * vec4(v_color, 1.0); + gl_FragColor = texture2D(u_sampler, v_textCoord); } """ @@ -50,13 +48,13 @@ val program: ShaderProgram; val vainfo = arrayOf( VertextAttributeInfo("a_position", 2), - VertextAttributeInfo("a_color", 3) + VertextAttributeInfo("a_texCoord", 2) ) // TODO: replace with Float32Array when it supports [] or set - private val spriteArray = Array(6, { 0f }) + private val spriteArray = Array(6 * 4, { 0f }) init { - program = ShaderProgram(Game.webgl, WebGLRenderingContext.TRIANGLES, vertexShaderSource, fragmentShaderSource, vainfo) + program = ShaderProgram(Game.gl(), WebGLRenderingContext.TRIANGLES, vertexShaderSource, fragmentShaderSource, vainfo) } fun begin() { @@ -66,6 +64,8 @@ fun draw(sprite: Sprite, x: Float, y: Float) { spriteArray[0] = 1f + Textures.get(sprite.textureName).bind() + program.queueVertices(Float32Array(spriteArray)) } diff --git a/lib/kotludens/com/persesgames/texture/Textures.kt b/lib/kotludens/com/persesgames/texture/Textures.kt index baa37e9..4bcaaf8 100644 --- a/lib/kotludens/com/persesgames/texture/Textures.kt +++ b/lib/kotludens/com/persesgames/texture/Textures.kt @@ -15,10 +15,15 @@ class Texture(val glTexture: WebGLTexture) { + fun bind() { + Game.gl().activeTexture(WebGLRenderingContext.TEXTURE0) + Game.gl().bindTexture(WebGLRenderingContext.TEXTURE_2D, glTexture); + } + } object Textures { - var textures = HashMap(); + var textures = HashMap(); var startedLoading = 0 var loaded = 0 @@ -27,7 +32,7 @@ } fun load(name: String, filename: String) { - var gl = Game.webgl + var gl = Game.gl() startedLoading++ @@ -36,7 +41,7 @@ var image = document.createElement("img") as HTMLImageElement image.onload = { textureLoaded(webGlTexture, image) - textures.put(name, webGlTexture) + textures.put(name, Texture(webGlTexture)) loaded++ println("loaded texture $loaded/$startedLoading ${ready()}") } @@ -47,7 +52,7 @@ } fun textureLoaded(texture: WebGLTexture, image: HTMLImageElement) { - var gl = Game.webgl + var gl = Game.gl() gl.bindTexture(WebGLRenderingContext.TEXTURE_2D, texture); gl.pixelStorei(WebGLRenderingContext.UNPACK_FLIP_Y_WEBGL, 1); // second argument must be an int diff --git a/lib/kotludens/com/persesgames/game/Game.kt b/lib/kotludens/com/persesgames/game/Game.kt index 0f32da7..365e999 100644 --- a/lib/kotludens/com/persesgames/game/Game.kt +++ b/lib/kotludens/com/persesgames/game/Game.kt @@ -3,7 +3,9 @@ import com.persesgames.math.Matrix4 import com.persesgames.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 @@ -17,8 +19,8 @@ override fun render() { // show loading message? - Game.webgl.clearColor(1f, 1f, 0f, 1f) - Game.webgl.clear(WebGLRenderingContext.COLOR_BUFFER_BIT) + Game.gl().clearColor(1f, 1f, 0f, 1f) + Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) } } @@ -68,31 +70,64 @@ } } +class HTMLElements { + var container: HTMLElement + var webgl: WebGLRenderingContext + var canvas2d: CanvasRenderingContext2D + + init { + container = document.createElement("div") as HTMLElement + + var webGlCanvas = document.createElement("canvas") as HTMLCanvasElement + var canvas = document.createElement("canvas") as HTMLCanvasElement + + container.setAttribute("style", "position: relative;") + 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) + + webgl = webGlCanvas.getContext("webgl") as WebGLRenderingContext + canvas2d = canvas.getContext("2d") as CanvasRenderingContext2D + + } +} + object Game { var started = false val view: View = View() - val webgl: WebGLRenderingContext by lazy { - var canvas = document.createElement("canvas") as HTMLCanvasElement - document.body!!.appendChild(canvas) - canvas.getContext("webgl") as WebGLRenderingContext - } - + val html: HTMLElements by lazy { HTMLElements() } var currentScreen: Screen = DefaultScreen() var start = Date().getTime() var currentTime = start var currentDelta = 0f + fun gl() = html.webgl + fun resize() { - var canvas = webgl.canvas + var canvas = gl().canvas + // Check if the canvas is not the same size. if (canvas.width != window.innerWidth.toInt() || canvas.height != window.innerHeight.toInt()) { + var textCanvas = html.canvas2d.canvas // Make the canvas the same size canvas.width = window.innerWidth.toInt() canvas.height = window.innerHeight.toInt() - webgl.viewport(0, 0, canvas.width, canvas.height) + textCanvas.width = 2000 + textCanvas.height = 1000 + + textCanvas.setAttribute("style", "position: absolute; left: 0px; top: 0px; z-index: 10; width: ${window.innerWidth.toInt()}px; height: ${window.innerHeight.toInt()}px;" ) + + html.canvas2d.fillStyle = "green" + html.canvas2d.font = "bold 36pt Arial" + html.canvas2d.fillText("Hello World!", 10.0, 40.0) + + gl().viewport(0, 0, canvas.width, canvas.height) } } @@ -118,8 +153,8 @@ fun gameLoop() { if (!Textures.ready()) { - Game.webgl.clearColor(1f, 0f, 0f, 1f) - Game.webgl.clear(WebGLRenderingContext.COLOR_BUFFER_BIT) + Game.gl().clearColor(1f, 0f, 0f, 1f) + Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) } else { resize(); diff --git a/lib/kotludens/com/persesgames/shader/ShaderProgram.kt b/lib/kotludens/com/persesgames/shader/ShaderProgram.kt index 1657c83..37f50c7 100644 --- a/lib/kotludens/com/persesgames/shader/ShaderProgram.kt +++ b/lib/kotludens/com/persesgames/shader/ShaderProgram.kt @@ -92,6 +92,15 @@ currentIndex += verts.length } + fun queueVertices(verts: Array) { + if((currentIndex + verts.size) >= verticesLength) { + flush(); + } + + vertices.set(verts, currentIndex) + currentIndex += verts.size + } + fun begin() { webgl.useProgram(shaderProgram); webgl.bindBuffer(WebGLRenderingContext.ARRAY_BUFFER, attribBuffer); diff --git a/lib/kotludens/com/persesgames/sprite/SpriteBatch.kt b/lib/kotludens/com/persesgames/sprite/SpriteBatch.kt index f8af424..09a80e7 100644 --- a/lib/kotludens/com/persesgames/sprite/SpriteBatch.kt +++ b/lib/kotludens/com/persesgames/sprite/SpriteBatch.kt @@ -3,6 +3,7 @@ import com.persesgames.game.Game import com.persesgames.shader.ShaderProgram import com.persesgames.shader.VertextAttributeInfo +import com.persesgames.texture.Textures import org.khronos.webgl.Float32Array import org.khronos.webgl.WebGLRenderingContext @@ -18,16 +19,14 @@ private val vertexShaderSource = """ attribute vec2 a_position; - attribute vec3 a_color; + attribute vec2 a_texCoord; uniform mat4 u_projectionView; - varying vec3 v_color; varying vec2 v_textCoord; void main(void) { - v_color = a_color; - v_textCoord = a_position.xy; + v_textCoord = a_texCoord; gl_Position = u_projectionView * vec4(a_position, -1, 1.0); } @@ -38,11 +37,10 @@ uniform sampler2D u_sampler; - varying vec3 v_color; varying vec2 v_textCoord; void main(void) { - gl_FragColor = texture2D(u_sampler, v_textCoord) * vec4(v_color, 1.0); + gl_FragColor = texture2D(u_sampler, v_textCoord); } """ @@ -50,13 +48,13 @@ val program: ShaderProgram; val vainfo = arrayOf( VertextAttributeInfo("a_position", 2), - VertextAttributeInfo("a_color", 3) + VertextAttributeInfo("a_texCoord", 2) ) // TODO: replace with Float32Array when it supports [] or set - private val spriteArray = Array(6, { 0f }) + private val spriteArray = Array(6 * 4, { 0f }) init { - program = ShaderProgram(Game.webgl, WebGLRenderingContext.TRIANGLES, vertexShaderSource, fragmentShaderSource, vainfo) + program = ShaderProgram(Game.gl(), WebGLRenderingContext.TRIANGLES, vertexShaderSource, fragmentShaderSource, vainfo) } fun begin() { @@ -66,6 +64,8 @@ fun draw(sprite: Sprite, x: Float, y: Float) { spriteArray[0] = 1f + Textures.get(sprite.textureName).bind() + program.queueVertices(Float32Array(spriteArray)) } diff --git a/lib/kotludens/com/persesgames/texture/Textures.kt b/lib/kotludens/com/persesgames/texture/Textures.kt index baa37e9..4bcaaf8 100644 --- a/lib/kotludens/com/persesgames/texture/Textures.kt +++ b/lib/kotludens/com/persesgames/texture/Textures.kt @@ -15,10 +15,15 @@ class Texture(val glTexture: WebGLTexture) { + fun bind() { + Game.gl().activeTexture(WebGLRenderingContext.TEXTURE0) + Game.gl().bindTexture(WebGLRenderingContext.TEXTURE_2D, glTexture); + } + } object Textures { - var textures = HashMap(); + var textures = HashMap(); var startedLoading = 0 var loaded = 0 @@ -27,7 +32,7 @@ } fun load(name: String, filename: String) { - var gl = Game.webgl + var gl = Game.gl() startedLoading++ @@ -36,7 +41,7 @@ var image = document.createElement("img") as HTMLImageElement image.onload = { textureLoaded(webGlTexture, image) - textures.put(name, webGlTexture) + textures.put(name, Texture(webGlTexture)) loaded++ println("loaded texture $loaded/$startedLoading ${ready()}") } @@ -47,7 +52,7 @@ } fun textureLoaded(texture: WebGLTexture, image: HTMLImageElement) { - var gl = Game.webgl + var gl = Game.gl() gl.bindTexture(WebGLRenderingContext.TEXTURE_2D, texture); gl.pixelStorei(WebGLRenderingContext.UNPACK_FLIP_Y_WEBGL, 1); // second argument must be an int diff --git a/src/com/persesgames/Test.kt b/src/com/persesgames/Test.kt index c11d710..1c4f983 100644 --- a/src/com/persesgames/Test.kt +++ b/src/com/persesgames/Test.kt @@ -6,10 +6,7 @@ import com.persesgames.texture.Textures import org.khronos.webgl.Float32Array import org.khronos.webgl.WebGLRenderingContext -import org.w3c.dom.HTMLCanvasElement -import kotlin.browser.document import kotlin.browser.window -import kotlin.dom.on /** * User: rnentjes @@ -129,8 +126,7 @@ program.begin() - webgl.activeTexture(WebGLRenderingContext.TEXTURE0) - webgl.bindTexture(WebGLRenderingContext.TEXTURE_2D, Textures.get("SHIP")); + Textures.get("SHIP").bind() program.setUniform1i("u_sampler", 0) program.setUniformMatrix4fv("u_projectionView", mMatrix.getFloat32Array()) diff --git a/lib/kotludens/com/persesgames/game/Game.kt b/lib/kotludens/com/persesgames/game/Game.kt index 0f32da7..365e999 100644 --- a/lib/kotludens/com/persesgames/game/Game.kt +++ b/lib/kotludens/com/persesgames/game/Game.kt @@ -3,7 +3,9 @@ import com.persesgames.math.Matrix4 import com.persesgames.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 @@ -17,8 +19,8 @@ override fun render() { // show loading message? - Game.webgl.clearColor(1f, 1f, 0f, 1f) - Game.webgl.clear(WebGLRenderingContext.COLOR_BUFFER_BIT) + Game.gl().clearColor(1f, 1f, 0f, 1f) + Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) } } @@ -68,31 +70,64 @@ } } +class HTMLElements { + var container: HTMLElement + var webgl: WebGLRenderingContext + var canvas2d: CanvasRenderingContext2D + + init { + container = document.createElement("div") as HTMLElement + + var webGlCanvas = document.createElement("canvas") as HTMLCanvasElement + var canvas = document.createElement("canvas") as HTMLCanvasElement + + container.setAttribute("style", "position: relative;") + 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) + + webgl = webGlCanvas.getContext("webgl") as WebGLRenderingContext + canvas2d = canvas.getContext("2d") as CanvasRenderingContext2D + + } +} + object Game { var started = false val view: View = View() - val webgl: WebGLRenderingContext by lazy { - var canvas = document.createElement("canvas") as HTMLCanvasElement - document.body!!.appendChild(canvas) - canvas.getContext("webgl") as WebGLRenderingContext - } - + val html: HTMLElements by lazy { HTMLElements() } var currentScreen: Screen = DefaultScreen() var start = Date().getTime() var currentTime = start var currentDelta = 0f + fun gl() = html.webgl + fun resize() { - var canvas = webgl.canvas + var canvas = gl().canvas + // Check if the canvas is not the same size. if (canvas.width != window.innerWidth.toInt() || canvas.height != window.innerHeight.toInt()) { + var textCanvas = html.canvas2d.canvas // Make the canvas the same size canvas.width = window.innerWidth.toInt() canvas.height = window.innerHeight.toInt() - webgl.viewport(0, 0, canvas.width, canvas.height) + textCanvas.width = 2000 + textCanvas.height = 1000 + + textCanvas.setAttribute("style", "position: absolute; left: 0px; top: 0px; z-index: 10; width: ${window.innerWidth.toInt()}px; height: ${window.innerHeight.toInt()}px;" ) + + html.canvas2d.fillStyle = "green" + html.canvas2d.font = "bold 36pt Arial" + html.canvas2d.fillText("Hello World!", 10.0, 40.0) + + gl().viewport(0, 0, canvas.width, canvas.height) } } @@ -118,8 +153,8 @@ fun gameLoop() { if (!Textures.ready()) { - Game.webgl.clearColor(1f, 0f, 0f, 1f) - Game.webgl.clear(WebGLRenderingContext.COLOR_BUFFER_BIT) + Game.gl().clearColor(1f, 0f, 0f, 1f) + Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) } else { resize(); diff --git a/lib/kotludens/com/persesgames/shader/ShaderProgram.kt b/lib/kotludens/com/persesgames/shader/ShaderProgram.kt index 1657c83..37f50c7 100644 --- a/lib/kotludens/com/persesgames/shader/ShaderProgram.kt +++ b/lib/kotludens/com/persesgames/shader/ShaderProgram.kt @@ -92,6 +92,15 @@ currentIndex += verts.length } + fun queueVertices(verts: Array) { + if((currentIndex + verts.size) >= verticesLength) { + flush(); + } + + vertices.set(verts, currentIndex) + currentIndex += verts.size + } + fun begin() { webgl.useProgram(shaderProgram); webgl.bindBuffer(WebGLRenderingContext.ARRAY_BUFFER, attribBuffer); diff --git a/lib/kotludens/com/persesgames/sprite/SpriteBatch.kt b/lib/kotludens/com/persesgames/sprite/SpriteBatch.kt index f8af424..09a80e7 100644 --- a/lib/kotludens/com/persesgames/sprite/SpriteBatch.kt +++ b/lib/kotludens/com/persesgames/sprite/SpriteBatch.kt @@ -3,6 +3,7 @@ import com.persesgames.game.Game import com.persesgames.shader.ShaderProgram import com.persesgames.shader.VertextAttributeInfo +import com.persesgames.texture.Textures import org.khronos.webgl.Float32Array import org.khronos.webgl.WebGLRenderingContext @@ -18,16 +19,14 @@ private val vertexShaderSource = """ attribute vec2 a_position; - attribute vec3 a_color; + attribute vec2 a_texCoord; uniform mat4 u_projectionView; - varying vec3 v_color; varying vec2 v_textCoord; void main(void) { - v_color = a_color; - v_textCoord = a_position.xy; + v_textCoord = a_texCoord; gl_Position = u_projectionView * vec4(a_position, -1, 1.0); } @@ -38,11 +37,10 @@ uniform sampler2D u_sampler; - varying vec3 v_color; varying vec2 v_textCoord; void main(void) { - gl_FragColor = texture2D(u_sampler, v_textCoord) * vec4(v_color, 1.0); + gl_FragColor = texture2D(u_sampler, v_textCoord); } """ @@ -50,13 +48,13 @@ val program: ShaderProgram; val vainfo = arrayOf( VertextAttributeInfo("a_position", 2), - VertextAttributeInfo("a_color", 3) + VertextAttributeInfo("a_texCoord", 2) ) // TODO: replace with Float32Array when it supports [] or set - private val spriteArray = Array(6, { 0f }) + private val spriteArray = Array(6 * 4, { 0f }) init { - program = ShaderProgram(Game.webgl, WebGLRenderingContext.TRIANGLES, vertexShaderSource, fragmentShaderSource, vainfo) + program = ShaderProgram(Game.gl(), WebGLRenderingContext.TRIANGLES, vertexShaderSource, fragmentShaderSource, vainfo) } fun begin() { @@ -66,6 +64,8 @@ fun draw(sprite: Sprite, x: Float, y: Float) { spriteArray[0] = 1f + Textures.get(sprite.textureName).bind() + program.queueVertices(Float32Array(spriteArray)) } diff --git a/lib/kotludens/com/persesgames/texture/Textures.kt b/lib/kotludens/com/persesgames/texture/Textures.kt index baa37e9..4bcaaf8 100644 --- a/lib/kotludens/com/persesgames/texture/Textures.kt +++ b/lib/kotludens/com/persesgames/texture/Textures.kt @@ -15,10 +15,15 @@ class Texture(val glTexture: WebGLTexture) { + fun bind() { + Game.gl().activeTexture(WebGLRenderingContext.TEXTURE0) + Game.gl().bindTexture(WebGLRenderingContext.TEXTURE_2D, glTexture); + } + } object Textures { - var textures = HashMap(); + var textures = HashMap(); var startedLoading = 0 var loaded = 0 @@ -27,7 +32,7 @@ } fun load(name: String, filename: String) { - var gl = Game.webgl + var gl = Game.gl() startedLoading++ @@ -36,7 +41,7 @@ var image = document.createElement("img") as HTMLImageElement image.onload = { textureLoaded(webGlTexture, image) - textures.put(name, webGlTexture) + textures.put(name, Texture(webGlTexture)) loaded++ println("loaded texture $loaded/$startedLoading ${ready()}") } @@ -47,7 +52,7 @@ } fun textureLoaded(texture: WebGLTexture, image: HTMLImageElement) { - var gl = Game.webgl + var gl = Game.gl() gl.bindTexture(WebGLRenderingContext.TEXTURE_2D, texture); gl.pixelStorei(WebGLRenderingContext.UNPACK_FLIP_Y_WEBGL, 1); // second argument must be an int diff --git a/src/com/persesgames/Test.kt b/src/com/persesgames/Test.kt index c11d710..1c4f983 100644 --- a/src/com/persesgames/Test.kt +++ b/src/com/persesgames/Test.kt @@ -6,10 +6,7 @@ import com.persesgames.texture.Textures import org.khronos.webgl.Float32Array import org.khronos.webgl.WebGLRenderingContext -import org.w3c.dom.HTMLCanvasElement -import kotlin.browser.document import kotlin.browser.window -import kotlin.dom.on /** * User: rnentjes @@ -129,8 +126,7 @@ program.begin() - webgl.activeTexture(WebGLRenderingContext.TEXTURE0) - webgl.bindTexture(WebGLRenderingContext.TEXTURE_2D, Textures.get("SHIP")); + Textures.get("SHIP").bind() program.setUniform1i("u_sampler", 0) program.setUniformMatrix4fv("u_projectionView", mMatrix.getFloat32Array()) diff --git a/src/com/persesgames/shooter/Shooter.kt b/src/com/persesgames/shooter/Shooter.kt index ba34e44..989963e 100644 --- a/src/com/persesgames/shooter/Shooter.kt +++ b/src/com/persesgames/shooter/Shooter.kt @@ -27,8 +27,8 @@ } override fun render() { - Game.webgl.clearColor(0f, 1f, 1f, 1f) - Game.webgl.clear(WebGLRenderingContext.COLOR_BUFFER_BIT) + Game.gl().clearColor(0f, 1f, 1f, 1f) + Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT) sprites.begin() sprites.draw(sprite, x, y);