Buckets:
| import { Quaternion } from '../math/Quaternion.js'; | |
| class PropertyMixer { | |
| constructor( binding, typeName, valueSize ) { | |
| this.binding = binding; | |
| this.valueSize = valueSize; | |
| let mixFunction, | |
| mixFunctionAdditive, | |
| setIdentity; | |
| // buffer layout: [ incoming | accu0 | accu1 | orig | addAccu | (optional work) ] | |
| // | |
| // interpolators can use .buffer as their .result | |
| // the data then goes to 'incoming' | |
| // | |
| // 'accu0' and 'accu1' are used frame-interleaved for | |
| // the cumulative result and are compared to detect | |
| // changes | |
| // | |
| // 'orig' stores the original state of the property | |
| // | |
| // 'add' is used for additive cumulative results | |
| // | |
| // 'work' is optional and is only present for quaternion types. It is used | |
| // to store intermediate quaternion multiplication results | |
| switch ( typeName ) { | |
| case 'quaternion': | |
| mixFunction = this._slerp; | |
| mixFunctionAdditive = this._slerpAdditive; | |
| setIdentity = this._setAdditiveIdentityQuaternion; | |
| this.buffer = new Float64Array( valueSize * 6 ); | |
| this._workIndex = 5; | |
| break; | |
| case 'string': | |
| case 'bool': | |
| mixFunction = this._select; | |
| // Use the regular mix function and for additive on these types, | |
| // additive is not relevant for non-numeric types | |
| mixFunctionAdditive = this._select; | |
| setIdentity = this._setAdditiveIdentityOther; | |
| this.buffer = new Array( valueSize * 5 ); | |
| break; | |
| default: | |
| mixFunction = this._lerp; | |
| mixFunctionAdditive = this._lerpAdditive; | |
| setIdentity = this._setAdditiveIdentityNumeric; | |
| this.buffer = new Float64Array( valueSize * 5 ); | |
| } | |
| this._mixBufferRegion = mixFunction; | |
| this._mixBufferRegionAdditive = mixFunctionAdditive; | |
| this._setIdentity = setIdentity; | |
| this._origIndex = 3; | |
| this._addIndex = 4; | |
| this.cumulativeWeight = 0; | |
| this.cumulativeWeightAdditive = 0; | |
| this.useCount = 0; | |
| this.referenceCount = 0; | |
| } | |
| // accumulate data in the 'incoming' region into 'accu<i>' | |
| accumulate( accuIndex, weight ) { | |
| // note: happily accumulating nothing when weight = 0, the caller knows | |
| // the weight and shouldn't have made the call in the first place | |
| const buffer = this.buffer, | |
| stride = this.valueSize, | |
| offset = accuIndex * stride + stride; | |
| let currentWeight = this.cumulativeWeight; | |
| if ( currentWeight === 0 ) { | |
| // accuN := incoming * weight | |
| for ( let i = 0; i !== stride; ++ i ) { | |
| buffer[ offset + i ] = buffer[ i ]; | |
| } | |
| currentWeight = weight; | |
| } else { | |
| // accuN := accuN + incoming * weight | |
| currentWeight += weight; | |
| const mix = weight / currentWeight; | |
| this._mixBufferRegion( buffer, offset, 0, mix, stride ); | |
| } | |
| this.cumulativeWeight = currentWeight; | |
| } | |
| // accumulate data in the 'incoming' region into 'add' | |
| accumulateAdditive( weight ) { | |
| const buffer = this.buffer, | |
| stride = this.valueSize, | |
| offset = stride * this._addIndex; | |
| if ( this.cumulativeWeightAdditive === 0 ) { | |
| // add = identity | |
| this._setIdentity(); | |
| } | |
| // add := add + incoming * weight | |
| this._mixBufferRegionAdditive( buffer, offset, 0, weight, stride ); | |
| this.cumulativeWeightAdditive += weight; | |
| } | |
| // apply the state of 'accu<i>' to the binding when accus differ | |
| apply( accuIndex ) { | |
| const stride = this.valueSize, | |
| buffer = this.buffer, | |
| offset = accuIndex * stride + stride, | |
| weight = this.cumulativeWeight, | |
| weightAdditive = this.cumulativeWeightAdditive, | |
| binding = this.binding; | |
| this.cumulativeWeight = 0; | |
| this.cumulativeWeightAdditive = 0; | |
| if ( weight < 1 ) { | |
| // accuN := accuN + original * ( 1 - cumulativeWeight ) | |
| const originalValueOffset = stride * this._origIndex; | |
| this._mixBufferRegion( | |
| buffer, offset, originalValueOffset, 1 - weight, stride ); | |
| } | |
| if ( weightAdditive > 0 ) { | |
| // accuN := accuN + additive accuN | |
| this._mixBufferRegionAdditive( buffer, offset, this._addIndex * stride, 1, stride ); | |
| } | |
| for ( let i = stride, e = stride + stride; i !== e; ++ i ) { | |
| if ( buffer[ i ] !== buffer[ i + stride ] ) { | |
| // value has changed -> update scene graph | |
| binding.setValue( buffer, offset ); | |
| break; | |
| } | |
| } | |
| } | |
| // remember the state of the bound property and copy it to both accus | |
| saveOriginalState() { | |
| const binding = this.binding; | |
| const buffer = this.buffer, | |
| stride = this.valueSize, | |
| originalValueOffset = stride * this._origIndex; | |
| binding.getValue( buffer, originalValueOffset ); | |
| // accu[0..1] := orig -- initially detect changes against the original | |
| for ( let i = stride, e = originalValueOffset; i !== e; ++ i ) { | |
| buffer[ i ] = buffer[ originalValueOffset + ( i % stride ) ]; | |
| } | |
| // Add to identity for additive | |
| this._setIdentity(); | |
| this.cumulativeWeight = 0; | |
| this.cumulativeWeightAdditive = 0; | |
| } | |
| // apply the state previously taken via 'saveOriginalState' to the binding | |
| restoreOriginalState() { | |
| const originalValueOffset = this.valueSize * 3; | |
| this.binding.setValue( this.buffer, originalValueOffset ); | |
| } | |
| _setAdditiveIdentityNumeric() { | |
| const startIndex = this._addIndex * this.valueSize; | |
| const endIndex = startIndex + this.valueSize; | |
| for ( let i = startIndex; i < endIndex; i ++ ) { | |
| this.buffer[ i ] = 0; | |
| } | |
| } | |
| _setAdditiveIdentityQuaternion() { | |
| this._setAdditiveIdentityNumeric(); | |
| this.buffer[ this._addIndex * this.valueSize + 3 ] = 1; | |
| } | |
| _setAdditiveIdentityOther() { | |
| const startIndex = this._origIndex * this.valueSize; | |
| const targetIndex = this._addIndex * this.valueSize; | |
| for ( let i = 0; i < this.valueSize; i ++ ) { | |
| this.buffer[ targetIndex + i ] = this.buffer[ startIndex + i ]; | |
| } | |
| } | |
| // mix functions | |
| _select( buffer, dstOffset, srcOffset, t, stride ) { | |
| if ( t >= 0.5 ) { | |
| for ( let i = 0; i !== stride; ++ i ) { | |
| buffer[ dstOffset + i ] = buffer[ srcOffset + i ]; | |
| } | |
| } | |
| } | |
| _slerp( buffer, dstOffset, srcOffset, t ) { | |
| Quaternion.slerpFlat( buffer, dstOffset, buffer, dstOffset, buffer, srcOffset, t ); | |
| } | |
| _slerpAdditive( buffer, dstOffset, srcOffset, t, stride ) { | |
| const workOffset = this._workIndex * stride; | |
| // Store result in intermediate buffer offset | |
| Quaternion.multiplyQuaternionsFlat( buffer, workOffset, buffer, dstOffset, buffer, srcOffset ); | |
| // Slerp to the intermediate result | |
| Quaternion.slerpFlat( buffer, dstOffset, buffer, dstOffset, buffer, workOffset, t ); | |
| } | |
| _lerp( buffer, dstOffset, srcOffset, t, stride ) { | |
| const s = 1 - t; | |
| for ( let i = 0; i !== stride; ++ i ) { | |
| const j = dstOffset + i; | |
| buffer[ j ] = buffer[ j ] * s + buffer[ srcOffset + i ] * t; | |
| } | |
| } | |
| _lerpAdditive( buffer, dstOffset, srcOffset, t, stride ) { | |
| for ( let i = 0; i !== stride; ++ i ) { | |
| const j = dstOffset + i; | |
| buffer[ j ] = buffer[ j ] + buffer[ srcOffset + i ] * t; | |
| } | |
| } | |
| } | |
| export { PropertyMixer }; | |
Xet Storage Details
- Size:
- 6.83 kB
- Xet hash:
- eb99b42b98bcf175620005d3be0a42919f9015439fe2f0d319dfba8af5d48d5b
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.