diff options
Diffstat (limited to 'save.c')
| -rw-r--r-- | save.c | 153 |
1 files changed, 153 insertions, 0 deletions
@@ -516,6 +516,145 @@ write_model_chunk(FILE *fp) { } static bool +read_material_chunk(FILE *fp, SaveLoadContext *ctx, MaterialProperty prop) { + u32 count; + if (!read_u32_le(fp, &count)) { + return false; + } + + for (u32 i = 0; i < count; ++i) { + u64 pid; + u32 mat_idx, key_len; + + if (!read_u64_le(fp, &pid) || + !read_u32_le(fp, &mat_idx) || + !read_u32_le(fp, &key_len)) { + return false; + } + + if (!pid || pid >= ctx->next_pid || + mat_idx == UINT32_MAX || !key_len) { + return false; + } + + Entity *ent = entity_get(entity_id_from_pid(pid)); + if (!ent || !ent->mdl.has) { + return false; + } + + ModelCmp *model = &ent->mdl; + + if (mat_idx >= model->mat_cnt) { + size_t slots = (size_t)mat_idx + 1; + if (slots > SIZE_MAX / sizeof(MaterialOverride)) { + return false; + } + + MaterialOverride *materials; + materials = realloc(model->materials, + slots * sizeof(*materials)); + + if (!materials) { + return false; + } + + memset(materials + model->mat_cnt, 0, + (slots - model->mat_cnt) * + sizeof(*materials)); + + model->materials = materials; + model->mat_cnt = slots; + } + + MaterialOverride *material; + material = &model->materials[mat_idx]; + + char **field = prop == MAT_PROP_TEXTURE ? + &material->tex_key : &material->shader_key; + + if (*field) { + return false; + } + + char *key = malloc((size_t)key_len + 1); + if (!key) { + return false; + } + + if (fread(key, 1, key_len, fp) != key_len) { + free(key); + return false; + } + + key[key_len] = '\0'; + *field = key; + } + + return true; +} + +static bool +write_material_chunk(FILE *fp, MaterialProperty prop) { + SaveChunk chunk = {0}; + u32 count = 0; + cstr label = prop == MAT_PROP_TEXTURE ? "MTEX" : "MSHD"; + + for (u32 i = 0; i < entity_count(); ++i) { + Entity *ent = &entity_data()[i]; + + if (!ent->pid || !ent->mdl.has) { + continue; + } + + for (u32 j = 0; j < ent->mdl.mat_cnt; ++j) { + const MaterialOverride *material; + material = &ent->mdl.materials[j]; + + cstr key = prop == MAT_PROP_TEXTURE ? + material->tex_key : material->shader_key; + + count += key != NULL; + } + } + + if (!chunk_begin(fp, label, &chunk) || + !write_u32_le(fp, count)) { + return false; + } + + for (u32 i = 0; i < entity_count(); ++i) { + Entity *ent = &entity_data()[i]; + + if (!ent->pid || !ent->mdl.has) { + continue; + } + + for (u32 j = 0; j < ent->mdl.mat_cnt; ++j) { + const MaterialOverride *material; + material = &ent->mdl.materials[j]; + + cstr key = prop == MAT_PROP_TEXTURE ? + material->tex_key : material->shader_key; + + if (!key) { + continue; + } + + u32 key_len = (u32)strlen(key); + + if (!write_u64_le(fp, ent->pid) || + !write_u32_le(fp, j) || + !write_u32_le(fp, key_len) || + !write_byte_arr(fp, key, key_len)) { + return false; + } + } + } + + return chunk_end(fp, &chunk); +} + +static bool read_physics_shape(FILE *fp, PhysicsShape *shape) { *shape = (PhysicsShape){0}; @@ -1006,6 +1145,18 @@ save_file_read(cstr path) { break; } success = read_model_chunk(fp, &ctx); + } else if (memcmp(label, "MTEX", 4) ==0 || + memcmp(label, "MSHD", 4) == 0) { + if (!read_entt) { + success = false; + break; + } + + MaterialProperty prop; + prop = memcmp(label, "MTEX", 4) == 0 ? + MAT_PROP_TEXTURE : MAT_PROP_SHADER; + + success = read_material_chunk(fp, &ctx, prop); } else if (memcmp(label, "PHYS", 4) == 0) { if (!read_entt) { TraceLog(LOG_ERROR, "PHYS found before ENTT."); @@ -1059,6 +1210,8 @@ save_file_write(cstr path) { write_entity_chunk(fp) && write_transform_chunk(fp) && write_model_chunk(fp) && + write_material_chunk(fp, MAT_PROP_TEXTURE) && + write_material_chunk(fp, MAT_PROP_SHADER) && write_physics_chunk(fp); if (fclose(fp) != 0) { |
