1 /**************************************************************************** 2 Copyright (c) 2010-2012 cocos2d-x.org 3 Copyright (c) 2008-2010 Ricardo Quesada 4 Copyright (c) 2011 Zynga Inc. 5 6 http://www.cocos2d-x.org 7 8 Permission is hereby granted, free of charge, to any person obtaining a copy 9 of this software and associated documentation files (the "Software"), to deal 10 in the Software without restriction, including without limitation the rights 11 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 copies of the Software, and to permit persons to whom the Software is 13 furnished to do so, subject to the following conditions: 14 15 The above copyright notice and this permission notice shall be included in 16 all copies or substantial portions of the Software. 17 18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 THE SOFTWARE. 25 ****************************************************************************/ 26 27 /** Layer will receive all the touches at once The onTouchesXXX API will be called 28 */ 29 cc.TOUCH_ALL_AT_ONCE = 0; 30 31 /** Layer will receive only one touch at the time. The onTouchXXX API will be called */ 32 cc.TOUCH_ONE_BY_ONE = 1; 33 34 /** cc.Layer is a subclass of cc.Node that implements the TouchEventsDelegate protocol.<br/> 35 * All features from cc.Node are valid, plus the following new features:<br/> 36 * It can receive iPhone Touches<br/> 37 * It can receive Accelerometer input 38 * @class 39 * @extends cc.Node 40 */ 41 cc.Layer = cc.Node.extend(/** @lends cc.Layer# */{ 42 _isTouchEnabled:false, 43 _isAccelerometerEnabled:false, 44 _isKeyboardEnabled:false, 45 _touchPriority:0, 46 _touchMode:cc.TOUCH_ALL_AT_ONCE, 47 _isMouseEnabled:false, 48 _mousePriority:0, 49 50 /** 51 * Constructor 52 */ 53 ctor:function () { 54 this._super(); 55 56 //this._initLayer(); 57 }, 58 59 _initLayer:function () { 60 this.setAnchorPoint(cc.p(0.5, 0.5)); 61 this._ignoreAnchorPointForPosition = true; 62 63 var director = cc.Director.getInstance(); 64 this.setContentSize(director.getWinSize()); 65 this._isTouchEnabled = false; 66 this._isAccelerometerEnabled = false; 67 this._isMouseEnabled = false; 68 this._touchMode = cc.TOUCH_ALL_AT_ONCE; 69 this._touchPriority = 0; 70 }, 71 72 /** 73 * 74 * @return {Boolean} 75 */ 76 init:function () { 77 /*var director = cc.Director.getInstance(); 78 if (!director) { 79 return false; 80 } 81 this.setContentSize(director.getWinSize()); 82 this._isTouchEnabled = false;*/ 83 this._super(); 84 this._initLayer(); 85 return true; 86 }, 87 88 /** 89 * If isTouchEnabled, this method is called onEnter. 90 */ 91 registerWithTouchDispatcher:function () { 92 if (this._touchMode === cc.TOUCH_ALL_AT_ONCE) 93 cc.Director.getInstance().getTouchDispatcher().addStandardDelegate(this, this._touchPriority); 94 else 95 cc.Director.getInstance().getTouchDispatcher().addTargetedDelegate(this, this._touchPriority, true); 96 }, 97 98 isMouseEnabled:function () { 99 return this._isMouseEnabled; 100 }, 101 102 setMouseEnabled:function (enabled) { 103 if (this._isMouseEnabled != enabled) { 104 this._isMouseEnabled = enabled; 105 if (this._running) { 106 if (enabled) 107 cc.Director.getInstance().getMouseDispatcher().addMouseDelegate(this, this._mousePriority); 108 else 109 cc.Director.getInstance().getMouseDispatcher().removeMouseDelegate(this); 110 } 111 } 112 }, 113 114 setMousePriority:function (priority) { 115 if (this._mousePriority != priority) { 116 this._mousePriority = priority; 117 // Update touch priority with handler 118 if (this._isMouseEnabled) { 119 this.setMouseEnabled(false); 120 this.setMouseEnabled(true); 121 } 122 } 123 }, 124 125 getMousePriority:function () { 126 return this._mousePriority; 127 }, 128 129 /** 130 * whether or not it will receive Touch events.<br/> 131 * You can enable / disable touch events with this property.<br/> 132 * Only the touches of this node will be affected. This "method" is not propagated to it's children.<br/> 133 * @return {Boolean} 134 */ 135 isTouchEnabled:function () { 136 return this._isTouchEnabled; 137 }, 138 139 /** 140 * Enable touch events 141 * @param {Boolean} enabled 142 */ 143 setTouchEnabled:function (enabled) { 144 if (this._isTouchEnabled != enabled) { 145 this._isTouchEnabled = enabled; 146 147 if (this._running) { 148 if (enabled) { 149 this.registerWithTouchDispatcher(); 150 } else { 151 // have problems? 152 cc.Director.getInstance().getTouchDispatcher().removeDelegate(this); 153 } 154 } 155 } 156 }, 157 158 /** returns the priority of the touch event handler 159 * @return {Number} 160 */ 161 getTouchPriority:function () { 162 return this._touchPriority; 163 }, 164 165 /** Sets the touch event handler priority. Default is 0. 166 * @param {Number} priority 167 */ 168 setTouchPriority:function (priority) { 169 if (this._touchPriority != priority) { 170 this._touchPriority = priority; 171 // Update touch priority with handler 172 if (this._isTouchEnabled) { 173 this.setTouchEnabled(false); 174 this.setTouchEnabled(true); 175 } 176 } 177 }, 178 179 /** returns the touch mode. 180 * @return {Number} 181 */ 182 getTouchMode:function () { 183 return this._touchMode; 184 }, 185 186 /** Sets the touch mode. 187 * @param {Number} mode 188 */ 189 setTouchMode:function (mode) { 190 if (this._touchMode != mode) { 191 this._touchMode = mode; 192 // update the mode with handler 193 if (this._isTouchEnabled) { 194 this.setTouchEnabled(false); 195 this.setTouchEnabled(true); 196 } 197 } 198 }, 199 200 /** 201 * whether or not it will receive Accelerometer events<br/> 202 * You can enable / disable accelerometer events with this property. 203 * @return {Boolean} 204 */ 205 isAccelerometerEnabled:function () { 206 return this._isAccelerometerEnabled; 207 }, 208 209 /** 210 * isAccelerometerEnabled setter 211 * @param enabled 212 */ 213 setAccelerometerEnabled:function (enabled) { 214 if (enabled != this._isAccelerometerEnabled) { 215 this._isAccelerometerEnabled = enabled; 216 217 if (this._running) { 218 var director = cc.Director.getInstance(); 219 if (enabled) { 220 director.getAccelerometer().setDelegate(this); 221 } else { 222 director.getAccelerometer().setDelegate(null); 223 } 224 } 225 } 226 }, 227 228 /** 229 * whether or not it will receive keyboard events<br/> 230 * You can enable / disable accelerometer events with this property.<br/> 231 * it's new in cocos2d-x 232 * @return {Boolean} 233 */ 234 isKeyboardEnabled:function () { 235 return this._isKeyboardEnabled; 236 }, 237 238 /** 239 * Enable Keyboard interaction 240 * @param {Boolean} enabled 241 */ 242 setKeyboardEnabled:function (enabled) { 243 if (enabled != this._isKeyboardEnabled) { 244 this._isKeyboardEnabled = enabled; 245 if (this._running) { 246 var director = cc.Director.getInstance(); 247 if (enabled) { 248 director.getKeyboardDispatcher().addDelegate(this); 249 } else { 250 director.getKeyboardDispatcher().removeDelegate(this); 251 } 252 } 253 } 254 }, 255 256 /** 257 * This is run when ever a layer just become visible 258 */ 259 onEnter:function () { 260 var director = cc.Director.getInstance(); 261 // register 'parent' nodes first 262 // since events are propagated in reverse order 263 if (this._isTouchEnabled) { 264 this.registerWithTouchDispatcher(); 265 } 266 267 // then iterate over all the children 268 this._super(); 269 270 //TODO not supported 271 // add this layer to concern the Accelerometer Sensor 272 /* if (this._isAccelerometerEnabled){ 273 director.getAccelerometer().setDelegate(this); 274 }*/ 275 276 277 // add this layer to concern the kaypad msg 278 if (this._isKeyboardEnabled) 279 director.getKeyboardDispatcher().addDelegate(this); 280 281 if (this._isMouseEnabled) 282 director.getMouseDispatcher().addMouseDelegate(this, this._mousePriority); 283 }, 284 285 /** 286 * @function 287 */ 288 onExit:function () { 289 var director = cc.Director.getInstance(); 290 if (this._isTouchEnabled) { 291 director.getTouchDispatcher().removeDelegate(this); 292 } 293 294 // remove this layer from the delegates who concern Accelerometer Sensor 295 //TODO not supported 296 /* if (this._isAccelerometerEnabled) { 297 director.getAccelerometer().setDelegate(null); 298 }*/ 299 300 // remove this layer from the delegates who concern the kaypad msg 301 if (this._isKeyboardEnabled) { 302 director.getKeyboardDispatcher().removeDelegate(this); 303 } 304 305 if (this._isMouseEnabled) 306 director.getMouseDispatcher().removeMouseDelegate(this); 307 308 this._super(); 309 }, 310 311 /** 312 * this is called when ever a layer is a child of a scene that just finished a transition 313 */ 314 onEnterTransitionDidFinish:function () { 315 //TODO not supported 316 /*if (this._isAccelerometerEnabled) { 317 cc.Director.getInstance().getAccelerometer().setDelegate(this); 318 }*/ 319 this._super(); 320 }, 321 322 /** 323 * default implements are used to call script callback if exist<br/> 324 * you must override these touch functions if you wish to utilize them 325 * @param {cc.Touch} touch 326 * @param {event} event 327 * @return {Boolean} 328 */ 329 onTouchBegan:function (touch, event) { 330 cc.Assert(false, "Layer#onTouchBegan override me"); 331 return true; 332 }, 333 334 /** 335 * callback when a touch event moved 336 * @param {cc.Touch} touch 337 * @param {event} event 338 */ 339 onTouchMoved:function (touch, event) { 340 }, 341 342 /** 343 * callback when a touch event finished 344 * @param {cc.Touch} touch 345 * @param {event} event 346 */ 347 onTouchEnded:function (touch, event) { 348 }, 349 350 /** 351 * @param {cc.Touch} touch 352 * @param {event} event 353 */ 354 onTouchCancelled:function (touch, event) { 355 }, 356 357 /** 358 * Touches is the same as Touch, except this one can handle multi-touch 359 * @param {cc.Touch} touch 360 * @param {event} event 361 */ 362 onTouchesBegan:function (touch, event) { 363 }, 364 365 /** 366 * when a touch moved 367 * @param {cc.Touch} touch 368 * @param {event} event 369 */ 370 onTouchesMoved:function (touch, event) { 371 }, 372 373 /** 374 * when a touch finished 375 * @param {cc.Touch} touch 376 * @param {event} event 377 */ 378 onTouchesEnded:function (touch, event) { 379 }, 380 381 /** 382 * @param touch 383 * @param event 384 */ 385 onTouchesCancelled:function (touch, event) { 386 }, 387 388 didAccelerate:function (pAccelerationValue) { 389 }, 390 391 // ---------------------CCMouseEventDelegate interface------------------------------ 392 393 /** 394 * <p>called when the "mouseDown" event is received. <br/> 395 * Return YES to avoid propagating the event to other delegates. </p> 396 * @param event 397 * @return {Boolean} 398 */ 399 onMouseDown:function (event) { 400 return false; 401 }, 402 403 /** 404 * <p>called when the "mouseDragged" event is received. <br/> 405 * Return YES to avoid propagating the event to other delegates.</p> 406 * @param event 407 * @return {Boolean} 408 */ 409 onMouseDragged:function (event) { 410 return false; 411 }, 412 413 /** 414 * <p> called when the "mouseMoved" event is received. <br/> 415 * Return YES to avoid propagating the event to other delegates. </p> 416 * @param event 417 * @return {Boolean} 418 */ 419 onMouseMoved:function (event) { 420 return false; 421 }, 422 423 /** 424 * <p> called when the "mouseUp" event is received. <br/> 425 * Return YES to avoid propagating the event to other delegates. </p> 426 * @param event 427 * @return {Boolean} 428 */ 429 onMouseUp:function (event) { 430 return false; 431 }, 432 433 //right 434 /** 435 * <p> called when the "rightMouseDown" event is received. <br/> 436 * Return YES to avoid propagating the event to other delegates. </p> 437 * @param event 438 * @return {Boolean} 439 */ 440 onRightMouseDown:function (event) { 441 return false; 442 }, 443 444 /** 445 * <p> called when the "rightMouseDragged" event is received. <br/> 446 * Return YES to avoid propagating the event to other delegates. </p> 447 * @param event 448 * @return {Boolean} 449 */ 450 onRightMouseDragged:function (event) { 451 return false; 452 }, 453 454 /** 455 * <p> called when the "rightMouseUp" event is received. <br/> 456 * Return YES to avoid propagating the event to other delegates. </p> 457 * @param event 458 * @return {Boolean} 459 */ 460 onRightMouseUp:function (event) { 461 return false; 462 }, 463 464 //other 465 /** 466 * <p>called when the "otherMouseDown" event is received. <br/> 467 * Return YES to avoid propagating the event to other delegates. </p> 468 * @param event 469 * @return {Boolean} 470 */ 471 onOtherMouseDown:function (event) { 472 return false; 473 }, 474 475 /** 476 * <p> called when the "otherMouseDragged" event is received. <br/> 477 * Return YES to avoid propagating the event to other delegates. </p> 478 * @param event 479 * @return {Boolean} 480 */ 481 onOtherMouseDragged:function (event) { 482 return false; 483 }, 484 485 /** 486 * <p> called when the "otherMouseUp" event is received. <br/> 487 * Return YES to avoid propagating the event to other delegates. </p> 488 * @param event 489 * @return {Boolean} 490 */ 491 onOtherMouseUp:function (event) { 492 return false; 493 }, 494 495 //scroll wheel 496 /** 497 * <p> called when the "scrollWheel" event is received. <br/> 498 * Return YES to avoid propagating the event to other delegates. </p> 499 * @param event 500 * @return {Boolean} 501 */ 502 onScrollWheel:function (event) { 503 return false; 504 }, 505 506 // enter / exit 507 /** 508 * <p> called when the "mouseEntered" event is received. <br/> 509 * Return YES to avoid propagating the event to other delegates. </p> 510 * @param theEvent 511 * @return {Boolean} 512 */ 513 onMouseEntered:function (theEvent) { 514 return false; 515 }, 516 517 /** 518 * <p> called when the "mouseExited" event is received. <br/> 519 * Return YES to avoid propagating the event to other delegates. </p> 520 * @param theEvent 521 * @return {Boolean} 522 */ 523 onMouseExited:function (theEvent) { 524 return false; 525 } 526 }); 527 528 /** 529 * creates a layer 530 * @example 531 * // Example 532 * var myLayer = cc.Layer.create(); 533 * //Yes! it's that simple 534 * @return {cc.Layer|Null} 535 */ 536 cc.Layer.create = function () { 537 var ret = new cc.Layer(); 538 if (ret && ret.init()) { 539 return ret; 540 } 541 return null; 542 }; 543 544 545 /** 546 * CCLayerColor is a subclass of CCLayer that implements the CCRGBAProtocol protocol.<br/> 547 * All features from CCLayer are valid, plus the following new features:<br/> 548 * <ul><li>opacity</li> 549 * <li>RGB colors</li></ul> 550 * @class 551 * @extends cc.Layer 552 */ 553 cc.LayerColor = cc.Layer.extend(/** @lends cc.LayerColor# */{ 554 RGBAProtocol:true, 555 _squareVertices:[], 556 _squareColors:[], 557 _opacity:0, 558 _color:new cc.Color3B(255, 255, 255), 559 _blendFunc:new cc.BlendFunc(cc.BLEND_SRC, cc.BLEND_DST), 560 _layerColorStr:null, 561 562 /** 563 * Constructor 564 */ 565 ctor:function () { 566 this._squareVertices = [new cc.Vertex2F(0, 0), new cc.Vertex2F(0, 0), new cc.Vertex2F(0, 0), new cc.Vertex2F(0, 0)]; 567 this._squareColors = [new cc.Color4F(0, 0, 0, 1), new cc.Color4F(0, 0, 0, 1), new cc.Color4F(0, 0, 0, 1), new cc.Color4F(0, 0, 0, 1)]; 568 this._color = new cc.Color4B(0, 0, 0, 0); 569 this._opacity = 255; 570 this._super(); 571 this._layerColorStr = this._getLayerColorString(); 572 }, 573 574 _getLayerColorString:function () { 575 return "rgba(" + (0 | this._color.r) + "," + (0 | this._color.g) + "," + (0 | this._color.b) + "," + (this.getOpacity() / 255).toFixed(5) + ")"; 576 }, 577 578 /** 579 * opacity getter 580 * @return {Number} 581 */ 582 getOpacity:function () { 583 return this._opacity; 584 }, 585 586 /** 587 * opacity setter 588 * @param {Number} Var a number between 0 and 255, 0 is totally transparent 589 */ 590 setOpacity:function (Var) { 591 this._opacity = Var; 592 this._updateColor(); 593 this.setNodeDirty(); 594 }, 595 596 /** 597 * color getter 598 * @return {cc.Color3B} 599 */ 600 getColor:function () { 601 return this._color; 602 }, 603 604 /** 605 * color setter 606 * @param {cc.Color3B} Var 607 */ 608 setColor:function (Var) { 609 this._color = Var; 610 this._updateColor(); 611 this.setNodeDirty(); 612 }, 613 614 /** 615 * blendFunc getter 616 * @return {cc.BlendFunc} 617 */ 618 getBlendFunc:function () { 619 return this._blendFunc; 620 }, 621 622 _isLighterMode:false, 623 /** 624 * blendFunc setter 625 * @param {Number} src 626 * @param {Number} dst 627 */ 628 setBlendFunc:function (src, dst) { 629 if (arguments.length == 1) { 630 this._blendFunc = src; 631 } else { 632 this._blendFunc = {src:src, dst:dst}; 633 } 634 this._isLighterMode = (this._blendFunc && (this._blendFunc.src == 1) && (this._blendFunc.dst == 771)); 635 }, 636 637 /** 638 * @param color 639 * @return {Boolean} 640 */ 641 init:function (color, width, height) { 642 this._initLayer(); 643 644 var winSize = cc.Director.getInstance().getWinSize(); 645 646 color = color || new cc.Color4B(0, 0, 0, 255); 647 width = width || winSize.width; 648 height = height || winSize.height; 649 650 this._blendFunc.src = cc.BLEND_SRC; 651 this._blendFunc.dst = cc.BLEND_DST; 652 653 this._color = new cc.Color3B(color.r, color.g, color.b); 654 this._opacity = color.a; 655 656 for (var i = 0; i < this._squareVertices.length; i++) { 657 this._squareVertices[i].x = 0.0; 658 this._squareVertices[i].y = 0.0; 659 } 660 661 this.setContentSize(cc.size(width, height)); 662 663 this._updateColor(); 664 //this.setShaderProgram(cc.ShaderCache.getInstance().programForKey(kCCShader_PositionColor)); 665 666 return true; 667 }, 668 669 /** 670 * override contentSize 671 * @param {cc.Size} size 672 */ 673 setContentSize:function (size) { 674 this._squareVertices[1].x = size.width; 675 this._squareVertices[2].y = size.height; 676 this._squareVertices[3].x = size.width; 677 this._squareVertices[3].y = size.height; 678 this._super(size); 679 }, 680 681 /** 682 * change width and height in Points 683 * @param {Number} w width 684 * @param {Number} h height 685 */ 686 changeWidthAndHeight:function (w, h) { 687 this.setContentSize(cc.size(w, h)); 688 }, 689 690 /** 691 * change width in Points 692 * @param {Number} w width 693 */ 694 changeWidth:function (w) { 695 this.setContentSize(cc.size(w, this._contentSize.height)); 696 }, 697 698 /** 699 * change height in Points 700 * @param {Number} h height 701 */ 702 changeHeight:function (h) { 703 this.setContentSize(cc.size(this._contentSize.width, h)); 704 }, 705 706 _updateColor:function () { 707 for (var i = 0; i < 4; i++) { 708 this._squareColors[i].r = this._color.r / 255; 709 this._squareColors[i].g = this._color.g / 255; 710 this._squareColors[i].b = this._color.b / 255; 711 this._squareColors[i].a = this._opacity / 255; 712 } 713 }, 714 715 /** 716 * set OpacityModifyRGB of cc.LayerColor 717 * @param {Boolean} value 718 */ 719 setOpacityModifyRGB:function (value) { 720 }, 721 722 /** 723 * is OpacityModifyRGB 724 * @return {Boolean} 725 */ 726 isOpacityModifyRGB:function () { 727 return false; 728 }, 729 730 /** 731 * renders the layer 732 * @param {CanvasContext|Null} ctx 733 */ 734 draw:function (ctx) { 735 var context = ctx || cc.renderContext; 736 737 var tWidth = this.getContentSize().width; 738 var tHeight = this.getContentSize().height; 739 var apip = this.getAnchorPointInPoints(); 740 741 context.fillStyle = "rgba(" + (0 | this._color.r) + "," + (0 | this._color.g) + "," + (0 | this._color.b) + "," + this.getOpacity() / 255 + ")"; 742 context.fillRect(-apip.x, apip.y, tWidth, -tHeight); 743 744 cc.INCREMENT_GL_DRAWS(1); 745 }, 746 747 _drawForWebGL:function (ctx) { 748 /*cc.NODE_DRAW_SETUP(); 749 ccGLEnableVertexAttribs( kCCVertexAttribFlag_Position | kCCVertexAttribFlag_Color ); 750 751 // 752 // Attributes 753 // 754 glVertexAttribPointer(kCCVertexAttrib_Position, 2, GL_FLOAT, GL_FALSE, 0, m_pSquareVertices); 755 glVertexAttribPointer(kCCVertexAttrib_Color, 4, GL_FLOAT, GL_FALSE, 0, m_pSquareColors); 756 ccGLBlendFunc( m_tBlendFunc.src, m_tBlendFunc.dst ); 757 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); */ 758 } 759 }); 760 761 /** 762 * creates a cc.Layer with color, width and height in Points 763 * @param {cc.Color4B} color 764 * @param {Number|Null} width 765 * @param {Number|Null} height 766 * @return {cc.LayerColor} 767 * @example 768 * // Example 769 * //Create a yellow color layer as background 770 * var yellowBackground = cc.LayerColor.create(cc.c4b(255,255,0,255)); 771 * //If you didnt pass in width and height, it defaults to the same size as the canvas 772 * 773 * //create a yellow box, 200 by 200 in size 774 * var yellowBox = cc.LayerColor.create(cc.c3b(255,255,0,255), 200, 200); 775 */ 776 cc.LayerColor.create = function (color, width, height) { 777 var ret = new cc.LayerColor(); 778 switch (arguments.length) { 779 case 0: 780 ret.init(); 781 break; 782 case 1: 783 ret.init(color); 784 break; 785 case 3: 786 ret.init(color, width, height); 787 break; 788 default : 789 ret.init(); 790 break; 791 } 792 return ret; 793 }; 794 795 796 /** 797 * CCLayerGradient is a subclass of cc.LayerColor that draws gradients across<br/> 798 * the background.<br/> 799 *<br/> 800 * All features from cc.LayerColor are valid, plus the following new features:<br/> 801 * <ul><li>direction</li> 802 * <li>final color</li> 803 * <li>interpolation mode</li></ul> 804 * <br/> 805 * Color is interpolated between the startColor and endColor along the given<br/> 806 * vector (starting at the origin, ending at the terminus). If no vector is<br/> 807 * supplied, it defaults to (0, -1) -- a fade from top to bottom.<br/> 808 * <br/> 809 * If 'compressedInterpolation' is disabled, you will not see either the start or end color for<br/> 810 * non-cardinal vectors; a smooth gradient implying both end points will be still<br/> 811 * be drawn, however.<br/> 812 *<br/> 813 * If ' compressedInterpolation' is enabled (default mode) you will see both the start and end colors of the gradient. 814 * @class 815 * @extends cc.LayerColor 816 */ 817 cc.LayerGradient = cc.LayerColor.extend(/** @lends cc.LayerGradient# */{ 818 _startColor:null, 819 _endColor:null, 820 _startOpacity:null, 821 _endOpacity:null, 822 _alongVector:null, 823 _compressedInterpolation:false, 824 825 _gradientStartPoint:null, 826 _gradientEndPoint:null, 827 828 /** 829 * Constructor 830 * @function 831 */ 832 ctor:function () { 833 this._super(); 834 835 this._color = new cc.Color3B(0, 0, 0); 836 this._startColor = new cc.Color3B(0, 0, 0); 837 this._endColor = new cc.Color3B(0, 0, 0); 838 this._alongVector = cc.p(0, -1); 839 this._startOpacity = 255; 840 this._endOpacity = 255; 841 842 this._gradientStartPoint = cc.p(0, 0); 843 this._gradientEndPoint = cc.p(0, 0); 844 }, 845 846 /** 847 * get the starting color 848 * @return {cc.Color3B} 849 */ 850 getStartColor:function () { 851 return this._color; 852 }, 853 854 /** 855 * set the starting color 856 * @param {cc.Color3B} color 857 * @example 858 * // Example 859 * myGradientLayer.setStartColor(cc.c3b(255,0,0)); 860 * //set the starting gradient to red 861 */ 862 setStartColor:function (color) { 863 this.setColor(color); 864 }, 865 866 /** 867 * set the end gradient color 868 * @param {cc.Color3B} color 869 * @example 870 * // Example 871 * myGradientLayer.setEndColor(cc.c3b(255,0,0)); 872 * //set the ending gradient to red 873 */ 874 setEndColor:function (color) { 875 this._endColor = color; 876 this._updateColor(); 877 }, 878 879 /** 880 * get the end color 881 * @return {cc.Color3B} 882 */ 883 getEndColor:function () { 884 return this._endColor; 885 }, 886 887 /** 888 * set starting gradient opacity 889 * @param {Number} o from 0 to 255, 0 is transparent 890 */ 891 setStartOpacity:function (o) { 892 this._startOpacity = o; 893 this._updateColor(); 894 }, 895 896 /** 897 * get the starting gradient opacity 898 * @return {Number} 899 */ 900 getStartOpacity:function () { 901 return this._startOpacity; 902 }, 903 904 /** 905 * set the end gradient opacity 906 * @param {Number} o 907 */ 908 setEndOpacity:function (o) { 909 this._endOpacity = o; 910 this._updateColor(); 911 }, 912 913 /** 914 * get the end gradient opacity 915 * @return {Number} 916 */ 917 getEndOpacity:function () { 918 return this._endOpacity; 919 }, 920 921 /** 922 * set vector 923 * @param {cc.Point} Var 924 */ 925 setVector:function (Var) { 926 this._alongVector = Var; 927 this._updateColor(); 928 }, 929 930 /** 931 * @return {cc.Point} 932 */ 933 getVector:function () { 934 return this._alongVector; 935 }, 936 937 /** is Compressed Interpolation 938 * @return {Boolean} 939 */ 940 isCompressedInterpolation:function () { 941 return this._compressedInterpolation; 942 }, 943 944 /** 945 * @param {Boolean} compress 946 */ 947 setCompressedInterpolation:function (compress) { 948 this._compressedInterpolation = compress; 949 this._updateColor(); 950 }, 951 952 /** 953 * @param {cc.Color3B} start starting color 954 * @param {cc.Color3B} end 955 * @param {cc.Point|Null} v 956 * @return {Boolean} 957 */ 958 init:function (start, end, v) { 959 var argnum = arguments.length; 960 961 if (argnum == 0) 962 return this._super(); 963 964 if (argnum == 2) { 965 // Initializes the CCLayer with a gradient between start and end. 966 v = cc.p(0, -1); 967 } 968 969 // Initializes the CCLayer with a gradient between start and end in the direction of v. 970 this._startColor.r = start.r; 971 this._startColor.g = start.g; 972 this._startColor.b = start.b; 973 this._startOpacity = start.a; 974 975 this._endColor.r = end.r; 976 this._endColor.g = end.g; 977 this._endColor.b = end.b; 978 this._endOpacity = end.a; 979 980 this._alongVector = v; 981 982 this._compressedInterpolation = true; 983 984 this._super(cc.c4b(start.r, start.g, start.b, 255)); 985 return true; 986 }, 987 988 _updateColor:function () { 989 if (cc.renderContextType === cc.CANVAS) { 990 var tWidth = this.getContentSize().width / 2; 991 var tHeight = this.getContentSize().height / 2; 992 var apip = this.getAnchorPointInPoints(); 993 var offWidth = tWidth - apip.x; 994 var offHeight = tHeight - apip.y; 995 996 this._gradientStartPoint = cc.p(tWidth * -this._alongVector.x + offWidth, tHeight * this._alongVector.y - offHeight); 997 this._gradientEndPoint = cc.p(tWidth * this._alongVector.x + offWidth, tHeight * -this._alongVector.y - offHeight); 998 } else { 999 //todo need fixed for webGL 1000 this._super(); 1001 1002 var h = cc.pLength(this._alongVector); 1003 if (h == 0) 1004 return; 1005 1006 var c = Math.sqrt(2.0); 1007 var u = cc.p(this._alongVector.x / h, this._alongVector.y / h); 1008 1009 // Compressed Interpolation mode 1010 if (this._compressedInterpolation) { 1011 var h2 = 1 / ( Math.abs(u.x) + Math.abs(u.y) ); 1012 u = cc.pMult(u, h2 * c); 1013 } 1014 1015 var opacityf = this._opacity / 255.0; 1016 1017 var S = new cc.Color4F(this._color.r / 255, this._color.g / 255, this._color.b / 255, (this._startOpacity * opacityf) / 255); 1018 1019 var E = new cc.Color4F(this._endColor.r / 255, this._endColor.g / 255, this._endColor.b / 255, (this._endOpacity * opacityf) / 255); 1020 1021 // (-1, -1) 1022 this._squareColors[0].r = ((E.r + (S.r - E.r) * ((c + u.x + u.y) / (2.0 * c)))); 1023 this._squareColors[0].g = ((E.g + (S.g - E.g) * ((c + u.x + u.y) / (2.0 * c)))); 1024 this._squareColors[0].b = ((E.b + (S.b - E.b) * ((c + u.x + u.y) / (2.0 * c)))); 1025 this._squareColors[0].a = ((E.a + (S.a - E.a) * ((c + u.x + u.y) / (2.0 * c)))); 1026 // (1, -1) 1027 this._squareColors[1].r = ((E.r + (S.r - E.r) * ((c - u.x + u.y) / (2.0 * c)))); 1028 this._squareColors[1].g = ((E.g + (S.g - E.g) * ((c - u.x + u.y) / (2.0 * c)))); 1029 this._squareColors[1].b = ((E.b + (S.b - E.b) * ((c - u.x + u.y) / (2.0 * c)))); 1030 this._squareColors[1].a = ((E.a + (S.a - E.a) * ((c - u.x + u.y) / (2.0 * c)))); 1031 // (-1, 1) 1032 this._squareColors[2].r = ((E.r + (S.r - E.r) * ((c + u.x - u.y) / (2.0 * c)))); 1033 this._squareColors[2].g = ((E.g + (S.g - E.g) * ((c + u.x - u.y) / (2.0 * c)))); 1034 this._squareColors[2].b = ((E.b + (S.b - E.b) * ((c + u.x - u.y) / (2.0 * c)))); 1035 this._squareColors[2].a = ((E.a + (S.a - E.a) * ((c + u.x - u.y) / (2.0 * c)))); 1036 // (1, 1) 1037 this._squareColors[3].r = ((E.r + (S.r - E.r) * ((c - u.x - u.y) / (2.0 * c)))); 1038 this._squareColors[3].g = ((E.g + (S.g - E.g) * ((c - u.x - u.y) / (2.0 * c)))); 1039 this._squareColors[3].b = ((E.b + (S.b - E.b) * ((c - u.x - u.y) / (2.0 * c)))); 1040 this._squareColors[3].a = ((E.a + (S.a - E.a) * ((c - u.x - u.y) / (2.0 * c)))); 1041 } 1042 }, 1043 1044 draw:function (ctx) { 1045 var context = ctx || cc.renderContext; 1046 if (cc.renderContextType == cc.CANVAS) { 1047 if (this._isLighterMode) 1048 context.globalCompositeOperation = 'lighter'; 1049 1050 context.save(); 1051 var tWidth = this.getContentSize().width; 1052 var tHeight = this.getContentSize().height; 1053 var apip = this.getAnchorPointInPoints(); 1054 var tGradient = context.createLinearGradient(this._gradientStartPoint.x, this._gradientStartPoint.y, 1055 this._gradientEndPoint.x, this._gradientEndPoint.y); 1056 tGradient.addColorStop(0, "rgba(" + Math.round(this._color.r) + "," + Math.round(this._color.g) + "," 1057 + Math.round(this._color.b) + "," + (this._startOpacity / 255).toFixed(4) + ")"); 1058 tGradient.addColorStop(1, "rgba(" + Math.round(this._endColor.r) + "," + Math.round(this._endColor.g) + "," 1059 + Math.round(this._endColor.b) + "," + (this._endOpacity / 255).toFixed(4) + ")"); 1060 context.fillStyle = tGradient; 1061 context.fillRect(-apip.x, apip.y, tWidth, -tHeight); 1062 1063 if (this._rotation != 0) 1064 context.rotate(this._rotationRadians); 1065 context.restore(); 1066 } 1067 } 1068 }); 1069 1070 /** 1071 * creates a gradient layer 1072 * @param {cc.Color3B} start starting color 1073 * @param {cc.Color3B} end ending color 1074 * @param {cc.Point|Null} v 1075 * @return {cc.LayerGradient} 1076 */ 1077 cc.LayerGradient.create = function (start, end, v) { 1078 var layer = new cc.LayerGradient(); 1079 switch (arguments.length) { 1080 case 2: 1081 /** Creates a full-screen CCLayer with a gradient between start and end. */ 1082 if (layer && layer.init(start, end)) { 1083 return layer; 1084 } 1085 break; 1086 case 3: 1087 /** Creates a full-screen CCLayer with a gradient between start and end in the direction of v. */ 1088 if (layer && layer.init(start, end, v)) { 1089 return layer; 1090 } 1091 break; 1092 case 0: 1093 if (layer && layer.init()) { 1094 return layer; 1095 } 1096 break; 1097 default: 1098 throw "Arguments error "; 1099 break; 1100 } 1101 return null; 1102 }; 1103 1104 1105 /** 1106 * CCMultipleLayer is a CCLayer with the ability to multiplex it's children.<br/> 1107 * Features:<br/> 1108 * <ul><li>- It supports one or more children</li> 1109 * <li>- Only one children will be active a time</li></ul> 1110 * @class 1111 * @extends cc.Layer 1112 */ 1113 cc.LayerMultiplex = cc.Layer.extend(/** @lends cc.LayerMultiplex# */{ 1114 _enabledLayer:0, 1115 _layers:null, 1116 1117 /** 1118 * Constructor 1119 */ 1120 ctor:function () { 1121 this._super(); 1122 }, 1123 1124 /** 1125 * @param {cc.Layer} layer 1126 * @deprecated merged with initWithLayers 1127 * @return {Boolean} 1128 */ 1129 initWithLayer:function (layer) { 1130 this._layers = []; 1131 this._layers.push(layer); 1132 this._enabledLayer = 0; 1133 this.addChild(layer); 1134 return true; 1135 }, 1136 1137 /** 1138 * @param {Array} args an array of cc.Layer 1139 * @return {Boolean} 1140 */ 1141 initWithLayers:function (args) { 1142 this._layers = args; 1143 this._enabledLayer = 0; 1144 this.addChild(this._layers[this._enabledLayer]); 1145 return true; 1146 }, 1147 1148 /** 1149 * switches to a certain layer indexed by n.<br/> 1150 * The current (old) layer will be removed from it's parent with 'cleanup:YES'. 1151 * @param {Number} n the layer index to switch to 1152 */ 1153 switchTo:function (n) { 1154 cc.Assert(n < this._layers.length, "Invalid index in MultiplexLayer switchTo message"); 1155 1156 this.removeChild(this._layers[this._enabledLayer], true); 1157 1158 this._enabledLayer = n; 1159 1160 this.addChild(this._layers[n]); 1161 }, 1162 1163 /** release the current layer and switches to another layer indexed by n.<br/> 1164 * The current (old) layer will be removed from it's parent with 'cleanup:YES'. 1165 * @param {Number} n the layer index to switch to 1166 */ 1167 switchToAndReleaseMe:function (n) { 1168 cc.Assert(n < this._layers.count(), "Invalid index in MultiplexLayer switchTo message"); 1169 1170 this.removeChild(this._layers[this._enabledLayer], true); 1171 1172 //[layers replaceObjectAtIndex:_enabledLayer withObject:[NSNull null]]; 1173 this._layers[this._enabledLayer] = null; 1174 1175 this._enabledLayer = n; 1176 1177 this.addChild(this._layers[n]); 1178 }, 1179 1180 /** 1181 * @param {cc.Layer} layer 1182 */ 1183 addLayer:function (layer) { 1184 cc.Assert(this._layers, "cc.Layer addLayer"); 1185 this._layers.push(layer); 1186 } 1187 }); 1188 1189 1190 /** 1191 * creates a cc.LayerMultiplex with one or more layers using a variable argument list. 1192 * @return {cc.LayerMultiplex|Null} 1193 * @example 1194 * // Example 1195 * var multiLayer = cc.LayerMultiple.create(layer1, layer2, layer3);//any number of layers 1196 */ 1197 cc.LayerMultiplex.create = function (/*Multiple Arguments*/) { 1198 var multiplexLayer = new cc.LayerMultiplex(); 1199 if (multiplexLayer.initWithLayers(arguments)) { 1200 return multiplexLayer; 1201 } 1202 return null; 1203 }; 1204 1205 1206 /** 1207 * a layer that does not get redraw if not needed, and its always gets placed on the bottom layer 1208 * @class 1209 * @extends cc.Node 1210 * @example 1211 * // Example 1212 * var veryLazy = new cc.LazyLayer(); 1213 * veryLazy.addChild(mySprite); 1214 */ 1215 cc.LazyLayer = cc.Node.extend(/** @lends cc.LazyLayer# */{ 1216 _layerCanvas:null, 1217 _layerContext:null, 1218 _isNeedUpdate:false, 1219 _canvasZOrder:-10, 1220 _layerId:"", 1221 1222 /** 1223 * Constructor 1224 */ 1225 ctor:function () { 1226 this._super(); 1227 this.setAnchorPoint(cc.p(0, 0)); 1228 //setup html 1229 this._setupHtml(); 1230 }, 1231 1232 /** 1233 * @param {Number} zOrder 1234 */ 1235 setLayerZOrder:function (zOrder) { 1236 if (zOrder >= 0) { 1237 throw "LazyLayer zOrder must Less than Zero.Because LazyLayer is a background Layer!"; 1238 } 1239 this._canvasZOrder = zOrder; 1240 this._layerCanvas.style.zIndex = this._canvasZOrder; 1241 }, 1242 1243 /** 1244 * 1245 * @return {Number} 1246 */ 1247 getLayerZOrder:function () { 1248 return this._canvasZOrder; 1249 }, 1250 1251 _setupHtml:function () { 1252 this._layerCanvas = document.createElement("canvas"); 1253 this._layerCanvas.width = cc.canvas.width; 1254 this._layerCanvas.height = cc.canvas.height; 1255 this._layerId = "lazyCanvas" + Date.now(); 1256 this._layerCanvas.id = this._layerId; 1257 this._layerCanvas.style.zIndex = this._canvasZOrder; 1258 this._layerCanvas.style.position = "absolute"; 1259 this._layerCanvas.style.top = "0"; 1260 this._layerCanvas.style.left = "0"; 1261 this._layerContext = this._layerCanvas.getContext("2d"); 1262 this._layerContext.fillStyle = "rgba(0,0,0,1)"; 1263 this._layerContext.translate(0, this._layerCanvas.height); 1264 cc.container.appendChild(this._layerCanvas); 1265 var selfPointer = this; 1266 window.addEventListener("resize", function (event) { 1267 selfPointer.adjustSizeForCanvas(); 1268 }); 1269 }, 1270 1271 /** 1272 * make it the same size as canvas, in case canvas resized 1273 */ 1274 adjustSizeForCanvas:function () { 1275 this._isNeedUpdate = true; 1276 this._layerCanvas.width = cc.canvas.width; 1277 this._layerCanvas.height = cc.canvas.height; 1278 var xScale = cc.canvas.width / cc.originalCanvasSize.width; 1279 var yScale = cc.canvas.height / cc.originalCanvasSize.height; 1280 if (xScale > yScale) { 1281 xScale = yScale; 1282 } 1283 this._layerContext.translate(0, this._layerCanvas.height); 1284 this._layerContext.scale(xScale, xScale); 1285 }, 1286 1287 /** 1288 * return lazylayer's canvas 1289 * @return {HTMLCanvasElement} 1290 */ 1291 getLayerCanvas:function () { 1292 return this._layerCanvas; 1293 }, 1294 1295 /** 1296 * same as cc.Node 1297 * @param {cc.Node} child 1298 * @param {Number|Null} zOrder 1299 * @param {Number|Null} tag 1300 */ 1301 addChild:function (child, zOrder, tag) { 1302 this._isNeedUpdate = true; 1303 this._super(child, zOrder, tag); 1304 }, 1305 1306 /** 1307 * @param {cc.Node} child 1308 * @param {Boolean} cleanup 1309 */ 1310 removeChild:function (child, cleanup) { 1311 this._isNeedUpdate = true; 1312 this._super(child, cleanup); 1313 }, 1314 1315 /** 1316 * stuff gets drawn in here 1317 */ 1318 visit:function () { 1319 // quick return if not visible 1320 if (!this._visible) { 1321 return; 1322 } 1323 if (!this._isNeedUpdate) { 1324 return; 1325 } 1326 1327 this._isNeedUpdate = false; 1328 var context = this._layerContext; 1329 context.save(); 1330 context.clearRect(0, 0, this._layerCanvas.width, -this._layerCanvas.height); 1331 1332 if (this._children && this._children.length > 0) { 1333 this.sortAllChildren(); 1334 // draw children zOrder < 0 1335 for (var i = 0; i < this._children.length; i++) { 1336 this._children[i].visit(context); 1337 } 1338 } 1339 1340 context.restore(); 1341 }, 1342 1343 /** 1344 * override onExit of cc.Node 1345 * @override 1346 */ 1347 onExit:function () { 1348 this._super(); 1349 1350 //clear canvas element from parent element 1351 if (this._layerCanvas.parentNode) { 1352 this._layerCanvas.parentNode.removeChild(this._layerCanvas); 1353 } 1354 }, 1355 1356 _setNodeDirtyForCache:function () { 1357 this._cacheDirty = true; 1358 this._isNeedUpdate = true; 1359 } 1360 }); 1361