Upgrade ST-transforms to affine transforms where possible, and add

incomplete rotation support to the text demo
This commit is contained in:
Patrick Walton 2017-11-29 10:50:47 -08:00
parent 58260beb8c
commit 86660572bd
25 changed files with 304 additions and 124 deletions

View File

@ -0,0 +1,18 @@
<div id="pf-rotate-slider-container">
<div id="pf-rotate-slider-card" class="card mb-4 pf-invisible">
<div class="card-body">
<form class="d-inline mr-3">
<input id="pf-rotate-slider" type="range" min="-3.14159" max="3.14159"
step="0.006136" value="0.0" autocomplete="off">
</form>
<button id="pf-rotate-close-button" type="button" class="close" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="pf-arrow-box"></div>
</div>
</div>
<button id="pf-rotate-button" type="button" title="Rotate"
class="btn btn-outline-secondary pf-toolbar-button">
<span class="pf-material-icons">rotate_left</span>
</button>

View File

@ -24,25 +24,7 @@
<span class="pf-material-icons">add</span> <span class="pf-material-icons">add</span>
</button> </button>
</div> </div>
<div id="pf-rotate-slider-container"> {{>partials/rotate.html}}
<div id="pf-rotate-slider-card" class="card mb-4 pf-invisible">
<div class="card-body">
<form class="d-inline mr-3">
<input id="pf-rotate-slider" type="range" min="-3.14159"
max="3.14159" step="0.006136" value="0.0" autocomplete="off">
</form>
<button id="pf-rotate-close-button" type="button" class="close"
aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="pf-arrow-box"></div>
</div>
</div>
<button id="pf-rotate-button" type="button" title="Rotate"
class="btn btn-outline-secondary pf-toolbar-button">
<span class="pf-material-icons">rotate_left</span>
</button>
<button id="pf-zoom-pulse-button" type="button" title="Pulse Zoom" <button id="pf-zoom-pulse-button" type="button" title="Pulse Zoom"
class="btn btn-outline-secondary pf-toolbar-button"> class="btn btn-outline-secondary pf-toolbar-button">
<span class="pf-material-icons">play_arrow</span> <span class="pf-material-icons">play_arrow</span>

View File

@ -23,6 +23,7 @@
<span class="pf-material-icons">add</span> <span class="pf-material-icons">add</span>
</button> </button>
</div> </div>
{{>partials/rotate.html}}
<button id="pf-zoom-pulse-button" type="button" title="Pulse Zoom" <button id="pf-zoom-pulse-button" type="button" title="Pulse Zoom"
class="btn btn-outline-secondary pf-toolbar-button"> class="btn btn-outline-secondary pf-toolbar-button">
<span class="pf-material-icons">play_arrow</span> <span class="pf-material-icons">play_arrow</span>

View File

@ -21,7 +21,7 @@ import PathfinderBufferTexture from "./buffer-texture";
import {CameraView, PerspectiveCamera} from "./camera"; import {CameraView, PerspectiveCamera} from "./camera";
import {UniformMap} from './gl-utils'; import {UniformMap} from './gl-utils';
import {PathfinderMeshData} from "./meshes"; import {PathfinderMeshData} from "./meshes";
import {Renderer} from './renderer'; import {PathTransformBuffers, Renderer} from './renderer';
import {ShaderMap, ShaderProgramSource} from "./shader-loader"; import {ShaderMap, ShaderProgramSource} from "./shader-loader";
import SSAAStrategy from "./ssaa-strategy"; import SSAAStrategy from "./ssaa-strategy";
import {BUILTIN_FONT_URI, ExpandedMeshData} from "./text"; import {BUILTIN_FONT_URI, ExpandedMeshData} from "./text";
@ -480,13 +480,13 @@ class ThreeDRenderer extends Renderer {
return TEXT_COLOR; return TEXT_COLOR;
} }
protected pathTransformsForObject(objectIndex: number): Float32Array { protected pathTransformsForObject(objectIndex: number): PathTransformBuffers<Float32Array> {
const meshDescriptor = this.renderContext.appController.meshDescriptors[objectIndex]; const meshDescriptor = this.renderContext.appController.meshDescriptors[objectIndex];
const pathCount = this.pathCountForObject(objectIndex); const pathCount = this.pathCountForObject(objectIndex);
const pathTransforms = new Float32Array(4 * (pathCount + 1)); const pathTransforms = this.createPathTransformBuffers(pathCount);
for (let pathIndex = 0; pathIndex < pathCount; pathIndex++) { for (let pathIndex = 0; pathIndex < pathCount; pathIndex++) {
const glyphOrigin = meshDescriptor.positions[pathIndex]; const glyphOrigin = meshDescriptor.positions[pathIndex];
pathTransforms.set([1, 1, glyphOrigin[0], glyphOrigin[1]], (pathIndex + 1) * 4); pathTransforms.st.set([1, 1, glyphOrigin[0], glyphOrigin[1]], (pathIndex + 1) * 4);
} }
return pathTransforms; return pathTransforms;
} }

View File

