Changed asset manager to a template instead of a void*

This commit is contained in:
OusmBlueNinja 2024-12-27 12:19:20 -06:00
parent 54e108b88e
commit 0c7c49dd43
20 changed files with 1758 additions and 500 deletions

View File

@ -0,0 +1,46 @@
# Blender v2.76 (sub 0) OBJ File: ''
# www.blender.org
mtllib cube.mtl
o Cube
v 1.000000 -1.000000 -1.000000
v 1.000000 -1.000000 1.000000
v -1.000000 -1.000000 1.000000
v -1.000000 -1.000000 -1.000000
v 1.000000 1.000000 -0.999999
v 0.999999 1.000000 1.000001
v -1.000000 1.000000 1.000000
v -1.000000 1.000000 -1.000000
vt 1.000000 0.333333
vt 1.000000 0.666667
vt 0.666667 0.666667
vt 0.666667 0.333333
vt 0.666667 0.000000
vt 0.000000 0.333333
vt 0.000000 0.000000
vt 0.333333 0.000000
vt 0.333333 1.000000
vt 0.000000 1.000000
vt 0.000000 0.666667
vt 0.333333 0.333333
vt 0.333333 0.666667
vt 1.000000 0.000000
vn 0.000000 -1.000000 0.000000
vn 0.000000 1.000000 0.000000
vn 1.000000 0.000000 0.000000
vn -0.000000 0.000000 1.000000
vn -1.000000 -0.000000 -0.000000
vn 0.000000 0.000000 -1.000000
usemtl Material
s off
f 2/1/1 3/2/1 4/3/1
f 8/1/2 7/4/2 6/5/2
f 5/6/3 6/7/3 2/8/3
f 6/8/4 7/5/4 3/4/4
f 3/9/5 7/10/5 8/11/5
f 1/12/6 4/13/6 8/11/6
f 1/4/1 2/1/1 4/3/1
f 5/14/2 8/1/2 6/5/2
f 1/12/3 5/6/3 2/8/3
f 2/12/4 6/8/4 3/4/4
f 4/13/5 3/9/5 8/11/5
f 5/6/6 1/12/6 8/11/6

Binary file not shown.

View File

@ -0,0 +1,6 @@
# Created by Kenney (www.kenney.nl)
newmtl colormap
Kd 1 1 1
map_Kd variation-a.png

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

View File

Before

Width:  |  Height:  |  Size: 2.7 MiB

After

Width:  |  Height:  |  Size: 2.7 MiB

View File

@ -44,6 +44,12 @@ Size=364,1142
Collapsed=0
DockId=0x00000009,0
[Window][Editor]
Pos=374,27
Size=1212,770
Collapsed=0
DockId=0x00000003,0
[Docking][Data]
DockSpace ID=0x14621557 Window=0x3DA2F1DE Pos=8,27 Size=1904,1142 Split=X Selected=0xF7365A5A
DockNode ID=0x00000009 Parent=0x14621557 SizeRef=364,1142 HiddenTabBar=1 Selected=0x3DC5AC3F
@ -51,7 +57,7 @@ DockSpace ID=0x14621557 Window=0x3DA2F1DE Pos=8,27 Size=1904,1142 Split=
DockNode ID=0x00000007 Parent=0x0000000A SizeRef=357,1142 Selected=0x7737E8B2
DockNode ID=0x00000008 Parent=0x0000000A SizeRef=1545,1142 Split=X
DockNode ID=0x00000001 Parent=0x00000008 SizeRef=1212,1142 Split=Y Selected=0xF7365A5A
DockNode ID=0x00000003 Parent=0x00000001 SizeRef=1578,770 CentralNode=1 HiddenTabBar=1 Selected=0xF7365A5A
DockNode ID=0x00000003 Parent=0x00000001 SizeRef=1578,770 CentralNode=1 HiddenTabBar=1 Selected=0xDF0EC458
DockNode ID=0x00000004 Parent=0x00000001 SizeRef=1578,370 HiddenTabBar=1 Selected=0x9DD4E196
DockNode ID=0x00000002 Parent=0x00000008 SizeRef=324,1142 Split=Y Selected=0x36DC96AB
DockNode ID=0x00000005 Parent=0x00000002 SizeRef=324,748 HiddenTabBar=1 Selected=0x36DC96AB

25
scenes/Cart.scene Normal file
View File

@ -0,0 +1,25 @@
Entities:
- ID: 0
Name: Default
Components:
Mesh:
vao: 3
indexCount: 2304
textureID: 1
MeshPath: assets/models/DefaultMesh.obj
Transform:
Position: [0, 0.400000006, 3.5]
Rotation: [-179.5, -135.5, 0]
Scale: [1, 1, 1]
- ID: 1
Name: New GameObject 1
Components:
Mesh:
vao: 1
indexCount: 36
textureID: 5
MeshPath: assets/models/DefaultMesh.obj
Transform:
Position: [0, -2.9000001, -100]
Rotation: [0, 0, 0]
Scale: [100, 100, 400]

View File

