pathfinder/demo/client/src/shader-loader.ts

202 lines
6.7 KiB
TypeScript
Raw Normal View History

2017-11-08 15:20:57 -05:00
// pathfinder/demo/client/src/shader-loader.ts
//
// 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.
import {AttributeMap, UniformMap} from './gl-utils';
2017-09-28 17:34:48 -04:00
import {expectNotNull, PathfinderError, unwrapNull} from './utils';
export interface ShaderMap<T> {
blitLinear: T;
blitGamma: T;
conservativeInterior: T;
demo3DDistantGlyph: T;
demo3DMonument: T;
directCurve: T;
directInterior: T;
direct3DCurve: T;
direct3DInterior: T;
ecaaLine: T;
ecaaCurve: T;
ecaaTransformedCurve: T;
mcaa: T;
ssaaSubpixelResolve: T;
xcaaMonoResolve: T;
xcaaMonoSubpixelResolve: T;
}
export interface UnlinkedShaderProgram {
vertex: WebGLShader;
fragment: WebGLShader;
}
const COMMON_SHADER_URL: string = '/glsl/gles2/common.inc.glsl';
export const SHADER_NAMES: Array<keyof ShaderMap<void>> = [
'blitLinear',
'blitGamma',
'conservativeInterior',
'directCurve',
'directInterior',
2017-09-05 22:47:19 -04:00
'direct3DCurve',
'direct3DInterior',
'ssaaSubpixelResolve',
'mcaa',
'ecaaLine',
'ecaaCurve',
'ecaaTransformedCurve',
'xcaaMonoResolve',
'xcaaMonoSubpixelResolve',
'demo3DDistantGlyph',
'demo3DMonument',
];
const SHADER_URLS: ShaderMap<ShaderProgramURLs> = {
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",
},
conservativeInterior: {
fragment: "/glsl/gles2/direct-interior.fs.glsl",
vertex: "/glsl/gles2/conservative-interior.vs.glsl",
},
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-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-28 17:34:48 -04:00
directInterior: {
fragment: "/glsl/gles2/direct-interior.fs.glsl",
vertex: "/glsl/gles2/direct-interior.vs.glsl",
},
ecaaCurve: {
fragment: "/glsl/gles2/ecaa-curve.fs.glsl",
2017-09-28 17:34:48 -04:00
vertex: "/glsl/gles2/ecaa-curve.vs.glsl",
},
ecaaLine: {
fragment: "/glsl/gles2/ecaa-line.fs.glsl",
2017-09-28 17:34:48 -04:00
vertex: "/glsl/gles2/ecaa-line.vs.glsl",
},
ecaaTransformedCurve: {
fragment: "/glsl/gles2/ecaa-curve.fs.glsl",
vertex: "/glsl/gles2/ecaa-transformed-curve.vs.glsl",
},
mcaa: {
fragment: "/glsl/gles2/mcaa.fs.glsl",
vertex: "/glsl/gles2/mcaa.vs.glsl",
},
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",
},
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",
},
};
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 {
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 = [];
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] })));
}
this.shaders = Promise.all(promises).then(promises => {
2017-09-28 17:34:48 -04:00
const shaderMap: Partial<ShaderMap<ShaderProgramSource>> = {};
for (let keyIndex = 0; keyIndex < shaderKeys.length; keyIndex++)
shaderMap[shaderKeys[keyIndex]] = promises[keyIndex];
return shaderMap as ShaderMap<ShaderProgramSource>;
});
}
}
export class PathfinderShaderProgram {
2017-09-28 17:34:48 -04:00
readonly uniforms: UniformMap;
readonly attributes: AttributeMap;
readonly program: WebGLProgram;
readonly programName: string;
2017-09-28 17:34:48 -04:00
constructor(gl: WebGLRenderingContext,
programName: string,
unlinkedShaderProgram: UnlinkedShaderProgram) {
this.programName = programName;
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) {
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 = {};
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;
}
}