INTERNAL v2 calculateProjectionRangeForEdge(v2 *vertexList, i32 vertexListSize, v2 edgeNormal) { v2 result = {0}; result.min = v2_dot(vertexList[0], edgeNormal); result.max = result.min; for (i32 vertexIndex = 0; vertexIndex < vertexListSize; vertexIndex++) { f32 dist = v2_dot(vertexList[vertexIndex], edgeNormal); if (dist < result.min) result.min = dist; else if (dist > result.max) result.max = dist; } return result; }
scalar_t noise2(scalar_t x, scalar_t y) { int i, j, b00, b10, b01, b11; int bx0, bx1, by0, by1; scalar_t rx0, rx1, ry0, ry1; scalar_t sx, sy, u, v, a, b; if(!tables_valid) { init_noise(); tables_valid = 1; } setup(x, bx0, bx1, rx0, rx1); setup(y, by0, by1, ry0, ry1); i = perm[bx0]; j = perm[bx1]; b00 = perm[i + by0]; b10 = perm[j + by0]; b01 = perm[i + by1]; b11 = perm[j + by1]; /* calculate hermite inteprolating factors */ sx = s_curve(rx0); sy = s_curve(ry0); /* interpolate along the left edge */ u = v2_dot(grad2[b00], v2_cons(rx0, ry0)); v = v2_dot(grad2[b10], v2_cons(rx1, ry0)); a = lerp(u, v, sx); /* interpolate along the right edge */ u = v2_dot(grad2[b01], v2_cons(rx0, ry1)); v = v2_dot(grad2[b11], v2_cons(rx1, ry1)); b = lerp(u, v, sx); /* interpolate between them */ return lerp(a, b, sy); }
void update_world_area(World_Area* area) { game_set_scale(2.0); real movespeed = 800; Vec2 move_impulse = v2(0, 0); if(_check(LEFT, A, State_Pressed)) { move_impulse.x -= movespeed; } if(_check(RIGHT, D, State_Pressed)) { move_impulse.x += movespeed; } if(_check(UP, W, State_Pressed)) { move_impulse.y -= movespeed; } if(_check(DOWN, S, State_Pressed)) { move_impulse.y += movespeed; } if(fabsf(move_impulse.x * move_impulse.y) > 0.01f) { move_impulse *= Math_InvSqrt2; } play_state->current_time = SDL_GetTicks(); real dt = (play_state->current_time - play_state->prev_time) / 1000.0; dt = clamp(dt, 0, 1.2f); play_state->accumulator += dt; play_state->prev_time = play_state->current_time; sim_sort_bodies_on_id(&area->sim); Entity* player_entity = world_area_find_entity(area, 0); Sim_Body* player = player_entity->body; Tile_Info* player_tile = area->map.info + tilemap_get_at(&area->map, player->shape.center); move_impulse *= player_tile->movement_modifier; while(play_state->accumulator >= Time_Step) { play_state->accumulator -= Time_Step; player->velocity += move_impulse; sim_update(&area->sim, &area->map, Time_Step); } Direction old_direction = player_entity->direction; if(move_impulse.y < 0) { player_entity->direction = Direction_North; } else if(move_impulse.y > 0) { player_entity->direction = Direction_South; } if(move_impulse.x < 0) { player_entity->facing = -1; player_entity->direction = Direction_West; } else if(move_impulse.x > 0) { player_entity->facing = 1; player_entity->direction = Direction_East; } if(input->scancodes[SDL_SCANCODE_SPACE] == State_Pressed) { player_entity->direction = old_direction; } Sprite* plr_spr = &player_entity->sprite; int32 player_frame = 0; if(v2_dot(move_impulse, move_impulse) > 0){ player_entity->counter++; player_frame = 1; if(player_entity->counter > 15) { player_frame = 0; if(player_entity->counter > 30) { player_entity->counter = 0; } } } else { player_entity->counter = 0; player_frame = 0; } if(player_entity->facing == -1) { plr_spr->texture = Get_Texture_Coordinates(32 + player_frame * 32, 0, -32, 32); } else if(player_entity->facing == 1) { plr_spr->texture = Get_Texture_Coordinates(0 + player_frame * 32, 0, 32, 32); } Vec2 target = player->shape.center; if(target.x < 0) { world_switch_current_area(play_state->world, area->west); play_state->world_xy.x--; } else if(target.x > area->map.w * Tile_Size) { world_switch_current_area(play_state->world, area->east); play_state->world_xy.x++; } else if(target.y < 0) { world_switch_current_area(play_state->world, area->north); play_state->world_xy.y--; } else if(target.y > area->map.h * Tile_Size) { world_switch_current_area(play_state->world, area->south); play_state->world_xy.y++; } area->offset += (target - area->offset) * 0.1f; area->offset -= game->size * 0.5f; if(area->offset.x < 0) area->offset.x = 0; else if((area->offset.x + game->size.x) > area->map.w * Tile_Size) area->offset.x = area->map.w * Tile_Size - game->size.x; if(area->offset.y < 0) area->offset.y = 0; else if((area->offset.y + game->size.y) > area->map.h * Tile_Size) area->offset.y = area->map.h * Tile_Size - game->size.y; //TODO(will) refactor into own function? /* * Player input code * */ if(input->mouse[SDL_BUTTON_LEFT] == State_Just_Pressed) { Entity* ball_entity = world_area_get_next_entity(area); Sim_Body* ball = ball_entity->body; Vec2 dmouse = v2(input->mouse_x / game->scale, input->mouse_y / game->scale) + area->offset; dmouse -= player->shape.center; real angle = atan2f(dmouse.y, dmouse.x); Vec2 normal = v2(cosf(angle), sinf(angle)); entity_add_event_on_activate(ball_entity, delete_on_activate); ball->damping = 0.9999f; ball->shape.hext = v2(8, 16); ball->shape.center = normal * ball->shape.hw * 4 + player->shape.center; ball->velocity += normal * 2000; ball->shape.hext = v2(8, 6); //ball->flags = Body_Flag_No_Friction; ball_entity->sprite.size = v2(16, 32); ball_entity->sprite.center = v2(0, 10); ball_entity->sprite.texture = Get_Texture_Coordinates(0, 96, 32, 64); } if(input->mouse[SDL_BUTTON_RIGHT] == State_Just_Pressed) { Vec2 dmouse = v2( input->mouse_x / game->scale, input->mouse_y / game->scale) + area->offset; AABB mbb = aabb(dmouse, 0, 0); world_area_synchronize_entities_and_bodies(area); for(isize i = 0; i < area->entities_count; ++i) { Entity* e = area->entities + i; if(aabb_intersect(e->body->shape, mbb)) { if(e->id != 0) { for(isize j = 0; j < e->event_on_activate_count; ++j) { e->event_on_activate[j](e, area); } break; } } } } if(input->scancodes[SDL_SCANCODE_F] == State_Just_Pressed) { //tilemap_set_at(&area->map, player->shape.center, Tile_Dug_Earth); Tile_State* state = tilemap_get_state_at(&area->map, player->shape.center); if(state != NULL) { state->damage++; update_tile_state_at(&area->map, player->shape.center); } } Sprite s; if(input->scancodes[SDL_SCANCODE_SPACE] >= State_Pressed) { init_sprite(&s); s.position = player->shape.center; s.size = v2(16, 16); s.texture = Get_Texture_Coordinates(0, renderer->texture_height - 16, 16, 16); s.color = v4(1, 1, 1, 1); switch(player_entity->direction) { case Direction_North: s.position.y -= s.size.y + player->shape.hh; break; case Direction_South: s.position.y += s.size.y + player->shape.hh; break; case Direction_East: s.position.x += s.size.x + player->shape.hw; break; case Direction_West: s.position.x -= s.size.x + player->shape.hh; break; } if(input->scancodes[SDL_SCANCODE_SPACE] == State_Just_Pressed) { //TODO(will) implement good space queries Sim_Body* touching = sim_query_aabb(&area->sim, aabb(s.position, s.size.x / 2, s.size.y / 2)); if(touching != NULL) { if(!Has_Flag(touching->flags, Body_Flag_Static)) player_entity->held_entity_id = touching->entity_id; } } } else { player_entity->held_entity_id = -1; } char debug_str[256]; if(player_entity->held_entity_id > 0) { Entity* e = world_area_find_entity(area, player_entity->held_entity_id); if(e != NULL) { Sim_Body* b = e->body; Vec2 target = player->shape.center; Vec2 diff = b->shape.hext + player->shape.hext + v2(8, 8); switch(player_entity->direction) { case Direction_North: target.y -= diff.y; break; case Direction_South: target.y += diff.y; break; case Direction_East: target.x += diff.x; break; case Direction_West: target.x -= diff.x; break; } Vec2 impulse = (target - b->shape.center); if(v2_dot(impulse, impulse) > (4 * Tile_Size * Tile_Size)) { player_entity->held_entity_id = -1; } impulse *= 60; { snprintf(debug_str, 256, "T(%.2f %.2f) j(%.2f %.2f)", target.x, target.y, impulse.x, impulse.y); } if(v2_dot(impulse, impulse) < (1000 * 1000)) b->velocity += impulse;// * b->inv_mass; } } renderer->offset = area->offset; area->offset += game->size * 0.5f; // throw a ball renderer_start(); Rect2 screen = rect2( area->offset.x - game->size.x / 2, area->offset.y - game->size.y / 2, game->size.x, game->size.y); isize sprite_count_offset = render_tilemap(&area->map, v2(0,0), screen); for(isize i = 0; i < area->entities_count; ++i) { Entity* e = area->entities + i; Sim_Body* b = sim_find_body(&area->sim, e->body_id); if (b == NULL) continue; e->sprite.position = b->shape.center; //e->sprite.size = v2(b->shape.hw * 2, b->shape.hh * 2); //TODO(will) align entity sprites by their bottom center renderer_push_sprite(&e->sprite); } renderer_push_sprite(&s); renderer_sort(sprite_count_offset); renderer_draw(); renderer->offset = v2(0, 0); game_set_scale(1.0); renderer_start(); char str[256]; isize len = snprintf(str, 256, "X:%d Y:%d Tile: %s", play_state->world_xy.x, play_state->world_xy.y, player_tile->name); render_body_text(str, v2(16, game->size.y - (body_font->glyph_height) - 8), true); render_body_text(debug_str, v2(16, 16), true); renderer_draw(); }
void sim_update(Simulator* sim, Tilemap* map, real dt) { Sim_Body *a, *b; for(isize times = 0; times < Sim_Iter_i; ++times) { //#if 0 if(sim->sort_axis == 0) { body_sort_on_x(sim->bodies, sim->bodies_count); } else if(sim->sort_axis == 1) { body_sort_on_y(sim->bodies, sim->bodies_count); } //#endif Vec2 center_sum1 = v2(0, 0); Vec2 center_sum2 = v2(0, 0); Vec2 variance = v2(0, 0); for(isize i = 0; i < sim->bodies_count; ++i) { a = sim->bodies + i; //sweep and prune stuff center_sum1 += a->shape.center; for(isize q = 0; q < 2; ++q) { center_sum2.e[q] += a->shape.center.e[q] * a->shape.center.e[q]; } //if(a->is_static) continue; for(isize j = i + 1; j < sim->bodies_count; ++j) { b = sim->bodies + j; uint64 a_is_static = Has_Flag(a->flags, Body_Flag_Static); uint64 b_is_static = Has_Flag(b->flags, Body_Flag_Static); if(a_is_static && b_is_static) continue; //#if 0 if(sim->sort_axis == 0) { if(AABB_x1(b->shape) > AABB_x2(a->shape)) { break; } } else if(sim->sort_axis == 1) { if(AABB_y1(b->shape) > AABB_y2(a->shape)) { break; } } //#endif if(aabb_intersect(&a->shape, &b->shape)) { Vec2 overlap; aabb_overlap(&a->shape, &b->shape, &overlap); real ovl_mag = sqrtf(v2_dot(overlap, overlap)); if (ovl_mag < 0.0001f) continue; Vec2 normal = overlap * (1.0f / ovl_mag); if(a->id == 0 || b->id == 0) { aabb_intersect(&a->shape, &b->shape); } #define _collision_slop (0.8f) if(a_is_static && !b_is_static) { b->shape.center += overlap; Vec2 relative_velocity = b->velocity; real velocity_on_normal = v2_dot(relative_velocity, normal); if(velocity_on_normal > 0) continue; real e = Min(a->restitution, b->restitution); real mag = -1.0f * (1.0f + e) * velocity_on_normal; mag /= b->inv_mass; Vec2 impulse = mag * normal; b->collision_vel += b->inv_mass * impulse; } else if(!a_is_static && b_is_static) { a->shape.center -= overlap; Vec2 relative_velocity = -a->velocity; real velocity_on_normal = v2_dot(relative_velocity, normal); if(velocity_on_normal > 0) continue; real e = Min(a->restitution, b->restitution); real mag = -1.0f * (1.0f + e) * velocity_on_normal; mag /= a->inv_mass + 0; Vec2 impulse = mag * normal; a->collision_vel -= a->inv_mass * impulse; } else { Vec2 separation = Max(ovl_mag - _collision_slop, 0) * (1.0f / (a->inv_mass + b->inv_mass)) * 0.5f * normal; a->shape.center -= a->inv_mass * separation; b->shape.center += b->inv_mass * separation; Vec2 relative_velocity = b->velocity - a->velocity; real velocity_on_normal = v2_dot(relative_velocity, normal); if(velocity_on_normal > 0) continue; real e = Min(a->restitution, b->restitution); real mag = -1.0f * (1.0f + e) * velocity_on_normal; mag /= a->inv_mass + b->inv_mass; Vec2 impulse = mag * normal; a->collision_vel -= a->inv_mass * impulse; b->collision_vel += b->inv_mass * impulse; } } } } for(isize i = 0; i < 2; ++i) { variance.e[i] = center_sum2.e[i] - center_sum1.e[i] * center_sum1.e[i] / sim->bodies_count; } if(variance.x > variance.y) { sim->sort_axis = 0; } else { sim->sort_axis = 1; } for(isize i = 0; i < sim->bodies_count; ++i) { a = sim->bodies + i; if(Has_Flag(a->flags, Body_Flag_Static)) continue; Vec2 iter_acl = (a->force * a->inv_mass) / Sim_Iter; Vec2 new_vel = a->velocity + (dt * iter_acl); Vec2 dpos = (a->velocity + new_vel) * 0.5f; dpos *= 1.0f / Sim_Iter; a->shape.center += dpos * dt; a->shape.center += a->collision_vel / Sim_Iter * dt; a->velocity = new_vel; Tile_Info* tile = map->info + tilemap_get_at(map, a->shape.center); real damping = 1.0f; if(Has_Flag(a->flags, Body_Flag_No_Friction)) { damping = a->damping; } else { damping = sqrtf(a->damping * a->damping + tile->friction * tile->friction) * Math_InvSqrt2; } a->velocity *= powf(damping, Sim_Iter); a->velocity += a->collision_vel; a->collision_vel = v2(0, 0); } } body_sort_on_id(sim->bodies, sim->bodies_count); }