diff --git a/CMakeLists.txt b/CMakeLists.txt index a1b5d489..493339a8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -281,7 +281,6 @@ if(NOT DEFINED RX_MODULES) importers scene terrain - edit world render ui/imgui @@ -304,6 +303,7 @@ if(NOT DEFINED RX_MODULES) locomotion ui/ugui app + editor ) endif() diff --git a/apps/editor/CMakeLists.txt b/apps/editor/CMakeLists.txt index d17d09c1..cffb2a9c 100644 --- a/apps/editor/CMakeLists.txt +++ b/apps/editor/CMakeLists.txt @@ -1,21 +1,9 @@ -# rx editor: an app::Application on app::Host with its entire UI in rx::ui -# (libultragui in draw-data mode). The ugui backend, platform shim and pipeline -# shaders live in rxe/ui/ugui now, because the engine splash needs them too. - -add_executable(rx_editor - main.cc - editor_app.cc - editor_terrain.cc - editor_ui.cc - editor_input.cc) +# The default rx editor: rx::editor (rxe/editor) on app::Host. A game builds its +# own editor the same way, linking its modules next to rx::editor. +add_executable(rx_editor_app main.cc) +# rx_editor is the rx::editor module; the binary keeps the name users run. +set_target_properties(rx_editor_app PROPERTIES OUTPUT_NAME rx_editor) +target_link_libraries(rx_editor_app PRIVATE rx::editor rx::app rx::foundation) # An engine build: the tiers ship loose beside it, to be edited. -rx_stage_content(rx_editor LOOSE_ENGINE_CONFIG) - -target_link_libraries(rx_editor PRIVATE - rx::app rx::ui rx::edit rx::terrain rx::render rx::anim rx::gltf rx::usd rx::blend rx::asset rx::scene rx::ecs rx::window rx::events rx::foundation - # Bake World: the same cook rxworld runs, so an archive from either is the same bytes. - rx::world) - -target_compile_definitions(rx_editor PRIVATE - RX_EDITOR_UI_DIR="${CMAKE_CURRENT_SOURCE_DIR}/ui" - RX_BLEND_CONVERTER_SCRIPT="${PROJECT_SOURCE_DIR}/tools/blend_to_glb.py") +rx_stage_content(rx_editor_app LOOSE_ENGINE_CONFIG) +rx_set_warnings(rx_editor_app) diff --git a/apps/editor/main.cc b/apps/editor/main.cc index 4665d7aa..775619a8 100644 --- a/apps/editor/main.cc +++ b/apps/editor/main.cc @@ -5,8 +5,8 @@ #include #include "base/strings/xstring.h" -#include "editor_app.h" #include "rxe/app/host.h" +#include "rxe/editor/editor_app.h" int main(int argc, char** argv) { base::String open_path; @@ -15,9 +15,6 @@ int main(int argc, char** argv) { if (!a.empty() && a[0] != '-') open_path = a; } -#if defined(RX_SHARED_BUILD) - rx::base::InitOptionsFromEnv(); -#endif rx::app::AppConfig config; config.id = "xn5ec6v99hcwg9d8xzbqshr0"; diff --git a/apps/rxworld/CMakeLists.txt b/apps/rxworld/CMakeLists.txt index df29924f..a9233a52 100644 --- a/apps/rxworld/CMakeLists.txt +++ b/apps/rxworld/CMakeLists.txt @@ -1,3 +1,3 @@ add_executable(rxworld main.cc) -target_link_libraries(rxworld PRIVATE rx::world rx::edit rx::asset rx::ecs rx::foundation) +target_link_libraries(rxworld PRIVATE rx::world rx::asset rx::ecs rx::foundation) rx_set_warnings(rxworld) diff --git a/apps/shell/CMakeLists.txt b/apps/shell/CMakeLists.txt index 92a8a2d8..0bff9ad2 100644 --- a/apps/shell/CMakeLists.txt +++ b/apps/shell/CMakeLists.txt @@ -40,7 +40,7 @@ set(RX_RUNTIME_MODULES rx::blend rx::scene # .rxscene text scenes: component reflection + the text loader. - rx::edit + # --world: baked worlds streamed around the camera. rx::world # --authoring-endpoint / --dump-commands: the live script command surface. @@ -125,7 +125,7 @@ endif() add_library(viewer_scene_authoring STATIC scene_authoring.cc) target_include_directories(viewer_scene_authoring PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) target_link_libraries(viewer_scene_authoring PUBLIC - rx::gltf rx::materialx rx::edit rx::scene rx::ecs rx::asset rx::render rx::foundation) + rx::gltf rx::materialx rx::scene rx::ecs rx::asset rx::render rx::foundation) rx_set_warnings(viewer_scene_authoring) add_executable(rx main.cc ${RX_RUNTIME_SOURCES}) diff --git a/cmake/install.cmake b/cmake/install.cmake index 3bd5968a..0993c178 100644 --- a/cmake/install.cmake +++ b/cmake/install.cmake @@ -37,7 +37,7 @@ set(RX_DEPS_INCDIR ${CMAKE_INSTALL_INCLUDEDIR}/rx-deps) # rx module targets + export set set(RX_MODULE_NAMES foundation events window gpu ecs script asset gltf usd materialx blend scene terrain render imgui_renderer render2d physics vehicles locomotion anim audio - weather rpc devtools character inventory inventory_world ui app) + weather rpc devtools character inventory inventory_world ui app world editor) set(RX_INSTALL_TARGETS) foreach(_m ${RX_MODULE_NAMES}) # Some modules are conditional (inventory_world only when rx_physics exists); diff --git a/docs/CONFIG.md b/docs/CONFIG.md index 4f186a01..c9d85650 100644 --- a/docs/CONFIG.md +++ b/docs/CONFIG.md @@ -70,7 +70,7 @@ reproduces the layout beside build-tree executables, re-copied every build: ```cmake rx_stage_content(mygame mytool) # Data/ beside both (same directory) -rx_stage_content(rx_editor LOOSE_ENGINE_CONFIG) # engine builds: + rxe/config/ +rx_stage_content(rx_editor_app LOOSE_ENGINE_CONFIG) # engine builds: + rxe/config/ add_custom_target(mygame_config ALL COMMAND ${CMAKE_COMMAND} -E copy_directory_if_different ${CMAKE_CURRENT_SOURCE_DIR}/config $/config) add_dependencies(mygame mygame_config) diff --git a/docs/STRUCTURE.md b/docs/STRUCTURE.md index 76ba2e33..08d29f1e 100644 --- a/docs/STRUCTURE.md +++ b/docs/STRUCTURE.md @@ -74,11 +74,12 @@ rxe/ the engine (Chromium: content/) world_bake/ offline world baking (tools and the editor link it, games do not) devtools/ the command bridge and endpoint (rxcall, agents) app/ Host, Application, AppConfig, platform config, world clock + terrain/ heightfield terrain (the editor edits it, so it is engine) editor/ the editor itself: selection, undo, panels, editor ui resources/ everything in rxe://: fonts/, config/ plugins/ optional, enabled per app (Chromium: components/) - character/ combat/ inventory/ locomotion/ placement/ terrain/ + character/ combat/ inventory/ locomotion/ placement/ nav/ nav/ + nav_debug/ (the only half that knows the renderer) replication/ replication/ + replication_debug/ vehicles/ cars, boats, aircraft, kites: physics, profiles, engine audio @@ -124,8 +125,10 @@ of that: `ecs`, `scene`, `script`, `world` or `app`. They work on their own handles, so they can be tested without an entity world, and `scene`/`app` are the only places that bind them to entities. This already holds today; the rule keeps it. -- **Nothing depends on `app`.** It is the engine's composition root: the only - module that knows every subsystem, with no feature logic of its own. +- **Nothing depends on `app` except apps and `editor`.** It is the engine's + composition root: the only module that knows every subsystem, with no feature + logic of its own. The editor is the one engine module that is itself an + application (games extend it), so it sits on the host the way an app does. - **Nothing a shipping game must link depends on `editor`, `world_bake` or `importers/usd`.** An app gets them only by asking. @@ -424,7 +427,12 @@ and after. local `export.h` workarounds are gone) and ships in the install package. `RX_PLUGIN`, `PluginRegistry` and `rx_add_app` wait for a plugin that needs startup registration; none does today. - - 6c: `rxe/editor` and a thin `apps/editor`, per-game editors. + - 6c (done): `rxe/editor` (`rx::editor`: the editor app code plus + selection and undo from `edit`) and `apps/editor`, now a `main.cc`. A + game's editor is its own `main.cc` over `rx::editor`. `terrain` moves + from `plugins/` into `rxe/`: terrain editing is built into the editor, and + an engine module cannot depend on a plugin. It can return to `plugins/` + with its editor mode once the editor has an extension point. - 6d: `EngineContext` goes away; the demos move to `apps/shell/demos` in `rx::shell`. 7. **Renderer features.** A separate design note for `RenderFeature`, then split diff --git a/plugins/inventory/README.md b/plugins/inventory/README.md index e633fa01..4d6eaaa3 100644 --- a/plugins/inventory/README.md +++ b/plugins/inventory/README.md @@ -79,7 +79,7 @@ after any bulk removal so equipped slots referencing vanished items clear. Inventories and world items serialize to compact, explicit-little-endian blobs (`byte_io.h`): a 4-byte magic + `u32` version + records. This was chosen over -`rxe/edit/` reflection + `.rxscene` deliberately: +`rxe/scene/` reflection + `.rxscene` deliberately: - Inventories are **frequently-mutated gameplay state** written to a *game save file*, not editor scene documents. They want a tiny, stable, self-describing diff --git a/plugins/inventory/serialize.h b/plugins/inventory/serialize.h index ab3fb0d4..83a32d35 100644 --- a/plugins/inventory/serialize.h +++ b/plugins/inventory/serialize.h @@ -7,7 +7,7 @@ #include "foundation/build_config/export.h" // Compact, versioned, explicit-little-endian persistence for inventories and -// equipment. A self-contained binary blob is used rather than edit::/.rxscene +// equipment. A self-contained binary blob is used rather than editor::/.rxscene // reflection: inventories are frequently-mutated gameplay state saved to a game // save file, not editor scene documents, and the blob wants to be stable, // tiny and independent of the editor module's schema. See the module README for diff --git a/rxe/edit/CMakeLists.txt b/rxe/edit/CMakeLists.txt deleted file mode 100644 index 15249448..00000000 --- a/rxe/edit/CMakeLists.txt +++ /dev/null @@ -1,18 +0,0 @@ -rx_add_module(edit - selection.cc - undo.cc -) - -# Editor state over the scene: undo/redo and selection. Reflection, the -# transform hierarchy and .rxscene io live in rx::scene, because a game needs -# them without the editor. Deliberately NOT on rx::render (the editor UI links -# render separately and drives it through the FrameView contract). -target_link_libraries(rx_edit PUBLIC rx::foundation rx::ecs rx::scene rx::asset) - -if(RX_BUILD_TESTS) - # Editor foundations test: reflection, scene round-trip, undo/redo and hierarchy - # composition. Fully headless (no GPU), so it always runs under plain ctest. - add_executable(edit_test edit_test.cc) - target_link_libraries(edit_test PRIVATE rx::edit rx::scene rx::ecs rx::asset rx::foundation) - add_test(NAME edit_test COMMAND edit_test) -endif() diff --git a/rxe/editor/CMakeLists.txt b/rxe/editor/CMakeLists.txt new file mode 100644 index 00000000..5927c2d0 --- /dev/null +++ b/rxe/editor/CMakeLists.txt @@ -0,0 +1,32 @@ +# rx::editor: the editor itself, as a library a game links into its own editor +# app (apps/editor is the default one: a main.cc over this module). Editing +# state (undo/redo, selection), the ugui interface, terrain and surface +# placement tools, import and world baking. Reflection, the transform hierarchy +# and .rxscene io live in rx::scene, because a game needs them without the +# editor. +rx_add_module(editor + editor_app.cc + editor_terrain.cc + editor_ui.cc + editor_input.cc + selection.cc + undo.cc +) + +target_link_libraries(rx_editor PUBLIC + rx::app rx::ui rx::terrain rx::render rx::anim rx::gltf rx::usd rx::blend rx::asset + rx::scene rx::ecs rx::window rx::events rx::foundation + # Bake World: the same cook rxworld runs, so an archive from either is the same bytes. + rx::world) + +target_compile_definitions(rx_editor PRIVATE + RX_EDITOR_UI_DIR="${CMAKE_CURRENT_SOURCE_DIR}/ui" + RX_BLEND_CONVERTER_SCRIPT="${PROJECT_SOURCE_DIR}/tools/blend_to_glb.py") + +if(RX_BUILD_TESTS) + # Editing model test: reflection, scene round-trip, undo/redo and hierarchy + # composition. Fully headless (no GPU), so it always runs under plain ctest. + add_executable(edit_test edit_test.cc) + target_link_libraries(edit_test PRIVATE rx::editor rx::scene rx::ecs rx::asset rx::foundation) + add_test(NAME edit_test COMMAND edit_test) +endif() diff --git a/rxe/edit/edit_test.cc b/rxe/editor/edit_test.cc similarity index 99% rename from rxe/edit/edit_test.cc rename to rxe/editor/edit_test.cc index 386b8730..a3afa9a8 100644 --- a/rxe/edit/edit_test.cc +++ b/rxe/editor/edit_test.cc @@ -16,15 +16,15 @@ #include "rxe/asset/asset_id.h" #include "rxe/asset/vfs.h" #include "rxe/ecs/world.h" -#include "rxe/edit/selection.h" -#include "rxe/edit/undo.h" +#include "rxe/editor/selection.h" +#include "rxe/editor/undo.h" #include "rxe/scene/components.h" #include "rxe/scene/hierarchy.h" #include "rxe/scene/reflect.h" #include "rxe/scene/scene_io.h" using namespace rx; -using namespace rx::edit; +using namespace rx::editor; namespace { diff --git a/apps/editor/editor_app.cc b/rxe/editor/editor_app.cc similarity index 99% rename from apps/editor/editor_app.cc rename to rxe/editor/editor_app.cc index c318f596..0b86a92f 100644 --- a/apps/editor/editor_app.cc +++ b/rxe/editor/editor_app.cc @@ -870,7 +870,7 @@ void Editor::OnUpdate(f32 dt) { if (!ctrl && editor_mode_ == EditorMode::kSelect && over_vp && edge(ui::Key::kDelete)) { if (ecs::Entity e = selection_.primary()) { - undo_.Push(*world_, edit::MakeDestroyEntity(*world_, e)); + undo_.Push(*world_, editor::MakeDestroyEntity(*world_, e)); selection_.Clear(); MarkDirty(); doc_dirty_ = true; @@ -1099,7 +1099,7 @@ void Editor::UpdateGizmo(f32 mx, f32 my, bool lmb_down, bool lmb_edge) { const scene::ComponentDesc *comp = scene::FindComponentByName("Transform"); if (comp) { undo_.Push(*world_, - edit::MakeSetProp(*world_, e, *comp, comp->props[0], + editor::MakeSetProp(*world_, e, *comp, comp->props[0], scene::PropValue::Vec3(np.x, np.y, np.z))); doc_dirty_ = true; } @@ -1577,10 +1577,10 @@ void Editor::RunAutopilot() { selection_.Set(e); undo_.BeginGroup("Move"); undo_.Push(*world_, - edit::MakeSetProp(*world_, e, *xf, xf->props[0], + editor::MakeSetProp(*world_, e, *xf, xf->props[0], scene::PropValue::Vec3(-1.2f, 0.55f, 1.0f))); undo_.Push(*world_, - edit::MakeSetProp(*world_, e, *xf, xf->props[0], + editor::MakeSetProp(*world_, e, *xf, xf->props[0], scene::PropValue::Vec3(-1.2f, 0.55f, 2.0f))); undo_.EndGroup(); doc_dirty_ = true; diff --git a/apps/editor/editor_app.h b/rxe/editor/editor_app.h similarity index 98% rename from apps/editor/editor_app.h rename to rxe/editor/editor_app.h index 9b88abe0..0309ce8f 100644 --- a/apps/editor/editor_app.h +++ b/rxe/editor/editor_app.h @@ -20,13 +20,13 @@ #include "base/memory/move.h" #include "base/optional.h" #include "base/strings/xstring.h" -#include "plugins/terrain/terrain.h" -#include "rxe/edit/selection.h" -#include "rxe/edit/undo.h" +#include "rxe/editor/selection.h" +#include "rxe/editor/undo.h" #include "rxe/scene/fly_camera.h" #include "rxe/scene/hierarchy.h" #include "rxe/scene/reflect.h" #include "rxe/scene/scene_io.h" +#include "rxe/terrain/terrain.h" #include "rxe/ui/ugui/ugui_backend.h" #include "rxe/ui/ugui/ugui_platform.h" #include "rxe/world/world_bake.h" @@ -262,8 +262,8 @@ class Editor final : public app::Application { // editor state scene::FlyCamera camera_; - edit::Selection selection_; - edit::UndoStack undo_; + editor::Selection selection_; + editor::UndoStack undo_; base::Optional assets_; // constructed once vfs is known GizmoMode gizmo_mode_ = GizmoMode::kTranslate; EditorMode editor_mode_ = EditorMode::kSelect; diff --git a/apps/editor/editor_input.cc b/rxe/editor/editor_input.cc similarity index 98% rename from apps/editor/editor_input.cc rename to rxe/editor/editor_input.cc index fe70d17b..92dd4bdf 100644 --- a/apps/editor/editor_input.cc +++ b/rxe/editor/editor_input.cc @@ -3,7 +3,7 @@ #include "rxe/ui/events/input.h" #include "rxe/ui/events/input_bindings.h" -namespace rx { +namespace rx::editor { void RegisterEditorInput(ui::InputMap& map) { map.RegisterAction(Action::kMoveForward, "move_forward"); @@ -57,4 +57,4 @@ void RegisterEditorInput(ui::InputMap& map) { }); } -} // namespace rx +} // namespace rx::editor diff --git a/apps/editor/editor_input.h b/rxe/editor/editor_input.h similarity index 92% rename from apps/editor/editor_input.h rename to rxe/editor/editor_input.h index 62052efb..134f52a3 100644 --- a/apps/editor/editor_input.h +++ b/rxe/editor/editor_input.h @@ -7,7 +7,7 @@ namespace rx::ui { class InputMap; } // namespace rx::ui -namespace rx { +namespace rx::editor { // The editor's action/axis set. The engine owns no verbs, so the app defines @@ -31,6 +31,6 @@ enum class Axis : ui::AxisId { kMoveX, kMoveY, kLookX, kLookY, kCount }; void RegisterEditorInput(ui::InputMap& map); -} // namespace rx +} // namespace rx::editor #endif // RX_EDITOR_INPUT_H_ diff --git a/apps/editor/editor_terrain.cc b/rxe/editor/editor_terrain.cc similarity index 99% rename from apps/editor/editor_terrain.cc rename to rxe/editor/editor_terrain.cc index b32dc45e..cbdc55a2 100644 --- a/apps/editor/editor_terrain.cc +++ b/rxe/editor/editor_terrain.cc @@ -42,7 +42,7 @@ u32 PackRgba(const base::Array& color) { (static_cast(color[2]) << 8) | color[3]; } -class TerrainCommand final : public edit::Command { +class TerrainCommand final : public editor::Command { public: using Refresh = base::Function)>; @@ -452,7 +452,7 @@ void Editor::UpdateModeInteraction(bool lmb_down, bool lmb_edge) { initial.push_back( {renderable, {{&renderable->props[0], scene::PropValue::AssetIdV(placement_.mesh.hash)}}}); initial.push_back({name, {{&name->props[0], scene::PropValue::String(placement_.name)}}}); - undo_.Push(*world_, edit::MakeCreateEntity(base::move(initial), nullptr)); + undo_.Push(*world_, editor::MakeCreateEntity(base::move(initial), nullptr)); doc_dirty_ = true; MarkDirty(); }; diff --git a/apps/editor/editor_ui.cc b/rxe/editor/editor_ui.cc similarity index 99% rename from apps/editor/editor_ui.cc rename to rxe/editor/editor_ui.cc index b51bc357..374e7822 100644 --- a/apps/editor/editor_ui.cc +++ b/rxe/editor/editor_ui.cc @@ -1193,7 +1193,7 @@ bool Editor::RouteClick(const base::String &name, ugui::MouseButton) { initial.push_back({xf, {}}); initial.push_back( {nm, {{&nm->props[0], scene::PropValue::String("Empty")}}}); - undo_.Push(*world_, edit::MakeCreateEntity(base::move(initial), &out)); + undo_.Push(*world_, editor::MakeCreateEntity(base::move(initial), &out)); selection_.Set(out); doc_dirty_ = true; MarkDirty(); @@ -1201,7 +1201,7 @@ bool Editor::RouteClick(const base::String &name, ugui::MouseButton) { } if (name == "hier_del") { if (ecs::Entity e = selection_.primary()) { - undo_.Push(*world_, edit::MakeDestroyEntity(*world_, e)); + undo_.Push(*world_, editor::MakeDestroyEntity(*world_, e)); selection_.Clear(); doc_dirty_ = true; MarkDirty(); @@ -1229,7 +1229,7 @@ bool Editor::RouteClick(const base::String &name, ugui::MouseButton) { ecs::ComponentId id = tail_u("insp_add_"); if (const scene::ComponentDesc *c = scene::FindComponent(id)) if (ecs::Entity e = selection_.primary()) { - undo_.Push(*world_, edit::MakeAddComponent(*world_, e, *c)); + undo_.Push(*world_, editor::MakeAddComponent(*world_, e, *c)); add_menu_open_ = false; doc_dirty_ = true; MarkDirty(); @@ -1240,7 +1240,7 @@ bool Editor::RouteClick(const base::String &name, ugui::MouseButton) { ecs::ComponentId id = tail_u("insp_rm_"); if (const scene::ComponentDesc *c = scene::FindComponent(id)) if (ecs::Entity e = selection_.primary()) { - undo_.Push(*world_, edit::MakeRemoveComponent(*world_, e, *c)); + undo_.Push(*world_, editor::MakeRemoveComponent(*world_, e, *c)); doc_dirty_ = true; MarkDirty(); } @@ -1256,7 +1256,7 @@ bool Editor::RouteClick(const base::String &name, ugui::MouseButton) { c->props[pi].type == scene::PropType::kBool) { scene::PropValue v; scene::GetProp(*world_, e, *c, c->props[pi], &v); - undo_.Push(*world_, edit::MakeSetProp(*world_, e, *c, c->props[pi], + undo_.Push(*world_, editor::MakeSetProp(*world_, e, *c, c->props[pi], scene::PropValue::Bool(!v.b))); doc_dirty_ = true; MarkDirty(); @@ -1516,14 +1516,14 @@ void Editor::UpdateScrub() { euler[scrub_.axis] = scrub_.base_value + dx * scrub_.step; Quat q = EulerToQuat(euler); undo_.Push(*world_, - edit::MakeSetProp(*world_, scrub_.entity, *scrub_.comp, pd, + editor::MakeSetProp(*world_, scrub_.entity, *scrub_.comp, pd, scene::PropValue::Quat(q.x, q.y, q.z, q.w))); } else { if (pd.min != pd.max) nv = rx::Clamp(nv, pd.min, pd.max); scene::PropValue out = v; out.f[scrub_.axis] = nv; - undo_.Push(*world_, edit::MakeSetProp(*world_, scrub_.entity, *scrub_.comp, + undo_.Push(*world_, editor::MakeSetProp(*world_, scrub_.entity, *scrub_.comp, pd, out)); } doc_dirty_ = true; diff --git a/rxe/edit/selection.cc b/rxe/editor/selection.cc similarity index 91% rename from rxe/edit/selection.cc rename to rxe/editor/selection.cc index a3f08038..ce489790 100644 --- a/rxe/edit/selection.cc +++ b/rxe/editor/selection.cc @@ -1,8 +1,8 @@ -#include "rxe/edit/selection.h" +#include "rxe/editor/selection.h" #include "base/algorithm.h" -namespace rx::edit { +namespace rx::editor { void Selection::Clear() { entities_.clear(); @@ -41,4 +41,4 @@ bool Selection::Contains(ecs::Entity entity) const { return base::Find(entities_.begin(), entities_.end(), entity) != entities_.end(); } -} // namespace rx::edit +} // namespace rx::editor diff --git a/rxe/edit/selection.h b/rxe/editor/selection.h similarity index 93% rename from rxe/edit/selection.h rename to rxe/editor/selection.h index 54a4730b..4ac81abf 100644 --- a/rxe/edit/selection.h +++ b/rxe/editor/selection.h @@ -7,12 +7,12 @@ #include "foundation/build_config/export.h" #include "rxe/ecs/entity.h" -namespace rx::edit { +namespace rx::editor { // The set of currently selected entities. The "primary" is the anchor for // single-target operations (the gizmo pivot, the inspector's subject): the most // recently added or set entity, and it stays valid as long as it is in the set. -class RX_EDIT_EXPORT Selection { +class RX_EDITOR_EXPORT Selection { public: void Clear(); // Replaces the selection with a single entity (becomes primary). @@ -34,6 +34,6 @@ class RX_EDIT_EXPORT Selection { ecs::Entity primary_{}; }; -} // namespace rx::edit +} // namespace rx::editor #endif // RX_EDIT_SELECTION_H_ diff --git a/apps/editor/ui/editor.ugui b/rxe/editor/ui/editor.ugui similarity index 100% rename from apps/editor/ui/editor.ugui rename to rxe/editor/ui/editor.ugui diff --git a/rxe/edit/undo.cc b/rxe/editor/undo.cc similarity index 99% rename from rxe/edit/undo.cc rename to rxe/editor/undo.cc index ad384ec8..20af9ab1 100644 --- a/rxe/edit/undo.cc +++ b/rxe/editor/undo.cc @@ -1,4 +1,4 @@ -#include "rxe/edit/undo.h" +#include "rxe/editor/undo.h" #include "base/containers/pair.h" #include "base/containers/vector.h" @@ -12,7 +12,7 @@ #include "rxe/scene/components.h" #include "rxe/scene/hierarchy.h" -namespace rx::edit { +namespace rx::editor { namespace { u64 RandomGuid() { @@ -444,4 +444,4 @@ base::UniquePointer MakeRemoveComponent(ecs::World &world, return base::MakeUnique(world, entity, comp); } -} // namespace rx::edit +} // namespace rx::editor diff --git a/rxe/edit/undo.h b/rxe/editor/undo.h similarity index 89% rename from rxe/edit/undo.h rename to rxe/editor/undo.h index a8bf7184..03cbc0a4 100644 --- a/rxe/edit/undo.h +++ b/rxe/editor/undo.h @@ -15,7 +15,7 @@ // other undo/redo steps is re-resolved through the world rather than dangling // (see scene::FindByGuid). The factory helpers snapshot whatever prior state // their Revert needs at construction time. -namespace rx::edit { +namespace rx::editor { class Command { public: @@ -25,7 +25,7 @@ class Command { virtual const char *label() const = 0; }; -class RX_EDIT_EXPORT UndoStack { +class RX_EDITOR_EXPORT UndoStack { public: // Applies `cmd` immediately, then records it (clearing the redo stack). // Inside a group the command is applied and buffered into the group. @@ -65,7 +65,7 @@ class RX_EDIT_EXPORT UndoStack { }; // Sets a single reflected field. Captures the current value for Revert. -RX_EDIT_EXPORT base::UniquePointer +RX_EDITOR_EXPORT base::UniquePointer MakeSetProp(ecs::World &world, ecs::Entity entity, const scene::ComponentDesc &comp, const scene::PropDesc &prop, scene::PropValue new_value); @@ -73,7 +73,7 @@ MakeSetProp(ecs::World &world, ecs::Entity entity, const scene::ComponentDesc &c // entity's Guid is stable across undo/redo; *out_entity (may be null) receives // the live handle from the initial Apply inside UndoStack::Push only; a stack // address is safe, later undo/redo never writes through it. -RX_EDIT_EXPORT base::UniquePointer MakeCreateEntity( +RX_EDITOR_EXPORT base::UniquePointer MakeCreateEntity( base::Vector>>> initial, @@ -81,25 +81,25 @@ RX_EDIT_EXPORT base::UniquePointer MakeCreateEntity( // Destroys an entity; snapshots all reflected components and their props (and // its Guid) so Revert recreates it faithfully. -RX_EDIT_EXPORT base::UniquePointer MakeDestroyEntity(ecs::World &world, +RX_EDITOR_EXPORT base::UniquePointer MakeDestroyEntity(ecs::World &world, ecs::Entity entity); // Reparents an entity, preserving its world transform. An invalid new_parent // unparents it. -RX_EDIT_EXPORT base::UniquePointer +RX_EDITOR_EXPORT base::UniquePointer MakeReparent(ecs::World &world, ecs::Entity entity, ecs::Entity new_parent); // Adds a default-constructed component (no-op if already present). Revert // removes it (only if this command added it). -RX_EDIT_EXPORT base::UniquePointer +RX_EDITOR_EXPORT base::UniquePointer MakeAddComponent(ecs::World &world, ecs::Entity entity, const scene::ComponentDesc &comp); // Removes a component; snapshots its props so Revert restores them. -RX_EDIT_EXPORT base::UniquePointer +RX_EDITOR_EXPORT base::UniquePointer MakeRemoveComponent(ecs::World &world, ecs::Entity entity, const scene::ComponentDesc &comp); -} // namespace rx::edit +} // namespace rx::editor #endif // RX_EDIT_UNDO_H_ diff --git a/plugins/terrain/CMakeLists.txt b/rxe/terrain/CMakeLists.txt similarity index 100% rename from plugins/terrain/CMakeLists.txt rename to rxe/terrain/CMakeLists.txt diff --git a/plugins/terrain/README.md b/rxe/terrain/README.md similarity index 100% rename from plugins/terrain/README.md rename to rxe/terrain/README.md diff --git a/plugins/terrain/terrain.cc b/rxe/terrain/terrain.cc similarity index 99% rename from plugins/terrain/terrain.cc rename to rxe/terrain/terrain.cc index 3b3f54e9..e4a7e8a6 100644 --- a/plugins/terrain/terrain.cc +++ b/rxe/terrain/terrain.cc @@ -4,7 +4,7 @@ #include "base/numeric_limits.h" #include "base/optional.h" #include "foundation/math/scalar.h" -#include "plugins/terrain/terrain.h" +#include "rxe/terrain/terrain.h" #include #include diff --git a/plugins/terrain/terrain.h b/rxe/terrain/terrain.h similarity index 100% rename from plugins/terrain/terrain.h rename to rxe/terrain/terrain.h diff --git a/plugins/terrain/terrain_io.cc b/rxe/terrain/terrain_io.cc similarity index 99% rename from plugins/terrain/terrain_io.cc rename to rxe/terrain/terrain_io.cc index c7a9edf6..c639cc2a 100644 --- a/plugins/terrain/terrain_io.cc +++ b/rxe/terrain/terrain_io.cc @@ -4,7 +4,7 @@ #include "base/strings/string_ref.h" #include "base/strings/xstring.h" #include "foundation/math/scalar.h" -#include "plugins/terrain/terrain.h" +#include "rxe/terrain/terrain.h" #include diff --git a/plugins/terrain/terrain_test.cc b/rxe/terrain/terrain_test.cc similarity index 99% rename from plugins/terrain/terrain_test.cc rename to rxe/terrain/terrain_test.cc index d34725e4..2229a985 100644 --- a/plugins/terrain/terrain_test.cc +++ b/rxe/terrain/terrain_test.cc @@ -6,7 +6,7 @@ #include "foundation/files/file_system.h" #include "foundation/math/scalar.h" #include "foundation/strings/format.h" -#include "plugins/terrain/terrain.h" +#include "rxe/terrain/terrain.h" #include #include diff --git a/rxe/world/CMakeLists.txt b/rxe/world/CMakeLists.txt index 97bcaf76..233ebc65 100644 --- a/rxe/world/CMakeLists.txt +++ b/rxe/world/CMakeLists.txt @@ -11,7 +11,7 @@ rx_add_module(world world_overlay.cc world_stream.cc ) -target_link_libraries(rx_world PUBLIC rx::foundation rx::ecs rx::asset rx::scene rx::edit) +target_link_libraries(rx_world PUBLIC rx::foundation rx::ecs rx::asset rx::scene) if(RX_BUILD_TESTS) add_executable(world_format_test world_format_test.cc) @@ -23,7 +23,7 @@ if(RX_BUILD_TESTS) add_test(NAME world_map_test COMMAND world_map_test) add_executable(world_stream_test world_stream_test.cc) - target_link_libraries(world_stream_test PRIVATE rx::world rx::edit rx::asset rx::scene rx::ecs rx::foundation) + target_link_libraries(world_stream_test PRIVATE rx::world rx::asset rx::scene rx::ecs rx::foundation) add_test(NAME world_stream_test COMMAND world_stream_test) add_executable(world_overlay_test world_overlay_test.cc) @@ -42,7 +42,7 @@ if(RX_BUILD_TESTS) # The cook's per-entity verdict, which the editor shows for the selection. # A label that lies about what an object will become is worse than no label. add_executable(world_classify_test world_classify_test.cc) - target_link_libraries(world_classify_test PRIVATE rx::world rx::edit rx::ecs rx::foundation) + target_link_libraries(world_classify_test PRIVATE rx::world rx::ecs rx::foundation) add_test(NAME world_classify_test COMMAND world_classify_test) endif() diff --git a/tools/checkincludes/checkincludes.py b/tools/checkincludes/checkincludes.py index b2861469..9bc8641a 100644 --- a/tools/checkincludes/checkincludes.py +++ b/tools/checkincludes/checkincludes.py @@ -23,9 +23,10 @@ # Modules that work on their own handles and must not know the entity world. ENTITY_FREE = {"foundation", "events", "window", "gpu", "imgui_renderer", "ui", "asset", "audio", "net", "http", "rpc", "physics", "anim", "render", "render2d"} -ENTITY_WORLD = {"ecs", "scene", "script", "world", "edit", "devtools", "app"} -# Headers only the editor and tools may use; a shipping game never links them. -EDITOR_ONLY = {"rxe/edit/selection.h", "rxe/edit/undo.h", "rxe/world/world_bake.h"} +ENTITY_WORLD = {"ecs", "scene", "script", "world", "editor", "devtools", "app"} +# Code only the editor and tools may use; a shipping game never links it. +EDITOR_ONLY_DIRS = ("rxe/editor/",) +EDITOR_ONLY = {"rxe/world/world_bake.h"} HEADER_EXTS = (".h", ".hpp", ".inl", ".def") SOURCE_EXTS = (".cc", ".cpp", ".c") + HEADER_EXTS CODE_DIRS = ("foundation", "rxe", "plugins", "apps", "tools") @@ -186,9 +187,11 @@ def module_rules_of(target): for mod in sorted(mods): if mod in ENTITY_FREE and dep_mods & ENTITY_WORLD: found.append(("entity-free", "%s may not know the entity world" % mod)) - if "app" in dep_mods: - found.append(("host", "only apps may depend on the host")) - if rel(dep) in EDITOR_ONLY: + # The editor is the one engine module that is itself an application + # (games extend it), so it may sit on the host like an app does. + if "app" in dep_mods and mod != "editor": + found.append(("host", "only apps and the editor may depend on the host")) + if mod != "editor" and (rel(dep) in EDITOR_ONLY or rel(dep).startswith(EDITOR_ONLY_DIRS)): found.append(("editor-only", "a library may not use editor-only code")) if mod not in plugins and dep_mods & plugins: found.append(("plugin", "engine module %s may not depend on a plugin" % mod)) diff --git a/tools/rewrite_includes/renames.txt b/tools/rewrite_includes/renames.txt index 8e2a558d..f8434094 100644 --- a/tools/rewrite_includes/renames.txt +++ b/tools/rewrite_includes/renames.txt @@ -398,3 +398,8 @@ symbol rx::kMaxAxes rx::ui::kMaxAxes symbol rx::ComputeSkyLighting rx::app::ComputeSkyLighting symbol rx::SkyLighting rx::app::SkyLighting symbol rx::WorldClock rx::app::WorldClock + +# Phase 6c: the editor becomes rx::editor (rxe/editor), terrain joins the engine +prefix rxe/edit/ rxe/editor/ +prefix plugins/terrain/ rxe/terrain/ +symbol edit:: editor::