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 /**
 54  * cc.Progresstimer is a subclass of cc.Node.<br/>
 55  * It renders the inner sprite according to the percentage.<br/>
 56  * The progress can be Radial, Horizontal or vertical.
 57  * @class
 58  * @extends cc.Node
 59  */
 60 cc.ProgressTimer = cc.Node.extend(/** @lends cc.ProgressTimer# */{
 61     RGBAProtocol:true,
 62     _type:null,
 63     _percentage:0.0,
 64     _sprite:null,
 65     _vertexDataCount:0,
 66     _vertexData:null,
 67 
 68     _midPoint:cc.PointZero(),
 69     _barChangeRate:cc.PointZero(),
 70     _reverseDirection:false,
 71 
 72     ctor:function () {
 73         this._type = cc.PROGRESS_TIMER_TYPE_RADIAL;
 74         this._percentage = 0.0;
 75         this._midPoint = cc.p(0, 0);
 76         this._barChangeRate = cc.p(0, 0);
 77         this._reverseDirection = false;
 78     },
 79 
 80     /**
 81      *    Midpoint is used to modify the progress start position.
 82      *    If you're using radials type then the midpoint changes the center point
 83      *    If you're using bar type the the midpoint changes the bar growth
 84      *        it expands from the center but clamps to the sprites edge so:
 85      *        you want a left to right then set the midpoint all the way to cc.p(0,y)
 86      *        you want a right to left then set the midpoint all the way to cc.p(1,y)
 87      *        you want a bottom to top then set the midpoint all the way to cc.p(x,0)
 88      *        you want a top to bottom then set the midpoint all the way to cc.p(x,1)
 89      *  @return {cc.Point}
 90      */
 91     getMidpoint:function () {
 92         return this._midPoint;
 93     },
 94 
 95     /**
 96      * Midpoint setter
 97      * @param {cc.Point} mpoint
 98      */
 99     setMidpoint:function (mpoint) {
100         this._midPoint = cc.pClamp(mpoint, cc.PointZero(), cc.p(1, 1));
101     },
102 
103     /**
104      *    This allows the bar type to move the component at a specific rate
105      *    Set the component to 0 to make sure it stays at 100%.
106      *    For example you want a left to right bar but not have the height stay 100%
107      *    Set the rate to be cc.p(0,1); and set the midpoint to = cc.p(0,.5f);
108      *  @return {cc.Point}
109      */
110     getBarChangeRate:function () {
111         return this._barChangeRate;
112     },
113 
114     /**
115      * @param {cc.Point} barChangeRate
116      */
117     setBarChangeRate:function (barChangeRate) {
118 
119         this._barChangeRate = cc.pClamp(barChangeRate, cc.PointZero(), cc.p(1, 1));
120     },
121 
122     /**
123      *  Change the percentage to change progress
124      * @return {cc.PROGRESS_TIMER_TYPE_RADIAL|cc.PROGRESS_TIMER_TYPE_BAR}
125      */
126     getType:function () {
127         return this._type;
128     },
129 
130     /**
131      * Percentages are from 0 to 100
132      * @return {Number}
133      */
134     getPercentage:function () {
135         return this._percentage;
136     },
137 
138     /**
139      * The image to show the progress percentage, retain
140      * @return {cc.Sprite}
141      */
142     getSprite:function () {
143         return this._sprite;
144     },
145 
146     /**
147      * Initializes a progress timer with the sprite as the shape the timer goes through
148      * @param {cc.Sprite} sprite
149      * @return {Boolean}
150      */
151     initWithSprite:function (sprite) {
152         this.setPercentage(0);
153         this._vertexData = null;
154         this._vertexDataCount = 0;
155         this.setAnchorPoint(cc.p(0.5, 0.5));
156 
157         this._type = cc.PROGRESS_TIMER_TYPE_RADIAL;
158         this._reverseDirection = false;
159         this.setMidpoint(cc.p(0.5, 0.5));
160         this.setBarChangeRate(cc.p(1, 1));
161         this.setSprite(sprite);
162 
163         //shader program
164         //this.setShaderProgram(cc.ShaderCache.getInstance().programForKey(kCCShader_PositionTextureColor));
165 
166         return true;
167     },
168 
169     /**
170      * from 0-100
171      * @param {Number} percentage
172      */
173     setPercentage:function (percentage) {
174         if (this._percentage != percentage) {
175             this._percentage = cc.clampf(percentage, 0, 100);
176             this._updateProgress();
177         }
178     },
179 
180     /**
181      * @param {cc.Sprite} sprite
182      */
183     setSprite:function (sprite) {
184         if (this._sprite != sprite) {
185             this._sprite = sprite;
186             this.setContentSize(this._sprite.getContentSize());
187 
188             //	Everytime we set a new sprite, we free the current vertex data
189             if (this._vertexData) {
190                 this._vertexData = null;
191                 this._vertexDataCount = 0;
192             }
193         }
194     },
195 
196     /**
197      * set Progress type of cc.ProgressTimer
198      * @param {cc.PROGRESS_TIMER_TYPE_RADIAL|cc.PROGRESS_TIMER_TYPE_BAR} type
199      */
200     setType:function (type) {
201         if (type != this._type) {
202             //	release all previous information
203             if (this._vertexData) {
204                 this._vertexData = null;
205                 this._vertexDataCount = 0;
206             }
207 
208             this._type = type;
209         }
210     },
211 
212     /**
213      * set color of sprite
214      * @param {cc.Color3B} color
215      */
216     setColor:function (color) {
217         this._sprite.setColor(color);
218         this._updateColor();
219     },
220 
221     /**
222      * return color of sprite
223      * @return {cc.Color3B}
224      */
225     getColor:function () {
226         return this._sprite.getColor();
227     },
228 
229     /**
230      * return Opacity of sprite
231      * @return {Number}
232      */
233     getOpacity:function () {
234         return this._sprite.getOpacity();
235     },
236 
237     /**
238      * Opacity
239      * @param {Number} opacity
240      */
241     setOpacity:function (opacity) {
242         this._sprite.setOpacity(opacity);
243         this._updateColor();
244     },
245 
246     setOpacityModifyRGB:function (bValue) {
247     },
248 
249     isOpacityModifyRGB:function () {
250         return false;
251     },
252 
253     isReverseDirection:function () {
254         return this._reverseDirection;
255     },
256 
257     /**
258      * Reverse Progress setter
259      * @param {Boolean} reverse
260      */
261     setReverseDirection:function (reverse) {
262         if (this._reverseDirection != reverse) {
263             this._reverseDirection = reverse;
264             //release all previous information
265             this._vertexData = null;
266             this._vertexDataCount = 0;
267         }
268     },
269 
270     /**
271      * stuff gets drawn here
272      * @param {CanvasContext} ctx
273      */
274     draw:function (ctx) {
275         if (cc.renderContextType == cc.CANVAS) {
276             var context = ctx || cc.renderContext;
277 
278             context.globalAlpha = this._sprite._opacity / 255;
279             var centerPoint, mpX = 0, mpY = 0;
280             if (this._sprite._flipX) {
281                 centerPoint = cc.p(this._sprite._contentSize.width / 2, this._sprite._contentSize.height / 2);
282                 mpX = 0 | (centerPoint.x - this._sprite._anchorPointInPoints.x);
283                 context.translate(mpX, 0);
284                 context.scale(-1, 1);
285             }
286 
287             if (this._sprite._flipY) {
288                 centerPoint = cc.p(this._sprite._contentSize.width / 2, this._sprite._contentSize.height / 2);
289                 mpY = -(0 | (centerPoint.y - this._sprite._anchorPointInPoints.y));
290                 context.translate(0, mpY);
291                 context.scale(1, -1);
292             }
293 
294             var pos;
295             if (this._type == cc.PROGRESS_TIMER_TYPE_BAR) {
296                 pos = cc.p(( -this._sprite._anchorPointInPoints.x + this._sprite._offsetPosition.x + this._drawPosition.x),
297                     ( -this._sprite._anchorPointInPoints.y + this._sprite._offsetPosition.y + this._drawPosition.y));
298 
299                 if (this._sprite._texture instanceof HTMLImageElement) {
300                     if ((this._originSize.width != 0) && (this._originSize.height != 0)) {
301                         context.drawImage(this._sprite._texture,
302                             this._sprite._rect.origin.x + this._origin.x, this._sprite._rect.origin.y + this._origin.y,
303                             this._originSize.width, this._originSize.height,
304                             pos.x, -(pos.y + this._drawSize.height),
305                             this._originSize.width, this._originSize.height);
306                     }
307                 } else if (this._sprite._texture instanceof  HTMLCanvasElement) {
308                     if ((this._originSize.width != 0) && (this._originSize.height != 0)) {
309                         context.drawImage(this._sprite._texture,
310                             this._origin.x, this._origin.y,
311                             this._originSize.width, this._originSize.height,
312                             pos.x, -(pos.y + this._drawSize.height),
313                             this._originSize.width, this._originSize.height);
314                     }
315                 }
316             } else {
317                 context.beginPath();
318                 context.arc(this._origin.x, this._origin.y, this._radius, (Math.PI / 180) * this._startAngle, (Math.PI / 180) * this._endAngle, false);
319                 context.lineTo(this._origin.x, this._origin.y);
320                 context.clip();
321                 context.closePath();
322 
323                 var offsetPixels = this._sprite._offsetPosition;
324                 pos = cc.p(0 | ( -this._sprite._anchorPointInPoints.x + offsetPixels.x),
325                     0 | ( -this._sprite._anchorPointInPoints.y + offsetPixels.y));
326 
327                 if (this._sprite._texture instanceof HTMLImageElement) {
328                     context.drawImage(this._sprite._texture,
329                         this._sprite._rect.origin.x, this._sprite._rect.origin.y,
330                         this._sprite._rect.size.width, this._sprite._rect.size.height,
331                         pos.x, -(pos.y + this._sprite._rect.size.height),
332                         this._sprite._rect.size.width, this._sprite._rect.size.height);
333                 } else if (this._sprite._texture instanceof  HTMLCanvasElement) {
334                     context.drawImage(this._sprite._texture,
335                         0, 0,
336                         this._sprite._rect.size.width, this._sprite._rect.size.height,
337                         pos.x, -(pos.y + this._sprite._rect.size.height),
338                         this._sprite._rect.size.width, this._sprite._rect.size.height);
339                 }
340             }
341         } else {
342             if (!this._vertexData || !this._sprite)
343                 return;
344         }
345         cc.INCREMENT_GL_DRAWS(1);
346     },
347 
348     /**
349      * @param {cc.Point} alpha
350      * @return {cc.Vertex2F} the vertex position from the texture coordinate
351      * @private
352      */
353     _textureCoordFromAlphaPoint:function (alpha) {
354         var ret = new cc.Tex2F(0, 0);
355         if (!this._sprite) {
356             return ret;
357         }
358         var quad = this._sprite.getQuad();
359         var min = cc.p(quad.bl.texCoords.u, quad.bl.texCoords.v);
360         var max = cc.p(quad.tr.texCoords.u, quad.tr.texCoords.v);
361 
362         //  Fix bug #1303 so that progress timer handles sprite frame texture rotation
363         if (this._sprite.isTextureRectRotated()) {
364             var tempX = alpha.x;
365             alpha.x = alpha.y;
366             alpha.y = tempX;
367         }
368         return new cc.Tex2F(min.x * (1 - alpha.x) + max.x * alpha.x, min.y * (1 - alpha.y) + max.y * alpha.y);
369     },
370 
371     _vertexFromAlphaPoint:function (alpha) {
372         var ret = new cc.Tex2F(0, 0);
373         if (!this._sprite) {
374             return ret;
375         }
376         var quad = this._sprite.getQuad();
377         var min = cc.p(quad.bl.vertices.x, quad.bl.vertices.y);
378         var max = cc.p(quad.tr.vertices.x, quad.tr.vertices.y);
379         ret.x = min.x * (1 - alpha.x) + max.x * alpha.x;
380         ret.y = min.y * (1 - alpha.y) + max.y * alpha.y;
381         return ret;
382     },
383 
384     _origin:cc.PointZero(),
385     _originSize:cc.SizeZero(),
386     _drawSize:cc.SizeZero(),
387     _drawPosition:cc.PointZero(),
388     _startAngle:270,
389     _endAngle:270,
390     _radius:0,
391     _updateProgress:function () {
392         if (cc.renderContextType == cc.CANVAS) {
393             var size = this._sprite.getContentSize();
394             var textureSize = this._sprite.getTextureRect().size;
395             if (this._type == cc.PROGRESS_TIMER_TYPE_RADIAL) {
396 
397                 this._origin = cc.p(-(size.width * (0.5 - this._midPoint.x)), -(size.height * (0.5 - this._midPoint.y)));
398                 this._radius = Math.round(Math.sqrt(size.width * size.width + size.height * size.height));
399                 if (this._reverseDirection) {
400                     this._startAngle = 270 - 3.6 * this._percentage;
401                 } else {
402                     this._endAngle = 270 + 3.6 * this._percentage;
403                 }
404             } else {
405                 this._origin = cc.p(0, 0);
406                 this._drawPosition = cc.p(0, 0);
407 
408                 var percentageF = this._percentage / 100;
409                 var startPoint = cc.p(size.width * this._midPoint.x, size.height * this._midPoint.y);
410                 var startPointTx = cc.p(textureSize.width * this._midPoint.x, textureSize.height * this._midPoint.y);
411 
412                 var drawedSize = cc.size((size.width * (1 - this._barChangeRate.x)), (size.height * (1 - this._barChangeRate.y)));
413                 var drawingSize = cc.size((size.width - drawedSize.width) * percentageF, (size.height - drawedSize.height) * percentageF);
414                 this._drawSize = cc.size(drawedSize.width + drawingSize.width, drawedSize.height + drawingSize.height);
415 
416                 var txDrawedSize = cc.size((textureSize.width * (1 - this._barChangeRate.x)), (textureSize.height * (1 - this._barChangeRate.y)));
417                 var txDrawingSize = cc.size((textureSize.width - txDrawedSize.width) * percentageF, (textureSize.height - txDrawedSize.height) * percentageF);
418                 this._originSize = cc.size(txDrawedSize.width + txDrawingSize.width, txDrawedSize.height + txDrawingSize.height);
419 
420                 var needToLeft = startPoint.x * percentageF;
421                 var needToLeftTx = startPointTx.x * percentageF;
422 
423                 if (size.width == this._drawSize.width) {
424                     this._origin.x = 0;
425                     this._drawPosition.x = 0;
426                 } else {
427                     this._origin.x = (startPointTx.x - needToLeftTx);
428                     this._drawPosition.x = (startPoint.x - needToLeft);
429                 }
430 
431                 var needToTop = (textureSize.height - startPointTx.y) * percentageF;
432 
433                 if (size.height == this._drawSize.height) {
434                     this._origin.y = 0;
435                     this._drawPosition.y = 0;
436                 } else {
437                     this._origin.y = (textureSize.height - startPointTx.y - needToTop);
438                     this._drawPosition.y = (startPoint.y - (startPoint.y * percentageF));
439                 }
440             }
441         } else {
442             switch (this._type) {
443                 case cc.PROGRESS_TIMER_TYPE_RADIAL:
444                     this._updateRadial();
445                     break;
446                 case cc.PROGRESS_TIMER_TYPE_BAR:
447                     this._updateBar();
448                     break;
449                 default:
450                     break;
451             }
452         }
453     },
454 
455     _updateBar:function () {
456         if (!this._sprite) {
457             return;
458         }
459 
460         var alpha = this._percentage / 100.0;
461         var alphaOffset = cc.pMult(cc.p((1.0 - this._barChangeRate.x) + alpha * this._barChangeRate.x,
462             (1.0 - this._barChangeRate.y) + alpha * this._barChangeRate.y), 0.5);
463         var min = cc.pSub(this._midPoint, alphaOffset);
464         var max = cc.pAdd(this._midPoint, alphaOffset);
465 
466         if (min.x < 0) {
467             max.x += -min.x;
468             min.x = 0;
469         }
470 
471         if (max.x > 1) {
472             min.x -= max.x - 1;
473             max.x = 1;
474         }
475 
476         if (min.y < 0) {
477             max.y += -min.y;
478             min.y = 0;
479         }
480 
481         if (max.y > 1) {
482             min.y -= max.y - 1;
483             max.y = 1;
484         }
485 
486         if (!this._reverseDirection) {
487             if (!this._vertexData) {
488                 this._vertexDataCount = 4;
489                 this._vertexData = [];
490                 for (i = 0; i < this._vertexDataCount; i++) {
491                     this._vertexData[i] = new cc.V2F_C4B_T2F();
492                 }
493                 cc.Assert(this._vertexData, "cc.ProgressTimer. Not enough memory");
494             }
495 
496             //    TOPLEFT
497             this._vertexData[0].texCoords = this._textureCoordFromAlphaPoint(cc.p(min.x, max.y));
498             this._vertexData[0].vertices = this._vertexFromAlphaPoint(cc.p(min.x, max.y));
499 
500             //    BOTLEFT
501             this._vertexData[1].texCoords = this._textureCoordFromAlphaPoint(cc.p(min.x, min.y));
502             this._vertexData[1].vertices = this._vertexFromAlphaPoint(cc.p(min.x, min.y));
503 
504             //    TOPRIGHT
505             this._vertexData[2].texCoords = this._textureCoordFromAlphaPoint(cc.p(max.x, max.y));
506             this._vertexData[2].vertices = this._vertexFromAlphaPoint(cc.p(max.x, max.y));
507 
508             //    BOTRIGHT
509             this._vertexData[3].texCoords = this._textureCoordFromAlphaPoint(cc.p(max.x, min.y));
510             this._vertexData[3].vertices = this._vertexFromAlphaPoint(cc.p(max.x, min.y));
511         } else {
512             if (!this._vertexData) {
513                 this._vertexData = 8;
514                 this._vertexData = [];
515                 for (i = 0; i < this._vertexDataCount; i++) {
516                     this._vertexData[i] = new cc.V2F_C4B_T2F();
517                 }
518                 cc.Assert(this._vertexData, "cc.ProgressTimer. Not enough memory");
519                 //    TOPLEFT 1
520                 this._vertexData[0].texCoords = this._textureCoordFromAlphaPoint(cc.p(0, 1));
521                 this._vertexData[0].vertices = this._vertexFromAlphaPoint(cc.p(0, 1));
522 
523                 //    BOTLEFT 1
524                 this._vertexData[1].texCoords = this._textureCoordFromAlphaPoint(cc.p(0, 0));
525                 this._vertexData[1].vertices = this._vertexFromAlphaPoint(cc.p(0, 0));
526 
527                 //    TOPRIGHT 2
528                 this._vertexData[6].texCoords = this._textureCoordFromAlphaPoint(cc.p(1, 1));
529                 this._vertexData[6].vertices = this._vertexFromAlphaPoint(cc.p(1, 1));
530 
531                 //    BOTRIGHT 2
532                 this._vertexData[7].texCoords = this._textureCoordFromAlphaPoint(cc.p(1, 0));
533                 this._vertexData[7].vertices = this._vertexFromAlphaPoint(cc.p(1, 0));
534             }
535 
536             //    TOPRIGHT 1
537             this._vertexData[2].texCoords = this._textureCoordFromAlphaPoint(cc.p(min.x, max.y));
538             this._vertexData[2].vertices = this._vertexFromAlphaPoint(cc.p(min.x, max.y));
539 
540             //    BOTRIGHT 1
541             this._vertexData[3].texCoords = this._textureCoordFromAlphaPoint(cc.p(min.x, min.y));
542             this._vertexData[3].vertices = this._vertexFromAlphaPoint(cc.p(min.x, min.y));
543 
544             //    TOPLEFT 2
545             this._vertexData[4].texCoords = this._textureCoordFromAlphaPoint(cc.p(max.x, max.y));
546             this._vertexData[4].vertices = this._vertexFromAlphaPoint(cc.p(max.x, max.y));
547 
548             //    BOTLEFT 2
549             this._vertexData[5].texCoords = this._textureCoordFromAlphaPoint(cc.p(max.x, min.y));
550             this._vertexData[5].vertices = this._vertexFromAlphaPoint(cc.p(max.x, min.y));
551         }
552         this._updateColor();
553     },
554 
555     _updateRadial:function () {
556         if (!this._sprite) {
557             return;
558         }
559         var i;
560         var alpha = this._percentage / 100;
561         var angle = 2 * (cc.PI) * ( this._reverseDirection ? alpha : 1.0 - alpha);
562 
563         //    We find the vector to do a hit detection based on the percentage
564         //    We know the first vector is the one @ 12 o'clock (top,mid) so we rotate
565         //    from that by the progress angle around the m_tMidpoint pivot
566         var topMid = cc.p(this._midPoint.x, 1);
567         var percentagePt = cc.pRotateByAngle(topMid, this._midPoint, angle);
568 
569         var index = 0;
570         var hit = cc.PointZero;
571 
572         if (alpha == 0) {
573             //    More efficient since we don't always need to check intersection
574             //    If the alpha is zero then the hit point is top mid and the index is 0.
575             hit = topMid;
576             index = 0;
577         } else if (alpha == 1) {
578             //    More efficient since we don't always need to check intersection
579             //    If the alpha is one then the hit point is top mid and the index is 4.
580             hit = topMid;
581             index = 4;
582         } else {
583             //    We run a for loop checking the edges of the texture to find the
584             //    intersection point
585             //    We loop through five points since the top is split in half
586 
587             var min_t = cc.FLT_MAX;
588 
589             for (i = 0; i <= cc.PROGRESS_TEXTURE_COORDS_COUNT; ++i) {
590                 var pIndex = (i + (cc.PROGRESS_TEXTURE_COORDS_COUNT - 1)) % cc.PROGRESS_TEXTURE_COORDS_COUNT;
591 
592                 var edgePtA = this._boundaryTexCoord(i % cc.PROGRESS_TEXTURE_COORDS_COUNT);
593                 var edgePtB = this._boundaryTexCoord(pIndex);
594 
595                 //    Remember that the top edge is split in half for the 12 o'clock position
596                 //    Let's deal with that here by finding the correct endpoints
597                 if (i == 0) {
598                     edgePtB = cc.pLerp(edgePtA, edgePtB, 1 - this._midPoint.x);
599                 } else if (i == 4) {
600                     edgePtA = cc.pLerp(edgePtA, edgePtB, 1 - this._midPoint.x);
601                 }
602 
603                 // s and t are returned by ccpLineIntersect
604                 var s = 0, t = 0;
605                 var retPoint = cc.p(0, 0);
606                 if (cc.pLineIntersect(edgePtA, edgePtB, this._midPoint, 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.width && retPoint.width <= 1)) {
612                             continue;
613                         }
614                     }
615                     //    As long as our t isn't negative we are at least finding a
616                     //    correct hitpoint from m_tMidpoint to percentagePt.
617                     if (retPoint.height >= 0) {
618                         //    Because the percentage line and all the texture edges are
619                         //    rays we should only account for the shortest intersection
620                         if (t < min_t) {
621                             min_t = t;
622                             index = i;
623                         }
624                     }
625                 }
626             }
627 
628             //    Now that we have the minimum magnitude we can use that to find our intersection
629             hit = cc.pAdd(this._midPoint, cc.pMult(cc.pSub(percentagePt, this._midPoint), min_t));
630         }
631 
632         //    The size of the vertex data is the index from the hitpoint
633         //    the 3 is for the m_tMidpoint, 12 o'clock point and hitpoint position.
634         var sameIndexCount = true;
635         if (this._vertexDataCount != index + 3) {
636             sameIndexCount = false;
637             this._vertexData = null;
638             this._vertexDataCount = 0;
639         }
640 
641         if (!this._vertexData) {
642             this._vertexDataCount = index + 3;
643             this._vertexData = [];
644             for (i = 0; i < this._vertexDataCount; i++) {
645                 this._vertexData[i] = new cc.V2F_C4B_T2F();
646             }
647             cc.Assert(this._vertexData, "cc.ProgressTimer. Not enough memory");
648         }
649         this._updateColor();
650 
651         if (!sameIndexCount) {
652             //    First we populate the array with the m_tMidpoint, then all
653             //    vertices/texcoords/colors of the 12 'o clock start and edges and the hitpoint
654             this._vertexData[0].texCoords = this._textureCoordFromAlphaPoint(this._midPoint);
655             this._vertexData[0].vertices = this._vertexFromAlphaPoint(this._midPoint);
656 
657             this._vertexData[1].texCoords = this._textureCoordFromAlphaPoint(topMid);
658             this._vertexData[1].vertices = this._vertexFromAlphaPoint(topMid);
659 
660             for (i = 0; i < index; ++i) {
661                 var alphaPoint = this._boundaryTexCoord(i);
662                 this._vertexData[i + 2].texCoords = this._textureCoordFromAlphaPoint(alphaPoint);
663                 this._vertexData[i + 2].vertices = this._vertexFromAlphaPoint(alphaPoint);
664             }
665         }
666 
667         //    hitpoint will go last
668         this._vertexData[this._vertexDataCount - 1].texCoords = this._textureCoordFromAlphaPoint(hit);
669         this._vertexData[this._vertexDataCount - 1].vertices = this._vertexFromAlphaPoint(hit);
670     },
671 
672     _updateColor:function () {
673         if (!this._sprite) {
674             return;
675         }
676 
677         if (this._vertexData) {
678             var sc = this._sprite.getQuad().tl.colors;
679             for (var i = 0; i < this._vertexDataCount; ++i) {
680                 this._vertexData[i].colors = sc;
681             }
682         }
683     },
684 
685     _boundaryTexCoord:function (index) {
686         if (index < cc.PROGRESS_TEXTURE_COORDS_COUNT) {
687             if (this._reverseDirection) {
688                 return cc.p((cc.PROGRESS_TEXTURE_COORDS >> (7 - (index << 1))) & 1, (cc.PROGRESS_TEXTURE_COORDS >> (7 - ((index << 1) + 1))) & 1);
689             } else {
690                 return cc.p((cc.PROGRESS_TEXTURE_COORDS >> ((index << 1) + 1)) & 1, (cc.PROGRESS_TEXTURE_COORDS >> (index << 1)) & 1);
691             }
692         }
693         return cc.PointZero();
694     }
695 });
696 
697 /**
698  * create a progress timer object with image file name that renders the inner sprite according to the percentage
699  * @param {cc.Sprite} sprite
700  * @return {cc.ProgressTimer}
701  * @example
702  * // Example
703  * var progress = cc.ProgressTimer.create('progress.png')
704  */
705 cc.ProgressTimer.create = function (sprite) {
706     var progressTimer = new cc.ProgressTimer();
707     if (progressTimer.initWithSprite(sprite)) {
708         return progressTimer;
709     } else {
710         return null;
711     }
712 };
713 
714