Skip to content

Editor Module

The Editor module provides an in-engine editor built on ImGui, offering tools for scene editing, entity manipulation, and content creation. It integrates seamlessly with the runtime to provide a unified development environment.

Purpose

The Editor module provides:

  • In-engine editor interface
  • Scene hierarchy management
  • Entity property inspection and editing
  • Viewport for scene visualization
  • Content browser for asset management
  • Console for logging and debugging
  • Editor layers and overlay system

Key Components

Editor

The main editor singleton that manages the editor initialization and runtime:

Key Methods:

  • init() - Initializes editor systems (EventDispatcher, Time, SystemManager, Engine, Window)
  • start() - Starts the editor
  • run() - Main editor loop
  • end() - Cleans up editor resources
  • get() - Returns singleton instance
  • get_current_layout() - Returns current layout configuration

Editor Layers

The editor is composed of multiple layers:

  • ViewportLayer - Scene rendering in ImGui window with framebuffer
  • SceneHierarchyLayer - Entity tree view
  • PropertiesLayer - Component inspection and editing
  • ContentBrowserLayer - Asset browsing and management
  • ConsoleLayer - Log messages and debugging
  • DockspaceOverlay - Main dockspace, menu bar, and theme

EditorCamera

Camera controller for viewport navigation (extends Object):

cpp
class EditorCamera : public Object {
public:
    EditorCamera(ENTITY_INIT_PARAMS, glm::vec3 position = glm::vec3(0.0f));

    void start();
    void pre_update();
    void update() override;
    void post_update();
    void on_enable() override {};
    void on_disable() override {};
};

Note: Camera movement controls are currently commented out in the implementation.

LayerManager

Manages editor layers and overlays:

cpp
struct LayerContext {
    EntityID selected_entity_id = -1;
    bool has_selected_entity();
};

class LayerManager {
public:
    static void init();
    static LayerManager* get();

    template<class T> void add_layer();
    template<class T> void add_overlay();

    LayerContext* get_layer_context();

    void for_each(std::function<void(Layer*)> fn);
    void for_each(std::function<void(Overlay*)> fn);
};

The LayerContext tracks the currently selected entity across all panels.

Architecture

Layer System

The editor uses a layer system for UI organization:

Editor (singleton)
    ├── LayerSystem (ECS system)
    │   └── LayerManager
    │       ├── DockspaceOverlay (main dockspace + menu)
    │       ├── ViewportLayer
    │       ├── SceneHierarchyLayer
    │       ├── PropertiesLayer
    │       ├── ContentBrowserLayer
    │       └── ConsoleLayer
    └── WebsocketServer (optional, for remote editing)

Note: Some layers are currently commented out in the LayerSystem initialization.

ImGui Integration

The editor is built on ImGui for immediate-mode UI. The DockspaceOverlay initializes ImGui and configures the main dockspace:

cpp
class DockspaceOverlay : public Overlay {
public:
    void start() override;        // Initializes ImGui context with OpenGL3 + GLFW
    void pre_update() override;   // Begins ImGui frame
    void update() override;       // Renders menu bar and dockspace
    void post_update() override;  // Ends ImGui frame
};

The overlay loads fonts (OpenSans Regular/Bold 18pt) and applies a custom dark theme.

LayerContext

The editor maintains shared state across layers:

cpp
struct LayerContext {
    EntityID selected_entity_id = -1;
    bool has_selected_entity();
};

This context is shared by all layers via LayerManager::get_layer_context() to track the currently selected entity.

Key Features

Scene Hierarchy

View and manipulate the entity tree. The SceneHierarchyLayer displays all entities in a tree view:

cpp
class SceneHierarchyLayer : public Layer {
public:
    SceneHierarchyLayer() : Layer("SceneHierarchy");

    void start() override;
    void update() override;
};

Features:

  • Tree view of all entities in the active scene
  • Left-click to select an entity (updates LayerContext)
  • Right-click context menu for Delete and Add Component
  • Window context menu for entity templates (Empty, Cube, Sphere, Capsule, Quad, Plane)

Properties Layer

Inspect and edit entity components. The PropertiesLayer displays component data for the selected entity:

cpp
class PropertiesLayer : public Layer {
public:
    PropertiesLayer() : Layer("Properties");

    void start() override;
    void update() override;
};

Supported Components:

  • TransformComponent
  • MaterialComponent
  • MeshComponent
  • CameraComponent
  • RigidBodyComponent
  • LightComponent

Features:

  • Loads component icons (transform, camera, rigidbody, light, mesh, skybox, settings)
  • Per-component header with settings button
  • Components can be marked as removable
  • Reads selected entity from LayerContext

Viewport Layer

Renders the engine framebuffer in an ImGui window:

cpp
class ViewportLayer : public Layer {
public:
    ViewportLayer() : Layer("Viewport");

    void start() override;
    void update() override;
};

Features:

  • Displays engine framebuffer as ImGui image texture
  • Dynamically resizes framebuffer based on panel size
  • Tracks viewport bounds, focused state, and hovered state
  • Provides viewport dimensions for rendering

Note: Gizmo system and entity manipulation tools are not currently implemented in the viewport.

Content Browser Layer

Browse and manage project assets:

cpp
class ContentBrowserLayer : public Layer {
public:
    ContentBrowserLayer();

    void start() override;
    void update() override;
};

Features:

  • Two-panel layout: directory tree (aside) + file grid (main)
  • Base directory: src/assets (relative to parent of working directory)
  • Drag-drop support with "CONTENT_BROWSER_ITEM" payload
  • Directory and file icons
  • Navigation through folder hierarchy

Console Layer

Display log messages and debugging information:

cpp
class ConsoleLayer : public Layer {
public:
    ConsoleLayer() : Layer("Console");

