diff --git a/demo/client/package.json b/demo/client/package.json index 9ed81cbc..b7d04334 100644 --- a/demo/client/package.json +++ b/demo/client/package.json @@ -14,6 +14,7 @@ "@types/lodash": "^4.14.74", "@types/node": "^8.0.28", "@types/opentype.js": "0.0.0", + "@types/webgl-ext": "0.0.29", "base64-js": "^1.2.1", "bootstrap": "^4.0.0-beta", "gl-matrix": "^2.4.0", diff --git a/demo/client/src/aa-strategy.ts b/demo/client/src/aa-strategy.ts index 02f1995a..b50360cb 100644 --- a/demo/client/src/aa-strategy.ts +++ b/demo/client/src/aa-strategy.ts @@ -10,7 +10,7 @@ import * as glmatrix from 'gl-matrix'; -import {DemoView} from './view'; +import {DemoView, Renderer} from './view'; export type AntialiasingStrategyName = 'none' | 'ssaa' | 'xcaa'; @@ -23,15 +23,15 @@ export abstract class AntialiasingStrategy { shouldRenderDirect: boolean; // Prepares any OpenGL data. This is only called on startup and canvas resize. - init(view: DemoView): void { - this.setFramebufferSize(view); + init(renderer: Renderer): void { + this.setFramebufferSize(renderer); } // Uploads any mesh data. This is called whenever a new set of meshes is supplied. - abstract attachMeshes(view: DemoView): void; + abstract attachMeshes(renderer: Renderer): void; // This is called whenever the framebuffer has changed. - abstract setFramebufferSize(view: DemoView): void; + abstract setFramebufferSize(renderer: Renderer): void; // Returns the transformation matrix that should be applied when directly rendering. abstract get transform(): glmatrix.mat4; @@ -39,17 +39,17 @@ export abstract class AntialiasingStrategy { // Called before direct rendering. // // Typically, this redirects direct rendering to a framebuffer of some sort. - abstract prepare(view: DemoView): void; + abstract prepare(renderer: Renderer): void; // Called after direct rendering. // // This usually performs the actual antialiasing. - abstract antialias(view: DemoView): void; + abstract antialias(renderer: Renderer): void; // Called after antialiasing. // // This usually blits to the real framebuffer. - abstract resolve(view: DemoView): void; + abstract resolve(renderer: Renderer): void; } export class NoAAStrategy extends AntialiasingStrategy { @@ -60,25 +60,25 @@ export class NoAAStrategy extends AntialiasingStrategy { this.framebufferSize = glmatrix.vec2.create(); } - attachMeshes(view: DemoView) {} + attachMeshes(renderer: Renderer) {} - setFramebufferSize(view: DemoView) { - this.framebufferSize = view.destAllocatedSize; + setFramebufferSize(renderer: Renderer) { + this.framebufferSize = renderer.destAllocatedSize; } get transform(): glmatrix.mat4 { return glmatrix.mat4.create(); } - prepare(view: DemoView) { - view.gl.bindFramebuffer(view.gl.FRAMEBUFFER, view.destFramebuffer); - view.gl.viewport(0, 0, this.framebufferSize[0], this.framebufferSize[1]); - view.gl.disable(view.gl.SCISSOR_TEST); + prepare(renderer: Renderer) { + renderer.gl.bindFramebuffer(renderer.gl.FRAMEBUFFER, renderer.destFramebuffer); + renderer.gl.viewport(0, 0, this.framebufferSize[0], this.framebufferSize[1]); + renderer.gl.disable(renderer.gl.SCISSOR_TEST); } - antialias(view: DemoView) {} + antialias(renderer: Renderer) {} - resolve(view: DemoView) {} + resolve(renderer: Renderer) {} get shouldRenderDirect() { return true; diff --git a/demo/client/src/gl-utils.ts b/demo/client/src/gl-utils.ts index 42d1baa6..6ce49ef7 100644 --- a/demo/client/src/gl-utils.ts +++ b/demo/client/src/gl-utils.ts @@ -11,7 +11,7 @@ import * as glmatrix from 'gl-matrix'; import {assert, UINT32_SIZE, unwrapNull} from './utils'; -import { DemoView } from './view'; +import {DemoView} from './view'; export type WebGLVertexArrayObject = any; @@ -23,26 +23,49 @@ export interface UniformMap { [uniformName: string]: WebGLUniformLocation; } +export interface EXTDisjointTimerQuery { + readonly QUERY_COUNTER_BITS_EXT: GLenum; + readonly CURRENT_QUERY_EXT: GLenum; + readonly QUERY_RESULT_EXT: GLenum; + readonly QUERY_RESULT_AVAILABLE_EXT: GLenum; + readonly TIME_ELAPSED_EXT: GLenum; + readonly TIMESTAMP_EXT: GLenum; + readonly GPU_DISJOINT_EXT: GLenum; + createQueryEXT(): WebGLQuery; + deleteQueryEXT(query: WebGLQuery): void; + isQueryEXT(query: any): GLboolean; + beginQueryEXT(target: GLenum, query: WebGLQuery): void; + endQueryEXT(target: GLenum): void; + queryCounterEXT(query: WebGLQuery, target: GLenum): void; + getQueryEXT(target: GLenum, pname: GLenum): any; + getQueryObjectEXT(query: WebGLQuery, pname: GLenum): any; +} + +export class WebGLQuery {} + export const QUAD_ELEMENTS: Uint8Array = new Uint8Array([2, 0, 1, 1, 3, 2]); -export function createFramebufferColorTexture(view: DemoView, size: glmatrix.vec2): WebGLTexture { +export function createFramebufferColorTexture(gl: WebGLRenderingContext, + size: glmatrix.vec2, + colorAlphaFormat: GLenum): + WebGLTexture { // Firefox seems to have a bug whereby textures don't get marked as initialized when cleared // if they're anything other than the first attachment of an FBO. To work around this, supply // zero data explicitly when initializing the texture. const zeroes = new Uint8Array(size[0] * size[1] * UINT32_SIZE); - const texture = unwrapNull(view.gl.createTexture()); - view.gl.activeTexture(view.gl.TEXTURE0); - view.gl.bindTexture(view.gl.TEXTURE_2D, texture); - view.gl.texImage2D(view.gl.TEXTURE_2D, + const texture = unwrapNull(gl.createTexture()); + gl.activeTexture(gl.TEXTURE0); + gl.bindTexture(gl.TEXTURE_2D, texture); + gl.texImage2D(gl.TEXTURE_2D, 0, - view.colorAlphaFormat, + colorAlphaFormat, size[0], size[1], 0, - view.colorAlphaFormat, - view.gl.UNSIGNED_BYTE, + colorAlphaFormat, + gl.UNSIGNED_BYTE, zeroes); - setTextureParameters(view.gl, view.gl.NEAREST); + setTextureParameters(gl, gl.NEAREST); return texture; } @@ -72,7 +95,7 @@ export function setTextureParameters(gl: WebGLRenderingContext, filter: number) } export function createFramebuffer(gl: WebGLRenderingContext, - drawBuffersExt: any, + drawBuffersExt: WebGLDrawBuffers, colorAttachments: WebGLTexture[], depthAttachment: WebGLTexture | null): WebGLFramebuffer { @@ -83,11 +106,9 @@ export function createFramebuffer(gl: WebGLRenderingContext, for (let colorAttachmentIndex = 0; colorAttachmentIndex < colorAttachmentCount; colorAttachmentIndex++) { - gl.framebufferTexture2D(gl.FRAMEBUFFER, - drawBuffersExt[`COLOR_ATTACHMENT${colorAttachmentIndex}_WEBGL`], - gl.TEXTURE_2D, - colorAttachments[colorAttachmentIndex], - 0); + const glEnum = (drawBuffersExt as any)[`COLOR_ATTACHMENT${colorAttachmentIndex}_WEBGL`]; + const attachment = colorAttachments[colorAttachmentIndex]; + gl.framebufferTexture2D(gl.FRAMEBUFFER, glEnum, gl.TEXTURE_2D, attachment, 0); } if (depthAttachment != null) { diff --git a/demo/client/src/ssaa-strategy.ts b/demo/client/src/ssaa-strategy.ts index cf9a151d..77f90292 100644 --- a/demo/client/src/ssaa-strategy.ts +++ b/demo/client/src/ssaa-strategy.ts @@ -13,7 +13,7 @@ import * as glmatrix from 'gl-matrix'; import {AntialiasingStrategy, SubpixelAAType} from './aa-strategy'; import {createFramebuffer, createFramebufferDepthTexture, setTextureParameters} from './gl-utils'; import {unwrapNull} from './utils'; -import {DemoView} from './view'; +import {DemoView, Renderer} from './view'; export default class SSAAStrategy extends AntialiasingStrategy { private level: number; @@ -33,39 +33,39 @@ export default class SSAAStrategy extends AntialiasingStrategy { this.supersampledFramebufferSize = glmatrix.vec2.create(); } - attachMeshes(view: DemoView) {} + attachMeshes(renderer: Renderer) {} - setFramebufferSize(view: DemoView) { - this.destFramebufferSize = glmatrix.vec2.clone(view.destAllocatedSize); + setFramebufferSize(renderer: Renderer) { + this.destFramebufferSize = glmatrix.vec2.clone(renderer.destAllocatedSize); this.supersampledFramebufferSize = glmatrix.vec2.create(); glmatrix.vec2.mul(this.supersampledFramebufferSize, this.destFramebufferSize, this.supersampleScale); - this.supersampledColorTexture = unwrapNull(view.gl.createTexture()); - view.gl.activeTexture(view.gl.TEXTURE0); - view.gl.bindTexture(view.gl.TEXTURE_2D, this.supersampledColorTexture); - view.gl.texImage2D(view.gl.TEXTURE_2D, - 0, - view.colorAlphaFormat, - this.supersampledFramebufferSize[0], - this.supersampledFramebufferSize[1], - 0, - view.colorAlphaFormat, - view.gl.UNSIGNED_BYTE, - null); - setTextureParameters(view.gl, view.gl.LINEAR); + this.supersampledColorTexture = unwrapNull(renderer.gl.createTexture()); + renderer.gl.activeTexture(renderer.gl.TEXTURE0); + renderer.gl.bindTexture(renderer.gl.TEXTURE_2D, this.supersampledColorTexture); + renderer.gl.texImage2D(renderer.gl.TEXTURE_2D, + 0, + renderer.colorAlphaFormat, + this.supersampledFramebufferSize[0], + this.supersampledFramebufferSize[1], + 0, + renderer.colorAlphaFormat, + renderer.gl.UNSIGNED_BYTE, + null); + setTextureParameters(renderer.gl, renderer.gl.LINEAR); this.supersampledDepthTexture = - createFramebufferDepthTexture(view.gl, this.supersampledFramebufferSize); + createFramebufferDepthTexture(renderer.gl, this.supersampledFramebufferSize); - this.supersampledFramebuffer = createFramebuffer(view.gl, - view.drawBuffersExt, + this.supersampledFramebuffer = createFramebuffer(renderer.gl, + renderer.drawBuffersExt, [this.supersampledColorTexture], this.supersampledDepthTexture); - view.gl.bindFramebuffer(view.gl.FRAMEBUFFER, null); + renderer.gl.bindFramebuffer(renderer.gl.FRAMEBUFFER, null); } get transform(): glmatrix.mat4 { @@ -77,42 +77,42 @@ export default class SSAAStrategy extends AntialiasingStrategy { return transform; } - prepare(view: DemoView) { + prepare(renderer: Renderer) { const framebufferSize = this.supersampledFramebufferSize; - const usedSize = this.usedSupersampledFramebufferSize(view); - view.gl.bindFramebuffer(view.gl.FRAMEBUFFER, this.supersampledFramebuffer); - view.gl.viewport(0, 0, framebufferSize[0], framebufferSize[1]); - view.gl.scissor(0, 0, usedSize[0], usedSize[1]); - view.gl.enable(view.gl.SCISSOR_TEST); + const usedSize = this.usedSupersampledFramebufferSize(renderer); + renderer.gl.bindFramebuffer(renderer.gl.FRAMEBUFFER, this.supersampledFramebuffer); + renderer.gl.viewport(0, 0, framebufferSize[0], framebufferSize[1]); + renderer.gl.scissor(0, 0, usedSize[0], usedSize[1]); + renderer.gl.enable(renderer.gl.SCISSOR_TEST); } - antialias(view: DemoView) {} + antialias(renderer: Renderer) {} - resolve(view: DemoView) { - view.gl.bindFramebuffer(view.gl.FRAMEBUFFER, view.destFramebuffer); - view.gl.viewport(0, 0, view.destAllocatedSize[0], view.destAllocatedSize[1]); - view.gl.disable(view.gl.DEPTH_TEST); - view.gl.disable(view.gl.BLEND); + resolve(renderer: Renderer) { + renderer.gl.bindFramebuffer(renderer.gl.FRAMEBUFFER, renderer.destFramebuffer); + renderer.gl.viewport(0, 0, renderer.destAllocatedSize[0], renderer.destAllocatedSize[1]); + renderer.gl.disable(renderer.gl.DEPTH_TEST); + renderer.gl.disable(renderer.gl.BLEND); // Set up the blit program VAO. let resolveProgram; if (this.subpixelAA !== 'none') - resolveProgram = view.shaderPrograms.ssaaSubpixelResolve; + resolveProgram = renderer.shaderPrograms.ssaaSubpixelResolve; else - resolveProgram = view.shaderPrograms.blit; - view.gl.useProgram(resolveProgram.program); - view.initQuadVAO(resolveProgram.attributes); + resolveProgram = renderer.shaderPrograms.blit; + renderer.gl.useProgram(resolveProgram.program); + renderer.initQuadVAO(resolveProgram.attributes); // Resolve framebuffer. - view.gl.activeTexture(view.gl.TEXTURE0); - view.gl.bindTexture(view.gl.TEXTURE_2D, this.supersampledColorTexture); - view.gl.uniform1i(resolveProgram.uniforms.uSource, 0); - view.gl.uniform2i(resolveProgram.uniforms.uSourceDimensions, + renderer.gl.activeTexture(renderer.gl.TEXTURE0); + renderer.gl.bindTexture(renderer.gl.TEXTURE_2D, this.supersampledColorTexture); + renderer.gl.uniform1i(resolveProgram.uniforms.uSource, 0); + renderer.gl.uniform2i(resolveProgram.uniforms.uSourceDimensions, this.supersampledFramebufferSize[0], this.supersampledFramebufferSize[1]); - view.setTransformAndTexScaleUniformsForDest(resolveProgram.uniforms); - view.gl.bindBuffer(view.gl.ELEMENT_ARRAY_BUFFER, view.quadElementsBuffer); - view.gl.drawElements(view.gl.TRIANGLES, 6, view.gl.UNSIGNED_BYTE, 0); + renderer.setTransformAndTexScaleUniformsForDest(resolveProgram.uniforms); + renderer.gl.bindBuffer(renderer.gl.ELEMENT_ARRAY_BUFFER, renderer.quadElementsBuffer); + renderer.gl.drawElements(renderer.gl.TRIANGLES, 6, renderer.gl.UNSIGNED_BYTE, 0); } get shouldRenderDirect() { @@ -123,9 +123,9 @@ export default class SSAAStrategy extends AntialiasingStrategy { return glmatrix.vec2.clone([this.subpixelAA !== 'none' ? 3 : 2, this.level === 2 ? 1 : 2]); } - private usedSupersampledFramebufferSize(view: DemoView): glmatrix.vec2 { + private usedSupersampledFramebufferSize(renderer: Renderer): glmatrix.vec2 { const result = glmatrix.vec2.create(); - glmatrix.vec2.mul(result, view.destUsedSize, this.supersampleScale); + glmatrix.vec2.mul(result, renderer.destUsedSize, this.supersampleScale); return result; } } diff --git a/demo/client/src/text-demo.ts b/demo/client/src/text-demo.ts index ca001e1a..0777c5bc 100644 --- a/demo/client/src/text-demo.ts +++ b/demo/client/src/text-demo.ts @@ -288,8 +288,13 @@ class TextDemoView extends MonochromeDemoView { return glmatrix.vec2.create(); } - readonly bgColor: glmatrix.vec4 = glmatrix.vec4.fromValues(1.0, 1.0, 1.0, 0.0); - readonly fgColor: glmatrix.vec4 = glmatrix.vec4.fromValues(0.0, 0.0, 0.0, 1.0); + get bgColor(): glmatrix.vec4 { + return glmatrix.vec4.fromValues(1.0, 1.0, 1.0, 0.0); + } + + get fgColor(): glmatrix.vec4 { + return glmatrix.vec4.fromValues(0.0, 0.0, 0.0, 1.0); + } protected depthFunction: number = this.gl.GREATER; diff --git a/demo/client/src/view.ts b/demo/client/src/view.ts index c3d05ba4..5166aa05 100644 --- a/demo/client/src/view.ts +++ b/demo/client/src/view.ts @@ -17,7 +17,7 @@ import {AntialiasingStrategy, AntialiasingStrategyName, NoAAStrategy} from "./aa import {StemDarkeningMode, SubpixelAAType} from "./aa-strategy"; import PathfinderBufferTexture from './buffer-texture'; import {Camera} from "./camera"; -import {QUAD_ELEMENTS, UniformMap} from './gl-utils'; +import {EXTDisjointTimerQuery, QUAD_ELEMENTS, UniformMap} from './gl-utils'; import {PathfinderMeshBuffers, PathfinderMeshData} from './meshes'; import {PathfinderShaderProgram, SHADER_NAMES, ShaderMap} from './shader-loader'; import {ShaderProgramSource, UnlinkedShaderProgram} from './shader-loader'; @@ -121,15 +121,15 @@ export abstract class PathfinderView { } } -export abstract class DemoView extends PathfinderView { +export abstract class DemoView extends PathfinderView implements Renderer { gl: WebGLRenderingContext; shaderPrograms: ShaderMap; - drawBuffersExt: any; - instancedArraysExt: any; - textureHalfFloatExt: any; - vertexArrayObjectExt: any; + drawBuffersExt: WebGLDrawBuffers; + instancedArraysExt: ANGLEInstancedArrays; + textureHalfFloatExt: OESTextureHalfFloat; + vertexArrayObjectExt: OESVertexArrayObject; quadPositionsBuffer: WebGLBuffer; quadTexCoordsBuffer: WebGLBuffer; @@ -140,16 +140,24 @@ export abstract class DemoView extends PathfinderView { pathTransformBufferTextures: PathfinderBufferTexture[]; + get bgColor(): glmatrix.vec4 | null { + return null; + } + + get fgColor(): glmatrix.vec4 | null { + return null; + } + get emboldenAmount(): glmatrix.vec2 { return glmatrix.vec2.create(); } - get colorAlphaFormat(): number { + get colorAlphaFormat(): GLenum { return this.sRGBExt == null ? this.gl.RGBA : this.sRGBExt.SRGB_ALPHA_EXT; } - protected sRGBExt: any; - protected timerQueryExt: any; + protected sRGBExt: EXTsRGB; + protected timerQueryExt: EXTDisjointTimerQuery; protected antialiasingStrategy: AntialiasingStrategy | null; protected colorBufferHalfFloatExt: any; @@ -216,7 +224,7 @@ export abstract class DemoView extends PathfinderView { this.setDirty(); } - initQuadVAO(attributes: any) { + initQuadVAO(attributes: any): void { this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.quadPositionsBuffer); this.gl.vertexAttribPointer(attributes.aPosition, 2, this.gl.FLOAT, false, 0, 0); this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.quadTexCoordsBuffer); @@ -246,13 +254,13 @@ export abstract class DemoView extends PathfinderView { transform[13]); } - setTransformSTAndTexScaleUniformsForDest(uniforms: UniformMap) { + setTransformSTAndTexScaleUniformsForDest(uniforms: UniformMap): void { const usedSize = this.usedSizeFactor; this.gl.uniform4f(uniforms.uTransformST, 2.0 * usedSize[0], 2.0 * usedSize[1], -1.0, -1.0); this.gl.uniform2f(uniforms.uTexScale, usedSize[0], usedSize[1]); } - setTransformAndTexScaleUniformsForDest(uniforms: UniformMap) { + setTransformAndTexScaleUniformsForDest(uniforms: UniformMap): void { const usedSize = this.usedSizeFactor; const transform = glmatrix.mat4.create(); @@ -727,3 +735,45 @@ export abstract class MonochromeDemoView extends DemoView { abstract get bgColor(): glmatrix.vec4; abstract get fgColor(): glmatrix.vec4; } + +export interface Renderer { + /// The OpenGL context. + readonly gl: WebGLRenderingContext; + + /// The `WEBGL_draw_buffers` extension. + readonly drawBuffersExt: WebGLDrawBuffers; + readonly instancedArraysExt: ANGLEInstancedArrays; + readonly textureHalfFloatExt: OESTextureHalfFloat; + readonly vertexArrayObjectExt: OESVertexArrayObject; + + readonly shaderPrograms: ShaderMap; + + readonly quadPositionsBuffer: WebGLBuffer; + readonly quadElementsBuffer: WebGLBuffer; + + readonly destFramebuffer: WebGLFramebuffer | null; + readonly pathTransformBufferTextures: PathfinderBufferTexture[]; + + readonly meshes: PathfinderMeshBuffers[]; + readonly meshData: PathfinderMeshData[]; + + readonly colorAlphaFormat: GLenum; + + readonly destAllocatedSize: glmatrix.vec2; + readonly destUsedSize: glmatrix.vec2; + + readonly emboldenAmount: glmatrix.vec2; + + readonly bgColor: glmatrix.vec4 | null; + readonly fgColor: glmatrix.vec4 | null; + + initQuadVAO(attributes: any): void; + + pathBoundingRects(objectIndex: number): Float32Array; + + setFramebufferSizeUniform(uniforms: UniformMap): void; + setHintsUniform(uniforms: UniformMap): void; + setTransformAndTexScaleUniformsForDest(uniforms: UniformMap): void; + setTransformSTAndTexScaleUniformsForDest(uniforms: UniformMap): void; + setTransformSTUniform(uniforms: UniformMap, objectIndex: number): void; +} diff --git a/demo/client/src/xcaa-strategy.ts b/demo/client/src/xcaa-strategy.ts index f028c20f..4ab08e98 100644 --- a/demo/client/src/xcaa-strategy.ts +++ b/demo/client/src/xcaa-strategy.ts @@ -20,7 +20,7 @@ import {B_QUAD_LOWER_INDICES_OFFSET, B_QUAD_SIZE, B_QUAD_UPPER_INDICES_OFFSET} f import {PathfinderShaderProgram} from './shader-loader'; import {computeStemDarkeningAmount} from './text'; import {FLOAT32_SIZE, lerp, UINT32_SIZE, unwrapNull} from './utils'; -import {MonochromeDemoView} from './view'; +import {MonochromeDemoView, Renderer} from './view'; interface FastEdgeVAOs { upper: WebGLVertexArrayObject; @@ -59,220 +59,224 @@ export abstract class XCAAStrategy extends AntialiasingStrategy { this.destFramebufferSize = glmatrix.vec2.create(); } - init(view: MonochromeDemoView) { - super.init(view); + init(renderer: Renderer) { + super.init(renderer); } - attachMeshes(view: MonochromeDemoView) { - this.createEdgeDetectVAO(view); - this.createResolveVAO(view); + attachMeshes(renderer: Renderer) { + this.createEdgeDetectVAO(renderer); + this.createResolveVAO(renderer); } - setFramebufferSize(view: MonochromeDemoView) { - this.destFramebufferSize = glmatrix.vec2.clone(view.destAllocatedSize); + setFramebufferSize(renderer: Renderer) { + this.destFramebufferSize = glmatrix.vec2.clone(renderer.destAllocatedSize); glmatrix.vec2.mul(this.supersampledFramebufferSize, this.destFramebufferSize, this.supersampleScale); - this.initDirectFramebuffer(view); - this.initEdgeDetectFramebuffer(view); - this.initAAAlphaFramebuffer(view); - view.gl.bindFramebuffer(view.gl.FRAMEBUFFER, null); + this.initDirectFramebuffer(renderer); + this.initEdgeDetectFramebuffer(renderer); + this.initAAAlphaFramebuffer(renderer); + renderer.gl.bindFramebuffer(renderer.gl.FRAMEBUFFER, null); } - prepare(view: MonochromeDemoView) { - const usedSize = this.supersampledUsedSize(view); - view.gl.bindFramebuffer(view.gl.FRAMEBUFFER, this.directFramebuffer); - view.gl.viewport(0, - 0, - this.supersampledFramebufferSize[0], - this.supersampledFramebufferSize[1]); - view.gl.scissor(0, 0, usedSize[0], usedSize[1]); - view.gl.enable(view.gl.SCISSOR_TEST); + prepare(renderer: Renderer) { + const usedSize = this.supersampledUsedSize(renderer); + renderer.gl.bindFramebuffer(renderer.gl.FRAMEBUFFER, this.directFramebuffer); + renderer.gl.viewport(0, + 0, + this.supersampledFramebufferSize[0], + this.supersampledFramebufferSize[1]); + renderer.gl.scissor(0, 0, usedSize[0], usedSize[1]); + renderer.gl.enable(renderer.gl.SCISSOR_TEST); // Clear out the color and depth textures. - view.drawBuffersExt.drawBuffersWEBGL([ - view.drawBuffersExt.COLOR_ATTACHMENT0_WEBGL, - view.drawBuffersExt.NONE, + renderer.drawBuffersExt.drawBuffersWEBGL([ + renderer.drawBuffersExt.COLOR_ATTACHMENT0_WEBGL, + renderer.gl.NONE, ]); - view.gl.clearColor(1.0, 1.0, 1.0, 1.0); - view.gl.clearDepth(0.0); - view.gl.depthMask(true); - view.gl.clear(view.gl.COLOR_BUFFER_BIT | view.gl.DEPTH_BUFFER_BIT); + renderer.gl.clearColor(1.0, 1.0, 1.0, 1.0); + renderer.gl.clearDepth(0.0); + renderer.gl.depthMask(true); + renderer.gl.clear(renderer.gl.COLOR_BUFFER_BIT | renderer.gl.DEPTH_BUFFER_BIT); // Clear out the path ID texture. - view.drawBuffersExt.drawBuffersWEBGL([ - view.drawBuffersExt.NONE, - view.drawBuffersExt.COLOR_ATTACHMENT1_WEBGL, + renderer.drawBuffersExt.drawBuffersWEBGL([ + renderer.gl.NONE, + renderer.drawBuffersExt.COLOR_ATTACHMENT1_WEBGL, ]); - view.gl.clearColor(0.0, 0.0, 0.0, 0.0); - view.gl.clear(view.gl.COLOR_BUFFER_BIT); + renderer.gl.clearColor(0.0, 0.0, 0.0, 0.0); + renderer.gl.clear(renderer.gl.COLOR_BUFFER_BIT); // Render to both textures. - view.drawBuffersExt.drawBuffersWEBGL([ - view.drawBuffersExt.COLOR_ATTACHMENT0_WEBGL, - view.drawBuffersExt.COLOR_ATTACHMENT1_WEBGL, + renderer.drawBuffersExt.drawBuffersWEBGL([ + renderer.drawBuffersExt.COLOR_ATTACHMENT0_WEBGL, + renderer.drawBuffersExt.COLOR_ATTACHMENT1_WEBGL, ]); } - antialias(view: MonochromeDemoView) { + antialias(renderer: Renderer) { // Detect edges if necessary. - this.detectEdgesIfNecessary(view); + this.detectEdgesIfNecessary(renderer); // Set up antialiasing. - this.prepareAA(view); + this.prepareAA(renderer); // Clear. - this.clear(view); + this.clear(renderer); } - resolve(view: MonochromeDemoView) { + resolve(renderer: Renderer) { // Resolve the antialiasing. - this.resolveAA(view); + this.resolveAA(renderer); } get transform(): glmatrix.mat4 { return glmatrix.mat4.create(); } - protected initDirectFramebuffer(view: MonochromeDemoView) { - this.directColorTexture = createFramebufferColorTexture(view, this.destFramebufferSize); - this.directPathIDTexture = createFramebufferColorTexture(view, this.destFramebufferSize); + protected initDirectFramebuffer(renderer: Renderer) { + this.directColorTexture = createFramebufferColorTexture(renderer.gl, + this.destFramebufferSize, + renderer.colorAlphaFormat); + this.directPathIDTexture = createFramebufferColorTexture(renderer.gl, + this.destFramebufferSize, + renderer.colorAlphaFormat); this.directFramebuffer = - createFramebuffer(view.gl, - view.drawBuffersExt, + createFramebuffer(renderer.gl, + renderer.drawBuffersExt, [this.directColorTexture, this.directPathIDTexture], this.directDepthTexture); } - protected setResolveDepthState(view: MonochromeDemoView): void { - view.gl.disable(view.gl.DEPTH_TEST); + protected setResolveDepthState(renderer: Renderer): void { + renderer.gl.disable(renderer.gl.DEPTH_TEST); } - protected supersampledUsedSize(view: MonochromeDemoView): glmatrix.vec2 { + protected supersampledUsedSize(renderer: Renderer): glmatrix.vec2 { const usedSize = glmatrix.vec2.create(); - glmatrix.vec2.mul(usedSize, view.destUsedSize, this.supersampleScale); + glmatrix.vec2.mul(usedSize, renderer.destUsedSize, this.supersampleScale); return usedSize; } - protected prepareAA(view: MonochromeDemoView): void { + protected prepareAA(renderer: Renderer): void { // Set state for antialiasing. - const usedSize = this.supersampledUsedSize(view); - view.gl.bindFramebuffer(view.gl.FRAMEBUFFER, this.aaFramebuffer); - view.gl.viewport(0, - 0, - this.supersampledFramebufferSize[0], - this.supersampledFramebufferSize[1]); - view.gl.scissor(0, 0, usedSize[0], usedSize[1]); - view.gl.enable(view.gl.SCISSOR_TEST); + const usedSize = this.supersampledUsedSize(renderer); + renderer.gl.bindFramebuffer(renderer.gl.FRAMEBUFFER, this.aaFramebuffer); + renderer.gl.viewport(0, + 0, + this.supersampledFramebufferSize[0], + this.supersampledFramebufferSize[1]); + renderer.gl.scissor(0, 0, usedSize[0], usedSize[1]); + renderer.gl.enable(renderer.gl.SCISSOR_TEST); - this.createPathBoundsBufferTexture(view); + this.createPathBoundsBufferTexture(renderer); } - protected setAAState(view: MonochromeDemoView) { - const usedSize = this.supersampledUsedSize(view); - view.gl.bindFramebuffer(view.gl.FRAMEBUFFER, this.aaFramebuffer); - view.gl.viewport(0, - 0, - this.supersampledFramebufferSize[0], - this.supersampledFramebufferSize[1]); - view.gl.scissor(0, 0, usedSize[0], usedSize[1]); - view.gl.enable(view.gl.SCISSOR_TEST); + protected setAAState(renderer: Renderer) { + const usedSize = this.supersampledUsedSize(renderer); + renderer.gl.bindFramebuffer(renderer.gl.FRAMEBUFFER, this.aaFramebuffer); + renderer.gl.viewport(0, + 0, + this.supersampledFramebufferSize[0], + this.supersampledFramebufferSize[1]); + renderer.gl.scissor(0, 0, usedSize[0], usedSize[1]); + renderer.gl.enable(renderer.gl.SCISSOR_TEST); - this.setAADepthState(view); + this.setAADepthState(renderer); } - protected setAAUniforms(view: MonochromeDemoView, uniforms: UniformMap) { - view.setTransformSTUniform(uniforms, 0); - view.setFramebufferSizeUniform(uniforms); - view.pathTransformBufferTextures[0].bind(view.gl, uniforms, 0); - this.pathBoundsBufferTexture.bind(view.gl, uniforms, 1); - view.setHintsUniform(uniforms); + protected setAAUniforms(renderer: Renderer, uniforms: UniformMap) { + renderer.setTransformSTUniform(uniforms, 0); + renderer.setFramebufferSizeUniform(uniforms); + renderer.pathTransformBufferTextures[0].bind(renderer.gl, uniforms, 0); + this.pathBoundsBufferTexture.bind(renderer.gl, uniforms, 1); + renderer.setHintsUniform(uniforms); } - protected abstract clear(view: MonochromeDemoView): void; - protected abstract getResolveProgram(view: MonochromeDemoView): PathfinderShaderProgram; - protected abstract initEdgeDetectFramebuffer(view: MonochromeDemoView): void; - protected abstract createEdgeDetectVAO(view: MonochromeDemoView): void; - protected abstract detectEdgesIfNecessary(view: MonochromeDemoView): void; - protected abstract setAADepthState(view: MonochromeDemoView): void; - protected abstract clearForResolve(view: MonochromeDemoView): void; - protected abstract setResolveUniforms(view: MonochromeDemoView, - program: PathfinderShaderProgram): void; + protected abstract clear(renderer: Renderer): void; + protected abstract getResolveProgram(renderer: Renderer): PathfinderShaderProgram; + protected abstract initEdgeDetectFramebuffer(renderer: Renderer): void; + protected abstract createEdgeDetectVAO(renderer: Renderer): void; + protected abstract detectEdgesIfNecessary(renderer: Renderer): void; + protected abstract setAADepthState(renderer: Renderer): void; + protected abstract clearForResolve(renderer: Renderer): void; + protected abstract setResolveUniforms(renderer: Renderer, program: PathfinderShaderProgram): + void; - private initAAAlphaFramebuffer(view: MonochromeDemoView) { - this.aaAlphaTexture = unwrapNull(view.gl.createTexture()); - view.gl.activeTexture(view.gl.TEXTURE0); - view.gl.bindTexture(view.gl.TEXTURE_2D, this.aaAlphaTexture); - view.gl.texImage2D(view.gl.TEXTURE_2D, - 0, - view.gl.RGB, - this.supersampledFramebufferSize[0], - this.supersampledFramebufferSize[1], - 0, - view.gl.RGB, - view.textureHalfFloatExt.HALF_FLOAT_OES, - null); - setTextureParameters(view.gl, view.gl.NEAREST); + private initAAAlphaFramebuffer(renderer: Renderer) { + this.aaAlphaTexture = unwrapNull(renderer.gl.createTexture()); + renderer.gl.activeTexture(renderer.gl.TEXTURE0); + renderer.gl.bindTexture(renderer.gl.TEXTURE_2D, this.aaAlphaTexture); + renderer.gl.texImage2D(renderer.gl.TEXTURE_2D, + 0, + renderer.gl.RGB, + this.supersampledFramebufferSize[0], + this.supersampledFramebufferSize[1], + 0, + renderer.gl.RGB, + renderer.textureHalfFloatExt.HALF_FLOAT_OES, + null); + setTextureParameters(renderer.gl, renderer.gl.NEAREST); - this.aaDepthTexture = createFramebufferDepthTexture(view.gl, + this.aaDepthTexture = createFramebufferDepthTexture(renderer.gl, this.supersampledFramebufferSize); - this.aaFramebuffer = createFramebuffer(view.gl, - view.drawBuffersExt, + this.aaFramebuffer = createFramebuffer(renderer.gl, + renderer.drawBuffersExt, [this.aaAlphaTexture], this.aaDepthTexture); } - private createPathBoundsBufferTexture(view: MonochromeDemoView) { - const pathBounds = view.pathBoundingRects(0); - this.pathBoundsBufferTexture = new PathfinderBufferTexture(view.gl, 'uPathBounds'); - this.pathBoundsBufferTexture.upload(view.gl, pathBounds); + private createPathBoundsBufferTexture(renderer: Renderer) { + const pathBounds = renderer.pathBoundingRects(0); + this.pathBoundsBufferTexture = new PathfinderBufferTexture(renderer.gl, 'uPathBounds'); + this.pathBoundsBufferTexture.upload(renderer.gl, pathBounds); } - private createResolveVAO(view: MonochromeDemoView) { - this.resolveVAO = view.vertexArrayObjectExt.createVertexArrayOES(); - view.vertexArrayObjectExt.bindVertexArrayOES(this.resolveVAO); + private createResolveVAO(renderer: Renderer) { + this.resolveVAO = renderer.vertexArrayObjectExt.createVertexArrayOES(); + renderer.vertexArrayObjectExt.bindVertexArrayOES(this.resolveVAO); - const resolveProgram = this.getResolveProgram(view); - view.gl.useProgram(resolveProgram.program); - view.initQuadVAO(resolveProgram.attributes); + const resolveProgram = this.getResolveProgram(renderer); + renderer.gl.useProgram(resolveProgram.program); + renderer.initQuadVAO(resolveProgram.attributes); - view.vertexArrayObjectExt.bindVertexArrayOES(null); + renderer.vertexArrayObjectExt.bindVertexArrayOES(null); } - private resolveAA(view: MonochromeDemoView) { + private resolveAA(renderer: Renderer) { // Set state for ECAA resolve. - const usedSize = view.destUsedSize; - view.gl.bindFramebuffer(view.gl.FRAMEBUFFER, view.destFramebuffer); - view.gl.viewport(0, 0, this.destFramebufferSize[0], this.destFramebufferSize[1]); - view.gl.scissor(0, 0, usedSize[0], usedSize[1]); - view.gl.enable(view.gl.SCISSOR_TEST); - this.setResolveDepthState(view); - view.gl.disable(view.gl.BLEND); - if (view.destFramebuffer != null) - view.drawBuffersExt.drawBuffersWEBGL([view.drawBuffersExt.COLOR_ATTACHMENT0_WEBGL]); + const usedSize = renderer.destUsedSize; + renderer.gl.bindFramebuffer(renderer.gl.FRAMEBUFFER, renderer.destFramebuffer); + renderer.gl.viewport(0, 0, this.destFramebufferSize[0], this.destFramebufferSize[1]); + renderer.gl.scissor(0, 0, usedSize[0], usedSize[1]); + renderer.gl.enable(renderer.gl.SCISSOR_TEST); + this.setResolveDepthState(renderer); + renderer.gl.disable(renderer.gl.BLEND); + if (renderer.destFramebuffer != null) + renderer.drawBuffersExt.drawBuffersWEBGL([renderer.drawBuffersExt.COLOR_ATTACHMENT0_WEBGL]); else - view.drawBuffersExt.drawBuffersWEBGL([view.gl.BACK]); + renderer.drawBuffersExt.drawBuffersWEBGL([renderer.gl.BACK]); // Clear out the resolve buffer, if necessary. - this.clearForResolve(view); + this.clearForResolve(renderer); // Resolve. - const resolveProgram = this.getResolveProgram(view); - view.gl.useProgram(resolveProgram.program); - view.vertexArrayObjectExt.bindVertexArrayOES(this.resolveVAO); - view.setFramebufferSizeUniform(resolveProgram.uniforms); - view.gl.activeTexture(view.gl.TEXTURE0); - view.gl.bindTexture(view.gl.TEXTURE_2D, this.aaAlphaTexture); - view.gl.uniform1i(resolveProgram.uniforms.uAAAlpha, 0); - view.gl.uniform2i(resolveProgram.uniforms.uAAAlphaDimensions, + const resolveProgram = this.getResolveProgram(renderer); + renderer.gl.useProgram(resolveProgram.program); + renderer.vertexArrayObjectExt.bindVertexArrayOES(this.resolveVAO); + renderer.setFramebufferSizeUniform(resolveProgram.uniforms); + renderer.gl.activeTexture(renderer.gl.TEXTURE0); + renderer.gl.bindTexture(renderer.gl.TEXTURE_2D, this.aaAlphaTexture); + renderer.gl.uniform1i(resolveProgram.uniforms.uAAAlpha, 0); + renderer.gl.uniform2i(resolveProgram.uniforms.uAAAlphaDimensions, this.supersampledFramebufferSize[0], this.supersampledFramebufferSize[1]); - this.setResolveUniforms(view, resolveProgram); - view.setTransformSTAndTexScaleUniformsForDest(resolveProgram.uniforms); - view.gl.drawElements(view.gl.TRIANGLES, 6, view.gl.UNSIGNED_BYTE, 0); - view.vertexArrayObjectExt.bindVertexArrayOES(null); + this.setResolveUniforms(renderer, resolveProgram); + renderer.setTransformSTAndTexScaleUniformsForDest(resolveProgram.uniforms); + renderer.gl.drawElements(renderer.gl.TRIANGLES, 6, renderer.gl.UNSIGNED_BYTE, 0); + renderer.vertexArrayObjectExt.bindVertexArrayOES(null); } protected get directDepthTexture(): WebGLTexture | null { @@ -289,577 +293,588 @@ export abstract class MCAAStrategy extends XCAAStrategy { private lineVAOs: FastEdgeVAOs; private curveVAOs: FastEdgeVAOs; - attachMeshes(view: MonochromeDemoView) { - super.attachMeshes(view); + attachMeshes(renderer: Renderer) { + super.attachMeshes(renderer); - this.createCoverVAO(view); - this.createLineVAOs(view); - this.createCurveVAOs(view); + this.createCoverVAO(renderer); + this.createLineVAOs(renderer); + this.createCurveVAOs(renderer); } - antialias(view: MonochromeDemoView) { - super.antialias(view); + antialias(renderer: Renderer) { + super.antialias(renderer); // Conservatively cover. - this.cover(view); + this.cover(renderer); // Antialias. - this.antialiasLines(view); - this.antialiasCurves(view); + this.antialiasLines(renderer); + this.antialiasCurves(renderer); } - protected prepareAA(view: MonochromeDemoView): void { - super.prepareAA(view); + protected prepareAA(renderer: Renderer): void { + super.prepareAA(renderer); - this.setCoverDepthState(view); + this.setCoverDepthState(renderer); - view.gl.blendEquation(view.gl.FUNC_ADD); - view.gl.blendFunc(view.gl.ONE, view.gl.ONE); - view.gl.enable(view.gl.BLEND); + renderer.gl.blendEquation(renderer.gl.FUNC_ADD); + renderer.gl.blendFunc(renderer.gl.ONE, renderer.gl.ONE); + renderer.gl.enable(renderer.gl.BLEND); - this.clear(view); + this.clear(renderer); } - protected setCoverDepthState(view: MonochromeDemoView): void { - view.gl.disable(view.gl.DEPTH_TEST); + protected setCoverDepthState(renderer: Renderer): void { + renderer.gl.disable(renderer.gl.DEPTH_TEST); } - private createCoverVAO(view: MonochromeDemoView) { - this.coverVAO = view.vertexArrayObjectExt.createVertexArrayOES(); - view.vertexArrayObjectExt.bindVertexArrayOES(this.coverVAO); + private createCoverVAO(renderer: Renderer) { + this.coverVAO = renderer.vertexArrayObjectExt.createVertexArrayOES(); + renderer.vertexArrayObjectExt.bindVertexArrayOES(this.coverVAO); - const coverProgram = view.shaderPrograms.mcaaCover; + const coverProgram = renderer.shaderPrograms.mcaaCover; const attributes = coverProgram.attributes; - view.gl.useProgram(coverProgram.program); - view.gl.bindBuffer(view.gl.ARRAY_BUFFER, view.quadPositionsBuffer); - view.gl.vertexAttribPointer(attributes.aQuadPosition, 2, view.gl.FLOAT, false, 0, 0); - view.gl.bindBuffer(view.gl.ARRAY_BUFFER, view.meshes[0].edgeBoundingBoxVertexPositions); - view.gl.vertexAttribPointer(attributes.aUpperLeftPosition, - 2, - view.gl.FLOAT, - false, - FLOAT32_SIZE * 4, - 0); - view.gl.vertexAttribPointer(attributes.aLowerRightPosition, - 2, - view.gl.FLOAT, - false, - FLOAT32_SIZE * 4, - FLOAT32_SIZE * 2); - view.gl.bindBuffer(view.gl.ARRAY_BUFFER, view.meshes[0].edgeBoundingBoxPathIDs); - view.gl.vertexAttribPointer(attributes.aPathID, - 1, - view.gl.UNSIGNED_SHORT, - false, - 0, - 0); - view.gl.enableVertexAttribArray(attributes.aQuadPosition); - view.gl.enableVertexAttribArray(attributes.aUpperLeftPosition); - view.gl.enableVertexAttribArray(attributes.aLowerRightPosition); - view.gl.enableVertexAttribArray(attributes.aPathID); - view.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aUpperLeftPosition, 1); - view.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aLowerRightPosition, 1); - view.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aPathID, 1); - view.gl.bindBuffer(view.gl.ELEMENT_ARRAY_BUFFER, view.quadElementsBuffer); - - view.vertexArrayObjectExt.bindVertexArrayOES(null); - } - - private createLineVAOs(view: MonochromeDemoView) { - const vaos: Partial = {}; - const lineProgram = view.shaderPrograms.mcaaLine; - const attributes = lineProgram.attributes; - - for (const direction of DIRECTIONS) { - const vao = view.vertexArrayObjectExt.createVertexArrayOES(); - view.vertexArrayObjectExt.bindVertexArrayOES(vao); - - const lineVertexPositionsBuffer = { - lower: view.meshes[0].edgeLowerLineVertexPositions, - upper: view.meshes[0].edgeUpperLineVertexPositions, - }[direction]; - const linePathIDsBuffer = { - lower: view.meshes[0].edgeLowerLinePathIDs, - upper: view.meshes[0].edgeUpperLinePathIDs, - }[direction]; - - view.gl.useProgram(lineProgram.program); - view.gl.bindBuffer(view.gl.ARRAY_BUFFER, view.quadPositionsBuffer); - view.gl.vertexAttribPointer(attributes.aQuadPosition, 2, view.gl.FLOAT, false, 0, 0); - view.gl.bindBuffer(view.gl.ARRAY_BUFFER, lineVertexPositionsBuffer); - view.gl.vertexAttribPointer(attributes.aLeftPosition, + renderer.gl.useProgram(coverProgram.program); + renderer.gl.bindBuffer(renderer.gl.ARRAY_BUFFER, renderer.quadPositionsBuffer); + renderer.gl.vertexAttribPointer(attributes.aQuadPosition, 2, renderer.gl.FLOAT, false, 0, 0); + renderer.gl.bindBuffer(renderer.gl.ARRAY_BUFFER, + renderer.meshes[0].edgeBoundingBoxVertexPositions); + renderer.gl.vertexAttribPointer(attributes.aUpperLeftPosition, 2, - view.gl.FLOAT, + renderer.gl.FLOAT, false, FLOAT32_SIZE * 4, 0); - view.gl.vertexAttribPointer(attributes.aRightPosition, + renderer.gl.vertexAttribPointer(attributes.aLowerRightPosition, 2, - view.gl.FLOAT, + renderer.gl.FLOAT, false, FLOAT32_SIZE * 4, FLOAT32_SIZE * 2); - view.gl.bindBuffer(view.gl.ARRAY_BUFFER, linePathIDsBuffer); - view.gl.vertexAttribPointer(attributes.aPathID, + renderer.gl.bindBuffer(renderer.gl.ARRAY_BUFFER, + renderer.meshes[0].edgeBoundingBoxPathIDs); + renderer.gl.vertexAttribPointer(attributes.aPathID, 1, - view.gl.UNSIGNED_SHORT, + renderer.gl.UNSIGNED_SHORT, false, 0, 0); + renderer.gl.enableVertexAttribArray(attributes.aQuadPosition); + renderer.gl.enableVertexAttribArray(attributes.aUpperLeftPosition); + renderer.gl.enableVertexAttribArray(attributes.aLowerRightPosition); + renderer.gl.enableVertexAttribArray(attributes.aPathID); + renderer.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aUpperLeftPosition, 1); + renderer.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aLowerRightPosition, 1); + renderer.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aPathID, 1); + renderer.gl.bindBuffer(renderer.gl.ELEMENT_ARRAY_BUFFER, renderer.quadElementsBuffer); - view.gl.enableVertexAttribArray(attributes.aQuadPosition); - view.gl.enableVertexAttribArray(attributes.aLeftPosition); - view.gl.enableVertexAttribArray(attributes.aRightPosition); - view.gl.enableVertexAttribArray(attributes.aPathID); + renderer.vertexArrayObjectExt.bindVertexArrayOES(null); + } - view.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aLeftPosition, 1); - view.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aRightPosition, 1); - view.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aPathID, 1); + private createLineVAOs(renderer: Renderer) { + const vaos: Partial = {}; + const lineProgram = renderer.shaderPrograms.mcaaLine; + const attributes = lineProgram.attributes; - view.gl.bindBuffer(view.gl.ELEMENT_ARRAY_BUFFER, view.quadElementsBuffer); + for (const direction of DIRECTIONS) { + const vao = renderer.vertexArrayObjectExt.createVertexArrayOES(); + renderer.vertexArrayObjectExt.bindVertexArrayOES(vao); + + const lineVertexPositionsBuffer = { + lower: renderer.meshes[0].edgeLowerLineVertexPositions, + upper: renderer.meshes[0].edgeUpperLineVertexPositions, + }[direction]; + const linePathIDsBuffer = { + lower: renderer.meshes[0].edgeLowerLinePathIDs, + upper: renderer.meshes[0].edgeUpperLinePathIDs, + }[direction]; + + renderer.gl.useProgram(lineProgram.program); + renderer.gl.bindBuffer(renderer.gl.ARRAY_BUFFER, renderer.quadPositionsBuffer); + renderer.gl.vertexAttribPointer(attributes.aQuadPosition, 2, renderer.gl.FLOAT, false, 0, 0); + renderer.gl.bindBuffer(renderer.gl.ARRAY_BUFFER, lineVertexPositionsBuffer); + renderer.gl.vertexAttribPointer(attributes.aLeftPosition, + 2, + renderer.gl.FLOAT, + false, + FLOAT32_SIZE * 4, + 0); + renderer.gl.vertexAttribPointer(attributes.aRightPosition, + 2, + renderer.gl.FLOAT, + false, + FLOAT32_SIZE * 4, + FLOAT32_SIZE * 2); + renderer.gl.bindBuffer(renderer.gl.ARRAY_BUFFER, linePathIDsBuffer); + renderer.gl.vertexAttribPointer(attributes.aPathID, + 1, + renderer.gl.UNSIGNED_SHORT, + false, + 0, + 0); + + renderer.gl.enableVertexAttribArray(attributes.aQuadPosition); + renderer.gl.enableVertexAttribArray(attributes.aLeftPosition); + renderer.gl.enableVertexAttribArray(attributes.aRightPosition); + renderer.gl.enableVertexAttribArray(attributes.aPathID); + + renderer.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aLeftPosition, 1); + renderer.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aRightPosition, 1); + renderer.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aPathID, 1); + + renderer.gl.bindBuffer(renderer.gl.ELEMENT_ARRAY_BUFFER, renderer.quadElementsBuffer); vaos[direction] = vao; } - view.vertexArrayObjectExt.bindVertexArrayOES(null); + renderer.vertexArrayObjectExt.bindVertexArrayOES(null); this.lineVAOs = vaos as FastEdgeVAOs; } - private createCurveVAOs(view: MonochromeDemoView) { + private createCurveVAOs(renderer: Renderer) { const vaos: Partial = {}; - const curveProgram = view.shaderPrograms.mcaaCurve; + const curveProgram = renderer.shaderPrograms.mcaaCurve; const attributes = curveProgram.attributes; for (const direction of DIRECTIONS) { - const vao = view.vertexArrayObjectExt.createVertexArrayOES(); - view.vertexArrayObjectExt.bindVertexArrayOES(vao); + const vao = renderer.vertexArrayObjectExt.createVertexArrayOES(); + renderer.vertexArrayObjectExt.bindVertexArrayOES(vao); const curveVertexPositionsBuffer = { - lower: view.meshes[0].edgeLowerCurveVertexPositions, - upper: view.meshes[0].edgeUpperCurveVertexPositions, + lower: renderer.meshes[0].edgeLowerCurveVertexPositions, + upper: renderer.meshes[0].edgeUpperCurveVertexPositions, }[direction]; const curvePathIDsBuffer = { - lower: view.meshes[0].edgeLowerCurvePathIDs, - upper: view.meshes[0].edgeUpperCurvePathIDs, + lower: renderer.meshes[0].edgeLowerCurvePathIDs, + upper: renderer.meshes[0].edgeUpperCurvePathIDs, }[direction]; - view.gl.useProgram(curveProgram.program); - view.gl.bindBuffer(view.gl.ARRAY_BUFFER, view.quadPositionsBuffer); - view.gl.vertexAttribPointer(attributes.aQuadPosition, 2, view.gl.FLOAT, false, 0, 0); - view.gl.bindBuffer(view.gl.ARRAY_BUFFER, curveVertexPositionsBuffer); - view.gl.vertexAttribPointer(attributes.aLeftPosition, - 2, - view.gl.FLOAT, - false, - FLOAT32_SIZE * 6, - 0); - view.gl.vertexAttribPointer(attributes.aControlPointPosition, - 2, - view.gl.FLOAT, - false, - FLOAT32_SIZE * 6, - FLOAT32_SIZE * 2); - view.gl.vertexAttribPointer(attributes.aRightPosition, - 2, - view.gl.FLOAT, - false, - FLOAT32_SIZE * 6, - FLOAT32_SIZE * 4); - view.gl.bindBuffer(view.gl.ARRAY_BUFFER, curvePathIDsBuffer); - view.gl.vertexAttribPointer(attributes.aPathID, - 1, - view.gl.UNSIGNED_SHORT, - false, - 0, - 0); + renderer.gl.useProgram(curveProgram.program); + renderer.gl.bindBuffer(renderer.gl.ARRAY_BUFFER, renderer.quadPositionsBuffer); + renderer.gl.vertexAttribPointer(attributes.aQuadPosition, + 2, + renderer.gl.FLOAT, + false, + 0, + 0); + renderer.gl.bindBuffer(renderer.gl.ARRAY_BUFFER, curveVertexPositionsBuffer); + renderer.gl.vertexAttribPointer(attributes.aLeftPosition, + 2, + renderer.gl.FLOAT, + false, + FLOAT32_SIZE * 6, + 0); + renderer.gl.vertexAttribPointer(attributes.aControlPointPosition, + 2, + renderer.gl.FLOAT, + false, + FLOAT32_SIZE * 6, + FLOAT32_SIZE * 2); + renderer.gl.vertexAttribPointer(attributes.aRightPosition, + 2, + renderer.gl.FLOAT, + false, + FLOAT32_SIZE * 6, + FLOAT32_SIZE * 4); + renderer.gl.bindBuffer(renderer.gl.ARRAY_BUFFER, curvePathIDsBuffer); + renderer.gl.vertexAttribPointer(attributes.aPathID, + 1, + renderer.gl.UNSIGNED_SHORT, + false, + 0, + 0); - view.gl.enableVertexAttribArray(attributes.aQuadPosition); - view.gl.enableVertexAttribArray(attributes.aLeftPosition); - view.gl.enableVertexAttribArray(attributes.aControlPointPosition); - view.gl.enableVertexAttribArray(attributes.aRightPosition); - view.gl.enableVertexAttribArray(attributes.aPathID); + renderer.gl.enableVertexAttribArray(attributes.aQuadPosition); + renderer.gl.enableVertexAttribArray(attributes.aLeftPosition); + renderer.gl.enableVertexAttribArray(attributes.aControlPointPosition); + renderer.gl.enableVertexAttribArray(attributes.aRightPosition); + renderer.gl.enableVertexAttribArray(attributes.aPathID); - view.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aLeftPosition, 1); - view.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aControlPointPosition, + renderer.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aLeftPosition, 1); + renderer.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aControlPointPosition, 1); - view.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aRightPosition, 1); - view.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aPathID, 1); + renderer.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aRightPosition, 1); + renderer.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aPathID, 1); - view.gl.bindBuffer(view.gl.ELEMENT_ARRAY_BUFFER, view.quadElementsBuffer); + renderer.gl.bindBuffer(renderer.gl.ELEMENT_ARRAY_BUFFER, renderer.quadElementsBuffer); vaos[direction] = vao; } - view.vertexArrayObjectExt.bindVertexArrayOES(null); + renderer.vertexArrayObjectExt.bindVertexArrayOES(null); this.curveVAOs = vaos as FastEdgeVAOs; } - private cover(view: MonochromeDemoView): void { + private cover(renderer: Renderer): void { // Conservatively cover. - const coverProgram = view.shaderPrograms.mcaaCover; - view.gl.useProgram(coverProgram.program); - view.vertexArrayObjectExt.bindVertexArrayOES(this.coverVAO); - this.setAAUniforms(view, coverProgram.uniforms); - view.instancedArraysExt.drawElementsInstancedANGLE(view.gl.TRIANGLES, - 6, - view.gl.UNSIGNED_BYTE, - 0, - view.meshData[0].bQuadCount); - view.vertexArrayObjectExt.bindVertexArrayOES(null); + const coverProgram = renderer.shaderPrograms.mcaaCover; + renderer.gl.useProgram(coverProgram.program); + renderer.vertexArrayObjectExt.bindVertexArrayOES(this.coverVAO); + this.setAAUniforms(renderer, coverProgram.uniforms); + renderer.instancedArraysExt.drawElementsInstancedANGLE(renderer.gl.TRIANGLES, + 6, + renderer.gl.UNSIGNED_BYTE, + 0, + renderer.meshData[0].bQuadCount); + renderer.vertexArrayObjectExt.bindVertexArrayOES(null); } - private setBlendModeForAA(view: MonochromeDemoView, direction: 'upper' | 'lower') { - view.gl.blendEquation(view.gl.FUNC_ADD); - view.gl.blendFunc(view.gl.ONE, view.gl.ONE); - view.gl.enable(view.gl.BLEND); + private setBlendModeForAA(renderer: Renderer, direction: 'upper' | 'lower') { + renderer.gl.blendEquation(renderer.gl.FUNC_ADD); + renderer.gl.blendFunc(renderer.gl.ONE, renderer.gl.ONE); + renderer.gl.enable(renderer.gl.BLEND); } - private antialiasLines(view: MonochromeDemoView) { - this.setAAState(view); + private antialiasLines(renderer: Renderer) { + this.setAAState(renderer); - const lineProgram = view.shaderPrograms.mcaaLine; + const lineProgram = renderer.shaderPrograms.mcaaLine; - view.gl.useProgram(lineProgram.program); + renderer.gl.useProgram(lineProgram.program); const uniforms = lineProgram.uniforms; - this.setAAUniforms(view, uniforms); + this.setAAUniforms(renderer, uniforms); for (const direction of DIRECTIONS) { const vao = this.lineVAOs[direction]; - view.vertexArrayObjectExt.bindVertexArrayOES(vao); + renderer.vertexArrayObjectExt.bindVertexArrayOES(vao); - this.setBlendModeForAA(view, direction); - view.gl.uniform1i(uniforms.uWinding, direction === 'upper' ? 1 : 0); + this.setBlendModeForAA(renderer, direction); + renderer.gl.uniform1i(uniforms.uWinding, direction === 'upper' ? 1 : 0); const count = { - lower: view.meshData[0].edgeLowerLineCount, - upper: view.meshData[0].edgeUpperLineCount, + lower: renderer.meshData[0].edgeLowerLineCount, + upper: renderer.meshData[0].edgeUpperLineCount, }[direction]; - view.instancedArraysExt.drawElementsInstancedANGLE(view.gl.TRIANGLES, - 6, - view.gl.UNSIGNED_BYTE, - 0, - count); + renderer.instancedArraysExt.drawElementsInstancedANGLE(renderer.gl.TRIANGLES, + 6, + renderer.gl.UNSIGNED_BYTE, + 0, + count); } - view.vertexArrayObjectExt.bindVertexArrayOES(null); + renderer.vertexArrayObjectExt.bindVertexArrayOES(null); } - private antialiasCurves(view: MonochromeDemoView) { - this.setAAState(view); + private antialiasCurves(renderer: Renderer) { + this.setAAState(renderer); - const curveProgram = view.shaderPrograms.mcaaCurve; + const curveProgram = renderer.shaderPrograms.mcaaCurve; - view.gl.useProgram(curveProgram.program); + renderer.gl.useProgram(curveProgram.program); const uniforms = curveProgram.uniforms; - this.setAAUniforms(view, uniforms); + this.setAAUniforms(renderer, uniforms); for (const direction of DIRECTIONS) { const vao = this.curveVAOs[direction]; - view.vertexArrayObjectExt.bindVertexArrayOES(vao); + renderer.vertexArrayObjectExt.bindVertexArrayOES(vao); - this.setBlendModeForAA(view, direction); - view.gl.uniform1i(uniforms.uWinding, direction === 'upper' ? 1 : 0); + this.setBlendModeForAA(renderer, direction); + renderer.gl.uniform1i(uniforms.uWinding, direction === 'upper' ? 1 : 0); const count = { - lower: view.meshData[0].edgeLowerCurveCount, - upper: view.meshData[0].edgeUpperCurveCount, + lower: renderer.meshData[0].edgeLowerCurveCount, + upper: renderer.meshData[0].edgeUpperCurveCount, }[direction]; - view.instancedArraysExt.drawElementsInstancedANGLE(view.gl.TRIANGLES, - 6, - view.gl.UNSIGNED_BYTE, - 0, - count); + renderer.instancedArraysExt.drawElementsInstancedANGLE(renderer.gl.TRIANGLES, + 6, + renderer.gl.UNSIGNED_BYTE, + 0, + count); } - view.vertexArrayObjectExt.bindVertexArrayOES(null); + renderer.vertexArrayObjectExt.bindVertexArrayOES(null); } } export class ECAAStrategy extends XCAAStrategy { - private boldLineVAO: WebGLVertexArrayObject; - private boldCurveVAO: WebGLVertexArrayObject; + private lineVAO: WebGLVertexArrayObject; + private curveVAO: WebGLVertexArrayObject; get shouldRenderDirect() { return false; } - attachMeshes(view: MonochromeDemoView) { - super.attachMeshes(view); + attachMeshes(renderer: Renderer) { + super.attachMeshes(renderer); - this.createBoldLineVAO(view); - this.createBoldCurveVAO(view); + this.createLineVAO(renderer); + this.createCurveVAO(renderer); } - antialias(view: MonochromeDemoView) { - super.antialias(view); + antialias(renderer: Renderer) { + super.antialias(renderer); // Antialias. - this.antialiasLines(view); - this.antialiasCurves(view); + this.antialiasLines(renderer); + this.antialiasCurves(renderer); } - protected setAAUniforms(view: MonochromeDemoView, uniforms: UniformMap) { - super.setAAUniforms(view, uniforms); - const emboldenAmount = view.emboldenAmount; - view.gl.uniform2f(uniforms.uEmboldenAmount, emboldenAmount[0], emboldenAmount[1]); + protected setAAUniforms(renderer: Renderer, uniforms: UniformMap) { + super.setAAUniforms(renderer, uniforms); + const emboldenAmount = renderer.emboldenAmount; + renderer.gl.uniform2f(uniforms.uEmboldenAmount, emboldenAmount[0], emboldenAmount[1]); } - protected getResolveProgram(view: MonochromeDemoView): PathfinderShaderProgram { + protected getResolveProgram(renderer: Renderer): PathfinderShaderProgram { if (this.subpixelAA !== 'none') - return view.shaderPrograms.xcaaMonoSubpixelResolve; - return view.shaderPrograms.xcaaMonoResolve; + return renderer.shaderPrograms.xcaaMonoSubpixelResolve; + return renderer.shaderPrograms.xcaaMonoResolve; } - protected initEdgeDetectFramebuffer(view: MonochromeDemoView) {} + protected initEdgeDetectFramebuffer(renderer: Renderer) {} - protected createEdgeDetectVAO(view: MonochromeDemoView) {} + protected createEdgeDetectVAO(renderer: Renderer) {} - protected detectEdgesIfNecessary(view: MonochromeDemoView) {} + protected detectEdgesIfNecessary(renderer: Renderer) {} - protected clear(view: MonochromeDemoView) { - view.gl.clearColor(0.0, 0.0, 0.0, 0.0); - view.gl.clearDepth(0.0); - view.gl.clear(view.gl.COLOR_BUFFER_BIT | view.gl.DEPTH_BUFFER_BIT); + protected clear(renderer: Renderer) { + renderer.gl.clearColor(0.0, 0.0, 0.0, 0.0); + renderer.gl.clearDepth(0.0); + renderer.gl.clear(renderer.gl.COLOR_BUFFER_BIT | renderer.gl.DEPTH_BUFFER_BIT); } - protected setAADepthState(view: MonochromeDemoView) { - view.gl.disable(view.gl.DEPTH_TEST); + protected setAADepthState(renderer: Renderer) { + renderer.gl.disable(renderer.gl.DEPTH_TEST); } - protected clearForResolve(view: MonochromeDemoView) { - view.gl.clearColor(0.0, 0.0, 0.0, 0.0); - view.gl.clear(view.gl.COLOR_BUFFER_BIT); + protected clearForResolve(renderer: Renderer) { + renderer.gl.clearColor(0.0, 0.0, 0.0, 0.0); + renderer.gl.clear(renderer.gl.COLOR_BUFFER_BIT); } - protected setResolveUniforms(view: MonochromeDemoView, program: PathfinderShaderProgram) { - view.gl.uniform4fv(program.uniforms.uBGColor, view.bgColor); - view.gl.uniform4fv(program.uniforms.uFGColor, view.fgColor); + protected setResolveUniforms(renderer: Renderer, program: PathfinderShaderProgram) { + if (renderer.bgColor != null) + renderer.gl.uniform4fv(program.uniforms.uBGColor, renderer.bgColor); + if (renderer.fgColor != null) + renderer.gl.uniform4fv(program.uniforms.uFGColor, renderer.fgColor); } - private setBlendModeForAA(view: MonochromeDemoView) { - view.gl.blendEquation(view.gl.FUNC_ADD); - view.gl.blendFunc(view.gl.ONE, view.gl.ONE); - view.gl.enable(view.gl.BLEND); + private setBlendModeForAA(renderer: Renderer) { + renderer.gl.blendEquation(renderer.gl.FUNC_ADD); + renderer.gl.blendFunc(renderer.gl.ONE, renderer.gl.ONE); + renderer.gl.enable(renderer.gl.BLEND); } - private createBoldLineVAO(view: MonochromeDemoView) { - const lineProgram = view.shaderPrograms.ecaaLine; + private createLineVAO(renderer: Renderer) { + const lineProgram = renderer.shaderPrograms.ecaaLine; const attributes = lineProgram.attributes; - const vao = view.vertexArrayObjectExt.createVertexArrayOES(); - view.vertexArrayObjectExt.bindVertexArrayOES(vao); + const vao = renderer.vertexArrayObjectExt.createVertexArrayOES(); + renderer.vertexArrayObjectExt.bindVertexArrayOES(vao); - const lineVertexPositionsBuffer = view.meshes[0].segmentLines; - const linePathIDsBuffer = view.meshes[0].segmentLinePathIDs; - const lineNormalsBuffer = view.meshes[0].segmentLineNormals; + const lineVertexPositionsBuffer = renderer.meshes[0].segmentLines; + const linePathIDsBuffer = renderer.meshes[0].segmentLinePathIDs; + const lineNormalsBuffer = renderer.meshes[0].segmentLineNormals; - view.gl.useProgram(lineProgram.program); - view.gl.bindBuffer(view.gl.ARRAY_BUFFER, view.quadPositionsBuffer); - view.gl.vertexAttribPointer(attributes.aQuadPosition, 2, view.gl.FLOAT, false, 0, 0); - view.gl.bindBuffer(view.gl.ARRAY_BUFFER, lineVertexPositionsBuffer); - view.gl.vertexAttribPointer(attributes.aLeftPosition, + renderer.gl.useProgram(lineProgram.program); + renderer.gl.bindBuffer(renderer.gl.ARRAY_BUFFER, renderer.quadPositionsBuffer); + renderer.gl.vertexAttribPointer(attributes.aQuadPosition, 2, renderer.gl.FLOAT, false, 0, 0); + renderer.gl.bindBuffer(renderer.gl.ARRAY_BUFFER, lineVertexPositionsBuffer); + renderer.gl.vertexAttribPointer(attributes.aLeftPosition, 2, - view.gl.FLOAT, + renderer.gl.FLOAT, false, FLOAT32_SIZE * 4, 0); - view.gl.vertexAttribPointer(attributes.aRightPosition, + renderer.gl.vertexAttribPointer(attributes.aRightPosition, 2, - view.gl.FLOAT, + renderer.gl.FLOAT, false, FLOAT32_SIZE * 4, FLOAT32_SIZE * 2); - view.gl.bindBuffer(view.gl.ARRAY_BUFFER, linePathIDsBuffer); - view.gl.vertexAttribPointer(attributes.aPathID, + renderer.gl.bindBuffer(renderer.gl.ARRAY_BUFFER, linePathIDsBuffer); + renderer.gl.vertexAttribPointer(attributes.aPathID, 1, - view.gl.UNSIGNED_SHORT, + renderer.gl.UNSIGNED_SHORT, false, 0, 0); - view.gl.bindBuffer(view.gl.ARRAY_BUFFER, lineNormalsBuffer); - view.gl.vertexAttribPointer(attributes.aLeftNormalAngle, + renderer.gl.bindBuffer(renderer.gl.ARRAY_BUFFER, lineNormalsBuffer); + renderer.gl.vertexAttribPointer(attributes.aLeftNormalAngle, 1, - view.gl.FLOAT, + renderer.gl.FLOAT, false, FLOAT32_SIZE * 2, 0); - view.gl.vertexAttribPointer(attributes.aRightNormalAngle, + renderer.gl.vertexAttribPointer(attributes.aRightNormalAngle, 1, - view.gl.FLOAT, + renderer.gl.FLOAT, false, FLOAT32_SIZE * 2, FLOAT32_SIZE); - view.gl.enableVertexAttribArray(attributes.aQuadPosition); - view.gl.enableVertexAttribArray(attributes.aLeftPosition); - view.gl.enableVertexAttribArray(attributes.aRightPosition); - view.gl.enableVertexAttribArray(attributes.aPathID); - view.gl.enableVertexAttribArray(attributes.aLeftNormalAngle); - view.gl.enableVertexAttribArray(attributes.aRightNormalAngle); + renderer.gl.enableVertexAttribArray(attributes.aQuadPosition); + renderer.gl.enableVertexAttribArray(attributes.aLeftPosition); + renderer.gl.enableVertexAttribArray(attributes.aRightPosition); + renderer.gl.enableVertexAttribArray(attributes.aPathID); + renderer.gl.enableVertexAttribArray(attributes.aLeftNormalAngle); + renderer.gl.enableVertexAttribArray(attributes.aRightNormalAngle); - view.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aLeftPosition, 1); - view.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aRightPosition, 1); - view.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aPathID, 1); - view.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aLeftNormalAngle, 1); - view.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aRightNormalAngle, 1); + renderer.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aLeftPosition, 1); + renderer.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aRightPosition, 1); + renderer.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aPathID, 1); + renderer.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aLeftNormalAngle, 1); + renderer.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aRightNormalAngle, 1); - view.gl.bindBuffer(view.gl.ELEMENT_ARRAY_BUFFER, view.quadElementsBuffer); + renderer.gl.bindBuffer(renderer.gl.ELEMENT_ARRAY_BUFFER, renderer.quadElementsBuffer); - view.vertexArrayObjectExt.bindVertexArrayOES(null); + renderer.vertexArrayObjectExt.bindVertexArrayOES(null); - this.boldLineVAO = vao; + this.lineVAO = vao; } - private createBoldCurveVAO(view: MonochromeDemoView) { - const curveProgram = view.shaderPrograms.ecaaCurve; + private createCurveVAO(renderer: Renderer) { + const curveProgram = renderer.shaderPrograms.ecaaCurve; const attributes = curveProgram.attributes; - const vao = view.vertexArrayObjectExt.createVertexArrayOES(); - view.vertexArrayObjectExt.bindVertexArrayOES(vao); + const vao = renderer.vertexArrayObjectExt.createVertexArrayOES(); + renderer.vertexArrayObjectExt.bindVertexArrayOES(vao); - const curveVertexPositionsBuffer = view.meshes[0].segmentCurves; - const curvePathIDsBuffer = view.meshes[0].segmentCurvePathIDs; - const curveNormalsBuffer = view.meshes[0].segmentCurveNormals; + const curveVertexPositionsBuffer = renderer.meshes[0].segmentCurves; + const curvePathIDsBuffer = renderer.meshes[0].segmentCurvePathIDs; + const curveNormalsBuffer = renderer.meshes[0].segmentCurveNormals; - view.gl.useProgram(curveProgram.program); - view.gl.bindBuffer(view.gl.ARRAY_BUFFER, view.quadPositionsBuffer); - view.gl.vertexAttribPointer(attributes.aQuadPosition, 2, view.gl.FLOAT, false, 0, 0); - view.gl.bindBuffer(view.gl.ARRAY_BUFFER, curveVertexPositionsBuffer); - view.gl.vertexAttribPointer(attributes.aLeftPosition, - 2, - view.gl.FLOAT, - false, - FLOAT32_SIZE * 6, - 0); - view.gl.vertexAttribPointer(attributes.aControlPointPosition, - 2, - view.gl.FLOAT, - false, - FLOAT32_SIZE * 6, - FLOAT32_SIZE * 2); - view.gl.vertexAttribPointer(attributes.aRightPosition, - 2, - view.gl.FLOAT, - false, - FLOAT32_SIZE * 6, - FLOAT32_SIZE * 4); - view.gl.bindBuffer(view.gl.ARRAY_BUFFER, curvePathIDsBuffer); - view.gl.vertexAttribPointer(attributes.aPathID, - 1, - view.gl.UNSIGNED_SHORT, - false, - 0, - 0); - view.gl.bindBuffer(view.gl.ARRAY_BUFFER, curveNormalsBuffer); - view.gl.vertexAttribPointer(attributes.aNormalAngles, - 3, - view.gl.FLOAT, - false, - FLOAT32_SIZE * 3, - 0); + renderer.gl.useProgram(curveProgram.program); + renderer.gl.bindBuffer(renderer.gl.ARRAY_BUFFER, renderer.quadPositionsBuffer); + renderer.gl.vertexAttribPointer(attributes.aQuadPosition, 2, renderer.gl.FLOAT, false, 0, 0); + renderer.gl.bindBuffer(renderer.gl.ARRAY_BUFFER, curveVertexPositionsBuffer); + renderer.gl.vertexAttribPointer(attributes.aLeftPosition, + 2, + renderer.gl.FLOAT, + false, + FLOAT32_SIZE * 6, + 0); + renderer.gl.vertexAttribPointer(attributes.aControlPointPosition, + 2, + renderer.gl.FLOAT, + false, + FLOAT32_SIZE * 6, + FLOAT32_SIZE * 2); + renderer.gl.vertexAttribPointer(attributes.aRightPosition, + 2, + renderer.gl.FLOAT, + false, + FLOAT32_SIZE * 6, + FLOAT32_SIZE * 4); + renderer.gl.bindBuffer(renderer.gl.ARRAY_BUFFER, curvePathIDsBuffer); + renderer.gl.vertexAttribPointer(attributes.aPathID, + 1, + renderer.gl.UNSIGNED_SHORT, + false, + 0, + 0); + renderer.gl.bindBuffer(renderer.gl.ARRAY_BUFFER, curveNormalsBuffer); + renderer.gl.vertexAttribPointer(attributes.aNormalAngles, + 3, + renderer.gl.FLOAT, + false, + FLOAT32_SIZE * 3, + 0); - view.gl.enableVertexAttribArray(attributes.aQuadPosition); - view.gl.enableVertexAttribArray(attributes.aLeftPosition); - view.gl.enableVertexAttribArray(attributes.aControlPointPosition); - view.gl.enableVertexAttribArray(attributes.aRightPosition); - view.gl.enableVertexAttribArray(attributes.aPathID); - view.gl.enableVertexAttribArray(attributes.aNormalAngles); + renderer.gl.enableVertexAttribArray(attributes.aQuadPosition); + renderer.gl.enableVertexAttribArray(attributes.aLeftPosition); + renderer.gl.enableVertexAttribArray(attributes.aControlPointPosition); + renderer.gl.enableVertexAttribArray(attributes.aRightPosition); + renderer.gl.enableVertexAttribArray(attributes.aPathID); + renderer.gl.enableVertexAttribArray(attributes.aNormalAngles); - view.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aLeftPosition, 1); - view.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aControlPointPosition, 1); - view.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aRightPosition, 1); - view.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aPathID, 1); - view.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aNormalAngles, 1); + renderer.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aLeftPosition, 1); + renderer.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aControlPointPosition, 1); + renderer.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aRightPosition, 1); + renderer.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aPathID, 1); + renderer.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aNormalAngles, 1); - view.gl.bindBuffer(view.gl.ELEMENT_ARRAY_BUFFER, view.quadElementsBuffer); + renderer.gl.bindBuffer(renderer.gl.ELEMENT_ARRAY_BUFFER, renderer.quadElementsBuffer); - view.vertexArrayObjectExt.bindVertexArrayOES(null); + renderer.vertexArrayObjectExt.bindVertexArrayOES(null); - this.boldCurveVAO = vao; + this.curveVAO = vao; } - private antialiasLines(view: MonochromeDemoView) { - this.setAAState(view); + private antialiasLines(renderer: Renderer) { + this.setAAState(renderer); - const lineProgram = view.shaderPrograms.ecaaLine; + const lineProgram = renderer.shaderPrograms.ecaaLine; - view.gl.useProgram(lineProgram.program); + renderer.gl.useProgram(lineProgram.program); const uniforms = lineProgram.uniforms; - this.setAAUniforms(view, uniforms); + this.setAAUniforms(renderer, uniforms); - const vao = this.boldLineVAO; - view.vertexArrayObjectExt.bindVertexArrayOES(vao); + const vao = this.lineVAO; + renderer.vertexArrayObjectExt.bindVertexArrayOES(vao); - this.setBlendModeForAA(view); + this.setBlendModeForAA(renderer); - const count = view.meshData[0].segmentLineCount; - view.instancedArraysExt.drawElementsInstancedANGLE(view.gl.TRIANGLES, - 6, - view.gl.UNSIGNED_BYTE, - 0, - count); + const count = renderer.meshData[0].segmentLineCount; + renderer.instancedArraysExt.drawElementsInstancedANGLE(renderer.gl.TRIANGLES, + 6, + renderer.gl.UNSIGNED_BYTE, + 0, + count); - view.vertexArrayObjectExt.bindVertexArrayOES(null); + renderer.vertexArrayObjectExt.bindVertexArrayOES(null); } - private antialiasCurves(view: MonochromeDemoView) { - this.setAAState(view); + private antialiasCurves(renderer: Renderer) { + this.setAAState(renderer); - const curveProgram = view.shaderPrograms.ecaaCurve; + const curveProgram = renderer.shaderPrograms.ecaaCurve; - view.gl.useProgram(curveProgram.program); + renderer.gl.useProgram(curveProgram.program); const uniforms = curveProgram.uniforms; - this.setAAUniforms(view, uniforms); + this.setAAUniforms(renderer, uniforms); - const vao = this.boldCurveVAO; - view.vertexArrayObjectExt.bindVertexArrayOES(vao); + const vao = this.curveVAO; + renderer.vertexArrayObjectExt.bindVertexArrayOES(vao); - this.setBlendModeForAA(view); + this.setBlendModeForAA(renderer); - const count = view.meshData[0].segmentCurveCount; - view.instancedArraysExt.drawElementsInstancedANGLE(view.gl.TRIANGLES, - 6, - view.gl.UNSIGNED_BYTE, - 0, - count); + const count = renderer.meshData[0].segmentCurveCount; + renderer.instancedArraysExt.drawElementsInstancedANGLE(renderer.gl.TRIANGLES, + 6, + renderer.gl.UNSIGNED_BYTE, + 0, + count); - view.vertexArrayObjectExt.bindVertexArrayOES(null); + renderer.vertexArrayObjectExt.bindVertexArrayOES(null); } } export class MCAAMonochromeStrategy extends MCAAStrategy { - protected getResolveProgram(view: MonochromeDemoView): PathfinderShaderProgram { + protected getResolveProgram(renderer: Renderer): PathfinderShaderProgram { if (this.subpixelAA !== 'none') - return view.shaderPrograms.xcaaMonoSubpixelResolve; - return view.shaderPrograms.xcaaMonoResolve; + return renderer.shaderPrograms.xcaaMonoSubpixelResolve; + return renderer.shaderPrograms.xcaaMonoResolve; } - protected initEdgeDetectFramebuffer(view: MonochromeDemoView) {} + protected initEdgeDetectFramebuffer(renderer: Renderer) {} - protected createEdgeDetectVAO(view: MonochromeDemoView) {} + protected createEdgeDetectVAO(renderer: Renderer) {} - protected detectEdgesIfNecessary(view: MonochromeDemoView) {} + protected detectEdgesIfNecessary(renderer: Renderer) {} - protected clear(view: MonochromeDemoView) { - view.gl.clearColor(0.0, 0.0, 0.0, 0.0); - view.gl.clearDepth(0.0); - view.gl.clear(view.gl.COLOR_BUFFER_BIT | view.gl.DEPTH_BUFFER_BIT); + protected clear(renderer: Renderer) { + renderer.gl.clearColor(0.0, 0.0, 0.0, 0.0); + renderer.gl.clearDepth(0.0); + renderer.gl.clear(renderer.gl.COLOR_BUFFER_BIT | renderer.gl.DEPTH_BUFFER_BIT); } - protected setAADepthState(view: MonochromeDemoView) { - view.gl.disable(view.gl.DEPTH_TEST); + protected setAADepthState(renderer: Renderer) { + renderer.gl.disable(renderer.gl.DEPTH_TEST); } - protected clearForResolve(view: MonochromeDemoView) { - view.gl.clearColor(0.0, 0.0, 0.0, 0.0); - view.gl.clear(view.gl.COLOR_BUFFER_BIT); + protected clearForResolve(renderer: Renderer) { + renderer.gl.clearColor(0.0, 0.0, 0.0, 0.0); + renderer.gl.clear(renderer.gl.COLOR_BUFFER_BIT); } - protected setResolveUniforms(view: MonochromeDemoView, program: PathfinderShaderProgram) { - view.gl.uniform4fv(program.uniforms.uBGColor, view.bgColor); - view.gl.uniform4fv(program.uniforms.uFGColor, view.fgColor); + protected setResolveUniforms(renderer: Renderer, program: PathfinderShaderProgram) { + if (renderer.bgColor != null) + renderer.gl.uniform4fv(program.uniforms.uBGColor, renderer.bgColor); + if (renderer.fgColor != null) + renderer.gl.uniform4fv(program.uniforms.uFGColor, renderer.fgColor); } get shouldRenderDirect() { @@ -883,39 +898,39 @@ export class AdaptiveMonochromeXCAAStrategy implements AntialiasingStrategy { this.ecaaStrategy = new ECAAStrategy(level, subpixelAA); } - init(view: MonochromeDemoView): void { - this.mcaaStrategy.init(view); - this.ecaaStrategy.init(view); + init(renderer: Renderer): void { + this.mcaaStrategy.init(renderer); + this.ecaaStrategy.init(renderer); } - attachMeshes(view: MonochromeDemoView): void { - this.mcaaStrategy.attachMeshes(view); - this.ecaaStrategy.attachMeshes(view); + attachMeshes(renderer: Renderer): void { + this.mcaaStrategy.attachMeshes(renderer); + this.ecaaStrategy.attachMeshes(renderer); } - setFramebufferSize(view: MonochromeDemoView): void { - this.mcaaStrategy.setFramebufferSize(view); - this.ecaaStrategy.setFramebufferSize(view); + setFramebufferSize(renderer: Renderer): void { + this.mcaaStrategy.setFramebufferSize(renderer); + this.ecaaStrategy.setFramebufferSize(renderer); } get transform(): glmatrix.mat4 { return this.mcaaStrategy.transform; } - prepare(view: MonochromeDemoView): void { - this.getAppropriateStrategy(view).prepare(view); + prepare(renderer: Renderer): void { + this.getAppropriateStrategy(renderer).prepare(renderer); } - antialias(view: MonochromeDemoView): void { - this.getAppropriateStrategy(view).antialias(view); + antialias(renderer: Renderer): void { + this.getAppropriateStrategy(renderer).antialias(renderer); } - resolve(view: MonochromeDemoView): void { - this.getAppropriateStrategy(view).resolve(view); + resolve(renderer: Renderer): void { + this.getAppropriateStrategy(renderer).resolve(renderer); } - private getAppropriateStrategy(view: MonochromeDemoView): AntialiasingStrategy { - if (glmatrix.vec2.equals(view.emboldenAmount, [0.0, 0.0])) + private getAppropriateStrategy(renderer: Renderer): AntialiasingStrategy { + if (glmatrix.vec2.equals(renderer.emboldenAmount, [0.0, 0.0])) return this.mcaaStrategy; return this.ecaaStrategy; } @@ -929,109 +944,111 @@ export class MCAAMulticolorStrategy extends MCAAStrategy { private bgColorTexture: WebGLTexture; private fgColorTexture: WebGLTexture; - protected getResolveProgram(view: MonochromeDemoView): PathfinderShaderProgram { - return view.shaderPrograms.xcaaMultiResolve; + protected getResolveProgram(renderer: Renderer): PathfinderShaderProgram { + return renderer.shaderPrograms.xcaaMultiResolve; } - protected initDirectFramebuffer(view: MonochromeDemoView) { + protected initDirectFramebuffer(renderer: Renderer) { this._directDepthTexture = - createFramebufferDepthTexture(view.gl, this.supersampledFramebufferSize); - super.initDirectFramebuffer(view); + createFramebufferDepthTexture(renderer.gl, this.supersampledFramebufferSize); + super.initDirectFramebuffer(renderer); } - protected initEdgeDetectFramebuffer(view: MonochromeDemoView) { - this.bgColorTexture = createFramebufferColorTexture(view, - this.supersampledFramebufferSize); - this.fgColorTexture = createFramebufferColorTexture(view, - this.supersampledFramebufferSize); - this.edgeDetectFramebuffer = createFramebuffer(view.gl, - view.drawBuffersExt, + protected initEdgeDetectFramebuffer(renderer: Renderer) { + this.bgColorTexture = createFramebufferColorTexture(renderer.gl, + this.supersampledFramebufferSize, + renderer.colorAlphaFormat); + this.fgColorTexture = createFramebufferColorTexture(renderer.gl, + this.supersampledFramebufferSize, + renderer.colorAlphaFormat); + this.edgeDetectFramebuffer = createFramebuffer(renderer.gl, + renderer.drawBuffersExt, [this.bgColorTexture, this.fgColorTexture], this.aaDepthTexture); } - protected createEdgeDetectVAO(view: MonochromeDemoView) { - this.edgeDetectVAO = view.vertexArrayObjectExt.createVertexArrayOES(); - view.vertexArrayObjectExt.bindVertexArrayOES(this.edgeDetectVAO); + protected createEdgeDetectVAO(renderer: Renderer) { + this.edgeDetectVAO = renderer.vertexArrayObjectExt.createVertexArrayOES(); + renderer.vertexArrayObjectExt.bindVertexArrayOES(this.edgeDetectVAO); - const edgeDetectProgram = view.shaderPrograms.xcaaEdgeDetect; - view.gl.useProgram(edgeDetectProgram.program); - view.initQuadVAO(edgeDetectProgram.attributes); + const edgeDetectProgram = renderer.shaderPrograms.xcaaEdgeDetect; + renderer.gl.useProgram(edgeDetectProgram.program); + renderer.initQuadVAO(edgeDetectProgram.attributes); - view.vertexArrayObjectExt.bindVertexArrayOES(null); + renderer.vertexArrayObjectExt.bindVertexArrayOES(null); } - protected detectEdgesIfNecessary(view: MonochromeDemoView) { + protected detectEdgesIfNecessary(renderer: Renderer) { // Set state for edge detection. - const edgeDetectProgram = view.shaderPrograms.xcaaEdgeDetect; - view.gl.bindFramebuffer(view.gl.FRAMEBUFFER, this.edgeDetectFramebuffer); - view.gl.viewport(0, - 0, - this.supersampledFramebufferSize[0], - this.supersampledFramebufferSize[1]); + const edgeDetectProgram = renderer.shaderPrograms.xcaaEdgeDetect; + renderer.gl.bindFramebuffer(renderer.gl.FRAMEBUFFER, this.edgeDetectFramebuffer); + renderer.gl.viewport(0, + 0, + this.supersampledFramebufferSize[0], + this.supersampledFramebufferSize[1]); - view.drawBuffersExt.drawBuffersWEBGL([ - view.drawBuffersExt.COLOR_ATTACHMENT0_WEBGL, - view.drawBuffersExt.COLOR_ATTACHMENT1_WEBGL, + renderer.drawBuffersExt.drawBuffersWEBGL([ + renderer.drawBuffersExt.COLOR_ATTACHMENT0_WEBGL, + renderer.drawBuffersExt.COLOR_ATTACHMENT1_WEBGL, ]); - view.gl.depthMask(true); - view.gl.depthFunc(view.gl.ALWAYS); - view.gl.enable(view.gl.DEPTH_TEST); - view.gl.disable(view.gl.BLEND); + renderer.gl.depthMask(true); + renderer.gl.depthFunc(renderer.gl.ALWAYS); + renderer.gl.enable(renderer.gl.DEPTH_TEST); + renderer.gl.disable(renderer.gl.BLEND); - view.gl.clearDepth(0.0); - view.gl.clearColor(0.0, 0.0, 0.0, 0.0); - view.gl.clear(view.gl.COLOR_BUFFER_BIT | view.gl.DEPTH_BUFFER_BIT); + renderer.gl.clearDepth(0.0); + renderer.gl.clearColor(0.0, 0.0, 0.0, 0.0); + renderer.gl.clear(renderer.gl.COLOR_BUFFER_BIT | renderer.gl.DEPTH_BUFFER_BIT); // Perform edge detection. - view.gl.useProgram(edgeDetectProgram.program); - view.vertexArrayObjectExt.bindVertexArrayOES(this.edgeDetectVAO); - view.setFramebufferSizeUniform(edgeDetectProgram.uniforms); - view.setTransformSTAndTexScaleUniformsForDest(edgeDetectProgram.uniforms); - view.gl.activeTexture(view.gl.TEXTURE0); - view.gl.bindTexture(view.gl.TEXTURE_2D, this.directColorTexture); - view.gl.uniform1i(edgeDetectProgram.uniforms.uColor, 0); - view.gl.activeTexture(view.gl.TEXTURE1); - view.gl.bindTexture(view.gl.TEXTURE_2D, this.directPathIDTexture); - view.gl.uniform1i(edgeDetectProgram.uniforms.uPathID, 1); - view.gl.bindBuffer(view.gl.ELEMENT_ARRAY_BUFFER, view.quadElementsBuffer); - view.gl.drawElements(view.gl.TRIANGLES, 6, view.gl.UNSIGNED_BYTE, 0); - view.vertexArrayObjectExt.bindVertexArrayOES(null); + renderer.gl.useProgram(edgeDetectProgram.program); + renderer.vertexArrayObjectExt.bindVertexArrayOES(this.edgeDetectVAO); + renderer.setFramebufferSizeUniform(edgeDetectProgram.uniforms); + renderer.setTransformSTAndTexScaleUniformsForDest(edgeDetectProgram.uniforms); + renderer.gl.activeTexture(renderer.gl.TEXTURE0); + renderer.gl.bindTexture(renderer.gl.TEXTURE_2D, this.directColorTexture); + renderer.gl.uniform1i(edgeDetectProgram.uniforms.uColor, 0); + renderer.gl.activeTexture(renderer.gl.TEXTURE1); + renderer.gl.bindTexture(renderer.gl.TEXTURE_2D, this.directPathIDTexture); + renderer.gl.uniform1i(edgeDetectProgram.uniforms.uPathID, 1); + renderer.gl.bindBuffer(renderer.gl.ELEMENT_ARRAY_BUFFER, renderer.quadElementsBuffer); + renderer.gl.drawElements(renderer.gl.TRIANGLES, 6, renderer.gl.UNSIGNED_BYTE, 0); + renderer.vertexArrayObjectExt.bindVertexArrayOES(null); } - protected setCoverDepthState(view: MonochromeDemoView) { - view.gl.depthMask(false); - view.gl.depthFunc(view.gl.ALWAYS); - view.gl.enable(view.gl.DEPTH_TEST); + protected setCoverDepthState(renderer: Renderer) { + renderer.gl.depthMask(false); + renderer.gl.depthFunc(renderer.gl.ALWAYS); + renderer.gl.enable(renderer.gl.DEPTH_TEST); } - protected clear(view: MonochromeDemoView) { - view.gl.clearColor(0.0, 0.0, 0.0, 0.0); - view.gl.clear(view.gl.COLOR_BUFFER_BIT); + protected clear(renderer: Renderer) { + renderer.gl.clearColor(0.0, 0.0, 0.0, 0.0); + renderer.gl.clear(renderer.gl.COLOR_BUFFER_BIT); } - protected setAADepthState(view: MonochromeDemoView) { - view.gl.depthMask(false); - view.gl.depthFunc(view.gl.EQUAL); - view.gl.enable(view.gl.DEPTH_TEST); + protected setAADepthState(renderer: Renderer) { + renderer.gl.depthMask(false); + renderer.gl.depthFunc(renderer.gl.EQUAL); + renderer.gl.enable(renderer.gl.DEPTH_TEST); } - protected setResolveDepthState(view: MonochromeDemoView) { - view.gl.depthMask(false); - view.gl.depthFunc(view.gl.NOTEQUAL); - view.gl.enable(view.gl.DEPTH_TEST); + protected setResolveDepthState(renderer: Renderer) { + renderer.gl.depthMask(false); + renderer.gl.depthFunc(renderer.gl.NOTEQUAL); + renderer.gl.enable(renderer.gl.DEPTH_TEST); } - protected clearForResolve(view: MonochromeDemoView) {} + protected clearForResolve(renderer: Renderer) {} - protected setResolveUniforms(view: MonochromeDemoView, program: PathfinderShaderProgram) { - view.gl.activeTexture(view.gl.TEXTURE1); - view.gl.bindTexture(view.gl.TEXTURE_2D, this.bgColorTexture); - view.gl.uniform1i(program.uniforms.uBGColor, 1); - view.gl.activeTexture(view.gl.TEXTURE2); - view.gl.bindTexture(view.gl.TEXTURE_2D, this.fgColorTexture); - view.gl.uniform1i(program.uniforms.uFGColor, 2); + protected setResolveUniforms(renderer: Renderer, program: PathfinderShaderProgram) { + renderer.gl.activeTexture(renderer.gl.TEXTURE1); + renderer.gl.bindTexture(renderer.gl.TEXTURE_2D, this.bgColorTexture); + renderer.gl.uniform1i(program.uniforms.uBGColor, 1); + renderer.gl.activeTexture(renderer.gl.TEXTURE2); + renderer.gl.bindTexture(renderer.gl.TEXTURE_2D, this.fgColorTexture); + renderer.gl.uniform1i(program.uniforms.uFGColor, 2); } get shouldRenderDirect() { diff --git a/demo/client/tsconfig.json b/demo/client/tsconfig.json index 8f754cb7..09871b14 100644 --- a/demo/client/tsconfig.json +++ b/demo/client/tsconfig.json @@ -7,7 +7,8 @@ "gl-matrix", "lodash", "node", - "opentype.js" + "opentype.js", + "webgl-ext" ], "typeRoots": [ "node_modules/@types"