Implemented first version of reading/writing entites to/from files

dev
Shariq Shah 6 years ago
parent 651cbf1883
commit cf8f989301
  1. 21
      src/game/console.c
  2. 13
      src/game/entity.c
  3. 3
      src/game/entity.h
  4. 192
      src/game/scene.c
  5. 2
      src/game/scene.h
  6. 12
      todo.txt

@ -16,6 +16,7 @@ static struct nk_color console_message_color[CMT_MAX];
static int console_filter(const struct nk_text_edit *box, nk_rune unicode); static int console_filter(const struct nk_text_edit *box, nk_rune unicode);
static void console_command_scene_save(struct Console* console, const char* command); static void console_command_scene_save(struct Console* console, const char* command);
static void console_command_scene_load(struct Console* console, const char* command);
static void console_command_entity_save(struct Console* console, const char* command); static void console_command_entity_save(struct Console* console, const char* command);
static void console_command_entity_load(struct Console* console, const char* command); static void console_command_entity_load(struct Console* console, const char* command);
static void console_command_help(struct Console* console, const char* command); static void console_command_help(struct Console* console, const char* command);
@ -45,6 +46,7 @@ void console_init(struct Console* console)
console->console_commands = hashmap_new(); console->console_commands = hashmap_new();
hashmap_ptr_set(console->console_commands, "scene_save", &console_command_scene_save); hashmap_ptr_set(console->console_commands, "scene_save", &console_command_scene_save);
hashmap_ptr_set(console->console_commands, "scene_load", &console_command_scene_load);
hashmap_ptr_set(console->console_commands, "entity_save", &console_command_entity_save); hashmap_ptr_set(console->console_commands, "entity_save", &console_command_entity_save);
hashmap_ptr_set(console->console_commands, "entity_load", &console_command_entity_load); hashmap_ptr_set(console->console_commands, "entity_load", &console_command_entity_load);
hashmap_ptr_set(console->console_commands, "help", &console_command_help); hashmap_ptr_set(console->console_commands, "help", &console_command_help);
@ -245,3 +247,22 @@ void console_command_scene_save(struct Console* console, const char* command)
if(!scene_save(game_state_get()->scene, full_filename, DIRT_INSTALL)) if(!scene_save(game_state_get()->scene, full_filename, DIRT_INSTALL))
log_error("scene_save", "Command failed"); log_error("scene_save", "Command failed");
} }
void console_command_scene_load(struct Console* console, const char* command)
{
char filename[MAX_FILENAME_LEN];
memset(filename, '\0', MAX_FILENAME_LEN);
int params_read = sscanf(command, "%s", filename);
if(params_read != 1)
{
log_warning("Invalid parameters for command");
log_warning("Usage: scene_load [file name]");
return;
}
char full_filename[MAX_FILENAME_LEN];
snprintf(full_filename, MAX_FILENAME_LEN, "scenes/%s.symtres", filename);
if(!scene_load(game_state_get()->scene, full_filename, DIRT_INSTALL))
log_error("scene_load", "Command failed");
}

