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

@@ -5,11 +5,17 @@
</component>
<component name="ChangeListManager">
<list default="true" id="e81d6e08-efc7-40a0-909d-ec4943d948e9" name="Changes" comment="">
<change afterPath="$PROJECT_DIR$/enginecustom/src/inc/system/ecs/ComponentFactory.h" afterDir="false" />
<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/enginecustom.vcxproj" beforeDir="false" afterPath="$PROJECT_DIR$/enginecustom/enginecustom.vcxproj" afterDir="false" />
<change beforePath="$PROJECT_DIR$/enginecustom/imgui.ini" beforeDir="false" afterPath="$PROJECT_DIR$/enginecustom/imgui.ini" afterDir="false" />
<change beforePath="$PROJECT_DIR$/enginecustom/src/inc/system/ecs/component.h" beforeDir="false" afterPath="$PROJECT_DIR$/enginecustom/src/inc/system/ecs/component.h" afterDir="false" />
<change beforePath="$PROJECT_DIR$/enginecustom/src/inc/system/ecs/components/identity_component.h" beforeDir="false" afterPath="$PROJECT_DIR$/enginecustom/src/inc/system/ecs/components/identity_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/components/model_path_component.h" beforeDir="false" afterPath="$PROJECT_DIR$/enginecustom/src/inc/system/ecs/components/model_path_component.h" afterDir="false" />
<change beforePath="$PROJECT_DIR$/enginecustom/src/inc/system/ecs/components/physics_component.h" beforeDir="false" afterPath="$PROJECT_DIR$/enginecustom/src/inc/system/ecs/components/physics_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/shader_component.h" beforeDir="false" afterPath="$PROJECT_DIR$/enginecustom/src/inc/system/ecs/components/shader_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/scene_manager.h" beforeDir="false" afterPath="$PROJECT_DIR$/enginecustom/src/inc/system/scene_manager.h" afterDir="false" />
<change beforePath="$PROJECT_DIR$/enginecustom/src/src/system/scene_manager.cpp" beforeDir="false" afterPath="$PROJECT_DIR$/enginecustom/src/src/system/scene_manager.cpp" afterDir="false" />
</list>
<option name="SHOW_DIALOG" value="false" />
@@ -24,11 +30,13 @@
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
</component>
<component name="HighlightingSettingsPerFile">
<setting file="cidr-memory-view://2" root0="FORCE_HIGHLIGHTING" />
<setting file="file://C:/Program Files (x86)/Windows Kits/10/Include/10.0.26100.0/um/d3d11.h" root0="SKIP_HIGHLIGHTING" />
<setting file="file://C:/Program Files (x86)/Windows Kits/10/Include/10.0.26100.0/um/dinput.h" root0="SKIP_HIGHLIGHTING" />
<setting file="file://C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Tools/MSVC/14.44.35207/include/memory" root0="SKIP_HIGHLIGHTING" />
<setting file="file://$PROJECT_DIR$/enginecustom/include/Inc/VertexTypes.h" root0="SKIP_HIGHLIGHTING" />
<setting file="file://$PROJECT_DIR$/enginecustom/include/Vulkan/Include/vulkan/vulkan_core.h" root0="SKIP_HIGHLIGHTING" />
<setting file="file://$PROJECT_DIR$/enginecustom/src/inc/system/ecs/ComponentFactory.h" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$PROJECT_DIR$/enginecustom/src/inc/system/ecs/component.h" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$PROJECT_DIR$/enginecustom/src/inc/system/ecs/components/identity_component.h" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$PROJECT_DIR$/enginecustom/src/inc/system/ecs/components/model_path_component.h" root0="FORCE_HIGHLIGHTING" />
@@ -241,6 +249,10 @@
<workItem from="1755617169013" duration="222000" />
<workItem from="1757101936080" duration="185000" />
<workItem from="1757158576637" duration="2501000" />
<workItem from="1757167799006" duration="45000" />
<workItem from="1757167889796" duration="7081000" />
<workItem from="1757175031271" duration="2289000" />
<workItem from="1757177353935" duration="305000" />
</task>
<task id="LOCAL-00001" summary="Minor update - viewport window tweak">
<option name="closed" value="true" />

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
ShaderComponent:LIGHTING
ModelPathComponent:Content/Assets/Kobject/86.obj
TextureData:1:assets/Texture/Bricks2K.png:1:assets/Texture/BricksNRM2K.png:1:assets/Texture/BricksGLOSS2K.png:0
EndEntity

