Paste
Of Code


 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
#include "../include/WavefrontOBJ.h"
#include <JGL/types/VertexArray.h>
#include <JGL/logger/logger.h>

std::pair<float, unsigned long> ParseNumber(const std::string& file_text, const unsigned long& offset) {
    std::string number;
    unsigned long new_offset = offset;
    bool decimal_used = false;

    if (offset >= file_text.size())
        return {0.0f, offset};

    for (; new_offset < file_text.size(); new_offset++) {
        if (file_text[new_offset] == '-') {
            if (number.empty()) {
                number.push_back(file_text[new_offset]);
                continue;
            }
            Logger::Error("Error while parsing number, Index: " + std::to_string(new_offset) + " Extra negative sign.");
            return {0.0f, offset};
        }

        else if (file_text[new_offset] == '.') {
            if (!decimal_used) {
                number.push_back(file_text[new_offset]);
                decimal_used = true;
                continue;
            }
            Logger::Error("Error parsing number at: " + std::to_string(new_offset) + " Extra decimal point.");
            return {0.0f, offset};
        }

        else if (isdigit(file_text[new_offset]))
            number.push_back(file_text[new_offset]);
        else
            break;
    }
    return {std::stof(number), new_offset};
}

std::pair<Vector2, unsigned long> ParseVector2(const std::string& file_text, const unsigned long& offset) {
    auto x_result = ParseNumber(file_text, offset);
    auto y_result = ParseNumber(file_text, x_result.second + 1);

    // If the new offset is the same as the offset we passed in then we know it didn't work.
    if (x_result.second == offset || y_result.second == x_result.second)
        return {Vector2(0, 0), offset};

    return {Vector2(x_result.first, y_result.first), y_result.second + 1};
}

std::pair<Vector3, unsigned long> ParseVector3(const std::string& file_text, const unsigned long& offset) {
    auto x_result = ParseNumber(file_text, offset);
    auto y_result = ParseNumber(file_text, x_result.second + 1);
    auto z_result = ParseNumber(file_text, y_result.second + 1);

    // If the new offset is the same as the offset we passed in then we know it didn't work.
    if (x_result.second == offset || y_result.second == x_result.second || z_result.second == y_result.second)
        return {Vector3(0,0,0), offset};

    return {Vector3(x_result.first, y_result.first, z_result.first), z_result.second + 1};
}

std::pair<std::array<Vector3, 3>, unsigned long> ParseFaceData(const std::string& file_text, const unsigned long& offset) {
    unsigned long new_offset = offset;
    std::array<Vector3, 3> face_data;

    for (unsigned int i = 0; i < 3; i++) {
        Vector3 vertex = {-1, -1, -1};

        // Vertex
        if (std::isdigit(file_text[new_offset])) {
            auto v_result = ParseNumber(file_text, new_offset);
            vertex.x = v_result.first;
            new_offset = v_result.second;
        }

        // UV
        if (new_offset < file_text.size() && file_text[new_offset] == '/') {
            new_offset++;

            if (new_offset < file_text.size() && (std::isdigit(file_text[new_offset]))) {
                auto vt_result = ParseNumber(file_text, new_offset);
                vertex.y = vt_result.first;
                new_offset = vt_result.second;
            }
        }

        // Normal
        if (new_offset < file_text.size() && file_text[new_offset] == '/') {
            new_offset++;

            if (new_offset < file_text.size() && (std::isdigit(file_text[new_offset]))) {
                auto vn_result = ParseNumber(file_text, new_offset);
                vertex.z = vn_result.first;
                new_offset = vn_result.second;
            }
        }

        face_data[i] = vertex;
        new_offset++;
    }
    return {face_data, new_offset};
}

VertexArray JGL::LoadWavefrontOBJ(const std::string &file_text) {
    std::vector<std::array<Vector3, 3>> faceline_data;

    std::vector<TextureCoordinate> temp_uvs;
    std::vector<Normal> temp_normals;
    std::vector<Vertex> temp_vertices;

    unsigned long offset = 0;

    while (offset < file_text.size()) {
        char c = file_text[offset];
        
        // TODO the entire line a comment is on should be skipped.
        // Skip forward to the character after the next newline.
        if (c == '#' || c == '\n' || c == '\r') {
            offset++;
            continue;
        }

        // Vertices
        if (c == 'v' && offset + 1 < file_text.size() && file_text[offset + 1] == ' ') {
            offset += 2;

            auto vertex_result = ParseVector3(file_text, offset);
            if (vertex_result.second != offset) {
                temp_vertices.push_back(vertex_result.first);
                offset = vertex_result.second;
            }
        }

            // Normals.
        else if (c == 'v' && offset + 2 < file_text.size() && file_text[offset + 1] == 'n' &&
                 file_text[offset + 2] == ' ') {
            offset += 3;

            auto normal_result = ParseVector3(file_text, offset);
            if (normal_result.second != offset) {
                temp_normals.push_back(normal_result.first);
                offset = normal_result.second;
            }
        }

            // Texture Coordinates
        else if (c == 'v' && offset + 2 < file_text.size() && file_text[offset + 1] == 't' &&
                 file_text[offset + 2] == ' ') {
            offset += 3;

            auto uv_result = ParseVector2(file_text, offset);
            if (uv_result.second != offset) {
                temp_uvs.push_back(uv_result.first);
                offset = uv_result.second;
            }
        }

            // Face lines.
        else if (c == 'f' && offset + 1 < file_text.size() && file_text[offset + 1] == ' ') {
            offset += 2;

            auto faceline_result = ParseFaceData(file_text, offset);
            if (faceline_result.second != offset) {
                faceline_data.push_back(faceline_result.first);
                offset = faceline_result.second;
            }
        } else
            offset++;
    }

// Pick everything out of the face lines and set up how OpenGL expects.
    std::vector<Vertex> final_vertices;
    std::vector<TextureCoordinate> final_uvs;
    std::vector<Normal> final_normals;
    std::vector<unsigned int> final_indices;
    for (const auto &face: faceline_data) {
        for (const auto &vp: face) {
            Vertex vertex;
            TextureCoordinate uv;
            Normal normal;

            if (vp.x != -1)
                vertex = temp_vertices[vp.x - 1];
            if (vp.y != -1)
                uv = temp_uvs[vp.y - 1];
            if (vp.z != -1)
                normal = temp_normals[vp.z - 1];

            final_vertices.push_back(vertex);
            final_uvs.push_back(uv);
            final_normals.push_back(normal);
            final_indices.push_back((unsigned int) final_vertices.size() - 1);
        }
    }

    return VertexArray(
            final_vertices.data(), final_vertices.size(),
            final_indices.data(), final_indices.size(),
            final_normals.data(), final_normals.size(),
            final_uvs.data(), final_uvs.size());
}

Toggle: theme, font