molstar
Version:
A comprehensive macromolecular library.
740 lines • 35 kB
JavaScript
/**
* Copyright (c) 2018-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
* @author David Sehnal <david.sehnal@gmail.com>
*/
import { __assign } from "tslib";
import { BehaviorSubject } from 'rxjs';
import { now } from '../mol-util/now';
import { Vec3 } from '../mol-math/linear-algebra';
import { InputObserver } from '../mol-util/input/input-observer';
import { Renderer, RendererParams } from '../mol-gl/renderer';
import { TrackballControls, TrackballControlsParams } from './controls/trackball';
import { Viewport } from './camera/util';
import { createContext, getGLContext } from '../mol-gl/webgl/context';
import { Representation } from '../mol-repr/representation';
import { Scene } from '../mol-gl/scene';
import { EmptyLoci, isEmptyLoci } from '../mol-model/loci';
import { Camera } from './camera';
import { ParamDefinition as PD } from '../mol-util/param-definition';
import { DebugHelperParams } from './helper/bounding-sphere-helper';
import { SetUtils } from '../mol-util/set';
import { Canvas3dInteractionHelper, Canvas3dInteractionHelperParams } from './helper/interaction-events';
import { PostprocessingParams } from './passes/postprocessing';
import { MultiSampleHelper, MultiSampleParams, MultiSamplePass } from './passes/multi-sample';
import { PickHelper } from './passes/pick';
import { ImagePass } from './passes/image';
import { Sphere3D } from '../mol-math/geometry';
import { isDebugMode } from '../mol-util/debug';
import { CameraHelperParams } from './helper/camera-helper';
import { produce } from 'immer';
import { HandleHelperParams } from './helper/handle-helper';
import { StereoCamera, StereoCameraParams } from './camera/stereo';
import { Helper } from './helper/helper';
import { Passes } from './passes/passes';
import { shallowEqual } from '../mol-util';
import { MarkingParams } from './passes/marking';
export var Canvas3DParams = {
camera: PD.Group({
mode: PD.Select('perspective', PD.arrayToOptions(['perspective', 'orthographic']), { label: 'Camera' }),
helper: PD.Group(CameraHelperParams, { isFlat: true }),
stereo: PD.MappedStatic('off', {
on: PD.Group(StereoCameraParams),
off: PD.Group({})
}, { cycle: true, hideIf: function (p) { return (p === null || p === void 0 ? void 0 : p.mode) !== 'perspective'; } }),
manualReset: PD.Boolean(false, { isHidden: true }),
}, { pivot: 'mode' }),
cameraFog: PD.MappedStatic('on', {
on: PD.Group({
intensity: PD.Numeric(15, { min: 1, max: 100, step: 1 }),
}),
off: PD.Group({})
}, { cycle: true, description: 'Show fog in the distance' }),
cameraClipping: PD.Group({
radius: PD.Numeric(100, { min: 0, max: 99, step: 1 }, { label: 'Clipping', description: 'How much of the scene to show.' }),
far: PD.Boolean(true, { description: 'Hide scene in the distance' }),
}, { pivot: 'radius' }),
viewport: PD.MappedStatic('canvas', {
canvas: PD.Group({}),
'static-frame': PD.Group({
x: PD.Numeric(0),
y: PD.Numeric(0),
width: PD.Numeric(128),
height: PD.Numeric(128)
}),
'relative-frame': PD.Group({
x: PD.Numeric(0.33, { min: 0, max: 1, step: 0.01 }),
y: PD.Numeric(0.33, { min: 0, max: 1, step: 0.01 }),
width: PD.Numeric(0.5, { min: 0.01, max: 1, step: 0.01 }),
height: PD.Numeric(0.5, { min: 0.01, max: 1, step: 0.01 })
})
}),
cameraResetDurationMs: PD.Numeric(250, { min: 0, max: 1000, step: 1 }, { description: 'The time it takes to reset the camera.' }),
transparentBackground: PD.Boolean(false),
multiSample: PD.Group(MultiSampleParams),
postprocessing: PD.Group(PostprocessingParams),
marking: PD.Group(MarkingParams),
renderer: PD.Group(RendererParams),
trackball: PD.Group(TrackballControlsParams),
interaction: PD.Group(Canvas3dInteractionHelperParams),
debug: PD.Group(DebugHelperParams),
handle: PD.Group(HandleHelperParams),
};
export var DefaultCanvas3DParams = PD.getDefaultValues(Canvas3DParams);
export { Canvas3DContext };
var Canvas3DContext;
(function (Canvas3DContext) {
Canvas3DContext.DefaultAttribs = {
/** true by default to avoid issues with Safari (Jan 2021) */
antialias: true,
/** true to support multiple Canvas3D objects with a single context */
preserveDrawingBuffer: true,
pixelScale: 1,
pickScale: 0.25,
/** extra pixels to around target to check in case target is empty */
pickPadding: 1,
enableWboit: true,
preferWebGl1: false
};
function fromCanvas(canvas, attribs) {
if (attribs === void 0) { attribs = {}; }
var a = __assign(__assign({}, Canvas3DContext.DefaultAttribs), attribs);
var antialias = a.antialias, preserveDrawingBuffer = a.preserveDrawingBuffer, pixelScale = a.pixelScale, preferWebGl1 = a.preferWebGl1;
var gl = getGLContext(canvas, {
antialias: antialias,
preserveDrawingBuffer: preserveDrawingBuffer,
alpha: true,
depth: true,
premultipliedAlpha: true,
preferWebGl1: preferWebGl1
});
if (gl === null)
throw new Error('Could not create a WebGL rendering context');
var input = InputObserver.fromElement(canvas, { pixelScale: pixelScale, preventGestures: true });
var webgl = createContext(gl, { pixelScale: pixelScale });
var passes = new Passes(webgl, attribs);
if (isDebugMode) {
var loseContextExt_1 = gl.getExtension('WEBGL_lose_context');
if (loseContextExt_1) {
// Hold down shift+ctrl+alt and press any mouse button to call `loseContext`.
// After 1 second `restoreContext` will be called.
canvas.addEventListener('mousedown', function (e) {
if (webgl.isContextLost)
return;
if (!e.shiftKey || !e.ctrlKey || !e.altKey)
return;
if (isDebugMode)
console.log('lose context');
loseContextExt_1.loseContext();
setTimeout(function () {
if (!webgl.isContextLost)
return;
if (isDebugMode)
console.log('restore context');
loseContextExt_1.restoreContext();
}, 1000);
}, false);
}
}
// https://www.khronos.org/webgl/wiki/HandlingContextLost
var contextLost = new BehaviorSubject(0);
var handleWebglContextLost = function (e) {
webgl.setContextLost();
e.preventDefault();
if (isDebugMode)
console.log('context lost');
contextLost.next(now());
};
var handlewWebglContextRestored = function () {
if (!webgl.isContextLost)
return;
webgl.handleContextRestored(function () {
passes.draw.reset();
});
if (isDebugMode)
console.log('context restored');
};
canvas.addEventListener('webglcontextlost', handleWebglContextLost, false);
canvas.addEventListener('webglcontextrestored', handlewWebglContextRestored, false);
return {
canvas: canvas,
webgl: webgl,
input: input,
passes: passes,
attribs: a,
contextLost: contextLost,
contextRestored: webgl.contextRestored,
dispose: function (options) {
input.dispose();
canvas.removeEventListener('webglcontextlost', handleWebglContextLost, false);
canvas.removeEventListener('webglcontextrestored', handlewWebglContextRestored, false);
webgl.destroy(options);
}
};
}
Canvas3DContext.fromCanvas = fromCanvas;
})(Canvas3DContext || (Canvas3DContext = {}));
export { Canvas3D };
var requestAnimationFrame = typeof window !== 'undefined'
? window.requestAnimationFrame
: function (f) { return setImmediate(function () { return f(Date.now()); }); };
var cancelAnimationFrame = typeof window !== 'undefined'
? window.cancelAnimationFrame
: function (handle) { return clearImmediate(handle); };
var Canvas3D;
(function (Canvas3D) {
function create(_a, props) {
var webgl = _a.webgl, input = _a.input, passes = _a.passes, attribs = _a.attribs;
if (props === void 0) { props = {}; }
var p = __assign(__assign({}, DefaultCanvas3DParams), props);
var reprRenderObjects = new Map();
var reprUpdatedSubscriptions = new Map();
var reprCount = new BehaviorSubject(0);
var startTime = now();
var didDraw = new BehaviorSubject(0);
var commited = new BehaviorSubject(0);
var gl = webgl.gl, contextRestored = webgl.contextRestored;
var x = 0;
var y = 0;
var width = 128;
var height = 128;
updateViewport();
var scene = Scene.create(webgl);
var camera = new Camera({
position: Vec3.create(0, 0, 100),
mode: p.camera.mode,
fog: p.cameraFog.name === 'on' ? p.cameraFog.params.intensity : 0,
clipFar: p.cameraClipping.far
}, { x: x, y: y, width: width, height: height }, { pixelScale: attribs.pixelScale });
var stereoCamera = new StereoCamera(camera, p.camera.stereo.params);
var controls = TrackballControls.create(input, camera, p.trackball);
var renderer = Renderer.create(webgl, p.renderer);
var helper = new Helper(webgl, scene, p);
var pickHelper = new PickHelper(webgl, renderer, scene, helper, passes.pick, { x: x, y: y, width: width, height: height }, attribs.pickPadding);
var interactionHelper = new Canvas3dInteractionHelper(identify, getLoci, input, camera, p.interaction);
var multiSampleHelper = new MultiSampleHelper(passes.multiSample);
var cameraResetRequested = false;
var nextCameraResetDuration = void 0;
var nextCameraResetSnapshot = void 0;
var resizeRequested = false;
var notifyDidDraw = true;
function getLoci(pickingId) {
var loci = EmptyLoci;
var repr = Representation.Empty;
if (pickingId) {
var cameraHelperLoci = helper.camera.getLoci(pickingId);
if (cameraHelperLoci !== EmptyLoci)
return { loci: cameraHelperLoci, repr: repr };
loci = helper.handle.getLoci(pickingId);
reprRenderObjects.forEach(function (_, _repr) {
var _loci = _repr.getLoci(pickingId);
if (!isEmptyLoci(_loci)) {
if (!isEmptyLoci(loci)) {
console.warn('found another loci, this should not happen');
}
loci = _loci;
repr = _repr;
}
});
}
return { loci: loci, repr: repr };
}
function mark(reprLoci, action, noDraw) {
if (noDraw === void 0) { noDraw = false; }
var repr = reprLoci.repr, loci = reprLoci.loci;
var changed = false;
if (repr) {
changed = repr.mark(loci, action);
}
else {
changed = helper.handle.mark(loci, action);
changed = helper.camera.mark(loci, action) || changed;
reprRenderObjects.forEach(function (_, _repr) { changed = _repr.mark(loci, action) || changed; });
}
if (changed && !noDraw) {
scene.update(void 0, true);
helper.handle.scene.update(void 0, true);
helper.camera.scene.update(void 0, true);
var prevPickDirty = pickHelper.dirty;
draw(true);
pickHelper.dirty = prevPickDirty; // marking does not change picking buffers
}
}
function render(force) {
if (webgl.isContextLost)
return false;
var resized = false;
if (resizeRequested) {
handleResize(false);
resizeRequested = false;
resized = true;
}
if (x > gl.drawingBufferWidth || x + width < 0 ||
y > gl.drawingBufferHeight || y + height < 0)
return false;
var didRender = false;
controls.update(currentTime);
var cameraChanged = camera.update();
var shouldRender = force || cameraChanged || resized || forceNextRender;
forceNextRender = false;
var multiSampleChanged = multiSampleHelper.update(shouldRender, p.multiSample);
if (shouldRender || multiSampleChanged) {
var cam = camera;
if (p.camera.stereo.name === 'on') {
stereoCamera.update();
cam = stereoCamera;
}
if (MultiSamplePass.isEnabled(p.multiSample)) {
multiSampleHelper.render(renderer, cam, scene, helper, true, p.transparentBackground, p);
}
else {
passes.draw.render(renderer, cam, scene, helper, true, p.transparentBackground, p.postprocessing, p.marking);
}
pickHelper.dirty = true;
didRender = true;
}
return didRender;
}
var forceNextRender = false;
var forceDrawAfterAllCommited = false;
var currentTime = 0;
var drawPaused = false;
function draw(force) {
if (drawPaused)
return;
if (render(!!force) && notifyDidDraw) {
didDraw.next(now() - startTime);
}
}
function requestDraw(force) {
forceNextRender = forceNextRender || !!force;
}
var animationFrameHandle = 0;
function tick(t, options) {
currentTime = t;
commit(options === null || options === void 0 ? void 0 : options.isSynchronous);
camera.transition.tick(currentTime);
if (options === null || options === void 0 ? void 0 : options.manualDraw) {
return;
}
draw(false);
if (!camera.transition.inTransition && !webgl.isContextLost) {
interactionHelper.tick(currentTime);
}
}
function _animate() {
tick(now());
animationFrameHandle = requestAnimationFrame(_animate);
}
function resetTime(t) {
startTime = t;
controls.start(t);
}
function animate() {
drawPaused = false;
controls.start(now());
if (animationFrameHandle === 0)
_animate();
}
function pause(noDraw) {
if (noDraw === void 0) { noDraw = false; }
drawPaused = noDraw;
cancelAnimationFrame(animationFrameHandle);
animationFrameHandle = 0;
}
function identify(x, y) {
var cam = p.camera.stereo.name === 'on' ? stereoCamera : camera;
return webgl.isContextLost ? undefined : pickHelper.identify(x, y, cam);
}
function commit(isSynchronous) {
if (isSynchronous === void 0) { isSynchronous = false; }
var allCommited = commitScene(isSynchronous);
// Only reset the camera after the full scene has been commited.
if (allCommited) {
resolveCameraReset();
if (forceDrawAfterAllCommited) {
if (helper.debug.isEnabled)
helper.debug.update();
draw(true);
forceDrawAfterAllCommited = false;
}
commited.next(now());
}
}
function resolveCameraReset() {
if (!cameraResetRequested)
return;
var boundingSphere = scene.boundingSphereVisible;
var center = boundingSphere.center, radius = boundingSphere.radius;
var autoAdjustControls = controls.props.autoAdjustMinMaxDistance;
if (autoAdjustControls.name === 'on') {
var minDistance = autoAdjustControls.params.minDistanceFactor * radius + autoAdjustControls.params.minDistancePadding;
var maxDistance = Math.max(autoAdjustControls.params.maxDistanceFactor * radius, autoAdjustControls.params.maxDistanceMin);
controls.setProps({ minDistance: minDistance, maxDistance: maxDistance });
}
if (radius > 0) {
var duration = nextCameraResetDuration === undefined ? p.cameraResetDurationMs : nextCameraResetDuration;
var focus_1 = camera.getFocus(center, radius);
var next = typeof nextCameraResetSnapshot === 'function' ? nextCameraResetSnapshot(scene, camera) : nextCameraResetSnapshot;
var snapshot = next ? __assign(__assign({}, focus_1), next) : focus_1;
camera.setState(__assign(__assign({}, snapshot), { radiusMax: scene.boundingSphere.radius }), duration);
}
nextCameraResetDuration = void 0;
nextCameraResetSnapshot = void 0;
cameraResetRequested = false;
}
var oldBoundingSphereVisible = Sphere3D();
var cameraSphere = Sphere3D();
function shouldResetCamera() {
if (camera.state.radiusMax === 0)
return true;
if (camera.transition.inTransition || nextCameraResetSnapshot)
return false;
var cameraSphereOverlapsNone = true;
Sphere3D.set(cameraSphere, camera.state.target, camera.state.radius);
// check if any renderable has moved outside of the old bounding sphere
// and if no renderable is overlapping with the camera sphere
for (var _i = 0, _a = scene.renderables; _i < _a.length; _i++) {
var r = _a[_i];
if (!r.state.visible)
continue;
var b = r.values.boundingSphere.ref.value;
if (!b.radius)
continue;
var cameraDist = Vec3.distance(cameraSphere.center, b.center);
if ((cameraDist > cameraSphere.radius || cameraDist > b.radius || b.radius > camera.state.radiusMax) && !Sphere3D.includes(oldBoundingSphereVisible, b))
return true;
if (Sphere3D.overlaps(cameraSphere, b))
cameraSphereOverlapsNone = false;
}
return cameraSphereOverlapsNone;
}
var sceneCommitTimeoutMs = 250;
function commitScene(isSynchronous) {
if (!scene.needsCommit)
return true;
// snapshot the current bounding sphere of visible objects
Sphere3D.copy(oldBoundingSphereVisible, scene.boundingSphereVisible);
if (!scene.commit(isSynchronous ? void 0 : sceneCommitTimeoutMs))
return false;
if (helper.debug.isEnabled)
helper.debug.update();
if (!p.camera.manualReset && (reprCount.value === 0 || shouldResetCamera())) {
cameraResetRequested = true;
}
if (oldBoundingSphereVisible.radius === 0)
nextCameraResetDuration = 0;
camera.setState({ radiusMax: scene.boundingSphere.radius }, 0);
reprCount.next(reprRenderObjects.size);
if (isDebugMode)
consoleStats();
return true;
}
function consoleStats() {
console.table(scene.renderables.map(function (r) { return ({
drawCount: r.values.drawCount.ref.value,
instanceCount: r.values.instanceCount.ref.value,
materialId: r.materialId,
renderItemId: r.id,
}); }));
console.log(webgl.stats);
var _a = webgl.resources.getByteCounts(), texture = _a.texture, attribute = _a.attribute, elements = _a.elements;
console.log({
texture: (texture / 1024 / 1024).toFixed(3) + " MiB",
attribute: (attribute / 1024 / 1024).toFixed(3) + " MiB",
elements: (elements / 1024 / 1024).toFixed(3) + " MiB",
});
}
function add(repr) {
registerAutoUpdate(repr);
var oldRO = reprRenderObjects.get(repr);
var newRO = new Set();
repr.renderObjects.forEach(function (o) { return newRO.add(o); });
if (oldRO) {
if (!SetUtils.areEqual(newRO, oldRO)) {
newRO.forEach(function (o) { if (!oldRO.has(o))
scene.add(o); });
oldRO.forEach(function (o) { if (!newRO.has(o))
scene.remove(o); });
}
}
else {
repr.renderObjects.forEach(function (o) { return scene.add(o); });
}
reprRenderObjects.set(repr, newRO);
scene.update(repr.renderObjects, false);
forceDrawAfterAllCommited = true;
if (isDebugMode)
consoleStats();
}
function remove(repr) {
unregisterAutoUpdate(repr);
var renderObjects = reprRenderObjects.get(repr);
if (renderObjects) {
renderObjects.forEach(function (o) { return scene.remove(o); });
reprRenderObjects.delete(repr);
forceDrawAfterAllCommited = true;
if (isDebugMode)
consoleStats();
}
}
function registerAutoUpdate(repr) {
if (reprUpdatedSubscriptions.has(repr))
return;
reprUpdatedSubscriptions.set(repr, repr.updated.subscribe(function (_) {
if (!repr.state.syncManually)
add(repr);
}));
}
function unregisterAutoUpdate(repr) {
var updatedSubscription = reprUpdatedSubscriptions.get(repr);
if (updatedSubscription) {
updatedSubscription.unsubscribe();
reprUpdatedSubscriptions.delete(repr);
}
}
function getProps() {
var radius = scene.boundingSphere.radius > 0
? 100 - Math.round((camera.transition.target.radius / scene.boundingSphere.radius) * 100)
: 0;
return {
camera: {
mode: camera.state.mode,
helper: __assign({}, helper.camera.props),
stereo: __assign({}, p.camera.stereo),
manualReset: !!p.camera.manualReset
},
cameraFog: camera.state.fog > 0
? { name: 'on', params: { intensity: camera.state.fog } }
: { name: 'off', params: {} },
cameraClipping: { far: camera.state.clipFar, radius: radius },
cameraResetDurationMs: p.cameraResetDurationMs,
transparentBackground: p.transparentBackground,
viewport: p.viewport,
postprocessing: __assign({}, p.postprocessing),
marking: __assign({}, p.marking),
multiSample: __assign({}, p.multiSample),
renderer: __assign({}, renderer.props),
trackball: __assign({}, controls.props),
interaction: __assign({}, interactionHelper.props),
debug: __assign({}, helper.debug.props),
handle: __assign({}, helper.handle.props),
};
}
var contextRestoredSub = contextRestored.subscribe(function () {
pickHelper.dirty = true;
draw(true);
// Unclear why, but in Chrome with wboit enabled the first `draw` only clears
// the drawingBuffer. Note that in Firefox the drawingBuffer is preserved after
// context loss so it is unclear if it behaves the same.
draw(true);
});
var resized = new BehaviorSubject(0);
function handleResize(draw) {
if (draw === void 0) { draw = true; }
passes.updateSize();
updateViewport();
syncViewport();
if (draw)
requestDraw(true);
resized.next(+new Date());
}
return {
webgl: webgl,
add: add,
remove: remove,
commit: commit,
update: function (repr, keepSphere) {
if (repr) {
if (!reprRenderObjects.has(repr))
return;
scene.update(repr.renderObjects, !!keepSphere);
}
else {
scene.update(void 0, !!keepSphere);
}
forceDrawAfterAllCommited = true;
},
clear: function () {
reprUpdatedSubscriptions.forEach(function (v) { return v.unsubscribe(); });
reprUpdatedSubscriptions.clear();
reprRenderObjects.clear();
scene.clear();
helper.debug.clear();
requestDraw(true);
reprCount.next(reprRenderObjects.size);
},
syncVisibility: function () {
if (camera.state.radiusMax === 0) {
cameraResetRequested = true;
nextCameraResetDuration = 0;
}
if (scene.syncVisibility()) {
if (helper.debug.isEnabled)
helper.debug.update();
}
requestDraw(true);
},
requestDraw: requestDraw,
tick: tick,
animate: animate,
resetTime: resetTime,
pause: pause,
resume: function () { drawPaused = false; },
identify: identify,
mark: mark,
getLoci: getLoci,
handleResize: handleResize,
requestResize: function () {
resizeRequested = true;
},
requestCameraReset: function (options) {
nextCameraResetDuration = options === null || options === void 0 ? void 0 : options.durationMs;
nextCameraResetSnapshot = options === null || options === void 0 ? void 0 : options.snapshot;
cameraResetRequested = true;
},
camera: camera,
boundingSphere: scene.boundingSphere,
boundingSphereVisible: scene.boundingSphereVisible,
get notifyDidDraw() { return notifyDidDraw; },
set notifyDidDraw(v) { notifyDidDraw = v; },
didDraw: didDraw,
commited: commited,
reprCount: reprCount,
resized: resized,
setProps: function (properties, doNotRequestDraw) {
var _a, _b, _c;
if (doNotRequestDraw === void 0) { doNotRequestDraw = false; }
var props = typeof properties === 'function'
? produce(getProps(), properties)
: properties;
var cameraState = Object.create(null);
if (props.camera && props.camera.mode !== undefined && props.camera.mode !== camera.state.mode) {
cameraState.mode = props.camera.mode;
}
if (props.cameraFog !== undefined && props.cameraFog.params) {
var newFog = props.cameraFog.name === 'on' ? props.cameraFog.params.intensity : 0;
if (newFog !== camera.state.fog)
cameraState.fog = newFog;
}
if (props.cameraClipping !== undefined) {
if (props.cameraClipping.far !== undefined && props.cameraClipping.far !== camera.state.clipFar) {
cameraState.clipFar = props.cameraClipping.far;
}
if (props.cameraClipping.radius !== undefined) {
var radius = (scene.boundingSphere.radius / 100) * (100 - props.cameraClipping.radius);
if (radius > 0 && radius !== cameraState.radius) {
// if radius = 0, NaNs happen
cameraState.radius = Math.max(radius, 0.01);
}
}
}
if (Object.keys(cameraState).length > 0)
camera.setState(cameraState);
if ((_a = props.camera) === null || _a === void 0 ? void 0 : _a.helper)
helper.camera.setProps(props.camera.helper);
if (((_b = props.camera) === null || _b === void 0 ? void 0 : _b.manualReset) !== undefined)
p.camera.manualReset = props.camera.manualReset;
if (((_c = props.camera) === null || _c === void 0 ? void 0 : _c.stereo) !== undefined)
Object.assign(p.camera.stereo, props.camera.stereo);
if (props.cameraResetDurationMs !== undefined)
p.cameraResetDurationMs = props.cameraResetDurationMs;
if (props.transparentBackground !== undefined)
p.transparentBackground = props.transparentBackground;
if (props.viewport !== undefined) {
var doNotUpdate = p.viewport === props.viewport ||
(p.viewport.name === props.viewport.name && shallowEqual(p.viewport.params, props.viewport.params));
if (!doNotUpdate) {
p.viewport = props.viewport;
updateViewport();
syncViewport();
}
}
if (props.postprocessing)
Object.assign(p.postprocessing, props.postprocessing);
if (props.marking)
Object.assign(p.marking, props.marking);
if (props.multiSample)
Object.assign(p.multiSample, props.multiSample);
if (props.renderer)
renderer.setProps(props.renderer);
if (props.trackball)
controls.setProps(props.trackball);
if (props.interaction)
interactionHelper.setProps(props.interaction);
if (props.debug)
helper.debug.setProps(props.debug);
if (props.handle)
helper.handle.setProps(props.handle);
if (cameraState.mode === 'orthographic') {
p.camera.stereo.name = 'off';
}
if (!doNotRequestDraw) {
requestDraw(true);
}
},
getImagePass: function (props) {
if (props === void 0) { props = {}; }
return new ImagePass(webgl, renderer, scene, camera, helper, passes.draw.wboitEnabled, props);
},
getRenderObjects: function () {
var renderObjects = [];
scene.forEach(function (_, ro) { return renderObjects.push(ro); });
return renderObjects;
},
get props() {
return getProps();
},
get input() {
return input;
},
get stats() {
return renderer.stats;
},
get interaction() {
return interactionHelper.events;
},
dispose: function () {
contextRestoredSub.unsubscribe();
scene.clear();
helper.debug.clear();
controls.dispose();
renderer.dispose();
interactionHelper.dispose();
}
};
function updateViewport() {
var oldX = x, oldY = y, oldWidth = width, oldHeight = height;
if (p.viewport.name === 'canvas') {
x = 0;
y = 0;
width = gl.drawingBufferWidth;
height = gl.drawingBufferHeight;
}
else if (p.viewport.name === 'static-frame') {
x = p.viewport.params.x * webgl.pixelRatio;
height = p.viewport.params.height * webgl.pixelRatio;
y = gl.drawingBufferHeight - height - p.viewport.params.y * webgl.pixelRatio;
width = p.viewport.params.width * webgl.pixelRatio;
}
else if (p.viewport.name === 'relative-frame') {
x = Math.round(p.viewport.params.x * gl.drawingBufferWidth);
height = Math.round(p.viewport.params.height * gl.drawingBufferHeight);
y = Math.round(gl.drawingBufferHeight - height - p.viewport.params.y * gl.drawingBufferHeight);
width = Math.round(p.viewport.params.width * gl.drawingBufferWidth);
}
if (oldX !== x || oldY !== y || oldWidth !== width || oldHeight !== height) {
forceNextRender = true;
}
}
function syncViewport() {
pickHelper.setViewport(x, y, width, height);
renderer.setViewport(x, y, width, height);
Viewport.set(camera.viewport, x, y, width, height);
Viewport.set(controls.viewport, x, y, width, height);
}
}
Canvas3D.create = create;
})(Canvas3D || (Canvas3D = {}));
//# sourceMappingURL=canvas3d.js.map