diff --git a/src/log.c b/src/log.c index 421c9f06..a2349885 100644 --- a/src/log.c +++ b/src/log.c @@ -139,15 +139,16 @@ void _log(i32 level, struct string msg) #if LOG_INCLUDE_SOURCE_LOCATION struct string msg_formatted = string_format( scratch.arena, - LIT("%F:%F:%F |Thread %F| [%F] <%F:%F> %F"), + LIT("[%F:%F:%F.%F] |%F| [%F] <%F:%F> %F"), /* Time */ - FMT_UINT(lt.hour), - FMT_UINT(lt.minute), - FMT_UINT(lt.second), + FMT_UINT_Z(lt.hour, 2), + FMT_UINT_Z(lt.minute, 2), + FMT_UINT_Z(lt.second, 2), + FMT_UINT_Z(lt.milliseconds, 3), /* TID */ - FMT_UINT(tid), + FMT_UINT_Z(tid, 5), /* Level */ FMT_STR(shorthand), @@ -162,15 +163,16 @@ void _log(i32 level, struct string msg) #else struct string msg_formatted = string_format( scratch.arena, - LIT("%F:%F:%F |Thread %F| [%F] %F"), + LIT("[%F:%F:%F.%F] |%F| [%F] %F"), /* Time */ - FMT_UINT(lt.hour), - FMT_UINT(lt.minute), - FMT_UINT(lt.second), + FMT_UINT_Z(lt.hour, 2), + FMT_UINT_Z(lt.minute, 2), + FMT_UINT_Z(lt.second, 2), + FMT_UINT_Z(lt.milliseconds, 3), /* TID */ - FMT_UINT(tid), + FMT_UINT_Z(tid, 5), /* Level */ FMT_STR(shorthand), diff --git a/src/phys.c b/src/phys.c index f8b0f93c..af1d3467 100644 --- a/src/phys.c +++ b/src/phys.c @@ -55,7 +55,7 @@ struct phys_collision_data_array phys_create_and_update_contacts(struct arena *a for (u64 check0_index = 0; check0_index < ss->num_ents_reserved; ++check0_index) { struct sim_ent *check0 = &ss->ents[check0_index]; if (!sim_ent_is_valid_and_active(check0)) continue; - if (!(sim_ent_has_prop(check0, SEPROP_PHYSICAL_DYNAMIC) || sim_ent_has_prop(check0, SEPROP_PHYSICAL_KINEMATIC))) continue; + if (!(sim_ent_has_prop(check0, SEPROP_PHYSICAL_DYNAMIC) || sim_ent_has_prop(check0, SEPROP_PHYSICAL_KINEMATIC) || sim_ent_has_prop(check0, SEPROP_SENSOR))) continue; if (check0->local_collider.count <= 0) continue; struct xform check0_xf = sim_ent_get_xform(check0); @@ -68,7 +68,7 @@ struct phys_collision_data_array phys_create_and_update_contacts(struct arena *a struct sim_ent *check1 = sim_ent_from_id(ss, space_entry->ent); if (check1 == check0) continue; if (!sim_ent_is_valid_and_active(check1)) continue; - if (!(sim_ent_has_prop(check1, SEPROP_PHYSICAL_DYNAMIC) || sim_ent_has_prop(check1, SEPROP_PHYSICAL_KINEMATIC))) continue; + if (!(sim_ent_has_prop(check1, SEPROP_PHYSICAL_DYNAMIC) || sim_ent_has_prop(check1, SEPROP_PHYSICAL_KINEMATIC) || sim_ent_has_prop(check1, SEPROP_SENSOR))) continue; if (check1->local_collider.count <= 0) continue; /* Deterministic order based on entity id */ @@ -323,11 +323,11 @@ void phys_prepare_contacts(struct phys_step_ctx *ctx, u64 phys_iteration) constraint->inv_i0 = inv_i0; constraint->inv_i1 = inv_i1; - if (sim_ent_has_prop(e0, SEPROP_PHYSICAL_KINEMATIC)) { + if (!sim_ent_has_prop(e0, SEPROP_PHYSICAL_DYNAMIC)) { constraint->inv_m0 = 0; constraint->inv_i0 = 0; } - if (sim_ent_has_prop(e1, SEPROP_PHYSICAL_KINEMATIC)) { + if (!sim_ent_has_prop(e1, SEPROP_PHYSICAL_DYNAMIC)) { constraint->inv_m1 = 0; constraint->inv_i1 = 0; } @@ -381,8 +381,8 @@ void phys_prepare_contacts(struct phys_step_ctx *ctx, u64 phys_iteration) if (!sim_ent_should_simulate(e0) || !sim_ent_should_simulate(e1) - || !(sim_ent_has_prop(e0, SEPROP_PHYSICAL_DYNAMIC) || sim_ent_has_prop(e0, SEPROP_PHYSICAL_KINEMATIC)) - || !(sim_ent_has_prop(e1, SEPROP_PHYSICAL_DYNAMIC) || sim_ent_has_prop(e1, SEPROP_PHYSICAL_KINEMATIC))) { + || !(sim_ent_has_prop(e0, SEPROP_PHYSICAL_DYNAMIC) || sim_ent_has_prop(e0, SEPROP_PHYSICAL_KINEMATIC) || !sim_ent_has_prop(e0, SEPROP_SENSOR)) + || !(sim_ent_has_prop(e1, SEPROP_PHYSICAL_DYNAMIC) || sim_ent_has_prop(e1, SEPROP_PHYSICAL_KINEMATIC) || !sim_ent_has_prop(e1, SEPROP_SENSOR))) { /* Mark dbg ent for removal */ sim_ent_disable_prop(dbg_ent, SEPROP_ACTIVE); sim_ent_enable_prop(dbg_ent, SEPROP_RELEASE); @@ -1002,7 +1002,7 @@ f32 phys_determine_earliest_toi_for_bullets(struct phys_step_ctx *ctx, f32 step_ for (u64 e0_index = 0; e0_index < ss->num_ents_reserved; ++e0_index) { struct sim_ent *e0 = &ss->ents[e0_index]; if (!sim_ent_should_simulate(e0)) continue; - if (!(sim_ent_has_prop(e0, SEPROP_PHYSICAL_DYNAMIC) || sim_ent_has_prop(e0, SEPROP_PHYSICAL_KINEMATIC))) continue; + if (!(sim_ent_has_prop(e0, SEPROP_PHYSICAL_DYNAMIC) || sim_ent_has_prop(e0, SEPROP_PHYSICAL_KINEMATIC) || sim_ent_has_prop(e0, SEPROP_SENSOR))) continue; if (!sim_ent_has_prop(e0, SEPROP_BULLET)) continue; if (e0->local_collider.count <= 0) continue; @@ -1021,7 +1021,7 @@ f32 phys_determine_earliest_toi_for_bullets(struct phys_step_ctx *ctx, f32 step_ struct sim_ent *e1 = sim_ent_from_id(ss, entry->ent); if (e1 == e0) continue; if (!sim_ent_should_simulate(e1)) continue; - if (!(sim_ent_has_prop(e1, SEPROP_PHYSICAL_DYNAMIC) || sim_ent_has_prop(e1, SEPROP_PHYSICAL_KINEMATIC))) continue; + if (!(sim_ent_has_prop(e1, SEPROP_PHYSICAL_DYNAMIC) || sim_ent_has_prop(e1, SEPROP_PHYSICAL_KINEMATIC) || sim_ent_has_prop(e1, SEPROP_SENSOR))) continue; if (e1->local_collider.count <= 0) continue; struct collider_shape e1_collider = e1->local_collider; @@ -1068,6 +1068,26 @@ void phys_update_aabbs(struct phys_step_ctx *ctx) * Step * ========================== */ +INTERNAL void run_collision_callbacks(struct phys_step_ctx *ctx, phys_collision_callback_func *callback, struct phys_collision_data_array collision_data) +{ + struct sim_step_ctx *sim_step_ctx = ctx->sim_step_ctx; + for (u64 i = 0; i < collision_data.count; ++i) { + /* Collision data from e0's perspective */ + struct phys_collision_data *data = &collision_data.a[i]; + + /* Collision data from e1's perspective */ + struct phys_collision_data data_inverted = *data; + data_inverted.e0 = data->e1; + data_inverted.e1 = data->e0; + data_inverted.normal = v2_neg(data->normal); + data_inverted.vrel = v2_neg(data->vrel); + + /* Run callback twice for both e0 & e1 */ + callback(data, sim_step_ctx); + callback(&data_inverted, sim_step_ctx); + } +} + /* Returns phys iteration to be fed into next step. Supplied iteration must be > 0. */ void phys_step(struct phys_step_ctx *ctx, f32 timestep) { @@ -1107,7 +1127,7 @@ void phys_step(struct phys_step_ctx *ctx, f32 timestep) if (ctx->pre_solve_callback) { __profscope(pre_solve_callback); - ctx->pre_solve_callback(collision_data, ctx->sim_step_ctx); + run_collision_callbacks(ctx, ctx->pre_solve_callback, collision_data); } f32 substep_dt = step_dt / SIM_PHYSICS_SUBSTEPS; @@ -1141,7 +1161,7 @@ void phys_step(struct phys_step_ctx *ctx, f32 timestep) if (ctx->post_solve_callback) { __profscope(post_solve_callback); - ctx->post_solve_callback(collision_data, ctx->sim_step_ctx); + run_collision_callbacks(ctx, ctx->post_solve_callback, collision_data); } scratch_end(scratch); diff --git a/src/phys.h b/src/phys.h index 73d7e29e..b8861aa0 100644 --- a/src/phys.h +++ b/src/phys.h @@ -10,6 +10,7 @@ struct sim_step_ctx; struct phys_contact_constraint; struct phys_collision_data { + /* NOTE: e0 & e1 can be opposite of e0 & e1 contained in constraint when passed to collision callbacks */ struct phys_contact_constraint *constraint; struct sim_ent_id e0; struct sim_ent_id e1; @@ -25,7 +26,7 @@ struct phys_collision_data_array { }; struct phys_collision_data; -#define PHYS_COLLISION_CALLBACK_FUNC_DEF(name, arg_collision_data, arg_sim_step_ctx) void name(struct phys_collision_data_array arg_collision_data, struct sim_step_ctx *arg_sim_step_ctx) +#define PHYS_COLLISION_CALLBACK_FUNC_DEF(name, arg_collision_data, arg_sim_step_ctx) void name(struct phys_collision_data *arg_collision_data, struct sim_step_ctx *arg_sim_step_ctx) typedef PHYS_COLLISION_CALLBACK_FUNC_DEF(phys_collision_callback_func, collision_data, ctx); /* Structure containing data used for a single physics step */ diff --git a/src/renderer_d3d11.c b/src/renderer_d3d11.c index 1ae7e00c..18c561f2 100644 --- a/src/renderer_d3d11.c +++ b/src/renderer_d3d11.c @@ -291,9 +291,16 @@ INTERNAL struct string shader_alloc(struct arena *arena, struct dx11_shader *sha } else { error_str = LIT("Unknown error"); if (error_blob) { - u64 error_cstr_len = ID3D10Blob_GetBufferSize(error_blob); - char *error_cstr = (char *)ID3D10Blob_GetBufferPointer(error_blob); - error_str = string_copy(arena, string_from_cstr(error_cstr, error_cstr_len)); + u64 error_blob_cstr_len = ID3D10Blob_GetBufferSize(error_blob); + char *error_blob_cstr = (char *)ID3D10Blob_GetBufferPointer(error_blob); + struct string error_blob_str = string_copy(arena, string_from_cstr(error_blob_cstr, error_blob_cstr_len)); + if (string_ends_with(error_blob_str, LIT("\n"))) { + /* Remove trailing newline */ + error_blob_str.len -= 1; + } + if (error_blob_str.len > 0) { + error_str = error_blob_str; + } } } @@ -346,7 +353,7 @@ INTERNAL void reload_shader(struct dx11_shader *old_shader, struct dx11_shader_d *old_shader = new_shader; } else { error_msg = string_format(scratch.arena, - LIT("Failed to compile shader \"%F\":\n\n%F"), + LIT("Failed to compile shader \"%F\":\n%F"), FMT_STR(name), FMT_STR(comp_error)); shader_release(&new_shader); diff --git a/src/sim_ent.h b/src/sim_ent.h index 640dcb59..b301e59e 100644 --- a/src/sim_ent.h +++ b/src/sim_ent.h @@ -48,7 +48,6 @@ enum sim_ent_prop { SEPROP_TRIGGER_NEXT_TICK, SEPROP_EXPLOSION, - SEPROP_EXPLOSION_STARTED, SEPROP_BULLET, SEPROP_TRACER, @@ -303,6 +302,7 @@ struct sim_ent { /* Explosion */ f32 explosion_radius; + u64 explosion_tick; /* ====================================================================== */ /* Tracer */ diff --git a/src/sim_step.c b/src/sim_step.c index 4a8c15df..14ca1dc3 100644 --- a/src/sim_step.c +++ b/src/sim_step.c @@ -49,7 +49,7 @@ void sim_accel_reset(struct sim_snapshot *ss, struct sim_accel *accel) * Test * ========================== */ -/* TODO: Remove this */ + /* TODO: Remove this */ INTERNAL struct sim_ent *spawn_test_employee(struct sim_step_ctx *ctx) { @@ -153,6 +153,23 @@ INTERNAL struct sim_ent *spawn_test_camera(struct sim_snapshot *world, struct si return camera_ent; } +INTERNAL struct sim_ent *spawn_test_explosion(struct sim_snapshot *world, struct v2 point, f32 radius) +{ + struct sim_ent *root = sim_ent_from_id(world, SIM_ENT_ROOT_ID); + + struct sim_ent *ent = sim_ent_alloc_sync_src(root); + sim_ent_set_xform(ent, XFORM_POS(point)); + + sim_ent_enable_prop(ent, SEPROP_EXPLOSION); + ent->explosion_radius = radius; + + sim_ent_enable_prop(ent, SEPROP_SENSOR); + ent->local_collider.count = 1; + ent->local_collider.radius = radius; + + return ent; +} + INTERNAL void spawn_test_entities(struct sim_step_ctx *ctx, struct v2 offset) { struct sim_snapshot *world = ctx->world; @@ -257,30 +274,25 @@ INTERNAL void test_clear_level(struct sim_step_ctx *ctx) * Respond to physics collisions * ========================== */ -INTERNAL void on_collision(struct sim_ent *e0, struct sim_ent *e1, struct phys_collision_data *data, struct sim_step_ctx *step_ctx) +INTERNAL PHYS_COLLISION_CALLBACK_FUNC_DEF(on_collision, data, step_ctx) { - struct sim_snapshot *world = step_ctx->world; + struct sim_ent *e0 = sim_ent_from_id(world, data->e0); + struct sim_ent *e1 = sim_ent_from_id(world, data->e1); struct sim_ent *root = sim_ent_from_id(world, SIM_ENT_ROOT_ID); - struct phys_contact_constraint *constraint = data->constraint; if (sim_ent_should_simulate(e0) && sim_ent_should_simulate(e1)) { - /* Bullet impact */ if (sim_ent_has_prop(e0, SEPROP_BULLET)) { struct v2 normal = data->normal; /* Impact normal */ - struct v2 vrel = v2_neg(data->vrel); /* Impact velocity */ + struct v2 vrel = data->vrel; /* Impact velocity */ struct sim_ent *bullet = e0; struct sim_ent *target = e1; struct sim_ent *src = sim_ent_from_id(world, bullet->bullet_src); - if (bullet->bullet_has_hit || sim_ent_id_eq(src->top, target->top)) { - /* Ignore collision if bullet already spent or if weapon and - * target share same top level parent */ - /* NOTE: Since bullet is most likely just a sensor skip_solve is probably already true */ - constraint->skip_solve = true; - } else { + /* Process collision if bullet already spent or * target share same top level parent */ + if (!bullet->bullet_has_hit && !sim_ent_id_eq(src->top, target->top)) { struct v2 point = data->point; /* Update tracer */ @@ -323,12 +335,7 @@ INTERNAL void on_collision(struct sim_ent *e0, struct sim_ent *e1, struct phys_c /* Create explosion */ if (bullet->bullet_impact_explosion_radius > 0) { - struct sim_ent *exp = sim_ent_alloc_sync_src(root); - sim_ent_set_xform(exp, XFORM_POS(point)); - - sim_ent_enable_prop(exp, SEPROP_SENSOR); - sim_ent_enable_prop(exp, SEPROP_EXPLOSION); - exp->explosion_radius = bullet->bullet_impact_explosion_radius; + spawn_test_explosion(world, point, bullet->bullet_impact_explosion_radius); } /* Update bullet */ @@ -336,20 +343,39 @@ INTERNAL void on_collision(struct sim_ent *e0, struct sim_ent *e1, struct phys_c sim_ent_enable_prop(bullet, SEPROP_RELEASE); } } - } -} -INTERNAL PHYS_COLLISION_CALLBACK_FUNC_DEF(pre_solve_callback, collision_data_array, step_ctx) -{ - struct sim_snapshot *world = step_ctx->world; - for (u64 i = 0; i < collision_data_array.count; ++i) { - struct phys_collision_data *data = &collision_data_array.a[i]; - struct sim_ent *e0 = sim_ent_from_id(world, data->e0); - struct sim_ent *e1 = sim_ent_from_id(world, data->e1); - if (sim_ent_is_valid_and_active(e0) && sim_ent_is_valid_and_active(e1)) { - on_collision(e0, e1, data, step_ctx); - if (sim_ent_is_valid_and_active(e1) && sim_ent_is_valid_and_active(e0)) { - on_collision(e1, e0, data, step_ctx); + /* Explosion blast collision */ + if (sim_ent_has_prop(e0, SEPROP_EXPLOSION) && (e0->explosion_tick == world->tick || e0->explosion_tick == 0)) { + struct sim_ent *exp = e0; + struct sim_ent *victim = e1; + + exp->explosion_tick = world->tick; + sim_ent_disable_prop(exp, SEPROP_SENSOR); + + struct xform xf = sim_ent_get_xform(exp); + + f32 radius = exp->explosion_radius; + + struct collider_shape origin_collider = ZI; + origin_collider.count = 1; + + struct xform victim_xf = sim_ent_get_xform(victim); + struct collider_closest_points_result closest_points = collider_closest_points(&origin_collider, &victim->local_collider, xf, victim_xf); + struct v2 dir = v2_sub(closest_points.p1, closest_points.p0); + f32 distance = v2_len(dir); + if (closest_points.colliding) { + dir = v2_neg(dir); + distance = 0; + } else { + distance = v2_len(dir); + } + /* TODO: Blast obstruction */ + if (distance <= radius) { + /* TODO: Exponential decay */ + f32 strength = 100; + f32 ratio = (radius - distance) / radius; + struct v2 impulse = v2_with_len(dir, strength * ratio); + sim_ent_apply_linear_impulse(victim, impulse, closest_points.p1); } } } @@ -584,11 +610,7 @@ void sim_step(struct sim_step_ctx *ctx) if (flags & SIM_CONTROL_FLAG_EXPLODE_TEST) { if (!(old_control.flags & SIM_CONTROL_FLAG_EXPLODE_TEST)) { logf_info("Explosion (test)"); - struct sim_ent *exp = sim_ent_alloc_sync_src(root); - sim_ent_set_xform(exp, XFORM_POS(player->player_cursor_pos)); - - sim_ent_enable_prop(exp, SEPROP_EXPLOSION); - exp->explosion_radius = 50; + spawn_test_explosion(world, player->player_cursor_pos, 1); } } @@ -1228,64 +1250,10 @@ void sim_step(struct sim_step_ctx *ctx) { struct phys_step_ctx phys = ZI; phys.sim_step_ctx = ctx; - phys.pre_solve_callback = pre_solve_callback; + phys.pre_solve_callback = on_collision; phys_step(&phys, sim_dt); } - /* ========================== * - * Update explosions - * ========================== */ - - for (u64 ent_index = 0; ent_index < world->num_ents_reserved; ++ent_index) { - struct sim_ent *ent = &world->ents[ent_index]; - if (!sim_ent_should_simulate(ent)) continue; - - if (sim_ent_has_prop(ent, SEPROP_EXPLOSION)) { - struct xform xf = sim_ent_get_xform(ent); - if (!sim_ent_has_prop(ent, SEPROP_EXPLOSION_STARTED)) { - f32 radius = ent->explosion_radius; - sim_ent_enable_prop(ent, SEPROP_EXPLOSION_STARTED); - - struct collider_shape origin_collider = ZI; - origin_collider.count = 1; - - struct aabb aabb = ZI; - { - struct collider_shape radius_collider = ZI; - radius_collider.radius = radius; - radius_collider.count = 1; - ent->local_collider = radius_collider; - aabb = collider_aabb_from_collider(&radius_collider, xf); - } - - /* Find ents in blast range */ - struct space_iter iter = space_iter_begin_aabb(ctx->accel->space, aabb); - struct space_entry *space_entry; - while ((space_entry = space_iter_next(&iter))) { - struct sim_ent *victim = sim_ent_from_id(world, space_entry->ent); - if (sim_ent_should_simulate(victim) && sim_ent_has_prop(victim, SEPROP_PHYSICAL_DYNAMIC) && !sim_ent_id_eq(ent->id, victim->id)) { - struct xform victim_xf = sim_ent_get_xform(victim); - struct collider_closest_points_result closest_points = collider_closest_points(&origin_collider, &victim->local_collider, xf, victim_xf); - struct v2 dir = v2_sub(closest_points.p1, closest_points.p0); - f32 distance = v2_len(dir); - /* TODO: Blast obstruction */ - if (distance <= radius) { - /* TODO: Exponential decay */ - //f32 ratio = (radius - distance) / radius; - //f32 strength = 100; - //struct v2 impulse = v2_with_len(dir, strength * ratio); - struct v2 impulse = V2(-100, 0); - - //sim_ent_apply_linear_impulse(victim, impulse, closest_points.p1); - sim_ent_apply_linear_impulse_to_center(victim, impulse); - } - } - } - space_iter_end(iter); - } - } - } - /* ========================== * * Update tracers * ========================== */