1 /*
  2 * Sprite3D.js
  3 * Visit the internets for documentation, updates and examples.
  4 * https://github.com/boblemarin/Sprite3D.js
  5 * http://minimal.be/lab/Sprite3D
  6 *
  7 * Copyright (c) 2010 boblemarin emeric@minimal.be http://www.minimal.be
  8 * 
  9 * Permission is hereby granted, free of charge, to any person
 10 * obtaining a copy of this software and associated documentation
 11 * files (the "Software"), to deal in the Software without
 12 * restriction, including without limitation the rights to use,
 13 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 14 * copies of the Software, and to permit persons to whom the
 15 * Software is furnished to do so, subject to the following
 16 * conditions:
 17 * 
 18 * The above copyright notice and this permission notice shall be
 19 * included in all copies or substantial portions of the Software.
 20 * 
 21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 22 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 23 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 24 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 25 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 26 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 27 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 28 * OTHER DEALINGS IN THE SOFTWARE.
 29 */
 30 
 31 /**
 32  * Creates an instance of Sprite3D
 33  *
 34  * @constructor
 35  * @author boblemarin
 36  * @this {Sprite3D}
 37  * @param {Object} element The DOM element to wrap the Sprite3D object around. When no element is provided, a empty div is created and added to the document.
 38  */
 39 function Sprite3D(element) {
 40 
 41 	if ( !Sprite3D.prototype._isInit ) Sprite3D.isSupported();
 42 
 43 	// private variables
 44 	var p = "", 
 45 		s = "",
 46 		rx = "",
 47 		ry = "",
 48 		rz = "",
 49 		ts = "",
 50 		i,
 51 		alpha = 1;
 52 //		listeners = {};
 53 		
 54 	this.listeners = {};
 55 
 56 	// create an empty <div> if no element is provided
 57 	if (element == null) { element = document.createElement("div"); }
 58 
 59 	// prepare for 3D positionning
 60 	element.style[ this._browserPrefix + "TransformStyle" ] = "preserve-3d";
 61 	element.style.margin = "0px";
 62 	element.style.padding = "0px";
 63 	element.style.position = "absolute";
 64 
 65 	// trigger hardware acceleration even if no property is set
 66 	element.style[ this._transformProperty ] = "translateZ(0px)";
 67 
 68 	// debug style
 69 	//element.style.border = '1px solid red';
 70 	this.domElement = element;
 71 	this.style = element.style;
 72 	this.children = [];
 73 }
 74 
 75 /** The X-axis position of the Sprite3D */
 76 Sprite3D.prototype.x = 0;
 77 /** The Y-axis position of the Sprite3D */
 78 Sprite3D.prototype.y = 0;
 79 /** The Z-axis position of the Sprite3D */
 80 Sprite3D.prototype.z = 0;
 81 
 82 /** The X-axis rotation of the Sprite3D */
 83 Sprite3D.prototype.rotationX = 0;
 84 /** The Y-axis rotation of the Sprite3D */
 85 Sprite3D.prototype.rotationY = 0;
 86 /** The Z-axis rotation of the Sprite3D */
 87 Sprite3D.prototype.rotationZ = 0;
 88 
 89 /** The X-axis scale of the Sprite3D */
 90 Sprite3D.prototype.scaleX = 1;
 91 /** The Y-axis scale of the Sprite3D */
 92 Sprite3D.prototype.scaleY = 1;
 93 /** The Z-axis scale of the Sprite3D */
 94 Sprite3D.prototype.scaleZ = 1;
 95 
 96 /** The width of the HTML element associated with the Sprite3D object */
 97 Sprite3D.prototype.width = 0;
 98 /** The height of the HTML element associated with the Sprite3D object */
 99 Sprite3D.prototype.height = 0;
