241 lines
6.5 KiB
C++
241 lines
6.5 KiB
C++
#pragma once
|
||
|
||
#include <string>
|
||
#include <unordered_map>
|
||
#include <map>
|
||
#include <GL/glew.h>
|
||
#include <vector>
|
||
#include <variant>
|
||
#include "gcml.h"
|
||
#include "stdexcept"
|
||
#include <iostream>
|
||
#include "Rendering/Shader.h"
|
||
#include <algorithm>
|
||
#include <cmath> // For std::abs
|
||
#include <memory>
|
||
|
||
// 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<Vertex> vertices;
|
||
std::vector<unsigned int> indices;
|
||
std::vector<Texture> 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<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);
|
||
}
|
||
}
|
||
};
|
||
|
||
// The main AssetManager
|
||
class AssetManager
|
||
{
|
||
public:
|
||
AssetManager() = default;
|
||
~AssetManager() = default;
|
||
|
||
using AssetVariant = std::variant<std::shared_ptr<Model>, std::shared_ptr<Shader>, std::shared_ptr<GLuint>>;
|
||
|
||
// Template function to load an asset
|
||
template <typename T>
|
||
std::shared_ptr<T> 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<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);
|
||
// }
|
||
//}
|
||
|
||
// 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<std::shared_ptr<T>>(assetData);
|
||
}
|
||
|
||
void DebugAssetMap();
|
||
|
||
private:
|
||
// Cache of already loaded assets: key = "type + path"
|
||
std::unordered_map<std::string, AssetVariant> m_AssetMap;
|
||
|
||
AssetVariant loadAssetFromDisk(AssetType type, const std::string &path);
|
||
// Generate the Key for each file
|
||
std::string generateKey(AssetType type, const std::string &path);
|
||
};
|