molstar
Version:
A comprehensive macromolecular library.
595 lines • 32.3 kB
JavaScript
/**
* Copyright (c) 2018-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { Viewport } from '../mol-canvas3d/camera/util';
import { Mat4, Vec3, Vec4, Vec2, Quat } from '../mol-math/linear-algebra';
import { Color } from '../mol-util/color';
import { ValueCell, deepEqual } from '../mol-util';
import { ParamDefinition as PD } from '../mol-util/param-definition';
import { Clipping } from '../mol-theme/clipping';
import { stringToWords } from '../mol-util/string';
import { degToRad } from '../mol-math/misc';
import { createNullTexture } from './webgl/texture';
import { arrayMapUpsert } from '../mol-util/array';
import { clamp } from '../mol-math/interpolate';
export var RendererParams = {
backgroundColor: PD.Color(Color(0x000000), { description: 'Background color of the 3D canvas' }),
// the following are general 'material' parameters
pickingAlphaThreshold: PD.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: PD.Numeric(0.5, { min: 0.0, max: 1.0, step: 0.01 }),
interiorColorFlag: PD.Boolean(true, { label: 'Use Interior Color' }),
interiorColor: PD.Color(Color.fromNormalizedRgb(0.3, 0.3, 0.3)),
highlightColor: PD.Color(Color.fromNormalizedRgb(1.0, 0.4, 0.6)),
selectColor: PD.Color(Color.fromNormalizedRgb(0.2, 1.0, 0.1)),
highlightStrength: PD.Numeric(0.7, { min: 0.0, max: 1.0, step: 0.1 }),
selectStrength: PD.Numeric(0.7, { min: 0.0, max: 1.0, step: 0.1 }),
markerPriority: PD.Select(1, [[1, 'Highlight'], [2, 'Select']]),
xrayEdgeFalloff: PD.Numeric(1, { min: 0.0, max: 3.0, step: 0.1 }),
style: PD.MappedStatic('matte', {
custom: PD.Group({
lightIntensity: PD.Numeric(0.6, { min: 0.0, max: 1.0, step: 0.01 }),
ambientIntensity: PD.Numeric(0.4, { min: 0.0, max: 1.0, step: 0.01 }),
metalness: PD.Numeric(0.0, { min: 0.0, max: 1.0, step: 0.01 }),
roughness: PD.Numeric(1.0, { min: 0.0, max: 1.0, step: 0.01 }),
reflectivity: PD.Numeric(0.5, { min: 0.0, max: 1.0, step: 0.01 }),
}, { isExpanded: true }),
flat: PD.Group({}),
matte: PD.Group({}),
glossy: PD.Group({}),
metallic: PD.Group({}),
plastic: PD.Group({}),
}, { label: 'Lighting', description: 'Style in which the 3D scene is rendered/lighted' }),
clip: PD.Group({
variant: PD.Select('instance', PD.arrayToOptions(['instance', 'pixel'])),
objects: PD.ObjectList({
type: PD.Select('plane', PD.objectToOptions(Clipping.Type, function (t) { return stringToWords(t); })),
invert: PD.Boolean(false),
position: PD.Vec3(Vec3()),
rotation: PD.Group({
axis: PD.Vec3(Vec3.create(1, 0, 0)),
angle: PD.Numeric(0, { min: -180, max: 180, step: 1 }, { description: 'Angle in Degrees' }),
}, { isExpanded: true }),
scale: PD.Vec3(Vec3.create(1, 1, 1)),
}, function (o) { return stringToWords(o.type); })
})
};
export function getStyle(props) {
switch (props.name) {
case 'custom':
return props.params;
case 'flat':
return {
lightIntensity: 0, ambientIntensity: 1,
metalness: 0, roughness: 0.4, reflectivity: 0.5
};
case 'matte':
return {
lightIntensity: 0.7, ambientIntensity: 0.3,
metalness: 0, roughness: 1, reflectivity: 0.5
};
case 'glossy':
return {
lightIntensity: 0.7, ambientIntensity: 0.3,
metalness: 0, roughness: 0.4, reflectivity: 0.5
};
case 'metallic':
return {
lightIntensity: 0.7, ambientIntensity: 0.7,
metalness: 0.6, roughness: 0.6, reflectivity: 0.5
};
case 'plastic':
return {
lightIntensity: 0.7, ambientIntensity: 0.3,
metalness: 0, roughness: 0.2, reflectivity: 0.5
};
}
}
var tmpQuat = Quat();
function getClip(props, clip) {
var _a = (clip === null || clip === void 0 ? void 0 : clip.objects) || {
type: (new Array(5)).fill(1),
invert: (new Array(5)).fill(false),
position: (new Array(5 * 3)).fill(0),
rotation: (new Array(5 * 4)).fill(0),
scale: (new Array(5 * 3)).fill(1),
}, type = _a.type, invert = _a.invert, position = _a.position, rotation = _a.rotation, scale = _a.scale;
for (var i = 0, il = props.objects.length; i < il; ++i) {
var p = props.objects[i];
type[i] = Clipping.Type[p.type];
invert[i] = p.invert;
Vec3.toArray(p.position, position, i * 3);
Quat.toArray(Quat.setAxisAngle(tmpQuat, p.rotation.axis, degToRad(p.rotation.angle)), rotation, i * 4);
Vec3.toArray(p.scale, scale, i * 3);
}
return {
variant: props.variant,
objects: { count: props.objects.length, type: type, invert: invert, position: position, rotation: rotation, scale: scale }
};
}
var Renderer;
(function (Renderer) {
function create(ctx, props) {
if (props === void 0) { props = {}; }
var gl = ctx.gl, state = ctx.state, stats = ctx.stats, fragDepth = ctx.extensions.fragDepth;
var p = PD.merge(RendererParams, PD.getDefaultValues(RendererParams), props);
var style = getStyle(p.style);
var clip = getClip(p.clip);
var viewport = Viewport();
var drawingBufferSize = Vec2.create(gl.drawingBufferWidth, gl.drawingBufferHeight);
var bgColor = Color.toVec3Normalized(Vec3(), p.backgroundColor);
var transparentBackground = false;
var nullDepthTexture = createNullTexture(gl);
var sharedTexturesList = [
['tDepth', nullDepthTexture]
];
var view = Mat4();
var invView = Mat4();
var modelView = Mat4();
var invModelView = Mat4();
var invProjection = Mat4();
var modelViewProjection = Mat4();
var invModelViewProjection = Mat4();
var cameraDir = Vec3();
var viewOffset = Vec2();
var globalUniforms = {
uModel: ValueCell.create(Mat4.identity()),
uView: ValueCell.create(view),
uInvView: ValueCell.create(invView),
uModelView: ValueCell.create(modelView),
uInvModelView: ValueCell.create(invModelView),
uInvProjection: ValueCell.create(invProjection),
uProjection: ValueCell.create(Mat4()),
uModelViewProjection: ValueCell.create(modelViewProjection),
uInvModelViewProjection: ValueCell.create(invModelViewProjection),
uIsOrtho: ValueCell.create(1),
uViewOffset: ValueCell.create(viewOffset),
uPixelRatio: ValueCell.create(ctx.pixelRatio),
uViewport: ValueCell.create(Viewport.toVec4(Vec4(), viewport)),
uDrawingBufferSize: ValueCell.create(drawingBufferSize),
uCameraPosition: ValueCell.create(Vec3()),
uCameraDir: ValueCell.create(cameraDir),
uNear: ValueCell.create(1),
uFar: ValueCell.create(10000),
uFogNear: ValueCell.create(1),
uFogFar: ValueCell.create(10000),
uFogColor: ValueCell.create(bgColor),
uRenderWboit: ValueCell.create(false),
uMarkingDepthTest: ValueCell.create(false),
uTransparentBackground: ValueCell.create(false),
uClipObjectType: ValueCell.create(clip.objects.type),
uClipObjectInvert: ValueCell.create(clip.objects.invert),
uClipObjectPosition: ValueCell.create(clip.objects.position),
uClipObjectRotation: ValueCell.create(clip.objects.rotation),
uClipObjectScale: ValueCell.create(clip.objects.scale),
// the following are general 'material' uniforms
uLightIntensity: ValueCell.create(style.lightIntensity),
uAmbientIntensity: ValueCell.create(style.ambientIntensity),
uMetalness: ValueCell.create(style.metalness),
uRoughness: ValueCell.create(style.roughness),
uReflectivity: ValueCell.create(style.reflectivity),
uPickingAlphaThreshold: ValueCell.create(p.pickingAlphaThreshold),
uInteriorDarkening: ValueCell.create(p.interiorDarkening),
uInteriorColorFlag: ValueCell.create(p.interiorColorFlag),
uInteriorColor: ValueCell.create(Color.toVec3Normalized(Vec3(), p.interiorColor)),
uHighlightColor: ValueCell.create(Color.toVec3Normalized(Vec3(), p.highlightColor)),
uSelectColor: ValueCell.create(Color.toVec3Normalized(Vec3(), p.selectColor)),
uHighlightStrength: ValueCell.create(p.highlightStrength),
uSelectStrength: ValueCell.create(p.selectStrength),
uMarkerPriority: ValueCell.create(p.markerPriority),
uXrayEdgeFalloff: ValueCell.create(p.xrayEdgeFalloff),
};
var globalUniformList = Object.entries(globalUniforms);
var globalUniformsNeedUpdate = true;
var renderObject = function (r, variant) {
if (r.state.disposed || !r.state.visible || (!r.state.pickable && variant[0] === 'p')) {
return;
}
var definesNeedUpdate = false;
if (r.state.noClip) {
if (r.values.dClipObjectCount.ref.value !== 0) {
ValueCell.update(r.values.dClipObjectCount, 0);
definesNeedUpdate = true;
}
}
else {
if (r.values.dClipObjectCount.ref.value !== clip.objects.count) {
ValueCell.update(r.values.dClipObjectCount, clip.objects.count);
definesNeedUpdate = true;
}
if (r.values.dClipVariant.ref.value !== clip.variant) {
ValueCell.update(r.values.dClipVariant, clip.variant);
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);
globalUniformsNeedUpdate = false;
}
if (r.values.dRenderMode) { // indicates direct-volume
// 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`
// still need to enable when fragDepth can be used to write depth
if (r.values.dRenderMode.ref.value === 'volume' || !fragDepth) {
state.disable(gl.DEPTH_TEST);
state.depthMask(false);
}
else {
state.enable(gl.DEPTH_TEST);
state.depthMask(r.values.uAlpha.ref.value === 1.0);
}
}
}
else {
if (r.values.dDoubleSided) {
if (r.values.dDoubleSided.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 (r.values.dFlipSided) {
if (r.values.dFlipSided.ref.value) {
state.frontFace(gl.CW);
state.cullFace(gl.FRONT);
}
else {
state.frontFace(gl.CCW);
state.cullFace(gl.BACK);
}
}
else {
// webgl default
state.frontFace(gl.CCW);
state.cullFace(gl.BACK);
}
}
r.render(variant, sharedTexturesList);
};
var update = function (camera) {
ValueCell.update(globalUniforms.uView, camera.view);
ValueCell.update(globalUniforms.uInvView, Mat4.invert(invView, camera.view));
ValueCell.update(globalUniforms.uProjection, camera.projection);
ValueCell.update(globalUniforms.uInvProjection, Mat4.invert(invProjection, camera.projection));
ValueCell.updateIfChanged(globalUniforms.uIsOrtho, camera.state.mode === 'orthographic' ? 1 : 0);
ValueCell.update(globalUniforms.uViewOffset, camera.viewOffset.enabled ? Vec2.set(viewOffset, camera.viewOffset.offsetX * 16, camera.viewOffset.offsetY * 16) : Vec2.set(viewOffset, 0, 0));
ValueCell.update(globalUniforms.uCameraPosition, camera.state.position);
ValueCell.update(globalUniforms.uCameraDir, Vec3.normalize(cameraDir, Vec3.sub(cameraDir, camera.state.target, camera.state.position)));
ValueCell.updateIfChanged(globalUniforms.uFar, camera.far);
ValueCell.updateIfChanged(globalUniforms.uNear, camera.near);
ValueCell.updateIfChanged(globalUniforms.uFogFar, camera.fogFar);
ValueCell.updateIfChanged(globalUniforms.uFogNear, camera.fogNear);
ValueCell.updateIfChanged(globalUniforms.uTransparentBackground, transparentBackground);
};
var updateInternal = function (group, camera, depthTexture, renderWboit, markingDepthTest) {
arrayMapUpsert(sharedTexturesList, 'tDepth', depthTexture || nullDepthTexture);
ValueCell.update(globalUniforms.uModel, group.view);
ValueCell.update(globalUniforms.uModelView, Mat4.mul(modelView, group.view, camera.view));
ValueCell.update(globalUniforms.uInvModelView, Mat4.invert(invModelView, modelView));
ValueCell.update(globalUniforms.uModelViewProjection, Mat4.mul(modelViewProjection, modelView, camera.projection));
ValueCell.update(globalUniforms.uInvModelViewProjection, Mat4.invert(invModelViewProjection, modelViewProjection));
ValueCell.updateIfChanged(globalUniforms.uRenderWboit, renderWboit);
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;
gl.viewport(x, y, width, height);
gl.scissor(x, y, width, height);
globalUniformsNeedUpdate = true;
state.currentRenderItemId = -1;
};
var renderPick = function (group, camera, variant, depthTexture) {
state.disable(gl.BLEND);
state.enable(gl.DEPTH_TEST);
state.depthMask(true);
updateInternal(group, camera, depthTexture, false, false);
var renderables = group.renderables;
for (var i = 0, il = renderables.length; i < il; ++i) {
if (!renderables[i].state.colorOnly) {
renderObject(renderables[i], variant);
}
}
};
var renderDepth = function (group, camera, depthTexture) {
state.disable(gl.BLEND);
state.enable(gl.DEPTH_TEST);
state.depthMask(true);
updateInternal(group, camera, depthTexture, false, false);
var renderables = group.renderables;
for (var i = 0, il = renderables.length; i < il; ++i) {
renderObject(renderables[i], 'depth');
}
};
var renderMarkingDepth = function (group, camera, depthTexture) {
state.disable(gl.BLEND);
state.enable(gl.DEPTH_TEST);
state.depthMask(true);
updateInternal(group, camera, depthTexture, false, false);
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], 'markingDepth');
}
}
};
var renderMarkingMask = function (group, camera, depthTexture) {
state.disable(gl.BLEND);
state.enable(gl.DEPTH_TEST);
state.depthMask(true);
updateInternal(group, camera, depthTexture, false, !!depthTexture);
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], 'markingMask');
}
}
};
var renderBlended = function (group, camera, depthTexture) {
renderBlendedOpaque(group, camera, depthTexture);
renderBlendedTransparent(group, camera, depthTexture);
};
var renderBlendedOpaque = function (group, camera, depthTexture) {
state.disable(gl.BLEND);
state.enable(gl.DEPTH_TEST);
state.depthMask(true);
updateInternal(group, camera, depthTexture, false, 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');
}
}
};
var renderBlendedTransparent = function (group, camera, depthTexture) {
state.enable(gl.DEPTH_TEST);
updateInternal(group, camera, depthTexture, false, 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');
}
}
state.depthMask(false);
for (var i = 0, il = renderables.length; i < il; ++i) {
var r = renderables[i];
if (!r.state.opaque && !r.state.writeDepth) {
renderObject(r, 'colorBlended');
}
}
};
var renderBlendedVolumeOpaque = function (group, camera, depthTexture) {
var _a;
state.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
state.enable(gl.BLEND);
updateInternal(group, camera, depthTexture, false, 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 = clamp(r.values.alpha.ref.value * r.state.alphaFactor, 0, 1);
if (alpha === 1 && r.values.transparencyAverage.ref.value !== 1 && !((_a = r.values.dXrayShaded) === null || _a === void 0 ? void 0 : _a.ref.value)) {
renderObject(r, 'colorBlended');
}
}
};
var renderBlendedVolumeTransparent = function (group, camera, depthTexture) {
var _a;
state.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
state.enable(gl.BLEND);
updateInternal(group, camera, depthTexture, false, 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 = clamp(r.values.alpha.ref.value * r.state.alphaFactor, 0, 1);
if (alpha < 1 || r.values.transparencyAverage.ref.value > 0 || ((_a = r.values.dXrayShaded) === null || _a === void 0 ? void 0 : _a.ref.value)) {
renderObject(r, 'colorBlended');
}
}
};
var renderWboitOpaque = function (group, camera, depthTexture) {
var _a, _b, _c;
state.disable(gl.BLEND);
state.enable(gl.DEPTH_TEST);
state.depthMask(true);
updateInternal(group, camera, depthTexture, false, 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 = clamp(r.values.alpha.ref.value * r.state.alphaFactor, 0, 1);
if (alpha === 1 && r.values.transparencyAverage.ref.value !== 1 && ((_a = r.values.dRenderMode) === null || _a === void 0 ? void 0 : _a.ref.value) !== 'volume' && ((_b = r.values.dPointStyle) === null || _b === void 0 ? void 0 : _b.ref.value) !== 'fuzzy' && !((_c = r.values.dXrayShaded) === null || _c === void 0 ? void 0 : _c.ref.value)) {
renderObject(r, 'colorWboit');
}
}
};
var renderWboitTransparent = function (group, camera, depthTexture) {
var _a, _b, _c;
updateInternal(group, camera, depthTexture, true, 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 = clamp(r.values.alpha.ref.value * r.state.alphaFactor, 0, 1);
if (alpha < 1 || r.values.transparencyAverage.ref.value > 0 || ((_a = r.values.dRenderMode) === null || _a === void 0 ? void 0 : _a.ref.value) === 'volume' || ((_b = r.values.dPointStyle) === null || _b === void 0 ? void 0 : _b.ref.value) === 'fuzzy' || !!r.values.uBackgroundColor || ((_c = r.values.dXrayShaded) === null || _c === void 0 ? void 0 : _c.ref.value)) {
renderObject(r, 'colorWboit');
}
}
};
return {
clear: function (toBackgroundColor) {
state.enable(gl.SCISSOR_TEST);
state.enable(gl.DEPTH_TEST);
state.colorMask(true, true, true, true);
state.depthMask(true);
if (transparentBackground) {
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 () {
state.enable(gl.SCISSOR_TEST);
state.enable(gl.DEPTH_TEST);
state.depthMask(true);
gl.clear(gl.DEPTH_BUFFER_BIT);
},
update: update,
renderPick: renderPick,
renderDepth: renderDepth,
renderMarkingDepth: renderMarkingDepth,
renderMarkingMask: renderMarkingMask,
renderBlended: renderBlended,
renderBlendedOpaque: renderBlendedOpaque,
renderBlendedTransparent: renderBlendedTransparent,
renderBlendedVolumeOpaque: renderBlendedVolumeOpaque,
renderBlendedVolumeTransparent: renderBlendedVolumeTransparent,
renderWboitOpaque: renderWboitOpaque,
renderWboitTransparent: renderWboitTransparent,
setProps: function (props) {
if (props.backgroundColor !== undefined && props.backgroundColor !== p.backgroundColor) {
p.backgroundColor = props.backgroundColor;
Color.toVec3Normalized(bgColor, p.backgroundColor);
ValueCell.update(globalUniforms.uFogColor, Vec3.copy(globalUniforms.uFogColor.ref.value, bgColor));
}
if (props.pickingAlphaThreshold !== undefined && props.pickingAlphaThreshold !== p.pickingAlphaThreshold) {
p.pickingAlphaThreshold = props.pickingAlphaThreshold;
ValueCell.update(globalUniforms.uPickingAlphaThreshold, p.pickingAlphaThreshold);
}
if (props.interiorDarkening !== undefined && props.interiorDarkening !== p.interiorDarkening) {
p.interiorDarkening = props.interiorDarkening;
ValueCell.update(globalUniforms.uInteriorDarkening, p.interiorDarkening);
}
if (props.interiorColorFlag !== undefined && props.interiorColorFlag !== p.interiorColorFlag) {
p.interiorColorFlag = props.interiorColorFlag;
ValueCell.update(globalUniforms.uInteriorColorFlag, p.interiorColorFlag);
}
if (props.interiorColor !== undefined && props.interiorColor !== p.interiorColor) {
p.interiorColor = props.interiorColor;
ValueCell.update(globalUniforms.uInteriorColor, Color.toVec3Normalized(globalUniforms.uInteriorColor.ref.value, p.interiorColor));
}
if (props.highlightColor !== undefined && props.highlightColor !== p.highlightColor) {
p.highlightColor = props.highlightColor;
ValueCell.update(globalUniforms.uHighlightColor, Color.toVec3Normalized(globalUniforms.uHighlightColor.ref.value, p.highlightColor));
}
if (props.selectColor !== undefined && props.selectColor !== p.selectColor) {
p.selectColor = props.selectColor;
ValueCell.update(globalUniforms.uSelectColor, Color.toVec3Normalized(globalUniforms.uSelectColor.ref.value, p.selectColor));
}
if (props.highlightStrength !== undefined && props.highlightStrength !== p.highlightStrength) {
p.highlightStrength = props.highlightStrength;
ValueCell.update(globalUniforms.uHighlightStrength, p.highlightStrength);
}
if (props.selectStrength !== undefined && props.selectStrength !== p.selectStrength) {
p.selectStrength = props.selectStrength;
ValueCell.update(globalUniforms.uSelectStrength, p.selectStrength);
}
if (props.markerPriority !== undefined && props.markerPriority !== p.markerPriority) {
p.markerPriority = props.markerPriority;
ValueCell.update(globalUniforms.uMarkerPriority, p.markerPriority);
}
if (props.xrayEdgeFalloff !== undefined && props.xrayEdgeFalloff !== p.xrayEdgeFalloff) {
p.xrayEdgeFalloff = props.xrayEdgeFalloff;
ValueCell.update(globalUniforms.uXrayEdgeFalloff, p.xrayEdgeFalloff);
}
if (props.style !== undefined) {
p.style = props.style;
Object.assign(style, getStyle(props.style));
ValueCell.updateIfChanged(globalUniforms.uLightIntensity, style.lightIntensity);
ValueCell.updateIfChanged(globalUniforms.uAmbientIntensity, style.ambientIntensity);
ValueCell.updateIfChanged(globalUniforms.uMetalness, style.metalness);
ValueCell.updateIfChanged(globalUniforms.uRoughness, style.roughness);
ValueCell.updateIfChanged(globalUniforms.uReflectivity, style.reflectivity);
}
if (props.clip !== undefined && !deepEqual(props.clip, p.clip)) {
p.clip = props.clip;
Object.assign(clip, getClip(props.clip, clip));
ValueCell.update(globalUniforms.uClipObjectPosition, clip.objects.position);
ValueCell.update(globalUniforms.uClipObjectRotation, clip.objects.rotation);
ValueCell.update(globalUniforms.uClipObjectScale, clip.objects.scale);
ValueCell.update(globalUniforms.uClipObjectType, clip.objects.type);
}
},
setViewport: function (x, y, width, height) {
gl.viewport(x, y, width, height);
gl.scissor(x, y, width, height);
if (x !== viewport.x || y !== viewport.y || width !== viewport.width || height !== viewport.height) {
Viewport.set(viewport, x, y, width, height);
ValueCell.update(globalUniforms.uViewport, 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]) {
ValueCell.update(globalUniforms.uDrawingBufferSize, Vec2.set(drawingBufferSize, width, height));
}
},
setPixelRatio: function (value) {
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 = {}));
export { Renderer };
//# sourceMappingURL=renderer.js.map