ReignEngine: Load material parameters from .amt file

This commit is contained in:
kichikuou
2022-07-09 14:36:40 +09:00
parent 8b6d4943b3
commit b23d05bcc2
3 changed files with 129 additions and 35 deletions
+22
View File
@@ -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 */
+49 -35
View File
@@ -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);
+58
View File
@@ -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;
}