// // Created by lbmas on 4/29/2026. // #include #include "ModelLoader.h" #include #include #include #include std::unordered_map> ModelLoader::models; void process_ai_node(aiNode* node, const aiScene* scene, Model* model); Mesh process_ai_mesh(const aiMesh* aiMesh); Material process_ai_material(aiMaterial* mat); std::shared_ptr ModelLoader::load_from_file(std::string_view _path) { Assimp::Importer importer; const aiScene* scene = importer.ReadFile(_path.data(), aiProcess_Triangulate | aiProcess_GenSmoothNormals | aiProcess_FlipUVs | aiProcess_CalcTangentSpace); if (!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode) { spdlog::error("failed to load model {}: {}", _path, importer.GetErrorString()); return nullptr; } auto model = std::make_shared(); model->materials.resize(scene->mNumMaterials); for (unsigned int i = 0; i < scene->mNumMaterials; i++) { aiMaterial* mat = scene->mMaterials[i]; model->materials[i] = std::make_shared(process_ai_material(mat)); } model->meshes.resize(scene->mNumMeshes); for (unsigned int i = 0; i < scene->mNumMeshes; i++) { aiMesh* mesh = scene->mMeshes[i]; model->meshes[i] = std::make_shared(process_ai_mesh(mesh)); } return model; } void process_ai_node(aiNode* node, const aiScene* scene, Model* model) { for (unsigned int i = 0; i < node->mNumChildren; i++) { } } Mesh process_ai_mesh(const aiMesh* aiMesh) { auto positions = std::vector(aiMesh->mNumVertices * 3); auto uvs = std::vector(aiMesh->mNumVertices * 2); auto normals = std::vector(aiMesh->mNumVertices * 3); auto indices = std::vector(aiMesh->mNumFaces * 3); for (unsigned int i = 0; i < aiMesh->mNumVertices; i++) { auto position = aiMesh->mVertices[i]; positions.push_back(position.x); positions.push_back(position.y); positions.push_back(position.z); if (aiMesh->HasNormals()) { normals.push_back(aiMesh->mNormals[i].x); normals.push_back(aiMesh->mNormals[i].y); normals.push_back(aiMesh->mNormals[i].z); } else { normals.push_back(0); normals.push_back(0); normals.push_back(0); } if (aiMesh->HasTextureCoords(0)) { uvs.push_back(aiMesh->mTextureCoords[0][i].x); uvs.push_back(aiMesh->mTextureCoords[0][i].y); } else { uvs.push_back(0); uvs.push_back(0); } } for(unsigned int i = 0; i < aiMesh->mNumFaces; i++) { const aiFace face = aiMesh->mFaces[i]; for(unsigned int j = 0; j < face.mNumIndices; j++) indices.push_back(face.mIndices[j]); } return {positions, uvs, normals, indices}; } Material process_ai_material(aiMaterial *mat) { aiString matName; aiReturn ret = mat->Get(AI_MATKEY_NAME, matName); if (ret != AI_SUCCESS) { spdlog::error("Could not find material name"); } aiColor3D ambientColor {0.f, 0.f, 0.f}; ret = mat->Get(AI_MATKEY_COLOR_DIFFUSE, ambientColor); if (ret != AI_SUCCESS) { spdlog::error("Could not find ambient color for material: {}", matName.C_Str()); ambientColor = {.3f, .3f, .3f}; } aiColor3D diffuseColor {1.f, 1.f, 1.f}; ret = mat->Get(AI_MATKEY_COLOR_DIFFUSE, diffuseColor); if (ret != AI_SUCCESS) { spdlog::error("Could not find diffuse color for material: {}", matName.C_Str()); diffuseColor = {1.f, 1.f, 1.f}; } aiColor3D specularColor {1.f, 1.f, 1.f}; ret = mat->Get(AI_MATKEY_COLOR_SPECULAR, specularColor); if (ret != AI_SUCCESS) { spdlog::error("Could not find specular color for material: {}", matName.C_Str()); specularColor = {1.f, 1.f, 1.f}; } float shininess = 32.f; ret = mat->Get(AI_MATKEY_SHININESS, shininess); if (ret != AI_SUCCESS) { spdlog::error("Could not find shininess for material: {}", matName.C_Str()); shininess = 32.f; } Material material; material.name = matName.C_Str(); material.phong.ambient = glm::vec3{ambientColor.r, ambientColor.g, ambientColor.b}; material.phong.diffuse = glm::vec3{diffuseColor.r, diffuseColor.g, diffuseColor.b}; material.phong.specular = glm::vec3{specularColor.r, specularColor.g, specularColor.b}; material.phong.shininess = shininess; return material; }