diff --git a/demo/client/src/aa-strategy.ts b/demo/client/src/aa-strategy.ts index ba0f32d0..dc26bae7 100644 --- a/demo/client/src/aa-strategy.ts +++ b/demo/client/src/aa-strategy.ts @@ -14,47 +14,48 @@ import {PathfinderView} from './view'; export type AntialiasingStrategyName = 'none' | 'ssaa' | 'ecaa'; -export interface AntialiasingStrategy { +export abstract class AntialiasingStrategy { // Prepares any OpenGL data. This is only called on startup and canvas resize. - init(view: PathfinderView): void; + init(view: PathfinderView): void { + this.setFramebufferSize(view); + } // Uploads any mesh data. This is called whenever a new set of meshes is supplied. - attachMeshes(view: PathfinderView): void; + abstract attachMeshes(view: PathfinderView): void; // This is called whenever the framebuffer has changed. - setFramebufferSize(view: PathfinderView, framebufferSize: glmatrix.vec2): void; + abstract setFramebufferSize(view: PathfinderView): void; // Returns the transformation matrix that should be applied when directly rendering. - transform(): glmatrix.mat4; + abstract get transform(): glmatrix.mat4; // Called before direct rendering. // // Typically, this redirects direct rendering to a framebuffer of some sort. - prepare(view: PathfinderView): void; + abstract prepare(view: PathfinderView): void; // Called after direct rendering. // // This usually performs the actual antialiasing and blits to the real framebuffer. - resolve(view: PathfinderView): void; + abstract resolve(view: PathfinderView): void; // True if direct rendering should occur. shouldRenderDirect: boolean; } -export class NoAAStrategy implements AntialiasingStrategy { +export class NoAAStrategy extends AntialiasingStrategy { constructor(level: number) { + super(); this.framebufferSize = glmatrix.vec2.create(); } - init(view: PathfinderView) {} - attachMeshes(view: PathfinderView) {} - setFramebufferSize(view: PathfinderView, framebufferSize: glmatrix.vec2) { - this.framebufferSize = framebufferSize; + setFramebufferSize(view: PathfinderView) { + this.framebufferSize = view.destAllocatedSize; } - transform(): glmatrix.mat4 { + get transform(): glmatrix.mat4 { return glmatrix.mat4.create(); } diff --git a/demo/client/src/ecaa-strategy.ts b/demo/client/src/ecaa-strategy.ts index b7bae6b9..fa106596 100644 --- a/demo/client/src/ecaa-strategy.ts +++ b/demo/client/src/ecaa-strategy.ts @@ -25,12 +25,14 @@ interface UpperAndLower { lower: T; } -export abstract class ECAAStrategy implements AntialiasingStrategy { +export abstract class ECAAStrategy extends AntialiasingStrategy { constructor(level: number) { + super(); this.framebufferSize = glmatrix.vec2.create(); } init(view: MonochromePathfinderView) { + super.init(view); this.bVertexPositionBufferTexture = new PathfinderBufferTexture(view.gl, 'uBVertexPosition'); this.bVertexPathIDBufferTexture = new PathfinderBufferTexture(view.gl, 'uBVertexPathID'); @@ -49,8 +51,8 @@ export abstract class ECAAStrategy implements AntialiasingStrategy { this.createResolveVAO(view); } - setFramebufferSize(view: MonochromePathfinderView, framebufferSize: glmatrix.vec2) { - this.framebufferSize = framebufferSize; + setFramebufferSize(view: MonochromePathfinderView) { + this.framebufferSize = view.destAllocatedSize; this.initDirectFramebuffer(view); this.initEdgeDetectFramebuffer(view); @@ -58,7 +60,7 @@ export abstract class ECAAStrategy implements AntialiasingStrategy { view.gl.bindFramebuffer(view.gl.FRAMEBUFFER, null); } - transform(): glmatrix.mat4 { + get transform(): glmatrix.mat4 { return glmatrix.mat4.create(); } @@ -288,7 +290,7 @@ export abstract class ECAAStrategy implements AntialiasingStrategy { view.setFramebufferSizeUniform(uniforms); this.bVertexPositionBufferTexture.bind(view.gl, uniforms, 0); this.bVertexPathIDBufferTexture.bind(view.gl, uniforms, 1); - view.atlasTransformBuffer.bind(view.gl, uniforms, 2); + view.pathTransformBufferTexture.bind(view.gl, uniforms, 2); view.instancedArraysExt.drawElementsInstancedANGLE(view.gl.TRIANGLES, 6, view.gl.UNSIGNED_BYTE, @@ -315,7 +317,7 @@ export abstract class ECAAStrategy implements AntialiasingStrategy { view.setFramebufferSizeUniform(uniforms); this.bVertexPositionBufferTexture.bind(view.gl, uniforms, 0); this.bVertexPathIDBufferTexture.bind(view.gl, uniforms, 1); - view.atlasTransformBuffer.bind(view.gl, uniforms, 2); + view.pathTransformBufferTexture.bind(view.gl, uniforms, 2); } private antialiasLines(view: MonochromePathfinderView) { diff --git a/demo/client/src/ssaa-strategy.ts b/demo/client/src/ssaa-strategy.ts index 91550ca3..ff13b334 100644 --- a/demo/client/src/ssaa-strategy.ts +++ b/demo/client/src/ssaa-strategy.ts @@ -15,23 +15,22 @@ import {createFramebufferDepthTexture, createFramebuffer, setTextureParameters} import {unwrapNull} from './utils'; import {PathfinderView} from './view'; -export default class SSAAStrategy implements AntialiasingStrategy { +export default class SSAAStrategy extends AntialiasingStrategy { constructor(level: number) { + super(); this.level = level; this.destFramebufferSize = glmatrix.vec2.create(); this.supersampledFramebufferSize = glmatrix.vec2.create(); } - init(view: PathfinderView) {} - attachMeshes(view: PathfinderView) {} - setFramebufferSize(view: PathfinderView, framebufferSize: glmatrix.vec2) { - this.destFramebufferSize = framebufferSize; + setFramebufferSize(view: PathfinderView) { + this.destFramebufferSize = view.destAllocatedSize; this.supersampledFramebufferSize = glmatrix.vec2.create(); glmatrix.vec2.mul(this.supersampledFramebufferSize, - framebufferSize, + this.destFramebufferSize, this.supersampleScale); this.supersampledColorTexture = unwrapNull(view.gl.createTexture()); @@ -59,7 +58,7 @@ export default class SSAAStrategy implements AntialiasingStrategy { view.gl.bindFramebuffer(view.gl.FRAMEBUFFER, null); } - transform(): glmatrix.mat4 { + get transform(): glmatrix.mat4 { const scale = glmatrix.vec2.create(); glmatrix.vec2.div(scale, this.supersampledFramebufferSize, this.destFramebufferSize); diff --git a/demo/client/src/svg.ts b/demo/client/src/svg.ts index 3d893edf..47da39f2 100644 --- a/demo/client/src/svg.ts +++ b/demo/client/src/svg.ts @@ -143,7 +143,10 @@ class SVGDemoView extends PathfinderView { this._scale = 1.0; } - protected resized(initialSize: boolean) {} + protected resized(initialSize: boolean) { + this.antialiasingStrategy.init(this); + this.setDirty(); + } get destAllocatedSize(): glmatrix.vec2 { return glmatrix.vec2.fromValues(this.canvas.width, this.canvas.height); @@ -157,17 +160,29 @@ class SVGDemoView extends PathfinderView { return this.destAllocatedSize; } - protected panned(): void {} + protected panned(): void { + this.setDirty(); + } uploadPathData(elements: SVGPathElement[]) { const pathColors = new Uint8Array(4 * (elements.length + 1)); + const pathTransforms = new Float32Array(4 * (elements.length + 1)); for (let pathIndex = 0; pathIndex < elements.length; pathIndex++) { + const startOffset = (pathIndex + 1) * 4; + + // Set color. const style = window.getComputedStyle(elements[pathIndex]); - const fillColor = style.fill === 'none' ? [0, 0, 0, 0] : parseColor(style.fill).rgba; - pathColors.set(fillColor, (pathIndex + 1) * 4); + const fillColor: number[] = + style.fill === 'none' ? [0, 0, 0, 0] : parseColor(style.fill).rgba; + pathColors.set(fillColor.slice(0, 3), startOffset); + pathColors[startOffset + 3] = fillColor[3] * 255; + + // TODO(pcwalton): Set transform. + pathTransforms.set([1, 1, 0, 0], startOffset); } this.pathColorsBufferTexture.upload(this.gl, pathColors); + this.pathTransformBufferTexture.upload(this.gl, pathTransforms); } protected createAAStrategy(aaType: AntialiasingStrategyName, aaLevel: number): @@ -182,7 +197,7 @@ class SVGDemoView extends PathfinderView { } protected get usedSizeFactor(): glmatrix.vec2 { - return glmatrix.vec2.create(); + return glmatrix.vec2.fromValues(1.0, 1.0); } protected get scale(): number { @@ -194,6 +209,13 @@ class SVGDemoView extends PathfinderView { this.setDirty(); } + protected get worldTransform() { + const transform = glmatrix.mat4.create(); + glmatrix.mat4.fromTranslation(transform, [this.translation[0], this.translation[1], 0]); + glmatrix.mat4.scale(transform, transform, [this.scale, this.scale, 1.0]); + return transform; + } + private _scale: number; private appController: SVGDemoController; diff --git a/demo/client/src/text.ts b/demo/client/src/text.ts index b720f269..84a76022 100644 --- a/demo/client/src/text.ts +++ b/demo/client/src/text.ts @@ -380,7 +380,7 @@ class TextDemoView extends MonochromePathfinderView { transforms[pathID * 4 + 3] = atlasLocation[1] - bottom; } - this.atlasTransformBuffer.upload(this.gl, transforms); + this.pathTransformBufferTexture.upload(this.gl, transforms); } private createAtlasFramebuffer() { @@ -392,7 +392,7 @@ class TextDemoView extends MonochromePathfinderView { this.atlasDepthTexture); // Allow the antialiasing strategy to set up framebuffers as necessary. - this.antialiasingStrategy.setFramebufferSize(this, ATLAS_SIZE); + this.antialiasingStrategy.setFramebufferSize(this); } private setGlyphTexCoords() { @@ -551,6 +551,10 @@ class TextDemoView extends MonochromePathfinderView { this.appController.updateTimings(timings); } + protected get worldTransform() { + return glmatrix.mat4.create(); + } + atlasFramebuffer: WebGLFramebuffer; atlasDepthTexture: WebGLTexture; @@ -560,8 +564,6 @@ class TextDemoView extends MonochromePathfinderView { glyphTexCoordsBuffer: WebGLBuffer; glyphElementsBuffer: WebGLBuffer; - atlasTransformBuffer: PathfinderBufferTexture; - appController: TextDemoController; } diff --git a/demo/client/src/view.ts b/demo/client/src/view.ts index 29a0fbf8..7eea0e5c 100644 --- a/demo/client/src/view.ts +++ b/demo/client/src/view.ts @@ -60,7 +60,7 @@ export abstract class PathfinderView { const shaderSource = this.compileShaders(commonShaderSource, shaderSources); this.shaderPrograms = this.linkShaders(shaderSource); - this.atlasTransformBuffer = new PathfinderBufferTexture(this.gl, 'uPathTransform'); + this.pathTransformBufferTexture = new PathfinderBufferTexture(this.gl, 'uPathTransform'); this.pathColorsBufferTexture = new PathfinderBufferTexture(this.gl, 'uPathColors'); this.antialiasingStrategy = new NoAAStrategy(0); @@ -77,7 +77,6 @@ export abstract class PathfinderView { let canvas = this.canvas; this.antialiasingStrategy.init(this); - this.antialiasingStrategy.setFramebufferSize(this, this.destAllocatedSize); if (this.meshData != null) this.antialiasingStrategy.attachMeshes(this); @@ -233,14 +232,15 @@ export abstract class PathfinderView { // Draw the glyphs with the resolved atlas to the default framebuffer. this.compositeIfNecessary(); - // Finish timing, clear dirty bit and finish. + // Finish timing, clear dirty bit, and finish. this.finishTiming(); this.dirty = false; } private setTransformUniform(uniforms: UniformMap) { - const transform = this.antialiasingStrategy.transform(); - this.gl.uniformMatrix4fv(uniforms.uTransform, false, this.antialiasingStrategy.transform()); + const transform = glmatrix.mat4.create(); + glmatrix.mat4.mul(transform, this.worldTransform, this.antialiasingStrategy.transform); + this.gl.uniformMatrix4fv(uniforms.uTransform, false, transform); } private renderDirect() { @@ -275,7 +275,7 @@ export abstract class PathfinderView { this.setTransformUniform(directInteriorProgram.uniforms); this.setFramebufferSizeUniform(directInteriorProgram.uniforms); this.pathColorsBufferTexture.bind(this.gl, directInteriorProgram.uniforms, 0); - this.atlasTransformBuffer.bind(this.gl, directInteriorProgram.uniforms, 1); + this.pathTransformBufferTexture.bind(this.gl, directInteriorProgram.uniforms, 1); let indexCount = this.gl.getBufferParameter(this.gl.ELEMENT_ARRAY_BUFFER, this.gl.BUFFER_SIZE) / UINT32_SIZE; this.gl.drawElements(this.gl.TRIANGLES, indexCount, this.gl.UNSIGNED_INT, 0); @@ -326,7 +326,7 @@ export abstract class PathfinderView { this.setTransformUniform(directCurveProgram.uniforms); this.setFramebufferSizeUniform(directCurveProgram.uniforms); this.pathColorsBufferTexture.bind(this.gl, directCurveProgram.uniforms, 0); - this.atlasTransformBuffer.bind(this.gl, directCurveProgram.uniforms, 1); + this.pathTransformBufferTexture.bind(this.gl, directCurveProgram.uniforms, 1); indexCount = this.gl.getBufferParameter(this.gl.ELEMENT_ARRAY_BUFFER, this.gl.BUFFER_SIZE) / UINT32_SIZE; this.gl.drawElements(this.gl.TRIANGLES, indexCount, this.gl.UNSIGNED_INT, 0); @@ -437,6 +437,8 @@ export abstract class PathfinderView { protected abstract get scale(): number; protected abstract set scale(newScale: number); + protected abstract get worldTransform(): glmatrix.mat4; + protected antialiasingStrategy: AntialiasingStrategy; protected translation: glmatrix.vec2; @@ -461,7 +463,7 @@ export abstract class PathfinderView { meshes: PathfinderMeshBuffers; meshData: PathfinderMeshData; - atlasTransformBuffer: PathfinderBufferTexture; + pathTransformBufferTexture: PathfinderBufferTexture; protected pathColorsBufferTexture: PathfinderBufferTexture; private atlasRenderingTimerQuery: WebGLQuery;