View File

@@ -120,6 +120,7 @@
<ClInclude Include="src\inc\system\d_3d_class.h" />
<ClInclude Include="src\inc\system\display_plane_class.h" />
<ClInclude Include="src\inc\system\ecs\component.h" />
<ClInclude Include="src\inc\system\ecs\ComponentFactory.h" />
<ClInclude Include="src\inc\system\ecs\components\identity_component.h" />
<ClInclude Include="src\inc\system\ecs\components\model_path_component.h" />
<ClInclude Include="src\inc\system\ecs\components\physics_component.h" />

View File

@@ -16,7 +16,7 @@ DockId=0x00000005,0
[Window][render Stats]
Pos=0,630
Size=792,231
Size=1584,231
Collapsed=0
DockId=0x00000009,0
@@ -27,14 +27,14 @@ Collapsed=0
DockId=0x0000000B,0
[Window][Terrain]
Pos=236,19
Pos=0,19
Size=266,842
Collapsed=0
DockId=0x00000007,0
[Window][Log Window]
Pos=794,630
Size=790,231
Pos=0,630
Size=1584,231
Collapsed=0
DockId=0x0000000A,0
@@ -42,11 +42,11 @@ DockId=0x0000000A,0
Pos=0,19
Size=234,609
Collapsed=0
DockId=0x0000000B,1
DockId=0x0000000B,0
[Window][Engine Settings]
Pos=1267,631
Size=317,230
Pos=1267,462
Size=317,166
Collapsed=0
DockId=0x00000006,0

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;

View File

