add panning and zooming

This commit is contained in:
Rokas Puzonas 2023-08-03 00:49:04 +03:00
parent dc34800fac
commit b47d6235fd
3 changed files with 85 additions and 21 deletions

View File

@ -64,6 +64,8 @@ struct Visuals {
Color boid_color = BLACK;
Color bg_color = RAYWHITE;
Camera2D camera;
bool show_control_panel = true;
bool draw_boid_direction = false;

View File

@ -25,6 +25,8 @@ static World g_world;
static Visuals g_visuals;
static UI g_ui;
// TODO: Add controls window
// TODO: Make boids form specific shapes defined by user, options:
// Circles, triangles, by image, text.
@ -41,7 +43,7 @@ int main() {
int screen_height = 720;
raylib::Window window(screen_width, screen_height, "Boid Playground");
window.SetState(FLAG_VSYNC_HINT);
window.SetState(FLAG_VSYNC_HINT | FLAG_WINDOW_RESIZABLE);
GuiLoadStyleDefault();
@ -56,6 +58,7 @@ int main() {
g_world.boids.push_back(boid);
}
g_ui.target_boid_count = g_world.boids.size();
visuals_init(&g_world, &g_visuals);
#ifdef __EMSCRIPTEN__
emscripten_set_main_loop(UpdateDrawFrame, 0, 1);
@ -111,6 +114,9 @@ static void profiling_test() {
void UpdateDrawFrame() {
float dt = GetFrameTime();
g_world.size.x = GetScreenWidth();
g_world.size.y = GetScreenHeight();
RPROF_START("Update");
#ifdef PLATFORM_WEB
// If user goes to another tab and comes back, the time that the user was gone needs to be ignored.
@ -121,6 +127,7 @@ void UpdateDrawFrame() {
#else
world_update(&g_world, dt);
#endif
visuals_update(&g_world, &g_visuals);
RPROF_STOP();
// Draw

View File

@ -117,6 +117,11 @@ static void world_init(World *world, float width, float height) {
world->size = { width, height };
}
static void visuals_init(World *world, Visuals *visuals) {
visuals->camera = { 0 };
visuals->camera.zoom = 1;
}
static void world_free(World *world) {
arena_free(&world->frame_arena);
}
@ -305,7 +310,7 @@ static void world_compute_local_boids(BoidList *local_boids, World *world, Chunk
int boid_count = world->boids.size();
MemoryArena *arena = &world->frame_arena;
boid_pair b2b_cmps[B2B_CAPACITY + SIMD_32B_LANES];
boid_pair *b2b_cmps = (boid_pair*)arena_malloc(arena, (B2B_CAPACITY + SIMD_32B_LANES)*sizeof(boid_pair));
int b2b_cmps_count = 0;
RPROF_START("Move chunk data to static arrays");
@ -415,6 +420,27 @@ static BoidList* world_compute_local_boids(World *world) {
return all_local_boids;
}
static void aggregate_flock_modifiers(World *world, BoidList *flock, Boid *boid, Vector2 *center, Vector2 *heading, Vector2 *separation_force) {
*center = { 0, 0 };
*heading = { 0, 0 };
*separation_force = { 0, 0 };
uboid_t boid_id;
BoidsListNodeIterator it = boid_list_get_iterator(flock);
while (boid_list_iterator_next(&it, &boid_id)) {
Boid *flock_boid = &world->boids[boid_id];
*heading = Vector2Add(*heading, flock_boid->dir);
*center = Vector2Add(*center , flock_boid->pos);
Vector2 pos_diff = Vector2Subtract(boid->pos, flock_boid->pos);
float dist_sqr = Vector2LengthSqr(pos_diff);
if (dist_sqr <= world->separation_radius * world->separation_radius) {
*separation_force = Vector2Add(*separation_force, vector2_div_value(pos_diff, dist_sqr));
}
}
*center = vector2_div_value(*center, flock->count);
}
static void world_update(World *world, float dt) {
if (world->freeze) return;
@ -422,7 +448,7 @@ static void world_update(World *world, float dt) {
Boid *boids = world->boids.data();
int boid_count = world->boids.size();
assert(boid_count <= MAX_BOIDS);
DEBUG_ASSERT(boid_count <= MAX_BOIDS);
BoidList *list_of_local_boids = world_compute_local_boids(world);
@ -438,24 +464,8 @@ static void world_update(World *world, float dt) {
BoidList *local_boids = &list_of_local_boids[i];
if (local_boids->count > 0) {
Vector2 separation_force = { 0, 0 };
Vector2 flock_center = { 0, 0 };
Vector2 flock_heading = { 0, 0 };
uboid_t local_boid_id;
BoidsListNodeIterator it = boid_list_get_iterator(local_boids);
while (boid_list_iterator_next(&it, &local_boid_id)) {
Boid *local_boid = &boids[local_boid_id];
flock_heading = Vector2Add(flock_heading, local_boid->dir);
flock_center = Vector2Add(flock_center , local_boid->pos);
Vector2 pos_diff = Vector2Subtract(boid->pos, local_boid->pos);
float dist_sqr = Vector2LengthSqr(pos_diff);
if (dist_sqr <= world->separation_radius * world->separation_radius) {
separation_force = Vector2Add(separation_force, vector2_div_value(pos_diff, dist_sqr));
}
}
flock_center = vector2_div_value(flock_center, local_boids->count);
Vector2 separation_force, flock_center, flock_heading;
aggregate_flock_modifiers(world, local_boids, boid, &flock_center, &flock_heading, &separation_force);
Vector2 alignment_force = Vector2Normalize(flock_heading);
acc = Vector2Add(acc, vector2_mul_value(alignment_force, world->alignment_strength));
@ -633,11 +643,55 @@ static void draw_boids(World *world, Visuals *visuals) {
rlEnd();
}
static void visuals_update(World *world, Visuals *visuals) {
Camera2D *camera = &visuals->camera;
if (IsKeyPressed(KEY_R)) {
*camera = { 0 };
camera->zoom = 1;
}
if (IsMouseButtonDown(MOUSE_BUTTON_MIDDLE)) {
Vector2 delta = GetMouseDelta();
delta = Vector2Scale(delta, -1.0f/camera->zoom);
camera->target = Vector2Add(camera->target, delta);
}
float wheel = GetMouseWheelMove();
if (wheel != 0) {
// Get the world point that is under the mouse
Vector2 mouseWorldPos = GetScreenToWorld2D(GetMousePosition(), *camera);
// Set the offset to where the mouse is
camera->offset = GetMousePosition();
// Set the target to match, so that the camera maps the world space point
// under the cursor to the screen space point under the cursor at any zoom
camera->target = mouseWorldPos;
// Zoom increment
const float zoom_speed = 0.125f;
camera->zoom = camera->zoom*(1+zoom_speed*wheel);
if (camera->zoom < zoom_speed) camera->zoom = zoom_speed;
}
}
static void world_draw(World *world, Visuals *visuals) {
BeginMode2D(visuals->camera);
for (int i = 0; i < world->obstacles.size(); i++) {
draw_obstacle(&world->obstacles[i], GRAY);
}
Color border_color = RED;
float world_width = world->size.x;
float world_height = world->size.y;
DrawLine(0, -1, world_width, -1, RED);
DrawLine(-1, 0, -1, world_height, RED);
DrawLine(0, world_height+1, world_width, world_height+1, RED);
DrawLine(world_width+1, 0, world_width+1, world_height, RED);
if (visuals->draw_view_cone) {
Color view_cone_color = Fade(GRAY, 0.4);
for (int i = 0; i < world->boids.size(); i++) {
@ -673,4 +727,5 @@ static void world_draw(World *world, Visuals *visuals) {
DrawLine(boid->pos.x, boid->pos.y, look_pos.x, look_pos.y, RED);
}
}
EndMode2D();
}