diff --git a/examples/dev_testing/resources/.gitignore b/examples/dev_testing/resources/.gitignore index e687263..cad6e74 100644 --- a/examples/dev_testing/resources/.gitignore +++ b/examples/dev_testing/resources/.gitignore @@ -1,5 +1,2 @@ -*.blend -*.obj -*.png -*.bin -*.gltf \ No newline at end of file +* +!shaders \ No newline at end of file diff --git a/examples/dev_testing/src/main.cpp b/examples/dev_testing/src/main.cpp index d58be80..d5f840d 100644 --- a/examples/dev_testing/src/main.cpp +++ b/examples/dev_testing/src/main.cpp @@ -1,4 +1,3 @@ -#include "entt/entity/fwd.hpp" #include "simpleengine/camera.h" #include "simpleengine/ecs/component/mesh_component.h" #include @@ -12,7 +11,6 @@ #include "simpleengine/gfx/renderer.h" #include "simpleengine/gfx/texture.h" #include "simpleengine/vector.h" -#include #include #include #include @@ -21,11 +19,8 @@ #include #include #include - #include -//#include - #include #include #include @@ -170,8 +165,8 @@ int main(int argc, char *argv[]) { 5, 6, 12, 12, 6, 13 }; - std::unordered_map> textures; - textures.emplace(white_texture.type, std::vector{ white_texture }); + std::unordered_map>> textures; + textures.emplace(white_texture.type, std::vector>{ std::make_shared(white_texture) }); se::gfx::Material white_material(textures, 1.f, 0.f, 0.f, 0.f, 0.f); // Create a renderer @@ -184,10 +179,17 @@ int main(int argc, char *argv[]) { // Create an Entity in the Scene and add components to it. se::ecs::Entity entity = scene->create_entity(); - entity.add_component("examples/dev_testing/resources/dragon.obj"); - entity.add_component(); + //entity.add_component("examples/dev_testing/resources/dragon.obj"); + //entity.add_component("examples/dev_testing/resources/stall.obj"); + entity.add_component("examples/dev_testing/resources/backpack/backpack.obj"); + //entity.add_component("examples/dev_testing/resources/scientist/scientist.fbx"); + //entity.add_component("examples/dev_testing/resources/paradigm/paradigm.fbx"); + //entity.add_component(); auto& transform_comp = entity.add_component(); - transform_comp.translate(12.f, -4.f, 0.f); + transform_comp.translate(15.f, -8.f, 0.f); + /* transform_comp.scale(0.1f); + transform_comp.rotate_z(-90.f);*/ + transform_comp.rotate_x(-90.f); // Create the entity and add the model component to it. diff --git a/include/simpleengine/gfx/material.h b/include/simpleengine/gfx/material.h index 8dd3817..c024e45 100644 --- a/include/simpleengine/gfx/material.h +++ b/include/simpleengine/gfx/material.h @@ -3,12 +3,14 @@ #include "texture.h" #include + #include +#include namespace simpleengine::gfx { class Material { public: - std::unordered_map> textures; + std::unordered_map>> textures; float ambient_scalar; float diffuse_scalar; @@ -16,7 +18,7 @@ namespace simpleengine::gfx { float shine; float reflectivity; - Material(std::unordered_map> textures, float shine = 1.f, float reflectivity = 0.f, float specular_scalar = 0.f, float ambient_scalar = 0.f, float diffuse_scalar = 0.f) : + Material(std::unordered_map>> textures, float shine = 1.f, float reflectivity = 0.f, float specular_scalar = 0.f, float ambient_scalar = 0.f, float diffuse_scalar = 0.f) : textures(textures), ambient_scalar(ambient_scalar), diffuse_scalar(diffuse_scalar), specular_scalar(specular_scalar), shine(shine), reflectivity(reflectivity) { diff --git a/include/simpleengine/gfx/model.h b/include/simpleengine/gfx/model.h index 13535ca..c525c51 100644 --- a/include/simpleengine/gfx/model.h +++ b/include/simpleengine/gfx/model.h @@ -26,8 +26,10 @@ namespace simpleengine::gfx { Model(std::string file_path); void load_model(std::string path); - void process_node(aiNode* node, const aiScene* scene); - gfx::Mesh process_mesh(aiMesh* mesh, const aiScene* scene); - std::vector load_material_textures(aiMaterial* material, aiTextureType type); + void process_node(std::unordered_map>>& processed_textures, aiNode* node, const aiScene* scene); + gfx::Mesh process_mesh(std::unordered_map>>& processed_textures, aiMesh* mesh, const aiScene* scene); + + std::unordered_map> load_all_textures(aiMaterial* material); + std::vector> load_material_texture(std::unordered_map>>& processed_textures, aiMaterial* material, aiTextureType type); }; } \ No newline at end of file diff --git a/include/simpleengine/gfx/texture.h b/include/simpleengine/gfx/texture.h index b7a8289..981f0e2 100644 --- a/include/simpleengine/gfx/texture.h +++ b/include/simpleengine/gfx/texture.h @@ -30,6 +30,7 @@ namespace simpleengine::gfx { int width; int channels; aiTextureType type; + std::string path; /** * @brief Construct a new Texture object from a path. @@ -38,7 +39,7 @@ namespace simpleengine::gfx { * @param img_2d Whether or not the texture is 2D. * @param mipmap Whether or not to generate mipmaps for this texture. */ - Texture(const char* path, aiTextureType type = aiTextureType::aiTextureType_DIFFUSE, bool img_2d = true, bool mipmap = true); + Texture(const char* path, aiTextureType type = aiTextureType::aiTextureType_DIFFUSE, bool img_2d = true, bool flip_vertically = false, bool mipmap = true); /** * @brief Construct a new Texture object from the loaded file buffer. @@ -48,7 +49,7 @@ namespace simpleengine::gfx { * @param img_2d Whether or not the texture is 2D. * @param mipmap Whether or not to generate mipmaps for this texture. */ - Texture(const unsigned char *const buffer, int buffer_length, aiTextureType type = aiTextureType::aiTextureType_DIFFUSE, bool img_2d = true, bool mipmap = true); + Texture(const unsigned char *const buffer, int buffer_length, aiTextureType type = aiTextureType::aiTextureType_DIFFUSE, bool img_2d = true, bool flip_vertically = false, bool mipmap = true); /** * @brief Construct a new Texture object from the loaded file buffer. @@ -57,7 +58,7 @@ namespace simpleengine::gfx { * @param img_2d Whether or not the texture is 2D. * @param mipmap Whether or not to generate mipmaps for this texture. */ - Texture(std::vector buffer, aiTextureType type = aiTextureType::aiTextureType_DIFFUSE, bool img_2d = true, bool mipmap = true); + Texture(std::vector buffer, aiTextureType type = aiTextureType::aiTextureType_DIFFUSE, bool img_2d = true, bool flip_vertically = false, bool mipmap = true); static Texture white_texture(); diff --git a/shell.nix b/shell.nix index c9852e1..47146ae 100644 --- a/shell.nix +++ b/shell.nix @@ -12,6 +12,5 @@ pkgs.mkShell { glfw glm assimp - (callPackage ./soil2.nix { }) ]; } \ No newline at end of file diff --git a/soil2.nix b/soil2.nix deleted file mode 100644 index 09f587e..0000000 --- a/soil2.nix +++ /dev/null @@ -1,37 +0,0 @@ -{ lib -, stdenv -, fetchFromGitHub -, cmake -, libGL -, libX11 -}: - -stdenv.mkDerivation rec { - version = "39028e64921c03cabbc53b937da4a85aba264e00"; - pname = "soil2"; - - src = fetchFromGitHub { - owner = "SpartanJ"; - repo = pname; - rev = version; - sha256 = "sha256-zQQ8lwOkMCxdlf6zfnIOYVUTGVqnJuHL/LL8fbzxwHY="; - }; - - nativeBuildInputs = [ cmake libGL libX11 ]; - - installPhase = '' - runHook preInstall - - cmake --build . --target install --config Release - - runHook postInstall - ''; - - meta = with lib; { - description = "SOIL2 is a tiny C library used primarily for uploading textures into OpenGL."; - homepage = "https://github.com/SpartanJ/SOIL2"; - license = licenses.mit0; - platforms = platforms.unix; - maintainers = with maintainers; [ seanomik ]; - }; -} \ No newline at end of file diff --git a/src/gfx/model.cpp b/src/gfx/model.cpp index 8f1d531..4968035 100644 --- a/src/gfx/model.cpp +++ b/src/gfx/model.cpp @@ -31,28 +31,28 @@ namespace simpleengine::gfx { model_directory = path.substr(0, path.find_last_of('/')); - process_node(scene->mRootNode, scene); + std::unordered_map>> processed_textures; + process_node(processed_textures, scene->mRootNode, scene); } - void Model::process_node(aiNode* node, const aiScene* scene) { + void Model::process_node(std::unordered_map>>& processed_textures, aiNode* node, const aiScene* scene) { // process all the node's meshes (if any) for (int i = 0; i < node->mNumMeshes; i++) { aiMesh *mesh = scene->mMeshes[node->mMeshes[i]]; - meshes.push_back(process_mesh(mesh, scene)); + meshes.push_back(process_mesh(processed_textures, mesh, scene)); } // then do the same for each of its children for (int i = 0; i < node->mNumChildren; i++) { - process_node(node->mChildren[i], scene); + process_node(processed_textures, node->mChildren[i], scene); } } - gfx::Mesh Model::process_mesh(aiMesh* mesh, const aiScene* scene) { + gfx::Mesh Model::process_mesh(std::unordered_map>>& processed_textures, aiMesh* mesh, const aiScene* scene) { std::vector vertices; std::vector indices; - std::vector textures; - for(unsigned int i = 0; i < mesh->mNumVertices; i++) { + for (unsigned int i = 0; i < mesh->mNumVertices; i++) { LitVertex vertex; vertex.color = glm::vec3(1.f); vertex.texture_id = 0; @@ -63,7 +63,7 @@ namespace simpleengine::gfx { glm::vec3 normal(mesh->mNormals[i].x, mesh->mNormals[i].y, mesh->mNormals[i].z); vertex.normal = normal; - if(mesh->mTextureCoords[0]) { + if (mesh->mTextureCoords[0]) { glm::vec2 tex_coord(mesh->mTextureCoords[0][i].x, mesh->mTextureCoords[0][i].y); vertex.tex_coord = tex_coord; @@ -83,18 +83,18 @@ namespace simpleengine::gfx { // Create a default material and white texture. auto white_texture = gfx::Texture::white_texture(); - std::unordered_map> default_textures; - default_textures.emplace(white_texture.type, std::vector{ white_texture }); + std::unordered_map>> default_textures; + default_textures.emplace(white_texture.type, std::vector>{ std::make_shared(white_texture) }); gfx::Material mat(default_textures, 1.f, 0.f, 0.f, 0.f, 0.f); - if(mesh->mMaterialIndex >= 0) { + if (mesh->mMaterialIndex >= 0) { std::cout << "TODO: Process model materials!" << std::endl; - std::unordered_map> textures; + std::unordered_map>> textures; aiMaterial *material = scene->mMaterials[mesh->mMaterialIndex]; // Load Diffuse texture maps - std::vector diffuse_maps = load_material_textures(material, aiTextureType_DIFFUSE); + std::vector> diffuse_maps = load_material_texture(processed_textures, material, aiTextureType_DIFFUSE); if (!diffuse_maps.empty()) textures.emplace(aiTextureType_DIFFUSE, diffuse_maps); // TODO Handle other types of texture maps @@ -102,25 +102,73 @@ namespace simpleengine::gfx { if (!textures.empty()) { // TODO: Find a way to let the user set the scalars. mat = Material(textures, 1.f, 0.f, 0.f, 0.f, 0.f); + + // Add `textures` into the `processed_textures` list. + for (const auto& pair : textures) { + for (const auto& texture : pair.second) { + bool contains = false; + + auto found = processed_textures.find(pair.first); + if (found != processed_textures.end()) { + for (const auto& processed_text : found->second) { + if (processed_text->path == texture->path) { + contains = true; + break; + } + } + + if (!contains) { + //found->second + found->second.emplace_back(texture); + } + } else { + processed_textures.emplace(pair.first, std::vector>{ pair.second }); + } + } + } } } return Mesh(vertices, indices, mat); } - std::vector Model::load_material_textures(aiMaterial* material, aiTextureType type) { - std::vector textures; + std::unordered_map> load_all_textures(aiMaterial* material) { + // Load Diffuse texture maps + return {}; + } - for(int i = 0; i < material->GetTextureCount(type); i++) { - aiString texture_path; - material->GetTexture(type, i, &texture_path); + std::vector> Model::load_material_texture(std::unordered_map>>& processed_textures, aiMaterial* material, aiTextureType type) { + std::vector> textures; + + for (int i = 0; i < material->GetTextureCount(type); i++) { + aiString texture_path_ai; + material->GetTexture(type, i, &texture_path_ai); + std::string texture_path = texture_path_ai.C_Str(); + + // If the texture has been read, we should skip it. + bool skip = false; + for (const auto& pair : processed_textures) { + if (pair.first == type) { + for (const auto& texture : pair.second) { + if (texture->path == texture_path) { + textures.emplace_back(texture); // Push a copy of the texture for this Mesh. + skip = true; + break; + } + } + } + } + if (skip) continue; std::stringstream ss; - ss << model_directory << "/" << texture_path.C_Str(); + ss << model_directory << "/" << texture_path; std::string full_path = ss.str(); - Texture texture(full_path.c_str(), type); - textures.emplace_back(texture); + Texture texture(full_path.c_str(), type, true, true); + texture.path = texture_path; + textures.emplace_back(std::make_shared(texture)); + + std::cout << "Texture full path: " << full_path << ", texture_path: " << texture_path << std::endl; } return textures; diff --git a/src/gfx/renderer.cpp b/src/gfx/renderer.cpp index 6e4e058..11f18a5 100644 --- a/src/gfx/renderer.cpp +++ b/src/gfx/renderer.cpp @@ -111,7 +111,7 @@ namespace simpleengine::gfx { if (texture_count >= 16) break; glActiveTexture(GL_TEXTURE0 + texture_count); - glBindTextureUnit(texture_count, texture.get_texture_id()); + glBindTextureUnit(texture_count, texture->get_texture_id()); texture_count++; } diff --git a/src/gfx/texture.cpp b/src/gfx/texture.cpp index 6c0f0e2..d3cdedc 100644 --- a/src/gfx/texture.cpp +++ b/src/gfx/texture.cpp @@ -4,7 +4,7 @@ #include namespace simpleengine::gfx { - Texture::Texture(const char* path, aiTextureType type, bool img_2d, bool mipmap): type(type) { + Texture::Texture(const char* path, aiTextureType type, bool img_2d, bool flip_vertically, bool mipmap): type(type) { image_type_gl = img_2d ? GL_TEXTURE_2D : GL_TEXTURE_3D; glGenTextures(1, &texture_id); @@ -17,6 +17,8 @@ namespace simpleengine::gfx { glTexParameteri(image_type_gl, GL_TEXTURE_MIN_FILTER, linear_param); glTexParameteri(image_type_gl, GL_TEXTURE_MAG_FILTER, linear_param); + stbi_set_flip_vertically_on_load(flip_vertically); + // Read 4 channels (RGBA) img_data = stbi_load(path, &width, &height, &channels, 4); if(!img_data) { @@ -32,10 +34,12 @@ namespace simpleengine::gfx { glGenerateMipmap(image_type_gl); } + stbi_set_flip_vertically_on_load(false); + unbind(); } - Texture::Texture(const unsigned char *const buffer, int buffer_length, aiTextureType type, bool img_2d, bool mipmap): type(type) { + Texture::Texture(const unsigned char *const buffer, int buffer_length, aiTextureType type, bool img_2d, bool flip_vertically, bool mipmap): type(type) { image_type_gl = img_2d ? GL_TEXTURE_2D : GL_TEXTURE_3D; glGenTextures(1, &texture_id); @@ -48,6 +52,8 @@ namespace simpleengine::gfx { glTexParameteri(image_type_gl, GL_TEXTURE_MIN_FILTER, linear_param); glTexParameteri(image_type_gl, GL_TEXTURE_MAG_FILTER, linear_param); + stbi_set_flip_vertically_on_load(flip_vertically); + // Read 4 channels (RGBA) img_data = stbi_load_from_memory(buffer, buffer_length, &width, &height, &channels, 4); if(!img_data) { @@ -63,10 +69,12 @@ namespace simpleengine::gfx { glGenerateMipmap(image_type_gl); } + stbi_set_flip_vertically_on_load(false); + unbind(); } - Texture::Texture(std::vector buffer, aiTextureType type, bool img_2d, bool mipmap) : + Texture::Texture(std::vector buffer, aiTextureType type, bool img_2d, bool flip_vertically, bool mipmap) : Texture(buffer.data(), buffer.size(), type, img_2d, mipmap) { }