scene save implemented
This commit is contained in:
@@ -3,6 +3,7 @@ set(CMAKE_CXX_STANDARD 17)
|
||||
|
||||
find_package(OGRE REQUIRED COMPONENTS Bites Overlay CONFIG)
|
||||
find_package(flecs REQUIRED CONFIG)
|
||||
find_package(nlohmann_json REQUIRED)
|
||||
find_package(SDL2 REQUIRED)
|
||||
|
||||
# Collect all source files
|
||||
@@ -10,6 +11,7 @@ set(EDITSCENE_SOURCES
|
||||
main.cpp
|
||||
EditorApp.cpp
|
||||
systems/EditorUISystem.cpp
|
||||
systems/SceneSerializer.cpp
|
||||
ui/TransformEditor.cpp
|
||||
ui/RenderableEditor.cpp
|
||||
camera/EditorCamera.cpp
|
||||
@@ -23,6 +25,7 @@ set(EDITSCENE_HEADERS
|
||||
components/EntityName.hpp
|
||||
components/Relationship.hpp
|
||||
systems/EditorUISystem.hpp
|
||||
systems/SceneSerializer.hpp
|
||||
ui/ComponentEditor.hpp
|
||||
ui/ComponentRegistry.hpp
|
||||
ui/TransformEditor.hpp
|
||||
@@ -38,6 +41,7 @@ target_link_libraries(editSceneEditor
|
||||
OgreBites
|
||||
OgreOverlay
|
||||
flecs::flecs_static
|
||||
nlohmann_json::nlohmann_json
|
||||
)
|
||||
|
||||
target_include_directories(editSceneEditor PRIVATE
|
||||
|
||||
@@ -64,7 +64,7 @@ void EditorApp::setup()
|
||||
// Base setup
|
||||
OgreBites::ApplicationContext::setup();
|
||||
|
||||
// Get root and create scene manager
|
||||
// Create scene manager
|
||||
Ogre::Root *root = getRoot();
|
||||
m_sceneMgr = root->createSceneManager();
|
||||
m_sceneMgr->setAmbientLight(Ogre::ColourValue(0.3f, 0.3f, 0.3f));
|
||||
@@ -129,22 +129,7 @@ void EditorApp::setupECS()
|
||||
|
||||
void EditorApp::createDefaultEntities()
|
||||
{
|
||||
// Create root entity
|
||||
flecs::entity root = m_world.entity("Root");
|
||||
root.set<EntityNameComponent>(EntityNameComponent("Root"));
|
||||
root.add<EditorMarkerComponent>();
|
||||
|
||||
// Create child using flecs::ChildOf relationship
|
||||
flecs::entity child1 = m_world.entity("Child1");
|
||||
child1.set<EntityNameComponent>(EntityNameComponent("Child 1"));
|
||||
child1.add<EditorMarkerComponent>();
|
||||
child1.child_of(root);
|
||||
|
||||
// Create grandchild using flecs::ChildOf relationship
|
||||
flecs::entity grandchild = m_world.entity("Grandchild");
|
||||
grandchild.set<EntityNameComponent>(EntityNameComponent("Grandchild"));
|
||||
grandchild.add<EditorMarkerComponent>();
|
||||
grandchild.child_of(child1);
|
||||
// Start with empty scene - user creates entities as needed
|
||||
}
|
||||
|
||||
void EditorApp::setupLights()
|
||||
|
||||
@@ -79,8 +79,9 @@ void Gizmo::update()
|
||||
|
||||
auto &transform = m_attachedEntity.get<TransformComponent>();
|
||||
if (transform.node) {
|
||||
m_gizmoNode->setPosition(transform.position);
|
||||
m_gizmoNode->setOrientation(transform.rotation);
|
||||
// Use derived (world) position and orientation
|
||||
m_gizmoNode->setPosition(transform.node->_getDerivedPosition());
|
||||
m_gizmoNode->setOrientation(transform.node->_getDerivedOrientation());
|
||||
m_gizmoNode->setVisible(true);
|
||||
}
|
||||
}
|
||||
@@ -192,8 +193,11 @@ bool Gizmo::onMousePressed(const Ogre::Ray &mouseRay)
|
||||
|
||||
m_isDragging = true;
|
||||
auto &transform = m_attachedEntity.get_mut<TransformComponent>();
|
||||
m_dragStartPosition = transform.position;
|
||||
|
||||
// Use derived (world) position for dragging
|
||||
m_dragStartPosition = transform.node->_getDerivedPosition();
|
||||
|
||||
// Get axis direction in world space from gizmo orientation
|
||||
switch (m_selectedAxis) {
|
||||
case Axis::X: m_dragAxisDir = m_gizmoNode->getOrientation() * Ogre::Vector3::UNIT_X; break;
|
||||
case Axis::Y: m_dragAxisDir = m_gizmoNode->getOrientation() * Ogre::Vector3::UNIT_Y; break;
|
||||
@@ -224,10 +228,20 @@ bool Gizmo::onMouseMoved(const Ogre::Ray &mouseRay, const Ogre::Vector2 &mouseDe
|
||||
|
||||
float deltaT = currentT - m_dragStartT;
|
||||
|
||||
transform.position = m_dragStartPosition + m_dragAxisDir * deltaT;
|
||||
// Calculate new world position
|
||||
Ogre::Vector3 newWorldPos = m_dragStartPosition + m_dragAxisDir * deltaT;
|
||||
|
||||
// Convert to local position if node has a parent
|
||||
if (transform.node->getParent()) {
|
||||
transform.position = transform.node->getParent()->convertWorldToLocalPosition(newWorldPos);
|
||||
} else {
|
||||
transform.position = newWorldPos;
|
||||
}
|
||||
|
||||
transform.applyToNode();
|
||||
|
||||
m_gizmoNode->setPosition(transform.position);
|
||||
// Update gizmo to follow (use derived position)
|
||||
m_gizmoNode->setPosition(transform.node->_getDerivedPosition());
|
||||
|
||||
return true;
|
||||
} else if (m_axisX->isVisible()) {
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
[General]
|
||||
FileSystem=resources
|
||||
FileSystem=resources/materials
|
||||
FileSystem=resources/materials/scripts
|
||||
FileSystem=resources/meshes
|
||||
FileSystem=resources/textures
|
||||
FileSystem=resources/buildings
|
||||
@@ -10,7 +11,6 @@ FileSystem=resources/vehicles
|
||||
|
||||
[Popular]
|
||||
FileSystem=resources/materials/programs
|
||||
FileSystem=resources/materials/scripts
|
||||
FileSystem=resources/materials/textures
|
||||
|
||||
[Essential]
|
||||
|
||||
@@ -17,6 +17,7 @@ EditorUISystem::EditorUISystem(flecs::world &world,
|
||||
{
|
||||
registerComponentEditors();
|
||||
m_gizmo = std::make_unique<Gizmo>(m_sceneMgr);
|
||||
m_serializer = std::make_unique<SceneSerializer>(m_world, m_sceneMgr);
|
||||
}
|
||||
|
||||
EditorUISystem::~EditorUISystem() = default;
|
||||
@@ -146,6 +147,18 @@ void EditorUISystem::renderHierarchyWindow()
|
||||
if (ImGui::Begin("Entity Hierarchy", nullptr, windowFlags)) {
|
||||
// Menu bar
|
||||
if (ImGui::BeginMenuBar()) {
|
||||
// File menu
|
||||
if (ImGui::BeginMenu("File")) {
|
||||
if (ImGui::MenuItem("Save Scene", "Ctrl+S")) {
|
||||
saveScene("scene.json");
|
||||
}
|
||||
if (ImGui::MenuItem("Load Scene", "Ctrl+O")) {
|
||||
loadScene("scene.json");
|
||||
}
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
// Entity menu
|
||||
if (ImGui::BeginMenu("Entity")) {
|
||||
if (ImGui::MenuItem("New Entity", "Ctrl+N")) {
|
||||
createNewEntity();
|
||||
@@ -170,6 +183,17 @@ void EditorUISystem::renderHierarchyWindow()
|
||||
}
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
// Settings menu
|
||||
if (ImGui::BeginMenu("Settings")) {
|
||||
if (ImGui::Checkbox("Parent SceneNodes", &m_parentSceneNodes)) {
|
||||
// Toggle applied immediately to new entities
|
||||
}
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("When enabled, child entities' SceneNodes are parented to their parent's SceneNode, inheriting transforms. When disabled, SceneNodes are created at root level.");
|
||||
}
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
ImGui::EndMenuBar();
|
||||
}
|
||||
|
||||
@@ -484,11 +508,21 @@ void EditorUISystem::createChildEntity(flecs::entity parent)
|
||||
entity.set<EntityNameComponent>(EntityNameComponent("Child Entity"));
|
||||
entity.add<EditorMarkerComponent>();
|
||||
|
||||
// Create transform with parent as scene node parent
|
||||
// Create transform
|
||||
TransformComponent transform;
|
||||
auto &parentTransform = parent.get_mut<TransformComponent>();
|
||||
transform.node = parentTransform.node->createChildSceneNode();
|
||||
transform.position = Ogre::Vector3::ZERO;
|
||||
|
||||
// SceneNode parenting depends on setting
|
||||
if (m_parentSceneNodes) {
|
||||
// Child SceneNode inherits parent's transform
|
||||
transform.node = parentTransform.node->createChildSceneNode();
|
||||
transform.position = Ogre::Vector3::ZERO;
|
||||
} else {
|
||||
// Child SceneNode at root level, position relative to parent
|
||||
transform.node = m_sceneMgr->getRootSceneNode()->createChildSceneNode();
|
||||
transform.position = parentTransform.position;
|
||||
}
|
||||
|
||||
transform.rotation = Ogre::Quaternion::IDENTITY;
|
||||
transform.scale = Ogre::Vector3::UNIT_SCALE;
|
||||
entity.set<TransformComponent>(transform);
|
||||
@@ -561,18 +595,26 @@ void EditorUISystem::duplicateEntity(flecs::entity entity)
|
||||
auto &oldTransform = entity.get<TransformComponent>();
|
||||
TransformComponent newTransform;
|
||||
|
||||
// Find parent node
|
||||
Ogre::SceneNode *parentNode = m_sceneMgr->getRootSceneNode();
|
||||
// Find parent entity and node
|
||||
flecs::entity parent = entity.parent();
|
||||
Ogre::SceneNode *parentNode = m_sceneMgr->getRootSceneNode();
|
||||
|
||||
if (parent.is_valid() && parent != 0 &&
|
||||
parent.has<TransformComponent>()) {
|
||||
parentNode = parent.get<TransformComponent>().node;
|
||||
}
|
||||
|
||||
newTransform.node = parentNode->createChildSceneNode();
|
||||
newTransform.position =
|
||||
oldTransform.position +
|
||||
Ogre::Vector3(1, 0, 0); // Offset slightly
|
||||
// SceneNode parenting depends on setting
|
||||
if (m_parentSceneNodes && parent.is_valid() && parent != 0) {
|
||||
// Create as child of parent's SceneNode
|
||||
newTransform.node = parentNode->createChildSceneNode();
|
||||
newTransform.position = oldTransform.position + Ogre::Vector3(1, 0, 0);
|
||||
} else {
|
||||
// Create at root level
|
||||
newTransform.node = m_sceneMgr->getRootSceneNode()->createChildSceneNode();
|
||||
newTransform.position = oldTransform.position + Ogre::Vector3(1, 0, 0);
|
||||
}
|
||||
|
||||
newTransform.rotation = oldTransform.rotation;
|
||||
newTransform.scale = oldTransform.scale;
|
||||
newTransform.applyToNode();
|
||||
@@ -635,3 +677,29 @@ bool EditorUISystem::isDescendantOf(flecs::entity potentialChild,
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void EditorUISystem::saveScene(const std::string& filepath)
|
||||
{
|
||||
if (!m_serializer) return;
|
||||
|
||||
if (m_serializer->saveToFile(filepath)) {
|
||||
Ogre::LogManager::getSingleton().logMessage(
|
||||
"Scene saved to: " + filepath);
|
||||
} else {
|
||||
Ogre::LogManager::getSingleton().logMessage(
|
||||
"Failed to save scene: " + m_serializer->getLastError());
|
||||
}
|
||||
}
|
||||
|
||||
void EditorUISystem::loadScene(const std::string& filepath)
|
||||
{
|
||||
if (!m_serializer) return;
|
||||
|
||||
if (m_serializer->loadFromFile(filepath, this)) {
|
||||
Ogre::LogManager::getSingleton().logMessage(
|
||||
"Scene loaded from: " + filepath);
|
||||
} else {
|
||||
Ogre::LogManager::getSingleton().logMessage(
|
||||
"Failed to load scene: " + m_serializer->getLastError());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,9 +4,11 @@
|
||||
#include <flecs.h>
|
||||
#include <Ogre.h>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include "../ui/ComponentRegistry.hpp"
|
||||
#include "../components/EntityName.hpp"
|
||||
#include "../gizmo/Gizmo.hpp"
|
||||
#include "SceneSerializer.hpp"
|
||||
|
||||
/**
|
||||
* Main UI system for the scene editor
|
||||
@@ -57,7 +59,25 @@ public:
|
||||
*/
|
||||
Gizmo *getGizmo() const { return m_gizmo.get(); }
|
||||
|
||||
/**
|
||||
* Get/set SceneNode parenting mode
|
||||
*/
|
||||
bool getParentSceneNodes() const { return m_parentSceneNodes; }
|
||||
void setParentSceneNodes(bool value) { m_parentSceneNodes = value; }
|
||||
|
||||
/**
|
||||
* Save scene to file
|
||||
*/
|
||||
void saveScene(const std::string& filepath);
|
||||
|
||||
/**
|
||||
* Load scene from file
|
||||
*/
|
||||
void loadScene(const std::string& filepath);
|
||||
|
||||
private:
|
||||
// File menu
|
||||
void renderFileMenu();
|
||||
// Window rendering functions
|
||||
void renderHierarchyWindow();
|
||||
void renderPropertyWindow();
|
||||
@@ -91,6 +111,10 @@ private:
|
||||
ComponentRegistry m_componentRegistry;
|
||||
std::vector<flecs::entity> m_allEntities;
|
||||
std::unique_ptr<Gizmo> m_gizmo;
|
||||
std::unique_ptr<SceneSerializer> m_serializer;
|
||||
|
||||
// Settings
|
||||
bool m_parentSceneNodes = true; // Whether child entities inherit parent's SceneNode
|
||||
|
||||
// Queries
|
||||
flecs::query<EntityNameComponent> m_nameQuery;
|
||||
|
||||
285
src/features/editScene/systems/SceneSerializer.cpp
Normal file
285
src/features/editScene/systems/SceneSerializer.cpp
Normal file
@@ -0,0 +1,285 @@
|
||||
#include "SceneSerializer.hpp"
|
||||
#include "../components/Transform.hpp"
|
||||
#include "../components/Renderable.hpp"
|
||||
#include "../components/EntityName.hpp"
|
||||
#include "../components/EditorMarker.hpp"
|
||||
#include "EditorUISystem.hpp"
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
SceneSerializer::SceneSerializer(flecs::world& world, Ogre::SceneManager* sceneMgr)
|
||||
: m_world(world)
|
||||
, m_sceneMgr(sceneMgr)
|
||||
{
|
||||
}
|
||||
|
||||
bool SceneSerializer::saveToFile(const std::string& filepath)
|
||||
{
|
||||
try {
|
||||
nlohmann::json scene;
|
||||
scene["version"] = "1.0";
|
||||
scene["entities"] = nlohmann::json::array();
|
||||
|
||||
// Collect all entities with EditorMarkerComponent
|
||||
m_world.query_builder<>()
|
||||
.with<EditorMarkerComponent>()
|
||||
.build()
|
||||
.each([&](flecs::entity entity) {
|
||||
// Only save root entities (children will be saved recursively)
|
||||
flecs::entity parent = entity.parent();
|
||||
if (!parent.is_valid() || parent == 0) {
|
||||
scene["entities"].push_back(serializeEntity(entity));
|
||||
}
|
||||
});
|
||||
|
||||
// Write to file
|
||||
std::ofstream file(filepath);
|
||||
if (!file.is_open()) {
|
||||
m_lastError = "Failed to open file for writing: " + filepath;
|
||||
return false;
|
||||
}
|
||||
|
||||
file << scene.dump(4); // Pretty print with 4-space indent
|
||||
file.close();
|
||||
|
||||
return true;
|
||||
} catch (const std::exception& e) {
|
||||
m_lastError = std::string("Save error: ") + e.what();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool SceneSerializer::loadFromFile(const std::string& filepath, EditorUISystem* uiSystem)
|
||||
{
|
||||
try {
|
||||
// Read from file
|
||||
std::ifstream file(filepath);
|
||||
if (!file.is_open()) {
|
||||
m_lastError = "Failed to open file for reading: " + filepath;
|
||||
return false;
|
||||
}
|
||||
|
||||
nlohmann::json scene;
|
||||
file >> scene;
|
||||
file.close();
|
||||
|
||||
// Clear existing entities (optional - could be made configurable)
|
||||
// For now, we'll just add to the existing scene
|
||||
|
||||
// Validate version
|
||||
if (scene.contains("version")) {
|
||||
std::string version = scene["version"];
|
||||
if (version != "1.0") {
|
||||
m_lastError = "Unsupported scene version: " + version;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Clear entity map for new load
|
||||
m_entityMap.clear();
|
||||
|
||||
// Load entities
|
||||
if (scene.contains("entities") && scene["entities"].is_array()) {
|
||||
for (const auto& entityJson : scene["entities"]) {
|
||||
deserializeEntity(entityJson, flecs::entity::null(), uiSystem);
|
||||
}
|
||||
}
|
||||
|
||||
m_entityMap.clear();
|
||||
return true;
|
||||
} catch (const std::exception& e) {
|
||||
m_lastError = std::string("Load error: ") + e.what();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
nlohmann::json SceneSerializer::serializeEntity(flecs::entity entity)
|
||||
{
|
||||
nlohmann::json json;
|
||||
|
||||
// Store entity ID for parent/child relationships
|
||||
json["id"] = entity.id();
|
||||
|
||||
// Serialize components
|
||||
if (entity.has<EntityNameComponent>()) {
|
||||
json["name"] = serializeEntityName(entity);
|
||||
}
|
||||
|
||||
if (entity.has<TransformComponent>()) {
|
||||
json["transform"] = serializeTransform(entity);
|
||||
}
|
||||
|
||||
if (entity.has<RenderableComponent>()) {
|
||||
json["renderable"] = serializeRenderable(entity);
|
||||
}
|
||||
|
||||
// Serialize children
|
||||
json["children"] = nlohmann::json::array();
|
||||
entity.children([&](flecs::entity child) {
|
||||
if (child.has<EditorMarkerComponent>()) {
|
||||
json["children"].push_back(serializeEntity(child));
|
||||
}
|
||||
});
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
void SceneSerializer::deserializeEntity(const nlohmann::json& json, flecs::entity parent, EditorUISystem* uiSystem)
|
||||
{
|
||||
// Create new entity
|
||||
flecs::entity entity = m_world.entity();
|
||||
entity.add<EditorMarkerComponent>();
|
||||
|
||||
// Store in map for potential future reference
|
||||
if (json.contains("id")) {
|
||||
uint64_t id = json["id"];
|
||||
m_entityMap[id] = entity;
|
||||
}
|
||||
|
||||
// Set parent relationship
|
||||
if (parent.is_valid() && parent != 0) {
|
||||
entity.child_of(parent);
|
||||
}
|
||||
|
||||
// Deserialize components
|
||||
if (json.contains("name")) {
|
||||
deserializeEntityName(entity, json["name"]);
|
||||
} else {
|
||||
entity.set<EntityNameComponent>(EntityNameComponent("Entity"));
|
||||
}
|
||||
|
||||
if (json.contains("transform")) {
|
||||
deserializeTransform(entity, json["transform"], parent);
|
||||
}
|
||||
|
||||
if (json.contains("renderable")) {
|
||||
deserializeRenderable(entity, json["renderable"]);
|
||||
}
|
||||
|
||||
// Add to UI system if provided
|
||||
if (uiSystem) {
|
||||
uiSystem->addEntity(entity);
|
||||
}
|
||||
|
||||
// Deserialize children
|
||||
if (json.contains("children") && json["children"].is_array()) {
|
||||
for (const auto& childJson : json["children"]) {
|
||||
deserializeEntity(childJson, entity, uiSystem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nlohmann::json SceneSerializer::serializeTransform(flecs::entity entity)
|
||||
{
|
||||
auto& transform = entity.get<TransformComponent>();
|
||||
nlohmann::json json;
|
||||
|
||||
json["position"] = {
|
||||
{"x", transform.position.x},
|
||||
{"y", transform.position.y},
|
||||
{"z", transform.position.z}
|
||||
};
|
||||
|
||||
json["rotation"] = {
|
||||
{"w", transform.rotation.w},
|
||||
{"x", transform.rotation.x},
|
||||
{"y", transform.rotation.y},
|
||||
{"z", transform.rotation.z}
|
||||
};
|
||||
|
||||
json["scale"] = {
|
||||
{"x", transform.scale.x},
|
||||
{"y", transform.scale.y},
|
||||
{"z", transform.scale.z}
|
||||
};
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
nlohmann::json SceneSerializer::serializeRenderable(flecs::entity entity)
|
||||
{
|
||||
auto& renderable = entity.get<RenderableComponent>();
|
||||
nlohmann::json json;
|
||||
json["meshName"] = renderable.meshName;
|
||||
json["visible"] = renderable.visible;
|
||||
return json;
|
||||
}
|
||||
|
||||
nlohmann::json SceneSerializer::serializeEntityName(flecs::entity entity)
|
||||
{
|
||||
auto& name = entity.get<EntityNameComponent>();
|
||||
nlohmann::json json;
|
||||
json["name"] = name.name;
|
||||
return json;
|
||||
}
|
||||
|
||||
void SceneSerializer::deserializeTransform(flecs::entity entity, const nlohmann::json& json, flecs::entity parentEntity)
|
||||
{
|
||||
TransformComponent transform;
|
||||
|
||||
// Read position
|
||||
if (json.contains("position")) {
|
||||
auto& pos = json["position"];
|
||||
transform.position = Ogre::Vector3(
|
||||
pos.value("x", 0.0f),
|
||||
pos.value("y", 0.0f),
|
||||
pos.value("z", 0.0f)
|
||||
);
|
||||
}
|
||||
|
||||
// Read rotation
|
||||
if (json.contains("rotation")) {
|
||||
auto& rot = json["rotation"];
|
||||
transform.rotation = Ogre::Quaternion(
|
||||
rot.value("w", 1.0f),
|
||||
rot.value("x", 0.0f),
|
||||
rot.value("y", 0.0f),
|
||||
rot.value("z", 0.0f)
|
||||
);
|
||||
}
|
||||
|
||||
// Read scale
|
||||
if (json.contains("scale")) {
|
||||
auto& scl = json["scale"];
|
||||
transform.scale = Ogre::Vector3(
|
||||
scl.value("x", 1.0f),
|
||||
scl.value("y", 1.0f),
|
||||
scl.value("z", 1.0f)
|
||||
);
|
||||
}
|
||||
|
||||
// Create scene node
|
||||
if (parentEntity.is_valid() && parentEntity != 0 && parentEntity.has<TransformComponent>()) {
|
||||
// Child of parent entity's node
|
||||
auto& parentTransform = parentEntity.get<TransformComponent>();
|
||||
if (parentTransform.node) {
|
||||
transform.node = parentTransform.node->createChildSceneNode();
|
||||
} else {
|
||||
transform.node = m_sceneMgr->getRootSceneNode()->createChildSceneNode();
|
||||
}
|
||||
} else {
|
||||
// Root level
|
||||
transform.node = m_sceneMgr->getRootSceneNode()->createChildSceneNode();
|
||||
}
|
||||
|
||||
transform.applyToNode();
|
||||
entity.set<TransformComponent>(transform);
|
||||
}
|
||||
|
||||
void SceneSerializer::deserializeRenderable(flecs::entity entity, const nlohmann::json& json)
|
||||
{
|
||||
RenderableComponent renderable;
|
||||
renderable.meshName = json.value("meshName", "");
|
||||
renderable.visible = json.value("visible", true);
|
||||
|
||||
// Don't create the Ogre::Entity here - it will be created when mesh is loaded
|
||||
renderable.entity = nullptr;
|
||||
|
||||
entity.set<RenderableComponent>(renderable);
|
||||
}
|
||||
|
||||
void SceneSerializer::deserializeEntityName(flecs::entity entity, const nlohmann::json& json)
|
||||
{
|
||||
std::string name = json.value("name", "Entity");
|
||||
entity.set<EntityNameComponent>(EntityNameComponent(name));
|
||||
}
|
||||
59
src/features/editScene/systems/SceneSerializer.hpp
Normal file
59
src/features/editScene/systems/SceneSerializer.hpp
Normal file
@@ -0,0 +1,59 @@
|
||||
#ifndef EDITSCENE_SCENESERIALIZER_HPP
|
||||
#define EDITSCENE_SCENESERIALIZER_HPP
|
||||
|
||||
#pragma once
|
||||
#include <flecs.h>
|
||||
#include <Ogre.h>
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
// Forward declarations
|
||||
class EditorUISystem;
|
||||
|
||||
/**
|
||||
* Scene serializer for saving/loading scenes in JSON format
|
||||
*/
|
||||
class SceneSerializer {
|
||||
public:
|
||||
SceneSerializer(flecs::world& world, Ogre::SceneManager* sceneMgr);
|
||||
|
||||
/**
|
||||
* Save scene to JSON file
|
||||
*/
|
||||
bool saveToFile(const std::string& filepath);
|
||||
|
||||
/**
|
||||
* Load scene from JSON file
|
||||
*/
|
||||
bool loadFromFile(const std::string& filepath, EditorUISystem* uiSystem = nullptr);
|
||||
|
||||
/**
|
||||
* Get last error message
|
||||
*/
|
||||
const std::string& getLastError() const { return m_lastError; }
|
||||
|
||||
private:
|
||||
// Serialization helpers
|
||||
nlohmann::json serializeEntity(flecs::entity entity);
|
||||
void deserializeEntity(const nlohmann::json& json, flecs::entity parent, EditorUISystem* uiSystem);
|
||||
|
||||
// Component serialization
|
||||
nlohmann::json serializeTransform(flecs::entity entity);
|
||||
nlohmann::json serializeRenderable(flecs::entity entity);
|
||||
nlohmann::json serializeEntityName(flecs::entity entity);
|
||||
|
||||
// Component deserialization
|
||||
void deserializeTransform(flecs::entity entity, const nlohmann::json& json, flecs::entity parentEntity);
|
||||
void deserializeRenderable(flecs::entity entity, const nlohmann::json& json);
|
||||
void deserializeEntityName(flecs::entity entity, const nlohmann::json& json);
|
||||
|
||||
flecs::world& m_world;
|
||||
Ogre::SceneManager* m_sceneMgr;
|
||||
std::string m_lastError;
|
||||
|
||||
// Track entity ID mapping for parent/child relationships
|
||||
std::unordered_map<uint64_t, flecs::entity> m_entityMap;
|
||||
};
|
||||
|
||||
#endif // EDITSCENE_SCENESERIALIZER_HPP
|
||||
Reference in New Issue
Block a user