Spaces:
Running
Running
| import { Quaternion } from '../math/Quaternion.js'; | |
| /** | |
| * | |
| * Buffered scene graph property that allows weighted accumulation. | |
| * | |
| * | |
| * @author Ben Houston / http://clara.io/ | |
| * @author David Sarno / http://lighthaus.us/ | |
| * @author tschw | |
| */ | |
| function PropertyMixer( binding, typeName, valueSize ) { | |
| this.binding = binding; | |
| this.valueSize = valueSize; | |
| var bufferType = Float64Array, | |
| mixFunction; | |
| switch ( typeName ) { | |
| case 'quaternion': | |
| mixFunction = this._slerp; | |
| break; | |
| case 'string': | |
| case 'bool': | |
| bufferType = Array; | |
| mixFunction = this._select; | |
| break; | |
| default: | |
| mixFunction = this._lerp; | |
| } | |
| this.buffer = new bufferType( valueSize * 4 ); | |
| // layout: [ incoming | accu0 | accu1 | orig ] | |
| // | |
| // 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 | |
| this._mixBufferRegion = mixFunction; | |
| this.cumulativeWeight = 0; | |
| this.useCount = 0; | |
| this.referenceCount = 0; | |
| } | |
| Object.assign( PropertyMixer.prototype, { | |
| // accumulate data in the 'incoming' region into 'accu<i>' | |
| accumulate: function ( 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 | |
| var buffer = this.buffer, | |
| stride = this.valueSize, | |
| offset = accuIndex * stride + stride, | |
| currentWeight = this.cumulativeWeight; | |
| if ( currentWeight === 0 ) { | |
| // accuN := incoming * weight | |
| for ( var i = 0; i !== stride; ++ i ) { | |
| buffer[ offset + i ] = buffer[ i ]; | |
| } | |
| currentWeight = weight; | |
| } else { | |
| // accuN := accuN + incoming * weight | |
| currentWeight += weight; | |
| var mix = weight / currentWeight; | |
| this._mixBufferRegion( buffer, offset, 0, mix, stride ); | |
| } | |
| this.cumulativeWeight = currentWeight; | |
| }, | |
| // apply the state of 'accu<i>' to the binding when accus differ | |
| apply: function ( accuIndex ) { | |
| var stride = this.valueSize, | |
| buffer = this.buffer, | |
| offset = accuIndex * stride + stride, | |
| weight = this.cumulativeWeight, | |
| binding = this.binding; | |
| this.cumulativeWeight = 0; | |
| if ( weight < 1 ) { | |
| // accuN := accuN + original * ( 1 - cumulativeWeight ) | |
| var originalValueOffset = stride * 3; | |
| this._mixBufferRegion( | |
| buffer, offset, originalValueOffset, 1 - weight, stride ); | |
| } | |
| for ( var 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: function () { | |
| var binding = this.binding; | |
| var buffer = this.buffer, | |
| stride = this.valueSize, | |
| originalValueOffset = stride * 3; | |
| binding.getValue( buffer, originalValueOffset ); | |
| // accu[0..1] := orig -- initially detect changes against the original | |
| for ( var i = stride, e = originalValueOffset; i !== e; ++ i ) { | |
| buffer[ i ] = buffer[ originalValueOffset + ( i % stride ) ]; | |
| } | |
| this.cumulativeWeight = 0; | |
| }, | |
| // apply the state previously taken via 'saveOriginalState' to the binding | |
| restoreOriginalState: function () { | |
| var originalValueOffset = this.valueSize * 3; | |
| this.binding.setValue( this.buffer, originalValueOffset ); | |
| }, | |
| // mix functions | |
| _select: function ( buffer, dstOffset, srcOffset, t, stride ) { | |
| if ( t >= 0.5 ) { | |
| for ( var i = 0; i !== stride; ++ i ) { | |
| buffer[ dstOffset + i ] = buffer[ srcOffset + i ]; | |
| } | |
| } | |
| }, | |
| _slerp: function ( buffer, dstOffset, srcOffset, t ) { | |
| Quaternion.slerpFlat( buffer, dstOffset, buffer, dstOffset, buffer, srcOffset, t ); | |
| }, | |
| _lerp: function ( buffer, dstOffset, srcOffset, t, stride ) { | |
| var s = 1 - t; | |
| for ( var i = 0; i !== stride; ++ i ) { | |
| var j = dstOffset + i; | |
| buffer[ j ] = buffer[ j ] * s + buffer[ srcOffset + i ] * t; | |
| } | |
| } | |
| } ); | |
| export { PropertyMixer }; | |