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