scop
a small 3D object loader
Loading...
Searching...
No Matches
Parsing.cpp
Go to the documentation of this file.
1/* ************************************************************************** */
2/* */
3/* ::: :::::::: */
4/* Parsing.cpp :+: :+: :+: */
5/* +:+ +:+ +:+ */
6/* By: rbourgea <rbourgea@student.42.fr> +#+ +:+ +#+ */
7/* +#+#+#+#+#+ +#+ */
8/* Created: 2024/01/11 07:50:09 by rbourgea #+# #+# */
9/* Updated: 2024/04/09 14:54:24 by rbourgea ### ########.fr */
10/* */
11/* ************************************************************************** */
12
13#include "VulkanApp.hpp"
14
15void VulkanApp::parseObjFile(const std::string& filename) {
16 std::ifstream file(filename);
17 if (!file.is_open()) {
18 std::cerr << "Error opening file: " << filename << std::endl;
19 std::exit(EXIT_FAILURE);
20 }
21
22 std::string mtlFilename;
23 std::vector<vec3> positions;
24 std::vector<vec2> texCoords;
25 std::vector<vec3> colors;
26 std::string line;
27 std::string currentMaterial;
28
29 float minX = std::numeric_limits<float>::max(), maxX = std::numeric_limits<float>::lowest();
30 float minY = std::numeric_limits<float>::max(), maxY = std::numeric_limits<float>::lowest();
31 float minZ = std::numeric_limits<float>::max(), maxZ = std::numeric_limits<float>::lowest();
32
33 while (std::getline(file, line)) {
34 std::istringstream iss(line);
35 std::string type;
36 if (!(iss >> type))
37 continue;
38
39 if (iss.eof()) {
40 std::cerr << "Error: Empty " << type << " line in file: " << filename << std::endl;
41 std::exit(EXIT_FAILURE);
42 }
43
44 if (type == "mtllib") {
45 iss >> mtlFilename;
46 } else if (type == "usemtl") {
47 iss >> currentMaterial;
48 } else if (type == "v") {
49 float x, y, z;
50 if (!(iss >> x >> y >> z)) {
51 std::cerr << "Error: Bad " << type << " line in file: " << filename << std::endl;
52 std::exit(EXIT_FAILURE);
53 }
54 vec3 pos(x, y, z);
55 positions.push_back(pos);
56
57 minX = std::min(x, minX);
58 minY = std::min(y, minY);
59 minZ = std::min(z, minZ);
60
61 maxX = std::max(x, maxX);
62 maxY = std::max(y, maxY);
63 maxZ = std::max(z, maxZ);
64 } else if (type == "vt") {
65 float u, v;
66 if (!(iss >> u >> v)) {
67 std::cerr << "Error: Bad " << type << " line in file: " << filename << std::endl;
68 std::exit(EXIT_FAILURE);
69 }
70 texCoords.push_back(vec2(u, v));
71 } else if (type == "vc") {
72 float r, g, b;
73 if (!(iss >> r >> g >> b)) {
74 std::cerr << "Error: Bad " << type << " line in file: " << filename << std::endl;
75 std::exit(EXIT_FAILURE);
76 }
77 colors.push_back(vec3(r, g, b));
78 } else if (type == "f") {
79 std::vector<int> vertexIndices;
80 std::vector<int> texCoordIndices;
81
82 std::string vertexData;
83 while (iss >> vertexData) {
84 std::istringstream vertexDataStream(vertexData);
85 std::string index;
86 int i = 0;
87 while (std::getline(vertexDataStream, index, '/')) {
88 if (i == 0 && !index.empty()) {
89 vertexIndices.push_back(std::stoi(index) - 1);
90 } else if (i == 1 && !index.empty()) {
91 texCoordIndices.push_back(std::stoi(index) - 1);
92 }
93 i++;
94 }
95 }
96
97 if (vertexIndices.size() < 3) {
98 std::cerr << "Error: Bad " << type << " line in file: " << filename << std::endl;
99 std::exit(EXIT_FAILURE);
100 }
101
102 for (size_t j = 0; j < vertexIndices.size() - 2; ++j) {
103 std::vector<int> triangleIndices = {0, static_cast<int>(j + 1), static_cast<int>(j + 2)};
104
105 for (int index : triangleIndices) {
106 Vertex vertex;
107
108 if (positions.empty())
109 continue;
110
111 vertex.pos = positions[vertexIndices[index]];
112
113 if (!texCoords.empty()) {
114 vertex.texCoord = texCoords[texCoordIndices[index]];
115 } else {
116 vertex.texCoord = vec2((vertex.pos.x - minX) / (maxX - minX), 1.0f - ((vertex.pos.y - minY) / (maxY - minY)));
117 }
118
119 if (!colors.empty()) {
120 vertex.color = colors[vertexIndices[index]];
121 } else {
122 vertex.color = vec3(0.65, 0.65, 0.65);
123 }
124
125 vertex.ambientColor = vec3(1, 1, 1);
126 vertex.dissolveFactor = 1;
127 vertex.material_name = currentMaterial;
128
129 vertices.push_back(vertex);
130 indices.push_back(static_cast<uint16_t>(vertices.size() - 1));
131 }
132 }
133 }
134 }
135
136 modelCentroid = vec3((minX + maxX) / 2.f, (minY + maxY) / 2.f, (minZ + maxZ) / 2.f);
137
138 if (!mtlFilename.empty()) {
139 parseMtlFile(filename, mtlFilename);
140 }
141
142 // // Print vertices
143 // for (const auto& vertex : vertices) {
144 // std::cout << "Position : " << "(" << vertex.pos.x << ", " << vertex.pos.y << ", " << vertex.pos.z << ")" << std::endl;
145 // std::cout << "TexCoord : " << "(" << vertex.texCoord.x << ", " << vertex.texCoord.y << ")" << std::endl;
146 // std::cout << "Color : " << "(" << vertex.color.x << ", " << vertex.color.y << ", " << vertex.color.z << ")" << std::endl;
147 // std::cout << "AmbientColor : " << "(" << vertex.ambientColor.x << ", " << vertex.ambientColor.y << ", " << vertex.ambientColor.z << ")" << std::endl;
148 // std::cout << "DissolveFactor: " << vertex.dissolveFactor << std::endl;
149 // std::cout << "<==========>" << std::endl;
150 // }
151
152 // // Print indices
153 // std::cout << "Indices:" << std::endl;
154 // for (const auto& index : indices) {
155 // std::cout << index << " ";
156 // }
157 // std::cout << std::endl;
158
159 file.close();
160
161 if (positions.empty()) {
162 std::cerr << "Error: The OBJ file does not contain vertex." << std::endl;
163 std::exit(EXIT_FAILURE);
164 }
165
166 if (indices.empty()) {
167 std::cerr << "Error: The OBJ file does not contain face." << std::endl;
168 std::exit(EXIT_FAILURE);
169 }
170}
171
172void VulkanApp::parseMtlFile(const std::string& objFilePath, const std::string& mtlFilename) {
173 std::filesystem::path objPath(objFilePath);
174 std::filesystem::path mtlPath = objPath.parent_path() / mtlFilename;
175
176 std::ifstream file(mtlPath);
177 if (!file.is_open()) {
178 std::cout << "Warning: MTL file not found: " << mtlPath << std::endl;
179 return;
180 }
181
182 std::string line;
183
184 std::unordered_map<std::string, Material> materials;
185 auto mat = materials.end();
186
187 while (std::getline(file, line)) {
188 std::istringstream iss(line);
189 std::string type;
190 iss >> type;
191
192 if (type == "newmtl") {
193 std::string name;
194 iss >> name;
195
196 auto [it, mode] = materials.insert_or_assign(name, Material{});
197 mat = it;
198 if (!mode) {
199 std::clog << "Warning: replaced old material " << name << std::endl;
200 }
201 } else if (type == "Ka") {
202 if (mat == materials.end()) {
203 std::cerr << "Error: Material not defined before " << type << " in file: " << mtlFilename << std::endl;
204 std::exit(EXIT_FAILURE);
205 }
206 if (!(iss >> mat->second.ambient.x >> mat->second.ambient.y >> mat->second.ambient.z)) {
207 std::cerr << "Error: Bad " << type << " line in file: " << mtlFilename << std::endl;
208 std::exit(EXIT_FAILURE);
209 }
210 } else if (type == "Kd") {
211 if (mat == materials.end()) {
212 std::cerr << "Error: Material not defined before " << type << " in file: " << mtlFilename << std::endl;
213 std::exit(EXIT_FAILURE);
214 }
215 if (!(iss >> mat->second.diffuse.x >> mat->second.diffuse.y >> mat->second.diffuse.z)) {
216 std::cerr << "Error: Bad " << type << " line in file: " << mtlFilename << std::endl;
217 std::exit(EXIT_FAILURE);
218 }
219 } else if (type == "Ks") {
220 if (mat == materials.end()) {
221 std::cerr << "Error: Material not defined before " << type << " in file: " << mtlFilename << std::endl;
222 std::exit(EXIT_FAILURE);
223 }
224 if (!(iss >> mat->second.specular.x >> mat->second.specular.y >> mat->second.specular.z)) {
225 std::cerr << "Error: Bad " << type << " line in file: " << mtlFilename << std::endl;
226 std::exit(EXIT_FAILURE);
227 }
228 } else if (type == "d") {
229 if (mat == materials.end()) {
230 std::cerr << "Error: Material not defined before " << type << " in file: " << mtlFilename << std::endl;
231 std::exit(EXIT_FAILURE);
232 }
233 if (!(iss >> mat->second.dissolve)) {
234 std::cerr << "Error: Bad " << type << " line in file: " << mtlFilename << std::endl;
235 std::exit(EXIT_FAILURE);
236 }
237 }
238 // TODO: add more material properties
239 }
240
241 if (mat == materials.end()) {
242 return;
243 }
244 for (auto& vertex : vertices) {
245 if (!vertex.material_name.empty()) {
246 try {
247 const auto&[ambient, diffuse, specular, dissolve] = materials.at(vertex.material_name);
248
249 vertex.color = diffuse;
250 vertex.ambientColor = ambient;
251 vertex.specularColor = specular;
252 vertex.dissolveFactor = dissolve;
253 } catch (const std::out_of_range&) {}
254 }
255 }
256}
257
258std::vector<char> VulkanApp::readFile(const std::string& filename) {
259 std::ifstream file(filename, std::ios::ate | std::ios::binary);
260
261 if (!file.is_open()) {
262 std::cerr << "Error opening file: " << filename << std::endl;
263 std::exit(EXIT_FAILURE);
264 }
265
266 size_t fileSize = (size_t) file.tellg();
267 std::vector<char> buffer(fileSize);
268
269 file.seekg(0);
270 file.read(buffer.data(), fileSize);
271
272 file.close();
273
274 return buffer;
275}
static std::vector< char > readFile(const std::string &filename)
Definition Parsing.cpp:258
std::vector< uint32_t > indices
vec3 modelCentroid
void parseMtlFile(const std::string &objFilePath, const std::string &mtlFilename)
Definition Parsing.cpp:172
void parseObjFile(const std::string &filename)
Definition Parsing.cpp:15
std::vector< Vertex > vertices
Definition Math.hpp:19
Definition Math.hpp:65
float x
Definition Math.hpp:67
float y
Definition Math.hpp:67
vec3 color
Definition VulkanApp.hpp:97
vec3 ambientColor
Definition VulkanApp.hpp:99
vec2 texCoord
Definition VulkanApp.hpp:98
float dissolveFactor
std::string material_name
vec3 pos
Definition VulkanApp.hpp:96