UNPKG

@openhps/core

Version:

Open Hybrid Positioning System - Core component

800 lines (748 loc) 24.9 kB
import { Vector3 } from '../math/Vector3.js'; import { Vector2 } from '../math/Vector2.js'; import { denormalize, normalize } from '../math/MathUtils.js'; import { StaticDrawUsage, FloatType } from '../constants.js'; import { fromHalfFloat, toHalfFloat } from '../extras/DataUtils.js'; const _vector = /*@__PURE__*/new Vector3(); const _vector2 = /*@__PURE__*/new Vector2(); let _id = 0; /** * This class stores data for an attribute (such as vertex positions, face * indices, normals, colors, UVs, and any custom attributes ) associated with * a geometry, which allows for more efficient passing of data to the GPU. * * When working with vector-like data, the `fromBufferAttribute( attribute, index )` * helper methods on vector and color class might be helpful. E.g. {@link Vector3#fromBufferAttribute}. */ class BufferAttribute { /** * Constructs a new buffer attribute. * * @param {TypedArray} array - The array holding the attribute data. * @param {number} itemSize - The item size. * @param {boolean} [normalized=false] - Whether the data are normalized or not. */ constructor(array, itemSize, normalized = false) { if (Array.isArray(array)) { throw new TypeError('THREE.BufferAttribute: array should be a Typed Array.'); } /** * This flag can be used for type testing. * * @type {boolean} * @readonly * @default true */ this.isBufferAttribute = true; /** * The ID of the buffer attribute. * * @name BufferAttribute#id * @type {number} * @readonly */ Object.defineProperty(this, 'id', { value: _id++ }); /** * The name of the buffer attribute. * * @type {string} */ this.name = ''; /** * The array holding the attribute data. It should have `itemSize * numVertices` * elements, where `numVertices` is the number of vertices in the associated geometry. * * @type {TypedArray} */ this.array = array; /** * The number of values of the array that should be associated with a particular vertex. * For instance, if this attribute is storing a 3-component vector (such as a position, * normal, or color), then the value should be `3`. * * @type {number} */ this.itemSize = itemSize; /** * Represents the number of items this buffer attribute stores. It is internally computed * by dividing the `array` length by the `itemSize`. * * @type {number} * @readonly */ this.count = array !== undefined ? array.length / itemSize : 0; /** * Applies to integer data only. Indicates how the underlying data in the buffer maps to * the values in the GLSL code. For instance, if `array` is an instance of `UInt16Array`, * and `normalized` is `true`, the values `0 -+65535` in the array data will be mapped to * `0.0f - +1.0f` in the GLSL attribute. If `normalized` is `false`, the values will be converted * to floats unmodified, i.e. `65535` becomes `65535.0f`. * * @type {boolean} */ this.normalized = normalized; /** * Defines the intended usage pattern of the data store for optimization purposes. * * Note: After the initial use of a buffer, its usage cannot be changed. Instead, * instantiate a new one and set the desired usage before the next render. * * @type {(StaticDrawUsage|DynamicDrawUsage|StreamDrawUsage|StaticReadUsage|DynamicReadUsage|StreamReadUsage|StaticCopyUsage|DynamicCopyUsage|StreamCopyUsage)} * @default StaticDrawUsage */ this.usage = StaticDrawUsage; /** * This can be used to only update some components of stored vectors (for example, just the * component related to color). Use the `addUpdateRange()` function to add ranges to this array. * * @type {Array<Object>} */ this.updateRanges = []; /** * Configures the bound GPU type for use in shaders. * * Note: this only has an effect for integer arrays and is not configurable for float arrays. * For lower precision float types, use `Float16BufferAttribute`. * * @type {(FloatType|IntType)} * @default FloatType */ this.gpuType = FloatType; /** * A version number, incremented every time the `needsUpdate` is set to `true`. * * @type {number} */ this.version = 0; } /** * A callback function that is executed after the renderer has transferred the attribute * array data to the GPU. */ onUploadCallback() {} /** * Flag to indicate that this attribute has changed and should be re-sent to * the GPU. Set this to `true` when you modify the value of the array. * * @type {number} * @default false * @param {boolean} value */ set needsUpdate(value) { if (value === true) this.version++; } /** * Sets the usage of this buffer attribute. * * @param {(StaticDrawUsage|DynamicDrawUsage|StreamDrawUsage|StaticReadUsage|DynamicReadUsage|StreamReadUsage|StaticCopyUsage|DynamicCopyUsage|StreamCopyUsage)} value - The usage to set. * @return {BufferAttribute} A reference to this buffer attribute. */ setUsage(value) { this.usage = value; return this; } /** * Adds a range of data in the data array to be updated on the GPU. * * @param {number} start - Position at which to start update. * @param {number} count - The number of components to update. */ addUpdateRange(start, count) { this.updateRanges.push({ start, count }); } /** * Clears the update ranges. */ clearUpdateRanges() { this.updateRanges.length = 0; } /** * Copies the values of the given buffer attribute to this instance. * * @param {BufferAttribute} source - The buffer attribute to copy. * @return {BufferAttribute} A reference to this instance. */ copy(source) { this.name = source.name; this.array = new source.array.constructor(source.array); this.itemSize = source.itemSize; this.count = source.count; this.normalized = source.normalized; this.usage = source.usage; this.gpuType = source.gpuType; return this; } /** * Copies a vector from the given buffer attribute to this one. The start * and destination position in the attribute buffers are represented by the * given indices. * * @param {number} index1 - The destination index into this buffer attribute. * @param {BufferAttribute} attribute - The buffer attribute to copy from. * @param {number} index2 - The source index into the given buffer attribute. * @return {BufferAttribute} A reference to this instance. */ copyAt(index1, attribute, index2) { index1 *= this.itemSize; index2 *= attribute.itemSize; for (let i = 0, l = this.itemSize; i < l; i++) { this.array[index1 + i] = attribute.array[index2 + i]; } return this; } /** * Copies the given array data into this buffer attribute. * * @param {(TypedArray|Array)} array - The array to copy. * @return {BufferAttribute} A reference to this instance. */ copyArray(array) { this.array.set(array); return this; } /** * Applies the given 3x3 matrix to the given attribute. Works with * item size `2` and `3`. * * @param {Matrix3} m - The matrix to apply. * @return {BufferAttribute} A reference to this instance. */ applyMatrix3(m) { if (this.itemSize === 2) { for (let i = 0, l = this.count; i < l; i++) { _vector2.fromBufferAttribute(this, i); _vector2.applyMatrix3(m); this.setXY(i, _vector2.x, _vector2.y); } } else if (this.itemSize === 3) { for (let i = 0, l = this.count; i < l; i++) { _vector.fromBufferAttribute(this, i); _vector.applyMatrix3(m); this.setXYZ(i, _vector.x, _vector.y, _vector.z); } } return this; } /** * Applies the given 4x4 matrix to the given attribute. Only works with * item size `3`. * * @param {Matrix4} m - The matrix to apply. * @return {BufferAttribute} A reference to this instance. */ applyMatrix4(m) { for (let i = 0, l = this.count; i < l; i++) { _vector.fromBufferAttribute(this, i); _vector.applyMatrix4(m); this.setXYZ(i, _vector.x, _vector.y, _vector.z); } return this; } /** * Applies the given 3x3 normal matrix to the given attribute. Only works with * item size `3`. * * @param {Matrix3} m - The normal matrix to apply. * @return {BufferAttribute} A reference to this instance. */ applyNormalMatrix(m) { for (let i = 0, l = this.count; i < l; i++) { _vector.fromBufferAttribute(this, i); _vector.applyNormalMatrix(m); this.setXYZ(i, _vector.x, _vector.y, _vector.z); } return this; } /** * Applies the given 4x4 matrix to the given attribute. Only works with * item size `3` and with direction vectors. * * @param {Matrix4} m - The matrix to apply. * @return {BufferAttribute} A reference to this instance. */ transformDirection(m) { for (let i = 0, l = this.count; i < l; i++) { _vector.fromBufferAttribute(this, i); _vector.transformDirection(m); this.setXYZ(i, _vector.x, _vector.y, _vector.z); } return this; } /** * Sets the given array data in the buffer attribute. * * @param {(TypedArray|Array)} value - The array data to set. * @param {number} [offset=0] - The offset in this buffer attribute's array. * @return {BufferAttribute} A reference to this instance. */ set(value, offset = 0) { // Matching BufferAttribute constructor, do not normalize the array. this.array.set(value, offset); return this; } /** * Returns the given component of the vector at the given index. * * @param {number} index - The index into the buffer attribute. * @param {number} component - The component index. * @return {number} The returned value. */ getComponent(index, component) { let value = this.array[index * this.itemSize + component]; if (this.normalized) value = denormalize(value, this.array); return value; } /** * Sets the given value to the given component of the vector at the given index. * * @param {number} index - The index into the buffer attribute. * @param {number} component - The component index. * @param {number} value - The value to set. * @return {BufferAttribute} A reference to this instance. */ setComponent(index, component, value) { if (this.normalized) value = normalize(value, this.array); this.array[index * this.itemSize + component] = value; return this; } /** * Returns the x component of the vector at the given index. * * @param {number} index - The index into the buffer attribute. * @return {number} The x component. */ getX(index) { let x = this.array[index * this.itemSize]; if (this.normalized) x = denormalize(x, this.array); return x; } /** * Sets the x component of the vector at the given index. * * @param {number} index - The index into the buffer attribute. * @param {number} x - The value to set. * @return {BufferAttribute} A reference to this instance. */ setX(index, x) { if (this.normalized) x = normalize(x, this.array); this.array[index * this.itemSize] = x; return this; } /** * Returns the y component of the vector at the given index. * * @param {number} index - The index into the buffer attribute. * @return {number} The y component. */ getY(index) { let y = this.array[index * this.itemSize + 1]; if (this.normalized) y = denormalize(y, this.array); return y; } /** * Sets the y component of the vector at the given index. * * @param {number} index - The index into the buffer attribute. * @param {number} y - The value to set. * @return {BufferAttribute} A reference to this instance. */ setY(index, y) { if (this.normalized) y = normalize(y, this.array); this.array[index * this.itemSize + 1] = y; return this; } /** * Returns the z component of the vector at the given index. * * @param {number} index - The index into the buffer attribute. * @return {number} The z component. */ getZ(index) { let z = this.array[index * this.itemSize + 2]; if (this.normalized) z = denormalize(z, this.array); return z; } /** * Sets the z component of the vector at the given index. * * @param {number} index - The index into the buffer attribute. * @param {number} z - The value to set. * @return {BufferAttribute} A reference to this instance. */ setZ(index, z) { if (this.normalized) z = normalize(z, this.array); this.array[index * this.itemSize + 2] = z; return this; } /** * Returns the w component of the vector at the given index. * * @param {number} index - The index into the buffer attribute. * @return {number} The w component. */ getW(index) { let w = this.array[index * this.itemSize + 3]; if (this.normalized) w = denormalize(w, this.array); return w; } /** * Sets the w component of the vector at the given index. * * @param {number} index - The index into the buffer attribute. * @param {number} w - The value to set. * @return {BufferAttribute} A reference to this instance. */ setW(index, w) { if (this.normalized) w = normalize(w, this.array); this.array[index * this.itemSize + 3] = w; return this; } /** * Sets the x and y component of the vector at the given index. * * @param {number} index - The index into the buffer attribute. * @param {number} x - The value for the x component to set. * @param {number} y - The value for the y component to set. * @return {BufferAttribute} A reference to this instance. */ setXY(index, x, y) { index *= this.itemSize; if (this.normalized) { x = normalize(x, this.array); y = normalize(y, this.array); } this.array[index + 0] = x; this.array[index + 1] = y; return this; } /** * Sets the x, y and z component of the vector at the given index. * * @param {number} index - The index into the buffer attribute. * @param {number} x - The value for the x component to set. * @param {number} y - The value for the y component to set. * @param {number} z - The value for the z component to set. * @return {BufferAttribute} A reference to this instance. */ setXYZ(index, x, y, z) { index *= this.itemSize; if (this.normalized) { x = normalize(x, this.array); y = normalize(y, this.array); z = normalize(z, this.array); } this.array[index + 0] = x; this.array[index + 1] = y; this.array[index + 2] = z; return this; } /** * Sets the x, y, z and w component of the vector at the given index. * * @param {number} index - The index into the buffer attribute. * @param {number} x - The value for the x component to set. * @param {number} y - The value for the y component to set. * @param {number} z - The value for the z component to set. * @param {number} w - The value for the w component to set. * @return {BufferAttribute} A reference to this instance. */ setXYZW(index, x, y, z, w) { index *= this.itemSize; if (this.normalized) { x = normalize(x, this.array); y = normalize(y, this.array); z = normalize(z, this.array); w = normalize(w, this.array); } this.array[index + 0] = x; this.array[index + 1] = y; this.array[index + 2] = z; this.array[index + 3] = w; return this; } /** * Sets the given callback function that is executed after the Renderer has transferred * the attribute array data to the GPU. Can be used to perform clean-up operations after * the upload when attribute data are not needed anymore on the CPU side. * * @param {Function} callback - The `onUpload()` callback. * @return {BufferAttribute} A reference to this instance. */ onUpload(callback) { this.onUploadCallback = callback; return this; } /** * Returns a new buffer attribute with copied values from this instance. * * @return {BufferAttribute} A clone of this instance. */ clone() { return new this.constructor(this.array, this.itemSize).copy(this); } /** * Serializes the buffer attribute into JSON. * * @return {Object} A JSON object representing the serialized buffer attribute. */ toJSON() { const data = { itemSize: this.itemSize, type: this.array.constructor.name, array: Array.from(this.array), normalized: this.normalized }; if (this.name !== '') data.name = this.name; if (this.usage !== StaticDrawUsage) data.usage = this.usage; return data; } } /** * Convenient class that can be used when creating a `Int8` buffer attribute with * a plain `Array` instance. * * @augments BufferAttribute */ class Int8BufferAttribute extends BufferAttribute { /** * Constructs a new buffer attribute. * * @param {(Array<number>|Int8Array)} array - The array holding the attribute data. * @param {number} itemSize - The item size. * @param {boolean} [normalized=false] - Whether the data are normalized or not. */ constructor(array, itemSize, normalized) { super(new Int8Array(array), itemSize, normalized); } } /** * Convenient class that can be used when creating a `UInt8` buffer attribute with * a plain `Array` instance. * * @augments BufferAttribute */ class Uint8BufferAttribute extends BufferAttribute { /** * Constructs a new buffer attribute. * * @param {(Array<number>|Uint8Array)} array - The array holding the attribute data. * @param {number} itemSize - The item size. * @param {boolean} [normalized=false] - Whether the data are normalized or not. */ constructor(array, itemSize, normalized) { super(new Uint8Array(array), itemSize, normalized); } } /** * Convenient class that can be used when creating a `UInt8Clamped` buffer attribute with * a plain `Array` instance. * * @augments BufferAttribute */ class Uint8ClampedBufferAttribute extends BufferAttribute { /** * Constructs a new buffer attribute. * * @param {(Array<number>|Uint8ClampedArray)} array - The array holding the attribute data. * @param {number} itemSize - The item size. * @param {boolean} [normalized=false] - Whether the data are normalized or not. */ constructor(array, itemSize, normalized) { super(new Uint8ClampedArray(array), itemSize, normalized); } } /** * Convenient class that can be used when creating a `Int16` buffer attribute with * a plain `Array` instance. * * @augments BufferAttribute */ class Int16BufferAttribute extends BufferAttribute { /** * Constructs a new buffer attribute. * * @param {(Array<number>|Int16Array)} array - The array holding the attribute data. * @param {number} itemSize - The item size. * @param {boolean} [normalized=false] - Whether the data are normalized or not. */ constructor(array, itemSize, normalized) { super(new Int16Array(array), itemSize, normalized); } } /** * Convenient class that can be used when creating a `UInt16` buffer attribute with * a plain `Array` instance. * * @augments BufferAttribute */ class Uint16BufferAttribute extends BufferAttribute { /** * Constructs a new buffer attribute. * * @param {(Array<number>|Uint16Array)} array - The array holding the attribute data. * @param {number} itemSize - The item size. * @param {boolean} [normalized=false] - Whether the data are normalized or not. */ constructor(array, itemSize, normalized) { super(new Uint16Array(array), itemSize, normalized); } } /** * Convenient class that can be used when creating a `Int32` buffer attribute with * a plain `Array` instance. * * @augments BufferAttribute */ class Int32BufferAttribute extends BufferAttribute { /** * Constructs a new buffer attribute. * * @param {(Array<number>|Int32Array)} array - The array holding the attribute data. * @param {number} itemSize - The item size. * @param {boolean} [normalized=false] - Whether the data are normalized or not. */ constructor(array, itemSize, normalized) { super(new Int32Array(array), itemSize, normalized); } } /** * Convenient class that can be used when creating a `UInt32` buffer attribute with * a plain `Array` instance. * * @augments BufferAttribute */ class Uint32BufferAttribute extends BufferAttribute { /** * Constructs a new buffer attribute. * * @param {(Array<number>|Uint32Array)} array - The array holding the attribute data. * @param {number} itemSize - The item size. * @param {boolean} [normalized=false] - Whether the data are normalized or not. */ constructor(array, itemSize, normalized) { super(new Uint32Array(array), itemSize, normalized); } } /** * Convenient class that can be used when creating a `Float16` buffer attribute with * a plain `Array` instance. * * This class automatically converts to to and from FP16 since `Float16Array` is not * natively supported in JavaScript. * * @augments BufferAttribute */ class Float16BufferAttribute extends BufferAttribute { /** * Constructs a new buffer attribute. * * @param {(Array<number>|Uint16Array)} array - The array holding the attribute data. * @param {number} itemSize - The item size. * @param {boolean} [normalized=false] - Whether the data are normalized or not. */ constructor(array, itemSize, normalized) { super(new Uint16Array(array), itemSize, normalized); this.isFloat16BufferAttribute = true; } getX(index) { let x = fromHalfFloat(this.array[index * this.itemSize]); if (this.normalized) x = denormalize(x, this.array); return x; } setX(index, x) { if (this.normalized) x = normalize(x, this.array); this.array[index * this.itemSize] = toHalfFloat(x); return this; } getY(index) { let y = fromHalfFloat(this.array[index * this.itemSize + 1]); if (this.normalized) y = denormalize(y, this.array); return y; } setY(index, y) { if (this.normalized) y = normalize(y, this.array); this.array[index * this.itemSize + 1] = toHalfFloat(y); return this; } getZ(index) { let z = fromHalfFloat(this.array[index * this.itemSize + 2]); if (this.normalized) z = denormalize(z, this.array); return z; } setZ(index, z) { if (this.normalized) z = normalize(z, this.array); this.array[index * this.itemSize + 2] = toHalfFloat(z); return this; } getW(index) { let w = fromHalfFloat(this.array[index * this.itemSize + 3]); if (this.normalized) w = denormalize(w, this.array); return w; } setW(index, w) { if (this.normalized) w = normalize(w, this.array); this.array[index * this.itemSize + 3] = toHalfFloat(w); return this; } setXY(index, x, y) { index *= this.itemSize; if (this.normalized) { x = normalize(x, this.array); y = normalize(y, this.array); } this.array[index + 0] = toHalfFloat(x); this.array[index + 1] = toHalfFloat(y); return this; } setXYZ(index, x, y, z) { index *= this.itemSize; if (this.normalized) { x = normalize(x, this.array); y = normalize(y, this.array); z = normalize(z, this.array); } this.array[index + 0] = toHalfFloat(x); this.array[index + 1] = toHalfFloat(y); this.array[index + 2] = toHalfFloat(z); return this; } setXYZW(index, x, y, z, w) { index *= this.itemSize; if (this.normalized) { x = normalize(x, this.array); y = normalize(y, this.array); z = normalize(z, this.array); w = normalize(w, this.array); } this.array[index + 0] = toHalfFloat(x); this.array[index + 1] = toHalfFloat(y); this.array[index + 2] = toHalfFloat(z); this.array[index + 3] = toHalfFloat(w); return this; } } /** * Convenient class that can be used when creating a `Float32` buffer attribute with * a plain `Array` instance. * * @augments BufferAttribute */ class Float32BufferAttribute extends BufferAttribute { /** * Constructs a new buffer attribute. * * @param {(Array<number>|Float32Array)} array - The array holding the attribute data. * @param {number} itemSize - The item size. * @param {boolean} [normalized=false] - Whether the data are normalized or not. */ constructor(array, itemSize, normalized) { super(new Float32Array(array), itemSize, normalized); } } // export { Float32BufferAttribute, Float16BufferAttribute, Uint32BufferAttribute, Int32BufferAttribute, Uint16BufferAttribute, Int16BufferAttribute, Uint8ClampedBufferAttribute, Uint8BufferAttribute, Int8BufferAttribute, BufferAttribute };