Added character models and lua scripts to groups

This commit is contained in:
2026-04-18 11:35:38 +03:00
parent 79b6af1fff
commit e2960d67e4
4 changed files with 444 additions and 395 deletions

View File

@@ -161,6 +161,12 @@ add_custom_command(TARGET editSceneEditor POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
"${CMAKE_BINARY_DIR}/resources"
"${CMAKE_CURRENT_BINARY_DIR}/resources"
COMMAND ${CMAKE_COMMAND} -E copy_directory
"${CMAKE_BINARY_DIR}/characters"
"${CMAKE_CURRENT_BINARY_DIR}/characters"
COMMAND ${CMAKE_COMMAND} -E copy_directory
"${CMAKE_BINARY_DIR}/lua-scripts"
"${CMAKE_CURRENT_BINARY_DIR}/lua-scripts"
COMMAND ${CMAKE_COMMAND} -E copy
"${CMAKE_CURRENT_SOURCE_DIR}/resources.cfg"
"${CMAKE_CURRENT_BINARY_DIR}/resources.cfg"

View File

@@ -40,7 +40,7 @@
ImGuiRenderListener::ImGuiRenderListener(Ogre::ImGuiOverlay *imguiOverlay,
EditorUISystem *uiSystem,
Ogre::RenderWindow* renderWindow)
Ogre::RenderWindow *renderWindow)
: m_imguiOverlay(imguiOverlay)
, m_uiSystem(uiSystem)
, m_renderWindow(renderWindow)
@@ -52,12 +52,12 @@ void ImGuiRenderListener::preViewportUpdate(
const Ogre::RenderTargetViewportEvent &evt)
{
(void)evt;
// Calculate delta time
unsigned long currentTime = m_timer.getMilliseconds();
m_deltaTime = (currentTime - m_lastTime) / 1000.0f;
m_lastTime = currentTime;
// Start ImGui frame before viewport renders
Ogre::ImGuiOverlay::NewFrame();
@@ -71,13 +71,15 @@ void ImGuiRenderListener::postViewportUpdate(
const Ogre::RenderTargetViewportEvent &evt)
{
(void)evt;
// Capture stats after rendering (they're updated at end of frame)
if (m_renderWindow && m_uiSystem) {
Ogre::RenderTarget::FrameStats stats = m_renderWindow->getStatistics();
m_uiSystem->setLastBatchCount(static_cast<int>(stats.batchCount));
Ogre::RenderTarget::FrameStats stats =
m_renderWindow->getStatistics();
m_uiSystem->setLastBatchCount(
static_cast<int>(stats.batchCount));
}
// End ImGui frame after viewport renders
ImGui::EndFrame();
}
@@ -101,20 +103,21 @@ EditorApp::~EditorApp()
if (m_uiSystem) {
m_uiSystem->shutdown();
}
// Delete all editor entities before OGRE cleanup
// This ensures all components with Ogre resources are cleaned up while SceneManager exists
// Collect entities first, then delete after iteration (can't modify during iteration)
std::vector<flecs::entity> entitiesToDelete;
m_world.query<EditorMarkerComponent>().each([&](flecs::entity e, EditorMarkerComponent) {
entitiesToDelete.push_back(e);
});
for (auto& e : entitiesToDelete) {
m_world.query<EditorMarkerComponent>().each(
[&](flecs::entity e, EditorMarkerComponent) {
entitiesToDelete.push_back(e);
});
for (auto &e : entitiesToDelete) {
if (e.is_alive()) {
e.destruct();
}
}
// Release all systems
m_proceduralMeshSystem.reset();
m_proceduralMaterialSystem.reset();
@@ -127,7 +130,7 @@ EditorApp::~EditorApp()
m_imguiListener.reset();
m_uiSystem.reset();
m_camera.reset();
// Now OGRE can shut down safely
// Singletons are managed by OGRE, don't delete them
}
@@ -141,7 +144,8 @@ void EditorApp::setup()
// Get root and create scene manager
Ogre::Root *root = getRoot();
m_sceneMgr = root->createSceneManager();
m_sceneMgr->setAmbientLight(Ogre::ColourValue(0.3f, 0.3f, 0.3f));
m_sceneMgr->setAmbientLight(
Ogre::ColourValue(0.3f, 0.3f, 0.3f));
// Add scene manager to RTShader generator
Ogre::RTShader::ShaderGenerator *shadergen =
@@ -164,8 +168,8 @@ void EditorApp::setup()
}
// Setup camera
m_camera =
std::make_unique<EditorCamera>(m_sceneMgr, getRenderWindow());
m_camera = std::make_unique<EditorCamera>(m_sceneMgr,
getRenderWindow());
// Setup ECS and scene
setupECS();
@@ -175,46 +179,58 @@ void EditorApp::setup()
createDefaultEntities();
// Setup UI system
m_uiSystem = std::make_unique<EditorUISystem>(m_world, m_sceneMgr, getRenderWindow());
m_uiSystem = std::make_unique<EditorUISystem>(
m_world, m_sceneMgr, getRenderWindow());
// Setup physics system
m_physicsSystem = std::make_unique<EditorPhysicsSystem>(m_world, m_sceneMgr);
m_physicsSystem = std::make_unique<EditorPhysicsSystem>(
m_world, m_sceneMgr);
m_physicsSystem->initialize();
m_uiSystem->setPhysicsSystem(m_physicsSystem.get());
// Setup light system
m_lightSystem = std::make_unique<EditorLightSystem>(m_world, m_sceneMgr);
m_lightSystem = std::make_unique<EditorLightSystem>(m_world,
m_sceneMgr);
// Setup camera system
m_cameraSystem = std::make_unique<EditorCameraSystem>(m_world, m_sceneMgr,
getRenderWindow());
m_cameraSystem = std::make_unique<EditorCameraSystem>(
m_world, m_sceneMgr, getRenderWindow());
// Setup LOD system
m_lodSystem = std::make_unique<EditorLodSystem>(m_world, m_sceneMgr);
m_lodSystem =
std::make_unique<EditorLodSystem>(m_world, m_sceneMgr);
m_lodSystem->initialize();
// Setup StaticGeometry system
m_staticGeometrySystem = std::make_unique<StaticGeometrySystem>(m_world, m_sceneMgr);
m_staticGeometrySystem = std::make_unique<StaticGeometrySystem>(
m_world, m_sceneMgr);
m_staticGeometrySystem->initialize();
// Setup ProceduralTexture system
m_proceduralTextureSystem = std::make_unique<ProceduralTextureSystem>(m_world, m_sceneMgr);
m_proceduralTextureSystem =
std::make_unique<ProceduralTextureSystem>(m_world,
m_sceneMgr);
m_proceduralTextureSystem->initialize();
// Setup ProceduralMaterial system
m_proceduralMaterialSystem = std::make_unique<ProceduralMaterialSystem>(m_world, m_sceneMgr);
m_proceduralMaterialSystem =
std::make_unique<ProceduralMaterialSystem>(m_world,
m_sceneMgr);
m_proceduralMaterialSystem->initialize();
// Setup ProceduralMesh system
m_proceduralMeshSystem = std::make_unique<ProceduralMeshSystem>(m_world, m_sceneMgr);
m_proceduralMeshSystem = std::make_unique<ProceduralMeshSystem>(
m_world, m_sceneMgr);
m_proceduralMeshSystem->initialize();
// Setup CellGrid system
m_cellGridSystem = std::make_unique<CellGridSystem>(m_world, m_sceneMgr);
m_cellGridSystem =
std::make_unique<CellGridSystem>(m_world, m_sceneMgr);
m_cellGridSystem->initialize();
// Setup RoomLayout system
m_roomLayoutSystem = std::make_unique<RoomLayoutSystem>(m_world, m_sceneMgr);
m_roomLayoutSystem =
std::make_unique<RoomLayoutSystem>(m_world, m_sceneMgr);
m_roomLayoutSystem->initialize();
// Add default entities to UI cache
@@ -230,9 +246,10 @@ void EditorApp::setup()
// Register input listeners
addInputListener(this);
addInputListener(getImGuiInputListener());
} catch (const std::exception& e) {
Ogre::LogManager::getSingleton().logMessage("Setup failed: " + Ogre::String(e.what()));
} catch (const std::exception &e) {
Ogre::LogManager::getSingleton().logMessage(
"Setup failed: " + Ogre::String(e.what()));
throw;
}
}
@@ -244,34 +261,34 @@ void EditorApp::setupECS()
m_world.component<TransformComponent>();
m_world.component<RenderableComponent>();
m_world.component<EditorMarkerComponent>();
// Register physics components
m_world.component<PhysicsColliderComponent>();
m_world.component<GeneratedPhysicsTag>();
m_world.component<RigidBodyComponent>();
// Register light and camera components
m_world.component<LightComponent>();
m_world.component<CameraComponent>();
// Register LOD components
m_world.component<LodComponent>();
m_world.component<LodSettingsComponent>();
// Register StaticGeometry components
m_world.component<StaticGeometryComponent>();
m_world.component<StaticGeometryMemberComponent>();
// Register ProceduralTexture component
m_world.component<ProceduralTextureComponent>();
// Register ProceduralMaterial component
m_world.component<ProceduralMaterialComponent>();
// Register Primitive and TriangleBuffer components
m_world.component<PrimitiveComponent>();
m_world.component<TriangleBufferComponent>();
// Register CellGrid/Town components
CellGridModule::registerComponents(m_world);
}
@@ -401,47 +418,47 @@ bool EditorApp::frameRenderingQueued(const Ogre::FrameEvent &evt)
if (m_physicsSystem) {
m_physicsSystem->update(evt.timeSinceLastFrame);
}
// Update lights
if (m_lightSystem) {
m_lightSystem->update();
}
// Update cameras
if (m_cameraSystem) {
m_cameraSystem->update();
}
// Update LOD system
if (m_lodSystem) {
m_lodSystem->update();
}
// Update StaticGeometry system
if (m_staticGeometrySystem) {
m_staticGeometrySystem->update();
}
// Update ProceduralTexture system
if (m_proceduralTextureSystem) {
m_proceduralTextureSystem->update();
}
// Update ProceduralMaterial system
if (m_proceduralMaterialSystem) {
m_proceduralMaterialSystem->update();
}
// Update ProceduralMesh system
if (m_proceduralMeshSystem) {
m_proceduralMeshSystem->update();
}
// Update RoomLayout system FIRST (generates cells for CellGrid)
if (m_roomLayoutSystem) {
m_roomLayoutSystem->update();
}
// Update CellGrid system (builds mesh from cells)
if (m_cellGridSystem) {
m_cellGridSystem->update();
@@ -565,3 +582,20 @@ flecs::entity EditorApp::getSelectedEntity() const
}
return flecs::entity::null();
}
void EditorApp::locateResources()
{
Ogre::ResourceGroupManager::getSingleton().createResourceGroup(
"Characters", true);
// Ogre::ResourceGroupManager::getSingleton().createResourceGroup(
// "Water", true);
Ogre::ResourceGroupManager::getSingleton().createResourceGroup(
"LuaScripts", false);
Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
"./lua-scripts", "FileSystem", "LuaScripts", true, true);
Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
"./characters/male", "FileSystem", "Characters", false, true);
Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
"./characters/female", "FileSystem", "Characters", false, true);
OgreBites::ApplicationContext::locateResources();
}

