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 AntialiasingStrategyName = 'none' | 'ssaa' | 'xcaa';
|
||||||
|
|
||||||
export type DirectRenderingMode = 'none' | 'color' | 'color-depth';
|
export type DirectRenderingMode = 'none' | 'color';
|
||||||
|
|
||||||
export type SubpixelAAType = 'none' | 'medium';
|
export type SubpixelAAType = 'none' | 'medium';
|
||||||
|
|
||||||
|
@ -73,6 +73,9 @@ export abstract class AntialiasingStrategy {
|
||||||
abstract antialiasObject(renderer: Renderer, objectIndex: number): void;
|
abstract antialiasObject(renderer: Renderer, objectIndex: number): void;
|
||||||
|
|
||||||
// Called after antialiasing each object.
|
// 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;
|
abstract resolveAAForObject(renderer: Renderer, objectIndex: number): void;
|
||||||
|
|
||||||
// Called after antialiasing.
|
// Called after antialiasing.
|
||||||
|
@ -175,6 +178,8 @@ export class NoAAStrategy extends AntialiasingStrategy {
|
||||||
|
|
||||||
antialiasObject(renderer: Renderer, objectIndex: number): void {}
|
antialiasObject(renderer: Renderer, objectIndex: number): void {}
|
||||||
|
|
||||||
|
finishAntialiasingObject(renderer: Renderer, objectIndex: number): void {}
|
||||||
|
|
||||||
resolveAAForObject(renderer: Renderer): void {}
|
resolveAAForObject(renderer: Renderer): void {}
|
||||||
|
|
||||||
resolve(pass: number, 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`.
|
// FIXME(pcwalton): This duplicates information below in `MESH_TYPES`.
|
||||||
const INDEX_SIZE: number = 4;
|
const INDEX_SIZE: number = 4;
|
||||||
|
const B_QUAD_VERTEX_POSITION_SIZE: number = 12 * 4;
|
||||||
const B_VERTEX_POSITION_SIZE: number = 4 * 2;
|
const B_VERTEX_POSITION_SIZE: number = 4 * 2;
|
||||||
const EDGE_BOUNDING_BOX_VERTEX_POSITION_SIZE: number = 4 * 4;
|
const EDGE_BOUNDING_BOX_VERTEX_POSITION_SIZE: number = 4 * 4;
|
||||||
const EDGE_UPPER_LINE_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 SEGMENT_CURVE_SIZE: number = 4 * 6;
|
||||||
|
|
||||||
const MESH_TYPES: Meshes<MeshBufferTypeDescriptor> = {
|
const MESH_TYPES: Meshes<MeshBufferTypeDescriptor> = {
|
||||||
|
bQuadVertexPositions: { type: 'Float32', size: 12 },
|
||||||
bQuads: { type: 'Uint32', size: B_QUAD_FIELD_COUNT },
|
bQuads: { type: 'Uint32', size: B_QUAD_FIELD_COUNT },
|
||||||
bVertexLoopBlinnData: { type: 'Uint32', size: 1 },
|
bVertexLoopBlinnData: { type: 'Uint32', size: 1 },
|
||||||
bVertexNormals: { type: 'Float32', size: 1 },
|
bVertexNormals: { type: 'Float32', size: 1 },
|
||||||
|
@ -112,6 +114,7 @@ const MESH_TYPES: Meshes<MeshBufferTypeDescriptor> = {
|
||||||
};
|
};
|
||||||
|
|
||||||
const BUFFER_TYPES: Meshes<BufferType> = {
|
const BUFFER_TYPES: Meshes<BufferType> = {
|
||||||
|
bQuadVertexPositions: 'ARRAY_BUFFER',
|
||||||
bQuads: 'ARRAY_BUFFER',
|
bQuads: 'ARRAY_BUFFER',
|
||||||
bVertexLoopBlinnData: 'ARRAY_BUFFER',
|
bVertexLoopBlinnData: 'ARRAY_BUFFER',
|
||||||
bVertexNormals: '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()`.
|
// Must match the FourCCs in `pathfinder_partitioner::mesh_library::MeshLibrary::serialize_into()`.
|
||||||
const BUFFER_TYPE_FOURCCS: BufferTypeFourCCTable = {
|
const BUFFER_TYPE_FOURCCS: BufferTypeFourCCTable = {
|
||||||
bqua: 'bQuads',
|
bqua: 'bQuads',
|
||||||
|
bqvp: 'bQuadVertexPositions',
|
||||||
bvlb: 'bVertexLoopBlinnData',
|
bvlb: 'bVertexLoopBlinnData',
|
||||||
bvno: 'bVertexNormals',
|
bvno: 'bVertexNormals',
|
||||||
bvpo: 'bVertexPositions',
|
bvpo: 'bVertexPositions',
|
||||||
|
@ -166,6 +170,7 @@ const BUFFER_TYPE_FOURCCS: BufferTypeFourCCTable = {
|
||||||
// `pathfinder_partitioner::mesh_library::MeshLibrary::serialize_into::write_path_ranges()`.
|
// `pathfinder_partitioner::mesh_library::MeshLibrary::serialize_into::write_path_ranges()`.
|
||||||
const PATH_RANGE_TYPE_FOURCCS: PathRangeTypeFourCCTable = {
|
const PATH_RANGE_TYPE_FOURCCS: PathRangeTypeFourCCTable = {
|
||||||
bqua: 'bQuadPathRanges',
|
bqua: 'bQuadPathRanges',
|
||||||
|
bqvp: 'bQuadVertexPositionPathRanges',
|
||||||
bver: 'bVertexPathRanges',
|
bver: 'bVertexPathRanges',
|
||||||
cvci: 'coverCurveIndexRanges',
|
cvci: 'coverCurveIndexRanges',
|
||||||
cvii: 'coverInteriorIndexRanges',
|
cvii: 'coverInteriorIndexRanges',
|
||||||
|
@ -180,6 +185,7 @@ const PATH_RANGE_TYPE_FOURCCS: PathRangeTypeFourCCTable = {
|
||||||
|
|
||||||
const RANGE_TO_COUNT_TABLE: RangeToCountTable = {
|
const RANGE_TO_COUNT_TABLE: RangeToCountTable = {
|
||||||
bQuadPathRanges: 'bQuadCount',
|
bQuadPathRanges: 'bQuadCount',
|
||||||
|
bQuadVertexPositionPathRanges: 'bQuadVertexPositionCount',
|
||||||
bVertexPathRanges: 'bVertexCount',
|
bVertexPathRanges: 'bVertexCount',
|
||||||
coverCurveIndexRanges: 'coverCurveCount',
|
coverCurveIndexRanges: 'coverCurveCount',
|
||||||
coverInteriorIndexRanges: 'coverInteriorCount',
|
coverInteriorIndexRanges: 'coverInteriorCount',
|
||||||
|
@ -205,6 +211,7 @@ const RANGE_TO_RANGE_BUFFER_TABLE: RangeToRangeBufferTable = {
|
||||||
|
|
||||||
const RANGE_KEYS: Array<keyof PathRanges> = [
|
const RANGE_KEYS: Array<keyof PathRanges> = [
|
||||||
'bQuadPathRanges',
|
'bQuadPathRanges',
|
||||||
|
'bQuadVertexPositionPathRanges',
|
||||||
'bVertexPathRanges',
|
'bVertexPathRanges',
|
||||||
'coverInteriorIndexRanges',
|
'coverInteriorIndexRanges',
|
||||||
'coverCurveIndexRanges',
|
'coverCurveIndexRanges',
|
||||||
|
@ -221,6 +228,7 @@ type BufferType = 'ARRAY_BUFFER' | 'ELEMENT_ARRAY_BUFFER';
|
||||||
|
|
||||||
export interface Meshes<T> {
|
export interface Meshes<T> {
|
||||||
readonly bQuads: T;
|
readonly bQuads: T;
|
||||||
|
readonly bQuadVertexPositions: T;
|
||||||
readonly bVertexPositions: T;
|
readonly bVertexPositions: T;
|
||||||
readonly bVertexLoopBlinnData: T;
|
readonly bVertexLoopBlinnData: T;
|
||||||
readonly bVertexNormals: T;
|
readonly bVertexNormals: T;
|
||||||
|
@ -248,6 +256,7 @@ export interface Meshes<T> {
|
||||||
|
|
||||||
interface MeshDataCounts {
|
interface MeshDataCounts {
|
||||||
readonly bQuadCount: number;
|
readonly bQuadCount: number;
|
||||||
|
readonly bQuadVertexPositionCount: number;
|
||||||
readonly bVertexCount: number;
|
readonly bVertexCount: number;
|
||||||
readonly coverCurveCount: number;
|
readonly coverCurveCount: number;
|
||||||
readonly coverInteriorCount: number;
|
readonly coverInteriorCount: number;
|
||||||
|
@ -262,6 +271,7 @@ interface MeshDataCounts {
|
||||||
|
|
||||||
interface PathRanges {
|
interface PathRanges {
|
||||||
bQuadPathRanges: Range[];
|
bQuadPathRanges: Range[];
|
||||||
|
bQuadVertexPositionPathRanges: Range[];
|
||||||
bVertexPathRanges: Range[];
|
bVertexPathRanges: Range[];
|
||||||
coverInteriorIndexRanges: Range[];
|
coverInteriorIndexRanges: Range[];
|
||||||
coverCurveIndexRanges: Range[];
|
coverCurveIndexRanges: Range[];
|
||||||
|
@ -276,6 +286,7 @@ interface PathRanges {
|
||||||
|
|
||||||
export class PathfinderMeshData implements Meshes<ArrayBuffer>, MeshDataCounts, PathRanges {
|
export class PathfinderMeshData implements Meshes<ArrayBuffer>, MeshDataCounts, PathRanges {
|
||||||
readonly bQuads: ArrayBuffer;
|
readonly bQuads: ArrayBuffer;
|
||||||
|
readonly bQuadVertexPositions: ArrayBuffer;
|
||||||
readonly bVertexPositions: ArrayBuffer;
|
readonly bVertexPositions: ArrayBuffer;
|
||||||
readonly bVertexLoopBlinnData: ArrayBuffer;
|
readonly bVertexLoopBlinnData: ArrayBuffer;
|
||||||
readonly bVertexNormals: ArrayBuffer;
|
readonly bVertexNormals: ArrayBuffer;
|
||||||
|
@ -292,6 +303,7 @@ export class PathfinderMeshData implements Meshes<ArrayBuffer>, MeshDataCounts,
|
||||||
readonly segmentCurveNormals: ArrayBuffer;
|
readonly segmentCurveNormals: ArrayBuffer;
|
||||||
|
|
||||||
readonly bQuadCount: number;
|
readonly bQuadCount: number;
|
||||||
|
readonly bQuadVertexPositionCount: number;
|
||||||
readonly bVertexCount: number;
|
readonly bVertexCount: number;
|
||||||
readonly coverCurveCount: number;
|
readonly coverCurveCount: number;
|
||||||
readonly coverInteriorCount: number;
|
readonly coverInteriorCount: number;
|
||||||
|
@ -313,6 +325,7 @@ export class PathfinderMeshData implements Meshes<ArrayBuffer>, MeshDataCounts,
|
||||||
segmentLinePathIDs: ArrayBuffer;
|
segmentLinePathIDs: ArrayBuffer;
|
||||||
|
|
||||||
bQuadPathRanges: Range[];
|
bQuadPathRanges: Range[];
|
||||||
|
bQuadVertexPositionPathRanges: Range[];
|
||||||
bVertexPathRanges: Range[];
|
bVertexPathRanges: Range[];
|
||||||
coverInteriorIndexRanges: Range[];
|
coverInteriorIndexRanges: Range[];
|
||||||
coverCurveIndexRanges: Range[];
|
coverCurveIndexRanges: Range[];
|
||||||
|
@ -356,6 +369,8 @@ export class PathfinderMeshData implements Meshes<ArrayBuffer>, MeshDataCounts,
|
||||||
}
|
}
|
||||||
|
|
||||||
this.bQuadCount = this.bQuads.byteLength / B_QUAD_SIZE;
|
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.bVertexCount = this.bVertexPositions.byteLength / B_VERTEX_POSITION_SIZE;
|
||||||
this.coverCurveCount = this.coverCurveIndices.byteLength / INDEX_SIZE;
|
this.coverCurveCount = this.coverCurveIndices.byteLength / INDEX_SIZE;
|
||||||
this.coverInteriorCount = this.coverInteriorIndices.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 firstBVertexIndex = bVertexCopyResult.originalStartIndex;
|
||||||
const lastBVertexIndex = bVertexCopyResult.originalEndIndex;
|
const lastBVertexIndex = bVertexCopyResult.originalEndIndex;
|
||||||
|
|
||||||
|
// Copy over B-quad vertex positions.
|
||||||
|
copyVertices(['bQuadVertexPositions'],
|
||||||
|
'bQuadVertexPositionPathRanges',
|
||||||
|
expandedArrays,
|
||||||
|
expandedRanges,
|
||||||
|
originalBuffers,
|
||||||
|
originalRanges,
|
||||||
|
expandedPathID,
|
||||||
|
originalPathID);
|
||||||
|
|
||||||
// Copy over edge data.
|
// Copy over edge data.
|
||||||
copyVertices(['edgeBoundingBoxVertexPositions'],
|
copyVertices(['edgeBoundingBoxVertexPositions'],
|
||||||
'edgeBoundingBoxRanges',
|
'edgeBoundingBoxRanges',
|
||||||
|
@ -555,6 +580,7 @@ export class PathfinderMeshData implements Meshes<ArrayBuffer>, MeshDataCounts,
|
||||||
|
|
||||||
export class PathfinderMeshBuffers implements Meshes<WebGLBuffer>, PathRanges {
|
export class PathfinderMeshBuffers implements Meshes<WebGLBuffer>, PathRanges {
|
||||||
readonly bQuads: WebGLBuffer;
|
readonly bQuads: WebGLBuffer;
|
||||||
|
readonly bQuadVertexPositions: WebGLBuffer;
|
||||||
readonly bVertexPositions: WebGLBuffer;
|
readonly bVertexPositions: WebGLBuffer;
|
||||||
readonly bVertexPathIDs: WebGLBuffer;
|
readonly bVertexPathIDs: WebGLBuffer;
|
||||||
readonly bVertexLoopBlinnData: WebGLBuffer;
|
readonly bVertexLoopBlinnData: WebGLBuffer;
|
||||||
|
@ -579,6 +605,7 @@ export class PathfinderMeshBuffers implements Meshes<WebGLBuffer>, PathRanges {
|
||||||
readonly segmentCurveNormals: WebGLBuffer;
|
readonly segmentCurveNormals: WebGLBuffer;
|
||||||
|
|
||||||
readonly bQuadPathRanges: Range[];
|
readonly bQuadPathRanges: Range[];
|
||||||
|
readonly bQuadVertexPositionPathRanges: Range[];
|
||||||
readonly bVertexPathRanges: Range[];
|
readonly bVertexPathRanges: Range[];
|
||||||
readonly coverInteriorIndexRanges: Range[];
|
readonly coverInteriorIndexRanges: Range[];
|
||||||
readonly coverCurveIndexRanges: Range[];
|
readonly coverCurveIndexRanges: Range[];
|
||||||
|
|
|
@ -22,7 +22,6 @@ import {CompositingOperation, RenderTaskType} from './render-task';
|
||||||
import {ShaderMap} from './shader-loader';
|
import {ShaderMap} from './shader-loader';
|
||||||
import {FLOAT32_SIZE, Range, UINT16_SIZE, UINT32_SIZE, unwrapNull, unwrapUndef} from './utils';
|
import {FLOAT32_SIZE, Range, UINT16_SIZE, UINT32_SIZE, unwrapNull, unwrapUndef} from './utils';
|
||||||
import {RenderContext, Timings} from "./view";
|
import {RenderContext, Timings} from "./view";
|
||||||
import {ECAAMulticolorStrategy} from './xcaa-strategy';
|
|
||||||
|
|
||||||
const MAX_PATHS: number = 65535;
|
const MAX_PATHS: number = 65535;
|
||||||
|
|
||||||
|
@ -161,11 +160,14 @@ export abstract class Renderer {
|
||||||
// Antialias.
|
// Antialias.
|
||||||
antialiasingStrategy.antialiasObject(this, objectIndex);
|
antialiasingStrategy.antialiasObject(this, objectIndex);
|
||||||
|
|
||||||
// Prepare for direct rendering.
|
// Perform post-antialiasing tasks.
|
||||||
antialiasingStrategy.prepareToRenderObject(this, objectIndex);
|
antialiasingStrategy.finishAntialiasingObject(this, objectIndex);
|
||||||
|
|
||||||
// Perform direct rendering (Loop-Blinn).
|
// Perform direct rendering (Loop-Blinn).
|
||||||
if (antialiasingStrategy.directRenderingMode !== 'none') {
|
if (antialiasingStrategy.directRenderingMode !== 'none') {
|
||||||
|
// Prepare for direct rendering.
|
||||||
|
antialiasingStrategy.prepareToRenderObject(this, objectIndex);
|
||||||
|
|
||||||
// Clear.
|
// Clear.
|
||||||
this.clearForDirectRendering(objectIndex);
|
this.clearForDirectRendering(objectIndex);
|
||||||
|
|
||||||
|
@ -420,9 +422,6 @@ export abstract class Renderer {
|
||||||
gl.depthMask(true);
|
gl.depthMask(true);
|
||||||
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
||||||
break;
|
break;
|
||||||
case 'color-depth':
|
|
||||||
gl.clear(gl.COLOR_BUFFER_BIT);
|
|
||||||
break;
|
|
||||||
case 'none':
|
case 'none':
|
||||||
// Nothing to do.
|
// Nothing to do.
|
||||||
break;
|
break;
|
||||||
|
@ -496,10 +495,6 @@ export abstract class Renderer {
|
||||||
this.pathTransformBufferTextures[meshIndex]
|
this.pathTransformBufferTextures[meshIndex]
|
||||||
.ext
|
.ext
|
||||||
.bind(gl, directInteriorProgram.uniforms, 2);
|
.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);
|
const coverInteriorRange = getMeshIndexRange(meshes.coverInteriorIndexRanges, pathRange);
|
||||||
if (!this.pathIDsAreInstanced) {
|
if (!this.pathIDsAreInstanced) {
|
||||||
gl.drawElements(gl.TRIANGLES,
|
gl.drawElements(gl.TRIANGLES,
|
||||||
|
@ -516,7 +511,7 @@ export abstract class Renderer {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set up direct curve state.
|
// Set up direct curve state.
|
||||||
gl.depthMask(renderingMode === 'color-depth');
|
gl.depthMask(false);
|
||||||
gl.enable(gl.BLEND);
|
gl.enable(gl.BLEND);
|
||||||
gl.blendEquation(gl.FUNC_ADD);
|
gl.blendEquation(gl.FUNC_ADD);
|
||||||
gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE);
|
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.setEmboldenAmountUniform(objectIndex, directCurveProgram.uniforms);
|
||||||
this.pathTransformBufferTextures[meshIndex].st.bind(gl, directCurveProgram.uniforms, 1);
|
this.pathTransformBufferTextures[meshIndex].st.bind(gl, directCurveProgram.uniforms, 1);
|
||||||
this.pathTransformBufferTextures[meshIndex].ext.bind(gl, directCurveProgram.uniforms, 2);
|
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);
|
const coverCurveRange = getMeshIndexRange(meshes.coverCurveIndexRanges, pathRange);
|
||||||
if (!this.pathIDsAreInstanced) {
|
if (!this.pathIDsAreInstanced) {
|
||||||
gl.drawElements(gl.TRIANGLES,
|
gl.drawElements(gl.TRIANGLES,
|
||||||
|
|
|
@ -27,15 +27,10 @@ export interface ShaderMap<T> {
|
||||||
mcaaCover: T;
|
mcaaCover: T;
|
||||||
mcaaLine: T;
|
mcaaLine: T;
|
||||||
mcaaCurve: T;
|
mcaaCurve: T;
|
||||||
|
mcaaMulti: T;
|
||||||
ssaaSubpixelResolve: T;
|
ssaaSubpixelResolve: T;
|
||||||
xcaaMonoResolve: T;
|
xcaaMonoResolve: T;
|
||||||
xcaaMonoSubpixelResolve: T;
|
xcaaMonoSubpixelResolve: T;
|
||||||
xcaaMultiDirectCurve: T;
|
|
||||||
xcaaMultiDirectInterior: T;
|
|
||||||
xcaaMultiEdgeMaskCurve: T;
|
|
||||||
xcaaMultiEdgeMaskTransformedCurve: T;
|
|
||||||
xcaaMultiEdgeMaskLine: T;
|
|
||||||
xcaaMultiResolve: T;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface UnlinkedShaderProgram {
|
export interface UnlinkedShaderProgram {
|
||||||
|
@ -57,17 +52,12 @@ export const SHADER_NAMES: Array<keyof ShaderMap<void>> = [
|
||||||
'mcaaCover',
|
'mcaaCover',
|
||||||
'mcaaLine',
|
'mcaaLine',
|
||||||
'mcaaCurve',
|
'mcaaCurve',
|
||||||
|
'mcaaMulti',
|
||||||
'ecaaLine',
|
'ecaaLine',
|
||||||
'ecaaCurve',
|
'ecaaCurve',
|
||||||
'ecaaTransformedCurve',
|
'ecaaTransformedCurve',
|
||||||
'xcaaMonoResolve',
|
'xcaaMonoResolve',
|
||||||
'xcaaMonoSubpixelResolve',
|
'xcaaMonoSubpixelResolve',
|
||||||
'xcaaMultiDirectCurve',
|
|
||||||
'xcaaMultiDirectInterior',
|
|
||||||
'xcaaMultiEdgeMaskCurve',
|
|
||||||
'xcaaMultiEdgeMaskTransformedCurve',
|
|
||||||
'xcaaMultiEdgeMaskLine',
|
|
||||||
'xcaaMultiResolve',
|
|
||||||
'demo3DDistantGlyph',
|
'demo3DDistantGlyph',
|
||||||
'demo3DMonument',
|
'demo3DMonument',
|
||||||
];
|
];
|
||||||
|
@ -133,6 +123,10 @@ const SHADER_URLS: ShaderMap<ShaderProgramURLs> = {
|
||||||
fragment: "/glsl/gles2/xcaa-line.fs.glsl",
|
fragment: "/glsl/gles2/xcaa-line.fs.glsl",
|
||||||
vertex: "/glsl/gles2/mcaa-line.vs.glsl",
|
vertex: "/glsl/gles2/mcaa-line.vs.glsl",
|
||||||
},
|
},
|
||||||
|
mcaaMulti: {
|
||||||
|
fragment: "/glsl/gles2/mcaa-multi.fs.glsl",
|
||||||
|
vertex: "/glsl/gles2/mcaa-multi.vs.glsl",
|
||||||
|
},
|
||||||
ssaaSubpixelResolve: {
|
ssaaSubpixelResolve: {
|
||||||
fragment: "/glsl/gles2/ssaa-subpixel-resolve.fs.glsl",
|
fragment: "/glsl/gles2/ssaa-subpixel-resolve.fs.glsl",
|
||||||
vertex: "/glsl/gles2/blit.vs.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",
|
fragment: "/glsl/gles2/xcaa-mono-subpixel-resolve.fs.glsl",
|
||||||
vertex: "/glsl/gles2/xcaa-mono-subpixel-resolve.vs.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 {
|
export interface ShaderProgramSource {
|
||||||
|
|
|
@ -167,6 +167,8 @@ export default class SSAAStrategy extends AntialiasingStrategy {
|
||||||
|
|
||||||
antialiasObject(renderer: Renderer): void {}
|
antialiasObject(renderer: Renderer): void {}
|
||||||
|
|
||||||
|
finishAntialiasingObject(renderer: Renderer, objectIndex: number): void {}
|
||||||
|
|
||||||
resolveAAForObject(renderer: Renderer): void {}
|
resolveAAForObject(renderer: Renderer): void {}
|
||||||
|
|
||||||
resolve(pass: number, renderer: Renderer): void {
|
resolve(pass: number, renderer: Renderer): void {
|
||||||
|
|
|
@ -22,7 +22,7 @@ import SSAAStrategy from './ssaa-strategy';
|
||||||
import {SVGLoader} from './svg-loader';
|
import {SVGLoader} from './svg-loader';
|
||||||
import {Range} from './utils';
|
import {Range} from './utils';
|
||||||
import {RenderContext} from './view';
|
import {RenderContext} from './view';
|
||||||
import {ECAAMulticolorStrategy, XCAAStrategy} from './xcaa-strategy';
|
import {MCAAMulticolorStrategy, XCAAStrategy} from './xcaa-strategy';
|
||||||
|
|
||||||
interface AntialiasingStrategyTable {
|
interface AntialiasingStrategyTable {
|
||||||
none: typeof NoAAStrategy;
|
none: typeof NoAAStrategy;
|
||||||
|
@ -33,7 +33,7 @@ interface AntialiasingStrategyTable {
|
||||||
const ANTIALIASING_STRATEGIES: AntialiasingStrategyTable = {
|
const ANTIALIASING_STRATEGIES: AntialiasingStrategyTable = {
|
||||||
none: NoAAStrategy,
|
none: NoAAStrategy,
|
||||||
ssaa: SSAAStrategy,
|
ssaa: SSAAStrategy,
|
||||||
xcaa: ECAAMulticolorStrategy,
|
xcaa: MCAAMulticolorStrategy,
|
||||||
};
|
};
|
||||||
|
|
||||||
export abstract class SVGRenderer extends Renderer {
|
export abstract class SVGRenderer extends Renderer {
|
||||||
|
@ -41,6 +41,14 @@ export abstract class SVGRenderer extends Renderer {
|
||||||
|
|
||||||
camera: OrthographicCamera;
|
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 {
|
get usesSTTransform(): boolean {
|
||||||
return this.camera.usesSTTransform;
|
return this.camera.usesSTTransform;
|
||||||
}
|
}
|
||||||
|
@ -150,14 +158,10 @@ export abstract class SVGRenderer extends Renderer {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected directCurveProgramName(): keyof ShaderMap<void> {
|
protected directCurveProgramName(): keyof ShaderMap<void> {
|
||||||
if (this.antialiasingStrategy instanceof XCAAStrategy)
|
|
||||||
return 'xcaaMultiDirectCurve';
|
|
||||||
return 'directCurve';
|
return 'directCurve';
|
||||||
}
|
}
|
||||||
|
|
||||||
protected directInteriorProgramName(): keyof ShaderMap<void> {
|
protected directInteriorProgramName(): keyof ShaderMap<void> {
|
||||||
if (this.antialiasingStrategy instanceof XCAAStrategy)
|
|
||||||
return 'xcaaMultiDirectInterior';
|
|
||||||
return 'directInterior';
|
return 'directInterior';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,6 +41,7 @@ export abstract class XCAAStrategy extends AntialiasingStrategy {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract get usesDilationTransforms(): boolean;
|
protected abstract get usesDilationTransforms(): boolean;
|
||||||
|
protected abstract get usesAAFramebuffer(): boolean;
|
||||||
|
|
||||||
protected pathBoundsBufferTexture: PathfinderBufferTexture;
|
protected pathBoundsBufferTexture: PathfinderBufferTexture;
|
||||||
|
|
||||||
|
@ -49,11 +50,11 @@ export abstract class XCAAStrategy extends AntialiasingStrategy {
|
||||||
|
|
||||||
protected subpixelAA: SubpixelAAType;
|
protected subpixelAA: SubpixelAAType;
|
||||||
|
|
||||||
protected resolveVAO: WebGLVertexArrayObject;
|
protected resolveVAO: WebGLVertexArrayObject | null;
|
||||||
|
|
||||||
protected aaAlphaTexture: WebGLTexture;
|
protected aaAlphaTexture: WebGLTexture | null;
|
||||||
protected aaDepthTexture: WebGLTexture;
|
protected aaDepthTexture: WebGLTexture | null;
|
||||||
protected aaFramebuffer: WebGLFramebuffer;
|
protected aaFramebuffer: WebGLFramebuffer | null;
|
||||||
|
|
||||||
protected renderTargetColorTextures: WebGLTexture[];
|
protected renderTargetColorTextures: WebGLTexture[];
|
||||||
protected renderTargetDepthTextures: WebGLTexture[];
|
protected renderTargetDepthTextures: WebGLTexture[];
|
||||||
|
@ -98,23 +99,27 @@ export abstract class XCAAStrategy extends AntialiasingStrategy {
|
||||||
|
|
||||||
prepareForDirectRendering(renderer: Renderer): void {}
|
prepareForDirectRendering(renderer: Renderer): void {}
|
||||||
|
|
||||||
prepareToRenderObject(renderer: Renderer, objectIndex: number): void {
|
finishAntialiasingObject(renderer: Renderer, objectIndex: number): void {
|
||||||
const renderContext = renderer.renderContext;
|
const renderContext = renderer.renderContext;
|
||||||
const gl = renderContext.gl;
|
const gl = renderContext.gl;
|
||||||
|
|
||||||
this.initResolveFramebufferForObject(renderer, objectIndex);
|
this.initResolveFramebufferForObject(renderer, objectIndex);
|
||||||
|
|
||||||
const usedSize = this.supersampledUsedSize(renderer);
|
if (this.usesAAFramebuffer) {
|
||||||
gl.scissor(0, 0, usedSize[0], usedSize[1]);
|
const usedSize = this.supersampledUsedSize(renderer);
|
||||||
gl.enable(gl.SCISSOR_TEST);
|
gl.scissor(0, 0, usedSize[0], usedSize[1]);
|
||||||
|
gl.enable(gl.SCISSOR_TEST);
|
||||||
|
|
||||||
// Clear out the color and depth textures.
|
// Clear out the color and depth textures.
|
||||||
gl.clearColor(1.0, 1.0, 1.0, 1.0);
|
gl.clearColor(1.0, 1.0, 1.0, 1.0);
|
||||||
gl.clearDepth(0.0);
|
gl.clearDepth(0.0);
|
||||||
gl.depthMask(true);
|
gl.depthMask(true);
|
||||||
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
prepareToRenderObject(renderer: Renderer, objectIndex: number): void {}
|
||||||
|
|
||||||
finishDirectlyRenderingObject(renderer: Renderer, objectIndex: number): void {
|
finishDirectlyRenderingObject(renderer: Renderer, objectIndex: number): void {
|
||||||
// TODO(pcwalton)
|
// TODO(pcwalton)
|
||||||
}
|
}
|
||||||
|
@ -123,9 +128,6 @@ export abstract class XCAAStrategy extends AntialiasingStrategy {
|
||||||
// Perform early preparations.
|
// Perform early preparations.
|
||||||
this.createPathBoundsBufferTextureForObject(renderer, objectIndex);
|
this.createPathBoundsBufferTextureForObject(renderer, objectIndex);
|
||||||
|
|
||||||
// Mask edges if necessary.
|
|
||||||
this.maskEdgesOfObjectIfNecessary(renderer, objectIndex);
|
|
||||||
|
|
||||||
// Set up antialiasing.
|
// Set up antialiasing.
|
||||||
this.prepareAA(renderer);
|
this.prepareAA(renderer);
|
||||||
|
|
||||||
|
@ -137,6 +139,10 @@ export abstract class XCAAStrategy extends AntialiasingStrategy {
|
||||||
const renderContext = renderer.renderContext;
|
const renderContext = renderer.renderContext;
|
||||||
const gl = renderContext.gl;
|
const gl = renderContext.gl;
|
||||||
|
|
||||||
|
const resolveProgram = this.getResolveProgram(renderContext);
|
||||||
|
if (resolveProgram == null)
|
||||||
|
return;
|
||||||
|
|
||||||
// Set state for ECAA resolve.
|
// Set state for ECAA resolve.
|
||||||
const usedSize = renderer.destUsedSize;
|
const usedSize = renderer.destUsedSize;
|
||||||
gl.scissor(0, 0, usedSize[0], usedSize[1]);
|
gl.scissor(0, 0, usedSize[0], usedSize[1]);
|
||||||
|
@ -147,7 +153,6 @@ export abstract class XCAAStrategy extends AntialiasingStrategy {
|
||||||
this.clearForResolve(renderer);
|
this.clearForResolve(renderer);
|
||||||
|
|
||||||
// Resolve.
|
// Resolve.
|
||||||
const resolveProgram = this.getResolveProgram(renderContext);
|
|
||||||
gl.useProgram(resolveProgram.program);
|
gl.useProgram(resolveProgram.program);
|
||||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(this.resolveVAO);
|
renderContext.vertexArrayObjectExt.bindVertexArrayOES(this.resolveVAO);
|
||||||
gl.uniform2i(resolveProgram.uniforms.uFramebufferSize,
|
gl.uniform2i(resolveProgram.uniforms.uFramebufferSize,
|
||||||
|
@ -257,8 +262,8 @@ export abstract class XCAAStrategy extends AntialiasingStrategy {
|
||||||
void {}
|
void {}
|
||||||
|
|
||||||
protected abstract clearForAA(renderer: Renderer): void;
|
protected abstract clearForAA(renderer: Renderer): void;
|
||||||
protected abstract getResolveProgram(renderContext: RenderContext): PathfinderShaderProgram;
|
protected abstract getResolveProgram(renderContext: RenderContext):
|
||||||
protected abstract maskEdgesOfObjectIfNecessary(renderer: Renderer, objectIndex: number): void;
|
PathfinderShaderProgram | null;
|
||||||
protected abstract setAADepthState(renderer: Renderer): void;
|
protected abstract setAADepthState(renderer: Renderer): void;
|
||||||
protected abstract clearForResolve(renderer: Renderer): void;
|
protected abstract clearForResolve(renderer: Renderer): void;
|
||||||
|
|
||||||
|
@ -295,6 +300,13 @@ export abstract class XCAAStrategy extends AntialiasingStrategy {
|
||||||
}
|
}
|
||||||
|
|
||||||
private initAAAlphaFramebuffer(renderer: Renderer): void {
|
private initAAAlphaFramebuffer(renderer: Renderer): void {
|
||||||
|
if (!this.usesAAFramebuffer) {
|
||||||
|
this.aaAlphaTexture = null;
|
||||||
|
this.aaDepthTexture = null;
|
||||||
|
this.aaFramebuffer = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const renderContext = renderer.renderContext;
|
const renderContext = renderer.renderContext;
|
||||||
const gl = renderContext.gl;
|
const gl = renderContext.gl;
|
||||||
|
|
||||||
|
@ -329,10 +341,13 @@ export abstract class XCAAStrategy extends AntialiasingStrategy {
|
||||||
const renderContext = renderer.renderContext;
|
const renderContext = renderer.renderContext;
|
||||||
const gl = renderContext.gl;
|
const gl = renderContext.gl;
|
||||||
|
|
||||||
|
const resolveProgram = this.getResolveProgram(renderContext);
|
||||||
|
if (resolveProgram == null)
|
||||||
|
return;
|
||||||
|
|
||||||
this.resolveVAO = renderContext.vertexArrayObjectExt.createVertexArrayOES();
|
this.resolveVAO = renderContext.vertexArrayObjectExt.createVertexArrayOES();
|
||||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(this.resolveVAO);
|
renderContext.vertexArrayObjectExt.bindVertexArrayOES(this.resolveVAO);
|
||||||
|
|
||||||
const resolveProgram = this.getResolveProgram(renderContext);
|
|
||||||
gl.useProgram(resolveProgram.program);
|
gl.useProgram(resolveProgram.program);
|
||||||
renderContext.initQuadVAO(resolveProgram.attributes);
|
renderContext.initQuadVAO(resolveProgram.attributes);
|
||||||
|
|
||||||
|
@ -348,15 +363,20 @@ export abstract class XCAAStrategy extends AntialiasingStrategy {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export abstract class MCAAStrategy extends XCAAStrategy {
|
export class MCAAMonochromeStrategy extends XCAAStrategy {
|
||||||
private coverVAO: WebGLVertexArrayObject;
|
protected coverVAO: WebGLVertexArrayObject | null;
|
||||||
private lineVAOs: FastEdgeVAOs;
|
|
||||||
private curveVAOs: FastEdgeVAOs;
|
protected lineVAOs: FastEdgeVAOs;
|
||||||
|
protected curveVAOs: FastEdgeVAOs;
|
||||||
|
|
||||||
|
protected get usesDilationTransforms(): boolean {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
attachMeshes(renderer: Renderer): void {
|
attachMeshes(renderer: Renderer): void {
|
||||||
super.attachMeshes(renderer);
|
super.attachMeshes(renderer);
|
||||||
|
|
||||||
this.createCoverVAO(renderer);
|
this.createCoverVAOIfNecessary(renderer);
|
||||||
this.createLineVAOs(renderer);
|
this.createLineVAOs(renderer);
|
||||||
this.createCurveVAOs(renderer);
|
this.createCurveVAOs(renderer);
|
||||||
}
|
}
|
||||||
|
@ -365,13 +385,58 @@ export abstract class MCAAStrategy extends XCAAStrategy {
|
||||||
super.antialiasObject(renderer, objectIndex);
|
super.antialiasObject(renderer, objectIndex);
|
||||||
|
|
||||||
// Conservatively cover.
|
// Conservatively cover.
|
||||||
this.coverObject(renderer, objectIndex);
|
this.coverObjectIfNecessary(renderer, objectIndex);
|
||||||
|
|
||||||
// Antialias.
|
// Antialias.
|
||||||
this.antialiasLinesOfObject(renderer, objectIndex);
|
this.antialiasLinesOfObject(renderer, objectIndex);
|
||||||
this.antialiasCurvesOfObject(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 {
|
protected prepareAA(renderer: Renderer): void {
|
||||||
super.prepareAA(renderer);
|
super.prepareAA(renderer);
|
||||||
|
|
||||||
|
@ -415,7 +480,7 @@ export abstract class MCAAStrategy extends XCAAStrategy {
|
||||||
const vao = this.lineVAOs[direction];
|
const vao = this.lineVAOs[direction];
|
||||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(vao);
|
renderContext.vertexArrayObjectExt.bindVertexArrayOES(vao);
|
||||||
|
|
||||||
this.setBlendModeForAA(renderer, direction);
|
this.setBlendModeForAA(renderer);
|
||||||
gl.uniform1i(uniforms.uWinding, direction === 'upper' ? 1 : 0);
|
gl.uniform1i(uniforms.uWinding, direction === 'upper' ? 1 : 0);
|
||||||
|
|
||||||
const indexRanges = {
|
const indexRanges = {
|
||||||
|
@ -431,6 +496,113 @@ export abstract class MCAAStrategy extends XCAAStrategy {
|
||||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(null);
|
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,
|
protected antialiasCurvesOfObjectWithProgram(renderer: Renderer,
|
||||||
objectIndex: number,
|
objectIndex: number,
|
||||||
curveProgram: PathfinderShaderProgram):
|
curveProgram: PathfinderShaderProgram):
|
||||||
|
@ -454,7 +626,7 @@ export abstract class MCAAStrategy extends XCAAStrategy {
|
||||||
const vao = this.curveVAOs[direction];
|
const vao = this.curveVAOs[direction];
|
||||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(vao);
|
renderContext.vertexArrayObjectExt.bindVertexArrayOES(vao);
|
||||||
|
|
||||||
this.setBlendModeForAA(renderer, direction);
|
this.setBlendModeForAA(renderer);
|
||||||
gl.uniform1i(uniforms.uWinding, direction === 'upper' ? 1 : 0);
|
gl.uniform1i(uniforms.uWinding, direction === 'upper' ? 1 : 0);
|
||||||
|
|
||||||
const indexRanges = {
|
const indexRanges = {
|
||||||
|
@ -470,62 +642,12 @@ export abstract class MCAAStrategy extends XCAAStrategy {
|
||||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(null);
|
renderContext.vertexArrayObjectExt.bindVertexArrayOES(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private createCoverVAO(renderer: Renderer): void {
|
protected lineProgram(renderer: Renderer): PathfinderShaderProgram {
|
||||||
this.coverVAO = renderer.renderContext.vertexArrayObjectExt.createVertexArrayOES();
|
return renderer.renderContext.shaderPrograms.mcaaLine;
|
||||||
}
|
}
|
||||||
|
|
||||||
private initCoverVAOForObject(renderer: Renderer, objectIndex: number): void {
|
protected curveProgram(renderer: Renderer): PathfinderShaderProgram {
|
||||||
if (renderer.meshes == null || renderer.meshData == null)
|
return renderer.renderContext.shaderPrograms.mcaaCurve;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private createLineVAOs(renderer: Renderer): void {
|
private createLineVAOs(renderer: Renderer): void {
|
||||||
|
@ -547,7 +669,7 @@ export abstract class MCAAStrategy extends XCAAStrategy {
|
||||||
const pathRange = renderer.pathRangeForObject(objectIndex);
|
const pathRange = renderer.pathRangeForObject(objectIndex);
|
||||||
const meshIndex = renderer.meshIndexForObject(objectIndex);
|
const meshIndex = renderer.meshIndexForObject(objectIndex);
|
||||||
|
|
||||||
const lineProgram = renderContext.shaderPrograms.mcaaLine;
|
const lineProgram = this.lineProgram(renderer);
|
||||||
const attributes = lineProgram.attributes;
|
const attributes = lineProgram.attributes;
|
||||||
|
|
||||||
for (const direction of DIRECTIONS) {
|
for (const direction of DIRECTIONS) {
|
||||||
|
@ -619,88 +741,11 @@ export abstract class MCAAStrategy extends XCAAStrategy {
|
||||||
this.curveVAOs = vaos as FastEdgeVAOs;
|
this.curveVAOs = vaos as FastEdgeVAOs;
|
||||||
}
|
}
|
||||||
|
|
||||||
private initCurveVAOsForObject(renderer: Renderer, objectIndex: number): void {
|
get directRenderingMode(): DirectRenderingMode {
|
||||||
if (renderer.meshes == null || renderer.meshData == null)
|
return 'none';
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private coverObject(renderer: Renderer, objectIndex: number): void {
|
private initCoverVAOForObject(renderer: Renderer, objectIndex: number): void {
|
||||||
if (renderer.meshes == null || renderer.meshData == null)
|
if (renderer.meshes == null || renderer.meshData == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -710,36 +755,55 @@ export abstract class MCAAStrategy extends XCAAStrategy {
|
||||||
const pathRange = renderer.pathRangeForObject(objectIndex);
|
const pathRange = renderer.pathRangeForObject(objectIndex);
|
||||||
const meshIndex = renderer.meshIndexForObject(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);
|
renderContext.vertexArrayObjectExt.bindVertexArrayOES(this.coverVAO);
|
||||||
this.setAAUniforms(renderer, coverProgram.uniforms, objectIndex);
|
|
||||||
|
|
||||||
const bQuadRange = renderer.meshData[meshIndex].bQuadPathRanges;
|
const bQuadRanges = renderer.meshData[meshIndex].bQuadPathRanges;
|
||||||
const count = calculateCountFromIndexRanges(pathRange, bQuadRange);
|
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
|
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);
|
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 {
|
private antialiasLinesOfObject(renderer: Renderer, objectIndex: number): void {
|
||||||
const renderContext = renderer.renderContext;
|
const renderContext = renderer.renderContext;
|
||||||
this.setAAState(renderer);
|
this.setAAState(renderer);
|
||||||
|
|
||||||
const lineProgram = renderContext.shaderPrograms.mcaaLine;
|
const lineProgram = this.lineProgram(renderer);
|
||||||
renderContext.gl.useProgram(lineProgram.program);
|
renderContext.gl.useProgram(lineProgram.program);
|
||||||
|
|
||||||
// FIXME(pcwalton): Refactor.
|
// FIXME(pcwalton): Refactor.
|
||||||
|
@ -750,7 +814,7 @@ export abstract class MCAAStrategy extends XCAAStrategy {
|
||||||
const renderContext = renderer.renderContext;
|
const renderContext = renderer.renderContext;
|
||||||
this.setAAState(renderer);
|
this.setAAState(renderer);
|
||||||
|
|
||||||
const curveProgram = renderContext.shaderPrograms.mcaaCurve;
|
const curveProgram = this.curveProgram(renderer);
|
||||||
renderContext.gl.useProgram(curveProgram.program);
|
renderContext.gl.useProgram(curveProgram.program);
|
||||||
|
|
||||||
this.antialiasCurvesOfObjectWithProgram(renderer, objectIndex, curveProgram);
|
this.antialiasCurvesOfObjectWithProgram(renderer, objectIndex, curveProgram);
|
||||||
|
@ -803,8 +867,6 @@ export abstract class ECAAStrategy extends XCAAStrategy {
|
||||||
return renderContext.shaderPrograms.xcaaMonoResolve;
|
return renderContext.shaderPrograms.xcaaMonoResolve;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected maskEdgesOfObjectIfNecessary(renderer: Renderer, objectIndex: number): void {}
|
|
||||||
|
|
||||||
protected clearForAA(renderer: Renderer): void {
|
protected clearForAA(renderer: Renderer): void {
|
||||||
const renderContext = renderer.renderContext;
|
const renderContext = renderer.renderContext;
|
||||||
const gl = renderContext.gl;
|
const gl = renderContext.gl;
|
||||||
|
@ -1078,6 +1140,10 @@ export class ECAAMonochromeStrategy extends ECAAStrategy {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected get usesAAFramebuffer(): boolean {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
protected get lineShaderProgramNames(): Array<keyof ShaderMap<void>> {
|
protected get lineShaderProgramNames(): Array<keyof ShaderMap<void>> {
|
||||||
return ['ecaaLine'];
|
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 {
|
protected get usesDilationTransforms(): boolean {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected getResolveProgram(renderContext: RenderContext): PathfinderShaderProgram {
|
attachMeshes(renderer: Renderer): void {
|
||||||
if (this.subpixelAA !== 'none')
|
super.attachMeshes(renderer);
|
||||||
return renderContext.shaderPrograms.xcaaMonoSubpixelResolve;
|
|
||||||
return renderContext.shaderPrograms.xcaaMonoResolve;
|
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 {
|
protected clearForAA(renderer: Renderer): void {
|
||||||
const renderContext = renderer.renderContext;
|
const renderContext = renderer.renderContext;
|
||||||
const gl = renderContext.gl;
|
const gl = renderContext.gl;
|
||||||
|
|
||||||
gl.clearColor(0.0, 0.0, 0.0, 0.0);
|
gl.clearColor(1.0, 1.0, 1.0, 1.0);
|
||||||
gl.clearDepth(0.0);
|
gl.clearDepth(0.0);
|
||||||
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected setAADepthState(renderer: Renderer): void {
|
protected setAADepthState(renderer: Renderer): void {
|
||||||
const renderContext = renderer.renderContext;
|
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 renderContext = renderer.renderContext;
|
||||||
const gl = renderContext.gl;
|
const gl = renderContext.gl;
|
||||||
|
|
||||||
gl.clearColor(0.0, 0.0, 0.0, 0.0);
|
gl.blendEquation(gl.FUNC_ADD);
|
||||||
gl.clear(gl.COLOR_BUFFER_BIT);
|
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 {
|
get directRenderingMode(): DirectRenderingMode {
|
||||||
|
@ -1174,6 +1383,10 @@ export class AdaptiveMonochromeXCAAStrategy implements AntialiasingStrategy {
|
||||||
this.getAppropriateStrategy(renderer).prepareForDirectRendering(renderer);
|
this.getAppropriateStrategy(renderer).prepareForDirectRendering(renderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
finishAntialiasingObject(renderer: Renderer, objectIndex: number): void {
|
||||||
|
this.getAppropriateStrategy(renderer).finishAntialiasingObject(renderer, objectIndex);
|
||||||
|
}
|
||||||
|
|
||||||
prepareToRenderObject(renderer: Renderer, objectIndex: number): void {
|
prepareToRenderObject(renderer: Renderer, objectIndex: number): void {
|
||||||
this.getAppropriateStrategy(renderer).prepareToRenderObject(renderer, objectIndex);
|
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 {
|
function calculateStartFromIndexRanges(pathRange: Range, indexRanges: Range[]): number {
|
||||||
return indexRanges.length === 0 ? 0 : indexRanges[pathRange.start - 1].start;
|
return indexRanges.length === 0 ? 0 : indexRanges[pathRange.start - 1].start;
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,8 @@ use {BQuad, BVertexLoopBlinnData};
|
||||||
pub struct MeshLibrary {
|
pub struct MeshLibrary {
|
||||||
pub path_ranges: Vec<PathRanges>,
|
pub path_ranges: Vec<PathRanges>,
|
||||||
pub b_quads: Vec<BQuad>,
|
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_positions: Vec<Point2D<f32>>,
|
||||||
pub b_vertex_loop_blinn_data: Vec<BVertexLoopBlinnData>,
|
pub b_vertex_loop_blinn_data: Vec<BVertexLoopBlinnData>,
|
||||||
pub b_vertex_normals: Vec<f32>,
|
pub b_vertex_normals: Vec<f32>,
|
||||||
|
@ -39,6 +41,7 @@ impl MeshLibrary {
|
||||||
MeshLibrary {
|
MeshLibrary {
|
||||||
path_ranges: vec![],
|
path_ranges: vec![],
|
||||||
b_quads: vec![],
|
b_quads: vec![],
|
||||||
|
b_quad_vertex_positions: vec![],
|
||||||
b_vertex_positions: vec![],
|
b_vertex_positions: vec![],
|
||||||
b_vertex_loop_blinn_data: vec![],
|
b_vertex_loop_blinn_data: vec![],
|
||||||
b_vertex_normals: vec![],
|
b_vertex_normals: vec![],
|
||||||
|
@ -52,6 +55,7 @@ impl MeshLibrary {
|
||||||
pub fn clear(&mut self) {
|
pub fn clear(&mut self) {
|
||||||
self.path_ranges.clear();
|
self.path_ranges.clear();
|
||||||
self.b_quads.clear();
|
self.b_quads.clear();
|
||||||
|
self.b_quad_vertex_positions.clear();
|
||||||
self.b_vertex_positions.clear();
|
self.b_vertex_positions.clear();
|
||||||
self.b_vertex_loop_blinn_data.clear();
|
self.b_vertex_loop_blinn_data.clear();
|
||||||
self.b_vertex_normals.clear();
|
self.b_vertex_normals.clear();
|
||||||
|
@ -90,6 +94,13 @@ impl MeshLibrary {
|
||||||
let lower_right_position =
|
let lower_right_position =
|
||||||
&self.b_vertex_positions[b_quad.lower_right_vertex_index as usize];
|
&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 =
|
let upper_left_bounding_box_position =
|
||||||
Point2D::new(upper_left_position.x,
|
Point2D::new(upper_left_position.x,
|
||||||
f32::max(upper_left_position.y, upper_right_position.y));
|
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 {
|
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 {
|
self.edge_data.upper_line_vertex_positions.push(EdgeLineVertexPositions {
|
||||||
left: *upper_left_position,
|
left: *upper_left_position,
|
||||||
right: *upper_right_position,
|
right: *upper_right_position,
|
||||||
|
@ -110,6 +122,7 @@ impl MeshLibrary {
|
||||||
} else {
|
} else {
|
||||||
let upper_control_point_position =
|
let upper_control_point_position =
|
||||||
&self.b_vertex_positions[b_quad.upper_control_point_vertex_index as usize];
|
&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 {
|
self.edge_data.upper_curve_vertex_positions.push(EdgeCurveVertexPositions {
|
||||||
left: *upper_left_position,
|
left: *upper_left_position,
|
||||||
control_point: *upper_control_point_position,
|
control_point: *upper_control_point_position,
|
||||||
|
@ -118,6 +131,7 @@ impl MeshLibrary {
|
||||||
}
|
}
|
||||||
|
|
||||||
if b_quad.lower_control_point_vertex_index == u32::MAX {
|
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 {
|
self.edge_data.lower_line_vertex_positions.push(EdgeLineVertexPositions {
|
||||||
left: *lower_left_position,
|
left: *lower_left_position,
|
||||||
right: *lower_right_position,
|
right: *lower_right_position,
|
||||||
|
@ -125,6 +139,7 @@ impl MeshLibrary {
|
||||||
} else {
|
} else {
|
||||||
let lower_control_point_position =
|
let lower_control_point_position =
|
||||||
&self.b_vertex_positions[b_quad.lower_control_point_vertex_index as usize];
|
&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 {
|
self.edge_data.lower_curve_vertex_positions.push(EdgeCurveVertexPositions {
|
||||||
left: *lower_left_position,
|
left: *lower_left_position,
|
||||||
control_point: *lower_control_point_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_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"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"bvpo", &self.b_vertex_positions));
|
||||||
try!(write_simple_chunk(writer, b"bvlb", &self.b_vertex_loop_blinn_data));
|
try!(write_simple_chunk(writer, b"bvlb", &self.b_vertex_loop_blinn_data));
|
||||||
try!(write_simple_chunk(writer, b"bvno", &self.b_vertex_normals));
|
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<()>
|
fn write_path_ranges<W>(writer: &mut W, path_ranges: &[PathRanges]) -> io::Result<()>
|
||||||
where W: Write + Seek {
|
where W: Write + Seek {
|
||||||
try!(write_path_range(writer, b"bqua", path_ranges, |ranges| &ranges.b_quads));
|
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"bver", path_ranges, |ranges| &ranges.b_vertices));
|
||||||
try!(write_path_range(writer,
|
try!(write_path_range(writer,
|
||||||
b"cvii",
|
b"cvii",
|
||||||
|
@ -309,6 +329,7 @@ impl MeshLibrary {
|
||||||
pub(crate) fn snapshot_lengths(&self) -> MeshLibraryLengths {
|
pub(crate) fn snapshot_lengths(&self) -> MeshLibraryLengths {
|
||||||
MeshLibraryLengths {
|
MeshLibraryLengths {
|
||||||
b_quads: self.b_quads.len() as u32,
|
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,
|
b_vertices: self.b_vertex_positions.len() as u32,
|
||||||
cover_interior_indices: self.cover_indices.interior_indices.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,
|
cover_curve_indices: self.cover_indices.curve_indices.len() as u32,
|
||||||
|
@ -344,6 +365,7 @@ impl MeshLibraryCoverIndices {
|
||||||
|
|
||||||
pub(crate) struct MeshLibraryLengths {
|
pub(crate) struct MeshLibraryLengths {
|
||||||
b_quads: u32,
|
b_quads: u32,
|
||||||
|
b_quad_vertex_positions: u32,
|
||||||
b_vertices: u32,
|
b_vertices: u32,
|
||||||
cover_interior_indices: u32,
|
cover_interior_indices: u32,
|
||||||
cover_curve_indices: u32,
|
cover_curve_indices: u32,
|
||||||
|
@ -357,6 +379,7 @@ pub(crate) struct MeshLibraryLengths {
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct PathRanges {
|
pub struct PathRanges {
|
||||||
pub b_quads: Range<u32>,
|
pub b_quads: Range<u32>,
|
||||||
|
pub b_quad_vertex_positions: Range<u32>,
|
||||||
pub b_vertices: Range<u32>,
|
pub b_vertices: Range<u32>,
|
||||||
pub cover_interior_indices: Range<u32>,
|
pub cover_interior_indices: Range<u32>,
|
||||||
pub cover_curve_indices: Range<u32>,
|
pub cover_curve_indices: Range<u32>,
|
||||||
|
@ -373,6 +396,7 @@ impl PathRanges {
|
||||||
fn new() -> PathRanges {
|
fn new() -> PathRanges {
|
||||||
PathRanges {
|
PathRanges {
|
||||||
b_quads: 0..0,
|
b_quads: 0..0,
|
||||||
|
b_quad_vertex_positions: 0..0,
|
||||||
b_vertices: 0..0,
|
b_vertices: 0..0,
|
||||||
cover_interior_indices: 0..0,
|
cover_interior_indices: 0..0,
|
||||||
cover_curve_indices: 0..0,
|
cover_curve_indices: 0..0,
|
||||||
|
@ -390,6 +414,7 @@ impl PathRanges {
|
||||||
start: &MeshLibraryLengths,
|
start: &MeshLibraryLengths,
|
||||||
end: &MeshLibraryLengths) {
|
end: &MeshLibraryLengths) {
|
||||||
self.b_quads = start.b_quads..end.b_quads;
|
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.b_vertices = start.b_vertices..end.b_vertices;
|
||||||
self.cover_interior_indices = start.cover_interior_indices..end.cover_interior_indices;
|
self.cover_interior_indices = start.cover_interior_indices..end.cover_interior_indices;
|
||||||
self.cover_curve_indices = start.cover_curve_indices..end.cover_curve_indices;
|
self.cover_curve_indices = start.cover_curve_indices..end.cover_curve_indices;
|
||||||
|
|
|
@ -131,12 +131,39 @@ vec2 computeMCAAPosition(vec2 position,
|
||||||
vec4 localTransformST,
|
vec4 localTransformST,
|
||||||
vec4 globalTransformST,
|
vec4 globalTransformST,
|
||||||
ivec2 framebufferSize) {
|
ivec2 framebufferSize) {
|
||||||
|
if (position == vec2(0.0))
|
||||||
|
return position;
|
||||||
|
|
||||||
position = hintPosition(position, hints);
|
position = hintPosition(position, hints);
|
||||||
position = transformVertexPositionST(position, localTransformST);
|
position = transformVertexPositionST(position, localTransformST);
|
||||||
position = transformVertexPositionST(position, globalTransformST);
|
position = transformVertexPositionST(position, globalTransformST);
|
||||||
return convertClipToScreenSpace(position, framebufferSize);
|
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,
|
bool computeMCAAQuadPosition(out vec2 outPosition,
|
||||||
inout vec2 leftPosition,
|
inout vec2 leftPosition,
|
||||||
inout vec2 rightPosition,
|
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));
|
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
|
// https://www.freetype.org/freetype2/docs/reference/ft2-lcd_filtering.html
|
||||||
float lcdFilter(float shadeL2, float shadeL1, float shade0, float shadeR1, float shadeR2) {
|
float lcdFilter(float shadeL2, float shadeL1, float shade0, float shadeR1, float shadeR2) {
|
||||||
return LCD_FILTER_FACTOR_2 * shadeL2 +
|
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