VEX Engine
Retro looking game engine made in vulkan mostly because i wanted to understand it better.
Loading...
Searching...
No Matches
Editor.cpp
3#include "Editor.hpp"
4#include "components/UtilitySystem.hpp"
6
8#include "Tools/WorldSettingsMenu.hpp"
9#include "Tools/SceneMenu.hpp"
10
11#include <imgui.h>
12#include <imgui_internal.h>
13#include <glm/glm.hpp>
14#include <glm/gtc/type_ptr.hpp>
15#include <volk.h>
16#include <filesystem>
17#include <limits>
18
21#include "components/AssetTypes.hpp"
22#include "ImReflect.hpp"
23
27
29#include "components/EngineCommands.hpp"
33
34namespace vex {
35
36 Editor::Editor(const char* title, int width, int height, GameInfo gInfo, const std::string& projectBinaryPath) : Engine(SkipInit{}) {
37 std::filesystem::current_path(GetExecutableDir());
38 SetAssetRoot(projectBinaryPath);
39 m_gameInfo = gInfo;
40 if(m_gameInfo.versionMajor == 0 && m_gameInfo.versionMinor == 0 && m_gameInfo.versionPatch == 0){
41 log("Project version not set!");
42 }
43
44 log("Creating window..");
45 m_window = std::make_shared<Window>(title, width, height);
46 m_resolutionManager = std::make_unique<ResolutionManager>(m_window->GetSDLWindow());
47
48 #ifdef __linux__
49 const char* driver = SDL_GetCurrentVideoDriver();
50 if (driver && std::string(driver) == "wayland") {
51 m_isWayland = true;
52 log("Wayland detected: Enforcing Software VSync strategy.");
53 }
54 #endif
55
56 log("Initializing virtual file system..\nSwitching vfs path to: %s", projectBinaryPath.c_str());
57 m_vfs = std::make_shared<VirtualFileSystem>();
58 m_vfs->initialize(projectBinaryPath);
59
60 m_physicsSystem = std::make_unique<PhysicsSystem>(m_registry);
61 m_physicsSystem->init();
62
63 auto renderRes = m_resolutionManager->getRenderResolution();
64 log("Initializing Vulkan interface...");
65 m_interface = std::make_unique<Interface>(m_window->GetSDLWindow(), renderRes, m_gameInfo, m_vfs.get());
66 m_imgui = std::make_unique<EditorImGUIWrapper>(m_window->GetSDLWindow(), *m_interface->getContext());
67 m_imgui->init();
68
69 ImGui::GetIO().ConfigFlags &= ~ImGuiConfigFlags_ViewportsEnable;
70
71 vex::DebugConsole::Get().Init();
72
73 log("Initializing engine components...");
74
75 m_inputSystem = std::make_unique<InputSystem>(m_registry, m_window->GetSDLWindow());
76 m_sceneManager = std::make_unique<SceneManager>();
77
78 getInterface()->getMeshManager().init(static_cast<Engine*>(this));
79 setInputMode(InputMode::UI);
80
81 RegisterEngineCommands(this);
82
83 log("Initializing editor components...");
84
85 std::filesystem::path projectPath = projectBinaryPath;
86 std::filesystem::path assetsPath = projectPath / "Assets";
87 m_assetBrowser = std::make_unique<AssetBrowser>(assetsPath.string());
89
90 m_projectBinaryPath = projectBinaryPath;
91
92 m_camera = std::make_unique<EditorCameraObject>(*this, "VexEditorCamera", m_window->GetSDLWindow());
93 m_editorMenuBar = std::make_unique<EditorMenuBar>(*m_imgui, *this);
94
95 LoadConfig(m_editorProperties, "editor_config.json");
96 m_SavedEditorProperties = m_editorProperties;
97
98 setFrameLimit(m_editorProperties.frameLimit);
99 setVSync(m_editorProperties.vsync);
100
101 std::filesystem::path projectConfigPath = projectPath / "VexProject.json";
102 log("Loading project configuration from: %s", projectConfigPath.string().c_str());
103 LoadProjectConfig(m_projectProperties, projectConfigPath.string());
104 //m_SavedProjectProperties = m_projectProperties;
105
106 log("Editor initialized successfully");
107 }
108
110 auto& io = ImGui::GetIO();
111 bool ctrl = io.KeyCtrl;
112 bool shift = io.KeyShift;
113
114 if (ctrl && ImGui::IsKeyPressed(ImGuiKey_Z)) Undo();
115 if (ctrl && ImGui::IsKeyPressed(ImGuiKey_Y)) Redo();
116
117 if (ctrl && ImGui::IsKeyPressed(ImGuiKey_S)) {
118 if (shift) m_editorMenuBar->SaveSceneAs();
119 else {
120 std::string sceneName = vex::GetAssetPath(getSceneManager()->getLastSceneName());
121 getSceneManager()->GetScene(sceneName)->Save(sceneName);
122 log("Quick Saved Scene.");
123 }
124 }
125
126 if (ctrl && ImGui::IsKeyPressed(ImGuiKey_N)) m_editorMenuBar->NewScene();
127 if (ctrl && ImGui::IsKeyPressed(ImGuiKey_O)) m_editorMenuBar->OpenScene();
128
129 if (shift && ImGui::IsKeyPressed(ImGuiKey_Q)) m_currentGizmoOperation = (ImGuizmo::OPERATION)0;
130 if (shift && ImGui::IsKeyPressed(ImGuiKey_W)) m_currentGizmoOperation = ImGuizmo::TRANSLATE;
131 if (shift && ImGui::IsKeyPressed(ImGuiKey_E)) m_currentGizmoOperation = ImGuizmo::ROTATE;
132 if (shift && ImGui::IsKeyPressed(ImGuiKey_R)) m_currentGizmoOperation = ImGuizmo::SCALE;
133
134 if (shift && ImGui::IsKeyPressed(ImGuiKey_F)) {
135 if (m_selectedObject.second && m_camera && m_selectedObject.second->HasComponent<TransformComponent>()) {
136 auto& targetTC = m_selectedObject.second->GetComponent<TransformComponent>();
137 auto& camTC = m_camera->GetComponent<TransformComponent>();
138 glm::vec3 targetPos = targetTC.getWorldPosition();
139 glm::vec3 offset = camTC.getForwardVector() * -5.0f;
140 camTC.setWorldPosition(targetPos + offset);
141 }
142 }
143 }
144
146 if (m_undoStack.empty()) return;
147 m_undoStack.back()->Undo();
148 m_redoStack.push_back(std::move(m_undoStack.back()));
149 m_undoStack.pop_back();
150 }
151
153 if (m_redoStack.empty()) return;
154 m_redoStack.back()->Execute();
155 m_undoStack.push_back(std::move(m_redoStack.back()));
156 m_redoStack.pop_back();
157 }
158
160 if (!m_selectedObject.second) return;
161 m_clipboard.hasData = true;
162 if (m_selectedObject.second->HasComponent<NameComponent>()) {
163 m_clipboard.name = m_selectedObject.second->GetComponent<NameComponent>().name;
164 } else {
165 m_clipboard.name = "Unnamed";
166 }
167 m_clipboard.type = m_selectedObject.second->getObjectType();
168 m_clipboard.components.clear();
169
170 const auto& regNames = ComponentRegistry::getInstance().getRegisteredNames();
171 for (const auto& compName : regNames) {
172 nlohmann::json data = ComponentRegistry::getInstance().saveComponent(*m_selectedObject.second, compName);
173 if (!data.is_null()) m_clipboard.components[compName] = data;
174 }
175 }
176
178 if (!m_clipboard.hasData) return;
179 std::string newName = m_clipboard.name + " (Paste)";
180 GameObject* newObj = GameObjectFactory::getInstance().create(m_clipboard.type, *this, newName);
181 if (!newObj) return;
182
183 for (const auto& [name, data] : m_clipboard.components) {
184 ComponentRegistry::getInstance().loadComponent(*newObj, name, data);
185 }
186
187 getSceneManager()->GetScene(getSceneManager()->getLastSceneName())->AddEditorGameObject(newObj);
188
189 m_selectedObject.second = newObj;
190 m_selectedObject.first = true;
192 }
193
198
200 if (!m_selectedObject.second) return;
201
202 std::vector<GameObject*> toDelete = { m_selectedObject.second };
203 PushCommand(new DeleteCommand(*this, toDelete));
204
205 getSceneManager()->GetScene(getSceneManager()->getLastSceneName())->DestroyGameObject(m_selectedObject.second);
206
207 m_selectedObject.second = nullptr;
208 m_selectedObject.first = false;
210 }
211
212 void Editor::update(float deltaTime) {
213 if (!m_pendingSceneToLoad.empty() && !m_waitForGui) {
214 m_interface->WaitForGPUToFinish();
215 getSceneManager()->loadScene(m_pendingSceneToLoad, *this);
216 m_pendingSceneToLoad.clear();
217 m_waitForGui = true;
218 m_frame = 0;
219 m_undoStack.clear();
220 m_redoStack.clear();
221 }else if(!m_pendingSceneToLoad.empty() && m_waitForGui){
222 m_waitForGui = false;
223 }
224
225 std::filesystem::path projectPath = m_projectBinaryPath;
226 std::filesystem::path assetsPath = projectPath / "Assets";
227 if(!getSceneManager()->getLastSceneName().contains(assetsPath.string())){
228 requestSceneReload(GetAssetPath(getSceneManager()->getLastSceneName()));
229 }
230
231 m_fps = static_cast<int>(1.0f / deltaTime);
232
233 if(m_SavedEditorProperties != m_editorProperties || m_frame == 0){
234 SaveConfig(m_editorProperties, "editor_config.json");
235 m_SavedEditorProperties = m_editorProperties;
236
237 if (m_editorProperties.editorCameraFov < 10.0f) m_editorProperties.editorCameraFov = 10.0f;
238 if (m_editorProperties.editorCameraFov > 170.0f) m_editorProperties.editorCameraFov = 170.0f;
239
240 if (m_editorProperties.editorCameraRenderDistance < 0.1f) m_editorProperties.editorCameraRenderDistance = 0.1f;
241 if (m_editorProperties.editorCameraRenderDistance > 100000.0f) m_editorProperties.editorCameraRenderDistance = 100000.0f;
242
243 m_camera->GetComponent<vex::CameraComponent>().fov = m_editorProperties.editorCameraFov;
244 m_camera->GetComponent<vex::CameraComponent>().farPlane = m_editorProperties.editorCameraRenderDistance;
245
246 setFrameLimit(m_editorProperties.frameLimit);
247 setVSync(m_editorProperties.vsync);
248 }
249
250 if(m_SavedProjectProperties != m_projectProperties){
251 std::filesystem::path projectPath = m_projectBinaryPath;
252 std::filesystem::path projectConfigPath = projectPath / "VexProject.json";
253 SaveProjectConfig(m_projectProperties, projectConfigPath.string());
254 m_SavedProjectProperties = m_projectProperties;
255 }
256
257 if (auto* scene = getSceneManager()->GetScene(getSceneManager()->getLastSceneName())) {
258 scene->FlushDestructionQueue();
259 }
260
262 m_registry.remove<vex::EditorBillboardComponent>(entity);
263 });
264
265 auto addIcon = [&](vex::Entity entity, const char* path) {
266 auto& comp = m_registry.add_or_replace<vex::EditorBillboardComponent>(entity);
267 comp.texturePaths.emplace_back(path);
268 };
269
270 vex::View<vex::LightComponent>(m_registry).each([&](vex::Entity entity, vex::LightComponent& comp) { addIcon(entity, "../Assets/icons/lightbulb-fill.png"); });
271 vex::View<vex::ParticleEmitterComponent>(m_registry).each([&](vex::Entity entity, vex::ParticleEmitterComponent& comp) { addIcon(entity, "../Assets/icons/sparkling-fill.png"); });
272 vex::View<vex::FogComponent>(m_registry).each([&](vex::Entity entity, vex::FogComponent& comp) { addIcon(entity, "../Assets/icons/foggy-fill.png"); });
273 vex::View<vex::AudioSourceComponent>(m_registry).each([&](vex::Entity entity, vex::AudioSourceComponent& comp) { addIcon(entity, "../Assets/icons/file-music-fill.png"); });
274 m_camera->Update(deltaTime);
275 m_physicsSystem->SyncBodies();
276
277 vex::ProcessParticles(m_registry, deltaTime);
278
279 render();
280 if(!m_refresh){
281 m_frame = 1;
282 }else{
283 m_refresh = false;
284 }
285 }
286
287 void Editor::processEvent(const SDL_Event& event, float deltaTime) {
288 m_camera->processEvent(event, deltaTime);
289 }
290
292 auto cameraEntity = m_camera->GetEntity();
293 if (cameraEntity == vex::NULL_ENTITY) return;
294
297 }
298
299 if(getInputMode() != InputMode::UI){
300 setInputMode(InputMode::UI);
301 }
302
303 glm::uvec2 viewportRes = (m_viewportSize.x > 0 && m_viewportSize.y > 0)
304 ? m_viewportSize
305 : m_resolutionManager->getRenderResolution();
306
307 try {
308 SceneRenderData renderData{};
309 if (!m_interface->getRenderer().beginFrame(viewportRes, renderData)) {
310 return;
311 }
312 renderData.imguiTextureID = m_interface->getRenderer().getImGuiTextureID(*m_imgui);
313
314 const std::vector<DebugVertex>* debugLines = nullptr;
315 if(m_editorProperties.showCollisions){
316 auto* dbg = m_interface->getPhysicsDebug();
317 dbg->Clear();
318 m_physicsSystem->setDebugRenderer(dbg);
319 m_physicsSystem->drawDebug();
320 debugLines = &dbg->GetLines();
321 }
322
323 m_interface->getRenderer().renderScene(renderData, cameraEntity, m_registry, m_frame, debugLines, true);
324 m_imgui->beginFrame();
326 m_imgui->executeUIFunctions();
327
328 glm::uvec2 newRes = viewportRes;
329 drawEditorLayout(renderData, newRes);
330
331 if (newRes != m_viewportSize && newRes.x > 0 && newRes.y > 0) {
332 m_viewportSize = newRes;
333 }
334
335 if (showConsole) {
336 vex::DebugConsole::Get().Draw(&showConsole, true);
337 }
338
339 m_imgui->endFrame();
340 m_interface->getRenderer().composeFrame(renderData, *m_imgui, true);
341 m_interface->getRenderer().endFrame(renderData);
342
343 } catch (const std::exception& e) {
344 log(LogLevel::ERROR, "Editor render failed");
346 }
347 }
348
349 void Editor::requestSceneReload(const std::string& scenePath){
350 m_pendingSceneToLoad = scenePath;
351 m_selectedObject.first = false;
352 m_selectedObject.second = nullptr;
353 }
354
356 auto* resources = m_interface->getResources();
357 auto* vfs = m_vfs.get();
358 auto* vulkanGUI = static_cast<VulkanImGUIWrapper*>(m_imgui.get());
359 if (!vulkanGUI) {
360 log(LogLevel::ERROR, "Failed to cast ImGUI wrapper to VulkanImGUIWrapper");
361 return;
362 }
363 std::vector<std::pair<std::string, ImTextureID*>> targets = {
364 { "../Assets/icons/folder-fill.png", &m_icons.folder },
365 { "../Assets/icons/file-fill.png", &m_icons.file },
366 { "../Assets/icons/box-3-fill.png", &m_icons.mesh },
367 { "../Assets/icons/file-image-fill.png", &m_icons.texture },
368 { "../Assets/icons/map-2-fill.png", &m_icons.scene },
369 { "../Assets/icons/file-text-fill.png", &m_icons.text },
370 { "../Assets/icons/window-fill.png", &m_icons.ui },
371 { "../Assets/icons/file-music-fill.png", &m_icons.audio }
372 };
373
374 VkSampler sampler = resources->getTextureSampler();
375
376 for (auto& [path, targetPtr] : targets) {
377 std::string name = "editor_" + path;
378
379 try {
380 std::filesystem::path correctPath = GetExecutableDir() / path;
381 resources->loadTexture(correctPath.string(), name);
382
383 VkDescriptorSet ds = vulkanGUI->addTexture(
384 sampler,
385 resources->getTextureView(name),
386 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
387 );
388
389 *targetPtr = (ImTextureID)ds;
390
391 } catch (const std::exception& e) {
392 log(LogLevel::ERROR, "Failed to load icon: %s", path.c_str());
393 VkDescriptorSet ds = vulkanGUI->addTexture(
394 sampler,
395 resources->getTextureView("default"),
396 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
397 );
398 *targetPtr = (ImTextureID)ds;
399 }
400 }
401
402 vex::ComponentRegistry::getInstance().SetEditorIcon("mesh", m_icons.mesh);
403 vex::ComponentRegistry::getInstance().SetEditorIcon("texture", m_icons.texture);
404 vex::ComponentRegistry::getInstance().SetEditorIcon("audio", m_icons.audio);
405 vex::ComponentRegistry::getInstance().SetEditorIcon("file", m_icons.file);
406 }
407
408 void Editor::drawGizmo(const glm::vec2& viewportPos, const glm::vec2& viewportSize) {
409 m_isHoveringGizmoUI = false;
410
411 auto selectedEntity = m_selectedObject.second ? m_selectedObject.second->GetEntity() : vex::NULL_ENTITY;
412 if (selectedEntity == vex::NULL_ENTITY || !m_registry.has<TransformComponent>(selectedEntity)) return;
413
414 ImGuizmo::SetOrthographic(false);
415 ImGuizmo::SetDrawlist();
416 ImGuizmo::SetRect(viewportPos.x, viewportPos.y, viewportSize.x, viewportSize.y);
417
418
419 auto& camTC = m_registry.get<TransformComponent>(m_camera->GetEntity());
420 auto& camComp = m_registry.get<CameraComponent>(m_camera->GetEntity());
421
422 glm::mat4 view = glm::lookAt(
423 camTC.getWorldPosition(),
424 camTC.getWorldPosition() + camTC.getForwardVector(),
425 camTC.getUpVector()
426 );
427
428 float aspect = viewportSize.x / viewportSize.y;
429 glm::mat4 proj = glm::perspective(glm::radians(camComp.fov), aspect, camComp.nearPlane, camComp.farPlane);
430
431 auto& tc = m_registry.get<TransformComponent>(selectedEntity);
432 glm::mat4 transformMatrix = tc.matrix();
433
434 ImGui::SetCursorScreenPos(ImVec2(viewportPos.x + 10, viewportPos.y + 32));
435
436 auto gizmoButton = [&](const char* label, ImGuizmo::OPERATION op) {
437 bool wasActive = (m_currentGizmoOperation == op);
438 if (wasActive) ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1.00f, 0.23f, 0.01f, 1.0f));
439 if (ImGui::Button(label)) m_currentGizmoOperation = op;
440 if (wasActive) ImGui::PopStyleColor();
441 if (ImGui::IsItemHovered()) m_isHoveringGizmoUI = true;
442 ImGui::SameLine();
443 };
444
445 gizmoButton("T", ImGuizmo::TRANSLATE);
446 gizmoButton("R", ImGuizmo::ROTATE);
447 gizmoButton("S", ImGuizmo::SCALE);
448
449 ImGui::Dummy(ImVec2(10, 0)); ImGui::SameLine();
450
451 if(m_currentGizmoMode == ImGuizmo::WORLD) {
452 if(ImGui::Button("World")) m_currentGizmoMode = ImGuizmo::LOCAL;
453 } else {
454 if(ImGui::Button("Local")) m_currentGizmoMode = ImGuizmo::WORLD;
455 }
456
457 if (ImGui::IsKeyPressed(ImGuiKey_LeftCtrl)) m_useSnap = true;
458 else if (ImGui::IsKeyReleased(ImGuiKey_LeftCtrl)) m_useSnap = false;
459
460 float snap[3] = { 0.f, 0.f, 0.f };
461 if(m_useSnap) {
462 if (m_currentGizmoOperation == ImGuizmo::TRANSLATE) { snap[0] = snap[1] = snap[2] = 0.5f; }
463 else if (m_currentGizmoOperation == ImGuizmo::ROTATE) { snap[0] = 45.0f; }
464 else if (m_currentGizmoOperation == ImGuizmo::SCALE) { snap[0] = snap[1] = snap[2] = 0.1f; }
465 }
466
467 bool manipulated = ImGuizmo::Manipulate(
468 glm::value_ptr(view),
469 glm::value_ptr(proj),
470 m_currentGizmoOperation,
471 m_currentGizmoMode,
472 glm::value_ptr(transformMatrix),
473 nullptr,
474 m_useSnap ? snap : nullptr
475 );
476
477 bool isUsing = ImGuizmo::IsUsing();
478
479 if (isUsing && !m_gizmoWasUsing) {
480 m_gizmoStartPos = tc.getLocalPosition();
481 m_gizmoStartRot = tc.rotation;
482 m_gizmoStartScale = tc.getLocalScale();
483 }
484
485 if (!isUsing && m_gizmoWasUsing) {
486 if (tc.getLocalPosition() != m_gizmoStartPos ||
487 tc.rotation != m_gizmoStartRot ||
488 tc.getLocalScale() != m_gizmoStartScale)
489 {
491 m_selectedObject.second,
492 m_gizmoStartPos, m_gizmoStartRot, m_gizmoStartScale,
493 tc.getLocalPosition(), tc.rotation, tc.getLocalScale()
494 ));
495 }
496 }
497 m_gizmoWasUsing = isUsing;
498
499 if (manipulated) {
500 glm::mat4 localMatrix = transformMatrix;
501
502 vex::Entity parent = tc.getParent();
503 if (parent != vex::NULL_ENTITY && m_registry.has<vex::TransformComponent>(parent) && m_registry.has<TransformComponent>(parent)) {
504 glm::mat4 parentMatrix = m_registry.get<TransformComponent>(parent).matrix();
505 localMatrix = glm::inverse(parentMatrix) * transformMatrix;
506 }
507
508 glm::vec3 translation, scale, skew;
509 glm::quat rotation;
510 glm::vec4 perspective;
511 glm::decompose(localMatrix, scale, rotation, translation, skew, perspective);
512
513 tc.setLocalPosition(translation);
514 tc.setLocalScale(scale);
515
516 tc.rotation = glm::degrees(glm::eulerAngles(rotation));
517 tc.convertRot();
518
519 tc.enableLastTransformed();
520 }
521 }
522
523 float Editor::raySphereIntersect(const glm::vec3& rayOrigin, const glm::vec3& rayDir, const glm::vec3& sphereCenter, float sphereRadius) {
524 glm::vec3 l = sphereCenter - rayOrigin;
525 float tca = glm::dot(l, rayDir);
526 if (tca < 0) return -1.0f;
527 float d2 = glm::dot(l, l) - tca * tca;
528 float radius2 = sphereRadius * sphereRadius;
529 if (d2 > radius2) return -1.0f;
530 float thc = sqrt(radius2 - d2);
531 return tca - thc;
532 }
533
535 const glm::vec3& rayOrigin, const glm::vec3& rayDir,
536 const glm::vec3& v0, const glm::vec3& v1, const glm::vec3& v2)
537 {
538 const float epsilon = 0.0000001f;
539 glm::vec3 edge1 = v1 - v0;
540 glm::vec3 edge2 = v2 - v0;
541 glm::vec3 h = glm::cross(rayDir, edge2);
542 float a = glm::dot(edge1, h);
543
544 if (a > -epsilon && a < epsilon) return -1.0f;
545
546 float f = 1.0f / a;
547 glm::vec3 s = rayOrigin - v0;
548 float u = f * glm::dot(s, h);
549 if (u < 0.0f || u > 1.0f) return -1.0f;
550
551 glm::vec3 q = glm::cross(s, edge1);
552 float v = f * glm::dot(rayDir, q);
553 if (v < 0.0f || u + v > 1.0f) return -1.0f;
554
555 float t = f * glm::dot(edge2, q);
556 if (t > epsilon) return t;
557 else return -1.0f;
558 }
559
560 void Editor::ExtractObjectByEntity(vex::Entity entity, std::pair<bool, vex::GameObject*>& selectedObject){
561 auto* obj = getSceneManager()->GetScene(getSceneManager()->getLastSceneName())->GetGameObjectByEntity(entity);
562 if(obj){
563 if (obj->HasComponent<TransformComponent>() && obj->GetComponent<TransformComponent>().getParent() != vex::NULL_ENTITY) {
564 ExtractObjectByEntity(obj->GetComponent<TransformComponent>().getParent(), selectedObject);
565 }else{
566 selectedObject.first = false;
567 selectedObject.second = obj;
568 }
569 }
570 }
571
572 void Editor::HandleMeshDrop(const std::string& filepath, vex::Entity parent) {
573 std::filesystem::path path(filepath);
574 std::string filename = path.stem().string();
575
576 vex::GameObject* newObj = vex::GameObjectFactory::getInstance().create("GameObject", *this, filename);
577 if (!newObj) return;
578
580
581 if (parent != vex::NULL_ENTITY) {
582 newObj->GetComponent<vex::TransformComponent>().setParent(parent);
583 }
584
585 std::filesystem::path absPath = filepath;
586 std::filesystem::path assetDir = GetAssetDir();
587
588 std::filesystem::path relative = absPath.lexically_relative(assetDir);
589
590 std::string relativePath = relative.generic_string();
591
592 vex::MeshComponent meshComp = vex::createMeshFromPath(relativePath, *this);
593
594 newObj->AddComponent(meshComp);
595
596 getSceneManager()->GetScene(getSceneManager()->getLastSceneName())->AddEditorGameObject(newObj);
597
598 newObj->BeginPlay();
600
601 vex::log("Instantiated mesh from: %s", filepath.c_str());
602 }
603
604 void Editor::drawEditorLayout(const SceneRenderData& data, glm::uvec2& outNewResolution) {
605 ImGuiViewport* viewport = ImGui::GetMainViewport();
606 ImGui::SetNextWindowPos(viewport->Pos);
607 ImGui::SetNextWindowSize(viewport->Size);
608 ImGui::SetNextWindowViewport(viewport->ID);
609
610 ImGuiWindowFlags windowFlags = ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoTitleBar |
611 ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize |
612 ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoBringToFrontOnFocus |
613 ImGuiWindowFlags_NoNavFocus | ImGuiWindowFlags_NoBackground |
614 ImGuiWindowFlags_MenuBar;
615
616 ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
617 ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
618 ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
619
620 ImGui::Begin("EditorDockSpace", nullptr, windowFlags);
621 ImGui::PopStyleVar(3);
622
623 m_editorMenuBar->DrawBar();
624
625 ImGuiID dockspaceId = ImGui::GetID("MyDockSpace");
626
627 ImGuiDockNodeFlags dockFlags = ImGuiDockNodeFlags_None;
628 dockFlags |= ImGuiDockNodeFlags_NoWindowMenuButton;
629
630 if (!ImGui::DockBuilderGetNode(dockspaceId)) {
631 ImGui::DockBuilderRemoveNode(dockspaceId);
632 ImGui::DockBuilderAddNode(dockspaceId, ImGuiDockNodeFlags_DockSpace);
633 ImGui::DockBuilderSetNodeSize(dockspaceId, viewport->Size);
634
635 ImGuiID dockMainId = dockspaceId;
636 ImGuiID dockRightId = ImGui::DockBuilderSplitNode(dockMainId, ImGuiDir_Right, 0.3f, nullptr, &dockMainId);
637 ImGuiID dockBottomId = ImGui::DockBuilderSplitNode(dockMainId, ImGuiDir_Down, 0.45f, nullptr, &dockMainId);
638 ImGuiID dockLeftId = ImGui::DockBuilderSplitNode(dockMainId, ImGuiDir_Left, 0.2f, nullptr, &dockMainId);
639 ImGuiID dockRightTopId, dockRightBottomId;
640 ImGui::DockBuilderSplitNode(dockRightId, ImGuiDir_Down, 0.5f, &dockRightBottomId, &dockRightTopId);
641
642 ImGui::DockBuilderDockWindow("Viewport", dockMainId);
643 ImGui::DockBuilderDockWindow("Game Objects", dockLeftId);
644 ImGui::DockBuilderDockWindow("Assets", dockBottomId);
645 ImGui::DockBuilderDockWindow("Scene", dockRightTopId);
646 ImGui::DockBuilderDockWindow("Properties", dockRightBottomId);
647 ImGui::DockBuilderDockWindow("World Settings", dockRightBottomId);
648
649 ImGui::DockBuilderFinish(dockspaceId);
650 }
651
652 ImGui::DockSpace(dockspaceId, ImVec2(0.0f, 0.0f), dockFlags);
653 ImGui::End();
654
655 ImGuiWindowFlags childFlags = ImGuiWindowFlags_NoCollapse;
656
657 ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0));
658 ImGui::Begin("Viewport", nullptr, childFlags);
659
660 if (m_camera) {
661 m_camera->setViewportHovered(ImGui::IsWindowHovered());
662 }
663
664 ImVec2 viewportPanelSize = ImGui::GetContentRegionAvail();
665 ImVec2 viewportPos = ImGui::GetWindowPos();
666 ImVec2 cursorScreenPos = ImGui::GetCursorScreenPos();
667
668 outNewResolution = { (uint32_t)viewportPanelSize.x, (uint32_t)viewportPanelSize.y };
669
670 if (data.imguiTextureID) {
671 ImGui::Image((ImTextureID)data.imguiTextureID, viewportPanelSize);
672 bool isViewportHovered = ImGui::IsItemHovered();
673 auto* drawList = ImGui::GetWindowDrawList();
674
675 if(m_editorProperties.showFPS) {
676 char fpsText[32];
677 sprintf(fpsText, "FPS: %d", m_fps);
678
679 ImU32 fpsColor;
680 if (m_fps >= 60) {
681 fpsColor = IM_COL32(0, 255, 0, 255);
682 } else if (m_fps >= 30) {
683 fpsColor = IM_COL32(255, 255, 0, 255);
684 } else {
685 fpsColor = IM_COL32(255, 0, 0, 255);
686 }
687
688 ImVec2 textPos = ImVec2(cursorScreenPos.x + 10.0f, cursorScreenPos.y + 64.0f);
689 drawList->AddText(ImVec2(textPos.x + 1.0f, textPos.y + 1.0f), IM_COL32(0, 0, 0, 255), fpsText);
690 drawList->AddText(textPos, fpsColor, fpsText);
691 }
692
693 std::string currentScenePath = getSceneManager()->getLastSceneName();
694 std::string sceneName = std::filesystem::path(currentScenePath).stem().string();
695
696 if (sceneName.empty()) sceneName = "Unnamed Scene";
697
698 ImVec2 iconSize = ImVec2(16.0f, 16.0f);
699 ImVec2 padding = ImVec2(8.0f, 6.0f);
700 float iconTextSpacing = 6.0f;
701
702 ImVec2 textSize = ImGui::CalcTextSize(sceneName.c_str());
703 float rectWidth = padding.x + iconSize.x + iconTextSpacing + textSize.x + padding.x;
704 float rectHeight = padding.y + std::max(iconSize.y, textSize.y) + padding.y;
705
706 ImVec2 rectMin = cursorScreenPos;
707 ImVec2 rectMax = ImVec2(rectMin.x + rectWidth, rectMin.y + rectHeight);
708
709 ImU32 bgColor = IM_COL32(20, 20, 20, 220);
710 drawList->AddRectFilled(rectMin, rectMax, bgColor, 12.0f, ImDrawFlags_RoundCornersBottomRight);
711
712 ImVec2 iconMin = ImVec2(rectMin.x + padding.x, rectMin.y + padding.y + std::max(0.0f, (textSize.y - iconSize.y) / 2.0f));
713 ImVec2 iconMax = ImVec2(iconMin.x + iconSize.x, iconMin.y + iconSize.y);
714
715 if (m_icons.scene) {
716 drawList->AddImage(m_icons.scene, iconMin, iconMax);
717 }
718
719 ImVec2 textPos = ImVec2(iconMax.x + iconTextSpacing, rectMin.y + padding.y + std::max(0.0f, (iconSize.y - textSize.y) / 2.0f));
720 drawList->AddText(textPos, IM_COL32(255, 255, 255, 255), sceneName.c_str());
721
722 if (ImGui::BeginDragDropTarget()) {
723 if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("ASSET_ITEM")) {
724 std::string filepath = (const char*)payload->Data;
725 std::filesystem::path path(filepath);
726 std::string ext = path.extension().string();
727
728 if (AssetExtensions::IsValid(ext, AssetExtensions::Mesh)) {
730 }
731 }
732 ImGui::EndDragDropTarget();
733 }
734
735 drawGizmo(glm::vec2(cursorScreenPos.x, cursorScreenPos.y),
736 glm::vec2(viewportPanelSize.x, viewportPanelSize.y));
737
738 if (isViewportHovered && !m_isHoveringGizmoUI && ImGui::IsMouseClicked(ImGuiMouseButton_Left) && !ImGuizmo::IsOver()) {
739 ImVec2 mousePos = ImGui::GetMousePos();
740 float mouseX = mousePos.x - viewportPos.x;
741 float mouseY = mousePos.y - viewportPos.y;
742
743 float ndcX = (mouseX / viewportPanelSize.x) * 2.0f - 1.0f;
744 float ndcY = (mouseY / viewportPanelSize.y) * 2.0f - 1.0f;
745
746 auto& camTC = m_registry.get<TransformComponent>(m_camera->GetEntity());
747 auto& camComp = m_registry.get<CameraComponent>(m_camera->GetEntity());
748
749 glm::mat4 view = glm::lookAt(camTC.getWorldPosition(), camTC.getWorldPosition() + camTC.getForwardVector(), camTC.getUpVector());
750 glm::mat4 proj = glm::perspective(glm::radians(camComp.fov), viewportPanelSize.x / viewportPanelSize.y, camComp.nearPlane, camComp.farPlane);
751 proj[1][1] *= -1; // Vulkan Y-Flip
752
753 glm::mat4 invProjView = glm::inverse(proj * view);
754
755 glm::vec4 rayStartClip = glm::vec4(ndcX, ndcY, 0.0f, 1.0f);
756 glm::vec4 rayStartWorld = invProjView * rayStartClip;
757 rayStartWorld /= rayStartWorld.w;
758
759 glm::vec4 rayEndClip = glm::vec4(ndcX, ndcY, 1.0f, 1.0f);
760 glm::vec4 rayEndWorld = invProjView * rayEndClip;
761 rayEndWorld /= rayEndWorld.w;
762
763 glm::vec3 rayDir = glm::normalize(glm::vec3(rayEndWorld) - glm::vec3(rayStartWorld));
764 glm::vec3 rayOrigin = glm::vec3(rayStartWorld);
765
766 float closestDist = std::numeric_limits<float>::max();
767 vex::Entity hitEntity = vex::NULL_ENTITY;
768
770 if (raySphereIntersect(rayOrigin, rayDir, mesh.worldCenter, mesh.worldRadius) < 0.0f) {
771 return;
772 }
773
774 glm::mat4 modelMat = transform.matrix();
775 glm::mat4 invModel = glm::inverse(modelMat);
776
777 glm::vec4 localOrigin4 = invModel * glm::vec4(rayOrigin, 1.0f);
778 glm::vec3 localOrigin = glm::vec3(localOrigin4) / localOrigin4.w;
779 glm::vec3 localDir = glm::vec3(invModel * glm::vec4(rayDir, 0.0f));
780 localDir = glm::normalize(localDir);
781
782 float localClosest = std::numeric_limits<float>::max();
783 bool hitMesh = false;
784
785 for (const auto& submesh : mesh.meshData.submeshes) {
786 for (size_t i = 0; i < submesh.indices.size(); i += 3) {
787 const auto& v0 = submesh.vertices[submesh.indices[i]].position;
788 const auto& v1 = submesh.vertices[submesh.indices[i+1]].position;
789 const auto& v2 = submesh.vertices[submesh.indices[i+2]].position;
790
791 float t = rayTriangleIntersect(localOrigin, localDir, v0, v1, v2);
792
793 if (t > 0.0f && t < localClosest) {
794 localClosest = t;
795 hitMesh = true;
796 }
797 }
798 }
799
800 if (hitMesh) {
801 glm::vec3 hitPointLocal = localOrigin + (localDir * localClosest);
802 glm::vec3 hitPointWorld = glm::vec3(modelMat * glm::vec4(hitPointLocal, 1.0f));
803
804 float dist = glm::distance(rayOrigin, hitPointWorld);
805
806 if (dist < closestDist) {
807 closestDist = dist;
808 hitEntity = entity;
809 }
810 }
811 });
812 if (hitEntity != vex::NULL_ENTITY) {
813 ExtractObjectByEntity(hitEntity, m_selectedObject);
814
815 log("Selected Entity ID: %d", (uint32_t)hitEntity);
816 } else {
817 m_selectedObject.first = false;
818 m_selectedObject.second = nullptr;
819 }
820 }else{
821 //log("Item hovered: %d\nMouse Clicked: %d\nImGuizmo Over: %d", ImGui::IsItemHovered(), ImGui::IsMouseClicked(ImGuiMouseButton_Left), ImGuizmo::IsOver());
822 }
823 }else {
824 ImGui::Text("Viewport Texture Could not be retrieved.");
825 }
826
827 ImGui::End();
828 ImGui::PopStyleVar();
829
830 ImGui::Begin("Game Objects", nullptr, childFlags);
831 std::vector<std::string> engineTypes = GameObjectFactory::getInstance().GetNonDynamicRegisteredObjectTypes();
832
833 ImGui::Dummy(ImVec2(5.0f, 5.0f));
834 ImGui::Text("Engine Objects:");
835 ImGui::Separator();
836
837 for (const auto& type : engineTypes) {
838 if (ImGui::Button(type.c_str(), ImVec2(-1, 0))) {
839 std::string currentScene = getSceneManager()->getLastSceneName();
840 if (!currentScene.empty()) {
841
842 std::string newName = "New " + type;
843 GameObject* newObj = GameObjectFactory::getInstance().create(type, *this, newName);
844
845 if(m_selectedObject.second){
847 newObj->ParentTo(m_selectedObject.second->GetEntity());
848 }
849
850 m_frame = 0;
851 m_refresh = true;
852 newObj->BeginPlay();
853
854 if (newObj) {
855 getSceneManager()->GetScene(currentScene)->AddEditorGameObject(newObj);
856 }
857 } else {
858 log(LogLevel::ERROR, "No scene loaded. Cannot create object.");
859 }
860 }
861 }
862
863 std::vector<std::string> dynamicTypes = GameObjectFactory::getInstance().GetDynamicRegisteredObjectTypes();
864
865 ImGui::Dummy(ImVec2(10.0f, 10.0f));
866 ImGui::Text("Game Objects:");
867 ImGui::Separator();
868
869 for (const auto& type : dynamicTypes) {
870 if (ImGui::Button(type.c_str(), ImVec2(-1, 0))) {
871 std::string currentScene = getSceneManager()->getLastSceneName();
872 if (!currentScene.empty()) {
873
874 std::string newName = "New " + type;
875 GameObject* newObj = GameObjectFactory::getInstance().create(type, *this, newName);
876
877 if(m_selectedObject.second){
879 newObj->ParentTo(m_selectedObject.second->GetEntity());
880 }
881
882 m_frame = 0;
883 m_refresh = true;
884 newObj->BeginPlay();
885
886 if (newObj) {
887 getSceneManager()->GetScene(currentScene)->AddEditorGameObject(newObj);
888 }
889 } else {
890 log(LogLevel::ERROR, "No scene loaded. Cannot create object.");
891 }
892 }
893 }
894 ImGui::End();
895
896 ImGui::Begin("Assets", nullptr, childFlags);
897
898 m_isAssetBrowserFocused = ImGui::IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows);
899
900 if (m_assetBrowser) {
901 std::string openedFile = m_assetBrowser->Draw(m_icons, m_editorProperties.assetBrowserThumbnailSize);
902
903 if (!openedFile.empty()) {
904 log("Opening file: %s", openedFile.c_str());
905 if (m_assetBrowser->GetExtension(openedFile) == ".json") {
906 if (m_assetBrowser->GetJSONAssetType(openedFile) == 1){
907 requestSceneReload(openedFile);
908 }
909 }
910 }
911 }else{
912 ImGui::Text("Could not load assets");
913 }
914 ImGui::End();
915
916 ImGui::Begin("Scene", nullptr, childFlags);
917 DrawSceneHierarchy(*this, m_selectedObject);
918 ImGui::End();
919
920 ImGui::Begin("Properties", nullptr, childFlags);
921 if(m_selectedObject.second){
922 DrawPropertiesOfAnObject(m_selectedObject.second, m_selectedObject.first);
923 }
924 ImGui::End();
925
926 ImGui::Begin("World Settings", nullptr, childFlags);
927 DrawWorldSettings(*this);
928 ImGui::End();
929
930 if (!m_pendingSceneToLoad.empty() || m_pendingSceneToLoad != "") {
931
932 if (ImGui::Begin("Opening scene...", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
933 ImGui::Text("Loading scene: %s", m_pendingSceneToLoad.c_str());
934 }
935 ImGui::End();
936 }
937 }
938
940 log("Hot Reload detected: Deselecting objects and reloading scene...");
941
942 m_selectedObject.first = false;
943 m_selectedObject.second = nullptr;
944
945 if (getSceneManager() && !getSceneManager()->getLastSceneName().empty()) {
946 requestSceneReload(getSceneManager()->getLastSceneName());
947 }
948 }
949}
Defines the AudioSourceComponent struct.
Contains basic components like transform, camera, name components..
Simple 2D quad rendered in 3d space exclusevely for editor.
A specialized ImGUI wrapper for the editor, inheriting from VulkanImGUIWrapper.
The main Editor class, inheriting from Engine and providing editor-specific functionality and UI.
This file defines InputSystem class.
This file defines interface Class for vulkan backend.
This file defines functions for creating model objects and mesh components.
Utility function for drawing the component properties inspector for a selected GameObject.
void DrawPropertiesOfAnObject(vex::GameObject *object, bool temporary)
Draws the properties panel for a given GameObject, including its name and all components.
This file defines Renderer Class.
This file defines ResolutionManager class and ResolutionMode struct.
This file defines SceneManager class.
Utility functions for drawing the Scene Hierarchy and related object manipulation logic.
void DrawSceneHierarchy(vex::Engine &engine, std::pair< bool, vex::GameObject * > &selectedObject)
Draws the full scene hierarchy tree in an ImGUI window, handling selection, context menus,...
This file defines class with Imgui for vulkan backend definition.
This file defines Window class.
Saves Delete action command.
void processEvent(const SDL_Event &event, float deltaTime) override
Overrides the Engine's processEvent function to handle editor-specific events (e.g....
Definition Editor.cpp:287
void LoadConfig(EditorProperties &data, const std::string &filename)
Loads the EditorProperties configuration from a JSON file.
Definition Editor.hpp:191
void LoadProjectConfig(ProjectProperties &data, const std::string &filename)
Loads the ProjectProperties configuration from a JSON file.
Definition Editor.hpp:223
void Undo()
Undoes the last action performed in the editor.
Definition Editor.cpp:145
void PushCommand(ICommand *cmd)
Pushes a command onto the undo stack and clears the redo stack.
Definition Editor.hpp:242
void DeleteSelectedObject()
Deletes the selected object from the scene.
Definition Editor.cpp:199
float raySphereIntersect(const glm::vec3 &rayOrigin, const glm::vec3 &rayDir, const glm::vec3 &sphereCenter, float sphereRadius)
Performs a ray-sphere intersection test.
Definition Editor.cpp:523
void refreshForObject() override
Overrides the base Engine function to trigger a frame and refresh.
Definition Editor.hpp:94
void SaveProjectConfig(const ProjectProperties &data, const std::string &filename)
Saves the current ProjectProperties configuration to a JSON file.
Definition Editor.hpp:210
void drawEditorLayout(const SceneRenderData &data, glm::uvec2 &outNewResolution)
Helper to draw the ImGUI dockspace and viewport window for the editor.
Definition Editor.cpp:604
void drawGizmo(const glm::vec2 &viewportPos, const glm::vec2 &viewportSize)
Draws the ImGuizmo for the currently selected object.
Definition Editor.cpp:408
void CopySelectedObject()
Copies the selected object to the clipboard.
Definition Editor.cpp:159
void Redo()
Redoes the last undone action in the editor.
Definition Editor.cpp:152
void OnHotReload()
Handler for post-hot-reload operations.
Definition Editor.cpp:939
void render() override
Overrides the Engine's render function to inject the Editor UI logic (dockspace, viewport,...
Definition Editor.cpp:291
void SaveConfig(const EditorProperties &data, const std::string &filename)
Saves the current EditorProperties configuration to a JSON file.
Definition Editor.hpp:178
void HandleMeshDrop(const std::string &filepath, vex::Entity parent=vex::NULL_ENTITY)
Handles the dropping of a mesh asset.
Definition Editor.cpp:572
void ExtractObjectByEntity(vex::Entity entity, std::pair< bool, vex::GameObject * > &selectedObject)
Retrieves the GameObject corresponding to a given entity ID and updates the selected object pair.
Definition Editor.cpp:560
void DuplicateSelectedObject()
Duplicates the selected object in the scene.
Definition Editor.cpp:194
Editor(const char *title, int width, int height, GameInfo gInfo, const std::string &projectBinaryPath)
Constructs the Editor.
Definition Editor.cpp:36
void ProcessEditorShortcuts()
Processes editor shortcuts.
Definition Editor.cpp:109
float rayTriangleIntersect(const glm::vec3 &rayOrigin, const glm::vec3 &rayDir, const glm::vec3 &v0, const glm::vec3 &v1, const glm::vec3 &v2)
Performs a ray-triangle intersection test (using the Möller–Trumbore algorithm).
Definition Editor.cpp:534
void PasteObjectToScene()
Pastes the object from the clipboard to the scene.
Definition Editor.cpp:177
void requestSceneReload(const std::string &scenePath)
Requests a scene reload with a specific path. The reload is typically executed in the main update loo...
Definition Editor.cpp:349
void loadAssetIcons()
Loads the texture icons used for the Asset Browser and other UI elements.
Definition Editor.cpp:355
void update(float deltaTime) override
Overrides the Engine's update function to handle editor-specific logic.
Definition Editor.cpp:212
void setInputMode(InputMode mode)
Function allowing for changing input mode at runtime.
Definition Engine.hpp:126
SceneManager * getSceneManager()
Returns pointer to SceneManager.
Definition Engine.cpp:102
Interface * getInterface()
Returns Interface, used internally.
Definition Engine.cpp:106
InputMode getInputMode() const
Returns the current input mode.
Definition Engine.hpp:130
void setFrameLimit(int fps)
Sets the target frame rate limit.
Definition Engine.cpp:203
void setResolutionMode(ResolutionMode mode)
Sets the resolution mode and updates the resolution manager.
Definition Engine.cpp:238
ResolutionMode getResolutionMode() const
Returns the current resolution mode.
Definition Engine.hpp:118
Engine(const char *title, int width, int height, GameInfo gInfo)
Constructor for the Engine class.
Definition Engine.cpp:46
void setVSync(bool enabled)
Toggles VSync (Vertical Synchronization).
Definition Engine.cpp:207
GameObject * create(const std::string &type, Engine &engine, const std::string &name)
Create a GameObject instance of the specified type string.
static GameObjectFactory & getInstance()
Get the singleton instance of the GameObjectFactory.
std::vector< std::string > GetDynamicRegisteredObjectTypes()
Get all dynamic registered object types.
std::vector< std::string > GetNonDynamicRegisteredObjectTypes()
Get all non-dynamic registered object types.
Its base class for all game objects, eg. Player, Enemy, Weapon. Your Class needs to inherit from it.
virtual void BeginPlay()
virtual void function you override to implement custom behavior when the game starts.
void ParentTo(vex::Entity entity)
Function that parent this Object to another GameObject. You need to pass another GameObject's entity.
T & GetComponent()
Function that returns reference to a requested component.
void AddComponent(const T &comp)
Function that adds a component to the GameObject.
MeshManager & getMeshManager()
Getter for MeshManager.
Definition Interface.hpp:71
void init(Engine *engine)
Initialize the MeshManager.
void loadScene(const std::string &path, Engine &engine)
Unloads all current scenes and loads a new one from a file.
Scene * GetScene(const std::string &scene) const
Safely retrieves a pointer to a specific Scene.
std::string getLastSceneName() const
Function to get last scene name.
GameObject * GetGameObjectByEntity(vex::Entity &entity)
Function to get a game object by its entity ID.
Definition Scene.cpp:332
void AddEditorGameObject(GameObject *gameObject)
Promotes a temporary GameObject (e.g., created by the Editor) to a persistent Scene object.
Definition Scene.cpp:456
void Save(const std::string &outputPath)
Saves the current state of the scene to a JSON file.
Definition Scene.cpp:346
void DestroyGameObject(GameObject *gameObject)
Marks a game object for destruction.
Definition Scene.cpp:267
Gizmo Movement Command.
Provides iteration over entities that have all specified component types.
Definition View.hpp:17
void each(Func func)
Iterates over all entities with the specified component types.
Definition View.hpp:40
Class with Imgui for vulkan backend definition, inheriting from ImGUIWrapper.
std::string VEX_EXPORT GetAssetDir()
Gets the current asset directory override.
Definition PathUtils.cpp:29
uint32_t Entity
Type alias representing a unique entity identifier in the ECS system.
Definition Types.hpp:11
MeshComponent createMeshFromPath(const std::string &path, Engine &engine)
Just creates meshcomponent from file. Copies meshData and texture paths for later backend specific pr...
std::filesystem::path VEX_EXPORT GetExecutableDir()
Retrieves the directory containing the current executable.
Definition PathUtils.cpp:37
@ NATIVE
Use window resolution.
void VEX_EXPORT SetAssetRoot(const std::string &projectPath)
Overrides the default asset root directory.
Definition PathUtils.cpp:18
void DrawWorldSettings(Engine &engine)
Draws the world settings menu, allowing modification of environment parameters like shading,...
void VEX_EXPORT log(const char *fmt,...)
Logs a formatted message.
void VEX_EXPORT handle_critical_exception(const std::exception &e)
Handles a critical exception, forcing termination.
std::string VEX_EXPORT GetAssetPath(const std::string &relativePath)
Resolves the absolute path of an asset based on the current build configuration.
Definition PathUtils.cpp:73
constexpr Entity NULL_ENTITY
Special entity value indicating an invalid or null entity.
Definition Types.hpp:15
void ProcessParticles(vex::Registry &registry, float deltaTime)
Processes CPU-side particle simulation and prepares GPU data.
Struct that contains camera properties. Used by build in CameraObject, but needed for any custom one ...
A component for rendering a 2D quad that always faces the camera.
std::vector< vex::texture_asset_path > texturePaths
Paths to the textures mapped onto the billboard.
Struct containing fog properties.
this struct contains information about the game. like project name and version.
Definition GameInfo.hpp:15
Struct containing light properties.
Struct containing raw meshData, mesh id, texture paths and material properties. It just template and ...
Struct that simply contains name of the entity. It is used to identify entity and needs to be unique.
Component that emits and manages a system of particles.
Data structure to pass state between render stages.
Definition Renderer.hpp:57
Struct containing transform data and methods.
vex::Entity getParent() const
Get the parent entity.
glm::mat4 matrix(bool forceRecalculate=false)
Method used by renderer to calculate the transformation matrix.
glm::vec3 getWorldPosition()
Method to get world position, needed when object is parented as position parameter stores local posit...
void setWorldPosition(glm::vec3 newPosition)
Method to set world position, needed when object is parented as position parameter stores local posit...