Minor - Implements scene saving and loading - V12.10.0

Adds scene saving and loading functionality, using a component factory for dynamic component creation and serialization.
This allows users to save and load the state of entities, including their components and textures.

A new component factory is introduced to register and create different component types.
Each component implements serialization and deserialization methods, which are used to store and restore the component's state.

A new .ker scene file format is introduced to serialize entity data and to load it back into memory to restore the scene.

Also adds a DemoScene_V12.9.0.ker file to showcase the engine.
This commit is contained in:
2025-09-06 18:59:42 +02:00
parent 118e635415
commit defc1cb795
13 changed files with 518 additions and 374 deletions

View File

@@ -0,0 +1,54 @@
// ComponentFactory.h
#pragma once
#include <unordered_map>
#include <functional>
#include <memory>
#include <string>
#include "entity.h"
#include "component.h"
#include "components/identity_component.h"
#include "components/render_component.h"
#include "components/transform_component.h"
#include "components/physics_component.h"
#include "components/shader_component.h"
#include "components/model_path_component.h"
class ComponentFactory {
public:
static ComponentFactory& Get() {
static ComponentFactory instance;
return instance;
}
template<typename T>
void EnregistrerComposant(const std::string& typeName) {
m_creators[typeName] = [](std::shared_ptr<ecs::Entity> entity) -> std::shared_ptr<ecs::Component> {
return entity->AddComponent<T>();
};
}
std::shared_ptr<ecs::Component> CreerComposant(const std::string& typeName,
std::shared_ptr<ecs::Entity> entity) {
auto it = m_creators.find(typeName);
if (it != m_creators.end()) {
return it->second(entity);
}
return nullptr;
}
private:
std::unordered_map<std::string, std::function<std::shared_ptr<ecs::Component>(std::shared_ptr<ecs::Entity>)>> m_creators;
};
// Fonction d'initialisation pour enregistrer tous les composants
inline void EnregistrerTousLesComposants() {
auto& factory = ComponentFactory::Get();
factory.EnregistrerComposant<ecs::TransformComponent>("TransformComponent");
factory.EnregistrerComposant<ecs::PhysicsComponent>("PhysicsComponent");
factory.EnregistrerComposant<ecs::ShaderComponent>("ShaderComponent");
factory.EnregistrerComposant<ecs::ModelPathComponent>("ModelPathComponent");
factory.EnregistrerComposant<ecs::IdentityComponent>("IdentityComponent");
factory.EnregistrerComposant<ecs::RenderComponent>("RenderComponent");
// Ajouter d'autres composants ici
}

View File

@@ -1,4 +1,6 @@
#pragma once
#include <sstream>
#include "../component.h"
#include <string>
@@ -94,13 +96,15 @@ public:
/**
* Serialize the component to a string.
* Format: "id:name:type"
* Format: "IdentityComponent:id:name:type"
* @return A string representation of the component.
*/
std::string Serialize() const override
{
std::string Serialize() const override {
std::stringstream ss;
ss << m_id << ":" << m_name << ":" << ObjectTypeToString(m_type);
ss << "IdentityComponent:"
<< GetId() << ":"
<< GetName() << ":"
<< ObjectTypeToString(GetType());
return ss.str();
}
@@ -110,31 +114,24 @@ public:
* @param data The string data to deserialize from.
* @return True if deserialization was successful, otherwise false.
*/
bool Deserialize(const std::string& data) override
{
bool Deserialize(const std::string& data) override {
std::stringstream ss(data);
std::string segment;
std::vector<std::string> segments;
while (std::getline(ss, segment, ':'))
{
segments.push_back(segment);
}
if (segments.empty()) return false;
if (segments.size() != 3) return false;
try
{
m_id = std::stoi(segments[0]);
m_name = segments[1];
m_type = StringToObjectType(segments[2]);
return true;
} catch (const std::exception&)
{
return false;
}
std::string type;
std::getline(ss, type, ':');
if (type != "IdentityComponent") return false;
std::string token, name, objectTypeStr;
int id;
std::getline(ss, token, ':'); id = std::stoi(token);
std::getline(ss, name, ':');
std::getline(ss, objectTypeStr);
SetId(id);
SetName(name);
SetType(StringToObjectType(objectTypeStr));
return true;
}

View File

@@ -23,6 +23,37 @@ public:
* @param path The path to set as a std::wstring.
*/
void SetPath(const std::wstring& path) { m_path = path; }
std::string convert_w_string_to_string(const std::wstring& wstr) const
{
if (wstr.empty()) return std::string();
int size_needed = WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), NULL, 0, NULL, NULL);
std::string str(size_needed, 0);
WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), &str[0], size_needed, NULL, NULL);
return str;
}
std::string Serialize() const override {
std::stringstream ss;
ss << "ModelPathComponent:"
<< convert_w_string_to_string(m_path);
return ss.str();
}
bool Deserialize(const std::string& data) override {
std::stringstream ss(data);
std::string type;
std::getline(ss, type, ':');
if (type != "ModelPathComponent") return false;
std::string modelPath;
std::getline(ss, modelPath);
SetPath(std::wstring(modelPath.begin(), modelPath.end()));
return true;
}
private:
std::wstring m_path;

