part_emt.cpp 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882
  1. /*
  2. ** Command & Conquer Renegade(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /***************************************************************************
  19. *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
  20. ***************************************************************************
  21. * *
  22. * Project Name : G *
  23. * *
  24. * $Archive:: /VSS_Sync/ww3d2/part_emt.cpp $*
  25. * *
  26. * $Author:: Vss_sync $*
  27. * *
  28. * $Modtime:: 10/26/01 2:56p $*
  29. * *
  30. * $Revision:: 14 $*
  31. * *
  32. *-------------------------------------------------------------------------*
  33. * Functions: *
  34. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  35. #include "part_emt.h"
  36. #include "wwdebug.h"
  37. #include "ww3d.h"
  38. #include "assetmgr.h"
  39. #include "part_ldr.h"
  40. #include "w3derr.h"
  41. #include "scene.h"
  42. #include "texture.h"
  43. #include "wwprofile.h"
  44. #include <limits.h>
  45. #include <gcd_lcm.h>
  46. #include "texture.h"
  47. #include "part_ldr.h"
  48. // Global variable which is only used to communicate the worldspace emitter
  49. // velocity from ParticleEmitterClass::Create_New_Particles() to
  50. // ParticleEmitterClass::Initialize_Particle(), for velocity inheritance.
  51. Vector3 InheritedWorldSpaceEmitterVel;
  52. // This debug setting disables particles from being generated
  53. bool ParticleEmitterClass::DebugDisable = false;
  54. // This is used to set the global behavior of emitters...
  55. // Should they be removed from the scene when they complete their
  56. // emissions, or should they stay in the scene. (For editing purposes)
  57. // (gth) 09/17/2000 - particle emitters now have a local RemoveOnComplete flag
  58. // which is initialized to the state of DefaultRemoveOnComplete.
  59. bool ParticleEmitterClass::DefaultRemoveOnComplete = true;
  60. ParticleEmitterClass::ParticleEmitterClass(float emit_rate, unsigned int burst_size,
  61. Vector3Randomizer *pos_rnd, Vector3 base_vel, Vector3Randomizer *vel_rnd, float out_vel,
  62. float vel_inherit_factor,
  63. ParticlePropertyStruct<Vector3> &color,
  64. ParticlePropertyStruct<float> &opacity,
  65. ParticlePropertyStruct<float> &size,
  66. ParticlePropertyStruct<float> &rotation, float orient_rnd,
  67. ParticlePropertyStruct<float> &frames,
  68. ParticlePropertyStruct<float> &blur_times,
  69. Vector3 accel, float max_age, TextureClass *tex, ShaderClass shader, int max_particles,
  70. int max_buffer_size, bool pingpong,int render_mode,int frame_mode,
  71. const W3dEmitterLinePropertiesStruct * line_props
  72. ) :
  73. OneTimeBurstSize(1),
  74. OneTimeBurst(false),
  75. PosRand(pos_rnd),
  76. BaseVel(base_vel * 0.001f),
  77. VelRand(vel_rnd),
  78. OutwardVel(out_vel * 0.001f),
  79. VelInheritFactor(vel_inherit_factor),
  80. EmitRemain(0U),
  81. PrevQ(true),
  82. PrevOrig(0.0, 0.0, 0.0),
  83. Active(false),
  84. FirstTime(true),
  85. ParticlesLeft(max_particles),
  86. MaxParticles(max_particles),
  87. IsComplete(false),
  88. RemoveOnComplete(DefaultRemoveOnComplete),
  89. NameString(NULL),
  90. UserString(NULL),
  91. IsInScene(false)
  92. {
  93. EmitRate = emit_rate > 0.0f ? (unsigned int)(1000.0f / emit_rate) : 1000U;
  94. BurstSize = burst_size != 0 ? burst_size : 1;
  95. max_age = max_age > 0.0f ? max_age : 1.0f;
  96. VelRand->Scale(0.001f);
  97. // The maximum number of particles is determined by the emission rate, burst size and lifetime.
  98. // However, it is capped both by the particle cap and by the maximum buffer size, if these are
  99. // active.
  100. int max_num = BurstSize * emit_rate * (max_age + 1);
  101. if (max_particles > 0) max_num = MIN(max_num, max_particles);
  102. if (max_buffer_size > 0) max_num = MIN(max_num, max_buffer_size);
  103. max_num = MAX(max_num, 2); // max_num of 1 causes problems
  104. Buffer = new ParticleBufferClass(this, max_num, color, opacity, size, rotation, orient_rnd,
  105. frames, blur_times, accel/1000000.0f,max_age, tex, shader, pingpong, render_mode, frame_mode,
  106. line_props);
  107. SET_REF_OWNER( Buffer );
  108. BufferSceneNeeded = true;
  109. NameString = ::_strdup ("ParticleEmitter");
  110. }
  111. ParticleEmitterClass::ParticleEmitterClass(const ParticleEmitterClass & src) :
  112. IsInScene(false),
  113. RenderObjClass(src)
  114. {
  115. EmitRate = src.EmitRate;
  116. BurstSize = src.BurstSize;
  117. OneTimeBurstSize = src.OneTimeBurstSize;
  118. OneTimeBurst = src.OneTimeBurst;
  119. if (src.PosRand) {
  120. PosRand = src.PosRand->Clone();
  121. } else {
  122. PosRand = NULL;
  123. }
  124. BaseVel = src.BaseVel;
  125. if (src.VelRand) {
  126. VelRand = src.VelRand->Clone();
  127. } else {
  128. VelRand = NULL;
  129. }
  130. OutwardVel = src.OutwardVel;
  131. VelInheritFactor = src.VelInheritFactor;
  132. EmitRemain = src.EmitRemain;
  133. PrevQ = src.PrevQ;
  134. PrevOrig = src.PrevOrig;
  135. MaxParticles = src.MaxParticles;
  136. ParticlesLeft = src.ParticlesLeft;
  137. Buffer = (ParticleBufferClass *) src.Buffer->Clone();
  138. Buffer->Set_Emitter(this);
  139. SET_REF_OWNER( Buffer );
  140. BufferSceneNeeded = true;
  141. Active = true; // default to on
  142. FirstTime = true;
  143. IsComplete = false;
  144. NameString = ::_strdup (src.NameString);
  145. }
  146. ParticleEmitterClass & ParticleEmitterClass::operator = (const ParticleEmitterClass & that)
  147. {
  148. RenderObjClass::operator = (that);
  149. if (this != &that) {
  150. assert(0); // TODO: if you hit this assert, please implement me !!!;-)
  151. }
  152. return * this;
  153. }
  154. ParticleEmitterClass::~ParticleEmitterClass(void)
  155. {
  156. Buffer->Emitter_Is_Dead();
  157. Buffer->Release_Ref();
  158. if (PosRand != NULL) {
  159. delete PosRand;
  160. PosRand = NULL;
  161. }
  162. if (VelRand != NULL) {
  163. delete VelRand;
  164. VelRand = NULL;
  165. }
  166. if (NameString != NULL) {
  167. ::free (NameString);
  168. NameString = NULL;
  169. }
  170. return ;
  171. }
  172. ParticleEmitterClass *
  173. ParticleEmitterClass::Create_From_Definition (const ParticleEmitterDefClass &definition)
  174. {
  175. // Assume failure
  176. ParticleEmitterClass *pemitter = NULL;
  177. // Attempt to load the texture for this emitter
  178. const char *ptexture_filename = definition.Get_Texture_Filename ();
  179. TextureClass *ptexture = NULL;
  180. if (ptexture_filename && ptexture_filename[0]) {
  181. ptexture = WW3DAssetManager::Get_Instance()->Get_Texture(
  182. ptexture_filename,
  183. TextureClass::MIP_LEVELS_ALL,
  184. WW3D_FORMAT_UNKNOWN);
  185. // false); // no compression for particle textures!
  186. }
  187. ShaderClass shader;
  188. definition.Get_Shader (shader);
  189. if (WW3DAssetManager::Get_Instance()->Get_Activate_Fog_On_Load()) {
  190. shader.Enable_Fog ("ParticleEmitterClass");
  191. }
  192. /*if (ptexture) {
  193. // If texture has an alpha channel do alpha blending instead of additive
  194. // (which is the default for point groups):
  195. srTextureIFace::Dimensions dimensions;
  196. ptexture->getDimensions(dimensions);
  197. if (dimensions.pixelFormat.aBits > 0) {
  198. shader = ShaderClass::_PresetAlphaSpriteShader;
  199. }
  200. }*/
  201. //
  202. // Peek at the definition's keyframes
  203. //
  204. ParticlePropertyStruct<Vector3> color_keys;
  205. ParticlePropertyStruct<float> opacity_keys;
  206. ParticlePropertyStruct<float> size_keys;
  207. ParticlePropertyStruct<float> rotation_keys;
  208. ParticlePropertyStruct<float> frame_keys;
  209. ParticlePropertyStruct<float> blur_time_keys;
  210. definition.Get_Color_Keyframes (color_keys);
  211. definition.Get_Opacity_Keyframes (opacity_keys);
  212. definition.Get_Size_Keyframes (size_keys);
  213. definition.Get_Rotation_Keyframes (rotation_keys);
  214. definition.Get_Frame_Keyframes (frame_keys);
  215. definition.Get_Blur_Time_Keyframes (blur_time_keys);
  216. //
  217. // Create the emitter
  218. //
  219. pemitter = NEW_REF( ParticleEmitterClass, ( definition.Get_Emission_Rate (),
  220. definition.Get_Burst_Size (),
  221. definition.Get_Creation_Volume (),
  222. definition.Get_Velocity (),
  223. definition.Get_Velocity_Random (),
  224. definition.Get_Outward_Vel (),
  225. definition.Get_Vel_Inherit (),
  226. color_keys,
  227. opacity_keys,
  228. size_keys,
  229. rotation_keys,
  230. definition.Get_Initial_Orientation_Random(),
  231. frame_keys,
  232. blur_time_keys,
  233. definition.Get_Acceleration (),
  234. definition.Get_Lifetime (),
  235. ptexture,
  236. shader,
  237. definition.Get_Max_Emissions (),
  238. 0,
  239. false,
  240. definition.Get_Render_Mode (),
  241. definition.Get_Frame_Mode (),
  242. definition.Get_Line_Properties ()) );
  243. if (color_keys.KeyTimes != NULL) delete [] color_keys.KeyTimes;
  244. if (color_keys.Values != NULL) delete [] color_keys.Values;
  245. if (opacity_keys.KeyTimes != NULL) delete [] opacity_keys.KeyTimes;
  246. if (opacity_keys.Values != NULL) delete [] opacity_keys.Values;
  247. if (size_keys.KeyTimes != NULL) delete [] size_keys.KeyTimes;
  248. if (size_keys.Values != NULL) delete [] size_keys.Values;
  249. if (rotation_keys.KeyTimes != NULL) delete [] rotation_keys.KeyTimes;
  250. if (rotation_keys.Values != NULL) delete [] rotation_keys.Values;
  251. if (frame_keys.KeyTimes != NULL) delete [] frame_keys.KeyTimes;
  252. if (frame_keys.Values != NULL) delete [] frame_keys.Values;
  253. if (blur_time_keys.KeyTimes != NULL) delete [] blur_time_keys.KeyTimes;
  254. if (blur_time_keys.Values != NULL) delete [] blur_time_keys.Values;
  255. // Pass the name along to the emitter
  256. pemitter->Set_Name (definition.Get_Name ());
  257. // release our reference to particle texture.
  258. if (ptexture) {
  259. REF_PTR_RELEASE(ptexture);
  260. ptexture = 0;
  261. }
  262. // Return a pointer to the new emitter
  263. return pemitter;
  264. }
  265. RenderObjClass * ParticleEmitterClass::Clone(void) const
  266. {
  267. return new ParticleEmitterClass(*this);
  268. }
  269. void ParticleEmitterClass::Restart(void)
  270. {
  271. // calling Start will cause all internal counters to reset
  272. Start();
  273. }
  274. void ParticleEmitterClass::Notify_Added(SceneClass * scene)
  275. {
  276. RenderObjClass::Notify_Added(scene);
  277. scene->Register(this,SceneClass::ON_FRAME_UPDATE);
  278. if (FirstTime == false) {
  279. Active = true;
  280. }
  281. IsInScene = true;
  282. }
  283. void ParticleEmitterClass::Notify_Removed(SceneClass * scene)
  284. {
  285. scene->Unregister(this,SceneClass::ON_FRAME_UPDATE);
  286. RenderObjClass::Notify_Removed(scene);
  287. Active = false;
  288. IsInScene = false;
  289. //Buffer->Emitter_Is_Dead();
  290. }
  291. // Scales the size of all particles and effects positions/velocities of
  292. // particles emitted after the Scale() call (but not before)
  293. void ParticleEmitterClass::Scale(float scale)
  294. {
  295. // Scale all velosity and position parameters
  296. if (PosRand) PosRand->Scale(scale);
  297. BaseVel *= scale;
  298. if (VelRand) VelRand->Scale(scale);
  299. OutwardVel *= scale;
  300. // Scale sizes of all particles
  301. Buffer->Scale(scale);
  302. }
  303. // Put particle buffer in scene if this is the first time (clunky code
  304. // - hopefully can be rewritten more cleanly in future)...
  305. void ParticleEmitterClass::On_Frame_Update(void)
  306. {
  307. if (Active && !IsComplete) {
  308. if (FirstTime) {
  309. // The particle buffer doesn't have a valid Scene yet - the emitter
  310. // finds out what scene it belongs to (goes up the container tree
  311. // until it finds a non-NULL Scene), and then adds the particle
  312. // buffer to it.
  313. if ( BufferSceneNeeded ) {
  314. if (Is_In_Scene()) {
  315. Buffer->Add(Scene);
  316. BufferSceneNeeded = false;
  317. } else {
  318. return;
  319. }
  320. }
  321. BufferSceneNeeded = false;
  322. // Initialize previous transform:
  323. PrevQ = Build_Quaternion(Get_Transform());
  324. PrevOrig = Get_Transform().Get_Translation();
  325. FirstTime = false;
  326. }
  327. }
  328. if (Is_Complete()) {
  329. if (Is_In_Scene() && Is_Remove_On_Complete_Enabled()) {
  330. Scene->Register(this,SceneClass::RELEASE);
  331. }
  332. }
  333. }
  334. void ParticleEmitterClass::Reset(void)
  335. {
  336. // Note: This flag needs to be set first thing, otherwise
  337. // getting the transform will result in an 'update_x' call
  338. // which in turn results in a 'Set_Animation_Hidden' call, which
  339. // in turn will cause the Update_Visibilty function to call
  340. // Start(). This won't cause a stack overflow like in Start
  341. // but it would do some extra work.
  342. Active = true;
  343. // Initialize previous transform:
  344. PrevQ = Build_Quaternion(Get_Transform());
  345. PrevOrig = Get_Transform().Get_Translation();
  346. // Reset the number of particles to emit
  347. ParticlesLeft = MaxParticles;
  348. EmitRemain = 0;
  349. IsComplete = false;
  350. }
  351. void ParticleEmitterClass::Start(void)
  352. {
  353. // Note: This flag needs to be set first thing, otherwise
  354. // getting the transform will result in an 'update_x' call
  355. // which in turn results in a 'Set_Animation_Hidden' call, which
  356. // in turn will cause the Update_Visibilty function to call
  357. // this method. And then... Stack Overflow! ;)
  358. Active = true;
  359. // Initialize previous transform:
  360. PrevQ = Build_Quaternion(Get_Transform());
  361. PrevOrig = Get_Transform().Get_Translation();
  362. // Reset the number of particles to emit (if necessary)
  363. if (IsComplete == true) {
  364. ParticlesLeft = MaxParticles;
  365. IsComplete = false;
  366. }
  367. }
  368. void ParticleEmitterClass::Stop(void)
  369. {
  370. Active = false;
  371. }
  372. bool ParticleEmitterClass::Is_Stopped(void)
  373. {
  374. return (Active == false);
  375. }
  376. void ParticleEmitterClass::Set_Position_Randomizer(Vector3Randomizer *rand)
  377. {
  378. if (PosRand) {
  379. delete PosRand;
  380. PosRand =NULL;
  381. }
  382. PosRand = rand;
  383. }
  384. void ParticleEmitterClass::Set_Velocity_Randomizer(Vector3Randomizer *rand)
  385. {
  386. if (VelRand) {
  387. delete VelRand;
  388. VelRand =NULL;
  389. }
  390. VelRand = rand;
  391. if (VelRand) {
  392. VelRand->Scale(0.001f); // Convert from seconds to ms
  393. }
  394. }
  395. Vector3Randomizer *ParticleEmitterClass::Get_Creation_Volume (void) const
  396. {
  397. Vector3Randomizer *randomizer = NULL;
  398. if (PosRand != NULL) {
  399. randomizer = PosRand->Clone ();
  400. //randomizer->Scale (1000.0F);
  401. }
  402. return randomizer;
  403. }
  404. Vector3Randomizer *ParticleEmitterClass::Get_Velocity_Random (void) const
  405. {
  406. Vector3Randomizer *randomizer = NULL;
  407. if (VelRand != NULL) {
  408. randomizer = VelRand->Clone ();
  409. randomizer->Scale (1000.0F);
  410. }
  411. return randomizer;
  412. }
  413. void ParticleEmitterClass::Set_Base_Velocity(const Vector3& base_vel)
  414. {
  415. BaseVel = base_vel * 0.001f; // Convert from seconds to ms
  416. }
  417. void ParticleEmitterClass::Set_Outwards_Velocity(float out_vel)
  418. {
  419. OutwardVel = out_vel * 0.001f; // Convert from seconds to ms
  420. }
  421. void ParticleEmitterClass::Set_Velocity_Inheritance_Factor(float inh_factor)
  422. {
  423. VelInheritFactor = inh_factor;
  424. }
  425. // Emit particles (put in particle buffer). This is called by the particle
  426. // buffer On_Frame_Update() function to avoid order dependence.
  427. void ParticleEmitterClass::Emit(void)
  428. {
  429. WWPROFILE("PartlicleEmitter::Emit");
  430. #ifdef WWDEBUG
  431. if (DebugDisable == true) {
  432. return;
  433. }
  434. #endif
  435. if (Active && !IsComplete) {
  436. Quaternion curr_quat; // Quaternion form of orientation.
  437. Vector3 curr_orig; // Origin.
  438. // Convert current matrix into quaternion + origin form.
  439. curr_quat = Build_Quaternion(Get_Transform());
  440. curr_orig = Get_Transform().Get_Translation();
  441. Create_New_Particles(curr_quat, curr_orig);
  442. PrevQ = curr_quat;
  443. PrevOrig = curr_orig;
  444. } else {
  445. // These need to be updated each frame no matter what
  446. PrevQ = Build_Quaternion(Get_Transform());
  447. PrevOrig = Get_Transform().Get_Translation();
  448. }
  449. }
  450. // Collision sphere is a point - emitter emits also when not visible, so this
  451. // is only important to avoid affecting the collision spheres of composite
  452. // objects into which the emitter is inserted.
  453. void ParticleEmitterClass::Update_Cached_Bounding_Volumes(void) const
  454. {
  455. CachedBoundingSphere.Init(Get_Position(),0.0);
  456. CachedBoundingBox.Center = Get_Position();
  457. CachedBoundingBox.Extent.Set(0,0,0);
  458. Validate_Cached_Bounding_Volumes();
  459. }
  460. // Note that creation location and velocity are in local coordinates, so new
  461. // particles need to be transformed into worldspace. It is important to get
  462. // the correct transform at the exact time of particle creation (for frame-
  463. // rate independence), so the current emitter transform is calculated by
  464. // time-based interpolation between the transforms at the beginning and end
  465. // of the current frame. This interpolation is performed via quaternion-
  466. // slerping the orientation and lerping the origin.
  467. void ParticleEmitterClass::Create_New_Particles(const Quaternion & curr_quat, const Vector3 & curr_orig)
  468. {
  469. Quaternion quat;
  470. Vector3 orig;
  471. // The emit remainder from the previous interval (the time remaining in
  472. // the previous interval when the last particle was emitted) is added to
  473. // the size of the current frame to yield the time currently available
  474. // for emitting particles.
  475. unsigned int frametime = WW3D::Get_Frame_Time();
  476. // Since the particles are written into a wraparound buffer, we can take the time modulo a time
  477. // constant which represents the time it takes to fill up the entire buffer with new particles.
  478. // We will do this so we don't run into performance problems with very large frame times.
  479. if (frametime > 100 * EmitRate) { // If the loop will run over 100 times
  480. unsigned int buf_size = Buffer->Get_Buffer_Size();
  481. unsigned int gcd = Greatest_Common_Divisor(buf_size, BurstSize);
  482. unsigned int bursts = buf_size / gcd;
  483. unsigned int cycle_time = EmitRate * bursts;
  484. if (cycle_time > 1) {
  485. frametime = frametime % cycle_time;
  486. } else {
  487. frametime = 1;
  488. }
  489. }
  490. EmitRemain += frametime;
  491. // The interpolation factor (0: start of interval: 1: end of interval).
  492. // Possibly negative at this point, but after the delta is added to it, it
  493. // will be positive.
  494. float fl_frametime = (float)frametime;
  495. float alpha = 1 - ((float)EmitRemain / fl_frametime);
  496. float d_alpha = (float)EmitRate / fl_frametime;
  497. // Setup the slerp between the two quaternions.
  498. SlerpInfoStruct slerp_info;
  499. Slerp_Setup(PrevQ, curr_quat, &slerp_info);
  500. // Find the velocity of the emitter (for velocity inheritance).
  501. // InheritedWorldSpaceEmitterVel is a global variable which is only used
  502. // to pass this into the following Initialize_Particle() calls without
  503. // having to set it as an argument for each call.
  504. if (VelInheritFactor) {
  505. InheritedWorldSpaceEmitterVel = (curr_orig - PrevOrig) * (VelInheritFactor / fl_frametime);
  506. } else {
  507. InheritedWorldSpaceEmitterVel.Set(0.0, 0.0, 0.0);
  508. }
  509. for (; EmitRemain > EmitRate;) {
  510. // Calculate the new remainder.
  511. EmitRemain -= EmitRate;
  512. // Interpolate the start and end transforms to find the transform at
  513. // the moment of particle creation.
  514. alpha += d_alpha;
  515. quat = Cached_Slerp(PrevQ, curr_quat, alpha, &slerp_info);
  516. orig = Lerp(PrevOrig, curr_orig, alpha);
  517. // Initialize BurstSize new particles with the given age and emitter
  518. // transform (expressed as a quaternion and origin vector), and add it
  519. // to the particle buffer's new particle vector.
  520. unsigned int age = WW3D::Get_Sync_Time() - EmitRemain;
  521. unsigned int burst_size = BurstSize;
  522. if (OneTimeBurst) {
  523. burst_size = OneTimeBurstSize;
  524. OneTimeBurst = false;
  525. }
  526. if ( ParticlesLeft > 0 ) { // if we are counting,
  527. if (burst_size > (unsigned int)ParticlesLeft) {
  528. burst_size = (unsigned int)ParticlesLeft;
  529. ParticlesLeft = 0;
  530. } else {
  531. ParticlesLeft -= burst_size;
  532. }
  533. if ( ParticlesLeft <= 0 ) { // count and if done
  534. IsComplete = true; // stop
  535. }
  536. }
  537. for (unsigned int i = 0; i < burst_size; i++) {
  538. Initialize_Particle(Buffer->Add_Uninitialized_New_Particle(), age, quat, orig);
  539. }
  540. if (IsComplete) break;
  541. }
  542. }
  543. // Initialize one new particle at the given NewParticleStruct address, with
  544. // the given age and emitter transform (expressed as a quaternion and origin
  545. // vector). (must check if address is NULL).
  546. void ParticleEmitterClass::Initialize_Particle(NewParticleStruct * newpart,
  547. unsigned int timestamp, const Quaternion & quat, const Vector3 & orig)
  548. {
  549. // Set time stamp.
  550. newpart->TimeStamp = timestamp;
  551. // Set starting (random) local position.
  552. Vector3 rand_pos;
  553. if (PosRand) {
  554. PosRand->Get_Vector(rand_pos);
  555. } else {
  556. rand_pos.Set(0.0, 0.0, 0.0);
  557. }
  558. // Transform position to worldspace, using the transform at moment of
  559. // particle creation.
  560. newpart->Position = quat.Rotate_Vector(rand_pos) + orig;
  561. // Set (random) local velocity.
  562. Vector3 rand_vel;
  563. if (VelRand) {
  564. VelRand->Get_Vector(rand_vel);
  565. } else {
  566. rand_vel.Set(0.0, 0.0, 0.0);
  567. }
  568. // Add outwards velocity to emitterspace velocity
  569. if (OutwardVel) {
  570. // Find vector pointing outwards (from origin to creation position)
  571. Vector3 outwards;
  572. float pos_l2 = rand_pos.Length2();
  573. if (pos_l2) {
  574. outwards = rand_pos * (OutwardVel * WWMath::Inv_Sqrt(pos_l2));
  575. } else {
  576. outwards.X = OutwardVel;
  577. outwards.Y = 0.0f;
  578. outwards.Z = 0.0f;
  579. }
  580. rand_vel += outwards;
  581. }
  582. // Add base velocity to emitterspace velocity
  583. rand_vel += BaseVel;
  584. // Rotate velocity to worldspace and add emitter's inherited velocity.
  585. newpart->Velocity = InheritedWorldSpaceEmitterVel + quat.Rotate_Vector(rand_vel);
  586. }
  587. ParticleEmitterDefClass *
  588. ParticleEmitterClass::Build_Definition (void) const
  589. {
  590. // Allocate a new emitter definition object
  591. ParticleEmitterDefClass *pdefinition = new ParticleEmitterDefClass;
  592. WWASSERT (pdefinition != NULL);
  593. if (pdefinition != NULL) {
  594. // Set the texture's filename
  595. TextureClass *ptexture = Get_Texture ();
  596. if (ptexture != NULL) {
  597. pdefinition->Set_Texture_Filename (ptexture->Get_Texture_Name());
  598. REF_PTR_RELEASE(ptexture);
  599. }
  600. // Now fill the definition with data from this emitter instance
  601. pdefinition->Set_Render_Mode (Get_Render_Mode());
  602. pdefinition->Set_Frame_Mode (Get_Frame_Mode());
  603. pdefinition->Set_Name (Get_Name ());
  604. pdefinition->Set_Lifetime (Get_Lifetime ());
  605. pdefinition->Set_Emission_Rate (Get_Emission_Rate ());
  606. pdefinition->Set_Max_Emissions (Get_Max_Particles ());
  607. pdefinition->Set_Fade_Time (Get_Fade_Time ());
  608. pdefinition->Set_Gravity (0);
  609. pdefinition->Set_Elasticity (0);
  610. pdefinition->Set_Velocity (Get_Start_Velocity ());
  611. pdefinition->Set_Acceleration (Get_Acceleration ());
  612. pdefinition->Set_Burst_Size (Get_Burst_Size ());
  613. pdefinition->Set_Outward_Vel (Get_Outwards_Vel ());
  614. pdefinition->Set_Vel_Inherit (Get_Velocity_Inherit ());
  615. pdefinition->Set_Shader (Get_Shader ());
  616. //
  617. // Pass the creation volume onto the definition
  618. //
  619. Vector3Randomizer *randomizer = Get_Creation_Volume ();
  620. pdefinition->Set_Creation_Volume (randomizer);
  621. //
  622. // Pass the velocity randomizer onto the definition
  623. //
  624. randomizer = Get_Velocity_Random ();
  625. pdefinition->Set_Velocity_Random (randomizer);
  626. //
  627. // Pass the color keyframes onto the definition
  628. //
  629. ParticlePropertyStruct<Vector3> colors;
  630. Get_Color_Key_Frames (colors);
  631. pdefinition->Set_Color_Keyframes (colors);
  632. if (colors.KeyTimes != NULL) delete [] colors.KeyTimes;
  633. if (colors.Values != NULL) delete [] colors.Values;
  634. //
  635. // Pass the opacity keyframes onto the definition
  636. //
  637. ParticlePropertyStruct<float> opacities;
  638. Get_Opacity_Key_Frames (opacities);
  639. pdefinition->Set_Opacity_Keyframes (opacities);
  640. if (opacities.KeyTimes != NULL) delete [] opacities.KeyTimes;
  641. if (opacities.Values != NULL) delete [] opacities.Values;
  642. //
  643. // Pass the size keyframes onto the definition
  644. //
  645. ParticlePropertyStruct<float> sizes;
  646. Get_Size_Key_Frames (sizes);
  647. pdefinition->Set_Size_Keyframes (sizes);
  648. if (sizes.KeyTimes != NULL) delete [] sizes.KeyTimes;
  649. if (sizes.Values != NULL) delete [] sizes.Values;
  650. //
  651. // Pass the rotation keyframes onto the definition
  652. //
  653. ParticlePropertyStruct<float> rotations;
  654. Get_Rotation_Key_Frames (rotations);
  655. pdefinition->Set_Rotation_Keyframes (rotations, Get_Initial_Orientation_Random());
  656. if (rotations.KeyTimes != NULL) delete [] rotations.KeyTimes;
  657. if (rotations.Values != NULL) delete [] rotations.Values;
  658. //
  659. // Pass the frame keyframes onto the definition
  660. //
  661. ParticlePropertyStruct<float> frames;
  662. Get_Frame_Key_Frames (frames);
  663. pdefinition->Set_Frame_Keyframes (frames);
  664. if (frames.KeyTimes != NULL) delete [] frames.KeyTimes;
  665. if (frames.Values != NULL) delete [] frames.Values;
  666. //
  667. // Pass the blur time keyframes onto the definition
  668. //
  669. ParticlePropertyStruct<float> blur_times;
  670. Get_Blur_Time_Key_Frames (blur_times);
  671. pdefinition->Set_Blur_Time_Keyframes (blur_times);
  672. if (blur_times.KeyTimes != NULL) delete [] blur_times.KeyTimes;
  673. if (blur_times.Values != NULL) delete [] blur_times.Values;
  674. //
  675. // Set up the line parameters
  676. //
  677. pdefinition->Set_Line_Texture_Mapping_Mode(Get_Line_Texture_Mapping_Mode());
  678. pdefinition->Set_Merge_Intersections(Is_Merge_Intersections());
  679. pdefinition->Set_Freeze_Random(Is_Freeze_Random());
  680. pdefinition->Set_Disable_Sorting(Is_Sorting_Disabled());
  681. pdefinition->Set_End_Caps(Are_End_Caps_Enabled());
  682. pdefinition->Set_Subdivision_Level(Get_Subdivision_Level());
  683. pdefinition->Set_Noise_Amplitude(Get_Noise_Amplitude());
  684. pdefinition->Set_Merge_Abort_Factor(Get_Merge_Abort_Factor());
  685. pdefinition->Set_Texture_Tile_Factor(Get_Texture_Tile_Factor());
  686. pdefinition->Set_UV_Offset_Rate(Get_UV_Offset_Rate());
  687. }
  688. // Return a pointer to the new definition
  689. return pdefinition;
  690. }
  691. WW3DErrorType
  692. ParticleEmitterClass::Save (ChunkSaveClass &chunk_save) const
  693. {
  694. // Assume error
  695. WW3DErrorType ret_val = WW3D_ERROR_SAVE_FAILED;
  696. // Build a definition from this emitter instance, and save it
  697. // to the chunk.
  698. ParticleEmitterDefClass *pdefinition = Build_Definition ();
  699. if (pdefinition != NULL) {
  700. ret_val = pdefinition->Save_W3D (chunk_save);
  701. }
  702. // Return the WW3DErrorType return code
  703. return ret_val;
  704. }
  705. void
  706. ParticleEmitterClass::Set_Name (const char *pname)
  707. {
  708. // Free the old name if necessary
  709. if (NameString != NULL) {
  710. ::free (NameString);
  711. NameString = NULL;
  712. }
  713. // Copy the provided name
  714. NameString = ::_strdup (pname);
  715. return ;
  716. }
  717. void
  718. ParticleEmitterClass::Update_On_Visibilty(void)
  719. {
  720. // Simply start or stop the emission based on
  721. // the visibility state of the emitter.
  722. if (Is_Not_Hidden_At_All () && Is_Stopped () && IsInScene) {
  723. Start ();
  724. } else if ((Is_Not_Hidden_At_All () == false) && (Is_Stopped () == false)) {
  725. Stop ();
  726. }
  727. return ;
  728. }
  729. void
  730. ParticleEmitterClass::Add_Dependencies_To_List
  731. (
  732. DynamicVectorClass<StringClass> &file_list,
  733. bool textures_only
  734. )
  735. {
  736. //
  737. // Get the texture the emitter is using and add it to our list
  738. //
  739. TextureClass *texture = Get_Texture ();
  740. if (texture != NULL) {
  741. file_list.Add (texture->Get_Full_Path ());
  742. REF_PTR_RELEASE(texture);
  743. }
  744. // Allow the base class to process this call (extremely important)
  745. RenderObjClass::Add_Dependencies_To_List (file_list, textures_only);
  746. return ;
  747. }