Minor - Improves scene loading and audio component - V13.6.0

Refactors scene loading to properly initialize models and textures from the scene file.

Adds audio component deserialization and file path handling.

Fixes model loading and texture application in scene manager.
Addresses potential issues with missing components during scene loading.
This commit is contained in:
2025-09-17 00:01:13 +02:00
parent de05631608
commit 7fc4b08808
7 changed files with 223 additions and 171 deletions

View File

@@ -0,0 +1,8 @@
Entity:0:86
IdentityComponent:0:86:Unknown
TransformComponent:0:50:0:0:-0:0:1:1:1
RenderComponent:HasModel:1:assets/Texture/Bricks2K.png:1:assets/Texture/BricksNRM2K.png:1:assets/Texture/BricksGLOSS2K.png:0:
ShaderComponent:LIGHTING
ModelPathComponent:Content/Assets/Kobject/86.obj
AudioComponent:F:\Github_Repo\khaotic-engine-Reborn\x64\Release\assets\sounds\default.mp3;1:0:1:1:0:0:128:1:0
EndEntity

View File

@@ -5,6 +5,8 @@
#include <imgui.h>
#include "entity.h"
#include "Logger.h"
/**
* namespace for the Entity-Component-System (ECS)
*/

View File

@@ -18,6 +18,14 @@ class AudioComponent : public Component {
public:
AudioComponent() : m_sound(nullptr), m_channel(nullptr) {}
~AudioComponent() override {
// stop the sound if it's playing
if (m_channel) {
bool isPlaying = false;
m_channel->isPlaying(&isPlaying);
if (isPlaying) {
m_channel->stop();
}
}
if (m_sound) m_sound->release();
// Ne pas lib<69>rer m_system ici car il peut <20>tre partag<61>
}
@@ -51,10 +59,13 @@ public:
if (!m_system) return false;
}
Logger::Get().Log("Loading audio file: " + path, __FILE__, __LINE__, Logger::LogLevel::Info);
m_soundPath = path;
if (!std::filesystem::exists(path)) {
m_lastError = "Fichier non trouv<75>: " + path;
Logger::Get().Log(m_lastError, __FILE__, __LINE__, Logger::LogLevel::Error);
return false;
}
@@ -437,7 +448,7 @@ public:
std::string Serialize() const override {
std::stringstream ss;
ss << "AudioComponent:"
<< m_soundPath << ":"
<< m_soundPath << ";"
<< m_volume << ":"
<< m_pan << ":"
<< m_pitch << ":"
@@ -465,7 +476,7 @@ public:
std::string s_volume, s_pan, s_pitch, s_looping, s_muted, s_paused, s_priority, s_spatialized, s_use_velocity;
std::getline(ss, m_soundPath, ':');
std::getline(ss, m_soundPath, ';');
std::getline(ss, s_volume, ':');
std::getline(ss, s_pan, ':');
std::getline(ss, s_pitch, ':');
@@ -476,6 +487,8 @@ public:
std::getline(ss, s_spatialized, ':');
std::getline(ss, s_use_velocity, ':');
Logger::Get().Log("Deserializing AudioComponent: path=" + m_soundPath, __FILE__, __LINE__, Logger::LogLevel::Warning);
m_volume = std::stof(s_volume);
m_pan = std::stof(s_pan);
m_pitch = std::stof(s_pitch);

View File

@@ -35,6 +35,9 @@ public:
SetDevice(parent->GetDevice());
SetContext(parent->GetContext());
}
texture_container_buffer = TextureContainer();
}
void Update(float deltaTime) override {}
@@ -194,12 +197,42 @@ public:
*/
std::string Serialize() const override {
if (!m_model) return "RenderComponent:NoModel";
TextureContainer texture_container_buffer = m_model->GetTextureContainer();
auto serializePaths = [](const std::vector<std::wstring> &paths) -> std::string {
std::string result;
for (size_t i = 0; i < paths.size(); ++i) {
std::string p = std::string(paths[i].begin(), paths[i].end());
result += p;
if (i + 1 < paths.size()) {
result += ","; // virgule entre chemins mais pas apr<70>s dernier
}
}
return result;
};
int diffuse_count = (int)texture_container_buffer.diffuse.size();
int normal_count = (int)texture_container_buffer.normal.size();
int specular_count = (int)texture_container_buffer.specular.size();
int alpha_count = (int)texture_container_buffer.alpha.size();
std::string diffuse_paths_ = serializePaths(texture_container_buffer.diffusePaths);
std::string normal_paths_ = serializePaths(texture_container_buffer.normalPaths);
std::string specular_paths_ = serializePaths(texture_container_buffer.specularPaths);
std::string alpha_paths_ = serializePaths(texture_container_buffer.alphaPaths);
std::stringstream ss;
ss << "RenderComponent:HasModel";
ss << "RenderComponent:HasModel:"
<< diffuse_count << ":" << diffuse_paths_ << ":"
<< normal_count << ":" << normal_paths_ << ":"
<< specular_count << ":" << specular_paths_ << ":"
<< alpha_count << ":" << alpha_paths_;
return ss.str();
}
/**
* Deserialize the RenderComponent's state from a string.
* This method parses the string and sets the component's properties accordingly.
@@ -210,14 +243,81 @@ public:
bool Deserialize(const std::string& data) override {
std::stringstream ss(data);
std::string type;
std::getline(ss, type, ':');
if (type != "RenderComponent") return false;
std::string hasModel;
std::getline(ss, hasModel);
// Le mod<6F>le sera charg<72> s<>par<61>ment
if (!std::getline(ss, type, ':') || type != "RenderComponent")
return false;
std::string token;
if (!std::getline(ss, token, ':') || token != "HasModel")
return false;
int diffuse_count = 0, normal_count = 0, specular_count = 0, alpha_count = 0;
std::vector<std::wstring> paths_diffuse, paths_normal, paths_specular, paths_alpha;
auto read_count = [&](int& count) -> bool {
if (!std::getline(ss, token, ':'))
return false;
try {
count = std::stoi(token);
}
catch (...) {
return false;
}
return true;
};
auto clean_token = [](std::string& str) {
// Retirer virgules et espaces
str.erase(std::remove(str.begin(), str.end(), ','), str.end());
str.erase(0, str.find_first_not_of(" \t\n\r"));
str.erase(str.find_last_not_of(" \t\n\r") + 1);
};
auto read_paths = [&](int count, std::vector<std::wstring>& paths) -> bool {
for (int i = 0; i < count; ++i) {
if (!std::getline(ss, token, ':'))
return false;
clean_token(token);
if (!token.empty()) {
paths.emplace_back(token.begin(), token.end());
Logger::Get().Log("Loaded path: " + std::string(token.begin(), token.end()), __FILE__, __LINE__, Logger::LogLevel::Info);
}
}
return true;
};
if (!read_count(diffuse_count)) return false;
if (!read_paths(diffuse_count, paths_diffuse)) return false;
if (!read_count(normal_count)) return false;
if (!read_paths(normal_count, paths_normal)) return false;
if (!read_count(specular_count)) return false;
if (!read_paths(specular_count, paths_specular)) return false;
if (!read_count(alpha_count)) return false;
if (!read_paths(alpha_count, paths_alpha)) return false;
// Lib<69>rer textures existantes
for (auto& tex : texture_container_buffer.diffuse) if (tex) { tex->Release(); tex = nullptr; }
for (auto& tex : texture_container_buffer.normal) if (tex) { tex->Release(); tex = nullptr; }
for (auto& tex : texture_container_buffer.specular) if (tex) { tex->Release(); tex = nullptr; }
for (auto& tex : texture_container_buffer.alpha) if (tex) { tex->Release(); tex = nullptr; }
texture_container_buffer.diffuse.clear();
texture_container_buffer.normal.clear();
texture_container_buffer.specular.clear();
texture_container_buffer.alpha.clear();
texture_container_buffer.diffusePaths = std::move(paths_diffuse);
texture_container_buffer.normalPaths = std::move(paths_normal);
texture_container_buffer.specularPaths = std::move(paths_specular);
texture_container_buffer.alphaPaths = std::move(paths_alpha);
return true;
}
@@ -350,12 +450,16 @@ public:
void SetDevice (ID3D11Device* dev) { device = dev; }
void SetContext(ID3D11DeviceContext* ctx) { context = ctx; }
void SetTextureContainer(const TextureContainer& texContainer) { texture_container_buffer = texContainer; }
const TextureContainer& GetTextureContainerBuffer() const { return texture_container_buffer; }
private:
std::shared_ptr<model_class> m_model;
std::string m_modelFilePath;
bool m_isVisible;
ID3D11Device* device;
ID3D11DeviceContext* context;
TextureContainer texture_container_buffer;
};
} // namespace ecs

View File

@@ -279,6 +279,7 @@ bool model_class::LoadObjModel(char* filename)
{
XMFLOAT3 pos;
sscanf_s(line.c_str() + 2, "%f %f %f", &pos.x, &pos.y, &pos.z);
pos.z = -pos.z; // Inversion de l'axe Z pour DirectX
temp_positions.push_back(pos);
}
else if (line[1] == 't') // Coordonn<6E>es de texture
@@ -313,19 +314,19 @@ bool model_class::LoadObjModel(char* filename)
if (normIndex[i] < 0) normIndex[i] += temp_normals.size() + 1;
}
for (int i = 0; i < 3; i++)
{
ModelType vertex{};
vertex.x = temp_positions[posIndex[i] - 1].x;
vertex.y = temp_positions[posIndex[i] - 1].y;
vertex.z = temp_positions[posIndex[i] - 1].z;
vertex.tu = temp_texcoords[texIndex[i] - 1].x;
vertex.tv = temp_texcoords[texIndex[i] - 1].y;
vertex.nx = temp_normals[normIndex[i] - 1].x;
vertex.ny = temp_normals[normIndex[i] - 1].y;
vertex.nz = temp_normals[normIndex[i] - 1].z;
temp_model.push_back(vertex);
}
for (int i = 2; i >= 0; --i)
{
ModelType vertex{};
vertex.x = temp_positions[posIndex[i] - 1].x;
vertex.y = temp_positions[posIndex[i] - 1].y;
vertex.z = temp_positions[posIndex[i] - 1].z;
vertex.tu = temp_texcoords[texIndex[i] - 1].x;
vertex.tv = temp_texcoords[texIndex[i] - 1].y;
vertex.nx = temp_normals[normIndex[i] - 1].x;
vertex.ny = temp_normals[normIndex[i] - 1].y;
vertex.nz = temp_normals[normIndex[i] - 1].z;
temp_model.push_back(vertex);
}
}
}

View File

@@ -153,96 +153,60 @@ bool scene_manager::load_scene() {
// Finaliser l'entit<69> - chargement du mod<6F>le si n<>cessaire
if (currentEntity) {
auto modelPathComponent = currentEntity->GetComponent<ecs::ModelPathComponent>();
if (modelPathComponent && !modelPathComponent->GetPath().empty()) {
std::wstring modelPath = modelPathComponent->GetPath();
std::string modelKey = convert_w_string_to_string(modelPath);
if (!modelPathComponent) {
Logger::Get().Log("ModelPathComponent missing for entity ID: " + std::to_string(currentEntity->GetID()), __FILE__, __LINE__, Logger::LogLevel::Warning);
}
if (!modelPathComponent || modelPathComponent->GetPath().empty()) {
Logger::Get().Log("No model path specified for entity ID: " + std::to_string(currentEntity->GetID()), __FILE__, __LINE__, Logger::LogLevel::Warning);
}
auto renderComponent = currentEntity->GetComponent<ecs::RenderComponent>();
if (!renderComponent)
{
Logger::Get().Log("RenderComponent missing for entity ID: " + std::to_string(currentEntity->GetID()), __FILE__, __LINE__, Logger::LogLevel::Warning);
}
currentTextures = renderComponent->GetTextureContainerBuffer();
std::wstring modelPath = modelPathComponent->GetPath();
std::string modelKey = convert_w_string_to_string(modelPath);
// V<>rifier si le mod<6F>le existe dans le cache
std::shared_ptr<model_class> model;
auto it = modelCache.find(modelKey);
if (it != modelCache.end()) {
model = it->second;
} else {
// Cr<43>er et initialiser un nouveau mod<6F>le
model = std::make_shared<model_class>();
// V<>rifier si le mod<6F>le existe dans le cache
std::shared_ptr<model_class> model;
auto it = modelCache.find(modelKey);
if (it != modelCache.end()) {
model = it->second;
} else {
// Cr<43>er et initialiser un nouveau mod<6F>le
model = std::make_shared<model_class>();
// Pr<50>charger les textures
if (!model->PreloadTextures(direct_3d_->get_device(), direct_3d_->get_device_context(), currentTextures)) {
Logger::Get().Log("<EFBFBD>chec du pr<70>chargement des textures", __FILE__, __LINE__, Logger::LogLevel::Error);
}
char modelFilename[256];
size_t convertedChars = 0;
wcstombs_s(&convertedChars, modelFilename, sizeof(modelFilename), modelPath.c_str(), _TRUNCATE);
if (!model->Initialize(direct_3d_->get_device(), direct_3d_->get_device_context(), modelFilename, currentTextures)) {
Logger::Get().Log("<EFBFBD>chec d'initialisation du mod<6F>le", __FILE__, __LINE__, Logger::LogLevel::Error);
} else {
// Ajouter au cache
modelCache[modelKey] = model;
}
// Pr<50>charger les textures
if (!model->PreloadTextures(direct_3d_->get_device(), direct_3d_->get_device_context(), currentTextures)) {
Logger::Get().Log("<EFBFBD>chec du pr<70>chargement des textures", __FILE__, __LINE__, Logger::LogLevel::Error);
}
// Ajouter le composant de rendu avec le mod<6F>le
if (model) {
auto renderComponent = currentEntity->GetComponent<ecs::RenderComponent>();
if (!renderComponent) {
renderComponent = currentEntity->AddComponent<ecs::RenderComponent>();
}
renderComponent->InitializeWithModel(model);
char modelFilename[256];
size_t convertedChars = 0;
wcstombs_s(&convertedChars, modelFilename, sizeof(modelFilename), modelPath.c_str(), _TRUNCATE);
if (!model->Initialize(direct_3d_->get_device(), direct_3d_->get_device_context(), modelFilename, currentTextures)) {
Logger::Get().Log("<EFBFBD>chec d'initialisation du mod<6F>le", __FILE__, __LINE__, Logger::LogLevel::Error);
} else {
// Ajouter au cache
modelCache[modelKey] = model;
}
}
// Ajouter le composant de rendu avec le mod<6F>le
if (model) renderComponent->InitializeWithModel(model);
}
currentEntity = nullptr;
}
else if (!line.empty() && line.find("TextureData:") == 0) {
Logger::Get().Log(line.substr(11), __FILE__, __LINE__, Logger::LogLevel::Info);
if (currentEntity) {
std::stringstream ss(line.substr(11));
std::string token;
// log the token values for debugging
Logger::Get().Log( token, __FILE__, __LINE__, Logger::LogLevel::Info);
std::getline(ss, token, ':');
// Diffuse
int diffuseCount = 0;
if (std::getline(ss, token, ':') && !token.empty())
diffuseCount = std::stoi(token);
for (int i = 0; i < diffuseCount; i++) {
if (std::getline(ss, token, ':'))
currentTextures.diffusePaths.push_back(std::wstring(token.begin(), token.end()));
}
// Normal
int normalCount = 0;
if (std::getline(ss, token, ':') && !token.empty())
normalCount = std::stoi(token);
for (int i = 0; i < normalCount; i++) {
if (std::getline(ss, token, ':'))
currentTextures.normalPaths.push_back(std::wstring(token.begin(), token.end()));
}
// Textures sp<73>culaires
int specularCount = 0;
if (std::getline(ss, token, ':') && !token.empty())
specularCount = std::stoi(token);
for (int i = 0; i < specularCount; i++) {
if (std::getline(ss, token, ':'))
currentTextures.specularPaths.push_back(std::wstring(token.begin(), token.end()));
}
// Textures alpha
int alphaCount = 0;
if (std::getline(ss, token, ':') && !token.empty())
alphaCount = std::stoi(token);
for (int i = 0; i < alphaCount; i++) {
if (std::getline(ss, token, ':'))
currentTextures.alphaPaths.push_back(std::wstring(token.begin(), token.end()));
}
}
}
else if (currentEntity) {
// D<>terminer le type de composant
std::string componentType = line.substr(0, line.find(':'));
@@ -291,45 +255,6 @@ bool scene_manager::save_scene() {
}
}
// S<>rialiser les textures pour les composants de rendu
auto renderComponent = entity->GetComponent<ecs::RenderComponent>();
if (renderComponent && renderComponent->GetModel()) {
const auto& model = renderComponent->GetModel();
const auto& textureContainer = model->GetTextureContainer();
outFile << "TextureData:";
// Textures diffuses
const auto& diffusePaths = textureContainer.GetPaths(TextureType::Diffuse);
outFile << diffusePaths.size();
for (const auto& path : diffusePaths) {
outFile << ":" << convert_w_string_to_string(path);
}
// Textures normales
const auto& normalPaths = textureContainer.GetPaths(TextureType::Normal);
outFile << ":" << normalPaths.size();
for (const auto& path : normalPaths) {
outFile << ":" << convert_w_string_to_string(path);
}
// Textures sp<73>culaires
const auto& specularPaths = textureContainer.GetPaths(TextureType::Specular);
outFile << ":" << specularPaths.size();
for (const auto& path : specularPaths) {
outFile << ":" << convert_w_string_to_string(path);
}
// Textures alpha
const auto& alphaPaths = textureContainer.GetPaths(TextureType::Alpha);
outFile << ":" << alphaPaths.size();
for (const auto& path : alphaPaths) {
outFile << ":" << convert_w_string_to_string(path);
}
outFile << std::endl;
}
outFile << "EndEntity" << std::endl;
}