1 /*
  2   Copyright (c) 2009 Seneca College
  3   Licenced under the MIT License (http://www.c3dl.org/index.php/mit-license/)
  4 */
  5 
  6 /**
  7 	@class c3dl.Actor is a base class for 3D objects.
  8 */
  9 c3dl.Actor = function()
 10 {
 11 	// Raw Position Values
 12 	this.left	    = c3dl.makeVector(1.0, 0.0, 0.0); // Left vector
 13 	this.up		    = c3dl.makeVector(0.0, 1.0, 0.0); // Up Vector
 14 	this.dir		= c3dl.makeVector(0.0, 0.0, 1.0); // Forward Vector
 15 	this.pos	    = c3dl.makeVector(0.0, 0.0, 0.0); // Position
 16 	this.scaleVec	= c3dl.makeVector(1.0, 1.0, 1.0); // Scale
 17 	
 18 	// Delta Values for Animations
 19 	this.linVel		= c3dl.makeVector(0.0, 0.0, 0.0); // Animation of positions
 20 	this.angVel		= c3dl.makeVector(0.0, 0.0, 0.0); // Animations of rotation around (side Vector, up Vector, dir Vector)
 21 	
 22 	this.name = "unnamed";
 23 }
 24 	
 25 // -------------------------------------------------------
 26 
 27 // Getters
 28 
 29 /**
 30 	Get the position of the Actor relative to the world origin.
 31 
 32 	@returns {Array} The position of the Actor.
 33 */
 34 c3dl.Actor.prototype.getPosition = function()
 35 {
 36 	return c3dl.makeVector(this.pos[0], this.pos[1], this.pos[2]); 
 37 }
 38 
 39 /**
 40 	The the Up Vector of the actor.
 41 
 42 	@returns {Array} The up Vector of the actor.
 43 */
 44 c3dl.Actor.prototype.getUp = function()
 45 {
 46 	return c3dl.makeVector(this.up[0], this.up[1], this.up[2]); 
 47 }
 48 
 49 /**
 50 	Get the direction of the actor, where the actor is 
 51 	'pointing' or looking'.
 52 
 53 	@returns {Array} The direction of the actor.
 54 */
 55 c3dl.Actor.prototype.getDirection = function()
 56 {
 57 	return c3dl.makeVector(this.dir[0], this.dir[1], this.dir[2]); 
 58 }
 59 
 60 /**
 61 	Get the left Vector of the actor.
 62 
 63 	@returns {Array} The left Vector of the actor.
 64 */
 65 c3dl.Actor.prototype.getLeft = function()
 66 {
 67 	return c3dl.makeVector(this.left[0], this.left[1], this.left[2]); 
 68 }
 69 
 70 /**
 71 	Get the linear velocity of the Actor.
 72 
 73 	@returns {Array} The linear velocity of the Actor.
 74 */
 75 c3dl.Actor.prototype.getLinearVel = function()
 76 {
 77 	return c3dl.makeVector(this.linVel[0], this.linVel[1], this.linVel[2]); 
 78 }
 79 
 80 /**
 81 	Get the angular velocity of the Actor.
 82 
 83 	@returns {Array} The angular velocity of the Actor.
 84 */
 85 c3dl.Actor.prototype.getAngularVel = function()
 86 {
 87 	return c3dl.makeVector(this.angVel[0], this.angVel[1], this.angVel[2]); 
 88 }
 89 
 90 /**
 91 	Get the scale factor of the Actor.  It has a default value 
 92 	of (1,1,1) when created.
 93 
 94 	@returns {Array} The scale amount of the Actor.
 95 */
 96 c3dl.Actor.prototype.getScale = function()
 97 {
 98 	return c3dl.makeVector(this.scaleVec[0], this.scaleVec[1], this.scaleVec[2]);
 99 }
