A clone of the game Geometry Wars including a bloom effect, a huge number of particles, and a deformable grid (also implemented as particles). Uses framebuffers to store particle position and velocity, allowing all particle simulation to be done on the GPU using shaders.
Sparks and the deformable grid are simulated using an old-school style GPGPU technique to simluate them as particles. Particles' positions and velocities are stored as textures on the GPU where the index of each pixel represents each particle, and the red and green values represent the x and y components of each vector. The sparks don't have any acceleration after being created, so all that's needed is the elapsed time to calculate the next position and velocity for each particle. Sparks are then rendered by passing in geometry data with each index to access to draw the particle.
Because the grid experiences variable acceleration, the process is more complex. Each intersection point is simulated as a particle as before, but there's two sources of acceleration it can experience: push forces from objects in the game, and pull forces from the elasticity of the grid.
In order to have multiple push effects on the grid, an acceleration texture is generated in screen space, where each pixel represents the acceleration that a particle at that position would experience from objects in the game.
This is combined with the pull force from the elasticity of the grid that pulls the grid particle back towards its initial position with strength proportional to its distance from that initial position. Initial positions are stored in another texture thats used when updating the grid particles.
There's a couple improvements I could make to the particle simulation, both of which weren't done initially because I was just learning how to use shaders to do more complex tasks, and wanted to keep things simple. First of all, positions and velocities could live in the same texture with the red and green components being the position and blue and alpha components being the velocity. Also instead of keeping a separate texture for the grid particles' initial positions, they could be generated on the fly in the shader using the indices passed in. Besides reducing the required video memory by more than half (going from 5 textures to 2 textures), this would also likely reduce cache misses while updating particles.