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     _className: "Layer",
 34 
 35     /**
 36      * <p>Constructor of cc.Layer, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function.</p>
 37      */
 38     ctor: function () {
 39         var nodep = cc.Node.prototype;
 40         nodep.ctor.call(this);
 41         this._ignoreAnchorPointForPosition = true;
 42         nodep.setAnchorPoint.call(this, 0.5, 0.5);
 43         nodep.setContentSize.call(this, cc.winSize);
 44     },
 45 
 46     /**
 47      * Initialization of the layer, please do not call this function by yourself, you should pass the parameters to constructor to initialize a layer
 48      */
 49     init: function(){
 50         var _t = this;
 51         _t._ignoreAnchorPointForPosition = true;
 52         _t.setAnchorPoint(0.5, 0.5);
 53         _t.setContentSize(cc.winSize);
 54         _t._cascadeColorEnabled = false;
 55         _t._cascadeOpacityEnabled = false;
 56         return true;
 57     },
 58 
 59     /**
 60      * Sets the layer to cache all of children to a bake sprite, and draw itself by bake sprite. recommend using it in UI.<br/>
 61      * This is useful only in html5 engine
 62      * @function
 63      * @see cc.Layer#unbake
 64      */
 65     bake: function(){
 66         this._renderCmd.bake();
 67     },
 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: function(){
 76         this._renderCmd.unbake();
 77     },
 78 
 79     /**
 80      * Determines if the layer is baked.
 81      * @function
 82      * @returns {boolean}
 83      * @see cc.Layer#bake and cc.Layer#unbake
 84      */
 85     isBaked: function(){
 86         return this._isBaked;
 87     },
 88 
 89     addChild: function(child, localZOrder, tag){
 90         cc.Node.prototype.addChild.call(this, child, localZOrder, tag);
 91         this._renderCmd._bakeForAddChild(child);
 92     },
 93 
 94     _createRenderCmd: function(){
 95         if (cc._renderType === cc._RENDER_TYPE_CANVAS)
 96             return new cc.Layer.CanvasRenderCmd(this);
 97         else
 98             return new cc.Layer.WebGLRenderCmd(this);
 99     }
