Minor - Enhances ECS component functionality - V13.5.0

Adds serialization/deserialization to components,
allowing saving and loading of entity states.
Provides ImGui widgets for editing component properties,
improving editor usability.
Passes the D3D device and context to entities and
components enabling resource creation within components.
This commit is contained in:
2025-09-16 18:26:33 +02:00
parent f875580197
commit de05631608
8 changed files with 346 additions and 16 deletions

View File

@@ -6,8 +6,10 @@
<component name="ChangeListManager">
<list default="true" id="e81d6e08-efc7-40a0-909d-ec4943d948e9" name="Changes" comment="">
<change beforePath="$PROJECT_DIR$/.idea/.idea.KhaoticEngineReborn/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/.idea.KhaoticEngineReborn/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/enginecustom/src/inc/system/application_class.h" beforeDir="false" afterPath="$PROJECT_DIR$/enginecustom/src/inc/system/application_class.h" afterDir="false" />
<change beforePath="$PROJECT_DIR$/enginecustom/src/inc/system/camera_class.h" beforeDir="false" afterPath="$PROJECT_DIR$/enginecustom/src/inc/system/camera_class.h" afterDir="false" />
<change beforePath="$PROJECT_DIR$/enginecustom/src/inc/system/ecs/components/audio_component.h" beforeDir="false" afterPath="$PROJECT_DIR$/enginecustom/src/inc/system/ecs/components/audio_component.h" afterDir="false" />
<change beforePath="$PROJECT_DIR$/enginecustom/src/inc/system/ecs/components/render_component.h" beforeDir="false" afterPath="$PROJECT_DIR$/enginecustom/src/inc/system/ecs/components/render_component.h" afterDir="false" />
<change beforePath="$PROJECT_DIR$/enginecustom/src/inc/system/ecs/components/transform_component.h" beforeDir="false" afterPath="$PROJECT_DIR$/enginecustom/src/inc/system/ecs/components/transform_component.h" afterDir="false" />
<change beforePath="$PROJECT_DIR$/enginecustom/src/inc/system/ecs/entity.h" beforeDir="false" afterPath="$PROJECT_DIR$/enginecustom/src/inc/system/ecs/entity.h" afterDir="false" />
<change beforePath="$PROJECT_DIR$/enginecustom/src/inc/system/ecs/entity_manager.h" beforeDir="false" afterPath="$PROJECT_DIR$/enginecustom/src/inc/system/ecs/entity_manager.h" afterDir="false" />
<change beforePath="$PROJECT_DIR$/enginecustom/src/src/system/application_class.cpp" beforeDir="false" afterPath="$PROJECT_DIR$/enginecustom/src/src/system/application_class.cpp" afterDir="false" />
@@ -258,7 +260,7 @@
<workItem from="1757952791669" duration="4499000" />
<workItem from="1757959923169" duration="1930000" />
<workItem from="1757961888820" duration="9053000" />
<workItem from="1758030961823" duration="1895000" />
<workItem from="1758030961823" duration="8967000" />
</task>
<task id="LOCAL-00001" summary="Minor update - viewport window tweak">
<option name="closed" value="true" />

View File