@ -1,122 +1,121 @@
Entities:
- ID: 0
Name: Car
Name: Carrrrr Yeaaa
Components:
Mesh:
vao: 2
indexCount: 200000
textureID: 1
Transform:
Position: [0, 2.79999995, -12.6000004]
Rotation: [149.699997, -137.899994, -39.2999992]
Scale: [1, 1, 1]
Mesh:
vao: 2
indexCount: 200000
textureID: 1
MeshPath: assets/models/DefaultMesh.obj
- ID: 1
Name: Left Cube
Name: Cube Yay
Components:
Transform:
Position: [-11.8999996, -2, -21.7999992]
Rotation: [-9, -18.6000004, -28.1000004]
Scale: [1, 1, 1]
Mesh:
vao: 1
indexCount: 36
textureID: 2
Transform:
Position: [-11.6999998, -2, -21.7999992]
Rotation: [-9, -18.6000004, -28.1000004]
Scale: [1, 1, 1]
MeshPath: assets/models/DefaultMesh.obj
- ID: 2
Name: Right Cube Top
Name: Cube Yay 2
Components:
Transform:
Position: [7.80000019, -8.10000038, -20.6000004]
Rotation: [-86.3000031, 0, -66]
Scale: [1, 1, 1]
Mesh:
vao: 1
indexCount: 36
textureID: 3
Transform:
Position: [8, -8.10000038, -20.6000004]
Rotation: [-86.3000031, 0, -66]
Scale: [1, 1, 1]
MeshPath: assets/models/DefaultMesh.obj
- ID: 3
Name: Center Grass
Name: Cube Yay 3
Components:
Transform:
Position: [-1.20000005, -3.4000001, -17.7000008]
Rotation: [-23.5, 15.8999996, -59.9000015]
Scale: [1, 1, 1]
Mesh:
vao: 1
indexCount: 36
textureID: 4
Transform:
Position: [-0.600000024, -3.4000001, -17.7000008]
Rotation: [-23.5, 15.8999996, -59.9000015]
Scale: [1, 1, 1]
MeshPath: assets/models/DefaultMesh.obj
- ID: 4
Name: Right Most
Name: Cube Yay 4
Components:
Transform:
Position: [8.10000038, 0.800000012, -12]
Rotation: [-17.2999992, -16.1000004, -19.2999992]
Scale: [1, 1, 1]
Mesh:
vao: 1
indexCount: 36
textureID: 5
Transform:
Position: [8.10000038, 0.5, -12]
Rotation: [-17.2999992, -16.1000004, -19.2999992]
Scale: [1, 1, 1]
MeshPath: assets/models/DefaultMesh.obj
- ID: 5
Name: Left Screen Mirror
Name: Colormap
Components:
Transform:
Position: [-6.80000019, 2.29999995, -13.8000002]
Rotation: [-39.7000008, 0, -33.2000008]
Scale: [1, 1, 1]
Mesh:
vao: 1
indexCount: 36
textureID: 6
MeshPath: assets/models/DefaultMesh.obj
Transform:
Position: [-6.80000019, 2.70000005, -13.8000002]
Rotation: [-39.7000008, 0, -33.2000008]
Scale: [1, 1, 1]
- ID: 6
Name: Top Left
Name: Cube Yay 6
Components:
Transform:
Position: [-6.5, -6, -18]
Rotation: [15.8000002, -18.2000008, -11.1000004]
Scale: [1, 1, 1]
Mesh:
vao: 1
indexCount: 36
textureID: 3
Transform:
Position: [-6.9000001, -6, -18]
Rotation: [15.8000002, -18.2000008, -11.1000004]
Scale: [1, 1, 1]
MeshPath: assets/models/DefaultMesh.obj
- ID: 7
Name: Bottom Grass
Name: Cube Yay 7
Components:
Mesh:
vao: 1
indexCount: 36
textureID: 4
Transform:
Position: [6.5, 1.79999995, -23.8999996]
Rotation: [-16.1000004, -15.8999996, -35]
Scale: [1, 1, 1]
Mesh:
vao: 1
indexCount: 36
textureID: 4
MeshPath: assets/models/DefaultMesh.obj
- ID: 8
Name: Back Wood
Name: Cube Yay 8
Components:
Transform:
Position: [-7.80000019, 0.200000003, -29.7999992]
Rotation: [22.5, -32.7999992, 0]
Scale: [1, 1, 1]
Mesh:
vao: 1
indexCount: 36
textureID: 1
Transform:
Position: [-7.80000019, -1, -29.7999992]
Rotation: [22.5, -34.2999992, 0]
Scale: [1, 1, 1]
MeshPath: assets/models/DefaultMesh.obj
- ID: 9
Name: Right Brick
Name: Cube Yay 9
Components:
Transform:
Position: [5.5, -2.9000001, -19.5]
Rotation: [-41.4000015, -22.6000004, -52.2999992]
Scale: [1, 1, 1]
Mesh:
vao: 1
indexCount: 36
textureID: 2
Transform:
Position: [5.5, -3.20000005, -19.5]
Rotation: [-41.4000015, -24.8999996, -52.2999992]
Scale: [1, 1, 1]
- ID: 10
Name: Plant
Components:
Mesh:
vao: 3
indexCount: 589632
textureID: 5
Transform:
Position: [0, 1.29999995, -2]
Rotation: [-180, -58.5999985, 0]
Scale: [0.5, 0.5, 0.5]
MeshPath: assets/models/DefaultMesh.obj

View File

@ -103,6 +103,7 @@ void GameObject::Deserialize(const YAML::Node &node)
//}
//else if (compName == MeshComponent::GetStaticName())
//{

View File

