Program Listing for File OBJLoader.h

Return to documentation for file (Utilities/OBJLoader.h)

#ifndef __OBJLoader_h__
#define __OBJLoader_h__

#include <string>
#include "Logger.h"
#include "StringTools.h"
#include <array>

namespace Utilities
{
    struct MeshFaceIndices
    {
        std::array<int, 3> posIndices;
        std::array<int, 3> texIndices;
        std::array<int, 3> normalIndices;
    };

    class OBJLoader
    {
    public:
        using Vec3f = std::array<float, 3>;
        using Vec2f = std::array<float, 2>;

        static void loadObj(const std::string &filename, std::vector<Vec3f> *x, std::vector<MeshFaceIndices> *faces, std::vector<Vec3f> *normals, std::vector<Vec2f> *texcoords, const Vec3f &scale)
        {
            LOG_INFO << "Loading " << filename;

            std::ifstream filestream;
            filestream.open(filename.c_str());
            if (filestream.fail())
            {
                LOG_ERR << "Failed to open file: " << filename;
                return;
            }

            std::string line_stream;
            bool vt = false;
            bool vn = false;

            std::vector<std::string> pos_buffer;
            std::vector<std::string> f_buffer;

            while (getline(filestream, line_stream))
            {
                std::stringstream str_stream(line_stream);
                std::string type_str;
                str_stream >> type_str;

                if (type_str == "v")
                {
                    Vec3f pos;
                    pos_buffer.clear();
                    std::string parse_str = line_stream.substr(line_stream.find("v") + 1);
                    StringTools::tokenize(parse_str, pos_buffer);
                    for (unsigned int i = 0; i < 3; i++)
                        pos[i] = stof(pos_buffer[i]) * scale[i];

                    x->push_back(pos);
                }
                else if (type_str == "vt")
                {
                    if (texcoords != nullptr)
                    {
                        Vec2f tex;
                        pos_buffer.clear();
                        std::string parse_str = line_stream.substr(line_stream.find("vt") + 2);
                        StringTools::tokenize(parse_str, pos_buffer);
                        for (unsigned int i = 0; i < 2; i++)
                            tex[i] = stof(pos_buffer[i]);

                        texcoords->push_back(tex);
                        vt = true;
                    }
                }
                else if (type_str == "vn")
                {
                    if (normals != nullptr)
                    {
                        Vec3f nor;
                        pos_buffer.clear();
                        std::string parse_str = line_stream.substr(line_stream.find("vn") + 2);
                        StringTools::tokenize(parse_str, pos_buffer);
                        for (unsigned int i = 0; i < 3; i++)
                            nor[i] = stof(pos_buffer[i]);

                        normals->push_back(nor);
                        vn = true;
                    }
                }
                else if (type_str == "f")
                {
                    MeshFaceIndices faceIndex;
                    if (vn && vt)
                    {
                        f_buffer.clear();
                        std::string parse_str = line_stream.substr(line_stream.find("f") + 1);
                        StringTools::tokenize(parse_str, f_buffer);
                        for (int i = 0; i < 3; ++i)
                        {
                            pos_buffer.clear();
                            StringTools::tokenize(f_buffer[i], pos_buffer, "/");
                            faceIndex.posIndices[i] = stoi(pos_buffer[0]) - 1;
                            faceIndex.texIndices[i] = stoi(pos_buffer[1]) - 1;
                            faceIndex.normalIndices[i] = stoi(pos_buffer[2]) - 1;
                        }
                    }
                    else if (vn)
                    {
                        f_buffer.clear();
                        std::string parse_str = line_stream.substr(line_stream.find("f") + 1);
                        StringTools::tokenize(parse_str, f_buffer);
                        for (int i = 0; i < 3; ++i)
                        {
                            pos_buffer.clear();
                            StringTools::tokenize(f_buffer[i], pos_buffer, "/");
                            faceIndex.posIndices[i] = stoi(pos_buffer[0]) - 1;
                            faceIndex.normalIndices[i] = stoi(pos_buffer[1]) - 1;
                        }
                    }
                    else if (vt)
                    {
                        f_buffer.clear();
                        std::string parse_str = line_stream.substr(line_stream.find("f") + 1);
                        StringTools::tokenize(parse_str, f_buffer);
                        for (int i = 0; i < 3; ++i)
                        {
                            pos_buffer.clear();
                            StringTools::tokenize(f_buffer[i], pos_buffer, "/");
                            faceIndex.posIndices[i] = stoi(pos_buffer[0]) - 1;
                            faceIndex.texIndices[i] = stoi(pos_buffer[1]) - 1;
                        }
                    }
                    else
                    {
                        f_buffer.clear();
                        std::string parse_str = line_stream.substr(line_stream.find("f") + 1);
                        StringTools::tokenize(parse_str, f_buffer);
                        for (int i = 0; i < 3; ++i)
                        {
                            faceIndex.posIndices[i] = stoi(f_buffer[i]) - 1;
                        }
                    }
                    faces->push_back(faceIndex);
                }
            }
            filestream.close();
        }

    };
}

#endif