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;
+}