1 /****************************************************************************
  2  Copyright (c) 2008-2010 Ricardo Quesada
  3  Copyright (c) 2011-2012 cocos2d-x.org
  4  Copyright (c) 2013-2014 Chukong Technologies 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 /** cc.Layer is a subclass of cc.Node that implements the TouchEventsDelegate protocol.<br/>
 28  * All features from cc.Node are valid, plus the bake feature: Baked layer can cache a static layer to improve performance
 29  * @class
 30  * @extends cc.Node
 31  */
 32 cc.Layer = cc.Node.extend(/** @lends cc.Layer# */{
 33     _isBaked: false,
 34     _bakeSprite: null,
 35     _className: "Layer",
 36 
 37     /**
 38      * <p>Constructor of cc.Layer, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function.</p>
 39      */
 40     ctor: function () {
 41         var nodep = cc.Node.prototype;
 42         nodep.ctor.call(this);
 43         this._ignoreAnchorPointForPosition = true;
 44         nodep.setAnchorPoint.call(this, 0.5, 0.5);
 45         nodep.setContentSize.call(this, cc.winSize);
 46     },
 47 
 48     /**
 49      * Initialization of the layer, please do not call this function by yourself, you should pass the parameters to constructor to initialize a layer
 50      */
 51     init: function(){
 52         var _t = this;
 53         _t._ignoreAnchorPointForPosition = true;
 54         _t.setAnchorPoint(0.5, 0.5);
 55         _t.setContentSize(cc.winSize);
 56         _t.cascadeOpacity = false;
 57         _t.cascadeColor = false;
 58         return true;
 59     },
 60 
 61     /**
 62      * Sets the layer to cache all of children to a bake sprite, and draw itself by bake sprite. recommend using it in UI.<br/>
 63      * This is useful only in html5 engine
 64      * @function
 65      * @see cc.Layer#unbake
 66      */
 67     bake: null,
 68 
 69     /**
 70      * Cancel the layer to cache all of children to a bake sprite.<br/>
 71      * This is useful only in html5 engine
 72      * @function
 73      * @see cc.Layer#bake
 74      */
 75     unbake: null,
 76 
 77     /**
 78      * Determines if the layer is baked.
 79      * @function
 80      * @returns {boolean}
 81      * @see cc.Layer#bake and cc.Layer#unbake
 82      */
 83     isBaked: function(){
 84         return this._isBaked;
 85     },
 86 
 87     visit: null
 88 });
 89 
 90 /**
 91  * Creates a layer
 92  * @deprecated since v3.0, please use the new construction instead
 93  * @see cc.Layer
 94  * @return {cc.Layer|Null}
 95  */
 96 cc.Layer.create = function () {
 97     return new cc.Layer();
 98 };
 99 
