See full change log in git commit history, of course.

# Version 3.0.0 Changes (April 2022)

- Inline action mode allows massive speedup by enabling compiler optimization across actions, parallelization, and better memory access
- Removed last vestiges of action list emitting experiment.
- Minor enhancements to Playground app and Benchmark app.

# Version 2.3.0 Changes (April 2022)

- The build system is now CMake.
- The project is hosted on GitHub. Your collaboration is invited.
- Parallelized Gravitate and other N^2 actions using C++17 execution policies (just comment it out if you're not on C++17.)
- Parallelized Sort using C++17 execution policies (just comment it out if you're not on C++17.)
- Fixed multiple bugs in particle dynamics, including bounce off outside of sphere, and avoid.
- Bounce works on the inside and outside of boxes.
- The sample effects are much more elegant and unified.
- The sample effect particle dynamics are framerate independent by varying dt with frame time.
- The sample effects uniformly use units of seconds.
- The sample effects now render the domains they bounce off of or avoid.
- Flocking behavior effect, based on Boids by Craig Reynolds, is integrated to Effects.cpp and works great.
- Fixed two significant memory leaks.

# Version 2.21 Changes (December 2008)

- Made user data an attribute of particle source state, settable via the Data() call. Also made it a 64-bit unisgned integer. Before, it was sometimes a long and sometimes a void *.
- Added a Callback() action that simply calls user code for each particle in the middle of particle simulation. This allows for implementing effects that can't be expressed solely with the existing API.
- Ported to Visual Studio 2008 (MSVC 9.0). This yields about a 15% perf improvement.
- Fixed a memory leak with deleting ParticleContext_t.
- Fixed the bug with the distributed demos not running on certain XP machines because of a bug in the compiler's manifest generator.
- Fixed bug with bounding boxes.
- PSpray now waits at least 6 seconds before cycling to a different random demo.
- Thanks to Andrew Chew, Stefan Maton, Lloyd Tullues, and Bryan Witkowski for bug reports and fixes.

# Version 2.20 Changes (March 2007)

- Added the PDUnion domain, which is the union of multiple other domains. This gets us closer to being able to define a polygonal model domain. It also is a good way to specify colors for the Balloons effect, where colors come from disjoint sets, not from a continuum.
- Fixed the Within() function for many domains. Some domains just had their sense reversed. Non-3D domains used to always return false but now I try to determine whether the point rests in the plane or whatever.
- Wrote some domain self-testing code that does Generate() then calls Within() on the generated point to make sure they match.
- Added the new pError.h file and added an error when negative radiuses are supplied to a domain.
- Fixed Rotational damping. It was previously just doing positional damping. Oops!
- Avoid() was incorrectly being scaled by dt when computing the look_ahead position.
- Avoid() of a rectangle was steering toward the middle of the rectangle sometimes.
- Avoid() of a plane was pulling away from the plane too sharply, basically bouncing.
- Made PSpray check whether you have SSE and whether you have the necessary OpenGL extensions for point sprites.
- Added #include "typeinfo" to appease STLPort implementation of STL.
- Extended GetParticlePointer() to return all particle data.
- Tripled the performance of the pNRandf() function, which creates a normally-distributed random number.
- In PSpray, I check for the existance of SSE and I allow it to work without Nvidia's point sprites.
- Thanks to Greg Croft, Lloyd Tullues, and John Berendsen for bug reports and fixes.

# Version 2.10 Changes (November 2006)

- Documented the API using Doxygen. I'm new to Doxygen, so feel free to change things or give me advice. But finally the API documentation is current.
- Updated my Makefiles and compiled the code on Linux under GCC 4.1.
- Changed the Visual Studio project files to be Visual Studio 2005 (VC8). With VC8's stricter containers, I fixed a few pseudo-bugs.
- Implemented C++ exception handling for error detection and reporting.
- Created a PAPI namespace and put the whole API in it. My demos use "using namespace PAPI;", but you can put "PAPI::" in front of every identifier if you feel the need.
- Created a user-visible ParticleContext_t struct. It contains four base classes, each of which contains one of the four kinds of API calls. Most people will probably create a single, global ParticleContext_t in their app. For example,

      ParticleContext_t P;

      void DoParticles()
      {
          P.Color(pVec(1,1,1));
          P.Source(10, PDLine(pVec(0.0, 0.0, 0.401), pVec(0.0, 0.0, 0.405)));
          P.Move();
      }

  For single-threaded apps, the main change is that you say `P.Action()` rather than `pAction()`. This new structure is more thread-safe, more C++-esque and better performing when multithreaded.
- Renamed ColorD() to Color() and *D() because the function prototype distinguishes the version.
- Added a ResetSourceState() call that sets the particle creation state back to its default values.
- Changed SetMaxParticles() to not return a value because it was just the value that you passed in.
- Removed the Reset() function that deletes all the particles in the current group because SetMaxParticles(0) will do that.
- Changed the default value of StartingAge's sigma from 1.0 to 0.0. I figure that if people don't specify an amount of variation in the starting age, it's probably because they don't want any.
- Finally got a good Vortex action defined. It's beautiful!
- Optimized the code further. Performance is up by a factor of 2 or 3 in many cases.
- I tuned the working set size for action lists down to 256KB. This apparently gives us all the goodness, and works on every machine. Added a SetWorkingSetSize() command.
- Using action lists is now very beneficial. I changed PSpray to make this the default.
- Added flags to the Move() action to specify whether you're moving the velocity, rotational velocity, or both.
- Changed the semantics of the Restore() and Explosion() actions so that you now have to decrement time_left, or increment radius manually, even in action list mode. This is to preserve the rule that action lists don't change once created.
- Cleaned up the code internally, mostly in regards to STL containers that have changed with the compiler upgrades.
- Renamed some of the .cpp files to have more clear names.
- Fixed a bug where mass was not properly getting changed in some cases.
- Fixed a bug where particle age was not receiving a normal distribution for particles made with Vertex().

# Version 2.0 Beta Changes (March 2006)

This is the first major update to the particle system API in about five years. It includes enhancements in several areas. Here are the major improvements:

- More actions. I added pSort, which sorts particles back-to-front, given an eye point and look vector. I added control over the random number seeds (useful for repeatability and multithreaded apps). Someone (I wish I could remember who) added support for callback functions that get called whenever a particle is created or destroyed. He also added particle rotation actions. This is really nice for complex particles like boulders.
- Improved actions. The pJet action can now apply acceleration to particles within any domain, not just within a sphere. Particles can now bounce off the inside of a sphere domain. The vortex action is more sane now.
- Stronger typing. Each API call used to just take a long list of floats as args. This was confusing, especially for specifying domains. Now the vector type, pVec, and the domains are exposed as classes, so this line:

      pSource(10, PDLine, 0.0, 0.0, 0.401, 0.0, 0.0, 0.405);

  becomes this:

      pSource(10, PDLine(pVec(0.0, 0.0, 0.401), pVec(0.0, 0.0, 0.405)));

  This is much easier to read, safer, and now the Visual C++ editor can provide useful function prototype hints.
- Faster code. It is now very advantageous to use action lists. This is because I divide a particle group into working sets that are about the size of a CPU's L2 cache. I perform as many actions as possible on this working set before moving on to the next. That way, the particles only get loaded into cache on the first action of their working set, rather than for every action. This provides about a 2X speedup for large particle systems. I have also experimented with compound actions, which are hard-coded combinations of actions, such as "pSink(); pMove();". When these two appear in an action list, an internal action, pSinkMove, could be called instead to further reduce overhead. A compound Fountain action got about a 3X speedup over the traditional fountain. I have also experimented with using SSE, and have made some infrastructure changes to prepare, but haven't done the actual implementation yet. I have turned on /arch:SSE2 in the MSVC compiler and got about 15% speedup from it. I also improved the efficiency of several individual actions such as pRestore.
- Better code. I have used STL containers to re-implement action lists and particle groups, thereby fixing some bugs and making the code more readable. I made each kind of domain a separate class and use virtual functions instead of switch statements. It's just as fast and is much more solid and more extensible. I also reorganized classes and pulled all global variables into classes.
- Better demos. I have restructured the demos for better code sharing, and made it easier to add new effects. I spruced up some effects, and added new ones: a snow globe, a bunch of rectangles that the particles bounce off, and a flame thrower. It now cycles randomly through the demos like a screen saver.
- I added a point sprite rendering mode to the demos. Point sprites allow an arbitrary texture to be mapped onto a screen-aligned square primitive. This square is defined by a single GL vertex. This is several times faster than the old way of creating screen-aligned textured primitives, which required three or four vertices.
- I removed the pDrawGroup* calls. It's pretty rare that they provide exactly what you want, and they created a dependency on OpenGL. Instead, look at the code in Example.cpp and DrawGroups.cpp to see ways of drawing with OpenGL.

# Version 1.2 Changes (November 1999)

- Added a gaussian splat drawing mode to PSpray. You can draw either as a triangle or a quad with a gaussian alpha texture.
- Added a PDDisc domain for generating and bouncing.
- Split the PDPlane domain into PDPlane, for infinite planes and half-spaces; and PDRectangle, for rhombus-shaped planar patches.
- Added pTargetVelocity to make all particles tend toward a given velocity. This is a component of Boids.
- Added pMatchVelocity to match velocity to near neighbors.
- Added pAvoid to steer to avoid the given domain.
- Added pSpeedLimit.
- Removed pKillSlow. Instead use pSinkVelocity.
- Fixed a bug in the Within logic for PDBlob so now it's right.
- Demonstrated flocking behavior using a Boids demo.
- Changed pGetParticles so that verts can be NULL. It now returns the number of particles it's copying. This way you can just tell it the size of your array instead of having to call pGetGroupCount.
- Changed the particle size scalar to be a domain. This will allow greater expression of particle shape. Orientation becomes more important. Added pSizeD to specify it. Changed pGetParticles so that it returns three floats per particle for size.
- For Windows, made it a DLL instead of a static library.
- For Windows, ships with a DLL compiled with the Intel Vtune compiler (a bit faster).
- Made pspray choose a demo randomly on startup.
- Made pStartingAge take an optional parameter for the standard deviation of random starting ages, centered at age.
- Replaced the lifetime parameter of explosions with stdev and made the shock wave be gaussian instead of square. This will fix the ugly stratification effects in explosions of very dense particle clouds.
- Updated the documentation.
- Changed pCallActionList to be storable in action lists, as the docs said.
- Added a trivial app. for learning the API.
- Made a rocket demo. It has the rockets in one particle group and their sparks in another, generated at the rocket positions.
- When re-using an action list that was already generated, it now properly deletes the previous actions.

# Version 1.11 Changes (February 2, 1999)

- Added a length attribute
- Added more domains
- Added bug fixes