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