molstar
Version:
A comprehensive macromolecular library.
194 lines • 8.05 kB
JavaScript
/**
* Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.createProgram = exports.getProgram = void 0;
var shader_code_1 = require("../shader-code");
var uniform_1 = require("./uniform");
var buffer_1 = require("./buffer");
var id_factory_1 = require("../../mol-util/id-factory");
var debug_1 = require("../../mol-util/debug");
var getNextProgramId = (0, id_factory_1.idFactory)();
function getLocations(gl, program, schema) {
var locations = {};
Object.keys(schema).forEach(function (k) {
var spec = schema[k];
if (spec.type === 'attribute') {
var loc = gl.getAttribLocation(program, k);
// unused attributes will result in a `-1` location which is usually fine
// if (loc === -1) console.info(`Could not get attribute location for '${k}'`)
locations[k] = loc;
}
else if (spec.type === 'uniform' || spec.type === 'texture') {
var loc = gl.getUniformLocation(program, k);
// unused uniforms will result in a `null` location which is usually fine
// if (loc === null) console.info(`Could not get uniform location for '${k}'`)
locations[k] = loc;
}
});
return locations;
}
function checkActiveAttributes(gl, program, schema) {
var attribCount = gl.getProgramParameter(program, gl.ACTIVE_ATTRIBUTES);
for (var i = 0; i < attribCount; ++i) {
var info = gl.getActiveAttrib(program, i);
if (info) {
var name_1 = info.name, type = info.type;
if (name_1.startsWith('__activeAttribute')) {
// name assigned by `gl.shim.ts`, ignore for checks
continue;
}
if (name_1 === 'gl_InstanceID')
continue; // WebGL2 built-in
if (name_1 === 'gl_VertexID')
continue; // WebGL2 built-in
var spec = schema[name_1];
if (spec === undefined) {
throw new Error("missing 'uniform' or 'texture' with name '" + name_1 + "' in schema");
}
if (spec.type !== 'attribute') {
throw new Error("'" + name_1 + "' must be of type 'attribute' but is '" + spec.type + "'");
}
var attribType = (0, buffer_1.getAttribType)(gl, spec.kind, spec.itemSize);
if (attribType !== type) {
throw new Error("unexpected attribute type for " + name_1);
}
}
}
}
function checkActiveUniforms(gl, program, schema) {
var attribCount = gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS);
for (var i = 0; i < attribCount; ++i) {
var info = gl.getActiveUniform(program, i);
if (info) {
var name_2 = info.name, type = info.type;
if (name_2.startsWith('__activeUniform')) {
// name assigned by `gl.shim.ts`, ignore for checks
continue;
}
var baseName = name_2.replace(/[[0-9]+\]$/, ''); // 'array' uniforms
var spec = schema[baseName];
if (spec === undefined) {
throw new Error("missing 'uniform' or 'texture' with name '" + name_2 + "' in schema");
}
if (spec.type === 'uniform') {
var uniformType = (0, uniform_1.getUniformType)(gl, spec.kind);
if (uniformType !== type) {
throw new Error("unexpected uniform type for " + name_2);
}
}
else if (spec.type === 'texture') {
if (spec.kind === 'image-float32' || spec.kind === 'image-uint8') {
if (type !== gl.SAMPLER_2D) {
throw new Error("unexpected sampler type for '" + name_2 + "'");
}
}
else if (spec.kind === 'volume-float32' || spec.kind === 'volume-uint8') {
if (type !== gl.SAMPLER_3D) {
throw new Error("unexpected sampler type for '" + name_2 + "'");
}
}
else {
// TODO
}
}
else {
throw new Error("'" + name_2 + "' must be of type 'uniform' or 'texture' but is '" + spec.type + "'");
}
}
}
}
function checkProgram(gl, program) {
// no-op in FF on Mac, see https://bugzilla.mozilla.org/show_bug.cgi?id=1284425
// gl.validateProgram(program)
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
throw new Error("Could not compile WebGL program. \n\n" + gl.getProgramInfoLog(program));
}
}
function getProgram(gl) {
var program = gl.createProgram();
if (program === null) {
throw new Error('Could not create WebGL program');
}
return program;
}
exports.getProgram = getProgram;
function createProgram(gl, state, extensions, getShader, props) {
var defineValues = props.defineValues, _shaderCode = props.shaderCode, schema = props.schema;
var program = getProgram(gl);
var programId = getNextProgramId();
var shaderCode = (0, shader_code_1.addShaderDefines)(gl, extensions, defineValues, _shaderCode);
var vertShader = getShader('vert', shaderCode.vert);
var fragShader = getShader('frag', shaderCode.frag);
var locations;
var uniformSetters;
function init() {
vertShader.attach(program);
fragShader.attach(program);
gl.linkProgram(program);
if (debug_1.isDebugMode) {
checkProgram(gl, program);
}
locations = getLocations(gl, program, schema);
uniformSetters = (0, uniform_1.getUniformSetters)(schema);
if (debug_1.isDebugMode) {
checkActiveAttributes(gl, program, schema);
checkActiveUniforms(gl, program, schema);
}
}
init();
var destroyed = false;
return {
id: programId,
use: function () {
// console.log('use', programId)
state.currentProgramId = programId;
gl.useProgram(program);
},
setUniforms: function (uniformValues) {
for (var i = 0, il = uniformValues.length; i < il; ++i) {
var _a = uniformValues[i], k = _a[0], v = _a[1];
if (v) {
var l = locations[k];
if (l !== null)
uniformSetters[k](gl, l, v.ref.value);
}
}
},
bindAttributes: function (attributeBuffers) {
for (var i = 0, il = attributeBuffers.length; i < il; ++i) {
var _a = attributeBuffers[i], k = _a[0], buffer = _a[1];
var l = locations[k];
if (l !== -1)
buffer.bind(l);
}
},
bindTextures: function (textures, startingTargetUnit) {
for (var i = 0, il = textures.length; i < il; ++i) {
var _a = textures[i], k = _a[0], texture = _a[1];
var l = locations[k];
if (l !== null && l !== undefined) {
texture.bind((i + startingTargetUnit));
uniformSetters[k](gl, l, (i + startingTargetUnit));
}
}
},
reset: function () {
program = getProgram(gl);
init();
},
destroy: function () {
if (destroyed)
return;
vertShader.destroy();
fragShader.destroy();
gl.deleteProgram(program);
destroyed = true;
}
};
}
exports.createProgram = createProgram;
//# sourceMappingURL=program.js.map
;