diff --git a/src/common/parser.c b/src/common/parser.c index 61ec2de..c9126de 100755 --- a/src/common/parser.c +++ b/src/common/parser.c @@ -238,11 +238,13 @@ int parser_object_type_from_str(const char* str) { int object_type = PO_UNKNOWN; - if(strncmp(str, "Entity", HASH_MAX_KEY_LEN) == 0) object_type = PO_ENTITY; - else if(strncmp(str, "Model", HASH_MAX_KEY_LEN) == 0) object_type = PO_MODEL; - else if(strncmp(str, "Material", HASH_MAX_KEY_LEN) == 0) object_type = PO_MATERIAL; - else if(strncmp(str, "Config", HASH_MAX_KEY_LEN) == 0) object_type = PO_CONFIG; - else if(strncmp(str, "Key", HASH_MAX_KEY_LEN) == 0) object_type = PO_KEY; + if(strncmp(str, "Entity", HASH_MAX_KEY_LEN) == 0) object_type = PO_ENTITY; + else if(strncmp(str, "Model", HASH_MAX_KEY_LEN) == 0) object_type = PO_MODEL; + else if(strncmp(str, "Material", HASH_MAX_KEY_LEN) == 0) object_type = PO_MATERIAL; + else if(strncmp(str, "Config", HASH_MAX_KEY_LEN) == 0) object_type = PO_CONFIG; + else if(strncmp(str, "Key", HASH_MAX_KEY_LEN) == 0) object_type = PO_KEY; + else if(strncmp(str, "Scene_Entity_Entry", HASH_MAX_KEY_LEN) == 0) object_type = PO_SCENE_ENTITY_ENTRY; + else if(strncmp(str, "Scene_Config", HASH_MAX_KEY_LEN) == 0) object_type = PO_SCENE_CONFIG; return object_type; } @@ -251,12 +253,14 @@ const char* parser_object_type_to_str(int type) { switch(type) { - case PO_ENTITY: return "Entity"; - case PO_MODEL: return "Model"; - case PO_MATERIAL: return "Material"; - case PO_CONFIG: return "Config"; - case PO_KEY: return "Key"; - case PO_UNKNOWN: return "Unknown"; + case PO_ENTITY: return "Entity"; + case PO_MODEL: return "Model"; + case PO_MATERIAL: return "Material"; + case PO_CONFIG: return "Config"; + case PO_KEY: return "Key"; + case PO_UNKNOWN: return "Unknown"; + case PO_SCENE_CONFIG: return "Scene_Config"; + case PO_SCENE_ENTITY_ENTRY: return "Scene_Entity_Entry"; default: return "Unknown"; } } diff --git a/src/common/parser.h b/src/common/parser.h index ad79bfd..9d5849b 100755 --- a/src/common/parser.h +++ b/src/common/parser.h @@ -8,6 +8,8 @@ enum Parser_Object_Type { PO_CONFIG, PO_ENTITY, + PO_SCENE_CONFIG, + PO_SCENE_ENTITY_ENTRY, PO_MATERIAL, PO_MODEL, PO_KEY, diff --git a/src/game/console.c b/src/game/console.c index 2a1507a..bdc0f4f 100755 --- a/src/game/console.c +++ b/src/game/console.c @@ -15,6 +15,7 @@ static struct nk_color console_message_color[CMT_MAX]; 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_entity_save(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); @@ -43,6 +44,7 @@ void console_init(struct Console* console) } console->console_commands = hashmap_new(); + hashmap_ptr_set(console->console_commands, "scene_save", &console_command_scene_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, "help", &console_command_help); @@ -224,3 +226,22 @@ void console_command_help(struct Console* console, const char* command) } log_message("======================================"); } + +void console_command_scene_save(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_save [file name]"); + return; + } + + char full_filename[MAX_FILENAME_LEN]; + snprintf(full_filename, MAX_FILENAME_LEN, "scenes/%s.symtres", filename); + if(!scene_save(game_state_get()->scene, full_filename, DIRT_INSTALL)) + log_error("scene_save", "Command failed"); +} diff --git a/src/game/scene.c b/src/game/scene.c index 005462a..f942978 100755 --- a/src/game/scene.c +++ b/src/game/scene.c @@ -15,6 +15,8 @@ #include "../system/sound.h" #include "../system/physics.h" #include "../system/platform.h" +#include "../common/hashmap.h" +#include "renderer.h" #include #include @@ -64,14 +66,59 @@ void scene_init(struct Scene* scene) scene->active_camera_index = game_state_get()->game_mode == GAME_MODE_GAME ? CAM_GAME : CAM_EDITOR; } -bool scene_load(struct Scene* scene, const char* filename, int dir_type) +bool scene_load(struct Scene* scene, const char* filename, int directory_type) { return false; } -bool scene_save(struct Scene* scene, const char* filename, int dir_type) +bool scene_save(struct Scene* scene, const char* filename, int directory_type) { - return false; + FILE* scene_file = io_file_open(directory_type, filename, "w"); + if(!scene_file) + { + log_error("scene:save", "Failed to open scene file %s for writing"); + return false; + } + + struct Parser* parser = parser_new(); + + //Start by saving the scene configuration information + struct Parser_Object* scene_config_object = parser_object_new(parser, PO_SCENE_CONFIG); + struct Render_Settings* render_settings = &game_state_get()->renderer->settings; + struct Hashmap* scene_data = scene_config_object->data; + hashmap_int_set(scene_data, "fog_type", render_settings->fog.mode); + hashmap_float_set(scene_data, "fog_density", render_settings->fog.density); + hashmap_float_set(scene_data, "fog_start_distance", render_settings->fog.start_dist); + hashmap_float_set(scene_data, "fog_max_distance", render_settings->fog.max_dist); + hashmap_vec3_set(scene_data, "fog_color", &render_settings->fog.color); + hashmap_vec3_set(scene_data, "ambient_light", &render_settings->ambient_light); + hashmap_vec4_set(scene_data, "debug_draw_color", &render_settings->debug_draw_color); + hashmap_bool_set(scene_data, "debug_draw_enabled", render_settings->debug_draw_enabled); + 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); + + for(int i = 0; i < MAX_ENTITIES; i++) + { + struct Entity* entity = &scene->entities[i]; + if(!entity->active) + continue; + + 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)) + log_message("Scene saved to %s", filename); + + parser_free(parser); + fclose(scene_file); + return true; } void scene_destroy(struct Scene* scene) diff --git a/src/game/scene.h b/src/game/scene.h index df56cf1..3aab0af 100755 --- a/src/game/scene.h +++ b/src/game/scene.h @@ -15,7 +15,6 @@ struct Raycast_Result; struct Scene { - struct Render_Settings renderer_profile; struct Entity root_entity; struct Player player; struct Entity entities[MAX_ENTITIES]; @@ -27,8 +26,8 @@ struct Scene }; void scene_init(struct Scene* scene); -bool scene_load(struct Scene* scene, const char* filename, int dir_type); -bool scene_save(struct Scene* scene, const char* filename, int dir_type); +bool scene_load(struct Scene* scene, const char* filename, int directory_type); +bool scene_save(struct Scene* scene, const char* filename, int directory_type); void scene_destroy(struct Scene* scene); void scene_update(struct Scene* scene, float dt); void scene_post_update(struct Scene* scene); diff --git a/todo.txt b/todo.txt index 962f549..ef24055 100644 --- a/todo.txt +++ b/todo.txt @@ -1,9 +1,11 @@ Todo: + - Implement entitie storing a reference or name of file they've been loaded from to help when they're being saved - 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 + - 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 - 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