ParticleTechnique.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414
  1. #include "core/particles/ParticleTechnique.h"
  2. #include <OgreLogManager.h>
  3. #include <OgreStringConverter.h>
  4. #include "core/particles/ParticleSystemManager.h"
  5. #include "core/particles/ParticleVisual.h"
  6. //------------------------------------------------------------------------------
  7. ParticleTechnique::ParticleTechnique():
  8. m_Renderer(nullptr),
  9. m_VisualParticleQuota(10),
  10. m_VisualParticlePoolIncreased(false),
  11. m_EmittedEmitterQuota(10),
  12. m_ParticleEmitterPoolIncreased(false)
  13. {
  14. }
  15. //------------------------------------------------------------------------------
  16. ParticleTechnique::~ParticleTechnique()
  17. {
  18. DestroyAllEmitters();
  19. DestroyRenderer();
  20. }
  21. //------------------------------------------------------------------------------
  22. void
  23. ParticleTechnique::CopyAttributesTo(ParticleTechnique* technique)
  24. {
  25. Ogre::LogManager::getSingletonPtr()->logMessage("ParticleTechnique::CopyAttributesTo start");
  26. // Destroy the emitters, affectors, etc.
  27. technique->DestroyAllEmitters();
  28. Ogre::LogManager::getSingletonPtr()->logMessage("ParticleTechnique::CopyAttributesTo 1");
  29. technique->DestroyRenderer();
  30. technique->m_ParentSystem = m_ParentSystem;
  31. Ogre::LogManager::getSingletonPtr()->logMessage("ParticleTechnique::CopyAttributesTo 2");
  32. // Copy the renderer
  33. ParticleRenderer* cloned_renderer = ParticleSystemManager::getSingletonPtr()->CloneRenderer(m_Renderer);
  34. Ogre::LogManager::getSingletonPtr()->logMessage("ParticleTechnique::CopyAttributesTo 3");
  35. technique->SetRenderer(cloned_renderer);
  36. technique->m_VisualParticleQuota = m_VisualParticleQuota;
  37. technique->m_VisualParticlePoolIncreased = false;
  38. Ogre::LogManager::getSingletonPtr()->logMessage("ParticleTechnique::CopyAttributesTo 4");
  39. technique->m_EmittedEmitterQuota = m_EmittedEmitterQuota;
  40. technique->m_ParticleEmitterPoolIncreased = false;
  41. Ogre::LogManager::getSingletonPtr()->logMessage("ParticleTechnique::CopyAttributesTo 5");
  42. // Copy all emitters
  43. ParticleEmitter* cloned_emitter;
  44. for( unsigned int i = 0; i < m_Emitters.size(); ++i )
  45. {
  46. cloned_emitter = ParticleSystemManager::getSingletonPtr()->CloneEmitter( m_Emitters[ i ] );
  47. technique->AddEmitter( cloned_emitter );
  48. }
  49. Ogre::LogManager::getSingletonPtr()->logMessage("ParticleTechnique::CopyAttributesTo end");
  50. }
  51. //------------------------------------------------------------------------------
  52. void
  53. ParticleTechnique::UpdateRenderQueue(Ogre::RenderQueue* queue)
  54. {
  55. if (m_Renderer && m_Renderer->IsRendererInitialised())
  56. {
  57. m_Renderer->UpdateRenderQueue(queue, m_VisualParticlesPool);
  58. }
  59. }
  60. //------------------------------------------------------------------------------
  61. void
  62. ParticleTechnique::Initialize()
  63. {
  64. if (m_Renderer && m_Renderer->IsRendererInitialised() == false)
  65. {
  66. m_Renderer->Initialize();
  67. }
  68. // Create new visual particles if the quota has been increased
  69. if (m_VisualParticlePoolIncreased == false)
  70. {
  71. int old_size = m_VisualParticlesPool.GetSize();
  72. if (m_VisualParticleQuota > old_size)
  73. {
  74. // Create new visual particles
  75. VisualParticle* particle = nullptr;
  76. for (int i = old_size; i < m_VisualParticleQuota; ++i)
  77. {
  78. particle = new VisualParticle();
  79. m_VisualParticlesPool.AddElement(particle);
  80. m_VisualParticles.push_back(particle);
  81. }
  82. }
  83. m_VisualParticlePoolIncreased = true;
  84. }
  85. // Create new emitter particles if the quota has been increased
  86. if (m_ParticleEmitterPoolIncreased == false)
  87. {
  88. int old_size = m_ParticleEmitterPool.GetSize();
  89. if (m_EmittedEmitterQuota > old_size)
  90. {
  91. // Create new emitters, based on the already created emitters in the technique and which are marked for emission.
  92. int numberOfEmittedEmitters = GetNumEmittableEmitters();
  93. if (numberOfEmittedEmitters == 0)
  94. {
  95. return;
  96. }
  97. ParticleEmitter* existing_emitter = 0;
  98. ParticleEmitter* cloned_emitter = 0;
  99. // Distribute size equally
  100. int increment = m_EmittedEmitterQuota / numberOfEmittedEmitters;
  101. // Run through emitters of the technique
  102. for( unsigned int i = 0; i < m_Emitters.size(); ++i )
  103. {
  104. if( m_Emitters[ i ]->IsEmittable() )
  105. {
  106. // Clone the emitter 'increment' times and add to the pool
  107. for (int j = 0; j < increment; ++j)
  108. {
  109. cloned_emitter = ParticleSystemManager::getSingletonPtr()->CloneEmitter(m_Emitters[i]);
  110. cloned_emitter->SetEmittable(true);
  111. m_ParticleEmitterPool.AddElement(cloned_emitter->GetName(), cloned_emitter);
  112. }
  113. }
  114. }
  115. }
  116. m_ParticleEmitterPoolIncreased = true;
  117. }
  118. }
  119. //------------------------------------------------------------------------------
  120. void
  121. ParticleTechnique::Update(Ogre::Real time_elapsed)
  122. {
  123. Ogre::LogManager::getSingletonPtr()->logMessage("ParticleTechnique::Update START");
  124. // Perform some initialisation type of activities (if needed). This must be done within the update-loop,
  125. // because settings could be changed (i.e. changing quota), which must trigger a re-initialisation.
  126. Ogre::LogManager::getSingletonPtr()->logMessage("ParticleTechnique::Update initialize start");
  127. Initialize();
  128. Ogre::LogManager::getSingletonPtr()->logMessage("ParticleTechnique::Update initialize end");
  129. // Process the emitters
  130. for( unsigned int i = 0; i < m_Emitters.size(); ++i )
  131. {
  132. // emitted particles handled in pool update
  133. if( m_Emitters[ i ]->IsEmittable() == false )
  134. {
  135. Ogre::LogManager::getSingletonPtr()->logMessage("ParticleTechnique::Update emit static emitters");
  136. ExecuteEmitParticles(m_Emitters[i], m_Emitters[i]->CalculateRequestedParticles(time_elapsed), time_elapsed);
  137. }
  138. }
  139. if (m_VisualParticlesPool.IsEmpty() == false)
  140. {
  141. Ogre::LogManager::getSingletonPtr()->logMessage("ParticleTechnique::Update: visual particle started.");
  142. VisualParticle* particle = m_VisualParticlesPool.GetFirst();
  143. while (!m_VisualParticlesPool.End())
  144. {
  145. if (particle != nullptr)
  146. {
  147. Ogre::LogManager::getSingletonPtr()->logMessage("ParticleTechnique::Update found particle with ttl " + Ogre::StringConverter::toString(particle->time_to_live));
  148. if (particle->time_to_live > time_elapsed)
  149. {
  150. Ogre::LogManager::getSingletonPtr()->logMessage("ParticleTechnique::Update update visual start");
  151. particle->Update(time_elapsed);
  152. Ogre::LogManager::getSingletonPtr()->logMessage("ParticleTechnique::Update update visual end");
  153. }
  154. else
  155. {
  156. Ogre::LogManager::getSingletonPtr()->logMessage("ParticleTechnique::Update expire visual start");
  157. particle->InitForExpiration();
  158. m_VisualParticlesPool.LockLatestElement();
  159. Ogre::LogManager::getSingletonPtr()->logMessage("ParticleTechnique::Update expire visual end");
  160. }
  161. // Decrement time to live
  162. particle->time_to_live -= time_elapsed;
  163. }
  164. particle = m_VisualParticlesPool.GetNext();
  165. }
  166. Ogre::LogManager::getSingletonPtr()->logMessage("ParticleTechnique::Update: visual particle finished.");
  167. }
  168. // Process all particles
  169. if (m_ParticleEmitterPool.IsEmpty() == false)
  170. {
  171. Ogre::LogManager::getSingletonPtr()->logMessage("ParticleTechnique::Update: emitter particle started.");
  172. ParticleEmitter* particle = m_ParticleEmitterPool.GetFirst();
  173. while (!m_ParticleEmitterPool.End())
  174. {
  175. if (particle)
  176. {
  177. if (particle->time_to_live > time_elapsed)
  178. {
  179. particle->Update(time_elapsed);
  180. ExecuteEmitParticles(particle, particle->CalculateRequestedParticles(time_elapsed), time_elapsed);
  181. }
  182. else
  183. {
  184. particle->InitForExpiration();
  185. m_ParticleEmitterPool.LockLatestElement();
  186. }
  187. // Decrement time to live
  188. particle->time_to_live -= time_elapsed;
  189. }
  190. particle = m_ParticleEmitterPool.GetNext();
  191. }
  192. Ogre::LogManager::getSingletonPtr()->logMessage("ParticleTechnique::Update: emitter particle finished.");
  193. }
  194. Ogre::LogManager::getSingletonPtr()->logMessage("ParticleTechnique::Update END");
  195. }
  196. //------------------------------------------------------------------------------
  197. ParticleRenderer*
  198. ParticleTechnique::CreateRenderer(const Ogre::String& renderer_type)
  199. {
  200. if (m_Renderer)
  201. {
  202. DestroyRenderer();
  203. }
  204. if (renderer_type != Ogre::StringUtil::BLANK)
  205. {
  206. m_Renderer = ParticleSystemManager::getSingletonPtr()->CreateRenderer(renderer_type);
  207. m_Renderer->SetParentTechnique(this);
  208. m_Renderer->SetRendererInitialised(false);
  209. }
  210. return m_Renderer;
  211. }
  212. //------------------------------------------------------------------------------
  213. void
  214. ParticleTechnique::SetRenderer(ParticleRenderer* renderer)
  215. {
  216. if (m_Renderer)
  217. {
  218. DestroyRenderer();
  219. }
  220. m_Renderer = renderer;
  221. m_Renderer->SetParentTechnique(this);
  222. m_Renderer->SetRendererInitialised(false);
  223. }
  224. //------------------------------------------------------------------------------
  225. void
  226. ParticleTechnique::DestroyRenderer()
  227. {
  228. if (m_Renderer)
  229. {
  230. ParticleSystemManager::getSingletonPtr()->DestroyRenderer(m_Renderer);
  231. m_Renderer = nullptr;
  232. }
  233. }
  234. //------------------------------------------------------------------------------
  235. ParticleEmitter*
  236. ParticleTechnique::CreateEmitter(const Ogre::String& emitter_type)
  237. {
  238. ParticleEmitter* emitter = nullptr;
  239. if (emitter_type != Ogre::StringUtil::BLANK)
  240. {
  241. emitter = ParticleSystemManager::getSingletonPtr()->CreateEmitter(emitter_type);
  242. m_Emitters.push_back(emitter);
  243. emitter->SetParentTechnique(this);
  244. EmissionChange();
  245. }
  246. return emitter;
  247. }
  248. //------------------------------------------------------------------------------
  249. void
  250. ParticleTechnique::AddEmitter(ParticleEmitter* emitter)
  251. {
  252. if (emitter != nullptr)
  253. {
  254. m_Emitters.push_back(emitter);
  255. emitter->SetParentTechnique(this);
  256. EmissionChange();
  257. }
  258. }
  259. //------------------------------------------------------------------------------
  260. void
  261. ParticleTechnique::DestroyAllEmitters()
  262. {
  263. for( unsigned int i = 0; i < m_Emitters.size(); ++i )
  264. {
  265. ParticleSystemManager::getSingletonPtr()->DestroyEmitter(m_Emitters[i]);
  266. }
  267. m_Emitters.clear();
  268. }
  269. //------------------------------------------------------------------------------
  270. int
  271. ParticleTechnique::GetNumEmittableEmitters() const
  272. {
  273. int count = 0;
  274. for( unsigned int i = 0; i < m_Emitters.size(); ++i )
  275. {
  276. if (m_Emitters[i]->IsEmittable())
  277. {
  278. count++;
  279. }
  280. }
  281. return count;
  282. }
  283. //------------------------------------------------------------------------------
  284. void
  285. ParticleTechnique::EmissionChange()
  286. {
  287. // Run through all emitters and set MarkedForEmission to false.
  288. for( unsigned int i = 0; i < m_Emitters.size(); ++i )
  289. {
  290. m_Emitters[i]->SetEmittable(false);
  291. }
  292. // Run through all emitters and determine which objects each one emits.
  293. for( unsigned int i = 0; i < m_Emitters.size(); ++i )
  294. {
  295. Ogre::String name = m_Emitters[i]->GetEmitsName();
  296. if (name != m_Emitters[i]->GetName())
  297. {
  298. // Search the emitter to be emitted
  299. for( unsigned int j = 0; j < m_Emitters.size(); ++j )
  300. {
  301. if (m_Emitters[j]->GetName() == name)
  302. {
  303. m_Emitters[j]->SetEmittable(true);
  304. }
  305. }
  306. }
  307. }
  308. }
  309. //------------------------------------------------------------------------------
  310. void
  311. ParticleTechnique::ExecuteEmitParticles(ParticleEmitter* emitter, int requested, Ogre::Real time_elapsed)
  312. {
  313. // Only proceed if the emitter and technique are enabled
  314. if (emitter->IsEnabled() == false)
  315. {
  316. return;
  317. }
  318. Ogre::LogManager::getSingletonPtr()->logMessage("ParticleTechnique::ExecuteEmitParticles request " + Ogre::StringConverter::toString(requested) + " particles to emit.");
  319. for (int j = 0; j < requested; ++j)
  320. {
  321. // Create a new particle & init using emitter
  322. Particle* particle = nullptr;
  323. switch (emitter->GetEmitsType())
  324. {
  325. case Particle::PT_VISUAL: particle = m_VisualParticlesPool.ReleaseElement(); break;
  326. case Particle::PT_EMITTER: particle = m_ParticleEmitterPool.ReleaseElement(emitter->GetEmitsName()); break;
  327. }
  328. // Return if there is no particle left anymore, or the name cannot be found
  329. if (particle == nullptr)
  330. {
  331. Ogre::LogManager::getSingletonPtr()->logMessage("ParticleTechnique::ExecuteEmitParticles request there is no particles left.");
  332. return;
  333. }
  334. particle->InitForEmission();
  335. // Initialise the particle with data from the emitter.
  336. emitter->InitParticleForEmission(particle);
  337. }
  338. }
  339. //------------------------------------------------------------------------------
  340. void
  341. ParticleTechnique::ResetVisualParticles()
  342. {
  343. for( unsigned int i = 0; i < m_VisualParticles.size(); ++i )
  344. {
  345. m_VisualParticles[i]->additional_data = nullptr;
  346. }
  347. m_VisualParticlesPool.LockAllElements();
  348. }
  349. //------------------------------------------------------------------------------