UNPKG

@openhps/core

Version:

Open Hybrid Positioning System - Core component

243 lines (226 loc) 6.53 kB
import { NodeUpdateType } from './constants.js'; /** * Management class for updating nodes. The module tracks metrics like * the elapsed time, delta time, the render and frame ID to correctly * call the node update methods {@link Node#updateBefore}, {@link Node#update} * and {@link Node#updateAfter} depending on the node's configuration. */ class NodeFrame { /** * Constructs a new node fame. */ constructor() { /** * The elapsed time in seconds. * * @type {number} * @default 0 */ this.time = 0; /** * The delta time in seconds. * * @type {number} * @default 0 */ this.deltaTime = 0; /** * The frame ID. * * @type {number} * @default 0 */ this.frameId = 0; /** * The render ID. * * @type {number} * @default 0 */ this.renderId = 0; /** * Used to control the {@link Node#update} call. * * @type {WeakMap<Node, Object>} */ this.updateMap = new WeakMap(); /** * Used to control the {@link Node#updateBefore} call. * * @type {WeakMap<Node, Object>} */ this.updateBeforeMap = new WeakMap(); /** * Used to control the {@link Node#updateAfter} call. * * @type {WeakMap<Node, Object>} */ this.updateAfterMap = new WeakMap(); /** * A reference to the current renderer. * * @type {?Renderer} * @default null */ this.renderer = null; /** * A reference to the current material. * * @type {?Material} * @default null */ this.material = null; /** * A reference to the current camera. * * @type {?Camera} * @default null */ this.camera = null; /** * A reference to the current 3D object. * * @type {?Object3D} * @default null */ this.object = null; /** * A reference to the current scene. * * @type {?Scene} * @default null */ this.scene = null; } /** * Returns a dictionary for a given node and update map which * is used to correctly call node update methods per frame or render. * * @private * @param {WeakMap<Node, Object>} referenceMap - The reference weak map. * @param {Node} nodeRef - The reference to the current node. * @return {Object<string,WeakMap>} The dictionary. */ _getMaps(referenceMap, nodeRef) { let maps = referenceMap.get(nodeRef); if (maps === undefined) { maps = { renderMap: new WeakMap(), frameMap: new WeakMap() }; referenceMap.set(nodeRef, maps); } return maps; } /** * This method executes the {@link Node#updateBefore} for the given node. * It makes sure {@link Node#updateBeforeType} is honored meaning the update * is only executed once per frame, render or object depending on the update * type. * * @param {Node} node - The node that should be updated. */ updateBeforeNode(node) { const updateType = node.getUpdateBeforeType(); const reference = node.updateReference(this); if (updateType === NodeUpdateType.FRAME) { const { frameMap } = this._getMaps(this.updateBeforeMap, reference); if (frameMap.get(reference) !== this.frameId) { if (node.updateBefore(this) !== false) { frameMap.set(reference, this.frameId); } } } else if (updateType === NodeUpdateType.RENDER) { const { renderMap } = this._getMaps(this.updateBeforeMap, reference); if (renderMap.get(reference) !== this.renderId) { if (node.updateBefore(this) !== false) { renderMap.set(reference, this.renderId); } } } else if (updateType === NodeUpdateType.OBJECT) { node.updateBefore(this); } } /** * This method executes the {@link Node#updateAfter} for the given node. * It makes sure {@link Node#updateAfterType} is honored meaning the update * is only executed once per frame, render or object depending on the update * type. * * @param {Node} node - The node that should be updated. */ updateAfterNode(node) { const updateType = node.getUpdateAfterType(); const reference = node.updateReference(this); if (updateType === NodeUpdateType.FRAME) { const { frameMap } = this._getMaps(this.updateAfterMap, reference); if (frameMap.get(reference) !== this.frameId) { if (node.updateAfter(this) !== false) { frameMap.set(reference, this.frameId); } } } else if (updateType === NodeUpdateType.RENDER) { const { renderMap } = this._getMaps(this.updateAfterMap, reference); if (renderMap.get(reference) !== this.renderId) { if (node.updateAfter(this) !== false) { renderMap.set(reference, this.renderId); } } } else if (updateType === NodeUpdateType.OBJECT) { node.updateAfter(this); } } /** * This method executes the {@link Node#update} for the given node. * It makes sure {@link Node#updateType} is honored meaning the update * is only executed once per frame, render or object depending on the update * type. * * @param {Node} node - The node that should be updated. */ updateNode(node) { const updateType = node.getUpdateType(); const reference = node.updateReference(this); if (updateType === NodeUpdateType.FRAME) { const { frameMap } = this._getMaps(this.updateMap, reference); if (frameMap.get(reference) !== this.frameId) { if (node.update(this) !== false) { frameMap.set(reference, this.frameId); } } } else if (updateType === NodeUpdateType.RENDER) { const { renderMap } = this._getMaps(this.updateMap, reference); if (renderMap.get(reference) !== this.renderId) { if (node.update(this) !== false) { renderMap.set(reference, this.renderId); } } } else if (updateType === NodeUpdateType.OBJECT) { node.update(this); } } /** * Updates the internal state of the node frame. This method is * called by the renderer in its internal animation loop. */ update() { this.frameId++; if (this.lastTime === undefined) this.lastTime = performance.now(); this.deltaTime = (performance.now() - this.lastTime) / 1000; this.lastTime = performance.now(); this.time += this.deltaTime; } } export default NodeFrame;