From 1c38d93304dac6cd269a6f2e502ead957dadd164 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tur=C3=A1nszki=20J=C3=A1nos?= Date: Fri, 17 May 2024 08:04:05 +0200 Subject: [PATCH] Editor gui v2 (#843) --- Editor/AnimationWindow.cpp | 4 +- Editor/ArmatureWindow.cpp | 4 +- Editor/CMakeLists.txt | 1 - Editor/CameraComponentWindow.cpp | 2 +- Editor/CameraWindow.cpp | 12 +- Editor/ColliderWindow.cpp | 2 +- Editor/ComponentsWindow.cpp | 465 +++++- Editor/ComponentsWindow.h | 49 + Editor/ContentBrowserWindow.cpp | 25 +- Editor/DecalWindow.cpp | 2 +- Editor/Editor.cpp | 1353 +++++++++++----- Editor/Editor.h | 56 +- Editor/Editor_SOURCE.vcxitems | 2 - Editor/Editor_SOURCE.vcxitems.filters | 2 - Editor/EmitterWindow.cpp | 2 +- Editor/EnvProbeWindow.cpp | 2 +- Editor/ExpressionWindow.cpp | 2 +- Editor/FontWindow.cpp | 2 +- Editor/ForceFieldWindow.cpp | 2 +- Editor/GeneralWindow.cpp | 147 +- Editor/GraphicsWindow.cpp | 12 +- Editor/HairParticleWindow.cpp | 2 +- Editor/HierarchyWindow.cpp | 4 +- Editor/HumanoidWindow.cpp | 4 +- Editor/IKWindow.cpp | 2 +- Editor/IconDefinitions.h | 8 + Editor/LayerWindow.cpp | 2 +- Editor/LightWindow.cpp | 4 +- Editor/MaterialPickerWindow.cpp | 5 +- Editor/MaterialWindow.cpp | 4 +- Editor/MeshWindow.cpp | 2 +- Editor/NameWindow.cpp | 4 +- Editor/ObjectWindow.cpp | 2 +- Editor/OptionsWindow.cpp | 771 --------- Editor/OptionsWindow.h | 75 - Editor/PaintToolWindow.cpp | 33 +- Editor/ProfilerWindow.cpp | 19 - Editor/RigidBodyWindow.cpp | 2 +- Editor/ScriptWindow.cpp | 2 +- Editor/SoftBodyWindow.cpp | 2 +- Editor/SoundWindow.cpp | 2 +- Editor/SpringWindow.cpp | 2 +- Editor/SpriteWindow.cpp | 2 +- Editor/TerrainWindow.cpp | 28 +- Editor/TransformWindow.cpp | 2 +- Editor/Translator.cpp | 33 +- Editor/Translator.h | 7 +- Editor/VideoWindow.cpp | 2 +- Editor/VoxelGridWindow.cpp | 2 +- Editor/WeatherWindow.cpp | 2 +- Editor/languages/Magyar.xml | 1410 ++++++++--------- Editor/languages/日本語.xml | 1410 ++++++++--------- Editor/main_Windows.cpp | 1 + README.md | 30 +- WickedEngine/shaders/ShaderInterop_Image.h | 6 + .../shaders/ShaderInterop_Postprocess.h | 7 +- WickedEngine/shaders/imagePS.hlsl | 25 +- WickedEngine/shaders/tonemapCS.hlsl | 56 +- WickedEngine/wiApplication.cpp | 31 +- WickedEngine/wiApplication.h | 2 + WickedEngine/wiBacklog.cpp | 9 + WickedEngine/wiBacklog.h | 2 + WickedEngine/wiGUI.cpp | 1090 +++++++++---- WickedEngine/wiGUI.h | 78 +- WickedEngine/wiGraphics.h | 8 + WickedEngine/wiGraphicsDevice_Vulkan.cpp | 5 +- WickedEngine/wiImage.cpp | 20 + WickedEngine/wiImage.h | 20 + WickedEngine/wiInput.cpp | 64 + WickedEngine/wiInput.h | 17 + WickedEngine/wiJobSystem.cpp | 134 +- WickedEngine/wiJobSystem.h | 8 + WickedEngine/wiRenderPath3D.cpp | 15 +- WickedEngine/wiRenderer.cpp | 16 +- WickedEngine/wiScene.cpp | 2 +- WickedEngine/wiScene_Serializers.cpp | 1 + WickedEngine/wiVersion.cpp | 4 +- 77 files changed, 4283 insertions(+), 3365 deletions(-) delete mode 100644 Editor/OptionsWindow.cpp delete mode 100644 Editor/OptionsWindow.h diff --git a/Editor/AnimationWindow.cpp b/Editor/AnimationWindow.cpp index 88720aa48..d9a3e3d5e 100644 --- a/Editor/AnimationWindow.cpp +++ b/Editor/AnimationWindow.cpp @@ -21,7 +21,7 @@ void AnimationWindow::Create(EditorComponent* _editor) editor->RecordEntity(archive, entity); - editor->optionsWnd.RefreshEntityTree(); + editor->componentsWnd.RefreshEntityTree(); }); float x = 80; @@ -922,7 +922,7 @@ void AnimationWindow::Create(EditorComponent* _editor) } scene.names.Create(retarget_entity) = name; - editor->optionsWnd.RefreshEntityTree(); + editor->componentsWnd.RefreshEntityTree(); } }); AddWidget(&retargetCombo); diff --git a/Editor/ArmatureWindow.cpp b/Editor/ArmatureWindow.cpp index 6a3c3d798..bd17c8737 100644 --- a/Editor/ArmatureWindow.cpp +++ b/Editor/ArmatureWindow.cpp @@ -22,7 +22,7 @@ void ArmatureWindow::Create(EditorComponent* _editor) editor->RecordEntity(archive, entity); - editor->optionsWnd.RefreshEntityTree(); + editor->componentsWnd.RefreshEntityTree(); }); float x = 60; @@ -217,7 +217,7 @@ void ArmatureWindow::Create(EditorComponent* _editor) // record NEW selection state... editor->RecordSelection(archive); - editor->optionsWnd.RefreshEntityTree(); + editor->componentsWnd.RefreshEntityTree(); }); AddWidget(&boneList); diff --git a/Editor/CMakeLists.txt b/Editor/CMakeLists.txt index 794798d89..cec2d14bc 100644 --- a/Editor/CMakeLists.txt +++ b/Editor/CMakeLists.txt @@ -38,7 +38,6 @@ set (SOURCE_FILES HierarchyWindow.cpp ExpressionWindow.cpp ArmatureWindow.cpp - OptionsWindow.cpp ComponentsWindow.cpp TerrainWindow.cpp HumanoidWindow.cpp diff --git a/Editor/CameraComponentWindow.cpp b/Editor/CameraComponentWindow.cpp index 4ff41a1e5..a215af20b 100644 --- a/Editor/CameraComponentWindow.cpp +++ b/Editor/CameraComponentWindow.cpp @@ -81,7 +81,7 @@ void CameraComponentWindow::Create(EditorComponent* _editor) editor->RecordEntity(archive, entity); - editor->optionsWnd.RefreshEntityTree(); + editor->componentsWnd.RefreshEntityTree(); }); float x = 140; diff --git a/Editor/CameraWindow.cpp b/Editor/CameraWindow.cpp index e9e56a801..712a18db9 100644 --- a/Editor/CameraWindow.cpp +++ b/Editor/CameraWindow.cpp @@ -33,11 +33,13 @@ void CameraWindow::ResetCam() void CameraWindow::Create(EditorComponent* _editor) { editor = _editor; - wi::gui::Window::Create("Camera", wi::gui::Window::WindowControls::COLLAPSE); + wi::gui::Window::Create("Camera", wi::gui::Window::WindowControls::CLOSE | wi::gui::Window::WindowControls::RESIZE_RIGHT); + SetText("Camera " ICON_CAMERAOPTIONS); + editor->GetCurrentEditorScene().camera_transform.MatrixTransform(editor->GetCurrentEditorScene().camera.GetInvView()); editor->GetCurrentEditorScene().camera_transform.UpdateTransform(); - SetSize(XMFLOAT2(320, 390)); + SetSize(XMFLOAT2(300, 390)); float x = 140; float y = 0; @@ -257,7 +259,7 @@ void CameraWindow::Create(EditorComponent* _editor) editor->RecordSelection(archive); editor->RecordEntity(archive, entity); - editor->optionsWnd.RefreshEntityTree(); + editor->componentsWnd.RefreshEntityTree(); SetEntity(entity); }); AddWidget(&proxyButton); @@ -277,9 +279,7 @@ void CameraWindow::Create(EditorComponent* _editor) SetEntity(INVALID_ENTITY); - SetPos(XMFLOAT2(100, 100)); - - SetMinimized(true); + SetVisible(false); } void CameraWindow::SetEntity(Entity entity) diff --git a/Editor/ColliderWindow.cpp b/Editor/ColliderWindow.cpp index b4f8ae9cc..be6680cd3 100644 --- a/Editor/ColliderWindow.cpp +++ b/Editor/ColliderWindow.cpp @@ -22,7 +22,7 @@ void ColliderWindow::Create(EditorComponent* _editor) editor->RecordEntity(archive, entity); - editor->optionsWnd.RefreshEntityTree(); + editor->componentsWnd.RefreshEntityTree(); }); float x = 60; diff --git a/Editor/ComponentsWindow.cpp b/Editor/ComponentsWindow.cpp index a8c3af4d1..e58a94834 100644 --- a/Editor/ComponentsWindow.cpp +++ b/Editor/ComponentsWindow.cpp @@ -9,10 +9,119 @@ void ComponentsWindow::Create(EditorComponent* _editor) { editor = _editor; - wi::gui::Window::Create("Components ", wi::gui::Window::WindowControls::RESIZE_TOPLEFT); + wi::gui::Window::Create("Components ", wi::gui::Window::WindowControls::RESIZE_LEFT); + SetText("Entity - Component System"); font.params.h_align = wi::font::WIFALIGN_RIGHT; SetShadowRadius(2); + filterCombo.Create(""); + filterCombo.SetShadowRadius(0); + filterCombo.SetMaxVisibleItemCount(16); + filterCombo.AddItem("*", (uint64_t)Filter::All); + filterCombo.AddItem(ICON_TRANSFORM, (uint64_t)Filter::Transform); + filterCombo.AddItem(ICON_MATERIAL, (uint64_t)Filter::Material); + filterCombo.AddItem(ICON_MESH, (uint64_t)Filter::Mesh); + filterCombo.AddItem(ICON_OBJECT, (uint64_t)Filter::Object); + filterCombo.AddItem(ICON_ENVIRONMENTPROBE, (uint64_t)Filter::EnvironmentProbe); + filterCombo.AddItem(ICON_DECAL, (uint64_t)Filter::Decal); + filterCombo.AddItem(ICON_SOUND, (uint64_t)Filter::Sound); + filterCombo.AddItem(ICON_VIDEO, (uint64_t)Filter::Video); + filterCombo.AddItem(ICON_WEATHER, (uint64_t)Filter::Weather); + filterCombo.AddItem(ICON_POINTLIGHT, (uint64_t)Filter::Light); + filterCombo.AddItem(ICON_ANIMATION, (uint64_t)Filter::Animation); + filterCombo.AddItem(ICON_FORCE, (uint64_t)Filter::Force); + filterCombo.AddItem(ICON_EMITTER, (uint64_t)Filter::Emitter); + filterCombo.AddItem(ICON_HAIR, (uint64_t)Filter::Hairparticle); + filterCombo.AddItem(ICON_IK, (uint64_t)Filter::IK); + filterCombo.AddItem(ICON_CAMERA, (uint64_t)Filter::Camera); + filterCombo.AddItem(ICON_ARMATURE, (uint64_t)Filter::Armature); + filterCombo.AddItem(ICON_SPRING, (uint64_t)Filter::Spring); + filterCombo.AddItem(ICON_COLLIDER, (uint64_t)Filter::Collider); + filterCombo.AddItem(ICON_SCRIPT, (uint64_t)Filter::Script); + filterCombo.AddItem(ICON_EXPRESSION, (uint64_t)Filter::Expression); + filterCombo.AddItem(ICON_HUMANOID, (uint64_t)Filter::Humanoid); + filterCombo.AddItem(ICON_TERRAIN, (uint64_t)Filter::Terrain); + filterCombo.AddItem(ICON_SPRITE, (uint64_t)Filter::Sprite); + filterCombo.AddItem(ICON_FONT, (uint64_t)Filter::Font); + filterCombo.AddItem(ICON_VOXELGRID, (uint64_t)Filter::VoxelGrid); + filterCombo.AddItem(ICON_RIGIDBODY, (uint64_t)Filter::RigidBody); + filterCombo.AddItem(ICON_SOFTBODY, (uint64_t)Filter::SoftBody); + filterCombo.SetTooltip("Apply filtering to the Entities by components"); + filterCombo.SetLocalizationEnabled(wi::gui::LocalizationEnabled::Tooltip); + filterCombo.OnSelect([&](wi::gui::EventArgs args) { + filter = (Filter)args.userdata; + RefreshEntityTree(); + }); + AddWidget(&filterCombo); + + + filterInput.Create(""); + filterInput.SetShadowRadius(0); + filterInput.SetTooltip("Search entities by name"); + filterInput.SetDescription(ICON_SEARCH " "); + filterInput.SetCancelInputEnabled(false); + filterInput.OnInput([=](wi::gui::EventArgs args) { + RefreshEntityTree(); + }); + filterInput.SetLocalizationEnabled(wi::gui::LocalizationEnabled::Tooltip); + AddWidget(&filterInput); + + filterCaseCheckBox.Create(""); + filterCaseCheckBox.SetShadowRadius(0); + filterCaseCheckBox.SetCheckText("Aa"); + filterCaseCheckBox.SetUnCheckText("a"); + filterCaseCheckBox.SetTooltip("Toggle case-sensitive name filtering"); + filterCaseCheckBox.SetLocalizationEnabled(wi::gui::LocalizationEnabled::Tooltip); + filterCaseCheckBox.OnClick([=](wi::gui::EventArgs args) { + RefreshEntityTree(); + }); + AddWidget(&filterCaseCheckBox); + + + entityTree.Create("Entities"); + entityTree.SetSize(XMFLOAT2(300, 300)); + entityTree.OnSelect([this](wi::gui::EventArgs args) { + + if (args.iValue < 0) + return; + + wi::Archive& archive = editor->AdvanceHistory(); + archive << EditorComponent::HISTORYOP_SELECTION; + // record PREVIOUS selection state... + editor->RecordSelection(archive); + + editor->translator.selected.clear(); + + for (int i = 0; i < entityTree.GetItemCount(); ++i) + { + const wi::gui::TreeList::Item& item = entityTree.GetItem(i); + if (item.selected) + { + wi::scene::PickResult pick; + pick.entity = (Entity)item.userdata; + editor->AddSelected(pick); + } + } + + // record NEW selection state... + editor->RecordSelection(archive); + + }); + entityTree.OnDelete([=](wi::gui::EventArgs args) { + // Deletions will be performed in a batch next frame: + // We don't delete here, because this callback will execute once for each item + editor->deleting = true; + }); + entityTree.OnDoubleClick([this](wi::gui::EventArgs args) { + editor->FocusCameraOnSelected(); + }); + AddWidget(&entityTree); + + if (editor->main->config.GetSection("layout").Has("entities.height")) + { + float height = editor->main->config.GetSection("layout").GetFloat("entities.height"); + entityTree.SetSize(XMFLOAT2(entityTree.GetSize().x, height)); + } materialWnd.Create(editor); weatherWnd.Create(editor); @@ -76,12 +185,13 @@ void ComponentsWindow::Create(EditorComponent* _editor) ADD_VOXELGRID, }; - newComponentCombo.Create("Add: "); - newComponentCombo.selected_font.anim.typewriter.looped = true; - newComponentCombo.selected_font.anim.typewriter.time = 2; - newComponentCombo.selected_font.anim.typewriter.character_start = 1; - newComponentCombo.SetTooltip("Add a component to the last selected entity."); - newComponentCombo.SetInvalidSelectionText("..."); + newComponentCombo.Create("Add component "); + newComponentCombo.SetDropArrowEnabled(false); + newComponentCombo.SetAngularHighlightWidth(3); + newComponentCombo.SetShadowRadius(0); + newComponentCombo.SetFixedDropWidth(250); + newComponentCombo.SetTooltip("Add a component to the selected entity."); + newComponentCombo.SetInvalidSelectionText("+"); newComponentCombo.AddItem("Name " ICON_NAME, ADD_NAME); newComponentCombo.AddItem("Layer " ICON_LAYER, ADD_LAYER); newComponentCombo.AddItem("Hierarchy " ICON_HIERARCHY, ADD_HIERARCHY); @@ -340,7 +450,7 @@ void ComponentsWindow::Create(EditorComponent* _editor) editor->RecordEntity(archive, entity); - editor->optionsWnd.RefreshEntityTree(); + RefreshEntityTree(); }); AddWidget(&newComponentCombo); @@ -415,10 +525,6 @@ void ComponentsWindow::Create(EditorComponent* _editor) { size.x = editor->main->config.GetSection("layout").GetFloat("components.width"); } - if (editor->main->config.GetSection("layout").Has("components.height")) - { - size.y = editor->main->config.GetSection("layout").GetFloat("components.height"); - } SetSize(size); } void ComponentsWindow::Update(float dt) @@ -431,25 +537,52 @@ void ComponentsWindow::ResizeLayout() { wi::gui::Window::ResizeLayout(); const wi::scene::Scene& scene = editor->GetCurrentScene(); - const float padding = 4; - XMFLOAT2 pos = XMFLOAT2(padding, padding); - const float width = GetWidgetAreaSize().x - padding * 2; + float padding = 2; + XMFLOAT2 pos = XMFLOAT2(padding, 0); + const float width = GetWidgetAreaSize().x - padding; + const float height = GetWidgetAreaSize().y - padding * 2; editor->main->config.GetSection("layout").Set("components.width", GetSize().x); - editor->main->config.GetSection("layout").Set("components.height", GetSize().y); + editor->main->config.GetSection("layout").Set("entities.height", entityTree.GetSize().y); + + // Entities: + { + float x_off = 25; + float filterHeight = filterCombo.GetSize().y; + float filterComboWidth = 30; + + filterInput.SetPos(XMFLOAT2(pos.x + x_off, pos.y)); + filterInput.SetSize(XMFLOAT2(width - x_off - filterHeight - 5 - filterComboWidth - filterHeight, filterCombo.GetScale().y)); + + filterCaseCheckBox.SetPos(XMFLOAT2(filterInput.GetPos().x + filterInput.GetSize().x + 1, pos.y)); + filterCaseCheckBox.SetSize(XMFLOAT2(filterHeight, filterHeight)); + + filterCombo.SetPos(XMFLOAT2(filterCaseCheckBox.GetPos().x + filterCaseCheckBox.GetSize().x + 1, pos.y)); + filterCombo.SetSize(XMFLOAT2(filterComboWidth, filterHeight)); + pos.y += filterCombo.GetSize().y; + pos.y += padding; + + pos.x = 0; + entityTree.SetPos(pos); + entityTree.SetSize(XMFLOAT2(width, wi::math::Clamp(entityTree.GetSize().y, 0, height - pos.y - 50))); + pos.y += entityTree.GetSize().y; + pos.y += padding * 4; + } if (!editor->translator.selected.empty()) { newComponentCombo.SetVisible(true); - newComponentCombo.SetPos(XMFLOAT2(pos.x + 35, pos.y)); - newComponentCombo.SetSize(XMFLOAT2(width - 35 - 21, 20)); + newComponentCombo.SetSize(XMFLOAT2(20, 20)); + newComponentCombo.SetPos(XMFLOAT2(pos.x + width - 30, pos.y)); pos.y += newComponentCombo.GetSize().y; - pos.y += padding; + pos.y += padding * 4; } else { newComponentCombo.SetVisible(false); } + padding = 1; + if (scene.names.Contains(nameWnd.entity)) { nameWnd.SetVisible(true); @@ -866,3 +999,297 @@ void ComponentsWindow::ResizeLayout() voxelGridWnd.SetVisible(false); } } + + +void ComponentsWindow::PushToEntityTree(wi::ecs::Entity entity, int level) +{ + if (entitytree_added_items.count(entity) != 0) + { + return; + } + const Scene& scene = editor->GetCurrentScene(); + + if (CheckEntityFilter(entity)) + { + wi::gui::TreeList::Item item; + if (filter == Filter::All) + { + item.level = level; + } + else + { + item.level = 0; + } + item.userdata = entity; + item.selected = editor->IsSelected(entity); + item.open = entitytree_opened_items.count(entity) != 0; + + const NameComponent* name = scene.names.GetComponent(entity); + + std::string name_string; + if (name == nullptr) + { + name_string = "[no_name] " + std::to_string(entity); + } + else if (name->name.empty()) + { + name_string = "[name_empty] " + std::to_string(entity); + } + else + { + name_string = name->name; + } + + std::string name_filter = filterInput.GetCurrentInputValue(); + if (!name_filter.empty()) + { + if (filterCaseCheckBox.GetCheck() && name_string.find(name_filter) == std::string::npos) + { + return; + } + else if (wi::helper::toUpper(name_string).find(wi::helper::toUpper(name_filter)) == std::string::npos) + { + return; + } + } + + // Icons: + if (scene.layers.Contains(entity)) + { + item.name += ICON_LAYER " "; + } + if (scene.transforms.Contains(entity)) + { + item.name += ICON_TRANSFORM " "; + } + if (scene.terrains.Contains(entity)) + { + item.name += ICON_TERRAIN " "; + } + if (scene.meshes.Contains(entity)) + { + item.name += ICON_MESH " "; + } + if (scene.objects.Contains(entity)) + { + item.name += ICON_OBJECT " "; + } + if (scene.rigidbodies.Contains(entity)) + { + item.name += ICON_RIGIDBODY " "; + } + if (scene.softbodies.Contains(entity)) + { + item.name += ICON_SOFTBODY " "; + } + if (scene.emitters.Contains(entity)) + { + item.name += ICON_EMITTER " "; + } + if (scene.hairs.Contains(entity)) + { + item.name += ICON_HAIR " "; + } + if (scene.forces.Contains(entity)) + { + item.name += ICON_FORCE " "; + } + if (scene.sounds.Contains(entity)) + { + item.name += ICON_SOUND " "; + } + if (scene.videos.Contains(entity)) + { + item.name += ICON_VIDEO " "; + } + if (scene.decals.Contains(entity)) + { + item.name += ICON_DECAL " "; + } + if (scene.cameras.Contains(entity)) + { + item.name += ICON_CAMERA " "; + } + if (scene.probes.Contains(entity)) + { + item.name += ICON_ENVIRONMENTPROBE " "; + } + if (scene.animations.Contains(entity)) + { + item.name += ICON_ANIMATION " "; + } + if (scene.animation_datas.Contains(entity)) + { + item.name += "[animation_data] "; + } + if (scene.armatures.Contains(entity)) + { + item.name += ICON_ARMATURE " "; + } + if (scene.humanoids.Contains(entity)) + { + item.name += ICON_HUMANOID " "; + } + if (scene.sprites.Contains(entity)) + { + item.name += ICON_SPRITE " "; + } + if (scene.fonts.Contains(entity)) + { + item.name += ICON_FONT " "; + } + if (scene.voxel_grids.Contains(entity)) + { + item.name += ICON_VOXELGRID " "; + } + if (scene.lights.Contains(entity)) + { + const LightComponent* light = scene.lights.GetComponent(entity); + switch (light->type) + { + default: + case LightComponent::POINT: + item.name += ICON_POINTLIGHT " "; + break; + case LightComponent::SPOT: + item.name += ICON_SPOTLIGHT " "; + break; + case LightComponent::DIRECTIONAL: + item.name += ICON_DIRECTIONALLIGHT " "; + break; + } + } + if (scene.materials.Contains(entity)) + { + item.name += ICON_MATERIAL " "; + } + if (scene.weathers.Contains(entity)) + { + item.name += ICON_WEATHER " "; + } + if (scene.inverse_kinematics.Contains(entity)) + { + item.name += ICON_IK " "; + } + if (scene.springs.Contains(entity)) + { + item.name += ICON_SPRING " "; + } + if (scene.colliders.Contains(entity)) + { + item.name += ICON_COLLIDER " "; + } + if (scene.scripts.Contains(entity)) + { + item.name += ICON_SCRIPT " "; + } + if (scene.expressions.Contains(entity)) + { + item.name += ICON_EXPRESSION " "; + } + bool bone_found = false; + for (size_t i = 0; i < scene.armatures.GetCount() && !bone_found; ++i) + { + const ArmatureComponent& armature = scene.armatures[i]; + for (Entity bone : armature.boneCollection) + { + if (entity == bone) + { + item.name += ICON_BONE " "; + bone_found = true; + break; + } + } + } + + item.name += name_string; + entityTree.AddItem(item); + + entitytree_added_items.insert(entity); + } + + for (size_t i = 0; i < scene.hierarchy.GetCount(); ++i) + { + if (scene.hierarchy[i].parentID == entity) + { + PushToEntityTree(scene.hierarchy.GetEntity(i), level + 1); + } + } +} +void ComponentsWindow::RefreshEntityTree() +{ + if (editor == nullptr) + return; + const Scene& scene = editor->GetCurrentScene(); + editor->materialPickerWnd.RecreateButtons(); + + for (int i = 0; i < entityTree.GetItemCount(); ++i) + { + const wi::gui::TreeList::Item& item = entityTree.GetItem(i); + if (item.open) + { + entitytree_opened_items.insert((Entity)item.userdata); + } + } + + entityTree.ClearItems(); + + entitytree_temp_items.clear(); + scene.FindAllEntities(entitytree_temp_items); + + // Add items to level 0 that are not in hierarchy (not in hierarchy can also mean top level parent): + // Note that PushToEntityTree will add children recursively, so this is all we need + for (auto& x : entitytree_temp_items) + { + if (!scene.hierarchy.Contains(x)) + { + PushToEntityTree(x, 0); + } + } + + entitytree_added_items.clear(); + entitytree_opened_items.clear(); +} +bool ComponentsWindow::CheckEntityFilter(wi::ecs::Entity entity) +{ + if (filter == Filter::All) + return true; + + const Scene& scene = editor->GetCurrentScene(); + bool valid = false; + + if ( + has_flag(filter, Filter::Transform) && scene.transforms.Contains(entity) || + has_flag(filter, Filter::Material) && scene.materials.Contains(entity) || + has_flag(filter, Filter::Mesh) && scene.meshes.Contains(entity) || + has_flag(filter, Filter::Object) && scene.objects.Contains(entity) || + has_flag(filter, Filter::EnvironmentProbe) && scene.probes.Contains(entity) || + has_flag(filter, Filter::Decal) && scene.decals.Contains(entity) || + has_flag(filter, Filter::Sound) && scene.sounds.Contains(entity) || + has_flag(filter, Filter::Weather) && scene.weathers.Contains(entity) || + has_flag(filter, Filter::Light) && scene.lights.Contains(entity) || + has_flag(filter, Filter::Animation) && scene.animations.Contains(entity) || + has_flag(filter, Filter::Force) && scene.forces.Contains(entity) || + has_flag(filter, Filter::Emitter) && scene.emitters.Contains(entity) || + has_flag(filter, Filter::IK) && scene.inverse_kinematics.Contains(entity) || + has_flag(filter, Filter::Camera) && scene.cameras.Contains(entity) || + has_flag(filter, Filter::Armature) && scene.armatures.Contains(entity) || + has_flag(filter, Filter::Collider) && scene.colliders.Contains(entity) || + has_flag(filter, Filter::Script) && scene.scripts.Contains(entity) || + has_flag(filter, Filter::Expression) && scene.expressions.Contains(entity) || + has_flag(filter, Filter::Terrain) && scene.terrains.Contains(entity) || + has_flag(filter, Filter::Spring) && scene.springs.Contains(entity) || + has_flag(filter, Filter::Humanoid) && scene.humanoids.Contains(entity) || + has_flag(filter, Filter::Video) && scene.videos.Contains(entity) || + has_flag(filter, Filter::Sprite) && scene.sprites.Contains(entity) || + has_flag(filter, Filter::Font) && scene.fonts.Contains(entity) || + has_flag(filter, Filter::VoxelGrid) && scene.voxel_grids.Contains(entity) || + has_flag(filter, Filter::RigidBody) && scene.rigidbodies.Contains(entity) || + has_flag(filter, Filter::SoftBody) && scene.softbodies.Contains(entity) + ) + { + valid = true; + } + + return valid; +} diff --git a/Editor/ComponentsWindow.h b/Editor/ComponentsWindow.h index d544499c1..8367266d2 100644 --- a/Editor/ComponentsWindow.h +++ b/Editor/ComponentsWindow.h @@ -74,4 +74,53 @@ public: SpriteWindow spriteWnd; FontWindow fontWnd; VoxelGridWindow voxelGridWnd; + + enum class Filter : uint64_t + { + Transform = 1 << 0, + Material = 1 << 1, + Mesh = 1 << 2, + Object = 1 << 3, + EnvironmentProbe = 1 << 4, + Decal = 1 << 5, + Sound = 1 << 6, + Weather = 1 << 7, + Light = 1 << 8, + Animation = 1 << 9, + Force = 1 << 10, + Emitter = 1 << 11, + Hairparticle = 1 << 12, + IK = 1 << 13, + Camera = 1 << 14, + Armature = 1 << 15, + Collider = 1 << 16, + Script = 1 << 17, + Expression = 1 << 18, + Terrain = 1 << 19, + Spring = 1 << 20, + Humanoid = 1 << 21, + Video = 1 << 22, + Sprite = 1 << 23, + Font = 1 << 24, + VoxelGrid = 1 << 25, + RigidBody = 1 << 26, + SoftBody = 1 << 27, + + All = ~0ull, + } filter = Filter::All; + wi::gui::ComboBox filterCombo; + wi::gui::TextInputField filterInput; + wi::gui::CheckBox filterCaseCheckBox; + wi::gui::TreeList entityTree; + wi::unordered_set entitytree_temp_items; + wi::unordered_set entitytree_added_items; + wi::unordered_set entitytree_opened_items; + void PushToEntityTree(wi::ecs::Entity entity, int level); + void RefreshEntityTree(); + bool CheckEntityFilter(wi::ecs::Entity entity); +}; + +template<> +struct enable_bitmask_operators { + static const bool enable = true; }; diff --git a/Editor/ContentBrowserWindow.cpp b/Editor/ContentBrowserWindow.cpp index 02224d4c1..79a08ca95 100644 --- a/Editor/ContentBrowserWindow.cpp +++ b/Editor/ContentBrowserWindow.cpp @@ -9,9 +9,7 @@ void ContentBrowserWindow::Create(EditorComponent* _editor) editor = _editor; control_size = 30; - wi::gui::Window::WindowControls controls = wi::gui::Window::WindowControls::ALL; - controls &= ~wi::gui::Window::WindowControls::RESIZE_BOTTOMLEFT; - wi::gui::Window::Create("Content Browser", controls); + wi::gui::Window::Create("Content Browser"); RemoveWidget(&scrollbar_horizontal); @@ -49,25 +47,6 @@ void ContentBrowserWindow::Update(const wi::Canvas& canvas, float dt) sprites[i].params.corners_rounding[1].radius = radius; sprites[i].params.corners_rounding[2].radius = radius; sprites[i].params.corners_rounding[3].radius = radius; - resizeDragger_UpperLeft.sprites[i].params.enableCornerRounding(); - resizeDragger_UpperLeft.sprites[i].params.corners_rounding[0].radius = radius; - resizeDragger_UpperRight.sprites[i].params.enableCornerRounding(); - resizeDragger_UpperRight.sprites[i].params.corners_rounding[1].radius = radius; - resizeDragger_BottomLeft.sprites[i].params.enableCornerRounding(); - resizeDragger_BottomLeft.sprites[i].params.corners_rounding[2].radius = radius; - resizeDragger_BottomRight.sprites[i].params.enableCornerRounding(); - resizeDragger_BottomRight.sprites[i].params.corners_rounding[3].radius = radius; - - if (IsCollapsed()) - { - resizeDragger_UpperLeft.sprites[i].params.corners_rounding[2].radius = radius; - resizeDragger_UpperRight.sprites[i].params.corners_rounding[3].radius = radius; - } - else - { - resizeDragger_UpperLeft.sprites[i].params.corners_rounding[2].radius = 0; - resizeDragger_UpperRight.sprites[i].params.corners_rounding[3].radius = 0; - } openFolderButton.sprites[i].params.enableCornerRounding(); openFolderButton.sprites[i].params.corners_rounding[0].radius = radius; @@ -353,7 +332,7 @@ void ContentBrowserWindow::SetSelection(SELECTION selection) } // Refresh theme: - editor->optionsWnd.generalWnd.themeCombo.SetSelected(editor->optionsWnd.generalWnd.themeCombo.GetSelected()); + editor->generalWnd.themeCombo.SetSelected(editor->generalWnd.themeCombo.GetSelected()); }); } diff --git a/Editor/DecalWindow.cpp b/Editor/DecalWindow.cpp index 8e3f76417..22bb31469 100644 --- a/Editor/DecalWindow.cpp +++ b/Editor/DecalWindow.cpp @@ -22,7 +22,7 @@ void DecalWindow::Create(EditorComponent* _editor) editor->RecordEntity(archive, entity); - editor->optionsWnd.RefreshEntityTree(); + editor->componentsWnd.RefreshEntityTree(); }); float x = 200; diff --git a/Editor/Editor.cpp b/Editor/Editor.cpp index b8ba6691b..b15159182 100644 --- a/Editor/Editor.cpp +++ b/Editor/Editor.cpp @@ -95,107 +95,19 @@ void Editor::Initialize() wi::renderer::SetOcclusionCullingEnabled(true); - loader.Load(); - renderComponent.main = this; - - loader.addLoadingComponent(&renderComponent, this, 0.2f); - - ActivatePath(&loader); -} - -void EditorLoadingScreen::Load() -{ - font = wi::SpriteFont("Loading...", wi::font::Params(0, 0, 36, wi::font::WIFALIGN_LEFT, wi::font::WIFALIGN_CENTER)); - font.anim.typewriter.time = 2; - font.anim.typewriter.looped = true; - font.anim.typewriter.character_start = 7; - AddFont(&font); - - sprite.anim.opa = 1; - sprite.anim.repeatable = true; - sprite.params.siz = XMFLOAT2(128, 128); - sprite.params.pivot = XMFLOAT2(0.5f, 1.0f); - sprite.params.quality = wi::image::QUALITY_LINEAR; - sprite.params.blendFlag = wi::enums::BLENDMODE_ALPHA; - AddSprite(&sprite); - - wi::gui::CheckBox::SetCheckTextGlobal(ICON_CHECK); - - LoadingScreen::Load(); -} -void EditorLoadingScreen::Update(float dt) -{ - font.params.posX = GetLogicalWidth()*0.5f - font.TextWidth() * 0.5f; - font.params.posY = GetLogicalHeight()*0.5f; - sprite.params.pos = XMFLOAT3(GetLogicalWidth()*0.5f, GetLogicalHeight()*0.5f - font.TextHeight(), 0); - sprite.textureResource.SetTexture(*wi::texturehelper::getLogo()); // use embedded asset - - LoadingScreen::Update(dt); + renderComponent.Load(); + ActivatePath(&renderComponent, 0.2f); } void EditorComponent::ResizeBuffers() { - optionsWnd.graphicsWnd.UpdateSwapChainFormats(&main->swapChain); + graphicsWnd.UpdateSwapChainFormats(&main->swapChain); init(main->canvas); RenderPath2D::ResizeBuffers(); - GraphicsDevice* device = wi::graphics::GetDevice(); - - renderPath->init(*this); - renderPath->ResizeBuffers(); - - if(renderPath->GetDepthStencil() != nullptr) - { - bool success = false; - - XMUINT2 internalResolution = GetInternalResolution(); - - TextureDesc desc; - desc.width = internalResolution.x; - desc.height = internalResolution.y; - - desc.format = Format::R8_UNORM; - desc.bind_flags = BindFlag::RENDER_TARGET | BindFlag::SHADER_RESOURCE; - if (renderPath->getMSAASampleCount() > 1) - { - desc.sample_count = renderPath->getMSAASampleCount(); - success = device->CreateTexture(&desc, nullptr, &rt_selectionOutline_MSAA); - assert(success); - desc.sample_count = 1; - } - success = device->CreateTexture(&desc, nullptr, &rt_selectionOutline[0]); - assert(success); - success = device->CreateTexture(&desc, nullptr, &rt_selectionOutline[1]); - assert(success); - } - - { - TextureDesc desc; - desc.width = renderPath->GetRenderResult().GetDesc().width; - desc.height = renderPath->GetRenderResult().GetDesc().height; - desc.format = Format::R8_UNORM; - desc.bind_flags = BindFlag::RENDER_TARGET | BindFlag::SHADER_RESOURCE; - desc.swizzle.r = ComponentSwizzle::R; - desc.swizzle.g = ComponentSwizzle::R; - desc.swizzle.b = ComponentSwizzle::R; - desc.swizzle.a = ComponentSwizzle::R; - device->CreateTexture(&desc, nullptr, &rt_dummyOutline); - device->SetName(&rt_dummyOutline, "rt_dummyOutline"); - } - - { - TextureDesc desc; - desc.width = renderPath->GetRenderResult().GetDesc().width; - desc.height = renderPath->GetRenderResult().GetDesc().height; - desc.format = Format::D32_FLOAT; - desc.bind_flags = BindFlag::DEPTH_STENCIL; - desc.layout = ResourceState::DEPTHSTENCIL; - desc.misc_flags = ResourceMiscFlag::TRANSIENT_ATTACHMENT; - device->CreateTexture(&desc, nullptr, &editor_depthbuffer); - device->SetName(&editor_depthbuffer, "editor_depthbuffer"); - } + ResizeViewport3D(); } void EditorComponent::ResizeLayout() { @@ -206,11 +118,11 @@ void EditorComponent::ResizeLayout() float screenW = GetLogicalWidth(); float screenH = GetLogicalHeight(); - optionsWnd.SetPos(XMFLOAT2(0, screenH - optionsWnd.GetScale().y)); - optionsWnd.scale_local = wi::math::Clamp(optionsWnd.scale_local, XMFLOAT3(1, 1, 1), XMFLOAT3(screenW, screenH, 1)); + topmenuWnd.SetSize(XMFLOAT2(screenW, 30)); + topmenuWnd.SetPos(XMFLOAT2(0, 0)); - componentsWnd.SetPos(XMFLOAT2(screenW - componentsWnd.GetScale().x, screenH - componentsWnd.GetScale().y)); - componentsWnd.scale_local = wi::math::Clamp(componentsWnd.scale_local, XMFLOAT3(1, 1, 1), XMFLOAT3(screenW, screenH, 1)); + componentsWnd.SetSize(XMFLOAT2(componentsWnd.GetSize().x, screenH - topmenuWnd.GetSize().y)); + componentsWnd.SetPos(XMFLOAT2(screenW - componentsWnd.scale_local.x, topmenuWnd.scale_local.y + topmenuWnd.GetShadowRadius())); aboutWindow.SetSize(XMFLOAT2(screenW / 2.0f, screenH / 1.5f)); aboutWindow.SetPos(XMFLOAT2(screenW / 2.0f - aboutWindow.scale.x / 2.0f, screenH / 2.0f - aboutWindow.scale.y / 2.0f)); @@ -221,13 +133,381 @@ void EditorComponent::ResizeLayout() } void EditorComponent::Load() { + wi::gui::CheckBox::SetCheckTextGlobal(ICON_CHECK); + + loadmodel_workload.priority = wi::jobsystem::Priority::Low; + + loadmodel_font.SetText("Loading model..."); + loadmodel_font.anim.typewriter.time = 2; + loadmodel_font.anim.typewriter.looped = true; + loadmodel_font.anim.typewriter.character_start = 13; + loadmodel_font.params.size = 22; + loadmodel_font.params.h_align = wi::font::WIFALIGN_LEFT; + loadmodel_font.params.v_align = wi::font::WIFALIGN_TOP; + AddFont(&loadmodel_font); + + topmenuWnd.Create("", wi::gui::Window::WindowControls::NONE); + topmenuWnd.SetShadowRadius(2); + GetGUI().AddWidget(&topmenuWnd); + topmenuWnd.scrollbar_horizontal.Detach(); + topmenuWnd.scrollbar_vertical.Detach(); + + generalButton.Create(ICON_GENERALOPTIONS); + generalButton.OnClick([this](wi::gui::EventArgs args) { + generalWnd.SetVisible(!generalWnd.IsVisible()); + graphicsWnd.SetVisible(false); + cameraWnd.SetVisible(false); + materialPickerWnd.SetVisible(false); + paintToolWnd.SetVisible(false); + }); + generalButton.SetShadowRadius(0); + generalButton.SetTooltip("General options"); + generalButton.SetLocalizationEnabled(wi::gui::LocalizationEnabled::Tooltip); + GetGUI().AddWidget(&generalButton); + + graphicsButton.Create(ICON_GRAPHICSOPTIONS); + graphicsButton.OnClick([this](wi::gui::EventArgs args) { + generalWnd.SetVisible(false); + graphicsWnd.SetVisible(!graphicsWnd.IsVisible()); + cameraWnd.SetVisible(false); + materialPickerWnd.SetVisible(false); + paintToolWnd.SetVisible(false); + }); + graphicsButton.SetShadowRadius(0); + graphicsButton.SetTooltip("Graphics options"); + graphicsButton.SetLocalizationEnabled(wi::gui::LocalizationEnabled::Tooltip); + GetGUI().AddWidget(&graphicsButton); + + cameraButton.Create(ICON_CAMERAOPTIONS); + cameraButton.OnClick([this](wi::gui::EventArgs args) { + generalWnd.SetVisible(false); + graphicsWnd.SetVisible(false); + cameraWnd.SetVisible(!cameraWnd.IsVisible()); + materialPickerWnd.SetVisible(false); + paintToolWnd.SetVisible(false); + }); + cameraButton.SetShadowRadius(0); + cameraButton.SetTooltip("Camera options"); + cameraButton.SetLocalizationEnabled(wi::gui::LocalizationEnabled::Tooltip); + GetGUI().AddWidget(&cameraButton); + + materialsButton.Create(ICON_MATERIALBROWSER); + materialsButton.OnClick([this](wi::gui::EventArgs args) { + generalWnd.SetVisible(false); + graphicsWnd.SetVisible(false); + cameraWnd.SetVisible(false); + materialPickerWnd.SetVisible(!materialPickerWnd.IsVisible()); + paintToolWnd.SetVisible(false); + if (materialPickerWnd.IsVisible()) + { + materialPickerWnd.RecreateButtons(); + } + }); + materialsButton.SetShadowRadius(0); + materialsButton.SetTooltip("Material browser"); + materialsButton.SetLocalizationEnabled(wi::gui::LocalizationEnabled::Tooltip); + GetGUI().AddWidget(&materialsButton); + + paintToolButton.Create(ICON_PAINTTOOL); + paintToolButton.OnClick([this](wi::gui::EventArgs args) { + generalWnd.SetVisible(false); + graphicsWnd.SetVisible(false); + cameraWnd.SetVisible(false); + materialPickerWnd.SetVisible(false); + paintToolWnd.SetVisible(!paintToolWnd.IsVisible()); + }); + paintToolButton.SetShadowRadius(0); + paintToolButton.SetTooltip("Paint tool"); + paintToolButton.SetLocalizationEnabled(wi::gui::LocalizationEnabled::Tooltip); + GetGUI().AddWidget(&paintToolButton); + + graphicsWnd.Create(this); + GetGUI().AddWidget(&graphicsWnd); + + cameraWnd.Create(this); + GetGUI().AddWidget(&cameraWnd); + + paintToolWnd.Create(this); + GetGUI().AddWidget(&paintToolWnd); + + materialPickerWnd.Create(this); + GetGUI().AddWidget(&materialPickerWnd); + + generalWnd.Create(this); + GetGUI().AddWidget(&generalWnd); + newSceneButton.Create("+"); newSceneButton.SetLocalizationEnabled(wi::gui::LocalizationEnabled::Tooltip); newSceneButton.SetTooltip("New scene"); newSceneButton.OnClick([&](wi::gui::EventArgs args) { NewScene(); }); - GetGUI().AddWidget(&newSceneButton); + topmenuWnd.AddWidget(&newSceneButton); + + enum NEW_THING + { + NEW_TRANSFORM, + NEW_MATERIAL, + NEW_POINTLIGHT, + NEW_SPOTLIGHT, + NEW_DIRECTIONALLIGHT, + NEW_ENVIRONMENTPROBE, + NEW_FORCE, + NEW_DECAL, + NEW_SOUND, + NEW_VIDEO, + NEW_WEATHER, + NEW_EMITTER, + NEW_HAIR, + NEW_CAMERA, + NEW_CUBE, + NEW_PLANE, + NEW_SPHERE, + NEW_ANIMATION, + NEW_SCRIPT, + NEW_COLLIDER, + NEW_TERRAIN, + NEW_SPRITE, + NEW_FONT, + NEW_VOXELGRID, + }; + + newEntityCombo.Create("New: "); + newEntityCombo.SetShadowRadius(0); + newEntityCombo.SetInvalidSelectionText("+"); + newEntityCombo.SetDropArrowEnabled(false); + newEntityCombo.SetFixedDropWidth(200); + newEntityCombo.SetMaxVisibleItemCount(16); + newEntityCombo.SetAngularHighlightWidth(3); + newEntityCombo.AddItem("Transform " ICON_TRANSFORM, NEW_TRANSFORM); + newEntityCombo.AddItem("Material " ICON_MATERIAL, NEW_MATERIAL); + newEntityCombo.AddItem("Point Light " ICON_POINTLIGHT, NEW_POINTLIGHT); + newEntityCombo.AddItem("Spot Light " ICON_SPOTLIGHT, NEW_SPOTLIGHT); + newEntityCombo.AddItem("Directional Light " ICON_DIRECTIONALLIGHT, NEW_DIRECTIONALLIGHT); + newEntityCombo.AddItem("Environment Probe " ICON_ENVIRONMENTPROBE, NEW_ENVIRONMENTPROBE); + newEntityCombo.AddItem("Force " ICON_FORCE, NEW_FORCE); + newEntityCombo.AddItem("Decal " ICON_DECAL, NEW_DECAL); + newEntityCombo.AddItem("Sound " ICON_SOUND, NEW_SOUND); + newEntityCombo.AddItem("Video " ICON_VIDEO, NEW_VIDEO); + newEntityCombo.AddItem("Weather " ICON_WEATHER, NEW_WEATHER); + newEntityCombo.AddItem("Emitter " ICON_EMITTER, NEW_EMITTER); + newEntityCombo.AddItem("HairParticle " ICON_HAIR, NEW_HAIR); + newEntityCombo.AddItem("Camera " ICON_CAMERA, NEW_CAMERA); + newEntityCombo.AddItem("Cube " ICON_CUBE, NEW_CUBE); + newEntityCombo.AddItem("Plane " ICON_SQUARE, NEW_PLANE); + newEntityCombo.AddItem("Sphere " ICON_CIRCLE, NEW_SPHERE); + newEntityCombo.AddItem("Animation " ICON_ANIMATION, NEW_ANIMATION); + newEntityCombo.AddItem("Script " ICON_SCRIPT, NEW_SCRIPT); + newEntityCombo.AddItem("Collider " ICON_COLLIDER, NEW_COLLIDER); + newEntityCombo.AddItem("Terrain " ICON_TERRAIN, NEW_TERRAIN); + newEntityCombo.AddItem("Sprite " ICON_SPRITE, NEW_SPRITE); + newEntityCombo.AddItem("Font " ICON_FONT, NEW_FONT); + newEntityCombo.AddItem("Voxel Grid " ICON_VOXELGRID, NEW_VOXELGRID); + newEntityCombo.OnSelect([this](wi::gui::EventArgs args) { + newEntityCombo.SetSelectedWithoutCallback(-1); + const EditorComponent::EditorScene& editorscene = GetCurrentEditorScene(); + const CameraComponent& camera = editorscene.camera; + Scene& scene = GetCurrentScene(); + PickResult pick; + + XMFLOAT3 in_front_of_camera; + XMStoreFloat3(&in_front_of_camera, XMVectorAdd(camera.GetEye(), camera.GetAt() * 4)); + + switch (args.userdata) + { + case NEW_TRANSFORM: + pick.entity = scene.Entity_CreateTransform("transform"); + break; + case NEW_MATERIAL: + pick.entity = scene.Entity_CreateMaterial("material"); + break; + case NEW_POINTLIGHT: + pick.entity = scene.Entity_CreateLight("pointlight", in_front_of_camera, XMFLOAT3(1, 1, 1), 2, 60); + scene.lights.GetComponent(pick.entity)->type = LightComponent::POINT; + scene.lights.GetComponent(pick.entity)->intensity = 20; + break; + case NEW_SPOTLIGHT: + pick.entity = scene.Entity_CreateLight("spotlight", in_front_of_camera, XMFLOAT3(1, 1, 1), 2, 60); + scene.lights.GetComponent(pick.entity)->type = LightComponent::SPOT; + scene.lights.GetComponent(pick.entity)->intensity = 100; + break; + case NEW_DIRECTIONALLIGHT: + pick.entity = scene.Entity_CreateLight("dirlight", XMFLOAT3(0, 3, 0), XMFLOAT3(1, 1, 1), 2, 60); + scene.lights.GetComponent(pick.entity)->type = LightComponent::DIRECTIONAL; + scene.lights.GetComponent(pick.entity)->intensity = 10; + break; + case NEW_ENVIRONMENTPROBE: + pick.entity = scene.Entity_CreateEnvironmentProbe("envprobe", in_front_of_camera); + break; + case NEW_FORCE: + pick.entity = scene.Entity_CreateForce("force"); + break; + case NEW_DECAL: + pick.entity = scene.Entity_CreateDecal("decal", ""); + if (scene.materials.Contains(pick.entity)) + { + MaterialComponent* decal_material = scene.materials.GetComponent(pick.entity); + decal_material->textures[MaterialComponent::BASECOLORMAP].resource.SetTexture(*wi::texturehelper::getLogo()); + } + scene.transforms.GetComponent(pick.entity)->RotateRollPitchYaw(XMFLOAT3(XM_PIDIV2, 0, 0)); + break; + case NEW_SOUND: + { + wi::helper::FileDialogParams params; + params.type = wi::helper::FileDialogParams::OPEN; + params.description = "Sound"; + params.extensions = wi::resourcemanager::GetSupportedSoundExtensions(); + wi::helper::FileDialog(params, [=](std::string fileName) { + wi::eventhandler::Subscribe_Once(wi::eventhandler::EVENT_THREAD_SAFE_POINT, [=](uint64_t userdata) { + Entity entity = GetCurrentScene().Entity_CreateSound(wi::helper::GetFileNameFromPath(fileName), fileName); + + wi::Archive& archive = AdvanceHistory(); + archive << EditorComponent::HISTORYOP_ADD; + RecordSelection(archive); + + ClearSelected(); + AddSelected(entity); + + RecordSelection(archive); + RecordEntity(archive, entity); + + componentsWnd.RefreshEntityTree(); + componentsWnd.soundWnd.SetEntity(entity); + }); + }); + return; + } + break; + case NEW_VIDEO: + { + wi::helper::FileDialogParams params; + params.type = wi::helper::FileDialogParams::OPEN; + params.description = "Video"; + params.extensions = wi::resourcemanager::GetSupportedVideoExtensions(); + wi::helper::FileDialog(params, [=](std::string fileName) { + wi::eventhandler::Subscribe_Once(wi::eventhandler::EVENT_THREAD_SAFE_POINT, [=](uint64_t userdata) { + Entity entity = GetCurrentScene().Entity_CreateVideo(wi::helper::GetFileNameFromPath(fileName), fileName); + + wi::Archive& archive = AdvanceHistory(); + archive << EditorComponent::HISTORYOP_ADD; + RecordSelection(archive); + + ClearSelected(); + AddSelected(entity); + + RecordSelection(archive); + RecordEntity(archive, entity); + + componentsWnd.RefreshEntityTree(); + componentsWnd.videoWnd.SetEntity(entity); + }); + }); + return; + } + break; + case NEW_WEATHER: + pick.entity = CreateEntity(); + scene.weathers.Create(pick.entity); + scene.names.Create(pick.entity) = "weather"; + break; + case NEW_EMITTER: + pick.entity = scene.Entity_CreateEmitter("emitter"); + break; + case NEW_HAIR: + pick.entity = scene.Entity_CreateHair("hair"); + break; + case NEW_CAMERA: + pick.entity = scene.Entity_CreateCamera("camera", camera.width, camera.height); + *scene.cameras.GetComponent(pick.entity) = camera; + *scene.transforms.GetComponent(pick.entity) = editorscene.camera_transform; + break; + case NEW_CUBE: + pick.entity = scene.Entity_CreateCube("cube"); + pick.subsetIndex = 0; + break; + case NEW_PLANE: + pick.entity = scene.Entity_CreatePlane("plane"); + pick.subsetIndex = 0; + break; + case NEW_SPHERE: + pick.entity = scene.Entity_CreateSphere("sphere"); + pick.subsetIndex = 0; + break; + case NEW_ANIMATION: + pick.entity = CreateEntity(); + scene.animations.Create(pick.entity); + scene.names.Create(pick.entity) = "animation"; + break; + case NEW_SCRIPT: + pick.entity = CreateEntity(); + scene.scripts.Create(pick.entity); + scene.names.Create(pick.entity) = "script"; + break; + case NEW_COLLIDER: + pick.entity = CreateEntity(); + scene.colliders.Create(pick.entity); + scene.transforms.Create(pick.entity); + scene.names.Create(pick.entity) = "collider"; + break; + case NEW_TERRAIN: + componentsWnd.terrainWnd.entity = pick.entity; + componentsWnd.terrainWnd.SetupAssets(); + pick.entity = CreateEntity(); + scene.terrains.Create(pick.entity) = componentsWnd.terrainWnd.terrain_preset; + scene.names.Create(pick.entity) = "terrain"; + break; + case NEW_SPRITE: + { + pick.entity = CreateEntity(); + wi::Sprite& sprite = scene.sprites.Create(pick.entity); + sprite.params.pivot = XMFLOAT2(0.5f, 0.5f); + sprite.anim.repeatable = true; + scene.transforms.Create(pick.entity).Translate(XMFLOAT3(0, 2, 0)); + scene.names.Create(pick.entity) = "sprite"; + } + break; + case NEW_FONT: + { + pick.entity = CreateEntity(); + wi::SpriteFont& font = scene.fonts.Create(pick.entity); + font.SetText("Text"); + font.params.h_align = wi::font::Alignment::WIFALIGN_CENTER; + font.params.v_align = wi::font::Alignment::WIFALIGN_CENTER; + font.params.scaling = 0.1f; + font.params.size = 26; + font.anim.typewriter.looped = true; + scene.transforms.Create(pick.entity).Translate(XMFLOAT3(0, 2, 0)); + scene.names.Create(pick.entity) = "font"; + } + break; + case NEW_VOXELGRID: + { + pick.entity = CreateEntity(); + scene.voxel_grids.Create(pick.entity).init(64, 64, 64); + scene.transforms.Create(pick.entity).Scale(XMFLOAT3(0.25f, 0.25f, 0.25f)); + scene.names.Create(pick.entity) = "voxelgrid"; + } + break; + default: + break; + } + if (pick.entity != INVALID_ENTITY) + { + wi::Archive& archive = AdvanceHistory(); + archive << EditorComponent::HISTORYOP_ADD; + RecordSelection(archive); + + ClearSelected(); + AddSelected(pick); + + RecordSelection(archive); + RecordEntity(archive, pick.entity); + } + componentsWnd.RefreshEntityTree(); + }); + newEntityCombo.SetEnabled(true); + newEntityCombo.SetTooltip("Create a new entity"); + GetGUI().AddWidget(&newEntityCombo); translateButton.Create(ICON_TRANSLATE); rotateButton.Create(ICON_ROTATE); @@ -280,7 +560,7 @@ void EditorComponent::Load() dummyButton.Create(ICON_DUMMY); dummyButton.SetShadowRadius(2); - dummyButton.SetTooltip("Toggle reference dummy visualizer\n - Use the reference dummy to get an idea about object sizes compared to a human character size.\n - Position the dummy by clicking on something with the left mouse button while the dummy is active and nothing is selected.\n - Pressing this button while Ctrl key is held down will reset dummy position to the origin.\n - Pressing this button while the Shift key is held down will switch between male and female dummies."); + dummyButton.SetTooltip("Toggle reference dummy visualizer\n - Use the reference dummy to get an idea about object sizes compared to a human character size.\n - Position the dummy by clicking on something with the middle mouse button while the dummy is active.\n - Pressing this button while Ctrl key is held down will reset dummy position to the origin.\n - Pressing this button while the Shift key is held down will switch between male and female dummies."); dummyButton.SetLocalizationEnabled(wi::gui::LocalizationEnabled::Tooltip); dummyButton.OnClick([&](wi::gui::EventArgs args) { if (wi::input::Down(wi::input::KEYBOARD_BUTTON_LCONTROL) || wi::input::Down(wi::input::KEYBOARD_BUTTON_RCONTROL)) @@ -341,7 +621,7 @@ void EditorComponent::Load() }); } }); - GetGUI().AddWidget(&playButton); + topmenuWnd.AddWidget(&playButton); if (main->config.Has("last_script_path")) { @@ -359,7 +639,7 @@ void EditorComponent::Load() stopButton.OnClick([&](wi::gui::EventArgs args) { wi::lua::KillProcesses(); }); - GetGUI().AddWidget(&stopButton); + topmenuWnd.AddWidget(&stopButton); @@ -373,7 +653,7 @@ void EditorComponent::Load() saveButton.OnClick([&](wi::gui::EventArgs args) { SaveAs(); }); - GetGUI().AddWidget(&saveButton); + topmenuWnd.AddWidget(&saveButton); openButton.Create("Open"); @@ -418,7 +698,7 @@ void EditorComponent::Load() }); }); }); - GetGUI().AddWidget(&openButton); + topmenuWnd.AddWidget(&openButton); contentBrowserButton.Create("Content Browser"); @@ -435,7 +715,7 @@ void EditorComponent::Load() contentBrowserWnd.RefreshContent(); } }); - GetGUI().AddWidget(&contentBrowserButton); + topmenuWnd.AddWidget(&contentBrowserButton); logButton.Create("Backlog"); @@ -448,7 +728,7 @@ void EditorComponent::Load() logButton.OnClick([&](wi::gui::EventArgs args) { wi::backlog::Toggle(); }); - GetGUI().AddWidget(&logButton); + topmenuWnd.AddWidget(&logButton); profilerButton.Create("Profiler"); @@ -462,10 +742,10 @@ void EditorComponent::Load() profilerWnd.SetVisible(!wi::profiler::IsEnabled()); wi::profiler::SetEnabled(!wi::profiler::IsEnabled()); }); - GetGUI().AddWidget(&profilerButton); + topmenuWnd.AddWidget(&profilerButton); - cinemaButton.Create("Cinema"); + cinemaButton.Create(ICON_CINEMA_MODE); cinemaButton.SetLocalizationEnabled(wi::gui::LocalizationEnabled::Tooltip); cinemaButton.SetShadowRadius(2); cinemaButton.font.params.shadowColor = wi::Color::Transparent(); @@ -523,7 +803,7 @@ void EditorComponent::Load() }); }); - GetGUI().AddWidget(&fullscreenButton); + topmenuWnd.AddWidget(&fullscreenButton); bugButton.Create("Bug report"); @@ -536,7 +816,7 @@ void EditorComponent::Load() bugButton.OnClick([](wi::gui::EventArgs args) { wi::helper::OpenUrl("https://github.com/turanszkij/WickedEngine/issues/new"); }); - GetGUI().AddWidget(&bugButton); + topmenuWnd.AddWidget(&bugButton); aboutButton.Create("About"); @@ -549,7 +829,7 @@ void EditorComponent::Load() aboutButton.OnClick([&](wi::gui::EventArgs args) { aboutWindow.SetVisible(!aboutWindow.IsVisible()); }); - GetGUI().AddWidget(&aboutButton); + topmenuWnd.AddWidget(&aboutButton); { std::string ss; @@ -561,9 +841,9 @@ void EditorComponent::Load() ss += "\n\nControls\n"; ss += "------------\n"; ss += "Move camera: WASD, or Contoller left stick or D-pad\n"; - ss += "Look: Middle mouse button / arrow keys / controller right stick\n"; - ss += "Select: Right mouse button\n"; - ss += "Interact with physics/water: Left mouse button when nothing is selected\n"; + ss += "Look: Right mouse button / arrow keys / controller right stick\n"; + ss += "Select: Left mouse button\n"; + ss += "Interact with physics/water/grass: Middle mouse button\n"; ss += "Faster camera: Left Shift button or controller R2/RT\n"; ss += "Snap transform: Left Ctrl (hold while transforming)\n"; ss += "Camera up: E\n"; @@ -637,25 +917,6 @@ void EditorComponent::Load() aboutWindow.sprites[i].params.corners_rounding[1].radius = 10; aboutWindow.sprites[i].params.corners_rounding[2].radius = 10; aboutWindow.sprites[i].params.corners_rounding[3].radius = 10; - aboutWindow.resizeDragger_UpperLeft.sprites[i].params.enableCornerRounding(); - aboutWindow.resizeDragger_UpperLeft.sprites[i].params.corners_rounding[0].radius = 10; - aboutWindow.resizeDragger_UpperRight.sprites[i].params.enableCornerRounding(); - aboutWindow.resizeDragger_UpperRight.sprites[i].params.corners_rounding[1].radius = 10; - aboutWindow.resizeDragger_BottomLeft.sprites[i].params.enableCornerRounding(); - aboutWindow.resizeDragger_BottomLeft.sprites[i].params.corners_rounding[2].radius = 10; - aboutWindow.resizeDragger_BottomRight.sprites[i].params.enableCornerRounding(); - aboutWindow.resizeDragger_BottomRight.sprites[i].params.corners_rounding[3].radius = 10; - - if (aboutWindow.IsCollapsed()) - { - aboutWindow.resizeDragger_UpperLeft.sprites[i].params.corners_rounding[2].radius = 10; - aboutWindow.resizeDragger_UpperRight.sprites[i].params.corners_rounding[3].radius = 10; - } - else - { - aboutWindow.resizeDragger_UpperLeft.sprites[i].params.corners_rounding[2].radius = 0; - aboutWindow.resizeDragger_UpperRight.sprites[i].params.corners_rounding[3].radius = 0; - } } }); GetGUI().AddWidget(&aboutWindow); @@ -671,10 +932,7 @@ void EditorComponent::Load() exitButton.OnClick([this](wi::gui::EventArgs args) { wi::platform::Exit(); }); - GetGUI().AddWidget(&exitButton); - - optionsWnd.Create(this); - GetGUI().AddWidget(&optionsWnd); + topmenuWnd.AddWidget(&exitButton); componentsWnd.Create(this); GetGUI().AddWidget(&componentsWnd); @@ -688,31 +946,31 @@ void EditorComponent::Load() std::string theme = main->config.GetSection("options").GetText("theme"); if(theme.empty()) { - optionsWnd.generalWnd.themeCombo.SetSelected(0); + generalWnd.themeCombo.SetSelected(0); } else if (!theme.compare("Dark")) { - optionsWnd.generalWnd.themeCombo.SetSelected(0); + generalWnd.themeCombo.SetSelected(0); } else if (!theme.compare("Bright")) { - optionsWnd.generalWnd.themeCombo.SetSelected(1); + generalWnd.themeCombo.SetSelected(1); } else if (!theme.compare("Soft")) { - optionsWnd.generalWnd.themeCombo.SetSelected(2); + generalWnd.themeCombo.SetSelected(2); } else if (!theme.compare("Hacking")) { - optionsWnd.generalWnd.themeCombo.SetSelected(3); + generalWnd.themeCombo.SetSelected(3); } else if (!theme.compare("Nord")) { - optionsWnd.generalWnd.themeCombo.SetSelected(4); + generalWnd.themeCombo.SetSelected(4); } SetDefaultLocalization(); - optionsWnd.generalWnd.RefreshLanguageSelectionAfterWholeGUIWasInitialized(); + generalWnd.RefreshLanguageSelectionAfterWholeGUIWasInitialized(); auto load_font = [this](std::string filename) { font_datas.emplace_back().name = filename; @@ -786,6 +1044,8 @@ void EditorComponent::Update(float dt) } } + loadmodel_font.SetHidden(!wi::jobsystem::IsBusy(loadmodel_workload)); + Scene& scene = GetCurrentScene(); EditorScene& editorscene = GetCurrentEditorScene(); CameraComponent& camera = editorscene.camera; @@ -797,14 +1057,15 @@ void EditorComponent::Update(float dt) scene.Entity_Remove(grass_interaction_entity); } - optionsWnd.Update(dt); + cameraWnd.Update(); + paintToolWnd.Update(dt); + graphicsWnd.Update(); componentsWnd.Update(dt); // Pulsating selection color update: outlineTimer += dt; CheckBonePickingEnabled(); - UpdateTopMenuAnimation(); save_text_alpha = std::max(0.0f, save_text_alpha - std::min(dt, 0.033f)); // after saving, dt can become huge @@ -826,35 +1087,41 @@ void EditorComponent::Update(float dt) } } - translator.interactable = false; - // Camera control: if (!wi::backlog::isActive() && !GetGUI().HasFocus()) { + if (paintToolWnd.GetMode() == PaintToolWindow::MODE::MODE_DISABLED) + { + translator.Update(camera, currentMouse, *renderPath); + } + + // This check whether pressing left mouse can modify selection: + const bool leftmouse_select = + !translator.IsInteracting() && // translator shouldn't be active + paintToolWnd.GetMode() == PaintToolWindow::MODE::MODE_DISABLED && // paint tool shouldn't be active + (!componentsWnd.decalWnd.IsEnabled() || !componentsWnd.decalWnd.placementCheckBox.GetCheck()) && // decal placement shouldn't be active + !(wi::input::Down(wi::input::KEYBOARD_BUTTON_LCONTROL) && wi::input::Down(wi::input::KEYBOARD_BUTTON_LSHIFT)) && // instance placement shouldn't be active + wi::input::Press(wi::input::MOUSE_BUTTON_LEFT); + deleting = wi::input::Press(wi::input::KEYBOARD_BUTTON_DELETE); - translator.interactable = true; - XMFLOAT4 currentMouse = wi::input::GetPointer(); - static XMFLOAT4 originalMouse = XMFLOAT4(0, 0, 0, 0); - static bool camControlStart = true; + currentMouse = wi::input::GetPointer(); if (camControlStart) { - originalMouse = wi::input::GetPointer(); + originalMouse = currentMouse; } + // After originalMouse is saved, currentMouse is remapped inside 3D viewport: + // originalMouse shouldn't be remapped, because that will be used to reset mouse position + currentMouse.x -= renderPath->PhysicalToLogical((uint32_t)viewport3D.top_left_x); + currentMouse.y -= renderPath->PhysicalToLogical((uint32_t)viewport3D.top_left_y); + float xDif = 0, yDif = 0; - if (wi::input::Down(wi::input::MOUSE_BUTTON_MIDDLE)) + if (wi::input::Down(wi::input::MOUSE_BUTTON_RIGHT)) { camControlStart = false; -#if 0 - // Mouse delta from previous frame: - xDif = currentMouse.x - originalMouse.x; - yDif = currentMouse.y - originalMouse.y; -#else - // Mouse delta from hardware read: xDif = wi::input::GetMouseState().delta_position.x; yDif = wi::input::GetMouseState().delta_position.y; -#endif xDif = 0.1f * xDif * (1.0f / 60.0f); yDif = 0.1f * yDif * (1.0f / 60.0f); wi::input::SetPointer(originalMouse); @@ -892,16 +1159,16 @@ void EditorComponent::Update(float dt) xDif += rightStick.x * jostickrotspeed; yDif += rightStick.y * jostickrotspeed; - xDif *= optionsWnd.cameraWnd.rotationspeedSlider.GetValue(); - yDif *= optionsWnd.cameraWnd.rotationspeedSlider.GetValue(); + xDif *= cameraWnd.rotationspeedSlider.GetValue(); + yDif *= cameraWnd.rotationspeedSlider.GetValue(); - if (optionsWnd.cameraWnd.fpsCheckBox.GetCheck()) + if (cameraWnd.fpsCheckBox.GetCheck()) { // FPS Camera const float clampedDT = std::min(dt, 0.1f); // if dt > 100 millisec, don't allow the camera to jump too far... - const float speed = ((wi::input::Down(wi::input::KEYBOARD_BUTTON_LSHIFT) ? 10.0f : 1.0f) + rightTrigger.x * 10.0f) * optionsWnd.cameraWnd.movespeedSlider.GetValue() * clampedDT; + const float speed = ((wi::input::Down(wi::input::KEYBOARD_BUTTON_LSHIFT) ? 10.0f : 1.0f) + rightTrigger.x * 10.0f) * cameraWnd.movespeedSlider.GetValue() * clampedDT; XMVECTOR move = XMLoadFloat3(&editorscene.cam_move); XMVECTOR moveNew = XMVectorSet(0, 0, 0, 0); @@ -919,7 +1186,7 @@ void EditorComponent::Update(float dt) moveNew += XMVectorSet(leftStick.x, 0, leftStick.y, 0); moveNew *= speed; - move = XMVectorLerp(move, moveNew, optionsWnd.cameraWnd.accelerationSlider.GetValue() * clampedDT / 0.0166f); // smooth the movement a bit + move = XMVectorLerp(move, moveNew, cameraWnd.accelerationSlider.GetValue() * clampedDT / 0.0166f); // smooth the movement a bit float moveLength = XMVectorGetX(XMVector3Length(move)); if (moveLength < 0.0001f) @@ -976,11 +1243,11 @@ void EditorComponent::Update(float dt) inspector_mode = wi::input::Down((wi::input::BUTTON)'I'); // Begin picking: - pickRay = wi::renderer::GetPickRay((long)currentMouse.x, (long)currentMouse.y, *this, camera); + pickRay = wi::renderer::GetPickRay((long)currentMouse.x, (long)currentMouse.y, *renderPath, camera); { hovered = wi::scene::PickResult(); - if (has_flag(optionsWnd.filter, OptionsWindow::Filter::Light)) + if (has_flag(componentsWnd.filter, ComponentsWindow::Filter::Light)) { for (size_t i = 0; i < scene.lights.GetCount(); ++i) { @@ -1030,7 +1297,7 @@ void EditorComponent::Update(float dt) } } } - if (has_flag(optionsWnd.filter, OptionsWindow::Filter::Decal)) + if (has_flag(componentsWnd.filter, ComponentsWindow::Filter::Decal)) { for (size_t i = 0; i < scene.decals.GetCount(); ++i) { @@ -1049,7 +1316,7 @@ void EditorComponent::Update(float dt) } } } - if (has_flag(optionsWnd.filter, OptionsWindow::Filter::Force)) + if (has_flag(componentsWnd.filter, ComponentsWindow::Filter::Force)) { for (size_t i = 0; i < scene.forces.GetCount(); ++i) { @@ -1068,7 +1335,7 @@ void EditorComponent::Update(float dt) } } } - if (has_flag(optionsWnd.filter, OptionsWindow::Filter::Emitter)) + if (has_flag(componentsWnd.filter, ComponentsWindow::Filter::Emitter)) { for (size_t i = 0; i < scene.emitters.GetCount(); ++i) { @@ -1087,7 +1354,7 @@ void EditorComponent::Update(float dt) } } } - if (has_flag(optionsWnd.filter, OptionsWindow::Filter::Hairparticle)) + if (has_flag(componentsWnd.filter, ComponentsWindow::Filter::Hairparticle)) { for (size_t i = 0; i < scene.hairs.GetCount(); ++i) { @@ -1106,7 +1373,7 @@ void EditorComponent::Update(float dt) } } } - if (has_flag(optionsWnd.filter, OptionsWindow::Filter::EnvironmentProbe)) + if (has_flag(componentsWnd.filter, ComponentsWindow::Filter::EnvironmentProbe)) { for (size_t i = 0; i < scene.probes.GetCount(); ++i) { @@ -1127,7 +1394,7 @@ void EditorComponent::Update(float dt) } } } - if (has_flag(optionsWnd.filter, OptionsWindow::Filter::Camera)) + if (has_flag(componentsWnd.filter, ComponentsWindow::Filter::Camera)) { for (size_t i = 0; i < scene.cameras.GetCount(); ++i) { @@ -1146,7 +1413,7 @@ void EditorComponent::Update(float dt) } } } - if (has_flag(optionsWnd.filter, OptionsWindow::Filter::Armature)) + if (has_flag(componentsWnd.filter, ComponentsWindow::Filter::Armature)) { for (size_t i = 0; i < scene.armatures.GetCount(); ++i) { @@ -1165,7 +1432,7 @@ void EditorComponent::Update(float dt) } } } - if (has_flag(optionsWnd.filter, OptionsWindow::Filter::Sound)) + if (has_flag(componentsWnd.filter, ComponentsWindow::Filter::Sound)) { for (size_t i = 0; i < scene.sounds.GetCount(); ++i) { @@ -1184,7 +1451,7 @@ void EditorComponent::Update(float dt) } } } - if (has_flag(optionsWnd.filter, OptionsWindow::Filter::Video)) + if (has_flag(componentsWnd.filter, ComponentsWindow::Filter::Video)) { for (size_t i = 0; i < scene.videos.GetCount(); ++i) { @@ -1203,7 +1470,7 @@ void EditorComponent::Update(float dt) } } } - if (has_flag(optionsWnd.filter, OptionsWindow::Filter::VoxelGrid)) + if (has_flag(componentsWnd.filter, ComponentsWindow::Filter::VoxelGrid)) { for (size_t i = 0; i < scene.voxel_grids.GetCount(); ++i) { @@ -1307,14 +1574,16 @@ void EditorComponent::Update(float dt) if (hovered.entity == INVALID_ENTITY) { // Object picking only when mouse button down, because it can be slow with high polycount - if ( - wi::input::Down(wi::input::MOUSE_BUTTON_LEFT) || - wi::input::Down(wi::input::MOUSE_BUTTON_RIGHT) || - optionsWnd.paintToolWnd.GetMode() != PaintToolWindow::MODE_DISABLED || - inspector_mode - ) + if (!translator.IsInteracting() && paintToolWnd.GetMode() == PaintToolWindow::MODE_DISABLED) { - hovered = wi::scene::Pick(pickRay, wi::enums::FILTER_OBJECT_ALL, ~0u, scene); + if ( + wi::input::Down(wi::input::MOUSE_BUTTON_LEFT) || + wi::input::Down(wi::input::MOUSE_BUTTON_MIDDLE) || + inspector_mode + ) + { + hovered = wi::scene::Pick(pickRay, wi::enums::FILTER_OBJECT_ALL, ~0u, scene); + } } } } @@ -1325,16 +1594,16 @@ void EditorComponent::Update(float dt) { camera.focal_length = hovered.distance; camera.SetDirty(); - optionsWnd.cameraWnd.focalLengthSlider.SetValue(camera.focal_length); + cameraWnd.focalLengthSlider.SetValue(camera.focal_length); + hovered = {}; } - // Interactions only when paint tool is disabled: - if (optionsWnd.paintToolWnd.GetMode() == PaintToolWindow::MODE_DISABLED) + // Interactions: { // Interact: if (wi::input::Down((wi::input::BUTTON)'P')) { - if (wi::input::Press(wi::input::MOUSE_BUTTON_LEFT)) + if (wi::input::Press(wi::input::MOUSE_BUTTON_MIDDLE)) { // Physics impulse tester: wi::physics::RayIntersectionResult result = wi::physics::Intersects(scene, pickRay); @@ -1367,7 +1636,7 @@ void EditorComponent::Update(float dt) else { // Physics pick dragger: - if (wi::input::Down(wi::input::MOUSE_BUTTON_LEFT)) + if (wi::input::Down(wi::input::MOUSE_BUTTON_MIDDLE)) { wi::physics::PickDrag(scene, pickRay, physicsDragOp); } @@ -1377,10 +1646,40 @@ void EditorComponent::Update(float dt) } } - // Other: - if (hovered.entity != INVALID_ENTITY && wi::input::Down(wi::input::MOUSE_BUTTON_LEFT)) + // Decal placement: + if (componentsWnd.decalWnd.IsEnabled() && componentsWnd.decalWnd.placementCheckBox.GetCheck() && wi::input::Press(wi::input::MOUSE_BUTTON_LEFT)) { - if (dummy_enabled && translator.selected.empty()) + // if not water, put a decal on it: + Entity entity = scene.Entity_CreateDecal("editorDecal", ""); + // material and decal parameters will be copied from selected: + if (scene.decals.Contains(componentsWnd.decalWnd.entity)) + { + *scene.decals.GetComponent(entity) = *scene.decals.GetComponent(componentsWnd.decalWnd.entity); + } + if (scene.materials.Contains(componentsWnd.decalWnd.entity)) + { + *scene.materials.GetComponent(entity) = *scene.materials.GetComponent(componentsWnd.decalWnd.entity); + } + // place it on picked surface: + TransformComponent& transform = *scene.transforms.GetComponent(entity); + transform.MatrixTransform(hovered.orientation); + transform.RotateRollPitchYaw(XMFLOAT3(XM_PIDIV2, 0, 0)); + scene.Component_Attach(entity, hovered.entity); + + wi::Archive& archive = AdvanceHistory(); + archive << EditorComponent::HISTORYOP_ADD; + RecordSelection(archive); + RecordSelection(archive); + RecordEntity(archive, entity); + + componentsWnd.RefreshEntityTree(); + hovered = {}; + } + + // Other: + if (hovered.entity != INVALID_ENTITY && wi::input::Down(wi::input::MOUSE_BUTTON_MIDDLE)) + { + if (dummy_enabled) { dummy_pos = hovered.position; } @@ -1389,39 +1688,12 @@ void EditorComponent::Update(float dt) const ObjectComponent* object = scene.objects.GetComponent(hovered.entity); if (object != nullptr) { - if (translator.selected.empty() && object->GetFilterMask() & wi::enums::FILTER_WATER) + if (object->GetFilterMask() & wi::enums::FILTER_WATER) { // if water, then put a water ripple onto it: scene.PutWaterRipple(hovered.position); } - else if (componentsWnd.decalWnd.IsEnabled() && componentsWnd.decalWnd.placementCheckBox.GetCheck() && wi::input::Press(wi::input::MOUSE_BUTTON_LEFT)) - { - // if not water, put a decal on it: - Entity entity = scene.Entity_CreateDecal("editorDecal", ""); - // material and decal parameters will be copied from selected: - if (scene.decals.Contains(componentsWnd.decalWnd.entity)) - { - *scene.decals.GetComponent(entity) = *scene.decals.GetComponent(componentsWnd.decalWnd.entity); - } - if (scene.materials.Contains(componentsWnd.decalWnd.entity)) - { - *scene.materials.GetComponent(entity) = *scene.materials.GetComponent(componentsWnd.decalWnd.entity); - } - // place it on picked surface: - TransformComponent& transform = *scene.transforms.GetComponent(entity); - transform.MatrixTransform(hovered.orientation); - transform.RotateRollPitchYaw(XMFLOAT3(XM_PIDIV2, 0, 0)); - scene.Component_Attach(entity, hovered.entity); - - wi::Archive& archive = AdvanceHistory(); - archive << EditorComponent::HISTORYOP_ADD; - RecordSelection(archive); - RecordSelection(archive); - RecordEntity(archive, entity); - - optionsWnd.RefreshEntityTree(); - } - else if (translator.selected.empty()) + else { // Check for interactive grass (hair particle that is child of hovered object: for (size_t i = 0; i < scene.hairs.GetCount(); ++i) @@ -1453,9 +1725,8 @@ void EditorComponent::Update(float dt) } // Select... - if (wi::input::Press(wi::input::MOUSE_BUTTON_RIGHT) || selectAll || clear_selected) + if (leftmouse_select || selectAll || clear_selected) { - wi::Archive& archive = AdvanceHistory(); archive << HISTORYOP_SELECTION; // record PREVIOUS selection state... @@ -1510,7 +1781,7 @@ void EditorComponent::Update(float dt) // record NEW selection state... RecordSelection(archive); - optionsWnd.RefreshEntityTree(); + componentsWnd.RefreshEntityTree(); } } @@ -1529,7 +1800,7 @@ void EditorComponent::Update(float dt) if (wi::input::Press((wi::input::BUTTON)'W')) { wi::renderer::SetWireRender(!wi::renderer::IsWireRender()); - optionsWnd.generalWnd.wireFrameCheckBox.SetCheck(wi::renderer::IsWireRender()); + generalWnd.wireFrameCheckBox.SetCheck(wi::renderer::IsWireRender()); } // Enable transform tool if (wi::input::Press((wi::input::BUTTON)'T')) @@ -1596,7 +1867,7 @@ void EditorComponent::Update(float dt) RecordSelection(archive); RecordEntity(archive, addedEntities); - optionsWnd.RefreshEntityTree(); + componentsWnd.RefreshEntityTree(); } // Duplicate Instances if (wi::input::Press((wi::input::BUTTON)'D')) @@ -1624,7 +1895,7 @@ void EditorComponent::Update(float dt) RecordSelection(archive); RecordEntity(archive, addedEntities); - optionsWnd.RefreshEntityTree(); + componentsWnd.RefreshEntityTree(); } // Put Instances if (clipboard.IsOpen() && hovered.subsetIndex >= 0 && wi::input::Down(wi::input::KEYBOARD_BUTTON_LSHIFT) && wi::input::Press(wi::input::MOUSE_BUTTON_LEFT)) @@ -1670,7 +1941,7 @@ void EditorComponent::Update(float dt) RecordSelection(archive); RecordEntity(archive, addedEntities); - optionsWnd.RefreshEntityTree(); + componentsWnd.RefreshEntityTree(); } // Undo if (wi::input::Press((wi::input::BUTTON)'Z') && @@ -1679,7 +1950,7 @@ void EditorComponent::Update(float dt) { ConsumeHistoryOperation(true); - optionsWnd.RefreshEntityTree(); + componentsWnd.RefreshEntityTree(); } // Redo if (wi::input::Press((wi::input::BUTTON)'Y') || @@ -1689,7 +1960,7 @@ void EditorComponent::Update(float dt) { ConsumeHistoryOperation(false); - optionsWnd.RefreshEntityTree(); + componentsWnd.RefreshEntityTree(); } } @@ -1736,13 +2007,13 @@ void EditorComponent::Update(float dt) ClearSelected(); - optionsWnd.RefreshEntityTree(); + componentsWnd.RefreshEntityTree(); } // Update window data bindings... if (translator.selected.empty()) { - optionsWnd.cameraWnd.SetEntity(INVALID_ENTITY); + cameraWnd.SetEntity(INVALID_ENTITY); componentsWnd.objectWnd.SetEntity(INVALID_ENTITY); componentsWnd.emitterWnd.SetEntity(INVALID_ENTITY); componentsWnd.hairWnd.SetEntity(INVALID_ENTITY); @@ -1780,7 +2051,7 @@ void EditorComponent::Update(float dt) const wi::scene::PickResult& picked = translator.selected.back(); assert(picked.entity != INVALID_ENTITY); - optionsWnd.cameraWnd.SetEntity(picked.entity); + cameraWnd.SetEntity(picked.entity); componentsWnd.emitterWnd.SetEntity(picked.entity); componentsWnd.hairWnd.SetEntity(picked.entity); componentsWnd.lightWnd.SetEntity(picked.entity); @@ -1923,19 +2194,19 @@ void EditorComponent::Update(float dt) componentsWnd.hairWnd.UpdateData(); // Follow camera proxy: - if (optionsWnd.cameraWnd.followCheckBox.IsEnabled() && optionsWnd.cameraWnd.followCheckBox.GetCheck()) + if (cameraWnd.followCheckBox.IsEnabled() && cameraWnd.followCheckBox.GetCheck()) { - TransformComponent* proxy = scene.transforms.GetComponent(optionsWnd.cameraWnd.entity); + TransformComponent* proxy = scene.transforms.GetComponent(cameraWnd.entity); if (proxy != nullptr) { - editorscene.camera_transform.Lerp(editorscene.camera_transform, *proxy, 1.0f - optionsWnd.cameraWnd.followSlider.GetValue()); + editorscene.camera_transform.Lerp(editorscene.camera_transform, *proxy, 1.0f - cameraWnd.followSlider.GetValue()); editorscene.camera_transform.UpdateTransform(); } - CameraComponent* proxy_camera = scene.cameras.GetComponent(optionsWnd.cameraWnd.entity); + CameraComponent* proxy_camera = scene.cameras.GetComponent(cameraWnd.entity); if (proxy_camera != nullptr) { - editorscene.camera.Lerp(editorscene.camera, *proxy_camera, 1.0f - optionsWnd.cameraWnd.followSlider.GetValue()); + editorscene.camera.Lerp(editorscene.camera, *proxy_camera, 1.0f - cameraWnd.followSlider.GetValue()); } } @@ -1945,7 +2216,7 @@ void EditorComponent::Update(float dt) wi::RenderPath3D_PathTracing* pathtracer = dynamic_cast(renderPath.get()); if (pathtracer != nullptr) { - pathtracer->setTargetSampleCount((int)optionsWnd.graphicsWnd.pathTraceTargetSlider.GetValue()); + pathtracer->setTargetSampleCount((int)graphicsWnd.pathTraceTargetSlider.GetValue()); std::string ss; ss += "Sample count: " + std::to_string(pathtracer->getCurrentSampleCount()) + "\n"; @@ -1961,18 +2232,16 @@ void EditorComponent::Update(float dt) { ss += "Denoiser not available!\nTo find out how to enable the denoiser, visit the documentation."; } - optionsWnd.graphicsWnd.pathTraceStatisticsLabel.SetText(ss); + graphicsWnd.pathTraceStatisticsLabel.SetText(ss); } wi::profiler::EndRange(profrange); RenderPath2D::Update(dt); - if (optionsWnd.paintToolWnd.GetMode() == PaintToolWindow::MODE::MODE_DISABLED) - { - translator.Update(camera, *this); - } + UpdateDynamicWidgets(); + ResizeViewport3D(); renderPath->colorspace = colorspace; renderPath->Update(dt); @@ -2065,7 +2334,7 @@ void EditorComponent::Update(float dt) } else { - wi::renderer::SetToDrawDebugColliders(optionsWnd.generalWnd.colliderVisCheckBox.GetCheck()); + wi::renderer::SetToDrawDebugColliders(generalWnd.colliderVisCheckBox.GetCheck()); } if (force_spring_visualizer) { @@ -2073,7 +2342,7 @@ void EditorComponent::Update(float dt) } else { - wi::renderer::SetToDrawDebugSprings(optionsWnd.generalWnd.springVisCheckBox.GetCheck()); + wi::renderer::SetToDrawDebugSprings(generalWnd.springVisCheckBox.GetCheck()); } } void EditorComponent::PostUpdate() @@ -2509,7 +2778,7 @@ void EditorComponent::Render() const fp.shadowColor = backgroundEntityColor; fp.shadow_softness = 1; - if (has_flag(optionsWnd.filter, OptionsWindow::Filter::Light)) + if (has_flag(componentsWnd.filter, ComponentsWindow::Filter::Light)) { for (size_t i = 0; i < scene.lights.GetCount(); ++i) { @@ -2657,7 +2926,7 @@ void EditorComponent::Render() const } } - if (has_flag(optionsWnd.filter, OptionsWindow::Filter::Decal)) + if (has_flag(componentsWnd.filter, ComponentsWindow::Filter::Decal)) { for (size_t i = 0; i < scene.decals.GetCount(); ++i) { @@ -2689,7 +2958,7 @@ void EditorComponent::Render() const } } - if (has_flag(optionsWnd.filter, OptionsWindow::Filter::Force)) + if (has_flag(componentsWnd.filter, ComponentsWindow::Filter::Force)) { for (size_t i = 0; i < scene.forces.GetCount(); ++i) { @@ -2720,7 +2989,7 @@ void EditorComponent::Render() const } } - if (has_flag(optionsWnd.filter, OptionsWindow::Filter::Camera)) + if (has_flag(componentsWnd.filter, ComponentsWindow::Filter::Camera)) { for (size_t i = 0; i < scene.cameras.GetCount(); ++i) { @@ -2751,7 +3020,7 @@ void EditorComponent::Render() const } } - if (has_flag(optionsWnd.filter, OptionsWindow::Filter::Armature)) + if (has_flag(componentsWnd.filter, ComponentsWindow::Filter::Armature)) { for (size_t i = 0; i < scene.armatures.GetCount(); ++i) { @@ -2782,7 +3051,7 @@ void EditorComponent::Render() const } } - if (has_flag(optionsWnd.filter, OptionsWindow::Filter::Emitter)) + if (has_flag(componentsWnd.filter, ComponentsWindow::Filter::Emitter)) { for (size_t i = 0; i < scene.emitters.GetCount(); ++i) { @@ -2813,7 +3082,7 @@ void EditorComponent::Render() const } } - if (has_flag(optionsWnd.filter, OptionsWindow::Filter::Hairparticle)) + if (has_flag(componentsWnd.filter, ComponentsWindow::Filter::Hairparticle)) { for (size_t i = 0; i < scene.hairs.GetCount(); ++i) { @@ -2844,7 +3113,7 @@ void EditorComponent::Render() const } } - if (has_flag(optionsWnd.filter, OptionsWindow::Filter::Sound)) + if (has_flag(componentsWnd.filter, ComponentsWindow::Filter::Sound)) { for (size_t i = 0; i < scene.sounds.GetCount(); ++i) { @@ -2874,7 +3143,7 @@ void EditorComponent::Render() const wi::font::Draw(ICON_SOUND, fp, cmd); } } - if (has_flag(optionsWnd.filter, OptionsWindow::Filter::Video)) + if (has_flag(componentsWnd.filter, ComponentsWindow::Filter::Video)) { for (size_t i = 0; i < scene.videos.GetCount(); ++i) { @@ -2904,7 +3173,7 @@ void EditorComponent::Render() const wi::font::Draw(ICON_VIDEO, fp, cmd); } } - if (has_flag(optionsWnd.filter, OptionsWindow::Filter::VoxelGrid)) + if (has_flag(componentsWnd.filter, ComponentsWindow::Filter::VoxelGrid)) { for (size_t i = 0; i < scene.voxel_grids.GetCount(); ++i) { @@ -3081,7 +3350,7 @@ void EditorComponent::Render() const } } - color.w *= optionsWnd.generalWnd.bonePickerOpacitySlider.GetValue(); + color.w *= generalWnd.bonePickerOpacitySlider.GetValue(); XMVECTOR Base = XMLoadFloat3(&capsule.base); XMVECTOR Tip = XMLoadFloat3(&capsule.tip); @@ -3164,7 +3433,7 @@ void EditorComponent::Render() const } } - if (optionsWnd.generalWnd.nameDebugCheckBox.GetCheck()) + if (generalWnd.nameDebugCheckBox.GetCheck()) { device->EventBegin("Debug Names", cmd); struct DebugNameEntitySorter @@ -3242,11 +3511,10 @@ void EditorComponent::Render() const wi::font::Draw(str, params, cmd); } - - optionsWnd.paintToolWnd.DrawBrush(*this, cmd); - if (optionsWnd.paintToolWnd.GetMode() == PaintToolWindow::MODE::MODE_DISABLED) + paintToolWnd.DrawBrush(*this, cmd); + if (paintToolWnd.GetMode() == PaintToolWindow::MODE::MODE_DISABLED) { - translator.Draw(GetCurrentEditorScene().camera, cmd); + translator.Draw(GetCurrentEditorScene().camera, currentMouse, cmd); } device->RenderPassEnd(cmd); @@ -3260,8 +3528,16 @@ void EditorComponent::Render() const } void EditorComponent::Compose(CommandList cmd) const { + GetDevice()->BindViewports(1, &viewport3D, cmd); renderPath->Compose(cmd); + Viewport vp; + vp.top_left_x = 0; + vp.top_left_y = 0; + vp.width = (float)GetPhysicalWidth(); + vp.height = (float)GetPhysicalHeight(); + GetDevice()->BindViewports(1, &vp, cmd); + RenderPath2D::Compose(cmd); if (save_text_alpha > 0) @@ -3296,6 +3572,152 @@ void EditorComponent::Compose(CommandList cmd) const #endif // TERRAIN_VIRTUAL_TEXTURE_DEBUG } +void EditorComponent::ResizeViewport3D() +{ + int width = GetPhysicalWidth(); + int height = GetPhysicalHeight(); + if (GetGUI().IsVisible()) + { + if (componentsWnd.IsVisible()) + { + width -= LogicalToPhysical(componentsWnd.scale_local.x); + } + if (generalWnd.IsVisible()) + { + width -= LogicalToPhysical(generalWnd.scale_local.x); + } + if (graphicsWnd.IsVisible()) + { + width -= LogicalToPhysical(graphicsWnd.scale_local.x); + } + if (cameraWnd.IsVisible()) + { + width -= LogicalToPhysical(cameraWnd.scale_local.x); + } + if (materialPickerWnd.IsVisible()) + { + width -= LogicalToPhysical(materialPickerWnd.scale_local.x); + } + if (paintToolWnd.IsVisible()) + { + width -= LogicalToPhysical(paintToolWnd.scale_local.x); + } + height -= LogicalToPhysical(topmenuWnd.scale_local.y); + } + width = std::max(64, width); + height = std::max(64, height); + if (renderPath->width == width && renderPath->height == height) + { + if (GetGUI().IsVisible()) + { + main->infoDisplay.rect.from_viewport(viewport3D); + main->infoDisplay.rect.left = LogicalToPhysical(generalButton.translation_local.x + generalButton.scale_local.x + 10); + } + loadmodel_font.params.posX = PhysicalToLogical(uint32_t(viewport3D.top_left_x + viewport3D.width * 0.5f)); + loadmodel_font.params.posX -= wi::font::TextWidth(loadmodel_font.GetText(), loadmodel_font.params) * 0.5f; + loadmodel_font.params.posY = PhysicalToLogical(uint32_t(viewport3D.top_left_y)) + 15; + return; + } + + renderPath->width = width; + renderPath->height = height; + renderPath->dpi = dpi; + renderPath->scaling = scaling; + renderPath->ResizeBuffers(); + + viewport3D.top_left_x = 0; + viewport3D.top_left_y = 0; + if (GetGUI().IsVisible()) + { + if (generalWnd.IsVisible()) + { + viewport3D.top_left_x = (float)LogicalToPhysical(generalWnd.scale_local.x); + } + if (graphicsWnd.IsVisible()) + { + viewport3D.top_left_x = (float)LogicalToPhysical(graphicsWnd.scale_local.x); + } + if (cameraWnd.IsVisible()) + { + viewport3D.top_left_x = (float)LogicalToPhysical(cameraWnd.scale_local.x); + } + if (materialPickerWnd.IsVisible()) + { + viewport3D.top_left_x = (float)LogicalToPhysical(materialPickerWnd.scale_local.x); + } + if (paintToolWnd.IsVisible()) + { + viewport3D.top_left_x = (float)LogicalToPhysical(paintToolWnd.scale_local.x); + } + viewport3D.top_left_y = (float)LogicalToPhysical(topmenuWnd.scale_local.y); + } + viewport3D.width = (float)renderPath->width; + viewport3D.height = (float)renderPath->height; + + if (GetGUI().IsVisible()) + { + main->infoDisplay.rect.from_viewport(viewport3D); + main->infoDisplay.rect.left = LogicalToPhysical(generalButton.translation_local.x + generalButton.scale_local.x + 10); + } + + loadmodel_font.params.posX = PhysicalToLogical(uint32_t(viewport3D.top_left_x + viewport3D.width * 0.5f)); + loadmodel_font.params.posX -= wi::font::TextWidth(loadmodel_font.GetText(), loadmodel_font.params) * 0.5f; + loadmodel_font.params.posY = PhysicalToLogical(uint32_t(viewport3D.top_left_y)) + 15; + + GraphicsDevice* device = wi::graphics::GetDevice(); + + if (renderPath->GetDepthStencil() != nullptr) + { + bool success = false; + + XMUINT2 internalResolution = renderPath->GetInternalResolution(); + + TextureDesc desc; + desc.width = internalResolution.x; + desc.height = internalResolution.y; + + desc.format = Format::R8_UNORM; + desc.bind_flags = BindFlag::RENDER_TARGET | BindFlag::SHADER_RESOURCE; + if (renderPath->getMSAASampleCount() > 1) + { + desc.sample_count = renderPath->getMSAASampleCount(); + success = device->CreateTexture(&desc, nullptr, &rt_selectionOutline_MSAA); + assert(success); + desc.sample_count = 1; + } + success = device->CreateTexture(&desc, nullptr, &rt_selectionOutline[0]); + assert(success); + success = device->CreateTexture(&desc, nullptr, &rt_selectionOutline[1]); + assert(success); + } + + { + TextureDesc desc; + desc.width = renderPath->GetRenderResult().GetDesc().width; + desc.height = renderPath->GetRenderResult().GetDesc().height; + desc.format = Format::R8_UNORM; + desc.bind_flags = BindFlag::RENDER_TARGET | BindFlag::SHADER_RESOURCE; + desc.swizzle.r = ComponentSwizzle::R; + desc.swizzle.g = ComponentSwizzle::R; + desc.swizzle.b = ComponentSwizzle::R; + desc.swizzle.a = ComponentSwizzle::R; + device->CreateTexture(&desc, nullptr, &rt_dummyOutline); + device->SetName(&rt_dummyOutline, "rt_dummyOutline"); + } + + { + TextureDesc desc; + desc.width = renderPath->GetRenderResult().GetDesc().width; + desc.height = renderPath->GetRenderResult().GetDesc().height; + desc.format = Format::D32_FLOAT; + desc.bind_flags = BindFlag::DEPTH_STENCIL; + desc.layout = ResourceState::DEPTHSTENCIL; + desc.misc_flags = ResourceMiscFlag::TRANSIENT_ATTACHMENT; + device->CreateTexture(&desc, nullptr, &editor_depthbuffer); + device->SetName(&editor_depthbuffer, "editor_depthbuffer"); + } +} + void EditorComponent::ClearSelected() { translator.selected.clear(); @@ -3644,7 +4066,7 @@ void EditorComponent::ConsumeHistoryOperation(bool undo) } break; case HISTORYOP_PAINTTOOL: - optionsWnd.paintToolWnd.ConsumeHistoryOperation(archive, undo); + paintToolWnd.ConsumeHistoryOperation(archive, undo); break; case HISTORYOP_NONE: default: @@ -3660,7 +4082,7 @@ void EditorComponent::ConsumeHistoryOperation(bool undo) scene.Update(0); } - optionsWnd.RefreshEntityTree(); + componentsWnd.RefreshEntityTree(); } void EditorComponent::RegisterRecentlyUsed(const std::string& filename) @@ -3736,20 +4158,20 @@ void EditorComponent::Open(std::string filename) main->config.Commit(); playButton.SetScriptTip("dofile(\"" + last_script_path + "\")"); wi::lua::RunFile(filename); - optionsWnd.RefreshEntityTree(); + componentsWnd.RefreshEntityTree(); RegisterRecentlyUsed(filename); return; } if (type == FileType::VIDEO) { GetCurrentScene().Entity_CreateVideo(wi::helper::GetFileNameFromPath(filename), filename); - optionsWnd.RefreshEntityTree(); + componentsWnd.RefreshEntityTree(); return; } if (type == FileType::SOUND) { GetCurrentScene().Entity_CreateSound(wi::helper::GetFileNameFromPath(filename), filename); - optionsWnd.RefreshEntityTree(); + componentsWnd.RefreshEntityTree(); return; } if (type == FileType::IMAGE) @@ -3771,7 +4193,7 @@ void EditorComponent::Open(std::string filename) sprite.anim.repeatable = true; scene.transforms.Create(entity).Translate(XMFLOAT3(0, 2, 0)); scene.names.Create(entity) = wi::helper::GetFileNameFromPath(filename); - optionsWnd.RefreshEntityTree(); + componentsWnd.RefreshEntityTree(); return; } @@ -3779,82 +4201,76 @@ void EditorComponent::Open(std::string filename) size_t camera_count_prev = GetCurrentScene().cameras.GetCount(); - main->loader.addLoadingFunction([=](wi::jobsystem::JobArgs args) { - - if (type == FileType::WISCENE) // engine-serialized + wi::jobsystem::Execute(loadmodel_workload, [=] (wi::jobsystem::JobArgs) { + wi::backlog::post("[Editor] started loading model: " + filename); + std::shared_ptr scene = std::make_shared(); + if (type == FileType::WISCENE) { - Scene scene; - wi::scene::LoadModel(scene, filename); - GetCurrentScene().Merge(scene); - if (GetCurrentEditorScene().path.empty()) - { - GetCurrentEditorScene().path = filename; - } + wi::scene::LoadModel(*scene, filename); } - else if (type == FileType::OBJ) // wavefront-obj + else if (type == FileType::OBJ) { - Scene scene; - ImportModel_OBJ(filename, scene); - GetCurrentScene().Merge(scene); + ImportModel_OBJ(filename, *scene); } - else if (type == FileType::GLTF || type == FileType::GLB || type == FileType::VRM) // gltf, vrm + else if (type == FileType::GLTF || type == FileType::GLB || type == FileType::VRM) { - Scene scene; - ImportModel_GLTF(filename, scene); - GetCurrentScene().Merge(scene); + ImportModel_GLTF(filename, *scene); } else if (type == FileType::FBX) { - Scene scene; - ImportModel_FBX(filename, scene); - GetCurrentScene().Merge(scene); + ImportModel_FBX(filename, *scene); } - }); - main->loader.onFinished([=] { - // Detect when the new scene contains a new camera, and snap the camera onto it: - size_t camera_count = GetCurrentScene().cameras.GetCount(); - if (camera_count > 0 && camera_count > camera_count_prev) - { - Entity entity = GetCurrentScene().cameras.GetEntity(camera_count_prev); - if (entity != INVALID_ENTITY) + wi::eventhandler::Subscribe_Once(wi::eventhandler::EVENT_THREAD_SAFE_POINT, [=] (uint64_t userdata) { + + if (type == FileType::WISCENE && GetCurrentEditorScene().path.empty()) { - CameraComponent* cam = GetCurrentScene().cameras.GetComponent(entity); - if (cam != nullptr) + GetCurrentEditorScene().path = filename; + } + GetCurrentScene().Merge(*scene); + + // Detect when the new scene contains a new camera, and snap the camera onto it: + size_t camera_count = GetCurrentScene().cameras.GetCount(); + if (camera_count > 0 && camera_count > camera_count_prev) + { + Entity entity = GetCurrentScene().cameras.GetEntity(camera_count_prev); + if (entity != INVALID_ENTITY) { - EditorScene& editorscene = GetCurrentEditorScene(); - editorscene.camera.Eye = cam->Eye; - editorscene.camera.At = cam->At; - editorscene.camera.Up = cam->Up; - editorscene.camera.fov = cam->fov; - editorscene.camera.zNearP = cam->zNearP; - editorscene.camera.zFarP = cam->zFarP; - editorscene.camera.focal_length = cam->focal_length; - editorscene.camera.aperture_size = cam->aperture_size; - editorscene.camera.aperture_shape = cam->aperture_shape; - // camera aspect should be always for the current screen - editorscene.camera.width = (float)renderPath->GetInternalResolution().x; - editorscene.camera.height = (float)renderPath->GetInternalResolution().y; - - TransformComponent* camera_transform = GetCurrentScene().transforms.GetComponent(entity); - if (camera_transform != nullptr) + CameraComponent* cam = GetCurrentScene().cameras.GetComponent(entity); + if (cam != nullptr) { - editorscene.camera_transform = *camera_transform; - editorscene.camera.TransformCamera(editorscene.camera_transform); - } + EditorScene& editorscene = GetCurrentEditorScene(); + editorscene.camera.Eye = cam->Eye; + editorscene.camera.At = cam->At; + editorscene.camera.Up = cam->Up; + editorscene.camera.fov = cam->fov; + editorscene.camera.zNearP = cam->zNearP; + editorscene.camera.zFarP = cam->zFarP; + editorscene.camera.focal_length = cam->focal_length; + editorscene.camera.aperture_size = cam->aperture_size; + editorscene.camera.aperture_shape = cam->aperture_shape; + // camera aspect should be always for the current screen + editorscene.camera.width = (float)renderPath->GetInternalResolution().x; + editorscene.camera.height = (float)renderPath->GetInternalResolution().y; - editorscene.camera.UpdateCamera(); + TransformComponent* camera_transform = GetCurrentScene().transforms.GetComponent(entity); + if (camera_transform != nullptr) + { + editorscene.camera_transform = *camera_transform; + editorscene.camera.TransformCamera(editorscene.camera_transform); + } + + editorscene.camera.UpdateCamera(); + } } } - } + RefreshSceneList(); - main->ActivatePath(this, 0.2f, wi::Color::Black()); - componentsWnd.weatherWnd.Update(); - optionsWnd.RefreshEntityTree(); - RefreshSceneList(); + componentsWnd.weatherWnd.Update(); + componentsWnd.RefreshEntityTree(); + wi::backlog::post("[Editor] finished loading model: " + filename); }); - main->ActivatePath(&main->loader, 0.2f, wi::Color::Black()); - ResetHistory(); + }); } void EditorComponent::Save(const std::string& filename) { @@ -3871,7 +4287,7 @@ void EditorComponent::Save(const std::string& filename) if(type == FileType::WISCENE) { - const bool dump_to_header = optionsWnd.generalWnd.saveModeComboBox.GetSelected() == 2; + const bool dump_to_header = generalWnd.saveModeComboBox.GetSelected() == 2; wi::Archive archive = dump_to_header ? wi::Archive() : wi::Archive(filename, false); if (archive.IsOpen()) @@ -3880,7 +4296,7 @@ void EditorComponent::Save(const std::string& filename) Scene& scene = GetCurrentScene(); - wi::resourcemanager::Mode embed_mode = (wi::resourcemanager::Mode)optionsWnd.generalWnd.saveModeComboBox.GetItemUserData(optionsWnd.generalWnd.saveModeComboBox.GetSelected()); + wi::resourcemanager::Mode embed_mode = (wi::resourcemanager::Mode)generalWnd.saveModeComboBox.GetItemUserData(generalWnd.saveModeComboBox.GetSelected()); wi::resourcemanager::SetMode(embed_mode); scene.Serialize(archive); @@ -3910,7 +4326,7 @@ void EditorComponent::Save(const std::string& filename) } void EditorComponent::SaveAs() { - const bool dump_to_header = optionsWnd.generalWnd.saveModeComboBox.GetSelected() == 2; + const bool dump_to_header = generalWnd.saveModeComboBox.GetSelected() == 2; wi::helper::FileDialogParams params; params.type = wi::helper::FileDialogParams::SAVE; @@ -4032,7 +4448,7 @@ void EditorComponent::PostSaveText(const std::string& message, const std::string void EditorComponent::CheckBonePickingEnabled() { - if (optionsWnd.generalWnd.skeletonsVisibleCheckBox.GetCheck()) + if (generalWnd.skeletonsVisibleCheckBox.GetCheck()) { bone_picking = true; return; @@ -4068,11 +4484,10 @@ void EditorComponent::CheckBonePickingEnabled() } } -void EditorComponent::UpdateTopMenuAnimation() +void EditorComponent::UpdateDynamicWidgets() { float screenW = GetLogicalWidth(); float screenH = GetLogicalHeight(); - float hei = 25; float wid_idle = 40; float wid_focus = wid_idle * 2.5f; float padding = 4; @@ -4127,17 +4542,6 @@ void EditorComponent::UpdateTopMenuAnimation() logButton.SetText(logButton.GetState() > wi::gui::WIDGETSTATE::IDLE ? ICON_BACKLOG " Backlog" : ICON_BACKLOG); } - if (cinemaButton.GetState() > wi::gui::WIDGETSTATE::IDLE && current_localization.Get((size_t)EditorLocalization::Cinema) != nullptr) - { - tmp = ICON_CINEMA_MODE " "; - tmp += current_localization.Get((size_t)EditorLocalization::Cinema); - cinemaButton.SetText(tmp); - } - else - { - cinemaButton.SetText(cinemaButton.GetState() > wi::gui::WIDGETSTATE::IDLE ? ICON_CINEMA_MODE " Cinema" : ICON_CINEMA_MODE); - } - if (profilerButton.GetState() > wi::gui::WIDGETSTATE::IDLE && current_localization.Get((size_t)EditorLocalization::Profiler) != nullptr) { tmp = ICON_PROFILER " "; @@ -4209,50 +4613,110 @@ void EditorComponent::UpdateTopMenuAnimation() exitButton.SetText(exitButton.GetState() > wi::gui::WIDGETSTATE::IDLE ? ICON_EXIT " Exit" : ICON_EXIT); } + float hei = topmenuWnd.GetSize().y - topmenuWnd.GetShadowRadius() - 2; + float y = topmenuWnd.GetShadowRadius() + 2; + exitButton.SetSize(XMFLOAT2(wi::math::Lerp(exitButton.GetSize().x, exitButton.GetState() > wi::gui::WIDGETSTATE::IDLE ? wid_focus : wid_idle, lerp), hei)); aboutButton.SetSize(XMFLOAT2(wi::math::Lerp(aboutButton.GetSize().x, aboutButton.GetState() > wi::gui::WIDGETSTATE::IDLE ? wid_focus : wid_idle, lerp), hei)); fullscreenButton.SetSize(XMFLOAT2(wi::math::Lerp(fullscreenButton.GetSize().x, fullscreenButton.GetState() > wi::gui::WIDGETSTATE::IDLE ? wid_focus : wid_idle, lerp), hei)); bugButton.SetSize(XMFLOAT2(wi::math::Lerp(bugButton.GetSize().x, bugButton.GetState() > wi::gui::WIDGETSTATE::IDLE ? wid_focus : wid_idle, lerp), hei)); profilerButton.SetSize(XMFLOAT2(wi::math::Lerp(profilerButton.GetSize().x, profilerButton.GetState() > wi::gui::WIDGETSTATE::IDLE ? wid_focus : wid_idle, lerp), hei)); - cinemaButton.SetSize(XMFLOAT2(wi::math::Lerp(cinemaButton.GetSize().x, cinemaButton.GetState() > wi::gui::WIDGETSTATE::IDLE ? wid_focus : wid_idle, lerp), hei)); logButton.SetSize(XMFLOAT2(wi::math::Lerp(logButton.GetSize().x, logButton.GetState() > wi::gui::WIDGETSTATE::IDLE ? wid_focus : wid_idle, lerp), hei)); contentBrowserButton.SetSize(XMFLOAT2(wi::math::Lerp(contentBrowserButton.GetSize().x, contentBrowserButton.GetState() > wi::gui::WIDGETSTATE::IDLE ? wid_focus : wid_idle, lerp), hei)); openButton.SetSize(XMFLOAT2(wi::math::Lerp(openButton.GetSize().x, openButton.GetState() > wi::gui::WIDGETSTATE::IDLE ? wid_focus : wid_idle, lerp), hei)); saveButton.SetSize(XMFLOAT2(wi::math::Lerp(saveButton.GetSize().x, saveButton.GetState() > wi::gui::WIDGETSTATE::IDLE ? wid_focus : wid_idle, lerp), hei)); - exitButton.SetPos(XMFLOAT2(screenW - exitButton.GetSize().x, 0)); - aboutButton.SetPos(XMFLOAT2(exitButton.GetPos().x - aboutButton.GetSize().x - padding, 0)); - bugButton.SetPos(XMFLOAT2(aboutButton.GetPos().x - bugButton.GetSize().x - padding, 0)); - fullscreenButton.SetPos(XMFLOAT2(bugButton.GetPos().x - fullscreenButton.GetSize().x - padding, 0)); - cinemaButton.SetPos(XMFLOAT2(fullscreenButton.GetPos().x - cinemaButton.GetSize().x - padding, 0)); - profilerButton.SetPos(XMFLOAT2(cinemaButton.GetPos().x - profilerButton.GetSize().x - padding, 0)); - logButton.SetPos(XMFLOAT2(profilerButton.GetPos().x - logButton.GetSize().x - padding, 0)); - contentBrowserButton.SetPos(XMFLOAT2(logButton.GetPos().x - contentBrowserButton.GetSize().x - padding, 0)); - openButton.SetPos(XMFLOAT2(contentBrowserButton.GetPos().x - openButton.GetSize().x - padding, 0)); - saveButton.SetPos(XMFLOAT2(openButton.GetPos().x - saveButton.GetSize().x - padding, 0)); + exitButton.SetPos(XMFLOAT2(screenW - exitButton.GetSize().x, y)); + aboutButton.SetPos(XMFLOAT2(exitButton.GetPos().x - aboutButton.GetSize().x - padding, y)); + bugButton.SetPos(XMFLOAT2(aboutButton.GetPos().x - bugButton.GetSize().x - padding, y)); + fullscreenButton.SetPos(XMFLOAT2(bugButton.GetPos().x - fullscreenButton.GetSize().x - padding, y)); + profilerButton.SetPos(XMFLOAT2(fullscreenButton.GetPos().x - profilerButton.GetSize().x - padding, y)); + logButton.SetPos(XMFLOAT2(profilerButton.GetPos().x - logButton.GetSize().x - padding, y)); + contentBrowserButton.SetPos(XMFLOAT2(logButton.GetPos().x - contentBrowserButton.GetSize().x - padding, y)); + openButton.SetPos(XMFLOAT2(contentBrowserButton.GetPos().x - openButton.GetSize().x - padding, y)); + saveButton.SetPos(XMFLOAT2(openButton.GetPos().x - saveButton.GetSize().x - padding, y)); float static_pos = screenW - wid_idle * 12; - dummyButton.SetSize(XMFLOAT2(wid_idle * 0.75f, hei)); - dummyButton.SetPos(XMFLOAT2(static_pos - dummyButton.GetSize().x - 20, 0)); - navtestButton.SetSize(XMFLOAT2(wid_idle * 0.75f, hei)); - navtestButton.SetPos(XMFLOAT2(dummyButton.GetPos().x - navtestButton.GetSize().x - padding, 0)); - - physicsButton.SetSize(XMFLOAT2(wid_idle * 0.75f, hei)); - physicsButton.SetPos(XMFLOAT2(navtestButton.GetPos().x - physicsButton.GetSize().x - 20, 0)); - stopButton.SetSize(XMFLOAT2(wid_idle * 0.75f, hei)); - stopButton.SetPos(XMFLOAT2(physicsButton.GetPos().x - stopButton.GetSize().x - 20, 0)); + stopButton.SetPos(XMFLOAT2(static_pos - stopButton.GetSize().x - 20, y)); playButton.SetSize(XMFLOAT2(wid_idle * 0.75f, hei)); - playButton.SetPos(XMFLOAT2(stopButton.GetPos().x - playButton.GetSize().x - padding, 0)); + playButton.SetPos(XMFLOAT2(stopButton.GetPos().x - playButton.GetSize().x - padding, y)); - scaleButton.SetSize(XMFLOAT2(wid_idle * 0.75f, hei)); - scaleButton.SetPos(XMFLOAT2(playButton.GetPos().x - scaleButton.GetSize().x - 20, 0)); - rotateButton.SetSize(XMFLOAT2(wid_idle * 0.75f, hei)); - rotateButton.SetPos(XMFLOAT2(scaleButton.GetPos().x - rotateButton.GetSize().x - padding, 0)); - translateButton.SetSize(XMFLOAT2(wid_idle * 0.75f, hei)); - translateButton.SetPos(XMFLOAT2(rotateButton.GetPos().x - translateButton.GetSize().x - padding, 0)); + float ofs = 0; + wid_idle = 105; + float mid = 0; + for (int i = 0; i < int(scenes.size()); ++i) + { + auto& editorscene = scenes[i]; + editorscene->tabSelectButton.SetShadowRadius(topmenuWnd.GetShadowRadius()); + editorscene->tabCloseButton.SetShadowRadius(topmenuWnd.GetShadowRadius()); + editorscene->tabSelectButton.SetSize(XMFLOAT2(wid_idle, hei)); + editorscene->tabCloseButton.SetSize(XMFLOAT2(hei, hei)); + editorscene->tabSelectButton.SetPos(XMFLOAT2(ofs, y)); + ofs += editorscene->tabSelectButton.GetSize().x + editorscene->tabSelectButton.GetShadowRadius(); + editorscene->tabCloseButton.SetPos(XMFLOAT2(ofs, y)); + ofs += editorscene->tabCloseButton.GetSize().x + editorscene->tabCloseButton.GetShadowRadius(); + ofs += padding; + mid = editorscene->tabSelectButton.GetPos().y + editorscene->tabSelectButton.GetSize().y * 0.5f; + } + hei = 22; + newSceneButton.SetShadowRadius(0); + newSceneButton.SetSize(XMFLOAT2(hei, hei)); + newSceneButton.SetPos(XMFLOAT2(ofs, mid - hei * 0.5f)); + + hei = 24; + padding = 8; + ofs = screenW - padding - hei; + if (componentsWnd.IsVisible()) + { + ofs -= componentsWnd.GetSize().x + componentsWnd.GetShadowRadius(); + } + y = topmenuWnd.GetSize().y + padding; + + translateButton.SetSize(XMFLOAT2(hei, hei)); + translateButton.SetPos(XMFLOAT2(ofs, y)); + translateButton.Update(*this, 0); + y += translateButton.GetSize().y + translateButton.GetShadowRadius(); + + rotateButton.SetSize(XMFLOAT2(hei, hei)); + rotateButton.SetPos(XMFLOAT2(ofs, y)); + rotateButton.Update(*this, 0); + y += rotateButton.GetSize().y + rotateButton.GetShadowRadius(); + + scaleButton.SetSize(XMFLOAT2(hei, hei)); + scaleButton.SetPos(XMFLOAT2(ofs, y)); + scaleButton.Update(*this, 0); + y += scaleButton.GetSize().y + padding; + + physicsButton.SetSize(XMFLOAT2(hei, hei)); + physicsButton.SetPos(XMFLOAT2(ofs, y)); + physicsButton.Update(*this, 0); + y += physicsButton.GetSize().y + padding; + + dummyButton.SetSize(XMFLOAT2(hei, hei)); + dummyButton.SetPos(XMFLOAT2(ofs, y)); + dummyButton.Update(*this, 0); + y += dummyButton.GetSize().y + padding; + + navtestButton.SetSize(XMFLOAT2(hei, hei)); + navtestButton.SetPos(XMFLOAT2(ofs, y)); + navtestButton.Update(*this, 0); + y += navtestButton.GetSize().y + padding; + + cinemaButton.SetSize(XMFLOAT2(hei, hei)); + cinemaButton.SetPos(XMFLOAT2(ofs, y)); + cinemaButton.Update(*this, 0); + y += cinemaButton.GetSize().y + padding; + + + newEntityCombo.SetSize(XMFLOAT2(hei * 1.4f, hei * 1.4f)); + ofs -= padding * 2 + newEntityCombo.GetSize().x; + y = topmenuWnd.GetSize().y + padding; + newEntityCombo.SetPos(XMFLOAT2(ofs, y)); + newEntityCombo.Update(*this, 0); + newEntityCombo.SetText(""); // override localization XMFLOAT4 color_on = playButton.sprites[wi::gui::FOCUS].params.color; @@ -4304,24 +4768,107 @@ void EditorComponent::UpdateTopMenuAnimation() physicsButton.sprites[wi::gui::IDLE].params.color = color_off; } - float ofs = screenW - 2; - float y = exitButton.GetPos().y + exitButton.GetSize().y + 5; - hei = 18; - wid_idle = 105; - for (int i = 0; i < int(scenes.size()); ++i) + + + if (wi::backlog::GetUnseenLogLevelMax() >= wi::backlog::LogLevel::Error) { - auto& editorscene = scenes[i]; - editorscene->tabSelectButton.SetSize(XMFLOAT2(wid_idle, hei)); - editorscene->tabCloseButton.SetSize(XMFLOAT2(hei, hei)); - ofs -= editorscene->tabCloseButton.GetSize().x; - editorscene->tabCloseButton.SetPos(XMFLOAT2(ofs, y)); - ofs -= editorscene->tabSelectButton.GetSize().x; - editorscene->tabSelectButton.SetPos(XMFLOAT2(ofs, y)); - ofs -= 4; + logButton.sprites[wi::gui::IDLE].params.color = wi::Color::Error(); } - newSceneButton.SetSize(XMFLOAT2(hei, hei)); - ofs -= newSceneButton.GetSize().x; - newSceneButton.SetPos(XMFLOAT2(ofs, y)); + else if (wi::backlog::GetUnseenLogLevelMax() >= wi::backlog::LogLevel::Warning) + { + logButton.sprites[wi::gui::IDLE].params.color = wi::Color::Warning(); + } + else + { + logButton.sprites[wi::gui::IDLE].params.color = color_off; + } + + + + ofs = padding; + if (generalWnd.IsVisible()) + { + generalWnd.SetPos(XMFLOAT2(0, topmenuWnd.scale_local.y + topmenuWnd.GetShadowRadius())); + generalWnd.SetSize(XMFLOAT2(generalWnd.scale_local.x, screenH - topmenuWnd.scale_local.y - topmenuWnd.GetShadowRadius())); + ofs += generalWnd.scale_local.x + generalWnd.GetShadowRadius(); + generalButton.sprites[wi::gui::IDLE].params.color = color_on; + } + else + { + generalButton.sprites[wi::gui::IDLE].params.color = color_off; + } + if (graphicsWnd.IsVisible()) + { + graphicsWnd.SetPos(XMFLOAT2(0, topmenuWnd.scale_local.y + topmenuWnd.GetShadowRadius())); + graphicsWnd.SetSize(XMFLOAT2(graphicsWnd.scale_local.x, screenH - topmenuWnd.scale_local.y - topmenuWnd.GetShadowRadius())); + ofs += graphicsWnd.scale_local.x + graphicsWnd.GetShadowRadius(); + graphicsButton.sprites[wi::gui::IDLE].params.color = color_on; + } + else + { + graphicsButton.sprites[wi::gui::IDLE].params.color = color_off; + } + if (cameraWnd.IsVisible()) + { + cameraWnd.SetPos(XMFLOAT2(0, topmenuWnd.scale_local.y + topmenuWnd.GetShadowRadius())); + cameraWnd.SetSize(XMFLOAT2(cameraWnd.scale_local.x, screenH - topmenuWnd.scale_local.y - topmenuWnd.GetShadowRadius())); + ofs += cameraWnd.scale_local.x + cameraWnd.GetShadowRadius(); + cameraButton.sprites[wi::gui::IDLE].params.color = color_on; + } + else + { + cameraButton.sprites[wi::gui::IDLE].params.color = color_off; + } + if (materialPickerWnd.IsVisible()) + { + materialPickerWnd.SetPos(XMFLOAT2(0, topmenuWnd.scale_local.y + topmenuWnd.GetShadowRadius())); + materialPickerWnd.SetSize(XMFLOAT2(materialPickerWnd.scale_local.x, screenH - topmenuWnd.scale_local.y - topmenuWnd.GetShadowRadius())); + ofs += materialPickerWnd.scale_local.x + materialPickerWnd.GetShadowRadius(); + materialsButton.sprites[wi::gui::IDLE].params.color = color_on; + } + else + { + materialsButton.sprites[wi::gui::IDLE].params.color = color_off; + } + if (paintToolWnd.IsVisible()) + { + paintToolWnd.SetPos(XMFLOAT2(0, topmenuWnd.scale_local.y + topmenuWnd.GetShadowRadius())); + paintToolWnd.SetSize(XMFLOAT2(paintToolWnd.scale_local.x, screenH - topmenuWnd.scale_local.y - topmenuWnd.GetShadowRadius())); + ofs += paintToolWnd.scale_local.x + paintToolWnd.GetShadowRadius(); + paintToolButton.sprites[wi::gui::IDLE].params.color = color_on; + } + else + { + paintToolButton.sprites[wi::gui::IDLE].params.color = color_off; + } + y = padding + topmenuWnd.GetSize().y + topmenuWnd.GetShadowRadius(); + hei = 40; + + generalButton.SetPos(XMFLOAT2(ofs, y)); + generalButton.SetSize(XMFLOAT2(hei, hei)); + generalButton.Update(*this, 0); + y += hei + padding; + + graphicsButton.SetPos(XMFLOAT2(ofs, y)); + graphicsButton.SetSize(XMFLOAT2(hei, hei)); + graphicsButton.Update(*this, 0); + y += hei + padding; + + cameraButton.SetPos(XMFLOAT2(ofs, y)); + cameraButton.SetSize(XMFLOAT2(hei, hei)); + cameraButton.Update(*this, 0); + y += hei + padding; + + materialsButton.SetPos(XMFLOAT2(ofs, y)); + materialsButton.SetSize(XMFLOAT2(hei, hei)); + materialsButton.Update(*this, 0); + y += hei + padding; + + paintToolButton.SetPos(XMFLOAT2(ofs, y)); + paintToolButton.SetSize(XMFLOAT2(hei, hei)); + paintToolButton.Update(*this, 0); + y += hei + padding; + } void EditorComponent::SetCurrentScene(int index) @@ -4331,12 +4878,12 @@ void EditorComponent::SetCurrentScene(int index) this->renderPath->camera = &scenes[current_scene].get()->camera; wi::lua::scene::SetGlobalScene(renderPath->scene); wi::lua::scene::SetGlobalCamera(renderPath->camera); - optionsWnd.RefreshEntityTree(); + componentsWnd.RefreshEntityTree(); RefreshSceneList(); } void EditorComponent::RefreshSceneList() { - optionsWnd.generalWnd.themeCombo.SetSelected(optionsWnd.generalWnd.themeCombo.GetSelected()); + generalWnd.themeCombo.SetSelected(generalWnd.themeCombo.GetSelected()); for (int i = 0; i < int(scenes.size()); ++i) { auto& editorscene = scenes[i]; @@ -4368,7 +4915,7 @@ void EditorComponent::RefreshSceneList() translator.selected.clear(); wi::scene::Scene& scene = scenes[i]->scene; wi::renderer::ClearWorld(scene); - optionsWnd.cameraWnd.SetEntity(wi::ecs::INVALID_ENTITY); + cameraWnd.SetEntity(wi::ecs::INVALID_ENTITY); componentsWnd.objectWnd.SetEntity(wi::ecs::INVALID_ENTITY); componentsWnd.meshWnd.SetEntity(wi::ecs::INVALID_ENTITY, -1); componentsWnd.lightWnd.SetEntity(wi::ecs::INVALID_ENTITY); @@ -4400,15 +4947,15 @@ void EditorComponent::RefreshSceneList() componentsWnd.fontWnd.SetEntity(wi::ecs::INVALID_ENTITY); componentsWnd.voxelGridWnd.SetEntity(wi::ecs::INVALID_ENTITY); - optionsWnd.RefreshEntityTree(); + componentsWnd.RefreshEntityTree(); ResetHistory(); scenes[i]->path.clear(); wi::eventhandler::Subscribe_Once(wi::eventhandler::EVENT_THREAD_SAFE_POINT, [=](uint64_t userdata) { if (scenes.size() > 1) { - GetGUI().RemoveWidget(&scenes[i]->tabSelectButton); - GetGUI().RemoveWidget(&scenes[i]->tabCloseButton); + topmenuWnd.RemoveWidget(&scenes[i]->tabSelectButton); + topmenuWnd.RemoveWidget(&scenes[i]->tabCloseButton); scenes.erase(scenes.begin() + i); } SetCurrentScene(std::max(0, i - 1)); @@ -4426,12 +4973,12 @@ void EditorComponent::NewScene() editorscene->tabCloseButton.Create("X"); editorscene->tabCloseButton.SetLocalizationEnabled(false); editorscene->tabCloseButton.SetTooltip("Close scene. This operation cannot be undone!"); - GetGUI().AddWidget(&editorscene->tabSelectButton); - GetGUI().AddWidget(&editorscene->tabCloseButton); + topmenuWnd.AddWidget(&editorscene->tabSelectButton); + topmenuWnd.AddWidget(&editorscene->tabCloseButton); SetCurrentScene(scene_id); RefreshSceneList(); - UpdateTopMenuAnimation(); - optionsWnd.cameraWnd.ResetCam(); + UpdateDynamicWidgets(); + cameraWnd.ResetCam(); } void EditorComponent::FocusCameraOnSelected() @@ -4446,11 +4993,11 @@ void EditorComponent::FocusCameraOnSelected() for (auto& x : translator.selected) { TransformComponent* transform = scene.transforms.GetComponent(x.entity); - if (transform != nullptr) - { - centerV = XMVectorAdd(centerV, transform->GetPositionV()); - count += 1.0f; - } + if (transform == nullptr) + continue; + + centerV = XMVectorAdd(centerV, transform->GetPositionV()); + count += 1.0f; if (scene.objects.Contains(x.entity)) { @@ -4485,11 +5032,13 @@ void EditorComponent::FocusCameraOnSelected() { centerV /= count; } + else + return; float focus_offset = 5; if (aabb.getArea() > 0) { - focus_offset = aabb.getRadius() * 1.5f; + focus_offset = aabb.getRadius() * 2; XMFLOAT3 aabb_center = aabb.getCenter(); centerV = XMLoadFloat3(&aabb_center); } @@ -4522,5 +5071,5 @@ void EditorComponent::SetLocalization(wi::Localization& loc) } void EditorComponent::ReloadLanguage() { - optionsWnd.generalWnd.languageCombo.SetSelected(optionsWnd.generalWnd.languageCombo.GetSelected()); + generalWnd.languageCombo.SetSelected(generalWnd.languageCombo.GetSelected()); } diff --git a/Editor/Editor.h b/Editor/Editor.h index ad81bdaf1..95a53a2f8 100644 --- a/Editor/Editor.h +++ b/Editor/Editor.h @@ -1,22 +1,16 @@ #pragma once #include "Translator.h" #include "wiScene_BindLua.h" -#include "OptionsWindow.h" #include "ComponentsWindow.h" #include "ProfilerWindow.h" #include "ContentBrowserWindow.h" +#include "GraphicsWindow.h" +#include "CameraWindow.h" +#include "MaterialPickerWindow.h" +#include "PaintToolWindow.h" +#include "GeneralWindow.h" #include "IconDefinitions.h" -class EditorLoadingScreen : public wi::LoadingScreen -{ -private: - wi::Sprite sprite; - wi::SpriteFont font; -public: - void Load() override; - void Update(float dt) override; -}; - class Editor; class EditorComponent : public wi::RenderPath2D { @@ -25,6 +19,8 @@ public: wi::gui::Button newSceneButton; + wi::gui::ComboBox newEntityCombo; + wi::gui::Button translateButton; wi::gui::Button rotateButton; wi::gui::Button scaleButton; @@ -58,10 +54,22 @@ public: wi::gui::Window aboutWindow; wi::gui::Label aboutLabel; - OptionsWindow optionsWnd; ComponentsWindow componentsWnd; ProfilerWindow profilerWnd; ContentBrowserWindow contentBrowserWnd; + wi::gui::Window topmenuWnd; + + wi::gui::Button generalButton; + wi::gui::Button graphicsButton; + wi::gui::Button cameraButton; + wi::gui::Button materialsButton; + wi::gui::Button paintToolButton; + + GeneralWindow generalWnd; + GraphicsWindow graphicsWnd; + CameraWindow cameraWnd; + MaterialPickerWindow materialPickerWnd; + PaintToolWindow paintToolWnd; wi::primitive::Ray pickRay; wi::physics::PickDragOperation physicsDragOp; @@ -80,6 +88,12 @@ public: void Render() const override; void Compose(wi::graphics::CommandList cmd) const override; + wi::graphics::Viewport viewport3D; + void ResizeViewport3D(); + + bool camControlStart = true; + XMFLOAT4 originalMouse = XMFLOAT4(0, 0, 0, 0); + XMFLOAT4 currentMouse = XMFLOAT4(0, 0, 0, 0); enum EDITORSTENCILREF { @@ -119,7 +133,7 @@ public: bool bone_picking = false; void CheckBonePickingEnabled(); - void UpdateTopMenuAnimation(); + void UpdateDynamicWidgets(); wi::Archive clipboard; @@ -200,13 +214,15 @@ public: wi::vector filedata; }; wi::vector font_datas; + + wi::jobsystem::context loadmodel_workload; + wi::SpriteFont loadmodel_font; }; class Editor : public wi::Application { public: EditorComponent renderComponent; - EditorLoadingScreen loader; wi::config::File config; void Initialize() override; @@ -223,18 +239,16 @@ enum class EditorLocalization // Top menu: Save, Open, - ContentBrowser, Backlog, Profiler, - Cinema, + __REMOVED_Cinema, FullScreen, Windowed, BugReport, About, Exit, - - // Other: UntitledScene, + ContentBrowser, Count }; @@ -242,7 +256,6 @@ static const char* EditorLocalizationStrings[] = { // Top menu: "Save", "Open", - "Content", "Backlog", "Profiler", "Cinema", @@ -251,8 +264,7 @@ static const char* EditorLocalizationStrings[] = { "Bug report", "About", "Exit", - - // Other: - "Untitled scene" + "Untitled scene", + "Content", }; static_assert(arraysize(EditorLocalizationStrings) == size_t(EditorLocalization::Count)); diff --git a/Editor/Editor_SOURCE.vcxitems b/Editor/Editor_SOURCE.vcxitems index fde35ddb7..c7b9477fb 100644 --- a/Editor/Editor_SOURCE.vcxitems +++ b/Editor/Editor_SOURCE.vcxitems @@ -103,7 +103,6 @@ - @@ -173,7 +172,6 @@ - diff --git a/Editor/Editor_SOURCE.vcxitems.filters b/Editor/Editor_SOURCE.vcxitems.filters index f41826e6d..178ad34f4 100644 --- a/Editor/Editor_SOURCE.vcxitems.filters +++ b/Editor/Editor_SOURCE.vcxitems.filters @@ -74,7 +74,6 @@ - @@ -132,7 +131,6 @@ - diff --git a/Editor/EmitterWindow.cpp b/Editor/EmitterWindow.cpp index dc92cba4b..3b801eee8 100644 --- a/Editor/EmitterWindow.cpp +++ b/Editor/EmitterWindow.cpp @@ -21,7 +21,7 @@ void EmitterWindow::Create(EditorComponent* _editor) editor->RecordEntity(archive, entity); - editor->optionsWnd.RefreshEntityTree(); + editor->componentsWnd.RefreshEntityTree(); }); float x = 130; diff --git a/Editor/EnvProbeWindow.cpp b/Editor/EnvProbeWindow.cpp index c7ba2f6cf..2589f4c32 100644 --- a/Editor/EnvProbeWindow.cpp +++ b/Editor/EnvProbeWindow.cpp @@ -23,7 +23,7 @@ void EnvProbeWindow::Create(EditorComponent* _editor) editor->RecordEntity(archive, entity); - editor->optionsWnd.RefreshEntityTree(); + editor->componentsWnd.RefreshEntityTree(); }); float x = 5, y = 0, step = 35; diff --git a/Editor/ExpressionWindow.cpp b/Editor/ExpressionWindow.cpp index 9534a0574..2e07f8494 100644 --- a/Editor/ExpressionWindow.cpp +++ b/Editor/ExpressionWindow.cpp @@ -22,7 +22,7 @@ void ExpressionWindow::Create(EditorComponent* _editor) editor->RecordEntity(archive, entity); - editor->optionsWnd.RefreshEntityTree(); + editor->componentsWnd.RefreshEntityTree(); }); float x = 60; diff --git a/Editor/FontWindow.cpp b/Editor/FontWindow.cpp index 424599cff..8f7f0a340 100644 --- a/Editor/FontWindow.cpp +++ b/Editor/FontWindow.cpp @@ -22,7 +22,7 @@ void FontWindow::Create(EditorComponent* _editor) editor->RecordEntity(archive, entity); - editor->optionsWnd.RefreshEntityTree(); + editor->componentsWnd.RefreshEntityTree(); }); float x = 60; diff --git a/Editor/ForceFieldWindow.cpp b/Editor/ForceFieldWindow.cpp index 52859fc73..d5677a1d1 100644 --- a/Editor/ForceFieldWindow.cpp +++ b/Editor/ForceFieldWindow.cpp @@ -21,7 +21,7 @@ void ForceFieldWindow::Create(EditorComponent* _editor) editor->RecordEntity(archive, entity); - editor->optionsWnd.RefreshEntityTree(); + editor->componentsWnd.RefreshEntityTree(); }); float x = 60; diff --git a/Editor/GeneralWindow.cpp b/Editor/GeneralWindow.cpp index 427cda80d..33eabb839 100644 --- a/Editor/GeneralWindow.cpp +++ b/Editor/GeneralWindow.cpp @@ -11,9 +11,10 @@ void GeneralWindow::Create(EditorComponent* _editor) { editor = _editor; - wi::gui::Window::Create("General", wi::gui::Window::WindowControls::COLLAPSE); + wi::gui::Window::Create("General", wi::gui::Window::WindowControls::CLOSE | wi::gui::Window::WindowControls::RESIZE_RIGHT); + SetText("General Options " ICON_GENERALOPTIONS); - SetSize(XMFLOAT2(580, 700)); + SetSize(XMFLOAT2(300, 700)); physicsDebugCheckBox.Create("Physics visualizer: "); physicsDebugCheckBox.SetTooltip("Visualize the physics world"); @@ -370,7 +371,7 @@ void GeneralWindow::Create(EditorComponent* _editor) theme_color_idle = wi::Color(46, 52, 64, 255); theme_color_focus = wi::Color(59, 66, 82, 255); dark_point = wi::Color(46, 52, 64, 255); - theme.shadow_color = wi::Color(46, 52, 64, 200); + theme.shadow_color = wi::Color(106, 112, 124, 200); theme.font.color = wi::Color(236, 239, 244, 255); theme.font.shadow_color = wi::Color::Shadow(); break; @@ -432,39 +433,33 @@ void GeneralWindow::Create(EditorComponent* _editor) } // customize individual elements: + editor->loadmodel_font.params.color = theme.font.color; + XMFLOAT4 highlight = theme_color_focus; + highlight.x *= 2; + highlight.y *= 2; + highlight.z *= 2; + editor->newEntityCombo.SetAngularHighlightColor(highlight); + editor->componentsWnd.newComponentCombo.SetAngularHighlightColor(highlight); editor->componentsWnd.materialWnd.textureSlotButton.SetColor(wi::Color::White(), wi::gui::IDLE); editor->componentsWnd.spriteWnd.textureButton.SetColor(wi::Color::White(), wi::gui::IDLE); - editor->optionsWnd.paintToolWnd.brushTextureButton.SetColor(wi::Color::White(), wi::gui::IDLE); - editor->optionsWnd.paintToolWnd.revealTextureButton.SetColor(wi::Color::White(), wi::gui::IDLE); + editor->paintToolWnd.brushTextureButton.SetColor(wi::Color::White(), wi::gui::IDLE); + editor->paintToolWnd.revealTextureButton.SetColor(wi::Color::White(), wi::gui::IDLE); editor->aboutLabel.sprites[wi::gui::FOCUS] = editor->aboutLabel.sprites[wi::gui::IDLE]; - for (int i = 0; i < arraysize(wi::gui::Widget::sprites); ++i) - { - editor->optionsWnd.sprites[i].params.enableCornerRounding(); - editor->optionsWnd.sprites[i].params.corners_rounding[1].radius = 10; - editor->optionsWnd.resizeDragger_UpperRight.sprites[i].params.enableCornerRounding(); - editor->optionsWnd.resizeDragger_UpperRight.sprites[i].params.corners_rounding[1].radius = 10; - } - for (int i = 0; i < arraysize(wi::gui::Widget::sprites); ++i) - { - editor->componentsWnd.sprites[i].params.enableCornerRounding(); - editor->componentsWnd.sprites[i].params.corners_rounding[0].radius = 10; - editor->componentsWnd.resizeDragger_UpperLeft.sprites[i].params.enableCornerRounding(); - editor->componentsWnd.resizeDragger_UpperLeft.sprites[i].params.corners_rounding[0].radius = 10; - } int scene_id = 0; for (auto& editorscene : editor->scenes) { - for (int i = 0; i < arraysize(editorscene->tabSelectButton.sprites); ++i) + if (scene_id > 0) { - editorscene->tabSelectButton.sprites[i].params.enableCornerRounding(); - editorscene->tabSelectButton.sprites[i].params.corners_rounding[0].radius = 10; - editorscene->tabSelectButton.sprites[i].params.corners_rounding[2].radius = 10; + for (int i = 0; i < arraysize(editorscene->tabSelectButton.sprites); ++i) + { + editorscene->tabSelectButton.sprites[i].params.enableCornerRounding(); + editorscene->tabSelectButton.sprites[i].params.corners_rounding[0].radius = 10; + } } for (int i = 0; i < arraysize(editorscene->tabCloseButton.sprites); ++i) { editorscene->tabCloseButton.sprites[i].params.enableCornerRounding(); editorscene->tabCloseButton.sprites[i].params.corners_rounding[1].radius = 10; - editorscene->tabCloseButton.sprites[i].params.corners_rounding[3].radius = 10; } if (editor->current_scene == scene_id) @@ -481,10 +476,76 @@ void GeneralWindow::Create(EditorComponent* _editor) for (int i = 0; i < arraysize(editor->newSceneButton.sprites); ++i) { editor->newSceneButton.sprites[i].params.enableCornerRounding(); - editor->newSceneButton.sprites[i].params.corners_rounding[0].radius = 10; - editor->newSceneButton.sprites[i].params.corners_rounding[1].radius = 10; - editor->newSceneButton.sprites[i].params.corners_rounding[2].radius = 10; - editor->newSceneButton.sprites[i].params.corners_rounding[3].radius = 10; + editor->newSceneButton.sprites[i].params.corners_rounding[0].radius = 20; + editor->newSceneButton.sprites[i].params.corners_rounding[1].radius = 20; + editor->newSceneButton.sprites[i].params.corners_rounding[2].radius = 20; + editor->newSceneButton.sprites[i].params.corners_rounding[3].radius = 20; + + editor->newEntityCombo.sprites[i].params.enableCornerRounding(); + editor->newEntityCombo.sprites[i].params.corners_rounding[0].radius = 20; + editor->newEntityCombo.sprites[i].params.corners_rounding[1].radius = 20; + editor->newEntityCombo.sprites[i].params.corners_rounding[2].radius = 20; + editor->newEntityCombo.sprites[i].params.corners_rounding[3].radius = 20; + + editor->generalButton.sprites[i].params.enableCornerRounding(); + editor->generalButton.sprites[i].params.corners_rounding[0].radius = 20; + editor->generalButton.sprites[i].params.corners_rounding[1].radius = 20; + editor->generalButton.sprites[i].params.corners_rounding[2].radius = 20; + editor->generalButton.sprites[i].params.corners_rounding[3].radius = 20; + + editor->graphicsButton.sprites[i].params.enableCornerRounding(); + editor->graphicsButton.sprites[i].params.corners_rounding[0].radius = 20; + editor->graphicsButton.sprites[i].params.corners_rounding[1].radius = 20; + editor->graphicsButton.sprites[i].params.corners_rounding[2].radius = 20; + editor->graphicsButton.sprites[i].params.corners_rounding[3].radius = 20; + + editor->cameraButton.sprites[i].params.enableCornerRounding(); + editor->cameraButton.sprites[i].params.corners_rounding[0].radius = 20; + editor->cameraButton.sprites[i].params.corners_rounding[1].radius = 20; + editor->cameraButton.sprites[i].params.corners_rounding[2].radius = 20; + editor->cameraButton.sprites[i].params.corners_rounding[3].radius = 20; + + editor->materialsButton.sprites[i].params.enableCornerRounding(); + editor->materialsButton.sprites[i].params.corners_rounding[0].radius = 20; + editor->materialsButton.sprites[i].params.corners_rounding[1].radius = 20; + editor->materialsButton.sprites[i].params.corners_rounding[2].radius = 20; + editor->materialsButton.sprites[i].params.corners_rounding[3].radius = 20; + + editor->paintToolButton.sprites[i].params.enableCornerRounding(); + editor->paintToolButton.sprites[i].params.corners_rounding[0].radius = 20; + editor->paintToolButton.sprites[i].params.corners_rounding[1].radius = 20; + editor->paintToolButton.sprites[i].params.corners_rounding[2].radius = 20; + editor->paintToolButton.sprites[i].params.corners_rounding[3].radius = 20; + + editor->componentsWnd.newComponentCombo.sprites[i].params.enableCornerRounding(); + editor->componentsWnd.newComponentCombo.sprites[i].params.corners_rounding[0].radius = 20; + editor->componentsWnd.newComponentCombo.sprites[i].params.corners_rounding[1].radius = 20; + editor->componentsWnd.newComponentCombo.sprites[i].params.corners_rounding[2].radius = 20; + editor->componentsWnd.newComponentCombo.sprites[i].params.corners_rounding[3].radius = 20; + + editor->dummyButton.sprites[i].params.enableCornerRounding(); + editor->dummyButton.sprites[i].params.corners_rounding[0].radius = 10; + editor->dummyButton.sprites[i].params.corners_rounding[1].radius = 10; + editor->dummyButton.sprites[i].params.corners_rounding[2].radius = 10; + editor->dummyButton.sprites[i].params.corners_rounding[3].radius = 10; + + editor->physicsButton.sprites[i].params.enableCornerRounding(); + editor->physicsButton.sprites[i].params.corners_rounding[0].radius = 10; + editor->physicsButton.sprites[i].params.corners_rounding[1].radius = 10; + editor->physicsButton.sprites[i].params.corners_rounding[2].radius = 10; + editor->physicsButton.sprites[i].params.corners_rounding[3].radius = 10; + + editor->navtestButton.sprites[i].params.enableCornerRounding(); + editor->navtestButton.sprites[i].params.corners_rounding[0].radius = 10; + editor->navtestButton.sprites[i].params.corners_rounding[1].radius = 10; + editor->navtestButton.sprites[i].params.corners_rounding[2].radius = 10; + editor->navtestButton.sprites[i].params.corners_rounding[3].radius = 10; + + editor->cinemaButton.sprites[i].params.enableCornerRounding(); + editor->cinemaButton.sprites[i].params.corners_rounding[0].radius = 10; + editor->cinemaButton.sprites[i].params.corners_rounding[1].radius = 10; + editor->cinemaButton.sprites[i].params.corners_rounding[2].radius = 10; + editor->cinemaButton.sprites[i].params.corners_rounding[3].radius = 10; } for (int i = 0; i < arraysize(wi::gui::Widget::sprites); ++i) { @@ -511,41 +572,35 @@ void GeneralWindow::Create(EditorComponent* _editor) editor->aboutWindow.sprites[i].params.corners_rounding[1].radius = 10; editor->aboutWindow.sprites[i].params.corners_rounding[2].radius = 10; editor->aboutWindow.sprites[i].params.corners_rounding[3].radius = 10; - editor->aboutWindow.resizeDragger_UpperLeft.sprites[i].params.enableCornerRounding(); - editor->aboutWindow.resizeDragger_UpperLeft.sprites[i].params.corners_rounding[0].radius = 10; - editor->aboutWindow.resizeDragger_UpperRight.sprites[i].params.enableCornerRounding(); - editor->aboutWindow.resizeDragger_UpperRight.sprites[i].params.corners_rounding[1].radius = 10; - editor->aboutWindow.resizeDragger_BottomLeft.sprites[i].params.enableCornerRounding(); - editor->aboutWindow.resizeDragger_BottomLeft.sprites[i].params.corners_rounding[2].radius = 10; - editor->aboutWindow.resizeDragger_BottomRight.sprites[i].params.enableCornerRounding(); - editor->aboutWindow.resizeDragger_BottomRight.sprites[i].params.corners_rounding[3].radius = 10; } for (int i = 0; i < arraysize(wi::gui::Widget::sprites); ++i) { editor->saveButton.sprites[i].params.enableCornerRounding(); - editor->saveButton.sprites[i].params.corners_rounding[2].radius = 10; + editor->saveButton.sprites[i].params.corners_rounding[0].radius = 10; editor->playButton.sprites[i].params.enableCornerRounding(); - editor->playButton.sprites[i].params.corners_rounding[2].radius = 40; + editor->playButton.sprites[i].params.corners_rounding[0].radius = 10; editor->stopButton.sprites[i].params.enableCornerRounding(); - editor->stopButton.sprites[i].params.corners_rounding[3].radius = 40; + editor->stopButton.sprites[i].params.corners_rounding[1].radius = 10; editor->translateButton.sprites[i].params.enableCornerRounding(); - editor->translateButton.sprites[i].params.corners_rounding[2].radius = 40; + editor->translateButton.sprites[i].params.corners_rounding[0].radius = 10; + editor->translateButton.sprites[i].params.corners_rounding[1].radius = 10; editor->scaleButton.sprites[i].params.enableCornerRounding(); - editor->scaleButton.sprites[i].params.corners_rounding[3].radius = 40; + editor->scaleButton.sprites[i].params.corners_rounding[2].radius = 10; + editor->scaleButton.sprites[i].params.corners_rounding[3].radius = 10; editor->dummyButton.sprites[i].params.enableCornerRounding(); - editor->dummyButton.sprites[i].params.corners_rounding[3].radius = 40; + editor->dummyButton.sprites[i].params.corners_rounding[3].radius = 10; editor->navtestButton.sprites[i].params.enableCornerRounding(); - editor->navtestButton.sprites[i].params.corners_rounding[2].radius = 40; + editor->navtestButton.sprites[i].params.corners_rounding[2].radius = 10; editor->physicsButton.sprites[i].params.enableCornerRounding(); - editor->physicsButton.sprites[i].params.corners_rounding[2].radius = 40; - editor->physicsButton.sprites[i].params.corners_rounding[3].radius = 40; + editor->physicsButton.sprites[i].params.corners_rounding[2].radius = 10; + editor->physicsButton.sprites[i].params.corners_rounding[3].radius = 10; } editor->componentsWnd.weatherWnd.default_sky_horizon = dark_point; editor->componentsWnd.weatherWnd.default_sky_zenith = theme_color_idle; @@ -676,6 +731,8 @@ void GeneralWindow::Create(EditorComponent* _editor) }); AddWidget(&ktxConvButton); + + SetVisible(false); } void GeneralWindow::RefreshLanguageSelectionAfterWholeGUIWasInitialized() diff --git a/Editor/GraphicsWindow.cpp b/Editor/GraphicsWindow.cpp index fab7c00ba..a10d7ddcb 100644 --- a/Editor/GraphicsWindow.cpp +++ b/Editor/GraphicsWindow.cpp @@ -7,13 +7,14 @@ using namespace wi::graphics; void GraphicsWindow::Create(EditorComponent* _editor) { editor = _editor; - wi::gui::Window::Create("Graphics", wi::gui::Window::WindowControls::COLLAPSE); + wi::gui::Window::Create("Graphics", wi::gui::Window::WindowControls::CLOSE | wi::gui::Window::WindowControls::RESIZE_RIGHT); + SetText("Graphics Options " ICON_GRAPHICSOPTIONS); wi::renderer::SetToDrawDebugEnvProbes(true); wi::renderer::SetToDrawGridHelper(true); wi::renderer::SetToDrawDebugCameras(true); - SetSize(XMFLOAT2(580, 1660)); + SetSize(XMFLOAT2(300, 1660)); float step = 21; float itemheight = 18; @@ -1417,8 +1418,7 @@ void GraphicsWindow::Create(EditorComponent* _editor) fsr2Combo.SetSelected(fsr2_preset); AddWidget(&fsr2Combo); - Translate(XMFLOAT3(100, 50, 0)); - SetMinimized(true); + SetVisible(false); } void GraphicsWindow::UpdateSwapChainFormats(wi::graphics::SwapChain* swapChain) @@ -1632,7 +1632,7 @@ void GraphicsWindow::ResizeLayout() if (!widget.IsVisible()) return; const float margin_left = 155; - const float margin_right = 45; + const float margin_right = 50; widget.SetPos(XMFLOAT2(margin_left, y)); widget.SetSize(XMFLOAT2(width - margin_left - margin_right, widget.GetScale().y)); y += widget.GetSize().y; @@ -1641,7 +1641,7 @@ void GraphicsWindow::ResizeLayout() auto add_right = [&](wi::gui::Widget& widget) { if (!widget.IsVisible()) return; - const float margin_right = 45; + const float margin_right = 50; widget.SetPos(XMFLOAT2(width - margin_right - widget.GetSize().x, y)); y += widget.GetSize().y; y += padding; diff --git a/Editor/HairParticleWindow.cpp b/Editor/HairParticleWindow.cpp index 4310c0aef..8553f7d68 100644 --- a/Editor/HairParticleWindow.cpp +++ b/Editor/HairParticleWindow.cpp @@ -21,7 +21,7 @@ void HairParticleWindow::Create(EditorComponent* _editor) editor->RecordEntity(archive, entity); - editor->optionsWnd.RefreshEntityTree(); + editor->componentsWnd.RefreshEntityTree(); }); float x = 120; diff --git a/Editor/HierarchyWindow.cpp b/Editor/HierarchyWindow.cpp index c48894d20..938fd602d 100644 --- a/Editor/HierarchyWindow.cpp +++ b/Editor/HierarchyWindow.cpp @@ -21,7 +21,7 @@ void HierarchyWindow::Create(EditorComponent* _editor) editor->RecordEntity(archive, entity); - editor->optionsWnd.RefreshEntityTree(); + editor->componentsWnd.RefreshEntityTree(); }); float x = 80; @@ -53,7 +53,7 @@ void HierarchyWindow::Create(EditorComponent* _editor) editor->RecordEntity(archive, entity); - editor->optionsWnd.RefreshEntityTree(); + editor->componentsWnd.RefreshEntityTree(); }); parentCombo.SetTooltip("Choose a parent entity (also works if selected entity has no transform)"); diff --git a/Editor/HumanoidWindow.cpp b/Editor/HumanoidWindow.cpp index 7fb7fa672..30b698183 100644 --- a/Editor/HumanoidWindow.cpp +++ b/Editor/HumanoidWindow.cpp @@ -22,7 +22,7 @@ void HumanoidWindow::Create(EditorComponent* _editor) editor->RecordEntity(archive, entity); - editor->optionsWnd.RefreshEntityTree(); + editor->componentsWnd.RefreshEntityTree(); }); float x = 60; @@ -228,7 +228,7 @@ void HumanoidWindow::Create(EditorComponent* _editor) // record NEW selection state... editor->RecordSelection(archive); - editor->optionsWnd.RefreshEntityTree(); + editor->componentsWnd.RefreshEntityTree(); }); AddWidget(&boneList); diff --git a/Editor/IKWindow.cpp b/Editor/IKWindow.cpp index 426960acf..997ad7026 100644 --- a/Editor/IKWindow.cpp +++ b/Editor/IKWindow.cpp @@ -21,7 +21,7 @@ void IKWindow::Create(EditorComponent* _editor) editor->RecordEntity(archive, entity); - editor->optionsWnd.RefreshEntityTree(); + editor->componentsWnd.RefreshEntityTree(); }); float x = 120; diff --git a/Editor/IconDefinitions.h b/Editor/IconDefinitions.h index 47149ac91..fb015848b 100644 --- a/Editor/IconDefinitions.h +++ b/Editor/IconDefinitions.h @@ -3,6 +3,7 @@ // These map the Font Awesome icon definitions to editor: // These definitions will help to change icons that are scattered throughout the editor code +// Search available icons: https://fontawesome.com/search?q=paper&o=r&m=free #define ICON_LAYER ICON_FA_LAYER_GROUP #define ICON_TRANSFORM ICON_FA_LOCATION_DOT #define ICON_MESH ICON_FA_CUBE @@ -73,6 +74,7 @@ #define ICON_STOP ICON_FA_STOP #define ICON_PEN ICON_FA_PEN #define ICON_FILTER ICON_FA_FILTER +#define ICON_SEARCH ICON_FA_MAGNIFYING_GLASS #define ICON_SAVE_EMBED ICON_FA_FILE_ZIPPER #define ICON_SAVE_NO_EMBED ICON_FA_FILE #define ICON_SAVE_HEADER ICON_FA_FILE_CODE @@ -83,3 +85,9 @@ #define ICON_SOFT ICON_FA_LEAF #define ICON_HACKING ICON_FA_COMPUTER #define ICON_NORD ICON_FA_MOUNTAIN + +#define ICON_GENERALOPTIONS ICON_FA_GEAR +#define ICON_GRAPHICSOPTIONS ICON_FA_DISPLAY +#define ICON_CAMERAOPTIONS ICON_CAMERA +#define ICON_MATERIALBROWSER ICON_MATERIAL +#define ICON_PAINTTOOL ICON_FA_PAINTBRUSH diff --git a/Editor/LayerWindow.cpp b/Editor/LayerWindow.cpp index 339657ec1..762467fb9 100644 --- a/Editor/LayerWindow.cpp +++ b/Editor/LayerWindow.cpp @@ -21,7 +21,7 @@ void LayerWindow::Create(EditorComponent* _editor) editor->RecordEntity(archive, entity); - editor->optionsWnd.RefreshEntityTree(); + editor->componentsWnd.RefreshEntityTree(); }); float x = 30; diff --git a/Editor/LightWindow.cpp b/Editor/LightWindow.cpp index 907e30ef3..dc925ac5b 100644 --- a/Editor/LightWindow.cpp +++ b/Editor/LightWindow.cpp @@ -22,7 +22,7 @@ void LightWindow::Create(EditorComponent* _editor) editor->RecordEntity(archive, entity); - editor->optionsWnd.RefreshEntityTree(); + editor->componentsWnd.RefreshEntityTree(); }); float x = 130; @@ -463,7 +463,7 @@ void LightWindow::RefreshCascades() addCascadeButton.SetEnabled(true); // refresh theme: - editor->optionsWnd.generalWnd.themeCombo.SetSelected(editor->optionsWnd.generalWnd.themeCombo.GetSelected()); + editor->generalWnd.themeCombo.SetSelected(editor->generalWnd.themeCombo.GetSelected()); } diff --git a/Editor/MaterialPickerWindow.cpp b/Editor/MaterialPickerWindow.cpp index 834a91635..90f6da769 100644 --- a/Editor/MaterialPickerWindow.cpp +++ b/Editor/MaterialPickerWindow.cpp @@ -8,13 +8,14 @@ using namespace wi::scene; void MaterialPickerWindow::Create(EditorComponent* _editor) { editor = _editor; - wi::gui::Window::Create("Materials", wi::gui::Window::WindowControls::COLLAPSE); + wi::gui::Window::Create("Materials", wi::gui::Window::WindowControls::CLOSE | wi::gui::Window::WindowControls::RESIZE_RIGHT); + SetText("Materials " ICON_MATERIALBROWSER); SetSize(XMFLOAT2(300, 400)); zoomSlider.Create(10, 100, 100, 100 - 10, "Zoom: "); AddWidget(&zoomSlider); - SetCollapsed(true); + SetVisible(false); } void MaterialPickerWindow::RecreateButtons() diff --git a/Editor/MaterialWindow.cpp b/Editor/MaterialWindow.cpp index de2749409..25704d34a 100644 --- a/Editor/MaterialWindow.cpp +++ b/Editor/MaterialWindow.cpp @@ -22,7 +22,7 @@ void MaterialWindow::Create(EditorComponent* _editor) editor->RecordEntity(archive, entity); - editor->optionsWnd.RefreshEntityTree(); + editor->componentsWnd.RefreshEntityTree(); }); float hei = 18; @@ -505,7 +505,7 @@ void MaterialWindow::Create(EditorComponent* _editor) { *name = args.sValue; - editor->optionsWnd.RefreshEntityTree(); + editor->componentsWnd.RefreshEntityTree(); } }); AddWidget(&materialNameField); diff --git a/Editor/MeshWindow.cpp b/Editor/MeshWindow.cpp index 859e8823b..ad374036c 100644 --- a/Editor/MeshWindow.cpp +++ b/Editor/MeshWindow.cpp @@ -25,7 +25,7 @@ void MeshWindow::Create(EditorComponent* _editor) editor->RecordEntity(archive, entity); - editor->optionsWnd.RefreshEntityTree(); + editor->componentsWnd.RefreshEntityTree(); }); float x = 95; diff --git a/Editor/NameWindow.cpp b/Editor/NameWindow.cpp index df769ded3..88acc8fa6 100644 --- a/Editor/NameWindow.cpp +++ b/Editor/NameWindow.cpp @@ -21,7 +21,7 @@ void NameWindow::Create(EditorComponent* _editor) editor->RecordEntity(archive, entity); - editor->optionsWnd.RefreshEntityTree(); + editor->componentsWnd.RefreshEntityTree(); }); float x = 60; @@ -42,7 +42,7 @@ void NameWindow::Create(EditorComponent* _editor) } name->name = args.sValue; - editor->optionsWnd.RefreshEntityTree(); + editor->componentsWnd.RefreshEntityTree(); }); AddWidget(&nameInput); diff --git a/Editor/ObjectWindow.cpp b/Editor/ObjectWindow.cpp index 2dd043a97..150e259cf 100644 --- a/Editor/ObjectWindow.cpp +++ b/Editor/ObjectWindow.cpp @@ -270,7 +270,7 @@ void ObjectWindow::Create(EditorComponent* _editor) editor->RecordEntity(archive, entity); - editor->optionsWnd.RefreshEntityTree(); + editor->componentsWnd.RefreshEntityTree(); }); float x = 140; diff --git a/Editor/OptionsWindow.cpp b/Editor/OptionsWindow.cpp deleted file mode 100644 index e9300efb8..000000000 --- a/Editor/OptionsWindow.cpp +++ /dev/null @@ -1,771 +0,0 @@ -#include "stdafx.h" -#include "OptionsWindow.h" - -using namespace wi::ecs; -using namespace wi::scene; -using namespace wi::graphics; - -void OptionsWindow::Create(EditorComponent* _editor) -{ - editor = _editor; - - wi::gui::Window::Create("Options", wi::gui::Window::WindowControls::RESIZE_TOPRIGHT); - SetShadowRadius(2); - - enum NEW_THING - { - NEW_TRANSFORM, - NEW_MATERIAL, - NEW_POINTLIGHT, - NEW_SPOTLIGHT, - NEW_DIRECTIONALLIGHT, - NEW_ENVIRONMENTPROBE, - NEW_FORCE, - NEW_DECAL, - NEW_SOUND, - NEW_VIDEO, - NEW_WEATHER, - NEW_EMITTER, - NEW_HAIR, - NEW_CAMERA, - NEW_CUBE, - NEW_PLANE, - NEW_SPHERE, - NEW_ANIMATION, - NEW_SCRIPT, - NEW_COLLIDER, - NEW_TERRAIN, - NEW_SPRITE, - NEW_FONT, - NEW_VOXELGRID, - }; - - newCombo.Create("New: "); - newCombo.selected_font.anim.typewriter.looped = true; - newCombo.selected_font.anim.typewriter.time = 2; - newCombo.selected_font.anim.typewriter.character_start = 1; - newCombo.SetInvalidSelectionText("..."); - newCombo.AddItem("Transform " ICON_TRANSFORM, NEW_TRANSFORM); - newCombo.AddItem("Material " ICON_MATERIAL, NEW_MATERIAL); - newCombo.AddItem("Point Light " ICON_POINTLIGHT, NEW_POINTLIGHT); - newCombo.AddItem("Spot Light " ICON_SPOTLIGHT, NEW_SPOTLIGHT); - newCombo.AddItem("Directional Light " ICON_DIRECTIONALLIGHT, NEW_DIRECTIONALLIGHT); - newCombo.AddItem("Environment Probe " ICON_ENVIRONMENTPROBE, NEW_ENVIRONMENTPROBE); - newCombo.AddItem("Force " ICON_FORCE, NEW_FORCE); - newCombo.AddItem("Decal " ICON_DECAL, NEW_DECAL); - newCombo.AddItem("Sound " ICON_SOUND, NEW_SOUND); - newCombo.AddItem("Video " ICON_VIDEO, NEW_VIDEO); - newCombo.AddItem("Weather " ICON_WEATHER, NEW_WEATHER); - newCombo.AddItem("Emitter " ICON_EMITTER, NEW_EMITTER); - newCombo.AddItem("HairParticle " ICON_HAIR, NEW_HAIR); - newCombo.AddItem("Camera " ICON_CAMERA, NEW_CAMERA); - newCombo.AddItem("Cube " ICON_CUBE, NEW_CUBE); - newCombo.AddItem("Plane " ICON_SQUARE, NEW_PLANE); - newCombo.AddItem("Sphere " ICON_CIRCLE, NEW_SPHERE); - newCombo.AddItem("Animation " ICON_ANIMATION, NEW_ANIMATION); - newCombo.AddItem("Script " ICON_SCRIPT, NEW_SCRIPT); - newCombo.AddItem("Collider " ICON_COLLIDER, NEW_COLLIDER); - newCombo.AddItem("Terrain " ICON_TERRAIN, NEW_TERRAIN); - newCombo.AddItem("Sprite " ICON_SPRITE, NEW_SPRITE); - newCombo.AddItem("Font " ICON_FONT, NEW_FONT); - newCombo.AddItem("Voxel Grid " ICON_VOXELGRID, NEW_VOXELGRID); - newCombo.OnSelect([&](wi::gui::EventArgs args) { - newCombo.SetSelectedWithoutCallback(-1); - const EditorComponent::EditorScene& editorscene = editor->GetCurrentEditorScene(); - const CameraComponent& camera = editorscene.camera; - Scene& scene = editor->GetCurrentScene(); - PickResult pick; - - XMFLOAT3 in_front_of_camera; - XMStoreFloat3(&in_front_of_camera, XMVectorAdd(camera.GetEye(), camera.GetAt() * 4)); - - switch (args.userdata) - { - case NEW_TRANSFORM: - pick.entity = scene.Entity_CreateTransform("transform"); - break; - case NEW_MATERIAL: - pick.entity = scene.Entity_CreateMaterial("material"); - break; - case NEW_POINTLIGHT: - pick.entity = scene.Entity_CreateLight("pointlight", in_front_of_camera, XMFLOAT3(1, 1, 1), 2, 60); - scene.lights.GetComponent(pick.entity)->type = LightComponent::POINT; - scene.lights.GetComponent(pick.entity)->intensity = 20; - break; - case NEW_SPOTLIGHT: - pick.entity = scene.Entity_CreateLight("spotlight", in_front_of_camera, XMFLOAT3(1, 1, 1), 2, 60); - scene.lights.GetComponent(pick.entity)->type = LightComponent::SPOT; - scene.lights.GetComponent(pick.entity)->intensity = 100; - break; - case NEW_DIRECTIONALLIGHT: - pick.entity = scene.Entity_CreateLight("dirlight", XMFLOAT3(0, 3, 0), XMFLOAT3(1, 1, 1), 2, 60); - scene.lights.GetComponent(pick.entity)->type = LightComponent::DIRECTIONAL; - scene.lights.GetComponent(pick.entity)->intensity = 10; - break; - case NEW_ENVIRONMENTPROBE: - pick.entity = scene.Entity_CreateEnvironmentProbe("envprobe", in_front_of_camera); - break; - case NEW_FORCE: - pick.entity = scene.Entity_CreateForce("force"); - break; - case NEW_DECAL: - pick.entity = scene.Entity_CreateDecal("decal", ""); - if (scene.materials.Contains(pick.entity)) - { - MaterialComponent* decal_material = scene.materials.GetComponent(pick.entity); - decal_material->textures[MaterialComponent::BASECOLORMAP].resource.SetTexture(*wi::texturehelper::getLogo()); - } - scene.transforms.GetComponent(pick.entity)->RotateRollPitchYaw(XMFLOAT3(XM_PIDIV2, 0, 0)); - break; - case NEW_SOUND: - { - wi::helper::FileDialogParams params; - params.type = wi::helper::FileDialogParams::OPEN; - params.description = "Sound"; - params.extensions = wi::resourcemanager::GetSupportedSoundExtensions(); - wi::helper::FileDialog(params, [=](std::string fileName) { - wi::eventhandler::Subscribe_Once(wi::eventhandler::EVENT_THREAD_SAFE_POINT, [=](uint64_t userdata) { - Entity entity = editor->GetCurrentScene().Entity_CreateSound(wi::helper::GetFileNameFromPath(fileName), fileName); - - wi::Archive& archive = editor->AdvanceHistory(); - archive << EditorComponent::HISTORYOP_ADD; - editor->RecordSelection(archive); - - editor->ClearSelected(); - editor->AddSelected(entity); - - editor->RecordSelection(archive); - editor->RecordEntity(archive, entity); - - RefreshEntityTree(); - editor->componentsWnd.soundWnd.SetEntity(entity); - }); - }); - return; - } - break; - case NEW_VIDEO: - { - wi::helper::FileDialogParams params; - params.type = wi::helper::FileDialogParams::OPEN; - params.description = "Video"; - params.extensions = wi::resourcemanager::GetSupportedVideoExtensions(); - wi::helper::FileDialog(params, [=](std::string fileName) { - wi::eventhandler::Subscribe_Once(wi::eventhandler::EVENT_THREAD_SAFE_POINT, [=](uint64_t userdata) { - Entity entity = editor->GetCurrentScene().Entity_CreateVideo(wi::helper::GetFileNameFromPath(fileName), fileName); - - wi::Archive& archive = editor->AdvanceHistory(); - archive << EditorComponent::HISTORYOP_ADD; - editor->RecordSelection(archive); - - editor->ClearSelected(); - editor->AddSelected(entity); - - editor->RecordSelection(archive); - editor->RecordEntity(archive, entity); - - RefreshEntityTree(); - editor->componentsWnd.videoWnd.SetEntity(entity); - }); - }); - return; - } - break; - case NEW_WEATHER: - pick.entity = CreateEntity(); - scene.weathers.Create(pick.entity); - scene.names.Create(pick.entity) = "weather"; - break; - case NEW_EMITTER: - pick.entity = scene.Entity_CreateEmitter("emitter"); - break; - case NEW_HAIR: - pick.entity = scene.Entity_CreateHair("hair"); - break; - case NEW_CAMERA: - pick.entity = scene.Entity_CreateCamera("camera", camera.width, camera.height); - *scene.cameras.GetComponent(pick.entity) = camera; - *scene.transforms.GetComponent(pick.entity) = editorscene.camera_transform; - break; - case NEW_CUBE: - pick.entity = scene.Entity_CreateCube("cube"); - pick.subsetIndex = 0; - break; - case NEW_PLANE: - pick.entity = scene.Entity_CreatePlane("plane"); - pick.subsetIndex = 0; - break; - case NEW_SPHERE: - pick.entity = scene.Entity_CreateSphere("sphere"); - pick.subsetIndex = 0; - break; - case NEW_ANIMATION: - pick.entity = CreateEntity(); - scene.animations.Create(pick.entity); - scene.names.Create(pick.entity) = "animation"; - break; - case NEW_SCRIPT: - pick.entity = CreateEntity(); - scene.scripts.Create(pick.entity); - scene.names.Create(pick.entity) = "script"; - break; - case NEW_COLLIDER: - pick.entity = CreateEntity(); - scene.colliders.Create(pick.entity); - scene.transforms.Create(pick.entity); - scene.names.Create(pick.entity) = "collider"; - break; - case NEW_TERRAIN: - editor->componentsWnd.terrainWnd.entity = pick.entity; - editor->componentsWnd.terrainWnd.SetupAssets(); - pick.entity = CreateEntity(); - scene.terrains.Create(pick.entity) = editor->componentsWnd.terrainWnd.terrain_preset; - scene.names.Create(pick.entity) = "terrain"; - break; - case NEW_SPRITE: - { - pick.entity = CreateEntity(); - wi::Sprite& sprite = scene.sprites.Create(pick.entity); - sprite.params.pivot = XMFLOAT2(0.5f, 0.5f); - sprite.anim.repeatable = true; - scene.transforms.Create(pick.entity).Translate(XMFLOAT3(0, 2, 0)); - scene.names.Create(pick.entity) = "sprite"; - } - break; - case NEW_FONT: - { - pick.entity = CreateEntity(); - wi::SpriteFont& font = scene.fonts.Create(pick.entity); - font.SetText("Text"); - font.params.h_align = wi::font::Alignment::WIFALIGN_CENTER; - font.params.v_align = wi::font::Alignment::WIFALIGN_CENTER; - font.params.scaling = 0.1f; - font.params.size = 26; - font.anim.typewriter.looped = true; - scene.transforms.Create(pick.entity).Translate(XMFLOAT3(0, 2, 0)); - scene.names.Create(pick.entity) = "font"; - } - break; - case NEW_VOXELGRID: - { - pick.entity = CreateEntity(); - scene.voxel_grids.Create(pick.entity).init(64, 64, 64); - scene.transforms.Create(pick.entity).Scale(XMFLOAT3(0.25f, 0.25f, 0.25f)); - scene.names.Create(pick.entity) = "voxelgrid"; - } - break; - default: - break; - } - if (pick.entity != INVALID_ENTITY) - { - wi::Archive& archive = editor->AdvanceHistory(); - archive << EditorComponent::HISTORYOP_ADD; - editor->RecordSelection(archive); - - editor->ClearSelected(); - editor->AddSelected(pick); - - editor->RecordSelection(archive); - editor->RecordEntity(archive, pick.entity); - } - RefreshEntityTree(); - }); - newCombo.SetEnabled(true); - newCombo.SetTooltip("Create new entity"); - AddWidget(&newCombo); - - - - - - filterCombo.Create(""); - filterCombo.AddItem("*", (uint64_t)Filter::All); - filterCombo.AddItem(ICON_TRANSFORM, (uint64_t)Filter::Transform); - filterCombo.AddItem(ICON_MATERIAL, (uint64_t)Filter::Material); - filterCombo.AddItem(ICON_MESH, (uint64_t)Filter::Mesh); - filterCombo.AddItem(ICON_OBJECT, (uint64_t)Filter::Object); - filterCombo.AddItem(ICON_ENVIRONMENTPROBE, (uint64_t)Filter::EnvironmentProbe); - filterCombo.AddItem(ICON_DECAL, (uint64_t)Filter::Decal); - filterCombo.AddItem(ICON_SOUND, (uint64_t)Filter::Sound); - filterCombo.AddItem(ICON_VIDEO, (uint64_t)Filter::Video); - filterCombo.AddItem(ICON_WEATHER, (uint64_t)Filter::Weather); - filterCombo.AddItem(ICON_POINTLIGHT, (uint64_t)Filter::Light); - filterCombo.AddItem(ICON_ANIMATION, (uint64_t)Filter::Animation); - filterCombo.AddItem(ICON_FORCE, (uint64_t)Filter::Force); - filterCombo.AddItem(ICON_EMITTER, (uint64_t)Filter::Emitter); - filterCombo.AddItem(ICON_HAIR, (uint64_t)Filter::Hairparticle); - filterCombo.AddItem(ICON_IK, (uint64_t)Filter::IK); - filterCombo.AddItem(ICON_CAMERA, (uint64_t)Filter::Camera); - filterCombo.AddItem(ICON_ARMATURE, (uint64_t)Filter::Armature); - filterCombo.AddItem(ICON_SPRING, (uint64_t)Filter::Spring); - filterCombo.AddItem(ICON_COLLIDER, (uint64_t)Filter::Collider); - filterCombo.AddItem(ICON_SCRIPT, (uint64_t)Filter::Script); - filterCombo.AddItem(ICON_EXPRESSION, (uint64_t)Filter::Expression); - filterCombo.AddItem(ICON_HUMANOID, (uint64_t)Filter::Humanoid); - filterCombo.AddItem(ICON_TERRAIN, (uint64_t)Filter::Terrain); - filterCombo.AddItem(ICON_SPRITE, (uint64_t)Filter::Sprite); - filterCombo.AddItem(ICON_FONT, (uint64_t)Filter::Font); - filterCombo.AddItem(ICON_VOXELGRID, (uint64_t)Filter::VoxelGrid); - filterCombo.AddItem(ICON_RIGIDBODY, (uint64_t)Filter::RigidBody); - filterCombo.AddItem(ICON_SOFTBODY, (uint64_t)Filter::SoftBody); - filterCombo.SetTooltip("Apply filtering to the Entities by components"); - filterCombo.OnSelect([&](wi::gui::EventArgs args) { - filter = (Filter)args.userdata; - RefreshEntityTree(); - }); - AddWidget(&filterCombo); - - - filterInput.Create(""); - filterInput.SetTooltip("Apply filtering to the Entities by name"); - filterInput.SetDescription(ICON_FILTER ": "); - filterInput.SetCancelInputEnabled(false); - filterInput.OnInput([=](wi::gui::EventArgs args) { - RefreshEntityTree(); - }); - AddWidget(&filterInput); - - filterCaseCheckBox.Create(""); - filterCaseCheckBox.SetCheckText("Aa"); - filterCaseCheckBox.SetUnCheckText("a"); - filterCaseCheckBox.SetTooltip("Toggle case-sensitive name filtering"); - filterCaseCheckBox.OnClick([=](wi::gui::EventArgs args) { - RefreshEntityTree(); - }); - AddWidget(&filterCaseCheckBox); - - - entityTree.Create("Entities"); - entityTree.SetSize(XMFLOAT2(300, 300)); - entityTree.OnSelect([this](wi::gui::EventArgs args) { - - if (args.iValue < 0) - return; - - wi::Archive& archive = editor->AdvanceHistory(); - archive << EditorComponent::HISTORYOP_SELECTION; - // record PREVIOUS selection state... - editor->RecordSelection(archive); - - editor->translator.selected.clear(); - - for (int i = 0; i < entityTree.GetItemCount(); ++i) - { - const wi::gui::TreeList::Item& item = entityTree.GetItem(i); - if (item.selected) - { - wi::scene::PickResult pick; - pick.entity = (Entity)item.userdata; - editor->AddSelected(pick); - } - } - - // record NEW selection state... - editor->RecordSelection(archive); - - }); - entityTree.OnDelete([=](wi::gui::EventArgs args) { - // Deletions will be performed in a batch next frame: - // We don't delete here, because this callback will execute once for each item - editor->deleting = true; - }); - AddWidget(&entityTree); - - graphicsWnd.Create(editor); - graphicsWnd.SetCollapsed(true); - AddWidget(&graphicsWnd); - - cameraWnd.Create(editor); - cameraWnd.SetCollapsed(true); - AddWidget(&cameraWnd); - - paintToolWnd.Create(editor); - paintToolWnd.SetCollapsed(true); - AddWidget(&paintToolWnd); - - materialPickerWnd.Create(editor); - AddWidget(&materialPickerWnd); - - - generalWnd.Create(editor); - generalWnd.SetCollapsed(true); - AddWidget(&generalWnd); - - - XMFLOAT2 size = XMFLOAT2(338, 500); - if (editor->main->config.GetSection("layout").Has("options.width")) - { - size.x = editor->main->config.GetSection("layout").GetFloat("options.width"); - } - if (editor->main->config.GetSection("layout").Has("options.height")) - { - size.y = editor->main->config.GetSection("layout").GetFloat("options.height"); - } - SetSize(size); -} -void OptionsWindow::Update(float dt) -{ - cameraWnd.Update(); - paintToolWnd.Update(dt); - graphicsWnd.Update(); -} - -void OptionsWindow::ResizeLayout() -{ - wi::gui::Window::ResizeLayout(); - const float padding = 4; - XMFLOAT2 pos = XMFLOAT2(padding, padding); - const float width = GetWidgetAreaSize().x - padding * 2; - float x_off = 100; - editor->main->config.GetSection("layout").Set("options.width", GetSize().x); - editor->main->config.GetSection("layout").Set("options.height", GetSize().y); - - generalWnd.SetPos(pos); - generalWnd.SetSize(XMFLOAT2(width, generalWnd.GetScale().y)); - pos.y += generalWnd.GetSize().y; - pos.y += padding; - - graphicsWnd.SetPos(pos); - graphicsWnd.SetSize(XMFLOAT2(width, graphicsWnd.GetScale().y)); - pos.y += graphicsWnd.GetSize().y; - pos.y += padding; - - cameraWnd.SetPos(pos); - cameraWnd.SetSize(XMFLOAT2(width, cameraWnd.GetScale().y)); - pos.y += cameraWnd.GetSize().y; - pos.y += padding; - - materialPickerWnd.SetPos(pos); - materialPickerWnd.SetSize(XMFLOAT2(width, materialPickerWnd.GetScale().y)); - pos.y += materialPickerWnd.GetSize().y; - pos.y += padding; - - paintToolWnd.SetPos(pos); - paintToolWnd.SetSize(XMFLOAT2(width, paintToolWnd.GetScale().y)); - pos.y += paintToolWnd.GetSize().y; - pos.y += padding; - - x_off = 45; - - newCombo.SetPos(XMFLOAT2(pos.x + x_off, pos.y)); - newCombo.SetSize(XMFLOAT2(width - x_off - newCombo.GetScale().y - 1, newCombo.GetScale().y)); - pos.y += newCombo.GetSize().y; - pos.y += padding; - - - - float filterHeight = filterCombo.GetSize().y; - float filterComboWidth = 30; - - filterInput.SetPos(XMFLOAT2(pos.x + x_off, pos.y)); - filterInput.SetSize(XMFLOAT2(width - x_off - filterHeight - 5 - filterComboWidth - filterHeight, filterCombo.GetScale().y)); - - filterCaseCheckBox.SetPos(XMFLOAT2(filterInput.GetPos().x + filterInput.GetSize().x + 2, pos.y)); - filterCaseCheckBox.SetSize(XMFLOAT2(filterHeight, filterHeight)); - - filterCombo.SetPos(XMFLOAT2(filterCaseCheckBox.GetPos().x + filterCaseCheckBox.GetSize().x + 2, pos.y)); - filterCombo.SetSize(XMFLOAT2(filterComboWidth, filterHeight)); - pos.y += filterCombo.GetSize().y; - pos.y += padding; - - - - entityTree.SetPos(pos); - entityTree.SetSize(XMFLOAT2(width, editor->GetLogicalHeight() - pos.y - this->translation_local.y - this->control_size - padding)); - pos.y += entityTree.GetSize().y; - pos.y += padding; -} - - -void OptionsWindow::PushToEntityTree(wi::ecs::Entity entity, int level) -{ - if (entitytree_added_items.count(entity) != 0) - { - return; - } - const Scene& scene = editor->GetCurrentScene(); - - if (CheckEntityFilter(entity)) - { - wi::gui::TreeList::Item item; - if (filter == Filter::All) - { - item.level = level; - } - else - { - item.level = 0; - } - item.userdata = entity; - item.selected = editor->IsSelected(entity); - item.open = entitytree_opened_items.count(entity) != 0; - - const NameComponent* name = scene.names.GetComponent(entity); - - std::string name_string; - if (name == nullptr) - { - name_string = "[no_name] " + std::to_string(entity); - } - else if (name->name.empty()) - { - name_string = "[name_empty] " + std::to_string(entity); - } - else - { - name_string = name->name; - } - - std::string name_filter = filterInput.GetCurrentInputValue(); - if (!name_filter.empty()) - { - if (filterCaseCheckBox.GetCheck() && name_string.find(name_filter) == std::string::npos) - { - return; - } - else if (wi::helper::toUpper(name_string).find(wi::helper::toUpper(name_filter)) == std::string::npos) - { - return; - } - } - - // Icons: - if (scene.layers.Contains(entity)) - { - item.name += ICON_LAYER " "; - } - if (scene.transforms.Contains(entity)) - { - item.name += ICON_TRANSFORM " "; - } - if (scene.terrains.Contains(entity)) - { - item.name += ICON_TERRAIN " "; - } - if (scene.meshes.Contains(entity)) - { - item.name += ICON_MESH " "; - } - if (scene.objects.Contains(entity)) - { - item.name += ICON_OBJECT " "; - } - if (scene.rigidbodies.Contains(entity)) - { - item.name += ICON_RIGIDBODY " "; - } - if (scene.softbodies.Contains(entity)) - { - item.name += ICON_SOFTBODY " "; - } - if (scene.emitters.Contains(entity)) - { - item.name += ICON_EMITTER " "; - } - if (scene.hairs.Contains(entity)) - { - item.name += ICON_HAIR " "; - } - if (scene.forces.Contains(entity)) - { - item.name += ICON_FORCE " "; - } - if (scene.sounds.Contains(entity)) - { - item.name += ICON_SOUND " "; - } - if (scene.videos.Contains(entity)) - { - item.name += ICON_VIDEO " "; - } - if (scene.decals.Contains(entity)) - { - item.name += ICON_DECAL " "; - } - if (scene.cameras.Contains(entity)) - { - item.name += ICON_CAMERA " "; - } - if (scene.probes.Contains(entity)) - { - item.name += ICON_ENVIRONMENTPROBE " "; - } - if (scene.animations.Contains(entity)) - { - item.name += ICON_ANIMATION " "; - } - if (scene.animation_datas.Contains(entity)) - { - item.name += "[animation_data] "; - } - if (scene.armatures.Contains(entity)) - { - item.name += ICON_ARMATURE " "; - } - if (scene.humanoids.Contains(entity)) - { - item.name += ICON_HUMANOID " "; - } - if (scene.sprites.Contains(entity)) - { - item.name += ICON_SPRITE " "; - } - if (scene.fonts.Contains(entity)) - { - item.name += ICON_FONT " "; - } - if (scene.voxel_grids.Contains(entity)) - { - item.name += ICON_VOXELGRID " "; - } - if (scene.lights.Contains(entity)) - { - const LightComponent* light = scene.lights.GetComponent(entity); - switch (light->type) - { - default: - case LightComponent::POINT: - item.name += ICON_POINTLIGHT " "; - break; - case LightComponent::SPOT: - item.name += ICON_SPOTLIGHT " "; - break; - case LightComponent::DIRECTIONAL: - item.name += ICON_DIRECTIONALLIGHT " "; - break; - } - } - if (scene.materials.Contains(entity)) - { - item.name += ICON_MATERIAL " "; - } - if (scene.weathers.Contains(entity)) - { - item.name += ICON_WEATHER " "; - } - if (scene.inverse_kinematics.Contains(entity)) - { - item.name += ICON_IK " "; - } - if (scene.springs.Contains(entity)) - { - item.name += ICON_SPRING " "; - } - if (scene.colliders.Contains(entity)) - { - item.name += ICON_COLLIDER " "; - } - if (scene.scripts.Contains(entity)) - { - item.name += ICON_SCRIPT " "; - } - if (scene.expressions.Contains(entity)) - { - item.name += ICON_EXPRESSION " "; - } - bool bone_found = false; - for (size_t i = 0; i < scene.armatures.GetCount() && !bone_found; ++i) - { - const ArmatureComponent& armature = scene.armatures[i]; - for (Entity bone : armature.boneCollection) - { - if (entity == bone) - { - item.name += ICON_BONE " "; - bone_found = true; - break; - } - } - } - - item.name += name_string; - entityTree.AddItem(item); - - entitytree_added_items.insert(entity); - } - - for (size_t i = 0; i < scene.hierarchy.GetCount(); ++i) - { - if (scene.hierarchy[i].parentID == entity) - { - PushToEntityTree(scene.hierarchy.GetEntity(i), level + 1); - } - } -} -void OptionsWindow::RefreshEntityTree() -{ - const Scene& scene = editor->GetCurrentScene(); - materialPickerWnd.RecreateButtons(); - - for (int i = 0; i < entityTree.GetItemCount(); ++i) - { - const wi::gui::TreeList::Item& item = entityTree.GetItem(i); - if (item.open) - { - entitytree_opened_items.insert((Entity)item.userdata); - } - } - - entityTree.ClearItems(); - - entitytree_temp_items.clear(); - scene.FindAllEntities(entitytree_temp_items); - - // Add items to level 0 that are not in hierarchy (not in hierarchy can also mean top level parent): - // Note that PushToEntityTree will add children recursively, so this is all we need - for (auto& x : entitytree_temp_items) - { - if (!scene.hierarchy.Contains(x)) - { - PushToEntityTree(x, 0); - } - } - - entitytree_added_items.clear(); - entitytree_opened_items.clear(); -} - -bool OptionsWindow::CheckEntityFilter(wi::ecs::Entity entity) -{ - if (filter == Filter::All) - return true; - - const Scene& scene = editor->GetCurrentScene(); - bool valid = false; - - if ( - has_flag(filter, Filter::Transform) && scene.transforms.Contains(entity) || - has_flag(filter, Filter::Material) && scene.materials.Contains(entity) || - has_flag(filter, Filter::Mesh) && scene.meshes.Contains(entity) || - has_flag(filter, Filter::Object) && scene.objects.Contains(entity) || - has_flag(filter, Filter::EnvironmentProbe) && scene.probes.Contains(entity) || - has_flag(filter, Filter::Decal) && scene.decals.Contains(entity) || - has_flag(filter, Filter::Sound) && scene.sounds.Contains(entity) || - has_flag(filter, Filter::Weather) && scene.weathers.Contains(entity) || - has_flag(filter, Filter::Light) && scene.lights.Contains(entity) || - has_flag(filter, Filter::Animation) && scene.animations.Contains(entity) || - has_flag(filter, Filter::Force) && scene.forces.Contains(entity) || - has_flag(filter, Filter::Emitter) && scene.emitters.Contains(entity) || - has_flag(filter, Filter::IK) && scene.inverse_kinematics.Contains(entity) || - has_flag(filter, Filter::Camera) && scene.cameras.Contains(entity) || - has_flag(filter, Filter::Armature) && scene.armatures.Contains(entity) || - has_flag(filter, Filter::Collider) && scene.colliders.Contains(entity) || - has_flag(filter, Filter::Script) && scene.scripts.Contains(entity) || - has_flag(filter, Filter::Expression) && scene.expressions.Contains(entity) || - has_flag(filter, Filter::Terrain) && scene.terrains.Contains(entity) || - has_flag(filter, Filter::Spring) && scene.springs.Contains(entity) || - has_flag(filter, Filter::Humanoid) && scene.humanoids.Contains(entity) || - has_flag(filter, Filter::Video) && scene.videos.Contains(entity) || - has_flag(filter, Filter::Sprite) && scene.sprites.Contains(entity) || - has_flag(filter, Filter::Font) && scene.fonts.Contains(entity) || - has_flag(filter, Filter::VoxelGrid) && scene.voxel_grids.Contains(entity) || - has_flag(filter, Filter::RigidBody) && scene.rigidbodies.Contains(entity) || - has_flag(filter, Filter::SoftBody) && scene.softbodies.Contains(entity) - ) - { - valid = true; - } - - return valid; -} diff --git a/Editor/OptionsWindow.h b/Editor/OptionsWindow.h deleted file mode 100644 index efe7f9b2a..000000000 --- a/Editor/OptionsWindow.h +++ /dev/null @@ -1,75 +0,0 @@ -#pragma once -#include "GraphicsWindow.h" -#include "CameraWindow.h" -#include "MaterialPickerWindow.h" -#include "PaintToolWindow.h" -#include "GeneralWindow.h" - -class EditorComponent; - -class OptionsWindow : public wi::gui::Window -{ -public: - void Create(EditorComponent* editor); - void Update(float dt); - - void ResizeLayout() override; - - EditorComponent* editor = nullptr; - GeneralWindow generalWnd; - GraphicsWindow graphicsWnd; - CameraWindow cameraWnd; - MaterialPickerWindow materialPickerWnd; - PaintToolWindow paintToolWnd; - - enum class Filter : uint64_t - { - Transform = 1 << 0, - Material = 1 << 1, - Mesh = 1 << 2, - Object = 1 << 3, - EnvironmentProbe = 1 << 4, - Decal = 1 << 5, - Sound = 1 << 6, - Weather = 1 << 7, - Light = 1 << 8, - Animation = 1 << 9, - Force = 1 << 10, - Emitter = 1 << 11, - Hairparticle = 1 << 12, - IK = 1 << 13, - Camera = 1 << 14, - Armature = 1 << 15, - Collider = 1 << 16, - Script = 1 << 17, - Expression = 1 << 18, - Terrain = 1 << 19, - Spring = 1 << 20, - Humanoid = 1 << 21, - Video = 1 << 22, - Sprite = 1 << 23, - Font = 1 << 24, - VoxelGrid = 1 << 25, - RigidBody = 1 << 26, - SoftBody = 1 << 27, - - All = ~0ull, - } filter = Filter::All; - wi::gui::ComboBox newCombo; - wi::gui::ComboBox filterCombo; - wi::gui::TextInputField filterInput; - wi::gui::CheckBox filterCaseCheckBox; - wi::gui::TreeList entityTree; - wi::unordered_set entitytree_temp_items; - wi::unordered_set entitytree_added_items; - wi::unordered_set entitytree_opened_items; - void PushToEntityTree(wi::ecs::Entity entity, int level); - void RefreshEntityTree(); - - bool CheckEntityFilter(wi::ecs::Entity entity); -}; - -template<> -struct enable_bitmask_operators { - static const bool enable = true; -}; diff --git a/Editor/PaintToolWindow.cpp b/Editor/PaintToolWindow.cpp index 879435454..b32bf72c1 100644 --- a/Editor/PaintToolWindow.cpp +++ b/Editor/PaintToolWindow.cpp @@ -11,8 +11,9 @@ void PaintToolWindow::Create(EditorComponent* _editor) { editor = _editor; - wi::gui::Window::Create("Paint Tool", wi::gui::Window::WindowControls::COLLAPSE); - SetSize(XMFLOAT2(360, 800)); + wi::gui::Window::Create("Paint Tool", wi::gui::Window::WindowControls::CLOSE | wi::gui::Window::WindowControls::RESIZE_RIGHT); + SetText("Paint Tool " ICON_PAINTTOOL); + SetSize(XMFLOAT2(300, 800)); float x = 105; float y = 0; @@ -388,9 +389,7 @@ void PaintToolWindow::Create(EditorComponent* _editor) }); AddWidget(&revealTextureButton); - Translate(XMFLOAT3((float)editor->GetLogicalWidth() - 550, 50, 0)); - - SetMinimized(true); + SetVisible(false); } void PaintToolWindow::Update(float dt) @@ -469,9 +468,8 @@ void PaintToolWindow::Update(float dt) } } - auto pointer = wi::input::GetPointer(); - posNew = XMFLOAT2(pointer.x, pointer.y); - float pressureNew = pressureCheckBox.GetCheck() ? pointer.w : 1.0f; + posNew = XMFLOAT2(editor->currentMouse.x, editor->currentMouse.y); + float pressureNew = pressureCheckBox.GetCheck() ? editor->currentMouse.w : 1.0f; const MODE mode = GetMode(); const float radius = radiusSlider.GetValue(); @@ -549,7 +547,7 @@ void PaintToolWindow::Update(float dt) { case MODE_TEXTURE: { - wi::primitive::Ray pickRay = wi::renderer::GetPickRay((long)pos.x, (long)pos.y, *editor, camera); + wi::primitive::Ray pickRay = wi::renderer::GetPickRay((long)pos.x, (long)pos.y, *editor->renderPath, camera); brushIntersect = wi::scene::Pick(pickRay, ~0u, ~0u, scene); ObjectComponent* object = scene.objects.GetComponent(brushIntersect.entity); @@ -669,7 +667,7 @@ void PaintToolWindow::Update(float dt) case MODE_TERRAIN_MATERIAL: { - Ray pickRay = wi::renderer::GetPickRay((long)pos.x, (long)pos.y, *editor, camera); + Ray pickRay = wi::renderer::GetPickRay((long)pos.x, (long)pos.y, *editor->renderPath, camera); brushIntersect = wi::scene::Pick(pickRay, wi::enums::FILTER_TERRAIN, ~0u, scene); if (brushIntersect.entity == INVALID_ENTITY) break; @@ -768,7 +766,7 @@ void PaintToolWindow::Update(float dt) case MODE_VERTEXCOLOR: case MODE_WIND: { - Ray pickRay = wi::renderer::GetPickRay((long)pos.x, (long)pos.y, *editor, camera); + Ray pickRay = wi::renderer::GetPickRay((long)pos.x, (long)pos.y, *editor->renderPath, camera); brushIntersect = wi::scene::Pick(pickRay, wi::enums::FILTER_OBJECT_ALL, ~0u, scene); if (brushIntersect.entity == INVALID_ENTITY) break; @@ -939,7 +937,7 @@ void PaintToolWindow::Update(float dt) case MODE_SCULPTING_ADD: case MODE_SCULPTING_SUBTRACT: { - Ray pickRay = wi::renderer::GetPickRay((long)pos.x, (long)pos.y, *editor, camera); + Ray pickRay = wi::renderer::GetPickRay((long)pos.x, (long)pos.y, *editor->renderPath, camera); brushIntersect = wi::scene::Pick(pickRay, terrain_only ? wi::enums::FILTER_TERRAIN : wi::enums::FILTER_OBJECT_ALL, ~0u, scene); if (brushIntersect.entity == INVALID_ENTITY) break; @@ -979,7 +977,7 @@ void PaintToolWindow::Update(float dt) case PaintToolWindow::AxisLock::Disabled: if (sculpting_normal.x < FLT_EPSILON && sculpting_normal.y < FLT_EPSILON && sculpting_normal.z < FLT_EPSILON) { - sculpting_normal = editor->hovered.normal; + sculpting_normal = brushIntersect.normal; } sculptDir = XMVector3TransformNormal(XMVector3Normalize(XMLoadFloat3(&sculpting_normal)), XMMatrixInverse(nullptr, W)); break; @@ -1123,7 +1121,7 @@ void PaintToolWindow::Update(float dt) wi::renderer::RenderableLine sculpt_dir_line; sculpt_dir_line.color_start = XMFLOAT4(0, 1, 0, 1); sculpt_dir_line.color_end = XMFLOAT4(0, 1, 0, 1); - sculpt_dir_line.start = editor->hovered.position; + sculpt_dir_line.start = brushIntersect.position; XMStoreFloat3( &sculpt_dir_line.end, XMLoadFloat3(&sculpt_dir_line.start) + @@ -1146,7 +1144,7 @@ void PaintToolWindow::Update(float dt) case MODE_SOFTBODY_PINNING: case MODE_SOFTBODY_PHYSICS: { - Ray pickRay = wi::renderer::GetPickRay((long)pos.x, (long)pos.y, *editor, camera); + Ray pickRay = wi::renderer::GetPickRay((long)pos.x, (long)pos.y, *editor->renderPath, camera); brushIntersect = wi::scene::Pick(pickRay, wi::enums::FILTER_OBJECT_ALL, ~0u, scene); if (brushIntersect.entity == INVALID_ENTITY) break; @@ -1254,7 +1252,7 @@ void PaintToolWindow::Update(float dt) case MODE_HAIRPARTICLE_REMOVE_TRIANGLE: case MODE_HAIRPARTICLE_LENGTH: { - Ray pickRay = wi::renderer::GetPickRay((long)pos.x, (long)pos.y, *editor, camera); + Ray pickRay = wi::renderer::GetPickRay((long)pos.x, (long)pos.y, *editor->renderPath, camera); brushIntersect = wi::scene::Pick(pickRay, wi::enums::FILTER_OBJECT_ALL, ~0u, scene); if (brushIntersect.entity == INVALID_ENTITY) break; @@ -1508,6 +1506,8 @@ void PaintToolWindow::DrawBrush(const wi::Canvas& canvas, CommandList cmd) const PaintToolWindow::MODE PaintToolWindow::GetMode() const { + if (!IsVisible()) + return MODE_DISABLED; return (MODE)modeComboBox.GetSelectedUserdata(); } @@ -2040,6 +2040,7 @@ void PaintToolWindow::RecreateTerrainMaterialButtons() button.Create(""); AddWidget(&button); button.SetVisible(false); + button.SetEnabled(true); button.SetText(""); button.SetTooltip(""); diff --git a/Editor/ProfilerWindow.cpp b/Editor/ProfilerWindow.cpp index 0f430da9c..077b57862 100644 --- a/Editor/ProfilerWindow.cpp +++ b/Editor/ProfilerWindow.cpp @@ -49,25 +49,6 @@ void ProfilerWindow::Update(const wi::Canvas& canvas, float dt) sprites[i].params.corners_rounding[1].radius = 10; sprites[i].params.corners_rounding[2].radius = 10; sprites[i].params.corners_rounding[3].radius = 10; - resizeDragger_UpperLeft.sprites[i].params.enableCornerRounding(); - resizeDragger_UpperLeft.sprites[i].params.corners_rounding[0].radius = 10; - resizeDragger_UpperRight.sprites[i].params.enableCornerRounding(); - resizeDragger_UpperRight.sprites[i].params.corners_rounding[1].radius = 10; - resizeDragger_BottomLeft.sprites[i].params.enableCornerRounding(); - resizeDragger_BottomLeft.sprites[i].params.corners_rounding[2].radius = 10; - resizeDragger_BottomRight.sprites[i].params.enableCornerRounding(); - resizeDragger_BottomRight.sprites[i].params.corners_rounding[3].radius = 10; - - if (IsCollapsed()) - { - resizeDragger_UpperLeft.sprites[i].params.corners_rounding[2].radius = 10; - resizeDragger_UpperRight.sprites[i].params.corners_rounding[3].radius = 10; - } - else - { - resizeDragger_UpperLeft.sprites[i].params.corners_rounding[2].radius = 0; - resizeDragger_UpperRight.sprites[i].params.corners_rounding[3].radius = 0; - } } } void ProfilerWindow::ResizeLayout() diff --git a/Editor/RigidBodyWindow.cpp b/Editor/RigidBodyWindow.cpp index bb035d790..ac6bab1b8 100644 --- a/Editor/RigidBodyWindow.cpp +++ b/Editor/RigidBodyWindow.cpp @@ -22,7 +22,7 @@ void RigidBodyWindow::Create(EditorComponent* _editor) editor->RecordEntity(archive, entity); - editor->optionsWnd.RefreshEntityTree(); + editor->componentsWnd.RefreshEntityTree(); }); float x = 140; diff --git a/Editor/ScriptWindow.cpp b/Editor/ScriptWindow.cpp index 1bfed85cf..6e739cbe8 100644 --- a/Editor/ScriptWindow.cpp +++ b/Editor/ScriptWindow.cpp @@ -18,7 +18,7 @@ void ScriptWindow::Create(EditorComponent* _editor) editor->RecordEntity(archive, entity); - editor->optionsWnd.RefreshEntityTree(); + editor->componentsWnd.RefreshEntityTree(); }); float hei = 20; diff --git a/Editor/SoftBodyWindow.cpp b/Editor/SoftBodyWindow.cpp index 9dc398914..7e638fc8b 100644 --- a/Editor/SoftBodyWindow.cpp +++ b/Editor/SoftBodyWindow.cpp @@ -21,7 +21,7 @@ void SoftBodyWindow::Create(EditorComponent* _editor) editor->RecordEntity(archive, entity); - editor->optionsWnd.RefreshEntityTree(); + editor->componentsWnd.RefreshEntityTree(); }); float x = 95; diff --git a/Editor/SoundWindow.cpp b/Editor/SoundWindow.cpp index 1a449926f..ce6ecbb18 100644 --- a/Editor/SoundWindow.cpp +++ b/Editor/SoundWindow.cpp @@ -48,7 +48,7 @@ void SoundWindow::Create(EditorComponent* _editor) editor->RecordEntity(archive, entity); - editor->optionsWnd.RefreshEntityTree(); + editor->componentsWnd.RefreshEntityTree(); }); float x = 60; diff --git a/Editor/SpringWindow.cpp b/Editor/SpringWindow.cpp index c8a1478ae..5a06759ec 100644 --- a/Editor/SpringWindow.cpp +++ b/Editor/SpringWindow.cpp @@ -21,7 +21,7 @@ void SpringWindow::Create(EditorComponent* _editor) editor->RecordEntity(archive, entity); - editor->optionsWnd.RefreshEntityTree(); + editor->componentsWnd.RefreshEntityTree(); }); float x = 120; diff --git a/Editor/SpriteWindow.cpp b/Editor/SpriteWindow.cpp index 3e4b4de54..4313f203c 100644 --- a/Editor/SpriteWindow.cpp +++ b/Editor/SpriteWindow.cpp @@ -23,7 +23,7 @@ void SpriteWindow::Create(EditorComponent* _editor) editor->RecordEntity(archive, entity); - editor->optionsWnd.RefreshEntityTree(); + editor->componentsWnd.RefreshEntityTree(); }); textureButton.Create("Base Texture"); diff --git a/Editor/TerrainWindow.cpp b/Editor/TerrainWindow.cpp index 21bede072..3e6c19af4 100644 --- a/Editor/TerrainWindow.cpp +++ b/Editor/TerrainWindow.cpp @@ -67,6 +67,7 @@ PerlinModifierWindow::PerlinModifierWindow() : ModifierWindow("Perlin Noise") AddWidget(&octavesSlider); SetSize(XMFLOAT2(200, 140)); + SetCollapsed(true); } void PerlinModifierWindow::ResizeLayout() { @@ -140,6 +141,7 @@ VoronoiModifierWindow::VoronoiModifierWindow() : ModifierWindow("Voronoi Noise") AddWidget(&perturbationSlider); SetSize(XMFLOAT2(200, 200)); + SetCollapsed(true); } void VoronoiModifierWindow::ResizeLayout() { @@ -238,6 +240,7 @@ HeightmapModifierWindow::HeightmapModifierWindow() : ModifierWindow("Heightmap") AddWidget(&loadButton); SetSize(XMFLOAT2(200, 180)); + SetCollapsed(true); } void HeightmapModifierWindow::ResizeLayout() { @@ -545,7 +548,7 @@ void PropsWindow::AddWindow(wi::terrain::Prop& prop) windows.emplace_back().reset(wnd); - editor->optionsWnd.generalWnd.themeCombo.SetSelected(editor->optionsWnd.generalWnd.themeCombo.GetSelected()); // theme refresh + editor->generalWnd.themeCombo.SetSelected(editor->generalWnd.themeCombo.GetSelected()); // theme refresh } void PropsWindow::Update(const wi::Canvas& canvas, float dt) @@ -604,6 +607,17 @@ void PropsWindow::ResizeLayout() y += padding; }; + auto add_fullwidth = [&](wi::gui::Widget& widget) { + if (!widget.IsVisible()) + return; + const float margin_left = padding; + const float margin_right = padding; + widget.SetPos(XMFLOAT2(margin_left, y)); + widget.SetSize(XMFLOAT2(width - margin_left - margin_right, widget.GetScale().y)); + y += widget.GetSize().y; + y += padding; + }; + auto add_window = [&](wi::gui::Window& widget) { const float margin_left = padding; const float margin_right = padding; @@ -614,7 +628,7 @@ void PropsWindow::ResizeLayout() widget.SetEnabled(true); }; - add(addButton); + add_fullwidth(addButton); for(auto& window : windows) { @@ -646,7 +660,7 @@ void TerrainWindow::Create(EditorComponent* _editor) editor->RecordEntity(archive, entity); - editor->optionsWnd.RefreshEntityTree(); + editor->componentsWnd.RefreshEntityTree(); }); float x = 140; @@ -937,7 +951,7 @@ void TerrainWindow::Create(EditorComponent* _editor) generate_callback(); - editor->optionsWnd.RefreshEntityTree(); + editor->componentsWnd.RefreshEntityTree(); }); AddWidget(&presetCombo); @@ -1102,7 +1116,7 @@ void TerrainWindow::Create(EditorComponent* _editor) { terrain->materialEntities[i] = INVALID_ENTITY; } - editor->optionsWnd.paintToolWnd.RecreateTerrainMaterialButtons(); + editor->paintToolWnd.RecreateTerrainMaterialButtons(); }); AddWidget(&materialCombos[i]); @@ -1410,7 +1424,7 @@ void TerrainWindow::AddModifier(ModifierWindow* modifier_window) modifiers_to_remove.push_back(modifier_window); }); - editor->optionsWnd.generalWnd.themeCombo.SetSelected(editor->optionsWnd.generalWnd.themeCombo.GetSelected()); // theme refresh + editor->generalWnd.themeCombo.SetSelected(editor->generalWnd.themeCombo.GetSelected()); // theme refresh } void TerrainWindow::SetupAssets() { @@ -1722,7 +1736,7 @@ void TerrainWindow::SetupAssets() terrain = &terrain_preset; presetCombo.SetSelected(0); - editor->optionsWnd.paintToolWnd.RecreateTerrainMaterialButtons(); + editor->paintToolWnd.RecreateTerrainMaterialButtons(); } void TerrainWindow::Update(const wi::Canvas& canvas, float dt) diff --git a/Editor/TransformWindow.cpp b/Editor/TransformWindow.cpp index f982dfafd..750e40c97 100644 --- a/Editor/TransformWindow.cpp +++ b/Editor/TransformWindow.cpp @@ -21,7 +21,7 @@ void TransformWindow::Create(EditorComponent* _editor) editor->RecordEntity(archive, entity); - editor->optionsWnd.RefreshEntityTree(); + editor->componentsWnd.RefreshEntityTree(); }); float x = 80; diff --git a/Editor/Translator.cpp b/Editor/Translator.cpp index a737dad2e..7eb5d7cd2 100644 --- a/Editor/Translator.cpp +++ b/Editor/Translator.cpp @@ -104,7 +104,7 @@ namespace Translator_Internal } using namespace Translator_Internal; -void Translator::Update(const CameraComponent& camera, const wi::Canvas& canvas) +void Translator::Update(const CameraComponent& camera, const XMFLOAT4& currentMouse, const wi::Canvas& canvas) { if (selected.empty()) { @@ -116,7 +116,6 @@ void Translator::Update(const CameraComponent& camera, const wi::Canvas& canvas) dragStarted = false; dragEnded = false; - XMFLOAT4 pointer = wi::input::GetPointer(); XMVECTOR pos = transform.GetPositionV(); // Non recursive selection will be computed to not apply recursive operations two times @@ -144,7 +143,7 @@ void Translator::Update(const CameraComponent& camera, const wi::Canvas& canvas) if (!has_selected_transform) return; - const Ray ray = wi::renderer::GetPickRay((long)pointer.x, (long)pointer.y, canvas, camera); + const Ray ray = wi::renderer::GetPickRay((long)currentMouse.x, (long)currentMouse.y, canvas, camera); const XMVECTOR rayOrigin = XMLoadFloat3(&ray.origin); const XMVECTOR rayDir = XMLoadFloat3(&ray.direction); @@ -286,7 +285,7 @@ void Translator::Update(const CameraComponent& camera, const wi::Canvas& canvas) } } - if (dragging || (state != TRANSLATOR_IDLE && wi::input::Press(wi::input::MOUSE_BUTTON_LEFT) && interactable)) + if (dragging || (state != TRANSLATOR_IDLE && wi::input::Press(wi::input::MOUSE_BUTTON_LEFT))) { // Dragging operation: if (isRotator) @@ -491,7 +490,7 @@ void Translator::Update(const CameraComponent& camera, const wi::Canvas& canvas) dragging = false; } } -void Translator::Draw(const CameraComponent& camera, CommandList cmd) const +void Translator::Draw(const CameraComponent& camera, const XMFLOAT4& currentMouse, CommandList cmd) const { if (!IsEnabled() || selected.empty() || !has_selected_transform) { @@ -1025,47 +1024,47 @@ void Translator::Draw(const CameraComponent& camera, CommandList cmd) const device->Draw(vertexCount, 0, cmd); } - XMFLOAT4 pointer = wi::input::GetPointer(); wi::font::Params params; - params.posX = pointer.x - 20; - params.posY = pointer.y + 20; + params.posX = currentMouse.x - 20; + params.posY = currentMouse.y + 20; params.v_align = wi::font::WIFALIGN_TOP; params.h_align = wi::font::WIFALIGN_RIGHT; params.scaling = 0.8f; params.shadowColor = wi::Color::Black(); - std::string str; + + char text[256] = {}; + if (isTranslator) { - str += "Offset = " + std::to_string(transform.translation_local.x - transform_start.translation_local.x) + ", " + std::to_string(transform.translation_local.y - transform_start.translation_local.y) + ", " + std::to_string(transform.translation_local.z - transform_start.translation_local.z); + snprintf(text, arraysize(text), "Offset = %.2f, %.2f, %.2f", transform.translation_local.x - transform_start.translation_local.x, transform.translation_local.y - transform_start.translation_local.y, transform.translation_local.z - transform_start.translation_local.z); } if (isRotator) { switch (state) { case Translator::TRANSLATOR_X: - str += "Axis = X"; + snprintf(text, arraysize(text), "Axis = X\nAngle = %.2f degrees", wi::math::RadiansToDegrees(angle)); break; case Translator::TRANSLATOR_Y: - str += "Axis = Y"; + snprintf(text, arraysize(text), "Axis = Y\nAngle = %.2f degrees", wi::math::RadiansToDegrees(angle)); break; case Translator::TRANSLATOR_Z: - str += "Axis = Z"; + snprintf(text, arraysize(text), "Axis = Z\nAngle = %.2f degrees", wi::math::RadiansToDegrees(angle)); break; case Translator::TRANSLATOR_XYZ: - str += "Axis = Screen"; + snprintf(text, arraysize(text), "Axis = Screen\nAngle = %.2f degrees", wi::math::RadiansToDegrees(angle)); break; default: break; } - str += "\nAngle = " + std::to_string(int(angle / XM_PI * 180)) + " degrees"; } if (isScalator) { - str += "Scaling = " + std::to_string(transform.scale_local.x / transform_start.scale_local.x) + ", " + std::to_string(transform.scale_local.y / transform_start.scale_local.y) + ", " + std::to_string(transform.scale_local.z / transform_start.scale_local.z); + snprintf(text, arraysize(text), "Scaling = %.2f, %.2f, %.2f", transform.scale_local.x / transform_start.scale_local.x, transform.scale_local.y / transform_start.scale_local.y, transform.scale_local.z / transform_start.scale_local.z); } params.shadowColor.setA(uint8_t(opacity * 255.0f)); params.color.setA(uint8_t(opacity * 255.0f)); - wi::font::Draw(str, params, cmd); + wi::font::Draw(text, params, cmd); } device->EventEnd(cmd); diff --git a/Editor/Translator.h b/Editor/Translator.h index 41c5c540a..ff960d51e 100644 --- a/Editor/Translator.h +++ b/Editor/Translator.h @@ -13,8 +13,8 @@ private: bool has_selected_transform = false; public: - void Update(const wi::scene::CameraComponent& camera, const wi::Canvas& canvas); - void Draw(const wi::scene::CameraComponent& camera, wi::graphics::CommandList cmd) const; + void Update(const wi::scene::CameraComponent& camera, const XMFLOAT4& currentMouse, const wi::Canvas& canvas); + void Draw(const wi::scene::CameraComponent& camera, const XMFLOAT4& currentMouse, wi::graphics::CommandList cmd) const; // Attach selection to translator temporarily void PreTranslate(); @@ -49,7 +49,6 @@ public: float dist = 1; - bool interactable = true; bool isTranslator = true; bool isScalator = false; bool isRotator = false; @@ -74,6 +73,8 @@ public: // Check if the drag ended in this exact frame bool IsDragEnded() const { return dragEnded; }; + bool IsInteracting() const { return state != TRANSLATOR_IDLE; } + wi::scene::TransformComponent transform_start; wi::vector matrices_start; wi::vector matrices_current; diff --git a/Editor/VideoWindow.cpp b/Editor/VideoWindow.cpp index 2cb9c2e4d..e52371e95 100644 --- a/Editor/VideoWindow.cpp +++ b/Editor/VideoWindow.cpp @@ -44,7 +44,7 @@ void VideoWindow::Create(EditorComponent* _editor) editor->RecordEntity(archive, entity); - editor->optionsWnd.RefreshEntityTree(); + editor->componentsWnd.RefreshEntityTree(); }); float x = 60; diff --git a/Editor/VoxelGridWindow.cpp b/Editor/VoxelGridWindow.cpp index b481906f9..5d9ae8a32 100644 --- a/Editor/VoxelGridWindow.cpp +++ b/Editor/VoxelGridWindow.cpp @@ -21,7 +21,7 @@ void VoxelGridWindow::Create(EditorComponent* _editor) editor->RecordEntity(archive, entity); - editor->optionsWnd.RefreshEntityTree(); + editor->componentsWnd.RefreshEntityTree(); }); float x = 80; diff --git a/Editor/WeatherWindow.cpp b/Editor/WeatherWindow.cpp index 4aee580d9..b5fb695e1 100644 --- a/Editor/WeatherWindow.cpp +++ b/Editor/WeatherWindow.cpp @@ -22,7 +22,7 @@ void WeatherWindow::Create(EditorComponent* _editor) editor->RecordEntity(archive, entity); - editor->optionsWnd.RefreshEntityTree(); + editor->componentsWnd.RefreshEntityTree(); }); float x = 150; diff --git a/Editor/languages/Magyar.xml b/Editor/languages/Magyar.xml index 85bd85377..e44b326ed 100644 --- a/Editor/languages/Magyar.xml +++ b/Editor/languages/Magyar.xml @@ -12,6 +12,7 @@ Információ Kilépés Névtelen jelenet +Tartalmak
Új jelenet @@ -22,769 +23,766 @@
Minden háttérben futó szkript szál leállítása.
-
- Opciók -
- Grafika -
- Cube Shadowmap res: - Choose a shadow quality preset for cube shadow maps (pointlights, area lights)... +
+ Grafika +
+ Cube Shadowmap res: + Choose a shadow quality preset for cube shadow maps (pointlights, area lights)... This specifies the maximum shadow resolution for these light types, but that can dynamically change unless they are set to a fixed resolution individually. -
- Off - 128 - 256 - 512 - 1024 - 2048 -
+
+ Off + 128 + 256 + 512 + 1024 + 2048
-
- Path tracing statistics -
-
- EyeAdaption: - Enable eye adaption for the overall screen luminance -
-
- Shadow type: - Choose between shadowmaps and ray traced shadows. +
+
+ Path tracing statistics +
+
+ EyeAdaption: + Enable eye adaption for the overall screen luminance +
+
+ Shadow type: + Choose between shadowmaps and ray traced shadows. Note that ray traced shadows need hardware raytracing support, otherwise they are not available -
- Shadowmaps - Ray traced -
+
+ Shadowmaps + Ray traced
-
- Display Output: - Choose between different display output formats. +
+
+ Display Output: + Choose between different display output formats. If the display doesn't support the selected format, it will switch back to a reasonable default. HDR formats will be only selectable when the current display supports HDR output -
- SDR 8bit - SDR 10bit -
+
+ SDR 8bit + SDR 10bit
-
- VXGI Reflections: - Toggle specular reflections computation for VXGI. +
+
+ VXGI Reflections: + Toggle specular reflections computation for VXGI. +
+
+ Choose Surfel GI debug visualization. +
+ No Debug + Normal + Color + Point + Random + Heatmap + Inconsist.
-
- Choose Surfel GI debug visualization. -
- No Debug - Normal - Color - Point - Random - Heatmap - Inconsist. -
-
-
- Key: - Set the key value for eye adaption. -
-
- Sample count: - The path tracing will perform this many samples per pixel. -
-
- Strength: - The lens distortion amount. -
-
- VXGI Distance: - Adjust max raymarching distance for VXGI. -
-
- Probe count in X dimension. -
-
- Rate: - Set the eye adaption rate (speed of adjustment) -
-
- Sample Count: - Set AO ray count. Only for SSAO -
-
- Cartoon Outline: - Toggle the cartoon outline effect. Only those materials will be outlined that have Cartoon Outline enabled. -
-
- Cutoff: - Set maximum roughness which can be used to apply screen space or raytraced reflections. -
-
- Transparent Shadows: - Enables color tinted shadows and refraction caustics effects for transparent objects and water. -
-
- DDGI RayCount: - Adjust the ray count per DDGI probe. -
-
- 2.5D Light Culling: - Enable a more aggressive light culling approach which can result in slower culling but faster rendering (Tiled renderer only) -
-
- 2D Shadowmap res: - Choose a shadow quality preset for 2D shadow maps (spotlights, directional lights)... +
+
+ Key: + Set the key value for eye adaption. +
+
+ Sample count: + The path tracing will perform this many samples per pixel. +
+
+ Strength: + The lens distortion amount. +
+
+ VXGI Distance: + Adjust max raymarching distance for VXGI. +
+
+ Probe count in X dimension. +
+
+ Rate: + Set the eye adaption rate (speed of adjustment) +
+
+ Sample Count: + Set AO ray count. Only for SSAO +
+
+ Cartoon Outline: + Toggle the cartoon outline effect. Only those materials will be outlined that have Cartoon Outline enabled. +
+
+ Cutoff: + Set maximum roughness which can be used to apply screen space or raytraced reflections. +
+
+ Transparent Shadows: + Enables color tinted shadows and refraction caustics effects for transparent objects and water. +
+
+ DDGI RayCount: + Adjust the ray count per DDGI probe. +
+
+ 2.5D Light Culling: + Enable a more aggressive light culling approach which can result in slower culling but faster rendering (Tiled renderer only) +
+
+ 2D Shadowmap res: + Choose a shadow quality preset for 2D shadow maps (spotlights, directional lights)... This specifies the maximum shadow resolution for these light types, but that can dynamically change unless they are set to a fixed resolution individually. -
- Off - 128 - 256 - 512 - 1024 - 2048 - 4096 -
+
+ Off + 128 + 256 + 512 + 1024 + 2048 + 4096
-
- DDGI Smoothen: - Adjust the amount of smooth backface test. +
+
+ DDGI Smoothen: + Adjust the amount of smooth backface test. +
+
+ RT Reflections: + Enable Ray Traced Reflections. Only if GPU supports raytracing. +
+
+ AO: + Choose Ambient Occlusion type. RTAO is only available if hardware supports ray tracing +
+ Disabled + SSAO + HBAO + MSAO + RTAO
-
- RT Reflections: - Enable Ray Traced Reflections. Only if GPU supports raytracing. -
-
- AO: - Choose Ambient Occlusion type. RTAO is only available if hardware supports ray tracing -
- Disabled - SSAO - HBAO - MSAO - RTAO -
-
-
- Power: - Set SSAO Power. Higher values produce darker, more pronounced effect -
-
- Visibility Compute Shading: - Visibility Compute Shading (experimental) +
+
+ Power: + Set SSAO Power. Higher values produce darker, more pronounced effect +
+
+ Visibility Compute Shading: + Visibility Compute Shading (experimental) This will shade the scene in compute shaders instead of pixel shaders This has a higher initial performance cost, but it will be faster in high polygon scenes. It is not compatible with MSAA and tessellation. -
-
- Render Path: - Choose a render path... +
+
+ Render Path: + Choose a render path... Path tracing will use fallback raytracing with non-raytracing GPU, which will be slow. Changing render path will reset some graphics settings! -
- Default - Path Tracing -
+
+ Default + Path Tracing
-
- Raytrace Bounces: - How many light bounces to compute when doing these ray tracing effects: +
+
+ Raytrace Bounces: + How many light bounces to compute when doing these ray tracing effects: - Path tracing - Lightmap baking -
-
- DEBUG: - Disable blending of frame history. Camera Subpixel jitter will be visible. -
-
- Threshold: - Outline edge detection threshold. Increase if not enough otlines are detected, decrease if too many outlines are detected. -
-
- FSR 2.1 Preset: - Set resolution scaling quality mode for FSR 2.1: +
+
+ DEBUG: + Disable blending of frame history. Camera Subpixel jitter will be visible. +
+
+ Threshold: + Outline edge detection threshold. Increase if not enough otlines are detected, decrease if too many outlines are detected. +
+
+ FSR 2.1 Preset: + Set resolution scaling quality mode for FSR 2.1: Quality: 1.5x Balanced: 1.7x Performance: 2.0x Ultra performance: 3.0x -
- Quality - Balanced - Performance - Ultra performance -
+
+ Quality + Balanced + Performance + Ultra performance
-
- DepthOfField: - Enable Depth of field effect. Requires additional camera setup: focal length and aperture size. -
-
- Dithering: - Toggle the full screen dithering effect. This helps to reduce color banding. -
-
- VXGI Ray Step: - Adjust the precision of ray marching for [reflection] cone tracing step. Lower values = more precision but slower performance. -
-
- GI Boost: - Adjust the strength of GI. +
+
+ DepthOfField: + Enable Depth of field effect. Requires additional camera setup: focal length and aperture size. +
+
+ Dithering: + Toggle the full screen dithering effect. This helps to reduce color banding. +
+
+ VXGI Ray Step: + Adjust the precision of ray marching for [reflection] cone tracing step. Lower values = more precision but slower performance. +
+
+ GI Boost: + Adjust the strength of GI. Note that values other than 1.0 will cause mismatch with path tracing reference! +
+
+ DEBUG: + Toggle visualization of the screen space light culling heatmap grid (Tiled renderer only) +
+
+ Thickness: + Set outline thickness. +
+
+ Tessellation: + Enable tessellation feature. You also need to specify a tessellation factor for individual objects. +
+
+ VSync: + Toggle vertical sync +
+
+ Surfel GI: + Surfel GI is a raytraced diffuse GI using raytracing and surface cache. +
+
+ FSR 1.0: + FidelityFX FSR Upscaling version 1.0. Use this alongside Temporal AA or MSAA when the resolution scaling is lowered. +
+
+ FSR 2.1: + FidelityFX FSR Upscaling, version 2.1. You can use this as a replacement for Temporal AA while also upscaling from lowered rendering resolution. +
+
+ Toggle VXGI visualization. +
+ No debug + Clipmaps + Clipmap 0 + Clipmap 1 + Clipmap 2 + Clipmap 3 + Clipmap 4 + Clipmap 5
-
- DEBUG: - Toggle visualization of the screen space light culling heatmap grid (Tiled renderer only) -
-
- Thickness: - Set outline thickness. -
-
- Tessellation: - Enable tessellation feature. You also need to specify a tessellation factor for individual objects. -
-
- VSync: - Toggle vertical sync -
-
- Surfel GI: - Surfel GI is a raytraced diffuse GI using raytracing and surface cache. -
-
- FSR 1.0: - FidelityFX FSR Upscaling version 1.0. Use this alongside Temporal AA or MSAA when the resolution scaling is lowered. -
-
- FSR 2.1: - FidelityFX FSR Upscaling, version 2.1. You can use this as a replacement for Temporal AA while also upscaling from lowered rendering resolution. -
-
- Toggle VXGI visualization. -
- No debug - Clipmaps - Clipmap 0 - Clipmap 1 - Clipmap 2 - Clipmap 3 - Clipmap 4 - Clipmap 5 -
-
-
- SSR: - Enable Screen Space Reflections. This can not reflect anything that is outside of the screen. -
-
- VXGI Voxel Size: - Adjust the voxel size for VXGI calculations. -
-
- Brightness: -
-
- LensFlare: - Toggle visibility of light source flares. Additional setup needed per light for a lensflare to be visible. -
-
- Speed: - Adjust the global speed (time multiplier) -
-
- VXGI: - Toggle Voxel Global Illumination. -
-
- Samples: - Sample count of contact shadows. Higher values are better quality but slower. -
-
- Sharpen Filter: - Toggle sharpening post process of the final image. -
-
- RT Diffuse: - Enable Ray Traced Diffuse. Only if GPU supports raytracing. +
+
+ SSR: + Enable Screen Space Reflections. This can not reflect anything that is outside of the screen. +
+
+ VXGI Voxel Size: + Adjust the voxel size for VXGI calculations. +
+
+ Brightness: +
+
+ LensFlare: + Toggle visibility of light source flares. Additional setup needed per light for a lensflare to be visible. +
+
+ Speed: + Adjust the global speed (time multiplier) +
+
+ VXGI: + Toggle Voxel Global Illumination. +
+
+ Samples: + Sample count of contact shadows. Higher values are better quality but slower. +
+
+ Sharpen Filter: + Toggle sharpening post process of the final image. +
+
+ RT Diffuse: + Enable Ray Traced Diffuse. Only if GPU supports raytracing. This effect computes single bounce diffuse with ray tracing per pixel. If DDGI is enabled, it will make it multi bounce. -
-
- Range: - Range of contact shadows -
-
- Resolution Scale: - Adjust the internal rendering resolution. -
-
- DDGI Blend Speed: - Adjust the contribution of newly traced rays. Higher values will make the DDGI update faster, but can result in increased flickering. -
-
- Color Grading: - Enable color grading of the final render. An additional lookup texture must be set in the Weather! -
-
- VRS Classification: - Enable classification of variable rate shading on the screen. Less important parts will be shaded with lesser resolution. +
+
+ Range: + Range of contact shadows +
+
+ Resolution Scale: + Adjust the internal rendering resolution. +
+
+ DDGI Blend Speed: + Adjust the contribution of newly traced rays. Higher values will make the DDGI update faster, but can result in increased flickering. +
+
+ Color Grading: + Enable color grading of the final render. An additional lookup texture must be set in the Weather! +
+
+ VRS Classification: + Enable classification of variable rate shading on the screen. Less important parts will be shaded with lesser resolution. Requires Tier2 support for variable shading rate -
-
- Temporal AA: - Toggle Temporal Anti Aliasing. It is a supersampling techique which is performed across multiple frames. -
-
- MSAA: - Multisampling Anti Aliasing quality. -
- Off - 2 - 4 - 8 -
-
-
- FXAA: - Fast Approximate Anti Aliasing. A fast antialiasing method, but can be a bit too blurry. -
-
- LightShafts: - Enable light shaft for directional light sources. -
-
- Chromatic Aberration: - Toggle the full screen chromatic aberration effect. This simulates lens distortion at screen edges. -
-
- Probe count in Y dimension. -
-
- Bloom: - Enable bloom. The effect adds color bleeding to the brightest parts of the scene. -
-
- VXGI Full Resolution: - Toggle resolve mode for VXGI opaque. Full resolution will use the full rendering resolution, otherwise it will be upsampled from lower resolution. -
-
- Contrast: -
-
- Saturation: -
-
- Texture Quality: - Choose a texture sampling method for material textures. -
- Nearest - Bilinear - Trilinear - Anisotropic -
-
-
- Screen Shadows: - Enable screen space contact shadows. This can add small shadows details to shadow maps in screen space. -
-
- Probe count in Z dimension. -
-
- Tonemap Exposure: - Set the tonemap exposure value -
-
- Sharpness: - The sharpening amount to apply for FSR 2.1 upscaling. -
-
- Occlusion Culling: - Toggle occlusion culling. This can boost framerate if many objects are occluded in the scene. -
-
- MipLOD Bias: - Bias the rendered mip map level of the material textures. -
-
- MotionBlur: - Enable motion blur for camera movement and animated meshes. -
-
- DDGI: - Toggle Dynamic Diffuse Global Illumination (DDGI). -Note that DDGI probes that were loaded with the scene will still be active if this is turned off, but they won't be updated. +
+
+ Temporal AA: + Toggle Temporal Anti Aliasing. It is a supersampling techique which is performed across multiple frames. +
+
+ MSAA: + Multisampling Anti Aliasing quality. +
+ Off + 2 + 4 + 8
-
- Általános -
- AABB visualizer: - Visualize the scene bounding boxes +
+ FXAA: + Fast Approximate Anti Aliasing. A fast antialiasing method, but can be a bit too blurry. +
+
+ LightShafts: + Enable light shaft for directional light sources. +
+
+ Chromatic Aberration: + Toggle the full screen chromatic aberration effect. This simulates lens distortion at screen edges. +
+
+ Probe count in Y dimension. +
+
+ Bloom: + Enable bloom. The effect adds color bleeding to the brightest parts of the scene. +
+
+ VXGI Full Resolution: + Toggle resolve mode for VXGI opaque. Full resolution will use the full rendering resolution, otherwise it will be upsampled from lower resolution. +
+
+ Contrast: +
+
+ Saturation: +
+
+ Texture Quality: + Choose a texture sampling method for material textures. +
+ Nearest + Bilinear + Trilinear + Anisotropic
-
-  Lokalizációs Minta Készítése - Készíts egy lokalizációs fájlt amivel más nyelvre lehet fordítani a programot, a jelenleg kiválasztott nyelv alapján. +
+
+ Screen Shadows: + Enable screen space contact shadows. This can add small shadows details to shadow maps in screen space. +
+
+ Probe count in Z dimension. +
+
+ Tonemap Exposure: + Set the tonemap exposure value +
+
+ Sharpness: + The sharpening amount to apply for FSR 2.1 upscaling. +
+
+ Occlusion Culling: + Toggle occlusion culling. This can boost framerate if many objects are occluded in the scene. +
+
+ MipLOD Bias: + Bias the rendered mip map level of the material textures. +
+
+ MotionBlur: + Enable motion blur for camera movement and animated meshes. +
+
+ DDGI: + Toggle Dynamic Diffuse Global Illumination (DDGI). +Note that DDGI probes that were loaded with the scene will still be active if this is turned off, but they won't be updated. +
+
+
+ Általános +
+ AABB visualizer: + Visualize the scene bounding boxes +
+
+  Lokalizációs Minta Készítése + Készíts egy lokalizációs fájlt amivel más nyelvre lehet fordítani a programot, a jelenleg kiválasztott nyelv alapján. +
+
+ Név vizualizáció: + Visualize the entity names in the scene +
+
+ Csont átlátszóság: + You can control the transparency of the bone selector tool +
+
+ Környezeti szonda vizualizáció: + Toggle visualization of environment probes as reflective spheres +
+
+ Téma: + Choose a color theme... +
+ Sötét  + Világos  + Kellemes  + Hacklés  + Nord 
-
- Név vizualizáció: - Visualize the entity names in the scene -
-
- Csont átlátszóság: - You can control the transparency of the bone selector tool -
-
- Környezeti szonda vizualizáció: - Toggle visualization of environment probes as reflective spheres -
-
- Téma: - Choose a color theme... -
- Sötét  - Világos  - Kellemes  - Hacklés  - Nord  -
-
-
- Infó: - Toggle advanced data in the info display text in top left corner. -
-
- Erőtér vizualizáció: - Visualize force fields -
-
- Nyelv: - Nyelv választás. +
+
+ Infó: + Toggle advanced data in the info display text in top left corner. +
+
+ Erőtér vizualizáció: + Visualize force fields +
+
+ Nyelv: + Nyelv választás. Új nyelv hozzáadásához készíts egy XML fájlt a languages mappába. Alább van egy gomb amivel nyelvi mintát készíthetsz. -
-
- Freeze culling camera: - Freeze culling camera update. Scene culling will not be updated with the view -
-
- Vonal rajzolás: - Visualize the scene as a wireframe -
-
- FPS: - Toggle the FPS display text in top left corner. -
-
- Disable albedo maps: - Disables albedo maps on objects for easier lighting debugging -
-
- Mentési mód: - Choose whether to embed resources (textures, sounds...) in the scene file when saving, or keep them as separate files. +
+
+ Freeze culling camera: + Freeze culling camera update. Scene culling will not be updated with the view +
+
+ Vonal rajzolás: + Visualize the scene as a wireframe +
+
+ FPS: + Toggle the FPS display text in top left corner. +
+
+ Disable albedo maps: + Disables albedo maps on objects for easier lighting debugging +
+
+ Mentési mód: + Choose whether to embed resources (textures, sounds...) in the scene file when saving, or keep them as separate files. The Dump to header () option will use embedding and create a C++ header file with byte data of the scene to be used with wi::Archive serialization. -
- Embed resources  - No embedding  - Dump to header  -
-
-
- Force diffuse lighting: - Sets every surface fully diffuse, with zero specularity -
-
- Grid helper: - Toggle showing of unit visualizer grid in the world origin -
-
- Ütköző vizualizáció: - Toggle visualization of colliders in the scene -
-
- Mozgató átlátszóság: - You can control the transparency of the object placement tool -
-
- Verzió: - Toggle the engine version display text in top left corner. -
-
- Fizika vizualizáció: - Visualize the physics world -
-
- Csont vizualizáció: - Visualize bones of armatures -
-
- Emitter vizualizáció: - Visualize emitters -
-
- Fizika: - Toggle Physics Simulation On/Off -
-
- Kamera vizualizáció: - Toggle visualization of camera proxies in the scene -
-
- RT BVH vizualizáció: - Visualize scene BVH if raytracing is enabled (only for software raytracing currently) -
-
-
- Toggle case-sensitive name filtering -
-
- Új: - Create new entity
- Transzformáció  - Anyag  - Pontfény  - Spotfény  - Irányfény  - Környezeti szonda  - Erőtér  - Matrica  - Hang  - Videó  - Időjárás  - Emitter  - Haj Részecske  - Kamera  - Kocka  - Sík  - Animáció  - Szkript  - Ütköző  - Terep  + Embed resources  + No embedding  + Dump to header 
-
- Anyagok -
- Zoom: +
+ Force diffuse lighting: + Sets every surface fully diffuse, with zero specularity +
+
+ Grid helper: + Toggle showing of unit visualizer grid in the world origin +
+
+ Ütköző vizualizáció: + Toggle visualization of colliders in the scene +
+
+ Mozgató átlátszóság: + You can control the transparency of the object placement tool +
+
+ Verzió: + Toggle the engine version display text in top left corner. +
+
+ Fizika vizualizáció: + Visualize the physics world +
+
+ Csont vizualizáció: + Visualize bones of armatures +
+
+ Emitter vizualizáció: + Visualize emitters +
+
+ Fizika: + Toggle Physics Simulation On/Off +
+
+ Kamera vizualizáció: + Toggle visualization of camera proxies in the scene +
+
+ RT BVH vizualizáció: + Visualize scene BVH if raytracing is enabled (only for software raytracing currently) +
+
+
+ Toggle case-sensitive name filtering +
+
+ Új: + Create new entity +
+ Transzformáció  + Anyag  + Pontfény  + Spotfény  + Irányfény  + Környezeti szonda  + Erőtér  + Matrica  + Hang  + Videó  + Időjárás  + Emitter  + Haj Részecske  + Kamera  + Kocka  + Sík  + Animáció  + Szkript  + Ütköző  + Terep  +
+
+
+ Anyagok +
+ Zoom: +
+
+
+ Festő Ecset +
+ Smoothness: + Set the brush smoothness. 0 = hard, increase for more smoothness +
+
+ Spacing: + Brush spacing means how much brush movement (in pixels) starts a new stroke. 0 = new stroke every frame, 100 = every 100 pixel movement since last stroke will start a new stroke. +
+
+ Backfaces: + Set whether to paint on backfaces of geometry or not +
+
+ Paint Tool is disabled. +
+
+ Save Texture + Save edited texture. +
+
+ Power: + Set the brush power amount. 0 = minimum affection, 1 = maximum affection +
+
+ Brush Shape: + Choose shape for brush masking effect +
+ +
-
- Festő Ecset -
- Smoothness: - Set the brush smoothness. 0 = hard, increase for more smoothness +
+ Brush Radius: + Set the brush radius in pixel units +
+
+ Stabilizer: + The stabilizer generates a small delay between user input and painting, which will be used to compute a smoother paint stroke.. +
+
+ Color +
+ Enter value for BLUE channel (0-255)
-
- Spacing: - Brush spacing means how much brush movement (in pixels) starts a new stroke. 0 = new stroke every frame, 100 = every 100 pixel movement since last stroke will start a new stroke. +
+ Enter value for SATURATION channel (0-100)
-
- Backfaces: - Set whether to paint on backfaces of geometry or not +
+ Enter value for RED channel (0-255)
-
- Paint Tool is disabled. +
+ Enter value for GREEN channel (0-255)
-
- Save Texture - Save edited texture. +
+ Value for ALPHA - TRANSPARENCY channel (0-255)
-
- Power: - Set the brush power amount. 0 = minimum affection, 1 = maximum affection +
+ Enter value for LUMINANCE channel (0-100)
-
- Brush Shape: - Choose shape for brush masking effect -
- - -
+
+ Enter value for HUE channel (0-360)
-
- Brush Radius: - Set the brush radius in pixel units +
+
+ Axis Lock: + You can lock modification to an axis here. +
+ + X  + Y  + Z 
-
- Stabilizer: - The stabilizer generates a small delay between user input and painting, which will be used to compute a smoother paint stroke.. +
+
+ Pressure: + Set whether to use pressure sensitivity (for example pen tablet) +
+
+ Mode: + Choose paint tool mode +
+  Disabled +  Texture +  Vertexcolor +  Sculpting - Add +  Sculpting - Subtract +  Softbody - Pinning +  Softbody - Physics +  Hairparticle - Add Triangle +  Hairparticle - Remove Triangle +  Hairparticle - Length (Alpha) +  Wind weight (Alpha)
-
- Color -
- Enter value for BLUE channel (0-255) -
-
- Enter value for SATURATION channel (0-100) -
-
- Enter value for RED channel (0-255) -
-
- Enter value for GREEN channel (0-255) -
-
- Value for ALPHA - TRANSPARENCY channel (0-255) -
-
- Enter value for LUMINANCE channel (0-100) -
-
- Enter value for HUE channel (0-360) -
-
-
- Axis Lock: - You can lock modification to an axis here. -
- - X  - Y  - Z  -
-
-
- Pressure: - Set whether to use pressure sensitivity (for example pen tablet) -
-
- Mode: - Choose paint tool mode -
-  Disabled -  Texture -  Vertexcolor -  Sculpting - Add -  Sculpting - Subtract -  Softbody - Pinning -  Softbody - Physics -  Hairparticle - Add Triangle -  Hairparticle - Remove Triangle -  Hairparticle - Length (Alpha) -  Wind weight (Alpha) -
-
-
- Wireframe: - Set whether to draw wireframe on top of geometry or not -
-
- Rotation: - Brush rotation randomness. This will affect the splat mode brush texture. -
-
- Open an image to use as reveal mode texture. +
+
+ Wireframe: + Set whether to draw wireframe on top of geometry or not +
+
+ Rotation: + Brush rotation randomness. This will affect the splat mode brush texture. +
+
+ Open an image to use as reveal mode texture. Reveal mode means that the texture will use the UV of the mesh. It will be multiplied by brush tex. -
-
- Texture Slot: - Choose texture slot of the selected material to paint (texture paint mode only) -
- BaseColor (RGBA) - Normal (RGB) - SurfaceMap (RGBA) - DisplacementMap (R) - EmissiveMap (RGBA) - OcclusionMap (R) - TransmissionMap (R) - SheenColorMap (R) - SheenRoughMap (R) - ClearcoatMap (R) - ClearcoatRoughMap (R) - ClearcoatNormMap (R) -
-
-
- Open an image to use as brush texture (splatting mode). -Splat mode means that the texture will be relative to the brush position -
-
- Entitások szűrése típus alapján +
+ Texture Slot: + Choose texture slot of the selected material to paint (texture paint mode only)
- * - - - - - - - - - - - - - - - - - - - - - - + BaseColor (RGBA) + Normal (RGB) + SurfaceMap (RGBA) + DisplacementMap (R) + EmissiveMap (RGBA) + OcclusionMap (R) + TransmissionMap (R) + SheenColorMap (R) + SheenRoughMap (R) + ClearcoatMap (R) + ClearcoatRoughMap (R) + ClearcoatNormMap (R)
-
- Entitások +
+ Open an image to use as brush texture (splatting mode). +Splat mode means that the texture will be relative to the brush position
-
- Entitások szűrése név alapján +
+
+ Entitások szűrése típus alapján +
+ * + + + + + + + + + + + + + + + + + + + + + +
-
- Kamera -
- Movement Speed: -
-
- Far Plane: - Controls the camera's far clip plane, geometry farther than this will be clipped. -
-
- Aperture Shape Y: - Controls the depth of field effect's bokeh shape -
-
- Aperture Size: - Controls the depth of field effect's strength -
-
- Aperture Shape X: - Controls the depth of field effect's bokeh shape -
-
- Follow Proxy Delay: -
-
- Focal Length: - Controls the depth of field effect's focus distance -
-
- Place Proxy - Copy the current camera and place a proxy of it in the world. -
-
- FOV: - Controls the camera's top-down field of view (in degrees) -
-
- Near Plane: - Controls the camera's near clip plane, geometry closer than this will be clipped. -
-
- Follow Proxy: -
-
- Reset Camera -
-
- Acceleration: -
-
- Rotation Speed: -
-
- FPS Camera: -
+
+
+ Entitások +
+
+ Entitások szűrése név alapján +
+
+ Kamera +
+ Movement Speed: +
+
+ Far Plane: + Controls the camera's far clip plane, geometry farther than this will be clipped. +
+
+ Aperture Shape Y: + Controls the depth of field effect's bokeh shape +
+
+ Aperture Size: + Controls the depth of field effect's strength +
+
+ Aperture Shape X: + Controls the depth of field effect's bokeh shape +
+
+ Follow Proxy Delay: +
+
+ Focal Length: + Controls the depth of field effect's focus distance +
+
+ Place Proxy + Copy the current camera and place a proxy of it in the world. +
+
+ FOV: + Controls the camera's top-down field of view (in degrees) +
+
+ Near Plane: + Controls the camera's near clip plane, geometry closer than this will be clipped. +
+
+ Follow Proxy: +
+
+ Reset Camera +
+
+ Acceleration: +
+
+ Rotation Speed: +
+
+ FPS Camera:
diff --git a/Editor/languages/日本語.xml b/Editor/languages/日本語.xml index 76c8dbb7c..fd89c50aa 100644 --- a/Editor/languages/日本語.xml +++ b/Editor/languages/日本語.xml @@ -12,6 +12,7 @@ 情報 出口 無題のシーン +コンテント
新しいシーン @@ -22,770 +23,767 @@
まだ実行中のすべてのスクリプトバックグラウンドプロセスを停止します。
-
- オプション -
- グラフィックス -
- Cube Shadowmap res: - Choose a shadow quality preset for cube shadow maps (pointlights, area lights)... +
+ グラフィックス +
+ Cube Shadowmap res: + Choose a shadow quality preset for cube shadow maps (pointlights, area lights)... This specifies the maximum shadow resolution for these light types, but that can dynamically change unless they are set to a fixed resolution individually. -
- Off - 128 - 256 - 512 - 1024 - 2048 -
+
+ Off + 128 + 256 + 512 + 1024 + 2048
-
- Path tracing statistics -
-
- EyeAdaption: - Enable eye adaption for the overall screen luminance -
-
- Shadow type: - Choose between shadowmaps and ray traced shadows. +
+
+ Path tracing statistics +
+
+ EyeAdaption: + Enable eye adaption for the overall screen luminance +
+
+ Shadow type: + Choose between shadowmaps and ray traced shadows. Note that ray traced shadows need hardware raytracing support, otherwise they are not available -
- Shadowmaps - Ray traced -
+
+ Shadowmaps + Ray traced
-
- Display Output: - Choose between different display output formats. +
+
+ Display Output: + Choose between different display output formats. If the display doesn't support the selected format, it will switch back to a reasonable default. HDR formats will be only selectable when the current display supports HDR output -
- SDR 8bit - SDR 10bit -
+
+ SDR 8bit + SDR 10bit
-
- VXGI Reflections: - Toggle specular reflections computation for VXGI. +
+
+ VXGI Reflections: + Toggle specular reflections computation for VXGI. +
+
+ Choose Surfel GI debug visualization. +
+ No Debug + Normal + Color + Point + Random + Heatmap + Inconsist.
-
- Choose Surfel GI debug visualization. -
- No Debug - Normal - Color - Point - Random - Heatmap - Inconsist. -
-
-
- Key: - Set the key value for eye adaption. -
-
- Sample count: - The path tracing will perform this many samples per pixel. -
-
- Strength: - The lens distortion amount. -
-
- VXGI Distance: - Adjust max raymarching distance for VXGI. -
-
- Probe count in X dimension. -
-
- Rate: - Set the eye adaption rate (speed of adjustment) -
-
- Sample Count: - Set AO ray count. Only for SSAO -
-
- Cartoon Outline: - Toggle the cartoon outline effect. Only those materials will be outlined that have Cartoon Outline enabled. -
-
- Cutoff: - Set maximum roughness which can be used to apply screen space or raytraced reflections. -
-
- Transparent Shadows: - Enables color tinted shadows and refraction caustics effects for transparent objects and water. -
-
- DDGI RayCount: - Adjust the ray count per DDGI probe. -
-
- 2.5D Light Culling: - Enable a more aggressive light culling approach which can result in slower culling but faster rendering (Tiled renderer only) -
-
- 2D Shadowmap res: - Choose a shadow quality preset for 2D shadow maps (spotlights, directional lights)... +
+
+ Key: + Set the key value for eye adaption. +
+
+ Sample count: + The path tracing will perform this many samples per pixel. +
+
+ Strength: + The lens distortion amount. +
+
+ VXGI Distance: + Adjust max raymarching distance for VXGI. +
+
+ Probe count in X dimension. +
+
+ Rate: + Set the eye adaption rate (speed of adjustment) +
+
+ Sample Count: + Set AO ray count. Only for SSAO +
+
+ Cartoon Outline: + Toggle the cartoon outline effect. Only those materials will be outlined that have Cartoon Outline enabled. +
+
+ Cutoff: + Set maximum roughness which can be used to apply screen space or raytraced reflections. +
+
+ Transparent Shadows: + Enables color tinted shadows and refraction caustics effects for transparent objects and water. +
+
+ DDGI RayCount: + Adjust the ray count per DDGI probe. +
+
+ 2.5D Light Culling: + Enable a more aggressive light culling approach which can result in slower culling but faster rendering (Tiled renderer only) +
+
+ 2D Shadowmap res: + Choose a shadow quality preset for 2D shadow maps (spotlights, directional lights)... This specifies the maximum shadow resolution for these light types, but that can dynamically change unless they are set to a fixed resolution individually. -
- Off - 128 - 256 - 512 - 1024 - 2048 - 4096 -
+
+ Off + 128 + 256 + 512 + 1024 + 2048 + 4096
-
- DDGI Smoothen: - Adjust the amount of smooth backface test. +
+
+ DDGI Smoothen: + Adjust the amount of smooth backface test. +
+
+ RT Reflections: + Enable Ray Traced Reflections. Only if GPU supports raytracing. +
+
+ AO: + Choose Ambient Occlusion type. RTAO is only available if hardware supports ray tracing +
+ Disabled + SSAO + HBAO + MSAO + RTAO
-
- RT Reflections: - Enable Ray Traced Reflections. Only if GPU supports raytracing. -
-
- AO: - Choose Ambient Occlusion type. RTAO is only available if hardware supports ray tracing -
- Disabled - SSAO - HBAO - MSAO - RTAO -
-
-
- Power: - Set SSAO Power. Higher values produce darker, more pronounced effect -
-
- Visibility Compute Shading: - Visibility Compute Shading (experimental) +
+
+ Power: + Set SSAO Power. Higher values produce darker, more pronounced effect +
+
+ Visibility Compute Shading: + Visibility Compute Shading (experimental) This will shade the scene in compute shaders instead of pixel shaders This has a higher initial performance cost, but it will be faster in high polygon scenes. It is not compatible with MSAA and tessellation. -
-
- Render Path: - Choose a render path... +
+
+ Render Path: + Choose a render path... Path tracing will use fallback raytracing with non-raytracing GPU, which will be slow. Changing render path will reset some graphics settings! -
- Default - Path Tracing -
+
+ Default + Path Tracing
-
- Raytrace Bounces: - How many light bounces to compute when doing these ray tracing effects: +
+
+ Raytrace Bounces: + How many light bounces to compute when doing these ray tracing effects: - Path tracing - Lightmap baking -
-
- DEBUG: - Disable blending of frame history. Camera Subpixel jitter will be visible. -
-
- Threshold: - Outline edge detection threshold. Increase if not enough otlines are detected, decrease if too many outlines are detected. -
-
- FSR 2.1 Preset: - Set resolution scaling quality mode for FSR 2.1: +
+
+ DEBUG: + Disable blending of frame history. Camera Subpixel jitter will be visible. +
+
+ Threshold: + Outline edge detection threshold. Increase if not enough otlines are detected, decrease if too many outlines are detected. +
+
+ FSR 2.1 Preset: + Set resolution scaling quality mode for FSR 2.1: Quality: 1.5x Balanced: 1.7x Performance: 2.0x Ultra performance: 3.0x -
- Quality - Balanced - Performance - Ultra performance -
+
+ Quality + Balanced + Performance + Ultra performance
-
- DepthOfField: - Enable Depth of field effect. Requires additional camera setup: focal length and aperture size. -
-
- Dithering: - Toggle the full screen dithering effect. This helps to reduce color banding. -
-
- VXGI Ray Step: - Adjust the precision of ray marching for [reflection] cone tracing step. Lower values = more precision but slower performance. -
-
- GI Boost: - Adjust the strength of GI. +
+
+ DepthOfField: + Enable Depth of field effect. Requires additional camera setup: focal length and aperture size. +
+
+ Dithering: + Toggle the full screen dithering effect. This helps to reduce color banding. +
+
+ VXGI Ray Step: + Adjust the precision of ray marching for [reflection] cone tracing step. Lower values = more precision but slower performance. +
+
+ GI Boost: + Adjust the strength of GI. Note that values other than 1.0 will cause mismatch with path tracing reference! +
+
+ DEBUG: + Toggle visualization of the screen space light culling heatmap grid (Tiled renderer only) +
+
+ Thickness: + Set outline thickness. +
+
+ Tessellation: + Enable tessellation feature. You also need to specify a tessellation factor for individual objects. +
+
+ VSync: + Toggle vertical sync +
+
+ Surfel GI: + Surfel GI is a raytraced diffuse GI using raytracing and surface cache. +
+
+ FSR 1.0: + FidelityFX FSR Upscaling version 1.0. Use this alongside Temporal AA or MSAA when the resolution scaling is lowered. +
+
+ FSR 2.1: + FidelityFX FSR Upscaling, version 2.1. You can use this as a replacement for Temporal AA while also upscaling from lowered rendering resolution. +
+
+ Toggle VXGI visualization. +
+ No debug + Clipmaps + Clipmap 0 + Clipmap 1 + Clipmap 2 + Clipmap 3 + Clipmap 4 + Clipmap 5
-
- DEBUG: - Toggle visualization of the screen space light culling heatmap grid (Tiled renderer only) -
-
- Thickness: - Set outline thickness. -
-
- Tessellation: - Enable tessellation feature. You also need to specify a tessellation factor for individual objects. -
-
- VSync: - Toggle vertical sync -
-
- Surfel GI: - Surfel GI is a raytraced diffuse GI using raytracing and surface cache. -
-
- FSR 1.0: - FidelityFX FSR Upscaling version 1.0. Use this alongside Temporal AA or MSAA when the resolution scaling is lowered. -
-
- FSR 2.1: - FidelityFX FSR Upscaling, version 2.1. You can use this as a replacement for Temporal AA while also upscaling from lowered rendering resolution. -
-
- Toggle VXGI visualization. -
- No debug - Clipmaps - Clipmap 0 - Clipmap 1 - Clipmap 2 - Clipmap 3 - Clipmap 4 - Clipmap 5 -
-
-
- SSR: - Enable Screen Space Reflections. This can not reflect anything that is outside of the screen. -
-
- VXGI Voxel Size: - Adjust the voxel size for VXGI calculations. -
-
- Brightness: -
-
- LensFlare: - Toggle visibility of light source flares. Additional setup needed per light for a lensflare to be visible. -
-
- Speed: - Adjust the global speed (time multiplier) -
-
- VXGI: - Toggle Voxel Global Illumination. -
-
- Samples: - Sample count of contact shadows. Higher values are better quality but slower. -
-
- Sharpen Filter: - Toggle sharpening post process of the final image. -
-
- RT Diffuse: - Enable Ray Traced Diffuse. Only if GPU supports raytracing. +
+
+ SSR: + Enable Screen Space Reflections. This can not reflect anything that is outside of the screen. +
+
+ VXGI Voxel Size: + Adjust the voxel size for VXGI calculations. +
+
+ Brightness: +
+
+ LensFlare: + Toggle visibility of light source flares. Additional setup needed per light for a lensflare to be visible. +
+
+ Speed: + Adjust the global speed (time multiplier) +
+
+ VXGI: + Toggle Voxel Global Illumination. +
+
+ Samples: + Sample count of contact shadows. Higher values are better quality but slower. +
+
+ Sharpen Filter: + Toggle sharpening post process of the final image. +
+
+ RT Diffuse: + Enable Ray Traced Diffuse. Only if GPU supports raytracing. This effect computes single bounce diffuse with ray tracing per pixel. If DDGI is enabled, it will make it multi bounce. -
-
- Range: - Range of contact shadows -
-
- Resolution Scale: - Adjust the internal rendering resolution. -
-
- DDGI Blend Speed: - Adjust the contribution of newly traced rays. Higher values will make the DDGI update faster, but can result in increased flickering. -
-
- Color Grading: - Enable color grading of the final render. An additional lookup texture must be set in the Weather! -
-
- VRS Classification: - Enable classification of variable rate shading on the screen. Less important parts will be shaded with lesser resolution. +
+
+ Range: + Range of contact shadows +
+
+ Resolution Scale: + Adjust the internal rendering resolution. +
+
+ DDGI Blend Speed: + Adjust the contribution of newly traced rays. Higher values will make the DDGI update faster, but can result in increased flickering. +
+
+ Color Grading: + Enable color grading of the final render. An additional lookup texture must be set in the Weather! +
+
+ VRS Classification: + Enable classification of variable rate shading on the screen. Less important parts will be shaded with lesser resolution. Requires Tier2 support for variable shading rate -
-
- Temporal AA: - Toggle Temporal Anti Aliasing. It is a supersampling techique which is performed across multiple frames. -
-
- MSAA: - Multisampling Anti Aliasing quality. -
- Off - 2 - 4 - 8 -
-
-
- FXAA: - Fast Approximate Anti Aliasing. A fast antialiasing method, but can be a bit too blurry. -
-
- LightShafts: - Enable light shaft for directional light sources. -
-
- Chromatic Aberration: - Toggle the full screen chromatic aberration effect. This simulates lens distortion at screen edges. -
-
- Probe count in Y dimension. -
-
- Bloom: - Enable bloom. The effect adds color bleeding to the brightest parts of the scene. -
-
- VXGI Full Resolution: - Toggle resolve mode for VXGI opaque. Full resolution will use the full rendering resolution, otherwise it will be upsampled from lower resolution. -
-
- Contrast: -
-
- Saturation: -
-
- Texture Quality: - Choose a texture sampling method for material textures. -
- Nearest - Bilinear - Trilinear - Anisotropic -
-
-
- Screen Shadows: - Enable screen space contact shadows. This can add small shadows details to shadow maps in screen space. -
-
- Probe count in Z dimension. -
-
- Tonemap Exposure: - Set the tonemap exposure value -
-
- Sharpness: - The sharpening amount to apply for FSR 2.1 upscaling. -
-
- Occlusion Culling: - Toggle occlusion culling. This can boost framerate if many objects are occluded in the scene. -
-
- MipLOD Bias: - Bias the rendered mip map level of the material textures. -
-
- MotionBlur: - Enable motion blur for camera movement and animated meshes. -
-
- DDGI: - Toggle Dynamic Diffuse Global Illumination (DDGI). -Note that DDGI probes that were loaded with the scene will still be active if this is turned off, but they won't be updated. +
+
+ Temporal AA: + Toggle Temporal Anti Aliasing. It is a supersampling techique which is performed across multiple frames. +
+
+ MSAA: + Multisampling Anti Aliasing quality. +
+ Off + 2 + 4 + 8
-
- 一般設定 -
- AABB visualizer: - Visualize the scene bounding boxes +
+ FXAA: + Fast Approximate Anti Aliasing. A fast antialiasing method, but can be a bit too blurry. +
+
+ LightShafts: + Enable light shaft for directional light sources. +
+
+ Chromatic Aberration: + Toggle the full screen chromatic aberration effect. This simulates lens distortion at screen edges. +
+
+ Probe count in Y dimension. +
+
+ Bloom: + Enable bloom. The effect adds color bleeding to the brightest parts of the scene. +
+
+ VXGI Full Resolution: + Toggle resolve mode for VXGI opaque. Full resolution will use the full rendering resolution, otherwise it will be upsampled from lower resolution. +
+
+ Contrast: +
+
+ Saturation: +
+
+ Texture Quality: + Choose a texture sampling method for material textures. +
+ Nearest + Bilinear + Trilinear + Anisotropic
-
-  ローカリゼーションテンプレートの作成 - エディターのローカリゼーションの編集に使用できるファイルを生成する. +
+
+ Screen Shadows: + Enable screen space contact shadows. This can add small shadows details to shadow maps in screen space. +
+
+ Probe count in Z dimension. +
+
+ Tonemap Exposure: + Set the tonemap exposure value +
+
+ Sharpness: + The sharpening amount to apply for FSR 2.1 upscaling. +
+
+ Occlusion Culling: + Toggle occlusion culling. This can boost framerate if many objects are occluded in the scene. +
+
+ MipLOD Bias: + Bias the rendered mip map level of the material textures. +
+
+ MotionBlur: + Enable motion blur for camera movement and animated meshes. +
+
+ DDGI: + Toggle Dynamic Diffuse Global Illumination (DDGI). +Note that DDGI probes that were loaded with the scene will still be active if this is turned off, but they won't be updated. +
+
+
+ 一般設定 +
+ AABB visualizer: + Visualize the scene bounding boxes +
+
+  ローカリゼーションテンプレートの作成 + エディターのローカリゼーションの編集に使用できるファイルを生成する. テンプレートは現在選択されている言語から作成されます. +
+
+ Name visualizer: + Visualize the entity names in the scene +
+
+ Bone Picker Opacity: + You can control the transparency of the bone selector tool +
+
+ Env probe visualizer: + Toggle visualization of environment probes as reflective spheres +
+
+ テーマ: + 配色テーマを選択する... +
+ 暗い  + 明るい  + 柔らかい  + ハッキング  + Nord 
-
- Name visualizer: - Visualize the entity names in the scene -
-
- Bone Picker Opacity: - You can control the transparency of the bone selector tool -
-
- Env probe visualizer: - Toggle visualization of environment probes as reflective spheres -
-
- テーマ: - 配色テーマを選択する... -
- 暗い  - 明るい  - 柔らかい  - ハッキング  - Nord  -
-
-
- 情報: - Toggle advanced data in the info display text in top left corner. -
-
- Force Field visualizer: - Visualize force fields -
-
- 言語: - 言語を選択. +
+
+ 情報: + Toggle advanced data in the info display text in top left corner. +
+
+ Force Field visualizer: + Visualize force fields +
+
+ 言語: + 言語を選択. XML ファイルを言語フォルダーに追加して、新しい言語オプションを作成することもできます。. 言語テンプレートを作成するために使用できるボタンが下にあります. -
-
- Freeze culling camera: - Freeze culling camera update. Scene culling will not be updated with the view -
-
- Render Wireframe: - Visualize the scene as a wireframe -
-
- FPS: - Toggle the FPS display text in top left corner. -
-
- Disable albedo maps: - Disables albedo maps on objects for easier lighting debugging -
-
- セーブモード: - Choose whether to embed resources (textures, sounds...) in the scene file when saving, or keep them as separate files. +
+
+ Freeze culling camera: + Freeze culling camera update. Scene culling will not be updated with the view +
+
+ Render Wireframe: + Visualize the scene as a wireframe +
+
+ FPS: + Toggle the FPS display text in top left corner. +
+
+ Disable albedo maps: + Disables albedo maps on objects for easier lighting debugging +
+
+ セーブモード: + Choose whether to embed resources (textures, sounds...) in the scene file when saving, or keep them as separate files. The Dump to header () option will use embedding and create a C++ header file with byte data of the scene to be used with wi::Archive serialization. -
- Embed resources  - No embedding  - Dump to header  -
-
-
- Force diffuse lighting: - Sets every surface fully diffuse, with zero specularity -
-
- Grid helper: - Toggle showing of unit visualizer grid in the world origin -
-
- Collider visualizer: - Toggle visualization of colliders in the scene -
-
- Transform Tool Opacity: - You can control the transparency of the object placement tool -
-
- バージョン: - Toggle the engine version display text in top left corner. -
-
- Physics visualizer: - Visualize the physics world -
-
- Bone line visualizer: - Visualize bones of armatures -
-
- Emitter visualizer: - Visualize emitters -
-
- Physics: - Toggle Physics Simulation On/Off -
-
- Camera visualizer: - Toggle visualization of camera proxies in the scene -
-
- RT BVH visualizer: - Visualize scene BVH if raytracing is enabled (only for software raytracing currently) -
-
-
- 大文字と小文字を区別する名前のフィルター処理を切り替える -
-
- 足す: - 新しいエンティティの作成
- トランスフォーム  - マテリアル  - ポイントライト  - スポットライト  - 指向性ライト  - 環境プローブ  - フォース  - デカル  - 音  - ビデオ  - 天気  - エミッター  - ヘアパーティクル  - カメラ  - 三乗  - プレーぬ  - アニメーション  - スクリプト  - コライダー  - 地形  + Embed resources  + No embedding  + Dump to header 
-
- -
- Zoom: +
+ Force diffuse lighting: + Sets every surface fully diffuse, with zero specularity +
+
+ Grid helper: + Toggle showing of unit visualizer grid in the world origin +
+
+ Collider visualizer: + Toggle visualization of colliders in the scene +
+
+ Transform Tool Opacity: + You can control the transparency of the object placement tool +
+
+ バージョン: + Toggle the engine version display text in top left corner. +
+
+ Physics visualizer: + Visualize the physics world +
+
+ Bone line visualizer: + Visualize bones of armatures +
+
+ Emitter visualizer: + Visualize emitters +
+
+ Physics: + Toggle Physics Simulation On/Off +
+
+ Camera visualizer: + Toggle visualization of camera proxies in the scene +
+
+ RT BVH visualizer: + Visualize scene BVH if raytracing is enabled (only for software raytracing currently) +
+
+
+ 大文字と小文字を区別する名前のフィルター処理を切り替える +
+
+ 足す: + 新しいエンティティの作成 +
+ トランスフォーム  + マテリアル  + ポイントライト  + スポットライト  + 指向性ライト  + 環境プローブ  + フォース  + デカル  + 音  + ビデオ  + 天気  + エミッター  + ヘアパーティクル  + カメラ  + 三乗  + プレーぬ  + アニメーション  + スクリプト  + コライダー  + 地形  +
+
+
+ +
+ Zoom: +
+
+
+ ペイントツール +
+ Smoothness: + Set the brush smoothness. 0 = hard, increase for more smoothness +
+
+ Spacing: + Brush spacing means how much brush movement (in pixels) starts a new stroke. 0 = new stroke every frame, 100 = every 100 pixel movement since last stroke will start a new stroke. +
+
+ Backfaces: + Set whether to paint on backfaces of geometry or not +
+
+ Paint Tool is disabled. +
+
+ Save Texture + Save edited texture. +
+
+ Power: + Set the brush power amount. 0 = minimum affection, 1 = maximum affection +
+
+ Brush Shape: + Choose shape for brush masking effect +
+ +
-
- ペイントツール -
- Smoothness: - Set the brush smoothness. 0 = hard, increase for more smoothness +
+ Brush Radius: + Set the brush radius in pixel units +
+
+ Stabilizer: + The stabilizer generates a small delay between user input and painting, which will be used to compute a smoother paint stroke.. +
+
+ Color +
+ Enter value for BLUE channel (0-255)
-
- Spacing: - Brush spacing means how much brush movement (in pixels) starts a new stroke. 0 = new stroke every frame, 100 = every 100 pixel movement since last stroke will start a new stroke. +
+ Enter value for SATURATION channel (0-100)
-
- Backfaces: - Set whether to paint on backfaces of geometry or not +
+ Enter value for RED channel (0-255)
-
- Paint Tool is disabled. +
+ Enter value for GREEN channel (0-255)
-
- Save Texture - Save edited texture. +
+ Value for ALPHA - TRANSPARENCY channel (0-255)
-
- Power: - Set the brush power amount. 0 = minimum affection, 1 = maximum affection +
+ Enter value for LUMINANCE channel (0-100)
-
- Brush Shape: - Choose shape for brush masking effect -
- - -
+
+ Enter value for HUE channel (0-360)
-
- Brush Radius: - Set the brush radius in pixel units +
+
+ Axis Lock: + You can lock modification to an axis here. +
+ + X  + Y  + Z 
-
- Stabilizer: - The stabilizer generates a small delay between user input and painting, which will be used to compute a smoother paint stroke.. +
+
+ Pressure: + Set whether to use pressure sensitivity (for example pen tablet) +
+
+ Mode: + Choose paint tool mode +
+  Disabled +  Texture +  Vertexcolor +  Sculpting - Add +  Sculpting - Subtract +  Softbody - Pinning +  Softbody - Physics +  Hairparticle - Add Triangle +  Hairparticle - Remove Triangle +  Hairparticle - Length (Alpha) +  Wind weight (Alpha)
-
- Color -
- Enter value for BLUE channel (0-255) -
-
- Enter value for SATURATION channel (0-100) -
-
- Enter value for RED channel (0-255) -
-
- Enter value for GREEN channel (0-255) -
-
- Value for ALPHA - TRANSPARENCY channel (0-255) -
-
- Enter value for LUMINANCE channel (0-100) -
-
- Enter value for HUE channel (0-360) -
-
-
- Axis Lock: - You can lock modification to an axis here. -
- - X  - Y  - Z  -
-
-
- Pressure: - Set whether to use pressure sensitivity (for example pen tablet) -
-
- Mode: - Choose paint tool mode -
-  Disabled -  Texture -  Vertexcolor -  Sculpting - Add -  Sculpting - Subtract -  Softbody - Pinning -  Softbody - Physics -  Hairparticle - Add Triangle -  Hairparticle - Remove Triangle -  Hairparticle - Length (Alpha) -  Wind weight (Alpha) -
-
-
- Wireframe: - Set whether to draw wireframe on top of geometry or not -
-
- Rotation: - Brush rotation randomness. This will affect the splat mode brush texture. -
-
- Open an image to use as reveal mode texture. +
+
+ Wireframe: + Set whether to draw wireframe on top of geometry or not +
+
+ Rotation: + Brush rotation randomness. This will affect the splat mode brush texture. +
+
+ Open an image to use as reveal mode texture. Reveal mode means that the texture will use the UV of the mesh. It will be multiplied by brush tex. -
-
- Texture Slot: - Choose texture slot of the selected material to paint (texture paint mode only) -
- BaseColor (RGBA) - Normal (RGB) - SurfaceMap (RGBA) - DisplacementMap (R) - EmissiveMap (RGBA) - OcclusionMap (R) - TransmissionMap (R) - SheenColorMap (R) - SheenRoughMap (R) - ClearcoatMap (R) - ClearcoatRoughMap (R) - ClearcoatNormMap (R) -
-
-
- Open an image to use as brush texture (splatting mode). -Splat mode means that the texture will be relative to the brush position -
-
- タイプ別のエンティティにフィルタリングを適用する +
+ Texture Slot: + Choose texture slot of the selected material to paint (texture paint mode only)
- * - - - - - - - - - - - - - - - - - - - - - - + BaseColor (RGBA) + Normal (RGB) + SurfaceMap (RGBA) + DisplacementMap (R) + EmissiveMap (RGBA) + OcclusionMap (R) + TransmissionMap (R) + SheenColorMap (R) + SheenRoughMap (R) + ClearcoatMap (R) + ClearcoatRoughMap (R) + ClearcoatNormMap (R)
-
- エンティティ +
+ Open an image to use as brush texture (splatting mode). +Splat mode means that the texture will be relative to the brush position
-
- 名前によるエンティティへのフィルタリングの適用 +
+
+ タイプ別のエンティティにフィルタリングを適用する +
+ * + + + + + + + + + + + + + + + + + + + + + +
-
- カメラ -
- Movement Speed: -
-
- Far Plane: - Controls the camera's far clip plane, geometry farther than this will be clipped. -
-
- Aperture Shape Y: - Controls the depth of field effect's bokeh shape -
-
- Aperture Size: - Controls the depth of field effect's strength -
-
- Aperture Shape X: - Controls the depth of field effect's bokeh shape -
-
- Follow Proxy Delay: -
-
- Focal Length: - Controls the depth of field effect's focus distance -
-
- Place Proxy - Copy the current camera and place a proxy of it in the world. -
-
- FOV: - Controls the camera's top-down field of view (in degrees) -
-
- Near Plane: - Controls the camera's near clip plane, geometry closer than this will be clipped. -
-
- Follow Proxy: -
-
- Reset Camera -
-
- Acceleration: -
-
- Rotation Speed: -
-
- FPS Camera: -
+
+
+ エンティティ +
+
+ 名前によるエンティティへのフィルタリングの適用 +
+
+ カメラ +
+ Movement Speed: +
+
+ Far Plane: + Controls the camera's far clip plane, geometry farther than this will be clipped. +
+
+ Aperture Shape Y: + Controls the depth of field effect's bokeh shape +
+
+ Aperture Size: + Controls the depth of field effect's strength +
+
+ Aperture Shape X: + Controls the depth of field effect's bokeh shape +
+
+ Follow Proxy Delay: +
+
+ Focal Length: + Controls the depth of field effect's focus distance +
+
+ Place Proxy + Copy the current camera and place a proxy of it in the world. +
+
+ FOV: + Controls the camera's top-down field of view (in degrees) +
+
+ Near Plane: + Controls the camera's near clip plane, geometry closer than this will be clipped. +
+
+ Follow Proxy: +
+
+ Reset Camera +
+
+ Acceleration: +
+
+ Rotation Speed: +
+
+ FPS Camera:
diff --git a/Editor/main_Windows.cpp b/Editor/main_Windows.cpp index 6ef27f39b..245d3495c 100644 --- a/Editor/main_Windows.cpp +++ b/Editor/main_Windows.cpp @@ -179,6 +179,7 @@ BOOL CreateEditorWindow(int nCmdShow) editor.SetWindow(hWnd); ShowWindow(hWnd, nCmdShow); + //SendMessage(hWnd, WM_SYSCOMMAND, SC_MAXIMIZE, 0); UpdateWindow(hWnd); DragAcceptFiles(hWnd, TRUE); diff --git a/README.md b/README.md index dfb2238d3..e2b432ee2 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,7 @@ [![Github Build Status](https://github.com/turanszkij/WickedEngine/workflows/Build/badge.svg)](https://github.com/turanszkij/WickedEngine/actions) [![Discord chat](https://img.shields.io/discord/602811659224088577?logo=discord)](https://discord.gg/CFjRYmE) +[![Forum](https://img.shields.io/badge/forum--blue)](https://wickedengine.net/forum/) follow on Twitter
[![Steam](https://img.shields.io/badge/-Steam-383838.svg?style=for-the-badge&logo=steam)](https://store.steampowered.com/app/1967460/Wicked_Engine/) @@ -13,15 +14,15 @@
Wicked Engine is an open-source 3D engine with modern graphics. Use this as a C++ framework for your graphics projects, a standalone 3D editor, LUA scripting or just for learning.
-This project is hosted on GitHub. -- [Documentation](Content/Documentation/WickedEngine-Documentation.md)
-- [Scripting API Documentation](Content/Documentation/ScriptingAPI-Documentation.md)
+- [Website](https://wickedengine.net/)
+- [Forum](https://wickedengine.net/forum/)
- [Features](features.txt)
-- [Devblog](https://wickedengine.net/)
- [Videos](https://www.youtube.com/playlist?list=PLLN-1FTGyLU_HJoC5zx6hJkB3D2XLiaxS)
+- [C++ Documentation](Content/Documentation/WickedEngine-Documentation.md)
+- [Lua Documentation](Content/Documentation/ScriptingAPI-Documentation.md)
-You can get the full source code by using Git version control and cloning https://github.com/turanszkij/WickedEngine.git, or downloading it as zip. You can also download prebuilt and packaged version of the Editor here (requires Github sign in): [![Github Build Status](https://github.com/turanszkij/WickedEngine/workflows/Build/badge.svg)](https://github.com/turanszkij/WickedEngine/actions) +You can get the full source code by using Git version control and cloning https://github.com/turanszkij/WickedEngine.git, or downloading it as zip. You can also download nightly packaged builds of the Editor here (requires Github sign in): [![Github Build Status](https://github.com/turanszkij/WickedEngine/workflows/Build/badge.svg)](https://github.com/turanszkij/WickedEngine/actions)

@@ -203,7 +204,7 @@ The native model format is the WISCENE format. Any application using Wick -In addition, the Editor supports the importing of some common model formats (the list will potentially grow): +In addition, the Editor supports importing some common model formats: - OBJ - GLTF 2.0 - VRM @@ -214,24 +215,20 @@ The preferred workflow is to import models into the Editor, and save them as ### Graphics API: -The default renderer is `DirectX 12` on Windows and `Vulkan` on Linux. The `DirectX 11` renderer is no longer available starting from version 0.57.0, but it can be found on the dx11-backup branch. +The default renderer is `DirectX 12` on Windows and `Vulkan` on Linux. You can specify command line arguments (without any prefix) to switch between render devices or other settings. Currently the list of options: - - - - - + - + @@ -271,9 +268,10 @@ If you are having trouble getting the applications to run, make sure that you sa -- If you experience crashes, follow these steps to find out the problem: +- If you experience crashes, you can try these to find out the problem: - make sure your environment is up to date, with latest graphics drivers and operating system updates. - - see if there is a wiBackLog.txt in your user temp folder (for example: C:\Users\username\AppData\Local\Temp), and request help on Discord or Github issue - - build the engine in Debug mode and try to run it, see where it crashes, provide call stack on Discord or Github issue + - see if there is a wiBackLog.txt in your user temp folder (for example: C:\Users\username\AppData\Local\Temp) + - request help on the [Forum](https://wickedengine.net/forum/), [Discord](https://discord.gg/CFjRYmE) or [Github issue](https://github.com/turanszkij/WickedEngine/issues) + - build the engine in Debug mode and try to run it, see where it crashes - run the engine with the `debugdevice` command argument and post the text from your console output window when the crash happens - for very advanced users, using `gpuvalidation` with `debugdevice` will print additional graphics debug information diff --git a/WickedEngine/shaders/ShaderInterop_Image.h b/WickedEngine/shaders/ShaderInterop_Image.h index 4ed5276e1..2d5646706 100644 --- a/WickedEngine/shaders/ShaderInterop_Image.h +++ b/WickedEngine/shaders/ShaderInterop_Image.h @@ -8,6 +8,8 @@ static const uint IMAGE_FLAG_OUTPUT_COLOR_SPACE_LINEAR = 1u << 2u; static const uint IMAGE_FLAG_FULLSCREEN = 1u << 3u; static const uint IMAGE_FLAG_MIRROR = 1u << 4u; static const uint IMAGE_FLAG_CORNER_ROUNDING = 1u << 5u; +static const uint IMAGE_FLAG_ANGULAR_DOUBLESIDED = 1u << 6u; +static const uint IMAGE_FLAG_ANGULAR_INVERSE = 1u << 7u; struct ImageConstants { @@ -33,6 +35,10 @@ struct ImageConstants float2 b1; float2 b2; float2 b3; + + float2 angular_softness_direction; + float angular_softness_scale; + float angular_softness_offset; }; CONSTANTBUFFER(image, ImageConstants, CBSLOT_IMAGE); diff --git a/WickedEngine/shaders/ShaderInterop_Postprocess.h b/WickedEngine/shaders/ShaderInterop_Postprocess.h index 6ad3825dd..e22565718 100644 --- a/WickedEngine/shaders/ShaderInterop_Postprocess.h +++ b/WickedEngine/shaders/ShaderInterop_Postprocess.h @@ -125,11 +125,7 @@ static const uint TONEMAP_FLAG_ACES = 1 << 1; struct PushConstantsTonemap { float2 resolution_rcp; - float exposure; - uint flags; - float brightness; - float contrast; - float saturation; + uint2 exposure_brightness_contrast_saturation; int texture_input; int buffer_input_luminance; @@ -139,6 +135,7 @@ struct PushConstantsTonemap int texture_bloom; int texture_output; uint display_colorspace; + uint flags; }; struct PostprocessTileStatistics diff --git a/WickedEngine/shaders/imagePS.hlsl b/WickedEngine/shaders/imagePS.hlsl index a72b6b09d..6777fe0bf 100644 --- a/WickedEngine/shaders/imagePS.hlsl +++ b/WickedEngine/shaders/imagePS.hlsl @@ -56,12 +56,35 @@ float4 main(VertextoPixel input) : SV_TARGET color.rgb = RemoveSRGBCurve_Fast(color.rgb); color.rgb *= image.hdr_scaling; } - + + [branch] if (image.border_soften > 0) { float edge = max(abs(input.edge.x), abs(input.edge.y)); color.a *= smoothstep(0, image.border_soften, 1 - edge); } + [branch] + if (image.angular_softness_scale > 0) + { + float2 direction = normalize(uvsets.xy - 0.5); + float dp = dot(direction, image.angular_softness_direction); + if (image.flags & IMAGE_FLAG_ANGULAR_DOUBLESIDED) + { + dp = abs(dp); + } + else + { + dp = saturate(dp); + } + float angular = saturate(mad(dp, image.angular_softness_scale, image.angular_softness_offset)); + if (image.flags & IMAGE_FLAG_ANGULAR_INVERSE) + { + angular = 1 - angular; + } + angular = smoothstep(0, 1, angular); + color.a *= angular; + } + return color; } diff --git a/WickedEngine/shaders/tonemapCS.hlsl b/WickedEngine/shaders/tonemapCS.hlsl index e54a7e920..5252c5212 100644 --- a/WickedEngine/shaders/tonemapCS.hlsl +++ b/WickedEngine/shaders/tonemapCS.hlsl @@ -59,53 +59,19 @@ float4x4 saturationMatrix(float saturation) return float4x4(red, 0, green, 0, blue, 0, 0, 0, 0, 1); } -#ifndef __PSSL__ -#undef WICKED_ENGINE_DEFAULT_ROOTSIGNATURE // don't use auto root signature! -[RootSignature( - "RootConstants(num32BitConstants=16, b999)," - "DescriptorTable( " - "SRV(t0, space = 2, offset = 0, numDescriptors = unbounded, flags = DESCRIPTORS_VOLATILE | DATA_VOLATILE)," - "SRV(t0, space = 3, offset = 0, numDescriptors = unbounded, flags = DESCRIPTORS_VOLATILE | DATA_VOLATILE)," - "SRV(t0, space = 4, offset = 0, numDescriptors = unbounded, flags = DESCRIPTORS_VOLATILE | DATA_VOLATILE)," - "SRV(t0, space = 5, offset = 0, numDescriptors = unbounded, flags = DESCRIPTORS_VOLATILE | DATA_VOLATILE)," - "SRV(t0, space = 6, offset = 0, numDescriptors = unbounded, flags = DESCRIPTORS_VOLATILE | DATA_VOLATILE)," - "SRV(t0, space = 7, offset = 0, numDescriptors = unbounded, flags = DESCRIPTORS_VOLATILE | DATA_VOLATILE)," - "SRV(t0, space = 8, offset = 0, numDescriptors = unbounded, flags = DESCRIPTORS_VOLATILE | DATA_VOLATILE)," - "SRV(t0, space = 9, offset = 0, numDescriptors = unbounded, flags = DESCRIPTORS_VOLATILE | DATA_VOLATILE)," - "SRV(t0, space = 10, offset = 0, numDescriptors = unbounded, flags = DESCRIPTORS_VOLATILE | DATA_VOLATILE)," - "SRV(t0, space = 11, offset = 0, numDescriptors = unbounded, flags = DESCRIPTORS_VOLATILE | DATA_VOLATILE)," - "SRV(t0, space = 12, offset = 0, numDescriptors = unbounded, flags = DESCRIPTORS_VOLATILE | DATA_VOLATILE)," - "SRV(t0, space = 13, offset = 0, numDescriptors = unbounded, flags = DESCRIPTORS_VOLATILE | DATA_VOLATILE)," - "SRV(t0, space = 14, offset = 0, numDescriptors = unbounded, flags = DESCRIPTORS_VOLATILE | DATA_VOLATILE)," - "SRV(t0, space = 15, offset = 0, numDescriptors = unbounded, flags = DESCRIPTORS_VOLATILE | DATA_VOLATILE)," - "SRV(t0, space = 16, offset = 0, numDescriptors = unbounded, flags = DESCRIPTORS_VOLATILE | DATA_VOLATILE)," - "SRV(t0, space = 17, offset = 0, numDescriptors = unbounded, flags = DESCRIPTORS_VOLATILE | DATA_VOLATILE)," - "SRV(t0, space = 18, offset = 0, numDescriptors = unbounded, flags = DESCRIPTORS_VOLATILE | DATA_VOLATILE)," - "SRV(t0, space = 19, offset = 0, numDescriptors = unbounded, flags = DESCRIPTORS_VOLATILE | DATA_VOLATILE)," - "SRV(t0, space = 20, offset = 0, numDescriptors = unbounded, flags = DESCRIPTORS_VOLATILE | DATA_VOLATILE)," - "UAV(u0, space = 21, offset = 0, numDescriptors = unbounded, flags = DESCRIPTORS_VOLATILE | DATA_VOLATILE)," - "UAV(u0, space = 22, offset = 0, numDescriptors = unbounded, flags = DESCRIPTORS_VOLATILE | DATA_VOLATILE)," - "UAV(u0, space = 23, offset = 0, numDescriptors = unbounded, flags = DESCRIPTORS_VOLATILE | DATA_VOLATILE)," - "UAV(u0, space = 24, offset = 0, numDescriptors = unbounded, flags = DESCRIPTORS_VOLATILE | DATA_VOLATILE)," - "UAV(u0, space = 25, offset = 0, numDescriptors = unbounded, flags = DESCRIPTORS_VOLATILE | DATA_VOLATILE)," - "UAV(u0, space = 26, offset = 0, numDescriptors = unbounded, flags = DESCRIPTORS_VOLATILE | DATA_VOLATILE)," - "UAV(u0, space = 27, offset = 0, numDescriptors = unbounded, flags = DESCRIPTORS_VOLATILE | DATA_VOLATILE)," - "UAV(u0, space = 28, offset = 0, numDescriptors = unbounded, flags = DESCRIPTORS_VOLATILE | DATA_VOLATILE)," - "UAV(u0, space = 29, offset = 0, numDescriptors = unbounded, flags = DESCRIPTORS_VOLATILE | DATA_VOLATILE)," - "UAV(u0, space = 30, offset = 0, numDescriptors = unbounded, flags = DESCRIPTORS_VOLATILE | DATA_VOLATILE)," - "UAV(u0, space = 31, offset = 0, numDescriptors = unbounded, flags = DESCRIPTORS_VOLATILE | DATA_VOLATILE)," - "UAV(u0, space = 32, offset = 0, numDescriptors = unbounded, flags = DESCRIPTORS_VOLATILE | DATA_VOLATILE)," - "UAV(u0, space = 33, offset = 0, numDescriptors = unbounded, flags = DESCRIPTORS_VOLATILE | DATA_VOLATILE)" - "), " - "StaticSampler(s100, addressU = TEXTURE_ADDRESS_CLAMP, addressV = TEXTURE_ADDRESS_CLAMP, addressW = TEXTURE_ADDRESS_CLAMP, filter = FILTER_MIN_MAG_MIP_LINEAR)" -)] -#endif // __PSSL__ - [numthreads(POSTPROCESS_BLOCKSIZE, POSTPROCESS_BLOCKSIZE, 1)] void main(uint3 DTid : SV_DispatchThreadID) { + if(!GetCamera().is_pixel_inside_scissor(DTid.xy)) + return; + float2 uv = (DTid.xy + 0.5f) * tonemap_push.resolution_rcp; - float exposure = tonemap_push.exposure; + + float4 exposure_brightness_contrast_saturation = unpack_half4(tonemap_push.exposure_brightness_contrast_saturation); + float exposure = exposure_brightness_contrast_saturation.x; + float brightness = exposure_brightness_contrast_saturation.y; + float contrast = exposure_brightness_contrast_saturation.z; + float saturation = exposure_brightness_contrast_saturation.w; [branch] if (tonemap_push.texture_input_distortion >= 0) @@ -164,8 +130,8 @@ void main(uint3 DTid : SV_DispatchThreadID) result.rgb += (dither((float2)DTid.xy) - 0.5f) / 64.0f; } - result.rgb = (result.rgb - 0.5f) * tonemap_push.contrast + 0.5f + tonemap_push.brightness; - result.rgb = (float3)(mul(saturationMatrix(tonemap_push.saturation), result)); + result.rgb = (result.rgb - 0.5f) * contrast + 0.5f + brightness; + result.rgb = (float3)(mul(saturationMatrix(saturation), result)); [branch] if (tonemap_push.texture_output >= 0) diff --git a/WickedEngine/wiApplication.cpp b/WickedEngine/wiApplication.cpp index 155376319..fb5a8dea3 100644 --- a/WickedEngine/wiApplication.cpp +++ b/WickedEngine/wiApplication.cpp @@ -256,6 +256,8 @@ namespace wi { auto range = wi::profiler::BeginRangeCPU("Update"); + infoDisplay.rect = {}; + wi::lua::SetDeltaTime(double(dt)); wi::lua::Update(); @@ -317,6 +319,11 @@ namespace wi // Draw the information display if (infoDisplay.active) { + if (infoDisplay.rect.right > 0) + { + graphicsDevice->BindScissorRects(1, &infoDisplay.rect, cmd); + } + infodisplay_str.clear(); if (infoDisplay.watermark) { @@ -445,8 +452,8 @@ namespace wi } wi::font::Params params = wi::font::Params( - 4, - 4, + 4 + canvas.PhysicalToLogical((uint32_t)infoDisplay.rect.left), + 4 + canvas.PhysicalToLogical((uint32_t)infoDisplay.rect.top), infoDisplay.size, wi::font::WIFALIGN_LEFT, wi::font::WIFALIGN_TOP, @@ -506,10 +513,26 @@ namespace wi params.cursor = wi::font::Draw(std::to_string(wi::renderer::GetShaderErrorCount()) + " shader compilation errors! Check the backlog for more information!\n", params, cmd); } - if (infoDisplay.colorgrading_helper) { - wi::image::Draw(wi::texturehelper::getColorGradeDefault(), wi::image::Params(0, 0, 256.0f / canvas.GetDPIScaling(), 16.0f / canvas.GetDPIScaling()), cmd); + wi::image::Draw( + wi::texturehelper::getColorGradeDefault(), + wi::image::Params( + canvas.PhysicalToLogical((uint32_t)infoDisplay.rect.left), + canvas.PhysicalToLogical((uint32_t)infoDisplay.rect.top), + canvas.PhysicalToLogical(256), + canvas.PhysicalToLogical(16) + ), + cmd + ); + } + + if (infoDisplay.rect.right > 0) + { + Rect rect; + rect.right = canvas.width; + rect.bottom = canvas.height; + graphicsDevice->BindScissorRects(1, &rect, cmd); } } diff --git a/WickedEngine/wiApplication.h b/WickedEngine/wiApplication.h index 4ce4da288..1e077521c 100644 --- a/WickedEngine/wiApplication.h +++ b/WickedEngine/wiApplication.h @@ -116,6 +116,8 @@ namespace wi int size = 16; // display default color grading helper texture in top left corner of the screen bool colorgrading_helper = false; + // rect to specify where to render the information + wi::graphics::Rect rect; }; // display all-time engine information text InfoDisplayer infoDisplay; diff --git a/WickedEngine/wiBacklog.cpp b/WickedEngine/wiBacklog.cpp index 7bb047b67..6fe0041f8 100644 --- a/WickedEngine/wiBacklog.cpp +++ b/WickedEngine/wiBacklog.cpp @@ -46,6 +46,7 @@ namespace wi::backlog bool locked = false; bool blockLuaExec = false; LogLevel logLevel = LogLevel::Default; + LogLevel unseen = LogLevel::None; std::string getTextWithoutLock() { @@ -321,6 +322,7 @@ namespace wi::backlog } params.cursor = wi::font::Draw(x.text, params, cmd); } + unseen = LogLevel::None; } std::string getText() @@ -385,6 +387,8 @@ namespace wi::backlog break; } + unseen = std::max(unseen, level); + // lock released on block end } @@ -463,4 +467,9 @@ namespace wi::backlog { logLevel = newLevel; } + + LogLevel GetUnseenLogLevelMax() + { + return unseen; + } } diff --git a/WickedEngine/wiBacklog.h b/WickedEngine/wiBacklog.h index 8169a14a7..36ec866d8 100644 --- a/WickedEngine/wiBacklog.h +++ b/WickedEngine/wiBacklog.h @@ -53,6 +53,8 @@ namespace wi::backlog void SetLogLevel(LogLevel newLevel); + LogLevel GetUnseenLogLevelMax(); + // These are no longer used, but kept here to not break user code: inline void input(const char input) {} diff --git a/WickedEngine/wiGUI.cpp b/WickedEngine/wiGUI.cpp index 002d70770..cf4869c9a 100644 --- a/WickedEngine/wiGUI.cpp +++ b/WickedEngine/wiGUI.cpp @@ -325,6 +325,39 @@ namespace wi::gui sprites[state].Update(dt); font.Update(dt); + + angular_highlight_timer += dt; + } + void Widget::Render(const wi::Canvas& canvas, wi::graphics::CommandList cmd) const + { + if (!IsVisible()) + { + return; + } + + if (angular_highlight_width > 0) + { + wi::image::Params fx; + fx.color = angular_highlight_color; + fx.pos.x = translation.x - angular_highlight_width; + fx.pos.y = translation.y - angular_highlight_width; + fx.siz.x = scale.x + angular_highlight_width * 2; + fx.siz.y = scale.y + angular_highlight_width * 2; + if (sprites[state].params.isCornerRoundingEnabled()) + { + fx.enableCornerRounding(); + fx.corners_rounding[0] = sprites[state].params.corners_rounding[0]; + fx.corners_rounding[1] = sprites[state].params.corners_rounding[1]; + fx.corners_rounding[2] = sprites[state].params.corners_rounding[2]; + fx.corners_rounding[3] = sprites[state].params.corners_rounding[3]; + } + fx.angular_softness_outer_angle = XM_PI * 0.6f; + fx.angular_softness_inner_angle = 0; + XMStoreFloat2(&fx.angular_softness_direction, XMVector2Normalize(XMVectorSet(std::sin(angular_highlight_timer), std::cos(angular_highlight_timer), 0, 0))); + fx.enableAngularSoftnessDoubleSided(); + fx.border_soften = 0.1f; + wi::image::Draw(nullptr, fx, cmd); + } } void Widget::RenderTooltip(const wi::Canvas& canvas, CommandList cmd) const { @@ -906,6 +939,7 @@ namespace wi::gui } void Button::Render(const wi::Canvas& canvas, CommandList cmd) const { + Widget::Render(canvas, cmd); if (!IsVisible()) { return; @@ -1115,6 +1149,7 @@ namespace wi::gui } void ScrollBar::Render(const wi::Canvas& canvas, CommandList cmd) const { + Widget::Render(canvas, cmd); if (!IsVisible()) { return; @@ -1200,7 +1235,14 @@ namespace wi::gui } Widget::Update(canvas, dt); - font.params.h_wrap = scale.x; + if (wrap_enabled) + { + font.params.h_wrap = scale.x; + } + else + { + font.params.h_wrap = -1; + } switch (font.params.h_align) { @@ -1229,11 +1271,14 @@ namespace wi::gui break; } - scrollbar.SetListLength(font.TextHeight()); - scrollbar.ClearTransform(); - scrollbar.SetPos(XMFLOAT2(translation.x + scale.x - scrollbar_width, translation.y)); - scrollbar.SetSize(XMFLOAT2(scrollbar_width, scale.y)); - scrollbar.Update(canvas, dt); + if (scrollbar.IsEnabled()) + { + scrollbar.SetListLength(font.TextHeight()); + scrollbar.ClearTransform(); + scrollbar.SetPos(XMFLOAT2(translation.x + scale.x - scrollbar_width, translation.y)); + scrollbar.SetSize(XMFLOAT2(scrollbar_width, scale.y)); + scrollbar.Update(canvas, dt); + } if (IsEnabled() && dt > 0) { @@ -1243,7 +1288,7 @@ namespace wi::gui } Hitbox2D pointerHitbox = GetPointerHitbox(); - if (scroll_allowed && scrollbar.IsScrollbarRequired() && pointerHitbox.intersects(hitBox)) + if (scroll_allowed && scrollbar.IsEnabled() && scrollbar.IsScrollbarRequired() && pointerHitbox.intersects(hitBox)) { scroll_allowed = false; state = FOCUS; @@ -1261,15 +1306,18 @@ namespace wi::gui } } - if (scrollbar.IsScrollbarRequired()) + if (scrollbar.IsEnabled()) { - font.params.h_wrap = scale.x - scrollbar_width; + if (scrollbar.IsScrollbarRequired()) + { + font.params.h_wrap = scale.x - scrollbar_width; + } + font.params.posY += scrollbar.GetOffset(); } - - font.params.posY += scrollbar.GetOffset(); } void Label::Render(const wi::Canvas& canvas, CommandList cmd) const { + Widget::Render(canvas, cmd); if (!IsVisible()) { return; @@ -1302,7 +1350,10 @@ namespace wi::gui sprites[IDLE].Draw(cmd); font.Draw(cmd); - scrollbar.Render(canvas, cmd); + if (scrollbar.IsEnabled()) + { + scrollbar.Render(canvas, cmd); + } } void Label::SetColor(wi::Color color, int id) { @@ -1560,6 +1611,7 @@ namespace wi::gui } void TextInputField::Render(const wi::Canvas& canvas, CommandList cmd) const { + Widget::Render(canvas, cmd); if (!IsVisible()) { return; @@ -1642,7 +1694,6 @@ namespace wi::gui { font.Draw(cmd); } - } void TextInputField::OnInputAccepted(std::function func) { @@ -1917,6 +1968,7 @@ namespace wi::gui } void Slider::Render(const wi::Canvas& canvas, CommandList cmd) const { + Widget::Render(canvas, cmd); if (!IsVisible()) { return; @@ -2087,6 +2139,7 @@ namespace wi::gui } void CheckBox::Render(const wi::Canvas& canvas, CommandList cmd) const { + Widget::Render(canvas, cmd); if (!IsVisible()) { return; @@ -2207,7 +2260,7 @@ namespace wi::gui - + static constexpr float combo_height() { return 20; }; void ComboBox::Create(const std::string& name) { SetName(name); @@ -2226,17 +2279,32 @@ namespace wi::gui { float screenheight = canvas.GetLogicalHeight(); int visible_items = std::min(maxVisibleItemCount, int(items.size()) - firstItemVisible); - float total_height = (visible_items + 1) * scale.y; + float total_height = scale.y + visible_items * combo_height(); if (translation.y + total_height > screenheight) { return -total_height - 1; } return 1; } + float ComboBox::GetDropX(const wi::Canvas& canvas) const + { + if (fixed_drop_width && translation.x > canvas.GetLogicalWidth() * 0.5f) + { + // in this case, left-align the drop down: + float x = translation.x + scale.x - fixed_drop_width; + if (HasScrollbar()) + { + x -= 1 + scale.y; + } + x = std::max(0.0f, x); + return x; + } + return translation.x; + } float ComboBox::GetItemOffset(const wi::Canvas& canvas, int index) const { index = std::max(firstItemVisible, index) - firstItemVisible; - return scale.y * (index + 1) + GetDropOffset(canvas); + return scale.y + combo_height() * index + GetDropOffset(canvas); } bool ComboBox::HasScrollbar() const { @@ -2251,6 +2319,9 @@ namespace wi::gui Widget::Update(canvas, dt); + const float drop_width = fixed_drop_width > 0 ? fixed_drop_width : (IsDropArrowEnabled() ? scale.x : (scale.x - 1 - scale.y)); + const float drop_x = GetDropX(canvas); + if (IsEnabled() && dt > 0) { float drop_offset = GetDropOffset(canvas); @@ -2275,7 +2346,11 @@ namespace wi::gui hitBox.pos.x = translation.x; hitBox.pos.y = translation.y; - hitBox.siz.x = scale.x + scale.y + 1; // + drop-down indicator arrow + little offset + hitBox.siz.x = scale.x; + if (drop_arrow) + { + hitBox.siz.x += scale.y + 1; // + drop-down indicator arrow + little offset + } hitBox.siz.y = scale.y; Hitbox2D pointerHitbox = GetPointerHitbox(); @@ -2314,7 +2389,7 @@ namespace wi::gui } const float scrollbar_begin = translation.y + scale.y + drop_offset + scale.y * 0.5f; - const float scrollbar_end = scrollbar_begin + std::max(0.0f, (float)std::min(maxVisibleItemCount, (int)items.size()) - 1) * scale.y; + const float scrollbar_end = scrollbar_begin + std::max(0.0f, (float)std::min(maxVisibleItemCount, (int)items.size()) - 1) * combo_height(); if (state == ACTIVE) { @@ -2323,7 +2398,7 @@ namespace wi::gui { if (combostate != COMBOSTATE_SELECTING && combostate != COMBOSTATE_INACTIVE) { - if (combostate == COMBOSTATE_SCROLLBAR_GRABBED || pointerHitbox.intersects(Hitbox2D(XMFLOAT2(translation.x + scale.x + 1, translation.y + scale.y + drop_offset), XMFLOAT2(scale.y, (float)std::min(maxVisibleItemCount, (int)items.size()) * scale.y)))) + if (combostate == COMBOSTATE_SCROLLBAR_GRABBED || pointerHitbox.intersects(Hitbox2D(XMFLOAT2(drop_x + drop_width + 1, translation.y + scale.y + drop_offset), XMFLOAT2(scale.y, (float)std::min(maxVisibleItemCount, (int)items.size()) * combo_height())))) { if (click_down) { @@ -2370,10 +2445,10 @@ namespace wi::gui for (int i = firstItemVisible; i < (firstItemVisible + std::min(maxVisibleItemCount, (int)items.size())); ++i) { Hitbox2D itembox; - itembox.pos.x = translation.x; + itembox.pos.x = drop_x; itembox.pos.y = translation.y + GetItemOffset(canvas, i); - itembox.siz.x = scale.x; - itembox.siz.y = scale.y; + itembox.siz.x = drop_width; + itembox.siz.y = combo_height(); if (pointerHitbox.intersects(itembox)) { hovered = i; @@ -2410,19 +2485,27 @@ namespace wi::gui } void ComboBox::Render(const wi::Canvas& canvas, CommandList cmd) const { + Widget::Render(canvas, cmd); if (!IsVisible()) { return; } GraphicsDevice* device = wi::graphics::GetDevice(); + const float drop_width = fixed_drop_width > 0 ? fixed_drop_width : (IsDropArrowEnabled() ? scale.x : (scale.x - 1 - scale.y)); + const float drop_x = GetDropX(canvas); + // shadow: if (shadow > 0) { wi::image::Params fx = sprites[state].params; fx.pos.x -= shadow; fx.pos.y -= shadow; - fx.siz.x += shadow * 2 + 1 + scale.y; + fx.siz.x += shadow * 2; + if (drop_arrow) + { + fx.siz.x += 1 + scale.y; + } fx.siz.y += shadow * 2; fx.color = shadow_color; if (fx.isCornerRoundingEnabled()) @@ -2446,56 +2529,60 @@ namespace wi::gui font.Draw(cmd); - struct Vertex + const float drop_offset = GetDropOffset(canvas); + + if (drop_arrow) { - XMFLOAT4 pos; - XMFLOAT4 col; - }; - static GPUBuffer vb_triangle; - if (!vb_triangle.IsValid()) - { - Vertex vertices[3]; - vertices[0].col = XMFLOAT4(1, 1, 1, 1); - vertices[1].col = XMFLOAT4(1, 1, 1, 1); - vertices[2].col = XMFLOAT4(1, 1, 1, 1); - wi::math::ConstructTriangleEquilateral(1, vertices[0].pos, vertices[1].pos, vertices[2].pos); - - GPUBufferDesc desc; - desc.bind_flags = BindFlag::VERTEX_BUFFER; - desc.size = sizeof(vertices); - device->CreateBuffer(&desc, &vertices, &vb_triangle); - } - const XMMATRIX Projection = canvas.GetProjection(); - - float drop_offset = GetDropOffset(canvas); - - // control-arrow-background - wi::image::Params fx = sprites[state].params; - fx.pos = XMFLOAT3(translation.x + scale.x + 1, translation.y, 0); - fx.siz = XMFLOAT2(scale.y, scale.y); - wi::image::Draw(nullptr, fx, cmd); - - // control-arrow-triangle - { - device->BindPipelineState(&gui_internal().PSO_colored, cmd); - - MiscCB cb; - cb.g_xColor = font.params.color; - XMStoreFloat4x4(&cb.g_xTransform, XMMatrixScaling(scale.y * 0.25f, scale.y * 0.25f, 1) * - XMMatrixRotationZ(drop_offset < 0 ? -XM_PIDIV2 : XM_PIDIV2) * - XMMatrixTranslation(translation.x + scale.x + 1 + scale.y * 0.5f, translation.y + scale.y * 0.5f, 0) * - Projection - ); - device->BindDynamicConstantBuffer(cb, CBSLOT_RENDERER_MISC, cmd); - const GPUBuffer* vbs[] = { - &vb_triangle, + struct Vertex + { + XMFLOAT4 pos; + XMFLOAT4 col; }; - const uint32_t strides[] = { - sizeof(Vertex), - }; - device->BindVertexBuffers(vbs, 0, arraysize(vbs), strides, nullptr, cmd); + static GPUBuffer vb_triangle; + if (!vb_triangle.IsValid()) + { + Vertex vertices[3]; + vertices[0].col = XMFLOAT4(1, 1, 1, 1); + vertices[1].col = XMFLOAT4(1, 1, 1, 1); + vertices[2].col = XMFLOAT4(1, 1, 1, 1); + wi::math::ConstructTriangleEquilateral(1, vertices[0].pos, vertices[1].pos, vertices[2].pos); - device->Draw(3, 0, cmd); + GPUBufferDesc desc; + desc.bind_flags = BindFlag::VERTEX_BUFFER; + desc.size = sizeof(vertices); + device->CreateBuffer(&desc, &vertices, &vb_triangle); + } + const XMMATRIX Projection = canvas.GetProjection(); + + // control-arrow-background + wi::image::Params fx = sprites[state].params; + fx.disableCornerRounding(); + fx.pos = XMFLOAT3(translation.x + scale.x + 1, translation.y, 0); + fx.siz = XMFLOAT2(scale.y, scale.y); + wi::image::Draw(nullptr, fx, cmd); + + // control-arrow-triangle + { + device->BindPipelineState(&gui_internal().PSO_colored, cmd); + + MiscCB cb; + cb.g_xColor = font.params.color; + XMStoreFloat4x4(&cb.g_xTransform, XMMatrixScaling(scale.y * 0.25f, scale.y * 0.25f, 1) * + XMMatrixRotationZ(drop_offset < 0 ? -XM_PIDIV2 : XM_PIDIV2) * + XMMatrixTranslation(translation.x + scale.x + 1 + scale.y * 0.5f, translation.y + scale.y * 0.5f, 0) * + Projection + ); + device->BindDynamicConstantBuffer(cb, CBSLOT_RENDERER_MISC, cmd); + const GPUBuffer* vbs[] = { + &vb_triangle, + }; + const uint32_t strides[] = { + sizeof(Vertex), + }; + device->BindVertexBuffers(vbs, 0, arraysize(vbs), strides, nullptr, cmd); + + device->Draw(3, 0, cmd); + } } ApplyScissor(canvas, scissorRect, cmd); @@ -2508,21 +2595,21 @@ namespace wi::gui // drop-down if (state == ACTIVE) { - if (HasScrollbar()) { Rect rect; - rect.left = int(translation.x + scale.x + 1); - rect.right = int(translation.x + scale.x + 1 + scale.y); + rect.left = int(drop_x + drop_width + 1); + rect.right = int(drop_x + drop_width + 1 + scale.y); rect.top = int(translation.y + scale.y + drop_offset); - rect.bottom = int(translation.y + scale.y + drop_offset + scale.y * maxVisibleItemCount); + rect.bottom = int(translation.y + scale.y + drop_offset + combo_height() * maxVisibleItemCount); ApplyScissor(canvas, rect, cmd, false); // control-scrollbar-base { - fx = sprites[state].params; - fx.pos = XMFLOAT3(translation.x + scale.x + 1, translation.y + scale.y + drop_offset, 0); - fx.siz = XMFLOAT2(scale.y, scale.y * maxVisibleItemCount); + wi::image::Params fx = sprites[state].params; + fx.disableCornerRounding(); + fx.pos = XMFLOAT3(drop_x + drop_width + 1, translation.y + scale.y + drop_offset, 0); + fx.siz = XMFLOAT2(scale.y, combo_height() * maxVisibleItemCount); fx.color = drop_color; wi::image::Draw(nullptr, fx, cmd); } @@ -2541,10 +2628,10 @@ namespace wi::gui wi::image::Draw( wi::texturehelper::getWhite(), wi::image::Params( - translation.x + scale.x + 1, + drop_x + drop_width + 1, translation.y + scale.y + drop_offset + scrollbar_delta, scale.y, - scale.y, + combo_height(), col ), cmd @@ -2553,18 +2640,19 @@ namespace wi::gui } Rect rect; - rect.left = int(translation.x); - rect.right = rect.left + int(scale.x); + rect.left = int(drop_x); + rect.right = rect.left + int(drop_width); rect.top = int(translation.y + scale.y + drop_offset); - rect.bottom = rect.top + int(scale.y * maxVisibleItemCount); + rect.bottom = rect.top + int(combo_height() * maxVisibleItemCount); ApplyScissor(canvas, rect, cmd, false); // control-list for (int i = firstItemVisible; i < (firstItemVisible + std::min(maxVisibleItemCount, (int)items.size())); ++i) { - fx = sprites[state].params; - fx.pos = XMFLOAT3(translation.x, translation.y + GetItemOffset(canvas, i), 0); - fx.siz = XMFLOAT2(scale.x, scale.y); + wi::image::Params fx = sprites[state].params; + fx.disableCornerRounding(); + fx.pos = XMFLOAT3(drop_x, translation.y + GetItemOffset(canvas, i), 0); + fx.siz = XMFLOAT2(drop_width, combo_height()); fx.color = drop_color; if (hovered == i) { @@ -2580,8 +2668,8 @@ namespace wi::gui wi::image::Draw(nullptr, fx, cmd); wi::font::Params fp = wi::font::Params( - translation.x + scale.x * 0.5f, - translation.y + scale.y * 0.5f + GetItemOffset(canvas, i), + drop_x + drop_width * 0.5f, + translation.y + combo_height() * 0.5f + GetItemOffset(canvas, i), wi::font::WIFONTSIZE_DEFAULT, wi::font::WIFALIGN_CENTER, wi::font::WIFALIGN_CENTER, @@ -2777,103 +2865,14 @@ namespace wi::gui SetText(name); SetSize(XMFLOAT2(640, 480)); + controls = window_controls; + for (int i = IDLE + 1; i < WIDGETSTATE_COUNT; ++i) { sprites[i].params.color = sprites[IDLE].params.color; } // Add controls - if (has_flag(window_controls, WindowControls::RESIZE_TOPLEFT)) - { - // Add a resizer control to the upperleft corner - resizeDragger_UpperLeft.Create(name + "_resize_dragger_upper_left"); - resizeDragger_UpperLeft.SetLocalizationEnabled(LocalizationEnabled::None); - resizeDragger_UpperLeft.SetShadowRadius(0); - resizeDragger_UpperLeft.SetTooltip("Resize window"); - resizeDragger_UpperLeft.SetText("«|»"); - resizeDragger_UpperLeft.font.params.rotation = XM_PIDIV4; - resizeDragger_UpperLeft.OnDrag([this](EventArgs args) { - auto saved_parent = this->parent; - this->Detach(); - XMFLOAT2 scaleDiff; - scaleDiff.x = (scale.x - args.deltaPos.x) / scale.x; - scaleDiff.y = (scale.y - args.deltaPos.y) / scale.y; - this->Translate(XMFLOAT3(args.deltaPos.x, args.deltaPos.y, 0)); - this->Scale(XMFLOAT3(scaleDiff.x, scaleDiff.y, 1)); - this->scale_local = wi::math::Max(this->scale_local, XMFLOAT3(control_size * 3, control_size * 2, 1)); // don't allow resize to negative or too small - this->AttachTo(saved_parent); - }); - AddWidget(&resizeDragger_UpperLeft, AttachmentOptions::NONE); - } - - if (has_flag(window_controls, WindowControls::RESIZE_TOPRIGHT)) - { - // Add a resizer control to the upperleft corner - resizeDragger_UpperRight.Create(name + "_resize_dragger_upper_right"); - resizeDragger_UpperRight.SetLocalizationEnabled(LocalizationEnabled::None); - resizeDragger_UpperRight.SetShadowRadius(0); - resizeDragger_UpperRight.SetTooltip("Resize window"); - resizeDragger_UpperRight.SetText("«|»"); - resizeDragger_UpperRight.font.params.rotation = XM_PIDIV4 * 3; - resizeDragger_UpperRight.OnDrag([this](EventArgs args) { - auto saved_parent = this->parent; - this->Detach(); - XMFLOAT2 scaleDiff; - scaleDiff.x = (scale.x + args.deltaPos.x) / scale.x; - scaleDiff.y = (scale.y - args.deltaPos.y) / scale.y; - this->Translate(XMFLOAT3(0, args.deltaPos.y, 0)); - this->Scale(XMFLOAT3(scaleDiff.x, scaleDiff.y, 1)); - this->scale_local = wi::math::Max(this->scale_local, XMFLOAT3(control_size * 3, control_size * 2, 1)); // don't allow resize to negative or too small - this->AttachTo(saved_parent); - }); - AddWidget(&resizeDragger_UpperRight, AttachmentOptions::NONE); - } - - if (has_flag(window_controls, WindowControls::RESIZE_BOTTOMLEFT)) - { - // Add a resizer control to the bottom right corner - resizeDragger_BottomLeft.Create(name + "_resize_dragger_bottom_left"); - resizeDragger_BottomLeft.SetLocalizationEnabled(LocalizationEnabled::None); - resizeDragger_BottomLeft.SetShadowRadius(0); - resizeDragger_BottomLeft.SetTooltip("Resize window"); - resizeDragger_BottomLeft.SetText("«|»"); - resizeDragger_BottomLeft.font.params.rotation = XM_PIDIV4 * 3; - resizeDragger_BottomLeft.OnDrag([this](EventArgs args) { - auto saved_parent = this->parent; - this->Detach(); - XMFLOAT2 scaleDiff; - scaleDiff.x = (scale.x - args.deltaPos.x) / scale.x; - scaleDiff.y = (scale.y + args.deltaPos.y) / scale.y; - this->Translate(XMFLOAT3(args.deltaPos.x, 0, 0)); - this->Scale(XMFLOAT3(scaleDiff.x, scaleDiff.y, 1)); - this->scale_local = wi::math::Max(this->scale_local, XMFLOAT3(control_size * 3, control_size * 2, 1)); // don't allow resize to negative or too small - this->AttachTo(saved_parent); - }); - AddWidget(&resizeDragger_BottomLeft, AttachmentOptions::NONE); - } - - if (has_flag(window_controls, WindowControls::RESIZE_BOTTOMRIGHT)) - { - // Add a resizer control to the bottom right corner - resizeDragger_BottomRight.Create(name + "_resize_dragger_bottom_right"); - resizeDragger_BottomRight.SetLocalizationEnabled(LocalizationEnabled::None); - resizeDragger_BottomRight.SetShadowRadius(0); - resizeDragger_BottomRight.SetTooltip("Resize window"); - resizeDragger_BottomRight.SetText("«|»"); - resizeDragger_BottomRight.font.params.rotation = XM_PIDIV4; - resizeDragger_BottomRight.OnDrag([this](EventArgs args) { - auto saved_parent = this->parent; - this->Detach(); - XMFLOAT2 scaleDiff; - scaleDiff.x = (scale.x + args.deltaPos.x) / scale.x; - scaleDiff.y = (scale.y + args.deltaPos.y) / scale.y; - this->Scale(XMFLOAT3(scaleDiff.x, scaleDiff.y, 1)); - this->scale_local = wi::math::Max(this->scale_local, XMFLOAT3(control_size * 3, control_size * 2, 1)); // don't allow resize to negative or too small - this->AttachTo(saved_parent); - }); - AddWidget(&resizeDragger_BottomRight, AttachmentOptions::NONE); - } - if (has_flag(window_controls, WindowControls::MOVE)) { // Add a grabber onto the title bar @@ -2927,7 +2926,7 @@ namespace wi::gui AddWidget(&collapseButton, AttachmentOptions::NONE); } - if (!has_flag(window_controls, WindowControls::MOVE)) + if (!has_flag(window_controls, WindowControls::MOVE) && !name.empty()) { // Simple title bar label.Create(name); @@ -2935,6 +2934,8 @@ namespace wi::gui label.SetShadowRadius(0); label.SetText(name); label.font.params.h_align = wi::font::WIFALIGN_LEFT; + label.scrollbar.SetEnabled(false); + label.SetWrapEnabled(false); AddWidget(&label, AttachmentOptions::NONE); } @@ -2944,6 +2945,7 @@ namespace wi::gui scrollbar_horizontal.sprites_knob[ScrollBar::SCROLLBAR_HOVER].params.color = wi::Color(180, 180, 180, 180); scrollbar_horizontal.sprites_knob[ScrollBar::SCROLLBAR_GRABBED].params.color = wi::Color::White(); scrollbar_horizontal.knob_inset_border = XMFLOAT2(2, 4); + scrollbar_horizontal.SetOverScroll(0.1f); AddWidget(&scrollbar_horizontal); scrollbar_vertical.SetVertical(true); @@ -2952,6 +2954,7 @@ namespace wi::gui scrollbar_vertical.sprites_knob[ScrollBar::SCROLLBAR_HOVER].params.color = wi::Color(180, 180, 180, 180); scrollbar_vertical.sprites_knob[ScrollBar::SCROLLBAR_GRABBED].params.color = wi::Color::White(); scrollbar_vertical.knob_inset_border = XMFLOAT2(4, 2); + scrollbar_vertical.SetOverScroll(0.1f); AddWidget(&scrollbar_vertical); scrollable_area.ClearTransform(); @@ -3006,19 +3009,290 @@ namespace wi::gui return; } + bool focus = false; + + Hitbox2D pointerHitbox = GetPointerHitbox(); + + // Resizer updates: + if (IsEnabled()) + { + float vscale = IsCollapsed() ? control_size : scale.y; + Hitbox2D lefthitbox; + Hitbox2D righthitbox; + Hitbox2D tophitbox; + Hitbox2D bottomhitbox; + Hitbox2D toplefthitbox; + Hitbox2D toprighthitbox; + Hitbox2D bottomrighthitbox; + Hitbox2D bottomlefthitbox; + if (has_flag(controls, WindowControls::RESIZE_LEFT)) + { + lefthitbox = Hitbox2D(XMFLOAT2(translation.x - resizehitboxwidth, translation.y), XMFLOAT2(resizehitboxwidth, vscale)); + } + if (has_flag(controls, WindowControls::RESIZE_RIGHT)) + { + righthitbox = Hitbox2D(XMFLOAT2(translation.x + scale.x, translation.y), XMFLOAT2(resizehitboxwidth, vscale)); + } + if (!IsCollapsed()) + { + if (has_flag(controls, WindowControls::RESIZE_TOP)) + { + tophitbox = Hitbox2D(XMFLOAT2(translation.x, translation.y - resizehitboxwidth), XMFLOAT2(scale.x, resizehitboxwidth)); + } + if (has_flag(controls, WindowControls::RESIZE_BOTTOM)) + { + bottomhitbox = Hitbox2D(XMFLOAT2(translation.x, translation.y + vscale), XMFLOAT2(scale.x, resizehitboxwidth)); + } + if (has_flag(controls, WindowControls::RESIZE_TOPLEFT)) + { + toplefthitbox = Hitbox2D(XMFLOAT2(translation.x - resizehitboxwidth, translation.y - resizehitboxwidth), XMFLOAT2(resizehitboxwidth * 2, resizehitboxwidth * 2)); + } + if (has_flag(controls, WindowControls::RESIZE_TOPRIGHT)) + { + toprighthitbox = Hitbox2D(XMFLOAT2(translation.x + scale.x - resizehitboxwidth, translation.y - resizehitboxwidth), XMFLOAT2(resizehitboxwidth * 2, resizehitboxwidth * 2)); + } + if (has_flag(controls, WindowControls::RESIZE_BOTTOMRIGHT)) + { + bottomrighthitbox = Hitbox2D(XMFLOAT2(translation.x + scale.x - resizehitboxwidth, translation.y + vscale - resizehitboxwidth), XMFLOAT2(resizehitboxwidth * 2, resizehitboxwidth * 2)); + } + if (has_flag(controls, WindowControls::RESIZE_BOTTOMLEFT)) + { + bottomlefthitbox = Hitbox2D(XMFLOAT2(translation.x - resizehitboxwidth, translation.y + vscale - resizehitboxwidth), XMFLOAT2(resizehitboxwidth * 2, resizehitboxwidth * 2)); + } + } + + if (resize_state == RESIZE_STATE_NONE && wi::input::Press(wi::input::MOUSE_BUTTON_LEFT)) + { + if (pointerHitbox.intersects(toplefthitbox)) + { + resize_state = RESIZE_STATE_TOPLEFT; + Activate(); + focus = true; + } + else if (pointerHitbox.intersects(toprighthitbox)) + { + resize_state = RESIZE_STATE_TOPRIGHT; + Activate(); + focus = true; + } + else if (pointerHitbox.intersects(bottomrighthitbox)) + { + resize_state = RESIZE_STATE_BOTTOMRIGHT; + Activate(); + focus = true; + } + else if (pointerHitbox.intersects(bottomlefthitbox)) + { + resize_state = RESIZE_STATE_BOTTOMLEFT; + Activate(); + focus = true; + } + else if (pointerHitbox.intersects(lefthitbox)) + { + resize_state = RESIZE_STATE_LEFT; + Activate(); + focus = true; + } + else if (pointerHitbox.intersects(righthitbox)) + { + resize_state = RESIZE_STATE_RIGHT; + Activate(); + focus = true; + } + else if (pointerHitbox.intersects(tophitbox)) + { + resize_state = RESIZE_STATE_TOP; + Activate(); + focus = true; + } + else if (pointerHitbox.intersects(bottomhitbox)) + { + resize_state = RESIZE_STATE_BOTTOM; + Activate(); + focus = true; + } + resize_begin = pointerHitbox.pos; + } + if (wi::input::Down(wi::input::MOUSE_BUTTON_LEFT)) + { + if (resize_state != RESIZE_STATE_NONE) + { + auto saved_parent = this->parent; + this->Detach(); + float deltaX = pointerHitbox.pos.x - resize_begin.x; + float deltaY = pointerHitbox.pos.y - resize_begin.y; + + switch (resize_state) + { + case wi::gui::Window::RESIZE_STATE_LEFT: + this->Translate(XMFLOAT3(deltaX, 0, 0)); + this->Scale(XMFLOAT3((scale.x - deltaX) / scale.x, 1, 1)); + break; + case wi::gui::Window::RESIZE_STATE_TOP: + this->Translate(XMFLOAT3(0, deltaY, 0)); + this->Scale(XMFLOAT3(1, (scale.y - deltaY) / scale.y, 1)); + break; + case wi::gui::Window::RESIZE_STATE_RIGHT: + this->Scale(XMFLOAT3((scale.x + deltaX) / scale.x, 1, 1)); + break; + case wi::gui::Window::RESIZE_STATE_BOTTOM: + this->Scale(XMFLOAT3(1, (scale.y + deltaY) / scale.y, 1)); + break; + case wi::gui::Window::RESIZE_STATE_TOPLEFT: + this->Translate(XMFLOAT3(deltaX, deltaY, 0)); + this->Scale(XMFLOAT3((scale.x - deltaX) / scale.x, (scale.y - deltaY) / scale.y, 1)); + break; + case wi::gui::Window::RESIZE_STATE_TOPRIGHT: + this->Translate(XMFLOAT3(0, deltaY, 0)); + this->Scale(XMFLOAT3((scale.x + deltaX) / scale.x, (scale.y - deltaY) / scale.y, 1)); + break; + case wi::gui::Window::RESIZE_STATE_BOTTOMRIGHT: + this->Scale(XMFLOAT3((scale.x + deltaX) / scale.x, (scale.y + deltaY) / scale.y, 1)); + break; + case wi::gui::Window::RESIZE_STATE_BOTTOMLEFT: + this->Translate(XMFLOAT3(deltaX, 0, 0)); + this->Scale(XMFLOAT3((scale.x - deltaX) / scale.x, (scale.y + deltaY) / scale.y, 1)); + break; + default: + break; + } + + this->scale_local = wi::math::Max(this->scale_local, XMFLOAT3(control_size * 3, control_size * 2, 1)); // don't allow resize to negative or too small + this->AttachTo(saved_parent); + resize_begin = pointerHitbox.pos; + } + } + else + { + resize_state = RESIZE_STATE_NONE; + } + + if ( + resize_state != RESIZE_STATE_NONE || + pointerHitbox.intersects(toplefthitbox) || + pointerHitbox.intersects(toprighthitbox) || + pointerHitbox.intersects(bottomlefthitbox) || + pointerHitbox.intersects(bottomrighthitbox) || + pointerHitbox.intersects(lefthitbox) || + pointerHitbox.intersects(righthitbox) || + pointerHitbox.intersects(tophitbox) || + pointerHitbox.intersects(bottomhitbox) + ) + { + resize_blink_timer += dt; + } + else + { + resize_blink_timer = 0; + } + } + + // Corner rounding update for control widgets: + for (int i = 0; i < arraysize(moveDragger.sprites); ++i) + { + moveDragger.sprites[i].params.disableCornerRounding(); + label.sprites[i].params.disableCornerRounding(); + collapseButton.sprites[i].params.disableCornerRounding(); + closeButton.sprites[i].params.disableCornerRounding(); + scrollbar_horizontal.sprites[i].params.disableCornerRounding(); + scrollbar_vertical.sprites[i].params.disableCornerRounding(); + + if (sprites[state].params.isCornerRoundingEnabled()) + { + // Left side: + if (closeButton.parent) + { + closeButton.sprites[i].params.enableCornerRounding(); + closeButton.sprites[i].params.corners_rounding[0].radius = sprites[state].params.corners_rounding[0].radius; + if (IsCollapsed()) + { + closeButton.sprites[i].params.corners_rounding[2].radius = sprites[state].params.corners_rounding[2].radius; + } + else + { + closeButton.sprites[i].params.corners_rounding[2].radius = 0; + } + } + else if (collapseButton.parent) + { + collapseButton.sprites[i].params.enableCornerRounding(); + collapseButton.sprites[i].params.corners_rounding[0].radius = sprites[state].params.corners_rounding[0].radius; + if (IsCollapsed()) + { + collapseButton.sprites[i].params.corners_rounding[2].radius = sprites[state].params.corners_rounding[2].radius; + } + else + { + collapseButton.sprites[i].params.corners_rounding[2].radius = 0; + } + } + else if (moveDragger.parent) + { + moveDragger.sprites[i].params.enableCornerRounding(); + moveDragger.sprites[i].params.corners_rounding[0].radius = sprites[state].params.corners_rounding[0].radius; + if (IsCollapsed()) + { + moveDragger.sprites[i].params.corners_rounding[2].radius = sprites[state].params.corners_rounding[2].radius; + } + else + { + moveDragger.sprites[i].params.corners_rounding[2].radius = 0; + } + } + else if (label.parent) + { + label.sprites[i].params.enableCornerRounding(); + label.sprites[i].params.corners_rounding[0].radius = sprites[state].params.corners_rounding[0].radius; + if (IsCollapsed()) + { + label.sprites[i].params.corners_rounding[2].radius = sprites[state].params.corners_rounding[2].radius; + } + else + { + label.sprites[i].params.corners_rounding[2].radius = 0; + } + } + + // Right side: + if (moveDragger.parent) + { + moveDragger.sprites[i].params.enableCornerRounding(); + moveDragger.sprites[i].params.corners_rounding[1].radius = sprites[state].params.corners_rounding[1].radius; + if (IsCollapsed()) + { + moveDragger.sprites[i].params.corners_rounding[3].radius = sprites[state].params.corners_rounding[3].radius; + } + else + { + moveDragger.sprites[i].params.corners_rounding[3].radius = 0; + } + } + else if (label.parent) + { + label.sprites[i].params.enableCornerRounding(); + label.sprites[i].params.corners_rounding[1].radius = sprites[state].params.corners_rounding[1].radius; + if (IsCollapsed()) + { + label.sprites[i].params.corners_rounding[3].radius = sprites[state].params.corners_rounding[3].radius; + } + else + { + label.sprites[i].params.corners_rounding[3].radius = 0; + } + } + + scrollbar_horizontal.sprites[i].params.enableCornerRounding(); + scrollbar_horizontal.sprites[i].params.corners_rounding[3].radius = sprites[state].params.corners_rounding[3].radius; + scrollbar_vertical.sprites[i].params.enableCornerRounding(); + scrollbar_vertical.sprites[i].params.corners_rounding[3].radius = sprites[state].params.corners_rounding[3].radius; + } + } + moveDragger.force_disable = force_disable; - resizeDragger_UpperLeft.force_disable = force_disable; - resizeDragger_UpperRight.force_disable = force_disable; - resizeDragger_BottomLeft.force_disable = force_disable; - resizeDragger_BottomRight.force_disable = force_disable; scrollbar_horizontal.force_disable = force_disable; scrollbar_vertical.force_disable = force_disable; moveDragger.Update(canvas, dt); - resizeDragger_UpperLeft.Update(canvas, dt); - resizeDragger_UpperRight.Update(canvas, dt); - resizeDragger_BottomLeft.Update(canvas, dt); - resizeDragger_BottomRight.Update(canvas, dt); // Don't allow moving outside of screen: if (parent == nullptr) @@ -3032,51 +3306,53 @@ namespace wi::gui ResizeLayout(); - Hitbox2D pointerHitbox = GetPointerHitbox(); - uint32_t priority = 0; - // Compute scrollable area: - float scroll_length_horizontal = 0; - float scroll_length_vertical = 0; - for (auto& widget : widgets) - { - if (!widget->IsVisible()) - continue; - if (widget->parent == &scrollable_area) - { - XMFLOAT2 size = widget->GetSize(); - scroll_length_horizontal = std::max(scroll_length_horizontal, widget->translation_local.x + size.x); - scroll_length_vertical = std::max(scroll_length_vertical, widget->translation_local.y + size.y); - } - } - scrollbar_horizontal.SetListLength(scroll_length_horizontal); - scrollbar_vertical.SetListLength(scroll_length_vertical); - scrollbar_horizontal.Update(canvas, 0); - scrollbar_vertical.Update(canvas, 0); + scrollable_area.scissorRect = scissorRect; + scrollable_area.Detach(); scrollable_area.ClearTransform(); scrollable_area.Translate(translation); - scrollable_area.Translate(XMFLOAT3(scrollbar_horizontal.GetOffset(), control_size + 1 + scrollbar_vertical.GetOffset(), 0)); + + // Compute scrollable area: + if (scrollbar_horizontal.parent != nullptr || scrollbar_vertical.parent != nullptr) + { + float scroll_length_horizontal = 0; + float scroll_length_vertical = 0; + for (auto& widget : widgets) + { + if (!widget->IsVisible()) + continue; + if (widget->parent == &scrollable_area) + { + XMFLOAT2 size = widget->GetSize(); + scroll_length_horizontal = std::max(scroll_length_horizontal, widget->translation_local.x + size.x); + scroll_length_vertical = std::max(scroll_length_vertical, widget->translation_local.y + size.y); + } + } + scrollbar_horizontal.SetListLength(scroll_length_horizontal); + scrollbar_vertical.SetListLength(scroll_length_vertical); + scrollbar_horizontal.Update(canvas, 0); + scrollbar_vertical.Update(canvas, 0); + scrollable_area.Translate(XMFLOAT3(scrollbar_horizontal.GetOffset(), control_size + 1 + scrollbar_vertical.GetOffset(), 0)); + scrollable_area.scissorRect.left += 1; + scrollable_area.scissorRect.top += (int32_t)control_size; + if (scrollbar_horizontal.parent != nullptr && scrollbar_horizontal.IsScrollbarRequired()) + { + scrollable_area.scissorRect.bottom -= (int32_t)control_size + 1; + } + if (scrollbar_vertical.parent != nullptr && scrollbar_vertical.IsScrollbarRequired()) + { + scrollable_area.scissorRect.right -= (int32_t)control_size + 1; + } + scrollable_area.active_area.pos.x = float(scrollable_area.scissorRect.left); + scrollable_area.active_area.pos.y = float(scrollable_area.scissorRect.top); + scrollable_area.active_area.siz.x = float(scrollable_area.scissorRect.right) - float(scrollable_area.scissorRect.left); + scrollable_area.active_area.siz.y = float(scrollable_area.scissorRect.bottom) - float(scrollable_area.scissorRect.top); + } + scrollable_area.AttachTo(this); - scrollable_area.scissorRect = scissorRect; - scrollable_area.scissorRect.left += 1; - scrollable_area.scissorRect.top += (int32_t)control_size; - if (scrollbar_horizontal.parent != nullptr && scrollbar_horizontal.IsScrollbarRequired()) - { - scrollable_area.scissorRect.bottom -= (int32_t)control_size + 1; - } - if (scrollbar_vertical.parent != nullptr && scrollbar_vertical.IsScrollbarRequired()) - { - scrollable_area.scissorRect.right -= (int32_t)control_size + 1; - } - scrollable_area.active_area.pos.x = float(scrollable_area.scissorRect.left); - scrollable_area.active_area.pos.y = float(scrollable_area.scissorRect.top); - scrollable_area.active_area.siz.x = float(scrollable_area.scissorRect.right) - float(scrollable_area.scissorRect.left); - scrollable_area.active_area.siz.y = float(scrollable_area.scissorRect.bottom) - float(scrollable_area.scissorRect.top); - - bool focus = false; for (size_t i = 0; i < widgets.size(); ++i) { Widget* widget = widgets[i]; // re index in loop, because widgets can be realloced while updating! @@ -3177,6 +3453,7 @@ namespace wi::gui } void Window::Render(const wi::Canvas& canvas, CommandList cmd) const { + Widget::Render(canvas, cmd); if (!IsVisible()) { return; @@ -3212,6 +3489,146 @@ namespace wi::gui wi::image::Draw(nullptr, fx, cmd); } + // resize indicator: + if (IsEnabled()) + { + // hitboxes are recomputed because window transform might have changed since update!! + float vscale = IsCollapsed() ? control_size : scale.y; + Hitbox2D lefthitbox; + Hitbox2D righthitbox; + Hitbox2D tophitbox; + Hitbox2D bottomhitbox; + Hitbox2D toplefthitbox; + Hitbox2D toprighthitbox; + Hitbox2D bottomrighthitbox; + Hitbox2D bottomlefthitbox; + if (has_flag(controls, WindowControls::RESIZE_LEFT)) + { + lefthitbox = Hitbox2D(XMFLOAT2(translation.x - resizehitboxwidth, translation.y), XMFLOAT2(resizehitboxwidth, vscale)); + } + if (has_flag(controls, WindowControls::RESIZE_RIGHT)) + { + righthitbox = Hitbox2D(XMFLOAT2(translation.x + scale.x, translation.y), XMFLOAT2(resizehitboxwidth, vscale)); + } + if (!IsCollapsed()) + { + if (has_flag(controls, WindowControls::RESIZE_TOP)) + { + tophitbox = Hitbox2D(XMFLOAT2(translation.x, translation.y - resizehitboxwidth), XMFLOAT2(scale.x, resizehitboxwidth)); + } + if (has_flag(controls, WindowControls::RESIZE_BOTTOM)) + { + bottomhitbox = Hitbox2D(XMFLOAT2(translation.x, translation.y + vscale), XMFLOAT2(scale.x, resizehitboxwidth)); + } + if (has_flag(controls, WindowControls::RESIZE_TOPLEFT)) + { + toplefthitbox = Hitbox2D(XMFLOAT2(translation.x - resizehitboxwidth, translation.y - resizehitboxwidth), XMFLOAT2(resizehitboxwidth * 2, resizehitboxwidth * 2)); + } + if (has_flag(controls, WindowControls::RESIZE_TOPRIGHT)) + { + toprighthitbox = Hitbox2D(XMFLOAT2(translation.x + scale.x - resizehitboxwidth, translation.y - resizehitboxwidth), XMFLOAT2(resizehitboxwidth * 2, resizehitboxwidth * 2)); + } + if (has_flag(controls, WindowControls::RESIZE_BOTTOMRIGHT)) + { + bottomrighthitbox = Hitbox2D(XMFLOAT2(translation.x + scale.x - resizehitboxwidth, translation.y + vscale - resizehitboxwidth), XMFLOAT2(resizehitboxwidth * 2, resizehitboxwidth * 2)); + } + if (has_flag(controls, WindowControls::RESIZE_BOTTOMLEFT)) + { + bottomlefthitbox = Hitbox2D(XMFLOAT2(translation.x - resizehitboxwidth, translation.y + vscale - resizehitboxwidth), XMFLOAT2(resizehitboxwidth * 2, resizehitboxwidth * 2)); + } + } + + const Hitbox2D pointerHitbox = GetPointerHitbox(); + + wi::image::Params fx = sprites[state].params; + fx.blendFlag = wi::enums::BLENDMODE_ALPHA; + fx.pos.x -= resizehitboxwidth; + fx.pos.y -= resizehitboxwidth; + fx.siz.x += resizehitboxwidth * 2; + fx.siz.y += resizehitboxwidth * 2; + fx.color = resize_state == RESIZE_STATE_NONE ? sprites[FOCUS].params.color : sprites[ACTIVE].params.color; + if (IsMinimized()) + { + fx.siz.y = control_size + resizehitboxwidth * 2; + } + if (fx.isCornerRoundingEnabled()) + { + for (auto& corner_rounding : fx.corners_rounding) + { + if (corner_rounding.radius > 0) + { + corner_rounding.radius += resizehitboxwidth; + } + } + } + //fx.border_soften = 0.01f; + + if (resize_state == RESIZE_STATE_TOPLEFT || pointerHitbox.intersects(toplefthitbox)) + { + fx.angular_softness_outer_angle = XM_PI * 0.03f; + fx.angular_softness_inner_angle = XM_PI * wi::math::Lerp(0.0f, 0.025f, std::abs(std::sin(resize_blink_timer * 4))); + XMStoreFloat2(&fx.angular_softness_direction, XMVector2Normalize(XMVectorSet(-1, -1, 0, 0))); + wi::image::Draw(nullptr, fx, cmd); + wi::input::SetCursor(wi::input::CURSOR_RESIZE_NWSE); + } + else if (resize_state == RESIZE_STATE_TOPRIGHT || pointerHitbox.intersects(toprighthitbox)) + { + fx.angular_softness_outer_angle = XM_PI * 0.03f; + fx.angular_softness_inner_angle = XM_PI * wi::math::Lerp(0.0f, 0.025f, std::abs(std::sin(resize_blink_timer * 4))); + XMStoreFloat2(&fx.angular_softness_direction, XMVector2Normalize(XMVectorSet(1, -1, 0, 0))); + wi::image::Draw(nullptr, fx, cmd); + wi::input::SetCursor(wi::input::CURSOR_RESIZE_NESW); + } + else if (resize_state == RESIZE_STATE_BOTTOMRIGHT || pointerHitbox.intersects(bottomrighthitbox)) + { + fx.angular_softness_outer_angle = XM_PI * 0.03f; + fx.angular_softness_inner_angle = XM_PI * wi::math::Lerp(0.0f, 0.025f, std::abs(std::sin(resize_blink_timer * 4))); + XMStoreFloat2(&fx.angular_softness_direction, XMVector2Normalize(XMVectorSet(1, 1, 0, 0))); + wi::image::Draw(nullptr, fx, cmd); + wi::input::SetCursor(wi::input::CURSOR_RESIZE_NWSE); + } + else if (resize_state == RESIZE_STATE_BOTTOMLEFT || pointerHitbox.intersects(bottomlefthitbox)) + { + fx.angular_softness_outer_angle = XM_PI * 0.03f; + fx.angular_softness_inner_angle = XM_PI * wi::math::Lerp(0.0f, 0.025f, std::abs(std::sin(resize_blink_timer * 4))); + XMStoreFloat2(&fx.angular_softness_direction, XMVector2Normalize(XMVectorSet(-1, 1, 0, 0))); + wi::image::Draw(nullptr, fx, cmd); + wi::input::SetCursor(wi::input::CURSOR_RESIZE_NESW); + } + else if (resize_state == RESIZE_STATE_LEFT || pointerHitbox.intersects(lefthitbox)) + { + fx.angular_softness_outer_angle = XM_PI * 0.25f; + fx.angular_softness_inner_angle = XM_PI * wi::math::Lerp(0.0f, 0.24f, std::abs(std::sin(resize_blink_timer * 4))); + fx.angular_softness_direction = XMFLOAT2(-1, 0); + wi::image::Draw(nullptr, fx, cmd); + wi::input::SetCursor(wi::input::CURSOR_RESIZE_EW); + } + else if (resize_state == RESIZE_STATE_RIGHT || pointerHitbox.intersects(righthitbox)) + { + fx.angular_softness_outer_angle = XM_PI * 0.25f; + fx.angular_softness_inner_angle = XM_PI * wi::math::Lerp(0.0f, 0.24f, std::abs(std::sin(resize_blink_timer * 4))); + fx.angular_softness_direction = XMFLOAT2(1, 0); + wi::image::Draw(nullptr, fx, cmd); + wi::input::SetCursor(wi::input::CURSOR_RESIZE_EW); + } + else if (resize_state == RESIZE_STATE_TOP || pointerHitbox.intersects(tophitbox)) + { + fx.angular_softness_outer_angle = XM_PI * 0.25f; + fx.angular_softness_inner_angle = XM_PI * wi::math::Lerp(0.0f, 0.24f, std::abs(std::sin(resize_blink_timer * 4))); + fx.angular_softness_direction = XMFLOAT2(0, -1); + wi::image::Draw(nullptr, fx, cmd); + wi::input::SetCursor(wi::input::CURSOR_RESIZE_NS); + } + else if (resize_state == RESIZE_STATE_BOTTOM || pointerHitbox.intersects(bottomhitbox)) + { + fx.angular_softness_outer_angle = XM_PI * 0.25f; + fx.angular_softness_inner_angle = XM_PI * wi::math::Lerp(0.0f, 0.24f, std::abs(std::sin(resize_blink_timer * 4))); + fx.angular_softness_direction = XMFLOAT2(0, 1); + wi::image::Draw(nullptr, fx, cmd); + wi::input::SetCursor(wi::input::CURSOR_RESIZE_NS); + } + } + // base: if (!IsCollapsed()) { @@ -3232,7 +3649,6 @@ namespace wi::gui widget->Render(canvas, cmd); } - //Rect scissorRect; //scissorRect.bottom = (int32_t)(canvas.GetPhysicalHeight()); //scissorRect.left = (int32_t)(0); @@ -3265,8 +3681,6 @@ namespace wi::gui for (auto& x : widgets) { if ( - x == &resizeDragger_UpperLeft || - x == &resizeDragger_UpperRight || x == &closeButton || x == &collapseButton || x == &moveDragger || @@ -3292,14 +3706,6 @@ namespace wi::gui continue; if (x == &closeButton) continue; - if (x == &resizeDragger_UpperLeft) - continue; - if (x == &resizeDragger_UpperRight) - continue; - if (x == &resizeDragger_BottomLeft) - continue; - if (x == &resizeDragger_BottomRight) - continue; if (x == &scrollbar_horizontal) continue; if (x == &scrollbar_vertical) @@ -3322,8 +3728,6 @@ namespace wi::gui for (auto& x : widgets) { if ( - x == &resizeDragger_UpperLeft || - x == &resizeDragger_UpperRight || x == &closeButton || x == &collapseButton || x == &moveDragger || @@ -3435,14 +3839,6 @@ namespace wi::gui { moveDragger.Detach(); float rem = 0; - if (resizeDragger_UpperLeft.parent != nullptr) - { - rem++; - } - if (resizeDragger_UpperRight.parent != nullptr) - { - rem++; - } if (closeButton.parent != nullptr) { rem++; @@ -3453,10 +3849,6 @@ namespace wi::gui } moveDragger.SetSize(XMFLOAT2(scale.x - control_size * rem, control_size)); float offset = 0; - if (resizeDragger_UpperLeft.parent != nullptr) - { - offset++; - } if (closeButton.parent != nullptr) { offset++; @@ -3473,10 +3865,6 @@ namespace wi::gui closeButton.Detach(); closeButton.SetSize(XMFLOAT2(control_size, control_size)); float offset = 0; - if (resizeDragger_UpperLeft.parent != nullptr) - { - offset++; - } closeButton.SetPos(XMFLOAT2(translation.x + control_size * offset, translation.y)); closeButton.AttachTo(this); } @@ -3489,52 +3877,15 @@ namespace wi::gui { offset++; } - if (resizeDragger_UpperLeft.parent != nullptr) - { - offset++; - } collapseButton.SetPos(XMFLOAT2(translation.x + control_size * offset, translation.y)); collapseButton.AttachTo(this); } - if (resizeDragger_UpperLeft.parent != nullptr) - { - resizeDragger_UpperLeft.Detach(); - resizeDragger_UpperLeft.SetSize(XMFLOAT2(control_size, control_size)); - resizeDragger_UpperLeft.SetPos(XMFLOAT2(translation.x, translation.y)); - resizeDragger_UpperLeft.AttachTo(this); - } - if (resizeDragger_UpperRight.parent != nullptr) - { - resizeDragger_UpperRight.Detach(); - resizeDragger_UpperRight.SetSize(XMFLOAT2(control_size, control_size)); - resizeDragger_UpperRight.SetPos(XMFLOAT2(translation.x + scale.x - control_size, translation.y)); - resizeDragger_UpperRight.AttachTo(this); - } - if (resizeDragger_BottomLeft.parent != nullptr) - { - resizeDragger_BottomLeft.Detach(); - resizeDragger_BottomLeft.SetSize(XMFLOAT2(control_size, control_size)); - resizeDragger_BottomLeft.SetPos(XMFLOAT2(translation.x, translation.y + scale.y - control_size)); - resizeDragger_BottomLeft.AttachTo(this); - } - if (resizeDragger_BottomRight.parent != nullptr) - { - resizeDragger_BottomRight.Detach(); - resizeDragger_BottomRight.SetSize(XMFLOAT2(control_size, control_size)); - resizeDragger_BottomRight.SetPos(XMFLOAT2(translation.x + scale.x - control_size, translation.y + scale.y - control_size)); - resizeDragger_BottomRight.AttachTo(this); - } if (label.parent != nullptr) { label.font.params = font.params; label.Detach(); XMFLOAT2 label_size = XMFLOAT2(scale.x, control_size); XMFLOAT2 label_pos = XMFLOAT2(translation.x, translation.y); - if (resizeDragger_UpperLeft.parent != nullptr) - { - label_size.x -= control_size; - label_pos.x += control_size; - } if (closeButton.parent != nullptr) { label_size.x -= control_size; @@ -3545,10 +3896,6 @@ namespace wi::gui label_size.x -= control_size; label_pos.x += control_size; } - if (resizeDragger_UpperRight.parent != nullptr) - { - label_size.x -= control_size; - } label.SetSize(label_size); label.SetPos(label_pos); label.AttachTo(this); @@ -3556,28 +3903,17 @@ namespace wi::gui if (scrollbar_horizontal.parent != nullptr) { scrollbar_horizontal.Detach(); - float offset = 0; - if (resizeDragger_BottomLeft.parent != nullptr) - { - offset++; - } - scrollbar_horizontal.SetSize(XMFLOAT2(GetWidgetAreaSize().x - control_size * (offset + 1), control_size)); - scrollbar_horizontal.SetPos(XMFLOAT2(translation.x + control_size * offset, translation.y + scale.y - control_size)); + scrollbar_horizontal.SetSize(XMFLOAT2(GetWidgetAreaSize().x - control_size, control_size)); + scrollbar_horizontal.SetPos(XMFLOAT2(translation.x + control_size, translation.y + scale.y - control_size)); scrollbar_horizontal.AttachTo(this); - scrollbar_horizontal.SetSafeArea(scrollbar_horizontal.scale.y); + scrollbar_horizontal.SetSafeArea(control_size * 2); } if (scrollbar_vertical.parent != nullptr) { scrollbar_vertical.Detach(); - float offset = 1; - if (resizeDragger_BottomRight.parent != nullptr) - { - offset++; - } - scrollbar_vertical.SetSize(XMFLOAT2(control_size, GetWidgetAreaSize().y - (control_size + 1) * offset)); - scrollbar_vertical.SetPos(XMFLOAT2(translation.x + scale.x - control_size, translation.y + 1 + control_size)); + scrollbar_vertical.SetSize(XMFLOAT2(control_size, GetWidgetAreaSize().y - control_size)); + scrollbar_vertical.SetPos(XMFLOAT2(translation.x + scale.x - control_size, translation.y + control_size)); scrollbar_vertical.AttachTo(this); - scrollbar_vertical.SetSafeArea(scrollbar_vertical.scale.x); } if (onResize) @@ -4493,7 +4829,9 @@ namespace wi::gui Hitbox2D TreeList::GetHitbox_ItemOpener(int visible_count, int level) const { XMFLOAT2 pos = XMFLOAT2(translation.x + 2 + level * item_height(), translation.y + GetItemOffset(visible_count) + item_height() * 0.5f); - return Hitbox2D(XMFLOAT2(pos.x, pos.y - item_height() * 0.25f), XMFLOAT2(item_height() * 0.5f, item_height() * 0.5f)); + Hitbox2D hb = Hitbox2D(XMFLOAT2(pos.x, pos.y - item_height() * 0.25f), XMFLOAT2(item_height() * 0.5f, item_height() * 0.5f)); + HitboxConstrain(hb); + return hb; } bool TreeList::HasScrollbar() const { @@ -4508,6 +4846,71 @@ namespace wi::gui Widget::Update(canvas, dt); + // Resizer updates: + if (IsEnabled()) + { + Hitbox2D pointerHitbox = GetPointerHitbox(false); + + float vscale = scale.y; + Hitbox2D bottomhitbox = Hitbox2D(XMFLOAT2(translation.x, translation.y + vscale), XMFLOAT2(scale.x, resizehitboxwidth)); + + if (resize_state == RESIZE_STATE_NONE && wi::input::Press(wi::input::MOUSE_BUTTON_LEFT)) + { + if (pointerHitbox.intersects(bottomhitbox)) + { + resize_state = RESIZE_STATE_BOTTOM; + Activate(); + } + resize_begin = pointerHitbox.pos; + } + if (wi::input::Down(wi::input::MOUSE_BUTTON_LEFT)) + { + if (resize_state != RESIZE_STATE_NONE) + { + auto saved_parent = this->parent; + this->Detach(); + float deltaX = pointerHitbox.pos.x - resize_begin.x; + float deltaY = pointerHitbox.pos.y - resize_begin.y; + + switch (resize_state) + { + case RESIZE_STATE_BOTTOM: + this->Scale(XMFLOAT3(1, (scale.y + deltaY) / scale.y, 1)); + break; + default: + break; + } + + this->scale_local = wi::math::Max(this->scale_local, XMFLOAT3(item_height() * 3, item_height() * 3, 1)); // don't allow resize to negative or too small + this->AttachTo(saved_parent); + resize_begin = pointerHitbox.pos; + } + } + else + { + resize_state = RESIZE_STATE_NONE; + } + + if ( + resize_state != RESIZE_STATE_NONE || + pointerHitbox.intersects(bottomhitbox) + ) + { + resize_blink_timer += dt; + } + else + { + resize_blink_timer = 0; + } + } + + active_area.pos.x = float(scissorRect.left); + active_area.pos.y = float(scissorRect.top); + active_area.siz.x = float(scissorRect.right) - float(scissorRect.left); + active_area.siz.y = float(scissorRect.bottom) - float(scissorRect.top); + + Hitbox2D pointerHitbox = GetPointerHitbox(); + // compute control-list height float scroll_length = 0; { @@ -4551,7 +4954,6 @@ namespace wi::gui } Hitbox2D hitbox = Hitbox2D(XMFLOAT2(translation.x, translation.y), XMFLOAT2(scale.x, scale.y)); - Hitbox2D pointerHitbox = GetPointerHitbox(); if (state == IDLE && hitbox.intersects(pointerHitbox)) { @@ -4650,12 +5052,23 @@ namespace wi::gui SetTooltip(item.name); if (clicked) { - if (!wi::input::Down(wi::input::KEYBOARD_BUTTON_LCONTROL) && !wi::input::Down(wi::input::KEYBOARD_BUTTON_RCONTROL) - && !wi::input::Down(wi::input::KEYBOARD_BUTTON_LSHIFT) && !wi::input::Down(wi::input::KEYBOARD_BUTTON_RSHIFT)) + if (wi::input::IsDoubleClicked() && onDoubleClick != nullptr) { - ClearSelection(); + EventArgs args; + args.iValue = i; + args.sValue = items[i].name; + args.userdata = items[i].userdata; + onDoubleClick(args); + } + else + { + if (!wi::input::Down(wi::input::KEYBOARD_BUTTON_LCONTROL) && !wi::input::Down(wi::input::KEYBOARD_BUTTON_RCONTROL) + && !wi::input::Down(wi::input::KEYBOARD_BUTTON_LSHIFT) && !wi::input::Down(wi::input::KEYBOARD_BUTTON_RSHIFT)) + { + ClearSelection(); + } + Select(i); } - Select(i); Activate(); } } @@ -4670,6 +5083,7 @@ namespace wi::gui } void TreeList::Render(const wi::Canvas& canvas, CommandList cmd) const { + Widget::Render(canvas, cmd); if (!IsVisible()) { return; @@ -4698,6 +5112,44 @@ namespace wi::gui wi::image::Draw(nullptr, fx, cmd); } + // resize indicator: + if (IsEnabled()) + { + // hitboxes are recomputed because window transform might have changed since update!! + float vscale = scale.y; + Hitbox2D bottomhitbox = Hitbox2D(XMFLOAT2(translation.x, translation.y + vscale), XMFLOAT2(scale.x, resizehitboxwidth)); + + const Hitbox2D pointerHitbox = GetPointerHitbox(false); + + wi::image::Params fx = sprites[state].params; + fx.blendFlag = wi::enums::BLENDMODE_ALPHA; + fx.pos.x -= resizehitboxwidth; + fx.pos.y -= resizehitboxwidth; + fx.siz.x += resizehitboxwidth * 2; + fx.siz.y = scale.y + resizehitboxwidth * 2; + fx.color = resize_state == RESIZE_STATE_NONE ? sprites[FOCUS].params.color : sprites[ACTIVE].params.color; + if (fx.isCornerRoundingEnabled()) + { + for (auto& corner_rounding : fx.corners_rounding) + { + if (corner_rounding.radius > 0) + { + corner_rounding.radius += resizehitboxwidth; + } + } + } + //fx.border_soften = 0.01f; + + if (resize_state == RESIZE_STATE_BOTTOM || pointerHitbox.intersects(bottomhitbox)) + { + fx.angular_softness_outer_angle = XM_PI * 0.25f; + fx.angular_softness_inner_angle = XM_PI * wi::math::Lerp(0.0f, 0.24f, std::abs(std::sin(resize_blink_timer * 4))); + fx.angular_softness_direction = XMFLOAT2(0, 1); + wi::image::Draw(nullptr, fx, cmd); + wi::input::SetCursor(wi::input::CURSOR_RESIZE_NS); + } + } + // control-base sprites[state].Draw(cmd); @@ -4821,6 +5273,10 @@ namespace wi::gui { onDelete = func; } + void TreeList::OnDoubleClick(std::function func) + { + onDoubleClick = func; + } void TreeList::AddItem(const Item& item) { items.push_back(item); diff --git a/WickedEngine/wiGUI.h b/WickedEngine/wiGUI.h index 3b9627a16..3840a4fe4 100644 --- a/WickedEngine/wiGUI.h +++ b/WickedEngine/wiGUI.h @@ -264,6 +264,9 @@ namespace wi::gui mutable wi::Sprite tooltipSprite; mutable wi::SpriteFont tooltipFont; mutable wi::SpriteFont scripttipFont; + float angular_highlight_width = 0; + float angular_highlight_timer = 0; + XMFLOAT4 angular_highlight_color = XMFLOAT4(1, 1, 1, 1); public: Widget(); @@ -295,7 +298,7 @@ namespace wi::gui virtual void ResizeLayout() {}; virtual void Update(const wi::Canvas& canvas, float dt); - virtual void Render(const wi::Canvas& canvas, wi::graphics::CommandList cmd) const {} + virtual void Render(const wi::Canvas& canvas, wi::graphics::CommandList cmd) const; virtual void RenderTooltip(const wi::Canvas& canvas, wi::graphics::CommandList cmd) const; // last param default: set color for all states @@ -338,6 +341,11 @@ namespace wi::gui void SetLocalizationEnabled(bool value) { localization_enabled = value ? LocalizationEnabled::All : LocalizationEnabled::None; } virtual void ExportLocalization(wi::Localization& localization) const; virtual void ImportLocalization(const wi::Localization& localization); + + void SetAngularHighlightWidth(float value) { angular_highlight_width = value; }; + float GetAngularHighlightWidth() const { return angular_highlight_width; }; + void SetAngularHighlightColor(const XMFLOAT4& value) { angular_highlight_color = value; }; + XMFLOAT4 GetAngularHighlightColor() const { return angular_highlight_color; }; }; // Clickable, draggable box @@ -396,7 +404,7 @@ namespace wi::gui // 1: full extra offset void SetOverScroll(float amount) { overscroll = amount; } // Check whether the scrollbar is required (when the items don't fit and scrolling could be used) - bool IsScrollbarRequired() const { return scrollbar_granularity < 0.999f; } + bool IsScrollbarRequired() const { return scrollbar_granularity < 1; } void SetSafeArea(float value) { safe_area = value; } enum SCROLLBAR_STATE @@ -423,6 +431,7 @@ namespace wi::gui class Label : public Widget { protected: + bool wrap_enabled = true; public: void Create(const std::string& name); @@ -434,6 +443,8 @@ namespace wi::gui float scrollbar_width = 18; ScrollBar scrollbar; + + void SetWrapEnabled(bool value) { wrap_enabled = value; } }; // Text input box @@ -547,6 +558,8 @@ namespace wi::gui int selected = -1; int maxVisibleItemCount = 8; int firstItemVisible = 0; + bool drop_arrow = true; + float fixed_drop_width = 0; // 0 = not fixed, takes width from base scale // While the widget is active (rolled down) these are the inner states that control behaviour enum COMBOSTATE @@ -573,6 +586,7 @@ namespace wi::gui std::wstring invalid_selection_text; float GetDropOffset(const wi::Canvas& canvas) const; + float GetDropX(const wi::Canvas& canvas) const; float GetItemOffset(const wi::Canvas& canvas, int index) const; public: void Create(const std::string& name); @@ -608,6 +622,11 @@ namespace wi::gui void ExportLocalization(wi::Localization& localization) const override; void ImportLocalization(const wi::Localization& localization) override; + + void SetDropArrowEnabled(bool value) { drop_arrow = value; } + bool IsDropArrowEnabled() const { return drop_arrow; } + void SetFixedDropWidth(float value) { fixed_drop_width = value; } + float GetFixedDropWidth() const { return fixed_drop_width; } }; // Widget container @@ -622,19 +641,41 @@ namespace wi::gui std::function onCollapse; std::function onResize; + float resizehitboxwidth = 6; + enum RESIZE_STATE + { + RESIZE_STATE_NONE, + + RESIZE_STATE_LEFT, + RESIZE_STATE_TOP, + RESIZE_STATE_RIGHT, + RESIZE_STATE_BOTTOM, + + RESIZE_STATE_TOPLEFT, + RESIZE_STATE_TOPRIGHT, + RESIZE_STATE_BOTTOMRIGHT, + RESIZE_STATE_BOTTOMLEFT, + } resize_state = RESIZE_STATE_NONE; + XMFLOAT2 resize_begin = XMFLOAT2(0, 0); + float resize_blink_timer = 0; + public: enum class WindowControls { NONE = 0, - RESIZE_TOPLEFT = 1 << 0, - RESIZE_TOPRIGHT = 1 << 1, - RESIZE_BOTTOMLEFT = 1 << 2, - RESIZE_BOTTOMRIGHT = 1 << 3, - MOVE = 1 << 4, - CLOSE = 1 << 5, - COLLAPSE = 1 << 6, + RESIZE_LEFT = 1 << 0, + RESIZE_TOP = 1 << 1, + RESIZE_RIGHT = 1 << 2, + RESIZE_BOTTOM = 1 << 3, + RESIZE_TOPLEFT = 1 << 4, + RESIZE_TOPRIGHT = 1 << 5, + RESIZE_BOTTOMLEFT = 1 << 6, + RESIZE_BOTTOMRIGHT = 1 << 7, + MOVE = 1 << 8, + CLOSE = 1 << 9, + COLLAPSE = 1 << 10, - RESIZE = RESIZE_TOPLEFT | RESIZE_TOPRIGHT | RESIZE_BOTTOMLEFT | RESIZE_BOTTOMRIGHT, + RESIZE = RESIZE_LEFT | RESIZE_TOP | RESIZE_RIGHT | RESIZE_BOTTOM | RESIZE_TOPLEFT | RESIZE_TOPRIGHT | RESIZE_BOTTOMLEFT | RESIZE_BOTTOMRIGHT, CLOSE_AND_COLLAPSE = CLOSE | COLLAPSE, ALL = RESIZE | MOVE | CLOSE | COLLAPSE, }; @@ -675,14 +716,11 @@ namespace wi::gui Button closeButton; Button collapseButton; - Button resizeDragger_UpperLeft; - Button resizeDragger_UpperRight; - Button resizeDragger_BottomLeft; - Button resizeDragger_BottomRight; Button moveDragger; Label label; ScrollBar scrollbar_vertical; ScrollBar scrollbar_horizontal; + WindowControls controls; void ExportLocalization(wi::Localization& localization) const override; void ImportLocalization(const wi::Localization& localization) override; @@ -742,6 +780,7 @@ namespace wi::gui protected: std::function onSelect; std::function onDelete; + std::function onDoubleClick; int item_highlight = -1; int opener_highlight = -1; @@ -753,6 +792,16 @@ namespace wi::gui float GetItemOffset(int index) const; bool DoesItemHaveChildren(int index) const; + + float resizehitboxwidth = 6; + enum RESIZE_STATE + { + RESIZE_STATE_NONE, + RESIZE_STATE_BOTTOM, + } resize_state = RESIZE_STATE_NONE; + XMFLOAT2 resize_begin = XMFLOAT2(0, 0); + float resize_blink_timer = 0; + public: void Create(const std::string& name); @@ -775,6 +824,7 @@ namespace wi::gui void OnSelect(std::function func); void OnDelete(std::function func); + void OnDoubleClick(std::function func); ScrollBar scrollbar; }; diff --git a/WickedEngine/wiGraphics.h b/WickedEngine/wiGraphics.h index 0d41536a0..1ef6e0746 100644 --- a/WickedEngine/wiGraphics.h +++ b/WickedEngine/wiGraphics.h @@ -769,6 +769,14 @@ namespace wi::graphics int32_t top = 0; int32_t right = 0; int32_t bottom = 0; + + constexpr void from_viewport(const Viewport& vp) + { + left = int32_t(vp.top_left_x); + right = int32_t(vp.top_left_x + vp.width); + top = int32_t(vp.top_left_y); + bottom = int32_t(vp.top_left_y + vp.height); + } }; struct Box diff --git a/WickedEngine/wiGraphicsDevice_Vulkan.cpp b/WickedEngine/wiGraphicsDevice_Vulkan.cpp index daa2ed40e..e68f4f0d0 100644 --- a/WickedEngine/wiGraphicsDevice_Vulkan.cpp +++ b/WickedEngine/wiGraphicsDevice_Vulkan.cpp @@ -1173,10 +1173,7 @@ namespace vulkan_internal // the color space change will not be applied res = vkDeviceWaitIdle(device); assert(res == VK_SUCCESS); - { - std::scoped_lock lock(allocationhandler->destroylocker); - allocationhandler->destroyer_swapchains.emplace_back(internal_state->swapChain, allocationhandler->framecount); - } + vkDestroySwapchainKHR(device, internal_state->swapChain, nullptr); internal_state->swapChain = nullptr; } } diff --git a/WickedEngine/wiImage.cpp b/WickedEngine/wiImage.cpp index 578c9a36a..5d547e898 100644 --- a/WickedEngine/wiImage.cpp +++ b/WickedEngine/wiImage.cpp @@ -114,6 +114,18 @@ namespace wi::image image.packed_color.x = uint(packed_color.v); image.packed_color.y = uint(packed_color.v >> 32ull); + if (params.angular_softness_outer_angle > 0) + { + const float innerConeAngleCos = std::cos(params.angular_softness_inner_angle); + const float outerConeAngleCos = std::cos(params.angular_softness_outer_angle); + // https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_lights_punctual#inner-and-outer-cone-angles + const float lightAngleScale = 1.0f / std::max(0.001f, innerConeAngleCos - outerConeAngleCos); + const float lightAngleOffset = -outerConeAngleCos * lightAngleScale; + image.angular_softness_direction = params.angular_softness_direction; + image.angular_softness_scale = lightAngleScale; + image.angular_softness_offset = lightAngleOffset; + } + image.flags = 0; if (params.isExtractNormalMapEnabled()) { @@ -132,6 +144,14 @@ namespace wi::image { image.flags |= IMAGE_FLAG_FULLSCREEN; } + if (params.isAngularSoftnessDoubleSided()) + { + image.flags |= IMAGE_FLAG_ANGULAR_DOUBLESIDED; + } + if (params.isAngularSoftnessInverse()) + { + image.flags |= IMAGE_FLAG_ANGULAR_INVERSE; + } image.border_soften = params.border_soften; image.mask_alpha_range = XMConvertFloatToHalf(params.mask_alpha_range_start) | (XMConvertFloatToHalf(params.mask_alpha_range_end) << 16u); diff --git a/WickedEngine/wiImage.h b/WickedEngine/wiImage.h index 342a390a8..92809a024 100644 --- a/WickedEngine/wiImage.h +++ b/WickedEngine/wiImage.h @@ -4,6 +4,7 @@ #include "wiEnums.h" #include "wiColor.h" #include "wiCanvas.h" +#include "wiPrimitive.h" namespace wi::image { @@ -57,6 +58,8 @@ namespace wi::image OUTPUT_COLOR_SPACE_LINEAR = 1 << 7, CORNER_ROUNDING = 1 << 8, DEPTH_TEST = 1 << 9, + ANGULAR_DOUBLESIDED = 1 << 10, + ANGULAR_INVERSE = 1 << 11, }; uint32_t _flags = EMPTY; @@ -76,6 +79,9 @@ namespace wi::image float hdr_scaling = 1.0f; // a scaling value for use by linear output mapping float mask_alpha_range_start = 0; // constrain mask alpha to not go below this level float mask_alpha_range_end = 1; // constrain mask alpha to not go above this level + XMFLOAT2 angular_softness_direction = XMFLOAT2(0, 1); + float angular_softness_inner_angle = 0; + float angular_softness_outer_angle = 0; // you can deform the image by its corners (0: top left, 1: top right, 2: bottom left, 3: bottom right) XMFLOAT2 corners[4] = { @@ -117,6 +123,8 @@ namespace wi::image constexpr bool isLinearOutputMappingEnabled() const { return _flags & OUTPUT_COLOR_SPACE_LINEAR; } constexpr bool isCornerRoundingEnabled() const { return _flags & CORNER_ROUNDING; } constexpr bool isDepthTestEnabled() const { return _flags & DEPTH_TEST; } + constexpr bool isAngularSoftnessDoubleSided() const { return _flags & ANGULAR_DOUBLESIDED; } + constexpr bool isAngularSoftnessInverse() const { return _flags & ANGULAR_INVERSE; } // enables draw rectangle for base texture (cutout texture outside draw rectangle) constexpr void enableDrawRect(const XMFLOAT4& rect) { _flags |= DRAWRECT; drawRect = rect; } @@ -137,6 +145,8 @@ namespace wi::image constexpr void enableLinearOutputMapping(float scaling = 1.0f) { _flags |= OUTPUT_COLOR_SPACE_LINEAR; hdr_scaling = scaling; } constexpr void enableCornerRounding() { _flags |= CORNER_ROUNDING; } constexpr void enableDepthTest() { _flags |= DEPTH_TEST; } + constexpr void enableAngularSoftnessDoubleSided() { _flags |= ANGULAR_DOUBLESIDED; } + constexpr void enableAngularSoftnessInverse() { _flags |= ANGULAR_INVERSE; } // disable draw rectangle for base texture (whole texture will be drawn, no cutout) constexpr void disableDrawRect() { _flags &= ~DRAWRECT; } @@ -150,6 +160,8 @@ namespace wi::image constexpr void disableLinearOutputMapping() { _flags &= ~OUTPUT_COLOR_SPACE_LINEAR; } constexpr void disableCornerRounding() { _flags &= ~CORNER_ROUNDING; } constexpr void disableDepthTest() { _flags &= ~DEPTH_TEST; } + constexpr void disableAngularSoftnessDoubleSided() { _flags &= ~ANGULAR_DOUBLESIDED; } + constexpr void disableAngularSoftnessInverse() { _flags &= ~ANGULAR_INVERSE; } Params() = default; @@ -185,6 +197,14 @@ namespace wi::image enableBackground(); } } + + Params( + const wi::primitive::Hitbox2D& hitbox, const XMFLOAT4& color = XMFLOAT4(1, 1, 1, 1) + ) : + pos(XMFLOAT3(hitbox.pos.x, hitbox.pos.y, 0)), + siz(hitbox.siz), + color(color) + {} }; diff --git a/WickedEngine/wiInput.cpp b/WickedEngine/wiInput.cpp index c93930f1d..c18060ddd 100644 --- a/WickedEngine/wiInput.cpp +++ b/WickedEngine/wiInput.cpp @@ -50,6 +50,11 @@ namespace wi::input MouseState mouse; Pen pen; bool pen_override = false; + bool double_click = false; + wi::Timer doubleclick_timer; + XMFLOAT2 doubleclick_prevpos = XMFLOAT2(0, 0); + CURSOR cursor_current = CURSOR_DEFAULT; + CURSOR cursor_next = CURSOR_DEFAULT; const KeyboardState& GetKeyboardState() { return keyboard; } const MouseState& GetMouseState() { return mouse; } @@ -429,6 +434,55 @@ namespace wi::input } } + double_click = false; + if (Press(MOUSE_BUTTON_LEFT)) + { + XMFLOAT2 pos = mouse.position; + double elapsed = doubleclick_timer.record_elapsed_seconds(); + if (elapsed < 0.5 && wi::math::Distance(doubleclick_prevpos, pos) < 5) + { + double_click = true; + } + doubleclick_prevpos = pos; + } + + // Cursor update: + if(cursor_next != cursor_current || cursor_next != CURSOR_DEFAULT) + { +#ifdef PLATFORM_WINDOWS_DESKTOP + static HCURSOR cursor_table[] = { + ::LoadCursor(nullptr, IDC_ARROW), + ::LoadCursor(nullptr, IDC_IBEAM), + ::LoadCursor(nullptr, IDC_SIZEALL), + ::LoadCursor(nullptr, IDC_SIZENS), + ::LoadCursor(nullptr, IDC_SIZEWE), + ::LoadCursor(nullptr, IDC_SIZENESW), + ::LoadCursor(nullptr, IDC_SIZENWSE), + ::LoadCursor(nullptr, IDC_HAND), + ::LoadCursor(nullptr, IDC_NO) + }; + ::SetCursor(cursor_table[cursor_next]); +#endif // PLATFORM_WINDOWS_DESKTOP + +#ifdef SDL2 + static SDL_Cursor* cursor_table[] = { + SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW), + SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_IBEAM), + SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEALL), + SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENS), + SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEWE), + SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENESW), + SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENWSE), + SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_HAND), + SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_NO), + }; + SDL_SetCursor(cursor_table[cursor_next] ? cursor_table[cursor_next] : cursor_table[CURSOR_DEFAULT]); +#endif // SDL2 + + cursor_current = cursor_next; + } + cursor_next = CURSOR_DEFAULT; + wi::profiler::EndRange(range); } @@ -749,6 +803,11 @@ namespace wi::input #endif // _WIN32 } + bool IsDoubleClicked() + { + return double_click; + } + XMFLOAT4 GetAnalog(GAMEPAD_ANALOG analog, int playerindex) { if (playerindex < (int)controllers.size()) @@ -805,4 +864,9 @@ namespace wi::input return touches; } + void SetCursor(CURSOR cursor) + { + cursor_next = cursor; + } + } diff --git a/WickedEngine/wiInput.h b/WickedEngine/wiInput.h index e99fb22c5..228f0d1a5 100644 --- a/WickedEngine/wiInput.h +++ b/WickedEngine/wiInput.h @@ -181,6 +181,9 @@ namespace wi::input // send various feedback to the controller void SetControllerFeedback(const ControllerFeedback& data, int playerindex = 0); + // Check if left mouse button was double clicked in the current frame: + bool IsDoubleClicked(); + struct Pen { XMFLOAT2 position = {}; @@ -203,5 +206,19 @@ namespace wi::input }; const wi::vector& GetTouches(); + enum CURSOR + { + CURSOR_DEFAULT, + CURSOR_TEXTINPUT, + CURSOR_RESIZEALL, + CURSOR_RESIZE_NS, + CURSOR_RESIZE_EW, + CURSOR_RESIZE_NESW, + CURSOR_RESIZE_NWSE, + CURSOR_HAND, + CURSOR_NOTALLOWED, + }; + void SetCursor(CURSOR cursor); + }; diff --git a/WickedEngine/wiJobSystem.cpp b/WickedEngine/wiJobSystem.cpp index 32592d6a2..5b93c0be4 100644 --- a/WickedEngine/wiJobSystem.cpp +++ b/WickedEngine/wiJobSystem.cpp @@ -62,12 +62,12 @@ namespace wi::jobsystem { uint32_t numCores = 0; uint32_t numThreads = 0; - std::unique_ptr jobQueuePerThread; + std::unique_ptr jobQueuePerThread[int(Priority::Count)]; std::atomic_bool alive{ true }; std::condition_variable wakeCondition; std::mutex wakeMutex; std::atomic nextQueue{ 0 }; - wi::vector threads; + wi::vector threads[int(Priority::Count)]; void ShutDown() { alive.store(false); // indicate that new jobs cannot be started from this point @@ -78,14 +78,20 @@ namespace wi::jobsystem wakeCondition.notify_all(); // wakes up sleeping worker threads } }); - for (auto& thread : threads) + for (auto& thread : threads[int(Priority::High)]) + { + thread.join(); + } + for (auto& thread : threads[int(Priority::Low)]) { thread.join(); } wake_loop = false; waker.join(); - jobQueuePerThread.reset(); - threads.clear(); + jobQueuePerThread[int(Priority::High)].reset(); + jobQueuePerThread[int(Priority::Low)].reset(); + threads[int(Priority::High)].clear(); + threads[int(Priority::Low)].clear(); numCores = 0; numThreads = 0; } @@ -97,12 +103,12 @@ namespace wi::jobsystem // Start working on a job queue // After the job queue is finished, it can switch to an other queue and steal jobs from there - inline void work(uint32_t startingQueue) + inline void work(uint32_t startingQueue, Priority priority) { Job job; for (uint32_t i = 0; i < internal_state.numThreads; ++i) { - JobQueue& job_queue = internal_state.jobQueuePerThread[startingQueue % internal_state.numThreads]; + JobQueue& job_queue = internal_state.jobQueuePerThread[int(priority)][startingQueue % internal_state.numThreads]; while (job_queue.pop_front(job)) { JobArgs args; @@ -146,65 +152,95 @@ namespace wi::jobsystem // Calculate the actual number of worker threads we want (-1 main thread): internal_state.numThreads = std::min(maxThreadCount, std::max(1u, internal_state.numCores - 1)); - internal_state.jobQueuePerThread.reset(new JobQueue[internal_state.numThreads]); - internal_state.threads.reserve(internal_state.numThreads); + internal_state.jobQueuePerThread[int(Priority::High)].reset(new JobQueue[internal_state.numThreads]); + internal_state.jobQueuePerThread[int(Priority::Low)].reset(new JobQueue[internal_state.numThreads]); + internal_state.threads[int(Priority::High)].reserve(internal_state.numThreads); + internal_state.threads[int(Priority::Low)].reserve(internal_state.numThreads); for (uint32_t threadID = 0; threadID < internal_state.numThreads; ++threadID) { - internal_state.threads.emplace_back([threadID] { + for (int prio = 0; prio < int(Priority::Count); ++prio) + { + const Priority priority = (Priority)prio; + internal_state.threads[prio].emplace_back([threadID, priority] { - while (internal_state.alive.load()) - { - work(threadID); + while (internal_state.alive.load()) + { + work(threadID, priority); - // finished with jobs, put to sleep - std::unique_lock lock(internal_state.wakeMutex); - internal_state.wakeCondition.wait(lock); - } + // finished with jobs, put to sleep + std::unique_lock lock(internal_state.wakeMutex); + internal_state.wakeCondition.wait(lock); + } - }); - std::thread& worker = internal_state.threads.back(); + }); + std::thread& worker = internal_state.threads[prio].back(); #ifdef _WIN32 - // Do Windows-specific thread setup: - HANDLE handle = (HANDLE)worker.native_handle(); + // Do Windows-specific thread setup: + HANDLE handle = (HANDLE)worker.native_handle(); - // Put each thread on to dedicated core: - DWORD_PTR affinityMask = 1ull << threadID; - DWORD_PTR affinity_result = SetThreadAffinityMask(handle, affinityMask); - assert(affinity_result > 0); + // Put each thread on to dedicated core: + DWORD_PTR affinityMask = 1ull << threadID; + DWORD_PTR affinity_result = SetThreadAffinityMask(handle, affinityMask); + assert(affinity_result > 0); - //// Increase thread priority: - //BOOL priority_result = SetThreadPriority(handle, THREAD_PRIORITY_HIGHEST); - //assert(priority_result != 0); + if (priority == Priority::High) + { + BOOL priority_result = SetThreadPriority(handle, THREAD_PRIORITY_NORMAL); + assert(priority_result != 0); + + std::wstring wthreadname = L"wi::jobsystem_" + std::to_wstring(threadID); + HRESULT hr = SetThreadDescription(handle, wthreadname.c_str()); + assert(SUCCEEDED(hr)); + } + else + { + BOOL priority_result = SetThreadPriority(handle, THREAD_PRIORITY_LOWEST); + assert(priority_result != 0); + + std::wstring wthreadname = L"wi::jobsystem_lowprio_" + std::to_wstring(threadID); + HRESULT hr = SetThreadDescription(handle, wthreadname.c_str()); + assert(SUCCEEDED(hr)); + } - // Name the thread: - std::wstring wthreadname = L"wi::jobsystem_" + std::to_wstring(threadID); - HRESULT hr = SetThreadDescription(handle, wthreadname.c_str()); - assert(SUCCEEDED(hr)); #elif defined(PLATFORM_LINUX) #define handle_error_en(en, msg) \ do { errno = en; perror(msg); } while (0) - int ret; - cpu_set_t cpuset; - CPU_ZERO(&cpuset); - size_t cpusetsize = sizeof(cpuset); + int ret; + cpu_set_t cpuset; + CPU_ZERO(&cpuset); + size_t cpusetsize = sizeof(cpuset); - CPU_SET(threadID, &cpuset); - ret = pthread_setaffinity_np(worker.native_handle(), cpusetsize, &cpuset); - if (ret != 0) - handle_error_en(ret, std::string(" pthread_setaffinity_np[" + std::to_string(threadID) + ']').c_str()); + CPU_SET(threadID, &cpuset); + ret = pthread_setaffinity_np(worker.native_handle(), cpusetsize, &cpuset); + if (ret != 0) + handle_error_en(ret, std::string(" pthread_setaffinity_np[" + std::to_string(threadID) + ']').c_str()); + + + if (priority == Priority::High) + { + std::string thread_name = "wi::job::" + std::to_string(threadID); + ret = pthread_setname_np(worker.native_handle(), thread_name.c_str()); + if (ret != 0) + handle_error_en(ret, std::string(" pthread_setname_np[" + std::to_string(threadID) + ']').c_str()); + } + else + { + // TODO: set lower priority + + std::string thread_name = "wi::job_low::" + std::to_string(threadID); + ret = pthread_setname_np(worker.native_handle(), thread_name.c_str()); + if (ret != 0) + handle_error_en(ret, std::string(" pthread_setname_np[" + std::to_string(threadID) + ']').c_str()); + } - // Name the thread - std::string thread_name = "wi::job::" + std::to_string(threadID); - ret = pthread_setname_np(worker.native_handle(), thread_name.c_str()); - if (ret != 0) - handle_error_en(ret, std::string(" pthread_setname_np[" + std::to_string(threadID) + ']').c_str()); #undef handle_error_en #elif defined(PLATFORM_PS5) - wi::jobsystem::ps5::SetupWorker(worker, threadID); + wi::jobsystem::ps5::SetupWorker(worker, threadID); #endif // _WIN32 + } } wi::backlog::post("wi::jobsystem Initialized with [" + std::to_string(internal_state.numCores) + " cores] [" + std::to_string(internal_state.numThreads) + " threads] (" + std::to_string((int)std::round(timer.elapsed())) + " ms)"); @@ -233,7 +269,7 @@ namespace wi::jobsystem job.groupJobEnd = 1; job.sharedmemory_size = 0; - internal_state.jobQueuePerThread[internal_state.nextQueue.fetch_add(1) % internal_state.numThreads].push_back(job); + internal_state.jobQueuePerThread[int(ctx.priority)][internal_state.nextQueue.fetch_add(1) % internal_state.numThreads].push_back(job); internal_state.wakeCondition.notify_one(); } @@ -261,7 +297,7 @@ namespace wi::jobsystem job.groupJobOffset = groupID * groupSize; job.groupJobEnd = std::min(job.groupJobOffset + groupSize, jobCount); - internal_state.jobQueuePerThread[internal_state.nextQueue.fetch_add(1) % internal_state.numThreads].push_back(job); + internal_state.jobQueuePerThread[int(ctx.priority)][internal_state.nextQueue.fetch_add(1) % internal_state.numThreads].push_back(job); } internal_state.wakeCondition.notify_all(); @@ -287,7 +323,7 @@ namespace wi::jobsystem internal_state.wakeCondition.notify_all(); // work() will pick up any jobs that are on stand by and execute them on this thread: - work(internal_state.nextQueue.fetch_add(1) % internal_state.numThreads); + work(internal_state.nextQueue.fetch_add(1) % internal_state.numThreads, ctx.priority); while (IsBusy(ctx)) { diff --git a/WickedEngine/wiJobSystem.h b/WickedEngine/wiJobSystem.h index 291df5b69..aa35eb2a9 100644 --- a/WickedEngine/wiJobSystem.h +++ b/WickedEngine/wiJobSystem.h @@ -20,10 +20,18 @@ namespace wi::jobsystem uint32_t GetThreadCount(); + enum class Priority + { + High, // Default + Low, // Use this when you need the results after a few frames, not blocking high priority tasks + Count + }; + // Defines a state of execution, can be waited on struct context { std::atomic counter{ 0 }; + Priority priority = Priority::High; }; // Add a task to execute asynchronously. Any idle thread will execute this. diff --git a/WickedEngine/wiRenderPath3D.cpp b/WickedEngine/wiRenderPath3D.cpp index bdd1bbddd..d2876e550 100644 --- a/WickedEngine/wiRenderPath3D.cpp +++ b/WickedEngine/wiRenderPath3D.cpp @@ -1635,11 +1635,6 @@ namespace wi { GraphicsDevice* device = wi::graphics::GetDevice(); - // Set scissor on Compose, because some post processes don't handle scissoring (eg. Bloom) and those should be cut off: - // Note that on expensive render operations we also used scissor to avoid wasted processing - Rect scissor = GetScissorNativeResolution(); - device->BindScissorRects(1, &scissor, cmd); - wi::image::Params fx; fx.blendFlag = BLENDMODE_OPAQUE; fx.quality = wi::image::QUALITY_LINEAR; @@ -1660,13 +1655,6 @@ namespace wi wi::image::Draw(&debugUAV, fx, cmd); } - // Restore full resolution scissor: - scissor.left = 0; - scissor.top = 0; - scissor.right = GetPhysicalWidth(); - scissor.bottom = GetPhysicalHeight(); - device->BindScissorRects(1, &scissor, cmd); - RenderPath2D::Compose(cmd); } @@ -2346,6 +2334,9 @@ namespace wi { ao = value; + if (!rtParticleDistortion.IsValid()) + return; // ResizeBuffers hasn't been called yet + rtAO = {}; ssaoResources = {}; msaoResources = {}; diff --git a/WickedEngine/wiRenderer.cpp b/WickedEngine/wiRenderer.cpp index b064675c6..21b99a67c 100644 --- a/WickedEngine/wiRenderer.cpp +++ b/WickedEngine/wiRenderer.cpp @@ -6392,7 +6392,7 @@ void DrawDebugWorld( device->CreateBuffer(&bd, indices, &wirecamIB); } - device->BindPipelineState(&PSO_debug[DEBUGRENDERING_CUBE], cmd); + device->BindPipelineState(&PSO_debug[DEBUGRENDERING_CUBE_DEPTH], cmd); const GPUBuffer* vbs[] = { &wirecamVB, @@ -6528,7 +6528,7 @@ void DrawDebugWorld( { device->EventBegin("DebugPartitionTree", cmd); - device->BindPipelineState(&PSO_debug[DEBUGRENDERING_CUBE], cmd); + device->BindPipelineState(&PSO_debug[DEBUGRENDERING_CUBE_DEPTH], cmd); const GPUBuffer* vbs[] = { &wirecubeVB, @@ -7221,7 +7221,7 @@ void DrawDebugWorld( // Local proxy boxes: - device->BindPipelineState(&PSO_debug[DEBUGRENDERING_CUBE], cmd); + device->BindPipelineState(&PSO_debug[DEBUGRENDERING_CUBE_DEPTH], cmd); const GPUBuffer* vbs[] = { &wirecubeVB, @@ -7375,7 +7375,7 @@ void DrawDebugWorld( if (mesh == nullptr) { // No mesh, just draw a box: - device->BindPipelineState(&PSO_debug[DEBUGRENDERING_CUBE], cmd); + device->BindPipelineState(&PSO_debug[DEBUGRENDERING_CUBE_DEPTH], cmd); const GPUBuffer* vbs[] = { &wirecubeVB, }; @@ -15807,10 +15807,13 @@ void Postprocess_Tonemap( assert(texture_colorgradinglut == nullptr || texture_colorgradinglut->desc.type == TextureDesc::Type::TEXTURE_3D); // This must be a 3D lut + XMHALF4 exposure_brightness_contrast_saturation = XMHALF4(exposure, brightness, contrast, saturation); + PushConstantsTonemap tonemap_push = {}; tonemap_push.resolution_rcp.x = 1.0f / desc.width; tonemap_push.resolution_rcp.y = 1.0f / desc.height; - tonemap_push.exposure = exposure; + tonemap_push.exposure_brightness_contrast_saturation.x = uint(exposure_brightness_contrast_saturation.v); + tonemap_push.exposure_brightness_contrast_saturation.y = uint(exposure_brightness_contrast_saturation.v >> 32ull); tonemap_push.flags = 0; if (dither) { @@ -15820,9 +15823,6 @@ void Postprocess_Tonemap( { tonemap_push.flags |= TONEMAP_FLAG_ACES; } - tonemap_push.brightness = brightness; - tonemap_push.contrast = contrast; - tonemap_push.saturation = saturation; tonemap_push.texture_input = device->GetDescriptorIndex(&input, SubresourceType::SRV); tonemap_push.buffer_input_luminance = device->GetDescriptorIndex((buffer_luminance == nullptr) ? &luminance_dummy : buffer_luminance, SubresourceType::SRV); tonemap_push.texture_input_distortion = device->GetDescriptorIndex(texture_distortion, SubresourceType::SRV); diff --git a/WickedEngine/wiScene.cpp b/WickedEngine/wiScene.cpp index e5bb3b439..f31a9c1d2 100644 --- a/WickedEngine/wiScene.cpp +++ b/WickedEngine/wiScene.cpp @@ -4844,7 +4844,7 @@ namespace wi::scene { SoundComponent& sound = sounds[i]; - if (!sound.soundinstance.IsValid()) + if (!sound.soundinstance.IsValid() && sound.soundResource.IsValid()) { sound.soundinstance.SetLooped(sound.IsLooped()); wi::audio::CreateSoundInstance(&sound.soundResource.GetSound(), &sound.soundinstance); diff --git a/WickedEngine/wiScene_Serializers.cpp b/WickedEngine/wiScene_Serializers.cpp index b7225ad80..a9689ce31 100644 --- a/WickedEngine/wiScene_Serializers.cpp +++ b/WickedEngine/wiScene_Serializers.cpp @@ -2078,6 +2078,7 @@ namespace wi::scene // With this we will ensure that serialized entities are unique and persistent across the scene: EntitySerializer seri; + seri.ctx.priority = wi::jobsystem::Priority::Low; // serialization tasks will be low priority to not block rendering if scene loading is asynchronous if(archive.GetVersion() >= 84) { diff --git a/WickedEngine/wiVersion.cpp b/WickedEngine/wiVersion.cpp index b290c2ab2..28e310ef2 100644 --- a/WickedEngine/wiVersion.cpp +++ b/WickedEngine/wiVersion.cpp @@ -9,7 +9,7 @@ namespace wi::version // minor features, major updates, breaking compatibility changes const int minor = 71; // minor bug fixes, alterations, refactors, updates - const int revision = 455; + const int revision = 456; const std::string version_string = std::to_string(major) + "." + std::to_string(minor) + "." + std::to_string(revision); @@ -50,7 +50,7 @@ All contributors: https://github.com/turanszkij/WickedEngine/graphs/contributors Patreon supporters --------------------------- -Nemerle, James Webb, Quifeng Jin, TheGameCreators, Joseph Goldin, Yuri, Sergey K, Yukawa Kanta, Dragon Josh, John, LurkingNinja, Bernardo Del Castillo, Invictus, Scott Hunt, Yazan Altaki, Tuan NV, Robert MacGregor, cybernescence, Alexander Dahlin, blueapples, Delhills, NI NI, Sherief, ktopoet, Justin Macklin, Cédric Fabre, TogetherTeam, Bartosz Boczula, Arne Koenig, Ivan Trajchev, nathants, Fahd Ahmed, Gabriel Jadderson, SAS_Controller, Dominik Madarász, Segfault, Mike amanfo, Dennis Brakhane, rookie, Peter Moore, therealjtgill, Nicolas Embleton, Desuuc, radino1977, Anthony Curtis, manni heck, Matthias Hölzl, Phyffer, Lucas Pinheiro, Tapkaara, gpman, Anthony Python, Gnowos, Klaus, slaughternaut, Paul Brain, Connor Greaves, Alexandr, Lee Bamber, MCAlarm MC2, Titoutan, Willow, Aldo, lokimx, K. Osterman, Nomad, ykl, Alex Krokos, Timmy, Avaflow +Nemerle, James Webb, Quifeng Jin, TheGameCreators, Joseph Goldin, Yuri, Sergey K, Yukawa Kanta, Dragon Josh, John, LurkingNinja, Bernardo Del Castillo, Invictus, Scott Hunt, Yazan Altaki, Tuan NV, Robert MacGregor, cybernescence, Alexander Dahlin, blueapples, Delhills, NI NI, Sherief, ktopoet, Justin Macklin, Cédric Fabre, TogetherTeam, Bartosz Boczula, Arne Koenig, Ivan Trajchev, nathants, Fahd Ahmed, Gabriel Jadderson, SAS_Controller, Dominik Madarász, Segfault, Mike amanfo, Dennis Brakhane, rookie, Peter Moore, therealjtgill, Nicolas Embleton, Desuuc, radino1977, Anthony Curtis, manni heck, Matthias Hölzl, Phyffer, Lucas Pinheiro, Tapkaara, gpman, Anthony Python, Gnowos, Klaus, slaughternaut, Paul Brain, Connor Greaves, Alexandr, Lee Bamber, MCAlarm MC2, Titoutan, Willow, Aldo, lokimx, K. Osterman, Nomad, ykl, Alex Krokos, Timmy, Avaflow, mat, Hexegonel Samael Michael, Joe Spataro, soru )"; return credits;
Argument Description
dx12Use DirectX 12 rendering device
vulkanUse Vulkan rendering deviceUse the Vulkan rendering device on Windows
debugdeviceUse debug layer for graphics API validation. Performance will be degraded, but graphics warnings and errors will be written to "Output" windowUse debug layer for graphics API validation. Performance will be degraded, but graphics warnings and errors will be written to the "Output" window
gpuvalidation