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 Copyright (c) 2010 Lam Pham 6 7 http://www.cocos2d-x.org 8 9 Permission is hereby granted, free of charge, to any person obtaining a copy 10 of this software and associated documentation files (the "Software"), to deal 11 in the Software without restriction, including without limitation the rights 12 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 copies of the Software, and to permit persons to whom the Software is 14 furnished to do so, subject to the following conditions: 15 16 The above copyright notice and this permission notice shall be included in 17 all copies or substantial portions of the Software. 18 19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 THE SOFTWARE. 26 ****************************************************************************/ 27 28 /** 29 * cc.Progresstimer is a subclass of cc.Node. <br/> 30 * It renders the inner sprite according to the percentage.<br/> 31 * The progress can be Radial, Horizontal or vertical. 32 * @class 33 * @extends cc.Node 34 * 35 * @property {cc.Point} midPoint <p>- Midpoint is used to modify the progress start position.<br/> 36 * If you're using radials type then the midpoint changes the center point<br/> 37 * If you're using bar type the the midpoint changes the bar growth<br/> 38 * it expands from the center but clamps to the sprites edge so:<br/> 39 * you want a left to right then set the midpoint all the way to cc.p(0,y)<br/> 40 * you want a right to left then set the midpoint all the way to cc.p(1,y)<br/> 41 * you want a bottom to top then set the midpoint all the way to cc.p(x,0)<br/> 42 * you want a top to bottom then set the midpoint all the way to cc.p(x,1)</p> 43 * @property {cc.Point} barChangeRate - This allows the bar type to move the component at a specific rate. 44 * @property {enum} type - Type of the progress timer: cc.ProgressTimer.TYPE_RADIAL|cc.ProgressTimer.TYPE_BAR. 45 * @property {Number} percentage - Percentage to change progress, from 0 to 100. 46 * @property {cc.Sprite} sprite - The sprite to show the progress percentage. 47 * @property {Boolean} reverseDir - Indicate whether the direction is reversed. 48 */ 49 cc.ProgressTimer = cc.Node.extend(/** @lends cc.ProgressTimer# */{ 50 _type:null, 51 _percentage:0.0, 52 _sprite:null, 53 54 _midPoint:null, 55 _barChangeRate:null, 56 _reverseDirection:false, 57 _className:"ProgressTimer", 58 59 /** 60 * Midpoint is used to modify the progress start position. 61 * If you're using radials type then the midpoint changes the center point 62 * If you're using bar type the the midpoint changes the bar growth 63 * it expands from the center but clamps to the sprites edge so: 64 * you want a left to right then set the midpoint all the way to cc.p(0,y) 65 * you want a right to left then set the midpoint all the way to cc.p(1,y) 66 * you want a bottom to top then set the midpoint all the way to cc.p(x,0) 67 * you want a top to bottom then set the midpoint all the way to cc.p(x,1) 68 * @return {cc.Point} 69 */ 70 getMidpoint:function () { 71 return cc.p(this._midPoint.x, this._midPoint.y); 72 }, 73 74 /** 75 * Midpoint setter 76 * @param {cc.Point} mpoint 77 */ 78 setMidpoint:function (mpoint) { 79 this._midPoint = cc.pClamp(mpoint, cc.p(0, 0), cc.p(1, 1)); 80 }, 81 82 /** 83 * This allows the bar type to move the component at a specific rate 84 * Set the component to 0 to make sure it stays at 100%. 85 * For example you want a left to right bar but not have the height stay 100% 86 * Set the rate to be cc.p(0,1); and set the midpoint to = cc.p(0,.5f); 87 * @return {cc.Point} 88 */ 89 getBarChangeRate:function () { 90 return cc.p(this._barChangeRate.x, this._barChangeRate.y); 91 }, 92 93 /** 94 * @param {cc.Point} barChangeRate 95 */ 96 setBarChangeRate:function (barChangeRate) { 97 this._barChangeRate = cc.pClamp(barChangeRate, cc.p(0, 0), cc.p(1, 1)); 98 }, 99 100 /** 101 * Change the percentage to change progress 102 * @return {cc.ProgressTimer.TYPE_RADIAL|cc.ProgressTimer.TYPE_BAR} 103 */ 104 getType:function () { 105 return this._type; 106 }, 107 108 /** 109 * Percentages are from 0 to 100 110 * @return {Number} 111 */ 112 getPercentage:function () { 113 return this._percentage; 114 }, 115 116 /** 117 * The image to show the progress percentage, retain 118 * @return {cc.Sprite} 119 */ 120 getSprite:function () { 121 return this._sprite; 122 }, 123 124 /** 125 * from 0-100 126 * @param {Number} percentage 127 */ 128 setPercentage:function (percentage) { 129 if (this._percentage != percentage) { 130 this._percentage = cc.clampf(percentage, 0, 100); 131 this._updateProgress(); 132 } 133 }, 134 135 setOpacityModifyRGB:function (bValue) { 136 }, 137 138 isOpacityModifyRGB:function () { 139 return false; 140 }, 141 142 isReverseDirection:function () { 143 return this._reverseDirection; 144 }, 145 146 _boundaryTexCoord:function (index) { 147 if (index < cc.ProgressTimer.TEXTURE_COORDS_COUNT) { 148 var locProTextCoords = cc.ProgressTimer.TEXTURE_COORDS; 149 if (this._reverseDirection) 150 return cc.p((locProTextCoords >> (7 - (index << 1))) & 1, (locProTextCoords >> (7 - ((index << 1) + 1))) & 1); 151 else 152 return cc.p((locProTextCoords >> ((index << 1) + 1)) & 1, (locProTextCoords >> (index << 1)) & 1); 153 } 154 return cc.p(0,0); 155 }, 156 157 _origin:null, 158 _startAngle:270, 159 _endAngle:270, 160 _radius:0, 161 _counterClockWise:false, 162 _barRect:null, 163 164 _vertexDataCount:0, 165 _vertexData:null, 166 _vertexArrayBuffer:null, 167 _vertexWebGLBuffer:null, 168 _vertexDataDirty:false, 169 170 ctor: null, 171 172 _ctorForCanvas: function (sprite) { 173 cc.Node.prototype.ctor.call(this); 174 175 this._type = cc.ProgressTimer.TYPE_RADIAL; 176 this._percentage = 0.0; 177 this._midPoint = cc.p(0, 0); 178 this._barChangeRate = cc.p(0, 0); 179 this._reverseDirection = false; 180 181 this._sprite = null; 182 183 this._origin = cc.p(0,0); 184 this._startAngle = 270; 185 this._endAngle = 270; 186 this._radius = 0; 187 this._counterClockWise = false; 188 this._barRect = cc.rect(0, 0, 0, 0); 189 190 sprite && this._initWithSpriteForCanvas(sprite); 191 }, 192 193 _ctorForWebGL: function (sprite) { 194 cc.Node.prototype.ctor.call(this); 195 this._type = cc.ProgressTimer.TYPE_RADIAL; 196 this._percentage = 0.0; 197 this._midPoint = cc.p(0, 0); 198 this._barChangeRate = cc.p(0, 0); 199 this._reverseDirection = false; 200 201 this._sprite = null; 202 203 this._vertexWebGLBuffer = cc._renderContext.createBuffer(); 204 this._vertexDataCount = 0; 205 this._vertexData = null; 206 this._vertexArrayBuffer = null; 207 this._vertexDataDirty = false; 208 209 sprite && this._initWithSpriteForWebGL(sprite); 210 }, 211 212 /** 213 * set color of sprite 214 * @param {cc.Color} color 215 */ 216 setColor:function (color) { 217 this._sprite.color = color; 218 this._updateColor(); 219 }, 220 221 /** 222 * Opacity 223 * @param {Number} opacity 224 */ 225 setOpacity:function (opacity) { 226 this._sprite.opacity = opacity; 227 this._updateColor(); 228 }, 229 230 /** 231 * return color of sprite 232 * @return {cc.Color} 233 */ 234 getColor:function () { 235 return this._sprite.color; 236 }, 237 238 /** 239 * return Opacity of sprite 240 * @return {Number} 241 */ 242 getOpacity:function () { 243 return this._sprite.opacity; 244 }, 245 246 /** 247 * @function 248 * @param {Boolean} reverse 249 */ 250 setReverseProgress:null, 251 252 _setReverseProgressForCanvas:function (reverse) { 253 if (this._reverseDirection !== reverse) 254 this._reverseDirection = reverse; 255 }, 256 257 _setReverseProgressForWebGL:function (reverse) { 258 if (this._reverseDirection !== reverse) { 259 this._reverseDirection = reverse; 260 261 // release all previous information 262 this._vertexData = null; 263 this._vertexArrayBuffer = null; 264 this._vertexDataCount = 0; 265 } 266 }, 267 268 /** 269 * @function 270 * @param {cc.Sprite} sprite 271 */ 272 setSprite:null, 273 274 _setSpriteForCanvas:function (sprite) { 275 if (this._sprite != sprite) { 276 this._sprite = sprite; 277 this.width = this._sprite.width; 278 this.height = this._sprite.height; 279 } 280 }, 281 282 _setSpriteForWebGL:function (sprite) { 283 if (sprite && this._sprite != sprite) { 284 this._sprite = sprite; 285 this.width = sprite.width; 286 this.height = sprite.height; 287 288 // Everytime we set a new sprite, we free the current vertex data 289 if (this._vertexData) { 290 this._vertexData = null; 291 this._vertexArrayBuffer = null; 292 this._vertexDataCount = 0; 293 } 294 } 295 }, 296 297 /** 298 * set Progress type of cc.ProgressTimer 299 * @function 300 * @param {cc.ProgressTimer.TYPE_RADIAL|cc.ProgressTimer.TYPE_BAR} type 301 */ 302 setType:null, 303 304 _setTypeForCanvas:function (type) { 305 if (type !== this._type) 306 this._type = type; 307 }, 308 309 _setTypeForWebGL:function (type) { 310 if (type !== this._type) { 311 // release all previous information 312 if (this._vertexData) { 313 this._vertexData = null; 314 this._vertexArrayBuffer = null; 315 this._vertexDataCount = 0; 316 } 317 this._type = type; 318 } 319 }, 320 321 /** 322 * Reverse Progress setter 323 * @function 324 * @param {Boolean} reverse 325 */ 326 setReverseDirection: null, 327 328 _setReverseDirectionForCanvas: function (reverse) { 329 if (this._reverseDirection !== reverse) 330 this._reverseDirection = reverse; 331 }, 332 333 _setReverseDirectionForWebGL: function (reverse) { 334 if (this._reverseDirection !== reverse) { 335 this._reverseDirection = reverse; 336 //release all previous information 337 this._vertexData = null; 338 this._vertexArrayBuffer = null; 339 this._vertexDataCount = 0; 340 } 341 }, 342 343 /** 344 * @param {cc.Point} alpha 345 * @return {cc.Vertex2F | Object} the vertex position from the texture coordinate 346 * @private 347 */ 348 _textureCoordFromAlphaPoint:function (alpha) { 349 var locSprite = this._sprite; 350 if (!locSprite) { 351 return {u:0, v:0}; //new cc.Tex2F(0, 0); 352 } 353 var quad = locSprite.quad; 354 var min = cc.p(quad.bl.texCoords.u, quad.bl.texCoords.v); 355 var max = cc.p(quad.tr.texCoords.u, quad.tr.texCoords.v); 356 357 // Fix bug #1303 so that progress timer handles sprite frame texture rotation 358 if (locSprite.textureRectRotated) { 359 var temp = alpha.x; 360 alpha.x = alpha.y; 361 alpha.y = temp; 362 } 363 return {u: min.x * (1 - alpha.x) + max.x * alpha.x, v: min.y * (1 - alpha.y) + max.y * alpha.y}; 364 }, 365 366 _vertexFromAlphaPoint:function (alpha) { 367 if (!this._sprite) { 368 return {x: 0, y: 0}; 369 } 370 var quad = this._sprite.quad; 371 var min = cc.p(quad.bl.vertices.x, quad.bl.vertices.y); 372 var max = cc.p(quad.tr.vertices.x, quad.tr.vertices.y); 373 return {x: min.x * (1 - alpha.x) + max.x * alpha.x, y: min.y * (1 - alpha.y) + max.y * alpha.y}; 374 }, 375 376 /** 377 * Initializes a progress timer with the sprite as the shape the timer goes through 378 * @function 379 * @param {cc.Sprite} sprite 380 * @return {Boolean} 381 */ 382 initWithSprite:null, 383 384 _initWithSpriteForCanvas:function (sprite) { 385 this.percentage = 0; 386 this.anchorX = 0.5; 387 this.anchorY = 0.5; 388 389 this._type = cc.ProgressTimer.TYPE_RADIAL; 390 this._reverseDirection = false; 391 this.midPoint = cc.p(0.5, 0.5); 392 this.barChangeRate = cc.p(1, 1); 393 this.sprite = sprite; 394 395 return true; 396 }, 397 398 _initWithSpriteForWebGL:function (sprite) { 399 this.percentage = 0; 400 this._vertexData = null; 401 this._vertexArrayBuffer = null; 402 this._vertexDataCount = 0; 403 this.anchorX = 0.5; 404 this.anchorY = 0.5; 405 406 this._type = cc.ProgressTimer.TYPE_RADIAL; 407 this._reverseDirection = false; 408 this.midPoint = cc.p(0.5, 0.5); 409 this.barChangeRate = cc.p(1, 1); 410 this.sprite = sprite; 411 412 //shader program 413 this.shaderProgram = cc.shaderCache.programForKey(cc.SHADER_POSITION_TEXTURECOLOR); 414 return true; 415 }, 416 417 /** 418 * Stuff gets drawn here 419 * @function 420 * @param {CanvasRenderingContext2D} ctx 421 */ 422 draw:null, 423 424 _drawForCanvas:function (ctx) { 425 var context = ctx || cc._renderContext; 426 427 var locSprite = this._sprite; 428 if (locSprite._isLighterMode) 429 context.globalCompositeOperation = 'lighter'; 430 431 var locEGL_ScaleX = cc.view.getScaleX(), locEGL_ScaleY = cc.view.getScaleY(); 432 433 context.globalAlpha = locSprite._displayedOpacity / 255; 434 var locRect = locSprite._rect, locContentSize = locSprite._contentSize, locOffsetPosition = locSprite._offsetPosition, locDrawSizeCanvas = locSprite._drawSize_Canvas; 435 var flipXOffset = 0 | (locOffsetPosition.x), flipYOffset = -locOffsetPosition.y - locRect.height, locTextureCoord = locSprite._textureRect_Canvas; 436 locDrawSizeCanvas.width = locRect.width * locEGL_ScaleX; 437 locDrawSizeCanvas.height = locRect.height * locEGL_ScaleY; 438 439 context.save(); 440 if (locSprite._flippedX) { 441 flipXOffset = -locOffsetPosition.x - locRect.width; 442 context.scale(-1, 1); 443 } 444 if (locSprite._flippedY) { 445 flipYOffset = locOffsetPosition.y; 446 context.scale(1, -1); 447 } 448 449 flipXOffset *= locEGL_ScaleX; 450 flipYOffset *= locEGL_ScaleY; 451 452 //clip 453 if (this._type == cc.ProgressTimer.TYPE_BAR) { 454 var locBarRect = this._barRect; 455 context.beginPath(); 456 context.rect(locBarRect.x * locEGL_ScaleX, locBarRect.y * locEGL_ScaleY, locBarRect.width * locEGL_ScaleX, locBarRect.height * locEGL_ScaleY); 457 context.clip(); 458 context.closePath(); 459 } else if (this._type == cc.ProgressTimer.TYPE_RADIAL) { 460 var locOriginX = this._origin.x * locEGL_ScaleX; 461 var locOriginY = this._origin.y * locEGL_ScaleY; 462 context.beginPath(); 463 context.arc(locOriginX, locOriginY, this._radius * locEGL_ScaleY, (Math.PI / 180) * this._startAngle, (Math.PI / 180) * this._endAngle, this._counterClockWise); 464 context.lineTo(locOriginX, locOriginY); 465 context.clip(); 466 context.closePath(); 467 } 468 469 //draw sprite 470 if (locSprite._texture && locTextureCoord.validRect) { 471 var image = locSprite._texture.getHtmlElementObj(); 472 if (this._colorized) { 473 context.drawImage(image, 474 0, 0, locTextureCoord.width, locTextureCoord.height, 475 flipXOffset, flipYOffset, locDrawSizeCanvas.width, locDrawSizeCanvas.height); 476 } else { 477 context.drawImage(image, 478 locTextureCoord.x, locTextureCoord.y, locTextureCoord.width, locTextureCoord.height, 479 flipXOffset, flipYOffset, locDrawSizeCanvas.width , locDrawSizeCanvas.height); 480 } 481 } else if (locContentSize.width !== 0) { 482 var curColor = this.color; 483 context.fillStyle = "rgba(" + curColor.r + "," + curColor.g + "," + curColor.b + ",1)"; 484 context.fillRect(flipXOffset, flipYOffset, locContentSize.width * locEGL_ScaleX, locContentSize.height * locEGL_ScaleY); 485 } 486 487 context.restore(); 488 cc.incrementGLDraws(1); 489 }, 490 491 _drawForWebGL:function (ctx) { 492 var context = ctx || cc._renderContext; 493 if (!this._vertexData || !this._sprite) 494 return; 495 496 cc.nodeDrawSetup(this); 497 498 var blendFunc = this._sprite.getBlendFunc(); 499 cc.glBlendFunc(blendFunc.src, blendFunc.dst); 500 cc.glEnableVertexAttribs(cc.VERTEX_ATTRIB_FLAG_POS_COLOR_TEX); 501 502 cc.glBindTexture2D(this._sprite.texture); 503 504 context.bindBuffer(context.ARRAY_BUFFER, this._vertexWebGLBuffer); 505 if(this._vertexDataDirty){ 506 context.bufferData(context.ARRAY_BUFFER, this._vertexArrayBuffer, context.DYNAMIC_DRAW); 507 this._vertexDataDirty = false; 508 } 509 var locVertexDataLen = cc.V2F_C4B_T2F.BYTES_PER_ELEMENT; 510 context.vertexAttribPointer(cc.VERTEX_ATTRIB_POSITION, 2, context.FLOAT, false, locVertexDataLen, 0); 511 context.vertexAttribPointer(cc.VERTEX_ATTRIB_COLOR, 4, context.UNSIGNED_BYTE, true, locVertexDataLen, 8); 512 context.vertexAttribPointer(cc.VERTEX_ATTRIB_TEX_COORDS, 2, context.FLOAT, false, locVertexDataLen, 12); 513 514 if (this._type === cc.ProgressTimer.TYPE_RADIAL) 515 context.drawArrays(context.TRIANGLE_FAN, 0, this._vertexDataCount); 516 else if (this._type == cc.ProgressTimer.TYPE_BAR) { 517 if (!this._reverseDirection) 518 context.drawArrays(context.TRIANGLE_STRIP, 0, this._vertexDataCount); 519 else { 520 context.drawArrays(context.TRIANGLE_STRIP, 0, this._vertexDataCount / 2); 521 context.drawArrays(context.TRIANGLE_STRIP, 4, this._vertexDataCount / 2); 522 // 2 draw calls 523 cc.g_NumberOfDraws++; 524 } 525 } 526 cc.g_NumberOfDraws++; 527 }, 528 529 /** 530 * <p> 531 * Update does the work of mapping the texture onto the triangles <br/> 532 * It now doesn't occur the cost of free/alloc data every update cycle. <br/> 533 * It also only changes the percentage point but no other points if they have not been modified. <br/> 534 * <br/> 535 * It now deals with flipped texture. If you run into this problem, just use the <br/> 536 * sprite property and enable the methods flipX, flipY. <br/> 537 * </p> 538 * @private 539 */ 540 _updateRadial:function () { 541 if (!this._sprite) 542 return; 543 544 var i, locMidPoint = this._midPoint; 545 var alpha = this._percentage / 100; 546 var angle = 2 * (cc.PI) * ( this._reverseDirection ? alpha : 1.0 - alpha); 547 548 // We find the vector to do a hit detection based on the percentage 549 // We know the first vector is the one @ 12 o'clock (top,mid) so we rotate 550 // from that by the progress angle around the m_tMidpoint pivot 551 var topMid = cc.p(locMidPoint.x, 1); 552 var percentagePt = cc.pRotateByAngle(topMid, locMidPoint, angle); 553 554 var index = 0; 555 var hit; 556 557 if (alpha == 0) { 558 // More efficient since we don't always need to check intersection 559 // If the alpha is zero then the hit point is top mid and the index is 0. 560 hit = topMid; 561 index = 0; 562 } else if (alpha == 1) { 563 // More efficient since we don't always need to check intersection 564 // If the alpha is one then the hit point is top mid and the index is 4. 565 hit = topMid; 566 index = 4; 567 } else { 568 // We run a for loop checking the edges of the texture to find the 569 // intersection point 570 // We loop through five points since the top is split in half 571 572 var min_t = cc.FLT_MAX; 573 var locProTextCoordsCount = cc.ProgressTimer.TEXTURE_COORDS_COUNT; 574 for (i = 0; i <= locProTextCoordsCount; ++i) { 575 var pIndex = (i + (locProTextCoordsCount - 1)) % locProTextCoordsCount; 576 577 var edgePtA = this._boundaryTexCoord(i % locProTextCoordsCount); 578 var edgePtB = this._boundaryTexCoord(pIndex); 579 580 // Remember that the top edge is split in half for the 12 o'clock position 581 // Let's deal with that here by finding the correct endpoints 582 if (i == 0) 583 edgePtB = cc.pLerp(edgePtA, edgePtB, 1 - locMidPoint.x); 584 else if (i == 4) 585 edgePtA = cc.pLerp(edgePtA, edgePtB, 1 - locMidPoint.x); 586 587 // retPoint are returned by ccpLineIntersect 588 var retPoint = cc.p(0, 0); 589 if (cc.pLineIntersect(edgePtA, edgePtB, locMidPoint, percentagePt, retPoint)) { 590 // Since our hit test is on rays we have to deal with the top edge 591 // being in split in half so we have to test as a segment 592 if ((i == 0 || i == 4)) { 593 // s represents the point between edgePtA--edgePtB 594 if (!(0 <= retPoint.x && retPoint.x <= 1)) 595 continue; 596 } 597 // As long as our t isn't negative we are at least finding a 598 // correct hitpoint from m_tMidpoint to percentagePt. 599 if (retPoint.y >= 0) { 600 // Because the percentage line and all the texture edges are 601 // rays we should only account for the shortest intersection 602 if (retPoint.y < min_t) { 603 min_t = retPoint.y; 604 index = i; 605 } 606 } 607 } 608 } 609 610 // Now that we have the minimum magnitude we can use that to find our intersection 611 hit = cc.pAdd(locMidPoint, cc.pMult(cc.pSub(percentagePt, locMidPoint), min_t)); 612 } 613 614 // The size of the vertex data is the index from the hitpoint 615 // the 3 is for the m_tMidpoint, 12 o'clock point and hitpoint position. 616 var sameIndexCount = true; 617 if (this._vertexDataCount != index + 3) { 618 sameIndexCount = false; 619 this._vertexData = null; 620 this._vertexArrayBuffer = null; 621 this._vertexDataCount = 0; 622 } 623 624 if (!this._vertexData) { 625 this._vertexDataCount = index + 3; 626 var locCount = this._vertexDataCount, vertexDataLen = cc.V2F_C4B_T2F.BYTES_PER_ELEMENT; 627 this._vertexArrayBuffer = new ArrayBuffer(locCount * vertexDataLen); 628 var locData = []; 629 for (i = 0; i < locCount; i++) 630 locData[i] = new cc.V2F_C4B_T2F(null, null, null, this._vertexArrayBuffer, i * vertexDataLen); 631 632 this._vertexData = locData; 633 if(!this._vertexData){ 634 cc.log( "cc.ProgressTimer._updateRadial() : Not enough memory"); 635 return; 636 } 637 } 638 this._updateColor(); 639 640 var locVertexData = this._vertexData; 641 if (!sameIndexCount) { 642 // First we populate the array with the m_tMidpoint, then all 643 // vertices/texcoords/colors of the 12 'o clock start and edges and the hitpoint 644 locVertexData[0].texCoords = this._textureCoordFromAlphaPoint(locMidPoint); 645 locVertexData[0].vertices = this._vertexFromAlphaPoint(locMidPoint); 646 647 locVertexData[1].texCoords = this._textureCoordFromAlphaPoint(topMid); 648 locVertexData[1].vertices = this._vertexFromAlphaPoint(topMid); 649 650 for (i = 0; i < index; i++) { 651 var alphaPoint = this._boundaryTexCoord(i); 652 locVertexData[i + 2].texCoords = this._textureCoordFromAlphaPoint(alphaPoint); 653 locVertexData[i + 2].vertices = this._vertexFromAlphaPoint(alphaPoint); 654 } 655 } 656 657 // hitpoint will go last 658 locVertexData[this._vertexDataCount - 1].texCoords = this._textureCoordFromAlphaPoint(hit); 659 locVertexData[this._vertexDataCount - 1].vertices = this._vertexFromAlphaPoint(hit); 660 }, 661 662 /** 663 * <p> 664 * Update does the work of mapping the texture onto the triangles for the bar <br/> 665 * It now doesn't occur the cost of free/alloc data every update cycle. <br/> 666 * It also only changes the percentage point but no other points if they have not been modified. <br/> 667 * <br/> 668 * It now deals with flipped texture. If you run into this problem, just use the <br/> 669 * sprite property and enable the methods flipX, flipY. <br/> 670 * </p> 671 * @private 672 */ 673 _updateBar:function () { 674 if (!this._sprite) 675 return; 676 677 var i; 678 var alpha = this._percentage / 100.0; 679 var locBarChangeRate = this._barChangeRate; 680 var alphaOffset = cc.pMult(cc.p((1.0 - locBarChangeRate.x) + alpha * locBarChangeRate.x, 681 (1.0 - locBarChangeRate.y) + alpha * locBarChangeRate.y), 0.5); 682 var min = cc.pSub(this._midPoint, alphaOffset); 683 var max = cc.pAdd(this._midPoint, alphaOffset); 684 685 if (min.x < 0) { 686 max.x += -min.x; 687 min.x = 0; 688 } 689 690 if (max.x > 1) { 691 min.x -= max.x - 1; 692 max.x = 1; 693 } 694 695 if (min.y < 0) { 696 max.y += -min.y; 697 min.y = 0; 698 } 699 700 if (max.y > 1) { 701 min.y -= max.y - 1; 702 max.y = 1; 703 } 704 705 var locVertexData; 706 if (!this._reverseDirection) { 707 if (!this._vertexData) { 708 this._vertexDataCount = 4; 709 var vertexDataLen = cc.V2F_C4B_T2F.BYTES_PER_ELEMENT, locCount = 4; 710 this._vertexArrayBuffer = new ArrayBuffer(locCount * vertexDataLen); 711 this._vertexData = []; 712 for (i = 0; i < locCount; i++) 713 this._vertexData[i] = new cc.V2F_C4B_T2F(null, null, null, this._vertexArrayBuffer, i * vertexDataLen); 714 } 715 716 locVertexData = this._vertexData; 717 // TOPLEFT 718 locVertexData[0].texCoords = this._textureCoordFromAlphaPoint(cc.p(min.x, max.y)); 719 locVertexData[0].vertices = this._vertexFromAlphaPoint(cc.p(min.x, max.y)); 720 721 // BOTLEFT 722 locVertexData[1].texCoords = this._textureCoordFromAlphaPoint(cc.p(min.x, min.y)); 723 locVertexData[1].vertices = this._vertexFromAlphaPoint(cc.p(min.x, min.y)); 724 725 // TOPRIGHT 726 locVertexData[2].texCoords = this._textureCoordFromAlphaPoint(cc.p(max.x, max.y)); 727 locVertexData[2].vertices = this._vertexFromAlphaPoint(cc.p(max.x, max.y)); 728 729 // BOTRIGHT 730 locVertexData[3].texCoords = this._textureCoordFromAlphaPoint(cc.p(max.x, min.y)); 731 locVertexData[3].vertices = this._vertexFromAlphaPoint(cc.p(max.x, min.y)); 732 } else { 733 if (!this._vertexData) { 734 this._vertexDataCount = 8; 735 var rVertexDataLen = cc.V2F_C4B_T2F.BYTES_PER_ELEMENT, rLocCount = 8; 736 this._vertexArrayBuffer = new ArrayBuffer(rLocCount * rVertexDataLen); 737 var rTempData = []; 738 for (i = 0; i < rLocCount; i++) 739 rTempData[i] = new cc.V2F_C4B_T2F(null, null, null, this._vertexArrayBuffer, i * rVertexDataLen); 740 // TOPLEFT 1 741 rTempData[0].texCoords = this._textureCoordFromAlphaPoint(cc.p(0, 1)); 742 rTempData[0].vertices = this._vertexFromAlphaPoint(cc.p(0, 1)); 743 744 // BOTLEFT 1 745 rTempData[1].texCoords = this._textureCoordFromAlphaPoint(cc.p(0, 0)); 746 rTempData[1].vertices = this._vertexFromAlphaPoint(cc.p(0, 0)); 747 748 // TOPRIGHT 2 749 rTempData[6].texCoords = this._textureCoordFromAlphaPoint(cc.p(1, 1)); 750 rTempData[6].vertices = this._vertexFromAlphaPoint(cc.p(1, 1)); 751 752 // BOTRIGHT 2 753 rTempData[7].texCoords = this._textureCoordFromAlphaPoint(cc.p(1, 0)); 754 rTempData[7].vertices = this._vertexFromAlphaPoint(cc.p(1, 0)); 755 756 this._vertexData = rTempData; 757 } 758 759 locVertexData = this._vertexData; 760 // TOPRIGHT 1 761 locVertexData[2].texCoords = this._textureCoordFromAlphaPoint(cc.p(min.x, max.y)); 762 locVertexData[2].vertices = this._vertexFromAlphaPoint(cc.p(min.x, max.y)); 763 764 // BOTRIGHT 1 765 locVertexData[3].texCoords = this._textureCoordFromAlphaPoint(cc.p(min.x, min.y)); 766 locVertexData[3].vertices = this._vertexFromAlphaPoint(cc.p(min.x, min.y)); 767 768 // TOPLEFT 2 769 locVertexData[4].texCoords = this._textureCoordFromAlphaPoint(cc.p(max.x, max.y)); 770 locVertexData[4].vertices = this._vertexFromAlphaPoint(cc.p(max.x, max.y)); 771 772 // BOTLEFT 2 773 locVertexData[5].texCoords = this._textureCoordFromAlphaPoint(cc.p(max.x, min.y)); 774 locVertexData[5].vertices = this._vertexFromAlphaPoint(cc.p(max.x, min.y)); 775 } 776 this._updateColor(); 777 }, 778 779 _updateColor:function () { 780 if (!this._sprite || !this._vertexData) 781 return; 782 783 var sc = this._sprite.quad.tl.colors; 784 var locVertexData = this._vertexData; 785 for (var i = 0, len = this._vertexDataCount; i < len; ++i) 786 locVertexData[i].colors = sc; 787 this._vertexDataDirty = true; 788 }, 789 790 _updateProgress:null, 791 792 _updateProgressForCanvas:function () { 793 var locSprite = this._sprite; 794 var sw = locSprite.width, sh = locSprite.height; 795 var locMidPoint = this._midPoint; 796 797 if (this._type == cc.ProgressTimer.TYPE_RADIAL) { 798 this._radius = Math.round(Math.sqrt(sw * sw + sh * sh)); 799 var locStartAngle, locEndAngle, locCounterClockWise = false, locOrigin = this._origin; 800 locOrigin.x = sw * locMidPoint.x; 801 locOrigin.y = -sh * locMidPoint.y; 802 803 if (this._reverseDirection) { 804 locEndAngle = 270; 805 locStartAngle = 270 - 3.6 * this._percentage; 806 } else { 807 locStartAngle = -90; 808 locEndAngle = -90 + 3.6 * this._percentage; 809 } 810 811 if (locSprite._flippedX) { 812 locOrigin.x -= sw * (this._midPoint.x * 2); 813 locStartAngle= -locStartAngle; 814 locEndAngle= -locEndAngle; 815 locStartAngle -= 180; 816 locEndAngle -= 180; 817 locCounterClockWise = !locCounterClockWise; 818 } 819 if (locSprite._flippedY) { 820 locOrigin.y+=sh*(this._midPoint.y*2); 821 locCounterClockWise = !locCounterClockWise; 822 locStartAngle= -locStartAngle; 823 locEndAngle= -locEndAngle; 824 } 825 826 this._startAngle = locStartAngle; 827 this._endAngle = locEndAngle; 828 this._counterClockWise = locCounterClockWise; 829 } else { 830 var locBarChangeRate = this._barChangeRate; 831 var percentageF = this._percentage / 100; 832 var locBarRect = this._barRect; 833 834 var drawedSize = cc.size((sw * (1 - locBarChangeRate.x)), (sh * (1 - locBarChangeRate.y))); 835 var drawingSize = cc.size((sw - drawedSize.width) * percentageF, (sh - drawedSize.height) * percentageF); 836 var currentDrawSize = cc.size(drawedSize.width + drawingSize.width, drawedSize.height + drawingSize.height); 837 838 var startPoint = cc.p(sw * locMidPoint.x, sh * locMidPoint.y); 839 840 var needToLeft = startPoint.x - currentDrawSize.width / 2; 841 if (locMidPoint.x > 0.5) { 842 if (currentDrawSize.width / 2 >= sw - startPoint.x) { 843 needToLeft = sw - currentDrawSize.width; 844 } 845 } 846 847 var needToTop = startPoint.y - currentDrawSize.height / 2; 848 if (locMidPoint.y > 0.5) { 849 if (currentDrawSize.height / 2 >= sh - startPoint.y) { 850 needToTop = sh - currentDrawSize.height; 851 } 852 } 853 854 //left pos 855 locBarRect.x = 0; 856 var flipXNeed = 1; 857 if (locSprite._flippedX) { 858 locBarRect.x -= currentDrawSize.width; 859 flipXNeed = -1; 860 } 861 862 if (needToLeft > 0) 863 locBarRect.x += needToLeft * flipXNeed; 864 865 //right pos 866 locBarRect.y = 0; 867 var flipYNeed = 1; 868 if (locSprite._flippedY) { 869 locBarRect.y += currentDrawSize.height; 870 flipYNeed = -1; 871 } 872 873 if (needToTop > 0) 874 locBarRect.y -= needToTop * flipYNeed; 875 876 //clip width and clip height 877 locBarRect.width = currentDrawSize.width; 878 locBarRect.height = -currentDrawSize.height; 879 } 880 }, 881 882 _updateProgressForWebGL:function () { 883 var locType = this._type; 884 if(locType === cc.ProgressTimer.TYPE_RADIAL) 885 this._updateRadial(); 886 else if(locType === cc.ProgressTimer.TYPE_BAR) 887 this._updateBar(); 888 this._vertexDataDirty = true; 889 } 890 }); 891 892 var _p = cc.ProgressTimer.prototype; 893 if(cc._renderType == cc._RENDER_TYPE_WEBGL){ 894 _p.ctor = _p._ctorForWebGL; 895 _p.setReverseProgress = _p._setReverseProgressForWebGL; 896 _p.setSprite = _p._setSpriteForWebGL; 897 _p.setType = _p._setTypeForWebGL; 898 _p.setReverseDirection = _p._setReverseDirectionForWebGL; 899 _p.initWithSprite = _p._initWithSpriteForWebGL; 900 _p.draw = _p._drawForWebGL; 901 _p._updateProgress = _p._updateProgressForWebGL; 902 } else { 903 _p.ctor = _p._ctorForCanvas; 904 _p.setReverseProgress = _p._setReverseProgressForCanvas; 905 _p.setSprite = _p._setSpriteForCanvas; 906 _p.setType = _p._setTypeForCanvas; 907 _p.setReverseDirection = _p._setReverseDirectionForCanvas; 908 _p.initWithSprite = _p._initWithSpriteForCanvas; 909 _p.draw = _p._drawForCanvas; 910 _p._updateProgress = cc.ProgressTimer.prototype._updateProgressForCanvas; 911 } 912 913 // Extended properties 914 /** @expose */ 915 _p.midPoint; 916 cc.defineGetterSetter(_p, "midPoint", _p.getMidpoint, _p.setMidpoint); 917 /** @expose */ 918 _p.barChangeRate; 919 cc.defineGetterSetter(_p, "barChangeRate", _p.getBarChangeRate, _p.setBarChangeRate); 920 /** @expose */ 921 _p.type; 922 cc.defineGetterSetter(_p, "type", _p.getType, _p.setType); 923 /** @expose */ 924 _p.percentage; 925 cc.defineGetterSetter(_p, "percentage", _p.getPercentage, _p.setPercentage); 926 /** @expose */ 927 _p.sprite; 928 cc.defineGetterSetter(_p, "sprite", _p.getSprite, _p.setSprite); 929 /** @expose */ 930 _p.reverseDir; 931 cc.defineGetterSetter(_p, "reverseDir", _p.isReverseDirection, _p.setReverseDirection); 932 933 934 /** 935 * create a progress timer object with image file name that renders the inner sprite according to the percentage 936 * @deprecated 937 * @param {cc.Sprite} sprite 938 * @return {cc.ProgressTimer} 939 * @example 940 * // Example 941 * var progress = cc.ProgressTimer.create('progress.png') 942 */ 943 cc.ProgressTimer.create = function (sprite) { 944 return new cc.ProgressTimer(sprite); 945 }; 946 947 /** 948 * @constant 949 * @type Number 950 */ 951 cc.ProgressTimer.TEXTURE_COORDS_COUNT = 4; 952 953 /** 954 * @constant 955 * @type Number 956 */ 957 cc.ProgressTimer.TEXTURE_COORDS = 0x4b; 958 959 /** 960 * Radial Counter-Clockwise 961 * @type Number 962 * @constant 963 */ 964 cc.ProgressTimer.TYPE_RADIAL = 0; 965 966 /** 967 * Bar 968 * @type Number 969 * @constant 970 */ 971 cc.ProgressTimer.TYPE_BAR = 1; 972