@ -1,5 +1,12 @@
#include "Mesh.h"
#include "Engine/AssetManager.h"
#include "gcml.h"
#include "../Engine/AssetManager.h"
extern AssetManager *g_AssetManager;
//TODO: Make this have a OBJ path, make indexCount derive from AssetManager
//TODO: and make texture id also get from AssetManager
@ -8,7 +15,7 @@
const std::string MeshComponent::name = "Mesh";
MeshComponent::MeshComponent()
: vao(0), indexCount(0), textureID(0)
: vao(0), indexCount(0), textureID(0), MeshPath("assets/models/DefaultMesh.obj")
{
}
@ -30,6 +37,12 @@ YAML::Node MeshComponent::Serialize()
node["indexCount"] = static_cast<int>(indexCount);
node["textureID"] = static_cast<int>(textureID);
node["MeshPath"] = static_cast<std::string>(MeshPath);
return node;
@ -49,4 +62,24 @@ void MeshComponent::Deserialize(const YAML::Node& node)
{
textureID = static_cast<int>(node["textureID"].as<int>());
}
if (node["MeshPath"])
{
MeshPath = static_cast<std::string>(node["MeshPath"].as<std::string>());
g_AssetManager->DebugAssetMap();
#if 1
DEBUG_PRINT("Loading Mesh: >%s<", MeshPath.c_str());
Model* model = g_AssetManager->loadAsset<Model*>(AssetType::MODEL, MeshPath.c_str());
DEBUG_PRINT("Model loaded successfully with %lld vertices and %lld indices.", model->vertices.size(), model->indices.size());
#else
DEBUG_PRINT("Automatic Mesh Loading Disabled.");
#endif
}
}

View File

@ -15,6 +15,9 @@ public:
GLuint indexCount = 0; // Number of indices to draw
GLuint textureID = 0; // The texture handle
std::string MeshPath;
MeshComponent();
virtual const std::string& GetName() const override;
static const std::string& GetStaticName();

View File

@ -150,7 +150,7 @@ void MyEngine::Run()
// printf("Got Valid Mesh Component\n");
mesh->vao = CreateCubeVAO();
mesh->indexCount = 36;
mesh->textureID = static_cast<GLuint>(reinterpret_cast<uintptr_t>(g_AssetManager.loadAsset(AssetType::TEXTURE, "assets/textures/wood.png")));
mesh->textureID = g_AssetManager.loadAsset<GLuint>(AssetType::TEXTURE, "assets/textures/wood.png");
}
else
{
@ -171,12 +171,14 @@ void MyEngine::Run()
DEBUG_PRINT("Could not find Transform Component");
}
g_AssetManager.loadAsset(AssetType::TEXTURE, "assets/textures/bricks.png");
g_AssetManager.loadAsset(AssetType::TEXTURE, "assets/textures/default.png");
g_AssetManager.loadAsset(AssetType::TEXTURE, "assets/textures/lush_grass.png");
g_AssetManager.loadAsset<GLuint>(AssetType::TEXTURE, "assets/textures/bricks.png");
g_AssetManager.loadAsset<GLuint>(AssetType::TEXTURE, "assets/textures/default.png");
g_AssetManager.loadAsset<GLuint>(AssetType::TEXTURE, "assets/textures/lush_grass.png");
g_AssetManager.loadAsset<GLuint>(AssetType::TEXTURE, "assets/textures/vegetation_tree_bark_40.png");
// Load a model
void* modelPtr = g_AssetManager.loadAsset(AssetType::MODEL, "assets/models/LowPolyFiatUNO.obj");
Model* modelPtr = g_AssetManager.loadAsset<Model*>(AssetType::MODEL, "assets/models/LowPolyFiatUNO.obj");
if (modelPtr == nullptr)
{
DEBUG_PRINT("Failed to load model.");
@ -188,18 +190,11 @@ void MyEngine::Run()
}
// Load a model
void* modelPtr2 = g_AssetManager.loadAsset(AssetType::MODEL, "assets/models/OutSidePlant.obj");
if (modelPtr2 == nullptr)
{
DEBUG_PRINT("Failed to load model.");
}
else
{
Model* model2 = reinterpret_cast<Model*>(modelPtr2);
DEBUG_PRINT("Model loaded successfully with %lld vertices and %lld indices.", model2->vertices.size(), model2->indices.size());
}
Model* modelPtr4 = g_AssetManager.loadAsset<Model*>(AssetType::MODEL, "assets/models/shopping-cart.obj");
Model* model4 = reinterpret_cast<Model*>(modelPtr4);
DEBUG_PRINT("Model loaded successfully with %lld vertices and %lld indices.", model4->vertices.size(), model4->indices.size());
g_GameObjects.push_back(newGameObject);

View File

