#include "mesh.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "texture.h"
#include "util_string.h"
int current_material_idx = 0;
int current_texture_idx = 0;
Mesh parse_obj(const char *filename) {
Mesh mesh;
bool obj_has_material = false;
FILE *file = fopen(filename, "r");
if (!file) {
printf("Failed to open file: %s\n", filename);
return mesh;
}
char line_buffer[1024];
string line = {nullptr, 0};
char base_dir[512];
strcpy(base_dir, filename);
char *last_slash = strrchr(base_dir, '/');
if (last_slash) {
last_slash[1] = '\0';
} else {
base_dir[0] = '\0';
}
while (fgets(line_buffer, sizeof(line_buffer), file)) {
line = string_from_cstr(line_buffer);
string_trim(&line);
if (line.size == 0 || line.str[0] == '#') {
continue;
}
if (string_starts_with(line, "v ")) {
vec3f v;
sscanf(line.str, "v %f %f %f", &v.x, &v.y, &v.z);
mesh.vertices.push_back(v);
} else if (string_starts_with(line, "vt ")) {
vec2f vt;
sscanf(line.str, "vt %f %f", &vt.x, &vt.y);
mesh.texcoords.push_back(vt);
} else if (string_starts_with(line, "vn ")) {
vec3f vn;
sscanf(line.str, "vn %f %f %f", &vn.x, &vn.y, &vn.z);
mesh.normals.push_back(vn);
} else if (string_starts_with(line, "f ")) {
char *face_token = strtok(line.str + 2, " \n\r");
while (face_token) {
Face idx = {0, 0, 0};
int v = 0, vt = 0, vn = 0;
char *slash1 = strchr(face_token, '/');
if (slash1) {
*slash1 = '\0';
v = atoi(face_token);
char *slash2 = strchr(slash1 + 1, '/');
if (slash2) {
*slash2 = '\0';
vt = atoi(slash1 + 1);
vn = atoi(slash2 + 1);
} else {
vt = atoi(slash1 + 1);
}
} else {
v = atoi(face_token);
}
if (v > 0) idx.vertex_idx = v - 1;
if (vt > 0) idx.vertex_texture_idx = vt - 1;
if (vn > 0) idx.vertex_normal_idx = vn - 1;
if (obj_has_material) {
idx.mat_idx = current_material_idx;
} else {
idx.mat_idx = 0;
}
mesh.faces.push_back(idx);
face_token = strtok(nullptr, " \n\r");
}
} else if (string_starts_with(line, "mtllib ")) {
obj_has_material = true;
char mtlfile[256];
sscanf(line.str + 7, "%255s", mtlfile);
char mtlpath[512];
strcpy(mtlpath, base_dir);
strcat(mtlpath, mtlfile);
FILE *mtl = fopen(mtlpath, "r");
if (!mtl) {
printf("Failed to open MTL: %s\n", mtlpath);
continue;
}
Material current = {};
char mtl_line[512];
while (fgets(mtl_line, sizeof(mtl_line), mtl)) {
string mline = string_from_cstr(mtl_line);
string_trim(&mline);
if (string_starts_with(mline, "newmtl ")) {
if (current.name[0] != '\0') {
materials.push_back(current);
}
memset(¤t, 0, sizeof(Material));
sscanf(mline.str + 7, "%127s", current.name);
} else if (string_starts_with(mline, "Ka ")) {
sscanf(mline.str + 3, "%f %f %f", ¤t.ambient.x, ¤t.ambient.y, ¤t.ambient.z);
} else if (string_starts_with(mline, "Kd ")) {
sscanf(mline.str + 3, "%f %f %f", ¤t.diffuse.x, ¤t.diffuse.y, ¤t.diffuse.z);
} else if (string_starts_with(mline, "Ks ")) {
sscanf(mline.str + 3, "%f %f %f", ¤t.specular.x, ¤t.specular.y, ¤t.specular.z);
} else if (string_starts_with(mline, "map_Kd ")) {
char texfile[256];
sscanf(mline.str + 7, "%255s", texfile);
char fulltex[512];
strcpy(fulltex, base_dir);
strcat(fulltex, texfile);
Texture t = load_texture(fulltex);
textures.push_back(t);
current.texture_img_idx = (int)textures.size() - 1;
strcpy(current.texture_path, fulltex);
}
}
if (current.name[0] != '\0') {
materials.push_back(current);
}
fclose(mtl);
} else if (string_starts_with(line, "usemtl ")) {
obj_has_material = true;
char matname[128];
sscanf(line.str + 7, "%127s", matname);
for (int i = 0; i < materials.size(); i++) {
if (strcmp(materials[i].name, matname) == 0) {
current_material_idx = i;
break;
}
}
}
}
fclose(file);
return mesh;
}