-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathSceneEmbedding.cpp
More file actions
153 lines (123 loc) · 5.75 KB
/
Copy pathSceneEmbedding.cpp
File metadata and controls
153 lines (123 loc) · 5.75 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
// rendering custom 3D shapes on a Vulkan offscreen framebuffer and composite it as content of a view component
#include <ViewDesign/view/widget/DefaultWindow.h>
#include <ViewDesign/view/frame/CenterFrame.h>
#include <ViewDesign/view/frame/BorderFrame.h>
#include <ViewDesign/view/control/Placeholder.h>
#include <ViewDesign/platform/vulkan/texture.h>
#include <ViewDesign/platform/vulkan/pipeline/composite.h>
#include "pipeline/tetra.h"
#include <chrono>
#include <optional>
#include <glm/gtc/matrix_transform.hpp>
using namespace ViewDesign;
class EmbeddedView : public Placeholder<Auto, Auto> {
private:
// the existing `Vulkan::Framebuffer` and `Vulkan::Render()` are used for `Layer` or `Surface` to render a `Canvas` with transform/clip context
// therefore, we define `Scene` as our framebuffer with an additional depth image and a custom render function
class Scene {
public:
static constexpr SizeU size = SizeU(400, 400);
public:
Texture color_texture;
Texture depth_texture;
public:
Scene() : color_texture(size) {
depth_texture.CreateDepthImage(size);
depth_texture.ClearDepthImage();
}
public:
void Render() {
// called during `EmbeddedView::OnDraw()`, reusing the command buffer of the current frame-in-flight of the window's surface
// the frame-in-flight itself is currently not being rendered
FrameInFlight& frame_in_flight = FrameInFlight::GetCurrent();
vk::raii::CommandBuffer& command_buffer = frame_in_flight.command_buffer;
static constexpr vk::ClearValue color_clear_value = vk::ClearValue(vk::ClearColorValue(std::array<float, 4>{ 0.0f, 0.0f, 0.0f, 0.0f }));
static constexpr vk::ClearValue depth_clear_value = vk::ClearValue(vk::ClearDepthStencilValue(1.0f, 0));
vk::Extent2D extent = color_texture.extent;
TransitionImageLayout(command_buffer, *color_texture.image, color_texture.image_layout, vk::ImageLayout::eColorAttachmentOptimal);
vk::RenderingAttachmentInfo color_attachment(*color_texture.image_view, vk::ImageLayout::eColorAttachmentOptimal, {}, {}, {}, vk::AttachmentLoadOp::eClear, vk::AttachmentStoreOp::eStore, color_clear_value);
vk::RenderingAttachmentInfo depth_attachment(*depth_texture.image_view, vk::ImageLayout::eDepthAttachmentOptimal, {}, {}, {}, vk::AttachmentLoadOp::eClear, vk::AttachmentStoreOp::eDontCare, depth_clear_value);
command_buffer.beginRendering(vk::RenderingInfo({}, vk::Rect2D({}, extent), 1, 0, color_attachment, &depth_attachment));
{
using Layout = TetraPipeline::Layout;
using Vertex = TetraPipeline::Input;
static constexpr float s = 0.8165f; // sqrt(2/3)
static constexpr float h = 0.5774f; // 1/sqrt(3)
static constexpr std::array<Vertex, 4> v = {
Vertex({ s, -h, 0.0f }, { 1, 0, 0 }),
Vertex({ -s, -h, 0.0f }, { 0, 1, 0 }),
Vertex({ 0.0f, h, -1.0f }, { 0, 0, 1 }),
Vertex({ 0.0f, h, 1.0f }, { 1, 1, 0 }),
};
static constexpr std::array<Vertex, 12> vertices = {
v[0], v[1], v[2],
v[0], v[2], v[3],
v[0], v[1], v[3],
v[1], v[2], v[3],
};
command_buffer.setViewport(0, vk::Viewport(0.0f, 0.0f, extent.width, extent.height, 0.0f, 1.0f));
command_buffer.setScissor(0, vk::Rect2D({}, extent));
command_buffer.bindPipeline(vk::PipelineBindPoint::eGraphics, *GetPipeline<TetraPipeline>());
float t = std::chrono::duration<float>(std::chrono::steady_clock::now().time_since_epoch()).count();
glm::mat4 model = glm::rotate(glm::mat4(1.0f), t, glm::vec3(0.4f, 1.0f, 0.3f));
glm::mat4 view = glm::lookAt(glm::vec3(0.0f, 0.0f, 3.5f), glm::vec3(0.0f), glm::vec3(0.0f, 1.0f, 0.0f));
glm::mat4 proj = glm::perspective(glm::radians(45.0f), (float)extent.width / extent.height, 0.1f, 100.0f);
glm::mat4 mvp = proj * view * model;
command_buffer.pushConstants<glm::mat4>(*GetPipelineLayout<Layout>(), vk::ShaderStageFlagBits::eVertex, offsetof(Layout::Context, vertex.mvp), mvp);
auto [vertex_buffer, offset] = frame_in_flight.PushVertices(vertices.data(), sizeof(vertices));
command_buffer.bindVertexBuffers(0, vertex_buffer, { offset });
command_buffer.draw(vertices.size(), 1, 0, 0);
}
command_buffer.endRendering();
TransitionImageLayout(command_buffer, *color_texture.image, color_texture.image_layout, vk::ImageLayout::eShaderReadOnlyOptimal);
}
};
struct SceneFigure : Figure {
Scene& scene;
SceneFigure(Scene& scene) : scene(scene) {}
virtual void DrawOn(RenderTarget& target, Point point) const override {
// the frame-in-flight is currently being rendered
// `Scene::Render()` should not be called here
target.BindPipeline<CompositePipeline>();
CompositePipeline::SetOpacity(target, 1.0f);
CompositePipeline::BindTexture(target, scene.color_texture);
target.DrawVertices(Zip(GetVertices(AsQuad(Rect(point, scene.size))), GetVertices(AsQuad(Rect(0.0f, 0.0f, 1.0f, 1.0f)))));
}
};
public:
EmbeddedView() : Placeholder(Scene::size) {}
private:
std::optional<Scene> scene;
public:
void Redraw() { Placeholder::Redraw(rect_infinite); }
private:
virtual void OnDraw(Canvas& canvas, Rect draw_region) override {
// `Scene` should also be created during `EmbeddedView::OnDraw()`, because it uses the command buffer of the current frame-in-flight as well
if (!scene.has_value()) { scene.emplace(); }
scene.value().Render();
canvas.draw(point_zero, new SceneFigure(*scene));
}
};
void App() {
ref_ptr<EmbeddedView> embedded_view;
desktop.AddWindow(
new DefaultWindow(
DefaultWindow::Style(),
u"SceneEmbedding",
new CenterFrame<Fixed, Fixed>(
new BorderFrame(
Border(2.0f, ColorCode::Orange),
embedded_view = new EmbeddedView()
)
)
)
);
for (;;) {
desktop.PollEvents();
if (desktop.WindowListEmpty()) {
break;
}
// `embedded_view` becomes a dangling reference after the window is closed
embedded_view->Redraw();
}
}