Line data Source code
1 : #include "editor.hpp"
2 :
3 : #include <wren/render_target.hpp>
4 :
5 : #include "filesystem_panel.hpp"
6 : #include "inspector_panel.hpp"
7 : #include "scene_panel.hpp"
8 : #include "wren/logging/log.hpp"
9 :
10 : namespace editor {
11 :
12 0 : auto Editor::create(const std::shared_ptr<wren::Application>& app,
13 : const std::filesystem::path& project_path)
14 : -> wren::expected<std::shared_ptr<Editor>> {
15 0 : wren::log::debug("Editor::create");
16 : // const auto &ctx = app->context();
17 :
18 0 : std::vector<std::filesystem::path> asset_paths = {
19 : #ifdef WREN_BUILD_ASSETS_DIR
20 0 : WREN_BUILD_ASSETS_DIR
21 : #endif
22 : };
23 :
24 0 : wren::assets::Manager asset_manager(asset_paths, project_path);
25 :
26 0 : auto editor = std::make_shared<Editor>(app->context());
27 0 : editor->editor_context_.asset_manager = asset_manager;
28 0 : editor->editor_context_.project_path = project_path;
29 0 : editor->load_scene();
30 :
31 : // TRY_RESULT(editor->viewer_shader_,
32 : // wren::vk::Shader::create(
33 : // app->context()->graphics_context->Device().get(),
34 : // editor->editor_context_.asset_manager
35 : // .find_asset("shaders/editor_grid.wren_shader")
36 : // .value()));
37 :
38 0 : wren::log::info("Intializing shaders");
39 :
40 0 : TRY_RESULT(const auto asset_path,
41 : editor->editor_context_.asset_manager.find_asset(
42 : "shaders/editor_mesh.slang"));
43 :
44 0 : TRY_RESULT(editor->mesh_shader_,
45 : wren::vk::Shader::create(
46 : app->context()->graphics_context->Device().get(), asset_path));
47 :
48 0 : TRY_RESULT(const auto graph, editor->build_render_graph(app->context()));
49 0 : TRY_RESULT(graph.build());
50 :
51 0 : editor::ui::init(app->context());
52 :
53 0 : vk::SamplerCreateInfo sampler_info{};
54 :
55 0 : auto t = app->context()->graphics_context->Device().get().createSampler(
56 : sampler_info);
57 0 : editor->texture_sampler_ = t.value;
58 :
59 0 : editor->dset_.resize(1);
60 0 : const auto scene_view = app->context()
61 0 : ->renderer->get_graph()
62 0 : .node_by_name("mesh")
63 0 : ->render_pass->colour_target()
64 0 : ->view();
65 0 : editor->dset_[0] =
66 0 : ImGui_ImplVulkan_AddTexture(editor->texture_sampler_, scene_view,
67 : VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
68 :
69 0 : app->add_callback_to_update_phase(
70 0 : [editor](const auto&) { editor->on_update(); });
71 :
72 0 : return editor;
73 0 : }
74 :
75 0 : Editor::Editor(const std::shared_ptr<wren::Context>& ctx)
76 0 : : camera_(45.F, 16.f / 9.f, 0.1, 1000.0),
77 0 : scene_(wren::scene::Scene::create()),
78 0 : wren_ctx_(ctx) {}
79 :
80 0 : void Editor::on_update() {
81 0 : ZoneScoped; // NOLINT
82 :
83 0 : if (scene_resized_.has_value()) {
84 0 : const auto& mesh_pass =
85 0 : wren_ctx_->renderer->get_graph().node_by_name("mesh")->render_pass;
86 :
87 0 : mesh_pass->resize_target(scene_resized_.value());
88 :
89 0 : const auto scene_view = wren_ctx_->renderer->get_graph()
90 0 : .node_by_name("mesh")
91 0 : ->render_pass->colour_target()
92 0 : ->view();
93 :
94 0 : ImGui_ImplVulkan_RemoveTexture(dset_[0]);
95 0 : dset_[0] = ImGui_ImplVulkan_AddTexture(
96 0 : texture_sampler_, scene_view, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
97 :
98 0 : camera_.aspect(static_cast<float>(scene_resized_->x()) /
99 0 : static_cast<float>(scene_resized_->y()));
100 :
101 0 : scene_resized_.reset();
102 0 : }
103 :
104 0 : editor::ui::begin();
105 :
106 : // ImGui::ShowDemoWindow();
107 :
108 : static ImGuiDockNodeFlags dockspace_flags = ImGuiDockNodeFlags_None;
109 0 : ImGuiWindowFlags window_flags =
110 : ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse |
111 : ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove |
112 : ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus |
113 : ImGuiWindowFlags_MenuBar;
114 :
115 0 : const ImGuiViewport* viewport = ImGui::GetMainViewport();
116 0 : ImGui::SetNextWindowPos(viewport->WorkPos);
117 0 : ImGui::SetNextWindowSize(viewport->WorkSize);
118 0 : ImGui::SetNextWindowViewport(viewport->ID);
119 0 : ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0F);
120 0 : ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0F);
121 :
122 0 : ImGui::Begin("Editor", nullptr, window_flags);
123 0 : if (ImGui::BeginMenuBar()) {
124 0 : if (ImGui::BeginMenu("File")) {
125 0 : if (ImGui::MenuItem("Save")) {
126 : // SAVE the scene
127 :
128 0 : auto file = editor_context_.project_path / "scene.wren";
129 0 : wren::scene::serialize(scene_, file);
130 0 : }
131 :
132 0 : ImGui::EndMenu();
133 0 : }
134 0 : ImGui::EndMenuBar();
135 0 : }
136 :
137 0 : ImGui::PopStyleVar(2);
138 :
139 0 : ImGuiIO& io = ImGui::GetIO();
140 0 : if (io.ConfigFlags & ImGuiConfigFlags_DockingEnable) {
141 0 : ImGuiID dockspace_id = ImGui::GetID("Editor");
142 0 : ImGui::DockSpace(dockspace_id, ImVec2{0.0F, 0.0F}, dockspace_flags);
143 :
144 : static bool first_time = true;
145 0 : if (first_time) {
146 0 : first_time = false;
147 :
148 0 : ImGui::DockBuilderRemoveNode(dockspace_id);
149 0 : ImGui::DockBuilderAddNode(dockspace_id,
150 0 : dockspace_flags | ImGuiDockNodeFlags_DockSpace);
151 0 : ImGui::DockBuilderSetNodeSize(dockspace_id, viewport->Size);
152 :
153 0 : const auto inspector = ImGui::DockBuilderSplitNode(
154 0 : dockspace_id, ImGuiDir_Right, 0.25F, nullptr, &dockspace_id);
155 :
156 0 : ImGuiID viewer = 0;
157 0 : const auto left = ImGui::DockBuilderSplitNode(dockspace_id, ImGuiDir_Left,
158 : 0.25F, nullptr, &viewer);
159 :
160 0 : ImGuiID scene = 0;
161 0 : const auto dockspace_id_bottom = ImGui::DockBuilderSplitNode(
162 0 : left, ImGuiDir_Down, 0.25, nullptr, &scene);
163 :
164 0 : ImGui::DockBuilderDockWindow("Inspector", inspector);
165 0 : ImGui::DockBuilderDockWindow("Viewer", viewer);
166 0 : ImGui::DockBuilderDockWindow("Scene", scene);
167 0 : ImGui::DockBuilderDockWindow("Filesystem", dockspace_id_bottom);
168 :
169 0 : ImGui::DockBuilderFinish(dockspace_id_bottom);
170 0 : }
171 0 : }
172 :
173 0 : ImGui::PushStyleVar(ImGuiStyleVar_WindowMinSize, ImVec2{500, 100});
174 :
175 : // Panels
176 0 : render_scene_panel(scene_, selected_entity_);
177 :
178 0 : ImGui::Begin("Viewer");
179 0 : auto curr_size = ImGui::GetContentRegionAvail();
180 0 : auto curr_size_vec = wren::math::Vec2f{curr_size.x, curr_size.y};
181 0 : if (curr_size_vec != last_scene_size_) {
182 0 : scene_resized_ = curr_size_vec;
183 0 : last_scene_size_ = curr_size_vec;
184 0 : }
185 :
186 0 : ImGui::Image(dset_[0], {static_cast<float>(last_scene_size_.x()),
187 0 : static_cast<float>(last_scene_size_.y())});
188 0 : ImGui::End();
189 :
190 0 : render_inspector_panel(editor_context_, scene_, selected_entity_);
191 :
192 0 : render_filesystem_panel(editor_context_);
193 :
194 0 : ImGui::End();
195 0 : ImGui::PopStyleVar();
196 :
197 0 : editor::ui::end();
198 0 : }
199 :
200 0 : auto Editor::load_scene() -> wren::expected<void> {
201 : // Deserialize project
202 :
203 0 : wren::log::info("Loading scene");
204 :
205 0 : std::string scene_name;
206 :
207 0 : wren::scene::deserialize(editor_context_.project_path, "scene.wren", scene_);
208 :
209 0 : wren::log::debug("Scene loaded");
210 :
211 0 : return {};
212 0 : }
213 :
214 0 : auto Editor::build_render_graph(const std::shared_ptr<wren::Context>& ctx)
215 : -> wren::expected<wren::GraphBuilder> {
216 0 : wren::GraphBuilder builder(ctx);
217 :
218 : auto render_query =
219 0 : scene_->world()
220 0 : .query_builder<const wren::scene::components::Transform,
221 : wren::scene::components::MeshRenderer>()
222 0 : .build();
223 :
224 0 : builder
225 0 : .add_pass(
226 0 : "mesh",
227 0 : wren::PassResources("scene_viewer")
228 0 : .add_shader("mesh", mesh_shader_)
229 0 : .add_colour_target()
230 0 : .add_depth_target(),
231 0 : [this, ctx, render_query](wren::RenderPass& pass,
232 : ::vk::CommandBuffer& cmd) {
233 : struct GLOBALS {
234 0 : wren::math::Mat4f view = wren::math::Mat4f::identity();
235 0 : wren::math::Mat4f proj = wren::math::Mat4f::identity();
236 : };
237 0 : GLOBALS ubo{};
238 :
239 0 : ubo.view = this->camera_.transform().matrix();
240 0 : ubo.proj = this->camera_.projection();
241 :
242 : // pass.bind_pipeline("viewer");
243 :
244 : // pass.write_scratch_buffer(cmd, 0, 0, ubo);
245 :
246 : // cmd.draw(6, 1, 0, 0);
247 :
248 0 : pass.bind_pipeline("mesh");
249 0 : pass.write_scratch_buffer(cmd, 0, 0, ubo);
250 :
251 0 : render_query.each(
252 0 : [cmd, ctx, this](
253 : const wren::scene::components::Transform& transform,
254 : wren::scene::components::MeshRenderer& mesh_renderer) {
255 0 : mesh_renderer.bind(ctx, mesh_shader_, cmd,
256 0 : transform.matrix());
257 0 : });
258 0 : })
259 0 : .add_pass("ui", wren::PassResources("swapchain_target"),
260 0 : [](wren::RenderPass& pass, ::vk::CommandBuffer& cmd) {
261 0 : editor::ui::flush(cmd);
262 0 : });
263 :
264 0 : return builder;
265 0 : }
266 :
267 : } // namespace editor
|