CCProgressTimer.js 36 KB

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