import { gl } from './Renderer.js' export class Shader { #vertexShader; #fragmentShader; #program; #attributes; #uniforms; constructor(vertexCode, fragmentCode) { this.#vertexShader = gl.createShader(gl.VERTEX_SHADER) this.#fragmentShader = gl.createShader(gl.FRAGMENT_SHADER) gl.shaderSource(this.#vertexShader, vertexCode) gl.shaderSource(this.#fragmentShader, fragmentCode) gl.compileShader(this.#vertexShader) if (!gl.getShaderParameter(this.#vertexShader, gl.COMPILE_STATUS)) { console.error('Failed to compile vertex shader!', gl.getShaderInfoLog(this.#vertexShader)) return } gl.compileShader(this.#fragmentShader) if (!gl.getShaderParameter(this.#fragmentShader, gl.COMPILE_STATUS)) { console.error('Failed to compile fragment shader!', gl.getShaderInfoLog(this.#fragmentShader)) return } this.#program = gl.createProgram() gl.attachShader(this.#program, this.#vertexShader) gl.attachShader(this.#program, this.#fragmentShader) gl.linkProgram(this.#program) if (!gl.getProgramParameter(this.#program, gl.LINK_STATUS)) { console.error("Failed to link shader program!", gl.getProgramInfoLog(this.#program)); return } gl.validateProgram(this.#program); if (!gl.getProgramParameter(this.#program, gl.VALIDATE_STATUS)) { console.error("Failed to validate shader program!", gl.getProgramInfoLog(this.#program)); return } this.#attributes = [] this.#uniforms = {} vertexCode.split('\n').forEach((line) => { const tokens = line.trim().split(" ") if (tokens.length != 3) return if (tokens[0] === "attribute") { this.#attributes.push(tokens[2].replace(/\s+/g, '').split(';')[0]) } if (tokens[0] == "uniform") { const loc = gl.getUniformLocation(this.#program, tokens[2].replace(/\s+/g, '').split(';')[0]) this.#uniforms[tokens[2].replace(/\s+/g, '').split(';')[0]] = loc } }) } start() { gl.useProgram(this.#program) for (let i = 0; i < this.#attributes.length; i++) { gl.bindAttribLocation(this.#program, i, this.#attributes[i]) } } stop() { gl.useProgram(null) } loadFloat(name, float) { gl.uniform1f(this.#uniforms[name], float) } loadInt(name, int) { gl.uniform1i(this.#uniforms[name], int) } loadVec2(name, v) { gl.uniform2f(this.#uniforms[name], v.x, v.y) } loadVec3(name, v) { gl.uniform3f(this.#uniforms[name], v.x, v.y, v.z) } loadMat4(name, m) { if(this.#uniforms[name] == undefined) return; gl.uniformMatrix4fv(this.#uniforms[name], gl.FALSE, m.data) } loadBool(name, bool) { gl.uniform1f(this.#uniforms[name], bool ? 1 : 0) } }