Add support for full 3D transforms, including rotation, to SVG in XCAA mode.
This commit is contained in:
parent
0e9144286e
commit
6942bb51ca
|
@ -21,7 +21,7 @@ import {CompositingOperation, RenderTaskType} from './render-task';
|
|||
import {ShaderMap} from './shader-loader';
|
||||
import {FLOAT32_SIZE, Range, UINT16_SIZE, UINT32_SIZE, unwrapNull, unwrapUndef} from './utils';
|
||||
import {RenderContext, Timings} from "./view";
|
||||
import {MCAAMulticolorStrategy} from './xcaa-strategy';
|
||||
import {ECAAMulticolorStrategy} from './xcaa-strategy';
|
||||
|
||||
const MAX_PATHS: number = 65535;
|
||||
|
||||
|
@ -232,6 +232,12 @@ export abstract class Renderer {
|
|||
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 {
|
||||
// FIXME(pcwalton): Lossy conversion from a 4x4 matrix to an ST matrix is ugly and fragile.
|
||||
// Refactor.
|
||||
|
@ -444,7 +450,7 @@ export abstract class Renderer {
|
|||
this.pathTransformBufferTextures[meshIndex]
|
||||
.bind(gl, directInteriorProgram.uniforms, 1);
|
||||
if (renderingMode === 'color-depth') {
|
||||
const strategy = antialiasingStrategy as MCAAMulticolorStrategy;
|
||||
const strategy = antialiasingStrategy as ECAAMulticolorStrategy;
|
||||
strategy.bindEdgeDepthTexture(gl, directInteriorProgram.uniforms, 2);
|
||||
}
|
||||
const coverInteriorRange = getMeshIndexRange(meshes.coverInteriorIndexRanges, pathRange);
|
||||
|
@ -486,7 +492,7 @@ export abstract class Renderer {
|
|||
this.setEmboldenAmountUniform(objectIndex, directCurveProgram.uniforms);
|
||||
this.pathTransformBufferTextures[meshIndex].bind(gl, directCurveProgram.uniforms, 1);
|
||||
if (renderingMode === 'color-depth') {
|
||||
const strategy = antialiasingStrategy as MCAAMulticolorStrategy;
|
||||
const strategy = antialiasingStrategy as ECAAMulticolorStrategy;
|
||||
strategy.bindEdgeDepthTexture(gl, directCurveProgram.uniforms, 2);
|
||||
}
|
||||
const coverCurveRange = getMeshIndexRange(meshes.coverCurveIndexRanges, pathRange);
|
||||
|
@ -687,12 +693,6 @@ export abstract class Renderer {
|
|||
gl.bufferData(gl.ARRAY_BUFFER, pathIDs, gl.STATIC_DRAW);
|
||||
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 {
|
||||
|
|
|
@ -147,11 +147,11 @@ const SHADER_URLS: ShaderMap<ShaderProgramURLs> = {
|
|||
},
|
||||
xcaaMultiEdgeMaskCurve: {
|
||||
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: {
|
||||
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: {
|
||||
fragment: "/glsl/gles2/xcaa-multi-resolve.fs.glsl",
|
||||
|
@ -198,10 +198,13 @@ export class PathfinderShaderProgram {
|
|||
readonly uniforms: UniformMap;
|
||||
readonly attributes: AttributeMap;
|
||||
readonly program: WebGLProgram;
|
||||
readonly programName: string;
|
||||
|
||||
constructor(gl: WebGLRenderingContext,
|
||||
programName: string,
|
||||
unlinkedShaderProgram: UnlinkedShaderProgram) {
|
||||
this.programName = programName;
|
||||
|
||||
this.program = expectNotNull(gl.createProgram(), "Failed to create shader program!");
|
||||
for (const compiledShader of Object.values(unlinkedShaderProgram))
|
||||
gl.attachShader(this.program, compiledShader);
|
||||
|
|
|
@ -25,7 +25,7 @@ import SSAAStrategy from "./ssaa-strategy";
|
|||
import {BUILTIN_SVG_URI, SVGLoader} from './svg-loader';
|
||||
import {panic, Range, unwrapNull} from './utils';
|
||||
import {DemoView, Timings} from './view';
|
||||
import {MCAAMulticolorStrategy, XCAAStrategy} from "./xcaa-strategy";
|
||||
import {ECAAMulticolorStrategy, XCAAStrategy} from "./xcaa-strategy";
|
||||
|
||||
const parseColor = require('parse-color');
|
||||
|
||||
|
@ -36,7 +36,7 @@ const DEFAULT_FILE: string = 'tiger';
|
|||
const ANTIALIASING_STRATEGIES: AntialiasingStrategyTable = {
|
||||
none: NoAAStrategy,
|
||||
ssaa: SSAAStrategy,
|
||||
xcaa: MCAAMulticolorStrategy,
|
||||
xcaa: ECAAMulticolorStrategy,
|
||||
};
|
||||
|
||||
interface AntialiasingStrategyTable {
|
||||
|
@ -82,7 +82,7 @@ class SVGDemoController extends DemoAppController<SVGDemoView> {
|
|||
private meshesReceived(): void {
|
||||
this.view.then(view => {
|
||||
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 {
|
||||
// TODO
|
||||
return new Float32Array(0);
|
||||
const loader = this.renderContext.appController.loader;
|
||||
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 {
|
||||
|
@ -203,13 +206,11 @@ class SVGDemoRenderer extends Renderer {
|
|||
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]);
|
||||
|
||||
if (!(this.antialiasingStrategy instanceof XCAAStrategy)) {
|
||||
const centerPoint = glmatrix.vec3.clone([canvas.width * 0.5, canvas.height * 0.5, 0.0]);
|
||||
glmatrix.mat4.translate(transform, transform, centerPoint);
|
||||
glmatrix.mat4.rotateZ(transform, transform, this.camera.rotationAngle);
|
||||
glmatrix.vec3.negate(centerPoint, centerPoint);
|
||||
glmatrix.mat4.translate(transform, transform, centerPoint);
|
||||
}
|
||||
|
||||
const translation = this.camera.translation;
|
||||
glmatrix.mat4.translate(transform, transform, [translation[0], translation[1], 0]);
|
||||
|
|
|
@ -74,7 +74,8 @@ export class SVGLoader {
|
|||
renderTasks: RenderTask[];
|
||||
pathInstances: SVGPath[];
|
||||
scale: number;
|
||||
bounds: glmatrix.vec4;
|
||||
pathBounds: glmatrix.vec4[];
|
||||
svgBounds: glmatrix.vec4;
|
||||
|
||||
private svg: SVGSVGElement;
|
||||
private fileData: ArrayBuffer;
|
||||
|
@ -86,8 +87,8 @@ export class SVGLoader {
|
|||
this.scale = 1.0;
|
||||
this.renderTasks = [];
|
||||
this.pathInstances = [];
|
||||
this.paths = [];
|
||||
this.bounds = glmatrix.vec4.create();
|
||||
this.pathBounds = [];
|
||||
this.svgBounds = glmatrix.vec4.create();
|
||||
this.svg = unwrapNull(document.getElementById('pf-svg')) as Element as SVGSVGElement;
|
||||
}
|
||||
|
||||
|
@ -133,10 +134,10 @@ export class SVGLoader {
|
|||
this.scanElement(this.svg);
|
||||
this.popTopRenderTaskIfEmpty();
|
||||
|
||||
let minX = 0, minY = 0, maxX = 0, maxY = 0;
|
||||
this.paths = [];
|
||||
|
||||
// Extract, normalize, and transform the path data.
|
||||
const svgBottomLeft = glmatrix.vec2.create(), svgTopRight = glmatrix.vec2.create();
|
||||
|
||||
for (const instance of this.pathInstances) {
|
||||
const element = instance.element;
|
||||
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, [this.scale, this.scale]);
|
||||
|
||||
const bottomLeft = glmatrix.vec2.create();
|
||||
const topRight = glmatrix.vec2.create();
|
||||
|
||||
const segments = element.getPathData({ normalize: true }).map(segment => {
|
||||
const newValues = _.flatMap(_.chunk(segment.values, 2), coords => {
|
||||
const point = glmatrix.vec2.create();
|
||||
glmatrix.vec2.transformMat2d(point, coords, ctm);
|
||||
|
||||
minX = Math.min(point[0], minX);
|
||||
minY = Math.min(point[1], minY);
|
||||
maxX = Math.max(point[0], maxX);
|
||||
maxY = Math.max(point[1], maxY);
|
||||
glmatrix.vec2.min(bottomLeft, bottomLeft, point);
|
||||
glmatrix.vec2.max(topRight, topRight, point);
|
||||
|
||||
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) {
|
||||
this.paths.push({ segments: segments, kind: 'Fill' });
|
||||
this.pathBounds.push(pathBounds);
|
||||
} else if (instance instanceof SVGStroke) {
|
||||
this.paths.push({
|
||||
kind: { Stroke: Math.max(HAIRLINE_STROKE_WIDTH, instance.width) },
|
||||
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 {
|
||||
|
|
|
@ -18,7 +18,7 @@ import {createFramebufferDepthTexture, setTextureParameters, UniformMap} from '.
|
|||
import {WebGLVertexArrayObject} from './gl-utils';
|
||||
import {B_QUAD_LOWER_INDICES_OFFSET, B_QUAD_SIZE, B_QUAD_UPPER_INDICES_OFFSET} from './meshes';
|
||||
import {Renderer} from './renderer';
|
||||
import {PathfinderShaderProgram} from './shader-loader';
|
||||
import {PathfinderShaderProgram, ShaderMap} from './shader-loader';
|
||||
import {computeStemDarkeningAmount} from './text';
|
||||
import {assert, FLOAT32_SIZE, lerp, Range, UINT16_SIZE, UINT32_SIZE, unwrapNull} from './utils';
|
||||
import {unwrapUndef} from './utils';
|
||||
|
@ -36,6 +36,8 @@ const DIRECTIONS: Direction[] = ['upper', 'lower'];
|
|||
export abstract class XCAAStrategy extends AntialiasingStrategy {
|
||||
abstract readonly directRenderingMode: DirectRenderingMode;
|
||||
|
||||
protected abstract get usesDilationTransforms(): boolean;
|
||||
|
||||
protected pathBoundsBufferTexture: PathfinderBufferTexture;
|
||||
|
||||
protected supersampledFramebufferSize: glmatrix.vec2;
|
||||
|
@ -225,7 +227,11 @@ export abstract class XCAAStrategy extends AntialiasingStrategy {
|
|||
const renderContext = renderer.renderContext;
|
||||
const gl = renderContext.gl;
|
||||
|
||||
if (this.usesDilationTransforms)
|
||||
renderer.setTransformSTUniform(uniforms, 0);
|
||||
else
|
||||
renderer.setTransformUniform(uniforms, 0);
|
||||
|
||||
gl.uniform2i(uniforms.uFramebufferSize,
|
||||
this.supersampledFramebufferSize[0],
|
||||
this.supersampledFramebufferSize[1]);
|
||||
|
@ -746,9 +752,12 @@ export abstract class MCAAStrategy extends XCAAStrategy {
|
|||
}
|
||||
}
|
||||
|
||||
export class ECAAStrategy extends XCAAStrategy {
|
||||
private lineVAO: WebGLVertexArrayObject;
|
||||
private curveVAO: WebGLVertexArrayObject;
|
||||
export abstract class ECAAStrategy extends XCAAStrategy {
|
||||
protected abstract get lineShaderProgramNames(): Array<keyof ShaderMap<void>>;
|
||||
protected abstract get curveShaderProgramNames(): Array<keyof ShaderMap<void>>;
|
||||
|
||||
private lineVAOs: Partial<ShaderMap<WebGLVertexArrayObject>>;
|
||||
private curveVAOs: Partial<ShaderMap<WebGLVertexArrayObject>>;
|
||||
|
||||
get directRenderingMode(): DirectRenderingMode {
|
||||
return 'none';
|
||||
|
@ -757,16 +766,23 @@ export class ECAAStrategy extends XCAAStrategy {
|
|||
attachMeshes(renderer: Renderer): void {
|
||||
super.attachMeshes(renderer);
|
||||
|
||||
this.createLineVAO(renderer);
|
||||
this.createCurveVAO(renderer);
|
||||
this.createLineVAOs(renderer);
|
||||
this.createCurveVAOs(renderer);
|
||||
}
|
||||
|
||||
antialiasObject(renderer: Renderer, objectIndex: number): void {
|
||||
super.antialiasObject(renderer, objectIndex);
|
||||
|
||||
// Antialias.
|
||||
this.antialiasLinesOfObject(renderer, objectIndex);
|
||||
this.antialiasCurvesOfObject(renderer, objectIndex);
|
||||
const shaderPrograms = renderer.renderContext.shaderPrograms;
|
||||
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 {
|
||||
|
@ -804,6 +820,64 @@ export class ECAAStrategy extends XCAAStrategy {
|
|||
gl.clear(gl.COLOR_BUFFER_BIT);
|
||||
}
|
||||
|
||||
protected antialiasLinesOfObjectWithProgram(renderer: Renderer,
|
||||
objectIndex: number,
|
||||
programName: keyof ShaderMap<void>):
|
||||
void {
|
||||
if (renderer.meshData == null)
|
||||
return;
|
||||
|
||||
const renderContext = renderer.renderContext;
|
||||
const gl = renderContext.gl;
|
||||
|
||||
const pathRange = renderer.pathRangeForObject(objectIndex);
|
||||
const meshIndex = renderer.meshIndexForObject(objectIndex);
|
||||
|
||||
const lineProgram = renderContext.shaderPrograms[programName];
|
||||
gl.useProgram(lineProgram.program);
|
||||
const uniforms = lineProgram.uniforms;
|
||||
this.setAAUniforms(renderer, uniforms, objectIndex);
|
||||
|
||||
const vao = this.lineVAOs[programName];
|
||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(vao);
|
||||
|
||||
// FIXME(pcwalton): Only render the appropriate instances.
|
||||
const count = renderer.meshData[meshIndex].segmentLineCount;
|
||||
renderContext.instancedArraysExt
|
||||
.drawElementsInstancedANGLE(gl.TRIANGLES, 6, gl.UNSIGNED_BYTE, 0, count);
|
||||
|
||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(null);
|
||||
}
|
||||
|
||||
protected antialiasCurvesOfObjectWithProgram(renderer: Renderer,
|
||||
objectIndex: number,
|
||||
programName: keyof ShaderMap<void>):
|
||||
void {
|
||||
if (renderer.meshData == null)
|
||||
return;
|
||||
|
||||
const renderContext = renderer.renderContext;
|
||||
const gl = renderContext.gl;
|
||||
|
||||
const pathRange = renderer.pathRangeForObject(objectIndex);
|
||||
const meshIndex = renderer.meshIndexForObject(objectIndex);
|
||||
|
||||
const curveProgram = renderContext.shaderPrograms[programName];
|
||||
gl.useProgram(curveProgram.program);
|
||||
const uniforms = curveProgram.uniforms;
|
||||
this.setAAUniforms(renderer, uniforms, objectIndex);
|
||||
|
||||
const vao = this.curveVAOs[programName];
|
||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(vao);
|
||||
|
||||
// FIXME(pcwalton): Only render the appropriate instances.
|
||||
const count = renderer.meshData[meshIndex].segmentCurveCount;
|
||||
renderContext.instancedArraysExt
|
||||
.drawElementsInstancedANGLE(gl.TRIANGLES, 6, gl.UNSIGNED_BYTE, 0, count);
|
||||
|
||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(null);
|
||||
}
|
||||
|
||||
private setBlendModeForAA(renderer: Renderer): void {
|
||||
const renderContext = renderer.renderContext;
|
||||
const gl = renderContext.gl;
|
||||
|
@ -813,14 +887,17 @@ export class ECAAStrategy extends XCAAStrategy {
|
|||
gl.enable(gl.BLEND);
|
||||
}
|
||||
|
||||
private createLineVAO(renderer: Renderer): void {
|
||||
if (renderer.meshes == null)
|
||||
private createLineVAOs(renderer: Renderer): void {
|
||||
if (renderer.meshes == null || renderer.meshData == null)
|
||||
return;
|
||||
|
||||
const renderContext = renderer.renderContext;
|
||||
const gl = renderContext.gl;
|
||||
|
||||
const lineProgram = renderContext.shaderPrograms.ecaaLine;
|
||||
this.lineVAOs = {};
|
||||
|
||||
for (const programName of this.lineShaderProgramNames) {
|
||||
const lineProgram = renderContext.shaderPrograms[programName];
|
||||
const attributes = lineProgram.attributes;
|
||||
|
||||
const vao = renderContext.vertexArrayObjectExt.createVertexArrayOES();
|
||||
|
@ -834,7 +911,12 @@ export class ECAAStrategy extends XCAAStrategy {
|
|||
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.aLeftPosition,
|
||||
2,
|
||||
gl.FLOAT,
|
||||
false,
|
||||
FLOAT32_SIZE * 4,
|
||||
0);
|
||||
gl.vertexAttribPointer(attributes.aRightPosition,
|
||||
2,
|
||||
gl.FLOAT,
|
||||
|
@ -843,6 +925,18 @@ export class ECAAStrategy extends XCAAStrategy {
|
|||
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,
|
||||
|
@ -857,34 +951,34 @@ export class ECAAStrategy extends XCAAStrategy {
|
|||
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);
|
||||
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;
|
||||
this.lineVAOs[programName] = vao;
|
||||
}
|
||||
}
|
||||
|
||||
private createCurveVAO(renderer: Renderer): void {
|
||||
if (renderer.meshes == null)
|
||||
private createCurveVAOs(renderer: Renderer): void {
|
||||
if (renderer.meshes == null || renderer.meshData == null)
|
||||
return;
|
||||
|
||||
const renderContext = renderer.renderContext;
|
||||
const gl = renderContext.gl;
|
||||
|
||||
const curveProgram = renderContext.shaderPrograms.ecaaCurve;
|
||||
this.curveVAOs = {};
|
||||
|
||||
for (const programName of this.curveShaderProgramNames) {
|
||||
const curveProgram = renderContext.shaderPrograms[programName];
|
||||
const attributes = curveProgram.attributes;
|
||||
|
||||
const vao = renderContext.vertexArrayObjectExt.createVertexArrayOES();
|
||||
|
@ -898,7 +992,12 @@ export class ECAAStrategy extends XCAAStrategy {
|
|||
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.aLeftPosition,
|
||||
2,
|
||||
gl.FLOAT,
|
||||
false,
|
||||
FLOAT32_SIZE * 6,
|
||||
0);
|
||||
gl.vertexAttribPointer(attributes.aControlPointPosition,
|
||||
2,
|
||||
gl.FLOAT,
|
||||
|
@ -913,94 +1012,63 @@ export class ECAAStrategy extends XCAAStrategy {
|
|||
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.aRightPosition, 1);
|
||||
renderContext.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aPathID, 1);
|
||||
renderContext.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aNormalAngles, 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.curveVAO = vao;
|
||||
this.curveVAOs[programName] = vao;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private antialiasLinesOfObject(renderer: Renderer, objectIndex: number): void {
|
||||
if (renderer.meshData == null)
|
||||
return;
|
||||
|
||||
const renderContext = renderer.renderContext;
|
||||
const gl = renderContext.gl;
|
||||
|
||||
const pathRange = renderer.pathRangeForObject(objectIndex);
|
||||
const meshIndex = renderer.meshIndexForObject(objectIndex);
|
||||
|
||||
this.setAAState(renderer);
|
||||
|
||||
const lineProgram = renderContext.shaderPrograms.ecaaLine;
|
||||
|
||||
gl.useProgram(lineProgram.program);
|
||||
const uniforms = lineProgram.uniforms;
|
||||
this.setAAUniforms(renderer, uniforms, objectIndex);
|
||||
|
||||
const vao = this.lineVAO;
|
||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(vao);
|
||||
|
||||
this.setBlendModeForAA(renderer);
|
||||
|
||||
// FIXME(pcwalton): Only render the appropriate instances.
|
||||
const count = renderer.meshData[meshIndex].segmentLineCount;
|
||||
renderContext.instancedArraysExt
|
||||
.drawElementsInstancedANGLE(gl.TRIANGLES, 6, gl.UNSIGNED_BYTE, 0, count);
|
||||
|
||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(null);
|
||||
export class ECAAMonochromeStrategy extends ECAAStrategy {
|
||||
protected get usesDilationTransforms(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
private antialiasCurvesOfObject(renderer: Renderer, objectIndex: number): void {
|
||||
if (renderer.meshData == null)
|
||||
return;
|
||||
protected get lineShaderProgramNames(): Array<keyof ShaderMap<void>> {
|
||||
return ['ecaaLine'];
|
||||
}
|
||||
|
||||
const renderContext = renderer.renderContext;
|
||||
const gl = renderContext.gl;
|
||||
|
||||
const pathRange = renderer.pathRangeForObject(objectIndex);
|
||||
const meshIndex = renderer.meshIndexForObject(objectIndex);
|
||||
|
||||
this.setAAState(renderer);
|
||||
|
||||
const curveProgram = renderContext.shaderPrograms.ecaaCurve;
|
||||
|
||||
gl.useProgram(curveProgram.program);
|
||||
const uniforms = curveProgram.uniforms;
|
||||
this.setAAUniforms(renderer, uniforms, objectIndex);
|
||||
|
||||
const vao = this.curveVAO;
|
||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(vao);
|
||||
|
||||
this.setBlendModeForAA(renderer);
|
||||
|
||||
// FIXME(pcwalton): Only render the appropriate instances.
|
||||
const count = renderer.meshData[meshIndex].segmentCurveCount;
|
||||
renderContext.instancedArraysExt
|
||||
.drawElementsInstancedANGLE(gl.TRIANGLES, 6, gl.UNSIGNED_BYTE, 0, count);
|
||||
|
||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(null);
|
||||
protected get curveShaderProgramNames(): Array<keyof ShaderMap<void>> {
|
||||
return ['ecaaCurve'];
|
||||
}
|
||||
}
|
||||
|
||||
export class MCAAMonochromeStrategy extends MCAAStrategy {
|
||||
protected get usesDilationTransforms(): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected getResolveProgram(renderContext: RenderContext): PathfinderShaderProgram {
|
||||
if (this.subpixelAA !== 'none')
|
||||
return renderContext.shaderPrograms.xcaaMonoSubpixelResolve;
|
||||
|
@ -1049,7 +1117,7 @@ export class AdaptiveMonochromeXCAAStrategy implements AntialiasingStrategy {
|
|||
|
||||
constructor(level: number, subpixelAA: SubpixelAAType) {
|
||||
this.mcaaStrategy = new MCAAMonochromeStrategy(level, subpixelAA);
|
||||
this.ecaaStrategy = new ECAAStrategy(level, subpixelAA);
|
||||
this.ecaaStrategy = new ECAAMonochromeStrategy(level, subpixelAA);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
bindEdgeDepthTexture(gl: WebGLRenderingContext, uniforms: UniformMap, textureUnit: number):
|
||||
|
@ -1136,7 +1216,7 @@ export class MCAAMulticolorStrategy extends MCAAStrategy {
|
|||
this.supersampledFramebufferSize[0],
|
||||
this.supersampledFramebufferSize[1]);
|
||||
|
||||
gl.colorMask(false, false, false, false);
|
||||
gl.colorMask(true, true, true, true);
|
||||
gl.depthMask(true);
|
||||
gl.depthFunc(gl.GREATER);
|
||||
gl.enable(gl.DEPTH_TEST);
|
||||
|
@ -1147,12 +1227,9 @@ export class MCAAMulticolorStrategy extends MCAAStrategy {
|
|||
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
||||
|
||||
// Perform edge masking.
|
||||
const edgeMaskLineProgram = renderer.renderContext.shaderPrograms.xcaaMultiEdgeMaskLine;
|
||||
gl.useProgram(edgeMaskLineProgram.program);
|
||||
this.antialiasLinesOfObjectWithProgram(renderer, objectIndex, edgeMaskLineProgram);
|
||||
const edgeMaskCurveProgram = renderer.renderContext.shaderPrograms.xcaaMultiEdgeMaskCurve;
|
||||
gl.useProgram(edgeMaskCurveProgram.program);
|
||||
this.antialiasCurvesOfObjectWithProgram(renderer, objectIndex, edgeMaskCurveProgram);
|
||||
gl.colorMask(false, false, false, false);
|
||||
this.antialiasLinesOfObjectWithProgram(renderer, objectIndex, 'xcaaMultiEdgeMaskLine');
|
||||
this.antialiasCurvesOfObjectWithProgram(renderer, objectIndex, 'xcaaMultiEdgeMaskCurve');
|
||||
|
||||
gl.colorMask(true, true, true, true);
|
||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(null);
|
||||
|
@ -1160,17 +1237,19 @@ export class MCAAMulticolorStrategy extends MCAAStrategy {
|
|||
|
||||
protected setCoverDepthState(renderer: Renderer): void {
|
||||
const renderContext = renderer.renderContext;
|
||||
renderContext.gl.depthMask(false);
|
||||
renderContext.gl.depthFunc(renderContext.gl.EQUAL);
|
||||
renderContext.gl.enable(renderContext.gl.DEPTH_TEST);
|
||||
const gl = renderContext.gl;
|
||||
|
||||
gl.depthMask(false);
|
||||
gl.depthFunc(gl.EQUAL);
|
||||
gl.enable(gl.DEPTH_TEST);
|
||||
}
|
||||
|
||||
protected clearForAA(renderer: Renderer): void {
|
||||
const renderContext = renderer.renderContext;
|
||||
/*const renderContext = renderer.renderContext;
|
||||
const gl = renderContext.gl;
|
||||
|
||||
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 {
|
||||
|
|
|
@ -425,8 +425,9 @@ fn partition_svg_paths(request: Json<PartitionSvgPathsRequest>)
|
|||
let mut path_buffer = PathBuffer::new();
|
||||
let mut paths = vec![];
|
||||
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 first_subpath_index = path_buffer.subpaths.len() as u32;
|
||||
|
@ -463,7 +464,9 @@ fn partition_svg_paths(request: Json<PartitionSvgPathsRequest>)
|
|||
|
||||
match path.kind {
|
||||
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) => {
|
||||
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 = MonotonicPathCommandStream::new(stream);
|
||||
library.push_segments((path_index + 1) as u16, stream.clone());
|
||||
path_buffer.add_stream(stream)
|
||||
}
|
||||
}
|
||||
|
@ -481,7 +485,7 @@ fn partition_svg_paths(request: Json<PartitionSvgPathsRequest>)
|
|||
}
|
||||
|
||||
// Partition the paths.
|
||||
let mut partitioner = Partitioner::new(MeshLibrary::new());
|
||||
let mut partitioner = Partitioner::new(library);
|
||||
partitioner.init_with_path_buffer(&path_buffer);
|
||||
let path_partitioning_result = PathPartitioningResult::compute(&mut partitioner, &paths);
|
||||
|
||||
|
|
|
@ -120,6 +120,7 @@ impl PathBuffer {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct PathBufferStream<'a> {
|
||||
path_buffer: &'a PathBuffer,
|
||||
endpoint_index: u32,
|
||||
|
|
|
@ -15,6 +15,7 @@ use std::mem;
|
|||
use PathCommand;
|
||||
use curve::Curve;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct MonotonicPathCommandStream<I> {
|
||||
inner: I,
|
||||
queue: ArrayVec<[PathCommand; 2]>,
|
||||
|
|
|
@ -160,48 +160,60 @@ bool computeECAAQuadPosition(out vec2 outPosition,
|
|||
vec2 quadPosition,
|
||||
ivec2 framebufferSize,
|
||||
vec4 localTransformST,
|
||||
vec4 globalTransformST,
|
||||
mat4 globalTransform,
|
||||
vec4 hints,
|
||||
vec4 bounds,
|
||||
float leftNormalAngle,
|
||||
float rightNormalAngle,
|
||||
vec2 emboldenAmount) {
|
||||
vec2 edgeBL = bounds.xy, edgeTL = bounds.xw, edgeTR = bounds.zw, edgeBR = bounds.zy;
|
||||
|
||||
leftPosition = dilatePosition(leftPosition, leftNormalAngle, emboldenAmount);
|
||||
rightPosition = dilatePosition(rightPosition, rightNormalAngle, emboldenAmount);
|
||||
|
||||
leftPosition = hintPosition(leftPosition, hints);
|
||||
rightPosition = hintPosition(rightPosition, hints);
|
||||
vec2 edgePosition = hintPosition(bounds.zw, hints);
|
||||
|
||||
leftPosition = transformVertexPositionST(leftPosition, 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);
|
||||
rightPosition = transformVertexPositionST(rightPosition, globalTransformST);
|
||||
edgePosition = transformVertexPositionST(edgePosition, globalTransformST);
|
||||
leftPosition = transformVertexPosition(leftPosition, globalTransform);
|
||||
rightPosition = transformVertexPosition(rightPosition, globalTransform);
|
||||
edgeBL = transformVertexPosition(edgeBL, globalTransform);
|
||||
edgeTL = transformVertexPosition(edgeTL, globalTransform);
|
||||
edgeBR = transformVertexPosition(edgeBR, globalTransform);
|
||||
edgeTR = transformVertexPosition(edgeTR, globalTransform);
|
||||
|
||||
leftPosition = convertClipToScreenSpace(leftPosition, framebufferSize);
|
||||
rightPosition = convertClipToScreenSpace(rightPosition, framebufferSize);
|
||||
edgePosition = convertClipToScreenSpace(edgePosition, framebufferSize);
|
||||
|
||||
float winding = sign(leftPosition.x - rightPosition.x);
|
||||
outWinding = winding;
|
||||
if (winding > 0.0) {
|
||||
vec2 tmp = leftPosition;
|
||||
leftPosition = rightPosition;
|
||||
rightPosition = tmp;
|
||||
}
|
||||
outWinding = winding;
|
||||
|
||||
if (rightPosition.x - leftPosition.x <= EPSILON) {
|
||||
outPosition = vec2(0.0);
|
||||
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),
|
||||
floor(min(leftPosition.y, rightPosition.y)),
|
||||
ceil(rightPosition.x),
|
||||
ceil(edgePosition.y));
|
||||
ceil(pathBottomY));
|
||||
|
||||
vec2 position = mix(roundedExtents.xy, roundedExtents.zw, quadPosition);
|
||||
outPosition = convertScreenToClipSpace(position, framebufferSize);
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
precision highp float;
|
||||
|
||||
uniform vec4 uTransformST;
|
||||
uniform mat4 uTransform;
|
||||
uniform vec4 uHints;
|
||||
uniform ivec2 uFramebufferSize;
|
||||
uniform ivec2 uPathTransformDimensions;
|
||||
|
@ -23,8 +23,8 @@ attribute vec2 aQuadPosition;
|
|||
attribute vec2 aLeftPosition;
|
||||
attribute vec2 aControlPointPosition;
|
||||
attribute vec2 aRightPosition;
|
||||
attribute vec3 aNormalAngles;
|
||||
attribute float aPathID;
|
||||
attribute vec3 aNormalAngles;
|
||||
|
||||
varying vec4 vEndpoints;
|
||||
varying vec2 vControlPoint;
|
||||
|
@ -52,7 +52,7 @@ void main() {
|
|||
aQuadPosition,
|
||||
uFramebufferSize,
|
||||
transform,
|
||||
uTransformST,
|
||||
uTransform,
|
||||
uHints,
|
||||
bounds,
|
||||
leftNormalAngle,
|
||||
|
@ -63,7 +63,7 @@ void main() {
|
|||
uEmboldenAmount);
|
||||
controlPointPosition = hintPosition(controlPointPosition, uHints);
|
||||
controlPointPosition = transformVertexPositionST(controlPointPosition, transform);
|
||||
controlPointPosition = transformVertexPositionST(controlPointPosition, uTransformST);
|
||||
controlPointPosition = transformVertexPosition(controlPointPosition, uTransform);
|
||||
controlPointPosition = convertClipToScreenSpace(controlPointPosition, uFramebufferSize);
|
||||
}
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
precision highp float;
|
||||
|
||||
uniform vec4 uTransformST;
|
||||
uniform mat4 uTransform;
|
||||
uniform vec4 uHints;
|
||||
uniform ivec2 uFramebufferSize;
|
||||
uniform ivec2 uPathTransformDimensions;
|
||||
|
@ -49,7 +49,7 @@ void main() {
|
|||
aQuadPosition,
|
||||
uFramebufferSize,
|
||||
transform,
|
||||
uTransformST,
|
||||
uTransform,
|
||||
uHints,
|
||||
bounds,
|
||||
leftNormalAngle,
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -21,7 +21,7 @@ void main() {
|
|||
float edgeDepth = texture2D(uAADepth, vTexCoord).r;
|
||||
int edgePathID = convertWindowDepthValueToPathIndex(edgeDepth);
|
||||
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_FragDepthEXT = edgeDepth;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue