site/www/js/smc/progbuilder.js

133 lines
3.2 KiB
JavaScript

import { SmcErr } from './errors.js';
export { SmcProgramBuilder };
class SmcProgramBuilder {
#gl;
#program;
#isBuilt = false;
#hasVertexShader = false;
#hasFragmentShader = false;
#defaultVertexShader = `
attribute vec4 aVertex;
void main() {
gl_Position = aVertex;
}
`;
// TODO: reset the sample fragment shader back to the rainbow
#sampleFragmentShader = `
precision mediump float;
// uniform float uTime;
uniform vec2 uResolution;
void main() {
vec2 uv = gl_FragCoord.xy / uResolution.xy;
// vec3 col = 0.5 + 0.5 * cos(uTime + uv.xyx + vec3(0, 2, 4));
// gl_FragColor = vec4(col, 1.0);
// gl_FragColor = vec4(216., 43., 72., 255.) / 255.;
// float maxfc = max(gl_FragCoord.x, gl_FragCoord.y);
// gl_FragColor = vec4(gl_FragCoord.xy, maxfc, maxfc) / maxfc;
float maxuv = max(uv.x, uv.y);
gl_FragColor = vec4(216. * maxuv, 43., 72., 255.) / 255.;
// vec3 col = 0.5 + 0.5*cos(uv.xyx+vec3(0,2,4));
// gl_FragColor = vec4(col, 1.);
}
`;
constructor(gl, raiseError) {
this.#gl = gl;
this.#program = this.#gl.createProgram();
this.raiseError = raiseError;
}
addVertexShader(source) {
this.#gl.attachShader(
this.#program,
this.#newShader(
this.#gl.VERTEX_SHADER,
source
)
)
this.#hasVertexShader = true;
return this;
}
addFragmentShader(source) {
this.#gl.attachShader(
this.#program,
this.#newShader(
this.#gl.FRAGMENT_SHADER,
source
)
)
console.log(source)
this.#hasFragmentShader = true;
return this;
}
// fetchVertexShader(uri) {
// (async () => this.#fetchShader(uri, (source) => this.addVertexShader(source)))();
// return this;
// }
// async fetchFragmentShader(uri) {
// var delegate = (source) => this.addFragmentShader(source);
// var source = await this.#fetchShader(uri);
// return this;
// }
build() {
// avoid user accidental calls to build()
if (!this.#isBuilt) {
if (!this.#hasVertexShader)
this.addVertexShader(this.#defaultVertexShader)
if (!this.#hasFragmentShader)
this.addFragmentShader(this.#sampleFragmentShader);
this.#gl.linkProgram(this.#program);
this.#gl.useProgram(this.#program);
}
return this.#program;
}
// Creates a shader of the given type, uploads the source and compiles
#newShader(type, source) {
const shader = this.#gl.createShader(type);
this.#gl.shaderSource(shader, source);
this.#gl.compileShader(shader);
if (!this.#gl.getShaderParameter(shader, this.#gl.COMPILE_STATUS)) {
this.#gl.deleteShader(shader);
const infoLog = this.#gl.getShaderInfoLog(shader);
this.raiseError(
SmcErr.SHADER_COMPILATION,
new Error(`An error occurred while compiling the shader: ${infoLog}`)
);
}
return shader;
}
// async #fetchShader(uri, delegate) {
// const res = await fetch(uri);
// if (res.ok)
// return await res.text();
// this.raiseError(
// SmcErr.FETCH_SHADER,
// `Failed to load shader source ${url}: ${res.status} ${res.json()}`);
// return ""
// }
}