@openhps/core
Version:
Open Hybrid Positioning System - Core component
244 lines (225 loc) • 7.5 kB
JavaScript
import DataMap from './DataMap.js';
import { AttributeType } from './Constants.js';
import { arrayNeedsUint32 } from '../../utils.js';
import { Uint16BufferAttribute, Uint32BufferAttribute } from '../../core/BufferAttribute.js';
/**
* Returns the wireframe version for the given geometry.
*
* @private
* @function
* @param {BufferGeometry} geometry - The geometry.
* @return {number} The version.
*/
function getWireframeVersion(geometry) {
return geometry.index !== null ? geometry.index.version : geometry.attributes.position.version;
}
/**
* Returns a wireframe index attribute for the given geometry.
*
* @private
* @function
* @param {BufferGeometry} geometry - The geometry.
* @return {BufferAttribute} The wireframe index attribute.
*/
function getWireframeIndex(geometry) {
const indices = [];
const geometryIndex = geometry.index;
const geometryPosition = geometry.attributes.position;
if (geometryIndex !== null) {
const array = geometryIndex.array;
for (let i = 0, l = array.length; i < l; i += 3) {
const a = array[i + 0];
const b = array[i + 1];
const c = array[i + 2];
indices.push(a, b, b, c, c, a);
}
} else {
const array = geometryPosition.array;
for (let i = 0, l = array.length / 3 - 1; i < l; i += 3) {
const a = i + 0;
const b = i + 1;
const c = i + 2;
indices.push(a, b, b, c, c, a);
}
}
const attribute = new (arrayNeedsUint32(indices) ? Uint32BufferAttribute : Uint16BufferAttribute)(indices, 1);
attribute.version = getWireframeVersion(geometry);
return attribute;
}
/**
* This renderer module manages geometries.
*
* @private
* @augments DataMap
*/
class Geometries extends DataMap {
/**
* Constructs a new geometry management component.
*
* @param {Attributes} attributes - Renderer component for managing attributes.
* @param {Info} info - Renderer component for managing metrics and monitoring data.
*/
constructor(attributes, info) {
super();
/**
* Renderer component for managing attributes.
*
* @type {Attributes}
*/
this.attributes = attributes;
/**
* Renderer component for managing metrics and monitoring data.
*
* @type {Info}
*/
this.info = info;
/**
* Weak Map for managing attributes for wireframe rendering.
*
* @type {WeakMap<BufferGeometry,BufferAttribute>}
*/
this.wireframes = new WeakMap();
/**
* This Weak Map is used to make sure buffer attributes are
* updated only once per render call.
*
* @type {WeakMap<BufferAttribute,number>}
*/
this.attributeCall = new WeakMap();
}
/**
* Returns `true` if the given render object has an initialized geometry.
*
* @param {RenderObject} renderObject - The render object.
* @return {boolean} Whether if the given render object has an initialized geometry or not.
*/
has(renderObject) {
const geometry = renderObject.geometry;
return super.has(geometry) && this.get(geometry).initialized === true;
}
/**
* Prepares the geometry of the given render object for rendering.
*
* @param {RenderObject} renderObject - The render object.
*/
updateForRender(renderObject) {
if (this.has(renderObject) === false) this.initGeometry(renderObject);
this.updateAttributes(renderObject);
}
/**
* Initializes the geometry of the given render object.
*
* @param {RenderObject} renderObject - The render object.
*/
initGeometry(renderObject) {
const geometry = renderObject.geometry;
const geometryData = this.get(geometry);
geometryData.initialized = true;
this.info.memory.geometries++;
const onDispose = () => {
this.info.memory.geometries--;
const index = geometry.index;
const geometryAttributes = renderObject.getAttributes();
if (index !== null) {
this.attributes.delete(index);
}
for (const geometryAttribute of geometryAttributes) {
this.attributes.delete(geometryAttribute);
}
const wireframeAttribute = this.wireframes.get(geometry);
if (wireframeAttribute !== undefined) {
this.attributes.delete(wireframeAttribute);
}
geometry.removeEventListener('dispose', onDispose);
};
geometry.addEventListener('dispose', onDispose);
}
/**
* Updates the geometry attributes of the given render object.
*
* @param {RenderObject} renderObject - The render object.
*/
updateAttributes(renderObject) {
// attributes
const attributes = renderObject.getAttributes();
for (const attribute of attributes) {
if (attribute.isStorageBufferAttribute || attribute.isStorageInstancedBufferAttribute) {
this.updateAttribute(attribute, AttributeType.STORAGE);
} else {
this.updateAttribute(attribute, AttributeType.VERTEX);
}
}
// indexes
const index = this.getIndex(renderObject);
if (index !== null) {
this.updateAttribute(index, AttributeType.INDEX);
}
// indirect
const indirect = renderObject.geometry.indirect;
if (indirect !== null) {
this.updateAttribute(indirect, AttributeType.INDIRECT);
}
}
/**
* Updates the given attribute.
*
* @param {BufferAttribute} attribute - The attribute to update.
* @param {number} type - The attribute type.
*/
updateAttribute(attribute, type) {
const callId = this.info.render.calls;
if (!attribute.isInterleavedBufferAttribute) {
if (this.attributeCall.get(attribute) !== callId) {
this.attributes.update(attribute, type);
this.attributeCall.set(attribute, callId);
}
} else {
if (this.attributeCall.get(attribute) === undefined) {
this.attributes.update(attribute, type);
this.attributeCall.set(attribute, callId);
} else if (this.attributeCall.get(attribute.data) !== callId) {
this.attributes.update(attribute, type);
this.attributeCall.set(attribute.data, callId);
this.attributeCall.set(attribute, callId);
}
}
}
/**
* Returns the indirect buffer attribute of the given render object.
*
* @param {RenderObject} renderObject - The render object.
* @return {?BufferAttribute} The indirect attribute. `null` if no indirect drawing is used.
*/
getIndirect(renderObject) {
return renderObject.geometry.indirect;
}
/**
* Returns the index of the given render object's geometry. This is implemented
* in a method to return a wireframe index if necessary.
*
* @param {RenderObject} renderObject - The render object.
* @return {?BufferAttribute} The index. Returns `null` for non-indexed geometries.
*/
getIndex(renderObject) {
const {
geometry,
material
} = renderObject;
let index = geometry.index;
if (material.wireframe === true) {
const wireframes = this.wireframes;
let wireframeAttribute = wireframes.get(geometry);
if (wireframeAttribute === undefined) {
wireframeAttribute = getWireframeIndex(geometry);
wireframes.set(geometry, wireframeAttribute);
} else if (wireframeAttribute.version !== getWireframeVersion(geometry)) {
this.attributes.delete(wireframeAttribute);
wireframeAttribute = getWireframeIndex(geometry);
wireframes.set(geometry, wireframeAttribute);
}
index = wireframeAttribute;
}
return index;
}
}
export default Geometries;