CCParticleSystem.js 94 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742
  1. /****************************************************************************
  2. Copyright (c) 2010-2012 cocos2d-x.org
  3. Copyright (c) 2008-2010 Ricardo Quesada
  4. Copyright (c) 2011 Zynga Inc.
  5. http://www.cocos2d-x.org
  6. Permission is hereby granted, free of charge, to any person obtaining a copy
  7. of this software and associated documentation files (the "Software"), to deal
  8. in the Software without restriction, including without limitation the rights
  9. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10. copies of the Software, and to permit persons to whom the Software is
  11. furnished to do so, subject to the following conditions:
  12. The above copyright notice and this permission notice shall be included in
  13. all copies or substantial portions of the Software.
  14. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. THE SOFTWARE.
  21. ****************************************************************************/
  22. // ideas taken from:
  23. // . The ocean spray in your face [Jeff Lander]
  24. // http://www.double.co.nz/dust/col0798.pdf
  25. // . Building an Advanced Particle System [John van der Burg]
  26. // http://www.gamasutra.com/features/20000623/vanderburg_01.htm
  27. // . LOVE game engine
  28. // http://love2d.org/
  29. //
  30. //
  31. // Radius mode support, from 71 squared
  32. // http://particledesigner.71squared.com/
  33. //
  34. // IMPORTANT: Particle Designer is supported by cocos2d, but
  35. // 'Radius Mode' in Particle Designer uses a fixed emit rate of 30 hz. Since that can't be guarateed in cocos2d,
  36. // cocos2d uses a another approach, but the results are almost identical.
  37. //
  38. /**
  39. * Shape Mode of Particle Draw
  40. * @constant
  41. * @type Number
  42. */
  43. cc.PARTICLE_SHAPE_MODE = 0;
  44. /**
  45. * Texture Mode of Particle Draw
  46. * @constant
  47. * @type Number
  48. */
  49. cc.PARTICLE_TEXTURE_MODE = 1;
  50. /**
  51. * Star Shape for ShapeMode of Particle
  52. * @constant
  53. * @type Number
  54. */
  55. cc.PARTICLE_STAR_SHAPE = 0;
  56. /**
  57. * Ball Shape for ShapeMode of Particle
  58. * @constant
  59. * @type Number
  60. */
  61. cc.PARTICLE_BALL_SHAPE = 1;
  62. /**
  63. * The Particle emitter lives forever
  64. * @constant
  65. * @type Number
  66. */
  67. cc.PARTICLE_DURATION_INFINITY = -1;
  68. /**
  69. * The starting size of the particle is equal to the ending size
  70. * @constant
  71. * @type Number
  72. */
  73. cc.PARTICLE_START_SIZE_EQUAL_TO_END_SIZE = -1;
  74. /**
  75. * The starting radius of the particle is equal to the ending radius
  76. * @constant
  77. * @type Number
  78. */
  79. cc.PARTICLE_START_RADIUS_EQUAL_TO_END_RADIUS = -1;
  80. /**
  81. * Gravity mode (A mode)
  82. * @constant
  83. * @type Number
  84. */
  85. cc.PARTICLE_MODE_GRAVITY = 0;
  86. /**
  87. * Radius mode (B mode)
  88. * @constant
  89. * @type Number
  90. */
  91. cc.PARTICLE_MODE_RADIUS = 1;
  92. // tCCPositionType
  93. // possible types of particle positions
  94. /**
  95. * Living particles are attached to the world and are unaffected by emitter repositioning.
  96. * @constant
  97. * @type Number
  98. */
  99. cc.PARTICLE_TYPE_FREE = 0;
  100. /**
  101. * Living particles are attached to the world but will follow the emitter repositioning.<br/>
  102. * Use case: Attach an emitter to an sprite, and you want that the emitter follows the sprite.
  103. * @constant
  104. * @type Number
  105. */
  106. cc.PARTICLE_TYPE_RELATIVE = 1;
  107. /**
  108. * Living particles are attached to the emitter and are translated along with it.
  109. * @constant
  110. * @type Number
  111. */
  112. cc.PARTICLE_TYPE_GROUPED = 2;
  113. /**
  114. * Structure that contains the values of each particle
  115. * @Class
  116. * @Construct
  117. * @param {cc.Point} [pos=cc.PointZero()] Position of particle
  118. * @param {cc.Point} [startPos=cc.PointZero()]
  119. * @param {cc.Color4F} [color= cc.Color4F(0, 0, 0, 1)]
  120. * @param {cc.Color4F} [deltaColor=cc.Color4F(0, 0, 0, 1)]
  121. * @param {cc.Size} [size=0]
  122. * @param {cc.Size} [deltaSize=0]
  123. * @param {Number} [rotation=0]
  124. * @param {Number} [deltaRotation=0]
  125. * @param {Number} [timeToLive=0]
  126. * @param {Number} [atlasIndex=0]
  127. * @param {cc.Particle.ModeA} [modeA=]
  128. * @param {cc.Particle.ModeA} [modeB=]
  129. */
  130. cc.Particle = function (pos, startPos, color, deltaColor, size, deltaSize, rotation, deltaRotation, timeToLive, atlasIndex, modeA, modeB) {
  131. this.pos = pos ? pos : cc.PointZero();
  132. this.startPos = startPos ? startPos : cc.PointZero();
  133. this.color = color ? color : new cc.Color4F(0, 0, 0, 1);
  134. this.deltaColor = deltaColor ? deltaColor : new cc.Color4F(0, 0, 0, 1);
  135. this.size = size || 0;
  136. this.deltaSize = deltaSize || 0;
  137. this.rotation = rotation || 0;
  138. this.deltaRotation = deltaRotation || 0;
  139. this.timeToLive = timeToLive || 0;
  140. this.atlasIndex = atlasIndex || 0;
  141. this.modeA = modeA ? modeA : new cc.Particle.ModeA();
  142. this.modeB = modeB ? modeB : new cc.Particle.ModeB();
  143. this.isChangeColor = false;
  144. this.drawPos = cc.p(0, 0);
  145. };
  146. /**
  147. * Mode A: gravity, direction, radial accel, tangential accel
  148. * @Class
  149. * @Construct
  150. * @param {cc.Point} dir direction of particle
  151. * @param {Number} radialAccel
  152. * @param {Number} tangentialAccel
  153. */
  154. cc.Particle.ModeA = function (dir, radialAccel, tangentialAccel) {
  155. this.dir = dir ? dir : cc.PointZero();
  156. this.radialAccel = radialAccel || 0;
  157. this.tangentialAccel = tangentialAccel || 0;
  158. };
  159. /**
  160. * Mode B: radius mode
  161. * @Class
  162. * @Construct
  163. * @param {Number} angle
  164. * @param {Number} degreesPerSecond
  165. * @param {Number} radius
  166. * @param {Number} deltaRadius
  167. */
  168. cc.Particle.ModeB = function (angle, degreesPerSecond, radius, deltaRadius) {
  169. this.angle = angle || 0;
  170. this.degreesPerSecond = degreesPerSecond || 0;
  171. this.radius = radius || 0;
  172. this.deltaRadius = deltaRadius || 0;
  173. };
  174. /**
  175. * Array of Point instances used to optimize particle updates
  176. */
  177. cc.Particle.TemporaryPoints = [
  178. cc.p(),
  179. cc.p(),
  180. cc.p(),
  181. cc.p()
  182. ];
  183. /**
  184. * <p>
  185. * Particle System base class. <br/>
  186. * Attributes of a Particle System:<br/>
  187. * - emmision rate of the particles<br/>
  188. * - Gravity Mode (Mode A): <br/>
  189. * - gravity <br/>
  190. * - direction <br/>
  191. * - speed +- variance <br/>
  192. * - tangential acceleration +- variance<br/>
  193. * - radial acceleration +- variance<br/>
  194. * - Radius Mode (Mode B): <br/>
  195. * - startRadius +- variance <br/>
  196. * - endRadius +- variance <br/>
  197. * - rotate +- variance <br/>
  198. * - Properties common to all modes: <br/>
  199. * - life +- life variance <br/>
  200. * - start spin +- variance <br/>
  201. * - end spin +- variance <br/>
  202. * - start size +- variance <br/>
  203. * - end size +- variance <br/>
  204. * - start color +- variance <br/>
  205. * - end color +- variance <br/>
  206. * - life +- variance <br/>
  207. * - blending function <br/>
  208. * - texture <br/>
  209. * <br/>
  210. * cocos2d also supports particles generated by Particle Designer (http://particledesigner.71squared.com/).<br/>
  211. * 'Radius Mode' in Particle Designer uses a fixed emit rate of 30 hz. Since that can't be guarateed in cocos2d, <br/>
  212. * cocos2d uses a another approach, but the results are almost identical.<br/>
  213. * cocos2d supports all the variables used by Particle Designer plus a bit more: <br/>
  214. * - spinning particles (supported when using ParticleSystem) <br/>
  215. * - tangential acceleration (Gravity mode) <br/>
  216. * - radial acceleration (Gravity mode) <br/>
  217. * - radius direction (Radius mode) (Particle Designer supports outwards to inwards direction only) <br/>
  218. * It is possible to customize any of the above mentioned properties in runtime. Example: <br/>
  219. * </p>
  220. * @class
  221. * @extends cc.Node
  222. *
  223. * @example
  224. * emitter.radialAccel = 15;
  225. * emitter.startSpin = 0;
  226. */
  227. cc.ParticleSystem = cc.Node.extend(/** @lends cc.ParticleSystem# */{
  228. //***********variables*************
  229. _plistFile: "",
  230. //! time elapsed since the start of the system (in seconds)
  231. _elapsed: 0,
  232. _dontTint: false,
  233. // Different modes
  234. //! Mode A:Gravity + Tangential Accel + Radial Accel
  235. modeA: null,
  236. //! Mode B: circular movement (gravity, radial accel and tangential accel don't are not used in this mode)
  237. modeB: null,
  238. //private POINTZERO for ParticleSystem
  239. _pointZeroForParticle: cc.p(0, 0),
  240. //! Array of particles
  241. _particles: null,
  242. // color modulate
  243. // BOOL colorModulate;
  244. //! How many particles can be emitted per second
  245. _emitCounter: 0,
  246. //! particle idx
  247. _particleIdx: 0,
  248. _batchNode: null,
  249. _atlasIndex: 0,
  250. //true if scaled or rotated
  251. _transformSystemDirty: false,
  252. _allocatedParticles: 0,
  253. //drawMode
  254. _drawMode: cc.PARTICLE_SHAPE_MODE,
  255. //shape type
  256. _shapeType: cc.PARTICLE_BALL_SHAPE,
  257. _isActive: false,
  258. _particleCount: 0,
  259. _duration: 0,
  260. _sourcePosition: null,
  261. _posVar: null,
  262. _life: 0,
  263. _lifeVar: 0,
  264. _angle: 0,
  265. _angleVar: 0,
  266. _startSize: 0,
  267. _startSizeVar: 0,
  268. _endSize: 0,
  269. _endSizeVar: 0,
  270. _startColor: null,
  271. _startColorVar: null,
  272. _endColor: null,
  273. _endColorVar: null,
  274. _startSpin: 0,
  275. _startSpinVar: 0,
  276. _endSpin: 0,
  277. _endSpinVar: 0,
  278. _emissionRate: 0,
  279. _totalParticles: 0,
  280. _texture: null,
  281. _blendFunc: null,
  282. _opacityModifyRGB: false,
  283. _positionType: cc.PARTICLE_TYPE_FREE,
  284. _isAutoRemoveOnFinish: false,
  285. _emitterMode: 0,
  286. // quads to be rendered
  287. _quads:null,
  288. // indices
  289. _indices:null,
  290. //_VAOname:0,
  291. //0: vertex 1: indices
  292. _buffersVBO:null,
  293. _pointRect:null,
  294. _textureLoaded: null,
  295. _quadsArrayBuffer:null,
  296. /**
  297. * Constructor
  298. * @override
  299. */
  300. ctor:function () {
  301. cc.Node.prototype.ctor.call(this);
  302. this._emitterMode = cc.PARTICLE_MODE_GRAVITY;
  303. this.modeA = new cc.ParticleSystem.ModeA();
  304. this.modeB = new cc.ParticleSystem.ModeB();
  305. this._blendFunc = {src:cc.BLEND_SRC, dst:cc.BLEND_DST};
  306. this._particles = [];
  307. this._sourcePosition = new cc.Point(0, 0);
  308. this._posVar = new cc.Point(0, 0);
  309. this._startColor = new cc.Color4F(1, 1, 1, 1);
  310. this._startColorVar = new cc.Color4F(1, 1, 1, 1);
  311. this._endColor = new cc.Color4F(1, 1, 1, 1);
  312. this._endColorVar = new cc.Color4F(1, 1, 1, 1);
  313. this._plistFile = "";
  314. this._elapsed = 0;
  315. this._dontTint = false;
  316. this._pointZeroForParticle = cc.p(0, 0);
  317. this._emitCounter = 0;
  318. this._particleIdx = 0;
  319. this._batchNode = null;
  320. this._atlasIndex = 0;
  321. this._transformSystemDirty = false;
  322. this._allocatedParticles = 0;
  323. this._drawMode = cc.PARTICLE_SHAPE_MODE;
  324. this._shapeType = cc.PARTICLE_BALL_SHAPE;
  325. this._isActive = false;
  326. this._particleCount = 0;
  327. this._duration = 0;
  328. this._life = 0;
  329. this._lifeVar = 0;
  330. this._angle = 0;
  331. this._angleVar = 0;
  332. this._startSize = 0;
  333. this._startSizeVar = 0;
  334. this._endSize = 0;
  335. this._endSizeVar = 0;
  336. this._startSpin = 0;
  337. this._startSpinVar = 0;
  338. this._endSpin = 0;
  339. this._endSpinVar = 0;
  340. this._emissionRate = 0;
  341. this._totalParticles = 0;
  342. this._texture = null;
  343. this._opacityModifyRGB = false;
  344. this._positionType = cc.PARTICLE_TYPE_FREE;
  345. this._isAutoRemoveOnFinish = false;
  346. this._buffersVBO = [0, 0];
  347. this._quads = [];
  348. this._indices = [];
  349. this._pointRect = cc.RectZero();
  350. this._textureLoaded = true;
  351. if (cc.renderContextType === cc.WEBGL) {
  352. this._quadsArrayBuffer = null;
  353. }
  354. },
  355. /**
  356. * initializes the indices for the vertices
  357. */
  358. initIndices:function () {
  359. var locIndices = this._indices;
  360. for (var i = 0, len = this._totalParticles; i < len; ++i) {
  361. var i6 = i * 6;
  362. var i4 = i * 4;
  363. locIndices[i6 + 0] = i4 + 0;
  364. locIndices[i6 + 1] = i4 + 1;
  365. locIndices[i6 + 2] = i4 + 2;
  366. locIndices[i6 + 5] = i4 + 1;
  367. locIndices[i6 + 4] = i4 + 2;
  368. locIndices[i6 + 3] = i4 + 3;
  369. }
  370. },
  371. /**
  372. * <p> initializes the texture with a rectangle measured Points<br/>
  373. * pointRect should be in Texture coordinates, not pixel coordinates
  374. * </p>
  375. * @param {cc.Rect} pointRect
  376. */
  377. initTexCoordsWithRect:function (pointRect) {
  378. var scaleFactor = cc.CONTENT_SCALE_FACTOR();
  379. // convert to pixels coords
  380. var rect = cc.rect(
  381. pointRect.x * scaleFactor,
  382. pointRect.y * scaleFactor,
  383. pointRect.width * scaleFactor,
  384. pointRect.height * scaleFactor);
  385. var wide = pointRect.width;
  386. var high = pointRect.height;
  387. if (this._texture) {
  388. wide = this._texture.getPixelsWide();
  389. high = this._texture.getPixelsHigh();
  390. }
  391. if(cc.renderContextType === cc.CANVAS)
  392. return;
  393. var left, bottom, right, top;
  394. if (cc.FIX_ARTIFACTS_BY_STRECHING_TEXEL) {
  395. left = (rect.x * 2 + 1) / (wide * 2);
  396. bottom = (rect.y * 2 + 1) / (high * 2);
  397. right = left + (rect.width * 2 - 2) / (wide * 2);
  398. top = bottom + (rect.height * 2 - 2) / (high * 2);
  399. } else {
  400. left = rect.x / wide;
  401. bottom = rect.y / high;
  402. right = left + rect.width / wide;
  403. top = bottom + rect.height / high;
  404. }
  405. // Important. Texture in cocos2d are inverted, so the Y component should be inverted
  406. var temp = top;
  407. top = bottom;
  408. bottom = temp;
  409. var quads;
  410. var start = 0, end = 0;
  411. if (this._batchNode) {
  412. quads = this._batchNode.getTextureAtlas().getQuads();
  413. start = this._atlasIndex;
  414. end = this._atlasIndex + this._totalParticles;
  415. } else {
  416. quads = this._quads;
  417. start = 0;
  418. end = this._totalParticles;
  419. }
  420. for (var i = start; i < end; i++) {
  421. if (!quads[i])
  422. quads[i] = cc.V3F_C4B_T2F_QuadZero();
  423. // bottom-left vertex:
  424. var selQuad = quads[i];
  425. selQuad.bl.texCoords.u = left;
  426. selQuad.bl.texCoords.v = bottom;
  427. // bottom-right vertex:
  428. selQuad.br.texCoords.u = right;
  429. selQuad.br.texCoords.v = bottom;
  430. // top-left vertex:
  431. selQuad.tl.texCoords.u = left;
  432. selQuad.tl.texCoords.v = top;
  433. // top-right vertex:
  434. selQuad.tr.texCoords.u = right;
  435. selQuad.tr.texCoords.v = top;
  436. }
  437. },
  438. /**
  439. * return weak reference to the cc.SpriteBatchNode that renders the cc.Sprite
  440. * @return {cc.ParticleBatchNode}
  441. */
  442. getBatchNode:function () {
  443. return this._batchNode;
  444. },
  445. /**
  446. * set weak reference to the cc.SpriteBatchNode that renders the cc.Sprite
  447. * @param {cc.ParticleBatchNode} batchNode
  448. */
  449. setBatchNode:function (batchNode) {
  450. if (this._batchNode != batchNode) {
  451. var oldBatch = this._batchNode;
  452. this._batchNode = batchNode; //weak reference
  453. if (batchNode) {
  454. var locParticles = this._particles;
  455. for (var i = 0; i < this._totalParticles; i++)
  456. locParticles[i].atlasIndex = i;
  457. }
  458. // NEW: is self render ?
  459. if (!batchNode) {
  460. this._allocMemory();
  461. this.initIndices();
  462. this.setTexture(oldBatch.getTexture());
  463. //if (cc.TEXTURE_ATLAS_USE_VAO)
  464. // this._setupVBOandVAO();
  465. //else
  466. this._setupVBO();
  467. } else if (!oldBatch) {
  468. // OLD: was it self render cleanup ?
  469. // copy current state to batch
  470. this._batchNode.getTextureAtlas()._copyQuadsToTextureAtlas(this._quads, this._atlasIndex);
  471. //delete buffer
  472. cc.renderContext.deleteBuffer(this._buffersVBO[1]); //where is re-bindBuffer code?
  473. //if (cc.TEXTURE_ATLAS_USE_VAO)
  474. // glDeleteVertexArrays(1, this._VAOname);
  475. }
  476. }
  477. },
  478. /**
  479. * return index of system in batch node array
  480. * @return {Number}
  481. */
  482. getAtlasIndex:function () {
  483. return this._atlasIndex;
  484. },
  485. /**
  486. * set index of system in batch node array
  487. * @param {Number} atlasIndex
  488. */
  489. setAtlasIndex:function (atlasIndex) {
  490. this._atlasIndex = atlasIndex;
  491. },
  492. /**
  493. * Return DrawMode of ParticleSystem
  494. * @return {Number}
  495. */
  496. getDrawMode:function () {
  497. return this._drawMode;
  498. },
  499. /**
  500. * DrawMode of ParticleSystem setter
  501. * @param {Number} drawMode
  502. */
  503. setDrawMode:function (drawMode) {
  504. this._drawMode = drawMode;
  505. },
  506. /**
  507. * Return ShapeType of ParticleSystem
  508. * @return {Number}
  509. */
  510. getShapeType:function () {
  511. return this._shapeType;
  512. },
  513. /**
  514. * ShapeType of ParticleSystem setter
  515. * @param {Number} shapeType
  516. */
  517. setShapeType:function (shapeType) {
  518. this._shapeType = shapeType;
  519. },
  520. /**
  521. * Return ParticleSystem is active
  522. * @return {Boolean}
  523. */
  524. isActive:function () {
  525. return this._isActive;
  526. },
  527. /**
  528. * Quantity of particles that are being simulated at the moment
  529. * @return {Number}
  530. */
  531. getParticleCount:function () {
  532. return this._particleCount;
  533. },
  534. /**
  535. * Quantity of particles setter
  536. * @param {Number} particleCount
  537. */
  538. setParticleCount:function (particleCount) {
  539. this._particleCount = particleCount;
  540. },
  541. /**
  542. * How many seconds the emitter wil run. -1 means 'forever'
  543. * @return {Number}
  544. */
  545. getDuration:function () {
  546. return this._duration;
  547. },
  548. /**
  549. * set run seconds of the emitter
  550. * @param {Number} duration
  551. */
  552. setDuration:function (duration) {
  553. this._duration = duration;
  554. },
  555. /**
  556. * Return sourcePosition of the emitter
  557. * @return {cc.Point | Object}
  558. */
  559. getSourcePosition:function () {
  560. return {x:this._sourcePosition.x, y:this._sourcePosition.y};
  561. },
  562. /**
  563. * sourcePosition of the emitter setter
  564. * @param sourcePosition
  565. */
  566. setSourcePosition:function (sourcePosition) {
  567. this._sourcePosition = sourcePosition;
  568. },
  569. /**
  570. * Return Position variance of the emitter
  571. * @return {cc.Point | Object}
  572. */
  573. getPosVar:function () {
  574. return {x: this._posVar.x, y: this._posVar.y};
  575. },
  576. /**
  577. * Position variance of the emitter setter
  578. * @param {cc.Point} posVar
  579. */
  580. setPosVar:function (posVar) {
  581. this._posVar = posVar;
  582. },
  583. /**
  584. * Return life of each particle
  585. * @return {Number}
  586. */
  587. getLife:function () {
  588. return this._life;
  589. },
  590. /**
  591. * life of each particle setter
  592. * @param {Number} life
  593. */
  594. setLife:function (life) {
  595. this._life = life;
  596. },
  597. /**
  598. * Return life variance of each particle
  599. * @return {Number}
  600. */
  601. getLifeVar:function () {
  602. return this._lifeVar;
  603. },
  604. /**
  605. * life variance of each particle setter
  606. * @param {Number} lifeVar
  607. */
  608. setLifeVar:function (lifeVar) {
  609. this._lifeVar = lifeVar;
  610. },
  611. /**
  612. * Return angle of each particle
  613. * @return {Number}
  614. */
  615. getAngle:function () {
  616. return this._angle;
  617. },
  618. /**
  619. * angle of each particle setter
  620. * @param {Number} angle
  621. */
  622. setAngle:function (angle) {
  623. this._angle = angle;
  624. },
  625. /**
  626. * Return angle variance of each particle
  627. * @return {Number}
  628. */
  629. getAngleVar:function () {
  630. return this._angleVar;
  631. },
  632. /**
  633. * angle variance of each particle setter
  634. * @param angleVar
  635. */
  636. setAngleVar:function (angleVar) {
  637. this._angleVar = angleVar;
  638. },
  639. // mode A
  640. /**
  641. * Return Gravity of emitter
  642. * @return {cc.Point}
  643. */
  644. getGravity:function () {
  645. if(this._emitterMode !== cc.PARTICLE_MODE_GRAVITY)
  646. cc.log("cc.ParticleBatchNode.getGravity() : Particle Mode should be Gravity");
  647. var locGravity = this.modeA.gravity;
  648. return cc.p(locGravity.x, locGravity.y);
  649. },
  650. /**
  651. * Gravity of emitter setter
  652. * @param {cc.Point} gravity
  653. */
  654. setGravity:function (gravity) {
  655. if(this._emitterMode !== cc.PARTICLE_MODE_GRAVITY)
  656. cc.log("cc.ParticleBatchNode.setGravity() : Particle Mode should be Gravity");
  657. this.modeA.gravity = gravity;
  658. },
  659. /**
  660. * Return Speed of each particle
  661. * @return {Number}
  662. */
  663. getSpeed:function () {
  664. if(this._emitterMode !== cc.PARTICLE_MODE_GRAVITY)
  665. cc.log("cc.ParticleBatchNode.getSpeed() : Particle Mode should be Gravity");
  666. return this.modeA.speed;
  667. },
  668. /**
  669. * Speed of each particle setter
  670. * @param {Number} speed
  671. */
  672. setSpeed:function (speed) {
  673. if(this._emitterMode !== cc.PARTICLE_MODE_GRAVITY)
  674. cc.log("cc.ParticleBatchNode.setSpeed() : Particle Mode should be Gravity");
  675. this.modeA.speed = speed;
  676. },
  677. /**
  678. * return speed variance of each particle. Only available in 'Gravity' mode.
  679. * @return {Number}
  680. */
  681. getSpeedVar:function () {
  682. if(this._emitterMode !== cc.PARTICLE_MODE_GRAVITY)
  683. cc.log("cc.ParticleBatchNode.getSpeedVar() : Particle Mode should be Gravity");
  684. return this.modeA.speedVar;
  685. },
  686. /**
  687. * speed variance of each particle setter. Only available in 'Gravity' mode.
  688. * @param {Number} speedVar
  689. */
  690. setSpeedVar:function (speedVar) {
  691. if(this._emitterMode !== cc.PARTICLE_MODE_GRAVITY)
  692. cc.log("cc.ParticleBatchNode.setSpeedVar() : Particle Mode should be Gravity");
  693. this.modeA.speedVar = speedVar;
  694. },
  695. /**
  696. * Return tangential acceleration of each particle. Only available in 'Gravity' mode.
  697. * @return {Number}
  698. */
  699. getTangentialAccel:function () {
  700. if(this._emitterMode !== cc.PARTICLE_MODE_GRAVITY)
  701. cc.log("cc.ParticleBatchNode.getTangentialAccel() : Particle Mode should be Gravity");
  702. return this.modeA.tangentialAccel;
  703. },
  704. /**
  705. * Tangential acceleration of each particle setter. Only available in 'Gravity' mode.
  706. * @param {Number} tangentialAccel
  707. */
  708. setTangentialAccel:function (tangentialAccel) {
  709. if(this._emitterMode !== cc.PARTICLE_MODE_GRAVITY)
  710. cc.log("cc.ParticleBatchNode.setTangentialAccel() : Particle Mode should be Gravity");
  711. this.modeA.tangentialAccel = tangentialAccel;
  712. },
  713. /**
  714. * Return tangential acceleration variance of each particle. Only available in 'Gravity' mode.
  715. * @return {Number}
  716. */
  717. getTangentialAccelVar:function () {
  718. if(this._emitterMode !== cc.PARTICLE_MODE_GRAVITY)
  719. cc.log("cc.ParticleBatchNode.getTangentialAccelVar() : Particle Mode should be Gravity");
  720. return this.modeA.tangentialAccelVar;
  721. },
  722. /**
  723. * tangential acceleration variance of each particle setter. Only available in 'Gravity' mode.
  724. * @param {Number} tangentialAccelVar
  725. */
  726. setTangentialAccelVar:function (tangentialAccelVar) {
  727. if(this._emitterMode !== cc.PARTICLE_MODE_GRAVITY)
  728. cc.log("cc.ParticleBatchNode.setTangentialAccelVar() : Particle Mode should be Gravity");
  729. this.modeA.tangentialAccelVar = tangentialAccelVar;
  730. },
  731. /**
  732. * Return radial acceleration of each particle. Only available in 'Gravity' mode.
  733. * @return {Number}
  734. */
  735. getRadialAccel:function () {
  736. if(this._emitterMode !== cc.PARTICLE_MODE_GRAVITY)
  737. cc.log("cc.ParticleBatchNode.getRadialAccel() : Particle Mode should be Gravity");
  738. return this.modeA.radialAccel;
  739. },
  740. /**
  741. * radial acceleration of each particle setter. Only available in 'Gravity' mode.
  742. * @param {Number} radialAccel
  743. */
  744. setRadialAccel:function (radialAccel) {
  745. if(this._emitterMode !== cc.PARTICLE_MODE_GRAVITY)
  746. cc.log("cc.ParticleBatchNode.setRadialAccel() : Particle Mode should be Gravity");
  747. this.modeA.radialAccel = radialAccel;
  748. },
  749. /**
  750. * Return radial acceleration variance of each particle. Only available in 'Gravity' mode.
  751. * @return {Number}
  752. */
  753. getRadialAccelVar:function () {
  754. if(this._emitterMode !== cc.PARTICLE_MODE_GRAVITY)
  755. cc.log("cc.ParticleBatchNode.getRadialAccelVar() : Particle Mode should be Gravity");
  756. return this.modeA.radialAccelVar;
  757. },
  758. /**
  759. * radial acceleration variance of each particle setter. Only available in 'Gravity' mode.
  760. * @param {Number} radialAccelVar
  761. */
  762. setRadialAccelVar:function (radialAccelVar) {
  763. if(this._emitterMode !== cc.PARTICLE_MODE_GRAVITY)
  764. cc.log("cc.ParticleBatchNode.setRadialAccelVar() : Particle Mode should be Gravity");
  765. this.modeA.radialAccelVar = radialAccelVar;
  766. },
  767. /**
  768. * get the rotation of each particle to its direction Only available in 'Gravity' mode.
  769. * @returns {boolean}
  770. */
  771. getRotationIsDir: function(){
  772. if(this._emitterMode !== cc.PARTICLE_MODE_GRAVITY)
  773. cc.log("cc.ParticleBatchNode.getRotationIsDir() : Particle Mode should be Gravity");
  774. return this.modeA.rotationIsDir;
  775. },
  776. /**
  777. * set the rotation of each particle to its direction Only available in 'Gravity' mode.
  778. * @param {boolean} t
  779. */
  780. setRotationIsDir: function(t){
  781. if(this._emitterMode !== cc.PARTICLE_MODE_GRAVITY)
  782. cc.log("cc.ParticleBatchNode.setRotationIsDir() : Particle Mode should be Gravity");
  783. this.modeA.rotationIsDir = t;
  784. },
  785. // mode B
  786. /**
  787. * Return starting radius of the particles. Only available in 'Radius' mode.
  788. * @return {Number}
  789. */
  790. getStartRadius:function () {
  791. if(this._emitterMode !== cc.PARTICLE_MODE_RADIUS)
  792. cc.log("cc.ParticleBatchNode.getStartRadius() : Particle Mode should be Radius");
  793. return this.modeB.startRadius;
  794. },
  795. /**
  796. * starting radius of the particles setter. Only available in 'Radius' mode.
  797. * @param {Number} startRadius
  798. */
  799. setStartRadius:function (startRadius) {
  800. if(this._emitterMode !== cc.PARTICLE_MODE_RADIUS)
  801. cc.log("cc.ParticleBatchNode.setStartRadius() : Particle Mode should be Radius");
  802. this.modeB.startRadius = startRadius;
  803. },
  804. /**
  805. * Return starting radius variance of the particles. Only available in 'Radius' mode.
  806. * @return {Number}
  807. */
  808. getStartRadiusVar:function () {
  809. if(this._emitterMode !== cc.PARTICLE_MODE_RADIUS)
  810. cc.log("cc.ParticleBatchNode.getStartRadiusVar() : Particle Mode should be Radius");
  811. return this.modeB.startRadiusVar;
  812. },
  813. /**
  814. * starting radius variance of the particles setter. Only available in 'Radius' mode.
  815. * @param {Number} startRadiusVar
  816. */
  817. setStartRadiusVar:function (startRadiusVar) {
  818. if(this._emitterMode !== cc.PARTICLE_MODE_RADIUS)
  819. cc.log("cc.ParticleBatchNode.setStartRadiusVar() : Particle Mode should be Radius");
  820. this.modeB.startRadiusVar = startRadiusVar;
  821. },
  822. /**
  823. * Return ending radius of the particles. Only available in 'Radius' mode.
  824. * @return {Number}
  825. */
  826. getEndRadius:function () {
  827. if(this._emitterMode !== cc.PARTICLE_MODE_RADIUS)
  828. cc.log("cc.ParticleBatchNode.getEndRadius() : Particle Mode should be Radius");
  829. return this.modeB.endRadius;
  830. },
  831. /**
  832. * ending radius of the particles setter. Only available in 'Radius' mode.
  833. * @param {Number} endRadius
  834. */
  835. setEndRadius:function (endRadius) {
  836. if(this._emitterMode !== cc.PARTICLE_MODE_RADIUS)
  837. cc.log("cc.ParticleBatchNode.setEndRadius() : Particle Mode should be Radius");
  838. this.modeB.endRadius = endRadius;
  839. },
  840. /**
  841. * Return ending radius variance of the particles. Only available in 'Radius' mode.
  842. * @return {Number}
  843. */
  844. getEndRadiusVar:function () {
  845. if(this._emitterMode !== cc.PARTICLE_MODE_RADIUS)
  846. cc.log("cc.ParticleBatchNode.getEndRadiusVar() : Particle Mode should be Radius");
  847. return this.modeB.endRadiusVar;
  848. },
  849. /**
  850. * ending radius variance of the particles setter. Only available in 'Radius' mode.
  851. * @param endRadiusVar
  852. */
  853. setEndRadiusVar:function (endRadiusVar) {
  854. if(this._emitterMode !== cc.PARTICLE_MODE_RADIUS)
  855. cc.log("cc.ParticleBatchNode.setEndRadiusVar() : Particle Mode should be Radius");
  856. this.modeB.endRadiusVar = endRadiusVar;
  857. },
  858. /**
  859. * get Number of degress to rotate a particle around the source pos per second. Only available in 'Radius' mode.
  860. * @return {Number}
  861. */
  862. getRotatePerSecond:function () {
  863. if(this._emitterMode !== cc.PARTICLE_MODE_RADIUS)
  864. cc.log("cc.ParticleBatchNode.getRotatePerSecond() : Particle Mode should be Radius");
  865. return this.modeB.rotatePerSecond;
  866. },
  867. /**
  868. * set Number of degress to rotate a particle around the source pos per second. Only available in 'Radius' mode.
  869. * @param {Number} degrees
  870. */
  871. setRotatePerSecond:function (degrees) {
  872. if(this._emitterMode !== cc.PARTICLE_MODE_RADIUS)
  873. cc.log("cc.ParticleBatchNode.setRotatePerSecond() : Particle Mode should be Radius");
  874. this.modeB.rotatePerSecond = degrees;
  875. },
  876. /**
  877. * Return Variance in degrees for rotatePerSecond. Only available in 'Radius' mode.
  878. * @return {Number}
  879. */
  880. getRotatePerSecondVar:function () {
  881. if(this._emitterMode !== cc.PARTICLE_MODE_RADIUS)
  882. cc.log("cc.ParticleBatchNode.getRotatePerSecondVar() : Particle Mode should be Radius");
  883. return this.modeB.rotatePerSecondVar;
  884. },
  885. /**
  886. * Variance in degrees for rotatePerSecond setter. Only available in 'Radius' mode.
  887. * @param degrees
  888. */
  889. setRotatePerSecondVar:function (degrees) {
  890. if(this._emitterMode !== cc.PARTICLE_MODE_RADIUS)
  891. cc.log("cc.ParticleBatchNode.setRotatePerSecondVar() : Particle Mode should be Radius");
  892. this.modeB.rotatePerSecondVar = degrees;
  893. },
  894. //////////////////////////////////////////////////////////////////////////
  895. //don't use a transform matrix, this is faster
  896. setScale:function (scale, scaleY) {
  897. this._transformSystemDirty = true;
  898. cc.Node.prototype.setScale.call(this, scale, scaleY);
  899. },
  900. setRotation:function (newRotation) {
  901. this._transformSystemDirty = true;
  902. cc.Node.prototype.setRotation.call(this, newRotation);
  903. },
  904. setScaleX:function (newScaleX) {
  905. this._transformSystemDirty = true;
  906. cc.Node.prototype.setScaleX.call(this, newScaleX);
  907. },
  908. setScaleY:function (newScaleY) {
  909. this._transformSystemDirty = true;
  910. cc.Node.prototype.setScaleY.call(this, newScaleY);
  911. },
  912. /**
  913. * get start size in pixels of each particle
  914. * @return {Number}
  915. */
  916. getStartSize:function () {
  917. return this._startSize;
  918. },
  919. /**
  920. * set start size in pixels of each particle
  921. * @param {Number} startSize
  922. */
  923. setStartSize:function (startSize) {
  924. this._startSize = startSize;
  925. },
  926. /**
  927. * get size variance in pixels of each particle
  928. * @return {Number}
  929. */
  930. getStartSizeVar:function () {
  931. return this._startSizeVar;
  932. },
  933. /**
  934. * set size variance in pixels of each particle
  935. * @param {Number} startSizeVar
  936. */
  937. setStartSizeVar:function (startSizeVar) {
  938. this._startSizeVar = startSizeVar;
  939. },
  940. /**
  941. * get end size in pixels of each particle
  942. * @return {Number}
  943. */
  944. getEndSize:function () {
  945. return this._endSize;
  946. },
  947. /**
  948. * set end size in pixels of each particle
  949. * @param endSize
  950. */
  951. setEndSize:function (endSize) {
  952. this._endSize = endSize;
  953. },
  954. /**
  955. * get end size variance in pixels of each particle
  956. * @return {Number}
  957. */
  958. getEndSizeVar:function () {
  959. return this._endSizeVar;
  960. },
  961. /**
  962. * set end size variance in pixels of each particle
  963. * @param {Number} endSizeVar
  964. */
  965. setEndSizeVar:function (endSizeVar) {
  966. this._endSizeVar = endSizeVar;
  967. },
  968. /**
  969. * set start color of each particle
  970. * @return {cc.Color4F}
  971. */
  972. getStartColor:function () {
  973. return this._startColor;
  974. },
  975. /**
  976. * get start color of each particle
  977. * @param {cc.Color4F} startColor
  978. */
  979. setStartColor:function (startColor) {
  980. if (startColor instanceof cc.Color3B)
  981. startColor = cc.c4FFromccc3B(startColor);
  982. this._startColor = startColor;
  983. },
  984. /**
  985. * get start color variance of each particle
  986. * @return {cc.Color4F}
  987. */
  988. getStartColorVar:function () {
  989. return this._startColorVar;
  990. },
  991. /**
  992. * set start color variance of each particle
  993. * @param {cc.Color4F} startColorVar
  994. */
  995. setStartColorVar:function (startColorVar) {
  996. if (startColorVar instanceof cc.Color3B)
  997. startColorVar = cc.c4FFromccc3B(startColorVar);
  998. this._startColorVar = startColorVar;
  999. },
  1000. /**
  1001. * get end color and end color variation of each particle
  1002. * @return {cc.Color4F}
  1003. */
  1004. getEndColor:function () {
  1005. return this._endColor;
  1006. },
  1007. /**
  1008. * set end color and end color variation of each particle
  1009. * @param {cc.Color4F} endColor
  1010. */
  1011. setEndColor:function (endColor) {
  1012. if (endColor instanceof cc.Color3B)
  1013. endColor = cc.c4FFromccc3B(endColor);
  1014. this._endColor = endColor;
  1015. },
  1016. /**
  1017. * get end color variance of each particle
  1018. * @return {cc.Color4F}
  1019. */
  1020. getEndColorVar:function () {
  1021. return this._endColorVar;
  1022. },
  1023. /**
  1024. * set end color variance of each particle
  1025. * @param {cc.Color4F} endColorVar
  1026. */
  1027. setEndColorVar:function (endColorVar) {
  1028. if (endColorVar instanceof cc.Color3B)
  1029. endColorVar = cc.c4FFromccc3B(endColorVar);
  1030. this._endColorVar = endColorVar;
  1031. },
  1032. /**
  1033. * get initial angle of each particle
  1034. * @return {Number}
  1035. */
  1036. getStartSpin:function () {
  1037. return this._startSpin;
  1038. },
  1039. /**
  1040. * set initial angle of each particle
  1041. * @param {Number} startSpin
  1042. */
  1043. setStartSpin:function (startSpin) {
  1044. this._startSpin = startSpin;
  1045. },
  1046. /**
  1047. * get initial angle variance of each particle
  1048. * @return {Number}
  1049. */
  1050. getStartSpinVar:function () {
  1051. return this._startSpinVar;
  1052. },
  1053. /**
  1054. * set initial angle variance of each particle
  1055. * @param {Number} startSpinVar
  1056. */
  1057. setStartSpinVar:function (startSpinVar) {
  1058. this._startSpinVar = startSpinVar;
  1059. },
  1060. /**
  1061. * get end angle of each particle
  1062. * @return {Number}
  1063. */
  1064. getEndSpin:function () {
  1065. return this._endSpin;
  1066. },
  1067. /**
  1068. * set end angle of each particle
  1069. * @param {Number} endSpin
  1070. */
  1071. setEndSpin:function (endSpin) {
  1072. this._endSpin = endSpin;
  1073. },
  1074. /**
  1075. * get end angle variance of each particle
  1076. * @return {Number}
  1077. */
  1078. getEndSpinVar:function () {
  1079. return this._endSpinVar;
  1080. },
  1081. /**
  1082. * set end angle variance of each particle
  1083. * @param {Number} endSpinVar
  1084. */
  1085. setEndSpinVar:function (endSpinVar) {
  1086. this._endSpinVar = endSpinVar;
  1087. },
  1088. /**
  1089. * get emission rate of the particles
  1090. * @return {Number}
  1091. */
  1092. getEmissionRate:function () {
  1093. return this._emissionRate;
  1094. },
  1095. /**
  1096. * set emission rate of the particles
  1097. * @param {Number} emissionRate
  1098. */
  1099. setEmissionRate:function (emissionRate) {
  1100. this._emissionRate = emissionRate;
  1101. },
  1102. /**
  1103. * get maximum particles of the system
  1104. * @return {Number}
  1105. */
  1106. getTotalParticles:function () {
  1107. return this._totalParticles;
  1108. },
  1109. /**
  1110. * set maximum particles of the system
  1111. * @param {Number} tp totalParticles
  1112. */
  1113. setTotalParticles:function (tp) {
  1114. //cc.Assert(tp <= this._allocatedParticles, "Particle: resizing particle array only supported for quads");
  1115. if (cc.renderContextType === cc.CANVAS){
  1116. this._totalParticles = (tp < 200) ? tp : 200;
  1117. return;
  1118. }
  1119. // If we are setting the total numer of particles to a number higher
  1120. // than what is allocated, we need to allocate new arrays
  1121. if (tp > this._allocatedParticles) {
  1122. var quadSize = cc.V3F_C4B_T2F_Quad.BYTES_PER_ELEMENT;
  1123. // Allocate new memory
  1124. this._indices = new Uint16Array(tp * 6);
  1125. var locQuadsArrayBuffer = new ArrayBuffer(tp * quadSize);
  1126. //TODO need fix
  1127. // Assign pointers
  1128. var locParticles = this._particles;
  1129. locParticles.length = 0;
  1130. var locQuads = this._quads;
  1131. locQuads.length = 0;
  1132. for (var j = 0; j < tp; j++) {
  1133. locParticles[j] = new cc.Particle();
  1134. locQuads[j] = new cc.V3F_C4B_T2F_Quad(null, null, null, null, locQuadsArrayBuffer, j * quadSize);
  1135. }
  1136. this._allocatedParticles = tp;
  1137. this._totalParticles = tp;
  1138. // Init particles
  1139. if (this._batchNode) {
  1140. for (var i = 0; i < tp; i++)
  1141. locParticles[i].atlasIndex = i;
  1142. }
  1143. this._quadsArrayBuffer = locQuadsArrayBuffer;
  1144. this.initIndices();
  1145. //if (cc.TEXTURE_ATLAS_USE_VAO)
  1146. // this._setupVBOandVAO();
  1147. //else
  1148. this._setupVBO();
  1149. //set the texture coord
  1150. if(this._texture){
  1151. var size = this._texture.getContentSize();
  1152. this.initTexCoordsWithRect(cc.rect(0, 0, size.width, size.height));
  1153. }
  1154. } else
  1155. this._totalParticles = tp;
  1156. this.resetSystem();
  1157. },
  1158. /**
  1159. * get Texture of Particle System
  1160. * @return {cc.Texture2D}
  1161. */
  1162. getTexture:function () {
  1163. return this._texture;
  1164. },
  1165. /**
  1166. * set Texture of Particle System
  1167. * @param {cc.Texture2D } texture
  1168. */
  1169. setTexture:function (texture) {
  1170. if(texture.isLoaded()){
  1171. var size = texture.getContentSize();
  1172. this.setTextureWithRect(texture, cc.rect(0, 0, size.width, size.height));
  1173. } else {
  1174. this._textureLoaded = false;
  1175. texture.addLoadedEventListener(function(sender){
  1176. this._textureLoaded = true;
  1177. var size = sender.getContentSize();
  1178. this.setTextureWithRect(sender, cc.rect(0, 0, size.width, size.height));
  1179. }, this);
  1180. }
  1181. },
  1182. /** conforms to CocosNodeTexture protocol */
  1183. /**
  1184. * get BlendFunc of Particle System
  1185. * @return {cc.BlendFunc}
  1186. */
  1187. getBlendFunc:function () {
  1188. return this._blendFunc;
  1189. },
  1190. /**
  1191. * set BlendFunc of Particle System
  1192. * @param {Number} src
  1193. * @param {Number} dst
  1194. */
  1195. setBlendFunc:function (src, dst) {
  1196. if (dst === undefined) {
  1197. if (this._blendFunc != src) {
  1198. this._blendFunc = src;
  1199. this._updateBlendFunc();
  1200. }
  1201. } else {
  1202. if (this._blendFunc.src != src || this._blendFunc.dst != dst) {
  1203. this._blendFunc = {src:src, dst:dst};
  1204. this._updateBlendFunc();
  1205. }
  1206. }
  1207. },
  1208. /**
  1209. * does the alpha value modify color getter
  1210. * @return {Boolean}
  1211. */
  1212. getOpacityModifyRGB:function () {
  1213. return this._opacityModifyRGB;
  1214. },
  1215. /**
  1216. * does the alpha value modify color setter
  1217. * @param newValue
  1218. */
  1219. setOpacityModifyRGB:function (newValue) {
  1220. this._opacityModifyRGB = newValue;
  1221. },
  1222. /**
  1223. * <p>whether or not the particles are using blend additive.<br/>
  1224. * If enabled, the following blending function will be used.<br/>
  1225. * </p>
  1226. * @return {Boolean}
  1227. * @example
  1228. * source blend function = GL_SRC_ALPHA;
  1229. * dest blend function = GL_ONE;
  1230. */
  1231. isBlendAdditive:function () {
  1232. return (( this._blendFunc.src == gl.SRC_ALPHA && this._blendFunc.dst == gl.ONE) || (this._blendFunc.src == gl.ONE && this._blendFunc.dst == gl.ONE));
  1233. },
  1234. /**
  1235. * <p>whether or not the particles are using blend additive.<br/>
  1236. * If enabled, the following blending function will be used.<br/>
  1237. * </p>
  1238. * @param {Boolean} isBlendAdditive
  1239. */
  1240. setBlendAdditive:function (isBlendAdditive) {
  1241. var locBlendFunc = this._blendFunc;
  1242. if (isBlendAdditive) {
  1243. locBlendFunc.src = gl.SRC_ALPHA;
  1244. locBlendFunc.dst = gl.ONE;
  1245. } else {
  1246. if (cc.renderContextType === cc.WEBGL) {
  1247. if (this._texture && !this._texture.hasPremultipliedAlpha()) {
  1248. locBlendFunc.src = gl.SRC_ALPHA;
  1249. locBlendFunc.dst = gl.ONE_MINUS_SRC_ALPHA;
  1250. } else {
  1251. locBlendFunc.src = cc.BLEND_SRC;
  1252. locBlendFunc.dst = cc.BLEND_DST;
  1253. }
  1254. } else {
  1255. locBlendFunc.src = cc.BLEND_SRC;
  1256. locBlendFunc.dst = cc.BLEND_DST;
  1257. }
  1258. }
  1259. },
  1260. /**
  1261. * get particles movement type: Free or Grouped
  1262. * @return {Number}
  1263. */
  1264. getPositionType:function () {
  1265. return this._positionType;
  1266. },
  1267. /**
  1268. * set particles movement type: Free or Grouped
  1269. * @param {Number} positionType
  1270. */
  1271. setPositionType:function (positionType) {
  1272. this._positionType = positionType;
  1273. },
  1274. /**
  1275. * <p> return whether or not the node will be auto-removed when it has no particles left.<br/>
  1276. * By default it is false.<br/>
  1277. * </p>
  1278. * @return {Boolean}
  1279. */
  1280. isAutoRemoveOnFinish:function () {
  1281. return this._isAutoRemoveOnFinish;
  1282. },
  1283. /**
  1284. * <p> set whether or not the node will be auto-removed when it has no particles left.<br/>
  1285. * By default it is false.<br/>
  1286. * </p>
  1287. * @param {Boolean} isAutoRemoveOnFinish
  1288. */
  1289. setAutoRemoveOnFinish:function (isAutoRemoveOnFinish) {
  1290. this._isAutoRemoveOnFinish = isAutoRemoveOnFinish;
  1291. },
  1292. /**
  1293. * return kind of emitter modes
  1294. * @return {Number}
  1295. */
  1296. getEmitterMode:function () {
  1297. return this._emitterMode;
  1298. },
  1299. /**
  1300. * <p>Switch between different kind of emitter modes:<br/>
  1301. * - CCPARTICLE_MODE_GRAVITY: uses gravity, speed, radial and tangential acceleration<br/>
  1302. * - CCPARTICLE_MODE_RADIUS: uses radius movement + rotation <br/>
  1303. * </p>
  1304. * @param {Number} emitterMode
  1305. */
  1306. setEmitterMode:function (emitterMode) {
  1307. this._emitterMode = emitterMode;
  1308. },
  1309. /**
  1310. * initializes a cc.ParticleSystem
  1311. */
  1312. init:function () {
  1313. return this.initWithTotalParticles(150);
  1314. },
  1315. /**
  1316. * <p>
  1317. * initializes a CCParticleSystem from a plist file. <br/>
  1318. * This plist files can be creted manually or with Particle Designer:<br/>
  1319. * http://particledesigner.71squared.com/
  1320. * </p>
  1321. * @param {String} plistFile
  1322. * @return {boolean}
  1323. */
  1324. initWithFile:function (plistFile) {
  1325. this._plistFile = plistFile;
  1326. var fileUtils = cc.FileUtils.getInstance();
  1327. var fullPath = fileUtils.fullPathForFilename(plistFile);
  1328. var dict = fileUtils.dictionaryWithContentsOfFileThreadSafe(fullPath);
  1329. if(!dict){
  1330. cc.log("cc.ParticleSystem.initWithFile(): Particles: file not found");
  1331. return false;
  1332. }
  1333. // XXX compute path from a path, should define a function somewhere to do it
  1334. return this.initWithDictionary(dict, "");
  1335. },
  1336. /**
  1337. * return bounding box of particle system in world space
  1338. * @return {cc.Rect}
  1339. */
  1340. getBoundingBoxToWorld:function () {
  1341. return cc.rect(0, 0, cc.canvas.width, cc.canvas.height);
  1342. },
  1343. /**
  1344. * initializes a particle system from a NSDictionary and the path from where to load the png
  1345. * @param {object} dictionary
  1346. * @param {String} dirname
  1347. * @return {Boolean}
  1348. */
  1349. initWithDictionary:function (dictionary, dirname) {
  1350. var ret = false;
  1351. var buffer = null;
  1352. var image = null;
  1353. var locValueForKey = this._valueForKey;
  1354. var maxParticles = parseInt(locValueForKey("maxParticles", dictionary));
  1355. // self, not super
  1356. if (this.initWithTotalParticles(maxParticles)) {
  1357. // angle
  1358. this._angle = parseFloat(locValueForKey("angle", dictionary));
  1359. this._angleVar = parseFloat(locValueForKey("angleVariance", dictionary));
  1360. // duration
  1361. this._duration = parseFloat(locValueForKey("duration", dictionary));
  1362. // blend function
  1363. this._blendFunc.src = parseInt(locValueForKey("blendFuncSource", dictionary));
  1364. this._blendFunc.dst = parseInt(locValueForKey("blendFuncDestination", dictionary));
  1365. // color
  1366. var locStartColor = this._startColor;
  1367. locStartColor.r = parseFloat(locValueForKey("startColorRed", dictionary));
  1368. locStartColor.g = parseFloat(locValueForKey("startColorGreen", dictionary));
  1369. locStartColor.b = parseFloat(locValueForKey("startColorBlue", dictionary));
  1370. locStartColor.a = parseFloat(locValueForKey("startColorAlpha", dictionary));
  1371. var locStartColorVar = this._startColorVar;
  1372. locStartColorVar.r = parseFloat(locValueForKey("startColorVarianceRed", dictionary));
  1373. locStartColorVar.g = parseFloat(locValueForKey("startColorVarianceGreen", dictionary));
  1374. locStartColorVar.b = parseFloat(locValueForKey("startColorVarianceBlue", dictionary));
  1375. locStartColorVar.a = parseFloat(locValueForKey("startColorVarianceAlpha", dictionary));
  1376. var locEndColor = this._endColor;
  1377. locEndColor.r = parseFloat(locValueForKey("finishColorRed", dictionary));
  1378. locEndColor.g = parseFloat(locValueForKey("finishColorGreen", dictionary));
  1379. locEndColor.b = parseFloat(locValueForKey("finishColorBlue", dictionary));
  1380. locEndColor.a = parseFloat(locValueForKey("finishColorAlpha", dictionary));
  1381. var locEndColorVar = this._endColorVar;
  1382. locEndColorVar.r = parseFloat(locValueForKey("finishColorVarianceRed", dictionary));
  1383. locEndColorVar.g = parseFloat(locValueForKey("finishColorVarianceGreen", dictionary));
  1384. locEndColorVar.b = parseFloat(locValueForKey("finishColorVarianceBlue", dictionary));
  1385. locEndColorVar.a = parseFloat(locValueForKey("finishColorVarianceAlpha", dictionary));
  1386. // particle size
  1387. this._startSize = parseFloat(locValueForKey("startParticleSize", dictionary));
  1388. this._startSizeVar = parseFloat(locValueForKey("startParticleSizeVariance", dictionary));
  1389. this._endSize = parseFloat(locValueForKey("finishParticleSize", dictionary));
  1390. this._endSizeVar = parseFloat(locValueForKey("finishParticleSizeVariance", dictionary));
  1391. // position
  1392. var x = parseFloat(locValueForKey("sourcePositionx", dictionary));
  1393. var y = parseFloat(locValueForKey("sourcePositiony", dictionary));
  1394. this.setPosition(x, y);
  1395. this._posVar.x = parseFloat(locValueForKey("sourcePositionVariancex", dictionary));
  1396. this._posVar.y = parseFloat(locValueForKey("sourcePositionVariancey", dictionary));
  1397. // Spinning
  1398. this._startSpin = parseFloat(locValueForKey("rotationStart", dictionary));
  1399. this._startSpinVar = parseFloat(locValueForKey("rotationStartVariance", dictionary));
  1400. this._endSpin = parseFloat(locValueForKey("rotationEnd", dictionary));
  1401. this._endSpinVar = parseFloat(locValueForKey("rotationEndVariance", dictionary));
  1402. this._emitterMode = parseInt(locValueForKey("emitterType", dictionary));
  1403. // Mode A: Gravity + tangential accel + radial accel
  1404. if (this._emitterMode == cc.PARTICLE_MODE_GRAVITY) {
  1405. var locModeA = this.modeA;
  1406. // gravity
  1407. locModeA.gravity.x = parseFloat(locValueForKey("gravityx", dictionary));
  1408. locModeA.gravity.y = parseFloat(locValueForKey("gravityy", dictionary));
  1409. // speed
  1410. locModeA.speed = parseFloat(locValueForKey("speed", dictionary));
  1411. locModeA.speedVar = parseFloat(locValueForKey("speedVariance", dictionary));
  1412. // radial acceleration
  1413. var pszTmp = locValueForKey("radialAcceleration", dictionary);
  1414. locModeA.radialAccel = (pszTmp) ? parseFloat(pszTmp) : 0;
  1415. pszTmp = locValueForKey("radialAccelVariance", dictionary);
  1416. locModeA.radialAccelVar = (pszTmp) ? parseFloat(pszTmp) : 0;
  1417. // tangential acceleration
  1418. pszTmp = locValueForKey("tangentialAcceleration", dictionary);
  1419. locModeA.tangentialAccel = (pszTmp) ? parseFloat(pszTmp) : 0;
  1420. pszTmp = locValueForKey("tangentialAccelVariance", dictionary);
  1421. locModeA.tangentialAccelVar = (pszTmp) ? parseFloat(pszTmp) : 0;
  1422. // rotation is dir
  1423. var locRotationIsDir = locValueForKey("rotationIsDir", dictionary).toLowerCase();
  1424. locModeA.rotationIsDir = (locRotationIsDir != null && (locRotationIsDir === "true" || locRotationIsDir === "1"));
  1425. } else if (this._emitterMode == cc.PARTICLE_MODE_RADIUS) {
  1426. // or Mode B: radius movement
  1427. var locModeB = this.modeB;
  1428. locModeB.startRadius = parseFloat(locValueForKey("maxRadius", dictionary));
  1429. locModeB.startRadiusVar = parseFloat(locValueForKey("maxRadiusVariance", dictionary));
  1430. locModeB.endRadius = parseFloat(locValueForKey("minRadius", dictionary));
  1431. locModeB.endRadiusVar = 0;
  1432. locModeB.rotatePerSecond = parseFloat(locValueForKey("rotatePerSecond", dictionary));
  1433. locModeB.rotatePerSecondVar = parseFloat(locValueForKey("rotatePerSecondVariance", dictionary));
  1434. } else {
  1435. cc.log("cc.ParticleSystem.initWithDictionary(): Invalid emitterType in config file");
  1436. return false;
  1437. }
  1438. // life span
  1439. this._life = parseFloat(locValueForKey("particleLifespan", dictionary));
  1440. this._lifeVar = parseFloat(locValueForKey("particleLifespanVariance", dictionary));
  1441. // emission Rate
  1442. this._emissionRate = this._totalParticles / this._life;
  1443. //don't get the internal texture if a batchNode is used
  1444. if (!this._batchNode) {
  1445. // Set a compatible default for the alpha transfer
  1446. this._opacityModifyRGB = false;
  1447. // texture
  1448. // Try to get the texture from the cache
  1449. var textureName = locValueForKey("textureFileName", dictionary);
  1450. var fileUtils = cc.FileUtils.getInstance();
  1451. var imgPath = fileUtils.fullPathFromRelativeFile(textureName, this._plistFile);
  1452. var tex = cc.TextureCache.getInstance().textureForKey(imgPath);
  1453. if (tex) {
  1454. this.setTexture(tex);
  1455. } else {
  1456. var textureData = locValueForKey("textureImageData", dictionary);
  1457. if (textureData && textureData.length == 0) {
  1458. tex = cc.TextureCache.getInstance().addImage(imgPath);
  1459. if (!tex)
  1460. return false;
  1461. this.setTexture(tex);
  1462. } else {
  1463. buffer = cc.unzipBase64AsArray(textureData, 1);
  1464. if (!buffer) {
  1465. cc.log("cc.ParticleSystem: error decoding or ungzipping textureImageData");
  1466. return false;
  1467. }
  1468. var imageFormat = cc.getImageFormatByData(buffer);
  1469. if(imageFormat !== cc.FMT_TIFF && imageFormat !== cc.FMT_PNG){
  1470. cc.log("cc.ParticleSystem: unknown image format with Data");
  1471. return false;
  1472. }
  1473. var canvasObj = document.createElement("canvas");
  1474. if(imageFormat === cc.FMT_PNG){
  1475. var myPngObj = new cc.PNGReader(buffer);
  1476. myPngObj.render(canvasObj);
  1477. } else {
  1478. var myTIFFObj = cc.TIFFReader.getInstance();
  1479. myTIFFObj.parseTIFF(buffer,canvasObj);
  1480. }
  1481. var imgFullPath = fileUtils.fullPathForFilename(imgPath);
  1482. cc.TextureCache.getInstance().cacheImage(imgFullPath, canvasObj);
  1483. var addTexture = cc.TextureCache.getInstance().textureForKey(imgPath);
  1484. if(!addTexture)
  1485. cc.log("cc.ParticleSystem.initWithDictionary() : error loading the texture");
  1486. this.setTexture(addTexture);
  1487. }
  1488. }
  1489. }
  1490. ret = true;
  1491. }
  1492. return ret;
  1493. },
  1494. /**
  1495. * Initializes a system with a fixed number of particles
  1496. * @param {Number} numberOfParticles
  1497. * @return {Boolean}
  1498. */
  1499. initWithTotalParticles:function (numberOfParticles) {
  1500. this._totalParticles = numberOfParticles;
  1501. var i, locParticles = this._particles;
  1502. locParticles.length = 0;
  1503. for(i = 0; i< numberOfParticles; i++){
  1504. locParticles[i] = new cc.Particle();
  1505. }
  1506. if (!locParticles) {
  1507. cc.log("Particle system: not enough memory");
  1508. return false;
  1509. }
  1510. this._allocatedParticles = numberOfParticles;
  1511. if (this._batchNode)
  1512. for (i = 0; i < this._totalParticles; i++)
  1513. locParticles[i].atlasIndex = i;
  1514. // default, active
  1515. this._isActive = true;
  1516. // default blend function
  1517. this._blendFunc.src = cc.BLEND_SRC;
  1518. this._blendFunc.dst = cc.BLEND_DST;
  1519. // default movement type;
  1520. this._positionType = cc.PARTICLE_TYPE_FREE;
  1521. // by default be in mode A:
  1522. this._emitterMode = cc.PARTICLE_MODE_GRAVITY;
  1523. // default: modulate
  1524. // XXX: not used
  1525. // colorModulate = YES;
  1526. this._isAutoRemoveOnFinish = false;
  1527. //for batchNode
  1528. this._transformSystemDirty = false;
  1529. // udpate after action in run!
  1530. this.scheduleUpdateWithPriority(1);
  1531. if(cc.renderContextType === cc.WEBGL){
  1532. // allocating data space
  1533. if (!this._allocMemory())
  1534. return false;
  1535. this.initIndices();
  1536. //if (cc.TEXTURE_ATLAS_USE_VAO)
  1537. // this._setupVBOandVAO();
  1538. //else
  1539. this._setupVBO();
  1540. this.setShaderProgram(cc.ShaderCache.getInstance().programForKey(cc.SHADER_POSITION_TEXTURECOLOR));
  1541. }
  1542. return true;
  1543. },
  1544. destroyParticleSystem:function () {
  1545. this.unscheduleUpdate();
  1546. },
  1547. /**
  1548. * Add a particle to the emitter
  1549. * @return {Boolean}
  1550. */
  1551. addParticle: function () {
  1552. if (this.isFull())
  1553. return false;
  1554. var particle, particles = this._particles;
  1555. if (cc.renderContextType === cc.CANVAS) {
  1556. if (this._particleCount < particles.length) {
  1557. particle = particles[this._particleCount];
  1558. } else {
  1559. particle = new cc.Particle();
  1560. particles.push(particle);
  1561. }
  1562. } else {
  1563. particle = particles[this._particleCount];
  1564. }
  1565. this.initParticle(particle);
  1566. ++this._particleCount;
  1567. return true;
  1568. },
  1569. /**
  1570. * Initializes a particle
  1571. * @param {cc.Particle} particle
  1572. */
  1573. initParticle:function (particle) {
  1574. var locRandomMinus11 = cc.RANDOM_MINUS1_1;
  1575. // timeToLive
  1576. // no negative life. prevent division by 0
  1577. particle.timeToLive = this._life + this._lifeVar * locRandomMinus11();
  1578. particle.timeToLive = Math.max(0, particle.timeToLive);
  1579. // position
  1580. particle.pos.x = this._sourcePosition.x + this._posVar.x * locRandomMinus11();
  1581. particle.pos.y = this._sourcePosition.y + this._posVar.y * locRandomMinus11();
  1582. // Color
  1583. var start, end;
  1584. var locStartColor = this._startColor, locStartColorVar = this._startColorVar;
  1585. var locEndColor = this._endColor, locEndColorVar = this._endColorVar;
  1586. if (cc.renderContextType === cc.CANVAS) {
  1587. start = new cc.Color4F(
  1588. cc.clampf(locStartColor.r + locStartColorVar.r * locRandomMinus11(), 0, 1),
  1589. cc.clampf(locStartColor.g + locStartColorVar.g * locRandomMinus11(), 0, 1),
  1590. cc.clampf(locStartColor.b + locStartColorVar.b * locRandomMinus11(), 0, 1),
  1591. cc.clampf(locStartColor.a + locStartColorVar.a * locRandomMinus11(), 0, 1)
  1592. );
  1593. end = new cc.Color4F(
  1594. cc.clampf(locEndColor.r + locEndColorVar.r * locRandomMinus11(), 0, 1),
  1595. cc.clampf(locEndColor.g + locEndColorVar.g * locRandomMinus11(), 0, 1),
  1596. cc.clampf(locEndColor.b + locEndColorVar.b * locRandomMinus11(), 0, 1),
  1597. cc.clampf(locEndColor.a + locEndColorVar.a * locRandomMinus11(), 0, 1)
  1598. );
  1599. } else {
  1600. start = {
  1601. r: cc.clampf(locStartColor.r + locStartColorVar.r * locRandomMinus11(), 0, 1),
  1602. g: cc.clampf(locStartColor.g + locStartColorVar.g * locRandomMinus11(), 0, 1),
  1603. b: cc.clampf(locStartColor.b + locStartColorVar.b * locRandomMinus11(), 0, 1),
  1604. a: cc.clampf(locStartColor.a + locStartColorVar.a * locRandomMinus11(), 0, 1)
  1605. };
  1606. end = {
  1607. r: cc.clampf(locEndColor.r + locEndColorVar.r * locRandomMinus11(), 0, 1),
  1608. g: cc.clampf(locEndColor.g + locEndColorVar.g * locRandomMinus11(), 0, 1),
  1609. b: cc.clampf(locEndColor.b + locEndColorVar.b * locRandomMinus11(), 0, 1),
  1610. a: cc.clampf(locEndColor.a + locEndColorVar.a * locRandomMinus11(), 0, 1)
  1611. };
  1612. }
  1613. particle.color = start;
  1614. var locParticleDeltaColor = particle.deltaColor, locParticleTimeToLive = particle.timeToLive;
  1615. locParticleDeltaColor.r = (end.r - start.r) / locParticleTimeToLive;
  1616. locParticleDeltaColor.g = (end.g - start.g) / locParticleTimeToLive;
  1617. locParticleDeltaColor.b = (end.b - start.b) / locParticleTimeToLive;
  1618. locParticleDeltaColor.a = (end.a - start.a) / locParticleTimeToLive;
  1619. // size
  1620. var startS = this._startSize + this._startSizeVar * locRandomMinus11();
  1621. startS = Math.max(0, startS); // No negative value
  1622. particle.size = startS;
  1623. if (this._endSize === cc.PARTICLE_START_SIZE_EQUAL_TO_END_SIZE) {
  1624. particle.deltaSize = 0;
  1625. } else {
  1626. var endS = this._endSize + this._endSizeVar * locRandomMinus11();
  1627. endS = Math.max(0, endS); // No negative values
  1628. particle.deltaSize = (endS - startS) / locParticleTimeToLive;
  1629. }
  1630. // rotation
  1631. var startA = this._startSpin + this._startSpinVar * locRandomMinus11();
  1632. var endA = this._endSpin + this._endSpinVar * locRandomMinus11();
  1633. particle.rotation = startA;
  1634. particle.deltaRotation = (endA - startA) / locParticleTimeToLive;
  1635. // position
  1636. if (this._positionType == cc.PARTICLE_TYPE_FREE)
  1637. particle.startPos = this.convertToWorldSpace(this._pointZeroForParticle);
  1638. else if (this._positionType == cc.PARTICLE_TYPE_RELATIVE){
  1639. particle.startPos.x = this._position.x;
  1640. particle.startPos.y = this._position.y;
  1641. }
  1642. // direction
  1643. var a = cc.DEGREES_TO_RADIANS(this._angle + this._angleVar * locRandomMinus11());
  1644. // Mode Gravity: A
  1645. if (this._emitterMode === cc.PARTICLE_MODE_GRAVITY) {
  1646. var locModeA = this.modeA, locParticleModeA = particle.modeA;
  1647. var s = locModeA.speed + locModeA.speedVar * locRandomMinus11();
  1648. // direction
  1649. locParticleModeA.dir.x = Math.cos(a);
  1650. locParticleModeA.dir.y = Math.sin(a);
  1651. cc.pMultIn(locParticleModeA.dir, s);
  1652. // radial accel
  1653. locParticleModeA.radialAccel = locModeA.radialAccel + locModeA.radialAccelVar * locRandomMinus11();
  1654. // tangential accel
  1655. locParticleModeA.tangentialAccel = locModeA.tangentialAccel + locModeA.tangentialAccelVar * locRandomMinus11();
  1656. // rotation is dir
  1657. if(locModeA.rotationIsDir)
  1658. particle.rotation = -cc.RADIANS_TO_DEGREES(cc.pToAngle(locParticleModeA.dir));
  1659. } else {
  1660. // Mode Radius: B
  1661. var locModeB = this.modeB, locParitlceModeB = particle.modeB;
  1662. // Set the default diameter of the particle from the source position
  1663. var startRadius = locModeB.startRadius + locModeB.startRadiusVar * locRandomMinus11();
  1664. var endRadius = locModeB.endRadius + locModeB.endRadiusVar * locRandomMinus11();
  1665. locParitlceModeB.radius = startRadius;
  1666. locParitlceModeB.deltaRadius = (locModeB.endRadius === cc.PARTICLE_START_RADIUS_EQUAL_TO_END_RADIUS) ? 0 : (endRadius - startRadius) / locParticleTimeToLive;
  1667. locParitlceModeB.angle = a;
  1668. locParitlceModeB.degreesPerSecond = cc.DEGREES_TO_RADIANS(locModeB.rotatePerSecond + locModeB.rotatePerSecondVar * locRandomMinus11());
  1669. }
  1670. },
  1671. /**
  1672. * stop emitting particles. Running particles will continue to run until they die
  1673. */
  1674. stopSystem:function () {
  1675. this._isActive = false;
  1676. this._elapsed = this._duration;
  1677. this._emitCounter = 0;
  1678. },
  1679. /**
  1680. * Kill all living particles.
  1681. */
  1682. resetSystem:function () {
  1683. this._isActive = true;
  1684. this._elapsed = 0;
  1685. var locParticles = this._particles;
  1686. for (this._particleIdx = 0; this._particleIdx < this._particleCount; ++this._particleIdx)
  1687. locParticles[this._particleIdx].timeToLive = 0 ;
  1688. },
  1689. /**
  1690. * whether or not the system is full
  1691. * @return {Boolean}
  1692. */
  1693. isFull:function () {
  1694. return (this._particleCount >= this._totalParticles);
  1695. },
  1696. /**
  1697. * should be overridden by subclasses
  1698. * @param {cc.Particle} particle
  1699. * @param {cc.Point} newPosition
  1700. */
  1701. updateQuadWithParticle:function (particle, newPosition) {
  1702. var quad = null;
  1703. if (this._batchNode) {
  1704. var batchQuads = this._batchNode.getTextureAtlas().getQuads();
  1705. quad = batchQuads[this._atlasIndex + particle.atlasIndex];
  1706. this._batchNode.getTextureAtlas()._dirty = true;
  1707. } else
  1708. quad = this._quads[this._particleIdx];
  1709. var r, g, b, a;
  1710. if(this._opacityModifyRGB){
  1711. r = 0 | (particle.color.r * particle.color.a * 255);
  1712. g = 0 | (particle.color.g * particle.color.a * 255);
  1713. b = 0 | (particle.color.b * particle.color.a * 255);
  1714. a = 0 | (particle.color.a * 255);
  1715. }else{
  1716. r = 0 | (particle.color.r * 255);
  1717. g = 0 | (particle.color.g * 255);
  1718. b = 0 | (particle.color.b * 255);
  1719. a = 0 | (particle.color.a * 255);
  1720. }
  1721. var locColors = quad.bl.colors;
  1722. locColors.r = r;
  1723. locColors.g = g;
  1724. locColors.b = b;
  1725. locColors.a = a;
  1726. locColors = quad.br.colors;
  1727. locColors.r = r;
  1728. locColors.g = g;
  1729. locColors.b = b;
  1730. locColors.a = a;
  1731. locColors = quad.tl.colors;
  1732. locColors.r = r;
  1733. locColors.g = g;
  1734. locColors.b = b;
  1735. locColors.a = a;
  1736. locColors = quad.tr.colors;
  1737. locColors.r = r;
  1738. locColors.g = g;
  1739. locColors.b = b;
  1740. locColors.a = a;
  1741. // vertices
  1742. var size_2 = particle.size / 2;
  1743. if (particle.rotation) {
  1744. var x1 = -size_2;
  1745. var y1 = -size_2;
  1746. var x2 = size_2;
  1747. var y2 = size_2;
  1748. var x = newPosition.x;
  1749. var y = newPosition.y;
  1750. var rad = -cc.DEGREES_TO_RADIANS(particle.rotation);
  1751. var cr = Math.cos(rad);
  1752. var sr = Math.sin(rad);
  1753. var ax = x1 * cr - y1 * sr + x;
  1754. var ay = x1 * sr + y1 * cr + y;
  1755. var bx = x2 * cr - y1 * sr + x;
  1756. var by = x2 * sr + y1 * cr + y;
  1757. var cx = x2 * cr - y2 * sr + x;
  1758. var cy = x2 * sr + y2 * cr + y;
  1759. var dx = x1 * cr - y2 * sr + x;
  1760. var dy = x1 * sr + y2 * cr + y;
  1761. // bottom-left
  1762. quad.bl.vertices.x = ax;
  1763. quad.bl.vertices.y = ay;
  1764. // bottom-right vertex:
  1765. quad.br.vertices.x = bx;
  1766. quad.br.vertices.y = by;
  1767. // top-left vertex:
  1768. quad.tl.vertices.x = dx;
  1769. quad.tl.vertices.y = dy;
  1770. // top-right vertex:
  1771. quad.tr.vertices.x = cx;
  1772. quad.tr.vertices.y = cy;
  1773. } else {
  1774. // bottom-left vertex:
  1775. quad.bl.vertices.x = newPosition.x - size_2;
  1776. quad.bl.vertices.y = newPosition.y - size_2;
  1777. // bottom-right vertex:
  1778. quad.br.vertices.x = newPosition.x + size_2;
  1779. quad.br.vertices.y = newPosition.y - size_2;
  1780. // top-left vertex:
  1781. quad.tl.vertices.x = newPosition.x - size_2;
  1782. quad.tl.vertices.y = newPosition.y + size_2;
  1783. // top-right vertex:
  1784. quad.tr.vertices.x = newPosition.x + size_2;
  1785. quad.tr.vertices.y = newPosition.y + size_2;
  1786. }
  1787. },
  1788. /**
  1789. * should be overridden by subclasses
  1790. */
  1791. postStep:function () {
  1792. if (cc.renderContextType === cc.WEBGL) {
  1793. var gl = cc.renderContext;
  1794. gl.bindBuffer(gl.ARRAY_BUFFER, this._buffersVBO[0]);
  1795. gl.bufferData(gl.ARRAY_BUFFER, this._quadsArrayBuffer, gl.DYNAMIC_DRAW);
  1796. // Option 2: Data
  1797. // glBufferData(GL_ARRAY_BUFFER, sizeof(quads_[0]) * particleCount, quads_, GL_DYNAMIC_DRAW);
  1798. // Option 3: Orphaning + glMapBuffer
  1799. // glBufferData(GL_ARRAY_BUFFER, sizeof(m_pQuads[0])*m_uTotalParticles, NULL, GL_STREAM_DRAW);
  1800. // void *buf = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
  1801. // memcpy(buf, m_pQuads, sizeof(m_pQuads[0])*m_uTotalParticles);
  1802. // glUnmapBuffer(GL_ARRAY_BUFFER);
  1803. //cc.CHECK_GL_ERROR_DEBUG();
  1804. }
  1805. },
  1806. /**
  1807. * update emitter's status
  1808. * @override
  1809. * @param {Number} dt delta time
  1810. */
  1811. update:function (dt) {
  1812. if (this._isActive && this._emissionRate) {
  1813. var rate = 1.0 / this._emissionRate;
  1814. //issue #1201, prevent bursts of particles, due to too high emitCounter
  1815. if (this._particleCount < this._totalParticles)
  1816. this._emitCounter += dt;
  1817. while ((this._particleCount < this._totalParticles) && (this._emitCounter > rate)) {
  1818. this.addParticle();
  1819. this._emitCounter -= rate;
  1820. }
  1821. this._elapsed += dt;
  1822. if (this._duration != -1 && this._duration < this._elapsed)
  1823. this.stopSystem();
  1824. }
  1825. this._particleIdx = 0;
  1826. var currentPosition = cc.Particle.TemporaryPoints[0];
  1827. if (this._positionType == cc.PARTICLE_TYPE_FREE) {
  1828. cc.pIn(currentPosition, this.convertToWorldSpace(this._pointZeroForParticle));
  1829. } else if (this._positionType == cc.PARTICLE_TYPE_RELATIVE) {
  1830. currentPosition.x = this._position.x;
  1831. currentPosition.y = this._position.y;
  1832. }
  1833. if (this._visible) {
  1834. // Used to reduce memory allocation / creation within the loop
  1835. var tpa = cc.Particle.TemporaryPoints[1],
  1836. tpb = cc.Particle.TemporaryPoints[2],
  1837. tpc = cc.Particle.TemporaryPoints[3];
  1838. var locParticles = this._particles;
  1839. while (this._particleIdx < this._particleCount) {
  1840. // Reset the working particles
  1841. cc.pZeroIn(tpa);
  1842. cc.pZeroIn(tpb);
  1843. cc.pZeroIn(tpc);
  1844. var selParticle = locParticles[this._particleIdx];
  1845. // life
  1846. selParticle.timeToLive -= dt;
  1847. if (selParticle.timeToLive > 0) {
  1848. // Mode A: gravity, direction, tangential accel & radial accel
  1849. if (this._emitterMode == cc.PARTICLE_MODE_GRAVITY) {
  1850. var tmp = tpc, radial = tpa, tangential = tpb;
  1851. // radial acceleration
  1852. if (selParticle.pos.x || selParticle.pos.y) {
  1853. cc.pIn(radial, selParticle.pos);
  1854. cc.pNormalizeIn(radial);
  1855. } else {
  1856. cc.pZeroIn(radial);
  1857. }
  1858. cc.pIn(tangential, radial);
  1859. cc.pMultIn(radial, selParticle.modeA.radialAccel);
  1860. // tangential acceleration
  1861. var newy = tangential.x;
  1862. tangential.x = -tangential.y;
  1863. tangential.y = newy;
  1864. cc.pMultIn(tangential, selParticle.modeA.tangentialAccel);
  1865. cc.pIn(tmp, radial);
  1866. cc.pAddIn(tmp, tangential);
  1867. cc.pAddIn(tmp, this.modeA.gravity);
  1868. cc.pMultIn(tmp, dt);
  1869. cc.pAddIn(selParticle.modeA.dir, tmp);
  1870. cc.pIn(tmp, selParticle.modeA.dir);
  1871. cc.pMultIn(tmp, dt);
  1872. cc.pAddIn(selParticle.pos, tmp);
  1873. } else {
  1874. // Mode B: radius movement
  1875. var selModeB = selParticle.modeB;
  1876. // Update the angle and radius of the particle.
  1877. selModeB.angle += selModeB.degreesPerSecond * dt;
  1878. selModeB.radius += selModeB.deltaRadius * dt;
  1879. selParticle.pos.x = -Math.cos(selModeB.angle) * selModeB.radius;
  1880. selParticle.pos.y = -Math.sin(selModeB.angle) * selModeB.radius;
  1881. }
  1882. // color
  1883. if (!this._dontTint) {
  1884. selParticle.color.r += (selParticle.deltaColor.r * dt);
  1885. selParticle.color.g += (selParticle.deltaColor.g * dt);
  1886. selParticle.color.b += (selParticle.deltaColor.b * dt);
  1887. selParticle.color.a += (selParticle.deltaColor.a * dt);
  1888. selParticle.isChangeColor = true;
  1889. }
  1890. // size
  1891. selParticle.size += (selParticle.deltaSize * dt);
  1892. selParticle.size = Math.max(0, selParticle.size);
  1893. // angle
  1894. selParticle.rotation += (selParticle.deltaRotation * dt);
  1895. //
  1896. // update values in quad
  1897. //
  1898. var newPos = tpa;
  1899. if (this._positionType == cc.PARTICLE_TYPE_FREE || this._positionType == cc.PARTICLE_TYPE_RELATIVE) {
  1900. var diff = tpb;
  1901. cc.pIn(diff, currentPosition);
  1902. cc.pSubIn(diff, selParticle.startPos);
  1903. cc.pIn(newPos, selParticle.pos);
  1904. cc.pSubIn(newPos, diff);
  1905. } else {
  1906. cc.pIn(newPos, selParticle.pos);
  1907. }
  1908. // translate newPos to correct position, since matrix transform isn't performed in batchnode
  1909. // don't update the particle with the new position information, it will interfere with the radius and tangential calculations
  1910. if (this._batchNode) {
  1911. newPos.x += this._position.x;
  1912. newPos.y += this._position.y;
  1913. }
  1914. if (cc.renderContextType == cc.WEBGL) {
  1915. // IMPORTANT: newPos may not be used as a reference here! (as it is just the temporary tpa point)
  1916. // the implementation of updateQuadWithParticle must use
  1917. // the x and y values directly
  1918. this.updateQuadWithParticle(selParticle, newPos);
  1919. } else {
  1920. cc.pIn(selParticle.drawPos, newPos);
  1921. }
  1922. //updateParticleImp(self, updateParticleSel, p, newPos);
  1923. // update particle counter
  1924. ++this._particleIdx;
  1925. } else {
  1926. // life < 0
  1927. var currentIndex = selParticle.atlasIndex;
  1928. if(this._particleIdx !== this._particleCount -1){
  1929. var deadParticle = locParticles[this._particleIdx];
  1930. locParticles[this._particleIdx] = locParticles[this._particleCount -1];
  1931. locParticles[this._particleCount -1] = deadParticle;
  1932. }
  1933. if (this._batchNode) {
  1934. //disable the switched particle
  1935. this._batchNode.disableParticle(this._atlasIndex + currentIndex);
  1936. //switch indexes
  1937. locParticles[this._particleCount - 1].atlasIndex = currentIndex;
  1938. }
  1939. --this._particleCount;
  1940. if (this._particleCount == 0 && this._isAutoRemoveOnFinish) {
  1941. this.unscheduleUpdate();
  1942. this._parent.removeChild(this, true);
  1943. return;
  1944. }
  1945. }
  1946. }
  1947. this._transformSystemDirty = false;
  1948. }
  1949. if (!this._batchNode)
  1950. this.postStep();
  1951. },
  1952. updateWithNoTime:function () {
  1953. this.update(0);
  1954. },
  1955. /**
  1956. * return the string found by key in dict.
  1957. * @param {string} key
  1958. * @param {object} dict
  1959. * @return {String} "" if not found; return the string if found.
  1960. * @private
  1961. */
  1962. _valueForKey:function (key, dict) {
  1963. if (dict) {
  1964. var pString = dict[key];
  1965. return pString != null ? pString : "";
  1966. }
  1967. return "";
  1968. },
  1969. _updateBlendFunc:function () {
  1970. if(this._batchNode){
  1971. cc.log("Can't change blending functions when the particle is being batched");
  1972. return;
  1973. }
  1974. var locTexture = this._texture;
  1975. if (locTexture && locTexture instanceof cc.Texture2D) {
  1976. this._opacityModifyRGB = false;
  1977. var locBlendFunc = this._blendFunc;
  1978. if (locBlendFunc.src == cc.BLEND_SRC && locBlendFunc.dst == cc.BLEND_DST) {
  1979. if (locTexture.hasPremultipliedAlpha()) {
  1980. this._opacityModifyRGB = true;
  1981. } else {
  1982. locBlendFunc.src = gl.SRC_ALPHA;
  1983. locBlendFunc.dst = gl.ONE_MINUS_SRC_ALPHA;
  1984. }
  1985. }
  1986. }
  1987. },
  1988. clone:function () {
  1989. var retParticle = new cc.ParticleSystem();
  1990. // self, not super
  1991. if (retParticle.initWithTotalParticles(this._totalParticles)) {
  1992. // angle
  1993. retParticle._angle = this._angle;
  1994. retParticle._angleVar = this._angleVar;
  1995. // duration
  1996. retParticle._duration = this._duration;
  1997. // blend function
  1998. retParticle._blendFunc.src = this._blendFunc.src;
  1999. retParticle._blendFunc.dst = this._blendFunc.dst;
  2000. // color
  2001. var particleStartColor = retParticle._startColor, locStartColor = this._startColor;
  2002. particleStartColor.r = locStartColor.r;
  2003. particleStartColor.g = locStartColor.g;
  2004. particleStartColor.b = locStartColor.b;
  2005. particleStartColor.a = locStartColor.a;
  2006. var particleStartColorVar = retParticle._startColorVar, locStartColorVar = this._startColorVar;
  2007. particleStartColorVar.r = locStartColorVar.r;
  2008. particleStartColorVar.g = locStartColorVar.g;
  2009. particleStartColorVar.b = locStartColorVar.b;
  2010. particleStartColorVar.a = locStartColorVar.a;
  2011. var particleEndColor = retParticle._endColor, locEndColor = this._endColor;
  2012. particleEndColor.r = locEndColor.r;
  2013. particleEndColor.g = locEndColor.g;
  2014. particleEndColor.b = locEndColor.b;
  2015. particleEndColor.a = locEndColor.a;
  2016. var particleEndColorVar = retParticle._endColorVar, locEndColorVar = this._endColorVar;
  2017. particleEndColorVar.r = locEndColorVar.r;
  2018. particleEndColorVar.g = locEndColorVar.g;
  2019. particleEndColorVar.b = locEndColorVar.b;
  2020. particleEndColorVar.a = locEndColorVar.a;
  2021. // particle size
  2022. retParticle._startSize = this._startSize;
  2023. retParticle._startSizeVar = this._startSizeVar;
  2024. retParticle._endSize = this._endSize;
  2025. retParticle._endSizeVar = this._endSizeVar;
  2026. // position
  2027. retParticle.setPosition(this._position.x, this._position.y);
  2028. retParticle._posVar.x = this._posVar.x;
  2029. retParticle._posVar.y = this._posVar.y;
  2030. // Spinning
  2031. retParticle._startSpin = this._startSpin;
  2032. retParticle._startSpinVar = this._startSpinVar;
  2033. retParticle._endSpin = this._endSpin;
  2034. retParticle._endSpinVar = this._endSpinVar;
  2035. retParticle._emitterMode = this._emitterMode;
  2036. // Mode A: Gravity + tangential accel + radial accel
  2037. if (this._emitterMode == cc.PARTICLE_MODE_GRAVITY) {
  2038. var particleModeA = retParticle.modeA, locModeA = this.modeA;
  2039. // gravity
  2040. particleModeA.gravity.x = locModeA.gravity.x;
  2041. particleModeA.gravity.y = locModeA.gravity.y;
  2042. // speed
  2043. particleModeA.speed = locModeA.speed;
  2044. particleModeA.speedVar = locModeA.speedVar;
  2045. // radial acceleration
  2046. particleModeA.radialAccel = locModeA.radialAccel;
  2047. particleModeA.radialAccelVar = locModeA.radialAccelVar;
  2048. // tangential acceleration
  2049. particleModeA.tangentialAccel = locModeA.tangentialAccel;
  2050. particleModeA.tangentialAccelVar = locModeA.tangentialAccelVar;
  2051. } else if (this._emitterMode == cc.PARTICLE_MODE_RADIUS) {
  2052. var particleModeB = retParticle.modeB, locModeB = this.modeB;
  2053. // or Mode B: radius movement
  2054. particleModeB.startRadius = locModeB.startRadius;
  2055. particleModeB.startRadiusVar = locModeB.startRadiusVar;
  2056. particleModeB.endRadius = locModeB.endRadius;
  2057. particleModeB.endRadiusVar = locModeB.endRadiusVar;
  2058. particleModeB.rotatePerSecond = locModeB.rotatePerSecond;
  2059. particleModeB.rotatePerSecondVar = locModeB.rotatePerSecondVar;
  2060. }
  2061. // life span
  2062. retParticle._life = this._life;
  2063. retParticle._lifeVar = this._lifeVar;
  2064. // emission Rate
  2065. retParticle._emissionRate = this._emissionRate;
  2066. //don't get the internal texture if a batchNode is used
  2067. if (!this._batchNode) {
  2068. // Set a compatible default for the alpha transfer
  2069. retParticle._opacityModifyRGB = this._opacityModifyRGB;
  2070. // texture
  2071. retParticle._texture = this._texture;
  2072. }
  2073. }
  2074. return retParticle;
  2075. },
  2076. /**
  2077. * <p> Sets a new CCSpriteFrame as particle.</br>
  2078. * WARNING: this method is experimental. Use setTextureWithRect instead.
  2079. * </p>
  2080. * @param {cc.SpriteFrame} spriteFrame
  2081. */
  2082. setDisplayFrame:function (spriteFrame) {
  2083. var locOffset = spriteFrame.getOffsetInPixels();
  2084. if(locOffset.x != 0 || locOffset.y != 0)
  2085. cc.log("cc.ParticleSystem.setDisplayFrame(): QuadParticle only supports SpriteFrames with no offsets");
  2086. // update texture before updating texture rect
  2087. if (cc.renderContextType === cc.WEBGL)
  2088. if (!this._texture || spriteFrame.getTexture()._webTextureObj != this._texture._webTextureObj)
  2089. this.setTexture(spriteFrame.getTexture());
  2090. },
  2091. /**
  2092. * Sets a new texture with a rect. The rect is in Points.
  2093. * @param {cc.Texture2D} texture
  2094. * @param {cc.Rect} rect
  2095. */
  2096. setTextureWithRect:function (texture, rect) {
  2097. var locTexture = this._texture;
  2098. if (cc.renderContextType === cc.WEBGL) {
  2099. // Only update the texture if is different from the current one
  2100. if ((!locTexture || texture._webTextureObj != locTexture._webTextureObj) && (locTexture != texture)) {
  2101. this._texture = texture;
  2102. this._updateBlendFunc();
  2103. }
  2104. } else {
  2105. if ((!locTexture || texture != locTexture) && (locTexture != texture)) {
  2106. this._texture = texture;
  2107. this._updateBlendFunc();
  2108. }
  2109. }
  2110. this._pointRect = rect;
  2111. this.initTexCoordsWithRect(rect);
  2112. },
  2113. /**
  2114. * draw particle
  2115. * @param {CanvasRenderingContext2D} ctx CanvasContext
  2116. * @override
  2117. */
  2118. draw:function (ctx) {
  2119. if(!this._textureLoaded || this._batchNode) // draw should not be called when added to a particleBatchNode
  2120. return;
  2121. if (cc.renderContextType === cc.CANVAS)
  2122. this._drawForCanvas(ctx);
  2123. else
  2124. this._drawForWebGL(ctx);
  2125. cc.g_NumberOfDraws++;
  2126. },
  2127. _drawForCanvas:function (ctx) {
  2128. var context = ctx || cc.renderContext;
  2129. context.save();
  2130. if (this.isBlendAdditive())
  2131. context.globalCompositeOperation = 'lighter';
  2132. else
  2133. context.globalCompositeOperation = 'source-over';
  2134. for (var i = 0; i < this._particleCount; i++) {
  2135. var particle = this._particles[i];
  2136. var lpx = (0 | (particle.size * 0.5));
  2137. if (this._drawMode == cc.PARTICLE_TEXTURE_MODE) {
  2138. var element = this._texture.getHtmlElementObj();
  2139. // Delay drawing until the texture is fully loaded by the browser
  2140. if (!element.width || !element.height)
  2141. continue;
  2142. context.save();
  2143. context.globalAlpha = particle.color.a;
  2144. context.translate((0 | particle.drawPos.x), -(0 | particle.drawPos.y));
  2145. var size = Math.floor(particle.size / 4) * 4;
  2146. var w = this._pointRect.width;
  2147. var h = this._pointRect.height;
  2148. context.scale(
  2149. Math.max((1 / w) * size, 0.000001),
  2150. Math.max((1 / h) * size, 0.000001)
  2151. );
  2152. if (particle.rotation)
  2153. context.rotate(cc.DEGREES_TO_RADIANS(particle.rotation));
  2154. context.translate(-(0 | (w / 2)), -(0 | (h / 2)));
  2155. if (particle.isChangeColor) {
  2156. var cacheTextureForColor = cc.TextureCache.getInstance().getTextureColors(element);
  2157. if (cacheTextureForColor) {
  2158. // Create another cache for the tinted version
  2159. // This speeds up things by a fair bit
  2160. if (!cacheTextureForColor.tintCache) {
  2161. cacheTextureForColor.tintCache = document.createElement('canvas');
  2162. cacheTextureForColor.tintCache.width = element.width;
  2163. cacheTextureForColor.tintCache.height = element.height;
  2164. }
  2165. cc.generateTintImage(element, cacheTextureForColor, particle.color, this._pointRect, cacheTextureForColor.tintCache);
  2166. element = cacheTextureForColor.tintCache;
  2167. }
  2168. }
  2169. context.drawImage(element, 0, 0);
  2170. context.restore();
  2171. } else {
  2172. context.save();
  2173. context.globalAlpha = particle.color.a;
  2174. context.translate(0 | particle.drawPos.x, -(0 | particle.drawPos.y));
  2175. if (this._shapeType == cc.PARTICLE_STAR_SHAPE) {
  2176. if (particle.rotation)
  2177. context.rotate(cc.DEGREES_TO_RADIANS(particle.rotation));
  2178. cc.drawingUtil.drawStar(context, lpx, particle.color);
  2179. } else
  2180. cc.drawingUtil.drawColorBall(context, lpx, particle.color);
  2181. context.restore();
  2182. }
  2183. }
  2184. context.restore();
  2185. },
  2186. _drawForWebGL:function (ctx) {
  2187. if(!this._texture)
  2188. return;
  2189. var gl = ctx || cc.renderContext;
  2190. this._shaderProgram.use();
  2191. this._shaderProgram.setUniformForModelViewAndProjectionMatrixWithMat4();
  2192. cc.glBindTexture2D(this._texture);
  2193. cc.glBlendFuncForParticle(this._blendFunc.src, this._blendFunc.dst);
  2194. //cc.Assert(this._particleIdx == this._particleCount, "Abnormal error in particle quad");
  2195. //
  2196. // Using VBO without VAO
  2197. //
  2198. cc.glEnableVertexAttribs(cc.VERTEX_ATTRIB_FLAG_POS_COLOR_TEX);
  2199. gl.bindBuffer(gl.ARRAY_BUFFER, this._buffersVBO[0]);
  2200. gl.vertexAttribPointer(cc.VERTEX_ATTRIB_POSITION, 3, gl.FLOAT, false, 24, 0); // vertices
  2201. gl.vertexAttribPointer(cc.VERTEX_ATTRIB_COLOR, 4, gl.UNSIGNED_BYTE, true, 24, 12); // colors
  2202. gl.vertexAttribPointer(cc.VERTEX_ATTRIB_TEX_COORDS, 2, gl.FLOAT, false, 24, 16); // tex coords
  2203. gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._buffersVBO[1]);
  2204. gl.drawElements(gl.TRIANGLES, this._particleIdx * 6, gl.UNSIGNED_SHORT, 0);
  2205. },
  2206. /**
  2207. * listen the event that coming to foreground on Android
  2208. * @param {cc.Class} obj
  2209. */
  2210. listenBackToForeground:function (obj) {
  2211. if (cc.TEXTURE_ATLAS_USE_VAO)
  2212. this._setupVBOandVAO();
  2213. else
  2214. this._setupVBO();
  2215. },
  2216. _setupVBOandVAO:function () {
  2217. //Not support on WebGL
  2218. /*if (cc.renderContextType == cc.CANVAS) {
  2219. return;
  2220. }*/
  2221. //NOT SUPPORTED
  2222. /*glGenVertexArrays(1, this._VAOname);
  2223. glBindVertexArray(this._VAOname);
  2224. var kQuadSize = sizeof(m_pQuads[0].bl);
  2225. glGenBuffers(2, this._buffersVBO[0]);
  2226. glBindBuffer(GL_ARRAY_BUFFER, this._buffersVBO[0]);
  2227. glBufferData(GL_ARRAY_BUFFER, sizeof(this._quads[0]) * this._totalParticles, this._quads, GL_DYNAMIC_DRAW);
  2228. // vertices
  2229. glEnableVertexAttribArray(kCCVertexAttrib_Position);
  2230. glVertexAttribPointer(kCCVertexAttrib_Position, 2, GL_FLOAT, GL_FALSE, kQuadSize, offsetof(ccV3F_C4B_T2F, vertices));
  2231. // colors
  2232. glEnableVertexAttribArray(kCCVertexAttrib_Color);
  2233. glVertexAttribPointer(kCCVertexAttrib_Color, 4, GL_UNSIGNED_BYTE, GL_TRUE, kQuadSize, offsetof(ccV3F_C4B_T2F, colors));
  2234. // tex coords
  2235. glEnableVertexAttribArray(kCCVertexAttrib_TexCoords);
  2236. glVertexAttribPointer(kCCVertexAttrib_TexCoords, 2, GL_FLOAT, GL_FALSE, kQuadSize, offsetof(ccV3F_C4B_T2F, texCoords));
  2237. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this._buffersVBO[1]);
  2238. glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(m_pIndices[0]) * m_uTotalParticles * 6, m_pIndices, GL_STATIC_DRAW);
  2239. glBindVertexArray(0);
  2240. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
  2241. glBindBuffer(GL_ARRAY_BUFFER, 0);
  2242. CHECK_GL_ERROR_DEBUG();*/
  2243. },
  2244. _setupVBO:function () {
  2245. if (cc.renderContextType == cc.CANVAS)
  2246. return;
  2247. var gl = cc.renderContext;
  2248. //gl.deleteBuffer(this._buffersVBO[0]);
  2249. this._buffersVBO[0] = gl.createBuffer();
  2250. gl.bindBuffer(gl.ARRAY_BUFFER, this._buffersVBO[0]);
  2251. gl.bufferData(gl.ARRAY_BUFFER, this._quadsArrayBuffer, gl.DYNAMIC_DRAW);
  2252. this._buffersVBO[1] = gl.createBuffer();
  2253. gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._buffersVBO[1]);
  2254. gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this._indices, gl.STATIC_DRAW);
  2255. //cc.CHECK_GL_ERROR_DEBUG();
  2256. },
  2257. _allocMemory:function () {
  2258. if (cc.renderContextType === cc.CANVAS)
  2259. return true;
  2260. //cc.Assert((!this._quads && !this._indices), "Memory already allocated");
  2261. if(this._batchNode){
  2262. cc.log("cc.ParticleSystem._allocMemory(): Memory should not be allocated when not using batchNode");
  2263. return false;
  2264. }
  2265. var quadSize = cc.V3F_C4B_T2F_Quad.BYTES_PER_ELEMENT;
  2266. var totalParticles = this._totalParticles;
  2267. var locQuads = this._quads;
  2268. locQuads.length = 0;
  2269. this._indices = new Uint16Array(totalParticles * 6);
  2270. var locQuadsArrayBuffer = new ArrayBuffer(quadSize * totalParticles);
  2271. for (var i = 0; i < totalParticles; i++)
  2272. locQuads[i] = new cc.V3F_C4B_T2F_Quad(null, null, null, null, locQuadsArrayBuffer, i * quadSize);
  2273. if (!locQuads || !this._indices) {
  2274. cc.log("cocos2d: Particle system: not enough memory");
  2275. return false;
  2276. }
  2277. this._quadsArrayBuffer = locQuadsArrayBuffer;
  2278. return true;
  2279. }
  2280. });
  2281. /**
  2282. * <p> return the string found by key in dict. <br/>
  2283. * This plist files can be create manually or with Particle Designer:<br/>
  2284. * http://particledesigner.71squared.com/<br/>
  2285. * </p>
  2286. * @param {String} plistFile
  2287. * @return {cc.ParticleSystem}
  2288. */
  2289. cc.ParticleSystem.create = function (plistFile) {
  2290. var ret = new cc.ParticleSystem();
  2291. if (!plistFile || typeof(plistFile) === "number") {
  2292. var ton = plistFile || 100;
  2293. ret.setDrawMode(cc.PARTICLE_TEXTURE_MODE);
  2294. ret.initWithTotalParticles(ton);
  2295. return ret;
  2296. }
  2297. if (ret && ret.initWithFile(plistFile))
  2298. return ret;
  2299. return null;
  2300. };
  2301. /**
  2302. * create a system with a fixed number of particles
  2303. * @param {Number} number_of_particles
  2304. * @return {cc.ParticleSystem}
  2305. */
  2306. cc.ParticleSystem.createWithTotalParticles = function (number_of_particles) {
  2307. //emitter.initWithTotalParticles(number_of_particles);
  2308. var particle = new cc.ParticleSystem();
  2309. if (particle && particle.initWithTotalParticles(number_of_particles))
  2310. return particle;
  2311. return null;
  2312. };
  2313. // Different modes
  2314. /**
  2315. * Mode A:Gravity + Tangential Accel + Radial Accel
  2316. * @Class
  2317. * @Construct
  2318. * @param {cc.Point} [gravity=] Gravity value.
  2319. * @param {Number} [speed=0] speed of each particle.
  2320. * @param {Number} [speedVar=0] speed variance of each particle.
  2321. * @param {Number} [tangentialAccel=0] tangential acceleration of each particle.
  2322. * @param {Number} [tangentialAccelVar=0] tangential acceleration variance of each particle.
  2323. * @param {Number} [radialAccel=0] radial acceleration of each particle.
  2324. * @param {Number} [radialAccelVar=0] radial acceleration variance of each particle.
  2325. * @param {boolean} [rotationIsDir=false]
  2326. */
  2327. cc.ParticleSystem.ModeA = function (gravity, speed, speedVar, tangentialAccel, tangentialAccelVar, radialAccel, radialAccelVar, rotationIsDir) {
  2328. /** Gravity value. Only available in 'Gravity' mode. */
  2329. this.gravity = gravity ? gravity : cc.PointZero();
  2330. /** speed of each particle. Only available in 'Gravity' mode. */
  2331. this.speed = speed || 0;
  2332. /** speed variance of each particle. Only available in 'Gravity' mode. */
  2333. this.speedVar = speedVar || 0;
  2334. /** tangential acceleration of each particle. Only available in 'Gravity' mode. */
  2335. this.tangentialAccel = tangentialAccel || 0;
  2336. /** tangential acceleration variance of each particle. Only available in 'Gravity' mode. */
  2337. this.tangentialAccelVar = tangentialAccelVar || 0;
  2338. /** radial acceleration of each particle. Only available in 'Gravity' mode. */
  2339. this.radialAccel = radialAccel || 0;
  2340. /** radial acceleration variance of each particle. Only available in 'Gravity' mode. */
  2341. this.radialAccelVar = radialAccelVar || 0;
  2342. /** set the rotation of each particle to its direction Only available in 'Gravity' mode. */
  2343. this.rotationIsDir = rotationIsDir || false;
  2344. };
  2345. /**
  2346. * Mode B: circular movement (gravity, radial accel and tangential accel don't are not used in this mode)
  2347. * @Class
  2348. * @Construct
  2349. * @param {Number} startRadius The starting radius of the particles.
  2350. * @param {Number} startRadiusVar The starting radius variance of the particles.
  2351. * @param {Number} endRadius The ending radius of the particles.
  2352. * @param {Number} endRadiusVar The ending radius variance of the particles.
  2353. * @param {Number} rotatePerSecond Number of degress to rotate a particle around the source pos per second.
  2354. * @param {Number} rotatePerSecondVar Variance in degrees for rotatePerSecond.
  2355. */
  2356. cc.ParticleSystem.ModeB = function (startRadius, startRadiusVar, endRadius, endRadiusVar, rotatePerSecond, rotatePerSecondVar) {
  2357. /** The starting radius of the particles. Only available in 'Radius' mode. */
  2358. this.startRadius = startRadius || 0;
  2359. /** The starting radius variance of the particles. Only available in 'Radius' mode. */
  2360. this.startRadiusVar = startRadiusVar || 0;
  2361. /** The ending radius of the particles. Only available in 'Radius' mode. */
  2362. this.endRadius = endRadius || 0;
  2363. /** The ending radius variance of the particles. Only available in 'Radius' mode. */
  2364. this.endRadiusVar = endRadiusVar || 0;
  2365. /** Number of degress to rotate a particle around the source pos per second. Only available in 'Radius' mode. */
  2366. this.rotatePerSecond = rotatePerSecond || 0;
  2367. /** Variance in degrees for rotatePerSecond. Only available in 'Radius' mode. */
  2368. this.rotatePerSecondVar = rotatePerSecondVar || 0;
  2369. };