start reworking for checking looping neighbouring boids

This commit is contained in:
Rokas Puzonas 2023-08-07 00:32:39 +03:00
parent f6d001e9de
commit d1af945202
5 changed files with 176 additions and 56 deletions

View File

@ -19,6 +19,10 @@
static App g_app;
// TODO: Repeat visuals in looping walls mode
// TODO: Make WASM canvas resizable
// TODO: Add prompt for restarting program in WASM on crash
// TODO: Add controls window
@ -73,14 +77,11 @@ static void profiling_test() {
SetRandomSeed(10);
for (int i = 0; i < 50000; i++) {
Boid boid;
boid_rand_init(&world, &boid, 5);
world.boids.push_back(boid);
}
world_spawn_boids(&world, 50000);
for (int i = 0; i < FRAMERATE; i++) {
// world_update(&world, TIME_PER_FRAME);
arena_clear(&world.frame_arena);
world_update(&world, TIME_PER_FRAME);
}
printf("arena: %ld (%.03fMiB)\n", world.frame_arena.offset, (float)world.frame_arena.offset / 1024 / 1024);
@ -89,8 +90,8 @@ static void profiling_test() {
rprof_end();
printf("interactions: %d\n", g_prof_interactions);
int expected_interactions = 40501984;
if (g_prof_interactions != expected_interactions) { // 22 051 739
int expected_interactions = 40134438;
if (g_prof_interactions != expected_interactions) {
printf("!!!!!! ITERACTIONS DONT MATCH, %d\n", g_prof_interactions - expected_interactions);
}
@ -111,7 +112,7 @@ void UpdateDrawFrame() {
world_update(&g_world, dt);
}
#else
world_update(&g_app, &g_app.world, dt);
world_update(&g_app.world, dt);
#endif
visuals_update(&g_app.world, &g_app.visuals);
RPROF_STOP();

View File

@ -1,4 +1,5 @@
#include "raycast.hpp"
#include "raymath.hpp"
static float get_intersect_point(Vector2 ray_origin, Vector2 ray_dir, Vector2 line1, Vector2 line2) {
Vector2 line_dir = Vector2Subtract(line2, line1);
@ -17,8 +18,8 @@ static void set_nearest_hit(RayHitResult *nearest_hit, float hit, Vector2 line1,
bool is_gotten_hit_better = (nearest_hit->hit < 0 || nearest_hit->hit > hit);
if (got_hit && is_gotten_hit_better) {
nearest_hit->hit = hit;
nearest_hit->line1 = line1;
nearest_hit->line2 = line2;
// nearest_hit->line1 = line1;
// nearest_hit->line2 = line2;
}
}

View File

@ -4,9 +4,8 @@
struct RayHitResult {
float hit = -1;
// TODO: `line1` and `line2` are not used, maybe remove them?
Vector2 line1;
Vector2 line2;
// Vector2 line1; // not used
// Vector2 line2; // not used
};
static float get_intersect_point(Vector2 ray_origin, Vector2 ray_dir, Vector2 line1, Vector2 line2);

View File

@ -13,6 +13,7 @@ static inline bool mm_is_zero(__simdi x) {
#define mm_set1_ps(x) _mm256_set1_ps(x)
#define mm_sub_ps(a, b) _mm256_sub_ps(a, b)
#define mm_mul_ps(a, b) _mm256_mul_ps(a, b)
#define mm_add_ps(a, b) _mm256_add_ps(a, b)
#define mm_and_ps(a, b) _mm256_and_ps(a, b)
#define mm_store_ps(a, b) _mm256_store_ps(a, b)
#define mm_fmadd_ps(a, b, c) _mm256_fmadd_ps(a, b, c)
@ -32,6 +33,7 @@ static inline bool mm_is_zero(__simdi x) {
#define mm_set1_ps(x) _mm_set1_ps(x)
#define mm_sub_ps(a, b) _mm_sub_ps(a, b)
#define mm_mul_ps(a, b) _mm_mul_ps(a, b)
#define mm_add_ps(a, b) _mm_add_ps(a, b)
#define mm_and_ps(a, b) _mm_and_ps(a, b)
#define mm_store_ps(a, b) _mm_store_ps(a, b)
#define mm_fmadd_ps(a, b, c) _mm_add_ps(_mm_mul_ps(a, b), c)

View File

@ -239,27 +239,9 @@ static void app_cleanup(App *app) {
// --------------------- Utils -----------------------
void world_adjust_boid_count(World *world, int new_boid_count) {
if (new_boid_count >= MAX_BOIDS) return;
int boid_count = world->boids.size();
int diff = new_boid_count - boid_count;
if (diff > 0) {
for (int i = 0; i < diff; i++) {
Boid boid;
boid_rand_init(world, &boid, 5);
world->boids.push_back(boid);
}
} else if (diff < 0) {
for (int i = 0; i < -diff ; i++) {
world->boids.pop_back();
}
}
}
static void world_spawn_boids(World *world, size_t count) {
float border = 0;
if (world->looping_walls) {
if (!world->looping_walls) {
border = world->collision_avoidance_distance;
}
@ -270,6 +252,25 @@ static void world_spawn_boids(World *world, size_t count) {
}
}
void world_adjust_boid_count(World *world, int new_boid_count) {
if (new_boid_count >= MAX_BOIDS) return;
int boid_count = world->boids.size();
int diff = new_boid_count - boid_count;
if (diff > 0) {
world_spawn_boids(world, diff);
} else if (diff < 0) {
for (int i = 0; i < -diff ; i++) {
world->boids.pop_back();
}
}
}
// TODO: Enforce max view radius, so boid could not see himself in looping world
// static float world_get_max_boid_view_radius(World *world) {
// return MIN(world->size.x/2, world->size.y/2);
// }
// --------------------- Update -----------------------
static size_t chunkgrid_get_idx(ChunkGrid *grid, int x, int y) {
@ -306,9 +307,10 @@ static int nearest_multiple(int num, int divisor) {
return (num / divisor + (num % divisor > 0 ? 1 : 0)) * divisor;
}
struct boid_pair {
struct boid_cmp {
uboid_t from;
uboid_t to;
Vector2 to_offset;
};
#ifdef SIMD256
@ -323,7 +325,25 @@ struct boid_pair {
boids[b2b_cmps[8*i+1].SIDE].FIELD, \
boids[b2b_cmps[8*i+0].SIDE].FIELD \
)
#define GET_TO_OFFSET_FROM_CMPS(i, FIELD) \
_mm256_set_ps( \
b2b_cmps[8*i+7].to_offset.FIELD, \
b2b_cmps[8*i+6].to_offset.FIELD, \
b2b_cmps[8*i+5].to_offset.FIELD, \
b2b_cmps[8*i+4].to_offset.FIELD, \
b2b_cmps[8*i+3].to_offset.FIELD, \
b2b_cmps[8*i+2].to_offset.FIELD, \
b2b_cmps[8*i+1].to_offset.FIELD, \
b2b_cmps[8*i+0].to_offset.FIELD \
)
#else
#define GET_TO_OFFSET_FROM_CMPS(i, FIELD) \
_mm_set_ps( \
b2b_cmps[4*i+3].to_offset.FIELD, \
b2b_cmps[4*i+2].to_offset.FIELD, \
b2b_cmps[4*i+1].to_offset.FIELD, \
b2b_cmps[4*i+0].to_offset.FIELD \
)
#define GET_F32_CHUNK_FROM_BOIDS(i, SIDE, FIELD) \
_mm_set_ps( \
boids[b2b_cmps[4*i+3].SIDE].FIELD, \
@ -332,7 +352,7 @@ struct boid_pair {
boids[b2b_cmps[4*i+0].SIDE].FIELD \
)
#endif
static void world_calc_distances_and_angles(World *world, BoidList *local_boids, boid_pair *b2b_cmps, int *b2b_cmps_count) {
static void world_calc_distances_and_angles(World *world, BoidList *local_boids, boid_cmp *b2b_cmps, int *b2b_cmps_count) {
RPROF_START("Calc dot products and distances");
// Simplified from:
// float dot_threshold = Vector2DotProduct(dir, Vector2Rotate(dir, world->view_angle/2));
@ -359,9 +379,15 @@ static void world_calc_distances_and_angles(World *world, BoidList *local_boids,
__simd from_pos_x = GET_F32_CHUNK_FROM_BOIDS(i, from, pos.x);
__simd from_pos_y = GET_F32_CHUNK_FROM_BOIDS(i, from, pos.y);
__simd to_offset_pos_x = GET_TO_OFFSET_FROM_CMPS(i, x);
__simd to_offset_pos_y = GET_TO_OFFSET_FROM_CMPS(i, y);
__simd to_pos_x = GET_F32_CHUNK_FROM_BOIDS(i, to, pos.x);
__simd to_pos_y = GET_F32_CHUNK_FROM_BOIDS(i, to, pos.y);
to_pos_x = mm_add_ps(to_pos_x, to_offset_pos_x);
to_pos_y = mm_add_ps(to_pos_y, to_offset_pos_y);
__simd sub_x = mm_sub_ps(from_pos_x, to_pos_x);
__simd sub_y = mm_sub_ps(from_pos_y, to_pos_y);
@ -418,7 +444,8 @@ static void world_calc_distances_and_angles(World *world, BoidList *local_boids,
#define B2B_CAPACITY 1024*8
#define B2B_THRESHOLD B2B_CAPACITY*0.25
static inline void append_b2b_cmp(World *world, BoidList *local_boids, boid_pair *b2b_cmps, int *b2b_cmps_count, boid_pair b2b_cmp) {
// TODO: eeehh, a lot of parameters. Shorten?
static inline void append_b2b_cmp(World *world, BoidList *local_boids, boid_cmp *b2b_cmps, int *b2b_cmps_count, boid_cmp b2b_cmp) {
if ((*b2b_cmps_count) == B2B_CAPACITY) {
world_calc_distances_and_angles(world, local_boids, b2b_cmps, b2b_cmps_count);
}
@ -426,12 +453,96 @@ static inline void append_b2b_cmp(World *world, BoidList *local_boids, boid_pair
b2b_cmps[(*b2b_cmps_count)++] = b2b_cmp;
}
// TODO: eeehh, a lot of parameters. Shorten?
static inline void append_many_b2b_cmp(World *world, BoidList *local_boids, boid_cmp *b2b_cmps, int *b2b_cmps_count, Vector2 to_offset, uboid_t from_boid, uboid_t *to_boids, int to_boids_count) {
for (int i = 0; i < to_boids_count; i++) {
boid_cmp b2b_cmp = {
.from = from_boid,
.to = to_boids[i],
.to_offset = to_offset
};
append_b2b_cmp(world, local_boids, b2b_cmps, b2b_cmps_count, b2b_cmp);
}
}
// TODO: Dear god :O, this name.
static inline void world_compute_local_boids_looping_top_edge(BoidList *local_boids, World *world, ChunkGrid *chunks, uboid_t **static_chunks, boid_cmp *b2b_cmps, int *b2b_cmps_count, int neighbour_y) {
Vector2 to_offset = { 0, -world->size.y };
for (int x = 1; x < chunks->width; x++) {
size_t chunk_idx = chunkgrid_get_idx(chunks, x, 0);
BoidList *chunk = &chunks->data[chunk_idx];
uboid_t *chunk_boids = static_chunks[chunk_idx];
for (int ox = -1; ox <= 1; ox++) {
int neighbour_x = x+ox;
if (neighbour_x < 0 || neighbour_x >= chunks->width) continue;
size_t neighbour_idx = chunkgrid_get_idx(chunks, neighbour_x, neighbour_y);
BoidList *neighbour_chunk = &chunks->data[neighbour_idx];
uboid_t *neighbour_boids = static_chunks[neighbour_idx];
for (int i = 0; i < chunk->count; i++) {
uboid_t from_boid = chunk_boids[i];
append_many_b2b_cmp(world, local_boids, b2b_cmps, b2b_cmps_count, to_offset, chunk_boids[i], neighbour_boids, neighbour_chunk->count);
}
}
}
}
// TODO: Dear god :O, this name.
static inline void world_compute_local_boids_looping_left_edge(BoidList *local_boids, World *world, ChunkGrid *chunks, uboid_t **static_chunks, boid_cmp *b2b_cmps, int *b2b_cmps_count, int neighbour_x) {
Vector2 to_offset = { -world->size.x, 0 };
for (int y = 1; y < chunks->height; y++) {
size_t chunk_idx = chunkgrid_get_idx(chunks, 0, y);
BoidList *chunk = &chunks->data[chunk_idx];
uboid_t *chunk_boids = static_chunks[chunk_idx];
for (int oy = -1; oy <= 1; oy++) {
int neighbour_y = y+oy;
if (neighbour_y < 0 || neighbour_y >= chunks->height) continue;
size_t neighbour_idx = chunkgrid_get_idx(chunks, neighbour_x, neighbour_y);
BoidList *neighbour_chunk = &chunks->data[neighbour_idx];
uboid_t *neighbour_boids = static_chunks[neighbour_idx];
for (int i = 0; i < chunk->count; i++) {
uboid_t from_boid = chunk_boids[i];
append_many_b2b_cmp(world, local_boids, b2b_cmps, b2b_cmps_count, to_offset, chunk_boids[i], neighbour_boids, neighbour_chunk->count);
}
}
}
}
// TODO: Dear god :O, this name. PLEASE DO SOMETHING
static inline void world_compute_local_boids_looping_top_left(BoidList *local_boids, World *world, ChunkGrid *chunks, uboid_t **static_chunks, boid_cmp *b2b_cmps, int *b2b_cmps_count, int neighbour_x) {
Vector2 to_offset = { -world->size.x, 0 };
for (int y = 1; y < chunks->height; y++) {
size_t chunk_idx = chunkgrid_get_idx(chunks, 0, y);
BoidList *chunk = &chunks->data[chunk_idx];
uboid_t *chunk_boids = static_chunks[chunk_idx];
for (int oy = -1; oy <= 1; oy++) {
int neighbour_y = y+oy;
if (neighbour_y < 0 || neighbour_y >= chunks->height) continue;
size_t neighbour_idx = chunkgrid_get_idx(chunks, neighbour_x, neighbour_y);
BoidList *neighbour_chunk = &chunks->data[neighbour_idx];
uboid_t *neighbour_boids = static_chunks[neighbour_idx];
for (int i = 0; i < chunk->count; i++) {
uboid_t from_boid = chunk_boids[i];
append_many_b2b_cmp(world, local_boids, b2b_cmps, b2b_cmps_count, to_offset, chunk_boids[i], neighbour_boids, neighbour_chunk->count);
}
}
}
}
static void world_compute_local_boids(BoidList *local_boids, World *world, ChunkGrid *chunks) {
Boid *boids = world->boids.data();
int boid_count = world->boids.size();
MemoryArena *arena = &world->frame_arena;
boid_pair *b2b_cmps = (boid_pair*)arena_malloc(arena, (B2B_CAPACITY + SIMD_32B_LANES)*sizeof(boid_pair));
boid_cmp *b2b_cmps = (boid_cmp*)arena_malloc(arena, (B2B_CAPACITY + SIMD_32B_LANES)*sizeof(boid_cmp));
int b2b_cmps_count = 0;
RPROF_START("Move chunk data to static arrays");
@ -446,7 +557,7 @@ static void world_compute_local_boids(BoidList *local_boids, World *world, Chunk
}
RPROF_STOP();
RPROF_START("Iterate over chunks");
RPROF_START("Iterate over chunks (for local boids)");
for (int y = 0; y < chunks->height; y++) {
for (int x = 0; x < chunks->width; x++) {
size_t chunk_idx = chunkgrid_get_idx(chunks, x, y);
@ -459,13 +570,7 @@ static void world_compute_local_boids(BoidList *local_boids, World *world, Chunk
uboid_t *to_boids = &chunk_boids[i+1];
uboid_t to_boids_count = chunk->count-i-1;
for (int j = 0; j < to_boids_count; j++) {
boid_pair b2b_cmp = {
.from = from_boid,
.to = to_boids[j]
};
append_b2b_cmp(world, local_boids, b2b_cmps, &b2b_cmps_count, b2b_cmp);
}
append_many_b2b_cmp(world, local_boids, b2b_cmps, &b2b_cmps_count, { 0 }, from_boid, to_boids, to_boids_count);
}
Vector2 neighbours[] = { { 1, 0 }, { 0, 1 }, { 1, 1 }, { -1, 1 } };
@ -477,17 +582,11 @@ static void world_compute_local_boids(BoidList *local_boids, World *world, Chunk
size_t neighbour_idx = chunkgrid_get_idx(chunks, chunk_x, chunk_y);
BoidList *neighbour_chunk = &chunks->data[neighbour_idx];
if (neighbour_chunk->count == 0) continue;
uboid_t *neighbour_boids = static_chunks[neighbour_idx];
for (int i = 0; i < chunk->count; i++) {
for (int j = 0; j < neighbour_chunk->count; j++) {
boid_pair b2b_cmp = {
.from = chunk_boids[i],
.to = neighbour_boids[j]
};
append_b2b_cmp(world, local_boids, b2b_cmps, &b2b_cmps_count, b2b_cmp);
}
uboid_t from_boid = chunk_boids[i];
append_many_b2b_cmp(world, local_boids, b2b_cmps, &b2b_cmps_count, { 0 }, from_boid, neighbour_boids, neighbour_chunk->count);
}
}
@ -497,6 +596,23 @@ static void world_compute_local_boids(BoidList *local_boids, World *world, Chunk
}
}
// For checking neighbours on the edge of the wall
if (world->looping_walls) {
// TODO: Rewrite a nicer version here.
// world_compute_local_boids_looping_top_edge(local_boids, world, chunks, static_chunks, b2b_cmps, &b2b_cmps_count, chunks->height-1);
// world_compute_local_boids_looping_left_edge(local_boids, world, chunks, static_chunks, b2b_cmps, &b2b_cmps_count, chunks->width-1);
//
// if (fmod(world->size.y, chunks->chunk_size) >= 1) {
// world_compute_local_boids_looping_top_edge(local_boids, world, chunks, static_chunks, b2b_cmps, &b2b_cmps_count, chunks->height-2);
// }
// if (fmod(world->size.x, chunks->chunk_size) >= 1) {
// world_compute_local_boids_looping_left_edge(local_boids, world, chunks, static_chunks, b2b_cmps, &b2b_cmps_count, chunks->width-2);
// }
// TODO: Check top left chunk
}
if (b2b_cmps_count > 0) {
world_calc_distances_and_angles(world, local_boids, b2b_cmps, &b2b_cmps_count);
}
@ -544,6 +660,7 @@ static BoidList* world_compute_local_boids(World *world) {
}
static void aggregate_flock_modifiers(World *world, BoidList *flock, Boid *boid, Vector2 *center, Vector2 *heading, Vector2 *separation_force) {
// TODO: use simd here
*center = { 0, 0 };
*heading = { 0, 0 };
*separation_force = { 0, 0 };
@ -564,14 +681,14 @@ static void aggregate_flock_modifiers(World *world, BoidList *flock, Boid *boid,
*center = vector2_div_value(*center, flock->count);
}
static void world_update(App *app, World *world, float dt) {
if (world->freeze) return;
static void world_update(World *world, float dt) {
Boid *boids = world->boids.data();
int boid_count = world->boids.size();
DEBUG_ASSERT(boid_count <= MAX_BOIDS);
world_place_boids_into_chunks(world);
if (world->freeze) return;
BoidList *list_of_local_boids = world_compute_local_boids(world);
RPROF_START("Apply forces");