ThreeLab/Engine/Components/ModelComponent.cpp

135 lines
4.4 KiB
C++
Raw Normal View History

2025-04-01 20:03:18 +00:00
#include "ModelComponent.h"
2025-04-01 20:19:00 +00:00
#include "stb_image.h"
2025-04-02 01:28:37 +00:00
#include "../Engine.h"
2025-04-01 22:28:45 +00:00
2025-04-01 20:19:00 +00:00
#include <iostream>
2025-04-01 22:28:45 +00:00
#include <sstream>
#include <map>
#include <algorithm>
2025-04-02 01:28:37 +00:00
#include "../utils/AssetManager.h"
#include <glm/gtc/type_ptr.hpp>
2025-04-01 20:03:18 +00:00
2025-04-01 22:28:45 +00:00
// Constructor: initialize default values.
2025-04-01 20:03:18 +00:00
ModelComponent::ModelComponent()
2025-04-01 22:28:45 +00:00
: modelPath("./assets/models/sponza.obj"),
diffuseColor(1.0f, 1.0f, 1.0f),
2025-04-01 20:03:18 +00:00
specularColor(1.0f, 1.0f, 1.0f),
2025-04-01 22:28:45 +00:00
shininess(32.0f)
2025-04-01 20:19:00 +00:00
{
2025-04-01 22:28:45 +00:00
// Load the model on construction.
LoadModel(modelPath);
2025-04-01 20:03:18 +00:00
}
ModelComponent::~ModelComponent() {
2025-04-02 01:28:37 +00:00
// Clean up each submesh's OpenGL buffers.
2025-04-01 22:28:45 +00:00
for (auto &mesh : meshes) {
2025-04-02 01:28:37 +00:00
if (mesh.VAO) glDeleteVertexArrays(1, &mesh.VAO);
if (mesh.VBO) glDeleteBuffers(1, &mesh.VBO);
if (mesh.EBO) glDeleteBuffers(1, &mesh.EBO);
// Do not delete mesh.diffuseTexture here since it's managed by the Asset Manager.
// if(mesh.diffuseTexture) glDeleteTextures(1, &mesh.diffuseTexture);
2025-04-01 22:28:45 +00:00
}
2025-04-01 20:19:00 +00:00
}
2025-04-02 01:28:37 +00:00
2025-04-01 22:28:45 +00:00
void ModelComponent::SetupMesh(SubMesh &mesh) {
glGenVertexArrays(1, &mesh.VAO);
glGenBuffers(1, &mesh.VBO);
glGenBuffers(1, &mesh.EBO);
2025-04-01 20:19:00 +00:00
2025-04-01 22:28:45 +00:00
glBindVertexArray(mesh.VAO);
2025-04-01 20:19:00 +00:00
2025-04-01 22:28:45 +00:00
glBindBuffer(GL_ARRAY_BUFFER, mesh.VBO);
glBufferData(GL_ARRAY_BUFFER, mesh.vertices.size() * sizeof(Vertex), &mesh.vertices[0], GL_STATIC_DRAW);
2025-04-01 20:19:00 +00:00
2025-04-01 22:28:45 +00:00
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh.EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, mesh.indices.size() * sizeof(GLuint), &mesh.indices[0], GL_STATIC_DRAW);
2025-04-01 20:19:00 +00:00
// Vertex attributes:
// Positions.
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)0);
glEnableVertexAttribArray(0);
// Normals.
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Normal));
glEnableVertexAttribArray(1);
// TexCoords.
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, TexCoords));
glEnableVertexAttribArray(2);
// Tangents.
glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Tangent));
glEnableVertexAttribArray(3);
glBindVertexArray(0);
}
2025-04-01 22:28:45 +00:00
bool ModelComponent::LoadDiffuseTexture(const std::string &filepath, GLuint &textureID) {
2025-04-01 20:19:00 +00:00
int w, h, channels;
unsigned char* data = stbi_load(filepath.c_str(), &w, &h, &channels, 0);
if (!data) {
std::cout << "Failed to load diffuse texture: " << filepath << std::endl;
return false;
}
2025-04-01 22:28:45 +00:00
glGenTextures(1, &textureID);
glBindTexture(GL_TEXTURE_2D, textureID);
2025-04-01 20:19:00 +00:00
GLenum format = (channels == 3) ? GL_RGB : GL_RGBA;
glTexImage2D(GL_TEXTURE_2D, 0, format, w, h, 0, format, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
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);
stbi_image_free(data);
return true;
}
bool ModelComponent::LoadNormalTexture(const std::string &filepath) {
2025-04-01 22:28:45 +00:00
// Similar to LoadDiffuseTexture but for normalTexture; not used in this submesh example.
return true;
}
// Loads a model using tiny_obj_loader and groups faces by material.
bool ModelComponent::LoadModel(const std::string &filepath) {
2025-04-02 01:28:37 +00:00
// Use the AssetManager to load the raw model data.
ModelAsset asset;
if (!AssetManager::Get().LoadModel(filepath, asset))
2025-04-01 20:19:00 +00:00
return false;
2025-04-02 01:28:37 +00:00
// Save the model path.
modelPath = asset.modelPath;
2025-04-01 22:28:45 +00:00
// Clear any existing submeshes.
meshes.clear();
2025-04-02 01:28:37 +00:00
// Copy the cached raw submesh data.
// Note: We do not copy OpenGL buffers (VAO, VBO, EBO) since they are instance-specific.
for (const SubMesh &cachedMesh : asset.meshes) {
SubMesh mesh = cachedMesh;
// Ensure buffer IDs are reset.
mesh.VAO = mesh.VBO = mesh.EBO = 0;
meshes.push_back(mesh);
}
2025-04-01 22:28:45 +00:00
2025-04-02 01:28:37 +00:00
for (auto &mesh : meshes) {
SetupMesh(mesh);
2025-04-01 22:28:45 +00:00
}
2025-04-01 20:19:00 +00:00
return true;
}
2025-04-02 01:28:37 +00:00
2025-04-01 20:19:00 +00:00
void ModelComponent::Draw() {
2025-04-02 01:28:37 +00:00
// Render each submesh.
2025-04-01 22:28:45 +00:00
for (auto &mesh : meshes) {
2025-04-02 01:28:37 +00:00
// Bind the diffuse texture if available.
if (mesh.diffuseTexture) {
2025-04-01 22:28:45 +00:00
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, mesh.diffuseTexture);
}
glBindVertexArray(mesh.VAO);
glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(mesh.indices.size()), GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
}
2025-04-01 20:03:18 +00:00
}
2025-04-02 01:28:37 +00:00