100 });
101 
102 /**
103  * Creates a layer
104  * @deprecated since v3.0, please use the new construction instead
105  * @see cc.Layer
106  * @return {cc.Layer|Null}
107  */
108 cc.Layer.create = function () {
109     return new cc.Layer();
110 };
111 
112 /**
113  * <p>
114  * CCLayerColor is a subclass of CCLayer that implements the CCRGBAProtocol protocol.       <br/>
115  *  All features from CCLayer are valid, plus the following new features:                   <br/>
116  * - opacity                                                                     <br/>
117  * - RGB colors                                                                  </p>
118  * @class
119  * @extends cc.Layer
120  *
121  * @param {cc.Color} [color=] The color of the layer
122  * @param {Number} [width=] The width of the layer
123  * @param {Number} [height=] The height of the layer
124  *
125  * @example
126  * // Example
127  * //Create a yellow color layer as background
128  * var yellowBackground = new cc.LayerColor(cc.color(255,255,0,255));
129  * //If you didn't pass in width and height, it defaults to the same size as the canvas
130  *
131  * //create a yellow box, 200 by 200 in size
132  * var yellowBox = new cc.LayerColor(cc.color(255,255,0,255), 200, 200);
133  */
134 cc.LayerColor = cc.Layer.extend(/** @lends cc.LayerColor# */{
135     _blendFunc: null,
136     _className: "LayerColor",
137 
138     /**
139      * Returns the blend function
140      * @return {cc.BlendFunc}
141      */
142     getBlendFunc: function () {
143         return this._blendFunc;
144     },
145 
146     /**
147      * Changes width and height
148      * @deprecated since v3.0 please use setContentSize instead
149      * @see cc.Node#setContentSize
150      * @param {Number} w width
151      * @param {Number} h height
152      */
153     changeWidthAndHeight: function (w, h) {
154         this.width = w;
155         this.height = h;
156     },
157 
158     /**
159      * Changes width in Points
160      * @deprecated since v3.0 please use setContentSize instead
161      * @see cc.Node#setContentSize
162      * @param {Number} w width
163      */
164     changeWidth: function (w) {
165         this.width = w;
166     },
167 
168     /**
169      * change height in Points
170      * @deprecated since v3.0 please use setContentSize instead
171      * @see cc.Node#setContentSize
172      * @param {Number} h height
173      */
174     changeHeight: function (h) {
175         this.height = h;
176     },
177 
178     setOpacityModifyRGB: function (value) {
179     },
180 
181     isOpacityModifyRGB: function () {
182         return false;
183     },
184 
185     /**
186      * Constructor of cc.LayerColor
187      * @function
188      * @param {cc.Color} [color=]
189      * @param {Number} [width=]
190      * @param {Number} [height=]
191      */
192     ctor: function(color, width, height){
193         cc.Layer.prototype.ctor.call(this);
194         this._blendFunc = new cc.BlendFunc(cc.BLEND_SRC, cc.BLEND_DST);
195         cc.LayerColor.prototype.init.call(this, color, width, height);
196     },
197 
198     /**
199      * Initialization of the layer, please do not call this function by yourself, you should pass the parameters to constructor to initialize a layer
200      * @param {cc.Color} [color=]
201      * @param {Number} [width=]
202      * @param {Number} [height=]
203      * @return {Boolean}
204      */
205     init: function (color, width, height) {
206         if (cc._renderType !== cc._RENDER_TYPE_CANVAS)
207             this.shaderProgram = cc.shaderCache.programForKey(cc.SHADER_POSITION_COLOR);
208 
209         var winSize = cc.director.getWinSize();
210         color = color || cc.color(0, 0, 0, 255);
211         width = width === undefined ? winSize.width : width;
212         height = height === undefined ? winSize.height : height;
213 
214         var locRealColor = this._realColor;
215         locRealColor.r = color.r;
216         locRealColor.g = color.g;
217         locRealColor.b = color.b;
218         this._realOpacity = color.a;
219         this._renderCmd.setDirtyFlag(cc.Node._dirtyFlags.colorDirty|cc.Node._dirtyFlags.opacityDirty);
220 
221         cc.LayerColor.prototype.setContentSize.call(this, width, height);
222         return true;
223     },
224 
225     /**
226      * Sets the blend func, you can pass either a cc.BlendFunc object or source and destination value separately
227      * @param {Number|cc.BlendFunc} src
228      * @param {Number} [dst]
229      */
230     setBlendFunc: function (src, dst) {
231         var locBlendFunc = this._blendFunc;
232         if (dst === undefined) {
233             locBlendFunc.src = src.src;
234             locBlendFunc.dst = src.dst;
235         } else {
236             locBlendFunc.src = src;
237             locBlendFunc.dst = dst;
238         }
239         this._renderCmd.updateBlendFunc(locBlendFunc);
240     },
241 
242     _setWidth: function(width){
243         cc.Node.prototype._setWidth.call(this, width);
244         this._renderCmd._updateSquareVerticesWidth(width);
245     },
246 
247     _setHeight: function(height){
248         cc.Node.prototype._setHeight.call(this, height);
249         this._renderCmd._updateSquareVerticesHeight(height);
250     },
251 
252     setContentSize: function(size, height){
253         cc.Layer.prototype.setContentSize.call(this, size, height);
254         this._renderCmd._updateSquareVertices(size, height);
255     },
256 
257     _createRenderCmd: function(){
258         if (cc._renderType === cc._RENDER_TYPE_CANVAS)
259             return new cc.LayerColor.CanvasRenderCmd(this);
260         else
261             return new cc.LayerColor.WebGLRenderCmd(this);
262     }
263 });
264 
265 /**
266  * Creates a cc.Layer with color, width and height in Points
267  * @deprecated since v3.0 please use the new construction instead
268  * @see cc.LayerColor
269  * @param {cc.Color} color
270  * @param {Number|Null} [width=]
271  * @param {Number|Null} [height=]
272  * @return {cc.LayerColor}
273  */
274 cc.LayerColor.create = function (color, width, height) {
275     return new cc.LayerColor(color, width, height);
276 };
277 
278 //LayerColor - Getter Setter
279 (function(){
280     var proto = cc.LayerColor.prototype;
281     cc.defineGetterSetter(proto, "width", proto._getWidth, proto._setWidth);
282     cc.defineGetterSetter(proto, "height", proto._getHeight, proto._setHeight);
283 })();
284 
285 /**
286  * <p>
287  * CCLayerGradient is a subclass of cc.LayerColor that draws gradients across the background.<br/>
288  *<br/>
289  * All features from cc.LayerColor are valid, plus the following new features:<br/>
290  * <ul><li>direction</li>
291  * <li>final color</li>
292  * <li>interpolation mode</li></ul>
293  * <br/>
294  * Color is interpolated between the startColor and endColor along the given<br/>
295  * vector (starting at the origin, ending at the terminus).  If no vector is<br/>
296  * supplied, it defaults to (0, -1) -- a fade from top to bottom.<br/>
297  * <br/>
298  * If 'compressedInterpolation' is disabled, you will not see either the start or end color for<br/>
299  * non-cardinal vectors; a smooth gradient implying both end points will be still<br/>
300  * be drawn, however.<br/>
301  *<br/>
302  * If 'compressedInterpolation' is enabled (default mode) you will see both the start and end colors of the gradient.
303  * </p>
304  * @class
305  * @extends cc.LayerColor
306  *
307  * @param {cc.Color} start Starting color
308  * @param {cc.Color} end Ending color
309  * @param {cc.Point} [v=cc.p(0, -1)] A vector defines the gradient direction, default direction is from top to bottom
310  *
311  * @property {cc.Color} startColor              - Start color of the color gradient
312  * @property {cc.Color} endColor                - End color of the color gradient
313  * @property {Number}   startOpacity            - Start opacity of the color gradient
314  * @property {Number}   endOpacity              - End opacity of the color gradient
315  * @property {Number}   vector                  - Direction vector of the color gradient
316  * @property {Number}   compresseInterpolation  - Indicate whether or not the interpolation will be compressed
317  */
318 cc.LayerGradient = cc.LayerColor.extend(/** @lends cc.LayerGradient# */{
319     _endColor: null,
320     _startOpacity: 255,
321     _endOpacity: 255,
322     _alongVector: null,
323     _compressedInterpolation: false,
324     _className: "LayerGradient",
325 
326     /**
327      * Constructor of cc.LayerGradient
328      * @param {cc.Color} start
329      * @param {cc.Color} end
330      * @param {cc.Point} [v=cc.p(0, -1)]
331      */
332     ctor: function (start, end, v) {
333         var _t = this;
334         cc.LayerColor.prototype.ctor.call(_t);
335         _t._endColor = cc.color(0, 0, 0, 255);
336         _t._alongVector = cc.p(0, -1);
337         _t._startOpacity = 255;
338         _t._endOpacity = 255;
339         cc.LayerGradient.prototype.init.call(_t, start, end, v);
340     },
341 
342     /**
343      * Initialization of the layer, please do not call this function by yourself, you should pass the parameters to constructor to initialize a layer
344      * @param {cc.Color} start starting color
345      * @param {cc.Color} end
346      * @param {cc.Point|Null} v
347      * @return {Boolean}
348      */
349     init: function (start, end, v) {
350         start = start || cc.color(0, 0, 0, 255);
351         end = end || cc.color(0, 0, 0, 255);
352         v = v || cc.p(0, -1);
353         var _t = this;
354 
355         // Initializes the CCLayer with a gradient between start and end in the direction of v.
356         var locEndColor = _t._endColor;
357         _t._startOpacity = start.a;
358 
359         locEndColor.r = end.r;
360         locEndColor.g = end.g;
361         locEndColor.b = end.b;
362         _t._endOpacity = end.a;
363 
364         _t._alongVector = v;
365         _t._compressedInterpolation = true;
366 
367         cc.LayerColor.prototype.init.call(_t, cc.color(start.r, start.g, start.b, 255));
368         this._renderCmd.setDirtyFlag(cc.Node._dirtyFlags.colorDirty|cc.Node._dirtyFlags.opacityDirty|cc.Node._dirtyFlags.gradientDirty);
369         return true;
370     },
371 
372     /**
373      * Sets the untransformed size of the LayerGradient.
374      * @param {cc.Size|Number} size The untransformed size of the LayerGradient or The untransformed size's width of the LayerGradient.
375      * @param {Number} [height] The untransformed size's height of the LayerGradient.
376      */
377     setContentSize: function (size, height) {
378         cc.LayerColor.prototype.setContentSize.call(this, size, height);
379         this._renderCmd.setDirtyFlag(cc.Node._dirtyFlags.gradientDirty);
380     },
381 
382     _setWidth: function (width) {
383         cc.LayerColor.prototype._setWidth.call(this, width);
384         this._renderCmd.setDirtyFlag(cc.Node._dirtyFlags.gradientDirty);
385     },
386     _setHeight: function (height) {
387         cc.LayerColor.prototype._setHeight.call(this, height);
388         this._renderCmd.setDirtyFlag(cc.Node._dirtyFlags.gradientDirty);
389     },
390 
391     /**
392      * Returns the starting color
393      * @return {cc.Color}
394      */
395     getStartColor: function () {
396         return this._realColor;
397     },
398 
399     /**
400      * Sets the starting color
401      * @param {cc.Color} color
402      * @example
403      * // Example
404      * myGradientLayer.setStartColor(cc.color(255,0,0));
405      * //set the starting gradient to red
406      */
407     setStartColor: function (color) {
408         this.color = color;
409     },
410 
411     /**
412      * Sets the end gradient color
413      * @param {cc.Color} color
414      * @example
415      * // Example
416      * myGradientLayer.setEndColor(cc.color(255,0,0));
417      * //set the ending gradient to red
418      */
419     setEndColor: function (color) {
420         this._endColor = color;
421         this._renderCmd.setDirtyFlag(cc.Node._dirtyFlags.colorDirty);
422     },
423 
424     /**
425      * Returns the end color
426      * @return {cc.Color}
427      */
428     getEndColor: function () {
429         return this._endColor;
430     },
431 
432     /**
433      * Sets starting gradient opacity
434      * @param {Number} o from 0 to 255, 0 is transparent
435      */
436     setStartOpacity: function (o) {
437         this._startOpacity = o;
438         this._renderCmd.setDirtyFlag(cc.Node._dirtyFlags.opacityDirty);
439     },
440 
441     /**
442      * Returns the starting gradient opacity
443      * @return {Number}
444      */
445     getStartOpacity: function () {
446         return this._startOpacity;
447     },
448 
449     /**
450      * Sets the end gradient opacity
451      * @param {Number} o
452      */
453     setEndOpacity: function (o) {
454         this._endOpacity = o;
455         this._renderCmd.setDirtyFlag(cc.Node._dirtyFlags.opacityDirty);
456     },
457 
458     /**
459      * Returns the end gradient opacity
460      * @return {Number}
461      */
462     getEndOpacity: function () {
463         return this._endOpacity;
464     },
465 
466     /**
467      * Sets the direction vector of the gradient
468      * @param {cc.Point} Var
469      */
470     setVector: function (Var) {
471         this._alongVector.x = Var.x;
472         this._alongVector.y = Var.y;
473         this._renderCmd.setDirtyFlag(cc.Node._dirtyFlags.gradientDirty);
474     },
475 
476     /**
477      * Returns the direction vector of the gradient
478      * @return {cc.Point}
479      */
480     getVector: function () {
481         return cc.p(this._alongVector.x, this._alongVector.y);
482     },
483 
484     /**
485      * Returns whether compressed interpolation is enabled
486      * @return {Boolean}
487      */
488     isCompressedInterpolation: function () {
489         return this._compressedInterpolation;
490     },
491 
492     /**
493      * Sets whether compressed interpolation is enabled
494      * @param {Boolean} compress
495      */
496     setCompressedInterpolation: function (compress) {
497         this._compressedInterpolation = compress;
498         this._renderCmd.setDirtyFlag(cc.Node._dirtyFlags.gradientDirty);
499     },
500 
501     _createRenderCmd: function(){
502         if (cc._renderType === cc._RENDER_TYPE_CANVAS)
503             return new cc.LayerGradient.CanvasRenderCmd(this);
504         else
505             return new cc.LayerGradient.WebGLRenderCmd(this);
506     }
507 });
508 
509 /**
510  * Creates a gradient layer
511  * @deprecated since v3.0, please use the new construction instead
512  * @see cc.layerGradient
513  * @param {cc.Color} start starting color
514  * @param {cc.Color} end ending color
515  * @param {cc.Point|Null} v
516  * @return {cc.LayerGradient}
517  */
518 cc.LayerGradient.create = function (start, end, v) {
519     return new cc.LayerGradient(start, end, v);
520 };
521 //LayerGradient - Getter Setter
522 (function(){
523     var proto = cc.LayerGradient.prototype;
524     // Extended properties
525     /** @expose */
526     proto.startColor;
527     cc.defineGetterSetter(proto, "startColor", proto.getStartColor, proto.setStartColor);
528     /** @expose */
529     proto.endColor;
530     cc.defineGetterSetter(proto, "endColor", proto.getEndColor, proto.setEndColor);
531     /** @expose */
532     proto.startOpacity;
533     cc.defineGetterSetter(proto, "startOpacity", proto.getStartOpacity, proto.setStartOpacity);
534     /** @expose */
535     proto.endOpacity;
536     cc.defineGetterSetter(proto, "endOpacity", proto.getEndOpacity, proto.setEndOpacity);
537     /** @expose */
538     proto.vector;
539     cc.defineGetterSetter(proto, "vector", proto.getVector, proto.setVector);
540 })();
541 
542 /**
543  * CCMultipleLayer is a CCLayer with the ability to multiplex it's children.<br/>
544  * Features:<br/>
545  *  <ul><li>- It supports one or more children</li>
546  *  <li>- Only one children will be active a time</li></ul>
547  * @class
548  * @extends cc.Layer
549  * @param {Array} layers an array of cc.Layer
550  * @example
551  * // Example
552  * var multiLayer = new cc.LayerMultiple(layer1, layer2, layer3);//any number of layers
553  */
554 cc.LayerMultiplex = cc.Layer.extend(/** @lends cc.LayerMultiplex# */{
555     _enabledLayer: 0,
556     _layers: null,
557     _className: "LayerMultiplex",
558 
559     /**
560      * Constructor of cc.LayerMultiplex
561      * @param {Array} layers an array of cc.Layer
562      */
563     ctor: function (layers) {
564         cc.Layer.prototype.ctor.call(this);
565         if (layers instanceof Array)
566             cc.LayerMultiplex.prototype.initWithLayers.call(this, layers);
567         else
568             cc.LayerMultiplex.prototype.initWithLayers.call(this, Array.prototype.slice.call(arguments));
569     },
570 
571     /**
572      * 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
573      * @param {Array} layers an array of cc.Layer
574      * @return {Boolean}
575      */
576     initWithLayers: function (layers) {
577         if ((layers.length > 0) && (layers[layers.length - 1] == null))
578             cc.log(cc._LogInfos.LayerMultiplex_initWithLayers);
579 
580         this._layers = layers;
581         this._enabledLayer = 0;
582         this.addChild(this._layers[this._enabledLayer]);
583         return true;
584     },
585 
586     /**
587      * Switches to a certain layer indexed by n.<br/>
588      * The current (old) layer will be removed from it's parent with 'cleanup:YES'.
589      * @param {Number} n the layer index to switch to
590      */
591     switchTo: function (n) {
592         if (n >= this._layers.length) {
593             cc.log(cc._LogInfos.LayerMultiplex_switchTo);
594             return;
595         }
596 
597         this.removeChild(this._layers[this._enabledLayer], true);
598         this._enabledLayer = n;
599         this.addChild(this._layers[n]);
600     },
601 
602     /**
603      * Release the current layer and switches to another layer indexed by n.<br/>
604      * The current (old) layer will be removed from it's parent with 'cleanup:YES'.
605      * @param {Number} n the layer index to switch to
606      */
607     switchToAndReleaseMe: function (n) {
608         if (n >= this._layers.length) {
609             cc.log(cc._LogInfos.LayerMultiplex_switchToAndReleaseMe);
610             return;
611         }
612 
613         this.removeChild(this._layers[this._enabledLayer], true);
614 
615         //[layers replaceObjectAtIndex:_enabledLayer withObject:[NSNull null]];
616         this._layers[this._enabledLayer] = null;
617         this._enabledLayer = n;
618         this.addChild(this._layers[n]);
619     },
620 
621     /**
622      * Add a layer to the multiplex layers list
623      * @param {cc.Layer} layer
624      */
625     addLayer: function (layer) {
626         if (!layer) {
627             cc.log(cc._LogInfos.LayerMultiplex_addLayer);
628             return;
629         }
630         this._layers.push(layer);
631     }
632 });
633 
634 /**
635  * Creates a cc.LayerMultiplex with one or more layers using a variable argument list.
636  * @deprecated since v3.0, please use new construction instead
637  * @see cc.LayerMultiplex
638  * @return {cc.LayerMultiplex|Null}
639  */
640 cc.LayerMultiplex.create = function (/*Multiple Arguments*/) {
641     return new cc.LayerMultiplex(Array.prototype.slice.call(arguments));
642 };