Skip to content

Instantly share code, notes, and snippets.

@matias-eduardo
Created July 15, 2023 19:31
Show Gist options
  • Save matias-eduardo/788fa6374c60e453b7534cd796f98867 to your computer and use it in GitHub Desktop.
Save matias-eduardo/788fa6374c60e453b7534cd796f98867 to your computer and use it in GitHub Desktop.
Particles with SOA
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#if defined(__linux)
#define HAVE_POSIX_TIMER
#include <time.h>
#ifdef CLOCK_MONOTONIC
#define CLOCKID CLOCK_MONOTONIC
#else
#define CLOCKID CLOCK_REALTIME
#endif
#elif defined(__APPLE__)
#define HAVE_MACH_TIMER
#include <mach/mach_time.h>
#elif defined(_WIN32)
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#endif
static uint64_t ns() {
static uint64_t is_init = 0;
#if defined(__APPLE__)
static mach_timebase_info_data_t info;
if (0 == is_init) {
mach_timebase_info(&info);
is_init = 1;
}
uint64_t now;
now = mach_absolute_time();
now *= info.numer;
now /= info.denom;
return now;
#elif defined(__linux)
static struct timespec linux_rate;
if (0 == is_init) {
clock_getres(CLOCKID, &linux_rate);
is_init = 1;
}
uint64_t now;
struct timespec spec;
clock_gettime(CLOCKID, &spec);
now = spec.tv_sec * 1.0e9 + spec.tv_nsec;
return now;
#elif defined(_WIN32)
static LARGE_INTEGER win_frequency;
if (0 == is_init) {
QueryPerformanceFrequency(&win_frequency);
is_init = 1;
}
LARGE_INTEGER now;
QueryPerformanceCounter(&now);
return (uint64_t) ((1e9 * now.QuadPart) / win_frequency.QuadPart);
#endif
}
///////////////////////////////
typedef struct vec3 {
float x, y, z;
} vec3;
vec3 vec3_add(vec3 a, vec3 b) {
return (vec3){
a.x + b.x,
a.y + b.y,
a.z + b.z,
};
}
vec3 vec3_sub(vec3 a, vec3 b) {
return (vec3){
a.x - b.x,
a.y - b.y,
a.z - b.z,
};
}
vec3 vec3_mulf(vec3 a, float f) {
return (vec3){
a.x * f,
a.y * f,
a.z * f,
};
}
float rand_float(float min, float max) {
return ((float)rand() / (float)RAND_MAX) * (max - min) + min;
}
///////////////////////////////
#define PARTICLES_MAX 32768
typedef struct Globals {
int particle_count;
vec3 particle_pos[PARTICLES_MAX];
vec3 particle_vel[PARTICLES_MAX];
float particle_time[PARTICLES_MAX];
} Globals;
static Globals o = {0};
static void particles_create() {
#define SPAWN_CHANCE 50
int new_chance = rand() % SPAWN_CHANCE;
if (new_chance == 0) {
int new_count = rand() % 1000;
if ((o.particle_count + new_count) > PARTICLES_MAX)
new_count = PARTICLES_MAX - o.particle_count;
for (int i = 0; i < new_count; i++)
o.particle_pos[o.particle_count+i] = (vec3){0, 0, 0};
for (int i = 0; i < new_count; i++)
o.particle_vel[o.particle_count+i] = (vec3){rand_float(-1000, 1000), rand_float(0, 1000), rand_float(-1000, 1000)};
for (int i = 0; i < new_count; i++)
o.particle_time[o.particle_count+i] = rand_float(0.5, 5.0);
o.particle_count += new_count;
}
}
static void particles_update() {
float tick = 1.0 / 60.0;
float half_tick = tick * 0.5;
for (int i = 0; i < o.particle_count; i++)
o.particle_vel[i].y += 8.0;
for (int i = 0; i < o.particle_count; i++)
o.particle_vel[i] = vec3_sub(o.particle_vel[i], vec3_mulf(o.particle_vel[i], half_tick));
for (int i = 0; i < o.particle_count; i++)
o.particle_pos[i] = vec3_add(o.particle_pos[i], vec3_mulf(o.particle_vel[i], tick));
for (int i = 0; i < o.particle_count; i++) {
o.particle_time[i] -= tick;
if (o.particle_time[i] < 0) {
o.particle_count--;
o.particle_pos[i] = o.particle_pos[o.particle_count];
o.particle_vel[i] = o.particle_vel[o.particle_count];
o.particle_time[i] = o.particle_time[o.particle_count];
i--;
}
}
}
int main(int argc, char **argv) {
// bench: init
srand(0xC0FFE);
// bench: warmup
#define WARMUP_RUNS 1000
for (int benchmark_i = 0; benchmark_i < WARMUP_RUNS; benchmark_i++) {
particles_create();
particles_update();
}
// bench: run
#define RUNS 100000
uint64_t time_start = ns();
for (int benchmark_i = 0; benchmark_i < RUNS; benchmark_i++) {
particles_create();
particles_update();
}
// bench: time
uint64_t total_time = ns() - time_start;
printf("In-place move, spawn chance 1/50, SOA: %8.2f ms\n", (double)total_time/1000000.0);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment