Use the LUT to gamma correct text, and fix stem darkening math
This commit is contained in:
parent
82fd214a76
commit
e5b76726d9
|
@ -70,6 +70,10 @@
|
||||||
{{>partials/switch.html id="pf-subpixel-aa"
|
{{>partials/switch.html id="pf-subpixel-aa"
|
||||||
title="Subpixel AA"}}
|
title="Subpixel AA"}}
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group row justify-content-between">
|
||||||
|
{{>partials/switch.html id="pf-gamma-correction"
|
||||||
|
title="Gamma Correction"}}
|
||||||
|
</div>
|
||||||
<div class="form-group row justify-content-between">
|
<div class="form-group row justify-content-between">
|
||||||
{{>partials/switch.html id="pf-stem-darkening"
|
{{>partials/switch.html id="pf-stem-darkening"
|
||||||
title="Stem Darkening"}}
|
title="Stem Darkening"}}
|
||||||
|
|
|
@ -22,6 +22,8 @@ export type DirectRenderingMode = 'none' | 'color' | 'color-depth';
|
||||||
|
|
||||||
export type SubpixelAAType = 'none' | 'medium';
|
export type SubpixelAAType = 'none' | 'medium';
|
||||||
|
|
||||||
|
export type GammaCorrectionMode = 'off' | 'on';
|
||||||
|
|
||||||
export type StemDarkeningMode = 'none' | 'dark';
|
export type StemDarkeningMode = 'none' | 'dark';
|
||||||
|
|
||||||
export abstract class AntialiasingStrategy {
|
export abstract class AntialiasingStrategy {
|
||||||
|
|
|
@ -8,7 +8,8 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
import {AntialiasingStrategyName, StemDarkeningMode, SubpixelAAType} from "./aa-strategy";
|
import {AntialiasingStrategyName, GammaCorrectionMode, StemDarkeningMode} from "./aa-strategy";
|
||||||
|
import {SubpixelAAType} from "./aa-strategy";
|
||||||
import {FilePickerView} from "./file-picker";
|
import {FilePickerView} from "./file-picker";
|
||||||
import {ShaderLoader, ShaderMap, ShaderProgramSource} from './shader-loader';
|
import {ShaderLoader, ShaderMap, ShaderProgramSource} from './shader-loader';
|
||||||
import {expectNotNull, unwrapNull, unwrapUndef} from './utils';
|
import {expectNotNull, unwrapNull, unwrapUndef} from './utils';
|
||||||
|
@ -16,6 +17,52 @@ import {DemoView, Timings, TIMINGS} from "./view";
|
||||||
|
|
||||||
const GAMMA_LUT_URI: string = "/textures/gamma-lut.png";
|
const GAMMA_LUT_URI: string = "/textures/gamma-lut.png";
|
||||||
|
|
||||||
|
const SWITCHES: SwitchMap = {
|
||||||
|
gammaCorrection: {
|
||||||
|
id: 'pf-gamma-correction',
|
||||||
|
offValue: 'off',
|
||||||
|
onValue: 'on',
|
||||||
|
radioButtonName: 'gammaCorrectionRadioButton',
|
||||||
|
},
|
||||||
|
stemDarkening: {
|
||||||
|
id: 'pf-stem-darkening',
|
||||||
|
offValue: 'none',
|
||||||
|
onValue: 'dark',
|
||||||
|
radioButtonName: 'stemDarkeningRadioButton',
|
||||||
|
},
|
||||||
|
subpixelAA: {
|
||||||
|
id: 'pf-subpixel-aa',
|
||||||
|
offValue: 'none',
|
||||||
|
onValue: 'medium',
|
||||||
|
radioButtonName: 'subpixelAARadioButton',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
interface SwitchDescriptor {
|
||||||
|
id: string;
|
||||||
|
radioButtonName: keyof Switches;
|
||||||
|
onValue: string;
|
||||||
|
offValue: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SwitchMap {
|
||||||
|
gammaCorrection: SwitchDescriptor;
|
||||||
|
stemDarkening: SwitchDescriptor;
|
||||||
|
subpixelAA: SwitchDescriptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AAOptions {
|
||||||
|
gammaCorrection: GammaCorrectionMode;
|
||||||
|
stemDarkening: StemDarkeningMode;
|
||||||
|
subpixelAA: SubpixelAAType;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Switches {
|
||||||
|
subpixelAARadioButton: HTMLInputElement | null;
|
||||||
|
gammaCorrectionRadioButton: HTMLInputElement | null;
|
||||||
|
stemDarkeningRadioButton: HTMLInputElement | null;
|
||||||
|
}
|
||||||
|
|
||||||
export abstract class AppController {
|
export abstract class AppController {
|
||||||
protected canvas: HTMLCanvasElement;
|
protected canvas: HTMLCanvasElement;
|
||||||
|
|
||||||
|
@ -47,9 +94,14 @@ export abstract class AppController {
|
||||||
protected abstract get defaultFile(): string;
|
protected abstract get defaultFile(): string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export abstract class DemoAppController<View extends DemoView> extends AppController {
|
export abstract class DemoAppController<View extends DemoView> extends AppController
|
||||||
|
implements Switches {
|
||||||
view: Promise<View>;
|
view: Promise<View>;
|
||||||
|
|
||||||
|
subpixelAARadioButton: HTMLInputElement | null;
|
||||||
|
gammaCorrectionRadioButton: HTMLInputElement | null;
|
||||||
|
stemDarkeningRadioButton: HTMLInputElement | null;
|
||||||
|
|
||||||
protected abstract readonly builtinFileURI: string;
|
protected abstract readonly builtinFileURI: string;
|
||||||
|
|
||||||
protected filePickerView: FilePickerView | null;
|
protected filePickerView: FilePickerView | null;
|
||||||
|
@ -59,8 +111,6 @@ export abstract class DemoAppController<View extends DemoView> extends AppContro
|
||||||
protected gammaLUT: HTMLImageElement;
|
protected gammaLUT: HTMLImageElement;
|
||||||
|
|
||||||
private aaLevelSelect: HTMLSelectElement | null;
|
private aaLevelSelect: HTMLSelectElement | null;
|
||||||
private subpixelAARadioButton: HTMLInputElement | null;
|
|
||||||
private stemDarkeningRadioButton: HTMLInputElement | null;
|
|
||||||
private fpsLabel: HTMLElement | null;
|
private fpsLabel: HTMLElement | null;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
|
@ -169,22 +219,15 @@ export abstract class DemoAppController<View extends DemoView> extends AppContro
|
||||||
// click listener that Bootstrap sets up until the event bubbles up to the document. This
|
// click listener that Bootstrap sets up until the event bubbles up to the document. This
|
||||||
// click listener is what toggles the `checked` attribute, so we have to wait until it
|
// click listener is what toggles the `checked` attribute, so we have to wait until it
|
||||||
// fires before updating the antialiasing settings.
|
// fires before updating the antialiasing settings.
|
||||||
this.subpixelAARadioButton =
|
for (const switchName of Object.keys(SWITCHES) as Array<keyof SwitchMap>) {
|
||||||
document.getElementById('pf-subpixel-aa-select-on') as HTMLInputElement | null;
|
const radioButtonName = SWITCHES[switchName].radioButtonName;
|
||||||
const subpixelAAButtons =
|
const switchID = SWITCHES[switchName].id;
|
||||||
document.getElementById('pf-subpixel-aa-buttons') as HTMLElement | null;
|
this[radioButtonName] = document.getElementById(`${switchID}-select-on`) as
|
||||||
if (subpixelAAButtons != null) {
|
HTMLInputElement | null;
|
||||||
subpixelAAButtons.addEventListener('click', () => {
|
const buttons = document.getElementById(`${switchID}-buttons`) as HTMLElement | null;
|
||||||
window.setTimeout(() => this.updateAALevel(), 0);
|
if (buttons == null)
|
||||||
}, false);
|
continue;
|
||||||
}
|
buttons.addEventListener('click', () => {
|
||||||
|
|
||||||
this.stemDarkeningRadioButton =
|
|
||||||
document.getElementById('pf-stem-darkening-select-on') as HTMLInputElement | null;
|
|
||||||
const stemDarkeningButtons =
|
|
||||||
document.getElementById('pf-stem-darkening-buttons') as HTMLElement | null;
|
|
||||||
if (stemDarkeningButtons != null) {
|
|
||||||
stemDarkeningButtons.addEventListener('click', () => {
|
|
||||||
window.setTimeout(() => this.updateAALevel(), 0);
|
window.setTimeout(() => this.updateAALevel(), 0);
|
||||||
}, false);
|
}, false);
|
||||||
}
|
}
|
||||||
|
@ -242,20 +285,19 @@ export abstract class DemoAppController<View extends DemoView> extends AppContro
|
||||||
aaLevel = 0;
|
aaLevel = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
let subpixelAA: SubpixelAAType;
|
const aaOptions: Partial<AAOptions> = {};
|
||||||
if (this.subpixelAARadioButton != null && this.subpixelAARadioButton.checked)
|
for (const switchName of Object.keys(SWITCHES) as Array<keyof SwitchMap>) {
|
||||||
subpixelAA = 'medium';
|
const switchDescriptor = SWITCHES[switchName];
|
||||||
|
const radioButtonName = switchDescriptor.radioButtonName;
|
||||||
|
const radioButton = this[radioButtonName];
|
||||||
|
if (radioButton != null && radioButton.checked)
|
||||||
|
aaOptions[switchName] = switchDescriptor.onValue as any;
|
||||||
else
|
else
|
||||||
subpixelAA = 'none';
|
aaOptions[switchName] = switchDescriptor.offValue as any;
|
||||||
|
}
|
||||||
let stemDarkening: StemDarkeningMode;
|
|
||||||
if (this.stemDarkeningRadioButton != null && this.stemDarkeningRadioButton.checked)
|
|
||||||
stemDarkening = 'dark';
|
|
||||||
else
|
|
||||||
stemDarkening = 'none';
|
|
||||||
|
|
||||||
this.view.then(view => {
|
this.view.then(view => {
|
||||||
view.setAntialiasingOptions(aaType, aaLevel, subpixelAA, stemDarkening);
|
view.setAntialiasingOptions(aaType, aaLevel, aaOptions as AAOptions);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,8 +11,9 @@
|
||||||
import * as glmatrix from 'gl-matrix';
|
import * as glmatrix from 'gl-matrix';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
import {AntialiasingStrategy, AntialiasingStrategyName, NoAAStrategy} from './aa-strategy';
|
import {AntialiasingStrategy, AntialiasingStrategyName, GammaCorrectionMode} from './aa-strategy';
|
||||||
import {StemDarkeningMode, SubpixelAAType} from './aa-strategy';
|
import {NoAAStrategy, StemDarkeningMode, SubpixelAAType} from './aa-strategy';
|
||||||
|
import {AAOptions} from './app-controller';
|
||||||
import PathfinderBufferTexture from "./buffer-texture";
|
import PathfinderBufferTexture from "./buffer-texture";
|
||||||
import {UniformMap} from './gl-utils';
|
import {UniformMap} from './gl-utils';
|
||||||
import {PathfinderMeshBuffers, PathfinderMeshData} from "./meshes";
|
import {PathfinderMeshBuffers, PathfinderMeshData} from "./meshes";
|
||||||
|
@ -42,8 +43,8 @@ export abstract class Renderer {
|
||||||
return glmatrix.vec2.create();
|
return glmatrix.vec2.create();
|
||||||
}
|
}
|
||||||
|
|
||||||
get bgColor(): glmatrix.vec4 | null {
|
get bgColor(): glmatrix.vec4 {
|
||||||
return null;
|
return glmatrix.vec4.clone([1.0, 1.0, 1.0, 1.0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
get fgColor(): glmatrix.vec4 | null {
|
get fgColor(): glmatrix.vec4 | null {
|
||||||
|
@ -66,6 +67,8 @@ export abstract class Renderer {
|
||||||
protected lastTimings: Timings;
|
protected lastTimings: Timings;
|
||||||
protected pathColorsBufferTextures: PathfinderBufferTexture[];
|
protected pathColorsBufferTextures: PathfinderBufferTexture[];
|
||||||
|
|
||||||
|
protected gammaCorrectionMode: GammaCorrectionMode;
|
||||||
|
|
||||||
protected get pathIDsAreInstanced(): boolean {
|
protected get pathIDsAreInstanced(): boolean {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -87,6 +90,8 @@ export abstract class Renderer {
|
||||||
|
|
||||||
this.lastTimings = { rendering: 0, compositing: 0 };
|
this.lastTimings = { rendering: 0, compositing: 0 };
|
||||||
|
|
||||||
|
this.gammaCorrectionMode = 'on';
|
||||||
|
|
||||||
this.pathTransformBufferTextures = [];
|
this.pathTransformBufferTextures = [];
|
||||||
this.pathColorsBufferTextures = [];
|
this.pathColorsBufferTextures = [];
|
||||||
|
|
||||||
|
@ -154,12 +159,14 @@ export abstract class Renderer {
|
||||||
|
|
||||||
setAntialiasingOptions(aaType: AntialiasingStrategyName,
|
setAntialiasingOptions(aaType: AntialiasingStrategyName,
|
||||||
aaLevel: number,
|
aaLevel: number,
|
||||||
subpixelAA: SubpixelAAType,
|
aaOptions: AAOptions):
|
||||||
stemDarkening: StemDarkeningMode) {
|
void {
|
||||||
|
this.gammaCorrectionMode = aaOptions.gammaCorrection;
|
||||||
|
|
||||||
this.antialiasingStrategy = this.createAAStrategy(aaType,
|
this.antialiasingStrategy = this.createAAStrategy(aaType,
|
||||||
aaLevel,
|
aaLevel,
|
||||||
subpixelAA,
|
aaOptions.subpixelAA,
|
||||||
stemDarkening);
|
aaOptions.stemDarkening);
|
||||||
|
|
||||||
this.antialiasingStrategy.init(this);
|
this.antialiasingStrategy.init(this);
|
||||||
if (this.meshData != null)
|
if (this.meshData != null)
|
||||||
|
@ -168,12 +175,12 @@ export abstract class Renderer {
|
||||||
this.renderContext.setDirty();
|
this.renderContext.setDirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
canvasResized() {
|
canvasResized(): void {
|
||||||
if (this.antialiasingStrategy != null)
|
if (this.antialiasingStrategy != null)
|
||||||
this.antialiasingStrategy.init(this);
|
this.antialiasingStrategy.init(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
setFramebufferSizeUniform(uniforms: UniformMap) {
|
setFramebufferSizeUniform(uniforms: UniformMap): void {
|
||||||
const gl = this.renderContext.gl;
|
const gl = this.renderContext.gl;
|
||||||
gl.uniform2i(uniforms.uFramebufferSize,
|
gl.uniform2i(uniforms.uFramebufferSize,
|
||||||
this.destAllocatedSize[0],
|
this.destAllocatedSize[0],
|
||||||
|
@ -201,7 +208,7 @@ export abstract class Renderer {
|
||||||
gl.uniform2f(uniforms.uTexScale, usedSize[0], usedSize[1]);
|
gl.uniform2f(uniforms.uTexScale, usedSize[0], usedSize[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
setTransformSTUniform(uniforms: UniformMap, objectIndex: number) {
|
setTransformSTUniform(uniforms: UniformMap, objectIndex: number): void {
|
||||||
// FIXME(pcwalton): Lossy conversion from a 4x4 matrix to an ST matrix is ugly and fragile.
|
// FIXME(pcwalton): Lossy conversion from a 4x4 matrix to an ST matrix is ugly and fragile.
|
||||||
// Refactor.
|
// Refactor.
|
||||||
const renderContext = this.renderContext;
|
const renderContext = this.renderContext;
|
||||||
|
@ -219,7 +226,7 @@ export abstract class Renderer {
|
||||||
transform[13]);
|
transform[13]);
|
||||||
}
|
}
|
||||||
|
|
||||||
uploadPathColors(objectCount: number) {
|
uploadPathColors(objectCount: number): void {
|
||||||
const renderContext = this.renderContext;
|
const renderContext = this.renderContext;
|
||||||
for (let objectIndex = 0; objectIndex < objectCount; objectIndex++) {
|
for (let objectIndex = 0; objectIndex < objectCount; objectIndex++) {
|
||||||
const pathColors = this.pathColorsForObject(objectIndex);
|
const pathColors = this.pathColorsForObject(objectIndex);
|
||||||
|
@ -237,7 +244,7 @@ export abstract class Renderer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uploadPathTransforms(objectCount: number) {
|
uploadPathTransforms(objectCount: number): void {
|
||||||
const renderContext = this.renderContext;
|
const renderContext = this.renderContext;
|
||||||
for (let objectIndex = 0; objectIndex < objectCount; objectIndex++) {
|
for (let objectIndex = 0; objectIndex < objectCount; objectIndex++) {
|
||||||
const pathTransforms = this.pathTransformsForObject(objectIndex);
|
const pathTransforms = this.pathTransformsForObject(objectIndex);
|
||||||
|
@ -273,6 +280,18 @@ export abstract class Renderer {
|
||||||
return glmatrix.vec4.create();
|
return glmatrix.vec4.create();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected bindGammaLUT(bgColor: glmatrix.vec3, textureUnit: number, uniforms: UniformMap):
|
||||||
|
void {
|
||||||
|
const renderContext = this.renderContext;
|
||||||
|
const gl = renderContext.gl;
|
||||||
|
|
||||||
|
gl.activeTexture(gl.TEXTURE0 + textureUnit);
|
||||||
|
gl.bindTexture(gl.TEXTURE_2D, this.gammaLUTTexture);
|
||||||
|
gl.uniform1i(uniforms.uGammaLUT, textureUnit);
|
||||||
|
|
||||||
|
gl.uniform3f(uniforms.uBGColor, bgColor[0], bgColor[1], bgColor[2]);
|
||||||
|
}
|
||||||
|
|
||||||
protected abstract createAAStrategy(aaType: AntialiasingStrategyName,
|
protected abstract createAAStrategy(aaType: AntialiasingStrategyName,
|
||||||
aaLevel: number,
|
aaLevel: number,
|
||||||
subpixelAA: SubpixelAAType,
|
subpixelAA: SubpixelAAType,
|
||||||
|
@ -515,6 +534,12 @@ export abstract class Renderer {
|
||||||
const texture = unwrapNull(gl.createTexture());
|
const texture = unwrapNull(gl.createTexture());
|
||||||
gl.bindTexture(gl.TEXTURE_2D, texture);
|
gl.bindTexture(gl.TEXTURE_2D, texture);
|
||||||
gl.texImage2D(gl.TEXTURE_2D, 0, gl.LUMINANCE, gl.LUMINANCE, gl.UNSIGNED_BYTE, gammaLUT);
|
gl.texImage2D(gl.TEXTURE_2D, 0, gl.LUMINANCE, gl.LUMINANCE, gl.UNSIGNED_BYTE, gammaLUT);
|
||||||
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
|
||||||
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
|
||||||
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
||||||
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
||||||
|
|
||||||
|
this.gammaLUTTexture = texture;
|
||||||
}
|
}
|
||||||
|
|
||||||
private initImplicitCoverCurveVAO(objectIndex: number, instanceRange: Range): void {
|
private initImplicitCoverCurveVAO(objectIndex: number, instanceRange: Range): void {
|
||||||
|
|
|
@ -12,7 +12,8 @@ import {AttributeMap, UniformMap} from './gl-utils';
|
||||||
import {expectNotNull, PathfinderError, unwrapNull} from './utils';
|
import {expectNotNull, PathfinderError, unwrapNull} from './utils';
|
||||||
|
|
||||||
export interface ShaderMap<T> {
|
export interface ShaderMap<T> {
|
||||||
blit: T;
|
blitLinear: T;
|
||||||
|
blitGamma: T;
|
||||||
compositeAlphaMask: T;
|
compositeAlphaMask: T;
|
||||||
demo3DDistantGlyph: T;
|
demo3DDistantGlyph: T;
|
||||||
demo3DMonument: T;
|
demo3DMonument: T;
|
||||||
|
@ -43,7 +44,8 @@ export interface UnlinkedShaderProgram {
|
||||||
const COMMON_SHADER_URL: string = '/glsl/gles2/common.inc.glsl';
|
const COMMON_SHADER_URL: string = '/glsl/gles2/common.inc.glsl';
|
||||||
|
|
||||||
export const SHADER_NAMES: Array<keyof ShaderMap<void>> = [
|
export const SHADER_NAMES: Array<keyof ShaderMap<void>> = [
|
||||||
'blit',
|
'blitLinear',
|
||||||
|
'blitGamma',
|
||||||
'compositeAlphaMask',
|
'compositeAlphaMask',
|
||||||
'directCurve',
|
'directCurve',
|
||||||
'directInterior',
|
'directInterior',
|
||||||
|
@ -67,8 +69,12 @@ export const SHADER_NAMES: Array<keyof ShaderMap<void>> = [
|
||||||
];
|
];
|
||||||
|
|
||||||
const SHADER_URLS: ShaderMap<ShaderProgramURLs> = {
|
const SHADER_URLS: ShaderMap<ShaderProgramURLs> = {
|
||||||
blit: {
|
blitGamma: {
|
||||||
fragment: "/glsl/gles2/blit.fs.glsl",
|
fragment: "/glsl/gles2/blit-gamma.fs.glsl",
|
||||||
|
vertex: "/glsl/gles2/blit.vs.glsl",
|
||||||
|
},
|
||||||
|
blitLinear: {
|
||||||
|
fragment: "/glsl/gles2/blit-linear.fs.glsl",
|
||||||
vertex: "/glsl/gles2/blit.vs.glsl",
|
vertex: "/glsl/gles2/blit.vs.glsl",
|
||||||
},
|
},
|
||||||
compositeAlphaMask: {
|
compositeAlphaMask: {
|
||||||
|
|
|
@ -176,7 +176,7 @@ export default class SSAAStrategy extends AntialiasingStrategy {
|
||||||
if (this.subpixelAA !== 'none')
|
if (this.subpixelAA !== 'none')
|
||||||
resolveProgram = renderContext.shaderPrograms.ssaaSubpixelResolve;
|
resolveProgram = renderContext.shaderPrograms.ssaaSubpixelResolve;
|
||||||
else
|
else
|
||||||
resolveProgram = renderContext.shaderPrograms.blit;
|
resolveProgram = renderContext.shaderPrograms.blitLinear;
|
||||||
gl.useProgram(resolveProgram.program);
|
gl.useProgram(resolveProgram.program);
|
||||||
renderContext.initQuadVAO(resolveProgram.attributes);
|
renderContext.initQuadVAO(resolveProgram.attributes);
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ import * as opentype from 'opentype.js';
|
||||||
import {Metrics} from 'opentype.js';
|
import {Metrics} from 'opentype.js';
|
||||||
import {AntialiasingStrategy, AntialiasingStrategyName, NoAAStrategy} from "./aa-strategy";
|
import {AntialiasingStrategy, AntialiasingStrategyName, NoAAStrategy} from "./aa-strategy";
|
||||||
import {StemDarkeningMode, SubpixelAAType} from './aa-strategy';
|
import {StemDarkeningMode, SubpixelAAType} from './aa-strategy';
|
||||||
import {DemoAppController} from './app-controller';
|
import {AAOptions, DemoAppController} from './app-controller';
|
||||||
import {Atlas, ATLAS_SIZE, AtlasGlyph, GlyphKey, SUBPIXEL_GRANULARITY} from './atlas';
|
import {Atlas, ATLAS_SIZE, AtlasGlyph, GlyphKey, SUBPIXEL_GRANULARITY} from './atlas';
|
||||||
import PathfinderBufferTexture from './buffer-texture';
|
import PathfinderBufferTexture from './buffer-texture';
|
||||||
import {CameraView, OrthographicCamera} from "./camera";
|
import {CameraView, OrthographicCamera} from "./camera";
|
||||||
|
@ -379,10 +379,9 @@ class TextDemoRenderer extends TextRenderer {
|
||||||
|
|
||||||
setAntialiasingOptions(aaType: AntialiasingStrategyName,
|
setAntialiasingOptions(aaType: AntialiasingStrategyName,
|
||||||
aaLevel: number,
|
aaLevel: number,
|
||||||
subpixelAA: SubpixelAAType,
|
aaOptions: AAOptions):
|
||||||
stemDarkening: StemDarkeningMode):
|
|
||||||
void {
|
void {
|
||||||
super.setAntialiasingOptions(aaType, aaLevel, subpixelAA, stemDarkening);
|
super.setAntialiasingOptions(aaType, aaLevel, aaOptions);
|
||||||
|
|
||||||
// Need to relayout because changing AA options can cause font dilation to change...
|
// Need to relayout because changing AA options can cause font dilation to change...
|
||||||
this.layoutText();
|
this.layoutText();
|
||||||
|
@ -425,8 +424,11 @@ class TextDemoRenderer extends TextRenderer {
|
||||||
gl.clearColor(1.0, 1.0, 1.0, 1.0);
|
gl.clearColor(1.0, 1.0, 1.0, 1.0);
|
||||||
gl.clear(gl.COLOR_BUFFER_BIT);
|
gl.clear(gl.COLOR_BUFFER_BIT);
|
||||||
|
|
||||||
|
// Set the appropriate program.
|
||||||
|
const programName = this.gammaCorrectionMode === 'off' ? 'blitLinear' : 'blitGamma';
|
||||||
|
const blitProgram = this.renderContext.shaderPrograms[programName];
|
||||||
|
|
||||||
// Set up the composite VAO.
|
// Set up the composite VAO.
|
||||||
const blitProgram = this.renderContext.shaderPrograms.blit;
|
|
||||||
const attributes = blitProgram.attributes;
|
const attributes = blitProgram.attributes;
|
||||||
gl.useProgram(blitProgram.program);
|
gl.useProgram(blitProgram.program);
|
||||||
gl.bindBuffer(gl.ARRAY_BUFFER, this.glyphPositionsBuffer);
|
gl.bindBuffer(gl.ARRAY_BUFFER, this.glyphPositionsBuffer);
|
||||||
|
@ -458,6 +460,7 @@ class TextDemoRenderer extends TextRenderer {
|
||||||
gl.bindTexture(gl.TEXTURE_2D, destTexture);
|
gl.bindTexture(gl.TEXTURE_2D, destTexture);
|
||||||
gl.uniform1i(blitProgram.uniforms.uSource, 0);
|
gl.uniform1i(blitProgram.uniforms.uSource, 0);
|
||||||
this.setIdentityTexScaleUniform(blitProgram.uniforms);
|
this.setIdentityTexScaleUniform(blitProgram.uniforms);
|
||||||
|
this.bindGammaLUT(glmatrix.vec3.clone([1.0, 1.0, 1.0]), 1, blitProgram.uniforms);
|
||||||
const totalGlyphCount = this.layout.textFrame.totalGlyphCount;
|
const totalGlyphCount = this.layout.textFrame.totalGlyphCount;
|
||||||
gl.drawElements(gl.TRIANGLES, totalGlyphCount * 6, gl.UNSIGNED_INT, 0);
|
gl.drawElements(gl.TRIANGLES, totalGlyphCount * 6, gl.UNSIGNED_INT, 0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -386,10 +386,7 @@ export function computeStemDarkeningAmount(pixelsPerEm: number, pixelsPerUnit: n
|
||||||
return amount;
|
return amount;
|
||||||
|
|
||||||
glmatrix.vec2.scale(amount, STEM_DARKENING_FACTORS, pixelsPerEm);
|
glmatrix.vec2.scale(amount, STEM_DARKENING_FACTORS, pixelsPerEm);
|
||||||
glmatrix.vec2.min(amount, amount, MIN_STEM_DARKENING_AMOUNT);
|
glmatrix.vec2.max(amount, amount, MIN_STEM_DARKENING_AMOUNT);
|
||||||
|
|
||||||
// Convert diameter to radius.
|
|
||||||
glmatrix.vec2.scale(amount, amount, 0.5);
|
|
||||||
glmatrix.vec2.scale(amount, amount, 1.0 / pixelsPerUnit);
|
glmatrix.vec2.scale(amount, amount, 1.0 / pixelsPerUnit);
|
||||||
return amount;
|
return amount;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ import * as glmatrix from 'gl-matrix';
|
||||||
|
|
||||||
import {AntialiasingStrategy, AntialiasingStrategyName, NoAAStrategy} from "./aa-strategy";
|
import {AntialiasingStrategy, AntialiasingStrategyName, NoAAStrategy} from "./aa-strategy";
|
||||||
import {StemDarkeningMode, SubpixelAAType} from "./aa-strategy";
|
import {StemDarkeningMode, SubpixelAAType} from "./aa-strategy";
|
||||||
|
import {AAOptions} from './app-controller';
|
||||||
import PathfinderBufferTexture from './buffer-texture';
|
import PathfinderBufferTexture from './buffer-texture';
|
||||||
import {Camera} from "./camera";
|
import {Camera} from "./camera";
|
||||||
import {EXTDisjointTimerQuery, QUAD_ELEMENTS, UniformMap} from './gl-utils';
|
import {EXTDisjointTimerQuery, QUAD_ELEMENTS, UniformMap} from './gl-utils';
|
||||||
|
@ -153,15 +154,13 @@ export abstract class DemoView extends PathfinderView implements RenderContext {
|
||||||
meshData: PathfinderMeshData[];
|
meshData: PathfinderMeshData[];
|
||||||
|
|
||||||
get colorAlphaFormat(): GLenum {
|
get colorAlphaFormat(): GLenum {
|
||||||
return this.sRGBExt == null ? this.gl.RGBA : this.sRGBExt.SRGB_ALPHA_EXT;
|
return this.gl.RGBA;
|
||||||
}
|
}
|
||||||
|
|
||||||
get renderContext(): RenderContext {
|
get renderContext(): RenderContext {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected sRGBExt: EXTsRGB;
|
|
||||||
|
|
||||||
protected colorBufferHalfFloatExt: any;
|
protected colorBufferHalfFloatExt: any;
|
||||||
|
|
||||||
private wantsScreenshot: boolean;
|
private wantsScreenshot: boolean;
|
||||||
|
@ -204,9 +203,9 @@ export abstract class DemoView extends PathfinderView implements RenderContext {
|
||||||
|
|
||||||
setAntialiasingOptions(aaType: AntialiasingStrategyName,
|
setAntialiasingOptions(aaType: AntialiasingStrategyName,
|
||||||
aaLevel: number,
|
aaLevel: number,
|
||||||
subpixelAA: SubpixelAAType,
|
aaOptions: AAOptions):
|
||||||
stemDarkening: StemDarkeningMode) {
|
void {
|
||||||
this.renderer.setAntialiasingOptions(aaType, aaLevel, subpixelAA, stemDarkening);
|
this.renderer.setAntialiasingOptions(aaType, aaLevel, aaOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected resized(): void {
|
protected resized(): void {
|
||||||
|
@ -220,7 +219,6 @@ export abstract class DemoView extends PathfinderView implements RenderContext {
|
||||||
"Failed to initialize WebGL! Check that your browser supports it.");
|
"Failed to initialize WebGL! Check that your browser supports it.");
|
||||||
this.colorBufferHalfFloatExt = this.gl.getExtension('EXT_color_buffer_half_float');
|
this.colorBufferHalfFloatExt = this.gl.getExtension('EXT_color_buffer_half_float');
|
||||||
this.instancedArraysExt = this.gl.getExtension('ANGLE_instanced_arrays');
|
this.instancedArraysExt = this.gl.getExtension('ANGLE_instanced_arrays');
|
||||||
this.sRGBExt = this.gl.getExtension('EXT_sRGB');
|
|
||||||
this.textureHalfFloatExt = this.gl.getExtension('OES_texture_half_float');
|
this.textureHalfFloatExt = this.gl.getExtension('OES_texture_half_float');
|
||||||
this.timerQueryExt = this.gl.getExtension('EXT_disjoint_timer_query');
|
this.timerQueryExt = this.gl.getExtension('EXT_disjoint_timer_query');
|
||||||
this.vertexArrayObjectExt = this.gl.getExtension('OES_vertex_array_object');
|
this.vertexArrayObjectExt = this.gl.getExtension('OES_vertex_array_object');
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
// pathfinder/shaders/gles2/blit-gamma.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.
|
||||||
|
|
||||||
|
/// Blits a texture, applying gamma correction.
|
||||||
|
|
||||||
|
precision mediump float;
|
||||||
|
|
||||||
|
uniform sampler2D uSource;
|
||||||
|
|
||||||
|
uniform vec3 uBGColor;
|
||||||
|
uniform sampler2D uGammaLUT;
|
||||||
|
|
||||||
|
varying vec2 vTexCoord;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec4 source = texture2D(uSource, vTexCoord);
|
||||||
|
gl_FragColor = vec4(gammaCorrect(source.rgb, uBGColor, uGammaLUT), source.a);
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
// pathfinder/shaders/gles2/blit.fs.glsl
|
// pathfinder/shaders/gles2/blit-linear.fs.glsl
|
||||||
//
|
//
|
||||||
// Copyright (c) 2017 The Pathfinder Project Developers.
|
// Copyright (c) 2017 The Pathfinder Project Developers.
|
||||||
//
|
//
|
|
@ -306,6 +306,17 @@ float lcdFilter(float shadeL2, float shadeL1, float shade0, float shadeR1, float
|
||||||
LCD_FILTER_FACTOR_2 * shadeR2;
|
LCD_FILTER_FACTOR_2 * shadeR2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float gammaCorrectChannel(float fgColor, float bgColor, sampler2D gammaLUT) {
|
||||||
|
return texture2D(gammaLUT, vec2(fgColor, 1.0 - bgColor)).r;
|
||||||
|
}
|
||||||
|
|
||||||
|
// `fgColor` is in linear space.
|
||||||
|
vec3 gammaCorrect(vec3 fgColor, vec3 bgColor, sampler2D gammaLUT) {
|
||||||
|
return vec3(gammaCorrectChannel(fgColor.r, bgColor.r, gammaLUT),
|
||||||
|
gammaCorrectChannel(fgColor.g, bgColor.g, gammaLUT),
|
||||||
|
gammaCorrectChannel(fgColor.b, bgColor.b, gammaLUT));
|
||||||
|
}
|
||||||
|
|
||||||
int unpackUInt16(vec2 packedValue) {
|
int unpackUInt16(vec2 packedValue) {
|
||||||
ivec2 valueBytes = ivec2(floor(packedValue * 255.0));
|
ivec2 valueBytes = ivec2(floor(packedValue * 255.0));
|
||||||
return valueBytes.y * 256 + valueBytes.x;
|
return valueBytes.y * 256 + valueBytes.x;
|
||||||
|
|
Loading…
Reference in New Issue