100 
101 /**
102        Get the transformation of this node. Keep in mind that
103        if this node is 'animated', the matrix will be changing with 
104        each update(). In that case, the matrix this function returns
105        will the the state the matrix is in at the time the function is called.
106        
107        @return {Array}
108 */
109 c3dl.Actor.prototype.getTransform = function()
110 {
111 	var mat = c3dl.makePoseMatrix(this.left, this.up, this.dir, this.pos);
112 
113 	var smat = c3dl.makeMatrix();
114 	c3dl.setMatrix(smat, this.scaleVec[0], 0, 0, 0,
115 								0, this.scaleVec[1], 0, 0,
116 								0, 0, this.scaleVec[2], 0,
117 								0, 0, 0, 1 );
118 						   
119 	mat = c3dl.multiplyMatrixByMatrix(mat, smat);
120 
121 	return mat;
122 }
123 
124 /**
125 	Get the name of this actor.
126 	
127 	@returns {String} actor's name
128 */
129 c3dl.Actor.prototype.getName = function()
130 {
131 	return this.name;
132 }
133 
134 // Setters	
135 
136 /**
137 	Set the transformation of this actor.
138 
139 	@param {Array} mat
140 */
141 c3dl.Actor.prototype.setTransform = function(mat)
142 {
143 	this.left = c3dl.makeVector(mat[0], mat[1], mat[2]);
144 	this.up = c3dl.makeVector(mat[4], mat[5], mat[6]);
145 	this.dir = c3dl.makeVector(mat[8], mat[9], mat[10]);
146 	this.pos = c3dl.makeVector(mat[12], mat[13], mat[14]);
147 }
148 
149 /**
150 */
151 c3dl.Actor.prototype.resetTransform = function()
152 {
153 	this.angVel = c3dl.makeVector(0.0, 0.0, 0.0);
154 	this.linVel = c3dl.makeVector(0.0, 0.0, 0.0);
155 
156 	this.left = c3dl.makeVector(1.0, 0.0, 0.0);
157 	this.up   = c3dl.makeVector(0.0, 1.0, 0.0);
158 	this.dir  = c3dl.makeVector(0.0, 0.0, 1.0);
159 	this.pos  = c3dl.makeVector(0.0, 0.0, 0.0);
160 }
161 
162 
163 
164 /**
165 	Scale the  Actor relative to its current scaling value.	
166 	Attempts to scale the x, y or z values of the Actor less 
167 	than or equal to zero will be ignored.
168 
169 	@param {Array} scaleVec The amount to scale the Actor.
170 */
171 c3dl.Actor.prototype.scale = function(scaleVec)
172 {
173 	if ( c3dl.isValidVector(scaleVec))
174 	{
175 		// none of the values should be less than or equal to zero
176 		if(	scaleVec[0]  > 0.0 && scaleVec[1]  > 0.0 && scaleVec[2]  > 0.0)
177 		{				
178 			this.scaleVec = [	this.scaleVec[0] * scaleVec[0], 
179 								this.scaleVec[1] * scaleVec[1], 
180 								this.scaleVec[2] * scaleVec[2]];
181 		}			
182 	}
183 	else
184 	{
185 		c3dl.debug.logWarning('Actor::scale() called with a parameter that\'s not a vector');
186 	}
187 }
188 
189 /**
190 	Set the new location of the Actor.
191 
192 	@param {Array} vecPos A vector containing the new location for the actor.
193 */
194 c3dl.Actor.prototype.setPosition = function( vecPos )
195 {
196 	if (c3dl.isValidVector(vecPos))
197 	{
198 		this.pos = vecPos;
199 	}
200 	else
201 	{
202 		c3dl.debug.logWarning("Actor::setPosition() called with a parameter that's not a vector");
203 	}
204 }
205 
206 /**
207 	Move the object relative to where it is currently, not relative 
208 	to the origin.
209 
210 	@param {Array} translation A vector which represents 
211 	how far away to move the actor from its current location.
212 */
213 c3dl.Actor.prototype.translate = function( translation )
214 {
215 	this.pos = c3dl.addVectors(this.pos, translation);
216 }
217 
218 
219 /**
220 	Set the point in space where the Actor will look at (No Animation).
221 
222 	@param {Array} newVec
223 */	
224 c3dl.Actor.prototype.setForward = function(newVec)
225 {
226 	if (c3dl.isValidVector(newVec))
227 	{
228 		// Figure out the direction of the point we are looking at
229 		this.dir = this.pos;
230 		c3dl.subtractVectors(this.dir,newVec, this.dir);
231 		c3dl.normalizeVector(this.dir);
232 
233 		// Adjust the Up and Left vectors accordingly
234 		c3dl.vectorCrossProduct(this.up, this.dir, this.left);
235 		c3dl.normalizeVector(this.left);
236 		c3dl.vectorCrossProduct(this.dir, this.up, this.up);
237 		c3dl.normalizeVector(this.up);
238 	}
239 	else
240 	{
241 		c3dl.debug.logWarning('Actor::setForward() called with a parameter that\'s not a vector');
242 	}
243 }
244 
245 /**
246 	Set the orientation of Up (No Animation)
247 
248 	@param {Array} newVec
249 */
250 c3dl.Actor.prototype.setUpVector = function(newVec)
251 {
252 	if (c3dl.isValidVector(newVec))
253 	{
254 		this.up = newVec;
255 	}
256 	else
257 	{
258 		c3dl.debug.logWarning('Actor::setUpVector() called with a parameter that\'s not a vector');
259 	}
260 }
261 
262 /**
263 	Set a new Linear Velocity that will be added to the Position on every update
264 
265 	@param {Array} newVec
266 */
267 c3dl.Actor.prototype.setLinearVel = function(newVec)
268 {
269 	if (c3dl.isValidVector(newVec))
270 	{
271 		this.linVel = newVec;
272 	}
273 	else
274 	{
275 		c3dl.debug.logWarning('Actor::setLinearVel() called with a parameter that\'s not a vector');
276 	}
277 }
278 
279 /**
280   Set a new Angular Veclocity that will be added to the rotation on 
281   every update.
282 
283   @param {Array} newVec
284 */
285 c3dl.Actor.prototype.setAngularVel = function(newVec)
286 {
287 	if (c3dl.isValidVector(newVec))
288 	{
289 		this.angVel = newVec;
290 	}
291 	else
292 	{
293 		c3dl.debug.logWarning("Actor's setAngularVel() called with a parameter that's not a vector");
294 	}
295 }
296 
297 /**
298 	Set the name of this actor.
299 	
300 	@param {String} name The new name of for this actor.
301 */
302 c3dl.Actor.prototype.setName = function(name)
303 {
304 	this.name = name;
305 }
306 
307 // -------------------------------------------------------
308 
309 /**
310 	Rotate Actor on an axis which is centered on the position of 
311 	the Actor.
312 
313 	@param {Array} axisVec
314 	@param {float} angle in radians.
315 */
316 c3dl.Actor.prototype.rotateOnAxis = function(axisVec, angle)
317 {
318 	var rotateOnAxisQuat = c3dl.makeQuat(0, 0, 0, 0);
319 	var rotateOnAxisMat = c3dl.makeZeroMatrix();
320 
321 	if ( !c3dl.isValidVector(axisVec) )
322 	{
323 		c3dl.debug.logWarning('Actor::rotateOnAxis() called with the first parameter not a vector');
324 		return;
325 	}
326 	if (isNaN(angle))
327 	{
328 		c3dl.debug.logWarning('Actor::rotateOnAxis() called with the second parameter not a number');
329 		return;
330 	}
331 	if( angle == 0)
332 	{
333 		return;
334 	}
335 
336 	// Create a proper Quaternion based on location and angle
337 	c3dl.axisAngleToQuat(axisVec, angle, rotateOnAxisQuat);
338 
339 	// Create a rotation Matrix out of this quaternion
340 	rotateOnAxisMat = c3dl.quatToMatrix(rotateOnAxisQuat);
341 
342 	// Apply changes to the remaining vectors
343 	//
344 	c3dl.multiplyMatrixByVector(rotateOnAxisMat, this.dir, this.dir);
345 	c3dl.normalizeVector(this.dir);
346 
347 	c3dl.multiplyMatrixByVector(rotateOnAxisMat, this.left, this.left);
348 	c3dl.normalizeVector(this.left);
349 
350 	c3dl.multiplyMatrixByVector(rotateOnAxisMat, this.up, this.up);
351 	c3dl.normalizeVector(this.up);
352 }
353 
354 /**
355 	Rotate around the Up Vector by a hard amount (No Animation)
356 
357 	@param {float} angle in radians.
358 */
359 c3dl.Actor.prototype.yaw = function(angle)
360 {
361 	if(angle != 0)
362 	{
363 		this.rotateOnAxis(this.up, angle);
364 	}
365 }
366 
367 /**
368 	Rotate around the Dir Vector by a hard amount (No Animation)
369 
370 	@param {float} angle in radians.
371 */
372 c3dl.Actor.prototype.roll = function(angle)
373 {
374 	if(angle != 0)
375 	{
376 		this.rotateOnAxis(this.dir, angle);
377 	}
378 }
379 
380 /**
381 	Rotate around the Side Vector by a hard amount (No Animation)
382 
383 	@param {float} angle in radians.
384 */
385 c3dl.Actor.prototype.pitch = function(angle)
386 {
387 	if(angle != 0 )
388 	{
389 		this.rotateOnAxis(this.left, angle);
390 	}
391 }	
392 
393 /**
394 	@private
395 	
396 	Called automatically. Update animations, etc.
397 
398 	@param {float} timeStep
399 */
400 c3dl.Actor.prototype.update = function(timeStep)
401 {
402 	// if update took longer than 1/2 a second, it was
403 	// probably the GC, so don't apply angular velocities
404 	// since that will change the directions.
405 	if(timeStep < 500)
406 	{
407 		// Add a velocity to the position
408 		var velVec = this.linVel;
409 		c3dl.multiplyVector(velVec, timeStep);
410 		c3dl.addVectors(this.pos, velVec, this.pos);
411 
412 		// Apply some rotations to the orientation from the angular velocity
413 		this.pitch(this.angVel[0] * timeStep);
414 		this.yaw(this.angVel[1] * timeStep);
415 		this.roll(this.angVel[2] * timeStep);
416 	}
417 }
418 
419 /**
420 	@private
421 */
422 c3dl.Actor.prototype.getCopy = function()
423 {
424 	var actor = new c3dl.Actor();
425 	actor.clone(this);
426 	return actor;
427 }
428 
429 
430 /**
431 */
432 c3dl.Actor.getObjectType = function()
433 {
434 	return c3dl.COLLADA;
435 }
436 	
437 /**
438 	@private
439 */
440 c3dl.Actor.prototype.clone = function(other)
441 {
442 	this.left = c3dl.copyVector(other.left);
443 	this.up = c3dl.copyVector(other.up);
444 	this.dir = c3dl.copyVector(other.dir);
445 	this.pos = c3dl.copyVector(other.pos);
446 	this.scaleVec = c3dl.copyVector(other.scaleVec);
447 	this.linVel = c3dl.copyVector(other.linVel);
448 	this.angVel = c3dl.copyVector(other.angVel);
449 	this.name = other.name;
450 }
451