Move bone map to boneNodeName conversion to MdlReader
This commit is contained in:
parent
5fce19c95b
commit
bb2b5b255b
5 changed files with 43 additions and 56 deletions
|
@ -114,7 +114,8 @@ void MdlReader::doLoad() {
|
|||
readNodeNames(nameOffsets);
|
||||
|
||||
// Read nodes
|
||||
unique_ptr<ModelNode> rootNode(readNode(offRootNode, nullptr));
|
||||
shared_ptr<ModelNode> rootNode(readNode(offRootNode, nullptr));
|
||||
prepareSkinMeshes();
|
||||
|
||||
// Load supermodel
|
||||
shared_ptr<Model> superModel;
|
||||
|
@ -158,7 +159,7 @@ void MdlReader::readNodeNames(const vector<uint32_t> &offsets) {
|
|||
}
|
||||
}
|
||||
|
||||
unique_ptr<ModelNode> MdlReader::readNode(uint32_t offset, const ModelNode *parent, bool anim) {
|
||||
shared_ptr<ModelNode> MdlReader::readNode(uint32_t offset, const ModelNode *parent, bool anim) {
|
||||
seek(kMdlDataOffset + offset);
|
||||
|
||||
uint16_t flags = readUint16();
|
||||
|
@ -177,13 +178,10 @@ unique_ptr<ModelNode> MdlReader::readNode(uint32_t offset, const ModelNode *pare
|
|||
throw runtime_error("Unsupported MDL node flags: " + to_string(flags));
|
||||
}
|
||||
string name(_nodeNames[nameIndex]);
|
||||
if (!anim) {
|
||||
_nodeFlags.insert(make_pair(name, flags));
|
||||
}
|
||||
glm::vec3 restPosition(glm::make_vec3(&positionValues[0]));
|
||||
glm::quat restOrientation(orientationValues[0], orientationValues[1], orientationValues[2], orientationValues[3]);
|
||||
|
||||
auto node = make_unique<ModelNode>(
|
||||
auto node = make_shared<ModelNode>(
|
||||
move(name),
|
||||
move(restPosition),
|
||||
move(restOrientation),
|
||||
|
@ -203,6 +201,10 @@ unique_ptr<ModelNode> MdlReader::readNode(uint32_t offset, const ModelNode *pare
|
|||
if (flags & NodeFlags::reference) {
|
||||
node->setReference(readReference());
|
||||
}
|
||||
if (!anim) {
|
||||
_nodes.push_back(node);
|
||||
_nodeFlags.insert(make_pair(name, flags));
|
||||
}
|
||||
|
||||
vector<float> controllerData(readFloatArray(kMdlDataOffset + controllerDataArrayDef.offset, controllerDataArrayDef.count));
|
||||
readControllers(controllerArrayDef.offset, controllerArrayDef.count, controllerData, anim, *node);
|
||||
|
@ -297,22 +299,10 @@ shared_ptr<ModelNode::TriangleMesh> MdlReader::readMesh(int flags) {
|
|||
vector<uint16_t> boneNodeSerial(readUint16Array(16));
|
||||
ignore(4); // padding
|
||||
|
||||
// boneNodeSerial above is a more compact representation of the bone
|
||||
// map, but it is limited to 16 bones, which is not enough for certain
|
||||
// models
|
||||
vector<float> boneMap(readFloatArray(kMdlDataOffset + offBones, numBones));
|
||||
for (size_t i = 0; i < boneMap.size(); ++i) {
|
||||
auto boneId = static_cast<uint16_t>(boneMap[i]);
|
||||
if (boneId != 0xffff) {
|
||||
if (boneId >= boneNodeSerial.size()) {
|
||||
boneNodeSerial.resize(boneId + 1);
|
||||
}
|
||||
boneNodeSerial[boneId] = static_cast<uint16_t>(i);
|
||||
}
|
||||
}
|
||||
|
||||
skin = make_shared<ModelNode::Skin>();
|
||||
skin->boneNodeSerial = move(boneNodeSerial);
|
||||
skin->boneMap = move(boneMap);
|
||||
attributes.offBoneIndices = offMdxBoneIndices;
|
||||
attributes.offBoneWeights = offMdxBoneWeights;
|
||||
|
||||
|
@ -676,6 +666,24 @@ void MdlReader::readControllers(uint32_t keyOffset, uint32_t keyCount, const vec
|
|||
}
|
||||
}
|
||||
|
||||
void MdlReader::prepareSkinMeshes() {
|
||||
for (auto &node : _nodes) {
|
||||
if (!node->isSkinMesh()) continue;
|
||||
|
||||
shared_ptr<ModelNode::Skin> skin(node->mesh()->skin);
|
||||
for (size_t i = 0; i < skin->boneMap.size(); ++i) {
|
||||
auto boneIdx = static_cast<uint16_t>(skin->boneMap[i]);
|
||||
if (boneIdx >= skin->boneNodeName.size()) {
|
||||
skin->boneNodeName.resize(boneIdx + 1);
|
||||
}
|
||||
if (boneIdx != 0xffff) {
|
||||
shared_ptr<ModelNode> boneNode(_nodes[i]);
|
||||
skin->boneNodeName[boneIdx] = boneNode->name();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vector<shared_ptr<Animation>> MdlReader::readAnimations(const vector<uint32_t> &offsets) {
|
||||
vector<shared_ptr<Animation>> anims;
|
||||
anims.reserve(offsets.size());
|
||||
|
@ -708,7 +716,7 @@ unique_ptr<Animation> MdlReader::readAnimation(uint32_t offset) {
|
|||
ArrayDefinition eventArrayDef(readArrayDefinition());
|
||||
ignore(4); // unknown
|
||||
|
||||
unique_ptr<ModelNode> rootNode(readNode(offRootNode, nullptr, true));
|
||||
shared_ptr<ModelNode> rootNode(readNode(offRootNode, nullptr, true));
|
||||
|
||||
// Events
|
||||
vector<Animation::Event> events;
|
||||
|
|
|
@ -77,6 +77,7 @@ private:
|
|||
std::unique_ptr<StreamReader> _mdxReader;
|
||||
bool _tsl { false }; /**< is this a TSL model? */
|
||||
std::vector<std::string> _nodeNames;
|
||||
std::vector<std::shared_ptr<ModelNode>> _nodes; /**< loaded model nodes (DFS ordering) */
|
||||
std::map<std::string, uint16_t> _nodeFlags;
|
||||
std::shared_ptr<graphics::Model> _model;
|
||||
|
||||
|
@ -84,7 +85,7 @@ private:
|
|||
|
||||
ArrayDefinition readArrayDefinition();
|
||||
void readNodeNames(const std::vector<uint32_t> &offsets);
|
||||
std::unique_ptr<graphics::ModelNode> readNode(uint32_t offset, const ModelNode *parent, bool anim = false);
|
||||
std::shared_ptr<graphics::ModelNode> readNode(uint32_t offset, const ModelNode *parent, bool anim = false);
|
||||
std::vector<std::shared_ptr<graphics::Animation>> readAnimations(const std::vector<uint32_t> &offsets);
|
||||
std::unique_ptr<graphics::Animation> readAnimation(uint32_t offset);
|
||||
void readControllers(uint32_t keyOffset, uint32_t keyCount, const std::vector<float> &data, bool anim, graphics::ModelNode &node);
|
||||
|
@ -96,6 +97,8 @@ private:
|
|||
|
||||
std::shared_ptr<ModelNode::AABBTree> readAABBTree(uint32_t offset);
|
||||
|
||||
void prepareSkinMeshes();
|
||||
|
||||
// Controllers
|
||||
|
||||
void initControllerFn();
|
||||
|
|
|
@ -46,8 +46,7 @@ Model::Model(
|
|||
throw invalid_argument("rootNode must not be null");
|
||||
}
|
||||
|
||||
fillNodeLookups(_rootNode);
|
||||
fillBoneNodeId();
|
||||
fillNodeByName(_rootNode);
|
||||
computeAABB();
|
||||
|
||||
for (auto &anim : animations) {
|
||||
|
@ -55,33 +54,11 @@ Model::Model(
|
|||
}
|
||||
}
|
||||
|
||||
void Model::fillNodeLookups(const shared_ptr<ModelNode> &node) {
|
||||
_nodes.push_back(node);
|
||||
void Model::fillNodeByName(const shared_ptr<ModelNode> &node) {
|
||||
_nodeByName.insert(make_pair(node->name(), node));
|
||||
|
||||
for (auto &child : node->children()) {
|
||||
fillNodeLookups(child);
|
||||
}
|
||||
}
|
||||
|
||||
void Model::fillBoneNodeId() {
|
||||
// In MDL files, bones reference node serial numbers (DFS ordering).
|
||||
// We want them to reference node names instead.
|
||||
|
||||
for (auto &node : _nodes) {
|
||||
if (!node->isSkinMesh()) continue;
|
||||
|
||||
shared_ptr<ModelNode::TriangleMesh> mesh(node->mesh());
|
||||
mesh->skin->boneNodeName.resize(mesh->skin->boneNodeSerial.size());
|
||||
|
||||
for (size_t i = 0; i < mesh->skin->boneNodeSerial.size(); ++i) {
|
||||
uint16_t nodeSerial = mesh->skin->boneNodeSerial[i];
|
||||
if (nodeSerial < static_cast<int>(_nodes.size())) {
|
||||
mesh->skin->boneNodeName[i] = _nodes[nodeSerial]->name();
|
||||
} else {
|
||||
mesh->skin->boneNodeName[i].clear();
|
||||
}
|
||||
}
|
||||
fillNodeByName(child);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
@ -94,16 +95,13 @@ private:
|
|||
std::shared_ptr<ModelNode> _rootNode;
|
||||
std::unordered_map<std::string, std::shared_ptr<Animation>> _animations;
|
||||
std::shared_ptr<Model> _superModel;
|
||||
float _animationScale;
|
||||
float _animationScale; /**< scales supermodel animations */
|
||||
|
||||
bool _affectedByFog;
|
||||
AABB _aabb;
|
||||
|
||||
std::vector<std::shared_ptr<ModelNode>> _nodes;
|
||||
bool _affectedByFog;
|
||||
std::unordered_map<std::string, std::shared_ptr<ModelNode>> _nodeByName;
|
||||
|
||||
void fillNodeLookups(const std::shared_ptr<ModelNode> &node);
|
||||
void fillBoneNodeId();
|
||||
void fillNodeByName(const std::shared_ptr<ModelNode> &node);
|
||||
void computeAABB();
|
||||
};
|
||||
|
||||
|
|
|
@ -40,13 +40,14 @@ namespace graphics {
|
|||
class Model;
|
||||
|
||||
/**
|
||||
* Model or animation node. Can be specialized to represent a triangle mesh, a light, an emitter and etc.
|
||||
* Model or animation node. Can be specialized to represent a triangle mesh, a
|
||||
* light, an emitter and etc.
|
||||
*/
|
||||
class ModelNode : boost::noncopyable {
|
||||
public:
|
||||
struct Skin {
|
||||
std::vector<std::string> boneNodeName;
|
||||
std::vector<uint16_t> boneNodeSerial; /**< temporary, used to fill boneNodeName above */
|
||||
std::vector<std::string> boneNodeName; /**< node name per bone, used for skeletal animation */
|
||||
std::vector<float> boneMap; /**< bone index per node (DFS ordering) */
|
||||
};
|
||||
|
||||
struct UVAnimation {
|
||||
|
|
Loading…
Reference in a new issue