Use a single-pass pixel-snapping MCAA algorithm instead of a multipass
ECAA algorithm for multicolor SVG. This is much faster than both Skia and the previous XCAA algorithm while maintaining slightly higher quality than the latter. There are a couple of known issues: * Vertical inflection points of hairlines with very steep slopes can become very light or even drop out occasionally. I suspect this is due to floating point error. * Rarely, single columns of pixels can disappear from a mesh. Cause TBD. Besides these bugs, this technique can be cleaned up and probably made faster, but it's a sizable improvement as is.
This commit is contained in:
parent
5da56fea0b
commit
cfe72f486e
|
@ -18,7 +18,7 @@ import {DemoView} from './view';
|
|||
|
||||
export type AntialiasingStrategyName = 'none' | 'ssaa' | 'xcaa';
|
||||
|
||||
export type DirectRenderingMode = 'none' | 'color' | 'color-depth';
|
||||
export type DirectRenderingMode = 'none' | 'color';
|
||||
|
||||
export type SubpixelAAType = 'none' | 'medium';
|
||||
|
||||
|
@ -73,6 +73,9 @@ export abstract class AntialiasingStrategy {
|
|||
abstract antialiasObject(renderer: Renderer, objectIndex: number): void;
|
||||
|
||||
// Called after antialiasing each object.
|
||||
abstract finishAntialiasingObject(renderer: Renderer, objectIndex: number): void;
|
||||
|
||||
// Called before rendering each object directly.
|
||||
abstract resolveAAForObject(renderer: Renderer, objectIndex: number): void;
|
||||
|
||||
// Called after antialiasing.
|
||||
|
@ -175,6 +178,8 @@ export class NoAAStrategy extends AntialiasingStrategy {
|
|||
|
||||
antialiasObject(renderer: Renderer, objectIndex: number): void {}
|
||||
|
||||
finishAntialiasingObject(renderer: Renderer, objectIndex: number): void {}
|
||||
|
||||
resolveAAForObject(renderer: Renderer): void {}
|
||||
|
||||
resolve(pass: number, renderer: Renderer): void {}
|
||||
|
|
|
@ -76,6 +76,7 @@ const B_QUAD_FIELD_COUNT: number = B_QUAD_SIZE / UINT32_SIZE;
|
|||
|
||||
// FIXME(pcwalton): This duplicates information below in `MESH_TYPES`.
|
||||
const INDEX_SIZE: number = 4;
|
||||
const B_QUAD_VERTEX_POSITION_SIZE: number = 12 * 4;
|
||||
const B_VERTEX_POSITION_SIZE: number = 4 * 2;
|
||||
const EDGE_BOUNDING_BOX_VERTEX_POSITION_SIZE: number = 4 * 4;
|
||||
const EDGE_UPPER_LINE_VERTEX_POSITION_SIZE: number = 4 * 4;
|
||||
|
@ -86,6 +87,7 @@ const SEGMENT_LINE_SIZE: number = 4 * 4;
|
|||
const SEGMENT_CURVE_SIZE: number = 4 * 6;
|
||||
|
||||
const MESH_TYPES: Meshes<MeshBufferTypeDescriptor> = {
|
||||
bQuadVertexPositions: { type: 'Float32', size: 12 },
|
||||
bQuads: { type: 'Uint32', size: B_QUAD_FIELD_COUNT },
|
||||
bVertexLoopBlinnData: { type: 'Uint32', size: 1 },
|
||||
bVertexNormals: { type: 'Float32', size: 1 },
|
||||
|
@ -112,6 +114,7 @@ const MESH_TYPES: Meshes<MeshBufferTypeDescriptor> = {
|
|||
};
|
||||
|
||||
const BUFFER_TYPES: Meshes<BufferType> = {
|
||||
bQuadVertexPositions: 'ARRAY_BUFFER',
|
||||
bQuads: 'ARRAY_BUFFER',
|
||||
bVertexLoopBlinnData: 'ARRAY_BUFFER',
|
||||
bVertexNormals: 'ARRAY_BUFFER',
|
||||
|
@ -146,6 +149,7 @@ const MESH_LIBRARY_FOURCC: string = 'PFML';
|
|||
// Must match the FourCCs in `pathfinder_partitioner::mesh_library::MeshLibrary::serialize_into()`.
|
||||
const BUFFER_TYPE_FOURCCS: BufferTypeFourCCTable = {
|
||||
bqua: 'bQuads',
|
||||
bqvp: 'bQuadVertexPositions',
|
||||
bvlb: 'bVertexLoopBlinnData',
|
||||
bvno: 'bVertexNormals',
|
||||
bvpo: 'bVertexPositions',
|
||||
|
@ -166,6 +170,7 @@ const BUFFER_TYPE_FOURCCS: BufferTypeFourCCTable = {
|
|||
// `pathfinder_partitioner::mesh_library::MeshLibrary::serialize_into::write_path_ranges()`.
|
||||
const PATH_RANGE_TYPE_FOURCCS: PathRangeTypeFourCCTable = {
|
||||
bqua: 'bQuadPathRanges',
|
||||
bqvp: 'bQuadVertexPositionPathRanges',
|
||||
bver: 'bVertexPathRanges',
|
||||
cvci: 'coverCurveIndexRanges',
|
||||
cvii: 'coverInteriorIndexRanges',
|
||||
|
@ -180,6 +185,7 @@ const PATH_RANGE_TYPE_FOURCCS: PathRangeTypeFourCCTable = {
|
|||
|
||||
const RANGE_TO_COUNT_TABLE: RangeToCountTable = {
|
||||
bQuadPathRanges: 'bQuadCount',
|
||||
bQuadVertexPositionPathRanges: 'bQuadVertexPositionCount',
|
||||
bVertexPathRanges: 'bVertexCount',
|
||||
coverCurveIndexRanges: 'coverCurveCount',
|
||||
coverInteriorIndexRanges: 'coverInteriorCount',
|
||||
|
@ -205,6 +211,7 @@ const RANGE_TO_RANGE_BUFFER_TABLE: RangeToRangeBufferTable = {
|
|||
|
||||
const RANGE_KEYS: Array<keyof PathRanges> = [
|
||||
'bQuadPathRanges',
|
||||
'bQuadVertexPositionPathRanges',
|
||||
'bVertexPathRanges',
|
||||
'coverInteriorIndexRanges',
|
||||
'coverCurveIndexRanges',
|
||||
|
@ -221,6 +228,7 @@ type BufferType = 'ARRAY_BUFFER' | 'ELEMENT_ARRAY_BUFFER';
|
|||
|
||||
export interface Meshes<T> {
|
||||
readonly bQuads: T;
|
||||
readonly bQuadVertexPositions: T;
|
||||
readonly bVertexPositions: T;
|
||||
readonly bVertexLoopBlinnData: T;
|
||||
readonly bVertexNormals: T;
|
||||
|
@ -248,6 +256,7 @@ export interface Meshes<T> {
|
|||
|
||||
interface MeshDataCounts {
|
||||
readonly bQuadCount: number;
|
||||
readonly bQuadVertexPositionCount: number;
|
||||
readonly bVertexCount: number;
|
||||
readonly coverCurveCount: number;
|
||||
readonly coverInteriorCount: number;
|
||||
|
@ -262,6 +271,7 @@ interface MeshDataCounts {
|
|||
|
||||
interface PathRanges {
|
||||
bQuadPathRanges: Range[];
|
||||
bQuadVertexPositionPathRanges: Range[];
|
||||
bVertexPathRanges: Range[];
|
||||
coverInteriorIndexRanges: Range[];
|
||||
coverCurveIndexRanges: Range[];
|
||||
|
@ -276,6 +286,7 @@ interface PathRanges {
|
|||
|
||||
export class PathfinderMeshData implements Meshes<ArrayBuffer>, MeshDataCounts, PathRanges {
|
||||
readonly bQuads: ArrayBuffer;
|
||||
readonly bQuadVertexPositions: ArrayBuffer;
|
||||
readonly bVertexPositions: ArrayBuffer;
|
||||
readonly bVertexLoopBlinnData: ArrayBuffer;
|
||||
readonly bVertexNormals: ArrayBuffer;
|
||||
|
@ -292,6 +303,7 @@ export class PathfinderMeshData implements Meshes<ArrayBuffer>, MeshDataCounts,
|
|||
readonly segmentCurveNormals: ArrayBuffer;
|
||||
|
||||
readonly bQuadCount: number;
|
||||
readonly bQuadVertexPositionCount: number;
|
||||
readonly bVertexCount: number;
|
||||
readonly coverCurveCount: number;
|
||||
readonly coverInteriorCount: number;
|
||||
|
@ -313,6 +325,7 @@ export class PathfinderMeshData implements Meshes<ArrayBuffer>, MeshDataCounts,
|
|||
segmentLinePathIDs: ArrayBuffer;
|
||||
|
||||
bQuadPathRanges: Range[];
|
||||
bQuadVertexPositionPathRanges: Range[];
|
||||
bVertexPathRanges: Range[];
|
||||
coverInteriorIndexRanges: Range[];
|
||||
coverCurveIndexRanges: Range[];
|
||||
|
@ -356,6 +369,8 @@ export class PathfinderMeshData implements Meshes<ArrayBuffer>, MeshDataCounts,
|
|||
}
|
||||
|
||||
this.bQuadCount = this.bQuads.byteLength / B_QUAD_SIZE;
|
||||
this.bQuadVertexPositionCount = this.bQuadVertexPositions.byteLength /
|
||||
B_QUAD_VERTEX_POSITION_SIZE;
|
||||
this.bVertexCount = this.bVertexPositions.byteLength / B_VERTEX_POSITION_SIZE;
|
||||
this.coverCurveCount = this.coverCurveIndices.byteLength / INDEX_SIZE;
|
||||
this.coverInteriorCount = this.coverInteriorIndices.byteLength / INDEX_SIZE;
|
||||
|
@ -421,6 +436,16 @@ export class PathfinderMeshData implements Meshes<ArrayBuffer>, MeshDataCounts,
|
|||
const firstBVertexIndex = bVertexCopyResult.originalStartIndex;
|
||||
const lastBVertexIndex = bVertexCopyResult.originalEndIndex;
|
||||
|
||||
// Copy over B-quad vertex positions.
|
||||
copyVertices(['bQuadVertexPositions'],
|
||||
'bQuadVertexPositionPathRanges',
|
||||
expandedArrays,
|
||||
expandedRanges,
|
||||
originalBuffers,
|
||||
originalRanges,
|
||||
expandedPathID,
|
||||
originalPathID);
|
||||
|
||||
// Copy over edge data.
|
||||
copyVertices(['edgeBoundingBoxVertexPositions'],
|
||||
'edgeBoundingBoxRanges',
|
||||
|
@ -555,6 +580,7 @@ export class PathfinderMeshData implements Meshes<ArrayBuffer>, MeshDataCounts,
|
|||
|
||||
export class PathfinderMeshBuffers implements Meshes<WebGLBuffer>, PathRanges {
|
||||
readonly bQuads: WebGLBuffer;
|
||||
readonly bQuadVertexPositions: WebGLBuffer;
|
||||
readonly bVertexPositions: WebGLBuffer;
|
||||
readonly bVertexPathIDs: WebGLBuffer;
|
||||
readonly bVertexLoopBlinnData: WebGLBuffer;
|
||||
|
@ -579,6 +605,7 @@ export class PathfinderMeshBuffers implements Meshes<WebGLBuffer>, PathRanges {
|
|||
readonly segmentCurveNormals: WebGLBuffer;
|
||||
|
||||
readonly bQuadPathRanges: Range[];
|
||||
readonly bQuadVertexPositionPathRanges: Range[];
|
||||
readonly bVertexPathRanges: Range[];
|
||||
readonly coverInteriorIndexRanges: Range[];
|
||||
readonly coverCurveIndexRanges: Range[];
|
||||
|
|
|
@ -22,7 +22,6 @@ 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 {ECAAMulticolorStrategy} from './xcaa-strategy';
|
||||
|
||||
const MAX_PATHS: number = 65535;
|
||||
|
||||
|
@ -161,11 +160,14 @@ export abstract class Renderer {
|
|||
// Antialias.
|
||||
antialiasingStrategy.antialiasObject(this, objectIndex);
|
||||
|
||||
// Prepare for direct rendering.
|
||||
antialiasingStrategy.prepareToRenderObject(this, objectIndex);
|
||||
// Perform post-antialiasing tasks.
|
||||
antialiasingStrategy.finishAntialiasingObject(this, objectIndex);
|
||||
|
||||
// Perform direct rendering (Loop-Blinn).
|
||||
if (antialiasingStrategy.directRenderingMode !== 'none') {
|
||||
// Prepare for direct rendering.
|
||||
antialiasingStrategy.prepareToRenderObject(this, objectIndex);
|
||||
|
||||
// Clear.
|
||||
this.clearForDirectRendering(objectIndex);
|
||||
|
||||
|
@ -420,9 +422,6 @@ export abstract class Renderer {
|
|||
gl.depthMask(true);
|
||||
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
||||
break;
|
||||
case 'color-depth':
|
||||
gl.clear(gl.COLOR_BUFFER_BIT);
|
||||
break;
|
||||
case 'none':
|
||||
// Nothing to do.
|
||||
break;
|
||||
|
@ -496,10 +495,6 @@ export abstract class Renderer {
|
|||
this.pathTransformBufferTextures[meshIndex]
|
||||
.ext
|
||||
.bind(gl, directInteriorProgram.uniforms, 2);
|
||||
if (renderingMode === 'color-depth') {
|
||||
const strategy = antialiasingStrategy as ECAAMulticolorStrategy;
|
||||
strategy.bindEdgeDepthTexture(gl, directInteriorProgram.uniforms, 3);
|
||||
}
|
||||
const coverInteriorRange = getMeshIndexRange(meshes.coverInteriorIndexRanges, pathRange);
|
||||
if (!this.pathIDsAreInstanced) {
|
||||
gl.drawElements(gl.TRIANGLES,
|
||||
|
@ -516,7 +511,7 @@ export abstract class Renderer {
|
|||
}
|
||||
|
||||
// Set up direct curve state.
|
||||
gl.depthMask(renderingMode === 'color-depth');
|
||||
gl.depthMask(false);
|
||||
gl.enable(gl.BLEND);
|
||||
gl.blendEquation(gl.FUNC_ADD);
|
||||
gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE);
|
||||
|
@ -539,10 +534,6 @@ export abstract class Renderer {
|
|||
this.setEmboldenAmountUniform(objectIndex, directCurveProgram.uniforms);
|
||||
this.pathTransformBufferTextures[meshIndex].st.bind(gl, directCurveProgram.uniforms, 1);
|
||||
this.pathTransformBufferTextures[meshIndex].ext.bind(gl, directCurveProgram.uniforms, 2);
|
||||
if (renderingMode === 'color-depth') {
|
||||
const strategy = antialiasingStrategy as ECAAMulticolorStrategy;
|
||||
strategy.bindEdgeDepthTexture(gl, directCurveProgram.uniforms, 3);
|
||||
}
|
||||
const coverCurveRange = getMeshIndexRange(meshes.coverCurveIndexRanges, pathRange);
|
||||
if (!this.pathIDsAreInstanced) {
|
||||
gl.drawElements(gl.TRIANGLES,
|
||||
|
|
|
@ -27,15 +27,10 @@ export interface ShaderMap<T> {
|
|||
mcaaCover: T;
|
||||
mcaaLine: T;
|
||||
mcaaCurve: T;
|
||||
mcaaMulti: T;
|
||||
ssaaSubpixelResolve: T;
|
||||
xcaaMonoResolve: T;
|
||||
xcaaMonoSubpixelResolve: T;
|
||||
xcaaMultiDirectCurve: T;
|
||||
xcaaMultiDirectInterior: T;
|
||||
xcaaMultiEdgeMaskCurve: T;
|
||||
xcaaMultiEdgeMaskTransformedCurve: T;
|
||||
xcaaMultiEdgeMaskLine: T;
|
||||
xcaaMultiResolve: T;
|
||||
}
|
||||
|
||||
export interface UnlinkedShaderProgram {
|
||||
|
@ -57,17 +52,12 @@ export const SHADER_NAMES: Array<keyof ShaderMap<void>> = [
|
|||
'mcaaCover',
|
||||
'mcaaLine',
|
||||
'mcaaCurve',
|
||||
'mcaaMulti',
|
||||
'ecaaLine',
|
||||
'ecaaCurve',
|
||||
'ecaaTransformedCurve',
|
||||
'xcaaMonoResolve',
|
||||
'xcaaMonoSubpixelResolve',
|
||||
'xcaaMultiDirectCurve',
|
||||
'xcaaMultiDirectInterior',
|
||||
'xcaaMultiEdgeMaskCurve',
|
||||
'xcaaMultiEdgeMaskTransformedCurve',
|
||||
'xcaaMultiEdgeMaskLine',
|
||||
'xcaaMultiResolve',
|
||||
'demo3DDistantGlyph',
|
||||
'demo3DMonument',
|
||||
];
|
||||
|
@ -133,6 +123,10 @@ const SHADER_URLS: ShaderMap<ShaderProgramURLs> = {
|
|||
fragment: "/glsl/gles2/xcaa-line.fs.glsl",
|
||||
vertex: "/glsl/gles2/mcaa-line.vs.glsl",
|
||||
},
|
||||
mcaaMulti: {
|
||||
fragment: "/glsl/gles2/mcaa-multi.fs.glsl",
|
||||
vertex: "/glsl/gles2/mcaa-multi.vs.glsl",
|
||||
},
|
||||
ssaaSubpixelResolve: {
|
||||
fragment: "/glsl/gles2/ssaa-subpixel-resolve.fs.glsl",
|
||||
vertex: "/glsl/gles2/blit.vs.glsl",
|
||||
|
@ -145,30 +139,6 @@ const SHADER_URLS: ShaderMap<ShaderProgramURLs> = {
|
|||
fragment: "/glsl/gles2/xcaa-mono-subpixel-resolve.fs.glsl",
|
||||
vertex: "/glsl/gles2/xcaa-mono-subpixel-resolve.vs.glsl",
|
||||
},
|
||||
xcaaMultiDirectCurve: {
|
||||
fragment: "/glsl/gles2/xcaa-multi-direct-curve.fs.glsl",
|
||||
vertex: "/glsl/gles2/xcaa-multi-direct-curve.vs.glsl",
|
||||
},
|
||||
xcaaMultiDirectInterior: {
|
||||
fragment: "/glsl/gles2/xcaa-multi-direct-interior.fs.glsl",
|
||||
vertex: "/glsl/gles2/xcaa-multi-direct-interior.vs.glsl",
|
||||
},
|
||||
xcaaMultiEdgeMaskCurve: {
|
||||
fragment: "/glsl/gles2/xcaa-multi-edge-mask-curve.fs.glsl",
|
||||
vertex: "/glsl/gles2/ecaa-multi-edge-mask-curve.vs.glsl",
|
||||
},
|
||||
xcaaMultiEdgeMaskLine: {
|
||||
fragment: "/glsl/gles2/xcaa-multi-edge-mask-line.fs.glsl",
|
||||
vertex: "/glsl/gles2/ecaa-multi-edge-mask-line.vs.glsl",
|
||||
},
|
||||
xcaaMultiEdgeMaskTransformedCurve: {
|
||||
fragment: "/glsl/gles2/xcaa-multi-edge-mask-curve.fs.glsl",
|
||||
vertex: "/glsl/gles2/ecaa-multi-edge-mask-transformed-curve.vs.glsl",
|
||||
},
|
||||
xcaaMultiResolve: {
|
||||
fragment: "/glsl/gles2/xcaa-multi-resolve.fs.glsl",
|
||||
vertex: "/glsl/gles2/xcaa-multi-resolve.vs.glsl",
|
||||
},
|
||||
};
|
||||
|
||||
export interface ShaderProgramSource {
|
||||
|
|
|
@ -167,6 +167,8 @@ export default class SSAAStrategy extends AntialiasingStrategy {
|
|||
|
||||
antialiasObject(renderer: Renderer): void {}
|
||||
|
||||
finishAntialiasingObject(renderer: Renderer, objectIndex: number): void {}
|
||||
|
||||
resolveAAForObject(renderer: Renderer): void {}
|
||||
|
||||
resolve(pass: number, renderer: Renderer): void {
|
||||
|
|
|
@ -22,7 +22,7 @@ import SSAAStrategy from './ssaa-strategy';
|
|||
import {SVGLoader} from './svg-loader';
|
||||
import {Range} from './utils';
|
||||
import {RenderContext} from './view';
|
||||
import {ECAAMulticolorStrategy, XCAAStrategy} from './xcaa-strategy';
|
||||
import {MCAAMulticolorStrategy, XCAAStrategy} from './xcaa-strategy';
|
||||
|
||||
interface AntialiasingStrategyTable {
|
||||
none: typeof NoAAStrategy;
|
||||
|
@ -33,7 +33,7 @@ interface AntialiasingStrategyTable {
|
|||
const ANTIALIASING_STRATEGIES: AntialiasingStrategyTable = {
|
||||
none: NoAAStrategy,
|
||||
ssaa: SSAAStrategy,
|
||||
xcaa: ECAAMulticolorStrategy,
|
||||
xcaa: MCAAMulticolorStrategy,
|
||||
};
|
||||
|
||||
export abstract class SVGRenderer extends Renderer {
|
||||
|
@ -41,6 +41,14 @@ export abstract class SVGRenderer extends Renderer {
|
|||
|
||||
camera: OrthographicCamera;
|
||||
|
||||
get bgColor(): glmatrix.vec4 {
|
||||
return glmatrix.vec4.clone([1.0, 1.0, 1.0, 1.0]);
|
||||
}
|
||||
|
||||
get fgColor(): glmatrix.vec4 {
|
||||
return glmatrix.vec4.clone([0.0, 0.0, 0.0, 1.0]);
|
||||
}
|
||||
|
||||
get usesSTTransform(): boolean {
|
||||
return this.camera.usesSTTransform;
|
||||
}
|
||||
|
@ -150,14 +158,10 @@ export abstract class SVGRenderer extends Renderer {
|
|||
}
|
||||
|
||||
protected directCurveProgramName(): keyof ShaderMap<void> {
|
||||
if (this.antialiasingStrategy instanceof XCAAStrategy)
|
||||
return 'xcaaMultiDirectCurve';
|
||||
return 'directCurve';
|
||||
}
|
||||
|
||||
protected directInteriorProgramName(): keyof ShaderMap<void> {
|
||||
if (this.antialiasingStrategy instanceof XCAAStrategy)
|
||||
return 'xcaaMultiDirectInterior';
|
||||
return 'directInterior';
|
||||
}
|
||||
|
||||
|
|
|
@ -41,6 +41,7 @@ export abstract class XCAAStrategy extends AntialiasingStrategy {
|
|||
}
|
||||
|
||||
protected abstract get usesDilationTransforms(): boolean;
|
||||
protected abstract get usesAAFramebuffer(): boolean;
|
||||
|
||||
protected pathBoundsBufferTexture: PathfinderBufferTexture;
|
||||
|
||||
|
@ -49,11 +50,11 @@ export abstract class XCAAStrategy extends AntialiasingStrategy {
|
|||
|
||||
protected subpixelAA: SubpixelAAType;
|
||||
|
||||
protected resolveVAO: WebGLVertexArrayObject;
|
||||
protected resolveVAO: WebGLVertexArrayObject | null;
|
||||
|
||||
protected aaAlphaTexture: WebGLTexture;
|
||||
protected aaDepthTexture: WebGLTexture;
|
||||
protected aaFramebuffer: WebGLFramebuffer;
|
||||
protected aaAlphaTexture: WebGLTexture | null;
|
||||
protected aaDepthTexture: WebGLTexture | null;
|
||||
protected aaFramebuffer: WebGLFramebuffer | null;
|
||||
|
||||
protected renderTargetColorTextures: WebGLTexture[];
|
||||
protected renderTargetDepthTextures: WebGLTexture[];
|
||||
|
@ -98,23 +99,27 @@ export abstract class XCAAStrategy extends AntialiasingStrategy {
|
|||
|
||||
prepareForDirectRendering(renderer: Renderer): void {}
|
||||
|
||||
prepareToRenderObject(renderer: Renderer, objectIndex: number): void {
|
||||
finishAntialiasingObject(renderer: Renderer, objectIndex: number): void {
|
||||
const renderContext = renderer.renderContext;
|
||||
const gl = renderContext.gl;
|
||||
|
||||
this.initResolveFramebufferForObject(renderer, objectIndex);
|
||||
|
||||
const usedSize = this.supersampledUsedSize(renderer);
|
||||
gl.scissor(0, 0, usedSize[0], usedSize[1]);
|
||||
gl.enable(gl.SCISSOR_TEST);
|
||||
if (this.usesAAFramebuffer) {
|
||||
const usedSize = this.supersampledUsedSize(renderer);
|
||||
gl.scissor(0, 0, usedSize[0], usedSize[1]);
|
||||
gl.enable(gl.SCISSOR_TEST);
|
||||
|
||||
// Clear out the color and depth textures.
|
||||
gl.clearColor(1.0, 1.0, 1.0, 1.0);
|
||||
gl.clearDepth(0.0);
|
||||
gl.depthMask(true);
|
||||
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
||||
// Clear out the color and depth textures.
|
||||
gl.clearColor(1.0, 1.0, 1.0, 1.0);
|
||||
gl.clearDepth(0.0);
|
||||
gl.depthMask(true);
|
||||
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
||||
}
|
||||
}
|
||||
|
||||
prepareToRenderObject(renderer: Renderer, objectIndex: number): void {}
|
||||
|
||||
finishDirectlyRenderingObject(renderer: Renderer, objectIndex: number): void {
|
||||
// TODO(pcwalton)
|
||||
}
|
||||
|
@ -123,9 +128,6 @@ export abstract class XCAAStrategy extends AntialiasingStrategy {
|
|||
// Perform early preparations.
|
||||
this.createPathBoundsBufferTextureForObject(renderer, objectIndex);
|
||||
|
||||
// Mask edges if necessary.
|
||||
this.maskEdgesOfObjectIfNecessary(renderer, objectIndex);
|
||||
|
||||
// Set up antialiasing.
|
||||
this.prepareAA(renderer);
|
||||
|
||||
|
@ -137,6 +139,10 @@ export abstract class XCAAStrategy extends AntialiasingStrategy {
|
|||
const renderContext = renderer.renderContext;
|
||||
const gl = renderContext.gl;
|
||||
|
||||
const resolveProgram = this.getResolveProgram(renderContext);
|
||||
if (resolveProgram == null)
|
||||
return;
|
||||
|
||||
// Set state for ECAA resolve.
|
||||
const usedSize = renderer.destUsedSize;
|
||||
gl.scissor(0, 0, usedSize[0], usedSize[1]);
|
||||
|
@ -147,7 +153,6 @@ export abstract class XCAAStrategy extends AntialiasingStrategy {
|
|||
this.clearForResolve(renderer);
|
||||
|
||||
// Resolve.
|
||||
const resolveProgram = this.getResolveProgram(renderContext);
|
||||
gl.useProgram(resolveProgram.program);
|
||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(this.resolveVAO);
|
||||
gl.uniform2i(resolveProgram.uniforms.uFramebufferSize,
|
||||
|
@ -257,8 +262,8 @@ export abstract class XCAAStrategy extends AntialiasingStrategy {
|
|||
void {}
|
||||
|
||||
protected abstract clearForAA(renderer: Renderer): void;
|
||||
protected abstract getResolveProgram(renderContext: RenderContext): PathfinderShaderProgram;
|
||||
protected abstract maskEdgesOfObjectIfNecessary(renderer: Renderer, objectIndex: number): void;
|
||||
protected abstract getResolveProgram(renderContext: RenderContext):
|
||||
PathfinderShaderProgram | null;
|
||||
protected abstract setAADepthState(renderer: Renderer): void;
|
||||
protected abstract clearForResolve(renderer: Renderer): void;
|
||||
|
||||
|
@ -295,6 +300,13 @@ export abstract class XCAAStrategy extends AntialiasingStrategy {
|
|||
}
|
||||
|
||||
private initAAAlphaFramebuffer(renderer: Renderer): void {
|
||||
if (!this.usesAAFramebuffer) {
|
||||
this.aaAlphaTexture = null;
|
||||
this.aaDepthTexture = null;
|
||||
this.aaFramebuffer = null;
|
||||
return;
|
||||
}
|
||||
|
||||
const renderContext = renderer.renderContext;
|
||||
const gl = renderContext.gl;
|
||||
|
||||
|
@ -329,10 +341,13 @@ export abstract class XCAAStrategy extends AntialiasingStrategy {
|
|||
const renderContext = renderer.renderContext;
|
||||
const gl = renderContext.gl;
|
||||
|
||||
const resolveProgram = this.getResolveProgram(renderContext);
|
||||
if (resolveProgram == null)
|
||||
return;
|
||||
|
||||
this.resolveVAO = renderContext.vertexArrayObjectExt.createVertexArrayOES();
|
||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(this.resolveVAO);
|
||||
|
||||
const resolveProgram = this.getResolveProgram(renderContext);
|
||||
gl.useProgram(resolveProgram.program);
|
||||
renderContext.initQuadVAO(resolveProgram.attributes);
|
||||
|
||||
|
@ -348,15 +363,20 @@ export abstract class XCAAStrategy extends AntialiasingStrategy {
|
|||
}
|
||||
}
|
||||
|
||||
export abstract class MCAAStrategy extends XCAAStrategy {
|
||||
private coverVAO: WebGLVertexArrayObject;
|
||||
private lineVAOs: FastEdgeVAOs;
|
||||
private curveVAOs: FastEdgeVAOs;
|
||||
export class MCAAMonochromeStrategy extends XCAAStrategy {
|
||||
protected coverVAO: WebGLVertexArrayObject | null;
|
||||
|
||||
protected lineVAOs: FastEdgeVAOs;
|
||||
protected curveVAOs: FastEdgeVAOs;
|
||||
|
||||
protected get usesDilationTransforms(): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
attachMeshes(renderer: Renderer): void {
|
||||
super.attachMeshes(renderer);
|
||||
|
||||
this.createCoverVAO(renderer);
|
||||
this.createCoverVAOIfNecessary(renderer);
|
||||
this.createLineVAOs(renderer);
|
||||
this.createCurveVAOs(renderer);
|
||||
}
|
||||
|
@ -365,13 +385,58 @@ export abstract class MCAAStrategy extends XCAAStrategy {
|
|||
super.antialiasObject(renderer, objectIndex);
|
||||
|
||||
// Conservatively cover.
|
||||
this.coverObject(renderer, objectIndex);
|
||||
this.coverObjectIfNecessary(renderer, objectIndex);
|
||||
|
||||
// Antialias.
|
||||
this.antialiasLinesOfObject(renderer, objectIndex);
|
||||
this.antialiasCurvesOfObject(renderer, objectIndex);
|
||||
}
|
||||
|
||||
protected get usesAAFramebuffer(): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected getResolveProgram(renderContext: RenderContext): PathfinderShaderProgram {
|
||||
if (this.subpixelAA !== 'none')
|
||||
return renderContext.shaderPrograms.xcaaMonoSubpixelResolve;
|
||||
return renderContext.shaderPrograms.xcaaMonoResolve;
|
||||
}
|
||||
|
||||
protected clearForAA(renderer: Renderer): void {
|
||||
const renderContext = renderer.renderContext;
|
||||
const gl = renderContext.gl;
|
||||
|
||||
gl.clearColor(0.0, 0.0, 0.0, 0.0);
|
||||
gl.clearDepth(0.0);
|
||||
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
||||
}
|
||||
|
||||
protected setAADepthState(renderer: Renderer): void {
|
||||
const renderContext = renderer.renderContext;
|
||||
renderContext.gl.disable(renderContext.gl.DEPTH_TEST);
|
||||
}
|
||||
|
||||
protected clearForResolve(renderer: Renderer): void {
|
||||
const renderContext = renderer.renderContext;
|
||||
const gl = renderContext.gl;
|
||||
|
||||
gl.clearColor(1.0, 1.0, 1.0, 1.0);
|
||||
gl.clear(gl.COLOR_BUFFER_BIT);
|
||||
}
|
||||
|
||||
protected createCoverVAOIfNecessary(renderer: Renderer): void {
|
||||
this.coverVAO = renderer.renderContext.vertexArrayObjectExt.createVertexArrayOES();
|
||||
}
|
||||
|
||||
protected 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);
|
||||
}
|
||||
|
||||
protected prepareAA(renderer: Renderer): void {
|
||||
super.prepareAA(renderer);
|
||||
|
||||
|
@ -415,7 +480,7 @@ export abstract class MCAAStrategy extends XCAAStrategy {
|
|||
const vao = this.lineVAOs[direction];
|
||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(vao);
|
||||
|
||||
this.setBlendModeForAA(renderer, direction);
|
||||
this.setBlendModeForAA(renderer);
|
||||
gl.uniform1i(uniforms.uWinding, direction === 'upper' ? 1 : 0);
|
||||
|
||||
const indexRanges = {
|
||||
|
@ -431,6 +496,113 @@ export abstract class MCAAStrategy extends XCAAStrategy {
|
|||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(null);
|
||||
}
|
||||
|
||||
protected coverObjectIfNecessary(renderer: Renderer, objectIndex: number): void {
|
||||
if (renderer.meshes == null || renderer.meshData == null)
|
||||
return;
|
||||
|
||||
const renderContext = renderer.renderContext;
|
||||
const gl = renderContext.gl;
|
||||
|
||||
const pathRange = renderer.pathRangeForObject(objectIndex);
|
||||
const meshIndex = renderer.meshIndexForObject(objectIndex);
|
||||
|
||||
this.initCoverVAOForObject(renderer, objectIndex);
|
||||
|
||||
// Conservatively cover.
|
||||
const coverProgram = renderContext.shaderPrograms.mcaaCover;
|
||||
gl.useProgram(coverProgram.program);
|
||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(this.coverVAO);
|
||||
this.setAAUniforms(renderer, coverProgram.uniforms, objectIndex);
|
||||
|
||||
const bQuadRange = renderer.meshData[meshIndex].bQuadPathRanges;
|
||||
const count = calculateCountFromIndexRanges(pathRange, bQuadRange);
|
||||
|
||||
renderContext.instancedArraysExt
|
||||
.drawElementsInstancedANGLE(gl.TRIANGLES, 6, gl.UNSIGNED_BYTE, 0, count);
|
||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(null);
|
||||
}
|
||||
|
||||
protected initCurveVAOsForObject(renderer: Renderer, objectIndex: number): void {
|
||||
if (renderer.meshes == null || renderer.meshData == null)
|
||||
return;
|
||||
|
||||
const renderContext = renderer.renderContext;
|
||||
const gl = renderContext.gl;
|
||||
|
||||
const pathRange = renderer.pathRangeForObject(objectIndex);
|
||||
const meshIndex = renderer.meshIndexForObject(objectIndex);
|
||||
|
||||
const curveProgram = this.curveProgram(renderer);
|
||||
const attributes = curveProgram.attributes;
|
||||
|
||||
for (const direction of DIRECTIONS) {
|
||||
const vao = this.curveVAOs[direction];
|
||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(vao);
|
||||
|
||||
const curveVertexPositionsBuffer = {
|
||||
lower: renderer.meshes[meshIndex].edgeLowerCurveVertexPositions,
|
||||
upper: renderer.meshes[meshIndex].edgeUpperCurveVertexPositions,
|
||||
}[direction];
|
||||
const curvePathIDsBuffer = {
|
||||
lower: renderer.meshes[meshIndex].edgeLowerCurvePathIDs,
|
||||
upper: renderer.meshes[meshIndex].edgeUpperCurvePathIDs,
|
||||
}[direction];
|
||||
const curveIndexRanges = {
|
||||
lower: renderer.meshData[meshIndex].edgeLowerCurveIndexRanges,
|
||||
upper: renderer.meshData[meshIndex].edgeUpperCurveIndexRanges,
|
||||
}[direction];
|
||||
|
||||
const offset = calculateStartFromIndexRanges(pathRange, curveIndexRanges);
|
||||
|
||||
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,
|
||||
FLOAT32_SIZE * 6 * offset);
|
||||
gl.vertexAttribPointer(attributes.aControlPointPosition,
|
||||
2,
|
||||
gl.FLOAT,
|
||||
false,
|
||||
FLOAT32_SIZE * 6,
|
||||
FLOAT32_SIZE * 6 * offset + FLOAT32_SIZE * 2);
|
||||
gl.vertexAttribPointer(attributes.aRightPosition,
|
||||
2,
|
||||
gl.FLOAT,
|
||||
false,
|
||||
FLOAT32_SIZE * 6,
|
||||
FLOAT32_SIZE * 6 * offset + FLOAT32_SIZE * 4);
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, curvePathIDsBuffer);
|
||||
gl.vertexAttribPointer(attributes.aPathID,
|
||||
1,
|
||||
gl.UNSIGNED_SHORT,
|
||||
false,
|
||||
0,
|
||||
UINT16_SIZE * offset);
|
||||
|
||||
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);
|
||||
|
||||
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, renderContext.quadElementsBuffer);
|
||||
}
|
||||
|
||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(null);
|
||||
}
|
||||
|
||||
protected antialiasCurvesOfObjectWithProgram(renderer: Renderer,
|
||||
objectIndex: number,
|
||||
curveProgram: PathfinderShaderProgram):
|
||||
|
@ -454,7 +626,7 @@ export abstract class MCAAStrategy extends XCAAStrategy {
|
|||
const vao = this.curveVAOs[direction];
|
||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(vao);
|
||||
|
||||
this.setBlendModeForAA(renderer, direction);
|
||||
this.setBlendModeForAA(renderer);
|
||||
gl.uniform1i(uniforms.uWinding, direction === 'upper' ? 1 : 0);
|
||||
|
||||
const indexRanges = {
|
||||
|
@ -470,62 +642,12 @@ export abstract class MCAAStrategy extends XCAAStrategy {
|
|||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(null);
|
||||
}
|
||||
|
||||
private createCoverVAO(renderer: Renderer): void {
|
||||
this.coverVAO = renderer.renderContext.vertexArrayObjectExt.createVertexArrayOES();
|
||||
protected lineProgram(renderer: Renderer): PathfinderShaderProgram {
|
||||
return renderer.renderContext.shaderPrograms.mcaaLine;
|
||||
}
|
||||
|
||||
private initCoverVAOForObject(renderer: Renderer, objectIndex: number): void {
|
||||
if (renderer.meshes == null || renderer.meshData == null)
|
||||
return;
|
||||
|
||||
const renderContext = renderer.renderContext;
|
||||
const gl = renderContext.gl;
|
||||
|
||||
const pathRange = renderer.pathRangeForObject(objectIndex);
|
||||
const meshIndex = renderer.meshIndexForObject(objectIndex);
|
||||
|
||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(this.coverVAO);
|
||||
|
||||
const bQuadRanges = renderer.meshData[meshIndex].bQuadPathRanges;
|
||||
const offset = calculateStartFromIndexRanges(pathRange, bQuadRanges);
|
||||
|
||||
const coverProgram = renderContext.shaderPrograms.mcaaCover;
|
||||
const attributes = coverProgram.attributes;
|
||||
gl.useProgram(coverProgram.program);
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, renderContext.quadPositionsBuffer);
|
||||
gl.vertexAttribPointer(attributes.aQuadPosition, 2, gl.FLOAT, false, 0, 0);
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, renderer.meshes[meshIndex].edgeBoundingBoxVertexPositions);
|
||||
gl.vertexAttribPointer(attributes.aUpperLeftPosition,
|
||||
2,
|
||||
gl.FLOAT,
|
||||
false,
|
||||
FLOAT32_SIZE * 4,
|
||||
FLOAT32_SIZE * 4 * offset);
|
||||
gl.vertexAttribPointer(attributes.aLowerRightPosition,
|
||||
2,
|
||||
gl.FLOAT,
|
||||
false,
|
||||
FLOAT32_SIZE * 4,
|
||||
FLOAT32_SIZE * 4 * offset + FLOAT32_SIZE * 2);
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, renderer.meshes[meshIndex].edgeBoundingBoxPathIDs);
|
||||
gl.vertexAttribPointer(attributes.aPathID,
|
||||
1,
|
||||
gl.UNSIGNED_SHORT,
|
||||
false,
|
||||
0,
|
||||
UINT16_SIZE * offset);
|
||||
gl.enableVertexAttribArray(attributes.aQuadPosition);
|
||||
gl.enableVertexAttribArray(attributes.aUpperLeftPosition);
|
||||
gl.enableVertexAttribArray(attributes.aLowerRightPosition);
|
||||
gl.enableVertexAttribArray(attributes.aPathID);
|
||||
renderContext.instancedArraysExt
|
||||
.vertexAttribDivisorANGLE(attributes.aUpperLeftPosition, 1);
|
||||
renderContext.instancedArraysExt
|
||||
.vertexAttribDivisorANGLE(attributes.aLowerRightPosition, 1);
|
||||
renderContext.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aPathID, 1);
|
||||
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, renderContext.quadElementsBuffer);
|
||||
|
||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(null);
|
||||
protected curveProgram(renderer: Renderer): PathfinderShaderProgram {
|
||||
return renderer.renderContext.shaderPrograms.mcaaCurve;
|
||||
}
|
||||
|
||||
private createLineVAOs(renderer: Renderer): void {
|
||||
|
@ -547,7 +669,7 @@ export abstract class MCAAStrategy extends XCAAStrategy {
|
|||
const pathRange = renderer.pathRangeForObject(objectIndex);
|
||||
const meshIndex = renderer.meshIndexForObject(objectIndex);
|
||||
|
||||
const lineProgram = renderContext.shaderPrograms.mcaaLine;
|
||||
const lineProgram = this.lineProgram(renderer);
|
||||
const attributes = lineProgram.attributes;
|
||||
|
||||
for (const direction of DIRECTIONS) {
|
||||
|
@ -619,88 +741,11 @@ export abstract class MCAAStrategy extends XCAAStrategy {
|
|||
this.curveVAOs = vaos as FastEdgeVAOs;
|
||||
}
|
||||
|
||||
private initCurveVAOsForObject(renderer: Renderer, objectIndex: number): void {
|
||||
if (renderer.meshes == null || 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.mcaaCurve;
|
||||
const attributes = curveProgram.attributes;
|
||||
|
||||
for (const direction of DIRECTIONS) {
|
||||
const vao = this.curveVAOs[direction];
|
||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(vao);
|
||||
|
||||
const curveVertexPositionsBuffer = {
|
||||
lower: renderer.meshes[meshIndex].edgeLowerCurveVertexPositions,
|
||||
upper: renderer.meshes[meshIndex].edgeUpperCurveVertexPositions,
|
||||
}[direction];
|
||||
const curvePathIDsBuffer = {
|
||||
lower: renderer.meshes[meshIndex].edgeLowerCurvePathIDs,
|
||||
upper: renderer.meshes[meshIndex].edgeUpperCurvePathIDs,
|
||||
}[direction];
|
||||
const curveIndexRanges = {
|
||||
lower: renderer.meshData[meshIndex].edgeLowerCurveIndexRanges,
|
||||
upper: renderer.meshData[meshIndex].edgeUpperCurveIndexRanges,
|
||||
}[direction];
|
||||
|
||||
const offset = calculateStartFromIndexRanges(pathRange, curveIndexRanges);
|
||||
|
||||
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,
|
||||
FLOAT32_SIZE * 6 * offset);
|
||||
gl.vertexAttribPointer(attributes.aControlPointPosition,
|
||||
2,
|
||||
gl.FLOAT,
|
||||
false,
|
||||
FLOAT32_SIZE * 6,
|
||||
FLOAT32_SIZE * 6 * offset + FLOAT32_SIZE * 2);
|
||||
gl.vertexAttribPointer(attributes.aRightPosition,
|
||||
2,
|
||||
gl.FLOAT,
|
||||
false,
|
||||
FLOAT32_SIZE * 6,
|
||||
FLOAT32_SIZE * 6 * offset + FLOAT32_SIZE * 4);
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, curvePathIDsBuffer);
|
||||
gl.vertexAttribPointer(attributes.aPathID,
|
||||
1,
|
||||
gl.UNSIGNED_SHORT,
|
||||
false,
|
||||
0,
|
||||
UINT16_SIZE * offset);
|
||||
|
||||
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);
|
||||
|
||||
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, renderContext.quadElementsBuffer);
|
||||
}
|
||||
|
||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(null);
|
||||
get directRenderingMode(): DirectRenderingMode {
|
||||
return 'none';
|
||||
}
|
||||
|
||||
private coverObject(renderer: Renderer, objectIndex: number): void {
|
||||
private initCoverVAOForObject(renderer: Renderer, objectIndex: number): void {
|
||||
if (renderer.meshes == null || renderer.meshData == null)
|
||||
return;
|
||||
|
||||
|
@ -710,36 +755,55 @@ export abstract class MCAAStrategy extends XCAAStrategy {
|
|||
const pathRange = renderer.pathRangeForObject(objectIndex);
|
||||
const meshIndex = renderer.meshIndexForObject(objectIndex);
|
||||
|
||||
this.initCoverVAOForObject(renderer, objectIndex);
|
||||
|
||||
// Conservatively cover.
|
||||
const coverProgram = renderContext.shaderPrograms.mcaaCover;
|
||||
gl.useProgram(coverProgram.program);
|
||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(this.coverVAO);
|
||||
this.setAAUniforms(renderer, coverProgram.uniforms, objectIndex);
|
||||
|
||||
const bQuadRange = renderer.meshData[meshIndex].bQuadPathRanges;
|
||||
const count = calculateCountFromIndexRanges(pathRange, bQuadRange);
|
||||
const bQuadRanges = renderer.meshData[meshIndex].bQuadPathRanges;
|
||||
const offset = calculateStartFromIndexRanges(pathRange, bQuadRanges);
|
||||
|
||||
const coverProgram = renderContext.shaderPrograms.mcaaCover;
|
||||
const attributes = coverProgram.attributes;
|
||||
gl.useProgram(coverProgram.program);
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, renderContext.quadPositionsBuffer);
|
||||
gl.vertexAttribPointer(attributes.aQuadPosition, 2, gl.FLOAT, false, 0, 0);
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, renderer.meshes[meshIndex].edgeBoundingBoxVertexPositions);
|
||||
gl.vertexAttribPointer(attributes.aUpperLeftPosition,
|
||||
2,
|
||||
gl.FLOAT,
|
||||
false,
|
||||
FLOAT32_SIZE * 4,
|
||||
FLOAT32_SIZE * 4 * offset);
|
||||
gl.vertexAttribPointer(attributes.aLowerRightPosition,
|
||||
2,
|
||||
gl.FLOAT,
|
||||
false,
|
||||
FLOAT32_SIZE * 4,
|
||||
FLOAT32_SIZE * 4 * offset + FLOAT32_SIZE * 2);
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, renderer.meshes[meshIndex].edgeBoundingBoxPathIDs);
|
||||
gl.vertexAttribPointer(attributes.aPathID,
|
||||
1,
|
||||
gl.UNSIGNED_SHORT,
|
||||
false,
|
||||
0,
|
||||
UINT16_SIZE * offset);
|
||||
gl.enableVertexAttribArray(attributes.aQuadPosition);
|
||||
gl.enableVertexAttribArray(attributes.aUpperLeftPosition);
|
||||
gl.enableVertexAttribArray(attributes.aLowerRightPosition);
|
||||
gl.enableVertexAttribArray(attributes.aPathID);
|
||||
renderContext.instancedArraysExt
|
||||
.drawElementsInstancedANGLE(gl.TRIANGLES, 6, gl.UNSIGNED_BYTE, 0, count);
|
||||
.vertexAttribDivisorANGLE(attributes.aUpperLeftPosition, 1);
|
||||
renderContext.instancedArraysExt
|
||||
.vertexAttribDivisorANGLE(attributes.aLowerRightPosition, 1);
|
||||
renderContext.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aPathID, 1);
|
||||
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, renderContext.quadElementsBuffer);
|
||||
|
||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(null);
|
||||
}
|
||||
|
||||
private setBlendModeForAA(renderer: Renderer, direction: 'upper' | 'lower'): 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 antialiasLinesOfObject(renderer: Renderer, objectIndex: number): void {
|
||||
const renderContext = renderer.renderContext;
|
||||
this.setAAState(renderer);
|
||||
|
||||
const lineProgram = renderContext.shaderPrograms.mcaaLine;
|
||||
const lineProgram = this.lineProgram(renderer);
|
||||
renderContext.gl.useProgram(lineProgram.program);
|
||||
|
||||
// FIXME(pcwalton): Refactor.
|
||||
|
@ -750,7 +814,7 @@ export abstract class MCAAStrategy extends XCAAStrategy {
|
|||
const renderContext = renderer.renderContext;
|
||||
this.setAAState(renderer);
|
||||
|
||||
const curveProgram = renderContext.shaderPrograms.mcaaCurve;
|
||||
const curveProgram = this.curveProgram(renderer);
|
||||
renderContext.gl.useProgram(curveProgram.program);
|
||||
|
||||
this.antialiasCurvesOfObjectWithProgram(renderer, objectIndex, curveProgram);
|
||||
|
@ -803,8 +867,6 @@ export abstract class ECAAStrategy extends XCAAStrategy {
|
|||
return renderContext.shaderPrograms.xcaaMonoResolve;
|
||||
}
|
||||
|
||||
protected maskEdgesOfObjectIfNecessary(renderer: Renderer, objectIndex: number): void {}
|
||||
|
||||
protected clearForAA(renderer: Renderer): void {
|
||||
const renderContext = renderer.renderContext;
|
||||
const gl = renderContext.gl;
|
||||
|
@ -1078,6 +1140,10 @@ export class ECAAMonochromeStrategy extends ECAAStrategy {
|
|||
return false;
|
||||
}
|
||||
|
||||
protected get usesAAFramebuffer(): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected get lineShaderProgramNames(): Array<keyof ShaderMap<void>> {
|
||||
return ['ecaaLine'];
|
||||
}
|
||||
|
@ -1087,39 +1153,182 @@ export class ECAAMonochromeStrategy extends ECAAStrategy {
|
|||
}
|
||||
}
|
||||
|
||||
export class MCAAMonochromeStrategy extends MCAAStrategy {
|
||||
export class MCAAMulticolorStrategy extends XCAAStrategy {
|
||||
protected vao: WebGLVertexArrayObject;
|
||||
|
||||
protected get usesDilationTransforms(): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected getResolveProgram(renderContext: RenderContext): PathfinderShaderProgram {
|
||||
if (this.subpixelAA !== 'none')
|
||||
return renderContext.shaderPrograms.xcaaMonoSubpixelResolve;
|
||||
return renderContext.shaderPrograms.xcaaMonoResolve;
|
||||
attachMeshes(renderer: Renderer): void {
|
||||
super.attachMeshes(renderer);
|
||||
|
||||
const renderContext = renderer.renderContext;
|
||||
this.vao = renderContext.vertexArrayObjectExt.createVertexArrayOES();
|
||||
}
|
||||
|
||||
protected maskEdgesOfObjectIfNecessary(renderer: Renderer, objectIndex: number): void {}
|
||||
antialiasObject(renderer: Renderer, objectIndex: number): void {
|
||||
super.antialiasObject(renderer, objectIndex);
|
||||
|
||||
const shaderProgram = this.edgeProgram(renderer);
|
||||
this.antialiasEdgesOfObjectWithProgram(renderer, objectIndex, shaderProgram);
|
||||
}
|
||||
|
||||
protected get usesAAFramebuffer(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected getResolveProgram(renderContext: RenderContext): PathfinderShaderProgram | null {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected prepareAA(renderer: Renderer): void {
|
||||
super.prepareAA(renderer);
|
||||
|
||||
this.clearForAA(renderer);
|
||||
}
|
||||
|
||||
protected coverObjectIfNecessary(renderer: Renderer, objectIndex: number): void {}
|
||||
|
||||
protected antialiasEdgesOfObjectWithProgram(renderer: Renderer,
|
||||
objectIndex: number,
|
||||
shaderProgram: PathfinderShaderProgram):
|
||||
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.initVAOForObject(renderer, objectIndex);
|
||||
|
||||
gl.useProgram(shaderProgram.program);
|
||||
const uniforms = shaderProgram.uniforms;
|
||||
this.setAAUniforms(renderer, uniforms, objectIndex);
|
||||
|
||||
// FIXME(pcwalton): Refactor.
|
||||
const vao = this.vao;
|
||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(vao);
|
||||
|
||||
this.setBlendModeForAA(renderer);
|
||||
|
||||
const bQuadRanges = renderer.meshData[meshIndex].bQuadPathRanges;
|
||||
const count = calculateCountFromIndexRanges(pathRange, bQuadRanges);
|
||||
|
||||
renderContext.instancedArraysExt
|
||||
.drawElementsInstancedANGLE(gl.TRIANGLES, 6, gl.UNSIGNED_BYTE, 0, count);
|
||||
|
||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(null);
|
||||
}
|
||||
|
||||
protected clearForAA(renderer: Renderer): void {
|
||||
const renderContext = renderer.renderContext;
|
||||
const gl = renderContext.gl;
|
||||
|
||||
gl.clearColor(0.0, 0.0, 0.0, 0.0);
|
||||
gl.clearColor(1.0, 1.0, 1.0, 1.0);
|
||||
gl.clearDepth(0.0);
|
||||
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
||||
}
|
||||
|
||||
protected setAADepthState(renderer: Renderer): void {
|
||||
const renderContext = renderer.renderContext;
|
||||
renderContext.gl.disable(renderContext.gl.DEPTH_TEST);
|
||||
const gl = renderContext.gl;
|
||||
|
||||
gl.disable(gl.DEPTH_TEST);
|
||||
}
|
||||
|
||||
protected clearForResolve(renderer: Renderer): void {
|
||||
protected clearForResolve(renderer: Renderer): void {}
|
||||
|
||||
protected setBlendModeForAA(renderer: Renderer): void {
|
||||
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.blendEquation(gl.FUNC_ADD);
|
||||
gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE);
|
||||
gl.enable(gl.BLEND);
|
||||
}
|
||||
|
||||
protected setAAUniforms(renderer: Renderer, uniforms: UniformMap, objectIndex: number):
|
||||
void {
|
||||
super.setAAUniforms(renderer, uniforms, objectIndex);
|
||||
renderer.setPathColorsUniform(0, uniforms, 2);
|
||||
}
|
||||
|
||||
protected initVAOForObject(renderer: Renderer, objectIndex: number): void {
|
||||
if (renderer.meshes == null || renderer.meshData == null)
|
||||
return;
|
||||
|
||||
const renderContext = renderer.renderContext;
|
||||
const gl = renderContext.gl;
|
||||
|
||||
const pathRange = renderer.pathRangeForObject(objectIndex);
|
||||
const meshIndex = renderer.meshIndexForObject(objectIndex);
|
||||
|
||||
const shaderProgram = this.edgeProgram(renderer);
|
||||
const attributes = shaderProgram.attributes;
|
||||
|
||||
// FIXME(pcwalton): Refactor.
|
||||
const vao = this.vao;
|
||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(vao);
|
||||
|
||||
const bQuadRanges = renderer.meshData[meshIndex].bQuadPathRanges;
|
||||
const offset = calculateStartFromIndexRanges(pathRange, bQuadRanges);
|
||||
|
||||
gl.useProgram(shaderProgram.program);
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, renderContext.quadPositionsBuffer);
|
||||
gl.vertexAttribPointer(attributes.aQuadPosition, 2, gl.FLOAT, false, 0, 0);
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, renderer.meshes[meshIndex].bQuadVertexPositions);
|
||||
gl.vertexAttribPointer(attributes.aUpperEndpointPositions,
|
||||
4,
|
||||
gl.FLOAT,
|
||||
false,
|
||||
FLOAT32_SIZE * 12,
|
||||
FLOAT32_SIZE * 12 * offset);
|
||||
gl.vertexAttribPointer(attributes.aLowerEndpointPositions,
|
||||
4,
|
||||
gl.FLOAT,
|
||||
false,
|
||||
FLOAT32_SIZE * 12,
|
||||
FLOAT32_SIZE * 12 * offset + FLOAT32_SIZE * 4);
|
||||
gl.vertexAttribPointer(attributes.aControlPointPositions,
|
||||
4,
|
||||
gl.FLOAT,
|
||||
false,
|
||||
FLOAT32_SIZE * 12,
|
||||
FLOAT32_SIZE * 12 * offset + FLOAT32_SIZE * 8);
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, renderer.meshes[meshIndex].edgeBoundingBoxPathIDs);
|
||||
gl.vertexAttribPointer(attributes.aPathID,
|
||||
1,
|
||||
gl.UNSIGNED_SHORT,
|
||||
false,
|
||||
0,
|
||||
UINT16_SIZE * offset);
|
||||
gl.enableVertexAttribArray(attributes.aQuadPosition);
|
||||
gl.enableVertexAttribArray(attributes.aUpperEndpointPositions);
|
||||
gl.enableVertexAttribArray(attributes.aLowerEndpointPositions);
|
||||
gl.enableVertexAttribArray(attributes.aControlPointPositions);
|
||||
gl.enableVertexAttribArray(attributes.aPathID);
|
||||
renderContext.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aPathID, 1);
|
||||
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, renderContext.quadElementsBuffer);
|
||||
|
||||
renderContext.instancedArraysExt
|
||||
.vertexAttribDivisorANGLE(attributes.aUpperEndpointPositions, 1);
|
||||
renderContext.instancedArraysExt
|
||||
.vertexAttribDivisorANGLE(attributes.aLowerEndpointPositions, 1);
|
||||
renderContext.instancedArraysExt
|
||||
.vertexAttribDivisorANGLE(attributes.aControlPointPositions, 1);
|
||||
renderContext.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aPathID, 1);
|
||||
|
||||
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, renderContext.quadElementsBuffer);
|
||||
|
||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(null);
|
||||
}
|
||||
|
||||
protected edgeProgram(renderer: Renderer): PathfinderShaderProgram {
|
||||
return renderer.renderContext.shaderPrograms.mcaaMulti;
|
||||
}
|
||||
|
||||
get directRenderingMode(): DirectRenderingMode {
|
||||
|
@ -1174,6 +1383,10 @@ export class AdaptiveMonochromeXCAAStrategy implements AntialiasingStrategy {
|
|||
this.getAppropriateStrategy(renderer).prepareForDirectRendering(renderer);
|
||||
}
|
||||
|
||||
finishAntialiasingObject(renderer: Renderer, objectIndex: number): void {
|
||||
this.getAppropriateStrategy(renderer).finishAntialiasingObject(renderer, objectIndex);
|
||||
}
|
||||
|
||||
prepareToRenderObject(renderer: Renderer, objectIndex: number): void {
|
||||
this.getAppropriateStrategy(renderer).prepareToRenderObject(renderer, objectIndex);
|
||||
}
|
||||
|
@ -1208,132 +1421,6 @@ export class AdaptiveMonochromeXCAAStrategy implements AntialiasingStrategy {
|
|||
}
|
||||
}
|
||||
|
||||
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',
|
||||
'ecaaTransformedCurve',
|
||||
'xcaaMultiEdgeMaskCurve',
|
||||
'xcaaMultiEdgeMaskTransformedCurve',
|
||||
];
|
||||
}
|
||||
|
||||
private edgeMaskVAO: WebGLVertexArrayObject;
|
||||
|
||||
bindEdgeDepthTexture(gl: WebGLRenderingContext, uniforms: UniformMap, textureUnit: number):
|
||||
void {
|
||||
gl.activeTexture(gl.TEXTURE0 + textureUnit);
|
||||
gl.bindTexture(gl.TEXTURE_2D, this.aaDepthTexture);
|
||||
gl.uniform1i(uniforms.uEdgeDepth, textureUnit);
|
||||
gl.activeTexture(gl.TEXTURE0 + textureUnit + 1);
|
||||
gl.bindTexture(gl.TEXTURE_2D, this.aaAlphaTexture);
|
||||
gl.uniform1i(uniforms.uEdgeAlpha, textureUnit);
|
||||
}
|
||||
|
||||
protected getResolveProgram(renderContext: RenderContext): PathfinderShaderProgram {
|
||||
return renderContext.shaderPrograms.xcaaMultiResolve;
|
||||
}
|
||||
|
||||
protected initDirectFramebufferIfNecessary(renderer: Renderer): void {}
|
||||
|
||||
protected maskEdgesOfObjectIfNecessary(renderer: Renderer, objectIndex: number): void {
|
||||
const renderContext = renderer.renderContext;
|
||||
const gl = renderContext.gl;
|
||||
|
||||
// Set state for edge masking.
|
||||
gl.bindFramebuffer(gl.FRAMEBUFFER, this.aaFramebuffer);
|
||||
gl.viewport(0,
|
||||
0,
|
||||
this.supersampledFramebufferSize[0],
|
||||
this.supersampledFramebufferSize[1]);
|
||||
|
||||
gl.colorMask(true, true, true, true);
|
||||
gl.depthMask(true);
|
||||
gl.depthFunc(gl.GREATER);
|
||||
gl.enable(gl.DEPTH_TEST);
|
||||
gl.disable(gl.BLEND);
|
||||
|
||||
gl.clearDepth(0.0);
|
||||
gl.clearColor(0.0, 0.0, 0.0, 0.0);
|
||||
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
||||
|
||||
// Perform edge masking.
|
||||
gl.colorMask(false, false, false, false);
|
||||
this.antialiasLinesOfObjectWithProgram(renderer, objectIndex, 'xcaaMultiEdgeMaskLine');
|
||||
this.antialiasCurvesOfObjectWithPrograms(renderer,
|
||||
objectIndex,
|
||||
'xcaaMultiEdgeMaskCurve',
|
||||
'xcaaMultiEdgeMaskTransformedCurve');
|
||||
|
||||
gl.colorMask(true, true, true, true);
|
||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(null);
|
||||
}
|
||||
|
||||
protected setCoverDepthState(renderer: Renderer): void {
|
||||
const renderContext = renderer.renderContext;
|
||||
const gl = renderContext.gl;
|
||||
|
||||
gl.depthMask(false);
|
||||
gl.depthFunc(gl.EQUAL);
|
||||
gl.enable(gl.DEPTH_TEST);
|
||||
}
|
||||
|
||||
protected clearForAA(renderer: Renderer): void {}
|
||||
|
||||
protected setAADepthState(renderer: Renderer): void {
|
||||
const renderContext = renderer.renderContext;
|
||||
const gl = renderContext.gl;
|
||||
|
||||
gl.depthMask(false);
|
||||
gl.depthFunc(gl.EQUAL);
|
||||
gl.enable(gl.DEPTH_TEST);
|
||||
}
|
||||
|
||||
protected setDepthAndBlendModeForResolve(renderContext: RenderContext): void {
|
||||
const gl = renderContext.gl;
|
||||
|
||||
gl.depthMask(true);
|
||||
gl.depthFunc(gl.GREATER);
|
||||
gl.enable(gl.DEPTH_TEST);
|
||||
|
||||
gl.blendEquation(gl.FUNC_ADD);
|
||||
gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE);
|
||||
gl.enable(gl.BLEND);
|
||||
}
|
||||
|
||||
protected clearForResolve(renderer: Renderer): void {}
|
||||
|
||||
protected setAdditionalStateForResolveIfNecessary(renderer: Renderer,
|
||||
resolveProgram: PathfinderShaderProgram,
|
||||
firstFreeTextureUnit: number):
|
||||
void {
|
||||
const renderContext = renderer.renderContext;
|
||||
const gl = renderContext.gl;
|
||||
|
||||
gl.activeTexture(gl.TEXTURE0 + firstFreeTextureUnit + 0);
|
||||
gl.bindTexture(gl.TEXTURE_2D, this.aaDepthTexture);
|
||||
gl.uniform1i(resolveProgram.uniforms.uAADepth, firstFreeTextureUnit + 0);
|
||||
|
||||
renderer.setPathColorsUniform(0, resolveProgram.uniforms, firstFreeTextureUnit + 1);
|
||||
}
|
||||
|
||||
get directRenderingMode(): DirectRenderingMode {
|
||||
return 'color-depth';
|
||||
}
|
||||
|
||||
protected get directDepthTexture(): WebGLTexture | null {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function calculateStartFromIndexRanges(pathRange: Range, indexRanges: Range[]): number {
|
||||
return indexRanges.length === 0 ? 0 : indexRanges[pathRange.start - 1].start;
|
||||
}
|
||||
|
|
|
@ -24,6 +24,8 @@ use {BQuad, BVertexLoopBlinnData};
|
|||
pub struct MeshLibrary {
|
||||
pub path_ranges: Vec<PathRanges>,
|
||||
pub b_quads: Vec<BQuad>,
|
||||
// FIXME(pcwalton): Merge with `b_vertex_positions` below.
|
||||
pub b_quad_vertex_positions: Vec<Point2D<f32>>,
|
||||
pub b_vertex_positions: Vec<Point2D<f32>>,
|
||||
pub b_vertex_loop_blinn_data: Vec<BVertexLoopBlinnData>,
|
||||
pub b_vertex_normals: Vec<f32>,
|
||||
|
@ -39,6 +41,7 @@ impl MeshLibrary {
|
|||
MeshLibrary {
|
||||
path_ranges: vec![],
|
||||
b_quads: vec![],
|
||||
b_quad_vertex_positions: vec![],
|
||||
b_vertex_positions: vec![],
|
||||
b_vertex_loop_blinn_data: vec![],
|
||||
b_vertex_normals: vec![],
|
||||
|
@ -52,6 +55,7 @@ impl MeshLibrary {
|
|||
pub fn clear(&mut self) {
|
||||
self.path_ranges.clear();
|
||||
self.b_quads.clear();
|
||||
self.b_quad_vertex_positions.clear();
|
||||
self.b_vertex_positions.clear();
|
||||
self.b_vertex_loop_blinn_data.clear();
|
||||
self.b_vertex_normals.clear();
|
||||
|
@ -90,6 +94,13 @@ impl MeshLibrary {
|
|||
let lower_right_position =
|
||||
&self.b_vertex_positions[b_quad.lower_right_vertex_index as usize];
|
||||
|
||||
self.b_quad_vertex_positions.extend_from_slice(&[
|
||||
*upper_left_position,
|
||||
*upper_right_position,
|
||||
*lower_left_position,
|
||||
*lower_right_position,
|
||||
]);
|
||||
|
||||
let upper_left_bounding_box_position =
|
||||
Point2D::new(upper_left_position.x,
|
||||
f32::max(upper_left_position.y, upper_right_position.y));
|
||||
|
@ -103,6 +114,7 @@ impl MeshLibrary {
|
|||
});
|
||||
|
||||
if b_quad.upper_control_point_vertex_index == u32::MAX {
|
||||
self.b_quad_vertex_positions.push(Point2D::zero());
|
||||
self.edge_data.upper_line_vertex_positions.push(EdgeLineVertexPositions {
|
||||
left: *upper_left_position,
|
||||
right: *upper_right_position,
|
||||
|
@ -110,6 +122,7 @@ impl MeshLibrary {
|
|||
} else {
|
||||
let upper_control_point_position =
|
||||
&self.b_vertex_positions[b_quad.upper_control_point_vertex_index as usize];
|
||||
self.b_quad_vertex_positions.push(*upper_control_point_position);
|
||||
self.edge_data.upper_curve_vertex_positions.push(EdgeCurveVertexPositions {
|
||||
left: *upper_left_position,
|
||||
control_point: *upper_control_point_position,
|
||||
|
@ -118,6 +131,7 @@ impl MeshLibrary {
|
|||
}
|
||||
|
||||
if b_quad.lower_control_point_vertex_index == u32::MAX {
|
||||
self.b_quad_vertex_positions.push(Point2D::zero());
|
||||
self.edge_data.lower_line_vertex_positions.push(EdgeLineVertexPositions {
|
||||
left: *lower_left_position,
|
||||
right: *lower_right_position,
|
||||
|
@ -125,6 +139,7 @@ impl MeshLibrary {
|
|||
} else {
|
||||
let lower_control_point_position =
|
||||
&self.b_vertex_positions[b_quad.lower_control_point_vertex_index as usize];
|
||||
self.b_quad_vertex_positions.push(*lower_control_point_position);
|
||||
self.edge_data.lower_curve_vertex_positions.push(EdgeCurveVertexPositions {
|
||||
left: *lower_left_position,
|
||||
control_point: *lower_control_point_position,
|
||||
|
@ -205,6 +220,7 @@ impl MeshLibrary {
|
|||
try!(write_chunk(writer, b"prng", |writer| write_path_ranges(writer, &self.path_ranges)));
|
||||
|
||||
try!(write_simple_chunk(writer, b"bqua", &self.b_quads));
|
||||
try!(write_simple_chunk(writer, b"bqvp", &self.b_quad_vertex_positions));
|
||||
try!(write_simple_chunk(writer, b"bvpo", &self.b_vertex_positions));
|
||||
try!(write_simple_chunk(writer, b"bvlb", &self.b_vertex_loop_blinn_data));
|
||||
try!(write_simple_chunk(writer, b"bvno", &self.b_vertex_normals));
|
||||
|
@ -255,6 +271,10 @@ impl MeshLibrary {
|
|||
fn write_path_ranges<W>(writer: &mut W, path_ranges: &[PathRanges]) -> io::Result<()>
|
||||
where W: Write + Seek {
|
||||
try!(write_path_range(writer, b"bqua", path_ranges, |ranges| &ranges.b_quads));
|
||||
try!(write_path_range(writer,
|
||||
b"bqvp",
|
||||
path_ranges,
|
||||
|ranges| &ranges.b_quad_vertex_positions));
|
||||
try!(write_path_range(writer, b"bver", path_ranges, |ranges| &ranges.b_vertices));
|
||||
try!(write_path_range(writer,
|
||||
b"cvii",
|
||||
|
@ -309,6 +329,7 @@ impl MeshLibrary {
|
|||
pub(crate) fn snapshot_lengths(&self) -> MeshLibraryLengths {
|
||||
MeshLibraryLengths {
|
||||
b_quads: self.b_quads.len() as u32,
|
||||
b_quad_vertex_positions: self.b_quad_vertex_positions.len() as u32,
|
||||
b_vertices: self.b_vertex_positions.len() as u32,
|
||||
cover_interior_indices: self.cover_indices.interior_indices.len() as u32,
|
||||
cover_curve_indices: self.cover_indices.curve_indices.len() as u32,
|
||||
|
@ -344,6 +365,7 @@ impl MeshLibraryCoverIndices {
|
|||
|
||||
pub(crate) struct MeshLibraryLengths {
|
||||
b_quads: u32,
|
||||
b_quad_vertex_positions: u32,
|
||||
b_vertices: u32,
|
||||
cover_interior_indices: u32,
|
||||
cover_curve_indices: u32,
|
||||
|
@ -357,6 +379,7 @@ pub(crate) struct MeshLibraryLengths {
|
|||
#[derive(Clone, Debug)]
|
||||
pub struct PathRanges {
|
||||
pub b_quads: Range<u32>,
|
||||
pub b_quad_vertex_positions: Range<u32>,
|
||||
pub b_vertices: Range<u32>,
|
||||
pub cover_interior_indices: Range<u32>,
|
||||
pub cover_curve_indices: Range<u32>,
|
||||
|
@ -373,6 +396,7 @@ impl PathRanges {
|
|||
fn new() -> PathRanges {
|
||||
PathRanges {
|
||||
b_quads: 0..0,
|
||||
b_quad_vertex_positions: 0..0,
|
||||
b_vertices: 0..0,
|
||||
cover_interior_indices: 0..0,
|
||||
cover_curve_indices: 0..0,
|
||||
|
@ -390,6 +414,7 @@ impl PathRanges {
|
|||
start: &MeshLibraryLengths,
|
||||
end: &MeshLibraryLengths) {
|
||||
self.b_quads = start.b_quads..end.b_quads;
|
||||
self.b_quad_vertex_positions = start.b_quad_vertex_positions..end.b_quad_vertex_positions;
|
||||
self.b_vertices = start.b_vertices..end.b_vertices;
|
||||
self.cover_interior_indices = start.cover_interior_indices..end.cover_interior_indices;
|
||||
self.cover_curve_indices = start.cover_curve_indices..end.cover_curve_indices;
|
||||
|
|
|
@ -131,12 +131,39 @@ vec2 computeMCAAPosition(vec2 position,
|
|||
vec4 localTransformST,
|
||||
vec4 globalTransformST,
|
||||
ivec2 framebufferSize) {
|
||||
if (position == vec2(0.0))
|
||||
return position;
|
||||
|
||||
position = hintPosition(position, hints);
|
||||
position = transformVertexPositionST(position, localTransformST);
|
||||
position = transformVertexPositionST(position, globalTransformST);
|
||||
return convertClipToScreenSpace(position, framebufferSize);
|
||||
}
|
||||
|
||||
vec2 computeMCAASnappedPosition(vec2 position,
|
||||
vec4 hints,
|
||||
vec4 localTransformST,
|
||||
vec4 globalTransformST,
|
||||
ivec2 framebufferSize,
|
||||
float tanTheta) {
|
||||
position = hintPosition(position, hints);
|
||||
position = transformVertexPositionST(position, localTransformST);
|
||||
position = transformVertexPositionST(position, globalTransformST);
|
||||
position = convertClipToScreenSpace(position, framebufferSize);
|
||||
//position.x = abs(mod(position.x, 1.0)) < 0.5 ? floor(position.x) : ceil(position.x);
|
||||
|
||||
float xNudge = fract(position.x);
|
||||
if (xNudge < 0.5)
|
||||
xNudge = -xNudge;
|
||||
else
|
||||
xNudge = 1.0 - xNudge;
|
||||
|
||||
position.x += xNudge;
|
||||
position.y += xNudge * tanTheta;
|
||||
|
||||
return position;
|
||||
}
|
||||
|
||||
bool computeMCAAQuadPosition(out vec2 outPosition,
|
||||
inout vec2 leftPosition,
|
||||
inout vec2 rightPosition,
|
||||
|
@ -440,6 +467,13 @@ vec2 solveCurveT(float p0x, float p1x, float p2x, vec2 x) {
|
|||
return 2.0 * c / (-b - sqrt(b * b - 4.0 * a * c));
|
||||
}
|
||||
|
||||
vec2 solveCurveT1(float p0x, float p1x, float p2x, vec2 x) {
|
||||
float a = p0x - 2.0 * p1x + p2x;
|
||||
float b = 2.0 * p1x - 2.0 * p0x;
|
||||
vec2 c = p0x - x;
|
||||
return (-b + sqrt(b * b - 4.0 * a * c)) / (2.0 * a);
|
||||
}
|
||||
|
||||
// https://www.freetype.org/freetype2/docs/reference/ft2-lcd_filtering.html
|
||||
float lcdFilter(float shadeL2, float shadeL1, float shade0, float shadeR1, float shadeR2) {
|
||||
return LCD_FILTER_FACTOR_2 * shadeL2 +
|
||||
|
|
|
@ -1,77 +0,0 @@
|
|||
// pathfinder/shaders/gles2/ecaa-multi-edge-mask-curve.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;
|
||||
|
||||
uniform mat4 uTransform;
|
||||
uniform ivec2 uFramebufferSize;
|
||||
uniform ivec2 uPathTransformSTDimensions;
|
||||
uniform sampler2D uPathTransformST;
|
||||
uniform ivec2 uPathTransformExtDimensions;
|
||||
uniform sampler2D uPathTransformExt;
|
||||
|
||||
attribute vec2 aQuadPosition;
|
||||
attribute vec2 aLeftPosition;
|
||||
attribute vec2 aControlPointPosition;
|
||||
attribute vec2 aRightPosition;
|
||||
attribute float aPathID;
|
||||
|
||||
varying vec4 vEndpoints;
|
||||
varying vec2 vControlPoint;
|
||||
|
||||
void main() {
|
||||
vec2 leftPosition = aLeftPosition;
|
||||
vec2 controlPointPosition = aControlPointPosition;
|
||||
vec2 rightPosition = aRightPosition;
|
||||
int pathID = int(aPathID);
|
||||
|
||||
vec2 pathTransformExt;
|
||||
vec4 pathTransformST = fetchPathAffineTransform(pathTransformExt,
|
||||
uPathTransformST,
|
||||
uPathTransformSTDimensions,
|
||||
uPathTransformExt,
|
||||
uPathTransformExtDimensions,
|
||||
pathID);
|
||||
|
||||
// Transform the points.
|
||||
leftPosition = transformECAAPositionToScreenSpace(leftPosition,
|
||||
pathTransformST,
|
||||
pathTransformExt,
|
||||
uTransform,
|
||||
uFramebufferSize);
|
||||
rightPosition = transformECAAPositionToScreenSpace(rightPosition,
|
||||
pathTransformST,
|
||||
pathTransformExt,
|
||||
uTransform,
|
||||
uFramebufferSize);
|
||||
controlPointPosition = transformECAAPositionToScreenSpace(controlPointPosition,
|
||||
pathTransformST,
|
||||
pathTransformExt,
|
||||
uTransform,
|
||||
uFramebufferSize);
|
||||
|
||||
float winding = computeECAAWinding(leftPosition, rightPosition);
|
||||
if (winding == 0.0) {
|
||||
gl_Position = vec4(0.0);
|
||||
return;
|
||||
}
|
||||
|
||||
vec4 extents = vec4(leftPosition.x,
|
||||
min(leftPosition.y, rightPosition.y),
|
||||
rightPosition.x,
|
||||
max(leftPosition.y, rightPosition.y));
|
||||
vec2 position = computeXCAAClipSpaceQuadPosition(extents, aQuadPosition, uFramebufferSize);
|
||||
|
||||
float depth = convertPathIndexToViewportDepthValue(pathID);
|
||||
|
||||
gl_Position = vec4(position, depth, 1.0);
|
||||
vEndpoints = vec4(leftPosition, rightPosition);
|
||||
vControlPoint = controlPointPosition;
|
||||
}
|
|
@ -1,69 +0,0 @@
|
|||
// pathfinder/shaders/gles2/ecaa-multi-edge-mask-line.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;
|
||||
|
||||
uniform mat4 uTransform;
|
||||
uniform vec4 uHints;
|
||||
uniform ivec2 uFramebufferSize;
|
||||
uniform ivec2 uPathTransformSTDimensions;
|
||||
uniform sampler2D uPathTransformST;
|
||||
uniform ivec2 uPathTransformExtDimensions;
|
||||
uniform sampler2D uPathTransformExt;
|
||||
|
||||
attribute vec2 aQuadPosition;
|
||||
attribute vec2 aLeftPosition;
|
||||
attribute vec2 aRightPosition;
|
||||
attribute float aPathID;
|
||||
|
||||
varying vec4 vEndpoints;
|
||||
|
||||
void main() {
|
||||
vec2 leftPosition = aLeftPosition;
|
||||
vec2 rightPosition = aRightPosition;
|
||||
int pathID = int(aPathID);
|
||||
|
||||
vec2 pathTransformExt;
|
||||
vec4 pathTransformST = fetchPathAffineTransform(pathTransformExt,
|
||||
uPathTransformST,
|
||||
uPathTransformSTDimensions,
|
||||
uPathTransformExt,
|
||||
uPathTransformExtDimensions,
|
||||
pathID);
|
||||
|
||||
// Transform the points.
|
||||
leftPosition = transformECAAPositionToScreenSpace(leftPosition,
|
||||
pathTransformST,
|
||||
pathTransformExt,
|
||||
uTransform,
|
||||
uFramebufferSize);
|
||||
rightPosition = transformECAAPositionToScreenSpace(rightPosition,
|
||||
pathTransformST,
|
||||
pathTransformExt,
|
||||
uTransform,
|
||||
uFramebufferSize);
|
||||
|
||||
float winding = computeECAAWinding(leftPosition, rightPosition);
|
||||
if (winding == 0.0) {
|
||||
gl_Position = vec4(0.0);
|
||||
return;
|
||||
}
|
||||
|
||||
vec4 extents = vec4(min(leftPosition.x, rightPosition.x),
|
||||
min(leftPosition.y, rightPosition.y),
|
||||
max(rightPosition.x, rightPosition.x),
|
||||
max(leftPosition.y, rightPosition.y));
|
||||
vec2 position = computeXCAAClipSpaceQuadPosition(extents, aQuadPosition, uFramebufferSize);
|
||||
|
||||
float depth = convertPathIndexToViewportDepthValue(pathID);
|
||||
|
||||
gl_Position = vec4(position, depth, 1.0);
|
||||
vEndpoints = vec4(leftPosition, rightPosition);
|
||||
}
|
|
@ -1,83 +0,0 @@
|
|||
// pathfinder/shaders/gles2/ecaa-multi-edge-mask-transformed-curve.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;
|
||||
|
||||
uniform mat4 uTransform;
|
||||
uniform ivec2 uFramebufferSize;
|
||||
uniform ivec2 uPathTransformSTDimensions;
|
||||
uniform sampler2D uPathTransformST;
|
||||
uniform ivec2 uPathTransformExtDimensions;
|
||||
uniform sampler2D uPathTransformExt;
|
||||
uniform int uPassIndex;
|
||||
|
||||
attribute vec2 aQuadPosition;
|
||||
attribute vec2 aLeftPosition;
|
||||
attribute vec2 aControlPointPosition;
|
||||
attribute vec2 aRightPosition;
|
||||
attribute float aPathID;
|
||||
|
||||
varying vec4 vEndpoints;
|
||||
varying vec2 vControlPoint;
|
||||
|
||||
void main() {
|
||||
vec2 leftPosition = aLeftPosition;
|
||||
vec2 controlPointPosition = aControlPointPosition;
|
||||
vec2 rightPosition = aRightPosition;
|
||||
int pathID = int(aPathID);
|
||||
|
||||
vec2 pathTransformExt;
|
||||
vec4 pathTransformST = fetchPathAffineTransform(pathTransformExt,
|
||||
uPathTransformST,
|
||||
uPathTransformSTDimensions,
|
||||
uPathTransformExt,
|
||||
uPathTransformExtDimensions,
|
||||
pathID);
|
||||
|
||||
// Transform the points.
|
||||
leftPosition = transformECAAPositionToScreenSpace(leftPosition,
|
||||
pathTransformST,
|
||||
pathTransformExt,
|
||||
uTransform,
|
||||
uFramebufferSize);
|
||||
rightPosition = transformECAAPositionToScreenSpace(rightPosition,
|
||||
pathTransformST,
|
||||
pathTransformExt,
|
||||
uTransform,
|
||||
uFramebufferSize);
|
||||
controlPointPosition = transformECAAPositionToScreenSpace(controlPointPosition,
|
||||
pathTransformST,
|
||||
pathTransformExt,
|
||||
uTransform,
|
||||
uFramebufferSize);
|
||||
|
||||
float winding;
|
||||
vec3 leftTopRightEdges;
|
||||
if (!splitCurveAndComputeECAAWinding(winding,
|
||||
leftTopRightEdges,
|
||||
leftPosition,
|
||||
rightPosition,
|
||||
controlPointPosition,
|
||||
uPassIndex)) {
|
||||
gl_Position = vec4(0.0);
|
||||
return;
|
||||
}
|
||||
|
||||
vec4 extents = vec4(leftTopRightEdges,
|
||||
max(max(leftPosition.y, rightPosition.y), controlPointPosition.y));
|
||||
vec2 position = computeXCAAClipSpaceQuadPosition(extents, aQuadPosition, uFramebufferSize);
|
||||
|
||||
float depth = convertPathIndexToViewportDepthValue(pathID);
|
||||
|
||||
gl_Position = vec4(position, depth, 1.0);
|
||||
vEndpoints = vec4(leftPosition, rightPosition);
|
||||
vControlPoint = controlPointPosition;
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
// pathfinder/shaders/gles2/mcaa-multi.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;
|
||||
|
||||
varying vec4 vUpperEndpoints;
|
||||
varying vec4 vLowerEndpoints;
|
||||
varying vec4 vControlPoints;
|
||||
varying vec4 vColor;
|
||||
|
||||
float computeCoverageForSide(vec2 p0, vec2 cp, vec2 p1, float winding) {
|
||||
// Compute pixel extents.
|
||||
vec2 pixelCenter = gl_FragCoord.xy;
|
||||
vec2 pixelColumnBounds = pixelCenter.xx + vec2(-0.5, 0.5);
|
||||
|
||||
vec2 clippedP0, clippedDP;
|
||||
if (cp == vec2(0.0)) {
|
||||
vec4 p0DPX = clipLineToPixelColumn(p0, p1 - p0, pixelCenter.x);
|
||||
clippedP0 = p0DPX.xy;
|
||||
clippedDP = p0DPX.zw;
|
||||
} else {
|
||||
// Clip the curve to the left and right edges to create a line.
|
||||
vec2 t = solveCurveT(p0.x, cp.x, p1.x, pixelColumnBounds);
|
||||
|
||||
// Handle endpoints properly. These tests are negated to handle NaNs.
|
||||
if (!(p0.x < pixelColumnBounds.x))
|
||||
t.x = 0.0;
|
||||
if (!(p1.x > pixelColumnBounds.y))
|
||||
t.y = 1.0;
|
||||
|
||||
clippedP0 = mix(mix(p0, cp, t.x), mix(cp, p1, t.x), t.x);
|
||||
clippedDP = mix(mix(p0, cp, t.y), mix(cp, p1, t.y), t.y) - clippedP0;
|
||||
}
|
||||
|
||||
return computeCoverage(clippedP0, clippedDP, pixelCenter.y, winding);
|
||||
}
|
||||
|
||||
void main() {
|
||||
float alpha = computeCoverageForSide(vLowerEndpoints.xy,
|
||||
vControlPoints.zw,
|
||||
vLowerEndpoints.zw,
|
||||
-1.0);
|
||||
|
||||
alpha += computeCoverageForSide(vUpperEndpoints.xy,
|
||||
vControlPoints.xy,
|
||||
vUpperEndpoints.zw,
|
||||
1.0);
|
||||
|
||||
// Compute area.
|
||||
gl_FragColor = vec4(vColor.rgb, vColor.a * alpha);
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
// pathfinder/shaders/gles2/mcaa-multi.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;
|
||||
|
||||
uniform vec4 uTransformST;
|
||||
uniform vec4 uHints;
|
||||
uniform ivec2 uFramebufferSize;
|
||||
uniform ivec2 uPathTransformSTDimensions;
|
||||
uniform sampler2D uPathTransformST;
|
||||
uniform ivec2 uPathColorsDimensions;
|
||||
uniform sampler2D uPathColors;
|
||||
|
||||
attribute vec2 aQuadPosition;
|
||||
attribute vec4 aUpperEndpointPositions;
|
||||
attribute vec4 aLowerEndpointPositions;
|
||||
attribute vec4 aControlPointPositions;
|
||||
attribute float aPathID;
|
||||
|
||||
varying vec4 vUpperEndpoints;
|
||||
varying vec4 vLowerEndpoints;
|
||||
varying vec4 vControlPoints;
|
||||
varying vec4 vColor;
|
||||
|
||||
void main() {
|
||||
vec2 tlPosition = aUpperEndpointPositions.xy;
|
||||
vec2 tcPosition = aControlPointPositions.xy;
|
||||
vec2 trPosition = aUpperEndpointPositions.zw;
|
||||
vec2 blPosition = aLowerEndpointPositions.xy;
|
||||
vec2 bcPosition = aControlPointPositions.zw;
|
||||
vec2 brPosition = aLowerEndpointPositions.zw;
|
||||
vec2 quadPosition = aQuadPosition;
|
||||
int pathID = int(aPathID);
|
||||
|
||||
vec4 transformST = fetchFloat4Data(uPathTransformST, pathID, uPathTransformSTDimensions);
|
||||
|
||||
vec4 color = fetchFloat4Data(uPathColors, pathID, uPathColorsDimensions);
|
||||
|
||||
vec2 topVector = trPosition - tlPosition, bottomVector = brPosition - blPosition;
|
||||
float topTanTheta = topVector.y / topVector.x;
|
||||
float bottomTanTheta = bottomVector.y / bottomVector.x;
|
||||
|
||||
// Transform the points, and compute the position of this vertex.
|
||||
tlPosition = computeMCAASnappedPosition(tlPosition,
|
||||
uHints,
|
||||
transformST,
|
||||
uTransformST,
|
||||
uFramebufferSize,
|
||||
topTanTheta);
|
||||
trPosition = computeMCAASnappedPosition(trPosition,
|
||||
uHints,
|
||||
transformST,
|
||||
uTransformST,
|
||||
uFramebufferSize,
|
||||
topTanTheta);
|
||||
tcPosition = computeMCAAPosition(tcPosition,
|
||||
uHints,
|
||||
transformST,
|
||||
uTransformST,
|
||||
uFramebufferSize);
|
||||
blPosition = computeMCAASnappedPosition(blPosition,
|
||||
uHints,
|
||||
transformST,
|
||||
uTransformST,
|
||||
uFramebufferSize,
|
||||
bottomTanTheta);
|
||||
brPosition = computeMCAASnappedPosition(brPosition,
|
||||
uHints,
|
||||
transformST,
|
||||
uTransformST,
|
||||
uFramebufferSize,
|
||||
bottomTanTheta);
|
||||
bcPosition = computeMCAAPosition(bcPosition,
|
||||
uHints,
|
||||
transformST,
|
||||
uTransformST,
|
||||
uFramebufferSize);
|
||||
|
||||
float depth = convertPathIndexToViewportDepthValue(pathID);
|
||||
|
||||
vec2 position;
|
||||
position.x = mix(tlPosition.x, brPosition.x, quadPosition.x);
|
||||
if (quadPosition.y < 0.5)
|
||||
position.y = floor(min(tlPosition.y, trPosition.y));
|
||||
else
|
||||
position.y = ceil(max(blPosition.y, brPosition.y));
|
||||
position = convertScreenToClipSpace(position, uFramebufferSize);
|
||||
|
||||
gl_Position = vec4(position, depth, 1.0);
|
||||
vUpperEndpoints = vec4(tlPosition, trPosition);
|
||||
vLowerEndpoints = vec4(blPosition, brPosition);
|
||||
vControlPoints = vec4(tcPosition, bcPosition);
|
||||
vColor = color;
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
// pathfinder/shaders/gles2/xcaa-multi-direct-curve.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.
|
||||
|
||||
// This shader implements the quadratic Loop-Blinn formulation.
|
||||
|
||||
precision highp float;
|
||||
|
||||
uniform ivec2 uFramebufferSize;
|
||||
uniform sampler2D uEdgeDepth;
|
||||
|
||||
varying vec4 vColor;
|
||||
varying vec2 vTexCoord;
|
||||
varying float vSign;
|
||||
|
||||
void main() {
|
||||
vec2 center = floor(gl_FragCoord.xy);
|
||||
float depth = gl_FragCoord.z;
|
||||
vec2 texCoord = floor(center) / vec2(uFramebufferSize);
|
||||
|
||||
// TODO(pcwalton): Get back early Z somehow?
|
||||
if (depth == texture2D(uEdgeDepth, texCoord).r)
|
||||
discard;
|
||||
|
||||
float side = vTexCoord.x * vTexCoord.x - vTexCoord.y;
|
||||
if (sign(side) != sign(vSign))
|
||||
discard;
|
||||
|
||||
gl_FragColor = vColor;
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
// pathfinder/shaders/gles2/xcaa-multi-direct-curve.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;
|
||||
|
||||
uniform mat4 uTransform;
|
||||
uniform vec4 uHints;
|
||||
uniform vec2 uEmboldenAmount;
|
||||
uniform ivec2 uPathColorsDimensions;
|
||||
uniform sampler2D uPathColors;
|
||||
uniform ivec2 uPathTransformSTDimensions;
|
||||
uniform sampler2D uPathTransformST;
|
||||
uniform ivec2 uPathTransformExtDimensions;
|
||||
uniform sampler2D uPathTransformExt;
|
||||
|
||||
attribute vec2 aPosition;
|
||||
attribute vec2 aTexCoord;
|
||||
attribute float aPathID;
|
||||
attribute float aSign;
|
||||
attribute float aNormalAngle;
|
||||
|
||||
varying vec4 vColor;
|
||||
varying vec2 vTexCoord;
|
||||
varying float vSign;
|
||||
|
||||
void main() {
|
||||
int pathID = int(aPathID);
|
||||
|
||||
vec2 pathTransformExt;
|
||||
vec4 pathTransformST = fetchPathAffineTransform(pathTransformExt,
|
||||
uPathTransformST,
|
||||
uPathTransformSTDimensions,
|
||||
uPathTransformExt,
|
||||
uPathTransformExtDimensions,
|
||||
pathID);
|
||||
|
||||
vec2 position = dilatePosition(aPosition, aNormalAngle, uEmboldenAmount);
|
||||
position = hintPosition(position, uHints);
|
||||
position = transformVertexPositionAffine(position, pathTransformST, pathTransformExt);
|
||||
position = transformVertexPosition(position, uTransform);
|
||||
|
||||
float depth = convertPathIndexToViewportDepthValue(pathID);
|
||||
gl_Position = vec4(position, depth, 1.0);
|
||||
|
||||
vColor = fetchFloat4Data(uPathColors, pathID, uPathColorsDimensions);
|
||||
vTexCoord = vec2(aTexCoord) / 2.0;
|
||||
vSign = aSign;
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
// pathfinder/shaders/gles2/xcaa-multi-direct-interior.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 sampler2D uEdgeAlpha;
|
||||
uniform sampler2D uEdgeDepth;
|
||||
|
||||
varying vec4 vColor;
|
||||
|
||||
void main() {
|
||||
vec2 center = floor(gl_FragCoord.xy);
|
||||
float depth = gl_FragCoord.z;
|
||||
vec2 texCoord = floor(center) / vec2(uFramebufferSize);
|
||||
|
||||
vec4 color = vColor;
|
||||
if (depth == texture2D(uEdgeDepth, texCoord).r)
|
||||
color.a = texture2D(uEdgeAlpha, texCoord).r;
|
||||
|
||||
gl_FragColor = vColor;
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
// pathfinder/shaders/gles2/xcaa-multi-direct-interior.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;
|
||||
|
||||
uniform mat4 uTransform;
|
||||
uniform vec4 uHints;
|
||||
uniform vec2 uEmboldenAmount;
|
||||
uniform ivec2 uPathColorsDimensions;
|
||||
uniform sampler2D uPathColors;
|
||||
uniform ivec2 uPathTransformSTDimensions;
|
||||
uniform sampler2D uPathTransformST;
|
||||
uniform ivec2 uPathTransformExtDimensions;
|
||||
uniform sampler2D uPathTransformExt;
|
||||
|
||||
attribute vec2 aPosition;
|
||||
attribute float aPathID;
|
||||
attribute float aNormalAngle;
|
||||
|
||||
varying vec4 vColor;
|
||||
varying float vSign;
|
||||
|
||||
void main() {
|
||||
int pathID = int(aPathID);
|
||||
|
||||
vec2 pathTransformExt;
|
||||
vec4 pathTransformST = fetchPathAffineTransform(pathTransformExt,
|
||||
uPathTransformST,
|
||||
uPathTransformSTDimensions,
|
||||
uPathTransformExt,
|
||||
uPathTransformExtDimensions,
|
||||
pathID);
|
||||
|
||||
vec2 position = dilatePosition(aPosition, aNormalAngle, uEmboldenAmount);
|
||||
position = hintPosition(position, uHints);
|
||||
position = transformVertexPositionAffine(position, pathTransformST, pathTransformExt);
|
||||
position = transformVertexPosition(position, uTransform);
|
||||
|
||||
float depth = convertPathIndexToViewportDepthValue(pathID);
|
||||
gl_Position = vec4(position, depth, 1.0);
|
||||
|
||||
vColor = fetchFloat4Data(uPathColors, pathID, uPathColorsDimensions);
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
// pathfinder/shaders/gles2/xcaa-multi-edge-mask-curve.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;
|
||||
|
||||
varying vec4 vEndpoints;
|
||||
varying vec2 vControlPoint;
|
||||
|
||||
void main() {
|
||||
// Unpack.
|
||||
vec2 pixelCenter = gl_FragCoord.xy;
|
||||
vec2 p0 = vEndpoints.xy, p1 = vEndpoints.zw;
|
||||
vec2 cp = vControlPoint;
|
||||
|
||||
// Clip to left and right pixel boundaries.
|
||||
vec2 pixelColumnBounds = pixelCenter.xx + vec2(-0.5, 0.5);
|
||||
|
||||
// Clip the curve to the left and right edges to create a line.
|
||||
vec2 t = solveCurveT(p0.x, cp.x, p1.x, pixelColumnBounds);
|
||||
|
||||
// Handle endpoints properly. These tests are negated to handle NaNs.
|
||||
if (!(p0.x < pixelColumnBounds.x))
|
||||
t.x = 0.0;
|
||||
if (!(p1.x > pixelColumnBounds.y))
|
||||
t.y = 1.0;
|
||||
|
||||
vec2 clippedP0 = mix(mix(p0, cp, t.x), mix(cp, p1, t.x), t.x);
|
||||
vec2 clippedP1 = mix(mix(p0, cp, t.y), mix(cp, p1, t.y), t.y);
|
||||
|
||||
// Discard if not edge.
|
||||
if (!isPartiallyCovered(clippedP0, clippedP1 - clippedP0, pixelCenter.y))
|
||||
discard;
|
||||
gl_FragColor = vec4(1.0);
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
// pathfinder/shaders/gles2/xcaa-multi-edge-mask-line.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;
|
||||
|
||||
varying vec4 vEndpoints;
|
||||
|
||||
void main() {
|
||||
// Unpack.
|
||||
vec2 pixelCenter = gl_FragCoord.xy;
|
||||
vec2 p0 = vEndpoints.xy, p1 = vEndpoints.zw;
|
||||
|
||||
// Clip to left and right pixel boundaries.
|
||||
vec2 dP = p1 - p0;
|
||||
vec4 p0DPX = clipLineToPixelColumn(p0, dP, pixelCenter.x);
|
||||
|
||||
// Discard if not edge.
|
||||
if (!isPartiallyCovered(p0DPX.xy, p0DPX.zw, pixelCenter.y))
|
||||
discard;
|
||||
gl_FragColor = vec4(1.0);
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
// pathfinder/shaders/gles2/xcaa-multi-resolve.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 uPathColorsDimensions;
|
||||
uniform sampler2D uAAAlpha;
|
||||
uniform sampler2D uAADepth;
|
||||
uniform sampler2D uPathColors;
|
||||
|
||||
varying vec2 vTexCoord;
|
||||
|
||||
void main() {
|
||||
float edgeDepth = texture2D(uAADepth, vTexCoord).r;
|
||||
int edgePathID = convertWindowDepthValueToPathIndex(edgeDepth);
|
||||
vec4 edgeColor = fetchFloat4Data(uPathColors, edgePathID, uPathColorsDimensions);
|
||||
float edgeAlpha = abs(texture2D(uAAAlpha, vTexCoord).r);
|
||||
gl_FragColor = vec4(edgeColor.rgb, edgeColor.a * edgeAlpha);
|
||||
gl_FragDepthEXT = edgeDepth;
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
// pathfinder/shaders/gles2/xcaa-multi-resolve.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() {
|
||||
float depth = convertPathIndexToViewportDepthValue(0);
|
||||
gl_Position = vec4(mix(vec2(-1.0), vec2(1.0), aPosition), depth, 1.0);
|
||||
vTexCoord = aTexCoord;
|
||||
}
|
Loading…
Reference in New Issue