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