WavefrontOBJLoader.cpp 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  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 <LibCore/File.h>
  11. #include <stdlib.h>
  12. static inline GLuint get_index_value(StringView& representation)
  13. {
  14. return representation.to_uint().value_or(1) - 1;
  15. }
  16. RefPtr<Mesh> WavefrontOBJLoader::load(Core::File& file)
  17. {
  18. Vector<Vertex> vertices;
  19. Vector<Vertex> normals;
  20. Vector<TexCoord> tex_coords;
  21. Vector<Triangle> triangles;
  22. dbgln("Wavefront: Loading {}...", file.name());
  23. // Start reading file line by line
  24. for (auto object_line : file.lines()) {
  25. // Ignore file comments
  26. if (object_line.starts_with('#'))
  27. continue;
  28. if (object_line.starts_with("vt"sv)) {
  29. auto tex_coord_line = object_line.split_view(' ');
  30. if (tex_coord_line.size() != 3) {
  31. dbgln("Wavefront: Malformed TexCoord line. Aborting.");
  32. return nullptr;
  33. }
  34. tex_coords.append({ static_cast<GLfloat>(atof(String(tex_coord_line.at(1)).characters())),
  35. static_cast<GLfloat>(atof(String(tex_coord_line.at(2)).characters())) });
  36. continue;
  37. }
  38. if (object_line.starts_with("vn"sv)) {
  39. auto normal_line = object_line.split_view(' ');
  40. if (normal_line.size() != 4) {
  41. dbgln("Wavefront: Malformed vertex normal line. Aborting.");
  42. return nullptr;
  43. }
  44. normals.append({ static_cast<GLfloat>(atof(String(normal_line.at(1)).characters())),
  45. static_cast<GLfloat>(atof(String(normal_line.at(2)).characters())),
  46. static_cast<GLfloat>(atof(String(normal_line.at(3)).characters())) });
  47. continue;
  48. }
  49. // This line describes a vertex (a position in 3D space)
  50. if (object_line.starts_with('v')) {
  51. auto vertex_line = object_line.split_view(' ');
  52. if (vertex_line.size() != 4) {
  53. dbgln("Wavefront: Malformed vertex line. Aborting.");
  54. return nullptr;
  55. }
  56. vertices.append({ static_cast<GLfloat>(atof(String(vertex_line.at(1)).characters())),
  57. static_cast<GLfloat>(atof(String(vertex_line.at(2)).characters())),
  58. static_cast<GLfloat>(atof(String(vertex_line.at(3)).characters())) });
  59. continue;
  60. }
  61. // This line describes a face (a collection of 3+ vertices, aka a triangle or polygon)
  62. if (object_line.starts_with('f')) {
  63. auto face_line = object_line.substring_view(2).split_view(' ');
  64. auto number_of_vertices = face_line.size();
  65. if (number_of_vertices < 3) {
  66. dbgln("Wavefront: Malformed face line. Aborting.");
  67. return nullptr;
  68. }
  69. auto vertex_indices = FixedArray<GLuint>::must_create_but_fixme_should_propagate_errors(number_of_vertices);
  70. auto tex_coord_indices = FixedArray<GLuint>::must_create_but_fixme_should_propagate_errors(number_of_vertices);
  71. auto normal_indices = FixedArray<GLuint>::must_create_but_fixme_should_propagate_errors(number_of_vertices);
  72. for (size_t i = 0; i < number_of_vertices; ++i) {
  73. auto vertex_parts = face_line.at(i).split_view('/', true);
  74. vertex_indices[i] = get_index_value(vertex_parts[0]);
  75. tex_coord_indices[i] = (vertex_parts.size() >= 2) ? get_index_value(vertex_parts[1]) : 0;
  76. normal_indices[i] = (vertex_parts.size() >= 3) ? get_index_value(vertex_parts[2]) : 0;
  77. }
  78. // Create a triangle for each part of the polygon
  79. for (size_t i = 0; i < number_of_vertices - 2; ++i) {
  80. triangles.append({
  81. vertex_indices[0],
  82. vertex_indices[i + 1],
  83. vertex_indices[i + 2],
  84. tex_coord_indices[0],
  85. tex_coord_indices[i + 1],
  86. tex_coord_indices[i + 2],
  87. normal_indices[0],
  88. normal_indices[i + 1],
  89. normal_indices[i + 2],
  90. });
  91. }
  92. }
  93. }
  94. if (vertices.is_empty()) {
  95. dbgln("Wavefront: Failed to read any data from 3D file: {}", file.name());
  96. return nullptr;
  97. }
  98. dbgln("Wavefront: Done.");
  99. return adopt_ref(*new Mesh(vertices, tex_coords, normals, triangles));
  100. }