Tesseract-Engine/src/Engine/AssetManager.h
2024-12-31 16:35:06 -06:00

241 lines
6.5 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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 its 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);
};