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