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