fix epa collision not detecting when diagonals touch

This commit is contained in:
jacob 2024-09-19 17:37:24 -05:00
parent 1f0c8964d0
commit dbdd653ae8
5 changed files with 141 additions and 131 deletions

View File

@ -116,7 +116,6 @@ struct entity {
b32 solved; b32 solved;
b32 test_torque_applied; b32 test_torque_applied;
b32 test_collided;

View File

@ -129,10 +129,10 @@ INTERNAL void spawn_test_entities(void)
//struct v2 pos = V2(0.374142020941, -0.246118023992); /* Touching glitch spot */ //struct v2 pos = V2(0.374142020941, -0.246118023992); /* Touching glitch spot */
//struct v2 size = V2(1, 1); //struct v2 size = V2(1, 1);
struct v2 size = V2(0.5, 0.5); struct v2 size = V2(0.5, 0.5);
//f32 r = PI / 4; f32 r = PI / 4;
//f32 r = PI / 3; //f32 r = PI / 3;
//f32 r = PI / 2; //f32 r = PI / 2;
f32 r = 0; //f32 r = 0;
f32 skew = 0; f32 skew = 0;
struct entity *e = entity_alloc(root); struct entity *e = entity_alloc(root);
@ -155,8 +155,8 @@ INTERNAL void spawn_test_entities(void)
entity_enable_prop(e, ENTITY_PROP_PHYSICAL); entity_enable_prop(e, ENTITY_PROP_PHYSICAL);
e->mass_unscaled = 100; e->mass_unscaled = 100;
e->inertia_unscaled = 1; //e->inertia_unscaled = 1;
//e->inertia_unscaled = F32_INFINITY; e->inertia_unscaled = F32_INFINITY;
e->linear_ground_friction = 1000; e->linear_ground_friction = 1000;
e->angular_ground_friction = 100; e->angular_ground_friction = 100;
@ -250,6 +250,8 @@ INTERNAL void create_contact_manifolds(void)
static u64 manifold_iteration = 0; static u64 manifold_iteration = 0;
++manifold_iteration; ++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 entity_store *store = G.tick.entity_store;
struct sprite_scope *sprite_frame_scope = G.sprite_frame_scope; struct sprite_scope *sprite_frame_scope = G.sprite_frame_scope;
struct entity *root = G.root; 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_hash = hash_fnv64(manifold_hash, BUFFER_FROM_STRUCT(&h1));
manifold_key = STRING_FROM_BUFFER(BUFFER_FROM_STRUCT(&manifold_hash)); 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 */ /* Ensure manifold hasn't already been computed this iteration */
if (manifold) { if (manifold->valid) {
if (manifold->last_manifold_iteration == manifold_iteration) { if (manifold->last_manifold_iteration == manifold_iteration) {
/* Already iterated this manifold from The other entity's perspective, skip */ /* Already iterated this manifold from The other entity's perspective, skip */
continue; continue;
@ -336,8 +343,16 @@ INTERNAL void create_contact_manifolds(void)
#endif #endif
struct gjk_contact_points_result res = gjk_contact_points(e0_poly, e1_poly); 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 (res.num_pairs > 0) {
if (!manifold) { if (!manifold->valid) {
manifold = entity_alloc(root); manifold = entity_alloc(root);
manifold->manifold_e0 = e0->handle; manifold->manifold_e0 = e0->handle;
manifold->manifold_e1 = e1->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)); manifold->manifold_normal = v2_norm(v2_sub(res.pairs[0].p1, res.pairs[0].p0));
entity_enable_prop(manifold, ENTITY_PROP_MANIFOLD); entity_enable_prop(manifold, ENTITY_PROP_MANIFOLD);
activate_now(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 */ /* 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; struct v2 old_normal = manifold->manifold_normal;
for (i32 j = 0; j < (i32)manifold->num_contacts; ++j) { for (i32 j = 0; j < (i32)manifold->num_contacts; ++j) {
@ -420,12 +442,14 @@ INTERNAL void create_contact_manifolds(void)
c = &overflow[overflow_count++]; c = &overflow[overflow_count++];
} }
f32 depth = v2_len(v2_sub(p1_world, p0_world));
MEMZERO_STRUCT(c); MEMZERO_STRUCT(c);
c->p0_local = xform_invert_mul_v2(e0_xf, p0_world); c->p0_local = xform_invert_mul_v2(e0_xf, p0_world);
c->p0_initial_world = p0_world; c->p0_initial_world = p0_world;
c->p1_local = xform_invert_mul_v2(e1_xf, p1_world); c->p1_local = xform_invert_mul_v2(e1_xf, p1_world);
c->p1_initial_world = 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) { } else if (manifold->valid) {
/* No longer colliding, delete contact */ /* No longer colliding, delete manifold */
#if 0
manifold->num_contacts = 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; u32 num_contacts = manifold->num_contacts;
f32 inv_num_contacts = 1.f / num_contacts; f32 inv_num_contacts = 1.f / num_contacts;
if (num_contacts > 0 && e0->valid && e1->valid) { 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 e0_xf = entity_get_xform(e0);
struct xform e1_xf = entity_get_xform(e1); 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_i0 = 1.f / i0;
f32 inv_i1 = 1.f / i1; f32 inv_i1 = 1.f / i1;
struct queued_impulse { struct queued_impulse {
struct v2 p0, p1; struct v2 p0, p1;
f32 impulse; f32 impulse;
@ -602,14 +629,17 @@ INTERNAL void solve_collisions(f32 dt, b32 apply_bias)
/* (to be applied along n) */ /* (to be applied along n) */
f32 j = (vn + bias) / k; f32 j = (vn + bias) / k;
j *= inv_num_contacts; /* TODO: Is this the correct place to do this? */ j *= inv_num_contacts; /* TODO: Is this the correct place to do this? */
(UNUSED)inv_num_contacts;
f32 old_impulse = contact->accumulated_impulse; f32 old_accumulated_impulse = contact->accumulated_impulse;
contact->accumulated_impulse = max_f32(contact->accumulated_impulse + j, 0); 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) { queued_impulses[contact_index] = (struct queued_impulse) {
.p0 = p0, .p0 = p0,
.p1 = p1, .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(e0, impulse, qi.p0);
entity_apply_linear_impulse(e1, v2_neg(impulse), qi.p1); 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; 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) {
/* ========================== * #if 0
* Collision resolution 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); create_contact_manifolds();
solve_collisions(substep_dt, true);
/* ========================== * integrate_positions(substep_dt);
* Integrate positions from velocity #endif
* ========================== */ }
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
} }
#endif
/* ========================== * /* ========================== *
* Initialize bullet kinematics from sources * Initialize bullet kinematics from sources

View File

@ -196,14 +196,17 @@ struct gjk_contact_points_result gjk_contact_points(struct v2_array shape0, stru
s.len = 1; s.len = 1;
/* Second point is support point towards origin */ /* Second point is support point towards origin */
DBGSTEP;
dir = v2_neg(s.a.p); dir = v2_neg(s.a.p);
m = menkowski_point_extended(shape0, shape1, dir); m = menkowski_point_extended(shape0, shape1, dir);
if (v2_dot(dir, m.p) > 0) { if (v2_dot(dir, m.p) > 0) {
DBGSTEP;
s.b = s.a; s.b = s.a;
s.a = m; s.a = m;
s.len = 2; s.len = 2;
while (true) { while (true) {
/* Third point is support point in direction of line normal towards origin */ /* 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)); 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); m = menkowski_point_extended(shape0, shape1, dir);
if (v2_dot(dir, m.p) < 0) { 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 vac = v2_sub(s.c.p, s.a.p);
struct v2 a_to_origin = v2_neg(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 */ dir = v2_perp_towards_dir(vab, v2_neg(vac)); /* Normal of ab pointing away from c */
if (v2_dot(dir, a_to_origin) > 0) { if (v2_dot(dir, a_to_origin) > 0) {
/* Point is in region ab, remove c from simplex */ /* 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_ps_index = ps_index;
pen_pe_index = pe_index; pen_pe_index = pe_index;
pen_len_sq = pd_len_sq; 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; s.len = 2;
/* Find new point in dir */ /* 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); m = menkowski_point_extended(shape0, shape1, dir);
/* Check unique */ /* Check unique */
/* TODO: Better */ /* TODO: Better */
DBGSTEP;
{ {
b32 unique = true; b32 unique = true;
for (u32 i = 0; i < proto_count; ++i) { for (u32 i = 0; i < proto_count; ++i) {

View File

@ -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 */ /* TODO: Maybe increase tolerance for higher precision but more power usage */
//const double tolerance = 0.001200 * scheduler_period_ms; //const double tolerance = 0.001200 * scheduler_period_ms;
const double tolerance = 0.000520 * 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; INT64 max_ticks = (INT64)scheduler_period_ms * 9500;
while (true) { while (true) {

View File

@ -494,9 +494,8 @@ INTERNAL void user_update(void)
entity_set_xform(e, xform_lerp(e0_xf, e1_xf, tick_blend)); 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_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->control_move_force = math_lerp(e0->control_move_force, e1->control_move_force, tick_blend);
e->linear_velocity = v2_lerp(e0->linear_velocity, e1->linear_velocity, 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); 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)) { if (entity_has_prop(ent, ENTITY_PROP_MANIFOLD)) {
f32 radius = 5;
struct entity *e0 = entity_from_handle(store, ent->manifold_e0); struct entity *e0 = entity_from_handle(store, ent->manifold_e0);
struct entity *e1 = entity_from_handle(store, ent->manifold_e1); 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)e1;
(UNUSED)colliding; (UNUSED)colliding;
struct xform e0_xf = entity_get_xform(e0);
struct xform e1_xf = entity_get_xform(e1);
/* Create shapes */ /* Create shapes */
struct quad ent_quad; struct quad e0_quad;
struct v2_array ent_poly; struct v2_array e0_poly;
struct quad e1_quad; struct quad e1_quad;
struct v2_array e1_poly; struct v2_array e1_poly;
{ {
{ {
struct sprite_sheet *sheet = sprite_sheet_from_tag_await(sprite_frame_scope, ent->sprite); 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"), ent->animation_frame); struct sprite_sheet_slice slice = sprite_sheet_get_slice(sheet, STR("shape"), e0->animation_frame);
ent_quad = xform_mul_quad(ent->sprite_local_xform, quad_from_rect(slice.rect)); e0_quad = xform_mul_quad(e0->sprite_local_xform, quad_from_rect(slice.rect));
ent_quad = xform_mul_quad(xf, ent_quad); e0_quad = xform_mul_quad(e0_xf, e0_quad);
ent_poly = (struct v2_array) { e0_poly = (struct v2_array) {
.count = ARRAY_COUNT(ent_quad.e), .count = ARRAY_COUNT(e0_quad.e),
.points = ent_quad.e .points = e0_quad.e
}; };
} }
{ {
struct sprite_sheet *sheet = sprite_sheet_from_tag_await(sprite_frame_scope, e1->sprite); 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); 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(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) { e1_poly = (struct v2_array) {
.count = ARRAY_COUNT(e1_quad.e), .count = ARRAY_COUNT(e1_quad.e),
.points = e1_quad.e .points = e1_quad.e
@ -1051,23 +1026,25 @@ INTERNAL void user_update(void)
} }
} }
#if 0
/* Draw collision shapes */ /* Draw collision shapes */
{ {
f32 thickness = 2; f32 thickness = 2;
u32 color = RGBA_32_F(1, 0, 0, 0.25); 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); draw_solid_quad_line(G.viewport_canvas, quad, thickness, color);
} }
#endif
/* Draw menkowski */ /* 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); u32 color = ent->solved ? RGBA_32_F(0, 0, 0.25, 1) : RGBA_32_F(0, 0.25, 0.25, 1);
f32 thickness = 2; f32 thickness = 2;
(UNUSED)thickness; (UNUSED)thickness;
struct v2_array m = menkowski(temp.arena, ent_poly, e1_poly); struct v2_array m = menkowski(temp.arena, e0_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, 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]); 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); draw_solid_poly_line(G.viewport_canvas, m, true, thickness, color);
@ -1075,11 +1052,11 @@ INTERNAL void user_update(void)
} }
/* Draw cloud */ /* Draw cloud */
if (entity_has_prop(ent, ENTITY_PROP_PLAYER_CONTROLLED)) { {
u32 color = RGBA_32_F(1, 1, 1, 1); u32 color = RGBA_32_F(1, 1, 1, 1);
f32 radius = 2; 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) { for (u64 i = 0; i < m.count; ++i) {
struct v2 p = xform_mul_v2(G.world_view, m.points[i]);; struct v2 p = xform_mul_v2(G.world_view, m.points[i]);;
@ -1088,7 +1065,8 @@ INTERNAL void user_update(void)
} }
/* Draw pendir */ /* Draw pendir */
if (entity_has_prop(ent, ENTITY_PROP_PLAYER_CONTROLLED)) { #if 0
{
f32 thickness = 2; f32 thickness = 2;
u32 color = COLOR_YELLOW; 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); draw_solid_arrow_ray(G.viewport_canvas, start, ray, thickness, thickness * 4, color);
} }
#endif
/* Draw prototype */ /* Draw prototype */
if (entity_has_prop(ent, ENTITY_PROP_PLAYER_CONTROLLED)) { {
f32 thickness = 2; f32 thickness = 2;
u32 color = RGBA_32_F(1, 1, 1, 0.25); u32 color = RGBA_32_F(1, 1, 1, 0.25);
@ -1112,7 +1091,7 @@ INTERNAL void user_update(void)
} }
/* Draw simplex */ /* Draw simplex */
if (entity_has_prop(ent, ENTITY_PROP_PLAYER_CONTROLLED)) { {
f32 thickness = 2; f32 thickness = 2;
u32 line_color = colliding ? COLOR_WHITE: COLOR_YELLOW; u32 line_color = colliding ? COLOR_WHITE: COLOR_YELLOW;
u32 color_first = RGBA_32_F(1, 0, 0, 0.75); 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; 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); for (u32 i = 0; i < ent->num_contacts; ++i) {
{ struct contact contact = ent->contacts[i];
struct v2 point = xform_mul_v2(G.world_view, ent->point0); {
draw_solid_circle(G.viewport_canvas, point, radius, color, 10); 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);
if (!v2_is_zero(ent->point1)) { //struct v2 point = contact.p0_initial_world;
//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); point = xform_mul_v2(G.world_view, point);
struct v2 point = xform_mul_v2(G.world_view, ent->point1); draw_solid_circle(G.viewport_canvas, point, radius, color, 10);
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))); draw_text(G.viewport_canvas, font, pos, string_format(temp.arena, STR("world time: %F"), FMT_FLOAT((f64)G.world.time)));
pos.y += spacing; 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))); 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; pos.y += spacing;