#pragma once #include #include #include // =================== Model Loading ======================== // Piss Poor Model Loading // This section contains a whole host of things: // 1. classes // 2. std::vectors // 3. std::strings // that I have only used as a glue for I did not know if I had the model loading setup properly. // @todo: replace these things eventually. For now the goal is to complete learnopengl #include s32 TextureFromFile(const char* filepath, std::string directory) { // @note: this function is stupid as it already became outdated as I needed to tweak the parameters // for wrapping. Either those become function parameters (Which makes sense I guess) or I look at // exactly what steps I am reusing and just make that a function so the function is called fewer times. // // I am guessing this won't look good from a design point of view for all those jobs and postings, even if // this may be the simpler and faster thing to do, albeit at the cost of typing. std::string filename = std::string(filepath); filename = directory + '/' + filename; u32 texid; glGenTextures(1, &texid); s32 width, height, nrChannels; unsigned char *data = stbi_load(filename.c_str(), &width, &height, &nrChannels, 0); if (data) { GLenum format; if (nrChannels == 1) format = GL_RED; else if (nrChannels == 3) format = GL_RGB; else if (nrChannels == 4) format = GL_RGBA; glBindTexture(GL_TEXTURE_2D, texid); glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data); glGenerateMipmap(GL_TEXTURE_2D); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); stbi_image_free(data); } else { printf("failed to load image texture at path: %s", filepath); stbi_image_free(data); } return texid; } enum TextureType { TextureDiffuse=0, TextureSpecular }; struct Vertex { Vec3 position; Vec3 normal; Vec2 texture; }; struct Texture { u32 id; enum TextureType type; std::string fname; }; class Mesh { public: std::vector vertices; std::vector indices; std::vector textures; u32 vao; u32 vbo; u32 ebo; Mesh(std::vector vertices, std::vector indices, std::vector textures) { this->vertices = vertices; this->indices = indices; this->textures = textures; // setup mesh shader stuff glGenVertexArrays(1, &vao); glGenBuffers(1, &vbo); glGenBuffers(1, &ebo); glBindVertexArray(vao); glBindBuffer(GL_ARRAY_BUFFER, vbo); glBufferData(GL_ARRAY_BUFFER, this->vertices.size() * sizeof(struct Vertex), &(this->vertices[0]), GL_STATIC_DRAW); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo); glBufferData(GL_ELEMENT_ARRAY_BUFFER, this->indices.size() * sizeof(u32), &(this->indices[0]), GL_STATIC_DRAW); // position glEnableVertexAttribArray(0); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)0); // normal glEnableVertexAttribArray(1); glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, normal)); // texture glEnableVertexAttribArray(2); glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, texture)); glBindVertexArray(0); } void draw(u32 shader_program) { glUseProgram(shader_program); u32 diffuse_num = 1; u32 specular_num = 1; char tex_unit_name[64]; // set shininess s32 mat_shine_loc = glGetUniformLocation(shader_program, "material.shininess"); glUniform1f(mat_shine_loc, 32.0f); for (u32 i=0; i loaded_textures; std::vector meshes; std::string directory; Model(std::string path) { load_model(path); } void instance_mesh(); void draw(u32 shader_program); void draw_instanced(u32 shader_program, u32 instance_count); private: void load_model(std::string path); void process_node(aiNode *node, const aiScene *scene); Mesh process_mesh(aiMesh *mesh, const aiScene *scene); std::vector load_material_textures(aiMaterial *mat, aiTextureType type, TextureType type_name); }; void Model::instance_mesh() { for (u32 i=0; i < meshes.size(); i++) { Mesh curr_mesh = meshes[i]; glBindVertexArray(curr_mesh.vao); glVertexAttribPointer(3, 4, GL_FLOAT, GL_FALSE, 16 * sizeof(u32), (void*)0); glEnableVertexAttribArray(3); glVertexAttribPointer(4, 4, GL_FLOAT, GL_FALSE, 16 * sizeof(u32), (void*)(4*sizeof(u32))); glEnableVertexAttribArray(4); glVertexAttribPointer(5, 4, GL_FLOAT, GL_FALSE, 16 * sizeof(u32), (void*)(8*sizeof(u32))); glEnableVertexAttribArray(5); glVertexAttribPointer(6, 4, GL_FLOAT, GL_FALSE, 16 * sizeof(u32), (void*)(12*sizeof(u32))); glEnableVertexAttribArray(6); glBindBuffer(GL_ARRAY_BUFFER, 0); glVertexAttribDivisor(3, 1);123 glVertexAttribDivisor(4, 1); glVertexAttribDivisor(5, 1); glVertexAttribDivisor(6, 1); glBindVertexArray(0); } } void Model::draw(u32 shader_program) { for (int i=0; i < meshes.size(); i++) { meshes[i].draw(shader_program); } } void Model::draw_instanced(u32 shader_program, u32 instance_count) { for (int i=0; i < meshes.size(); i++) { meshes[i].draw_instanced(shader_program, instance_count); } } void Model::load_model(std::string path) { Assimp::Importer import; const aiScene *scene = import.ReadFile(path, aiProcess_Triangulate | aiProcess_FlipUVs); if (!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode) { printf("error loading model :%s\n", import.GetErrorString()); return; } directory = path.substr(0, path.find_last_of('/')); process_node(scene->mRootNode, scene); } void Model::process_node(aiNode *node, const aiScene *scene) { for (int i=0; i < node->mNumMeshes; i++) { aiMesh *mesh = scene->mMeshes[node->mMeshes[i]]; meshes.push_back(process_mesh(mesh, scene)); } for (int i=0; imNumChildren; i++) { process_node(node->mChildren[i], scene); } } Mesh Model::process_mesh(aiMesh *mesh, const aiScene *scene) { std::vector vertices; std::vector indices; std::vector textures; for (u32 i=0; i < mesh->mNumVertices; i++) { Vec3 position; position.x = mesh->mVertices[i].x; position.y = mesh->mVertices[i].y; position.z = mesh->mVertices[i].z; Vec3 normal; normal.x = mesh->mNormals[i].x; normal.y = mesh->mNormals[i].y; normal.z = mesh->mNormals[i].z; Vec2 texture = {0, 0}; if (mesh->mTextureCoords[0]) { texture.x = mesh->mTextureCoords[0][i].x; texture.y = mesh->mTextureCoords[0][i].y; } struct Vertex vertex; vertex.position = position; vertex.normal = normal; vertex.texture = texture; vertices.push_back(vertex); } // process indices for (u32 i = 0; i < mesh->mNumFaces; i++) { aiFace face = mesh->mFaces[i]; for(u32 j = 0; j < face.mNumIndices; j++) { indices.push_back(face.mIndices[j]); } } // process material if (mesh->mMaterialIndex >= 0) { aiMaterial *material = scene->mMaterials[mesh->mMaterialIndex]; std::vector diffuse_maps = load_material_textures(material, aiTextureType_DIFFUSE, TextureDiffuse); textures.insert(textures.end(), diffuse_maps.begin(), diffuse_maps.end()); std::vector specular_maps = load_material_textures(material, aiTextureType_SPECULAR, TextureSpecular); textures.insert(textures.end(), specular_maps.begin(), specular_maps.end()); } return Mesh(vertices, indices, textures); } std::vector Model::load_material_textures(aiMaterial *mat, aiTextureType type, TextureType tex_type) { std::vector textures; for(u32 i=0; iGetTextureCount(type); i++) { bool load_texture = true; aiString str; mat->GetTexture(type, i, &str); const char* fname = str.C_Str(); for (s32 j=0; j