diff --git a/engine/include/sophia/scene.hpp b/engine/include/sophia/scene.hpp index 2e4af2c..5571a53 100644 --- a/engine/include/sophia/scene.hpp +++ b/engine/include/sophia/scene.hpp @@ -13,18 +13,17 @@ class Scene { Scene(); ~Scene(); - // Every entity gets a TagComponent (named `name`) and a TransformComponent. Entity createEntity(const std::string& name = {}); void destroyEntity(Entity entity); + Entity createCamera(const std::string& name = "Camera"); + /** Calls `fn(Entity)` for every live entity. Defined in entity.hpp. */ template void forEachEntity(Fn&& fn); - // The camera a render request uses when it doesn't name one. Null until - // set. - entt::entity getActiveCamera() const { return activeCamera; } - void setActiveCamera(entt::entity camera) { activeCamera = camera; } + Entity getActiveCamera(); + void setActiveCamera(Entity camera); private: friend class Entity; diff --git a/engine/include/sophia/scene_view.hpp b/engine/include/sophia/scene_view.hpp index 7d83da9..af5860c 100644 --- a/engine/include/sophia/scene_view.hpp +++ b/engine/include/sophia/scene_view.hpp @@ -17,8 +17,9 @@ enum class ClearFlags : u8 { struct SceneView { SceneHandle scene = INVALID_HANDLE; - RenderTargetHandle target = INVALID_HANDLE; - Entity camera; + RenderTargetHandle target = + INVALID_HANDLE; // null implies render to swapchain + Entity camera; // null implies use scene's active camera vec4 viewport{0.0f, 0.0f, 1.0f, 1.0f}; diff --git a/engine/src/rendering/imgui_renderer.cpp b/engine/src/rendering/imgui_renderer.cpp index d458938..e59aa4a 100644 --- a/engine/src/rendering/imgui_renderer.cpp +++ b/engine/src/rendering/imgui_renderer.cpp @@ -91,12 +91,13 @@ void ImGuiRenderer::beginFrame() { } ImTextureID ImGuiRenderer::getTextureId(RenderTargetHandle handle) { - vk::ImageView view = - resources.renderTargetPool.get(handle).getImage().getView(); + const RenderTarget& target = resources.renderTargetPool.get(handle); + vk::ImageView view = target.getImage().getView(); auto it = textures.find(handle.index); if (it != textures.end()) { - if (it->second.generation == handle.generation && it->second.view == view) { + if (it->second.generation == handle.generation && + it->second.version == target.getVersion()) { return (ImTextureID)it->second.descriptorSet; } ImGui_ImplVulkan_RemoveTexture(it->second.descriptorSet); @@ -107,7 +108,8 @@ ImTextureID ImGuiRenderer::getTextureId(RenderTargetHandle handle) { // left in once the scene pass has finished. VkDescriptorSet descriptorSet = ImGui_ImplVulkan_AddTexture( static_cast(view), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - textures[handle.index] = {handle.generation, view, descriptorSet}; + textures[handle.index] = {handle.generation, target.getVersion(), + descriptorSet}; return (ImTextureID)descriptorSet; } @@ -120,7 +122,7 @@ void ImGuiRenderer::releaseStaleTextures() { bool stale = !renderTargetPool.isAlive(handle) || - renderTargetPool.get(handle).getImage().getView() != it->second.view; + renderTargetPool.get(handle).getVersion() != it->second.version; if (stale) { ImGui_ImplVulkan_RemoveTexture(it->second.descriptorSet); it = textures.erase(it); diff --git a/engine/src/rendering/imgui_renderer.hpp b/engine/src/rendering/imgui_renderer.hpp index 5ee558a..31c2304 100644 --- a/engine/src/rendering/imgui_renderer.hpp +++ b/engine/src/rendering/imgui_renderer.hpp @@ -37,7 +37,7 @@ class ImGuiRenderer { struct Texture { u32 generation; - vk::ImageView view; + u32 version; VkDescriptorSet descriptorSet; }; diff --git a/engine/src/resources/render_target.cpp b/engine/src/resources/render_target.cpp index b4e81e1..23cccb7 100644 --- a/engine/src/resources/render_target.cpp +++ b/engine/src/resources/render_target.cpp @@ -39,6 +39,7 @@ void RenderTarget::applyPendingResize() { } void RenderTarget::create(u32 width, u32 height) { + this->version++; this->image = Image::Builder(this->device) .setExtent(width, height) .setFormat(this->format) diff --git a/engine/src/resources/render_target.hpp b/engine/src/resources/render_target.hpp index fd4f4f8..c545c52 100644 --- a/engine/src/resources/render_target.hpp +++ b/engine/src/resources/render_target.hpp @@ -27,6 +27,7 @@ class RenderTarget { Image& getImage() const { return *this->image; } vk::Extent2D getExtent() const; + u32 getVersion() const { return this->version; } void requestResize(u32 width, u32 height); @@ -46,6 +47,7 @@ class RenderTarget { std::unique_ptr image; std::optional pendingExtent; + u32 version = 0; }; } // namespace sophia diff --git a/engine/src/scene/scene.cpp b/engine/src/scene/scene.cpp index 1dfb9db..efef623 100644 --- a/engine/src/scene/scene.cpp +++ b/engine/src/scene/scene.cpp @@ -16,6 +16,24 @@ Entity Scene::createEntity(const std::string& name) { return entity; } +Entity Scene::createCamera(const std::string& name) { + Entity camera = createEntity(name); + camera.addComponent(); + if (this->activeCamera == entt::null) { + this->activeCamera = camera; + } + return camera; +} + +Entity Scene::getActiveCamera() { + if (this->activeCamera == entt::null) { + return {}; + } + return {this->activeCamera, this}; +} + +void Scene::setActiveCamera(Entity camera) { this->activeCamera = camera; } + void Scene::destroyEntity(Entity entity) { if (this->activeCamera == entity) { this->activeCamera = entt::null; diff --git a/examples/boids_2d/main.cpp b/examples/boids_2d/main.cpp index a3d9536..9d34a50 100644 --- a/examples/boids_2d/main.cpp +++ b/examples/boids_2d/main.cpp @@ -87,6 +87,8 @@ class Boids2D : public sophia::Application { [this](sophia::KeyReleasedEvent& e) { setScrollKeyHeld(e.getKeyCode(), false); }); + + debugUI().show(); } void onCreate() override { @@ -110,8 +112,7 @@ class Boids2D : public sophia::Application { sceneHandle = scenes().create(); sophia::Scene& scene = scenes().get(sceneHandle); - cameraEntity = scene.createEntity("Camera"); - cameraEntity.addComponent(); + cameraEntity = scene.createCamera(); std::uniform_real_distribution tint{0.0f, 1.0f}; for (Boid& boid : boids) { @@ -127,7 +128,6 @@ class Boids2D : public sophia::Application { target = resources().create(); views().create({.scene = sceneHandle, .target = target, - .camera = cameraEntity, .clearColor = {0.01f, 0.01f, 0.02f, 1.0f}}); panels().emplace(ui(), target); diff --git a/examples/image_viewer/main.cpp b/examples/image_viewer/main.cpp index 2eae2df..7559565 100644 --- a/examples/image_viewer/main.cpp +++ b/examples/image_viewer/main.cpp @@ -40,8 +40,7 @@ class ImageViewer : public sophia::Application { sophia::SceneHandle sceneHandle = scenes().create(); sophia::Scene& scene = scenes().get(sceneHandle); - camera = scene.createEntity("Camera"); - camera.addComponent(); + camera = scene.createCamera(); sophia::TextureHandle texture = resources().load(path); imageSize = resources().getExtent(texture); @@ -54,7 +53,6 @@ class ImageViewer : public sophia::Application { target = resources().create(); views().create({.scene = sceneHandle, .target = target, - .camera = camera, .clearColor = {0.1f, 0.1f, 0.15f, 1.f}}); panels().emplace(ui(), target);