aboutsummaryrefslogtreecommitdiff
path: root/web/pw-visualizer/src/webgl
diff options
context:
space:
mode:
Diffstat (limited to 'web/pw-visualizer/src/webgl')
-rw-r--r--web/pw-visualizer/src/webgl/msdf_text.ts181
-rw-r--r--web/pw-visualizer/src/webgl/texture.ts10
-rw-r--r--web/pw-visualizer/src/webgl/util.ts1
3 files changed, 190 insertions, 2 deletions
diff --git a/web/pw-visualizer/src/webgl/msdf_text.ts b/web/pw-visualizer/src/webgl/msdf_text.ts
new file mode 100644
index 0000000..5bbac20
--- /dev/null
+++ b/web/pw-visualizer/src/webgl/msdf_text.ts
@@ -0,0 +1,181 @@
+import { Shader, Uniform1f, Uniform4f, UniformMatrix3fv } from "./shader";
+import { Texture } from "./texture";
+import { DefaultRenderable } from "./renderer";
+import { IndexBuffer, VertexBuffer } from "./buffer";
+import { VertexBufferLayout, VertexArray } from "./vertexBufferLayout";
+import { robotoMsdfJson } from "../assets";
+import { GlypInfo } from "./text";
+
+
+export enum Align {
+ Begin,
+ End,
+ Middle,
+}
+
+export type FontAtlas = {
+ atlas: AtlasMeta,
+ metrics: Metrics,
+ glyphs: Glyph[],
+}
+
+export type AtlasMeta = {
+ type: string,
+ distanceRange: number,
+ size: number,
+ width: number,
+ height: number,
+ yOrigin: string,
+}
+
+export type Metrics = {
+ emSize: number,
+ lineHeight: number,
+ ascender: number,
+ descender: number,
+ underlineY: number,
+ underlineThickness: number,
+}
+
+
+export type Glyph = {
+ unicode: number,
+ advance: number,
+ planeBounds?: Bounds,
+ atlasBounds?: Bounds,
+}
+
+export type Bounds = {
+ left: number,
+ bottom: number,
+ right: number,
+ top: number,
+}
+
+
+export class MsdfLabelFactory {
+ texture: Texture;
+ font: FontAtlas;
+ shader: Shader;
+
+ constructor(gl: WebGLRenderingContext, fontTexture: Texture, font: FontAtlas, shader: Shader) {
+ this.texture = fontTexture;
+ 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: FontAtlas;
+ charAtlas: {[unicodeNumber: number]: Glyph};
+
+ constructor(gl: WebGLRenderingContext, shader: Shader, tex: Texture, font: FontAtlas, transform: UniformMatrix3fv) {
+ this.font = font;
+ this.charAtlas = {}
+ this.font.glyphs.forEach((glyph) => {
+ this.charAtlas[glyph.unicode] = glyph;
+ });
+
+ const uniforms = {
+ "u_trans": transform,
+ "u_trans_next": transform,
+ "u_fgColor": new Uniform4f([1.0, 1.0, 1.0, 1.0]),
+ "u_bgColor": new Uniform4f([0.0, 0.0, 0.0, 1.0]),
+ "u_distanceRange": new Uniform1f(font.atlas.distanceRange),
+ "u_glyphSize": new Uniform1f(font.atlas.size),
+ };
+ 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 = [];
+
+ let xPos = 0;
+ let yPos = 0;
+ switch (v_align) {
+ case Align.Begin:
+ yPos = -1;
+ break;
+ case Align.End:
+ yPos = 0;
+ break;
+ case Align.Middle:
+ yPos = -0.5;
+ break;
+ }
+
+ // track position in the index buffer
+ let bufPos = 0;
+ for (let charIndex = 0; charIndex < text.length; charIndex++) {
+ let char = this.charAtlas[text.charCodeAt(charIndex)]
+ if (char.atlasBounds && char.planeBounds) {
+ verts_pos.push(xPos + char.planeBounds.left, yPos-char.planeBounds.top);
+ verts_pos.push(xPos + char.planeBounds.right, yPos-char.planeBounds.top);
+ verts_pos.push(xPos + char.planeBounds.left, yPos-char.planeBounds.bottom);
+ verts_pos.push(xPos + char.planeBounds.right, yPos-char.planeBounds.bottom);
+
+ const atlasWidth = this.font.atlas.width;
+ const atlasHeight = this.font.atlas.height;
+
+ verts_tex.push(char.atlasBounds.left / atlasWidth, char.atlasBounds.top / atlasHeight);
+ verts_tex.push(char.atlasBounds.right / atlasWidth, char.atlasBounds.top / atlasHeight);
+ verts_tex.push(char.atlasBounds.left / atlasWidth, char.atlasBounds.bottom / atlasHeight);
+ verts_tex.push(char.atlasBounds.right / atlasWidth, char.atlasBounds.bottom / atlasHeight);
+
+ idxs.push(bufPos+0, bufPos+1, bufPos+2);
+ idxs.push(bufPos+1, bufPos+2, bufPos+3);
+ bufPos += 4;
+ }
+ xPos += char.advance;
+ }
+
+ let shift = 0;
+ switch (h_align) {
+ case Align.End:
+ shift = xPos;
+ break;
+ case Align.Middle:
+ shift = xPos / 2;
+ break;
+ }
+
+ for (let i = 0; i < verts_pos.length; i += 2) {
+ verts_pos[i] -= shift;
+ }
+
+
+ this.inner.updateIndexBuffer(gl, idxs);
+ this.inner.updateVAOBuffer(gl, 0, verts_pos);
+ this.inner.updateVAOBuffer(gl, 1, verts_tex);
+ }
+}
+
+export function defaultMsdfLabelFactory(gl: WebGLRenderingContext, fontTexture: Texture, shader: Shader): MsdfLabelFactory {
+ return new MsdfLabelFactory(gl, fontTexture, robotoMsdfJson, shader);
+}
diff --git a/web/pw-visualizer/src/webgl/texture.ts b/web/pw-visualizer/src/webgl/texture.ts
index 9624489..9ebd5c0 100644
--- a/web/pw-visualizer/src/webgl/texture.ts
+++ b/web/pw-visualizer/src/webgl/texture.ts
@@ -67,8 +67,14 @@ export class Texture {
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);
+ if (name == "font") {
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+ } else {
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
+
+ }
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA,
gl.UNSIGNED_BYTE, new Uint8Array([255, 0, 0, 255]));
diff --git a/web/pw-visualizer/src/webgl/util.ts b/web/pw-visualizer/src/webgl/util.ts
index 7b55d19..922b016 100644
--- a/web/pw-visualizer/src/webgl/util.ts
+++ b/web/pw-visualizer/src/webgl/util.ts
@@ -74,6 +74,7 @@ export class Resizer {
mouse_pos = [0, 0];
last_drag = [0, 0];
+ // x, y, w, h
viewbox: number[];
orig_viewbox: number[];