View File

@@ -32,21 +32,23 @@ class ImGuiRenderListener : public Ogre::RenderTargetListener {
public:
ImGuiRenderListener(Ogre::ImGuiOverlay *imguiOverlay,
EditorUISystem *uiSystem,
Ogre::RenderWindow* renderWindow);
Ogre::RenderWindow *renderWindow);
void preViewportUpdate(const Ogre::RenderTargetViewportEvent &evt) override;
void postViewportUpdate(const Ogre::RenderTargetViewportEvent &evt) override;
void
preViewportUpdate(const Ogre::RenderTargetViewportEvent &evt) override;
void
postViewportUpdate(const Ogre::RenderTargetViewportEvent &evt) override;
private:
Ogre::ImGuiOverlay *m_imguiOverlay;
EditorUISystem *m_uiSystem;
Ogre::RenderWindow* m_renderWindow;
Ogre::RenderWindow *m_renderWindow;
// Timer for delta time calculation
Ogre::Timer m_timer;
unsigned long m_lastTime = 0;
float m_deltaTime = 0.0f;
// Frame stats (updated in postViewportUpdate)
int m_lastBatchCount = 0;
};
@@ -63,6 +65,7 @@ public:
// OgreBites::ApplicationContext overrides
void setup() override;
bool frameRenderingQueued(const Ogre::FrameEvent &evt) override;
void locateResources() override;
// OgreBites::InputListener overrides
bool mouseMoved(const OgreBites::MouseMotionEvent &evt) override;
@@ -82,8 +85,14 @@ public:
// Getters
flecs::entity getSelectedEntity() const;
Ogre::SceneManager *getSceneManager() const { return m_sceneMgr; }
flecs::world *getWorld() { return &m_world; }
Ogre::SceneManager *getSceneManager() const
{
return m_sceneMgr;
}
flecs::world *getWorld()
{
return &m_world;
}
private:
// Ogre objects

