diff --git a/src/entity.h b/src/entity.h index 6ba99a6a..ea12cc6d 100644 --- a/src/entity.h +++ b/src/entity.h @@ -116,7 +116,6 @@ struct entity { b32 solved; b32 test_torque_applied; - b32 test_collided; diff --git a/src/game.c b/src/game.c index d9e496e1..e13697c8 100644 --- a/src/game.c +++ b/src/game.c @@ -129,10 +129,10 @@ INTERNAL void spawn_test_entities(void) //struct v2 pos = V2(0.374142020941, -0.246118023992); /* Touching glitch spot */ //struct v2 size = V2(1, 1); struct v2 size = V2(0.5, 0.5); - //f32 r = PI / 4; + f32 r = PI / 4; //f32 r = PI / 3; //f32 r = PI / 2; - f32 r = 0; + //f32 r = 0; f32 skew = 0; struct entity *e = entity_alloc(root); @@ -155,8 +155,8 @@ INTERNAL void spawn_test_entities(void) entity_enable_prop(e, ENTITY_PROP_PHYSICAL); e->mass_unscaled = 100; - e->inertia_unscaled = 1; - //e->inertia_unscaled = F32_INFINITY; + //e->inertia_unscaled = 1; + e->inertia_unscaled = F32_INFINITY; e->linear_ground_friction = 1000; e->angular_ground_friction = 100; @@ -250,6 +250,8 @@ INTERNAL void create_contact_manifolds(void) static u64 manifold_iteration = 0; ++manifold_iteration; + /* FIXME: I think it's technically possible for manifold entities to swap between iterations */ + struct entity_store *store = G.tick.entity_store; struct sprite_scope *sprite_frame_scope = G.sprite_frame_scope; struct entity *root = G.root; @@ -301,10 +303,15 @@ INTERNAL void create_contact_manifolds(void) manifold_hash = hash_fnv64(manifold_hash, BUFFER_FROM_STRUCT(&h1)); manifold_key = STRING_FROM_BUFFER(BUFFER_FROM_STRUCT(&manifold_hash)); } - struct entity *manifold = fixed_dict_get(&dict, manifold_key); + + struct entity *manifold = entity_nil(); + struct entity_handle *entry = fixed_dict_get(&dict, manifold_key); + if (entry) { + manifold = entity_from_handle(store, *entry); + } /* Ensure manifold hasn't already been computed this iteration */ - if (manifold) { + if (manifold->valid) { if (manifold->last_manifold_iteration == manifold_iteration) { /* Already iterated this manifold from The other entity's perspective, skip */ continue; @@ -336,8 +343,16 @@ INTERNAL void create_contact_manifolds(void) #endif struct gjk_contact_points_result res = gjk_contact_points(e0_poly, e1_poly); + + /* TODO: Remove this (debugging) */ + if (manifold->valid) { + manifold->prototype = res.prototype; + manifold->simplex = res.simplex; + manifold->solved = res.solved; + } + if (res.num_pairs > 0) { - if (!manifold) { + if (!manifold->valid) { manifold = entity_alloc(root); manifold->manifold_e0 = e0->handle; manifold->manifold_e1 = e1->handle; @@ -345,16 +360,23 @@ INTERNAL void create_contact_manifolds(void) manifold->manifold_normal = v2_norm(v2_sub(res.pairs[0].p1, res.pairs[0].p0)); entity_enable_prop(manifold, ENTITY_PROP_MANIFOLD); activate_now(manifold); - fixed_dict_set(&dict_arena, &dict, manifold_key, manifold); + + if (entry) { + *entry = manifold->handle; + } else { + entry = arena_push(&dict_arena, struct entity_handle); + *entry = manifold->handle; + fixed_dict_set(&dict_arena, &dict, manifold_key, entry); + } + + /* TODO: Remove this (debugging) */ + { + manifold->prototype = res.prototype; + manifold->simplex = res.simplex; + manifold->solved = res.solved; + } } - - /* TODO: Remove this (debugging) */ - manifold->prototype = res.prototype; - manifold->simplex = res.simplex; - - - /* Update contact depths, and remove contacts that are no longer penetrating or have drifted too far from original position */ struct v2 old_normal = manifold->manifold_normal; for (i32 j = 0; j < (i32)manifold->num_contacts; ++j) { @@ -420,12 +442,14 @@ INTERNAL void create_contact_manifolds(void) c = &overflow[overflow_count++]; } + f32 depth = v2_len(v2_sub(p1_world, p0_world)); + MEMZERO_STRUCT(c); c->p0_local = xform_invert_mul_v2(e0_xf, p0_world); c->p0_initial_world = p0_world; c->p1_local = xform_invert_mul_v2(e1_xf, p1_world); c->p1_initial_world = p1_world; - c->depth = v2_len(v2_sub(p1_world, p0_world)); + c->depth = depth; } } @@ -508,10 +532,19 @@ INTERNAL void create_contact_manifolds(void) - } else if (manifold) { - /* No longer colliding, delete contact */ + } else if (manifold->valid) { + /* No longer colliding, delete manifold */ +#if 0 manifold->num_contacts = 0; - fixed_dict_set(&dict_arena, &dict, manifold_key, NULL); + //fixed_dict_set(&dict_arena, &dict, manifold_key, NULL); + //entity_enable_prop(manifold, ENTITY_PROP_RELEASE); +#else + if (res.solved) { + manifold->prototype.len = 0; + manifold->simplex.len = 0; + } + manifold->num_contacts = 0; +#endif } } } @@ -534,13 +567,8 @@ INTERNAL void solve_collisions(f32 dt, b32 apply_bias) u32 num_contacts = manifold->num_contacts; f32 inv_num_contacts = 1.f / num_contacts; + if (num_contacts > 0 && e0->valid && e1->valid) { - /* TODO: Remove this (testing) */ - if (!e0->test_collided) { - e0->test_collided = true; - } - - struct xform e0_xf = entity_get_xform(e0); struct xform e1_xf = entity_get_xform(e1); @@ -555,7 +583,6 @@ INTERNAL void solve_collisions(f32 dt, b32 apply_bias) f32 inv_i0 = 1.f / i0; f32 inv_i1 = 1.f / i1; - struct queued_impulse { struct v2 p0, p1; f32 impulse; @@ -602,14 +629,17 @@ INTERNAL void solve_collisions(f32 dt, b32 apply_bias) /* (to be applied along n) */ f32 j = (vn + bias) / k; j *= inv_num_contacts; /* TODO: Is this the correct place to do this? */ + (UNUSED)inv_num_contacts; - f32 old_impulse = contact->accumulated_impulse; - contact->accumulated_impulse = max_f32(contact->accumulated_impulse + j, 0); + f32 old_accumulated_impulse = contact->accumulated_impulse; + f32 new_accumulated_impulse = max_f32(contact->accumulated_impulse + j, 0); + f32 delta_impulse = new_accumulated_impulse - old_accumulated_impulse; + contact->accumulated_impulse = new_accumulated_impulse; queued_impulses[contact_index] = (struct queued_impulse) { .p0 = p0, .p1 = p1, - .impulse = contact->accumulated_impulse - old_impulse + .impulse = delta_impulse }; } @@ -619,8 +649,6 @@ INTERNAL void solve_collisions(f32 dt, b32 apply_bias) entity_apply_linear_impulse(e0, impulse, qi.p0); entity_apply_linear_impulse(e1, v2_neg(impulse), qi.p1); } - } else { - entity_enable_prop(manifold, ENTITY_PROP_RELEASE); } } } @@ -1306,48 +1334,31 @@ INTERNAL void game_update(struct game_cmd_array game_cmds) ent->torque = 0; } - - - - - - - -#if 0 /* ========================== * - * Create contact manifolds + * Physics * ========================== */ - create_contact_manifolds(); + { + u32 substeps = 4; + f32 substep_dt = dt / substeps; + for (u32 i = 0; i < substeps; ++i) { - /* ========================== * - * Collision resolution - * ========================== */ + #if 0 + create_contact_manifolds(); + solve_collisions(substep_dt, true); + integrate_positions(substep_dt); + solve_collisions(substep_dt, false); + #else + (UNUSED)create_contact_manifolds; + (UNUSED)solve_collisions; + (UNUSED)integrate_positions; - solve_collisions(dt); - - /* ========================== * - * Integrate positions from velocity - * ========================== */ - - integrate_positions(dt); -#else - u32 iterations = 4; - for (u32 i = 0; i < iterations; ++i) { - f32 timestep = dt / iterations; - -#if 1 - create_contact_manifolds(); - solve_collisions(timestep, true); - integrate_positions(timestep); - solve_collisions(timestep, false); -#else - create_contact_manifolds(); - solve_collisions(timestep, false); - integrate_positions(timestep); -#endif + create_contact_manifolds(); + solve_collisions(substep_dt, true); + integrate_positions(substep_dt); + #endif + } } -#endif /* ========================== * * Initialize bullet kinematics from sources diff --git a/src/gjk.c b/src/gjk.c index a0b5dc99..51eec46f 100644 --- a/src/gjk.c +++ b/src/gjk.c @@ -196,14 +196,17 @@ struct gjk_contact_points_result gjk_contact_points(struct v2_array shape0, stru s.len = 1; /* Second point is support point towards origin */ + DBGSTEP; dir = v2_neg(s.a.p); m = menkowski_point_extended(shape0, shape1, dir); if (v2_dot(dir, m.p) > 0) { + DBGSTEP; s.b = s.a; s.a = m; s.len = 2; while (true) { /* Third point is support point in direction of line normal towards origin */ + DBGSTEP; dir = v2_perp_towards_dir(v2_sub(s.b.p, s.a.p), v2_neg(s.a.p)); m = menkowski_point_extended(shape0, shape1, dir); if (v2_dot(dir, m.p) < 0) { @@ -220,6 +223,7 @@ struct gjk_contact_points_result gjk_contact_points(struct v2_array shape0, stru struct v2 vac = v2_sub(s.c.p, s.a.p); struct v2 a_to_origin = v2_neg(s.a.p); + DBGSTEP; dir = v2_perp_towards_dir(vab, v2_neg(vac)); /* Normal of ab pointing away from c */ if (v2_dot(dir, a_to_origin) > 0) { /* Point is in region ab, remove c from simplex */ @@ -283,7 +287,6 @@ struct gjk_contact_points_result gjk_contact_points(struct v2_array shape0, stru pen_ps_index = ps_index; pen_pe_index = pe_index; pen_len_sq = pd_len_sq; - dir = pd; } } @@ -293,11 +296,18 @@ struct gjk_contact_points_result gjk_contact_points(struct v2_array shape0, stru s.len = 2; /* Find new point in dir */ + DBGSTEP; + { + /* Next point is in direction of line normal pointing outwards from shape */ + struct v2 n = proto[(pen_pe_index < proto_count - 1) ? (pen_pe_index + 1) : 0].p; /* Next point along prototype after edge */ + struct v2 van = v2_sub(n, s.a.p); + struct v2 vab = v2_sub(s.b.p, s.a.p); + dir = v2_perp_towards_dir(vab, v2_neg(van)); + } m = menkowski_point_extended(shape0, shape1, dir); /* Check unique */ /* TODO: Better */ - DBGSTEP; { b32 unique = true; for (u32 i = 0; i < proto_count; ++i) { diff --git a/src/sys_win32.c b/src/sys_win32.c index 2e038799..25aa1edf 100644 --- a/src/sys_win32.c +++ b/src/sys_win32.c @@ -1938,6 +1938,7 @@ INTERNAL void win32_precise_sleep_timer(f64 seconds, HANDLE timer) /* TODO: Maybe increase tolerance for higher precision but more power usage */ //const double tolerance = 0.001200 * scheduler_period_ms; const double tolerance = 0.000520 * scheduler_period_ms; + //const double tolerance = 1 * scheduler_period_ms; INT64 max_ticks = (INT64)scheduler_period_ms * 9500; while (true) { diff --git a/src/user.c b/src/user.c index f83ff272..4aa7bce4 100644 --- a/src/user.c +++ b/src/user.c @@ -494,9 +494,8 @@ INTERNAL void user_update(void) entity_set_xform(e, xform_lerp(e0_xf, e1_xf, tick_blend)); } - e->verlet_xform = xform_lerp(e0->verlet_xform, e1->verlet_xform, tick_blend); - - e->control_move_force = math_lerp(e0->control_move_force, e1->control_move_force, tick_blend); + e->control_force = math_lerp(e0->control_force, e1->control_force, tick_blend); + e->control_torque = math_lerp(e0->control_torque, e1->control_torque, tick_blend); e->linear_velocity = v2_lerp(e0->linear_velocity, e1->linear_velocity, tick_blend); e->angular_velocity = math_lerp(e0->angular_velocity, e1->angular_velocity, tick_blend); @@ -988,62 +987,38 @@ INTERNAL void user_update(void) } } - /* Draw contact */ +#if 1 + /* Draw collision */ if (entity_has_prop(ent, ENTITY_PROP_MANIFOLD)) { - f32 radius = 5; struct entity *e0 = entity_from_handle(store, ent->manifold_e0); struct entity *e1 = entity_from_handle(store, ent->manifold_e1); - struct xform e0_xf = entity_get_xform(e0); - struct xform e1_xf = entity_get_xform(e1); - (UNUSED)e0_xf; - (UNUSED)e1_xf; - for (u32 i = 0; i < ent->num_contacts; ++i) { - struct contact contact = ent->contacts[i]; - { - u32 color = entity_has_prop(e0, ENTITY_PROP_PLAYER_CONTROLLED) ? RGBA_32_F(1, 0, 0, 0.50) : RGBA_32_F(0, 1, 1, 0.50); - struct v2 point = xform_mul_v2(e0_xf, contact.p0_local); - //struct v2 point = contact.p0_initial_world; - point = xform_mul_v2(G.world_view, point); - draw_solid_circle(G.viewport_canvas, point, radius, color, 10); - } - { - u32 color = entity_has_prop(e1, ENTITY_PROP_PLAYER_CONTROLLED) ? RGBA_32_F(1, 0, 0, 0.50) : RGBA_32_F(0, 1, 1, 0.50); - struct v2 point = xform_mul_v2(e1_xf, contact.p1_local); - //struct v2 point = contact.p1_initial_world; - point = xform_mul_v2(G.world_view, point); - draw_solid_circle(G.viewport_canvas, point, radius, color, 10); - } - } - } - -#if 0 - /* Draw collision */ - if (ent->is_top) { - struct entity *e1 = entity_from_handle(store, ent->colliding_with); (UNUSED)e1; (UNUSED)colliding; + struct xform e0_xf = entity_get_xform(e0); + struct xform e1_xf = entity_get_xform(e1); + /* Create shapes */ - struct quad ent_quad; - struct v2_array ent_poly; + struct quad e0_quad; + struct v2_array e0_poly; struct quad e1_quad; struct v2_array e1_poly; { { - struct sprite_sheet *sheet = sprite_sheet_from_tag_await(sprite_frame_scope, ent->sprite); - struct sprite_sheet_slice slice = sprite_sheet_get_slice(sheet, STR("shape"), ent->animation_frame); - ent_quad = xform_mul_quad(ent->sprite_local_xform, quad_from_rect(slice.rect)); - ent_quad = xform_mul_quad(xf, ent_quad); - ent_poly = (struct v2_array) { - .count = ARRAY_COUNT(ent_quad.e), - .points = ent_quad.e + struct sprite_sheet *sheet = sprite_sheet_from_tag_await(sprite_frame_scope, e0->sprite); + struct sprite_sheet_slice slice = sprite_sheet_get_slice(sheet, STR("shape"), e0->animation_frame); + e0_quad = xform_mul_quad(e0->sprite_local_xform, quad_from_rect(slice.rect)); + e0_quad = xform_mul_quad(e0_xf, e0_quad); + e0_poly = (struct v2_array) { + .count = ARRAY_COUNT(e0_quad.e), + .points = e0_quad.e }; } { struct sprite_sheet *sheet = sprite_sheet_from_tag_await(sprite_frame_scope, e1->sprite); struct sprite_sheet_slice slice = sprite_sheet_get_slice(sheet, STR("shape"), e1->animation_frame); e1_quad = xform_mul_quad(e1->sprite_local_xform, quad_from_rect(slice.rect)); - e1_quad = xform_mul_quad(entity_get_xform(e1), e1_quad); + e1_quad = xform_mul_quad(e1_xf, e1_quad); e1_poly = (struct v2_array) { .count = ARRAY_COUNT(e1_quad.e), .points = e1_quad.e @@ -1051,23 +1026,25 @@ INTERNAL void user_update(void) } } +#if 0 /* Draw collision shapes */ { f32 thickness = 2; u32 color = RGBA_32_F(1, 0, 0, 0.25); - struct quad quad = xform_mul_quad(G.world_view, ent_quad); + struct quad quad = xform_mul_quad(G.world_view, e0_quad); draw_solid_quad_line(G.viewport_canvas, quad, thickness, color); } +#endif /* Draw menkowski */ - if (entity_has_prop(ent, ENTITY_PROP_PLAYER_CONTROLLED)) { + { u32 color = ent->solved ? RGBA_32_F(0, 0, 0.25, 1) : RGBA_32_F(0, 0.25, 0.25, 1); f32 thickness = 2; (UNUSED)thickness; - struct v2_array m = menkowski(temp.arena, ent_poly, e1_poly); - //struct v2_array m = menkowski(temp.arena, ent_poly, e1_poly, v2_sub(ent->xf1.og, ent->xf0.og)); + struct v2_array m = menkowski(temp.arena, e0_poly, e1_poly); + //struct v2_array m = menkowski(temp.arena, e0_poly, e1_poly, v2_sub(ent->xf1.og, ent->xf0.og)); for (u64 i = 0; i < m.count; ++i) m.points[i] = xform_mul_v2(G.world_view, m.points[i]); draw_solid_poly_line(G.viewport_canvas, m, true, thickness, color); @@ -1075,11 +1052,11 @@ INTERNAL void user_update(void) } /* Draw cloud */ - if (entity_has_prop(ent, ENTITY_PROP_PLAYER_CONTROLLED)) { + { u32 color = RGBA_32_F(1, 1, 1, 1); f32 radius = 2; - struct v2_array m = cloud(temp.arena, ent_poly, e1_poly); + struct v2_array m = cloud(temp.arena, e0_poly, e1_poly); for (u64 i = 0; i < m.count; ++i) { struct v2 p = xform_mul_v2(G.world_view, m.points[i]);; @@ -1088,7 +1065,8 @@ INTERNAL void user_update(void) } /* Draw pendir */ - if (entity_has_prop(ent, ENTITY_PROP_PLAYER_CONTROLLED)) { +#if 0 + { f32 thickness = 2; u32 color = COLOR_YELLOW; @@ -1097,9 +1075,10 @@ INTERNAL void user_update(void) draw_solid_arrow_ray(G.viewport_canvas, start, ray, thickness, thickness * 4, color); } +#endif /* Draw prototype */ - if (entity_has_prop(ent, ENTITY_PROP_PLAYER_CONTROLLED)) { + { f32 thickness = 2; u32 color = RGBA_32_F(1, 1, 1, 0.25); @@ -1112,7 +1091,7 @@ INTERNAL void user_update(void) } /* Draw simplex */ - if (entity_has_prop(ent, ENTITY_PROP_PLAYER_CONTROLLED)) { + { f32 thickness = 2; u32 line_color = colliding ? COLOR_WHITE: COLOR_YELLOW; u32 color_first = RGBA_32_F(1, 0, 0, 0.75); @@ -1141,18 +1120,25 @@ INTERNAL void user_update(void) } } - /* Draw points */ + /* Draw contacts */ { f32 radius = 5; - u32 color = entity_has_prop(ent, ENTITY_PROP_PLAYER_CONTROLLED) ? RGBA_32_F(1, 0, 0, 0.75) : RGBA_32_F(0, 1, 1, 0.75); - { - struct v2 point = xform_mul_v2(G.world_view, ent->point0); - draw_solid_circle(G.viewport_canvas, point, radius, color, 10); - } - if (!v2_is_zero(ent->point1)) { - //u32 color = entity_has_prop(ent, ENTITY_PROP_PLAYER_CONTROLLED) ? RGBA_32_F(1, 1, 0, 0.75) : RGBA_32_F(1, 0, 1, 0.75); - struct v2 point = xform_mul_v2(G.world_view, ent->point1); - draw_solid_circle(G.viewport_canvas, point, radius, color, 10); + for (u32 i = 0; i < ent->num_contacts; ++i) { + struct contact contact = ent->contacts[i]; + { + u32 color = entity_has_prop(e0, ENTITY_PROP_PLAYER_CONTROLLED) ? RGBA_32_F(1, 0, 0, 0.50) : RGBA_32_F(0, 1, 1, 0.50); + struct v2 point = xform_mul_v2(e0_xf, contact.p0_local); + //struct v2 point = contact.p0_initial_world; + point = xform_mul_v2(G.world_view, point); + draw_solid_circle(G.viewport_canvas, point, radius, color, 10); + } + { + u32 color = entity_has_prop(e1, ENTITY_PROP_PLAYER_CONTROLLED) ? RGBA_32_F(1, 0, 0, 0.50) : RGBA_32_F(0, 1, 1, 0.50); + struct v2 point = xform_mul_v2(e1_xf, contact.p1_local); + //struct v2 point = contact.p1_initial_world; + point = xform_mul_v2(G.world_view, point); + draw_solid_circle(G.viewport_canvas, point, radius, color, 10); + } } } } @@ -1302,6 +1288,9 @@ INTERNAL void user_update(void) draw_text(G.viewport_canvas, font, pos, string_format(temp.arena, STR("world time: %F"), FMT_FLOAT((f64)G.world.time))); pos.y += spacing; + //draw_text(G.viewport_canvas, font, pos, string_format(temp.arena, STR("time - world time: %F"), FMT_FLOAT((f64)G.time - (f64)G.world.time))); + //pos.y += spacing; + draw_text(G.viewport_canvas, font, pos, string_format(temp.arena, STR("entities: %F/%F"), FMT_UINT(G.world.entity_store->allocated), FMT_UINT(G.world.entity_store->reserved))); pos.y += spacing;