2#include "../../MoreString.h"
3#include "DAEUtil/DAEConvertSGameObject.h"
4#include "../../../Object/SGameObjectFromSPrefab.h"
6#include "../../../Component/DrawableSkinnedMeshComponent.h"
7#include "../../../Component/RenderComponent.h"
8#include "../../Render/STexture.h"
9#include "../../Render/SMaterial.h"
10#include "../../../Manager/EngineCore.h"
14const mat4 CORRECTION = mat4::Identity();
16DAELoader::DAELoader(
const char* path, LOAD_TYPE type,
bool isLoad) {
17 if (type == NOTHING)
return;
19 if (isLoad) Load(path, type);
22DAELoader::~DAELoader() {
26void DAELoader::Load(
const char* path, LOAD_TYPE type) {
28 std::string path_str = path;
29 std::size_t index = path_str.rfind(
'/');
30 if (index == std::string::npos) {
31 index = path_str.rfind(
'\\');
33 std::size_t name_index = path_str.rfind(
'.');
35 m_name = path_str.substr(index + 1, name_index - index - 1);
38 m_root =
XFILE(path).getRoot();
39 XNode collada = m_root->getChild(
"COLLADA");
41 if (type == LOAD_TYPE::MESH || type == LOAD_TYPE::ALL || type == LOAD_TYPE::AUTO) {
44 if(collada.hasChild(
"library_controllers") && collada.hasChild(
"library_visual_scenes")) {
45 safe_result = LoadSkin(collada.getChild(
"library_controllers"));
46 safe_result &= LoadSkeleton(collada.getChild(
"library_visual_scenes"));
50 m_isSkinning = safe_result;
52 std::cout <<
"passing skinning...\n";
57 if(collada.hasChild(
"library_images"))
58 LoadTexturePath(collada.getChild(
"library_images"));
60 std::cout <<
"passing texture...\n";
62 std::cout <<
"passing texture...\n";
66 const auto& geometryData = collada.getChild(
"library_geometries").children;
67 m_meshList.reserve(geometryData.size());
69 for (
const auto& geometry : geometryData) {
70 auto meshData =
new DAEMeshData();
71 meshData->meshName = geometry.getAttribute(
"id").value;
72 LoadGeometry(geometry, meshData);
73 m_meshList.push_back(meshData);
76 std::cout <<
"passing geometry...\n";
79 if (type == ANIMATION || type == ALL || type == AUTO) {
83 safe_exception = m_animationLoader->Load(path, m_name);
86 SAFE_DELETE(m_animationLoader);
90 SAFE_DELETE(m_animationLoader);
91 std::cout <<
"passing Animation...\n";
99 if (asset ==
nullptr)
return;
101 auto* texture = SResource::Create<STexture>(asset);
102 m_texture_name = texture->GetName();
105void DAELoader::Exterminate() {
107 for (
auto mesh : m_meshList) {
112 SAFE_DELETE(m_skinningData);
113 SAFE_DELETE(m_animationLoader);
117bool DAELoader::LoadSkin(
const XNode& root_s) {
119 if(!root_s.hasChild(
"controller"))
return false;
121 XNode skinningData = root_s.getChild(
"controller").getChild(
"skin");
123 std::vector<std::string> jointsList = loadJointsList(skinningData);
124 std::vector<float> weights = loadWeights(skinningData);
125 const XNode& weightsDataNode = skinningData.getChild(
"vertex_weights");
126 std::vector<int> effectorJointCounts = getEffectiveJointsCounts(weightsDataNode);
127 std::vector<VertexSkinData*> vertexWeights = getSkinData(weightsDataNode, effectorJointCounts, weights);
129 SAFE_DELETE(m_skinningData);
131 m_skinningData->set_jointOrder(jointsList);
132 m_skinningData->set_verticesSkinData(vertexWeights);
136bool DAELoader::LoadSkeleton(
const XNode& root_s) {
138 if(!root_s.hasChild(
"visual_scene"))
return false;
139 if(!root_s.getChild(
"visual_scene").hasNodeByAttribute(
"node",
"id",
"Armature"))
return false;
141 XNode armatureData = root_s.getChild(
"visual_scene").getNodeByAttribute(
"node",
"id",
"Armature");
143 const XNode& headNode = armatureData.getChild(
"node");
144 Joint* headJoint = loadJointData(headNode,
true);
148 if (m_skeletonData ==
nullptr)
149 m_skeletonData =
new Skeleton(m_jointSize, headJoint);
151 m_skeletonData->SetJoint(m_jointSize, headJoint);
156bool DAELoader::LoadGeometry(
const XNode& root_g, DAEMeshData* meshData) {
158 if(!root_g.hasChild(
"mesh"))
return false;
160 const XNode& root_m = root_g.getChild(
"mesh");
161 std::vector<VertexSkinData*> vertexSkinData;
164 m_skinningData ==
nullptr ? std::vector<VertexSkinData*>() : m_skinningData->get_verticesSkinData();
168 ReadPositions(root_m, vertexSkinData, meshData);
171 std::string normalsId;
172 std::string texCoordsId;
176 if(!root_m.hasChild(
"polylist"))
return false;
178 const XNode& polylist = root_m.getChild(
"polylist");
180 normalsId = polylist.getNodeByAttribute(
"input",
"semantic",
"NORMAL")
181 .getAttribute(
"source").value.substr(1);
182 const XNode& childWithAttribute = polylist.getNodeByAttribute(
"input",
"semantic",
"TEXCOORD");
183 texCoordsId = childWithAttribute.getAttribute(
"source").value.substr(1);
184 m_polygonType = POLYGON_TYPE::POLYLIST;
188 const XNode& triangles = root_m.getChild(
"triangles");
190 const XNode& normals = triangles.getNodeByAttribute(
"input",
"semantic",
"NORMAL");
191 normalsId = normals.getAttribute(
"source").value.substr(1);
192 const XNode& childWithAttribute = triangles.getNodeByAttribute(
"input",
"semantic",
"TEXCOORD");
193 texCoordsId = childWithAttribute.getAttribute(
"source").value.substr(1);
194 m_polygonType = POLYGON_TYPE::TRIANGLES;
199 ReadNormals(root_m, normalsId, meshData);
200 ReadUVs(root_m, texCoordsId, meshData);
201 AssembleVertices(root_m, meshData);
202 removeUnusedVertices(meshData);
203 ConvertDataToVectors(meshData);
212void DAELoader::ReadPositions(
const XNode& data, std::vector<VertexSkinData*> vertexWeight, DAEMeshData* meshData)
const {
213 std::string positionID = data.getChild(
"vertices").getChild(
"input").getAttribute(
"source").value.substr(1);
214 XNode positionData = data.getNodeByAttribute(
"source",
"id", positionID.c_str()).getChild(
"float_array");
215 int vertsSize = std::stoi(positionData.getAttribute(
"count").value);
216 std::vector<float> vertices = positionData.value.toFloatVector();
218 for (
int i = 0; i < vertsSize / 3; ++i) {
219 float x = vertices[i * 3];
220 float y = vertices[i * 3 + 1];
221 float z = vertices[i * 3 + 2];
224 mat4 transform = mat4::Translate(x, y, z) * CORRECTION;
225 meshData->vertices.push_back(
226 new Vertex(meshData->vertices.size(),
vec3{ transform.w.x, transform.w.y, transform.w.z },
227 m_isSkinning ? vertexWeight.at(meshData->vertices.size()) : nullptr));
231void DAELoader::ReadNormals(
const XNode& data,
const std::string& normalsId, DAEMeshData* meshData) {
232 XNode normalsData = data.getNodeByAttribute(
"source",
"id", normalsId.c_str()).getChild(
"float_array");
233 int normalsSize = std::stoi(normalsData.getAttribute(
"count").value);
234 std::vector<float> normals = normalsData.value.toFloatVector();
236 for (
int i = 0; i < normalsSize / 3; i++) {
237 float x = normals[i * 3];
238 float y = normals[i * 3 + 1];
239 float z = normals[i * 3 + 2];
242 mat4 transform = mat4::Translate(x, y, z) * CORRECTION;
245 meshData->normals.emplace_back( transform.w.x, transform.w.y, transform.w.z );
250void DAELoader::ReadUVs(
const XNode& data,
const std::string& texCoordsId, DAEMeshData* meshData) {
251 XNode texData = data.getNodeByAttribute(
"source",
"id", texCoordsId.c_str()).getChild(
"float_array");
252 int uvSize = std::stoi(texData.getAttribute(
"count").value);
253 auto uvs = texData.value.toFloatVector();
255 for (
int i = 0; i < uvSize / 2; i++) {
256 float s = uvs[i * 2];
257 float t = uvs[i * 2 + 1];
259 meshData->texUVs.emplace_back( s, t );
264void DAELoader::AssembleVertices(
const XNode& data, DAEMeshData* meshData) {
265 XNode poly = data.getChild(m_polygonType == POLYLIST ?
"polylist" :
"triangles");
268 for (
const auto& child : poly.children) {
269 if (child.name ==
"input") {
270 int offset = std::stoi(child.getAttribute(
"offset").value) + 1;
271 if (offset > typeCount) {
277 std::vector<int> indexData = poly.getChild(
"p").value.toIntegerVector();
278 int texcoordOffset = -1;
280 const XNode& texSemantic = poly.getNodeByAttribute(
"input",
"semantic",
"TEXCOORD");
281 texcoordOffset = std::stoi(texSemantic.getAttribute(
"offset").value);
289 for (
int i = 0; i < indexData.size() / typeCount; i++) {
290 int positionIndex = indexData[i * typeCount];
291 int normalIndex = indexData[i * typeCount + 1];
292 int texCoordIndex = -1;
293 if (texcoordOffset != -1) {
294 texCoordIndex = indexData[i * typeCount + texcoordOffset];
296 processVertex(positionIndex, normalIndex, texCoordIndex, meshData);
300Vertex* DAELoader::processVertex(
int posIndex,
int normIndex,
int texIndex, DAEMeshData* meshData) {
301 Vertex* currentVertex = meshData->vertices.at(posIndex);
302 if (!currentVertex->isSet()) {
303 currentVertex->setTextureIndex(texIndex);
304 currentVertex->setNormalIndex(normIndex);
305 meshData->indices.push_back(posIndex);
307 return currentVertex;
309 return dealWithAlreadyProcessedVertex(currentVertex, texIndex, normIndex, meshData);
313Vertex* DAELoader::dealWithAlreadyProcessedVertex(
Vertex* previousVertex,
int newTextureIndex,
int newNormalIndex,
314 DAEMeshData* meshData) {
315 if (previousVertex->hasSameTextureAndNormal(newTextureIndex, newNormalIndex)) {
316 meshData->indices.push_back(previousVertex->getIndex());
318 return previousVertex;
320 Vertex* anotherVertex = previousVertex->getDuplicateVertex();
321 if (anotherVertex !=
nullptr) {
322 return dealWithAlreadyProcessedVertex(anotherVertex, newTextureIndex, newNormalIndex, meshData);
324 auto* duplicateVertex =
new Vertex(meshData->vertices.size(),
325 previousVertex->getPosition(), previousVertex->getWeightsData());
326 duplicateVertex->setTextureIndex(newTextureIndex);
327 duplicateVertex->setNormalIndex(newNormalIndex);
328 previousVertex->setDuplicateVertex(duplicateVertex);
329 meshData->vertices.push_back(duplicateVertex);
330 meshData->indices.push_back(duplicateVertex->getIndex());
332 return duplicateVertex;
337void DAELoader::removeUnusedVertices(DAEMeshData* meshData) {
338 for (
const auto& vertex : meshData->vertices) {
339 vertex->averageTangents();
340 if (!vertex->isSet()) {
341 vertex->setTextureIndex(0);
342 vertex->setNormalIndex(0);
351std::vector<std::string> DAELoader::loadJointsList(
const XNode& skinningData) {
352 const XNode& inputNode = skinningData.getChild(
"vertex_weights");
353 std::string jointDataId = inputNode.getNodeByAttribute(
"input",
"semantic",
"JOINT").getAttribute(
354 "source").value.substr(1);
355 XNode jointsNode = skinningData.getNodeByAttribute(
"source",
"id", jointDataId.c_str()).getChild(
"Name_array");
357 std::vector<std::string> jointsList = jointsNode.value.toStringVector();
362std::vector<float> DAELoader::loadWeights(
const XNode& skinningData) {
363 const XNode& inputNode = skinningData.getChild(
"vertex_weights");
364 std::string weightsDataId = inputNode.getNodeByAttribute(
"input",
"semantic",
"WEIGHT").getAttribute(
365 "source").value.substr(1);
366 XNode weightsNode = skinningData.getNodeByAttribute(
"source",
"id", weightsDataId.c_str()).getChild(
"float_array");
367 std::vector<float> weights = weightsNode.value.toFloatVector();
372std::vector<int> DAELoader::getEffectiveJointsCounts(
const XNode& node) {
373 if(m_polygonType == POLYLIST) {
374 return node.getChild(
"vcount").value.toIntegerVector();
381std::vector<VertexSkinData*>
382DAELoader::getSkinData(
const XNode& weightsDataNode,
const std::vector<int>& counts, std::vector<float> weights)
const {
383 auto rawData = weightsDataNode.getChild(
"v").value.toIntegerVector();
384 auto weightsCount = std::stoi(weightsDataNode.getAttribute(
"count").value);
385 std::vector<VertexSkinData*> skinningData;
387 for (
int index = 0; index < weightsCount; ++index) {
389 short count = (m_polygonType == POLYLIST) ? counts[index] : static_cast<short>(m_polygonType);
390 for (
short i = 0; i < count; ++i) {
391 int jointId = rawData[pointer++];
392 int weightId = rawData[pointer++];
393 skinData->addJointEffect(jointId, weights[weightId]);
395 skinData->limitJointNumber(m_maxWeight);
396 skinningData.push_back(skinData);
405Joint* DAELoader::extractMainJointData(
const XNode& jointNode,
bool isRoot) {
406 std::string nameId = jointNode.getAttribute(
"id").value;
408 auto jointOrders = m_skinningData->get_jointOrder();
409 for (
int i = 0; i < jointOrders.size(); ++i) {
410 if (trim(jointOrders[i]) == nameId) {
419 std::vector<float> matrixData = jointNode.getChild(
"matrix").value.toFloatVector();
421 matrix = matrix.Transposed();
424 matrix *= CORRECTION;
427 return new Joint(index, nameId, matrix);
430Joint* DAELoader::loadJointData(
const XNode& jointNode,
bool isRoot) {
431 Joint* joint = extractMainJointData(jointNode, isRoot);
434 for (
const XNode& childNode : jointNode.children) {
435 if (childNode.name ==
"node") {
436 joint->addChild(loadJointData(childNode,
false));
439 }
catch (
int error) {}
444void DAELoader::LoadTexturePath(
const XNode& imageNode) {
446 if(!imageNode.hasChild(
"image"))
return;
448 std::string path = imageNode.getChild(
"image").getChild(
"init_from").value;
450 auto asset = CORE->GetCore(
ResMgr)->GetAssetReference(path);
451 if (asset ==
nullptr)
return;
456void DAELoader::ConvertDataToVectors(DAEMeshData* meshData)
const {
457 std::vector<float> vertices;
458 std::vector<float> normals;
459 std::vector<float> texUVs;
460 std::vector<short> jointIDs;
461 std::vector<float> weights;
464 int size = meshData->vertices.size();
465 vertices.resize(size * 3);
466 normals.resize(size * 3);
467 texUVs.resize(size * 2);
469 jointIDs.resize(size * 3);
470 weights.resize(size * 3);
474 float furthestPoint = 0;
475 int vertices_size = meshData->vertices.size();
476 for (
int i = 0; i < vertices_size; ++i) {
477 Vertex& currentVertex = *meshData->vertices[i];
478 if (currentVertex.getLength() > furthestPoint) {
479 furthestPoint = currentVertex.getLength();
481 vec3 position = currentVertex.getPosition();
483 vec2 textureCoord = meshData->texUVs.at(currentVertex.getTextureIndex());
484 vec3 normalVector = meshData->normals.at(currentVertex.getNormalIndex());
485 vertices[i * 3] = position.x;
486 vertices[i * 3 + 1] = position.y;
487 vertices[i * 3 + 2] = position.z;
488 texUVs[i * 2] = textureCoord.x;
489 texUVs[i * 2 + 1] = 1 - textureCoord.y;
490 normals[i * 3] = normalVector.x;
491 normals[i * 3 + 1] = normalVector.y;
492 normals[i * 3 + 2] = normalVector.z;
494 if (!m_isSkinning)
continue;
497 jointIDs[i * 3] = weightsData->getJointIDs()[0];
498 jointIDs[i * 3 + 1] = weightsData->getJointIDs()[1];
499 jointIDs[i * 3 + 2] = weightsData->getJointIDs()[2];
500 weights[i * 3] = weightsData->getWeights()[0];
501 weights[i * 3 + 1] = weightsData->getWeights()[1];
502 weights[i * 3 + 2] = weightsData->getWeights()[2];
504 AttachDataToObjSurface(meshData->vertices.size(), vertices, normals, texUVs, meshData->indices, jointIDs, weights,
509DAELoader::AttachDataToObjSurface(
int vertices_size, std::vector<float> vertices, std::vector<float> normals,
510 std::vector<float> texUVs, std::vector<int> indices, std::vector<short> jointIDs,
511 std::vector<float> weights, DAEMeshData* meshData) {
512 int sizeIndices = indices.size() / 3;
513 const auto meshSurface = meshData->meshSurface;
514 meshSurface->MakeVertices(vertices_size, &vertices[0], &normals[0], (texUVs.empty() ?
nullptr : &texUVs[0]),
515 (weights.empty() ? nullptr : &weights[0]), (jointIDs.empty() ? nullptr : &jointIDs[0]));
516 meshSurface->MakeIndices(sizeIndices, &indices[0]);
520 if (prefab ==
nullptr)
523 prefab->SetGameObject(root);
529 root->AddChild(joint_root);
530 DAEConvertSGameObject::CreateJoints(joint_root, m_skeletonData->getHeadJoint());
534 for (
const auto& mesh : m_meshList) {
536 root->AddChild(mesh_root);
545 mesh_component->SetMesh(*mesh->meshSurface);
549 joint_root_component->GetGameObject(),
550 m_skeletonData->getJointCount());
557 SGameObject* animationObj = DAEConvertSGameObject::CreateAnimation(root, joint_root_component,
558 m_animationLoader->GetAnimation(),
567 auto* loader =
new DAELoader(path, AUTO,
false);
568 auto asset = CORE->GetCore(
ResMgr)->GetAssetReference(path);
569 if (asset ==
nullptr) {
573 std::string prefab_id = asset->id;
575 loader->m_resource_id = asset->id;
576 loader->m_skeletonData = skeleton;
578 if (loader->m_skeletonData ==
nullptr) {
579 loader->m_skeletonData =
new Skeleton();
582 const auto& meshData = loader->m_meshList;
583 for (
const auto& mesh : meshData) {
584 mesh->meshSurface->LinkResource(prefab_id +
"." + mesh->meshName +
"?mesh");
586 loader->m_skeletonData->LinkResource(prefab_id +
"?skeleton");
588 loader->Load(path, AUTO);
589 prefab = loader->GeneratePrefab(animation, prefab);