@ -36,6 +36,7 @@ void entity_init(struct Entity* entity, const char* name, struct Entity* parent)
strncpy(entity->name, name ? name : "DEFAULT_ENTITY_NAME", MAX_ENTITY_NAME_LEN); strncpy(entity->name, name ? name : "DEFAULT_ENTITY_NAME", MAX_ENTITY_NAME_LEN);
entity->name[MAX_ENTITY_NAME_LEN - 1] = '\0'; entity->name[MAX_ENTITY_NAME_LEN - 1] = '\0';
entity->type = ET_DEFAULT; entity->type = ET_DEFAULT;
entity->archetype_index = -1;
entity->active = true; entity->active = true;
entity->marked_for_deletion = false; entity->marked_for_deletion = false;
entity->selected_in_editor = false; entity->selected_in_editor = false;
@ -46,13 +47,14 @@ void entity_reset(struct Entity * entity, int id)
{ {
assert(entity); assert(entity);
entity->id = id; entity->id = id;
entity->type = ET_DEFAULT;
entity->archetype_index = -1;
entity->active = false; entity->active = false;
entity->marked_for_deletion = false; entity->marked_for_deletion = false;
entity->selected_in_editor = false; entity->selected_in_editor = false;
memset(entity->name, '\0', MAX_ENTITY_NAME_LEN); memset(entity->name, '\0', MAX_ENTITY_NAME_LEN);
} }
bool entity_write(struct Entity* entity, struct Parser_Object* object, bool write_transform) bool entity_write(struct Entity* entity, struct Parser_Object* object, bool write_transform)
{ {
if(!object) if(!object)
@ -168,14 +170,14 @@ bool entity_write(struct Entity* entity, struct Parser_Object* object, bool writ
{ {
case MAT_BLINN: case MAT_BLINN:
hashmap_vec4_set(entity_data, "diffuse_color", &model->material_params[MMP_DIFFUSE_COL].val_vec4); hashmap_vec4_set(entity_data, "diffuse_color", &model->material_params[MMP_DIFFUSE_COL].val_vec4);
hashmap_str_set(entity_data, "diffuse_texture", texture_get_name(model->material_params[MMP_DIFFUSE_TEX].val_int)); 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, "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", model->material_params[MMP_SPECULAR].val_float);
hashmap_float_set(entity_data, "specular_strength", model->material_params[MMP_SPECULAR_STRENGTH].val_float); hashmap_float_set(entity_data, "specular_strength", model->material_params[MMP_SPECULAR_STRENGTH].val_float);
break; break;
case MAT_UNSHADED: case MAT_UNSHADED:
hashmap_vec3_set(entity_data, "diffuse_color", &mesh->model.material_params[MMP_DIFFUSE_COL].val_vec3); hashmap_vec3_set(entity_data, "diffuse_color", &mesh->model.material_params[MMP_DIFFUSE_COL].val_vec3);
hashmap_int_set(entity_data, "diffuse_texture", mesh->model.material_params[MMP_DIFFUSE_TEX].val_int); 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));
break; break;
}; };
@ -297,6 +299,7 @@ struct Entity* entity_read(struct Parser_Object* object, struct Entity* parent_e
int fbo_width = -1; int fbo_width = -1;
int fbo_height = -1; int fbo_height = -1;
struct Camera* camera = scene_camera_create(scene, name, parent_entity, 320, 240); 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, "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, "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, "zoom")) camera->zoom = hashmap_float_get(object->data, "zoom");
@ -469,7 +472,7 @@ struct Entity* entity_read(struct Parser_Object* object, struct Entity* parent_e
return new_entity; return new_entity;
} }
bool entity_load(const char* filename, int directory_type) struct Entity* entity_load(const char* filename, int directory_type)
{ {
FILE* entity_file = io_file_open(directory_type, filename, "rb"); FILE* entity_file = io_file_open(directory_type, filename, "rb");
if(!entity_file) if(!entity_file)
@ -519,7 +522,7 @@ bool entity_load(const char* filename, int directory_type)
parser_free(parsed_file); parser_free(parsed_file);
fclose(entity_file); fclose(entity_file);
return num_entites_loaded > 0 ? true : false; return parent_entity;
} }
const char* entity_type_name_get(struct Entity* entity) const char* entity_type_name_get(struct Entity* entity)

