summaryrefslogtreecommitdiff
path: root/Userland/Applications/3DFileViewer/WavefrontOBJLoader.cpp
blob: 891f13dc8f292be96af0f13c1ba54fc051a1e5f0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
/*
 * Copyright (c) 2021, Jesse Buhagiar <jooster669@gmail.com>
 * Copyright (c) 2021, Mathieu Gaillard <gaillard.mathieu.39@gmail.com>
 *
 * SPDX-License-Identifier: BSD-2-Clause
 */

#include "WavefrontOBJLoader.h"
#include <LibCore/File.h>
#include <stdlib.h>

RefPtr<Mesh> WavefrontOBJLoader::load(const String& fname)
{
    auto obj_file_or_error = Core::File::open(fname, Core::OpenMode::ReadOnly);
    Vector<Vertex> vertices;
    Vector<Triangle> triangles;

    dbgln("Wavefront: Loading {}...", fname);

    if (obj_file_or_error.is_error())
        return nullptr;

    // Start reading file line by line
    for (auto line = obj_file_or_error.value()->line_begin(); !line.at_end(); ++line) {
        auto object_line = *line;

        // FIXME: Parse texture coordinates and vertex normals
        if (object_line.starts_with("vt") || object_line.starts_with("vn")) {
            continue;
        }

        // This line describes a vertex (a position in 3D space)
        if (object_line.starts_with("v")) {
            auto vertex_line = object_line.split_view(' ');
            if (vertex_line.size() != 4) {
                dbgln("Wavefront: Malformed vertex line. Aborting.");
                return nullptr;
            }

            vertices.append(
                { static_cast<GLfloat>(atof(String(vertex_line.at(1)).characters())),
                    static_cast<GLfloat>(atof(String(vertex_line.at(2)).characters())),
                    static_cast<GLfloat>(atof(String(vertex_line.at(3)).characters())) });
        }
        // This line describes a face (a collection of 3 vertices, aka a triangle)
        else if (object_line.starts_with("f")) {
            auto face_line = object_line.split_view(' ');
            if (face_line.size() != 4) {
                dbgln("Wavefront: Malformed face line. Aborting.");
                return nullptr;
            }

            if (object_line.contains("/")) {
                for (int i = 1; i <= 3; ++i) {
                    face_line.at(i) = face_line.at(i).split_view("/").at(0);
                }
            }

            // Create a new triangle
            triangles.append(
                {
                    face_line.at(1).to_uint().value() - 1,
                    face_line.at(2).to_uint().value() - 1,
                    face_line.at(3).to_uint().value() - 1,
                });
        }
    }

    if (vertices.is_empty()) {
        dbgln("Wavefront: Failed to read any data from 3D file: {}", fname);
        return nullptr;
    }

    dbgln("Wavefront: Done.");
    return adopt_ref(*new Mesh(vertices, triangles));
}