Fix rotation artefacts by rendering curves in two passes, clipping at X
inflection points as necessary.
This commit is contained in:
parent
801c25305f
commit
9b59ce2443
|
@ -23,6 +23,7 @@ export interface ShaderMap<T> {
|
|||
direct3DInterior: T;
|
||||
ecaaLine: T;
|
||||
ecaaCurve: T;
|
||||
ecaaTransformedCurve: T;
|
||||
mcaaCover: T;
|
||||
mcaaLine: T;
|
||||
mcaaCurve: T;
|
||||
|
@ -32,6 +33,7 @@ export interface ShaderMap<T> {
|
|||
xcaaMultiDirectCurve: T;
|
||||
xcaaMultiDirectInterior: T;
|
||||
xcaaMultiEdgeMaskCurve: T;
|
||||
xcaaMultiEdgeMaskTransformedCurve: T;
|
||||
xcaaMultiEdgeMaskLine: T;
|
||||
xcaaMultiResolve: T;
|
||||
}
|
||||
|
@ -57,11 +59,13 @@ export const SHADER_NAMES: Array<keyof ShaderMap<void>> = [
|
|||
'mcaaCurve',
|
||||
'ecaaLine',
|
||||
'ecaaCurve',
|
||||
'ecaaTransformedCurve',
|
||||
'xcaaMonoResolve',
|
||||
'xcaaMonoSubpixelResolve',
|
||||
'xcaaMultiDirectCurve',
|
||||
'xcaaMultiDirectInterior',
|
||||
'xcaaMultiEdgeMaskCurve',
|
||||
'xcaaMultiEdgeMaskTransformedCurve',
|
||||
'xcaaMultiEdgeMaskLine',
|
||||
'xcaaMultiResolve',
|
||||
'demo3DDistantGlyph',
|
||||
|
@ -113,6 +117,10 @@ const SHADER_URLS: ShaderMap<ShaderProgramURLs> = {
|
|||
fragment: "/glsl/gles2/xcaa-line.fs.glsl",
|
||||
vertex: "/glsl/gles2/ecaa-line.vs.glsl",
|
||||
},
|
||||
ecaaTransformedCurve: {
|
||||
fragment: "/glsl/gles2/xcaa-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",
|
||||
|
@ -153,6 +161,10 @@ const SHADER_URLS: ShaderMap<ShaderProgramURLs> = {
|
|||
fragment: "/glsl/gles2/xcaa-multi-edge-mask-line.fs.glsl",
|
||||
vertex: "/glsl/gles2/ecaa-multi-edge-mask-line.vs.glsl",
|
||||
},
|
||||
xcaaMultiEdgeMaskTransformedCurve: {
|
||||
fragment: "/glsl/gles2/xcaa-multi-edge-mask-curve.fs.glsl",
|
||||
vertex: "/glsl/gles2/ecaa-multi-edge-mask-transformed-curve.vs.glsl",
|
||||
},
|
||||
xcaaMultiResolve: {
|
||||
fragment: "/glsl/gles2/xcaa-multi-resolve.fs.glsl",
|
||||
vertex: "/glsl/gles2/xcaa-multi-resolve.vs.glsl",
|
||||
|
|
|
@ -781,9 +781,10 @@ export abstract class ECAAStrategy extends XCAAStrategy {
|
|||
this.antialiasLinesOfObjectWithProgram(renderer,
|
||||
objectIndex,
|
||||
this.lineShaderProgramNames[0]);
|
||||
this.antialiasCurvesOfObjectWithProgram(renderer,
|
||||
this.antialiasCurvesOfObjectWithPrograms(renderer,
|
||||
objectIndex,
|
||||
this.curveShaderProgramNames[0]);
|
||||
this.curveShaderProgramNames[0],
|
||||
this.curveShaderProgramNames[1]);
|
||||
}
|
||||
|
||||
protected setAAUniforms(renderer: Renderer, uniforms: UniformMap, objectIndex: number): void {
|
||||
|
@ -850,9 +851,24 @@ export abstract class ECAAStrategy extends XCAAStrategy {
|
|||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(null);
|
||||
}
|
||||
|
||||
protected antialiasCurvesOfObjectWithProgram(renderer: Renderer,
|
||||
protected antialiasCurvesOfObjectWithPrograms(renderer: Renderer,
|
||||
objectIndex: number,
|
||||
programName: keyof ShaderMap<void>):
|
||||
stProgram: keyof ShaderMap<void>,
|
||||
transformedProgram: keyof ShaderMap<void>):
|
||||
void {
|
||||
if (renderer.usesSTTransform) {
|
||||
this.antialiasCurvesOfObjectWithProgram(renderer, objectIndex, stProgram, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
this.antialiasCurvesOfObjectWithProgram(renderer, objectIndex, transformedProgram, 0);
|
||||
this.antialiasCurvesOfObjectWithProgram(renderer, objectIndex, transformedProgram, 1);
|
||||
}
|
||||
|
||||
private antialiasCurvesOfObjectWithProgram(renderer: Renderer,
|
||||
objectIndex: number,
|
||||
programName: keyof ShaderMap<void>,
|
||||
passIndex: number):
|
||||
void {
|
||||
if (renderer.meshData == null)
|
||||
return;
|
||||
|
@ -867,6 +883,7 @@ export abstract class ECAAStrategy extends XCAAStrategy {
|
|||
gl.useProgram(curveProgram.program);
|
||||
const uniforms = curveProgram.uniforms;
|
||||
this.setAAUniforms(renderer, uniforms, objectIndex);
|
||||
gl.uniform1i(uniforms.uPassIndex, passIndex);
|
||||
|
||||
const vao = this.curveVAOs[programName];
|
||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(vao);
|
||||
|
@ -1061,7 +1078,7 @@ export class ECAAMonochromeStrategy extends ECAAStrategy {
|
|||
}
|
||||
|
||||
protected get curveShaderProgramNames(): Array<keyof ShaderMap<void>> {
|
||||
return ['ecaaCurve'];
|
||||
return ['ecaaCurve', 'ecaaTransformedCurve'];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1188,7 +1205,12 @@ export class ECAAMulticolorStrategy extends ECAAStrategy {
|
|||
}
|
||||
|
||||
protected get curveShaderProgramNames(): Array<keyof ShaderMap<void>> {
|
||||
return ['ecaaCurve', 'xcaaMultiEdgeMaskCurve'];
|
||||
return [
|
||||
'ecaaCurve',
|
||||
'ecaaTransformedCurve',
|
||||
'xcaaMultiEdgeMaskCurve',
|
||||
'xcaaMultiEdgeMaskTransformedCurve',
|
||||
];
|
||||
}
|
||||
|
||||
private edgeMaskVAO: WebGLVertexArrayObject;
|
||||
|
@ -1233,7 +1255,10 @@ export class ECAAMulticolorStrategy extends ECAAStrategy {
|
|||
// Perform edge masking.
|
||||
gl.colorMask(false, false, false, false);
|
||||
this.antialiasLinesOfObjectWithProgram(renderer, objectIndex, 'xcaaMultiEdgeMaskLine');
|
||||
this.antialiasCurvesOfObjectWithProgram(renderer, objectIndex, 'xcaaMultiEdgeMaskCurve');
|
||||
this.antialiasCurvesOfObjectWithPrograms(renderer,
|
||||
objectIndex,
|
||||
'xcaaMultiEdgeMaskCurve',
|
||||
'xcaaMultiEdgeMaskTransformedCurve');
|
||||
|
||||
gl.colorMask(true, true, true, true);
|
||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(null);
|
||||
|
|
|
@ -126,17 +126,6 @@ vec2 computeXCAAClipSpaceQuadPosition(vec4 extents, vec2 quadPosition, ivec2 fra
|
|||
return convertScreenToClipSpace(position, framebufferSize);
|
||||
}
|
||||
|
||||
vec2 computeXCAAEdgeBoundedClipSpaceQuadPosition(vec2 leftPosition,
|
||||
vec2 rightPosition,
|
||||
vec2 quadPosition,
|
||||
ivec2 framebufferSize) {
|
||||
vec4 extents = vec4(leftPosition.x,
|
||||
min(leftPosition.y, rightPosition.y),
|
||||
rightPosition.x,
|
||||
max(leftPosition.y, rightPosition.y));
|
||||
return computeXCAAClipSpaceQuadPosition(extents, quadPosition, framebufferSize);
|
||||
}
|
||||
|
||||
vec2 computeMCAAPosition(vec2 position,
|
||||
vec4 hints,
|
||||
vec4 localTransformST,
|
||||
|
@ -172,10 +161,11 @@ bool computeMCAAQuadPosition(out vec2 outPosition,
|
|||
return false;
|
||||
}
|
||||
|
||||
outPosition = computeXCAAEdgeBoundedClipSpaceQuadPosition(leftPosition,
|
||||
rightPosition,
|
||||
quadPosition,
|
||||
framebufferSize);
|
||||
vec4 extents = vec4(leftPosition.x,
|
||||
min(leftPosition.y, rightPosition.y),
|
||||
rightPosition.x,
|
||||
max(leftPosition.y, rightPosition.y));
|
||||
outPosition = computeXCAAClipSpaceQuadPosition(extents, quadPosition, framebufferSize);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -228,6 +218,31 @@ float computeECAAWinding(inout vec2 leftPosition, inout vec2 rightPosition) {
|
|||
return rightPosition.x - leftPosition.x > EPSILON ? winding : 0.0;
|
||||
}
|
||||
|
||||
vec2 computeECAAQuadPositionFromTransformedPositions(vec2 leftPosition,
|
||||
vec2 rightPosition,
|
||||
vec2 quadPosition,
|
||||
ivec2 framebufferSize,
|
||||
vec4 localTransformST,
|
||||
vec2 localTransformExt,
|
||||
mat4 globalTransform,
|
||||
vec4 bounds,
|
||||
vec3 leftTopRightEdges) {
|
||||
vec2 edgeBL = bounds.xy, edgeTL = bounds.xw, edgeTR = bounds.zw, edgeBR = bounds.zy;
|
||||
edgeBL = transformECAAPosition(edgeBL, localTransformST, localTransformExt, globalTransform);
|
||||
edgeBR = transformECAAPosition(edgeBR, localTransformST, localTransformExt, globalTransform);
|
||||
edgeTL = transformECAAPosition(edgeTL, localTransformST, localTransformExt, globalTransform);
|
||||
edgeTR = transformECAAPosition(edgeTR, localTransformST, localTransformExt, globalTransform);
|
||||
|
||||
// Find the bottom of the path, and convert to clip space.
|
||||
//
|
||||
// FIXME(pcwalton): Speed this up somehow?
|
||||
float pathBottomY = max(max(edgeBL.y, edgeBR.y), max(edgeTL.y, edgeTR.y));
|
||||
pathBottomY = (pathBottomY + 1.0) * 0.5 * float(framebufferSize.y);
|
||||
|
||||
vec4 extents = vec4(leftTopRightEdges, pathBottomY);
|
||||
return computeXCAAClipSpaceQuadPosition(extents, quadPosition, framebufferSize);
|
||||
}
|
||||
|
||||
// FIXME(pcwalton): Clean up this signature somehow?
|
||||
bool computeECAAQuadPosition(out vec2 outPosition,
|
||||
out float outWinding,
|
||||
|
@ -259,12 +274,6 @@ bool computeECAAQuadPosition(out vec2 outPosition,
|
|||
globalTransform,
|
||||
framebufferSize);
|
||||
|
||||
vec2 edgeBL = bounds.xy, edgeTL = bounds.xw, edgeTR = bounds.zw, edgeBR = bounds.zy;
|
||||
edgeBL = transformECAAPosition(edgeBL, localTransformST, localTransformExt, globalTransform);
|
||||
edgeBR = transformECAAPosition(edgeBR, localTransformST, localTransformExt, globalTransform);
|
||||
edgeTL = transformECAAPosition(edgeTL, localTransformST, localTransformExt, globalTransform);
|
||||
edgeTR = transformECAAPosition(edgeTR, localTransformST, localTransformExt, globalTransform);
|
||||
|
||||
float winding = computeECAAWinding(leftPosition, rightPosition);
|
||||
outWinding = winding;
|
||||
if (winding == 0.0) {
|
||||
|
@ -272,49 +281,54 @@ bool computeECAAQuadPosition(out vec2 outPosition,
|
|||
return false;
|
||||
}
|
||||
|
||||
// Find the bottom of the path, and convert to clip space.
|
||||
//
|
||||
// FIXME(pcwalton): Speed this up somehow?
|
||||
float pathBottomY = max(max(edgeBL.y, edgeBR.y), max(edgeTL.y, edgeTR.y));
|
||||
pathBottomY = (pathBottomY + 1.0) * 0.5 * float(framebufferSize.y);
|
||||
|
||||
vec4 extents = vec4(leftPosition.x,
|
||||
vec3 leftTopRightEdges = vec3(leftPosition.x,
|
||||
min(leftPosition.y, rightPosition.y),
|
||||
rightPosition.x,
|
||||
pathBottomY);
|
||||
outPosition = computeXCAAClipSpaceQuadPosition(extents, quadPosition, framebufferSize);
|
||||
rightPosition.x);
|
||||
outPosition = computeECAAQuadPositionFromTransformedPositions(leftPosition,
|
||||
rightPosition,
|
||||
quadPosition,
|
||||
framebufferSize,
|
||||
localTransformST,
|
||||
localTransformExt,
|
||||
globalTransform,
|
||||
bounds,
|
||||
leftTopRightEdges);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool computeECAAMultiEdgeMaskQuadPosition(out vec2 outPosition,
|
||||
bool splitCurveAndComputeECAAWinding(out float outWinding,
|
||||
out vec3 outLeftTopRightEdges,
|
||||
inout vec2 leftPosition,
|
||||
inout vec2 rightPosition,
|
||||
vec2 quadPosition,
|
||||
ivec2 framebufferSize,
|
||||
vec4 localTransformST,
|
||||
vec2 localTransformExt,
|
||||
mat4 globalTransform) {
|
||||
leftPosition = transformECAAPositionToScreenSpace(leftPosition,
|
||||
localTransformST,
|
||||
localTransformExt,
|
||||
globalTransform,
|
||||
framebufferSize);
|
||||
rightPosition = transformECAAPositionToScreenSpace(rightPosition,
|
||||
localTransformST,
|
||||
localTransformExt,
|
||||
globalTransform,
|
||||
framebufferSize);
|
||||
|
||||
float winding = computeECAAWinding(leftPosition, rightPosition);
|
||||
if (winding == 0.0) {
|
||||
outPosition = vec2(0.0);
|
||||
vec2 controlPointPosition,
|
||||
int passIndex) {
|
||||
// Split at the X inflection point if necessary.
|
||||
float num = leftPosition.x - controlPointPosition.x;
|
||||
float denom = leftPosition.x - 2.0 * controlPointPosition.x + rightPosition.x;
|
||||
float inflectionT = num / denom;
|
||||
if (inflectionT > EPSILON && inflectionT < 1.0 - EPSILON) {
|
||||
vec2 newCP0 = mix(leftPosition, controlPointPosition, inflectionT);
|
||||
vec2 newCP1 = mix(controlPointPosition, rightPosition, inflectionT);
|
||||
vec2 inflectionPoint = mix(newCP0, newCP1, inflectionT);
|
||||
if (passIndex == 0) {
|
||||
controlPointPosition = newCP0;
|
||||
rightPosition = inflectionPoint;
|
||||
} else {
|
||||
controlPointPosition = newCP1;
|
||||
leftPosition = inflectionPoint;
|
||||
}
|
||||
} else if (passIndex != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
outPosition = computeXCAAEdgeBoundedClipSpaceQuadPosition(leftPosition,
|
||||
rightPosition,
|
||||
quadPosition,
|
||||
framebufferSize);
|
||||
float winding = computeECAAWinding(leftPosition, rightPosition);
|
||||
outWinding = winding;
|
||||
if (winding == 0.0)
|
||||
return false;
|
||||
|
||||
outLeftTopRightEdges = vec3(min(leftPosition.x, controlPointPosition.x),
|
||||
min(min(leftPosition.y, controlPointPosition.y), rightPosition.y),
|
||||
max(rightPosition.x, controlPointPosition.x));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ uniform ivec2 uPathTransformSTDimensions;
|
|||
uniform sampler2D uPathTransformST;
|
||||
uniform ivec2 uPathTransformExtDimensions;
|
||||
uniform sampler2D uPathTransformExt;
|
||||
uniform int uPassIndex;
|
||||
|
||||
attribute vec2 aQuadPosition;
|
||||
attribute vec2 aLeftPosition;
|
||||
|
@ -40,23 +41,35 @@ void main() {
|
|||
uPathTransformExtDimensions,
|
||||
pathID);
|
||||
|
||||
// Transform the points, and compute the position of this vertex.
|
||||
vec2 position;
|
||||
if (computeECAAMultiEdgeMaskQuadPosition(position,
|
||||
leftPosition,
|
||||
rightPosition,
|
||||
aQuadPosition,
|
||||
uFramebufferSize,
|
||||
// Transform the points.
|
||||
leftPosition = transformECAAPositionToScreenSpace(leftPosition,
|
||||
pathTransformST,
|
||||
pathTransformExt,
|
||||
uTransform)) {
|
||||
uTransform,
|
||||
uFramebufferSize);
|
||||
rightPosition = transformECAAPositionToScreenSpace(rightPosition,
|
||||
pathTransformST,
|
||||
pathTransformExt,
|
||||
uTransform,
|
||||
uFramebufferSize);
|
||||
controlPointPosition = transformECAAPositionToScreenSpace(controlPointPosition,
|
||||
pathTransformST,
|
||||
pathTransformExt,
|
||||
uTransform,
|
||||
uFramebufferSize);
|
||||
|
||||
float winding = computeECAAWinding(leftPosition, rightPosition);
|
||||
if (winding == 0.0) {
|
||||
gl_Position = vec4(0.0);
|
||||
return;
|
||||
}
|
||||
|
||||
vec4 extents = vec4(leftPosition.x,
|
||||
min(leftPosition.y, rightPosition.y),
|
||||
rightPosition.y,
|
||||
max(leftPosition.y, rightPosition.y));
|
||||
vec2 position = computeXCAAClipSpaceQuadPosition(extents, aQuadPosition, uFramebufferSize);
|
||||
|
||||
float depth = convertPathIndexToViewportDepthValue(pathID);
|
||||
|
||||
gl_Position = vec4(position, depth, 1.0);
|
||||
|
|
|
@ -38,16 +38,29 @@ void main() {
|
|||
uPathTransformExtDimensions,
|
||||
pathID);
|
||||
|
||||
// Transform the points, and compute the position of this vertex.
|
||||
vec2 position;
|
||||
computeECAAMultiEdgeMaskQuadPosition(position,
|
||||
leftPosition,
|
||||
rightPosition,
|
||||
aQuadPosition,
|
||||
uFramebufferSize,
|
||||
// Transform the points.
|
||||
leftPosition = transformECAAPositionToScreenSpace(leftPosition,
|
||||
pathTransformST,
|
||||
pathTransformExt,
|
||||
uTransform);
|
||||
uTransform,
|
||||
uFramebufferSize);
|
||||
rightPosition = transformECAAPositionToScreenSpace(rightPosition,
|
||||
pathTransformST,
|
||||
pathTransformExt,
|
||||
uTransform,
|
||||
uFramebufferSize);
|
||||
|
||||
float winding = computeECAAWinding(leftPosition, rightPosition);
|
||||
if (winding == 0.0) {
|
||||
gl_Position = vec4(0.0);
|
||||
return;
|
||||
}
|
||||
|
||||
vec4 extents = vec4(min(leftPosition.x, rightPosition.x),
|
||||
min(leftPosition.y, rightPosition.y),
|
||||
max(rightPosition.x, rightPosition.x),
|
||||
max(leftPosition.y, rightPosition.y));
|
||||
vec2 position = computeXCAAClipSpaceQuadPosition(extents, aQuadPosition, uFramebufferSize);
|
||||
|
||||
float depth = convertPathIndexToViewportDepthValue(pathID);
|
||||
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
// pathfinder/shaders/gles2/ecaa-multi-edge-mask-transformed-curve.vs.glsl
|
||||
//
|
||||
// Copyright (c) 2017 The Pathfinder Project Developers.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
precision highp float;
|
||||
|
||||
uniform mat4 uTransform;
|
||||
uniform ivec2 uFramebufferSize;
|
||||
uniform ivec2 uPathTransformSTDimensions;
|
||||
uniform sampler2D uPathTransformST;
|
||||
uniform ivec2 uPathTransformExtDimensions;
|
||||
uniform sampler2D uPathTransformExt;
|
||||
uniform int uPassIndex;
|
||||
|
||||
attribute vec2 aQuadPosition;
|
||||
attribute vec2 aLeftPosition;
|
||||
attribute vec2 aControlPointPosition;
|
||||
attribute vec2 aRightPosition;
|
||||
attribute float aPathID;
|
||||
|
||||
varying vec4 vEndpoints;
|
||||
varying vec2 vControlPoint;
|
||||
|
||||
void main() {
|
||||
vec2 leftPosition = aLeftPosition;
|
||||
vec2 controlPointPosition = aControlPointPosition;
|
||||
vec2 rightPosition = aRightPosition;
|
||||
int pathID = int(aPathID);
|
||||
|
||||
vec2 pathTransformExt;
|
||||
vec4 pathTransformST = fetchPathAffineTransform(pathTransformExt,
|
||||
uPathTransformST,
|
||||
uPathTransformSTDimensions,
|
||||
uPathTransformExt,
|
||||
uPathTransformExtDimensions,
|
||||
pathID);
|
||||
|
||||
// Transform the points.
|
||||
leftPosition = transformECAAPositionToScreenSpace(leftPosition,
|
||||
pathTransformST,
|
||||
pathTransformExt,
|
||||
uTransform,
|
||||
uFramebufferSize);
|
||||
rightPosition = transformECAAPositionToScreenSpace(rightPosition,
|
||||
pathTransformST,
|
||||
pathTransformExt,
|
||||
uTransform,
|
||||
uFramebufferSize);
|
||||
controlPointPosition = transformECAAPositionToScreenSpace(controlPointPosition,
|
||||
pathTransformST,
|
||||
pathTransformExt,
|
||||
uTransform,
|
||||
uFramebufferSize);
|
||||
|
||||
float winding;
|
||||
vec3 leftTopRightEdges;
|
||||
if (!splitCurveAndComputeECAAWinding(winding,
|
||||
leftTopRightEdges,
|
||||
leftPosition,
|
||||
rightPosition,
|
||||
controlPointPosition,
|
||||
uPassIndex)) {
|
||||
gl_Position = vec4(0.0);
|
||||
return;
|
||||
}
|
||||
|
||||
vec4 extents = vec4(leftTopRightEdges,
|
||||
max(max(leftPosition.y, rightPosition.y), controlPointPosition.y));
|
||||
vec2 position = computeXCAAClipSpaceQuadPosition(extents, aQuadPosition, uFramebufferSize);
|
||||
|
||||
float depth = convertPathIndexToViewportDepthValue(pathID);
|
||||
|
||||
gl_Position = vec4(position, depth, 1.0);
|
||||
vEndpoints = vec4(leftPosition, rightPosition);
|
||||
vControlPoint = controlPointPosition;
|
||||
}
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
// pathfinder/shaders/gles2/ecaa-transformed-curve.vs.glsl
|
||||
//
|
||||
// Copyright (c) 2017 The Pathfinder Project Developers.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
precision highp float;
|
||||
|
||||
uniform mat4 uTransform;
|
||||
uniform vec4 uHints;
|
||||
uniform ivec2 uFramebufferSize;
|
||||
uniform ivec2 uPathTransformSTDimensions;
|
||||
uniform sampler2D uPathTransformST;
|
||||
uniform ivec2 uPathTransformExtDimensions;
|
||||
uniform sampler2D uPathTransformExt;
|
||||
uniform ivec2 uPathBoundsDimensions;
|
||||
uniform sampler2D uPathBounds;
|
||||
uniform vec2 uEmboldenAmount;
|
||||
uniform int uPassIndex;
|
||||
|
||||
attribute vec2 aQuadPosition;
|
||||
attribute vec2 aLeftPosition;
|
||||
attribute vec2 aControlPointPosition;
|
||||
attribute vec2 aRightPosition;
|
||||
attribute float aPathID;
|
||||
attribute vec3 aNormalAngles;
|
||||
|
||||
varying vec4 vEndpoints;
|
||||
varying vec2 vControlPoint;
|
||||
varying float vWinding;
|
||||
|
||||
void main() {
|
||||
vec2 leftPosition = aLeftPosition;
|
||||
vec2 controlPointPosition = aControlPointPosition;
|
||||
vec2 rightPosition = aRightPosition;
|
||||
int pathID = int(aPathID);
|
||||
|
||||
vec2 pathTransformExt;
|
||||
vec4 pathTransformST = fetchPathAffineTransform(pathTransformExt,
|
||||
uPathTransformST,
|
||||
uPathTransformSTDimensions,
|
||||
uPathTransformExt,
|
||||
uPathTransformExtDimensions,
|
||||
pathID);
|
||||
vec4 bounds = fetchFloat4Data(uPathBounds, pathID, uPathBoundsDimensions);
|
||||
|
||||
// Transform the points.
|
||||
leftPosition = computeECAAPosition(leftPosition,
|
||||
aNormalAngles.x,
|
||||
uEmboldenAmount,
|
||||
uHints,
|
||||
pathTransformST,
|
||||
pathTransformExt,
|
||||
uTransform,
|
||||
uFramebufferSize);
|
||||
rightPosition = computeECAAPosition(rightPosition,
|
||||
aNormalAngles.z,
|
||||
uEmboldenAmount,
|
||||
uHints,
|
||||
pathTransformST,
|
||||
pathTransformExt,
|
||||
uTransform,
|
||||
uFramebufferSize);
|
||||
controlPointPosition = computeECAAPosition(controlPointPosition,
|
||||
aNormalAngles.y,
|
||||
uEmboldenAmount,
|
||||
uHints,
|
||||
pathTransformST,
|
||||
pathTransformExt,
|
||||
uTransform,
|
||||
uFramebufferSize);
|
||||
|
||||
float winding;
|
||||
vec3 leftTopRightEdges;
|
||||
if (!splitCurveAndComputeECAAWinding(winding,
|
||||
leftTopRightEdges,
|
||||
leftPosition,
|
||||
rightPosition,
|
||||
controlPointPosition,
|
||||
uPassIndex)) {
|
||||
gl_Position = vec4(0.0);
|
||||
return;
|
||||
}
|
||||
|
||||
vec2 position = computeECAAQuadPositionFromTransformedPositions(leftPosition,
|
||||
rightPosition,
|
||||
aQuadPosition,
|
||||
uFramebufferSize,
|
||||
pathTransformST,
|
||||
pathTransformExt,
|
||||
uTransform,
|
||||
bounds,
|
||||
leftTopRightEdges);
|
||||
|
||||
float depth = convertPathIndexToViewportDepthValue(pathID);
|
||||
|
||||
gl_Position = vec4(position, depth, 1.0);
|
||||
vEndpoints = vec4(leftPosition, rightPosition);
|
||||
vControlPoint = controlPointPosition;
|
||||
vWinding = winding;
|
||||
}
|
Loading…
Reference in New Issue