adding and integrating ImGuizmo

This commit is contained in:
2026-10-02 11:36:33 -07:00
parent 379589fe8c
commit 6e48b0605c
28 changed files with 1223 additions and 108 deletions
+82 -15
View File
@@ -1,49 +1,86 @@
#include <iostream>
#include <sophia/application.hpp>
#include <sophia/components.hpp>
#include <sophia/entity.hpp>
#include <sophia/primitives.hpp>
#include <vector>
#include "editor_context.hpp"
#include "panels/asset_browser_panel.hpp"
#include "panels/game_panel.hpp"
#include "panels/inspector_panel.hpp"
#include "panels/scene_hierarchy_panel.hpp"
#include "panels/scene_panel.hpp"
#include "utilities/logger.hpp"
class Editor : public sophia::Application {
public:
Editor() : Application{{.width = 750, .height = 1000, .name = "Editor"}} {}
void onCreate() override {
std::cout << "Editor created" << std::endl;
log("Editor created");
debugUI().show();
textures.emplace_back("Checker", createCheckerTexture());
cubeMesh = createShadedCube();
sophia::SceneHandle sceneHandle = scenes().create();
sophia::Scene& scene = scenes().get(sceneHandle);
createDemoScene(scene);
sophia::SceneHandle sceneHandle = context.createScene("Demo");
createDemoScene(scenes().get(sceneHandle));
context.setScene(sceneHandle);
panels().emplace<SceneHierarchyPanel>(scene, selected);
panels().emplace<InspectorPanel>(selected, textures);
panels().emplace<AssetBrowserPanel>();
// The editor's own scene, never edited or rendered. It holds the camera
// the Scene panel looks through, which a SceneView may take from any
// scene.
sophia::SceneHandle editorSceneHandle = scenes().create();
sophia::Entity editorCamera =
scenes().get(editorSceneHandle).createCamera("Editor Camera");
// Views start without a scene; their panels point them at the active
// scene each frame.
sophia::RenderTargetHandle sceneTarget =
resources().create<sophia::RenderTarget>();
sceneViews().create({.scene = sceneHandle, .target = sceneTarget});
panels().emplace<ScenePanel>(ui(), sceneTarget, scene, selected);
sophia::SceneViewHandle sceneView = sceneViews().create(
{.target = sceneTarget, .camera = editorCamera, .enabled = false});
// No camera: the Game panel shows the scene through its active one.
sophia::RenderTargetHandle gameTarget =
resources().create<sophia::RenderTarget>();
sophia::SceneViewHandle gameView =
sceneViews().create({.target = gameTarget, .enabled = false});
panels().emplace<SceneHierarchyPanel>(context, cubeMesh);
panels().emplace<InspectorPanel>(context, textures);
panels().emplace<AssetBrowserPanel>();
viewPanels.push_back(
{panels().emplace<ScenePanel>(ui(), resources(), context, sceneViews(),
sceneView, sceneTarget, editorCamera),
sceneView});
viewPanels.push_back(
{panels().emplace<GamePanel>(ui(), context, sceneViews(), gameView,
gameTarget),
gameView});
panels().setDefaultLayout(
{.left = {"Scene Hierarchy"},
.right = {"Inspector", "Frame Stats", "PanelRegistry"},
.bottom = {"Asset Browser", "Console"},
.center = {"Scene"}});
.center = {"Scene", "Game"}});
}
void onUpdate(const sophia::FrameInfo& frameInfo) override {}
void onUpdate(const sophia::FrameInfo& frameInfo) override {
// A closed panel's onUpdate() doesn't run, so it can't stop its view
// rendering itself.
for (const ViewPanel& viewPanel : viewPanels) {
if (!panels().get(viewPanel.panel).isVisible() &&
sceneViews().peek(viewPanel.view).enabled) {
sceneViews().get(viewPanel.view).enabled = false;
}
}
}
private:
// Adds to a new scene, which already has a camera.
void createDemoScene(sophia::Scene& scene) {
scene.createCamera("Main Camera");
sophia::Entity checker = scene.createEntity("Checker");
checker.getComponent<sophia::TransformComponent>().position = {-1.5f, 0.f,
0.f};
@@ -63,6 +100,27 @@ class Editor : public sophia::Application {
sophia::SpriteComponent{.color = {0.25f, 0.45f, 0.95f, 0.6f},
.size = {2.f, 2.f},
.sortOrder = 1});
sophia::Entity cube = scene.createEntity("Cube");
auto& cubeTransform = cube.getComponent<sophia::TransformComponent>();
cubeTransform.position = {0.f, 2.5f, 0.f};
cubeTransform.rotation =
glm::quat{glm::radians(glm::vec3{30.f, 45.f, 0.f})};
cube.addComponent<sophia::MeshComponent>(sophia::MeshComponent{
.handle = cubeMesh, .color = {0.4f, 0.8f, 0.5f, 1.f}});
}
// Meshes are unlit, so a plain cube is a flat silhouette. Bake a fixed
// light into its vertex colors so its faces read in 3D until there's real
// lighting; MeshComponent::color still tints it.
sophia::MeshHandle createShadedCube() {
const glm::vec3 lightDirection = glm::normalize(glm::vec3{0.4f, 1.f, 0.7f});
sophia::MeshData data = sophia::primitives::cube();
for (sophia::MeshVertex& vertex : data.vertices) {
float light = glm::dot(vertex.normal, lightDirection) * 0.5f + 0.5f;
vertex.color = glm::vec4{glm::vec3{0.35f + 0.65f * light}, 1.f};
}
return resources().create<sophia::Mesh>(data);
}
sophia::TextureHandle createCheckerTexture() {
@@ -79,8 +137,17 @@ class Editor : public sophia::Application {
return resources().create<sophia::Texture>(SIZE, SIZE, std::move(pixels));
}
sophia::Entity selected;
// A panel showing a scene view, which should only render while the panel
// is on screen.
struct ViewPanel {
sophia::PanelHandle panel;
sophia::SceneViewHandle view;
};
EditorContext context{scenes()};
std::vector<ViewPanel> viewPanels;
InspectorPanel::TextureList textures;
sophia::MeshHandle cubeMesh;
};
SOPHIA_MAIN(Editor)