2024-12-25 23:35:38 +00:00
|
|
|
#include "Engine/AssetManager.h"
|
2024-12-27 05:31:12 +00:00
|
|
|
|
2024-12-25 23:01:05 +00:00
|
|
|
#include <iostream>
|
2024-12-27 05:31:12 +00:00
|
|
|
#include <fstream>
|
|
|
|
#include <sstream>
|
|
|
|
#include <cstring>
|
|
|
|
#include <GL/glew.h>
|
|
|
|
#include <vector>
|
2024-12-27 18:19:20 +00:00
|
|
|
|
|
|
|
#include <filesystem>
|
|
|
|
#include <variant>
|
|
|
|
|
2024-12-27 05:31:12 +00:00
|
|
|
#define STB_IMAGE_IMPLEMENTATION
|
|
|
|
#include "stb/stb_image.h"
|
2024-12-25 23:01:05 +00:00
|
|
|
|
2024-12-27 05:31:12 +00:00
|
|
|
#include "imgui.h"
|
2024-12-27 18:19:20 +00:00
|
|
|
#include "gcml.h"
|
2024-12-25 23:35:38 +00:00
|
|
|
|
|
|
|
#include "Windows/LoggerWindow.h"
|
2024-12-27 05:31:12 +00:00
|
|
|
#include "Rendering/Shader.h"
|
2024-12-25 23:35:38 +00:00
|
|
|
|
2024-12-27 18:19:20 +00:00
|
|
|
GLuint LoadTextureFromList(const std::string &path);
|
|
|
|
Shader *LoadShaderFromList(const std::string &path);
|
|
|
|
Model *LoadModelFromList(const std::string &path);
|
2024-12-25 23:01:05 +00:00
|
|
|
|
2024-12-27 18:19:20 +00:00
|
|
|
int LoadedAssets = 0;
|
2024-12-25 23:35:38 +00:00
|
|
|
|
|
|
|
extern LoggerWindow *g_LoggerWindow;
|
|
|
|
|
2024-12-27 18:19:20 +00:00
|
|
|
std::string getDirectoryPath(const std::string &fullPath)
|
|
|
|
{
|
2024-12-27 05:31:12 +00:00
|
|
|
std::filesystem::path pathObj(fullPath);
|
|
|
|
std::filesystem::path dir = pathObj.parent_path();
|
|
|
|
return dir.string();
|
|
|
|
}
|
|
|
|
|
2024-12-27 18:19:20 +00:00
|
|
|
void AssetManager::DebugAssetMap()
|
2024-12-25 23:01:05 +00:00
|
|
|
{
|
2024-12-27 18:19:20 +00:00
|
|
|
std::cout << "[AssetManager] Debugging m_AssetMap:" << std::endl;
|
|
|
|
int i = 0;
|
|
|
|
for (const auto &[key, value] : m_AssetMap)
|
2024-12-25 23:01:05 +00:00
|
|
|
{
|
2024-12-27 18:19:20 +00:00
|
|
|
std::cout << " Key: " << key << ", Type Index: " << value.index() << std::endl;
|
|
|
|
i++;
|
2024-12-25 23:01:05 +00:00
|
|
|
}
|
2024-12-27 18:19:20 +00:00
|
|
|
if (i == 0)
|
2024-12-25 23:01:05 +00:00
|
|
|
{
|
2024-12-27 18:19:20 +00:00
|
|
|
DEBUG_PRINT("No Cashed Assets");
|
2024-12-25 23:01:05 +00:00
|
|
|
}
|
2024-12-27 18:19:20 +00:00
|
|
|
}
|
2024-12-25 23:01:05 +00:00
|
|
|
|
2024-12-27 18:19:20 +00:00
|
|
|
// Implementation of AssetManager::loadAssetFromDisk
|
|
|
|
AssetManager::AssetVariant AssetManager::loadAssetFromDisk(AssetType type, const std::string &path)
|
|
|
|
{
|
2024-12-27 18:47:48 +00:00
|
|
|
DebugAssetMap();
|
2024-12-27 18:19:20 +00:00
|
|
|
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");
|
|
|
|
}
|
2024-12-25 23:01:05 +00:00
|
|
|
}
|
|
|
|
|
2024-12-27 05:31:12 +00:00
|
|
|
std::string AssetManager::generateKey(AssetType type, const std::string &path)
|
2024-12-25 23:01:05 +00:00
|
|
|
{
|
|
|
|
return std::to_string(static_cast<int>(type)) + ":" + path;
|
|
|
|
}
|
|
|
|
|
2024-12-27 18:19:20 +00:00
|
|
|
GLuint LoadTextureFromList(const std::string &path)
|
2024-12-25 23:01:05 +00:00
|
|
|
{
|
2024-12-27 18:19:20 +00:00
|
|
|
// --------------------------------------------
|
|
|
|
// 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)
|
2024-12-25 23:35:38 +00:00
|
|
|
{
|
2024-12-27 18:19:20 +00:00
|
|
|
std::cerr << "[AssetManager] stb_image failed for: " << path << std::endl;
|
|
|
|
return 0;
|
|
|
|
}
|
2024-12-25 23:35:38 +00:00
|
|
|
|
2024-12-27 18:19:20 +00:00
|
|
|
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;
|
|
|
|
}
|
2024-12-25 23:01:05 +00:00
|
|
|
|
2024-12-27 18:19:20 +00:00
|
|
|
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))
|
|
|
|
{
|
|
|
|
std::cerr << "[AssetManager] Could not load shader: "
|
|
|
|
<< vertPath << " / " << fragPath << std::endl;
|
|
|
|
delete newShader; // Cleanup
|
|
|
|
return nullptr;
|
2024-12-25 23:35:38 +00:00
|
|
|
}
|
|
|
|
|
2024-12-27 18:19:20 +00:00
|
|
|
// Return as void*
|
|
|
|
return newShader;
|
|
|
|
}
|
2024-12-25 23:35:38 +00:00
|
|
|
|
2024-12-27 18:19:20 +00:00
|
|
|
// case AssetType::SOUND:
|
|
|
|
//{
|
|
|
|
// std::cout << "[AssetManager] Loading SOUND from: " << path << std::endl;
|
|
|
|
// // Stub or real code to load .wav / .ogg
|
|
|
|
// return (void *)0xAAAA8888; // placeholder
|
|
|
|
// }
|
2024-12-25 23:35:38 +00:00
|
|
|
|
2024-12-27 18:19:20 +00:00
|
|
|
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())
|
2024-12-25 23:35:38 +00:00
|
|
|
{
|
2024-12-27 18:19:20 +00:00
|
|
|
DEBUG_PRINT("[AssetManager] Failed to open OBJ file: %s\n", path.c_str());
|
|
|
|
return nullptr;
|
2024-12-27 05:31:12 +00:00
|
|
|
}
|
|
|
|
|
2024-12-27 18:19:20 +00:00
|
|
|
std::vector<float> temp_positions;
|
|
|
|
std::vector<float> temp_texCoords;
|
|
|
|
std::vector<float> temp_normals;
|
|
|
|
std::vector<unsigned int> vertexIndices, texCoordIndices, normalIndices;
|
2024-12-27 05:31:12 +00:00
|
|
|
|
2024-12-27 18:19:20 +00:00
|
|
|
std::string directory;
|
|
|
|
size_t lastSlash = path.find_last_of("/\\");
|
|
|
|
if (lastSlash != std::string::npos)
|
|
|
|
directory = path.substr(0, lastSlash + 1);
|
|
|
|
else
|
|
|
|
directory = "";
|
2024-12-27 05:31:12 +00:00
|
|
|
|
2024-12-27 18:19:20 +00:00
|
|
|
DEBUG_PRINT("[AssetManager] Asset Directory: %s", directory.c_str());
|
2024-12-27 05:31:12 +00:00
|
|
|
|
2024-12-27 18:19:20 +00:00
|
|
|
std::string line;
|
|
|
|
std::string mtlFileName;
|
|
|
|
while (std::getline(objFile, line))
|
|
|
|
{
|
|
|
|
std::istringstream iss(line);
|
|
|
|
std::string prefix;
|
|
|
|
iss >> prefix;
|
|
|
|
if (prefix == "v")
|
2024-12-27 05:31:12 +00:00
|
|
|
{
|
2024-12-27 18:19:20 +00:00
|
|
|
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)
|
2024-12-27 05:31:12 +00:00
|
|
|
{
|
2024-12-27 18:19:20 +00:00
|
|
|
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)
|
2024-12-27 05:31:12 +00:00
|
|
|
{
|
2024-12-27 18:19:20 +00:00
|
|
|
// Format: f v1 v2 v3
|
|
|
|
vIdx = std::stoi(vertexStr);
|
2024-12-27 05:31:12 +00:00
|
|
|
}
|
2024-12-27 18:19:20 +00:00
|
|
|
else if (secondSlash == std::string::npos)
|
2024-12-27 05:31:12 +00:00
|
|
|
{
|
2024-12-27 18:19:20 +00:00
|
|
|
// 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));
|
2024-12-27 05:31:12 +00:00
|
|
|
}
|
2024-12-27 18:19:20 +00:00
|
|
|
|
|
|
|
faceVertices.emplace_back(vIdx, tIdx, nIdx);
|
2024-12-27 05:31:12 +00:00
|
|
|
}
|
|
|
|
|
2024-12-27 18:19:20 +00:00
|
|
|
// Triangulate if the face has more than 3 vertices (optional)
|
|
|
|
for (size_t i = 1; i + 1 < faceVertices.size(); ++i)
|
2024-12-27 05:31:12 +00:00
|
|
|
{
|
2024-12-27 18:19:20 +00:00
|
|
|
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]));
|
2024-12-27 05:31:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-12-27 18:19:20 +00:00
|
|
|
else if (prefix == "mtllib")
|
|
|
|
{
|
|
|
|
iss >> mtlFileName;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
objFile.close();
|
2024-12-27 05:31:12 +00:00
|
|
|
|
2024-12-27 18:19:20 +00:00
|
|
|
// Load MTL file if specified
|
|
|
|
std::string texturePath;
|
|
|
|
if (!mtlFileName.empty())
|
|
|
|
{
|
|
|
|
std::ifstream mtlFile(directory + mtlFileName);
|
|
|
|
if (mtlFile.is_open())
|
2024-12-27 05:31:12 +00:00
|
|
|
{
|
2024-12-27 18:19:20 +00:00
|
|
|
while (std::getline(mtlFile, line))
|
2024-12-27 05:31:12 +00:00
|
|
|
{
|
2024-12-27 18:19:20 +00:00
|
|
|
std::istringstream mtlIss(line);
|
|
|
|
std::string mtlPrefix;
|
|
|
|
mtlIss >> mtlPrefix;
|
|
|
|
if (mtlPrefix == "map_Kd")
|
2024-12-27 05:31:12 +00:00
|
|
|
{
|
2024-12-27 18:19:20 +00:00
|
|
|
mtlIss >> texturePath;
|
|
|
|
break; // Assuming only one texture map for simplicity
|
2024-12-27 05:31:12 +00:00
|
|
|
}
|
|
|
|
}
|
2024-12-27 18:19:20 +00:00
|
|
|
mtlFile.close();
|
2024-12-27 05:31:12 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2024-12-27 18:19:20 +00:00
|
|
|
DEBUG_PRINT("[AssetManager] Failed to open MTL file: %s", mtlFileName.c_str());
|
2024-12-27 05:31:12 +00:00
|
|
|
}
|
2024-12-27 18:19:20 +00:00
|
|
|
}
|
2024-12-27 05:31:12 +00:00
|
|
|
|
2024-12-27 18:19:20 +00:00
|
|
|
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());
|
|
|
|
}
|
2024-12-27 05:31:12 +00:00
|
|
|
|
2024-12-27 18:19:20 +00:00
|
|
|
// Create Model object
|
|
|
|
Model *model = new Model();
|
2024-12-27 05:31:12 +00:00
|
|
|
|
2024-12-27 18:19:20 +00:00
|
|
|
// 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();
|
2024-12-27 05:31:12 +00:00
|
|
|
|
2024-12-27 18:19:20 +00:00
|
|
|
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];
|
2024-12-27 05:31:12 +00:00
|
|
|
|
2024-12-27 18:19:20 +00:00
|
|
|
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;
|
|
|
|
}
|
2024-12-27 05:31:12 +00:00
|
|
|
|
2024-12-27 18:19:20 +00:00
|
|
|
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];
|
2024-12-27 05:31:12 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2024-12-27 18:19:20 +00:00
|
|
|
vertex.normal[0] = 0.0f;
|
|
|
|
vertex.normal[1] = 0.0f;
|
|
|
|
vertex.normal[2] = 0.0f;
|
2024-12-27 05:31:12 +00:00
|
|
|
}
|
2024-12-27 18:19:20 +00:00
|
|
|
|
|
|
|
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]);
|
2024-12-27 05:31:12 +00:00
|
|
|
}
|
2024-12-27 18:19:20 +00:00
|
|
|
}
|
2024-12-27 05:31:12 +00:00
|
|
|
|
2024-12-27 18:19:20 +00:00
|
|
|
// Generate OpenGL buffers
|
|
|
|
glGenVertexArrays(1, &model->vao);
|
|
|
|
glGenBuffers(1, &model->vbo);
|
|
|
|
glGenBuffers(1, &model->ebo);
|
2024-12-27 05:31:12 +00:00
|
|
|
|
2024-12-27 18:19:20 +00:00
|
|
|
glBindVertexArray(model->vao);
|
2024-12-27 05:31:12 +00:00
|
|
|
|
2024-12-27 18:19:20 +00:00
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, model->vbo);
|
|
|
|
glBufferData(GL_ARRAY_BUFFER, model->vertices.size() * sizeof(Vertex), model->vertices.data(), GL_STATIC_DRAW);
|
2024-12-27 05:31:12 +00:00
|
|
|
|
2024-12-27 18:19:20 +00:00
|
|
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, model->ebo);
|
|
|
|
glBufferData(GL_ELEMENT_ARRAY_BUFFER, model->indices.size() * sizeof(unsigned int), model->indices.data(), GL_STATIC_DRAW);
|
2024-12-27 05:31:12 +00:00
|
|
|
|
2024-12-27 18:19:20 +00:00
|
|
|
// 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)));
|
2024-12-27 05:31:12 +00:00
|
|
|
|
2024-12-27 18:19:20 +00:00
|
|
|
glBindVertexArray(0);
|
2024-12-27 05:31:12 +00:00
|
|
|
|
2024-12-27 18:19:20 +00:00
|
|
|
// 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)
|
2024-12-27 05:31:12 +00:00
|
|
|
{
|
2024-12-27 18:19:20 +00:00
|
|
|
DEBUG_PRINT("[AssetManager] stb_image failed to load texture: %s", (directory + texturePath).c_str());
|
2024-12-27 05:31:12 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2024-12-27 18:19:20 +00:00
|
|
|
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);
|
2024-12-27 05:31:12 +00:00
|
|
|
}
|
2024-12-25 23:35:38 +00:00
|
|
|
}
|
2024-12-27 18:19:20 +00:00
|
|
|
else
|
2024-12-25 23:35:38 +00:00
|
|
|
{
|
2024-12-27 18:19:20 +00:00
|
|
|
model->textureID = 0; // No texture
|
2024-12-25 23:01:05 +00:00
|
|
|
}
|
2024-12-27 18:19:20 +00:00
|
|
|
|
|
|
|
// Return the Model pointer as void*
|
|
|
|
return model;
|
2024-12-25 23:01:05 +00:00
|
|
|
}
|