PropertyBinding.js 5.7 KB
Newer Older
1 2 3 4 5 6 7 8
/**
 *
 * A track bound to a real value in the scene graph.
 * 
 * @author Ben Houston / http://clara.io/
 * @author David Sarno / http://lighthaus.us/
 */

9
THREE.PropertyBinding = function ( rootNode, trackName ) {
10 11 12 13

	this.rootNode = rootNode;
	this.trackName = trackName;

14
	var parseResults = THREE.PropertyBinding.parseTrackName( trackName );
15 16 17

	this.directoryName = parseResults.directoryName || null;
	this.nodeName = parseResults.nodeName;
18
	this.material = parseResults.material;
19
	this.materialIndex = parseResults.materialIndex;
20
	this.propertyName = parseResults.propertyName || null;
21
	this.propertyIndex = parseResults.propertyIndex || -1;
22

23
	this.node = THREE.PropertyBinding.findNode( rootNode, this.nodeName );
24 25 26

};

27
THREE.PropertyBinding.prototype = {
28

29
	constructor: THREE.PropertyBinding,
30 31 32

	set: function( value ) {

33
		 console.log( "PropertyBinding.set( " + value + ")" );
34

35 36
		 var targetObject = this.node;

37
 		// ensure there is a value node
38
		if( ! targetObject ) {
39
			console.log( "  trying to update node for track: " + this.trackName + " but it wasn't found." );
B
Ben Houston 已提交
40
			return;
41 42
		}

43 44
		if( this.material ) {
			targetObject = targetObject.material;
45 46 47 48 49 50 51 52
			if( this.materialIndex !== undefined && this.materialIndex !== null && this.materialIndex >= 0 ) {
				if( targetObject.materials ) {
					targetObject = targetObject.materials[ this.materialIndex ];
				}
				else {
					console.log( "  trying to submaterial via index, but no materials exist:", targetObject );				
				}
			}
53 54
		}

55
 		// ensure there is a value property on the node
56
		var nodeProperty = targetObject[ this.propertyName ];
57
		if( ! nodeProperty ) {
58
			console.log( "  trying to update property for track: " + this.nodeName + '.' + this.propertyName + " but it wasn't found.", targetObject );				
B
Ben Houston 已提交
59
			return;
60 61 62
		}

		// access a sub element of the property array (only primitives are supported right now)
63 64 65
		if( ( this.propertyIndex.length && this.propertyIndex.length > 0 ) || this.propertyIndex >= 0 ) {
			console.log( '  update property array ' + this.propertyName + '[' + this.propertyIndex + '] via assignment.' );				
			nodeProperty[ this.propertyIndex ] = value;
66 67 68 69 70 71 72 73 74
		}
		// must use copy for Object3D.Euler/Quaternion		
		else if( nodeProperty.copy ) {
			console.log( '  update property ' + this.name + '.' + this.propertyName + ' via a set() function.' );				
			nodeProperty.copy( value );
		}
		// otherwise just set the property directly on the node (do not use nodeProperty as it may not be a reference object)
		else {
			console.log( '  update property ' + this.name + '.' + this.propertyName + ' via assignment.' );				
75
			targetObject[ this.propertyName ] = value;	
76 77 78
		}

		// trigger node dirty			
79
		if( targetObject.needsUpdate !== undefined ) { // material
80 81 82
			console.log( '  triggering material as dirty' );
			this.node.needsUpdate = true;
		}			
83
		if( targetObject.matrixWorldNeedsUpdate !== undefined ) { // node transform
84
			console.log( '  triggering node as dirty' );
85
			targetObject.matrixWorldNeedsUpdate = true;
86 87 88 89 90 91 92 93 94 95 96 97 98
		}

	},

	get: function() {

		throw new Error( "TODO" );

	}

};


99
THREE.PropertyBinding.parseTrackName = function( trackName ) {
100 101

	// matches strings in the form of:
102 103
	//    nodeName.property
	//    nodeName.property[accessor]
104
	//    nodeName.material.property[accessor]
105
	//    uuid.property[accessor]
106
	//    uuid.material.property[accessor]
107 108
	//    parentName/nodeName.property
	//    parentName/parentName/nodeName.property[index]
109 110
	// created and tested via https://regex101.com/#javascript

111
	var re = /^(([\w]+\/)*)([\w-]+)?(\.material(\[([\w]+)\])?)?(\.([\w]+)(\[([\w]+)\])?)?$/; 
112 113 114 115 116 117 118 119 120 121
	var matches = re.exec(trackName);

	if( ! matches ) {
		throw new Error( "cannot parse trackName at all: " + trackName );
	}

    if (matches.index === re.lastIndex) {
        re.lastIndex++;
    }

122
	var results = {
B
Ben Houston 已提交
123
		directoryName: matches[0],
B
Ben Houston 已提交
124
		nodeName: matches[3], 	// allowed to be null, specified root node.
125
		material: ( matches[4] && matches[4].length > 0 ),
126 127 128
		materialIndex: matches[6],
		propertyName: matches[8],
		propertyIndex: matches[10]	// allowed to be null, specifies that the whole property is set.
129 130
	};

B
Ben Houston 已提交
131
	console.log( "PropertyBinding.parseTrackName", trackName, results, matches );
132

133 134 135 136 137
	if( results.propertyName === null || results.propertyName.length === 0 ) {
		throw new Error( "can not parse propertyName from trackName: " + trackName );
	}

	return results;
138 139 140 141

};

// TODO: Cache this at some point
142
THREE.PropertyBinding.findNode = function( root, nodeName ) {
143 144 145

	console.log( 'AnimationUtils.findNode( ' + root.name + ', nodeName: ' + nodeName + ')');
	
146
	if( ! nodeName || nodeName === "" || nodeName === "root" || nodeName === "." || nodeName === -1 || nodeName === root.name || nodeName === root.uuid ) {
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163

		console.log( '  root.' );
		return root;

	}

	// (2) search into skeleton bones.
	if( root.skeleton ) {

		var searchSkeleton = function( skeleton ) {

			for( var i = 0; i < skeleton.bones.length; i ++ ) {

				var bone = skeleton.bones[i];

				if( bone.name === nodeName ) {

B
Ben Houston 已提交
164
					return bone;
165 166 167 168 169 170 171 172

				}
			}

			return null;

		};

B
Ben Houston 已提交
173
		var bone = searchSkeleton( root.skeleton );
174

B
Ben Houston 已提交
175
		if( bone ) {
176 177

			console.log( '  bone: ' + bone.name + '.' );
B
Ben Houston 已提交
178
			return bone;
179 180 181 182 183 184 185 186 187 188 189 190 191

		}
	}

	// (3) search into node subtree.
	if( root.children ) {

		var searchNodeSubtree = function( children ) {

			for( var i = 0; i < children.length; i ++ ) {

				var childNode = children[i];

192
				if( childNode.name === nodeName || childNode.uuid === nodeName ) {
193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218

					return childNode;

				}

				var result = searchNodeSubtree( childNode.children );

				if( result ) return result;

			}

			return null;	

		};

		var subTreeNode = searchNodeSubtree( root.children );

		if( subTreeNode ) {

			console.log( '  node: ' + subTreeNode.name + '.' );
			return subTreeNode;

		}

	}

B
Ben Houston 已提交
219
	console.log( "   <null>.  No node found for name: " + nodeName );
220 221 222

	return null;
}