@ -6,66 +6,65 @@
#include <cstring>
#include <GL/glew.h>
#include <vector>
#include <filesystem>
#include <variant>
#define STB_IMAGE_IMPLEMENTATION
#include "stb/stb_image.h"
#include "imgui.h"
#include "gcml.h"
#include "Windows/LoggerWindow.h"
#include "Rendering/Shader.h"
#include "gcml.h"
GLuint LoadTextureFromList(const std::string &path);
Shader *LoadShaderFromList(const std::string &path);
Model *LoadModelFromList(const std::string &path);
#include <filesystem>
int LoaddedAssets = 0;
int LoadedAssets = 0;
extern LoggerWindow *g_LoggerWindow;
std::string getDirectoryPath(const std::string& fullPath) {
std::string getDirectoryPath(const std::string &fullPath)
{
std::filesystem::path pathObj(fullPath);
std::filesystem::path dir = pathObj.parent_path();
return dir.string();
}
void *AssetManager::loadAsset(AssetType type, const std::string &path)
void AssetManager::DebugAssetMap()
{
// 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())
std::cout << "[AssetManager] Debugging m_AssetMap:" << std::endl;
int i = 0;
for (const auto &[key, value] : m_AssetMap)
{
// Return existing pointer
return it->second.data;
std::cout << " Key: " << key << ", Type Index: " << value.index() << std::endl;
i++;
}
// 3) Not loaded yet, load from disk
void *assetData = loadAssetFromDisk(type, path);
if (!assetData)
if (i == 0)
{
DEBUG_PRINT("[AssetManager] Failed to load asset: %s", path.c_str());
g_LoggerWindow->AddLog("[AsseetManager] Failed to load asset: %s", ImVec4(1.0f, 0.0f, 0.0f, 1.0f), path.c_str());
return nullptr;
DEBUG_PRINT("No Cashed Assets");
}
}
// 4) Store in cache
GenericAsset newAsset;
newAsset.data = assetData;
m_AssetMap[key] = newAsset;
LoaddedAssets += 1;
g_LoggerWindow->AddLog("[AsseetManager] Loadded Asset: %s", path.c_str());
// 5) Return pointer
return assetData;
// Implementation of AssetManager::loadAssetFromDisk
AssetManager::AssetVariant AssetManager::loadAssetFromDisk(AssetType type, const std::string &path)
{
switch (type)
{
case AssetType::TEXTURE:
return LoadTextureFromList(path); // Returns GLuint
case AssetType::SHADER:
return LoadShaderFromList(path); // Returns Shader*
case AssetType::SOUND:
return std::string("Loaded sound: " + path); // Example placeholder for sound
case AssetType::MODEL:
return LoadModelFromList(path); // Returns Model*
default:
throw std::invalid_argument("Unknown AssetType");
}
}
std::string AssetManager::generateKey(AssetType type, const std::string &path)
@ -73,375 +72,361 @@ std::string AssetManager::generateKey(AssetType type, const std::string &path)
return std::to_string(static_cast<int>(type)) + ":" + path;
}
void *AssetManager::loadAssetFromDisk(AssetType type, const std::string &path)
GLuint LoadTextureFromList(const std::string &path)
{
switch (type)
// --------------------------------------------
// Load a texture with stb_image
// --------------------------------------------
std::cout << "[AssetManager] Loading TEXTURE from: " << path << std::endl;
int width, height, channels;
unsigned char *data = stbi_load(path.c_str(), &width, &height, &channels, 0);
if (!data)
{
case AssetType::TEXTURE:
{
// --------------------------------------------
// Load a texture with stb_image
// --------------------------------------------
std::cout << "[AssetManager] Loading TEXTURE from: " << path << std::endl;
int width, height, channels;
unsigned char *data = stbi_load(path.c_str(), &width, &height, &channels, 0);
if (!data)
{
std::cerr << "[AssetManager] stb_image failed for: " << path << std::endl;
return nullptr;
}
GLenum format = GL_RGBA;
if (channels == 1)
format = GL_RED;
else if (channels == 3)
format = GL_RGB;
// if channels == 4, already GL_RGBA
GLuint texID = 0;
glGenTextures(1, &texID);
glBindTexture(GL_TEXTURE_2D, texID);
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0,
format, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
// Set texture params
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// Cleanup
glBindTexture(GL_TEXTURE_2D, 0);
stbi_image_free(data);
// Return as void*
return reinterpret_cast<void *>(static_cast<uintptr_t>(texID));
std::cerr << "[AssetManager] stb_image failed for: " << path << std::endl;
return 0;
}
case AssetType::SHADER:
GLenum format = GL_RGBA;
if (channels == 1)
format = GL_RED;
else if (channels == 3)
format = GL_RGB;
// if channels == 4, already GL_RGBA
GLuint texID = 0;
glGenTextures(1, &texID);
glBindTexture(GL_TEXTURE_2D, texID);
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0,
format, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
// Set texture params
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// Cleanup
glBindTexture(GL_TEXTURE_2D, 0);
stbi_image_free(data);
// Return as void*
return texID;
}
Shader *LoadShaderFromList(const std::string &path)
{
// --------------------------------------------
// Load a shader using your existing "Shader" class
// --------------------------------------------
// Example usage: path = "shaders/UnlitMaterial" =>
// loads "shaders/UnlitMaterial.vert" and "shaders/UnlitMaterial.frag"
std::cout << "[AssetManager] Loading SHADER from: " << path << std::endl;
// Create a new Shader object on the heap
Shader *newShader = new Shader();
// Build actual paths from the base path
std::string vertPath = path + ".vert";
std::string fragPath = path + ".frag";
// Attempt to load
if (!newShader->Load(vertPath, fragPath))
{
// --------------------------------------------
// Load a shader using your existing "Shader" class
// --------------------------------------------
// Example usage: path = "shaders/UnlitMaterial" =>
// loads "shaders/UnlitMaterial.vert" and "shaders/UnlitMaterial.frag"
std::cout << "[AssetManager] Loading SHADER from: " << path << std::endl;
// Create a new Shader object on the heap
Shader *newShader = new Shader();
// Build actual paths from the base path
std::string vertPath = path + ".vert";
std::string fragPath = path + ".frag";
// Attempt to load
if (!newShader->Load(vertPath, fragPath))
{
std::cerr << "[AssetManager] Could not load shader: "
<< vertPath << " / " << fragPath << std::endl;
delete newShader; // Cleanup
return nullptr;
}
// Return as void*
return reinterpret_cast<void *>(newShader);
}
case AssetType::SOUND:
{
std::cout << "[AssetManager] Loading SOUND from: " << path << std::endl;
// Stub or real code to load .wav / .ogg
return (void *)0xAAAA8888; // placeholder
}
case AssetType::MODEL:
{
// --------------------------------------------
// Load an OBJ model
// --------------------------------------------
std::cout << "[AssetManager] Loading MODEL from: " << path << std::endl;
std::ifstream objFile(path);
if (!objFile.is_open())
{
DEBUG_PRINT("[AssetManager] Failed to open OBJ file: %s\n", path.c_str());
return nullptr;
}
std::vector<float> temp_positions;
std::vector<float> temp_texCoords;
std::vector<float> temp_normals;
std::vector<unsigned int> vertexIndices, texCoordIndices, normalIndices;
std::string directory;
size_t lastSlash = path.find_last_of("/\\");
if (lastSlash != std::string::npos)
directory = path.substr(0, lastSlash + 1);
else
directory = "";
DEBUG_PRINT("[AssetManager] Asset Directory: %s", directory.c_str());
std::string line;
std::string mtlFileName;
while (std::getline(objFile, line))
{
std::istringstream iss(line);
std::string prefix;
iss >> prefix;
if (prefix == "v")
{
float x, y, z;
iss >> x >> y >> z;
temp_positions.push_back(x);
temp_positions.push_back(y);
temp_positions.push_back(z);
}
else if (prefix == "vt")
{
float u, v;
iss >> u >> v;
temp_texCoords.push_back(u);
temp_texCoords.push_back(v);
}
else if (prefix == "vn")
{
float nx, ny, nz;
iss >> nx >> ny >> nz;
temp_normals.push_back(nx);
temp_normals.push_back(ny);
temp_normals.push_back(nz);
}
else if (prefix == "f")
{
std::string vertexStr;
std::vector<std::tuple<unsigned int, unsigned int, unsigned int>> faceVertices;
while (iss >> vertexStr)
{
unsigned int vIdx = 0, tIdx = 0, nIdx = 0;
size_t firstSlash = vertexStr.find('/');
size_t secondSlash = vertexStr.find('/', firstSlash + 1);
if (firstSlash == std::string::npos)
{
// Format: f v1 v2 v3
vIdx = std::stoi(vertexStr);
}
else if (secondSlash == std::string::npos)
{
// Format: f v1/vt1 v2/vt2 v3/vt3
vIdx = std::stoi(vertexStr.substr(0, firstSlash));
tIdx = std::stoi(vertexStr.substr(firstSlash + 1));
}
else if (secondSlash > firstSlash + 1)
{
// Format: f v1/vt1/vn1 v2/vt2/vn2 v3/vt3/vn3
vIdx = std::stoi(vertexStr.substr(0, firstSlash));
tIdx = std::stoi(vertexStr.substr(firstSlash + 1, secondSlash - firstSlash - 1));
nIdx = std::stoi(vertexStr.substr(secondSlash + 1));
}
else
{
// Format: f v1//vn1 v2//vn2 v3//vn3
vIdx = std::stoi(vertexStr.substr(0, firstSlash));
nIdx = std::stoi(vertexStr.substr(secondSlash + 1));
}
faceVertices.emplace_back(vIdx, tIdx, nIdx);
}
// Triangulate if the face has more than 3 vertices (optional)
for (size_t i = 1; i + 1 < faceVertices.size(); ++i)
{
vertexIndices.push_back(std::get<0>(faceVertices[0]));
texCoordIndices.push_back(std::get<1>(faceVertices[0]));
normalIndices.push_back(std::get<2>(faceVertices[0]));
vertexIndices.push_back(std::get<0>(faceVertices[i]));
texCoordIndices.push_back(std::get<1>(faceVertices[i]));
normalIndices.push_back(std::get<2>(faceVertices[i]));
vertexIndices.push_back(std::get<0>(faceVertices[i + 1]));
texCoordIndices.push_back(std::get<1>(faceVertices[i + 1]));
normalIndices.push_back(std::get<2>(faceVertices[i + 1]));
}
}
else if (prefix == "mtllib")
{
iss >> mtlFileName;
}
}
objFile.close();
// Load MTL file if specified
std::string texturePath;
if (!mtlFileName.empty())
{
std::ifstream mtlFile(directory + mtlFileName);
if (mtlFile.is_open())
{
while (std::getline(mtlFile, line))
{
std::istringstream mtlIss(line);
std::string mtlPrefix;
mtlIss >> mtlPrefix;
if (mtlPrefix == "map_Kd")
{
mtlIss >> texturePath;
break; // Assuming only one texture map for simplicity
}
}
mtlFile.close();
}
else
{
DEBUG_PRINT("[AssetManager] Failed to open MTL file: %s", mtlFileName.c_str());
}
}
if (texturePath.empty())
{
DEBUG_PRINT("[AssetManager] No texture found for OBJ: %s", path.c_str());
}
else
{
DEBUG_PRINT("[AssetManager] Texture for OBJ: %s%s", directory.c_str(), texturePath.c_str());
}
// Create Model object
Model *model = new Model();
// Populate vertices
std::unordered_map<std::string, unsigned int> uniqueVertices;
for (size_t i = 0; i < vertexIndices.size(); ++i)
{
std::ostringstream keyStream;
keyStream << vertexIndices[i] << "/" << texCoordIndices[i] << "/" << normalIndices[i];
std::string key = keyStream.str();
if (uniqueVertices.find(key) == uniqueVertices.end())
{
Vertex vertex;
// OBJ indices are 1-based
vertex.position[0] = temp_positions[(vertexIndices[i] - 1) * 3];
vertex.position[1] = temp_positions[(vertexIndices[i] - 1) * 3 + 1];
vertex.position[2] = temp_positions[(vertexIndices[i] - 1) * 3 + 2];
if (!temp_texCoords.empty())
{
vertex.texCoord[0] = temp_texCoords[(texCoordIndices[i] - 1) * 2];
vertex.texCoord[1] = temp_texCoords[(texCoordIndices[i] - 1) * 2 + 1];
}
else
{
vertex.texCoord[0] = 0.0f;
vertex.texCoord[1] = 0.0f;
}
if (!temp_normals.empty())
{
vertex.normal[0] = temp_normals[(normalIndices[i] - 1) * 3];
vertex.normal[1] = temp_normals[(normalIndices[i] - 1) * 3 + 1];
vertex.normal[2] = temp_normals[(normalIndices[i] - 1) * 3 + 2];
}
else
{
vertex.normal[0] = 0.0f;
vertex.normal[1] = 0.0f;
vertex.normal[2] = 0.0f;
}
model->vertices.push_back(vertex);
unsigned int newIndex = static_cast<unsigned int>(model->vertices.size() - 1);
uniqueVertices[key] = newIndex;
model->indices.push_back(newIndex);
}
else
{
model->indices.push_back(uniqueVertices[key]);
}
}
// Generate OpenGL buffers
glGenVertexArrays(1, &model->vao);
glGenBuffers(1, &model->vbo);
glGenBuffers(1, &model->ebo);
glBindVertexArray(model->vao);
glBindBuffer(GL_ARRAY_BUFFER, model->vbo);
glBufferData(GL_ARRAY_BUFFER, model->vertices.size() * sizeof(Vertex), model->vertices.data(), GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, model->ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, model->indices.size() * sizeof(unsigned int), model->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);
// Load texture if available
if (!texturePath.empty())
{
int width, height, channels;
unsigned char *data = stbi_load((directory + texturePath).c_str(), &width, &height, &channels, 0);
if (!data)
{
DEBUG_PRINT("[AssetManager] stb_image failed to load texture: %s", (directory + texturePath).c_str());
}
else
{
GLenum format = GL_RGBA;
if (channels == 1)
format = GL_RED;
else if (channels == 3)
format = GL_RGB;
// if channels == 4, already GL_RGBA
glGenTextures(1, &model->textureID);
glBindTexture(GL_TEXTURE_2D, model->textureID);
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0,
format, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
// Set texture params
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, 0);
stbi_image_free(data);
}
}
else
{
model->textureID = 0; // No texture
}
// Return the Model pointer as void*
return reinterpret_cast<void *>(model);
}
default:
{
std::cerr << "[AssetManager] Unknown asset type for: " << path << std::endl;
std::cerr << "[AssetManager] Could not load shader: "
<< vertPath << " / " << fragPath << std::endl;
delete newShader; // Cleanup
return nullptr;
}
}
// Return as void*
return newShader;
}
// case AssetType::SOUND:
//{
// std::cout << "[AssetManager] Loading SOUND from: " << path << std::endl;
// // Stub or real code to load .wav / .ogg
// return (void *)0xAAAA8888; // placeholder
// }
Model *LoadModelFromList(const std::string &path)
{
// --------------------------------------------
// Load an OBJ model
// --------------------------------------------
std::cout << "[AssetManager] Loading MODEL from: " << path << std::endl;
std::ifstream objFile(path);
if (!objFile.is_open())
{
DEBUG_PRINT("[AssetManager] Failed to open OBJ file: %s\n", path.c_str());
return nullptr;
}
std::vector<float> temp_positions;
std::vector<float> temp_texCoords;
std::vector<float> temp_normals;
std::vector<unsigned int> vertexIndices, texCoordIndices, normalIndices;
std::string directory;
size_t lastSlash = path.find_last_of("/\\");
if (lastSlash != std::string::npos)
directory = path.substr(0, lastSlash + 1);
else
directory = "";
DEBUG_PRINT("[AssetManager] Asset Directory: %s", directory.c_str());
std::string line;
std::string mtlFileName;
while (std::getline(objFile, line))
{
std::istringstream iss(line);
std::string prefix;
iss >> prefix;
if (prefix == "v")
{
float x, y, z;
iss >> x >> y >> z;
temp_positions.push_back(x);
temp_positions.push_back(y);
temp_positions.push_back(z);
}
else if (prefix == "vt")
{
float u, v;
iss >> u >> v;
temp_texCoords.push_back(u);
temp_texCoords.push_back(v);
}
else if (prefix == "vn")
{
float nx, ny, nz;
iss >> nx >> ny >> nz;
temp_normals.push_back(nx);
temp_normals.push_back(ny);
temp_normals.push_back(nz);
}
else if (prefix == "f")
{
std::string vertexStr;
std::vector<std::tuple<unsigned int, unsigned int, unsigned int>> faceVertices;
while (iss >> vertexStr)
{
unsigned int vIdx = 0, tIdx = 0, nIdx = 0;
size_t firstSlash = vertexStr.find('/');
size_t secondSlash = vertexStr.find('/', firstSlash + 1);
if (firstSlash == std::string::npos)
{
// Format: f v1 v2 v3
vIdx = std::stoi(vertexStr);
}
else if (secondSlash == std::string::npos)
{
// Format: f v1/vt1 v2/vt2 v3/vt3
vIdx = std::stoi(vertexStr.substr(0, firstSlash));
tIdx = std::stoi(vertexStr.substr(firstSlash + 1));
}
else if (secondSlash > firstSlash + 1)
{
// Format: f v1/vt1/vn1 v2/vt2/vn2 v3/vt3/vn3
vIdx = std::stoi(vertexStr.substr(0, firstSlash));
tIdx = std::stoi(vertexStr.substr(firstSlash + 1, secondSlash - firstSlash - 1));
nIdx = std::stoi(vertexStr.substr(secondSlash + 1));
}
else
{
// Format: f v1//vn1 v2//vn2 v3//vn3
vIdx = std::stoi(vertexStr.substr(0, firstSlash));
nIdx = std::stoi(vertexStr.substr(secondSlash + 1));
}
faceVertices.emplace_back(vIdx, tIdx, nIdx);
}
// Triangulate if the face has more than 3 vertices (optional)
for (size_t i = 1; i + 1 < faceVertices.size(); ++i)
{
vertexIndices.push_back(std::get<0>(faceVertices[0]));
texCoordIndices.push_back(std::get<1>(faceVertices[0]));
normalIndices.push_back(std::get<2>(faceVertices[0]));
vertexIndices.push_back(std::get<0>(faceVertices[i]));
texCoordIndices.push_back(std::get<1>(faceVertices[i]));
normalIndices.push_back(std::get<2>(faceVertices[i]));
vertexIndices.push_back(std::get<0>(faceVertices[i + 1]));
texCoordIndices.push_back(std::get<1>(faceVertices[i + 1]));
normalIndices.push_back(std::get<2>(faceVertices[i + 1]));
}
}
else if (prefix == "mtllib")
{
iss >> mtlFileName;
}
}
objFile.close();
// Load MTL file if specified
std::string texturePath;
if (!mtlFileName.empty())
{
std::ifstream mtlFile(directory + mtlFileName);
if (mtlFile.is_open())
{
while (std::getline(mtlFile, line))
{
std::istringstream mtlIss(line);
std::string mtlPrefix;
mtlIss >> mtlPrefix;
if (mtlPrefix == "map_Kd")
{
mtlIss >> texturePath;
break; // Assuming only one texture map for simplicity
}
}
mtlFile.close();
}
else
{
DEBUG_PRINT("[AssetManager] Failed to open MTL file: %s", mtlFileName.c_str());
}
}
if (texturePath.empty())
{
DEBUG_PRINT("[AssetManager] No texture found for OBJ: %s", path.c_str());
}
else
{
DEBUG_PRINT("[AssetManager] Texture for OBJ: %s%s", directory.c_str(), texturePath.c_str());
}
// Create Model object
Model *model = new Model();
// Populate vertices
std::unordered_map<std::string, unsigned int> uniqueVertices;
for (size_t i = 0; i < vertexIndices.size(); ++i)
{
std::ostringstream keyStream;
keyStream << vertexIndices[i] << "/" << texCoordIndices[i] << "/" << normalIndices[i];
std::string key = keyStream.str();
if (uniqueVertices.find(key) == uniqueVertices.end())
{
Vertex vertex;
// OBJ indices are 1-based
vertex.position[0] = temp_positions[(vertexIndices[i] - 1) * 3];
vertex.position[1] = temp_positions[(vertexIndices[i] - 1) * 3 + 1];
vertex.position[2] = temp_positions[(vertexIndices[i] - 1) * 3 + 2];
if (!temp_texCoords.empty())
{
vertex.texCoord[0] = temp_texCoords[(texCoordIndices[i] - 1) * 2];
vertex.texCoord[1] = temp_texCoords[(texCoordIndices[i] - 1) * 2 + 1];
}
else
{
vertex.texCoord[0] = 0.0f;
vertex.texCoord[1] = 0.0f;
}
if (!temp_normals.empty())
{
vertex.normal[0] = temp_normals[(normalIndices[i] - 1) * 3];
vertex.normal[1] = temp_normals[(normalIndices[i] - 1) * 3 + 1];
vertex.normal[2] = temp_normals[(normalIndices[i] - 1) * 3 + 2];
}
else
{
vertex.normal[0] = 0.0f;
vertex.normal[1] = 0.0f;
vertex.normal[2] = 0.0f;
}
model->vertices.push_back(vertex);
unsigned int newIndex = static_cast<unsigned int>(model->vertices.size() - 1);
uniqueVertices[key] = newIndex;
model->indices.push_back(newIndex);
}
else
{
model->indices.push_back(uniqueVertices[key]);
}
}
// Generate OpenGL buffers
glGenVertexArrays(1, &model->vao);
glGenBuffers(1, &model->vbo);
glGenBuffers(1, &model->ebo);
glBindVertexArray(model->vao);
glBindBuffer(GL_ARRAY_BUFFER, model->vbo);
glBufferData(GL_ARRAY_BUFFER, model->vertices.size() * sizeof(Vertex), model->vertices.data(), GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, model->ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, model->indices.size() * sizeof(unsigned int), model->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);
// Load texture if available
if (!texturePath.empty())
{
int width, height, channels;
unsigned char *data = stbi_load((directory + texturePath).c_str(), &width, &height, &channels, 0);
if (!data)
{
DEBUG_PRINT("[AssetManager] stb_image failed to load texture: %s", (directory + texturePath).c_str());
}
else
{
GLenum format = GL_RGBA;
if (channels == 1)
format = GL_RED;
else if (channels == 3)
format = GL_RGB;
// if channels == 4, already GL_RGBA
glGenTextures(1, &model->textureID);
glBindTexture(GL_TEXTURE_2D, model->textureID);
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0,
format, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
// Set texture params
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, 0);
stbi_image_free(data);
}
}
else
{
model->textureID = 0; // No texture
}
// Return the Model pointer as void*
return model;
}

