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     ctor: function () {
 51         cc.Node.prototype.ctor.call(this);
 52         this._isTouchEnabled = false;
 53         this._isAccelerometerEnabled = false;
 54         this._isKeyboardEnabled = false;
 55         this._touchPriority = 0;
 56         this._touchMode = cc.TOUCH_ALL_AT_ONCE;
 57         this._isMouseEnabled = false;
 58         this._mousePriority = 0;
 59     },
 60 
 61     _initLayer:function () {
 62         this.setAnchorPoint(cc.p(0.5, 0.5));
 63         this._ignoreAnchorPointForPosition = true;
 64 
 65         var director = cc.Director.getInstance();
 66         this.setContentSize(director.getWinSize());
 67     },
 68 
 69     /**
 70      *
 71      * @return {Boolean}
 72      */
 73     init:function () {
 74         cc.Node.prototype.init.call(this);
 75         this._initLayer();
 76         return true;
 77     },
 78 
 79     /**
 80      * If isTouchEnabled, this method is called onEnter.
 81      */
 82     registerWithTouchDispatcher:function () {
 83         if (this._touchMode === cc.TOUCH_ALL_AT_ONCE)
 84             cc.registerStandardDelegate(this,this._touchPriority);
 85         else
 86             cc.registerTargetedDelegate(this._touchPriority, true, this);
 87     },
 88 
 89     isMouseEnabled:function () {
 90         return this._isMouseEnabled;
 91     },
 92 
 93     setMouseEnabled:function (enabled) {
 94         if(!cc.MouseDispatcher)
 95             throw "cc.MouseDispatcher is undefined, maybe it has been removed from js loading list.";
 96 
 97         if (this._isMouseEnabled != enabled) {
 98             this._isMouseEnabled = enabled;
 99             if (this._running) {
100                 if (enabled)
101                     cc.Director.getInstance().getMouseDispatcher().addMouseDelegate(this, this._mousePriority);
102                 else
103                     cc.Director.getInstance().getMouseDispatcher().removeMouseDelegate(this);
104             }
105         }
106     },
107 
108     setMousePriority:function (priority) {
109         if(!cc.MouseDispatcher)
110             throw "cc.MouseDispatcher is undefined, maybe it has been removed from js loading list.";
111 
112         if (this._mousePriority !== priority) {
113             this._mousePriority = priority;
114             // Update touch priority with handler
115             if (this._isMouseEnabled) {
116                 this.setMouseEnabled(false);
117                 this.setMouseEnabled(true);
118             }
119         }
120     },
121 
122     getMousePriority:function () {
123         return this._mousePriority;
124     },
125 
126     /**
127      * whether or not it will receive Touch events.<br/>
128      * You can enable / disable touch events with this property.<br/>
129      * Only the touches of this node will be affected. This "method" is not propagated to it's children.<br/>
130      * @return {Boolean}
131      */
132     isTouchEnabled:function () {
133         return this._isTouchEnabled;
134     },
135 
136     /**
137      * Enable touch events
138      * @param {Boolean} enabled
139      */
140     setTouchEnabled:function (enabled) {
141         if (this._isTouchEnabled !== enabled) {
142             this._isTouchEnabled = enabled;
143 
144             if (this._running) {
145                 if (enabled) {
146                     this.registerWithTouchDispatcher();
147                 } else {
148                     // have problems?
149                     cc.unregisterTouchDelegate(this);
150                 }
151             }
152         }
153     },
154 
155     /** returns the priority of the touch event handler
156      * @return {Number}
157      */
158     getTouchPriority:function () {
159         return this._touchPriority;
160     },
161 
162     /** Sets the touch event handler priority. Default is 0.
163      * @param {Number} priority
164      */
165     setTouchPriority:function (priority) {
166         if (this._touchPriority !== priority) {
167             this._touchPriority = priority;
168             // Update touch priority with handler
169             if (this._isTouchEnabled) {
170                 this.setTouchEnabled(false);
171                 this.setTouchEnabled(true);
172             }
173         }
174     },
175 
176     /** returns the touch mode.
177      * @return {Number}
178      */
179     getTouchMode:function () {
180         return this._touchMode;
181     },
182 
183     /** Sets the touch mode.
184      * @param {Number} mode
185      */
186     setTouchMode:function (mode) {
187         if (this._touchMode !== mode) {
188             this._touchMode = mode;
189             // update the mode with handler
190             if (this._isTouchEnabled) {
191                 this.setTouchEnabled(false);
192                 this.setTouchEnabled(true);
193             }
194         }
195     },
196 
197     /**
198      * whether or not it will receive Accelerometer events<br/>
199      * You can enable / disable accelerometer events with this property.
200      * @return {Boolean}
201      */
202     isAccelerometerEnabled:function () {
203         return this._isAccelerometerEnabled;
204     },
205 
206     /**
207      * isAccelerometerEnabled setter
208      * @param {Boolean} enabled
209      */
210     setAccelerometerEnabled:function (enabled) {
211         if(!cc.Accelerometer)
212             throw "cc.Accelerometer is undefined, maybe it has been removed from js loading list.";
213         if (enabled !== this._isAccelerometerEnabled) {
214             this._isAccelerometerEnabled = enabled;
215             if (this._running) {
216                 var director = cc.Director.getInstance();
217                 if (enabled)
218                     director.getAccelerometer().setDelegate(this);
219                 else
220                     director.getAccelerometer().setDelegate(null);
221             }
222         }
223     },
224 
225     /**
226      * accelerometerInterval setter
227      * @param {Number} interval
228      */
229     setAccelerometerInterval:function (interval) {
230         if (this._isAccelerometerEnabled && cc.Accelerometer)
231             cc.Director.getInstance().getAccelerometer().setAccelerometerInterval(interval);
232     },
233 
234     onAccelerometer:function (accelerationValue) {
235         cc.log("onAccelerometer event should be handled.")
236     },
237 
238     /**
239      * whether or not it will receive keyboard events<br/>
240      * You can enable / disable accelerometer events with this property.<br/>
241      * it's new in cocos2d-x
242      * @return {Boolean}
243      */
244     isKeyboardEnabled:function () {
245         return this._isKeyboardEnabled;
246     },
247 
248     /**
249      * Enable Keyboard interaction
250      * @param {Boolean} enabled
251      */
252     setKeyboardEnabled:function (enabled) {
253         if(!cc.KeyboardDispatcher)
254             throw "cc.KeyboardDispatcher is undefined, maybe it has been removed from js loading list.";
255 
256         if (enabled !== this._isKeyboardEnabled) {
257             this._isKeyboardEnabled = enabled;
258             if (this._running) {
259                 var director = cc.Director.getInstance();
260                 if (enabled) {
261                     director.getKeyboardDispatcher().addDelegate(this);
262                 } else {
263                     director.getKeyboardDispatcher().removeDelegate(this);
264                 }
265             }
266         }
267     },
268 
269     /**
270      * This is run when ever a layer just become visible
271      */
272     onEnter:function () {
273         var director = cc.Director.getInstance();
274         // register 'parent' nodes first
275         // since events are propagated in reverse order
276         if (this._isTouchEnabled)
277             this.registerWithTouchDispatcher();
278 
279         // then iterate over all the children
280         cc.Node.prototype.onEnter.call(this);
281 
282         // add this layer to concern the Accelerometer Sensor
283         if (this._isAccelerometerEnabled && cc.Accelerometer)
284             director.getAccelerometer().setDelegate(this);
285 
286         // add this layer to concern the kaypad msg
287         if (this._isKeyboardEnabled && cc.KeyboardDispatcher)
288             director.getKeyboardDispatcher().addDelegate(this);
289 
290         if (this._isMouseEnabled && cc.MouseDispatcher)
291             director.getMouseDispatcher().addMouseDelegate(this, this._mousePriority);
292     },
293 
294     /**
295      * @function
296      */
297     onExit:function () {
298         var director = cc.Director.getInstance();
299         if (this._isTouchEnabled)
300             cc.unregisterTouchDelegate(this);
301 
302         // remove this layer from the delegates who concern Accelerometer Sensor
303         if (this._isAccelerometerEnabled && cc.Accelerometer)
304             director.getAccelerometer().setDelegate(null);
305 
306         // remove this layer from the delegates who concern the kaypad msg
307         if (this._isKeyboardEnabled && cc.KeyboardDispatcher)
308             director.getKeyboardDispatcher().removeDelegate(this);
309 
310         if (this._isMouseEnabled && cc.MouseDispatcher)
311             director.getMouseDispatcher().removeMouseDelegate(this);
312 
313         cc.Node.prototype.onExit.call(this);
314     },
315 
316     /**
317      * this is called when ever a layer is a child of a scene that just finished a transition
318      */
319     onEnterTransitionDidFinish:function () {
320         if (this._isAccelerometerEnabled && cc.Accelerometer)
321             cc.Director.getInstance().getAccelerometer().setDelegate(this);
322         cc.Node.prototype.onEnterTransitionDidFinish.call(this);
323     },
324 
325     // ---------------------CCTouchDelegate interface------------------------------
326 
327     /**
328      * default implements are used to call script callback if exist<br/>
329      * you must override these touch functions if you wish to utilize them
330      * @param {cc.Touch} touch
331      * @param {event} event
332      * @return {Boolean}
333      */
334     onTouchBegan:function (touch, event) {
335         cc.log("onTouchBegan event should be handled.");
336         return true;
337     },
338 
339     /**
340      * callback when a touch event moved
341      * @param {cc.Touch} touch
342      * @param {event} event
343      */
344     onTouchMoved:function (touch, event) {
345     },
346 
347     /**
348      * callback when a touch event finished
349      * @param {cc.Touch} touch
350      * @param {event} event
351      */
352     onTouchEnded:function (touch, event) {
353     },
354 
355     /**
356      * @param {cc.Touch} touch
357      * @param {event} event
358      */
359     onTouchCancelled:function (touch, event) {
360     },
361 
362     /**
363      * Touches is the same as Touch, except this one can handle multi-touch
364      * @param {cc.Touch} touch
365      * @param {event} event
366      */
367     onTouchesBegan:function (touch, event) {
368     },
369 
370     /**
371      * when a touch moved
372      * @param {cc.Touch} touch
373      * @param {event} event
374      */
375     onTouchesMoved:function (touch, event) {
376     },
377 
378     /**
379      * when a touch finished
380      * @param {cc.Touch} touch
381      * @param {event} event
382      */
383     onTouchesEnded:function (touch, event) {
384     },
385 
386     /**
387      * @param touch
388      * @param event
389      */
390     onTouchesCancelled:function (touch, event) {
391     },
392 
393     // ---------------------CCMouseEventDelegate interface------------------------------
394 
395     /**
396      * <p>called when the "mouseDown" event is received. <br/>
397      * Return YES to avoid propagating the event to other delegates.  </p>
398      * @param event
399      * @return {Boolean}
400      */
401     onMouseDown:function (event) {
402         return false;
403     },
404 
405     /**
406      * <p>called when the "mouseDragged" event is received.         <br/>
407      * Return YES to avoid propagating the event to other delegates.</p>
408      * @param event
409      * @return {Boolean}
410      */
411     onMouseDragged:function (event) {
412         return false;
413     },
414 
415     /**
416      * <p> called when the "mouseMoved" event is received.            <br/>
417      * Return YES to avoid propagating the event to other delegates.  </p>
418      * @param event
419      * @return {Boolean}
420      */
421     onMouseMoved:function (event) {
422         return false;
423     },
424 
425     /**
426      * <p> called when the "mouseUp" event is received.               <br/>
427      * Return YES to avoid propagating the event to other delegates.  </p>
428      * @param event
429      * @return {Boolean}
430      */
431     onMouseUp:function (event) {
432         return false;
433     },
434 
435     //right
436     /**
437      * <p> called when the "rightMouseDown" event is received.        <br/>
438      * Return YES to avoid propagating the event to other delegates.  </p>
439      * @param event
440      * @return {Boolean}
441      */
442     onRightMouseDown:function (event) {
443         return false;
444     },
445 
446     /**
447      * <p> called when the "rightMouseDragged" event is received.    <br/>
448      * Return YES to avoid propagating the event to other delegates. </p>
449      * @param event
450      * @return {Boolean}
451      */
452     onRightMouseDragged:function (event) {
453         return false;
454     },
455 
456     /**
457      * <p> called when the "rightMouseUp" event is received.          <br/>
458      * Return YES to avoid propagating the event to other delegates.  </p>
459      * @param event
460      * @return {Boolean}
461      */
462     onRightMouseUp:function (event) {
463         return false;
464     },
465 
466     //other
467     /**
468      * <p>called when the "otherMouseDown" event is received.         <br/>
469      * Return YES to avoid propagating the event to other delegates.  </p>
470      * @param event
471      * @return {Boolean}
472      */
473     onOtherMouseDown:function (event) {
474         return false;
475     },
476 
477     /**
478      * <p> called when the "otherMouseDragged" event is received.     <br/>
479      * Return YES to avoid propagating the event to other delegates.  </p>
480      * @param event
481      * @return {Boolean}
482      */
483     onOtherMouseDragged:function (event) {
484         return false;
485     },
486 
487     /**
488      * <p> called when the "otherMouseUp" event is received.          <br/>
489      * Return YES to avoid propagating the event to other delegates.  </p>
490      * @param event
491      * @return {Boolean}
492      */
493     onOtherMouseUp:function (event) {
494         return false;
495     },
496 
497     //scroll wheel
498     /**
499      * <p> called when the "scrollWheel" event is received.           <br/>
500      * Return YES to avoid propagating the event to other delegates.  </p>
501      * @param event
502      * @return {Boolean}
503      */
504     onScrollWheel:function (event) {
505         return false;
506     },
507 
508     // enter / exit
509     /**
510      *  <p> called when the "mouseEntered" event is received.         <br/>
511      *  Return YES to avoid propagating the event to other delegates. </p>
512      * @param theEvent
513      * @return {Boolean}
514      */
515     onMouseEntered:function (theEvent) {
516         return false;
517     },
518 
519     /**
520      * <p> called when the "mouseExited" event is received.          <br/>
521      * Return YES to avoid propagating the event to other delegates. </p>
522      * @param theEvent
523      * @return {Boolean}
524      */
525     onMouseExited:function (theEvent) {
526         return false;
527     },
528 
529     // ---------------------CCKeyboardDelegate interface------------------------------
530 
531     /**
532      * Call back when a key is pressed down
533      * @param {Number} keyCode
534      * @example
535      * // example
536      * if(keyCode == cc.KEY.w){}
537      */
538     onKeyDown:function (keyCode) {
539     },
540 
541     /**
542      * Call back when a key is released
543      * @param {Number} keyCode
544      * @example
545      * // example
546      * if(keyCode == cc.KEY.w){}
547      */
548     onKeyUp:function (keyCode) {
549     }
550 });
551 
552 /**
553  * creates a layer
554  * @example
555  * // Example
556  * var myLayer = cc.Layer.create();
557  * //Yes! it's that simple
558  * @return {cc.Layer|Null}
559  */
560 cc.Layer.create = function () {
561     var ret = new cc.Layer();
562     if (ret && ret.init())
563         return ret;
564     return null;
565 };
566 
567 /**
568  * <p>
569  *     CCLayerRGBA is a subclass of CCLayer that implements the CCRGBAProtocol protocol using a solid color as the background.                        <br/>
570  *     All features from CCLayer are valid, plus the following new features that propagate into children that conform to the CCRGBAProtocol:          <br/>
571  *       - opacity                                                                                                                                    <br/>
572  *       - RGB colors
573  * </p>
574  * @class
575  * @extends cc.Layer
576  */
577 cc.LayerRGBA = cc.Layer.extend(/** @lends cc.LayerRGBA# */{
578     RGBAProtocol:true,
579     _displayedOpacity: 0,
580     _realOpacity: 0,
581     _displayedColor: null,
582     _realColor: null,
583     _cascadeOpacityEnabled: false,
584     _cascadeColorEnabled: false,
585 
586     ctor: function () {
587         cc.Layer.prototype.ctor.call(this);
588         this.RGBAProtocol = true;
589         this._displayedOpacity = 255;
590         this._realOpacity = 255;
591         this._displayedColor = cc.white();
592         this._realColor = cc.white();
593         this._cascadeOpacityEnabled = false;
594         this._cascadeColorEnabled = false;
595     },
596 
597     init: function () {
598         if(cc.Layer.prototype.init.call(this)){
599             this.setCascadeOpacityEnabled(false);
600             this.setCascadeColorEnabled(false);
601             return true;
602         }
603         return false;
604     },
605 
606     /**
607      *
608      * @returns {number}
609      */
610     getOpacity: function () {
611         return this._realOpacity;
612     },
613 
614     /**
615      *
616      * @returns {number}
617      */
618     getDisplayedOpacity: function () {
619         return this._displayedOpacity;
620     },
621 
622     /**
623      * Override synthesized setOpacity to recurse items
624      * @param {Number} opacity
625      */
626     setOpacity: function (opacity) {
627         this._displayedOpacity = this._realOpacity = opacity;
628 
629         var parentOpacity = 255, locParent = this._parent;
630         if (locParent && locParent.RGBAProtocol && locParent.isCascadeOpacityEnabled())
631             parentOpacity = locParent.getDisplayedOpacity();
632         this.updateDisplayedOpacity(parentOpacity);
633     },
634 
635     /**
636      *
637      * @param {Number} parentOpacity
638      */
639     updateDisplayedOpacity: function (parentOpacity) {
640         this._displayedOpacity = 0 | (this._realOpacity * parentOpacity / 255.0);
641 
642         if (this._cascadeOpacityEnabled) {
643             var locChildren = this._children;
644             for (var i = 0; i < locChildren.length; i++) {
645                 var selItem = locChildren[i];
646                 if (selItem && selItem.RGBAProtocol)
647                     selItem.updateDisplayedOpacity(this._displayedOpacity);
648             }
649         }
650     },
651 
652     isCascadeOpacityEnabled: function () {
653         return this._cascadeOpacityEnabled;
654     },
655 
656     setCascadeOpacityEnabled: function (cascadeOpacityEnabled) {
657         if(this._cascadeOpacityEnabled === cascadeOpacityEnabled)
658             return;
659 
660         this._cascadeOpacityEnabled = cascadeOpacityEnabled;
661         if(cascadeOpacityEnabled)
662             this._enableCascadeOpacity();
663         else
664             this._disableCascadeOpacity();
665     },
666 
667     _enableCascadeOpacity:function(){
668         var parentOpacity = 255, locParent = this._parent;
669         if (locParent && locParent.RGBAProtocol && locParent.isCascadeOpacityEnabled())
670             parentOpacity = locParent.getDisplayedOpacity();
671         this.updateDisplayedOpacity(parentOpacity);
672     },
673 
674     _disableCascadeOpacity:function(){
675         this._displayedOpacity = this._realOpacity;
676         var selChildren = this._children;
677         for(var i = 0; i< selChildren.length;i++){
678             var item = selChildren[i];
679             if(item && item.RGBAProtocol && item._disableCascadeOpacity)
680                 item._disableCascadeOpacity();
681         }
682     },
683 
684     getColor: function () {
685         var locRealColor = this._realColor;
686         return cc.c3b(locRealColor.r, locRealColor.g, locRealColor.b);
687     },
688 
689     getDisplayedColor: function () {
690         var locDisplayedColor = this._displayedColor;
691         return cc.c3b(locDisplayedColor.r, locDisplayedColor.g, locDisplayedColor.b);
692     },
693 
694     setColor: function (color) {
695         var locDisplayed = this._displayedColor, locRealColor = this._realColor;
696         locDisplayed.r = locRealColor.r = color.r;
697         locDisplayed.g = locRealColor.g = color.g;
698         locDisplayed.b = locRealColor.b = color.b;
699 
700         var parentColor, locParent = this._parent;
701         if (locParent && locParent.RGBAProtocol && locParent.isCascadeColorEnabled())
702             parentColor = locParent.getDisplayedColor();
703         else
704             parentColor = cc.white();
705         this.updateDisplayedColor(parentColor);
706     },
707 
708     updateDisplayedColor: function (parentColor) {
709         var locDisplayedColor = this._displayedColor, locRealColor = this._realColor;
710         locDisplayedColor.r = 0 | (locRealColor.r * parentColor.r / 255.0);
711         locDisplayedColor.g = 0 | (locRealColor.g * parentColor.g / 255.0);
712         locDisplayedColor.b = 0 | (locRealColor.b * parentColor.b / 255.0);
713 
714         if (this._cascadeColorEnabled) {
715             var locChildren = this._children;
716             for (var i = 0; i < locChildren.length; i++) {
717                 var selItem = locChildren[i];
718                 if (selItem && selItem.RGBAProtocol)
719                     selItem.updateDisplayedColor(locDisplayedColor);
720             }
721         }
722     },
723 
724     isCascadeColorEnabled: function () {
725         return this._cascadeColorEnabled;
726     },
727 
728     setCascadeColorEnabled: function (cascadeColorEnabled) {
729         if(this._cascadeColorEnabled === cascadeColorEnabled)
730             return;
731         this._cascadeColorEnabled = cascadeColorEnabled;
732         if(this._cascadeColorEnabled)
733             this._enableCascadeColor();
734         else
735             this._disableCascadeColor();
736     },
737 
738     _enableCascadeColor: function(){
739         var parentColor , locParent =  this._parent;
740         if (locParent && locParent.RGBAProtocol &&  locParent.isCascadeColorEnabled())
741             parentColor = locParent.getDisplayedColor();
742         else
743             parentColor = cc.white();
744         this.updateDisplayedColor(parentColor);
745     },
746 
747     _disableCascadeColor: function(){
748         var locDisplayedColor = this._displayedColor, locRealColor = this._realColor;
749         locDisplayedColor.r = locRealColor.r;
750         locDisplayedColor.g = locRealColor.g;
751         locDisplayedColor.b = locRealColor.b;
752 
753         var selChildren = this._children;
754         for(var i = 0; i< selChildren.length;i++){
755             var item = selChildren[i];
756             if(item && item.RGBAProtocol && item._disableCascadeColor)
757                 item._disableCascadeColor();
758         }
759     },
760 
761     addChild:function(child, zOrder, tag){
762         cc.Node.prototype.addChild.call(this, child, zOrder, tag);
763 
764         if(this._cascadeColorEnabled)
765             this._enableCascadeColor();
766         if(this._cascadeOpacityEnabled)
767             this._enableCascadeOpacity();
768     },
769 
770     setOpacityModifyRGB: function (bValue) {
771     },
772 
773     isOpacityModifyRGB: function () {
774         return false;
775     }
776 });
777 
778 /**
779  * <p>
780  * CCLayerColor is a subclass of CCLayer that implements the CCRGBAProtocol protocol.       <br/>
781  *  All features from CCLayer are valid, plus the following new features:                   <br/>
782  * <ul><li>opacity</li>                                                                     <br/>
783  * <li>RGB colors</li></ul>                                                                 <br/>
784  * </p>
785  * @class
786  * @extends cc.Layer
787  */
788 cc.LayerColor = cc.LayerRGBA.extend(/** @lends cc.LayerColor# */{
789     _blendFunc:null,
790 
791     /**
792      * blendFunc getter
793      * @return {cc.BlendFunc}
794      */
795     getBlendFunc:function () {
796         return this._blendFunc;
797     },
798 
799     /**
800      * change width and height in Points
801      * @param {Number} w width
802      * @param {Number} h height
803      */
804     changeWidthAndHeight:function (w, h) {
805         this.setContentSize(cc.size(w, h));
806     },
807 
808     /**
809      * change width in Points
810      * @param {Number} w width
811      */
812     changeWidth:function (w) {
813         this.setContentSize(cc.size(w, this._contentSize.height));
814     },
815 
816     /**
817      * change height in Points
818      * @param {Number} h height
819      */
820     changeHeight:function (h) {
821         this.setContentSize(cc.size(this._contentSize.width, h));
822     },
823 
824     /**
825      * set OpacityModifyRGB of cc.LayerColor
826      * @param {Boolean}  value
827      */
828     setOpacityModifyRGB:function (value) {
829     },
830 
831     /**
832      * is OpacityModifyRGB
833      * @return {Boolean}
834      */
835     isOpacityModifyRGB:function () {
836         return false;
837     },
838 
839     setColor:function(color){
840         cc.LayerRGBA.prototype.setColor.call(this, color);
841         this._updateColor();
842     },
843 
844     setOpacity:function(opacity){
845         cc.LayerRGBA.prototype.setOpacity.call(this, opacity);
846         this._updateColor();
847     },
848 
849     _isLighterMode:false,
850     _squareVertices:null,
851     _squareColors:null,
852     _verticesFloat32Buffer:null,
853     _colorsUint8Buffer:null,
854     _squareVerticesAB:null,
855     _squareColorsAB:null,
856 
857     _ctorForCanvas: function () {
858         cc.LayerRGBA.prototype.ctor.call(this);
859         this._blendFunc = new cc.BlendFunc(cc.BLEND_SRC, cc.BLEND_DST);
860     },
861 
862     _ctorForWebGL: function () {
863         cc.LayerRGBA.prototype.ctor.call(this);
864         this._blendFunc = new cc.BlendFunc(cc.BLEND_SRC, cc.BLEND_DST);
865 
866         this._squareVerticesAB = new ArrayBuffer(32);
867         this._squareColorsAB = new ArrayBuffer(64);
868 
869         var locSquareVerticesAB = this._squareVerticesAB, locSquareColorsAB = this._squareColorsAB;
870         var locVertex2FLen = cc.Vertex2F.BYTES_PER_ELEMENT, locColor4FLen = cc.Color4F.BYTES_PER_ELEMENT;
871         this._squareVertices = [new cc.Vertex2F(0, 0, locSquareVerticesAB, 0),
872             new cc.Vertex2F(0, 0, locSquareVerticesAB, locVertex2FLen),
873             new cc.Vertex2F(0, 0, locSquareVerticesAB, locVertex2FLen * 2),
874             new cc.Vertex2F(0, 0, locSquareVerticesAB, locVertex2FLen * 3)];
875         this._squareColors = [new cc.Color4F(0, 0, 0, 1, locSquareColorsAB, 0),
876             new cc.Color4F(0, 0, 0, 1, locSquareColorsAB, locColor4FLen),
877             new cc.Color4F(0, 0, 0, 1, locSquareColorsAB, locColor4FLen * 2),
878             new cc.Color4F(0, 0, 0, 1, locSquareColorsAB, locColor4FLen * 3)];
879         this._verticesFloat32Buffer = cc.renderContext.createBuffer();
880         this._colorsUint8Buffer = cc.renderContext.createBuffer();
881     },
882 
883     /**
884      * blendFunc setter
885      * @param {Number} src
886      * @param {Number} dst
887      */
888     setBlendFunc:function (src, dst) {
889         if (arguments.length == 1)
890             this._blendFunc = src;
891         else
892             this._blendFunc = {src:src, dst:dst};
893         if(cc.renderContextType === cc.CANVAS)
894             this._isLighterMode = (this._blendFunc && (this._blendFunc.src == 1) && (this._blendFunc.dst == 771));
895     },
896 
897     /**
898      * @param {cc.Color4B} [color=]
899      * @param {Number} [width=]
900      * @param {Number} [height=]
901      * @return {Boolean}
902      */
903     init:function (color, width, height) {
904         if(!cc.Layer.prototype.init.call(this))
905             return false;
906 
907         if(cc.renderContextType !== cc.CANVAS)
908             this.setShaderProgram(cc.ShaderCache.getInstance().programForKey(cc.SHADER_POSITION_COLOR));
909 
910         var winSize = cc.Director.getInstance().getWinSize();
911         color = color || new cc.Color4B(0, 0, 0, 255);
912         width = width || winSize.width;
913         height = height || winSize.height;
914 
915         var locDisplayedColor = this._displayedColor;
916         locDisplayedColor.r = color.r;
917         locDisplayedColor.g = color.g;
918         locDisplayedColor.b = color.b;
919 
920         var locRealColor = this._realColor;
921         locRealColor.r = color.r;
922         locRealColor.g = color.g;
923         locRealColor.b = color.b;
924 
925         this._displayedOpacity = color.a;
926         this._realOpacity = color.a;
927 
928         this.setContentSize(cc.size(width, height));
929         this._updateColor();
930         return true;
931     },
932 
933     /**
934      * override contentSize
935      * @param {cc.Size} size
936      */
937     setContentSize:null,
938 
939     _setContentSizeForWebGL:function (size) {
940         var locSquareVertices = this._squareVertices;
941         locSquareVertices[1].x = size.width;
942         locSquareVertices[2].y = size.height;
943         locSquareVertices[3].x = size.width;
944         locSquareVertices[3].y = size.height;
945         this._bindLayerVerticesBufferData();
946         cc.Layer.prototype.setContentSize.call(this,size);
947     },
948 
949     _updateColor:null,
950 
951     _updateColorForCanvas:function () {
952     },
953 
954     _updateColorForWebGL:function () {
955         var locDisplayedColor = this._displayedColor;
956         var locDisplayedOpacity = this._displayedOpacity, locSquareColors = this._squareColors;
957         for (var i = 0; i < 4; i++) {
958             locSquareColors[i].r = locDisplayedColor.r / 255;
959             locSquareColors[i].g = locDisplayedColor.g / 255;
960             locSquareColors[i].b = locDisplayedColor.b / 255;
961             locSquareColors[i].a = locDisplayedOpacity / 255;
962         }
963         this._bindLayerColorsBufferData();
964     },
965 
966     updateDisplayedColor:function(parentColor){
967         cc.LayerRGBA.prototype.updateDisplayedColor.call(this, parentColor);
968         this._updateColor();
969     },
970 
971     updateDisplayedOpacity: function(parentOpacity){
972         cc.LayerRGBA.prototype.updateDisplayedOpacity.call(this, parentOpacity);
973         this._updateColor();
974     },
975 
976     _bindLayerVerticesBufferData:function () {
977         var glContext = cc.renderContext;
978         glContext.bindBuffer(glContext.ARRAY_BUFFER, this._verticesFloat32Buffer);
979         glContext.bufferData(glContext.ARRAY_BUFFER, this._squareVerticesAB , glContext.STATIC_DRAW);
980     },
981 
982     _bindLayerColorsBufferData:function () {
983         var glContext = cc.renderContext;
984         glContext.bindBuffer(glContext.ARRAY_BUFFER, this._colorsUint8Buffer);
985         glContext.bufferData(glContext.ARRAY_BUFFER, this._squareColorsAB, glContext.STATIC_DRAW);
986     },
987 
988     /**
989      * renders the layer
990      * @param {CanvasRenderingContext2D|Null} ctx
991      */
992     draw:null,
993 
994     _drawForCanvas:function (ctx) {
995         var context = ctx || cc.renderContext;
996 
997         var locContentSize = this.getContentSize(), locEGLViewer = cc.EGLView.getInstance();
998 
999         var locDisplayedColor = this._displayedColor;
1000 
1001         context.fillStyle = "rgba(" + (0 | locDisplayedColor.r) + "," + (0 | locDisplayedColor.g) + ","
1002             + (0 | locDisplayedColor.b) + "," + this._displayedOpacity / 255 + ")";
1003         context.fillRect(0, 0, locContentSize.width * locEGLViewer.getScaleX(), -locContentSize.height * locEGLViewer.getScaleY());
1004 
1005         cc.g_NumberOfDraws++;
1006     },
1007 
1008     _drawForWebGL:function (ctx) {
1009         var context = ctx || cc.renderContext;
1010 
1011         cc.NODE_DRAW_SETUP(this);
1012         cc.glEnableVertexAttribs(cc.VERTEX_ATTRIB_FLAG_POSITION | cc.VERTEX_ATTRIB_FLAG_COLOR);
1013 
1014         //
1015         // Attributes
1016         //
1017         context.bindBuffer(context.ARRAY_BUFFER, this._verticesFloat32Buffer);
1018         context.vertexAttribPointer(cc.VERTEX_ATTRIB_POSITION, 2, context.FLOAT, false, 0, 0);
1019 
1020         context.bindBuffer(context.ARRAY_BUFFER, this._colorsUint8Buffer);
1021         context.vertexAttribPointer(cc.VERTEX_ATTRIB_COLOR, 4, context.FLOAT, false, 0, 0);
1022 
1023         cc.glBlendFunc(this._blendFunc.src, this._blendFunc.dst);
1024         context.drawArrays(context.TRIANGLE_STRIP, 0, 4);
1025     }
1026 });
1027 
1028 if(cc.Browser.supportWebGL){
1029     cc.LayerColor.prototype.ctor = cc.LayerColor.prototype._ctorForWebGL;
1030     cc.LayerColor.prototype.setContentSize = cc.LayerColor.prototype._setContentSizeForWebGL;
1031     cc.LayerColor.prototype._updateColor = cc.LayerColor.prototype._updateColorForWebGL;
1032     cc.LayerColor.prototype.draw = cc.LayerColor.prototype._drawForWebGL;
1033 } else {
1034     cc.LayerColor.prototype.ctor = cc.LayerColor.prototype._ctorForCanvas;
1035     cc.LayerColor.prototype.setContentSize = cc.LayerRGBA.prototype.setContentSize;
1036     cc.LayerColor.prototype._updateColor = cc.LayerColor.prototype._updateColorForCanvas;
1037     cc.LayerColor.prototype.draw = cc.LayerColor.prototype._drawForCanvas;
1038 }
1039 
1040 
1041 /**
1042  * creates a cc.Layer with color, width and height in Points
1043  * @param {cc.Color4B} color
1044  * @param {Number|Null} [width=]
1045  * @param {Number|Null} [height=]
1046  * @return {cc.LayerColor}
1047  * @example
1048  * // Example
1049  * //Create a yellow color layer as background
1050  * var yellowBackground = cc.LayerColor.create(cc.c4b(255,255,0,255));
1051  * //If you didnt pass in width and height, it defaults to the same size as the canvas
1052  *
1053  * //create a yellow box, 200 by 200 in size
1054  * var yellowBox = cc.LayerColor.create(cc.c4b(255,255,0,255), 200, 200);
1055  */
1056 cc.LayerColor.create = function (color, width, height) {
1057     var ret = new cc.LayerColor();
1058     switch (arguments.length) {
1059         case 0:
1060             ret.init();
1061             break;
1062         case 1:
1063             ret.init(color);
1064             break;
1065         case 3:
1066             ret.init(color, width, height);
1067             break;
1068         default :
1069             ret.init();
1070             break;
1071     }
1072     return ret;
1073 };
1074 
1075 /**
1076  * <p>
1077  * CCLayerGradient is a subclass of cc.LayerColor that draws gradients across the background.<br/>
1078  *<br/>
1079  * All features from cc.LayerColor are valid, plus the following new features:<br/>
1080  * <ul><li>direction</li>
1081  * <li>final color</li>
1082  * <li>interpolation mode</li></ul>
1083  * <br/>
1084  * Color is interpolated between the startColor and endColor along the given<br/>
1085  * vector (starting at the origin, ending at the terminus).  If no vector is<br/>
1086  * supplied, it defaults to (0, -1) -- a fade from top to bottom.<br/>
1087  * <br/>
1088  * If 'compressedInterpolation' is disabled, you will not see either the start or end color for<br/>
1089  * non-cardinal vectors; a smooth gradient implying both end points will be still<br/>
1090  * be drawn, however.<br/>
1091  *<br/>
1092  * If 'compressedInterpolation' is enabled (default mode) you will see both the start and end colors of the gradient.
1093  * </p>
1094  * @class
1095  * @extends cc.LayerColor
1096  */
1097 cc.LayerGradient = cc.LayerColor.extend(/** @lends cc.LayerGradient# */{
1098     _startColor:null,
1099     _endColor:null,
1100     _startOpacity:null,
1101     _endOpacity:null,
1102     _alongVector:null,
1103     _compressedInterpolation:false,
1104     _gradientStartPoint:null,
1105     _gradientEndPoint:null,
1106 
1107     /**
1108      * Constructor
1109      * @function
1110      */
1111     ctor:function () {
1112         cc.LayerColor.prototype.ctor.call(this);
1113 
1114         this._startColor = new cc.Color3B(0, 0, 0);
1115         this._endColor = new cc.Color3B(0, 0, 0);
1116         this._alongVector = cc.p(0, -1);
1117         this._startOpacity = 255;
1118         this._endOpacity = 255;
1119         this._gradientStartPoint = cc.p(0, 0);
1120         this._gradientEndPoint = cc.p(0, 0);
1121     },
1122 
1123     /**
1124      * override contentSize
1125      * @param {cc.Size} size
1126      */
1127     setContentSize:function(size){
1128         cc.LayerColor.prototype.setContentSize.call(this,size);
1129         this._updateColor();
1130     },
1131 
1132     /**
1133      * get the starting color
1134      * @return {cc.Color3B}
1135      */
1136     getStartColor:function () {
1137         return this._realColor;
1138     },
1139 
1140     /**
1141      * set the starting color
1142      * @param {cc.Color3B} color
1143      * @example
1144      * // Example
1145      * myGradientLayer.setStartColor(cc.c3b(255,0,0));
1146      * //set the starting gradient to red
1147      */
1148     setStartColor:function (color) {
1149         this.setColor(color);
1150     },
1151 
1152     /**
1153      * set the end gradient color
1154      * @param {cc.Color3B} color
1155      * @example
1156      * // Example
1157      * myGradientLayer.setEndColor(cc.c3b(255,0,0));
1158      * //set the ending gradient to red
1159      */
1160     setEndColor:function (color) {
1161         this._endColor = color;
1162         this._updateColor();
1163     },
1164 
1165     /**
1166      * get the end color
1167      * @return {cc.Color3B}
1168      */
1169     getEndColor:function () {
1170         return this._endColor;
1171     },
1172 
1173     /**
1174      * set starting gradient opacity
1175      * @param {Number} o from 0 to 255, 0 is transparent
1176      */
1177     setStartOpacity:function (o) {
1178         this._startOpacity = o;
1179         this._updateColor();
1180     },
1181 
1182     /**
1183      * get the starting gradient opacity
1184      * @return {Number}
1185      */
1186     getStartOpacity:function () {
1187         return this._startOpacity;
1188     },
1189 
1190     /**
1191      * set the end gradient opacity
1192      * @param {Number} o
1193      */
1194     setEndOpacity:function (o) {
1195         this._endOpacity = o;
1196         this._updateColor();
1197     },
1198 
1199     /**
1200      * get the end gradient opacity
1201      * @return {Number}
1202      */
1203     getEndOpacity:function () {
1204         return this._endOpacity;
1205     },
1206 
1207     /**
1208      * set vector
1209      * @param {cc.Point} Var
1210      */
1211     setVector:function (Var) {
1212         this._alongVector.x = Var.x;
1213         this._alongVector.y = Var.y;
1214         this._updateColor();
1215     },
1216 
1217     /**
1218      * @return {cc.Point}
1219      */
1220     getVector:function () {
1221         return cc.p(this._alongVector.x, this._alongVector.y);
1222     },
1223 
1224     /** is Compressed Interpolation
1225      * @return {Boolean}
1226      */
1227     isCompressedInterpolation:function () {
1228         return this._compressedInterpolation;
1229     },
1230 
1231     /**
1232      * @param {Boolean} compress
1233      */
1234     setCompressedInterpolation:function (compress) {
1235         this._compressedInterpolation = compress;
1236         this._updateColor();
1237     },
1238 
1239     /**
1240      * @param {cc.Color4B} start starting color
1241      * @param {cc.Color4B} end
1242      * @param {cc.Point|Null} v
1243      * @return {Boolean}
1244      */
1245     init:function (start, end, v) {
1246         start = start || cc.c4(0,0,0,255);
1247         end = end || cc.c4(0,0,0,255);
1248         v = v || cc.p(0, -1);
1249 
1250         // Initializes the CCLayer with a gradient between start and end in the direction of v.
1251         var locStartColor = this._startColor, locEndColor = this._endColor;
1252         locStartColor.r = start.r;
1253         locStartColor.g = start.g;
1254         locStartColor.b = start.b;
1255         this._startOpacity = start.a;
1256 
1257         locEndColor.r = end.r;
1258         locEndColor.g = end.g;
1259         locEndColor.b = end.b;
1260         this._endOpacity = end.a;
1261 
1262         this._alongVector = v;
1263         this._compressedInterpolation = true;
1264 
1265         cc.LayerColor.prototype.init.call(this,cc.c4b(start.r, start.g, start.b, 255));
1266         return true;
1267     },
1268 
1269     draw:function (ctx) {
1270         if (cc.renderContextType === cc.WEBGL){
1271             cc.LayerColor.prototype.draw.call(this, ctx);
1272             return;
1273         }
1274 
1275         var context = ctx || cc.renderContext;
1276         if (this._isLighterMode)
1277             context.globalCompositeOperation = 'lighter';
1278 
1279         context.save();
1280         var locEGLViewer = cc.EGLView.getInstance(), opacityf = this._displayedOpacity / 255.0;
1281         var tWidth = this.getContentSize().width * locEGLViewer.getScaleX();
1282         var tHeight = this.getContentSize().height * locEGLViewer.getScaleY();
1283         var tGradient = context.createLinearGradient(this._gradientStartPoint.x, this._gradientStartPoint.y,
1284             this._gradientEndPoint.x, this._gradientEndPoint.y);
1285         var locDisplayedColor = this._displayedColor;
1286         var locEndColor = this._endColor;
1287         tGradient.addColorStop(0, "rgba(" + Math.round(locDisplayedColor.r) + "," + Math.round(locDisplayedColor.g) + ","
1288             + Math.round(locDisplayedColor.b) + "," + (opacityf * (this._startOpacity / 255)).toFixed(4) + ")");
1289         tGradient.addColorStop(1, "rgba(" + Math.round(locEndColor.r) + "," + Math.round(locEndColor.g) + ","
1290             + Math.round(locEndColor.b) + "," + (opacityf * (this._endOpacity / 255)).toFixed(4) + ")");
1291         context.fillStyle = tGradient;
1292         context.fillRect(0, 0, tWidth, -tHeight);
1293 
1294         if (this._rotation != 0)
1295             context.rotate(this._rotationRadians);
1296         context.restore();
1297     },
1298 
1299     _updateColor:function () {
1300         var locAlongVector = this._alongVector;
1301         if (cc.renderContextType === cc.CANVAS) {
1302             var tWidth = this.getContentSize().width * 0.5;
1303             var tHeight = this.getContentSize().height * 0.5;
1304 
1305             this._gradientStartPoint = cc.p(tWidth * (-locAlongVector.x) + tWidth, tHeight * locAlongVector.y - tHeight);
1306             this._gradientEndPoint = cc.p(tWidth * locAlongVector.x + tWidth, tHeight * (-locAlongVector.y) - tHeight);
1307         } else {
1308             var h = cc.pLength(locAlongVector);
1309             if (h === 0)
1310                 return;
1311 
1312             var c = Math.sqrt(2.0);
1313             var u = cc.p(locAlongVector.x / h, locAlongVector.y / h);
1314 
1315             // Compressed Interpolation mode
1316             if (this._compressedInterpolation) {
1317                 var h2 = 1 / ( Math.abs(u.x) + Math.abs(u.y) );
1318                 u = cc.pMult(u, h2 * c);
1319             }
1320 
1321             var opacityf = this._displayedOpacity / 255.0;
1322             var locDisplayedColor = this._displayedColor, locEndColor = this._endColor;
1323             var S = { r: locDisplayedColor.r / 255, g: locDisplayedColor.g / 255, b: locDisplayedColor.b / 255, a: (this._startOpacity * opacityf) / 255};
1324             var E = {r: locEndColor.r / 255, g: locEndColor.g / 255, b: locEndColor.b / 255, a: (this._endOpacity * opacityf) / 255};
1325 
1326             // (-1, -1)
1327             var locSquareColors = this._squareColors;
1328             var locSquareColor0 = locSquareColors[0], locSquareColor1 = locSquareColors[1], locSquareColor2 = locSquareColors[2],locSquareColor3 = locSquareColors[3];
1329             locSquareColor0.r = ((E.r + (S.r - E.r) * ((c + u.x + u.y) / (2.0 * c))));
1330             locSquareColor0.g = ((E.g + (S.g - E.g) * ((c + u.x + u.y) / (2.0 * c))));
1331             locSquareColor0.b = ((E.b + (S.b - E.b) * ((c + u.x + u.y) / (2.0 * c))));
1332             locSquareColor0.a = ((E.a + (S.a - E.a) * ((c + u.x + u.y) / (2.0 * c))));
1333             // (1, -1)
1334             locSquareColor1.r = ((E.r + (S.r - E.r) * ((c - u.x + u.y) / (2.0 * c))));
1335             locSquareColor1.g = ((E.g + (S.g - E.g) * ((c - u.x + u.y) / (2.0 * c))));
1336             locSquareColor1.b = ((E.b + (S.b - E.b) * ((c - u.x + u.y) / (2.0 * c))));
1337             locSquareColor1.a = ((E.a + (S.a - E.a) * ((c - u.x + u.y) / (2.0 * c))));
1338             // (-1, 1)
1339             locSquareColor2.r = ((E.r + (S.r - E.r) * ((c + u.x - u.y) / (2.0 * c))));
1340             locSquareColor2.g = ((E.g + (S.g - E.g) * ((c + u.x - u.y) / (2.0 * c))));
1341             locSquareColor2.b = ((E.b + (S.b - E.b) * ((c + u.x - u.y) / (2.0 * c))));
1342             locSquareColor2.a = ((E.a + (S.a - E.a) * ((c + u.x - u.y) / (2.0 * c))));
1343             // (1, 1)
1344             locSquareColor3.r = ((E.r + (S.r - E.r) * ((c - u.x - u.y) / (2.0 * c))));
1345             locSquareColor3.g = ((E.g + (S.g - E.g) * ((c - u.x - u.y) / (2.0 * c))));
1346             locSquareColor3.b = ((E.b + (S.b - E.b) * ((c - u.x - u.y) / (2.0 * c))));
1347             locSquareColor3.a = ((E.a + (S.a - E.a) * ((c - u.x - u.y) / (2.0 * c))));
1348 
1349             this._bindLayerColorsBufferData();
1350         }
1351     }
1352 });
1353 
1354 /**
1355  * creates a gradient layer
1356  * @param {cc.Color3B} start starting color
1357  * @param {cc.Color3B} end ending color
1358  * @param {cc.Point|Null} v
1359  * @return {cc.LayerGradient}
1360  */
1361 cc.LayerGradient.create = function (start, end, v) {
1362     var layer = new cc.LayerGradient();
1363     switch (arguments.length) {
1364         case 2:
1365             /** Creates a full-screen CCLayer with a gradient between start and end. */
1366             if (layer && layer.init(start, end))
1367                 return layer;
1368             break;
1369         case 3:
1370             /** Creates a full-screen CCLayer with a gradient between start and end in the direction of v. */
1371             if (layer && layer.init(start, end, v))
1372                 return layer;
1373             break;
1374         case 0:
1375             if (layer && layer.init())
1376                 return layer;
1377             break;
1378         default:
1379             throw "Arguments error ";
1380             break;
1381     }
1382     return null;
1383 };
1384 
1385 /**
1386  * CCMultipleLayer is a CCLayer with the ability to multiplex it's children.<br/>
1387  * Features:<br/>
1388  *  <ul><li>- It supports one or more children</li>
1389  *  <li>- Only one children will be active a time</li></ul>
1390  *  @class
1391  *  @extends cc.Layer
1392  */
1393 cc.LayerMultiplex = cc.Layer.extend(/** @lends cc.LayerMultiplex# */{
1394     _enabledLayer:0,
1395     _layers:null,
1396 
1397     /**
1398      * @param {cc.Layer} layer
1399      * @deprecated merged with initWithLayers
1400      * @return {Boolean}
1401      */
1402     initWithLayer:function (layer) {
1403         this._layers = [];
1404         this._layers.push(layer);
1405         this._enabledLayer = 0;
1406         this.addChild(layer);
1407         return true;
1408     },
1409 
1410     /**
1411      * @param {Array} args an array of cc.Layer
1412      * @return {Boolean}
1413      */
1414     initWithLayers:function (args) {
1415         this._layers = args;
1416         this._enabledLayer = 0;
1417         this.addChild(this._layers[this._enabledLayer]);
1418         return true;
1419     },
1420 
1421     /**
1422      * switches to a certain layer indexed by n.<br/>
1423      * The current (old) layer will be removed from it's parent with 'cleanup:YES'.
1424      * @param {Number} n the layer index to switch to
1425      */
1426     switchTo:function (n) {
1427         if(n >= this._layers.length){
1428             cc.log("cc.LayerMultiplex.switchTo():Invalid index in MultiplexLayer switchTo message");
1429             return;
1430         }
1431 
1432         this.removeChild(this._layers[this._enabledLayer], true);
1433         this._enabledLayer = n;
1434         this.addChild(this._layers[n]);
1435     },
1436 
1437     /** release the current layer and switches to another layer indexed by n.<br/>
1438      * The current (old) layer will be removed from it's parent with 'cleanup:YES'.
1439      * @param {Number} n the layer index to switch to
1440      */
1441     switchToAndReleaseMe:function (n) {
1442         if(n >= this._layers.length){
1443             cc.log("cc.LayerMultiplex.switchToAndReleaseMe():Invalid index in MultiplexLayer switchTo message");
1444             return;
1445         }
1446 
1447         this.removeChild(this._layers[this._enabledLayer], true);
1448 
1449         //[layers replaceObjectAtIndex:_enabledLayer withObject:[NSNull null]];
1450         this._layers[this._enabledLayer] = null;
1451         this._enabledLayer = n;
1452         this.addChild(this._layers[n]);
1453     },
1454 
1455     /**
1456      * @param {cc.Layer} layer
1457      */
1458     addLayer:function (layer) {
1459         if(!layer){
1460             cc.log("cc.Layer.addLayer(): layer should be non-null");
1461             return;
1462         }
1463         this._layers.push(layer);
1464     }
1465 });
1466 
1467 /**
1468  * creates a cc.LayerMultiplex with one or more layers using a variable argument list.
1469  * @return {cc.LayerMultiplex|Null}
1470  * @example
1471  * // Example
1472  * var multiLayer = cc.LayerMultiple.create(layer1, layer2, layer3);//any number of layers
1473  */
1474 cc.LayerMultiplex.create = function (/*Multiple Arguments*/) {
1475     if((arguments.length > 0) && (arguments[arguments.length-1] == null))
1476         cc.log("parameters should not be ending with null in Javascript");
1477     var multiplexLayer = new cc.LayerMultiplex();
1478     if (multiplexLayer.initWithLayers(arguments)) {
1479         return multiplexLayer;
1480     }
1481     return null;
1482 };
1483 
1484