summaryrefslogtreecommitdiff
path: root/source/model.h
diff options
context:
space:
mode:
authortalha <talha@talhaamir.xyz>2024-04-25 03:19:05 +0500
committertalha <talha@talhaamir.xyz>2024-04-25 03:19:05 +0500
commit708b6e523d7f57f4eb4eb8395530be9ddf67986a (patch)
tree43c3f028683524f3f09f5c166a5508866b772fe9 /source/model.h
parentca2835943ca4327ad08b54af480e0c6333df201f (diff)
Added freetype, started refactoring
Diffstat (limited to 'source/model.h')
-rw-r--r--source/model.h370
1 files changed, 370 insertions, 0 deletions
diff --git a/source/model.h b/source/model.h
new file mode 100644
index 0000000..2f281b1
--- /dev/null
+++ b/source/model.h
@@ -0,0 +1,370 @@
+#pragma once
+
+#include <assimp/Importer.hpp>
+#include <assimp/scene.h>
+#include <assimp/postprocess.h>
+
+// =================== 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 <vector>
+
+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<Vertex> vertices;
+ std::vector<u32> indices;
+ std::vector<Texture> textures;
+
+ u32 vao;
+ u32 vbo;
+ u32 ebo;
+
+ Mesh(std::vector<Vertex> vertices, std::vector<u32> indices, std::vector<Texture> 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<textures.size(); i++)
+ {
+ struct Texture curr_tex = textures[i];
+ if (curr_tex.type == TextureDiffuse)
+ {
+ sprintf(tex_unit_name, "material.diffuse[%i]", diffuse_num);
+ }
+ else if (curr_tex.type == TextureSpecular)
+ {
+ sprintf(tex_unit_name, "material.diffuse[%i]", specular_num);
+ }
+
+ glActiveTexture(GL_TEXTURE0 + i);
+ s32 tex_unit_loc = glGetUniformLocation(shader_program, tex_unit_name);
+ glUniform1i(tex_unit_loc, i);
+ glBindTexture(GL_TEXTURE_2D, curr_tex.id);
+ }
+ glActiveTexture(GL_TEXTURE0);
+
+ glBindVertexArray(vao);
+ glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, 0);
+ glBindVertexArray(0);
+ }
+
+ void draw_instanced(u32 shader_program, u32 instance_count)
+ {
+ 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<textures.size(); i++)
+ {
+ struct Texture curr_tex = textures[i];
+ if (curr_tex.type == TextureDiffuse)
+ {
+ sprintf(tex_unit_name, "material.diffuse[%i]", diffuse_num);
+ }
+ else if (curr_tex.type == TextureSpecular)
+ {
+ sprintf(tex_unit_name, "material.diffuse[%i]", specular_num);
+ }
+
+ glActiveTexture(GL_TEXTURE0 + i);
+ s32 tex_unit_loc = glGetUniformLocation(shader_program, tex_unit_name);
+ glUniform1i(tex_unit_loc, i);
+ glBindTexture(GL_TEXTURE_2D, curr_tex.id);
+ }
+ glActiveTexture(GL_TEXTURE0);
+
+ glBindVertexArray(vao);
+ glDrawElementsInstanced(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, 0, instance_count);
+ glBindVertexArray(0);
+ }
+};
+
+class Model
+{
+ public:
+ std::vector<Texture> loaded_textures;
+ std::vector<Mesh> 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<Texture> 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; i<node->mNumChildren; i++)
+ {
+ process_node(node->mChildren[i], scene);
+ }
+}
+
+Mesh Model::process_mesh(aiMesh *mesh, const aiScene *scene)
+{
+ std::vector<Vertex> vertices;
+ std::vector<u32> indices;
+ std::vector<Texture> 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<Texture> diffuse_maps = load_material_textures(material, aiTextureType_DIFFUSE, TextureDiffuse);
+ textures.insert(textures.end(), diffuse_maps.begin(), diffuse_maps.end());
+ std::vector<Texture> 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<Texture> Model::load_material_textures(aiMaterial *mat, aiTextureType type, TextureType tex_type)
+{
+ std::vector<Texture> textures;
+ for(u32 i=0; i<mat->GetTextureCount(type); i++)
+ {
+ bool load_texture = true;
+ aiString str;
+ mat->GetTexture(type, i, &str);
+ const char* fname = str.C_Str();
+
+ for (s32 j=0; j<loaded_textures.size(); j++)
+ {
+ if (std::strcmp(loaded_textures[j].fname.data(), fname) == 0)
+ {
+ load_texture = false;
+ textures.push_back(loaded_textures[j]);
+ break;
+ }
+ }
+ if (load_texture)
+ {
+ Texture texture;
+ texture.id = TextureFromFile(fname, directory);
+ texture.type = tex_type;
+ texture.fname = std::string(fname);
+ textures.push_back(texture);
+ loaded_textures.push_back(texture);
+ }
+ }
+
+ return textures;
+}