@ -61,6 +61,7 @@ struct Entity
{ {
int id; int id;
int type; int type;
int archetype_index;
char name[MAX_ENTITY_NAME_LEN]; char name[MAX_ENTITY_NAME_LEN];
bool marked_for_deletion; bool marked_for_deletion;
bool active; bool active;
@ -154,7 +155,7 @@ struct Player
void entity_init(struct Entity* entity, const char* name, struct Entity* parent); void entity_init(struct Entity* entity, const char* name, struct Entity* parent);
void entity_reset(struct Entity* entity, int id); void entity_reset(struct Entity* entity, int id);
bool entity_save(struct Entity* entity, const char* filename, int directory_type); bool entity_save(struct Entity* entity, const char* filename, int directory_type);
bool entity_load(const char* filename, int directory_type); struct Entity* entity_load(const char* filename, int directory_type);
bool entity_write(struct Entity* entity, struct Parser_Object* object, bool write_transform); 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); struct Entity* entity_read(struct Parser_Object* object, struct Entity* parent_entity);
const char* entity_type_name_get(struct Entity* entity); const char* entity_type_name_get(struct Entity* entity);

@ -22,6 +22,9 @@
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
static void scene_write_entity_entry(struct Scene* scene, struct Entity* entity, struct Parser* parser);
static void scene_write_entity_list(struct Scene* scene, int entity_type, struct Parser* parser);
void scene_init(struct Scene* scene) void scene_init(struct Scene* scene)
{ {
assert(scene); assert(scene);
@ -39,6 +42,7 @@ void scene_init(struct Scene* scene)
entity_reset(&scene->lights[i], i); entity_reset(&scene->lights[i], i);
scene->lights[i].type = ET_LIGHT; scene->lights[i].type = ET_LIGHT;
} }
for(int i = 0; i < MAX_STATIC_MESHES; i++) for(int i = 0; i < MAX_STATIC_MESHES; i++)
{ {
entity_reset(&scene->static_meshes[i], i); entity_reset(&scene->static_meshes[i], i);
@ -49,6 +53,7 @@ void scene_init(struct Scene* scene)
mesh->model.geometry_index = -1; mesh->model.geometry_index = -1;
mesh->model.material = NULL; mesh->model.material = NULL;
} }
for(int i = 0; i < MAX_SOUND_SOURCES; i++) entity_reset(&scene->sound_sources[i], i); for(int i = 0; i < MAX_SOUND_SOURCES; i++) entity_reset(&scene->sound_sources[i], i);
int width = 1280, height = 720; int width = 1280, height = 720;
window_get_drawable_size(game_state->window, &width, &height); window_get_drawable_size(game_state->window, &width, &height);
@ -57,9 +62,13 @@ void scene_init(struct Scene* scene)
{ {
entity_init(&scene->cameras[i], NULL, &scene->root_entity); entity_init(&scene->cameras[i], NULL, &scene->root_entity);
camera_init(&scene->cameras[i], width, height); camera_init(&scene->cameras[i], width, height);
scene->cameras[i].base.active = false;
scene->cameras[i].base.id = i; scene->cameras[i].base.id = i;
} }
for(int i = 0; i < MAX_ENTITY_ARCHETYPES; i++)
memset(&scene->entity_archetypes[i][0], '\0', MAX_FILENAME_LEN);
player_init(&scene->player, scene); player_init(&scene->player, scene);
editor_init_camera(game_state->editor, game_state->cvars); editor_init_camera(game_state->editor, game_state->cvars);
@ -68,9 +77,100 @@ void scene_init(struct Scene* scene)
bool scene_load(struct Scene* scene, const char* filename, int directory_type) bool scene_load(struct Scene* scene, const char* filename, int directory_type)
{ {
FILE* scene_file = io_file_open(directory_type, filename, "rb");
if(!scene_file)
{
log_error("scene:load", "Failed to open scene file %s for reading");
return false; return false;
} }
// Load scene config and apply renderer settings
struct Parser* parsed_file = parser_load_objects(scene_file, filename);
if(!parsed_file)
{
log_error("scene:load", "Failed to parse file '%s' for loading scene", filename);
fclose(scene_file);
return false;
}
if(array_len(parsed_file->objects) == 0)
{
log_error("scene:load", "No objects found in file %s", filename);
parser_free(parsed_file);
fclose(scene_file);
return false;
}
//Clear previous scene and re-initialize
scene_destroy(scene);
scene_post_update(scene);
scene_init(scene);
int num_objects_loaded = 0;
for(int i = 0; i < array_len(parsed_file->objects); i++)
{
struct Parser_Object* object = &parsed_file->objects[i];
if(object->type == PO_SCENE_CONFIG)
{
struct Hashmap* scene_data = object->data;
struct Render_Settings* render_settings = &game_state_get()->renderer->settings;
if(hashmap_value_exists(scene_data, "fog_type")) render_settings->fog.mode = hashmap_int_get(scene_data, "fog_type");
if(hashmap_value_exists(scene_data, "fog_density")) render_settings->fog.density = hashmap_float_get(scene_data, "fog_density");
if(hashmap_value_exists(scene_data, "fog_start_distance")) render_settings->fog.start_dist = hashmap_float_get(scene_data, "fog_start_distance");
if(hashmap_value_exists(scene_data, "fog_max_distance")) render_settings->fog.max_dist = hashmap_float_get(scene_data, "fog_max_distance");
if(hashmap_value_exists(scene_data, "fog_color")) render_settings->fog.color = hashmap_vec3_get(scene_data, "fog_color");
if(hashmap_value_exists(scene_data, "ambient_light")) render_settings->ambient_light = hashmap_vec3_get(scene_data, "ambient_light");
if(hashmap_value_exists(scene_data, "debug_draw_color")) render_settings->debug_draw_color = hashmap_vec4_get(scene_data, "debug_draw_color");
if(hashmap_value_exists(scene_data, "debug_draw_enabled")) render_settings->debug_draw_enabled = hashmap_bool_get(scene_data, "debug_draw_enabled");
if(hashmap_value_exists(scene_data, "debug_draw_mode")) render_settings->debug_draw_mode = hashmap_int_get(scene_data, "debug_draw_mode");
if(hashmap_value_exists(scene_data, "debug_draw_physics")) render_settings->debug_draw_physics = hashmap_bool_get(scene_data, "debug_draw_physics");
num_objects_loaded++;
}
else if(object->type == PO_ENTITY)
{
if(entity_read(object, &scene->root_entity))
num_objects_loaded++;
}
else if(object->type == PO_SCENE_ENTITY_ENTRY)
{
struct Hashmap* entity_entry_data = object->data;
if(hashmap_value_exists(object->data, "filename"))
{
struct Entity* loaded_entity = entity_load(hashmap_str_get(entity_entry_data, "filename"), DIRT_INSTALL);
if(loaded_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(entity_entry_data, "position")) position = hashmap_vec3_get(entity_entry_data, "position");
if(hashmap_value_exists(entity_entry_data, "rotation")) rotation = hashmap_quat_get(entity_entry_data, "rotation");
if(hashmap_value_exists(entity_entry_data, "scale")) scale = hashmap_vec3_get(entity_entry_data, "scale");
transform_set_position(loaded_entity, &position);
transform_scale(loaded_entity, &scale);
quat_assign(&loaded_entity->transform.rotation, &rotation);
transform_update_transmat(loaded_entity);
if(hashmap_value_exists(entity_entry_data, "name")) strncpy(loaded_entity->name, hashmap_str_get(entity_entry_data, "name"), MAX_ENTITY_NAME_LEN);
num_objects_loaded++;
}
}
}
else
{
log_warning("Unknown object type '%s' in scene file %s", parser_object_type_to_str(object->type), filename);
continue;
}
}
parser_free(parsed_file);
fclose(scene_file);
return num_objects_loaded > 0 ? true : false;
}
bool scene_save(struct Scene* scene, const char* filename, int directory_type) bool scene_save(struct Scene* scene, const char* filename, int directory_type)
{ {
FILE* scene_file = io_file_open(directory_type, filename, "w"); FILE* scene_file = io_file_open(directory_type, filename, "w");
@ -97,21 +197,11 @@ bool scene_save(struct Scene* scene, const char* filename, int directory_type)
hashmap_int_set(scene_data, "debug_draw_mode", render_settings->debug_draw_mode); hashmap_int_set(scene_data, "debug_draw_mode", render_settings->debug_draw_mode);
hashmap_bool_set(scene_data, "debug_draw_physics", render_settings->debug_draw_physics); hashmap_bool_set(scene_data, "debug_draw_physics", render_settings->debug_draw_physics);
for(int i = 0; i < MAX_ENTITIES; i++) scene_write_entity_list(scene, ET_DEFAULT, parser);
{ scene_write_entity_list(scene, ET_LIGHT, parser);
struct Entity* entity = &scene->entities[i]; scene_write_entity_list(scene, ET_STATIC_MESH, parser);
if(!entity->active) scene_write_entity_list(scene, ET_CAMERA, parser);
continue; scene_write_entity_list(scene, ET_SOUND_SOURCE, parser);
struct Parser_Object* object = parser_object_new(parser, PO_ENTITY);
if(!entity_write(entity, object, false))
{
log_error("scene:save", "Failed to save entity : %s to file : %s", entity->name, filename);
parser_free(parser);
fclose(scene_file);
return false;
}
}
if(parser_write_objects(parser, scene_file, filename)) if(parser_write_objects(parser, scene_file, filename))
log_message("Scene saved to %s", filename); log_message("Scene saved to %s", filename);
@ -121,6 +211,77 @@ bool scene_save(struct Scene* scene, const char* filename, int directory_type)
return true; return true;
} }
void scene_write_entity_list(struct Scene* scene, int entity_type, struct Parser* parser)
{
int max_length = 0;
size_t stride = 0;
struct Entity* entity = NULL;
switch(entity_type)
{
case ET_DEFAULT:
max_length = MAX_ENTITIES;
entity = &scene->entities[0];
stride = sizeof(struct Entity);
break;
case ET_LIGHT:
max_length = MAX_LIGHTS;
entity = &scene->lights[0].base;
stride = sizeof(struct Light);
break;
case ET_STATIC_MESH:
max_length = MAX_STATIC_MESHES;
entity = &scene->static_meshes[0].base;
stride = sizeof(struct Static_Mesh);
break;
case ET_CAMERA:
max_length = MAX_CAMERAS;
entity = &scene->cameras[0].base;
stride = sizeof(struct Camera);
break;
case ET_SOUND_SOURCE:
max_length = MAX_SOUND_SOURCES;
entity = &scene->sound_sources[0].base;
stride = sizeof(struct Sound_Source);
break;
default: return;
}
size_t count = 0;
while(count < max_length)
{
//((char*)entity) += stride * count;
((char*)entity) += stride;
if(entity->active)
{
if(entity->archetype_index != -1)
{
scene_write_entity_entry(scene, entity, parser);
}
else
{
struct Parser_Object* object = parser_object_new(parser, PO_ENTITY);
if(!entity_write(entity, object, true))
log_error("scene:save", "Failed to save entity : %s", entity->name);
}
}
count++;
}
}
void scene_write_entity_entry(struct Scene* scene, struct Entity* entity, struct Parser* parser)
{
// For entities with archetypes, we only write the name of the archetype to load
// them from and their transformation info
struct Parser_Object* object = parser_object_new(parser, PO_SCENE_ENTITY_ENTRY);
hashmap_str_set(object->data, "filename", &scene->entity_archetypes[entity->archetype_index][0]);
hashmap_str_set(object->data, "name", entity->name);
hashmap_vec3_set(object->data, "position", &entity->transform.position);
hashmap_vec3_set(object->data, "scale", &entity->transform.scale);
hashmap_quat_set(object->data, "rotation", &entity->transform.rotation);
}
void scene_destroy(struct Scene* scene) void scene_destroy(struct Scene* scene)
{ {
assert(scene); assert(scene);
@ -130,6 +291,7 @@ void scene_destroy(struct Scene* scene)
for(int i = 0; i < MAX_LIGHTS; i++) scene_light_remove(scene, &scene->lights[i]); for(int i = 0; i < MAX_LIGHTS; i++) scene_light_remove(scene, &scene->lights[i]);
for(int i = 0; i < MAX_STATIC_MESHES; i++) scene_static_mesh_remove(scene, &scene->static_meshes[i]); for(int i = 0; i < MAX_STATIC_MESHES; i++) scene_static_mesh_remove(scene, &scene->static_meshes[i]);
for(int i = 0; i < MAX_SOUND_SOURCES; i++) scene_sound_source_remove(scene, &scene->sound_sources[i]); for(int i = 0; i < MAX_SOUND_SOURCES; i++) scene_sound_source_remove(scene, &scene->sound_sources[i]);
for(int i = 0; i < MAX_ENTITY_ARCHETYPES; i++) memset(&scene->entity_archetypes[i][0], '\0', MAX_FILENAME_LEN);
player_destroy(&scene->player); player_destroy(&scene->player);
entity_reset(&scene->root_entity, 0); entity_reset(&scene->root_entity, 0);
scene->root_entity.active = false; scene->root_entity.active = false;

@ -9,6 +9,7 @@
#define MAX_CAMERAS 2 #define MAX_CAMERAS 2
#define MAX_STATIC_MESHES 1024 #define MAX_STATIC_MESHES 1024
#define MAX_SOUND_SOURCES 128 #define MAX_SOUND_SOURCES 128
#define MAX_ENTITY_ARCHETYPES 32
struct Ray; struct Ray;
struct Raycast_Result; struct Raycast_Result;
@ -22,6 +23,7 @@ struct Scene
struct Camera cameras[MAX_CAMERAS]; struct Camera cameras[MAX_CAMERAS];
struct Light lights[MAX_LIGHTS]; struct Light lights[MAX_LIGHTS];
struct Sound_Source sound_sources[MAX_SOUND_SOURCES]; struct Sound_Source sound_sources[MAX_SOUND_SOURCES];
char entity_archetypes[MAX_ENTITY_ARCHETYPES][MAX_FILENAME_LEN];
int active_camera_index; int active_camera_index;
}; };

