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