part_emt.cpp 26 KB

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