2024-12-25 23:01:05 +00:00
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
|
|
#include <string>
|
|
|
|
|
#include <unordered_map>
|
2024-12-31 08:40:23 +00:00
|
|
|
|
#include <map>
|
2024-12-27 05:31:12 +00:00
|
|
|
|
#include <GL/glew.h>
|
|
|
|
|
#include <vector>
|
2024-12-27 18:19:20 +00:00
|
|
|
|
#include <variant>
|
|
|
|
|
#include "gcml.h"
|
|
|
|
|
#include "stdexcept"
|
|
|
|
|
#include <iostream>
|
2024-12-31 08:40:23 +00:00
|
|
|
|
#include "Rendering/Shader.h"
|
|
|
|
|
#include <algorithm>
|
|
|
|
|
#include <cmath> // For std::abs
|
|
|
|
|
#include <memory>
|
2024-12-25 23:01:05 +00:00
|
|
|
|
|
2024-12-25 23:35:38 +00:00
|
|
|
|
// Forward-declare your Shader class
|
|
|
|
|
class Shader;
|
2024-12-25 23:01:05 +00:00
|
|
|
|
|
2024-12-25 23:35:38 +00:00
|
|
|
|
// Define types of assets
|
2024-12-25 23:01:05 +00:00
|
|
|
|
enum class AssetType
|
|
|
|
|
{
|
|
|
|
|
TEXTURE,
|
|
|
|
|
SHADER,
|
|
|
|
|
SOUND,
|
2024-12-27 05:31:12 +00:00
|
|
|
|
MODEL,
|
2024-12-25 23:01:05 +00:00
|
|
|
|
};
|
|
|
|
|
|
2024-12-25 23:35:38 +00:00
|
|
|
|
// A simple struct to hold the generic pointer
|
2024-12-25 23:01:05 +00:00
|
|
|
|
struct GenericAsset
|
|
|
|
|
{
|
2024-12-27 18:19:20 +00:00
|
|
|
|
void *data = nullptr;
|
2024-12-25 23:01:05 +00:00
|
|
|
|
};
|
|
|
|
|
|
2024-12-27 18:19:20 +00:00
|
|
|
|
struct Vertex
|
|
|
|
|
{
|
2024-12-27 05:31:12 +00:00
|
|
|
|
float position[3];
|
|
|
|
|
float texCoord[2];
|
|
|
|
|
float normal[3];
|
2024-12-31 08:40:23 +00:00
|
|
|
|
|
|
|
|
|
// 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;
|
|
|
|
|
}
|
2024-12-27 05:31:12 +00:00
|
|
|
|
};
|
|
|
|
|
|
2024-12-30 04:25:16 +00:00
|
|
|
|
// Define a Texture structure
|
2024-12-31 08:40:23 +00:00
|
|
|
|
struct Texture
|
|
|
|
|
{
|
2024-12-30 04:25:16 +00:00
|
|
|
|
GLuint id;
|
|
|
|
|
std::string type;
|
|
|
|
|
std::string path;
|
|
|
|
|
};
|
|
|
|
|
|
2024-12-31 08:40:23 +00:00
|
|
|
|
// In AssetManager.h or a separate header file
|
|
|
|
|
|
|
|
|
|
struct Submesh
|
|
|
|
|
{
|
2024-12-27 05:31:12 +00:00
|
|
|
|
std::vector<Vertex> vertices;
|
|
|
|
|
std::vector<unsigned int> indices;
|
2024-12-30 04:25:16 +00:00
|
|
|
|
std::vector<Texture> textures;
|
2024-12-31 08:40:23 +00:00
|
|
|
|
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<GLsizei>(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<Submesh> 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);
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-12-27 05:31:12 +00:00
|
|
|
|
};
|
|
|
|
|
|
2024-12-25 23:35:38 +00:00
|
|
|
|
// The main AssetManager
|
2024-12-25 23:01:05 +00:00
|
|
|
|
class AssetManager
|
|
|
|
|
{
|
|
|
|
|
public:
|
2024-12-27 18:19:20 +00:00
|
|
|
|
AssetManager() = default;
|
2024-12-25 23:01:05 +00:00
|
|
|
|
~AssetManager() = default;
|
|
|
|
|
|
2024-12-31 08:40:23 +00:00
|
|
|
|
using AssetVariant = std::variant<std::shared_ptr<Model>, std::shared_ptr<Shader>, std::shared_ptr<GLuint>>;
|
2024-12-27 18:19:20 +00:00
|
|
|
|
|
|
|
|
|
// Template function to load an asset
|
|
|
|
|
template <typename T>
|
2024-12-31 08:40:23 +00:00
|
|
|
|
std::shared_ptr<T> loadAsset(AssetType type, const std::string &path)
|
2024-12-27 18:19:20 +00:00
|
|
|
|
{
|
|
|
|
|
// 1) Create a unique key for cache lookup
|
|
|
|
|
std::string key = generateKey(type, path);
|
|
|
|
|
|
|
|
|
|
// 2) Check if it’s already loaded
|
2024-12-31 22:35:06 +00:00
|
|
|
|
// auto it = m_AssetMap.find(key);
|
|
|
|
|
// if (it != m_AssetMap.end())
|
|
|
|
|
//{
|
|
|
|
|
// // Debug: Log the variant type
|
|
|
|
|
// if (std::holds_alternative<std::shared_ptr<T>>(it->second))
|
|
|
|
|
// {
|
|
|
|
|
// #ifdef DEBUG
|
|
|
|
|
// DebugAssetMap();
|
|
|
|
|
// #endif
|
|
|
|
|
// std::cout << "[AssetManager] Retrieved asset from cache: " << key << std::endl;
|
|
|
|
|
// return std::get<std::shared_ptr<T>>(it->second);
|
|
|
|
|
// }
|
|
|
|
|
// else
|
|
|
|
|
// {
|
|
|
|
|
// throw std::runtime_error("Asset type mismatch for key: " + key);
|
|
|
|
|
// }
|
|
|
|
|
//}
|
2024-12-27 18:19:20 +00:00
|
|
|
|
|
2024-12-31 08:40:23 +00:00
|
|
|
|
// 3) Not loaded yet
|
2024-12-27 18:19:20 +00:00
|
|
|
|
AssetVariant assetData = loadAssetFromDisk(type, path);
|
|
|
|
|
|
2024-12-31 08:40:23 +00:00
|
|
|
|
if (assetData.valueless_by_exception())
|
2024-12-27 18:19:20 +00:00
|
|
|
|
{
|
|
|
|
|
DEBUG_PRINT("[AssetManager] Failed to load asset: %s", path.c_str());
|
2024-12-31 08:40:23 +00:00
|
|
|
|
return nullptr; // For smart pointers, return nullptr on failure
|
2024-12-27 18:19:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 4) Store in cache
|
|
|
|
|
m_AssetMap[key] = assetData;
|
|
|
|
|
|
|
|
|
|
// 5) Return the loaded asset
|
2024-12-31 08:40:23 +00:00
|
|
|
|
return std::get<std::shared_ptr<T>>(assetData);
|
2024-12-27 18:19:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DebugAssetMap();
|
2024-12-25 23:01:05 +00:00
|
|
|
|
|
|
|
|
|
private:
|
2024-12-25 23:35:38 +00:00
|
|
|
|
// Cache of already loaded assets: key = "type + path"
|
2024-12-31 08:41:59 +00:00
|
|
|
|
std::unordered_map<std::string, AssetVariant> m_AssetMap;
|
2024-12-25 23:01:05 +00:00
|
|
|
|
|
2024-12-27 18:19:20 +00:00
|
|
|
|
AssetVariant loadAssetFromDisk(AssetType type, const std::string &path);
|
2024-12-31 09:01:59 +00:00
|
|
|
|
// Generate the Key for each file
|
2024-12-27 18:19:20 +00:00
|
|
|
|
std::string generateKey(AssetType type, const std::string &path);
|
2024-12-25 23:01:05 +00:00
|
|
|
|
};
|