100 if (cc._renderType === cc._RENDER_TYPE_CANVAS) {
101     var p = cc.Layer.prototype;
102     p.bake = function(){
103         if (!this._isBaked) {
104             //limit: 1. its children's blendfunc are invalid.
105             this._isBaked = this._cacheDirty = true;
106 
107             this._cachedParent = this;
108             var children = this._children;
109             for(var i = 0, len = children.length; i < len; i++)
110                 children[i]._setCachedParent(this);
111 
112             if (!this._bakeSprite)
113                 this._bakeSprite = new cc.BakeSprite();
114         }
115     };
116 
117     p.unbake = function(){
118         if (this._isBaked) {
119             this._isBaked = false;
120             this._cacheDirty = true;
121 
122             this._cachedParent = null;
123             var children = this._children;
124             for(var i = 0, len = children.length; i < len; i++)
125                 children[i]._setCachedParent(null);
126         }
127     };
128 
129     p.visit = function(ctx){
130         if(!this._isBaked){
131             cc.Node.prototype.visit.call(this, ctx);
132             return;
133         }
134 
135         var context = ctx || cc._renderContext, i;
136         var _t = this;
137         var children = _t._children;
138         var len = children.length;
139         // quick return if not visible
140         if (!_t._visible || len === 0)
141             return;
142 
143         var locBakeSprite = this._bakeSprite;
144 
145         context.save();
146         _t.transform(context);
147 
148         if(this._cacheDirty){
149             //compute the bounding box of the bake layer.
150             var boundingBox = this._getBoundingBoxForBake();
151             boundingBox.width = 0 | boundingBox.width;
152             boundingBox.height = 0 | boundingBox.height;
153             var bakeContext = locBakeSprite.getCacheContext();
154             locBakeSprite.resetCanvasSize(boundingBox.width, boundingBox.height);
155             bakeContext.translate(0 - boundingBox.x, boundingBox.height + boundingBox.y);
156 
157             //reset the bake sprite's position
158             var anchor = locBakeSprite.getAnchorPointInPoints();
159             locBakeSprite.setPosition(anchor.x + boundingBox.x, anchor.y + boundingBox.y);
160 
161             //visit for canvas
162             _t.sortAllChildren();
163             cc.view._setScaleXYForRenderTexture();
164             for (i = 0; i < len; i++) {
165                 children[i].visit(bakeContext);
166             }
167             cc.view._resetScale();
168             this._cacheDirty = false;
169         }
170 
171         //the bakeSprite is drawing
172         locBakeSprite.visit(context);
173 
174         _t.arrivalOrder = 0;
175         context.restore();
176     };
177 
178     p._getBoundingBoxForBake = function () {
179         var rect = null;
180 
181         //query child's BoundingBox
182         if (!this._children || this._children.length === 0)
183             return cc.rect(0, 0, 10, 10);
184 
185         var locChildren = this._children;
186         for (var i = 0; i < locChildren.length; i++) {
187             var child = locChildren[i];
188             if (child && child._visible) {
189                 if(rect){
190                     var childRect = child._getBoundingBoxToCurrentNode();
191                     if (childRect)
192                         rect = cc.rectUnion(rect, childRect);
193                 }else{
194                     rect = child._getBoundingBoxToCurrentNode();
195                 }
196             }
197         }
198         return rect;
199     };
200     p = null;
201 }else{
202     cc.assert(typeof cc._tmp.LayerDefineForWebGL === "function", cc._LogInfos.MissingFile, "CCLayerWebGL.js");
203     cc._tmp.LayerDefineForWebGL();
204     delete cc._tmp.LayerDefineForWebGL;
205 }
206 
207 /**
208  * <p>
209  * CCLayerColor is a subclass of CCLayer that implements the CCRGBAProtocol protocol.       <br/>
210  *  All features from CCLayer are valid, plus the following new features:                   <br/>
211  * - opacity                                                                     <br/>
212  * - RGB colors                                                                </p>
213  * @class
214  * @extends cc.Layer
215  *
216  * @param {cc.Color} [color=] The color of the layer
217  * @param {Number} [width=] The width of the layer
218  * @param {Number} [height=] The height of the layer
219  *
220  * @example
221  * // Example
222  * //Create a yellow color layer as background
223  * var yellowBackground = new cc.LayerColor(cc.color(255,255,0,255));
224  * //If you didnt pass in width and height, it defaults to the same size as the canvas
225  *
226  * //create a yellow box, 200 by 200 in size
227  * var yellowBox = new cc.LayerColor(cc.color(255,255,0,255), 200, 200);
228  */
229 cc.LayerColor = cc.Layer.extend(/** @lends cc.LayerColor# */{
230     _blendFunc: null,
231     _className: "LayerColor",
232 
233     /**
234      * Returns the blend function
235      * @return {cc.BlendFunc}
236      */
237     getBlendFunc: function () {
238         return this._blendFunc;
239     },
240 
241     /**
242      * Changes width and height
243      * @deprecated since v3.0 please use setContentSize instead
244      * @see cc.Node#setContentSize
245      * @param {Number} w width
246      * @param {Number} h height
247      */
248     changeWidthAndHeight: function (w, h) {
249         this.width = w;
250         this.height = h;
251     },
252 
253     /**
254      * Changes width in Points
255      * @deprecated since v3.0 please use setContentSize instead
256      * @see cc.Node#setContentSize
257      * @param {Number} w width
258      */
259     changeWidth: function (w) {
260         this.width = w;
261     },
262 
263     /**
264      * change height in Points
265      * @deprecated since v3.0 please use setContentSize instead
266      * @see cc.Node#setContentSize
267      * @param {Number} h height
268      */
269     changeHeight: function (h) {
270         this.height = h;
271     },
272 
273     setOpacityModifyRGB: function (value) {
274     },
275 
276     isOpacityModifyRGB: function () {
277         return false;
278     },
279 
280     setColor: function (color) {
281         cc.Layer.prototype.setColor.call(this, color);
282         this._updateColor();
283     },
284 
285     setOpacity: function (opacity) {
286         cc.Layer.prototype.setOpacity.call(this, opacity);
287         this._updateColor();
288     },
289 
290     _blendFuncStr: "source",
291 
292     /**
293      * Constructor of cc.LayerColor
294      * @function
295      * @param {cc.Color} [color=]
296      * @param {Number} [width=]
297      * @param {Number} [height=]
298      */
299     ctor: null,
300 
301     /**
302      * Initialization of the layer, please do not call this function by yourself, you should pass the parameters to constructor to initialize a layer
303      * @param {cc.Color} [color=]
304      * @param {Number} [width=]
305      * @param {Number} [height=]
306      * @return {Boolean}
307      */
308     init: function (color, width, height) {
309         if (cc._renderType !== cc._RENDER_TYPE_CANVAS)
310             this.shaderProgram = cc.shaderCache.programForKey(cc.SHADER_POSITION_COLOR);
311 
312         var winSize = cc.director.getWinSize();
313         color = color || cc.color(0, 0, 0, 255);
314         width = width === undefined ? winSize.width : width;
315         height = height === undefined ? winSize.height : height;
316 
317         var locDisplayedColor = this._displayedColor;
318         locDisplayedColor.r = color.r;
319         locDisplayedColor.g = color.g;
320         locDisplayedColor.b = color.b;
321 
322         var locRealColor = this._realColor;
323         locRealColor.r = color.r;
324         locRealColor.g = color.g;
325         locRealColor.b = color.b;
326 
327         this._displayedOpacity = color.a;
328         this._realOpacity = color.a;
329 
330         var proto = cc.LayerColor.prototype;
331         proto.setContentSize.call(this, width, height);
332         proto._updateColor.call(this);
333         return true;
334     },
335 
336     /**
337      * Sets the blend func, you can pass either a cc.BlendFunc object or source and destination value separately
338      * @param {Number|cc.BlendFunc} src
339      * @param {Number} [dst]
340      */
341     setBlendFunc: function (src, dst) {
342         var _t = this, locBlendFunc = this._blendFunc;
343         if (dst === undefined) {
344             locBlendFunc.src = src.src;
345             locBlendFunc.dst = src.dst;
346         } else {
347             locBlendFunc.src = src;
348             locBlendFunc.dst = dst;
349         }
350         if (cc._renderType === cc._RENDER_TYPE_CANVAS)
351             _t._blendFuncStr = cc._getCompositeOperationByBlendFunc(locBlendFunc);
352     },
353 
354     _setWidth: null,
355 
356     _setHeight: null,
357 
358     _updateColor: null,
359 
360     updateDisplayedColor: function (parentColor) {
361         cc.Layer.prototype.updateDisplayedColor.call(this, parentColor);
362         this._updateColor();
363     },
364 
365     updateDisplayedOpacity: function (parentOpacity) {
366         cc.Layer.prototype.updateDisplayedOpacity.call(this, parentOpacity);
367         this._updateColor();
368     },
369 
370     draw: null
371 });
372 
373 /**
374  * Creates a cc.Layer with color, width and height in Points
375  * @deprecated since v3.0 please use the new construction instead
376  * @see cc.LayerColor
377  * @param {cc.Color} color
378  * @param {Number|Null} [width=]
379  * @param {Number|Null} [height=]
380  * @return {cc.LayerColor}
381  */
382 cc.LayerColor.create = function (color, width, height) {
383     return new cc.LayerColor(color, width, height);
384 };
385 
386 if (cc._renderType === cc._RENDER_TYPE_CANVAS) {
387     //cc.LayerColor define start
388     var _p = cc.LayerColor.prototype;
389     _p.ctor = function (color, width, height) {
390         cc.Layer.prototype.ctor.call(this);
391         this._blendFunc = new cc.BlendFunc(cc.BLEND_SRC, cc.BLEND_DST);
392         cc.LayerColor.prototype.init.call(this, color, width, height);
393     };
394     _p._setWidth = cc.Layer.prototype._setWidth;
395     _p._setHeight = cc.Layer.prototype._setHeight;
396     _p._updateColor = function () {
397     };
398     _p.draw = function (ctx) {
399         var context = ctx || cc._renderContext, _t = this;
400         var locEGLViewer = cc.view, locDisplayedColor = _t._displayedColor;
401 
402         context.fillStyle = "rgba(" + (0 | locDisplayedColor.r) + "," + (0 | locDisplayedColor.g) + ","
403             + (0 | locDisplayedColor.b) + "," + _t._displayedOpacity / 255 + ")";
404         context.fillRect(0, 0, _t.width * locEGLViewer.getScaleX(), -_t.height * locEGLViewer.getScaleY());
405         cc.g_NumberOfDraws++;
406     };
407 
408     //for bake
409     _p.visit = function(ctx){
410         if(!this._isBaked){
411             cc.Node.prototype.visit.call(this, ctx);
412             return;
413         }
414 
415         var context = ctx || cc._renderContext, i;
416         var _t = this;
417         var children = _t._children;
418         var len = children.length;
419         // quick return if not visible
420         if (!_t._visible)
421             return;
422 
423         var locBakeSprite = this._bakeSprite;
424 
425         context.save();
426         _t.transform(context);
427 
428         if(this._cacheDirty){
429             //compute the bounding box of the bake layer.
430             var boundingBox = this._getBoundingBoxForBake();
431             boundingBox.width = 0 | boundingBox.width;
432             boundingBox.height = 0 | boundingBox.height;
433             var bakeContext = locBakeSprite.getCacheContext();
434             locBakeSprite.resetCanvasSize(boundingBox.width, boundingBox.height);
435             var anchor = locBakeSprite.getAnchorPointInPoints(), locPos = this._position;
436             if(this._ignoreAnchorPointForPosition){
437                 bakeContext.translate(0 - boundingBox.x + locPos.x, boundingBox.height + boundingBox.y - locPos.y);
438                 //reset the bake sprite's position
439                 locBakeSprite.setPosition(anchor.x + boundingBox.x - locPos.x, anchor.y + boundingBox.y - locPos.y);
440             } else {
441                 var selfAnchor = this.getAnchorPointInPoints();
442                 var selfPos = {x: locPos.x - selfAnchor.x, y: locPos.y - selfAnchor.y};
443                 bakeContext.translate(0 - boundingBox.x + selfPos.x, boundingBox.height + boundingBox.y - selfPos.y);
444                 locBakeSprite.setPosition(anchor.x + boundingBox.x - selfPos.x, anchor.y + boundingBox.y - selfPos.y);
445             }
446 
447             var child;
448             cc.view._setScaleXYForRenderTexture();
449             //visit for canvas
450             if (len > 0) {
451                 _t.sortAllChildren();
452                 // draw children zOrder < 0
453                 for (i = 0; i < len; i++) {
454                     child = children[i];
455                     if (child._localZOrder < 0)
456                         child.visit(bakeContext);
457                     else
458                         break;
459                 }
460                 _t.draw(bakeContext);
461                 for (; i < len; i++) {
462                     children[i].visit(bakeContext);
463                 }
464             } else
465                 _t.draw(bakeContext);
466             cc.view._resetScale();
467             this._cacheDirty = false;
468         }
469 
470         //the bakeSprite is drawing
471         locBakeSprite.visit(context);
472 
473         _t.arrivalOrder = 0;
474         context.restore();
475     };
476 
477     _p._getBoundingBoxForBake = function () {
478         //default size
479         var rect = cc.rect(0, 0, this._contentSize.width, this._contentSize.height);
480         var trans = this.nodeToWorldTransform();
481         rect = cc.rectApplyAffineTransform(rect, this.nodeToWorldTransform());
482 
483         //query child's BoundingBox
484         if (!this._children || this._children.length === 0)
485             return rect;
486 
487         var locChildren = this._children;
488         for (var i = 0; i < locChildren.length; i++) {
489             var child = locChildren[i];
490             if (child && child._visible) {
491                 var childRect = child._getBoundingBoxToCurrentNode(trans);
492                 rect = cc.rectUnion(rect, childRect);
493             }
494         }
495         return rect;
496     };
497 
498     //cc.LayerColor define end
499     _p = null;
500 } else {
501     cc.assert(typeof cc._tmp.WebGLLayerColor === "function", cc._LogInfos.MissingFile, "CCLayerWebGL.js");
502     cc._tmp.WebGLLayerColor();
503     delete cc._tmp.WebGLLayerColor;
504 }
505 
506 cc.assert(typeof cc._tmp.PrototypeLayerColor === "function", cc._LogInfos.MissingFile, "CCLayerPropertyDefine.js");
507 cc._tmp.PrototypeLayerColor();
508 delete cc._tmp.PrototypeLayerColor;
509 
510 /**
511  * <p>
512  * CCLayerGradient is a subclass of cc.LayerColor that draws gradients across the background.<br/>
513  *<br/>
514  * All features from cc.LayerColor are valid, plus the following new features:<br/>
515  * <ul><li>direction</li>
516  * <li>final color</li>
517  * <li>interpolation mode</li></ul>
518  * <br/>
519  * Color is interpolated between the startColor and endColor along the given<br/>
520  * vector (starting at the origin, ending at the terminus).  If no vector is<br/>
521  * supplied, it defaults to (0, -1) -- a fade from top to bottom.<br/>
522  * <br/>
523  * If 'compressedInterpolation' is disabled, you will not see either the start or end color for<br/>
524  * non-cardinal vectors; a smooth gradient implying both end points will be still<br/>
525  * be drawn, however.<br/>
526  *<br/>
527  * If 'compressedInterpolation' is enabled (default mode) you will see both the start and end colors of the gradient.
528  * </p>
529  * @class
530  * @extends cc.LayerColor
531  *
532  * @param {cc.Color} start Starting color
533  * @param {cc.Color} end Ending color
534  * @param {cc.Point} [v=cc.p(0, -1)] A vector defines the gradient direction, default direction is from top to bottom
535  *
536  * @property {cc.Color} startColor              - Start color of the color gradient
537  * @property {cc.Color} endColor                - End color of the color gradient
538  * @property {Number}   startOpacity            - Start opacity of the color gradient
539  * @property {Number}   endOpacity              - End opacity of the color gradient
540  * @property {Number}   vector                  - Direction vector of the color gradient
541  * @property {Number}   compresseInterpolation  - Indicate whether or not the interpolation will be compressed
542  */
543 cc.LayerGradient = cc.LayerColor.extend(/** @lends cc.LayerGradient# */{
544     _startColor: null,
545     _endColor: null,
546     _startOpacity: 255,
547     _endOpacity: 255,
548     _alongVector: null,
549     _compressedInterpolation: false,
550     _gradientStartPoint: null,
551     _gradientEndPoint: null,
552     _className: "LayerGradient",
553 
554     /**
555      * Constructor of cc.LayerGradient
556      * @param {cc.Color} start
557      * @param {cc.Color} end
558      * @param {cc.Point} [v=cc.p(0, -1)]
559      */
560     ctor: function (start, end, v) {
561         var _t = this;
562         cc.LayerColor.prototype.ctor.call(_t);
563 
564         _t._startColor = cc.color(0, 0, 0, 255);
565         _t._endColor = cc.color(0, 0, 0, 255);
566         _t._alongVector = cc.p(0, -1);
567         _t._startOpacity = 255;
568         _t._endOpacity = 255;
569         _t._gradientStartPoint = cc.p(0, 0);
570         _t._gradientEndPoint = cc.p(0, 0);
571         cc.LayerGradient.prototype.init.call(_t, start, end, v);
572     },
573 
574     /**
575      * Initialization of the layer, please do not call this function by yourself, you should pass the parameters to constructor to initialize a layer
576      * @param {cc.Color} start starting color
577      * @param {cc.Color} end
578      * @param {cc.Point|Null} v
579      * @return {Boolean}
580      */
581     init: function (start, end, v) {
582         start = start || cc.color(0, 0, 0, 255);
583         end = end || cc.color(0, 0, 0, 255);
584         v = v || cc.p(0, -1);
585         var _t = this;
586 
587         // Initializes the CCLayer with a gradient between start and end in the direction of v.
588         var locStartColor = _t._startColor, locEndColor = _t._endColor;
589         locStartColor.r = start.r;
590         locStartColor.g = start.g;
591         locStartColor.b = start.b;
592         _t._startOpacity = start.a;
593 
594         locEndColor.r = end.r;
595         locEndColor.g = end.g;
596         locEndColor.b = end.b;
597         _t._endOpacity = end.a;
598 
599         _t._alongVector = v;
600         _t._compressedInterpolation = true;
601         _t._gradientStartPoint = cc.p(0, 0);
602         _t._gradientEndPoint = cc.p(0, 0);
603 
604         cc.LayerColor.prototype.init.call(_t, cc.color(start.r, start.g, start.b, 255));
605         cc.LayerGradient.prototype._updateColor.call(_t);
606         return true;
607     },
608 
609     /**
610      * Sets the untransformed size of the LayerGradient.
611      * @param {cc.Size|Number} size The untransformed size of the LayerGradient or The untransformed size's width of the LayerGradient.
612      * @param {Number} [height] The untransformed size's height of the LayerGradient.
613      */
614     setContentSize: function (size, height) {
615         cc.LayerColor.prototype.setContentSize.call(this, size, height);
616         this._updateColor();
617     },
618 
619     _setWidth: function (width) {
620         cc.LayerColor.prototype._setWidth.call(this, width);
621         this._updateColor();
622     },
623     _setHeight: function (height) {
624         cc.LayerColor.prototype._setHeight.call(this, height);
625         this._updateColor();
626     },
627 
628     /**
629      * Returns the starting color
630      * @return {cc.Color}
631      */
632     getStartColor: function () {
633         return this._realColor;
634     },
635 
636     /**
637      * Sets the starting color
638      * @param {cc.Color} color
639      * @example
640      * // Example
641      * myGradientLayer.setStartColor(cc.color(255,0,0));
642      * //set the starting gradient to red
643      */
644     setStartColor: function (color) {
645         this.color = color;
646     },
647 
648     /**
649      * Sets the end gradient color
650      * @param {cc.Color} color
651      * @example
652      * // Example
653      * myGradientLayer.setEndColor(cc.color(255,0,0));
654      * //set the ending gradient to red
655      */
656     setEndColor: function (color) {
657         this._endColor = color;
658         this._updateColor();
659     },
660 
661     /**
662      * Returns the end color
663      * @return {cc.Color}
664      */
665     getEndColor: function () {
666         return this._endColor;
667     },
668 
669     /**
670      * Sets starting gradient opacity
671      * @param {Number} o from 0 to 255, 0 is transparent
672      */
673     setStartOpacity: function (o) {
674         this._startOpacity = o;
675         this._updateColor();
676     },
677 
678     /**
679      * Returns the starting gradient opacity
680      * @return {Number}
681      */
682     getStartOpacity: function () {
683         return this._startOpacity;
684     },
685 
686     /**
687      * Sets the end gradient opacity
688      * @param {Number} o
689      */
690     setEndOpacity: function (o) {
691         this._endOpacity = o;
692         this._updateColor();
693     },
694 
695     /**
696      * Returns the end gradient opacity
697      * @return {Number}
698      */
699     getEndOpacity: function () {
700         return this._endOpacity;
701     },
702 
703     /**
704      * Sets the direction vector of the gradient
705      * @param {cc.Point} Var
706      */
707     setVector: function (Var) {
708         this._alongVector.x = Var.x;
709         this._alongVector.y = Var.y;
710         this._updateColor();
711     },
712 
713     /**
714      * Returns the direction vector of the gradient
715      * @return {cc.Point}
716      */
717     getVector: function () {
718         return cc.p(this._alongVector.x, this._alongVector.y);
719     },
720 
721     /**
722      * Returns whether compressed interpolation is enabled
723      * @return {Boolean}
724      */
725     isCompressedInterpolation: function () {
726         return this._compressedInterpolation;
727     },
728 
729     /**
730      * Sets whether compressed interpolation is enabled
731      * @param {Boolean} compress
732      */
733     setCompressedInterpolation: function (compress) {
734         this._compressedInterpolation = compress;
735         this._updateColor();
736     },
737 
738     _draw: null,
739 
740     _updateColor: null
741 });
742 
743 /**
744  * Creates a gradient layer
745  * @deprecated since v3.0, please use the new construction instead
746  * @see cc.layerGradient
747  * @param {cc.Color} start starting color
748  * @param {cc.Color} end ending color
749  * @param {cc.Point|Null} v
750  * @return {cc.LayerGradient}
751  */
752 cc.LayerGradient.create = function (start, end, v) {
753     return new cc.LayerGradient(start, end, v);
754 };
755 
756 
757 if (cc._renderType === cc._RENDER_TYPE_CANVAS) {
758     //cc.LayerGradient define start
759     var _p = cc.LayerGradient.prototype;
760     _p.draw = function (ctx) {
761         var context = ctx || cc._renderContext, _t = this;
762         if (_t._blendFuncStr != "source")
763             context.globalCompositeOperation = _t._blendFuncStr;
764 
765         context.save();
766         var opacityf = _t._displayedOpacity / 255.0;
767         var scaleX = cc.view.getScaleX(), scaleY = cc.view.getScaleY();
768         var tWidth = _t.width * scaleX, tHeight = _t.height * scaleY;
769         var tGradient = context.createLinearGradient(_t._gradientStartPoint.x * scaleX, _t._gradientStartPoint.y * scaleY,
770             _t._gradientEndPoint.x * scaleX, _t._gradientEndPoint.y * scaleY);
771         var locDisplayedColor = _t._displayedColor, locEndColor = _t._endColor;
772         tGradient.addColorStop(0, "rgba(" + Math.round(locDisplayedColor.r) + "," + Math.round(locDisplayedColor.g) + ","
773             + Math.round(locDisplayedColor.b) + "," + (opacityf * (_t._startOpacity / 255)).toFixed(4) + ")");
774         tGradient.addColorStop(1, "rgba(" + Math.round(locEndColor.r) + "," + Math.round(locEndColor.g) + ","
775             + Math.round(locEndColor.b) + "," + (opacityf * (_t._endOpacity / 255)).toFixed(4) + ")");
776         context.fillStyle = tGradient;
777         context.fillRect(0, 0, tWidth, -tHeight);
778 
779         if (_t._rotation != 0)
780             context.rotate(_t._rotationRadians);
781         context.restore();
782         cc.g_NumberOfDraws++;
783     };
784     _p._updateColor = function () {
785         var _t = this;
786         var locAlongVector = _t._alongVector, tWidth = _t.width * 0.5, tHeight = _t.height * 0.5;
787 
788         _t._gradientStartPoint.x = tWidth * (-locAlongVector.x) + tWidth;
789         _t._gradientStartPoint.y = tHeight * locAlongVector.y - tHeight;
790         _t._gradientEndPoint.x = tWidth * locAlongVector.x + tWidth;
791         _t._gradientEndPoint.y = tHeight * (-locAlongVector.y) - tHeight;
792     };
793     //cc.LayerGradient define end
794     _p = null;
795 } else {
796     cc.assert(typeof cc._tmp.WebGLLayerGradient === "function", cc._LogInfos.MissingFile, "CCLayerWebGL.js");
797     cc._tmp.WebGLLayerGradient();
798     delete cc._tmp.WebGLLayerGradient;
799 }
800 
801 cc.assert(typeof cc._tmp.PrototypeLayerGradient === "function", cc._LogInfos.MissingFile, "CCLayerPropertyDefine.js");
802 cc._tmp.PrototypeLayerGradient();
803 delete cc._tmp.PrototypeLayerGradient;
804 
805 /**
806  * CCMultipleLayer is a CCLayer with the ability to multiplex it's children.<br/>
807  * Features:<br/>
808  *  <ul><li>- It supports one or more children</li>
809  *  <li>- Only one children will be active a time</li></ul>
810  * @class
811  * @extends cc.Layer
812  * @param {Array} layers an array of cc.Layer
813  * @example
814  * // Example
815  * var multiLayer = new cc.LayerMultiple(layer1, layer2, layer3);//any number of layers
816  */
817 cc.LayerMultiplex = cc.Layer.extend(/** @lends cc.LayerMultiplex# */{
818     _enabledLayer: 0,
819     _layers: null,
820     _className: "LayerMultiplex",
821 
822     /**
823      * Constructor of cc.LayerMultiplex
824      * @param {Array} layers an array of cc.Layer
825      */
826     ctor: function (layers) {
827         cc.Layer.prototype.ctor.call(this);
828         if (layers instanceof Array)
829             cc.LayerMultiplex.prototype.initWithLayers.call(this, layers);
830         else
831             cc.LayerMultiplex.prototype.initWithLayers.call(this, Array.prototype.slice.call(arguments));
832     },
833 
834     /**
835      * Initialization of the layer multiplex, please do not call this function by yourself, you should pass the parameters to constructor to initialize a layer multiplex
836      * @param {Array} layers an array of cc.Layer
837      * @return {Boolean}
838      */
839     initWithLayers: function (layers) {
840         if ((layers.length > 0) && (layers[layers.length - 1] == null))
841             cc.log(cc._LogInfos.LayerMultiplex_initWithLayers);
842 
843         this._layers = layers;
844         this._enabledLayer = 0;
845         this.addChild(this._layers[this._enabledLayer]);
846         return true;
847     },
848 
849     /**
850      * Switches to a certain layer indexed by n.<br/>
851      * The current (old) layer will be removed from it's parent with 'cleanup:YES'.
852      * @param {Number} n the layer index to switch to
853      */
854     switchTo: function (n) {
855         if (n >= this._layers.length) {
856             cc.log(cc._LogInfos.LayerMultiplex_switchTo);
857             return;
858         }
859 
860         this.removeChild(this._layers[this._enabledLayer], true);
861         this._enabledLayer = n;
862         this.addChild(this._layers[n]);
863     },
864 
865     /**
866      * Release the current layer and switches to another layer indexed by n.<br/>
867      * The current (old) layer will be removed from it's parent with 'cleanup:YES'.
868      * @param {Number} n the layer index to switch to
869      */
870     switchToAndReleaseMe: function (n) {
871         if (n >= this._layers.length) {
872             cc.log(cc._LogInfos.LayerMultiplex_switchToAndReleaseMe);
873             return;
874         }
875 
876         this.removeChild(this._layers[this._enabledLayer], true);
877 
878         //[layers replaceObjectAtIndex:_enabledLayer withObject:[NSNull null]];
879         this._layers[this._enabledLayer] = null;
880         this._enabledLayer = n;
881         this.addChild(this._layers[n]);
882     },
883 
884     /**
885      * Add a layer to the multiplex layers list
886      * @param {cc.Layer} layer
887      */
888     addLayer: function (layer) {
889         if (!layer) {
890             cc.log(cc._LogInfos.LayerMultiplex_addLayer);
891             return;
892         }
893         this._layers.push(layer);
894     }
895 });
896 
897 /**
898  * Creates a cc.LayerMultiplex with one or more layers using a variable argument list.
899  * @deprecated since v3.0, please use new construction instead
900  * @see cc.LayerMultiplex
901  * @return {cc.LayerMultiplex|Null}
902  */
903 cc.LayerMultiplex.create = function (/*Multiple Arguments*/) {
904     return new cc.LayerMultiplex(Array.prototype.slice.call(arguments));
905 };