A 3d fps game made in OpenGL
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
Symmetry/src/game/entity.c

725 lines
29 KiB

#include "entity.h"
#include "../common/array.h"
#include "../common/log.h"
#include "../common/string_utils.h"
#include "transform.h"
#include "camera.h"
#include "light.h"
#include "model.h"
#include "material.h"
#include "geometry.h"
#include "framebuffer.h"
#include "scene.h"
#include "../common/variant.h"
#include "../common/parser.h"
#include "../common/hashmap.h"
#include "../system/file_io.h"
#include "../system/physics.h"
#include "scene.h"
#include "game.h"
#include "texture.h"
#include "enemy.h"
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <stdarg.h>
#include <ctype.h>
#include <float.h>
#define MAX_ENTITY_PROP_NAME_LEN 128
#define MAX_ENTITY_PROP_LEN 256
#define MAX_LINE_LEN 512
void entity_init(struct Entity* entity, const char* name, struct Entity* parent)
{
assert(entity);
strncpy(entity->name, name ? name : "DEFAULT_ENTITY_NAME", MAX_ENTITY_NAME_LEN);
entity->name[MAX_ENTITY_NAME_LEN - 1] = '\0';
entity->type = ET_DEFAULT;
entity->archetype_index = -1;
entity->flags = EF_ACTIVE;
entity_bounding_box_reset(entity, false);
entity->derived_bounding_box.min = (vec3){ -0.5f, -0.5f, -0.5f };
entity->derived_bounding_box.max = (vec3){ 0.5f, 0.5f, 0.5f };
transform_init(entity, parent);
}
void entity_reset(struct Entity* entity, int id)
{
assert(entity);
entity->id = id;
entity->type = ET_DEFAULT;
entity->archetype_index = -1;
entity->flags = EF_NONE;
entity_bounding_box_reset(entity, false);
entity->derived_bounding_box.min = (vec3){ -0.5f, -0.5f, -0.5f };
entity->derived_bounding_box.max = (vec3){ 0.5f, 0.5f, 0.5f };
memset(entity->name, '\0', MAX_ENTITY_NAME_LEN);
}
void entity_update_derived_bounding_box(struct Entity* entity)
{
struct Bounding_Box* derived_box = &entity->derived_bounding_box;
vec3_fill(&derived_box->min, FLT_MAX, FLT_MAX, FLT_MAX);
vec3_fill(&derived_box->max, -FLT_MAX, -FLT_MAX, -FLT_MAX);
vec3 box_vertices[8];
bv_bounding_box_vertices_get(&entity->bounding_box, box_vertices);
for(int i = 0; i < 8; i++)
{
vec3 transformed_vertex = { 0.f, 0.f, 0.f };
vec3_mul_mat4(&transformed_vertex, &box_vertices[i], &entity->transform.trans_mat);
if(transformed_vertex.x < derived_box->min.x) derived_box->min.x = transformed_vertex.x;
if(transformed_vertex.y < derived_box->min.y) derived_box->min.y = transformed_vertex.y;
if(transformed_vertex.z < derived_box->min.z) derived_box->min.z = transformed_vertex.z;
if(transformed_vertex.x > derived_box->max.x) derived_box->max.x = transformed_vertex.x;
if(transformed_vertex.y > derived_box->max.y) derived_box->max.y = transformed_vertex.y;
if(transformed_vertex.z > derived_box->max.z) derived_box->max.z = transformed_vertex.z;
}
}
void entity_bounding_box_reset(struct Entity* entity, bool update_derived)
{
if(entity->type == ET_STATIC_MESH)
{
struct Static_Mesh* mesh = (struct Static_Mesh*)entity;
struct Geometry* geom = geom_get(mesh->model.geometry_index);
vec3_assign(&entity->bounding_box.min, &geom->bounding_box.min);
vec3_assign(&entity->bounding_box.max, &geom->bounding_box.max);
}
else
{
vec3_fill(&entity->bounding_box.min, -0.5f, -0.5f, -0.5f);
vec3_fill(&entity->bounding_box.max, 0.5f, 0.5f, 0.5f);
}
if(update_derived) entity_update_derived_bounding_box(entity);
}
bool entity_write(struct Entity* entity, struct Parser_Object* object, bool write_transform)
{
if(!object)
{
log_error("entity:write", "Invalid object");
return false;
}
/* First write all properties common to all entity types */
struct Hashmap* entity_data = object->data;
hashmap_str_set(entity_data, "name", entity->name);
hashmap_int_set(entity_data, "type", entity->type);
hashmap_bool_set(entity_data, "active", entity->flags & EF_ACTIVE ? true : false);
//if(entity->has_collision)
//{
// if(entity->collision.rigidbody)
// hashmap_bool_set(entity_data, "has_rigidbody", true);
// else
// hashmap_bool_set(entity_data, "has_rigidbody", false);
// int shape_type = platform->physics.cs_type_get(entity->collision.collision_shape);
// hashmap_int_set(entity_data, "collision_shape_type", shape_type);
// switch(shape_type)
// {
// case CST_BOX:
// {
// float x, y, z;
// x = y = z = 0.f;
// platform->physics.cs_box_params_get(entity->collision.collision_shape, &x, &y, &z);
// hashmap_float_set(entity_data, "collision_shape_x", x);
// hashmap_float_set(entity_data, "collision_shape_y", y);
// hashmap_float_set(entity_data, "collision_shape_z", z);
// }
// break;
// case CST_SPHERE:
// {
// float radius = 0.f;
// platform->physics.cs_sphere_radius_get(entity->collision.collision_shape);
// hashmap_float_set(entity_data, "collision_shape_radius", radius);
// }
// break;
// case CST_CAPSULE:
// {
// float length = 0.f, radius = 0.f;
// platform->physics.cs_capsule_params_get(entity->collision.collision_shape, &radius, &length);
// hashmap_float_set(entity_data, "collision_shape_length", length);
// hashmap_float_set(entity_data, "collision_shape_radius", radius);
// }
// break;
// case CST_PLANE:
// {
// float a, b, c, d;
// platform->physics.cs_plane_params_get(entity->collision.collision_shape, &a, &b, &c, &d);
// hashmap_float_set(entity_data, "collision_shape_a", a);
// hashmap_float_set(entity_data, "collision_shape_b", b);
// hashmap_float_set(entity_data, "collision_shape_c", c);
// hashmap_float_set(entity_data, "collision_shape_d", d);
// }
// break;
// default: break;
// }
//}
//struct Entity* parent = entity_get_parent(entity->id);
//hashmap_str_set(entity_data, "parent", parent ? parent->name : "NONE");
/* Transform */
hashmap_vec3_set(entity_data, "position", &entity->transform.position);
hashmap_vec3_set(entity_data, "scale", &entity->transform.scale);
hashmap_quat_set(entity_data, "rotation", &entity->transform.rotation);
if(entity->type != ET_STATIC_MESH)
{
hashmap_vec3_set(entity_data, "bouding_box_min", &entity->bounding_box.min);
hashmap_vec3_set(entity_data, "bouding_box_max", &entity->bounding_box.max);
}
switch(entity->type)
{
case ET_CAMERA:
{
struct Camera* camera = (struct Camera*)entity;
hashmap_bool_set(entity_data, "ortho", camera->ortho);
hashmap_bool_set(entity_data, "resizeable", camera->resizeable);
hashmap_float_set(entity_data, "fov", camera->fov);
hashmap_float_set(entity_data, "zoom", camera->zoom);
hashmap_float_set(entity_data, "nearz", camera->nearz);
hashmap_float_set(entity_data, "farz", camera->farz);
hashmap_vec4_set(entity_data, "clear_color", &camera->clear_color);
if(camera->fbo != -1)
{
hashmap_bool_set(entity_data, "has_fbo", true);
hashmap_int_set(entity_data, "fbo_height", framebuffer_height_get(camera->fbo));
hashmap_int_set(entity_data, "fbo_width", framebuffer_width_get(camera->fbo));
hashmap_bool_set(entity_data, "fbo_has_render_tex", camera->render_tex == -1 ? false : true);
hashmap_bool_set(entity_data, "fbo_has_depth_tex", camera->depth_tex == -1 ? false : true);
}
else
{
hashmap_bool_set(entity_data, "has_fbo", true);
}
}
break;
case ET_STATIC_MESH:
{
struct Static_Mesh* mesh = (struct Static_Mesh*)entity;
struct Geometry* geom = geom_get(mesh->model.geometry_index);
hashmap_int_set(entity_data, "material", mesh->model.material->type);
//Set material model params for this particular mesh
struct Model* model = &mesh->model;
switch(model->material->type)
{
case MAT_BLINN:
hashmap_vec4_set(entity_data, "diffuse_color", &model->material_params[MMP_DIFFUSE_COL].val_vec4);
hashmap_str_set(entity_data, "diffuse_texture", model->material_params[MMP_DIFFUSE_TEX].val_int == -1 ? "default.tga" : texture_get_name(model->material_params[MMP_DIFFUSE_TEX].val_int));
hashmap_float_set(entity_data, "diffuse", model->material_params[MMP_DIFFUSE].val_float);
hashmap_float_set(entity_data, "specular", model->material_params[MMP_SPECULAR].val_float);
hashmap_float_set(entity_data, "specular_strength", model->material_params[MMP_SPECULAR_STRENGTH].val_float);
hashmap_vec2_set(entity_data, "uv_scale", &model->material_params[MMP_UV_SCALE].val_vec2);
break;
case MAT_UNSHADED:
hashmap_vec3_set(entity_data, "diffuse_color", &model->material_params[MMP_DIFFUSE_COL].val_vec3);
hashmap_str_set(entity_data, "diffuse_texture", model->material_params[MMP_DIFFUSE_TEX].val_int == -1 ? "default.tga" : texture_get_name(model->material_params[MMP_DIFFUSE_TEX].val_int));
hashmap_vec2_set(entity_data, "uv_scale", &model->material_params[MMP_UV_SCALE].val_vec2);
break;
};
hashmap_str_set(entity_data, "geometry", geom->filename);
}
break;
case ET_LIGHT:
{
struct Light* light = (struct Light*)entity;
hashmap_int_set(entity_data, "light_type", light->type);
hashmap_float_set(entity_data, "outer_angle", light->outer_angle);
hashmap_float_set(entity_data, "inner_angle", light->inner_angle);
hashmap_float_set(entity_data, "falloff", light->falloff);
hashmap_float_set(entity_data, "radius", light->radius);
hashmap_float_set(entity_data, "intensity", light->intensity);
hashmap_float_set(entity_data, "depth_bias", light->depth_bias);
hashmap_bool_set(entity_data, "valid", light->valid);
hashmap_bool_set(entity_data, "cast_shadow", light->cast_shadow);
hashmap_bool_set(entity_data, "pcf_enabled", light->pcf_enabled);
hashmap_vec3_set(entity_data, "color", &light->color);
}
break;
case ET_SOUND_SOURCE:
{
struct Sound_Source* sound_source = (struct Sound_Source*)entity;
hashmap_str_set(entity_data, "source_filename", sound_source->source_buffer->filename);
hashmap_bool_set(entity_data, "playing", sound_source->playing);
hashmap_int_set(entity_data, "sound_type", sound_source->type);
hashmap_bool_set(entity_data, "loop", sound_source->loop);
hashmap_float_set(entity_data, "volume", sound_source->volume);
hashmap_float_set(entity_data, "sound_min_distance", sound_source->min_distance);
hashmap_float_set(entity_data, "sound_max_distance", sound_source->max_distance);
hashmap_float_set(entity_data, "rolloff_factor", sound_source->rolloff_factor);
hashmap_int_set(entity_data, "sound_attenuation_type", sound_source->attenuation_type);
}
break;
case ET_ENEMY:
{
struct Enemy* enemy = (struct Enemy*)entity;
enemy_write(enemy, entity_data);
}
break;
};
return true;
}
bool entity_save(struct Entity* entity, const char* filename, int directory_type)
{
char prefixed_filename[MAX_FILENAME_LEN + 16];
snprintf(prefixed_filename, MAX_FILENAME_LEN + 16, "entities/%s.symtres", filename);
FILE* entity_file = io_file_open(directory_type, prefixed_filename, "w");
if(!entity_file)
{
log_error("entity:save", "Failed to open entity file %s for writing");
return false;
}
struct Parser* parser = parser_new();
struct Parser_Object* object = parser_object_new(parser, PO_ENTITY);
if(!entity_write(entity, object, false))
{
log_error("entity:save", "Failed to save entity : %s to file : %s", entity->name, prefixed_filename);
parser_free(parser);
fclose(entity_file);
return false;
}
// See if the entity has any children, if it does,
// write the entity first then, write all its children
int num_children = array_len(entity->transform.children);
for (int i = 0; i < num_children; i++)
{
struct Parser_Object* child_object = parser_object_new(parser, PO_ENTITY);
struct Entity* child_entity = entity->transform.children[i];
if(!entity_write(child_entity, child_object, true))
{
log_error("entity:save", "Failed to write child entity : %s for parent entity : %s to file : %s", entity->name, child_entity->name, prefixed_filename);
parser_free(parser);
fclose(entity_file);
return false;
}
}
if(parser_write_objects(parser, entity_file, prefixed_filename))
log_message("Entity %s saved to %s", entity->name, prefixed_filename);
//Update the entity's archetype index to the one we just saved
entity->archetype_index = scene_entity_archetype_add(game_state_get()->scene, filename);
parser_free(parser);
fclose(entity_file);
return true;
}
struct Entity* entity_read(struct Parser_Object* object, struct Entity* parent_entity)
{
assert(object);
struct Scene* scene = game_state_get()->scene;
if(object->type != PO_ENTITY)
{
log_error("entity:read", "Invalid object type");
return NULL;
}
const char* name = hashmap_str_get(object->data, "name");
int type = hashmap_int_get(object->data, "type");
if(!name)
{
log_error("entity:read", "No entity name provided");
return NULL;
}
if(type < 0 || type >= ET_MAX)
{
log_error("entity:read", "Invalid entity type");
return NULL;
}
struct Entity* new_entity = NULL;
switch(type)
{
case ET_CAMERA:
{
bool has_fbo = false;
bool fbo_has_depth_tex = false;
bool fbo_has_render_tex = false;
int fbo_width = -1;
int fbo_height = -1;
struct Camera* camera = scene_camera_create(scene, name, parent_entity, 320, 240);
if(!camera) return new_entity;
if(hashmap_value_exists(object->data, "fov")) camera->fov = hashmap_float_get(object->data, "fov");
if(hashmap_value_exists(object->data, "resizeable")) camera->resizeable = hashmap_bool_get(object->data, "resizeable");
if(hashmap_value_exists(object->data, "zoom")) camera->zoom = hashmap_float_get(object->data, "zoom");
if(hashmap_value_exists(object->data, "nearz")) camera->nearz = hashmap_float_get(object->data, "nearz");
if(hashmap_value_exists(object->data, "farz")) camera->farz = hashmap_float_get(object->data, "farz");
if(hashmap_value_exists(object->data, "ortho")) camera->ortho = hashmap_bool_get(object->data, "ortho");
if(hashmap_value_exists(object->data, "has_fbo")) has_fbo = hashmap_bool_get(object->data, "has_fbo");
if(hashmap_value_exists(object->data, "fbo_has_depth_tex")) fbo_has_depth_tex = hashmap_bool_get(object->data, "fbo_has_depth_tex");
if(hashmap_value_exists(object->data, "fbo_has_render_tex")) fbo_has_render_tex = hashmap_bool_get(object->data, "fbo_has_render_tex");
if(hashmap_value_exists(object->data, "fbo_width")) fbo_width = hashmap_int_get(object->data, "fbo_width");
if(hashmap_value_exists(object->data, "fbo_height")) fbo_height = hashmap_int_get(object->data, "fbo_height");
if(hashmap_value_exists(object->data, "clear_color"))
{
vec4 color = hashmap_vec4_get(object->data, "clear_color");
vec4_assign(&camera->clear_color, &color);
}
float aspect_ratio = (float)fbo_width / (float)fbo_height;
camera->aspect_ratio = aspect_ratio <= 0.f ? (4.f / 3.f) : aspect_ratio;
camera->fbo = -1;
camera->render_tex = -1;
camera->depth_tex = -1;
if(has_fbo)
{
camera_attach_fbo(camera, fbo_width, fbo_height, fbo_has_depth_tex, fbo_has_render_tex, camera->resizeable);
}
camera_update_proj(camera);
camera_update_view(camera);
new_entity = &camera->base;
}
break;
case ET_LIGHT:
{
struct Light* light = scene_light_create(scene, name, parent_entity, LT_POINT);
if(!light)
return new_entity;
if(hashmap_value_exists(object->data, "light_type")) light->type = hashmap_int_get(object->data, "light_type");
if(hashmap_value_exists(object->data, "outer_angle")) light->outer_angle = hashmap_float_get(object->data, "outer_angle");
if(hashmap_value_exists(object->data, "inner_angle")) light->inner_angle = hashmap_float_get(object->data, "inner_angle");
if(hashmap_value_exists(object->data, "falloff")) light->falloff = hashmap_float_get(object->data, "falloff");
if(hashmap_value_exists(object->data, "intensity")) light->intensity = hashmap_float_get(object->data, "intensity");
if(hashmap_value_exists(object->data, "depth_bias")) light->depth_bias = hashmap_float_get(object->data, "depth_bias");
if(hashmap_value_exists(object->data, "color")) light->color = hashmap_vec3_get(object->data, "color");
if(hashmap_value_exists(object->data, "cast_shadow")) light->cast_shadow = hashmap_bool_get(object->data, "cast_shadow");
if(hashmap_value_exists(object->data, "pcf_enabled")) light->pcf_enabled = hashmap_bool_get(object->data, "pcf_enabled");
if(hashmap_value_exists(object->data, "radius")) light->radius = hashmap_int_get(object->data, "radius");
new_entity = &light->base;
}
break;
case ET_SOUND_SOURCE:
{
struct Sound_Source* sound_source = scene_sound_source_create(scene, name, parent_entity, "sounds/teh_beatz.wav", ST_WAV, true, true);
if(!sound_source)
return new_entity;
struct Sound_Source_Buffer* default_source_buffer = sound_source->source_buffer;
uint default_source_instance = sound_source->source_instance;
if(hashmap_value_exists(object->data, "playing")) sound_source->playing = hashmap_bool_get(object->data, "playing");
if(hashmap_value_exists(object->data, "loop")) sound_source->loop = hashmap_bool_get(object->data, "loop");
if(hashmap_value_exists(object->data, "sound_min_distance")) sound_source->min_distance = hashmap_float_get(object->data, "sound_min_distance");
if(hashmap_value_exists(object->data, "sound_max_distance")) sound_source->max_distance = hashmap_float_get(object->data, "sound_max_distance");
if(hashmap_value_exists(object->data, "volume")) sound_source->volume = hashmap_float_get(object->data, "volume");
if(hashmap_value_exists(object->data, "rolloff_factor")) sound_source->rolloff_factor = hashmap_float_get(object->data, "rolloff_factor");
if(hashmap_value_exists(object->data, "sound_type")) sound_source->type = hashmap_int_get(object->data, "sound_type");
if(hashmap_value_exists(object->data, "sound_attenuation_type")) sound_source->attenuation_type = hashmap_int_get(object->data, "sound_attenuation_type");
if(hashmap_value_exists(object->data, "source_filename"))
{
struct Sound* sound = game_state_get()->sound;
sound_source->source_buffer = sound_source_buffer_create(sound, hashmap_str_get(object->data, "source_filename"), sound_source->type);
if(sound_source->source_buffer)
{
sound_source->source_instance = sound_source_instance_create(sound, sound_source->source_buffer, true);
vec3 abs_pos = {0.f, 0.f, 0.f};
transform_get_absolute_position(sound_source, &abs_pos);
sound_source_instance_update_position(sound, sound_source->source_instance, abs_pos);
sound_source_instance_loop_set(sound, sound_source->source_instance, sound_source->loop);
sound_source_instance_min_max_distance_set(sound, sound_source->source_instance, sound_source->min_distance, sound_source->max_distance);
sound_source_instance_attenuation_set(sound, sound_source->source_instance, sound_source->attenuation_type, sound_source->rolloff_factor);
sound_source_instance_volume_set(sound, sound_source->source_instance, sound_source->volume);
sound_update_3d(sound);
if(sound_source->playing)
sound_source_instance_play(sound, sound_source->source_instance);
//Stop the default sound source from playing now that we have loaded the actual buffer
sound_source_instance_destroy(sound, default_source_instance);
}
else
{
log_error("Failed to create sound source from '%s'", hashmap_str_get(object->data, "source_filename"));
}
}
else
{
log_error("entity:read", "No filename provided for sound source for entity '%s'", name);
}
new_entity = &sound_source->base;
}
break;
case ET_STATIC_MESH:
{
const char* geometry_name = NULL;
int material_type = MAT_UNSHADED;
if(hashmap_value_exists(object->data, "geometry")) geometry_name = hashmap_str_get(object->data, "geometry");
if(hashmap_value_exists(object->data, "material")) material_type = hashmap_int_get(object->data, "material");
struct Static_Mesh* mesh = scene_static_mesh_create(scene, name, parent_entity, geometry_name, material_type);
if(!mesh)
return new_entity;
new_entity = &mesh->base;
//Set material model params for this particular mesh
struct Model* model = &mesh->model;
switch(model->material->type)
{
case MAT_BLINN:
if(hashmap_value_exists(object->data, "diffuse_texture"))
{
const char* texture_name = hashmap_str_get(object->data, "diffuse_texture");
model->material_params[MMP_DIFFUSE_TEX].val_int = texture_create_from_file(texture_name, TU_DIFFUSE);
}
if(hashmap_value_exists(object->data, "diffuse_color")) model->material_params[MMP_DIFFUSE_COL].val_vec4 = hashmap_vec4_get(object->data, "diffuse_color");
if(hashmap_value_exists(object->data, "diffuse")) model->material_params[MMP_DIFFUSE].val_float = hashmap_float_get(object->data, "diffuse");
if(hashmap_value_exists(object->data, "specular")) model->material_params[MMP_SPECULAR].val_float = hashmap_float_get(object->data, "specular");
if(hashmap_value_exists(object->data, "specular_strength")) model->material_params[MMP_SPECULAR_STRENGTH].val_float = hashmap_float_get(object->data, "specular_strength");
if(hashmap_value_exists(object->data, "uv_scale")) model->material_params[MMP_UV_SCALE].val_vec2 = hashmap_vec2_get(object->data, "uv_scale");
break;
case MAT_UNSHADED:
if(hashmap_value_exists(object->data, "diffuse_color")) model->material_params[MMP_DIFFUSE_COL].val_vec4 = hashmap_vec4_get(object->data, "diffuse_color");
if(hashmap_value_exists(object->data, "diffuse_texture"))
{
const char* texture_name = hashmap_str_get(object->data, "diffuse_texture");
model->material_params[MMP_DIFFUSE_TEX].val_int = texture_create_from_file(texture_name, TU_DIFFUSE);
}
if(hashmap_value_exists(object->data, "uv_scale")) model->material_params[MMP_UV_SCALE].val_vec2 = hashmap_vec2_get(object->data, "uv_scale");
break;
};
}
break;
case ET_ENEMY:
{
new_entity = &enemy_read(object, name, parent_entity)->base;
if(!new_entity)
return new_entity;
}
break;
default:
log_warning("Unhandled Entity type '%d' detected", type);
break;
}
vec3 position = { 0.f, 0.f, 0.f };
quat rotation = { 0.f, 0.f, 0.f, 1.f };
vec3 scale = { 1.f, 1.f, 1.f };
if(hashmap_value_exists(object->data, "position")) position = hashmap_vec3_get(object->data, "position");
if(hashmap_value_exists(object->data, "rotation")) rotation = hashmap_quat_get(object->data, "rotation");
if(hashmap_value_exists(object->data, "scale")) scale = hashmap_vec3_get(object->data, "scale");
transform_set_position(new_entity, &position);
transform_scale(new_entity, &scale);
quat_mul(&new_entity->transform.rotation, &new_entity->transform.rotation, &rotation);
if(new_entity->type != ET_STATIC_MESH)
{
if(hashmap_value_exists(object->data, "bounding_box_min")) new_entity->bounding_box.min = hashmap_vec3_get(object->data, "bounding_box_min");
if(hashmap_value_exists(object->data, "bounding_box_max")) new_entity->bounding_box.max = hashmap_vec3_get(object->data, "bounding_box_max");
}
transform_update_transmat(new_entity);
return new_entity;
}
struct Entity* entity_load(const char* filename, int directory_type)
{
char prefixed_filename[MAX_FILENAME_LEN + 16];
snprintf(prefixed_filename, MAX_FILENAME_LEN + 16, "entities/%s.symtres", filename);
FILE* entity_file = io_file_open(directory_type, prefixed_filename, "rb");
if(!entity_file)
{
log_error("entity:load", "Failed to open entity file %s for reading", prefixed_filename);
return false;
}
struct Parser* parsed_file = parser_load_objects(entity_file, prefixed_filename);
struct Entity* new_entity = false;
if(!parsed_file)
{
log_error("entity:load", "Failed to parse file '%s' for entity definition", prefixed_filename);
fclose(entity_file);
return false;
}
if(array_len(parsed_file->objects) == 0)
{
log_error("entity:load", "No objects found in file %s", prefixed_filename);
parser_free(parsed_file);
fclose(entity_file);
return false;
}
int num_entites_loaded = 0;
struct Entity* parent_entity = NULL;
for(int i = 0; i < array_len(parsed_file->objects); i++)
{
struct Parser_Object* object = &parsed_file->objects[i];
if(object->type != PO_ENTITY) continue;
new_entity = entity_read(object, parent_entity);
if(new_entity)
{
if(i == 0)
{
new_entity->archetype_index = scene_entity_archetype_add(game_state_get()->scene, filename);
parent_entity = new_entity;
}
// We don't want this entity to be saved when we're saving the scene because
// this entity and its parent will be loaded from this same file next time the scene is loaded
if(i != 0)
new_entity->flags |= EF_TRANSIENT;
num_entites_loaded++;
log_message("Entity %s loaded from %s", new_entity->name, prefixed_filename);
}
else
{
log_error("entity:load", "Failed to load entity from %s", prefixed_filename);
}
}
parser_free(parsed_file);
fclose(entity_file);
return parent_entity;
}
const char* entity_type_name_get(struct Entity* entity)
{
const char* typename = "NONE";
switch(entity->type)
{
case ET_NONE: typename = "None"; break;
case ET_DEFAULT: typename = "Default"; break;
case ET_CAMERA: typename = "Camera"; break;
case ET_LIGHT: typename = "Light"; break;
case ET_PLAYER: typename = "Player"; break;
case ET_ROOT: typename = "Root"; break;
case ET_SOUND_SOURCE: typename = "Sound Source"; break;
case ET_STATIC_MESH: typename = "Static Mesh"; break;
default: typename = "Unknown"; break;
};
return typename;
}
void entity_rigidbody_on_move(Rigidbody body)
{
struct Entity* entity = physics_body_data_get(body);
vec3 pos = {0.f};
quat rot = {0.f};
physics_body_position_get(body, &pos.x, &pos.y, &pos.z);
physics_body_rotation_get(body, &rot.x, &rot.y, &rot.z, &rot.w);
quat_assign(&entity->transform.rotation, &rot);
transform_set_position(entity, &pos);
entity->transform.sync_physics = false;
}
void entity_rigidbody_on_collision(Rigidbody body_A, Rigidbody body_B)
{
struct Entity* ent_A = NULL;
struct Entity* ent_B = NULL;
if(body_A)
{
ent_A = physics_body_data_get(body_A);
}
if(body_B)
{
ent_B = physics_body_data_get(body_B);
}
//if(ent_A && ent_A->collision.on_collision)
//{
// ent_A->collision.on_collision(ent_A, ent_B ? ent_B : NULL, body_A, body_B ? body_B : NULL);
//}
//if(ent_B && ent_B->collision.on_collision)
//{
// ent_B->collision.on_collision(ent_B, ent_A ? ent_A : NULL, body_B, body_A ? body_A : NULL);
//}
if(ent_A && ent_B)
{
//log_message("Entity %s collided with Entity %s", ent_A->name, ent_B->name);
}
}
void entity_rigidbody_set(struct Entity * entity, struct Collision* collision, Rigidbody body)
{
assert(entity && body);
//Remove previous rigidbody if there is any
if(collision->rigidbody || collision->collision_shape)
{
if(collision->rigidbody)
{
physics_body_remove(collision->rigidbody);
}
else if(collision->collision_shape)
{
physics_cs_remove(collision->collision_shape);
}
collision->rigidbody = NULL;
collision->collision_shape = NULL;
}
collision->rigidbody = body;
collision->collision_shape = physics_body_cs_get(body);
vec3 abs_pos = {0.f, 0.f, 0.f};
quat abs_rot = {0.f, 0.f, 0.f, 1.f};
transform_get_absolute_position(entity, &abs_pos);
transform_get_absolute_rot(entity, &abs_rot);
physics_body_rotation_set(body, abs_rot.x, abs_rot.y, abs_rot.z, abs_rot.w);
physics_body_position_set(body, abs_pos.x, abs_pos.y, abs_pos.z);
physics_body_data_set(body, entity);
}
void entity_collision_shape_set(struct Entity* entity, struct Collision* collision, Collision_Shape shape)
{
assert(entity && shape);
if(collision->rigidbody || collision->collision_shape)
{
if(collision->rigidbody)
{
physics_body_remove(collision->rigidbody);
}
else if(collision->collision_shape)
{
physics_cs_remove(collision->collision_shape);
}
collision->rigidbody = NULL;
collision->collision_shape = NULL;
}
collision->collision_shape = shape;
physics_cs_data_set(shape, entity);
}
void entity_rename(struct Entity* entity, const char* new_name)
{
assert(entity);
memset(entity->name, '\0', MAX_ENTITY_NAME_LEN);
snprintf(entity->name, MAX_ENTITY_NAME_LEN, new_name);
}