#include "mesh.h" #include #include #include #include #include namespace fs = std::filesystem; std::map load_mtl_materials(const std::string& mtl_path) { std::map materials; std::ifstream file(mtl_path); if (!file.is_open()) { std::cerr << "Warning: could not open MTL file: " << mtl_path << std::endl; return materials; } std::string line, current_mtl; while (std::getline(file, line)) { std::istringstream ss(line); std::string keyword; ss >> keyword; if (keyword == "newmtl") { ss >> current_mtl; materials[current_mtl] = Material{Color(255, 255, 255), ""}; // Default white, no texture } else if (keyword == "Kd") { float r, g, b; ss >> r >> g >> b; if (materials.count(current_mtl)) { materials[current_mtl].color = Color( static_cast(r * 255), static_cast(g * 255), static_cast(b * 255) ); } } else if (keyword == "map_Kd") { std::string texture_path; ss >> texture_path; if (materials.count(current_mtl)) { materials[current_mtl].texture_path = texture_path; } } } return materials; } std::vector load_obj(const std::string& obj_path, Renderer* renderer) { std::ifstream file(obj_path); if (!file.is_open()) { throw std::runtime_error("Failed to open OBJ file: " + obj_path); } std::vector positions; std::vector texcoords; std::map materials; std::map texture_map; std::vector triangles; std::string current_material = ""; fs::path base_path = fs::path(obj_path).parent_path(); std::string line; while (std::getline(file, line)) { std::istringstream ss(line); std::string keyword; ss >> keyword; if (keyword == "v") { float x, y, z; ss >> x >> y >> z; positions.emplace_back((int)(x * 4096), (int)(y * 4096), (int)(z * 4096)); } else if (keyword == "vt") { float u, v; ss >> u >> v; texcoords.emplace_back(u, 1.0f - v); // flip v } else if (keyword == "f") { std::vector tokens; std::string token; while (ss >> token) tokens.push_back(token); std::vector v_idx, t_idx; for (const auto& t : tokens) { std::stringstream ts(t); std::string part; int vi = -1, ti = -1; std::getline(ts, part, '/'); if (!part.empty()) vi = std::stoi(part) - 1; if (std::getline(ts, part, '/') && !part.empty()) ti = std::stoi(part) - 1; v_idx.push_back(vi); t_idx.push_back(ti); } // Triangulate face for (size_t i = 1; i + 1 < v_idx.size(); ++i) { Triangle tri; tri.v0 = positions[v_idx[0]]; tri.v1 = positions[v_idx[i]]; tri.v2 = positions[v_idx[i + 1]]; tri.uv0 = (t_idx[0] >= 0 && t_idx[0] < (int)texcoords.size()) ? texcoords[t_idx[0]] : Vec2(0, 0); tri.uv1 = (t_idx[i] >= 0 && t_idx[i] < (int)texcoords.size()) ? texcoords[t_idx[i]] : Vec2(0, 0); tri.uv2 = (t_idx[i + 1] >= 0 && t_idx[i + 1] < (int)texcoords.size()) ? texcoords[t_idx[i + 1]] : Vec2(0, 0); if (materials.count(current_material)) { tri.color = materials[current_material].color; tri.texture = texture_map[current_material]; } else { tri.color = Color(255, 255, 255); // Fallback white tri.texture = 0; // No texture } triangles.push_back(tri); } } else if (keyword == "mtllib") { std::string mtl_file; ss >> mtl_file; fs::path mtl_path = base_path / mtl_file; materials = load_mtl_materials(mtl_path.string()); // Load textures for all materials for (const auto& mat_pair : materials) { const std::string& mat_name = mat_pair.first; const Material& mat = mat_pair.second; if (!mat.texture_path.empty()) { fs::path texture_full_path = base_path / mat.texture_path; texture_map[mat_name] = renderer->load_texture(texture_full_path.string()); } else { texture_map[mat_name] = 0; // No texture } } } else if (keyword == "usemtl") { ss >> current_material; } } return triangles; }