diff --git a/armoury/src/singlegearview.cpp b/armoury/src/singlegearview.cpp index 9c82168..140c11a 100644 --- a/armoury/src/singlegearview.cpp +++ b/armoury/src/singlegearview.cpp @@ -11,7 +11,7 @@ #include "filecache.h" #include "magic_enum.hpp" -#include "tiny_gltf.h" +#include "mdlimport.h" SingleGearView::SingleGearView(GameData *data, FileCache &cache, QWidget *parent) : QWidget(parent) @@ -315,69 +315,9 @@ QString SingleGearView::getLoadedGearPath() const void SingleGearView::importModel(const QString &filename) { - tinygltf::Model model; - - std::string error, warning; - - tinygltf::TinyGLTF loader; - if (!loader.LoadBinaryFromFile(&model, &error, &warning, filename.toStdString())) { - qInfo() << "Error when loading glTF model:" << error; - return; - } - - if (!warning.empty()) { - qInfo() << "Warnings when loading glTF model:" << warning; - } - auto &mdl = gearView->part().getModel(0); - for (const auto &node : model.nodes) { - // Detect if it's a mesh node - if (node.mesh >= 0) { - qInfo() << "Importing" << node.name; - - const QStringList parts = QString::fromStdString(node.name).split(QLatin1Char(' ')); - const QString &name = parts[0]; - const QStringList lodPartNumber = parts[2].split(QLatin1Char('.')); - - const int lodNumber = lodPartNumber[0].toInt(); - const int partNumber = lodPartNumber[1].toInt(); - - qInfo() << "- LOD:" << lodNumber; - qInfo() << "- Part:" << partNumber; - - auto &mesh = model.meshes[node.mesh]; - auto &primitive = mesh.primitives[0]; - - // All of the accessors are mapped to the same buffer vertex view - const auto &vertexAccessor = model.accessors[primitive.attributes["POSITION"]]; - const auto &vertexView = model.bufferViews[vertexAccessor.bufferView]; - const auto &vertexBuffer = model.buffers[vertexView.buffer]; - - const auto &indexAccessor = model.accessors[primitive.indices]; - const auto &indexView = model.bufferViews[indexAccessor.bufferView]; - const auto &indexBuffer = model.buffers[indexView.buffer]; - - qInfo() << "- Importing mesh of" << vertexAccessor.count << "vertices and" << indexAccessor.count << "indices."; - - auto vertexData = (glm::vec3 *)(&vertexBuffer.data.at(0) + vertexView.byteOffset); - - std::vector newVertices; - for (int i = 0; i < vertexAccessor.count; i++) { - // Replace position data - auto vertex = mdl.model.lods[lodNumber].parts[partNumber].vertices[i]; - vertex.position[0] = vertexData[i].x; - vertex.position[1] = vertexData[i].y; - vertex.position[2] = vertexData[i].z; - - newVertices.push_back(vertex); - } - - auto indexData = (const uint16_t *)(&indexBuffer.data.at(0) + indexView.byteOffset); - - physis_mdl_replace_vertices(&mdl.model, lodNumber, partNumber, vertexAccessor.count, newVertices.data(), indexAccessor.count, indexData); - } - } + ::importModel(mdl.model, filename); gearView->part().reloadModel(0); diff --git a/parts/mdl/CMakeLists.txt b/parts/mdl/CMakeLists.txt index c369209..27fe2af 100644 --- a/parts/mdl/CMakeLists.txt +++ b/parts/mdl/CMakeLists.txt @@ -3,6 +3,10 @@ add_library(mdlpart STATIC) target_sources(mdlpart PRIVATE + mdlexport.cpp + mdlexport.h + mdlimport.cpp + mdlimport.h mdlpart.cpp mdlpart.h vulkanwindow.cpp diff --git a/parts/mdl/mdlexport.cpp b/parts/mdl/mdlexport.cpp new file mode 100644 index 0000000..3fd4460 --- /dev/null +++ b/parts/mdl/mdlexport.cpp @@ -0,0 +1,237 @@ +// SPDX-FileCopyrightText: 2023 Joshua Goins +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "mdlexport.h" +#include + +#include "tiny_gltf.h" + +void exportModel(const QString &name, const physis_MDL &model, const physis_Skeleton &skeleton, const std::vector &boneData, const QString &fileName) +{ + const int selectedModel = 0; + const int selectedLod = 0; + + const physis_LOD &lod = model.lods[selectedLod]; + + tinygltf::Model gltfModel; + gltfModel.asset.generator = "Novus"; + + // TODO: just write the code better! dummy!! + gltfModel.nodes.reserve(1 + model.num_affected_bones + lod.num_parts); + + auto &gltfSkeletonNode = gltfModel.nodes.emplace_back(); + gltfSkeletonNode.name = skeleton.root_bone->name; + + for (int i = 0; i < model.num_affected_bones; i++) { + auto &node = gltfModel.nodes.emplace_back(); + node.name = model.affected_bone_names[i]; + + int real_bone_id = 0; + for (int k = 0; k < skeleton.num_bones; k++) { + if (strcmp(skeleton.bones[k].name, model.affected_bone_names[i]) == 0) { + real_bone_id = k; + } + } + + auto &real_bone = skeleton.bones[real_bone_id]; + node.translation = {real_bone.position[0], real_bone.position[1], real_bone.position[2]}; + node.rotation = {real_bone.rotation[0], real_bone.rotation[1], real_bone.rotation[2], real_bone.rotation[3]}; + node.scale = {real_bone.scale[0], real_bone.scale[1], real_bone.scale[2]}; + } + + // setup parenting + for (int i = 0; i < model.num_affected_bones; i++) { + int real_bone_id = 0; + for (int k = 0; k < skeleton.num_bones; k++) { + if (strcmp(skeleton.bones[k].name, model.affected_bone_names[i]) == 0) { + real_bone_id = k; + } + } + + auto &real_bone = skeleton.bones[real_bone_id]; + if (real_bone.parent_bone != nullptr) { + bool found = false; + for (int k = 0; k < model.num_affected_bones; k++) { + if (strcmp(model.affected_bone_names[k], real_bone.parent_bone->name) == 0) { + gltfModel.nodes[k + 1].children.push_back(i + 1); // +1 for the skeleton node taking up the first index + found = true; + } + } + + // Find the next closest bone that isn't a direct descendant + // of n_root, but won't have a parent anyway + if (!found) { + gltfSkeletonNode.children.push_back(i + 1); + } + } else { + gltfSkeletonNode.children.push_back(i + 1); + } + } + + auto &gltfSkin = gltfModel.skins.emplace_back(); + gltfSkin.name = gltfSkeletonNode.name; + gltfSkin.skeleton = 0; + for (int i = 1; i < gltfModel.nodes.size(); i++) { + gltfSkin.joints.push_back(i); + } + + // Inverse bind matrices + { + gltfSkin.inverseBindMatrices = gltfModel.accessors.size(); + + auto &inverseAccessor = gltfModel.accessors.emplace_back(); + inverseAccessor.bufferView = gltfModel.bufferViews.size(); + inverseAccessor.componentType = TINYGLTF_COMPONENT_TYPE_FLOAT; + inverseAccessor.count = model.num_affected_bones; + inverseAccessor.type = TINYGLTF_TYPE_MAT4; + + auto &inverseBufferView = gltfModel.bufferViews.emplace_back(); + inverseBufferView.buffer = gltfModel.buffers.size(); + + auto &inverseBuffer = gltfModel.buffers.emplace_back(); + for (int i = 0; i < model.num_affected_bones; i++) { + int real_bone_id = 0; + for (int k = 0; k < skeleton.num_bones; k++) { + if (strcmp(skeleton.bones[k].name, model.affected_bone_names[i]) == 0) { + real_bone_id = k; + } + } + + auto &real_bone = skeleton.bones[real_bone_id]; + auto inverseMatrix = boneData[real_bone.index].inversePose; + auto inverseMatrixCPtr = reinterpret_cast(glm::value_ptr(inverseMatrix)); + + inverseBuffer.data.insert(inverseBuffer.data.end(), inverseMatrixCPtr, inverseMatrixCPtr + sizeof(float) * 16); + } + + inverseBufferView.byteLength = inverseBuffer.data.size(); + } + + for (int i = 0; i < lod.num_parts; i++) { + gltfSkeletonNode.children.push_back(gltfModel.nodes.size()); + + auto &gltfNode = gltfModel.nodes.emplace_back(); + + gltfNode.name = name.toStdString() + " Part " + std::to_string(i) + ".0"; + gltfNode.skin = 0; + + gltfNode.mesh = gltfModel.meshes.size(); + auto &gltfMesh = gltfModel.meshes.emplace_back(); + + gltfMesh.name = gltfNode.name + " Mesh Attribute"; + + auto &gltfPrimitive = gltfMesh.primitives.emplace_back(); + gltfPrimitive.attributes["POSITION"] = gltfModel.accessors.size(); + gltfPrimitive.attributes["TEXCOORD_0"] = gltfModel.accessors.size() + 1; + gltfPrimitive.attributes["TEXCOORD_1"] = gltfModel.accessors.size() + 2; + gltfPrimitive.attributes["NORMAL"] = gltfModel.accessors.size() + 3; + gltfPrimitive.attributes["COLOR_0"] = gltfModel.accessors.size() + 6; + gltfPrimitive.attributes["WEIGHTS_0"] = gltfModel.accessors.size() + 7; + gltfPrimitive.attributes["JOINTS_0"] = gltfModel.accessors.size() + 8; + gltfPrimitive.mode = TINYGLTF_MODE_TRIANGLES; + + // Vertices + { + auto &positionAccessor = gltfModel.accessors.emplace_back(); + positionAccessor.bufferView = gltfModel.bufferViews.size(); + positionAccessor.componentType = TINYGLTF_COMPONENT_TYPE_FLOAT; + positionAccessor.count = lod.parts[i].num_vertices; + positionAccessor.type = TINYGLTF_TYPE_VEC3; + + auto &uv0Accessor = gltfModel.accessors.emplace_back(); + uv0Accessor.bufferView = gltfModel.bufferViews.size(); + uv0Accessor.componentType = TINYGLTF_COMPONENT_TYPE_FLOAT; + uv0Accessor.count = lod.parts[i].num_vertices; + uv0Accessor.type = TINYGLTF_TYPE_VEC2; + uv0Accessor.byteOffset = offsetof(Vertex, uv0); + + auto &uv1Accessor = gltfModel.accessors.emplace_back(); + uv1Accessor.bufferView = gltfModel.bufferViews.size(); + uv1Accessor.componentType = TINYGLTF_COMPONENT_TYPE_FLOAT; + uv1Accessor.count = lod.parts[i].num_vertices; + uv1Accessor.type = TINYGLTF_TYPE_VEC2; + uv1Accessor.byteOffset = offsetof(Vertex, uv1); + + auto &normalAccessor = gltfModel.accessors.emplace_back(); + normalAccessor.bufferView = gltfModel.bufferViews.size(); + normalAccessor.componentType = TINYGLTF_COMPONENT_TYPE_FLOAT; + normalAccessor.count = lod.parts[i].num_vertices; + normalAccessor.type = TINYGLTF_TYPE_VEC3; + normalAccessor.byteOffset = offsetof(Vertex, normal); + + auto &tangent1Accessor = gltfModel.accessors.emplace_back(); + tangent1Accessor.bufferView = gltfModel.bufferViews.size(); + tangent1Accessor.componentType = TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE; + tangent1Accessor.count = lod.parts[i].num_vertices; + tangent1Accessor.type = TINYGLTF_TYPE_VEC4; + tangent1Accessor.byteOffset = offsetof(Vertex, tangent1); + + auto &tangent2Accessor = gltfModel.accessors.emplace_back(); + tangent2Accessor.bufferView = gltfModel.bufferViews.size(); + tangent2Accessor.componentType = TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE; + tangent2Accessor.count = lod.parts[i].num_vertices; + tangent2Accessor.type = TINYGLTF_TYPE_VEC4; + tangent2Accessor.byteOffset = offsetof(Vertex, tangent2); + + auto &colorAccessor = gltfModel.accessors.emplace_back(); + colorAccessor.bufferView = gltfModel.bufferViews.size(); + colorAccessor.componentType = TINYGLTF_COMPONENT_TYPE_FLOAT; + colorAccessor.count = lod.parts[i].num_vertices; + colorAccessor.type = TINYGLTF_TYPE_VEC4; + colorAccessor.byteOffset = offsetof(Vertex, color); + + auto &boneWeightAccessor = gltfModel.accessors.emplace_back(); + boneWeightAccessor.bufferView = gltfModel.bufferViews.size(); + boneWeightAccessor.componentType = TINYGLTF_COMPONENT_TYPE_FLOAT; + boneWeightAccessor.count = lod.parts[i].num_vertices; + boneWeightAccessor.type = TINYGLTF_TYPE_VEC4; + boneWeightAccessor.byteOffset = offsetof(Vertex, bone_weight); + + auto &boneIdAccessor = gltfModel.accessors.emplace_back(); + boneIdAccessor.bufferView = gltfModel.bufferViews.size(); + boneIdAccessor.componentType = TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE; + boneIdAccessor.count = lod.parts[i].num_vertices; + boneIdAccessor.type = TINYGLTF_TYPE_VEC4; + boneIdAccessor.byteOffset = offsetof(Vertex, bone_id); + + auto &vertexBufferView = gltfModel.bufferViews.emplace_back(); + vertexBufferView.buffer = gltfModel.buffers.size(); + vertexBufferView.target = TINYGLTF_TARGET_ARRAY_BUFFER; + + auto &vertexBuffer = gltfModel.buffers.emplace_back(); + vertexBuffer.data.resize(lod.parts[i].num_vertices * sizeof(Vertex)); + memcpy(vertexBuffer.data.data(), lod.parts[i].vertices, vertexBuffer.data.size()); + + vertexBufferView.byteLength = vertexBuffer.data.size(); + vertexBufferView.byteStride = sizeof(Vertex); + } + + // Indices + { + gltfPrimitive.indices = gltfModel.accessors.size(); + auto &indexAccessor = gltfModel.accessors.emplace_back(); + indexAccessor.bufferView = gltfModel.bufferViews.size(); + indexAccessor.componentType = TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT; + indexAccessor.count = lod.parts[i].num_indices; + indexAccessor.type = TINYGLTF_TYPE_SCALAR; + + auto &indexBufferView = gltfModel.bufferViews.emplace_back(); + indexBufferView.buffer = gltfModel.buffers.size(); + indexBufferView.target = TINYGLTF_TARGET_ELEMENT_ARRAY_BUFFER; + + auto &indexBuffer = gltfModel.buffers.emplace_back(); + indexBuffer.data.resize(lod.parts[i].num_indices * sizeof(uint16_t)); + memcpy(indexBuffer.data.data(), lod.parts[i].indices, indexBuffer.data.size()); + + indexBufferView.byteLength = indexBuffer.data.size(); + indexBufferView.byteStride = sizeof(uint16_t); + } + } + + auto &scene = gltfModel.scenes.emplace_back(); + scene.name = name.toStdString(); + scene.nodes = {0}; + + tinygltf::TinyGLTF loader; + loader.WriteGltfSceneToFile(&gltfModel, fileName.toStdString(), true, true, false, true); +} \ No newline at end of file diff --git a/parts/mdl/mdlexport.h b/parts/mdl/mdlexport.h new file mode 100644 index 0000000..917d17d --- /dev/null +++ b/parts/mdl/mdlexport.h @@ -0,0 +1,16 @@ +// SPDX-FileCopyrightText: 2023 Joshua Goins +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include + +#include +#include + +// TODO: lol got rid of this +struct BoneData { + glm::mat4 localTransform, finalTransform, inversePose; +}; + +void exportModel(const QString &name, const physis_MDL &model, const physis_Skeleton &skeleton, const std::vector &boneData, const QString &fileName); \ No newline at end of file diff --git a/parts/mdl/mdlimport.cpp b/parts/mdl/mdlimport.cpp new file mode 100644 index 0000000..bdc2c87 --- /dev/null +++ b/parts/mdl/mdlimport.cpp @@ -0,0 +1,76 @@ +// SPDX-FileCopyrightText: 2023 Joshua Goins +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "mdlimport.h" + +#include +#include + +#include "tiny_gltf.h" + +void importModel(physis_MDL &existingModel, const QString &filename) +{ + tinygltf::Model model; + + std::string error, warning; + + tinygltf::TinyGLTF loader; + if (!loader.LoadBinaryFromFile(&model, &error, &warning, filename.toStdString())) { + qInfo() << "Error when loading glTF model:" << error; + return; + } + + if (!warning.empty()) { + qInfo() << "Warnings when loading glTF model:" << warning; + } + + for (const auto &node : model.nodes) { + // Detect if it's a mesh node + if (node.mesh >= 0) { + qInfo() << "Importing" << node.name; + + const QStringList parts = QString::fromStdString(node.name).split(QLatin1Char(' ')); + const QString &name = parts[0]; + const QStringList lodPartNumber = parts[2].split(QLatin1Char('.')); + + const int lodNumber = lodPartNumber[0].toInt(); + const int partNumber = lodPartNumber[1].toInt(); + + qInfo() << "- LOD:" << lodNumber; + qInfo() << "- Part:" << partNumber; + + auto &mesh = model.meshes[node.mesh]; + auto &primitive = mesh.primitives[0]; + + // All of the accessors are mapped to the same buffer vertex view + const auto &vertexAccessor = model.accessors[primitive.attributes["POSITION"]]; + const auto &vertexView = model.bufferViews[vertexAccessor.bufferView]; + const auto &vertexBuffer = model.buffers[vertexView.buffer]; + + const auto &indexAccessor = model.accessors[primitive.indices]; + const auto &indexView = model.bufferViews[indexAccessor.bufferView]; + const auto &indexBuffer = model.buffers[indexView.buffer]; + + qInfo() << "- Importing mesh of" << vertexAccessor.count << "vertices and" << indexAccessor.count << "indices."; + + auto vertexData = (glm::vec3 *)(&vertexBuffer.data.at(0) + vertexView.byteOffset); + + std::vector newVertices; + for (int i = 0; i < vertexAccessor.count; i++) { + // Replace position data + auto vertex = existingModel.lods[lodNumber].parts[partNumber].vertices[i]; + vertex.position[0] = vertexData[i].x; + vertex.position[1] = vertexData[i].y; + vertex.position[2] = vertexData[i].z; + + newVertices.push_back(vertex); + } + + auto indexData = (const uint16_t *)(&indexBuffer.data.at(0) + indexView.byteOffset); + + physis_mdl_replace_vertices(&existingModel, lodNumber, partNumber, vertexAccessor.count, newVertices.data(), indexAccessor.count, indexData); + } + } + + qInfo() << "Successfully imported model!"; +} \ No newline at end of file diff --git a/parts/mdl/mdlimport.h b/parts/mdl/mdlimport.h new file mode 100644 index 0000000..e24972a --- /dev/null +++ b/parts/mdl/mdlimport.h @@ -0,0 +1,10 @@ +// SPDX-FileCopyrightText: 2023 Joshua Goins +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include + +#include + +void importModel(physis_MDL &existingModel, const QString &filename); \ No newline at end of file diff --git a/parts/mdl/mdlpart.cpp b/parts/mdl/mdlpart.cpp index 27e6227..04c0620 100644 --- a/parts/mdl/mdlpart.cpp +++ b/parts/mdl/mdlpart.cpp @@ -13,10 +13,8 @@ #include #include #include -#include #include "filecache.h" -#include "tiny_gltf.h" #include "vulkanwindow.h" MDLPart::MDLPart(GameData *data, FileCache &cache) @@ -49,233 +47,8 @@ MDLPart::MDLPart(GameData *data, FileCache &cache) void MDLPart::exportModel(const QString &fileName) { - const int selectedModel = 0; - const int selectedLod = 0; - - const physis_MDL &model = models[selectedModel].model; - const physis_LOD &lod = model.lods[selectedLod]; - - tinygltf::Model gltfModel; - gltfModel.asset.generator = "Novus"; - - // TODO: just write the code better! dummy!! - gltfModel.nodes.reserve(1 + model.num_affected_bones + lod.num_parts); - - auto &gltfSkeletonNode = gltfModel.nodes.emplace_back(); - gltfSkeletonNode.name = skeleton->root_bone->name; - - for (int i = 0; i < model.num_affected_bones; i++) { - auto &node = gltfModel.nodes.emplace_back(); - node.name = model.affected_bone_names[i]; - - int real_bone_id = 0; - for (int k = 0; k < skeleton->num_bones; k++) { - if (strcmp(skeleton->bones[k].name, model.affected_bone_names[i]) == 0) { - real_bone_id = k; - } - } - - auto &real_bone = skeleton->bones[real_bone_id]; - node.translation = {real_bone.position[0], real_bone.position[1], real_bone.position[2]}; - node.rotation = {real_bone.rotation[0], real_bone.rotation[1], real_bone.rotation[2], real_bone.rotation[3]}; - node.scale = {real_bone.scale[0], real_bone.scale[1], real_bone.scale[2]}; - } - - // setup parenting - for (int i = 0; i < model.num_affected_bones; i++) { - int real_bone_id = 0; - for (int k = 0; k < skeleton->num_bones; k++) { - if (strcmp(skeleton->bones[k].name, model.affected_bone_names[i]) == 0) { - real_bone_id = k; - } - } - - auto &real_bone = skeleton->bones[real_bone_id]; - if (real_bone.parent_bone != nullptr) { - bool found = false; - for (int k = 0; k < model.num_affected_bones; k++) { - if (strcmp(model.affected_bone_names[k], real_bone.parent_bone->name) == 0) { - gltfModel.nodes[k + 1].children.push_back(i + 1); // +1 for the skeleton node taking up the first index - found = true; - } - } - - // Find the next closest bone that isn't a direct descendant - // of n_root, but won't have a parent anyway - if (!found) { - gltfSkeletonNode.children.push_back(i + 1); - } - } else { - gltfSkeletonNode.children.push_back(i + 1); - } - } - - auto &gltfSkin = gltfModel.skins.emplace_back(); - gltfSkin.name = gltfSkeletonNode.name; - gltfSkin.skeleton = 0; - for (int i = 1; i < gltfModel.nodes.size(); i++) { - gltfSkin.joints.push_back(i); - } - - // Inverse bind matrices - { - gltfSkin.inverseBindMatrices = gltfModel.accessors.size(); - - auto &inverseAccessor = gltfModel.accessors.emplace_back(); - inverseAccessor.bufferView = gltfModel.bufferViews.size(); - inverseAccessor.componentType = TINYGLTF_COMPONENT_TYPE_FLOAT; - inverseAccessor.count = model.num_affected_bones; - inverseAccessor.type = TINYGLTF_TYPE_MAT4; - - auto &inverseBufferView = gltfModel.bufferViews.emplace_back(); - inverseBufferView.buffer = gltfModel.buffers.size(); - - auto &inverseBuffer = gltfModel.buffers.emplace_back(); - for (int i = 0; i < model.num_affected_bones; i++) { - int real_bone_id = 0; - for (int k = 0; k < skeleton->num_bones; k++) { - if (strcmp(skeleton->bones[k].name, model.affected_bone_names[i]) == 0) { - real_bone_id = k; - } - } - - auto &real_bone = skeleton->bones[real_bone_id]; - auto inverseMatrix = boneData[real_bone.index].inversePose; - auto inverseMatrixCPtr = reinterpret_cast(glm::value_ptr(inverseMatrix)); - - inverseBuffer.data.insert(inverseBuffer.data.end(), inverseMatrixCPtr, inverseMatrixCPtr + sizeof(float) * 16); - } - - inverseBufferView.byteLength = inverseBuffer.data.size(); - } - - for (int i = 0; i < lod.num_parts; i++) { - gltfSkeletonNode.children.push_back(gltfModel.nodes.size()); - - auto &gltfNode = gltfModel.nodes.emplace_back(); - - gltfNode.name = models[0].name.toStdString() + " Part " + std::to_string(i) + ".0"; - gltfNode.skin = 0; - - gltfNode.mesh = gltfModel.meshes.size(); - auto &gltfMesh = gltfModel.meshes.emplace_back(); - - gltfMesh.name = gltfNode.name + " Mesh Attribute"; - - auto &gltfPrimitive = gltfMesh.primitives.emplace_back(); - gltfPrimitive.attributes["POSITION"] = gltfModel.accessors.size(); - gltfPrimitive.attributes["TEXCOORD_0"] = gltfModel.accessors.size() + 1; - gltfPrimitive.attributes["TEXCOORD_1"] = gltfModel.accessors.size() + 2; - gltfPrimitive.attributes["NORMAL"] = gltfModel.accessors.size() + 3; - gltfPrimitive.attributes["COLOR_0"] = gltfModel.accessors.size() + 6; - gltfPrimitive.attributes["WEIGHTS_0"] = gltfModel.accessors.size() + 7; - gltfPrimitive.attributes["JOINTS_0"] = gltfModel.accessors.size() + 8; - gltfPrimitive.mode = TINYGLTF_MODE_TRIANGLES; - - // Vertices - { - auto &positionAccessor = gltfModel.accessors.emplace_back(); - positionAccessor.bufferView = gltfModel.bufferViews.size(); - positionAccessor.componentType = TINYGLTF_COMPONENT_TYPE_FLOAT; - positionAccessor.count = lod.parts[i].num_vertices; - positionAccessor.type = TINYGLTF_TYPE_VEC3; - - auto &uv0Accessor = gltfModel.accessors.emplace_back(); - uv0Accessor.bufferView = gltfModel.bufferViews.size(); - uv0Accessor.componentType = TINYGLTF_COMPONENT_TYPE_FLOAT; - uv0Accessor.count = lod.parts[i].num_vertices; - uv0Accessor.type = TINYGLTF_TYPE_VEC2; - uv0Accessor.byteOffset = offsetof(Vertex, uv0); - - auto &uv1Accessor = gltfModel.accessors.emplace_back(); - uv1Accessor.bufferView = gltfModel.bufferViews.size(); - uv1Accessor.componentType = TINYGLTF_COMPONENT_TYPE_FLOAT; - uv1Accessor.count = lod.parts[i].num_vertices; - uv1Accessor.type = TINYGLTF_TYPE_VEC2; - uv1Accessor.byteOffset = offsetof(Vertex, uv1); - - auto &normalAccessor = gltfModel.accessors.emplace_back(); - normalAccessor.bufferView = gltfModel.bufferViews.size(); - normalAccessor.componentType = TINYGLTF_COMPONENT_TYPE_FLOAT; - normalAccessor.count = lod.parts[i].num_vertices; - normalAccessor.type = TINYGLTF_TYPE_VEC3; - normalAccessor.byteOffset = offsetof(Vertex, normal); - - auto &tangent1Accessor = gltfModel.accessors.emplace_back(); - tangent1Accessor.bufferView = gltfModel.bufferViews.size(); - tangent1Accessor.componentType = TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE; - tangent1Accessor.count = lod.parts[i].num_vertices; - tangent1Accessor.type = TINYGLTF_TYPE_VEC4; - tangent1Accessor.byteOffset = offsetof(Vertex, tangent1); - - auto &tangent2Accessor = gltfModel.accessors.emplace_back(); - tangent2Accessor.bufferView = gltfModel.bufferViews.size(); - tangent2Accessor.componentType = TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE; - tangent2Accessor.count = lod.parts[i].num_vertices; - tangent2Accessor.type = TINYGLTF_TYPE_VEC4; - tangent2Accessor.byteOffset = offsetof(Vertex, tangent2); - - auto &colorAccessor = gltfModel.accessors.emplace_back(); - colorAccessor.bufferView = gltfModel.bufferViews.size(); - colorAccessor.componentType = TINYGLTF_COMPONENT_TYPE_FLOAT; - colorAccessor.count = lod.parts[i].num_vertices; - colorAccessor.type = TINYGLTF_TYPE_VEC4; - colorAccessor.byteOffset = offsetof(Vertex, color); - - auto &boneWeightAccessor = gltfModel.accessors.emplace_back(); - boneWeightAccessor.bufferView = gltfModel.bufferViews.size(); - boneWeightAccessor.componentType = TINYGLTF_COMPONENT_TYPE_FLOAT; - boneWeightAccessor.count = lod.parts[i].num_vertices; - boneWeightAccessor.type = TINYGLTF_TYPE_VEC4; - boneWeightAccessor.byteOffset = offsetof(Vertex, bone_weight); - - auto &boneIdAccessor = gltfModel.accessors.emplace_back(); - boneIdAccessor.bufferView = gltfModel.bufferViews.size(); - boneIdAccessor.componentType = TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE; - boneIdAccessor.count = lod.parts[i].num_vertices; - boneIdAccessor.type = TINYGLTF_TYPE_VEC4; - boneIdAccessor.byteOffset = offsetof(Vertex, bone_id); - - auto &vertexBufferView = gltfModel.bufferViews.emplace_back(); - vertexBufferView.buffer = gltfModel.buffers.size(); - vertexBufferView.target = TINYGLTF_TARGET_ARRAY_BUFFER; - - auto &vertexBuffer = gltfModel.buffers.emplace_back(); - vertexBuffer.data.resize(lod.parts[i].num_vertices * sizeof(Vertex)); - memcpy(vertexBuffer.data.data(), lod.parts[i].vertices, vertexBuffer.data.size()); - - vertexBufferView.byteLength = vertexBuffer.data.size(); - vertexBufferView.byteStride = sizeof(Vertex); - } - - // Indices - { - gltfPrimitive.indices = gltfModel.accessors.size(); - auto &indexAccessor = gltfModel.accessors.emplace_back(); - indexAccessor.bufferView = gltfModel.bufferViews.size(); - indexAccessor.componentType = TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT; - indexAccessor.count = lod.parts[i].num_indices; - indexAccessor.type = TINYGLTF_TYPE_SCALAR; - - auto &indexBufferView = gltfModel.bufferViews.emplace_back(); - indexBufferView.buffer = gltfModel.buffers.size(); - indexBufferView.target = TINYGLTF_TARGET_ELEMENT_ARRAY_BUFFER; - - auto &indexBuffer = gltfModel.buffers.emplace_back(); - indexBuffer.data.resize(lod.parts[i].num_indices * sizeof(uint16_t)); - memcpy(indexBuffer.data.data(), lod.parts[i].indices, indexBuffer.data.size()); - - indexBufferView.byteLength = indexBuffer.data.size(); - indexBufferView.byteStride = sizeof(uint16_t); - } - } - - auto &scene = gltfModel.scenes.emplace_back(); - scene.name = models[0].name.toStdString(); - scene.nodes = {0}; - - tinygltf::TinyGLTF loader; - loader.WriteGltfSceneToFile(&gltfModel, fileName.toStdString(), true, true, false, true); + auto &model = models[0]; + ::exportModel(model.name, model.model, *skeleton, boneData, fileName); } RenderModel &MDLPart::getModel(const int index) diff --git a/parts/mdl/mdlpart.h b/parts/mdl/mdlpart.h index 326fc35..b03301e 100644 --- a/parts/mdl/mdlpart.h +++ b/parts/mdl/mdlpart.h @@ -7,6 +7,7 @@ #include #include +#include "mdlexport.h" #include "renderer.hpp" struct GameData; @@ -38,10 +39,6 @@ public: std::unique_ptr skeleton; - struct BoneData { - glm::mat4 localTransform, finalTransform, inversePose; - }; - std::vector boneData; std::function requestUpdate;