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.NodeRGBA 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.NodeRGBA.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 () { 173 cc.NodeRGBA.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 191 _ctorForWebGL: function () { 192 cc.NodeRGBA.prototype.ctor.call(this); 193 this._type = cc.ProgressTimer.TYPE_RADIAL; 194 this._percentage = 0.0; 195 this._midPoint = cc.p(0, 0); 196 this._barChangeRate = cc.p(0, 0); 197 this._reverseDirection = false; 198 199 this._sprite = null; 200 201 this._vertexWebGLBuffer = cc._renderContext.createBuffer(); 202 this._vertexDataCount = 0; 203 this._vertexData = null; 204 this._vertexArrayBuffer = null; 205 this._vertexDataDirty = false; 206 }, 207 208 /** 209 * set color of sprite 210 * @param {cc.Color} color 211 */ 212 setColor:function (color) { 213 this._sprite.color = color; 214 this._updateColor(); 215 }, 216 217 /** 218 * Opacity 219 * @param {Number} opacity 220 */ 221 setOpacity:function (opacity) { 222 this._sprite.opacity = opacity; 223 this._updateColor(); 224 }, 225 226 /** 227 * return color of sprite 228 * @return {cc.Color} 229 */ 230 getColor:function () { 231 return this._sprite.color; 232 }, 233 234 /** 235 * return Opacity of sprite 236 * @return {Number} 237 */ 238 getOpacity:function () { 239 return this._sprite.opacity; 240 }, 241 242 /** 243 * @function 244 * @param {Boolean} reverse 245 */ 246 setReverseProgress:null, 247 248 _setReverseProgressForCanvas:function (reverse) { 249 if (this._reverseDirection !== reverse) 250 this._reverseDirection = reverse; 251 }, 252 253 _setReverseProgressForWebGL:function (reverse) { 254 if (this._reverseDirection !== reverse) { 255 this._reverseDirection = reverse; 256 257 // release all previous information 258 this._vertexData = null; 259 this._vertexArrayBuffer = null; 260 this._vertexDataCount = 0; 261 } 262 }, 263 264 /** 265 * @function 266 * @param {cc.Sprite} sprite 267 */ 268 setSprite:null, 269 270 _setSpriteForCanvas:function (sprite) { 271 if (this._sprite != sprite) { 272 this._sprite = sprite; 273 this.width = this._sprite.width; 274 this.height = this._sprite.height; 275 } 276 }, 277 278 _setSpriteForWebGL:function (sprite) { 279 if (sprite && this._sprite != sprite) { 280 this._sprite = sprite; 281 this.width = sprite.width; 282 this.height = sprite.height; 283 284 // Everytime we set a new sprite, we free the current vertex data 285 if (this._vertexData) { 286 this._vertexData = null; 287 this._vertexArrayBuffer = null; 288 this._vertexDataCount = 0; 289 } 290 } 291 }, 292 293 /** 294 * set Progress type of cc.ProgressTimer 295 * @function 296 * @param {cc.ProgressTimer.TYPE_RADIAL|cc.ProgressTimer.TYPE_BAR} type 297 */ 298 setType:null, 299 300 _setTypeForCanvas:function (type) { 301 if (type !== this._type) 302 this._type = type; 303 }, 304 305 _setTypeForWebGL:function (type) { 306 if (type !== this._type) { 307 // release all previous information 308 if (this._vertexData) { 309 this._vertexData = null; 310 this._vertexArrayBuffer = null; 311 this._vertexDataCount = 0; 312 } 313 this._type = type; 314 } 315 }, 316 317 /** 318 * Reverse Progress setter 319 * @function 320 * @param {Boolean} reverse 321 */ 322 setReverseDirection: null, 323 324 _setReverseDirectionForCanvas: function (reverse) { 325 if (this._reverseDirection !== reverse) 326 this._reverseDirection = reverse; 327 }, 328 329 _setReverseDirectionForWebGL: function (reverse) { 330 if (this._reverseDirection !== reverse) { 331 this._reverseDirection = reverse; 332 //release all previous information 333 this._vertexData = null; 334 this._vertexArrayBuffer = null; 335 this._vertexDataCount = 0; 336 } 337 }, 338 339 /** 340 * @param {cc.Point} alpha 341 * @return {cc.Vertex2F | Object} the vertex position from the texture coordinate 342 * @private 343 */ 344 _textureCoordFromAlphaPoint:function (alpha) { 345 var locSprite = this._sprite; 346 if (!locSprite) { 347 return {u:0, v:0}; //new cc.Tex2F(0, 0); 348 } 349 var quad = locSprite.quad; 350 var min = cc.p(quad.bl.texCoords.u, quad.bl.texCoords.v); 351 var max = cc.p(quad.tr.texCoords.u, quad.tr.texCoords.v); 352 353 // Fix bug #1303 so that progress timer handles sprite frame texture rotation 354 if (locSprite.textureRectRotated) { 355 var temp = alpha.x; 356 alpha.x = alpha.y; 357 alpha.y = temp; 358 } 359 return {u: min.x * (1 - alpha.x) + max.x * alpha.x, v: min.y * (1 - alpha.y) + max.y * alpha.y}; 360 }, 361 362 _vertexFromAlphaPoint:function (alpha) { 363 if (!this._sprite) { 364 return {x: 0, y: 0}; 365 } 366 var quad = this._sprite.quad; 367 var min = cc.p(quad.bl.vertices.x, quad.bl.vertices.y); 368 var max = cc.p(quad.tr.vertices.x, quad.tr.vertices.y); 369 return {x: min.x * (1 - alpha.x) + max.x * alpha.x, y: min.y * (1 - alpha.y) + max.y * alpha.y}; 370 }, 371 372 /** 373 * Initializes a progress timer with the sprite as the shape the timer goes through 374 * @function 375 * @param {cc.Sprite} sprite 376 * @return {Boolean} 377 */ 378 initWithSprite:null, 379 380 _initWithSpriteForCanvas:function (sprite) { 381 this.percentage = 0; 382 this.anchorX = 0.5; 383 this.anchorY = 0.5; 384 385 this._type = cc.ProgressTimer.TYPE_RADIAL; 386 this._reverseDirection = false; 387 this.midPoint = cc.p(0.5, 0.5); 388 this.barChangeRate = cc.p(1, 1); 389 this.sprite = sprite; 390 391 return true; 392 }, 393 394 _initWithSpriteForWebGL:function (sprite) { 395 this.percentage = 0; 396 this._vertexData = null; 397 this._vertexArrayBuffer = null; 398 this._vertexDataCount = 0; 399 this.anchorX = 0.5; 400 this.anchorY = 0.5; 401 402 this._type = cc.ProgressTimer.TYPE_RADIAL; 403 this._reverseDirection = false; 404 this.midPoint = cc.p(0.5, 0.5); 405 this.barChangeRate = cc.p(1, 1); 406 this.sprite = sprite; 407 408 //shader program 409 this.shaderProgram = cc.shaderCache.programForKey(cc.SHADER_POSITION_TEXTURECOLOR); 410 return true; 411 }, 412 413 /** 414 * Stuff gets drawn here 415 * @function 416 * @param {CanvasRenderingContext2D} ctx 417 */ 418 draw:null, 419 420 _drawForCanvas:function (ctx) { 421 var context = ctx || cc._renderContext; 422 423 var locSprite = this._sprite; 424 if (locSprite._isLighterMode) 425 context.globalCompositeOperation = 'lighter'; 426 427 var locEGL_ScaleX = cc.view.getScaleX(), locEGL_ScaleY = cc.view.getScaleY(); 428 429 context.globalAlpha = locSprite._displayedOpacity / 255; 430 var locRect = locSprite._rect, locContentSize = locSprite._contentSize, locOffsetPosition = locSprite._offsetPosition, locDrawSizeCanvas = locSprite._drawSize_Canvas; 431 var flipXOffset = 0 | (locOffsetPosition.x), flipYOffset = -locOffsetPosition.y - locRect.height, locTextureCoord = locSprite._textureRect_Canvas; 432 locDrawSizeCanvas.width = locRect.width * locEGL_ScaleX; 433 locDrawSizeCanvas.height = locRect.height * locEGL_ScaleY; 434 435 context.save(); 436 if (locSprite._flippedX) { 437 flipXOffset = -locOffsetPosition.x - locRect.width; 438 context.scale(-1, 1); 439 } 440 if (locSprite._flippedY) { 441 flipYOffset = locOffsetPosition.y; 442 context.scale(1, -1); 443 } 444 445 flipXOffset *= locEGL_ScaleX; 446 flipYOffset *= locEGL_ScaleY; 447 448 //clip 449 if (this._type == cc.ProgressTimer.TYPE_BAR) { 450 var locBarRect = this._barRect; 451 context.beginPath(); 452 context.rect(locBarRect.x * locEGL_ScaleX, locBarRect.y * locEGL_ScaleY, locBarRect.width * locEGL_ScaleX, locBarRect.height * locEGL_ScaleY); 453 context.clip(); 454 context.closePath(); 455 } else if (this._type == cc.ProgressTimer.TYPE_RADIAL) { 456 var locOriginX = this._origin.x * locEGL_ScaleX; 457 var locOriginY = this._origin.y * locEGL_ScaleY; 458 context.beginPath(); 459 context.arc(locOriginX, locOriginY, this._radius * locEGL_ScaleY, (Math.PI / 180) * this._startAngle, (Math.PI / 180) * this._endAngle, this._counterClockWise); 460 context.lineTo(locOriginX, locOriginY); 461 context.clip(); 462 context.closePath(); 463 } 464 465 //draw sprite 466 if (locSprite._texture && locTextureCoord.validRect) { 467 var image = locSprite._texture.getHtmlElementObj(); 468 if (this._colorized) { 469 context.drawImage(image, 470 0, 0, locTextureCoord.width, locTextureCoord.height, 471 flipXOffset, flipYOffset, locDrawSizeCanvas.width, locDrawSizeCanvas.height); 472 } else { 473 context.drawImage(image, 474 locTextureCoord.x, locTextureCoord.y, locTextureCoord.width, locTextureCoord.height, 475 flipXOffset, flipYOffset, locDrawSizeCanvas.width , locDrawSizeCanvas.height); 476 } 477 } else if (locContentSize.width !== 0) { 478 var curColor = this.color; 479 context.fillStyle = "rgba(" + curColor.r + "," + curColor.g + "," + curColor.b + ",1)"; 480 context.fillRect(flipXOffset, flipYOffset, locContentSize.width * locEGL_ScaleX, locContentSize.height * locEGL_ScaleY); 481 } 482 483 context.restore(); 484 cc.incrementGLDraws(1); 485 }, 486 487 _drawForWebGL:function (ctx) { 488 var context = ctx || cc._renderContext; 489 if (!this._vertexData || !this._sprite) 490 return; 491 492 cc.nodeDrawSetup(this); 493 494 var blendFunc = this._sprite.getBlendFunc(); 495 cc.glBlendFunc(blendFunc.src, blendFunc.dst); 496 cc.glEnableVertexAttribs(cc.VERTEX_ATTRIB_FLAG_POS_COLOR_TEX); 497 498 cc.glBindTexture2D(this._sprite.texture); 499 500 context.bindBuffer(context.ARRAY_BUFFER, this._vertexWebGLBuffer); 501 if(this._vertexDataDirty){ 502 context.bufferData(context.ARRAY_BUFFER, this._vertexArrayBuffer, context.DYNAMIC_DRAW); 503 this._vertexDataDirty = false; 504 } 505 var locVertexDataLen = cc.V2F_C4B_T2F.BYTES_PER_ELEMENT; 506 context.vertexAttribPointer(cc.VERTEX_ATTRIB_POSITION, 2, context.FLOAT, false, locVertexDataLen, 0); 507 context.vertexAttribPointer(cc.VERTEX_ATTRIB_COLOR, 4, context.UNSIGNED_BYTE, true, locVertexDataLen, 8); 508 context.vertexAttribPointer(cc.VERTEX_ATTRIB_TEX_COORDS, 2, context.FLOAT, false, locVertexDataLen, 12); 509 510 if (this._type === cc.ProgressTimer.TYPE_RADIAL) 511 context.drawArrays(context.TRIANGLE_FAN, 0, this._vertexDataCount); 512 else if (this._type == cc.ProgressTimer.TYPE_BAR) { 513 if (!this._reverseDirection) 514 context.drawArrays(context.TRIANGLE_STRIP, 0, this._vertexDataCount); 515 else { 516 context.drawArrays(context.TRIANGLE_STRIP, 0, this._vertexDataCount / 2); 517 context.drawArrays(context.TRIANGLE_STRIP, 4, this._vertexDataCount / 2); 518 // 2 draw calls 519 cc.g_NumberOfDraws++; 520 } 521 } 522 cc.g_NumberOfDraws++; 523 }, 524 525 /** 526 * <p> 527 * Update does the work of mapping the texture onto the triangles <br/> 528 * It now doesn't occur the cost of free/alloc data every update cycle. <br/> 529 * It also only changes the percentage point but no other points if they have not been modified. <br/> 530 * <br/> 531 * It now deals with flipped texture. If you run into this problem, just use the <br/> 532 * sprite property and enable the methods flipX, flipY. <br/> 533 * </p> 534 * @private 535 */ 536 _updateRadial:function () { 537 if (!this._sprite) 538 return; 539 540 var i, locMidPoint = this._midPoint; 541 var alpha = this._percentage / 100; 542 var angle = 2 * (cc.PI) * ( this._reverseDirection ? alpha : 1.0 - alpha); 543 544 // We find the vector to do a hit detection based on the percentage 545 // We know the first vector is the one @ 12 o'clock (top,mid) so we rotate 546 // from that by the progress angle around the m_tMidpoint pivot 547 var topMid = cc.p(locMidPoint.x, 1); 548 var percentagePt = cc.pRotateByAngle(topMid, locMidPoint, angle); 549 550 var index = 0; 551 var hit; 552 553 if (alpha == 0) { 554 // More efficient since we don't always need to check intersection 555 // If the alpha is zero then the hit point is top mid and the index is 0. 556 hit = topMid; 557 index = 0; 558 } else if (alpha == 1) { 559 // More efficient since we don't always need to check intersection 560 // If the alpha is one then the hit point is top mid and the index is 4. 561 hit = topMid; 562 index = 4; 563 } else { 564 // We run a for loop checking the edges of the texture to find the 565 // intersection point 566 // We loop through five points since the top is split in half 567 568 var min_t = cc.FLT_MAX; 569 var locProTextCoordsCount = cc.ProgressTimer.TEXTURE_COORDS_COUNT; 570 for (i = 0; i <= locProTextCoordsCount; ++i) { 571 var pIndex = (i + (locProTextCoordsCount - 1)) % locProTextCoordsCount; 572 573 var edgePtA = this._boundaryTexCoord(i % locProTextCoordsCount); 574 var edgePtB = this._boundaryTexCoord(pIndex); 575 576 // Remember that the top edge is split in half for the 12 o'clock position 577 // Let's deal with that here by finding the correct endpoints 578 if (i == 0) 579 edgePtB = cc.pLerp(edgePtA, edgePtB, 1 - locMidPoint.x); 580 else if (i == 4) 581 edgePtA = cc.pLerp(edgePtA, edgePtB, 1 - locMidPoint.x); 582 583 // retPoint are returned by ccpLineIntersect 584 var retPoint = cc.p(0, 0); 585 if (cc.pLineIntersect(edgePtA, edgePtB, locMidPoint, percentagePt, retPoint)) { 586 // Since our hit test is on rays we have to deal with the top edge 587 // being in split in half so we have to test as a segment 588 if ((i == 0 || i == 4)) { 589 // s represents the point between edgePtA--edgePtB 590 if (!(0 <= retPoint.x && retPoint.x <= 1)) 591 continue; 592 } 593 // As long as our t isn't negative we are at least finding a 594 // correct hitpoint from m_tMidpoint to percentagePt. 595 if (retPoint.y >= 0) { 596 // Because the percentage line and all the texture edges are 597 // rays we should only account for the shortest intersection 598 if (retPoint.y < min_t) { 599 min_t = retPoint.y; 600 index = i; 601 } 602 } 603 } 604 } 605 606 // Now that we have the minimum magnitude we can use that to find our intersection 607 hit = cc.pAdd(locMidPoint, cc.pMult(cc.pSub(percentagePt, locMidPoint), min_t)); 608 } 609 610 // The size of the vertex data is the index from the hitpoint 611 // the 3 is for the m_tMidpoint, 12 o'clock point and hitpoint position. 612 var sameIndexCount = true; 613 if (this._vertexDataCount != index + 3) { 614 sameIndexCount = false; 615 this._vertexData = null; 616 this._vertexArrayBuffer = null; 617 this._vertexDataCount = 0; 618 } 619 620 if (!this._vertexData) { 621 this._vertexDataCount = index + 3; 622 var locCount = this._vertexDataCount, vertexDataLen = cc.V2F_C4B_T2F.BYTES_PER_ELEMENT; 623 this._vertexArrayBuffer = new ArrayBuffer(locCount * vertexDataLen); 624 var locData = []; 625 for (i = 0; i < locCount; i++) 626 locData[i] = new cc.V2F_C4B_T2F(null, null, null, this._vertexArrayBuffer, i * vertexDataLen); 627 628 this._vertexData = locData; 629 if(!this._vertexData){ 630 cc.log( "cc.ProgressTimer._updateRadial() : Not enough memory"); 631 return; 632 } 633 } 634 this._updateColor(); 635 636 var locVertexData = this._vertexData; 637 if (!sameIndexCount) { 638 // First we populate the array with the m_tMidpoint, then all 639 // vertices/texcoords/colors of the 12 'o clock start and edges and the hitpoint 640 locVertexData[0].texCoords = this._textureCoordFromAlphaPoint(locMidPoint); 641 locVertexData[0].vertices = this._vertexFromAlphaPoint(locMidPoint); 642 643 locVertexData[1].texCoords = this._textureCoordFromAlphaPoint(topMid); 644 locVertexData[1].vertices = this._vertexFromAlphaPoint(topMid); 645 646 for (i = 0; i < index; i++) { 647 var alphaPoint = this._boundaryTexCoord(i); 648 locVertexData[i + 2].texCoords = this._textureCoordFromAlphaPoint(alphaPoint); 649 locVertexData[i + 2].vertices = this._vertexFromAlphaPoint(alphaPoint); 650 } 651 } 652 653 // hitpoint will go last 654 locVertexData[this._vertexDataCount - 1].texCoords = this._textureCoordFromAlphaPoint(hit); 655 locVertexData[this._vertexDataCount - 1].vertices = this._vertexFromAlphaPoint(hit); 656 }, 657 658 /** 659 * <p> 660 * Update does the work of mapping the texture onto the triangles for the bar <br/> 661 * It now doesn't occur the cost of free/alloc data every update cycle. <br/> 662 * It also only changes the percentage point but no other points if they have not been modified. <br/> 663 * <br/> 664 * It now deals with flipped texture. If you run into this problem, just use the <br/> 665 * sprite property and enable the methods flipX, flipY. <br/> 666 * </p> 667 * @private 668 */ 669 _updateBar:function () { 670 if (!this._sprite) 671 return; 672 673 var i; 674 var alpha = this._percentage / 100.0; 675 var locBarChangeRate = this._barChangeRate; 676 var alphaOffset = cc.pMult(cc.p((1.0 - locBarChangeRate.x) + alpha * locBarChangeRate.x, 677 (1.0 - locBarChangeRate.y) + alpha * locBarChangeRate.y), 0.5); 678 var min = cc.pSub(this._midPoint, alphaOffset); 679 var max = cc.pAdd(this._midPoint, alphaOffset); 680 681 if (min.x < 0) { 682 max.x += -min.x; 683 min.x = 0; 684 } 685 686 if (max.x > 1) { 687 min.x -= max.x - 1; 688 max.x = 1; 689 } 690 691 if (min.y < 0) { 692 max.y += -min.y; 693 min.y = 0; 694 } 695 696 if (max.y > 1) { 697 min.y -= max.y - 1; 698 max.y = 1; 699 } 700 701 var locVertexData; 702 if (!this._reverseDirection) { 703 if (!this._vertexData) { 704 this._vertexDataCount = 4; 705 var vertexDataLen = cc.V2F_C4B_T2F.BYTES_PER_ELEMENT, locCount = 4; 706 this._vertexArrayBuffer = new ArrayBuffer(locCount * vertexDataLen); 707 this._vertexData = []; 708 for (i = 0; i < locCount; i++) 709 this._vertexData[i] = new cc.V2F_C4B_T2F(null, null, null, this._vertexArrayBuffer, i * vertexDataLen); 710 } 711 712 locVertexData = this._vertexData; 713 // TOPLEFT 714 locVertexData[0].texCoords = this._textureCoordFromAlphaPoint(cc.p(min.x, max.y)); 715 locVertexData[0].vertices = this._vertexFromAlphaPoint(cc.p(min.x, max.y)); 716 717 // BOTLEFT 718 locVertexData[1].texCoords = this._textureCoordFromAlphaPoint(cc.p(min.x, min.y)); 719 locVertexData[1].vertices = this._vertexFromAlphaPoint(cc.p(min.x, min.y)); 720 721 // TOPRIGHT 722 locVertexData[2].texCoords = this._textureCoordFromAlphaPoint(cc.p(max.x, max.y)); 723 locVertexData[2].vertices = this._vertexFromAlphaPoint(cc.p(max.x, max.y)); 724 725 // BOTRIGHT 726 locVertexData[3].texCoords = this._textureCoordFromAlphaPoint(cc.p(max.x, min.y)); 727 locVertexData[3].vertices = this._vertexFromAlphaPoint(cc.p(max.x, min.y)); 728 } else { 729 if (!this._vertexData) { 730 this._vertexDataCount = 8; 731 var rVertexDataLen = cc.V2F_C4B_T2F.BYTES_PER_ELEMENT, rLocCount = 8; 732 this._vertexArrayBuffer = new ArrayBuffer(rLocCount * rVertexDataLen); 733 var rTempData = []; 734 for (i = 0; i < rLocCount; i++) 735 rTempData[i] = new cc.V2F_C4B_T2F(null, null, null, this._vertexArrayBuffer, i * rVertexDataLen); 736 // TOPLEFT 1 737 rTempData[0].texCoords = this._textureCoordFromAlphaPoint(cc.p(0, 1)); 738 rTempData[0].vertices = this._vertexFromAlphaPoint(cc.p(0, 1)); 739 740 // BOTLEFT 1 741 rTempData[1].texCoords = this._textureCoordFromAlphaPoint(cc.p(0, 0)); 742 rTempData[1].vertices = this._vertexFromAlphaPoint(cc.p(0, 0)); 743 744 // TOPRIGHT 2 745 rTempData[6].texCoords = this._textureCoordFromAlphaPoint(cc.p(1, 1)); 746 rTempData[6].vertices = this._vertexFromAlphaPoint(cc.p(1, 1)); 747 748 // BOTRIGHT 2 749 rTempData[7].texCoords = this._textureCoordFromAlphaPoint(cc.p(1, 0)); 750 rTempData[7].vertices = this._vertexFromAlphaPoint(cc.p(1, 0)); 751 752 this._vertexData = rTempData; 753 } 754 755 locVertexData = this._vertexData; 756 // TOPRIGHT 1 757 locVertexData[2].texCoords = this._textureCoordFromAlphaPoint(cc.p(min.x, max.y)); 758 locVertexData[2].vertices = this._vertexFromAlphaPoint(cc.p(min.x, max.y)); 759 760 // BOTRIGHT 1 761 locVertexData[3].texCoords = this._textureCoordFromAlphaPoint(cc.p(min.x, min.y)); 762 locVertexData[3].vertices = this._vertexFromAlphaPoint(cc.p(min.x, min.y)); 763 764 // TOPLEFT 2 765 locVertexData[4].texCoords = this._textureCoordFromAlphaPoint(cc.p(max.x, max.y)); 766 locVertexData[4].vertices = this._vertexFromAlphaPoint(cc.p(max.x, max.y)); 767 768 // BOTLEFT 2 769 locVertexData[5].texCoords = this._textureCoordFromAlphaPoint(cc.p(max.x, min.y)); 770 locVertexData[5].vertices = this._vertexFromAlphaPoint(cc.p(max.x, min.y)); 771 } 772 this._updateColor(); 773 }, 774 775 _updateColor:function () { 776 if (!this._sprite || !this._vertexData) 777 return; 778 779 var sc = this._sprite.quad.tl.colors; 780 var locVertexData = this._vertexData; 781 for (var i = 0, len = this._vertexDataCount; i < len; ++i) 782 locVertexData[i].colors = sc; 783 this._vertexDataDirty = true; 784 }, 785 786 _updateProgress:null, 787 788 _updateProgressForCanvas:function () { 789 var locSprite = this._sprite; 790 var sw = locSprite.width, sh = locSprite.height; 791 var locMidPoint = this._midPoint; 792 793 if (this._type == cc.ProgressTimer.TYPE_RADIAL) { 794 this._radius = Math.round(Math.sqrt(sw * sw + sh * sh)); 795 var locStartAngle, locEndAngle, locCounterClockWise = false, locOrigin = this._origin; 796 locOrigin.x = sw * locMidPoint.x; 797 locOrigin.y = -sh * locMidPoint.y; 798 799 if (this._reverseDirection) { 800 locEndAngle = 270; 801 locStartAngle = 270 - 3.6 * this._percentage; 802 } else { 803 locStartAngle = -90; 804 locEndAngle = -90 + 3.6 * this._percentage; 805 } 806 807 if (locSprite._flippedX) { 808 locOrigin.x -= sw * (this._midPoint.x * 2); 809 locStartAngle= -locStartAngle; 810 locEndAngle= -locEndAngle; 811 locStartAngle -= 180; 812 locEndAngle -= 180; 813 locCounterClockWise = !locCounterClockWise; 814 } 815 if (locSprite._flippedY) { 816 locOrigin.y+=sh*(this._midPoint.y*2); 817 locCounterClockWise = !locCounterClockWise; 818 locStartAngle= -locStartAngle; 819 locEndAngle= -locEndAngle; 820 } 821 822 this._startAngle = locStartAngle; 823 this._endAngle = locEndAngle; 824 this._counterClockWise = locCounterClockWise; 825 } else { 826 var locBarChangeRate = this._barChangeRate; 827 var percentageF = this._percentage / 100; 828 var locBarRect = this._barRect; 829 830 var drawedSize = cc.size((sw * (1 - locBarChangeRate.x)), (sh * (1 - locBarChangeRate.y))); 831 var drawingSize = cc.size((sw - drawedSize.width) * percentageF, (sh - drawedSize.height) * percentageF); 832 var currentDrawSize = cc.size(drawedSize.width + drawingSize.width, drawedSize.height + drawingSize.height); 833 834 var startPoint = cc.p(sw * locMidPoint.x, sh * locMidPoint.y); 835 836 var needToLeft = startPoint.x - currentDrawSize.width / 2; 837 if (locMidPoint.x > 0.5) { 838 if (currentDrawSize.width / 2 >= sw - startPoint.x) { 839 needToLeft = sw - currentDrawSize.width; 840 } 841 } 842 843 var needToTop = startPoint.y - currentDrawSize.height / 2; 844 if (locMidPoint.y > 0.5) { 845 if (currentDrawSize.height / 2 >= sh - startPoint.y) { 846 needToTop = sh - currentDrawSize.height; 847 } 848 } 849 850 //left pos 851 locBarRect.x = 0; 852 var flipXNeed = 1; 853 if (locSprite._flippedX) { 854 locBarRect.x -= currentDrawSize.width; 855 flipXNeed = -1; 856 } 857 858 if (needToLeft > 0) 859 locBarRect.x += needToLeft * flipXNeed; 860 861 //right pos 862 locBarRect.y = 0; 863 var flipYNeed = 1; 864 if (locSprite._flippedY) { 865 locBarRect.y += currentDrawSize.height; 866 flipYNeed = -1; 867 } 868 869 if (needToTop > 0) 870 locBarRect.y -= needToTop * flipYNeed; 871 872 //clip width and clip height 873 locBarRect.width = currentDrawSize.width; 874 locBarRect.height = -currentDrawSize.height; 875 } 876 }, 877 878 _updateProgressForWebGL:function () { 879 var locType = this._type; 880 if(locType === cc.ProgressTimer.TYPE_RADIAL) 881 this._updateRadial(); 882 else if(locType === cc.ProgressTimer.TYPE_BAR) 883 this._updateBar(); 884 this._vertexDataDirty = true; 885 } 886 }); 887 888 var _p = cc.ProgressTimer.prototype; 889 if(cc._renderType == cc._RENDER_TYPE_WEBGL){ 890 _p.ctor = _p._ctorForWebGL; 891 _p.setReverseProgress = _p._setReverseProgressForWebGL; 892 _p.setSprite = _p._setSpriteForWebGL; 893 _p.setType = _p._setTypeForWebGL; 894 _p.setReverseDirection = _p._setReverseDirectionForWebGL; 895 _p.initWithSprite = _p._initWithSpriteForWebGL; 896 _p.draw = _p._drawForWebGL; 897 _p._updateProgress = _p._updateProgressForWebGL; 898 } else { 899 _p.ctor = _p._ctorForCanvas; 900 _p.setReverseProgress = _p._setReverseProgressForCanvas; 901 _p.setSprite = _p._setSpriteForCanvas; 902 _p.setType = _p._setTypeForCanvas; 903 _p.setReverseDirection = _p._setReverseDirectionForCanvas; 904 _p.initWithSprite = _p._initWithSpriteForCanvas; 905 _p.draw = _p._drawForCanvas; 906 _p._updateProgress = cc.ProgressTimer.prototype._updateProgressForCanvas; 907 } 908 909 // Extended properties 910 /** @expose */ 911 _p.midPoint; 912 cc.defineGetterSetter(_p, "midPoint", _p.getMidpoint, _p.setMidpoint); 913 /** @expose */ 914 _p.barChangeRate; 915 cc.defineGetterSetter(_p, "barChangeRate", _p.getBarChangeRate, _p.setBarChangeRate); 916 /** @expose */ 917 _p.type; 918 cc.defineGetterSetter(_p, "type", _p.getType, _p.setType); 919 /** @expose */ 920 _p.percentage; 921 cc.defineGetterSetter(_p, "percentage", _p.getPercentage, _p.setPercentage); 922 /** @expose */ 923 _p.sprite; 924 cc.defineGetterSetter(_p, "sprite", _p.getSprite, _p.setSprite); 925 /** @expose */ 926 _p.reverseDir; 927 cc.defineGetterSetter(_p, "reverseDir", _p.isReverseDirection, _p.setReverseDirection); 928 929 930 /** 931 * create a progress timer object with image file name that renders the inner sprite according to the percentage 932 * @param {cc.Sprite} sprite 933 * @return {cc.ProgressTimer} 934 * @example 935 * // Example 936 * var progress = cc.ProgressTimer.create('progress.png') 937 */ 938 cc.ProgressTimer.create = function (sprite) { 939 var progressTimer = new cc.ProgressTimer(); 940 if (progressTimer.initWithSprite(sprite)) 941 return progressTimer; 942 return null; 943 }; 944 945 /** 946 * @constant 947 * @type Number 948 */ 949 cc.ProgressTimer.TEXTURE_COORDS_COUNT = 4; 950 951 /** 952 * @constant 953 * @type Number 954 */ 955 cc.ProgressTimer.TEXTURE_COORDS = 0x4b; 956 957 /** 958 * Radial Counter-Clockwise 959 * @type Number 960 * @constant 961 */ 962 cc.ProgressTimer.TYPE_RADIAL = 0; 963 964 /** 965 * Bar 966 * @type Number 967 * @constant 968 */ 969 cc.ProgressTimer.TYPE_BAR = 1; 970