Decompile 3 functions in Source/Resource/Models/ModelResourceV2.cpp, Source/Resource/Models/ModelResource.h
Batch #1548 by ragnarok-clanker: 0 byte-identical, 3 confirmed by peer review. - fn_08020 C3dModelResV2::ReadVersion1: logic confirmed by peer review - fn_08021 C3dModelResV2::ReadVersion2: logic confirmed by peer review - fn_08022 C3dModelResV2::ReadVersion3: logic confirmed by peer review Reviewed-by: ragnarok-clanker
This commit is contained in:
parent
647969db3d
commit
f0050dbf61
2 changed files with 331 additions and 124 deletions
|
|
@ -143,7 +143,9 @@ public:
|
|||
|
||||
private:
|
||||
void ReadVersion(ResourceByteReader& input, unsigned minor);
|
||||
void ReadNode(ResourceByteReader& input, unsigned minor, const std::vector<std::string>& textureNames);
|
||||
void ReadVersion1(ResourceByteReader& input);
|
||||
void ReadVersion2(ResourceByteReader& input);
|
||||
void ReadVersion3(ResourceByteReader& input);
|
||||
};
|
||||
|
||||
static_assert(sizeof(ModelPositionKey) == 16);
|
||||
|
|
|
|||
|
|
@ -9,16 +9,6 @@
|
|||
#include <cstring>
|
||||
|
||||
namespace {
|
||||
// INLINED
|
||||
std::string ReadName(ResourceByteReader& input) {
|
||||
unsigned bytes = 0;
|
||||
input.Read(&bytes, 4);
|
||||
char name[40]{};
|
||||
input.Read(name, bytes);
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
// INLINED
|
||||
void ReadKeys(ResourceByteReader& input, std::vector<ModelRotationKey>& keys, bool scale) {
|
||||
int count = 0;
|
||||
|
|
@ -51,6 +41,17 @@ C3dModelResV2* C3dModelResV2::Create() {
|
|||
return new C3dModelResV2(*this->m_context);
|
||||
}
|
||||
|
||||
// INLINED
|
||||
inline void C3dModelResV2::ReadVersion(ResourceByteReader& input, unsigned minor) {
|
||||
if (minor == 1) {
|
||||
this->ReadVersion1(input);
|
||||
} else if (minor == 2) {
|
||||
this->ReadVersion2(input);
|
||||
} else {
|
||||
this->ReadVersion3(input);
|
||||
}
|
||||
}
|
||||
|
||||
// OFFSET: 0x00751F70
|
||||
// FUNCTION: fn_07954
|
||||
bool C3dModelResV2::Load(const char* name) {
|
||||
|
|
@ -90,161 +91,365 @@ bool C3dModelResV2::Load(const char* name) {
|
|||
return true;
|
||||
}
|
||||
|
||||
// INLINED
|
||||
inline void C3dModelResV2::ReadNode(ResourceByteReader& input, unsigned minor, const std::vector<std::string>& textureNames) {
|
||||
auto node = std::make_unique<ModelNodeV2>();
|
||||
node->model = this;
|
||||
node->mesh = std::make_unique<ModelMesh>();
|
||||
node->name = ReadName(input);
|
||||
node->parentName = ReadName(input);
|
||||
int textureCount = 0;
|
||||
input.Read(&textureCount, 4);
|
||||
|
||||
for (int index = 0; index < textureCount; ++index) {
|
||||
std::string name;
|
||||
|
||||
if (minor < 3) {
|
||||
int texture = 0;
|
||||
input.Read(&texture, 4);
|
||||
name = textureNames[texture];
|
||||
} else {
|
||||
name = ReadName(input);
|
||||
}
|
||||
|
||||
CTexture* texture = this->m_context->textures.Load(name.c_str(), 0, false, true, false);
|
||||
node->textures.push_back(texture);
|
||||
|
||||
if (texture) {
|
||||
texture->Retain();
|
||||
}
|
||||
}
|
||||
|
||||
input.Read(node->transform, sizeof(node->transform));
|
||||
ModelMesh& mesh = *node->mesh;
|
||||
input.Read(&mesh.vertexCount, 4);
|
||||
mesh.vertices = new std::array<float, 3>[mesh.vertexCount]{};
|
||||
input.Read(mesh.vertices, static_cast<unsigned>(mesh.vertexCount) * 12u);
|
||||
input.Read(&mesh.textureVertexCount, 4);
|
||||
mesh.textureVertices = new ModelTextureVertex[mesh.textureVertexCount];
|
||||
input.Read(mesh.textureVertices, static_cast<unsigned>(mesh.textureVertexCount) * 12u);
|
||||
input.Read(&mesh.faceCount, 4);
|
||||
mesh.faces = new ModelFace[mesh.faceCount];
|
||||
|
||||
for (int index = 0; index < mesh.faceCount; ++index) {
|
||||
ModelFace& face = mesh.faces[index];
|
||||
std::vector<unsigned char> bytes;
|
||||
unsigned char fixed[24];
|
||||
const unsigned char* record;
|
||||
unsigned size;
|
||||
|
||||
if (minor == 1) {
|
||||
input.Read(fixed, sizeof(fixed));
|
||||
record = fixed;
|
||||
size = sizeof(fixed);
|
||||
} else {
|
||||
size = 0;
|
||||
input.Read(&size, 4);
|
||||
bytes.resize(size);
|
||||
input.Read(bytes.data(), size);
|
||||
record = bytes.data();
|
||||
}
|
||||
|
||||
std::memcpy(face.vertices, record, sizeof(face.vertices));
|
||||
std::memcpy(face.textureVertices, record + 6, sizeof(face.textureVertices));
|
||||
std::memcpy(&face.texture, record + 12, sizeof(face.texture));
|
||||
std::memcpy(&face.twoSided, record + 16, sizeof(face.twoSided));
|
||||
const unsigned groups = (size - 20u) / 4u;
|
||||
face.smoothing.resize(groups);
|
||||
std::memcpy(face.smoothing.data(), record + 20, groups * 4u);
|
||||
}
|
||||
|
||||
// INLINED
|
||||
std::sort(mesh.faces, mesh.faces + mesh.faceCount, [](const ModelFace& a, const ModelFace& b) { return a.texture < b.texture; });
|
||||
mesh.CalculateNormals();
|
||||
ReadKeys(input, node->scaleKeys, false);
|
||||
ReadKeys(input, node->rotationKeys, true);
|
||||
ReadKeys(input, node->positionKeys, false);
|
||||
|
||||
if (minor == 3) {
|
||||
int textureAnimations = 0;
|
||||
input.Read(&textureAnimations, 4);
|
||||
|
||||
for (int index = 0; index < textureAnimations; ++index) {
|
||||
int texture = 0;
|
||||
input.Read(&texture, 4);
|
||||
ModelTextureChannels channels;
|
||||
int channelCount = 0;
|
||||
input.Read(&channelCount, 4);
|
||||
|
||||
for (int channel = 0; channel < channelCount; ++channel) {
|
||||
int id = 0;
|
||||
int keyCount = 0;
|
||||
input.Read(&id, 4);
|
||||
input.Read(&keyCount, 4);
|
||||
|
||||
for (int key = 0; key < keyCount; ++key) {
|
||||
ModelTextureKey value;
|
||||
input.Read(&value, sizeof(value));
|
||||
channels[id].push_back(value);
|
||||
}
|
||||
}
|
||||
|
||||
node->textureKeys[texture] = std::move(channels);
|
||||
}
|
||||
}
|
||||
|
||||
this->meshes[node->name] = node->mesh.get();
|
||||
this->nodes.push_back(node.release());
|
||||
}
|
||||
|
||||
// OFFSET: 0x00759ED0
|
||||
// OFFSET: 0x0075AB20
|
||||
// OFFSET: 0x0075B8E0
|
||||
void C3dModelResV2::ReadVersion(ResourceByteReader& input, unsigned minor) {
|
||||
// FUNCTION: fn_08020
|
||||
void C3dModelResV2::ReadVersion1(ResourceByteReader& input) {
|
||||
input.Read(&this->animationLength, 4);
|
||||
input.Read(&this->shade, 4);
|
||||
input.Read(&this->alpha, 1);
|
||||
input.Read(&this->framesPerSecond, 4);
|
||||
std::vector<std::string> textureNames;
|
||||
int textureCount = 0;
|
||||
input.Read(&textureCount, 4);
|
||||
std::vector<std::string> textureNames;
|
||||
|
||||
if (minor < 3) {
|
||||
for (int index = 0; index < textureCount; ++index) {
|
||||
unsigned bytes = 0;
|
||||
input.Read(&bytes, 4);
|
||||
char name[40]{};
|
||||
input.Read(name, bytes);
|
||||
textureNames.emplace_back(name);
|
||||
}
|
||||
} else {
|
||||
for (int index = 0; index < textureCount; ++index) {
|
||||
unsigned bytes = 0;
|
||||
input.Read(&bytes, 4);
|
||||
char name[40]{};
|
||||
input.Read(name, bytes);
|
||||
this->rootNames.emplace_back(name);
|
||||
}
|
||||
for (int index = 0; index < textureCount; ++index) {
|
||||
unsigned bytes = 0;
|
||||
input.Read(&bytes, 4);
|
||||
char name[40]{};
|
||||
input.Read(name, bytes);
|
||||
textureNames.emplace_back(name);
|
||||
}
|
||||
|
||||
if (minor < 3) {
|
||||
int rootCount = 0;
|
||||
input.Read(&rootCount, 4);
|
||||
int rootCount = 0;
|
||||
input.Read(&rootCount, 4);
|
||||
|
||||
for (int index = 0; index < rootCount; ++index) {
|
||||
unsigned bytes = 0;
|
||||
input.Read(&bytes, 4);
|
||||
char name[40]{};
|
||||
input.Read(name, bytes);
|
||||
this->rootNames.emplace_back(name);
|
||||
}
|
||||
for (int index = 0; index < rootCount; ++index) {
|
||||
unsigned bytes = 0;
|
||||
input.Read(&bytes, 4);
|
||||
char name[40]{};
|
||||
input.Read(name, bytes);
|
||||
this->rootNames.emplace_back(name);
|
||||
}
|
||||
|
||||
int nodeCount = 0;
|
||||
input.Read(&nodeCount, 4);
|
||||
|
||||
for (int index = 0; index < nodeCount; ++index) {
|
||||
this->ReadNode(input, minor, textureNames);
|
||||
auto* node = new ModelNodeV2;
|
||||
node->model = this;
|
||||
node->mesh.reset(new ModelMesh);
|
||||
unsigned bytes = 0;
|
||||
input.Read(&bytes, 4);
|
||||
char name[40]{};
|
||||
input.Read(name, bytes);
|
||||
node->name = name;
|
||||
bytes = 0;
|
||||
input.Read(&bytes, 4);
|
||||
|
||||
if (static_cast<int>(bytes) > 0) {
|
||||
char parentName[40]{};
|
||||
input.Read(parentName, bytes);
|
||||
node->parentName = parentName;
|
||||
}
|
||||
|
||||
int nodeTextureCount = 0;
|
||||
input.Read(&nodeTextureCount, 4);
|
||||
|
||||
for (int texture = 0; texture < nodeTextureCount; ++texture) {
|
||||
int textureIndex = 0;
|
||||
input.Read(&textureIndex, 4);
|
||||
CTexture* loaded = this->m_context->textures.Load(textureNames[textureIndex].c_str(), 0, false, true, false);
|
||||
node->textures.push_back(loaded);
|
||||
|
||||
if (loaded) {
|
||||
loaded->Retain();
|
||||
}
|
||||
}
|
||||
|
||||
input.Read(node->transform, sizeof(node->transform));
|
||||
ModelMesh& mesh = *node->mesh;
|
||||
input.Read(&mesh.vertexCount, 4);
|
||||
mesh.vertices = new std::array<float, 3>[mesh.vertexCount]{};
|
||||
input.Read(mesh.vertices, static_cast<unsigned>(mesh.vertexCount) * 12u);
|
||||
input.Read(&mesh.textureVertexCount, 4);
|
||||
mesh.textureVertices = new ModelTextureVertex[mesh.textureVertexCount];
|
||||
input.Read(mesh.textureVertices, static_cast<unsigned>(mesh.textureVertexCount) * 12u);
|
||||
input.Read(&mesh.faceCount, 4);
|
||||
mesh.faces = new ModelFace[mesh.faceCount];
|
||||
|
||||
for (int face = 0; face < mesh.faceCount; ++face) {
|
||||
ModelFace& target = mesh.faces[face];
|
||||
struct {
|
||||
/* 0000 */ std::uint16_t vertices[3];
|
||||
/* 0006 */ std::uint16_t textureVertices[3];
|
||||
/* 000C */ std::uint16_t texture;
|
||||
/* 000E */ std::uint16_t unknown_000E;
|
||||
/* 0010 */ std::uint32_t twoSided;
|
||||
/* 0014 */ std::uint32_t smoothing;
|
||||
} record;
|
||||
input.Read(&record, sizeof(record));
|
||||
std::memcpy(target.vertices, record.vertices, sizeof(target.vertices));
|
||||
std::memcpy(target.textureVertices, record.textureVertices, sizeof(target.textureVertices));
|
||||
target.texture = record.texture;
|
||||
target.unknown_000E = record.unknown_000E;
|
||||
target.twoSided = record.twoSided;
|
||||
|
||||
if (target.smoothing.empty()) {
|
||||
target.smoothing.push_back(record.smoothing);
|
||||
}
|
||||
}
|
||||
|
||||
std::sort(mesh.faces, mesh.faces + mesh.faceCount, [](const ModelFace& a, const ModelFace& b) { return a.texture < b.texture; });
|
||||
mesh.CalculateNormals();
|
||||
ReadKeys(input, node->scaleKeys, false);
|
||||
ReadKeys(input, node->rotationKeys, true);
|
||||
ReadKeys(input, node->positionKeys, false);
|
||||
this->nodes.push_back(node);
|
||||
this->meshes[node->name] = node->mesh.get();
|
||||
}
|
||||
|
||||
for (ModelNode* node : this->nodes) {
|
||||
if (!node->parentName.empty()) {
|
||||
ModelNode* parent = this->FindNode(node->parentName.c_str());
|
||||
|
||||
if (parent) {
|
||||
node->parent = parent;
|
||||
parent->children.push_back(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int volumeCount = 0;
|
||||
input.Read(&volumeCount, 4);
|
||||
|
||||
for (int index = 0; index < volumeCount; ++index) {
|
||||
auto* volume = new ModelVolume;
|
||||
std::memset(volume, 0, 132);
|
||||
input.Read(volume, sizeof(ModelVolume));
|
||||
this->volumes.push_back(volume);
|
||||
}
|
||||
}
|
||||
|
||||
// OFFSET: 0x0075AB20
|
||||
// FUNCTION: fn_08021
|
||||
void C3dModelResV2::ReadVersion2(ResourceByteReader& input) {
|
||||
input.Read(&this->animationLength, 4);
|
||||
input.Read(&this->shade, 4);
|
||||
input.Read(&this->alpha, 1);
|
||||
input.Read(&this->framesPerSecond, 4);
|
||||
int textureCount = 0;
|
||||
input.Read(&textureCount, 4);
|
||||
std::vector<std::string> textureNames;
|
||||
|
||||
for (int index = 0; index < textureCount; ++index) {
|
||||
unsigned bytes = 0;
|
||||
input.Read(&bytes, 4);
|
||||
char name[40]{};
|
||||
input.Read(name, bytes);
|
||||
textureNames.emplace_back(name);
|
||||
}
|
||||
|
||||
int rootCount = 0;
|
||||
input.Read(&rootCount, 4);
|
||||
|
||||
for (int index = 0; index < rootCount; ++index) {
|
||||
unsigned bytes = 0;
|
||||
input.Read(&bytes, 4);
|
||||
char name[40]{};
|
||||
input.Read(name, bytes);
|
||||
this->rootNames.emplace_back(name);
|
||||
}
|
||||
|
||||
int nodeCount = 0;
|
||||
input.Read(&nodeCount, 4);
|
||||
|
||||
for (int index = 0; index < nodeCount; ++index) {
|
||||
auto* node = new ModelNodeV2;
|
||||
node->model = this;
|
||||
node->mesh.reset(new ModelMesh);
|
||||
unsigned bytes = 0;
|
||||
input.Read(&bytes, 4);
|
||||
char name[40]{};
|
||||
input.Read(name, bytes);
|
||||
node->name = name;
|
||||
bytes = 0;
|
||||
input.Read(&bytes, 4);
|
||||
|
||||
if (static_cast<int>(bytes) > 0) {
|
||||
char parentName[40]{};
|
||||
input.Read(parentName, bytes);
|
||||
node->parentName = parentName;
|
||||
}
|
||||
|
||||
int nodeTextureCount = 0;
|
||||
input.Read(&nodeTextureCount, 4);
|
||||
|
||||
for (int texture = 0; texture < nodeTextureCount; ++texture) {
|
||||
int textureIndex = 0;
|
||||
input.Read(&textureIndex, 4);
|
||||
CTexture* loaded = this->m_context->textures.Load(textureNames[textureIndex].c_str(), 0, false, true, false);
|
||||
node->textures.push_back(loaded);
|
||||
|
||||
if (loaded) {
|
||||
loaded->Retain();
|
||||
}
|
||||
}
|
||||
|
||||
input.Read(node->transform, sizeof(node->transform));
|
||||
ModelMesh& mesh = *node->mesh;
|
||||
input.Read(&mesh.vertexCount, 4);
|
||||
mesh.vertices = new std::array<float, 3>[mesh.vertexCount]{};
|
||||
input.Read(mesh.vertices, static_cast<unsigned>(mesh.vertexCount) * 12u);
|
||||
input.Read(&mesh.textureVertexCount, 4);
|
||||
mesh.textureVertices = new ModelTextureVertex[mesh.textureVertexCount];
|
||||
input.Read(mesh.textureVertices, static_cast<unsigned>(mesh.textureVertexCount) * 12u);
|
||||
input.Read(&mesh.faceCount, 4);
|
||||
mesh.faces = new ModelFace[mesh.faceCount];
|
||||
|
||||
for (int face = 0; face < mesh.faceCount; ++face) {
|
||||
ModelFace& target = mesh.faces[face];
|
||||
unsigned size = 0;
|
||||
input.Read(&size, 4);
|
||||
std::vector<unsigned char> record(size);
|
||||
input.Read(record.data(), size);
|
||||
std::memcpy(&target, record.data(), 20);
|
||||
const unsigned groups = (size - 20u) / 4u;
|
||||
target.smoothing.resize(groups);
|
||||
std::memcpy(target.smoothing.data(), record.data() + 20, groups * 4u);
|
||||
}
|
||||
|
||||
std::sort(mesh.faces, mesh.faces + mesh.faceCount, [](const ModelFace& a, const ModelFace& b) { return a.texture < b.texture; });
|
||||
mesh.CalculateNormals();
|
||||
ReadKeys(input, node->scaleKeys, false);
|
||||
ReadKeys(input, node->rotationKeys, true);
|
||||
ReadKeys(input, node->positionKeys, false);
|
||||
this->nodes.push_back(node);
|
||||
this->meshes[node->name] = node->mesh.get();
|
||||
}
|
||||
|
||||
for (ModelNode* node : this->nodes) {
|
||||
if (!node->parentName.empty()) {
|
||||
ModelNode* parent = this->FindNode(node->parentName.c_str());
|
||||
|
||||
if (parent) {
|
||||
node->parent = parent;
|
||||
parent->children.push_back(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int volumeCount = 0;
|
||||
input.Read(&volumeCount, 4);
|
||||
|
||||
for (int index = 0; index < volumeCount; ++index) {
|
||||
auto* volume = new ModelVolume;
|
||||
std::memset(volume, 0, 132);
|
||||
input.Read(volume, sizeof(ModelVolume));
|
||||
this->volumes.push_back(volume);
|
||||
}
|
||||
}
|
||||
|
||||
// OFFSET: 0x0075B8E0
|
||||
// FUNCTION: fn_08022
|
||||
void C3dModelResV2::ReadVersion3(ResourceByteReader& input) {
|
||||
input.Read(&this->animationLength, 4);
|
||||
input.Read(&this->shade, 4);
|
||||
input.Read(&this->alpha, 1);
|
||||
input.Read(&this->framesPerSecond, 4);
|
||||
int rootCount = 0;
|
||||
input.Read(&rootCount, 4);
|
||||
|
||||
for (int index = 0; index < rootCount; ++index) {
|
||||
unsigned bytes = 0;
|
||||
input.Read(&bytes, 4);
|
||||
char name[40]{};
|
||||
input.Read(name, bytes);
|
||||
this->rootNames.emplace_back(name);
|
||||
}
|
||||
|
||||
int nodeCount = 0;
|
||||
input.Read(&nodeCount, 4);
|
||||
|
||||
for (int index = 0; index < nodeCount; ++index) {
|
||||
auto* node = new ModelNodeV2;
|
||||
node->model = this;
|
||||
node->mesh.reset(new ModelMesh);
|
||||
unsigned bytes = 0;
|
||||
input.Read(&bytes, 4);
|
||||
char name[40]{};
|
||||
input.Read(name, bytes);
|
||||
node->name = name;
|
||||
bytes = 0;
|
||||
input.Read(&bytes, 4);
|
||||
|
||||
if (static_cast<int>(bytes) > 0) {
|
||||
char parentName[40]{};
|
||||
input.Read(parentName, bytes);
|
||||
node->parentName = parentName;
|
||||
}
|
||||
|
||||
int nodeTextureCount = 0;
|
||||
input.Read(&nodeTextureCount, 4);
|
||||
|
||||
for (int texture = 0; texture < nodeTextureCount; ++texture) {
|
||||
unsigned textureBytes = 0;
|
||||
input.Read(&textureBytes, 4);
|
||||
char textureName[40]{};
|
||||
input.Read(textureName, textureBytes);
|
||||
CTexture* loaded = this->m_context->textures.Load(textureName, 0, false, true, false);
|
||||
node->textures.push_back(loaded);
|
||||
|
||||
if (loaded) {
|
||||
loaded->Retain();
|
||||
}
|
||||
}
|
||||
|
||||
input.Read(node->transform, sizeof(node->transform));
|
||||
ModelMesh& mesh = *node->mesh;
|
||||
input.Read(&mesh.vertexCount, 4);
|
||||
mesh.vertices = new std::array<float, 3>[mesh.vertexCount]{};
|
||||
input.Read(mesh.vertices, static_cast<unsigned>(mesh.vertexCount) * 12u);
|
||||
input.Read(&mesh.textureVertexCount, 4);
|
||||
mesh.textureVertices = new ModelTextureVertex[mesh.textureVertexCount];
|
||||
input.Read(mesh.textureVertices, static_cast<unsigned>(mesh.textureVertexCount) * 12u);
|
||||
input.Read(&mesh.faceCount, 4);
|
||||
mesh.faces = new ModelFace[mesh.faceCount];
|
||||
|
||||
for (int face = 0; face < mesh.faceCount; ++face) {
|
||||
ModelFace& target = mesh.faces[face];
|
||||
unsigned size = 0;
|
||||
input.Read(&size, 4);
|
||||
std::vector<unsigned char> record(size);
|
||||
input.Read(record.data(), size);
|
||||
std::memcpy(&target, record.data(), 20);
|
||||
const unsigned groups = (size - 20u) / 4u;
|
||||
target.smoothing.resize(groups);
|
||||
std::memcpy(target.smoothing.data(), record.data() + 20, groups * 4u);
|
||||
}
|
||||
|
||||
std::sort(mesh.faces, mesh.faces + mesh.faceCount, [](const ModelFace& a, const ModelFace& b) { return a.texture < b.texture; });
|
||||
mesh.CalculateNormals();
|
||||
ReadKeys(input, node->scaleKeys, false);
|
||||
ReadKeys(input, node->rotationKeys, true);
|
||||
ReadKeys(input, node->positionKeys, false);
|
||||
int textureAnimations = 0;
|
||||
input.Read(&textureAnimations, 4);
|
||||
|
||||
for (int animation = 0; animation < textureAnimations; ++animation) {
|
||||
int texture = 0;
|
||||
input.Read(&texture, 4);
|
||||
ModelTextureChannels channels;
|
||||
int channelCount = 0;
|
||||
input.Read(&channelCount, 4);
|
||||
|
||||
for (int channel = 0; channel < channelCount; ++channel) {
|
||||
int id = 0;
|
||||
int keyCount = 0;
|
||||
input.Read(&id, 4);
|
||||
input.Read(&keyCount, 4);
|
||||
|
||||
for (int key = 0; key < keyCount; ++key) {
|
||||
ModelTextureKey value;
|
||||
input.Read(&value, sizeof(value));
|
||||
channels[id].push_back(value);
|
||||
}
|
||||
}
|
||||
|
||||
node->textureKeys[texture] = std::move(channels);
|
||||
}
|
||||
|
||||
this->nodes.push_back(node);
|
||||
this->meshes[node->name] = node->mesh.get();
|
||||
}
|
||||
|
||||
for (ModelNode* node : this->nodes) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue