ZMLParticleSystemQuad.cpp 34 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022
  1. /****************************************************************************
  2. Copyright (c) 2008-2010 Ricardo Quesada
  3. Copyright (c) 2009 Leonardo Kasperavičius
  4. Copyright (c) 2010-2012 cocos2d-x.org
  5. Copyright (c) 2011 Zynga Inc.
  6. Copyright (c) 2013-2017 Chukong Technologies Inc.
  7. http://www.cocos2d-x.org
  8. Permission is hereby granted, free of charge, to any person obtaining a copy
  9. of this software and associated documentation files (the "Software"), to deal
  10. in the Software without restriction, including without limitation the rights
  11. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  12. copies of the Software, and to permit persons to whom the Software is
  13. furnished to do so, subject to the following conditions:
  14. The above copyright notice and this permission notice shall be included in
  15. all copies or substantial portions of the Software.
  16. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  19. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22. THE SOFTWARE.
  23. ****************************************************************************/
  24. //#include "ZMLParticleSystemQuad.h"
  25. #include "ZMLParticleSystemQuad.h"
  26. //#include "ZGHeader.h"
  27. //#include <algorithm>
  28. //#include "2d/CCSpriteFrame.h"
  29. //#include "2d/CCParticleBatchNode.h"
  30. //#include "renderer/CCTextureAtlas.h"
  31. //#include "renderer/ccGLStateCache.h"
  32. //#include "renderer/CCRenderer.h"
  33. //#include "base/CCDirector.h"
  34. //#include "base/CCEventType.h"
  35. //#include "base/CCConfiguration.h"
  36. //#include "base/CCEventListenerCustom.h"
  37. //#include "base/CCEventDispatcher.h"
  38. //#include "base/ccUTF8.h"
  39. //#include "common/CocosConfig.h"
  40. NS_RU_BEGIN
  41. ZMLParticleSystemQuad::ZMLParticleSystemQuad()
  42. :_quads(nullptr)
  43. ,_indices(nullptr)
  44. ,_VAOname(0)
  45. {
  46. m_lightSprite = nullptr;
  47. memset(_buffersVBO, 0, sizeof(_buffersVBO));
  48. _vertexInfo = (PARTICLE_VERTEX_INFO*)malloc(100 * sizeof(PARTICLE_VERTEX_INFO));
  49. memset(_vertexInfo,1,100 * sizeof(PARTICLE_VERTEX_INFO));
  50. }
  51. ZMLParticleSystemQuad::~ZMLParticleSystemQuad()
  52. {
  53. if (m_lightSprite)
  54. {
  55. if (m_lightSprite->isRunning())
  56. {
  57. m_lightSprite->removeFromParent();
  58. }
  59. m_lightSprite->release();
  60. m_lightSprite = nullptr;
  61. }
  62. CC_SAFE_FREE(_vertexInfo);
  63. if (nullptr == _batchNode)
  64. {
  65. CC_SAFE_FREE(_quads);
  66. CC_SAFE_FREE(_indices);
  67. glDeleteBuffers(2, &_buffersVBO[0]);
  68. if (Configuration::getInstance()->supportsShareableVAO())
  69. {
  70. glDeleteVertexArrays(1, &_VAOname);
  71. GL::bindVAO(0);
  72. }
  73. }
  74. }
  75. // implementation ZMLParticleSystemQuad
  76. ZMLParticleSystemQuad * ZMLParticleSystemQuad::create(const std::string& filename)
  77. {
  78. ZMLParticleSystemQuad *ret = new (std::nothrow) ZMLParticleSystemQuad();
  79. if (ret && ret->initWithFile(filename))
  80. {
  81. ret->autorelease();
  82. return ret;
  83. }
  84. CC_SAFE_DELETE(ret);
  85. return ret;
  86. }
  87. ZMLParticleSystemQuad * ZMLParticleSystemQuad::createWithTotalParticles(int numberOfParticles) {
  88. ZMLParticleSystemQuad *ret = new (std::nothrow) ZMLParticleSystemQuad();
  89. if (ret && ret->initWithTotalParticles(numberOfParticles))
  90. {
  91. ret->autorelease();
  92. return ret;
  93. }
  94. CC_SAFE_DELETE(ret);
  95. return ret;
  96. }
  97. ZMLParticleSystemQuad * ZMLParticleSystemQuad::create(ValueMap &dictionary)
  98. {
  99. ZMLParticleSystemQuad *ret = new (std::nothrow) ZMLParticleSystemQuad();
  100. if (ret && ret->initWithDictionary(dictionary))
  101. {
  102. ret->autorelease();
  103. return ret;
  104. }
  105. CC_SAFE_DELETE(ret);
  106. return ret;
  107. }
  108. ZMLParticleSystemQuad* ZMLParticleSystemQuad::createWithJsonString(string jsonStr){
  109. ZMLParticleSystemQuad *ret = new (std::nothrow) ZMLParticleSystemQuad();
  110. if (ret && ret->initWithJsonString(jsonStr))
  111. {
  112. ret->autorelease();
  113. return ret;
  114. }
  115. CC_SAFE_DELETE(ret);
  116. return ret;
  117. }
  118. ZMLParticleSystemQuad* ZMLParticleSystemQuad::createWithJsonFile(string path){
  119. ZMLParticleSystemQuad *ret = new (std::nothrow) ZMLParticleSystemQuad();
  120. if (ret && ret->initWithJsonFile(path))
  121. {
  122. if (ret->getModule(ParticleSystemModuleFlag::TEXTURE_SHEET) == nullptr) {
  123. ret->autoUpdateTexture();
  124. }
  125. ret->_plName = path;
  126. ret->autorelease();
  127. return ret;
  128. }
  129. CC_SAFE_DELETE(ret);
  130. return ret;
  131. }
  132. //implementation ZMLParticleSystemQuad
  133. // overriding the init method
  134. bool ZMLParticleSystemQuad::initWithTotalParticles(int numberOfParticles)
  135. {
  136. // base initialization
  137. if( ParticleSystem::initWithTotalParticles(numberOfParticles) )
  138. {
  139. // allocating data space
  140. if( ! this->allocMemory() ) {
  141. this->release();
  142. return false;
  143. }
  144. initIndices();
  145. if (Configuration::getInstance()->supportsShareableVAO())
  146. {
  147. setupVBOandVAO();
  148. }
  149. else
  150. {
  151. setupVBO();
  152. }
  153. UpdateGLProgramState();
  154. #if CC_ENABLE_CACHE_TEXTURE_DATA
  155. // Need to listen the event only when not use batchnode, because it will use VBO
  156. auto listener = EventListenerCustom::create(EVENT_RENDERER_RECREATED, CC_CALLBACK_1(ZMLParticleSystemQuad::listenRendererRecreated, this));
  157. _eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);
  158. #endif
  159. return true;
  160. }
  161. return false;
  162. }
  163. void ZMLParticleSystemQuad::UpdateGLProgramState()
  164. {
  165. auto fileUtiles = FileUtils::getInstance();
  166. if(_shaderType == SHADER_COLOR)
  167. {
  168. setGLProgramState(GLProgramState::getOrCreateWithGLProgramName(GLProgram::SHADER_NAME_POSITION_TEXTURE_COLOR_NO_MVP));
  169. }else {
  170. static string shaders[] = {"fx_alpha","fx_distort_additive","efx_normalMapped"};
  171. #if PARTICLE_EDITOR_MODE
  172. auto fragmentFullPath = fileUtiles->fullPathForFilename("shaders/" + shaders[_shaderType-1] + ".fsh");
  173. #else
  174. auto fragmentFullPath = fileUtiles->fullPathForFilename(shaders[_shaderType-1] + ".fsh");
  175. #endif
  176. auto fragSource = fileUtiles->getStringFromFile(fragmentFullPath);
  177. #if PARTICLE_EDITOR_MODE
  178. GLProgram* glProgram = GLProgram::createWithByteArrays(ccPositionTextureColor_noMVP_vert, fragSource.c_str());
  179. #else
  180. GLProgram* glProgram = GLProgramCache::getInstance()->getGLProgram(shaders[_shaderType-1]);
  181. #endif
  182. GLProgramState* state = GLProgramState::create(glProgram);
  183. if (_maskName.length() > 0)
  184. {
  185. #if PARTICLE_EDITOR_MODE
  186. auto alphaTexture = Director::getInstance()->getTextureCache()->addImage("img/" + _maskName);
  187. #else
  188. auto alphaTexture = Director::getInstance()->getTextureCache()->addImage(_maskName);
  189. #endif
  190. if (alphaTexture )
  191. {
  192. if (_shaderType != SHADER_NORMAL)
  193. {
  194. Texture2D::TexParams texParams = {GL_LINEAR, GL_LINEAR, GL_REPEAT, GL_REPEAT};
  195. alphaTexture->setTexParameters(texParams);
  196. }
  197. state->setUniformTexture("alphaTexture", alphaTexture);
  198. }
  199. }
  200. state->setUniformFloat("color_power", _colorPower);
  201. if (_shaderType == SHADER_NORMAL)
  202. {
  203. ClightSprite* lightSprite_dft=new ClightSprite();
  204. lightSprite_dft->autorelease();
  205. lightSprite_dft->init("unknown.png");
  206. this->setLightSprite(lightSprite_dft);
  207. lightSprite_dft->setPosition(Vec2(-1000,-1000));
  208. }
  209. setGLProgramState(state);
  210. }
  211. }
  212. void ZMLParticleSystemQuad::SetAlphaTexture(Texture2D* tex)
  213. {
  214. if (_maskName.length() > 0)
  215. {
  216. if (_shaderType != SHADER_NORMAL)
  217. {
  218. Texture2D::TexParams texParams = {GL_LINEAR, GL_LINEAR, GL_REPEAT, GL_REPEAT};
  219. tex->setTexParameters(texParams);
  220. }
  221. auto state = getGLProgramState();
  222. state->setUniformTexture("alphaTexture", tex);
  223. }
  224. }
  225. // pointRect should be in Texture coordinates, not pixel coordinates
  226. void ZMLParticleSystemQuad::initTexCoordsWithRect(const Rect& pointRect, bool isrotaed, Vec2 offset, Vec2 originalSize)
  227. {
  228. // convert to Tex coords
  229. Rect rect = Rect(
  230. pointRect.origin.x * CC_CONTENT_SCALE_FACTOR(),
  231. pointRect.origin.y * CC_CONTENT_SCALE_FACTOR(),
  232. pointRect.size.width * CC_CONTENT_SCALE_FACTOR(),
  233. pointRect.size.height * CC_CONTENT_SCALE_FACTOR());
  234. GLfloat wide = (GLfloat) rect.size.width;
  235. GLfloat high = (GLfloat) rect.size.height;
  236. float rw = rect.size.width;
  237. float rh = rect.size.height;
  238. if (isrotaed)
  239. std::swap(rw, rh);
  240. if (_texture)
  241. {
  242. wide = (GLfloat)_texture->getPixelsWide();
  243. high = (GLfloat)_texture->getPixelsHigh();
  244. }
  245. #if CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL
  246. GLfloat left = (rect.origin.x*2+1) / (wide*2);
  247. GLfloat bottom = (rect.origin.y*2+1) / (high*2);
  248. GLfloat right = left + (rw*2-2) / (wide*2);
  249. GLfloat top = bottom + (rh*2-2) / (high*2);
  250. #else
  251. GLfloat left = rect.origin.x / wide;
  252. GLfloat bottom = rect.origin.y / high;
  253. GLfloat right = left + rw / wide;
  254. GLfloat top = bottom + rh / high;
  255. #endif // ! CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL
  256. // Important. Texture in cocos2d are inverted, so the Y component should be inverted
  257. std::swap(top, bottom);
  258. CCASSERT(_texNumber < 100, "纹理数量超过上限");
  259. if (isrotaed)
  260. {
  261. _vertexInfo[_texNumber].bl.u = left;
  262. _vertexInfo[_texNumber].bl.v = top;
  263. _vertexInfo[_texNumber].br.u = left;
  264. _vertexInfo[_texNumber].br.v = bottom;
  265. _vertexInfo[_texNumber].tl.u = right;
  266. _vertexInfo[_texNumber].tl.v = top;
  267. _vertexInfo[_texNumber].tr.u = right;
  268. _vertexInfo[_texNumber].tr.v = bottom;
  269. }
  270. else
  271. {
  272. _vertexInfo[_texNumber].bl.u = left;
  273. _vertexInfo[_texNumber].bl.v = bottom;
  274. _vertexInfo[_texNumber].br.u = right;
  275. _vertexInfo[_texNumber].br.v = bottom;
  276. _vertexInfo[_texNumber].tl.u = left;
  277. _vertexInfo[_texNumber].tl.v = top;
  278. _vertexInfo[_texNumber].tr.u = right;
  279. _vertexInfo[_texNumber].tr.v = top;
  280. }
  281. if (!offset.isZero()){
  282. // CCLOG("");
  283. }
  284. float originalSizeX_2 = 2 / originalSize.x; // 宽的一半的倒数
  285. float originalSizeY_2 = 2 / originalSize.y;
  286. float x1 = (pointRect.size.width * 0.5 - offset.x) * originalSizeX_2;
  287. float x2 = (pointRect.size.width * 0.5 + offset.x) * originalSizeX_2;
  288. float y1 = (pointRect.size.height * 0.5 - offset.y) * originalSizeY_2;
  289. float y2 = (pointRect.size.height * 0.5 + offset.y) * originalSizeY_2;
  290. _vertexInfo[_texNumber].TexturePercentage.set(x1, x2, y1, y2);
  291. _texNumber++;
  292. }
  293. void ZMLParticleSystemQuad::autoUpdateTexture()
  294. {
  295. Texture2D* mainTex = nullptr;
  296. if (_mainTexName.length() > 0)
  297. {
  298. #if PARTICLE_EDITOR_MODE
  299. mainTex = Director::getInstance()->getTextureCache()->addImage("img/" + _mainTexName);
  300. #else
  301. mainTex = Director::getInstance()->getTextureCache()->addImage(_mainTexName);
  302. #endif
  303. if (FileUtils::getInstance()->fullPathForFilename(_mainTexName).size() == 0){//判断粒子图片是否在大图中
  304. SpriteFrame* frame = SpriteFrameCache::getInstance()->getSpriteFrameByName(_mainTexName);
  305. this->addSpriteFrame(frame);
  306. } else {
  307. setTexture(mainTex);
  308. }
  309. }
  310. }
  311. void ZMLParticleSystemQuad::updateTexCoords()
  312. {
  313. if (_texture)
  314. {
  315. // 走小图
  316. const Size& s = _texture->getContentSize();
  317. // bool isrotaed, Vec2 offset, Vec2 originalSize
  318. initTexCoordsWithRect(Rect(0, 0, s.width, s.height),false,Vec2(0,0),Vec2(s.width, s.height));
  319. }
  320. }
  321. void ZMLParticleSystemQuad::setTextureWithRect(Texture2D *texture, const Rect& rect, bool isrotaed, Vec2 offset, Vec2 originalSize)
  322. {
  323. // Only update the texture if is different from the current one
  324. if( !_texture)
  325. {
  326. ParticleSystem::setTexture(texture);
  327. } else {
  328. // || texture->getName() != _texture->getName()
  329. CCASSERT(texture->getName() == _texture->getName(), "不能瞎几把换纹理");
  330. }
  331. this->initTexCoordsWithRect(rect,isrotaed,offset,originalSize);
  332. }
  333. void ZMLParticleSystemQuad::setTexture(Texture2D* texture)
  334. {
  335. const Size& s = texture->getContentSize();
  336. this->setTextureWithRect(texture, Rect(0, 0, s.width, s.height),false,Vec2(0,0),Vec2(s.width, s.height));
  337. }
  338. void ZMLParticleSystemQuad::addSpriteFrame(SpriteFrame *spriteFrame){
  339. bool isrotaed = spriteFrame->isRotated();
  340. Vec2 offset = spriteFrame->getOffset();
  341. Vec2 originalSize = spriteFrame->getOriginalSize();
  342. auto pointRect = spriteFrame->getRect();
  343. this->setTextureWithRect(spriteFrame->getTexture(), pointRect,isrotaed,offset,originalSize);
  344. }
  345. void ZMLParticleSystemQuad::addSpriteFrame(const std::string &spriteFrameName){
  346. CCASSERT(!spriteFrameName.empty(), "spriteFrameName must not be empty");
  347. if (spriteFrameName.empty())
  348. {
  349. return;
  350. }
  351. SpriteFrameCache *cache = SpriteFrameCache::getInstance();
  352. SpriteFrame *spriteFrame = cache->getSpriteFrameByName(spriteFrameName);
  353. if (CocosConfig::getAutoAddSingleImage2Cache()) {
  354. if (spriteFrame == nullptr)
  355. {
  356. Texture2D * texture = Director::getInstance()->getTextureCache()->addImage(spriteFrameName.c_str());
  357. if(texture != nullptr)
  358. {
  359. Rect bounds = Rect(0, 0, texture->getContentSize().width, texture->getContentSize().height);
  360. spriteFrame = SpriteFrame::createWithTexture(texture, bounds);
  361. cache->addSpriteFrame(spriteFrame, spriteFrameName.c_str());
  362. }
  363. }
  364. }
  365. CCASSERT(spriteFrame, std::string("Invalid spriteFrameName :").append(spriteFrameName).c_str());
  366. addSpriteFrame(spriteFrame);
  367. }
  368. void ZMLParticleSystemQuad::initIndices()
  369. {
  370. for(int i = 0; i < _totalParticles; ++i)
  371. {
  372. const unsigned int i6 = i*6;
  373. const unsigned int i4 = i*4;
  374. _indices[i6+0] = (GLushort) i4+0;
  375. _indices[i6+1] = (GLushort) i4+1;
  376. _indices[i6+2] = (GLushort) i4+2;
  377. _indices[i6+5] = (GLushort) i4+1;
  378. _indices[i6+4] = (GLushort) i4+2;
  379. _indices[i6+3] = (GLushort) i4+3;
  380. }
  381. }
  382. inline void updatePosWithParticle(V3F_C4B_T2F_Quad *quad, const Vec3& newPosition, float rotation, float sizeWidth, float sizeHeigh, Vec4 texturePercentage)
  383. {
  384. // vertices
  385. GLfloat sizeWidth_2 = sizeWidth/2;
  386. GLfloat sizeHeigh_2 = sizeHeigh/2;
  387. GLfloat x1 = -sizeWidth_2 * texturePercentage.x;
  388. GLfloat y1 = -sizeHeigh_2 * texturePercentage.z;
  389. GLfloat x2 = sizeWidth_2 * texturePercentage.y;
  390. GLfloat y2 = sizeHeigh_2 * texturePercentage.w;
  391. GLfloat x = newPosition.x;
  392. GLfloat y = newPosition.y;
  393. GLfloat z = newPosition.z;
  394. GLfloat r = (GLfloat)-CC_DEGREES_TO_RADIANS(rotation);
  395. GLfloat cr = cosf(r);
  396. GLfloat sr = sinf(r);
  397. GLfloat ax = x1 * cr - y1 * sr + x;
  398. GLfloat ay = x1 * sr + y1 * cr + y;
  399. GLfloat bx = x2 * cr - y1 * sr + x;
  400. GLfloat by = x2 * sr + y1 * cr + y;
  401. GLfloat cx = x2 * cr - y2 * sr + x;
  402. GLfloat cy = x2 * sr + y2 * cr + y;
  403. GLfloat dx = x1 * cr - y2 * sr + x;
  404. GLfloat dy = x1 * sr + y2 * cr + y;
  405. // bottom-left
  406. quad->bl.vertices.x = ax;
  407. quad->bl.vertices.y = ay;
  408. quad->bl.vertices.z = z;
  409. // bottom-right vertex:
  410. quad->br.vertices.x = bx;
  411. quad->br.vertices.y = by;
  412. quad->br.vertices.z = z;
  413. // top-left vertex:
  414. quad->tl.vertices.x = dx;
  415. quad->tl.vertices.y = dy;
  416. quad->tl.vertices.z = z;
  417. // top-right vertex:
  418. quad->tr.vertices.x = cx;
  419. quad->tr.vertices.y = cy;
  420. quad->tr.vertices.z = z;
  421. }
  422. void ZMLParticleSystemQuad::updateParticleQuads()
  423. {
  424. if (_particleCount <= 0) {
  425. return;
  426. }
  427. Vec2 currentPosition;
  428. if (_positionType == PositionType::FREE)
  429. {
  430. currentPosition = this->convertToWorldSpace(Vec2::ZERO);
  431. }
  432. else if (_positionType == PositionType::RELATIVE)
  433. {
  434. currentPosition = _position;
  435. }
  436. V3F_C4B_T2F_Quad *startQuad;
  437. Vec2 pos = Vec2::ZERO;
  438. if (_batchNode)
  439. {
  440. V3F_C4B_T2F_Quad *batchQuads = _batchNode->getTextureAtlas()->getQuads();
  441. startQuad = &(batchQuads[_atlasIndex]);
  442. pos = _position;
  443. }
  444. else
  445. {
  446. startQuad = &(_quads[0]);
  447. }
  448. if( _positionType == PositionType::FREE )
  449. {
  450. Vec3 p1(currentPosition.x, currentPosition.y, 0);
  451. Mat4 worldToNodeTM = getWorldToNodeTransform();
  452. worldToNodeTM.transformPoint(&p1);
  453. Vec3 p2;
  454. Vec2 newPos;
  455. Vec3 newPos2;
  456. float* startX = _particleData.startPosX;
  457. float* startY = _particleData.startPosY;
  458. float* x = _particleData.posx;
  459. float* y = _particleData.posy;
  460. float* z = _particleDataExpansion.posz;
  461. int* texIndex = _particleDataExpansion.textureIndex;
  462. float* r = _particleData.rotation;
  463. float* sw = _particleDataExpansion.sizeWidth;
  464. float* sh = _particleDataExpansion.sizeHeight;
  465. V3F_C4B_T2F_Quad* quadStart = startQuad;
  466. for (int i = 0 ; i < _particleCount; ++i, ++startX, ++startY, ++x, ++y, ++z, ++quadStart, ++sw, ++sh, ++r, ++texIndex)
  467. {
  468. p2.set(*startX, *startY, 0);
  469. worldToNodeTM.transformPoint(&p2);
  470. newPos.set(*x,*y);
  471. p2 = p1 - p2;
  472. newPos.x -= p2.x - pos.x;
  473. newPos.y -= p2.y - pos.y;
  474. newPos2.set(newPos.x, newPos.y, *z);
  475. int index = *texIndex;
  476. Vec4 texturePercentage = _vertexInfo[index].TexturePercentage;
  477. updatePosWithParticle(quadStart, newPos2, *r, *sw, *sh, texturePercentage);
  478. }
  479. }
  480. else if( _positionType == PositionType::RELATIVE )
  481. {
  482. Vec2 newPos;
  483. Vec3 newPos2;
  484. float* startX = _particleData.startPosX;
  485. float* startY = _particleData.startPosY;
  486. float* x = _particleData.posx;
  487. float* y = _particleData.posy;
  488. float* z = _particleDataExpansion.posz;
  489. int* texIndex = _particleDataExpansion.textureIndex;
  490. float* r = _particleData.rotation;
  491. float* sw = _particleDataExpansion.sizeWidth;
  492. float* sh = _particleDataExpansion.sizeHeight;
  493. V3F_C4B_T2F_Quad* quadStart = startQuad;
  494. for (int i = 0 ; i < _particleCount; ++i, ++startX, ++startY, ++x, ++y, ++z, ++quadStart, ++sw, ++sh, ++r, ++texIndex)
  495. {
  496. newPos.set(*x, *y);
  497. newPos.x = *x - (currentPosition.x - *startX);
  498. newPos.y = *y - (currentPosition.y - *startY);
  499. newPos += pos;
  500. newPos2.set(newPos.x, newPos.y, *z);
  501. int index = *texIndex;
  502. Vec4 texturePercentage = _vertexInfo[index].TexturePercentage;
  503. updatePosWithParticle(quadStart, newPos2, *r, *sw, *sh, texturePercentage);
  504. }
  505. }
  506. else
  507. {
  508. Vec2 newPos;
  509. Vec3 newPos2;
  510. float* startX = _particleData.startPosX;
  511. float* startY = _particleData.startPosY;
  512. float* x = _particleData.posx;
  513. float* y = _particleData.posy;
  514. float* z = _particleDataExpansion.posz;
  515. int* texIndex = _particleDataExpansion.textureIndex;
  516. float* r = _particleData.rotation;
  517. float* sw = _particleDataExpansion.sizeWidth;
  518. float* sh = _particleDataExpansion.sizeHeight;
  519. V3F_C4B_T2F_Quad* quadStart = startQuad;
  520. for (int i = 0 ; i < _particleCount; ++i, ++startX, ++startY, ++x, ++y, ++z, ++quadStart, ++sw, ++sh, ++r, ++texIndex)
  521. {
  522. newPos.set(*x + pos.x, *y + pos.y);
  523. newPos2.set(newPos.x, newPos.y, *z);
  524. int index = *texIndex;
  525. Vec4 texturePercentage = _vertexInfo[index].TexturePercentage;
  526. updatePosWithParticle(quadStart, newPos2, *r, *sw, *sh, texturePercentage);
  527. }
  528. }
  529. //set color
  530. if(_opacityModifyRGB)
  531. {
  532. V3F_C4B_T2F_Quad* quad = startQuad;
  533. float* r = _particleData.colorR;
  534. float* g = _particleData.colorG;
  535. float* b = _particleData.colorB;
  536. float* a = _particleData.colorA;
  537. for (int i = 0; i < _particleCount; ++i,++quad,++r,++g,++b,++a)
  538. {
  539. GLubyte colorR = *r * *a * 255 * _displayedColor.r / 255 * _displayedOpacity / 255;
  540. GLubyte colorG = *g * *a * 255 * _displayedColor.g / 255 * _displayedOpacity / 255;
  541. GLubyte colorB = *b * *a * 255 * _displayedColor.b / 255 * _displayedOpacity / 255;
  542. GLubyte colorA = *a * 255 * _displayedOpacity / 255;
  543. quad->bl.colors.set(colorR, colorG, colorB, colorA);
  544. quad->br.colors.set(colorR, colorG, colorB, colorA);
  545. quad->tl.colors.set(colorR, colorG, colorB, colorA);
  546. quad->tr.colors.set(colorR, colorG, colorB, colorA);
  547. }
  548. }
  549. else
  550. {
  551. V3F_C4B_T2F_Quad* quad = startQuad;
  552. float* r = _particleData.colorR;
  553. float* g = _particleData.colorG;
  554. float* b = _particleData.colorB;
  555. float* a = _particleData.colorA;
  556. for (int i = 0; i < _particleCount; ++i,++quad,++r,++g,++b,++a)
  557. {
  558. GLubyte colorR = *r * 255 * _displayedColor.r / 255 * _displayedOpacity / 255;
  559. GLubyte colorG = *g * 255 * _displayedColor.g / 255 * _displayedOpacity / 255;
  560. GLubyte colorB = *b * 255 * _displayedColor.b / 255 * _displayedOpacity / 255;
  561. GLubyte colorA = *a * 255 * _displayedOpacity / 255;
  562. quad->bl.colors.set(colorR, colorG, colorB, colorA);
  563. quad->br.colors.set(colorR, colorG, colorB, colorA);
  564. quad->tl.colors.set(colorR, colorG, colorB, colorA);
  565. quad->tr.colors.set(colorR, colorG, colorB, colorA);
  566. }
  567. }
  568. {
  569. //设置顶点
  570. V3F_C4B_T2F_Quad* quad = startQuad;
  571. int* texIndex = _particleDataExpansion.textureIndex;
  572. for (int i = 0; i < _particleCount; ++i, ++quad, ++texIndex) {
  573. int index = *texIndex;
  574. quad->bl.texCoords.u = _vertexInfo[index].bl.u;
  575. quad->bl.texCoords.v = _vertexInfo[index].bl.v;
  576. // bottom-right vertex:
  577. quad->br.texCoords.u = _vertexInfo[index].br.u;
  578. quad->br.texCoords.v = _vertexInfo[index].br.v;
  579. // top-left vertex:
  580. quad->tl.texCoords.u = _vertexInfo[index].tl.u;
  581. quad->tl.texCoords.v = _vertexInfo[index].tl.v;
  582. // top-right vertex:
  583. quad->tr.texCoords.u = _vertexInfo[index].tr.u;
  584. quad->tr.texCoords.v = _vertexInfo[index].tr.v;
  585. }
  586. }
  587. }
  588. void ZMLParticleSystemQuad::postStep()
  589. {
  590. glBindBuffer(GL_ARRAY_BUFFER, _buffersVBO[0]);
  591. // Option 1: Sub Data
  592. glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(_quads[0])*_totalParticles, _quads);
  593. // Option 2: Data
  594. // glBufferData(GL_ARRAY_BUFFER, sizeof(quads_[0]) * particleCount, quads_, GL_DYNAMIC_DRAW);
  595. // Option 3: Orphaning + glMapBuffer
  596. // glBufferData(GL_ARRAY_BUFFER, sizeof(_quads[0])*_totalParticles, nullptr, GL_STREAM_DRAW);
  597. // void *buf = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
  598. // memcpy(buf, _quads, sizeof(_quads[0])*_totalParticles);
  599. // glUnmapBuffer(GL_ARRAY_BUFFER);
  600. glBindBuffer(GL_ARRAY_BUFFER, 0);
  601. CHECK_GL_ERROR_DEBUG();
  602. }
  603. void ZMLParticleSystemQuad::onPassUnifoAndBindTex(const Mat4 &transform, uint32_t flags){
  604. // assert(getGLProgram()==m_program);
  605. //----prepare uniform values
  606. Vec4 diffuseM_tmp={m_material.m_diffuse.r,m_material.m_diffuse.g,
  607. m_material.m_diffuse.b,m_material.m_diffuse.a};
  608. Vec4 ambientM_tmp = {m_material.m_ambient.r,m_material.m_ambient.g,m_material.m_ambient.b,m_material.m_ambient.a};
  609. Vec4 diffuseL_tmp={m_lightSprite->getDiffuse().r,m_lightSprite->getDiffuse().g,
  610. m_lightSprite->getDiffuse().b,m_lightSprite->getDiffuse().a};
  611. Vec4 ambientL_tmp={m_lightSprite->getAmbient().r,m_lightSprite->getAmbient().g,
  612. m_lightSprite->getAmbient().b,m_lightSprite->getAmbient().a};
  613. TextureSheetAnimationModule * module = dynamic_cast<TextureSheetAnimationModule*>(getModule(ParticleSystemModuleFlag::TEXTURE_SHEET));
  614. Vec2 contentSize_tmp = Vec2::ONE;
  615. if (module != nullptr)
  616. {
  617. contentSize_tmp = {module->getTileWidth(),module->getTileHeight()};
  618. }else {
  619. contentSize_tmp={getTexture()->getContentSizeInPixels().width,getTexture()->getContentSizeInPixels().height};
  620. }
  621. this->getNodeToParentTransform();//in order this->parentToNodeTransform() got right result, we must call this->getNodeToParentTransform() first, this is a bug of cocos2dx 3.3,see:http://www.cnblogs.com/wantnon/p/4330226.html
  622. Point lightPosInLocalSpace= PointApplyAffineTransform(m_lightSprite->getPosition(),this->getParentToNodeAffineTransform());
  623. Vec4 lightPosInLocalSpace_tmp = {lightPosInLocalSpace.x,lightPosInLocalSpace.y,m_lightSprite->getZ(),1};
  624. getGLProgramState()->setUniformVec4("u_diffuseM", diffuseM_tmp);//("u_diffuseM", 4, diffuseM_tmp);
  625. getGLProgramState()->setUniformVec4("u_ambientM", ambientM_tmp);
  626. getGLProgramState()->setUniformVec4("u_diffuseL", diffuseL_tmp);
  627. getGLProgramState()->setUniformVec4("u_ambientL", ambientL_tmp);
  628. getGLProgramState()->setUniformVec2("u_contentSize", contentSize_tmp);
  629. getGLProgramState()->setUniformVec4("u_lightPosInLocalSpace",lightPosInLocalSpace_tmp);
  630. getGLProgramState()->setUniformFloat("color_power", _colorPower);
  631. // getGLProgramState()->setUniformFloat("u_kBump", _colorPower); // 1 - 4
  632. }
  633. // overriding draw method
  634. void ZMLParticleSystemQuad::draw(Renderer *renderer, const Mat4 &transform, uint32_t flags)
  635. {
  636. //quad command
  637. if(_particleCount > 0)
  638. {
  639. if (_shaderType == SHADER_NORMAL)
  640. {
  641. //passUnifo and bindTex
  642. _passUnifoAndBindTexCommand.init(_globalZOrder);
  643. _passUnifoAndBindTexCommand.func = CC_CALLBACK_0(ZMLParticleSystemQuad::onPassUnifoAndBindTex, this,transform,flags);
  644. Director::getInstance()->getRenderer()->addCommand(&_passUnifoAndBindTexCommand);
  645. }
  646. _quadCommand.init(_globalZOrder, _texture, getGLProgramState(), _blendFunc, _quads, _particleCount, transform, flags);
  647. renderer->addCommand(&_quadCommand);
  648. }
  649. }
  650. void ZMLParticleSystemQuad::setTotalParticles(int tp)
  651. {
  652. // If we are setting the total number of particles to a number higher
  653. // than what is allocated, we need to allocate new arrays
  654. if( tp > _allocatedParticles )
  655. {
  656. // Allocate new memory
  657. size_t quadsSize = sizeof(_quads[0]) * tp * 1;
  658. size_t indicesSize = sizeof(_indices[0]) * tp * 6 * 1;
  659. _particleData.release();
  660. if (!_particleData.init(tp))
  661. {
  662. CCLOG("Particle system: not enough memory");
  663. return;
  664. }
  665. _particleDataExpansion.release();
  666. if( !_particleDataExpansion.init(tp))
  667. {
  668. CCLOG("Particle system: not enough memory");
  669. return ;
  670. }
  671. V3F_C4B_T2F_Quad* quadsNew = (V3F_C4B_T2F_Quad*)realloc(_quads, quadsSize);
  672. GLushort* indicesNew = (GLushort*)realloc(_indices, indicesSize);
  673. if (quadsNew && indicesNew)
  674. {
  675. // Assign pointers
  676. _quads = quadsNew;
  677. _indices = indicesNew;
  678. // Clear the memory
  679. memset(_quads, 0, quadsSize);
  680. memset(_indices, 0, indicesSize);
  681. _allocatedParticles = tp;
  682. }
  683. else
  684. {
  685. // Out of memory, failed to resize some array
  686. if (quadsNew) _quads = quadsNew;
  687. if (indicesNew) _indices = indicesNew;
  688. CCLOG("Particle system: out of memory");
  689. return;
  690. }
  691. _totalParticles = tp;
  692. // Init particles
  693. if (_batchNode)
  694. {
  695. for (int i = 0; i < _totalParticles; i++)
  696. {
  697. _particleData.atlasIndex[i] = i;
  698. }
  699. }
  700. initIndices();
  701. if (Configuration::getInstance()->supportsShareableVAO())
  702. {
  703. setupVBOandVAO();
  704. }
  705. else
  706. {
  707. setupVBO();
  708. }
  709. // fixed http://www.cocos2d-x.org/issues/3990
  710. // Updates texture coords.
  711. updateTexCoords();
  712. }
  713. else
  714. {
  715. _totalParticles = tp;
  716. }
  717. // fixed issue #5762
  718. // reset the emission rate
  719. if(CocosConfig::isCCBParticleUseEmitrate() == false){
  720. setEmissionRate(_totalParticles / _life);
  721. }
  722. resetSystem();
  723. }
  724. void ZMLParticleSystemQuad::setupVBOandVAO()
  725. {
  726. // clean VAO
  727. glDeleteBuffers(2, &_buffersVBO[0]);
  728. glDeleteVertexArrays(1, &_VAOname);
  729. GL::bindVAO(0);
  730. glGenVertexArrays(1, &_VAOname);
  731. GL::bindVAO(_VAOname);
  732. #define kQuadSize sizeof(_quads[0].bl)
  733. glGenBuffers(2, &_buffersVBO[0]);
  734. glBindBuffer(GL_ARRAY_BUFFER, _buffersVBO[0]);
  735. glBufferData(GL_ARRAY_BUFFER, sizeof(_quads[0]) * _totalParticles, _quads, GL_DYNAMIC_DRAW);
  736. // vertices
  737. glEnableVertexAttribArray(GLProgram::VERTEX_ATTRIB_POSITION);
  738. glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_POSITION, 2, GL_FLOAT, GL_FALSE, kQuadSize, (GLvoid*) offsetof( V3F_C4B_T2F, vertices));
  739. // colors
  740. glEnableVertexAttribArray(GLProgram::VERTEX_ATTRIB_COLOR);
  741. glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, kQuadSize, (GLvoid*) offsetof( V3F_C4B_T2F, colors));
  742. // tex coords
  743. glEnableVertexAttribArray(GLProgram::VERTEX_ATTRIB_TEX_COORD);
  744. glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_TEX_COORD, 2, GL_FLOAT, GL_FALSE, kQuadSize, (GLvoid*) offsetof( V3F_C4B_T2F, texCoords));
  745. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _buffersVBO[1]);
  746. glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(_indices[0]) * _totalParticles * 6, _indices, GL_STATIC_DRAW);
  747. // Must unbind the VAO before changing the element buffer.
  748. GL::bindVAO(0);
  749. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
  750. glBindBuffer(GL_ARRAY_BUFFER, 0);
  751. CHECK_GL_ERROR_DEBUG();
  752. }
  753. void ZMLParticleSystemQuad::setupVBO()
  754. {
  755. glDeleteBuffers(2, &_buffersVBO[0]);
  756. glGenBuffers(2, &_buffersVBO[0]);
  757. glBindBuffer(GL_ARRAY_BUFFER, _buffersVBO[0]);
  758. glBufferData(GL_ARRAY_BUFFER, sizeof(_quads[0]) * _totalParticles, _quads, GL_DYNAMIC_DRAW);
  759. glBindBuffer(GL_ARRAY_BUFFER, 0);
  760. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _buffersVBO[1]);
  761. glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(_indices[0]) * _totalParticles * 6, _indices, GL_STATIC_DRAW);
  762. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
  763. CHECK_GL_ERROR_DEBUG();
  764. }
  765. void ZMLParticleSystemQuad::listenRendererRecreated(EventCustom* /*event*/)
  766. {
  767. //when comes to foreground in android, _buffersVBO and _VAOname is a wild handle
  768. //before recreating, we need to reset them to 0
  769. memset(_buffersVBO, 0, sizeof(_buffersVBO));
  770. if (Configuration::getInstance()->supportsShareableVAO())
  771. {
  772. _VAOname = 0;
  773. setupVBOandVAO();
  774. }
  775. else
  776. {
  777. setupVBO();
  778. }
  779. }
  780. bool ZMLParticleSystemQuad::allocMemory()
  781. {
  782. CCASSERT( !_batchNode, "Memory should not be alloced when not using batchNode");
  783. CC_SAFE_FREE(_quads);
  784. CC_SAFE_FREE(_indices);
  785. _quads = (V3F_C4B_T2F_Quad*)malloc(_totalParticles * sizeof(V3F_C4B_T2F_Quad));
  786. _indices = (GLushort*)malloc(_totalParticles * 6 * sizeof(GLushort));
  787. if( !_quads || !_indices)
  788. {
  789. CCLOG("cocos2d: Particle system: not enough memory");
  790. CC_SAFE_FREE(_quads);
  791. CC_SAFE_FREE(_indices);
  792. return false;
  793. }
  794. memset(_quads, 0, _totalParticles * sizeof(V3F_C4B_T2F_Quad));
  795. memset(_indices, 0, _totalParticles * 6 * sizeof(GLushort));
  796. return true;
  797. }
  798. void ZMLParticleSystemQuad::setBatchNode(ParticleBatchNode * batchNode)
  799. {
  800. if( _batchNode != batchNode )
  801. {
  802. ParticleBatchNode* oldBatch = _batchNode;
  803. ParticleSystem::setBatchNode(batchNode);
  804. // NEW: is self render ?
  805. if( ! batchNode )
  806. {
  807. allocMemory();
  808. initIndices();
  809. setTexture(oldBatch->getTexture());
  810. if (Configuration::getInstance()->supportsShareableVAO())
  811. {
  812. setupVBOandVAO();
  813. }
  814. else
  815. {
  816. setupVBO();
  817. }
  818. }
  819. // OLD: was it self render ? cleanup
  820. else if( !oldBatch )
  821. {
  822. // copy current state to batch
  823. V3F_C4B_T2F_Quad *batchQuads = _batchNode->getTextureAtlas()->getQuads();
  824. V3F_C4B_T2F_Quad *quad = &(batchQuads[_atlasIndex] );
  825. memcpy( quad, _quads, _totalParticles * sizeof(_quads[0]) );
  826. CC_SAFE_FREE(_quads);
  827. CC_SAFE_FREE(_indices);
  828. glDeleteBuffers(2, &_buffersVBO[0]);
  829. memset(_buffersVBO, 0, sizeof(_buffersVBO));
  830. if (Configuration::getInstance()->supportsShareableVAO())
  831. {
  832. glDeleteVertexArrays(1, &_VAOname);
  833. GL::bindVAO(0);
  834. _VAOname = 0;
  835. }
  836. }
  837. }
  838. }
  839. ZMLParticleSystemQuad * ZMLParticleSystemQuad::create() {
  840. ZMLParticleSystemQuad *zmlParticleSystemQuad = new (std::nothrow) ZMLParticleSystemQuad();
  841. if (zmlParticleSystemQuad && zmlParticleSystemQuad->init())
  842. {
  843. zmlParticleSystemQuad->autorelease();
  844. return zmlParticleSystemQuad;
  845. }
  846. CC_SAFE_DELETE(zmlParticleSystemQuad);
  847. return nullptr;
  848. }
  849. void ZMLParticleSystemQuad::onExit()
  850. {
  851. if (_cbOnExit != nullptr && _plName.size() > 0) {
  852. _particleCount = 0;
  853. _cbOnExit(_plName, this);
  854. }
  855. ZMLParticleSystem::onExit();
  856. }
  857. void ZMLParticleSystemQuad::setCbOnExit(std::function<void(const std::string&, ZMLParticleSystem*)> cb) {
  858. _cbOnExit = cb;
  859. }
  860. std::string ZMLParticleSystemQuad::getDescription() const
  861. {
  862. return StringUtils::format("<ZMLParticleSystemQuad | Tag = %d, Total Particles = %d>", _tag, _totalParticles);
  863. }
  864. NS_RU_END