21#define OBJL_CONSOLE_OUTPUT
47 bool operator==(
const Vector2& other)
const
49 return (this->X == other.X && this->Y == other.Y);
52 bool operator!=(
const Vector2& other)
const
54 return !(this->X == other.X && this->Y == other.Y);
59 return Vector2(this->X + right.X, this->Y + right.Y);
64 return Vector2(this->X - right.X, this->Y - right.Y);
67 Vector2 operator*(
const float& other)
const
69 return Vector2(this->X *other, this->Y * other);
90 Vector3(
float X_,
float Y_,
float Z_)
97 bool operator==(
const Vector3& other)
const
99 return (this->X == other.X && this->Y == other.Y && this->Z == other.Z);
102 bool operator!=(
const Vector3& other)
const
104 return !(this->X == other.X && this->Y == other.Y && this->Z == other.Z);
109 return Vector3(this->X + right.X, this->Y + right.Y, this->Z + right.Z);
114 return Vector3(this->X - right.X, this->Y - right.Y, this->Z - right.Z);
117 Vector3 operator*(
const float& other)
const
119 return Vector3(this->X * other, this->Y * other, this->Z * other);
122 Vector3 operator/(
const float& other)
const
124 return Vector3(this->X / other, this->Y / other, this->Z / other);
187 std::string map_bump;
202 Mesh(std::vector<Vertex>& _Vertices, std::vector<unsigned int>& _Indices)
204 Vertices = _Vertices;
208 std::string MeshName;
210 std::vector<Vertex> Vertices;
212 std::vector<unsigned int> Indices;
227 return Vector3(a.Y * b.Z - a.Z * b.Y,
228 a.Z * b.X - a.X * b.Z,
229 a.X * b.Y - a.Y * b.X);
233 float MagnitudeV3(
const Vector3 in)
235 return (sqrtf(powf(in.X, 2) + powf(in.Y, 2) + powf(in.Z, 2)));
239 float DotV3(
const Vector3 a,
const Vector3 b)
241 return (a.X * b.X) + (a.Y * b.Y) + (a.Z * b.Z);
245 float AngleBetweenV3(
const Vector3 a,
const Vector3 b)
247 float angle = DotV3(a, b);
248 angle /= (MagnitudeV3(a) * MagnitudeV3(b));
249 return angle = acosf(angle);
253 Vector3 ProjV3(
const Vector3 a,
const Vector3 b)
255 Vector3 bn = b / MagnitudeV3(b);
256 return bn * DotV3(a, bn);
267 Vector3 operator*(
const float& left,
const Vector3& right)
269 return Vector3(right.X * left, right.Y * left, right.Z * left);
273 bool SameSide(Vector3 p1, Vector3 p2, Vector3 a, Vector3 b)
275 Vector3 cp1 = math::CrossV3(b - a, p1 - a);
276 Vector3 cp2 = math::CrossV3(b - a, p2 - a);
278 if (math::DotV3(cp1, cp2) >= 0)
285 Vector3 GenTriNormal(Vector3 t1, Vector3 t2, Vector3 t3)
290 Vector3 normal = math::CrossV3(u,v);
296 bool inTriangle(Vector3 point, Vector3 tri1, Vector3 tri2, Vector3 tri3)
299 bool within_tri_prisim = SameSide(point, tri1, tri2, tri3) && SameSide(point, tri2, tri1, tri3)
300 && SameSide(point, tri3, tri1, tri2);
303 if (!within_tri_prisim)
307 Vector3 n = GenTriNormal(tri1, tri2, tri3);
310 Vector3 proj = math::ProjV3(point, n);
314 if (math::MagnitudeV3(proj) == 0)
321 inline void split(
const std::string &in,
322 std::vector<std::string> &out,
329 for (
int i = 0; i < int(in.size()); i++)
331 std::string test = in.substr(i, token.size());
339 i += (int)token.size() - 1;
346 else if (i + token.size() >= in.size())
348 temp += in.substr(i, token.size());
360 inline std::string tail(
const std::string &in)
362 size_t token_start = in.find_first_not_of(
" \t");
363 size_t space_start = in.find_first_of(
" \t", token_start);
364 size_t tail_start = in.find_first_not_of(
" \t", space_start);
365 size_t tail_end = in.find_last_not_of(
" \t");
366 if (tail_start != std::string::npos && tail_end != std::string::npos)
368 return in.substr(tail_start, tail_end - tail_start + 1);
370 else if (tail_start != std::string::npos)
372 return in.substr(tail_start);
378 inline std::string firstToken(
const std::string &in)
382 size_t token_start = in.find_first_not_of(
" \t");
383 size_t token_end = in.find_first_of(
" \t", token_start);
384 if (token_start != std::string::npos && token_end != std::string::npos)
386 return in.substr(token_start, token_end - token_start);
388 else if (token_start != std::string::npos)
390 return in.substr(token_start);
398 inline const T & getElement(
const std::vector<T> &elements, std::string &index)
400 int idx = std::stoi(index);
402 idx = int(elements.size()) + idx;
405 return elements[idx];
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())
Definition: OBJ_Loader.h:413
Definition: OBJ_Loader.h:150
Definition: OBJ_Loader.h:195
Definition: OBJ_Loader.h:33
Definition: OBJ_Loader.h:81
Definition: OBJ_Loader.h:138