1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-26 08:27:45 +00:00

Applications: Support .obj polygons in 3DFileViewer

Our `WavefrontOBJLoader` only supported faces with 3 vertices, but
`.obj` files can specify arbitrary polygons with 4 or more vertices.
This commit is contained in:
Jelle Raaijmakers 2022-04-10 00:04:52 +02:00 committed by Andreas Kling
parent 1577a8ba42
commit a021a7e240

View file

@ -7,9 +7,15 @@
*/ */
#include "WavefrontOBJLoader.h" #include "WavefrontOBJLoader.h"
#include <AK/FixedArray.h>
#include <LibCore/File.h> #include <LibCore/File.h>
#include <stdlib.h> #include <stdlib.h>
static inline GLuint get_index_value(StringView& representation)
{
return representation.to_uint().value_or(1) - 1;
}
RefPtr<Mesh> WavefrontOBJLoader::load(Core::File& file) RefPtr<Mesh> WavefrontOBJLoader::load(Core::File& file)
{ {
Vector<Vertex> vertices; Vector<Vertex> vertices;
@ -29,7 +35,6 @@ RefPtr<Mesh> WavefrontOBJLoader::load(Core::File& file)
auto tex_coord_line = object_line.split_view(' '); auto tex_coord_line = object_line.split_view(' ');
if (tex_coord_line.size() != 3) { if (tex_coord_line.size() != 3) {
dbgln("Wavefront: Malformed TexCoord line. Aborting."); dbgln("Wavefront: Malformed TexCoord line. Aborting.");
dbgln("{}", object_line);
return nullptr; return nullptr;
} }
@ -68,54 +73,40 @@ RefPtr<Mesh> WavefrontOBJLoader::load(Core::File& file)
continue; continue;
} }
// This line describes a face (a collection of 3 vertices, aka a triangle) // This line describes a face (a collection of 3+ vertices, aka a triangle or polygon)
if (object_line.starts_with("f")) { if (object_line.starts_with("f")) {
auto face_line = object_line.split_view(' '); auto face_line = object_line.substring_view(2).split_view(' ');
if (face_line.size() != 4) { auto number_of_vertices = face_line.size();
if (number_of_vertices < 3) {
dbgln("Wavefront: Malformed face line. Aborting."); dbgln("Wavefront: Malformed face line. Aborting.");
return nullptr; return nullptr;
} }
GLuint vert_index[3]; auto vertex_indices = FixedArray<GLuint>::must_create_but_fixme_should_propagate_errors(number_of_vertices);
GLuint tex_coord_index[3]; auto tex_coord_indices = FixedArray<GLuint>::must_create_but_fixme_should_propagate_errors(number_of_vertices);
GLuint normal_index[3]; auto normal_indices = FixedArray<GLuint>::must_create_but_fixme_should_propagate_errors(number_of_vertices);
if (object_line.contains("/")) {
for (int i = 1; i <= 3; ++i) {
auto vertex_data = face_line.at(i).split_view("/", true);
vert_index[i - 1] = vertex_data.at(0).to_uint().value_or(1); for (size_t i = 0; i < number_of_vertices; ++i) {
tex_coord_index[i - 1] = vertex_data.at(1).to_uint().value_or(1); auto vertex_parts = face_line.at(i).split_view('/', true);
vertex_indices[i] = get_index_value(vertex_parts[0]);
if (vertex_data.size() == 3) tex_coord_indices[i] = (vertex_parts.size() >= 2) ? get_index_value(vertex_parts[1]) : 0;
normal_index[i - 1] = vertex_data.at(2).to_uint().value_or(1); normal_indices[i] = (vertex_parts.size() >= 3) ? get_index_value(vertex_parts[2]) : 0;
else
normal_index[i - 1] = 1;
}
} else {
vert_index[0] = (face_line.at(1).to_uint().value_or(1));
vert_index[1] = (face_line.at(2).to_uint().value_or(1));
vert_index[2] = (face_line.at(3).to_uint().value_or(1));
tex_coord_index[0] = 0;
tex_coord_index[1] = 0;
tex_coord_index[2] = 0;
normal_index[0] = 0;
normal_index[1] = 0;
normal_index[2] = 0;
} }
// Create a new triangle // Create a triangle for each part of the polygon
triangles.append( for (size_t i = 0; i < number_of_vertices - 2; ++i) {
{ triangles.append({
vert_index[0] - 1, vertex_indices[0],
vert_index[1] - 1, vertex_indices[i + 1],
vert_index[2] - 1, vertex_indices[i + 2],
tex_coord_index[0] - 1, tex_coord_indices[0],
tex_coord_index[1] - 1, tex_coord_indices[i + 1],
tex_coord_index[2] - 1, tex_coord_indices[i + 2],
normal_index[0] - 1, normal_indices[0],
normal_index[1] - 1, normal_indices[i + 1],
normal_index[2] - 1, normal_indices[i + 2],
}); });
}
} }
} }