2017-11-08 15:20:57 -05:00
|
|
|
// pathfinder/demo/client/src/shader-loader.ts
|
2017-08-26 15:54:25 -04:00
|
|
|
//
|
|
|
|
// Copyright © 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.
|
|
|
|
|
2017-08-26 16:47:18 -04:00
|
|
|
import {AttributeMap, UniformMap} from './gl-utils';
|
2017-09-28 17:34:48 -04:00
|
|
|
import {expectNotNull, PathfinderError, unwrapNull} from './utils';
|
2017-08-26 16:47:18 -04:00
|
|
|
|
2017-10-21 01:04:53 -04:00
|
|
|
export interface ShaderMap<T> {
|
2017-11-07 20:24:19 -05:00
|
|
|
blitLinear: T;
|
|
|
|
blitGamma: T;
|
2017-11-01 19:09:58 -04:00
|
|
|
compositeAlphaMask: T;
|
2017-10-21 01:04:53 -04:00
|
|
|
demo3DDistantGlyph: T;
|
|
|
|
demo3DMonument: T;
|
|
|
|
directCurve: T;
|
|
|
|
directInterior: T;
|
|
|
|
direct3DCurve: T;
|
|
|
|
direct3DInterior: T;
|
|
|
|
ecaaLine: T;
|
|
|
|
ecaaCurve: T;
|
2017-12-03 16:20:46 -05:00
|
|
|
ecaaTransformedCurve: T;
|
2017-10-21 01:04:53 -04:00
|
|
|
mcaaCover: T;
|
|
|
|
mcaaLine: T;
|
|
|
|
mcaaCurve: T;
|
|
|
|
ssaaSubpixelResolve: T;
|
|
|
|
xcaaMonoResolve: T;
|
|
|
|
xcaaMonoSubpixelResolve: T;
|
2017-10-31 15:41:38 -04:00
|
|
|
xcaaMultiDirectCurve: T;
|
|
|
|
xcaaMultiDirectInterior: T;
|
2017-10-30 16:34:55 -04:00
|
|
|
xcaaMultiEdgeMaskCurve: T;
|
2017-12-03 16:20:46 -05:00
|
|
|
xcaaMultiEdgeMaskTransformedCurve: T;
|
2017-10-30 16:34:55 -04:00
|
|
|
xcaaMultiEdgeMaskLine: T;
|
2017-10-21 01:04:53 -04:00
|
|
|
xcaaMultiResolve: T;
|
|
|
|
}
|
|
|
|
|
2017-08-26 16:47:18 -04:00
|
|
|
export interface UnlinkedShaderProgram {
|
|
|
|
vertex: WebGLShader;
|
|
|
|
fragment: WebGLShader;
|
|
|
|
}
|
|
|
|
|
2017-08-26 15:54:25 -04:00
|
|
|
const COMMON_SHADER_URL: string = '/glsl/gles2/common.inc.glsl';
|
|
|
|
|
|
|
|
export const SHADER_NAMES: Array<keyof ShaderMap<void>> = [
|
2017-11-07 20:24:19 -05:00
|
|
|
'blitLinear',
|
|
|
|
'blitGamma',
|
2017-11-01 19:09:58 -04:00
|
|
|
'compositeAlphaMask',
|
2017-08-26 15:54:25 -04:00
|
|
|
'directCurve',
|
|
|
|
'directInterior',
|
2017-09-05 22:47:19 -04:00
|
|
|
'direct3DCurve',
|
|
|
|
'direct3DInterior',
|
2017-09-06 19:32:11 -04:00
|
|
|
'ssaaSubpixelResolve',
|
2017-10-09 17:14:24 -04:00
|
|
|
'mcaaCover',
|
|
|
|
'mcaaLine',
|
|
|
|
'mcaaCurve',
|
2017-08-26 15:54:25 -04:00
|
|
|
'ecaaLine',
|
|
|
|
'ecaaCurve',
|
2017-12-03 16:20:46 -05:00
|
|
|
'ecaaTransformedCurve',
|
2017-10-09 17:14:24 -04:00
|
|
|
'xcaaMonoResolve',
|
|
|
|
'xcaaMonoSubpixelResolve',
|
2017-10-31 15:41:38 -04:00
|
|
|
'xcaaMultiDirectCurve',
|
|
|
|
'xcaaMultiDirectInterior',
|
2017-10-30 16:34:55 -04:00
|
|
|
'xcaaMultiEdgeMaskCurve',
|
2017-12-03 16:20:46 -05:00
|
|
|
'xcaaMultiEdgeMaskTransformedCurve',
|
2017-10-30 16:34:55 -04:00
|
|
|
'xcaaMultiEdgeMaskLine',
|
2017-10-09 17:14:24 -04:00
|
|
|
'xcaaMultiResolve',
|
2017-10-17 18:30:33 -04:00
|
|
|
'demo3DDistantGlyph',
|
2017-09-03 22:24:28 -04:00
|
|
|
'demo3DMonument',
|
2017-08-26 15:54:25 -04:00
|
|
|
];
|
|
|
|
|
|
|
|
const SHADER_URLS: ShaderMap<ShaderProgramURLs> = {
|
2017-11-07 20:24:19 -05:00
|
|
|
blitGamma: {
|
|
|
|
fragment: "/glsl/gles2/blit-gamma.fs.glsl",
|
|
|
|
vertex: "/glsl/gles2/blit.vs.glsl",
|
|
|
|
},
|
|
|
|
blitLinear: {
|
|
|
|
fragment: "/glsl/gles2/blit-linear.fs.glsl",
|
2017-09-28 17:34:48 -04:00
|
|
|
vertex: "/glsl/gles2/blit.vs.glsl",
|
2017-08-26 15:54:25 -04:00
|
|
|
},
|
2017-11-01 19:09:58 -04:00
|
|
|
compositeAlphaMask: {
|
|
|
|
fragment: "/glsl/gles2/composite-alpha-mask.fs.glsl",
|
|
|
|
vertex: "/glsl/gles2/composite-alpha-mask.vs.glsl",
|
|
|
|
},
|
2017-10-17 18:30:33 -04:00
|
|
|
demo3DDistantGlyph: {
|
|
|
|
fragment: "/glsl/gles2/demo-3d-distant-glyph.fs.glsl",
|
|
|
|
vertex: "/glsl/gles2/demo-3d-distant-glyph.vs.glsl",
|
|
|
|
},
|
2017-09-28 17:34:48 -04:00
|
|
|
demo3DMonument: {
|
|
|
|
fragment: "/glsl/gles2/demo-3d-monument.fs.glsl",
|
|
|
|
vertex: "/glsl/gles2/demo-3d-monument.vs.glsl",
|
2017-08-26 15:54:25 -04:00
|
|
|
},
|
2017-09-05 22:47:19 -04:00
|
|
|
direct3DCurve: {
|
|
|
|
fragment: "/glsl/gles2/direct-curve.fs.glsl",
|
2017-09-28 17:34:48 -04:00
|
|
|
vertex: "/glsl/gles2/direct-3d-curve.vs.glsl",
|
2017-09-05 22:47:19 -04:00
|
|
|
},
|
|
|
|
direct3DInterior: {
|
|
|
|
fragment: "/glsl/gles2/direct-interior.fs.glsl",
|
2017-09-28 17:34:48 -04:00
|
|
|
vertex: "/glsl/gles2/direct-3d-interior.vs.glsl",
|
2017-09-05 22:47:19 -04:00
|
|
|
},
|
2017-09-28 17:34:48 -04:00
|
|
|
directCurve: {
|
|
|
|
fragment: "/glsl/gles2/direct-curve.fs.glsl",
|
|
|
|
vertex: "/glsl/gles2/direct-curve.vs.glsl",
|
2017-09-06 19:32:11 -04:00
|
|
|
},
|
2017-09-28 17:34:48 -04:00
|
|
|
directInterior: {
|
|
|
|
fragment: "/glsl/gles2/direct-interior.fs.glsl",
|
|
|
|
vertex: "/glsl/gles2/direct-interior.vs.glsl",
|
2017-08-26 15:54:25 -04:00
|
|
|
},
|
|
|
|
ecaaCurve: {
|
2017-10-09 17:14:24 -04:00
|
|
|
fragment: "/glsl/gles2/xcaa-curve.fs.glsl",
|
2017-09-28 17:34:48 -04:00
|
|
|
vertex: "/glsl/gles2/ecaa-curve.vs.glsl",
|
|
|
|
},
|
|
|
|
ecaaLine: {
|
2017-10-09 17:14:24 -04:00
|
|
|
fragment: "/glsl/gles2/xcaa-line.fs.glsl",
|
2017-09-28 17:34:48 -04:00
|
|
|
vertex: "/glsl/gles2/ecaa-line.vs.glsl",
|
2017-08-26 15:54:25 -04:00
|
|
|
},
|
2017-12-03 16:20:46 -05:00
|
|
|
ecaaTransformedCurve: {
|
|
|
|
fragment: "/glsl/gles2/xcaa-curve.fs.glsl",
|
|
|
|
vertex: "/glsl/gles2/ecaa-transformed-curve.vs.glsl",
|
|
|
|
},
|
2017-10-09 17:14:24 -04:00
|
|
|
mcaaCover: {
|
|
|
|
fragment: "/glsl/gles2/mcaa-cover.fs.glsl",
|
|
|
|
vertex: "/glsl/gles2/mcaa-cover.vs.glsl",
|
2017-08-26 15:54:25 -04:00
|
|
|
},
|
2017-10-09 17:14:24 -04:00
|
|
|
mcaaCurve: {
|
|
|
|
fragment: "/glsl/gles2/xcaa-curve.fs.glsl",
|
|
|
|
vertex: "/glsl/gles2/mcaa-curve.vs.glsl",
|
2017-09-07 17:58:41 -04:00
|
|
|
},
|
2017-10-09 17:14:24 -04:00
|
|
|
mcaaLine: {
|
|
|
|
fragment: "/glsl/gles2/xcaa-line.fs.glsl",
|
|
|
|
vertex: "/glsl/gles2/mcaa-line.vs.glsl",
|
2017-08-26 15:54:25 -04:00
|
|
|
},
|
2017-09-28 17:34:48 -04:00
|
|
|
ssaaSubpixelResolve: {
|
|
|
|
fragment: "/glsl/gles2/ssaa-subpixel-resolve.fs.glsl",
|
2017-11-15 17:36:59 -05:00
|
|
|
vertex: "/glsl/gles2/blit.vs.glsl",
|
2017-09-03 22:24:28 -04:00
|
|
|
},
|
2017-10-09 17:14:24 -04:00
|
|
|
xcaaMonoResolve: {
|
|
|
|
fragment: "/glsl/gles2/xcaa-mono-resolve.fs.glsl",
|
|
|
|
vertex: "/glsl/gles2/xcaa-mono-resolve.vs.glsl",
|
|
|
|
},
|
|
|
|
xcaaMonoSubpixelResolve: {
|
|
|
|
fragment: "/glsl/gles2/xcaa-mono-subpixel-resolve.fs.glsl",
|
|
|
|
vertex: "/glsl/gles2/xcaa-mono-subpixel-resolve.vs.glsl",
|
|
|
|
},
|
2017-10-31 15:41:38 -04:00
|
|
|
xcaaMultiDirectCurve: {
|
|
|
|
fragment: "/glsl/gles2/xcaa-multi-direct-curve.fs.glsl",
|
|
|
|
vertex: "/glsl/gles2/xcaa-multi-direct-curve.vs.glsl",
|
2017-10-30 16:34:55 -04:00
|
|
|
},
|
2017-10-31 15:41:38 -04:00
|
|
|
xcaaMultiDirectInterior: {
|
|
|
|
fragment: "/glsl/gles2/xcaa-multi-direct-interior.fs.glsl",
|
|
|
|
vertex: "/glsl/gles2/xcaa-multi-direct-interior.vs.glsl",
|
2017-10-21 01:04:53 -04:00
|
|
|
},
|
2017-10-30 16:34:55 -04:00
|
|
|
xcaaMultiEdgeMaskCurve: {
|
|
|
|
fragment: "/glsl/gles2/xcaa-multi-edge-mask-curve.fs.glsl",
|
2017-11-28 20:05:59 -05:00
|
|
|
vertex: "/glsl/gles2/ecaa-multi-edge-mask-curve.vs.glsl",
|
2017-10-30 16:34:55 -04:00
|
|
|
},
|
|
|
|
xcaaMultiEdgeMaskLine: {
|
|
|
|
fragment: "/glsl/gles2/xcaa-multi-edge-mask-line.fs.glsl",
|
2017-11-28 20:05:59 -05:00
|
|
|
vertex: "/glsl/gles2/ecaa-multi-edge-mask-line.vs.glsl",
|
2017-10-21 01:04:53 -04:00
|
|
|
},
|
2017-12-03 16:20:46 -05:00
|
|
|
xcaaMultiEdgeMaskTransformedCurve: {
|
|
|
|
fragment: "/glsl/gles2/xcaa-multi-edge-mask-curve.fs.glsl",
|
|
|
|
vertex: "/glsl/gles2/ecaa-multi-edge-mask-transformed-curve.vs.glsl",
|
|
|
|
},
|
2017-10-09 17:14:24 -04:00
|
|
|
xcaaMultiResolve: {
|
|
|
|
fragment: "/glsl/gles2/xcaa-multi-resolve.fs.glsl",
|
|
|
|
vertex: "/glsl/gles2/xcaa-multi-resolve.vs.glsl",
|
|
|
|
},
|
2017-08-26 15:54:25 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
export interface ShaderProgramSource {
|
|
|
|
vertex: string;
|
|
|
|
fragment: string;
|
|
|
|
}
|
|
|
|
|
|
|
|
interface ShaderProgramURLs {
|
|
|
|
vertex: string;
|
|
|
|
fragment: string;
|
|
|
|
}
|
|
|
|
|
|
|
|
export class ShaderLoader {
|
2017-09-28 17:34:48 -04:00
|
|
|
common: Promise<string>;
|
|
|
|
shaders: Promise<ShaderMap<ShaderProgramSource>>;
|
|
|
|
|
2017-11-07 17:13:13 -05:00
|
|
|
load(): void {
|
2017-08-26 15:54:25 -04:00
|
|
|
this.common = window.fetch(COMMON_SHADER_URL).then(response => response.text());
|
|
|
|
|
|
|
|
const shaderKeys = Object.keys(SHADER_URLS) as Array<keyof ShaderMap<string>>;
|
2017-09-28 17:34:48 -04:00
|
|
|
const promises = [];
|
2017-08-26 15:54:25 -04:00
|
|
|
for (const shaderKey of shaderKeys) {
|
|
|
|
promises.push(Promise.all([
|
|
|
|
window.fetch(SHADER_URLS[shaderKey].vertex).then(response => response.text()),
|
|
|
|
window.fetch(SHADER_URLS[shaderKey].fragment).then(response => response.text()),
|
2017-09-28 17:34:48 -04:00
|
|
|
]).then(results => ({ vertex: results[0], fragment: results[1] })));
|
2017-08-26 15:54:25 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
this.shaders = Promise.all(promises).then(promises => {
|
2017-09-28 17:34:48 -04:00
|
|
|
const shaderMap: Partial<ShaderMap<ShaderProgramSource>> = {};
|
2017-08-26 15:54:25 -04:00
|
|
|
for (let keyIndex = 0; keyIndex < shaderKeys.length; keyIndex++)
|
|
|
|
shaderMap[shaderKeys[keyIndex]] = promises[keyIndex];
|
|
|
|
return shaderMap as ShaderMap<ShaderProgramSource>;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
2017-08-26 16:47:18 -04:00
|
|
|
|
|
|
|
export class PathfinderShaderProgram {
|
2017-09-28 17:34:48 -04:00
|
|
|
readonly uniforms: UniformMap;
|
|
|
|
readonly attributes: AttributeMap;
|
|
|
|
readonly program: WebGLProgram;
|
2017-11-23 00:10:51 -05:00
|
|
|
readonly programName: string;
|
2017-09-28 17:34:48 -04:00
|
|
|
|
2017-08-26 16:47:18 -04:00
|
|
|
constructor(gl: WebGLRenderingContext,
|
|
|
|
programName: string,
|
|
|
|
unlinkedShaderProgram: UnlinkedShaderProgram) {
|
2017-11-23 00:10:51 -05:00
|
|
|
this.programName = programName;
|
|
|
|
|
2017-08-26 16:47:18 -04:00
|
|
|
this.program = expectNotNull(gl.createProgram(), "Failed to create shader program!");
|
|
|
|
for (const compiledShader of Object.values(unlinkedShaderProgram))
|
|
|
|
gl.attachShader(this.program, compiledShader);
|
|
|
|
gl.linkProgram(this.program);
|
|
|
|
|
2017-09-28 17:34:48 -04:00
|
|
|
if (gl.getProgramParameter(this.program, gl.LINK_STATUS) === 0) {
|
2017-08-26 16:47:18 -04:00
|
|
|
const infoLog = gl.getProgramInfoLog(this.program);
|
|
|
|
throw new PathfinderError(`Failed to link program "${programName}":\n${infoLog}`);
|
|
|
|
}
|
|
|
|
|
|
|
|
const uniformCount = gl.getProgramParameter(this.program, gl.ACTIVE_UNIFORMS);
|
|
|
|
const attributeCount = gl.getProgramParameter(this.program, gl.ACTIVE_ATTRIBUTES);
|
|
|
|
|
2017-09-28 17:34:48 -04:00
|
|
|
const uniforms: UniformMap = {};
|
|
|
|
const attributes: AttributeMap = {};
|
2017-08-26 16:47:18 -04:00
|
|
|
|
|
|
|
for (let uniformIndex = 0; uniformIndex < uniformCount; uniformIndex++) {
|
|
|
|
const uniformName = unwrapNull(gl.getActiveUniform(this.program, uniformIndex)).name;
|
|
|
|
uniforms[uniformName] = expectNotNull(gl.getUniformLocation(this.program, uniformName),
|
|
|
|
`Didn't find uniform "${uniformName}"!`);
|
|
|
|
}
|
|
|
|
for (let attributeIndex = 0; attributeIndex < attributeCount; attributeIndex++) {
|
|
|
|
const attributeName = unwrapNull(gl.getActiveAttrib(this.program, attributeIndex)).name;
|
|
|
|
attributes[attributeName] = attributeIndex;
|
|
|
|
}
|
|
|
|
|
|
|
|
this.uniforms = uniforms;
|
|
|
|
this.attributes = attributes;
|
|
|
|
}
|
|
|
|
}
|