@ -1,9 +1,9 @@
Todo: Todo:
- Implement entitie storing a reference or name of file they've been loaded from to help when they're being saved - Implement flags that specify whether an entity should be written to file or not for example to avoid writing cameras and player to file
- Implment/Test reading/writing scene that has a mixture of default entites and entity archetypes
- Serialize player, camera properties to file
- Implement behaviour that avoids writing normal entities that do not have children or parent to file to avoid inconsistencies when loading them
- Change mouse behaviour to lock cursor when looking around so as not to interfere with gui elements when in editor mode - Change mouse behaviour to lock cursor when looking around so as not to interfere with gui elements when in editor mode
- 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 - Editor functionality to read/write scene to/from file
- Folder management api to create/delete folders when none exist. Dirent would suffice for our simple needs? - Folder management api to create/delete folders when none exist. Dirent would suffice for our simple needs?
- Display default mesh when selected entity type in editor does not have a mesh - Display default mesh when selected entity type in editor does not have a mesh
@ -328,3 +328,7 @@ Done:
* Implemented Static Mesh property viewing/editing in editor * Implemented Static Mesh property viewing/editing in editor
* Implemented contextual menu for re-entering diffuse texture name * Implemented contextual menu for re-entering diffuse texture name
* Implemented contextual menus for entering geometry and sound source names * Implemented contextual menus for entering geometry and sound source names
* Implemented entities storing a reference or name of file they've been loaded from to help when they're being saved
* Scene read/write to file with scene file only containing names of
entity archetypes
* Console command to read/write scene to/from file

Loading…
Cancel
Save