    void start() override;
    void update() override;
};

Features:

  • Loads icon textures for warn, info, and error levels
  • Menu bar with log level icon buttons for filtering
  • Search bar (logic not yet implemented)
  • Clear button (logic not yet implemented)
  • Displays log messages with color-coded severity

WebSocket Server (Optional)

For remote editor connections:

cpp
class WebsocketServer {
public:
    static void init();
    static WebsocketServer* get();

    void start();
    void update();

    void publish(std::string_view topic, std::string_view message,
                 uWS::OpCode opCode, bool compress = true);
    void publish(const char* topic, const char* message);

    std::string build_message(const char* topic, const char* message);
};

Features:

  • SSL WebSocket server on port 9001
  • Topics: "framebuffer", "scene", "logs"
  • Handles keyboard and mouse input from remote clients
  • Enabled via ASTRA_EDITOR_USOCKET compilation flag
  • Requires certificate files: misc/key.pem, misc/cert.pem, passphrase "1234"

Note: Play/pause mode state machine is not currently implemented.

Integration with Other Modules

With Engine Module

The editor initializes the engine and integrates with the ECS through the LayerSystem:

cpp
class LayerSystem : public System<LayerSystem> {
public:
    LayerSystem();  // Initializes LayerManager

    void start() override;
    void fixed_update(double fixed_dt) override;
    void pre_update(double dt) override;
    void update(double dt) override;
};

The LayerSystem is added to the SystemManager and updates all layers during the engine loop.

With Window Module

The editor uses the Window module for input and display:

cpp
void Editor::init() {
    // Initialize Time system
    Time::init();

    // Initialize SystemManager
    SystemManager::init();

    // Initialize Engine
    Engine::init();

    // Initialize Window
    Window::create(...);
    Window::start();
}

Asset Management

The ContentBrowserLayer browses assets in src/assets directory. Asset paths are relative to the parent of the working directory.

Editor Controls

Current Status

Note: Many editor controls are currently in development:

  • Camera movement controls are commented out in EditorCamera
  • Gizmo manipulation (W/E/R shortcuts) is not implemented
  • Keyboard shortcuts (Ctrl+S, Ctrl+D, Delete, F, Ctrl+Z, Ctrl+Y) are not implemented
  • Undo/redo system is not implemented

Implemented Features

  • Left-click entity in Scene Hierarchy to select
  • Right-click entity for context menu (Delete, Add Component)
  • Right-click viewport background for entity templates menu
  • Drag files from Content Browser (payload: "CONTENT_BROWSER_ITEM")

File Locations

/src/modules/editor/
├── editor.hpp/cpp              # Main editor singleton
├── camera.hpp/cpp              # Editor camera controller
├── websocket-server.hpp/cpp    # WebSocket server for remote editing
├── events/
│   ├── logs-event.hpp          # Log streaming events
│   └── viewport-event.hpp      # Viewport framebuffer events
├── layers/
│   ├── viewport-layer.hpp/cpp
│   ├── console-layer.hpp/cpp
│   ├── content-browser-layer.hpp/cpp
│   ├── properties-layer.hpp/cpp
│   ├── scene-hierarchy-layer.hpp/cpp
│   ├── managers/
│   │   └── layer-manager.hpp/cpp
│   └── systems/
│       └── layer-system.hpp/cpp
├── layouts/
│   ├── layout.hpp              # Layout configuration struct
│   └── default-layout.hpp/cpp  # Default panel layout
├── overlays/
│   └── dockspace-overlay.hpp/cpp  # Main dockspace + menu + theme
├── serializers/
│   ├── editor-serializer.hpp   # Empty placeholder
│   └── log-serializer.hpp/cpp  # Log entry JSON serialization
└── UI/
    └── imgui-widgets.hpp       # Reusable ImGui UI components
  • Engine - Provides ECS and SystemManager for layer integration
  • Window - Handles display and input
  • Streams - Serialization for logs and scene data

Best Practices

  1. Use Entity Templates: Create entities from templates in Scene Hierarchy context menu (Empty, Cube, Sphere, Capsule, Quad, Plane)
  2. Organize Scene: Keep scene hierarchy organized with descriptive entity names
  3. Component Icons: Use the Properties panel to visually identify component types
  4. Asset Organization: Keep assets organized in the src/assets directory structure

Performance Considerations

  • Editor UI is rendered with ImGui (immediate mode)
  • Viewport renders to framebuffer for ImGui texture display
  • WebSocket mode uses hardcoded 1920x1080 resolution for framebuffer streaming
  • Content browser iterates through filesystem on each update
  • Multiple icon textures loaded for UI elements
  • Font files (OpenSans Regular/Bold 18pt) loaded at startup

Common Patterns

Adding Custom Layers

Create a custom layer by extending the Layer base class:

cpp
class MyCustomLayer : public Layer {
public:
    MyCustomLayer() : Layer("MyCustomLayer") {}

    void start() override {
        // Initialize resources, load icons, etc.
    }

    void update() override {
        ImGui::Begin("My Custom Panel");
        // Your ImGui UI code here
        ImGui::End();
    }
};

// Register in LayerSystem or LayerManager
LayerManager::get()->add_layer<MyCustomLayer>();

Using LayerContext for Selection

Access the shared selection state across layers:

cpp
void MyCustomLayer::update() {
    LayerContext* ctx = LayerManager::get()->get_layer_context();

    if (ctx->has_selected_entity()) {
        EntityID selected = ctx->selected_entity_id;
        // Work with selected entity
    }
}

Template-Based Component UI

The editor uses a template pattern for drawing components:

cpp
// Defined in UI/imgui-widgets.hpp
template<typename T>
void draw_component(EntityID entity, std::function<void(T&)> ui_function);

This allows custom UI for each component type while maintaining consistent headers and controls.