Implemented reading/writing entity's children to file when saving an entity archetype and fixed a bug where an entity would not be removed from its parent's children list

dev
Shariq Shah 6 years ago
parent 665940ccad
commit 78992826d6
  1. 63
      src/game/entity.c
  2. 4
      src/game/entity.h
  3. 18
      src/game/game.c
  4. 15
      src/game/transform.c
  5. 4
      src/system/file_io.c
  6. 9
      todo.txt
  7. 3
      tools/setup_env.bat

@ -52,7 +52,7 @@ void entity_reset(struct Entity * entity, int id)
}
bool entity_write(struct Entity* entity, struct Parser_Object* object)
bool entity_write(struct Entity* entity, struct Parser_Object* object, bool write_transform)
{
if(!object)
{
@ -121,10 +121,14 @@ bool entity_write(struct Entity* entity, struct Parser_Object* object)
//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);
/* Transform */
if(write_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);
}
switch(entity->type)
{
case ET_CAMERA:
@ -205,15 +209,29 @@ bool entity_save(struct Entity* entity, const char* filename, int directory_type
struct Parser* parser = parser_new();
struct Parser_Object* object = parser_object_new(parser, PO_ENTITY);
if(!entity_write(entity, object))
if(!entity_write(entity, object, false))
{
log_error("entity:save", "Failed to save entity : %s to file : %s", entity->name, 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, filename);
parser_free(parser);
fclose(entity_file);
return false;
}
}
if(parser_write_objects(parser, entity_file, filename))
log_message("Entity %s saved to %s", entity->name, filename);
@ -223,7 +241,7 @@ bool entity_save(struct Entity* entity, const char* filename, int directory_type
return true;
}
struct Entity* entity_read(struct Parser_Object* object)
struct Entity* entity_read(struct Parser_Object* object, struct Entity* parent_entity)
{
assert(object);
@ -259,7 +277,7 @@ struct Entity* entity_read(struct Parser_Object* object)
bool fbo_has_render_tex = false;
int fbo_width = -1;
int fbo_height = -1;
struct Camera* camera = scene_camera_create(scene, name, NULL, 320, 240);
struct Camera* camera = scene_camera_create(scene, name, parent_entity, 320, 240);
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");
@ -296,7 +314,7 @@ struct Entity* entity_read(struct Parser_Object* object)
break;
case ET_LIGHT:
{
struct Light* light = scene_light_create(scene, name, NULL, LT_POINT);
struct Light* light = scene_light_create(scene, name, parent_entity, LT_POINT);
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");
@ -312,7 +330,7 @@ struct Entity* entity_read(struct Parser_Object* object)
break;
case ET_SOUND_SOURCE:
{
struct Sound_Source* sound_source = scene_sound_source_create(scene, name, NULL, "sounds/teh_beatz.wav", ST_WAV, true, true);
struct Sound_Source* sound_source = scene_sound_source_create(scene, name, parent_entity, "sounds/teh_beatz.wav", ST_WAV, true, true);
struct Sound_Source_Buffer* default_source_buffer = sound_source->source_buffer;
uint default_source_instance = sound_source->source_instance;
@ -372,7 +390,7 @@ struct Entity* entity_read(struct Parser_Object* object)
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_type")) material_type = hashmap_int_get(object->data, "material_type");
struct Static_Mesh* mesh = scene_static_mesh_create(scene, name, NULL, geometry_name, material_type);
struct Static_Mesh* mesh = scene_static_mesh_create(scene, name, parent_entity, geometry_name, material_type);
new_entity = &mesh->base;
}
break;
@ -386,6 +404,24 @@ struct Entity* entity_read(struct Parser_Object* object)
break;
}
//If there's a parent entity then it means this is a child entity and we shoud load it's relative transform values
if(parent_entity)
{
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);
transform_update_transmat(new_entity);
}
return new_entity;
}
@ -417,14 +453,17 @@ bool entity_load(const char* filename, int directory_type)
}
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);
new_entity = entity_read(object, parent_entity);
if(new_entity)
{
if(i == 0)
parent_entity = new_entity;
num_entites_loaded++;
log_message("Entity %s loaded from %s", new_entity->name, filename);
}

