📄 AnimationObjectGroup.js
¶
📊 Analysis Summary¶
Metric | Count |
---|---|
🔧 Functions | 5 |
🧱 Classes | 1 |
📦 Imports | 2 |
📊 Variables & Constants | 69 |
📚 Table of Contents¶
🛠️ File Location:¶
📂 src/animation/AnimationObjectGroup.js
📦 Imports¶
Name | Source |
---|---|
PropertyBinding |
./PropertyBinding.js |
generateUUID |
../math/MathUtils.js |
Variables & Constants¶
Name | Type | Kind | Value | Exported |
---|---|---|---|---|
indices |
{} |
let/var | {} |
✗ |
scope |
this |
let/var | this |
✗ |
objects |
any |
let/var | this._objects |
✗ |
indicesByUUID |
{} |
let/var | this._indicesByUUID |
✗ |
paths |
any[] |
let/var | this._paths |
✗ |
parsedPaths |
any[] |
let/var | this._parsedPaths |
✗ |
bindings |
any[] |
let/var | this._bindings |
✗ |
nBindings |
number |
let/var | bindings.length |
✗ |
knownObject |
any |
let/var | undefined |
✗ |
nObjects |
any |
let/var | objects.length |
✗ |
nCachedObjects |
number |
let/var | this.nCachedObjects_ |
✗ |
object |
any |
let/var | arguments[ i ] |
✗ |
uuid |
any |
let/var | object.uuid |
✗ |
index |
any |
let/var | indicesByUUID[ uuid ] |
✗ |
firstActiveIndex |
number |
let/var | -- nCachedObjects |
✗ |
lastCachedObject |
any |
let/var | objects[ firstActiveIndex ] |
✗ |
bindingsForPath |
any |
let/var | bindings[ j ] |
✗ |
lastCached |
any |
let/var | bindingsForPath[ firstActiveIndex ] |
✗ |
binding |
any |
let/var | bindingsForPath[ index ] |
✗ |
objects |
any |
let/var | this._objects |
✗ |
indicesByUUID |
{} |
let/var | this._indicesByUUID |
✗ |
bindings |
any[] |
let/var | this._bindings |
✗ |
nBindings |
number |
let/var | bindings.length |
✗ |
nCachedObjects |
number |
let/var | this.nCachedObjects_ |
✗ |
object |
any |
let/var | arguments[ i ] |
✗ |
uuid |
any |
let/var | object.uuid |
✗ |
index |
any |
let/var | indicesByUUID[ uuid ] |
✗ |
lastCachedIndex |
number |
let/var | nCachedObjects ++ |
✗ |
firstActiveObject |
any |
let/var | objects[ lastCachedIndex ] |
✗ |
bindingsForPath |
any |
let/var | bindings[ j ] |
✗ |
firstActive |
any |
let/var | bindingsForPath[ lastCachedIndex ] |
✗ |
binding |
any |
let/var | bindingsForPath[ index ] |
✗ |
objects |
any |
let/var | this._objects |
✗ |
indicesByUUID |
{} |
let/var | this._indicesByUUID |
✗ |
bindings |
any[] |
let/var | this._bindings |
✗ |
nBindings |
number |
let/var | bindings.length |
✗ |
nCachedObjects |
number |
let/var | this.nCachedObjects_ |
✗ |
nObjects |
any |
let/var | objects.length |
✗ |
object |
any |
let/var | arguments[ i ] |
✗ |
uuid |
any |
let/var | object.uuid |
✗ |
index |
any |
let/var | indicesByUUID[ uuid ] |
✗ |
firstActiveIndex |
number |
let/var | -- nCachedObjects |
✗ |
lastCachedObject |
any |
let/var | objects[ firstActiveIndex ] |
✗ |
lastIndex |
number |
let/var | -- nObjects |
✗ |
lastObject |
any |
let/var | objects[ lastIndex ] |
✗ |
bindingsForPath |
any |
let/var | bindings[ j ] |
✗ |
lastCached |
any |
let/var | bindingsForPath[ firstActiveIndex ] |
✗ |
last |
any |
let/var | bindingsForPath[ lastIndex ] |
✗ |
lastIndex |
number |
let/var | -- nObjects |
✗ |
lastObject |
any |
let/var | objects[ lastIndex ] |
✗ |
bindingsForPath |
any |
let/var | bindings[ j ] |
✗ |
indicesByPath |
{} |
let/var | this._bindingsIndicesByPath |
✗ |
index |
any |
let/var | indicesByPath[ path ] |
✗ |
bindings |
any[] |
let/var | this._bindings |
✗ |
paths |
any[] |
let/var | this._paths |
✗ |
parsedPaths |
any[] |
let/var | this._parsedPaths |
✗ |
objects |
any |
let/var | this._objects |
✗ |
nObjects |
any |
let/var | objects.length |
✗ |
nCachedObjects |
number |
let/var | this.nCachedObjects_ |
✗ |
bindingsForPath |
any[] |
let/var | new Array( nObjects ) |
✗ |
object |
any |
let/var | objects[ i ] |
✗ |
indicesByPath |
{} |
let/var | this._bindingsIndicesByPath |
✗ |
index |
any |
let/var | indicesByPath[ path ] |
✗ |
paths |
any[] |
let/var | this._paths |
✗ |
parsedPaths |
any[] |
let/var | this._parsedPaths |
✗ |
bindings |
any[] |
let/var | this._bindings |
✗ |
lastBindingsIndex |
number |
let/var | bindings.length - 1 |
✗ |
lastBindings |
any |
let/var | bindings[ lastBindingsIndex ] |
✗ |
lastBindingsPath |
any |
let/var | path[ lastBindingsIndex ] |
✗ |
Functions¶
AnimationObjectGroup.add(): void
¶
JSDoc:
/**
* Adds an arbitrary number of objects to this animation group.
*
* @param {...Object3D} arguments - The 3D objects to add.
*/
Returns: void
Calls:
objects.push
bindings[ j ].push
console.error
Internal Comments:
// unknown object -> add it to the ACTIVE region (x3)
// accounting is done, now do the same for all bindings (x2)
// move existing object to the ACTIVE region (x2)
// since we do not bother to create new bindings (x3)
// for objects that are cached, the binding may (x3)
// or may not exist (x3)
Code
add() {
const objects = this._objects,
indicesByUUID = this._indicesByUUID,
paths = this._paths,
parsedPaths = this._parsedPaths,
bindings = this._bindings,
nBindings = bindings.length;
let knownObject = undefined,
nObjects = objects.length,
nCachedObjects = this.nCachedObjects_;
for ( let i = 0, n = arguments.length; i !== n; ++ i ) {
const object = arguments[ i ],
uuid = object.uuid;
let index = indicesByUUID[ uuid ];
if ( index === undefined ) {
// unknown object -> add it to the ACTIVE region
index = nObjects ++;
indicesByUUID[ uuid ] = index;
objects.push( object );
// accounting is done, now do the same for all bindings
for ( let j = 0, m = nBindings; j !== m; ++ j ) {
bindings[ j ].push( new PropertyBinding( object, paths[ j ], parsedPaths[ j ] ) );
}
} else if ( index < nCachedObjects ) {
knownObject = objects[ index ];
// move existing object to the ACTIVE region
const firstActiveIndex = -- nCachedObjects,
lastCachedObject = objects[ firstActiveIndex ];
indicesByUUID[ lastCachedObject.uuid ] = index;
objects[ index ] = lastCachedObject;
indicesByUUID[ uuid ] = firstActiveIndex;
objects[ firstActiveIndex ] = object;
// accounting is done, now do the same for all bindings
for ( let j = 0, m = nBindings; j !== m; ++ j ) {
const bindingsForPath = bindings[ j ],
lastCached = bindingsForPath[ firstActiveIndex ];
let binding = bindingsForPath[ index ];
bindingsForPath[ index ] = lastCached;
if ( binding === undefined ) {
// since we do not bother to create new bindings
// for objects that are cached, the binding may
// or may not exist
binding = new PropertyBinding( object, paths[ j ], parsedPaths[ j ] );
}
bindingsForPath[ firstActiveIndex ] = binding;
}
} else if ( objects[ index ] !== knownObject ) {
console.error( 'THREE.AnimationObjectGroup: Different objects with the same UUID ' +
'detected. Clean the caches or recreate your infrastructure when reloading scenes.' );
} // else the object is already where we want it to be
} // for arguments
this.nCachedObjects_ = nCachedObjects;
}
AnimationObjectGroup.remove(): void
¶
JSDoc:
/**
* Removes an arbitrary number of objects to this animation group
*
* @param {...Object3D} arguments - The 3D objects to remove.
*/
Returns: void
Internal Comments:
// move existing object into the CACHED region (x2)
// accounting is done, now do the same for all bindings
Code
remove() {
const objects = this._objects,
indicesByUUID = this._indicesByUUID,
bindings = this._bindings,
nBindings = bindings.length;
let nCachedObjects = this.nCachedObjects_;
for ( let i = 0, n = arguments.length; i !== n; ++ i ) {
const object = arguments[ i ],
uuid = object.uuid,
index = indicesByUUID[ uuid ];
if ( index !== undefined && index >= nCachedObjects ) {
// move existing object into the CACHED region
const lastCachedIndex = nCachedObjects ++,
firstActiveObject = objects[ lastCachedIndex ];
indicesByUUID[ firstActiveObject.uuid ] = index;
objects[ index ] = firstActiveObject;
indicesByUUID[ uuid ] = lastCachedIndex;
objects[ lastCachedIndex ] = object;
// accounting is done, now do the same for all bindings
for ( let j = 0, m = nBindings; j !== m; ++ j ) {
const bindingsForPath = bindings[ j ],
firstActive = bindingsForPath[ lastCachedIndex ],
binding = bindingsForPath[ index ];
bindingsForPath[ index ] = firstActive;
bindingsForPath[ lastCachedIndex ] = binding;
}
}
} // for arguments
this.nCachedObjects_ = nCachedObjects;
}
AnimationObjectGroup.uncache(): void
¶
JSDoc:
/**
* Deallocates all memory resources for the passed 3D objects of this animation group.
*
* @param {...Object3D} arguments - The 3D objects to uncache.
*/
Returns: void
Calls:
objects.pop
bindingsForPath.pop
Internal Comments:
// object is cached, shrink the CACHED region (x2)
// last cached object takes this object's place (x4)
// last object goes to the activated slot and pop (x4)
// accounting is done, now do the same for all bindings (x2)
// object is active, just swap with the last and pop (x2)
Code
uncache() {
const objects = this._objects,
indicesByUUID = this._indicesByUUID,
bindings = this._bindings,
nBindings = bindings.length;
let nCachedObjects = this.nCachedObjects_,
nObjects = objects.length;
for ( let i = 0, n = arguments.length; i !== n; ++ i ) {
const object = arguments[ i ],
uuid = object.uuid,
index = indicesByUUID[ uuid ];
if ( index !== undefined ) {
delete indicesByUUID[ uuid ];
if ( index < nCachedObjects ) {
// object is cached, shrink the CACHED region
const firstActiveIndex = -- nCachedObjects,
lastCachedObject = objects[ firstActiveIndex ],
lastIndex = -- nObjects,
lastObject = objects[ lastIndex ];
// last cached object takes this object's place
indicesByUUID[ lastCachedObject.uuid ] = index;
objects[ index ] = lastCachedObject;
// last object goes to the activated slot and pop
indicesByUUID[ lastObject.uuid ] = firstActiveIndex;
objects[ firstActiveIndex ] = lastObject;
objects.pop();
// accounting is done, now do the same for all bindings
for ( let j = 0, m = nBindings; j !== m; ++ j ) {
const bindingsForPath = bindings[ j ],
lastCached = bindingsForPath[ firstActiveIndex ],
last = bindingsForPath[ lastIndex ];
bindingsForPath[ index ] = lastCached;
bindingsForPath[ firstActiveIndex ] = last;
bindingsForPath.pop();
}
} else {
// object is active, just swap with the last and pop
const lastIndex = -- nObjects,
lastObject = objects[ lastIndex ];
if ( lastIndex > 0 ) {
indicesByUUID[ lastObject.uuid ] = index;
}
objects[ index ] = lastObject;
objects.pop();
// accounting is done, now do the same for all bindings
for ( let j = 0, m = nBindings; j !== m; ++ j ) {
const bindingsForPath = bindings[ j ];
bindingsForPath[ index ] = bindingsForPath[ lastIndex ];
bindingsForPath.pop();
}
} // cached or active
} // if object is known
} // for arguments
this.nCachedObjects_ = nCachedObjects;
}
AnimationObjectGroup.subscribe_(path: any, parsedPath: any): any
¶
Parameters:
path
any
parsedPath
any
Returns: any
Calls:
paths.push
parsedPaths.push
bindings.push
Internal Comments:
// returns an array of bindings for the given path that is changed (x2)
// according to the contained objects in the group (x2)
Code
subscribe_( path, parsedPath ) {
// returns an array of bindings for the given path that is changed
// according to the contained objects in the group
const indicesByPath = this._bindingsIndicesByPath;
let index = indicesByPath[ path ];
const bindings = this._bindings;
if ( index !== undefined ) return bindings[ index ];
const paths = this._paths,
parsedPaths = this._parsedPaths,
objects = this._objects,
nObjects = objects.length,
nCachedObjects = this.nCachedObjects_,
bindingsForPath = new Array( nObjects );
index = bindings.length;
indicesByPath[ path ] = index;
paths.push( path );
parsedPaths.push( parsedPath );
bindings.push( bindingsForPath );
for ( let i = nCachedObjects, n = objects.length; i !== n; ++ i ) {
const object = objects[ i ];
bindingsForPath[ i ] = new PropertyBinding( object, path, parsedPath );
}
return bindingsForPath;
}
AnimationObjectGroup.unsubscribe_(path: any): void
¶
Parameters:
path
any
Returns: void
Calls:
bindings.pop
parsedPaths.pop
paths.pop
Internal Comments:
// tells the group to forget about a property path and no longer (x2)
// update the array previously obtained with 'subscribe_' (x2)
Code
unsubscribe_( path ) {
// tells the group to forget about a property path and no longer
// update the array previously obtained with 'subscribe_'
const indicesByPath = this._bindingsIndicesByPath,
index = indicesByPath[ path ];
if ( index !== undefined ) {
const paths = this._paths,
parsedPaths = this._parsedPaths,
bindings = this._bindings,
lastBindingsIndex = bindings.length - 1,
lastBindings = bindings[ lastBindingsIndex ],
lastBindingsPath = path[ lastBindingsIndex ];
indicesByPath[ lastBindingsPath ] = index;
bindings[ index ] = lastBindings;
bindings.pop();
parsedPaths[ index ] = parsedPaths[ lastBindingsIndex ];
parsedPaths.pop();
paths[ index ] = paths[ lastBindingsIndex ];
paths.pop();
}
}
Classes¶
AnimationObjectGroup
¶
Class Code
class AnimationObjectGroup {
/**
* Constructs a new animation group.
*
* @param {...Object3D} arguments - An arbitrary number of 3D objects that share the same animation state.
*/
constructor() {
/**
* This flag can be used for type testing.
*
* @type {boolean}
* @readonly
* @default true
*/
this.isAnimationObjectGroup = true;
/**
* The UUID of the 3D object.
*
* @type {string}
* @readonly
*/
this.uuid = generateUUID();
// cached objects followed by the active ones
this._objects = Array.prototype.slice.call( arguments );
this.nCachedObjects_ = 0; // threshold
// note: read by PropertyBinding.Composite
const indices = {};
this._indicesByUUID = indices; // for bookkeeping
for ( let i = 0, n = arguments.length; i !== n; ++ i ) {
indices[ arguments[ i ].uuid ] = i;
}
this._paths = []; // inside: string
this._parsedPaths = []; // inside: { we don't care, here }
this._bindings = []; // inside: Array< PropertyBinding >
this._bindingsIndicesByPath = {}; // inside: indices in these arrays
const scope = this;
this.stats = {
objects: {
get total() {
return scope._objects.length;
},
get inUse() {
return this.total - scope.nCachedObjects_;
}
},
get bindingsPerObject() {
return scope._bindings.length;
}
};
}
/**
* Adds an arbitrary number of objects to this animation group.
*
* @param {...Object3D} arguments - The 3D objects to add.
*/
add() {
const objects = this._objects,
indicesByUUID = this._indicesByUUID,
paths = this._paths,
parsedPaths = this._parsedPaths,
bindings = this._bindings,
nBindings = bindings.length;
let knownObject = undefined,
nObjects = objects.length,
nCachedObjects = this.nCachedObjects_;
for ( let i = 0, n = arguments.length; i !== n; ++ i ) {
const object = arguments[ i ],
uuid = object.uuid;
let index = indicesByUUID[ uuid ];
if ( index === undefined ) {
// unknown object -> add it to the ACTIVE region
index = nObjects ++;
indicesByUUID[ uuid ] = index;
objects.push( object );
// accounting is done, now do the same for all bindings
for ( let j = 0, m = nBindings; j !== m; ++ j ) {
bindings[ j ].push( new PropertyBinding( object, paths[ j ], parsedPaths[ j ] ) );
}
} else if ( index < nCachedObjects ) {
knownObject = objects[ index ];
// move existing object to the ACTIVE region
const firstActiveIndex = -- nCachedObjects,
lastCachedObject = objects[ firstActiveIndex ];
indicesByUUID[ lastCachedObject.uuid ] = index;
objects[ index ] = lastCachedObject;
indicesByUUID[ uuid ] = firstActiveIndex;
objects[ firstActiveIndex ] = object;
// accounting is done, now do the same for all bindings
for ( let j = 0, m = nBindings; j !== m; ++ j ) {
const bindingsForPath = bindings[ j ],
lastCached = bindingsForPath[ firstActiveIndex ];
let binding = bindingsForPath[ index ];
bindingsForPath[ index ] = lastCached;
if ( binding === undefined ) {
// since we do not bother to create new bindings
// for objects that are cached, the binding may
// or may not exist
binding = new PropertyBinding( object, paths[ j ], parsedPaths[ j ] );
}
bindingsForPath[ firstActiveIndex ] = binding;
}
} else if ( objects[ index ] !== knownObject ) {
console.error( 'THREE.AnimationObjectGroup: Different objects with the same UUID ' +
'detected. Clean the caches or recreate your infrastructure when reloading scenes.' );
} // else the object is already where we want it to be
} // for arguments
this.nCachedObjects_ = nCachedObjects;
}
/**
* Removes an arbitrary number of objects to this animation group
*
* @param {...Object3D} arguments - The 3D objects to remove.
*/
remove() {
const objects = this._objects,
indicesByUUID = this._indicesByUUID,
bindings = this._bindings,
nBindings = bindings.length;
let nCachedObjects = this.nCachedObjects_;
for ( let i = 0, n = arguments.length; i !== n; ++ i ) {
const object = arguments[ i ],
uuid = object.uuid,
index = indicesByUUID[ uuid ];
if ( index !== undefined && index >= nCachedObjects ) {
// move existing object into the CACHED region
const lastCachedIndex = nCachedObjects ++,
firstActiveObject = objects[ lastCachedIndex ];
indicesByUUID[ firstActiveObject.uuid ] = index;
objects[ index ] = firstActiveObject;
indicesByUUID[ uuid ] = lastCachedIndex;
objects[ lastCachedIndex ] = object;
// accounting is done, now do the same for all bindings
for ( let j = 0, m = nBindings; j !== m; ++ j ) {
const bindingsForPath = bindings[ j ],
firstActive = bindingsForPath[ lastCachedIndex ],
binding = bindingsForPath[ index ];
bindingsForPath[ index ] = firstActive;
bindingsForPath[ lastCachedIndex ] = binding;
}
}
} // for arguments
this.nCachedObjects_ = nCachedObjects;
}
/**
* Deallocates all memory resources for the passed 3D objects of this animation group.
*
* @param {...Object3D} arguments - The 3D objects to uncache.
*/
uncache() {
const objects = this._objects,
indicesByUUID = this._indicesByUUID,
bindings = this._bindings,
nBindings = bindings.length;
let nCachedObjects = this.nCachedObjects_,
nObjects = objects.length;
for ( let i = 0, n = arguments.length; i !== n; ++ i ) {
const object = arguments[ i ],
uuid = object.uuid,
index = indicesByUUID[ uuid ];
if ( index !== undefined ) {
delete indicesByUUID[ uuid ];
if ( index < nCachedObjects ) {
// object is cached, shrink the CACHED region
const firstActiveIndex = -- nCachedObjects,
lastCachedObject = objects[ firstActiveIndex ],
lastIndex = -- nObjects,
lastObject = objects[ lastIndex ];
// last cached object takes this object's place
indicesByUUID[ lastCachedObject.uuid ] = index;
objects[ index ] = lastCachedObject;
// last object goes to the activated slot and pop
indicesByUUID[ lastObject.uuid ] = firstActiveIndex;
objects[ firstActiveIndex ] = lastObject;
objects.pop();
// accounting is done, now do the same for all bindings
for ( let j = 0, m = nBindings; j !== m; ++ j ) {
const bindingsForPath = bindings[ j ],
lastCached = bindingsForPath[ firstActiveIndex ],
last = bindingsForPath[ lastIndex ];
bindingsForPath[ index ] = lastCached;
bindingsForPath[ firstActiveIndex ] = last;
bindingsForPath.pop();
}
} else {
// object is active, just swap with the last and pop
const lastIndex = -- nObjects,
lastObject = objects[ lastIndex ];
if ( lastIndex > 0 ) {
indicesByUUID[ lastObject.uuid ] = index;
}
objects[ index ] = lastObject;
objects.pop();
// accounting is done, now do the same for all bindings
for ( let j = 0, m = nBindings; j !== m; ++ j ) {
const bindingsForPath = bindings[ j ];
bindingsForPath[ index ] = bindingsForPath[ lastIndex ];
bindingsForPath.pop();
}
} // cached or active
} // if object is known
} // for arguments
this.nCachedObjects_ = nCachedObjects;
}
// Internal interface used by befriended PropertyBinding.Composite:
subscribe_( path, parsedPath ) {
// returns an array of bindings for the given path that is changed
// according to the contained objects in the group
const indicesByPath = this._bindingsIndicesByPath;
let index = indicesByPath[ path ];
const bindings = this._bindings;
if ( index !== undefined ) return bindings[ index ];
const paths = this._paths,
parsedPaths = this._parsedPaths,
objects = this._objects,
nObjects = objects.length,
nCachedObjects = this.nCachedObjects_,
bindingsForPath = new Array( nObjects );
index = bindings.length;
indicesByPath[ path ] = index;
paths.push( path );
parsedPaths.push( parsedPath );
bindings.push( bindingsForPath );
for ( let i = nCachedObjects, n = objects.length; i !== n; ++ i ) {
const object = objects[ i ];
bindingsForPath[ i ] = new PropertyBinding( object, path, parsedPath );
}
return bindingsForPath;
}
unsubscribe_( path ) {
// tells the group to forget about a property path and no longer
// update the array previously obtained with 'subscribe_'
const indicesByPath = this._bindingsIndicesByPath,
index = indicesByPath[ path ];
if ( index !== undefined ) {
const paths = this._paths,
parsedPaths = this._parsedPaths,
bindings = this._bindings,
lastBindingsIndex = bindings.length - 1,
lastBindings = bindings[ lastBindingsIndex ],
lastBindingsPath = path[ lastBindingsIndex ];
indicesByPath[ lastBindingsPath ] = index;
bindings[ index ] = lastBindings;
bindings.pop();
parsedPaths[ index ] = parsedPaths[ lastBindingsIndex ];
parsedPaths.pop();
paths[ index ] = paths[ lastBindingsIndex ];
paths.pop();
}
}
}
Methods¶
add(): void
¶
Code
add() {
const objects = this._objects,
indicesByUUID = this._indicesByUUID,
paths = this._paths,
parsedPaths = this._parsedPaths,
bindings = this._bindings,
nBindings = bindings.length;
let knownObject = undefined,
nObjects = objects.length,
nCachedObjects = this.nCachedObjects_;
for ( let i = 0, n = arguments.length; i !== n; ++ i ) {
const object = arguments[ i ],
uuid = object.uuid;
let index = indicesByUUID[ uuid ];
if ( index === undefined ) {
// unknown object -> add it to the ACTIVE region
index = nObjects ++;
indicesByUUID[ uuid ] = index;
objects.push( object );
// accounting is done, now do the same for all bindings
for ( let j = 0, m = nBindings; j !== m; ++ j ) {
bindings[ j ].push( new PropertyBinding( object, paths[ j ], parsedPaths[ j ] ) );
}
} else if ( index < nCachedObjects ) {
knownObject = objects[ index ];
// move existing object to the ACTIVE region
const firstActiveIndex = -- nCachedObjects,
lastCachedObject = objects[ firstActiveIndex ];
indicesByUUID[ lastCachedObject.uuid ] = index;
objects[ index ] = lastCachedObject;
indicesByUUID[ uuid ] = firstActiveIndex;
objects[ firstActiveIndex ] = object;
// accounting is done, now do the same for all bindings
for ( let j = 0, m = nBindings; j !== m; ++ j ) {
const bindingsForPath = bindings[ j ],
lastCached = bindingsForPath[ firstActiveIndex ];
let binding = bindingsForPath[ index ];
bindingsForPath[ index ] = lastCached;
if ( binding === undefined ) {
// since we do not bother to create new bindings
// for objects that are cached, the binding may
// or may not exist
binding = new PropertyBinding( object, paths[ j ], parsedPaths[ j ] );
}
bindingsForPath[ firstActiveIndex ] = binding;
}
} else if ( objects[ index ] !== knownObject ) {
console.error( 'THREE.AnimationObjectGroup: Different objects with the same UUID ' +
'detected. Clean the caches or recreate your infrastructure when reloading scenes.' );
} // else the object is already where we want it to be
} // for arguments
this.nCachedObjects_ = nCachedObjects;
}
remove(): void
¶
Code
remove() {
const objects = this._objects,
indicesByUUID = this._indicesByUUID,
bindings = this._bindings,
nBindings = bindings.length;
let nCachedObjects = this.nCachedObjects_;
for ( let i = 0, n = arguments.length; i !== n; ++ i ) {
const object = arguments[ i ],
uuid = object.uuid,
index = indicesByUUID[ uuid ];
if ( index !== undefined && index >= nCachedObjects ) {
// move existing object into the CACHED region
const lastCachedIndex = nCachedObjects ++,
firstActiveObject = objects[ lastCachedIndex ];
indicesByUUID[ firstActiveObject.uuid ] = index;
objects[ index ] = firstActiveObject;
indicesByUUID[ uuid ] = lastCachedIndex;
objects[ lastCachedIndex ] = object;
// accounting is done, now do the same for all bindings
for ( let j = 0, m = nBindings; j !== m; ++ j ) {
const bindingsForPath = bindings[ j ],
firstActive = bindingsForPath[ lastCachedIndex ],
binding = bindingsForPath[ index ];
bindingsForPath[ index ] = firstActive;
bindingsForPath[ lastCachedIndex ] = binding;
}
}
} // for arguments
this.nCachedObjects_ = nCachedObjects;
}
uncache(): void
¶
Code
uncache() {
const objects = this._objects,
indicesByUUID = this._indicesByUUID,
bindings = this._bindings,
nBindings = bindings.length;
let nCachedObjects = this.nCachedObjects_,
nObjects = objects.length;
for ( let i = 0, n = arguments.length; i !== n; ++ i ) {
const object = arguments[ i ],
uuid = object.uuid,
index = indicesByUUID[ uuid ];
if ( index !== undefined ) {
delete indicesByUUID[ uuid ];
if ( index < nCachedObjects ) {
// object is cached, shrink the CACHED region
const firstActiveIndex = -- nCachedObjects,
lastCachedObject = objects[ firstActiveIndex ],
lastIndex = -- nObjects,
lastObject = objects[ lastIndex ];
// last cached object takes this object's place
indicesByUUID[ lastCachedObject.uuid ] = index;
objects[ index ] = lastCachedObject;
// last object goes to the activated slot and pop
indicesByUUID[ lastObject.uuid ] = firstActiveIndex;
objects[ firstActiveIndex ] = lastObject;
objects.pop();
// accounting is done, now do the same for all bindings
for ( let j = 0, m = nBindings; j !== m; ++ j ) {
const bindingsForPath = bindings[ j ],
lastCached = bindingsForPath[ firstActiveIndex ],
last = bindingsForPath[ lastIndex ];
bindingsForPath[ index ] = lastCached;
bindingsForPath[ firstActiveIndex ] = last;
bindingsForPath.pop();
}
} else {
// object is active, just swap with the last and pop
const lastIndex = -- nObjects,
lastObject = objects[ lastIndex ];
if ( lastIndex > 0 ) {
indicesByUUID[ lastObject.uuid ] = index;
}
objects[ index ] = lastObject;
objects.pop();
// accounting is done, now do the same for all bindings
for ( let j = 0, m = nBindings; j !== m; ++ j ) {
const bindingsForPath = bindings[ j ];
bindingsForPath[ index ] = bindingsForPath[ lastIndex ];
bindingsForPath.pop();
}
} // cached or active
} // if object is known
} // for arguments
this.nCachedObjects_ = nCachedObjects;
}
subscribe_(path: any, parsedPath: any): any
¶
Code
subscribe_( path, parsedPath ) {
// returns an array of bindings for the given path that is changed
// according to the contained objects in the group
const indicesByPath = this._bindingsIndicesByPath;
let index = indicesByPath[ path ];
const bindings = this._bindings;
if ( index !== undefined ) return bindings[ index ];
const paths = this._paths,
parsedPaths = this._parsedPaths,
objects = this._objects,
nObjects = objects.length,
nCachedObjects = this.nCachedObjects_,
bindingsForPath = new Array( nObjects );
index = bindings.length;
indicesByPath[ path ] = index;
paths.push( path );
parsedPaths.push( parsedPath );
bindings.push( bindingsForPath );
for ( let i = nCachedObjects, n = objects.length; i !== n; ++ i ) {
const object = objects[ i ];
bindingsForPath[ i ] = new PropertyBinding( object, path, parsedPath );
}
return bindingsForPath;
}
unsubscribe_(path: any): void
¶
Code
unsubscribe_( path ) {
// tells the group to forget about a property path and no longer
// update the array previously obtained with 'subscribe_'
const indicesByPath = this._bindingsIndicesByPath,
index = indicesByPath[ path ];
if ( index !== undefined ) {
const paths = this._paths,
parsedPaths = this._parsedPaths,
bindings = this._bindings,
lastBindingsIndex = bindings.length - 1,
lastBindings = bindings[ lastBindingsIndex ],
lastBindingsPath = path[ lastBindingsIndex ];
indicesByPath[ lastBindingsPath ] = index;
bindings[ index ] = lastBindings;
bindings.pop();
parsedPaths[ index ] = parsedPaths[ lastBindingsIndex ];
parsedPaths.pop();
paths[ index ] = paths[ lastBindingsIndex ];
paths.pop();
}
}