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