@ -155,8 +155,8 @@ void entity_init(struct Entity* entity, const char* name, struct Entit
void entity_reset(struct Entity* entity, int id);
bool entity_save(struct Entity* entity, const char* filename, int directory_type);
bool entity_load(const char* filename, int directory_type);
bool entity_write(struct Entity* entity, struct Parser_Object* object);
struct Entity* entity_read(struct Parser_Object* object);
bool entity_write(struct Entity* entity, struct Parser_Object* object, bool write_transform);
struct Entity* entity_read(struct Parser_Object* object, struct Entity* parent_entity);
const char* entity_type_name_get(struct Entity* entity);
void entity_rigidbody_on_move(Rigidbody body);
void entity_rigidbody_on_collision(Rigidbody body_A, Rigidbody body_B);

@ -322,6 +322,24 @@ void game_scene_setup(void)
light->radius = 20;
vec3 light_pos = {0.f, 5.f, 0.f};
transform_translate(light, &light_pos, TS_WORLD);
struct Static_Mesh* suzanne = scene_static_mesh_create(game_state->scene, "Suz", NULL, "suzanne.symbres", MAT_BLINN);
suzanne->model.material_params[MMP_DIFFUSE_TEX].val_int = texture_create_from_file("white.tga", TU_DIFFUSE);
suzanne->model.material_params[MMP_DIFFUSE].val_float = 0.5f;
suzanne->model.material_params[MMP_SPECULAR].val_float = 1.f;
suzanne->model.material_params[MMP_SPECULAR_STRENGTH].val_float = 1.f;
vec3_fill(&suzanne->model.material_params[MMP_DIFFUSE_COL].val_vec3, 1.f, 0.f, 1.f);
suz_pos.x = 0.f;
suz_pos.y = 5.f;
suz_pos.z = 5.f;
transform_set_position(suzanne, &suz_pos);
struct Light* suz_light = scene_light_create(game_state->scene, "Suz_Light", suzanne, LT_POINT);
suz_light->color.x = 1.f;
suz_light->color.y = 0.f;
suz_light->color.z = 0.f;
vec3 suz_light_pos = {0.f, 3.f, 0.f};
transform_translate(suz_light, &suz_light_pos, TS_PARENT);
}
void game_debug(float dt)

@ -28,7 +28,13 @@ void transform_child_add(struct Entity* parent, struct Entity* child, bool updat
/* Check if already added */
for(int i = 0; i < array_len(parent_transform->children); i++)
if(parent_transform->children[i] == child) return;
{
if(parent_transform->children[i] == child)
{
log_warning("Parent : %s already has a child named %s", parent->name, parent_transform->children[i]->name);
return;
}
}
struct Entity** new_child_loc = array_grow(parent_transform->children, struct Entity*);
*new_child_loc = child;
@ -44,7 +50,7 @@ bool transform_child_remove(struct Entity* parent, struct Entity* child)
{
if(parent_transform->children[i] == child)
{
array_remove_at(parent_transform, i);
array_remove_at(parent_transform->children, i);
child->transform.parent = NULL;
success = true;
return success;
@ -233,6 +239,7 @@ void transform_update_transmat(struct Entity* entity)
void transform_destroy(struct Entity* entity)
{
struct Transform* transform = &entity->transform;
// Remove children
int children = array_len(transform->children);
if(children > 0)
{
@ -243,6 +250,10 @@ void transform_destroy(struct Entity* entity)
}
}
// Remove this entity from parent's children
if(entity->transform.parent)
transform_child_remove(entity->transform.parent, entity);
/* Remove transform */
array_free(transform->children);
vec3_fill(&transform->position, 0.f, 0.f, 0.f);

@ -1,6 +1,7 @@
#include <assert.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include "file_io.h"
#include "../common/log.h"
@ -81,7 +82,8 @@ FILE* io_file_open(const int directory_type, const char* path, const char* mode)
if(!file)
{
char err_str[256];
perror(err_str);
memset(&err_str[0], '\0', 256);
perror(&err_str[0]);
log_error("io:file_open", "Failed to open file '%s' (%s)", relative_path, err_str);
}
free(relative_path);

@ -1,13 +1,12 @@
Todo:
- Display default mesh when selected entity type in editor does not have a mesh
- Allow picking and selecting other entity types in editor i.e. the ones that don't have meshes
- Separate entity types in entity heirarchy view by the entity type or use a tree view to show parent/child relation or use differnt colours for different entity types
- Finish mesh and material properties serialization to and from file
- Editor functionality to add entity from specific file to scene
- Scene read/write to file with scene file only containing names of
entity archetypes
- Console command to read/write scene to/from file
- Editor functionality to read/write scene to/from file
- Display default mesh when selected entity type in editor does not have a mesh
- Allow picking and selecting other entity types in editor i.e. the ones that don't have meshes
- Separate entity types in entity heirarchy view by the entity type or use a tree view to show parent/child relation or use different colours for different entity types
? Entity creator window to create new types of entities and write them
to disk
- Entity browser window which lists all existing entity types from
@ -319,3 +318,5 @@ Done:
* Fixed symlink issue in genie for macos which interferes with fopen operations
* Implement/Fix copying libraries to executable folder after build completes on mac os
* Fixed all sound related bugs and completede sound to/from file
* Implemented saving/loading entity children when reading/writing entity to file
* Editor functionality to add entity from specific file to scene

@ -2,8 +2,7 @@
subst /D "W:"
subst W: %CD%\..
call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" x64
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat" x64
cls
set editor=""C:\Applications\Emacs\bin\runemacs.exe""
set path=W:\tools;%path% rem

Loading…
Cancel
Save