View File

@@ -195,6 +195,44 @@ public:
* @return The current position as an XMVECTOR.
*/
std::string Serialize() const override
{
std::stringstream ss;
ss << "PhysicsComponent:"
<< GetMass() << ":"
<< GetBoundingRadius() << ":"
<< (IsPhysicsEnabled() ? "1" : "0") << ":"
<< (IsGravityEnabled() ? "1" : "0") << ":"
<< (IsGrounded() ? "1" : "0");
return ss.str();
}
bool Deserialize(const std::string& data) override
{
std::stringstream ss(data);
std::string type;
std::getline(ss, type, ':');
if (type != "PhysicsComponent") return false;
std::string token;
float mass, boundingRadius;
bool physicsEnabled, gravityEnabled, isGrounded;
std::getline(ss, token, ':'); mass = std::stof(token);
std::getline(ss, token, ':'); boundingRadius = std::stof(token);
std::getline(ss, token, ':'); physicsEnabled = (token == "1");
std::getline(ss, token, ':'); gravityEnabled = (token == "1");
std::getline(ss, token, ':'); isGrounded = (token == "1");
SetMass(mass);
SetBoundingRadius(boundingRadius);
SetPhysicsEnabled(physicsEnabled);
SetGravityEnabled(gravityEnabled);
SetGrounded(isGrounded);
return true;
}
private:
XMVECTOR m_Velocity;
XMVECTOR m_Acceleration;

View File

@@ -186,6 +186,28 @@ public:
}
}
std::string Serialize() const override {
if (!m_model) return "RenderComponent:NoModel";
std::stringstream ss;
ss << "RenderComponent:HasModel";
return ss.str();
}
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
return true;
}
private:
std::shared_ptr<model_class> m_model;
std::string m_modelFilePath;

View File

@@ -88,6 +88,28 @@ public:
}
}
std::string Serialize() const override
{
std::stringstream ss;
ss << "ShaderComponent:"
<< ShaderTypeToString(GetActiveShader());
return ss.str();
}
bool Deserialize(const std::string& data) override {
std::stringstream ss(data);
std::string type;
std::getline(ss, type, ':');
if (type != "ShaderComponent") return false;
std::string shaderTypeStr;
std::getline(ss, shaderTypeStr);
SetActiveShader(StringToShaderType(shaderTypeStr));
return true;
}
private:
ShaderType m_activeShader;
};

View File

@@ -153,6 +153,50 @@ public:
*/
void SetTranslateMatrix(XMMATRIX matrix) { m_TranslateMatrix = matrix; UpdateWorldMatrix(); }
std::string Serialize() const override
{
XMFLOAT3 position, rotation, scale;
XMStoreFloat3(&position, GetPosition());
XMStoreFloat3(&rotation, GetRotation());
XMStoreFloat3(&scale, GetScale());
std::stringstream ss;
ss << "TransformComponent:"
<< position.x << ":" << position.y << ":" << position.z << ":"
<< rotation.x << ":" << rotation.y << ":" << rotation.z << ":"
<< scale.x << ":" << scale.y << ":" << scale.z;
return ss.str();
}
bool Deserialize(const std::string& data) override
{
std::stringstream ss(data);
std::string type;
std::getline(ss, type, ':');
if (type != "TransformComponent") return false;
std::string token;
XMFLOAT3 position, rotation, scale;
std::getline(ss, token, ':'); position.x = std::stof(token);
std::getline(ss, token, ':'); position.y = std::stof(token);
std::getline(ss, token, ':'); position.z = std::stof(token);
std::getline(ss, token, ':'); rotation.x = std::stof(token);
std::getline(ss, token, ':'); rotation.y = std::stof(token);
std::getline(ss, token, ':'); rotation.z = std::stof(token);
std::getline(ss, token, ':'); scale.x = std::stof(token);
std::getline(ss, token, ':'); scale.y = std::stof(token);
std::getline(ss, token, ':'); scale.z = std::stof(token);
SetPosition(XMLoadFloat3(&position));
SetRotation(XMLoadFloat3(&rotation));
SetScale(XMLoadFloat3(&scale));
return true;
}
private:
XMMATRIX m_ScaleMatrix;
XMMATRIX m_RotateMatrix;