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
+30
View File
@@ -0,0 +1,30 @@
#pragma once
#include <array>
#include <sophia/math.hpp>
namespace sophia {
/** @brief Axis-Aligned Bounding Box
*
* An axis-aligned box, from its smallest corner to its largest.
*/
struct AABB {
vec3 min{0.f, 0.f, 0.f};
vec3 max{0.f, 0.f, 0.f};
vec3 getCenter() const { return (min + max) * 0.5f; }
vec3 getSize() const { return max - min; }
// The 8 corners. Bit 0 of the index picks x from max, bit 1 y, bit 2 z.
std::array<vec3, 8> getCorners() const {
std::array<vec3, 8> corners;
for (int i = 0; i < 8; i++) {
corners[i] = {(i & 1) ? max.x : min.x, (i & 2) ? max.y : min.y,
(i & 4) ? max.z : min.z};
}
return corners;
}
};
} // namespace sophia
@@ -1,5 +1,6 @@
#pragma once
#include <sophia/aabb.hpp>
#include <sophia/handles.hpp>
#include <sophia/math.hpp>
#include <sophia/mesh_data.hpp>
@@ -28,6 +29,10 @@ class ResourceRegistryRef {
glm::vec2 getExtent(RenderTargetHandle handle) const;
glm::vec2 getExtent(TextureHandle handle) const;
// In the mesh's own space.
AABB getBounds(MeshHandle handle) const;
bool isAlive(MeshHandle handle) const;
bool isAlive(RenderTargetHandle handle) const;
bool isAlive(TextureHandle handle) const;
+8
View File
@@ -25,12 +25,20 @@ class Scene {
Entity getActiveCamera();
void setActiveCamera(Entity camera);
bool isVisible() const { return this->visible; }
void setVisible(bool visible) { this->visible = visible; }
bool isActive() const { return this->active; }
void setActive(bool active) { this->active = active; }
private:
friend class Entity;
friend class SceneRenderer; // !TEMP remove this
entt::registry registry;
entt::entity activeCamera = entt::null;
bool visible = true;
bool active = true;
};
} // namespace sophia
+3 -1
View File
@@ -19,7 +19,9 @@ struct SceneView {
SceneHandle scene = INVALID_HANDLE;
RenderTargetHandle target =
INVALID_HANDLE; // null implies render to swapchain
Entity camera; // null implies use scene's active camera
// Null implies the scene's active camera. May belong to another scene,
// e.g. an editor camera that isn't part of the scene being shown.
Entity camera;
// TODO(#76): not used yet; every view renders to its whole target.
vec4 viewport{0.0f, 0.0f, 1.0f, 1.0f};
+2
View File
@@ -48,6 +48,7 @@ class Panel {
bool isLocked() const { return config.locked; }
bool isVisible() const { return this->visible; }
bool isShown() const { return this->visible && this->shown; }
void setVisible(bool visible) { this->visible = visible; }
void toggleVisible() { this->visible = !this->visible; }
@@ -55,6 +56,7 @@ class Panel {
virtual void onUpdate(const FrameInfo& frameInfo) = 0;
bool visible = true;
bool shown = false;
private:
Config config;
+21
View File
@@ -5,6 +5,7 @@
* using namespace sophia;
* log::fatal("fatal message")
* log::info("Infomation message")
* log::print("no prefix, just the message")
*
* TODO Impl some form of log error handling
*/
@@ -122,4 +123,24 @@ void trace(Args... args) {
log(LEVEL::TRACE, args...);
}
// Like the functions above, but with no "[LEVEL]" prefix: just the arguments,
// separated by spaces, then a newline. With none, an empty line.
inline void print() {
#ifndef NDEBUG
std::cout << std::endl;
#endif // !NDEBUG
}
template <typename First, typename... Rest>
void print(First first, Rest... rest) {
#ifndef NDEBUG
std::cout << first;
((std::cout << ' ' << rest), ...);
std::cout << std::endl;
#else
(void)first;
(void)std::initializer_list<int>{((void)rest, 0)...};
#endif // !NDEBUG
}
} // namespace sophia::log
+1
View File
@@ -173,6 +173,7 @@ class Application::Impl {
const SceneView& view = sceneViewRegistry.peek(handle);
bool toSwapchain = !view.target.isValid();
if (!sceneRegistry.isAlive(view.scene) ||
!sceneRegistry.get(view.scene).isVisible() ||
(!toSwapchain && !renderTargetPool.isAlive(view.target))) {
continue;
}
+9
View File
@@ -20,6 +20,15 @@ Mesh::getAttributeDescriptions() {
}
Mesh::Mesh(Device& device, const MeshData& data) : device{device} {
if (!data.vertices.empty()) {
this->bounds = {data.vertices.front().position,
data.vertices.front().position};
for (const MeshVertex& vertex : data.vertices) {
this->bounds.min = glm::min(this->bounds.min, vertex.position);
this->bounds.max = glm::max(this->bounds.max, vertex.position);
}
}
createVertexBuffers(data.vertices);
createIndexBuffers(data.indices);
}
+6
View File
@@ -1,6 +1,7 @@
#pragma once
#include <memory>
#include <sophia/aabb.hpp>
#include <sophia/handles.hpp>
#include <sophia/math.hpp>
#include <sophia/mesh_data.hpp>
@@ -26,6 +27,9 @@ class Mesh {
Mesh(const Mesh&) = delete;
Mesh& operator=(const Mesh&) = delete;
// Bounds of the vertices, in the mesh's own space.
const AABB& getBounds() const { return this->bounds; }
void bind(vk::CommandBuffer commandBuffer) const;
void draw(vk::CommandBuffer commandBuffer, u32 instanceCount = 1,
u32 firstInstance = 0) const;
@@ -36,6 +40,8 @@ class Mesh {
Device& device;
AABB bounds;
std::unique_ptr<Buffer> vertexBuffer;
u32 vertexCount;
@@ -86,6 +86,14 @@ glm::vec2 ResourceRegistryRef::getExtent(RenderTargetHandle handle) const {
return {static_cast<float>(extent.width), static_cast<float>(extent.height)};
}
AABB ResourceRegistryRef::getBounds(MeshHandle handle) const {
return registry->meshPool.get(handle).getBounds();
}
bool ResourceRegistryRef::isAlive(MeshHandle handle) const {
return registry->meshPool.isAlive(handle);
}
bool ResourceRegistryRef::isAlive(RenderTargetHandle handle) const {
return registry->renderTargetPool.isAlive(handle);
}
+3 -2
View File
@@ -47,8 +47,9 @@ void Panel::draw(const FrameInfo& frameInfo) {
}
bool open = true;
ImGui::Begin(config.name.c_str(), config.hasCloseButton() ? &open : nullptr,
config.getWindowFlags());
this->shown = ImGui::Begin(config.name.c_str(),
config.hasCloseButton() ? &open : nullptr,
config.getWindowFlags());
onUpdate(frameInfo);
ImGui::End();