Compare commits

...

3 Commits

Author SHA1 Message Date
burkkyy 341249bb96 scene_view concept 2026-09-25 20:23:12 -07:00
burkkyy 0d145f615d changes 2026-09-25 20:22:29 -07:00
burkkyy 4ebae57cf8 Moving stuff around 2026-09-25 20:21:25 -07:00
19 changed files with 274 additions and 90 deletions
+1 -1
View File
@@ -20,7 +20,7 @@ class Editor : public sophia::Application {
panels().emplace<AssetBrowserPanel>(); panels().emplace<AssetBrowserPanel>();
sophia::RenderTargetHandle sceneTarget = sophia::RenderTargetHandle sceneTarget =
resources().create<sophia::RenderTarget>(); resources().create<sophia::RenderTarget>();
setSceneTarget(sceneTarget); views().create({.scene = scenes().create(), .target = sceneTarget});
panels().emplace<ViewportPanel>(ui(), sceneTarget); panels().emplace<ViewportPanel>(ui(), sceneTarget);
panels().setDefaultLayout( panels().setDefaultLayout(
+3 -10
View File
@@ -10,6 +10,7 @@
#include <sophia/math.hpp> #include <sophia/math.hpp>
#include <sophia/resource_registry_ref.hpp> #include <sophia/resource_registry_ref.hpp>
#include <sophia/scene_registry.hpp> #include <sophia/scene_registry.hpp>
#include <sophia/scene_view_registry.hpp>
#include <sophia/types.hpp> #include <sophia/types.hpp>
#include <sophia/ui/debug_ui.hpp> #include <sophia/ui/debug_ui.hpp>
#include <sophia/ui/panel_registry.hpp> #include <sophia/ui/panel_registry.hpp>
@@ -46,6 +47,7 @@ class Application {
ResourceRegistryRef resources(); ResourceRegistryRef resources();
PanelRegistry& panels() { return this->panelRegistry; } PanelRegistry& panels() { return this->panelRegistry; }
SceneRegistry& scenes() { return this->sceneRegistry; } SceneRegistry& scenes() { return this->sceneRegistry; }
SceneViewRegistry& views() { return this->sceneViewRegistry; }
UI& ui() { return this->_ui; } UI& ui() { return this->_ui; }
DebugUI& debugUI() { return this->_debugUI; } DebugUI& debugUI() { return this->_debugUI; }
@@ -58,16 +60,6 @@ class Application {
void drawMesh(MeshHandle handle, const glm::mat4& transform); void drawMesh(MeshHandle handle, const glm::mat4& transform);
/**
* !TEMP !TODO remove this func eventually
* Chooses where the scene is rendered. An invalid handle (the default) means
* the swapchain; a target created with
* ResourceRegistryRef::create<RenderTarget>() redirects it offscreen, and the
* swapchain then only receives the UI. FrameInfo::currentFramebufferExtent
* and the camera projection follow the target's size.
*/
void setSceneTarget(RenderTargetHandle handle);
private: private:
friend class Canvas; friend class Canvas;
@@ -79,6 +71,7 @@ class Application {
PanelRegistry panelRegistry; PanelRegistry panelRegistry;
SceneRegistry sceneRegistry; SceneRegistry sceneRegistry;
SceneViewRegistry sceneViewRegistry;
UI _ui; UI _ui;
DebugUI _debugUI; DebugUI _debugUI;
+2
View File
@@ -37,10 +37,12 @@ class Mesh;
class Panel; class Panel;
class RenderTarget; class RenderTarget;
class Scene; class Scene;
struct SceneView;
using MeshHandle = Handle<Mesh>; using MeshHandle = Handle<Mesh>;
using PanelHandle = Handle<Panel>; using PanelHandle = Handle<Panel>;
using RenderTargetHandle = Handle<RenderTarget>; using RenderTargetHandle = Handle<RenderTarget>;
using SceneHandle = Handle<Scene>; using SceneHandle = Handle<Scene>;
using SceneViewHandle = Handle<SceneView>;
} // namespace sophia } // namespace sophia
+34
View File
@@ -0,0 +1,34 @@
#pragma once
#include <sophia/entity.hpp>
#include <sophia/handles.hpp>
#include <sophia/math.hpp>
#include <sophia/scene.hpp>
namespace sophia {
enum class ClearFlags : u8 {
None = 0,
Color = 1 << 0,
Depth = 1 << 1,
Stencil = 1 << 2,
All = Color | Depth | Stencil
};
struct SceneView {
SceneHandle scene = INVALID_HANDLE;
RenderTargetHandle target = INVALID_HANDLE;
Entity camera;
vec4 viewport{0.0f, 0.0f, 1.0f, 1.0f};
vec4 clearColor{0.f, 0.f, 0.f, 1.f};
ClearFlags clearFlags = ClearFlags::All;
u32 priority = 0; // Lower priority renders first
u32 layerMask = 0xFFFFFFFF;
bool enabled = true; // Disabled views are kept but not rendered
};
} // namespace sophia
@@ -0,0 +1,86 @@
#pragma once
#include <algorithm>
#include <sophia/handles.hpp>
#include <sophia/scene_view.hpp>
#include <sophia/util/pool.hpp>
#include <utility>
#include <vector>
namespace sophia {
/**
* Every live SceneView. The application renders all enabled views each frame,
* in ascending priority order, before the UI.
*/
class SceneViewRegistry {
public:
SceneViewRegistry(const SceneViewRegistry&) = delete;
SceneViewRegistry& operator=(const SceneViewRegistry&) = delete;
SceneViewRegistry() = default;
~SceneViewRegistry() = default;
SceneViewHandle create(const SceneView& view = {}) {
isRenderQueueDirty = true;
return pool.create(view);
}
const SceneView& get(SceneViewHandle handle) const {
return pool.get(handle);
}
SceneView& get(SceneViewHandle handle) {
isRenderQueueDirty = true;
return pool.get(handle);
}
void release(SceneViewHandle handle) {
isRenderQueueDirty = true;
pool.release(handle);
}
bool isAlive(SceneViewHandle handle) const { return pool.isAlive(handle); }
u32 size() const { return pool.size(); }
template <typename Fn>
void forEach(Fn&& fn) {
isRenderQueueDirty = true;
pool.forEach(std::forward<Fn>(fn));
}
template <typename Fn>
void forEach(Fn&& fn) const {
pool.forEach(std::forward<Fn>(fn));
}
const std::vector<SceneViewHandle>& GetRenderQueue() const {
if (isRenderQueueDirty) {
rebuildRenderQueue();
}
return renderQueue;
}
private:
void rebuildRenderQueue() const {
renderQueue.clear();
pool.forEachWithHandle([&](SceneViewHandle handle, const SceneView& view) {
if (view.enabled) {
renderQueue.push_back(handle);
}
});
std::ranges::stable_sort(renderQueue, {}, [this](SceneViewHandle handle) {
return pool.get(handle).priority;
});
isRenderQueueDirty = false;
}
Pool<SceneView> pool{"SceneView"};
mutable std::vector<SceneViewHandle> renderQueue;
mutable bool isRenderQueueDirty = true;
};
} // namespace sophia
+11
View File
@@ -75,6 +75,17 @@ class Pool {
} }
} }
/** Calls `fn(handle, item)` for every live item. */
template <typename Fn>
void forEachWithHandle(Fn&& fn) const {
for (u32 index = 0; index < slots.size(); index++) {
const Slot& slot = slots[index];
if (slot.item) {
fn(Handle<T>{index, slot.generation}, *slot.item);
}
}
}
template <typename Predicate> template <typename Predicate>
T* findIf(Predicate&& predicate) { T* findIf(Predicate&& predicate) {
return const_cast<T*>( return const_cast<T*>(
+47 -62
View File
@@ -1,9 +1,11 @@
#include <imgui.h> #include <imgui.h>
#include <algorithm>
#include <array> #include <array>
#include <chrono> #include <chrono>
#include <cstddef> #include <cstddef>
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <map>
#include <sophia/application.hpp> #include <sophia/application.hpp>
#include <sophia/util/logger.hpp> #include <sophia/util/logger.hpp>
#include <string> #include <string>
@@ -15,6 +17,7 @@
#include "rendering/model_render_system.hpp" #include "rendering/model_render_system.hpp"
#include "rendering/render_context.hpp" #include "rendering/render_context.hpp"
#include "rendering/render_graph.hpp" #include "rendering/render_graph.hpp"
#include "rendering/scene_renderer.hpp"
#include "resources/mesh.hpp" #include "resources/mesh.hpp"
#include "resources/render_target.hpp" #include "resources/render_target.hpp"
#include "resources/resource_registry.hpp" #include "resources/resource_registry.hpp"
@@ -43,35 +46,8 @@ std::vector<std::string> commandLineArgs;
constexpr ClearColor CLEAR_COLOR = {0.01f, 0.01f, 0.02f, 1.0f}; constexpr ClearColor CLEAR_COLOR = {0.01f, 0.01f, 0.02f, 1.0f};
void beginColorPass(vk::CommandBuffer commandBuffer, vk::ImageView view, bool hasFlag(ClearFlags flags, ClearFlags flag) {
vk::Extent2D extent) { return (static_cast<u8>(flags) & static_cast<u8>(flag)) != 0;
vk::ClearValue clearValue{};
clearValue.color = vk::ClearColorValue{CLEAR_COLOR};
vk::RenderingAttachmentInfo colorAttachment{};
colorAttachment.imageView = view;
colorAttachment.imageLayout = vk::ImageLayout::eColorAttachmentOptimal;
colorAttachment.loadOp = vk::AttachmentLoadOp::eClear;
colorAttachment.storeOp = vk::AttachmentStoreOp::eStore;
colorAttachment.clearValue = clearValue;
vk::RenderingInfo renderingInfo{};
renderingInfo.renderArea = vk::Rect2D{{0, 0}, extent};
renderingInfo.layerCount = 1;
renderingInfo.colorAttachmentCount = 1;
renderingInfo.pColorAttachments = &colorAttachment;
commandBuffer.beginRendering(renderingInfo);
vk::Viewport viewport{0.0f,
0.0f,
static_cast<float>(extent.width),
static_cast<float>(extent.height),
0.0f,
1.0f};
vk::Rect2D scissor{{0, 0}, extent};
commandBuffer.setViewport(0, viewport);
commandBuffer.setScissor(0, scissor);
} }
} // namespace } // namespace
@@ -88,6 +64,8 @@ class Application::Impl {
void run() { void run() {
ModelRenderSystem modelRenderSystem{device, renderContext}; ModelRenderSystem modelRenderSystem{device, renderContext};
SceneRenderer sceneRenderer{this->application.sceneRegistry,
this->resourceRegistry};
ImGuiRenderer imguiRenderer{window, device, renderContext.getImageFormat(), ImGuiRenderer imguiRenderer{window, device, renderContext.getImageFormat(),
renderContext.getImageCount(), renderContext.getImageCount(),
this->resourceRegistry}; this->resourceRegistry};
@@ -106,6 +84,7 @@ class Application::Impl {
auto& renderTargetPool = this->resourceRegistry.renderTargetPool; auto& renderTargetPool = this->resourceRegistry.renderTargetPool;
PanelRegistry& panelRegistry = this->application.panelRegistry; PanelRegistry& panelRegistry = this->application.panelRegistry;
const SceneViewRegistry& sceneViews = this->application.sceneViewRegistry;
imguiRenderer.setDefaultLayout(panelRegistry.getDefaultLayout()); imguiRenderer.setDefaultLayout(panelRegistry.getDefaultLayout());
@@ -128,17 +107,10 @@ class Application::Impl {
// frame's work (or ImGui's references to the targets) is recorded. // frame's work (or ImGui's references to the targets) is recorded.
renderTargetPool.applyPendingResizes(); renderTargetPool.applyPendingResizes();
RenderTarget* sceneTarget =
this->sceneTargetHandle.isValid()
? &renderTargetPool.get(this->sceneTargetHandle)
: nullptr;
vk::Extent2D extent = renderContext.getExtent(); vk::Extent2D extent = renderContext.getExtent();
vk::Extent2D sceneExtent =
sceneTarget ? sceneTarget->getExtent() : extent;
FrameInfo frameInfo{frameIndex, elapsedTime, deltaTime, FrameInfo frameInfo{frameIndex, elapsedTime, deltaTime,
glm::vec2(static_cast<float>(sceneExtent.width), glm::vec2(static_cast<float>(extent.width),
static_cast<float>(sceneExtent.height)), static_cast<float>(extent.height)),
this->application.camera}; this->application.camera};
this->application.onUpdate(frameInfo); this->application.onUpdate(frameInfo);
this->application.camera.setProjection( this->application.camera.setProjection(
@@ -166,31 +138,54 @@ class Application::Impl {
this->drawCalls.end()); this->drawCalls.end());
this->drawCalls.clear(); this->drawCalls.clear();
if (sceneTarget) {
Image& targetImage = sceneTarget->getImage();
targetImage.transitionLayout(commandBuffer,
vk::ImageLayout::eColorAttachmentOptimal);
beginColorPass(commandBuffer, targetImage.getView(), sceneExtent);
modelRenderSystem.render(commandBuffer, instances, frameInfo);
commandBuffer.endRendering();
targetImage.transitionLayout(commandBuffer,
vk::ImageLayout::eShaderReadOnlyOptimal);
}
RenderGraph graph; RenderGraph graph;
ImageRef backbuffer = ImageRef backbuffer =
graph.importImage(renderContext.getCurrentImage(), Access::Present); graph.importImage(renderContext.getCurrentImage(), Access::Present);
std::map<RenderTargetHandle, ImageRef> viewTargets;
for (SceneViewHandle handle : sceneViews.GetRenderQueue()) {
const SceneView& view = sceneViews.get(handle);
if (!this->application.sceneRegistry.isAlive(view.scene) ||
!renderTargetPool.isAlive(view.target)) {
continue;
}
auto [it, inserted] = viewTargets.try_emplace(view.target);
if (inserted) {
it->second =
graph.importImage(renderTargetPool.get(view.target).getImage(),
Access::SampledRead);
}
const vec4& color = view.clearColor;
graph.addPass(
"scene view",
[&](RenderGraph::PassBuilder& pass) {
pass.writeColor(it->second,
hasFlag(view.clearFlags, ClearFlags::Color)
? vk::AttachmentLoadOp::eClear
: vk::AttachmentLoadOp::eLoad,
{color.r, color.g, color.b, color.a});
},
[&sceneRenderer, &sceneViews, handle](vk::CommandBuffer) {
const SceneView& view = sceneViews.get(handle);
if (view.camera) {
sceneRenderer.render(view);
}
});
}
graph.addPass( graph.addPass(
"main", "main",
[&](RenderGraph::PassBuilder& pass) { [&](RenderGraph::PassBuilder& pass) {
pass.writeColor(backbuffer, vk::AttachmentLoadOp::eClear, pass.writeColor(backbuffer, vk::AttachmentLoadOp::eClear,
CLEAR_COLOR); CLEAR_COLOR);
for (const auto& [handle, target] : viewTargets) {
pass.sample(target);
}
}, },
[&](vk::CommandBuffer commandBuffer) { [&](vk::CommandBuffer commandBuffer) {
if (!sceneTarget) { modelRenderSystem.render(commandBuffer, instances, frameInfo);
modelRenderSystem.render(commandBuffer, instances, frameInfo);
}
imguiRenderer.endFrame(commandBuffer); imguiRenderer.endFrame(commandBuffer);
}); });
@@ -237,10 +232,6 @@ class Application::Impl {
this->drawCalls.push_back({&mesh, transform}); this->drawCalls.push_back({&mesh, transform});
} }
void setSceneTarget(RenderTargetHandle handle) {
this->sceneTargetHandle = handle;
}
ResourceRegistry& getResourceRegistry() { return resourceRegistry; } ResourceRegistry& getResourceRegistry() { return resourceRegistry; }
private: private:
@@ -253,8 +244,6 @@ class Application::Impl {
std::vector<std::unique_ptr<Mesh>> meshes; std::vector<std::unique_ptr<Mesh>> meshes;
std::vector<ModelRenderSystem::MeshInstance> drawCalls; std::vector<ModelRenderSystem::MeshInstance> drawCalls;
RenderTargetHandle sceneTargetHandle = RenderTargetHandle::invalid();
}; };
void Application::setCommandLineArgs(int argc, const char* const* argv) { void Application::setCommandLineArgs(int argc, const char* const* argv) {
@@ -281,10 +270,6 @@ void Application::pushMesh(std::vector<CanvasVertex> vertices,
impl->pushMesh(std::move(vertices), std::move(indices)); impl->pushMesh(std::move(vertices), std::move(indices));
} }
void Application::setSceneTarget(RenderTargetHandle handle) {
impl->setSceneTarget(handle);
}
void Application::clearMeshes() { impl->clearMeshes(); } void Application::clearMeshes() { impl->clearMeshes(); }
void Application::drawMesh(MeshHandle handle, const glm::mat4& transform) { void Application::drawMesh(MeshHandle handle, const glm::mat4& transform) {
+10 -1
View File
@@ -3,6 +3,8 @@
#include <sophia/util/assert.hpp> #include <sophia/util/assert.hpp>
#include <utility> #include <utility>
#include "vulkan/debug_label.hpp"
namespace sophia { namespace sophia {
ImageRef RenderGraph::importImage(Image& image, Access finalAccess) { ImageRef RenderGraph::importImage(Image& image, Access finalAccess) {
@@ -74,6 +76,8 @@ void RenderGraph::flush(vk::CommandBuffer commandBuffer,
} }
void RenderGraph::recordPass(vk::CommandBuffer commandBuffer, Pass& pass) { void RenderGraph::recordPass(vk::CommandBuffer commandBuffer, Pass& pass) {
beginDebugLabel(commandBuffer, pass.name.c_str());
PendingBarriers pending; PendingBarriers pending;
for (const ImageUse& use : pass.uses) { for (const ImageUse& use : pass.uses) {
this->transitionTo(use.image, getAccessState(use.access), pending); this->transitionTo(use.image, getAccessState(use.access), pending);
@@ -82,9 +86,14 @@ void RenderGraph::recordPass(vk::CommandBuffer commandBuffer, Pass& pass) {
if (pass.colorAttachments.empty()) { if (pass.colorAttachments.empty()) {
pass.execute(commandBuffer); pass.execute(commandBuffer);
return; } else {
this->recordRendering(commandBuffer, pass);
} }
endDebugLabel(commandBuffer);
}
void RenderGraph::recordRendering(vk::CommandBuffer commandBuffer, Pass& pass) {
std::vector<vk::RenderingAttachmentInfo> attachments; std::vector<vk::RenderingAttachmentInfo> attachments;
attachments.reserve(pass.colorAttachments.size()); attachments.reserve(pass.colorAttachments.size());
+3 -1
View File
@@ -67,7 +67,8 @@ class RenderGraph {
/** /**
* Adds a pass. `setup` runs immediately and declares what the pass does to * Adds a pass. `setup` runs immediately and declares what the pass does to
* images; `execute` runs later, from execute(), with the barriers already * images; `execute` runs later, from execute(), with the barriers already
* recorded and (if the pass writes color) rendering begun. * recorded and (if the pass writes color) rendering begun. `name` labels
* the pass's commands in debugging tools such as RenderDoc.
*/ */
void addPass(std::string name, const SetupFn& setup, ExecuteFn execute); void addPass(std::string name, const SetupFn& setup, ExecuteFn execute);
@@ -112,6 +113,7 @@ class RenderGraph {
PendingBarriers& pending); PendingBarriers& pending);
void flush(vk::CommandBuffer commandBuffer, PendingBarriers& pending); void flush(vk::CommandBuffer commandBuffer, PendingBarriers& pending);
void recordPass(vk::CommandBuffer commandBuffer, Pass& pass); void recordPass(vk::CommandBuffer commandBuffer, Pass& pass);
void recordRendering(vk::CommandBuffer commandBuffer, Pass& pass);
std::vector<ImportedImage> images; std::vector<ImportedImage> images;
std::vector<Pass> passes; std::vector<Pass> passes;
+8 -4
View File
@@ -12,13 +12,17 @@ struct PushConstantData {
}; };
} // namespace } // namespace
SceneRenderer::SceneRenderer(ResourceRegistry& resources) SceneRenderer::SceneRenderer(const SceneRegistry& sceneRegistry,
: resources{resources} {} ResourceRegistry& resources)
: sceneRegistry{sceneRegistry}, resources{resources} {}
SceneRenderer::~SceneRenderer() {} SceneRenderer::~SceneRenderer() {}
void SceneRenderer::render(const Scene& scene, Entity camera, void SceneRenderer::render(SceneView sceneView) {
RenderTargetHandle target) { auto& handle = sceneView.scene;
auto& scene = this->sceneRegistry.get(handle);
auto& camera = sceneView.camera;
SOPHIA_ASSERT(camera.hasComponent<CameraComponent>(), SOPHIA_ASSERT(camera.hasComponent<CameraComponent>(),
"camera does not have camera component!"); "camera does not have camera component!");
+6 -5
View File
@@ -1,9 +1,8 @@
#pragma once #pragma once
#include <sophia/handles.hpp> #include <sophia/scene_registry.hpp>
#include <sophia/scene.hpp> #include <sophia/scene_view.hpp>
#include "entity.hpp"
#include "resources/resource_registry.hpp" #include "resources/resource_registry.hpp"
namespace sophia { namespace sophia {
@@ -16,12 +15,14 @@ class SceneRenderer {
SceneRenderer(const SceneRenderer&) = delete; SceneRenderer(const SceneRenderer&) = delete;
SceneRenderer& operator=(const SceneRenderer&) = delete; SceneRenderer& operator=(const SceneRenderer&) = delete;
SceneRenderer(ResourceRegistry& resources); SceneRenderer(const SceneRegistry& sceneRegistry,
ResourceRegistry& resources);
~SceneRenderer(); ~SceneRenderer();
void render(const Scene& scene, Entity camera, RenderTargetHandle target); void render(SceneView sceneView);
private: private:
const SceneRegistry& sceneRegistry;
ResourceRegistry& resources; ResourceRegistry& resources;
}; };
+1 -1
View File
@@ -32,8 +32,8 @@ void RenderTarget::applyPendingResize() {
return; return;
} }
// Earlier frames may still be sampling the old image (e.g. through the UI).
this->device.waitIdle(); this->device.waitIdle();
destroy(); destroy();
create(extent.width, extent.height); create(extent.width, extent.height);
} }
@@ -1,4 +1,4 @@
#include "entity.hpp" #include <sophia/entity.hpp>
namespace sophia { namespace sophia {
+34
View File
@@ -0,0 +1,34 @@
#include "vulkan/debug_label.hpp"
namespace sophia {
static PFN_vkCmdBeginDebugUtilsLabelEXT cmdBeginDebugUtilsLabel = nullptr;
static PFN_vkCmdEndDebugUtilsLabelEXT cmdEndDebugUtilsLabel = nullptr;
void loadDebugLabelFunctions(vk::Instance instance) {
cmdBeginDebugUtilsLabel = reinterpret_cast<PFN_vkCmdBeginDebugUtilsLabelEXT>(
vkGetInstanceProcAddr(instance, "vkCmdBeginDebugUtilsLabelEXT"));
cmdEndDebugUtilsLabel = reinterpret_cast<PFN_vkCmdEndDebugUtilsLabelEXT>(
vkGetInstanceProcAddr(instance, "vkCmdEndDebugUtilsLabelEXT"));
}
void beginDebugLabel(vk::CommandBuffer commandBuffer, const char* name) {
if (!cmdBeginDebugUtilsLabel) {
return;
}
VkDebugUtilsLabelEXT label{};
label.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
label.pLabelName = name;
cmdBeginDebugUtilsLabel(commandBuffer, &label);
}
void endDebugLabel(vk::CommandBuffer commandBuffer) {
if (!cmdEndDebugUtilsLabel) {
return;
}
cmdEndDebugUtilsLabel(commandBuffer);
}
} // namespace sophia
+13
View File
@@ -0,0 +1,13 @@
#pragma once
#include <vulkan/vulkan.hpp>
namespace sophia {
void loadDebugLabelFunctions(vk::Instance instance);
void beginDebugLabel(vk::CommandBuffer commandBuffer, const char* name);
void endDebugLabel(vk::CommandBuffer commandBuffer);
} // namespace sophia
+4
View File
@@ -5,6 +5,8 @@
#include <set> #include <set>
#include <sophia/util/logger.hpp> #include <sophia/util/logger.hpp>
#include "vulkan/debug_label.hpp"
namespace sophia { namespace sophia {
static VKAPI_ATTR vk::Bool32 VKAPI_CALL static VKAPI_ATTR vk::Bool32 VKAPI_CALL
@@ -288,6 +290,8 @@ void Device::setupDebugMessenger() {
nullptr, &this->debugMessenger) != VK_SUCCESS) { nullptr, &this->debugMessenger) != VK_SUCCESS) {
throw std::runtime_error("failed to set up debug callback!"); throw std::runtime_error("failed to set up debug callback!");
} }
loadDebugLabelFunctions(*instance);
} }
bool Device::checkValidationLayerSupport() { bool Device::checkValidationLayerSupport() {
+10 -4
View File
@@ -1,7 +1,9 @@
#include <imgui.h> #include <imgui.h>
#include <sophia/application.hpp> #include <sophia/application.hpp>
#include <sophia/entity.hpp>
#include <sophia/frame_info.hpp> #include <sophia/frame_info.hpp>
#include <sophia/scene_view.hpp>
#include <sophia/ui/panel.hpp> #include <sophia/ui/panel.hpp>
class Viewport : public sophia::Panel { class Viewport : public sophia::Panel {
@@ -25,11 +27,15 @@ class Testbed : public sophia::Application {
Testbed() : Application{{.width = 750, .height = 1000, .name = "Testbed"}} {} Testbed() : Application{{.width = 750, .height = 1000, .name = "Testbed"}} {}
void onCreate() override { void onCreate() override {
sophia::RenderTargetHandle target = view = views().create({.scene = scenes().create(),
resources().create<sophia::RenderTarget>(); .target = resources().create<sophia::RenderTarget>(),
setSceneTarget(target); .clearColor = {0.1f, 0.1f, 0.15f, 1.f}});
panels().emplace<Viewport>(ui(), target);
panels().emplace<Viewport>(ui(), views().get(view).target);
} }
private:
sophia::SceneViewHandle view;
}; };
SOPHIA_MAIN(Testbed) SOPHIA_MAIN(Testbed)