Skip to content

Embedded UI β€” Dear ImGuiΒ #42

@LyeZinho

Description

@LyeZinho

πŸ–₯️ Embedded UI β€” Dear ImGui

Fase: 6 β€” O Olimpo
Namespace: Caffeine::Editor
Status: πŸ“… Planejado
RFs: RF6.1, RF6.2, RF6.6


VisΓ£o Geral

IntegraΓ§Γ£o de Dear ImGui para a interface do Caffeine Studio IDE. ImGui Γ© uma biblioteca de UI em modo imediato (immediate mode) β€” cada frame redesenha todos os widgets. Ideal para ferramentas de desenvolvimento.

DistinΓ§Γ£o da Fase 4:

  • UI System β€” UI retida para jogos (HUD, menus, HealthBar)
  • Embedded ImGui β€” UI imediata para ferramentas de desenvolvimento (editor, profiler, console)

API Planejada

namespace Caffeine::Editor {

// ============================================================================
// @brief  IntegraΓ§Γ£o ImGui com SDL3 + RHI da Caffeine.
//
//  Inicializa ImGui com:
//  - Backend SDL3 (eventos de mouse/teclado)
//  - Backend SDL_GPU (renderizaΓ§Γ£o)
//
//  Lifecycle:
//  1. init(window, device)
//  2. Per frame: beginFrame() β†’ ImGui widgets β†’ endFrame(cmd)
//  3. shutdown()
// ============================================================================
class ImGuiIntegration {
public:
    bool init(SDL_Window* window, RHI::RenderDevice* device);
    void shutdown();

    void beginFrame();           // chama ImGui::NewFrame()
    void endFrame(RHI::CommandBuffer* cmd);  // chama ImGui::Render() + draw data

    // Passa evento SDL para ImGui (chame antes de processar input do jogo)
    bool processEvent(const SDL_Event& event);

    // Verifica se ImGui estΓ‘ capturando input (nΓ£o repassar ao jogo)
    bool wantsKeyboard() const;
    bool wantsMouse()    const;
};

// ============================================================================
// @brief  Janela de profiler β€” visualiza dados do Profiler da Fase 2.
// ============================================================================
class ProfilerWindow {
public:
    void render(const Debug::Profiler& profiler);

private:
    bool m_open = true;
    bool m_paused = false;
    // histograma de 120 frames
    std::array<f32, 120> m_frameTimes;
    u32 m_frameIdx = 0;
};

// ============================================================================
// @brief  Console window β€” exibe logs e aceita comandos.
// ============================================================================
class ConsoleWindow {
public:
    void render();
    void addLog(Debug::LogLevel level, const char* category,
                const char* message);

private:
    struct LogEntry {
        Debug::LogLevel level;
        FixedString<32>  category;
        FixedString<256> message;
    };
    std::vector<LogEntry> m_entries;
    char m_inputBuf[256] = {};
    bool m_autoScroll    = true;
    bool m_open          = true;
    Debug::LogLevel m_filterLevel = Debug::LogLevel::Trace;
};

// ============================================================================
// @brief  Stats overlay β€” frame time, FPS, memory.
// ============================================================================
class StatsOverlay {
public:
    void render(const GameLoop::FrameStats& stats,
                const AssetManager::CacheStats& cache);
};

}  // namespace Caffeine::Editor

Janelas do Editor

ProfilerWindow

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ πŸ”¬ Profiler                  [Pause] [X] β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Frame: 16.7ms  |  FPS: 60               β”‚
β”‚ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ (frame graph)  β”‚
β”‚                                          β”‚
β”‚ Scope                    avg    max      β”‚
β”‚ ECS::PhysicsSystem       2.1ms  4.3ms   β”‚
β”‚ BatchRenderer::flush     0.8ms  1.2ms   β”‚
β”‚ AnimationSystem          0.3ms  0.6ms   β”‚
β”‚ AudioSystem::update      0.1ms  0.2ms   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

ConsoleWindow

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ πŸ’¬ Console                          [X] β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Filter: [All β–Ύ]  [βœ“ Auto-scroll]        β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ [INFO] AssetManager  Loaded hero.caf    β”‚
β”‚ [WARN] Physics       Overlap detected   β”‚
β”‚ [INFO] Audio         Playing bgm.caf    β”‚
β”‚ [INFO] ECS           Created 50 entit. β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ > _                                      β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

IntegraΓ§Γ£o no Game Loop

// ── Init ──────────────────────────────────────────────────────
#if CF_EDITOR_MODE
Caffeine::Editor::ImGuiIntegration imgui;
imgui.init(window, &device);

Caffeine::Editor::ProfilerWindow profilerWindow;
Caffeine::Editor::ConsoleWindow consoleWindow;

// Hook no LogSystem para exibir no console:
Debug::LogSystem::instance().addSink([&](LogLevel lvl, const char* cat,
                                         const char* msg) {
    consoleWindow.addLog(lvl, cat, msg);
});
#endif

// ── Por frame ─────────────────────────────────────────────────
#if CF_EDITOR_MODE
imgui.beginFrame();

profilerWindow.render(Debug::Profiler::instance());
consoleWindow.render();
sceneEditor.render(world, camera);   // Fase 6.3

imgui.endFrame(cmd);
#endif

Hot-Reload Runtime (RF6.6)

FileWatcher (jΓ‘ no AssetManager::pollFileChanges())
    β”‚
    β–Ό
Arquivo modificado em disco
    β”‚
    β”œβ”€β”€ textura (.png) β†’ re-encode β†’ upload GPU β†’ todos os handles atualizados
    β”œβ”€β”€ shader (.hlsl/.glsl) β†’ recompile β†’ novo Pipeline β†’ substituΓ­do
    └── script (.lua) β†’ reload VM β†’ funΓ§Γ΅es atualizadas

CritΓ©rio de AceitaΓ§Γ£o

  • Dear ImGui integrado com SDL3 sem conflitos de input
  • ProfilerWindow mostra dados do Profiler real-time
  • ConsoleWindow filtra por nΓ­vel e categoria
  • Hot-reload: textura atualizada sem restart do jogo
  • ImGui nΓ£o interfere com input do jogo quando nΓ£o em foco

DependΓͺncias


ReferΓͺncias

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions