From b23d05bcc221a6a480232055beedcb2f2cee898f Mon Sep 17 00:00:00 2001 From: kichikuou Date: Mon, 4 Jul 2022 11:38:55 +0900 Subject: [PATCH] ReignEngine: Load material parameters from .amt file --- src/3d/3d_internal.h | 22 ++++++++++++ src/3d/model.c | 84 ++++++++++++++++++++++++++------------------ src/3d/parser.c | 58 ++++++++++++++++++++++++++++++ 3 files changed, 129 insertions(+), 35 deletions(-) diff --git a/src/3d/3d_internal.h b/src/3d/3d_internal.h index bd7422c..9b8af3d 100644 --- a/src/3d/3d_internal.h +++ b/src/3d/3d_internal.h @@ -47,6 +47,8 @@ struct mesh { struct material { GLuint color_map; bool opaque; + float specular_strength; + float specular_shininess; }; struct bone { @@ -191,6 +193,22 @@ struct mot_bone { struct mot_frame frames[]; }; +struct amt { + int version; + int nr_materials; + struct amt_material *materials[]; +}; + +struct amt_material { + char *name; + float fields[]; +}; + +enum amt_field_index { + AMT_SPECULAR_STRENGTH = 0, + AMT_SPECULAR_SHININESS = 2, +}; + struct pol *pol_parse(uint8_t *data, size_t size); void pol_free(struct pol *pol); struct pol_bone *pol_find_bone(struct pol *pol, uint32_t id); @@ -198,4 +216,8 @@ struct pol_bone *pol_find_bone(struct pol *pol, uint32_t id); struct mot *mot_parse(uint8_t *data, size_t size); void mot_free(struct mot *mot); +struct amt *amt_parse(uint8_t *data, size_t size); +void amt_free(struct amt *amt); +struct amt_material *amt_find_material(struct amt *amt, const char *name); + #endif /* SYSTEM4_3D_3D_INTERNAL_H */ diff --git a/src/3d/model.c b/src/3d/model.c index 664b1e2..f8df832 100644 --- a/src/3d/model.c +++ b/src/3d/model.c @@ -36,28 +36,33 @@ struct vertex { GLfloat bone_weight[NR_WEIGHTS]; }; -static bool init_material(struct material *material, const struct pol_material *m, struct archive *aar, const char *path) +static struct archive_data *get_aar_entry(struct archive *aar, const char *dir, const char *name, const char *ext) +{ + char *path = xmalloc(strlen(dir) + strlen(name) + strlen(ext) + 2); + sprintf(path, "%s\\%s%s", dir, name, ext); + struct archive_data *dfile = archive_get_by_name(aar, path); + free(path); + return dfile; +} + +static bool init_material(struct material *material, const struct pol_material *m, struct amt *amt, struct archive *aar, const char *path) { if (!m->textures[COLOR_MAP]) { WARNING("No color texture"); return false; } - char *texture_path = xmalloc(strlen(path) + strlen(m->textures[COLOR_MAP]) + 2); - sprintf(texture_path, "%s\\%s", path, m->textures[COLOR_MAP]); - struct archive_data *dfile = archive_get_by_name(aar, texture_path); + struct archive_data *dfile = get_aar_entry(aar, path, m->textures[COLOR_MAP], ""); if (!dfile) { - WARNING("cannot load texture %s", texture_path); - free(texture_path); + WARNING("cannot load texture %s\\%s", path, m->textures[COLOR_MAP]); return false; } struct cg *cg = cg_load_data(dfile); - archive_free_data(dfile); if (!cg) { - WARNING("cg_load_data failed: %s", texture_path); - free(texture_path); + WARNING("cg_load_data failed: %s", dfile->name); + archive_free_data(dfile); return false; } - free(texture_path); + archive_free_data(dfile); glGenTextures(1, &material->color_map); glBindTexture(GL_TEXTURE_2D, material->color_map); @@ -69,8 +74,14 @@ static bool init_material(struct material *material, const struct pol_material * glGenerateMipmap(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, 0); material->opaque = !cg->metrics.has_alpha; - cg_free(cg); + + struct amt_material *amt_m = amt ? amt_find_material(amt, m->name) : NULL; + if (amt_m) { + material->specular_strength = amt_m->fields[AMT_SPECULAR_STRENGTH]; + material->specular_shininess = amt_m->fields[AMT_SPECULAR_SHININESS]; + } + return true; } @@ -206,24 +217,30 @@ struct model *model_load(struct archive *aar, const char *path, struct RE_render const char *basename = strrchr(path, '\\'); basename = basename ? basename + 1 : path; - char *polname = xmalloc(strlen(path) + strlen(basename) + 6); - sprintf(polname, "%s\\%s.POL", path, basename); - struct archive_data *dfile = archive_get_by_name(aar, polname); - if (!dfile) { - WARNING("%s: not found", polname); - free(polname); + // Load .POL file + struct archive_data *pol_file = get_aar_entry(aar, path, basename, ".POL"); + if (!pol_file) { + WARNING("%s\\%s.POL: not found", path, basename); return NULL; } - - struct pol *pol = pol_parse(dfile->data, dfile->size); - archive_free_data(dfile); + struct pol *pol = pol_parse(pol_file->data, pol_file->size); if (!pol) { - WARNING("%s: parse error", polname); - free(polname); + WARNING("%s: parse error", pol_file->name); + archive_free_data(pol_file); return NULL; } - free(polname); + archive_free_data(pol_file); + + // Load .amt file, if any + struct amt *amt = NULL; + struct archive_data *amt_file = get_aar_entry(aar, path, basename, ".amt"); + if (amt_file) { + amt = amt_parse(amt_file->data, amt_file->size); + if (!amt) + WARNING("%s: parse error", amt_file->name); + archive_free_data(amt_file); + } struct model *model = xcalloc(1, sizeof(struct model)); model->path = strdup(path); @@ -254,12 +271,12 @@ struct model *model_load(struct archive *aar, const char *path, struct RE_render for (uint32_t i = 0; i < pol->nr_materials; i++) { if (pol->materials[i].nr_children == 0) { init_material(&model->materials[material_offsets[i]], - &pol->materials[i].m, aar, path); + &pol->materials[i].m, amt, aar, path); continue; } for (uint32_t j = 0; j < pol->materials[i].nr_children; j++) { init_material(&model->materials[material_offsets[i] + j], - &pol->materials[i].children[j], aar, path); + &pol->materials[i].children[j], amt, aar, path); } } @@ -279,6 +296,8 @@ struct model *model_load(struct archive *aar, const char *path, struct RE_render } free(material_offsets); + if (amt) + amt_free(amt); pol_free(pol); return model; } @@ -313,24 +332,19 @@ struct motion *motion_load(const char *name, struct RE_instance *instance, struc struct model *model = instance->model; if (!model) return NULL; - char *motname = xmalloc(strlen(model->path) + strlen(name) + 6); - sprintf(motname, "%s\\%s.MOT", model->path, name); - struct archive_data *dfile = archive_get_by_name(aar, motname); + struct archive_data *dfile = get_aar_entry(aar, model->path, name, ".MOT"); if (!dfile) { - WARNING("%s: not found", motname); - free(motname); + WARNING("%s\\%s.MOT: not found", model->path, name); return NULL; } - struct mot *mot = mot_parse(dfile->data, dfile->size); - archive_free_data(dfile); if (!mot) { - WARNING("%s: parse error", motname); - free(motname); + WARNING("%s: parse error", dfile->name); + archive_free_data(dfile); return NULL; } - free(motname); + archive_free_data(dfile); if (model->nr_bones != (int)mot->nr_bones) ERROR("%s: wrong number of bones. Expected %d but got %d", name, model->nr_bones, mot->nr_bones); diff --git a/src/3d/parser.c b/src/3d/parser.c index bac6d99..49e0743 100644 --- a/src/3d/parser.c +++ b/src/3d/parser.c @@ -339,3 +339,61 @@ void mot_free(struct mot *mot) } free(mot); } + +struct amt *amt_parse(uint8_t *data, size_t size) +{ + struct buffer r; + buffer_init(&r, data, size); + if (memcmp(buffer_strdata(&r), "AMT\0", 4)) + return NULL; + buffer_skip(&r, 4); + + uint32_t version = buffer_read_int32(&r); + int nr_fields; + switch (version) { + case 1: nr_fields = 3; break; + case 2: nr_fields = 5; break; + case 3: nr_fields = 6; break; + case 4: nr_fields = 7; break; + case 5: nr_fields = 11; break; + case 6: nr_fields = 15; break; + default: + WARNING("unknown MOT version: %d", version); + return NULL; + } + int nr_materials = buffer_read_int32(&r); + + struct amt *amt = xmalloc(sizeof(struct amt) + sizeof(struct amt_material *) * nr_materials); + amt->version = version; + amt->nr_materials = nr_materials; + for (int i = 0; i < nr_materials; i++) { + struct amt_material *m = amt->materials[i] = + xmalloc(sizeof(struct amt_material) + sizeof(float) * nr_fields); + m->name = read_cstring(&r); + for (int j = 0; j < nr_fields; j++) + m->fields[j] = buffer_read_float(&r); + } + + if (buffer_remaining(&r) != 0) { + WARNING("extra data at end"); + } + return amt; +} + +void amt_free(struct amt *amt) +{ + for (int i = 0; i < amt->nr_materials; i++) { + free(amt->materials[i]->name); + free(amt->materials[i]); + } + free(amt); +} + +struct amt_material *amt_find_material(struct amt *amt, const char *name) +{ + for (int i = 0; i < amt->nr_materials; i++) { + if (!strcmp(amt->materials[i]->name, name)) + return amt->materials[i]; + } + return NULL; +}