molstar
Version:
A comprehensive macromolecular library.
211 lines (210 loc) • 9.06 kB
JavaScript
/**
* Copyright (c) 2018-2022 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 compat_1 = require("./compat");
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') {
var loc = gl.getUniformLocation(program, k);
// headless-gl requires a '[0]' suffix for array uniforms (https://github.com/stackgl/headless-gl/issues/170)
if (loc === null && (0, uniform_1.isArrayUniform)(spec.kind))
loc = gl.getUniformLocation(program, k + '[0]');
// 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;
}
else if (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 '".concat(name_1, "' in schema"));
}
if (spec.type !== 'attribute') {
throw new Error("'".concat(name_1, "' must be of type 'attribute' but is '").concat(spec.type, "'"));
}
var attribType = (0, buffer_1.getAttribType)(gl, spec.kind, spec.itemSize);
if (attribType !== type) {
throw new Error("unexpected attribute type '".concat(attribType, "' for ").concat(name_1, ", expected '").concat(type, "'"));
}
}
}
}
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 '".concat(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 ".concat(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 '".concat(name_2, "'"));
}
}
else if (spec.kind === 'volume-float32' || spec.kind === 'volume-uint8') {
if ((0, compat_1.isWebGL2)(gl)) {
if (type !== gl.SAMPLER_3D) {
throw new Error("unexpected sampler type for '".concat(name_2, "'"));
}
}
else {
throw new Error("WebGL2 is required to use SAMPLER_3D");
}
}
else {
// TODO
}
}
else {
throw new Error("'".concat(name_2, "' must be of type 'uniform' or 'texture' but is '").concat(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".concat(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) {
state.clearVertexAttribsState();
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);
}
state.disableUnusedVertexAttribs();
},
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;
;