@ -19,7 +19,7 @@ import PathfinderBufferTexture from './buffer-texture';
import {OrthographicCamera} from './camera'; import {OrthographicCamera} from './camera';
import {UniformMap} from './gl-utils'; import {UniformMap} from './gl-utils';
import {PathfinderMeshData} from "./meshes"; import {PathfinderMeshData} from "./meshes";
import {Renderer} from './renderer'; import {PathTransformBuffers, Renderer} from './renderer';
import {ShaderMap, ShaderProgramSource} from "./shader-loader"; import {ShaderMap, ShaderProgramSource} from "./shader-loader";
import SSAAStrategy from './ssaa-strategy'; import SSAAStrategy from './ssaa-strategy';
import {BUILTIN_FONT_URI, ExpandedMeshData, GlyphStore, PathfinderFont, TextFrame} from "./text"; import {BUILTIN_FONT_URI, ExpandedMeshData, GlyphStore, PathfinderFont, TextFrame} from "./text";
@ -415,12 +415,12 @@ class BenchmarkRenderer extends Renderer {
return pathColors; return pathColors;
} }
protected pathTransformsForObject(objectIndex: number): Float32Array { protected pathTransformsForObject(objectIndex: number): PathTransformBuffers<Float32Array> {
const appController = this.renderContext.appController; const appController = this.renderContext.appController;
const canvas = this.renderContext.canvas; const canvas = this.renderContext.canvas;
const font = unwrapNull(appController.font); const font = unwrapNull(appController.font);
const pathTransforms = new Float32Array(4 * (STRING.length + 1)); const pathTransforms = this.createPathTransformBuffers(STRING.length);
let currentX = 0, currentY = 0; let currentX = 0, currentY = 0;
const availableWidth = canvas.width / this.pixelsPerUnit; const availableWidth = canvas.width / this.pixelsPerUnit;
@ -428,7 +428,7 @@ class BenchmarkRenderer extends Renderer {
for (let glyphIndex = 0; glyphIndex < STRING.length; glyphIndex++) { for (let glyphIndex = 0; glyphIndex < STRING.length; glyphIndex++) {
const glyphID = unwrapNull(appController.textRun).glyphIDs[glyphIndex]; const glyphID = unwrapNull(appController.textRun).glyphIDs[glyphIndex];
pathTransforms.set([1, 1, currentX, currentY], (glyphIndex + 1) * 4); pathTransforms.st.set([1, 1, currentX, currentY], (glyphIndex + 1) * 4);
currentX += font.opentypeFont.glyphs.get(glyphID).advanceWidth; currentX += font.opentypeFont.glyphs.get(glyphID).advanceWidth;
if (currentX > availableWidth) { if (currentX > availableWidth) {

View File

@ -20,7 +20,7 @@ import {SUBPIXEL_GRANULARITY} from './atlas';
import {OrthographicCamera} from './camera'; import {OrthographicCamera} from './camera';
import {UniformMap} from './gl-utils'; import {UniformMap} from './gl-utils';
import {PathfinderMeshData} from './meshes'; import {PathfinderMeshData} from './meshes';
import {Renderer} from "./renderer"; import {PathTransformBuffers, Renderer} from "./renderer";
import {ShaderMap, ShaderProgramSource} from "./shader-loader"; import {ShaderMap, ShaderProgramSource} from "./shader-loader";
import SSAAStrategy from './ssaa-strategy'; import SSAAStrategy from './ssaa-strategy';
import {BUILTIN_FONT_URI, computeStemDarkeningAmount, ExpandedMeshData, GlyphStore} from "./text"; import {BUILTIN_FONT_URI, computeStemDarkeningAmount, ExpandedMeshData, GlyphStore} from "./text";
@ -600,13 +600,13 @@ class ReferenceTestRenderer extends Renderer {
return pathColors; return pathColors;
} }
protected pathTransformsForObject(objectIndex: number): Float32Array { protected pathTransformsForObject(objectIndex: number): PathTransformBuffers<Float32Array> {
const appController = this.renderContext.appController; const appController = this.renderContext.appController;
const canvas = this.renderContext.canvas; const canvas = this.renderContext.canvas;
const font = unwrapNull(appController.font); const font = unwrapNull(appController.font);
const hint = new Hint(font, this.pixelsPerUnit, true); const hint = new Hint(font, this.pixelsPerUnit, true);
const pathTransforms = new Float32Array(4 * 2); const pathTransforms = this.createPathTransformBuffers(1);
const textRun = unwrapNull(appController.textRun); const textRun = unwrapNull(appController.textRun);
const glyphID = textRun.glyphIDs[0]; const glyphID = textRun.glyphIDs[0];
@ -620,7 +620,7 @@ class ReferenceTestRenderer extends Renderer {
const x = -pixelRect[0] / this.pixelsPerUnit; const x = -pixelRect[0] / this.pixelsPerUnit;
const y = (canvas.height - (pixelRect[3] - pixelRect[1])) / this.pixelsPerUnit; const y = (canvas.height - (pixelRect[3] - pixelRect[1])) / this.pixelsPerUnit;
pathTransforms.set([1, 1, x, y], 1 * 4); pathTransforms.st.set([1, 1, x, y], 1 * 4);
return pathTransforms; return pathTransforms;
} }

View File

@ -31,10 +31,15 @@ const B_LOOP_BLINN_DATA_SIZE: number = 4;
const B_LOOP_BLINN_DATA_TEX_COORD_OFFSET: number = 0; const B_LOOP_BLINN_DATA_TEX_COORD_OFFSET: number = 0;
const B_LOOP_BLINN_DATA_SIGN_OFFSET: number = 2; const B_LOOP_BLINN_DATA_SIGN_OFFSET: number = 2;
export interface PathTransformBuffers<T> {
st: T;
ext: T;
}
export abstract class Renderer { export abstract class Renderer {
readonly renderContext: RenderContext; readonly renderContext: RenderContext;
readonly pathTransformBufferTextures: PathfinderBufferTexture[]; readonly pathTransformBufferTextures: Array<PathTransformBuffers<PathfinderBufferTexture>>;
meshes: PathfinderMeshBuffers[] | null; meshes: PathfinderMeshBuffers[] | null;
meshData: PathfinderMeshData[] | null; meshData: PathfinderMeshData[] | null;
@ -279,16 +284,19 @@ export abstract class Renderer {
for (let objectIndex = 0; objectIndex < objectCount; objectIndex++) { for (let objectIndex = 0; objectIndex < objectCount; objectIndex++) {
const pathTransforms = this.pathTransformsForObject(objectIndex); const pathTransforms = this.pathTransformsForObject(objectIndex);
let pathTransformBufferTexture; let pathTransformBufferTextures;
if (objectIndex >= this.pathTransformBufferTextures.length) { if (objectIndex >= this.pathTransformBufferTextures.length) {
pathTransformBufferTexture = new PathfinderBufferTexture(renderContext.gl, pathTransformBufferTextures = {
'uPathTransform'); ext: new PathfinderBufferTexture(renderContext.gl, 'uPathTransformExt'),
this.pathTransformBufferTextures[objectIndex] = pathTransformBufferTexture; st: new PathfinderBufferTexture(renderContext.gl, 'uPathTransformST'),
};
this.pathTransformBufferTextures[objectIndex] = pathTransformBufferTextures;
} else { } else {
pathTransformBufferTexture = this.pathTransformBufferTextures[objectIndex]; pathTransformBufferTextures = this.pathTransformBufferTextures[objectIndex];
} }
pathTransformBufferTexture.upload(renderContext.gl, pathTransforms); pathTransformBufferTextures.st.upload(renderContext.gl, pathTransforms.st);
pathTransformBufferTextures.ext.upload(renderContext.gl, pathTransforms.ext);
} }
} }
@ -346,7 +354,8 @@ export abstract class Renderer {
AntialiasingStrategy; AntialiasingStrategy;
protected abstract compositeIfNecessary(): void; protected abstract compositeIfNecessary(): void;
protected abstract pathColorsForObject(objectIndex: number): Uint8Array; protected abstract pathColorsForObject(objectIndex: number): Uint8Array;
protected abstract pathTransformsForObject(objectIndex: number): Float32Array; protected abstract pathTransformsForObject(objectIndex: number):
PathTransformBuffers<Float32Array>;
protected abstract directCurveProgramName(): keyof ShaderMap<void>; protected abstract directCurveProgramName(): keyof ShaderMap<void>;
protected abstract directInteriorProgramName(): keyof ShaderMap<void>; protected abstract directInteriorProgramName(): keyof ShaderMap<void>;
@ -404,6 +413,14 @@ export abstract class Renderer {
/// Called whenever new GPU timing statistics are available. /// Called whenever new GPU timing statistics are available.
protected newTimingsReceived(): void {} protected newTimingsReceived(): void {}
protected createPathTransformBuffers(pathCount: number): PathTransformBuffers<Float32Array> {
pathCount += 1;
return {
ext: new Float32Array((pathCount + (pathCount & 1)) * 2),
st: new Float32Array(pathCount * 4),
};
}
private directlyRenderObject(objectIndex: number): void { private directlyRenderObject(objectIndex: number): void {
if (this.meshes == null || this.meshData == null) if (this.meshes == null || this.meshData == null)
return; return;
@ -447,11 +464,13 @@ export abstract class Renderer {
this.setHintsUniform(directInteriorProgram.uniforms); this.setHintsUniform(directInteriorProgram.uniforms);
this.setPathColorsUniform(objectIndex, directInteriorProgram.uniforms, 0); this.setPathColorsUniform(objectIndex, directInteriorProgram.uniforms, 0);
this.setEmboldenAmountUniform(objectIndex, directInteriorProgram.uniforms); this.setEmboldenAmountUniform(objectIndex, directInteriorProgram.uniforms);
this.pathTransformBufferTextures[meshIndex].st.bind(gl, directInteriorProgram.uniforms, 1);
this.pathTransformBufferTextures[meshIndex] this.pathTransformBufferTextures[meshIndex]
.bind(gl, directInteriorProgram.uniforms, 1); .ext
.bind(gl, directInteriorProgram.uniforms, 2);
if (renderingMode === 'color-depth') { if (renderingMode === 'color-depth') {
const strategy = antialiasingStrategy as ECAAMulticolorStrategy; const strategy = antialiasingStrategy as ECAAMulticolorStrategy;
strategy.bindEdgeDepthTexture(gl, directInteriorProgram.uniforms, 2); strategy.bindEdgeDepthTexture(gl, directInteriorProgram.uniforms, 3);
} }
const coverInteriorRange = getMeshIndexRange(meshes.coverInteriorIndexRanges, pathRange); const coverInteriorRange = getMeshIndexRange(meshes.coverInteriorIndexRanges, pathRange);
if (!this.pathIDsAreInstanced) { if (!this.pathIDsAreInstanced) {
@ -490,10 +509,11 @@ export abstract class Renderer {
this.setHintsUniform(directCurveProgram.uniforms); this.setHintsUniform(directCurveProgram.uniforms);
this.setPathColorsUniform(objectIndex, directCurveProgram.uniforms, 0); this.setPathColorsUniform(objectIndex, directCurveProgram.uniforms, 0);
this.setEmboldenAmountUniform(objectIndex, directCurveProgram.uniforms); this.setEmboldenAmountUniform(objectIndex, directCurveProgram.uniforms);
this.pathTransformBufferTextures[meshIndex].bind(gl, directCurveProgram.uniforms, 1); this.pathTransformBufferTextures[meshIndex].st.bind(gl, directCurveProgram.uniforms, 1);
this.pathTransformBufferTextures[meshIndex].ext.bind(gl, directCurveProgram.uniforms, 2);
if (renderingMode === 'color-depth') { if (renderingMode === 'color-depth') {
const strategy = antialiasingStrategy as ECAAMulticolorStrategy; const strategy = antialiasingStrategy as ECAAMulticolorStrategy;
strategy.bindEdgeDepthTexture(gl, directCurveProgram.uniforms, 2); strategy.bindEdgeDepthTexture(gl, directCurveProgram.uniforms, 3);
} }
const coverCurveRange = getMeshIndexRange(meshes.coverCurveIndexRanges, pathRange); const coverCurveRange = getMeshIndexRange(meshes.coverCurveIndexRanges, pathRange);
if (!this.pathIDsAreInstanced) { if (!this.pathIDsAreInstanced) {

View File

@ -19,7 +19,7 @@ import {OrthographicCamera} from "./camera";
import {UniformMap} from './gl-utils'; import {UniformMap} from './gl-utils';
import {PathfinderMeshData} from "./meshes"; import {PathfinderMeshData} from "./meshes";
import {CompositingOperation, RenderTaskType} from './render-task'; import {CompositingOperation, RenderTaskType} from './render-task';
import {Renderer} from './renderer'; import {PathTransformBuffers, Renderer} from './renderer';
import {ShaderMap, ShaderProgramSource} from './shader-loader'; import {ShaderMap, ShaderProgramSource} from './shader-loader';
import SSAAStrategy from "./ssaa-strategy"; import SSAAStrategy from "./ssaa-strategy";
import {BUILTIN_SVG_URI, SVGLoader} from './svg-loader'; import {BUILTIN_SVG_URI, SVGLoader} from './svg-loader';
@ -254,14 +254,14 @@ class SVGDemoRenderer extends Renderer {
return pathColors; return pathColors;
} }
protected pathTransformsForObject(objectIndex: number): Float32Array { protected pathTransformsForObject(objectIndex: number): PathTransformBuffers<Float32Array> {
const instances = this.renderContext.appController.loader.pathInstances; const instances = this.renderContext.appController.loader.pathInstances;
const pathTransforms = new Float32Array(4 * (instances.length + 1)); const pathTransforms = this.createPathTransformBuffers(instances.length);
for (let pathIndex = 0; pathIndex < instances.length; pathIndex++) { for (let pathIndex = 0; pathIndex < instances.length; pathIndex++) {
// TODO(pcwalton): Set transform. // TODO(pcwalton): Set transform.
const startOffset = (pathIndex + 1) * 4; const startOffset = (pathIndex + 1) * 4;
pathTransforms.set([1, 1, 0, 0], startOffset); pathTransforms.st.set([1, 1, 0, 0], startOffset);
} }
return pathTransforms; return pathTransforms;

View File

@ -131,6 +131,7 @@ class TextDemoController extends DemoAppController<TextDemoView> {
private meshes: PathfinderMeshData; private meshes: PathfinderMeshData;
private _fontSize: number; private _fontSize: number;
private _rotationAngle: number;
private text: string; private text: string;
@ -144,6 +145,7 @@ class TextDemoController extends DemoAppController<TextDemoView> {
super.start(); super.start();
this._fontSize = INITIAL_FONT_SIZE; this._fontSize = INITIAL_FONT_SIZE;
this._rotationAngle = 0.0;
this.hintingSelect = unwrapNull(document.getElementById('pf-hinting-select')) as this.hintingSelect = unwrapNull(document.getElementById('pf-hinting-select')) as
HTMLSelectElement; HTMLSelectElement;
@ -235,6 +237,15 @@ class TextDemoController extends DemoAppController<TextDemoView> {
this.view.then(view => view.renderer.relayoutText()); this.view.then(view => view.renderer.relayoutText());
} }
get rotationAngle(): number {
return this._rotationAngle;
}
set rotationAngle(newRotationAngle: number) {
this._rotationAngle = newRotationAngle;
this.view.then(view => view.renderer.relayoutText());
}
get layoutPixelsPerUnit(): number { get layoutPixelsPerUnit(): number {
return this._fontSize / this.font.opentypeFont.unitsPerEm; return this._fontSize / this.font.opentypeFont.unitsPerEm;
} }
@ -333,22 +344,28 @@ class TextDemoView extends DemoView implements TextRenderContext {
this.appController.newTimingsReceived(newTimings); this.appController.newTimingsReceived(newTimings);
} }
protected onPan() { protected onPan(): void {
this.renderer.viewPanned(); this.renderer.viewPanned();
} }
protected onZoom() { protected onZoom(): void {
this.appController.fontSize = this.renderer.camera.scale * this.appController.fontSize = this.renderer.camera.scale *
this.appController.font.opentypeFont.unitsPerEm; this.appController.font.opentypeFont.unitsPerEm;
} }
protected onRotate(): void {
this.appController.rotationAngle = this.renderer.camera.rotationAngle;
}
private set panZoomEventsEnabled(flag: boolean) { private set panZoomEventsEnabled(flag: boolean) {
if (flag) { if (flag) {
this.renderer.camera.onPan = () => this.onPan(); this.renderer.camera.onPan = () => this.onPan();
this.renderer.camera.onZoom = () => this.onZoom(); this.renderer.camera.onZoom = () => this.onZoom();
this.renderer.camera.onRotate = () => this.onRotate();
} else { } else {
this.renderer.camera.onPan = null; this.renderer.camera.onPan = null;
this.renderer.camera.onZoom = null; this.renderer.camera.onZoom = null;
this.renderer.camera.onRotate = null;
} }
} }
} }
@ -370,6 +387,10 @@ class TextDemoRenderer extends TextRenderer {
return glmatrix.vec4.create(); return glmatrix.vec4.create();
} }
get rotationAngle(): number {
return this.renderContext.appController.rotationAngle;
}
prepareToAttachText(): void { prepareToAttachText(): void {
if (this.atlasFramebuffer == null) if (this.atlasFramebuffer == null)
this.createAtlasFramebuffer(); this.createAtlasFramebuffer();

View File

@ -17,7 +17,7 @@ import {Atlas, ATLAS_SIZE, AtlasGlyph, GlyphKey, SUBPIXEL_GRANULARITY} from './a
import {CameraView, OrthographicCamera} from './camera'; import {CameraView, OrthographicCamera} from './camera';
import {createFramebuffer, createFramebufferDepthTexture, QUAD_ELEMENTS} from './gl-utils'; import {createFramebuffer, createFramebufferDepthTexture, QUAD_ELEMENTS} from './gl-utils';
import {UniformMap} from './gl-utils'; import {UniformMap} from './gl-utils';
import {Renderer} from './renderer'; import {PathTransformBuffers, Renderer} from './renderer';
import {ShaderMap} from './shader-loader'; import {ShaderMap} from './shader-loader';
import SSAAStrategy from './ssaa-strategy'; import SSAAStrategy from './ssaa-strategy';
import {calculatePixelRectForGlyph, computeStemDarkeningAmount, GlyphStore, Hint} from "./text"; import {calculatePixelRectForGlyph, computeStemDarkeningAmount, GlyphStore, Hint} from "./text";
@ -88,6 +88,10 @@ export abstract class TextRenderer extends Renderer {
return glmatrix.vec4.clone([1.0, 1.0, 1.0, 1.0]); return glmatrix.vec4.clone([1.0, 1.0, 1.0, 1.0]);
} }
get rotationAngle(): number {
return 0.0;
}
protected get layoutPixelsPerUnit(): number { protected get layoutPixelsPerUnit(): number {
return this.renderContext.fontSize / this.renderContext.font.opentypeFont.unitsPerEm; return this.renderContext.fontSize / this.renderContext.font.opentypeFont.unitsPerEm;
} }
@ -230,10 +234,11 @@ export abstract class TextRenderer extends Renderer {
return pathColors; return pathColors;
} }
protected pathTransformsForObject(objectIndex: number): Float32Array { protected pathTransformsForObject(objectIndex: number): PathTransformBuffers<Float32Array> {
const pathCount = this.pathCount; const pathCount = this.pathCount;
const atlasGlyphs = this.renderContext.atlasGlyphs; const atlasGlyphs = this.renderContext.atlasGlyphs;
const pixelsPerUnit = this.displayPixelsPerUnit; const pixelsPerUnit = this.displayPixelsPerUnit;
const rotationAngle = this.rotationAngle;
// FIXME(pcwalton): This is a hack that tries to preserve the vertical extents of the glyph // FIXME(pcwalton): This is a hack that tries to preserve the vertical extents of the glyph
// after stem darkening. It's better than nothing, but we should really do better. // after stem darkening. It's better than nothing, but we should really do better.
@ -250,16 +255,28 @@ export abstract class TextRenderer extends Renderer {
glmatrix.vec2.scale(stemDarkeningOffset, stemDarkeningOffset, SQRT_1_2); glmatrix.vec2.scale(stemDarkeningOffset, stemDarkeningOffset, SQRT_1_2);
glmatrix.vec2.mul(stemDarkeningOffset, stemDarkeningOffset, [1, stemDarkeningYScale]); glmatrix.vec2.mul(stemDarkeningOffset, stemDarkeningOffset, [1, stemDarkeningYScale]);
const transforms = new Float32Array((pathCount + 1) * 4); const transform = glmatrix.mat2d.create();
const transforms = this.createPathTransformBuffers(pathCount);
for (const glyph of atlasGlyphs) { for (const glyph of atlasGlyphs) {
const pathID = glyph.pathID; const pathID = glyph.pathID;
const atlasOrigin = glyph.calculateSubpixelOrigin(pixelsPerUnit); const atlasOrigin = glyph.calculateSubpixelOrigin(pixelsPerUnit);
transforms[pathID * 4 + 0] = pixelsPerUnit; glmatrix.mat2d.identity(transform);
transforms[pathID * 4 + 1] = pixelsPerUnit * stemDarkeningYScale; glmatrix.mat2d.translate(transform, transform, atlasOrigin);
transforms[pathID * 4 + 2] = atlasOrigin[0] + stemDarkeningOffset[0]; glmatrix.mat2d.translate(transform, transform, stemDarkeningOffset);
transforms[pathID * 4 + 3] = atlasOrigin[1] + stemDarkeningOffset[1]; glmatrix.mat2d.rotate(transform, transform, rotationAngle);
glmatrix.mat2d.scale(transform,
transform,
[pixelsPerUnit, pixelsPerUnit * stemDarkeningYScale]);
transforms.st[pathID * 4 + 0] = transform[0];
transforms.st[pathID * 4 + 1] = transform[3];
transforms.st[pathID * 4 + 2] = transform[4];
transforms.st[pathID * 4 + 3] = transform[5];
transforms.ext[pathID * 2 + 0] = transform[1];
transforms.ext[pathID * 2 + 1] = transform[2];
} }
return transforms; return transforms;

View File

@ -235,8 +235,9 @@ export abstract class XCAAStrategy extends AntialiasingStrategy {
gl.uniform2i(uniforms.uFramebufferSize, gl.uniform2i(uniforms.uFramebufferSize,
this.supersampledFramebufferSize[0], this.supersampledFramebufferSize[0],
this.supersampledFramebufferSize[1]); this.supersampledFramebufferSize[1]);
renderer.pathTransformBufferTextures[0].bind(gl, uniforms, 0); renderer.pathTransformBufferTextures[0].ext.bind(gl, uniforms, 0);
this.pathBoundsBufferTexture.bind(gl, uniforms, 1); renderer.pathTransformBufferTextures[0].st.bind(gl, uniforms, 1);
this.pathBoundsBufferTexture.bind(gl, uniforms, 2);
renderer.setHintsUniform(uniforms); renderer.setHintsUniform(uniforms);
} }

View File

@ -48,8 +48,12 @@ vec2 transformVertexPosition(vec2 position, mat4 transform) {
/// ///
/// An ST-transform is a combined 2D scale and translation, where the (x, y) coordinates specify /// An ST-transform is a combined 2D scale and translation, where the (x, y) coordinates specify
/// the scale and and the (z, w) coordinates specify the translation. /// the scale and and the (z, w) coordinates specify the translation.
vec2 transformVertexPositionST(vec2 position, vec4 stTransform) { vec2 transformVertexPositionST(vec2 position, vec4 transformST) {
return position * stTransform.xy + stTransform.zw; return position * transformST.xy + transformST.zw;
}
vec2 transformVertexPositionAffine(vec2 position, vec4 transformST, vec2 transformExt) {
return position * transformST.xy + position.yx * transformExt + transformST.zw;
} }
/// Interpolates the given 2D position in the vertical direction using the given ultra-slight /// Interpolates the given 2D position in the vertical direction using the given ultra-slight
@ -160,6 +164,7 @@ bool computeECAAQuadPosition(out vec2 outPosition,
vec2 quadPosition, vec2 quadPosition,
ivec2 framebufferSize, ivec2 framebufferSize,
vec4 localTransformST, vec4 localTransformST,
vec2 localTransformExt,
mat4 globalTransform, mat4 globalTransform,
vec4 hints, vec4 hints,
vec4 bounds, vec4 bounds,
@ -174,12 +179,16 @@ bool computeECAAQuadPosition(out vec2 outPosition,
leftPosition = hintPosition(leftPosition, hints); leftPosition = hintPosition(leftPosition, hints);
rightPosition = hintPosition(rightPosition, hints); rightPosition = hintPosition(rightPosition, hints);
leftPosition = transformVertexPositionST(leftPosition, localTransformST); leftPosition = transformVertexPositionAffine(leftPosition,
rightPosition = transformVertexPositionST(rightPosition, localTransformST); localTransformST,
edgeBL = transformVertexPositionST(edgeBL, localTransformST); localTransformExt);
edgeTL = transformVertexPositionST(edgeTL, localTransformST); rightPosition = transformVertexPositionAffine(rightPosition,
edgeBR = transformVertexPositionST(edgeBR, localTransformST); localTransformST,
edgeTR = transformVertexPositionST(edgeTR, localTransformST); localTransformExt);
edgeBL = transformVertexPositionAffine(edgeBL, localTransformST, localTransformExt);
edgeTL = transformVertexPositionAffine(edgeTL, localTransformST, localTransformExt);
edgeBR = transformVertexPositionAffine(edgeBR, localTransformST, localTransformExt);
edgeTR = transformVertexPositionAffine(edgeTR, localTransformST, localTransformExt);
leftPosition = transformVertexPosition(leftPosition, globalTransform); leftPosition = transformVertexPosition(leftPosition, globalTransform);
rightPosition = transformVertexPosition(rightPosition, globalTransform); rightPosition = transformVertexPosition(rightPosition, globalTransform);
@ -226,9 +235,14 @@ bool computeECAAMultiEdgeMaskQuadPosition(out vec2 outPosition,
vec2 quadPosition, vec2 quadPosition,
ivec2 framebufferSize, ivec2 framebufferSize,
vec4 localTransformST, vec4 localTransformST,
vec2 localTransformExt,
mat4 globalTransform) { mat4 globalTransform) {
leftPosition = transformVertexPositionST(leftPosition, localTransformST); leftPosition = transformVertexPositionAffine(leftPosition,
rightPosition = transformVertexPositionST(rightPosition, localTransformST); localTransformST,
localTransformExt);
rightPosition = transformVertexPositionAffine(rightPosition,
localTransformST,
localTransformExt);
leftPosition = transformVertexPosition(leftPosition, globalTransform); leftPosition = transformVertexPosition(leftPosition, globalTransform);
rightPosition = transformVertexPosition(rightPosition, globalTransform); rightPosition = transformVertexPosition(rightPosition, globalTransform);
@ -397,6 +411,24 @@ vec4 fetchFloat4Data(sampler2D dataTexture, int index, ivec2 dimensions) {
return texture2D(dataTexture, (vec2(pixelCoord) + 0.5) / vec2(dimensions)); return texture2D(dataTexture, (vec2(pixelCoord) + 0.5) / vec2(dimensions));
} }
vec2 fetchFloat2Data(sampler2D dataTexture, int index, ivec2 dimensions) {
int texelIndex = index / 2;
vec4 texel = fetchFloat4Data(dataTexture, texelIndex, dimensions);
return texelIndex * 2 == index ? texel.xy : texel.zw;
}
vec4 fetchPathAffineTransform(out vec2 outPathTransformExt,
sampler2D pathTransformSTTexture,
ivec2 pathTransformSTDimensions,
sampler2D pathTransformExtTexture,
ivec2 pathTransformExtDimensions,
int pathID) {
outPathTransformExt = fetchFloat2Data(pathTransformExtTexture,
pathID,
pathTransformExtDimensions);
return fetchFloat4Data(pathTransformSTTexture, pathID, pathTransformSTDimensions);
}
vec2 packPathID(int pathID) { vec2 packPathID(int pathID) {
return vec2(imod(pathID, 256), pathID / 256) / 255.0; return vec2(imod(pathID, 256), pathID / 256) / 255.0;
} }

View File

@ -13,9 +13,11 @@ precision highp float;
uniform mat4 uTransform; uniform mat4 uTransform;
uniform vec2 uEmboldenAmount; uniform vec2 uEmboldenAmount;
uniform ivec2 uPathColorsDimensions; uniform ivec2 uPathColorsDimensions;
uniform ivec2 uPathTransformDimensions;
uniform sampler2D uPathColors; uniform sampler2D uPathColors;
uniform sampler2D uPathTransform; uniform ivec2 uPathTransformSTDimensions;
uniform sampler2D uPathTransformST;
uniform ivec2 uPathTransformExtDimensions;
uniform sampler2D uPathTransformExt;
attribute vec2 aPosition; attribute vec2 aPosition;
attribute vec2 aTexCoord; attribute vec2 aTexCoord;
@ -31,10 +33,16 @@ varying float vSign;
void main() { void main() {
int pathID = int(aPathID); int pathID = int(aPathID);
vec4 pathTransform = fetchFloat4Data(uPathTransform, pathID, uPathTransformDimensions); vec2 pathTransformExt;
vec4 pathTransformST = fetchPathAffineTransform(pathTransformExt,
uPathTransformST,
uPathTransformSTDimensions,
uPathTransformExt,
uPathTransformExtDimensions,
pathID);
vec2 position = dilatePosition(aPosition, aNormalAngle, uEmboldenAmount); vec2 position = dilatePosition(aPosition, aNormalAngle, uEmboldenAmount);
position = transformVertexPositionST(position, pathTransform); position = transformVertexPositionAffine(position, pathTransformST, pathTransformExt);
gl_Position = uTransform * vec4(position, 0.0, 1.0); gl_Position = uTransform * vec4(position, 0.0, 1.0);

View File

@ -13,9 +13,11 @@ precision highp float;
uniform mat4 uTransform; uniform mat4 uTransform;
uniform vec2 uEmboldenAmount; uniform vec2 uEmboldenAmount;
uniform ivec2 uPathColorsDimensions; uniform ivec2 uPathColorsDimensions;
uniform ivec2 uPathTransformDimensions;
uniform sampler2D uPathColors; uniform sampler2D uPathColors;
uniform sampler2D uPathTransform; uniform ivec2 uPathTransformSTDimensions;
uniform sampler2D uPathTransformST;
uniform ivec2 uPathTransformExtDimensions;
uniform sampler2D uPathTransformExt;
attribute vec2 aPosition; attribute vec2 aPosition;
attribute float aPathID; attribute float aPathID;
@ -27,10 +29,16 @@ varying vec2 vPathID;
void main() { void main() {
int pathID = int(aPathID); int pathID = int(aPathID);
vec4 pathTransform = fetchFloat4Data(uPathTransform, pathID, uPathTransformDimensions); vec2 pathTransformExt;
vec4 pathTransformST = fetchPathAffineTransform(pathTransformExt,
uPathTransformST,
uPathTransformSTDimensions,
uPathTransformExt,
uPathTransformExtDimensions,
pathID);
vec2 position = dilatePosition(aPosition, aNormalAngle, uEmboldenAmount); vec2 position = dilatePosition(aPosition, aNormalAngle, uEmboldenAmount);
position = transformVertexPositionST(position, pathTransform); position = transformVertexPositionAffine(position, pathTransformST, pathTransformExt);
gl_Position = uTransform * vec4(position, 0.0, 1.0); gl_Position = uTransform * vec4(position, 0.0, 1.0);

View File

@ -14,9 +14,11 @@ uniform mat4 uTransform;
uniform vec4 uHints; uniform vec4 uHints;
uniform vec2 uEmboldenAmount; uniform vec2 uEmboldenAmount;
uniform ivec2 uPathColorsDimensions; uniform ivec2 uPathColorsDimensions;
uniform ivec2 uPathTransformDimensions;
uniform sampler2D uPathColors; uniform sampler2D uPathColors;
uniform sampler2D uPathTransform; uniform ivec2 uPathTransformSTDimensions;
uniform sampler2D uPathTransformST;
uniform ivec2 uPathTransformExtDimensions;
uniform sampler2D uPathTransformExt;
attribute vec2 aPosition; attribute vec2 aPosition;
attribute vec2 aTexCoord; attribute vec2 aTexCoord;
@ -31,11 +33,17 @@ varying float vSign;
void main() { void main() {
int pathID = int(aPathID); int pathID = int(aPathID);
vec4 pathTransform = fetchFloat4Data(uPathTransform, pathID, uPathTransformDimensions); vec2 pathTransformExt;
vec4 pathTransformST = fetchPathAffineTransform(pathTransformExt,
uPathTransformST,
uPathTransformSTDimensions,
uPathTransformExt,
uPathTransformExtDimensions,
pathID);
vec2 position = dilatePosition(aPosition, aNormalAngle, uEmboldenAmount); vec2 position = dilatePosition(aPosition, aNormalAngle, uEmboldenAmount);
position = hintPosition(position, uHints); position = hintPosition(position, uHints);
position = transformVertexPositionST(position, pathTransform); position = transformVertexPositionAffine(position, pathTransformST, pathTransformExt);
position = transformVertexPosition(position, uTransform); position = transformVertexPosition(position, uTransform);
float depth = convertPathIndexToViewportDepthValue(pathID); float depth = convertPathIndexToViewportDepthValue(pathID);

View File

@ -14,9 +14,11 @@ uniform mat4 uTransform;
uniform vec4 uHints; uniform vec4 uHints;
uniform vec2 uEmboldenAmount; uniform vec2 uEmboldenAmount;
uniform ivec2 uPathColorsDimensions; uniform ivec2 uPathColorsDimensions;
uniform ivec2 uPathTransformDimensions;
uniform sampler2D uPathColors; uniform sampler2D uPathColors;
uniform sampler2D uPathTransform; uniform ivec2 uPathTransformSTDimensions;
uniform sampler2D uPathTransformST;
uniform ivec2 uPathTransformExtDimensions;
uniform sampler2D uPathTransformExt;
attribute vec2 aPosition; attribute vec2 aPosition;
attribute float aPathID; attribute float aPathID;
@ -27,11 +29,17 @@ varying vec4 vColor;
void main() { void main() {
int pathID = int(aPathID); int pathID = int(aPathID);
vec4 pathTransform = fetchFloat4Data(uPathTransform, pathID, uPathTransformDimensions); vec2 pathTransformExt;
vec4 pathTransformST = fetchPathAffineTransform(pathTransformExt,
uPathTransformST,
uPathTransformSTDimensions,
uPathTransformExt,
uPathTransformExtDimensions,
pathID);
vec2 position = dilatePosition(aPosition, aNormalAngle, uEmboldenAmount); vec2 position = dilatePosition(aPosition, aNormalAngle, uEmboldenAmount);
position = hintPosition(position, uHints); position = hintPosition(position, uHints);
position = transformVertexPositionST(position, pathTransform); position = transformVertexPositionAffine(position, pathTransformST, pathTransformExt);
position = transformVertexPosition(position, uTransform); position = transformVertexPosition(position, uTransform);
float depth = convertPathIndexToViewportDepthValue(pathID); float depth = convertPathIndexToViewportDepthValue(pathID);

View File

@ -13,9 +13,11 @@ precision highp float;
uniform mat4 uTransform; uniform mat4 uTransform;
uniform vec4 uHints; uniform vec4 uHints;
uniform ivec2 uFramebufferSize; uniform ivec2 uFramebufferSize;
uniform ivec2 uPathTransformDimensions; uniform ivec2 uPathTransformSTDimensions;
uniform sampler2D uPathTransformST;
uniform ivec2 uPathTransformExtDimensions;
uniform sampler2D uPathTransformExt;
uniform ivec2 uPathBoundsDimensions; uniform ivec2 uPathBoundsDimensions;
uniform sampler2D uPathTransform;
uniform sampler2D uPathBounds; uniform sampler2D uPathBounds;
uniform vec2 uEmboldenAmount; uniform vec2 uEmboldenAmount;
@ -39,7 +41,13 @@ void main() {
float controlPointNormalAngle = aNormalAngles.y; float controlPointNormalAngle = aNormalAngles.y;
float rightNormalAngle = aNormalAngles.z; float rightNormalAngle = aNormalAngles.z;
vec4 transform = fetchFloat4Data(uPathTransform, pathID, uPathTransformDimensions); vec2 pathTransformExt;
vec4 pathTransformST = fetchPathAffineTransform(pathTransformExt,
uPathTransformST,
uPathTransformSTDimensions,
uPathTransformExt,
uPathTransformExtDimensions,
pathID);
vec4 bounds = fetchFloat4Data(uPathBounds, pathID, uPathBoundsDimensions); vec4 bounds = fetchFloat4Data(uPathBounds, pathID, uPathBoundsDimensions);
// Transform the points, and compute the position of this vertex. // Transform the points, and compute the position of this vertex.
@ -51,7 +59,8 @@ void main() {
rightPosition, rightPosition,
aQuadPosition, aQuadPosition,
uFramebufferSize, uFramebufferSize,
transform, pathTransformST,
pathTransformExt,
uTransform, uTransform,
uHints, uHints,
bounds, bounds,
@ -62,7 +71,9 @@ void main() {
controlPointNormalAngle, controlPointNormalAngle,
uEmboldenAmount); uEmboldenAmount);
controlPointPosition = hintPosition(controlPointPosition, uHints); controlPointPosition = hintPosition(controlPointPosition, uHints);
controlPointPosition = transformVertexPositionST(controlPointPosition, transform); controlPointPosition = transformVertexPositionAffine(controlPointPosition,
pathTransformST,
pathTransformExt);
controlPointPosition = transformVertexPosition(controlPointPosition, uTransform); controlPointPosition = transformVertexPosition(controlPointPosition, uTransform);
controlPointPosition = convertClipToScreenSpace(controlPointPosition, uFramebufferSize); controlPointPosition = convertClipToScreenSpace(controlPointPosition, uFramebufferSize);
} }

View File

@ -13,10 +13,12 @@ precision highp float;
uniform mat4 uTransform; uniform mat4 uTransform;
uniform vec4 uHints; uniform vec4 uHints;
uniform ivec2 uFramebufferSize; uniform ivec2 uFramebufferSize;
uniform ivec2 uPathTransformDimensions;
uniform ivec2 uPathBoundsDimensions; uniform ivec2 uPathBoundsDimensions;
uniform sampler2D uPathTransform;
uniform sampler2D uPathBounds; uniform sampler2D uPathBounds;
uniform ivec2 uPathTransformSTDimensions;
uniform sampler2D uPathTransformST;
uniform ivec2 uPathTransformExtDimensions;
uniform sampler2D uPathTransformExt;
uniform vec2 uEmboldenAmount; uniform vec2 uEmboldenAmount;
attribute vec2 aQuadPosition; attribute vec2 aQuadPosition;
@ -36,7 +38,13 @@ void main() {
float leftNormalAngle = aLeftNormalAngle; float leftNormalAngle = aLeftNormalAngle;
float rightNormalAngle = aRightNormalAngle; float rightNormalAngle = aRightNormalAngle;
vec4 transform = fetchFloat4Data(uPathTransform, pathID, uPathTransformDimensions); vec2 pathTransformExt;
vec4 pathTransformST = fetchPathAffineTransform(pathTransformExt,
uPathTransformST,
uPathTransformSTDimensions,
uPathTransformExt,
uPathTransformExtDimensions,
pathID);
vec4 bounds = fetchFloat4Data(uPathBounds, pathID, uPathBoundsDimensions); vec4 bounds = fetchFloat4Data(uPathBounds, pathID, uPathBoundsDimensions);
// Transform the points, and compute the position of this vertex. // Transform the points, and compute the position of this vertex.
@ -48,7 +56,8 @@ void main() {
rightPosition, rightPosition,
aQuadPosition, aQuadPosition,
uFramebufferSize, uFramebufferSize,
transform, pathTransformST,
pathTransformExt,
uTransform, uTransform,
uHints, uHints,
bounds, bounds,

View File

@ -12,8 +12,10 @@ precision highp float;
uniform mat4 uTransform; uniform mat4 uTransform;
uniform ivec2 uFramebufferSize; uniform ivec2 uFramebufferSize;
uniform ivec2 uPathTransformDimensions; uniform ivec2 uPathTransformSTDimensions;
uniform sampler2D uPathTransform; uniform sampler2D uPathTransformST;
uniform ivec2 uPathTransformExtDimensions;
uniform sampler2D uPathTransformExt;
attribute vec2 aQuadPosition; attribute vec2 aQuadPosition;
attribute vec2 aLeftPosition; attribute vec2 aLeftPosition;
@ -30,7 +32,13 @@ void main() {
vec2 rightPosition = aRightPosition; vec2 rightPosition = aRightPosition;
int pathID = int(aPathID); int pathID = int(aPathID);
vec4 transform = fetchFloat4Data(uPathTransform, pathID, uPathTransformDimensions); vec2 pathTransformExt;
vec4 pathTransformST = fetchPathAffineTransform(pathTransformExt,
uPathTransformST,
uPathTransformSTDimensions,
uPathTransformExt,
uPathTransformExtDimensions,
pathID);
// Transform the points, and compute the position of this vertex. // Transform the points, and compute the position of this vertex.
vec2 position; vec2 position;
@ -39,9 +47,12 @@ void main() {
rightPosition, rightPosition,
aQuadPosition, aQuadPosition,
uFramebufferSize, uFramebufferSize,
transform, pathTransformST,
pathTransformExt,
uTransform)) { uTransform)) {
controlPointPosition = transformVertexPositionST(controlPointPosition, transform); controlPointPosition = transformVertexPositionAffine(controlPointPosition,
pathTransformST,
pathTransformExt);
controlPointPosition = transformVertexPosition(controlPointPosition, uTransform); controlPointPosition = transformVertexPosition(controlPointPosition, uTransform);
controlPointPosition = convertClipToScreenSpace(controlPointPosition, uFramebufferSize); controlPointPosition = convertClipToScreenSpace(controlPointPosition, uFramebufferSize);
} }

View File

@ -13,8 +13,10 @@ precision highp float;
uniform mat4 uTransform; uniform mat4 uTransform;
uniform vec4 uHints; uniform vec4 uHints;
uniform ivec2 uFramebufferSize; uniform ivec2 uFramebufferSize;
uniform ivec2 uPathTransformDimensions; uniform ivec2 uPathTransformSTDimensions;
uniform sampler2D uPathTransform; uniform sampler2D uPathTransformST;
uniform ivec2 uPathTransformExtDimensions;
uniform sampler2D uPathTransformExt;
attribute vec2 aQuadPosition; attribute vec2 aQuadPosition;
attribute vec2 aLeftPosition; attribute vec2 aLeftPosition;
@ -28,7 +30,13 @@ void main() {
vec2 rightPosition = aRightPosition; vec2 rightPosition = aRightPosition;
int pathID = int(aPathID); int pathID = int(aPathID);
vec4 transform = fetchFloat4Data(uPathTransform, pathID, uPathTransformDimensions); vec2 pathTransformExt;
vec4 pathTransformST = fetchPathAffineTransform(pathTransformExt,
uPathTransformST,
uPathTransformSTDimensions,
uPathTransformExt,
uPathTransformExtDimensions,
pathID);
// Transform the points, and compute the position of this vertex. // Transform the points, and compute the position of this vertex.
vec2 position; vec2 position;
@ -37,7 +45,8 @@ void main() {
rightPosition, rightPosition,
aQuadPosition, aQuadPosition,
uFramebufferSize, uFramebufferSize,
transform, pathTransformST,
pathTransformExt,
uTransform); uTransform);
float depth = convertPathIndexToViewportDepthValue(pathID); float depth = convertPathIndexToViewportDepthValue(pathID);

View File

@ -13,8 +13,8 @@ precision highp float;
uniform vec4 uTransformST; uniform vec4 uTransformST;
uniform vec4 uHints; uniform vec4 uHints;
uniform ivec2 uFramebufferSize; uniform ivec2 uFramebufferSize;
uniform ivec2 uPathTransformDimensions; uniform ivec2 uPathTransformSTDimensions;
uniform sampler2D uPathTransform; uniform sampler2D uPathTransformST;
attribute vec2 aQuadPosition; attribute vec2 aQuadPosition;
attribute vec2 aUpperLeftPosition; attribute vec2 aUpperLeftPosition;
@ -26,13 +26,13 @@ varying vec2 vHorizontalExtents;
void main() { void main() {
int pathID = int(aPathID); int pathID = int(aPathID);
vec4 transform = fetchFloat4Data(uPathTransform, pathID, uPathTransformDimensions); vec4 transformST = fetchFloat4Data(uPathTransformST, pathID, uPathTransformSTDimensions);
vec2 upperLeftPosition = hintPosition(aUpperLeftPosition, uHints); vec2 upperLeftPosition = hintPosition(aUpperLeftPosition, uHints);
vec2 lowerRightPosition = hintPosition(aLowerRightPosition, uHints); vec2 lowerRightPosition = hintPosition(aLowerRightPosition, uHints);
upperLeftPosition = transformVertexPositionST(upperLeftPosition, transform); upperLeftPosition = transformVertexPositionST(upperLeftPosition, transformST);
lowerRightPosition = transformVertexPositionST(lowerRightPosition, transform); lowerRightPosition = transformVertexPositionST(lowerRightPosition, transformST);
upperLeftPosition = transformVertexPositionST(upperLeftPosition, uTransformST); upperLeftPosition = transformVertexPositionST(upperLeftPosition, uTransformST);
lowerRightPosition = transformVertexPositionST(lowerRightPosition, uTransformST); lowerRightPosition = transformVertexPositionST(lowerRightPosition, uTransformST);

View File

@ -13,8 +13,8 @@ precision highp float;
uniform vec4 uTransformST; uniform vec4 uTransformST;
uniform vec4 uHints; uniform vec4 uHints;
uniform ivec2 uFramebufferSize; uniform ivec2 uFramebufferSize;
uniform ivec2 uPathTransformDimensions; uniform ivec2 uPathTransformSTDimensions;
uniform sampler2D uPathTransform; uniform sampler2D uPathTransformST;
uniform bool uWinding; uniform bool uWinding;
attribute vec2 aQuadPosition; attribute vec2 aQuadPosition;
@ -33,7 +33,7 @@ void main() {
vec2 rightPosition = aRightPosition; vec2 rightPosition = aRightPosition;
int pathID = int(aPathID); int pathID = int(aPathID);
vec4 transform = fetchFloat4Data(uPathTransform, pathID, uPathTransformDimensions); vec4 transformST = fetchFloat4Data(uPathTransformST, pathID, uPathTransformSTDimensions);
// Transform the points, and compute the position of this vertex. // Transform the points, and compute the position of this vertex.
vec2 position; vec2 position;
@ -42,11 +42,11 @@ void main() {
rightPosition, rightPosition,
aQuadPosition, aQuadPosition,
uFramebufferSize, uFramebufferSize,
transform, transformST,
uTransformST, uTransformST,
uHints)) { uHints)) {
controlPointPosition = hintPosition(aControlPointPosition, uHints); controlPointPosition = hintPosition(aControlPointPosition, uHints);
controlPointPosition = transformVertexPositionST(controlPointPosition, transform); controlPointPosition = transformVertexPositionST(controlPointPosition, transformST);
controlPointPosition = transformVertexPositionST(controlPointPosition, uTransformST); controlPointPosition = transformVertexPositionST(controlPointPosition, uTransformST);
controlPointPosition = convertClipToScreenSpace(controlPointPosition, uFramebufferSize); controlPointPosition = convertClipToScreenSpace(controlPointPosition, uFramebufferSize);
} }

View File

@ -13,8 +13,8 @@ precision highp float;
uniform vec4 uTransformST; uniform vec4 uTransformST;
uniform vec4 uHints; uniform vec4 uHints;
uniform ivec2 uFramebufferSize; uniform ivec2 uFramebufferSize;
uniform ivec2 uPathTransformDimensions; uniform ivec2 uPathTransformSTDimensions;
uniform sampler2D uPathTransform; uniform sampler2D uPathTransformST;
uniform bool uWinding; uniform bool uWinding;
attribute vec2 aQuadPosition; attribute vec2 aQuadPosition;
@ -30,7 +30,7 @@ void main() {
vec2 rightPosition = aRightPosition; vec2 rightPosition = aRightPosition;
int pathID = int(aPathID); int pathID = int(aPathID);
vec4 transform = fetchFloat4Data(uPathTransform, pathID, uPathTransformDimensions); vec4 transformST = fetchFloat4Data(uPathTransformST, pathID, uPathTransformSTDimensions);
// Transform the points, and compute the position of this vertex. // Transform the points, and compute the position of this vertex.
vec2 position; vec2 position;
@ -39,7 +39,7 @@ void main() {
rightPosition, rightPosition,
aQuadPosition, aQuadPosition,
uFramebufferSize, uFramebufferSize,
transform, transformST,
uTransformST, uTransformST,
uHints); uHints);

View File

@ -15,8 +15,10 @@ uniform vec4 uHints;
uniform vec2 uEmboldenAmount; uniform vec2 uEmboldenAmount;
uniform ivec2 uPathColorsDimensions; uniform ivec2 uPathColorsDimensions;
uniform sampler2D uPathColors; uniform sampler2D uPathColors;
uniform ivec2 uPathTransformDimensions; uniform ivec2 uPathTransformSTDimensions;
uniform sampler2D uPathTransform; uniform sampler2D uPathTransformST;
uniform ivec2 uPathTransformExtDimensions;
uniform sampler2D uPathTransformExt;
attribute vec2 aPosition; attribute vec2 aPosition;
attribute vec2 aTexCoord; attribute vec2 aTexCoord;
@ -31,11 +33,17 @@ varying float vSign;
void main() { void main() {
int pathID = int(aPathID); int pathID = int(aPathID);
vec4 pathTransform = fetchFloat4Data(uPathTransform, pathID, uPathTransformDimensions); vec2 pathTransformExt;
vec4 pathTransformST = fetchPathAffineTransform(pathTransformExt,
uPathTransformST,
uPathTransformSTDimensions,
uPathTransformExt,
uPathTransformExtDimensions,
pathID);
vec2 position = dilatePosition(aPosition, aNormalAngle, uEmboldenAmount); vec2 position = dilatePosition(aPosition, aNormalAngle, uEmboldenAmount);
position = hintPosition(position, uHints); position = hintPosition(position, uHints);
position = transformVertexPositionST(position, pathTransform); position = transformVertexPositionAffine(position, pathTransformST, pathTransformExt);
position = transformVertexPosition(position, uTransform); position = transformVertexPosition(position, uTransform);
float depth = convertPathIndexToViewportDepthValue(pathID); float depth = convertPathIndexToViewportDepthValue(pathID);

View File

@ -14,9 +14,11 @@ uniform mat4 uTransform;
uniform vec4 uHints; uniform vec4 uHints;
uniform vec2 uEmboldenAmount; uniform vec2 uEmboldenAmount;
uniform ivec2 uPathColorsDimensions; uniform ivec2 uPathColorsDimensions;
uniform ivec2 uPathTransformDimensions;
uniform sampler2D uPathColors; uniform sampler2D uPathColors;
uniform sampler2D uPathTransform; uniform ivec2 uPathTransformSTDimensions;
uniform sampler2D uPathTransformST;
uniform ivec2 uPathTransformExtDimensions;
uniform sampler2D uPathTransformExt;
attribute vec2 aPosition; attribute vec2 aPosition;
attribute float aPathID; attribute float aPathID;
@ -28,11 +30,17 @@ varying float vSign;
void main() { void main() {
int pathID = int(aPathID); int pathID = int(aPathID);
vec4 pathTransform = fetchFloat4Data(uPathTransform, pathID, uPathTransformDimensions); vec2 pathTransformExt;
vec4 pathTransformST = fetchPathAffineTransform(pathTransformExt,
uPathTransformST,
uPathTransformSTDimensions,
uPathTransformExt,
uPathTransformExtDimensions,
pathID);
vec2 position = dilatePosition(aPosition, aNormalAngle, uEmboldenAmount); vec2 position = dilatePosition(aPosition, aNormalAngle, uEmboldenAmount);
position = hintPosition(position, uHints); position = hintPosition(position, uHints);
position = transformVertexPositionST(position, pathTransform); position = transformVertexPositionAffine(position, pathTransformST, pathTransformExt);
position = transformVertexPosition(position, uTransform); position = transformVertexPosition(position, uTransform);
float depth = convertPathIndexToViewportDepthValue(pathID); float depth = convertPathIndexToViewportDepthValue(pathID);