sim.c (11009B)
1 #include "sim.h" 2 3 #include <stdbool.h> 4 5 bool PAUSED = false; 6 bool BRUTE_FORCE = false; 7 bool RENDER_GRID = false; 8 bool RENDER_BOUNDING_BOX = false; 9 bool RENDER_TRAILS = false; 10 11 12 void sim_init(struct SimState *sim_state, int field_width, int field_height) 13 { 14 if (!sim_state) 15 { 16 // TODO: handle invalid pointer error 17 return; 18 } 19 20 sim_state->num_stars = NUM_STARS; 21 22 sim_state->bounding_box.center_x = field_width / 2; 23 sim_state->bounding_box.center_y = field_height / 2; 24 sim_state->bounding_box.side_length_x = 0; 25 sim_state->bounding_box.side_length_y = 0; 26 27 sim_state->view.dx = 0; 28 sim_state->view.dy = 0; 29 sim_state->view.zoom = 1; 30 31 float min_x = field_width / 2; 32 float max_x = field_width / 2; 33 float min_y = field_height / 2; 34 float max_y = field_height / 2; 35 36 for (int i = 0; i < sim_state->num_stars; ++i) 37 { 38 int star_x = rand() % field_width; 39 int star_y = rand() % field_height; 40 41 struct Star *star = &sim_state->stars[i]; 42 star->x = star_x; 43 star->y = star_y; 44 star->angle = ((float)rand()/(float)(RAND_MAX)) * 2 * M_PI; 45 star->speed = 0; 46 star->mass = 5; 47 star->size = star_calc_size(star->mass); 48 star->color = COLOR_WHITE; 49 //printf("%f, %f, %f\n", star->angle, star->speed, star->mass); 50 51 if (star_x <= min_x) 52 { 53 min_x = star_x; 54 } 55 else if (star_x >= max_x) 56 { 57 max_x = star_x; 58 } 59 if (star_y <= min_y) 60 { 61 min_y = star_y; 62 } 63 else if (star_y >= max_y) 64 { 65 max_y = star_y; 66 } 67 } 68 sim_bounding_box_update(&sim_state->bounding_box, min_x, min_y, max_x, max_y); 69 70 sim_state->qt = quad_tree_init(); 71 } 72 73 74 void sim_bounding_box_update(struct SimBounds *bounds, float min_x, float min_y, float max_x, float max_y) 75 { 76 if (!bounds) 77 { 78 // TODO: handle invalid pointer error 79 return; 80 } 81 82 float bounding_square_side_length = fmaxf(max_x - min_x, max_y - min_y); 83 bounds->side_length_x = bounding_square_side_length; 84 bounds->side_length_y = bounding_square_side_length; 85 bounds->center_x = (min_x + max_x) / 2; 86 bounds->center_y = (min_y + max_y) / 2; 87 } 88 89 90 void sim_update(struct SimState *sim_state, int field_width, int field_height) 91 { 92 if (!sim_state) 93 { 94 // TODO: handle invalid pointer error 95 return; 96 } 97 98 float min_x = sim_state->bounding_box.center_x; 99 float max_x = sim_state->bounding_box.center_x; 100 float min_y = sim_state->bounding_box.center_y; 101 float max_y = sim_state->bounding_box.center_y; 102 103 int num_stars = sim_state->num_stars; 104 struct Star *stars = sim_state->stars; 105 struct QuadTree *qt = sim_state->qt; 106 107 108 if (BRUTE_FORCE) 109 { 110 for (int i = 0; i < num_stars; ++i) 111 { 112 for (int j = i + 1; j < num_stars; ++j) 113 { 114 star_attract(&stars[i], &stars[j]); 115 } 116 } 117 } 118 else 119 { 120 quad_tree_node_free(qt->root); 121 qt->root = quad_tree_node_init( 122 sim_state->bounding_box.center_x, 123 sim_state->bounding_box.center_y, 124 sim_state->bounding_box.side_length_x / 2, 125 sim_state->bounding_box.side_length_y / 2); 126 127 for (int i = 0; i < num_stars; ++i) 128 { 129 quad_tree_node_insert_star(qt->root, &(stars[i])); 130 } 131 for (int i = 0; i < num_stars; ++i) 132 { 133 // TODO: Will this result in stars being attracted to each other 134 // twice? 135 quad_tree_calc_force_on_star(qt->root, &(stars[i])); 136 } 137 } 138 for (int i = 0; i < num_stars; ++i) 139 { 140 stars[i].x += sinf(stars[i].angle) * stars[i].speed; 141 stars[i].y -= cosf(stars[i].angle) * stars[i].speed; 142 stars[i].speed *= DRAG; 143 144 #ifdef RESPAWN_STARS 145 if (stars[i].x < 0 || stars[i].x > field_width 146 || stars[i].y < 0 || stars[i].y > field_height) 147 { 148 stars[i].x = rand() % field_width; 149 stars[i].y = rand() % field_height; 150 stars[i].angle = 0; 151 stars[i].speed = 0; 152 } 153 #endif 154 155 if (stars[i].x <= min_x) 156 { 157 min_x = stars[i].x; 158 } 159 else if (stars[i].x >= max_x) 160 { 161 max_x = stars[i].x; 162 } 163 if (stars[i].y <= min_y) 164 { 165 min_y = stars[i].y; 166 } 167 else if (stars[i].y >= max_y) 168 { 169 max_y = stars[i].y; 170 } 171 } 172 173 sim_bounding_box_update(&sim_state->bounding_box, min_x, min_y, max_x, max_y); 174 } 175 176 177 void sim_render(struct OffscreenBuffer *buffer, float dt, struct SimState *sim_state) 178 { 179 if (!buffer || !sim_state) 180 { 181 // TODO: handle invalid pointer error 182 return; 183 } 184 185 int num_stars = sim_state->num_stars; 186 struct Star *stars = sim_state->stars; 187 struct QuadTree *qt = sim_state->qt; 188 189 float dx = sim_state->view.dx; 190 float dy = sim_state->view.dy; 191 float zoom = sim_state->view.zoom; 192 193 for (int i = 0; i < num_stars; ++i) 194 { 195 uint32_t color; 196 if (BRUTE_FORCE) 197 { 198 color = COLOR_CYAN; 199 } 200 else 201 { 202 color = stars[i].color; 203 } 204 sim_set_pixel( 205 buffer, 206 sim_calc_render_offset(zoom, dx, stars[i].x + (sinf(stars[i].angle) * stars[i].speed) * dt, buffer->width/2), 207 sim_calc_render_offset(zoom, dy, stars[i].y - (cosf(stars[i].angle) * stars[i].speed) * dt, buffer->height/2), 208 color); 209 } 210 211 if (RENDER_GRID) 212 { 213 sim_grid_render(buffer, qt->root, COLOR_GREEN, &sim_state->view); 214 } 215 if (RENDER_BOUNDING_BOX) 216 { 217 sim_bounding_box_render(buffer, &sim_state->bounding_box, COLOR_RED, &sim_state->view); 218 } 219 } 220 221 222 void sim_grid_render(struct OffscreenBuffer *buffer, struct QuadTreeNode *node, uint32_t color, struct SimView *view) 223 { 224 if (!buffer) 225 { 226 // TODO: handle invalid pointer error 227 return; 228 } 229 230 if (node && node->ne && node->nw && node->sw && node->se) 231 { 232 for (int x = (node->cell->center_x - node->cell->distance_x); 233 x <= (node->cell->center_x + node->cell->distance_x); 234 ++x) 235 { 236 sim_set_pixel( 237 buffer, 238 sim_calc_render_offset(view->zoom, view->dx, x, buffer->width/2), 239 sim_calc_render_offset(view->zoom, view->dy, node->cell->center_y, buffer->height/2), 240 color); 241 } 242 243 for (int y = (node->cell->center_y - node->cell->distance_y); 244 y <= (node->cell->center_y + node->cell->distance_y); 245 ++y) 246 { 247 sim_set_pixel( 248 buffer, 249 sim_calc_render_offset(view->zoom, view->dx, node->cell->center_x, buffer->width/2), 250 sim_calc_render_offset(view->zoom, view->dy, y, buffer->height/2), 251 color); 252 } 253 254 sim_grid_render(buffer, node->ne, color, view); 255 sim_grid_render(buffer, node->nw, color, view); 256 sim_grid_render(buffer, node->sw, color, view); 257 sim_grid_render(buffer, node->se, color, view); 258 } 259 } 260 261 262 void sim_bounding_box_render(struct OffscreenBuffer *buffer, struct SimBounds *bounding_box, uint32_t color, struct SimView *view) 263 { 264 if (!buffer) 265 { 266 // TODO: handle invalid pointer error 267 return; 268 } 269 270 if (bounding_box) 271 { 272 int reticle_radius = 3; 273 for (int x = bounding_box->center_x - reticle_radius; 274 x <= bounding_box->center_x + reticle_radius; 275 x++) 276 { 277 sim_set_pixel( 278 buffer, 279 sim_calc_render_offset(view->zoom, view->dx, x, buffer->width/2), 280 sim_calc_render_offset(view->zoom, view->dy, bounding_box->center_y, buffer->height/2), 281 color); 282 } 283 for (int y = bounding_box->center_y - reticle_radius; 284 y <= bounding_box->center_y + reticle_radius; 285 y++) 286 { 287 sim_set_pixel( 288 buffer, 289 sim_calc_render_offset(view->zoom, view->dx, bounding_box->center_x, buffer->width/2), 290 sim_calc_render_offset(view->zoom, view->dy, y, buffer->height/2), 291 color); 292 } 293 294 float half_length_x = bounding_box->side_length_x / 2; 295 float half_length_y = bounding_box->side_length_y / 2; 296 297 for (int x = (bounding_box->center_x - half_length_x); 298 x <= (bounding_box->center_x + half_length_x); 299 ++x) 300 { 301 sim_set_pixel( 302 buffer, 303 sim_calc_render_offset(view->zoom, view->dx, x, buffer->width/2), 304 sim_calc_render_offset(view->zoom, view->dy, bounding_box->center_y - half_length_y, buffer->height/2), 305 color); 306 sim_set_pixel( 307 buffer, 308 sim_calc_render_offset(view->zoom, view->dx, x, buffer->width/2), 309 sim_calc_render_offset(view->zoom, view->dy, bounding_box->center_y + half_length_y, buffer->height/2), 310 color); 311 } 312 313 for (int y = (bounding_box->center_y - half_length_y); 314 y <= (bounding_box->center_y + half_length_y); 315 ++y) 316 { 317 sim_set_pixel( 318 buffer, 319 sim_calc_render_offset(view->zoom, view->dx, bounding_box->center_x - half_length_x, buffer->width/2), 320 sim_calc_render_offset(view->zoom, view->dy, y, buffer->height/2), 321 color); 322 sim_set_pixel( 323 buffer, 324 sim_calc_render_offset(view->zoom, view->dx, bounding_box->center_x + half_length_x, buffer->width/2), 325 sim_calc_render_offset(view->zoom, view->dy, y, buffer->height/2), 326 color); 327 } 328 } 329 } 330 331 332 float sim_calc_render_offset(float zoom, float delta, float pos, float center) 333 { 334 return ((1 - zoom) * center) + (pos + delta) * zoom; 335 } 336 337 338 void sim_set_pixel(struct OffscreenBuffer *buffer, uint32_t x, uint32_t y, uint32_t color) 339 { 340 if (!buffer) 341 { 342 // TODO: handle invalid pointer error 343 return; 344 } 345 346 /* Origin is (0, 0) on the upper left. 347 * To go one pixel right, increment by 32 bits. 348 * To go one pixel down, increment by (buffer.width * 32) bits. 349 */ 350 if (x < buffer->width && y < buffer->height) 351 { 352 uint8_t *pixel_pos = (uint8_t *)buffer->memory; 353 pixel_pos += ((BYTES_PER_PIXEL*x) + (buffer->pitch * y)); 354 uint32_t *pixel = (uint32_t *)pixel_pos; 355 *pixel = color; 356 } 357 } 358 359 360 void sim_cleanup(struct SimState *sim_state) 361 { 362 if (!sim_state) 363 { 364 // TODO: handle invalid pointer error 365 return; 366 } 367 368 quad_tree_free(sim_state->qt); 369 }