Line data Source code
1 : #include "ui.hpp"
2 :
3 : #include <imgui.h>
4 : #include <imgui_impl_sdl3.h>
5 : #include <imgui_impl_vulkan.h>
6 :
7 : #include <vulkan/vulkan.hpp>
8 : #include <wren/context.hpp>
9 : #include <wren/renderer.hpp>
10 : #include <wren/vk/result.hpp>
11 :
12 : #include "wren/logging/log.hpp"
13 :
14 : namespace editor::ui {
15 :
16 0 : void check_result(VkResult res) {
17 0 : if (res != VK_SUCCESS) {
18 0 : throw std::runtime_error("Vulkan error");
19 : }
20 0 : }
21 :
22 0 : auto mouse_code_to_imgui(wren::MouseCode code) {
23 0 : switch (code) {
24 : case wren::MouseCode::Left:
25 0 : return ImGuiMouseButton_Left;
26 : case wren::MouseCode::Right:
27 0 : return ImGuiMouseButton_Right;
28 : case wren::MouseCode::Middle:
29 0 : return ImGuiMouseButton_Middle;
30 0 : }
31 0 : }
32 :
33 0 : auto key_code_to_imgui(wren::KeyCode code) {
34 0 : switch (code) {
35 : case wren::KeyCode::kUnknown:
36 0 : return ImGuiKey::ImGuiKey_None;
37 : case wren::KeyCode::kEnter:
38 0 : return ImGuiKey::ImGuiKey_Enter;
39 : case wren::KeyCode::kEscape:
40 0 : return ImGuiKey::ImGuiKey_Escape;
41 : case wren::KeyCode::kBackspace:
42 0 : return ImGuiKey::ImGuiKey_Backspace;
43 : case wren::KeyCode::kTab:
44 0 : return ImGuiKey::ImGuiKey_Tab;
45 : case wren::KeyCode::kSpace:
46 0 : return ImGuiKey::ImGuiKey_Space;
47 : case wren::KeyCode::kExclaim:
48 0 : return ImGuiKey::ImGuiKey_None; // FIXME
49 : case wren::KeyCode::kDoubleQuote:
50 0 : return ImGuiKey::ImGuiKey_None; // FIXME
51 : case wren::KeyCode::kHash:
52 0 : return ImGuiKey::ImGuiKey_None; // FIXME
53 : case wren::KeyCode::kPercent:
54 0 : return ImGuiKey::ImGuiKey_None; // FIXME
55 : case wren::KeyCode::kDollar:
56 0 : return ImGuiKey::ImGuiKey_None; // FIXME
57 : case wren::KeyCode::kAmpersand:
58 0 : return ImGuiKey::ImGuiKey_None; // FIXME
59 : case wren::KeyCode::kQuote:
60 0 : return ImGuiKey::ImGuiKey_None; // FIXME
61 : case wren::KeyCode::kLeftParen:
62 0 : return ImGuiKey::ImGuiKey_None; // FIXME
63 : case wren::KeyCode::kRightParen:
64 0 : return ImGuiKey::ImGuiKey_None; // FIXME
65 : case wren::KeyCode::kAsterix:
66 0 : return ImGuiKey::ImGuiKey_None; // FIXME
67 : case wren::KeyCode::kPlus:
68 : case wren::KeyCode::kComma:
69 : case wren::KeyCode::kMinus:
70 : case wren::KeyCode::kPeriod:
71 : case wren::KeyCode::kSlash:
72 : case wren::KeyCode::k0:
73 0 : return ImGuiKey::ImGuiKey_0;
74 : case wren::KeyCode::k1:
75 0 : return ImGuiKey::ImGuiKey_1;
76 : case wren::KeyCode::k2:
77 0 : return ImGuiKey::ImGuiKey_2;
78 : case wren::KeyCode::k3:
79 0 : return ImGuiKey::ImGuiKey_3;
80 : case wren::KeyCode::k4:
81 0 : return ImGuiKey::ImGuiKey_4;
82 : case wren::KeyCode::k5:
83 0 : return ImGuiKey::ImGuiKey_5;
84 : case wren::KeyCode::k6:
85 0 : return ImGuiKey::ImGuiKey_6;
86 : case wren::KeyCode::k7:
87 0 : return ImGuiKey::ImGuiKey_7;
88 : case wren::KeyCode::k8:
89 0 : return ImGuiKey::ImGuiKey_8;
90 : case wren::KeyCode::k9:
91 0 : return ImGuiKey::ImGuiKey_9;
92 : case wren::KeyCode::kColon:
93 0 : return ImGuiKey::ImGuiKey_None; // FIXME
94 : case wren::KeyCode::kSemicolon:
95 0 : return ImGuiKey::ImGuiKey_Semicolon;
96 : case wren::KeyCode::kLess:
97 0 : return ImGuiKey::ImGuiKey_LeftShift;
98 : case wren::KeyCode::kEquals:
99 0 : return ImGuiKey::ImGuiKey_Equal;
100 : case wren::KeyCode::kGreater:
101 0 : return ImGuiKey::ImGuiKey_RightShift;
102 : case wren::KeyCode::kQuestion:
103 0 : return ImGuiKey::ImGuiKey_None; // FIXME
104 : case wren::KeyCode::kAt:
105 0 : return ImGuiKey::ImGuiKey_None; // FIXME
106 : case wren::KeyCode::kLeftBracket:
107 0 : return ImGuiKey::ImGuiKey_LeftBracket;
108 : case wren::KeyCode::kRightBracket:
109 0 : return ImGuiKey::ImGuiKey_RightBracket;
110 : case wren::KeyCode::kBackslash:
111 0 : return ImGuiKey::ImGuiKey_Backslash;
112 : case wren::KeyCode::kCaret:
113 0 : return ImGuiKey::ImGuiKey_GraveAccent;
114 : case wren::KeyCode::kUnderscore:
115 0 : return ImGuiKey::ImGuiKey_None; // NOLINT
116 : case wren::KeyCode::kBackquote:
117 0 : return ImGuiKey::ImGuiKey_None;
118 : case wren::KeyCode::kA:
119 0 : return ImGuiKey::ImGuiKey_A;
120 : case wren::KeyCode::kB:
121 0 : return ImGuiKey::ImGuiKey_B;
122 : case wren::KeyCode::kC:
123 0 : return ImGuiKey::ImGuiKey_C;
124 : case wren::KeyCode::kD:
125 0 : return ImGuiKey::ImGuiKey_D;
126 : case wren::KeyCode::kE:
127 0 : return ImGuiKey::ImGuiKey_E;
128 : case wren::KeyCode::kF:
129 0 : return ImGuiKey::ImGuiKey_F;
130 : case wren::KeyCode::kG:
131 0 : return ImGuiKey::ImGuiKey_G;
132 : case wren::KeyCode::kH:
133 0 : return ImGuiKey::ImGuiKey_H;
134 : case wren::KeyCode::kI:
135 0 : return ImGuiKey::ImGuiKey_I;
136 : case wren::KeyCode::kJ:
137 0 : return ImGuiKey::ImGuiKey_J;
138 : case wren::KeyCode::kK:
139 0 : return ImGuiKey::ImGuiKey_K;
140 : case wren::KeyCode::kL:
141 0 : return ImGuiKey::ImGuiKey_L;
142 : case wren::KeyCode::kM:
143 0 : return ImGuiKey::ImGuiKey_M;
144 : case wren::KeyCode::kN:
145 0 : return ImGuiKey::ImGuiKey_N;
146 : case wren::KeyCode::kO:
147 0 : return ImGuiKey::ImGuiKey_O;
148 : case wren::KeyCode::kP:
149 0 : return ImGuiKey::ImGuiKey_P;
150 : case wren::KeyCode::kQ:
151 0 : return ImGuiKey::ImGuiKey_Q;
152 : case wren::KeyCode::kR:
153 0 : return ImGuiKey::ImGuiKey_R;
154 : case wren::KeyCode::kS:
155 0 : return ImGuiKey::ImGuiKey_S;
156 : case wren::KeyCode::kT:
157 0 : return ImGuiKey::ImGuiKey_T;
158 : case wren::KeyCode::kU:
159 0 : return ImGuiKey::ImGuiKey_U;
160 : case wren::KeyCode::kV:
161 0 : return ImGuiKey::ImGuiKey_V;
162 : case wren::KeyCode::kW:
163 0 : return ImGuiKey::ImGuiKey_W;
164 : case wren::KeyCode::kX:
165 0 : return ImGuiKey::ImGuiKey_X;
166 : case wren::KeyCode::kY:
167 0 : return ImGuiKey::ImGuiKey_Y;
168 : case wren::KeyCode::kZ:
169 0 : return ImGuiKey::ImGuiKey_Z;
170 : case wren::KeyCode::kCapslock:
171 0 : return ImGuiKey::ImGuiKey_CapsLock;
172 : case wren::KeyCode::kF1:
173 0 : return ImGuiKey::ImGuiKey_F1;
174 : case wren::KeyCode::kF2:
175 0 : return ImGuiKey::ImGuiKey_F2;
176 : case wren::KeyCode::kF3:
177 0 : return ImGuiKey::ImGuiKey_F3;
178 : case wren::KeyCode::kF4:
179 0 : return ImGuiKey::ImGuiKey_F4;
180 : case wren::KeyCode::kF5:
181 0 : return ImGuiKey::ImGuiKey_F5;
182 : case wren::KeyCode::kF6:
183 0 : return ImGuiKey::ImGuiKey_F6;
184 : case wren::KeyCode::kF7:
185 0 : return ImGuiKey::ImGuiKey_F7;
186 : case wren::KeyCode::kF8:
187 0 : return ImGuiKey::ImGuiKey_F8;
188 : case wren::KeyCode::kF9:
189 0 : return ImGuiKey::ImGuiKey_F9;
190 : case wren::KeyCode::kF10:
191 0 : return ImGuiKey::ImGuiKey_F10;
192 : case wren::KeyCode::kF11:
193 0 : return ImGuiKey::ImGuiKey_F11;
194 : case wren::KeyCode::kF12:
195 0 : return ImGuiKey::ImGuiKey_F12;
196 : case wren::KeyCode::kF13:
197 0 : return ImGuiKey::ImGuiKey_F13;
198 : case wren::KeyCode::kF14:
199 0 : return ImGuiKey::ImGuiKey_F14;
200 : case wren::KeyCode::kF15:
201 0 : return ImGuiKey::ImGuiKey_F15;
202 : case wren::KeyCode::kF16:
203 0 : return ImGuiKey::ImGuiKey_F16;
204 : case wren::KeyCode::kF17:
205 0 : return ImGuiKey::ImGuiKey_F17;
206 : case wren::KeyCode::kF18:
207 0 : return ImGuiKey::ImGuiKey_F18;
208 : case wren::KeyCode::kF19:
209 0 : return ImGuiKey::ImGuiKey_F19;
210 : case wren::KeyCode::kF20:
211 0 : return ImGuiKey::ImGuiKey_F20;
212 : case wren::KeyCode::kF21:
213 0 : return ImGuiKey::ImGuiKey_F21;
214 : case wren::KeyCode::kF22:
215 0 : return ImGuiKey::ImGuiKey_F22;
216 : case wren::KeyCode::kF23:
217 0 : return ImGuiKey::ImGuiKey_F23;
218 : case wren::KeyCode::kF24:
219 0 : return ImGuiKey::ImGuiKey_F24;
220 : case wren::KeyCode::kPrintScreen:
221 0 : return ImGuiKey::ImGuiKey_PrintScreen;
222 : case wren::KeyCode::kScrollLock:
223 0 : return ImGuiKey::ImGuiKey_ScrollLock;
224 : case wren::KeyCode::kPause:
225 0 : return ImGuiKey::ImGuiKey_Pause;
226 : case wren::KeyCode::kInsert:
227 0 : return ImGuiKey::ImGuiKey_Insert;
228 : case wren::KeyCode::kHome:
229 0 : return ImGuiKey::ImGuiKey_Home;
230 : case wren::KeyCode::kPageUp:
231 0 : return ImGuiKey::ImGuiKey_PageUp;
232 : case wren::KeyCode::kDelete:
233 0 : return ImGuiKey::ImGuiKey_Delete;
234 : case wren::KeyCode::kEnd:
235 0 : return ImGuiKey::ImGuiKey_End;
236 : case wren::KeyCode::kPageDown:
237 0 : return ImGuiKey::ImGuiKey_PageDown;
238 : case wren::KeyCode::kRight:
239 0 : return ImGuiKey::ImGuiKey_RightArrow;
240 : case wren::KeyCode::kLeft:
241 0 : return ImGuiKey::ImGuiKey_LeftArrow;
242 : case wren::KeyCode::kUp:
243 0 : return ImGuiKey::ImGuiKey_UpArrow;
244 : case wren::KeyCode::kDown:
245 0 : return ImGuiKey::ImGuiKey_DownArrow;
246 : break;
247 0 : }
248 0 : }
249 :
250 0 : auto init(const std::shared_ptr<wren::Context>& context)
251 : -> wren::expected<void> {
252 0 : ImGui::CreateContext();
253 0 : ImGuiIO& io = ImGui::GetIO();
254 0 : io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
255 :
256 : // ========== Setup events ===========
257 0 : context->event_dispatcher.on<wren::event::MouseMoved>([&io](const auto& e) {
258 0 : if (!e.relative) {
259 0 : io.AddMousePosEvent(e.x, e.y);
260 0 : } else {
261 0 : io.MouseDelta = {e.x, e.y};
262 : }
263 0 : });
264 :
265 0 : context->event_dispatcher.on<wren::event::MouseButtonDown>(
266 0 : [&io](const auto& e) {
267 0 : io.AddMouseButtonEvent(mouse_code_to_imgui(e.button), true);
268 0 : });
269 :
270 0 : context->event_dispatcher.on<wren::event::MouseButtonUp>(
271 0 : [&io](const auto& e) {
272 0 : io.AddMouseButtonEvent(mouse_code_to_imgui(e.button), false);
273 0 : });
274 :
275 0 : context->event_dispatcher.on<wren::event::KeyDown>(
276 0 : [&io](const auto& e) { io.AddKeyEvent(key_code_to_imgui(e.key), true); });
277 :
278 0 : context->event_dispatcher.on<wren::event::KeyUp>([&io](const auto& e) {
279 0 : io.AddKeyEvent(key_code_to_imgui(e.key), false);
280 0 : });
281 :
282 0 : context->event_dispatcher.on<wren::event::KeyTyped>(
283 0 : [&io](const auto& e) { io.AddInputCharactersUTF8(e.text.data()); });
284 :
285 0 : context->event_dispatcher.on<wren::event::MouseWheel>(
286 0 : [&io](const auto& e) { io.AddMouseWheelEvent(e.x, e.y); });
287 :
288 : // Initialize rendering
289 :
290 0 : ImGui_ImplSDL3_InitForVulkan(context->window.native_handle());
291 :
292 0 : const auto& graphics_context = context->graphics_context;
293 :
294 0 : ::vk::DescriptorPool pool;
295 :
296 : {
297 0 : std::array pool_sizes = {
298 0 : ::vk::DescriptorPoolSize{::vk::DescriptorType::eSampler, 1000},
299 : ::vk::DescriptorPoolSize{::vk::DescriptorType::eCombinedImageSampler,
300 : 1000},
301 : ::vk::DescriptorPoolSize{::vk::DescriptorType::eSampledImage, 1000},
302 : ::vk::DescriptorPoolSize{::vk::DescriptorType::eStorageImage, 1000},
303 : ::vk::DescriptorPoolSize{::vk::DescriptorType::eUniformTexelBuffer,
304 : 1000},
305 : ::vk::DescriptorPoolSize{::vk::DescriptorType::eStorageTexelBuffer,
306 : 1000},
307 : ::vk::DescriptorPoolSize{::vk::DescriptorType::eUniformBuffer, 1000},
308 : ::vk::DescriptorPoolSize{::vk::DescriptorType::eStorageBuffer, 1000},
309 : ::vk::DescriptorPoolSize{::vk::DescriptorType::eUniformBufferDynamic,
310 : 1000},
311 : ::vk::DescriptorPoolSize{::vk::DescriptorType::eStorageBufferDynamic,
312 : 1000},
313 : ::vk::DescriptorPoolSize{::vk::DescriptorType::eInputAttachment, 1000},
314 : };
315 :
316 0 : ::vk::DescriptorPoolCreateInfo pool_info{
317 0 : ::vk::DescriptorPoolCreateFlagBits::eFreeDescriptorSet,
318 0 : 1000 * pool_sizes.size(), pool_sizes};
319 :
320 0 : VK_TIE_RESULT(
321 : pool, graphics_context->Device().get().createDescriptorPool(pool_info));
322 : }
323 :
324 0 : ImGui_ImplVulkan_InitInfo init_info{};
325 0 : init_info.Instance = graphics_context->Instance();
326 0 : init_info.PhysicalDevice = graphics_context->PhysicalDevice();
327 0 : init_info.Device = graphics_context->Device().get();
328 0 : init_info.Queue = graphics_context->Device().get_graphics_queue();
329 0 : init_info.QueueFamily =
330 0 : graphics_context->FindQueueFamilyIndices()->graphics_index;
331 0 : init_info.MinImageCount = 2;
332 0 : init_info.ImageCount = context->renderer->swapchain_images_views().size();
333 0 : init_info.PipelineInfoMain.MSAASamples = VK_SAMPLE_COUNT_1_BIT;
334 0 : init_info.PipelineInfoMain.RenderPass =
335 0 : context->renderer->get_graph().node_by_name("ui")->render_pass->get();
336 0 : init_info.DescriptorPool = pool;
337 0 : init_info.CheckVkResultFn = &check_result;
338 :
339 0 : if (!ImGui_ImplVulkan_Init(&init_info)) {
340 0 : wren::log::error("Failed to initialize vulkan for imgui");
341 0 : }
342 :
343 0 : wren::log::debug("Initialized ImGui");
344 :
345 0 : return {};
346 0 : }
347 :
348 0 : auto begin() -> void {
349 0 : ImGui_ImplVulkan_NewFrame();
350 0 : ImGui_ImplSDL3_NewFrame();
351 0 : ImGui::NewFrame();
352 0 : }
353 :
354 0 : auto end() -> void {}
355 :
356 0 : void flush(const ::vk::CommandBuffer& cmd) {
357 0 : ImGui::Render();
358 0 : ImDrawData* draw_data = ImGui::GetDrawData();
359 :
360 : // send draw data to command_buffer
361 0 : ImGui_ImplVulkan_RenderDrawData(draw_data, cmd);
362 0 : }
363 :
364 : } // namespace editor::ui
|