molstar
Version:
A comprehensive macromolecular library.
695 lines (694 loc) • 41.8 kB
JavaScript
"use strict";
/**
* Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
* @author Gianluca Tomasello <giagitom@gmail.com>
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.Renderer = exports.RendererParams = void 0;
var util_1 = require("../mol-canvas3d/camera/util");
var linear_algebra_1 = require("../mol-math/linear-algebra");
var color_1 = require("../mol-util/color");
var mol_util_1 = require("../mol-util");
var param_definition_1 = require("../mol-util/param-definition");
var misc_1 = require("../mol-math/misc");
var array_1 = require("../mol-util/array");
var interpolate_1 = require("../mol-math/interpolate");
var debug_1 = require("../mol-util/debug");
exports.RendererParams = {
backgroundColor: param_definition_1.ParamDefinition.Color((0, color_1.Color)(0x000000), { description: 'Background color of the 3D canvas' }),
pickingAlphaThreshold: param_definition_1.ParamDefinition.Numeric(0.5, { min: 0.0, max: 1.0, step: 0.01 }, { description: 'The minimum opacity value needed for an object to be pickable.' }),
interiorDarkening: param_definition_1.ParamDefinition.Numeric(0.5, { min: 0.0, max: 1.0, step: 0.01 }),
interiorColorFlag: param_definition_1.ParamDefinition.Boolean(true, { label: 'Use Interior Color' }),
interiorColor: param_definition_1.ParamDefinition.Color(color_1.Color.fromNormalizedRgb(0.3, 0.3, 0.3)),
colorMarker: param_definition_1.ParamDefinition.Boolean(true, { description: 'Enable color marker' }),
highlightColor: param_definition_1.ParamDefinition.Color(color_1.Color.fromNormalizedRgb(1.0, 0.4, 0.6)),
selectColor: param_definition_1.ParamDefinition.Color(color_1.Color.fromNormalizedRgb(0.2, 1.0, 0.1)),
highlightStrength: param_definition_1.ParamDefinition.Numeric(0.3, { min: 0.0, max: 1.0, step: 0.1 }),
selectStrength: param_definition_1.ParamDefinition.Numeric(0.3, { min: 0.0, max: 1.0, step: 0.1 }),
markerPriority: param_definition_1.ParamDefinition.Select(1, [[1, 'Highlight'], [2, 'Select']]),
xrayEdgeFalloff: param_definition_1.ParamDefinition.Numeric(1, { min: 0.0, max: 3.0, step: 0.1 }),
light: param_definition_1.ParamDefinition.ObjectList({
inclination: param_definition_1.ParamDefinition.Numeric(180, { min: 0, max: 180, step: 1 }),
azimuth: param_definition_1.ParamDefinition.Numeric(0, { min: 0, max: 360, step: 1 }),
color: param_definition_1.ParamDefinition.Color(color_1.Color.fromNormalizedRgb(1.0, 1.0, 1.0)),
intensity: param_definition_1.ParamDefinition.Numeric(0.6, { min: 0.0, max: 1.0, step: 0.01 }),
}, function (o) { return color_1.Color.toHexString(o.color); }, { defaultValue: [{
inclination: 180,
azimuth: 0,
color: color_1.Color.fromNormalizedRgb(1.0, 1.0, 1.0),
intensity: 0.6
}] }),
ambientColor: param_definition_1.ParamDefinition.Color(color_1.Color.fromNormalizedRgb(1.0, 1.0, 1.0)),
ambientIntensity: param_definition_1.ParamDefinition.Numeric(0.4, { min: 0.0, max: 1.0, step: 0.01 }),
};
var tmpDir = (0, linear_algebra_1.Vec3)();
var tmpColor = (0, linear_algebra_1.Vec3)();
function getLight(props, light) {
var _a = light || {
direction: (new Array(5 * 3)).fill(0),
color: (new Array(5 * 3)).fill(0),
}, direction = _a.direction, color = _a.color;
for (var i = 0, il = props.length; i < il; ++i) {
var p = props[i];
linear_algebra_1.Vec3.directionFromSpherical(tmpDir, (0, misc_1.degToRad)(p.inclination), (0, misc_1.degToRad)(p.azimuth), 1);
linear_algebra_1.Vec3.toArray(tmpDir, direction, i * 3);
linear_algebra_1.Vec3.scale(tmpColor, color_1.Color.toVec3Normalized(tmpColor, p.color), p.intensity);
linear_algebra_1.Vec3.toArray(tmpColor, color, i * 3);
}
return { count: props.length, direction: direction, color: color };
}
var Renderer;
(function (Renderer) {
function create(ctx, props) {
if (props === void 0) { props = {}; }
var gl = ctx.gl, state = ctx.state, stats = ctx.stats;
var p = param_definition_1.ParamDefinition.merge(exports.RendererParams, param_definition_1.ParamDefinition.getDefaultValues(exports.RendererParams), props);
var light = getLight(p.light);
var viewport = (0, util_1.Viewport)();
var drawingBufferSize = linear_algebra_1.Vec2.create(gl.drawingBufferWidth, gl.drawingBufferHeight);
var bgColor = color_1.Color.toVec3Normalized((0, linear_algebra_1.Vec3)(), p.backgroundColor);
var transparentBackground = false;
var emptyDepthTexture = ctx.resources.texture('image-uint8', 'rgba', 'ubyte', 'nearest');
emptyDepthTexture.define(1, 1);
emptyDepthTexture.load({ array: new Uint8Array([255, 255, 255, 255]), width: 1, height: 1 });
var sharedTexturesList = [
['tDepth', emptyDepthTexture]
];
var view = (0, linear_algebra_1.Mat4)();
var invView = (0, linear_algebra_1.Mat4)();
var modelView = (0, linear_algebra_1.Mat4)();
var invModelView = (0, linear_algebra_1.Mat4)();
var invProjection = (0, linear_algebra_1.Mat4)();
var modelViewProjection = (0, linear_algebra_1.Mat4)();
var invModelViewProjection = (0, linear_algebra_1.Mat4)();
var cameraDir = (0, linear_algebra_1.Vec3)();
var viewOffset = (0, linear_algebra_1.Vec2)();
var ambientColor = (0, linear_algebra_1.Vec3)();
linear_algebra_1.Vec3.scale(ambientColor, color_1.Color.toArrayNormalized(p.ambientColor, ambientColor, 0), p.ambientIntensity);
var globalUniforms = {
uModel: mol_util_1.ValueCell.create(linear_algebra_1.Mat4.identity()),
uView: mol_util_1.ValueCell.create(view),
uInvView: mol_util_1.ValueCell.create(invView),
uModelView: mol_util_1.ValueCell.create(modelView),
uInvModelView: mol_util_1.ValueCell.create(invModelView),
uInvProjection: mol_util_1.ValueCell.create(invProjection),
uProjection: mol_util_1.ValueCell.create((0, linear_algebra_1.Mat4)()),
uModelViewProjection: mol_util_1.ValueCell.create(modelViewProjection),
uInvModelViewProjection: mol_util_1.ValueCell.create(invModelViewProjection),
uIsOrtho: mol_util_1.ValueCell.create(1),
uViewOffset: mol_util_1.ValueCell.create(viewOffset),
uPixelRatio: mol_util_1.ValueCell.create(ctx.pixelRatio),
uViewport: mol_util_1.ValueCell.create(util_1.Viewport.toVec4((0, linear_algebra_1.Vec4)(), viewport)),
uDrawingBufferSize: mol_util_1.ValueCell.create(drawingBufferSize),
uCameraPosition: mol_util_1.ValueCell.create((0, linear_algebra_1.Vec3)()),
uCameraDir: mol_util_1.ValueCell.create(cameraDir),
uNear: mol_util_1.ValueCell.create(1),
uFar: mol_util_1.ValueCell.create(10000),
uFogNear: mol_util_1.ValueCell.create(1),
uFogFar: mol_util_1.ValueCell.create(10000),
uFogColor: mol_util_1.ValueCell.create(bgColor),
uRenderMask: mol_util_1.ValueCell.create(0),
uMarkingDepthTest: mol_util_1.ValueCell.create(false),
uPickType: mol_util_1.ValueCell.create(0 /* PickType.None */),
uMarkingType: mol_util_1.ValueCell.create(0 /* MarkingType.None */),
uTransparentBackground: mol_util_1.ValueCell.create(false),
uLightDirection: mol_util_1.ValueCell.create(light.direction),
uLightColor: mol_util_1.ValueCell.create(light.color),
uAmbientColor: mol_util_1.ValueCell.create(ambientColor),
uPickingAlphaThreshold: mol_util_1.ValueCell.create(p.pickingAlphaThreshold),
uInteriorDarkening: mol_util_1.ValueCell.create(p.interiorDarkening),
uInteriorColorFlag: mol_util_1.ValueCell.create(p.interiorColorFlag),
uInteriorColor: mol_util_1.ValueCell.create(color_1.Color.toVec3Normalized((0, linear_algebra_1.Vec3)(), p.interiorColor)),
uHighlightColor: mol_util_1.ValueCell.create(color_1.Color.toVec3Normalized((0, linear_algebra_1.Vec3)(), p.highlightColor)),
uSelectColor: mol_util_1.ValueCell.create(color_1.Color.toVec3Normalized((0, linear_algebra_1.Vec3)(), p.selectColor)),
uHighlightStrength: mol_util_1.ValueCell.create(p.highlightStrength),
uSelectStrength: mol_util_1.ValueCell.create(p.selectStrength),
uMarkerPriority: mol_util_1.ValueCell.create(p.markerPriority),
uXrayEdgeFalloff: mol_util_1.ValueCell.create(p.xrayEdgeFalloff),
};
var globalUniformList = Object.entries(globalUniforms);
var globalUniformsNeedUpdate = true;
var renderObject = function (r, variant, flag) {
var _a, _b, _c;
if (r.state.disposed || !r.state.visible || (!r.state.pickable && variant === 'pick')) {
return;
}
var definesNeedUpdate = false;
if (r.values.dLightCount.ref.value !== light.count) {
mol_util_1.ValueCell.update(r.values.dLightCount, light.count);
definesNeedUpdate = true;
}
if (r.values.dColorMarker.ref.value !== p.colorMarker) {
mol_util_1.ValueCell.update(r.values.dColorMarker, p.colorMarker);
definesNeedUpdate = true;
}
if (definesNeedUpdate)
r.update();
var program = r.getProgram(variant);
if (state.currentProgramId !== program.id) {
// console.log('new program')
globalUniformsNeedUpdate = true;
program.use();
}
if (globalUniformsNeedUpdate) {
// console.log('globalUniformsNeedUpdate')
program.setUniforms(globalUniformList);
program.bindTextures(sharedTexturesList, 0);
globalUniformsNeedUpdate = false;
}
if (r.values.dGeometryType.ref.value === 'directVolume') {
if (variant !== 'colorDpoit' && variant !== 'colorWboit' && variant !== 'colorBlended') {
return; // only color supported
}
// culling done in fragment shader
state.disable(gl.CULL_FACE);
state.frontFace(gl.CCW);
if (variant === 'colorBlended') {
// depth test done manually in shader against `depthTexture`
state.disable(gl.DEPTH_TEST);
state.depthMask(false);
}
}
else if (flag === 1 /* Flag.BlendedFront */) {
state.enable(gl.CULL_FACE);
if ((_a = r.values.dFlipSided) === null || _a === void 0 ? void 0 : _a.ref.value) {
state.frontFace(gl.CW);
state.cullFace(gl.FRONT);
}
else {
state.frontFace(gl.CCW);
state.cullFace(gl.BACK);
}
}
else if (flag === 2 /* Flag.BlendedBack */) {
state.enable(gl.CULL_FACE);
if ((_b = r.values.dFlipSided) === null || _b === void 0 ? void 0 : _b.ref.value) {
state.frontFace(gl.CW);
state.cullFace(gl.BACK);
}
else {
state.frontFace(gl.CCW);
state.cullFace(gl.FRONT);
}
}
else {
if (r.values.uDoubleSided) {
if (r.values.uDoubleSided.ref.value || r.values.hasReflection.ref.value) {
state.disable(gl.CULL_FACE);
}
else {
state.enable(gl.CULL_FACE);
}
}
else {
// webgl default
state.disable(gl.CULL_FACE);
}
if ((_c = r.values.dFlipSided) === null || _c === void 0 ? void 0 : _c.ref.value) {
state.frontFace(gl.CW);
state.cullFace(gl.FRONT);
}
else {
// webgl default
state.frontFace(gl.CCW);
state.cullFace(gl.BACK);
}
}
r.render(variant, sharedTexturesList.length);
};
var update = function (camera) {
mol_util_1.ValueCell.update(globalUniforms.uView, camera.view);
mol_util_1.ValueCell.update(globalUniforms.uInvView, linear_algebra_1.Mat4.invert(invView, camera.view));
mol_util_1.ValueCell.update(globalUniforms.uProjection, camera.projection);
mol_util_1.ValueCell.update(globalUniforms.uInvProjection, linear_algebra_1.Mat4.invert(invProjection, camera.projection));
mol_util_1.ValueCell.updateIfChanged(globalUniforms.uIsOrtho, camera.state.mode === 'orthographic' ? 1 : 0);
mol_util_1.ValueCell.update(globalUniforms.uViewOffset, camera.viewOffset.enabled ? linear_algebra_1.Vec2.set(viewOffset, camera.viewOffset.offsetX * 16, camera.viewOffset.offsetY * 16) : linear_algebra_1.Vec2.set(viewOffset, 0, 0));
mol_util_1.ValueCell.update(globalUniforms.uCameraPosition, camera.state.position);
mol_util_1.ValueCell.update(globalUniforms.uCameraDir, linear_algebra_1.Vec3.normalize(cameraDir, linear_algebra_1.Vec3.sub(cameraDir, camera.state.target, camera.state.position)));
mol_util_1.ValueCell.updateIfChanged(globalUniforms.uFar, camera.far);
mol_util_1.ValueCell.updateIfChanged(globalUniforms.uNear, camera.near);
mol_util_1.ValueCell.updateIfChanged(globalUniforms.uFogFar, camera.fogFar);
mol_util_1.ValueCell.updateIfChanged(globalUniforms.uFogNear, camera.fogNear);
mol_util_1.ValueCell.updateIfChanged(globalUniforms.uTransparentBackground, transparentBackground);
};
var updateInternal = function (group, camera, depthTexture, renderMask, markingDepthTest) {
(0, array_1.arrayMapUpsert)(sharedTexturesList, 'tDepth', depthTexture || emptyDepthTexture);
mol_util_1.ValueCell.update(globalUniforms.uModel, group.view);
mol_util_1.ValueCell.update(globalUniforms.uModelView, linear_algebra_1.Mat4.mul(modelView, group.view, camera.view));
mol_util_1.ValueCell.update(globalUniforms.uInvModelView, linear_algebra_1.Mat4.invert(invModelView, modelView));
mol_util_1.ValueCell.update(globalUniforms.uModelViewProjection, linear_algebra_1.Mat4.mul(modelViewProjection, modelView, camera.projection));
mol_util_1.ValueCell.update(globalUniforms.uInvModelViewProjection, linear_algebra_1.Mat4.invert(invModelViewProjection, modelViewProjection));
mol_util_1.ValueCell.updateIfChanged(globalUniforms.uRenderMask, renderMask);
mol_util_1.ValueCell.updateIfChanged(globalUniforms.uMarkingDepthTest, markingDepthTest);
state.enable(gl.SCISSOR_TEST);
state.colorMask(true, true, true, true);
var x = viewport.x, y = viewport.y, width = viewport.width, height = viewport.height;
state.viewport(x, y, width, height);
state.scissor(x, y, width, height);
globalUniformsNeedUpdate = true;
state.currentRenderItemId = -1;
};
var renderPick = function (group, camera, variant, depthTexture, pickType) {
if (debug_1.isTimingMode)
ctx.timer.mark('Renderer.renderPick');
state.disable(gl.BLEND);
state.enable(gl.DEPTH_TEST);
state.depthMask(true);
updateInternal(group, camera, depthTexture, 0 /* Mask.All */, false);
mol_util_1.ValueCell.updateIfChanged(globalUniforms.uPickType, pickType);
var renderables = group.renderables;
for (var i = 0, il = renderables.length; i < il; ++i) {
if (!renderables[i].state.colorOnly) {
renderObject(renderables[i], variant, 0 /* Flag.None */);
}
}
if (debug_1.isTimingMode)
ctx.timer.markEnd('Renderer.renderPick');
};
var renderDepth = function (group, camera, depthTexture) {
if (debug_1.isTimingMode)
ctx.timer.mark('Renderer.renderDepth');
state.disable(gl.BLEND);
state.enable(gl.DEPTH_TEST);
state.depthMask(true);
updateInternal(group, camera, depthTexture, 0 /* Mask.All */, false);
var renderables = group.renderables;
for (var i = 0, il = renderables.length; i < il; ++i) {
renderObject(renderables[i], 'depth', 0 /* Flag.None */);
}
if (debug_1.isTimingMode)
ctx.timer.markEnd('Renderer.renderDepth');
};
var renderDepthOpaque = function (group, camera, depthTexture) {
var _a;
if (debug_1.isTimingMode)
ctx.timer.mark('Renderer.renderDepthOpaque');
state.disable(gl.BLEND);
state.enable(gl.DEPTH_TEST);
state.depthMask(true);
updateInternal(group, camera, depthTexture, 1 /* Mask.Opaque */, false);
var renderables = group.renderables;
for (var i = 0, il = renderables.length; i < il; ++i) {
var r = renderables[i];
if (r.state.opaque && r.values.transparencyAverage.ref.value !== 1 && !((_a = r.values.dXrayShaded) === null || _a === void 0 ? void 0 : _a.ref.value)) {
renderObject(r, 'depth', 0 /* Flag.None */);
}
}
if (debug_1.isTimingMode)
ctx.timer.markEnd('Renderer.renderDepthOpaque');
};
var renderDepthTransparent = function (group, camera, depthTexture) {
var _a;
if (debug_1.isTimingMode)
ctx.timer.mark('Renderer.renderDepthTransparent');
state.disable(gl.BLEND);
state.enable(gl.DEPTH_TEST);
state.depthMask(true);
updateInternal(group, camera, depthTexture, 2 /* Mask.Transparent */, false);
var renderables = group.renderables;
for (var i = 0, il = renderables.length; i < il; ++i) {
var r = renderables[i];
if (!r.state.opaque || r.values.transparencyAverage.ref.value > 0 || ((_a = r.values.dXrayShaded) === null || _a === void 0 ? void 0 : _a.ref.value)) {
renderObject(r, 'depth', 0 /* Flag.None */);
}
}
if (debug_1.isTimingMode)
ctx.timer.markEnd('Renderer.renderDepthTransparent');
};
var renderMarkingDepth = function (group, camera, depthTexture) {
if (debug_1.isTimingMode)
ctx.timer.mark('Renderer.renderMarkingDepth');
state.disable(gl.BLEND);
state.enable(gl.DEPTH_TEST);
state.depthMask(true);
updateInternal(group, camera, depthTexture, 0 /* Mask.All */, false);
mol_util_1.ValueCell.updateIfChanged(globalUniforms.uMarkingType, 1 /* MarkingType.Depth */);
var renderables = group.renderables;
for (var i = 0, il = renderables.length; i < il; ++i) {
var r = renderables[i];
if (r.values.markerAverage.ref.value !== 1) {
renderObject(renderables[i], 'marking', 0 /* Flag.None */);
}
}
if (debug_1.isTimingMode)
ctx.timer.markEnd('Renderer.renderMarkingDepth');
};
var renderMarkingMask = function (group, camera, depthTexture) {
if (debug_1.isTimingMode)
ctx.timer.mark('Renderer.renderMarkingMask');
state.disable(gl.BLEND);
state.enable(gl.DEPTH_TEST);
state.depthMask(true);
updateInternal(group, camera, depthTexture, 0 /* Mask.All */, !!depthTexture);
mol_util_1.ValueCell.updateIfChanged(globalUniforms.uMarkingType, 2 /* MarkingType.Mask */);
var renderables = group.renderables;
for (var i = 0, il = renderables.length; i < il; ++i) {
var r = renderables[i];
if (r.values.markerAverage.ref.value > 0) {
renderObject(renderables[i], 'marking', 0 /* Flag.None */);
}
}
if (debug_1.isTimingMode)
ctx.timer.markEnd('Renderer.renderMarkingMask');
};
var renderBlended = function (scene, camera) {
if (scene.hasOpaque) {
renderBlendedOpaque(scene, camera, null);
}
if (scene.opacityAverage < 1) {
renderBlendedTransparent(scene, camera, null);
}
};
var renderBlendedOpaque = function (group, camera, depthTexture) {
var _a, _b;
if (debug_1.isTimingMode)
ctx.timer.mark('Renderer.renderBlendedOpaque');
state.disable(gl.BLEND);
state.enable(gl.DEPTH_TEST);
state.depthMask(true);
updateInternal(group, camera, depthTexture, 1 /* Mask.Opaque */, false);
var renderables = group.renderables;
for (var i = 0, il = renderables.length; i < il; ++i) {
var r = renderables[i];
if (r.state.opaque) {
renderObject(r, 'colorBlended', 0 /* Flag.None */);
}
else if (((_a = r.values.uDoubleSided) === null || _a === void 0 ? void 0 : _a.ref.value) && ((_b = r.values.dTransparentBackfaces) === null || _b === void 0 ? void 0 : _b.ref.value) === 'opaque') {
renderObject(r, 'colorBlended', 2 /* Flag.BlendedBack */);
}
}
if (debug_1.isTimingMode)
ctx.timer.markEnd('Renderer.renderBlendedOpaque');
};
var renderBlendedTransparent = function (group, camera, depthTexture) {
var _a, _b;
if (debug_1.isTimingMode)
ctx.timer.mark('Renderer.renderBlendedTransparent');
state.enable(gl.DEPTH_TEST);
updateInternal(group, camera, depthTexture, 2 /* Mask.Transparent */, false);
var renderables = group.renderables;
if (transparentBackground) {
state.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
}
else {
state.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
}
state.enable(gl.BLEND);
state.depthMask(true);
for (var i = 0, il = renderables.length; i < il; ++i) {
var r = renderables[i];
if (!r.state.opaque && r.state.writeDepth) {
renderObject(r, 'colorBlended', 0 /* Flag.None */);
}
}
state.depthMask(false);
for (var i = 0, il = renderables.length; i < il; ++i) {
var r = renderables[i];
if ((!r.state.opaque && !r.state.writeDepth) || r.values.transparencyAverage.ref.value > 0) {
if ((_a = r.values.uDoubleSided) === null || _a === void 0 ? void 0 : _a.ref.value) {
// render frontfaces and backfaces separately to avoid artefacts
if (((_b = r.values.dTransparentBackfaces) === null || _b === void 0 ? void 0 : _b.ref.value) !== 'opaque') {
renderObject(r, 'colorBlended', 2 /* Flag.BlendedBack */);
}
renderObject(r, 'colorBlended', 1 /* Flag.BlendedFront */);
}
else {
renderObject(r, 'colorBlended', 0 /* Flag.None */);
}
}
}
if (debug_1.isTimingMode)
ctx.timer.markEnd('Renderer.renderBlendedTransparent');
};
var renderBlendedVolume = function (group, camera, depthTexture) {
if (debug_1.isTimingMode)
ctx.timer.mark('Renderer.renderBlendedVolume');
state.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
state.enable(gl.BLEND);
updateInternal(group, camera, depthTexture, 2 /* Mask.Transparent */, false);
var renderables = group.renderables;
for (var i = 0, il = renderables.length; i < il; ++i) {
var r = renderables[i];
if (r.values.dGeometryType.ref.value === 'directVolume') {
renderObject(r, 'colorBlended', 0 /* Flag.None */);
}
}
if (debug_1.isTimingMode)
ctx.timer.markEnd('Renderer.renderBlendedVolume');
};
var renderWboitOpaque = function (group, camera, depthTexture) {
var _a, _b, _c;
if (debug_1.isTimingMode)
ctx.timer.mark('Renderer.renderWboitOpaque');
state.disable(gl.BLEND);
state.enable(gl.DEPTH_TEST);
state.depthMask(true);
updateInternal(group, camera, depthTexture, 1 /* Mask.Opaque */, false);
var renderables = group.renderables;
for (var i = 0, il = renderables.length; i < il; ++i) {
var r = renderables[i];
// TODO: simplify, handle in renderable.state???
// uAlpha is updated in "render" so we need to recompute it here
var alpha = (0, interpolate_1.clamp)(r.values.alpha.ref.value * r.state.alphaFactor, 0, 1);
if ((alpha === 1 && r.values.transparencyAverage.ref.value !== 1 && r.values.dGeometryType.ref.value !== 'directVolume' && ((_a = r.values.dPointStyle) === null || _a === void 0 ? void 0 : _a.ref.value) !== 'fuzzy' && !((_b = r.values.dXrayShaded) === null || _b === void 0 ? void 0 : _b.ref.value)) || ((_c = r.values.dTransparentBackfaces) === null || _c === void 0 ? void 0 : _c.ref.value) === 'opaque') {
renderObject(r, 'colorWboit', 0 /* Flag.None */);
}
}
if (debug_1.isTimingMode)
ctx.timer.markEnd('Renderer.renderWboitOpaque');
};
var renderWboitTransparent = function (group, camera, depthTexture) {
var _a, _b;
if (debug_1.isTimingMode)
ctx.timer.mark('Renderer.renderWboitTransparent');
updateInternal(group, camera, depthTexture, 2 /* Mask.Transparent */, false);
var renderables = group.renderables;
for (var i = 0, il = renderables.length; i < il; ++i) {
var r = renderables[i];
// TODO: simplify, handle in renderable.state???
// uAlpha is updated in "render" so we need to recompute it here
var alpha = (0, interpolate_1.clamp)(r.values.alpha.ref.value * r.state.alphaFactor, 0, 1);
if (alpha < 1 || r.values.transparencyAverage.ref.value > 0 || r.values.dGeometryType.ref.value === 'directVolume' || ((_a = r.values.dPointStyle) === null || _a === void 0 ? void 0 : _a.ref.value) === 'fuzzy' || r.values.dGeometryType.ref.value === 'text' || ((_b = r.values.dXrayShaded) === null || _b === void 0 ? void 0 : _b.ref.value)) {
renderObject(r, 'colorWboit', 0 /* Flag.None */);
}
}
if (debug_1.isTimingMode)
ctx.timer.markEnd('Renderer.renderWboitTransparent');
};
var renderDpoitOpaque = function (group, camera, depthTexture) {
var _a, _b, _c;
if (debug_1.isTimingMode)
ctx.timer.mark('Renderer.renderDpoitOpaque');
state.disable(gl.BLEND);
state.enable(gl.DEPTH_TEST);
state.depthMask(true);
updateInternal(group, camera, depthTexture, 1 /* Mask.Opaque */, false);
var renderables = group.renderables;
for (var i = 0, il = renderables.length; i < il; ++i) {
var r = renderables[i];
// TODO: simplify, handle in renderable.state???
// uAlpha is updated in "render" so we need to recompute it here
var alpha = (0, interpolate_1.clamp)(r.values.alpha.ref.value * r.state.alphaFactor, 0, 1);
if ((alpha === 1 && r.values.transparencyAverage.ref.value !== 1 && ((_a = r.values.dPointStyle) === null || _a === void 0 ? void 0 : _a.ref.value) !== 'fuzzy' && !((_b = r.values.dXrayShaded) === null || _b === void 0 ? void 0 : _b.ref.value)) || ((_c = r.values.dTransparentBackfaces) === null || _c === void 0 ? void 0 : _c.ref.value) === 'opaque') {
renderObject(r, 'colorDpoit', 0 /* Flag.None */);
}
}
if (debug_1.isTimingMode)
ctx.timer.markEnd('Renderer.renderDpoitOpaque');
};
var renderDpoitTransparent = function (group, camera, depthTexture, dpoitTextures) {
var _a, _b;
if (debug_1.isTimingMode)
ctx.timer.mark('Renderer.renderDpoitTransparent');
state.enable(gl.BLEND);
(0, array_1.arrayMapUpsert)(sharedTexturesList, 'tDpoitDepth', dpoitTextures.depth);
(0, array_1.arrayMapUpsert)(sharedTexturesList, 'tDpoitFrontColor', dpoitTextures.frontColor);
(0, array_1.arrayMapUpsert)(sharedTexturesList, 'tDpoitBackColor', dpoitTextures.backColor);
updateInternal(group, camera, depthTexture, 2 /* Mask.Transparent */, false);
var renderables = group.renderables;
for (var i = 0, il = renderables.length; i < il; ++i) {
var r = renderables[i];
// TODO: simplify, handle in renderable.state???
// uAlpha is updated in "render" so we need to recompute it here
var alpha = (0, interpolate_1.clamp)(r.values.alpha.ref.value * r.state.alphaFactor, 0, 1);
if (alpha < 1 || r.values.transparencyAverage.ref.value > 0 || ((_a = r.values.dPointStyle) === null || _a === void 0 ? void 0 : _a.ref.value) === 'fuzzy' || !!r.values.uBackgroundColor || ((_b = r.values.dXrayShaded) === null || _b === void 0 ? void 0 : _b.ref.value)) {
renderObject(r, 'colorDpoit', 0 /* Flag.None */);
}
}
if (debug_1.isTimingMode)
ctx.timer.markEnd('Renderer.renderDpoitTransparent');
};
var renderDpoitVolume = function (group, camera, depthTexture) {
if (debug_1.isTimingMode)
ctx.timer.mark('Renderer.renderDpoitVolume');
state.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
state.enable(gl.BLEND);
updateInternal(group, camera, depthTexture, 2 /* Mask.Transparent */, false);
var renderables = group.renderables;
for (var i = 0, il = renderables.length; i < il; ++i) {
var r = renderables[i];
if (r.values.dGeometryType.ref.value === 'directVolume') {
renderObject(r, 'colorDpoit', 0 /* Flag.None */);
}
}
if (debug_1.isTimingMode)
ctx.timer.markEnd('Renderer.renderDpoitVolume');
};
return {
clear: function (toBackgroundColor, ignoreTransparentBackground) {
state.enable(gl.SCISSOR_TEST);
state.enable(gl.DEPTH_TEST);
state.colorMask(true, true, true, true);
state.depthMask(true);
if (transparentBackground && !ignoreTransparentBackground) {
state.clearColor(0, 0, 0, 0);
}
else if (toBackgroundColor) {
state.clearColor(bgColor[0], bgColor[1], bgColor[2], 1);
}
else {
state.clearColor(1, 1, 1, 1);
}
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
},
clearDepth: function (packed) {
if (packed === void 0) { packed = false; }
state.enable(gl.SCISSOR_TEST);
if (packed) {
state.colorMask(true, true, true, true);
state.clearColor(1, 1, 1, 1);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
}
else {
state.enable(gl.DEPTH_TEST);
state.depthMask(true);
gl.clear(gl.DEPTH_BUFFER_BIT);
}
},
update: update,
renderPick: renderPick,
renderDepth: renderDepth,
renderDepthOpaque: renderDepthOpaque,
renderDepthTransparent: renderDepthTransparent,
renderMarkingDepth: renderMarkingDepth,
renderMarkingMask: renderMarkingMask,
renderBlended: renderBlended,
renderBlendedOpaque: renderBlendedOpaque,
renderBlendedTransparent: renderBlendedTransparent,
renderBlendedVolume: renderBlendedVolume,
renderWboitOpaque: renderWboitOpaque,
renderWboitTransparent: renderWboitTransparent,
renderDpoitOpaque: renderDpoitOpaque,
renderDpoitTransparent: renderDpoitTransparent,
renderDpoitVolume: renderDpoitVolume,
setProps: function (props) {
if (props.backgroundColor !== undefined && props.backgroundColor !== p.backgroundColor) {
p.backgroundColor = props.backgroundColor;
color_1.Color.toVec3Normalized(bgColor, p.backgroundColor);
mol_util_1.ValueCell.update(globalUniforms.uFogColor, linear_algebra_1.Vec3.copy(globalUniforms.uFogColor.ref.value, bgColor));
}
if (props.pickingAlphaThreshold !== undefined && props.pickingAlphaThreshold !== p.pickingAlphaThreshold) {
p.pickingAlphaThreshold = props.pickingAlphaThreshold;
mol_util_1.ValueCell.update(globalUniforms.uPickingAlphaThreshold, p.pickingAlphaThreshold);
}
if (props.interiorDarkening !== undefined && props.interiorDarkening !== p.interiorDarkening) {
p.interiorDarkening = props.interiorDarkening;
mol_util_1.ValueCell.update(globalUniforms.uInteriorDarkening, p.interiorDarkening);
}
if (props.interiorColorFlag !== undefined && props.interiorColorFlag !== p.interiorColorFlag) {
p.interiorColorFlag = props.interiorColorFlag;
mol_util_1.ValueCell.update(globalUniforms.uInteriorColorFlag, p.interiorColorFlag);
}
if (props.interiorColor !== undefined && props.interiorColor !== p.interiorColor) {
p.interiorColor = props.interiorColor;
mol_util_1.ValueCell.update(globalUniforms.uInteriorColor, color_1.Color.toVec3Normalized(globalUniforms.uInteriorColor.ref.value, p.interiorColor));
}
if (props.colorMarker !== undefined && props.colorMarker !== p.colorMarker) {
p.colorMarker = props.colorMarker;
}
if (props.highlightColor !== undefined && props.highlightColor !== p.highlightColor) {
p.highlightColor = props.highlightColor;
mol_util_1.ValueCell.update(globalUniforms.uHighlightColor, color_1.Color.toVec3Normalized(globalUniforms.uHighlightColor.ref.value, p.highlightColor));
}
if (props.selectColor !== undefined && props.selectColor !== p.selectColor) {
p.selectColor = props.selectColor;
mol_util_1.ValueCell.update(globalUniforms.uSelectColor, color_1.Color.toVec3Normalized(globalUniforms.uSelectColor.ref.value, p.selectColor));
}
if (props.highlightStrength !== undefined && props.highlightStrength !== p.highlightStrength) {
p.highlightStrength = props.highlightStrength;
mol_util_1.ValueCell.update(globalUniforms.uHighlightStrength, p.highlightStrength);
}
if (props.selectStrength !== undefined && props.selectStrength !== p.selectStrength) {
p.selectStrength = props.selectStrength;
mol_util_1.ValueCell.update(globalUniforms.uSelectStrength, p.selectStrength);
}
if (props.markerPriority !== undefined && props.markerPriority !== p.markerPriority) {
p.markerPriority = props.markerPriority;
mol_util_1.ValueCell.update(globalUniforms.uMarkerPriority, p.markerPriority);
}
if (props.xrayEdgeFalloff !== undefined && props.xrayEdgeFalloff !== p.xrayEdgeFalloff) {
p.xrayEdgeFalloff = props.xrayEdgeFalloff;
mol_util_1.ValueCell.update(globalUniforms.uXrayEdgeFalloff, p.xrayEdgeFalloff);
}
if (props.light !== undefined && !(0, mol_util_1.deepEqual)(props.light, p.light)) {
p.light = props.light;
Object.assign(light, getLight(props.light, light));
mol_util_1.ValueCell.update(globalUniforms.uLightDirection, light.direction);
mol_util_1.ValueCell.update(globalUniforms.uLightColor, light.color);
}
if (props.ambientColor !== undefined && props.ambientColor !== p.ambientColor) {
p.ambientColor = props.ambientColor;
linear_algebra_1.Vec3.scale(ambientColor, color_1.Color.toArrayNormalized(p.ambientColor, ambientColor, 0), p.ambientIntensity);
mol_util_1.ValueCell.update(globalUniforms.uAmbientColor, ambientColor);
}
if (props.ambientIntensity !== undefined && props.ambientIntensity !== p.ambientIntensity) {
p.ambientIntensity = props.ambientIntensity;
linear_algebra_1.Vec3.scale(ambientColor, color_1.Color.toArrayNormalized(p.ambientColor, ambientColor, 0), p.ambientIntensity);
mol_util_1.ValueCell.update(globalUniforms.uAmbientColor, ambientColor);
}
},
setViewport: function (x, y, width, height) {
state.viewport(x, y, width, height);
state.scissor(x, y, width, height);
if (x !== viewport.x || y !== viewport.y || width !== viewport.width || height !== viewport.height) {
util_1.Viewport.set(viewport, x, y, width, height);
mol_util_1.ValueCell.update(globalUniforms.uViewport, linear_algebra_1.Vec4.set(globalUniforms.uViewport.ref.value, x, y, width, height));
}
},
setTransparentBackground: function (value) {
transparentBackground = value;
},
setDrawingBufferSize: function (width, height) {
if (width !== drawingBufferSize[0] || height !== drawingBufferSize[1]) {
mol_util_1.ValueCell.update(globalUniforms.uDrawingBufferSize, linear_algebra_1.Vec2.set(drawingBufferSize, width, height));
}
},
setPixelRatio: function (value) {
mol_util_1.ValueCell.update(globalUniforms.uPixelRatio, value);
},
props: p,
get stats() {
return {
programCount: ctx.stats.resourceCounts.program,
shaderCount: ctx.stats.resourceCounts.shader,
attributeCount: ctx.stats.resourceCounts.attribute,
elementsCount: ctx.stats.resourceCounts.elements,
framebufferCount: ctx.stats.resourceCounts.framebuffer,
renderbufferCount: ctx.stats.resourceCounts.renderbuffer,
textureCount: ctx.stats.resourceCounts.texture,
vertexArrayCount: ctx.stats.resourceCounts.vertexArray,
drawCount: stats.drawCount,
instanceCount: stats.instanceCount,
instancedDrawCount: stats.instancedDrawCount,
};
},
dispose: function () {
// TODO
}
};
}
Renderer.create = create;
})(Renderer || (Renderer = {}));
exports.Renderer = Renderer;