package com.persesgames.shader import org.khronos.webgl.* /** * User: rnentjes * Date: 17-4-16 * Time: 15:15 */ class ShaderProgram<T>( val webgl: WebGLRenderingContext, val drawType: Int, vertexShaderSource: String, fragmentShaderSource: String, val vainfo: Array<VertextAttributeInfo>, val setter: (program: ShaderProgram<T>, data: T) -> Unit) { var shaderProgram: WebGLProgram var vertex: WebGLShader var fragment: WebGLShader var verticesBlockSize = 0 var drawLength = 0 init { vertex = compileShader(vertexShaderSource, WebGLRenderingContext.VERTEX_SHADER) fragment = compileShader(fragmentShaderSource, WebGLRenderingContext.FRAGMENT_SHADER) shaderProgram = webgl.createProgram() ?: throw IllegalStateException("Unable to request shader program from webgl context!") webgl.attachShader(shaderProgram, vertex) webgl.attachShader(shaderProgram, fragment) webgl.linkProgram(shaderProgram) if (webgl.getProgramParameter(shaderProgram, WebGLRenderingContext.LINK_STATUS) == false) { println(webgl.getProgramInfoLog(shaderProgram)) throw IllegalStateException("Unable to compile shader program!") } webgl.useProgram(shaderProgram) this.verticesBlockSize = 0; // set attribute locations... for (info in vainfo.iterator()) { info.location = webgl.getAttribLocation(shaderProgram, info.locationName) info.offset = verticesBlockSize; verticesBlockSize += info.numElements; println("attrib: ${info.locationName}, info.location: ${info.location}, info.offset: ${info.offset}"); } when(drawType) { WebGLRenderingContext.TRIANGLES -> { drawLength = verticesBlockSize * 3 } else -> { drawLength = verticesBlockSize } } println("verticesBlockSize $verticesBlockSize"); println("ShaderProgram constructor done"); } private fun compileShader(source: String, type: Int): WebGLShader { val result: WebGLShader result = webgl.createShader(type) ?: throw IllegalStateException("Unable to request shader from webgl context!") webgl.shaderSource(result, source) webgl.compileShader(result) if (webgl.getShaderParameter(result, WebGLRenderingContext.COMPILE_STATUS) == false) { throw IllegalStateException("Unable to compile shader!\n${source}\n\n${webgl.getShaderInfoLog(result)}") } return result } fun begin(attribBuffer: WebGLBuffer, userdata: T) { webgl.useProgram(shaderProgram); webgl.bindBuffer(WebGLRenderingContext.ARRAY_BUFFER, attribBuffer); // set attribute locations... for (info in vainfo.iterator()) { webgl.enableVertexAttribArray(info.location) webgl.vertexAttribPointer(info.location, info.numElements, WebGLRenderingContext.FLOAT, false, verticesBlockSize * 4, info.offset * 4) } setter(this, userdata) } fun end() { for (info in vainfo.iterator()) { webgl.disableVertexAttribArray(info.location); } webgl.useProgram(null) } fun getAttribLocation(location: String) = webgl.getAttribLocation(shaderProgram, location); fun getUniformLocation(location: String) = webgl.getUniformLocation(shaderProgram, location); fun setUniform1f(location: String, value: Float) { webgl.uniform1f(getUniformLocation(location), value); } fun setUniform4f(location: String, v1: Float, v2: Float, v3: Float, v4: Float) { webgl.uniform4f(getUniformLocation(location), v1, v2, v3, v4); } fun setUniform1i(location: String, value: Int) { webgl.uniform1i(getUniformLocation(location), value); } fun setUniformMatrix4fv(location: String, value: Float32Array) { webgl.uniformMatrix4fv(getUniformLocation(location), false, value); } }