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