WavefrontOBJLoader.cpp 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. /*
  2. * Copyright (c) 2021, Jesse Buhagiar <jooster669@gmail.com>
  3. * Copyright (c) 2021, Mathieu Gaillard <gaillard.mathieu.39@gmail.com>
  4. * Copyright (c) 2021, Pedro Pereira <pmh.pereira@gmail.com>
  5. *
  6. * SPDX-License-Identifier: BSD-2-Clause
  7. */
  8. #include "WavefrontOBJLoader.h"
  9. #include <AK/FixedArray.h>
  10. #include <AK/String.h>
  11. #include <LibCore/File.h>
  12. static inline GLuint get_index_value(StringView& representation)
  13. {
  14. return representation.to_number<GLuint>().value_or(1) - 1;
  15. }
  16. static ErrorOr<GLfloat> parse_float(StringView string)
  17. {
  18. auto maybe_float = string.to_number<GLfloat>(TrimWhitespace::No);
  19. if (!maybe_float.has_value())
  20. return Error::from_string_literal("Wavefront: Expected floating point value when parsing TexCoord line");
  21. return maybe_float.release_value();
  22. }
  23. ErrorOr<NonnullRefPtr<Mesh>> WavefrontOBJLoader::load(String const& filename, NonnullOwnPtr<Core::File> file)
  24. {
  25. auto buffered_file = TRY(Core::InputBufferedFile::create(move(file)));
  26. Vector<Vertex> vertices;
  27. Vector<Vertex> normals;
  28. Vector<TexCoord> tex_coords;
  29. Vector<Triangle> triangles;
  30. dbgln("Wavefront: Loading {}...", filename);
  31. // Start reading file line by line
  32. auto buffer = TRY(ByteBuffer::create_uninitialized(PAGE_SIZE));
  33. while (TRY(buffered_file->can_read_line())) {
  34. auto object_line = TRY(buffered_file->read_line(buffer));
  35. // Ignore file comments
  36. if (object_line.starts_with('#'))
  37. continue;
  38. if (object_line.starts_with("vt"sv)) {
  39. auto tex_coord_line = object_line.split_view(' ');
  40. if (tex_coord_line.size() != 3) {
  41. return Error::from_string_literal("Wavefront: Malformed TexCoord line.");
  42. }
  43. tex_coords.append({ TRY(parse_float(tex_coord_line.at(1))),
  44. TRY(parse_float(tex_coord_line.at(2))) });
  45. continue;
  46. }
  47. if (object_line.starts_with("vn"sv)) {
  48. auto normal_line = object_line.split_view(' ');
  49. if (normal_line.size() != 4) {
  50. return Error::from_string_literal("Wavefront: Malformed vertex normal line.");
  51. }
  52. normals.append({ TRY(parse_float(normal_line.at(1))),
  53. TRY(parse_float(normal_line.at(2))),
  54. TRY(parse_float(normal_line.at(3))) });
  55. continue;
  56. }
  57. // This line describes a vertex (a position in 3D space)
  58. if (object_line.starts_with('v')) {
  59. auto vertex_line = object_line.split_view(' ');
  60. if (vertex_line.size() != 4) {
  61. return Error::from_string_literal("Wavefront: Malformed vertex line.");
  62. }
  63. vertices.append({ TRY(parse_float((vertex_line.at(1)))),
  64. TRY(parse_float((vertex_line.at(2)))),
  65. TRY(parse_float((vertex_line.at(3)))) });
  66. continue;
  67. }
  68. // This line describes a face (a collection of 3+ vertices, aka a triangle or polygon)
  69. if (object_line.starts_with('f')) {
  70. auto face_line = object_line.substring_view(2).split_view(' ');
  71. auto number_of_vertices = face_line.size();
  72. if (number_of_vertices < 3) {
  73. return Error::from_string_literal("Wavefront: Malformed face line.");
  74. }
  75. auto vertex_indices = TRY(FixedArray<GLuint>::create(number_of_vertices));
  76. auto tex_coord_indices = TRY(FixedArray<GLuint>::create(number_of_vertices));
  77. auto normal_indices = TRY(FixedArray<GLuint>::create(number_of_vertices));
  78. for (size_t i = 0; i < number_of_vertices; ++i) {
  79. auto vertex_parts = face_line.at(i).split_view('/', SplitBehavior::KeepEmpty);
  80. vertex_indices[i] = get_index_value(vertex_parts[0]);
  81. tex_coord_indices[i] = (vertex_parts.size() >= 2) ? get_index_value(vertex_parts[1]) : 0;
  82. normal_indices[i] = (vertex_parts.size() >= 3) ? get_index_value(vertex_parts[2]) : 0;
  83. }
  84. // Create a triangle for each part of the polygon
  85. for (size_t i = 0; i < number_of_vertices - 2; ++i) {
  86. triangles.append({
  87. vertex_indices[0],
  88. vertex_indices[i + 1],
  89. vertex_indices[i + 2],
  90. tex_coord_indices[0],
  91. tex_coord_indices[i + 1],
  92. tex_coord_indices[i + 2],
  93. normal_indices[0],
  94. normal_indices[i + 1],
  95. normal_indices[i + 2],
  96. });
  97. }
  98. }
  99. }
  100. if (vertices.is_empty()) {
  101. return Error::from_string_literal("Wavefront: Failed to read any data from 3D file");
  102. }
  103. dbgln("Wavefront: Done.");
  104. return adopt_ref(*new Mesh(vertices, tex_coords, normals, triangles));
  105. }