#ifndef ENTITY_H #define ENTITY_H #include "sprite.h" #include "mixer.h" #include "phys.h" #include "client.h" enum entity_prop { ENTITY_PROP_NONE, ENTITY_PROP_ACTIVE, ENTITY_PROP_RELEASE_THIS_TICK, ENTITY_PROP_RELEASE_NEXT_TICK, ENTITY_PROP_PHYSICAL_DYNAMIC, ENTITY_PROP_PHYSICAL_KINEMATIC, ENTITY_PROP_COLLISION_DEBUG, ENTITY_PROP_CONTACT_CONSTRAINT, ENTITY_PROP_MOTOR_JOINT, ENTITY_PROP_MOUSE_JOINT, ENTITY_PROP_SENSOR, ENTITY_PROP_PLAYER_CONTROLLED, ENTITY_PROP_CAMERA, ENTITY_PROP_CAMERA_ACTIVE, ENTITY_PROP_WEAPON, ENTITY_PROP_TRIGGERING_EQUIPPED, ENTITY_PROP_TRIGGERED_THIS_TICK, ENTITY_PROP_TRIGGER_NEXT_TICK, ENTITY_PROP_BULLET, ENTITY_PROP_TRACER, ENTITY_PROP_QUAKE, ENTITY_PROP_ATTACHED, /* Test props */ ENTITY_PROP_TEST, ENTITY_PROP_TEST_SOUND_EMITTER, ENTITY_PROP_COUNT }; struct entity_store { b32 valid; struct arena arena; u64 allocated; u64 reserved; struct entity_handle first_free; struct entity_handle root; struct entity *entities; }; struct entity_lookup_key { u64 hash; }; struct entity_lookup_entry { struct entity_lookup_key key; struct entity_handle entity; struct entity_lookup_entry *next; struct entity_lookup_entry *prev; }; struct entity_lookup_bucket { struct entity_lookup_entry *first; struct entity_lookup_entry *last; }; struct entity_lookup { struct arena arena; struct entity_lookup_bucket *buckets; u64 num_buckets; struct entity_lookup_entry *first_free_entry; }; struct entity { /* ====================================================================== */ /* Metadata */ b32 valid; /* Is this entity allocated in memory that can be written to (can always be read) */ struct entity_handle handle; u64 continuity_gen; u64 props[(ENTITY_PROP_COUNT + 63) / 64]; struct entity_handle next_free; /* Is this the root entity */ b32 is_root; /* Is entity a child of the root entity */ b32 is_top; /* The handle of the top level parent of the entity */ struct entity_handle top; /* Tree */ struct entity_handle parent; struct entity_handle next; struct entity_handle prev; struct entity_handle first; struct entity_handle last; /* ====================================================================== */ /* Position */ /* 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 cached_global_xform; /* Calculated from entity tree */ b32 cached_global_xform_dirty; /* ====================================================================== */ /* Activation */ /* If 0, the entity will auto activate at start of next tick if not already active. */ u64 activation_tick; /* ====================================================================== */ /* Layer */ i32 layer; i32 final_layer; /* Calculated each tick from entity tree */ /* ====================================================================== */ /* Collider */ struct collider_shape local_collider; #if COLLIDER_DEBUG struct phys_collision_debug collision_debug_data; #endif struct space_entry_handle space_handle; /* ====================================================================== */ /* Contact constraint */ /* ENTITY_PROP_CONSTRAINT_CONTACT */ struct phys_contact_constraint contact_constraint_data; /* ====================================================================== */ /* Motor joint */ /* ENTITY_PROP_MOTOR_JOINT */ struct phys_motor_joint motor_joint_data; /* ====================================================================== */ /* Mouse joint */ /* ENTITY_PROP_MOUSE_JOINT */ struct phys_mouse_joint mouse_joint_data; /* ====================================================================== */ /* Player */ /* ENTITY_PROP_PLAYER_CONTROLLED */ struct client_handle controlling_client; /* ====================================================================== */ /* Control */ f32 control_force; /* How much force is applied to achieve desired control movement */ f32 control_force_max_speed; /* Maximum linear velocity achieved by force (m/s) */ f32 control_torque; /* How much torque is applied when turning towards desired focus */ struct { struct v2 move; /* Movement direction vector (speed of 0 -> 1) */ struct v2 focus; /* Focus direction vector (where should the entity look) */ } control; struct entity_handle move_joint; struct entity_handle aim_joint; /* ====================================================================== */ /* Physics */ /* ENTITY_PROP_PHYSICAL_DYNAMIC */ //f32 density; /* Density in kg/m^2 */ f32 friction; f32 mass_unscaled; /* Mass of entity in kg before any transformations */ f32 inertia_unscaled; /* Inertia of entity in kg*m^2 before any transformations */ struct entity_handle ground_friction_joint; f32 linear_ground_friction; f32 angular_ground_friction; /* Use entity_set_linear_velocity & entity_set_angular_velocity to set */ struct v2 linear_velocity; /* m/s */ f32 angular_velocity; /* rad/s */ struct v2 force; f32 torque; f32 linear_damping; f32 angular_damping; /* ====================================================================== */ /* Sprite */ struct sprite_tag sprite; struct string sprite_span_name; u32 sprite_tint; 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 */ /* ====================================================================== */ /* Animation */ /* ENTITY_PROP_ANIMATING */ f64 animation_time_in_frame; u32 animation_frame; /* ====================================================================== */ /* Attachment */ /* ENTITY_PROP_ATTACHED */ /* Slice name on the parent entity's sprite to attach to */ struct string attach_slice; /* ====================================================================== */ /* Equip */ struct entity_handle equipped; /* ====================================================================== */ /* Triggers */ /* ENTITY_PROP_TRIGGERED_THIS_TICK */ f32 trigger_delay; /* Minimum time between triggers */ f32 last_triggered; /* ====================================================================== */ /* Bullet */ struct entity_handle bullet_src; struct entity_handle bullet_tracer; struct v2 bullet_src_pos; struct v2 bullet_src_dir; f32 bullet_impulse; f32 bullet_knockback; b32 bullet_has_hit; /* ====================================================================== */ /* Tracer */ /* ENTITY_PROP_TRACER */ struct v2 tracer_start; struct v2 tracer_start_velocity; f32 tracer_fade_duration; /* Time for tracer to fade from opacity of 1 to 0 */ /* calculated each frame */ struct v2 tracer_gradient_start; struct v2 tracer_gradient_end; /* ====================================================================== */ /* Quake */ /* ENTITY_PROP_QUAKE */ f32 quake_intensity; f32 quake_frequency; f32 quake_fade; /* How much intensity to lose per second */ /* ====================================================================== */ /* Testing */ /* ENTITY_PROP_TEST */ b32 test_initialized; struct xform test_start_local_xform; struct xform test_start_sprite_xform; /* ENTITY_PROP_TEST_SOUND_EMITTER */ struct string sound_name; struct mixer_desc sound_desc; struct mixer_track_handle sound_handle; /* ====================================================================== */ /* Camera */ /* ENTITY_PROP_CAMERA */ struct entity_handle camera_follow; struct xform camera_quad_xform; f32 camera_lerp; /* Rate at which camera xform approaches target xform */ u32 camera_lerp_continuity_gen; struct xform camera_xform_target; /* Calculated from camera_follow */ u32 camera_applied_lerp_continuity_gen_plus_one; /* Calculated */ f32 shake; }; struct entity_array { struct entity *entities; u64 count; }; struct entity_prop_array { enum entity_prop *props; u64 count; }; /* ========================== * * Handle helpers * ========================== */ INLINE struct entity_handle entity_handle_nil(void) { return (struct entity_handle) { 0 }; } INLINE b32 entity_handle_eq(struct entity_handle a, struct entity_handle b) { return a.gen == b.gen && a.idx == b.idx; } /* ========================== * * Nil * ========================== */ INLINE struct entity *entity_nil(void) { extern READONLY struct entity _g_entity_nil; return &_g_entity_nil; } INLINE struct entity_store *entity_store_nil(void) { extern READONLY struct entity_store _g_entity_store_nil; return &_g_entity_store_nil; } /* ========================== * * Property helpers * ========================== */ INLINE void entity_enable_prop(struct entity *ent, enum entity_prop prop) { u64 index = prop / 64; u64 bit = prop % 64; ent->props[index] |= ((u64)1 << bit); } INLINE void entity_disable_prop(struct entity *ent, enum entity_prop prop) { u64 index = prop / 64; u64 bit = prop % 64; ent->props[index] &= ~((u64)1 << bit); } INLINE b32 entity_has_prop(struct entity *ent, enum entity_prop prop) { u64 index = prop / 64; u64 bit = prop % 64; return !!(ent->props[index] & ((u64)1 << bit)); } INLINE b32 entity_is_valid_and_active(struct entity *ent) { return ent->valid && entity_has_prop(ent, ENTITY_PROP_ACTIVE); } /* ========================== * * Entity functions * ========================== */ /* Entity store */ struct entity_store *entity_store_alloc(void); void entity_store_release(struct entity_store *store); void entity_store_copy_replace(struct entity_store *dest, struct entity_store *src); /* Entity */ struct entity *entity_alloc(struct entity *parent); void entity_release(struct entity_store *store, struct entity *ent); /* Xform */ struct xform entity_get_xform(struct entity *ent); struct xform entity_get_local_xform(struct entity *ent); void entity_set_xform(struct entity *ent, struct xform xf); void entity_set_local_xform(struct entity *ent, struct xform xf); /* Movement */ INLINE void entity_set_linear_velocity(struct entity *ent, struct v2 velocity) { ent->linear_velocity = v2_clamp_len(velocity, GAME_MAX_LINEAR_VELOCITY); } INLINE void entity_set_angular_velocity(struct entity *ent, f32 velocity) { ent->angular_velocity = clamp_f32(velocity, -GAME_MAX_ANGULAR_VELOCITY, GAME_MAX_ANGULAR_VELOCITY); } void entity_apply_linear_impulse(struct entity *ent, struct v2 impulse, struct v2 world_point); void entity_apply_linear_impulse_to_center(struct entity *ent, struct v2 impulse); void entity_apply_force_to_center(struct entity *ent, struct v2 force); void entity_apply_angular_impulse(struct entity *ent, f32 impulse); void entity_apply_torque(struct entity *ent, f32 torque); /* Query */ struct entity_store *entity_store_from_entity(struct entity *ent); struct entity *entity_from_handle(struct entity_store *store, struct entity_handle handle); struct entity *entity_find_first_match_one(struct entity_store *store, enum entity_prop prop); struct entity *entity_find_first_match_all(struct entity_store *store, struct entity_prop_array props); /* Tree */ void entity_link_parent(struct entity *parent, struct entity *child); void entity_unlink_from_parent(struct entity *ent); /* Lookup */ struct entity_lookup entity_lookup_alloc(u64 num_buckets); void entity_lookup_release(struct entity_lookup *l); struct entity_lookup_entry *entity_lookup_get(struct entity_lookup *l, struct entity_lookup_key key); void entity_lookup_set(struct entity_lookup *l, struct entity_lookup_key key, struct entity_handle handle); void entity_lookup_remove(struct entity_lookup *l, struct entity_lookup_entry *entry); struct entity_lookup_key entity_lookup_key_from_two_handles(struct entity_handle h0, struct entity_handle h1); /* Activate */ void entity_activate(struct entity *ent, u64 current_tick_id); #endif