three
Version:
JavaScript 3D library
549 lines (384 loc) • 12.8 kB
JavaScript
import { Vector3 } from '../math/Vector3.js';
import { BufferAttribute } from './BufferAttribute.js';
import { denormalize, normalize } from '../math/MathUtils.js';
const _vector = /*@__PURE__*/ new Vector3();
/**
* An alternative version of a buffer attribute with interleaved data. Interleaved
* attributes share a common interleaved data storage ({@link InterleavedBuffer}) and refer with
* different offsets into the buffer.
*/
class InterleavedBufferAttribute {
/**
* Constructs a new interleaved buffer attribute.
*
* @param {InterleavedBuffer} interleavedBuffer - The buffer holding the interleaved data.
* @param {number} itemSize - The item size.
* @param {number} offset - The attribute offset into the buffer.
* @param {boolean} [normalized=false] - Whether the data are normalized or not.
*/
constructor( interleavedBuffer, itemSize, offset, normalized = false ) {
/**
* This flag can be used for type testing.
*
* @type {boolean}
* @readonly
* @default true
*/
this.isInterleavedBufferAttribute = true;
/**
* The name of the buffer attribute.
*
* @type {string}
*/
this.name = '';
/**
* The buffer holding the interleaved data.
*
* @type {InterleavedBuffer}
*/
this.data = interleavedBuffer;
/**
* The item size, see {@link BufferAttribute#itemSize}.
*
* @type {number}
*/
this.itemSize = itemSize;
/**
* The attribute offset into the buffer.
*
* @type {number}
*/
this.offset = offset;
/**
* Whether the data are normalized or not, see {@link BufferAttribute#normalized}
*
* @type {InterleavedBuffer}
*/
this.normalized = normalized;
}
/**
* The item count of this buffer attribute.
*
* @type {number}
* @readonly
*/
get count() {
return this.data.count;
}
/**
* The array holding the interleaved buffer attribute data.
*
* @type {TypedArray}
*/
get array() {
return this.data.array;
}
/**
* 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 ) {
this.data.needsUpdate = value;
}
/**
* Applies the given 4x4 matrix to the given attribute. Only works with
* item size `3`.
*
* @param {Matrix4} m - The matrix to apply.
* @return {InterleavedBufferAttribute} A reference to this instance.
*/
applyMatrix4( m ) {
for ( let i = 0, l = this.data.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 {InterleavedBufferAttribute} 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 {InterleavedBufferAttribute} 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;
}
/**
* 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.data.stride + this.offset + 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 {InterleavedBufferAttribute} A reference to this instance.
*/
setComponent( index, component, value ) {
if ( this.normalized ) value = normalize( value, this.array );
this.data.array[ index * this.data.stride + this.offset + component ] = value;
return this;
}
/**
* 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 {InterleavedBufferAttribute} A reference to this instance.
*/
setX( index, x ) {
if ( this.normalized ) x = normalize( x, this.array );
this.data.array[ index * this.data.stride + this.offset ] = x;
return this;
}
/**
* 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 {InterleavedBufferAttribute} A reference to this instance.
*/
setY( index, y ) {
if ( this.normalized ) y = normalize( y, this.array );
this.data.array[ index * this.data.stride + this.offset + 1 ] = y;
return this;
}
/**
* 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 {InterleavedBufferAttribute} A reference to this instance.
*/
setZ( index, z ) {
if ( this.normalized ) z = normalize( z, this.array );
this.data.array[ index * this.data.stride + this.offset + 2 ] = z;
return this;
}
/**
* 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 {InterleavedBufferAttribute} A reference to this instance.
*/
setW( index, w ) {
if ( this.normalized ) w = normalize( w, this.array );
this.data.array[ index * this.data.stride + this.offset + 3 ] = w;
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.data.array[ index * this.data.stride + this.offset ];
if ( this.normalized ) x = denormalize( x, this.array );
return x;
}
/**
* 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.data.array[ index * this.data.stride + this.offset + 1 ];
if ( this.normalized ) y = denormalize( y, this.array );
return y;
}
/**
* 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.data.array[ index * this.data.stride + this.offset + 2 ];
if ( this.normalized ) z = denormalize( z, this.array );
return z;
}
/**
* 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.data.array[ index * this.data.stride + this.offset + 3 ];
if ( this.normalized ) w = denormalize( w, this.array );
return w;
}
/**
* 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 {InterleavedBufferAttribute} A reference to this instance.
*/
setXY( index, x, y ) {
index = index * this.data.stride + this.offset;
if ( this.normalized ) {
x = normalize( x, this.array );
y = normalize( y, this.array );
}
this.data.array[ index + 0 ] = x;
this.data.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 {InterleavedBufferAttribute} A reference to this instance.
*/
setXYZ( index, x, y, z ) {
index = index * this.data.stride + this.offset;
if ( this.normalized ) {
x = normalize( x, this.array );
y = normalize( y, this.array );
z = normalize( z, this.array );
}
this.data.array[ index + 0 ] = x;
this.data.array[ index + 1 ] = y;
this.data.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 {InterleavedBufferAttribute} A reference to this instance.
*/
setXYZW( index, x, y, z, w ) {
index = index * this.data.stride + this.offset;
if ( this.normalized ) {
x = normalize( x, this.array );
y = normalize( y, this.array );
z = normalize( z, this.array );
w = normalize( w, this.array );
}
this.data.array[ index + 0 ] = x;
this.data.array[ index + 1 ] = y;
this.data.array[ index + 2 ] = z;
this.data.array[ index + 3 ] = w;
return this;
}
/**
* Returns a new buffer attribute with copied values from this instance.
*
* If no parameter is provided, cloning an interleaved buffer attribute will de-interleave buffer data.
*
* @param {Object} [data] - An object with interleaved buffers that allows to retain the interleaved property.
* @return {BufferAttribute|InterleavedBufferAttribute} A clone of this instance.
*/
clone( data ) {
if ( data === undefined ) {
console.log( 'THREE.InterleavedBufferAttribute.clone(): Cloning an interleaved buffer attribute will de-interleave buffer data.' );
const array = [];
for ( let i = 0; i < this.count; i ++ ) {
const index = i * this.data.stride + this.offset;
for ( let j = 0; j < this.itemSize; j ++ ) {
array.push( this.data.array[ index + j ] );
}
}
return new BufferAttribute( new this.array.constructor( array ), this.itemSize, this.normalized );
} else {
if ( data.interleavedBuffers === undefined ) {
data.interleavedBuffers = {};
}
if ( data.interleavedBuffers[ this.data.uuid ] === undefined ) {
data.interleavedBuffers[ this.data.uuid ] = this.data.clone( data );
}
return new InterleavedBufferAttribute( data.interleavedBuffers[ this.data.uuid ], this.itemSize, this.offset, this.normalized );
}
}
/**
* Serializes the buffer attribute into JSON.
*
* If no parameter is provided, cloning an interleaved buffer attribute will de-interleave buffer data.
*
* @param {Object} [data] - An optional value holding meta information about the serialization.
* @return {Object} A JSON object representing the serialized buffer attribute.
*/
toJSON( data ) {
if ( data === undefined ) {
console.log( 'THREE.InterleavedBufferAttribute.toJSON(): Serializing an interleaved buffer attribute will de-interleave buffer data.' );
const array = [];
for ( let i = 0; i < this.count; i ++ ) {
const index = i * this.data.stride + this.offset;
for ( let j = 0; j < this.itemSize; j ++ ) {
array.push( this.data.array[ index + j ] );
}
}
// de-interleave data and save it as an ordinary buffer attribute for now
return {
itemSize: this.itemSize,
type: this.array.constructor.name,
array: array,
normalized: this.normalized
};
} else {
// save as true interleaved attribute
if ( data.interleavedBuffers === undefined ) {
data.interleavedBuffers = {};
}
if ( data.interleavedBuffers[ this.data.uuid ] === undefined ) {
data.interleavedBuffers[ this.data.uuid ] = this.data.toJSON( data );
}
return {
isInterleavedBufferAttribute: true,
itemSize: this.itemSize,
data: this.data.uuid,
offset: this.offset,
normalized: this.normalized
};
}
}
}
export { InterleavedBufferAttribute };