Merge MCAA monochrome and multicolor shaders.
Not only is this a lot simpler, it's faster too!
This commit is contained in:
parent
017a2e2f8c
commit
11913a20f1
|
@ -364,6 +364,10 @@ class ThreeDRenderer extends Renderer {
|
||||||
|
|
||||||
camera: PerspectiveCamera;
|
camera: PerspectiveCamera;
|
||||||
|
|
||||||
|
get isMulticolor(): boolean {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
get usesSTTransform(): boolean {
|
get usesSTTransform(): boolean {
|
||||||
return this.camera.usesSTTransform;
|
return this.camera.usesSTTransform;
|
||||||
}
|
}
|
||||||
|
@ -702,7 +706,7 @@ class ThreeDRenderer extends Renderer {
|
||||||
gl.disable(gl.SCISSOR_TEST);
|
gl.disable(gl.SCISSOR_TEST);
|
||||||
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.ONE, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE);
|
||||||
|
|
||||||
// Draw textures for distant glyphs.
|
// Draw textures for distant glyphs.
|
||||||
const cameraTransform = this.calculateCameraTransform(glmatrix.vec3.create(), TEXT_SCALE);
|
const cameraTransform = this.calculateCameraTransform(glmatrix.vec3.create(), TEXT_SCALE);
|
||||||
|
|
|
@ -423,6 +423,10 @@ class BenchmarkTextRenderer extends Renderer {
|
||||||
|
|
||||||
camera: OrthographicCamera;
|
camera: OrthographicCamera;
|
||||||
|
|
||||||
|
get isMulticolor(): boolean {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
get usesSTTransform(): boolean {
|
get usesSTTransform(): boolean {
|
||||||
return this.camera.usesSTTransform;
|
return this.camera.usesSTTransform;
|
||||||
}
|
}
|
||||||
|
|
|
@ -668,6 +668,10 @@ class ReferenceTestTextRenderer extends Renderer {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get isMulticolor(): boolean {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
get bgColor(): glmatrix.vec4 {
|
get bgColor(): glmatrix.vec4 {
|
||||||
return glmatrix.vec4.clone([1.0, 1.0, 1.0, 1.0]);
|
return glmatrix.vec4.clone([1.0, 1.0, 1.0, 1.0]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,6 +67,8 @@ export abstract class Renderer {
|
||||||
return this.meshes != null && this.meshData != null;
|
return this.meshes != null && this.meshData != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
abstract get isMulticolor(): boolean;
|
||||||
|
|
||||||
abstract get destFramebuffer(): WebGLFramebuffer | null;
|
abstract get destFramebuffer(): WebGLFramebuffer | null;
|
||||||
abstract get destAllocatedSize(): glmatrix.vec2;
|
abstract get destAllocatedSize(): glmatrix.vec2;
|
||||||
abstract get destUsedSize(): glmatrix.vec2;
|
abstract get destUsedSize(): glmatrix.vec2;
|
||||||
|
@ -131,14 +133,14 @@ export abstract class Renderer {
|
||||||
if (this.meshes == null)
|
if (this.meshes == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
this.clearDestFramebuffer();
|
||||||
|
|
||||||
// Start timing rendering.
|
// Start timing rendering.
|
||||||
if (this.timerQueryPollInterval == null) {
|
if (this.timerQueryPollInterval == null) {
|
||||||
renderContext.timerQueryExt.beginQueryEXT(renderContext.timerQueryExt.TIME_ELAPSED_EXT,
|
renderContext.timerQueryExt.beginQueryEXT(renderContext.timerQueryExt.TIME_ELAPSED_EXT,
|
||||||
renderContext.atlasRenderingTimerQuery);
|
renderContext.atlasRenderingTimerQuery);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.clearDestFramebuffer();
|
|
||||||
|
|
||||||
const antialiasingStrategy = unwrapNull(this.antialiasingStrategy);
|
const antialiasingStrategy = unwrapNull(this.antialiasingStrategy);
|
||||||
antialiasingStrategy.prepareForRendering(this);
|
antialiasingStrategy.prepareForRendering(this);
|
||||||
|
|
||||||
|
@ -155,8 +157,16 @@ export abstract class Renderer {
|
||||||
// Antialias.
|
// Antialias.
|
||||||
antialiasingStrategy.antialiasObject(this, objectIndex);
|
antialiasingStrategy.antialiasObject(this, objectIndex);
|
||||||
|
|
||||||
// Perform post-antialiasing tasks.
|
// End the timer, and start a new one.
|
||||||
antialiasingStrategy.finishAntialiasingObject(this, objectIndex);
|
// FIXME(pcwalton): This is kinda bogus for multipass.
|
||||||
|
if (this.timerQueryPollInterval == null && objectIndex === objectCount - 1 &&
|
||||||
|
pass === passCount - 1) {
|
||||||
|
renderContext.timerQueryExt
|
||||||
|
.endQueryEXT(renderContext.timerQueryExt.TIME_ELAPSED_EXT);
|
||||||
|
renderContext.timerQueryExt
|
||||||
|
.beginQueryEXT(renderContext.timerQueryExt.TIME_ELAPSED_EXT,
|
||||||
|
renderContext.compositingTimerQuery);
|
||||||
|
}
|
||||||
|
|
||||||
// Perform direct rendering (Loop-Blinn).
|
// Perform direct rendering (Loop-Blinn).
|
||||||
if (antialiasingStrategy.directRenderingMode !== 'none') {
|
if (antialiasingStrategy.directRenderingMode !== 'none') {
|
||||||
|
@ -169,20 +179,15 @@ export abstract class Renderer {
|
||||||
this.directlyRenderObject(pass, objectIndex);
|
this.directlyRenderObject(pass, objectIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Perform post-antialiasing tasks.
|
||||||
|
antialiasingStrategy.finishAntialiasingObject(this, objectIndex);
|
||||||
|
|
||||||
antialiasingStrategy.resolveAAForObject(this, objectIndex);
|
antialiasingStrategy.resolveAAForObject(this, objectIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
antialiasingStrategy.resolve(pass, this);
|
antialiasingStrategy.resolve(pass, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
// End the timer, and start a new one.
|
|
||||||
// FIXME(pcwalton): Removed this for multipass; get it split out again somehow.
|
|
||||||
if (this.timerQueryPollInterval == null) {
|
|
||||||
renderContext.timerQueryExt.endQueryEXT(renderContext.timerQueryExt.TIME_ELAPSED_EXT);
|
|
||||||
renderContext.timerQueryExt.beginQueryEXT(renderContext.timerQueryExt.TIME_ELAPSED_EXT,
|
|
||||||
renderContext.compositingTimerQuery);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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();
|
||||||
|
|
||||||
|
@ -306,22 +311,24 @@ export abstract class Renderer {
|
||||||
|
|
||||||
uploadPathTransforms(objectCount: number): void {
|
uploadPathTransforms(objectCount: number): void {
|
||||||
const renderContext = this.renderContext;
|
const renderContext = this.renderContext;
|
||||||
|
const gl = renderContext.gl;
|
||||||
|
|
||||||
for (let objectIndex = 0; objectIndex < objectCount; objectIndex++) {
|
for (let objectIndex = 0; objectIndex < objectCount; objectIndex++) {
|
||||||
const pathTransforms = this.pathTransformsForObject(objectIndex);
|
const pathTransforms = this.pathTransformsForObject(objectIndex);
|
||||||
|
|
||||||
let pathTransformBufferTextures;
|
let pathTransformBufferTextures;
|
||||||
if (objectIndex >= this.pathTransformBufferTextures.length) {
|
if (objectIndex >= this.pathTransformBufferTextures.length) {
|
||||||
pathTransformBufferTextures = {
|
pathTransformBufferTextures = {
|
||||||
ext: new PathfinderBufferTexture(renderContext.gl, 'uPathTransformExt'),
|
ext: new PathfinderBufferTexture(gl, 'uPathTransformExt'),
|
||||||
st: new PathfinderBufferTexture(renderContext.gl, 'uPathTransformST'),
|
st: new PathfinderBufferTexture(gl, 'uPathTransformST'),
|
||||||
};
|
};
|
||||||
this.pathTransformBufferTextures[objectIndex] = pathTransformBufferTextures;
|
this.pathTransformBufferTextures[objectIndex] = pathTransformBufferTextures;
|
||||||
} else {
|
} else {
|
||||||
pathTransformBufferTextures = this.pathTransformBufferTextures[objectIndex];
|
pathTransformBufferTextures = this.pathTransformBufferTextures[objectIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
pathTransformBufferTextures.st.upload(renderContext.gl, pathTransforms.st);
|
pathTransformBufferTextures.st.upload(gl, pathTransforms.st);
|
||||||
pathTransformBufferTextures.ext.upload(renderContext.gl, pathTransforms.ext);
|
pathTransformBufferTextures.ext.upload(gl, pathTransforms.ext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -501,7 +508,7 @@ export abstract class Renderer {
|
||||||
gl.depthMask(false);
|
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.ONE, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE);
|
||||||
|
|
||||||
// Set up the direct curve VAO.
|
// Set up the direct curve VAO.
|
||||||
//
|
//
|
||||||
|
|
|
@ -23,10 +23,7 @@ export interface ShaderMap<T> {
|
||||||
ecaaLine: T;
|
ecaaLine: T;
|
||||||
ecaaCurve: T;
|
ecaaCurve: T;
|
||||||
ecaaTransformedCurve: T;
|
ecaaTransformedCurve: T;
|
||||||
mcaaCover: T;
|
mcaa: T;
|
||||||
mcaaLine: T;
|
|
||||||
mcaaCurve: T;
|
|
||||||
mcaaMulti: T;
|
|
||||||
ssaaSubpixelResolve: T;
|
ssaaSubpixelResolve: T;
|
||||||
xcaaMonoResolve: T;
|
xcaaMonoResolve: T;
|
||||||
xcaaMonoSubpixelResolve: T;
|
xcaaMonoSubpixelResolve: T;
|
||||||
|
@ -47,10 +44,7 @@ export const SHADER_NAMES: Array<keyof ShaderMap<void>> = [
|
||||||
'direct3DCurve',
|
'direct3DCurve',
|
||||||
'direct3DInterior',
|
'direct3DInterior',
|
||||||
'ssaaSubpixelResolve',
|
'ssaaSubpixelResolve',
|
||||||
'mcaaCover',
|
'mcaa',
|
||||||
'mcaaLine',
|
|
||||||
'mcaaCurve',
|
|
||||||
'mcaaMulti',
|
|
||||||
'ecaaLine',
|
'ecaaLine',
|
||||||
'ecaaCurve',
|
'ecaaCurve',
|
||||||
'ecaaTransformedCurve',
|
'ecaaTransformedCurve',
|
||||||
|
@ -94,32 +88,20 @@ const SHADER_URLS: ShaderMap<ShaderProgramURLs> = {
|
||||||
vertex: "/glsl/gles2/direct-interior.vs.glsl",
|
vertex: "/glsl/gles2/direct-interior.vs.glsl",
|
||||||
},
|
},
|
||||||
ecaaCurve: {
|
ecaaCurve: {
|
||||||
fragment: "/glsl/gles2/xcaa-curve.fs.glsl",
|
fragment: "/glsl/gles2/ecaa-curve.fs.glsl",
|
||||||
vertex: "/glsl/gles2/ecaa-curve.vs.glsl",
|
vertex: "/glsl/gles2/ecaa-curve.vs.glsl",
|
||||||
},
|
},
|
||||||
ecaaLine: {
|
ecaaLine: {
|
||||||
fragment: "/glsl/gles2/xcaa-line.fs.glsl",
|
fragment: "/glsl/gles2/ecaa-line.fs.glsl",
|
||||||
vertex: "/glsl/gles2/ecaa-line.vs.glsl",
|
vertex: "/glsl/gles2/ecaa-line.vs.glsl",
|
||||||
},
|
},
|
||||||
ecaaTransformedCurve: {
|
ecaaTransformedCurve: {
|
||||||
fragment: "/glsl/gles2/xcaa-curve.fs.glsl",
|
fragment: "/glsl/gles2/ecaa-curve.fs.glsl",
|
||||||
vertex: "/glsl/gles2/ecaa-transformed-curve.vs.glsl",
|
vertex: "/glsl/gles2/ecaa-transformed-curve.vs.glsl",
|
||||||
},
|
},
|
||||||
mcaaCover: {
|
mcaa: {
|
||||||
fragment: "/glsl/gles2/mcaa-cover.fs.glsl",
|
fragment: "/glsl/gles2/mcaa.fs.glsl",
|
||||||
vertex: "/glsl/gles2/mcaa-cover.vs.glsl",
|
vertex: "/glsl/gles2/mcaa.vs.glsl",
|
||||||
},
|
|
||||||
mcaaCurve: {
|
|
||||||
fragment: "/glsl/gles2/xcaa-curve.fs.glsl",
|
|
||||||
vertex: "/glsl/gles2/mcaa-curve.vs.glsl",
|
|
||||||
},
|
|
||||||
mcaaLine: {
|
|
||||||
fragment: "/glsl/gles2/xcaa-line.fs.glsl",
|
|
||||||
vertex: "/glsl/gles2/mcaa-line.vs.glsl",
|
|
||||||
},
|
|
||||||
mcaaMulti: {
|
|
||||||
fragment: "/glsl/gles2/mcaa-multi.fs.glsl",
|
|
||||||
vertex: "/glsl/gles2/mcaa-multi.vs.glsl",
|
|
||||||
},
|
},
|
||||||
ssaaSubpixelResolve: {
|
ssaaSubpixelResolve: {
|
||||||
fragment: "/glsl/gles2/ssaa-subpixel-resolve.fs.glsl",
|
fragment: "/glsl/gles2/ssaa-subpixel-resolve.fs.glsl",
|
||||||
|
|
|
@ -21,18 +21,18 @@ 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 {MCAAMulticolorStrategy, XCAAStrategy} from './xcaa-strategy';
|
import {MCAAStrategy, XCAAStrategy} from './xcaa-strategy';
|
||||||
|
|
||||||
interface AntialiasingStrategyTable {
|
interface AntialiasingStrategyTable {
|
||||||
none: typeof NoAAStrategy;
|
none: typeof NoAAStrategy;
|
||||||
ssaa: typeof SSAAStrategy;
|
ssaa: typeof SSAAStrategy;
|
||||||
xcaa: typeof XCAAStrategy;
|
xcaa: typeof MCAAStrategy;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ANTIALIASING_STRATEGIES: AntialiasingStrategyTable = {
|
const ANTIALIASING_STRATEGIES: AntialiasingStrategyTable = {
|
||||||
none: NoAAStrategy,
|
none: NoAAStrategy,
|
||||||
ssaa: SSAAStrategy,
|
ssaa: SSAAStrategy,
|
||||||
xcaa: MCAAMulticolorStrategy,
|
xcaa: MCAAStrategy,
|
||||||
};
|
};
|
||||||
|
|
||||||
export abstract class SVGRenderer extends Renderer {
|
export abstract class SVGRenderer extends Renderer {
|
||||||
|
@ -40,6 +40,11 @@ export abstract class SVGRenderer extends Renderer {
|
||||||
|
|
||||||
camera: OrthographicCamera;
|
camera: OrthographicCamera;
|
||||||
|
|
||||||
|
get isMulticolor(): boolean {
|
||||||
|
// FIXME(pcwalton): Only if the SVG is actually multicolor!
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
get bgColor(): glmatrix.vec4 {
|
get bgColor(): glmatrix.vec4 {
|
||||||
return glmatrix.vec4.clone([1.0, 1.0, 1.0, 1.0]);
|
return glmatrix.vec4.clone([1.0, 1.0, 1.0, 1.0]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,6 +64,10 @@ export abstract class TextRenderer extends Renderer {
|
||||||
atlasFramebuffer: WebGLFramebuffer;
|
atlasFramebuffer: WebGLFramebuffer;
|
||||||
atlasDepthTexture: WebGLTexture;
|
atlasDepthTexture: WebGLTexture;
|
||||||
|
|
||||||
|
get isMulticolor(): boolean {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
get usesSTTransform(): boolean {
|
get usesSTTransform(): boolean {
|
||||||
return this.camera.usesSTTransform;
|
return this.camera.usesSTTransform;
|
||||||
}
|
}
|
||||||
|
@ -146,8 +150,11 @@ export abstract class TextRenderer extends Renderer {
|
||||||
}
|
}
|
||||||
|
|
||||||
setHintsUniform(uniforms: UniformMap): void {
|
setHintsUniform(uniforms: UniformMap): void {
|
||||||
|
const renderContext = this.renderContext;
|
||||||
|
const gl = renderContext.gl;
|
||||||
|
|
||||||
const hint = this.createHint();
|
const hint = this.createHint();
|
||||||
this.renderContext.gl.uniform4f(uniforms.uHints,
|
gl.uniform4f(uniforms.uHints,
|
||||||
hint.xHeight,
|
hint.xHeight,
|
||||||
hint.hintedXHeight,
|
hint.hintedXHeight,
|
||||||
hint.stemHeight,
|
hint.stemHeight,
|
||||||
|
|
|
@ -41,9 +41,8 @@ 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 pathBoundsBufferTextures: PathfinderBufferTexture[];
|
||||||
|
|
||||||
protected supersampledFramebufferSize: glmatrix.vec2;
|
protected supersampledFramebufferSize: glmatrix.vec2;
|
||||||
protected destFramebufferSize: glmatrix.vec2;
|
protected destFramebufferSize: glmatrix.vec2;
|
||||||
|
@ -72,6 +71,7 @@ export abstract class XCAAStrategy extends AntialiasingStrategy {
|
||||||
attachMeshes(renderer: Renderer): void {
|
attachMeshes(renderer: Renderer): void {
|
||||||
const renderContext = renderer.renderContext;
|
const renderContext = renderer.renderContext;
|
||||||
this.createResolveVAO(renderer);
|
this.createResolveVAO(renderer);
|
||||||
|
this.pathBoundsBufferTextures = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
setFramebufferSize(renderer: Renderer): void {
|
setFramebufferSize(renderer: Renderer): void {
|
||||||
|
@ -97,7 +97,9 @@ export abstract class XCAAStrategy extends AntialiasingStrategy {
|
||||||
|
|
||||||
this.initResolveFramebufferForObject(renderer, objectIndex);
|
this.initResolveFramebufferForObject(renderer, objectIndex);
|
||||||
|
|
||||||
if (this.usesAAFramebuffer) {
|
if (!this.usesAAFramebuffer(renderer))
|
||||||
|
return;
|
||||||
|
|
||||||
const usedSize = this.supersampledUsedSize(renderer);
|
const usedSize = this.supersampledUsedSize(renderer);
|
||||||
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);
|
||||||
|
@ -108,7 +110,6 @@ export abstract class XCAAStrategy extends AntialiasingStrategy {
|
||||||
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 {}
|
prepareToRenderObject(renderer: Renderer, objectIndex: number): void {}
|
||||||
|
|
||||||
|
@ -118,7 +119,7 @@ export abstract class XCAAStrategy extends AntialiasingStrategy {
|
||||||
|
|
||||||
antialiasObject(renderer: Renderer, objectIndex: number): void {
|
antialiasObject(renderer: Renderer, objectIndex: number): void {
|
||||||
// Perform early preparations.
|
// Perform early preparations.
|
||||||
this.createPathBoundsBufferTextureForObject(renderer, objectIndex);
|
this.createPathBoundsBufferTextureForObjectIfNecessary(renderer, objectIndex);
|
||||||
|
|
||||||
// Set up antialiasing.
|
// Set up antialiasing.
|
||||||
this.prepareAA(renderer);
|
this.prepareAA(renderer);
|
||||||
|
@ -131,7 +132,7 @@ 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);
|
const resolveProgram = this.getResolveProgram(renderer);
|
||||||
if (resolveProgram == null)
|
if (resolveProgram == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -172,6 +173,8 @@ export abstract class XCAAStrategy extends AntialiasingStrategy {
|
||||||
return glmatrix.mat4.create();
|
return glmatrix.mat4.create();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected abstract usesAAFramebuffer(renderer: Renderer): boolean;
|
||||||
|
|
||||||
protected supersampledUsedSize(renderer: Renderer): glmatrix.vec2 {
|
protected supersampledUsedSize(renderer: Renderer): glmatrix.vec2 {
|
||||||
const usedSize = glmatrix.vec2.create();
|
const usedSize = glmatrix.vec2.create();
|
||||||
glmatrix.vec2.mul(usedSize, renderer.destUsedSize, this.supersampleScale);
|
glmatrix.vec2.mul(usedSize, renderer.destUsedSize, this.supersampleScale);
|
||||||
|
@ -223,7 +226,7 @@ export abstract class XCAAStrategy extends AntialiasingStrategy {
|
||||||
this.supersampledFramebufferSize[1]);
|
this.supersampledFramebufferSize[1]);
|
||||||
renderer.pathTransformBufferTextures[0].ext.bind(gl, uniforms, 0);
|
renderer.pathTransformBufferTextures[0].ext.bind(gl, uniforms, 0);
|
||||||
renderer.pathTransformBufferTextures[0].st.bind(gl, uniforms, 1);
|
renderer.pathTransformBufferTextures[0].st.bind(gl, uniforms, 1);
|
||||||
this.pathBoundsBufferTexture.bind(gl, uniforms, 2);
|
this.pathBoundsBufferTextures[objectIndex].bind(gl, uniforms, 2);
|
||||||
renderer.setHintsUniform(uniforms);
|
renderer.setHintsUniform(uniforms);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -239,8 +242,7 @@ 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):
|
protected abstract getResolveProgram(renderer: Renderer): PathfinderShaderProgram | null;
|
||||||
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;
|
||||||
|
|
||||||
|
@ -254,7 +256,7 @@ export abstract class XCAAStrategy extends AntialiasingStrategy {
|
||||||
}
|
}
|
||||||
|
|
||||||
private initAAAlphaFramebuffer(renderer: Renderer): void {
|
private initAAAlphaFramebuffer(renderer: Renderer): void {
|
||||||
if (!this.usesAAFramebuffer) {
|
if (!this.usesAAFramebuffer(renderer)) {
|
||||||
this.aaAlphaTexture = null;
|
this.aaAlphaTexture = null;
|
||||||
this.aaDepthTexture = null;
|
this.aaDepthTexture = null;
|
||||||
this.aaFramebuffer = null;
|
this.aaFramebuffer = null;
|
||||||
|
@ -282,20 +284,27 @@ export abstract class XCAAStrategy extends AntialiasingStrategy {
|
||||||
this.aaFramebuffer = createFramebuffer(gl, this.aaAlphaTexture, this.aaDepthTexture);
|
this.aaFramebuffer = createFramebuffer(gl, this.aaAlphaTexture, this.aaDepthTexture);
|
||||||
}
|
}
|
||||||
|
|
||||||
private createPathBoundsBufferTextureForObject(renderer: Renderer, objectIndex: number): void {
|
private createPathBoundsBufferTextureForObjectIfNecessary(renderer: Renderer,
|
||||||
|
objectIndex: number):
|
||||||
|
void {
|
||||||
const renderContext = renderer.renderContext;
|
const renderContext = renderer.renderContext;
|
||||||
const gl = renderContext.gl;
|
const gl = renderContext.gl;
|
||||||
|
|
||||||
const pathBounds = renderer.pathBoundingRects(objectIndex);
|
const pathBounds = renderer.pathBoundingRects(objectIndex);
|
||||||
this.pathBoundsBufferTexture = new PathfinderBufferTexture(gl, 'uPathBounds');
|
|
||||||
this.pathBoundsBufferTexture.upload(gl, pathBounds);
|
if (this.pathBoundsBufferTextures[objectIndex] == null) {
|
||||||
|
this.pathBoundsBufferTextures[objectIndex] =
|
||||||
|
new PathfinderBufferTexture(gl, 'uPathBounds');
|
||||||
|
}
|
||||||
|
|
||||||
|
this.pathBoundsBufferTextures[objectIndex].upload(gl, pathBounds);
|
||||||
}
|
}
|
||||||
|
|
||||||
private createResolveVAO(renderer: Renderer): void {
|
private createResolveVAO(renderer: Renderer): void {
|
||||||
const renderContext = renderer.renderContext;
|
const renderContext = renderer.renderContext;
|
||||||
const gl = renderContext.gl;
|
const gl = renderContext.gl;
|
||||||
|
|
||||||
const resolveProgram = this.getResolveProgram(renderContext);
|
const resolveProgram = this.getResolveProgram(renderer);
|
||||||
if (resolveProgram == null)
|
if (resolveProgram == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -317,11 +326,8 @@ export abstract class XCAAStrategy extends AntialiasingStrategy {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class MCAAMonochromeStrategy extends XCAAStrategy {
|
export class MCAAStrategy extends XCAAStrategy {
|
||||||
protected coverVAO: WebGLVertexArrayObject | null;
|
protected vao: WebGLVertexArrayObject | null;
|
||||||
|
|
||||||
protected lineVAOs: FastEdgeVAOs;
|
|
||||||
protected curveVAOs: FastEdgeVAOs;
|
|
||||||
|
|
||||||
protected get usesDilationTransforms(): boolean {
|
protected get usesDilationTransforms(): boolean {
|
||||||
return true;
|
return true;
|
||||||
|
@ -330,27 +336,25 @@ export class MCAAMonochromeStrategy extends XCAAStrategy {
|
||||||
attachMeshes(renderer: Renderer): void {
|
attachMeshes(renderer: Renderer): void {
|
||||||
super.attachMeshes(renderer);
|
super.attachMeshes(renderer);
|
||||||
|
|
||||||
this.createCoverVAOIfNecessary(renderer);
|
const renderContext = renderer.renderContext;
|
||||||
this.createLineVAOs(renderer);
|
this.vao = renderContext.vertexArrayObjectExt.createVertexArrayOES();
|
||||||
this.createCurveVAOs(renderer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
antialiasObject(renderer: Renderer, objectIndex: number): void {
|
antialiasObject(renderer: Renderer, objectIndex: number): void {
|
||||||
super.antialiasObject(renderer, objectIndex);
|
super.antialiasObject(renderer, objectIndex);
|
||||||
|
|
||||||
// Conservatively cover.
|
const shaderProgram = this.edgeProgram(renderer);
|
||||||
this.coverObjectIfNecessary(renderer, objectIndex);
|
this.antialiasEdgesOfObjectWithProgram(renderer, objectIndex, shaderProgram);
|
||||||
|
|
||||||
// Antialias.
|
|
||||||
this.antialiasLinesOfObject(renderer, objectIndex);
|
|
||||||
this.antialiasCurvesOfObject(renderer, objectIndex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected get usesAAFramebuffer(): boolean {
|
protected usesAAFramebuffer(renderer: Renderer): boolean {
|
||||||
return true;
|
return !renderer.isMulticolor;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected getResolveProgram(renderContext: RenderContext): PathfinderShaderProgram {
|
protected getResolveProgram(renderer: Renderer): PathfinderShaderProgram | null {
|
||||||
|
const renderContext = renderer.renderContext;
|
||||||
|
if (renderer.isMulticolor)
|
||||||
|
return null;
|
||||||
if (this.subpixelAA !== 'none')
|
if (this.subpixelAA !== 'none')
|
||||||
return renderContext.shaderPrograms.xcaaMonoSubpixelResolve;
|
return renderContext.shaderPrograms.xcaaMonoSubpixelResolve;
|
||||||
return renderContext.shaderPrograms.xcaaMonoResolve;
|
return renderContext.shaderPrograms.xcaaMonoResolve;
|
||||||
|
@ -360,97 +364,52 @@ export class MCAAMonochromeStrategy extends XCAAStrategy {
|
||||||
const renderContext = renderer.renderContext;
|
const renderContext = renderer.renderContext;
|
||||||
const gl = renderContext.gl;
|
const gl = renderContext.gl;
|
||||||
|
|
||||||
|
if (renderer.isMulticolor)
|
||||||
|
gl.clearColor(1.0, 1.0, 1.0, 1.0);
|
||||||
|
else
|
||||||
gl.clearColor(0.0, 0.0, 0.0, 0.0);
|
gl.clearColor(0.0, 0.0, 0.0, 0.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 {
|
||||||
const renderContext = renderer.renderContext;
|
const renderContext = renderer.renderContext;
|
||||||
const gl = renderContext.gl;
|
const gl = renderContext.gl;
|
||||||
|
|
||||||
|
if (!renderer.isMulticolor) {
|
||||||
gl.clearColor(1.0, 1.0, 1.0, 1.0);
|
gl.clearColor(1.0, 1.0, 1.0, 1.0);
|
||||||
gl.clear(gl.COLOR_BUFFER_BIT);
|
gl.clear(gl.COLOR_BUFFER_BIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected createCoverVAOIfNecessary(renderer: Renderer): void {
|
|
||||||
this.coverVAO = renderer.renderContext.vertexArrayObjectExt.createVertexArrayOES();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected setBlendModeForAA(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.blendEquation(gl.FUNC_ADD);
|
if (renderer.isMulticolor)
|
||||||
|
gl.blendFuncSeparate(gl.ONE, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE);
|
||||||
|
else
|
||||||
gl.blendFunc(gl.ONE, gl.ONE);
|
gl.blendFunc(gl.ONE, gl.ONE);
|
||||||
|
|
||||||
|
gl.blendEquation(gl.FUNC_ADD);
|
||||||
gl.enable(gl.BLEND);
|
gl.enable(gl.BLEND);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected prepareAA(renderer: Renderer): void {
|
protected prepareAA(renderer: Renderer): void {
|
||||||
super.prepareAA(renderer);
|
super.prepareAA(renderer);
|
||||||
|
|
||||||
this.setCoverDepthState(renderer);
|
|
||||||
|
|
||||||
const renderContext = renderer.renderContext;
|
|
||||||
const gl = renderContext.gl;
|
|
||||||
|
|
||||||
gl.blendEquation(gl.FUNC_ADD);
|
|
||||||
gl.blendFunc(gl.ONE, gl.ONE);
|
|
||||||
gl.enable(gl.BLEND);
|
|
||||||
|
|
||||||
this.clearForAA(renderer);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected setCoverDepthState(renderer: Renderer): void {
|
|
||||||
const renderContext = renderer.renderContext;
|
|
||||||
renderContext.gl.disable(renderContext.gl.DEPTH_TEST);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected antialiasLinesOfObjectWithProgram(renderer: Renderer,
|
|
||||||
objectIndex: number,
|
|
||||||
lineProgram: 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.initLineVAOsForObject(renderer, objectIndex);
|
|
||||||
|
|
||||||
gl.useProgram(lineProgram.program);
|
|
||||||
const uniforms = lineProgram.uniforms;
|
|
||||||
this.setAAUniforms(renderer, uniforms, objectIndex);
|
|
||||||
|
|
||||||
for (const direction of DIRECTIONS) {
|
|
||||||
const vao = this.lineVAOs[direction];
|
|
||||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(vao);
|
|
||||||
|
|
||||||
this.setBlendModeForAA(renderer);
|
this.setBlendModeForAA(renderer);
|
||||||
gl.uniform1i(uniforms.uWinding, direction === 'upper' ? 1 : 0);
|
|
||||||
|
|
||||||
const indexRanges = {
|
|
||||||
lower: renderer.meshData[meshIndex].edgeLowerLineIndexRanges,
|
|
||||||
upper: renderer.meshData[meshIndex].edgeUpperLineIndexRanges,
|
|
||||||
}[direction];
|
|
||||||
const count = calculateCountFromIndexRanges(pathRange, indexRanges);
|
|
||||||
|
|
||||||
renderContext.instancedArraysExt
|
|
||||||
.drawElementsInstancedANGLE(gl.TRIANGLES, 6, gl.UNSIGNED_BYTE, 0, count);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(null);
|
protected initVAOForObject(renderer: Renderer, objectIndex: number): void {
|
||||||
}
|
|
||||||
|
|
||||||
protected coverObjectIfNecessary(renderer: Renderer, objectIndex: number): void {
|
|
||||||
if (renderer.meshes == null || renderer.meshData == null)
|
if (renderer.meshes == null || renderer.meshData == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -460,278 +419,45 @@ export class MCAAMonochromeStrategy 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);
|
const shaderProgram = this.edgeProgram(renderer);
|
||||||
|
const attributes = shaderProgram.attributes;
|
||||||
|
|
||||||
// Conservatively cover.
|
// FIXME(pcwalton): Refactor.
|
||||||
const coverProgram = renderContext.shaderPrograms.mcaaCover;
|
const vao = this.vao;
|
||||||
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);
|
renderContext.vertexArrayObjectExt.bindVertexArrayOES(vao);
|
||||||
|
|
||||||
const curveVertexPositionsBuffer = {
|
|
||||||
lower: renderer.meshes[meshIndex].edgeLowerCurveVertexPositions,
|
|
||||||
upper: renderer.meshes[meshIndex].edgeUpperCurveVertexPositions,
|
|
||||||
}[direction];
|
|
||||||
const curvePathIDsBuffer = {
|
|
||||||
lower: renderer.meshes[meshIndex].edgeLowerCurvePathIDs,
|
|
||||||
upper: renderer.meshes[meshIndex].edgeUpperCurvePathIDs,
|
|
||||||
}[direction];
|
|
||||||
const curveIndexRanges = {
|
|
||||||
lower: renderer.meshData[meshIndex].edgeLowerCurveIndexRanges,
|
|
||||||
upper: renderer.meshData[meshIndex].edgeUpperCurveIndexRanges,
|
|
||||||
}[direction];
|
|
||||||
|
|
||||||
const offset = calculateStartFromIndexRanges(pathRange, curveIndexRanges);
|
|
||||||
|
|
||||||
gl.useProgram(curveProgram.program);
|
|
||||||
gl.bindBuffer(gl.ARRAY_BUFFER, renderContext.quadPositionsBuffer);
|
|
||||||
gl.vertexAttribPointer(attributes.aQuadPosition, 2, gl.FLOAT, false, 0, 0);
|
|
||||||
gl.bindBuffer(gl.ARRAY_BUFFER, curveVertexPositionsBuffer);
|
|
||||||
gl.vertexAttribPointer(attributes.aLeftPosition,
|
|
||||||
2,
|
|
||||||
gl.FLOAT,
|
|
||||||
false,
|
|
||||||
FLOAT32_SIZE * 6,
|
|
||||||
FLOAT32_SIZE * 6 * offset);
|
|
||||||
gl.vertexAttribPointer(attributes.aControlPointPosition,
|
|
||||||
2,
|
|
||||||
gl.FLOAT,
|
|
||||||
false,
|
|
||||||
FLOAT32_SIZE * 6,
|
|
||||||
FLOAT32_SIZE * 6 * offset + FLOAT32_SIZE * 2);
|
|
||||||
gl.vertexAttribPointer(attributes.aRightPosition,
|
|
||||||
2,
|
|
||||||
gl.FLOAT,
|
|
||||||
false,
|
|
||||||
FLOAT32_SIZE * 6,
|
|
||||||
FLOAT32_SIZE * 6 * offset + FLOAT32_SIZE * 4);
|
|
||||||
gl.bindBuffer(gl.ARRAY_BUFFER, curvePathIDsBuffer);
|
|
||||||
gl.vertexAttribPointer(attributes.aPathID,
|
|
||||||
1,
|
|
||||||
gl.UNSIGNED_SHORT,
|
|
||||||
false,
|
|
||||||
0,
|
|
||||||
UINT16_SIZE * offset);
|
|
||||||
|
|
||||||
gl.enableVertexAttribArray(attributes.aQuadPosition);
|
|
||||||
gl.enableVertexAttribArray(attributes.aLeftPosition);
|
|
||||||
gl.enableVertexAttribArray(attributes.aControlPointPosition);
|
|
||||||
gl.enableVertexAttribArray(attributes.aRightPosition);
|
|
||||||
gl.enableVertexAttribArray(attributes.aPathID);
|
|
||||||
|
|
||||||
renderContext.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aLeftPosition, 1);
|
|
||||||
renderContext.instancedArraysExt
|
|
||||||
.vertexAttribDivisorANGLE(attributes.aControlPointPosition, 1);
|
|
||||||
renderContext.instancedArraysExt
|
|
||||||
.vertexAttribDivisorANGLE(attributes.aRightPosition, 1);
|
|
||||||
renderContext.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aPathID, 1);
|
|
||||||
|
|
||||||
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, renderContext.quadElementsBuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected antialiasCurvesOfObjectWithProgram(renderer: Renderer,
|
|
||||||
objectIndex: number,
|
|
||||||
curveProgram: PathfinderShaderProgram):
|
|
||||||
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.initCurveVAOsForObject(renderer, objectIndex);
|
|
||||||
|
|
||||||
gl.useProgram(curveProgram.program);
|
|
||||||
const uniforms = curveProgram.uniforms;
|
|
||||||
this.setAAUniforms(renderer, uniforms, objectIndex);
|
|
||||||
|
|
||||||
for (const direction of DIRECTIONS) {
|
|
||||||
const vao = this.curveVAOs[direction];
|
|
||||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(vao);
|
|
||||||
|
|
||||||
this.setBlendModeForAA(renderer);
|
|
||||||
gl.uniform1i(uniforms.uWinding, direction === 'upper' ? 1 : 0);
|
|
||||||
|
|
||||||
const indexRanges = {
|
|
||||||
lower: renderer.meshData[meshIndex].edgeLowerCurveIndexRanges,
|
|
||||||
upper: renderer.meshData[meshIndex].edgeUpperCurveIndexRanges,
|
|
||||||
}[direction];
|
|
||||||
const count = calculateCountFromIndexRanges(pathRange, indexRanges);
|
|
||||||
|
|
||||||
renderContext.instancedArraysExt
|
|
||||||
.drawElementsInstancedANGLE(gl.TRIANGLES, 6, gl.UNSIGNED_BYTE, 0, count);
|
|
||||||
}
|
|
||||||
|
|
||||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected lineProgram(renderer: Renderer): PathfinderShaderProgram {
|
|
||||||
return renderer.renderContext.shaderPrograms.mcaaLine;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected curveProgram(renderer: Renderer): PathfinderShaderProgram {
|
|
||||||
return renderer.renderContext.shaderPrograms.mcaaCurve;
|
|
||||||
}
|
|
||||||
|
|
||||||
private createLineVAOs(renderer: Renderer): void {
|
|
||||||
const renderContext = renderer.renderContext;
|
|
||||||
|
|
||||||
const vaos: Partial<FastEdgeVAOs> = {};
|
|
||||||
for (const direction of DIRECTIONS)
|
|
||||||
vaos[direction] = renderContext.vertexArrayObjectExt.createVertexArrayOES();
|
|
||||||
this.lineVAOs = vaos as FastEdgeVAOs;
|
|
||||||
}
|
|
||||||
|
|
||||||
private initLineVAOsForObject(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 lineProgram = this.lineProgram(renderer);
|
|
||||||
const attributes = lineProgram.attributes;
|
|
||||||
|
|
||||||
for (const direction of DIRECTIONS) {
|
|
||||||
const vao = this.lineVAOs[direction];
|
|
||||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(vao);
|
|
||||||
|
|
||||||
const lineVertexPositionsBuffer = {
|
|
||||||
lower: renderer.meshes[meshIndex].edgeLowerLineVertexPositions,
|
|
||||||
upper: renderer.meshes[meshIndex].edgeUpperLineVertexPositions,
|
|
||||||
}[direction];
|
|
||||||
const linePathIDsBuffer = {
|
|
||||||
lower: renderer.meshes[meshIndex].edgeLowerLinePathIDs,
|
|
||||||
upper: renderer.meshes[meshIndex].edgeUpperLinePathIDs,
|
|
||||||
}[direction];
|
|
||||||
const lineIndexRanges = {
|
|
||||||
lower: renderer.meshData[meshIndex].edgeLowerLineIndexRanges,
|
|
||||||
upper: renderer.meshData[meshIndex].edgeUpperLineIndexRanges,
|
|
||||||
}[direction];
|
|
||||||
|
|
||||||
const offset = calculateStartFromIndexRanges(pathRange, lineIndexRanges);
|
|
||||||
|
|
||||||
gl.useProgram(lineProgram.program);
|
|
||||||
gl.bindBuffer(gl.ARRAY_BUFFER, renderContext.quadPositionsBuffer);
|
|
||||||
gl.vertexAttribPointer(attributes.aQuadPosition, 2, gl.FLOAT, false, 0, 0);
|
|
||||||
gl.bindBuffer(gl.ARRAY_BUFFER, lineVertexPositionsBuffer);
|
|
||||||
gl.vertexAttribPointer(attributes.aLeftPosition,
|
|
||||||
2,
|
|
||||||
gl.FLOAT,
|
|
||||||
false,
|
|
||||||
FLOAT32_SIZE * 4,
|
|
||||||
offset * FLOAT32_SIZE * 4);
|
|
||||||
gl.vertexAttribPointer(attributes.aRightPosition,
|
|
||||||
2,
|
|
||||||
gl.FLOAT,
|
|
||||||
false,
|
|
||||||
FLOAT32_SIZE * 4,
|
|
||||||
offset * FLOAT32_SIZE * 4 + FLOAT32_SIZE * 2);
|
|
||||||
gl.bindBuffer(gl.ARRAY_BUFFER, linePathIDsBuffer);
|
|
||||||
gl.vertexAttribPointer(attributes.aPathID,
|
|
||||||
1,
|
|
||||||
gl.UNSIGNED_SHORT,
|
|
||||||
false,
|
|
||||||
0,
|
|
||||||
offset * UINT16_SIZE);
|
|
||||||
|
|
||||||
gl.enableVertexAttribArray(attributes.aQuadPosition);
|
|
||||||
gl.enableVertexAttribArray(attributes.aLeftPosition);
|
|
||||||
gl.enableVertexAttribArray(attributes.aRightPosition);
|
|
||||||
gl.enableVertexAttribArray(attributes.aPathID);
|
|
||||||
|
|
||||||
renderContext.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aLeftPosition, 1);
|
|
||||||
renderContext.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aRightPosition,
|
|
||||||
1);
|
|
||||||
renderContext.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aPathID, 1);
|
|
||||||
|
|
||||||
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, renderContext.quadElementsBuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
private createCurveVAOs(renderer: Renderer): void {
|
|
||||||
const renderContext = renderer.renderContext;
|
|
||||||
const gl = renderContext.gl;
|
|
||||||
|
|
||||||
const vaos: Partial<FastEdgeVAOs> = {};
|
|
||||||
for (const direction of DIRECTIONS)
|
|
||||||
vaos[direction] = renderContext.vertexArrayObjectExt.createVertexArrayOES();
|
|
||||||
this.curveVAOs = vaos as FastEdgeVAOs;
|
|
||||||
}
|
|
||||||
|
|
||||||
get directRenderingMode(): DirectRenderingMode {
|
|
||||||
return 'none';
|
|
||||||
}
|
|
||||||
|
|
||||||
private initCoverVAOForObject(renderer: Renderer, objectIndex: number): void {
|
|
||||||
if (renderer.meshes == null || renderer.meshData == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
const renderContext = renderer.renderContext;
|
|
||||||
const gl = renderContext.gl;
|
|
||||||
|
|
||||||
const pathRange = renderer.pathRangeForObject(objectIndex);
|
|
||||||
const meshIndex = renderer.meshIndexForObject(objectIndex);
|
|
||||||
|
|
||||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(this.coverVAO);
|
|
||||||
|
|
||||||
const bQuadRanges = renderer.meshData[meshIndex].bQuadPathRanges;
|
const bQuadRanges = renderer.meshData[meshIndex].bQuadPathRanges;
|
||||||
const offset = calculateStartFromIndexRanges(pathRange, bQuadRanges);
|
const offset = calculateStartFromIndexRanges(pathRange, bQuadRanges);
|
||||||
|
|
||||||
const coverProgram = renderContext.shaderPrograms.mcaaCover;
|
gl.useProgram(shaderProgram.program);
|
||||||
const attributes = coverProgram.attributes;
|
|
||||||
gl.useProgram(coverProgram.program);
|
|
||||||
gl.bindBuffer(gl.ARRAY_BUFFER, renderContext.quadPositionsBuffer);
|
gl.bindBuffer(gl.ARRAY_BUFFER, renderContext.quadPositionsBuffer);
|
||||||
gl.vertexAttribPointer(attributes.aQuadPosition, 2, gl.FLOAT, false, 0, 0);
|
gl.vertexAttribPointer(attributes.aQuadPosition, 2, gl.FLOAT, false, 0, 0);
|
||||||
gl.bindBuffer(gl.ARRAY_BUFFER, renderer.meshes[meshIndex].edgeBoundingBoxVertexPositions);
|
gl.bindBuffer(gl.ARRAY_BUFFER, renderer.meshes[meshIndex].bQuadVertexPositions);
|
||||||
gl.vertexAttribPointer(attributes.aUpperLeftPosition,
|
gl.vertexAttribPointer(attributes.aUpperEndpointPositions,
|
||||||
2,
|
4,
|
||||||
gl.FLOAT,
|
gl.FLOAT,
|
||||||
false,
|
false,
|
||||||
FLOAT32_SIZE * 4,
|
FLOAT32_SIZE * 12,
|
||||||
FLOAT32_SIZE * 4 * offset);
|
FLOAT32_SIZE * 12 * offset);
|
||||||
gl.vertexAttribPointer(attributes.aLowerRightPosition,
|
gl.vertexAttribPointer(attributes.aLowerEndpointPositions,
|
||||||
2,
|
4,
|
||||||
gl.FLOAT,
|
gl.FLOAT,
|
||||||
false,
|
false,
|
||||||
FLOAT32_SIZE * 4,
|
FLOAT32_SIZE * 12,
|
||||||
FLOAT32_SIZE * 4 * offset + FLOAT32_SIZE * 2);
|
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);
|
||||||
|
renderContext.instancedArraysExt
|
||||||
|
.vertexAttribDivisorANGLE(attributes.aUpperEndpointPositions, 1);
|
||||||
|
renderContext.instancedArraysExt
|
||||||
|
.vertexAttribDivisorANGLE(attributes.aLowerEndpointPositions, 1);
|
||||||
|
renderContext.instancedArraysExt
|
||||||
|
.vertexAttribDivisorANGLE(attributes.aControlPointPositions, 1);
|
||||||
|
|
||||||
gl.bindBuffer(gl.ARRAY_BUFFER, renderer.meshes[meshIndex].edgeBoundingBoxPathIDs);
|
gl.bindBuffer(gl.ARRAY_BUFFER, renderer.meshes[meshIndex].edgeBoundingBoxPathIDs);
|
||||||
gl.vertexAttribPointer(attributes.aPathID,
|
gl.vertexAttribPointer(attributes.aPathID,
|
||||||
1,
|
1,
|
||||||
|
@ -739,49 +465,89 @@ export class MCAAMonochromeStrategy extends XCAAStrategy {
|
||||||
false,
|
false,
|
||||||
0,
|
0,
|
||||||
UINT16_SIZE * offset);
|
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);
|
renderContext.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aPathID, 1);
|
||||||
|
|
||||||
|
gl.enableVertexAttribArray(attributes.aQuadPosition);
|
||||||
|
gl.enableVertexAttribArray(attributes.aUpperEndpointPositions);
|
||||||
|
gl.enableVertexAttribArray(attributes.aLowerEndpointPositions);
|
||||||
|
gl.enableVertexAttribArray(attributes.aControlPointPositions);
|
||||||
|
gl.enableVertexAttribArray(attributes.aPathID);
|
||||||
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, renderContext.quadElementsBuffer);
|
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, renderContext.quadElementsBuffer);
|
||||||
|
|
||||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(null);
|
renderContext.vertexArrayObjectExt.bindVertexArrayOES(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private antialiasLinesOfObject(renderer: Renderer, objectIndex: number): void {
|
protected edgeProgram(renderer: Renderer): PathfinderShaderProgram {
|
||||||
const renderContext = renderer.renderContext;
|
return renderer.renderContext.shaderPrograms.mcaa;
|
||||||
this.setAAState(renderer);
|
|
||||||
|
|
||||||
const lineProgram = this.lineProgram(renderer);
|
|
||||||
renderContext.gl.useProgram(lineProgram.program);
|
|
||||||
|
|
||||||
// FIXME(pcwalton): Refactor.
|
|
||||||
this.antialiasLinesOfObjectWithProgram(renderer, objectIndex, lineProgram);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private antialiasCurvesOfObject(renderer: Renderer, objectIndex: number): void {
|
protected antialiasEdgesOfObjectWithProgram(renderer: Renderer,
|
||||||
|
objectIndex: number,
|
||||||
|
shaderProgram: PathfinderShaderProgram):
|
||||||
|
void {
|
||||||
|
if (renderer.meshData == null)
|
||||||
|
return;
|
||||||
|
|
||||||
const renderContext = renderer.renderContext;
|
const renderContext = renderer.renderContext;
|
||||||
this.setAAState(renderer);
|
const gl = renderContext.gl;
|
||||||
|
|
||||||
const curveProgram = this.curveProgram(renderer);
|
const pathRange = renderer.pathRangeForObject(objectIndex);
|
||||||
renderContext.gl.useProgram(curveProgram.program);
|
const meshIndex = renderer.meshIndexForObject(objectIndex);
|
||||||
|
|
||||||
this.antialiasCurvesOfObjectWithProgram(renderer, objectIndex, curveProgram);
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
get directRenderingMode(): DirectRenderingMode {
|
||||||
|
return 'none';
|
||||||
|
}
|
||||||
|
|
||||||
|
protected setAAUniforms(renderer: Renderer, uniforms: UniformMap, objectIndex: number):
|
||||||
|
void {
|
||||||
|
super.setAAUniforms(renderer, uniforms, objectIndex);
|
||||||
|
|
||||||
|
const renderContext = renderer.renderContext;
|
||||||
|
const gl = renderContext.gl;
|
||||||
|
|
||||||
|
renderer.setPathColorsUniform(0, uniforms, 3);
|
||||||
|
|
||||||
|
gl.uniform1i(uniforms.uSnapToPixelGrid, renderer.isMulticolor ? 1 : 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export abstract class ECAAStrategy extends XCAAStrategy {
|
export class ECAAStrategy extends XCAAStrategy {
|
||||||
protected abstract get lineShaderProgramNames(): Array<keyof ShaderMap<void>>;
|
protected get lineShaderProgramNames(): Array<keyof ShaderMap<void>> {
|
||||||
protected abstract get curveShaderProgramNames(): Array<keyof ShaderMap<void>>;
|
return ['ecaaLine'];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected get curveShaderProgramNames(): Array<keyof ShaderMap<void>> {
|
||||||
|
return ['ecaaCurve', 'ecaaTransformedCurve'];
|
||||||
|
}
|
||||||
|
|
||||||
private lineVAOs: Partial<ShaderMap<WebGLVertexArrayObject>>;
|
private lineVAOs: Partial<ShaderMap<WebGLVertexArrayObject>>;
|
||||||
private curveVAOs: Partial<ShaderMap<WebGLVertexArrayObject>>;
|
private curveVAOs: Partial<ShaderMap<WebGLVertexArrayObject>>;
|
||||||
|
|
||||||
|
protected get usesDilationTransforms(): boolean {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
get directRenderingMode(): DirectRenderingMode {
|
get directRenderingMode(): DirectRenderingMode {
|
||||||
return 'none';
|
return 'none';
|
||||||
}
|
}
|
||||||
|
@ -809,13 +575,19 @@ export abstract class ECAAStrategy extends XCAAStrategy {
|
||||||
this.curveShaderProgramNames[1]);
|
this.curveShaderProgramNames[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected usesAAFramebuffer(): boolean {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
protected setAAUniforms(renderer: Renderer, uniforms: UniformMap, objectIndex: number):
|
protected setAAUniforms(renderer: Renderer, uniforms: UniformMap, objectIndex: number):
|
||||||
void {
|
void {
|
||||||
super.setAAUniforms(renderer, uniforms, objectIndex);
|
super.setAAUniforms(renderer, uniforms, objectIndex);
|
||||||
renderer.setEmboldenAmountUniform(objectIndex, uniforms);
|
renderer.setEmboldenAmountUniform(objectIndex, uniforms);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected getResolveProgram(renderContext: RenderContext): PathfinderShaderProgram {
|
protected getResolveProgram(renderer: Renderer): PathfinderShaderProgram {
|
||||||
|
const renderContext = renderer.renderContext;
|
||||||
|
|
||||||
if (this.subpixelAA !== 'none')
|
if (this.subpixelAA !== 'none')
|
||||||
return renderContext.shaderPrograms.xcaaMonoSubpixelResolve;
|
return renderContext.shaderPrograms.xcaaMonoSubpixelResolve;
|
||||||
return renderContext.shaderPrograms.xcaaMonoResolve;
|
return renderContext.shaderPrograms.xcaaMonoResolve;
|
||||||
|
@ -1089,212 +861,11 @@ export abstract class ECAAStrategy extends XCAAStrategy {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ECAAMonochromeStrategy extends ECAAStrategy {
|
|
||||||
protected get usesDilationTransforms(): boolean {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected get usesAAFramebuffer(): boolean {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected get lineShaderProgramNames(): Array<keyof ShaderMap<void>> {
|
|
||||||
return ['ecaaLine'];
|
|
||||||
}
|
|
||||||
|
|
||||||
protected get curveShaderProgramNames(): Array<keyof ShaderMap<void>> {
|
|
||||||
return ['ecaaCurve', 'ecaaTransformedCurve'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class MCAAMulticolorStrategy extends XCAAStrategy {
|
|
||||||
protected vao: WebGLVertexArrayObject;
|
|
||||||
|
|
||||||
protected get usesDilationTransforms(): boolean {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
attachMeshes(renderer: Renderer): void {
|
|
||||||
super.attachMeshes(renderer);
|
|
||||||
|
|
||||||
const renderContext = renderer.renderContext;
|
|
||||||
this.vao = renderContext.vertexArrayObjectExt.createVertexArrayOES();
|
|
||||||
}
|
|
||||||
|
|
||||||
antialiasObject(renderer: Renderer, objectIndex: number): void {
|
|
||||||
super.antialiasObject(renderer, objectIndex);
|
|
||||||
|
|
||||||
const shaderProgram = this.edgeProgram(renderer);
|
|
||||||
this.antialiasEdgesOfObjectWithProgram(renderer, objectIndex, shaderProgram);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected get usesAAFramebuffer(): boolean {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected getResolveProgram(renderContext: RenderContext): PathfinderShaderProgram | null {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected prepareAA(renderer: Renderer): void {
|
|
||||||
super.prepareAA(renderer);
|
|
||||||
|
|
||||||
this.clearForAA(renderer);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected coverObjectIfNecessary(renderer: Renderer, objectIndex: number): void {}
|
|
||||||
|
|
||||||
protected antialiasEdgesOfObjectWithProgram(renderer: Renderer,
|
|
||||||
objectIndex: number,
|
|
||||||
shaderProgram: PathfinderShaderProgram):
|
|
||||||
void {
|
|
||||||
if (renderer.meshData == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
const renderContext = renderer.renderContext;
|
|
||||||
const gl = renderContext.gl;
|
|
||||||
|
|
||||||
const pathRange = renderer.pathRangeForObject(objectIndex);
|
|
||||||
const meshIndex = renderer.meshIndexForObject(objectIndex);
|
|
||||||
|
|
||||||
this.initVAOForObject(renderer, objectIndex);
|
|
||||||
|
|
||||||
gl.useProgram(shaderProgram.program);
|
|
||||||
const uniforms = shaderProgram.uniforms;
|
|
||||||
this.setAAUniforms(renderer, uniforms, objectIndex);
|
|
||||||
|
|
||||||
// FIXME(pcwalton): Refactor.
|
|
||||||
const vao = this.vao;
|
|
||||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(vao);
|
|
||||||
|
|
||||||
this.setBlendModeForAA(renderer);
|
|
||||||
|
|
||||||
const bQuadRanges = renderer.meshData[meshIndex].bQuadPathRanges;
|
|
||||||
const count = calculateCountFromIndexRanges(pathRange, bQuadRanges);
|
|
||||||
|
|
||||||
renderContext.instancedArraysExt
|
|
||||||
.drawElementsInstancedANGLE(gl.TRIANGLES, 6, gl.UNSIGNED_BYTE, 0, count);
|
|
||||||
|
|
||||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected clearForAA(renderer: Renderer): void {
|
|
||||||
const renderContext = renderer.renderContext;
|
|
||||||
const gl = renderContext.gl;
|
|
||||||
|
|
||||||
gl.clearColor(1.0, 1.0, 1.0, 1.0);
|
|
||||||
gl.clearDepth(0.0);
|
|
||||||
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected setAADepthState(renderer: Renderer): void {
|
|
||||||
const renderContext = renderer.renderContext;
|
|
||||||
const gl = renderContext.gl;
|
|
||||||
|
|
||||||
gl.disable(gl.DEPTH_TEST);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected clearForResolve(renderer: Renderer): void {}
|
|
||||||
|
|
||||||
protected setBlendModeForAA(renderer: Renderer): void {
|
|
||||||
const renderContext = renderer.renderContext;
|
|
||||||
const gl = renderContext.gl;
|
|
||||||
|
|
||||||
gl.blendEquation(gl.FUNC_ADD);
|
|
||||||
gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE);
|
|
||||||
gl.enable(gl.BLEND);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected setAAUniforms(renderer: Renderer, uniforms: UniformMap, objectIndex: number):
|
|
||||||
void {
|
|
||||||
super.setAAUniforms(renderer, uniforms, objectIndex);
|
|
||||||
renderer.setPathColorsUniform(0, uniforms, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected initVAOForObject(renderer: Renderer, objectIndex: number): void {
|
|
||||||
if (renderer.meshes == null || renderer.meshData == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
const renderContext = renderer.renderContext;
|
|
||||||
const gl = renderContext.gl;
|
|
||||||
|
|
||||||
const pathRange = renderer.pathRangeForObject(objectIndex);
|
|
||||||
const meshIndex = renderer.meshIndexForObject(objectIndex);
|
|
||||||
|
|
||||||
const shaderProgram = this.edgeProgram(renderer);
|
|
||||||
const attributes = shaderProgram.attributes;
|
|
||||||
|
|
||||||
// FIXME(pcwalton): Refactor.
|
|
||||||
const vao = this.vao;
|
|
||||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(vao);
|
|
||||||
|
|
||||||
const bQuadRanges = renderer.meshData[meshIndex].bQuadPathRanges;
|
|
||||||
const offset = calculateStartFromIndexRanges(pathRange, bQuadRanges);
|
|
||||||
|
|
||||||
gl.useProgram(shaderProgram.program);
|
|
||||||
gl.bindBuffer(gl.ARRAY_BUFFER, renderContext.quadPositionsBuffer);
|
|
||||||
gl.vertexAttribPointer(attributes.aQuadPosition, 2, gl.FLOAT, false, 0, 0);
|
|
||||||
gl.bindBuffer(gl.ARRAY_BUFFER, renderer.meshes[meshIndex].bQuadVertexPositions);
|
|
||||||
gl.vertexAttribPointer(attributes.aUpperEndpointPositions,
|
|
||||||
4,
|
|
||||||
gl.FLOAT,
|
|
||||||
false,
|
|
||||||
FLOAT32_SIZE * 12,
|
|
||||||
FLOAT32_SIZE * 12 * offset);
|
|
||||||
gl.vertexAttribPointer(attributes.aLowerEndpointPositions,
|
|
||||||
4,
|
|
||||||
gl.FLOAT,
|
|
||||||
false,
|
|
||||||
FLOAT32_SIZE * 12,
|
|
||||||
FLOAT32_SIZE * 12 * offset + FLOAT32_SIZE * 4);
|
|
||||||
gl.vertexAttribPointer(attributes.aControlPointPositions,
|
|
||||||
4,
|
|
||||||
gl.FLOAT,
|
|
||||||
false,
|
|
||||||
FLOAT32_SIZE * 12,
|
|
||||||
FLOAT32_SIZE * 12 * offset + FLOAT32_SIZE * 8);
|
|
||||||
gl.bindBuffer(gl.ARRAY_BUFFER, renderer.meshes[meshIndex].edgeBoundingBoxPathIDs);
|
|
||||||
gl.vertexAttribPointer(attributes.aPathID,
|
|
||||||
1,
|
|
||||||
gl.UNSIGNED_SHORT,
|
|
||||||
false,
|
|
||||||
0,
|
|
||||||
UINT16_SIZE * offset);
|
|
||||||
gl.enableVertexAttribArray(attributes.aQuadPosition);
|
|
||||||
gl.enableVertexAttribArray(attributes.aUpperEndpointPositions);
|
|
||||||
gl.enableVertexAttribArray(attributes.aLowerEndpointPositions);
|
|
||||||
gl.enableVertexAttribArray(attributes.aControlPointPositions);
|
|
||||||
gl.enableVertexAttribArray(attributes.aPathID);
|
|
||||||
renderContext.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aPathID, 1);
|
|
||||||
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, renderContext.quadElementsBuffer);
|
|
||||||
|
|
||||||
renderContext.instancedArraysExt
|
|
||||||
.vertexAttribDivisorANGLE(attributes.aUpperEndpointPositions, 1);
|
|
||||||
renderContext.instancedArraysExt
|
|
||||||
.vertexAttribDivisorANGLE(attributes.aLowerEndpointPositions, 1);
|
|
||||||
renderContext.instancedArraysExt
|
|
||||||
.vertexAttribDivisorANGLE(attributes.aControlPointPositions, 1);
|
|
||||||
renderContext.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aPathID, 1);
|
|
||||||
|
|
||||||
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, renderContext.quadElementsBuffer);
|
|
||||||
|
|
||||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected edgeProgram(renderer: Renderer): PathfinderShaderProgram {
|
|
||||||
return renderer.renderContext.shaderPrograms.mcaaMulti;
|
|
||||||
}
|
|
||||||
|
|
||||||
get directRenderingMode(): DirectRenderingMode {
|
|
||||||
return 'none';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Switches between the mesh-based MCAA and ECAA depending on whether stem darkening is enabled.
|
/// Switches between the mesh-based MCAA and ECAA depending on whether stem darkening is enabled.
|
||||||
///
|
///
|
||||||
/// FIXME(pcwalton): Share textures and FBOs between the two strategies.
|
/// FIXME(pcwalton): Share textures and FBOs between the two strategies.
|
||||||
export class AdaptiveMonochromeXCAAStrategy implements AntialiasingStrategy {
|
export class AdaptiveMonochromeXCAAStrategy implements AntialiasingStrategy {
|
||||||
private mcaaStrategy: MCAAMonochromeStrategy;
|
private mcaaStrategy: MCAAStrategy;
|
||||||
private ecaaStrategy: ECAAStrategy;
|
private ecaaStrategy: ECAAStrategy;
|
||||||
|
|
||||||
get directRenderingMode(): DirectRenderingMode {
|
get directRenderingMode(): DirectRenderingMode {
|
||||||
|
@ -1306,8 +877,8 @@ export class AdaptiveMonochromeXCAAStrategy implements AntialiasingStrategy {
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(level: number, subpixelAA: SubpixelAAType) {
|
constructor(level: number, subpixelAA: SubpixelAAType) {
|
||||||
this.mcaaStrategy = new MCAAMonochromeStrategy(level, subpixelAA);
|
this.mcaaStrategy = new MCAAStrategy(level, subpixelAA);
|
||||||
this.ecaaStrategy = new ECAAMonochromeStrategy(level, subpixelAA);
|
this.ecaaStrategy = new ECAAStrategy(level, subpixelAA);
|
||||||
}
|
}
|
||||||
|
|
||||||
init(renderer: Renderer): void {
|
init(renderer: Renderer): void {
|
||||||
|
|
|
@ -87,6 +87,13 @@ impl BQuad {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, PartialEq, Debug, Serialize, Deserialize)]
|
||||||
|
pub struct BQuadVertexPositions {
|
||||||
|
pub upper_endpoint_positions: [Point2D<f32>; 2],
|
||||||
|
pub lower_endpoint_positions: [Point2D<f32>; 2],
|
||||||
|
pub control_point_positions: [Point2D<f32>; 2],
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Debug)]
|
#[derive(Clone, Copy, PartialEq, Debug)]
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
pub enum AntialiasingMode {
|
pub enum AntialiasingMode {
|
||||||
|
|
|
@ -18,14 +18,14 @@ use std::ops::Range;
|
||||||
use std::u32;
|
use std::u32;
|
||||||
|
|
||||||
use normal;
|
use normal;
|
||||||
use {BQuad, BVertexLoopBlinnData};
|
use {BQuad, BQuadVertexPositions, BVertexLoopBlinnData};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
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.
|
// FIXME(pcwalton): Merge with `b_vertex_positions` below.
|
||||||
pub b_quad_vertex_positions: Vec<Point2D<f32>>,
|
pub b_quad_vertex_positions: Vec<BQuadVertexPositions>,
|
||||||
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>,
|
||||||
|
@ -94,12 +94,11 @@ 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(&[
|
let mut b_quad_vertex_positions = BQuadVertexPositions {
|
||||||
*upper_left_position,
|
upper_endpoint_positions: [*upper_left_position, *upper_right_position],
|
||||||
*upper_right_position,
|
lower_endpoint_positions: [*lower_left_position, *lower_right_position],
|
||||||
*lower_left_position,
|
control_point_positions: [Point2D::zero(), Point2D::zero()],
|
||||||
*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,
|
||||||
|
@ -114,7 +113,6 @@ 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,
|
||||||
|
@ -122,7 +120,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);
|
b_quad_vertex_positions.control_point_positions[0] = *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,
|
||||||
|
@ -131,7 +129,6 @@ 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,
|
||||||
|
@ -139,13 +136,15 @@ 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);
|
b_quad_vertex_positions.control_point_positions[1] = *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,
|
||||||
right: *lower_right_position,
|
right: *lower_right_position,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.b_quad_vertex_positions.push(b_quad_vertex_positions);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reverses interior indices so that they draw front-to-back.
|
/// Reverses interior indices so that they draw front-to-back.
|
||||||
|
|
|
@ -145,17 +145,23 @@ vec2 computeMCAASnappedPosition(vec2 position,
|
||||||
vec4 localTransformST,
|
vec4 localTransformST,
|
||||||
vec4 globalTransformST,
|
vec4 globalTransformST,
|
||||||
ivec2 framebufferSize,
|
ivec2 framebufferSize,
|
||||||
float slope) {
|
float slope,
|
||||||
|
bool snapToPixelGrid) {
|
||||||
position = hintPosition(position, hints);
|
position = hintPosition(position, hints);
|
||||||
position = transformVertexPositionST(position, localTransformST);
|
position = transformVertexPositionST(position, localTransformST);
|
||||||
position = transformVertexPositionST(position, globalTransformST);
|
position = transformVertexPositionST(position, globalTransformST);
|
||||||
position = convertClipToScreenSpace(position, framebufferSize);
|
position = convertClipToScreenSpace(position, framebufferSize);
|
||||||
|
|
||||||
float xNudge = fract(position.x);
|
float xNudge;
|
||||||
|
if (snapToPixelGrid) {
|
||||||
|
xNudge = fract(position.x);
|
||||||
if (xNudge < 0.5)
|
if (xNudge < 0.5)
|
||||||
xNudge = -xNudge;
|
xNudge = -xNudge;
|
||||||
else
|
else
|
||||||
xNudge = 1.0 - xNudge;
|
xNudge = 1.0 - xNudge;
|
||||||
|
} else {
|
||||||
|
xNudge = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
return position + vec2(xNudge, xNudge * slope);
|
return position + vec2(xNudge, xNudge * slope);
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,5 +28,5 @@ varying float vSign;
|
||||||
void main() {
|
void main() {
|
||||||
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(vColor.rgb, vColor.a * alpha);
|
gl_FragColor = alpha * vColor;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// pathfinder/shaders/gles2/xcaa-curve.fs.glsl
|
// pathfinder/shaders/gles2/ecaa-curve.fs.glsl
|
||||||
//
|
//
|
||||||
// Copyright (c) 2017 The Pathfinder Project Developers.
|
// Copyright (c) 2017 The Pathfinder Project Developers.
|
||||||
//
|
//
|
|
@ -16,10 +16,10 @@
|
||||||
//! Use this shader only when *all* of the following are true:
|
//! Use this shader only when *all* of the following are true:
|
||||||
//!
|
//!
|
||||||
//! 1. You are only rendering monochrome paths such as text. (Otherwise,
|
//! 1. You are only rendering monochrome paths such as text. (Otherwise,
|
||||||
//! consider `mcaa-multi`.)
|
//! consider MCAA.)
|
||||||
//!
|
//!
|
||||||
//! 2. The paths are relatively small, so overdraw is not a concern.
|
//! 2. The paths are relatively small, so overdraw is not a concern.
|
||||||
//! (Otherwise, consider the MCAA shaders.)
|
//! (Otherwise, consider MCAA.)
|
||||||
//!
|
//!
|
||||||
//! 3. Your transform is only a scale and/or translation, not a perspective,
|
//! 3. Your transform is only a scale and/or translation, not a perspective,
|
||||||
//! rotation, or skew. (Otherwise, consider `ecaa-transformed-curve`.)
|
//! rotation, or skew. (Otherwise, consider `ecaa-transformed-curve`.)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// pathfinder/shaders/gles2/xcaa-line.fs.glsl
|
// pathfinder/shaders/gles2/ecaa-line.fs.glsl
|
||||||
//
|
//
|
||||||
// Copyright (c) 2017 The Pathfinder Project Developers.
|
// Copyright (c) 2017 The Pathfinder Project Developers.
|
||||||
//
|
//
|
|
@ -17,10 +17,10 @@
|
||||||
//! Use this shader only when *both* of the following are true:
|
//! Use this shader only when *both* of the following are true:
|
||||||
//!
|
//!
|
||||||
//! 1. You are only rendering monochrome paths such as text. (Otherwise,
|
//! 1. You are only rendering monochrome paths such as text. (Otherwise,
|
||||||
//! consider `mcaa-multi`.)
|
//! consider MCAA.)
|
||||||
//!
|
//!
|
||||||
//! 2. The paths are relatively small, so overdraw is not a concern.
|
//! 2. The paths are relatively small, so overdraw is not a concern.
|
||||||
//! (Otherwise, consider the MCAA shaders.)
|
//! (Otherwise, consider MCAA.)
|
||||||
|
|
||||||
precision highp float;
|
precision highp float;
|
||||||
|
|
||||||
|
|
|
@ -20,10 +20,10 @@
|
||||||
//! Use this shader only when *all* of the following are true:
|
//! Use this shader only when *all* of the following are true:
|
||||||
//!
|
//!
|
||||||
//! 1. You are only rendering monochrome paths such as text. (Otherwise,
|
//! 1. You are only rendering monochrome paths such as text. (Otherwise,
|
||||||
//! consider `mcaa-multi`.)
|
//! consider MCAA.)
|
||||||
//!
|
//!
|
||||||
//! 2. The paths are relatively small, so overdraw is not a concern.
|
//! 2. The paths are relatively small, so overdraw is not a concern.
|
||||||
//! (Otherwise, consider the MCAA shaders.)
|
//! (Otherwise, consider MCAA.)
|
||||||
//!
|
//!
|
||||||
//! 3. Your transform contains perspective, rotation, or skew. (Otherwise,
|
//! 3. Your transform contains perspective, rotation, or skew. (Otherwise,
|
||||||
//! consider `ecaa-curve`, which is faster and saves a pass.)
|
//! consider `ecaa-curve`, which is faster and saves a pass.)
|
||||||
|
|
|
@ -1,33 +0,0 @@
|
||||||
// pathfinder/shaders/gles2/mcaa-cover.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.
|
|
||||||
|
|
||||||
//! Performs the conservative coverage step for *mesh coverage antialiasing*
|
|
||||||
//! (MCAA).
|
|
||||||
//!
|
|
||||||
//! This shader expects to render to the red channel of a floating point color
|
|
||||||
//! buffer. Half precision floating point should be sufficient.
|
|
||||||
//!
|
|
||||||
//! Use this shader only when *both* of the following are true:
|
|
||||||
//!
|
|
||||||
//! 1. You are only rendering monochrome paths such as text. (Otherwise,
|
|
||||||
//! consider `mcaa-multi`.)
|
|
||||||
//!
|
|
||||||
//! 2. Your transform is only a scale and/or translation, not a perspective,
|
|
||||||
//! rotation, or skew. (Otherwise, consider the ECAA shaders.)
|
|
||||||
|
|
||||||
precision highp float;
|
|
||||||
|
|
||||||
varying vec2 vHorizontalExtents;
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
vec2 sides = gl_FragCoord.xx + vec2(-0.5, 0.5);
|
|
||||||
vec2 clampedSides = clamp(vHorizontalExtents, sides.x, sides.y);
|
|
||||||
gl_FragColor = vec4(vec3(clampedSides.y - clampedSides.x), 1.0);
|
|
||||||
}
|
|
|
@ -1,63 +0,0 @@
|
||||||
// pathfinder/shaders/gles2/mcaa-cover.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.
|
|
||||||
|
|
||||||
//! Performs the conservative coverage step for *mesh coverage antialiasing*
|
|
||||||
//! (MCAA).
|
|
||||||
//!
|
|
||||||
//! This shader expects to render to the red channel of a floating point color
|
|
||||||
//! buffer. Half precision floating point should be sufficient.
|
|
||||||
//!
|
|
||||||
//! Use this shader only when *both* of the following are true:
|
|
||||||
//!
|
|
||||||
//! 1. You are only rendering monochrome paths such as text. (Otherwise,
|
|
||||||
//! consider `mcaa-multi`.)
|
|
||||||
//!
|
|
||||||
//! 2. Your transform is only a scale and/or translation, not a perspective,
|
|
||||||
//! rotation, or skew. (Otherwise, consider the ECAA shaders.)
|
|
||||||
|
|
||||||
precision highp float;
|
|
||||||
|
|
||||||
uniform vec4 uTransformST;
|
|
||||||
uniform vec4 uHints;
|
|
||||||
uniform ivec2 uFramebufferSize;
|
|
||||||
uniform ivec2 uPathTransformSTDimensions;
|
|
||||||
uniform sampler2D uPathTransformST;
|
|
||||||
|
|
||||||
attribute vec2 aQuadPosition;
|
|
||||||
attribute vec2 aUpperLeftPosition;
|
|
||||||
attribute vec2 aLowerRightPosition;
|
|
||||||
attribute float aPathID;
|
|
||||||
|
|
||||||
varying vec2 vHorizontalExtents;
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
int pathID = int(aPathID);
|
|
||||||
|
|
||||||
vec4 transformST = fetchFloat4Data(uPathTransformST, pathID, uPathTransformSTDimensions);
|
|
||||||
|
|
||||||
vec2 upperLeftPosition = computeMCAAPosition(aUpperLeftPosition,
|
|
||||||
uHints,
|
|
||||||
transformST,
|
|
||||||
uTransformST,
|
|
||||||
uFramebufferSize);
|
|
||||||
vec2 lowerRightPosition = computeMCAAPosition(aLowerRightPosition,
|
|
||||||
uHints,
|
|
||||||
transformST,
|
|
||||||
uTransformST,
|
|
||||||
uFramebufferSize);
|
|
||||||
|
|
||||||
vHorizontalExtents = vec2(upperLeftPosition.x, lowerRightPosition.x);
|
|
||||||
|
|
||||||
vec4 extents = vec4(upperLeftPosition.x, ceil(upperLeftPosition.y), lowerRightPosition);
|
|
||||||
vec2 position = computeXCAAClipSpaceQuadPosition(extents, aQuadPosition, uFramebufferSize);
|
|
||||||
float depth = convertPathIndexToViewportDepthValue(pathID);
|
|
||||||
|
|
||||||
gl_Position = vec4(position, depth, 1.0);
|
|
||||||
}
|
|
|
@ -1,75 +0,0 @@
|
||||||
// pathfinder/shaders/gles2/mcaa-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.
|
|
||||||
|
|
||||||
//! Renders the curved edges of paths when performing *mesh coverage
|
|
||||||
//! antialiasing* (MCAA).
|
|
||||||
//!
|
|
||||||
//! This shader expects to render to the red channel of a floating point color
|
|
||||||
//! buffer. Half precision floating point should be sufficient.
|
|
||||||
//!
|
|
||||||
//! Use this shader only when *both* of the following are true:
|
|
||||||
//!
|
|
||||||
//! 1. You are only rendering monochrome paths such as text. (Otherwise,
|
|
||||||
//! consider `mcaa-multi`.)
|
|
||||||
//!
|
|
||||||
//! 2. Your transform is only a scale and/or translation, not a perspective,
|
|
||||||
//! rotation, or skew. (Otherwise, consider the ECAA shaders.)
|
|
||||||
|
|
||||||
precision highp float;
|
|
||||||
|
|
||||||
uniform vec4 uTransformST;
|
|
||||||
uniform vec4 uHints;
|
|
||||||
uniform ivec2 uFramebufferSize;
|
|
||||||
uniform ivec2 uPathTransformSTDimensions;
|
|
||||||
uniform sampler2D uPathTransformST;
|
|
||||||
uniform bool uWinding;
|
|
||||||
|
|
||||||
attribute vec2 aQuadPosition;
|
|
||||||
attribute vec2 aLeftPosition;
|
|
||||||
attribute vec2 aControlPointPosition;
|
|
||||||
attribute vec2 aRightPosition;
|
|
||||||
attribute float aPathID;
|
|
||||||
|
|
||||||
varying vec4 vEndpoints;
|
|
||||||
varying vec2 vControlPoint;
|
|
||||||
varying float vWinding;
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
vec2 leftPosition = aLeftPosition;
|
|
||||||
vec2 controlPointPosition = aControlPointPosition;
|
|
||||||
vec2 rightPosition = aRightPosition;
|
|
||||||
int pathID = int(aPathID);
|
|
||||||
|
|
||||||
vec4 transformST = fetchFloat4Data(uPathTransformST, pathID, uPathTransformSTDimensions);
|
|
||||||
|
|
||||||
// Transform the points, and compute the position of this vertex.
|
|
||||||
vec2 position;
|
|
||||||
if (computeMCAAQuadPosition(position,
|
|
||||||
leftPosition,
|
|
||||||
rightPosition,
|
|
||||||
aQuadPosition,
|
|
||||||
uFramebufferSize,
|
|
||||||
transformST,
|
|
||||||
uTransformST,
|
|
||||||
uHints)) {
|
|
||||||
controlPointPosition = computeMCAAPosition(controlPointPosition,
|
|
||||||
uHints,
|
|
||||||
transformST,
|
|
||||||
uTransformST,
|
|
||||||
uFramebufferSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
float depth = convertPathIndexToViewportDepthValue(pathID);
|
|
||||||
|
|
||||||
gl_Position = vec4(position, depth, 1.0);
|
|
||||||
vEndpoints = vec4(leftPosition, rightPosition);
|
|
||||||
vControlPoint = controlPointPosition;
|
|
||||||
vWinding = uWinding ? 1.0 : -1.0;
|
|
||||||
}
|
|
|
@ -1,62 +0,0 @@
|
||||||
// pathfinder/shaders/gles2/mcaa-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.
|
|
||||||
|
|
||||||
//! Renders the straight line segments of paths when performing *mesh coverage
|
|
||||||
//! antialiasing* (MCAA).
|
|
||||||
//!
|
|
||||||
//! Use this shader only when *both* of the following are true:
|
|
||||||
//!
|
|
||||||
//! 1. You are only rendering monochrome paths such as text. (Otherwise,
|
|
||||||
//! consider `mcaa-multi`.)
|
|
||||||
//!
|
|
||||||
//! 2. Your transform is only a scale and/or translation, not a perspective,
|
|
||||||
//! rotation, or skew. (Otherwise, consider the ECAA shaders.)
|
|
||||||
|
|
||||||
precision highp float;
|
|
||||||
|
|
||||||
uniform vec4 uTransformST;
|
|
||||||
uniform vec4 uHints;
|
|
||||||
uniform ivec2 uFramebufferSize;
|
|
||||||
uniform ivec2 uPathTransformSTDimensions;
|
|
||||||
uniform sampler2D uPathTransformST;
|
|
||||||
uniform bool uWinding;
|
|
||||||
|
|
||||||
attribute vec2 aQuadPosition;
|
|
||||||
attribute vec2 aLeftPosition;
|
|
||||||
attribute vec2 aRightPosition;
|
|
||||||
attribute float aPathID;
|
|
||||||
|
|
||||||
varying vec4 vEndpoints;
|
|
||||||
varying float vWinding;
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
vec2 leftPosition = aLeftPosition;
|
|
||||||
vec2 rightPosition = aRightPosition;
|
|
||||||
int pathID = int(aPathID);
|
|
||||||
|
|
||||||
vec4 transformST = fetchFloat4Data(uPathTransformST, pathID, uPathTransformSTDimensions);
|
|
||||||
|
|
||||||
// Transform the points, and compute the position of this vertex.
|
|
||||||
vec2 position;
|
|
||||||
computeMCAAQuadPosition(position,
|
|
||||||
leftPosition,
|
|
||||||
rightPosition,
|
|
||||||
aQuadPosition,
|
|
||||||
uFramebufferSize,
|
|
||||||
transformST,
|
|
||||||
uTransformST,
|
|
||||||
uHints);
|
|
||||||
|
|
||||||
float depth = convertPathIndexToViewportDepthValue(pathID);
|
|
||||||
|
|
||||||
gl_Position = vec4(position, depth, 1.0);
|
|
||||||
vEndpoints = vec4(leftPosition, rightPosition);
|
|
||||||
vWinding = uWinding ? 1.0 : -1.0;
|
|
||||||
}
|
|
|
@ -1,126 +0,0 @@
|
||||||
// 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.
|
|
||||||
|
|
||||||
//! Renders paths when performing multicolor *mesh coverage antialiasing*
|
|
||||||
//! (MCAA). This one shader handles both lines and curves.
|
|
||||||
//!
|
|
||||||
//! This shader expects to render to a standard RGB color buffer.
|
|
||||||
//!
|
|
||||||
//! Use this shader only when *both* of the following are true:
|
|
||||||
//!
|
|
||||||
//! 1. You are rendering multiple multicolor paths. (Otherwise, consider the
|
|
||||||
//! other MCAA shaders, which render with higher quality.)
|
|
||||||
//!
|
|
||||||
//! 2. Your transform is only a scale and/or translation, not a perspective,
|
|
||||||
//! rotation, or skew. (Otherwise, consider repartitioning the path to
|
|
||||||
//! generate a new mesh, or, alternatively, use the direct Loop-Blinn
|
|
||||||
//! shaders.)
|
|
||||||
|
|
||||||
#define MAX_SLOPE 10.0
|
|
||||||
|
|
||||||
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 topSlope = topVector.y / topVector.x;
|
|
||||||
float bottomSlope = bottomVector.y / bottomVector.x;
|
|
||||||
if (abs(topSlope) > MAX_SLOPE)
|
|
||||||
topSlope = sign(topSlope) * MAX_SLOPE;
|
|
||||||
if (abs(bottomSlope) > MAX_SLOPE)
|
|
||||||
bottomSlope = sign(bottomSlope) * MAX_SLOPE;
|
|
||||||
|
|
||||||
// Transform the points, and compute the position of this vertex.
|
|
||||||
tlPosition = computeMCAASnappedPosition(tlPosition,
|
|
||||||
uHints,
|
|
||||||
transformST,
|
|
||||||
uTransformST,
|
|
||||||
uFramebufferSize,
|
|
||||||
topSlope);
|
|
||||||
trPosition = computeMCAASnappedPosition(trPosition,
|
|
||||||
uHints,
|
|
||||||
transformST,
|
|
||||||
uTransformST,
|
|
||||||
uFramebufferSize,
|
|
||||||
topSlope);
|
|
||||||
tcPosition = computeMCAAPosition(tcPosition,
|
|
||||||
uHints,
|
|
||||||
transformST,
|
|
||||||
uTransformST,
|
|
||||||
uFramebufferSize);
|
|
||||||
blPosition = computeMCAASnappedPosition(blPosition,
|
|
||||||
uHints,
|
|
||||||
transformST,
|
|
||||||
uTransformST,
|
|
||||||
uFramebufferSize,
|
|
||||||
bottomSlope);
|
|
||||||
brPosition = computeMCAASnappedPosition(brPosition,
|
|
||||||
uHints,
|
|
||||||
transformST,
|
|
||||||
uTransformST,
|
|
||||||
uFramebufferSize,
|
|
||||||
bottomSlope);
|
|
||||||
bcPosition = computeMCAAPosition(bcPosition,
|
|
||||||
uHints,
|
|
||||||
transformST,
|
|
||||||
uTransformST,
|
|
||||||
uFramebufferSize);
|
|
||||||
|
|
||||||
float depth = convertPathIndexToViewportDepthValue(pathID);
|
|
||||||
|
|
||||||
// Use the same side--in this case, the top--or else floating point error during partitioning
|
|
||||||
// can occasionally cause inconsistent rounding, resulting in cracks.
|
|
||||||
vec2 position;
|
|
||||||
position.x = quadPosition.x < 0.5 ? tlPosition.x : trPosition.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,4 +1,4 @@
|
||||||
// pathfinder/shaders/gles2/mcaa-multi.fs.glsl
|
// pathfinder/shaders/gles2/mcaa.fs.glsl
|
||||||
//
|
//
|
||||||
// Copyright (c) 2017 The Pathfinder Project Developers.
|
// Copyright (c) 2017 The Pathfinder Project Developers.
|
||||||
//
|
//
|
||||||
|
@ -69,5 +69,5 @@ void main() {
|
||||||
1.0);
|
1.0);
|
||||||
|
|
||||||
// Compute area.
|
// Compute area.
|
||||||
gl_FragColor = vec4(vColor.rgb, vColor.a * alpha);
|
gl_FragColor = alpha * vColor;
|
||||||
}
|
}
|
|
@ -0,0 +1,146 @@
|
||||||
|
// pathfinder/shaders/gles2/mcaa.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.
|
||||||
|
|
||||||
|
//! Renders paths when performing *mesh coverage antialiasing* (MCAA). This
|
||||||
|
//! one shader handles both lines and curves.
|
||||||
|
//!
|
||||||
|
//! This shader expects to render to a standard RGB color buffer in the
|
||||||
|
//! multicolor case or a single-channel floating-point color buffer in the
|
||||||
|
//! monochrome case.
|
||||||
|
//!
|
||||||
|
//! Set state as follows depending on whether multiple overlapping multicolor
|
||||||
|
//! paths are present:
|
||||||
|
//!
|
||||||
|
//! * When paths of multiple colors are present, use
|
||||||
|
//! `glBlendFuncSeparate(GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE)` and
|
||||||
|
//! set `uSnapToPixelGrid` to 1.
|
||||||
|
//!
|
||||||
|
//! * Otherwise, if only one color of path is present, use
|
||||||
|
//! `glBlendFunc(GL_ONE, GL_ONE)` and set `uSnapToPixelGrid` to 0.
|
||||||
|
//!
|
||||||
|
//! Use this shader only when your transform is only a scale and/or
|
||||||
|
//! translation, not a perspective, rotation, or skew. (Otherwise, consider
|
||||||
|
//! repartitioning the path to generate a new mesh, or, alternatively, use the
|
||||||
|
//! direct Loop-Blinn shaders.)
|
||||||
|
|
||||||
|
#define MAX_SLOPE 10.0
|
||||||
|
|
||||||
|
precision highp float;
|
||||||
|
|
||||||
|
uniform vec4 uTransformST;
|
||||||
|
uniform vec4 uHints;
|
||||||
|
uniform ivec2 uFramebufferSize;
|
||||||
|
uniform ivec2 uPathTransformSTDimensions;
|
||||||
|
uniform sampler2D uPathTransformST;
|
||||||
|
uniform ivec2 uPathColorsDimensions;
|
||||||
|
uniform sampler2D uPathColors;
|
||||||
|
uniform bool uSnapToPixelGrid;
|
||||||
|
|
||||||
|
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(floor(aPathID));
|
||||||
|
|
||||||
|
vec4 transformST = fetchFloat4Data(uPathTransformST, pathID, uPathTransformSTDimensions);
|
||||||
|
if (abs(transformST.x) > 0.001 && abs(transformST.y) > 0.001) {
|
||||||
|
vec4 color = fetchFloat4Data(uPathColors, pathID, uPathColorsDimensions);
|
||||||
|
|
||||||
|
vec2 topVector = trPosition - tlPosition, bottomVector = brPosition - blPosition;
|
||||||
|
|
||||||
|
float topSlope = topVector.y / topVector.x;
|
||||||
|
float bottomSlope = bottomVector.y / bottomVector.x;
|
||||||
|
if (abs(topSlope) > MAX_SLOPE)
|
||||||
|
topSlope = sign(topSlope) * MAX_SLOPE;
|
||||||
|
if (abs(bottomSlope) > MAX_SLOPE)
|
||||||
|
bottomSlope = sign(bottomSlope) * MAX_SLOPE;
|
||||||
|
|
||||||
|
// Transform the points, and compute the position of this vertex.
|
||||||
|
tlPosition = computeMCAASnappedPosition(tlPosition,
|
||||||
|
uHints,
|
||||||
|
transformST,
|
||||||
|
uTransformST,
|
||||||
|
uFramebufferSize,
|
||||||
|
topSlope,
|
||||||
|
uSnapToPixelGrid);
|
||||||
|
trPosition = computeMCAASnappedPosition(trPosition,
|
||||||
|
uHints,
|
||||||
|
transformST,
|
||||||
|
uTransformST,
|
||||||
|
uFramebufferSize,
|
||||||
|
topSlope,
|
||||||
|
uSnapToPixelGrid);
|
||||||
|
tcPosition = computeMCAAPosition(tcPosition,
|
||||||
|
uHints,
|
||||||
|
transformST,
|
||||||
|
uTransformST,
|
||||||
|
uFramebufferSize);
|
||||||
|
blPosition = computeMCAASnappedPosition(blPosition,
|
||||||
|
uHints,
|
||||||
|
transformST,
|
||||||
|
uTransformST,
|
||||||
|
uFramebufferSize,
|
||||||
|
bottomSlope,
|
||||||
|
uSnapToPixelGrid);
|
||||||
|
brPosition = computeMCAASnappedPosition(brPosition,
|
||||||
|
uHints,
|
||||||
|
transformST,
|
||||||
|
uTransformST,
|
||||||
|
uFramebufferSize,
|
||||||
|
bottomSlope,
|
||||||
|
uSnapToPixelGrid);
|
||||||
|
bcPosition = computeMCAAPosition(bcPosition,
|
||||||
|
uHints,
|
||||||
|
transformST,
|
||||||
|
uTransformST,
|
||||||
|
uFramebufferSize);
|
||||||
|
|
||||||
|
float depth = convertPathIndexToViewportDepthValue(pathID);
|
||||||
|
|
||||||
|
// Use the same side--in this case, the top--or else floating point error during partitioning
|
||||||
|
// can occasionally cause inconsistent rounding, resulting in cracks.
|
||||||
|
vec2 position;
|
||||||
|
|
||||||
|
if (uSnapToPixelGrid)
|
||||||
|
position.x = quadPosition.x < 0.5 ? tlPosition.x : trPosition.x;
|
||||||
|
else
|
||||||
|
position.x = quadPosition.x < 0.5 ? floor(tlPosition.x) : ceil(trPosition.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;
|
||||||
|
} else {
|
||||||
|
gl_Position = vec4(0.0);
|
||||||
|
}
|
||||||
|
}
|
|
@ -41,5 +41,6 @@ void main() {
|
||||||
lcdFilter(shadeL.x, shade0, shadeR.x, shadeR.y, shadeR.z));
|
lcdFilter(shadeL.x, shade0, shadeR.x, shadeR.y, shadeR.z));
|
||||||
|
|
||||||
vec3 color = mix(uBGColor.rgb, uFGColor.rgb, shades);
|
vec3 color = mix(uBGColor.rgb, uFGColor.rgb, shades);
|
||||||
gl_FragColor = vec4(color, any(greaterThan(shades, vec3(0.0))) ? uFGColor.a : uBGColor.a);
|
float alpha = any(greaterThan(shades, vec3(0.0))) ? uFGColor.a : uBGColor.a;
|
||||||
|
gl_FragColor = alpha * vec4(color, 1.0);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue