From e0db570581d63063f7199b8f9a10a4cbd9be026d Mon Sep 17 00:00:00 2001 From: Sergey Lapin Date: Thu, 4 Dec 2025 15:51:56 +0300 Subject: [PATCH] Started implementing deficated editor GUI --- CMakeLists.txt | 4 +- Game.cpp | 1 + src/gamedata/AppModule.cpp | 15 + src/gamedata/AppModule.h | 25 ++ src/gamedata/CMakeLists.txt | 6 +- src/gamedata/Components.h | 5 - src/gamedata/GUIModule.cpp | 578 ++++++++++++++++++++++++++ src/gamedata/GUIModule.h | 7 +- src/gamedata/GameData.cpp | 93 ++++- src/gamedata/GameData.h | 4 +- src/gamedata/LuaData.cpp | 23 +- src/gamedata/VehicleManagerModule.cpp | 24 ++ src/gamedata/VehicleManagerModule.h | 15 + src/world/CMakeLists.txt | 1 + 14 files changed, 768 insertions(+), 33 deletions(-) create mode 100644 src/gamedata/AppModule.cpp create mode 100644 src/gamedata/AppModule.h create mode 100644 src/gamedata/VehicleManagerModule.cpp create mode 100644 src/gamedata/VehicleManagerModule.h diff --git a/CMakeLists.txt b/CMakeLists.txt index e06de69..89f0715 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 3.13.0) project(world2) -set(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_STANDARD 17) set(BLENDER "${CMAKE_SOURCE_DIR}/../../blender-bin/bin/blender" CACHE STRING "Blender path") set(CREATE_DIRECTORIES ${CMAKE_BINARY_DIR}/assets/blender/shapes/male @@ -75,6 +75,7 @@ add_subdirectory(morph) add_subdirectory(src/world) add_subdirectory(src/tests) add_subdirectory(src/physics) +add_subdirectory(src/editor) add_executable(Game Game.cpp ${WATER_SRC}) target_include_directories(Game PRIVATE src/gamedata) @@ -384,4 +385,5 @@ add_custom_target(import_vrm DEPENDS ${CHARACTER_GLBS}) target_compile_definitions(Game PRIVATE FLECS_CPP_NO_AUTO_REGISTRATION) install(TARGETS Game DESTINATION bin) +install(TARGETS Editor DESTINATION bin) diff --git a/Game.cpp b/Game.cpp index 8d36f9d..6b68874 100644 --- a/Game.cpp +++ b/Game.cpp @@ -16,6 +16,7 @@ #include "CharacterModule.h" #include "TerrainModule.h" #include "GUIModule.h" +#include "AppModule.h" #include "sound.h" class App; class SkyRenderer : public Ogre::SceneManager::Listener { diff --git a/src/gamedata/AppModule.cpp b/src/gamedata/AppModule.cpp new file mode 100644 index 0000000..b569862 --- /dev/null +++ b/src/gamedata/AppModule.cpp @@ -0,0 +1,15 @@ +#include "AppModule.h" +namespace ECS +{ +AppModule::AppModule(flecs::world &ecs) +{ + ecs.module(); + ecs.component() + .on_add([](App &app) { + app.mInput = nullptr; + app.mGuiOverlay = nullptr; + app.listeners.clear(); + }) + .add(flecs::Singleton); +} +} \ No newline at end of file diff --git a/src/gamedata/AppModule.h b/src/gamedata/AppModule.h new file mode 100644 index 0000000..a576241 --- /dev/null +++ b/src/gamedata/AppModule.h @@ -0,0 +1,25 @@ +#ifndef _APP_MODULE_H_ +#define _APP_MODULE_H_ +#include +#include +namespace Ogre +{ +class ImGuiOverlay; +} +namespace OgreBites +{ +class InputListenerChain; +class InputListener; +} +namespace ECS +{ +struct App { + Ogre::ImGuiOverlay *mGuiOverlay; + OgreBites::InputListenerChain *mInput; + std::vector listeners; +}; +struct AppModule { + AppModule(flecs::world &ecs); +}; +} +#endif \ No newline at end of file diff --git a/src/gamedata/CMakeLists.txt b/src/gamedata/CMakeLists.txt index f965bb3..436d214 100644 --- a/src/gamedata/CMakeLists.txt +++ b/src/gamedata/CMakeLists.txt @@ -2,8 +2,10 @@ project(gamedata) set(CMAKE_CXX_STANDARD 17) find_package(OGRE REQUIRED COMPONENTS Bites Bullet Paging Terrain Overlay CONFIG) find_package(Bullet REQUIRED) -add_library(GameData STATIC GameData.cpp CharacterModule.cpp WaterModule.cpp SunModule.cpp TerrainModule.cpp GUIModule.cpp LuaData.cpp WorldMapModule.cpp - BoatModule.cpp EventTriggerModule.cpp CharacterAnimationModule.cpp PhysicsModule.cpp EventModule.cpp CharacterManagerModule.cpp SmartObject.cpp SlotsModule.cpp goap.cpp) +add_library(GameData STATIC GameData.cpp CharacterModule.cpp WaterModule.cpp SunModule.cpp TerrainModule.cpp + GUIModule.cpp LuaData.cpp WorldMapModule.cpp BoatModule.cpp EventTriggerModule.cpp + CharacterAnimationModule.cpp PhysicsModule.cpp EventModule.cpp CharacterManagerModule.cpp + VehicleManagerModule.cpp AppModule.cpp SmartObject.cpp SlotsModule.cpp goap.cpp) target_link_libraries(GameData PUBLIC lua flecs::flecs_static OgreMain OgreBites OgrePaging OgreTerrain OgreOverlay PRIVATE sceneloader world-build physics) diff --git a/src/gamedata/Components.h b/src/gamedata/Components.h index bbadf68..d29b4a1 100644 --- a/src/gamedata/Components.h +++ b/src/gamedata/Components.h @@ -67,11 +67,6 @@ struct RenderWindow { Ogre::RenderWindow *window; float dpi; }; -struct App { - Ogre::ImGuiOverlay *mGuiOverlay; - OgreBites::InputListenerChain *mInput; - std::vector listeners; -}; struct CollisionShape { void *shape; }; diff --git a/src/gamedata/GUIModule.cpp b/src/gamedata/GUIModule.cpp index 35acf4a..7a8b837 100644 --- a/src/gamedata/GUIModule.cpp +++ b/src/gamedata/GUIModule.cpp @@ -11,15 +11,22 @@ #include "GameData.h" #include "Components.h" #include "LuaData.h" +#include "AppModule.h" #include "GUIModule.h" namespace ECS { struct GUIListener; +struct EditorGUIListener; struct GUIData { Ogre::ImGuiOverlay *mGuiOverlay; std::vector glb_names; GUIListener *mGUIListener; }; +struct EditorGUIData { + Ogre::ImGuiOverlay *mGuiOverlay; + std::vector glb_names; + EditorGUIListener *mGUIListener; +}; struct GUIListener : public Ogre::RenderTargetListener { float panel_width; bool enableEditor; @@ -459,8 +466,537 @@ struct GUIListener : public Ogre::RenderTargetListener { } }; +struct EditorGUIListener : public Ogre::RenderTargetListener { + float panel_width; + bool enableEditor; + bool enableMapEditor; + ImFont *smallFont, *midFont, *bigFont; + Ogre::FontPtr _smallFont, _midFont, _bigFont; + EditorGUIListener(Ogre::ImGuiOverlay *overlay) + : Ogre::RenderTargetListener() + { + std::cout << "WAAAAAAA!!!!!" << std::endl; + _midFont = createFont("midFont", "General", + "Jupiteroid-Regular.ttf", 18.0f); + _smallFont = createFont("smallFont", "General", + "Jupiteroid-Regular.ttf", 13.0f); + _bigFont = createFont("bigFont", "General", "Kenney Bold.ttf", + 32.0f); + smallFont = overlay->addFont("smallFont", "General"); + OgreAssert(smallFont, "Could not load font"); + midFont = overlay->addFont("midFont", "General"); + OgreAssert(midFont, "Could not load font"); + bigFont = overlay->addFont("bigFont", "General"); + OgreAssert(bigFont, "Could not load font"); +#if 0 + Ogre::FontPtr _midFont = createFont("midFont", "General", + "Kenney Bold.ttf", 28.0f); +#endif +#if 0 + ImGui::GetIO().Fonts->Build(); +#endif + } + Ogre::FontPtr createFont(const Ogre::String &name, + const Ogre::String &group, + const Ogre::String &ttfname, float fontSize) + { + Ogre::FontPtr ret = + Ogre::FontManager::getSingleton().create(name, group); + ret->setType(Ogre::FontType::FT_TRUETYPE); + ret->setSource(ttfname); + ret->setTrueTypeSize(fontSize); + ret->setTrueTypeResolution(75); + ret->addCodePointRange(Ogre::Font::CodePointRange(30, 128)); + ret->load(); + return ret; + } + void + preViewportUpdate(const Ogre::RenderTargetViewportEvent &evt) override + { + preview(evt); + } + void buttons_panel() + { + ImVec2 size = ImGui::GetMainViewport()->Size; + float window_width = size.x * 0.2f; + if (window_width > panel_width) + window_width = panel_width; + float window_height = size.y * 0.5f - 20; + ImGui::SetNextWindowPos(ImVec2(0, size.y * 0.5f + 20), + ImGuiCond_Always); + ImGui::SetNextWindowSize(ImVec2(window_width, window_height), + ImGuiCond_Always); + ImGui::Begin("Control"); + // if (ECS::get().get().enabled) + // ECS::get().get().app->setWindowGrab(true); + if (ImGui::Button("Quit")) + Ogre::Root::getSingleton().queueEndRendering(); + if (ImGui::Button("Return")) + ECS::get().get().finish(); + if (ImGui::Button("Enable/Disable item editor")) { + enableEditor ^= true; + if (enableEditor) + enableMapEditor = false; + } + if (ImGui::Button("Enable/Disable map editor")) { + enableMapEditor ^= true; + if (enableMapEditor) + enableEditor = false; + } + ImGui::Text("Text message..."); + ImGui::End(); + } + void create_entity_node(const Ogre::String &name, int key) + { + Ogre::Entity *ent = + ECS::get().get().mScnMgr->createEntity( + name); + Ogre::SceneNode *pnode = + ECS::get() + .get() + .mScnMgr->getRootSceneNode() + ->createChildSceneNode( + "ent:" + name + + Ogre::StringConverter::toString( + key), + ECS::get() + .get() + .mCameraPivot->getPosition(), + ECS::get() + .get() + .mCameraPivot->getOrientation()); + pnode->attachObject(ent); + Ogre::Quaternion q = pnode->getOrientation(); + Ogre::Radian yaw = q.getYaw(); + Ogre::Quaternion nq(yaw, Ogre::Vector3(0, 1, 0)); + pnode->setOrientation(nq); + + ECS::get().get().finish(); + } + void buildings_editor() + { + int i; + ImVec2 size = ImGui::GetMainViewport()->Size; + float window_width = size.x * 0.2f; + if (window_width > panel_width) + window_width = panel_width; + float window_height = size.y * 0.5 - 20; + ImGui::SetNextWindowPos(ImVec2(0, 0), ImGuiCond_Always); + ImGui::SetNextWindowSize(ImVec2(window_width, window_height), + ImGuiCond_Always); + ImGui::Begin("Droppings..."); + for (i = 0; + i < ECS::get().get().glb_names.size(); + i++) { + Ogre::String id_button = + "Create entity: " + + ECS::get().get().glb_names[i] + + "##ent:" + + ECS::get().get().glb_names[i]; + if (ImGui::Button(id_button.c_str())) { + create_entity_node(ECS::get() + .get() + .glb_names[i], + i); + } + } + ImGui::End(); + } + void position_editor(Ogre::SceneNode *node) + { + Ogre::Vector3 position = node->getPosition(); + float v[3] = { position.x, position.y, position.z }; + ImGui::InputFloat3("position", v); + position.x = v[0]; + position.y = v[1]; + position.z = v[2]; + node->setPosition(position); + } + void orientation_editor(Ogre::SceneNode *node) + { + Ogre::Quaternion q = node->getOrientation(); + float yaw = Ogre::Radian(q.getYaw()).valueDegrees(); + float pitch = Ogre::Radian(q.getPitch()).valueDegrees(); + float roll = Ogre::Radian(q.getRoll()).valueDegrees(); + bool m1 = ImGui::InputFloat("yaw", &yaw); + bool m2 = ImGui::InputFloat("pitch", &pitch); + bool m3 = ImGui::InputFloat("roll", &roll); + if (m1 || m2 || m3) { + Ogre::Quaternion q1(Ogre::Radian(Ogre::Degree(yaw)), + Ogre::Vector3::UNIT_Y); + Ogre::Quaternion q2(Ogre::Degree(pitch), + Ogre::Vector3::UNIT_X); + Ogre::Quaternion q3(Ogre::Degree(roll), + Ogre::Vector3::UNIT_Z); + node->setOrientation(q1 * q2 * q3); + } + } + void attachments_editor(Ogre::SceneNode *node) + { + const Ogre::SceneNode::ObjectMap &pmap = + node->getAttachedObjects(); + int i; + for (i = 0; i < pmap.size(); i++) { + const Ogre::MovableObject *mobj = pmap[i]; + const Ogre::String &pname = mobj->getName(); + ImGui::Text("Name: %s", pname.c_str()); + } + } + void map_editor() + { + } + void preview(const Ogre::RenderTargetViewportEvent &evt) + { + int i; + Ogre::ImGuiOverlay::NewFrame(); + std::cout << "GUI enabled: " << ECS::get().get().enabled + << std::endl; + if (ECS::get().get().enabled) { + buttons_panel(); + buildings_editor(); + map_editor(); + ImVec2 size = ImGui::GetMainViewport()->Size; + float window_width = size.x * 0.2f; + if (window_width > panel_width) + window_width = panel_width; + float window_height = size.y * 0.5f - 20; + ImGui::SetNextWindowPos(ImVec2(size.x - window_width, + size.y * 0.5f + 20), + ImGuiCond_Always); + ImGui::SetNextWindowSize(ImVec2(window_width, + window_height), + ImGuiCond_Always); + // ImGui::Begin("Dumb and Stupid", &mKbd.gui_active); + ImGui::Begin("Panel..."); + std::deque tree_input_queue, + tree_output_queue; + std::vector tree_list; + tree_input_queue.push_back( + ECS::get() + .get() + .mScnMgr->getRootSceneNode()); + tree_input_queue.push_back(nullptr); + std::set visited; + while (true) { + int new_nodes_count = 0; + while (!tree_input_queue.empty()) { + int child; + Ogre::SceneNode *item = + tree_input_queue.front(); + tree_input_queue.pop_front(); + if (item && + visited.find(item) == + visited.end()) { // new node + new_nodes_count++; + tree_output_queue.push_back( + item); + visited.insert(item); + const Ogre::Node::ChildNodeMap + &children = + item->getChildren(); + for (child = 0; + child < children.size(); + child++) { + tree_output_queue.push_back( + static_cast< + Ogre::SceneNode + *>( + children[child])); + tree_output_queue + .push_back( + nullptr); + } + } else + tree_output_queue.push_back( + item); + } + if (new_nodes_count == 0) + break; + tree_input_queue = tree_output_queue; + tree_output_queue.clear(); + } + tree_list.insert(tree_list.begin(), + tree_output_queue.begin(), + tree_output_queue.end()); + int count = 0; + int depth = 0; + std::vector check_depth; + int max_depth = 0; + check_depth.push_back(0); + for (count = 0; count < tree_list.size(); count++) { + int t; + + Ogre::SceneNode *node = tree_list[count]; + if (node && max_depth >= depth) { + Ogre::String name = node->getName(); + if (name.length() == 0) { + name = "Node #" + + Ogre::StringConverter:: + toString(count); + } + if (ImGui::TreeNode(name.c_str())) { + check_depth.push_back( + max_depth); + max_depth++; + ImGui::Text("%s", + (name + "##caption") + .c_str()); + position_editor(node); + ImGui::Separator(); + orientation_editor(node); + ImGui::Separator(); + ImGui::Text("Attachments"); + attachments_editor(node); + } + } else if (!node && max_depth >= depth) { + max_depth = check_depth.back(); + check_depth.pop_back(); + ImGui::TreePop(); + } + if (tree_list[count]) + depth++; + else + depth--; + } + ImGui::Spacing(); + ImGui::End(); +#if 0 + if (ECS::get().get().narrationBox) { + ImVec2 size = ImGui::GetMainViewport()->Size; + ImGui::SetNextWindowPos(ImVec2(0, + size.y * 0.75f), + ImGuiCond_Always); + ImGui::SetNextWindowSize(ImVec2(size.x, + size.y * 0.25f), + ImGuiCond_Always); + ImGui::Begin("Narration...", NULL, + ImGuiWindowFlags_NoTitleBar); + ImGui::PushFont(midFont); + ImVec2 p = ImGui::GetCursorScreenPos(); + ImGui::TextWrapped( + "%s", ECS::get() + .get() + .narrationText.c_str()); + if (ECS::get().get().choices.size() == 0) { + ImGui::SetCursorScreenPos(p); + if (ImGui::InvisibleButton( + "Background", + ImGui::GetWindowSize())) + ECS::get().mLua->call_handler( + "narration_progress"); + } else { + int i; + for (i = 0; i < ECS::get() + .get() + .choices.size(); + i++) { + if (ImGui::Button( + ECS::get() + .get() + .choices[i] + .c_str())) { + ECS::get() + .get_mut() + .narration_answer = + i + 1; + std::cout << "answer: " + << i + 1 + << std::endl; + ECS::modified(); + ECS::get() + .mLua + ->call_handler( + "narration_answered"); + } + } + } + ImGui::Spacing(); + ImGui::PopFont(); + ImGui::End(); + } else if (ECS::get().get().mainMenu) { + ImVec2 size = ImGui::GetMainViewport()->Size; + ImGui::SetNextWindowPos(ImVec2(0, 0), + ImGuiCond_Always); + ImGui::SetNextWindowSize(ImVec2(size.x, size.y), + ImGuiCond_Always); + ImGui::Begin( + "MainMenu", nullptr, + ImGuiWindowFlags_NoTitleBar | + ImGuiWindowFlags_NoDecoration | + + ImGuiWindowFlags_NoResize | + ImGuiWindowFlags_NoMove | + ImGuiWindowFlags_NoCollapse | + ImGuiWindowFlags_NoFocusOnAppearing | + 0); + // if (ECS::get().get().enabled) + // ECS::get().get().app->setWindowGrab(true); + ImGui::PushFont(bigFont); + ImGui::TextWrapped("%s", "Booo!!!!"); + bool pressed = false; + bool new_game = false, cont = false, + load_game = false, opts = false, + quit = false; + ImGui::SetCursorPosY(size.y / 2.0f - 300.0f); + ImGui::SetCursorPosX(size.x / 2.0f - 300.0f); + new_game = ImGui::Button("New Game"); + ImGui::SetCursorPosX(size.x / 2.0f - 300.0f); + cont = ImGui::Button("Continue"); + ImGui::SetCursorPosX(size.x / 2.0f - 300.0f); + load_game = ImGui::Button("Load Game"); + ImGui::SetCursorPosX(size.x / 2.0f - 300.0f); + opts = ImGui::Button("Options"); + ImGui::SetCursorPosX(size.x / 2.0f - 300.0f); + quit = ImGui::Button("Quit###quit"); + pressed = new_game || cont || load_game || + opts || quit; + ImGui::PopFont(); + ImGui::Spacing(); + ImGui::End(); + if (quit) + Ogre::Root::getSingleton() + .queueEndRendering(); + if (pressed) + ECS::get().get().finish(); + if (new_game) { + ECS::get().mLua->call_handler( + "new_game"); + } + } else { + buttons_panel(); + if (enableEditor) + buildings_editor(); + if (enableMapEditor) + map_editor(); + ImVec2 size = ImGui::GetMainViewport()->Size; + float window_width = size.x * 0.2f; + if (window_width > panel_width) + window_width = panel_width; + float window_height = size.y * 0.5f - 20; + ImGui::SetNextWindowPos( + ImVec2(size.x - window_width, + size.y * 0.5f + 20), + ImGuiCond_Always); + ImGui::SetNextWindowSize(ImVec2(window_width, + window_height), + ImGuiCond_Always); + // ImGui::Begin("Dumb and Stupid", &mKbd.gui_active); + ImGui::Begin("Panel..."); + std::deque tree_input_queue, + tree_output_queue; + std::vector tree_list; + tree_input_queue.push_back( + ECS::get() + .get() + .mScnMgr->getRootSceneNode()); + tree_input_queue.push_back(nullptr); + std::set visited; + while (true) { + int new_nodes_count = 0; + while (!tree_input_queue.empty()) { + int child; + Ogre::SceneNode *item = + tree_input_queue.front(); + tree_input_queue.pop_front(); + if (item && + visited.find(item) == + visited.end()) { // new node + new_nodes_count++; + tree_output_queue + .push_back( + item); + visited.insert(item); + const Ogre::Node::ChildNodeMap + &children = + item->getChildren(); + for (child = 0; + child < + children.size(); + child++) { + tree_output_queue + .push_back(static_cast< + Ogre::SceneNode + *>( + children[child])); + tree_output_queue + .push_back( + nullptr); + } + } else + tree_output_queue + .push_back( + item); + } + if (new_nodes_count == 0) + break; + tree_input_queue = tree_output_queue; + tree_output_queue.clear(); + } + tree_list.insert(tree_list.begin(), + tree_output_queue.begin(), + tree_output_queue.end()); + int count = 0; + int depth = 0; + std::vector check_depth; + int max_depth = 0; + check_depth.push_back(0); + for (count = 0; count < tree_list.size(); + count++) { + int t; + + Ogre::SceneNode *node = + tree_list[count]; + if (node && max_depth >= depth) { + Ogre::String name = + node->getName(); + if (name.length() == 0) { + name = "Node #" + + Ogre::StringConverter:: + toString( + count); + } + if (ImGui::TreeNode( + name.c_str())) { + check_depth.push_back( + max_depth); + max_depth++; + ImGui::Text( + "%s", + (name + + "##caption") + .c_str()); + position_editor(node); + ImGui::Separator(); + orientation_editor( + node); + ImGui::Separator(); + ImGui::Text( + "Attachments"); + attachments_editor( + node); + } + } else if (!node && + max_depth >= depth) { + max_depth = check_depth.back(); + check_depth.pop_back(); + ImGui::TreePop(); + } + if (tree_list[count]) + depth++; + else + depth--; + } + ImGui::Spacing(); + ImGui::End(); + } +#endif + } + } +}; GUIModule::GUIModule(flecs::world &ecs) { + ecs.module(); + ecs.import (); ecs.component() .on_add([](GUI &gui) { gui.enabled = false; @@ -522,4 +1058,46 @@ GUIModule::GUIModule(flecs::world &ecs) } }); } +EditorGUIModule::EditorGUIModule(flecs::world &ecs) +{ + ecs.module(); + ecs.import (); + ecs.component() + .on_add([](GUI &gui) { + gui.enabled = true; + gui.grab = false; + gui.grabChanged = false; + }) + .add(flecs::Singleton); + ecs.component() + .on_add([](EditorGUIData &priv) { + priv.glb_names.clear(); + priv.mGUIListener = nullptr; + priv.mGuiOverlay = nullptr; + }) + .add(flecs::Singleton); + ecs.observer("SupportEditorGUI") + .event(flecs::OnSet) + .without() + .each([](const RenderWindow &window, const App &app, GUI &gui) { + float vpScale = window.dpi / 96 * + window.window->getWidth() / 1600.0f; + Ogre::OverlayManager::getSingleton().setPixelRatio( + vpScale); + std::cout << "Editor GUI configure\n"; + OgreAssert(app.mGuiOverlay, "No ImGUI overlay"); + Ogre::ImGuiOverlay *guiOverlay = app.mGuiOverlay; + EditorGUIListener *guiListener = + new EditorGUIListener(guiOverlay); + guiOverlay->setZOrder(300); + guiOverlay->show(); + guiListener->panel_width = 300.0f; + guiListener->enableEditor = false; + window.window->addListener(guiListener); + + ECS::get().set( + { app.mGuiOverlay, {}, guiListener }); + std::cout << "Editor GUI configure finished\n"; + }); +} } \ No newline at end of file diff --git a/src/gamedata/GUIModule.h b/src/gamedata/GUIModule.h index 8b0dbc5..3043430 100644 --- a/src/gamedata/GUIModule.h +++ b/src/gamedata/GUIModule.h @@ -17,11 +17,11 @@ struct GUI { int narration_answer; static void setWindowGrab(bool g = true) { - ECS::GUI &gui = ECS::get().get_mut(); + ECS::GUI &gui = ECS::get().get_mut(); if (gui.grab != g) { gui.grab = g; gui.grabChanged = true; - ECS::get().modified(); + ECS::get().modified(); } } static void finish() @@ -38,5 +38,8 @@ struct GUIModule { flecs::entity ui_wait; GUIModule(flecs::world &ecs); }; +struct EditorGUIModule { + EditorGUIModule(flecs::world &ecs); +}; } #endif \ No newline at end of file diff --git a/src/gamedata/GameData.cpp b/src/gamedata/GameData.cpp index 483c1b4..1591cc7 100644 --- a/src/gamedata/GameData.cpp +++ b/src/gamedata/GameData.cpp @@ -15,6 +15,8 @@ #include "PhysicsModule.h" #include "EventModule.h" #include "CharacterManagerModule.h" +#include "VehicleManagerModule.h" +#include "AppModule.h" #include "world-build.h" namespace ECS @@ -30,18 +32,9 @@ void setup_minimal() ecs.import (); ecs.import (); ecs.import (); + ecs.import (); ecs.import (); - ecs.component(); - ecs.component().add(flecs::Singleton); - ecs.component().add(flecs::Singleton); - ecs.component().add(flecs::Singleton); - ecs.component() - .on_add([](App &app) { - app.mInput = nullptr; - app.mGuiOverlay = nullptr; - app.listeners.clear(); - }) - .add(flecs::Singleton); + ecs.import (); /* lots of things depend on it */ ecs.component().add(flecs::Singleton); } @@ -108,6 +101,11 @@ void setup(Ogre::SceneManager *scnMgr, Ogre::SceneNode *cameraNode, nullptr, false, { 0, 0, 0 } }); + if (!ecs.has()) + ecs.add(); + if (!ecs.has()) + ecs.set({}); + // ecs.set({}); std::cout << "Setup GameData done\n"; @@ -116,6 +114,79 @@ void setup(Ogre::SceneManager *scnMgr, Ogre::SceneNode *cameraNode, { 0, 0, 4 }, Ogre::Quaternion(Ogre::Radian(Ogre::Math::PI), Ogre::Vector3::UNIT_Y)); } +void setupEditor(Ogre::SceneManager *scnMgr, Ogre::SceneNode *cameraNode, + Ogre::Camera *camera, Ogre::RenderWindow *window) +{ + std::cout << "Setup Editor\n"; + setup_minimal(); + ecs.component().add(flecs::Singleton); + ecs.import (); + ecs.import (); + ecs.import (); + ecs.import (); + ecs.import (); + ecs.import (); + ecs.import (); + ecs.import (); + ecs.import (); + // ecs.import (); + ecs.import (); + + ecs.system("UpdateDelta") + .kind(flecs::OnUpdate) + .each([](EngineData &eng) { + eng.delta = ECS::get().delta_time(); + }); + ecs.system("UpdateDelay") + .kind(flecs::OnUpdate) + .with() + .with() + .with() + .each([](EngineData &eng) { + if (eng.startupDelay >= 0.0f) + eng.startupDelay -= eng.delta; +#ifdef VDEBUG + if (ECS::get().has()) + std::cout << "ground check ready\n"; +#endif + }); + ecs.system("CheckStatus") + .kind(flecs::OnUpdate) + .run([](flecs::iter &it) { +#ifdef VDEBUG + if (ECS::get().has()) + std::cout << "water ready\n"; + if (ECS::get().has()) + std::cout << "terrain ready\n"; + if (ECS::get().has()) + std::cout << "ground check ready\n"; +#endif + }); + ecs.set({ scnMgr, 0.0f, 5.0f, (int)window->getWidth(), + (int)window->getHeight(), false }); + ecs.set({ cameraNode, camera, false }); + ecs.add(); + ecs.add(); + ecs.add(); + ecs.set({ nullptr, nullptr, nullptr, nullptr }); + ecs.set({ nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + false, + { 0, 0, 0 } }); + ecs.set({ true, true, true, false, false, "", {}, -1 }); + ecs.get_mut().enabled = true; + ecs.get_mut().setWindowGrab(false); + ecs.modified(); + ecs.get_mut().setWindowGrab(true); + ecs.modified(); + ecs.get_mut().enabled = true; + ecs.modified(); +} + void update(float delta) { ecs.progress(delta); diff --git a/src/gamedata/GameData.h b/src/gamedata/GameData.h index 86ed828..ac35df0 100644 --- a/src/gamedata/GameData.h +++ b/src/gamedata/GameData.h @@ -7,6 +7,8 @@ extern flecs::entity player; void setup_minimal(); void setup(Ogre::SceneManager *scnMgr, Ogre::SceneNode *cameraNode, Ogre::Camera *camera, Ogre::RenderWindow *window); +void setupEditor(Ogre::SceneManager *scnMgr, Ogre::SceneNode *cameraNode, + Ogre::Camera *camera, Ogre::RenderWindow *window); void update(float delta); flecs::world get(); template const T &get() @@ -22,4 +24,4 @@ template void modified() ECS::get().modified(); } } -#endif \ No newline at end of file +#endif diff --git a/src/gamedata/LuaData.cpp b/src/gamedata/LuaData.cpp index 759b773..fe385e6 100644 --- a/src/gamedata/LuaData.cpp +++ b/src/gamedata/LuaData.cpp @@ -6,6 +6,7 @@ #include "CharacterModule.h" #include "CharacterAnimationModule.h" #include "CharacterManagerModule.h" +#include "VehicleManagerModule.h" #include "BoatModule.h" #include "EventTriggerModule.h" #include "SlotsModule.h" @@ -365,12 +366,14 @@ LuaData::LuaData() float x = lua_tonumber(L, 2); float y = lua_tonumber(L, 3); float z = lua_tonumber(L, 4); - flecs::entity e = ECS::get().entity(); Ogre::Quaternion orientation(Ogre::Radian(yaw), Ogre::Vector3(0, 1, 0)); Ogre::Vector3 position(x, y, z); - e.set( - { "boat.scene", position, orientation }); + flecs::entity e = + ECS::get_mut() + .createVehicleAtPosition( + "boat", position, orientation); + ECS::modified(); int ret = idmap.add_entity(e); lua_pushinteger(L, ret); std::cout << "boat created: " << ret << std::endl; @@ -380,12 +383,14 @@ LuaData::LuaData() float x = lua_tonumber(L, 2); float y = lua_tonumber(L, 3); float z = lua_tonumber(L, 4); - flecs::entity e = ECS::get().entity(); Ogre::Quaternion orientation(Ogre::Radian(yaw), Ogre::Vector3(0, 1, 0)); Ogre::Vector3 position(x, y, z); - e.set( - { "raft.scene", position, orientation }); + flecs::entity e = + ECS::get_mut() + .createVehicleAtPosition( + "raft", position, orientation); + ECS::modified(); int ret = idmap.add_entity(e); lua_pushinteger(L, ret); std::cout << "raft created: " << ret << std::endl; @@ -840,6 +845,7 @@ LuaModule::LuaModule(flecs::world &ecs) { ecs.module(); ecs.import (); + ecs.import (); ecs.component(); ecs.component() .on_add([](LuaBase &lua) { @@ -849,11 +855,6 @@ LuaModule::LuaModule(flecs::world &ecs) }) .add(flecs::Singleton); ecs.component().add(flecs::Singleton); - if (!ecs.has()) - ecs.add(); - if (!ecs.has()) - ecs.set({}); - ecs.system("LuaUpdate") .kind(flecs::OnUpdate) .each([](const EngineData &eng, LuaBase &lua) { diff --git a/src/gamedata/VehicleManagerModule.cpp b/src/gamedata/VehicleManagerModule.cpp new file mode 100644 index 0000000..2f4dd66 --- /dev/null +++ b/src/gamedata/VehicleManagerModule.cpp @@ -0,0 +1,24 @@ +#include "Components.h" +#include "GameData.h" +#include "BoatModule.h" +#include "VehicleManagerModule.h" +namespace ECS +{ +VehicleManagerModule::VehicleManagerModule(flecs::world &ecs) +{ + ecs.module(); + ecs.import (); +} +flecs::entity VehicleManagerModule::createVehicleAtPosition( + const Ogre::String &name, const Ogre::Vector3 &position, + const Ogre::Quaternion &orientation) +{ + flecs::entity vehicle = ECS::get().entity(); + if (name == "boat") + vehicle.set( + { name + ".scene", position, orientation }); + else + OgreAssert(false, "unsupported type: " + name); + return vehicle; +} +} \ No newline at end of file diff --git a/src/gamedata/VehicleManagerModule.h b/src/gamedata/VehicleManagerModule.h new file mode 100644 index 0000000..3bf83f9 --- /dev/null +++ b/src/gamedata/VehicleManagerModule.h @@ -0,0 +1,15 @@ +#ifndef _VEHICLE_MANAGER_MODULE_H_ +#define _VEHICLE_MANAGE_MODULE_H_ +#include +#include +namespace ECS +{ +struct VehicleManagerModule { + VehicleManagerModule(flecs::world &ecs); + flecs::entity + createVehicleAtPosition(const Ogre::String &name, + const Ogre::Vector3 &position, + const Ogre::Quaternion &orientation); +}; +} +#endif \ No newline at end of file diff --git a/src/world/CMakeLists.txt b/src/world/CMakeLists.txt index f16a1da..f9ac896 100644 --- a/src/world/CMakeLists.txt +++ b/src/world/CMakeLists.txt @@ -1,4 +1,5 @@ project(world) +set(CMAKE_CXX_STANDARD 17) find_package(Bullet) find_package(OGRE REQUIRED COMPONENTS Bites Bullet Paging Terrain Overlay CONFIG) add_library(action STATIC action.cpp)