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;
|
||||
|
||||
get isMulticolor(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
get usesSTTransform(): boolean {
|
||||
return this.camera.usesSTTransform;
|
||||
}
|
||||
|
@ -702,7 +706,7 @@ class ThreeDRenderer extends Renderer {
|
|||
gl.disable(gl.SCISSOR_TEST);
|
||||
gl.enable(gl.BLEND);
|
||||
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.
|
||||
const cameraTransform = this.calculateCameraTransform(glmatrix.vec3.create(), TEXT_SCALE);
|
||||
|
|
|
@ -423,6 +423,10 @@ class BenchmarkTextRenderer extends Renderer {
|
|||
|
||||
camera: OrthographicCamera;
|
||||
|
||||
get isMulticolor(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
get usesSTTransform(): boolean {
|
||||
return this.camera.usesSTTransform;
|
||||
}
|
||||
|
|
|
@ -668,6 +668,10 @@ class ReferenceTestTextRenderer extends Renderer {
|
|||
return null;
|
||||
}
|
||||
|
||||
get isMulticolor(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
get bgColor(): glmatrix.vec4 {
|
||||
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;
|
||||
}
|
||||
|
||||
abstract get isMulticolor(): boolean;
|
||||
|
||||
abstract get destFramebuffer(): WebGLFramebuffer | null;
|
||||
abstract get destAllocatedSize(): glmatrix.vec2;
|
||||
abstract get destUsedSize(): glmatrix.vec2;
|
||||
|
@ -131,14 +133,14 @@ export abstract class Renderer {
|
|||
if (this.meshes == null)
|
||||
return;
|
||||
|
||||
this.clearDestFramebuffer();
|
||||
|
||||
// Start timing rendering.
|
||||
if (this.timerQueryPollInterval == null) {
|
||||
renderContext.timerQueryExt.beginQueryEXT(renderContext.timerQueryExt.TIME_ELAPSED_EXT,
|
||||
renderContext.atlasRenderingTimerQuery);
|
||||
}
|
||||
|
||||
this.clearDestFramebuffer();
|
||||
|
||||
const antialiasingStrategy = unwrapNull(this.antialiasingStrategy);
|
||||
antialiasingStrategy.prepareForRendering(this);
|
||||
|
||||
|
@ -155,8 +157,16 @@ export abstract class Renderer {
|
|||
// Antialias.
|
||||
antialiasingStrategy.antialiasObject(this, objectIndex);
|
||||
|
||||
// Perform post-antialiasing tasks.
|
||||
antialiasingStrategy.finishAntialiasingObject(this, objectIndex);
|
||||
// End the timer, and start a new one.
|
||||
// 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).
|
||||
if (antialiasingStrategy.directRenderingMode !== 'none') {
|
||||
|
@ -169,20 +179,15 @@ export abstract class Renderer {
|
|||
this.directlyRenderObject(pass, objectIndex);
|
||||
}
|
||||
|
||||
// Perform post-antialiasing tasks.
|
||||
antialiasingStrategy.finishAntialiasingObject(this, objectIndex);
|
||||
|
||||
antialiasingStrategy.resolveAAForObject(this, objectIndex);
|
||||
}
|
||||
|
||||
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.
|
||||
this.compositeIfNecessary();
|
||||
|
||||
|
@ -306,22 +311,24 @@ export abstract class Renderer {
|
|||
|
||||
uploadPathTransforms(objectCount: number): void {
|
||||
const renderContext = this.renderContext;
|
||||
const gl = renderContext.gl;
|
||||
|
||||
for (let objectIndex = 0; objectIndex < objectCount; objectIndex++) {
|
||||
const pathTransforms = this.pathTransformsForObject(objectIndex);
|
||||
|
||||
let pathTransformBufferTextures;
|
||||
if (objectIndex >= this.pathTransformBufferTextures.length) {
|
||||
pathTransformBufferTextures = {
|
||||
ext: new PathfinderBufferTexture(renderContext.gl, 'uPathTransformExt'),
|
||||
st: new PathfinderBufferTexture(renderContext.gl, 'uPathTransformST'),
|
||||
ext: new PathfinderBufferTexture(gl, 'uPathTransformExt'),
|
||||
st: new PathfinderBufferTexture(gl, 'uPathTransformST'),
|
||||
};
|
||||
this.pathTransformBufferTextures[objectIndex] = pathTransformBufferTextures;
|
||||
} else {
|
||||
pathTransformBufferTextures = this.pathTransformBufferTextures[objectIndex];
|
||||
}
|
||||
|
||||
pathTransformBufferTextures.st.upload(renderContext.gl, pathTransforms.st);
|
||||
pathTransformBufferTextures.ext.upload(renderContext.gl, pathTransforms.ext);
|
||||
pathTransformBufferTextures.st.upload(gl, pathTransforms.st);
|
||||
pathTransformBufferTextures.ext.upload(gl, pathTransforms.ext);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -501,7 +508,7 @@ export abstract class Renderer {
|
|||
gl.depthMask(false);
|
||||
gl.enable(gl.BLEND);
|
||||
gl.blendEquation(gl.FUNC_ADD);
|
||||
gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE);
|
||||
gl.blendFuncSeparate(gl.ONE, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE);
|
||||
|
||||
// Set up the direct curve VAO.
|
||||
//
|
||||
|
|
|
@ -23,10 +23,7 @@ export interface ShaderMap<T> {
|
|||
ecaaLine: T;
|
||||
ecaaCurve: T;
|
||||
ecaaTransformedCurve: T;
|
||||
mcaaCover: T;
|
||||
mcaaLine: T;
|
||||
mcaaCurve: T;
|
||||
mcaaMulti: T;
|
||||
mcaa: T;
|
||||
ssaaSubpixelResolve: T;
|
||||
xcaaMonoResolve: T;
|
||||
xcaaMonoSubpixelResolve: T;
|
||||
|
@ -47,10 +44,7 @@ export const SHADER_NAMES: Array<keyof ShaderMap<void>> = [
|
|||
'direct3DCurve',
|
||||
'direct3DInterior',
|
||||
'ssaaSubpixelResolve',
|
||||
'mcaaCover',
|
||||
'mcaaLine',
|
||||
'mcaaCurve',
|
||||
'mcaaMulti',
|
||||
'mcaa',
|
||||
'ecaaLine',
|
||||
'ecaaCurve',
|
||||
'ecaaTransformedCurve',
|
||||
|
@ -94,32 +88,20 @@ const SHADER_URLS: ShaderMap<ShaderProgramURLs> = {
|
|||
vertex: "/glsl/gles2/direct-interior.vs.glsl",
|
||||
},
|
||||
ecaaCurve: {
|
||||
fragment: "/glsl/gles2/xcaa-curve.fs.glsl",
|
||||
fragment: "/glsl/gles2/ecaa-curve.fs.glsl",
|
||||
vertex: "/glsl/gles2/ecaa-curve.vs.glsl",
|
||||
},
|
||||
ecaaLine: {
|
||||
fragment: "/glsl/gles2/xcaa-line.fs.glsl",
|
||||
fragment: "/glsl/gles2/ecaa-line.fs.glsl",
|
||||
vertex: "/glsl/gles2/ecaa-line.vs.glsl",
|
||||
},
|
||||
ecaaTransformedCurve: {
|
||||
fragment: "/glsl/gles2/xcaa-curve.fs.glsl",
|
||||
fragment: "/glsl/gles2/ecaa-curve.fs.glsl",
|
||||
vertex: "/glsl/gles2/ecaa-transformed-curve.vs.glsl",
|
||||
},
|
||||
mcaaCover: {
|
||||
fragment: "/glsl/gles2/mcaa-cover.fs.glsl",
|
||||
vertex: "/glsl/gles2/mcaa-cover.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",
|
||||
mcaa: {
|
||||
fragment: "/glsl/gles2/mcaa.fs.glsl",
|
||||
vertex: "/glsl/gles2/mcaa.vs.glsl",
|
||||
},
|
||||
ssaaSubpixelResolve: {
|
||||
fragment: "/glsl/gles2/ssaa-subpixel-resolve.fs.glsl",
|
||||
|
|
|
@ -21,18 +21,18 @@ import SSAAStrategy from './ssaa-strategy';
|
|||
import {SVGLoader} from './svg-loader';
|
||||
import {Range} from './utils';
|
||||
import {RenderContext} from './view';
|
||||
import {MCAAMulticolorStrategy, XCAAStrategy} from './xcaa-strategy';
|
||||
import {MCAAStrategy, XCAAStrategy} from './xcaa-strategy';
|
||||
|
||||
interface AntialiasingStrategyTable {
|
||||
none: typeof NoAAStrategy;
|
||||
ssaa: typeof SSAAStrategy;
|
||||
xcaa: typeof XCAAStrategy;
|
||||
xcaa: typeof MCAAStrategy;
|
||||
}
|
||||
|
||||
const ANTIALIASING_STRATEGIES: AntialiasingStrategyTable = {
|
||||
none: NoAAStrategy,
|
||||
ssaa: SSAAStrategy,
|
||||
xcaa: MCAAMulticolorStrategy,
|
||||
xcaa: MCAAStrategy,
|
||||
};
|
||||
|
||||
export abstract class SVGRenderer extends Renderer {
|
||||
|
@ -40,6 +40,11 @@ export abstract class SVGRenderer extends Renderer {
|
|||
|
||||
camera: OrthographicCamera;
|
||||
|
||||
get isMulticolor(): boolean {
|
||||
// FIXME(pcwalton): Only if the SVG is actually multicolor!
|
||||
return true;
|
||||
}
|
||||
|
||||
get bgColor(): glmatrix.vec4 {
|
||||
return glmatrix.vec4.clone([1.0, 1.0, 1.0, 1.0]);
|
||||
}
|
||||
|
|
|
@ -64,6 +64,10 @@ export abstract class TextRenderer extends Renderer {
|
|||
atlasFramebuffer: WebGLFramebuffer;
|
||||
atlasDepthTexture: WebGLTexture;
|
||||
|
||||
get isMulticolor(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
get usesSTTransform(): boolean {
|
||||
return this.camera.usesSTTransform;
|
||||
}
|
||||
|
@ -146,12 +150,15 @@ export abstract class TextRenderer extends Renderer {
|
|||
}
|
||||
|
||||
setHintsUniform(uniforms: UniformMap): void {
|
||||
const renderContext = this.renderContext;
|
||||
const gl = renderContext.gl;
|
||||
|
||||
const hint = this.createHint();
|
||||
this.renderContext.gl.uniform4f(uniforms.uHints,
|
||||
hint.xHeight,
|
||||
hint.hintedXHeight,
|
||||
hint.stemHeight,
|
||||
hint.hintedStemHeight);
|
||||
gl.uniform4f(uniforms.uHints,
|
||||
hint.xHeight,
|
||||
hint.hintedXHeight,
|
||||
hint.stemHeight,
|
||||
hint.hintedStemHeight);
|
||||
}
|
||||
|
||||
pathBoundingRects(objectIndex: number): Float32Array {
|
||||
|
|
|
@ -41,9 +41,8 @@ export abstract class XCAAStrategy extends AntialiasingStrategy {
|
|||
}
|
||||
|
||||
protected abstract get usesDilationTransforms(): boolean;
|
||||
protected abstract get usesAAFramebuffer(): boolean;
|
||||
|
||||
protected pathBoundsBufferTexture: PathfinderBufferTexture;
|
||||
protected pathBoundsBufferTextures: PathfinderBufferTexture[];
|
||||
|
||||
protected supersampledFramebufferSize: glmatrix.vec2;
|
||||
protected destFramebufferSize: glmatrix.vec2;
|
||||
|
@ -72,6 +71,7 @@ export abstract class XCAAStrategy extends AntialiasingStrategy {
|
|||
attachMeshes(renderer: Renderer): void {
|
||||
const renderContext = renderer.renderContext;
|
||||
this.createResolveVAO(renderer);
|
||||
this.pathBoundsBufferTextures = [];
|
||||
}
|
||||
|
||||
setFramebufferSize(renderer: Renderer): void {
|
||||
|
@ -97,17 +97,18 @@ export abstract class XCAAStrategy extends AntialiasingStrategy {
|
|||
|
||||
this.initResolveFramebufferForObject(renderer, objectIndex);
|
||||
|
||||
if (this.usesAAFramebuffer) {
|
||||
const usedSize = this.supersampledUsedSize(renderer);
|
||||
gl.scissor(0, 0, usedSize[0], usedSize[1]);
|
||||
gl.enable(gl.SCISSOR_TEST);
|
||||
if (!this.usesAAFramebuffer(renderer))
|
||||
return;
|
||||
|
||||
// Clear out the color and depth textures.
|
||||
gl.clearColor(1.0, 1.0, 1.0, 1.0);
|
||||
gl.clearDepth(0.0);
|
||||
gl.depthMask(true);
|
||||
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
||||
}
|
||||
const usedSize = this.supersampledUsedSize(renderer);
|
||||
gl.scissor(0, 0, usedSize[0], usedSize[1]);
|
||||
gl.enable(gl.SCISSOR_TEST);
|
||||
|
||||
// Clear out the color and depth textures.
|
||||
gl.clearColor(1.0, 1.0, 1.0, 1.0);
|
||||
gl.clearDepth(0.0);
|
||||
gl.depthMask(true);
|
||||
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
||||
}
|
||||
|
||||
prepareToRenderObject(renderer: Renderer, objectIndex: number): void {}
|
||||
|
@ -118,7 +119,7 @@ export abstract class XCAAStrategy extends AntialiasingStrategy {
|
|||
|
||||
antialiasObject(renderer: Renderer, objectIndex: number): void {
|
||||
// Perform early preparations.
|
||||
this.createPathBoundsBufferTextureForObject(renderer, objectIndex);
|
||||
this.createPathBoundsBufferTextureForObjectIfNecessary(renderer, objectIndex);
|
||||
|
||||
// Set up antialiasing.
|
||||
this.prepareAA(renderer);
|
||||
|
@ -131,7 +132,7 @@ export abstract class XCAAStrategy extends AntialiasingStrategy {
|
|||
const renderContext = renderer.renderContext;
|
||||
const gl = renderContext.gl;
|
||||
|
||||
const resolveProgram = this.getResolveProgram(renderContext);
|
||||
const resolveProgram = this.getResolveProgram(renderer);
|
||||
if (resolveProgram == null)
|
||||
return;
|
||||
|
||||
|
@ -172,6 +173,8 @@ export abstract class XCAAStrategy extends AntialiasingStrategy {
|
|||
return glmatrix.mat4.create();
|
||||
}
|
||||
|
||||
protected abstract usesAAFramebuffer(renderer: Renderer): boolean;
|
||||
|
||||
protected supersampledUsedSize(renderer: Renderer): glmatrix.vec2 {
|
||||
const usedSize = glmatrix.vec2.create();
|
||||
glmatrix.vec2.mul(usedSize, renderer.destUsedSize, this.supersampleScale);
|
||||
|
@ -223,7 +226,7 @@ export abstract class XCAAStrategy extends AntialiasingStrategy {
|
|||
this.supersampledFramebufferSize[1]);
|
||||
renderer.pathTransformBufferTextures[0].ext.bind(gl, uniforms, 0);
|
||||
renderer.pathTransformBufferTextures[0].st.bind(gl, uniforms, 1);
|
||||
this.pathBoundsBufferTexture.bind(gl, uniforms, 2);
|
||||
this.pathBoundsBufferTextures[objectIndex].bind(gl, uniforms, 2);
|
||||
renderer.setHintsUniform(uniforms);
|
||||
}
|
||||
|
||||
|
@ -239,8 +242,7 @@ export abstract class XCAAStrategy extends AntialiasingStrategy {
|
|||
void {}
|
||||
|
||||
protected abstract clearForAA(renderer: Renderer): void;
|
||||
protected abstract getResolveProgram(renderContext: RenderContext):
|
||||
PathfinderShaderProgram | null;
|
||||
protected abstract getResolveProgram(renderer: Renderer): PathfinderShaderProgram | null;
|
||||
protected abstract setAADepthState(renderer: Renderer): void;
|
||||
protected abstract clearForResolve(renderer: Renderer): void;
|
||||
|
||||
|
@ -254,7 +256,7 @@ export abstract class XCAAStrategy extends AntialiasingStrategy {
|
|||
}
|
||||
|
||||
private initAAAlphaFramebuffer(renderer: Renderer): void {
|
||||
if (!this.usesAAFramebuffer) {
|
||||
if (!this.usesAAFramebuffer(renderer)) {
|
||||
this.aaAlphaTexture = null;
|
||||
this.aaDepthTexture = null;
|
||||
this.aaFramebuffer = null;
|
||||
|
@ -282,20 +284,27 @@ export abstract class XCAAStrategy extends AntialiasingStrategy {
|
|||
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 gl = renderContext.gl;
|
||||
|
||||
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 {
|
||||
const renderContext = renderer.renderContext;
|
||||
const gl = renderContext.gl;
|
||||
|
||||
const resolveProgram = this.getResolveProgram(renderContext);
|
||||
const resolveProgram = this.getResolveProgram(renderer);
|
||||
if (resolveProgram == null)
|
||||
return;
|
||||
|
||||
|
@ -317,11 +326,8 @@ export abstract class XCAAStrategy extends AntialiasingStrategy {
|
|||
}
|
||||
}
|
||||
|
||||
export class MCAAMonochromeStrategy extends XCAAStrategy {
|
||||
protected coverVAO: WebGLVertexArrayObject | null;
|
||||
|
||||
protected lineVAOs: FastEdgeVAOs;
|
||||
protected curveVAOs: FastEdgeVAOs;
|
||||
export class MCAAStrategy extends XCAAStrategy {
|
||||
protected vao: WebGLVertexArrayObject | null;
|
||||
|
||||
protected get usesDilationTransforms(): boolean {
|
||||
return true;
|
||||
|
@ -330,27 +336,25 @@ export class MCAAMonochromeStrategy extends XCAAStrategy {
|
|||
attachMeshes(renderer: Renderer): void {
|
||||
super.attachMeshes(renderer);
|
||||
|
||||
this.createCoverVAOIfNecessary(renderer);
|
||||
this.createLineVAOs(renderer);
|
||||
this.createCurveVAOs(renderer);
|
||||
const renderContext = renderer.renderContext;
|
||||
this.vao = renderContext.vertexArrayObjectExt.createVertexArrayOES();
|
||||
}
|
||||
|
||||
antialiasObject(renderer: Renderer, objectIndex: number): void {
|
||||
super.antialiasObject(renderer, objectIndex);
|
||||
|
||||
// Conservatively cover.
|
||||
this.coverObjectIfNecessary(renderer, objectIndex);
|
||||
|
||||
// Antialias.
|
||||
this.antialiasLinesOfObject(renderer, objectIndex);
|
||||
this.antialiasCurvesOfObject(renderer, objectIndex);
|
||||
const shaderProgram = this.edgeProgram(renderer);
|
||||
this.antialiasEdgesOfObjectWithProgram(renderer, objectIndex, shaderProgram);
|
||||
}
|
||||
|
||||
protected get usesAAFramebuffer(): boolean {
|
||||
return true;
|
||||
protected usesAAFramebuffer(renderer: Renderer): boolean {
|
||||
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')
|
||||
return renderContext.shaderPrograms.xcaaMonoSubpixelResolve;
|
||||
return renderContext.shaderPrograms.xcaaMonoResolve;
|
||||
|
@ -360,60 +364,126 @@ export class MCAAMonochromeStrategy extends XCAAStrategy {
|
|||
const renderContext = renderer.renderContext;
|
||||
const gl = renderContext.gl;
|
||||
|
||||
gl.clearColor(0.0, 0.0, 0.0, 0.0);
|
||||
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.clearDepth(0.0);
|
||||
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
||||
}
|
||||
|
||||
protected setAADepthState(renderer: Renderer): void {
|
||||
const renderContext = renderer.renderContext;
|
||||
renderContext.gl.disable(renderContext.gl.DEPTH_TEST);
|
||||
const gl = renderContext.gl;
|
||||
|
||||
gl.disable(gl.DEPTH_TEST);
|
||||
}
|
||||
|
||||
protected clearForResolve(renderer: Renderer): void {
|
||||
const renderContext = renderer.renderContext;
|
||||
const gl = renderContext.gl;
|
||||
|
||||
gl.clearColor(1.0, 1.0, 1.0, 1.0);
|
||||
gl.clear(gl.COLOR_BUFFER_BIT);
|
||||
}
|
||||
|
||||
protected createCoverVAOIfNecessary(renderer: Renderer): void {
|
||||
this.coverVAO = renderer.renderContext.vertexArrayObjectExt.createVertexArrayOES();
|
||||
if (!renderer.isMulticolor) {
|
||||
gl.clearColor(1.0, 1.0, 1.0, 1.0);
|
||||
gl.clear(gl.COLOR_BUFFER_BIT);
|
||||
}
|
||||
}
|
||||
|
||||
protected setBlendModeForAA(renderer: Renderer): void {
|
||||
const renderContext = renderer.renderContext;
|
||||
const gl = renderContext.gl;
|
||||
|
||||
if (renderer.isMulticolor)
|
||||
gl.blendFuncSeparate(gl.ONE, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE);
|
||||
else
|
||||
gl.blendFunc(gl.ONE, gl.ONE);
|
||||
|
||||
gl.blendEquation(gl.FUNC_ADD);
|
||||
gl.blendFunc(gl.ONE, gl.ONE);
|
||||
gl.enable(gl.BLEND);
|
||||
}
|
||||
|
||||
protected prepareAA(renderer: Renderer): void {
|
||||
super.prepareAA(renderer);
|
||||
|
||||
this.setCoverDepthState(renderer);
|
||||
this.setBlendModeForAA(renderer);
|
||||
}
|
||||
|
||||
protected initVAOForObject(renderer: Renderer, objectIndex: number): void {
|
||||
if (renderer.meshes == null || renderer.meshData == null)
|
||||
return;
|
||||
|
||||
const renderContext = renderer.renderContext;
|
||||
const gl = renderContext.gl;
|
||||
|
||||
gl.blendEquation(gl.FUNC_ADD);
|
||||
gl.blendFunc(gl.ONE, gl.ONE);
|
||||
gl.enable(gl.BLEND);
|
||||
const pathRange = renderer.pathRangeForObject(objectIndex);
|
||||
const meshIndex = renderer.meshIndexForObject(objectIndex);
|
||||
|
||||
this.clearForAA(renderer);
|
||||
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);
|
||||
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.vertexAttribPointer(attributes.aPathID,
|
||||
1,
|
||||
gl.UNSIGNED_SHORT,
|
||||
false,
|
||||
0,
|
||||
UINT16_SIZE * offset);
|
||||
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);
|
||||
|
||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(null);
|
||||
}
|
||||
|
||||
protected setCoverDepthState(renderer: Renderer): void {
|
||||
const renderContext = renderer.renderContext;
|
||||
renderContext.gl.disable(renderContext.gl.DEPTH_TEST);
|
||||
protected edgeProgram(renderer: Renderer): PathfinderShaderProgram {
|
||||
return renderer.renderContext.shaderPrograms.mcaa;
|
||||
}
|
||||
|
||||
protected antialiasLinesOfObjectWithProgram(renderer: Renderer,
|
||||
protected antialiasEdgesOfObjectWithProgram(renderer: Renderer,
|
||||
objectIndex: number,
|
||||
lineProgram: PathfinderShaderProgram):
|
||||
shaderProgram: PathfinderShaderProgram):
|
||||
void {
|
||||
if (renderer.meshData == null)
|
||||
return;
|
||||
|
@ -424,364 +494,60 @@ export class MCAAMonochromeStrategy extends XCAAStrategy {
|
|||
const pathRange = renderer.pathRangeForObject(objectIndex);
|
||||
const meshIndex = renderer.meshIndexForObject(objectIndex);
|
||||
|
||||
this.initLineVAOsForObject(renderer, objectIndex);
|
||||
this.initVAOForObject(renderer, objectIndex);
|
||||
|
||||
gl.useProgram(lineProgram.program);
|
||||
const uniforms = lineProgram.uniforms;
|
||||
gl.useProgram(shaderProgram.program);
|
||||
const uniforms = shaderProgram.uniforms;
|
||||
this.setAAUniforms(renderer, uniforms, objectIndex);
|
||||
|
||||
for (const direction of DIRECTIONS) {
|
||||
const vao = this.lineVAOs[direction];
|
||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(vao);
|
||||
// FIXME(pcwalton): Refactor.
|
||||
const vao = this.vao;
|
||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(vao);
|
||||
|
||||
this.setBlendModeForAA(renderer);
|
||||
gl.uniform1i(uniforms.uWinding, direction === 'upper' ? 1 : 0);
|
||||
this.setBlendModeForAA(renderer);
|
||||
|
||||
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 coverObjectIfNecessary(renderer: Renderer, objectIndex: number): void {
|
||||
if (renderer.meshes == null || renderer.meshData == null)
|
||||
return;
|
||||
|
||||
const renderContext = renderer.renderContext;
|
||||
const gl = renderContext.gl;
|
||||
|
||||
const pathRange = renderer.pathRangeForObject(objectIndex);
|
||||
const meshIndex = renderer.meshIndexForObject(objectIndex);
|
||||
|
||||
this.initCoverVAOForObject(renderer, objectIndex);
|
||||
|
||||
// Conservatively cover.
|
||||
const coverProgram = renderContext.shaderPrograms.mcaaCover;
|
||||
gl.useProgram(coverProgram.program);
|
||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(this.coverVAO);
|
||||
this.setAAUniforms(renderer, coverProgram.uniforms, objectIndex);
|
||||
|
||||
const bQuadRange = renderer.meshData[meshIndex].bQuadPathRanges;
|
||||
const count = calculateCountFromIndexRanges(pathRange, bQuadRange);
|
||||
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 initCurveVAOsForObject(renderer: Renderer, objectIndex: number): void {
|
||||
if (renderer.meshes == null || renderer.meshData == null)
|
||||
return;
|
||||
|
||||
const renderContext = renderer.renderContext;
|
||||
const gl = renderContext.gl;
|
||||
|
||||
const pathRange = renderer.pathRangeForObject(objectIndex);
|
||||
const meshIndex = renderer.meshIndexForObject(objectIndex);
|
||||
|
||||
const curveProgram = this.curveProgram(renderer);
|
||||
const attributes = curveProgram.attributes;
|
||||
|
||||
for (const direction of DIRECTIONS) {
|
||||
const vao = this.curveVAOs[direction];
|
||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(vao);
|
||||
|
||||
const curveVertexPositionsBuffer = {
|
||||
lower: renderer.meshes[meshIndex].edgeLowerCurveVertexPositions,
|
||||
upper: renderer.meshes[meshIndex].edgeUpperCurveVertexPositions,
|
||||
}[direction];
|
||||
const curvePathIDsBuffer = {
|
||||
lower: renderer.meshes[meshIndex].edgeLowerCurvePathIDs,
|
||||
upper: renderer.meshes[meshIndex].edgeUpperCurvePathIDs,
|
||||
}[direction];
|
||||
const curveIndexRanges = {
|
||||
lower: renderer.meshData[meshIndex].edgeLowerCurveIndexRanges,
|
||||
upper: renderer.meshData[meshIndex].edgeUpperCurveIndexRanges,
|
||||
}[direction];
|
||||
|
||||
const offset = calculateStartFromIndexRanges(pathRange, curveIndexRanges);
|
||||
|
||||
gl.useProgram(curveProgram.program);
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, renderContext.quadPositionsBuffer);
|
||||
gl.vertexAttribPointer(attributes.aQuadPosition, 2, gl.FLOAT, false, 0, 0);
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, curveVertexPositionsBuffer);
|
||||
gl.vertexAttribPointer(attributes.aLeftPosition,
|
||||
2,
|
||||
gl.FLOAT,
|
||||
false,
|
||||
FLOAT32_SIZE * 6,
|
||||
FLOAT32_SIZE * 6 * offset);
|
||||
gl.vertexAttribPointer(attributes.aControlPointPosition,
|
||||
2,
|
||||
gl.FLOAT,
|
||||
false,
|
||||
FLOAT32_SIZE * 6,
|
||||
FLOAT32_SIZE * 6 * offset + FLOAT32_SIZE * 2);
|
||||
gl.vertexAttribPointer(attributes.aRightPosition,
|
||||
2,
|
||||
gl.FLOAT,
|
||||
false,
|
||||
FLOAT32_SIZE * 6,
|
||||
FLOAT32_SIZE * 6 * offset + FLOAT32_SIZE * 4);
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, curvePathIDsBuffer);
|
||||
gl.vertexAttribPointer(attributes.aPathID,
|
||||
1,
|
||||
gl.UNSIGNED_SHORT,
|
||||
false,
|
||||
0,
|
||||
UINT16_SIZE * offset);
|
||||
|
||||
gl.enableVertexAttribArray(attributes.aQuadPosition);
|
||||
gl.enableVertexAttribArray(attributes.aLeftPosition);
|
||||
gl.enableVertexAttribArray(attributes.aControlPointPosition);
|
||||
gl.enableVertexAttribArray(attributes.aRightPosition);
|
||||
gl.enableVertexAttribArray(attributes.aPathID);
|
||||
|
||||
renderContext.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aLeftPosition, 1);
|
||||
renderContext.instancedArraysExt
|
||||
.vertexAttribDivisorANGLE(attributes.aControlPointPosition, 1);
|
||||
renderContext.instancedArraysExt
|
||||
.vertexAttribDivisorANGLE(attributes.aRightPosition, 1);
|
||||
renderContext.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aPathID, 1);
|
||||
|
||||
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, renderContext.quadElementsBuffer);
|
||||
}
|
||||
|
||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(null);
|
||||
}
|
||||
|
||||
protected antialiasCurvesOfObjectWithProgram(renderer: Renderer,
|
||||
objectIndex: number,
|
||||
curveProgram: PathfinderShaderProgram):
|
||||
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;
|
||||
protected setAAUniforms(renderer: Renderer, uniforms: UniformMap, objectIndex: number):
|
||||
void {
|
||||
super.setAAUniforms(renderer, uniforms, objectIndex);
|
||||
|
||||
const renderContext = renderer.renderContext;
|
||||
const gl = renderContext.gl;
|
||||
|
||||
const pathRange = renderer.pathRangeForObject(objectIndex);
|
||||
const meshIndex = renderer.meshIndexForObject(objectIndex);
|
||||
renderer.setPathColorsUniform(0, uniforms, 3);
|
||||
|
||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(this.coverVAO);
|
||||
|
||||
const bQuadRanges = renderer.meshData[meshIndex].bQuadPathRanges;
|
||||
const offset = calculateStartFromIndexRanges(pathRange, bQuadRanges);
|
||||
|
||||
const coverProgram = renderContext.shaderPrograms.mcaaCover;
|
||||
const attributes = coverProgram.attributes;
|
||||
gl.useProgram(coverProgram.program);
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, renderContext.quadPositionsBuffer);
|
||||
gl.vertexAttribPointer(attributes.aQuadPosition, 2, gl.FLOAT, false, 0, 0);
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, renderer.meshes[meshIndex].edgeBoundingBoxVertexPositions);
|
||||
gl.vertexAttribPointer(attributes.aUpperLeftPosition,
|
||||
2,
|
||||
gl.FLOAT,
|
||||
false,
|
||||
FLOAT32_SIZE * 4,
|
||||
FLOAT32_SIZE * 4 * offset);
|
||||
gl.vertexAttribPointer(attributes.aLowerRightPosition,
|
||||
2,
|
||||
gl.FLOAT,
|
||||
false,
|
||||
FLOAT32_SIZE * 4,
|
||||
FLOAT32_SIZE * 4 * offset + FLOAT32_SIZE * 2);
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, renderer.meshes[meshIndex].edgeBoundingBoxPathIDs);
|
||||
gl.vertexAttribPointer(attributes.aPathID,
|
||||
1,
|
||||
gl.UNSIGNED_SHORT,
|
||||
false,
|
||||
0,
|
||||
UINT16_SIZE * offset);
|
||||
gl.enableVertexAttribArray(attributes.aQuadPosition);
|
||||
gl.enableVertexAttribArray(attributes.aUpperLeftPosition);
|
||||
gl.enableVertexAttribArray(attributes.aLowerRightPosition);
|
||||
gl.enableVertexAttribArray(attributes.aPathID);
|
||||
renderContext.instancedArraysExt
|
||||
.vertexAttribDivisorANGLE(attributes.aUpperLeftPosition, 1);
|
||||
renderContext.instancedArraysExt
|
||||
.vertexAttribDivisorANGLE(attributes.aLowerRightPosition, 1);
|
||||
renderContext.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aPathID, 1);
|
||||
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, renderContext.quadElementsBuffer);
|
||||
|
||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(null);
|
||||
}
|
||||
|
||||
private antialiasLinesOfObject(renderer: Renderer, objectIndex: number): void {
|
||||
const renderContext = renderer.renderContext;
|
||||
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 {
|
||||
const renderContext = renderer.renderContext;
|
||||
this.setAAState(renderer);
|
||||
|
||||
const curveProgram = this.curveProgram(renderer);
|
||||
renderContext.gl.useProgram(curveProgram.program);
|
||||
|
||||
this.antialiasCurvesOfObjectWithProgram(renderer, objectIndex, curveProgram);
|
||||
gl.uniform1i(uniforms.uSnapToPixelGrid, renderer.isMulticolor ? 1 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
export abstract class ECAAStrategy extends XCAAStrategy {
|
||||
protected abstract get lineShaderProgramNames(): Array<keyof ShaderMap<void>>;
|
||||
protected abstract get curveShaderProgramNames(): Array<keyof ShaderMap<void>>;
|
||||
export class ECAAStrategy extends XCAAStrategy {
|
||||
protected get lineShaderProgramNames(): Array<keyof ShaderMap<void>> {
|
||||
return ['ecaaLine'];
|
||||
}
|
||||
|
||||
protected get curveShaderProgramNames(): Array<keyof ShaderMap<void>> {
|
||||
return ['ecaaCurve', 'ecaaTransformedCurve'];
|
||||
}
|
||||
|
||||
private lineVAOs: Partial<ShaderMap<WebGLVertexArrayObject>>;
|
||||
private curveVAOs: Partial<ShaderMap<WebGLVertexArrayObject>>;
|
||||
|
||||
protected get usesDilationTransforms(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
get directRenderingMode(): DirectRenderingMode {
|
||||
return 'none';
|
||||
}
|
||||
|
@ -809,13 +575,19 @@ export abstract class ECAAStrategy extends XCAAStrategy {
|
|||
this.curveShaderProgramNames[1]);
|
||||
}
|
||||
|
||||
protected usesAAFramebuffer(): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected setAAUniforms(renderer: Renderer, uniforms: UniformMap, objectIndex: number):
|
||||
void {
|
||||
super.setAAUniforms(renderer, uniforms, objectIndex);
|
||||
renderer.setEmboldenAmountUniform(objectIndex, uniforms);
|
||||
}
|
||||
|
||||
protected getResolveProgram(renderContext: RenderContext): PathfinderShaderProgram {
|
||||
protected getResolveProgram(renderer: Renderer): PathfinderShaderProgram {
|
||||
const renderContext = renderer.renderContext;
|
||||
|
||||
if (this.subpixelAA !== 'none')
|
||||
return renderContext.shaderPrograms.xcaaMonoSubpixelResolve;
|
||||
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.
|
||||
///
|
||||
/// FIXME(pcwalton): Share textures and FBOs between the two strategies.
|
||||
export class AdaptiveMonochromeXCAAStrategy implements AntialiasingStrategy {
|
||||
private mcaaStrategy: MCAAMonochromeStrategy;
|
||||
private mcaaStrategy: MCAAStrategy;
|
||||
private ecaaStrategy: ECAAStrategy;
|
||||
|
||||
get directRenderingMode(): DirectRenderingMode {
|
||||
|
@ -1306,8 +877,8 @@ export class AdaptiveMonochromeXCAAStrategy implements AntialiasingStrategy {
|
|||
}
|
||||
|
||||
constructor(level: number, subpixelAA: SubpixelAAType) {
|
||||
this.mcaaStrategy = new MCAAMonochromeStrategy(level, subpixelAA);
|
||||
this.ecaaStrategy = new ECAAMonochromeStrategy(level, subpixelAA);
|
||||
this.mcaaStrategy = new MCAAStrategy(level, subpixelAA);
|
||||
this.ecaaStrategy = new ECAAStrategy(level, subpixelAA);
|
||||
}
|
||||
|
||||
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)]
|
||||
#[repr(u8)]
|
||||
pub enum AntialiasingMode {
|
||||
|
|
|
@ -18,14 +18,14 @@ use std::ops::Range;
|
|||
use std::u32;
|
||||
|
||||
use normal;
|
||||
use {BQuad, BVertexLoopBlinnData};
|
||||
use {BQuad, BQuadVertexPositions, BVertexLoopBlinnData};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct MeshLibrary {
|
||||
pub path_ranges: Vec<PathRanges>,
|
||||
pub b_quads: Vec<BQuad>,
|
||||
// FIXME(pcwalton): Merge with `b_vertex_positions` below.
|
||||
pub b_quad_vertex_positions: Vec<Point2D<f32>>,
|
||||
pub b_quad_vertex_positions: Vec<BQuadVertexPositions>,
|
||||
pub b_vertex_positions: Vec<Point2D<f32>>,
|
||||
pub b_vertex_loop_blinn_data: Vec<BVertexLoopBlinnData>,
|
||||
pub b_vertex_normals: Vec<f32>,
|
||||
|
@ -94,12 +94,11 @@ impl MeshLibrary {
|
|||
let lower_right_position =
|
||||
&self.b_vertex_positions[b_quad.lower_right_vertex_index as usize];
|
||||
|
||||
self.b_quad_vertex_positions.extend_from_slice(&[
|
||||
*upper_left_position,
|
||||
*upper_right_position,
|
||||
*lower_left_position,
|
||||
*lower_right_position,
|
||||
]);
|
||||
let mut b_quad_vertex_positions = BQuadVertexPositions {
|
||||
upper_endpoint_positions: [*upper_left_position, *upper_right_position],
|
||||
lower_endpoint_positions: [*lower_left_position, *lower_right_position],
|
||||
control_point_positions: [Point2D::zero(), Point2D::zero()],
|
||||
};
|
||||
|
||||
let upper_left_bounding_box_position =
|
||||
Point2D::new(upper_left_position.x,
|
||||
|
@ -114,7 +113,6 @@ impl MeshLibrary {
|
|||
});
|
||||
|
||||
if b_quad.upper_control_point_vertex_index == u32::MAX {
|
||||
self.b_quad_vertex_positions.push(Point2D::zero());
|
||||
self.edge_data.upper_line_vertex_positions.push(EdgeLineVertexPositions {
|
||||
left: *upper_left_position,
|
||||
right: *upper_right_position,
|
||||
|
@ -122,7 +120,7 @@ impl MeshLibrary {
|
|||
} else {
|
||||
let upper_control_point_position =
|
||||
&self.b_vertex_positions[b_quad.upper_control_point_vertex_index as usize];
|
||||
self.b_quad_vertex_positions.push(*upper_control_point_position);
|
||||
b_quad_vertex_positions.control_point_positions[0] = *upper_control_point_position;
|
||||
self.edge_data.upper_curve_vertex_positions.push(EdgeCurveVertexPositions {
|
||||
left: *upper_left_position,
|
||||
control_point: *upper_control_point_position,
|
||||
|
@ -131,7 +129,6 @@ impl MeshLibrary {
|
|||
}
|
||||
|
||||
if b_quad.lower_control_point_vertex_index == u32::MAX {
|
||||
self.b_quad_vertex_positions.push(Point2D::zero());
|
||||
self.edge_data.lower_line_vertex_positions.push(EdgeLineVertexPositions {
|
||||
left: *lower_left_position,
|
||||
right: *lower_right_position,
|
||||
|
@ -139,13 +136,15 @@ impl MeshLibrary {
|
|||
} else {
|
||||
let lower_control_point_position =
|
||||
&self.b_vertex_positions[b_quad.lower_control_point_vertex_index as usize];
|
||||
self.b_quad_vertex_positions.push(*lower_control_point_position);
|
||||
b_quad_vertex_positions.control_point_positions[1] = *lower_control_point_position;
|
||||
self.edge_data.lower_curve_vertex_positions.push(EdgeCurveVertexPositions {
|
||||
left: *lower_left_position,
|
||||
control_point: *lower_control_point_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.
|
||||
|
|
|
@ -145,17 +145,23 @@ vec2 computeMCAASnappedPosition(vec2 position,
|
|||
vec4 localTransformST,
|
||||
vec4 globalTransformST,
|
||||
ivec2 framebufferSize,
|
||||
float slope) {
|
||||
float slope,
|
||||
bool snapToPixelGrid) {
|
||||
position = hintPosition(position, hints);
|
||||
position = transformVertexPositionST(position, localTransformST);
|
||||
position = transformVertexPositionST(position, globalTransformST);
|
||||
position = convertClipToScreenSpace(position, framebufferSize);
|
||||
|
||||
float xNudge = fract(position.x);
|
||||
if (xNudge < 0.5)
|
||||
xNudge = -xNudge;
|
||||
else
|
||||
xNudge = 1.0 - xNudge;
|
||||
float xNudge;
|
||||
if (snapToPixelGrid) {
|
||||
xNudge = fract(position.x);
|
||||
if (xNudge < 0.5)
|
||||
xNudge = -xNudge;
|
||||
else
|
||||
xNudge = 1.0 - xNudge;
|
||||
} else {
|
||||
xNudge = 0.0;
|
||||
}
|
||||
|
||||
return position + vec2(xNudge, xNudge * slope);
|
||||
}
|
||||
|
|
|
@ -28,5 +28,5 @@ varying float vSign;
|
|||
void main() {
|
||||
float side = vTexCoord.x * vTexCoord.x - vTexCoord.y;
|
||||
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.
|
||||
//
|
|
@ -16,10 +16,10 @@
|
|||
//! Use this shader only when *all* of the following are true:
|
||||
//!
|
||||
//! 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.
|
||||
//! (Otherwise, consider the MCAA shaders.)
|
||||
//! (Otherwise, consider MCAA.)
|
||||
//!
|
||||
//! 3. Your transform is only a scale and/or translation, not a perspective,
|
||||
//! 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.
|
||||
//
|
|
@ -17,10 +17,10 @@
|
|||
//! 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`.)
|
||||
//! consider MCAA.)
|
||||
//!
|
||||
//! 2. The paths are relatively small, so overdraw is not a concern.
|
||||
//! (Otherwise, consider the MCAA shaders.)
|
||||
//! (Otherwise, consider MCAA.)
|
||||
|
||||
precision highp float;
|
||||
|
||||
|
|
|
@ -20,10 +20,10 @@
|
|||
//! Use this shader only when *all* of the following are true:
|
||||
//!
|
||||
//! 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.
|
||||
//! (Otherwise, consider the MCAA shaders.)
|
||||
//! (Otherwise, consider MCAA.)
|
||||
//!
|
||||
//! 3. Your transform contains perspective, rotation, or skew. (Otherwise,
|
||||
//! 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.
|
||||
//
|
||||
|
@ -69,5 +69,5 @@ void main() {
|
|||
1.0);
|
||||
|
||||
// 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));
|
||||
|
||||
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