// // Created by lbmas on 4/29/2026. // #include #include "ModelLoader.h" #include #include #include #include #include "glm/ext/matrix_transform.hpp" std::unordered_map> ModelLoader::models; Mesh process_ai_mesh(aiMesh* aiMesh); void process_ai_node(aiNode* node, const aiScene* scene, Model* model); 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_GenNormals | aiProcess_FlipUVs); 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(); process_ai_node(scene->mRootNode, scene, model.get()); return model; } void process_ai_node(aiNode* node, const aiScene* scene, glm::mat4 transform, Model* model) { auto t = node->mTransformation; transform = transform * glm::mat4(nTransform) for (unsigned int i = 0; i < node->mNumMeshes; i++) { aiMesh* mesh = scene->mMeshes[node->mMeshes[i]]; model->meshes.push_back(std::make_shared(process_ai_mesh(mesh))); } for (unsigned int i = 0; i < node->mNumChildren; i++) { process_ai_node(node->mChildren[i], scene, model); } } Mesh process_ai_mesh(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(); for (unsigned int i = 0; i < aiMesh->mNumVertices; i++) { auto position = aiMesh->mVertices[i]; positions[3 * i] = position.x; positions[3 * i + 1] = position.y; positions[3 * i + 2] = position.z; if (aiMesh->HasNormals()) { aiVector3D norm = aiMesh->mNormals[i]; normals[3 * i] = norm.x; normals[3 * i + 1] = norm.y; normals[3 * i + 2] = norm.z; } else { normals[3 * i] = 0; normals[3 * i + 1] = 0; normals[3 * i + 2] = 0; } if (aiMesh->HasTextureCoords(0)) { uvs[2 * i] = aiMesh->mTextureCoords[0][i].x; uvs[2 * i + 1] = aiMesh->mTextureCoords[0][i].y; } else { uvs[2 * i] = 0; uvs[2 * i + 1] = 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; }