View File

@ -4,6 +4,10 @@
#include <unordered_map>
#include <GL/glew.h>
#include <vector>
#include <variant>
#include "gcml.h"
#include "stdexcept"
#include <iostream>
// Forward-declare your Shader class
class Shader;
@ -20,18 +24,18 @@ enum class AssetType
// A simple struct to hold the generic pointer
struct GenericAsset
{
void* data = nullptr;
void *data = nullptr;
};
struct Vertex {
struct Vertex
{
float position[3];
float texCoord[2];
float normal[3];
};
struct Model {
struct Model
{
std::vector<Vertex> vertices;
std::vector<unsigned int> indices;
GLuint vao;
@ -47,23 +51,74 @@ struct Model {
class AssetManager
{
public:
AssetManager() = default;
AssetManager() = default;
~AssetManager() = default;
using AssetVariant = std::variant<GLuint, Shader *, std::string, Model *>;
// Load an asset from disk (texture, shader, etc.)
// Returns a void* pointer to the loaded resource.
// - For TEXTURE, cast to (GLuint)
// - For SHADER, cast to (Shader*)
// - For SOUND, cast to whatever you store
void* loadAsset(AssetType type, const std::string& path);
// Template function to load an asset
// Template function to load an asset
template <typename T>
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
std::cout << "[AssetManager] Found asset in map." << std::endl;
if (std::holds_alternative<T>(it->second))
{
return std::get<T>(it->second);
}
else
{
throw std::runtime_error("Asset type mismatch for key: " + key);
}
}
// 3) Not loaded yet, load from disk
AssetVariant assetData = loadAssetFromDisk(type, path);
if (assetData.index() == std::variant_npos)
{
DEBUG_PRINT("[AssetManager] Failed to load asset: %s", path.c_str());
// Replace NULL with 0 for non-pointer types
if constexpr (std::is_pointer_v<T>)
{
return nullptr; // For pointers
}
else
{
return 0; // For non-pointer types
}
}
// 4) Store in cache
m_AssetMap[key] = assetData;
DEBUG_PRINT("[AssetManager] Loaded Asset: %s", path.c_str());
// 5) Return the loaded asset
return std::get<T>(assetData);
}
void DebugAssetMap();
private:
// Cache of already loaded assets: key = "type + path"
std::unordered_map<std::string, GenericAsset> m_AssetMap;
std::unordered_map<std::string, AssetVariant> m_AssetMap;
AssetVariant loadAssetFromDisk(AssetType type, const std::string &path);
// Generate the unique key
std::string generateKey(AssetType type, const std::string& path);
// Actual loading from disk
void* loadAssetFromDisk(AssetType type, const std::string& path);
std::string generateKey(AssetType type, const std::string &path);
};

View File

@ -320,6 +320,18 @@ void InspectorWindow::Show()
{
mesh->textureID = static_cast<GLuint>(textureID);
}
// Define a maximum buffer size
const size_t BUFFER_SIZE = 256;
// Allocate a buffer and initialize it with the current string
char buffer[BUFFER_SIZE];
strncpy(buffer, mesh->MeshPath.c_str(), BUFFER_SIZE - 1);
buffer[BUFFER_SIZE - 1] = '\0'; // Ensure null-termination
// Render the InputText widget
if (ImGui::InputText(mesh->MeshPath.c_str(), buffer, BUFFER_SIZE))
{
// Update the string if user made changes
mesh->MeshPath = buffer;
}
}
}
ImGui::Spacing();

