diff --git a/src/3d/3d_internal.h b/src/3d/3d_internal.h index 798cdc7..f29aeaa 100644 --- a/src/3d/3d_internal.h +++ b/src/3d/3d_internal.h @@ -40,9 +40,9 @@ struct model { int nr_materials; struct material *materials; int nr_bones; - struct bone *bones; - struct hash_table *bone_map; // bone id in POL/MOT -> struct bone * - struct hash_table *bone_name_map; // bone name -> (struct bone * | NULL) + struct bone *bones; // ordered so that parents precede their children + struct bone **bones_by_pol_index; // POL bone array index -> struct bone * + struct hash_table *bone_map; // bone id in POL -> struct bone * struct hash_table *mot_cache; // name -> struct mot * struct collider *collider; vec3 aabb[2]; // axis-aligned bounding box diff --git a/src/3d/model.c b/src/3d/model.c index 34b46f8..fb70952 100644 --- a/src/3d/model.c +++ b/src/3d/model.c @@ -485,14 +485,6 @@ static struct bone *add_bone(struct model *model, struct pol *pol, struct pol_bo glm_quat_mat4(pol_bone->rotq, bone->inverse_bind_matrix); glm_translate(bone->inverse_bind_matrix, pol_bone->pos); - // Update bone_name_map. If the bone name is not unique in the POL, set the - // map value to NULL so that ID matching will be used. - struct ht_slot *slot = ht_put(model->bone_name_map, pol_bone->name, bone); - if (slot->value != bone) { - NOTICE("%s: non-unique bone %s", model->path, pol_bone->name); - slot->value = NULL; - } - model->nr_bones++; return bone; } @@ -546,11 +538,11 @@ struct model *model_load(struct archive *aar, const char *path) if (pol->nr_bones > MAX_BONES) ERROR("%s: Too many bones (%u)", model->path, pol->nr_bones); model->bone_map = ht_create(pol->nr_bones * 3 / 2); - model->bone_name_map = ht_create(pol->nr_bones * 3 / 2); model->mot_cache = ht_create(16); model->bones = xcalloc_aligned(pol->nr_bones, struct bone); + model->bones_by_pol_index = xcalloc(pol->nr_bones, sizeof(struct bone *)); for (uint32_t i = 0; i < pol->nr_bones; i++) { - add_bone(model, pol, &pol->bones[i]); + model->bones_by_pol_index[i] = add_bone(model, pol, &pol->bones[i]); } if (model->nr_bones != (int)pol->nr_bones) ERROR("%s: Broken bone data", model->path); @@ -636,10 +628,9 @@ void model_free(struct model *model) for (int i = 0; i < model->nr_bones; i++) destroy_bone(&model->bones[i]); xfree_aligned(model->bones); + free(model->bones_by_pol_index); if (model->bone_map) ht_free_int(model->bone_map); - if (model->bone_name_map) - ht_free(model->bone_name_map); if (model->mot_cache) { ht_foreach_value(model->mot_cache, (void(*)(void*))mot_free); ht_free(model->mot_cache); @@ -746,11 +737,6 @@ struct model *model_create_sphere(int r, int g, int b, int a) return model; } -static int cmp_motions_by_bone_id(const void *lhs, const void *rhs) -{ - return (*(struct mot_bone **)lhs)->id - (*(struct mot_bone **)rhs)->id; -} - static struct mot *mot_load(const char *name, struct model *model, struct archive *aar) { struct archive_data *mot_file = RE_get_aar_entry(aar, model->path, name, ".MOT"); @@ -770,18 +756,14 @@ static struct mot *mot_load(const char *name, struct model *model, struct archiv ERROR("%s: wrong number of bones. Expected %d but got %d", name, model->nr_bones, mot->nr_bones); // Reorder mot->motions so that motion for model->bones[i] can be - // accessed by mot->motions[i]. + // accessed by mot->motions[i]. MOT bones are applied to POL bones purely + // by array index; bone name and bone id are never used for matching. + struct mot_bone **reordered = xmalloc(mot->nr_bones * sizeof(struct mot_bone *)); for (uint32_t i = 0; i < mot->nr_bones; i++) { - // Match by name first, since some MOT have wrong bone IDs (e.g. maidsan_ahoge_*). - struct bone *bone = ht_get(model->bone_name_map, mot->motions[i]->name, NULL); - // If it is not found or is NULL (non-unique bone name), match by bone ID. - if (!bone) - bone = ht_get_int(model->bone_map, mot->motions[i]->id, NULL); - if (!bone) - ERROR("%s: invalid bone \"%s\" (%d)", name, mot->motions[i]->name, mot->motions[i]->id); - mot->motions[i]->id = bone->index; + reordered[model->bones_by_pol_index[i]->index] = mot->motions[i]; } - qsort(mot->motions, mot->nr_bones, sizeof(struct mot_bone *), cmp_motions_by_bone_id); + memcpy(mot->motions, reordered, mot->nr_bones * sizeof(struct mot_bone *)); + free(reordered); // Load optional sidecar file. if (re_plugin_version <= RE_TAPIR_PLUGIN) {