aboutsummaryrefslogtreecommitdiff
path: root/web/pw-frontend/src/lib/visualizer/webgl/renderer.ts
diff options
context:
space:
mode:
Diffstat (limited to 'web/pw-frontend/src/lib/visualizer/webgl/renderer.ts')
-rw-r--r--web/pw-frontend/src/lib/visualizer/webgl/renderer.ts157
1 files changed, 157 insertions, 0 deletions
diff --git a/web/pw-frontend/src/lib/visualizer/webgl/renderer.ts b/web/pw-frontend/src/lib/visualizer/webgl/renderer.ts
new file mode 100644
index 0000000..c3b219f
--- /dev/null
+++ b/web/pw-frontend/src/lib/visualizer/webgl/renderer.ts
@@ -0,0 +1,157 @@
+import type { IndexBuffer } from './buffer';
+import type { VertexArray } from './vertexBufferLayout';
+import type { Texture } from './texture';
+import type { Dictionary } from './util';
+import type { Shader, Uniform } from './shader';
+import { Uniform1i } from './shader';
+
+function sortedIndex(array, value) {
+ var low = 0,
+ high = array.length;
+
+ while (low < high) {
+ var mid = (low + high) >>> 1;
+ if (array[mid] < value) low = mid + 1;
+ else high = mid;
+ }
+ return low;
+}
+
+export interface Renderable {
+ getUniforms() : Dictionary<Uniform>;
+ render(gl: WebGLRenderingContext): void;
+ updateVAOBuffer(gl: WebGLRenderingContext, index: number, data: number[]);
+ updateIndexBuffer(gl: WebGLRenderingContext, data: number[]);
+}
+
+export class DefaultRenderable implements Renderable {
+ ibo: IndexBuffer;
+ va: VertexArray;
+ shader: Shader;
+ textures: Texture[];
+ uniforms: Dictionary<Uniform>;
+
+ constructor(
+ ibo: IndexBuffer,
+ va: VertexArray,
+ shader: Shader,
+ textures: Texture[],
+ uniforms: Dictionary<Uniform>,
+ ) {
+ this.ibo = ibo;
+ this.va = va;
+ this.shader = shader;
+ this.textures = textures;
+ this.uniforms = uniforms;
+ }
+
+ getUniforms(): Dictionary<Uniform> {
+ return this.uniforms;
+ }
+
+ updateVAOBuffer(gl: WebGLRenderingContext, index: number, data: number[]) {
+ this.va.updateBuffer(gl, index, data);
+ }
+
+ updateIndexBuffer(gl: WebGLRenderingContext, data: number[]) {
+ this.ibo.updateData(gl, data);
+ }
+
+ render(gl: WebGLRenderingContext): void {
+
+ const indexBuffer = this.ibo;
+ const vertexArray = this.va;
+ const uniforms = this.uniforms;
+
+ const shader = this.shader;
+ const textures = this.textures;
+ let texLocation = 0;
+
+ for (let texture of textures) {
+
+ shader.uniform(gl, texture.name, new Uniform1i(texLocation));
+ texture.bind(gl, texLocation);
+
+ texLocation ++;
+ // if (texLocation > maxTextures) {
+ // console.error("Using too many textures, this is not supported yet\nUndefined behaviour!");
+ // }
+ }
+
+ if (vertexArray && shader && uniforms) {
+ for(let key in uniforms) {
+ shader.uniform(gl, key, uniforms[key]);
+ }
+
+ vertexArray.bind(gl, shader);
+
+ if (indexBuffer) {
+ indexBuffer.bind(gl);
+ gl.drawElements(gl.TRIANGLES, indexBuffer.getCount(), gl.UNSIGNED_SHORT, 0);
+ } else {
+ console.error("IndexBuffer is required to render, for now");
+ }
+ }
+
+ }
+}
+
+export class Renderer {
+ renderables: { [id: number] : [Renderable, boolean][]; };
+ renderable_layers: number[];
+
+ constructor() {
+ this.renderables = {};
+ this.renderable_layers = [];
+ }
+
+ updateUniform(i: number, f: (uniforms: Dictionary<Uniform>) => void, layer=0, ) {
+ f(this.renderables[layer][i][0].getUniforms());
+ }
+
+ disableRenderable(i: number, layer=0) {
+ this.renderables[layer][i][1] = false;
+ }
+
+ enableRenderable(i: number, layer=0) {
+ this.renderables[layer][i][1] = true;
+ }
+
+ addRenderable(item: Renderable, layer=0): number {
+ if(!this.renderables[layer]) {
+ const idx = sortedIndex(this.renderable_layers, layer);
+ this.renderable_layers.splice(idx, 0, layer);
+ this.renderables[layer] = [];
+ }
+
+ this.renderables[layer].push([item, true]);
+ return this.renderables[layer].length - 1;
+ }
+
+ addToDraw(indexBuffer: IndexBuffer, vertexArray: VertexArray, shader: Shader, uniforms?: Dictionary<Uniform>, texture?: Texture[], layer=0): number {
+ return this.addRenderable(
+ new DefaultRenderable(
+ indexBuffer,
+ vertexArray,
+ shader,
+ texture || [],
+ uniforms || {},
+ ), layer
+ );
+ }
+
+ render(gl: WebGLRenderingContext, frameBuffer?: WebGLFramebuffer, width?: number, height?: number) {
+ gl.bindFramebuffer(gl.FRAMEBUFFER, frameBuffer);
+ gl.viewport(0, 0, width || gl.canvas.width, height || gl.canvas.height);
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+
+ const maxTextures = gl.getParameter(gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS);
+
+ for (let layer of this.renderable_layers) {
+ for (let [r, e] of this.renderables[layer]) {
+ if (!e) continue;
+ r.render(gl);
+ }
+ }
+ }
+}