View File

@@ -7,445 +7,445 @@
#include "components/EulerUtils.hpp"
EditorApp::EditorApp()
: OgreBites::ApplicationContext("OgreEditor")
, mSceneMgr(nullptr)
, mOverlaySystem(nullptr)
, mImGuiOverlay(nullptr)
, mIsDraggingCursor(false)
, mCurrentModifiers(0)
, mGridVisible(true)
, mAxesVisible(true)
, m3DCursorPosition(Ogre::Vector3::ZERO)
: OgreBites::ApplicationContext("OgreEditor")
, mSceneMgr(nullptr)
, mOverlaySystem(nullptr)
, mImGuiOverlay(nullptr)
, mIsDraggingCursor(false)
, mCurrentModifiers(0)
, mGridVisible(true)
, mAxesVisible(true)
, m3DCursorPosition(Ogre::Vector3::ZERO)
{
}
EditorApp::~EditorApp()
{
if (mImGuiOverlay) {
delete mImGuiOverlay;
mImGuiOverlay = nullptr;
}
if (mOverlaySystem) {
delete mOverlaySystem;
mOverlaySystem = nullptr;
}
if (mImGuiOverlay) {
delete mImGuiOverlay;
mImGuiOverlay = nullptr;
}
if (mOverlaySystem) {
delete mOverlaySystem;
mOverlaySystem = nullptr;
}
}
void EditorApp::setup()
{
// Call base class setup first
OgreBites::ApplicationContext::setup();
// Call base class setup first
OgreBites::ApplicationContext::setup();
// Get root and setup scene
Ogre::Root *root = getRoot();
if (!root) {
OGRE_EXCEPT(Ogre::Exception::ERR_RT_ASSERTION_FAILED,
"Failed to get Ogre::Root", "EditorApp::setup");
return;
}
// Get root and setup scene
Ogre::Root *root = getRoot();
if (!root) {
OGRE_EXCEPT(Ogre::Exception::ERR_RT_ASSERTION_FAILED,
"Failed to get Ogre::Root", "EditorApp::setup");
return;
}
mSceneMgr = root->createSceneManager();
if (!mSceneMgr) {
OGRE_EXCEPT(Ogre::Exception::ERR_RT_ASSERTION_FAILED,
"Failed to create SceneManager",
"EditorApp::setup");
return;
}
mSceneMgr = root->createSceneManager();
if (!mSceneMgr) {
OGRE_EXCEPT(Ogre::Exception::ERR_RT_ASSERTION_FAILED,
"Failed to create SceneManager",
"EditorApp::setup");
return;
}
// Setup overlay system
mOverlaySystem = new Ogre::OverlaySystem();
mSceneMgr->addRenderQueueListener(mOverlaySystem);
// Setup overlay system
mOverlaySystem = new Ogre::OverlaySystem();
mSceneMgr->addRenderQueueListener(mOverlaySystem);
// Setup render window
Ogre::RenderWindow *window = getRenderWindow();
if (!window) {
OGRE_EXCEPT(Ogre::Exception::ERR_RT_ASSERTION_FAILED,
"Failed to get RenderWindow", "EditorApp::setup");
return;
}
// Setup render window
Ogre::RenderWindow *window = getRenderWindow();
if (!window) {
OGRE_EXCEPT(Ogre::Exception::ERR_RT_ASSERTION_FAILED,
"Failed to get RenderWindow", "EditorApp::setup");
return;
}
// Setup ImGui overlay
setupImGui();
// Setup ImGui overlay
setupImGui();
setupFlecs();
setupScene();
setupFlecs();
setupScene();
// Setup editor camera
mEditorCamera = std::make_unique<EditorCamera>(mSceneMgr, window);
// Setup editor camera
mEditorCamera = std::make_unique<EditorCamera>(mSceneMgr, window);
// Setup UI system
mUISystem = std::make_unique<EditorUISystem>(mWorld, mSceneMgr,
m3DCursorPosition);
// Setup UI system
mUISystem = std::make_unique<EditorUISystem>(mWorld, mSceneMgr,
m3DCursorPosition);
// Set the cursor moved callback
mUISystem->setOnCursorMoved(
[this](const Ogre::Vector3 &pos) { m3DCursorPosition = pos; });
// Set the cursor moved callback
mUISystem->setOnCursorMoved(
[this](const Ogre::Vector3 &pos) { m3DCursorPosition = pos; });
// Register input listeners
addInputListener(this);
// Register input listeners
addInputListener(this);
// Add ImGui input listener - this is a method of ApplicationContext
OgreBites::InputListener *imguiListener = getImGuiInputListener();
if (imguiListener) {
addInputListener(imguiListener);
}
// Add ImGui input listener - this is a method of ApplicationContext
OgreBites::InputListener *imguiListener = getImGuiInputListener();
if (imguiListener) {
addInputListener(imguiListener);
}
}
void EditorApp::setupFlecs()
{
// Configure flecs
mWorld.set_entity_range(1, 10000);
// Configure flecs
mWorld.set_entity_range(1, 10000);
// Register components using the helper function
registerComponents(mWorld);
// Register components using the helper function
registerComponents(mWorld);
// Create default entities
flecs::entity rootEntity = mWorld.entity();
rootEntity.set<EntityNameComponent>({ "Root" });
// Create default entities
flecs::entity rootEntity = mWorld.entity();
rootEntity.set<EntityNameComponent>({ "Root" });
// Create a test entity with mesh
flecs::entity testEntity = mWorld.entity();
testEntity.set<EntityNameComponent>({ "Test Cube" });
// Create a test entity with mesh
flecs::entity testEntity = mWorld.entity();
testEntity.set<EntityNameComponent>({ "Test Cube" });
// Create transform with scene node
TransformComponent transform;
transform.node = mSceneMgr->getRootSceneNode()->createChildSceneNode();
transform.position = Ogre::Vector3(0, 0, 0);
transform.applyToNode();
testEntity.set<TransformComponent>(transform);
// Create transform with scene node
TransformComponent transform;
transform.node = mSceneMgr->getRootSceneNode()->createChildSceneNode();
transform.position = Ogre::Vector3(0, 0, 0);
transform.applyToNode();
testEntity.set<TransformComponent>(transform);
// Try to load a mesh
try {
RenderableComponent renderable("cube.mesh");
renderable.entity = mSceneMgr->createEntity("cube.mesh");
testEntity.set<RenderableComponent>(renderable);
// Try to load a mesh
try {
RenderableComponent renderable("cube.mesh");
renderable.entity = mSceneMgr->createEntity("cube.mesh");
testEntity.set<RenderableComponent>(renderable);
// Attach to node
if (testEntity.has<TransformComponent>()) {
auto &testTransform =
testEntity.get_mut<TransformComponent>();
if (testTransform.node && renderable.entity) {
testTransform.node->attachObject(
renderable.entity);
}
}
} catch (const std::exception &e) {
Ogre::LogManager::getSingleton().logMessage(
"Failed to load cube.mesh: " + std::string(e.what()));
}
// Attach to node
if (testEntity.has<TransformComponent>()) {
auto &testTransform =
testEntity.get_mut<TransformComponent>();
if (testTransform.node && renderable.entity) {
testTransform.node->attachObject(
renderable.entity);
}
}
} catch (const std::exception &e) {
Ogre::LogManager::getSingleton().logMessage(
"Failed to load cube.mesh: " + std::string(e.what()));
}
// Optional: Add a system for auto-updating transforms
mWorld.system<TransformComponent>().each(
[](flecs::entity e, TransformComponent &transform) {
// Auto-sync transforms if needed
// transform.updateFromNode();
});
// Optional: Add a system for auto-updating transforms
mWorld.system<TransformComponent>().each(
[](flecs::entity e, TransformComponent &transform) {
// Auto-sync transforms if needed
// transform.updateFromNode();
});
}
void EditorApp::setupScene()
{
// Setup ambient light
mSceneMgr->setAmbientLight(Ogre::ColourValue(0.3f, 0.3f, 0.3f));
// Setup ambient light
mSceneMgr->setAmbientLight(Ogre::ColourValue(0.3f, 0.3f, 0.3f));
// Create directional light with scene node
Ogre::Light *directionalLight = mSceneMgr->createLight("MainLight");
directionalLight->setType(Ogre::Light::LT_DIRECTIONAL);
directionalLight->setDiffuseColour(Ogre::ColourValue(1.0f, 1.0f, 1.0f));
directionalLight->setSpecularColour(
Ogre::ColourValue(0.5f, 0.5f, 0.5f));
// Create directional light with scene node
Ogre::Light *directionalLight = mSceneMgr->createLight("MainLight");
directionalLight->setType(Ogre::Light::LT_DIRECTIONAL);
directionalLight->setDiffuseColour(Ogre::ColourValue(1.0f, 1.0f, 1.0f));
directionalLight->setSpecularColour(
Ogre::ColourValue(0.5f, 0.5f, 0.5f));
// Create scene node for directional light and set direction
Ogre::SceneNode *lightNode =
mSceneMgr->getRootSceneNode()->createChildSceneNode();
lightNode->attachObject(directionalLight);
lightNode->setDirection(Ogre::Vector3(1, -1, 0), Ogre::Node::TS_WORLD);
// Create scene node for directional light and set direction
Ogre::SceneNode *lightNode =
mSceneMgr->getRootSceneNode()->createChildSceneNode();
lightNode->attachObject(directionalLight);
lightNode->setDirection(Ogre::Vector3(1, -1, 0), Ogre::Node::TS_WORLD);
// Create a fill light from below
Ogre::Light *fillLight = mSceneMgr->createLight("FillLight");
fillLight->setType(Ogre::Light::LT_DIRECTIONAL);
fillLight->setDiffuseColour(Ogre::ColourValue(0.4f, 0.4f, 0.4f));
fillLight->setSpecularColour(Ogre::ColourValue(0.2f, 0.2f, 0.2f));
// Create a fill light from below
Ogre::Light *fillLight = mSceneMgr->createLight("FillLight");
fillLight->setType(Ogre::Light::LT_DIRECTIONAL);
fillLight->setDiffuseColour(Ogre::ColourValue(0.4f, 0.4f, 0.4f));
fillLight->setSpecularColour(Ogre::ColourValue(0.2f, 0.2f, 0.2f));
Ogre::SceneNode *fillLightNode =
mSceneMgr->getRootSceneNode()->createChildSceneNode();
fillLightNode->attachObject(fillLight);
fillLightNode->setDirection(Ogre::Vector3(-0.5f, -1.0f, 0.5f),
Ogre::Node::TS_WORLD);
Ogre::SceneNode *fillLightNode =
mSceneMgr->getRootSceneNode()->createChildSceneNode();
fillLightNode->attachObject(fillLight);
fillLightNode->setDirection(Ogre::Vector3(-0.5f, -1.0f, 0.5f),
Ogre::Node::TS_WORLD);
// Optional: Add a grid helper with named node for toggling
try {
Ogre::Plane plane(Ogre::Vector3::UNIT_Y, -1);
Ogre::MeshManager::getSingleton().createPlane(
"grid_plane",
Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
plane, 20, 20, 20, 20, true, 1, 5, 5,
Ogre::Vector3::UNIT_Z);
// Optional: Add a grid helper with named node for toggling
try {
Ogre::Plane plane(Ogre::Vector3::UNIT_Y, -1);
Ogre::MeshManager::getSingleton().createPlane(
"grid_plane",
Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
plane, 20, 20, 20, 20, true, 1, 5, 5,
Ogre::Vector3::UNIT_Z);
Ogre::Entity *gridEntity =
mSceneMgr->createEntity("grid_plane");
Ogre::Entity *gridEntity =
mSceneMgr->createEntity("grid_plane");
// Try to set a grid material if available
if (Ogre::MaterialManager::getSingleton().resourceExists(
"GridMaterial")) {
gridEntity->setMaterialName("GridMaterial");
}
// Try to set a grid material if available
if (Ogre::MaterialManager::getSingleton().resourceExists(
"GridMaterial")) {
gridEntity->setMaterialName("GridMaterial");
}
// Create node with a name for easy access
Ogre::SceneNode *gridNode =
mSceneMgr->getRootSceneNode()->createChildSceneNode(
"GridNode");
gridNode->attachObject(gridEntity);
gridNode->setPosition(0, -1, 0);
// Create node with a name for easy access
Ogre::SceneNode *gridNode =
mSceneMgr->getRootSceneNode()->createChildSceneNode(
"GridNode");
gridNode->attachObject(gridEntity);
gridNode->setPosition(0, -1, 0);
Ogre::LogManager::getSingleton().logMessage(
"Grid created successfully");
} catch (const std::exception &e) {
Ogre::LogManager::getSingleton().logMessage(
"Grid plane creation failed: " + std::string(e.what()));
}
Ogre::LogManager::getSingleton().logMessage(
"Grid created successfully");
} catch (const std::exception &e) {
Ogre::LogManager::getSingleton().logMessage(
"Grid plane creation failed: " + std::string(e.what()));
}
// Add a simple axis helper
createAxisHelper();
// Add a simple axis helper
createAxisHelper();
}
void EditorApp::createAxisHelper()
{
try {
// X-axis (red)
Ogre::ManualObject *axisX =
mSceneMgr->createManualObject("AxisX");
axisX->begin("BaseWhiteNoLighting",
Ogre::RenderOperation::OT_LINE_LIST);
axisX->colour(Ogre::ColourValue(1.0f, 0.0f, 0.0f));
axisX->position(0, 0, 0);
axisX->position(2, 0, 0);
axisX->end();
try {
// X-axis (red)
Ogre::ManualObject *axisX =
mSceneMgr->createManualObject("AxisX");
axisX->begin("BaseWhiteNoLighting",
Ogre::RenderOperation::OT_LINE_LIST);
axisX->colour(Ogre::ColourValue(1.0f, 0.0f, 0.0f));
axisX->position(0, 0, 0);
axisX->position(2, 0, 0);
axisX->end();
// Y-axis (green)
Ogre::ManualObject *axisY =
mSceneMgr->createManualObject("AxisY");
axisY->begin("BaseWhiteNoLighting",
Ogre::RenderOperation::OT_LINE_LIST);
axisY->colour(Ogre::ColourValue(0.0f, 1.0f, 0.0f));
axisY->position(0, 0, 0);
axisY->position(0, 2, 0);
axisY->end();
// Y-axis (green)
Ogre::ManualObject *axisY =
mSceneMgr->createManualObject("AxisY");
axisY->begin("BaseWhiteNoLighting",
Ogre::RenderOperation::OT_LINE_LIST);
axisY->colour(Ogre::ColourValue(0.0f, 1.0f, 0.0f));
axisY->position(0, 0, 0);
axisY->position(0, 2, 0);
axisY->end();
// Z-axis (blue)
Ogre::ManualObject *axisZ =
mSceneMgr->createManualObject("AxisZ");
axisZ->begin("BaseWhiteNoLighting",
Ogre::RenderOperation::OT_LINE_LIST);
axisZ->colour(Ogre::ColourValue(0.0f, 0.0f, 1.0f));
axisZ->position(0, 0, 0);
axisZ->position(0, 0, 2);
axisZ->end();
// Z-axis (blue)
Ogre::ManualObject *axisZ =
mSceneMgr->createManualObject("AxisZ");
axisZ->begin("BaseWhiteNoLighting",
Ogre::RenderOperation::OT_LINE_LIST);
axisZ->colour(Ogre::ColourValue(0.0f, 0.0f, 1.0f));
axisZ->position(0, 0, 0);
axisZ->position(0, 0, 2);
axisZ->end();
// Create named node for easy access
Ogre::SceneNode *axisNode =
mSceneMgr->getRootSceneNode()->createChildSceneNode(
"AxisNode");
axisNode->attachObject(axisX);
axisNode->attachObject(axisY);
axisNode->attachObject(axisZ);
// Create named node for easy access
Ogre::SceneNode *axisNode =
mSceneMgr->getRootSceneNode()->createChildSceneNode(
"AxisNode");
axisNode->attachObject(axisX);
axisNode->attachObject(axisY);
axisNode->attachObject(axisZ);
} catch (const std::exception &e) {
Ogre::LogManager::getSingleton().logMessage(
"Axis helper creation failed: " +
std::string(e.what()));
}
} catch (const std::exception &e) {
Ogre::LogManager::getSingleton().logMessage(
"Axis helper creation failed: " +
std::string(e.what()));
}
}
void EditorApp::setupImGui()
{
// Create ImGui overlay using Ogre's built-in integration
mImGuiOverlay = new Ogre::ImGuiOverlay();
// Create ImGui overlay using Ogre's built-in integration
mImGuiOverlay = new Ogre::ImGuiOverlay();
// Show the overlay - this enables it in the overlay system
mImGuiOverlay->show();
// Show the overlay - this enables it in the overlay system
mImGuiOverlay->show();
// Setup ImGui style
ImGui::StyleColorsDark();
// Setup ImGui style
ImGui::StyleColorsDark();
// Configure ImGui IO (standard features only)
ImGuiIO &io = ImGui::GetIO();
io.ConfigWindowsMoveFromTitleBarOnly = true;
// Configure ImGui IO (standard features only)
ImGuiIO &io = ImGui::GetIO();
io.ConfigWindowsMoveFromTitleBarOnly = true;
Ogre::LogManager::getSingleton().logMessage(
"ImGui overlay initialized");
Ogre::LogManager::getSingleton().logMessage(
"ImGui overlay initialized");
}
bool EditorApp::frameRenderingQueued(const Ogre::FrameEvent &evt)
{
// Update camera
if (mEditorCamera) {
mEditorCamera->update(evt.timeSinceLastFrame);
}
// Update camera
if (mEditorCamera) {
mEditorCamera->update(evt.timeSinceLastFrame);
}
// Start ImGui frame
if (mImGuiOverlay) {
mImGuiOverlay->NewFrame();
}
// Start ImGui frame
if (mImGuiOverlay) {
mImGuiOverlay->NewFrame();
}
// Update UI system (this will render all ImGui windows)
if (mUISystem) {
mUISystem->update();
}
// Update UI system (this will render all ImGui windows)
if (mUISystem) {
mUISystem->update();
}
return OgreBites::ApplicationContext::frameRenderingQueued(evt);
return OgreBites::ApplicationContext::frameRenderingQueued(evt);
}
bool EditorApp::mouseMoved(const OgreBites::MouseMotionEvent &evt)
{
if (mEditorCamera) {
mEditorCamera->handleMouseMove(evt);
}
return true;
if (mEditorCamera) {
mEditorCamera->handleMouseMove(evt);
}
return true;
}
bool EditorApp::mousePressed(const OgreBites::MouseButtonEvent &evt)
{
if (mEditorCamera) {
mEditorCamera->handleMousePress(evt);
if (mEditorCamera) {
mEditorCamera->handleMousePress(evt);
// Check for Ctrl key using current modifier state
if (evt.button == OgreBites::BUTTON_LEFT && isCtrlPressed()) {
Ogre::Viewport *vp =
mEditorCamera->getCamera()->getViewport();
if (vp) {
float screenX = static_cast<float>(evt.x) /
static_cast<float>(
vp->getActualWidth());
float screenY = static_cast<float>(evt.y) /
static_cast<float>(
vp->getActualHeight());
// Check for Ctrl key using current modifier state
if (evt.button == OgreBites::BUTTON_LEFT && isCtrlPressed()) {
Ogre::Viewport *vp =
mEditorCamera->getCamera()->getViewport();
if (vp) {
float screenX = static_cast<float>(evt.x) /
static_cast<float>(
vp->getActualWidth());
float screenY = static_cast<float>(evt.y) /
static_cast<float>(
vp->getActualHeight());
Ogre::Vector3 cursorPos =
mEditorCamera->getMouseRay(screenX,
screenY);
m3DCursorPosition = cursorPos;
}
}
}
return true;
Ogre::Vector3 cursorPos =
mEditorCamera->getMouseRay(screenX,
screenY);
m3DCursorPosition = cursorPos;
}
}
}
return true;
}
bool EditorApp::mouseReleased(const OgreBites::MouseButtonEvent &evt)
{
if (mEditorCamera) {
mEditorCamera->handleMouseRelease(evt);
}
return true;
if (mEditorCamera) {
mEditorCamera->handleMouseRelease(evt);
}
return true;
}
bool EditorApp::keyPressed(const OgreBites::KeyboardEvent &evt)
{
if (mEditorCamera) {
mEditorCamera->handleKeyboard(evt);
}
if (mEditorCamera) {
mEditorCamera->handleKeyboard(evt);
}
// Update current modifiers from the event
mCurrentModifiers = evt.keysym.mod;
// Update current modifiers from the event
mCurrentModifiers = evt.keysym.mod;
// Handle delete key
if (evt.keysym.sym == OgreBites::SDLK_DELETE) {
if (mUISystem && mSelectedEntity) {
// Clean up scene node
if (mSelectedEntity.has<TransformComponent>()) {
auto &transform =
mSelectedEntity
.get_mut<TransformComponent>();
if (transform.node) {
mSceneMgr->destroySceneNode(
transform.node);
transform.node = nullptr;
}
}
// Handle delete key
if (evt.keysym.sym == OgreBites::SDLK_DELETE) {
if (mUISystem && mSelectedEntity) {
// Clean up scene node
if (mSelectedEntity.has<TransformComponent>()) {
auto &transform =
mSelectedEntity
.get_mut<TransformComponent>();
if (transform.node) {
mSceneMgr->destroySceneNode(
transform.node);
transform.node = nullptr;
}
}
// Clean up renderable
if (mSelectedEntity.has<RenderableComponent>()) {
auto &renderable =
mSelectedEntity
.get_mut<RenderableComponent>();
if (renderable.entity) {
mSceneMgr->destroyEntity(
renderable.entity);
renderable.entity = nullptr;
}
}
// Clean up renderable
if (mSelectedEntity.has<RenderableComponent>()) {
auto &renderable =
mSelectedEntity
.get_mut<RenderableComponent>();
if (renderable.entity) {
mSceneMgr->destroyEntity(
renderable.entity);
renderable.entity = nullptr;
}
}
mSelectedEntity.destruct();
mUISystem->setSelectedEntity(flecs::entity::null());
}
}
mSelectedEntity.destruct();
mUISystem->setSelectedEntity(flecs::entity::null());
}
}
// Handle F5 for reloading resources
if (evt.keysym.sym == OgreBites::SDLK_F5) {
reloadResources();
}
// Handle F5 for reloading resources
if (evt.keysym.sym == OgreBites::SDLK_F5) {
reloadResources();
}
// Handle F3 for showing/hiding grid
if (evt.keysym.sym == OgreBites::SDLK_F3) {
toggleGrid();
}
// Handle F3 for showing/hiding grid
if (evt.keysym.sym == OgreBites::SDLK_F3) {
toggleGrid();
}
// Handle F4 for showing/hiding axes
if (evt.keysym.sym == OgreBites::SDLK_F4) {
toggleAxes();
}
// Handle F4 for showing/hiding axes
if (evt.keysym.sym == OgreBites::SDLK_F4) {
toggleAxes();
}
return true;
return true;
}
bool EditorApp::keyReleased(const OgreBites::KeyboardEvent &evt)
{
// Update current modifiers from the event
mCurrentModifiers = evt.keysym.mod;
// Update current modifiers from the event
mCurrentModifiers = evt.keysym.mod;
return true;
return true;
}
void EditorApp::toggleGrid()
{
// Use getChild and cast to SceneNode
Ogre::Node *node = mSceneMgr->getRootSceneNode()->getChild("GridNode");
if (node) {
Ogre::SceneNode *gridNode =
static_cast<Ogre::SceneNode *>(node);
mGridVisible = !mGridVisible;
gridNode->setVisible(mGridVisible);
Ogre::LogManager::getSingleton().logMessage(
"Grid visibility: " +
std::string(mGridVisible ? "ON" : "OFF"));
} else {
Ogre::LogManager::getSingleton().logMessage(
"Grid node not found");
}
// Use getChild and cast to SceneNode
Ogre::Node *node = mSceneMgr->getRootSceneNode()->getChild("GridNode");
if (node) {
Ogre::SceneNode *gridNode =
static_cast<Ogre::SceneNode *>(node);
mGridVisible = !mGridVisible;
gridNode->setVisible(mGridVisible);
Ogre::LogManager::getSingleton().logMessage(
"Grid visibility: " +
std::string(mGridVisible ? "ON" : "OFF"));
} else {
Ogre::LogManager::getSingleton().logMessage(
"Grid node not found");
}
}
void EditorApp::toggleAxes()
{
// Use getChild and cast to SceneNode
Ogre::Node *node = mSceneMgr->getRootSceneNode()->getChild("AxisNode");
if (node) {
Ogre::SceneNode *axisNode =
static_cast<Ogre::SceneNode *>(node);
mAxesVisible = !mAxesVisible;
axisNode->setVisible(mAxesVisible);
Ogre::LogManager::getSingleton().logMessage(
"Axes visibility: " +
std::string(mAxesVisible ? "ON" : "OFF"));
} else {
Ogre::LogManager::getSingleton().logMessage(
"Axis node not found");
}
// Use getChild and cast to SceneNode
Ogre::Node *node = mSceneMgr->getRootSceneNode()->getChild("AxisNode");
if (node) {
Ogre::SceneNode *axisNode =
static_cast<Ogre::SceneNode *>(node);
mAxesVisible = !mAxesVisible;
axisNode->setVisible(mAxesVisible);
Ogre::LogManager::getSingleton().logMessage(
"Axes visibility: " +
std::string(mAxesVisible ? "ON" : "OFF"));
} else {
Ogre::LogManager::getSingleton().logMessage(
"Axis node not found");
}
}
void EditorApp::reloadResources()
{
// Reload all materials
Ogre::LogManager::getSingleton().logMessage("Reloading materials...");
Ogre::MaterialManager::getSingleton().reloadAll();
// Reload all materials
Ogre::LogManager::getSingleton().logMessage("Reloading materials...");
Ogre::MaterialManager::getSingleton().reloadAll();
Ogre::LogManager::getSingleton().logMessage("Resources reloaded");
Ogre::LogManager::getSingleton().logMessage("Resources reloaded");
}