@@ -82,6 +82,12 @@ public:
*/
void get_reflection_view_matrix(XMMATRIX&) const;
/**
* @brief Calculates and returns the forward direction vector of the camera based on its rotation.
* This vector points in the direction the camera is facing.
* @return A normalized 3D vector representing the camera's forward direction.
*/
XMFLOAT3 get_forward() const {
float pitch = XMConvertToRadians(rotation_x_);
float yaw = XMConvertToRadians(rotation_y_);
@@ -93,7 +99,11 @@ public:
return forwardVec;
}
/**
* @brief Calculates and returns the right direction vector of the camera based on its rotation.
* This vector points to the right side of the camera.
* @return A normalized 3D vector representing the camera's right direction.
*/
XMFLOAT3 get_up() const {
// Construire matrice rotation <20> partir des angles
XMMATRIX rot = XMMatrixRotationRollPitchYaw(

View File

@@ -22,6 +22,10 @@ public:
// Ne pas lib<69>rer m_system ici car il peut <20>tre partag<61>
}
/**
* Initialize the audio component by setting up the FMOD system and camera from the parent entity.
* This method is called when the component is added to an entity.
*/
void Initialize() override
{
@@ -34,6 +38,13 @@ public:
}
/**
* Load an audio file from the specified path.
* If the FMOD system is not initialized, it will be initialized first.
* Creates a sound object with appropriate settings based on the component's properties.
* @param path The file path to load the audio from.
* @return True if the audio file was loaded successfully, otherwise false.
*/
bool Load(const std::string& path) {
if (!m_system) {
Initialize();
@@ -72,6 +83,11 @@ public:
return true;
}
/**
* Play the loaded audio sound.
* If the sound is already playing, it will be stopped and restarted.
* The channel properties such as volume, pan, pitch, mute, priority, and paused state are applied.
*/
void Play() {
if (m_system && m_sound) {
bool isPlaying = false;
@@ -96,6 +112,10 @@ public:
}
}
/**
* Pause the currently playing audio sound.
* If the sound is not playing, this method has no effect.
*/
void Pause() {
if (m_channel) {
m_paused = true;
@@ -103,6 +123,10 @@ public:
}
}
/**
* Resume the paused audio sound.
* If the sound is not paused, this method has no effect.
*/
void Resume() {
if (m_channel) {
m_paused = false;
@@ -110,13 +134,26 @@ public:
}
}
/**
* Stop the currently playing audio sound.
* If the sound is not playing, this method has no effect.
*/
void Stop() {
if (m_channel)
m_channel->stop();
}
/**
* Set the camera to be used for 3D audio spatialization.
* This camera is used to update the listener attributes in FMOD.
* @param camera Pointer to the camera_class instance.
*/
void SetCamera(camera_class* camera) {m_camera = camera; }
/**
* Update the audio component.
* @param deltaTime Time since the last update.
*/
void Update(float deltaTime) override {
if (!m_spatialized) return;
@@ -171,7 +208,12 @@ public:
m_system->update();
}
/**
* ImGui Widget to control the audio component properties.
* Allows loading/changing/removing audio files, and adjusting properties like volume, pan, pitch, looping, spatialization, etc.
* Displays error messages if loading fails.
* This method is called during the ImGui rendering phase.
*/
void OnImGuiRender() override {
if (!m_sound) {
ImGui::Text("No audio file loaded");
@@ -377,10 +419,81 @@ public:
}
}
/**
* Set the FMOD system to be used by this audio component.
* This method allows sharing the FMOD system instance across multiple audio components.
* @param system Pointer to the FMOD::System instance.
*/
void SetSoundSystem(FMOD::System* system) {
m_system = system;
}
/**
* Serialize the audio component's state to a string.
* This includes properties like sound path, volume, pan, pitch, looping, muted, paused, priority, spatialization, and use of velocity.
* This method is useful for saving the component's state or debugging.
* @return A string representation of the audio component's state.
*/
std::string Serialize() const override {
std::stringstream ss;
ss << "AudioComponent:"
<< m_soundPath << ":"
<< m_volume << ":"
<< m_pan << ":"
<< m_pitch << ":"
<< m_looping << ":"
<< m_muted << ":"
<< m_paused << ":"
<< m_priority << ":"
<< m_spatialized << ":"
<< m_use_velocity;
return ss.str();
}
/**
* Deserialize the audio component's state from a string.
* This method parses the string and sets the component's properties accordingly.
* If the sound path is valid, it attempts to load the audio file.
* @param data The string representation of the audio component's state.
* @return True if deserialization was successful, otherwise false.
*/
bool Deserialize(const std::string& data) override {
std::stringstream ss(data);
std::string type;
std::getline(ss, type, ':');
if (type != "AudioComponent") return false;
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, s_volume, ':');
std::getline(ss, s_pan, ':');
std::getline(ss, s_pitch, ':');
std::getline(ss, s_looping, ':');
std::getline(ss, s_muted, ':');
std::getline(ss, s_paused, ':');
std::getline(ss, s_priority, ':');
std::getline(ss, s_spatialized, ':');
std::getline(ss, s_use_velocity, ':');
m_volume = std::stof(s_volume);
m_pan = std::stof(s_pan);
m_pitch = std::stof(s_pitch);
m_looping = (s_looping == "1");
m_muted = (s_muted == "1");
m_paused = (s_paused == "1");
m_priority = std::stoi(s_priority);
m_spatialized = (s_spatialized == "1");
m_use_velocity = (s_use_velocity == "1");
// Recharger le son si le chemin existe (optional: ou laisser le chargement manuel)
if (!m_soundPath.empty() && m_system) {
Load(m_soundPath);
}
return true;
}
private:
FMOD::System* m_system;
FMOD::Sound* m_sound;

View File

@@ -14,17 +14,7 @@
extern std::map<std::string, std::shared_ptr<model_class>> g_model_cache;
namespace ecs {
/**
* Enum for different types of textures used in rendering.
*/
enum class TextureType
{
Diffuse,
Normal,
Specular,
Alpha,
Reflection
};
class RenderComponent : public Component {
public:
@@ -34,7 +24,18 @@ public:
RenderComponent() : m_model(nullptr), m_isVisible(true) {}
~RenderComponent() = default;
void Initialize() override {}
/**
* Initialize the component by setting up the Direct3D device and context from the parent entity.
* This method is called when the component is added to an entity.
*/
void Initialize() override
{
if (auto parent = GetParent()) {
SetDevice(parent->GetDevice());
SetContext(parent->GetContext());
}
}
void Update(float deltaTime) override {}
/**
@@ -186,6 +187,11 @@ public:
}
}
/**
* Serialize the RenderComponent's state to a string.
* This method is useful for saving the component's state or debugging.
* @return A string representation of the RenderComponent's state.
*/
std::string Serialize() const override {
if (!m_model) return "RenderComponent:NoModel";
@@ -194,6 +200,13 @@ public:
return ss.str();
}
/**
* Deserialize the RenderComponent's state from a string.
* This method parses the string and sets the component's properties accordingly.
* Note: The model will be loaded separately based on the model file path.
* @param data The string representation of the RenderComponent's state.
* @return True if deserialization was successful, otherwise false.
*/
bool Deserialize(const std::string& data) override {
std::stringstream ss(data);
std::string type;
@@ -208,6 +221,11 @@ public:
return true;
}
/**
* Render the ImGui interface for the RenderComponent.
* This method provides a user interface for inspecting and modifying the component's properties.
* It includes options to toggle visibility, display model information, and manage textures.
*/
void OnImGuiRender() override {
ImGui::Checkbox("Visible", &m_isVisible);
ImGui::Text("Model File Path: %s", m_modelFilePath.c_str());
@@ -216,12 +234,128 @@ public:
} else {
ImGui::Text("No model loaded.");
}
ImGui::Separator();
// D<>finir les types de textures_
std::vector<std::string> textureCategories = {
"Diffuse", "Normal", "Specular", "Alpha"
};
std::vector<TextureType> textureTypes = {
TextureType::Diffuse, TextureType::Normal,
TextureType::Specular, TextureType::Alpha
};
// Cr<43>er un espace pour afficher les textures_ avec d<>filement
ImGui::BeginChild("TextureChild", ImVec2(0, 200), true, ImGuiWindowFlags_HorizontalScrollbar);
// Pour chaque type de texture
for (int typeIndex = 0; typeIndex < textureCategories.size(); typeIndex++)
{
TextureType type = textureTypes[typeIndex];
std::string typeName = textureCategories[typeIndex];
// Afficher le titre de la cat<61>gorie
ImGui::Text("%s:", typeName.c_str());
ImGui::SameLine();
// Compter combien de textures_ de ce type existent
int textureCount = 0;
while (GetTexture(type, textureCount) != nullptr)
{
textureCount++;
}
// Afficher toutes les textures_ existantes
ImGui::BeginGroup();
for (int texIndex = 0; texIndex < textureCount; texIndex++)
{
ID3D11ShaderResourceView* texture = GetTexture(type, texIndex);
if (texture)
{
// ID unique pour chaque bouton de texture
std::string buttonId = "tex##" +
std::to_string(typeIndex) + "_" +
std::to_string(texIndex);
if (ImGui::ImageButton(buttonId.c_str(), (ImTextureID)texture, ImVec2(48, 48)))
{
// Ouvrir une bo<62>te de dialogue pour changer la texture
OPENFILENAME ofn;
WCHAR szFile[260];
ZeroMemory(&ofn, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = NULL;
ofn.lpstrFile = szFile;
szFile[0] = '\0';
ofn.nMaxFile = sizeof(szFile);
ofn.lpstrFilter = L"Texture\0*.png;*.jpg;*.dds\0";
ofn.nFilterIndex = 1;
ofn.lpstrInitialDir = NULL;
ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
if (GetOpenFileName(&ofn))
{
// Changer la texture existante
m_model->ChangeTexture(device, context, ofn.lpstrFile, type, texIndex);
}
}
// Afficher l'indice de texture et pr<70>visualisation au survol
if (ImGui::IsItemHovered())
{
ImGui::BeginTooltip();
ImGui::Text("%s %d", typeName.c_str(), texIndex);
ImGui::Image((ImTextureID)texture, ImVec2(192, 192));
ImGui::EndTooltip();
}
ImGui::SameLine();
}
}
// Bouton pour ajouter une nouvelle texture
std::string addButtonLabel = "+##" + std::to_string(typeIndex);
if (ImGui::Button(addButtonLabel.c_str(), ImVec2(48, 48)))
{
// Ouvrir une bo<62>te de dialogue pour ajouter une texture
OPENFILENAME ofn;
WCHAR szFile[260];
ZeroMemory(&ofn, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = NULL;
ofn.lpstrFile = szFile;
szFile[0] = '\0';
ofn.nMaxFile = sizeof(szFile);
ofn.lpstrFilter = L"Texture\0*.png;*.jpg;*.dds\0";
ofn.nFilterIndex = 1;
ofn.lpstrInitialDir = NULL;
ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
if (GetOpenFileName(&ofn))
{
// Ajouter une nouvelle texture
m_model->AddTexture(device, context, ofn.lpstrFile, type);
}
}
ImGui::EndGroup();
ImGui::Separator();
}
ImGui::EndChild();
}
void SetDevice (ID3D11Device* dev) { device = dev; }
void SetContext(ID3D11DeviceContext* ctx) { context = ctx; }
private:
std::shared_ptr<model_class> m_model;
std::string m_modelFilePath;
bool m_isVisible;
ID3D11Device* device;
ID3D11DeviceContext* context;
};
} // namespace ecs

View File

@@ -154,6 +154,11 @@ public:
*/
void SetTranslateMatrix(XMMATRIX matrix) { m_TranslateMatrix = matrix; UpdateWorldMatrix(); }
/**
* Serialize the transform component's state to a string.
* The format is: "TransformComponent:posX:posY:posZ:rotX:rotY:rotZ:scaleX:scaleY:scaleZ"
* @return A string representation of the transform component's state.
*/
std::string Serialize() const override
{
XMFLOAT3 position, rotation, scale;
@@ -169,6 +174,12 @@ public:
return ss.str();
}
/**
* Deserialize the transform component's state from a string.
* The expected format is: "TransformComponent:posX:posY:posZ:rotX:rotY:rotZ:scaleX:scaleY:scaleZ"
* @param data The string representation of the transform component's state.
* @return True if deserialization was successful, otherwise false.
*/
bool Deserialize(const std::string& data) override
{
std::stringstream ss(data);
@@ -198,6 +209,10 @@ public:
return true;
}
/**
* Render the ImGui interface for editing the transform component.
* This method provides draggable controls for position, rotation, and scale.
*/
void OnImGuiRender() override {
XMFLOAT3 position, rotation, scale;
XMStoreFloat3(&position, GetPosition());

View File

@@ -5,6 +5,8 @@
#include <memory>
#include <algorithm>
#include <cassert>
#include <WICTextureLoader.h>
#include <d3d11.h>
#include "camera_class.h"
#include <Fmod/core/inc/fmod.hpp>
@@ -138,12 +140,34 @@ public:
return m_Components;
}
/**
* Set the main camera of the scene to be used by components like AudioComponent.
* @param camera
*/
void SetCamera(camera_class* camera) {m_camera = camera; }
/**
* Get the main camera of the scene.
* @return A pointer to the main camera.
*/
camera_class* GetCamera() const { return m_camera; }
/**
* Set the FMOD sound system to be used by components like AudioComponent.
* @param soundSystem
*/
void SetSoundSystem(FMOD::System* soundSystem) {m_soundSystem = soundSystem; }
/**
* Get the FMOD sound system.
* @return A pointer to the FMOD sound system.
*/
FMOD::System* GetSoundSystem() const { return m_soundSystem; }
void SetDevice (ID3D11Device* dev) { device = dev; }
void SetContext(ID3D11DeviceContext* ctx) { context = ctx; }
ID3D11Device* GetDevice() const { return device; }
ID3D11DeviceContext* GetContext() const { return context; }
private:
/**
@@ -161,6 +185,9 @@ private:
// FMOD sound system
FMOD::System* m_soundSystem = nullptr;
ID3D11Device* device;
ID3D11DeviceContext* context;
};
} // namespace ecs

View File

@@ -3,6 +3,7 @@
#include <vector>
#include <unordered_map>
#include <queue>
#include <d3d11.h>
namespace ecs {
@@ -33,6 +34,8 @@ public:
auto entity = std::make_shared<Entity>(id);
entity->SetCamera(camera_);
entity->SetSoundSystem(sound_system_);
entity->SetDevice(device);
entity->SetContext(context);
m_Entities[id] = entity;
return entity;
@@ -146,18 +149,42 @@ public:
}
/**
* Set the main camera that will be propagate to the entity when creating a new entity.
* @param camera Pointer to the camera_class instance.
*/
void SetCamera(camera_class* camera) { camera_ = camera; }
/**
* Get the main camera used by entities.
* @return Pointer to the camera_class instance.
*/
camera_class* GetCamera() const { return camera_; }
/**
* Set the FMOD sound system that will be propagate to the entity when creating a new entity.
* @param sound_system Pointer to the FMOD::System instance.
*/
void SetSoundSystem(FMOD::System* sound_system) { sound_system_ = sound_system; }
/**
* Get the FMOD sound system used by entities.
* @return Pointer to the FMOD::System instance.
*/
FMOD::System* GetSoundSystem() const { return sound_system_; }
void SetDevice (ID3D11Device* dev) { device = dev; }
void SetContext(ID3D11DeviceContext* ctx) { context = ctx; }
ID3D11Device* GetDevice() const { return device; }
ID3D11DeviceContext* GetContext() const { return context; }
private:
EntityID m_NextEntityID;
std::unordered_map<EntityID, std::shared_ptr<Entity>> m_Entities;
std::queue<EntityID> m_FreeIDs; // IDs <20> r<>utiliser
camera_class* camera_ = nullptr;
FMOD::System* sound_system_ = nullptr;
ID3D11Device* device;
ID3D11DeviceContext* context;
};
} // namespace ecs

View File

@@ -521,6 +521,8 @@ bool application_class::initialize(int screenWidth, int screenHeight, HWND hwnd,
entity_manager_->SetCamera(camera_);
entity_manager_->SetSoundSystem(sound_system_);
entity_manager_->SetDevice(direct_3d_->get_device());
entity_manager_->SetContext(direct_3d_->get_device_context());
}