wggl
Version:
A friendly interface to shaders
92 lines (91 loc) • 4.63 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
var uniform_1 = require("./uniform");
var primitives_1 = require("./primitives");
// Bakes a vertex and fragment shader into a canvas and returns an object
// for operating with the resulting webgl program
var WgglProgram = /** @class */ (function () {
function WgglProgram(canvas, bindPointers, program) {
this.canvas = canvas;
this.bindPointers = bindPointers;
this.program = program;
this.gl = canvas.getContext("webgl");
}
WgglProgram.prototype.draw = function (values, drawMode, offset, size, keepCurrentViewport) {
var _this = this;
if (drawMode === void 0) { drawMode = primitives_1.DrawModes.TRIANGLE_STRIP; }
if (offset === void 0) { offset = 0; }
if (size === void 0) { size = 4; }
if (keepCurrentViewport === void 0) { keepCurrentViewport = false; }
var _a = this, canvas = _a.canvas, gl = _a.gl;
var textureCounter = 0;
if (!keepCurrentViewport)
gl.useProgram(this.program);
// Pass values to the GPU
Object.keys(values).forEach(function (key) {
var value = values[key];
var attr = _this.bindPointers[key];
switch (attr.parameters.glType) {
case primitives_1.GlType.attribute:
gl.enableVertexAttribArray(attr.location);
gl.bindBuffer(gl.ARRAY_BUFFER, attr.buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(value), gl.STATIC_DRAW);
var _a = attr.parameters, size_1 = _a.size, normalize = _a.normalize, stride = _a.stride, offset_1 = _a.offset;
gl.vertexAttribPointer(attr.location, size_1, gl.FLOAT, normalize, stride, offset_1);
break;
case primitives_1.GlType.uniform:
// TODO: Could be simplified by making the UniformType valies the single characters
var typeModifier = attr.parameters.type === uniform_1.UniformType.float ? "f" : "i";
if (isAnyArray(value)) {
if (value.length > 4) {
throw new Error("Value of uniform type has more than the maximum four dimensions");
}
// Dynamic GL method name, (e.g., gl.uniform4fv)
gl["uniform" + value.length + typeModifier + "v"](attr.location, value);
}
else if (value instanceof WebGLTexture && gl.isTexture(value)) {
// bind texture
gl.activeTexture(gl.TEXTURE0 + textureCounter);
gl.bindTexture(gl.TEXTURE_2D, value);
gl.uniform1i(attr.location, textureCounter);
textureCounter++;
}
else if (typeof value !== "number" && typeof value !== "boolean") {
throw new Error("Value of uniform type must be a number, boolean, or array");
}
else {
gl["uniform1" + typeModifier](attr.location, value);
}
break;
}
});
// Draw
if (!keepCurrentViewport) {
gl.viewport(0, 0, canvas.width, canvas.height);
}
gl.drawArrays(gl[drawMode], offset, size);
};
WgglProgram.prototype.drawTo = function (buffer, values, drawMode, offset, size) {
if (drawMode === void 0) { drawMode = primitives_1.DrawModes.TRIANGLE_STRIP; }
if (offset === void 0) { offset = 0; }
if (size === void 0) { size = 4; }
var gl = this.gl;
var texture = buffer.texture;
// Use the provided program to draw to the provided buffer
gl.useProgram(this.program);
gl.bindFramebuffer(gl.FRAMEBUFFER, buffer.buffer);
gl.viewport(0, 0, texture.width, texture.height);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl[buffer.attachment], gl[buffer.target], texture.texture, gl[buffer.level]);
this.draw(values, drawMode, offset, size, true);
// Reset the draw buffer to the screen
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
};
return WgglProgram;
}());
exports.WgglProgram = WgglProgram;
function isAnyArray(arr) {
if (arr == null)
return false;
// True when arr is any of the typed arrays or the basic array
return /^(Float(32|64)|Int(8|16|32)|Uint(8(Clamped)?|16|32|))?Array$/.test(arr.constructor.name);
}