Files
coven/core/entity.jai

286 lines
7.3 KiB
Plaintext

Entity_Id :: #type, isa s64;
Entity_Flags :: enum_flags u16 {
NONE :: 0;
RENDERABLE :: 1;
PHYSICS :: 2;
ANIMATED :: 4;
SNAP_TO_GRID :: 8;
UNIFORM_SCALE :: 16;
DONT_SAVE :: 32;
DELETED :: 64;
}
Renderable_Type :: enum {
MODEL;
}
Entity_Material :: struct {
base_color : Vector4;
}
MAX_NODES :: 256;
Node_Render_Data :: struct {
enabled : bool = true;
transform: Transform;
material : Entity_Material;
// Buffers
transform_buffer: Buffer_Handle;
material_buffer: Buffer_Handle;
bone_buffers : [MAX_BONES] Buffer_Handle;
num_bones: s64;
}
Renderable :: struct {
visible: bool = true;
type : Renderable_Type; @DontSerialize
use_default_pipeline: bool = true;
model: Model_Handle; @DontSerialize
nodes: [MAX_NODES] Node_Render_Data; @DontSerialize
num_nodes: s64; @DontSerialize
//node_buffer : Buffer_Handle; // Structure buffer with all transform + material // TODO
}
MAX_CHILDREN :: 16;
#if PHYSICS {
Collider_Type :: enum {
SPHERE;
BOX;
CAPSULE;
TRIANGLE_MESH;
CONVEX_MESH;
CHARACTER;
}
Physics_Lock :: enum_flags u8 {
LINEAR_X;
LINEAR_Y;
LINEAR_Z;
ANGULAR_X;
ANGULAR_Y;
ANGULAR_Z;
}
Physics_Body :: struct {
enabled: bool;
trigger: bool;
dynamic: bool;
velocity: Vector3;
static_friction: float;
dynamic_friction: float;
restitution: float;
render_collider: bool;
collider_color: Color;
lock: Physics_Lock;
offset: Vector3;
type: Collider_Type;
union {
sphere : struct {
radius: float;
}
box : struct {
half_extent: Vector3;
}
capsule : struct {
radius: float;
half_height: float;
}
character : struct {
radius: float;
height: float;
}
}
physx_handle: PhysX_Handle;
}
}
Entity :: struct {
name: string;
id: Entity_Id; @ReadOnly @DontSerialize
type : Type;
enabled: bool = true;
parent: *Entity; @DontSerialize
children: [MAX_CHILDREN] *Entity; @DontSerialize
num_children: s64; @DontSerialize
attach_node_index: s64 = -1; @DontSerialize
flags : Entity_Flags;
transform: Transform;
rendering_offset: Vector3;
snap_offset: Vector3;
snap_intervals: Vector3 = .{1,1,1};
renderable: Renderable;
animator: Animator; @DontSerialize
#if PHYSICS {
physics: Physics_Body; @DontSerialize
}
#if NETWORKING {
remote_id: Entity_Id; @DontSerialize
client_id: Client_Id; @DontSerialize
is_proxy: bool; @DontSerialize
last_replication_time: float; @DontSerialize
}
_locator: Bucket_Locator; @DontSerialize
scene: *Scene; @DontSerialize
using custom_fields: _Custom_Entity_Fields;
}
add_child :: (e: *Entity, child: *Entity, node_name: string = "") {
set_parent(child, e, node_name);
}
set_parent :: (e: *Entity, parent: *Entity, node_name: string = "") {
parent.children[parent.num_children] = e;
e.parent = parent;
parent.num_children += 1;
model := get_model_by_handle(parent.renderable.model);
for node, index: model.nodes {
if node.name == node_name {
e.attach_node_index = index;
break;
}
}
}
set_base_color :: (e: *Entity, color: Vector4, node_name: string = "") {
if e.renderable.type == .MODEL {
model := get_model_by_handle(e.renderable.model);
for i: 0..e.renderable.num_nodes-1 {
actual_node := model.nodes[i];
if node_name.count == 0 || node_name == actual_node.name {
data := *e.renderable.nodes[i];
if data.material_buffer > 0 {
material : Entity_Material = ---;
material.base_color = color;
upload_data_to_buffer(engine.renderer, data.material_buffer, *material, size_of(Entity_Material));
}
}
}
}
}
set_node_enabled :: (e: *Entity, node_name: string, enabled : bool) {
if e.renderable.type == .MODEL {
for i: 0..e.renderable.num_nodes-1 {
actual_node := e.renderable.model.nodes[i];
if node_name.count == 0 || node_name == actual_node.name {
data := *e.renderable.nodes[i];
data.enabled = enabled;
}
}
}
}
get_node_world_position :: (e: *Entity, node_name: string) -> Vector3 {
if e.renderable.type == .MODEL {
model := get_model_by_handle(e.renderable.model);
for i: 0..e.renderable.num_nodes-1 {
actual_node := model.nodes[i];
if node_name.count == 0 || node_name == actual_node.name {
data := *e.renderable.nodes[i];
return Vector3.{data.transform.world_matrix._14, data.transform.world_matrix._24, data.transform.world_matrix._34};
}
}
}
return .{};
}
load_model_into_entity :: (e: *Entity, handle: Model_Handle) {
if handle == 0 {
log_error("MODEL: Attempted to load model into entity of type %, but the model handle is zero. This probably means that the model has not been loaded properly.\n", e.type);
return;
}
model := get_model_by_handle(handle);
e.renderable.type = .MODEL;
assert(model.nodes.count <= MAX_NODES);
e.renderable.num_nodes = model.nodes.count;
e.renderable.model = handle;
for *model.nodes {
data : Node_Render_Data;
data.transform = it.transform;
update_matrix(*it.transform);
if it.meshes.count > 0 {
material : Entity_Material = ---;
material.base_color = it.material_defaults[0].base_color; // @Incomplete: What if there are multiple meshes?
data.material = material;
data.transform_buffer = create_constant_buffer(engine.renderer, null, size_of(Matrix4), mappable=true);
data.material_buffer = create_constant_buffer(engine.renderer, *material, size_of(Entity_Material), mappable=true);
data.num_bones = it.num_bones;
if it.num_bones > 0 {
for bone_index: 0..it.num_bones-1 {
data.bone_buffers[bone_index] = create_constant_buffer(engine.renderer, null, size_of(Matrix4) * MAX_BONES, mappable=true);
}
}
}
e.renderable.nodes[it_index] = data;
}
}
mark_entity_deleted :: (e: *Entity) {
e.flags |= .DELETED;
}
entity_should_be_rendered :: (e: *Entity) -> bool {
if !(e.flags & .RENDERABLE) || (e.flags & .DELETED) || !e.enabled return false;
return true;
}
destroy_entity :: (e: *Entity) {
call_correct_deinit_entity(e);
for 0..e.renderable.num_nodes-1 {
node_data := e.renderable.nodes[it];
if node_data.transform_buffer > 0 {
destroy_buffer(engine.renderer, node_data.transform_buffer);
}
if node_data.material_buffer > 0 {
destroy_buffer(engine.renderer, node_data.material_buffer);
}
for bi: 0..node_data.num_bones-1 {
destroy_buffer(engine.renderer, node_data.bone_buffers[bi]);
}
}
free(e.name);
}