#pragma once #include #include #include #include #include #include #include "gcml.h" #include "stdexcept" #include #include "Rendering/Shader.h" #include #include // For std::abs #include // Forward-declare your Shader class class Shader; // Define types of assets enum class AssetType { TEXTURE, SHADER, SOUND, MODEL, }; // A simple struct to hold the generic pointer struct GenericAsset { void *data = nullptr; }; struct Vertex { float position[3]; float texCoord[2]; float normal[3]; // Equality operator to compare two Vertex instances bool operator==(const Vertex &other) const { // Compare positions for (int i = 0; i < 3; ++i) { if (position[i] != other.position[i]) return false; } // Compare texture coordinates for (int i = 0; i < 2; ++i) { if (texCoord[i] != other.texCoord[i]) return false; } // Compare normals for (int i = 0; i < 3; ++i) { if (normal[i] != other.normal[i]) return false; } return true; } }; // Define a Texture structure struct Texture { GLuint id; std::string type; std::string path; }; // In AssetManager.h or a separate header file struct Submesh { std::vector vertices; std::vector indices; std::vector textures; GLuint vao = 0, vbo = 0, ebo = 0; // Initialize OpenGL buffers for the submesh void Initialize() { glGenVertexArrays(1, &vao); glGenBuffers(1, &vbo); glGenBuffers(1, &ebo); glBindVertexArray(vao); glBindBuffer(GL_ARRAY_BUFFER, vbo); glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(Vertex), vertices.data(), GL_STATIC_DRAW); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo); glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), indices.data(), GL_STATIC_DRAW); // Vertex positions glEnableVertexAttribArray(0); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void *)0); // Texture coordinates glEnableVertexAttribArray(1); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void *)(3 * sizeof(float))); // Normals glEnableVertexAttribArray(2); glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void *)(5 * sizeof(float))); glBindVertexArray(0); } // Render the submesh void Draw(Shader *shader) { // Bind appropriate textures unsigned int diffuseNr = 1; unsigned int specularNr = 1; unsigned int normalNr = 1; for (unsigned int i = 0; i < textures.size(); i++) { glActiveTexture(GL_TEXTURE0 + i); // Activate proper texture unit before binding // Retrieve texture number (the N in diffuse_textureN) std::string number; std::string name = textures[i].type; if (name == "texture_diffuse") number = std::to_string(diffuseNr++); else if (name == "texture_specular") number = std::to_string(specularNr++); else if (name == "texture_normal") number = std::to_string(normalNr++); // Now set the sampler to the correct texture unit shader->SetInt((name + number).c_str(), i); glBindTexture(GL_TEXTURE_2D, textures[i].id); } // Draw mesh glBindVertexArray(vao); glDrawElements(GL_TRIANGLES, static_cast(indices.size()), GL_UNSIGNED_INT, 0); glBindVertexArray(0); // Always good practice to set everything back to defaults once configured. glActiveTexture(GL_TEXTURE0); } }; // In AssetManager.h or a separate header file struct Model { std::vector submeshes; // Render all submeshes void Draw(Shader *shader) { for (auto &submesh : submeshes) { submesh.Draw(shader); } } // Cleanup OpenGL resources void Cleanup() { for (auto &submesh : submeshes) { if (submesh.vao != 0) glDeleteVertexArrays(1, &submesh.vao); if (submesh.vbo != 0) glDeleteBuffers(1, &submesh.vbo); if (submesh.ebo != 0) glDeleteBuffers(1, &submesh.ebo); } } }; // The main AssetManager class AssetManager { public: AssetManager() = default; ~AssetManager() = default; using AssetVariant = std::variant, std::shared_ptr, std::shared_ptr>; // Template function to load an asset template std::shared_ptr loadAsset(AssetType type, const std::string &path) { // 1) Create a unique key for cache lookup std::string key = generateKey(type, path); // 2) Check if it’s already loaded auto it = m_AssetMap.find(key); if (it != m_AssetMap.end()) { // Debug: Log the variant type if (std::holds_alternative>(it->second)) { #ifdef DEBUG DebugAssetMap(); #endif std::cout << "[AssetManager] Retrieved asset from cache: " << key << std::endl; return std::get>(it->second); } else { throw std::runtime_error("Asset type mismatch for key: " + key); } } // 3) Not loaded yet AssetVariant assetData = loadAssetFromDisk(type, path); if (assetData.valueless_by_exception()) { DEBUG_PRINT("[AssetManager] Failed to load asset: %s", path.c_str()); return nullptr; // For smart pointers, return nullptr on failure } // 4) Store in cache m_AssetMap[key] = assetData; // 5) Return the loaded asset return std::get>(assetData); } void DebugAssetMap(); private: // Cache of already loaded assets: key = "type + path" std::unordered_map m_AssetMap; AssetVariant loadAssetFromDisk(AssetType type, const std::string &path); // Generate the unique key std::string generateKey(AssetType type, const std::string &path); };