CCParticleSystem.cpp 47 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490
  1. /****************************************************************************
  2. Copyright (c) 2008-2010 Ricardo Quesada
  3. Copyright (c) 2010-2012 cocos2d-x.org
  4. Copyright (c) 2011 Zynga Inc.
  5. Copyright (c) 2013-2017 Chukong Technologies Inc.
  6. http://www.cocos2d-x.org
  7. Permission is hereby granted, free of charge, to any person obtaining a copy
  8. of this software and associated documentation files (the "Software"), to deal
  9. in the Software without restriction, including without limitation the rights
  10. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  11. copies of the Software, and to permit persons to whom the Software is
  12. furnished to do so, subject to the following conditions:
  13. The above copyright notice and this permission notice shall be included in
  14. all copies or substantial portions of the Software.
  15. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  21. THE SOFTWARE.
  22. ****************************************************************************/
  23. // ideas taken from:
  24. // . The ocean spray in your face [Jeff Lander]
  25. // http://www.double.co.nz/dust/col0798.pdf
  26. // . Building an Advanced Particle System [John van der Burg]
  27. // http://www.gamasutra.com/features/20000623/vanderburg_01.htm
  28. // . LOVE game engine
  29. // http://love2d.org/
  30. //
  31. //
  32. // Radius mode support, from 71 squared
  33. // http://particledesigner.71squared.com/
  34. //
  35. // IMPORTANT: Particle Designer is supported by cocos2d, but
  36. // 'Radius Mode' in Particle Designer uses a fixed emit rate of 30 hz. Since that can't be guaranteed in cocos2d,
  37. // cocos2d uses a another approach, but the results are almost identical.
  38. //
  39. #include "2d/CCParticleSystem.h"
  40. #include <string>
  41. #include "2d/CCParticleBatchNode.h"
  42. #include "renderer/CCTextureAtlas.h"
  43. #include "base/base64.h"
  44. #include "base/ZipUtils.h"
  45. #include "base/CCDirector.h"
  46. #include "base/CCProfiling.h"
  47. #include "base/ccUTF8.h"
  48. #include "renderer/CCTextureCache.h"
  49. #include "platform/CCFileUtils.h"
  50. #include "common/CocosConfig.h"
  51. using namespace std;
  52. NS_CC_BEGIN
  53. // ideas taken from:
  54. // . The ocean spray in your face [Jeff Lander]
  55. // http://www.double.co.nz/dust/col0798.pdf
  56. // . Building an Advanced Particle System [John van der Burg]
  57. // http://www.gamasutra.com/features/20000623/vanderburg_01.htm
  58. // . LOVE game engine
  59. // http://love2d.org/
  60. //
  61. //
  62. // Radius mode support, from 71 squared
  63. // http://particledesigner.71squared.com/
  64. //
  65. // IMPORTANT: Particle Designer is supported by cocos2d, but
  66. // 'Radius Mode' in Particle Designer uses a fixed emit rate of 30 hz. Since that can't be guaranteed in cocos2d,
  67. // cocos2d uses a another approach, but the results are almost identical.
  68. //
  69. inline void normalize_point(float x, float y, particle_point* out)
  70. {
  71. float n = x * x + y * y;
  72. // Already normalized.
  73. if (n == 1.0f)
  74. return;
  75. n = sqrt(n);
  76. // Too close to zero.
  77. if (n < MATH_TOLERANCE)
  78. return;
  79. n = 1.0f / n;
  80. out->x = x * n;
  81. out->y = y * n;
  82. }
  83. /**
  84. A more effect random number getter function, get from ejoy2d.
  85. */
  86. inline static float RANDOM_M11(unsigned int *seed) {
  87. *seed = *seed * 134775813 + 1;
  88. union {
  89. uint32_t d;
  90. float f;
  91. } u;
  92. u.d = (((uint32_t)(*seed) & 0x7fff) << 8) | 0x40000000;
  93. return u.f - 3.0f;
  94. }
  95. ParticleData::ParticleData()
  96. {
  97. memset(this, 0, sizeof(ParticleData));
  98. }
  99. bool ParticleData::init(int count)
  100. {
  101. maxCount = count;
  102. posx= (float*)malloc(count * sizeof(float));
  103. posy= (float*)malloc(count * sizeof(float));
  104. startPosX= (float*)malloc(count * sizeof(float));
  105. startPosY= (float*)malloc(count * sizeof(float));
  106. startRoation= (float*)malloc(count * sizeof(float));
  107. colorR= (float*)malloc(count * sizeof(float));
  108. colorG= (float*)malloc(count * sizeof(float));
  109. colorB= (float*)malloc(count * sizeof(float));
  110. colorA= (float*)malloc(count * sizeof(float));
  111. deltaColorR= (float*)malloc(count * sizeof(float));
  112. deltaColorG= (float*)malloc(count * sizeof(float));
  113. deltaColorB= (float*)malloc(count * sizeof(float));
  114. deltaColorA= (float*)malloc(count * sizeof(float));
  115. size= (float*)malloc(count * sizeof(float));
  116. deltaSize= (float*)malloc(count * sizeof(float));
  117. startSize= (float*)malloc(count * sizeof(float));
  118. deltaSizeAllLife= (float*)malloc(count * sizeof(float));
  119. rotation= (float*)malloc(count * sizeof(float));
  120. deltaRotation= (float*)malloc(count * sizeof(float));
  121. timeToLive= (float*)malloc(count * sizeof(float));
  122. life= (float*)malloc(count * sizeof(float));
  123. atlasIndex= (unsigned int*)malloc(count * sizeof(unsigned int));
  124. modeA.dirX= (float*)malloc(count * sizeof(float));
  125. modeA.dirY= (float*)malloc(count * sizeof(float));
  126. modeA.radialAccel= (float*)malloc(count * sizeof(float));
  127. modeA.tangentialAccel= (float*)malloc(count * sizeof(float));
  128. modeB.angle= (float*)malloc(count * sizeof(float));
  129. modeB.degreesPerSecond= (float*)malloc(count * sizeof(float));
  130. modeB.deltaRadius= (float*)malloc(count * sizeof(float));
  131. modeB.radius= (float*)malloc(count * sizeof(float));
  132. return posx && posy && startPosY && startPosX && startRoation && colorR && colorG && colorB && colorA &&
  133. deltaColorR && deltaColorG && deltaColorB && deltaColorA && size && startSize && deltaSizeAllLife && deltaSize &&
  134. rotation && deltaRotation && timeToLive && life && atlasIndex && modeA.dirX && modeA.dirY &&
  135. modeA.radialAccel && modeA.tangentialAccel && modeB.angle && modeB.degreesPerSecond &&
  136. modeB.deltaRadius && modeB.radius;
  137. }
  138. void ParticleData::release()
  139. {
  140. CC_SAFE_FREE(posx);
  141. CC_SAFE_FREE(posy);
  142. CC_SAFE_FREE(startPosX);
  143. CC_SAFE_FREE(startRoation);
  144. CC_SAFE_FREE(startPosY);
  145. CC_SAFE_FREE(colorR);
  146. CC_SAFE_FREE(colorG);
  147. CC_SAFE_FREE(colorB);
  148. CC_SAFE_FREE(colorA);
  149. CC_SAFE_FREE(deltaColorR);
  150. CC_SAFE_FREE(deltaColorG);
  151. CC_SAFE_FREE(deltaColorB);
  152. CC_SAFE_FREE(deltaColorA);
  153. CC_SAFE_FREE(size);
  154. CC_SAFE_FREE(deltaSize);
  155. CC_SAFE_FREE(startSize);
  156. CC_SAFE_FREE(deltaSizeAllLife);
  157. CC_SAFE_FREE(rotation);
  158. CC_SAFE_FREE(deltaRotation);
  159. CC_SAFE_FREE(timeToLive);
  160. CC_SAFE_FREE(life);
  161. CC_SAFE_FREE(atlasIndex);
  162. CC_SAFE_FREE(modeA.dirX);
  163. CC_SAFE_FREE(modeA.dirY);
  164. CC_SAFE_FREE(modeA.radialAccel);
  165. CC_SAFE_FREE(modeA.tangentialAccel);
  166. CC_SAFE_FREE(modeB.angle);
  167. CC_SAFE_FREE(modeB.degreesPerSecond);
  168. CC_SAFE_FREE(modeB.deltaRadius);
  169. CC_SAFE_FREE(modeB.radius);
  170. }
  171. Vector<ParticleSystem*> ParticleSystem::__allInstances;
  172. float ParticleSystem::__totalParticleCountFactor = 1.0f;
  173. ParticleSystem::ParticleSystem()
  174. : _isBlendAdditive(false)
  175. , _isAutoRemoveOnFinish(false)
  176. , _plistFile("")
  177. , _elapsed(0)
  178. , _configName("")
  179. , _emitCounter(0)
  180. , _batchNode(nullptr)
  181. , _atlasIndex(0)
  182. , _transformSystemDirty(false)
  183. , _allocatedParticles(0)
  184. , _isActive(true)
  185. , _particleCount(0)
  186. , _duration(0)
  187. , _life(0)
  188. , _lifeVar(0)
  189. , _angle(0)
  190. , _angleVar(0)
  191. , _emitterMode(Mode::GRAVITY)
  192. , _startSize(0)
  193. , _startSizeVar(0)
  194. , _endSize(0)
  195. , _endSizeVar(0)
  196. , _startSpin(0)
  197. , _startSpinVar(0)
  198. , _endSpin(0)
  199. , _endSpinVar(0)
  200. , _emissionRate(0)
  201. ,_emitFirstFrameEnabled(false)
  202. , _totalParticles(0)
  203. , _texture(nullptr)
  204. , _blendFunc(BlendFunc::ALPHA_PREMULTIPLIED)
  205. , _opacityModifyRGB(false)
  206. , _yCoordFlipped(1)
  207. , _positionType(PositionType::FREE)
  208. , _paused(false)
  209. , _sourcePositionCompatible(true) // In the furture this member's default value maybe false or be removed.
  210. ,_isInitColor(false)
  211. ,_cbOnExit(nullptr)
  212. {
  213. modeA.gravity.setZero();
  214. modeA.speed = 0;
  215. modeA.speedVar = 0;
  216. modeA.tangentialAccel = 0;
  217. modeA.tangentialAccelVar = 0;
  218. modeA.radialAccel = 0;
  219. modeA.radialAccelVar = 0;
  220. modeA.rotationIsDir = false;
  221. modeB.startRadius = 0;
  222. modeB.startRadiusVar = 0;
  223. modeB.endRadius = 0;
  224. modeB.endRadiusVar = 0;
  225. modeB.rotatePerSecond = 0;
  226. modeB.rotatePerSecondVar = 0;
  227. }
  228. // implementation ParticleSystem
  229. ParticleSystem * ParticleSystem::create(const std::string& plistFile)
  230. {
  231. ParticleSystem *ret = new (std::nothrow) ParticleSystem();
  232. if (ret && ret->initWithFile(plistFile))
  233. {
  234. ret->autorelease();
  235. return ret;
  236. }
  237. CC_SAFE_DELETE(ret);
  238. return ret;
  239. }
  240. ParticleSystem* ParticleSystem::createWithTotalParticles(int numberOfParticles)
  241. {
  242. ParticleSystem *ret = new (std::nothrow) ParticleSystem();
  243. if (ret && ret->initWithTotalParticles(numberOfParticles))
  244. {
  245. ret->autorelease();
  246. return ret;
  247. }
  248. CC_SAFE_DELETE(ret);
  249. return ret;
  250. }
  251. // static
  252. Vector<ParticleSystem*>& ParticleSystem::getAllParticleSystems()
  253. {
  254. return __allInstances;
  255. }
  256. void ParticleSystem::setTotalParticleCountFactor(float factor)
  257. {
  258. __totalParticleCountFactor = factor;
  259. }
  260. bool ParticleSystem::init()
  261. {
  262. return initWithTotalParticles(150);
  263. }
  264. bool ParticleSystem::initWithFile(const std::string& plistFile)
  265. {
  266. bool ret = false;
  267. _plName = plistFile;
  268. _plistFile = FileUtils::getInstance()->fullPathForFilename(plistFile);
  269. ValueMap dict = FileUtils::getInstance()->getValueMapFromFile(_plistFile);
  270. CCASSERT( !dict.empty(), "Particles: file not found");
  271. // FIXME: compute path from a path, should define a function somewhere to do it
  272. string listFilePath = plistFile;
  273. if (listFilePath.find('/') != string::npos)
  274. {
  275. listFilePath = listFilePath.substr(0, listFilePath.rfind('/') + 1);
  276. ret = this->initWithDictionary(dict, listFilePath);
  277. }
  278. else
  279. {
  280. ret = this->initWithDictionary(dict, "");
  281. }
  282. return ret;
  283. }
  284. bool ParticleSystem::initWithDictionary(ValueMap& dictionary)
  285. {
  286. return initWithDictionary(dictionary, "");
  287. }
  288. bool ParticleSystem::initWithDictionary(ValueMap& dictionary, const std::string& dirname)
  289. {
  290. bool ret = false;
  291. unsigned char *buffer = nullptr;
  292. unsigned char *deflated = nullptr;
  293. Image *image = nullptr;
  294. do
  295. {
  296. int maxParticles = dictionary["maxParticles"].asInt();
  297. // self, not super
  298. if(this->initWithTotalParticles(maxParticles))
  299. {
  300. // Emitter name in particle designer 2.0
  301. _configName = dictionary["configName"].asString();
  302. // angle
  303. _angle = dictionary["angle"].asFloat();
  304. _angleVar = dictionary["angleVariance"].asFloat();
  305. // duration
  306. _duration = dictionary["duration"].asFloat();
  307. // blend function
  308. if (!_configName.empty())
  309. {
  310. _blendFunc.src = dictionary["blendFuncSource"].asFloat();
  311. }
  312. else
  313. {
  314. _blendFunc.src = dictionary["blendFuncSource"].asInt();
  315. }
  316. _blendFunc.dst = dictionary["blendFuncDestination"].asInt();
  317. // color
  318. _startColor.r = dictionary["startColorRed"].asFloat();
  319. _startColor.g = dictionary["startColorGreen"].asFloat();
  320. _startColor.b = dictionary["startColorBlue"].asFloat();
  321. _startColor.a = dictionary["startColorAlpha"].asFloat();
  322. _startColorVar.r = dictionary["startColorVarianceRed"].asFloat();
  323. _startColorVar.g = dictionary["startColorVarianceGreen"].asFloat();
  324. _startColorVar.b = dictionary["startColorVarianceBlue"].asFloat();
  325. _startColorVar.a = dictionary["startColorVarianceAlpha"].asFloat();
  326. _endColor.r = dictionary["finishColorRed"].asFloat();
  327. _endColor.g = dictionary["finishColorGreen"].asFloat();
  328. _endColor.b = dictionary["finishColorBlue"].asFloat();
  329. _endColor.a = dictionary["finishColorAlpha"].asFloat();
  330. _endColorVar.r = dictionary["finishColorVarianceRed"].asFloat();
  331. _endColorVar.g = dictionary["finishColorVarianceGreen"].asFloat();
  332. _endColorVar.b = dictionary["finishColorVarianceBlue"].asFloat();
  333. _endColorVar.a = dictionary["finishColorVarianceAlpha"].asFloat();
  334. // particle size
  335. _startSize = dictionary["startParticleSize"].asFloat();
  336. _startSizeVar = dictionary["startParticleSizeVariance"].asFloat();
  337. _endSize = dictionary["finishParticleSize"].asFloat();
  338. _endSizeVar = dictionary["finishParticleSizeVariance"].asFloat();
  339. // position
  340. float x = dictionary["sourcePositionx"].asFloat();
  341. float y = dictionary["sourcePositiony"].asFloat();
  342. if(!_sourcePositionCompatible) {
  343. this->setSourcePosition(Vec2(x, y));
  344. }
  345. else {
  346. this->setPosition(Vec2(x, y));
  347. }
  348. _posVar.x = dictionary["sourcePositionVariancex"].asFloat();
  349. _posVar.y = dictionary["sourcePositionVariancey"].asFloat();
  350. // Spinning
  351. _startSpin = dictionary["rotationStart"].asFloat();
  352. _startSpinVar = dictionary["rotationStartVariance"].asFloat();
  353. _endSpin= dictionary["rotationEnd"].asFloat();
  354. _endSpinVar= dictionary["rotationEndVariance"].asFloat();
  355. _emitterMode = (Mode) dictionary["emitterType"].asInt();
  356. // Mode A: Gravity + tangential accel + radial accel
  357. if (_emitterMode == Mode::GRAVITY)
  358. {
  359. // gravity
  360. modeA.gravity.x = dictionary["gravityx"].asFloat();
  361. modeA.gravity.y = dictionary["gravityy"].asFloat();
  362. // speed
  363. modeA.speed = dictionary["speed"].asFloat();
  364. modeA.speedVar = dictionary["speedVariance"].asFloat();
  365. // radial acceleration
  366. modeA.radialAccel = dictionary["radialAcceleration"].asFloat();
  367. modeA.radialAccelVar = dictionary["radialAccelVariance"].asFloat();
  368. // tangential acceleration
  369. modeA.tangentialAccel = dictionary["tangentialAcceleration"].asFloat();
  370. modeA.tangentialAccelVar = dictionary["tangentialAccelVariance"].asFloat();
  371. // rotation is dir
  372. modeA.rotationIsDir = dictionary["rotationIsDir"].asBool();
  373. }
  374. // or Mode B: radius movement
  375. else if (_emitterMode == Mode::RADIUS)
  376. {
  377. if (!_configName.empty())
  378. {
  379. modeB.startRadius = dictionary["maxRadius"].asInt();
  380. }
  381. else
  382. {
  383. modeB.startRadius = dictionary["maxRadius"].asFloat();
  384. }
  385. modeB.startRadiusVar = dictionary["maxRadiusVariance"].asFloat();
  386. if (!_configName.empty())
  387. {
  388. modeB.endRadius = dictionary["minRadius"].asInt();
  389. }
  390. else
  391. {
  392. modeB.endRadius = dictionary["minRadius"].asFloat();
  393. }
  394. if (dictionary.find("minRadiusVariance") != dictionary.end())
  395. {
  396. modeB.endRadiusVar = dictionary["minRadiusVariance"].asFloat();
  397. }
  398. else
  399. {
  400. modeB.endRadiusVar = 0.0f;
  401. }
  402. if (!_configName.empty())
  403. {
  404. modeB.rotatePerSecond = dictionary["rotatePerSecond"].asInt();
  405. }
  406. else
  407. {
  408. modeB.rotatePerSecond = dictionary["rotatePerSecond"].asFloat();
  409. }
  410. modeB.rotatePerSecondVar = dictionary["rotatePerSecondVariance"].asFloat();
  411. } else {
  412. CCASSERT( false, "Invalid emitterType in config file");
  413. CC_BREAK_IF(true);
  414. }
  415. // life span
  416. _life = dictionary["particleLifespan"].asFloat();
  417. _lifeVar = dictionary["particleLifespanVariance"].asFloat();
  418. // emission Rate
  419. _emissionRate = _totalParticles / _life;
  420. //don't get the internal texture if a batchNode is used
  421. if (!_batchNode)
  422. {
  423. // Set a compatible default for the alpha transfer
  424. _opacityModifyRGB = false;
  425. // texture
  426. // Try to get the texture from the cache
  427. std::string textureName = dictionary["textureFileName"].asString();
  428. size_t rPos = textureName.rfind('/');
  429. if (rPos != string::npos)
  430. {
  431. string textureDir = textureName.substr(0, rPos + 1);
  432. if (!dirname.empty() && textureDir != dirname)
  433. {
  434. textureName = textureName.substr(rPos+1);
  435. textureName = dirname + textureName;
  436. }
  437. }
  438. else if (!dirname.empty() && !textureName.empty())
  439. {
  440. textureName = dirname + textureName;
  441. }
  442. //modify by djd 粒子支持plist大纹理,优先走大纹理找不到就走小图.
  443. Texture2D *tex = nullptr;
  444. SpriteFrame *tFrame = nullptr;
  445. if (!textureName.empty())
  446. {
  447. SpriteFrameCache * frameCache = SpriteFrameCache::getInstance();
  448. tFrame = frameCache->getSpriteFrameByName(textureName.c_str());
  449. // set not pop-up message box when load image failed
  450. bool notify = FileUtils::getInstance()->isPopupNotify();
  451. FileUtils::getInstance()->setPopupNotify(false);
  452. tex = Director::getInstance()->getTextureCache()->addImage(textureName);
  453. // reset the value of UIImage notify
  454. FileUtils::getInstance()->setPopupNotify(notify);
  455. }
  456. if (tFrame){
  457. bool isrotaed = tFrame->isRotated();
  458. Vec2 offset = tFrame->getOffset();
  459. Vec2 originalSize = tFrame->getOriginalSize();
  460. auto pointRect = tFrame->getRect();
  461. setTextureWithRect(tFrame->getTexture(), pointRect,isrotaed,offset,originalSize);
  462. }else if (tex)
  463. {
  464. setTexture(tex);
  465. }
  466. else if( dictionary.find("textureImageData") != dictionary.end() )
  467. {
  468. std::string textureData = dictionary.at("textureImageData").asString();
  469. CCASSERT(!textureData.empty(), "textureData can't be empty!");
  470. auto dataLen = textureData.size();
  471. if (dataLen != 0)
  472. {
  473. // if it fails, try to get it from the base64-gzipped data
  474. int decodeLen = base64Decode((unsigned char*)textureData.c_str(), (unsigned int)dataLen, &buffer);
  475. CCASSERT( buffer != nullptr, "CCParticleSystem: error decoding textureImageData");
  476. CC_BREAK_IF(!buffer);
  477. ssize_t deflatedLen = ZipUtils::inflateMemory(buffer, decodeLen, &deflated);
  478. CCASSERT( deflated != nullptr, "CCParticleSystem: error ungzipping textureImageData");
  479. CC_BREAK_IF(!deflated);
  480. // For android, we should retain it in VolatileTexture::addImage which invoked in Director::getInstance()->getTextureCache()->addUIImage()
  481. image = new (std::nothrow) Image();
  482. bool isOK = image->initWithImageData(deflated, deflatedLen);
  483. CCASSERT(isOK, "CCParticleSystem: error init image with Data");
  484. CC_BREAK_IF(!isOK);
  485. setTexture(Director::getInstance()->getTextureCache()->addImage(image, _plistFile + textureName));
  486. image->release();
  487. }
  488. }
  489. _yCoordFlipped = dictionary.find("yCoordFlipped") == dictionary.end() ? 1 : dictionary.at("yCoordFlipped").asInt();
  490. if( !this->_texture)
  491. CCLOGWARN("cocos2d: Warning: ParticleSystemQuad system without a texture");
  492. }
  493. ret = true;
  494. }
  495. } while (0);
  496. free(buffer);
  497. free(deflated);
  498. return ret;
  499. }
  500. bool ParticleSystem::initWithTotalParticles(int numberOfParticles)
  501. {
  502. _totalParticles = numberOfParticles;
  503. _particleData.release();
  504. if( !_particleData.init(_totalParticles) )
  505. {
  506. CCLOG("Particle system: not enough memory");
  507. this->release();
  508. return false;
  509. }
  510. _allocatedParticles = numberOfParticles;
  511. if (_batchNode)
  512. {
  513. for (int i = 0; i < _totalParticles; i++)
  514. {
  515. _particleData.atlasIndex[i] = i;
  516. }
  517. }
  518. // default, active
  519. _isActive = true;
  520. // default blend function
  521. _blendFunc = BlendFunc::ALPHA_PREMULTIPLIED;
  522. // default movement type;
  523. _positionType = PositionType::FREE;
  524. // by default be in mode A:
  525. _emitterMode = Mode::GRAVITY;
  526. // default: modulate
  527. // FIXME:: not used
  528. // colorModulate = YES;
  529. _isAutoRemoveOnFinish = false;
  530. // Optimization: compile updateParticle method
  531. //updateParticleSel = @selector(updateQuadWithParticle:newPosition:);
  532. //updateParticleImp = (CC_UPDATE_PARTICLE_IMP) [self methodForSelector:updateParticleSel];
  533. //for batchNode
  534. _transformSystemDirty = false;
  535. return true;
  536. }
  537. ParticleSystem::~ParticleSystem()
  538. {
  539. // Since the scheduler retains the "target (in this case the ParticleSystem)
  540. // it is not needed to call "unscheduleUpdate" here. In fact, it will be called in "cleanup"
  541. //unscheduleUpdate();
  542. _particleData.release();
  543. CC_SAFE_RELEASE(_texture);
  544. }
  545. void ParticleSystem::addParticles(int count)
  546. {
  547. if (_paused)
  548. return;
  549. uint32_t RANDSEED = rand();
  550. int start = _particleCount;
  551. _particleCount += count;
  552. //life
  553. for (int i = start; i < _particleCount ; ++i)
  554. {
  555. float theLife = _life + _lifeVar * RANDOM_M11(&RANDSEED);
  556. _particleData.timeToLive[i] = MAX(0, theLife);
  557. _particleData.life[i] = _particleData.timeToLive[i];
  558. }
  559. //position
  560. for (int i = start; i < _particleCount; ++i)
  561. {
  562. _particleData.posx[i] = _sourcePosition.x + _posVar.x * RANDOM_M11(&RANDSEED);
  563. }
  564. for (int i = start; i < _particleCount; ++i)
  565. {
  566. _particleData.posy[i] = _sourcePosition.y + _posVar.y * RANDOM_M11(&RANDSEED);
  567. }
  568. //color
  569. #define SET_COLOR(c, b, v)\
  570. for (int i = start; i < _particleCount; ++i)\
  571. {\
  572. c[i] = clampf( b + v * RANDOM_M11(&RANDSEED) , 0 , 1 );\
  573. }
  574. SET_COLOR(_particleData.colorR, _startColor.r, _startColorVar.r);
  575. SET_COLOR(_particleData.colorG, _startColor.g, _startColorVar.g);
  576. SET_COLOR(_particleData.colorB, _startColor.b, _startColorVar.b);
  577. SET_COLOR(_particleData.colorA, _startColor.a, _startColorVar.a);
  578. SET_COLOR(_particleData.deltaColorR, _endColor.r, _endColorVar.r);
  579. SET_COLOR(_particleData.deltaColorG, _endColor.g, _endColorVar.g);
  580. SET_COLOR(_particleData.deltaColorB, _endColor.b, _endColorVar.b);
  581. SET_COLOR(_particleData.deltaColorA, _endColor.a, _endColorVar.a);
  582. #define SET_DELTA_COLOR(c, dc)\
  583. for (int i = start; i < _particleCount; ++i)\
  584. {\
  585. dc[i] = (dc[i] - c[i]) / _particleData.timeToLive[i];\
  586. }
  587. SET_DELTA_COLOR(_particleData.colorR, _particleData.deltaColorR);
  588. SET_DELTA_COLOR(_particleData.colorG, _particleData.deltaColorG);
  589. SET_DELTA_COLOR(_particleData.colorB, _particleData.deltaColorB);
  590. SET_DELTA_COLOR(_particleData.colorA, _particleData.deltaColorA);
  591. //size
  592. for (int i = start; i < _particleCount; ++i)
  593. {
  594. _particleData.size[i] = _startSize + _startSizeVar * RANDOM_M11(&RANDSEED);
  595. _particleData.size[i] = MAX(0, _particleData.size[i]);
  596. _particleData.startSize[i] = _particleData.size[i];
  597. }
  598. if (_endSize != START_SIZE_EQUAL_TO_END_SIZE)
  599. {
  600. for (int i = start; i < _particleCount; ++i)
  601. {
  602. float endSize = _endSize + _endSizeVar * RANDOM_M11(&RANDSEED);
  603. endSize = MAX(0, endSize);
  604. _particleData.deltaSize[i] = (endSize - _particleData.size[i]) / _particleData.timeToLive[i];
  605. _particleData.deltaSizeAllLife[i] = endSize - _particleData.size[i];
  606. }
  607. }
  608. else
  609. {
  610. for (int i = start; i < _particleCount; ++i)
  611. {
  612. _particleData.deltaSize[i] = 0.0f;
  613. }
  614. }
  615. // rotation
  616. for (int i = start; i < _particleCount; ++i)
  617. {
  618. _particleData.rotation[i] = _startSpin + _startSpinVar * RANDOM_M11(&RANDSEED);
  619. }
  620. for (int i = start; i < _particleCount; ++i)
  621. {
  622. float endA = _endSpin + _endSpinVar * RANDOM_M11(&RANDSEED);
  623. _particleData.deltaRotation[i] = (endA - _particleData.rotation[i]) / _particleData.timeToLive[i];
  624. }
  625. // position
  626. Vec2 pos;
  627. float roation;
  628. if (_positionType == PositionType::FREE)
  629. {
  630. pos = this->convertToWorldSpace(Vec2::ZERO);
  631. roation = getWordRoation();
  632. }
  633. else if (_positionType == PositionType::RELATIVE)
  634. {
  635. pos = _position;
  636. roation = getRotation();
  637. }
  638. for (int i = start; i < _particleCount; ++i)
  639. {
  640. _particleData.startPosX[i] = pos.x;
  641. _particleData.startRoation[i] = roation;
  642. }
  643. for (int i = start; i < _particleCount; ++i)
  644. {
  645. _particleData.startPosY[i] = pos.y;
  646. }
  647. // Mode Gravity: A
  648. if (_emitterMode == Mode::GRAVITY)
  649. {
  650. // radial accel
  651. for (int i = start; i < _particleCount; ++i)
  652. {
  653. _particleData.modeA.radialAccel[i] = modeA.radialAccel + modeA.radialAccelVar * RANDOM_M11(&RANDSEED);
  654. }
  655. // tangential accel
  656. for (int i = start; i < _particleCount; ++i)
  657. {
  658. _particleData.modeA.tangentialAccel[i] = modeA.tangentialAccel + modeA.tangentialAccelVar * RANDOM_M11(&RANDSEED);
  659. }
  660. // rotation is dir
  661. if( modeA.rotationIsDir )
  662. {
  663. for (int i = start; i < _particleCount; ++i)
  664. {
  665. float a = CC_DEGREES_TO_RADIANS( _angle + _angleVar * RANDOM_M11(&RANDSEED) );
  666. Vec2 v(cosf( a ), sinf( a ));
  667. float s = modeA.speed + modeA.speedVar * RANDOM_M11(&RANDSEED);
  668. Vec2 dir = v * s;
  669. _particleData.modeA.dirX[i] = dir.x;//v * s ;
  670. _particleData.modeA.dirY[i] = dir.y;
  671. _particleData.rotation[i] = -CC_RADIANS_TO_DEGREES(dir.getAngle());
  672. }
  673. }
  674. else
  675. {
  676. for (int i = start; i < _particleCount; ++i)
  677. {
  678. float a = CC_DEGREES_TO_RADIANS( _angle + _angleVar * RANDOM_M11(&RANDSEED) );
  679. Vec2 v(cosf( a ), sinf( a ));
  680. float s = modeA.speed + modeA.speedVar * RANDOM_M11(&RANDSEED);
  681. Vec2 dir = v * s;
  682. _particleData.modeA.dirX[i] = dir.x;//v * s ;
  683. _particleData.modeA.dirY[i] = dir.y;
  684. }
  685. }
  686. }
  687. // Mode Radius: B
  688. else
  689. {
  690. //Need to check by Jacky
  691. // Set the default diameter of the particle from the source position
  692. for (int i = start; i < _particleCount; ++i)
  693. {
  694. _particleData.modeB.radius[i] = modeB.startRadius + modeB.startRadiusVar * RANDOM_M11(&RANDSEED);
  695. }
  696. for (int i = start; i < _particleCount; ++i)
  697. {
  698. _particleData.modeB.angle[i] = CC_DEGREES_TO_RADIANS( _angle + _angleVar * RANDOM_M11(&RANDSEED));
  699. }
  700. for (int i = start; i < _particleCount; ++i)
  701. {
  702. _particleData.modeB.degreesPerSecond[i] = CC_DEGREES_TO_RADIANS(modeB.rotatePerSecond + modeB.rotatePerSecondVar * RANDOM_M11(&RANDSEED));
  703. }
  704. if(modeB.endRadius == START_RADIUS_EQUAL_TO_END_RADIUS)
  705. {
  706. for (int i = start; i < _particleCount; ++i)
  707. {
  708. _particleData.modeB.deltaRadius[i] = 0.0f;
  709. }
  710. }
  711. else
  712. {
  713. for (int i = start; i < _particleCount; ++i)
  714. {
  715. float endRadius = modeB.endRadius + modeB.endRadiusVar * RANDOM_M11(&RANDSEED);
  716. _particleData.modeB.deltaRadius[i] = (endRadius - _particleData.modeB.radius[i]) / _particleData.timeToLive[i];
  717. }
  718. }
  719. }
  720. }
  721. void ParticleSystem::onEnter()
  722. {
  723. #if CC_ENABLE_SCRIPT_BINDING
  724. if (_scriptType == kScriptTypeJavascript)
  725. {
  726. if (ScriptEngineManager::sendNodeEventToJSExtended(this, kNodeOnEnter))
  727. return;
  728. }
  729. #endif
  730. Node::onEnter();
  731. // update after action in run!
  732. this->scheduleUpdateWithPriority(1);
  733. __allInstances.pushBack(this);
  734. }
  735. void ParticleSystem::onExit()
  736. {
  737. #if CC_ENABLE_SCRIPT_BINDING
  738. if (_scriptType == kScriptTypeJavascript)
  739. {
  740. if (ScriptEngineManager::sendNodeEventToJSExtended(this, kNodeOnExit))
  741. return;
  742. }
  743. #endif
  744. if (_cbOnExit != nullptr && _plName.size() > 0) {
  745. _cbOnExit(_plName, this);
  746. }
  747. this->unscheduleUpdate();
  748. Node::onExit();
  749. auto iter = std::find(std::begin(__allInstances), std::end(__allInstances), this);
  750. if (iter != std::end(__allInstances))
  751. {
  752. __allInstances.erase(iter);
  753. }
  754. }
  755. void ParticleSystem::stopSystem()
  756. {
  757. _isActive = false;
  758. _elapsed = _duration;
  759. _emitCounter = 0;
  760. }
  761. void ParticleSystem::setVisible(bool visible)
  762. {
  763. if (CocosConfig::getParticleVisibleReset()) {
  764. if (visible != _visible) {
  765. if (visible) this->resetSystem();
  766. else this->stopSystem();
  767. }
  768. }
  769. Node::setVisible(visible);
  770. }
  771. void ParticleSystem::setVisibleOnly(bool visible){
  772. Node::setVisible(visible);
  773. }
  774. //add by djd
  775. void ParticleSystem::updateDisplayedOpacity(GLubyte opacity){
  776. Node::updateDisplayedOpacity(opacity);
  777. if (!CocosConfig::getParticleOpacity()) {
  778. return;
  779. }
  780. if (!_isInitColor) {
  781. _initStartColor = getStartColor();
  782. _initStartColorVar = getStartColorVar();
  783. _initEndColor = getEndColor();
  784. _initEndColorVar = getEndColorVar();
  785. _initBlendFunc = _blendFunc;
  786. _isInitColor = true;
  787. }
  788. if (opacity < 100) {
  789. _blendFunc = BlendFunc::ADDITIVE;
  790. }else{
  791. _blendFunc = _initBlendFunc;
  792. }
  793. setStartColor(Color4F(_initStartColor.r* opacity/255, _initStartColor.g* opacity/255, _initStartColor.b* opacity/255, _initStartColor.a ));
  794. setStartColorVar(Color4F(_initStartColorVar.r* opacity/255, _initStartColorVar.g* opacity/255, _initStartColorVar.b* opacity/255, _initStartColorVar.a));
  795. setEndColor(Color4F(_initEndColor.r* opacity/255, _initEndColor.g* opacity/255, _initEndColor.b* opacity/255, _initEndColor.a));
  796. setEndColorVar(Color4F(_initEndColorVar.r* opacity/255, _initEndColorVar.g* opacity/255, _initEndColorVar.b* opacity/255, _initEndColorVar.a));
  797. }
  798. void ParticleSystem::resetSystem()
  799. {
  800. _isActive = true;
  801. _elapsed = 0;
  802. for (int i = 0; i < _particleCount; ++i)
  803. {
  804. _particleData.timeToLive[i] = 0.0f;
  805. }
  806. _particleCount = 0;
  807. }
  808. bool ParticleSystem::isFull()
  809. {
  810. return (_particleCount == _totalParticles);
  811. }
  812. // ParticleSystem - MainLoop
  813. void ParticleSystem::update(float dt)
  814. {
  815. CC_PROFILER_START_CATEGORY(kProfilerCategoryParticles , "CCParticleSystem - update");
  816. if(CocosConfig::isParticleUpdateOptimize() == false || _visible == true){
  817. if (_isActive && _emissionRate)
  818. {
  819. float rate = 1.0f / _emissionRate;
  820. int totalParticles = static_cast<int>(_totalParticles * __totalParticleCountFactor);
  821. //issue #1201, prevent bursts of particles, due to too high emitCounter
  822. if (_particleCount < totalParticles)
  823. {
  824. _emitCounter += dt;
  825. if (_emitCounter < 0.f)
  826. _emitCounter = 0.f;
  827. }
  828. int emitCount = MIN(totalParticles - _particleCount, _emitCounter / rate);
  829. addParticles(emitCount);
  830. _emitCounter -= rate * emitCount;
  831. _elapsed += dt;
  832. if (_elapsed < 0.f)
  833. _elapsed = 0.f;
  834. if (_duration != DURATION_INFINITY && _duration < _elapsed)
  835. {
  836. this->stopSystem();
  837. }
  838. }
  839. {
  840. for (int i = 0; i < _particleCount; ++i)
  841. {
  842. _particleData.timeToLive[i] -= dt;
  843. }
  844. for (int i = 0; i < _particleCount; ++i)
  845. {
  846. if (_particleData.timeToLive[i] <= 0.0f)
  847. {
  848. int j = _particleCount - 1;
  849. while (j > 0 && _particleData.timeToLive[j] <= 0)
  850. {
  851. _particleCount--;
  852. j--;
  853. }
  854. _particleData.copyParticle(i, _particleCount - 1);
  855. if (_batchNode)
  856. {
  857. //disable the switched particle
  858. int currentIndex = _particleData.atlasIndex[i];
  859. _batchNode->disableParticle(_atlasIndex + currentIndex);
  860. //switch indexes
  861. _particleData.atlasIndex[_particleCount - 1] = currentIndex;
  862. }
  863. --_particleCount;
  864. if( _particleCount == 0 && _isAutoRemoveOnFinish )
  865. {
  866. this->unscheduleUpdate();
  867. _parent->removeChild(this, true);
  868. return;
  869. }
  870. }
  871. }
  872. if (_emitterMode == Mode::GRAVITY)
  873. {
  874. for (int i = 0 ; i < _particleCount; ++i)
  875. {
  876. particle_point tmp, radial = {0.0f, 0.0f}, tangential;
  877. // radial acceleration
  878. if (_particleData.posx[i] || _particleData.posy[i])
  879. {
  880. normalize_point(_particleData.posx[i], _particleData.posy[i], &radial);
  881. }
  882. tangential = radial;
  883. radial.x *= _particleData.modeA.radialAccel[i];
  884. radial.y *= _particleData.modeA.radialAccel[i];
  885. // tangential acceleration
  886. std::swap(tangential.x, tangential.y);
  887. tangential.x *= - _particleData.modeA.tangentialAccel[i];
  888. tangential.y *= _particleData.modeA.tangentialAccel[i];
  889. // (gravity + radial + tangential) * dt
  890. tmp.x = radial.x + tangential.x + modeA.gravity.x;
  891. tmp.y = radial.y + tangential.y + modeA.gravity.y;
  892. tmp.x *= dt;
  893. tmp.y *= dt;
  894. _particleData.modeA.dirX[i] += tmp.x;
  895. _particleData.modeA.dirY[i] += tmp.y;
  896. // this is cocos2d-x v3.0
  897. // if (_configName.length()>0 && _yCoordFlipped != -1)
  898. // this is cocos2d-x v3.0
  899. tmp.x = _particleData.modeA.dirX[i] * dt * _yCoordFlipped;
  900. tmp.y = _particleData.modeA.dirY[i] * dt * _yCoordFlipped;
  901. _particleData.posx[i] += tmp.x;
  902. _particleData.posy[i] += tmp.y;
  903. }
  904. }
  905. else
  906. {
  907. //Why use so many for-loop separately instead of putting them together?
  908. //When the processor needs to read from or write to a location in memory,
  909. //it first checks whether a copy of that data is in the cache.
  910. //And every property's memory of the particle system is continuous,
  911. //for the purpose of improving cache hit rate, we should process only one property in one for-loop AFAP.
  912. //It was proved to be effective especially for low-end machine.
  913. for (int i = 0; i < _particleCount; ++i)
  914. {
  915. _particleData.modeB.angle[i] += _particleData.modeB.degreesPerSecond[i] * dt;
  916. }
  917. for (int i = 0; i < _particleCount; ++i)
  918. {
  919. _particleData.modeB.radius[i] += _particleData.modeB.deltaRadius[i] * dt;
  920. }
  921. for (int i = 0; i < _particleCount; ++i)
  922. {
  923. _particleData.posx[i] = - cosf(_particleData.modeB.angle[i]) * _particleData.modeB.radius[i];
  924. }
  925. for (int i = 0; i < _particleCount; ++i)
  926. {
  927. _particleData.posy[i] = - sinf(_particleData.modeB.angle[i]) * _particleData.modeB.radius[i] * _yCoordFlipped;
  928. }
  929. }
  930. //color r,g,b,a
  931. for (int i = 0 ; i < _particleCount; ++i)
  932. {
  933. _particleData.colorR[i] += _particleData.deltaColorR[i] * dt;
  934. }
  935. for (int i = 0 ; i < _particleCount; ++i)
  936. {
  937. _particleData.colorG[i] += _particleData.deltaColorG[i] * dt;
  938. }
  939. for (int i = 0 ; i < _particleCount; ++i)
  940. {
  941. _particleData.colorB[i] += _particleData.deltaColorB[i] * dt;
  942. }
  943. for (int i = 0 ; i < _particleCount; ++i)
  944. {
  945. _particleData.colorA[i] += _particleData.deltaColorA[i] * dt;
  946. }
  947. //size
  948. for (int i = 0 ; i < _particleCount; ++i)
  949. {
  950. _particleData.size[i] += (_particleData.deltaSize[i] * dt);
  951. _particleData.size[i] = MAX(0, _particleData.size[i]);
  952. }
  953. //angle
  954. for (int i = 0 ; i < _particleCount; ++i)
  955. {
  956. _particleData.rotation[i] += _particleData.deltaRotation[i] * dt;
  957. }
  958. updateParticleQuads();
  959. _transformSystemDirty = false;
  960. }
  961. }
  962. // only update gl buffer when visible
  963. if (_visible && ! _batchNode)
  964. {
  965. postStep();
  966. }
  967. CC_PROFILER_STOP_CATEGORY(kProfilerCategoryParticles , "CCParticleSystem - update");
  968. }
  969. void ParticleSystem::updateWithNoTime(void)
  970. {
  971. this->update(0.0f);
  972. }
  973. void ParticleSystem::updateParticleQuads()
  974. {
  975. //should be overridden
  976. }
  977. void ParticleSystem::postStep()
  978. {
  979. // should be overridden
  980. }
  981. // ParticleSystem - Texture protocol
  982. void ParticleSystem::setTexture(Texture2D* var)
  983. {
  984. if (_texture != var)
  985. {
  986. CC_SAFE_RETAIN(var);
  987. CC_SAFE_RELEASE(_texture);
  988. _texture = var;
  989. updateBlendFunc();
  990. }
  991. }
  992. void ParticleSystem::setTextureWithRect(Texture2D *texture, const Rect& rect, bool isrotated, Vec2& offset, Vec2 &originalSize){
  993. setTexture(texture);
  994. }
  995. void ParticleSystem::updateBlendFunc()
  996. {
  997. CCASSERT(! _batchNode, "Can't change blending functions when the particle is being batched");
  998. if(_texture)
  999. {
  1000. bool premultiplied = _texture->hasPremultipliedAlpha();
  1001. _opacityModifyRGB = false;
  1002. if( _texture && ( _blendFunc.src == CC_BLEND_SRC && _blendFunc.dst == CC_BLEND_DST ) )
  1003. {
  1004. if( premultiplied )
  1005. {
  1006. _opacityModifyRGB = true;
  1007. }
  1008. else
  1009. {
  1010. _blendFunc = BlendFunc::ALPHA_NON_PREMULTIPLIED;
  1011. }
  1012. }
  1013. }
  1014. }
  1015. Texture2D * ParticleSystem::getTexture() const
  1016. {
  1017. return _texture;
  1018. }
  1019. // ParticleSystem - Additive Blending
  1020. void ParticleSystem::setBlendAdditive(bool additive)
  1021. {
  1022. if( additive )
  1023. {
  1024. _blendFunc = BlendFunc::ADDITIVE;
  1025. }
  1026. else
  1027. {
  1028. if( _texture && ! _texture->hasPremultipliedAlpha() )
  1029. _blendFunc = BlendFunc::ALPHA_NON_PREMULTIPLIED;
  1030. else
  1031. _blendFunc = BlendFunc::ALPHA_PREMULTIPLIED;
  1032. }
  1033. }
  1034. bool ParticleSystem::isBlendAdditive() const
  1035. {
  1036. return( _blendFunc.src == GL_SRC_ALPHA && _blendFunc.dst == GL_ONE);
  1037. }
  1038. // ParticleSystem - Properties of Gravity Mode
  1039. void ParticleSystem::setTangentialAccel(float t)
  1040. {
  1041. CCASSERT( _emitterMode == Mode::GRAVITY, "Particle Mode should be Gravity");
  1042. modeA.tangentialAccel = t;
  1043. }
  1044. float ParticleSystem::getTangentialAccel() const
  1045. {
  1046. CCASSERT( _emitterMode == Mode::GRAVITY, "Particle Mode should be Gravity");
  1047. return modeA.tangentialAccel;
  1048. }
  1049. void ParticleSystem::setTangentialAccelVar(float t)
  1050. {
  1051. CCASSERT(_emitterMode == Mode::GRAVITY, "Particle Mode should be Gravity");
  1052. modeA.tangentialAccelVar = t;
  1053. }
  1054. float ParticleSystem::getTangentialAccelVar() const
  1055. {
  1056. CCASSERT(_emitterMode == Mode::GRAVITY, "Particle Mode should be Gravity");
  1057. return modeA.tangentialAccelVar;
  1058. }
  1059. void ParticleSystem::setRadialAccel(float t)
  1060. {
  1061. CCASSERT(_emitterMode == Mode::GRAVITY, "Particle Mode should be Gravity");
  1062. modeA.radialAccel = t;
  1063. }
  1064. float ParticleSystem::getRadialAccel() const
  1065. {
  1066. CCASSERT(_emitterMode == Mode::GRAVITY, "Particle Mode should be Gravity");
  1067. return modeA.radialAccel;
  1068. }
  1069. void ParticleSystem::setRadialAccelVar(float t)
  1070. {
  1071. CCASSERT(_emitterMode == Mode::GRAVITY, "Particle Mode should be Gravity");
  1072. modeA.radialAccelVar = t;
  1073. }
  1074. float ParticleSystem::getRadialAccelVar() const
  1075. {
  1076. CCASSERT(_emitterMode == Mode::GRAVITY, "Particle Mode should be Gravity");
  1077. return modeA.radialAccelVar;
  1078. }
  1079. void ParticleSystem::setRotationIsDir(bool t)
  1080. {
  1081. CCASSERT(_emitterMode == Mode::GRAVITY, "Particle Mode should be Gravity");
  1082. modeA.rotationIsDir = t;
  1083. }
  1084. bool ParticleSystem::getRotationIsDir() const
  1085. {
  1086. CCASSERT(_emitterMode == Mode::GRAVITY, "Particle Mode should be Gravity");
  1087. return modeA.rotationIsDir;
  1088. }
  1089. void ParticleSystem::setGravity(const Vec2& g)
  1090. {
  1091. CCASSERT(_emitterMode == Mode::GRAVITY, "Particle Mode should be Gravity");
  1092. modeA.gravity = g;
  1093. }
  1094. const Vec2& ParticleSystem::getGravity()
  1095. {
  1096. CCASSERT(_emitterMode == Mode::GRAVITY, "Particle Mode should be Gravity");
  1097. return modeA.gravity;
  1098. }
  1099. void ParticleSystem::setSpeed(float speed)
  1100. {
  1101. CCASSERT(_emitterMode == Mode::GRAVITY, "Particle Mode should be Gravity");
  1102. modeA.speed = speed;
  1103. }
  1104. float ParticleSystem::getSpeed() const
  1105. {
  1106. CCASSERT(_emitterMode == Mode::GRAVITY, "Particle Mode should be Gravity");
  1107. return modeA.speed;
  1108. }
  1109. void ParticleSystem::setSpeedVar(float speedVar)
  1110. {
  1111. CCASSERT(_emitterMode == Mode::GRAVITY, "Particle Mode should be Gravity");
  1112. modeA.speedVar = speedVar;
  1113. }
  1114. float ParticleSystem::getSpeedVar() const
  1115. {
  1116. CCASSERT(_emitterMode == Mode::GRAVITY, "Particle Mode should be Gravity");
  1117. return modeA.speedVar;
  1118. }
  1119. // ParticleSystem - Properties of Radius Mode
  1120. void ParticleSystem::setStartRadius(float startRadius)
  1121. {
  1122. CCASSERT(_emitterMode == Mode::RADIUS, "Particle Mode should be Radius");
  1123. modeB.startRadius = startRadius;
  1124. }
  1125. float ParticleSystem::getStartRadius() const
  1126. {
  1127. CCASSERT(_emitterMode == Mode::RADIUS, "Particle Mode should be Radius");
  1128. return modeB.startRadius;
  1129. }
  1130. void ParticleSystem::setStartRadiusVar(float startRadiusVar)
  1131. {
  1132. CCASSERT(_emitterMode == Mode::RADIUS, "Particle Mode should be Radius");
  1133. modeB.startRadiusVar = startRadiusVar;
  1134. }
  1135. float ParticleSystem::getStartRadiusVar() const
  1136. {
  1137. CCASSERT(_emitterMode == Mode::RADIUS, "Particle Mode should be Radius");
  1138. return modeB.startRadiusVar;
  1139. }
  1140. void ParticleSystem::setEndRadius(float endRadius)
  1141. {
  1142. CCASSERT(_emitterMode == Mode::RADIUS, "Particle Mode should be Radius");
  1143. modeB.endRadius = endRadius;
  1144. }
  1145. float ParticleSystem::getEndRadius() const
  1146. {
  1147. CCASSERT(_emitterMode == Mode::RADIUS, "Particle Mode should be Radius");
  1148. return modeB.endRadius;
  1149. }
  1150. void ParticleSystem::setEndRadiusVar(float endRadiusVar)
  1151. {
  1152. CCASSERT(_emitterMode == Mode::RADIUS, "Particle Mode should be Radius");
  1153. modeB.endRadiusVar = endRadiusVar;
  1154. }
  1155. float ParticleSystem::getEndRadiusVar() const
  1156. {
  1157. CCASSERT(_emitterMode == Mode::RADIUS, "Particle Mode should be Radius");
  1158. return modeB.endRadiusVar;
  1159. }
  1160. void ParticleSystem::setRotatePerSecond(float degrees)
  1161. {
  1162. CCASSERT(_emitterMode == Mode::RADIUS, "Particle Mode should be Radius");
  1163. modeB.rotatePerSecond = degrees;
  1164. }
  1165. float ParticleSystem::getRotatePerSecond() const
  1166. {
  1167. CCASSERT(_emitterMode == Mode::RADIUS, "Particle Mode should be Radius");
  1168. return modeB.rotatePerSecond;
  1169. }
  1170. void ParticleSystem::setRotatePerSecondVar(float degrees)
  1171. {
  1172. CCASSERT(_emitterMode == Mode::RADIUS, "Particle Mode should be Radius");
  1173. modeB.rotatePerSecondVar = degrees;
  1174. }
  1175. float ParticleSystem::getRotatePerSecondVar() const
  1176. {
  1177. CCASSERT(_emitterMode == Mode::RADIUS, "Particle Mode should be Radius");
  1178. return modeB.rotatePerSecondVar;
  1179. }
  1180. void ParticleSystem::setEmitFirstFrameEnabled(bool emitFirstFrameEnabled){
  1181. if(emitFirstFrameEnabled){
  1182. _emitCounter = _emissionRate;
  1183. }
  1184. _emitFirstFrameEnabled = emitFirstFrameEnabled;
  1185. }
  1186. bool ParticleSystem::isActive() const
  1187. {
  1188. return _isActive;
  1189. }
  1190. int ParticleSystem::getTotalParticles() const
  1191. {
  1192. return _totalParticles;
  1193. }
  1194. void ParticleSystem::setTotalParticles(int var)
  1195. {
  1196. CCASSERT( var <= _allocatedParticles, "Particle: resizing particle array only supported for quads");
  1197. _totalParticles = var;
  1198. }
  1199. const BlendFunc& ParticleSystem::getBlendFunc() const
  1200. {
  1201. return _blendFunc;
  1202. }
  1203. void ParticleSystem::setBlendFunc(const BlendFunc &blendFunc)
  1204. {
  1205. if( _blendFunc.src != blendFunc.src || _blendFunc.dst != blendFunc.dst ) {
  1206. _blendFunc = blendFunc;
  1207. this->updateBlendFunc();
  1208. }
  1209. }
  1210. bool ParticleSystem::isAutoRemoveOnFinish() const
  1211. {
  1212. return _isAutoRemoveOnFinish;
  1213. }
  1214. void ParticleSystem::setAutoRemoveOnFinish(bool var)
  1215. {
  1216. _isAutoRemoveOnFinish = var;
  1217. }
  1218. // ParticleSystem - methods for batchNode rendering
  1219. ParticleBatchNode* ParticleSystem::getBatchNode(void) const
  1220. {
  1221. return _batchNode;
  1222. }
  1223. void ParticleSystem::setBatchNode(ParticleBatchNode* batchNode)
  1224. {
  1225. if( _batchNode != batchNode ) {
  1226. _batchNode = batchNode; // weak reference
  1227. if( batchNode ) {
  1228. //each particle needs a unique index
  1229. for (int i = 0; i < _totalParticles; i++)
  1230. {
  1231. _particleData.atlasIndex[i] = i;
  1232. }
  1233. }
  1234. }
  1235. }
  1236. //don't use a transform matrix, this is faster
  1237. void ParticleSystem::setScale(float s)
  1238. {
  1239. _transformSystemDirty = true;
  1240. Node::setScale(s);
  1241. }
  1242. void ParticleSystem::setRotation(float newRotation)
  1243. {
  1244. _transformSystemDirty = true;
  1245. Node::setRotation(newRotation);
  1246. }
  1247. void ParticleSystem::setScaleX(float newScaleX)
  1248. {
  1249. _transformSystemDirty = true;
  1250. Node::setScaleX(newScaleX);
  1251. }
  1252. void ParticleSystem::setScaleY(float newScaleY)
  1253. {
  1254. _transformSystemDirty = true;
  1255. Node::setScaleY(newScaleY);
  1256. }
  1257. void ParticleSystem::start()
  1258. {
  1259. resetSystem();
  1260. }
  1261. void ParticleSystem::stop()
  1262. {
  1263. stopSystem();
  1264. }
  1265. bool ParticleSystem::isPaused() const
  1266. {
  1267. return _paused;
  1268. }
  1269. void ParticleSystem::pauseEmissions()
  1270. {
  1271. _paused = true;
  1272. }
  1273. void ParticleSystem::resumeEmissions()
  1274. {
  1275. _paused = false;
  1276. }
  1277. std::function<void(const std::string&, ParticleSystem*)> ParticleSystem::setCbOnExit(std::function<void(const std::string&, ParticleSystem*)> cb) {
  1278. std::function<void(const std::string&, ParticleSystem*)> old = _cbOnExit;
  1279. _cbOnExit = cb;
  1280. return old;
  1281. }
  1282. NS_CC_END