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
|
|
|
AssetManager::AssetVariant AssetManager::loadAssetFromDisk(AssetType type, const std::string &path)
|
|
|
|
{
|
2024-12-31 08:40:23 +00:00
|
|
|
// DebugAssetMap();
|
|
|
|
g_LoggerWindow->AddLog("[AssetManager] Loading asset: %s", path.c_str());
|
2024-12-27 21:27:05 +00:00
|
|
|
LoadedAssets = m_AssetMap.size();
|
2024-12-27 18:19:20 +00:00
|
|
|
switch (type)
|
|
|
|
{
|
|
|
|
case AssetType::TEXTURE:
|
2024-12-31 08:40:23 +00:00
|
|
|
{
|
|
|
|
GLuint textureID = LoadTextureFromList(path); // Returns GLuint
|
|
|
|
return std::make_shared<GLuint>(textureID); // Wrap in shared_ptr
|
|
|
|
}
|
2024-12-27 18:19:20 +00:00
|
|
|
case AssetType::SHADER:
|
2024-12-31 08:40:23 +00:00
|
|
|
{
|
2024-12-31 20:16:53 +00:00
|
|
|
Shader *shaderPtr = LoadShaderFromList(path); // Returns Shader*
|
2024-12-31 08:40:23 +00:00
|
|
|
if (shaderPtr != nullptr)
|
|
|
|
{
|
|
|
|
// It's essential to ensure that shaderPtr is dynamically allocated and not managed elsewhere
|
|
|
|
return std::shared_ptr<Shader>(shaderPtr);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
throw std::runtime_error("Failed to load shader: " + path);
|
|
|
|
}
|
|
|
|
}
|
2024-12-27 18:19:20 +00:00
|
|
|
case AssetType::MODEL:
|
2024-12-31 08:40:23 +00:00
|
|
|
{
|
2024-12-31 20:16:53 +00:00
|
|
|
Model *modelPtr = LoadModelFromList(path); // Returns Model*
|
2024-12-31 08:40:23 +00:00
|
|
|
if (modelPtr != nullptr)
|
|
|
|
{
|
|
|
|
// It's essential to ensure that modelPtr is dynamically allocated and not managed elsewhere
|
|
|
|
return std::shared_ptr<Model>(modelPtr);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
throw std::runtime_error("Failed to load model: " + path);
|
|
|
|
}
|
|
|
|
}
|
2024-12-27 18:19:20 +00:00
|
|
|
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
|
|
|
|
// --------------------------------------------
|
|
|
|
|
|
|
|
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
|
|
|
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-31 20:16:53 +00:00
|
|
|
Shader *LoadShaderFromList(const std::string &path)
|
2024-12-27 18:19:20 +00:00
|
|
|
{
|
|
|
|
|
|
|
|
// Build actual paths from the base path
|
|
|
|
std::string vertPath = path + ".vert";
|
|
|
|
std::string fragPath = path + ".frag";
|
|
|
|
|
2024-12-31 08:40:23 +00:00
|
|
|
// Create a new Shader object using the constructor that takes vertex and fragment paths
|
|
|
|
Shader *newShader = new Shader(vertPath.c_str(), fragPath.c_str());
|
|
|
|
|
|
|
|
// Check if shader compiled and linked successfully
|
|
|
|
if (newShader->ID == 0)
|
2024-12-27 18:19:20 +00:00
|
|
|
{
|
|
|
|
delete newShader; // Cleanup
|
|
|
|
return nullptr;
|
2024-12-25 23:35:38 +00:00
|
|
|
}
|
|
|
|
|
2024-12-31 08:40:23 +00:00
|
|
|
// Return the Shader pointer as void*
|
2024-12-27 18:19:20 +00:00
|
|
|
return newShader;
|
|
|
|
}
|
2024-12-25 23:35:38 +00:00
|
|
|
|
2024-12-30 04:25:16 +00:00
|
|
|
GLuint LoadTexture(const std::string &path, const std::string &directory)
|
|
|
|
{
|
|
|
|
std::string fullPath = directory + path;
|
|
|
|
int width, height, channels;
|
|
|
|
unsigned char *data = stbi_load(fullPath.c_str(), &width, &height, &channels, 0);
|
|
|
|
if (!data)
|
|
|
|
{
|
2024-12-31 20:16:53 +00:00
|
|
|
DEBUG_PRINT("[AssetManager] failed to load texture: %s: %s", fullPath.c_str(), stbi_failure_reason());
|
2024-12-30 04:25:16 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
GLenum format;
|
|
|
|
if (channels == 1)
|
|
|
|
format = GL_RED;
|
|
|
|
else if (channels == 3)
|
|
|
|
format = GL_RGB;
|
|
|
|
else if (channels == 4)
|
|
|
|
format = GL_RGBA;
|
|
|
|
else
|
|
|
|
format = GL_RGB; // Default fallback
|
|
|
|
|
|
|
|
GLuint textureID;
|
|
|
|
glGenTextures(1, &textureID);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, textureID);
|
2024-12-31 20:16:53 +00:00
|
|
|
|
2024-12-30 04:25:16 +00:00
|
|
|
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0,
|
|
|
|
format, GL_UNSIGNED_BYTE, data);
|
|
|
|
glGenerateMipmap(GL_TEXTURE_2D);
|
|
|
|
|
|
|
|
// Set texture parameters
|
2024-12-31 20:16:53 +00:00
|
|
|
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);
|
2024-12-30 04:25:16 +00:00
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
|
|
|
|
|
|
glBindTexture(GL_TEXTURE_2D, 0);
|
|
|
|
stbi_image_free(data);
|
|
|
|
|
|
|
|
return textureID;
|
|
|
|
}
|
|
|
|
|
2024-12-31 20:16:53 +00:00
|
|
|
#include <unordered_map>
|
2024-12-30 04:25:16 +00:00
|
|
|
|
2024-12-31 20:16:53 +00:00
|
|
|
// Custom hash function for Vertex
|
|
|
|
struct VertexHash
|
|
|
|
{
|
|
|
|
std::size_t operator()(const Vertex &v) const
|
|
|
|
{
|
|
|
|
std::size_t h1 = std::hash<float>{}(v.position[0]);
|
|
|
|
std::size_t h2 = std::hash<float>{}(v.position[1]);
|
|
|
|
std::size_t h3 = std::hash<float>{}(v.position[2]);
|
|
|
|
std::size_t h4 = std::hash<float>{}(v.texCoord[0]);
|
|
|
|
std::size_t h5 = std::hash<float>{}(v.texCoord[1]);
|
|
|
|
std::size_t h6 = std::hash<float>{}(v.normal[0]);
|
|
|
|
std::size_t h7 = std::hash<float>{}(v.normal[1]);
|
|
|
|
std::size_t h8 = std::hash<float>{}(v.normal[2]);
|
|
|
|
return h1 ^ h2 ^ h3 ^ h4 ^ h5 ^ h6 ^ h7 ^ h8;
|
|
|
|
}
|
|
|
|
};
|
2024-12-30 04:25:16 +00:00
|
|
|
|
2024-12-31 20:16:53 +00:00
|
|
|
// Hash map for deduplication
|
|
|
|
std::unordered_map<Vertex, unsigned int, VertexHash> vertexCache;
|
2024-12-30 04:25:16 +00:00
|
|
|
|
2024-12-31 20:16:53 +00:00
|
|
|
Model *LoadModelFromList(const std::string &path)
|
2024-12-27 18:19:20 +00:00
|
|
|
{
|
2024-12-31 20:16:53 +00:00
|
|
|
auto start = std::chrono::high_resolution_clock::now();
|
2024-12-27 18:19:20 +00:00
|
|
|
|
|
|
|
std::ifstream objFile(path);
|
|
|
|
if (!objFile.is_open())
|
2024-12-25 23:35:38 +00:00
|
|
|
{
|
2024-12-27 18:19:20 +00:00
|
|
|
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;
|
2024-12-30 04:25:16 +00:00
|
|
|
|
2024-12-31 20:16:53 +00:00
|
|
|
temp_positions.reserve(100000);
|
|
|
|
temp_texCoords.reserve(100000);
|
|
|
|
temp_normals.reserve(100000);
|
|
|
|
|
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-31 08:40:23 +00:00
|
|
|
std::string currentMaterial = "default";
|
|
|
|
|
|
|
|
// Map material name to Submesh
|
|
|
|
std::unordered_map<std::string, Submesh> materialToSubmesh;
|
|
|
|
materialToSubmesh[currentMaterial] = Submesh();
|
2024-12-27 05:31:12 +00:00
|
|
|
|
2024-12-27 18:19:20 +00:00
|
|
|
std::string line;
|
|
|
|
std::string mtlFileName;
|
2024-12-31 20:16:53 +00:00
|
|
|
|
|
|
|
// Read file into memory for faster line parsing
|
|
|
|
std::stringstream fileBuffer;
|
|
|
|
fileBuffer << objFile.rdbuf();
|
|
|
|
objFile.close();
|
|
|
|
DEBUG_PRINT("OBJ READ");
|
|
|
|
|
|
|
|
while (std::getline(fileBuffer, line))
|
2024-12-27 18:19:20 +00:00
|
|
|
{
|
2024-12-30 04:25:16 +00:00
|
|
|
if (line.empty() || line[0] == '#')
|
|
|
|
continue; // Skip empty lines and comments
|
|
|
|
|
2024-12-27 18:19:20 +00:00
|
|
|
std::istringstream iss(line);
|
|
|
|
std::string prefix;
|
|
|
|
iss >> prefix;
|
2024-12-31 08:40:23 +00:00
|
|
|
|
2024-12-27 18:19:20 +00:00
|
|
|
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;
|
2024-12-30 04:25:16 +00:00
|
|
|
// Flip the model vertically by inverting the y-axis
|
2024-12-27 18:19:20 +00:00
|
|
|
temp_positions.push_back(x);
|
2024-12-30 04:25:16 +00:00
|
|
|
temp_positions.push_back(-y); // Inverted
|
2024-12-27 18:19:20 +00:00
|
|
|
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;
|
2024-12-30 04:25:16 +00:00
|
|
|
// Invert the y-axis for normals as well
|
2024-12-27 18:19:20 +00:00
|
|
|
temp_normals.push_back(nx);
|
2024-12-30 04:25:16 +00:00
|
|
|
temp_normals.push_back(-ny); // Inverted
|
2024-12-27 18:19:20 +00:00
|
|
|
temp_normals.push_back(nz);
|
|
|
|
}
|
2024-12-31 08:40:23 +00:00
|
|
|
else if (prefix == "usemtl")
|
|
|
|
{
|
|
|
|
iss >> currentMaterial;
|
|
|
|
if (materialToSubmesh.find(currentMaterial) == materialToSubmesh.end())
|
|
|
|
{
|
|
|
|
materialToSubmesh[currentMaterial] = Submesh();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (prefix == "mtllib")
|
|
|
|
{
|
|
|
|
iss >> mtlFileName;
|
|
|
|
}
|
2024-12-27 18:19:20 +00:00
|
|
|
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;
|
2024-12-31 20:16:53 +00:00
|
|
|
const char *ptr = vertexStr.c_str();
|
2024-12-27 18:19:20 +00:00
|
|
|
|
2024-12-31 20:16:53 +00:00
|
|
|
// Parse vertex index (vIdx)
|
|
|
|
vIdx = std::strtol(ptr, const_cast<char **>(&ptr), 10);
|
|
|
|
|
|
|
|
if (*ptr == '/')
|
2024-12-27 18:19:20 +00:00
|
|
|
{
|
2024-12-31 20:16:53 +00:00
|
|
|
++ptr; // Skip the first '/'
|
|
|
|
if (*ptr != '/')
|
|
|
|
{
|
|
|
|
// Parse texture index (tIdx)
|
|
|
|
tIdx = std::strtol(ptr, const_cast<char **>(&ptr), 10);
|
|
|
|
}
|
|
|
|
if (*ptr == '/')
|
|
|
|
{
|
|
|
|
++ptr; // Skip the second '/'
|
|
|
|
// Parse normal index (nIdx)
|
|
|
|
nIdx = std::strtol(ptr, const_cast<char **>(&ptr), 10);
|
|
|
|
}
|
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-30 04:25:16 +00:00
|
|
|
// Triangulate if the face has more than 3 vertices
|
2024-12-27 18:19:20 +00:00
|
|
|
for (size_t i = 1; i + 1 < faceVertices.size(); ++i)
|
2024-12-27 05:31:12 +00:00
|
|
|
{
|
2024-12-31 08:40:23 +00:00
|
|
|
// Current material's submesh
|
|
|
|
Submesh ¤tSubmesh = materialToSubmesh[currentMaterial];
|
|
|
|
|
2024-12-31 20:16:53 +00:00
|
|
|
auto addVertex = [&](unsigned int v, unsigned int t, unsigned int n) -> unsigned int
|
|
|
|
{
|
2024-12-31 08:40:23 +00:00
|
|
|
Vertex vertex;
|
2024-12-31 20:16:53 +00:00
|
|
|
|
2024-12-31 08:40:23 +00:00
|
|
|
// OBJ indices are 1-based
|
|
|
|
vertex.position[0] = temp_positions[(v - 1) * 3];
|
|
|
|
vertex.position[1] = temp_positions[(v - 1) * 3 + 1];
|
|
|
|
vertex.position[2] = temp_positions[(v - 1) * 3 + 2];
|
2024-12-27 18:19:20 +00:00
|
|
|
|
2024-12-31 08:40:23 +00:00
|
|
|
if (!temp_texCoords.empty() && t > 0)
|
|
|
|
{
|
|
|
|
vertex.texCoord[0] = temp_texCoords[(t - 1) * 2];
|
|
|
|
vertex.texCoord[1] = temp_texCoords[(t - 1) * 2 + 1];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
vertex.texCoord[0] = 0.0f;
|
|
|
|
vertex.texCoord[1] = 0.0f;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!temp_normals.empty() && n > 0)
|
|
|
|
{
|
|
|
|
vertex.normal[0] = temp_normals[(n - 1) * 3];
|
|
|
|
vertex.normal[1] = temp_normals[(n - 1) * 3 + 1];
|
|
|
|
vertex.normal[2] = temp_normals[(n - 1) * 3 + 2];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
vertex.normal[0] = 0.0f;
|
|
|
|
vertex.normal[1] = 0.0f;
|
|
|
|
vertex.normal[2] = 0.0f;
|
|
|
|
}
|
2024-12-27 18:19:20 +00:00
|
|
|
|
2024-12-31 20:16:53 +00:00
|
|
|
// Use the hash map to check for duplicates
|
|
|
|
auto it = vertexCache.find(vertex);
|
|
|
|
if (it != vertexCache.end())
|
2024-12-31 08:40:23 +00:00
|
|
|
{
|
2024-12-31 20:16:53 +00:00
|
|
|
return it->second;
|
2024-12-31 08:40:23 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2024-12-31 20:16:53 +00:00
|
|
|
unsigned int newIndex = static_cast<unsigned int>(currentSubmesh.vertices.size());
|
2024-12-31 08:40:23 +00:00
|
|
|
currentSubmesh.vertices.push_back(vertex);
|
2024-12-31 20:16:53 +00:00
|
|
|
vertexCache[vertex] = newIndex;
|
|
|
|
return newIndex;
|
2024-12-31 08:40:23 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
unsigned int idx0 = addVertex(std::get<0>(faceVertices[0]), std::get<1>(faceVertices[0]), std::get<2>(faceVertices[0]));
|
|
|
|
unsigned int idx1 = addVertex(std::get<0>(faceVertices[i]), std::get<1>(faceVertices[i]), std::get<2>(faceVertices[i]));
|
|
|
|
unsigned int idx2 = addVertex(std::get<0>(faceVertices[i + 1]), std::get<1>(faceVertices[i + 1]), std::get<2>(faceVertices[i + 1]));
|
|
|
|
|
|
|
|
currentSubmesh.indices.push_back(idx0);
|
|
|
|
currentSubmesh.indices.push_back(idx1);
|
|
|
|
currentSubmesh.indices.push_back(idx2);
|
2024-12-27 05:31:12 +00:00
|
|
|
}
|
|
|
|
}
|
2024-12-27 18:19:20 +00:00
|
|
|
}
|
|
|
|
|
2024-12-31 20:16:53 +00:00
|
|
|
temp_positions.shrink_to_fit();
|
|
|
|
temp_texCoords.shrink_to_fit();
|
|
|
|
temp_normals.shrink_to_fit();
|
|
|
|
DEBUG_PRINT("MTL READ");
|
2024-12-27 05:31:12 +00:00
|
|
|
|
2024-12-27 18:19:20 +00:00
|
|
|
// Load MTL file if specified
|
2024-12-31 08:40:23 +00:00
|
|
|
std::unordered_map<std::string, std::vector<Texture>> materialTexturesMap;
|
2024-12-27 18:19:20 +00:00
|
|
|
if (!mtlFileName.empty())
|
|
|
|
{
|
|
|
|
std::ifstream mtlFile(directory + mtlFileName);
|
|
|
|
if (mtlFile.is_open())
|
2024-12-27 05:31:12 +00:00
|
|
|
{
|
2024-12-30 04:25:16 +00:00
|
|
|
std::string mtlLine;
|
2024-12-31 08:40:23 +00:00
|
|
|
std::string currentMaterialName;
|
2024-12-30 04:25:16 +00:00
|
|
|
while (std::getline(mtlFile, mtlLine))
|
2024-12-27 05:31:12 +00:00
|
|
|
{
|
2024-12-30 04:25:16 +00:00
|
|
|
if (mtlLine.empty() || mtlLine[0] == '#')
|
|
|
|
continue; // Skip comments and empty lines
|
|
|
|
|
|
|
|
std::istringstream mtlIss(mtlLine);
|
2024-12-27 18:19:20 +00:00
|
|
|
std::string mtlPrefix;
|
|
|
|
mtlIss >> mtlPrefix;
|
2024-12-30 04:25:16 +00:00
|
|
|
|
|
|
|
if (mtlPrefix == "newmtl")
|
|
|
|
{
|
2024-12-31 08:40:23 +00:00
|
|
|
mtlIss >> currentMaterialName;
|
2024-12-30 04:25:16 +00:00
|
|
|
}
|
|
|
|
else if (mtlPrefix == "map_Kd")
|
|
|
|
{
|
|
|
|
std::string texturePath;
|
|
|
|
mtlIss >> texturePath;
|
|
|
|
if (!texturePath.empty())
|
|
|
|
{
|
|
|
|
GLuint texID = LoadTexture(texturePath, directory);
|
|
|
|
if (texID != 0)
|
|
|
|
{
|
|
|
|
Texture texture;
|
|
|
|
texture.id = texID;
|
|
|
|
texture.type = "texture_diffuse";
|
|
|
|
texture.path = texturePath;
|
2024-12-31 08:40:23 +00:00
|
|
|
materialTexturesMap[currentMaterialName].push_back(texture);
|
2024-12-30 04:25:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (mtlPrefix == "map_Ks")
|
|
|
|
{
|
|
|
|
std::string texturePath;
|
|
|
|
mtlIss >> texturePath;
|
|
|
|
if (!texturePath.empty())
|
|
|
|
{
|
|
|
|
GLuint texID = LoadTexture(texturePath, directory);
|
|
|
|
if (texID != 0)
|
|
|
|
{
|
|
|
|
Texture texture;
|
|
|
|
texture.id = texID;
|
|
|
|
texture.type = "texture_specular";
|
|
|
|
texture.path = texturePath;
|
2024-12-31 08:40:23 +00:00
|
|
|
materialTexturesMap[currentMaterialName].push_back(texture);
|
2024-12-30 04:25:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (mtlPrefix == "map_Bump" || mtlPrefix == "map_bump" || mtlPrefix == "bump")
|
2024-12-27 05:31:12 +00:00
|
|
|
{
|
2024-12-30 04:25:16 +00:00
|
|
|
std::string texturePath;
|
2024-12-27 18:19:20 +00:00
|
|
|
mtlIss >> texturePath;
|
2024-12-30 04:25:16 +00:00
|
|
|
if (!texturePath.empty())
|
|
|
|
{
|
|
|
|
GLuint texID = LoadTexture(texturePath, directory);
|
|
|
|
if (texID != 0)
|
|
|
|
{
|
|
|
|
Texture texture;
|
|
|
|
texture.id = texID;
|
|
|
|
texture.type = "texture_normal";
|
|
|
|
texture.path = texturePath;
|
2024-12-31 08:40:23 +00:00
|
|
|
materialTexturesMap[currentMaterialName].push_back(texture);
|
2024-12-30 04:25:16 +00:00
|
|
|
}
|
|
|
|
}
|
2024-12-27 05:31:12 +00:00
|
|
|
}
|
2024-12-30 04:25:16 +00:00
|
|
|
// Add more texture types as needed
|
2024-12-27 05:31:12 +00:00
|
|
|
}
|
2024-12-30 04:25:16 +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
|
|
|
}
|
2024-12-30 04:25:16 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
}
|
2024-12-27 05:31:12 +00:00
|
|
|
|
2024-12-31 20:16:53 +00:00
|
|
|
DEBUG_PRINT("MTL SUBASSIGN");
|
|
|
|
|
2024-12-31 08:40:23 +00:00
|
|
|
// Assign textures to submeshes based on their material
|
|
|
|
for (auto &pair : materialToSubmesh)
|
2024-12-27 18:19:20 +00:00
|
|
|
{
|
2024-12-31 08:40:23 +00:00
|
|
|
const std::string &materialName = pair.first;
|
|
|
|
Submesh &submesh = pair.second;
|
2024-12-27 05:31:12 +00:00
|
|
|
|
2024-12-31 08:40:23 +00:00
|
|
|
if (materialTexturesMap.find(materialName) != materialTexturesMap.end())
|
2024-12-27 18:19:20 +00:00
|
|
|
{
|
2024-12-31 08:40:23 +00:00
|
|
|
submesh.textures = materialTexturesMap[materialName];
|
2024-12-27 18:19:20 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2024-12-31 08:40:23 +00:00
|
|
|
// If no material textures found, you can assign default textures or leave it empty
|
2024-12-27 05:31:12 +00:00
|
|
|
}
|
|
|
|
|
2024-12-31 08:40:23 +00:00
|
|
|
// Initialize OpenGL buffers for the submesh
|
|
|
|
submesh.Initialize();
|
|
|
|
}
|
2024-12-27 05:31:12 +00:00
|
|
|
|
2024-12-31 08:40:23 +00:00
|
|
|
if (materialToSubmesh.empty())
|
|
|
|
{
|
|
|
|
return nullptr;
|
|
|
|
}
|
2024-12-27 05:31:12 +00:00
|
|
|
|
2024-12-31 08:40:23 +00:00
|
|
|
// Create Model object
|
|
|
|
Model *model = new Model();
|
2024-12-27 05:31:12 +00:00
|
|
|
|
2024-12-31 08:40:23 +00:00
|
|
|
// Move submeshes to the model
|
2024-12-31 20:16:53 +00:00
|
|
|
DEBUG_PRINT("SUB MIGRATE");
|
|
|
|
|
2024-12-31 08:40:23 +00:00
|
|
|
for (auto &pair : materialToSubmesh)
|
|
|
|
{
|
|
|
|
model->submeshes.emplace_back(std::move(pair.second));
|
|
|
|
}
|
2024-12-31 20:16:53 +00:00
|
|
|
// Code to analyze
|
|
|
|
auto end = std::chrono::high_resolution_clock::now();
|
|
|
|
g_LoggerWindow->AddLog("Loaded Mesh in %.6f seconds",
|
|
|
|
std::chrono::duration_cast<std::chrono::duration<double>>(end - start).count());
|
2024-12-27 05:31:12 +00:00
|
|
|
|
2024-12-31 08:40:23 +00:00
|
|
|
DEBUG_PRINT("[AssetManager] Loaded model with %lld submeshes.", model->submeshes.size());
|
2024-12-27 05:31:12 +00:00
|
|
|
|
2024-12-27 18:19:20 +00:00
|
|
|
return model;
|
2024-12-31 08:40:23 +00:00
|
|
|
}
|