100 
101 /** The X-axis registration point of the Sprite3D object used for 3D positionning */
102 Sprite3D.prototype.regX = 0;
103 /** The Y-axis registration point of the Sprite3D object used for 3D positionning */
104 Sprite3D.prototype.regY = 0;
105 /** The Y-axis registration point of the Sprite3D object used for 3D positionning */
106 Sprite3D.prototype.regZ = 0;
107 
108 /** The width (in pixels) of the tiles in the spritesheet */
109 Sprite3D.prototype.tileWidth = 0;
110 /** The height (in pixels) of the tiles in the spritesheet */
111 Sprite3D.prototype.tileHeight = 0;
112 
113 /** A reference to the DOM element associated with this Sprite3D object */
114 Sprite3D.prototype.domElement = null;
115 
116 /** A reference to the CSS style object of the DOM element */
117 Sprite3D.prototype.style = null;
118 
119 /** An array holding references of the Sprite3D's children object */
120 Sprite3D.prototype.children = [];
121 
122 /** The number of child objects */
123 Sprite3D.prototype.numChildren = 0;
124 
125 /** A boolean value to decide in which order transformations are applied. If true, rotations are applied before translations. If false, translations are applied before rotations. For a more accurate control over transformations order, you should use the transformString property. This property is now BROKEN. */
126 Sprite3D.prototype.rotateFirst = false;
127 
128 /** The transform string. You can use this property to fine control the order in which transformations are applied.
129  * The following values will be replaced by their respective transformations :
130  * _p for position/translations
131  * _s for scaling
132  * _rx for rotationX
133  * _ry for rotationY
134  * _rz for rotationZ
135  * Example: sprite.transformString = "_rx _ry _rz _p _s";
136  */
137 Sprite3D.prototype.transformString = "_p _rx _ry _rz _s";
138 
139 /**
140  * Sets the value of the transformString property, allowing to control transformations order.
141  * A valid value may be "_rx _ry _rz _p _s". See the transformString property for more informations.
142  * @param {String} ts The string that will be used to swap
143  * @return {Sprite3D} The reference to this Sprite3D object
144  */
145 Sprite3D.prototype.setTransformString = function(ts) {
146 	this.transformString = ts;
147 	return this;
148 };
149 
150 /**
151  * Sets the X-axis position of the Sprite3D.
152  * @param {Number} px The position
153  * @return {Sprite3D} The reference to this Sprite3D object
154  */
155 Sprite3D.prototype.setX = function(px) {
156 	this.x = px;
157 	return this;
158 };
159 
160 /**
161  * Sets the Y-axis position of the Sprite3D.
162  * @param {Number} py The position
163  * @return {Sprite3D} The reference to this Sprite3D object
164  */
165 Sprite3D.prototype.setY = function(py) {
166 	this.y = py;
167 	return this;
168 };
169 
170 /**
171  * Sets the Z-axis position of the Sprite3D.
172  * @param {Number} pz The position
173  * @return {Sprite3D} The reference to this Sprite3D object
174  */
175 Sprite3D.prototype.setZ = function(pz) {
176 	this.z = pz;
177 	return this;
178 };
179 
180 /**
181  * Sets the 3D position of the Sprite.
182  * @param {Number} px The position on the X-axis
183  * @param {Number} py The position on the Y-axis
184  * @param {Number} pz The position on the Z-axis
185  * @return {Sprite3D} The reference to this Sprite3D object
186  */
187 Sprite3D.prototype.setPosition = function(px, py, pz) {
188 	this.x = px;
189 	this.y = py;
190 	this.z = pz;
191 	return this;
192 };
193 
194 /**
195  * Applies a relative translation in 3D space on the X-axis.
196  * @param {Number} px The value of the translation
197  * @return {Sprite3D} The reference to this Sprite3D object
198  */
199 Sprite3D.prototype.moveX = function(px) {
200 	this.x += px;
201 	return this;
202 };
203 
204 /**
205  * Applies a relative translation in 3D space on the Y-axis.
206  * @param {Number} py The value of the translation
207  * @return {Sprite3D} The reference to this Sprite3D object
208  */
209 Sprite3D.prototype.moveY = function(py) {
210 	this.y += py;
211 	return this;
212 };
213 
214 /**
215  * Applies a relative translation in 3D space on the Z-axis.
216  * @param {Number} pz The value of the translation
217  * @return {Sprite3D} The reference to this Sprite3D object
218  */
219 Sprite3D.prototype.moveZ = function(pz) {
220 	this.z += pz;
221 	return this;
222 };
223 
224 /**
225  * Applies a relative translation in 3D space.
226  * @param {Number} px The value of the translation on the X-axis
227  * @param {Number} py The value of the translation on the Y-axis
228  * @param {Number} pz The value of the translation on the Z-axis
229  * @return {Sprite3D} The reference to this Sprite3D object
230  */
231 Sprite3D.prototype.move = function(px, py, pz) {
232 	this.x += px;
233 	this.y += py;
234 	this.z += pz;
235 	return this;
236 };
237 
238 
239 
240 /**
241  * Sets the amount of rotation around the X-axis of the Sprite3D.
242  * @param {Number} rx The value of the rotation
243  * @return {Sprite3D} The reference to this Sprite3D object
244  */
245 Sprite3D.prototype.setRotationX = function(rx) {
246 	this.rotationX = rx;
247 	return this;
248 };
249 
250 /**
251  * Sets the amount of rotation around the Y-axis of the Sprite3D.
252  * @param {Number} ry The value of the rotation
253  * @return {Sprite3D} The reference to this Sprite3D object
254  */
255 Sprite3D.prototype.setRotationY = function(ry) {
256 	this.rotationY = ry;
257 	return this;
258 };
259 
260 /**
261  * Sets the amount of rotation around the Z-axis of the Sprite3D.
262  * @param {Number} rz The value of the rotation
263  * @return {Sprite3D} The reference to this Sprite3D object
264  */
265 Sprite3D.prototype.setRotationZ = function(rz) {
266 	this.rotationZ = rz;
267 	return this;
268 };
269 
270 /**
271  * Sets the 3D rotation of the Sprite.
272  * @param {Number} rx The rotation around the X-axis
273  * @param {Number} ry The rotation around the Y-axis
274  * @param {Number} rz The rotation around the Z-axis
275  * @return {Sprite3D} The reference to this Sprite3D object
276  */
277 Sprite3D.prototype.setRotation = function(rx, ry, rz) {
278 	this.rotationX = rx;
279 	this.rotationY = ry;
280 	this.rotationZ = rz;
281 	return this;
282 };
283 
284 
285 /**
286  * Applies a relative rotation in 3D space around the X-axis.
287  * @param {Number} rx The value of the rotation
288  * @return {Sprite3D} The reference to this Sprite3D object
289  */
290 Sprite3D.prototype.rotateX = function(rx) {
291 	this.rotationX += rx;
292 	return this;
293 };
294 
295 /**
296  * Applies a relative rotation in 3D space around the Y-axis.
297  * @param {Number} ry The value of the rotation
298  * @return {Sprite3D} The reference to this Sprite3D object
299  */
300 Sprite3D.prototype.rotateY = function(ry) {
301 	this.rotationY += ry;
302 	return this;
303 };
304 
305 /**
306  * Applies a relative rotation in 3D space around the Z-axis.
307  * @param {Number} rz The value of the rotation
308  * @return {Sprite3D} The reference to this Sprite3D object
309  */
310 Sprite3D.prototype.rotateZ = function(rz) {
311 	this.rotationZ += rz;
312 	return this;
313 };
314 
315 /**
316  * Applies a relative rotation in 3D space.
317  * @param {Number} rx The value of the rotation around the X-axis
318  * @param {Number} ry The value of the rotation around the Y-axis
319  * @param {Number} rz The value of the rotation around the Z-axis
320  * @return {Sprite3D} The reference to this Sprite3D object
321  */
322 Sprite3D.prototype.rotate = function(rx, ry, rz) {
323 	this.rotationX += rx;
324 	this.rotationY += ry;
325 	this.rotationZ += rz;
326 	return this;
327 };
328 
329 /**
330  * Sets the scaling of the Sprite3D object on the X-axis.
331  * @param {Number} sx The value of the scaling on the X-axis
332  * @return {Sprite3D} The reference to this Sprite3D object
333  */
334 Sprite3D.prototype.setScaleX = function( sx ) {
335 	this.scaleX = sx;
336 	return this;
337 };
338 
339 /**
340  * Sets the scaling of the Sprite3D object on the Y-axis.
341  * @param {Number} sy The value of the scaling on the Y-axis
342  * @return {Sprite3D} The reference to this Sprite3D object
343  */
344 Sprite3D.prototype.setScaleY = function( sy ) {
345 	this.scaleY = sy;
346 	return this;
347 };
348 
349 /**
350  * Sets the scaling of the Sprite3D object on the Z-axis.
351  * @param {Number} sz The value of the scaling on the Z-axis
352  * @return {Sprite3D} The reference to this Sprite3D object
353  */
354 Sprite3D.prototype.setScaleZ = function( sz ) {
355 	this.scaleZ = sz;
356 	return this;
357 };
358 
359 /**
360  * Sets the scaling of the Sprite3D object on the 3 axis.
361  * @param {Number} sx The value of the scaling on the X-axis
362  * @param {Number} sy The value of the scaling on the Y-axis
363  * @param {Number} sz The value of the scaling on the Z-axis
364  * @return {Sprite3D} The reference to this Sprite3D object
365  */
366 Sprite3D.prototype.setScale = function( sx, sy, sz ) {
367 	this.scaleX = sx;
368 	this.scaleY = sy;
369 	this.scaleZ = sz;
370 	return this;
371 };
372 
373 /**
374  * Sets the registrations point for the Sprite3D object. 
375  * By default, CSS positionning is relative to the top left corner of the element.
376  * The registration point values are simply substracted from the position when applied
377  * @param {Number} rx The registration point value for the X-axis
378  * @param {Number} ry The registration point value for the Y-axis
379  * @param {Number} rz The registration point value for the Z-axis
380  * @return {Sprite3D} The reference to this Sprite3D object
381  */
382 Sprite3D.prototype.setRegistrationPoint = function(rx, ry, rz) {
383 	this.regX = rx;
384 	this.regY = ry;
385 	this.regZ = rz;
386 	return this;
387 };
388 
389 /**
390  * Sets the origin of the 3D transforms.
391  * By default, CSS transforms are relative to the center of the element.
392  * @param {Number} px The transform origin value for the X-axis
393  * @param {Number} py The transform origin value for the Y-axis
394  * @return {Sprite3D} The reference to this Sprite3D object
395  */
396 Sprite3D.prototype.setTransformOrigin = function(px, py) {
397 //	this.style.webkitTransformOrigin = px + " " + py;
398 	this.style[ this._browserPrefix + "TransformOrigin" ] = px + " " + py;
399 	return this;
400 };
401 
402 
403 /**
404  * Sets the size of the HTML element linked to the Sprite3D object, using the width and height css properties.
405  * Note that animating using these properties does not provide an optimal performance.
406  * You should rather try to use CSS scale using the scale() method
407  * This method applies the changes to the style object, so it does not require a call to the update methods
408  * @param {Number} width The desired width
409  * @param {Number} height The desired height
410  * @return {Sprite3D} The reference to this Sprite3D object
411  */
412 Sprite3D.prototype.setSize = function(width, height) {
413 	this.style.width = (this.width = width) + "px";
414 	this.style.height = (this.height = height) + "px";
415 	return this;
416 };
417 
418 /**
419  * Sets the opacity of the element.
420  * This method applies the changes to the style object, so it does not require a call to the update methods
421  * @param {Number} alpha The desired opacity, ranging from 0 to 1
422  * @return {Sprite3D} The reference to this Sprite3D object
423  */
424 Sprite3D.prototype.setOpacity = function(alpha) {
425 	this.style.opacity = this.alpha = alpha;
426 	return this;
427 };
428 
429 /**
430  * Returns the opacity of the element.
431  * @return {Number} The opacity of the element
432  */
433 Sprite3D.prototype.getOpacity = function() {
434 	return this.alpha;
435 };
436 
437 /**
438  * Sets the CSS class name of the DOM element associated with the Sprite3D object.
439  * When applying multiple class names, provide a single string with space-separated class names like you would do in pure CSS manipulation.
440  * This method does not require a call to the update methods.
441  * @param {String} className The name of the class to be set
442  * @return {Sprite3D} The reference to this Sprite3D object
443  */
444 Sprite3D.prototype.setClassName = function(className) {
445 	this.domElement.className = className;
446 	return this;
447 };
448 
449 /**
450  * Returns the name of the CSS class of the DOM element.
451  * @return {String} The CSS class name
452  */
453 Sprite3D.prototype.getClassName = function() {
454 	return this.domElement.className;
455 };
456 
457 /**
458  * Adds a CSS class to the DOM element
459  * This method does not require a call to the update methods.
460  * @param {String} className The name of the class to be added
461  * @return {Sprite3D} The reference to this Sprite3D object
462  */
463 Sprite3D.prototype.addClassName = function(className) {
464 	this.domElement.className += " " + className + " ";
465 	return this;
466 };
467 
468 /**
469  * [BETA] Removes a CSS class from the DOM element
470  * This method does not require a call to the update methods.
471  * @param {String} className The name of the class to be removed
472  * @return {Sprite3D} The reference to this Sprite3D object
473  */
474 Sprite3D.prototype.removeClassName = function(className) {
475 	this.domElement.className = this.domElement.className.replace(className, '');
476 	//this.domElement.className += " " + className;
477 	return this;
478 };
479 
480 /**
481  * Sets the ID of the DOM element in the document.
482  * This method is just a helper allowing neverending chaining in the Sprite3D creation syntax.
483  * You can also simply access the <code>domElement</code> property of the Sprite3D and set its <code>id</code> property.
484  * This method does not require a call to the update methods.
485  * @param {String} id The ID
486  * @return {Sprite3D} The reference to this Sprite3D object
487  */
488 Sprite3D.prototype.setId = function(id) {
489 	this.domElement.id = id;
490 	return this;
491 };
492 
493 /**
494  * Returns the ID of the DOM element associated with the Sprite3D.
495  * @return {String} The CSS class name
496  */
497 Sprite3D.prototype.getId = function() {
498 	return this.domElement.id;
499 };
500 
501 /**
502  * Allows to set any value in any CSS property of the style object of the DOM element.
503  * This method is just a helper allowing neverending chaining in the Sprite3D creation syntax.
504  * For one time modifications, you can simply use the <code>style</code> property of the Sprite3D.
505  * This method does not require a call to the update methods.
506  * @param {String} name The name of the CSS property in which the value will be stored
507  * @param {String} value The value to assign to the property
508  * @return {Sprite3D} The reference to this Sprite3D object
509  */
510 Sprite3D.prototype.setCSS = function(name, value) {
511 	this.domElement.style[name] = value;
512 	return this;
513 };
514 
515 /**
516  * Returns the value assigned to the provided CSS property.
517  * @param {String} name The name of the property to get the value from
518  * @return {String} The value of the CSS property
519  */
520 Sprite3D.prototype.getCSS = function(name) {
521 	return this.domElement.style[name];
522 };
523 
524 /**
525  * Allows direct write access to the innerHTML property of the DOM element.
526  * @param {String} value The string to write into the innerHTML property
527  * @return {Sprite3D} The reference to this Sprite3D object
528  */
529 Sprite3D.prototype.setInnerHTML = function(value) {
530 	this.domElement.innerHTML = value;
531 	return this;
532 };
533 
534 
535 /**
536  * Sets the size of the tiles in the spritesheet used as background image.
537  * @param {Number} width The desired width
538  * @param {Number} height The desired height
539  * @return {Sprite3D} The reference to this Sprite3D object
540  */
541 Sprite3D.prototype.setTileSize = function(width, height) {
542 	this.tileWidth = width;
543 	this.tileHeight = height;
544 	return this;
545 };
546 
547 /**
548  * Modifies the sprites's background image position to display the selected tile.
549  * For this method to work, you are supposed to set a background image and limit the size of the element using CSS styles,
550  * and use a sprite sheet where all tiles have the same size. No checking is performed on the provided values.
551  * @param {Number} tilePosX The horizontal index of the tile to be displayed
552  * @param {Number} tilePosY The vertical index of the tile to be displayed
553  * @return {Sprite3D} The reference to this Sprite3D object
554  */
555 Sprite3D.prototype.setTilePosition = function(tilePosX, tilePosY) {
556 	this.style.backgroundPosition = "-" + (tilePosX * this.tileWidth) + "px -" + (tilePosY * this.tileHeight) + "px";
557 	return this;
558 };
559 
560 /**
561  * Allows to set a arbitary property value while using the chaining syntax.
562  * @param {String} label The name of the property
563  * @param {Object} value The value for that property
564  * @return {Sprite3D} The reference to this Sprite3D object
565  */
566 Sprite3D.prototype.setProperty = function(label, value) {
567 	this[label] = value;
568 	return this;
569 };
570 
571 /**
572  * Sets the order in which transformations are applied.
573  * If true, rotations are applied before translations. If false, translations are applied before rotations.
574  * Note that, when applying rotations, the axis of the object rotate, and subsequent translations follow the modified orientation of the axis.
575  * For a more accurate control, you should use the transformString property.
576  * @param {boolean} rf true to rotate first, false to translate first
577  * @return {Sprite3D} The reference to this Sprite3D object
578  */
579 Sprite3D.prototype.setRotateFirst = function(rf) {
580 	this.rotateFirst = rf;
581 	if ( rf ) {	
582 		this.transformString = "_rx _ry _rz _p _s";
583 	} else {
584 		this.transformString = "_p _rz _ry _rx _s";
585 	}
586 	return this;
587 };
588 
589 /**
590  * Applies position and rotation values.
591  * @return {Sprite3D} The reference to this Sprite3D object
592  */
593 Sprite3D.prototype.update = function() {
594 	this.p = "translate3d(" + (this.x - this.regX) + "px," + (this.y - this.regY) + "px," + (this.z - this.regZ) + "px) ";
595 	this.rx = "rotateX(" + this.rotationX + "deg) ";
596 	this.ry = "rotateY(" + this.rotationY + "deg) ";
597 	this.rz = "rotateZ(" + this.rotationZ + "deg) ";
598 	this.s = "scale3d(" + this.scaleX + ", " + this.scaleY + ", " + this.scaleX + ") ";
599 	/*
600 	if (this.rotateFirst)
601 		this.style.webkitTransform = this.rz + this.ry + this.rx + this.p + this.s;
602 	else
603 		this.style.webkitTransform = this.p + this.rx + this.ry + this.rz + this.s;
604 	*/
605 
606 	//	var transformString = "_rx _ry _rz _p _s";
607 	this.ts = this.transformString;
608 	this.ts = this.ts.replace( "_p", this.p );
609 	this.ts = this.ts.replace( "_rx", this.rx );
610 	this.ts = this.ts.replace( "_ry", this.ry );
611 	this.ts = this.ts.replace( "_rz", this.rz );
612 	this.ts = this.ts.replace( "_s", this.s );
613 	//this.style.webkitTransform = this.ts;
614 	this.style[this._transformProperty] = this.ts;
615 
616 	return this;
617 };
618 
619 
620 /**
621  * Applies 2D position, rotation and scaling values.
622  * This method allows to use Sprite3D with browsers that only support 2D transforms.
623  * When applying the transforms, it uses the x and y position, z rotation and x and y scaling.
624  * The other values are ignored.
625  * @return {Sprite3D} The reference to this Sprite3D object
626  */
627 Sprite3D.prototype.update2D = function() {
628 	this.p = "translate(" + (this.x - this.regX) + "px," + (this.y - this.regY) + "px) ";
629 	this.rz = "rotate(" + this.rotationZ + "deg) ";
630 	this.s = "scale(" + this.scaleX + ", " + this.scaleY + ") ";
631 
632 	this.ts = this.transformString;
633 	this.ts = this.ts.replace( "_p", this.p );
634 	this.ts = this.ts.replace( "_rx", "" );
635 	this.ts = this.ts.replace( "_ry", "" );
636 	this.ts = this.ts.replace( "_rz", this.rz );
637 	this.ts = this.ts.replace( "_s", this.s );
638 	//this.style.webkitTransform = this.ts;
639 	this.style[this._transformProperty] = this.ts;
640 
641 	//console.log( "apply 2D transforms using " + this._transformProperty );
642 
643 	return this;
644 };
645 
646 
647 /**
648  * Applies position and rotation values, as well as opacity and size.
649  * @return {Sprite3D} The reference to this Sprite3D object
650  */
651 Sprite3D.prototype.updateAll = function() {
652 	this.update();
653 	this.style.opacity = this.alpha;
654 	this.style.width = this.width + "px";
655 	this.style.height = this.height + "px";
656 	return this.update();
657 };
658 
659 
660 /**
661  * Calls the update() method on every child of the Sprite3D object.
662  * @return {Sprite3D} The reference to this Sprite3D object
663  */
664 Sprite3D.prototype.updateChildren = function() {
665 	for (this.i = 0; this.i < this.numChildren; this.i++) {
666 		this.children[this.i].update();
667 	}
668 	return this;
669 };
670 
671 /**
672  * Calls the updateAll() method on every child of the Sprite3D object.
673  * @return {Sprite3D} The reference to this Sprite3D object
674  */
675 Sprite3D.prototype.updateChildrenAll = function() {
676 	for (this.i = 0; this.i < this.numChildren; this.i++) {
677 		this.children[this.i].updateAll();
678 	}
679 	return this;
680 };
681 
682 /**
683  * Updates itself, then calls the update() method on every child of the Sprite3D object.
684  * @param {boolean} recursive If set to true, make the update call recursive, update every child's children
685  * @return {Sprite3D} The reference to this Sprite3D object
686  */
687 Sprite3D.prototype.updateWithChildren = function(recursive) {
688 	this.update();
689 
690 	for (this.i = 0; this.i < this.numChildren; this.i++) {
691 		if (recursive) {
692 			this.children[this.i].updateWithChildren(recursive);
693 		} else {
694 			this.children[this.i].update();
695 		}
696 	}
697 
698 	return this;
699 };
700 
701 /**
702  * Adds a Sprite3D object to this Sprite3D children.
703  * @param {Sprite3D} e The Sprite3D object to add
704  * @return {Sprite3D} The reference to the added Sprite3D object
705  */
706 Sprite3D.prototype.addChild = function(e) {
707 	this.numChildren = this.children.push(e);
708 	this.domElement.appendChild(e.domElement);
709 	return e;
710 };
711 
712 /**
713  * Removes a Sprite3D object from this Sprite3D children.
714  * @param {Sprite3D} child The Sprite3D object to remove
715  * @return {Sprite3D} The reference to the removed Sprite3D object. null if the child was not found in this Sprite3D children list
716  */
717 Sprite3D.prototype.removeChild = function(child) {
718 	var n = this.children.indexOf(child);
719 	if (n > -1) {
720 		return this.removeChildAt(n);
721 	}
722 	return null;
723 };
724 
725 /**
726  * Removes the nth Sprite3D object from this Sprite3D children.
727  * @param {number} n The index of the Sprite3D object to remove
728  * @return {Sprite3D} The reference to the removed Sprite3D object.
729  */
730 Sprite3D.prototype.removeChildAt = function(n) {
731 	--this.numChildren;
732 	this.domElement.removeChild(this.children[n].domElement);
733 	return this.children.splice(n, 1)[0];
734 };
735 
736 /**
737  * Finds and return the Sprite3D object associated with the provided DOM element
738  * @param {Object} element The DOM element
739  * @return {Sprite3D} The reference to the associated Sprite3D object. Returns null if no relevant Sprite3D object was found
740  */
741 Sprite3D.prototype.findFromDOMElement = function(element) {
742 	for (this.i = 0; this.i < this.numChildren; this.i++) {
743 		if (element == this.children[this.i].domElement) { return this.children[this.i]; }
744 	}
745 	return null;
746 };
747 
748 
749 Sprite3D.prototype.listeners = {};
750 
751 /**
752  * Adds an event listener to the DOM element for the provided event id.
753  * @param {String} event The name of the event to watch
754  * @param {Function} callback The callback function
755  * @return {Sprite3D} The reference to this Sprite3D object
756  */
757 Sprite3D.prototype.addEventListener = function(event, callback) {
758 	var fname = event + "_" + callback.name;
759 	if ( this.listeners[fname] == null ) {
760 		var sprite = this;
761 		var fn = function(e) { callback(e, sprite); }
762 		this.listeners[fname] = fn;
763 		this.domElement.addEventListener(event, fn );
764 	}
765 	return this;
766 };
767 
768 /**
769  * Removes an event listener to the DOM element for the provided event id.
770  * @param {String} event The name of the event to watch
771  * @param {Function} callback The callback function
772  * @return {Sprite3D} The reference to this Sprite3D object
773  */
774 Sprite3D.prototype.removeEventListener = function(event, callback) {
775 	var fname = event + "_" + callback.name;
776 	if ( this.listeners[fname] != null ) {
777 		this.domElement.removeEventListener(event, this.listeners[fname] );
778 		delete this.listeners[fname];
779 	}
780 	return this;
781 };
782 
783 
784 /**
785  * Creates a centered empty HTML div element to be used as root container for the other Sprite3D objects.
786  * @return {Sprite3D} The created Sprite3D object
787  */
788 Sprite3D.createCenteredContainer = function() {
789 	var c = document.createElement('div'),
790 		s = c.style;
791 	
792 	if ( !Sprite3D.prototype._isInit ) Sprite3D.isSupported();
793 
794 	s[Sprite3D.prototype._browserPrefix+"Perspective"] = "800" + (Sprite3D.prototype._browserPrefix=="Moz"?"px":"");
795 	s[Sprite3D.prototype._browserPrefix+"PerspectiveOrigin"] = "0 0";
796 	s[Sprite3D.prototype._browserPrefix+"TransformOrigin"] = "0 0";
797 	s[Sprite3D.prototype._browserPrefix+"Transform"] = "translateZ(0px)";
798 
799 	s.position = "absolute";
800 	s.top = "50%";
801 	s.left = "50%";
802 	s.margin = "0px";
803 	s.padding = "0px";
804 	//s.border = "1px solid red"; // <- this one is for debug
805 	document.body.appendChild(c);
806 
807 	return new Sprite3D(c);
808 };
809 
810 /**
811  * Creates a top-left aligned empty HTML div element to be used as root container for the other Sprite3D objects.
812  * @return {Sprite3D} The created Sprite3D object
813  */
814 Sprite3D.createTopLeftCenteredContainer = function() {
815     var c = document.createElement('div'),
816 		s = c.style;
817 		
818 		if ( !Sprite3D.prototype._isInit ) Sprite3D.isSupported();
819 
820 		s[Sprite3D.prototype._browserPrefix+"Perspective"] = "800" + (Sprite3D.prototype._browserPrefix=="Moz"?"px":"");
821 		//s[Sprite3D.prototype._browserPrefix+"PerspectiveOrigin"] = "0 0";
822 		//s[Sprite3D.prototype._browserPrefix+"TransformOrigin"] = "0 0";
823 		s[Sprite3D.prototype._browserPrefix+"Transform"] = "translateZ(0px)";
824 		
825 		
826 		//s.webkitPerspective = "800";
827 		//	s.webkitPerspectiveOrigin = "0 0";
828 		//	s.webkitTransformOrigin = "0 0";
829 		//s.webkitTransform = "translateZ(0px)";
830 		s.position = "relative";
831 		/*
832 		s.position = "absolute";
833 		s.top = "0px";
834 		s.left = "0px";
835 		s.right = "0px"
836 		s.bottom = "0px"
837 		s.margin = "0px";
838 		s.padding = "0px";
839 		s.border = "1px solid red";
840 		*/
841 		/* i left all those comments above because they might be useful in some use cases */
842 		document.body.appendChild(c);
843 
844 		return new Sprite3D(c);
845 };
846 
847 
848 /** Private static property. Used internally for browser checking. You should not change its value. */
849 Sprite3D.prototype._isInit = false;
850 
851 /** Private static property. Used internally for cross-browser compatibility. You should not change its value. */
852 Sprite3D.prototype._transformProperty = "webkitTransform";
853 
854 /** Private static property. Used internally for cross-browser compatibility. You should not change its value. */
855 Sprite3D.prototype._browserPrefix = "webkit";
856 
857 /**
858  * Test for CSS 3D transforms support in the current browser.
859  * If 3D transforms are not supported, the update() method is replaced by the update2D() method,
860  * providing an automatic fallback that might save some bits :)
861  * @return {boolean} True if the 3D transforms are supported by the browser
862  */
863 Sprite3D.isSupported = function() {
864 	var d = document.createElement("div"), 
865 			prefixes = ["", "webkit", "Moz", "o", "ms" ],
866 			n = prefixes.length, i;
867 
868 	// check for 3D transforms
869 	for( i = 0; i < n; i++ ) {
870 		if ( ( prefixes[i] + "Perspective" ) in d.style ) {
871 			Sprite3D.prototype._transformProperty = prefixes[i] + "Transform";
872 			Sprite3D.prototype._isInit = true;
873 			Sprite3D.prototype._browserPrefix = prefixes[i];
874 			//console.log( "found support for 3D transforms using prefix: " + prefixes[i] );
875 			return true;
876 		}
877 	}
878 
879 	// check for 2D transforms
880 	for( i = 0; i < n; i++ ) {
881 		if ( ( prefixes[i] + "Transform" ) in d.style ) {
882 			Sprite3D.prototype._transformProperty = prefixes[i] + "Transform";
883 			Sprite3D.prototype._isInit = true;
884 			Sprite3D.prototype._browserPrefix = prefixes[i];
885 			Sprite3D.prototype.update = Sprite3D.prototype.update2D;
886 			//console.log( "found support for 2D transforms using prefix: " + prefixes[i] );
887 			return false;
888 		}
889 	}
890 	//console.log( "no support for CSS transforms.");
891 	return false;
892 };
893