ParticleAPI 3.0.0 Performant particle system API in C++ for interactive graphics

pAPIContext.h
Go to the documentation of this file.
1/// PAPIClasses.h
2///
3/// Copyright 1997-2007, 2022 by David K. McAllister
4///
5/// Include this file in all applications that use the Particle System API.
6
7#ifndef particle_api_classes_h
8#define particle_api_classes_h
9
10#include "Particle/pDeclarations.h"
11#include "Particle/pError.h"
12#include "Particle/pInternalsIface.h"
13#include "Particle/pParticle.h"
14#include "Particle/pSourceState.h"
15
16 namespace PAPI {
17
18class PInternalState_t; // The API-internal struct containing the context's state. Don't try to use it.
19struct Particle_t;
20
21/// Action List Calls
22///
23/// These calls create and operate on action lists, which are scripts of many actions
24/// to be applied together as a block to the current particle group. An empty action
25/// list is first created using GenActionLists(), and is then filled or compiled by calling
26/// NewActionList(), then calling Actions, then calling EndActionList(). Once the action
27/// list is filled, it is run via CallActionList(). Thus, an action list is sort of a
28/// higher-level action. Complex behaviors can be stored in an action list and then
29/// called later, even as part of another action list. Action lists cannot be edited.
30/// They can only be created or destroyed. To destroy an action list, call DeleteActionLists().
31///
32/// When in immediate mode (not creating or calling an action list), particles are created
33/// with attributes from the current state. However, when particles are created within a
34/// NewActionList() / EndActionList() block, they will receive attributes from the state that was
35/// current when the action list was created (unlike OpenGL).
36///
37/// The time step length, dt, uses the value that is current when CallActionList() is executed, not the
38/// value of dt when the action list was created. This allows dt to be modified without recompiling action
39/// lists. Maybe this isn't a good idea. If it should be the other way in the future, let me know.
40 class PContextActionList_t {
41public:
42 /// Set the random number seed.
43 ///
44 /// The Particle API uses a pseudo-random number generator. The returned number is a function of the numbers already returned. If you start
45 /// two threads, each with a ParticleContext_t they will both generate the same particles if given the same commands. If this is not desired,
46 /// call Seed() on both of them with different seed values.
47 /// The API currently uses the C standard library random number generator, whose state is per-thread, so all contexts in the thread share
48 /// the same random number seed.
49 void Seed(const unsigned int seed);
50
51 /// Specify the time step length.
52 ///
53 /// The Particle System API uses a discrete time approximation to all actions. This means that actions are applied to the particles at a
54 /// particular instant in time as if the action's effect accumulated over a small time interval, dt, with the world being constant over the
55 /// interval. The clock is then "ticked" by the length of the interval and the actions can then be reapplied with the particles having their
56 /// updated values. This is the standard method of doing many time-varying simulations in computer science.
57 ///
58 /// How does the time step, dt, relate to the application's frame rate? The easiest method is to apply the actions once per frame. If the
59 /// application prefers to keep time in terms of seconds, dt can be set to (1 / frames_per_second). But more often, it is easier for a time
60 /// unit to be one frame instead of one second. In this case, dt should be 1.0, which is the default.
61 ///
62 /// For higher quality, the application can apply particle actions more than once per frame. This provides smoother, more realistic results
63 /// in many subtle ways. Suppose the application wanted to compute three animation steps for each rendered frame. Set dt to 1/3 its previous
64 /// value using TimeStep(), then loop three times over all the action code that gets executed per frame, including the calls to Move. If using
65 /// action lists, this can be simply a loop over the CallActionList() call. The run-time results should be about the same, but with fewer
66 /// discrete approximation artifacts. Depending on how much non-particle work is done per frame, increasing the number of time steps per frame
67 /// may or may not affect the frame rate very much.
68 ///
69 /// In terms of numerical integration, particle actions can be thought of as the first derivative of unknown functions dictating the particle
70 /// attributes (such as position) over time. In order to compute the particle attributes these derivative functions must be integrated. Since
71 /// closed form integration doesn't make sense for most actions, Euler's method is used instead. Euler's method is simply the method just
72 /// described - the evaluation of the derivative functions at a particular time and then incrementing the current particle values by these
73 /// derivative results times dt. In Euler's method, the smaller the dt, the more accurate the results.
74 ///
75 /// Unlike with other state setting calls, action lists execute using the current dt value set by TimeStep(), rather than the time step value
76 /// that was current when the action list was created. Making action lists independent of time step size allows the time step to be changed
77 /// without recompiling the action list.
78 ///
79 /// In general, it is folly to call TimeStep() in between other actions of a simulation frame. For example, calling Bounce(); TimeStep(); Move();
80 /// can cause particles to pass through the bounce domain instead of bouncing off it.
81 void TimeStep(const float new_dt);
82
83 /// Return the current time step, as set with TimeStep()
84 float GetTimeStep() const;
85
86 /// Execute the specified action list on the current particle group.
87 ///
88 /// Call the action functions as specified when this action list was created with NewActionList(). The actions are executed with the state
89 /// values in effect when the action list was created, except the context's current value of dt is used, not the value of dt when the list
90 /// was created.
91 ///
92 /// CallActionList() is the only function other than actions that can be stored in an action list. This allows action lists to become atomic
93 /// operations in more complex action lists.
94 ///
95 /// When calling CallActionList() during the creation of a new action list, action_list_num does not need to indicate an existing action list.
96 /// At all other times it is an error for action_list_num to not indicate an existing (generated) action list.
97 void CallActionList(const int action_list_num);
98
99 /// Delete one or more consecutive action lists.
100 ///
101 /// Deletes action_list_count action lists, with action_list_num being the list number of the first one. The lists must be numbered
102 /// sequentially, and must all exist. This removes the specified action lists from existence.
103 void DeleteActionLists(const int action_list_num, ///< The handle of the first action list to delete
104 const int action_list_count = 1 ///< How many action lists to delete
105 );
106
107 /// End the creation of a new action list.
108 ///
109 /// Obviously, it is an error to call EndActionList() without a corresponding call to NewActionList().
110 void EndActionList();
111
112 /// Generate a block of empty action lists.
113 ///
114 /// Returns the action list number of the first allocated list. All list numbers are in sequential order starting with the first list.
115 /// Valid action list numbers are non-negative.
116 int GenActionLists(const int action_list_count = 1 ///< How many action lists to create
117 );
118
119 /// Begin the creation of the specified action list.
120 ///
121 /// The action_list_num must have already been generated using GenActionLists. Most calls other than actions and state setting calls
122 /// cannot be made between a call to NewActionList() and the corresponding call to EndActionList().
123 /// If called on an action list that has previously been defined, the previous contents of the action list are destroyed and the action
124 /// list will be created anew. This is as with glNewActionList() in OpenGL.
125 void NewActionList(const int action_list_num);
126
127protected:
128 std::shared_ptr<PInternalState_t> PS; // The internal API data for this context is stored here.
129 void InternalSetup(std::shared_ptr<PInternalState_t> Sr); // Calls this after construction to set up the PS pointer
130};
131
132/// This class contains the API calls that operate on particle groups.
133///
134/// A particle group is first created using GenParticleGroups(), which will create a sequentially-numbered
135/// set of particle groups and return the identifying number of the first generated
136/// particle group. You specify which group is current using CurrentGroup(). Unless otherwise
137/// stated, all other commands operate on the current particle group. The maximum number
138/// of particles in the group is specified using SetMaxParticles(). The particle group
139/// is then acted upon using the Actions.
140///
141/// After the actions have been applied, the particles are rendered. This is done at
142/// the same stage of the application's execution as drawing other geometry. To draw
143/// a particle group in OpenGL, the application calls GetParticles() or GetParticlePointer()
144/// functions to get the vertex data, then sends it to OpenGL. When a particle group
145/// is no longer needed, it is deleted using DeleteParticleGroups().
146 class PContextParticleGroup_t {
147public:
148 /// Copy particles from the specified group into the current group.
149 ///
150 /// Copy particles from the specified particle group, p_src_group_num, to the current particle group. Only copy_count particles, starting
151 /// with number index, are copied. Of course, the number of particles actually copied is bounded by the available space in the current
152 /// particle group, and the number of particles actually in the source particle group. The particles are added, in sequential order, to the
153 /// end of the current group. The current group's BirthCallback(), if any, is called for each particle added to the list.
154 void CopyGroup(const int p_src_group_num, ///< group number of the source particle group
155 const size_t index, ///< index of the first particle in the source list to copy
156 const size_t copy_count ///< copy at most this many particles
157 );
158
159 /// Change which group is current.
160 ///
161 /// Makes p_group_num be the current particle group to which all actions and commands apply.
162 void CurrentGroup(const int p_group_num);
163
164 /// Delete one or more consecutive particle groups.
165 ///
166 /// Deletes p_group_count particle groups, with p_group_num being the particle group number of the first one. The groups must be numbered
167 /// sequentially, and must all exist. This removes the specified particle groups from existence (and all their particles). It does not merely
168 /// change the number of existing particles or the maximum size of the group.
169 ///
170 /// The DeathCallback is NOT called for the particles in the deleted groups. Should I change this?
171 void DeleteParticleGroups(const int p_group_num, ///< handle of the first particle group to delete
172 const int p_group_count = 1 ///< delete this many groups
173 );
174
175 /// Create particle groups, each with a maximum of max_particles.
176 ///
177 /// Generates p_group_count new particle groups and returns the particle group number of the first one. The groups are numbered sequentially,
178 /// beginning with the number returned. Each particle group is set to have at most max_particles particles. Call SetMaxParticles() to change this.
179 /// Particle group numbers of groups that have been deleted (using DeleteParticleGroups()) might be reused by GenParticleGroups().
180 int GenParticleGroups(const int p_group_count = 1, ///< generate this many groups
181 const size_t max_particles = 0 ///< each created group can have this many particles
182 );
183
184 /// Returns the number of particles existing in the current group.
185 ///
186 /// The number returned is less than or equal to the group's max_particles.
187 size_t GetGroupCount();
188
189 /// Return the maximum number of particles allowed in the current group.
190 ///
191 /// This can be changed with SetMaxParticles().
192 size_t GetMaxParticles();
193
194 /// Copy particles from the current group to application memory.
195 ///
196 /// Copies at most count particles beginning with the index-th particle in the current particle group into memory already allocated by the
197 /// application. Three floats are returned for the position of each particle, representing its x,y,z location. Four floats are returned for
198 /// the color of each particle, representing its R,G,B,A color. Three floats are returned for the velocity of each particle, representing
199 /// its dx,dy,dz direction vector. Three floats are returned for the size of each particle, representing whatever the application wants them
200 /// to. One float is returned for the age of each particle.
201 ///
202 /// GetParticles() returns the number of particles copied to application memory. Of course, the number of particles actually returned is
203 /// bounded by count and by the number of particles actually in the particle group minus index.
204 /// If verts, color, vel, size or age is NULL then the respective field will not be returned. index and count must be at least 0 and less
205 /// than the number of particles. index + count must be less than the number of particles.
206 /// As with all arrays in C, the index of the first particle is zero.
207 ///
208 /// The following code gets the position of all particles:
209 ///
210 /// int cnt = GetGroupCount();
211 /// float *ppos = new float[cnt * 3];
212 /// int num_ret = GetParticles(0, cnt, ppos);
213 size_t GetParticles(const size_t index, ///< index of the first particle to return
214 const size_t count, ///< max number of particles to return
215 float* position, ///< location to store 3 floats per particle for position
216 const bool getAlpha, ///< true to get a float4 color with alpha; false to get a float3 color
217 float* color = NULL, ///< location to store 3 or 4 floats per particle for color and optionally alpha
218 float* vel = NULL, ///< location to store 3 floats per particle for velocity
219 float* size = NULL, ///< location to store 3 floats per particle for size
220 float* age = NULL ///< location to store 1 float per particle for age
221 );
222
223 /// Return a pointer to particle data stored in API memory.
224 ///
225 /// This function exposes the internal storage of the particle data to the application. It provides a much higher performance way to render
226 /// particles because it avoids copying. In fact, the returned pointers can typically be passed directly to OpenGL or D3D without the
227 /// application ever owning a copy of the data.
228 ///
229 /// Writing to the returned memory is obviously unsafe. There may be auxiliary data that depend on the current values of the particle data.
230 /// You can try it if you want to, but your code may break against future API versions.
231 size_t GetParticlePointer(const float*& ptr, ///< the returned pointer to the particle data
232 size_t& stride, ///< the number of floats from one particle's value to the next particle's value
233 size_t& pos3Ofs, ///< the number of floats from returned ptr to the first particle's position parameter
234 size_t& posB3Ofs, ///< the number of floats from returned ptr to the first particle's positionB parameter
235 size_t& size3Ofs, ///< the number of floats from returned ptr to the first particle's size parameter
236 size_t& vel3Ofs, ///< the number of floats from returned ptr to the first particle's velocity parameter
237 size_t& velB3Ofs, ///< the number of floats from returned ptr to the first particle's velocityB parameter
238 size_t& color3Ofs, ///< the number of floats from returned ptr to the first particle's color parameter
239 size_t& alpha1Ofs, ///< the number of floats from returned ptr to the first particle's alpha parameter
240 size_t& age1Ofs, ///< the number of floats from returned ptr to the first particle's age parameter
241 size_t& up3Ofs, ///< the number of floats from returned ptr to the first particle's up parameter
242 size_t& rvel3Ofs, ///< the number of floats from returned ptr to the first particle's rvel parameter
243 size_t& upB3Ofs, ///< the number of floats from returned ptr to the first particle's upB parameter
244 size_t& mass1Ofs, ///< the number of floats from returned ptr to the first particle's mass parameter
245 size_t& data1Ofs ///< the number of floats from returned ptr to the first particle's data parameter, which is a 32-bit integer
246 );
247
248 /// Change the maximum number of particles in the current group.
249 ///
250 /// If necessary, this will delete particles from the end of the particle group, but no other particles will be deleted.
251 /// The DeathCallback() of deleted particles WILL be called.
252 /// Call SetMaxParticles(0) to empty the group.
253 void SetMaxParticles(const size_t max_count);
254
255 /// Specify a particle creation callback.
256 ///
257 /// Specify a callback function within your code that should be called every time a particle is created. The callback is associated only
258 /// with the particle group that is current at the time you make the BirthCallback() call. You can optionally pass a 32-bit value
259 /// that could be a handle to arbitrary data of your own, which is returned to your callback.
260 ///
261 /// The Particle_t struct is passed back to your callback function, so your application will have to include "Particle/pParticle.h".
262 void BirthCallback(P_PARTICLE_CALLBACK callback, ///< Pointer to function of yours to call
263 pdata_t group_data = 0 ///< Arbitrary per-group data of yours to pass into your function
264 );
265
266 /// Specify a particle death callback.
267 ///
268 /// Specify a callback function within your code that should be called every time a particle is killed. The callback is associated only
269 /// with the particle group that is current at the time you make the DeathCallback() call. You can optionally pass a pointer to arbitrary
270 /// data of your own, which is returned to your callback.
271 ///
272 /// The Particle_t struct is passed back to your callback function, so your application will have to include "Particle/pParticle.h".
273 void DeathCallback(P_PARTICLE_CALLBACK callback, ///< Pointer to function of yours to call
274 pdata_t group_data = 0 ///< Arbitrary per-group data of yours to pass into your function
275 );
276
277 /// Set the number of particles that fit in the CPU's cache
278 ///
279 /// You probably don't need to call this function. It is the number of bytes in the working set. Most action lists apply several actions to
280 /// the working set of particles, then load the next working set of particles and apply the same actions to them. This allows particles to
281 /// stay resident in the CPU's cache for a longer period of time, potentially increasing performance dramatically.
282 ///
283 /// You specify the working set size in bytes.
284 void SetWorkingSetSize(const int set_size_bytes);
285
286protected:
287 std::shared_ptr<PInternalState_t> PS; // The internal API data for this context is stored here.
288 void InternalSetup(std::shared_ptr<PInternalState_t> Sr); // Calls this after construction to set up the PS pointer
289};
290
291/// This class contains the Action API.
292///
293/// Actions modify the position, color, velocity, size, age, and other attributes of
294/// particles. All actions apply to the current particle group, as set by CurrentGroup().
295/// Some actions will add particles to or delete them from the particle group, and others
296/// will modify the particles in other ways. Typically, a series of actions will be
297/// applied to each particle group once (or more) per rendered frame.
298///
299/// Remember that the amount of effect of an action call depends on the time step size,
300/// dt, as set by \ref PAPI::PContextActionList_t::TimeStep().
301///
302/// Some functions have parameters with a default value of the constant P_EPS. P_EPS is a very small
303/// floating point constant that is most often used as the default value of the epsilon
304/// parameter to actions whose influence on a particle is relative to the inverse square
305/// of its distance from something. If that distance is very small, the amount of influence
306/// approaches infinity. Since all actions are computed using Euler's method, this can
307/// cause unsatisfying results in which particles are accelerated way too much. So this
308/// epsilon parameter is added to the distance before taking its inverse square, thus
309/// keeping the acceleration within reasonable limits. By varying epsilon, you specify
310/// what is reasonable. Larger epsilon make particles accelerate less.
311///
312/// \subsection inline_actions Inline Actions
313/// The inline actions API calls take a Particle_t as the first argument. The actions modify this particle using a function call that will be inlined.
314/// This enables a very efficient programming model with a (normally) parallel std::for_each loop around a per-particle list of actions.
315/// It also enables the inline actions functions to be called from CUDA, HIP, or other threads, allowing GPU acceleration.
316///
317/// The inline actions are called only from within a call to ParticleLoop(). For example: \code
318///
319/// P.ParticleLoop(std::execution::par_unseq, [&](Particle_t& p_) {
320/// P.Gravity(p_, Efx.GravityVec);
321/// P.Bounce(p_, 0.f, 0.5f, 0.f, PDDisc(pVec(0, 0, 1.f), pVec(0, 0, 1.f), 5));
322/// P.Move(p_, true, false);
323/// P.Sink(p_, false, PDPlane(pVec(0, 0, -3), pVec(0, 0, 1)));
324/// P.SinkVelocity(p_, true, PDSphere(pVec(0, 0, 0), 0.01));
325/// });
326/// P.CommitKills();
327/// \endcode
328///
329/// \subsection legacy_actions Legacy Actions
330/// The legacy, less performant, but perhaps more elegant Action API is still available.
331/// Other than not taking a Particle_t as the first parameter, the call signatures of the legacy API match those of the inline API.
332 class PContextActions_t {
333public:
334 /// Steer particles away from a domain of space.
335 ///
336 /// Particles are tested to see whether they will pass from being outside the specified domain to being inside it within look_ahead time
337 /// units from now if the next Move() action were to occur now. The specific direction and amount of turn is dependent on the kind of
338 /// domain being avoided.
339 ///
340 /// At present the only domains for which Avoid() is implemented are PDSphere, PDRectangle, PDTriangle, PDDisc and PDPlane.
341 void Avoid(Particle_t& m, const float magnitude, ///< how drastically the particle velocities are modified to avoid the obstacle at each time step.
342 const float epsilon, ///< added to distance to dampen acceleration
343 const float look_ahead, ///< how far forward along the velocity vector to look for the obstacle
344 const pDomain& dom ///< the space to avoid
345 );
346
347 /// Bounce particles off an object defined by a domain.
348 ///
349 /// Particles are tested to see whether they will pass from being outside the specified domain to being inside it if the next Move()
350 /// action were to occur now. If they would pass through the surface of the domain, they are instead bounced off it. That is, their
351 /// velocity vector is decomposed into components normal to the surface and tangent to the surface. The direction of the normal component
352 /// is reversed, and friction, resilience and fric_min_vel are applied to the components. They are then recomposed into a new velocity heading
353 /// away from the surface.
354 ///
355 /// Since particles are tested to see whether they would pass through the domain if Move() were called now, it is best to have Bounce()
356 /// be the last action that modifies a particle's velocity before calling Move().
357 /// Also, actions such as RandomDisplace() that modify a particle's position directly, rather than modifying its velocity vector, may yield
358 /// unsatisfying results when used with Bounce().
359 ///
360 /// At present Bounce() is not implemented for all domains. Feel free to implement others. For spheres, the particle bounces off either the inside or the
361 /// outside of the sphere. For planes, triangles and discs, the particles bounce off either side of the surface. For rectangles, particles bounce off either
362 /// side of the diamond-shaped patch whose corners are o, o+u, o+u+v, and o+v. See the documentation on domains for further explanation.
363 ///
364 /// Bounce() doesn't work correctly with small time step sizes for particles sliding along a surface, despite fric_min_vel. The friction and resilience
365 /// parameters should not be scaled by dt, since a bounce happens instantaneously. On the other hand, they should be scaled by dt because particles sliding
366 /// along a surface will hit more often if dt is smaller. Adjust these parameters manually when you change dt.
367 void Bounce(Particle_t& m, const float friction, ///< tangential component of the outgoing velocity vector is scaled by (1 - friction)
368 const float resilience, ///< normal component of the outgoing velocity vector is scaled by resilience
369 const float fric_min_vel, ///< only apply friction if tangential velocity is greater than fric_min_vel so particles can glide smoothly
370 const pDomain& dom ///< bounce off the surface of this domain
371 );
372
373 /// Set the secondary position and velocity from current.
374 void CopyVertexB(Particle_t& m, const bool copy_pos = true, ///< If true, sets particle's PositionB to the current position of that particle. This makes each
375 ///< particle remember this position so it can later return to it using the Restore() action.
376 const bool copy_vel = false ///< If true, sets particle's velocityB to the current velocity of that particle. Compute particle orientation
377 ///< by copying velocity before other actions. Then velocity X velocityB yields a tangent vector.
378 );
379
380 /// Simulate air by dampening particle velocities.
381 ///
382 /// If a particle's velocity magnitude is within min_vel and max_vel, then multiply each component of the velocity by the respective damping constant.
383 /// Typically, the three components of damping will have the same value.
384 ///
385 /// There are no bounds on the damping constants. Thus, by giving values greater than 1.0 they may be used to speed up particles instead of slow them down.
386 void Damping(Particle_t& m, const pVec& damping, ///< component-wise multiply this vector by the velocity vector
387 const float min_vel = 0.0f, ///< only dampen if velocity magnitude is greater than min_vel
388 const float max_vel = P_MAXFLOAT ///< only dampen if velocity magnitude is less than max_vel
389 );
390
391 /// Simulate air by dampening rotational velocities.
392 ///
393 /// If a particle's rotational velocity magnitude is within min_vel and max_vel, then multiply each component of the rotational velocity by
394 /// the respective damping constant. Typically, the three components of damping will have the same value.
395 ///
396 /// There are no bounds on the damping constants. Thus, by giving values greater than 1.0 they may be used to speed up particles instead of slow them down.
397 void RotDamping(Particle_t& m, const pVec& damping, ///< component-wise multiply this vector by the rotational velocity vector
398 const float min_vel = 0.0f, ///< only dampen if velocity magnitude is greater than min_vel
399 const float max_vel = P_MAXFLOAT ///< only dampen if velocity magnitude is less than max_vel
400 );
401
402 /// Exert force on each particle away from explosion center.
403 ///
404 /// Causes an explosion by accelerating all particles away from the center. Particles are accelerated away from the center by an amount proportional to
405 /// magnitude. The shock wave of the explosion has a gaussian magnitude. The peak of the wave front travels spherically outward from the center at the
406 /// specified velocity. So at a given time step, particles at a distance (velocity * age) from center will receive the most acceleration, and particles not
407 /// at the peak of the shock wave will receive a lesser outward acceleration.
408 ///
409 /// radius is the current radius of the explosion wave's peak. It is up to the application to increment the radius for each call to
410 /// Explosion(). For Explosion() calls in action lists, this means you will need to recreate the action list each time step.
411 ///
412 /// You can set up a standing wave by not incrementing the radius.
413 void Explosion(Particle_t& m, const pVec& center, ///< center point of shock wave
414 const float radius, ///< current radius of wave peak
415 const float magnitude, ///< scales the acceleration applied to particles
416 const float sigma, ///< standard deviation of the gaussian; the sharpness or broadness of the strength of the wave.
417 const float epsilon = P_EPS ///< added to distance to dampen acceleration
418 );
419
420 /// Accelerate particles in the given direction.
421 ///
422 /// The gravity acceleration vector is simply added to the velocity vector of each particle at each time step. The magnitude of the
423 /// gravity vector is the acceleration due to gravity.
424 void Gravity(Particle_t& m, const pVec& dir ///< acceleration vector
425 );
426
427 /// For particles in the domain of influence, accelerate them with a domain.
428 ///
429 /// For each particle within the jet's domain of influence, dom, Jet() chooses an acceleration vector from the domain acc and applies
430 /// it to the particle's velocity.
431 void Jet(Particle_t& m, const pDomain& dom, ///< apply jet to particles in this domain
432 const pDomain& acc ///< acceleration vector comes from this domain
433 );
434
435 /// Apply the particles' velocities to their positions, and age the particles.
436 ///
437 /// This action actually updates the particle positions by adding the current velocity to the current position and the current rotational
438 /// velocity to the current up vector. This is typically the last particle action performed in an iteration of a particle simulation, and
439 /// typically only occurs once per iteration.
440 ///
441 /// The velocity is multiplied by the time step length, dt, before being added to the position. This implements Euler's method of numerical
442 /// integration with a constant but specifiable step size. See TimeStep() for more on varying the time step size.
443 void Move(Particle_t& m, const bool move_velocity = true, ///< apply velocity to position.
444 const bool move_rotational_velocity = true ///< apply rotational velocity to Up vector. This is an optimization.
445 );
446
447 /// Accelerate particles toward the closest point on the given line.
448 ///
449 /// For each particle, this action computes the vector to the closest point on the line, and accelerates the particle in that direction.
450 void OrbitLine(Particle_t& m, const pVec& p, ///< a point on the line
451 const pVec& axis, ///< any vector parallel to the line
452 const float magnitude = 1.0f, ///< scales each particle's acceleration
453 const float epsilon = P_EPS, ///< added to distance to dampen acceleration
454 const float max_radius = P_MAXFLOAT ///< no particle further than max_radius from the line is affected
455 );
456
457 /// Accelerate particles toward the given center point.
458 ///
459 /// For each particle, this action computes the vector to the center point, and accelerates the particle in the vector direction.
460 void OrbitPoint(Particle_t& m, const pVec& center, ///< accelerate toward this point
461 const float magnitude = 1.0f, ///< scales each particle's acceleration
462 const float epsilon = P_EPS, ///< added to distance to dampen acceleration
463 const float max_radius = P_MAXFLOAT ///< no particle further than max_radius from the center is affected
464 );
465
466 /// Accelerate particles in random directions.
467 ///
468 /// For each particle, chooses an acceleration vector from the specified domain and adds it to the particle's velocity.
469 /// Reducing the time step, dt, will make a higher probability of being near the original velocity after unit time. Smaller dt approach
470 /// a normal distribution of velocity vectors instead of a square wave distribution.
471 void RandomAccel(Particle_t& m, const pDomain& dom ///< choose acceleration from this domain
472 );
473
474 /// Immediately displace position by a random amount.
475 ///
476 /// Chooses a displacement vector from the specified domain and adds it to the particle's position.
477 /// Reducing the time step, dt, will make a higher probability of being near the original position after unit time. Smaller dt approach a
478 /// normal distribution of particle positions instead of a square wave distribution.
479 ///
480 /// Since this action changes particle positions, rather than changing their velocities and depending on the Move() action to change the
481 /// positions, unsatisfying results may occur when used with the Avoid() or Bounce() actions.
482 /// In particular, particles may be displaced to the opposite side of the surface without bouncing off it.
483 void RandomDisplace(Particle_t& m, const pDomain& dom ///< choose position offset from this domain
484 );
485
486 /// Replace particle velocity with a random velocity.
487 ///
488 /// Sets each particle's velocity vector to a random vector in the specified domain.
489 /// This function is not affected by dt.
490 void RandomVelocity(Particle_t& m, const pDomain& dom ///< choose velocity from this domain
491 );
492
493 /// Immediately assign a random rotational velocity.
494 ///
495 /// Sets each particle's rotational velocity vector to a random vector in the specified domain.
496 /// This function is not affected by dt.
497 void RandomRotVelocity(Particle_t& m, const pDomain& dom ///< choose rotational velocity from this domain
498 );
499
500 /// Over time, restore particles to their target positionB and upB.
501 ///
502 /// If vel is true, computes a new velocity for each particle that will make the particle arrive at its positionB at the specified amount
503 /// of time in the future. If rvel is true, computes a new rotational velocity that moves up toward upB.
504 ///
505 /// The curved path that the particles take is a parametric quadratic. Once the specified amount of time has passed, Restore() instead sets
506 /// position and Up to equal positionB and upB and sets velocity and rotational velocity to 0 to freeze them in place.
507 ///
508 /// It is the application's responsibility to decrease time_left by dt on each call. When in an action list, this means you need to
509 /// recreate the action list each time step.
510 ///
511 /// The positionB attribute of each particle is typically the particle's position when it was created, or it can be specified within a
512 /// domain. This is controlled by VertexBTracks(), and VertexB(). The positionB can be set at any time to the particle's current position
513 /// using the CopyVertexB() action.
514 ///
515 /// Restore(0) is the opposite of CopyVertexB(); it sets each particle's position to be equal to its positionB. However, this has the side
516 /// effect of setting each particle's velocity to 0.
517 void Restore(Particle_t& m, const float time, ///< how long more until particles should arrive at target position and orientation
518 const bool vel = true, ///< restore positions
519 const bool rvel = true ///< restore up vectors
520 );
521
522 /// Clamp particle velocities to the given range.
523 ///
524 /// Computes each particle's speed (the magnitude of its velocity vector) and if it is less than min_speed or greater than max_speed the
525 /// velocity is scaled to within those bounds, while preserving the velocity vector's direction.
526 ///
527 /// The vector [0,0,0] is an exception because it has no direction. Such vectors are not modified by SpeedClamp().
528 void SpeedClamp(Particle_t& m, const float min_speed, ///< set velocity vectors below min_speed to min_speed
529 const float max_speed ///< set velocity vectors above max_speed to max_speed
530 );
531
532 /// Change color of all particles toward the specified color.
533 ///
534 /// Modifies the color and alpha of each particle to be scale percent of the way closer to the specified color and alpha. scale is
535 /// multiplied by dt before scaling the sizes. Thus, using smaller dt causes a slightly faster approach to the target color.
536 ///
537 /// This action makes all colors tend toward the specified, uniform color.
538 /// The value of scale will usually be very small (less than 0.01) to yield a gradual transition.
539 void TargetColor(Particle_t& m, const pVec& color, ///< target color
540 const float alpha, ///< target alpha value
541 const float scale ///< what percent of the way from the current color to the target color to transition in unit time
542 );
543
544 /// Change sizes of all particles toward the specified size.
545 ///
546 /// Modifies the size of each particle to be scale percent of the way closer to the specified size triple. This makes sizes grow
547 /// asymptotically closer to the given size. scale is multiplied by dt before scaling the sizes. Thus, using smaller dt causes a slightly
548 /// faster approach to the target size. The separate scales for each component allow only selected components to be scaled.
549 ///
550 /// This action makes all sizes tend toward the specified, uniform size. Future versions will have more actions that modify size.
551 /// Please send me suggestions (perhaps with sample implementations).
552 ///
553 /// The value of scale will usually be very small (less than 0.01) to yield a gradual transition.
554 void TargetSize(Particle_t& m, const pVec& size, ///< target size
555 const pVec& scale ///< what percent of the way from the current size to the target size to transition in unit time
556 );
557
558 /// Change velocity of all particles toward the specified velocity.
559 ///
560 /// Modifies the velocity of each particle to be scale percent of the way closer to the specified velocity. This makes velocities
561 /// grow asymptotically closer to the given velocity. scale is multiplied by dt before scaling the velocities. Thus, using smaller
562 /// dt causes a slightly faster approach to the target velocity.
563 ///
564 /// This action makes all velocities tend toward the specified, uniform velocity.
565 /// The value of scale will usually be very small (less than 0.01) to yield a gradual transition.
566 void TargetVelocity(Particle_t& m, const pVec& vel, ///< target velocity
567 const float scale ///< percent of the way from the current velocity to the target velocity to transition in unit time
568 );
569
570 /// Change rotational velocity of all particles toward the specified rotational velocity.
571 ///
572 /// Modifies the rotational velocity of each particle to be scale percent of the way closer to the specified rotational velocity.
573 /// This makes rotational velocities grow asymptotically closer to the given rotational velocity. scale is multiplied by dt before
574 /// scaling the velocities. Thus, using smaller dt causes a slightly faster approach to the target rotational velocity.
575 ///
576 /// This action makes all rotational velocities tend toward the specified, uniform rotational velocity.
577 /// The value of scale will usually be very small (less than 0.01) to yield a gradual transition.
578 void TargetRotVelocity(Particle_t& m, const pVec& rvel, ///< rotational velocity
579 const float scale ///< percent of the way from the current to the target rotational velocity to transition in unit time
580 );
581
582 /// Accelerate particles in a vortex-like way.
583 ///
584 /// The vortex is a complicated action to use, but when done correctly it makes particles fly around like in a tornado.
585 void Vortex(Particle_t& m, const pVec& tip, ///< tip of the vortex
586 const pVec& axis, ///< the ray along the center of the vortex
587 const float tightnessExponent, ///< exponent that curves the vortex silhouette; 1.0 is a cone; greater curves inward
588 const float max_radius, ///< no particle further than max_radius from the axis is affected
589 const float inSpeed, ///< inward acceleration of particles OUTSIDE the vortex
590 const float upSpeed, ///< vertical acceleration of particles INSIDE the vortex. Can be negative to apply gravity.
591 const float aroundSpeed ///< acceleration around vortex of particles INSIDE the vortex.
592 );
593
594 //////////////////////////////////////////////////////////////////
595 // Inter-particle actions
596
597 /// Accelerate toward the next particle in the list.
598 ///
599 /// This allows snaky effects where the particles follow each other. Each particle is accelerated toward the next particle in the group.
600 /// The Follow() action does not affect the last particle in the group. This allows controlled effects where the last particle in the group
601 /// is killed after each time step and replaced by a new particle at a slightly different position. See KillOld() to learn how to kill
602 /// the last particle in the group after each step.
603 void Follow(Particle_t& m, const float magnitude = 1.0f, ///< scales each particle's acceleration
604 const float epsilon = P_EPS, ///< added to distance to dampen acceleration
605 const float max_radius = P_MAXFLOAT ///< no particle further than max_radius from its predecessor is affected
606 );
607
608 /// Accelerate each particle toward each other particle.
609 ///
610 /// Each particle is accelerated toward each other particle.
611 /// This action is more computationally intensive than the others are because each particle is affected by each other particle.
612 void Gravitate(Particle_t& m, const float magnitude = 1.0f, ///< scales each particle's acceleration
613 const float epsilon = P_EPS, ///< added to distance to dampen acceleration
614 const float max_radius = P_MAXFLOAT ///< no particle further than max_radius from another particle is affected
615 );
616
617 /// Modify each particle's velocity to be similar to that of its neighbors.
618 ///
619 /// Each particle is accelerated toward the weighted mean of the velocities of the other particles in the group.
620 ///
621 /// Using an epsilon similar in size to magnitude can increase the range of influence of nearby particles on this particle.
622 void MatchVelocity(Particle_t& m, const float magnitude = 1.0f, ///< scales each particle's acceleration
623 const float epsilon = P_EPS, ///< added to distance to dampen acceleration
624 const float max_radius = P_MAXFLOAT ///< no particle further than max_radius from another particle is affected
625 );
626
627 /// Modify each particle's rotational velocity to be similar to that of its neighbors.
628 ///
629 /// Each particle is accelerated toward the weighted mean of the rotational velocities of the other particles in the group.
630 ///
631 /// Using an epsilon similar in size to magnitude can increase the range of influence of nearby particles on this particle.
632 void MatchRotVelocity(Particle_t& m, const float magnitude = 1.0f, ///< scales each particle's acceleration
633 const float epsilon = P_EPS, ///< added to distance to dampen acceleration
634 const float max_radius = P_MAXFLOAT ///< no particle further than max_radius from another particle is affected
635 );
636
637 //////////////////////////////////////////////////////////////////
638 // Other exceptional actions
639
640 /// Call an arbitrary user-provided function on each particle in the group.
641 ///
642 /// The function will receive both your call data and the full Particle_t struct, which contains per-particle user data.
643 void Callback(Particle_t& m, P_PARTICLE_CALLBACK_ACTION callbackFunc, ///< Pointer to function of yours to call.
644 const pdata_t call_data = 0 ///< Arbitrary data of yours to pass into your function
645 );
646
647 /// Get rid of older particles.
648 ///
649 /// Removes all particles older than age_limit. But if kill_less_than is true, it instead removes all particles newer than age_limit.
650 /// age_limit is not clamped, so negative values are ok. This can be used in conjunction with StartingAge(-n) to create and then kill a particular set of
651 /// particles.
652 ///
653 /// In order to kill a particular particle, set StartingAge() to a number that will never be a typical age for any other particle in the
654 /// group, for example -1.0. Then emit the particle using Source() or Vertex(). Then do the rest of the particle actions and finally call
655 /// KillOld(-0.9, true) to kill the special particle because it is the only one with an age less than -0.9.
656 void KillOld(Particle_t& m, const float age_limit, ///< max age of particles
657 const bool kill_less_than = false ///< true to kill particles younger than age_limit instead of older
658 );
659
660 /// Kill particles that have positions on wrong side of the specified domain.
661 ///
662 /// If kill_inside is true, deletes all particles inside the given domain. If kill_inside is false, deletes all particles outside the given domain.
663 void Sink(Particle_t& m, const bool kill_inside, ///< true to kill particles inside the domain
664 const pDomain& kill_pos_dom ///< kill particles in this domain
665 );
666
667 /// Kill particles that have velocities on wrong side of the specified domain.
668 ///
669 /// If kill_inside is true, deletes all particles whose velocity vectors are inside the given domain. If kill_inside is false, deletes all
670 /// particles whose velocity vectors are outside the given domain.
671 /// This allows particles to die when they turn around, get too fast or too slow, etc. For example, use a sphere domain centered at the
672 /// origin with a radius equal to the minimum velocity to kill particles that are too slow.
673 void SinkVelocity(Particle_t& m, const bool kill_inside, ///< true to kill particles with velocities inside the domain
674 const pDomain& kill_vel_dom ///< kill particles with velocities in this domain
675 );
676
677 /// Steer particles away from a domain of space.
678 ///
679 /// Particles are tested to see whether they will pass from being outside the specified domain to being inside it within look_ahead time
680 /// units from now if the next Move() action were to occur now. The specific direction and amount of turn is dependent on the kind of
681 /// domain being avoided.
682 ///
683 /// At present the only domains for which Avoid() is implemented are PDSphere, PDRectangle, PDTriangle, PDDisc and PDPlane.
684 void Avoid(const float magnitude, ///< how drastically the particle velocities are modified to avoid the obstacle at each time step.
685 const float epsilon, ///< added to distance to dampen acceleration
686 const float look_ahead, ///< how far forward along the velocity vector to look for the obstacle
687 const pDomain& dom ///< the space to avoid
688 );
689
690 /// Bounce particles off an object defined by a domain.
691 ///
692 /// Particles are tested to see whether they will pass from being outside the specified domain to being inside it if the next Move()
693 /// action were to occur now. If they would pass through the surface of the domain, they are instead bounced off it. That is, their
694 /// velocity vector is decomposed into components normal to the surface and tangent to the surface. The direction of the normal component
695 /// is reversed, and friction, resilience and fric_min_vel are applied to the components. They are then recomposed into a new velocity heading
696 /// away from the surface.
697 ///
698 /// Since particles are tested to see whether they would pass through the domain if Move() were called now, it is best to have Bounce()
699 /// be the last action that modifies a particle's velocity before calling Move().
700 /// Also, actions such as RandomDisplace() that modify a particle's position directly, rather than modifying its velocity vector, may yield
701 /// unsatisfying results when used with Bounce().
702 ///
703 /// At present Bounce() is not implemented for all domains. Feel free to implement others. For spheres, the particle bounces off either the inside or the
704 /// outside of the sphere. For planes, triangles and discs, the particles bounce off either side of the surface. For rectangles, particles bounce off either
705 /// side of the diamond-shaped patch whose corners are o, o+u, o+u+v, and o+v. See the documentation on domains for further explanation.
706 ///
707 /// Bounce() doesn't work correctly with small time step sizes for particles sliding along a surface, despite fric_min_vel. The friction and resilience
708 /// parameters should not be scaled by dt, since a bounce happens instantaneously. On the other hand, they should be scaled by dt because particles sliding
709 /// along a surface will hit more often if dt is smaller. Adjust these parameters manually when you change dt.
710 void Bounce(const float friction, ///< tangential component of the outgoing velocity vector is scaled by (1 - friction)
711 const float resilience, ///< normal component of the outgoing velocity vector is scaled by resilience
712 const float fric_min_vel, ///< only apply friction if tangential velocity is greater than fric_min_vel so particles can glide smoothly
713 const pDomain& dom ///< bounce off the surface of this domain
714 );
715
716 /// Set the secondary position and velocity from current.
717 void CopyVertexB(const bool copy_pos = true, ///< If true, sets particle's PositionB to the current position of that particle. This makes each
718 ///< particle remember this position so it can later return to it using the Restore() action.
719 const bool copy_vel = false ///< If true, sets particle's velocityB to the current velocity of that particle. Compute particle orientation
720 ///< by copying velocity before other actions. Then velocity X velocityB yields a tangent vector.
721 );
722
723 /// Simulate air by dampening particle velocities.
724 ///
725 /// If a particle's velocity magnitude is within min_vel and max_vel, then multiply each component of the velocity by the respective damping constant.
726 /// Typically, the three components of damping will have the same value.
727 ///
728 /// There are no bounds on the damping constants. Thus, by giving values greater than 1.0 they may be used to speed up particles instead of slow them down.
729 void Damping(const pVec& damping, ///< component-wise multiply this vector by the velocity vector
730 const float min_vel = 0.0f, ///< only dampen if velocity magnitude is greater than min_vel
731 const float max_vel = P_MAXFLOAT ///< only dampen if velocity magnitude is less than max_vel
732 );
733
734 /// Simulate air by dampening rotational velocities.
735 ///
736 /// If a particle's rotational velocity magnitude is within min_vel and max_vel, then multiply each component of the rotational velocity by
737 /// the respective damping constant. Typically, the three components of damping will have the same value.
738 ///
739 /// There are no bounds on the damping constants. Thus, by giving values greater than 1.0 they may be used to speed up particles instead of slow them down.
740 void RotDamping(const pVec& damping, ///< component-wise multiply this vector by the rotational velocity vector
741 const float min_vel = 0.0f, ///< only dampen if velocity magnitude is greater than min_vel
742 const float max_vel = P_MAXFLOAT ///< only dampen if velocity magnitude is less than max_vel
743 );
744
745 /// Exert force on each particle away from explosion center.
746 ///
747 /// Causes an explosion by accelerating all particles away from the center. Particles are accelerated away from the center by an amount proportional to
748 /// magnitude. The shock wave of the explosion has a gaussian magnitude. The peak of the wave front travels spherically outward from the center at the
749 /// specified velocity. So at a given time step, particles at a distance (velocity * age) from center will receive the most acceleration, and particles not
750 /// at the peak of the shock wave will receive a lesser outward acceleration.
751 ///
752 /// radius is the current radius of the explosion wave's peak. It is up to the application to increment the radius for each call to
753 /// Explosion(). For Explosion() calls in action lists, this means you will need to recreate the action list each time step.
754 ///
755 /// You can set up a standing wave by not incrementing the radius.
756 void Explosion(const pVec& center, ///< center point of shock wave
757 const float radius, ///< current radius of wave peak
758 const float magnitude, ///< scales the acceleration applied to particles
759 const float sigma, ///< standard deviation of the gaussian; the sharpness or broadness of the strength of the wave.
760 const float epsilon = P_EPS ///< added to distance to dampen acceleration
761 );
762
763 /// Accelerate particles in the given direction.
764 ///
765 /// The gravity acceleration vector is simply added to the velocity vector of each particle at each time step. The magnitude of the
766 /// gravity vector is the acceleration due to gravity.
767 void Gravity(const pVec& dir ///< acceleration vector
768 );
769
770 /// For particles in the domain of influence, accelerate them with a domain.
771 ///
772 /// For each particle within the jet's domain of influence, dom, Jet() chooses an acceleration vector from the domain acc and applies
773 /// it to the particle's velocity.
774 void Jet(const pDomain& dom, ///< apply jet to particles in this domain
775 const pDomain& acc ///< acceleration vector comes from this domain
776 );
777
778 /// Apply the particles' velocities to their positions, and age the particles.
779 ///
780 /// This action actually updates the particle positions by adding the current velocity to the current position and the current rotational
781 /// velocity to the current up vector. This is typically the last particle action performed in an iteration of a particle simulation, and
782 /// typically only occurs once per iteration.
783 ///
784 /// The velocity is multiplied by the time step length, dt, before being added to the position. This implements Euler's method of numerical
785 /// integration with a constant but specifiable step size. See TimeStep() for more on varying the time step size.
786 void Move(const bool move_velocity = true, ///< apply velocity to position.
787 const bool move_rotational_velocity = true ///< apply rotational velocity to Up vector. This is an optimization.
788 );
789
790 /// Accelerate particles toward the closest point on the given line.
791 ///
792 /// For each particle, this action computes the vector to the closest point on the line, and accelerates the particle in that direction.
793 void OrbitLine(const pVec& p, ///< a point on the line
794 const pVec& axis, ///< any vector parallel to the line
795 const float magnitude = 1.0f, ///< scales each particle's acceleration
796 const float epsilon = P_EPS, ///< added to distance to dampen acceleration
797 const float max_radius = P_MAXFLOAT ///< no particle further than max_radius from the line is affected
798 );
799
800 /// Accelerate particles toward the given center point.
801 ///
802 /// For each particle, this action computes the vector to the center point, and accelerates the particle in the vector direction.
803 void OrbitPoint(const pVec& center, ///< accelerate toward this point
804 const float magnitude = 1.0f, ///< scales each particle's acceleration
805 const float epsilon = P_EPS, ///< added to distance to dampen acceleration
806 const float max_radius = P_MAXFLOAT ///< no particle further than max_radius from the center is affected
807 );
808
809 /// Accelerate particles in random directions.
810 ///
811 /// For each particle, chooses an acceleration vector from the specified domain and adds it to the particle's velocity.
812 /// Reducing the time step, dt, will make a higher probability of being near the original velocity after unit time. Smaller dt approach
813 /// a normal distribution of velocity vectors instead of a square wave distribution.
814 void RandomAccel(const pDomain& dom ///< choose acceleration from this domain
815 );
816
817 /// Immediately displace position by a random amount.
818 ///
819 /// Chooses a displacement vector from the specified domain and adds it to the particle's position.
820 /// Reducing the time step, dt, will make a higher probability of being near the original position after unit time. Smaller dt approach a
821 /// normal distribution of particle positions instead of a square wave distribution.
822 ///
823 /// Since this action changes particle positions, rather than changing their velocities and depending on the Move() action to change the
824 /// positions, unsatisfying results may occur when used with the Avoid() or Bounce() actions.
825 /// In particular, particles may be displaced to the opposite side of the surface without bouncing off it.
826 void RandomDisplace(const pDomain& dom ///< choose position offset from this domain
827 );
828
829 /// Replace particle velocity with a random velocity.
830 ///
831 /// Sets each particle's velocity vector to a random vector in the specified domain.
832 /// This function is not affected by dt.
833 void RandomVelocity(const pDomain& dom ///< choose velocity from this domain
834 );
835
836 /// Immediately assign a random rotational velocity.
837 ///
838 /// Sets each particle's rotational velocity vector to a random vector in the specified domain.
839 /// This function is not affected by dt.
840 void RandomRotVelocity(const pDomain& dom ///< choose rotational velocity from this domain
841 );
842
843 /// Over time, restore particles to their target positionB and upB.
844 ///
845 /// If vel is true, computes a new velocity for each particle that will make the particle arrive at its positionB at the specified amount
846 /// of time in the future. If rvel is true, computes a new rotational velocity that moves up toward upB.
847 ///
848 /// The curved path that the particles take is a parametric quadratic. Once the specified amount of time has passed, Restore() instead sets
849 /// position and Up to equal positionB and upB and sets velocity and rotational velocity to 0 to freeze them in place.
850 ///
851 /// It is the application's responsibility to decrease time_left by dt on each call. When in an action list, this means you need to
852 /// recreate the action list each time step.
853 ///
854 /// The positionB attribute of each particle is typically the particle's position when it was created, or it can be specified within a
855 /// domain. This is controlled by VertexBTracks(), and VertexB(). The positionB can be set at any time to the particle's current position
856 /// using the CopyVertexB() action.
857 ///
858 /// Restore(0) is the opposite of CopyVertexB(); it sets each particle's position to be equal to its positionB. However, this has the side
859 /// effect of setting each particle's velocity to 0.
860 void Restore(const float time, ///< how long more until particles should arrive at target position and orientation
861 const bool vel = true, ///< restore positions
862 const bool rvel = true ///< restore up vectors
863 );
864
865 /// Clamp particle velocities to the given range.
866 ///
867 /// Computes each particle's speed (the magnitude of its velocity vector) and if it is less than min_speed or greater than max_speed the
868 /// velocity is scaled to within those bounds, while preserving the velocity vector's direction.
869 ///
870 /// The vector [0,0,0] is an exception because it has no direction. Such vectors are not modified by SpeedClamp().
871 void SpeedClamp(const float min_speed, ///< set velocity vectors below min_speed to min_speed
872 const float max_speed ///< set velocity vectors above max_speed to max_speed
873 );
874
875 /// Change color of all particles toward the specified color.
876 ///
877 /// Modifies the color and alpha of each particle to be scale percent of the way closer to the specified color and alpha. scale is
878 /// multiplied by dt before scaling the sizes. Thus, using smaller dt causes a slightly faster approach to the target color.
879 ///
880 /// This action makes all colors tend toward the specified, uniform color.
881 /// The value of scale will usually be very small (less than 0.01) to yield a gradual transition.
882 void TargetColor(const pVec& color, ///< target color
883 const float alpha, ///< target alpha value
884 const float scale ///< what percent of the way from the current color to the target color to transition in unit time
885 );
886
887 /// Change sizes of all particles toward the specified size.
888 ///
889 /// Modifies the size of each particle to be scale percent of the way closer to the specified size triple. This makes sizes grow
890 /// asymptotically closer to the given size. scale is multiplied by dt before scaling the sizes. Thus, using smaller dt causes a slightly
891 /// faster approach to the target size. The separate scales for each component allow only selected components to be scaled.
892 ///
893 /// This action makes all sizes tend toward the specified, uniform size. Future versions will have more actions that modify size.
894 /// Please send me suggestions (perhaps with sample implementations).
895 ///
896 /// The value of scale will usually be very small (less than 0.01) to yield a gradual transition.
897 void TargetSize(const pVec& size, ///< target size
898 const pVec& scale ///< what percent of the way from the current size to the target size to transition in unit time
899 );
900
901 /// Change velocity of all particles toward the specified velocity.
902 ///
903 /// Modifies the velocity of each particle to be scale percent of the way closer to the specified velocity. This makes velocities
904 /// grow asymptotically closer to the given velocity. scale is multiplied by dt before scaling the velocities. Thus, using smaller
905 /// dt causes a slightly faster approach to the target velocity.
906 ///
907 /// This action makes all velocities tend toward the specified, uniform velocity.
908 /// The value of scale will usually be very small (less than 0.01) to yield a gradual transition.
909 void TargetVelocity(const pVec& vel, ///< target velocity
910 const float scale ///< percent of the way from the current velocity to the target velocity to transition in unit time
911 );
912
913 /// Change rotational velocity of all particles toward the specified rotational velocity.
914 ///
915 /// Modifies the rotational velocity of each particle to be scale percent of the way closer to the specified rotational velocity.
916 /// This makes rotational velocities grow asymptotically closer to the given rotational velocity. scale is multiplied by dt before
917 /// scaling the velocities. Thus, using smaller dt causes a slightly faster approach to the target rotational velocity.
918 ///
919 /// This action makes all rotational velocities tend toward the specified, uniform rotational velocity.
920 /// The value of scale will usually be very small (less than 0.01) to yield a gradual transition.
921 void TargetRotVelocity(const pVec& rvel, ///< rotational velocity
922 const float scale ///< percent of the way from the current to the target rotational velocity to transition in unit time
923 );
924
925 /// Accelerate particles in a vortex-like way.
926 ///
927 /// The vortex is a complicated action to use, but when done correctly it makes particles fly around like in a tornado.
928 void Vortex(const pVec& tip, ///< tip of the vortex
929 const pVec& axis, ///< the ray along the center of the vortex
930 const float tightnessExponent, ///< exponent that curves the vortex silhouette; 1.0 is a cone; greater curves inward
931 const float max_radius, ///< no particle further than max_radius from the axis is affected
932 const float inSpeed, ///< inward acceleration of particles OUTSIDE the vortex
933 const float upSpeed, ///< vertical acceleration of particles INSIDE the vortex. Can be negative to apply gravity.
934 const float aroundSpeed ///< acceleration around vortex of particles INSIDE the vortex.
935 );
936
937 //////////////////////////////////////////////////////////////////
938 // Inter-particle actions
939
940 /// Accelerate toward the next particle in the list.
941 ///
942 /// This allows snaky effects where the particles follow each other. Each particle is accelerated toward the next particle in the group.
943 /// The Follow() action does not affect the last particle in the group. This allows controlled effects where the last particle in the group
944 /// is killed after each time step and replaced by a new particle at a slightly different position. See KillOld() to learn how to kill
945 /// the last particle in the group after each step.
946 void Follow(const float magnitude = 1.0f, ///< scales each particle's acceleration
947 const float epsilon = P_EPS, ///< added to distance to dampen acceleration
948 const float max_radius = P_MAXFLOAT ///< no particle further than max_radius from its predecessor is affected
949 );
950
951 /// Accelerate each particle toward each other particle.
952 ///
953 /// Each particle is accelerated toward each other particle.
954 /// This action is more computationally intensive than the others are because each particle is affected by each other particle.
955 void Gravitate(const float magnitude = 1.0f, ///< scales each particle's acceleration
956 const float epsilon = P_EPS, ///< added to distance to dampen acceleration
957 const float max_radius = P_MAXFLOAT ///< no particle further than max_radius from another particle is affected
958 );
959
960 /// Modify each particle's velocity to be similar to that of its neighbors.
961 ///
962 /// Each particle is accelerated toward the weighted mean of the velocities of the other particles in the group.
963 ///
964 /// Using an epsilon similar in size to magnitude can increase the range of influence of nearby particles on this particle.
965 void MatchVelocity(const float magnitude = 1.0f, ///< scales each particle's acceleration
966 const float epsilon = P_EPS, ///< added to distance to dampen acceleration
967 const float max_radius = P_MAXFLOAT ///< no particle further than max_radius from another particle is affected
968 );
969
970 /// Modify each particle's rotational velocity to be similar to that of its neighbors.
971 ///
972 /// Each particle is accelerated toward the weighted mean of the rotational velocities of the other particles in the group.
973 ///
974 /// Using an epsilon similar in size to magnitude can increase the range of influence of nearby particles on this particle.
975 void MatchRotVelocity(const float magnitude = 1.0f, ///< scales each particle's acceleration
976 const float epsilon = P_EPS, ///< added to distance to dampen acceleration
977 const float max_radius = P_MAXFLOAT ///< no particle further than max_radius from another particle is affected
978 );
979
980 //////////////////////////////////////////////////////////////////
981 // Other exceptional actions
982
983 /// Call an arbitrary user-provided function on each particle in the group.
984 ///
985 /// The function will receive both your call data and the full Particle_t struct, which contains per-particle user data.
986 void Callback(P_PARTICLE_CALLBACK_ACTION callbackFunc, ///< Pointer to function of yours to call.
987 const pdata_t call_data = 0 ///< Arbitrary data of yours to pass into your function
988 );
989
990 /// Get rid of older particles.
991 ///
992 /// Removes all particles older than age_limit. But if kill_less_than is true, it instead removes all particles newer than age_limit.
993 /// age_limit is not clamped, so negative values are ok. This can be used in conjunction with StartingAge(-n) to create and then kill a particular set of
994 /// particles.
995 ///
996 /// In order to kill a particular particle, set StartingAge() to a number that will never be a typical age for any other particle in the
997 /// group, for example -1.0. Then emit the particle using Source() or Vertex(). Then do the rest of the particle actions and finally call
998 /// KillOld(-0.9, true) to kill the special particle because it is the only one with an age less than -0.9.
999 void KillOld(const float age_limit, ///< max age of particles
1000 const bool kill_less_than = false ///< true to kill particles younger than age_limit instead of older
1001 );
1002
1003 /// Kill particles that have positions on wrong side of the specified domain.
1004 ///
1005 /// If kill_inside is true, deletes all particles inside the given domain. If kill_inside is false, deletes all particles outside the given domain.
1006 void Sink(const bool kill_inside, ///< true to kill particles inside the domain
1007 const pDomain& kill_pos_dom ///< kill particles in this domain
1008 );
1009
1010 /// Kill particles that have velocities on wrong side of the specified domain.
1011 ///
1012 /// If kill_inside is true, deletes all particles whose velocity vectors are inside the given domain. If kill_inside is false, deletes all
1013 /// particles whose velocity vectors are outside the given domain.
1014 /// This allows particles to die when they turn around, get too fast or too slow, etc. For example, use a sphere domain centered at the
1015 /// origin with a radius equal to the minimum velocity to kill particles that are too slow.
1016 void SinkVelocity(const bool kill_inside, ///< true to kill particles with velocities inside the domain
1017 const pDomain& kill_vel_dom ///< kill particles with velocities in this domain
1018 );
1019
1020 /// Delete particles tagged to be killed by inline P.I.KillOld(), P.I.Sink(), and P.I.SinkVelocity()
1021 void CommitKills();
1022
1023 /// Sort the particles by their projection onto the look vector.
1024 ///
1025 /// Many rendering systems require rendering transparent particles in back-to-front order. The ordering is defined by the eye point and the
1026 /// look vector. These are the same vectors you pass into gluLookAt(), for example. The vector from the eye point to each particle's
1027 /// position is computed, then projected onto the look vector. Particles are sorted back-to-front by the result of this dot product.
1028 /// Setting clamp_negative to true speeds up sorting time. Particles behind the viewer won't be visible so their relative order doesn't matter.
1029 void Sort(const pVec& eye, ///< eye point is a point on the line the particles project onto
1030 const pVec& look_dir, ///< direction vector of projection line; does not need to be normalized
1031 const bool front_to_back = false, ///< true to sort in front-to-back order instead of back-to-front
1032 const bool clamp_negative = false ///< true to set negative dot product values to zero before sorting
1033 );
1034
1035 /// Add particles with positions in the specified domain.
1036 ///
1037 /// Adds new particles to the current particle group. The particle positions are chosen from the given domain. All the other particle
1038 /// attributes such as color and velocity are chosen according to their current domains.
1039 ///
1040 /// When the Source action is called within an action list, the particle attribute domains used are those that were current when the Source
1041 /// command was called within the NewActionList() / EndActionList() block instead of when CallActionList() was called. Note that this is unlike OpenGL
1042 /// display lists.
1043 ///
1044 /// If particle_rate / dt is not an integer then Source() adjusts the number of particles to add during this time step so that the average
1045 /// number added per unit time is particle_rate.
1046 ///
1047 /// If too few particles seem to be added each frame, it is probably because the particle group is already full. If this is bad, you can
1048 /// grow the group using SetMaxParticles().
1049 void Source(const float particle_rate, ///< how many particles to add per unit time
1050 const pDomain& dom, ///< particle positions are chosen from this domain
1051 const pSourceState& SrcSt ///< all other particle attributes are chosen from this source state
1052 );
1053
1054 /// Add a single particle at the specified location.
1055 ///
1056 /// This action mostly is a shorthand for Source(1, PDPoint(x, y, z)) but allows different callback data per particle.
1057 ///
1058 /// When called in immediate mode, this action uses a slightly faster method to add a single particle to the current particle group.
1059 /// Also when in immediate mode, exactly one particle will be added per call, instead of an average of 1 / dt particles being added.
1060 /// Particle attributes are chosen according to their current domains, as with Source.
1061 ///
1062 /// The user data attribute is an exception. It always takes the attribute from the optional data parameter to Vertex(), overriding the source state value.
1063 ///
1064 /// This call is patterned after the glVertex() calls. It is useful for creating a particle group with exactly specified initial positions.
1065 /// For example, you can specify a geometrical model using Vertex calls, and then explode or deform it.
1066 void Vertex(const pVec& v, ///< position of particle to create
1067 const pSourceState& SrcSt, ///< all other particle attributes are chosen from this source state
1068 const pdata_t data = 0 ///< application data to be passed to the birth and death callbacks
1069 );
1070
1071 /// <summary>
1072 /// Loop over particles executing all actions expressed in function f
1073 /// </summary>
1074 /// <typeparam name="UnaryFunction"></typeparam>
1075 /// <param name="f">a lambda function expressing all operations to be performed on each particle</param>
1076 template <class UnaryFunction> void ParticleLoop(UnaryFunction f)
1077 {
1078 StartParticleLoop(PS, PSh);
1079 std::for_each(PSh.get_pgroup_begin(), PSh.get_pgroup_end(), f);
1080 EndParticleLoop(PS, PSh);
1081 }
1082
1083 /// <summary>
1084 /// Loop over particles executing all actions expressed in function f using the given execution policy for CPU parallelization
1085 /// </summary>
1086 /// <typeparam name="UnaryFunction"></typeparam>
1087 /// <param name="f">a lambda function expressing all operations to be performed on each particle</param>
1088 /// <param name="policy">execution policy to be used for parallelization, for example std::execution::par_unseq</param>
1089 template <class ExPol, class UnaryFunction> void ParticleLoop(ExPol&& policy, UnaryFunction f)
1090 {
1091 StartParticleLoop(PS, PSh);
1092 std::for_each(policy, PSh.get_pgroup_begin(), PSh.get_pgroup_end(), f);
1093 EndParticleLoop(PS, PSh);
1094 }
1095
1096protected:
1097 PInternalShadow_t PSh; // Shadow copy of some information from PInternalState_t that is used by the inline actions API
1098 std::shared_ptr<PInternalState_t> PS; // The internal API data for this context is stored here.
1099 void InternalSetup(std::shared_ptr<PInternalState_t> Sr); // Calls this after construction to set up the PS pointer
1100};
1101
1102/// The Particle System API Context - Your app should have one of these per host thread that will do particle systems concurrently.
1103///
1104/// This is a complete instance of the Particle API. All API state is stored in the context.
1105///
1106/// See the documentation of the base classes for the description of all the API entry points.
1107 class ParticleContext_t : public PContextParticleGroup_t, public PContextActionList_t, public PContextActions_t {
1108public:
1109 ParticleContext_t(); /// The context's default constructor
1110};
1111}; // namespace PAPI
1112
1113#endif
PAPI::PContextActionList_t
Action List Calls.
Definition: pAPIContext.h:40
PAPI::PContextActionList_t::TimeStep
void TimeStep(const float new_dt)
Specify the time step length.
PAPI::PContextActionList_t::CallActionList
void CallActionList(const int action_list_num)
Execute the specified action list on the current particle group.
PAPI::PContextActionList_t::GetTimeStep
float GetTimeStep() const
Return the current time step, as set with TimeStep()
PAPI::PContextActionList_t::Seed
void Seed(const unsigned int seed)
Set the random number seed.
PAPI::PContextActionList_t::GenActionLists
int GenActionLists(const int action_list_count=1)
Generate a block of empty action lists.
PAPI::PContextActionList_t::PS
std::shared_ptr< PInternalState_t > PS
Definition: pAPIContext.h:128
PAPI::PContextActionList_t::DeleteActionLists
void DeleteActionLists(const int action_list_num, const int action_list_count=1)
Delete one or more consecutive action lists.
PAPI::PContextActionList_t::NewActionList
void NewActionList(const int action_list_num)
Begin the creation of the specified action list.
PAPI::PContextActionList_t::EndActionList
void EndActionList()
End the creation of a new action list.
PAPI::PContextActionList_t::InternalSetup
void InternalSetup(std::shared_ptr< PInternalState_t > Sr)
PAPI::PContextActions_t
This class contains the Action API.
Definition: pAPIContext.h:332
PAPI::PContextActions_t::RandomDisplace
void RandomDisplace(const pDomain &dom)
Immediately displace position by a random amount.
PAPI::PContextActions_t::RandomDisplace
void RandomDisplace(Particle_t &m, const pDomain &dom)
Immediately displace position by a random amount.
Definition: pInlineActionsAPI.h:118
PAPI::PContextActions_t::KillOld
void KillOld(const float age_limit, const bool kill_less_than=false)
Get rid of older particles.
PAPI::PContextActions_t::Bounce
void Bounce(const float friction, const float resilience, const float fric_min_vel, const pDomain &dom)
Bounce particles off an object defined by a domain.
PAPI::PContextActions_t::TargetRotVelocity
void TargetRotVelocity(Particle_t &m, const pVec &rvel, const float scale)
Change rotational velocity of all particles toward the specified rotational velocity.
Definition: pInlineActionsAPI.h:166
PAPI::PContextActions_t::RandomAccel
void RandomAccel(Particle_t &m, const pDomain &dom)
Accelerate particles in random directions.
Definition: pInlineActionsAPI.h:112
PAPI::PContextActions_t::CommitKills
void CommitKills()
Delete particles tagged to be killed by inline P.I.KillOld(), P.I.Sink(), and P.I....
PAPI::PContextActions_t::SinkVelocity
void SinkVelocity(Particle_t &m, const bool kill_inside, const pDomain &kill_vel_dom)
Kill particles that have velocities on wrong side of the specified domain.
Definition: pInlineActionsAPI.h:227
PAPI::PContextActions_t::RandomAccel
void RandomAccel(const pDomain &dom)
Accelerate particles in random directions.
PAPI::PContextActions_t::CopyVertexB
void CopyVertexB(const bool copy_pos=true, const bool copy_vel=false)
Set the secondary position and velocity from current.
PAPI::PContextActions_t::Source
void Source(const float particle_rate, const pDomain &dom, const pSourceState &SrcSt)
Add particles with positions in the specified domain.
PAPI::PContextActions_t::TargetColor
void TargetColor(const pVec &color, const float alpha, const float scale)
Change color of all particles toward the specified color.
PAPI::PContextActions_t::MatchVelocity
void MatchVelocity(Particle_t &m, const float magnitude=1.0f, const float epsilon=P_EPS, const float max_radius=P_MAXFLOAT)
Modify each particle's velocity to be similar to that of its neighbors.
Definition: pInlineActionsAPI.h:194
PAPI::PContextActions_t::Restore
void Restore(Particle_t &m, const float time, const bool vel=true, const bool rvel=true)
Over time, restore particles to their target positionB and upB.
Definition: pInlineActionsAPI.h:136
PAPI::PContextActions_t::Callback
void Callback(Particle_t &m, P_PARTICLE_CALLBACK_ACTION callbackFunc, const pdata_t call_data=0)
Call an arbitrary user-provided function on each particle in the group.
Definition: pInlineActionsAPI.h:209
PAPI::PContextActions_t::Vertex
void Vertex(const pVec &v, const pSourceState &SrcSt, const pdata_t data=0)
Add a single particle at the specified location.
PAPI::PContextActions_t::Move
void Move(Particle_t &m, const bool move_velocity=true, const bool move_rotational_velocity=true)
Apply the particles' velocities to their positions, and age the particles.
Definition: pInlineActionsAPI.h:94
PAPI::PContextActions_t::Restore
void Restore(const float time, const bool vel=true, const bool rvel=true)
Over time, restore particles to their target positionB and upB.
PAPI::PContextActions_t::Jet
void Jet(Particle_t &m, const pDomain &dom, const pDomain &acc)
For particles in the domain of influence, accelerate them with a domain.
Definition: pInlineActionsAPI.h:88
PAPI::PContextActions_t::RandomRotVelocity
void RandomRotVelocity(const pDomain &dom)
Immediately assign a random rotational velocity.
PAPI::PContextActions_t::Avoid
void Avoid(const float magnitude, const float epsilon, const float look_ahead, const pDomain &dom)
Steer particles away from a domain of space.
PAPI::PContextActions_t::Follow
void Follow(const float magnitude=1.0f, const float epsilon=P_EPS, const float max_radius=P_MAXFLOAT)
Accelerate toward the next particle in the list.
PAPI::PContextActions_t::OrbitLine
void OrbitLine(Particle_t &m, const pVec &p, const pVec &axis, const float magnitude=1.0f, const float epsilon=P_EPS, const float max_radius=P_MAXFLOAT)
Accelerate particles toward the closest point on the given line.
Definition: pInlineActionsAPI.h:100
PAPI::PContextActions_t::SpeedClamp
void SpeedClamp(const float min_speed, const float max_speed)
Clamp particle velocities to the given range.
PAPI::PContextActions_t::KillOld
void KillOld(Particle_t &m, const float age_limit, const bool kill_less_than=false)
Get rid of older particles.
Definition: pInlineActionsAPI.h:215
PAPI::PContextActions_t::ParticleLoop
void ParticleLoop(ExPol &&policy, UnaryFunction f)
Loop over particles executing all actions expressed in function f using the given execution policy fo...
Definition: pAPIContext.h:1089
PAPI::PContextActions_t::Bounce
void Bounce(Particle_t &m, const float friction, const float resilience, const float fric_min_vel, const pDomain &dom)
Bounce particles off an object defined by a domain.
Definition: pInlineActionsAPI.h:44
PAPI::PContextActions_t::Sort
void Sort(const pVec &eye, const pVec &look_dir, const bool front_to_back=false, const bool clamp_negative=false)
Sort the particles by their projection onto the look vector.
PAPI::PContextActions_t::ParticleLoop
void ParticleLoop(UnaryFunction f)
Loop over particles executing all actions expressed in function f
Definition: pAPIContext.h:1076
PAPI::PContextActions_t::OrbitPoint
void OrbitPoint(const pVec &center, const float magnitude=1.0f, const float epsilon=P_EPS, const float max_radius=P_MAXFLOAT)
Accelerate particles toward the given center point.
PAPI::PContextActions_t::Vortex
void Vortex(const pVec &tip, const pVec &axis, const float tightnessExponent, const float max_radius, const float inSpeed, const float upSpeed, const float aroundSpeed)
Accelerate particles in a vortex-like way.
PAPI::PContextActions_t::Damping
void Damping(Particle_t &m, const pVec &damping, const float min_vel=0.0f, const float max_vel=P_MAXFLOAT)
Simulate air by dampening particle velocities.
Definition: pInlineActionsAPI.h:64
PAPI::PContextActions_t::OrbitLine
void OrbitLine(const pVec &p, const pVec &axis, const float magnitude=1.0f, const float epsilon=P_EPS, const float max_radius=P_MAXFLOAT)
Accelerate particles toward the closest point on the given line.
PAPI::PContextActions_t::TargetVelocity
void TargetVelocity(Particle_t &m, const pVec &vel, const float scale)
Change velocity of all particles toward the specified velocity.
Definition: pInlineActionsAPI.h:160
PAPI::PContextActions_t::Move
void Move(const bool move_velocity=true, const bool move_rotational_velocity=true)
Apply the particles' velocities to their positions, and age the particles.
PAPI::PContextActions_t::Explosion
void Explosion(Particle_t &m, const pVec &center, const float radius, const float magnitude, const float sigma, const float epsilon=P_EPS)
Exert force on each particle away from explosion center.
Definition: pInlineActionsAPI.h:76
PAPI::PContextActions_t::Gravity
void Gravity(Particle_t &m, const pVec &dir)
Accelerate particles in the given direction.
Definition: pInlineActionsAPI.h:82
PAPI::PContextActions_t::Gravitate
void Gravitate(Particle_t &m, const float magnitude=1.0f, const float epsilon=P_EPS, const float max_radius=P_MAXFLOAT)
Accelerate each particle toward each other particle.
Definition: pInlineActionsAPI.h:188
PAPI::PContextActions_t::PSh
PInternalShadow_t PSh
Definition: pAPIContext.h:1097
PAPI::PContextActions_t::TargetVelocity
void TargetVelocity(const pVec &vel, const float scale)
Change velocity of all particles toward the specified velocity.
PAPI::PContextActions_t::Follow
void Follow(Particle_t &m, const float magnitude=1.0f, const float epsilon=P_EPS, const float max_radius=P_MAXFLOAT)
Accelerate toward the next particle in the list.
Definition: pInlineActionsAPI.h:182
PAPI::PContextActions_t::Avoid
void Avoid(Particle_t &m, const float magnitude, const float epsilon, const float look_ahead, const pDomain &dom)
Steer particles away from a domain of space.
Definition: pInlineActionsAPI.h:31
PAPI::PContextActions_t::Vortex
void Vortex(Particle_t &m, const pVec &tip, const pVec &axis, const float tightnessExponent, const float max_radius, const float inSpeed, const float upSpeed, const float aroundSpeed)
Accelerate particles in a vortex-like way.
Definition: pInlineActionsAPI.h:172
PAPI::PContextActions_t::OrbitPoint
void OrbitPoint(Particle_t &m, const pVec &center, const float magnitude=1.0f, const float epsilon=P_EPS, const float max_radius=P_MAXFLOAT)
Accelerate particles toward the given center point.
Definition: pInlineActionsAPI.h:106
PAPI::PContextActions_t::Explosion
void Explosion(const pVec &center, const float radius, const float magnitude, const float sigma, const float epsilon=P_EPS)
Exert force on each particle away from explosion center.
PAPI::PContextActions_t::Sink
void Sink(Particle_t &m, const bool kill_inside, const pDomain &kill_pos_dom)
Kill particles that have positions on wrong side of the specified domain.
Definition: pInlineActionsAPI.h:221
PAPI::PContextActions_t::SpeedClamp
void SpeedClamp(Particle_t &m, const float min_speed, const float max_speed)
Clamp particle velocities to the given range.
Definition: pInlineActionsAPI.h:142
PAPI::PContextActions_t::Callback
void Callback(P_PARTICLE_CALLBACK_ACTION callbackFunc, const pdata_t call_data=0)
Call an arbitrary user-provided function on each particle in the group.
PAPI::PContextActions_t::PS
std::shared_ptr< PInternalState_t > PS
Definition: pAPIContext.h:1098
PAPI::PContextActions_t::RandomVelocity
void RandomVelocity(const pDomain &dom)
Replace particle velocity with a random velocity.
PAPI::PContextActions_t::Jet
void Jet(const pDomain &dom, const pDomain &acc)
For particles in the domain of influence, accelerate them with a domain.
PAPI::PContextActions_t::Sink
void Sink(const bool kill_inside, const pDomain &kill_pos_dom)
Kill particles that have positions on wrong side of the specified domain.
PAPI::PContextActions_t::RotDamping
void RotDamping(const pVec &damping, const float min_vel=0.0f, const float max_vel=P_MAXFLOAT)
Simulate air by dampening rotational velocities.
PAPI::PContextActions_t::MatchRotVelocity
void MatchRotVelocity(const float magnitude=1.0f, const float epsilon=P_EPS, const float max_radius=P_MAXFLOAT)
Modify each particle's rotational velocity to be similar to that of its neighbors.
PAPI::PContextActions_t::MatchRotVelocity
void MatchRotVelocity(Particle_t &m, const float magnitude=1.0f, const float epsilon=P_EPS, const float max_radius=P_MAXFLOAT)
Modify each particle's rotational velocity to be similar to that of its neighbors.
Definition: pInlineActionsAPI.h:200
PAPI::PContextActions_t::CopyVertexB
void CopyVertexB(Particle_t &m, const bool copy_pos=true, const bool copy_vel=false)
Set the secondary position and velocity from current.
Definition: pInlineActionsAPI.h:58
PAPI::PContextActions_t::TargetSize
void TargetSize(Particle_t &m, const pVec &size, const pVec &scale)
Change sizes of all particles toward the specified size.
Definition: pInlineActionsAPI.h:154
PAPI::PContextActions_t::SinkVelocity
void SinkVelocity(const bool kill_inside, const pDomain &kill_vel_dom)
Kill particles that have velocities on wrong side of the specified domain.
PAPI::PContextActions_t::Gravitate
void Gravitate(const float magnitude=1.0f, const float epsilon=P_EPS, const float max_radius=P_MAXFLOAT)
Accelerate each particle toward each other particle.
PAPI::PContextActions_t::Damping
void Damping(const pVec &damping, const float min_vel=0.0f, const float max_vel=P_MAXFLOAT)
Simulate air by dampening particle velocities.
PAPI::PContextActions_t::MatchVelocity
void MatchVelocity(const float magnitude=1.0f, const float epsilon=P_EPS, const float max_radius=P_MAXFLOAT)
Modify each particle's velocity to be similar to that of its neighbors.
PAPI::PContextActions_t::RotDamping
void RotDamping(Particle_t &m, const pVec &damping, const float min_vel=0.0f, const float max_vel=P_MAXFLOAT)
Simulate air by dampening rotational velocities.
Definition: pInlineActionsAPI.h:70
PAPI::PContextActions_t::RandomRotVelocity
void RandomRotVelocity(Particle_t &m, const pDomain &dom)
Immediately assign a random rotational velocity.
Definition: pInlineActionsAPI.h:130
PAPI::PContextActions_t::TargetRotVelocity
void TargetRotVelocity(const pVec &rvel, const float scale)
Change rotational velocity of all particles toward the specified rotational velocity.
PAPI::PContextActions_t::RandomVelocity
void RandomVelocity(Particle_t &m, const pDomain &dom)
Replace particle velocity with a random velocity.
Definition: pInlineActionsAPI.h:124
PAPI::PContextActions_t::TargetSize
void TargetSize(const pVec &size, const pVec &scale)
Change sizes of all particles toward the specified size.
PAPI::PContextActions_t::TargetColor
void TargetColor(Particle_t &m, const pVec &color, const float alpha, const float scale)
Change color of all particles toward the specified color.
Definition: pInlineActionsAPI.h:148
PAPI::PContextActions_t::Gravity
void Gravity(const pVec &dir)
Accelerate particles in the given direction.
PAPI::PContextActions_t::InternalSetup
void InternalSetup(std::shared_ptr< PInternalState_t > Sr)
PAPI::PContextParticleGroup_t
This class contains the API calls that operate on particle groups.
Definition: pAPIContext.h:146
PAPI::PContextParticleGroup_t::DeathCallback
void DeathCallback(P_PARTICLE_CALLBACK callback, pdata_t group_data=0)
Specify a particle death callback.
PAPI::PContextParticleGroup_t::SetWorkingSetSize
void SetWorkingSetSize(const int set_size_bytes)
Set the number of particles that fit in the CPU's cache.
PAPI::PContextParticleGroup_t::BirthCallback
void BirthCallback(P_PARTICLE_CALLBACK callback, pdata_t group_data=0)
Specify a particle creation callback.
PAPI::PContextParticleGroup_t::DeleteParticleGroups
void DeleteParticleGroups(const int p_group_num, const int p_group_count=1)
Delete one or more consecutive particle groups.
PAPI::PContextParticleGroup_t::GetParticlePointer
size_t GetParticlePointer(const float *&ptr, size_t &stride, size_t &pos3Ofs, size_t &posB3Ofs, size_t &size3Ofs, size_t &vel3Ofs, size_t &velB3Ofs, size_t &color3Ofs, size_t &alpha1Ofs, size_t &age1Ofs, size_t &up3Ofs, size_t &rvel3Ofs, size_t &upB3Ofs, size_t &mass1Ofs, size_t &data1Ofs)
Return a pointer to particle data stored in API memory.
PAPI::PContextParticleGroup_t::CopyGroup
void CopyGroup(const int p_src_group_num, const size_t index, const size_t copy_count)
Copy particles from the specified group into the current group.
PAPI::PContextParticleGroup_t::PS
std::shared_ptr< PInternalState_t > PS
Definition: pAPIContext.h:287
PAPI::PContextParticleGroup_t::GetMaxParticles
size_t GetMaxParticles()
Return the maximum number of particles allowed in the current group.
PAPI::PContextParticleGroup_t::GetGroupCount
size_t GetGroupCount()
Returns the number of particles existing in the current group.
PAPI::PContextParticleGroup_t::SetMaxParticles
void SetMaxParticles(const size_t max_count)
Change the maximum number of particles in the current group.
PAPI::PContextParticleGroup_t::GenParticleGroups
int GenParticleGroups(const int p_group_count=1, const size_t max_particles=0)
Create particle groups, each with a maximum of max_particles.
PAPI::PContextParticleGroup_t::CurrentGroup
void CurrentGroup(const int p_group_num)
Change which group is current.
PAPI::PContextParticleGroup_t::GetParticles
size_t GetParticles(const size_t index, const size_t count, float *position, const bool getAlpha, float *color=NULL, float *vel=NULL, float *size=NULL, float *age=NULL)
Copy particles from the current group to application memory.
PAPI::PContextParticleGroup_t::InternalSetup
void InternalSetup(std::shared_ptr< PInternalState_t > Sr)
PAPI::ParticleContext_t
The Particle System API Context - Your app should have one of these per host thread that will do part...
Definition: pAPIContext.h:1107
PAPI::ParticleContext_t::ParticleContext_t
ParticleContext_t()
PAPI::pDomain
A representation of a region of space.
Definition: pDomain.h:55
PAPI::pSourceState
These functions set the current state needed by Source() and Vertex() actions.
Definition: pSourceState.h:21
PAPI::pVec
A single-precision floating point three-vector.
Definition: pVec.h:63
PAPI
PAPIClasses.h.
Definition: pAPIContext.h:16
PAPI::P_MAXFLOAT
const float P_MAXFLOAT
A very large float value used as a default arg passed into functions.
Definition: pDeclarations.h:19
PAPI::P_PARTICLE_CALLBACK_ACTION
void(* P_PARTICLE_CALLBACK_ACTION)(struct Particle_t &particle, const pdata_t data, const float dt)
This is the type of the callback functions that you can register for the Callback() action.
Definition: pDeclarations.h:28
PAPI::pdata_t
unsigned int pdata_t
Definition: pDeclarations.h:16
PAPI::P_EPS
const float P_EPS
A very small float value added to some physical calculations to dampen them and improve stability.
Definition: pDeclarations.h:22
PAPI::Particle_t
Definition: pParticle.h:18