diff --git a/src/app.c b/src/app.c index 876b6aae..27ff367a 100644 --- a/src/app.c +++ b/src/app.c @@ -267,7 +267,6 @@ void app_entry_point(void) arena_temp_end(temp); } - logf_info("Program exited normally"); scratch_end(scratch); } diff --git a/src/entity.c b/src/entity.c index 75932fbe..69590cf3 100644 --- a/src/entity.c +++ b/src/entity.c @@ -78,7 +78,7 @@ void entity_store_copy_replace(struct entity_store *dest, struct entity_store *s } /* ========================== * - * Allocation + * Entity allocation * ========================== */ INTERNAL struct entity *entity_alloc_internal(struct entity_store *store) @@ -132,7 +132,7 @@ INTERNAL void entity_release_internal(struct entity_store *store, struct entity void entity_release(struct entity_store *store, struct entity *ent) { if (ent->parent.gen) { - entity_unlink_parent(ent); + entity_unlink_from_parent(ent); } entity_release_internal(store, ent); } @@ -352,7 +352,7 @@ void entity_link_parent(struct entity *ent, struct entity *parent) if (ent->parent.gen) { /* Unlink from current parent */ - entity_unlink_parent(ent); + entity_unlink_from_parent(ent); } struct entity_handle handle = ent->handle; @@ -370,11 +370,16 @@ void entity_link_parent(struct entity *ent, struct entity *parent) } parent->last = handle; - ent->is_top = parent->is_root; + if (parent->is_root) { + ent->is_top = true; + ent->top = handle; + } else { + ent->top = parent->top; + } } /* NOTE: Entity will be dangling after calling this, should re-link to root entity. */ -void entity_unlink_parent(struct entity *ent) +void entity_unlink_from_parent(struct entity *ent) { struct entity_store *store = entity_get_store(ent); diff --git a/src/entity.h b/src/entity.h index 0cdb2750..647bddaf 100644 --- a/src/entity.h +++ b/src/entity.h @@ -91,6 +91,9 @@ struct entity { /* Is entity a child of the root entity */ b32 is_top; + /* The handle of the top level parent of the entity */ + struct entity_handle top; + /* Tree */ struct entity_handle parent; struct entity_handle next; @@ -353,7 +356,7 @@ struct entity *entity_find_first_match_all(struct entity_store *store, struct en /* Tree */ void entity_link_parent(struct entity *parent, struct entity *child); -void entity_unlink_parent(struct entity *ent); +void entity_unlink_from_parent(struct entity *ent); /* Lookup */ struct entity_lookup entity_lookup_alloc(u64 num_buckets); diff --git a/src/game.c b/src/game.c index bb7bd18d..dcf5d184 100644 --- a/src/game.c +++ b/src/game.c @@ -335,6 +335,7 @@ INTERNAL PHYS_COLLISION_CALLBACK_FUNC_DEF(on_collision, array) for (u64 i = 0; i < array.count; ++i) { struct phys_collision_data *data = &array.a[i]; + struct phys_contact_constraint *constraint = data->constraint; struct entity *e0 = entity_from_handle(store, data->e0); struct entity *e1 = entity_from_handle(store, data->e1); @@ -343,8 +344,16 @@ INTERNAL PHYS_COLLISION_CALLBACK_FUNC_DEF(on_collision, array) if (entity_has_prop(e0, ENTITY_PROP_BULLET) || entity_has_prop(e1, ENTITY_PROP_BULLET)) { struct entity *bullet = entity_has_prop(e0, ENTITY_PROP_BULLET) ? e0 : e1; struct entity *target = e0 == bullet ? e1 : e0; + struct entity *src = entity_from_handle(store, bullet->bullet_src); (UNUSED)bullet; (UNUSED)target; + (UNUSED)src; + + if (entity_handle_eq(src->top, target->top)) { + /* Ignore collision if weapon and target share same top level parent */ + constraint->skip_solve = true; + continue; + } /* Disable bullet */ entity_enable_prop(bullet, ENTITY_PROP_RELEASE_BEFORE_PUBLISH); diff --git a/src/phys.c b/src/phys.c index 5576d934..b21adc64 100644 --- a/src/phys.c +++ b/src/phys.c @@ -119,10 +119,27 @@ struct phys_collision_data_array phys_create_contacts(struct arena *arena, struc struct phys_contact_constraint *constraint = NULL; if (collider_res.num_points > 0) { if (!entity_is_valid_and_active(constraint_ent)) { + /* Create constraint */ + { + constraint_ent = entity_alloc(root); + constraint_ent->contact_constraint_data.e1 = e1->handle; + constraint_ent->contact_constraint_data.e0 = e0->handle; + constraint_ent->contact_constraint_data.skip_solve = entity_has_prop(e0, ENTITY_PROP_SENSOR) || entity_has_prop(e1, ENTITY_PROP_SENSOR) + || !(entity_has_prop(e0, ENTITY_PROP_PHYSICAL_DYNAMIC) || entity_has_prop(e1, ENTITY_PROP_PHYSICAL_DYNAMIC)); + entity_enable_prop(constraint_ent, ENTITY_PROP_ACTIVE); + + /* TODO: Should we recalculate normal as more contact points are added? */ + entity_enable_prop(constraint_ent, ENTITY_PROP_CONTACT_CONSTRAINT); + entity_activate(constraint_ent, tick_id); + ASSERT(!entry); /* Existing entry should never be present here */ + entity_lookup_set(contact_lookup, key, constraint_ent->handle); + } + /* Push collision data */ if (ctx->pre_solve_callback || ctx->post_solve_callback) { struct phys_collision_data *data = arena_push_zero(arena, struct phys_collision_data); ++res.count; + data->constraint = &constraint_ent->contact_constraint_data; data->e0 = e0->handle; data->e1 = e1->handle; data->normal = collider_res.normal; @@ -150,22 +167,6 @@ struct phys_collision_data_array phys_create_contacts(struct arena *arena, struc } data->vrel = vrel; } - - /* Create constraint */ - { - constraint_ent = entity_alloc(root); - constraint_ent->contact_constraint_data.e1 = e1->handle; - constraint_ent->contact_constraint_data.e0 = e0->handle; - constraint_ent->contact_constraint_data.skip_solve = entity_has_prop(e0, ENTITY_PROP_SENSOR) || entity_has_prop(e1, ENTITY_PROP_SENSOR) - || !(entity_has_prop(e0, ENTITY_PROP_PHYSICAL_DYNAMIC) || entity_has_prop(e1, ENTITY_PROP_PHYSICAL_DYNAMIC)); - entity_enable_prop(constraint_ent, ENTITY_PROP_ACTIVE); - - /* TODO: Should we recalculate normal as more contact points are added? */ - entity_enable_prop(constraint_ent, ENTITY_PROP_CONTACT_CONSTRAINT); - entity_activate(constraint_ent, tick_id); - ASSERT(!entry); /* Existing entry should never be present here */ - entity_lookup_set(contact_lookup, key, constraint_ent->handle); - } } constraint = &constraint_ent->contact_constraint_data; constraint->normal = collider_res.normal; @@ -1127,7 +1128,7 @@ void phys_step(struct phys_ctx *ctx, f32 timestep) f32 remaining_dt = timestep; while (remaining_dt > 0) { - __profscope(step); + __profscope(step_part); struct temp_arena scratch = scratch_begin_no_conflict(); /* TOI */ f32 step_dt = remaining_dt; @@ -1160,22 +1161,27 @@ void phys_step(struct phys_ctx *ctx, f32 timestep) f32 substep_dt = step_dt / GAME_PHYSICS_SUBSTEPS; for (u32 i = 0; i < GAME_PHYSICS_SUBSTEPS; ++i) { __profscope(substep); + + /* Warm start */ #if GAME_PHYSICS_ENABLE_WARM_STARTING phys_warm_start_contacts(ctx); phys_warm_start_motor_joints(ctx); phys_warm_start_mouse_joints(ctx); #endif + /* Solve */ #if GAME_PHYSICS_ENABLE_COLLISION phys_solve_contacts(ctx, substep_dt, true); #endif phys_solve_motor_joints(ctx, substep_dt); phys_solve_mouse_joints(ctx, substep_dt); + /* Integrate */ phys_integrate_velocities(ctx, substep_dt); + /* Relaxation solve */ #if GAME_PHYSICS_ENABLE_COLLISION && GAME_PHYSICS_ENABLE_RELAXATION - phys_solve_contacts(ctx, substep_dt, false); /* Relaxation */ + phys_solve_contacts(ctx, substep_dt, false); #endif } diff --git a/src/phys.h b/src/phys.h index cfdb9469..aafbb71d 100644 --- a/src/phys.h +++ b/src/phys.h @@ -7,8 +7,9 @@ struct entity_store; struct entity_lookup; +struct phys_contact_constraint; struct phys_collision_data { - struct entity_handle constraint_ent; + struct phys_contact_constraint *constraint; struct entity_handle e0; struct entity_handle e1; struct v2 point;