C++ Playground

Sven van Huessen | Mar 29, 2024

💻 Language: C++


C++ Playground

A collection of small visual C++ projects/experiments. Including:

  • Particle Simulation
  • Conway’s Game of Life
  • Maze Generator + Solver
  • Wolfram CA
  • Verlet Physics

Particle Simulation (SIMD)

A simple particle simulation running on the CPU using SIMD (Single instruction multiple data) to speed things up.

Video below shows 900,000 particles getting their positions updated at ~3ms on a single thread (i7-11700K @ 3.6GHz). Rendering and clearing the screen takes around ~5-10ms depending on how spread out the particles are.

Clearing the screen is taking quite some time because I’m fading out the previous frame instead of just clearing it to black. This gives a trail effect for each particle

Note, the stutters and video compression are due to the recording software and the YouTube video player.

A particle simulation like this was a great way of experimenting with SIMD and low level optimizations. I started with a basic version where each particle got updated normally and slowly refactored each line of code to use SIMD.

Before:

float x = xDesiredDirections[i] + random.x * WanderStrength;
float y = yDesiredDirections[i] + random.y * WanderStrength;
float length = sqrt(x * x + y * y);
xDesiredDirections[i] = x / length;
yDesiredDirections[i] = y / length;

SIMD version:

__m256 xDir = _mm256_add_ps(_mm256_load_ps(&xDesiredDirections[i]), _mm256_mul_ps(_mm256_sub_ps(xRandom, half), wanderStrength));
__m256 yDir = _mm256_add_ps(_mm256_load_ps(&yDesiredDirections[i]), _mm256_mul_ps(_mm256_sub_ps(yRandom, half), wanderStrength));
__m256 length = _mm256_sqrt_ps(_mm256_add_ps(_mm256_mul_ps(xDir, xDir), _mm256_mul_ps(yDir, yDir)));
xDirResult = _mm256_div_ps(xDir, length);
yDirResult = _mm256_div_ps(yDir, length);

Source code on GitHub

Conway’s Game of Life

At this point, everyone knows Conway’s Game of Life right? Every pixel on the screen is either alive or dead, and based on the number of alive neighbors it will either stay alive, die or come back to life.

Video below shows a 1280x720 simulation running at ~0.2ms multithreaded. I picked 1280x720 for the video to avoid YouTube compression artifacts, but the simulation can easily run at 4K (3840x2160) at ~7ms.

Note, the video compression is due to the YouTube video player.

Also this project can be found on GitHub

Verlet Physics

A simple Verlet Physics simulation running on the CPU.

This simulation was a bit harder to multithread. I first tried to just loop through each particle and check for collisions, but doing this multithreaded caused issues with data races and synchronization.

To fix this I first hard to prepare the data in such a way that each thread could work on its own set of particles without interfering with others. I did this by dividing the simulation space into a grid and assigning each particle to a grid cell based on its position.

Giving a benchmark is a bit hard because it really depends on how many particles, their size, and how many collisions are happening.

Note, the video compression is due to the YouTube video player.

Each particle is placed in a grid cell based on its position. When checking for collisions, only particles in the same or neighboring cells are considered. This significantly reduces the number of collision checks needed, especially in simulations with a large number of particles:

VerleyGrid.png

Source code on GitHub

Circle Zoom

A simple experiment where you can keep dividing circles into smaller circles, eventually creating an image.

Note, the stutters and video compression are due to the recording software and the YouTube video player.

GitHub

All projects can be found on GitHub

Note, this is already quite some old code and have since become better at C++. If you’r elooking for more recent C++ code, check out my ImReflect