Files
sophia/editor/panels/viewport_panel.hpp
T
2026-09-30 18:53:16 -07:00

62 lines
1.8 KiB
C++

#pragma once
#include <sophia/entity.hpp>
#include <sophia/frame_info.hpp>
#include <sophia/handles.hpp>
#include <sophia/math.hpp>
#include <sophia/scene.hpp>
#include <sophia/ui/panel.hpp>
#include <sophia/ui/ui.hpp>
/**
* Shows the scene through its active camera. Click a sprite to select it,
* drag it to move it (in Move mode).
*
* Picking and moving are 2D: they assume an orthographic camera rotated only
* around Z, and work in the z = 0 plane.
*/
class ViewportPanel : public sophia::Panel {
public:
ViewportPanel(sophia::UI& ui, sophia::RenderTargetHandle target,
sophia::Scene& scene, sophia::Entity& selected)
: Panel{{.name = "Viewport",
.windowFlags = ImGuiWindowFlags_NoScrollbar |
ImGuiWindowFlags_NoScrollWithMouse}},
ui{ui},
target{target},
scene{scene},
selected{selected} {}
void onUpdate(const sophia::FrameInfo& frameInfo) override;
private:
// Where the scene image is on screen this frame, and the camera looking
// through it.
struct ViewportTransform {
ImVec2 origin;
ImVec2 size;
glm::mat4 viewProjection;
glm::mat4 inverseViewProjection;
ImVec2 worldToScreen(const glm::vec3& world) const;
glm::vec2 screenToWorld(const ImVec2& screen) const;
};
void drawToolbar();
void drawGrid(ImVec2 origin, ImVec2 size);
void handleInput(const ViewportTransform& viewport);
void drawSelection(const ViewportTransform& viewport);
// The top-most sprite under `world`, or a null Entity.
sophia::Entity pick(glm::vec2 world);
sophia::UI& ui;
sophia::RenderTargetHandle target;
sophia::Scene& scene;
sophia::Entity& selected;
bool showGrid = true;
// Set while a drag that started on the selected entity is moving it.
bool dragging = false;
};