part_buf.h 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460
  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_buf.h $*
  25. * *
  26. * $Author:: Vss_sync $*
  27. * *
  28. * $Modtime:: 10/26/01 2:56p $*
  29. * *
  30. * $Revision:: 10 $*
  31. * *
  32. *-------------------------------------------------------------------------*
  33. * Functions: *
  34. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  35. #if defined(_MSC_VER)
  36. #pragma once
  37. #endif
  38. #ifndef PART_BUF_H
  39. #define PART_BUF_H
  40. #include "rendobj.h"
  41. #include "pointgr.h"
  42. #include "seglinerenderer.h"
  43. #include "linegrp.h"
  44. class ParticleEmitterClass;
  45. template<class T> struct ParticlePropertyStruct;
  46. /**
  47. ** NewParticleStruct: structure for passing new particles from the particle
  48. ** emitter to the particle buffer. Since the emitter always continues
  49. ** emitting (unless stopped) but the buffer may not update for long periods,
  50. ** the emitter may emit more particles than the buffer can contain. However,
  51. ** in this case the older particles can be ignored. Therefore
  52. ** ParticleBufferClass contains a circular buffer of NewParticleStructs, and
  53. ** new ones overwrite the oldest in the case of overflows.
  54. */
  55. struct NewParticleStruct
  56. {
  57. Vector3 Position; // Particle position in worldspace.
  58. Vector3 Velocity; // Particle velocity in worldspace.
  59. unsigned int TimeStamp; // Millisecond time at creation.
  60. // These are needed by DynamicVectorClass (will probably never be used).
  61. bool operator != (const NewParticleStruct & p)
  62. {
  63. return (p.TimeStamp != TimeStamp) || (p.Position != Position);
  64. }
  65. bool operator == (const NewParticleStruct & p)
  66. {
  67. return (p.TimeStamp == TimeStamp) && (p.Position == Position);
  68. }
  69. };
  70. /**
  71. ** ParticleBufferClass: This is a renderobject which contains the particles
  72. ** emitted by a given renderer. The particle emitter is a different
  73. ** renderobject, a ParticleEmitterClass (there is one particle emitter per
  74. ** particle buffer). This separation is so that the bounding volumes of the
  75. ** particle group and the object containing the emitter (emitters will
  76. ** typically be inserted into a hierarchy object or some such) will remain
  77. ** separate.
  78. */
  79. class ParticleBufferClass : public RenderObjClass
  80. {
  81. public:
  82. ParticleBufferClass(ParticleEmitterClass *emitter, unsigned int buffer_size,
  83. ParticlePropertyStruct<Vector3> &color, ParticlePropertyStruct<float> &opacity,
  84. ParticlePropertyStruct<float> &size, ParticlePropertyStruct<float> &rotation,
  85. float orient_rnd, ParticlePropertyStruct<float> &frame,
  86. ParticlePropertyStruct<float> &blurtime, Vector3 accel,
  87. float max_age, TextureClass *tex, ShaderClass shader, bool pingpong,
  88. int render_mode, int frame_mode, const W3dEmitterLinePropertiesStruct * line_props);
  89. ParticleBufferClass(const ParticleBufferClass & src);
  90. ParticleBufferClass & operator = (const ParticleBufferClass &);
  91. virtual ~ParticleBufferClass(void);
  92. /*
  93. ** RenderObjClass Interface:
  94. */
  95. virtual RenderObjClass * Clone(void) const;
  96. virtual int Class_ID(void) const { return CLASSID_PARTICLEBUFFER; }
  97. virtual int Get_Num_Polys(void) const;
  98. int Get_Particle_Count(void) const;
  99. // Update particle state and draw the particles.
  100. virtual void Render(RenderInfoClass & rinfo);
  101. // Scales the size of the individual particles but doesn't affect their
  102. // position (and therefore the size of the particle system as a whole)
  103. virtual void Scale(float scale);
  104. // The particle buffer never receives a Set_Transform/Position call,
  105. // evem though its bounding volume changes. Since bounding volume
  106. // invalidations ordinarily occur when these functions are called,
  107. // the cached bounding volumes will not be invalidated unless we do
  108. // it elsewhere (such as here). We also need to call the particle
  109. // emitter's Emit() function (done here to avoid order dependence).
  110. virtual void On_Frame_Update(void);
  111. virtual void Notify_Added(SceneClass * scene);
  112. virtual void Notify_Removed(SceneClass * scene);
  113. virtual void Get_Obj_Space_Bounding_Sphere(SphereClass & sphere) const;
  114. virtual void Get_Obj_Space_Bounding_Box(AABoxClass & box) const;
  115. /////////////////////////////////////////////////////////////////////////////
  116. // Render Object Interface - Predictive LOD
  117. /////////////////////////////////////////////////////////////////////////////
  118. virtual void Prepare_LOD(CameraClass &camera);
  119. virtual void Increment_LOD(void);
  120. virtual void Decrement_LOD(void);
  121. virtual float Get_Cost(void) const;
  122. virtual float Get_Value(void) const;
  123. virtual float Get_Post_Increment_Value(void) const;
  124. virtual void Set_LOD_Level(int lod);
  125. virtual int Get_LOD_Level(void) const;
  126. virtual int Get_LOD_Count(void) const;
  127. virtual void Set_LOD_Bias(float bias) { LodBias = MAX(bias, 0.0f); }
  128. virtual int Calculate_Cost_Value_Arrays(float screen_area, float *values, float *costs) const;
  129. /*
  130. ** These members are not part of the RenderObjClass Interface:
  131. */
  132. void Reset_Colors(ParticlePropertyStruct<Vector3> &new_props);
  133. void Reset_Opacity(ParticlePropertyStruct<float> &new_props);
  134. void Reset_Size(ParticlePropertyStruct<float> &new_props);
  135. void Reset_Rotations(ParticlePropertyStruct<float> &new_rotations, float orient_rnd);
  136. void Reset_Frames(ParticlePropertyStruct<float> &new_frames);
  137. void Reset_Blur_Times(ParticlePropertyStruct<float> &new_blur_times);
  138. // This informs the buffer that the emitter is dead, so it can release
  139. // its pointer to it and be removed itself after all its particles dies
  140. // out.
  141. void Emitter_Is_Dead(void);
  142. // This set's the buffer's current emitter - this should usually be
  143. // called only by the emitter's copy constructor after it clones a
  144. // buffer.
  145. void Set_Emitter(ParticleEmitterClass *emitter);
  146. // from RenderObj...
  147. virtual bool Is_Complete(void) { return IsEmitterDead && !NonNewNum && !NewNum; }
  148. // This adds an uninitialized NewParticleStuct to the new particle
  149. // buffer and returns its address so the particle emitter can
  150. // initialize it. This is how the emitter sends new particles to the
  151. // buffer - it is done this way to avoid needless copying.
  152. NewParticleStruct * Add_Uninitialized_New_Particle(void);
  153. // Change the acceleration of the particles on the fly
  154. void Set_Acceleration (const Vector3 &acceleration) { Accel = acceleration; HasAccel = ((Accel.X != 0) || (Accel.Y != 0) || (Accel.Z != 0)); }
  155. //
  156. // Inline accessors.
  157. // These methods are provided as a means to get the emitter's settings.
  158. //
  159. int Get_Render_Mode (void) const { return RenderMode; }
  160. int Get_Frame_Mode (void) const { return FrameMode; }
  161. float Get_Particle_Size (void) const { return SizeKeyFrameValues[0]; }
  162. Vector3 Get_Acceleration (void) const { return Accel * 1000000.0F; }
  163. float Get_Lifetime (void) const { return (float(MaxAge)) / 1000.0F; }
  164. Vector3 Get_Start_Color (void) const { return ColorKeyFrameValues[0]; }
  165. float Get_Start_Opacity (void) const { return AlphaKeyFrameValues[0]; }
  166. Vector3 Get_End_Color (void) const { return (NumColorKeyFrames > 1) ? ColorKeyFrameValues[NumColorKeyFrames - 1] : ColorKeyFrameValues[0]; }
  167. float Get_End_Opacity (void) const { return (NumAlphaKeyFrames > 1) ? AlphaKeyFrameValues[NumAlphaKeyFrames - 1] : AlphaKeyFrameValues[0]; }
  168. TextureClass * Get_Texture (void) const;
  169. void Set_Texture (TextureClass *tex);
  170. float Get_Fade_Time (void) const { return (NumColorKeyFrames > 1) ? (((float)ColorKeyFrameTimes[1]) / 1000.0f) : 0.0f; }
  171. ShaderClass Get_Shader (void) const;
  172. //
  173. // Line rendering properties. These functions will always return
  174. // a default value if line rendering is not enabled.
  175. //
  176. int Get_Line_Texture_Mapping_Mode(void) const;
  177. int Is_Merge_Intersections(void) const;
  178. int Is_Freeze_Random(void) const;
  179. int Is_Sorting_Disabled(void) const;
  180. int Are_End_Caps_Enabled(void) const;
  181. int Get_Subdivision_Level(void) const;
  182. float Get_Noise_Amplitude(void) const;
  183. float Get_Merge_Abort_Factor(void) const;
  184. float Get_Texture_Tile_Factor(void) const;
  185. Vector2 Get_UV_Offset_Rate(void) const;
  186. // This is a utility function only meant to be called by the particle emitter.
  187. unsigned int Get_Buffer_Size(void) const { return MaxNum; }
  188. // Note: Caller IS RESPONSIBLE for freeing any memory allocated by these calls
  189. void Get_Color_Key_Frames (ParticlePropertyStruct<Vector3> &colors) const;
  190. void Get_Opacity_Key_Frames (ParticlePropertyStruct<float> &opacities) const;
  191. void Get_Size_Key_Frames (ParticlePropertyStruct<float> &sizes) const;
  192. void Get_Rotation_Key_Frames (ParticlePropertyStruct<float> &rotations) const;
  193. void Get_Frame_Key_Frames (ParticlePropertyStruct<float> &frames) const;
  194. void Get_Blur_Time_Key_Frames (ParticlePropertyStruct<float> &blurtimes) const;
  195. float Get_Initial_Orientation_Random (void) const { return InitialOrientationRandom; }
  196. // Total Active Particle Buffer Count
  197. static unsigned int Get_Total_Active_Count( void ) { return TotalActiveCount; }
  198. // Global control of particle LOD.
  199. static void Set_LOD_Max_Screen_Size(int lod_level,float max_screen_size);
  200. static float Get_LOD_Max_Screen_Size(int lod_level);
  201. protected:
  202. virtual void Update_Cached_Bounding_Volumes(void) const;
  203. // render the particle system as a collection of particles
  204. void Render_Particles(RenderInfoClass & rinfo);
  205. // render the particle system as a line
  206. void Render_Line(RenderInfoClass & rinfo);
  207. // render the particle system as a line group
  208. void Render_Line_Group(RenderInfoClass & rinfo);
  209. // Update the kinematic particle state. This includes getting new
  210. // particles from the new particle queue, updating velocity/position
  211. // for any existing particles, killing old ones, and updating
  212. // LastUpdateTime.
  213. void Update_Kinematic_Particle_State(void);
  214. // Update the visual particle state. This includes updating color/size
  215. // for all existing particles. Only needs to happen at rendering time.
  216. void Update_Visual_Particle_State(void);
  217. // Update the bounding box. (Updates the particle state if it needs to).
  218. void Update_Bounding_Box(void);
  219. // Helper function for Render_Particles and Render_LineGroup
  220. void Generate_APT(ShareBufferClass <unsigned int> **apt,unsigned int &active_point_count);
  221. void Combine_Color_And_Alpha();
  222. // Get new particles from the emitter and write them into the circular
  223. // particle buffer, possibly overwriting older particles. Perform
  224. // partial-interval upddate on them as well.
  225. void Get_New_Particles(void);
  226. // Kill all remaining particles which will be above their maxage at the
  227. // end of this time interval.
  228. void Kill_Old_Particles(void);
  229. // Update all living non-new particles according to time elapsed since
  230. // last update.
  231. void Update_Non_New_Particles(unsigned int elapsed);
  232. // Seperate circular buffer used by the emitter to pass new particles.
  233. // It is implemented as an array, start and end indices and a count (to
  234. // differentiate between completely full and completely empty).
  235. NewParticleStruct * NewParticleQueue;
  236. unsigned int NewParticleQueueStart;
  237. unsigned int NewParticleQueueEnd;
  238. int NewParticleQueueCount;
  239. // State global to the entire particle buffer.
  240. int RenderMode; // rendering mode being used (settings found in w3d_file.h)
  241. int FrameMode; // frame mode (settings found in w3d_file.h - 1x1..16x16)
  242. Vector3 Accel; // Worldspace acceleration per ms^2.
  243. bool HasAccel; // Is the acceleration non-zero?
  244. unsigned int MaxAge; // Maximum age in milliseconds.
  245. unsigned int LastUpdateTime;// Time at last update.
  246. bool IsEmitterDead;
  247. float MaxSize; // Used for BBox calculations
  248. // Circular buffer implementation. This is actually 2 sequential
  249. // circular buffers: one for non-new particles and one for new
  250. // particles (the distinction is needed because the two types of
  251. // particles are updated differently).
  252. // Besides the head/tail indices, a count is used for each buffer to
  253. // distinguish between full and empty.
  254. unsigned int MaxNum; // Maximum number of particles.
  255. unsigned int Start; // Start of existing (non-new) particles.
  256. unsigned int End; // End of existing (non-new) particles.
  257. unsigned int NewEnd; // End of new particles.
  258. int NonNewNum; // Non-new entry count (to know when empty).
  259. int NewNum; // New entry count (to know when empty).
  260. // Worldspace-aligned bounding box:
  261. AABoxClass BoundingBox;
  262. bool BoundingBoxDirty;
  263. // At least one keyframe must exist for each property (time 0).
  264. // If a randomizer is zero and there are no additional keyframes for
  265. // that property (or the keyframes are all equal), all the arrays for
  266. // that property are NULL (since they will never be used), except for
  267. // the Values array which will have one entry (the constant value).
  268. // Note that the rotation and orientation properties are different -
  269. // only orientation is used in rendering. The rotation data is only
  270. // used to compute the orientations. So the condition is different -
  271. // if rotation and orientation randomizers, and all rotation keyframes
  272. // are all zero, then all of the arrays will be NULL (including the
  273. // Values array).
  274. unsigned int NumColorKeyFrames;
  275. unsigned int * ColorKeyFrameTimes; // 0th entry is always 0
  276. Vector3 * ColorKeyFrameValues;
  277. Vector3 * ColorKeyFrameDeltas;
  278. unsigned int NumAlphaKeyFrames;
  279. unsigned int * AlphaKeyFrameTimes; // 0th entry is always 0
  280. float * AlphaKeyFrameValues;
  281. float * AlphaKeyFrameDeltas;
  282. unsigned int NumSizeKeyFrames;
  283. unsigned int * SizeKeyFrameTimes; // 0th entry is always 0
  284. float * SizeKeyFrameValues;
  285. float * SizeKeyFrameDeltas;
  286. unsigned int NumRotationKeyFrames;
  287. unsigned int * RotationKeyFrameTimes; // 0th entry is always 0
  288. float * RotationKeyFrameValues; // In rotations per millisecond
  289. float * HalfRotationKeyFrameDeltas; // (* 0.5f)
  290. float * OrientationKeyFrameValues; // Rotation preintegrated to keyframe times
  291. unsigned int NumFrameKeyFrames;
  292. unsigned int * FrameKeyFrameTimes; // 0th entry is always 0
  293. float * FrameKeyFrameValues;
  294. float * FrameKeyFrameDeltas;
  295. unsigned int NumBlurTimeKeyFrames;
  296. unsigned int * BlurTimeKeyFrameTimes; // 0th entry is always 0
  297. float * BlurTimeKeyFrameValues;
  298. float * BlurTimeKeyFrameDeltas;
  299. Vector4 DefaultTailDiffuse; // For line group mode, when all the tails are the same color
  300. // These tables are indexed by the array position in the particle buffer.
  301. // The table size is either the smallest power of two equal or larger
  302. // than the buffer size, or MAX_RANDOM_ENTRIES (defined in the .cpp
  303. // file - MUST be a power of two), whichever is smaller. Note that if a
  304. // randomizer is zero, the table will have one entry (containing zero),
  305. // which is why each property has its own NumXXXRandomEntries variable.
  306. // If a randomizer is zero and the property has no keyframes, the table
  307. // will be NULL since it will never be used (property is constant)).
  308. unsigned int NumRandomColorEntriesMinus1; // 2^n - 1 so can be used as a mask also
  309. Vector3 * RandomColorEntries;
  310. unsigned int NumRandomAlphaEntriesMinus1; // 2^n - 1 so can be used as a mask also
  311. float * RandomAlphaEntries;
  312. unsigned int NumRandomSizeEntriesMinus1; // 2^n - 1 so can be used as a mask also
  313. float * RandomSizeEntries;
  314. unsigned int NumRandomRotationEntriesMinus1; // 2^n - 1 so can be used as a mask also
  315. float * RandomRotationEntries;
  316. unsigned int NumRandomOrientationEntriesMinus1; // 2^n - 1 so can be used as a mask also
  317. float * RandomOrientationEntries;
  318. unsigned int NumRandomFrameEntriesMinus1; // 2^n - 1 so can be used as a mask also
  319. float * RandomFrameEntries;
  320. unsigned int NumRandomBlurTimeEntriesMinus1; // 2^n - 1 so can be used as a mask also
  321. float * RandomBlurTimeEntries;
  322. Vector3 ColorRandom;
  323. float OpacityRandom;
  324. float SizeRandom;
  325. float RotationRandom;
  326. float FrameRandom;
  327. float BlurTimeRandom;
  328. float InitialOrientationRandom;
  329. // This object implements particle rendering
  330. PointGroupClass * PointGroup;
  331. // This object implements line rendering
  332. SegLineRendererClass * LineRenderer;
  333. // This object implements line group rendering
  334. LineGroupClass * LineGroup;
  335. // These are shared with the point group. The position, color and alpha
  336. // arrays serve double duty: they are used to store and update particle
  337. // state and also to pass point information to the point group. The
  338. // active point table is used to communicate to the point group which
  339. // points are active (it is only used if all are not active)..
  340. ShareBufferClass<Vector3> * Position[2]; // Only [0] used unless pingpong enabled
  341. ShareBufferClass<Vector4> * Diffuse; // passed into point group
  342. ShareBufferClass<Vector3> * Color;
  343. ShareBufferClass<float> * Alpha;
  344. ShareBufferClass<float> * Size;
  345. ShareBufferClass<uint8> * Frame;
  346. ShareBufferClass<float> * UCoord; // Only used for line groups, uses Frame keyframes
  347. ShareBufferClass<Vector3> * TailPosition; // Only used for line groups
  348. ShareBufferClass<Vector4> * TailDiffuse; // Only used for line groups
  349. ShareBufferClass<uint8> * Orientation;
  350. ShareBufferClass<unsigned int> * APT;
  351. // Do we keep two ping-pong position buffers (for collision and possibly other effects
  352. // which need the previous frames position as well as this frames)
  353. bool PingPongPosition;
  354. // Additional per-particle state:
  355. Vector3 * Velocity; // World units per millisecond.
  356. unsigned int * TimeStamp; // Millisecond time at creation.
  357. // This pointer is used for synchronization - the emitter is called to
  358. // add new particles at the start of the buffers render function - to
  359. // prevent behavior which is dependent on the relative time order of
  360. // the emitter and buffer in the rendering list.
  361. ParticleEmitterClass * Emitter;
  362. // These are used for decimating particles for LOD purposes. The
  363. // threshold is compared vs. an array filled with a random permutation
  364. // of the numbers 0 to 15, and any particle whose entry (modulo 16) is
  365. // less than the threshold is not rendered. So if DecimationThreshold
  366. // is 0 (the minimum value), all particles are rendered - if it is 16
  367. // (the maximum value) none are rendered.
  368. unsigned int DecimationThreshold;
  369. static const unsigned int PermutationArray[16];
  370. // LOD values
  371. unsigned int LodCount;
  372. float Cost[17]; // Cost array needs one entry for each LOD level
  373. float Value[18]; // Value array needs one more entry than # of LODs
  374. float LodBias;
  375. // Projected area, used for LOD purposes
  376. float ProjectedArea;
  377. // Total Active Particle Buffer Count
  378. static unsigned int TotalActiveCount;
  379. // Static array of screen-size clamps for the 17 possible LOD levels a
  380. // particle buffer can have. We can change these from being global to
  381. // being per-buffer later if we wish. Default is NO_MAX_SCREEN_SIZE.
  382. static float LODMaxScreenSizes[17];
  383. enum TailDiffuseTypeEnum {
  384. BLACK,
  385. WHITE,
  386. SAME_AS_HEAD,
  387. SAME_AS_HEAD_ALPHA_ZERO
  388. };
  389. // Determine based on shader and texture
  390. // what the tail color should be
  391. TailDiffuseTypeEnum Determine_Tail_Diffuse();
  392. };
  393. #endif // PART_BUF_H