1 /****************************************************************************
  2  Copyright (c) 2010-2012 cocos2d-x.org
  3  Copyright (c) 2008-2010 Ricardo Quesada
  4  Copyright (c) 2011      Zynga Inc.
  5 
  6  http://www.cocos2d-x.org
  7 
  8  Permission is hereby granted, free of charge, to any person obtaining a copy
  9  of this software and associated documentation files (the "Software"), to deal
 10  in the Software without restriction, including without limitation the rights
 11  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 12  copies of the Software, and to permit persons to whom the Software is
 13  furnished to do so, subject to the following conditions:
 14 
 15  The above copyright notice and this permission notice shall be included in
 16  all copies or substantial portions of the Software.
 17 
 18  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 19  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 20  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 21  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 22  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 23  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 24  THE SOFTWARE.
 25  ****************************************************************************/
 26 
 27 /** Layer will receive all the touches at once The onTouchesXXX API will be called
 28  */
 29 cc.TOUCH_ALL_AT_ONCE = 0;
 30 
 31 /** Layer will receive only one touch at the time. The onTouchXXX API will be called */
 32 cc.TOUCH_ONE_BY_ONE = 1;
 33 
 34 /** cc.Layer is a subclass of cc.Node that implements the TouchEventsDelegate protocol.<br/>
 35  * All features from cc.Node are valid, plus the following new features:<br/>
 36  * It can receive iPhone Touches<br/>
 37  * It can receive Accelerometer input
 38  * @class
 39  * @extends cc.Node
 40  */
 41 cc.Layer = cc.Node.extend(/** @lends cc.Layer# */{
 42     _isTouchEnabled:false,
 43     _isAccelerometerEnabled:false,
 44     _isKeyboardEnabled:false,
 45     _touchPriority:0,
 46     _touchMode:cc.TOUCH_ALL_AT_ONCE,
 47     _isMouseEnabled:false,
 48     _mousePriority:0,
 49 
 50     /**
 51      * Constructor
 52      */
 53     ctor:function () {
 54         this._super();
 55 
 56         //this._initLayer();
 57     },
 58 
 59     _initLayer:function () {
 60         this.setAnchorPoint(cc.p(0.5, 0.5));
 61         this._ignoreAnchorPointForPosition = true;
 62 
 63         var director = cc.Director.getInstance();
 64         this.setContentSize(director.getWinSize());
 65         this._isTouchEnabled = false;
 66         this._isAccelerometerEnabled = false;
 67         this._isMouseEnabled = false;
 68         this._touchMode = cc.TOUCH_ALL_AT_ONCE;
 69         this._touchPriority = 0;
 70     },
 71 
 72     /**
 73      *
 74      * @return {Boolean}
 75      */
 76     init:function () {
 77         /*var director = cc.Director.getInstance();
 78          if (!director) {
 79          return false;
 80          }
 81          this.setContentSize(director.getWinSize());
 82          this._isTouchEnabled = false;*/
 83         this._super();
 84         this._initLayer();
 85         return true;
 86     },
 87 
 88     /**
 89      * If isTouchEnabled, this method is called onEnter.
 90      */
 91     registerWithTouchDispatcher:function () {
 92         if (this._touchMode === cc.TOUCH_ALL_AT_ONCE)
 93             cc.Director.getInstance().getTouchDispatcher().addStandardDelegate(this, this._touchPriority);
 94         else
 95             cc.Director.getInstance().getTouchDispatcher().addTargetedDelegate(this, this._touchPriority, true);
 96     },
 97 
 98     isMouseEnabled:function () {
 99         return this._isMouseEnabled;
100     },
101 
102     setMouseEnabled:function (enabled) {
103         if (this._isMouseEnabled != enabled) {
104             this._isMouseEnabled = enabled;
105             if (this._running) {
106                 if (enabled)
107                     cc.Director.getInstance().getMouseDispatcher().addMouseDelegate(this, this._mousePriority);
108                 else
109                     cc.Director.getInstance().getMouseDispatcher().removeMouseDelegate(this);
110             }
111         }
112     },
113 
114     setMousePriority:function (priority) {
115         if (this._mousePriority != priority) {
116             this._mousePriority = priority;
117             // Update touch priority with handler
118             if (this._isMouseEnabled) {
119                 this.setMouseEnabled(false);
120                 this.setMouseEnabled(true);
121             }
122         }
123     },
124 
125     getMousePriority:function () {
126         return this._mousePriority;
127     },
128 
129     /**
130      * whether or not it will receive Touch events.<br/>
131      * You can enable / disable touch events with this property.<br/>
132      * Only the touches of this node will be affected. This "method" is not propagated to it's children.<br/>
133      * @return {Boolean}
134      */
135     isTouchEnabled:function () {
136         return this._isTouchEnabled;
137     },
138 
139     /**
140      * Enable touch events
141      * @param {Boolean} enabled
142      */
143     setTouchEnabled:function (enabled) {
144         if (this._isTouchEnabled != enabled) {
145             this._isTouchEnabled = enabled;
146 
147             if (this._running) {
148                 if (enabled) {
149                     this.registerWithTouchDispatcher();
150                 } else {
151                     // have problems?
152                     cc.Director.getInstance().getTouchDispatcher().removeDelegate(this);
153                 }
154             }
155         }
156     },
157 
158     /** returns the priority of the touch event handler
159      * @return {Number}
160      */
161     getTouchPriority:function () {
162         return this._touchPriority;
163     },
164 
165     /** Sets the touch event handler priority. Default is 0.
166      * @param {Number} priority
167      */
168     setTouchPriority:function (priority) {
169         if (this._touchPriority != priority) {
170             this._touchPriority = priority;
171             // Update touch priority with handler
172             if (this._isTouchEnabled) {
173                 this.setTouchEnabled(false);
174                 this.setTouchEnabled(true);
175             }
176         }
177     },
178 
179     /** returns the touch mode.
180      * @return {Number}
181      */
182     getTouchMode:function () {
183         return this._touchMode;
184     },
185 
186     /** Sets the touch mode.
187      * @param {Number} mode
188      */
189     setTouchMode:function (mode) {
190         if (this._touchMode != mode) {
191             this._touchMode = mode;
192             // update the mode with handler
193             if (this._isTouchEnabled) {
194                 this.setTouchEnabled(false);
195                 this.setTouchEnabled(true);
196             }
197         }
198     },
199 
200     /**
201      * whether or not it will receive Accelerometer events<br/>
202      * You can enable / disable accelerometer events with this property.
203      * @return {Boolean}
204      */
205     isAccelerometerEnabled:function () {
206         return this._isAccelerometerEnabled;
207     },
208 
209     /**
210      * isAccelerometerEnabled setter
211      * @param enabled
212      */
213     setAccelerometerEnabled:function (enabled) {
214         if (enabled != this._isAccelerometerEnabled) {
215             this._isAccelerometerEnabled = enabled;
216 
217             if (this._running) {
218                 var director = cc.Director.getInstance();
219                 if (enabled) {
220                     director.getAccelerometer().setDelegate(this);
221                 } else {
222                     director.getAccelerometer().setDelegate(null);
223                 }
224             }
225         }
226     },
227 
228     /**
229      * whether or not it will receive keyboard events<br/>
230      * You can enable / disable accelerometer events with this property.<br/>
231      * it's new in cocos2d-x
232      * @return {Boolean}
233      */
234     isKeyboardEnabled:function () {
235         return this._isKeyboardEnabled;
236     },
237 
238     /**
239      * Enable Keyboard interaction
240      * @param {Boolean} enabled
241      */
242     setKeyboardEnabled:function (enabled) {
243         if (enabled != this._isKeyboardEnabled) {
244             this._isKeyboardEnabled = enabled;
245             if (this._running) {
246                 var director = cc.Director.getInstance();
247                 if (enabled) {
248                     director.getKeyboardDispatcher().addDelegate(this);
249                 } else {
250                     director.getKeyboardDispatcher().removeDelegate(this);
251                 }
252             }
253         }
254     },
255 
256     /**
257      * This is run when ever a layer just become visible
258      */
259     onEnter:function () {
260         var director = cc.Director.getInstance();
261         // register 'parent' nodes first
262         // since events are propagated in reverse order
263         if (this._isTouchEnabled) {
264             this.registerWithTouchDispatcher();
265         }
266 
267         // then iterate over all the children
268         this._super();
269 
270         //TODO not supported
271         // add this layer to concern the Accelerometer Sensor
272 /*        if (this._isAccelerometerEnabled){
273            director.getAccelerometer().setDelegate(this);
274         }*/
275 
276 
277         // add this layer to concern the kaypad msg
278         if (this._isKeyboardEnabled)
279             director.getKeyboardDispatcher().addDelegate(this);
280 
281         if (this._isMouseEnabled)
282             director.getMouseDispatcher().addMouseDelegate(this, this._mousePriority);
283     },
284 
285     /**
286      * @function
287      */
288     onExit:function () {
289         var director = cc.Director.getInstance();
290         if (this._isTouchEnabled) {
291             director.getTouchDispatcher().removeDelegate(this);
292         }
293 
294         // remove this layer from the delegates who concern Accelerometer Sensor
295         //TODO not supported
296 /*        if (this._isAccelerometerEnabled) {
297             director.getAccelerometer().setDelegate(null);
298         }*/
299 
300         // remove this layer from the delegates who concern the kaypad msg
301         if (this._isKeyboardEnabled) {
302             director.getKeyboardDispatcher().removeDelegate(this);
303         }
304 
305         if (this._isMouseEnabled)
306             director.getMouseDispatcher().removeMouseDelegate(this);
307 
308         this._super();
309     },
310 
311     /**
312      * this is called when ever a layer is a child of a scene that just finished a transition
313      */
314     onEnterTransitionDidFinish:function () {
315         //TODO not supported
316         /*if (this._isAccelerometerEnabled) {
317             cc.Director.getInstance().getAccelerometer().setDelegate(this);
318         }*/
319         this._super();
320     },
321 
322     /**
323      * default implements are used to call script callback if exist<br/>
324      * you must override these touch functions if you wish to utilize them
325      * @param {cc.Touch} touch
326      * @param {event} event
327      * @return {Boolean}
328      */
329     onTouchBegan:function (touch, event) {
330         cc.Assert(false, "Layer#onTouchBegan override me");
331         return true;
332     },
333 
334     /**
335      * callback when a touch event moved
336      * @param {cc.Touch} touch
337      * @param {event} event
338      */
339     onTouchMoved:function (touch, event) {
340     },
341 
342     /**
343      * callback when a touch event finished
344      * @param {cc.Touch} touch
345      * @param {event} event
346      */
347     onTouchEnded:function (touch, event) {
348     },
349 
350     /**
351      * @param {cc.Touch} touch
352      * @param {event} event
353      */
354     onTouchCancelled:function (touch, event) {
355     },
356 
357     /**
358      * Touches is the same as Touch, except this one can handle multi-touch
359      * @param {cc.Touch} touch
360      * @param {event} event
361      */
362     onTouchesBegan:function (touch, event) {
363     },
364 
365     /**
366      * when a touch moved
367      * @param {cc.Touch} touch
368      * @param {event} event
369      */
370     onTouchesMoved:function (touch, event) {
371     },
372 
373     /**
374      * when a touch finished
375      * @param {cc.Touch} touch
376      * @param {event} event
377      */
378     onTouchesEnded:function (touch, event) {
379     },
380 
381     /**
382      * @param touch
383      * @param event
384      */
385     onTouchesCancelled:function (touch, event) {
386     },
387 
388     didAccelerate:function (pAccelerationValue) {
389     },
390 
391     // ---------------------CCMouseEventDelegate interface------------------------------
392 
393     /**
394      * <p>called when the "mouseDown" event is received. <br/>
395      * Return YES to avoid propagating the event to other delegates.  </p>
396      * @param event
397      * @return {Boolean}
398      */
399     onMouseDown:function (event) {
400         return false;
401     },
402 
403     /**
404      * <p>called when the "mouseDragged" event is received.         <br/>
405      * Return YES to avoid propagating the event to other delegates.</p>
406      * @param event
407      * @return {Boolean}
408      */
409     onMouseDragged:function (event) {
410         return false;
411     },
412 
413     /**
414      * <p> called when the "mouseMoved" event is received.            <br/>
415      * Return YES to avoid propagating the event to other delegates.  </p>
416      * @param event
417      * @return {Boolean}
418      */
419     onMouseMoved:function (event) {
420         return false;
421     },
422 
423     /**
424      * <p> called when the "mouseUp" event is received.               <br/>
425      * Return YES to avoid propagating the event to other delegates.  </p>
426      * @param event
427      * @return {Boolean}
428      */
429     onMouseUp:function (event) {
430         return false;
431     },
432 
433     //right
434     /**
435      * <p> called when the "rightMouseDown" event is received.        <br/>
436      * Return YES to avoid propagating the event to other delegates.  </p>
437      * @param event
438      * @return {Boolean}
439      */
440     onRightMouseDown:function (event) {
441         return false;
442     },
443 
444     /**
445      * <p> called when the "rightMouseDragged" event is received.    <br/>
446      * Return YES to avoid propagating the event to other delegates. </p>
447      * @param event
448      * @return {Boolean}
449      */
450     onRightMouseDragged:function (event) {
451         return false;
452     },
453 
454     /**
455      * <p> called when the "rightMouseUp" event is received.          <br/>
456      * Return YES to avoid propagating the event to other delegates.  </p>
457      * @param event
458      * @return {Boolean}
459      */
460     onRightMouseUp:function (event) {
461         return false;
462     },
463 
464     //other
465     /**
466      * <p>called when the "otherMouseDown" event is received.         <br/>
467      * Return YES to avoid propagating the event to other delegates.  </p>
468      * @param event
469      * @return {Boolean}
470      */
471     onOtherMouseDown:function (event) {
472         return false;
473     },
474 
475     /**
476      * <p> called when the "otherMouseDragged" event is received.     <br/>
477      * Return YES to avoid propagating the event to other delegates.  </p>
478      * @param event
479      * @return {Boolean}
480      */
481     onOtherMouseDragged:function (event) {
482         return false;
483     },
484 
485     /**
486      * <p> called when the "otherMouseUp" event is received.          <br/>
487      * Return YES to avoid propagating the event to other delegates.  </p>
488      * @param event
489      * @return {Boolean}
490      */
491     onOtherMouseUp:function (event) {
492         return false;
493     },
494 
495     //scroll wheel
496     /**
497      * <p> called when the "scrollWheel" event is received.           <br/>
498      * Return YES to avoid propagating the event to other delegates.  </p>
499      * @param event
500      * @return {Boolean}
501      */
502     onScrollWheel:function (event) {
503         return false;
504     },
505 
506     // enter / exit
507     /**
508      *  <p> called when the "mouseEntered" event is received.         <br/>
509      *  Return YES to avoid propagating the event to other delegates. </p>
510      * @param theEvent
511      * @return {Boolean}
512      */
513     onMouseEntered:function (theEvent) {
514         return false;
515     },
516 
517     /**
518      * <p> called when the "mouseExited" event is received.          <br/>
519      * Return YES to avoid propagating the event to other delegates. </p>
520      * @param theEvent
521      * @return {Boolean}
522      */
523     onMouseExited:function (theEvent) {
524         return false;
525     }
526 });
527 
528 /**
529  * creates a layer
530  * @example
531  * // Example
532  * var myLayer = cc.Layer.create();
533  * //Yes! it's that simple
534  * @return {cc.Layer|Null}
535  */
536 cc.Layer.create = function () {
537     var ret = new cc.Layer();
538     if (ret && ret.init()) {
539         return ret;
540     }
541     return null;
542 };
543 
544 
545 /**
546  * CCLayerColor is a subclass of CCLayer that implements the CCRGBAProtocol protocol.<br/>
547  *  All features from CCLayer are valid, plus the following new features:<br/>
548  * <ul><li>opacity</li>
549  * <li>RGB colors</li></ul>
550  * @class
551  * @extends cc.Layer
552  */
553 cc.LayerColor = cc.Layer.extend(/** @lends cc.LayerColor# */{
554     RGBAProtocol:true,
555     _squareVertices:[],
556     _squareColors:[],
557     _opacity:0,
558     _color:new cc.Color3B(255, 255, 255),
559     _blendFunc:new cc.BlendFunc(cc.BLEND_SRC, cc.BLEND_DST),
560     _layerColorStr:null,
561 
562     /**
563      * Constructor
564      */
565     ctor:function () {
566         this._squareVertices = [new cc.Vertex2F(0, 0), new cc.Vertex2F(0, 0), new cc.Vertex2F(0, 0), new cc.Vertex2F(0, 0)];
567         this._squareColors = [new cc.Color4F(0, 0, 0, 1), new cc.Color4F(0, 0, 0, 1), new cc.Color4F(0, 0, 0, 1), new cc.Color4F(0, 0, 0, 1)];
568         this._color = new cc.Color4B(0, 0, 0, 0);
569         this._opacity = 255;
570         this._super();
571         this._layerColorStr = this._getLayerColorString();
572     },
573 
574     _getLayerColorString:function () {
575         return "rgba(" + (0 | this._color.r) + "," + (0 | this._color.g) + "," + (0 | this._color.b) + "," + (this.getOpacity() / 255).toFixed(5) + ")";
576     },
577 
578     /**
579      * opacity getter
580      * @return {Number}
581      */
582     getOpacity:function () {
583         return this._opacity;
584     },
585 
586     /**
587      * opacity setter
588      * @param {Number} Var a number between 0 and 255, 0 is totally transparent
589      */
590     setOpacity:function (Var) {
591         this._opacity = Var;
592         this._updateColor();
593         this.setNodeDirty();
594     },
595 
596     /**
597      * color getter
598      * @return {cc.Color3B}
599      */
600     getColor:function () {
601         return this._color;
602     },
603 
604     /**
605      * color setter
606      * @param {cc.Color3B} Var
607      */
608     setColor:function (Var) {
609         this._color = Var;
610         this._updateColor();
611         this.setNodeDirty();
612     },
613 
614     /**
615      * blendFunc getter
616      * @return {cc.BlendFunc}
617      */
618     getBlendFunc:function () {
619         return this._blendFunc;
620     },
621 
622     _isLighterMode:false,
623     /**
624      * blendFunc setter
625      * @param {Number} src
626      * @param {Number} dst
627      */
628     setBlendFunc:function (src, dst) {
629         if (arguments.length == 1) {
630             this._blendFunc = src;
631         } else {
632             this._blendFunc = {src:src, dst:dst};
633         }
634         this._isLighterMode = (this._blendFunc && (this._blendFunc.src == 1) && (this._blendFunc.dst == 771));
635     },
636 
637     /**
638      * @param color
639      * @return {Boolean}
640      */
641     init:function (color, width, height) {
642         this._initLayer();
643 
644         var winSize = cc.Director.getInstance().getWinSize();
645 
646         color = color || new cc.Color4B(0, 0, 0, 255);
647         width = width || winSize.width;
648         height = height || winSize.height;
649 
650         this._blendFunc.src = cc.BLEND_SRC;
651         this._blendFunc.dst = cc.BLEND_DST;
652 
653         this._color = new cc.Color3B(color.r, color.g, color.b);
654         this._opacity = color.a;
655 
656         for (var i = 0; i < this._squareVertices.length; i++) {
657             this._squareVertices[i].x = 0.0;
658             this._squareVertices[i].y = 0.0;
659         }
660 
661         this.setContentSize(cc.size(width, height));
662 
663         this._updateColor();
664         //this.setShaderProgram(cc.ShaderCache.getInstance().programForKey(kCCShader_PositionColor));
665 
666         return true;
667     },
668 
669     /**
670      * override contentSize
671      * @param {cc.Size} size
672      */
673     setContentSize:function (size) {
674         this._squareVertices[1].x = size.width;
675         this._squareVertices[2].y = size.height;
676         this._squareVertices[3].x = size.width;
677         this._squareVertices[3].y = size.height;
678         this._super(size);
679     },
680 
681     /**
682      * change width and height in Points
683      * @param {Number} w width
684      * @param {Number} h height
685      */
686     changeWidthAndHeight:function (w, h) {
687         this.setContentSize(cc.size(w, h));
688     },
689 
690     /**
691      * change width in Points
692      * @param {Number} w width
693      */
694     changeWidth:function (w) {
695         this.setContentSize(cc.size(w, this._contentSize.height));
696     },
697 
698     /**
699      * change height in Points
700      * @param {Number} h height
701      */
702     changeHeight:function (h) {
703         this.setContentSize(cc.size(this._contentSize.width, h));
704     },
705 
706     _updateColor:function () {
707         for (var i = 0; i < 4; i++) {
708             this._squareColors[i].r = this._color.r / 255;
709             this._squareColors[i].g = this._color.g / 255;
710             this._squareColors[i].b = this._color.b / 255;
711             this._squareColors[i].a = this._opacity / 255;
712         }
713     },
714 
715     /**
716      * set OpacityModifyRGB of cc.LayerColor
717      * @param {Boolean}  value
718      */
719     setOpacityModifyRGB:function (value) {
720     },
721 
722     /**
723      * is OpacityModifyRGB
724      * @return {Boolean}
725      */
726     isOpacityModifyRGB:function () {
727         return false;
728     },
729 
730     /**
731      * renders the layer
732      * @param {CanvasContext|Null} ctx
733      */
734     draw:function (ctx) {
735         var context = ctx || cc.renderContext;
736 
737         var tWidth = this.getContentSize().width;
738         var tHeight = this.getContentSize().height;
739         var apip = this.getAnchorPointInPoints();
740 
741         context.fillStyle = "rgba(" + (0 | this._color.r) + "," + (0 | this._color.g) + "," + (0 | this._color.b) + "," + this.getOpacity() / 255 + ")";
742         context.fillRect(-apip.x, apip.y, tWidth, -tHeight);
743 
744         cc.INCREMENT_GL_DRAWS(1);
745     },
746 
747     _drawForWebGL:function (ctx) {
748         /*cc.NODE_DRAW_SETUP();
749          ccGLEnableVertexAttribs( kCCVertexAttribFlag_Position | kCCVertexAttribFlag_Color );
750 
751          //
752          // Attributes
753          //
754          glVertexAttribPointer(kCCVertexAttrib_Position, 2, GL_FLOAT, GL_FALSE, 0, m_pSquareVertices);
755          glVertexAttribPointer(kCCVertexAttrib_Color, 4, GL_FLOAT, GL_FALSE, 0, m_pSquareColors);
756          ccGLBlendFunc( m_tBlendFunc.src, m_tBlendFunc.dst );
757          glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);   */
758     }
759 });
760 
761 /**
762  * creates a cc.Layer with color, width and height in Points
763  * @param {cc.Color4B} color
764  * @param {Number|Null} width
765  * @param {Number|Null} height
766  * @return {cc.LayerColor}
767  * @example
768  * // Example
769  * //Create a yellow color layer as background
770  * var yellowBackground = cc.LayerColor.create(cc.c4b(255,255,0,255));
771  * //If you didnt pass in width and height, it defaults to the same size as the canvas
772  *
773  * //create a yellow box, 200 by 200 in size
774  * var yellowBox = cc.LayerColor.create(cc.c3b(255,255,0,255), 200, 200);
775  */
776 cc.LayerColor.create = function (color, width, height) {
777     var ret = new cc.LayerColor();
778     switch (arguments.length) {
779         case 0:
780             ret.init();
781             break;
782         case 1:
783             ret.init(color);
784             break;
785         case 3:
786             ret.init(color, width, height);
787             break;
788         default :
789             ret.init();
790             break;
791     }
792     return ret;
793 };
794 
795 
796 /**
797  * CCLayerGradient is a subclass of cc.LayerColor that draws gradients across<br/>
798  * the background.<br/>
799  *<br/>
800  * All features from cc.LayerColor are valid, plus the following new features:<br/>
801  * <ul><li>direction</li>
802  * <li>final color</li>
803  * <li>interpolation mode</li></ul>
804  * <br/>
805  * Color is interpolated between the startColor and endColor along the given<br/>
806  * vector (starting at the origin, ending at the terminus).  If no vector is<br/>
807  * supplied, it defaults to (0, -1) -- a fade from top to bottom.<br/>
808  * <br/>
809  * If 'compressedInterpolation' is disabled, you will not see either the start or end color for<br/>
810  * non-cardinal vectors; a smooth gradient implying both end points will be still<br/>
811  * be drawn, however.<br/>
812  *<br/>
813  * If ' compressedInterpolation' is enabled (default mode) you will see both the start and end colors of the gradient.
814  * @class
815  * @extends cc.LayerColor
816  */
817 cc.LayerGradient = cc.LayerColor.extend(/** @lends cc.LayerGradient# */{
818     _startColor:null,
819     _endColor:null,
820     _startOpacity:null,
821     _endOpacity:null,
822     _alongVector:null,
823     _compressedInterpolation:false,
824 
825     _gradientStartPoint:null,
826     _gradientEndPoint:null,
827 
828     /**
829      * Constructor
830      * @function
831      */
832     ctor:function () {
833         this._super();
834 
835         this._color = new cc.Color3B(0, 0, 0);
836         this._startColor = new cc.Color3B(0, 0, 0);
837         this._endColor = new cc.Color3B(0, 0, 0);
838         this._alongVector = cc.p(0, -1);
839         this._startOpacity = 255;
840         this._endOpacity = 255;
841 
842         this._gradientStartPoint = cc.p(0, 0);
843         this._gradientEndPoint = cc.p(0, 0);
844     },
845 
846     /**
847      * get the starting color
848      * @return {cc.Color3B}
849      */
850     getStartColor:function () {
851         return this._color;
852     },
853 
854     /**
855      * set the starting color
856      * @param {cc.Color3B} color
857      * @example
858      * // Example
859      * myGradientLayer.setStartColor(cc.c3b(255,0,0));
860      * //set the starting gradient to red
861      */
862     setStartColor:function (color) {
863         this.setColor(color);
864     },
865 
866     /**
867      * set the end gradient color
868      * @param {cc.Color3B} color
869      * @example
870      * // Example
871      * myGradientLayer.setEndColor(cc.c3b(255,0,0));
872      * //set the ending gradient to red
873      */
874     setEndColor:function (color) {
875         this._endColor = color;
876         this._updateColor();
877     },
878 
879     /**
880      * get the end color
881      * @return {cc.Color3B}
882      */
883     getEndColor:function () {
884         return this._endColor;
885     },
886 
887     /**
888      * set starting gradient opacity
889      * @param {Number} o from 0 to 255, 0 is transparent
890      */
891     setStartOpacity:function (o) {
892         this._startOpacity = o;
893         this._updateColor();
894     },
895 
896     /**
897      * get the starting gradient opacity
898      * @return {Number}
899      */
900     getStartOpacity:function () {
901         return this._startOpacity;
902     },
903 
904     /**
905      * set the end gradient opacity
906      * @param {Number} o
907      */
908     setEndOpacity:function (o) {
909         this._endOpacity = o;
910         this._updateColor();
911     },
912 
913     /**
914      * get the end gradient opacity
915      * @return {Number}
916      */
917     getEndOpacity:function () {
918         return this._endOpacity;
919     },
920 
921     /**
922      * set vector
923      * @param {cc.Point} Var
924      */
925     setVector:function (Var) {
926         this._alongVector = Var;
927         this._updateColor();
928     },
929 
930     /**
931      * @return {cc.Point}
932      */
933     getVector:function () {
934         return this._alongVector;
935     },
936 
937     /** is Compressed Interpolation
938      * @return {Boolean}
939      */
940     isCompressedInterpolation:function () {
941         return this._compressedInterpolation;
942     },
943 
944     /**
945      * @param {Boolean} compress
946      */
947     setCompressedInterpolation:function (compress) {
948         this._compressedInterpolation = compress;
949         this._updateColor();
950     },
951 
952     /**
953      * @param {cc.Color3B} start starting color
954      * @param {cc.Color3B} end
955      * @param {cc.Point|Null} v
956      * @return {Boolean}
957      */
958     init:function (start, end, v) {
959         var argnum = arguments.length;
960 
961         if (argnum == 0)
962             return this._super();
963 
964         if (argnum == 2) {
965             // Initializes the CCLayer with a gradient between start and end.
966             v = cc.p(0, -1);
967         }
968 
969         // Initializes the CCLayer with a gradient between start and end in the direction of v.
970         this._startColor.r = start.r;
971         this._startColor.g = start.g;
972         this._startColor.b = start.b;
973         this._startOpacity = start.a;
974 
975         this._endColor.r = end.r;
976         this._endColor.g = end.g;
977         this._endColor.b = end.b;
978         this._endOpacity = end.a;
979 
980         this._alongVector = v;
981 
982         this._compressedInterpolation = true;
983 
984         this._super(cc.c4b(start.r, start.g, start.b, 255));
985         return true;
986     },
987 
988     _updateColor:function () {
989         if (cc.renderContextType === cc.CANVAS) {
990             var tWidth = this.getContentSize().width / 2;
991             var tHeight = this.getContentSize().height / 2;
992             var apip = this.getAnchorPointInPoints();
993             var offWidth = tWidth - apip.x;
994             var offHeight = tHeight - apip.y;
995 
996             this._gradientStartPoint = cc.p(tWidth * -this._alongVector.x + offWidth, tHeight * this._alongVector.y - offHeight);
997             this._gradientEndPoint = cc.p(tWidth * this._alongVector.x + offWidth, tHeight * -this._alongVector.y - offHeight);
998         } else {
999             //todo need fixed for webGL
1000             this._super();
1001 
1002             var h = cc.pLength(this._alongVector);
1003             if (h == 0)
1004                 return;
1005 
1006             var c = Math.sqrt(2.0);
1007             var u = cc.p(this._alongVector.x / h, this._alongVector.y / h);
1008 
1009             // Compressed Interpolation mode
1010             if (this._compressedInterpolation) {
1011                 var h2 = 1 / ( Math.abs(u.x) + Math.abs(u.y) );
1012                 u = cc.pMult(u, h2 * c);
1013             }
1014 
1015             var opacityf = this._opacity / 255.0;
1016 
1017             var S = new cc.Color4F(this._color.r / 255, this._color.g / 255, this._color.b / 255, (this._startOpacity * opacityf) / 255);
1018 
1019             var E = new cc.Color4F(this._endColor.r / 255, this._endColor.g / 255, this._endColor.b / 255, (this._endOpacity * opacityf) / 255);
1020 
1021             // (-1, -1)
1022             this._squareColors[0].r = ((E.r + (S.r - E.r) * ((c + u.x + u.y) / (2.0 * c))));
1023             this._squareColors[0].g = ((E.g + (S.g - E.g) * ((c + u.x + u.y) / (2.0 * c))));
1024             this._squareColors[0].b = ((E.b + (S.b - E.b) * ((c + u.x + u.y) / (2.0 * c))));
1025             this._squareColors[0].a = ((E.a + (S.a - E.a) * ((c + u.x + u.y) / (2.0 * c))));
1026             // (1, -1)
1027             this._squareColors[1].r = ((E.r + (S.r - E.r) * ((c - u.x + u.y) / (2.0 * c))));
1028             this._squareColors[1].g = ((E.g + (S.g - E.g) * ((c - u.x + u.y) / (2.0 * c))));
1029             this._squareColors[1].b = ((E.b + (S.b - E.b) * ((c - u.x + u.y) / (2.0 * c))));
1030             this._squareColors[1].a = ((E.a + (S.a - E.a) * ((c - u.x + u.y) / (2.0 * c))));
1031             // (-1, 1)
1032             this._squareColors[2].r = ((E.r + (S.r - E.r) * ((c + u.x - u.y) / (2.0 * c))));
1033             this._squareColors[2].g = ((E.g + (S.g - E.g) * ((c + u.x - u.y) / (2.0 * c))));
1034             this._squareColors[2].b = ((E.b + (S.b - E.b) * ((c + u.x - u.y) / (2.0 * c))));
1035             this._squareColors[2].a = ((E.a + (S.a - E.a) * ((c + u.x - u.y) / (2.0 * c))));
1036             // (1, 1)
1037             this._squareColors[3].r = ((E.r + (S.r - E.r) * ((c - u.x - u.y) / (2.0 * c))));
1038             this._squareColors[3].g = ((E.g + (S.g - E.g) * ((c - u.x - u.y) / (2.0 * c))));
1039             this._squareColors[3].b = ((E.b + (S.b - E.b) * ((c - u.x - u.y) / (2.0 * c))));
1040             this._squareColors[3].a = ((E.a + (S.a - E.a) * ((c - u.x - u.y) / (2.0 * c))));
1041         }
1042     },
1043 
1044     draw:function (ctx) {
1045         var context = ctx || cc.renderContext;
1046         if (cc.renderContextType == cc.CANVAS) {
1047             if (this._isLighterMode)
1048                 context.globalCompositeOperation = 'lighter';
1049 
1050             context.save();
1051             var tWidth = this.getContentSize().width;
1052             var tHeight = this.getContentSize().height;
1053             var apip = this.getAnchorPointInPoints();
1054             var tGradient = context.createLinearGradient(this._gradientStartPoint.x, this._gradientStartPoint.y,
1055                 this._gradientEndPoint.x, this._gradientEndPoint.y);
1056             tGradient.addColorStop(0, "rgba(" + Math.round(this._color.r) + "," + Math.round(this._color.g) + ","
1057                 + Math.round(this._color.b) + "," + (this._startOpacity / 255).toFixed(4) + ")");
1058             tGradient.addColorStop(1, "rgba(" + Math.round(this._endColor.r) + "," + Math.round(this._endColor.g) + ","
1059                 + Math.round(this._endColor.b) + "," + (this._endOpacity / 255).toFixed(4) + ")");
1060             context.fillStyle = tGradient;
1061             context.fillRect(-apip.x, apip.y, tWidth, -tHeight);
1062 
1063             if (this._rotation != 0)
1064                 context.rotate(this._rotationRadians);
1065             context.restore();
1066         }
1067     }
1068 });
1069 
1070 /**
1071  * creates a gradient layer
1072  * @param {cc.Color3B} start starting color
1073  * @param {cc.Color3B} end ending color
1074  * @param {cc.Point|Null} v
1075  * @return {cc.LayerGradient}
1076  */
1077 cc.LayerGradient.create = function (start, end, v) {
1078     var layer = new cc.LayerGradient();
1079     switch (arguments.length) {
1080         case 2:
1081             /** Creates a full-screen CCLayer with a gradient between start and end. */
1082             if (layer && layer.init(start, end)) {
1083                 return layer;
1084             }
1085             break;
1086         case 3:
1087             /** Creates a full-screen CCLayer with a gradient between start and end in the direction of v. */
1088             if (layer && layer.init(start, end, v)) {
1089                 return layer;
1090             }
1091             break;
1092         case 0:
1093             if (layer && layer.init()) {
1094                 return layer;
1095             }
1096             break;
1097         default:
1098             throw "Arguments error ";
1099             break;
1100     }
1101     return null;
1102 };
1103 
1104 
1105 /**
1106  * CCMultipleLayer is a CCLayer with the ability to multiplex it's children.<br/>
1107  * Features:<br/>
1108  *  <ul><li>- It supports one or more children</li>
1109  *  <li>- Only one children will be active a time</li></ul>
1110  *  @class
1111  *  @extends cc.Layer
1112  */
1113 cc.LayerMultiplex = cc.Layer.extend(/** @lends cc.LayerMultiplex# */{
1114     _enabledLayer:0,
1115     _layers:null,
1116 
1117     /**
1118      * Constructor
1119      */
1120     ctor:function () {
1121         this._super();
1122     },
1123 
1124     /**
1125      * @param {cc.Layer} layer
1126      * @deprecated merged with initWithLayers
1127      * @return {Boolean}
1128      */
1129     initWithLayer:function (layer) {
1130         this._layers = [];
1131         this._layers.push(layer);
1132         this._enabledLayer = 0;
1133         this.addChild(layer);
1134         return true;
1135     },
1136 
1137     /**
1138      * @param {Array} args an array of cc.Layer
1139      * @return {Boolean}
1140      */
1141     initWithLayers:function (args) {
1142         this._layers = args;
1143         this._enabledLayer = 0;
1144         this.addChild(this._layers[this._enabledLayer]);
1145         return true;
1146     },
1147 
1148     /**
1149      * switches to a certain layer indexed by n.<br/>
1150      * The current (old) layer will be removed from it's parent with 'cleanup:YES'.
1151      * @param {Number} n the layer index to switch to
1152      */
1153     switchTo:function (n) {
1154         cc.Assert(n < this._layers.length, "Invalid index in MultiplexLayer switchTo message");
1155 
1156         this.removeChild(this._layers[this._enabledLayer], true);
1157 
1158         this._enabledLayer = n;
1159 
1160         this.addChild(this._layers[n]);
1161     },
1162 
1163     /** release the current layer and switches to another layer indexed by n.<br/>
1164      * The current (old) layer will be removed from it's parent with 'cleanup:YES'.
1165      * @param {Number} n the layer index to switch to
1166      */
1167     switchToAndReleaseMe:function (n) {
1168         cc.Assert(n < this._layers.count(), "Invalid index in MultiplexLayer switchTo message");
1169 
1170         this.removeChild(this._layers[this._enabledLayer], true);
1171 
1172         //[layers replaceObjectAtIndex:_enabledLayer withObject:[NSNull null]];
1173         this._layers[this._enabledLayer] = null;
1174 
1175         this._enabledLayer = n;
1176 
1177         this.addChild(this._layers[n]);
1178     },
1179 
1180     /**
1181      * @param {cc.Layer} layer
1182      */
1183     addLayer:function (layer) {
1184         cc.Assert(this._layers, "cc.Layer addLayer");
1185         this._layers.push(layer);
1186     }
1187 });
1188 
1189 
1190 /**
1191  * creates a cc.LayerMultiplex with one or more layers using a variable argument list.
1192  * @return {cc.LayerMultiplex|Null}
1193  * @example
1194  * // Example
1195  * var multiLayer = cc.LayerMultiple.create(layer1, layer2, layer3);//any number of layers
1196  */
1197 cc.LayerMultiplex.create = function (/*Multiple Arguments*/) {
1198     var multiplexLayer = new cc.LayerMultiplex();
1199     if (multiplexLayer.initWithLayers(arguments)) {
1200         return multiplexLayer;
1201     }
1202     return null;
1203 };
1204 
1205 
1206 /**
1207  * a layer that does not get redraw if not needed, and its always gets placed on the bottom layer
1208  * @class
1209  * @extends cc.Node
1210  * @example
1211  * // Example
1212  * var veryLazy = new cc.LazyLayer();
1213  * veryLazy.addChild(mySprite);
1214  */
1215 cc.LazyLayer = cc.Node.extend(/** @lends cc.LazyLayer# */{
1216     _layerCanvas:null,
1217     _layerContext:null,
1218     _isNeedUpdate:false,
1219     _canvasZOrder:-10,
1220     _layerId:"",
1221 
1222     /**
1223      * Constructor
1224      */
1225     ctor:function () {
1226         this._super();
1227         this.setAnchorPoint(cc.p(0, 0));
1228         //setup html
1229         this._setupHtml();
1230     },
1231 
1232     /**
1233      * @param {Number} zOrder
1234      */
1235     setLayerZOrder:function (zOrder) {
1236         if (zOrder >= 0) {
1237             throw "LazyLayer zOrder must Less than Zero.Because LazyLayer is a background Layer!";
1238         }
1239         this._canvasZOrder = zOrder;
1240         this._layerCanvas.style.zIndex = this._canvasZOrder;
1241     },
1242 
1243     /**
1244      *
1245      * @return {Number}
1246      */
1247     getLayerZOrder:function () {
1248         return this._canvasZOrder;
1249     },
1250 
1251     _setupHtml:function () {
1252         this._layerCanvas = document.createElement("canvas");
1253         this._layerCanvas.width = cc.canvas.width;
1254         this._layerCanvas.height = cc.canvas.height;
1255         this._layerId = "lazyCanvas" + Date.now();
1256         this._layerCanvas.id = this._layerId;
1257         this._layerCanvas.style.zIndex = this._canvasZOrder;
1258         this._layerCanvas.style.position = "absolute";
1259         this._layerCanvas.style.top = "0";
1260         this._layerCanvas.style.left = "0";
1261         this._layerContext = this._layerCanvas.getContext("2d");
1262         this._layerContext.fillStyle = "rgba(0,0,0,1)";
1263         this._layerContext.translate(0, this._layerCanvas.height);
1264         cc.container.appendChild(this._layerCanvas);
1265         var selfPointer = this;
1266         window.addEventListener("resize", function (event) {
1267             selfPointer.adjustSizeForCanvas();
1268         });
1269     },
1270 
1271     /**
1272      * make it the same size as canvas, in case canvas resized
1273      */
1274     adjustSizeForCanvas:function () {
1275         this._isNeedUpdate = true;
1276         this._layerCanvas.width = cc.canvas.width;
1277         this._layerCanvas.height = cc.canvas.height;
1278         var xScale = cc.canvas.width / cc.originalCanvasSize.width;
1279         var yScale = cc.canvas.height / cc.originalCanvasSize.height;
1280         if (xScale > yScale) {
1281             xScale = yScale;
1282         }
1283         this._layerContext.translate(0, this._layerCanvas.height);
1284         this._layerContext.scale(xScale, xScale);
1285     },
1286 
1287     /**
1288      * return lazylayer's canvas
1289      * @return {HTMLCanvasElement}
1290      */
1291     getLayerCanvas:function () {
1292         return this._layerCanvas;
1293     },
1294 
1295     /**
1296      * same as cc.Node
1297      * @param {cc.Node} child
1298      * @param {Number|Null} zOrder
1299      * @param {Number|Null} tag
1300      */
1301     addChild:function (child, zOrder, tag) {
1302         this._isNeedUpdate = true;
1303         this._super(child, zOrder, tag);
1304     },
1305 
1306     /**
1307      * @param {cc.Node} child
1308      * @param {Boolean} cleanup
1309      */
1310     removeChild:function (child, cleanup) {
1311         this._isNeedUpdate = true;
1312         this._super(child, cleanup);
1313     },
1314 
1315     /**
1316      * stuff gets drawn in here
1317      */
1318     visit:function () {
1319         // quick return if not visible
1320         if (!this._visible) {
1321             return;
1322         }
1323         if (!this._isNeedUpdate) {
1324             return;
1325         }
1326 
1327         this._isNeedUpdate = false;
1328         var context = this._layerContext;
1329         context.save();
1330         context.clearRect(0, 0, this._layerCanvas.width, -this._layerCanvas.height);
1331 
1332         if (this._children && this._children.length > 0) {
1333             this.sortAllChildren();
1334             // draw children zOrder < 0
1335             for (var i = 0; i < this._children.length; i++) {
1336                 this._children[i].visit(context);
1337             }
1338         }
1339 
1340         context.restore();
1341     },
1342 
1343     /**
1344      * override onExit of cc.Node
1345      * @override
1346      */
1347     onExit:function () {
1348         this._super();
1349 
1350         //clear canvas element from parent element
1351         if (this._layerCanvas.parentNode) {
1352             this._layerCanvas.parentNode.removeChild(this._layerCanvas);
1353         }
1354     },
1355 
1356     _setNodeDirtyForCache:function () {
1357         this._cacheDirty = true;
1358         this._isNeedUpdate = true;
1359     }
1360 });
1361