diff options
author | Ilion Beyst <ilion.beyst@gmail.com> | 2021-12-29 21:24:57 +0100 |
---|---|---|
committer | Ilion Beyst <ilion.beyst@gmail.com> | 2021-12-29 21:25:29 +0100 |
commit | 0c6d978442b244ca3f29c1ffdd44b5007ae7ad93 (patch) | |
tree | baae5fa459a49ecd362e548e0649e2f58c669a70 /web/pw-frontend/src/lib/visualizer/webgl | |
parent | 3eeaab6cec70e7a06a99a1ac2662974f71064bee (diff) | |
download | planetwars.dev-0c6d978442b244ca3f29c1ffdd44b5007ae7ad93.tar.xz planetwars.dev-0c6d978442b244ca3f29c1ffdd44b5007ae7ad93.zip |
separate out visualizer library
Diffstat (limited to 'web/pw-frontend/src/lib/visualizer/webgl')
-rw-r--r-- | web/pw-frontend/src/lib/visualizer/webgl/buffer.ts | 55 | ||||
-rw-r--r-- | web/pw-frontend/src/lib/visualizer/webgl/index.ts | 122 | ||||
-rw-r--r-- | web/pw-frontend/src/lib/visualizer/webgl/renderer.ts | 157 | ||||
-rw-r--r-- | web/pw-frontend/src/lib/visualizer/webgl/shader.ts | 327 | ||||
-rw-r--r-- | web/pw-frontend/src/lib/visualizer/webgl/text.ts | 192 | ||||
-rw-r--r-- | web/pw-frontend/src/lib/visualizer/webgl/texture.ts | 106 | ||||
-rw-r--r-- | web/pw-frontend/src/lib/visualizer/webgl/util.ts | 229 | ||||
-rw-r--r-- | web/pw-frontend/src/lib/visualizer/webgl/vertexBufferLayout.ts | 115 |
8 files changed, 0 insertions, 1303 deletions
diff --git a/web/pw-frontend/src/lib/visualizer/webgl/buffer.ts b/web/pw-frontend/src/lib/visualizer/webgl/buffer.ts deleted file mode 100644 index 2739fbe..0000000 --- a/web/pw-frontend/src/lib/visualizer/webgl/buffer.ts +++ /dev/null @@ -1,55 +0,0 @@ - -export class Buffer { - buffer: WebGLBuffer; - data: any; - count: number; - type: number; - - constructor(gl: WebGLRenderingContext, data: number[], type: number) { - this.buffer = gl.createBuffer(); - this.type = type; - - if (data) - this.updateData(gl, data); - } - - _toArray(data: number[]): any { - return new Float32Array(data); - } - - updateData(gl: WebGLRenderingContext, data: number[]) { - this.data = data; - this.count = data.length; - gl.bindBuffer(this.type, this.buffer); - gl.bufferData(this.type, this._toArray(data), gl.STATIC_DRAW); - } - - bind(gl: WebGLRenderingContext) { - gl.bindBuffer(this.type, this.buffer); - } - - getCount(): number { - return this.count; - } -} - -export class VertexBuffer extends Buffer { - constructor(gl: WebGLRenderingContext, data: any) { - super(gl, data, gl.ARRAY_BUFFER); - } - - _toArray(data: number[]): any { - return new Float32Array(data); - } -} - - -export class IndexBuffer extends Buffer { - constructor(gl: WebGLRenderingContext, data: any) { - super(gl, data, gl.ELEMENT_ARRAY_BUFFER); - } - - _toArray(data: number[]): any { - return new Uint16Array(data); - } -} diff --git a/web/pw-frontend/src/lib/visualizer/webgl/index.ts b/web/pw-frontend/src/lib/visualizer/webgl/index.ts deleted file mode 100644 index fdb7886..0000000 --- a/web/pw-frontend/src/lib/visualizer/webgl/index.ts +++ /dev/null @@ -1,122 +0,0 @@ -import { Uniform4f, Uniform1f, Uniform2f, ShaderFactory, UniformMatrix3fv, Uniform3f } from './shader'; -import { resizeCanvasToDisplaySize, FPSCounter, onload2promise, Resizer, url_to_mesh } from "./util"; -import { VertexBuffer, IndexBuffer } from './buffer'; -import { VertexArray, VertexBufferLayout } from './vertexBufferLayout'; -import { Renderer } from './renderer'; -import { Texture } from './texture'; - -const URL = window.location.origin+window.location.pathname; -const LOCATION = URL.substring(0, URL.lastIndexOf("/") + 1); - -async function create_texture_from_svg(gl: WebGLRenderingContext, name: string, path: string, width: number, height: number): Promise<Texture> { - - const [mesh, factory] = await Promise.all([ - url_to_mesh(path), - ShaderFactory.create_factory(LOCATION + "static/shaders/frag/static_color.glsl", LOCATION + "static/shaders/vert/svg.glsl") - ]); - - const program = factory.create_shader(gl); - const renderer = new Renderer(); - - var positionBuffer = new VertexBuffer(gl, mesh.positions); - var layout = new VertexBufferLayout(); - layout.push(gl.FLOAT, 3, 4, "a_position"); - - const vao = new VertexArray(); - vao.addBuffer(positionBuffer, layout); - - program.bind(gl); - vao.bind(gl, program); - - var indexBuffer = new IndexBuffer(gl, mesh.cells); - indexBuffer.bind(gl); - - renderer.addToDraw(indexBuffer, vao, program, {}); - - return Texture.fromRenderer(gl, name, width, height, renderer); -} - - -async function main() { - - // Get A WebGL context - var canvas = <HTMLCanvasElement>document.getElementById("c"); - const resolution = [canvas.width, canvas.height]; - - const resizer = new Resizer(canvas, [-10, -10, 20, 20], true); - - var gl = canvas.getContext("webgl"); - if (!gl) { - return; - } - - const mesh = await url_to_mesh("static/res/images/earth.svg"); - console.log(Math.max(...mesh.positions), Math.min(...mesh.positions)); - const renderer = new Renderer(); - - const factory = await ShaderFactory.create_factory(LOCATION + "static/shaders/frag/static_color.glsl", LOCATION + "static/shaders/vert/simple.glsl"); - const program = factory.create_shader(gl); - - var positionBuffer = new VertexBuffer(gl, mesh.positions); - var layout = new VertexBufferLayout(); - layout.push(gl.FLOAT, 3, 4, "a_position"); - // layout.push(gl.FLOAT, 2, 4, "a_tex"); - - const vao = new VertexArray(); - vao.addBuffer(positionBuffer, layout); - - resizeCanvasToDisplaySize(<HTMLCanvasElement>gl.canvas); - - // Tell WebGL how to convert from clip space to pixels - gl.viewport(0, 0, gl.canvas.width, gl.canvas.height); - - // Clear the canvas - gl.clearColor(0, 0, 0, 0); - gl.clear(gl.COLOR_BUFFER_BIT); - - gl.enable(gl.BLEND); - gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA); - - program.bind(gl); - vao.bind(gl, program); - - var indexBuffer = new IndexBuffer(gl, mesh.cells); - indexBuffer.bind(gl); - - renderer.addToDraw(indexBuffer, vao, program, {}); - - const counter = new FPSCounter(); - - const step = function (time: number) { - - // console.log(resizer.get_viewbox()); - - program.uniform(gl, "u_time", new Uniform1f(time * 0.001)); - program.uniform(gl, "u_mouse", new Uniform2f(resizer.get_mouse_pos())); - program.uniform(gl, "u_viewbox", new Uniform4f(resizer.get_viewbox())); - program.uniform(gl, "u_resolution", new Uniform2f(resolution)); - program.uniform(gl, "u_trans", new UniformMatrix3fv([1, 0, 0, 0, 1, 0, 0, 0, 1])); - program.uniform(gl, "u_color", new Uniform3f(1.0, 0.5, 0.0)); - - renderer.render(gl); - - counter.frame(time); - requestAnimationFrame(step); - } - - requestAnimationFrame(step); -} - - -main(); - -document.getElementById("loader").classList.remove("loading"); - -// const loader = document.getElementById("loader"); -// setInterval(() => { -// if (loader.classList.contains("loading")) { -// loader.classList.remove("loading") -// } else { -// loader.classList.add("loading"); -// } -// }, 2000); diff --git a/web/pw-frontend/src/lib/visualizer/webgl/renderer.ts b/web/pw-frontend/src/lib/visualizer/webgl/renderer.ts deleted file mode 100644 index c3b219f..0000000 --- a/web/pw-frontend/src/lib/visualizer/webgl/renderer.ts +++ /dev/null @@ -1,157 +0,0 @@ -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); - } - } - } -} diff --git a/web/pw-frontend/src/lib/visualizer/webgl/shader.ts b/web/pw-frontend/src/lib/visualizer/webgl/shader.ts deleted file mode 100644 index 942c4c2..0000000 --- a/web/pw-frontend/src/lib/visualizer/webgl/shader.ts +++ /dev/null @@ -1,327 +0,0 @@ -import type { Dictionary } from './util'; - -function error(msg: string) { - console.error(msg); -} - -const defaultShaderType = [ - "VERTEX_SHADER", - "FRAGMENT_SHADER" -]; - -/// Create Shader from Source string -function loadShader( - gl: WebGLRenderingContext, - shaderSource: string, - shaderType: number, - opt_errorCallback: any, -): WebGLShader { - var errFn = opt_errorCallback || error; - // Create the shader object - var shader = gl.createShader(shaderType); - - // Load the shader source - gl.shaderSource(shader, shaderSource); - - // Compile the shader - gl.compileShader(shader); - - // Check the compile status - var compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS); - if (!compiled) { - // Something went wrong during compilation; get the error - var lastError = gl.getShaderInfoLog(shader); - errFn("*** Error compiling shader '" + shader + "':" + lastError); - gl.deleteShader(shader); - return null; - } - - return shader; -} - -/// Actually Create Program with Shader's -function createProgram( - gl: WebGLRenderingContext, - shaders: WebGLShader[], - opt_attribs: string[], - opt_locations: number[], - opt_errorCallback: any, -): WebGLProgram { - var errFn = opt_errorCallback || error; - var program = gl.createProgram(); - shaders.forEach(function (shader) { - gl.attachShader(program, shader); - }); - if (opt_attribs) { - opt_attribs.forEach(function (attrib, ndx) { - gl.bindAttribLocation( - program, - opt_locations ? opt_locations[ndx] : ndx, - attrib); - }); - } - gl.linkProgram(program); - - // Check the link status - var linked = gl.getProgramParameter(program, gl.LINK_STATUS); - if (!linked) { - // something went wrong with the link - var lastError = gl.getProgramInfoLog(program); - errFn("Error in program linking:" + lastError); - - gl.deleteProgram(program); - return null; - } - return program; -} - -export class ShaderFactory { - frag_source: string; - vert_source: string; - - static async create_factory(frag_url: string, vert_url: string): Promise<ShaderFactory> { - const sources = await Promise.all([ - fetch(frag_url).then((r) => r.text()), - fetch(vert_url).then((r) => r.text()), - ]); - - return new ShaderFactory(sources[0], sources[1]); - } - - constructor(frag_source: string, vert_source: string ) { - this.frag_source = frag_source; - this.vert_source = vert_source; - } - - create_shader( - gl: WebGLRenderingContext, - context?: Dictionary<string>, - opt_attribs?: string[], - opt_locations?: number[], - opt_errorCallback?: any, - ): Shader { - let vert = this.vert_source.slice(); - let frag = this.frag_source.slice(); - for (let key in context) { - vert = vert.replace(new RegExp("\\$" + key, 'g'), context[key]); - frag = frag.replace(new RegExp("\\$" + key, 'g'), context[key]); - } - - const shaders = [ - loadShader(gl, vert, gl.VERTEX_SHADER, opt_errorCallback), - loadShader(gl, frag, gl.FRAGMENT_SHADER, opt_errorCallback), - ]; - - return new Shader(createProgram(gl, shaders, opt_attribs, opt_locations, opt_errorCallback)); - } -} - -export class Shader { - shader: WebGLProgram; - uniformCache: Dictionary<WebGLUniformLocation>; - attribCache: Dictionary<number>; - - static async createProgramFromUrls( - gl: WebGLRenderingContext, - vert_url: string, - frag_url: string, - context?: Dictionary<string>, - opt_attribs?: string[], - opt_locations?: number[], - opt_errorCallback?: any, - ): Promise<Shader> { - const sources = (await Promise.all([ - fetch(vert_url).then((r) => r.text()), - fetch(frag_url).then((r) => r.text()), - ])).map(x => { - for (let key in context) { - x = x.replace(new RegExp("\\$" + key, 'g'), context[key]); - } - return x; - }); - - const shaders = [ - loadShader(gl, sources[0], 35633, opt_errorCallback), - loadShader(gl, sources[1], 35632, opt_errorCallback), - ]; - return new Shader(createProgram(gl, shaders, opt_attribs, opt_locations, opt_errorCallback)); - } - - constructor(shader: WebGLProgram) { - this.shader = shader; - this.uniformCache = {}; - this.attribCache = {}; - } - - bind(gl: WebGLRenderingContext) { - gl.useProgram(this.shader); - } - - // Different locations have different types :/ - getUniformLocation(gl: WebGLRenderingContext, name: string): WebGLUniformLocation { - if (this.uniformCache[name] === undefined) { - this.uniformCache[name] = gl.getUniformLocation(this.shader, name); - } - - return this.uniformCache[name]; - } - - getAttribLocation(gl: WebGLRenderingContext, name: string): number { - if (this.attribCache[name] === undefined) { - this.attribCache[name] = gl.getAttribLocation(this.shader, name); - } - - return this.attribCache[name]; - } - - uniform<T extends Uniform>( - gl: WebGLRenderingContext, - name: string, - uniform: T, - ) { - this.bind(gl); - const location = this.getUniformLocation(gl, name); - if (location < 0) { - console.error("No location found with name " + name); - } - - uniform.setUniform(gl, location); - } - - clear(gl: WebGLRenderingContext) { - gl.deleteProgram(this.shader); - } -} - -export interface Uniform { - setUniform(gl: WebGLRenderingContext, location: WebGLUniformLocation): void; -} - -export class Uniform2fv implements Uniform { - data: number[] | Float32Array; - constructor(data: number[] | Float32Array) { - this.data = data; - } - - setUniform(gl: WebGLRenderingContext, location: WebGLUniformLocation) { - gl.uniform2fv(location, this.data); - } -} - -export class Uniform3fv implements Uniform { - data: number[] | Float32Array; - constructor(data: number[] | Float32Array) { - this.data = data; - } - - setUniform(gl: WebGLRenderingContext, location: WebGLUniformLocation) { - gl.uniform3fv(location, this.data); - } -} - -export class Uniform3f implements Uniform { - x: number; - y: number; - z: number; - - constructor(x: number, y: number, z: number) { - this.x = x; - this.y = y; - this.z = z; - } - - setUniform(gl: WebGLRenderingContext, location: WebGLUniformLocation) { - gl.uniform3f(location, this.x ,this.y, this.z); - } -} - -export class Uniform1iv implements Uniform { - data: number[] | Int32List; - constructor(data: number[] | Int32List) { - this.data = data; - } - - setUniform(gl: WebGLRenderingContext, location: WebGLUniformLocation) { - gl.uniform1iv(location, this.data); - } -} - -export class Uniform1i implements Uniform { - texture: number; - - constructor(texture: number) { - this.texture = texture; - } - - setUniform(gl: WebGLRenderingContext, location: WebGLUniformLocation) { - gl.uniform1i(location, this.texture); - } -} - -export class Uniform1f implements Uniform { - texture: number; - - constructor(texture: number) { - this.texture = texture; - } - - setUniform(gl: WebGLRenderingContext, location: WebGLUniformLocation) { - gl.uniform1f(location, this.texture); - } -} - -export class Uniform2f implements Uniform { - x: number; - y: number; - - constructor(xy: number[]) { - this.x = xy[0]; - this.y = xy[1]; - } - - setUniform(gl: WebGLRenderingContext, location: WebGLUniformLocation) { - gl.uniform2f(location, this.x, this.y); - } -} - -export class Uniform4f implements Uniform { - v0: number; - v1: number; - v2: number; - v3: number; - - constructor(xyzw: number[]) { - this.v0 = xyzw[0]; - this.v1 = xyzw[1]; - this.v2 = xyzw[2]; - this.v3 = xyzw[3]; - } - - setUniform(gl: WebGLRenderingContext, location: WebGLUniformLocation) { - gl.uniform4f(location, this.v0, this.v1, this.v2, this.v3); - } -} - -export class UniformMatrix3fv implements Uniform { - data: number[] | Float32Array; - constructor(data: number[] | Float32Array) { - this.data = data; - } - - setUniform(gl: WebGLRenderingContext, location: WebGLUniformLocation) { - gl.uniformMatrix3fv(location, false, this.data); - } -} - -export class UniformBool implements Uniform { - data: boolean; - constructor(data: boolean) { - this.data = data; - } - - setUniform(gl: WebGLRenderingContext, location: WebGLUniformLocation) { - gl.uniform1i(location, this.data ? 1 : 0); - } -} - -export default Shader;
\ No newline at end of file diff --git a/web/pw-frontend/src/lib/visualizer/webgl/text.ts b/web/pw-frontend/src/lib/visualizer/webgl/text.ts deleted file mode 100644 index 3f1cec6..0000000 --- a/web/pw-frontend/src/lib/visualizer/webgl/text.ts +++ /dev/null @@ -1,192 +0,0 @@ -import type { Dictionary } from "./util"; -import type { Shader, UniformMatrix3fv } from "./shader"; -import { Texture } from "./texture"; -import { DefaultRenderable } from "./renderer"; -import { IndexBuffer, VertexBuffer } from "./buffer"; -import { VertexBufferLayout, VertexArray } from "./vertexBufferLayout"; - - -export enum Align { - Begin, - End, - Middle, -} - -export class GlypInfo { - x: number; - y: number; - width: number; -} - -export class FontInfo { - letterHeight: number; - spaceWidth: number; - spacing: number; - textureWidth: number; - textureHeight: number; - glyphInfos: Dictionary<GlypInfo>; -} - -export class LabelFactory { - texture: Texture; - font: FontInfo; - shader: Shader; - - constructor(gl: WebGLRenderingContext, loc: string, font: FontInfo, shader: Shader) { - this.texture = Texture.fromImage(gl, loc, 'font'); - this.font = font; - this.shader = shader; - } - - build(gl: WebGLRenderingContext, transform?: UniformMatrix3fv): Label { - return new Label(gl, this.shader, this.texture, this.font, transform); - } -} - -export class Label { - inner: DefaultRenderable; - - font: FontInfo; - - constructor(gl: WebGLRenderingContext, shader: Shader, tex: Texture, font: FontInfo, transform?: UniformMatrix3fv) { - this.font = font; - - const uniforms = transform ? { "u_trans": transform, "u_trans_next": transform, } : {}; - const ib = new IndexBuffer(gl, []); - const vb_pos = new VertexBuffer(gl, []); - const vb_tex = new VertexBuffer(gl, []); - - const layout_pos = new VertexBufferLayout(); - layout_pos.push(gl.FLOAT, 2, 4, "a_position"); - - const layout_tex = new VertexBufferLayout(); - layout_tex.push(gl.FLOAT, 2, 4, "a_texCoord"); - - const vao = new VertexArray(); - vao.addBuffer(vb_pos, layout_pos); - vao.addBuffer(vb_tex, layout_tex); - - this.inner = new DefaultRenderable(ib, vao, shader, [tex], uniforms); - } - - getRenderable(): DefaultRenderable { - return this.inner; - } - - setText(gl: WebGLRenderingContext, text: string, h_align = Align.Begin, v_align = Align.Begin) { - const idxs = []; - const verts_pos = []; - const verts_tex = []; - - const letterHeight = this.font.letterHeight / this.font.textureHeight; - let xPos = 0; - - switch (h_align) { - case Align.Begin: - break; - case Align.End: - xPos = -1 * [...text].map(n => this.font.glyphInfos[n] ? this.font.glyphInfos[n].width : this.font.spaceWidth).reduce((a, b) => a + b, 0) / this.font.letterHeight; - break; - case Align.Middle: - xPos = -1 * [...text].map(n => this.font.glyphInfos[n] ? this.font.glyphInfos[n].width : this.font.spaceWidth).reduce((a, b) => a + b, 0) / this.font.letterHeight / 2; - break; - } - let yStart = 0; - switch (v_align) { - case Align.Begin: - break; - case Align.End: - yStart = 1; - break; - case Align.Middle: - yStart = 0.5; - break; - } - - let j = 0; - for (let i = 0; i < text.length; i++) { - const info = this.font.glyphInfos[text[i]]; - if (info) { - const dx = info.width / this.font.letterHeight; - const letterWidth = info.width / this.font.textureWidth; - const x0 = info.x / this.font.textureWidth; - const y0 = info.y / this.font.textureHeight; - verts_pos.push(xPos, yStart); - verts_pos.push(xPos + dx, yStart); - verts_pos.push(xPos, yStart-1); - verts_pos.push(xPos + dx, yStart-1); - - verts_tex.push(x0, y0); - verts_tex.push(x0 + letterWidth, y0); - verts_tex.push(x0, y0 + letterHeight); - verts_tex.push(x0 + letterWidth, y0 + letterHeight); - - xPos += dx; - - idxs.push(j+0, j+1, j+2, j+1, j+2, j+3); - j += 4; - } else { - // Just move xPos - xPos += this.font.spaceWidth / this.font.letterHeight; - } - } - - this.inner.updateIndexBuffer(gl, idxs); - this.inner.updateVAOBuffer(gl, 0, verts_pos); - this.inner.updateVAOBuffer(gl, 1, verts_tex); - } -} - -export function defaultLabelFactory(gl: WebGLRenderingContext, shader: Shader): LabelFactory { - const fontInfo = { - letterHeight: 8, - spaceWidth: 8, - spacing: -1, - textureWidth: 64, - textureHeight: 40, - glyphInfos: { - 'a': { x: 0, y: 0, width: 8, }, - 'b': { x: 8, y: 0, width: 8, }, - 'c': { x: 16, y: 0, width: 8, }, - 'd': { x: 24, y: 0, width: 8, }, - 'e': { x: 32, y: 0, width: 8, }, - 'f': { x: 40, y: 0, width: 8, }, - 'g': { x: 48, y: 0, width: 8, }, - 'h': { x: 56, y: 0, width: 8, }, - 'i': { x: 0, y: 8, width: 8, }, - 'j': { x: 8, y: 8, width: 8, }, - 'k': { x: 16, y: 8, width: 8, }, - 'l': { x: 24, y: 8, width: 8, }, - 'm': { x: 32, y: 8, width: 8, }, - 'n': { x: 40, y: 8, width: 8, }, - 'o': { x: 48, y: 8, width: 8, }, - 'p': { x: 56, y: 8, width: 8, }, - 'q': { x: 0, y: 16, width: 8, }, - 'r': { x: 8, y: 16, width: 8, }, - 's': { x: 16, y: 16, width: 8, }, - 't': { x: 24, y: 16, width: 8, }, - 'u': { x: 32, y: 16, width: 8, }, - 'v': { x: 40, y: 16, width: 8, }, - 'w': { x: 48, y: 16, width: 8, }, - 'x': { x: 56, y: 16, width: 8, }, - 'y': { x: 0, y: 24, width: 8, }, - 'z': { x: 8, y: 24, width: 8, }, - '0': { x: 16, y: 24, width: 8, }, - '1': { x: 24, y: 24, width: 8, }, - '2': { x: 32, y: 24, width: 8, }, - '3': { x: 40, y: 24, width: 8, }, - '4': { x: 48, y: 24, width: 8, }, - '5': { x: 56, y: 24, width: 8, }, - '6': { x: 0, y: 32, width: 8, }, - '7': { x: 8, y: 32, width: 8, }, - '8': { x: 16, y: 32, width: 8, }, - '9': { x: 24, y: 32, width: 8, }, - '-': { x: 32, y: 32, width: 8, }, - '*': { x: 40, y: 32, width: 8, }, - '!': { x: 48, y: 32, width: 8, }, - '?': { x: 56, y: 32, width: 8, }, - }, - }; - - return new LabelFactory(gl, '/static/res/assets/font.png', fontInfo, shader); -} diff --git a/web/pw-frontend/src/lib/visualizer/webgl/texture.ts b/web/pw-frontend/src/lib/visualizer/webgl/texture.ts deleted file mode 100644 index 9d6adcf..0000000 --- a/web/pw-frontend/src/lib/visualizer/webgl/texture.ts +++ /dev/null @@ -1,106 +0,0 @@ -import type { Renderer } from "./renderer"; - -export class Texture { - texture: WebGLTexture; - width: number; - height: number; - loaded: boolean; - name: string; - - static fromImage( - gl: WebGLRenderingContext, - path: string, - name: string, - ): Texture { - const out = new Texture(gl, name); - - const image = new Image(); - image.onload = out.setImage.bind(out, gl, image); - image.onerror = error; - image.src = path; - - return out; - } - - static fromRenderer( - gl: WebGLRenderingContext, - name: string, - width: number, - height: number, - renderer: Renderer - ): Texture { - const out = new Texture(gl, name); - out.width = width; - out.height = height; - - gl.texImage2D( - gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, - gl.RGBA, gl.UNSIGNED_BYTE, null); - - const fb = gl.createFramebuffer(); - gl.bindFramebuffer(gl.FRAMEBUFFER, fb); - - const attachmentPoint = gl.COLOR_ATTACHMENT0; - gl.framebufferTexture2D(gl.FRAMEBUFFER, attachmentPoint, gl.TEXTURE_2D, out.texture, 0); - - renderer.render(gl, fb, width, height); - - out.loaded = true; - - return out; - } - - constructor( - gl: WebGLRenderingContext, - name: string, - ) { - this.loaded = false; - this.name = name; - - this.texture = gl.createTexture(); - this.bind(gl); - - 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); - - gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, - gl.UNSIGNED_BYTE, new Uint8Array([255, 0, 0, 255])); - } - - setImage(gl: WebGLRenderingContext, image: HTMLImageElement) { - this.bind(gl); - this.width = image.width; - this.height = image.height; - - gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image); - - this.unbind(gl); - - this.loaded = true; - } - - bind(gl: WebGLRenderingContext, location=0) { - gl.activeTexture(gl.TEXTURE0 + location); - gl.bindTexture(gl.TEXTURE_2D, this.texture); - } - - unbind(gl: WebGLRenderingContext) { - gl.bindTexture(gl.TEXTURE_2D, null); - } - - - getWidth(): number { - return this.width; - } - - getHeight(): number { - return this.height; - } -} - -function error(e: any) { - console.error("IMAGE LOAD ERROR"); - console.error(e); -} diff --git a/web/pw-frontend/src/lib/visualizer/webgl/util.ts b/web/pw-frontend/src/lib/visualizer/webgl/util.ts deleted file mode 100644 index 3ed2b4d..0000000 --- a/web/pw-frontend/src/lib/visualizer/webgl/util.ts +++ /dev/null @@ -1,229 +0,0 @@ -import { parse as parsePath } from 'extract-svg-path'; -import svgMesh3d from 'svg-mesh-3d'; - -export interface Dictionary<T> { - [Key: string]: T; -} - - -interface OnLoadable { - onload: any; -} - -export function onload2promise<T extends OnLoadable>(obj: T): Promise<T> { - return new Promise(resolve => { - obj.onload = () => resolve(obj); - }); -} - -export function resizeCanvasToDisplaySize( - canvas: HTMLCanvasElement, - multiplier?: number, -): boolean { - multiplier = multiplier || 1; - var width = canvas.clientWidth * multiplier | 0; - var height = canvas.clientHeight * multiplier | 0; - if (canvas.width !== width || canvas.height !== height) { - canvas.width = width; - canvas.height = height; - return true; - } - return false; -} - -export class FPSCounter { - last: number; - count: number; - _delta: number; - _prev: number; - - _frame_start: number; - _total_frametime: number; - - constructor() { - this.last = 0; - this.count = 0; - this._delta = 0; - this._prev = 0; - } - - frame(now: number) { - this._frame_start = performance.now(); - this.count += 1; - this._delta = now - this._prev; - this._prev = now; - - if (now - this.last > 1000) { - this.last = now; - console.log(`${this.count} fps, ${(this._total_frametime / this.count).toFixed(2)}ms avg per frame`); - this.count = 0; - this._total_frametime = 0; - } - } - - frame_end() { - this._total_frametime += (performance.now() - this._frame_start); - } - - delta(now: number): number { - return this._delta; - } -} - -export class Resizer { - hoovering = false; - dragging = false; - - mouse_pos = [0, 0]; - last_drag = [0, 0]; - - viewbox: number[]; - orig_viewbox: number[]; - - el_box: number[]; - - scaleX = 1; - scaleY = 1; - - constructor(el: HTMLCanvasElement, viewbox: number[], keep_aspect_ratio=false) { - viewbox = [-viewbox[0] - viewbox[2], - viewbox[1] - viewbox[3], viewbox[2], viewbox[3]]; - this.viewbox = [...viewbox]; - this.el_box = [el.width, el.height]; - - if (keep_aspect_ratio) { - const or_width = this.viewbox[2]; - const or_height = this.viewbox[3]; - - const width_percentage = this.viewbox[2] / el.width; - const height_percentage = this.viewbox[3] / el.height; - - if (width_percentage < height_percentage) { - // width should be larger - this.viewbox[2] = height_percentage * el.width; - } else { - // height should be larger - this.viewbox[3] = width_percentage * el.height; - } - - this.viewbox[0] -= (this.viewbox[2] - or_width) / 2; - this.viewbox[1] -= (this.viewbox[3] - or_height) / 2; - - this.scaleX = this.viewbox[2] / this.viewbox[3]; - } - - this.orig_viewbox = [...this.viewbox]; - - el.addEventListener("mouseenter", this.mouseenter.bind(this), { capture: false, passive: true}); - el.addEventListener("mouseleave", this.mouseleave.bind(this), { capture: false, passive: true}); - el.addEventListener("mousemove", this.mousemove.bind(this), { capture: false, passive: true}); - el.addEventListener("mousedown", this.mousedown.bind(this), { capture: false, passive: true}); - el.addEventListener("mouseup", this.mouseup.bind(this), { capture: false, passive: true}); - - window.addEventListener('wheel', this.wheel.bind(this), { capture: false, passive: true}); - } - - _clip_viewbox() { - this.viewbox[0] = Math.max(this.viewbox[0], this.orig_viewbox[0]); - this.viewbox[1] = Math.max(this.viewbox[1], this.orig_viewbox[1]); - - this.viewbox[0] = Math.min(this.viewbox[0] + this.viewbox[2], this.orig_viewbox[0] + this.orig_viewbox[2]) - this.viewbox[2]; - this.viewbox[1] = Math.min(this.viewbox[1] + this.viewbox[3], this.orig_viewbox[1] + this.orig_viewbox[3]) - this.viewbox[3]; - } - - mouseenter() { - this.hoovering = true; - } - - mouseleave() { - this.hoovering = false; - } - - mousemove(e: MouseEvent) { - this.mouse_pos = [e.offsetX, this.el_box[1] - e.offsetY]; - - if (this.dragging) { - const scaleX = this.viewbox[2] / this.el_box[0]; - const scaleY = this.viewbox[3] / this.el_box[1]; - - this.viewbox[0] += (this.last_drag[0] - this.mouse_pos[0]) * scaleX; - this.viewbox[1] += (this.last_drag[1] - this.mouse_pos[1]) * scaleY; - - this.last_drag = [...this.mouse_pos]; - - this._clip_viewbox(); - } - } - - mousedown() { - this.dragging = true; - this.last_drag = [...this.mouse_pos]; - } - - mouseup() { - this.dragging = false; - } - - wheel(e: WheelEvent) { - if (this.hoovering) { - const delta = e.deltaY > 0 ? 0.1 * this.viewbox[2] : -0.1 * this.viewbox[2]; - const dx = delta * this.scaleX; - const dy = delta * this.scaleY; - - const mouse_dx = this.mouse_pos[0] / this.el_box[0]; - const mouse_dy = this.mouse_pos[1] / this.el_box[1]; - - this._zoom([dx, dy], [mouse_dx, mouse_dy]); - } - } - - _zoom(deltas: number[], center: number[]) { - this.viewbox[2] += deltas[0]; - this.viewbox[0] -= deltas[0] * center[0]; - this.viewbox[2] = Math.min(this.viewbox[2], this.orig_viewbox[2]); - - this.viewbox[3] += deltas[1]; - this.viewbox[1] -= deltas[1] * center[1]; - this.viewbox[3] = Math.min(this.viewbox[3], this.orig_viewbox[3]); - - this._clip_viewbox(); - } - - get_viewbox(): number[] { - return this.viewbox; - } - - get_mouse_pos(): number[] { - return this.mouse_pos; - } -} - -export class Mesh { - cells: number[]; - positions: number[]; - - constructor(mesh: any) { - this.cells = mesh.cells.flat(); - this.positions = mesh.positions.flat(); - } -} - -export async function url_to_mesh(url: string): Promise<Mesh> { - - return new Promise(function(resolve) { - fetch(url) - .then(resp => resp.text()) - .then(data => { - // var div = document.createElement('div'); - // div.innerHTML = data; - // var svg = div.querySelector('svg'); - - var svgPath = parsePath(data); - var mesh = svgMesh3d(svgPath, { - delaunay: false, - scale: 10, - }); - - resolve(new Mesh(mesh)); - }) - }); -} diff --git a/web/pw-frontend/src/lib/visualizer/webgl/vertexBufferLayout.ts b/web/pw-frontend/src/lib/visualizer/webgl/vertexBufferLayout.ts deleted file mode 100644 index f44ed47..0000000 --- a/web/pw-frontend/src/lib/visualizer/webgl/vertexBufferLayout.ts +++ /dev/null @@ -1,115 +0,0 @@ -import type { VertexBuffer } from './buffer'; -import type { Shader } from './shader'; - -export class VertexBufferElement { - type: number; - amount: number; - type_size: number; - normalized: boolean; - index: string; - - constructor( - type: number, - amount: number, - type_size: number, - index: string, - normalized: boolean, - ) { - this.type = type; - this.amount = amount; - this.type_size = type_size; - this.normalized = normalized; - this.index = index; - } -} - -export class VertexBufferLayout { - elements: VertexBufferElement[]; - stride: number; - offset: number; - - constructor(offset = 0) { - this.elements = []; - this.stride = 0; - this.offset = offset; - } - - // Maybe wrong normalized type - push( - type: number, - amount: number, - type_size: number, - index: string, - normalized = false, - ) { - this.elements.push(new VertexBufferElement(type, amount, type_size, index, normalized)); - this.stride += amount * type_size; - } - - getElements(): VertexBufferElement[] { - return this.elements; - } - - getStride(): number { - return this.stride; - } -} - -// glEnableVertexAttribArray is to specify what location of the current program the follow data is needed -// glVertexAttribPointer tells gl that that data is at which location in the supplied data -export class VertexArray { - // There is no renderer ID, always at bind buffers and use glVertexAttribPointer - buffers: VertexBuffer[]; - layouts: VertexBufferLayout[]; - - constructor() { - this.buffers = []; - this.layouts = []; - } - - addBuffer(vb: VertexBuffer, layout: VertexBufferLayout) { - this.buffers.push(vb); - this.layouts.push(layout); - } - - updateBuffer(gl: WebGLRenderingContext, index: number, data: number[]) { - this.buffers[index].updateData(gl, data); - } - - /// Bind buffers providing program data - bind(gl: WebGLRenderingContext, shader: Shader) { - shader.bind(gl); - for(let i = 0; i < this.buffers.length; i ++) { - const buffer = this.buffers[i]; - const layout = this.layouts[i]; - - buffer.bind(gl); - const elements = layout.getElements(); - let offset = layout.offset; - - for (let j = 0; j < elements.length; j ++) { - const element = elements[j]; - const location = shader.getAttribLocation(gl, element.index); - - if (location >= 0) { - gl.enableVertexAttribArray(location); - gl.vertexAttribPointer( - location, element.amount, element.type, - element.normalized, layout.stride, offset - ); - } - - offset += element.amount * element.type_size; - } - } - } - - /// Undo bind operation - unbind(gl: WebGLRenderingContext) { - this.layouts.forEach((layout) => { - layout.getElements().forEach((_, index) => { - gl.disableVertexAttribArray(index); - }); - }) - } -} |