View File

@ -6,7 +6,7 @@
extern int LoaddedAssets;
extern int LoadedAssets;
extern int g_GPU_Triangles_drawn_to_screen;
const char* polygonModeOptions[] = { "Fill", "Wireframe", "Points" };
@ -160,7 +160,7 @@ void PerformanceWindow::Show(float fps, float ms)
ImGui::Separator();
// Show asset count
ImGui::TextColored(ImVec4(0.4f, 1.0f, 0.4f, 1.0f), "Assets: %d", LoaddedAssets);
ImGui::TextColored(ImVec4(0.4f, 1.0f, 0.4f, 1.0f), "Assets: %d", LoadedAssets);
ImGui::Separator();

View File

@ -231,7 +231,7 @@ void RenderWindow::InitGLResources()
// ----------------------------------------------------
{
void *shaderAsset = g_AssetManager.loadAsset(AssetType::SHADER, "assets/shaders/UnlitMaterial");
Shader* shaderAsset = g_AssetManager.loadAsset<Shader*>(AssetType::SHADER, "assets/shaders/UnlitMaterial");
if (!shaderAsset)
{
fprintf(stderr, "[RenderWindow] Failed to load shader via AssetManager.\n");
@ -270,7 +270,7 @@ void RenderWindow::InitGLResources()
// 3) Load TEXTURE from the asset manager
// ----------------------------------------------------
{
void *texAsset = g_AssetManager.loadAsset(AssetType::TEXTURE, "assets/textures/wood.png");
GLuint texAsset = g_AssetManager.loadAsset<GLuint>(AssetType::TEXTURE, "assets/textures/wood.png");
if (!texAsset)
{
fprintf(stderr, "[RenderWindow] Failed to load texture.\n");
@ -278,7 +278,7 @@ void RenderWindow::InitGLResources()
else
{
// Cast from void* to GLuint
m_TextureID = static_cast<GLuint>(reinterpret_cast<uintptr_t>(texAsset));
m_TextureID = texAsset;
}
}

View File

@ -31,7 +31,7 @@ std::shared_ptr<GameObject> CreateDefaultCube()
mesh->vao = CreateCubeVAO();
mesh->indexCount = 36;
mesh->textureID = static_cast<GLuint>(reinterpret_cast<uintptr_t>(g_AssetManager.loadAsset(AssetType::TEXTURE, "assets/textures/wood.png")));
mesh->textureID = g_AssetManager.loadAsset<GLuint>(AssetType::TEXTURE, "assets/textures/wood.png");
return newGameObject;
}