422 LoadedMeshes.clear();
431 bool LoadFile(std::string Path)
434 if (Path.substr(Path.size() - 4, 4) !=
".obj")
438 std::ifstream file(Path);
443 LoadedMeshes.clear();
444 LoadedVertices.clear();
445 LoadedIndices.clear();
447 std::vector<Vector3> Positions;
448 std::vector<Vector2> TCoords;
449 std::vector<Vector3> Normals;
451 std::vector<Vertex> Vertices;
452 std::vector<unsigned int> Indices;
454 std::vector<std::string> MeshMatNames;
456 bool listening =
false;
457 std::string meshname;
461 #ifdef OBJL_CONSOLE_OUTPUT
462 const unsigned int outputEveryNth = 1000;
463 unsigned int outputIndicator = outputEveryNth;
467 while (std::getline(file, curline))
469 #ifdef OBJL_CONSOLE_OUTPUT
470 if ((outputIndicator = ((outputIndicator + 1) % outputEveryNth)) == 1)
472 if (!meshname.empty())
475 <<
"\r- " << meshname
476 <<
"\t| vertices > " << Positions.size()
477 <<
"\t| texcoords > " << TCoords.size()
478 <<
"\t| normals > " << Normals.size()
479 <<
"\t| triangles > " << (Vertices.size() / 3)
480 << (!MeshMatNames.empty() ?
"\t| material: " + MeshMatNames.back() :
"");
486 if (algorithm::firstToken(curline) ==
"o" || algorithm::firstToken(curline) ==
"g" || curline[0] ==
'g')
492 if (algorithm::firstToken(curline) ==
"o" || algorithm::firstToken(curline) ==
"g")
494 meshname = algorithm::tail(curline);
498 meshname =
"unnamed";
505 if (!Indices.empty() && !Vertices.empty())
508 tempMesh =
Mesh(Vertices, Indices);
509 tempMesh.MeshName = meshname;
512 LoadedMeshes.push_back(tempMesh);
519 meshname = algorithm::tail(curline);
523 if (algorithm::firstToken(curline) ==
"o" || algorithm::firstToken(curline) ==
"g")
525 meshname = algorithm::tail(curline);
529 meshname =
"unnamed";
533 #ifdef OBJL_CONSOLE_OUTPUT
534 std::cout << std::endl;
539 if (algorithm::firstToken(curline) ==
"v")
541 std::vector<std::string> spos;
543 algorithm::split(algorithm::tail(curline), spos,
" ");
545 vpos.X = std::stof(spos[0]);
546 vpos.Y = std::stof(spos[1]);
547 vpos.Z = std::stof(spos[2]);
549 Positions.push_back(vpos);
552 if (algorithm::firstToken(curline) ==
"vt")
554 std::vector<std::string> stex;
556 algorithm::split(algorithm::tail(curline), stex,
" ");
558 vtex.X = std::stof(stex[0]);
559 vtex.Y = std::stof(stex[1]);
561 TCoords.push_back(vtex);
564 if (algorithm::firstToken(curline) ==
"vn")
566 std::vector<std::string> snor;
568 algorithm::split(algorithm::tail(curline), snor,
" ");
570 vnor.X = std::stof(snor[0]);
571 vnor.Y = std::stof(snor[1]);
572 vnor.Z = std::stof(snor[2]);
574 Normals.push_back(vnor);
577 if (algorithm::firstToken(curline) ==
"f")
580 std::vector<Vertex> vVerts;
581 GenVerticesFromRawOBJ(vVerts, Positions, TCoords, Normals, curline);
584 for (
int i = 0; i < int(vVerts.size()); i++)
586 Vertices.push_back(vVerts[i]);
588 LoadedVertices.push_back(vVerts[i]);
591 std::vector<unsigned int> iIndices;
593 VertexTriangluation(iIndices, vVerts);
596 for (
int i = 0; i < int(iIndices.size()); i++)
598 unsigned int indnum = (
unsigned int)((Vertices.size()) - vVerts.size()) + iIndices[i];
599 Indices.push_back(indnum);
601 indnum = (
unsigned int)((LoadedVertices.size()) - vVerts.size()) + iIndices[i];
602 LoadedIndices.push_back(indnum);
607 if (algorithm::firstToken(curline) ==
"usemtl")
609 MeshMatNames.push_back(algorithm::tail(curline));
612 if (!Indices.empty() && !Vertices.empty())
615 tempMesh =
Mesh(Vertices, Indices);
616 tempMesh.MeshName = meshname;
619 tempMesh.MeshName = meshname +
"_" + std::to_string(i);
621 for (
auto &m : LoadedMeshes)
622 if (m.MeshName == tempMesh.MeshName)
628 LoadedMeshes.push_back(tempMesh);
635 #ifdef OBJL_CONSOLE_OUTPUT
640 if (algorithm::firstToken(curline) ==
"mtllib")
645 std::vector<std::string> temp;
646 algorithm::split(Path, temp,
"/");
648 std::string pathtomat =
"";
650 if (temp.size() != 1)
652 for (
int i = 0; i < temp.size() - 1; i++)
654 pathtomat += temp[i] +
"/";
659 pathtomat += algorithm::tail(curline);
661 #ifdef OBJL_CONSOLE_OUTPUT
662 std::cout << std::endl <<
"- find materials in: " << pathtomat << std::endl;
666 LoadMaterials(pathtomat);
670 #ifdef OBJL_CONSOLE_OUTPUT
671 std::cout << std::endl;
676 if (!Indices.empty() && !Vertices.empty())
679 tempMesh =
Mesh(Vertices, Indices);
680 tempMesh.MeshName = meshname;
683 LoadedMeshes.push_back(tempMesh);
689 for (
int i = 0; i < MeshMatNames.size(); i++)
691 std::string matname = MeshMatNames[i];
695 for (
int j = 0; j < LoadedMaterials.size(); j++)
697 if (LoadedMaterials[j].name == matname)
699 LoadedMeshes[i].MeshMaterial = LoadedMaterials[j];
705 if (LoadedMeshes.empty() && LoadedVertices.empty() && LoadedIndices.empty())
716 std::vector<Mesh> LoadedMeshes;
718 std::vector<Vertex> LoadedVertices;
720 std::vector<unsigned int> LoadedIndices;
722 std::vector<Material> LoadedMaterials;
727 void GenVerticesFromRawOBJ(std::vector<Vertex>& oVerts,
728 const std::vector<Vector3>& iPositions,
729 const std::vector<Vector2>& iTCoords,
730 const std::vector<Vector3>& iNormals,
731 std::string icurline)
733 std::vector<std::string> sface, svert;
735 algorithm::split(algorithm::tail(icurline), sface,
" ");
737 bool noNormal =
false;
740 for (
int i = 0; i < int(sface.size()); i++)
745 algorithm::split(sface[i], svert,
"/");
748 if (svert.size() == 1)
755 if (svert.size() == 2)
763 if (svert.size() == 3)
782 vVert.Position = algorithm::getElement(iPositions, svert[0]);
783 vVert.TextureCoordinate =
Vector2(0, 0);
785 oVerts.push_back(vVert);
790 vVert.Position = algorithm::getElement(iPositions, svert[0]);
791 vVert.TextureCoordinate = algorithm::getElement(iTCoords, svert[1]);
793 oVerts.push_back(vVert);
798 vVert.Position = algorithm::getElement(iPositions, svert[0]);
799 vVert.TextureCoordinate =
Vector2(0, 0);
800 vVert.Normal = algorithm::getElement(iNormals, svert[2]);
801 oVerts.push_back(vVert);
806 vVert.Position = algorithm::getElement(iPositions, svert[0]);
807 vVert.TextureCoordinate = algorithm::getElement(iTCoords, svert[1]);
808 vVert.Normal = algorithm::getElement(iNormals, svert[2]);
809 oVerts.push_back(vVert);
824 Vector3 A = oVerts[0].Position - oVerts[1].Position;
825 Vector3 B = oVerts[2].Position - oVerts[1].Position;
827 Vector3 normal = math::CrossV3(A, B);
829 for (
int i = 0; i < int(oVerts.size()); i++)
831 oVerts[i].Normal = normal;
838 void VertexTriangluation(std::vector<unsigned int>& oIndices,
839 const std::vector<Vertex>& iVerts)
844 if (iVerts.size() < 3)
849 if (iVerts.size() == 3)
851 oIndices.push_back(0);
852 oIndices.push_back(1);
853 oIndices.push_back(2);
858 std::vector<Vertex> tVerts = iVerts;
863 for (
int i = 0; i < int(tVerts.size()); i++)
869 pPrev = tVerts[tVerts.size() - 1];
873 pPrev = tVerts[i - 1];
881 if (i == tVerts.size() - 1)
887 pNext = tVerts[i + 1];
892 if (tVerts.size() == 3)
895 for (
int j = 0; j < int(tVerts.size()); j++)
897 if (iVerts[j].Position == pCur.Position)
898 oIndices.push_back(j);
899 if (iVerts[j].Position == pPrev.Position)
900 oIndices.push_back(j);
901 if (iVerts[j].Position == pNext.Position)
902 oIndices.push_back(j);
908 if (tVerts.size() == 4)
911 for (
int j = 0; j < int(iVerts.size()); j++)
913 if (iVerts[j].Position == pCur.Position)
914 oIndices.push_back(j);
915 if (iVerts[j].Position == pPrev.Position)
916 oIndices.push_back(j);
917 if (iVerts[j].Position == pNext.Position)
918 oIndices.push_back(j);
922 for (
int j = 0; j < int(tVerts.size()); j++)
924 if (tVerts[j].Position != pCur.Position
925 && tVerts[j].Position != pPrev.Position
926 && tVerts[j].Position != pNext.Position)
928 tempVec = tVerts[j].Position;
934 for (
int j = 0; j < int(iVerts.size()); j++)
936 if (iVerts[j].Position == pPrev.Position)
937 oIndices.push_back(j);
938 if (iVerts[j].Position == pNext.Position)
939 oIndices.push_back(j);
940 if (iVerts[j].Position == tempVec)
941 oIndices.push_back(j);
949 float angle = math::AngleBetweenV3(pPrev.Position - pCur.Position, pNext.Position - pCur.Position) * (180 / 3.14159265359);
950 if (angle <= 0 && angle >= 180)
955 for (
int j = 0; j < int(iVerts.size()); j++)
957 if (algorithm::inTriangle(iVerts[j].Position, pPrev.Position, pCur.Position, pNext.Position)
958 && iVerts[j].Position != pPrev.Position
959 && iVerts[j].Position != pCur.Position
960 && iVerts[j].Position != pNext.Position)
970 for (
int j = 0; j < int(iVerts.size()); j++)
972 if (iVerts[j].Position == pCur.Position)
973 oIndices.push_back(j);
974 if (iVerts[j].Position == pPrev.Position)
975 oIndices.push_back(j);
976 if (iVerts[j].Position == pNext.Position)
977 oIndices.push_back(j);
981 for (
int j = 0; j < int(tVerts.size()); j++)
983 if (tVerts[j].Position == pCur.Position)
985 tVerts.erase(tVerts.begin() + j);
996 if (oIndices.size() == 0)
1000 if (tVerts.size() == 0)
1006 bool LoadMaterials(std::string path)
1009 if (path.substr(path.size() - 4, path.size()) !=
".mtl")
1012 std::ifstream file(path);
1015 if (!file.is_open())
1020 bool listening =
false;
1023 std::string curline;
1024 while (std::getline(file, curline))
1027 if (algorithm::firstToken(curline) ==
"newmtl")
1033 if (curline.size() > 7)
1035 tempMaterial.name = algorithm::tail(curline);
1039 tempMaterial.name =
"none";
1047 LoadedMaterials.push_back(tempMaterial);
1052 if (curline.size() > 7)
1054 tempMaterial.name = algorithm::tail(curline);
1058 tempMaterial.name =
"none";
1063 if (algorithm::firstToken(curline) ==
"Ka")
1065 std::vector<std::string> temp;
1066 algorithm::split(algorithm::tail(curline), temp,
" ");
1068 if (temp.size() != 3)
1071 tempMaterial.Ka.X = std::stof(temp[0]);
1072 tempMaterial.Ka.Y = std::stof(temp[1]);
1073 tempMaterial.Ka.Z = std::stof(temp[2]);
1076 if (algorithm::firstToken(curline) ==
"Kd")
1078 std::vector<std::string> temp;
1079 algorithm::split(algorithm::tail(curline), temp,
" ");
1081 if (temp.size() != 3)
1084 tempMaterial.Kd.X = std::stof(temp[0]);
1085 tempMaterial.Kd.Y = std::stof(temp[1]);
1086 tempMaterial.Kd.Z = std::stof(temp[2]);
1089 if (algorithm::firstToken(curline) ==
"Ks")
1091 std::vector<std::string> temp;
1092 algorithm::split(algorithm::tail(curline), temp,
" ");
1094 if (temp.size() != 3)
1097 tempMaterial.Ks.X = std::stof(temp[0]);
1098 tempMaterial.Ks.Y = std::stof(temp[1]);
1099 tempMaterial.Ks.Z = std::stof(temp[2]);
1102 if (algorithm::firstToken(curline) ==
"Ns")
1104 tempMaterial.Ns = std::stof(algorithm::tail(curline));
1107 if (algorithm::firstToken(curline) ==
"Ni")
1109 tempMaterial.Ni = std::stof(algorithm::tail(curline));
1112 if (algorithm::firstToken(curline) ==
"d")
1114 tempMaterial.d = std::stof(algorithm::tail(curline));
1117 if (algorithm::firstToken(curline) ==
"illum")
1119 tempMaterial.illum = std::stoi(algorithm::tail(curline));
1122 if (algorithm::firstToken(curline) ==
"map_Ka")
1124 tempMaterial.map_Ka = algorithm::tail(curline);
1127 if (algorithm::firstToken(curline) ==
"map_Kd")
1129 tempMaterial.map_Kd = algorithm::tail(curline);
1132 if (algorithm::firstToken(curline) ==
"map_Ks")
1134 tempMaterial.map_Ks = algorithm::tail(curline);
1137 if (algorithm::firstToken(curline) ==
"map_Ns")
1139 tempMaterial.map_Ns = algorithm::tail(curline);
1142 if (algorithm::firstToken(curline) ==
"map_d")
1144 tempMaterial.map_d = algorithm::tail(curline);
1147 if (algorithm::firstToken(curline) ==
"map_Bump" || algorithm::firstToken(curline) ==
"map_bump" || algorithm::firstToken(curline) ==
"bump")
1149 tempMaterial.map_bump = algorithm::tail(curline);
1156 LoadedMaterials.push_back(tempMaterial);
1160 if (LoadedMaterials.empty())