1 /**
  2  * potree.js 
  3  * http://potree.org
  4  *
  5  * Copyright 2012, Markus Sch�tz
  6  * Licensed under the GPL Version 2 or later.
  7  * - http://potree.org/wp/?page_id=7
  8  * - http://www.gnu.org/licenses/gpl-3.0.html
  9  *
 10  */
 11 
 12 /**
 13  * @class
 14  */
 15 function SceneNode(name, parent) {
 16 	if (arguments[0] === inheriting) return;
 17 	this._scene = null;
 18 	this.name = name;
 19 	this.parent = parent;
 20 	this.children = new Object();
 21 	this.aabb = null;
 22 	this._visible = true;
 23 
 24 	// age in s
 25 	this.age = 0;
 26 
 27 	this._transform = M4x4.I;
 28 	if (parent != null) {
 29 		parent.addChild(this);
 30 		this.scene = parent.scene;
 31 	}
 32 }
 33 
 34 Object.defineProperty(SceneNode.prototype, 'visible', {
 35 	set: function(visible){
 36 		this._visible = visible;
 37 	},
 38 	
 39 	get: function(){
 40 		return this._visible;
 41 	}
 42 });
 43 
 44 Object.defineProperty(SceneNode.prototype, 'scene', {
 45 	set: function(scene){
 46 		this._scene = scene;
 47 	},
 48 	
 49 	get: function(){
 50 		return this._scene;
 51 	}
 52 });
 53 
 54 Object.defineProperty(SceneNode.prototype, "transform", {
 55 	get: function(){
 56 		return this._transform;
 57 	},
 58 	set: function(transform){
 59 		this._transform = transform;
 60 	}
 61 });
 62 
 63 Object.defineProperty(SceneNode.prototype, 'localTransformation', {
 64 	get: function(){
 65 		return this._transform;
 66 	}
 67 });
 68 
 69 Object.defineProperty(SceneNode.prototype, 'globalTransformation', {
 70 	get: function(){
 71 		var cur = this;
 72 		var globalTransform = cur._transform;
 73 		while (cur.parent != null) {
 74 			cur = cur.parent;
 75 			globalTransform = M4x4.mul(cur._transform, globalTransform);
 76 		}
 77 		return globalTransform;
 78 	}
 79 });
 80 
 81 Object.defineProperty(SceneNode.prototype, 'localPosition', {
 82 	get: function(){
 83 		return V3.transform(V3.$(0, 0, 0), this._transform);
 84 	}
 85 });
 86 
 87 Object.defineProperty(SceneNode.prototype, 'globalPosition', {
 88 	get: function(){
 89 		return V3.transform(V3.$(0, 0, 0), this.globalTransformation);
 90 	}
 91 });
 92 
 93 Object.defineProperty(SceneNode.prototype, 'descendants', {
 94 	get: function(){
 95 		var descendants = new Array();
 96 		var stack = new Array();
 97 		stack.push(this);
 98 		while(stack.length != 0){
 99 			var node = stack.pop();
100 			descendants.push(node);
101 			for(var key in node.children) {
102 				stack.push(node.children[key]);
103 			}
104 		}
105 		
106 		return descendants;
107 	}
108 });
109 
110 SceneNode.prototype.getLocalDirection = function(){
111 	var pos1 = V3.transform(V3.$(0, 0, 0), this._transform);
112 	var pos2 = V3.transform(V3.$(0, 0, -1), this._transform);
113 	
114 	var dir = V3.normalize(V3.sub(pos2, pos1));
115 	return dir;
116 };
117 
118 SceneNode.prototype.getGlobalDirection = function(){
119 	var transform = this.globalTransformation;
120 	var pos1 = V3.transform(V3.$(0, 0, 0), transform);
121 	var pos2 = V3.transform(V3.$(0, 0, -1), transform);
122 	
123 	var dir = V3.normalize(V3.sub(pos2, pos1));
124 	return dir;
125 };
126 
127 SceneNode.prototype.getUpVector = function() {
128 	var pos = V3.transform(V3.$(0, 0, 0), this._transform);
129 	var absUp = V3.transform(V3.$(0, 1, 0), this._transform);
130 	var up = V3.sub(absUp, pos);
131 
132 	return up;
133 };
134 
135 SceneNode.prototype.getSideVector = function() {
136 	var pos = V3.transform(V3.$(0, 0, 0), this._transform);
137 	var absSide = V3.transform(V3.$(1, 0, 0), this._transform);
138 	var side = V3.sub(absSide, pos);
139 
140 	return side;
141 };
142 
143 SceneNode.prototype.getViewVector = function() {
144 	var pos = V3.transform(V3.$(0, 0, 0), this._transform);
145 	var absView = V3.transform(V3.$(1, 0, 0), this._transform);
146 	var view = V3.sub(absView, pos);
147 
148 	return view;
149 };
150 
151 
152 SceneNode.prototype.addTime = function(time) {
153 	this.age += time;
154 
155 	for ( var childname in this.children) {
156 		this.children[childname].addTime(time);
157 	}
158 };
159 
160 SceneNode.prototype.setParent = function(parent) {
161 	delete parent[this.name];
162 	this.parent = parent;
163 	parent.children[this.name] = this;
164 	this.scene = parent.scene;
165 };
166 
167 SceneNode.prototype.addChild = function(child) {
168 	if (child.parent != null) {
169 		delete child.parent.children[child.name];
170 	}
171 
172 	child.parent = this;
173 	child.scene = this.scene;
174 	this.children[child.name] = child;
175 };
176 
177 
178 /**
179  * Liefert das Inverse der lokalen Transformationsmatrix unter der Annahme, dass
180  * es sich um eine Matrix handelt, die nach R�ckverschiebung zum Ursprung
181  * orthogonal ist.
182  * 
183  * @returns
184  */
185 SceneNode.prototype.getInverseLocalTransformation = function() {
186 	var pos = this.localPosition;
187 	var toOrigin = M4x4.translate3(-pos[0], -pos[1], -pos[2], M4x4.I);
188 	var atOrigin = M4x4.mul(toOrigin, this._transform);
189 	var inverseOrthonormal = M4x4.inverseOrthonormal(atOrigin);
190 
191 	return M4x4.mul(inverseOrthonormal, toOrigin);
192 };
193 
194 /**
195  * Liefert das Inverse der globalen Transformationsmatrix unter der Annahme,
196  * dass es sich um eine Matrix handelt, die nach R�ckverschiebung zum Ursprung
197  * orthogonal ist.
198  * 
199  * @returns
200  */
201 SceneNode.prototype.getInverseGlobalTransformation = function() {
202 	var pos = this.globalPosition;
203 	var toOrigin = M4x4.translate3(-pos[0], -pos[1], -pos[2], M4x4.I);
204 	var atOrigin = M4x4.mul(toOrigin, this.globalTransformation);
205 	var inverseOrthonormal = M4x4.inverseOrthonormal(atOrigin);
206 
207 	return M4x4.mul(inverseOrthonormal, toOrigin);
208 };
209 
210 SceneNode.prototype.translate = function(x, y, z) {
211 	//TODO probably bugged. in one case the first, in another the second(commented) seems to behave right. 
212 	this._transform = M4x4.translate3(x, y, z, this._transform);
213 //	this._transform = M4x4.mul(M4x4.makeTranslate3(x,y,z), this._transform);
214 };
215 
216 SceneNode.prototype.rotate = function(angle, axis) {
217 	this._transform = M4x4.mul(M4x4.rotate(angle, axis, M4x4.I), this._transform);
218 };
219 
220 SceneNode.prototype.rotateX = function(angle) {
221 	this._transform = M4x4.mul(M4x4.rotate(angle, V3.$(1, 0, 0), M4x4.I), this._transform);
222 };
223 
224 SceneNode.prototype.rotateY = function(angle) {
225 	this._transform = M4x4.mul(M4x4.rotate(angle, V3.$(0, 1, 0), M4x4.I), this._transform);
226 };
227 
228 SceneNode.prototype.rotateZ = function(angle) {
229 	this._transform = M4x4.mul(M4x4.rotate(angle, V3.$(0, 0, 1), M4x4.I), this._transform);
230 };
231 
232 SceneNode.prototype.scale = function(x, y, z) {
233 	this._transform = M4x4.scale3(x, y, z, this._transform);
234 };
235 
236 SceneNode.prototype.lookAt = function(target){
237 	//TODO check for correctness
238 	//TODO probably will not work if this sceneNodes parent transformation is != Identity
239 	//TODO up-vector is always 0/1/0. check for linear independance
240 	
241 	var nPos = this.globalPosition;
242 	
243 	var dz = V3.direction(nPos, target);
244 	var dy = V3.$(0,1,0);
245 	var dx = V3.cross(dy, dz);
246 	dy = V3.cross(dz, dx);
247 	
248 	dx = V3.neg(dx);
249 	dy = V3.neg(dy);
250 	dz = V3.neg(dz);
251 	
252 	var lookAt = M4x4.$(
253 			dx.x, dx.y, dx.z, 0,
254 			dy.x, dy.y, dy.z, 0,
255 			dz.x, dz.y, dz.z, 0,
256 			0,	0,	0,	1);
257 	var translate = M4x4.makeTranslate3(nPos.x, nPos.y, nPos.z);
258 	
259 	this.transform = M4x4.mul(translate, lookAt);
260 };
261 
262 SceneNode.prototype.render = function(camera) {
263 	// in unterklassen �berschreiben
264 
265 //	if(this.visible){
266 //		for ( var childname in this.children) {
267 //			this.children[childname].render(camera);
268 //		}
269 //	}
270 
271 };
272 
273 SceneNode.prototype.toString = function() {
274 	return this.asTreeString(0);
275 };
276 
277 SceneNode.prototype.asTreeString = function(level) {
278 	var msg = " ".repeat(level * 3) + this.name + "\t"
279 			+ this.globalPosition + "\n";
280 	for ( var child in this.children) {
281 		msg += this.children[child].asTreeString(level + 1);
282 	}
283 
284 	return msg;
285 };
286