generated from rnentjes/kotlin-server-web-undertow
174 lines
4.6 KiB
Kotlin
174 lines
4.6 KiB
Kotlin
package mtmc.view
|
|
|
|
import kotlinx.html.canvas
|
|
import kotlinx.html.div
|
|
import mtmc.display
|
|
import mtmc.emulator.BufferedImageData
|
|
import mtmc.emulator.BufferedImageDataWebGl
|
|
import mtmc.emulator.MonTanaMiniComputer
|
|
import nl.astraeus.komp.HtmlBuilder
|
|
import nl.astraeus.komp.Komponent
|
|
import nl.astraeus.komp.currentElement
|
|
import org.khronos.webgl.Float32Array
|
|
import org.khronos.webgl.WebGLBuffer
|
|
import org.khronos.webgl.WebGLProgram
|
|
import org.khronos.webgl.WebGLRenderingContext
|
|
import org.khronos.webgl.WebGLShader
|
|
import org.khronos.webgl.WebGLTexture
|
|
import org.w3c.dom.HTMLCanvasElement
|
|
|
|
// language=GLSL
|
|
val vertexShader = """
|
|
attribute vec2 a_pos;
|
|
attribute vec2 a_uv;
|
|
varying vec2 v_uv;
|
|
void main() {
|
|
v_uv = a_uv;
|
|
gl_Position = vec4(a_pos, 0.0, 1.0);
|
|
}
|
|
"""
|
|
|
|
// language=GLSL
|
|
val fragmentShader = """
|
|
precision mediump float;
|
|
varying vec2 v_uv;
|
|
uniform sampler2D u_tex;
|
|
|
|
void main() {
|
|
gl_FragColor = texture2D(u_tex, v_uv);
|
|
}
|
|
""".trimIndent()
|
|
|
|
typealias GL = WebGLRenderingContext
|
|
|
|
class DiplayControlView(
|
|
val computer: MonTanaMiniComputer
|
|
) : Komponent() {
|
|
|
|
override fun HtmlBuilder.render() {
|
|
div("display") {
|
|
include(display)
|
|
}
|
|
}
|
|
}
|
|
|
|
class DisplayView(
|
|
val computer: MonTanaMiniComputer
|
|
) : Komponent() {
|
|
var ctx: WebGLRenderingContext? = null
|
|
var program: WebGLProgram? = null
|
|
var texture: WebGLTexture? = null
|
|
var buffer: WebGLBuffer? = null
|
|
|
|
override fun HtmlBuilder.render() {
|
|
canvas("display-canvas") {
|
|
width = "160px"
|
|
height = "144px"
|
|
|
|
val cv = currentElement() as? HTMLCanvasElement
|
|
|
|
ctx = cv?.getContext("webgl")?.unsafeCast<WebGLRenderingContext>()
|
|
|
|
if (program == null) {
|
|
createProgram()
|
|
createBuffer()
|
|
createTexture()
|
|
}
|
|
}
|
|
}
|
|
|
|
private fun createTexture() {
|
|
ctx?.let { gl: WebGLRenderingContext ->
|
|
texture = gl.createTexture()
|
|
gl.bindTexture(GL.TEXTURE_2D, texture)
|
|
|
|
// Set texture parameters for pixel-perfect rendering
|
|
gl.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_WRAP_S, GL.CLAMP_TO_EDGE)
|
|
gl.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_WRAP_T, GL.CLAMP_TO_EDGE)
|
|
gl.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_MIN_FILTER, GL.NEAREST)
|
|
gl.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_MAG_FILTER, GL.NEAREST)
|
|
}
|
|
}
|
|
|
|
private fun createBuffer() {
|
|
ctx?.let { gl ->
|
|
// Create quad vertices
|
|
val vertices = Float32Array(
|
|
arrayOf(
|
|
-1f, -1f, 0f, 1f, // position, texCoord
|
|
1f, -1f, 1f, 1f,
|
|
-1f, 1f, 0f, 0f,
|
|
1f, 1f, 1f, 0f
|
|
)
|
|
)
|
|
|
|
buffer = gl.createBuffer();
|
|
gl.bindBuffer(GL.ARRAY_BUFFER, buffer);
|
|
gl.bufferData(GL.ARRAY_BUFFER, vertices, GL.STATIC_DRAW);
|
|
}
|
|
}
|
|
|
|
|
|
private fun createProgram() {
|
|
val vs = createShader(WebGLRenderingContext.VERTEX_SHADER, vertexShader)
|
|
val fs = createShader(WebGLRenderingContext.FRAGMENT_SHADER, fragmentShader)
|
|
val prog = ctx?.createProgram()
|
|
if (vs != null && fs != null && prog != null) {
|
|
ctx?.attachShader(prog, vs)
|
|
ctx?.attachShader(prog, fs)
|
|
ctx?.linkProgram(prog)
|
|
}
|
|
program = prog
|
|
}
|
|
|
|
private fun createShader(type: Int, source: String): WebGLShader? {
|
|
var result: WebGLShader? = null
|
|
ctx?.let { gl ->
|
|
result = gl.createShader(type)
|
|
result?.let { shader ->
|
|
gl.shaderSource(shader, source)
|
|
gl.compileShader(shader)
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
override fun renderUpdate() {
|
|
// move data to canvas
|
|
val buffer = computer.display.buffer
|
|
if (buffer is BufferedImageData) {
|
|
//ctx?.putImageData(buffer.imageData, 0.0, 0.0)
|
|
} else if (buffer is BufferedImageDataWebGl) {
|
|
ctx?.let { gl ->
|
|
gl.clear(GL.COLOR_BUFFER_BIT)
|
|
|
|
gl.useProgram(program)
|
|
|
|
val positionLocation = gl.getAttribLocation(program, "a_pos")
|
|
val texCoordLocation = gl.getAttribLocation(program, "a_uv")
|
|
|
|
gl.bindBuffer(GL.ARRAY_BUFFER, this.buffer)
|
|
gl.enableVertexAttribArray(positionLocation)
|
|
gl.vertexAttribPointer(positionLocation, 2, GL.FLOAT, false, 16, 0)
|
|
gl.enableVertexAttribArray(texCoordLocation)
|
|
gl.vertexAttribPointer(texCoordLocation, 2, GL.FLOAT, false, 16, 8)
|
|
gl.bindTexture(GL.TEXTURE_2D, texture);
|
|
gl.texImage2D(
|
|
GL.TEXTURE_2D,
|
|
0, // level
|
|
GL.RGBA, // internal format
|
|
buffer.width,
|
|
buffer.height,
|
|
0, // border
|
|
GL.RGBA, // format
|
|
GL.UNSIGNED_BYTE, // type
|
|
buffer.data // data
|
|
)
|
|
|
|
// Draw quad
|
|
gl.drawArrays(GL.TRIANGLE_STRIP, 0, 4);
|
|
}
|
|
}
|
|
}
|
|
}
|