Add support for full 3D transforms, including rotation, to SVG in XCAA mode.

This commit is contained in:
Patrick Walton 2017-11-22 21:10:51 -08:00
parent 0e9144286e
commit 6942bb51ca
14 changed files with 340 additions and 324 deletions

View File

@ -21,7 +21,7 @@ import {CompositingOperation, RenderTaskType} from './render-task';
import {ShaderMap} from './shader-loader'; import {ShaderMap} from './shader-loader';
import {FLOAT32_SIZE, Range, UINT16_SIZE, UINT32_SIZE, unwrapNull, unwrapUndef} from './utils'; import {FLOAT32_SIZE, Range, UINT16_SIZE, UINT32_SIZE, unwrapNull, unwrapUndef} from './utils';
import {RenderContext, Timings} from "./view"; import {RenderContext, Timings} from "./view";
import {MCAAMulticolorStrategy} from './xcaa-strategy'; import {ECAAMulticolorStrategy} from './xcaa-strategy';
const MAX_PATHS: number = 65535; const MAX_PATHS: number = 65535;
@ -232,6 +232,12 @@ export abstract class Renderer {
gl.uniform2f(uniforms.uTexScale, usedSize[0], usedSize[1]); gl.uniform2f(uniforms.uTexScale, usedSize[0], usedSize[1]);
} }
setTransformUniform(uniforms: UniformMap, objectIndex: number) {
const transform = glmatrix.mat4.clone(this.worldTransform);
glmatrix.mat4.mul(transform, transform, this.getModelviewTransform(objectIndex));
this.renderContext.gl.uniformMatrix4fv(uniforms.uTransform, false, transform);
}
setTransformSTUniform(uniforms: UniformMap, objectIndex: number): void { setTransformSTUniform(uniforms: UniformMap, objectIndex: number): void {
// FIXME(pcwalton): Lossy conversion from a 4x4 matrix to an ST matrix is ugly and fragile. // FIXME(pcwalton): Lossy conversion from a 4x4 matrix to an ST matrix is ugly and fragile.
// Refactor. // Refactor.
@ -444,7 +450,7 @@ export abstract class Renderer {
this.pathTransformBufferTextures[meshIndex] this.pathTransformBufferTextures[meshIndex]
.bind(gl, directInteriorProgram.uniforms, 1); .bind(gl, directInteriorProgram.uniforms, 1);
if (renderingMode === 'color-depth') { if (renderingMode === 'color-depth') {
const strategy = antialiasingStrategy as MCAAMulticolorStrategy; const strategy = antialiasingStrategy as ECAAMulticolorStrategy;
strategy.bindEdgeDepthTexture(gl, directInteriorProgram.uniforms, 2); strategy.bindEdgeDepthTexture(gl, directInteriorProgram.uniforms, 2);
} }
const coverInteriorRange = getMeshIndexRange(meshes.coverInteriorIndexRanges, pathRange); const coverInteriorRange = getMeshIndexRange(meshes.coverInteriorIndexRanges, pathRange);
@ -486,7 +492,7 @@ export abstract class Renderer {
this.setEmboldenAmountUniform(objectIndex, directCurveProgram.uniforms); this.setEmboldenAmountUniform(objectIndex, directCurveProgram.uniforms);
this.pathTransformBufferTextures[meshIndex].bind(gl, directCurveProgram.uniforms, 1); this.pathTransformBufferTextures[meshIndex].bind(gl, directCurveProgram.uniforms, 1);
if (renderingMode === 'color-depth') { if (renderingMode === 'color-depth') {
const strategy = antialiasingStrategy as MCAAMulticolorStrategy; const strategy = antialiasingStrategy as ECAAMulticolorStrategy;
strategy.bindEdgeDepthTexture(gl, directCurveProgram.uniforms, 2); strategy.bindEdgeDepthTexture(gl, directCurveProgram.uniforms, 2);
} }
const coverCurveRange = getMeshIndexRange(meshes.coverCurveIndexRanges, pathRange); const coverCurveRange = getMeshIndexRange(meshes.coverCurveIndexRanges, pathRange);
@ -687,12 +693,6 @@ export abstract class Renderer {
gl.bufferData(gl.ARRAY_BUFFER, pathIDs, gl.STATIC_DRAW); gl.bufferData(gl.ARRAY_BUFFER, pathIDs, gl.STATIC_DRAW);
gl.bindBuffer(gl.ARRAY_BUFFER, null); gl.bindBuffer(gl.ARRAY_BUFFER, null);
} }
private setTransformUniform(uniforms: UniformMap, objectIndex: number) {
const transform = glmatrix.mat4.clone(this.worldTransform);
glmatrix.mat4.mul(transform, transform, this.getModelviewTransform(objectIndex));
this.renderContext.gl.uniformMatrix4fv(uniforms.uTransform, false, transform);
}
} }
function getMeshIndexRange(indexRanges: Range[], pathRange: Range): Range { function getMeshIndexRange(indexRanges: Range[], pathRange: Range): Range {

View File

@ -147,11 +147,11 @@ const SHADER_URLS: ShaderMap<ShaderProgramURLs> = {
}, },
xcaaMultiEdgeMaskCurve: { xcaaMultiEdgeMaskCurve: {
fragment: "/glsl/gles2/xcaa-multi-edge-mask-curve.fs.glsl", fragment: "/glsl/gles2/xcaa-multi-edge-mask-curve.fs.glsl",
vertex: "/glsl/gles2/mcaa-curve.vs.glsl", vertex: "/glsl/gles2/ecaa-curve.vs.glsl",
}, },
xcaaMultiEdgeMaskLine: { xcaaMultiEdgeMaskLine: {
fragment: "/glsl/gles2/xcaa-multi-edge-mask-line.fs.glsl", fragment: "/glsl/gles2/xcaa-multi-edge-mask-line.fs.glsl",
vertex: "/glsl/gles2/mcaa-line.vs.glsl", vertex: "/glsl/gles2/ecaa-line.vs.glsl",
}, },
xcaaMultiResolve: { xcaaMultiResolve: {
fragment: "/glsl/gles2/xcaa-multi-resolve.fs.glsl", fragment: "/glsl/gles2/xcaa-multi-resolve.fs.glsl",
@ -198,10 +198,13 @@ export class PathfinderShaderProgram {
readonly uniforms: UniformMap; readonly uniforms: UniformMap;
readonly attributes: AttributeMap; readonly attributes: AttributeMap;
readonly program: WebGLProgram; readonly program: WebGLProgram;
readonly programName: string;
constructor(gl: WebGLRenderingContext, constructor(gl: WebGLRenderingContext,
programName: string, programName: string,
unlinkedShaderProgram: UnlinkedShaderProgram) { unlinkedShaderProgram: UnlinkedShaderProgram) {
this.programName = programName;
this.program = expectNotNull(gl.createProgram(), "Failed to create shader program!"); this.program = expectNotNull(gl.createProgram(), "Failed to create shader program!");
for (const compiledShader of Object.values(unlinkedShaderProgram)) for (const compiledShader of Object.values(unlinkedShaderProgram))
gl.attachShader(this.program, compiledShader); gl.attachShader(this.program, compiledShader);

View File

@ -25,7 +25,7 @@ import SSAAStrategy from "./ssaa-strategy";
import {BUILTIN_SVG_URI, SVGLoader} from './svg-loader'; import {BUILTIN_SVG_URI, SVGLoader} from './svg-loader';
import {panic, Range, unwrapNull} from './utils'; import {panic, Range, unwrapNull} from './utils';
import {DemoView, Timings} from './view'; import {DemoView, Timings} from './view';
import {MCAAMulticolorStrategy, XCAAStrategy} from "./xcaa-strategy"; import {ECAAMulticolorStrategy, XCAAStrategy} from "./xcaa-strategy";
const parseColor = require('parse-color'); const parseColor = require('parse-color');
@ -36,7 +36,7 @@ const DEFAULT_FILE: string = 'tiger';
const ANTIALIASING_STRATEGIES: AntialiasingStrategyTable = { const ANTIALIASING_STRATEGIES: AntialiasingStrategyTable = {
none: NoAAStrategy, none: NoAAStrategy,
ssaa: SSAAStrategy, ssaa: SSAAStrategy,
xcaa: MCAAMulticolorStrategy, xcaa: ECAAMulticolorStrategy,
}; };
interface AntialiasingStrategyTable { interface AntialiasingStrategyTable {
@ -82,7 +82,7 @@ class SVGDemoController extends DemoAppController<SVGDemoView> {
private meshesReceived(): void { private meshesReceived(): void {
this.view.then(view => { this.view.then(view => {
view.attachMeshes([this.meshes]); view.attachMeshes([this.meshes]);
view.initCameraBounds(this.loader.bounds); view.initCameraBounds(this.loader.svgBounds);
}); });
} }
} }
@ -157,8 +157,11 @@ class SVGDemoRenderer extends Renderer {
} }
pathBoundingRects(objectIndex: number): Float32Array { pathBoundingRects(objectIndex: number): Float32Array {
// TODO const loader = this.renderContext.appController.loader;
return new Float32Array(0); const boundingRectsBuffer = new Float32Array((loader.pathBounds.length + 1) * 4);
for (let pathIndex = 0; pathIndex < loader.pathBounds.length; pathIndex++)
boundingRectsBuffer.set(loader.pathBounds[pathIndex], (pathIndex + 1) * 4);
return boundingRectsBuffer;
} }
attachMeshes(meshes: PathfinderMeshData[]): void { attachMeshes(meshes: PathfinderMeshData[]): void {
@ -203,13 +206,11 @@ class SVGDemoRenderer extends Renderer {
glmatrix.mat4.translate(transform, transform, [-1.0, -1.0, 0.0]); glmatrix.mat4.translate(transform, transform, [-1.0, -1.0, 0.0]);
glmatrix.mat4.scale(transform, transform, [2.0 / canvas.width, 2.0 / canvas.height, 1.0]); glmatrix.mat4.scale(transform, transform, [2.0 / canvas.width, 2.0 / canvas.height, 1.0]);
if (!(this.antialiasingStrategy instanceof XCAAStrategy)) { const centerPoint = glmatrix.vec3.clone([canvas.width * 0.5, canvas.height * 0.5, 0.0]);
const centerPoint = glmatrix.vec3.clone([canvas.width * 0.5, canvas.height * 0.5, 0.0]); glmatrix.mat4.translate(transform, transform, centerPoint);
glmatrix.mat4.translate(transform, transform, centerPoint); glmatrix.mat4.rotateZ(transform, transform, this.camera.rotationAngle);
glmatrix.mat4.rotateZ(transform, transform, this.camera.rotationAngle); glmatrix.vec3.negate(centerPoint, centerPoint);
glmatrix.vec3.negate(centerPoint, centerPoint); glmatrix.mat4.translate(transform, transform, centerPoint);
glmatrix.mat4.translate(transform, transform, centerPoint);
}
const translation = this.camera.translation; const translation = this.camera.translation;
glmatrix.mat4.translate(transform, transform, [translation[0], translation[1], 0]); glmatrix.mat4.translate(transform, transform, [translation[0], translation[1], 0]);

View File

@ -74,7 +74,8 @@ export class SVGLoader {
renderTasks: RenderTask[]; renderTasks: RenderTask[];
pathInstances: SVGPath[]; pathInstances: SVGPath[];
scale: number; scale: number;
bounds: glmatrix.vec4; pathBounds: glmatrix.vec4[];
svgBounds: glmatrix.vec4;
private svg: SVGSVGElement; private svg: SVGSVGElement;
private fileData: ArrayBuffer; private fileData: ArrayBuffer;
@ -86,8 +87,8 @@ export class SVGLoader {
this.scale = 1.0; this.scale = 1.0;
this.renderTasks = []; this.renderTasks = [];
this.pathInstances = []; this.pathInstances = [];
this.paths = []; this.pathBounds = [];
this.bounds = glmatrix.vec4.create(); this.svgBounds = glmatrix.vec4.create();
this.svg = unwrapNull(document.getElementById('pf-svg')) as Element as SVGSVGElement; this.svg = unwrapNull(document.getElementById('pf-svg')) as Element as SVGSVGElement;
} }
@ -133,10 +134,10 @@ export class SVGLoader {
this.scanElement(this.svg); this.scanElement(this.svg);
this.popTopRenderTaskIfEmpty(); this.popTopRenderTaskIfEmpty();
let minX = 0, minY = 0, maxX = 0, maxY = 0;
this.paths = []; this.paths = [];
// Extract, normalize, and transform the path data. const svgBottomLeft = glmatrix.vec2.create(), svgTopRight = glmatrix.vec2.create();
for (const instance of this.pathInstances) { for (const instance of this.pathInstances) {
const element = instance.element; const element = instance.element;
const svgCTM = element.getCTM(); const svgCTM = element.getCTM();
@ -146,15 +147,16 @@ export class SVGLoader {
glmatrix.mat2d.scale(ctm, ctm, [1.0, -1.0]); glmatrix.mat2d.scale(ctm, ctm, [1.0, -1.0]);
glmatrix.mat2d.scale(ctm, ctm, [this.scale, this.scale]); glmatrix.mat2d.scale(ctm, ctm, [this.scale, this.scale]);
const bottomLeft = glmatrix.vec2.create();
const topRight = glmatrix.vec2.create();
const segments = element.getPathData({ normalize: true }).map(segment => { const segments = element.getPathData({ normalize: true }).map(segment => {
const newValues = _.flatMap(_.chunk(segment.values, 2), coords => { const newValues = _.flatMap(_.chunk(segment.values, 2), coords => {
const point = glmatrix.vec2.create(); const point = glmatrix.vec2.create();
glmatrix.vec2.transformMat2d(point, coords, ctm); glmatrix.vec2.transformMat2d(point, coords, ctm);
minX = Math.min(point[0], minX); glmatrix.vec2.min(bottomLeft, bottomLeft, point);
minY = Math.min(point[1], minY); glmatrix.vec2.max(topRight, topRight, point);
maxX = Math.max(point[0], maxX);
maxY = Math.max(point[1], maxY);
return [point[0], point[1]]; return [point[0], point[1]];
}); });
@ -164,17 +166,30 @@ export class SVGLoader {
}; };
}); });
const pathBounds = glmatrix.vec4.clone([
bottomLeft[0], bottomLeft[1],
topRight[0], topRight[1],
]);
glmatrix.vec2.min(svgBottomLeft, svgBottomLeft, bottomLeft);
glmatrix.vec2.max(svgTopRight, svgTopRight, topRight);
if (instance instanceof SVGFill) { if (instance instanceof SVGFill) {
this.paths.push({ segments: segments, kind: 'Fill' }); this.paths.push({ segments: segments, kind: 'Fill' });
this.pathBounds.push(pathBounds);
} else if (instance instanceof SVGStroke) { } else if (instance instanceof SVGStroke) {
this.paths.push({ this.paths.push({
kind: { Stroke: Math.max(HAIRLINE_STROKE_WIDTH, instance.width) }, kind: { Stroke: Math.max(HAIRLINE_STROKE_WIDTH, instance.width) },
segments: segments, segments: segments,
}); });
this.pathBounds.push(pathBounds);
} }
} }
this.bounds = glmatrix.vec4.clone([minX, minY, maxX, maxY]); this.svgBounds = glmatrix.vec4.clone([
svgBottomLeft[0], svgBottomLeft[1],
svgTopRight[0], svgTopRight[1],
]);
} }
private scanElement(element: Element): void { private scanElement(element: Element): void {

View File

@ -18,7 +18,7 @@ import {createFramebufferDepthTexture, setTextureParameters, UniformMap} from '.
import {WebGLVertexArrayObject} from './gl-utils'; import {WebGLVertexArrayObject} from './gl-utils';
import {B_QUAD_LOWER_INDICES_OFFSET, B_QUAD_SIZE, B_QUAD_UPPER_INDICES_OFFSET} from './meshes'; import {B_QUAD_LOWER_INDICES_OFFSET, B_QUAD_SIZE, B_QUAD_UPPER_INDICES_OFFSET} from './meshes';
import {Renderer} from './renderer'; import {Renderer} from './renderer';
import {PathfinderShaderProgram} from './shader-loader'; import {PathfinderShaderProgram, ShaderMap} from './shader-loader';
import {computeStemDarkeningAmount} from './text'; import {computeStemDarkeningAmount} from './text';
import {assert, FLOAT32_SIZE, lerp, Range, UINT16_SIZE, UINT32_SIZE, unwrapNull} from './utils'; import {assert, FLOAT32_SIZE, lerp, Range, UINT16_SIZE, UINT32_SIZE, unwrapNull} from './utils';
import {unwrapUndef} from './utils'; import {unwrapUndef} from './utils';
@ -36,6 +36,8 @@ const DIRECTIONS: Direction[] = ['upper', 'lower'];
export abstract class XCAAStrategy extends AntialiasingStrategy { export abstract class XCAAStrategy extends AntialiasingStrategy {
abstract readonly directRenderingMode: DirectRenderingMode; abstract readonly directRenderingMode: DirectRenderingMode;
protected abstract get usesDilationTransforms(): boolean;
protected pathBoundsBufferTexture: PathfinderBufferTexture; protected pathBoundsBufferTexture: PathfinderBufferTexture;
protected supersampledFramebufferSize: glmatrix.vec2; protected supersampledFramebufferSize: glmatrix.vec2;
@ -225,7 +227,11 @@ export abstract class XCAAStrategy extends AntialiasingStrategy {
const renderContext = renderer.renderContext; const renderContext = renderer.renderContext;
const gl = renderContext.gl; const gl = renderContext.gl;
renderer.setTransformSTUniform(uniforms, 0); if (this.usesDilationTransforms)
renderer.setTransformSTUniform(uniforms, 0);
else
renderer.setTransformUniform(uniforms, 0);
gl.uniform2i(uniforms.uFramebufferSize, gl.uniform2i(uniforms.uFramebufferSize,
this.supersampledFramebufferSize[0], this.supersampledFramebufferSize[0],
this.supersampledFramebufferSize[1]); this.supersampledFramebufferSize[1]);
@ -746,9 +752,12 @@ export abstract class MCAAStrategy extends XCAAStrategy {
} }
} }
export class ECAAStrategy extends XCAAStrategy { export abstract class ECAAStrategy extends XCAAStrategy {
private lineVAO: WebGLVertexArrayObject; protected abstract get lineShaderProgramNames(): Array<keyof ShaderMap<void>>;
private curveVAO: WebGLVertexArrayObject; protected abstract get curveShaderProgramNames(): Array<keyof ShaderMap<void>>;
private lineVAOs: Partial<ShaderMap<WebGLVertexArrayObject>>;
private curveVAOs: Partial<ShaderMap<WebGLVertexArrayObject>>;
get directRenderingMode(): DirectRenderingMode { get directRenderingMode(): DirectRenderingMode {
return 'none'; return 'none';
@ -757,16 +766,23 @@ export class ECAAStrategy extends XCAAStrategy {
attachMeshes(renderer: Renderer): void { attachMeshes(renderer: Renderer): void {
super.attachMeshes(renderer); super.attachMeshes(renderer);
this.createLineVAO(renderer); this.createLineVAOs(renderer);
this.createCurveVAO(renderer); this.createCurveVAOs(renderer);
} }
antialiasObject(renderer: Renderer, objectIndex: number): void { antialiasObject(renderer: Renderer, objectIndex: number): void {
super.antialiasObject(renderer, objectIndex); super.antialiasObject(renderer, objectIndex);
// Antialias. // Antialias.
this.antialiasLinesOfObject(renderer, objectIndex); const shaderPrograms = renderer.renderContext.shaderPrograms;
this.antialiasCurvesOfObject(renderer, objectIndex); this.setAAState(renderer);
this.setBlendModeForAA(renderer);
this.antialiasLinesOfObjectWithProgram(renderer,
objectIndex,
this.lineShaderProgramNames[0]);
this.antialiasCurvesOfObjectWithProgram(renderer,
objectIndex,
this.curveShaderProgramNames[0]);
} }
protected setAAUniforms(renderer: Renderer, uniforms: UniformMap, objectIndex: number): void { protected setAAUniforms(renderer: Renderer, uniforms: UniformMap, objectIndex: number): void {
@ -804,140 +820,10 @@ export class ECAAStrategy extends XCAAStrategy {
gl.clear(gl.COLOR_BUFFER_BIT); gl.clear(gl.COLOR_BUFFER_BIT);
} }
private setBlendModeForAA(renderer: Renderer): void { protected antialiasLinesOfObjectWithProgram(renderer: Renderer,
const renderContext = renderer.renderContext; objectIndex: number,
const gl = renderContext.gl; programName: keyof ShaderMap<void>):
void {
gl.blendEquation(gl.FUNC_ADD);
gl.blendFunc(gl.ONE, gl.ONE);
gl.enable(gl.BLEND);
}
private createLineVAO(renderer: Renderer): void {
if (renderer.meshes == null)
return;
const renderContext = renderer.renderContext;
const gl = renderContext.gl;
const lineProgram = renderContext.shaderPrograms.ecaaLine;
const attributes = lineProgram.attributes;
const vao = renderContext.vertexArrayObjectExt.createVertexArrayOES();
renderContext.vertexArrayObjectExt.bindVertexArrayOES(vao);
const lineVertexPositionsBuffer = renderer.meshes[0].segmentLines;
const linePathIDsBuffer = renderer.meshes[0].segmentLinePathIDs;
const lineNormalsBuffer = renderer.meshes[0].segmentLineNormals;
gl.useProgram(lineProgram.program);
gl.bindBuffer(gl.ARRAY_BUFFER, renderContext.quadPositionsBuffer);
gl.vertexAttribPointer(attributes.aQuadPosition, 2, gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ARRAY_BUFFER, lineVertexPositionsBuffer);
gl.vertexAttribPointer(attributes.aLeftPosition, 2, gl.FLOAT, false, FLOAT32_SIZE * 4, 0);
gl.vertexAttribPointer(attributes.aRightPosition,
2,
gl.FLOAT,
false,
FLOAT32_SIZE * 4,
FLOAT32_SIZE * 2);
gl.bindBuffer(gl.ARRAY_BUFFER, linePathIDsBuffer);
gl.vertexAttribPointer(attributes.aPathID, 1, gl.UNSIGNED_SHORT, false, 0, 0);
gl.bindBuffer(gl.ARRAY_BUFFER, lineNormalsBuffer);
gl.vertexAttribPointer(attributes.aLeftNormalAngle,
1,
gl.FLOAT,
false,
FLOAT32_SIZE * 2,
0);
gl.vertexAttribPointer(attributes.aRightNormalAngle,
1,
gl.FLOAT,
false,
FLOAT32_SIZE * 2,
FLOAT32_SIZE);
gl.enableVertexAttribArray(attributes.aQuadPosition);
gl.enableVertexAttribArray(attributes.aLeftPosition);
gl.enableVertexAttribArray(attributes.aRightPosition);
gl.enableVertexAttribArray(attributes.aPathID);
gl.enableVertexAttribArray(attributes.aLeftNormalAngle);
gl.enableVertexAttribArray(attributes.aRightNormalAngle);
renderContext.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aLeftPosition, 1);
renderContext.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aRightPosition, 1);
renderContext.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aPathID, 1);
renderContext.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aLeftNormalAngle, 1);
renderContext.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aRightNormalAngle, 1);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, renderContext.quadElementsBuffer);
renderContext.vertexArrayObjectExt.bindVertexArrayOES(null);
this.lineVAO = vao;
}
private createCurveVAO(renderer: Renderer): void {
if (renderer.meshes == null)
return;
const renderContext = renderer.renderContext;
const gl = renderContext.gl;
const curveProgram = renderContext.shaderPrograms.ecaaCurve;
const attributes = curveProgram.attributes;
const vao = renderContext.vertexArrayObjectExt.createVertexArrayOES();
renderContext.vertexArrayObjectExt.bindVertexArrayOES(vao);
const curveVertexPositionsBuffer = renderer.meshes[0].segmentCurves;
const curvePathIDsBuffer = renderer.meshes[0].segmentCurvePathIDs;
const curveNormalsBuffer = renderer.meshes[0].segmentCurveNormals;
gl.useProgram(curveProgram.program);
gl.bindBuffer(gl.ARRAY_BUFFER, renderContext.quadPositionsBuffer);
gl.vertexAttribPointer(attributes.aQuadPosition, 2, gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ARRAY_BUFFER, curveVertexPositionsBuffer);
gl.vertexAttribPointer(attributes.aLeftPosition, 2, gl.FLOAT, false, FLOAT32_SIZE * 6, 0);
gl.vertexAttribPointer(attributes.aControlPointPosition,
2,
gl.FLOAT,
false,
FLOAT32_SIZE * 6,
FLOAT32_SIZE * 2);
gl.vertexAttribPointer(attributes.aRightPosition,
2,
gl.FLOAT,
false,
FLOAT32_SIZE * 6,
FLOAT32_SIZE * 4);
gl.bindBuffer(gl.ARRAY_BUFFER, curvePathIDsBuffer);
gl.vertexAttribPointer(attributes.aPathID, 1, gl.UNSIGNED_SHORT, false, 0, 0);
gl.bindBuffer(gl.ARRAY_BUFFER, curveNormalsBuffer);
gl.vertexAttribPointer(attributes.aNormalAngles, 3, gl.FLOAT, false, FLOAT32_SIZE * 3, 0);
gl.enableVertexAttribArray(attributes.aQuadPosition);
gl.enableVertexAttribArray(attributes.aLeftPosition);
gl.enableVertexAttribArray(attributes.aControlPointPosition);
gl.enableVertexAttribArray(attributes.aRightPosition);
gl.enableVertexAttribArray(attributes.aPathID);
gl.enableVertexAttribArray(attributes.aNormalAngles);
renderContext.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aLeftPosition, 1);
renderContext.instancedArraysExt
.vertexAttribDivisorANGLE(attributes.aControlPointPosition, 1);
renderContext.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aRightPosition, 1);
renderContext.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aPathID, 1);
renderContext.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aNormalAngles, 1);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, renderContext.quadElementsBuffer);
renderContext.vertexArrayObjectExt.bindVertexArrayOES(null);
this.curveVAO = vao;
}
private antialiasLinesOfObject(renderer: Renderer, objectIndex: number): void {
if (renderer.meshData == null) if (renderer.meshData == null)
return; return;
@ -947,19 +833,14 @@ export class ECAAStrategy extends XCAAStrategy {
const pathRange = renderer.pathRangeForObject(objectIndex); const pathRange = renderer.pathRangeForObject(objectIndex);
const meshIndex = renderer.meshIndexForObject(objectIndex); const meshIndex = renderer.meshIndexForObject(objectIndex);
this.setAAState(renderer); const lineProgram = renderContext.shaderPrograms[programName];
const lineProgram = renderContext.shaderPrograms.ecaaLine;
gl.useProgram(lineProgram.program); gl.useProgram(lineProgram.program);
const uniforms = lineProgram.uniforms; const uniforms = lineProgram.uniforms;
this.setAAUniforms(renderer, uniforms, objectIndex); this.setAAUniforms(renderer, uniforms, objectIndex);
const vao = this.lineVAO; const vao = this.lineVAOs[programName];
renderContext.vertexArrayObjectExt.bindVertexArrayOES(vao); renderContext.vertexArrayObjectExt.bindVertexArrayOES(vao);
this.setBlendModeForAA(renderer);
// FIXME(pcwalton): Only render the appropriate instances. // FIXME(pcwalton): Only render the appropriate instances.
const count = renderer.meshData[meshIndex].segmentLineCount; const count = renderer.meshData[meshIndex].segmentLineCount;
renderContext.instancedArraysExt renderContext.instancedArraysExt
@ -968,7 +849,10 @@ export class ECAAStrategy extends XCAAStrategy {
renderContext.vertexArrayObjectExt.bindVertexArrayOES(null); renderContext.vertexArrayObjectExt.bindVertexArrayOES(null);
} }
private antialiasCurvesOfObject(renderer: Renderer, objectIndex: number): void { protected antialiasCurvesOfObjectWithProgram(renderer: Renderer,
objectIndex: number,
programName: keyof ShaderMap<void>):
void {
if (renderer.meshData == null) if (renderer.meshData == null)
return; return;
@ -978,19 +862,14 @@ export class ECAAStrategy extends XCAAStrategy {
const pathRange = renderer.pathRangeForObject(objectIndex); const pathRange = renderer.pathRangeForObject(objectIndex);
const meshIndex = renderer.meshIndexForObject(objectIndex); const meshIndex = renderer.meshIndexForObject(objectIndex);
this.setAAState(renderer); const curveProgram = renderContext.shaderPrograms[programName];
const curveProgram = renderContext.shaderPrograms.ecaaCurve;
gl.useProgram(curveProgram.program); gl.useProgram(curveProgram.program);
const uniforms = curveProgram.uniforms; const uniforms = curveProgram.uniforms;
this.setAAUniforms(renderer, uniforms, objectIndex); this.setAAUniforms(renderer, uniforms, objectIndex);
const vao = this.curveVAO; const vao = this.curveVAOs[programName];
renderContext.vertexArrayObjectExt.bindVertexArrayOES(vao); renderContext.vertexArrayObjectExt.bindVertexArrayOES(vao);
this.setBlendModeForAA(renderer);
// FIXME(pcwalton): Only render the appropriate instances. // FIXME(pcwalton): Only render the appropriate instances.
const count = renderer.meshData[meshIndex].segmentCurveCount; const count = renderer.meshData[meshIndex].segmentCurveCount;
renderContext.instancedArraysExt renderContext.instancedArraysExt
@ -998,9 +877,198 @@ export class ECAAStrategy extends XCAAStrategy {
renderContext.vertexArrayObjectExt.bindVertexArrayOES(null); renderContext.vertexArrayObjectExt.bindVertexArrayOES(null);
} }
private setBlendModeForAA(renderer: Renderer): void {
const renderContext = renderer.renderContext;
const gl = renderContext.gl;
gl.blendEquation(gl.FUNC_ADD);
gl.blendFunc(gl.ONE, gl.ONE);
gl.enable(gl.BLEND);
}
private createLineVAOs(renderer: Renderer): void {
if (renderer.meshes == null || renderer.meshData == null)
return;
const renderContext = renderer.renderContext;
const gl = renderContext.gl;
this.lineVAOs = {};
for (const programName of this.lineShaderProgramNames) {
const lineProgram = renderContext.shaderPrograms[programName];
const attributes = lineProgram.attributes;
const vao = renderContext.vertexArrayObjectExt.createVertexArrayOES();
renderContext.vertexArrayObjectExt.bindVertexArrayOES(vao);
const lineVertexPositionsBuffer = renderer.meshes[0].segmentLines;
const linePathIDsBuffer = renderer.meshes[0].segmentLinePathIDs;
const lineNormalsBuffer = renderer.meshes[0].segmentLineNormals;
gl.useProgram(lineProgram.program);
gl.bindBuffer(gl.ARRAY_BUFFER, renderContext.quadPositionsBuffer);
gl.vertexAttribPointer(attributes.aQuadPosition, 2, gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ARRAY_BUFFER, lineVertexPositionsBuffer);
gl.vertexAttribPointer(attributes.aLeftPosition,
2,
gl.FLOAT,
false,
FLOAT32_SIZE * 4,
0);
gl.vertexAttribPointer(attributes.aRightPosition,
2,
gl.FLOAT,
false,
FLOAT32_SIZE * 4,
FLOAT32_SIZE * 2);
gl.bindBuffer(gl.ARRAY_BUFFER, linePathIDsBuffer);
gl.vertexAttribPointer(attributes.aPathID, 1, gl.UNSIGNED_SHORT, false, 0, 0);
gl.enableVertexAttribArray(attributes.aQuadPosition);
gl.enableVertexAttribArray(attributes.aLeftPosition);
gl.enableVertexAttribArray(attributes.aRightPosition);
gl.enableVertexAttribArray(attributes.aPathID);
renderContext.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aLeftPosition, 1);
renderContext.instancedArraysExt
.vertexAttribDivisorANGLE(attributes.aRightPosition, 1);
renderContext.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aPathID, 1);
if (renderer.meshData[0].segmentLineNormals.byteLength > 0) {
gl.bindBuffer(gl.ARRAY_BUFFER, lineNormalsBuffer);
gl.vertexAttribPointer(attributes.aLeftNormalAngle,
1,
gl.FLOAT,
false,
FLOAT32_SIZE * 2,
0);
gl.vertexAttribPointer(attributes.aRightNormalAngle,
1,
gl.FLOAT,
false,
FLOAT32_SIZE * 2,
FLOAT32_SIZE);
gl.enableVertexAttribArray(attributes.aLeftNormalAngle);
gl.enableVertexAttribArray(attributes.aRightNormalAngle);
renderContext.instancedArraysExt
.vertexAttribDivisorANGLE(attributes.aLeftNormalAngle, 1);
renderContext.instancedArraysExt
.vertexAttribDivisorANGLE(attributes.aRightNormalAngle, 1);
}
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, renderContext.quadElementsBuffer);
renderContext.vertexArrayObjectExt.bindVertexArrayOES(null);
this.lineVAOs[programName] = vao;
}
}
private createCurveVAOs(renderer: Renderer): void {
if (renderer.meshes == null || renderer.meshData == null)
return;
const renderContext = renderer.renderContext;
const gl = renderContext.gl;
this.curveVAOs = {};
for (const programName of this.curveShaderProgramNames) {
const curveProgram = renderContext.shaderPrograms[programName];
const attributes = curveProgram.attributes;
const vao = renderContext.vertexArrayObjectExt.createVertexArrayOES();
renderContext.vertexArrayObjectExt.bindVertexArrayOES(vao);
const curveVertexPositionsBuffer = renderer.meshes[0].segmentCurves;
const curvePathIDsBuffer = renderer.meshes[0].segmentCurvePathIDs;
const curveNormalsBuffer = renderer.meshes[0].segmentCurveNormals;
gl.useProgram(curveProgram.program);
gl.bindBuffer(gl.ARRAY_BUFFER, renderContext.quadPositionsBuffer);
gl.vertexAttribPointer(attributes.aQuadPosition, 2, gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ARRAY_BUFFER, curveVertexPositionsBuffer);
gl.vertexAttribPointer(attributes.aLeftPosition,
2,
gl.FLOAT,
false,
FLOAT32_SIZE * 6,
0);
gl.vertexAttribPointer(attributes.aControlPointPosition,
2,
gl.FLOAT,
false,
FLOAT32_SIZE * 6,
FLOAT32_SIZE * 2);
gl.vertexAttribPointer(attributes.aRightPosition,
2,
gl.FLOAT,
false,
FLOAT32_SIZE * 6,
FLOAT32_SIZE * 4);
gl.bindBuffer(gl.ARRAY_BUFFER, curvePathIDsBuffer);
gl.vertexAttribPointer(attributes.aPathID, 1, gl.UNSIGNED_SHORT, false, 0, 0);
gl.enableVertexAttribArray(attributes.aQuadPosition);
gl.enableVertexAttribArray(attributes.aLeftPosition);
gl.enableVertexAttribArray(attributes.aControlPointPosition);
gl.enableVertexAttribArray(attributes.aRightPosition);
gl.enableVertexAttribArray(attributes.aPathID);
renderContext.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aLeftPosition, 1);
renderContext.instancedArraysExt
.vertexAttribDivisorANGLE(attributes.aControlPointPosition, 1);
renderContext.instancedArraysExt
.vertexAttribDivisorANGLE(attributes.aRightPosition, 1);
renderContext.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aPathID, 1);
if (renderer.meshData[0].segmentCurveNormals.byteLength > 0) {
gl.bindBuffer(gl.ARRAY_BUFFER, curveNormalsBuffer);
gl.vertexAttribPointer(attributes.aNormalAngles,
3,
gl.FLOAT,
false,
FLOAT32_SIZE * 3,
0);
gl.enableVertexAttribArray(attributes.aNormalAngles);
renderContext.instancedArraysExt
.vertexAttribDivisorANGLE(attributes.aNormalAngles, 1);
}
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, renderContext.quadElementsBuffer);
renderContext.vertexArrayObjectExt.bindVertexArrayOES(null);
this.curveVAOs[programName] = vao;
}
}
}
export class ECAAMonochromeStrategy extends ECAAStrategy {
protected get usesDilationTransforms(): boolean {
return false;
}
protected get lineShaderProgramNames(): Array<keyof ShaderMap<void>> {
return ['ecaaLine'];
}
protected get curveShaderProgramNames(): Array<keyof ShaderMap<void>> {
return ['ecaaCurve'];
}
} }
export class MCAAMonochromeStrategy extends MCAAStrategy { export class MCAAMonochromeStrategy extends MCAAStrategy {
protected get usesDilationTransforms(): boolean {
return true;
}
protected getResolveProgram(renderContext: RenderContext): PathfinderShaderProgram { protected getResolveProgram(renderContext: RenderContext): PathfinderShaderProgram {
if (this.subpixelAA !== 'none') if (this.subpixelAA !== 'none')
return renderContext.shaderPrograms.xcaaMonoSubpixelResolve; return renderContext.shaderPrograms.xcaaMonoSubpixelResolve;
@ -1049,7 +1117,7 @@ export class AdaptiveMonochromeXCAAStrategy implements AntialiasingStrategy {
constructor(level: number, subpixelAA: SubpixelAAType) { constructor(level: number, subpixelAA: SubpixelAAType) {
this.mcaaStrategy = new MCAAMonochromeStrategy(level, subpixelAA); this.mcaaStrategy = new MCAAMonochromeStrategy(level, subpixelAA);
this.ecaaStrategy = new ECAAStrategy(level, subpixelAA); this.ecaaStrategy = new ECAAMonochromeStrategy(level, subpixelAA);
} }
init(renderer: Renderer): void { init(renderer: Renderer): void {
@ -1106,7 +1174,19 @@ export class AdaptiveMonochromeXCAAStrategy implements AntialiasingStrategy {
} }
} }
export class MCAAMulticolorStrategy extends MCAAStrategy { export class ECAAMulticolorStrategy extends ECAAStrategy {
protected get usesDilationTransforms(): boolean {
return false;
}
protected get lineShaderProgramNames(): Array<keyof ShaderMap<void>> {
return ['ecaaLine', 'xcaaMultiEdgeMaskLine'];
}
protected get curveShaderProgramNames(): Array<keyof ShaderMap<void>> {
return ['ecaaCurve', 'xcaaMultiEdgeMaskCurve'];
}
private edgeMaskVAO: WebGLVertexArrayObject; private edgeMaskVAO: WebGLVertexArrayObject;
bindEdgeDepthTexture(gl: WebGLRenderingContext, uniforms: UniformMap, textureUnit: number): bindEdgeDepthTexture(gl: WebGLRenderingContext, uniforms: UniformMap, textureUnit: number):
@ -1136,7 +1216,7 @@ export class MCAAMulticolorStrategy extends MCAAStrategy {
this.supersampledFramebufferSize[0], this.supersampledFramebufferSize[0],
this.supersampledFramebufferSize[1]); this.supersampledFramebufferSize[1]);
gl.colorMask(false, false, false, false); gl.colorMask(true, true, true, true);
gl.depthMask(true); gl.depthMask(true);
gl.depthFunc(gl.GREATER); gl.depthFunc(gl.GREATER);
gl.enable(gl.DEPTH_TEST); gl.enable(gl.DEPTH_TEST);
@ -1147,12 +1227,9 @@ export class MCAAMulticolorStrategy extends MCAAStrategy {
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
// Perform edge masking. // Perform edge masking.
const edgeMaskLineProgram = renderer.renderContext.shaderPrograms.xcaaMultiEdgeMaskLine; gl.colorMask(false, false, false, false);
gl.useProgram(edgeMaskLineProgram.program); this.antialiasLinesOfObjectWithProgram(renderer, objectIndex, 'xcaaMultiEdgeMaskLine');
this.antialiasLinesOfObjectWithProgram(renderer, objectIndex, edgeMaskLineProgram); this.antialiasCurvesOfObjectWithProgram(renderer, objectIndex, 'xcaaMultiEdgeMaskCurve');
const edgeMaskCurveProgram = renderer.renderContext.shaderPrograms.xcaaMultiEdgeMaskCurve;
gl.useProgram(edgeMaskCurveProgram.program);
this.antialiasCurvesOfObjectWithProgram(renderer, objectIndex, edgeMaskCurveProgram);
gl.colorMask(true, true, true, true); gl.colorMask(true, true, true, true);
renderContext.vertexArrayObjectExt.bindVertexArrayOES(null); renderContext.vertexArrayObjectExt.bindVertexArrayOES(null);
@ -1160,17 +1237,19 @@ export class MCAAMulticolorStrategy extends MCAAStrategy {
protected setCoverDepthState(renderer: Renderer): void { protected setCoverDepthState(renderer: Renderer): void {
const renderContext = renderer.renderContext; const renderContext = renderer.renderContext;
renderContext.gl.depthMask(false); const gl = renderContext.gl;
renderContext.gl.depthFunc(renderContext.gl.EQUAL);
renderContext.gl.enable(renderContext.gl.DEPTH_TEST); gl.depthMask(false);
gl.depthFunc(gl.EQUAL);
gl.enable(gl.DEPTH_TEST);
} }
protected clearForAA(renderer: Renderer): void { protected clearForAA(renderer: Renderer): void {
const renderContext = renderer.renderContext; /*const renderContext = renderer.renderContext;
const gl = renderContext.gl; const gl = renderContext.gl;
gl.clearColor(0.0, 0.0, 0.0, 0.0); gl.clearColor(0.0, 0.0, 0.0, 0.0);
gl.clear(gl.COLOR_BUFFER_BIT); gl.clear(gl.COLOR_BUFFER_BIT);*/
} }
protected setAADepthState(renderer: Renderer): void { protected setAADepthState(renderer: Renderer): void {

View File

@ -425,8 +425,9 @@ fn partition_svg_paths(request: Json<PartitionSvgPathsRequest>)
let mut path_buffer = PathBuffer::new(); let mut path_buffer = PathBuffer::new();
let mut paths = vec![]; let mut paths = vec![];
let mut last_point = Point2D::zero(); let mut last_point = Point2D::zero();
let mut library = MeshLibrary::new();
for path in &request.paths { for (path_index, path) in request.paths.iter().enumerate() {
let mut stream = vec![]; let mut stream = vec![];
let first_subpath_index = path_buffer.subpaths.len() as u32; let first_subpath_index = path_buffer.subpaths.len() as u32;
@ -463,7 +464,9 @@ fn partition_svg_paths(request: Json<PartitionSvgPathsRequest>)
match path.kind { match path.kind {
PartitionSvgPathKind::Fill => { PartitionSvgPathKind::Fill => {
path_buffer.add_stream(MonotonicPathCommandStream::new(stream.into_iter())) let stream = MonotonicPathCommandStream::new(stream.into_iter());
library.push_segments((path_index + 1) as u16, stream.clone());
path_buffer.add_stream(stream)
} }
PartitionSvgPathKind::Stroke(stroke_width) => { PartitionSvgPathKind::Stroke(stroke_width) => {
let mut temp_path_buffer = PathBuffer::new(); let mut temp_path_buffer = PathBuffer::new();
@ -471,6 +474,7 @@ fn partition_svg_paths(request: Json<PartitionSvgPathsRequest>)
let stream = PathBufferStream::new(&temp_path_buffer); let stream = PathBufferStream::new(&temp_path_buffer);
let stream = MonotonicPathCommandStream::new(stream); let stream = MonotonicPathCommandStream::new(stream);
library.push_segments((path_index + 1) as u16, stream.clone());
path_buffer.add_stream(stream) path_buffer.add_stream(stream)
} }
} }
@ -481,7 +485,7 @@ fn partition_svg_paths(request: Json<PartitionSvgPathsRequest>)
} }
// Partition the paths. // Partition the paths.
let mut partitioner = Partitioner::new(MeshLibrary::new()); let mut partitioner = Partitioner::new(library);
partitioner.init_with_path_buffer(&path_buffer); partitioner.init_with_path_buffer(&path_buffer);
let path_partitioning_result = PathPartitioningResult::compute(&mut partitioner, &paths); let path_partitioning_result = PathPartitioningResult::compute(&mut partitioner, &paths);

View File

@ -120,6 +120,7 @@ impl PathBuffer {
} }
} }
#[derive(Clone)]
pub struct PathBufferStream<'a> { pub struct PathBufferStream<'a> {
path_buffer: &'a PathBuffer, path_buffer: &'a PathBuffer,
endpoint_index: u32, endpoint_index: u32,

View File

@ -15,6 +15,7 @@ use std::mem;
use PathCommand; use PathCommand;
use curve::Curve; use curve::Curve;
#[derive(Clone)]
pub struct MonotonicPathCommandStream<I> { pub struct MonotonicPathCommandStream<I> {
inner: I, inner: I,
queue: ArrayVec<[PathCommand; 2]>, queue: ArrayVec<[PathCommand; 2]>,

View File

@ -160,48 +160,60 @@ bool computeECAAQuadPosition(out vec2 outPosition,
vec2 quadPosition, vec2 quadPosition,
ivec2 framebufferSize, ivec2 framebufferSize,
vec4 localTransformST, vec4 localTransformST,
vec4 globalTransformST, mat4 globalTransform,
vec4 hints, vec4 hints,
vec4 bounds, vec4 bounds,
float leftNormalAngle, float leftNormalAngle,
float rightNormalAngle, float rightNormalAngle,
vec2 emboldenAmount) { vec2 emboldenAmount) {
vec2 edgeBL = bounds.xy, edgeTL = bounds.xw, edgeTR = bounds.zw, edgeBR = bounds.zy;
leftPosition = dilatePosition(leftPosition, leftNormalAngle, emboldenAmount); leftPosition = dilatePosition(leftPosition, leftNormalAngle, emboldenAmount);
rightPosition = dilatePosition(rightPosition, rightNormalAngle, emboldenAmount); rightPosition = dilatePosition(rightPosition, rightNormalAngle, emboldenAmount);
leftPosition = hintPosition(leftPosition, hints); leftPosition = hintPosition(leftPosition, hints);
rightPosition = hintPosition(rightPosition, hints); rightPosition = hintPosition(rightPosition, hints);
vec2 edgePosition = hintPosition(bounds.zw, hints);
leftPosition = transformVertexPositionST(leftPosition, localTransformST); leftPosition = transformVertexPositionST(leftPosition, localTransformST);
rightPosition = transformVertexPositionST(rightPosition, localTransformST); rightPosition = transformVertexPositionST(rightPosition, localTransformST);
edgePosition = transformVertexPositionST(edgePosition, localTransformST); edgeBL = transformVertexPositionST(edgeBL, localTransformST);
edgeTL = transformVertexPositionST(edgeTL, localTransformST);
edgeBR = transformVertexPositionST(edgeBR, localTransformST);
edgeTR = transformVertexPositionST(edgeTR, localTransformST);
leftPosition = transformVertexPositionST(leftPosition, globalTransformST); leftPosition = transformVertexPosition(leftPosition, globalTransform);
rightPosition = transformVertexPositionST(rightPosition, globalTransformST); rightPosition = transformVertexPosition(rightPosition, globalTransform);
edgePosition = transformVertexPositionST(edgePosition, globalTransformST); edgeBL = transformVertexPosition(edgeBL, globalTransform);
edgeTL = transformVertexPosition(edgeTL, globalTransform);
edgeBR = transformVertexPosition(edgeBR, globalTransform);
edgeTR = transformVertexPosition(edgeTR, globalTransform);
leftPosition = convertClipToScreenSpace(leftPosition, framebufferSize); leftPosition = convertClipToScreenSpace(leftPosition, framebufferSize);
rightPosition = convertClipToScreenSpace(rightPosition, framebufferSize); rightPosition = convertClipToScreenSpace(rightPosition, framebufferSize);
edgePosition = convertClipToScreenSpace(edgePosition, framebufferSize);
float winding = sign(leftPosition.x - rightPosition.x); float winding = sign(leftPosition.x - rightPosition.x);
outWinding = winding;
if (winding > 0.0) { if (winding > 0.0) {
vec2 tmp = leftPosition; vec2 tmp = leftPosition;
leftPosition = rightPosition; leftPosition = rightPosition;
rightPosition = tmp; rightPosition = tmp;
} }
outWinding = winding;
if (rightPosition.x - leftPosition.x <= EPSILON) { if (rightPosition.x - leftPosition.x <= EPSILON) {
outPosition = vec2(0.0); outPosition = vec2(0.0);
return false; return false;
} }
// Find the bottom of the path, and convert to clip space.
//
// FIXME(pcwalton): Speed this up somehow?
float pathBottomY = max(max(edgeBL.y, edgeBR.y), max(edgeTL.y, edgeTR.y));
pathBottomY = (pathBottomY + 1.0) * 0.5 * float(framebufferSize.y);
vec4 roundedExtents = vec4(floor(leftPosition.x), vec4 roundedExtents = vec4(floor(leftPosition.x),
floor(min(leftPosition.y, rightPosition.y)), floor(min(leftPosition.y, rightPosition.y)),
ceil(rightPosition.x), ceil(rightPosition.x),
ceil(edgePosition.y)); ceil(pathBottomY));
vec2 position = mix(roundedExtents.xy, roundedExtents.zw, quadPosition); vec2 position = mix(roundedExtents.xy, roundedExtents.zw, quadPosition);
outPosition = convertScreenToClipSpace(position, framebufferSize); outPosition = convertScreenToClipSpace(position, framebufferSize);

View File

@ -10,7 +10,7 @@
precision highp float; precision highp float;
uniform vec4 uTransformST; uniform mat4 uTransform;
uniform vec4 uHints; uniform vec4 uHints;
uniform ivec2 uFramebufferSize; uniform ivec2 uFramebufferSize;
uniform ivec2 uPathTransformDimensions; uniform ivec2 uPathTransformDimensions;
@ -23,8 +23,8 @@ attribute vec2 aQuadPosition;
attribute vec2 aLeftPosition; attribute vec2 aLeftPosition;
attribute vec2 aControlPointPosition; attribute vec2 aControlPointPosition;
attribute vec2 aRightPosition; attribute vec2 aRightPosition;
attribute vec3 aNormalAngles;
attribute float aPathID; attribute float aPathID;
attribute vec3 aNormalAngles;
varying vec4 vEndpoints; varying vec4 vEndpoints;
varying vec2 vControlPoint; varying vec2 vControlPoint;
@ -52,7 +52,7 @@ void main() {
aQuadPosition, aQuadPosition,
uFramebufferSize, uFramebufferSize,
transform, transform,
uTransformST, uTransform,
uHints, uHints,
bounds, bounds,
leftNormalAngle, leftNormalAngle,
@ -63,7 +63,7 @@ void main() {
uEmboldenAmount); uEmboldenAmount);
controlPointPosition = hintPosition(controlPointPosition, uHints); controlPointPosition = hintPosition(controlPointPosition, uHints);
controlPointPosition = transformVertexPositionST(controlPointPosition, transform); controlPointPosition = transformVertexPositionST(controlPointPosition, transform);
controlPointPosition = transformVertexPositionST(controlPointPosition, uTransformST); controlPointPosition = transformVertexPosition(controlPointPosition, uTransform);
controlPointPosition = convertClipToScreenSpace(controlPointPosition, uFramebufferSize); controlPointPosition = convertClipToScreenSpace(controlPointPosition, uFramebufferSize);
} }

View File

@ -10,7 +10,7 @@
precision highp float; precision highp float;
uniform vec4 uTransformST; uniform mat4 uTransform;
uniform vec4 uHints; uniform vec4 uHints;
uniform ivec2 uFramebufferSize; uniform ivec2 uFramebufferSize;
uniform ivec2 uPathTransformDimensions; uniform ivec2 uPathTransformDimensions;
@ -49,7 +49,7 @@ void main() {
aQuadPosition, aQuadPosition,
uFramebufferSize, uFramebufferSize,
transform, transform,
uTransformST, uTransform,
uHints, uHints,
bounds, bounds,
leftNormalAngle, leftNormalAngle,

View File

@ -1,79 +0,0 @@
// pathfinder/shaders/gles2/xcaa-edge-detect.fs.glsl
//
// Copyright (c) 2017 The Pathfinder Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
precision highp float;
uniform ivec2 uFramebufferSize;
uniform ivec2 uPathColorsDimensions;
uniform sampler2D uPathID;
uniform sampler2D uPathColors;
varying vec2 vTexCoord;
void checkFG(out vec2 fgPosition, out int fgPathID, vec2 queryPosition, int queryPathID) {
if (queryPathID > fgPathID) {
fgPosition = queryPosition;
fgPathID = queryPathID;
}
}
void updateMinMaxInt(inout ivec2 minMax, int value) {
if (value < minMax.x)
minMax.x = value;
if (value > minMax.y)
minMax.y = value;
}
ivec2 minMaxIVec4(ivec4 values) {
ivec2 minMax = ivec2(values.x);
updateMinMaxInt(minMax, values.y);
updateMinMaxInt(minMax, values.z);
updateMinMaxInt(minMax, values.w);
return minMax;
}
void main() {
// Unpack.
vec2 position = vTexCoord;
// Compute positions.
vec2 onePixel = 1.0 / vec2(uFramebufferSize);
vec2 positionL = position + vec2(-onePixel.x, 0.0);
vec2 positionR = position + vec2( onePixel.x, 0.0);
vec2 positionB = position + vec2(0.0, -onePixel.y);
vec2 positionT = position + vec2(0.0, onePixel.y);
// Determine the topmost and bottommost paths.
int centerPathID = unpackPathID(texture2D(uPathID, position).rg);
ivec4 neighborPathIDs = ivec4(unpackPathID(texture2D(uPathID, positionL).rg),
unpackPathID(texture2D(uPathID, positionR).rg),
unpackPathID(texture2D(uPathID, positionB).rg),
unpackPathID(texture2D(uPathID, positionT).rg));
ivec2 pathIDsBGFG = minMaxIVec4(neighborPathIDs);
// Determine the depth.
//
// If all colors are the same, avoid touching this pixel in any further passes.
float outDepth;
if (pathIDsBGFG.x == pathIDsBGFG.y)
outDepth = 1.0;
else
outDepth = convertPathIndexToWindowDepthValue(pathIDsBGFG.y);
// FIXME(pcwalton): Fetch the background color.
// FIXME(pcwalton): Output path ID for debugging. Switch to BG color.
//vec2 color = pathIDsBGFG.x == pathIDsBGFG.y ? vec2(1.0) : packPathID(pathIDsBGFG.y);
//vec4 color = fetchFloat4Data(uPathColors, pathIDsBGFG.x, uPathColorsDimensions);
// Output results.
//gl_FragColor = vec4(packPathID(pathIDsBGFG.x), 0.0, 1.0);
gl_FragColor = vec4(packPathID(pathIDsBGFG.x), packPathID(pathIDsBGFG.y));
gl_FragDepthEXT = outDepth;
}

View File

@ -1,21 +0,0 @@
// pathfinder/shaders/gles2/xcaa-edge-detect.vs.glsl
//
// Copyright (c) 2017 The Pathfinder Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
precision highp float;
attribute vec2 aPosition;
attribute vec2 aTexCoord;
varying vec2 vTexCoord;
void main() {
gl_Position = vec4(mix(vec2(-1.0), vec2(1.0), aPosition), 0.0, 1.0);
vTexCoord = aTexCoord;
}

View File

@ -21,7 +21,7 @@ void main() {
float edgeDepth = texture2D(uAADepth, vTexCoord).r; float edgeDepth = texture2D(uAADepth, vTexCoord).r;
int edgePathID = convertWindowDepthValueToPathIndex(edgeDepth); int edgePathID = convertWindowDepthValueToPathIndex(edgeDepth);
vec4 edgeColor = fetchFloat4Data(uPathColors, edgePathID, uPathColorsDimensions); vec4 edgeColor = fetchFloat4Data(uPathColors, edgePathID, uPathColorsDimensions);
float edgeAlpha = texture2D(uAAAlpha, vTexCoord).r; float edgeAlpha = abs(texture2D(uAAAlpha, vTexCoord).r);
gl_FragColor = vec4(edgeColor.rgb, edgeColor.a * edgeAlpha); gl_FragColor = vec4(edgeColor.rgb, edgeColor.a * edgeAlpha);
gl_FragDepthEXT = edgeDepth; gl_FragDepthEXT = edgeDepth;
} }