5#include <vulkan/vulkan.h>
7#define GLM_ENABLE_EXPERIMENTAL
9#include <glm/gtx/hash.hpp>
17#include <unordered_map>
28 VkVertexInputBindingDescription bindingDescription{};
29 bindingDescription.binding = 0;
30 bindingDescription.stride =
sizeof(
ObjVertex);
31 bindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
33 return bindingDescription;
38 std::vector<VkVertexInputAttributeDescription> attributeDescriptions(3);
40 attributeDescriptions[0].binding = 0;
41 attributeDescriptions[0].location = 0;
42 attributeDescriptions[0].format = VK_FORMAT_R32G32B32_SFLOAT;
43 attributeDescriptions[0].offset = offsetof(
ObjVertex,
pos);
45 attributeDescriptions[1].binding = 0;
46 attributeDescriptions[1].location = 1;
47 attributeDescriptions[1].format = VK_FORMAT_R32G32B32_SFLOAT;
50 attributeDescriptions[2].binding = 0;
51 attributeDescriptions[2].location = 2;
52 attributeDescriptions[2].format = VK_FORMAT_R32G32_SFLOAT;
55 return attributeDescriptions;
70 return ((hash<glm::vec3>()(vertex.
pos) ^
71 (hash<glm::vec3>()(vertex.
normal) << 1)) >> 1) ^
72 (hash<glm::vec2>()(vertex.
tex_coord) << 1);
86 for (
size_t i = 0; i < 3; i++)
90 std::cout << std::endl;
101 this->m_path = m_path;
104 this->removeComments();
106 this->populateVerticesAndIndices();
111 return this->m_vertices;
116 return this->m_indices;
122 std::vector<std::string> m_lines;
124 std::vector<glm::vec3> m_vertexPos;
125 std::vector<glm::vec2> m_texCoords;
126 std::vector<glm::vec3> m_normals;
128 std::vector<Face> m_faces;
130 bool m_hasTexCoords =
false;
131 bool m_hasNormals =
false;
133 std::vector<ObjVertex> m_vertices;
134 std::vector<uint32_t> m_indices;
139 std::ifstream file(this->m_path);
142 throw std::runtime_error(
"Failed to open file '" + this->m_path +
"'");
146 while (std::getline(file, line))
148 this->m_lines.push_back(line);
152 void removeComments()
154 for (
size_t i = 0; i < this->m_lines.size(); i++)
156 std::string line = this->m_lines[i];
157 size_t commentPos = line.find(
'#');
158 if (commentPos != std::string::npos)
160 line = line.substr(0, commentPos);
162 this->m_lines[i] = line;
169 std::regex faceRegex_v(R
"(^f(\s\d+){3,}$)");
170 std::regex faceRegex_v_vt(R"(^f(\s\d+\/\d+){3,}$)");
171 std::regex faceRegex_v_vn(R"(^f(\s\d+\/\/\d+){3,}$)");
172 std::regex faceRegex_v_vt_vn(R"(^f(\s\d+\/\d+\/\d+){3,}$)");
174 for (uint32_t i = 0; i < this->m_lines.size(); i++)
178 if (std::all_of(this->m_lines[i].begin(), this->m_lines[i].end(), isspace))
183 std::string line = this->m_lines[i];
184 std::stringstream ss(line);
185 ss.exceptions(std::ios_base::failbit | std::ios_base::badbit);
190 if (memcmp(line.c_str(),
"v ", 2) == 0)
194 ss >> vertex[0] >> vertex[1] >> vertex[2];
195 this->m_vertexPos.push_back(vertex);
197 else if (memcmp(line.c_str(),
"vt ", 3) == 0)
201 ss >> texCoord[0] >> texCoord[1];
202 this->m_texCoords.push_back(texCoord);
203 this->m_hasTexCoords =
true;
205 else if (memcmp(line.c_str(),
"vn ", 3) == 0)
209 ss >> normal[0] >> normal[1] >> normal[2];
210 this->m_normals.push_back(normal);
211 this->m_hasNormals =
true;
213 else if (memcmp(line.c_str(),
"f ", 2) == 0)
215 std::vector<Face> tmp_faces;
218 bool v =
false, v_vt =
false, v_vn =
false, v_vt_vn =
false;
219 if (std::regex_match(line, faceRegex_v))
221 else if (std::regex_match(line, faceRegex_v_vt) && m_hasTexCoords)
223 else if (std::regex_match(line, faceRegex_v_vn) && m_hasNormals)
225 else if (std::regex_match(line, faceRegex_v_vt_vn) && m_hasTexCoords && m_hasNormals)
228 throw std::string(
"Parsing syntax error: Invalid face format");
234 while (ss.rdstate() == std::ios_base::goodbit)
247 if (this->checkIndices(face) ==
false)
249 throw std::string(
"Parsing value error");
252 tmp_faces.push_back(face);
257 for (j = 1; j + 1 < tmp_faces.size(); j++)
262 face.
vertexIndex[2] = tmp_faces[j + 1].vertexIndex[0];
273 face.
normalIndex[2] = tmp_faces[j + 1].normalIndex[0];
275 this->m_faces.push_back(face);
279 memcmp(line.c_str(),
"mtllib ", 7) != 0
280 && memcmp(line.c_str(),
"usemtl ", 7) != 0
281 && memcmp(line.c_str(),
"s ", 2) != 0
282 && memcmp(line.c_str(),
"g ", 2) != 0
283 && memcmp(line.c_str(),
"o ", 2) != 0
286 throw std::string(
"Parsing syntax error: Unknown line type");
289 }
catch (std::string& e)
291 throw std::runtime_error(this->m_path +
": line " + std::to_string(i + 1) +
": " + e);
296 bool checkIndices(
const Face & face)
313 void populateVerticesAndIndices()
315 std::unordered_map<ObjVertex, uint32_t> uniqueVertices{};
317 for (
const auto& face : this->m_faces)
319 glm::vec2 arbitraryTexCoords[3] =
321 glm::vec2(0.0f, 0.0f),
322 glm::vec2(1.0f, 0.0f),
323 glm::vec2(0.0f, 1.0f)
326 for (
size_t i = 0; i < 3; i++)
332 if (this->m_hasTexCoords)
334 vertex.tex_coord = this->m_texCoords[face.
texCoordIndex[i] - 1];
338 vertex.tex_coord = arbitraryTexCoords[i];
341 if (this->m_hasNormals)
343 vertex.normal = this->m_normals[face.
normalIndex[i] - 1];
346 if (uniqueVertices.count(vertex) == 0)
348 uniqueVertices[vertex] =
static_cast<uint32_t
>(m_vertices.size());
349 m_vertices.push_back(vertex);
352 m_indices.push_back(uniqueVertices[vertex]);
Definition: ObjLoader.hpp:95
ObjLoader(const std::string &m_path)
Definition: ObjLoader.hpp:99
const std::vector< uint32_t > & indices() const
Definition: ObjLoader.hpp:114
const std::vector< ObjVertex > & vertices() const
Definition: ObjLoader.hpp:109
Definition: ObjLoader.hpp:65
Definition: ObjLoader.hpp:78
uint32_t normalIndex[3]
Definition: ObjLoader.hpp:81
uint32_t vertexIndex[3]
Definition: ObjLoader.hpp:79
void log() const
Definition: ObjLoader.hpp:83
uint32_t texCoordIndex[3]
Definition: ObjLoader.hpp:80
Definition: ObjLoader.hpp:21
bool operator==(const ObjVertex &other) const
Definition: ObjLoader.hpp:58
static VkVertexInputBindingDescription getBindingDescription()
Definition: ObjLoader.hpp:26
static std::vector< VkVertexInputAttributeDescription > getAttributeDescriptions()
Definition: ObjLoader.hpp:36
glm::vec3 normal
Definition: ObjLoader.hpp:23
glm::vec2 tex_coord
Definition: ObjLoader.hpp:24
glm::vec3 pos
Definition: ObjLoader.hpp:22
size_t operator()(const ObjVertex &vertex) const
Definition: ObjLoader.hpp:68