#include "wapp.h" #include "raylib.h" #include #include #include #define WIDTH 1280 #define HEIGHT 720 #define HALF_WIDTH (WIDTH * 0.5f) #define HALF_HEIGHT (HEIGHT * 0.5f) #define MAX_WANDERER_DIM 8 #define MIN_WANDERER_DIM 3 #define MIN_ZONE_DIM 30 #define BG_COLOR (Color){.r = 0xea, .g = 0xf2, .b = 0xe3, .a = 0xff} #define FG_COLOR (Color){.r = 0x42, .g = 0x4C, .b = 0x55, .a = 0xff} #define ZONE_COLOR (Color){.r = 0xb4, .g = 0x65, .b = 0x4a, .a = 0xff} #define WANDERER_COUNT 50000 #define ZONE_COUNT 5 #define WANDERER_SLOWDOWN_FACTOR 0.5f #define WANDERER_SPEEDUP_FACTOR 2.0f #define MSG_BUF_LEN 4096 #define abs(A) (A < 0 ? A * -1 : A) #define min(A, B) (A < B ? A : B) #define max(A, B) (A > B ? A : B) #define OBJECT_COMMON struct {Position position; Scale scale;} typedef struct Position Position; struct Position { f32 x; f32 y; }; typedef struct Scale Scale; struct Scale { f32 width; f32 height; }; typedef struct Velocity Velocity; struct Velocity { f32 x; f32 y; }; typedef struct Wanderer Wanderer; struct Wanderer { OBJECT_COMMON; Velocity velocity; bool slow; }; typedef struct SlowZone SlowZone; struct SlowZone { OBJECT_COMMON; }; void init_wanderer(Wanderer *wanderer, XOR256State *state); void move_wanderer(Wanderer *wanderer, const SlowZone *zones); void render_wanderer(const Wanderer *wanderer); void init_slow_zone(SlowZone *zone, XOR256State *state); #ifndef NDEBUG void render_slow_zone(const SlowZone *zone); #endif bool inside_zone(const Wanderer *wanderer, const SlowZone *zone); f32 get_random_float(XOR256State *state); int main(void) { InitWindow(WIDTH, HEIGHT, "DOD test"); SetTargetFPS(120); Allocator arena = wapp_mem_arena_allocator_init(MB(10)); XOR256State state = wapp_prng_xorshift_init_state(); Wanderer *wanderers = wapp_mem_allocator_alloc(&arena, sizeof(Wanderer) * WANDERER_COUNT); SlowZone *zones = wapp_mem_allocator_alloc(&arena, sizeof(SlowZone) * ZONE_COUNT); assert(wanderers != NULL && zones != NULL); for (u64 i = 0; i < WANDERER_COUNT; ++i) { init_wanderer(&(wanderers[i]), &state); } for (u64 i = 0; i < ZONE_COUNT; ++i) { init_slow_zone(&(zones[i]),&state); } while (!WindowShouldClose()) { for (u64 i = 0; i < WANDERER_COUNT; ++i) { move_wanderer(&(wanderers[i]), zones); } BeginDrawing(); ClearBackground(BG_COLOR); #ifndef NDEBUG for (u64 i = 0; i < ZONE_COUNT; ++i) { render_slow_zone(&(zones[i])); } #endif for (u64 i = 0; i < WANDERER_COUNT; ++i) { render_wanderer(&(wanderers[i])); } EndDrawing(); } wapp_mem_arena_allocator_destroy(&arena); CloseWindow(); return 0; } void init_wanderer(Wanderer *wanderer, XOR256State *state) { wanderer->position = (Position){ .x = wapp_prng_xorshift_256(state) % WIDTH, .y = wapp_prng_xorshift_256(state) % HEIGHT, }; f32 scale = (f32)((wapp_prng_xorshift_256(state) % (MAX_WANDERER_DIM + 1 - MIN_WANDERER_DIM)) + MIN_WANDERER_DIM); wanderer->scale = (Scale){ .width = scale, .height = scale, }; wanderer->velocity = (Velocity){ .x = get_random_float(state), .y = get_random_float(state), }; } void move_wanderer(Wanderer *wanderer, const SlowZone *zones) { wanderer->position.x += wanderer->velocity.x; wanderer->position.y += wanderer->velocity.y; f32 max_x = WIDTH - wanderer->scale.width; f32 max_y = HEIGHT - wanderer->scale.height; if (wanderer->position.x < 0 || wanderer->position.x >= max_x) { wanderer->position.x = min(max(wanderer->position.x, 0), max_x); wanderer->velocity.x *= -1; } if (wanderer->position.y < 0 || wanderer->position.y >= max_y) { wanderer->position.y = min(max(wanderer->position.y, 0), max_y); wanderer->velocity.y *= -1; } bool was_slow = wanderer->slow; wanderer->slow = false; for (u64 i = 0; i < ZONE_COUNT; ++i) { if (inside_zone(wanderer, &(zones[i]))) { wanderer->slow = true; break; } } if (!was_slow && wanderer->slow) { wanderer->velocity.x *= WANDERER_SLOWDOWN_FACTOR; wanderer->velocity.y *= WANDERER_SLOWDOWN_FACTOR; } else if (was_slow && !(wanderer->slow)) { wanderer->velocity.x *= WANDERER_SPEEDUP_FACTOR; wanderer->velocity.y *= WANDERER_SPEEDUP_FACTOR; } } void render_wanderer(const Wanderer *wanderer) { Color color = wanderer->slow ? ZONE_COLOR : FG_COLOR; DrawRectangle( (i32)wanderer->position.x, (i32)wanderer->position.y, (i32)wanderer->scale.width, (i32)wanderer->scale.height, color ); } void init_slow_zone(SlowZone *zone, XOR256State *state) { zone->position = (Position){ .x = wapp_prng_xorshift_256(state) % WIDTH, .y = wapp_prng_xorshift_256(state) % HEIGHT, }; zone->scale = (Scale){ .width = wapp_prng_xorshift_256(state) % ((u64)HALF_WIDTH - MIN_ZONE_DIM) + MIN_ZONE_DIM, .height = wapp_prng_xorshift_256(state) % ((u64)HALF_HEIGHT - MIN_ZONE_DIM) + MIN_ZONE_DIM, }; } #ifndef NDEBUG void render_slow_zone(const SlowZone *zone) { DrawRectangleLines( zone->position.x, zone->position.y, zone->scale.width, zone->scale.height, ZONE_COLOR ); } #endif bool inside_zone(const Wanderer *wanderer, const SlowZone *zone) { f32 wanderer_min_x = wanderer->position.x + wanderer->scale.width; f32 wanderer_min_y = wanderer->position.y + wanderer->scale.height; f32 wanderer_max_x = wanderer->position.x; f32 wanderer_max_y = wanderer->position.y; f32 zone_x0 = zone->position.x; f32 zone_y0 = zone->position.y; f32 zone_x1 = zone->position.x + zone->scale.width; f32 zone_y1 = zone->position.y + zone->scale.height; return (wanderer_min_x > zone_x0 && wanderer_min_y > zone_y0 && wanderer_max_x < zone_x1 && wanderer_max_y < zone_y1); } f32 get_random_float(XOR256State *state) { i64 random = (i64)wapp_prng_xorshift_256(state) - INT64_MAX; return (f32)(random) / (f32)(INT64_MAX); }