#include #include #include #include #include #include #include #include #include #include #include "mesh.hpp" #include "arrays.hpp" #include "texture.hpp" #include "../../util/streams.hpp" using namespace Sim::Graphics; struct ProcState { unsigned int offset = 0; std::string base; std::vector lights; std::vector vertices; std::vector indices; std::unordered_map handles; std::unordered_map mat_nodes; }; static unsigned int proc_texture(const ProcState& state, aiMaterial* mat, const aiScene* scene, aiTextureType type, int index) { aiString str; mat->GetTexture(type, index, &str); if(str.C_Str()[0] == '\0') { return 0; } const aiTexture* tex = scene->GetEmbeddedTexture(str.C_Str()); if(tex != nullptr) { unsigned int handle = state.handles.find(tex)->second; std::cout << "Using preloaded texture: " << tex->mFilename.C_Str() << "\n"; return handle; } std::string filename(str.C_Str()); std::replace(filename.begin(), filename.end(), '\\', '/'); return Texture::load(state.base + "/" + filename); } static void proc_mesh(ProcState& state, glm::mat4 mat, aiMesh* mesh, const aiScene* scene) { aiMaterial* material = scene->mMaterials[mesh->mMaterialIndex]; aiString name; material->Get(AI_MATKEY_NAME, name); std::cout << "Material " << name.C_Str() << " has " << material->mNumProperties << " properties\n"; for(int i = 0; i < material->mNumProperties; i++) { aiMaterialProperty* prop = material->mProperties[i]; std::cout << " " << prop->mKey.C_Str() << ": type=" << prop->mType << " index=" << prop->mIndex << " length=" << prop->mDataLength; if(prop->mType == 1) { float* v = (float*)prop->mData; std::cout << " value="; switch(prop->mDataLength) { case 4: std::cout << v[0]; break; case 8: std::cout << "{" << v[0] << ", " << v[1] << "}"; break; case 12: std::cout << "{" << v[0] << ", " << v[1] << ", " << v[2] << "}"; break; case 16: std::cout << "{" << v[0] << ", " << v[1] << ", " << v[2] << ", " << v[3] << "}"; break; default: std::cout << "unknown"; } } std::cout << "\n"; } glm::vec3 matv(0); aiColor4D ai_cb; aiColor4D ai_em; material->Get(AI_MATKEY_ROUGHNESS_FACTOR, matv[0]); material->Get(AI_MATKEY_METALLIC_FACTOR, matv[1]); material->Get(AI_MATKEY_EMISSIVE_INTENSITY, matv[2]); material->Get(AI_MATKEY_COLOR_EMISSIVE, ai_em); material->Get(AI_MATKEY_BASE_COLOR, ai_cb); glm::vec4 cb = {ai_cb[0], ai_cb[1], ai_cb[2], ai_cb[3]}; glm::vec4 em = {ai_em[0], ai_em[1], ai_em[2], ai_em[3]}; if(em.x > 0 || em.y > 0 || em.z > 0) { cb = em; } std::cout << "Material: " << matv << "\n"; unsigned int handle = proc_texture(state, material, scene, aiTextureType_BASE_COLOR, 0); unsigned int offset = state.offset; glm::mat3 mat3(mat); if(!handle) { handle = proc_texture(state, material, scene, aiTextureType_DIFFUSE, 0); } if(!handle) { handle = Texture::handle_white; } for(unsigned int i = 0; i < mesh->mNumVertices; i++) { Arrays::Vertex vertex; auto [x, y, z] = mesh->mVertices[i]; vertex.pos = glm::vec4(x, y, z, 1) * mat; vertex.material = matv; vertex.texid = handle; vertex.colour = cb; if(mesh->HasNormals()) { auto [x, y, z] = mesh->mNormals[i]; vertex.normal = glm::vec3(x, y, z) * mat3; } /*if(mesh->HasTangentsAndBitangents()) { auto [x1, y1, z1] = mesh->mTangents[i]; auto [x2, y2, z2] = mesh->mBitangents[i]; vertex.tangent = {x1, y1, z1}; vertex.bitangent = {x2, y2, z2}; }*/ if(mesh->mTextureCoords[0]) { auto [x, y, z] = mesh->mTextureCoords[0][i]; vertex.texpos = {x, y}; } state.vertices.push_back(vertex); } for(unsigned int i = 0; i < mesh->mNumFaces; i++) { aiFace face = mesh->mFaces[i]; for(unsigned int j = 0; j < face.mNumIndices; j++) { state.indices.push_back(face.mIndices[j] + offset); } } state.offset += mesh->mNumVertices; } glm::mat4 get_mat(aiMatrix4x4 m) { return { m.a1, m.a2, m.a3, m.a4, m.b1, m.b2, m.b3, m.b4, m.c1, m.c2, m.c3, m.c4, m.d1, m.d2, m.d3, m.d4 }; } static void proc_node(ProcState& state, glm::mat4 mat, aiNode* node, const aiScene* scene) { mat = get_mat(node->mTransformation) * mat; std::string name(node->mName.C_Str()); state.mat_nodes[name] = mat; for(size_t i = 0; i < node->mNumMeshes; i++) { aiMesh* mesh = scene->mMeshes[node->mMeshes[i]]; proc_mesh(state, mat, mesh, scene); } for(size_t i = 0; i < node->mNumChildren; i++) { proc_node(state, mat, node->mChildren[i], scene); } } static unsigned int proc_embedded_texture(aiTexture* tex) { std::cout << "Loading embedded data: " << tex->mFilename.C_Str() << "\n"; if(tex->mHeight == 0) { return Texture::load_mem((unsigned char*)tex->pcData, tex->mWidth); } // swizzle each pixel to get RGBA for(int i = 0; i < tex->mWidth * tex->mHeight; i++) { aiTexel t = tex->pcData[i]; tex->pcData[i] = {t.r, t.g, t.b, t.a}; } return Texture::load_mem((unsigned char*)tex->pcData, tex->mWidth, tex->mHeight, 4); } glm::mat4 get_transforms(aiNode* node) { glm::mat4 mat(1); while(node->mParent != nullptr) { mat *= get_mat(node->mTransformation); node = node->mParent; } return mat; } void Mesh::load_model(std::string path) { load_model(".", path); } void Mesh::load_model(std::string base, std::string filename) { ProcState state {.base = base}; std::string path = base + "/" + filename; Assimp::Importer importer; const aiScene *scene = importer.ReadFile(path.c_str(), aiProcess_Triangulate | aiProcess_FlipUVs); if(scene == nullptr) { std::cerr << "AssImp: Error loading model\n"; return; } for(int i = 0; i < scene->mNumTextures; i++) { aiTexture* tex = scene->mTextures[i]; unsigned int handle = proc_embedded_texture(tex); state.handles[tex] = handle; } for(int i = 0; i < scene->mNumLights; i++) { aiLight* light = scene->mLights[i]; glm::mat4 mat = get_transforms(scene->mRootNode->FindNode(light->mName)); auto [x, y, z] = light->mPosition; auto [r, g, b] = light->mColorDiffuse; glm::vec4 pos = glm::vec4(x, y, z, 1) * mat; state.lights.push_back({ glm::vec3(pos), {r, g, b}, }); } proc_node(state, glm::mat4(1), scene->mRootNode, scene); mat_nodes = std::move(state.mat_nodes); vertices = std::move(state.vertices); indices = std::move(state.indices); lights = std::move(state.lights); }