@@ -4,11 +4,18 @@
#include <vector>
#include "ecs/entity.h"
#include "ecs/ComponentFactory.h"
class d_3d_class;
class object;
class application_class;
static inline std::string trim(const std::string& s) {
size_t start = s.find_first_not_of(" \t\r\n");
size_t end = s.find_last_not_of(" \t\r\n");
return (start == std::string::npos) ? "" : s.substr(start, end - start + 1);
}
class scene_manager
{
public:

View File

@@ -18,6 +18,18 @@ bool scene_manager::initialize(application_class* app)
}
app_ = app;
if (app_ == nullptr) {
Logger::Get().Log("Application pointer is null", __FILE__, __LINE__, Logger::LogLevel::Error);
return false;
}
direct_3d_ = app_->get_direct_3d();
if (!direct_3d_) {
Logger::Get().Log("Direct3D pointer is null", __FILE__, __LINE__, Logger::LogLevel::Error);
return false;
}
return true;
}
@@ -65,368 +77,264 @@ bool scene_manager::save_scene_as() {
}
bool scene_manager::load_scene() {
Logger::Get().Log("Loading scene from " , __FILE__, __LINE__, Logger::LogLevel::Info);
object_id_ = app_->get_object_id();
// Ouvrir une bo<62>te de dialogue pour s<>lectionner un fichier .ker
OPENFILENAME ofn;
wchar_t szFile[260] = { 0 };
ZeroMemory(&ofn, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = app_->get_hwnd();
ofn.lpstrFile = szFile;
ofn.nMaxFile = sizeof(szFile);
ofn.lpstrFilter = L"Ker Scene\0*.ker\0";
ofn.nFilterIndex = 1;
ofn.lpstrFileTitle = NULL;
ofn.nMaxFileTitle = 0;
ofn.lpstrInitialDir = NULL;
ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
ofn.lpstrDefExt = L"ker";
if (GetOpenFileName(&ofn) != TRUE) {
Logger::Get().Log("Load scene canceled or failed", __FILE__, __LINE__, Logger::LogLevel::Warning);
return false; // L'utilisateur a annul<75> la bo<62>te de dialogue
}
std::filesystem::path filepath = ofn.lpstrFile;
scene_path_ = convert_w_string_to_string(filepath.wstring());
if (scene_path_.empty()) {
Logger::Get().Log("Invalid scene path", __FILE__, __LINE__, Logger::LogLevel::Error);
return false;
}
Logger::Get().Log("Loading scene from: " + scene_path_, __FILE__, __LINE__, Logger::LogLevel::Info);
w_folder_ = app_->get_w_folder();
direct_3d_ = app_->get_direct_3d();
std::wstring scenePath = get_scene_path();
std::filesystem::current_path(w_folder_);
if (!scenePath.empty()) {
scene_path_ = convert_w_string_to_string(scenePath);
}
std::ifstream inFile(scene_path_);
if (!inFile.is_open()) {
Logger::Get().Log("Failed to open file for loading scene: " + scene_path_, __FILE__, __LINE__, Logger::LogLevel::Error);
return false;
}
// S'assurer que les composants sont enregistr<74>s
EnregistrerTousLesComposants();
// R<>initialiser l'ID d'objet le plus <20>lev<65>
object_id_ = 0;
// R<>cup<75>rer l'EntityManager pour cr<63>er de nouvelles entit<69>s
auto entity_manager = app_->get_entity_manager();
// Supprimer toutes les entit<69>s existantes
entity_manager->Clear();
// Sauvegarder le r<>pertoire de travail actuel
std::wstring currentDirectory = w_folder_;
std::string line;
while (std::getline(inFile, line)) {
std::istringstream iss(line);
int id;
std::string name;
XMFLOAT3 position, rotation, scale;
std::string modelPath;
std::string shaderTypeStr;
float boundingRadius;
std::string objectTypeStr;
float mass;
bool physicsEnabled;
// Lire les donn<6E>es de base de l'entit<69>
iss >> id >> name
>> position.x >> position.y >> position.z
>> rotation.x >> rotation.y >> rotation.z
>> scale.x >> scale.y >> scale.z;
// Lire le chemin du mod<6F>le - v<>rifier s'il est vide
iss >> modelPath;
// Si le chemin du mod<6F>le est vide ou commence par une lettre majuscule (probablement un type de shader),
// c'est qu'il a <20>t<EFBFBD> omis - utilisez une valeur par d<>faut
if (modelPath.empty() || (modelPath[0] >= 'A' && modelPath[0] <= 'Z')) {
// Reculer le curseur de lecture pour lire le type de shader <20> la place
iss.seekg(-static_cast<int>(modelPath.length()), std::ios::cur);
modelPath = "assets/Model/TXT/cube.txt"; // Valeur par d<>faut
}
iss >> shaderTypeStr
>> boundingRadius >> objectTypeStr
>> mass >> physicsEnabled;
if (iss.fail()) {
Logger::Get().Log("Failed to parse entity data: " + line, __FILE__, __LINE__, Logger::LogLevel::Error);
continue;
}
// Mettre <20> jour l'ID d'objet le plus <20>lev<65> si n<>cessaire
if (id >= object_id_) {
object_id_ = id + 1;
}
// Convertir le chemin du mod<6F>le en wstring
std::wstring wModelPath(modelPath.begin(), modelPath.end());
// V<>rifier si le chemin est relatif
if (modelPath != "NoModel" && modelPath.length() > 1 && modelPath[1] != ':') {
// C'est un chemin relatif, pr<70>fixer avec le r<>pertoire de travail
if (currentDirectory.back() != L'/' && currentDirectory.back() != L'\\') {
// Ajouter un s<>parateur si n<>cessaire
wModelPath = currentDirectory + L"\\" + wModelPath;
} else {
wModelPath = currentDirectory + wModelPath;
}
}
// Cr<43>er le conteneur de textures pour stocker les chemins
TextureContainer objectTextures;
// Vider les conteneurs de chemins de textures
objectTextures.diffusePaths.clear();
objectTextures.normalPaths.clear();
objectTextures.specularPaths.clear();
objectTextures.alphaPaths.clear();
// Lire les chemins des textures diffuses
int diffuseTextureCount;
iss >> diffuseTextureCount;
for (int i = 0; i < diffuseTextureCount; i++) {
std::string texturePath;
iss >> texturePath;
std::wstring wTexturePath(texturePath.begin(), texturePath.end());
objectTextures.diffusePaths.push_back(wTexturePath);
}
// Lire les chemins des textures normales
int normalTextureCount;
iss >> normalTextureCount;
for (int i = 0; i < normalTextureCount; i++) {
std::string texturePath;
iss >> texturePath;
std::wstring wTexturePath(texturePath.begin(), texturePath.end());
objectTextures.normalPaths.push_back(wTexturePath);
}
// Lire les chemins des textures sp<73>culaires
int specularTextureCount;
iss >> specularTextureCount;
for (int i = 0; i < specularTextureCount; i++) {
std::string texturePath;
iss >> texturePath;
std::wstring wTexturePath(texturePath.begin(), texturePath.end());
objectTextures.specularPaths.push_back(wTexturePath);
}
// Lire les chemins des textures alpha
int alphaTextureCount;
iss >> alphaTextureCount;
for (int i = 0; i < alphaTextureCount; i++) {
std::string texturePath;
iss >> texturePath;
std::wstring wTexturePath(texturePath.begin(), texturePath.end());
objectTextures.alphaPaths.push_back(wTexturePath);
}
// V<>rifier si on a un mod<6F>le <20> charger
if (modelPath == "NoModel") {
Logger::Get().Log("Skipping entity without model: " + name, __FILE__, __LINE__, Logger::LogLevel::Warning);
continue;
}
// R<>cup<75>rer le cache de mod<6F>les de l'application
auto& modelCache = app_->get_model_cache();
std::shared_ptr<model_class> sharedModel;
// V<>rifier si le mod<6F>le existe d<>j<EFBFBD> dans le cache
std::string modelKey = modelPath;
auto it = modelCache.find(modelKey);
if (it != modelCache.end()) {
// Utiliser le mod<6F>le existant du cache
Logger::Get().Log("Using cached model for: " + modelKey, __FILE__, __LINE__, Logger::LogLevel::Info);
sharedModel = it->second;
} else {
// Cr<43>er un nouveau mod<6F>le
char modelFilename[256];
size_t convertedChars = 0;
wcstombs_s(&convertedChars, modelFilename, sizeof(modelFilename), wModelPath.c_str(), _TRUNCATE);
Logger::Get().Log("Loading model: " + std::string(modelFilename), __FILE__, __LINE__, Logger::LogLevel::Info);
// Cr<43>er et initialiser le mod<6F>le
auto newModel = std::make_shared<model_class>();
// Pr<50>charger les textures
if (!newModel->PreloadTextures(direct_3d_->get_device(), direct_3d_->get_device_context(), objectTextures)) {
Logger::Get().Log("Failed to preload textures for: " + name, __FILE__, __LINE__, Logger::LogLevel::Error);
continue;
}
if (!newModel->Initialize(direct_3d_->get_device(), direct_3d_->get_device_context(), modelFilename, objectTextures)) {
Logger::Get().Log("Failed to initialize model: " + name, __FILE__, __LINE__, Logger::LogLevel::Error);
continue;
}
// Ajouter le mod<6F>le au cache
modelCache[modelKey] = newModel;
sharedModel = newModel;
}
// Cr<43>er une nouvelle entit<69> avec l'EntityManager
auto entity = entity_manager->CreateEntity();
// Ajouter un composant d'identit<69>
auto identityComponent = entity->AddComponent<ecs::IdentityComponent>(id);
identityComponent->SetName(name);
identityComponent->SetType(ecs::IdentityComponent::StringToObjectType(objectTypeStr));
// Ajouter un composant de transformation
auto transformComponent = entity->AddComponent<ecs::TransformComponent>();
transformComponent->SetPosition(XMLoadFloat3(&position));
transformComponent->SetRotation(XMLoadFloat3(&rotation));
transformComponent->SetScale(XMLoadFloat3(&scale));
transformComponent->UpdateWorldMatrix();
// Ajouter un composant de rendu avec le mod<6F>le
auto renderComponent = entity->AddComponent<ecs::RenderComponent>();
renderComponent->InitializeWithModel(sharedModel);
// Ajouter un composant de shader
auto shaderComponent = entity->AddComponent<ecs::ShaderComponent>();
shaderComponent->SetActiveShader(ecs::ShaderComponent::StringToShaderType(shaderTypeStr));
// Ajouter un composant de chemin de mod<6F>le
auto modelPathComponent = entity->AddComponent<ecs::ModelPathComponent>();
modelPathComponent->SetPath(wModelPath);
// Ajouter un composant de physique si n<>cessaire
auto physicsComponent = entity->AddComponent<ecs::PhysicsComponent>();
physicsComponent->Initialize();
physicsComponent->SetMass(mass);
physicsComponent->SetBoundingRadius(boundingRadius);
physicsComponent->SetPhysicsEnabled(physicsEnabled);
Logger::Get().Log("Entity loaded: " + name + " with ID: " + std::to_string(id), __FILE__, __LINE__, Logger::LogLevel::Info);
std::ifstream inFile(scene_path_);
if (!inFile.is_open()) {
Logger::Get().Log("<EFBFBD>chec de l'ouverture du fichier", __FILE__, __LINE__, Logger::LogLevel::Error);
return false;
}
// Mettre <20> jour l'ID global dans l'application
app_->set_object_id(object_id_);
auto entity_manager = app_->get_entity_manager();
entity_manager->Clear();
std::string line;
std::shared_ptr<ecs::Entity> currentEntity = nullptr;
TextureContainer currentTextures;
// Mettre <20> jour les statistiques apr<70>s le chargement
app_->update_stats_after_modification();
Logger::Get().Log("Scene loaded successfully from " + scene_path_, __FILE__, __LINE__, Logger::LogLevel::Info);
// Cache de mod<6F>le pour <20>viter de charger plusieurs fois le m<>me mod<6F>le
auto& modelCache = app_->get_model_cache();
while (std::getline(inFile, line)) {
line = trim(line);
if (line.substr(0, 7) == "Entity:") {
// Format: Entity:id:name
std::stringstream ss(line.substr(7));
std::string idStr, name;
std::getline(ss, idStr, ':');
std::getline(ss, name);
int id = std::stoi(idStr);
currentEntity = entity_manager->CreateEntity();
// Ajouter IdentityComponent en premier
auto identity = currentEntity->AddComponent<ecs::IdentityComponent>(id);
identity->SetName(name);
// R<>initialiser les donn<6E>es de texture pour cette entit<69>
currentTextures = TextureContainer();
}
else if (line == "EndEntity") {
// 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);
// 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;
}
}
// 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);
}
}
}
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(':'));
// Cr<43>er le composant via la factory et le d<>s<EFBFBD>rialiser
auto& factory = ComponentFactory::Get();
auto component = factory.CreerComposant(componentType, currentEntity);
if (component) {
component->Deserialize(line);
}
}
}
Logger::Get().Log("Sc<EFBFBD>ne charg<72>e avec succ<63>s", __FILE__, __LINE__, Logger::LogLevel::Info);
return true;
}
bool scene_manager::save_scene() {
bool scene_manager::save_scene() {
entity_ = app_->get_entity_manager()->GetAllEntities();
if (scene_path_.empty()) {
// Si le chemin de la sc<73>ne est vide, fallback vers la fonction de sauvegarde as
if (!save_scene_as()) {
Logger::Get().Log("Scene save cancelled by user", __FILE__, __LINE__, Logger::LogLevel::Info);
return false;
}
if (scene_path_.empty() && !save_scene_as()) {
return false;
}
std::ofstream outFile(scene_path_);
if (!outFile.is_open()) {
Logger::Get().Log("Failed to open file for saving scene", __FILE__, __LINE__, Logger::LogLevel::Error);
Logger::Get().Log("<EFBFBD>chec de l'ouverture du fichier", __FILE__, __LINE__, Logger::LogLevel::Error);
return false;
}
outFile << entity_.size() << std::endl;
for (const auto& entity : entity_) {
// R<>cup<75>rer l'ID de l'entit<69> via IdentityComponent
auto identity = entity->GetComponent<ecs::IdentityComponent>();
if (!identity) continue;
for (const auto& entity : entity_)
{
const auto& components = entity->GetAllComponents();
// <20>crire l'en-t<>te de l'entit<69>
outFile << "Entity:" << identity->GetId() << ":" << identity->GetName() << std::endl;
outFile << components.size() << std::endl;
for (const auto& component : components)
{
outFile << typeid(*component).name() << std::endl;
outFile << component->Serialize() << std::endl;
// S<>rialiser tous les composants
for (const auto& [typeId, component] : entity->GetAllComponents()) {
std::string serializedData = component->Serialize();
if (!serializedData.empty()) {
outFile << serializedData << std::endl;
}
}
// 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;
}
// for (const auto& object : entity_) {
// XMFLOAT3 position, scale, rotation;
// int id = 0;
// int mass = 0;
// float boundingRadius = 0;
// std::string name = "NONE";
// std::string shaderType = "NONE";
// std::string objectType = "NONE";
// std::wstring model_path = L"";
// bool physics_enabled = false;
//
// auto transform = object->GetComponent<ecs::TransformComponent>();
// if (transform) {
// // convert XMVECTOR to XMFLOAT3
// XMStoreFloat3(&position, transform->GetPosition());
// XMStoreFloat3(&rotation, transform->GetRotation());
// XMStoreFloat3(&scale, transform->GetScale());
// }
//
//
// auto identity = object->GetComponent<ecs::IdentityComponent>();
// if (identity) {
//
// id = identity->GetId();
// name = identity->GetName();
// objectType = identity->ObjectTypeToString(identity->GetType());
//
// }
//
// auto model_path_component = object->GetComponent<ecs::ModelPathComponent>();
// if (model_path_component) {
//
// model_path = model_path_component->GetPath();
// }
//
// auto shader = object->GetComponent<ecs::ShaderComponent>();
// if (shader)
// {
// shaderType = shader->ShaderTypeToString(shader->GetActiveShader());
// }
//
// auto physics = object->GetComponent<ecs::PhysicsComponent>();
// if (physics) {
// physics_enabled = physics->IsPhysicsEnabled();
// mass = physics->GetMass();
// boundingRadius = physics->GetBoundingRadius();
// }
//
// // <20>crire les donn<6E>es de base de l'objet
// outFile << id << " "
// << name << " "
// << position.x << " " << position.y << " " << position.z << " "
// << rotation.x << " " << rotation.y << " " << rotation.z << " "
// << scale.x << " " << scale.y << " " << scale.z << " "
// << convert_w_string_to_string(model_path) << " "
// << shaderType << " "
// << boundingRadius << " "
// << objectType << " "
// << mass << " "
// << physics_enabled;
//
// // Sauvegarder les chemins des textures_
// // Format: nombre de textures_ diffuses, puis les chemins
// // M<>me chose pour les autres types de textures_
//
//
// auto render = object->GetComponent<ecs::RenderComponent>();
// if (render)
// {
// const auto& model = render->GetModel();
//
// const auto& textureContainer = model->GetTextureContainer();
//
// const auto& diffusePaths = textureContainer.GetPaths(TextureType::Diffuse);
// outFile << " " << diffusePaths.size();
// for (const auto& path : diffusePaths) {
// outFile << " " << convert_w_string_to_string(path);
// }
//
// const auto& normalPaths = textureContainer.GetPaths(TextureType::Normal);
// outFile << " " << normalPaths.size();
// for (const auto& path : normalPaths) {
// outFile << " " << convert_w_string_to_string(path);
// }
// const auto& specularPaths = textureContainer.GetPaths(TextureType::Specular);
// outFile << " " << specularPaths.size();
// for (const auto& path : specularPaths) {
// outFile << " " << convert_w_string_to_string(path);
// }
// 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.close();
Logger::Get().Log("Scene saved successfully to " + scene_path_, __FILE__, __LINE__, Logger::LogLevel::Info);
Logger::Get().Log("Sc<EFBFBD>ne sauvegard<EFBFBD>e avec succ<63>s: " + scene_path_, __FILE__, __LINE__, Logger::LogLevel::Info);
return true;
}