import { webGLShader } from './utils/webglShader';
import { Uniform } from './uniform';
import {
FLOAT,
FLOAT_VEC2,
FLOAT_VEC3,
FLOAT_VEC4,
TEXTURE_2D,
SAMPLER_2D,
VERTEX_SHADER,
FRAGMENT_SHADER,
LINK_STATUS,
ACTIVE_UNIFORMS,
ACTIVE_ATTRIBUTES,
FLOAT_MAT2,
FLOAT_MAT3,
FLOAT_MAT4
} from 'tubugl-constants';
export class Program {
/**
* constructor
* compile shaders and link them to gl context
*
* @param {WebGLRenderingContext} gl
* @param {string} vertSrc
* @param {string} fragSrc
* @param {Object} params
* @param {booean} params.isDebug
*
* @constructor Program
*/
constructor(gl, vertSrc, fragSrc, params = {}) {
/**
* @private
* @member {boolean}
*/
this._isReady = false;
/**
* @private
* @member {boolean}
*/
this._isDebgu = params.isDebug;
/**
* @private
* @member {WebGLRenderingContext}
*/
this._gl = gl;
if (vertSrc && fragSrc) {
this.initProgram(vertSrc, fragSrc, params);
}
}
/**
* crate the program and compile shader
*
* @param {string} vertSrc vertex hader
* @param {string} fragSrc fragment shader src
* @param {Object} params optinal paramters
*/
initProgram(vertSrc, fragSrc, params = {}) {
/**
* @description vertexShader
* @private
* @member {WebGLShader}
*/
this._vertexShader = webGLShader(this._gl, VERTEX_SHADER, vertSrc);
/**
* @description fragmentShader
* @private
* @member {WebGLShader}
*/
this._fragmentShader = webGLShader(this._gl, FRAGMENT_SHADER, fragSrc);
/**
* @description program
* @private
* @member {WebGLProgram}
*/
this._program = this._gl.createProgram();
this._gl.attachShader(this._program, this._vertexShader);
this._gl.attachShader(this._program, this._fragmentShader);
this._gl.linkProgram(this._program);
try {
let success = this._gl.getProgramParameter(this._program, LINK_STATUS);
if (!success) throw this._gl.getProgramInfoLog(this._program);
} catch (error) {
console.error(`WebGLProgram: ${error}`);
}
this._setProperties();
}
/**
* set properties such as uniforms and attributes
* @private
*/
_setProperties() {
let ii;
// uniforms
const uniformNumber = this._gl.getProgramParameter(this._program, ACTIVE_UNIFORMS);
/**
* @member {object}
*/
this.uniform = {};
for (ii = 0; ii < uniformNumber; ii++) {
let uniformInfo = this._gl.getActiveUniform(this._program, ii);
this.uniform[uniformInfo.name] = new Uniform(this._gl, this._program, uniformInfo);
}
//attributes
const attributreNumber = this._gl.getProgramParameter(this._program, ACTIVE_ATTRIBUTES);
/**
* @member {object}
*/
this.attrib = {};
for (ii = 0; ii < attributreNumber; ii++) {
let attrib = this._gl.getActiveAttrib(this._program, ii);
this.attrib[attrib.name] = {
location: this._gl.getAttribLocation(this._program, attrib.name),
type: attrib.type,
size: attrib.size
};
}
return this;
}
/**
* use program, as same function as bind()
*/
use() {
return this.bind();
}
/**
* use program, as same function as use()
*/
bind() {
this._gl.useProgram(this._program);
return this;
}
/**
* get the value of the attribute of program(it will be remove)
*
* @param {string} name name of attributes
*/
getAttrib(name) {
return this.attrib[name];
}
/**
* get the value of uniform of program(it will be removed)
* @param {string} name name of uniforms
*/
getUniforms(name) {
return this.uniform[name];
}
/**
* set texture as uniform
* @param {Texture} texture
* @param {String} uniformName
*/
setUniformTexture(texture, uniformName) {
let { textureNum } = texture;
this.uniform[uniformName].update(textureNum);
}
/**
* dispose program
*/
dispose() {
if (this._gl === null) return;
this._gl.deleteProgram(this._program);
this._gl.deleteShader(this._vertexShader);
this._gl.deleteShader(this._fragmentShader);
this._gl = null;
}
}