Replace the multicolor (SVG) XCAA with a multipass compositing algorithm
This commit is contained in:
parent
b87d4126b0
commit
2604151521
|
@ -359,14 +359,6 @@ class ThreeDRenderer extends Renderer {
|
||||||
return this.destAllocatedSize;
|
return this.destAllocatedSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected get directCurveProgramName(): keyof ShaderMap<void> {
|
|
||||||
return 'direct3DCurve';
|
|
||||||
}
|
|
||||||
|
|
||||||
protected get directInteriorProgramName(): keyof ShaderMap<void> {
|
|
||||||
return 'direct3DInterior';
|
|
||||||
}
|
|
||||||
|
|
||||||
protected get depthFunction(): GLenum {
|
protected get depthFunction(): GLenum {
|
||||||
return this.renderContext.gl.LESS;
|
return this.renderContext.gl.LESS;
|
||||||
}
|
}
|
||||||
|
@ -528,6 +520,14 @@ class ThreeDRenderer extends Renderer {
|
||||||
this.renderContext.appController.newTimingsReceived(newTimings);
|
this.renderContext.appController.newTimingsReceived(newTimings);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected directCurveProgramNameForPass(pass: number): keyof ShaderMap<void> {
|
||||||
|
return 'direct3DCurve';
|
||||||
|
}
|
||||||
|
|
||||||
|
protected directInteriorProgramNameForPass(pass: number): keyof ShaderMap<void> {
|
||||||
|
return 'direct3DInterior';
|
||||||
|
}
|
||||||
|
|
||||||
// Cheap but effective backface culling.
|
// Cheap but effective backface culling.
|
||||||
private objectIsVisible(objectIndex: number): boolean {
|
private objectIsVisible(objectIndex: number): boolean {
|
||||||
const textFrameIndex = this.renderContext
|
const textFrameIndex = this.renderContext
|
||||||
|
|
|
@ -15,7 +15,7 @@ import {DemoView} from './view';
|
||||||
|
|
||||||
export type AntialiasingStrategyName = 'none' | 'ssaa' | 'xcaa';
|
export type AntialiasingStrategyName = 'none' | 'ssaa' | 'xcaa';
|
||||||
|
|
||||||
export type DirectRenderingMode = 'none' | 'color' | 'pathID';
|
export type DirectRenderingMode = 'none' | 'color' | 'two-pass';
|
||||||
|
|
||||||
export type SubpixelAAType = 'none' | 'medium';
|
export type SubpixelAAType = 'none' | 'medium';
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@ export abstract class AntialiasingStrategy {
|
||||||
// Called before direct rendering.
|
// Called before direct rendering.
|
||||||
//
|
//
|
||||||
// Typically, this redirects direct rendering to a framebuffer of some sort.
|
// Typically, this redirects direct rendering to a framebuffer of some sort.
|
||||||
abstract prepare(renderer: Renderer): void;
|
abstract prepareForDirectRendering(renderer: Renderer): void;
|
||||||
|
|
||||||
// Called after direct rendering.
|
// Called after direct rendering.
|
||||||
//
|
//
|
||||||
|
@ -73,7 +73,7 @@ export class NoAAStrategy extends AntialiasingStrategy {
|
||||||
return glmatrix.mat4.create();
|
return glmatrix.mat4.create();
|
||||||
}
|
}
|
||||||
|
|
||||||
prepare(renderer: Renderer) {
|
prepareForDirectRendering(renderer: Renderer) {
|
||||||
const renderContext = renderer.renderContext;
|
const renderContext = renderer.renderContext;
|
||||||
renderContext.gl.bindFramebuffer(renderContext.gl.FRAMEBUFFER, renderer.destFramebuffer);
|
renderContext.gl.bindFramebuffer(renderContext.gl.FRAMEBUFFER, renderer.destFramebuffer);
|
||||||
renderContext.gl.viewport(0, 0, this.framebufferSize[0], this.framebufferSize[1]);
|
renderContext.gl.viewport(0, 0, this.framebufferSize[0], this.framebufferSize[1]);
|
||||||
|
|
|
@ -309,14 +309,6 @@ class BenchmarkRenderer extends Renderer {
|
||||||
return glmatrix.vec2.clone([1.0, 1.0]);
|
return glmatrix.vec2.clone([1.0, 1.0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected get directCurveProgramName(): keyof ShaderMap<void> {
|
|
||||||
return 'directCurve';
|
|
||||||
}
|
|
||||||
|
|
||||||
protected get directInteriorProgramName(): keyof ShaderMap<void> {
|
|
||||||
return 'directInterior';
|
|
||||||
}
|
|
||||||
|
|
||||||
protected get depthFunction(): number {
|
protected get depthFunction(): number {
|
||||||
return this.renderContext.gl.GREATER;
|
return this.renderContext.gl.GREATER;
|
||||||
}
|
}
|
||||||
|
@ -445,6 +437,14 @@ class BenchmarkRenderer extends Renderer {
|
||||||
|
|
||||||
return pathTransforms;
|
return pathTransforms;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected directCurveProgramNameForPass(pass: number): keyof ShaderMap<void> {
|
||||||
|
return 'directCurve';
|
||||||
|
}
|
||||||
|
|
||||||
|
protected directInteriorProgramNameForPass(pass: number): keyof ShaderMap<void> {
|
||||||
|
return 'directInterior';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function computeMedian(values: number[]): number | null {
|
function computeMedian(values: number[]): number | null {
|
||||||
|
|
|
@ -18,6 +18,7 @@ import {PathfinderMeshBuffers, PathfinderMeshData} from "./meshes";
|
||||||
import {ShaderMap} from './shader-loader';
|
import {ShaderMap} from './shader-loader';
|
||||||
import {FLOAT32_SIZE, Range, UINT16_SIZE, UINT32_SIZE, unwrapNull} from './utils';
|
import {FLOAT32_SIZE, Range, UINT16_SIZE, UINT32_SIZE, unwrapNull} from './utils';
|
||||||
import {RenderContext, Timings} from "./view";
|
import {RenderContext, Timings} from "./view";
|
||||||
|
import {MCAAMulticolorStrategy} from './xcaa-strategy';
|
||||||
|
|
||||||
const MAX_PATHS: number = 65535;
|
const MAX_PATHS: number = 65535;
|
||||||
|
|
||||||
|
@ -64,8 +65,6 @@ export abstract class Renderer {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract get depthFunction(): GLenum;
|
protected abstract get depthFunction(): GLenum;
|
||||||
protected abstract get directCurveProgramName(): keyof ShaderMap<void>;
|
|
||||||
protected abstract get directInteriorProgramName(): keyof ShaderMap<void>;
|
|
||||||
protected abstract get usedSizeFactor(): glmatrix.vec2;
|
protected abstract get usedSizeFactor(): glmatrix.vec2;
|
||||||
protected abstract get worldTransform(): glmatrix.mat4;
|
protected abstract get worldTransform(): glmatrix.mat4;
|
||||||
|
|
||||||
|
@ -112,22 +111,22 @@ export abstract class Renderer {
|
||||||
renderContext.atlasRenderingTimerQuery);
|
renderContext.atlasRenderingTimerQuery);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prepare for direct rendering.
|
// Draw "scenery" (used in the 3D view).
|
||||||
|
this.drawSceneryIfNecessary();
|
||||||
|
|
||||||
|
// Antialias.
|
||||||
const antialiasingStrategy = unwrapNull(this.antialiasingStrategy);
|
const antialiasingStrategy = unwrapNull(this.antialiasingStrategy);
|
||||||
antialiasingStrategy.prepare(this);
|
antialiasingStrategy.antialias(this);
|
||||||
|
|
||||||
|
// Prepare for direct rendering.
|
||||||
|
antialiasingStrategy.prepareForDirectRendering(this);
|
||||||
|
|
||||||
// Clear.
|
// Clear.
|
||||||
this.clearForDirectRendering();
|
this.clearForDirectRendering();
|
||||||
|
|
||||||
// Draw "scenery" (used in the 3D view).
|
|
||||||
this.drawSceneryIfNecessary();
|
|
||||||
|
|
||||||
// Perform direct rendering (Loop-Blinn).
|
// Perform direct rendering (Loop-Blinn).
|
||||||
if (antialiasingStrategy.directRenderingMode !== 'none')
|
if (antialiasingStrategy.directRenderingMode !== 'none')
|
||||||
this.renderDirect();
|
this.renderDirect(0);
|
||||||
|
|
||||||
// Antialias.
|
|
||||||
antialiasingStrategy.antialias(this);
|
|
||||||
|
|
||||||
// End the timer, and start a new one.
|
// End the timer, and start a new one.
|
||||||
if (this.timerQueryPollInterval == null) {
|
if (this.timerQueryPollInterval == null) {
|
||||||
|
@ -138,6 +137,9 @@ export abstract class Renderer {
|
||||||
|
|
||||||
antialiasingStrategy.resolve(this);
|
antialiasingStrategy.resolve(this);
|
||||||
|
|
||||||
|
if (antialiasingStrategy.directRenderingMode === 'two-pass')
|
||||||
|
this.renderDirect(1);
|
||||||
|
|
||||||
// Draw the glyphs with the resolved atlas to the default framebuffer.
|
// Draw the glyphs with the resolved atlas to the default framebuffer.
|
||||||
this.compositeIfNecessary();
|
this.compositeIfNecessary();
|
||||||
|
|
||||||
|
@ -167,9 +169,10 @@ export abstract class Renderer {
|
||||||
}
|
}
|
||||||
|
|
||||||
setFramebufferSizeUniform(uniforms: UniformMap) {
|
setFramebufferSizeUniform(uniforms: UniformMap) {
|
||||||
this.renderContext.gl.uniform2i(uniforms.uFramebufferSize,
|
const gl = this.renderContext.gl;
|
||||||
this.destAllocatedSize[0],
|
gl.uniform2i(uniforms.uFramebufferSize,
|
||||||
this.destAllocatedSize[1]);
|
this.destAllocatedSize[0],
|
||||||
|
this.destAllocatedSize[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
setTransformAndTexScaleUniformsForDest(uniforms: UniformMap): void {
|
setTransformAndTexScaleUniformsForDest(uniforms: UniformMap): void {
|
||||||
|
@ -186,29 +189,29 @@ export abstract class Renderer {
|
||||||
|
|
||||||
setTransformSTAndTexScaleUniformsForDest(uniforms: UniformMap): void {
|
setTransformSTAndTexScaleUniformsForDest(uniforms: UniformMap): void {
|
||||||
const renderContext = this.renderContext;
|
const renderContext = this.renderContext;
|
||||||
|
const gl = renderContext.gl;
|
||||||
|
|
||||||
const usedSize = this.usedSizeFactor;
|
const usedSize = this.usedSizeFactor;
|
||||||
renderContext.gl.uniform4f(uniforms.uTransformST,
|
gl.uniform4f(uniforms.uTransformST, 2.0 * usedSize[0], 2.0 * usedSize[1], -1.0, -1.0);
|
||||||
2.0 * usedSize[0],
|
gl.uniform2f(uniforms.uTexScale, usedSize[0], usedSize[1]);
|
||||||
2.0 * usedSize[1],
|
|
||||||
-1.0,
|
|
||||||
-1.0);
|
|
||||||
renderContext.gl.uniform2f(uniforms.uTexScale, usedSize[0], usedSize[1]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setTransformSTUniform(uniforms: UniformMap, objectIndex: number) {
|
setTransformSTUniform(uniforms: UniformMap, objectIndex: number) {
|
||||||
// FIXME(pcwalton): Lossy conversion from a 4x4 matrix to an ST matrix is ugly and fragile.
|
// FIXME(pcwalton): Lossy conversion from a 4x4 matrix to an ST matrix is ugly and fragile.
|
||||||
// Refactor.
|
// Refactor.
|
||||||
const renderContext = this.renderContext;
|
const renderContext = this.renderContext;
|
||||||
|
const gl = renderContext.gl;
|
||||||
|
|
||||||
const transform = glmatrix.mat4.clone(this.worldTransform);
|
const transform = glmatrix.mat4.clone(this.worldTransform);
|
||||||
glmatrix.mat4.mul(transform, transform, this.getModelviewTransform(objectIndex));
|
glmatrix.mat4.mul(transform, transform, this.getModelviewTransform(objectIndex));
|
||||||
|
|
||||||
const translation = glmatrix.vec4.clone([transform[12], transform[13], 0.0, 1.0]);
|
const translation = glmatrix.vec4.clone([transform[12], transform[13], 0.0, 1.0]);
|
||||||
|
|
||||||
renderContext.gl.uniform4f(uniforms.uTransformST,
|
gl.uniform4f(uniforms.uTransformST,
|
||||||
transform[0],
|
transform[0],
|
||||||
transform[5],
|
transform[5],
|
||||||
transform[12],
|
transform[12],
|
||||||
transform[13]);
|
transform[13]);
|
||||||
}
|
}
|
||||||
|
|
||||||
uploadPathColors(objectCount: number) {
|
uploadPathColors(objectCount: number) {
|
||||||
|
@ -248,9 +251,8 @@ export abstract class Renderer {
|
||||||
}
|
}
|
||||||
|
|
||||||
setPathColorsUniform(objectIndex: number, uniforms: UniformMap, textureUnit: number): void {
|
setPathColorsUniform(objectIndex: number, uniforms: UniformMap, textureUnit: number): void {
|
||||||
this.pathColorsBufferTextures[objectIndex].bind(this.renderContext.gl,
|
const gl = this.renderContext.gl;
|
||||||
uniforms,
|
this.pathColorsBufferTextures[objectIndex].bind(gl, uniforms, textureUnit);
|
||||||
textureUnit);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract createAAStrategy(aaType: AntialiasingStrategyName,
|
protected abstract createAAStrategy(aaType: AntialiasingStrategyName,
|
||||||
|
@ -262,6 +264,9 @@ export abstract class Renderer {
|
||||||
protected abstract pathColorsForObject(objectIndex: number): Uint8Array;
|
protected abstract pathColorsForObject(objectIndex: number): Uint8Array;
|
||||||
protected abstract pathTransformsForObject(objectIndex: number): Float32Array;
|
protected abstract pathTransformsForObject(objectIndex: number): Float32Array;
|
||||||
|
|
||||||
|
protected abstract directCurveProgramNameForPass(pass: number): keyof ShaderMap<void>;
|
||||||
|
protected abstract directInteriorProgramNameForPass(pass: number): keyof ShaderMap<void>;
|
||||||
|
|
||||||
protected drawSceneryIfNecessary(): void {}
|
protected drawSceneryIfNecessary(): void {}
|
||||||
|
|
||||||
protected clearForDirectRendering(): void {
|
protected clearForDirectRendering(): void {
|
||||||
|
@ -269,22 +274,21 @@ export abstract class Renderer {
|
||||||
const renderContext = this.renderContext;
|
const renderContext = this.renderContext;
|
||||||
const gl = renderContext.gl;
|
const gl = renderContext.gl;
|
||||||
|
|
||||||
|
const clearColor = this.backgroundColor;
|
||||||
|
gl.clearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]);
|
||||||
|
|
||||||
switch (renderingMode) {
|
switch (renderingMode) {
|
||||||
case 'color':
|
case 'color':
|
||||||
const clearColor = this.backgroundColor;
|
|
||||||
gl.clearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]);
|
|
||||||
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);
|
||||||
break;
|
break;
|
||||||
case 'pathID':
|
case 'two-pass':
|
||||||
gl.clearColor(0.0, 0.0, 0.0, 0.0);
|
gl.clear(gl.COLOR_BUFFER_BIT);
|
||||||
gl.clearDepth(0.0);
|
|
||||||
gl.depthMask(true);
|
|
||||||
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
|
||||||
break;
|
break;
|
||||||
case 'none':
|
case 'none':
|
||||||
// Nothing to do.
|
// Nothing to do.
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -300,11 +304,13 @@ export abstract class Renderer {
|
||||||
/// Called whenever new GPU timing statistics are available.
|
/// Called whenever new GPU timing statistics are available.
|
||||||
protected newTimingsReceived(): void {}
|
protected newTimingsReceived(): void {}
|
||||||
|
|
||||||
private renderDirect(): void {
|
private renderDirect(pass: number): void {
|
||||||
const renderingMode = unwrapNull(this.antialiasingStrategy).directRenderingMode;
|
|
||||||
const renderContext = this.renderContext;
|
const renderContext = this.renderContext;
|
||||||
const gl = renderContext.gl;
|
const gl = renderContext.gl;
|
||||||
|
|
||||||
|
const antialiasingStrategy = unwrapNull(this.antialiasingStrategy);
|
||||||
|
const renderingMode = antialiasingStrategy.directRenderingMode;
|
||||||
|
|
||||||
for (let objectIndex = 0; objectIndex < this.meshes.length; objectIndex++) {
|
for (let objectIndex = 0; objectIndex < this.meshes.length; objectIndex++) {
|
||||||
const instanceRange = this.instanceRangeForObject(objectIndex);
|
const instanceRange = this.instanceRangeForObject(objectIndex);
|
||||||
if (instanceRange.isEmpty)
|
if (instanceRange.isEmpty)
|
||||||
|
@ -319,23 +325,26 @@ export abstract class Renderer {
|
||||||
gl.disable(gl.BLEND);
|
gl.disable(gl.BLEND);
|
||||||
|
|
||||||
// Set up the implicit cover interior VAO.
|
// Set up the implicit cover interior VAO.
|
||||||
const directInteriorProgram =
|
const directInteriorProgramName = this.directInteriorProgramNameForPass(pass);
|
||||||
renderContext.shaderPrograms[this.directInteriorProgramName];
|
const directInteriorProgram = renderContext.shaderPrograms[directInteriorProgramName];
|
||||||
if (this.implicitCoverInteriorVAO == null) {
|
if (this.implicitCoverInteriorVAO == null) {
|
||||||
this.implicitCoverInteriorVAO = renderContext.vertexArrayObjectExt
|
this.implicitCoverInteriorVAO = renderContext.vertexArrayObjectExt
|
||||||
.createVertexArrayOES();
|
.createVertexArrayOES();
|
||||||
}
|
}
|
||||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(this.implicitCoverInteriorVAO);
|
renderContext.vertexArrayObjectExt.bindVertexArrayOES(this.implicitCoverInteriorVAO);
|
||||||
this.initImplicitCoverInteriorVAO(objectIndex, instanceRange);
|
this.initImplicitCoverInteriorVAO(pass, objectIndex, instanceRange);
|
||||||
|
|
||||||
// Draw direct interior parts.
|
// Draw direct interior parts.
|
||||||
this.setTransformUniform(directInteriorProgram.uniforms, objectIndex);
|
this.setTransformUniform(directInteriorProgram.uniforms, objectIndex);
|
||||||
this.setFramebufferSizeUniform(directInteriorProgram.uniforms);
|
this.setFramebufferSizeUniform(directInteriorProgram.uniforms);
|
||||||
this.setHintsUniform(directInteriorProgram.uniforms);
|
this.setHintsUniform(directInteriorProgram.uniforms);
|
||||||
if (renderingMode === 'color')
|
this.setPathColorsUniform(objectIndex, directInteriorProgram.uniforms, 0);
|
||||||
this.setPathColorsUniform(objectIndex, directInteriorProgram.uniforms, 0);
|
|
||||||
this.pathTransformBufferTextures[objectIndex]
|
this.pathTransformBufferTextures[objectIndex]
|
||||||
.bind(gl, directInteriorProgram.uniforms, 1);
|
.bind(gl, directInteriorProgram.uniforms, 1);
|
||||||
|
if (renderingMode === 'two-pass') {
|
||||||
|
const strategy = antialiasingStrategy as MCAAMulticolorStrategy;
|
||||||
|
strategy.bindEdgeDepthTexture(gl, directInteriorProgram.uniforms, 2);
|
||||||
|
}
|
||||||
let indexCount = meshData.coverInteriorIndices.byteLength / UINT32_SIZE;
|
let indexCount = meshData.coverInteriorIndices.byteLength / UINT32_SIZE;
|
||||||
if (!this.pathIDsAreInstanced) {
|
if (!this.pathIDsAreInstanced) {
|
||||||
gl.drawElements(gl.TRIANGLES, indexCount, gl.UNSIGNED_INT, 0);
|
gl.drawElements(gl.TRIANGLES, indexCount, gl.UNSIGNED_INT, 0);
|
||||||
|
@ -356,21 +365,25 @@ export abstract class Renderer {
|
||||||
// Set up the direct curve VAO.
|
// Set up the direct curve VAO.
|
||||||
//
|
//
|
||||||
// TODO(pcwalton): Cache these.
|
// TODO(pcwalton): Cache these.
|
||||||
const directCurveProgram = renderContext.shaderPrograms[this.directCurveProgramName];
|
const directCurveProgramName = this.directCurveProgramNameForPass(pass);
|
||||||
|
const directCurveProgram = renderContext.shaderPrograms[directCurveProgramName];
|
||||||
if (this.implicitCoverCurveVAO == null) {
|
if (this.implicitCoverCurveVAO == null) {
|
||||||
this.implicitCoverCurveVAO = renderContext.vertexArrayObjectExt
|
this.implicitCoverCurveVAO = renderContext.vertexArrayObjectExt
|
||||||
.createVertexArrayOES();
|
.createVertexArrayOES();
|
||||||
}
|
}
|
||||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(this.implicitCoverCurveVAO);
|
renderContext.vertexArrayObjectExt.bindVertexArrayOES(this.implicitCoverCurveVAO);
|
||||||
this.initImplicitCoverCurveVAO(objectIndex, instanceRange);
|
this.initImplicitCoverCurveVAO(pass, objectIndex, instanceRange);
|
||||||
|
|
||||||
// Draw direct curve parts.
|
// Draw direct curve parts.
|
||||||
this.setTransformUniform(directCurveProgram.uniforms, objectIndex);
|
this.setTransformUniform(directCurveProgram.uniforms, objectIndex);
|
||||||
this.setFramebufferSizeUniform(directCurveProgram.uniforms);
|
this.setFramebufferSizeUniform(directCurveProgram.uniforms);
|
||||||
this.setHintsUniform(directCurveProgram.uniforms);
|
this.setHintsUniform(directCurveProgram.uniforms);
|
||||||
if (renderingMode === 'color')
|
this.setPathColorsUniform(objectIndex, directCurveProgram.uniforms, 0);
|
||||||
this.setPathColorsUniform(objectIndex, directCurveProgram.uniforms, 0);
|
|
||||||
this.pathTransformBufferTextures[objectIndex].bind(gl, directCurveProgram.uniforms, 1);
|
this.pathTransformBufferTextures[objectIndex].bind(gl, directCurveProgram.uniforms, 1);
|
||||||
|
if (renderingMode === 'two-pass') {
|
||||||
|
const strategy = antialiasingStrategy as MCAAMulticolorStrategy;
|
||||||
|
strategy.bindEdgeDepthTexture(gl, directCurveProgram.uniforms, 2);
|
||||||
|
}
|
||||||
indexCount = meshData.coverCurveIndices.byteLength / UINT32_SIZE;
|
indexCount = meshData.coverCurveIndices.byteLength / UINT32_SIZE;
|
||||||
if (!this.pathIDsAreInstanced) {
|
if (!this.pathIDsAreInstanced) {
|
||||||
gl.drawElements(gl.TRIANGLES, indexCount, gl.UNSIGNED_INT, 0);
|
gl.drawElements(gl.TRIANGLES, indexCount, gl.UNSIGNED_INT, 0);
|
||||||
|
@ -426,104 +439,104 @@ export abstract class Renderer {
|
||||||
}, TIME_INTERVAL_DELAY);
|
}, TIME_INTERVAL_DELAY);
|
||||||
}
|
}
|
||||||
|
|
||||||
private initImplicitCoverCurveVAO(objectIndex: number, instanceRange: Range): void {
|
private initImplicitCoverCurveVAO(pass: number, objectIndex: number, instanceRange: Range):
|
||||||
|
void {
|
||||||
const renderContext = this.renderContext;
|
const renderContext = this.renderContext;
|
||||||
|
const gl = renderContext.gl;
|
||||||
const meshes = this.meshes[objectIndex];
|
const meshes = this.meshes[objectIndex];
|
||||||
|
|
||||||
const directCurveProgram = renderContext.shaderPrograms[this.directCurveProgramName];
|
const directCurveProgramName = this.directCurveProgramNameForPass(pass);
|
||||||
renderContext.gl.useProgram(directCurveProgram.program);
|
const directCurveProgram = renderContext.shaderPrograms[directCurveProgramName];
|
||||||
renderContext.gl.bindBuffer(renderContext.gl.ARRAY_BUFFER, meshes.bVertexPositions);
|
gl.useProgram(directCurveProgram.program);
|
||||||
renderContext.gl.vertexAttribPointer(directCurveProgram.attributes.aPosition,
|
gl.bindBuffer(gl.ARRAY_BUFFER, meshes.bVertexPositions);
|
||||||
2,
|
gl.vertexAttribPointer(directCurveProgram.attributes.aPosition, 2, gl.FLOAT, false, 0, 0);
|
||||||
renderContext.gl.FLOAT,
|
|
||||||
false,
|
|
||||||
0,
|
|
||||||
0);
|
|
||||||
|
|
||||||
if (this.pathIDsAreInstanced)
|
if (this.pathIDsAreInstanced)
|
||||||
renderContext.gl.bindBuffer(renderContext.gl.ARRAY_BUFFER, this.instancedPathIDVBO);
|
gl.bindBuffer(gl.ARRAY_BUFFER, this.instancedPathIDVBO);
|
||||||
else
|
else
|
||||||
renderContext.gl.bindBuffer(renderContext.gl.ARRAY_BUFFER, meshes.bVertexPathIDs);
|
gl.bindBuffer(gl.ARRAY_BUFFER, meshes.bVertexPathIDs);
|
||||||
renderContext.gl.vertexAttribPointer(directCurveProgram.attributes.aPathID,
|
gl.vertexAttribPointer(directCurveProgram.attributes.aPathID,
|
||||||
1,
|
1,
|
||||||
renderContext.gl.UNSIGNED_SHORT,
|
gl.UNSIGNED_SHORT,
|
||||||
false,
|
false,
|
||||||
0,
|
0,
|
||||||
instanceRange.start * UINT16_SIZE);
|
instanceRange.start * UINT16_SIZE);
|
||||||
if (this.pathIDsAreInstanced) {
|
if (this.pathIDsAreInstanced) {
|
||||||
renderContext.instancedArraysExt
|
renderContext.instancedArraysExt
|
||||||
.vertexAttribDivisorANGLE(directCurveProgram.attributes.aPathID, 1);
|
.vertexAttribDivisorANGLE(directCurveProgram.attributes.aPathID, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderContext.gl.bindBuffer(renderContext.gl.ARRAY_BUFFER, meshes.bVertexLoopBlinnData);
|
gl.bindBuffer(gl.ARRAY_BUFFER, meshes.bVertexLoopBlinnData);
|
||||||
renderContext.gl.vertexAttribPointer(directCurveProgram.attributes.aTexCoord,
|
gl.vertexAttribPointer(directCurveProgram.attributes.aTexCoord,
|
||||||
2,
|
2,
|
||||||
renderContext.gl.UNSIGNED_BYTE,
|
gl.UNSIGNED_BYTE,
|
||||||
false,
|
false,
|
||||||
B_LOOP_BLINN_DATA_SIZE,
|
B_LOOP_BLINN_DATA_SIZE,
|
||||||
B_LOOP_BLINN_DATA_TEX_COORD_OFFSET);
|
B_LOOP_BLINN_DATA_TEX_COORD_OFFSET);
|
||||||
renderContext.gl.vertexAttribPointer(directCurveProgram.attributes.aSign,
|
gl.vertexAttribPointer(directCurveProgram.attributes.aSign,
|
||||||
1,
|
1,
|
||||||
renderContext.gl.BYTE,
|
gl.BYTE,
|
||||||
false,
|
false,
|
||||||
B_LOOP_BLINN_DATA_SIZE,
|
B_LOOP_BLINN_DATA_SIZE,
|
||||||
B_LOOP_BLINN_DATA_SIGN_OFFSET);
|
B_LOOP_BLINN_DATA_SIGN_OFFSET);
|
||||||
renderContext.gl.enableVertexAttribArray(directCurveProgram.attributes.aPosition);
|
gl.enableVertexAttribArray(directCurveProgram.attributes.aPosition);
|
||||||
renderContext.gl.enableVertexAttribArray(directCurveProgram.attributes.aTexCoord);
|
gl.enableVertexAttribArray(directCurveProgram.attributes.aTexCoord);
|
||||||
renderContext.gl.enableVertexAttribArray(directCurveProgram.attributes.aPathID);
|
gl.enableVertexAttribArray(directCurveProgram.attributes.aPathID);
|
||||||
renderContext.gl.enableVertexAttribArray(directCurveProgram.attributes.aSign);
|
gl.enableVertexAttribArray(directCurveProgram.attributes.aSign);
|
||||||
renderContext.gl.bindBuffer(renderContext.gl.ELEMENT_ARRAY_BUFFER,
|
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, meshes.coverCurveIndices);
|
||||||
meshes.coverCurveIndices);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private initImplicitCoverInteriorVAO(objectIndex: number, instanceRange: Range): void {
|
private initImplicitCoverInteriorVAO(pass: number,
|
||||||
|
objectIndex: number,
|
||||||
|
instanceRange: Range):
|
||||||
|
void {
|
||||||
const renderContext = this.renderContext;
|
const renderContext = this.renderContext;
|
||||||
|
const gl = renderContext.gl;
|
||||||
const meshes = this.meshes[objectIndex];
|
const meshes = this.meshes[objectIndex];
|
||||||
|
|
||||||
const directInteriorProgram = renderContext.shaderPrograms[this.directInteriorProgramName];
|
const directInteriorProgramName = this.directInteriorProgramNameForPass(pass);
|
||||||
renderContext.gl.useProgram(directInteriorProgram.program);
|
const directInteriorProgram = renderContext.shaderPrograms[directInteriorProgramName];
|
||||||
renderContext.gl.bindBuffer(renderContext.gl.ARRAY_BUFFER, meshes.bVertexPositions);
|
gl.useProgram(directInteriorProgram.program);
|
||||||
renderContext.gl.vertexAttribPointer(directInteriorProgram.attributes.aPosition,
|
gl.bindBuffer(gl.ARRAY_BUFFER, meshes.bVertexPositions);
|
||||||
2,
|
gl.vertexAttribPointer(directInteriorProgram.attributes.aPosition,
|
||||||
renderContext.gl.FLOAT,
|
2,
|
||||||
false,
|
gl.FLOAT,
|
||||||
0,
|
false,
|
||||||
0);
|
0,
|
||||||
|
0);
|
||||||
|
|
||||||
if (this.pathIDsAreInstanced)
|
if (this.pathIDsAreInstanced)
|
||||||
renderContext.gl.bindBuffer(renderContext.gl.ARRAY_BUFFER, this.instancedPathIDVBO);
|
gl.bindBuffer(gl.ARRAY_BUFFER, this.instancedPathIDVBO);
|
||||||
else
|
else
|
||||||
renderContext.gl.bindBuffer(renderContext.gl.ARRAY_BUFFER, meshes.bVertexPathIDs);
|
gl.bindBuffer(gl.ARRAY_BUFFER, meshes.bVertexPathIDs);
|
||||||
renderContext.gl.vertexAttribPointer(directInteriorProgram.attributes.aPathID,
|
gl.vertexAttribPointer(directInteriorProgram.attributes.aPathID,
|
||||||
1,
|
1,
|
||||||
renderContext.gl.UNSIGNED_SHORT,
|
gl.UNSIGNED_SHORT,
|
||||||
false,
|
false,
|
||||||
0,
|
0,
|
||||||
instanceRange.start * UINT16_SIZE);
|
instanceRange.start * UINT16_SIZE);
|
||||||
if (this.pathIDsAreInstanced) {
|
if (this.pathIDsAreInstanced) {
|
||||||
renderContext.instancedArraysExt
|
renderContext.instancedArraysExt
|
||||||
.vertexAttribDivisorANGLE(directInteriorProgram.attributes.aPathID, 1);
|
.vertexAttribDivisorANGLE(directInteriorProgram.attributes.aPathID, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderContext.gl.enableVertexAttribArray(directInteriorProgram.attributes.aPosition);
|
gl.enableVertexAttribArray(directInteriorProgram.attributes.aPosition);
|
||||||
renderContext.gl.enableVertexAttribArray(directInteriorProgram.attributes.aPathID);
|
gl.enableVertexAttribArray(directInteriorProgram.attributes.aPathID);
|
||||||
renderContext.gl.bindBuffer(renderContext.gl.ELEMENT_ARRAY_BUFFER,
|
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, meshes.coverInteriorIndices);
|
||||||
meshes.coverInteriorIndices);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private initInstancedPathIDVBO(): void {
|
private initInstancedPathIDVBO(): void {
|
||||||
const renderContext = this.renderContext;
|
const renderContext = this.renderContext;
|
||||||
|
const gl = renderContext.gl;
|
||||||
|
|
||||||
const pathIDs = new Uint16Array(MAX_PATHS);
|
const pathIDs = new Uint16Array(MAX_PATHS);
|
||||||
for (let pathIndex = 0; pathIndex < MAX_PATHS; pathIndex++)
|
for (let pathIndex = 0; pathIndex < MAX_PATHS; pathIndex++)
|
||||||
pathIDs[pathIndex] = pathIndex + 1;
|
pathIDs[pathIndex] = pathIndex + 1;
|
||||||
|
|
||||||
this.instancedPathIDVBO = renderContext.gl.createBuffer();
|
this.instancedPathIDVBO = renderContext.gl.createBuffer();
|
||||||
renderContext.gl.bindBuffer(renderContext.gl.ARRAY_BUFFER, this.instancedPathIDVBO);
|
gl.bindBuffer(gl.ARRAY_BUFFER, this.instancedPathIDVBO);
|
||||||
renderContext.gl.bufferData(renderContext.gl.ARRAY_BUFFER,
|
gl.bufferData(gl.ARRAY_BUFFER, pathIDs, gl.STATIC_DRAW);
|
||||||
pathIDs,
|
gl.bindBuffer(gl.ARRAY_BUFFER, null);
|
||||||
renderContext.gl.STATIC_DRAW);
|
|
||||||
renderContext.gl.bindBuffer(renderContext.gl.ARRAY_BUFFER, null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private setTransformUniform(uniforms: UniformMap, objectIndex: number) {
|
private setTransformUniform(uniforms: UniformMap, objectIndex: number) {
|
||||||
|
|
|
@ -25,11 +25,12 @@ export interface ShaderMap<T> {
|
||||||
mcaaLine: T;
|
mcaaLine: T;
|
||||||
mcaaCurve: T;
|
mcaaCurve: T;
|
||||||
ssaaSubpixelResolve: T;
|
ssaaSubpixelResolve: T;
|
||||||
xcaaEdgeDetect: T;
|
|
||||||
xcaaMonoResolve: T;
|
xcaaMonoResolve: T;
|
||||||
xcaaMonoSubpixelResolve: T;
|
xcaaMonoSubpixelResolve: T;
|
||||||
xcaaMultiDirectCurve: T;
|
xcaaMultiBGDirectCurve: T;
|
||||||
xcaaMultiDirectInterior: T;
|
xcaaMultiBGDirectInterior: T;
|
||||||
|
xcaaMultiEdgeMaskCurve: T;
|
||||||
|
xcaaMultiEdgeMaskLine: T;
|
||||||
xcaaMultiResolve: T;
|
xcaaMultiResolve: T;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,7 +48,6 @@ export const SHADER_NAMES: Array<keyof ShaderMap<void>> = [
|
||||||
'direct3DCurve',
|
'direct3DCurve',
|
||||||
'direct3DInterior',
|
'direct3DInterior',
|
||||||
'ssaaSubpixelResolve',
|
'ssaaSubpixelResolve',
|
||||||
'xcaaEdgeDetect',
|
|
||||||
'mcaaCover',
|
'mcaaCover',
|
||||||
'mcaaLine',
|
'mcaaLine',
|
||||||
'mcaaCurve',
|
'mcaaCurve',
|
||||||
|
@ -55,8 +55,10 @@ export const SHADER_NAMES: Array<keyof ShaderMap<void>> = [
|
||||||
'ecaaCurve',
|
'ecaaCurve',
|
||||||
'xcaaMonoResolve',
|
'xcaaMonoResolve',
|
||||||
'xcaaMonoSubpixelResolve',
|
'xcaaMonoSubpixelResolve',
|
||||||
'xcaaMultiDirectCurve',
|
'xcaaMultiBGDirectCurve',
|
||||||
'xcaaMultiDirectInterior',
|
'xcaaMultiBGDirectInterior',
|
||||||
|
'xcaaMultiEdgeMaskCurve',
|
||||||
|
'xcaaMultiEdgeMaskLine',
|
||||||
'xcaaMultiResolve',
|
'xcaaMultiResolve',
|
||||||
'demo3DDistantGlyph',
|
'demo3DDistantGlyph',
|
||||||
'demo3DMonument',
|
'demo3DMonument',
|
||||||
|
@ -115,10 +117,6 @@ const SHADER_URLS: ShaderMap<ShaderProgramURLs> = {
|
||||||
fragment: "/glsl/gles2/ssaa-subpixel-resolve.fs.glsl",
|
fragment: "/glsl/gles2/ssaa-subpixel-resolve.fs.glsl",
|
||||||
vertex: "/glsl/gles2/ssaa-subpixel-resolve.vs.glsl",
|
vertex: "/glsl/gles2/ssaa-subpixel-resolve.vs.glsl",
|
||||||
},
|
},
|
||||||
xcaaEdgeDetect: {
|
|
||||||
fragment: "/glsl/gles2/xcaa-edge-detect.fs.glsl",
|
|
||||||
vertex: "/glsl/gles2/xcaa-edge-detect.vs.glsl",
|
|
||||||
},
|
|
||||||
xcaaMonoResolve: {
|
xcaaMonoResolve: {
|
||||||
fragment: "/glsl/gles2/xcaa-mono-resolve.fs.glsl",
|
fragment: "/glsl/gles2/xcaa-mono-resolve.fs.glsl",
|
||||||
vertex: "/glsl/gles2/xcaa-mono-resolve.vs.glsl",
|
vertex: "/glsl/gles2/xcaa-mono-resolve.vs.glsl",
|
||||||
|
@ -127,13 +125,21 @@ 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: {
|
xcaaMultiBGDirectCurve: {
|
||||||
fragment: "/glsl/gles2/xcaa-multi-direct-curve.fs.glsl",
|
fragment: "/glsl/gles2/xcaa-multi-bg-direct-curve.fs.glsl",
|
||||||
vertex: "/glsl/gles2/xcaa-multi-direct-curve.vs.glsl",
|
vertex: "/glsl/gles2/xcaa-multi-bg-direct-curve.vs.glsl",
|
||||||
},
|
},
|
||||||
xcaaMultiDirectInterior: {
|
xcaaMultiBGDirectInterior: {
|
||||||
fragment: "/glsl/gles2/xcaa-multi-direct-interior.fs.glsl",
|
fragment: "/glsl/gles2/xcaa-multi-bg-direct-interior.fs.glsl",
|
||||||
vertex: "/glsl/gles2/xcaa-multi-direct-interior.vs.glsl",
|
vertex: "/glsl/gles2/xcaa-multi-bg-direct-interior.vs.glsl",
|
||||||
|
},
|
||||||
|
xcaaMultiEdgeMaskCurve: {
|
||||||
|
fragment: "/glsl/gles2/xcaa-multi-edge-mask-curve.fs.glsl",
|
||||||
|
vertex: "/glsl/gles2/mcaa-curve.vs.glsl",
|
||||||
|
},
|
||||||
|
xcaaMultiEdgeMaskLine: {
|
||||||
|
fragment: "/glsl/gles2/xcaa-multi-edge-mask-line.fs.glsl",
|
||||||
|
vertex: "/glsl/gles2/mcaa-line.vs.glsl",
|
||||||
},
|
},
|
||||||
xcaaMultiResolve: {
|
xcaaMultiResolve: {
|
||||||
fragment: "/glsl/gles2/xcaa-multi-resolve.fs.glsl",
|
fragment: "/glsl/gles2/xcaa-multi-resolve.fs.glsl",
|
||||||
|
|
|
@ -38,6 +38,7 @@ export default class SSAAStrategy extends AntialiasingStrategy {
|
||||||
|
|
||||||
setFramebufferSize(renderer: Renderer) {
|
setFramebufferSize(renderer: Renderer) {
|
||||||
const renderContext = renderer.renderContext;
|
const renderContext = renderer.renderContext;
|
||||||
|
const gl = renderContext.gl;
|
||||||
|
|
||||||
this.destFramebufferSize = glmatrix.vec2.clone(renderer.destAllocatedSize);
|
this.destFramebufferSize = glmatrix.vec2.clone(renderer.destAllocatedSize);
|
||||||
|
|
||||||
|
@ -46,28 +47,28 @@ export default class SSAAStrategy extends AntialiasingStrategy {
|
||||||
this.destFramebufferSize,
|
this.destFramebufferSize,
|
||||||
this.supersampleScale);
|
this.supersampleScale);
|
||||||
|
|
||||||
this.supersampledColorTexture = unwrapNull(renderContext.gl.createTexture());
|
this.supersampledColorTexture = unwrapNull(gl.createTexture());
|
||||||
renderContext.gl.activeTexture(renderContext.gl.TEXTURE0);
|
gl.activeTexture(gl.TEXTURE0);
|
||||||
renderContext.gl.bindTexture(renderContext.gl.TEXTURE_2D, this.supersampledColorTexture);
|
gl.bindTexture(gl.TEXTURE_2D, this.supersampledColorTexture);
|
||||||
renderContext.gl.texImage2D(renderContext.gl.TEXTURE_2D,
|
gl.texImage2D(gl.TEXTURE_2D,
|
||||||
0,
|
0,
|
||||||
renderContext.colorAlphaFormat,
|
renderContext.colorAlphaFormat,
|
||||||
this.supersampledFramebufferSize[0],
|
this.supersampledFramebufferSize[0],
|
||||||
this.supersampledFramebufferSize[1],
|
this.supersampledFramebufferSize[1],
|
||||||
0,
|
0,
|
||||||
renderContext.colorAlphaFormat,
|
renderContext.colorAlphaFormat,
|
||||||
renderContext.gl.UNSIGNED_BYTE,
|
gl.UNSIGNED_BYTE,
|
||||||
null);
|
null);
|
||||||
setTextureParameters(renderContext.gl, renderContext.gl.LINEAR);
|
setTextureParameters(gl, gl.LINEAR);
|
||||||
|
|
||||||
this.supersampledDepthTexture =
|
this.supersampledDepthTexture =
|
||||||
createFramebufferDepthTexture(renderContext.gl, this.supersampledFramebufferSize);
|
createFramebufferDepthTexture(gl, this.supersampledFramebufferSize);
|
||||||
|
|
||||||
this.supersampledFramebuffer = createFramebuffer(renderContext.gl,
|
this.supersampledFramebuffer = createFramebuffer(gl,
|
||||||
this.supersampledColorTexture,
|
this.supersampledColorTexture,
|
||||||
this.supersampledDepthTexture);
|
this.supersampledDepthTexture);
|
||||||
|
|
||||||
renderContext.gl.bindFramebuffer(renderContext.gl.FRAMEBUFFER, null);
|
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
get transform(): glmatrix.mat4 {
|
get transform(): glmatrix.mat4 {
|
||||||
|
@ -79,7 +80,7 @@ export default class SSAAStrategy extends AntialiasingStrategy {
|
||||||
return transform;
|
return transform;
|
||||||
}
|
}
|
||||||
|
|
||||||
prepare(renderer: Renderer) {
|
prepareForDirectRendering(renderer: Renderer) {
|
||||||
const renderContext = renderer.renderContext;
|
const renderContext = renderer.renderContext;
|
||||||
const gl = renderContext.gl;
|
const gl = renderContext.gl;
|
||||||
|
|
||||||
|
@ -95,13 +96,12 @@ export default class SSAAStrategy extends AntialiasingStrategy {
|
||||||
|
|
||||||
resolve(renderer: Renderer) {
|
resolve(renderer: Renderer) {
|
||||||
const renderContext = renderer.renderContext;
|
const renderContext = renderer.renderContext;
|
||||||
renderContext.gl.bindFramebuffer(renderContext.gl.FRAMEBUFFER, renderer.destFramebuffer);
|
const gl = renderContext.gl;
|
||||||
renderContext.gl.viewport(0,
|
|
||||||
0,
|
gl.bindFramebuffer(gl.FRAMEBUFFER, renderer.destFramebuffer);
|
||||||
renderer.destAllocatedSize[0],
|
gl.viewport(0, 0, renderer.destAllocatedSize[0], renderer.destAllocatedSize[1]);
|
||||||
renderer.destAllocatedSize[1]);
|
gl.disable(gl.DEPTH_TEST);
|
||||||
renderContext.gl.disable(renderContext.gl.DEPTH_TEST);
|
gl.disable(gl.BLEND);
|
||||||
renderContext.gl.disable(renderContext.gl.BLEND);
|
|
||||||
|
|
||||||
// Set up the blit program VAO.
|
// Set up the blit program VAO.
|
||||||
let resolveProgram;
|
let resolveProgram;
|
||||||
|
@ -109,23 +109,19 @@ export default class SSAAStrategy extends AntialiasingStrategy {
|
||||||
resolveProgram = renderContext.shaderPrograms.ssaaSubpixelResolve;
|
resolveProgram = renderContext.shaderPrograms.ssaaSubpixelResolve;
|
||||||
else
|
else
|
||||||
resolveProgram = renderContext.shaderPrograms.blit;
|
resolveProgram = renderContext.shaderPrograms.blit;
|
||||||
renderContext.gl.useProgram(resolveProgram.program);
|
gl.useProgram(resolveProgram.program);
|
||||||
renderContext.initQuadVAO(resolveProgram.attributes);
|
renderContext.initQuadVAO(resolveProgram.attributes);
|
||||||
|
|
||||||
// Resolve framebuffer.
|
// Resolve framebuffer.
|
||||||
renderContext.gl.activeTexture(renderContext.gl.TEXTURE0);
|
gl.activeTexture(gl.TEXTURE0);
|
||||||
renderContext.gl.bindTexture(renderContext.gl.TEXTURE_2D, this.supersampledColorTexture);
|
gl.bindTexture(gl.TEXTURE_2D, this.supersampledColorTexture);
|
||||||
renderContext.gl.uniform1i(resolveProgram.uniforms.uSource, 0);
|
gl.uniform1i(resolveProgram.uniforms.uSource, 0);
|
||||||
renderContext.gl.uniform2i(resolveProgram.uniforms.uSourceDimensions,
|
gl.uniform2i(resolveProgram.uniforms.uSourceDimensions,
|
||||||
this.supersampledFramebufferSize[0],
|
this.supersampledFramebufferSize[0],
|
||||||
this.supersampledFramebufferSize[1]);
|
this.supersampledFramebufferSize[1]);
|
||||||
renderer.setTransformAndTexScaleUniformsForDest(resolveProgram.uniforms);
|
renderer.setTransformAndTexScaleUniformsForDest(resolveProgram.uniforms);
|
||||||
renderContext.gl.bindBuffer(renderContext.gl.ELEMENT_ARRAY_BUFFER,
|
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, renderContext.quadElementsBuffer);
|
||||||
renderContext.quadElementsBuffer);
|
gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_BYTE, 0);
|
||||||
renderContext.gl.drawElements(renderContext.gl.TRIANGLES,
|
|
||||||
6,
|
|
||||||
renderContext.gl.UNSIGNED_BYTE,
|
|
||||||
0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get directRenderingMode(): DirectRenderingMode {
|
get directRenderingMode(): DirectRenderingMode {
|
||||||
|
|
|
@ -115,10 +115,8 @@ class SVGDemoRenderer extends Renderer {
|
||||||
camera: OrthographicCamera;
|
camera: OrthographicCamera;
|
||||||
|
|
||||||
get destAllocatedSize(): glmatrix.vec2 {
|
get destAllocatedSize(): glmatrix.vec2 {
|
||||||
return glmatrix.vec2.clone([
|
const canvas = this.renderContext.canvas;
|
||||||
this.renderContext.canvas.width,
|
return glmatrix.vec2.clone([canvas.width, canvas.height]);
|
||||||
this.renderContext.canvas.height,
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get destFramebuffer(): WebGLFramebuffer | null {
|
get destFramebuffer(): WebGLFramebuffer | null {
|
||||||
|
@ -183,15 +181,15 @@ class SVGDemoRenderer extends Renderer {
|
||||||
return transform;
|
return transform;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected get directCurveProgramName(): keyof ShaderMap<void> {
|
protected directCurveProgramNameForPass(pass: number): keyof ShaderMap<void> {
|
||||||
if (this.antialiasingStrategy instanceof XCAAStrategy)
|
if (this.antialiasingStrategy instanceof XCAAStrategy && pass === 0)
|
||||||
return 'xcaaMultiDirectCurve';
|
return 'xcaaMultiBGDirectCurve';
|
||||||
return 'directCurve';
|
return 'directCurve';
|
||||||
}
|
}
|
||||||
|
|
||||||
protected get directInteriorProgramName(): keyof ShaderMap<void> {
|
protected directInteriorProgramNameForPass(pass: number): keyof ShaderMap<void> {
|
||||||
if (this.antialiasingStrategy instanceof XCAAStrategy)
|
if (this.antialiasingStrategy instanceof XCAAStrategy && pass === 0)
|
||||||
return 'xcaaMultiDirectInterior';
|
return 'xcaaMultiBGDirectInterior';
|
||||||
return 'directInterior';
|
return 'directInterior';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,8 @@ import {panic, unwrapNull} from "./utils";
|
||||||
|
|
||||||
export const BUILTIN_SVG_URI: string = "/svg/demo";
|
export const BUILTIN_SVG_URI: string = "/svg/demo";
|
||||||
|
|
||||||
|
const parseColor = require('parse-color');
|
||||||
|
|
||||||
const PARTITION_SVG_PATHS_ENDPOINT_URL: string = "/partition-svg-paths";
|
const PARTITION_SVG_PATHS_ENDPOINT_URL: string = "/partition-svg-paths";
|
||||||
|
|
||||||
/// The minimum size of a stroke.
|
/// The minimum size of a stroke.
|
||||||
|
@ -105,9 +107,9 @@ export class SVGLoader {
|
||||||
|
|
||||||
if (element instanceof SVGPathElement) {
|
if (element instanceof SVGPathElement) {
|
||||||
const style = window.getComputedStyle(element);
|
const style = window.getComputedStyle(element);
|
||||||
if (style.fill !== 'none')
|
if (hasRenderingOperation(style.fill))
|
||||||
this.pathInstances.push({ element: element, stroke: 'fill' });
|
this.pathInstances.push({ element: element, stroke: 'fill' });
|
||||||
if (style.stroke !== 'none') {
|
if (hasRenderingOperation(style.stroke)) {
|
||||||
this.pathInstances.push({
|
this.pathInstances.push({
|
||||||
element: element,
|
element: element,
|
||||||
stroke: parseInt(style.strokeWidth!, 10),
|
stroke: parseInt(style.strokeWidth!, 10),
|
||||||
|
@ -159,3 +161,7 @@ export class SVGLoader {
|
||||||
this.bounds = glmatrix.vec4.clone([minX, minY, maxX, maxY]);
|
this.bounds = glmatrix.vec4.clone([minX, minY, maxX, maxY]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function hasRenderingOperation(style: string | null): boolean {
|
||||||
|
return style != null && style !== 'none' && parseColor(style).rgba[3] > 0.0;
|
||||||
|
}
|
||||||
|
|
|
@ -109,14 +109,6 @@ export abstract class TextRenderer extends Renderer {
|
||||||
return glmatrix.vec2.create();
|
return glmatrix.vec2.create();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected get directCurveProgramName(): keyof ShaderMap<void> {
|
|
||||||
return 'directCurve';
|
|
||||||
}
|
|
||||||
|
|
||||||
protected get directInteriorProgramName(): keyof ShaderMap<void> {
|
|
||||||
return 'directInterior';
|
|
||||||
}
|
|
||||||
|
|
||||||
protected get depthFunction(): number {
|
protected get depthFunction(): number {
|
||||||
return this.renderContext.gl.GREATER;
|
return this.renderContext.gl.GREATER;
|
||||||
}
|
}
|
||||||
|
@ -272,4 +264,12 @@ export abstract class TextRenderer extends Renderer {
|
||||||
this.displayPixelsPerUnit,
|
this.displayPixelsPerUnit,
|
||||||
this.renderContext.useHinting);
|
this.renderContext.useHinting);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected directCurveProgramNameForPass(pass: number): keyof ShaderMap<void> {
|
||||||
|
return 'directCurve';
|
||||||
|
}
|
||||||
|
|
||||||
|
protected directInteriorProgramNameForPass(pass: number): keyof ShaderMap<void> {
|
||||||
|
return 'directInterior';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,9 +47,9 @@ export abstract class XCAAStrategy extends AntialiasingStrategy {
|
||||||
|
|
||||||
protected resolveVAO: WebGLVertexArrayObject;
|
protected resolveVAO: WebGLVertexArrayObject;
|
||||||
protected aaAlphaTexture: WebGLTexture;
|
protected aaAlphaTexture: WebGLTexture;
|
||||||
|
protected aaFramebuffer: WebGLFramebuffer;
|
||||||
|
|
||||||
private directFramebuffer: WebGLFramebuffer;
|
private directFramebuffer: WebGLFramebuffer;
|
||||||
private aaFramebuffer: WebGLFramebuffer;
|
|
||||||
|
|
||||||
constructor(level: number, subpixelAA: SubpixelAAType) {
|
constructor(level: number, subpixelAA: SubpixelAAType) {
|
||||||
super();
|
super();
|
||||||
|
@ -66,7 +66,6 @@ export abstract class XCAAStrategy extends AntialiasingStrategy {
|
||||||
|
|
||||||
attachMeshes(renderer: Renderer) {
|
attachMeshes(renderer: Renderer) {
|
||||||
const renderContext = renderer.renderContext;
|
const renderContext = renderer.renderContext;
|
||||||
this.createEdgeDetectVAO(renderContext);
|
|
||||||
this.createResolveVAO(renderer);
|
this.createResolveVAO(renderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,13 +77,12 @@ export abstract class XCAAStrategy extends AntialiasingStrategy {
|
||||||
this.destFramebufferSize,
|
this.destFramebufferSize,
|
||||||
this.supersampleScale);
|
this.supersampleScale);
|
||||||
|
|
||||||
this.initDirectFramebuffer(renderer);
|
this.initDirectFramebufferIfNecessary(renderer);
|
||||||
this.initAAAlphaFramebuffer(renderer);
|
this.initAAAlphaFramebuffer(renderer);
|
||||||
this.initEdgeDetectFramebuffer(renderer);
|
|
||||||
renderContext.gl.bindFramebuffer(renderContext.gl.FRAMEBUFFER, null);
|
renderContext.gl.bindFramebuffer(renderContext.gl.FRAMEBUFFER, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
prepare(renderer: Renderer) {
|
prepareForDirectRendering(renderer: Renderer) {
|
||||||
const renderContext = renderer.renderContext;
|
const renderContext = renderer.renderContext;
|
||||||
const gl = renderContext.gl;
|
const gl = renderContext.gl;
|
||||||
|
|
||||||
|
@ -105,14 +103,17 @@ export abstract class XCAAStrategy extends AntialiasingStrategy {
|
||||||
}
|
}
|
||||||
|
|
||||||
antialias(renderer: Renderer) {
|
antialias(renderer: Renderer) {
|
||||||
// Detect edges if necessary.
|
// Perform early preparations.
|
||||||
this.detectEdgesIfNecessary(renderer);
|
this.createPathBoundsBufferTexture(renderer);
|
||||||
|
|
||||||
|
// Mask edges if necessary.
|
||||||
|
this.maskEdgesIfNecessary(renderer);
|
||||||
|
|
||||||
// Set up antialiasing.
|
// Set up antialiasing.
|
||||||
this.prepareAA(renderer);
|
this.prepareAA(renderer);
|
||||||
|
|
||||||
// Clear.
|
// Clear.
|
||||||
this.clear(renderer);
|
this.clearForAA(renderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
resolve(renderer: Renderer) {
|
resolve(renderer: Renderer) {
|
||||||
|
@ -124,20 +125,14 @@ export abstract class XCAAStrategy extends AntialiasingStrategy {
|
||||||
return glmatrix.mat4.create();
|
return glmatrix.mat4.create();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected initDirectFramebuffer(renderer: Renderer) {
|
protected initDirectFramebufferIfNecessary(renderer: Renderer) {
|
||||||
const renderContext = renderer.renderContext;
|
const renderContext = renderer.renderContext;
|
||||||
const gl = renderContext.gl;
|
const gl = renderContext.gl;
|
||||||
|
|
||||||
let textureFormat;
|
|
||||||
if (this.directRenderingMode === 'pathID')
|
|
||||||
textureFormat = gl.RGBA;
|
|
||||||
else
|
|
||||||
textureFormat = renderContext.colorAlphaFormat;
|
|
||||||
|
|
||||||
this.directTexture = createFramebufferColorTexture(gl,
|
this.directTexture = createFramebufferColorTexture(gl,
|
||||||
this.destFramebufferSize,
|
this.destFramebufferSize,
|
||||||
textureFormat);
|
renderContext.colorAlphaFormat);
|
||||||
this.directFramebuffer = createFramebuffer(renderContext.gl,
|
this.directFramebuffer = createFramebuffer(gl,
|
||||||
this.directTexture,
|
this.directTexture,
|
||||||
this.directDepthTexture);
|
this.directDepthTexture);
|
||||||
}
|
}
|
||||||
|
@ -159,8 +154,6 @@ export abstract class XCAAStrategy extends AntialiasingStrategy {
|
||||||
this.supersampledFramebufferSize[1]);
|
this.supersampledFramebufferSize[1]);
|
||||||
renderContext.gl.scissor(0, 0, usedSize[0], usedSize[1]);
|
renderContext.gl.scissor(0, 0, usedSize[0], usedSize[1]);
|
||||||
renderContext.gl.enable(renderContext.gl.SCISSOR_TEST);
|
renderContext.gl.enable(renderContext.gl.SCISSOR_TEST);
|
||||||
|
|
||||||
this.createPathBoundsBufferTexture(renderer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected setAAState(renderer: Renderer) {
|
protected setAAState(renderer: Renderer) {
|
||||||
|
@ -200,8 +193,7 @@ export abstract class XCAAStrategy extends AntialiasingStrategy {
|
||||||
gl.viewport(0, 0, this.destFramebufferSize[0], this.destFramebufferSize[1]);
|
gl.viewport(0, 0, this.destFramebufferSize[0], this.destFramebufferSize[1]);
|
||||||
gl.scissor(0, 0, usedSize[0], usedSize[1]);
|
gl.scissor(0, 0, usedSize[0], usedSize[1]);
|
||||||
gl.enable(gl.SCISSOR_TEST);
|
gl.enable(gl.SCISSOR_TEST);
|
||||||
gl.disable(gl.DEPTH_TEST);
|
this.setDepthAndBlendModeForResolve(renderContext);
|
||||||
gl.disable(gl.BLEND);
|
|
||||||
|
|
||||||
// Clear out the resolve buffer, if necessary.
|
// Clear out the resolve buffer, if necessary.
|
||||||
this.clearForResolve(renderer);
|
this.clearForResolve(renderer);
|
||||||
|
@ -224,15 +216,25 @@ export abstract class XCAAStrategy extends AntialiasingStrategy {
|
||||||
if (renderer.fgColor != null)
|
if (renderer.fgColor != null)
|
||||||
gl.uniform4fv(resolveProgram.uniforms.uFGColor, renderer.fgColor);
|
gl.uniform4fv(resolveProgram.uniforms.uFGColor, renderer.fgColor);
|
||||||
renderer.setTransformSTAndTexScaleUniformsForDest(resolveProgram.uniforms);
|
renderer.setTransformSTAndTexScaleUniformsForDest(resolveProgram.uniforms);
|
||||||
|
this.setAdditionalStateForResolveIfNecessary(renderer, resolveProgram, 1);
|
||||||
gl.drawElements(renderContext.gl.TRIANGLES, 6, renderContext.gl.UNSIGNED_BYTE, 0);
|
gl.drawElements(renderContext.gl.TRIANGLES, 6, renderContext.gl.UNSIGNED_BYTE, 0);
|
||||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(null);
|
renderContext.vertexArrayObjectExt.bindVertexArrayOES(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract clear(renderer: Renderer): void;
|
protected setDepthAndBlendModeForResolve(renderContext: RenderContext): void {
|
||||||
|
const gl = renderContext.gl;
|
||||||
|
gl.disable(gl.DEPTH_TEST);
|
||||||
|
gl.disable(gl.BLEND);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected setAdditionalStateForResolveIfNecessary(renderer: Renderer,
|
||||||
|
resolveProgram: PathfinderShaderProgram,
|
||||||
|
firstFreeTextureUnit: number):
|
||||||
|
void {}
|
||||||
|
|
||||||
|
protected abstract clearForAA(renderer: Renderer): void;
|
||||||
protected abstract getResolveProgram(renderContext: RenderContext): PathfinderShaderProgram;
|
protected abstract getResolveProgram(renderContext: RenderContext): PathfinderShaderProgram;
|
||||||
protected abstract initEdgeDetectFramebuffer(renderer: Renderer): void;
|
protected abstract maskEdgesIfNecessary(renderer: Renderer): void;
|
||||||
protected abstract createEdgeDetectVAO(renderContext: RenderContext): void;
|
|
||||||
protected abstract detectEdgesIfNecessary(renderer: Renderer): void;
|
|
||||||
protected abstract setAADepthState(renderer: Renderer): void;
|
protected abstract setAADepthState(renderer: Renderer): void;
|
||||||
protected abstract clearForResolve(renderer: Renderer): void;
|
protected abstract clearForResolve(renderer: Renderer): void;
|
||||||
|
|
||||||
|
@ -323,7 +325,7 @@ export abstract class MCAAStrategy extends XCAAStrategy {
|
||||||
renderContext.gl.blendFunc(renderContext.gl.ONE, renderContext.gl.ONE);
|
renderContext.gl.blendFunc(renderContext.gl.ONE, renderContext.gl.ONE);
|
||||||
renderContext.gl.enable(renderContext.gl.BLEND);
|
renderContext.gl.enable(renderContext.gl.BLEND);
|
||||||
|
|
||||||
this.clear(renderer);
|
this.clearForAA(renderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected setCoverDepthState(renderer: Renderer): void {
|
protected setCoverDepthState(renderer: Renderer): void {
|
||||||
|
@ -331,6 +333,64 @@ export abstract class MCAAStrategy extends XCAAStrategy {
|
||||||
renderContext.gl.disable(renderContext.gl.DEPTH_TEST);
|
renderContext.gl.disable(renderContext.gl.DEPTH_TEST);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected antialiasLinesWithProgram(renderer: Renderer,
|
||||||
|
lineProgram: PathfinderShaderProgram): void {
|
||||||
|
const renderContext = renderer.renderContext;
|
||||||
|
|
||||||
|
const uniforms = lineProgram.uniforms;
|
||||||
|
this.setAAUniforms(renderer, uniforms);
|
||||||
|
|
||||||
|
for (const direction of DIRECTIONS) {
|
||||||
|
const vao = this.lineVAOs[direction];
|
||||||
|
renderContext.vertexArrayObjectExt.bindVertexArrayOES(vao);
|
||||||
|
|
||||||
|
this.setBlendModeForAA(renderer, direction);
|
||||||
|
renderContext.gl.uniform1i(uniforms.uWinding, direction === 'upper' ? 1 : 0);
|
||||||
|
|
||||||
|
const count = {
|
||||||
|
lower: renderer.meshData[0].edgeLowerLineCount,
|
||||||
|
upper: renderer.meshData[0].edgeUpperLineCount,
|
||||||
|
}[direction];
|
||||||
|
renderContext.instancedArraysExt
|
||||||
|
.drawElementsInstancedANGLE(renderContext.gl.TRIANGLES,
|
||||||
|
6,
|
||||||
|
renderContext.gl.UNSIGNED_BYTE,
|
||||||
|
0,
|
||||||
|
count);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderContext.vertexArrayObjectExt.bindVertexArrayOES(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected antialiasCurvesWithProgram(renderer: Renderer,
|
||||||
|
curveProgram: PathfinderShaderProgram): void {
|
||||||
|
const renderContext = renderer.renderContext;
|
||||||
|
|
||||||
|
const uniforms = curveProgram.uniforms;
|
||||||
|
this.setAAUniforms(renderer, uniforms);
|
||||||
|
|
||||||
|
for (const direction of DIRECTIONS) {
|
||||||
|
const vao = this.curveVAOs[direction];
|
||||||
|
renderContext.vertexArrayObjectExt.bindVertexArrayOES(vao);
|
||||||
|
|
||||||
|
this.setBlendModeForAA(renderer, direction);
|
||||||
|
renderContext.gl.uniform1i(uniforms.uWinding, direction === 'upper' ? 1 : 0);
|
||||||
|
|
||||||
|
const count = {
|
||||||
|
lower: renderer.meshData[0].edgeLowerCurveCount,
|
||||||
|
upper: renderer.meshData[0].edgeUpperCurveCount,
|
||||||
|
}[direction];
|
||||||
|
renderContext.instancedArraysExt
|
||||||
|
.drawElementsInstancedANGLE(renderContext.gl.TRIANGLES,
|
||||||
|
6,
|
||||||
|
renderContext.gl.UNSIGNED_BYTE,
|
||||||
|
0,
|
||||||
|
count);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderContext.vertexArrayObjectExt.bindVertexArrayOES(null);
|
||||||
|
}
|
||||||
|
|
||||||
private createCoverVAO(renderer: Renderer) {
|
private createCoverVAO(renderer: Renderer) {
|
||||||
const renderContext = renderer.renderContext;
|
const renderContext = renderer.renderContext;
|
||||||
|
|
||||||
|
@ -561,35 +621,13 @@ export abstract class MCAAStrategy extends XCAAStrategy {
|
||||||
|
|
||||||
private antialiasLines(renderer: Renderer) {
|
private antialiasLines(renderer: Renderer) {
|
||||||
const renderContext = renderer.renderContext;
|
const renderContext = renderer.renderContext;
|
||||||
|
|
||||||
this.setAAState(renderer);
|
this.setAAState(renderer);
|
||||||
|
|
||||||
const lineProgram = renderContext.shaderPrograms.mcaaLine;
|
const lineProgram = renderContext.shaderPrograms.mcaaLine;
|
||||||
|
|
||||||
renderContext.gl.useProgram(lineProgram.program);
|
renderContext.gl.useProgram(lineProgram.program);
|
||||||
const uniforms = lineProgram.uniforms;
|
|
||||||
this.setAAUniforms(renderer, uniforms);
|
|
||||||
|
|
||||||
for (const direction of DIRECTIONS) {
|
// FIXME(pcwalton): Refactor.
|
||||||
const vao = this.lineVAOs[direction];
|
this.antialiasLinesWithProgram(renderer, lineProgram);
|
||||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(vao);
|
|
||||||
|
|
||||||
this.setBlendModeForAA(renderer, direction);
|
|
||||||
renderContext.gl.uniform1i(uniforms.uWinding, direction === 'upper' ? 1 : 0);
|
|
||||||
|
|
||||||
const count = {
|
|
||||||
lower: renderer.meshData[0].edgeLowerLineCount,
|
|
||||||
upper: renderer.meshData[0].edgeUpperLineCount,
|
|
||||||
}[direction];
|
|
||||||
renderContext.instancedArraysExt
|
|
||||||
.drawElementsInstancedANGLE(renderContext.gl.TRIANGLES,
|
|
||||||
6,
|
|
||||||
renderContext.gl.UNSIGNED_BYTE,
|
|
||||||
0,
|
|
||||||
count);
|
|
||||||
}
|
|
||||||
|
|
||||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private antialiasCurves(renderer: Renderer) {
|
private antialiasCurves(renderer: Renderer) {
|
||||||
|
@ -600,30 +638,10 @@ export abstract class MCAAStrategy extends XCAAStrategy {
|
||||||
const curveProgram = renderContext.shaderPrograms.mcaaCurve;
|
const curveProgram = renderContext.shaderPrograms.mcaaCurve;
|
||||||
|
|
||||||
renderContext.gl.useProgram(curveProgram.program);
|
renderContext.gl.useProgram(curveProgram.program);
|
||||||
const uniforms = curveProgram.uniforms;
|
|
||||||
this.setAAUniforms(renderer, uniforms);
|
|
||||||
|
|
||||||
for (const direction of DIRECTIONS) {
|
this.antialiasCurvesWithProgram(renderer, curveProgram);
|
||||||
const vao = this.curveVAOs[direction];
|
|
||||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(vao);
|
|
||||||
|
|
||||||
this.setBlendModeForAA(renderer, direction);
|
|
||||||
renderContext.gl.uniform1i(uniforms.uWinding, direction === 'upper' ? 1 : 0);
|
|
||||||
|
|
||||||
const count = {
|
|
||||||
lower: renderer.meshData[0].edgeLowerCurveCount,
|
|
||||||
upper: renderer.meshData[0].edgeUpperCurveCount,
|
|
||||||
}[direction];
|
|
||||||
renderContext.instancedArraysExt
|
|
||||||
.drawElementsInstancedANGLE(renderContext.gl.TRIANGLES,
|
|
||||||
6,
|
|
||||||
renderContext.gl.UNSIGNED_BYTE,
|
|
||||||
0,
|
|
||||||
count);
|
|
||||||
}
|
|
||||||
|
|
||||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ECAAStrategy extends XCAAStrategy {
|
export class ECAAStrategy extends XCAAStrategy {
|
||||||
|
@ -663,13 +681,9 @@ export class ECAAStrategy extends XCAAStrategy {
|
||||||
return renderContext.shaderPrograms.xcaaMonoResolve;
|
return renderContext.shaderPrograms.xcaaMonoResolve;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected initEdgeDetectFramebuffer(renderer: Renderer) {}
|
protected maskEdgesIfNecessary(renderer: Renderer) {}
|
||||||
|
|
||||||
protected createEdgeDetectVAO(renderContext: RenderContext) {}
|
protected clearForAA(renderer: Renderer) {
|
||||||
|
|
||||||
protected detectEdgesIfNecessary(renderer: Renderer) {}
|
|
||||||
|
|
||||||
protected clear(renderer: Renderer) {
|
|
||||||
const renderContext = renderer.renderContext;
|
const renderContext = renderer.renderContext;
|
||||||
renderContext.gl.clearColor(0.0, 0.0, 0.0, 0.0);
|
renderContext.gl.clearColor(0.0, 0.0, 0.0, 0.0);
|
||||||
renderContext.gl.clearDepth(0.0);
|
renderContext.gl.clearDepth(0.0);
|
||||||
|
@ -910,13 +924,9 @@ export class MCAAMonochromeStrategy extends MCAAStrategy {
|
||||||
return renderContext.shaderPrograms.xcaaMonoResolve;
|
return renderContext.shaderPrograms.xcaaMonoResolve;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected initEdgeDetectFramebuffer(renderer: Renderer) {}
|
protected maskEdgesIfNecessary(renderer: Renderer) {}
|
||||||
|
|
||||||
protected createEdgeDetectVAO(renderContext: RenderContext) {}
|
protected clearForAA(renderer: Renderer) {
|
||||||
|
|
||||||
protected detectEdgesIfNecessary(renderer: Renderer) {}
|
|
||||||
|
|
||||||
protected clear(renderer: Renderer) {
|
|
||||||
const renderContext = renderer.renderContext;
|
const renderContext = renderer.renderContext;
|
||||||
renderContext.gl.clearColor(0.0, 0.0, 0.0, 0.0);
|
renderContext.gl.clearColor(0.0, 0.0, 0.0, 0.0);
|
||||||
renderContext.gl.clearDepth(0.0);
|
renderContext.gl.clearDepth(0.0);
|
||||||
|
@ -975,8 +985,8 @@ export class AdaptiveMonochromeXCAAStrategy implements AntialiasingStrategy {
|
||||||
return this.mcaaStrategy.transform;
|
return this.mcaaStrategy.transform;
|
||||||
}
|
}
|
||||||
|
|
||||||
prepare(renderer: Renderer): void {
|
prepareForDirectRendering(renderer: Renderer): void {
|
||||||
this.getAppropriateStrategy(renderer).prepare(renderer);
|
this.getAppropriateStrategy(renderer).prepareForDirectRendering(renderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
antialias(renderer: Renderer): void {
|
antialias(renderer: Renderer): void {
|
||||||
|
@ -995,120 +1005,54 @@ export class AdaptiveMonochromeXCAAStrategy implements AntialiasingStrategy {
|
||||||
}
|
}
|
||||||
|
|
||||||
export class MCAAMulticolorStrategy extends MCAAStrategy {
|
export class MCAAMulticolorStrategy extends MCAAStrategy {
|
||||||
private _directDepthTexture: WebGLTexture;
|
private edgeMaskVAO: WebGLVertexArrayObject;
|
||||||
|
|
||||||
private edgeDetectFramebuffer: WebGLFramebuffer;
|
bindEdgeDepthTexture(gl: WebGLRenderingContext, uniforms: UniformMap, textureUnit: number):
|
||||||
private edgeDetectVAO: WebGLVertexArrayObject;
|
void {
|
||||||
private edgePathIDTexture: WebGLTexture;
|
gl.activeTexture(gl.TEXTURE0 + textureUnit);
|
||||||
|
gl.bindTexture(gl.TEXTURE_2D, this.aaDepthTexture);
|
||||||
|
gl.uniform1i(uniforms.uEdgeDepth, textureUnit);
|
||||||
|
}
|
||||||
|
|
||||||
protected getResolveProgram(renderContext: RenderContext): PathfinderShaderProgram {
|
protected getResolveProgram(renderContext: RenderContext): PathfinderShaderProgram {
|
||||||
return renderContext.shaderPrograms.xcaaMultiResolve;
|
return renderContext.shaderPrograms.xcaaMultiResolve;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected initDirectFramebuffer(renderer: Renderer) {
|
protected initDirectFramebufferIfNecessary(renderer: Renderer) {}
|
||||||
const renderContext = renderer.renderContext;
|
|
||||||
this._directDepthTexture = createFramebufferDepthTexture(renderContext.gl,
|
|
||||||
this.supersampledFramebufferSize);
|
|
||||||
super.initDirectFramebuffer(renderer);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected initEdgeDetectFramebuffer(renderer: Renderer) {
|
protected maskEdgesIfNecessary(renderer: Renderer) {
|
||||||
const renderContext = renderer.renderContext;
|
|
||||||
this.edgePathIDTexture = createFramebufferColorTexture(renderContext.gl,
|
|
||||||
this.supersampledFramebufferSize,
|
|
||||||
renderContext.gl.RGBA);
|
|
||||||
this.edgeDetectFramebuffer = createFramebuffer(renderContext.gl,
|
|
||||||
this.edgePathIDTexture,
|
|
||||||
this.aaDepthTexture);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected createEdgeDetectVAO(renderContext: RenderContext) {
|
|
||||||
this.edgeDetectVAO = renderContext.vertexArrayObjectExt.createVertexArrayOES();
|
|
||||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(this.edgeDetectVAO);
|
|
||||||
|
|
||||||
const edgeDetectProgram = renderContext.shaderPrograms.xcaaEdgeDetect;
|
|
||||||
renderContext.gl.useProgram(edgeDetectProgram.program);
|
|
||||||
renderContext.initQuadVAO(edgeDetectProgram.attributes);
|
|
||||||
|
|
||||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected detectEdgesIfNecessary(renderer: Renderer) {
|
|
||||||
const renderContext = renderer.renderContext;
|
const renderContext = renderer.renderContext;
|
||||||
const gl = renderContext.gl;
|
const gl = renderContext.gl;
|
||||||
|
|
||||||
// Set state for edge detection.
|
// Set state for edge masking.
|
||||||
const edgeDetectProgram = renderContext.shaderPrograms.xcaaEdgeDetect;
|
gl.bindFramebuffer(gl.FRAMEBUFFER, this.aaFramebuffer);
|
||||||
gl.bindFramebuffer(gl.FRAMEBUFFER, this.edgeDetectFramebuffer);
|
|
||||||
gl.viewport(0,
|
gl.viewport(0,
|
||||||
0,
|
0,
|
||||||
this.supersampledFramebufferSize[0],
|
this.supersampledFramebufferSize[0],
|
||||||
this.supersampledFramebufferSize[1]);
|
this.supersampledFramebufferSize[1]);
|
||||||
|
|
||||||
|
gl.colorMask(false, false, false, false);
|
||||||
gl.depthMask(true);
|
gl.depthMask(true);
|
||||||
gl.depthFunc(renderContext.gl.ALWAYS);
|
gl.depthFunc(gl.GREATER);
|
||||||
gl.enable(renderContext.gl.DEPTH_TEST);
|
gl.enable(gl.DEPTH_TEST);
|
||||||
gl.disable(renderContext.gl.BLEND);
|
gl.disable(gl.BLEND);
|
||||||
|
|
||||||
gl.clearDepth(0.0);
|
gl.clearDepth(0.0);
|
||||||
gl.clearColor(0.0, 0.0, 0.0, 0.0);
|
gl.clearColor(0.0, 0.0, 0.0, 0.0);
|
||||||
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
||||||
|
|
||||||
// Perform edge detection.
|
// Perform edge masking.
|
||||||
gl.useProgram(edgeDetectProgram.program);
|
const edgeMaskLineProgram = renderer.renderContext.shaderPrograms.xcaaMultiEdgeMaskLine;
|
||||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(this.edgeDetectVAO);
|
gl.useProgram(edgeMaskLineProgram.program);
|
||||||
renderer.setFramebufferSizeUniform(edgeDetectProgram.uniforms);
|
this.antialiasLinesWithProgram(renderer, edgeMaskLineProgram);
|
||||||
renderer.setTransformSTAndTexScaleUniformsForDest(edgeDetectProgram.uniforms);
|
const edgeMaskCurveProgram = renderer.renderContext.shaderPrograms.xcaaMultiEdgeMaskCurve;
|
||||||
renderer.setPathColorsUniform(0, edgeDetectProgram.uniforms, 0);
|
gl.useProgram(edgeMaskCurveProgram.program);
|
||||||
gl.activeTexture(renderContext.gl.TEXTURE1);
|
this.antialiasCurvesWithProgram(renderer, edgeMaskCurveProgram);
|
||||||
gl.bindTexture(renderContext.gl.TEXTURE_2D, this.directTexture);
|
|
||||||
gl.uniform1i(edgeDetectProgram.uniforms.uPathID, 1);
|
|
||||||
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, renderContext.quadElementsBuffer);
|
|
||||||
gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_BYTE, 0);
|
|
||||||
|
|
||||||
|
gl.colorMask(true, true, true, true);
|
||||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(null);
|
renderContext.vertexArrayObjectExt.bindVertexArrayOES(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected resolveAA(renderer: Renderer) {
|
|
||||||
const renderContext = renderer.renderContext;
|
|
||||||
const gl = renderContext.gl;
|
|
||||||
|
|
||||||
// Set state for ECAA resolve.
|
|
||||||
const usedSize = renderer.destUsedSize;
|
|
||||||
renderContext.gl.bindFramebuffer(renderContext.gl.FRAMEBUFFER, renderer.destFramebuffer);
|
|
||||||
renderContext.gl.viewport(0, 0, this.destFramebufferSize[0], this.destFramebufferSize[1]);
|
|
||||||
renderContext.gl.scissor(0, 0, usedSize[0], usedSize[1]);
|
|
||||||
renderContext.gl.enable(renderContext.gl.SCISSOR_TEST);
|
|
||||||
renderContext.gl.disable(renderContext.gl.DEPTH_TEST);
|
|
||||||
renderContext.gl.disable(renderContext.gl.BLEND);
|
|
||||||
|
|
||||||
// Resolve.
|
|
||||||
const resolveProgram = this.getResolveProgram(renderContext);
|
|
||||||
gl.useProgram(resolveProgram.program);
|
|
||||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(this.resolveVAO);
|
|
||||||
gl.uniform2i(resolveProgram.uniforms.uFramebufferSize,
|
|
||||||
this.destFramebufferSize[0],
|
|
||||||
this.destFramebufferSize[1]);
|
|
||||||
renderContext.gl.activeTexture(renderContext.gl.TEXTURE0);
|
|
||||||
renderContext.gl.bindTexture(renderContext.gl.TEXTURE_2D, this.aaAlphaTexture);
|
|
||||||
renderContext.gl.uniform1i(resolveProgram.uniforms.uAAAlpha, 0);
|
|
||||||
renderContext.gl.uniform2i(resolveProgram.uniforms.uAAAlphaDimensions,
|
|
||||||
this.supersampledFramebufferSize[0],
|
|
||||||
this.supersampledFramebufferSize[1]);
|
|
||||||
renderContext.gl.activeTexture(renderContext.gl.TEXTURE1);
|
|
||||||
renderContext.gl.bindTexture(renderContext.gl.TEXTURE_2D, this.edgePathIDTexture);
|
|
||||||
renderContext.gl.uniform1i(resolveProgram.uniforms.uBGFGPathID, 1);
|
|
||||||
renderer.setPathColorsUniform(0, resolveProgram.uniforms, 2);
|
|
||||||
renderer.setTransformSTAndTexScaleUniformsForDest(resolveProgram.uniforms);
|
|
||||||
renderContext.gl.drawElements(renderContext.gl.TRIANGLES,
|
|
||||||
6,
|
|
||||||
renderContext.gl.UNSIGNED_BYTE,
|
|
||||||
0);
|
|
||||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(null);
|
|
||||||
|
|
||||||
renderContext.gl.bindFramebuffer(renderContext.gl.FRAMEBUFFER, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected setCoverDepthState(renderer: Renderer) {
|
protected setCoverDepthState(renderer: Renderer) {
|
||||||
const renderContext = renderer.renderContext;
|
const renderContext = renderer.renderContext;
|
||||||
renderContext.gl.depthMask(false);
|
renderContext.gl.depthMask(false);
|
||||||
|
@ -1116,26 +1060,56 @@ export class MCAAMulticolorStrategy extends MCAAStrategy {
|
||||||
renderContext.gl.enable(renderContext.gl.DEPTH_TEST);
|
renderContext.gl.enable(renderContext.gl.DEPTH_TEST);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected clear(renderer: Renderer) {
|
protected clearForAA(renderer: Renderer) {
|
||||||
const renderContext = renderer.renderContext;
|
const renderContext = renderer.renderContext;
|
||||||
renderContext.gl.clearColor(0.0, 0.0, 0.0, 0.0);
|
const gl = renderContext.gl;
|
||||||
renderContext.gl.clear(renderContext.gl.COLOR_BUFFER_BIT);
|
|
||||||
|
gl.clearColor(0.0, 0.0, 0.0, 0.0);
|
||||||
|
gl.clear(gl.COLOR_BUFFER_BIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected setAADepthState(renderer: Renderer) {
|
protected setAADepthState(renderer: Renderer) {
|
||||||
const renderContext = renderer.renderContext;
|
const renderContext = renderer.renderContext;
|
||||||
renderContext.gl.depthMask(false);
|
const gl = renderContext.gl;
|
||||||
renderContext.gl.depthFunc(renderContext.gl.EQUAL);
|
|
||||||
renderContext.gl.enable(renderContext.gl.DEPTH_TEST);
|
gl.depthMask(false);
|
||||||
|
gl.depthFunc(gl.EQUAL);
|
||||||
|
gl.enable(gl.DEPTH_TEST);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected 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) {}
|
protected clearForResolve(renderer: Renderer) {}
|
||||||
|
|
||||||
get directRenderingMode(): DirectRenderingMode {
|
protected setAdditionalStateForResolveIfNecessary(renderer: Renderer,
|
||||||
return 'pathID';
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected get directDepthTexture(): WebGLTexture {
|
get directRenderingMode(): DirectRenderingMode {
|
||||||
return this._directDepthTexture;
|
return 'two-pass';
|
||||||
|
}
|
||||||
|
|
||||||
|
protected get directDepthTexture(): WebGLTexture | null {
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -109,6 +109,11 @@ float convertPathIndexToWindowDepthValue(int pathIndex) {
|
||||||
return float(pathIndex) / float(MAX_PATHS);
|
return float(pathIndex) / float(MAX_PATHS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int convertWindowDepthValueToPathIndex(float depthValue) {
|
||||||
|
float pathIndex = floor(depthValue * float(MAX_PATHS));
|
||||||
|
return int(pathIndex);
|
||||||
|
}
|
||||||
|
|
||||||
bool computeMCAAQuadPosition(out vec2 outPosition,
|
bool computeMCAAQuadPosition(out vec2 outPosition,
|
||||||
inout vec2 leftPosition,
|
inout vec2 leftPosition,
|
||||||
inout vec2 rightPosition,
|
inout vec2 rightPosition,
|
||||||
|
@ -261,6 +266,37 @@ float computeCoverage(vec2 p0, vec2 dp, vec2 center, float winding) {
|
||||||
return abs(area) * winding * 0.5;
|
return abs(area) * winding * 0.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME(pcwalton): Combine with `computeCoverage`.
|
||||||
|
bool isPartiallyCovered(vec2 p0, vec2 dp, vec2 center, float winding) {
|
||||||
|
// Set some flags.
|
||||||
|
bool slopeNegative = dp.y < -0.001;
|
||||||
|
bool slopeZero = abs(dp.y) < 0.001;
|
||||||
|
|
||||||
|
// Determine the bounds of this pixel.
|
||||||
|
vec4 pixelExtents = center.xxyy + vec4(-0.5, 0.5, -0.5, 0.5);
|
||||||
|
|
||||||
|
// Set up Liang-Barsky clipping.
|
||||||
|
vec4 q = pixelExtents - p0.xxyy;
|
||||||
|
|
||||||
|
// Use Liang-Barsky to clip to the left and right sides of this pixel.
|
||||||
|
vec2 t = clamp(q.xy / dp.xx, 0.0, 1.0);
|
||||||
|
vec2 spanP0 = p0 + dp * t.x, spanP1 = p0 + dp * t.y;
|
||||||
|
|
||||||
|
// Likewise, clip to the to the bottom and top.
|
||||||
|
if (!slopeZero) {
|
||||||
|
vec2 tVertical = q.zw / dp.yy;
|
||||||
|
if (slopeNegative)
|
||||||
|
tVertical.xy = tVertical.yx; // FIXME(pcwalton): Can this be removed?
|
||||||
|
t = vec2(max(t.x, tVertical.x), min(t.y, tVertical.y));
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the line doesn't pass through this pixel, detect that and bail.
|
||||||
|
//
|
||||||
|
// This should be worth a branch because it's very common for fragment blocks to all hit this
|
||||||
|
// path.
|
||||||
|
return !(t.x >= t.y || (slopeZero && (p0.y < pixelExtents.z || p0.y > pixelExtents.w)));
|
||||||
|
}
|
||||||
|
|
||||||
// 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,4 +1,4 @@
|
||||||
// pathfinder/shaders/gles2/xcaa-multi-direct-curve.fs.glsl
|
// pathfinder/shaders/gles2/xcaa-multi-bg-direct-curve.fs.glsl
|
||||||
//
|
//
|
||||||
// Copyright (c) 2017 The Pathfinder Project Developers.
|
// Copyright (c) 2017 The Pathfinder Project Developers.
|
||||||
//
|
//
|
||||||
|
@ -12,12 +12,23 @@
|
||||||
|
|
||||||
precision highp float;
|
precision highp float;
|
||||||
|
|
||||||
varying vec2 vPathID;
|
uniform ivec2 uFramebufferSize;
|
||||||
|
uniform sampler2D uEdgeDepth;
|
||||||
|
|
||||||
|
varying vec4 vColor;
|
||||||
varying vec2 vTexCoord;
|
varying vec2 vTexCoord;
|
||||||
varying float vSign;
|
varying float vSign;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
|
vec2 center = floor(gl_FragCoord.xy);
|
||||||
|
float depth = gl_FragCoord.z;
|
||||||
|
vec2 texCoord = floor(center) / vec2(uFramebufferSize);
|
||||||
|
|
||||||
|
// TODO(pcwalton): Remove this if possible?
|
||||||
|
if (depth >= texture2D(uEdgeDepth, texCoord).r)
|
||||||
|
discard;
|
||||||
|
|
||||||
float side = vTexCoord.x * vTexCoord.x - vTexCoord.y;
|
float side = vTexCoord.x * vTexCoord.x - vTexCoord.y;
|
||||||
float alpha = float(sign(side) == sign(vSign));
|
float alpha = float(sign(side) == sign(vSign));
|
||||||
gl_FragColor = vec4(vPathID, 0.0, alpha);
|
gl_FragColor = vec4(vColor.rgb, vColor.a * alpha);
|
||||||
}
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
// pathfinder/shaders/gles2/xcaa-multi-direct-curve.vs.glsl
|
// pathfinder/shaders/gles2/xcaa-multi-bg-direct-curve.vs.glsl
|
||||||
//
|
//
|
||||||
// Copyright (c) 2017 The Pathfinder Project Developers.
|
// Copyright (c) 2017 The Pathfinder Project Developers.
|
||||||
//
|
//
|
||||||
|
@ -12,6 +12,8 @@ precision highp float;
|
||||||
|
|
||||||
uniform mat4 uTransform;
|
uniform mat4 uTransform;
|
||||||
uniform vec4 uHints;
|
uniform vec4 uHints;
|
||||||
|
uniform ivec2 uPathColorsDimensions;
|
||||||
|
uniform sampler2D uPathColors;
|
||||||
uniform ivec2 uPathTransformDimensions;
|
uniform ivec2 uPathTransformDimensions;
|
||||||
uniform sampler2D uPathTransform;
|
uniform sampler2D uPathTransform;
|
||||||
|
|
||||||
|
@ -20,7 +22,7 @@ attribute vec2 aTexCoord;
|
||||||
attribute float aPathID;
|
attribute float aPathID;
|
||||||
attribute float aSign;
|
attribute float aSign;
|
||||||
|
|
||||||
varying vec2 vPathID;
|
varying vec4 vColor;
|
||||||
varying vec2 vTexCoord;
|
varying vec2 vTexCoord;
|
||||||
varying float vSign;
|
varying float vSign;
|
||||||
|
|
||||||
|
@ -36,7 +38,7 @@ void main() {
|
||||||
float depth = convertPathIndexToViewportDepthValue(pathID);
|
float depth = convertPathIndexToViewportDepthValue(pathID);
|
||||||
gl_Position = vec4(position, depth, 1.0);
|
gl_Position = vec4(position, depth, 1.0);
|
||||||
|
|
||||||
vPathID = packPathID(pathID);
|
vColor = fetchFloat4Data(uPathColors, pathID, uPathColorsDimensions);
|
||||||
vTexCoord = vec2(aTexCoord) / 2.0;
|
vTexCoord = vec2(aTexCoord) / 2.0;
|
||||||
vSign = aSign;
|
vSign = aSign;
|
||||||
}
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
// pathfinder/shaders/gles2/xcaa-multi-bg-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 uEdgeDepth;
|
||||||
|
|
||||||
|
varying vec4 vColor;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec2 center = floor(gl_FragCoord.xy);
|
||||||
|
float depth = gl_FragCoord.z;
|
||||||
|
vec2 texCoord = floor(center) / vec2(uFramebufferSize);
|
||||||
|
|
||||||
|
// TODO(pcwalton): Remove this if possible?
|
||||||
|
if (depth >= texture2D(uEdgeDepth, texCoord).r)
|
||||||
|
discard;
|
||||||
|
|
||||||
|
gl_FragColor = vColor;
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
// pathfinder/shaders/gles2/xcaa-multi-direct-interior.vs.glsl
|
// pathfinder/shaders/gles2/xcaa-multi-bg-direct-interior.vs.glsl
|
||||||
//
|
//
|
||||||
// Copyright (c) 2017 The Pathfinder Project Developers.
|
// Copyright (c) 2017 The Pathfinder Project Developers.
|
||||||
//
|
//
|
||||||
|
@ -12,13 +12,16 @@ precision highp float;
|
||||||
|
|
||||||
uniform mat4 uTransform;
|
uniform mat4 uTransform;
|
||||||
uniform vec4 uHints;
|
uniform vec4 uHints;
|
||||||
|
uniform ivec2 uPathColorsDimensions;
|
||||||
uniform ivec2 uPathTransformDimensions;
|
uniform ivec2 uPathTransformDimensions;
|
||||||
|
uniform sampler2D uPathColors;
|
||||||
uniform sampler2D uPathTransform;
|
uniform sampler2D uPathTransform;
|
||||||
|
|
||||||
attribute vec2 aPosition;
|
attribute vec2 aPosition;
|
||||||
attribute float aPathID;
|
attribute float aPathID;
|
||||||
|
|
||||||
varying vec2 vPathID;
|
varying vec4 vColor;
|
||||||
|
varying float vSign;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
int pathID = int(aPathID);
|
int pathID = int(aPathID);
|
||||||
|
@ -32,5 +35,5 @@ void main() {
|
||||||
float depth = convertPathIndexToViewportDepthValue(pathID);
|
float depth = convertPathIndexToViewportDepthValue(pathID);
|
||||||
gl_Position = vec4(position, depth, 1.0);
|
gl_Position = vec4(position, depth, 1.0);
|
||||||
|
|
||||||
vPathID = packPathID(pathID);
|
vColor = fetchFloat4Data(uPathColors, pathID, uPathColorsDimensions);
|
||||||
}
|
}
|
|
@ -1,17 +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;
|
|
||||||
|
|
||||||
varying vec2 vPathID;
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
gl_FragColor = vec4(vPathID, 0.0, 1.0);
|
|
||||||
}
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
// 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;
|
||||||
|
varying float vWinding;
|
||||||
|
|
||||||
|
// Solve the equation:
|
||||||
|
//
|
||||||
|
// x = p0x + t^2 * (p0x - 2*p1x + p2x) + t*(2*p1x - 2*p0x)
|
||||||
|
//
|
||||||
|
// We use the Citardauq Formula to avoid floating point precision issues.
|
||||||
|
float solveCurveT(float p0x, float p1x, float p2x, float x) {
|
||||||
|
float a = p0x - 2.0 * p1x + p2x;
|
||||||
|
float b = 2.0 * p1x - 2.0 * p0x;
|
||||||
|
float c = p0x - x;
|
||||||
|
return 2.0 * c / (-b - sqrt(b * b - 4.0 * a * c));
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
// Unpack.
|
||||||
|
vec2 center = gl_FragCoord.xy;
|
||||||
|
vec2 p0 = vEndpoints.xy, p1 = vEndpoints.zw;
|
||||||
|
vec2 cp = vControlPoint;
|
||||||
|
|
||||||
|
// Compute pixel extents.
|
||||||
|
vec4 pixelExtents = center.xxyy + vec4(-0.5, 0.5, -0.5, 0.5);
|
||||||
|
|
||||||
|
// Clip the curve to the left and right edges to create a line.
|
||||||
|
//
|
||||||
|
// TODO(pcwalton): Consider clipping to the bottom and top edges properly too. (I kind of doubt
|
||||||
|
// it's worth it to do this, though, given that the maximum error doing it this way will always
|
||||||
|
// be less than a pixel, and it saves a lot of time.)
|
||||||
|
//
|
||||||
|
// FIXME(pcwalton): Factor out shared terms to avoid computing them multiple times.
|
||||||
|
vec2 t = vec2(p0.x < pixelExtents.x ? solveCurveT(p0.x, cp.x, p1.x, pixelExtents.x) : 0.0,
|
||||||
|
p1.x > pixelExtents.y ? solveCurveT(p0.x, cp.x, p1.x, pixelExtents.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, center, vWinding))
|
||||||
|
discard;
|
||||||
|
gl_FragColor = vec4(1.0);
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
// 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;
|
||||||
|
varying float vWinding;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
// Unpack.
|
||||||
|
vec2 center = gl_FragCoord.xy;
|
||||||
|
vec2 p0 = vEndpoints.xy, p1 = vEndpoints.zw;
|
||||||
|
|
||||||
|
// Set up Liang-Barsky clipping.
|
||||||
|
vec4 pixelExtents = center.xxyy + vec4(-0.5, 0.5, -0.5, 0.5);
|
||||||
|
vec2 dp = p1 - p0;
|
||||||
|
vec4 q = pixelExtents - p0.xxyy;
|
||||||
|
|
||||||
|
// Use Liang-Barsky to clip to the left and right sides of this pixel.
|
||||||
|
vec2 t = clamp(q.xy / dp.xx, 0.0, 1.0);
|
||||||
|
vec2 spanP0 = p0 + dp * t.x, spanP1 = p0 + dp * t.y;
|
||||||
|
|
||||||
|
// Discard if not edge.
|
||||||
|
if (!isPartiallyCovered(p0, dp, center, vWinding))
|
||||||
|
discard;
|
||||||
|
gl_FragColor = vec4(1.0);
|
||||||
|
}
|
|
@ -11,20 +11,17 @@
|
||||||
precision highp float;
|
precision highp float;
|
||||||
|
|
||||||
uniform ivec2 uPathColorsDimensions;
|
uniform ivec2 uPathColorsDimensions;
|
||||||
uniform sampler2D uBGFGPathID;
|
|
||||||
uniform sampler2D uAAAlpha;
|
uniform sampler2D uAAAlpha;
|
||||||
|
uniform sampler2D uAADepth;
|
||||||
uniform sampler2D uPathColors;
|
uniform sampler2D uPathColors;
|
||||||
|
|
||||||
varying vec2 vTexCoord;
|
varying vec2 vTexCoord;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
vec4 packedPathIDsBGFG = texture2D(uBGFGPathID, vTexCoord);
|
float edgeDepth = texture2D(uAADepth, vTexCoord).r;
|
||||||
int pathIDBG = unpackPathID(packedPathIDsBGFG.xy);
|
int edgePathID = convertWindowDepthValueToPathIndex(edgeDepth);
|
||||||
int pathIDFG = unpackPathID(packedPathIDsBGFG.zw);
|
vec4 edgeColor = fetchFloat4Data(uPathColors, edgePathID, uPathColorsDimensions);
|
||||||
vec4 bgColor = fetchFloat4Data(uPathColors, pathIDBG, uPathColorsDimensions);
|
float edgeAlpha = texture2D(uAAAlpha, vTexCoord).r;
|
||||||
vec4 fgColor = fetchFloat4Data(uPathColors, pathIDFG, uPathColorsDimensions);
|
gl_FragColor = vec4(edgeColor.rgb, edgeColor.a * edgeAlpha);
|
||||||
float alpha = clamp(texture2D(uAAAlpha, vTexCoord).r, 0.0, 1.0);
|
gl_FragDepthEXT = edgeDepth;
|
||||||
gl_FragColor = mix(bgColor, fgColor, alpha);
|
|
||||||
//gl_FragColor = vec4(vec3(alpha), 1.0);
|
|
||||||
//gl_FragColor = bgColor != fgColor ? vec4(1.0, 0.0, 0.0, 1.0) : vec4(1.0);
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue