diff --git a/demo/client/html/text-demo.html.hbs b/demo/client/html/text-demo.html.hbs index 25d43ddc..1336851e 100644 --- a/demo/client/html/text-demo.html.hbs +++ b/demo/client/html/text-demo.html.hbs @@ -37,6 +37,13 @@ +
+ +
diff --git a/demo/client/src/3d-demo.ts b/demo/client/src/3d-demo.ts index d5157076..074086fc 100644 --- a/demo/client/src/3d-demo.ts +++ b/demo/client/src/3d-demo.ts @@ -117,10 +117,12 @@ class ThreeDView extends PathfinderDemoView { this.pathTransformBufferTexture.upload(this.gl, pathTransforms); } - protected createAAStrategy(aaType: AntialiasingStrategyName, aaLevel: number): + protected createAAStrategy(aaType: AntialiasingStrategyName, + aaLevel: number, + subpixelAA: boolean): AntialiasingStrategy { if (aaType != 'ecaa') - return new (ANTIALIASING_STRATEGIES[aaType])(aaLevel); + return new (ANTIALIASING_STRATEGIES[aaType])(aaLevel, subpixelAA); throw new PathfinderError("Unsupported antialiasing type!"); } diff --git a/demo/client/src/aa-strategy.ts b/demo/client/src/aa-strategy.ts index cec2f4e1..26232591 100644 --- a/demo/client/src/aa-strategy.ts +++ b/demo/client/src/aa-strategy.ts @@ -44,7 +44,7 @@ export abstract class AntialiasingStrategy { } export class NoAAStrategy extends AntialiasingStrategy { - constructor(level: number) { + constructor(level: number, subpixelAA: boolean) { super(); this.framebufferSize = glmatrix.vec2.create(); } diff --git a/demo/client/src/app-controller.ts b/demo/client/src/app-controller.ts index 1765bf2e..b90b8ed8 100644 --- a/demo/client/src/app-controller.ts +++ b/demo/client/src/app-controller.ts @@ -93,7 +93,11 @@ export abstract class DemoAppController extends }); this.aaLevelSelect = document.getElementById('pf-aa-level-select') as HTMLSelectElement; + this.subpixelAASwitch = + document.getElementById('pf-subpixel-aa') as HTMLInputElement | null; this.aaLevelSelect.addEventListener('change', () => this.updateAALevel(), false); + if (this.subpixelAASwitch != null) + this.subpixelAASwitch.addEventListener('change', () => this.updateAALevel(), false); this.updateAALevel(); } @@ -102,7 +106,8 @@ export abstract class DemoAppController extends const aaValues = unwrapNull(/^([a-z-]+)(?:-([0-9]+))?$/.exec(selectedOption.value)); const aaType = aaValues[1] as AntialiasingStrategyName; const aaLevel = aaValues[2] === "" ? 1 : parseInt(aaValues[2]); - this.view.then(view => view.setAntialiasingOptions(aaType, aaLevel)); + const subpixelAA = this.subpixelAASwitch == null ? false : this.subpixelAASwitch.checked; + this.view.then(view => view.setAntialiasingOptions(aaType, aaLevel, subpixelAA)); } protected loadFile(event: Event) { @@ -151,6 +156,8 @@ export abstract class DemoAppController extends protected shaderSources: ShaderMap | null; private aaLevelSelect: HTMLSelectElement; + private subpixelAASwitch: HTMLInputElement | null; + private settingsCard: HTMLElement; private settingsButton: HTMLButtonElement; private settingsCloseButton: HTMLButtonElement; diff --git a/demo/client/src/ecaa-strategy.ts b/demo/client/src/ecaa-strategy.ts index cbe6ee80..f56a0757 100644 --- a/demo/client/src/ecaa-strategy.ts +++ b/demo/client/src/ecaa-strategy.ts @@ -26,7 +26,7 @@ interface UpperAndLower { } export abstract class ECAAStrategy extends AntialiasingStrategy { - constructor(level: number) { + constructor(level: number, subpixelAA: boolean) { super(); this.framebufferSize = glmatrix.vec2.create(); } diff --git a/demo/client/src/shader-loader.ts b/demo/client/src/shader-loader.ts index 69fe9220..df91e302 100644 --- a/demo/client/src/shader-loader.ts +++ b/demo/client/src/shader-loader.ts @@ -24,6 +24,7 @@ export const SHADER_NAMES: Array> = [ 'directInterior', 'direct3DCurve', 'direct3DInterior', + 'ssaaSubpixelResolve', 'ecaaEdgeDetect', 'ecaaCover', 'ecaaLine', @@ -54,6 +55,10 @@ const SHADER_URLS: ShaderMap = { vertex: "/glsl/gles2/direct-3d-interior.vs.glsl", fragment: "/glsl/gles2/direct-interior.fs.glsl", }, + ssaaSubpixelResolve: { + vertex: "/glsl/gles2/ssaa-subpixel-resolve.vs.glsl", + fragment: "/glsl/gles2/ssaa-subpixel-resolve.fs.glsl", + }, ecaaEdgeDetect: { vertex: "/glsl/gles2/ecaa-edge-detect.vs.glsl", fragment: "/glsl/gles2/ecaa-edge-detect.fs.glsl", @@ -90,6 +95,7 @@ export interface ShaderMap { directInterior: T; direct3DCurve: T; direct3DInterior: T; + ssaaSubpixelResolve: T; ecaaEdgeDetect: T; ecaaCover: T; ecaaLine: T; diff --git a/demo/client/src/ssaa-strategy.ts b/demo/client/src/ssaa-strategy.ts index fc12c253..b56e5182 100644 --- a/demo/client/src/ssaa-strategy.ts +++ b/demo/client/src/ssaa-strategy.ts @@ -16,9 +16,10 @@ import {unwrapNull} from './utils'; import {PathfinderDemoView} from './view'; export default class SSAAStrategy extends AntialiasingStrategy { - constructor(level: number) { + constructor(level: number, subpixelAA: boolean) { super(); this.level = level; + this.subpixelAA = subpixelAA; this.destFramebufferSize = glmatrix.vec2.create(); this.supersampledFramebufferSize = glmatrix.vec2.create(); } @@ -88,15 +89,22 @@ export default class SSAAStrategy extends AntialiasingStrategy { view.gl.disable(view.gl.DEPTH_TEST); // Set up the blit program VAO. - const blitProgram = view.shaderPrograms.blit; - view.gl.useProgram(blitProgram.program); - view.initQuadVAO(blitProgram.attributes); + let resolveProgram; + if (this.subpixelAA) + resolveProgram = view.shaderPrograms.ssaaSubpixelResolve; + else + resolveProgram = view.shaderPrograms.blit; + view.gl.useProgram(resolveProgram.program); + view.initQuadVAO(resolveProgram.attributes); // Resolve framebuffer. view.gl.activeTexture(view.gl.TEXTURE0); view.gl.bindTexture(view.gl.TEXTURE_2D, this.supersampledColorTexture); - view.gl.uniform1i(blitProgram.uniforms.uSource, 0); - view.setTransformAndTexScaleUniformsForDest(blitProgram.uniforms); + view.gl.uniform1i(resolveProgram.uniforms.uSource, 0); + view.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); } @@ -106,7 +114,7 @@ export default class SSAAStrategy extends AntialiasingStrategy { } private get supersampleScale(): glmatrix.vec2 { - return glmatrix.vec2.fromValues(2, this.level == 2 ? 1 : 2); + return glmatrix.vec2.fromValues(this.subpixelAA ? 3 : 2, this.level == 2 ? 1 : 2); } private usedSupersampledFramebufferSize(view: PathfinderDemoView): glmatrix.vec2 { @@ -116,6 +124,8 @@ export default class SSAAStrategy extends AntialiasingStrategy { } private level: number; + private subpixelAA: boolean; + private destFramebufferSize: glmatrix.vec2; private supersampledFramebufferSize: glmatrix.vec2; private supersampledColorTexture: WebGLTexture; diff --git a/demo/client/src/svg-demo.ts b/demo/client/src/svg-demo.ts index 1a14f6d9..076a1d66 100644 --- a/demo/client/src/svg-demo.ts +++ b/demo/client/src/svg-demo.ts @@ -212,9 +212,11 @@ class SVGDemoView extends PathfinderDemoView { this.pathTransformBufferTexture.upload(this.gl, pathTransforms); } - protected createAAStrategy(aaType: AntialiasingStrategyName, aaLevel: number): + protected createAAStrategy(aaType: AntialiasingStrategyName, + aaLevel: number, + subpixelAA: boolean): AntialiasingStrategy { - return new (ANTIALIASING_STRATEGIES[aaType])(aaLevel); + return new (ANTIALIASING_STRATEGIES[aaType])(aaLevel, subpixelAA); } protected compositeIfNecessary(): void {} diff --git a/demo/client/src/text-demo.ts b/demo/client/src/text-demo.ts index 890413f2..ef661073 100644 --- a/demo/client/src/text-demo.ts +++ b/demo/client/src/text-demo.ts @@ -73,7 +73,7 @@ const B_POSITION_SIZE: number = 8; const B_PATH_INDEX_SIZE: number = 2; -const ATLAS_SIZE: glmatrix.vec2 = glmatrix.vec2.fromValues(3072, 3072); +const ATLAS_SIZE: glmatrix.vec2 = glmatrix.vec2.fromValues(2048, 4096); declare global { interface Window { @@ -477,9 +477,11 @@ class TextDemoView extends MonochromePathfinderView { return this.appController.atlas.usedSize; } - protected createAAStrategy(aaType: AntialiasingStrategyName, aaLevel: number): + protected createAAStrategy(aaType: AntialiasingStrategyName, + aaLevel: number, + subpixelAA: boolean): AntialiasingStrategy { - return new (ANTIALIASING_STRATEGIES[aaType])(aaLevel); + return new (ANTIALIASING_STRATEGIES[aaType])(aaLevel, subpixelAA); } protected updateTimings(timings: Timings) { diff --git a/demo/client/src/view.ts b/demo/client/src/view.ts index 4f1892ea..5739e400 100644 --- a/demo/client/src/view.ts +++ b/demo/client/src/view.ts @@ -107,12 +107,14 @@ export abstract class PathfinderDemoView extends PathfinderView { this.pathTransformBufferTexture = new PathfinderBufferTexture(this.gl, 'uPathTransform'); this.pathColorsBufferTexture = new PathfinderBufferTexture(this.gl, 'uPathColors'); - this.antialiasingStrategy = new NoAAStrategy(0); + this.antialiasingStrategy = new NoAAStrategy(0, false); this.antialiasingStrategy.init(this); } - setAntialiasingOptions(aaType: AntialiasingStrategyName, aaLevel: number) { - this.antialiasingStrategy = this.createAAStrategy(aaType, aaLevel); + setAntialiasingOptions(aaType: AntialiasingStrategyName, + aaLevel: number, + subpixelAA: boolean) { + this.antialiasingStrategy = this.createAAStrategy(aaType, aaLevel, subpixelAA); let canvas = this.canvas; this.antialiasingStrategy.init(this); @@ -409,7 +411,9 @@ export abstract class PathfinderDemoView extends PathfinderView { this.gl.uniform2f(uniforms.uTexScale, usedSize[0], usedSize[1]); } - protected abstract createAAStrategy(aaType: AntialiasingStrategyName, aaLevel: number): + protected abstract createAAStrategy(aaType: AntialiasingStrategyName, + aaLevel: number, + subpixelAA: boolean): AntialiasingStrategy; protected abstract compositeIfNecessary(): void; diff --git a/shaders/gles2/ssaa-subpixel-resolve.fs.glsl b/shaders/gles2/ssaa-subpixel-resolve.fs.glsl new file mode 100644 index 00000000..77b10765 --- /dev/null +++ b/shaders/gles2/ssaa-subpixel-resolve.fs.glsl @@ -0,0 +1,24 @@ +// pathfinder/shaders/gles2/ssaa-subpixel-resolve.fs.glsl +// +// Copyright (c) 2017 The Pathfinder Project Developers. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +precision mediump float; + +uniform sampler2D uSource; +uniform ivec2 uSourceDimensions; + +varying vec2 vTexCoord; + +void main() { + float onePixel = 1.0 / float(uSourceDimensions.x); + gl_FragColor = vec4(texture2D(uSource, vec2(vTexCoord.s - onePixel, vTexCoord.t)).r, + texture2D(uSource, vec2(vTexCoord.s, vTexCoord.t)).r, + texture2D(uSource, vec2(vTexCoord.s + onePixel, vTexCoord.t)).r, + 1.0); +} diff --git a/shaders/gles2/ssaa-subpixel-resolve.vs.glsl b/shaders/gles2/ssaa-subpixel-resolve.vs.glsl new file mode 100644 index 00000000..e45dc8ac --- /dev/null +++ b/shaders/gles2/ssaa-subpixel-resolve.vs.glsl @@ -0,0 +1,24 @@ +// pathfinder/shaders/gles2/ssaa-subpixel-resolve.vs.glsl +// +// Copyright (c) 2017 The Pathfinder Project Developers. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +precision mediump float; + +uniform mat4 uTransform; +uniform vec2 uTexScale; + +attribute vec2 aPosition; +attribute vec2 aTexCoord; + +varying vec2 vTexCoord; + +void main() { + gl_Position = uTransform * vec4(aPosition, 0.0, 1.0); + vTexCoord = aTexCoord * uTexScale; +}