star-sim

Barnes-Hut gravity simulation.
git clone git://git.amin.space/star-sim.git
Log | Files | Refs | README | LICENSE

commit 4ca59d402d47862140956aa39b48f291fe63a56d
parent 52c7683e46472bb86513218491fa42f265a08628
Author: amin <dev@aminmesbah.com>
Date:   Sat,  5 Aug 2017 10:23:29 +0000

Add ability to zoom in and out.

FossilOrigin-Name: c927846f6865abf6d47a087a4bf579618e06caa3cacb9811b9b9dc0603e78322
Diffstat:
MREADME.md | 7+++++--
Msrc/platform_sdl.c | 29+++++++++++++++++++++--------
Msrc/star_garden.c | 139+++++++++++++++++++++++++++++++++++++++++++------------------------------------
Msrc/star_garden.h | 6++++--
4 files changed, 106 insertions(+), 75 deletions(-)

diff --git a/README.md b/README.md @@ -11,8 +11,11 @@ efficiently calculate the forces acting on each star. ### Keyboard Shortcuts - `WASD` or `HJKL`: Pan. -- `Arrow Keys`: Slow Pan. -- `Home`: Center View. +- `Arrow Keys`: Slow pan. +- `=`: Zoom in. +- `-`: Zoom out. +- `0`: Zoom standard. +- `Home`: Return to original view. - `b`: Toggle bounding box rendering. - `f`: Toggle brute-force mode. Stars turn blue when this mode is active, and gravitational attraction is calculated for every single pair of stars. The diff --git a/src/platform_sdl.c b/src/platform_sdl.c @@ -210,40 +210,53 @@ int main(int argc, char *argv[]) // TODO: move this to a function if (keystate[SDL_SCANCODE_A] || keystate[SDL_SCANCODE_H]) { - sim_state.view.dx += 5; + sim_state.view.dx += 5 / sim_state.view.zoom; } if (keystate[SDL_SCANCODE_D] || keystate[SDL_SCANCODE_L]) { - sim_state.view.dx -= 5; + sim_state.view.dx -= 5 / sim_state.view.zoom; } if (keystate[SDL_SCANCODE_W] || keystate[SDL_SCANCODE_K]) { - sim_state.view.dy += 5; + sim_state.view.dy += 5 / sim_state.view.zoom; } if (keystate[SDL_SCANCODE_S] || keystate[SDL_SCANCODE_J]) { - sim_state.view.dy -= 5; + sim_state.view.dy -= 5 / sim_state.view.zoom; } if (keystate[SDL_SCANCODE_LEFT]) { - sim_state.view.dx++; + sim_state.view.dx += 1 / sim_state.view.zoom; } if (keystate[SDL_SCANCODE_RIGHT]) { - sim_state.view.dx--; + sim_state.view.dx -= 1 / sim_state.view.zoom; } if (keystate[SDL_SCANCODE_UP]) { - sim_state.view.dy++; + sim_state.view.dy += 1 / sim_state.view.zoom; } if (keystate[SDL_SCANCODE_DOWN]) { - sim_state.view.dy--; + sim_state.view.dy -= 1 / sim_state.view.zoom; + } + if (keystate[SDL_SCANCODE_EQUALS]) + { + sim_state.view.zoom *= 1.01; + } + if (keystate[SDL_SCANCODE_MINUS]) + { + sim_state.view.zoom *= 0.99; + } + if (keystate[SDL_SCANCODE_0]) + { + sim_state.view.zoom = 1; } if (keystate[SDL_SCANCODE_HOME]) { sim_state.view.dx = 0; sim_state.view.dy = 0; + sim_state.view.zoom = 1; } struct OffscreenBuffer buffer; diff --git a/src/star_garden.c b/src/star_garden.c @@ -26,6 +26,7 @@ void sim_init(struct SimState *sim_state, int field_width, int field_height) sim_state->view.dx = 0; sim_state->view.dy = 0; + sim_state->view.zoom = 1; float min_x = field_width / 2; float max_x = field_width / 2; @@ -181,69 +182,44 @@ void sim_render(struct OffscreenBuffer *buffer, float dt, struct SimState *sim_s return; } - float dx = sim_state->view.dx; - float dy = sim_state->view.dy; int num_stars = sim_state->num_stars; struct Star *stars = sim_state->stars; struct QuadTree *qt = sim_state->qt; - //printf("%f\n", dt); - if (BRUTE_FORCE) + + float dx = sim_state->view.dx; + float dy = sim_state->view.dy; + float zoom = sim_state->view.zoom; + + for (int i = 0; i < num_stars; ++i) { - for (int i = 0; i < num_stars; ++i) + uint32_t color; + if (BRUTE_FORCE) { - sim_set_pixel( - buffer, - (stars[i].x + (sinf(stars[i].angle) * stars[i].speed) * dt) + dx, - (stars[i].y - (cosf(stars[i].angle) * stars[i].speed) * dt) + dy, - COLOR_CYAN); + color = COLOR_CYAN; } - } - else - { - for (int i = 0; i < num_stars; ++i) + else { - sim_set_pixel( - buffer, - (stars[i].x + (sinf(stars[i].angle) * stars[i].speed) * dt) + dx, - (stars[i].y - (cosf(stars[i].angle) * stars[i].speed) * dt) + dy, - stars[i].color); + color = stars[i].color; } + sim_set_pixel( + buffer, + sim_calc_render_offset(zoom, dx, stars[i].x + (sinf(stars[i].angle) * stars[i].speed) * dt, buffer->width/2), + sim_calc_render_offset(zoom, dy, stars[i].y - (cosf(stars[i].angle) * stars[i].speed) * dt, buffer->height/2), + color); } if (RENDER_GRID) { - sim_grid_render(buffer, qt->root, COLOR_GREEN, dx, dy); + sim_grid_render(buffer, qt->root, COLOR_GREEN, &sim_state->view); } if (RENDER_BOUNDING_BOX) { - sim_bounding_box_render(buffer, &sim_state->bounding_box, COLOR_RED, dx, dy); - } -} - - -void sim_set_pixel(struct OffscreenBuffer *buffer, uint32_t x, uint32_t y, uint32_t color) -{ - if (!buffer) - { - // TODO: handle invalid pointer error - return; - } - - /* Origin is (0, 0) on the upper left. - * To go one pixel right, increment by 32 bits. - * To go one pixel down, increment by (buffer.width * 32) bits. - */ - if (x < buffer->width && y < buffer->height) - { - uint8_t *pixel_pos = (uint8_t *)buffer->memory; - pixel_pos += ((BYTES_PER_PIXEL*x) + (buffer->pitch * y)); - uint32_t *pixel = (uint32_t *)pixel_pos; - *pixel = color; + sim_bounding_box_render(buffer, &sim_state->bounding_box, COLOR_RED, &sim_state->view); } } -void sim_grid_render(struct OffscreenBuffer *buffer, struct QuadTreeNode *node, uint32_t color, float dx, float dy) +void sim_grid_render(struct OffscreenBuffer *buffer, struct QuadTreeNode *node, uint32_t color, struct SimView *view) { if (!buffer) { @@ -257,25 +233,33 @@ void sim_grid_render(struct OffscreenBuffer *buffer, struct QuadTreeNode *node, x <= (node->cell->center_x + node->cell->distance_x); ++x) { - sim_set_pixel(buffer, x + dx, node->cell->center_y + dy, color); + sim_set_pixel( + buffer, + sim_calc_render_offset(view->zoom, view->dx, x, buffer->width/2), + sim_calc_render_offset(view->zoom, view->dy, node->cell->center_y, buffer->height/2), + color); } for (int y = (node->cell->center_y - node->cell->distance_y); y <= (node->cell->center_y + node->cell->distance_y); ++y) { - sim_set_pixel(buffer, node->cell->center_x + dx, y + dy, color); + sim_set_pixel( + buffer, + sim_calc_render_offset(view->zoom, view->dx, node->cell->center_x, buffer->width/2), + sim_calc_render_offset(view->zoom, view->dy, y, buffer->height/2), + color); } - sim_grid_render(buffer, node->ne, color, dx, dy); - sim_grid_render(buffer, node->nw, color, dx, dy); - sim_grid_render(buffer, node->sw, color, dx, dy); - sim_grid_render(buffer, node->se, color, dx, dy); + sim_grid_render(buffer, node->ne, color, view); + sim_grid_render(buffer, node->nw, color, view); + sim_grid_render(buffer, node->sw, color, view); + sim_grid_render(buffer, node->se, color, view); } } -void sim_bounding_box_render(struct OffscreenBuffer *buffer, struct SimBounds *bounding_box, uint32_t color, float dx, float dy) +void sim_bounding_box_render(struct OffscreenBuffer *buffer, struct SimBounds *bounding_box, uint32_t color, struct SimView *view) { if (!buffer) { @@ -291,8 +275,9 @@ void sim_bounding_box_render(struct OffscreenBuffer *buffer, struct SimBounds *b x++) { sim_set_pixel( - buffer, x + dx, - bounding_box->center_y + dy, + buffer, + sim_calc_render_offset(view->zoom, view->dx, x, buffer->width/2), + sim_calc_render_offset(view->zoom, view->dy, bounding_box->center_y, buffer->height/2), color); } for (int y = bounding_box->center_y - reticle_radius; @@ -301,8 +286,8 @@ void sim_bounding_box_render(struct OffscreenBuffer *buffer, struct SimBounds *b { sim_set_pixel( buffer, - bounding_box->center_x + dx, - y + dy, + sim_calc_render_offset(view->zoom, view->dx, bounding_box->center_x, buffer->width/2), + sim_calc_render_offset(view->zoom, view->dy, y, buffer->height/2), color); } @@ -315,13 +300,13 @@ void sim_bounding_box_render(struct OffscreenBuffer *buffer, struct SimBounds *b { sim_set_pixel( buffer, - x + dx, - bounding_box->center_y - half_length_y + dy, + sim_calc_render_offset(view->zoom, view->dx, x, buffer->width/2), + sim_calc_render_offset(view->zoom, view->dy, bounding_box->center_y - half_length_y, buffer->height/2), color); sim_set_pixel( buffer, - x + dx, - bounding_box->center_y + half_length_y + dy, + sim_calc_render_offset(view->zoom, view->dx, x, buffer->width/2), + sim_calc_render_offset(view->zoom, view->dy, bounding_box->center_y + half_length_y, buffer->height/2), color); } @@ -331,19 +316,47 @@ void sim_bounding_box_render(struct OffscreenBuffer *buffer, struct SimBounds *b { sim_set_pixel( buffer, - bounding_box->center_x - half_length_x + dx, - y + dy, + sim_calc_render_offset(view->zoom, view->dx, bounding_box->center_x - half_length_x, buffer->width/2), + sim_calc_render_offset(view->zoom, view->dy, y, buffer->height/2), color); sim_set_pixel( buffer, - bounding_box->center_x + half_length_x + dx, - y + dy, + sim_calc_render_offset(view->zoom, view->dx, bounding_box->center_x + half_length_x, buffer->width/2), + sim_calc_render_offset(view->zoom, view->dy, y, buffer->height/2), color); } } } +float sim_calc_render_offset(float zoom, float delta, float pos, float center) +{ + return ((1 - zoom) * center) + (pos + delta) * zoom; +} + + +void sim_set_pixel(struct OffscreenBuffer *buffer, uint32_t x, uint32_t y, uint32_t color) +{ + if (!buffer) + { + // TODO: handle invalid pointer error + return; + } + + /* Origin is (0, 0) on the upper left. + * To go one pixel right, increment by 32 bits. + * To go one pixel down, increment by (buffer.width * 32) bits. + */ + if (x < buffer->width && y < buffer->height) + { + uint8_t *pixel_pos = (uint8_t *)buffer->memory; + pixel_pos += ((BYTES_PER_PIXEL*x) + (buffer->pitch * y)); + uint32_t *pixel = (uint32_t *)pixel_pos; + *pixel = color; + } +} + + void sim_cleanup(struct SimState *sim_state) { if (!sim_state) diff --git a/src/star_garden.h b/src/star_garden.h @@ -66,6 +66,7 @@ struct SimView { float dx; float dy; + float zoom; }; struct SimState @@ -90,9 +91,10 @@ void sim_init(struct SimState *sim_state, int field_width, int field_height); void sim_update(struct SimState *sim_state, int field_width, int field_height); void sim_bounding_box_update(struct SimBounds *bounds, float min_x, float min_y, float max_x, float max_y); void sim_render(struct OffscreenBuffer *buffer, float dt, struct SimState *sim_state); +void sim_bounding_box_render(struct OffscreenBuffer *buffer, struct SimBounds *bounding_box, uint32_t color, struct SimView *view); +void sim_grid_render(struct OffscreenBuffer *buffer, struct QuadTreeNode *node, uint32_t color, struct SimView *view); +float sim_calc_render_offset(float zoom, float delta, float pos, float center); void sim_set_pixel(struct OffscreenBuffer *buffer, uint32_t x, uint32_t y, uint32_t color); -void sim_bounding_box_render(struct OffscreenBuffer *buffer, struct SimBounds *bounding_box, uint32_t color, float dx, float dy); -void sim_grid_render(struct OffscreenBuffer *buffer, struct QuadTreeNode *node, uint32_t color, float dx, float dy); void sim_cleanup(struct SimState *sim_state); #define STAR_GARDEN_H