CCProgressTimer.js 35 KB

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