#pragma once
#include "backend/rhi.h"
#include "core/math_rtm.h"
#include "imgui.h"
#include "passes/fg.h"
#include "scene/camera.h"
#include "scene/light.h"
struct Scene;
struct SceneGraph;
struct RenderData;
struct DebugDraw;
struct Pipelines;
struct PassInspectorEntry;
struct PassContext;
struct QuickSubmit;
struct Arena;
struct Platform;
class AssetManager;
class PassTimings;
namespace rhi {
struct ShaderCompiler;
struct Swapchain;
} // namespace rhi
namespace editor {
constexpr ImGuiWindowFlags PANEL_FLAGS = ImGuiWindowFlags_NoCollapse;
enum GizmoTool : int {
GIZMO_TOOL_MOVE = 0,
GIZMO_TOOL_ROTATE = 1,
GIZMO_TOOL_SCALE = 2,
};
struct TextureViewerDesc {
rhi::Image *image = nullptr;
rhi::Sampler *sampler = nullptr;
const char *name = nullptr;
const char *format_name = nullptr;
};
bool draw_texture_inspector(rhi::Device &device, QuickSubmit &qs, const char *id, const TextureViewerDesc &desc);
void shutdown_texture_inspectors(rhi::Device &device);
// single-texel GPU readback (staging copy + timeline sync wait) into `out`.
// image TransferSrc usage and sample_count 1.
bool readback_texel_raw(
rhi::Device &device,
QuickSubmit &qs,
rhi::ImageView &view,
u32 mip,
u32 layer,
i64 tx,
i64 ty,
void *out,
usize out_size
);
void init_log_viewer();
void apply_style(f32 scale, ImGuiStyle &style);
// just a throttle to apply the euler -> quat only once per frame
// afaik translate/scale wont need something like this, because they're 1:1
// whereas rot for euler -> quat is many:1
struct EulerEdit {
int id = -1;
vec3 euler = vec3(0.0f);
quat sync;
};
struct Editor {
bool dock_layout_built = false;
ImFont *font_ui = nullptr;
ImFont *font_mono = nullptr;
rhi::Sampler viewport_sampler = {};
rhi::RenderPipeline *imgui_pipeline = nullptr;
u32 viewport_width = 0;
u32 viewport_height = 0;
bool viewport_resized = false;
rhi::Device *device = nullptr;
AssetManager *assets = nullptr;
QuickSubmit *qs = nullptr; // retained for one-off GPU work (readbacks); set in init.
bool visible = false;
bool enabled = true;
bool show_viewport = true;
bool show_hierarchy = true;
bool show_inspector = true;
bool show_texture_viewer = true;
bool show_timings = true;
bool show_log = true;
Platform *platform = nullptr;
// DdgiConfig ddgi_config;
u32 ddgi_frame_counter = 0;
int selected_node = -1;
// debug draw
bool show_debug_lines = true;
bool force_xray = false;
bool show_cat_default = true;
bool show_cat_grid = false;
bool show_cat_proxy = true;
bool show_cat_selection = true;
bool show_cat_light = false;
bool show_cat_ddgi = false;
bool show_cat_gizmo = true;
// shader reload
bool reload_requested_ = false;
GizmoTool gizmo_tool = GIZMO_TOOL_MOVE; // active tool (Blender-like)
bool gizmo_world = true; // true = world orientation, false = local
bool gizmo_snap = false;
f32 gizmo_snap_step = 0.1f; // move, world units
f32 gizmo_snap_angle = 15.0f; // rotate, degrees
f32 gizmo_snap_scale = 0.1f; // scale, factor step
// drag runtime (owned by update_*_gizmo; handles only)
bool gizmo_dragging = false;
int gizmo_grab_node = -1; // node the active drag belongs to
u8 gizmo_drag_axis = 0; // handle id gizmo axis id
int gizmo_hover_axis = -1; // screen-space handle hover (-1 = none)
vec3 gizmo_grab_point = vec3(0.0f); // world-space ref point at grab
vec3 gizmo_base_local = vec3(0.0f); // node local translation at grab
vec3 gizmo_base_world = vec3(0.0f); // node world origin at grab
vec3 gizmo_plane_n = vec3(0.0f); // drag plane normal captured at grab
// extended drag state for rotate/scale
mat4 gizmo_base_world_mat = identity(); // node world matrix at grab
mat4 gizmo_base_local_mat = identity(); // node local matrix at grab
vec3 gizmo_base_scale = vec3(1.0f); // node local scale at grab
f32 gizmo_grab_angle = 0.0f; // rotate: angle of grab point around axis
f32 gizmo_grab_dist = 0.0f; // scale: radial/axial distance at grab
vec3 gizmo_drag_u = vec3(0.0f); // rotate: basis u, perpendicular drag axis
vec3 gizmo_drag_v = vec3(0.0f); // rotate: basis v, perpendicular drag axis
int gizmo_tool_grab = -1; // tool active at grab (cancels cross-tool drags)
bool gizmo_world_grab = true; // orientation at grab (rebase on toggle)
ImVec2 gizmo_view_min = ImVec2(0, 0);
ImVec2 gizmo_view_size = ImVec2(0, 0);
// inspector rotation edit-state (see EulerEdit above)
EulerEdit node_rot; // id = node index
EulerEdit inst_rot; // id = instance slot (base + k), single-active-instance cache
};
inline bool reload_requested(Editor &e) {
if (e.reload_requested_) {
e.reload_requested_ = false;
return true;
}
return false;
}
inline void request_reload(Editor &e) {
e.reload_requested_ = true;
}
void init(
Editor &e,
rhi::Device &device,
Platform &platform,
QuickSubmit &qs,
Arena &staging,
FrameGraph &fg,
AssetManager &assets
);
void shutdown(Editor &e, rhi::Device &device);
void begin_frame(Editor &e, RenderData &rd);
void end_frame(Editor &e, Scene &scene, RenderData &rd, const PassInspectorEntry *passes, u32 pass_count);
void draw_viewport_central(Editor &e, RenderData &rd);
void draw_log_window(ImFont *mono_font);
void draw_timings_window(
Scene &scene, RenderData &rd, const PassInspectorEntry *passes, u32 pass_count, Editor &e, ImFont *mono_font
);
void draw_texture_viewer_window(rhi::Device &device, Editor &editor, RenderData &rd);
void draw_scene_graph_window(Scene &scene, const AssetManager &mgr, int &selected_node);
void draw_inspector_window(Scene &scene, const AssetManager &mgr, ImFont *mono_font, Editor &e);
void update_gizmo(Editor &e, Scene &scene, DebugDraw &draw);
void handle_frame_begin(
Editor &e,
RenderData &rd,
rhi::Device &device,
rhi::Swapchain &swapchain,
FrameGraph &fg,
ImageHandle swapchain_target,
rhi::Extent2D &render_size,
Scene &scene,
Pipelines &pipelines,
PassTimings &timings,
u32 frame_slot
);
void eval_render_size(u32 viewport_w, u32 viewport_h, rhi::Swapchain &swapchain, rhi::Extent2D &extent);
struct PresentTargets {
ImageHandle display;
ImageHandle id_blit;
ImageHandle irradiance;
ImageHandle distance;
ImageHandle cascade[Light::CASCADE_COUNT];
ImageHandle swapchain;
};
void record_present(
Editor &e,
Pipelines &pipelines,
rhi::ShaderCompiler &sc,
FrameGraph &fg,
rhi::Swapchain &swapchain,
const PresentTargets &targets,
PassTimings &timings
);
void apply_debug_settings(const Editor &e, DebugDraw &draw);
void debug_draw_selection(DebugDraw &draw, const Scene &scene, const RenderData &rd, int selected_node);
} // namespace editor