106 lines
3.7 KiB
TypeScript
106 lines
3.7 KiB
TypeScript
namespace TSE {
|
|
|
|
export abstract class Shader {
|
|
private _name: string;
|
|
private _program: WebGLProgram;
|
|
private _attributes: { [name: string]: number } = {};
|
|
private _uniforms: { [name: string]: WebGLUniformLocation } = {};
|
|
|
|
/**
|
|
* Create a new Shader.
|
|
* @param name The name of the Shader.
|
|
* @param vertexSource The source of the VertexShader
|
|
* @param fragementSource The source of the FragmentShader
|
|
*/
|
|
public constructor(name: string) {
|
|
this._name = name;
|
|
}
|
|
|
|
protected setSource(vertexSource: string, fragementSource: string): void {
|
|
let vertexShader = this.loadShader(vertexSource, gl.VERTEX_SHADER);
|
|
let fragmentShader = this.loadShader(fragementSource, gl.FRAGMENT_SHADER);
|
|
this.createProgram(vertexShader, fragmentShader);
|
|
|
|
this.detectAtrributes();
|
|
this.detectUniforms();
|
|
}
|
|
|
|
/** Use this Shader. */
|
|
public use(): void {
|
|
gl.useProgram(this._program);
|
|
}
|
|
|
|
private loadShader(source: string, shaderType: number): WebGLShader {
|
|
let shader: WebGLShader = gl.createShader(shaderType);
|
|
|
|
gl.shaderSource(shader, source);
|
|
gl.compileShader(shader);
|
|
|
|
const error = gl.getShaderInfoLog(shader);
|
|
if (error != "")
|
|
throw new Error("Error compiling shader '" + this._name + "': " + error);
|
|
|
|
return shader;
|
|
}
|
|
|
|
/** The name of this Shader. */
|
|
public get name(): string { return this._name; }
|
|
|
|
/**
|
|
* Get the Location of an Attribute with the provided Name.
|
|
* @param name The name of the Attribute.
|
|
*/
|
|
public getAttributeLocation(name: string): number {
|
|
if (this._attributes[name] === undefined) throw new Error(`Unable to find Attribute '${name}' in shader '${this._name}'`);
|
|
|
|
return this._attributes[name];
|
|
}
|
|
|
|
/**
|
|
* Get the Location of an Uniform with the provided Name.
|
|
* @param name The name of the Uniform.
|
|
*/
|
|
public getUniformLocation(name: string): WebGLUniformLocation {
|
|
if (this._uniforms[name] === undefined) throw new Error(`Unable to find Uniform '${name}' in shader '${this._name}'`);
|
|
|
|
return this._uniforms[name];
|
|
}
|
|
|
|
private createProgram(vertexShader: WebGLShader, fragmentShader: WebGLShader): void {
|
|
this._program = gl.createProgram();
|
|
|
|
gl.attachShader(this._program, vertexShader);
|
|
gl.attachShader(this._program, fragmentShader);
|
|
|
|
gl.linkProgram(this._program);
|
|
|
|
const error = gl.getProgramInfoLog(this._program);
|
|
if (error != "")
|
|
throw new Error("Error linking shader '" + this._name + "': " + error);
|
|
}
|
|
|
|
private detectAtrributes(): void {
|
|
let attributeCount = gl.getProgramParameter(this._program, gl.ACTIVE_ATTRIBUTES);
|
|
|
|
for (let i = 0; i < attributeCount; i++) {
|
|
let attributeInfo: WebGLActiveInfo = gl.getActiveAttrib(this._program, i);
|
|
if (!attributeInfo) break;
|
|
|
|
this._attributes[attributeInfo.name] = gl.getAttribLocation(this._program, attributeInfo.name);
|
|
}
|
|
}
|
|
|
|
private detectUniforms(): void {
|
|
let uniformCount = gl.getProgramParameter(this._program, gl.ACTIVE_UNIFORMS);
|
|
|
|
for (let i = 0; i < uniformCount; i++) {
|
|
let uniformInfo: WebGLActiveInfo = gl.getActiveUniform(this._program, i);
|
|
if (!uniformInfo) break;
|
|
|
|
this._uniforms[uniformInfo.name] = gl.getUniformLocation(this._program, uniformInfo.name);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
} |