refactor ent store into snapshot
This commit is contained in:
parent
e1a1006b32
commit
fd550a7119
@ -225,9 +225,8 @@ void app_entry_point(struct string args_str)
|
|||||||
struct sound_startup_receipt sound_sr = sound_startup(&work_sr, &asset_cache_sr, &resource_sr);
|
struct sound_startup_receipt sound_sr = sound_startup(&work_sr, &asset_cache_sr, &resource_sr);
|
||||||
struct draw_startup_receipt draw_sr = draw_startup(&renderer_sr, &font_sr);
|
struct draw_startup_receipt draw_sr = draw_startup(&renderer_sr, &font_sr);
|
||||||
struct phys_startup_receipt phys_sr = phys_startup();
|
struct phys_startup_receipt phys_sr = phys_startup();
|
||||||
struct sim_ent_startup_receipt sim_ent_sr = sim_ent_startup();
|
|
||||||
struct sim_snapshot_startup_receipt sim_snapshot_sr = sim_snapshot_startup();
|
struct sim_snapshot_startup_receipt sim_snapshot_sr = sim_snapshot_startup();
|
||||||
struct user_startup_receipt user_sr = user_startup(&work_sr, &renderer_sr, &font_sr, &sprite_sr, &draw_sr, &asset_cache_sr, &sound_sr, &mixer_sr, &phys_sr, &host_sr, &sim_ent_sr, &sim_snapshot_sr, args_str, &window);
|
struct user_startup_receipt user_sr = user_startup(&work_sr, &renderer_sr, &font_sr, &sprite_sr, &draw_sr, &asset_cache_sr, &sound_sr, &mixer_sr, &phys_sr, &host_sr, &sim_snapshot_sr, args_str, &window);
|
||||||
struct playback_startup_receipt playback_sr = playback_startup(&mixer_sr);
|
struct playback_startup_receipt playback_sr = playback_startup(&mixer_sr);
|
||||||
|
|
||||||
(UNUSED)user_sr;
|
(UNUSED)user_sr;
|
||||||
|
|||||||
143
src/phys.c
143
src/phys.c
@ -1,4 +1,5 @@
|
|||||||
#include "phys.h"
|
#include "phys.h"
|
||||||
|
#include "sim_snapshot.h"
|
||||||
#include "sim_ent.h"
|
#include "sim_ent.h"
|
||||||
#include "math.h"
|
#include "math.h"
|
||||||
#include "scratch.h"
|
#include "scratch.h"
|
||||||
@ -43,15 +44,16 @@ struct phys_collision_data_array phys_create_and_update_contacts(struct arena *a
|
|||||||
__prof;
|
__prof;
|
||||||
struct phys_collision_data_array res = ZI;
|
struct phys_collision_data_array res = ZI;
|
||||||
res.a = arena_dry_push(arena, struct phys_collision_data);
|
res.a = arena_dry_push(arena, struct phys_collision_data);
|
||||||
u64 tick = ctx->tick;
|
struct sim_snapshot *ss = ctx->ss;
|
||||||
struct sim_ent_lookup *contact_lookup = ctx->contact_lookup;
|
struct sim_ent_lookup *contact_lookup = ctx->contact_lookup;
|
||||||
struct sim_ent_lookup *debug_lookup = ctx->debug_lookup;
|
struct sim_ent_lookup *debug_lookup = ctx->debug_lookup;
|
||||||
struct space *space = ctx->space;
|
struct space *space = ctx->space;
|
||||||
struct sim_ent_store *store = ctx->store;
|
|
||||||
struct sim_ent *root = sim_ent_from_handle(store, SIM_ENT_ROOT_HANDLE);
|
|
||||||
|
|
||||||
for (u64 check0_index = 0; check0_index < store->num_reserved; ++check0_index) {
|
struct sim_ent *root = sim_ent_from_handle(ss, SIM_ENT_ROOT_HANDLE);
|
||||||
struct sim_ent *check0 = &store->entities[check0_index];
|
u64 tick = ss->tick;
|
||||||
|
|
||||||
|
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_is_valid_and_active(check0)) continue;
|
||||||
if (!(sim_ent_has_prop(check0, SIM_ENT_PROP_PHYSICAL_DYNAMIC) || sim_ent_has_prop(check0, SIM_ENT_PROP_PHYSICAL_KINEMATIC))) continue;
|
if (!(sim_ent_has_prop(check0, SIM_ENT_PROP_PHYSICAL_DYNAMIC) || sim_ent_has_prop(check0, SIM_ENT_PROP_PHYSICAL_KINEMATIC))) continue;
|
||||||
if (check0->local_collider.count <= 0) continue;
|
if (check0->local_collider.count <= 0) continue;
|
||||||
@ -63,7 +65,7 @@ struct phys_collision_data_array phys_create_and_update_contacts(struct arena *a
|
|||||||
struct space_iter iter = space_iter_begin_aabb(space, aabb);
|
struct space_iter iter = space_iter_begin_aabb(space, aabb);
|
||||||
struct space_entry *space_entry;
|
struct space_entry *space_entry;
|
||||||
while ((space_entry = space_iter_next(&iter))) {
|
while ((space_entry = space_iter_next(&iter))) {
|
||||||
struct sim_ent *check1 = sim_ent_from_handle(store, space_entry->ent);
|
struct sim_ent *check1 = sim_ent_from_handle(ss, space_entry->ent);
|
||||||
if (check1 == check0) continue;
|
if (check1 == check0) continue;
|
||||||
if (!sim_ent_is_valid_and_active(check1)) continue;
|
if (!sim_ent_is_valid_and_active(check1)) continue;
|
||||||
if (!(sim_ent_has_prop(check1, SIM_ENT_PROP_PHYSICAL_DYNAMIC) || sim_ent_has_prop(check1, SIM_ENT_PROP_PHYSICAL_KINEMATIC))) continue;
|
if (!(sim_ent_has_prop(check1, SIM_ENT_PROP_PHYSICAL_DYNAMIC) || sim_ent_has_prop(check1, SIM_ENT_PROP_PHYSICAL_KINEMATIC))) continue;
|
||||||
@ -93,11 +95,11 @@ struct phys_collision_data_array phys_create_and_update_contacts(struct arena *a
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct sim_ent_lookup_key key = sim_ent_lookup_key_from_two_handles(e0->handle, e1->handle);
|
struct sim_ent_lookup_key key = sim_ent_lookup_key_from_two_handles(e0->handle, e1->handle);
|
||||||
struct sim_ent_lookup_entry *constraint_entry= sim_ent_lookup_get(contact_lookup, key);
|
struct sim_ent_lookup_entry *constraint_entry = sim_ent_lookup_get(contact_lookup, key);
|
||||||
|
|
||||||
struct sim_ent *constraint_ent = sim_ent_nil();
|
struct sim_ent *constraint_ent = sim_ent_nil();
|
||||||
if (constraint_entry) {
|
if (constraint_entry) {
|
||||||
constraint_ent = sim_ent_from_handle(store, constraint_entry->entity);
|
constraint_ent = sim_ent_from_handle(ss, constraint_entry->ent);
|
||||||
if (sim_ent_is_valid_and_active(constraint_ent)) {
|
if (sim_ent_is_valid_and_active(constraint_ent)) {
|
||||||
if (constraint_ent->contact_constraint_data.last_phys_iteration >= phys_iteration) {
|
if (constraint_ent->contact_constraint_data.last_phys_iteration >= phys_iteration) {
|
||||||
/* Already processed constraint this iteration */
|
/* Already processed constraint this iteration */
|
||||||
@ -236,7 +238,7 @@ struct phys_collision_data_array phys_create_and_update_contacts(struct arena *a
|
|||||||
struct sim_ent *dbg_ent = sim_ent_nil();
|
struct sim_ent *dbg_ent = sim_ent_nil();
|
||||||
struct sim_ent_lookup_entry *dbg_entry = sim_ent_lookup_get(debug_lookup, key);
|
struct sim_ent_lookup_entry *dbg_entry = sim_ent_lookup_get(debug_lookup, key);
|
||||||
if (dbg_entry) {
|
if (dbg_entry) {
|
||||||
dbg_ent = sim_ent_from_handle(store, dbg_entry->entity);
|
dbg_ent = sim_ent_from_handle(ss, dbg_entry->entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!dbg_ent->valid) {
|
if (!dbg_ent->valid) {
|
||||||
@ -282,18 +284,18 @@ void phys_prepare_contacts(struct phys_ctx *ctx, u64 phys_iteration)
|
|||||||
{
|
{
|
||||||
__prof;
|
__prof;
|
||||||
struct sim_ent_lookup *contact_lookup = ctx->contact_lookup;
|
struct sim_ent_lookup *contact_lookup = ctx->contact_lookup;
|
||||||
struct sim_ent_store *store = ctx->store;
|
struct sim_snapshot *ss = ctx->ss;
|
||||||
|
|
||||||
for (u64 sim_ent_index = 0; sim_ent_index < store->num_reserved; ++sim_ent_index) {
|
for (u64 sim_ent_index = 0; sim_ent_index < ss->num_ents_reserved; ++sim_ent_index) {
|
||||||
struct sim_ent *constraint_ent = &store->entities[sim_ent_index];
|
struct sim_ent *constraint_ent = &ss->ents[sim_ent_index];
|
||||||
if (!sim_ent_is_valid_and_active(constraint_ent)) continue;
|
if (!sim_ent_is_valid_and_active(constraint_ent)) continue;
|
||||||
if (!sim_ent_has_prop(constraint_ent, SIM_ENT_PROP_CONTACT_CONSTRAINT)) continue;
|
if (!sim_ent_has_prop(constraint_ent, SIM_ENT_PROP_CONTACT_CONSTRAINT)) continue;
|
||||||
|
|
||||||
struct phys_contact_constraint *constraint = &constraint_ent->contact_constraint_data;
|
struct phys_contact_constraint *constraint = &constraint_ent->contact_constraint_data;
|
||||||
|
|
||||||
u32 num_points = constraint->num_points;
|
u32 num_points = constraint->num_points;
|
||||||
struct sim_ent *e0 = sim_ent_from_handle(store, constraint->e0);
|
struct sim_ent *e0 = sim_ent_from_handle(ss, constraint->e0);
|
||||||
struct sim_ent *e1 = sim_ent_from_handle(store, constraint->e1);
|
struct sim_ent *e1 = sim_ent_from_handle(ss, constraint->e1);
|
||||||
if (constraint->last_phys_iteration >= phys_iteration && num_points > 0 && sim_ent_is_valid_and_active(e0) && sim_ent_is_valid_and_active(e1)) {
|
if (constraint->last_phys_iteration >= phys_iteration && num_points > 0 && sim_ent_is_valid_and_active(e0) && sim_ent_is_valid_and_active(e1)) {
|
||||||
struct v2 normal = constraint->normal;
|
struct v2 normal = constraint->normal;
|
||||||
struct v2 tangent = v2_perp(normal);
|
struct v2 tangent = v2_perp(normal);
|
||||||
@ -375,14 +377,14 @@ void phys_prepare_contacts(struct phys_ctx *ctx, u64 phys_iteration)
|
|||||||
|
|
||||||
#if COLLIDER_DEBUG
|
#if COLLIDER_DEBUG
|
||||||
struct sim_ent_lookup *debug_lookup = ctx->debug_lookup;
|
struct sim_ent_lookup *debug_lookup = ctx->debug_lookup;
|
||||||
for (u64 sim_ent_index = 0; sim_ent_index < store->num_reserved; ++sim_ent_index) {
|
for (u64 sim_ent_index = 0; sim_ent_index < ss->num_ents_reserved; ++sim_ent_index) {
|
||||||
struct sim_ent *dbg_ent = &store->entities[sim_ent_index];
|
struct sim_ent *dbg_ent = &ss->ents[sim_ent_index];
|
||||||
if (!sim_ent_is_valid_and_active(dbg_ent)) continue;
|
if (!sim_ent_is_valid_and_active(dbg_ent)) continue;
|
||||||
if (!sim_ent_has_prop(dbg_ent, SIM_ENT_PROP_COLLISION_DEBUG)) continue;
|
if (!sim_ent_has_prop(dbg_ent, SIM_ENT_PROP_COLLISION_DEBUG)) continue;
|
||||||
|
|
||||||
struct phys_collision_debug *dbg = &dbg_ent->collision_debug_data;
|
struct phys_collision_debug *dbg = &dbg_ent->collision_debug_data;
|
||||||
struct sim_ent *e0 = sim_ent_from_handle(store, dbg->e0);
|
struct sim_ent *e0 = sim_ent_from_handle(ss, dbg->e0);
|
||||||
struct sim_ent *e1 = sim_ent_from_handle(store, dbg->e1);
|
struct sim_ent *e1 = sim_ent_from_handle(ss, dbg->e1);
|
||||||
|
|
||||||
|
|
||||||
if (!sim_ent_is_valid_and_active(e0) || !sim_ent_is_valid_and_active(e1)
|
if (!sim_ent_is_valid_and_active(e0) || !sim_ent_is_valid_and_active(e1)
|
||||||
@ -409,17 +411,17 @@ void phys_prepare_contacts(struct phys_ctx *ctx, u64 phys_iteration)
|
|||||||
void phys_warm_start_contacts(struct phys_ctx *ctx)
|
void phys_warm_start_contacts(struct phys_ctx *ctx)
|
||||||
{
|
{
|
||||||
__prof;
|
__prof;
|
||||||
struct sim_ent_store *store = ctx->store;
|
struct sim_snapshot *ss = ctx->ss;
|
||||||
for (u64 sim_ent_index = 0; sim_ent_index < store->num_reserved; ++sim_ent_index) {
|
for (u64 sim_ent_index = 0; sim_ent_index < ss->num_ents_reserved; ++sim_ent_index) {
|
||||||
struct sim_ent *constraint_ent = &store->entities[sim_ent_index];
|
struct sim_ent *constraint_ent = &ss->ents[sim_ent_index];
|
||||||
if (!sim_ent_is_valid_and_active(constraint_ent)) continue;
|
if (!sim_ent_is_valid_and_active(constraint_ent)) continue;
|
||||||
if (!sim_ent_has_prop(constraint_ent, SIM_ENT_PROP_CONTACT_CONSTRAINT)) continue;
|
if (!sim_ent_has_prop(constraint_ent, SIM_ENT_PROP_CONTACT_CONSTRAINT)) continue;
|
||||||
|
|
||||||
struct phys_contact_constraint *constraint = &constraint_ent->contact_constraint_data;
|
struct phys_contact_constraint *constraint = &constraint_ent->contact_constraint_data;
|
||||||
|
|
||||||
u32 num_points = constraint->num_points;
|
u32 num_points = constraint->num_points;
|
||||||
struct sim_ent *e0 = sim_ent_from_handle(store, constraint->e0);
|
struct sim_ent *e0 = sim_ent_from_handle(ss, constraint->e0);
|
||||||
struct sim_ent *e1 = sim_ent_from_handle(store, constraint->e1);
|
struct sim_ent *e1 = sim_ent_from_handle(ss, constraint->e1);
|
||||||
|
|
||||||
if (num_points > 0 && sim_ent_is_valid_and_active(e0) && sim_ent_is_valid_and_active(e1) && !constraint->skip_solve) {
|
if (num_points > 0 && sim_ent_is_valid_and_active(e0) && sim_ent_is_valid_and_active(e1) && !constraint->skip_solve) {
|
||||||
struct xform e0_xf = sim_ent_get_xform(e0);
|
struct xform e0_xf = sim_ent_get_xform(e0);
|
||||||
@ -464,16 +466,16 @@ void phys_warm_start_contacts(struct phys_ctx *ctx)
|
|||||||
void phys_solve_contacts(struct phys_ctx *ctx, f32 dt, b32 apply_bias)
|
void phys_solve_contacts(struct phys_ctx *ctx, f32 dt, b32 apply_bias)
|
||||||
{
|
{
|
||||||
__prof;
|
__prof;
|
||||||
struct sim_ent_store *store = ctx->store;
|
struct sim_snapshot *ss = ctx->ss;
|
||||||
for (u64 sim_ent_index = 0; sim_ent_index < store->num_reserved; ++sim_ent_index) {
|
for (u64 sim_ent_index = 0; sim_ent_index < ss->num_ents_reserved; ++sim_ent_index) {
|
||||||
struct sim_ent *constraint_ent = &store->entities[sim_ent_index];
|
struct sim_ent *constraint_ent = &ss->ents[sim_ent_index];
|
||||||
if (!sim_ent_is_valid_and_active(constraint_ent)) continue;
|
if (!sim_ent_is_valid_and_active(constraint_ent)) continue;
|
||||||
if (!sim_ent_has_prop(constraint_ent, SIM_ENT_PROP_CONTACT_CONSTRAINT)) continue;
|
if (!sim_ent_has_prop(constraint_ent, SIM_ENT_PROP_CONTACT_CONSTRAINT)) continue;
|
||||||
|
|
||||||
struct phys_contact_constraint *constraint = &constraint_ent->contact_constraint_data;
|
struct phys_contact_constraint *constraint = &constraint_ent->contact_constraint_data;
|
||||||
|
|
||||||
struct sim_ent *e0 = sim_ent_from_handle(store, constraint->e0);
|
struct sim_ent *e0 = sim_ent_from_handle(ss, constraint->e0);
|
||||||
struct sim_ent *e1 = sim_ent_from_handle(store, constraint->e1);
|
struct sim_ent *e1 = sim_ent_from_handle(ss, constraint->e1);
|
||||||
|
|
||||||
struct v2 v0 = e0->linear_velocity;
|
struct v2 v0 = e0->linear_velocity;
|
||||||
struct v2 v1 = e1->linear_velocity;
|
struct v2 v1 = e1->linear_velocity;
|
||||||
@ -595,16 +597,16 @@ struct phys_motor_joint phys_motor_joint_from_def(struct phys_motor_joint_def de
|
|||||||
void phys_prepare_motor_joints(struct phys_ctx *ctx)
|
void phys_prepare_motor_joints(struct phys_ctx *ctx)
|
||||||
{
|
{
|
||||||
__prof;
|
__prof;
|
||||||
struct sim_ent_store *store = ctx->store;
|
struct sim_snapshot *ss = ctx->ss;
|
||||||
for (u64 sim_ent_index = 0; sim_ent_index < store->num_reserved; ++sim_ent_index) {
|
for (u64 sim_ent_index = 0; sim_ent_index < ss->num_ents_reserved; ++sim_ent_index) {
|
||||||
struct sim_ent *joint_ent = &store->entities[sim_ent_index];
|
struct sim_ent *joint_ent = &ss->ents[sim_ent_index];
|
||||||
if (!sim_ent_is_valid_and_active(joint_ent)) continue;
|
if (!sim_ent_is_valid_and_active(joint_ent)) continue;
|
||||||
if (!sim_ent_has_prop(joint_ent, SIM_ENT_PROP_MOTOR_JOINT)) continue;
|
if (!sim_ent_has_prop(joint_ent, SIM_ENT_PROP_MOTOR_JOINT)) continue;
|
||||||
|
|
||||||
struct phys_motor_joint *joint = &joint_ent->motor_joint_data;
|
struct phys_motor_joint *joint = &joint_ent->motor_joint_data;
|
||||||
|
|
||||||
struct sim_ent *e0 = sim_ent_from_handle(store, joint->e0);
|
struct sim_ent *e0 = sim_ent_from_handle(ss, joint->e0);
|
||||||
struct sim_ent *e1 = sim_ent_from_handle(store, joint->e1);
|
struct sim_ent *e1 = sim_ent_from_handle(ss, joint->e1);
|
||||||
|
|
||||||
if (sim_ent_is_valid_and_active(e0) && sim_ent_is_valid_and_active(e1)) {
|
if (sim_ent_is_valid_and_active(e0) && sim_ent_is_valid_and_active(e1)) {
|
||||||
struct xform e0_xf = sim_ent_get_xform(e0);
|
struct xform e0_xf = sim_ent_get_xform(e0);
|
||||||
@ -659,16 +661,16 @@ void phys_prepare_motor_joints(struct phys_ctx *ctx)
|
|||||||
void phys_warm_start_motor_joints(struct phys_ctx *ctx)
|
void phys_warm_start_motor_joints(struct phys_ctx *ctx)
|
||||||
{
|
{
|
||||||
__prof;
|
__prof;
|
||||||
struct sim_ent_store *store = ctx->store;
|
struct sim_snapshot *ss = ctx->ss;
|
||||||
for (u64 sim_ent_index = 0; sim_ent_index < store->num_reserved; ++sim_ent_index) {
|
for (u64 sim_ent_index = 0; sim_ent_index < ss->num_ents_reserved; ++sim_ent_index) {
|
||||||
struct sim_ent *joint_ent = &store->entities[sim_ent_index];
|
struct sim_ent *joint_ent = &ss->ents[sim_ent_index];
|
||||||
if (!sim_ent_is_valid_and_active(joint_ent)) continue;
|
if (!sim_ent_is_valid_and_active(joint_ent)) continue;
|
||||||
if (!sim_ent_has_prop(joint_ent, SIM_ENT_PROP_MOTOR_JOINT)) continue;
|
if (!sim_ent_has_prop(joint_ent, SIM_ENT_PROP_MOTOR_JOINT)) continue;
|
||||||
|
|
||||||
struct phys_motor_joint *joint = &joint_ent->motor_joint_data;
|
struct phys_motor_joint *joint = &joint_ent->motor_joint_data;
|
||||||
|
|
||||||
struct sim_ent *e0 = sim_ent_from_handle(store, joint->e0);
|
struct sim_ent *e0 = sim_ent_from_handle(ss, joint->e0);
|
||||||
struct sim_ent *e1 = sim_ent_from_handle(store, joint->e1);
|
struct sim_ent *e1 = sim_ent_from_handle(ss, joint->e1);
|
||||||
|
|
||||||
struct xform e0_xf = sim_ent_get_xform(e0);
|
struct xform e0_xf = sim_ent_get_xform(e0);
|
||||||
struct xform e1_xf = sim_ent_get_xform(e1);
|
struct xform e1_xf = sim_ent_get_xform(e1);
|
||||||
@ -691,16 +693,16 @@ void phys_warm_start_motor_joints(struct phys_ctx *ctx)
|
|||||||
void phys_solve_motor_joints(struct phys_ctx *ctx, f32 dt)
|
void phys_solve_motor_joints(struct phys_ctx *ctx, f32 dt)
|
||||||
{
|
{
|
||||||
__prof;
|
__prof;
|
||||||
struct sim_ent_store *store = ctx->store;
|
struct sim_snapshot *ss = ctx->ss;
|
||||||
for (u64 sim_ent_index = 0; sim_ent_index < store->num_reserved; ++sim_ent_index) {
|
for (u64 sim_ent_index = 0; sim_ent_index < ss->num_ents_reserved; ++sim_ent_index) {
|
||||||
struct sim_ent *joint_ent = &store->entities[sim_ent_index];
|
struct sim_ent *joint_ent = &ss->ents[sim_ent_index];
|
||||||
if (!sim_ent_is_valid_and_active(joint_ent)) continue;
|
if (!sim_ent_is_valid_and_active(joint_ent)) continue;
|
||||||
if (!sim_ent_has_prop(joint_ent, SIM_ENT_PROP_MOTOR_JOINT)) continue;
|
if (!sim_ent_has_prop(joint_ent, SIM_ENT_PROP_MOTOR_JOINT)) continue;
|
||||||
|
|
||||||
struct phys_motor_joint *joint = &joint_ent->motor_joint_data;
|
struct phys_motor_joint *joint = &joint_ent->motor_joint_data;
|
||||||
|
|
||||||
struct sim_ent *e0 = sim_ent_from_handle(store, joint->e0);
|
struct sim_ent *e0 = sim_ent_from_handle(ss, joint->e0);
|
||||||
struct sim_ent *e1 = sim_ent_from_handle(store, joint->e1);
|
struct sim_ent *e1 = sim_ent_from_handle(ss, joint->e1);
|
||||||
|
|
||||||
struct xform e0_xf = sim_ent_get_xform(e0);
|
struct xform e0_xf = sim_ent_get_xform(e0);
|
||||||
struct xform e1_xf = sim_ent_get_xform(e1);
|
struct xform e1_xf = sim_ent_get_xform(e1);
|
||||||
@ -784,14 +786,14 @@ struct phys_mouse_joint phys_mouse_joint_from_def(struct phys_mouse_joint_def de
|
|||||||
void phys_prepare_mouse_joints(struct phys_ctx *ctx)
|
void phys_prepare_mouse_joints(struct phys_ctx *ctx)
|
||||||
{
|
{
|
||||||
__prof;
|
__prof;
|
||||||
struct sim_ent_store *store = ctx->store;
|
struct sim_snapshot *ss = ctx->ss;
|
||||||
for (u64 sim_ent_index = 0; sim_ent_index < store->num_reserved; ++sim_ent_index) {
|
for (u64 sim_ent_index = 0; sim_ent_index < ss->num_ents_reserved; ++sim_ent_index) {
|
||||||
struct sim_ent *joint_ent = &store->entities[sim_ent_index];
|
struct sim_ent *joint_ent = &ss->ents[sim_ent_index];
|
||||||
if (!sim_ent_is_valid_and_active(joint_ent)) continue;
|
if (!sim_ent_is_valid_and_active(joint_ent)) continue;
|
||||||
if (!sim_ent_has_prop(joint_ent, SIM_ENT_PROP_MOUSE_JOINT)) continue;
|
if (!sim_ent_has_prop(joint_ent, SIM_ENT_PROP_MOUSE_JOINT)) continue;
|
||||||
|
|
||||||
struct phys_mouse_joint *joint = &joint_ent->mouse_joint_data;
|
struct phys_mouse_joint *joint = &joint_ent->mouse_joint_data;
|
||||||
struct sim_ent *ent = sim_ent_from_handle(store, joint->target);
|
struct sim_ent *ent = sim_ent_from_handle(ss, joint->target);
|
||||||
if (sim_ent_is_valid_and_active(ent)) {
|
if (sim_ent_is_valid_and_active(ent)) {
|
||||||
struct xform xf = sim_ent_get_xform(ent);
|
struct xform xf = sim_ent_get_xform(ent);
|
||||||
|
|
||||||
@ -831,14 +833,14 @@ void phys_prepare_mouse_joints(struct phys_ctx *ctx)
|
|||||||
void phys_warm_start_mouse_joints(struct phys_ctx *ctx)
|
void phys_warm_start_mouse_joints(struct phys_ctx *ctx)
|
||||||
{
|
{
|
||||||
__prof;
|
__prof;
|
||||||
struct sim_ent_store *store = ctx->store;
|
struct sim_snapshot *ss = ctx->ss;
|
||||||
for (u64 sim_ent_index = 0; sim_ent_index < store->num_reserved; ++sim_ent_index) {
|
for (u64 sim_ent_index = 0; sim_ent_index < ss->num_ents_reserved; ++sim_ent_index) {
|
||||||
struct sim_ent *joint_ent = &store->entities[sim_ent_index];
|
struct sim_ent *joint_ent = &ss->ents[sim_ent_index];
|
||||||
if (!sim_ent_is_valid_and_active(joint_ent)) continue;
|
if (!sim_ent_is_valid_and_active(joint_ent)) continue;
|
||||||
if (!sim_ent_has_prop(joint_ent, SIM_ENT_PROP_MOUSE_JOINT)) continue;
|
if (!sim_ent_has_prop(joint_ent, SIM_ENT_PROP_MOUSE_JOINT)) continue;
|
||||||
|
|
||||||
struct phys_mouse_joint *joint = &joint_ent->mouse_joint_data;
|
struct phys_mouse_joint *joint = &joint_ent->mouse_joint_data;
|
||||||
struct sim_ent *ent = sim_ent_from_handle(store, joint->target);
|
struct sim_ent *ent = sim_ent_from_handle(ss, joint->target);
|
||||||
if (sim_ent_is_valid_and_active(ent)) {
|
if (sim_ent_is_valid_and_active(ent)) {
|
||||||
f32 inv_m = joint->inv_m;
|
f32 inv_m = joint->inv_m;
|
||||||
f32 inv_i = joint->inv_i;
|
f32 inv_i = joint->inv_i;
|
||||||
@ -853,14 +855,14 @@ void phys_warm_start_mouse_joints(struct phys_ctx *ctx)
|
|||||||
void phys_solve_mouse_joints(struct phys_ctx *ctx, f32 dt)
|
void phys_solve_mouse_joints(struct phys_ctx *ctx, f32 dt)
|
||||||
{
|
{
|
||||||
__prof;
|
__prof;
|
||||||
struct sim_ent_store *store = ctx->store;
|
struct sim_snapshot *ss = ctx->ss;
|
||||||
for (u64 sim_ent_index = 0; sim_ent_index < store->num_reserved; ++sim_ent_index) {
|
for (u64 sim_ent_index = 0; sim_ent_index < ss->num_ents_reserved; ++sim_ent_index) {
|
||||||
struct sim_ent *joint_ent = &store->entities[sim_ent_index];
|
struct sim_ent *joint_ent = &ss->ents[sim_ent_index];
|
||||||
if (!sim_ent_is_valid_and_active(joint_ent)) continue;
|
if (!sim_ent_is_valid_and_active(joint_ent)) continue;
|
||||||
if (!sim_ent_has_prop(joint_ent, SIM_ENT_PROP_MOUSE_JOINT)) continue;
|
if (!sim_ent_has_prop(joint_ent, SIM_ENT_PROP_MOUSE_JOINT)) continue;
|
||||||
|
|
||||||
struct phys_mouse_joint *joint = &joint_ent->mouse_joint_data;
|
struct phys_mouse_joint *joint = &joint_ent->mouse_joint_data;
|
||||||
struct sim_ent *ent = sim_ent_from_handle(store, joint->target);
|
struct sim_ent *ent = sim_ent_from_handle(ss, joint->target);
|
||||||
if (sim_ent_is_valid_and_active(ent)) {
|
if (sim_ent_is_valid_and_active(ent)) {
|
||||||
struct v2 v = ent->linear_velocity;
|
struct v2 v = ent->linear_velocity;
|
||||||
f32 w = ent->angular_velocity;
|
f32 w = ent->angular_velocity;
|
||||||
@ -940,9 +942,9 @@ INTERNAL struct xform get_derived_xform(struct sim_ent *ent, f32 dt)
|
|||||||
void phys_integrate_forces(struct phys_ctx *ctx, f32 dt)
|
void phys_integrate_forces(struct phys_ctx *ctx, f32 dt)
|
||||||
{
|
{
|
||||||
__prof;
|
__prof;
|
||||||
struct sim_ent_store *store = ctx->store;
|
struct sim_snapshot *ss = ctx->ss;
|
||||||
for (u64 sim_ent_index = 0; sim_ent_index < store->num_reserved; ++sim_ent_index) {
|
for (u64 sim_ent_index = 0; sim_ent_index < ss->num_ents_reserved; ++sim_ent_index) {
|
||||||
struct sim_ent *ent = &store->entities[sim_ent_index];
|
struct sim_ent *ent = &ss->ents[sim_ent_index];
|
||||||
if (!sim_ent_is_valid_and_active(ent)) continue;
|
if (!sim_ent_is_valid_and_active(ent)) continue;
|
||||||
|
|
||||||
b32 is_dynamic = sim_ent_has_prop(ent, SIM_ENT_PROP_PHYSICAL_DYNAMIC);
|
b32 is_dynamic = sim_ent_has_prop(ent, SIM_ENT_PROP_PHYSICAL_DYNAMIC);
|
||||||
@ -982,9 +984,9 @@ void phys_integrate_forces(struct phys_ctx *ctx, f32 dt)
|
|||||||
void phys_integrate_velocities(struct phys_ctx *ctx, f32 dt)
|
void phys_integrate_velocities(struct phys_ctx *ctx, f32 dt)
|
||||||
{
|
{
|
||||||
__prof;
|
__prof;
|
||||||
struct sim_ent_store *store = ctx->store;
|
struct sim_snapshot *ss = ctx->ss;
|
||||||
for (u64 sim_ent_index = 0; sim_ent_index < store->num_reserved; ++sim_ent_index) {
|
for (u64 sim_ent_index = 0; sim_ent_index < ss->num_ents_reserved; ++sim_ent_index) {
|
||||||
struct sim_ent *ent = &store->entities[sim_ent_index];
|
struct sim_ent *ent = &ss->ents[sim_ent_index];
|
||||||
if (!sim_ent_is_valid_and_active(ent)) continue;
|
if (!sim_ent_is_valid_and_active(ent)) continue;
|
||||||
if (!sim_ent_has_prop(ent, SIM_ENT_PROP_PHYSICAL_DYNAMIC) && !sim_ent_has_prop(ent, SIM_ENT_PROP_PHYSICAL_KINEMATIC)) continue;
|
if (!sim_ent_has_prop(ent, SIM_ENT_PROP_PHYSICAL_DYNAMIC) && !sim_ent_has_prop(ent, SIM_ENT_PROP_PHYSICAL_KINEMATIC)) continue;
|
||||||
|
|
||||||
@ -1005,12 +1007,12 @@ void phys_integrate_velocities(struct phys_ctx *ctx, f32 dt)
|
|||||||
f32 phys_determine_earliest_toi_for_bullets(struct phys_ctx *ctx, f32 step_dt, f32 tolerance, u32 max_iterations)
|
f32 phys_determine_earliest_toi_for_bullets(struct phys_ctx *ctx, f32 step_dt, f32 tolerance, u32 max_iterations)
|
||||||
{
|
{
|
||||||
__prof;
|
__prof;
|
||||||
struct sim_ent_store *store = ctx->store;
|
struct sim_snapshot *ss = ctx->ss;
|
||||||
struct space *space = ctx->space;
|
struct space *space = ctx->space;
|
||||||
f32 smallest_t = 1;
|
f32 smallest_t = 1;
|
||||||
|
|
||||||
for (u64 e0_index = 0; e0_index < store->num_reserved; ++e0_index) {
|
for (u64 e0_index = 0; e0_index < ss->num_ents_reserved; ++e0_index) {
|
||||||
struct sim_ent *e0 = &store->entities[e0_index];
|
struct sim_ent *e0 = &ss->ents[e0_index];
|
||||||
if (!sim_ent_is_valid_and_active(e0)) continue;
|
if (!sim_ent_is_valid_and_active(e0)) continue;
|
||||||
if (!(sim_ent_has_prop(e0, SIM_ENT_PROP_PHYSICAL_DYNAMIC) || sim_ent_has_prop(e0, SIM_ENT_PROP_PHYSICAL_KINEMATIC))) continue;
|
if (!(sim_ent_has_prop(e0, SIM_ENT_PROP_PHYSICAL_DYNAMIC) || sim_ent_has_prop(e0, SIM_ENT_PROP_PHYSICAL_KINEMATIC))) continue;
|
||||||
if (!sim_ent_has_prop(e0, SIM_ENT_PROP_BULLET)) continue;
|
if (!sim_ent_has_prop(e0, SIM_ENT_PROP_BULLET)) continue;
|
||||||
@ -1028,7 +1030,7 @@ f32 phys_determine_earliest_toi_for_bullets(struct phys_ctx *ctx, f32 step_dt, f
|
|||||||
struct space_iter iter = space_iter_begin_aabb(space, combined_aabb);
|
struct space_iter iter = space_iter_begin_aabb(space, combined_aabb);
|
||||||
struct space_entry *entry;
|
struct space_entry *entry;
|
||||||
while ((entry = space_iter_next(&iter))) {
|
while ((entry = space_iter_next(&iter))) {
|
||||||
struct sim_ent *e1 = sim_ent_from_handle(store, entry->ent);
|
struct sim_ent *e1 = sim_ent_from_handle(ss, entry->ent);
|
||||||
if (e1 == e0) continue;
|
if (e1 == e0) continue;
|
||||||
if (!sim_ent_is_valid_and_active(e1)) continue;
|
if (!sim_ent_is_valid_and_active(e1)) continue;
|
||||||
if (!(sim_ent_has_prop(e1, SIM_ENT_PROP_PHYSICAL_DYNAMIC) || sim_ent_has_prop(e1, SIM_ENT_PROP_PHYSICAL_KINEMATIC))) continue;
|
if (!(sim_ent_has_prop(e1, SIM_ENT_PROP_PHYSICAL_DYNAMIC) || sim_ent_has_prop(e1, SIM_ENT_PROP_PHYSICAL_KINEMATIC))) continue;
|
||||||
@ -1055,9 +1057,9 @@ f32 phys_determine_earliest_toi_for_bullets(struct phys_ctx *ctx, f32 step_dt, f
|
|||||||
|
|
||||||
void phys_update_aabbs(struct phys_ctx *ctx)
|
void phys_update_aabbs(struct phys_ctx *ctx)
|
||||||
{
|
{
|
||||||
struct sim_ent_store *store = ctx->store;
|
struct sim_snapshot *ss = ctx->ss;
|
||||||
for (u64 sim_ent_index = 0; sim_ent_index < store->num_reserved; ++sim_ent_index) {
|
for (u64 sim_ent_index = 0; sim_ent_index < ss->num_ents_reserved; ++sim_ent_index) {
|
||||||
struct sim_ent *ent = &store->entities[sim_ent_index];
|
struct sim_ent *ent = &ss->ents[sim_ent_index];
|
||||||
if (!sim_ent_is_valid_and_active(ent)) continue;
|
if (!sim_ent_is_valid_and_active(ent)) continue;
|
||||||
if (ent->local_collider.count <= 0) continue;
|
if (ent->local_collider.count <= 0) continue;
|
||||||
|
|
||||||
@ -1075,11 +1077,12 @@ void phys_update_aabbs(struct phys_ctx *ctx)
|
|||||||
* Step
|
* Step
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
u64 phys_step(struct phys_ctx *ctx, f32 timestep, u64 last_phys_iteration)
|
/* Returns phys iteration to be fed into next step. Supplied iteration must be > 0. */
|
||||||
|
u64 phys_step(struct phys_ctx *ctx, f32 timestep, u64 last_iteration)
|
||||||
{
|
{
|
||||||
__prof;
|
__prof;
|
||||||
phys_integrate_forces(ctx, timestep);
|
phys_integrate_forces(ctx, timestep);
|
||||||
u64 phys_iteration = last_phys_iteration;
|
u64 phys_iteration = last_iteration;
|
||||||
|
|
||||||
f32 remaining_dt = timestep;
|
f32 remaining_dt = timestep;
|
||||||
while (remaining_dt > 0) {
|
while (remaining_dt > 0) {
|
||||||
|
|||||||
@ -5,7 +5,6 @@
|
|||||||
#include "math.h"
|
#include "math.h"
|
||||||
|
|
||||||
struct space;
|
struct space;
|
||||||
struct sim_ent_store;
|
|
||||||
struct sim_ent_lookup;
|
struct sim_ent_lookup;
|
||||||
|
|
||||||
struct phys_contact_constraint;
|
struct phys_contact_constraint;
|
||||||
@ -30,9 +29,8 @@ typedef PHYS_COLLISION_CALLBACK_FUNC_DEF(phys_collision_callback_func, collision
|
|||||||
|
|
||||||
/* Structure containing data used for a single physics step */
|
/* Structure containing data used for a single physics step */
|
||||||
struct phys_ctx {
|
struct phys_ctx {
|
||||||
u64 tick;
|
struct sim_snapshot *ss;
|
||||||
struct space *space;
|
struct space *space;
|
||||||
struct sim_ent_store *store;
|
|
||||||
struct sim_ent_lookup *contact_lookup;
|
struct sim_ent_lookup *contact_lookup;
|
||||||
|
|
||||||
phys_collision_callback_func *pre_solve_callback;
|
phys_collision_callback_func *pre_solve_callback;
|
||||||
@ -210,7 +208,6 @@ void phys_update_aabbs(struct phys_ctx *ctx);
|
|||||||
* Step
|
* Step
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
/* Returns phys iteration to be fed into next step. Supplied iteration must be > 0. */
|
|
||||||
u64 phys_step(struct phys_ctx *ctx, f32 timestep, u64 phys_iteration);
|
u64 phys_step(struct phys_ctx *ctx, f32 timestep, u64 phys_iteration);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
126
src/sim.c
126
src/sim.c
@ -26,7 +26,6 @@
|
|||||||
struct sim_ctx *sim_ctx_alloc(struct sprite_startup_receipt *sprite_sr,
|
struct sim_ctx *sim_ctx_alloc(struct sprite_startup_receipt *sprite_sr,
|
||||||
struct phys_startup_receipt *phys_sr,
|
struct phys_startup_receipt *phys_sr,
|
||||||
struct host_startup_receipt *host_sr,
|
struct host_startup_receipt *host_sr,
|
||||||
struct sim_ent_startup_receipt *sim_ent_sr,
|
|
||||||
struct sim_snapshot_startup_receipt *sim_snapshot_sr,
|
struct sim_snapshot_startup_receipt *sim_snapshot_sr,
|
||||||
u16 host_port)
|
u16 host_port)
|
||||||
{
|
{
|
||||||
@ -37,7 +36,6 @@ struct sim_ctx *sim_ctx_alloc(struct sprite_startup_receipt *sprite_sr,
|
|||||||
(UNUSED)sprite_sr;
|
(UNUSED)sprite_sr;
|
||||||
(UNUSED)phys_sr;
|
(UNUSED)phys_sr;
|
||||||
(UNUSED)host_sr;
|
(UNUSED)host_sr;
|
||||||
(UNUSED)sim_ent_sr;
|
|
||||||
(UNUSED)sim_snapshot_sr;
|
(UNUSED)sim_snapshot_sr;
|
||||||
|
|
||||||
/* Intialize host */
|
/* Intialize host */
|
||||||
@ -83,7 +81,7 @@ void sim_ctx_release(struct sim_ctx *ctx)
|
|||||||
|
|
||||||
INTERNAL void spawn_test_entities(struct sim_ctx *ctx)
|
INTERNAL void spawn_test_entities(struct sim_ctx *ctx)
|
||||||
{
|
{
|
||||||
struct sim_ent *root = sim_ent_from_handle(ctx->world->ent_store, SIM_ENT_ROOT_HANDLE);
|
struct sim_ent *root = sim_ent_from_handle(ctx->world, SIM_ENT_ROOT_HANDLE);
|
||||||
root->mass_unscaled = F32_INFINITY;
|
root->mass_unscaled = F32_INFINITY;
|
||||||
root->inertia_unscaled = F32_INFINITY;
|
root->inertia_unscaled = F32_INFINITY;
|
||||||
|
|
||||||
@ -156,8 +154,7 @@ INTERNAL void spawn_test_entities(struct sim_ctx *ctx)
|
|||||||
|
|
||||||
INTERNAL struct sim_ent *spawn_test_player(struct sim_ctx *ctx)
|
INTERNAL struct sim_ent *spawn_test_player(struct sim_ctx *ctx)
|
||||||
{
|
{
|
||||||
struct sim_ent_store *store = ctx->world->ent_store;
|
struct sim_ent *root = sim_ent_from_handle(ctx->world, SIM_ENT_ROOT_HANDLE);
|
||||||
struct sim_ent *root = sim_ent_from_handle(store, SIM_ENT_ROOT_HANDLE);
|
|
||||||
|
|
||||||
/* Player */
|
/* Player */
|
||||||
struct sim_ent *player_ent = sim_ent_nil();
|
struct sim_ent *player_ent = sim_ent_nil();
|
||||||
@ -233,8 +230,7 @@ INTERNAL struct sim_ent *spawn_test_player(struct sim_ctx *ctx)
|
|||||||
|
|
||||||
INTERNAL struct sim_ent *spawn_test_player_camera(struct sim_ctx *ctx, struct sim_ent *player_ent)
|
INTERNAL struct sim_ent *spawn_test_player_camera(struct sim_ctx *ctx, struct sim_ent *player_ent)
|
||||||
{
|
{
|
||||||
struct sim_ent_store *store = ctx->world->ent_store;
|
struct sim_ent *root = sim_ent_from_handle(ctx->world, SIM_ENT_ROOT_HANDLE);
|
||||||
struct sim_ent *root = sim_ent_from_handle(store, SIM_ENT_ROOT_HANDLE);
|
|
||||||
|
|
||||||
struct sim_ent *camera_ent = sim_ent_nil();
|
struct sim_ent *camera_ent = sim_ent_nil();
|
||||||
if (player_ent->valid) {
|
if (player_ent->valid) {
|
||||||
@ -260,13 +256,12 @@ INTERNAL struct sim_ent *spawn_test_player_camera(struct sim_ctx *ctx, struct si
|
|||||||
INTERNAL void release_entities_with_prop(struct sim_ctx *ctx, enum sim_ent_prop prop)
|
INTERNAL void release_entities_with_prop(struct sim_ctx *ctx, enum sim_ent_prop prop)
|
||||||
{
|
{
|
||||||
struct temp_arena scratch = scratch_begin_no_conflict();
|
struct temp_arena scratch = scratch_begin_no_conflict();
|
||||||
struct sim_ent_store *store = ctx->world->ent_store;
|
|
||||||
struct space *space = ctx->space;
|
struct space *space = ctx->space;
|
||||||
|
|
||||||
struct sim_ent **ents_to_release = arena_dry_push(scratch.arena, struct sim_ent *);
|
struct sim_ent **ents_to_release = arena_dry_push(scratch.arena, struct sim_ent *);
|
||||||
u64 ents_to_release_count = 0;
|
u64 ents_to_release_count = 0;
|
||||||
for (u64 ent_index = 0; ent_index < store->num_reserved; ++ent_index) {
|
for (u64 ent_index = 0; ent_index < ctx->world->num_ents_reserved; ++ent_index) {
|
||||||
struct sim_ent *ent = &store->entities[ent_index];
|
struct sim_ent *ent = &ctx->world->ents[ent_index];
|
||||||
if (!ent->valid) continue;
|
if (!ent->valid) continue;
|
||||||
|
|
||||||
if (sim_ent_has_prop(ent, prop)) {
|
if (sim_ent_has_prop(ent, prop)) {
|
||||||
@ -293,7 +288,7 @@ INTERNAL void release_entities_with_prop(struct sim_ctx *ctx, enum sim_ent_prop
|
|||||||
for (u64 i = 0; i < ents_to_release_count; ++i) {
|
for (u64 i = 0; i < ents_to_release_count; ++i) {
|
||||||
struct sim_ent *ent = ents_to_release[i];
|
struct sim_ent *ent = ents_to_release[i];
|
||||||
if (ent->valid) {
|
if (ent->valid) {
|
||||||
sim_ent_release(store, ent);
|
sim_ent_release(ctx->world, ent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -307,15 +302,14 @@ INTERNAL void release_entities_with_prop(struct sim_ctx *ctx, enum sim_ent_prop
|
|||||||
INTERNAL PHYS_COLLISION_CALLBACK_FUNC_DEF(on_collision, collision_data_array, udata)
|
INTERNAL PHYS_COLLISION_CALLBACK_FUNC_DEF(on_collision, collision_data_array, udata)
|
||||||
{
|
{
|
||||||
struct sim_ctx *ctx = (struct sim_ctx *)udata;
|
struct sim_ctx *ctx = (struct sim_ctx *)udata;
|
||||||
struct sim_ent_store *store = ctx->world->ent_store;
|
struct sim_ent *root = sim_ent_from_handle(ctx->world, SIM_ENT_ROOT_HANDLE);
|
||||||
struct sim_ent *root = sim_ent_from_handle(store, SIM_ENT_ROOT_HANDLE);
|
|
||||||
|
|
||||||
for (u64 i = 0; i < collision_data_array.count; ++i) {
|
for (u64 i = 0; i < collision_data_array.count; ++i) {
|
||||||
struct phys_collision_data *data = &collision_data_array.a[i];
|
struct phys_collision_data *data = &collision_data_array.a[i];
|
||||||
|
|
||||||
struct phys_contact_constraint *constraint = data->constraint;
|
struct phys_contact_constraint *constraint = data->constraint;
|
||||||
struct sim_ent *e0 = sim_ent_from_handle(store, data->e0);
|
struct sim_ent *e0 = sim_ent_from_handle(ctx->world, data->e0);
|
||||||
struct sim_ent *e1 = sim_ent_from_handle(store, data->e1);
|
struct sim_ent *e1 = sim_ent_from_handle(ctx->world, data->e1);
|
||||||
|
|
||||||
if (sim_ent_is_valid_and_active(e0) && sim_ent_is_valid_and_active(e1)) {
|
if (sim_ent_is_valid_and_active(e0) && sim_ent_is_valid_and_active(e1)) {
|
||||||
/* Bullet hit entity */
|
/* Bullet hit entity */
|
||||||
@ -331,7 +325,7 @@ INTERNAL PHYS_COLLISION_CALLBACK_FUNC_DEF(on_collision, collision_data_array, ud
|
|||||||
normal = v2_neg(normal);
|
normal = v2_neg(normal);
|
||||||
vrel = v2_neg(vrel);
|
vrel = v2_neg(vrel);
|
||||||
}
|
}
|
||||||
struct sim_ent *src = sim_ent_from_handle(store, bullet->bullet_src);
|
struct sim_ent *src = sim_ent_from_handle(ctx->world, bullet->bullet_src);
|
||||||
|
|
||||||
if (bullet->bullet_has_hit || sim_ent_handle_eq(src->top, target->top)) {
|
if (bullet->bullet_has_hit || sim_ent_handle_eq(src->top, target->top)) {
|
||||||
/* Ignore collision if bullet already spent or if weapon and
|
/* Ignore collision if bullet already spent or if weapon and
|
||||||
@ -346,7 +340,7 @@ INTERNAL PHYS_COLLISION_CALLBACK_FUNC_DEF(on_collision, collision_data_array, ud
|
|||||||
sim_ent_enable_prop(bullet, SIM_ENT_PROP_RELEASE_THIS_TICK);
|
sim_ent_enable_prop(bullet, SIM_ENT_PROP_RELEASE_THIS_TICK);
|
||||||
|
|
||||||
/* Update tracer */
|
/* Update tracer */
|
||||||
struct sim_ent *tracer = sim_ent_from_handle(store, bullet->bullet_tracer);
|
struct sim_ent *tracer = sim_ent_from_handle(ctx->world, bullet->bullet_tracer);
|
||||||
if (sim_ent_is_valid_and_active(tracer)) {
|
if (sim_ent_is_valid_and_active(tracer)) {
|
||||||
struct xform xf = sim_ent_get_xform(tracer);
|
struct xform xf = sim_ent_get_xform(tracer);
|
||||||
xf.og = point;
|
xf.og = point;
|
||||||
@ -443,11 +437,10 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns)
|
|||||||
(UNUSED)world_dt;
|
(UNUSED)world_dt;
|
||||||
(UNUSED)world_time;
|
(UNUSED)world_time;
|
||||||
|
|
||||||
struct sim_ent_store *ent_store = ctx->world->ent_store;
|
|
||||||
struct space *space = ctx->space;
|
struct space *space = ctx->space;
|
||||||
struct sprite_scope *sprite_frame_scope = ctx->sprite_frame_scope;
|
struct sprite_scope *sprite_frame_scope = ctx->sprite_frame_scope;
|
||||||
|
|
||||||
struct sim_ent *root = sim_ent_from_handle(ctx->world->ent_store, SIM_ENT_ROOT_HANDLE);
|
struct sim_ent *root = sim_ent_from_handle(ctx->world, SIM_ENT_ROOT_HANDLE);
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
* Spawn test entities
|
* Spawn test entities
|
||||||
@ -473,8 +466,8 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns)
|
|||||||
* Activate entities
|
* Activate entities
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
for (u64 ent_index = 0; ent_index < ent_store->num_reserved; ++ent_index) {
|
for (u64 ent_index = 0; ent_index < ctx->world->num_ents_reserved; ++ent_index) {
|
||||||
struct sim_ent *ent = &ent_store->entities[ent_index];
|
struct sim_ent *ent = &ctx->world->ents[ent_index];
|
||||||
if (!ent->valid) continue;
|
if (!ent->valid) continue;
|
||||||
|
|
||||||
if (!sim_ent_has_prop(ent, SIM_ENT_PROP_ACTIVE)) {
|
if (!sim_ent_has_prop(ent, SIM_ENT_PROP_ACTIVE)) {
|
||||||
@ -489,8 +482,8 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns)
|
|||||||
* Reset triggered entities
|
* Reset triggered entities
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
for (u64 ent_index = 0; ent_index < ent_store->num_reserved; ++ent_index) {
|
for (u64 ent_index = 0; ent_index < ctx->world->num_ents_reserved; ++ent_index) {
|
||||||
struct sim_ent *ent = &ent_store->entities[ent_index];
|
struct sim_ent *ent = &ctx->world->ents[ent_index];
|
||||||
if (!sim_ent_is_valid_and_active(ent)) continue;
|
if (!sim_ent_is_valid_and_active(ent)) continue;
|
||||||
|
|
||||||
if (sim_ent_has_prop(ent, SIM_ENT_PROP_TRIGGER_NEXT_TICK)) {
|
if (sim_ent_has_prop(ent, SIM_ENT_PROP_TRIGGER_NEXT_TICK)) {
|
||||||
@ -647,8 +640,8 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns)
|
|||||||
* Update entity control from client control
|
* Update entity control from client control
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
for (u64 ent_index = 0; ent_index < ent_store->num_reserved; ++ent_index) {
|
for (u64 ent_index = 0; ent_index < ctx->world->num_ents_reserved; ++ent_index) {
|
||||||
struct sim_ent *ent = &ent_store->entities[ent_index];
|
struct sim_ent *ent = &ctx->world->ents[ent_index];
|
||||||
if (!sim_ent_is_valid_and_active(ent)) continue;
|
if (!sim_ent_is_valid_and_active(ent)) continue;
|
||||||
|
|
||||||
if (sim_ent_has_prop(ent, SIM_ENT_PROP_CONTROLLED)) {
|
if (sim_ent_has_prop(ent, SIM_ENT_PROP_CONTROLLED)) {
|
||||||
@ -669,8 +662,8 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns)
|
|||||||
* Update entities from sprite
|
* Update entities from sprite
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
for (u64 ent_index = 0; ent_index < ent_store->num_reserved; ++ent_index) {
|
for (u64 ent_index = 0; ent_index < ctx->world->num_ents_reserved; ++ent_index) {
|
||||||
struct sim_ent *ent = &ent_store->entities[ent_index];
|
struct sim_ent *ent = &ctx->world->ents[ent_index];
|
||||||
if (!sim_ent_is_valid_and_active(ent)) continue;
|
if (!sim_ent_is_valid_and_active(ent)) continue;
|
||||||
if (sprite_tag_is_nil(ent->sprite)) continue;
|
if (sprite_tag_is_nil(ent->sprite)) continue;
|
||||||
|
|
||||||
@ -764,12 +757,12 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns)
|
|||||||
* Update attachments
|
* Update attachments
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
for (u64 ent_index = 0; ent_index < ent_store->num_reserved; ++ent_index) {
|
for (u64 ent_index = 0; ent_index < ctx->world->num_ents_reserved; ++ent_index) {
|
||||||
struct sim_ent *ent = &ent_store->entities[ent_index];
|
struct sim_ent *ent = &ctx->world->ents[ent_index];
|
||||||
if (!sim_ent_is_valid_and_active(ent)) continue;
|
if (!sim_ent_is_valid_and_active(ent)) continue;
|
||||||
if (!sim_ent_has_prop(ent, SIM_ENT_PROP_ATTACHED)) continue;
|
if (!sim_ent_has_prop(ent, SIM_ENT_PROP_ATTACHED)) continue;
|
||||||
|
|
||||||
struct sim_ent *parent = sim_ent_from_handle(ent_store, ent->parent);
|
struct sim_ent *parent = sim_ent_from_handle(ctx->world, ent->parent);
|
||||||
struct sprite_tag parent_sprite = parent->sprite;
|
struct sprite_tag parent_sprite = parent->sprite;
|
||||||
struct sprite_sheet *parent_sheet = sprite_sheet_from_tag_await(sprite_frame_scope, parent_sprite);
|
struct sprite_sheet *parent_sheet = sprite_sheet_from_tag_await(sprite_frame_scope, parent_sprite);
|
||||||
|
|
||||||
@ -790,8 +783,8 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns)
|
|||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
for (u64 ent_index = 0; ent_index < ent_store->num_reserved; ++ent_index) {
|
for (u64 ent_index = 0; ent_index < ctx->world->num_ents_reserved; ++ent_index) {
|
||||||
struct sim_ent *ent = &ent_store->entities[ent_index];
|
struct sim_ent *ent = &ctx->world->ents[ent_index];
|
||||||
if (!sim_ent_is_valid_and_active(ent)) continue;
|
if (!sim_ent_is_valid_and_active(ent)) continue;
|
||||||
if (!sim_ent_has_prop(ent, SIM_ENT_PROP_TEST)) continue;
|
if (!sim_ent_has_prop(ent, SIM_ENT_PROP_TEST)) continue;
|
||||||
|
|
||||||
@ -840,12 +833,12 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns)
|
|||||||
* Trigger equipped
|
* Trigger equipped
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
for (u64 ent_index = 0; ent_index < ent_store->num_reserved; ++ent_index) {
|
for (u64 ent_index = 0; ent_index < ctx->world->num_ents_reserved; ++ent_index) {
|
||||||
struct sim_ent *ent = &ent_store->entities[ent_index];
|
struct sim_ent *ent = &ctx->world->ents[ent_index];
|
||||||
if (!sim_ent_is_valid_and_active(ent)) continue;
|
if (!sim_ent_is_valid_and_active(ent)) continue;
|
||||||
|
|
||||||
if (sim_ent_has_prop(ent, SIM_ENT_PROP_TRIGGERING_EQUIPPED)) {
|
if (sim_ent_has_prop(ent, SIM_ENT_PROP_TRIGGERING_EQUIPPED)) {
|
||||||
struct sim_ent *eq = sim_ent_from_handle(ent_store, ent->equipped);
|
struct sim_ent *eq = sim_ent_from_handle(ctx->world, ent->equipped);
|
||||||
if (sim_ent_is_valid_and_active(eq)) {
|
if (sim_ent_is_valid_and_active(eq)) {
|
||||||
sim_ent_enable_prop(eq, SIM_ENT_PROP_TRIGGERED_THIS_TICK);
|
sim_ent_enable_prop(eq, SIM_ENT_PROP_TRIGGERED_THIS_TICK);
|
||||||
}
|
}
|
||||||
@ -856,8 +849,8 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns)
|
|||||||
* Process triggered entities
|
* Process triggered entities
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
for (u64 ent_index = 0; ent_index < ent_store->num_reserved; ++ent_index) {
|
for (u64 ent_index = 0; ent_index < ctx->world->num_ents_reserved; ++ent_index) {
|
||||||
struct sim_ent *ent = &ent_store->entities[ent_index];
|
struct sim_ent *ent = &ctx->world->ents[ent_index];
|
||||||
if (!sim_ent_is_valid_and_active(ent)) continue;
|
if (!sim_ent_is_valid_and_active(ent)) continue;
|
||||||
if (!sim_ent_has_prop(ent, SIM_ENT_PROP_TRIGGERED_THIS_TICK)) continue;
|
if (!sim_ent_has_prop(ent, SIM_ENT_PROP_TRIGGERED_THIS_TICK)) continue;
|
||||||
if ((sim_time - ent->last_triggered < ent->trigger_delay) && ent->last_triggered != 0) continue;
|
if ((sim_time - ent->last_triggered < ent->trigger_delay) && ent->last_triggered != 0) continue;
|
||||||
@ -919,12 +912,12 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns)
|
|||||||
* Create motor joints from control move
|
* Create motor joints from control move
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
for (u64 ent_index = 0; ent_index < ent_store->num_reserved; ++ent_index) {
|
for (u64 ent_index = 0; ent_index < ctx->world->num_ents_reserved; ++ent_index) {
|
||||||
struct sim_ent *ent = &ent_store->entities[ent_index];
|
struct sim_ent *ent = &ctx->world->ents[ent_index];
|
||||||
if (!sim_ent_is_valid_and_active(ent)) continue;
|
if (!sim_ent_is_valid_and_active(ent)) continue;
|
||||||
|
|
||||||
if (sim_ent_has_prop(ent, SIM_ENT_PROP_CONTROLLED)) {
|
if (sim_ent_has_prop(ent, SIM_ENT_PROP_CONTROLLED)) {
|
||||||
struct sim_ent *joint_ent = sim_ent_from_handle(ent_store, ent->move_joint);
|
struct sim_ent *joint_ent = sim_ent_from_handle(ctx->world, ent->move_joint);
|
||||||
if (!sim_ent_is_valid_and_active(joint_ent)) {
|
if (!sim_ent_is_valid_and_active(joint_ent)) {
|
||||||
joint_ent = sim_ent_alloc(root);
|
joint_ent = sim_ent_alloc(root);
|
||||||
joint_ent->mass_unscaled = F32_INFINITY;
|
joint_ent->mass_unscaled = F32_INFINITY;
|
||||||
@ -952,8 +945,8 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns)
|
|||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
#if SIM_PLAYER_AIM
|
#if SIM_PLAYER_AIM
|
||||||
for (u64 ent_index = 0; ent_index < ent_store->num_reserved; ++ent_index) {
|
for (u64 ent_index = 0; ent_index < ctx->world->num_ents_reserved; ++ent_index) {
|
||||||
struct sim_ent *ent = &ent_store->entities[ent_index];
|
struct sim_ent *ent = &ctx->world->ents[ent_index];
|
||||||
if (!sim_ent_is_valid_and_active(ent)) continue;
|
if (!sim_ent_is_valid_and_active(ent)) continue;
|
||||||
|
|
||||||
if (sim_ent_has_prop(ent, SIM_ENT_PROP_CONTROLLED)) {
|
if (sim_ent_has_prop(ent, SIM_ENT_PROP_CONTROLLED)) {
|
||||||
@ -961,7 +954,7 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns)
|
|||||||
struct xform sprite_xf = xform_mul(xf, ent->sprite_local_xform);
|
struct xform sprite_xf = xform_mul(xf, ent->sprite_local_xform);
|
||||||
|
|
||||||
/* Retrieve / create aim joint */
|
/* Retrieve / create aim joint */
|
||||||
struct sim_ent *joint_ent = sim_ent_from_handle(ent_store, ent->aim_joint);
|
struct sim_ent *joint_ent = sim_ent_from_handle(ctx->world, ent->aim_joint);
|
||||||
if (!sim_ent_is_valid_and_active(joint_ent)) {
|
if (!sim_ent_is_valid_and_active(joint_ent)) {
|
||||||
joint_ent = sim_ent_alloc(root);
|
joint_ent = sim_ent_alloc(root);
|
||||||
joint_ent->mass_unscaled = F32_INFINITY;
|
joint_ent->mass_unscaled = F32_INFINITY;
|
||||||
@ -1045,12 +1038,12 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns)
|
|||||||
* Create motor joints from ground friction (gravity)
|
* Create motor joints from ground friction (gravity)
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
for (u64 ent_index = 0; ent_index < ent_store->num_reserved; ++ent_index) {
|
for (u64 ent_index = 0; ent_index < ctx->world->num_ents_reserved; ++ent_index) {
|
||||||
struct sim_ent *ent = &ent_store->entities[ent_index];
|
struct sim_ent *ent = &ctx->world->ents[ent_index];
|
||||||
if (!sim_ent_is_valid_and_active(ent)) continue;
|
if (!sim_ent_is_valid_and_active(ent)) continue;
|
||||||
if (!sim_ent_has_prop(ent, SIM_ENT_PROP_PHYSICAL_DYNAMIC)) continue;
|
if (!sim_ent_has_prop(ent, SIM_ENT_PROP_PHYSICAL_DYNAMIC)) continue;
|
||||||
|
|
||||||
struct sim_ent *joint_ent = sim_ent_from_handle(ent_store, ent->ground_friction_joint);
|
struct sim_ent *joint_ent = sim_ent_from_handle(ctx->world, ent->ground_friction_joint);
|
||||||
|
|
||||||
struct phys_motor_joint_def def = ZI;
|
struct phys_motor_joint_def def = ZI;
|
||||||
def.e0 = root->handle;
|
def.e0 = root->handle;
|
||||||
@ -1080,8 +1073,8 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns)
|
|||||||
b32 start_dragging = client->dbg_drag_start;
|
b32 start_dragging = client->dbg_drag_start;
|
||||||
b32 stop_dragging = client->dbg_drag_stop;
|
b32 stop_dragging = client->dbg_drag_stop;
|
||||||
|
|
||||||
struct sim_ent *joint_ent = sim_ent_from_handle(ent_store, client->dbg_drag_joint_ent);
|
struct sim_ent *joint_ent = sim_ent_from_handle(ctx->world, client->dbg_drag_joint_ent);
|
||||||
struct sim_ent *target_ent = sim_ent_from_handle(ent_store, joint_ent->mouse_joint_data.target);
|
struct sim_ent *target_ent = sim_ent_from_handle(ctx->world, joint_ent->mouse_joint_data.target);
|
||||||
|
|
||||||
if (start_dragging) {
|
if (start_dragging) {
|
||||||
struct xform mouse_xf = xform_from_pos(cursor);
|
struct xform mouse_xf = xform_from_pos(cursor);
|
||||||
@ -1089,8 +1082,8 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns)
|
|||||||
mouse_shape.points[0] = V2(0, 0);
|
mouse_shape.points[0] = V2(0, 0);
|
||||||
mouse_shape.count = 1;
|
mouse_shape.count = 1;
|
||||||
|
|
||||||
for (u64 sim_ent_index = 0; sim_ent_index < ent_store->num_reserved; ++sim_ent_index) {
|
for (u64 sim_ent_index = 0; sim_ent_index < ctx->world->num_ents_reserved; ++sim_ent_index) {
|
||||||
struct sim_ent *ent = &ent_store->entities[sim_ent_index];
|
struct sim_ent *ent = &ctx->world->ents[sim_ent_index];
|
||||||
if (!sim_ent_is_valid_and_active(ent)) continue;
|
if (!sim_ent_is_valid_and_active(ent)) continue;
|
||||||
if (!sim_ent_has_prop(ent, SIM_ENT_PROP_PHYSICAL_DYNAMIC)) continue;
|
if (!sim_ent_has_prop(ent, SIM_ENT_PROP_PHYSICAL_DYNAMIC)) continue;
|
||||||
|
|
||||||
@ -1145,8 +1138,7 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns)
|
|||||||
|
|
||||||
{
|
{
|
||||||
struct phys_ctx phys = ZI;
|
struct phys_ctx phys = ZI;
|
||||||
phys.tick = ctx->world->tick;
|
phys.ss = ctx->world;
|
||||||
phys.store = ent_store;
|
|
||||||
phys.space = space;
|
phys.space = space;
|
||||||
phys.contact_lookup = &ctx->contact_lookup;
|
phys.contact_lookup = &ctx->contact_lookup;
|
||||||
phys.pre_solve_callback = on_collision;
|
phys.pre_solve_callback = on_collision;
|
||||||
@ -1163,8 +1155,8 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns)
|
|||||||
* Update tracers
|
* Update tracers
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
for (u64 ent_index = 0; ent_index < ent_store->num_reserved; ++ent_index) {
|
for (u64 ent_index = 0; ent_index < ctx->world->num_ents_reserved; ++ent_index) {
|
||||||
struct sim_ent *ent = &ent_store->entities[ent_index];
|
struct sim_ent *ent = &ctx->world->ents[ent_index];
|
||||||
if (!sim_ent_is_valid_and_active(ent)) continue;
|
if (!sim_ent_is_valid_and_active(ent)) continue;
|
||||||
if (!sim_ent_has_prop(ent, SIM_ENT_PROP_TRACER)) continue;
|
if (!sim_ent_has_prop(ent, SIM_ENT_PROP_TRACER)) continue;
|
||||||
|
|
||||||
@ -1187,13 +1179,13 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns)
|
|||||||
* Initialize bullet kinematics from sources
|
* Initialize bullet kinematics from sources
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
for (u64 ent_index = 0; ent_index < ent_store->num_reserved; ++ent_index) {
|
for (u64 ent_index = 0; ent_index < ctx->world->num_ents_reserved; ++ent_index) {
|
||||||
struct sim_ent *ent = &ent_store->entities[ent_index];
|
struct sim_ent *ent = &ctx->world->ents[ent_index];
|
||||||
if (!sim_ent_is_valid_and_active(ent)) continue;
|
if (!sim_ent_is_valid_and_active(ent)) continue;
|
||||||
if (!sim_ent_has_prop(ent, SIM_ENT_PROP_BULLET)) continue;
|
if (!sim_ent_has_prop(ent, SIM_ENT_PROP_BULLET)) continue;
|
||||||
|
|
||||||
if (ent->activation_tick == ctx->world->tick) {
|
if (ent->activation_tick == ctx->world->tick) {
|
||||||
struct sim_ent *src = sim_ent_from_handle(ent_store, ent->bullet_src);
|
struct sim_ent *src = sim_ent_from_handle(ctx->world, ent->bullet_src);
|
||||||
struct xform src_xf = sim_ent_get_xform(src);
|
struct xform src_xf = sim_ent_get_xform(src);
|
||||||
|
|
||||||
struct v2 pos = xform_mul_v2(src_xf, ent->bullet_src_pos);
|
struct v2 pos = xform_mul_v2(src_xf, ent->bullet_src_pos);
|
||||||
@ -1204,7 +1196,7 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns)
|
|||||||
/* Add shooter velocity to bullet */
|
/* Add shooter velocity to bullet */
|
||||||
{
|
{
|
||||||
/* TODO: Add angular velocity as well? */
|
/* TODO: Add angular velocity as well? */
|
||||||
struct sim_ent *top = sim_ent_from_handle(ent_store, src->top);
|
struct sim_ent *top = sim_ent_from_handle(ctx->world, src->top);
|
||||||
impulse = v2_add(impulse, v2_mul(top->linear_velocity, dt));
|
impulse = v2_add(impulse, v2_mul(top->linear_velocity, dt));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -1216,7 +1208,7 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns)
|
|||||||
sim_ent_apply_linear_impulse_to_center(ent, impulse);
|
sim_ent_apply_linear_impulse_to_center(ent, impulse);
|
||||||
|
|
||||||
/* Initialize tracer */
|
/* Initialize tracer */
|
||||||
struct sim_ent *tracer = sim_ent_from_handle(ent_store, ent->bullet_tracer);
|
struct sim_ent *tracer = sim_ent_from_handle(ctx->world, ent->bullet_tracer);
|
||||||
if (sim_ent_is_valid_and_active(tracer)) {
|
if (sim_ent_is_valid_and_active(tracer)) {
|
||||||
sim_ent_set_xform(tracer, xf);
|
sim_ent_set_xform(tracer, xf);
|
||||||
sim_ent_enable_prop(tracer, SIM_ENT_PROP_PHYSICAL_KINEMATIC);
|
sim_ent_enable_prop(tracer, SIM_ENT_PROP_PHYSICAL_KINEMATIC);
|
||||||
@ -1242,8 +1234,8 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns)
|
|||||||
* Update cameras
|
* Update cameras
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
for (u64 ent_index = 0; ent_index < ent_store->num_reserved; ++ent_index) {
|
for (u64 ent_index = 0; ent_index < ctx->world->num_ents_reserved; ++ent_index) {
|
||||||
struct sim_ent *ent = &ent_store->entities[ent_index];
|
struct sim_ent *ent = &ctx->world->ents[ent_index];
|
||||||
if (!sim_ent_is_valid_and_active(ent)) continue;
|
if (!sim_ent_is_valid_and_active(ent)) continue;
|
||||||
if (!sim_ent_has_prop(ent, SIM_ENT_PROP_CAMERA)) continue;
|
if (!sim_ent_has_prop(ent, SIM_ENT_PROP_CAMERA)) continue;
|
||||||
|
|
||||||
@ -1251,7 +1243,7 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns)
|
|||||||
|
|
||||||
/* Camera follow */
|
/* Camera follow */
|
||||||
{
|
{
|
||||||
struct sim_ent *follow = sim_ent_from_handle(ent_store, ent->camera_follow);
|
struct sim_ent *follow = sim_ent_from_handle(ctx->world, ent->camera_follow);
|
||||||
|
|
||||||
f32 aspect_ratio = 1.0;
|
f32 aspect_ratio = 1.0;
|
||||||
{
|
{
|
||||||
@ -1283,8 +1275,8 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns)
|
|||||||
{
|
{
|
||||||
/* TODO: Update based on distance to quake */
|
/* TODO: Update based on distance to quake */
|
||||||
ent->shake = 0;
|
ent->shake = 0;
|
||||||
for (u64 quake_ent_index = 0; quake_ent_index < ent_store->num_reserved; ++quake_ent_index) {
|
for (u64 quake_ent_index = 0; quake_ent_index < ctx->world->num_ents_reserved; ++quake_ent_index) {
|
||||||
struct sim_ent *quake = &ent_store->entities[quake_ent_index];
|
struct sim_ent *quake = &ctx->world->ents[quake_ent_index];
|
||||||
if (!sim_ent_is_valid_and_active(quake)) continue;
|
if (!sim_ent_is_valid_and_active(quake)) continue;
|
||||||
if (!sim_ent_has_prop(quake, SIM_ENT_PROP_QUAKE)) continue;
|
if (!sim_ent_has_prop(quake, SIM_ENT_PROP_QUAKE)) continue;
|
||||||
ent->shake += quake->quake_intensity;
|
ent->shake += quake->quake_intensity;
|
||||||
@ -1298,8 +1290,8 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns)
|
|||||||
* Update quakes
|
* Update quakes
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
for (u64 ent_index = 0; ent_index < ent_store->num_reserved; ++ent_index) {
|
for (u64 ent_index = 0; ent_index < ctx->world->num_ents_reserved; ++ent_index) {
|
||||||
struct sim_ent *ent = &ent_store->entities[ent_index];
|
struct sim_ent *ent = &ctx->world->ents[ent_index];
|
||||||
if (!sim_ent_is_valid_and_active(ent)) continue;
|
if (!sim_ent_is_valid_and_active(ent)) continue;
|
||||||
if (!sim_ent_has_prop(ent, SIM_ENT_PROP_QUAKE)) continue;
|
if (!sim_ent_has_prop(ent, SIM_ENT_PROP_QUAKE)) continue;
|
||||||
|
|
||||||
@ -1326,7 +1318,7 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns)
|
|||||||
--stack_count;
|
--stack_count;
|
||||||
|
|
||||||
i32 parent_layer = parent->final_layer;
|
i32 parent_layer = parent->final_layer;
|
||||||
for (struct sim_ent *child = sim_ent_from_handle(ent_store, parent->first); child->valid; child = sim_ent_from_handle(ent_store, child->next)) {
|
for (struct sim_ent *child = sim_ent_from_handle(ctx->world, parent->first); child->valid; child = sim_ent_from_handle(ctx->world, child->next)) {
|
||||||
if (sim_ent_is_valid_and_active(child)) {
|
if (sim_ent_is_valid_and_active(child)) {
|
||||||
child->final_layer = parent_layer + child->layer;
|
child->final_layer = parent_layer + child->layer;
|
||||||
*arena_push(temp.arena, struct sim_ent *) = child;
|
*arena_push(temp.arena, struct sim_ent *) = child;
|
||||||
|
|||||||
@ -7,7 +7,6 @@
|
|||||||
struct sprite_startup_receipt;
|
struct sprite_startup_receipt;
|
||||||
struct phys_startup_receipt;
|
struct phys_startup_receipt;
|
||||||
struct host_startup_receipt;
|
struct host_startup_receipt;
|
||||||
struct sim_ent_startup_receipt;
|
|
||||||
struct sim_snapshot_startup_receipt;
|
struct sim_snapshot_startup_receipt;
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
@ -149,7 +148,6 @@ struct sim_ctx {
|
|||||||
struct sim_ctx *sim_ctx_alloc(struct sprite_startup_receipt *sprite_sr,
|
struct sim_ctx *sim_ctx_alloc(struct sprite_startup_receipt *sprite_sr,
|
||||||
struct phys_startup_receipt *phys_sr,
|
struct phys_startup_receipt *phys_sr,
|
||||||
struct host_startup_receipt *host_sr,
|
struct host_startup_receipt *host_sr,
|
||||||
struct sim_ent_startup_receipt *sim_ent_sr,
|
|
||||||
struct sim_snapshot_startup_receipt *sim_snapshot_sr,
|
struct sim_snapshot_startup_receipt *sim_snapshot_sr,
|
||||||
u16 host_port);
|
u16 host_port);
|
||||||
|
|
||||||
|
|||||||
@ -239,11 +239,11 @@ struct string sim_encode_snapshot(struct arena *arena, struct sim_client *client
|
|||||||
br_write_bytes(&bw, clients_src);
|
br_write_bytes(&bw, clients_src);
|
||||||
|
|
||||||
/* Entity store */
|
/* Entity store */
|
||||||
u64 num_entities = snapshot->ent_store->num_reserved;
|
u64 num_entities = snapshot->num_ents_reserved;
|
||||||
bw_write_var_uint(&bw, num_entities);
|
bw_write_var_uint(&bw, num_entities);
|
||||||
|
|
||||||
struct string entities_src = ZI;
|
struct string entities_src = ZI;
|
||||||
entities_src.text = (u8 *)snapshot->ent_store->entities;
|
entities_src.text = (u8 *)snapshot->ents;
|
||||||
entities_src.len = sizeof(struct sim_ent) * num_entities;
|
entities_src.len = sizeof(struct sim_ent) * num_entities;
|
||||||
br_write_bytes(&bw, entities_src);
|
br_write_bytes(&bw, entities_src);
|
||||||
|
|
||||||
@ -287,17 +287,17 @@ void sim_decode_snapshot(struct string str, struct sim_snapshot *snapshot)
|
|||||||
|
|
||||||
/* Entity store */
|
/* Entity store */
|
||||||
u64 num_entities = br_read_var_uint(&br);
|
u64 num_entities = br_read_var_uint(&br);
|
||||||
arena_push_array(&snapshot->ent_store->arena, struct sim_ent, num_entities - snapshot->ent_store->num_reserved);
|
arena_push_array(&snapshot->ents_arena, struct sim_ent, num_entities - snapshot->num_ents_reserved);
|
||||||
snapshot->ent_store->num_reserved = num_entities;
|
snapshot->num_ents_reserved = num_entities;
|
||||||
|
|
||||||
snapshot->ent_store->num_allocated = 0;
|
snapshot->num_ents_allocated = 0;
|
||||||
struct sim_ent *entities_src = br_seek(&br, num_entities * sizeof(struct sim_ent));
|
struct sim_ent *entities_src = br_seek(&br, num_entities * sizeof(struct sim_ent));
|
||||||
if (entities_src) {
|
if (entities_src) {
|
||||||
for (u64 i = 0; i < num_entities; ++i) {
|
for (u64 i = 0; i < num_entities; ++i) {
|
||||||
struct sim_ent *src = &entities_src[i];
|
struct sim_ent *src = &entities_src[i];
|
||||||
struct sim_ent *dst = &snapshot->ent_store->entities[i];
|
struct sim_ent *dst = &snapshot->ents[i];
|
||||||
if (dst->valid) {
|
if (dst->valid) {
|
||||||
++snapshot->ent_store->num_allocated;
|
++snapshot->num_ents_allocated;
|
||||||
}
|
}
|
||||||
*dst = *src;
|
*dst = *src;
|
||||||
}
|
}
|
||||||
@ -581,9 +581,9 @@ struct string sim_encode_snapshot(struct sim_encoder *enc, struct sim_snapshot *
|
|||||||
br_write_bytes(&bw, clients_src);
|
br_write_bytes(&bw, clients_src);
|
||||||
|
|
||||||
/* Ents */
|
/* Ents */
|
||||||
for (u64 i = 0; i < snapshot->ent_store->num_reserved; ++i) {
|
for (u64 i = 0; i < snapshot->num_ents_reserved; ++i) {
|
||||||
bw_write_u8(bw, 1);
|
bw_write_u8(bw, 1);
|
||||||
struct sim_ent *ent = &snapshot->ent_store->entities[i];
|
struct sim_ent *ent = &snapshot->ents[i];
|
||||||
sim_encode_ent(enc, ent);
|
sim_encode_ent(enc, ent);
|
||||||
}
|
}
|
||||||
bw_write_u8(bw, 0);
|
bw_write_u8(bw, 0);
|
||||||
@ -629,7 +629,7 @@ struct sim_snapshot *sim_decode_snapshot(struct sim_decoder *dec, struct sim_sna
|
|||||||
/* Ents */
|
/* Ents */
|
||||||
b32 read_entity = br_read_u8(br);
|
b32 read_entity = br_read_u8(br);
|
||||||
while (read_entity) {
|
while (read_entity) {
|
||||||
sim_decode_ent(dec, snapshot->ent_store);
|
sim_decode_ent(dec, snapshot);
|
||||||
read_entity = br_read_u8(br);
|
read_entity = br_read_u8(br);
|
||||||
}f
|
}f
|
||||||
}
|
}
|
||||||
|
|||||||
234
src/sim_ent.c
234
src/sim_ent.c
@ -1,202 +1,90 @@
|
|||||||
#include "sim_ent.h"
|
#include "sim_ent.h"
|
||||||
|
#include "sim_snapshot.h"
|
||||||
#include "math.h"
|
#include "math.h"
|
||||||
|
|
||||||
/* Offset in bytes from start of store struct to start of entities array (assume adjacently allocated) */
|
|
||||||
#define STORE_ENTITIES_OFFSET (sizeof(struct sim_ent_store) + (sizeof(struct sim_ent_store) % alignof(struct sim_ent)))
|
|
||||||
|
|
||||||
/* ========================== *
|
|
||||||
* Global state
|
|
||||||
* ========================== */
|
|
||||||
|
|
||||||
|
|
||||||
GLOBAL struct {
|
|
||||||
struct sim_ent *nil_ent;
|
|
||||||
struct sim_ent_store *nil_store;
|
|
||||||
} G = ZI, DEBUG_ALIAS(G, G_sim_ent);
|
|
||||||
|
|
||||||
/* Accessed via sim_ent_nil() */
|
|
||||||
READONLY struct sim_ent **_g_sim_ent_nil = &G.nil_ent;
|
|
||||||
|
|
||||||
/* Accessed via sim_ent_store_nil() */
|
|
||||||
READONLY struct sim_ent_store **_g_sim_ent_store_nil = &G.nil_store;
|
|
||||||
|
|
||||||
struct sim_ent_startup_receipt sim_ent_startup(void)
|
|
||||||
{
|
|
||||||
/* Setup nil store */
|
|
||||||
G.nil_store = sim_ent_store_alloc(GIGABYTE(1), false);
|
|
||||||
|
|
||||||
/* Setup nil ent */
|
|
||||||
G.nil_ent = arena_push_zero(&G.nil_store->arena, struct sim_ent);
|
|
||||||
++G.nil_store->num_allocated;
|
|
||||||
++G.nil_store->num_reserved;
|
|
||||||
MEMZERO_STRUCT(G.nil_ent);
|
|
||||||
G.nil_ent->handle = SIM_ENT_NIL_HANDLE;
|
|
||||||
G.nil_ent->local_xform = XFORM_IDENT;
|
|
||||||
G.nil_ent->cached_global_xform = XFORM_IDENT;
|
|
||||||
G.nil_ent->cached_global_xform_dirty = false;
|
|
||||||
G.nil_ent->friction = 0.5f;
|
|
||||||
G.nil_ent->mass_unscaled = 1;
|
|
||||||
G.nil_ent->inertia_unscaled = 1;
|
|
||||||
G.nil_ent->sprite_local_xform = XFORM_IDENT;
|
|
||||||
G.nil_ent->sprite_tint = COLOR_WHITE;
|
|
||||||
|
|
||||||
G.nil_ent->valid = false;
|
|
||||||
G.nil_store->valid = false;
|
|
||||||
|
|
||||||
arena_set_readonly(&G.nil_store->arena);
|
|
||||||
return (struct sim_ent_startup_receipt) { 0 };
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ========================== *
|
|
||||||
* Store allocation
|
|
||||||
* ========================== */
|
|
||||||
|
|
||||||
INTERNAL struct sim_ent *sim_ent_alloc_internal(struct sim_ent_store *store);
|
|
||||||
|
|
||||||
struct sim_ent_store *sim_ent_store_alloc(u64 arena_reserve, b32 create_root)
|
|
||||||
{
|
|
||||||
struct sim_ent_store *store;
|
|
||||||
{
|
|
||||||
struct arena arena = arena_alloc(arena_reserve);
|
|
||||||
store = arena_push_zero(&arena, struct sim_ent_store);
|
|
||||||
store->arena = arena;
|
|
||||||
}
|
|
||||||
store->valid = true;
|
|
||||||
|
|
||||||
store->entities = arena_dry_push(&store->arena, struct sim_ent);
|
|
||||||
ASSERT((u8 *)store->entities - (u8 *)store == STORE_ENTITIES_OFFSET); /* Offset must be correct */
|
|
||||||
|
|
||||||
/* Create root entity */
|
|
||||||
if (create_root) {
|
|
||||||
struct sim_ent *root = sim_ent_alloc_internal(store);
|
|
||||||
ASSERT(sim_ent_handle_eq(root->handle, SIM_ENT_ROOT_HANDLE));
|
|
||||||
root->is_root = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return store;
|
|
||||||
}
|
|
||||||
|
|
||||||
void sim_ent_store_copy(struct sim_ent_store *dst, struct sim_ent_store *src)
|
|
||||||
{
|
|
||||||
i64 commit_diff = (i64)src->arena.pos - (i64)dst->arena.pos;
|
|
||||||
if (commit_diff > 0) {
|
|
||||||
arena_push_array(&dst->arena, u8, commit_diff);
|
|
||||||
}
|
|
||||||
arena_pop_to(&dst->arena, src->arena.pos);
|
|
||||||
|
|
||||||
dst->first_free = src->first_free;
|
|
||||||
dst->entities = (struct sim_ent *)((u8 *)dst + ((u8 *)src->entities - (u8 *)src));
|
|
||||||
dst->num_allocated = src->num_allocated;
|
|
||||||
dst->num_reserved = src->num_reserved;
|
|
||||||
|
|
||||||
MEMCPY(dst->entities, src->entities, sizeof(*src->entities) * src->num_reserved);
|
|
||||||
|
|
||||||
/* Re-initialize root in case of copy from nil store */
|
|
||||||
struct sim_ent *root = &dst->entities[0];
|
|
||||||
root->handle = SIM_ENT_ROOT_HANDLE;
|
|
||||||
root->valid = true;
|
|
||||||
root->is_root = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void sim_ent_store_release(struct sim_ent_store *store)
|
|
||||||
{
|
|
||||||
arena_release(&store->arena);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
* Entity allocation
|
* Entity allocation
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
INTERNAL struct sim_ent *sim_ent_alloc_internal(struct sim_ent_store *store)
|
INTERNAL struct sim_ent *sim_ent_alloc_internal(struct sim_snapshot *ss)
|
||||||
{
|
{
|
||||||
struct sim_ent *entity = NULL;
|
struct sim_ent *ent = NULL;
|
||||||
struct sim_ent_handle handle = ZI;
|
struct sim_ent_handle handle = ZI;
|
||||||
if (store->first_free.gen) {
|
if (ss->first_free_ent.gen) {
|
||||||
/* Reuse from free list */;
|
/* Reuse from free list */;
|
||||||
entity = sim_ent_from_handle(store, store->first_free);
|
ent = sim_ent_from_handle(ss, ss->first_free_ent);
|
||||||
handle = entity->handle;
|
handle = ent->handle;
|
||||||
++handle.gen;
|
++handle.gen;
|
||||||
store->first_free = entity->next_free;
|
ss->first_free_ent = ent->next_free;
|
||||||
} else {
|
} else {
|
||||||
/* Make new */
|
/* Make new */
|
||||||
entity = arena_push(&store->arena, struct sim_ent);
|
ent = arena_push(&ss->ents_arena, struct sim_ent);
|
||||||
handle = (struct sim_ent_handle) { .gen = 1, .idx = store->num_reserved++ };
|
handle = (struct sim_ent_handle) { .gen = 1, .idx = ss->num_ents_reserved++ };
|
||||||
}
|
}
|
||||||
*entity = *sim_ent_nil();
|
*ent = *sim_ent_nil();
|
||||||
entity->valid = true;
|
ent->ss = ss;
|
||||||
entity->handle = handle;
|
ent->valid = true;
|
||||||
entity->cached_global_xform_dirty = true;
|
ent->handle = handle;
|
||||||
++store->num_allocated;
|
ent->cached_global_xform_dirty = true;
|
||||||
return entity;
|
++ss->num_ents_allocated;
|
||||||
|
return ent;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct sim_ent *sim_ent_alloc(struct sim_ent *parent)
|
struct sim_ent *sim_ent_alloc(struct sim_ent *parent)
|
||||||
{
|
{
|
||||||
ASSERT(parent->valid);
|
ASSERT(parent->valid);
|
||||||
struct sim_ent_store *store = sim_ent_store_from_ent(parent);
|
struct sim_snapshot *ss = parent->ss;
|
||||||
struct sim_ent *e = sim_ent_alloc_internal(store);
|
struct sim_ent *e = sim_ent_alloc_internal(ss);
|
||||||
sim_ent_link_parent(e, parent);
|
sim_ent_link_parent(e, parent);
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
INTERNAL void sim_ent_release_internal(struct sim_ent_store *store, struct sim_ent *ent)
|
INTERNAL void sim_ent_release_internal(struct sim_snapshot *ss, struct sim_ent *ent)
|
||||||
{
|
{
|
||||||
/* Release children */
|
/* Release children */
|
||||||
struct sim_ent_handle first_handle = ent->first;
|
struct sim_ent_handle first_handle = ent->first;
|
||||||
if (first_handle.gen) {
|
if (first_handle.gen) {
|
||||||
for (struct sim_ent *child = sim_ent_from_handle(store, first_handle); child->valid; child = sim_ent_from_handle(store, child->next)) {
|
for (struct sim_ent *child = sim_ent_from_handle(ss, first_handle); child->valid; child = sim_ent_from_handle(ss, child->next)) {
|
||||||
sim_ent_release_internal(store, child);
|
sim_ent_release_internal(ss, child);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Release */
|
/* Release */
|
||||||
++ent->handle.gen;
|
++ent->handle.gen;
|
||||||
ent->valid = false;
|
ent->valid = false;
|
||||||
ent->next_free = store->first_free;
|
ent->next_free = ss->first_free_ent;
|
||||||
store->first_free = ent->handle;
|
ss->first_free_ent = ent->handle;
|
||||||
--store->num_allocated;
|
--ss->num_ents_allocated;
|
||||||
}
|
}
|
||||||
|
|
||||||
void sim_ent_release(struct sim_ent_store *store, struct sim_ent *ent)
|
void sim_ent_release(struct sim_snapshot *ss, struct sim_ent *ent)
|
||||||
{
|
{
|
||||||
if (ent->parent.gen) {
|
if (ent->parent.gen) {
|
||||||
sim_ent_unlink_from_parent(ent);
|
sim_ent_unlink_from_parent(ent);
|
||||||
}
|
}
|
||||||
sim_ent_release_internal(store, ent);
|
sim_ent_release_internal(ss, ent);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
* Query
|
* Query
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
struct sim_ent_store *sim_ent_store_from_ent(struct sim_ent *ent)
|
/* Returns a valid ent or read-only nil ent. Always safe to read result, need to check `valid` to write. */
|
||||||
|
struct sim_ent *sim_ent_from_handle(struct sim_snapshot *ss, struct sim_ent_handle handle)
|
||||||
{
|
{
|
||||||
if (ent->valid) {
|
if (handle.gen != 0 && handle.idx < ss->num_ents_reserved) {
|
||||||
u64 first_ent_addr = (u64)(ent - ent->handle.idx);
|
struct sim_ent *ent = &ss->ents[handle.idx];
|
||||||
struct sim_ent_store *store = (struct sim_ent_store *)(first_ent_addr - STORE_ENTITIES_OFFSET);
|
if (ent->handle.gen == handle.gen) {
|
||||||
ASSERT(store->entities == (struct sim_ent *)first_ent_addr);
|
return ent;
|
||||||
return store;
|
|
||||||
} else {
|
|
||||||
return sim_ent_store_nil();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Returns a valid entity or read-only nil entity. Always safe to read result, need to check `valid` to write. */
|
|
||||||
struct sim_ent *sim_ent_from_handle(struct sim_ent_store *store, struct sim_ent_handle handle)
|
|
||||||
{
|
|
||||||
if (handle.gen != 0 && handle.idx < store->num_reserved) {
|
|
||||||
struct sim_ent *entity = &store->entities[handle.idx];
|
|
||||||
if (entity->handle.gen == handle.gen) {
|
|
||||||
return entity;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return sim_ent_nil();
|
return sim_ent_nil();
|
||||||
}
|
}
|
||||||
|
|
||||||
struct sim_ent *sim_ent_find_first_match_one(struct sim_ent_store *store, enum sim_ent_prop prop)
|
struct sim_ent *sim_ent_find_first_match_one(struct sim_snapshot *ss, enum sim_ent_prop prop)
|
||||||
{
|
{
|
||||||
u64 count = store->num_reserved;
|
u64 count = ss->num_ents_reserved;
|
||||||
struct sim_ent *entities = store->entities;
|
struct sim_ent *entities = ss->ents;
|
||||||
for (u64 ent_index = 0; ent_index < count; ++ent_index) {
|
for (u64 ent_index = 0; ent_index < count; ++ent_index) {
|
||||||
struct sim_ent *ent = &entities[ent_index];
|
struct sim_ent *ent = &entities[ent_index];
|
||||||
if (ent->valid && sim_ent_has_prop(ent, prop)) {
|
if (ent->valid && sim_ent_has_prop(ent, prop)) {
|
||||||
@ -206,10 +94,10 @@ struct sim_ent *sim_ent_find_first_match_one(struct sim_ent_store *store, enum s
|
|||||||
return sim_ent_nil();
|
return sim_ent_nil();
|
||||||
}
|
}
|
||||||
|
|
||||||
struct sim_ent *sim_ent_find_first_match_all(struct sim_ent_store *store, struct sim_ent_prop_array props)
|
struct sim_ent *sim_ent_find_first_match_all(struct sim_snapshot *ss, struct sim_ent_prop_array props)
|
||||||
{
|
{
|
||||||
u64 count = store->num_reserved;
|
u64 count = ss->num_ents_reserved;
|
||||||
struct sim_ent *entities = store->entities;
|
struct sim_ent *entities = ss->ents;
|
||||||
for (u64 ent_index = 0; ent_index < count; ++ent_index) {
|
for (u64 ent_index = 0; ent_index < count; ++ent_index) {
|
||||||
struct sim_ent *ent = &entities[ent_index];
|
struct sim_ent *ent = &entities[ent_index];
|
||||||
if (ent->valid) {
|
if (ent->valid) {
|
||||||
@ -232,27 +120,27 @@ struct sim_ent *sim_ent_find_first_match_all(struct sim_ent_store *store, struct
|
|||||||
* Xform
|
* Xform
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
INTERNAL void sim_ent_mark_child_xforms_dirty(struct sim_ent_store *store, struct sim_ent *ent)
|
INTERNAL void sim_ent_mark_child_xforms_dirty(struct sim_snapshot *ss, struct sim_ent *ent)
|
||||||
{
|
{
|
||||||
for (struct sim_ent *child = sim_ent_from_handle(store, ent->first); child->valid; child = sim_ent_from_handle(store, child->next)) {
|
for (struct sim_ent *child = sim_ent_from_handle(ss, ent->first); child->valid; child = sim_ent_from_handle(ss, child->next)) {
|
||||||
if (child->cached_global_xform_dirty) {
|
if (child->cached_global_xform_dirty) {
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
child->cached_global_xform_dirty = true;
|
child->cached_global_xform_dirty = true;
|
||||||
sim_ent_mark_child_xforms_dirty(store, child);
|
sim_ent_mark_child_xforms_dirty(ss, child);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
INTERNAL struct xform sim_ent_get_xform_w_store(struct sim_ent_store *store, struct sim_ent *ent)
|
INTERNAL struct xform sim_ent_get_xform_internal(struct sim_snapshot *ss, struct sim_ent *ent)
|
||||||
{
|
{
|
||||||
struct xform xf;
|
struct xform xf;
|
||||||
if (ent->cached_global_xform_dirty) {
|
if (ent->cached_global_xform_dirty) {
|
||||||
if (ent->is_top) {
|
if (ent->is_top) {
|
||||||
xf = ent->local_xform;
|
xf = ent->local_xform;
|
||||||
} else {
|
} else {
|
||||||
struct sim_ent *parent = sim_ent_from_handle(store, ent->parent);
|
struct sim_ent *parent = sim_ent_from_handle(ss, ent->parent);
|
||||||
xf = sim_ent_get_xform_w_store(store, parent);
|
xf = sim_ent_get_xform_internal(ss, parent);
|
||||||
xf = xform_mul(xf, ent->local_xform);
|
xf = xform_mul(xf, ent->local_xform);
|
||||||
ent->cached_global_xform = xf;
|
ent->cached_global_xform = xf;
|
||||||
ent->cached_global_xform_dirty = false;
|
ent->cached_global_xform_dirty = false;
|
||||||
@ -272,9 +160,9 @@ struct xform sim_ent_get_xform(struct sim_ent *ent)
|
|||||||
if (ent->is_top) {
|
if (ent->is_top) {
|
||||||
xf = ent->local_xform;
|
xf = ent->local_xform;
|
||||||
} else {
|
} else {
|
||||||
struct sim_ent_store *store = sim_ent_store_from_ent(ent);
|
struct sim_snapshot *ss = ent->ss;
|
||||||
struct sim_ent *parent = sim_ent_from_handle(store, ent->parent);
|
struct sim_ent *parent = sim_ent_from_handle(ss, ent->parent);
|
||||||
xf = sim_ent_get_xform_w_store(store, parent);
|
xf = sim_ent_get_xform_internal(ss, parent);
|
||||||
xf = xform_mul(xf, ent->local_xform);
|
xf = xform_mul(xf, ent->local_xform);
|
||||||
ent->cached_global_xform = xf;
|
ent->cached_global_xform = xf;
|
||||||
ent->cached_global_xform_dirty = false;
|
ent->cached_global_xform_dirty = false;
|
||||||
@ -295,18 +183,18 @@ struct xform sim_ent_get_local_xform(struct sim_ent *ent)
|
|||||||
void sim_ent_set_xform(struct sim_ent *ent, struct xform xf)
|
void sim_ent_set_xform(struct sim_ent *ent, struct xform xf)
|
||||||
{
|
{
|
||||||
if (!xform_eq(xf, ent->cached_global_xform)) {
|
if (!xform_eq(xf, ent->cached_global_xform)) {
|
||||||
struct sim_ent_store *store = sim_ent_store_from_ent(ent);
|
struct sim_snapshot *ss = ent->ss;
|
||||||
/* Update local xform */
|
/* Update local xform */
|
||||||
if (ent->is_top) {
|
if (ent->is_top) {
|
||||||
ent->local_xform = xf;
|
ent->local_xform = xf;
|
||||||
} else {
|
} else {
|
||||||
struct sim_ent *parent = sim_ent_from_handle(store, ent->parent);
|
struct sim_ent *parent = sim_ent_from_handle(ss, ent->parent);
|
||||||
struct xform parent_global = sim_ent_get_xform_w_store(store, parent);
|
struct xform parent_global = sim_ent_get_xform_internal(ss, parent);
|
||||||
ent->local_xform = xform_mul(xform_invert(parent_global), xf);
|
ent->local_xform = xform_mul(xform_invert(parent_global), xf);
|
||||||
}
|
}
|
||||||
ent->cached_global_xform = xf;
|
ent->cached_global_xform = xf;
|
||||||
ent->cached_global_xform_dirty = false;
|
ent->cached_global_xform_dirty = false;
|
||||||
sim_ent_mark_child_xforms_dirty(store, ent);
|
sim_ent_mark_child_xforms_dirty(ss, ent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -315,7 +203,7 @@ void sim_ent_set_local_xform(struct sim_ent *ent, struct xform xf)
|
|||||||
if (!xform_eq(xf, ent->local_xform)) {
|
if (!xform_eq(xf, ent->local_xform)) {
|
||||||
ent->local_xform = xf;
|
ent->local_xform = xf;
|
||||||
ent->cached_global_xform_dirty = true;
|
ent->cached_global_xform_dirty = true;
|
||||||
sim_ent_mark_child_xforms_dirty(sim_ent_store_from_ent(ent), ent);
|
sim_ent_mark_child_xforms_dirty(ent->ss, ent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -369,7 +257,7 @@ void sim_ent_apply_torque(struct sim_ent *ent, f32 torque)
|
|||||||
|
|
||||||
void sim_ent_link_parent(struct sim_ent *ent, struct sim_ent *parent)
|
void sim_ent_link_parent(struct sim_ent *ent, struct sim_ent *parent)
|
||||||
{
|
{
|
||||||
struct sim_ent_store *store = sim_ent_store_from_ent(ent);
|
struct sim_snapshot *ss = ent->ss;
|
||||||
|
|
||||||
if (ent->parent.gen) {
|
if (ent->parent.gen) {
|
||||||
/* Unlink from current parent */
|
/* Unlink from current parent */
|
||||||
@ -382,7 +270,7 @@ void sim_ent_link_parent(struct sim_ent *ent, struct sim_ent *parent)
|
|||||||
ent->parent = parent_handle;
|
ent->parent = parent_handle;
|
||||||
|
|
||||||
struct sim_ent_handle last_child_handle = parent->last;
|
struct sim_ent_handle last_child_handle = parent->last;
|
||||||
struct sim_ent *last_child = sim_ent_from_handle(store, last_child_handle);
|
struct sim_ent *last_child = sim_ent_from_handle(ss, last_child_handle);
|
||||||
if (last_child->valid) {
|
if (last_child->valid) {
|
||||||
ent->prev = last_child_handle;
|
ent->prev = last_child_handle;
|
||||||
last_child->next = handle;
|
last_child->next = handle;
|
||||||
@ -399,15 +287,15 @@ void sim_ent_link_parent(struct sim_ent *ent, struct sim_ent *parent)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* NOTE: Entity will be dangling after calling this, should re-link to root entity. */
|
/* NOTE: Entity will be dangling after calling this, should re-link to root ent. */
|
||||||
void sim_ent_unlink_from_parent(struct sim_ent *ent)
|
void sim_ent_unlink_from_parent(struct sim_ent *ent)
|
||||||
{
|
{
|
||||||
struct sim_ent_store *store = sim_ent_store_from_ent(ent);
|
struct sim_snapshot *ss = ent->ss;
|
||||||
|
|
||||||
struct sim_ent_handle parent_handle = ent->parent;
|
struct sim_ent_handle parent_handle = ent->parent;
|
||||||
struct sim_ent *parent = sim_ent_from_handle(store, parent_handle);
|
struct sim_ent *parent = sim_ent_from_handle(ss, parent_handle);
|
||||||
struct sim_ent *prev = sim_ent_from_handle(store, ent->prev);
|
struct sim_ent *prev = sim_ent_from_handle(ss, ent->prev);
|
||||||
struct sim_ent *next = sim_ent_from_handle(store, ent->next);
|
struct sim_ent *next = sim_ent_from_handle(ss, ent->next);
|
||||||
|
|
||||||
/* Unlink from parent & siblings */
|
/* Unlink from parent & siblings */
|
||||||
if (prev->valid) {
|
if (prev->valid) {
|
||||||
@ -475,7 +363,7 @@ void sim_ent_lookup_set(struct sim_ent_lookup *l, struct sim_ent_lookup_key key,
|
|||||||
struct sim_ent_lookup_entry *entry = *slot;
|
struct sim_ent_lookup_entry *entry = *slot;
|
||||||
if (entry) {
|
if (entry) {
|
||||||
/* Set existing entry */
|
/* Set existing entry */
|
||||||
entry->entity = handle;
|
entry->ent = handle;
|
||||||
} else {
|
} else {
|
||||||
/* Allocate entry */
|
/* Allocate entry */
|
||||||
if (l->first_free_entry) {
|
if (l->first_free_entry) {
|
||||||
@ -488,7 +376,7 @@ void sim_ent_lookup_set(struct sim_ent_lookup *l, struct sim_ent_lookup_key key,
|
|||||||
MEMZERO_STRUCT(entry);
|
MEMZERO_STRUCT(entry);
|
||||||
|
|
||||||
entry->key = key;
|
entry->key = key;
|
||||||
entry->entity = handle;
|
entry->ent = handle;
|
||||||
if (prev) {
|
if (prev) {
|
||||||
entry->prev = prev;
|
entry->prev = prev;
|
||||||
prev->next = entry;
|
prev->next = entry;
|
||||||
|
|||||||
@ -56,7 +56,7 @@ struct sim_ent_lookup_key {
|
|||||||
|
|
||||||
struct sim_ent_lookup_entry {
|
struct sim_ent_lookup_entry {
|
||||||
struct sim_ent_lookup_key key;
|
struct sim_ent_lookup_key key;
|
||||||
struct sim_ent_handle entity;
|
struct sim_ent_handle ent;
|
||||||
struct sim_ent_lookup_entry *next;
|
struct sim_ent_lookup_entry *next;
|
||||||
struct sim_ent_lookup_entry *prev;
|
struct sim_ent_lookup_entry *prev;
|
||||||
};
|
};
|
||||||
@ -75,7 +75,7 @@ struct sim_ent_lookup {
|
|||||||
|
|
||||||
struct sim_control {
|
struct sim_control {
|
||||||
struct v2 move; /* Movement direction vector (speed of 0 -> 1) */
|
struct v2 move; /* Movement direction vector (speed of 0 -> 1) */
|
||||||
struct v2 focus; /* Focus direction vector (where should the entity look) */
|
struct v2 focus; /* Focus direction vector (where should the ent look) */
|
||||||
b32 firing;
|
b32 firing;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -85,17 +85,18 @@ struct sim_ent {
|
|||||||
|
|
||||||
b32 valid; /* Is this ent allocated in memory that can be written to (can always be read) */
|
b32 valid; /* Is this ent allocated in memory that can be written to (can always be read) */
|
||||||
struct sim_ent_handle handle;
|
struct sim_ent_handle handle;
|
||||||
u64 continuity_gen;
|
struct sim_snapshot *ss;
|
||||||
u64 props[(SIM_ENT_PROP_COUNT + 63) / 64];
|
|
||||||
struct sim_ent_handle next_free;
|
|
||||||
|
|
||||||
/* Is this the root entity */
|
u64 props[(SIM_ENT_PROP_COUNT + 63) / 64];
|
||||||
|
u64 continuity_gen;
|
||||||
|
|
||||||
|
/* Is this the root ent */
|
||||||
b32 is_root;
|
b32 is_root;
|
||||||
|
|
||||||
/* Is entity a child of the root entity */
|
/* Is ent a child of the root ent */
|
||||||
b32 is_top;
|
b32 is_top;
|
||||||
|
|
||||||
/* The handle of the top level parent of the entity */
|
/* The handle of the top level parent of the ent */
|
||||||
struct sim_ent_handle top;
|
struct sim_ent_handle top;
|
||||||
|
|
||||||
/* Tree */
|
/* Tree */
|
||||||
@ -104,26 +105,27 @@ struct sim_ent {
|
|||||||
struct sim_ent_handle prev;
|
struct sim_ent_handle prev;
|
||||||
struct sim_ent_handle first;
|
struct sim_ent_handle first;
|
||||||
struct sim_ent_handle last;
|
struct sim_ent_handle last;
|
||||||
|
struct sim_ent_handle next_free;
|
||||||
|
|
||||||
/* ====================================================================== */
|
/* ====================================================================== */
|
||||||
/* Position */
|
/* Position */
|
||||||
|
|
||||||
/* Access with xform getters/setters */
|
/* Access with xform getters/setters */
|
||||||
struct xform local_xform; /* Transform in relation to parent entity (or the world if entity has no parent) */
|
struct xform local_xform; /* Transform in relation to parent ent (or the world if ent has no parent) */
|
||||||
struct xform cached_global_xform; /* Calculated from entity tree */
|
struct xform cached_global_xform; /* Calculated from ent tree */
|
||||||
b32 cached_global_xform_dirty;
|
b32 cached_global_xform_dirty;
|
||||||
|
|
||||||
/* ====================================================================== */
|
/* ====================================================================== */
|
||||||
/* Activation */
|
/* Activation */
|
||||||
|
|
||||||
/* If 0, the entity will auto activate at start of next tick if not already active. */
|
/* If 0, the ent will auto activate at start of next tick if not already active. */
|
||||||
u64 activation_tick;
|
u64 activation_tick;
|
||||||
|
|
||||||
/* ====================================================================== */
|
/* ====================================================================== */
|
||||||
/* Layer */
|
/* Layer */
|
||||||
|
|
||||||
i32 layer;
|
i32 layer;
|
||||||
i32 final_layer; /* Calculated each tick from entity tree */
|
i32 final_layer; /* Calculated each tick from ent tree */
|
||||||
|
|
||||||
/* ====================================================================== */
|
/* ====================================================================== */
|
||||||
/* Collider */
|
/* Collider */
|
||||||
@ -180,8 +182,8 @@ struct sim_ent {
|
|||||||
|
|
||||||
f32 friction;
|
f32 friction;
|
||||||
|
|
||||||
f32 mass_unscaled; /* Mass of entity in kg before any transformations */
|
f32 mass_unscaled; /* Mass of ent in kg before any transformations */
|
||||||
f32 inertia_unscaled; /* Inertia of entity in kg*m^2 before any transformations */
|
f32 inertia_unscaled; /* Inertia of ent in kg*m^2 before any transformations */
|
||||||
|
|
||||||
struct sim_ent_handle ground_friction_joint;
|
struct sim_ent_handle ground_friction_joint;
|
||||||
f32 linear_ground_friction;
|
f32 linear_ground_friction;
|
||||||
@ -206,7 +208,7 @@ struct sim_ent {
|
|||||||
|
|
||||||
struct string sprite_collider_slice; /* Collider will sync to bounds of this slice if set */
|
struct string sprite_collider_slice; /* Collider will sync to bounds of this slice if set */
|
||||||
|
|
||||||
struct xform sprite_local_xform; /* Sprite transform in relation to entity */
|
struct xform sprite_local_xform; /* Sprite transform in relation to ent */
|
||||||
|
|
||||||
/* ====================================================================== */
|
/* ====================================================================== */
|
||||||
/* Animation */
|
/* Animation */
|
||||||
@ -219,7 +221,7 @@ struct sim_ent {
|
|||||||
/* Attachment */
|
/* Attachment */
|
||||||
|
|
||||||
/* SIM_ENT_PROP_ATTACHED */
|
/* SIM_ENT_PROP_ATTACHED */
|
||||||
/* Slice name on the parent entity's sprite to attach to */
|
/* Slice name on the parent ent's sprite to attach to */
|
||||||
struct string attach_slice;
|
struct string attach_slice;
|
||||||
|
|
||||||
/* ====================================================================== */
|
/* ====================================================================== */
|
||||||
@ -295,18 +297,8 @@ struct sim_ent {
|
|||||||
f32 shake;
|
f32 shake;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct sim_ent_store {
|
|
||||||
b32 valid;
|
|
||||||
struct arena arena;
|
|
||||||
|
|
||||||
struct sim_ent_handle first_free;
|
|
||||||
struct sim_ent *entities;
|
|
||||||
u64 num_allocated;
|
|
||||||
u64 num_reserved;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct sim_ent_array {
|
struct sim_ent_array {
|
||||||
struct sim_ent *entities;
|
struct sim_ent *ents;
|
||||||
u64 count;
|
u64 count;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -315,13 +307,6 @@ struct sim_ent_prop_array {
|
|||||||
u64 count;
|
u64 count;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* ========================== *
|
|
||||||
* Startup
|
|
||||||
* ========================== */
|
|
||||||
|
|
||||||
struct sim_ent_startup_receipt { i32 _; };
|
|
||||||
struct sim_ent_startup_receipt sim_ent_startup(void);
|
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
* Handle helpers
|
* Handle helpers
|
||||||
* ========================== */
|
* ========================== */
|
||||||
@ -341,12 +326,6 @@ INLINE struct sim_ent *sim_ent_nil(void)
|
|||||||
return *_g_sim_ent_nil;
|
return *_g_sim_ent_nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
INLINE struct sim_ent_store *sim_ent_store_nil(void)
|
|
||||||
{
|
|
||||||
extern READONLY struct sim_ent_store **_g_sim_ent_store_nil;
|
|
||||||
return *_g_sim_ent_store_nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
* Property helpers
|
* Property helpers
|
||||||
* ========================== */
|
* ========================== */
|
||||||
@ -378,17 +357,12 @@ INLINE b32 sim_ent_is_valid_and_active(struct sim_ent *ent)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
* Entity functions
|
* Ent functions
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
/* Entity store */
|
/* Alloc */
|
||||||
struct sim_ent_store *sim_ent_store_alloc(u64 arena_reserve, b32 create_root);
|
|
||||||
void sim_ent_store_copy(struct sim_ent_store *dst, struct sim_ent_store *src);
|
|
||||||
void sim_ent_store_release(struct sim_ent_store *store);
|
|
||||||
|
|
||||||
/* Entity */
|
|
||||||
struct sim_ent *sim_ent_alloc(struct sim_ent *parent);
|
struct sim_ent *sim_ent_alloc(struct sim_ent *parent);
|
||||||
void sim_ent_release(struct sim_ent_store *store, struct sim_ent *ent);
|
void sim_ent_release(struct sim_snapshot *ss, struct sim_ent *ent);
|
||||||
|
|
||||||
/* Xform */
|
/* Xform */
|
||||||
struct xform sim_ent_get_xform(struct sim_ent *ent);
|
struct xform sim_ent_get_xform(struct sim_ent *ent);
|
||||||
@ -406,10 +380,9 @@ void sim_ent_apply_angular_impulse(struct sim_ent *ent, f32 impulse);
|
|||||||
void sim_ent_apply_torque(struct sim_ent *ent, f32 torque);
|
void sim_ent_apply_torque(struct sim_ent *ent, f32 torque);
|
||||||
|
|
||||||
/* Query */
|
/* Query */
|
||||||
struct sim_ent_store *sim_ent_store_from_ent(struct sim_ent *ent);
|
struct sim_ent *sim_ent_from_handle(struct sim_snapshot *ss, struct sim_ent_handle handle);
|
||||||
struct sim_ent *sim_ent_from_handle(struct sim_ent_store *store, struct sim_ent_handle handle);
|
struct sim_ent *sim_ent_find_first_match_one(struct sim_snapshot *ss, enum sim_ent_prop prop);
|
||||||
struct sim_ent *sim_ent_find_first_match_one(struct sim_ent_store *store, enum sim_ent_prop prop);
|
struct sim_ent *sim_ent_find_first_match_all(struct sim_snapshot *ss, struct sim_ent_prop_array props);
|
||||||
struct sim_ent *sim_ent_find_first_match_all(struct sim_ent_store *store, struct sim_ent_prop_array props);
|
|
||||||
|
|
||||||
/* Tree */
|
/* Tree */
|
||||||
void sim_ent_link_parent(struct sim_ent *parent, struct sim_ent *child);
|
void sim_ent_link_parent(struct sim_ent *parent, struct sim_ent *child);
|
||||||
|
|||||||
@ -20,34 +20,55 @@ GLOBAL struct {
|
|||||||
struct arena nil_arena;
|
struct arena nil_arena;
|
||||||
struct sim_snapshot_store *nil_snapshot_store;
|
struct sim_snapshot_store *nil_snapshot_store;
|
||||||
struct sim_snapshot *nil_snapshot;
|
struct sim_snapshot *nil_snapshot;
|
||||||
|
struct sim_ent *nil_ent;
|
||||||
struct sim_client *nil_client;
|
struct sim_client *nil_client;
|
||||||
} G = ZI, DEBUG_ALIAS(G, G_sim_snapshot);
|
} G = ZI, DEBUG_ALIAS(G, G_sim_snapshot);
|
||||||
|
|
||||||
READONLY struct sim_client **_g_sim_client_nil = &G.nil_client;
|
/* Accessed via `sim_snapshot_store_nil()` */
|
||||||
|
READONLY struct sim_snapshot_store **_g_sim_snapshot_store_nil = &G.nil_snapshot_store;
|
||||||
|
|
||||||
/* Accessed via `sim_snapshot_nil()` */
|
/* Accessed via `sim_snapshot_nil()` */
|
||||||
READONLY struct sim_snapshot **_g_sim_snapshot_nil = &G.nil_snapshot;
|
READONLY struct sim_snapshot **_g_sim_snapshot_nil = &G.nil_snapshot;
|
||||||
|
|
||||||
/* Accessed via `sim_snapshot_store_nil()` */
|
/* Accessed via `sim_ent_nil()` */
|
||||||
READONLY struct sim_snapshot_store **_g_sim_snapshot_store_nil = &G.nil_snapshot_store;
|
READONLY struct sim_ent **_g_sim_ent_nil = &G.nil_ent;
|
||||||
|
|
||||||
|
/* Accessed via `sim_client_nil()` */
|
||||||
|
READONLY struct sim_client **_g_sim_client_nil = &G.nil_client;
|
||||||
|
|
||||||
struct sim_snapshot_startup_receipt sim_snapshot_startup(void)
|
struct sim_snapshot_startup_receipt sim_snapshot_startup(void)
|
||||||
{
|
{
|
||||||
G.nil_arena = arena_alloc(GIGABYTE(1));
|
G.nil_arena = arena_alloc(GIGABYTE(1));
|
||||||
|
|
||||||
|
/* Nil snapshot store */
|
||||||
G.nil_snapshot_store = arena_push_zero(&G.nil_arena, struct sim_snapshot_store);
|
G.nil_snapshot_store = arena_push_zero(&G.nil_arena, struct sim_snapshot_store);
|
||||||
G.nil_snapshot_store->valid = false;
|
G.nil_snapshot_store->valid = false;
|
||||||
|
|
||||||
|
/* Nil snapshot */
|
||||||
G.nil_snapshot = arena_push_zero(&G.nil_arena, struct sim_snapshot);
|
G.nil_snapshot = arena_push_zero(&G.nil_arena, struct sim_snapshot);
|
||||||
G.nil_snapshot->valid = false;
|
G.nil_snapshot->valid = false;
|
||||||
G.nil_snapshot->store = sim_snapshot_store_nil();
|
G.nil_snapshot->store = sim_snapshot_store_nil();
|
||||||
G.nil_snapshot->ent_store = sim_ent_store_nil();
|
|
||||||
|
|
||||||
|
/* Nil ent */
|
||||||
|
G.nil_ent = arena_push_zero(&G.nil_arena, struct sim_ent);
|
||||||
|
G.nil_ent->ss = sim_snapshot_nil();
|
||||||
|
G.nil_ent->valid = false;
|
||||||
|
G.nil_ent->handle = SIM_ENT_NIL_HANDLE;
|
||||||
|
G.nil_ent->local_xform = XFORM_IDENT;
|
||||||
|
G.nil_ent->cached_global_xform = XFORM_IDENT;
|
||||||
|
G.nil_ent->cached_global_xform_dirty = false;
|
||||||
|
G.nil_ent->friction = 0.5f;
|
||||||
|
G.nil_ent->mass_unscaled = 1;
|
||||||
|
G.nil_ent->inertia_unscaled = 1;
|
||||||
|
G.nil_ent->sprite_local_xform = XFORM_IDENT;
|
||||||
|
G.nil_ent->sprite_tint = COLOR_WHITE;
|
||||||
|
|
||||||
|
/* Nil client */
|
||||||
G.nil_client = arena_push_zero(&G.nil_arena, struct sim_client);
|
G.nil_client = arena_push_zero(&G.nil_arena, struct sim_client);
|
||||||
G.nil_client->valid = false;
|
|
||||||
G.nil_client->ss = sim_snapshot_nil();
|
G.nil_client->ss = sim_snapshot_nil();
|
||||||
|
G.nil_client->valid = false;
|
||||||
|
|
||||||
|
/* Lock nil arena */
|
||||||
arena_set_readonly(&G.nil_arena);
|
arena_set_readonly(&G.nil_arena);
|
||||||
return (struct sim_snapshot_startup_receipt ) { 0 };
|
return (struct sim_snapshot_startup_receipt ) { 0 };
|
||||||
}
|
}
|
||||||
@ -76,16 +97,16 @@ void sim_snapshot_store_release(struct sim_snapshot_store *store)
|
|||||||
struct sim_snapshot *ss = sim_snapshot_from_tick(store, store->first_tick);
|
struct sim_snapshot *ss = sim_snapshot_from_tick(store, store->first_tick);
|
||||||
while (ss->valid) {
|
while (ss->valid) {
|
||||||
struct sim_snapshot *next = sim_snapshot_from_tick(store, ss->next_tick);
|
struct sim_snapshot *next = sim_snapshot_from_tick(store, ss->next_tick);
|
||||||
sim_ent_store_release(ss->ent_store);
|
|
||||||
arena_release(&ss->clients_arena);
|
arena_release(&ss->clients_arena);
|
||||||
|
arena_release(&ss->ents_arena);
|
||||||
arena_release(&ss->arena);
|
arena_release(&ss->arena);
|
||||||
ss = next;
|
ss = next;
|
||||||
}
|
}
|
||||||
ss = store->first_free_snapshot;
|
ss = store->first_free_snapshot;
|
||||||
while (ss) {
|
while (ss) {
|
||||||
struct sim_snapshot *next = ss->next_free;
|
struct sim_snapshot *next = ss->next_free;
|
||||||
sim_ent_store_release(ss->ent_store);
|
|
||||||
arena_release(&ss->clients_arena);
|
arena_release(&ss->clients_arena);
|
||||||
|
arena_release(&ss->ents_arena);
|
||||||
arena_release(&ss->arena);
|
arena_release(&ss->arena);
|
||||||
ss = next;
|
ss = next;
|
||||||
}
|
}
|
||||||
@ -108,29 +129,31 @@ struct sim_snapshot *sim_snapshot_alloc(struct sim_snapshot_store *store, struct
|
|||||||
{
|
{
|
||||||
struct arena arena = ZI;
|
struct arena arena = ZI;
|
||||||
struct arena clients_arena = ZI;
|
struct arena clients_arena = ZI;
|
||||||
struct sim_ent_store *ent_store = NULL;
|
struct arena ents_arena = ZI;
|
||||||
{
|
{
|
||||||
ss = store->first_free_snapshot;
|
ss = store->first_free_snapshot;
|
||||||
if (ss) {
|
if (ss) {
|
||||||
/* Re-use existing snasphot arenas */
|
/* Re-use existing snasphot arenas */
|
||||||
store->first_free_snapshot = ss->next_free;
|
store->first_free_snapshot = ss->next_free;
|
||||||
arena = ss->arena;
|
ents_arena = ss->ents_arena;
|
||||||
clients_arena = ss->clients_arena;
|
clients_arena = ss->clients_arena;
|
||||||
ent_store = ss->ent_store;
|
arena = ss->arena;
|
||||||
arena_reset(&ss->arena);
|
|
||||||
arena_reset(&ss->clients_arena);
|
|
||||||
} else {
|
} else {
|
||||||
/* Arenas allocated here will be released along with the entire snasphot store */
|
/* Arenas allocated here will be released along with the entire snasphot store */
|
||||||
arena = arena_alloc(GIGABYTE(64));
|
arena = arena_alloc(GIGABYTE(64));
|
||||||
clients_arena = arena_alloc(GIGABYTE(64));
|
clients_arena = arena_alloc(GIGABYTE(64));
|
||||||
ent_store = sim_ent_store_alloc(GIGABYTE(64), true);
|
ents_arena = arena_alloc(GIGABYTE(64));
|
||||||
ss = arena_push(&arena, struct sim_snapshot);
|
|
||||||
}
|
}
|
||||||
MEMZERO_STRUCT(ss);
|
|
||||||
}
|
}
|
||||||
|
arena_reset(&arena);
|
||||||
|
ss = arena_push_zero(&arena, struct sim_snapshot);
|
||||||
ss->arena = arena;
|
ss->arena = arena;
|
||||||
|
|
||||||
ss->clients_arena = clients_arena;
|
ss->clients_arena = clients_arena;
|
||||||
ss->ent_store = ent_store;
|
arena_reset(&ss->clients_arena);
|
||||||
|
|
||||||
|
ss->ents_arena = ents_arena;
|
||||||
|
arena_reset(&ss->ents_arena);
|
||||||
}
|
}
|
||||||
|
|
||||||
ss->tick = tick;
|
ss->tick = tick;
|
||||||
@ -148,7 +171,7 @@ struct sim_snapshot *sim_snapshot_alloc(struct sim_snapshot_store *store, struct
|
|||||||
ss->continuity_gen = src->continuity_gen;
|
ss->continuity_gen = src->continuity_gen;
|
||||||
ss->local_client = src->local_client;
|
ss->local_client = src->local_client;
|
||||||
|
|
||||||
/* Copy src clients */
|
/* Copy client lookup buckets */
|
||||||
if (src->num_client_lookup_buckets > 0) {
|
if (src->num_client_lookup_buckets > 0) {
|
||||||
ss->num_client_lookup_buckets = src->num_client_lookup_buckets;
|
ss->num_client_lookup_buckets = src->num_client_lookup_buckets;
|
||||||
ss->client_lookup_buckets = arena_push_array(&ss->arena, struct sim_client_lookup_bucket, ss->num_client_lookup_buckets);
|
ss->client_lookup_buckets = arena_push_array(&ss->arena, struct sim_client_lookup_bucket, ss->num_client_lookup_buckets);
|
||||||
@ -157,6 +180,8 @@ struct sim_snapshot *sim_snapshot_alloc(struct sim_snapshot_store *store, struct
|
|||||||
ss->num_client_lookup_buckets = CLIENT_LOOKUP_BUCKETS;
|
ss->num_client_lookup_buckets = CLIENT_LOOKUP_BUCKETS;
|
||||||
ss->client_lookup_buckets = arena_push_array_zero(&ss->arena, struct sim_client_lookup_bucket, ss->num_client_lookup_buckets);
|
ss->client_lookup_buckets = arena_push_array_zero(&ss->arena, struct sim_client_lookup_bucket, ss->num_client_lookup_buckets);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Copy clients */
|
||||||
ss->first_free_client = src->first_free_client;
|
ss->first_free_client = src->first_free_client;
|
||||||
ss->num_clients_allocated = src->num_clients_allocated;
|
ss->num_clients_allocated = src->num_clients_allocated;
|
||||||
ss->num_clients_reserved = src->num_clients_reserved;
|
ss->num_clients_reserved = src->num_clients_reserved;
|
||||||
@ -168,8 +193,29 @@ struct sim_snapshot *sim_snapshot_alloc(struct sim_snapshot_store *store, struct
|
|||||||
dst_client->ss = ss;
|
dst_client->ss = ss;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Copy src entities */
|
/* Copy entities */
|
||||||
sim_ent_store_copy(ss->ent_store, src->ent_store);
|
ss->first_free_ent = src->first_free_ent;
|
||||||
|
ss->num_ents_allocated = src->num_ents_allocated;
|
||||||
|
ss->num_ents_reserved = src->num_ents_reserved;
|
||||||
|
ss->ents = arena_push_array(&ss->ents_arena, struct sim_ent, ss->num_ents_reserved);
|
||||||
|
if (ss->num_ents_reserved == 0) {
|
||||||
|
/* Create root ent if copying from nil store */
|
||||||
|
struct sim_ent *root = arena_push(&ss->ents_arena, struct sim_ent);
|
||||||
|
*root = *sim_ent_nil();
|
||||||
|
root->ss = ss;
|
||||||
|
root->handle = SIM_ENT_ROOT_HANDLE;
|
||||||
|
root->valid = true;
|
||||||
|
root->is_root = true;
|
||||||
|
++ss->num_ents_allocated;
|
||||||
|
++ss->num_ents_reserved;
|
||||||
|
} else {
|
||||||
|
for (u64 i = 0; i < ss->num_ents_reserved; ++i) {
|
||||||
|
struct sim_ent *dst_ent = &ss->ents[i];
|
||||||
|
struct sim_ent *src_ent = &src->ents[i];
|
||||||
|
*dst_ent = *src_ent;
|
||||||
|
dst_ent->ss = ss;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Release duplicate tick if it exists */
|
/* Release duplicate tick if it exists */
|
||||||
{
|
{
|
||||||
@ -342,11 +388,11 @@ struct sim_snapshot *sim_snapshot_alloc_from_lerp(struct sim_snapshot_store *sto
|
|||||||
/* Blend entities */
|
/* Blend entities */
|
||||||
{
|
{
|
||||||
__profscope(snapshot_lerp_entities);
|
__profscope(snapshot_lerp_entities);
|
||||||
u64 num_entities = min_u64(ss0->ent_store->num_reserved, ss1->ent_store->num_reserved);
|
u64 num_entities = min_u64(ss0->num_ents_reserved, ss1->num_ents_reserved);
|
||||||
for (u64 i = 0; i < num_entities; ++i) {
|
for (u64 i = 0; i < num_entities; ++i) {
|
||||||
struct sim_ent *e = &ss->ent_store->entities[i];
|
struct sim_ent *e = &ss->ents[i];
|
||||||
struct sim_ent *e0 = &ss0->ent_store->entities[i];
|
struct sim_ent *e0 = &ss0->ents[i];
|
||||||
struct sim_ent *e1 = &ss1->ent_store->entities[i];
|
struct sim_ent *e1 = &ss1->ents[i];
|
||||||
sim_ent_lerp(e, e0, e1, blend);
|
sim_ent_lerp(e, e0, e1, blend);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -50,9 +50,11 @@ struct sim_snapshot {
|
|||||||
/* Which client in the client store represents the local host in the original snapshot */
|
/* Which client in the client store represents the local host in the original snapshot */
|
||||||
struct sim_client_handle local_client;
|
struct sim_client_handle local_client;
|
||||||
|
|
||||||
/* Clients */
|
/* Client lookup */
|
||||||
struct sim_client_lookup_bucket *client_lookup_buckets;
|
struct sim_client_lookup_bucket *client_lookup_buckets;
|
||||||
u64 num_client_lookup_buckets;
|
u64 num_client_lookup_buckets;
|
||||||
|
|
||||||
|
/* Clients */
|
||||||
struct arena clients_arena;
|
struct arena clients_arena;
|
||||||
struct sim_client *clients;
|
struct sim_client *clients;
|
||||||
struct sim_client_handle first_free_client;
|
struct sim_client_handle first_free_client;
|
||||||
@ -60,7 +62,11 @@ struct sim_snapshot {
|
|||||||
u64 num_clients_reserved;
|
u64 num_clients_reserved;
|
||||||
|
|
||||||
/* Entities */
|
/* Entities */
|
||||||
struct sim_ent_store *ent_store;
|
struct arena ents_arena;
|
||||||
|
struct sim_ent *ents;
|
||||||
|
struct sim_ent_handle first_free_ent;
|
||||||
|
u64 num_ents_allocated;
|
||||||
|
u64 num_ents_reserved;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
|
|||||||
27
src/user.c
27
src/user.c
@ -160,7 +160,6 @@ struct user_startup_receipt user_startup(struct work_startup_receipt *work_sr,
|
|||||||
struct mixer_startup_receipt *mixer_sr,
|
struct mixer_startup_receipt *mixer_sr,
|
||||||
struct phys_startup_receipt *phys_sr,
|
struct phys_startup_receipt *phys_sr,
|
||||||
struct host_startup_receipt *host_sr,
|
struct host_startup_receipt *host_sr,
|
||||||
struct sim_ent_startup_receipt *sim_ent_sr,
|
|
||||||
struct sim_snapshot_startup_receipt *sim_snapshot_sr,
|
struct sim_snapshot_startup_receipt *sim_snapshot_sr,
|
||||||
struct string connect_address_str,
|
struct string connect_address_str,
|
||||||
struct sys_window *window)
|
struct sys_window *window)
|
||||||
@ -201,7 +200,7 @@ struct user_startup_receipt user_startup(struct work_startup_receipt *work_sr,
|
|||||||
sys_window_register_event_callback(G.window, &window_event_callback);
|
sys_window_register_event_callback(G.window, &window_event_callback);
|
||||||
|
|
||||||
if (connect_address_str.len == 0) {
|
if (connect_address_str.len == 0) {
|
||||||
G.local_sim_ctx = sim_ctx_alloc(sprite_sr, phys_sr, host_sr, sim_ent_sr, sim_snapshot_sr, 12345);
|
G.local_sim_ctx = sim_ctx_alloc(sprite_sr, phys_sr, host_sr, sim_snapshot_sr, 12345);
|
||||||
G.connect_address_str = LIT("127.0.0.1:12345");
|
G.connect_address_str = LIT("127.0.0.1:12345");
|
||||||
G.local_sim_thread = sys_thread_alloc(&user_local_sim_thread_entry_point, G.local_sim_ctx, LIT("[P2] Local sim thread"));
|
G.local_sim_thread = sys_thread_alloc(&user_local_sim_thread_entry_point, G.local_sim_ctx, LIT("[P2] Local sim thread"));
|
||||||
} else {
|
} else {
|
||||||
@ -636,15 +635,15 @@ INTERNAL void user_update(void)
|
|||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
struct sim_client *local_client = sim_client_from_handle(G.world, G.world->local_client);
|
struct sim_client *local_client = sim_client_from_handle(G.world, G.world->local_client);
|
||||||
struct sim_ent *local_player = sim_ent_from_handle(G.world->ent_store, local_client->control_ent);
|
struct sim_ent *local_player = sim_ent_from_handle(G.world, local_client->control_ent);
|
||||||
struct sim_ent *local_camera = sim_ent_from_handle(G.world->ent_store, local_client->camera_ent);
|
struct sim_ent *local_camera = sim_ent_from_handle(G.world, local_client->camera_ent);
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
* Apply shake
|
* Apply shake
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
for (u64 ent_index = 0; ent_index < G.world->ent_store->num_reserved; ++ent_index) {
|
for (u64 ent_index = 0; ent_index < G.world->num_ents_reserved; ++ent_index) {
|
||||||
struct sim_ent *ent = &G.world->ent_store->entities[ent_index];
|
struct sim_ent *ent = &G.world->ents[ent_index];
|
||||||
if (!sim_ent_is_valid_and_active(ent)) continue;
|
if (!sim_ent_is_valid_and_active(ent)) continue;
|
||||||
|
|
||||||
/* How much time between camera shakes */
|
/* How much time between camera shakes */
|
||||||
@ -811,8 +810,8 @@ INTERNAL void user_update(void)
|
|||||||
/* Copy valid entities */
|
/* Copy valid entities */
|
||||||
{
|
{
|
||||||
__profscope(copy_sprites_for_sorting);
|
__profscope(copy_sprites_for_sorting);
|
||||||
for (u64 ent_index = 0; ent_index < G.world->ent_store->num_reserved; ++ent_index) {
|
for (u64 ent_index = 0; ent_index < G.world->num_ents_reserved; ++ent_index) {
|
||||||
struct sim_ent *ent = &G.world->ent_store->entities[ent_index];
|
struct sim_ent *ent = &G.world->ents[ent_index];
|
||||||
if (sim_ent_is_valid_and_active(ent)) {
|
if (sim_ent_is_valid_and_active(ent)) {
|
||||||
*arena_push(scratch.arena, struct sim_ent *) = ent;
|
*arena_push(scratch.arena, struct sim_ent *) = ent;
|
||||||
++sorted_count;
|
++sorted_count;
|
||||||
@ -839,7 +838,7 @@ INTERNAL void user_update(void)
|
|||||||
|
|
||||||
struct sprite_tag sprite = ent->sprite;
|
struct sprite_tag sprite = ent->sprite;
|
||||||
|
|
||||||
struct sim_ent *parent = sim_ent_from_handle(G.world->ent_store, ent->parent);
|
struct sim_ent *parent = sim_ent_from_handle(G.world, ent->parent);
|
||||||
|
|
||||||
struct xform xf = sim_ent_get_xform(ent);
|
struct xform xf = sim_ent_get_xform(ent);
|
||||||
struct xform parent_xf = sim_ent_get_xform(parent);
|
struct xform parent_xf = sim_ent_get_xform(parent);
|
||||||
@ -1024,8 +1023,8 @@ INTERNAL void user_update(void)
|
|||||||
/* Draw contact constraint */
|
/* Draw contact constraint */
|
||||||
if (sim_ent_has_prop(ent, SIM_ENT_PROP_CONTACT_CONSTRAINT)) {
|
if (sim_ent_has_prop(ent, SIM_ENT_PROP_CONTACT_CONSTRAINT)) {
|
||||||
struct phys_contact_constraint *data = &ent->contact_constraint_data;
|
struct phys_contact_constraint *data = &ent->contact_constraint_data;
|
||||||
struct sim_ent *e0 = sim_ent_from_handle(G.world->ent_store, data->e0);
|
struct sim_ent *e0 = sim_ent_from_handle(G.world, data->e0);
|
||||||
struct sim_ent *e1 = sim_ent_from_handle(G.world->ent_store, data->e1);
|
struct sim_ent *e1 = sim_ent_from_handle(G.world, data->e1);
|
||||||
(UNUSED)e0;
|
(UNUSED)e0;
|
||||||
(UNUSED)e1;
|
(UNUSED)e1;
|
||||||
|
|
||||||
@ -1098,8 +1097,8 @@ INTERNAL void user_update(void)
|
|||||||
if (sim_ent_has_prop(ent, SIM_ENT_PROP_COLLISION_DEBUG)) {
|
if (sim_ent_has_prop(ent, SIM_ENT_PROP_COLLISION_DEBUG)) {
|
||||||
struct phys_collision_debug *data = &ent->collision_debug_data;
|
struct phys_collision_debug *data = &ent->collision_debug_data;
|
||||||
struct collider_collision_points_result collider_res = data->res;
|
struct collider_collision_points_result collider_res = data->res;
|
||||||
struct sim_ent *e0 = sim_ent_from_handle(G.world->ent_store, data->e0);
|
struct sim_ent *e0 = sim_ent_from_handle(G.world, data->e0);
|
||||||
struct sim_ent *e1 = sim_ent_from_handle(G.world->ent_store, data->e1);
|
struct sim_ent *e1 = sim_ent_from_handle(G.world, data->e1);
|
||||||
struct collider_shape e0_collider = e0->local_collider;
|
struct collider_shape e0_collider = e0->local_collider;
|
||||||
struct collider_shape e1_collider = e1->local_collider;
|
struct collider_shape e1_collider = e1->local_collider;
|
||||||
(UNUSED)e0_collider;
|
(UNUSED)e0_collider;
|
||||||
@ -1499,7 +1498,7 @@ INTERNAL void user_update(void)
|
|||||||
pos.y += spacing;
|
pos.y += spacing;
|
||||||
pos.y += spacing;
|
pos.y += spacing;
|
||||||
|
|
||||||
draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("user entities: %F/%F"), FMT_UINT(G.world->ent_store->num_allocated), FMT_UINT(G.world->ent_store->num_reserved)));
|
draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("user entities: %F/%F"), FMT_UINT(G.world->num_ents_allocated), FMT_UINT(G.world->num_ents_reserved)));
|
||||||
pos.y += spacing;
|
pos.y += spacing;
|
||||||
|
|
||||||
draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("user tick: %F"), FMT_UINT(G.world->tick)));
|
draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("user tick: %F"), FMT_UINT(G.world->tick)));
|
||||||
|
|||||||
@ -12,7 +12,6 @@ struct sound_startup_receipt;
|
|||||||
struct mixer_startup_receipt;
|
struct mixer_startup_receipt;
|
||||||
struct phys_startup_receipt;
|
struct phys_startup_receipt;
|
||||||
struct host_startup_receipt;
|
struct host_startup_receipt;
|
||||||
struct sim_ent_startup_receipt;
|
|
||||||
struct sim_snapshot_startup_receipt;
|
struct sim_snapshot_startup_receipt;
|
||||||
|
|
||||||
enum user_bind_kind {
|
enum user_bind_kind {
|
||||||
@ -62,7 +61,6 @@ struct user_startup_receipt user_startup(struct work_startup_receipt *work_sr,
|
|||||||
struct mixer_startup_receipt *mixer_sr,
|
struct mixer_startup_receipt *mixer_sr,
|
||||||
struct phys_startup_receipt *phys_sr,
|
struct phys_startup_receipt *phys_sr,
|
||||||
struct host_startup_receipt *host_sr,
|
struct host_startup_receipt *host_sr,
|
||||||
struct sim_ent_startup_receipt *sim_ent_sr,
|
|
||||||
struct sim_snapshot_startup_receipt *sim_snapshot_sr,
|
struct sim_snapshot_startup_receipt *sim_snapshot_sr,
|
||||||
struct string connect_address_str,
|
struct string connect_address_str,
|
||||||
struct sys_window *window);
|
struct sys_window *window);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user