diff --git a/Editor/AnimationWindow.cpp b/Editor/AnimationWindow.cpp index 509bbfd61..819833f4a 100644 --- a/Editor/AnimationWindow.cpp +++ b/Editor/AnimationWindow.cpp @@ -33,6 +33,7 @@ void AnimationWindow::Create(EditorComponent* _editor) infoLabel.Create(""); infoLabel.SetSize(XMFLOAT2(100, 50)); infoLabel.SetText("The animation window will stay open even if you select other entities until it is collapsed, so you can record other entities' data."); + infoLabel.SetFitTextEnabled(true); AddWidget(&infoLabel); modeComboBox.Create("Sampling: "); diff --git a/Editor/ArmatureWindow.cpp b/Editor/ArmatureWindow.cpp index 87d6a28b4..789f45c03 100644 --- a/Editor/ArmatureWindow.cpp +++ b/Editor/ArmatureWindow.cpp @@ -32,8 +32,8 @@ void ArmatureWindow::Create(EditorComponent* _editor) float wid = 220; infoLabel.Create(""); - infoLabel.SetSize(XMFLOAT2(100, 80)); infoLabel.SetText("This window will stay open even if you select other entities until it is collapsed, so you can select other bone entities."); + infoLabel.SetFitTextEnabled(true); AddWidget(&infoLabel); resetPoseButton.Create("Reset Pose"); diff --git a/Editor/ColliderWindow.cpp b/Editor/ColliderWindow.cpp index 5ce0eb265..82c6e58f8 100644 --- a/Editor/ColliderWindow.cpp +++ b/Editor/ColliderWindow.cpp @@ -33,7 +33,7 @@ void ColliderWindow::Create(EditorComponent* _editor) infoLabel.Create(""); infoLabel.SetText("Colliders are used for simple fake physics, without using the physics engine. They are only used in specific CPU/GPU systems."); - infoLabel.SetSize(XMFLOAT2(100, 50)); + infoLabel.SetFitTextEnabled(true); AddWidget(&infoLabel); cpuCheckBox.Create("CPU: "); diff --git a/Editor/ConstraintWindow.cpp b/Editor/ConstraintWindow.cpp index 080d606f3..05341025f 100644 --- a/Editor/ConstraintWindow.cpp +++ b/Editor/ConstraintWindow.cpp @@ -26,8 +26,8 @@ void ConstraintWindow::Create(EditorComponent* _editor) }); infoLabel.Create("ConstraintInfo"); - infoLabel.SetSize(XMFLOAT2(100, 150)); infoLabel.SetText("Constraints can be added to bind one or two rigid bodies. If only one body is specified, then it will be bound to the constraint's location. If two bodies are specified, they will be bound together with the constraint acting as the pivot between them at the time of binding."); + infoLabel.SetFitTextEnabled(true); AddWidget(&infoLabel); physicsDebugCheckBox.Create(ICON_EYE " Physics visualizer: "); diff --git a/Editor/DecalWindow.cpp b/Editor/DecalWindow.cpp index 54869f5db..f20a84f85 100644 --- a/Editor/DecalWindow.cpp +++ b/Editor/DecalWindow.cpp @@ -25,22 +25,12 @@ void DecalWindow::Create(EditorComponent* _editor) editor->componentsWnd.RefreshEntityTree(); }); - float x = 200; - float y = 0; - float hei = 18; - float step = hei + 2; - placementCheckBox.Create("Decal Placement Enabled: "); - placementCheckBox.SetPos(XMFLOAT2(x, y)); - placementCheckBox.SetSize(XMFLOAT2(hei, hei)); placementCheckBox.SetCheck(false); placementCheckBox.SetTooltip("Enable decal placement. Use the left mouse button to place decals to the scene."); AddWidget(&placementCheckBox); - y += step; - onlyalphaCheckBox.Create("Alpha only basecolor: "); - onlyalphaCheckBox.SetSize(XMFLOAT2(hei, hei)); onlyalphaCheckBox.SetTooltip("You can enable this to only use alpha channel from basecolor map. Useful for blending normalmap-only decals."); onlyalphaCheckBox.OnClick([=](wi::gui::EventArgs args) { wi::scene::Scene& scene = editor->GetCurrentScene(); @@ -55,7 +45,6 @@ void DecalWindow::Create(EditorComponent* _editor) AddWidget(&onlyalphaCheckBox); slopeBlendPowerSlider.Create(0, 8, 0, 1000, "Slope Blend: "); - slopeBlendPowerSlider.SetSize(XMFLOAT2(100, hei)); slopeBlendPowerSlider.SetTooltip("Set a power factor for blending on surface slopes. 0 = no slope blend, increasing = more slope blend"); slopeBlendPowerSlider.OnSlide([=](wi::gui::EventArgs args) { wi::scene::Scene& scene = editor->GetCurrentScene(); @@ -69,15 +58,11 @@ void DecalWindow::Create(EditorComponent* _editor) }); AddWidget(&slopeBlendPowerSlider); - y += step; - infoLabel.Create(""); infoLabel.SetText("Set decal properties in the Material component. Decals support the following material properties:\n - Base color\n - Base color texture\n - Emissive strength\n - Normalmap texture\n - Normalmap strength\n - Surfacemap texture\n - Texture tiling (TexMulAdd)"); - infoLabel.SetSize(XMFLOAT2(300, 100)); - infoLabel.SetPos(XMFLOAT2(10, y)); infoLabel.SetColor(wi::Color::Transparent()); + infoLabel.SetFitTextEnabled(true); AddWidget(&infoLabel); - y += infoLabel.GetScale().y - step + 5; SetMinimized(true); SetVisible(false); diff --git a/Editor/EmitterWindow.cpp b/Editor/EmitterWindow.cpp index 81fde2299..d39933709 100644 --- a/Editor/EmitterWindow.cpp +++ b/Editor/EmitterWindow.cpp @@ -271,8 +271,7 @@ void EmitterWindow::Create(EditorComponent* _editor) infoLabel.Create("EmitterInfo"); - infoLabel.SetSize(XMFLOAT2(GetSize().x - 20, 160)); - infoLabel.SetPos(XMFLOAT2(10, y += step)); + infoLabel.SetFitTextEnabled(true); AddWidget(&infoLabel); @@ -953,6 +952,7 @@ void EmitterWindow::UpdateData() NameComponent* meshName = scene.names.GetComponent(emitter->meshID); std::string ss; + ss += "Tip: You can modify the Material on this entity to set texture, color, emissive to the particles. Particles can also be spawned from a mesh surface if you specify a mesh for it.\n\n"; ss += "Emitter Mesh: " + (meshName != nullptr ? meshName->name : "NO EMITTER MESH") + " (" + std::to_string(emitter->meshID) + ")\n"; ss += "Memory usage: " + wi::helper::GetMemorySizeText(emitter->GetMemorySizeInBytes()) + "\n"; ss += "\n"; diff --git a/Editor/EnvProbeWindow.cpp b/Editor/EnvProbeWindow.cpp index c0019ec0d..ea15e411e 100644 --- a/Editor/EnvProbeWindow.cpp +++ b/Editor/EnvProbeWindow.cpp @@ -26,18 +26,13 @@ void EnvProbeWindow::Create(EditorComponent* _editor) editor->componentsWnd.RefreshEntityTree(); }); - float x = 5, y = 0, step = 35; - infoLabel.Create(""); - infoLabel.SetSize(XMFLOAT2(300, 120)); - infoLabel.SetPos(XMFLOAT2(x, y)); infoLabel.SetColor(wi::Color::Transparent()); + infoLabel.SetFitTextEnabled(true); AddWidget(&infoLabel); - y += infoLabel.GetScale().y + 5; realTimeCheckBox.Create("RealTime: "); realTimeCheckBox.SetTooltip("Enable continuous rendering of the probe in every frame."); - realTimeCheckBox.SetPos(XMFLOAT2(x + 100, y)); realTimeCheckBox.SetEnabled(false); realTimeCheckBox.OnClick([&](wi::gui::EventArgs args) { wi::scene::Scene& scene = editor->GetCurrentScene(); @@ -54,7 +49,6 @@ void EnvProbeWindow::Create(EditorComponent* _editor) msaaCheckBox.Create("MSAA: "); msaaCheckBox.SetTooltip("Enable Multi Sampling Anti Aliasing for the probe, this will improve its quality."); - msaaCheckBox.SetPos(XMFLOAT2(x + 200, y)); msaaCheckBox.SetEnabled(false); msaaCheckBox.OnClick([&](wi::gui::EventArgs args) { wi::scene::Scene& scene = editor->GetCurrentScene(); @@ -71,7 +65,6 @@ void EnvProbeWindow::Create(EditorComponent* _editor) refreshButton.Create("Refresh"); refreshButton.SetTooltip("Re-renders the selected probe."); - refreshButton.SetPos(XMFLOAT2(x, y+= step)); refreshButton.SetEnabled(false); refreshButton.OnClick([&](wi::gui::EventArgs args) { wi::scene::Scene& scene = editor->GetCurrentScene(); @@ -87,7 +80,6 @@ void EnvProbeWindow::Create(EditorComponent* _editor) refreshAllButton.Create("Refresh All"); refreshAllButton.SetTooltip("Re-renders all probes in the scene."); - refreshAllButton.SetPos(XMFLOAT2(x + 120, y)); refreshAllButton.SetEnabled(true); refreshAllButton.OnClick([&](wi::gui::EventArgs args) { wi::scene::Scene& scene = editor->GetCurrentScene(); @@ -103,7 +95,6 @@ void EnvProbeWindow::Create(EditorComponent* _editor) importButton.Create("Import Cubemap"); importButton.SetTooltip("Import a DDS texture file into the selected environment probe."); - importButton.SetPos(XMFLOAT2(x, y += step)); importButton.SetEnabled(false); importButton.OnClick([&](wi::gui::EventArgs args) { wi::scene::Scene& scene = editor->GetCurrentScene(); @@ -142,7 +133,6 @@ void EnvProbeWindow::Create(EditorComponent* _editor) exportButton.Create("Export Cubemap"); exportButton.SetTooltip("Export the selected probe into a DDS cubemap texture file."); - exportButton.SetPos(XMFLOAT2(x, y += step)); exportButton.SetEnabled(false); exportButton.OnClick([&](wi::gui::EventArgs args) { wi::scene::Scene& scene = editor->GetCurrentScene(); diff --git a/Editor/ExpressionWindow.cpp b/Editor/ExpressionWindow.cpp index 0c5a931db..337126973 100644 --- a/Editor/ExpressionWindow.cpp +++ b/Editor/ExpressionWindow.cpp @@ -25,20 +25,13 @@ void ExpressionWindow::Create(EditorComponent* _editor) editor->componentsWnd.RefreshEntityTree(); }); - float x = 60; - float y = 4; - float hei = 20; - float step = hei + 2; - float wid = 220; - infoLabel.Create(""); - infoLabel.SetSize(XMFLOAT2(100, 60)); infoLabel.SetText("Tip: If you also attach a Sound component to this entity, the mouth expression (if available) will be animated based on the sound playing."); + infoLabel.SetFitTextEnabled(true); AddWidget(&infoLabel); talkCheckBox.Create("Force Talking: "); talkCheckBox.SetTooltip("Force continuous talking animation, even if no voice is playing"); - talkCheckBox.SetSize(XMFLOAT2(hei, hei)); talkCheckBox.OnClick([=](wi::gui::EventArgs args) { wi::scene::Scene& scene = editor->GetCurrentScene(); ExpressionComponent* expression_mastering = scene.expressions.GetComponent(entity); @@ -51,7 +44,6 @@ void ExpressionWindow::Create(EditorComponent* _editor) blinkFrequencySlider.Create(0, 1, 0, 1000, "Blinks: "); blinkFrequencySlider.SetTooltip("Specifies the number of blinks per second."); - blinkFrequencySlider.SetSize(XMFLOAT2(wid, hei)); blinkFrequencySlider.OnSlide([=](wi::gui::EventArgs args) { wi::scene::Scene& scene = editor->GetCurrentScene(); ExpressionComponent* expression_mastering = scene.expressions.GetComponent(entity); @@ -62,7 +54,6 @@ void ExpressionWindow::Create(EditorComponent* _editor) AddWidget(&blinkFrequencySlider); blinkLengthSlider.Create(0, 1, 0, 1000, "Blink Length: "); - blinkLengthSlider.SetSize(XMFLOAT2(wid, hei)); blinkLengthSlider.OnSlide([=](wi::gui::EventArgs args) { wi::scene::Scene& scene = editor->GetCurrentScene(); ExpressionComponent* expression_mastering = scene.expressions.GetComponent(entity); @@ -73,7 +64,6 @@ void ExpressionWindow::Create(EditorComponent* _editor) AddWidget(&blinkLengthSlider); blinkCountSlider.Create(1, 4, 2, 3, "Blink Count: "); - blinkCountSlider.SetSize(XMFLOAT2(wid, hei)); blinkCountSlider.OnSlide([=](wi::gui::EventArgs args) { wi::scene::Scene& scene = editor->GetCurrentScene(); ExpressionComponent* expression_mastering = scene.expressions.GetComponent(entity); @@ -85,7 +75,6 @@ void ExpressionWindow::Create(EditorComponent* _editor) lookFrequencySlider.Create(0, 1, 0, 1000, "Looks: "); lookFrequencySlider.SetTooltip("Specifies the number of look-aways per second."); - lookFrequencySlider.SetSize(XMFLOAT2(wid, hei)); lookFrequencySlider.OnSlide([=](wi::gui::EventArgs args) { wi::scene::Scene& scene = editor->GetCurrentScene(); ExpressionComponent* expression_mastering = scene.expressions.GetComponent(entity); @@ -96,7 +85,6 @@ void ExpressionWindow::Create(EditorComponent* _editor) AddWidget(&lookFrequencySlider); lookLengthSlider.Create(0, 1, 0, 1000, "Look Length: "); - lookLengthSlider.SetSize(XMFLOAT2(wid, hei)); lookLengthSlider.OnSlide([=](wi::gui::EventArgs args) { wi::scene::Scene& scene = editor->GetCurrentScene(); ExpressionComponent* expression_mastering = scene.expressions.GetComponent(entity); @@ -107,8 +95,6 @@ void ExpressionWindow::Create(EditorComponent* _editor) AddWidget(&lookLengthSlider); expressionList.Create("Expressions: "); - expressionList.SetSize(XMFLOAT2(wid, 200)); - expressionList.SetPos(XMFLOAT2(4, y += step)); expressionList.OnSelect([=](wi::gui::EventArgs args) { wi::scene::Scene& scene = editor->GetCurrentScene(); ExpressionComponent* expression_mastering = scene.expressions.GetComponent(entity); @@ -127,7 +113,6 @@ void ExpressionWindow::Create(EditorComponent* _editor) AddWidget(&expressionList); binaryCheckBox.Create("Binary: "); - binaryCheckBox.SetSize(XMFLOAT2(hei, hei)); binaryCheckBox.OnClick([=](wi::gui::EventArgs args) { wi::scene::Scene& scene = editor->GetCurrentScene(); ExpressionComponent* expression_mastering = scene.expressions.GetComponent(entity); @@ -150,8 +135,6 @@ void ExpressionWindow::Create(EditorComponent* _editor) AddWidget(&binaryCheckBox); weightSlider.Create(0, 1, 0, 100000, "Weight: "); - weightSlider.SetSize(XMFLOAT2(wid, hei)); - weightSlider.SetPos(XMFLOAT2(x, y += step)); weightSlider.OnSlide([&](wi::gui::EventArgs args) { wi::scene::Scene& scene = editor->GetCurrentScene(); ExpressionComponent* expression_mastering = scene.expressions.GetComponent(entity); @@ -177,7 +160,6 @@ void ExpressionWindow::Create(EditorComponent* _editor) overrideMouthCombo.Create("Override Mouth: "); overrideMouthCombo.SetTooltip("Lip sync override control"); - overrideMouthCombo.SetSize(XMFLOAT2(wid, hei)); overrideMouthCombo.AddItem("None", (uint64_t)ExpressionComponent::Override::None); overrideMouthCombo.AddItem("Block", (uint64_t)ExpressionComponent::Override::Block); overrideMouthCombo.AddItem("Blend", (uint64_t)ExpressionComponent::Override::Blend); @@ -206,7 +188,6 @@ void ExpressionWindow::Create(EditorComponent* _editor) overrideBlinkCombo.Create("Override Blink: "); overrideBlinkCombo.SetTooltip("Blink override control"); - overrideBlinkCombo.SetSize(XMFLOAT2(wid, hei)); overrideBlinkCombo.AddItem("None", (uint64_t)ExpressionComponent::Override::None); overrideBlinkCombo.AddItem("Block", (uint64_t)ExpressionComponent::Override::Block); overrideBlinkCombo.AddItem("Blend", (uint64_t)ExpressionComponent::Override::Blend); @@ -235,7 +216,6 @@ void ExpressionWindow::Create(EditorComponent* _editor) overrideLookCombo.Create("Override Look: "); overrideLookCombo.SetTooltip("Look-away override control"); - overrideLookCombo.SetSize(XMFLOAT2(wid, hei)); overrideLookCombo.AddItem("None", (uint64_t)ExpressionComponent::Override::None); overrideLookCombo.AddItem("Block", (uint64_t)ExpressionComponent::Override::Block); overrideLookCombo.AddItem("Blend", (uint64_t)ExpressionComponent::Override::Blend); diff --git a/Editor/FontWindow.cpp b/Editor/FontWindow.cpp index 181857bb0..4ffcbe0de 100644 --- a/Editor/FontWindow.cpp +++ b/Editor/FontWindow.cpp @@ -441,7 +441,7 @@ void FontWindow::Create(EditorComponent* _editor) AddWidget(&colorPicker); typewriterInfoLabel.Create("Tip: if you add Sound Component to text, then the typewriter animation will use that sound as typewriter sound effect."); - typewriterInfoLabel.SetSize(XMFLOAT2(80, 80)); + typewriterInfoLabel.SetFitTextEnabled(true); AddWidget(&typewriterInfoLabel); typewriterTimeSlider.Create(0, 10, 0, 10000, "Typewriter time: "); diff --git a/Editor/HairParticleWindow.cpp b/Editor/HairParticleWindow.cpp index c40363609..350386b4f 100644 --- a/Editor/HairParticleWindow.cpp +++ b/Editor/HairParticleWindow.cpp @@ -24,19 +24,11 @@ void HairParticleWindow::Create(EditorComponent* _editor) editor->componentsWnd.RefreshEntityTree(); }); - float x = 120; - float y = 0; - float hei = 18; - float step = hei + 2; - float wid = 150; - infoLabel.Create(""); - infoLabel.SetSize(XMFLOAT2(wid, 200)); + infoLabel.SetFitTextEnabled(true); AddWidget(&infoLabel); meshComboBox.Create("Mesh: "); - meshComboBox.SetSize(XMFLOAT2(wid, hei)); - meshComboBox.SetPos(XMFLOAT2(x, y)); meshComboBox.SetEnabled(false); meshComboBox.OnSelect([&](wi::gui::EventArgs args) { wi::scene::Scene& scene = editor->GetCurrentScene(); @@ -76,8 +68,6 @@ void HairParticleWindow::Create(EditorComponent* _editor) AddWidget(&cameraBendCheckbox); countSlider.Create(0, 100000, 1000, 100000, "Strand Count: "); - countSlider.SetSize(XMFLOAT2(wid, hei)); - countSlider.SetPos(XMFLOAT2(x, y += step)); countSlider.OnSlide([&](wi::gui::EventArgs args) { wi::scene::Scene& scene = editor->GetCurrentScene(); for (auto& x : editor->translator.selected) @@ -94,8 +84,6 @@ void HairParticleWindow::Create(EditorComponent* _editor) AddWidget(&countSlider); lengthSlider.Create(0, 4, 1, 1000, "Length: "); - lengthSlider.SetSize(XMFLOAT2(wid, hei)); - lengthSlider.SetPos(XMFLOAT2(x, y += step)); lengthSlider.OnSlide([&](wi::gui::EventArgs args) { wi::scene::Scene& scene = editor->GetCurrentScene(); for (auto& x : editor->translator.selected) @@ -112,8 +100,6 @@ void HairParticleWindow::Create(EditorComponent* _editor) AddWidget(&lengthSlider); widthSlider.Create(0, 2, 1, 1000, "Width: "); - widthSlider.SetSize(XMFLOAT2(wid, hei)); - widthSlider.SetPos(XMFLOAT2(x, y += step)); widthSlider.OnSlide([&](wi::gui::EventArgs args) { wi::scene::Scene& scene = editor->GetCurrentScene(); for (auto& x : editor->translator.selected) @@ -130,8 +116,6 @@ void HairParticleWindow::Create(EditorComponent* _editor) AddWidget(&widthSlider); stiffnessSlider.Create(0, 10, 0.5f, 100, "Stiffness: "); - stiffnessSlider.SetSize(XMFLOAT2(wid, hei)); - stiffnessSlider.SetPos(XMFLOAT2(x, y += step)); stiffnessSlider.OnSlide([&](wi::gui::EventArgs args) { wi::scene::Scene& scene = editor->GetCurrentScene(); for (auto& x : editor->translator.selected) @@ -148,8 +132,6 @@ void HairParticleWindow::Create(EditorComponent* _editor) AddWidget(&stiffnessSlider); dragSlider.Create(0, 1, 0.5f, 100, "Drag: "); - dragSlider.SetSize(XMFLOAT2(wid, hei)); - dragSlider.SetPos(XMFLOAT2(x, y += step)); dragSlider.OnSlide([&](wi::gui::EventArgs args) { wi::scene::Scene& scene = editor->GetCurrentScene(); for (auto& x : editor->translator.selected) @@ -166,8 +148,6 @@ void HairParticleWindow::Create(EditorComponent* _editor) AddWidget(&dragSlider); gravityPowerSlider.Create(0, 1, 0.5f, 100, "Gravity Power: "); - gravityPowerSlider.SetSize(XMFLOAT2(wid, hei)); - gravityPowerSlider.SetPos(XMFLOAT2(x, y += step)); gravityPowerSlider.OnSlide([&](wi::gui::EventArgs args) { wi::scene::Scene& scene = editor->GetCurrentScene(); for (auto& x : editor->translator.selected) @@ -184,8 +164,6 @@ void HairParticleWindow::Create(EditorComponent* _editor) AddWidget(&gravityPowerSlider); randomnessSlider.Create(0, 1, 0.2f, 1000, "Randomness: "); - randomnessSlider.SetSize(XMFLOAT2(wid, hei)); - randomnessSlider.SetPos(XMFLOAT2(x, y += step)); randomnessSlider.OnSlide([&](wi::gui::EventArgs args) { wi::scene::Scene& scene = editor->GetCurrentScene(); for (auto& x : editor->translator.selected) @@ -202,8 +180,6 @@ void HairParticleWindow::Create(EditorComponent* _editor) AddWidget(&randomnessSlider); segmentcountSlider.Create(1, 10, 1, 9, "Segments: "); - segmentcountSlider.SetSize(XMFLOAT2(wid, hei)); - segmentcountSlider.SetPos(XMFLOAT2(x, y += step)); segmentcountSlider.OnSlide([&](wi::gui::EventArgs args) { wi::scene::Scene& scene = editor->GetCurrentScene(); for (auto& x : editor->translator.selected) @@ -220,8 +196,6 @@ void HairParticleWindow::Create(EditorComponent* _editor) AddWidget(&segmentcountSlider); billboardcountSlider.Create(1, 10, 1, 9, "Billboards: "); - billboardcountSlider.SetSize(XMFLOAT2(wid, hei)); - billboardcountSlider.SetPos(XMFLOAT2(x, y += step)); billboardcountSlider.OnSlide([&](wi::gui::EventArgs args) { wi::scene::Scene& scene = editor->GetCurrentScene(); for (auto& x : editor->translator.selected) @@ -238,8 +212,6 @@ void HairParticleWindow::Create(EditorComponent* _editor) AddWidget(&billboardcountSlider); randomSeedSlider.Create(1, 12345, 1, 12344, "Random seed: "); - randomSeedSlider.SetSize(XMFLOAT2(wid, hei)); - randomSeedSlider.SetPos(XMFLOAT2(x, y += step)); randomSeedSlider.OnSlide([&](wi::gui::EventArgs args) { wi::scene::Scene& scene = editor->GetCurrentScene(); for (auto& x : editor->translator.selected) @@ -256,8 +228,6 @@ void HairParticleWindow::Create(EditorComponent* _editor) AddWidget(&randomSeedSlider); viewDistanceSlider.Create(0, 1000, 100, 10000, "View distance: "); - viewDistanceSlider.SetSize(XMFLOAT2(wid, hei)); - viewDistanceSlider.SetPos(XMFLOAT2(x, y += step)); viewDistanceSlider.OnSlide([&](wi::gui::EventArgs args) { wi::scene::Scene& scene = editor->GetCurrentScene(); for (auto& x : editor->translator.selected) @@ -274,8 +244,6 @@ void HairParticleWindow::Create(EditorComponent* _editor) AddWidget(&viewDistanceSlider); uniformitySlider.Create(0.01f, 2.0f, 0.1f, 1000, "Uniformity: "); - uniformitySlider.SetSize(XMFLOAT2(wid, hei)); - uniformitySlider.SetPos(XMFLOAT2(x, y += step)); uniformitySlider.OnSlide([&](wi::gui::EventArgs args) { wi::scene::Scene& scene = editor->GetCurrentScene(); for (auto& x : editor->translator.selected) @@ -504,7 +472,7 @@ void HairParticleWindow::UpdateData() Scene& scene = editor->GetCurrentScene(); std::string ss; - ss += "To use hair particle system, first you must select a surface mesh to spawn particles on, and then increase particle count to grow particles. The particles will get their texture from the Material that is created on the current entity.\n\n"; + ss += "Tip: To use hair particle system, first you must select a surface mesh to spawn particles on, and then increase particle count to grow particles. The particles will get their texture from the Material that is created on the current entity.\n\n"; ss += "Position format: " + std::string(wi::graphics::GetFormatString(hair->position_format)) + "\n"; ss += "Memory usage: " + wi::helper::GetMemorySizeText(hair->GetMemorySizeInBytes()) + "\n"; infoLabel.SetText(ss); diff --git a/Editor/HumanoidWindow.cpp b/Editor/HumanoidWindow.cpp index b6bcd27b9..8bdaf644b 100644 --- a/Editor/HumanoidWindow.cpp +++ b/Editor/HumanoidWindow.cpp @@ -25,20 +25,13 @@ void HumanoidWindow::Create(EditorComponent* _editor) editor->componentsWnd.RefreshEntityTree(); }); - float x = 60; - float y = 4; - float hei = 20; - float step = hei + 2; - float wid = 220; - infoLabel.Create(""); - infoLabel.SetSize(XMFLOAT2(100, 80)); infoLabel.SetText("This window will stay open even if you select other entities until it is collapsed, so you can select other bone entities."); + infoLabel.SetFitTextEnabled(true); AddWidget(&infoLabel); lookatCheckBox.Create("Look At: "); lookatCheckBox.SetTooltip("Enable updating the lookAt direction. If enabled, head will turn to face the lookAt point.\nA sample lookAt point can be generated by the editor if you enable the Follow mouse option."); - lookatCheckBox.SetSize(XMFLOAT2(hei, hei)); lookatCheckBox.OnClick([=](wi::gui::EventArgs args) { wi::scene::Scene& scene = editor->GetCurrentScene(); HumanoidComponent* humanoid = scene.humanoids.GetComponent(entity); @@ -51,7 +44,6 @@ void HumanoidWindow::Create(EditorComponent* _editor) lookatMouseCheckBox.Create("Follow mouse: "); lookatMouseCheckBox.SetTooltip("Generates a sample lookAt point at the mouse position. If LookAt is enabled, the character's head will try to face in the direction of the mouse"); - lookatMouseCheckBox.SetSize(XMFLOAT2(hei, hei)); AddWidget(&lookatMouseCheckBox); lookatMouseCheckBox.SetCheck(true); @@ -69,7 +61,6 @@ void HumanoidWindow::Create(EditorComponent* _editor) ragdollCheckBox.Create("Ragdoll: "); ragdollCheckBox.SetTooltip("Activate dynamic ragdoll physics.\nNote that kinematic ragdoll physics is always active (ragdoll is animation-driven/kinematic by default).\nNote that scaling humanoid will disable ragdoll physics and you need to re-enable if you want to."); - ragdollCheckBox.SetSize(XMFLOAT2(hei, hei)); ragdollCheckBox.OnClick([=](wi::gui::EventArgs args) { wi::scene::Scene& scene = editor->GetCurrentScene(); HumanoidComponent* humanoid = scene.humanoids.GetComponent(entity); @@ -82,7 +73,6 @@ void HumanoidWindow::Create(EditorComponent* _editor) capsuleShadowCheckBox.Create("Capsule Shadow Disabled: "); capsuleShadowCheckBox.SetTooltip("Disable capsule shadow for this specific humanoid."); - capsuleShadowCheckBox.SetSize(XMFLOAT2(hei, hei)); capsuleShadowCheckBox.OnClick([=](wi::gui::EventArgs args) { wi::scene::Scene& scene = editor->GetCurrentScene(); HumanoidComponent* humanoid = scene.humanoids.GetComponent(entity); @@ -95,7 +85,6 @@ void HumanoidWindow::Create(EditorComponent* _editor) headRotMaxXSlider.Create(0, 90, 60, 180, "Head horizontal: "); headRotMaxXSlider.SetTooltip("Limit horizontal head movement (input in degrees)"); - headRotMaxXSlider.SetSize(XMFLOAT2(wid, hei)); headRotMaxXSlider.OnSlide([=](wi::gui::EventArgs args) { wi::scene::Scene& scene = editor->GetCurrentScene(); HumanoidComponent* humanoid = scene.humanoids.GetComponent(entity); @@ -108,7 +97,6 @@ void HumanoidWindow::Create(EditorComponent* _editor) headRotMaxYSlider.Create(0, 60, 30, 60, "Head vertical: "); headRotMaxYSlider.SetTooltip("Limit vertical head movement (input in degrees)"); - headRotMaxYSlider.SetSize(XMFLOAT2(wid, hei)); headRotMaxYSlider.OnSlide([=](wi::gui::EventArgs args) { wi::scene::Scene& scene = editor->GetCurrentScene(); HumanoidComponent* humanoid = scene.humanoids.GetComponent(entity); @@ -121,7 +109,6 @@ void HumanoidWindow::Create(EditorComponent* _editor) headRotSpeedSlider.Create(0.05f, 1, 0.1f, 1000, "Head speed: "); headRotSpeedSlider.SetTooltip("Adjust head turning speed."); - headRotSpeedSlider.SetSize(XMFLOAT2(wid, hei)); headRotSpeedSlider.OnSlide([=](wi::gui::EventArgs args) { wi::scene::Scene& scene = editor->GetCurrentScene(); HumanoidComponent* humanoid = scene.humanoids.GetComponent(entity); @@ -135,7 +122,6 @@ void HumanoidWindow::Create(EditorComponent* _editor) eyeRotMaxXSlider.Create(0, 40, 20, 40, "Eye horizontal: "); eyeRotMaxXSlider.SetTooltip("Limit horizontal eye movement (input in degrees)"); - eyeRotMaxXSlider.SetSize(XMFLOAT2(wid, hei)); eyeRotMaxXSlider.OnSlide([=](wi::gui::EventArgs args) { wi::scene::Scene& scene = editor->GetCurrentScene(); HumanoidComponent* humanoid = scene.humanoids.GetComponent(entity); @@ -148,7 +134,6 @@ void HumanoidWindow::Create(EditorComponent* _editor) eyeRotMaxYSlider.Create(0, 30, 15, 30, "Eye vertical: "); eyeRotMaxYSlider.SetTooltip("Limit vertical eye movement (input in degrees)"); - eyeRotMaxYSlider.SetSize(XMFLOAT2(wid, hei)); eyeRotMaxYSlider.OnSlide([=](wi::gui::EventArgs args) { wi::scene::Scene& scene = editor->GetCurrentScene(); HumanoidComponent* humanoid = scene.humanoids.GetComponent(entity); @@ -161,7 +146,6 @@ void HumanoidWindow::Create(EditorComponent* _editor) eyeRotSpeedSlider.Create(0.05f, 1, 0.2f, 1000, "Eye speed: "); eyeRotSpeedSlider.SetTooltip("Adjust eye turning speed."); - eyeRotSpeedSlider.SetSize(XMFLOAT2(wid, hei)); eyeRotSpeedSlider.OnSlide([=](wi::gui::EventArgs args) { wi::scene::Scene& scene = editor->GetCurrentScene(); HumanoidComponent* humanoid = scene.humanoids.GetComponent(entity); @@ -174,7 +158,6 @@ void HumanoidWindow::Create(EditorComponent* _editor) headSizeSlider.Create(0.5f, 2, 1, 1000, "Head size: "); headSizeSlider.SetTooltip("Adjust head size."); - headSizeSlider.SetSize(XMFLOAT2(wid, hei)); headSizeSlider.OnSlide([=](wi::gui::EventArgs args) { wi::scene::Scene& scene = editor->GetCurrentScene(); HumanoidComponent* humanoid = scene.humanoids.GetComponent(entity); @@ -195,7 +178,6 @@ void HumanoidWindow::Create(EditorComponent* _editor) ragdollFatnessSlider.Create(0.5f, 2, 1, 1000, "Ragdoll fatness: "); ragdollFatnessSlider.SetTooltip("Adjust overall fatness of ragdoll physics skeleton."); - ragdollFatnessSlider.SetSize(XMFLOAT2(wid, hei)); ragdollFatnessSlider.OnSlide([=](wi::gui::EventArgs args) { wi::scene::Scene& scene = editor->GetCurrentScene(); HumanoidComponent* humanoid = scene.humanoids.GetComponent(entity); @@ -209,7 +191,6 @@ void HumanoidWindow::Create(EditorComponent* _editor) ragdollHeadSizeSlider.Create(0.5f, 2, 1, 1000, "Ragdoll head: "); ragdollHeadSizeSlider.SetTooltip("Adjust overall size of ragdoll physics head."); - ragdollHeadSizeSlider.SetSize(XMFLOAT2(wid, hei)); ragdollHeadSizeSlider.OnSlide([=](wi::gui::EventArgs args) { wi::scene::Scene& scene = editor->GetCurrentScene(); HumanoidComponent* humanoid = scene.humanoids.GetComponent(entity); @@ -222,8 +203,6 @@ void HumanoidWindow::Create(EditorComponent* _editor) AddWidget(&ragdollHeadSizeSlider); boneList.Create("Bones: "); - boneList.SetSize(XMFLOAT2(wid, 200)); - boneList.SetPos(XMFLOAT2(4, y += step)); boneList.OnSelect([=](wi::gui::EventArgs args) { if (args.iValue < 0) diff --git a/Editor/LayerWindow.cpp b/Editor/LayerWindow.cpp index b55d6bc01..ac9e456ef 100644 --- a/Editor/LayerWindow.cpp +++ b/Editor/LayerWindow.cpp @@ -24,25 +24,15 @@ void LayerWindow::Create(EditorComponent* _editor) editor->componentsWnd.RefreshEntityTree(); }); - float x = 30; - float y = 0; - float step = 25; - float siz = 20; - float wid = 250; - label.Create("LayerWindowLabel"); label.SetText("The layer is a 32-bit mask (uint32_t), which can be used for filtering by multiple systems (visibility, collision, picking, scripts, etc.).\n- If all bits are disabled, it means the layer will be inactive in most systems."); - label.SetPos(XMFLOAT2(x, y)); - label.SetSize(XMFLOAT2(wid, 100)); - label.SetColor(wi::Color::Transparent()); + label.SetFitTextEnabled(true); AddWidget(&label); - y += label.GetScale().y + 5; for (uint32_t i = 0; i < arraysize(layers); ++i) { layers[i].Create(""); layers[i].SetText(std::to_string(i) + ": "); - layers[i].SetPos(XMFLOAT2(x + 20 + (i % 5) * 50, y + (i / 5) * step)); layers[i].OnClick([=](wi::gui::EventArgs args) { wi::scene::Scene& scene = editor->GetCurrentScene(); for (auto& x : editor->translator.selected) @@ -66,10 +56,7 @@ void LayerWindow::Create(EditorComponent* _editor) AddWidget(&layers[i]); } - y += step * 7; - enableAllButton.Create("ALL " ICON_CHECK); - enableAllButton.SetPos(XMFLOAT2(x, y)); enableAllButton.OnClick([this](wi::gui::EventArgs args) { wi::scene::Scene& scene = editor->GetCurrentScene(); for (auto& x : editor->translator.selected) @@ -87,7 +74,6 @@ void LayerWindow::Create(EditorComponent* _editor) AddWidget(&enableAllButton); enableNoneButton.Create("NONE " ICON_DISABLED); - enableNoneButton.SetPos(XMFLOAT2(x + 120, y)); enableNoneButton.OnClick([this](wi::gui::EventArgs args) { wi::scene::Scene& scene = editor->GetCurrentScene(); for (auto& x : editor->translator.selected) diff --git a/Editor/MaterialWindow.cpp b/Editor/MaterialWindow.cpp index 1745be353..be9929699 100644 --- a/Editor/MaterialWindow.cpp +++ b/Editor/MaterialWindow.cpp @@ -1140,8 +1140,10 @@ void MaterialWindow::Create(EditorComponent* _editor) params.type = wi::helper::FileDialogParams::OPEN; params.description = "Texture"; params.extensions = wi::resourcemanager::GetSupportedImageExtensions(); - wi::helper::FileDialog(params, [this, material, slot](std::string fileName) { + Entity materialEntity = entity; + wi::helper::FileDialog(params, [this, materialEntity, slot](std::string fileName) { wi::eventhandler::Subscribe_Once(wi::eventhandler::EVENT_THREAD_SAFE_POINT, [=](uint64_t userdata) { + MaterialComponent* material = editor->GetCurrentScene().materials.GetComponent(entity); wi::resourcemanager::Flags flags = material->GetTextureSlotResourceFlags(MaterialComponent::TEXTURESLOT(slot)); material->textures[slot].resource = wi::resourcemanager::Load(fileName, flags); material->textures[slot].name = fileName; diff --git a/Editor/MeshWindow.cpp b/Editor/MeshWindow.cpp index d505b5fcb..d8c4c942a 100644 --- a/Editor/MeshWindow.cpp +++ b/Editor/MeshWindow.cpp @@ -42,25 +42,12 @@ void MeshWindow::Create(EditorComponent* _editor) editor->componentsWnd.RefreshEntityTree(); }); - float x = 95; - float y = 0; - float hei = 18; - float step = hei + 2; - float wid = 170; - - float infolabel_height = 360; meshInfoLabel.Create("Mesh Info"); - meshInfoLabel.SetPos(XMFLOAT2(20, y)); - meshInfoLabel.SetSize(XMFLOAT2(260, infolabel_height)); meshInfoLabel.SetColor(wi::Color::Transparent()); + meshInfoLabel.SetFitTextEnabled(true); AddWidget(&meshInfoLabel); - // Left side: - y = infolabel_height + 5; - subsetComboBox.Create("Select subset: "); - subsetComboBox.SetSize(XMFLOAT2(40, hei)); - subsetComboBox.SetPos(XMFLOAT2(x, y)); subsetComboBox.SetEnabled(false); subsetComboBox.OnSelect([=](wi::gui::EventArgs args) { Scene& scene = editor->GetCurrentScene(); @@ -152,8 +139,6 @@ void MeshWindow::Create(EditorComponent* _editor) doubleSidedCheckBox.Create("Double Sided: "); doubleSidedCheckBox.SetTooltip("If enabled, the inside of the mesh will be visible."); - doubleSidedCheckBox.SetSize(XMFLOAT2(hei, hei)); - doubleSidedCheckBox.SetPos(XMFLOAT2(x, y += step)); doubleSidedCheckBox.OnClick([&](wi::gui::EventArgs args) { wi::scene::Scene& scene = editor->GetCurrentScene(); for (auto& x : editor->translator.selected) @@ -168,8 +153,6 @@ void MeshWindow::Create(EditorComponent* _editor) doubleSidedShadowCheckBox.Create("Double Sided Shadow: "); doubleSidedShadowCheckBox.SetTooltip("If enabled, the shadow rendering will be forced to use double sided mode.\nThis can help fix some shadow artifacts without enabling double sided mode for the main rendering of this mesh."); - doubleSidedShadowCheckBox.SetSize(XMFLOAT2(hei, hei)); - doubleSidedShadowCheckBox.SetPos(XMFLOAT2(x, y += step)); doubleSidedShadowCheckBox.OnClick([&](wi::gui::EventArgs args) { wi::scene::Scene& scene = editor->GetCurrentScene(); for (auto& x : editor->translator.selected) @@ -184,8 +167,6 @@ void MeshWindow::Create(EditorComponent* _editor) bvhCheckBox.Create("Enable BVH: "); bvhCheckBox.SetTooltip("Whether to generate BVH (Bounding Volume Hierarchy) for the mesh or not.\nBVH will be used to optimize intersections with the mesh at an additional memory cost.\nIt is recommended to use a BVH for high polygon count meshes that will be used for intersections.\nThis CPU BVH does not support skinned or morphed geometry."); - bvhCheckBox.SetSize(XMFLOAT2(hei, hei)); - bvhCheckBox.SetPos(XMFLOAT2(x, y += step)); bvhCheckBox.OnClick([&](wi::gui::EventArgs args) { wi::scene::Scene& scene = editor->GetCurrentScene(); for (auto& x : editor->translator.selected) @@ -200,8 +181,6 @@ void MeshWindow::Create(EditorComponent* _editor) quantizeCheckBox.Create("Quantization Disabled: "); quantizeCheckBox.SetTooltip("Disable quantization of vertex positions if you notice inaccuracy errors with UNORM position formats."); - quantizeCheckBox.SetSize(XMFLOAT2(hei, hei)); - quantizeCheckBox.SetPos(XMFLOAT2(x, y += step)); quantizeCheckBox.OnClick([&](wi::gui::EventArgs args) { wi::scene::Scene& scene = editor->GetCurrentScene(); for (auto& x : editor->translator.selected) @@ -221,8 +200,6 @@ void MeshWindow::Create(EditorComponent* _editor) impostorCreateButton.Create("Create Impostor"); impostorCreateButton.SetTooltip("Create an impostor image of the mesh. The mesh will be replaced by this image when far away, to render faster."); - impostorCreateButton.SetSize(XMFLOAT2(wid, hei)); - impostorCreateButton.SetPos(XMFLOAT2(x, y += step)); impostorCreateButton.OnClick([&](wi::gui::EventArgs args) { Scene& scene = editor->GetCurrentScene(); ImpostorComponent* impostor = scene.impostors.GetComponent(entity); @@ -241,8 +218,6 @@ void MeshWindow::Create(EditorComponent* _editor) impostorDistanceSlider.Create(0, 1000, 100, 10000, "Impostor Dist: "); impostorDistanceSlider.SetTooltip("Assign the distance where the mesh geometry should be switched to the impostor image."); - impostorDistanceSlider.SetSize(XMFLOAT2(wid, hei)); - impostorDistanceSlider.SetPos(XMFLOAT2(x, y += step)); impostorDistanceSlider.OnSlide([&](wi::gui::EventArgs args) { ImpostorComponent* impostor = editor->GetCurrentScene().impostors.GetComponent(entity); if (impostor != nullptr) @@ -254,8 +229,6 @@ void MeshWindow::Create(EditorComponent* _editor) tessellationFactorSlider.Create(0, 100, 0, 10000, "Tess Factor: "); tessellationFactorSlider.SetTooltip("Set the dynamic tessellation amount. Tessellation should be enabled in the Renderer window and your GPU must support it!"); - tessellationFactorSlider.SetSize(XMFLOAT2(wid, hei)); - tessellationFactorSlider.SetPos(XMFLOAT2(x, y += step)); tessellationFactorSlider.OnSlide([&](wi::gui::EventArgs args) { wi::scene::Scene& scene = editor->GetCurrentScene(); for (auto& x : editor->translator.selected) @@ -268,9 +241,6 @@ void MeshWindow::Create(EditorComponent* _editor) }); AddWidget(&tessellationFactorSlider); - float mod_x = x - 20; - float mod_wid = wid + 40; - instanceSelectButton.Create("Select instances"); instanceSelectButton.SetTooltip("Select all instances that use this mesh."); instanceSelectButton.OnClick([&](wi::gui::EventArgs args) { @@ -295,8 +265,6 @@ void MeshWindow::Create(EditorComponent* _editor) flipCullingButton.Create("Flip Culling"); flipCullingButton.SetTooltip("Flip faces to reverse triangle culling order."); - flipCullingButton.SetSize(XMFLOAT2(mod_wid, hei)); - flipCullingButton.SetPos(XMFLOAT2(mod_x, y += step)); flipCullingButton.OnClick([&](wi::gui::EventArgs args) { wi::scene::Scene& scene = editor->GetCurrentScene(); wi::unordered_set visited_meshes; // fix double visit (straight mesh + object->mesh) @@ -314,8 +282,6 @@ void MeshWindow::Create(EditorComponent* _editor) flipNormalsButton.Create("Flip Normals"); flipNormalsButton.SetTooltip("Flip surface normals."); - flipNormalsButton.SetSize(XMFLOAT2(mod_wid, hei)); - flipNormalsButton.SetPos(XMFLOAT2(mod_x, y += step)); flipNormalsButton.OnClick([&](wi::gui::EventArgs args) { wi::scene::Scene& scene = editor->GetCurrentScene(); wi::unordered_set visited_meshes; // fix double visit (straight mesh + object->mesh) @@ -333,8 +299,6 @@ void MeshWindow::Create(EditorComponent* _editor) computeNormalsSmoothButton.Create("Compute Normals [SMOOTH]"); computeNormalsSmoothButton.SetTooltip("Compute surface normals of the mesh. Resulting normals will be unique per vertex. This can reduce vertex count, but is slow."); - computeNormalsSmoothButton.SetSize(XMFLOAT2(mod_wid, hei)); - computeNormalsSmoothButton.SetPos(XMFLOAT2(mod_x, y += step)); computeNormalsSmoothButton.OnClick([&](wi::gui::EventArgs args) { wi::scene::Scene& scene = editor->GetCurrentScene(); wi::unordered_set visited_meshes; // fix double visit (straight mesh + object->mesh) @@ -352,8 +316,6 @@ void MeshWindow::Create(EditorComponent* _editor) computeNormalsHardButton.Create("Compute Normals [HARD]"); computeNormalsHardButton.SetTooltip("Compute surface normals of the mesh. Resulting normals will be unique per face. This can increase vertex count."); - computeNormalsHardButton.SetSize(XMFLOAT2(mod_wid, hei)); - computeNormalsHardButton.SetPos(XMFLOAT2(mod_x, y += step)); computeNormalsHardButton.OnClick([&](wi::gui::EventArgs args) { wi::scene::Scene& scene = editor->GetCurrentScene(); wi::unordered_set visited_meshes; // fix double visit (straight mesh + object->mesh) @@ -371,8 +333,6 @@ void MeshWindow::Create(EditorComponent* _editor) recenterButton.Create("Recenter"); recenterButton.SetTooltip("Recenter mesh to AABB center."); - recenterButton.SetSize(XMFLOAT2(mod_wid, hei)); - recenterButton.SetPos(XMFLOAT2(mod_x, y += step)); recenterButton.OnClick([&](wi::gui::EventArgs args) { wi::scene::Scene& scene = editor->GetCurrentScene(); wi::unordered_set visited_meshes; // fix double visit (straight mesh + object->mesh) @@ -389,8 +349,6 @@ void MeshWindow::Create(EditorComponent* _editor) recenterToBottomButton.Create("RecenterToBottom"); recenterToBottomButton.SetTooltip("Recenter mesh to AABB bottom."); - recenterToBottomButton.SetSize(XMFLOAT2(mod_wid, hei)); - recenterToBottomButton.SetPos(XMFLOAT2(mod_x, y += step)); recenterToBottomButton.OnClick([&](wi::gui::EventArgs args) { wi::scene::Scene& scene = editor->GetCurrentScene(); wi::unordered_set visited_meshes; // fix double visit (straight mesh + object->mesh) @@ -407,8 +365,6 @@ void MeshWindow::Create(EditorComponent* _editor) mergeButton.Create("Merge Selected"); mergeButton.SetTooltip("Merges selected objects/meshes into one.\nAll selected object transformations will be applied to meshes and all meshes will be baked into a single mesh."); - mergeButton.SetSize(XMFLOAT2(mod_wid, hei)); - mergeButton.SetPos(XMFLOAT2(mod_x, y += step)); mergeButton.OnClick([=](wi::gui::EventArgs args) { Scene& scene = editor->GetCurrentScene(); ObjectComponent merged_object; @@ -680,8 +636,6 @@ void MeshWindow::Create(EditorComponent* _editor) optimizeButton.Create("Optimize"); optimizeButton.SetTooltip("Run the meshoptimizer library."); - optimizeButton.SetSize(XMFLOAT2(mod_wid, hei)); - optimizeButton.SetPos(XMFLOAT2(mod_x, y += step)); optimizeButton.OnClick([&](wi::gui::EventArgs args) { wi::scene::Scene& scene = editor->GetCurrentScene(); for (auto& x : editor->translator.selected) @@ -707,8 +661,6 @@ void MeshWindow::Create(EditorComponent* _editor) exportHeaderButton.Create("Export to C++ header"); exportHeaderButton.SetTooltip("Export vertex positions and index buffer into a C++ header file.\n - Object transformation (if selected through object picking) and Skinning pose will be applied.\n - Only LOD0 will be exported.\n - The generated vertex positions and indices will be reordered and optimized without considering other vertex attributes."); - exportHeaderButton.SetSize(XMFLOAT2(mod_wid, hei)); - exportHeaderButton.SetPos(XMFLOAT2(mod_x, y += step)); exportHeaderButton.OnClick([&](wi::gui::EventArgs args) { wi::helper::FileDialogParams params; params.description = ".h (C++ header file)"; @@ -832,8 +784,6 @@ void MeshWindow::Create(EditorComponent* _editor) subsetMaterialComboBox.Create("Material: "); - subsetMaterialComboBox.SetSize(XMFLOAT2(wid, hei)); - subsetMaterialComboBox.SetPos(XMFLOAT2(x, y += step)); subsetMaterialComboBox.SetEnabled(false); subsetMaterialComboBox.OnSelect([&](wi::gui::EventArgs args) { Scene& scene = editor->GetCurrentScene(); @@ -855,8 +805,6 @@ void MeshWindow::Create(EditorComponent* _editor) morphTargetCombo.Create("Morph Target:"); - morphTargetCombo.SetSize(XMFLOAT2(wid, hei)); - morphTargetCombo.SetPos(XMFLOAT2(x, y += step)); morphTargetCombo.OnSelect([&](wi::gui::EventArgs args) { MeshComponent* mesh = editor->GetCurrentScene().meshes.GetComponent(entity); if (mesh != nullptr && args.iValue < (int)mesh->morph_targets.size()) @@ -869,8 +817,6 @@ void MeshWindow::Create(EditorComponent* _editor) morphTargetSlider.Create(0, 1, 0, 100000, "Weight: "); morphTargetSlider.SetTooltip("Set the weight for morph target"); - morphTargetSlider.SetSize(XMFLOAT2(wid, hei)); - morphTargetSlider.SetPos(XMFLOAT2(x, y += step)); morphTargetSlider.OnSlide([&](wi::gui::EventArgs args) { wi::scene::Scene& scene = editor->GetCurrentScene(); for (auto& x : editor->translator.selected) @@ -888,8 +834,6 @@ void MeshWindow::Create(EditorComponent* _editor) lodgenButton.Create("LOD Gen"); lodgenButton.SetTooltip("Generate LODs (levels of detail)."); - lodgenButton.SetSize(XMFLOAT2(wid, hei)); - lodgenButton.SetPos(XMFLOAT2(x, y += step)); lodgenButton.OnClick([&](wi::gui::EventArgs args) { wi::scene::Scene& scene = editor->GetCurrentScene(); for (auto& x : editor->translator.selected) @@ -1008,26 +952,18 @@ void MeshWindow::Create(EditorComponent* _editor) lodCountSlider.Create(2, 10, 6, 8, "LOD Count: "); lodCountSlider.SetTooltip("This is how many levels of detail will be created."); - lodCountSlider.SetSize(XMFLOAT2(wid, hei)); - lodCountSlider.SetPos(XMFLOAT2(x, y += step)); AddWidget(&lodCountSlider); lodQualitySlider.Create(0.1f, 1.0f, 0.5f, 10000, "LOD Quality: "); lodQualitySlider.SetTooltip("Lower values will make LODs more agressively simplified."); - lodQualitySlider.SetSize(XMFLOAT2(wid, hei)); - lodQualitySlider.SetPos(XMFLOAT2(x, y += step)); AddWidget(&lodQualitySlider); lodErrorSlider.Create(0.01f, 0.1f, 0.03f, 10000, "LOD Error: "); lodErrorSlider.SetTooltip("Lower values will make more precise levels of detail."); - lodErrorSlider.SetSize(XMFLOAT2(wid, hei)); - lodErrorSlider.SetPos(XMFLOAT2(x, y += step)); AddWidget(&lodErrorSlider); lodSloppyCheckBox.Create("Sloppy LOD: "); lodSloppyCheckBox.SetTooltip("Use the sloppy simplification algorithm, which is faster but doesn't preserve shape well."); - lodSloppyCheckBox.SetSize(XMFLOAT2(hei, hei)); - lodSloppyCheckBox.SetPos(XMFLOAT2(x, y += step)); AddWidget(&lodSloppyCheckBox); diff --git a/Editor/PaintToolWindow.cpp b/Editor/PaintToolWindow.cpp index d97247756..1382909a8 100644 --- a/Editor/PaintToolWindow.cpp +++ b/Editor/PaintToolWindow.cpp @@ -15,19 +15,10 @@ void PaintToolWindow::Create(EditorComponent* _editor) SetText("Paint Tool " ICON_PAINTTOOL); SetSize(XMFLOAT2(300, 800)); - float x = 105; - float y = 0; - float hei = 20; - float step = hei + 4; - float wid = 160; - colorPicker.Create("Color", wi::gui::Window::WindowControls::NONE); - float mod_wid = colorPicker.GetScale().x; modeComboBox.Create("Mode: "); modeComboBox.SetTooltip("Choose paint tool mode"); - modeComboBox.SetPos(XMFLOAT2(x, y)); - modeComboBox.SetSize(XMFLOAT2(wid, hei)); modeComboBox.AddItem(ICON_DISABLED " Disabled", MODE_DISABLED); modeComboBox.AddItem(ICON_MATERIAL " Texture", MODE_TEXTURE); modeComboBox.AddItem(ICON_MESH " Vertexcolor", MODE_VERTEXCOLOR); @@ -111,20 +102,13 @@ void PaintToolWindow::Create(EditorComponent* _editor) }); AddWidget(&modeComboBox); - y += step + 5; - infoLabel.Create("Paint Tool is disabled."); - infoLabel.SetSize(XMFLOAT2(mod_wid - 10, 100)); - infoLabel.SetPos(XMFLOAT2(5, y)); infoLabel.SetColor(wi::Color::Transparent()); + infoLabel.SetFitTextEnabled(true); AddWidget(&infoLabel); - y += infoLabel.GetScale().y - step + 5; - radiusSlider.Create(0.1f, 20.0f, 1, 10000, "Brush Radius: "); radiusSlider.SetTooltip("Set the brush radius in pixel units"); - radiusSlider.SetSize(XMFLOAT2(wid, hei)); - radiusSlider.SetPos(XMFLOAT2(x, y += step)); radiusSlider.OnSlide([this](wi::gui::EventArgs args) { if (GetMode() == MODE_TEXTURE) { @@ -143,32 +127,22 @@ void PaintToolWindow::Create(EditorComponent* _editor) amountSlider.Create(0, 1, 1, 10000, "Power: "); amountSlider.SetTooltip("Set the brush power amount. 0 = minimum affection, 1 = maximum affection"); - amountSlider.SetSize(XMFLOAT2(wid, hei)); - amountSlider.SetPos(XMFLOAT2(x, y += step)); AddWidget(&amountSlider); smoothnessSlider.Create(0, 2, 1, 10000, "Smoothness: "); smoothnessSlider.SetTooltip("Set the brush smoothness. 0 = hard, increase for more smoothness"); - smoothnessSlider.SetSize(XMFLOAT2(wid, hei)); - smoothnessSlider.SetPos(XMFLOAT2(x, y += step)); AddWidget(&smoothnessSlider); spacingSlider.Create(0, 500, 1, 500, "Spacing: "); spacingSlider.SetTooltip("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."); - spacingSlider.SetSize(XMFLOAT2(wid, hei)); - spacingSlider.SetPos(XMFLOAT2(x, y += step)); AddWidget(&spacingSlider); rotationSlider.Create(0, 1, 0, 10000, "Rotation: "); rotationSlider.SetTooltip("Brush rotation randomness. This will affect the splat mode brush texture."); - rotationSlider.SetSize(XMFLOAT2(wid, hei)); - rotationSlider.SetPos(XMFLOAT2(x, y += step)); AddWidget(&rotationSlider); stabilizerSlider.Create(1, 15, 2, 14, "Stabilizer: "); stabilizerSlider.SetTooltip("The stabilizer generates a small delay between user input and painting, which will be used to compute a smoother paint stroke.."); - stabilizerSlider.SetSize(XMFLOAT2(wid, hei)); - stabilizerSlider.SetPos(XMFLOAT2(x, y += step)); if (editor->main->config.GetSection("paint_tool").Has("stabilizer")) { stabilizerSlider.SetValue((float)editor->main->config.GetSection("paint_tool").GetInt("stabilizer")); @@ -181,8 +155,6 @@ void PaintToolWindow::Create(EditorComponent* _editor) backfaceCheckBox.Create("Backfaces: "); backfaceCheckBox.SetTooltip("Set whether to paint on backfaces of geometry or not"); - backfaceCheckBox.SetSize(XMFLOAT2(hei, hei)); - backfaceCheckBox.SetPos(XMFLOAT2(x - 20, y += step)); if (editor->main->config.GetSection("paint_tool").Has("backfaces")) { backfaceCheckBox.SetCheck(editor->main->config.GetSection("paint_tool").GetBool("backfaces")); @@ -195,8 +167,6 @@ void PaintToolWindow::Create(EditorComponent* _editor) wireCheckBox.Create("Wireframe: "); wireCheckBox.SetTooltip("Set whether to draw wireframe on top of geometry or not"); - wireCheckBox.SetSize(XMFLOAT2(hei, hei)); - wireCheckBox.SetPos(XMFLOAT2(x - 20 + 100, y)); wireCheckBox.SetCheck(false); if (editor->main->config.GetSection("paint_tool").Has("wireframe")) { @@ -210,8 +180,6 @@ void PaintToolWindow::Create(EditorComponent* _editor) pressureCheckBox.Create("Pressure: "); pressureCheckBox.SetTooltip("Set whether to use pressure sensitivity (for example pen tablet)"); - pressureCheckBox.SetSize(XMFLOAT2(hei, hei)); - pressureCheckBox.SetPos(XMFLOAT2(x - 20 + 200, y)); if (editor->main->config.GetSection("paint_tool").Has("pressure")) { pressureCheckBox.SetCheck(editor->main->config.GetSection("paint_tool").GetBool("pressure")); @@ -225,36 +193,25 @@ void PaintToolWindow::Create(EditorComponent* _editor) alphaCheckBox.Create("Redirect alpha: "); alphaCheckBox.SetTooltip("The red color will be redirected to write alpha channel. Alpha value controls the blending like normally."); - alphaCheckBox.SetSize(XMFLOAT2(hei, hei)); - alphaCheckBox.SetPos(XMFLOAT2(x - 20 + 200, y)); AddWidget(&alphaCheckBox); terrainCheckBox.Create("Terrain only: "); terrainCheckBox.SetTooltip("Terrain specific sculpting mode."); - terrainCheckBox.SetSize(XMFLOAT2(hei, hei)); - terrainCheckBox.SetPos(XMFLOAT2(x - 20 + 200, y)); terrainCheckBox.SetCheckText(ICON_TERRAIN); AddWidget(&terrainCheckBox); axisCombo.Create("Axis Lock: "); axisCombo.SetTooltip("You can lock modification to an axis here."); - axisCombo.SetPos(XMFLOAT2(x, y)); - axisCombo.SetSize(XMFLOAT2(wid, hei)); axisCombo.AddItem(ICON_DISABLED, (uint64_t)AxisLock::Disabled); axisCombo.AddItem("X " ICON_LEFT_RIGHT, (uint64_t)AxisLock::X); axisCombo.AddItem("Y " ICON_UP_DOWN, (uint64_t)AxisLock::Y); axisCombo.AddItem("Z " ICON_UPRIGHT_DOWNLEFT, (uint64_t)AxisLock::Z); AddWidget(&axisCombo); - colorPicker.SetPos(XMFLOAT2(5, y += step)); AddWidget(&colorPicker); - y += colorPicker.GetScale().y; - textureSlotComboBox.Create("Texture Slot: "); textureSlotComboBox.SetTooltip("Choose texture slot of the selected material to paint (texture paint mode only)"); - textureSlotComboBox.SetPos(XMFLOAT2(x, y += step)); - textureSlotComboBox.SetSize(XMFLOAT2(wid, hei)); textureSlotComboBox.AddItem("BaseColor (RGBA)", MaterialComponent::BASECOLORMAP); textureSlotComboBox.AddItem("Normal (RGB)", MaterialComponent::NORMALMAP); textureSlotComboBox.AddItem("SurfaceMap (RGBA)", MaterialComponent::SURFACEMAP); @@ -275,8 +232,6 @@ void PaintToolWindow::Create(EditorComponent* _editor) brushShapeComboBox.Create("Brush Shape: "); brushShapeComboBox.SetTooltip("Choose shape for brush masking effect"); - brushShapeComboBox.SetPos(XMFLOAT2(x, y += step)); - brushShapeComboBox.SetSize(XMFLOAT2(wid, hei)); brushShapeComboBox.AddItem(ICON_CIRCLE); brushShapeComboBox.AddItem(ICON_SQUARE); brushShapeComboBox.SetSelected(0); @@ -284,8 +239,6 @@ void PaintToolWindow::Create(EditorComponent* _editor) saveTextureButton.Create("Save Texture"); saveTextureButton.SetTooltip("Save edited texture."); - saveTextureButton.SetSize(XMFLOAT2(wid, hei)); - saveTextureButton.SetPos(XMFLOAT2(x, y += step)); saveTextureButton.OnClick([this] (wi::gui::EventArgs args) { Scene& scene = editor->GetCurrentScene(); @@ -331,8 +284,6 @@ void PaintToolWindow::Create(EditorComponent* _editor) brushTextureButton.Create(""); brushTextureButton.SetDescription("Brush tex: "); brushTextureButton.SetTooltip("Open an image to use as brush texture (splatting mode).\nSplat mode means that the texture will be relative to the brush position"); - brushTextureButton.SetSize(XMFLOAT2(hei*2, hei*2)); - brushTextureButton.SetPos(XMFLOAT2(x, y += step)); brushTextureButton.sprites[wi::gui::IDLE].params.color = wi::Color::White(); brushTextureButton.sprites[wi::gui::FOCUS].params.color = wi::Color::Gray(); brushTextureButton.sprites[wi::gui::ACTIVE].params.color = wi::Color::White(); @@ -362,8 +313,6 @@ void PaintToolWindow::Create(EditorComponent* _editor) revealTextureButton.Create(""); revealTextureButton.SetDescription("Reveal tex: "); revealTextureButton.SetTooltip("Open an image to use as reveal mode texture.\nReveal mode means that the texture will use the UV of the mesh. It will be multiplied by brush tex."); - revealTextureButton.SetSize(XMFLOAT2(hei * 2, hei * 2)); - revealTextureButton.SetPos(XMFLOAT2(x + 150, y)); revealTextureButton.sprites[wi::gui::IDLE].params.color = wi::Color::White(); revealTextureButton.sprites[wi::gui::FOCUS].params.color = wi::Color::Gray(); revealTextureButton.sprites[wi::gui::ACTIVE].params.color = wi::Color::White(); diff --git a/Editor/RigidBodyWindow.cpp b/Editor/RigidBodyWindow.cpp index eeb8ac189..5ecd74d75 100644 --- a/Editor/RigidBodyWindow.cpp +++ b/Editor/RigidBodyWindow.cpp @@ -379,7 +379,7 @@ void RigidBodyWindow::Create(EditorComponent* _editor) characterLabel.Create("CharacterLabel"); characterLabel.SetText("Notes about physics-driven character:\n- The capsule shape is recommended for a physics character.\n- The friction and mass of the physics character are taken from the standard rigid body parameters.\n- This is different from CharacterComponent which uses custom character movement logic."); - characterLabel.SetSize(XMFLOAT2(100, 160)); + characterLabel.SetFitTextEnabled(true); AddWidget(&characterLabel); characterSlopeSlider.Create(0, 90, 50, 90, "Max slope angle: "); @@ -425,7 +425,7 @@ void RigidBodyWindow::Create(EditorComponent* _editor) tips += "- Enable physics visualizer while editing vehicle parameters\n"; tips += "- You can reset vehicles by Ctrl + left click on the physics toggle button\n"; vehicleLabel.SetText(tips); - vehicleLabel.SetSize(XMFLOAT2(100, 240)); + vehicleLabel.SetFitTextEnabled(true); AddWidget(&vehicleLabel); vehicleCombo.Create(ICON_VEHICLE " Vehicle physics: "); diff --git a/Editor/SoftBodyWindow.cpp b/Editor/SoftBodyWindow.cpp index c4499ff40..a6c9453ac 100644 --- a/Editor/SoftBodyWindow.cpp +++ b/Editor/SoftBodyWindow.cpp @@ -36,21 +36,13 @@ void SoftBodyWindow::Create(EditorComponent* _editor) editor->componentsWnd.RefreshEntityTree(); }); - float x = 95; - float y = 0; - float hei = 18; - float step = hei + 2; - float wid = 170; - infoLabel.Create(""); infoLabel.SetText("Soft body physics must be used together with a MeshComponent, otherwise it will have no effect.\nYou can use the Paint Tool to pin or soften soft body vertices."); - infoLabel.SetSize(XMFLOAT2(100, 90)); + infoLabel.SetFitTextEnabled(true); AddWidget(&infoLabel); resetButton.Create("Reset"); resetButton.SetTooltip("Set the detail to keep between simulation and graphics mesh.\nLower = less detailed, higher = more detailed."); - resetButton.SetSize(XMFLOAT2(wid, hei)); - resetButton.SetPos(XMFLOAT2(x, y)); resetButton.OnClick([&](wi::gui::EventArgs args) { wi::scene::Scene& scene = editor->GetCurrentScene(); for (auto& x : editor->translator.selected) @@ -75,8 +67,6 @@ void SoftBodyWindow::Create(EditorComponent* _editor) detailSlider.Create(0.001f, 1, 1, 1000, "LOD Detail: "); detailSlider.SetTooltip("Set the detail to keep between simulation and graphics mesh.\nLower = less detailed, higher = more detailed."); - detailSlider.SetSize(XMFLOAT2(wid, hei)); - detailSlider.SetPos(XMFLOAT2(x, y)); detailSlider.OnSlide([&](wi::gui::EventArgs args) { wi::scene::Scene& scene = editor->GetCurrentScene(); for (auto& x : editor->translator.selected) @@ -101,8 +91,6 @@ void SoftBodyWindow::Create(EditorComponent* _editor) massSlider.Create(0, 100, 1, 100000, "Mass: "); massSlider.SetTooltip("Set the mass amount for the physics engine."); - massSlider.SetSize(XMFLOAT2(wid, hei)); - massSlider.SetPos(XMFLOAT2(x, y)); massSlider.OnSlide([&](wi::gui::EventArgs args) { wi::scene::Scene& scene = editor->GetCurrentScene(); for (auto& x : editor->translator.selected) @@ -128,8 +116,6 @@ void SoftBodyWindow::Create(EditorComponent* _editor) frictionSlider.Create(0, 1, 0.5f, 100000, "Friction: "); frictionSlider.SetTooltip("Set the friction amount for the physics engine."); - frictionSlider.SetSize(XMFLOAT2(wid, hei)); - frictionSlider.SetPos(XMFLOAT2(x, y += step)); frictionSlider.OnSlide([&](wi::gui::EventArgs args) { wi::scene::Scene& scene = editor->GetCurrentScene(); for (auto& x : editor->translator.selected) @@ -154,8 +140,6 @@ void SoftBodyWindow::Create(EditorComponent* _editor) restitutionSlider.Create(0, 1, 0, 100000, "Restitution: "); restitutionSlider.SetTooltip("Set the restitution amount for the physics engine."); - restitutionSlider.SetSize(XMFLOAT2(wid, hei)); - restitutionSlider.SetPos(XMFLOAT2(x, y += step)); restitutionSlider.OnSlide([&](wi::gui::EventArgs args) { wi::scene::Scene& scene = editor->GetCurrentScene(); for (auto& x : editor->translator.selected) @@ -180,8 +164,6 @@ void SoftBodyWindow::Create(EditorComponent* _editor) pressureSlider.Create(0, 100000, 0, 100000, "Pressure: "); pressureSlider.SetTooltip("Set the pressure amount for the physics engine."); - pressureSlider.SetSize(XMFLOAT2(wid, hei)); - pressureSlider.SetPos(XMFLOAT2(x, y += step)); pressureSlider.OnSlide([&](wi::gui::EventArgs args) { wi::scene::Scene& scene = editor->GetCurrentScene(); for (auto& x : editor->translator.selected) @@ -207,8 +189,6 @@ void SoftBodyWindow::Create(EditorComponent* _editor) vertexRadiusSlider.Create(0, 1, 0, 100000, "Vertex Radius: "); vertexRadiusSlider.SetTooltip("Set how much distance vertices should keep from other physics bodies."); - vertexRadiusSlider.SetSize(XMFLOAT2(wid, hei)); - vertexRadiusSlider.SetPos(XMFLOAT2(x, y += step)); vertexRadiusSlider.OnSlide([&](wi::gui::EventArgs args) { wi::scene::Scene& scene = editor->GetCurrentScene(); for (auto& x : editor->translator.selected) @@ -234,8 +214,6 @@ void SoftBodyWindow::Create(EditorComponent* _editor) windCheckbox.Create("Wind: "); windCheckbox.SetTooltip("Enable/disable wind force on this soft body."); - windCheckbox.SetSize(XMFLOAT2(hei, hei)); - windCheckbox.SetPos(XMFLOAT2(x, y += step)); windCheckbox.OnClick([&](wi::gui::EventArgs args) { wi::scene::Scene& scene = editor->GetCurrentScene(); for (auto& x : editor->translator.selected) diff --git a/Editor/SplineWindow.cpp b/Editor/SplineWindow.cpp index 1347b3e9c..9427eb848 100644 --- a/Editor/SplineWindow.cpp +++ b/Editor/SplineWindow.cpp @@ -27,7 +27,8 @@ void SplineWindow::Create(EditorComponent* _editor) infoLabel.Create("SplineInfo"); infoLabel.SetSize(XMFLOAT2(100, 120)); - infoLabel.SetText("The spline is a curve that goes through every specified entity that has a TransformComponent smoothly. A mesh can be generated from it automatically by increasing the subdivisions. It can also modify terrain when the terrain modification slider is used."); + infoLabel.SetText("The spline is a curve that goes through every specified entity that has a TransformComponent smoothly. A mesh can be generated from it automatically by increasing the subdivisions. It can also modify terrain when the terrain modification slider is used. The terrain texture can also be modified if the spline has a material."); + infoLabel.SetFitTextEnabled(true); AddWidget(&infoLabel); loopedCheck.Create("Looped: "); @@ -181,6 +182,50 @@ void SplineWindow::Create(EditorComponent* _editor) }); AddWidget(&terrainSlider); + terrainTexSlider.Create(0, 1, 0, 100, "Terrain texture falloff: "); + terrainTexSlider.SetTooltip("Affects the terrain texturing falloff when spline is terrain modifying."); + terrainTexSlider.OnSlide([this](wi::gui::EventArgs args) { + wi::scene::Scene& scene = editor->GetCurrentScene(); + for (auto& x : editor->translator.selected) + { + SplineComponent* spline = scene.splines.GetComponent(x.entity); + if (spline == nullptr) + continue; + spline->terrain_texture_falloff = args.fValue; + } + + // indirect set: + SplineComponent* spline = scene.splines.GetComponent(entity); + if (spline != nullptr) + { + spline->terrain_texture_falloff = args.fValue; + } + editor->componentsWnd.RefreshEntityTree(); + }); + AddWidget(&terrainTexSlider); + + terrainPushdownSlider.Create(0, 10, 0, 100, "Terrain push down: "); + terrainPushdownSlider.SetTooltip("Push down the terrain genetry from the spline plane by an amount."); + terrainPushdownSlider.OnSlide([this](wi::gui::EventArgs args) { + wi::scene::Scene& scene = editor->GetCurrentScene(); + for (auto& x : editor->translator.selected) + { + SplineComponent* spline = scene.splines.GetComponent(x.entity); + if (spline == nullptr) + continue; + spline->terrain_pushdown = args.fValue; + } + + // indirect set: + SplineComponent* spline = scene.splines.GetComponent(entity); + if (spline != nullptr) + { + spline->terrain_pushdown = args.fValue; + } + editor->componentsWnd.RefreshEntityTree(); + }); + AddWidget(&terrainPushdownSlider); + addButton.Create("AddNode"); addButton.SetText("+"); addButton.SetTooltip("Add an entity as a node to the spline (it must have TransformComponent). Hotkey: Ctrl + E"); @@ -214,6 +259,8 @@ void SplineWindow::SetEntity(Entity entity) subdivSlider.SetValue(spline->mesh_generation_subdivision); subdivVerticalSlider.SetValue(spline->mesh_generation_vertical_subdivision); terrainSlider.SetValue(spline->terrain_modifier_amount); + terrainPushdownSlider.SetValue(spline->terrain_pushdown); + terrainTexSlider.SetValue(spline->terrain_texture_falloff); if (changed) { @@ -354,6 +401,8 @@ void SplineWindow::ResizeLayout() add(subdivSlider); add(subdivVerticalSlider); add(terrainSlider); + add(terrainPushdownSlider); + add(terrainTexSlider); add(widthSlider); add(rotSlider); add_right(loopedCheck); diff --git a/Editor/SplineWindow.h b/Editor/SplineWindow.h index c21e18aff..f698f3d9d 100644 --- a/Editor/SplineWindow.h +++ b/Editor/SplineWindow.h @@ -18,6 +18,8 @@ public: wi::gui::Slider subdivSlider; wi::gui::Slider subdivVerticalSlider; wi::gui::Slider terrainSlider; + wi::gui::Slider terrainTexSlider; + wi::gui::Slider terrainPushdownSlider; wi::gui::Button addButton; struct Entry diff --git a/Editor/VideoWindow.cpp b/Editor/VideoWindow.cpp index 1c21206bf..ce3e9ccd7 100644 --- a/Editor/VideoWindow.cpp +++ b/Editor/VideoWindow.cpp @@ -47,17 +47,9 @@ void VideoWindow::Create(EditorComponent* _editor) editor->componentsWnd.RefreshEntityTree(); }); - float x = 60; - float y = 0; - float hei = 18; - float step = hei + 2; - float wid = 200; - openButton.Create("Open File " ICON_OPEN); openButton.SetTooltip("Open video file.\nSupported extensions: MP4"); - openButton.SetPos(XMFLOAT2(x, y)); - openButton.SetSize(XMFLOAT2(wid, hei)); openButton.OnClick([&](wi::gui::EventArgs args) { VideoComponent* video = editor->GetCurrentScene().videos.GetComponent(entity); if (video != nullptr) @@ -79,14 +71,10 @@ void VideoWindow::Create(EditorComponent* _editor) AddWidget(&openButton); filenameLabel.Create("Filename"); - filenameLabel.SetPos(XMFLOAT2(x, y += step)); - filenameLabel.SetSize(XMFLOAT2(wid, hei)); AddWidget(&filenameLabel); playpauseButton.Create(ICON_PLAY); playpauseButton.SetTooltip("Play/Pause selected video instance."); - playpauseButton.SetPos(XMFLOAT2(x, y += step)); - playpauseButton.SetSize(XMFLOAT2(wid, hei)); playpauseButton.OnClick([&](wi::gui::EventArgs args) { VideoComponent* video = editor->GetCurrentScene().videos.GetComponent(entity); if (video != nullptr) @@ -107,8 +95,6 @@ void VideoWindow::Create(EditorComponent* _editor) stopButton.Create(ICON_STOP); stopButton.SetTooltip("Stop selected video instance."); - stopButton.SetPos(XMFLOAT2(x, y += step)); - stopButton.SetSize(XMFLOAT2(hei, hei)); stopButton.OnClick([&](wi::gui::EventArgs args) { VideoComponent* video = editor->GetCurrentScene().videos.GetComponent(entity); if (video != nullptr) @@ -123,8 +109,6 @@ void VideoWindow::Create(EditorComponent* _editor) loopedCheckbox.Create("Looped: "); loopedCheckbox.SetTooltip("Enable looping for the selected video instance."); - loopedCheckbox.SetPos(XMFLOAT2(x, y += step)); - loopedCheckbox.SetSize(XMFLOAT2(hei, hei)); loopedCheckbox.SetCheckText(ICON_LOOP); loopedCheckbox.OnClick([&](wi::gui::EventArgs args) { VideoComponent* video = editor->GetCurrentScene().videos.GetComponent(entity); @@ -136,7 +120,6 @@ void VideoWindow::Create(EditorComponent* _editor) AddWidget(&loopedCheckbox); timerSlider.Create(0, 1, 0, 100000, "Timer: "); - timerSlider.SetSize(XMFLOAT2(hei, hei)); timerSlider.OnSlide([&](wi::gui::EventArgs args) { VideoComponent* video = editor->GetCurrentScene().videos.GetComponent(entity); if (video != nullptr && video->videoResource.IsValid()) @@ -159,11 +142,10 @@ void VideoWindow::Create(EditorComponent* _editor) }); AddWidget(&timerSlider); - preview.SetSize(XMFLOAT2(160, 90)); AddWidget(&preview); infoLabel.Create(""); - infoLabel.SetSize(XMFLOAT2(800, 500)); + infoLabel.SetFitTextEnabled(true); AddWidget(&infoLabel); diff --git a/Editor/VoxelGridWindow.cpp b/Editor/VoxelGridWindow.cpp index b267c763a..aa4021a18 100644 --- a/Editor/VoxelGridWindow.cpp +++ b/Editor/VoxelGridWindow.cpp @@ -24,18 +24,11 @@ void VoxelGridWindow::Create(EditorComponent* _editor) editor->componentsWnd.RefreshEntityTree(); }); - float x = 80; - float y = 0; - float hei = 18; - float wid = 200; - float step = hei + 4; - infoLabel.Create(""); - infoLabel.SetSize(XMFLOAT2(100, 150)); + infoLabel.SetFitTextEnabled(true); AddWidget(&infoLabel); dimXInput.Create("DimX"); - dimXInput.SetSize(XMFLOAT2(100, hei)); dimXInput.SetDescription("Dimension X: "); dimXInput.OnInputAccepted([=](wi::gui::EventArgs args) { Scene& scene = editor->GetCurrentScene(); @@ -47,7 +40,6 @@ void VoxelGridWindow::Create(EditorComponent* _editor) AddWidget(&dimXInput); dimYInput.Create("DimY"); - dimYInput.SetSize(XMFLOAT2(100, hei)); dimYInput.SetDescription("Y: "); dimYInput.OnInputAccepted([=](wi::gui::EventArgs args) { Scene& scene = editor->GetCurrentScene(); @@ -59,7 +51,6 @@ void VoxelGridWindow::Create(EditorComponent* _editor) AddWidget(&dimYInput); dimZInput.Create("DimZ"); - dimZInput.SetSize(XMFLOAT2(100, hei)); dimZInput.SetDescription("Z: "); dimZInput.OnInputAccepted([=](wi::gui::EventArgs args) { Scene& scene = editor->GetCurrentScene(); @@ -71,7 +62,6 @@ void VoxelGridWindow::Create(EditorComponent* _editor) AddWidget(&dimZInput); clearButton.Create("Clear voxels " ICON_CLEARVOXELS); - clearButton.SetSize(XMFLOAT2(100, hei)); clearButton.OnClick([=](wi::gui::EventArgs args) { Scene& scene = editor->GetCurrentScene(); wi::VoxelGrid* voxelgrid = scene.voxel_grids.GetComponent(entity); @@ -83,7 +73,6 @@ void VoxelGridWindow::Create(EditorComponent* _editor) voxelizeObjectsButton.Create("Voxelize objects " ICON_VOXELIZE); voxelizeObjectsButton.SetTooltip("Generate navigation grid including all meshes."); - voxelizeObjectsButton.SetSize(XMFLOAT2(100, hei)); voxelizeObjectsButton.OnClick([=](wi::gui::EventArgs args) { Scene& scene = editor->GetCurrentScene(); wi::VoxelGrid* voxelgrid = scene.voxel_grids.GetComponent(entity); @@ -95,7 +84,6 @@ void VoxelGridWindow::Create(EditorComponent* _editor) voxelizeNavigationButton.Create("Voxelize navigation " ICON_VOXELIZE); voxelizeNavigationButton.SetTooltip("Generate navigation grid including all navmeshes (object tagged as navmesh)."); - voxelizeNavigationButton.SetSize(XMFLOAT2(100, hei)); voxelizeNavigationButton.OnClick([=](wi::gui::EventArgs args) { Scene& scene = editor->GetCurrentScene(); wi::VoxelGrid* voxelgrid = scene.voxel_grids.GetComponent(entity); @@ -107,7 +95,6 @@ void VoxelGridWindow::Create(EditorComponent* _editor) voxelizeCollidersButton.Create("Voxelize CPU colliders " ICON_VOXELIZE); voxelizeCollidersButton.SetTooltip("Generate navigation grid including all CPU colliders."); - voxelizeCollidersButton.SetSize(XMFLOAT2(100, hei)); voxelizeCollidersButton.OnClick([=](wi::gui::EventArgs args) { Scene& scene = editor->GetCurrentScene(); wi::VoxelGrid* voxelgrid = scene.voxel_grids.GetComponent(entity); @@ -119,7 +106,6 @@ void VoxelGridWindow::Create(EditorComponent* _editor) floodfillButton.Create("Flood fill " ICON_VOXELFILL); floodfillButton.SetTooltip("Fill enclosed empty voxel areas to solid.\nThis can take long if there are large enclosed empty areas."); - floodfillButton.SetSize(XMFLOAT2(100, hei)); floodfillButton.OnClick([=](wi::gui::EventArgs args) { Scene& scene = editor->GetCurrentScene(); wi::VoxelGrid* voxelgrid = scene.voxel_grids.GetComponent(entity); @@ -133,7 +119,6 @@ void VoxelGridWindow::Create(EditorComponent* _editor) fitToSceneButton.Create("Fit bounds to scene " ICON_VOXELBOUNDS); fitToSceneButton.SetTooltip("Fit the bounds of the voxel grid onto the whole scene."); - fitToSceneButton.SetSize(XMFLOAT2(100, hei)); fitToSceneButton.OnClick([=](wi::gui::EventArgs args) { Scene& scene = editor->GetCurrentScene(); if (scene.bounds.getArea() < 0) @@ -155,7 +140,6 @@ void VoxelGridWindow::Create(EditorComponent* _editor) generateMeshButton.Create("Generate Mesh " ICON_MESH); generateMeshButton.SetTooltip("Generate a mesh from the voxels."); - generateMeshButton.SetSize(XMFLOAT2(100, hei)); generateMeshButton.OnClick([=](wi::gui::EventArgs args) { Scene& scene = editor->GetCurrentScene(); wi::VoxelGrid* voxelgrid = scene.voxel_grids.GetComponent(entity); @@ -175,7 +159,6 @@ void VoxelGridWindow::Create(EditorComponent* _editor) generateSimplifiedMeshButton.Create("Generate Simplified Mesh " ICON_MESH); generateSimplifiedMeshButton.SetTooltip("Generate a simplified mesh from the voxels."); - generateSimplifiedMeshButton.SetSize(XMFLOAT2(100, hei)); generateSimplifiedMeshButton.OnClick([=](wi::gui::EventArgs args) { Scene& scene = editor->GetCurrentScene(); wi::VoxelGrid* voxelgrid = scene.voxel_grids.GetComponent(entity); @@ -195,7 +178,6 @@ void VoxelGridWindow::Create(EditorComponent* _editor) generateNavMeshButton.Create("Generate Navigation Mesh " ICON_NAVIGATION); generateNavMeshButton.SetTooltip("Generate a simplified navigation mesh from the voxels."); - generateNavMeshButton.SetSize(XMFLOAT2(100, hei)); generateNavMeshButton.OnClick([=](wi::gui::EventArgs args) { Scene& scene = editor->GetCurrentScene(); wi::VoxelGrid* voxelgrid = scene.voxel_grids.GetComponent(entity); @@ -226,12 +208,10 @@ void VoxelGridWindow::Create(EditorComponent* _editor) subtractCheckBox.Create("Subtraction mode: "); subtractCheckBox.SetTooltip("If enabled, voxelization will be subtractive, so it will remove voxels instead of add."); - subtractCheckBox.SetSize(XMFLOAT2(hei, hei)); AddWidget(&subtractCheckBox); debugAllCheckBox.Create("Debug draw all: "); debugAllCheckBox.SetTooltip("Draw all voxel grids, whether they are selected or not."); - debugAllCheckBox.SetSize(XMFLOAT2(hei, hei)); AddWidget(&debugAllCheckBox); diff --git a/WickedEngine/wiGUI.cpp b/WickedEngine/wiGUI.cpp index 8eb74e967..c700ae4af 100644 --- a/WickedEngine/wiGUI.cpp +++ b/WickedEngine/wiGUI.cpp @@ -1339,9 +1339,16 @@ namespace wi::gui break; } + const float textheight = font.TextHeight(); + + if (fittext_enabled) + { + SetSize(XMFLOAT2(GetSize().x, textheight + 4 + margin_top + margin_bottom)); + } + if (scrollbar.IsEnabled()) { - scrollbar.SetListLength(font.TextHeight()); + scrollbar.SetListLength(textheight); scrollbar.ClearTransform(); scrollbar.SetPos(XMFLOAT2(translation.x + scale.x - scrollbar_width, translation.y)); scrollbar.SetSize(XMFLOAT2(scrollbar_width, scale.y)); @@ -3350,20 +3357,7 @@ namespace wi::gui 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) + if (collapseButton.parent) { collapseButton.sprites[i].params.enableCornerRounding(); collapseButton.sprites[i].params.corners_rounding[0].radius = sprites[state].params.corners_rounding[0].radius; @@ -3404,7 +3398,20 @@ namespace wi::gui } // Right side: - if (moveDragger.parent) + if (closeButton.parent) + { + closeButton.sprites[i].params.enableCornerRounding(); + closeButton.sprites[i].params.corners_rounding[1].radius = sprites[state].params.corners_rounding[1].radius; + if (IsCollapsed()) + { + closeButton.sprites[i].params.corners_rounding[3].radius = sprites[state].params.corners_rounding[3].radius; + } + else + { + closeButton.sprites[i].params.corners_rounding[3].radius = 0; + } + } + else if (moveDragger.parent) { moveDragger.sprites[i].params.enableCornerRounding(); moveDragger.sprites[i].params.corners_rounding[1].radius = sprites[state].params.corners_rounding[1].radius; @@ -4035,10 +4042,6 @@ namespace wi::gui } moveDragger.SetSize(XMFLOAT2(scale.x - control_size * rem, control_size)); float offset = 0; - if (closeButton.parent != nullptr) - { - offset++; - } if (collapseButton.parent != nullptr) { offset++; @@ -4050,20 +4053,14 @@ namespace wi::gui { closeButton.Detach(); closeButton.SetSize(XMFLOAT2(control_size, control_size)); - float offset = 0; - closeButton.SetPos(XMFLOAT2(translation.x + control_size * offset, translation.y)); + closeButton.SetPos(XMFLOAT2(translation.x + scale.x - control_size, translation.y)); closeButton.AttachTo(this); } if (collapseButton.parent != nullptr) { collapseButton.Detach(); collapseButton.SetSize(XMFLOAT2(control_size, control_size)); - float offset = 0; - if (closeButton.parent != nullptr) - { - offset++; - } - collapseButton.SetPos(XMFLOAT2(translation.x + control_size * offset, translation.y)); + collapseButton.SetPos(XMFLOAT2(translation.x, translation.y)); collapseButton.AttachTo(this); } if (label.parent != nullptr) @@ -4075,7 +4072,6 @@ namespace wi::gui if (closeButton.parent != nullptr) { label_size.x -= control_size; - label_pos.x += control_size; } if (collapseButton.parent != nullptr) { diff --git a/WickedEngine/wiGUI.h b/WickedEngine/wiGUI.h index c8ec92b57..4e2601ea3 100644 --- a/WickedEngine/wiGUI.h +++ b/WickedEngine/wiGUI.h @@ -452,6 +452,7 @@ namespace wi::gui { protected: bool wrap_enabled = true; + bool fittext_enabled = false; public: void Create(const std::string& name); @@ -465,6 +466,7 @@ namespace wi::gui ScrollBar scrollbar; void SetWrapEnabled(bool value) { wrap_enabled = value; } + void SetFitTextEnabled(bool value) { fittext_enabled = value; } float margin_left = 0; float margin_right = 0; diff --git a/WickedEngine/wiGraphicsDevice_DX12.cpp b/WickedEngine/wiGraphicsDevice_DX12.cpp index 72cdfa7fb..50e398060 100644 --- a/WickedEngine/wiGraphicsDevice_DX12.cpp +++ b/WickedEngine/wiGraphicsDevice_DX12.cpp @@ -1714,12 +1714,12 @@ std::mutex queue_locker; } void GraphicsDevice_DX12::CopyAllocator::submit(CopyCMD cmd) { - cmd.commandList->Close(); + dx12_check(cmd.commandList->Close()); ID3D12CommandList* commandlists[] = { cmd.commandList.Get() }; - cmd.fence->Signal(0); + dx12_check(cmd.fence->Signal(0)); { #ifdef PLATFORM_XBOX diff --git a/WickedEngine/wiScene.cpp b/WickedEngine/wiScene.cpp index 9a649002f..fce1d05ce 100644 --- a/WickedEngine/wiScene.cpp +++ b/WickedEngine/wiScene.cpp @@ -5787,6 +5787,8 @@ namespace wi::scene dirty |= spline.prev_rotation != spline.rotation; bool dirty_terrain = spline.prev_terrain_modifier_amount != spline.terrain_modifier_amount; + dirty_terrain |= spline.prev_terrain_pushdown != spline.terrain_pushdown; + dirty_terrain |= spline.prev_terrain_texture_falloff != spline.terrain_texture_falloff; dirty_terrain |= spline.prev_terrain_generation_nodes != (int)spline.spline_node_entities.size(); dirty_terrain |= spline.prev_looped != spline.IsLooped(); dirty_terrain |= spline.prev_width != spline.width; @@ -5798,6 +5800,15 @@ namespace wi::scene spline.spline_node_transforms.resize(spline.spline_node_entities.size()); + if (materials.Contains(entity)) + { + spline.materialEntity = entity; + } + else + { + spline.materialEntity = INVALID_ENTITY; + } + // BEFORE mesh update: LOCAL space transform (because mesh will be also transformed by ObjectComponent instance) spline.precomputed_total_distance = 0; for (size_t i = 0; i < spline.spline_node_entities.size(); ++i) diff --git a/WickedEngine/wiScene.h b/WickedEngine/wiScene.h index 603d3079f..3d7c2b539 100644 --- a/WickedEngine/wiScene.h +++ b/WickedEngine/wiScene.h @@ -64,7 +64,7 @@ namespace wi::scene wi::ecs::ComponentManager& metadatas = componentLibrary.Register("wi::scene::Scene::metadatas"); wi::ecs::ComponentManager& characters = componentLibrary.Register("wi::scene::Scene::characters"); wi::ecs::ComponentManager& constraints = componentLibrary.Register("wi::scene::Scene::constraints", 5); // version = 5 - wi::ecs::ComponentManager& splines = componentLibrary.Register("wi::scene::Scene::splines", 1); // version = 1 + wi::ecs::ComponentManager& splines = componentLibrary.Register("wi::scene::Scene::splines", 2); // version = 2 // Non-serialized attributes: float dt = 0; diff --git a/WickedEngine/wiScene_Components.h b/WickedEngine/wiScene_Components.h index 999eadef2..db5a262d7 100644 --- a/WickedEngine/wiScene_Components.h +++ b/WickedEngine/wiScene_Components.h @@ -2563,7 +2563,9 @@ namespace wi::scene float rotation = 0; // rotation of nodes in radians around the spline axis (affects mesh generation) int mesh_generation_subdivision = 0; // increase this above 0 to request mesh generation int mesh_generation_vertical_subdivision = 0; // can create vertically subdivided mesh (corridoor, tunnel, etc. with this) - float terrain_modifier_amount = 0; // increase above 0 to affect terrain generation + float terrain_modifier_amount = 0; // increase above 0 to affect terrain generation (greater values increase the strength of the terrain trying to match the spline plane) + float terrain_pushdown = 0; // push down the terrain below the spline plane (or above if negative value) + float terrain_texture_falloff = 0.8f; // texture blend falloff for terrain modifier spline wi::vector spline_node_entities; @@ -2577,10 +2579,14 @@ namespace wi::scene int prev_mesh_generation_vertical_subdivision = 0; int prev_mesh_generation_nodes = 0; mutable float prev_terrain_modifier_amount = 0; + mutable float prev_terrain_pushdown = 0; + mutable float prev_terrain_texture_falloff = 0; mutable int prev_terrain_generation_nodes = 0; mutable bool dirty_terrain = false; bool prev_looped = false; wi::primitive::AABB aabb; + wi::ecs::Entity materialEntity = wi::ecs::INVALID_ENTITY; // temp for terrain usage + mutable wi::ecs::Entity materialEntity_terrainPrev = wi::ecs::INVALID_ENTITY; // temp for terrain usage // Evaluate an interpolated location on the spline at t which in range [0,1] on the spline // the result matrix is oriented to look towards the spline direction and face upwards along the spline normal diff --git a/WickedEngine/wiScene_Serializers.cpp b/WickedEngine/wiScene_Serializers.cpp index 3ff7d55f4..324fcd3db 100644 --- a/WickedEngine/wiScene_Serializers.cpp +++ b/WickedEngine/wiScene_Serializers.cpp @@ -2529,6 +2529,11 @@ namespace wi::scene { archive >> terrain_modifier_amount; } + if (seri.GetVersion() >= 2) + { + archive >> terrain_pushdown; + archive >> terrain_texture_falloff; + } } else { @@ -2548,6 +2553,11 @@ namespace wi::scene { archive << terrain_modifier_amount; } + if (seri.GetVersion() >= 2) + { + archive << terrain_pushdown; + archive << terrain_texture_falloff; + } } } diff --git a/WickedEngine/wiTerrain.cpp b/WickedEngine/wiTerrain.cpp index 86f14662c..7a80ddb55 100644 --- a/WickedEngine/wiTerrain.cpp +++ b/WickedEngine/wiTerrain.cpp @@ -189,7 +189,7 @@ namespace wi::terrain static std::mutex locker; - void weight_norm(XMFLOAT4& weights) + constexpr void weight_norm(XMFLOAT4& weights) { const float norm = 1.0f / (weights.x + weights.y + weights.z + weights.w); weights.x *= norm; @@ -594,6 +594,7 @@ namespace wi::terrain break; } } + splineMaterialEntities.clear(); for (size_t i = 0; i < scene->splines.GetCount(); ++i) { const SplineComponent& spline = scene->splines[i]; @@ -604,8 +605,18 @@ namespace wi::terrain { spline.dirty_terrain = false; spline.prev_terrain_modifier_amount = spline.terrain_modifier_amount; + spline.prev_terrain_pushdown = spline.terrain_pushdown; + spline.prev_terrain_texture_falloff = spline.terrain_texture_falloff; spline.prev_terrain_generation_nodes = (int)spline.spline_node_entities.size(); } + restart_generation |= spline.materialEntity != spline.materialEntity_terrainPrev; + const MaterialComponent* splineMaterial = scene->materials.GetComponent(spline.materialEntity); + if (splineMaterial != nullptr) + { + restart_generation |= splineMaterial->IsDirty(); + splineMaterialEntities.push_back(spline.materialEntity); + } + spline.materialEntity_terrainPrev = spline.materialEntity; } } @@ -937,11 +948,17 @@ namespace wi::terrain mesh.vertex_tangents.resize(vertexCount); mesh.vertex_uvset_0.resize(vertexCount); - chunk_data.blendmap_layers.reserve(4); - chunk_data.blendmap_layers.emplace_back().pixels.resize(vertexCount); - chunk_data.blendmap_layers.emplace_back().pixels.resize(vertexCount); - chunk_data.blendmap_layers.emplace_back().pixels.resize(vertexCount); - chunk_data.blendmap_layers.emplace_back().pixels.resize(vertexCount); + chunk_data.blendmap_layers.resize(4); + for (auto& x : chunk_data.blendmap_layers) + { + x.pixels.resize(vertexCount); + } + + chunk_data.spline_blendmap_layers.resize(splineMaterialEntities.size()); + for (auto& x : chunk_data.spline_blendmap_layers) + { + x.pixels.resize(vertexCount); + } chunk_data.mesh_vertex_positions = mesh.vertex_positions.data(); @@ -978,18 +995,29 @@ namespace wi::terrain } height = lerp(bottomLevel, topLevel, height); + const bool is_real_vertex = coord.x < chunk_width && coord.y < chunk_width; + const uint32_t real_index = coord.x + coord.y * chunk_width; + // Apply splines to height only: const XMVECTOR P = XMVectorSet(world_pos.x, -100000, world_pos.y, 0); + int splinematerialcnt = -1; for (size_t j = 0; j < generator->splines.size(); ++j) { const SplineComponent& spline = generator->splines[j]; + if (spline.materialEntity != INVALID_ENTITY) + splinematerialcnt++; if (!spline.aabb.intersects(P)) continue; XMVECTOR S = spline.TraceSplinePlane(P, UP, 4); S = spline.ClosestPointOnSpline(S, 4); const float splineheight = XMVectorGetY(S); const float splinedist = wi::math::Distance(XMVectorSetY(P, splineheight), S); - height = lerp(splineheight, height, smoothstep(0.0f, 1.0f, saturate(splinedist * sqr(spline.terrain_modifier_amount)))); + const float splinefactor = 1.0f - smoothstep(0.0f, 1.0f, saturate(splinedist * sqr(spline.terrain_modifier_amount))); + if (is_real_vertex && spline.materialEntity != INVALID_ENTITY) + { + chunk_data.spline_blendmap_layers[splinematerialcnt].pixels[real_index] = uint8_t(smoothstep(clamp(spline.terrain_texture_falloff, 0.0f, 0.999f), 1.0f, splinefactor) * 255); + } + height = lerp(height, splineheight - spline.terrain_pushdown, splinefactor); } heights_padded[coord.x][coord.y] = height; @@ -1044,9 +1072,19 @@ namespace wi::terrain XMFLOAT3 vertex_pos(chunk_data.position.x + x, height, chunk_data.position.z + z); + float spline_factor = 0; + if (!chunk_data.spline_blendmap_layers.empty()) + { + for (auto& y : chunk_data.spline_blendmap_layers) + { + spline_factor += float(y.pixels[index]) / 255.0f; + } + spline_factor /= float(chunk_data.spline_blendmap_layers.size()); + } + const float grass_noise_frequency = 0.1f; const float grass_noise = perlin_noise.compute(vertex_pos.x * grass_noise_frequency, vertex_pos.y * grass_noise_frequency, vertex_pos.z * grass_noise_frequency) * 0.5f + 0.5f; - const float region_grass = std::pow(materialBlendWeights.x * (1 - materialBlendWeights.w), 8.0f) * grass_noise; + const float region_grass = std::pow(materialBlendWeights.x * (1 - materialBlendWeights.w), 8.0f) * grass_noise * (1 - saturate(spline_factor)); if (region_grass > 0.1f) { grass_valid_vertex_count.fetch_add(1); @@ -1167,6 +1205,22 @@ namespace wi::terrain XMFLOAT4 region0 = wi::Color(chunk_data.blendmap_layers[0].pixels[ind0], chunk_data.blendmap_layers[1].pixels[ind0], chunk_data.blendmap_layers[2].pixels[ind0], chunk_data.blendmap_layers[3].pixels[ind0]); XMFLOAT4 region1 = wi::Color(chunk_data.blendmap_layers[0].pixels[ind1], chunk_data.blendmap_layers[1].pixels[ind1], chunk_data.blendmap_layers[2].pixels[ind1], chunk_data.blendmap_layers[3].pixels[ind1]); XMFLOAT4 region2 = wi::Color(chunk_data.blendmap_layers[0].pixels[ind2], chunk_data.blendmap_layers[1].pixels[ind2], chunk_data.blendmap_layers[2].pixels[ind2], chunk_data.blendmap_layers[3].pixels[ind2]); + float spline_factor0 = 0; + float spline_factor1 = 0; + float spline_factor2 = 0; + if (!chunk_data.spline_blendmap_layers.empty()) + { + for (auto& y : chunk_data.spline_blendmap_layers) + { + spline_factor0 += float(y.pixels[ind0]) / 255.0f; + spline_factor1 += float(y.pixels[ind1]) / 255.0f; + spline_factor2 += float(y.pixels[ind2]) / 255.0f; + } + const float rcp = 1.0f / float(chunk_data.spline_blendmap_layers.size()); + spline_factor0 *= rcp; + spline_factor1 *= rcp; + spline_factor2 *= rcp; + } weight_norm(region0); weight_norm(region1); weight_norm(region2); @@ -1189,9 +1243,10 @@ namespace wi::terrain region0.z + f * (region1.z - region0.z) + g * (region2.z - region0.z), region0.w + f * (region1.w - region0.w) + g * (region2.w - region0.w) ); + const float spline_factor = spline_factor0 + f * (spline_factor1 - spline_factor0) + g * (spline_factor2 - spline_factor0); const float noise = std::pow(perlin_noise.compute((vertex_pos.x + chunk_data.position.x) * prop.noise_frequency, vertex_pos.y * prop.noise_frequency, (vertex_pos.z + chunk_data.position.z) * prop.noise_frequency) * 0.5f + 0.5f, prop.noise_power); - const float chance = std::pow(((float*)®ion)[prop.region], prop.region_power) * noise; + const float chance = std::pow(((float*)®ion)[prop.region], prop.region_power) * noise * (1 - saturate(spline_factor)); if (chance > prop.threshold) { wi::Archive archive = wi::Archive(prop.data.data(), prop.data.size()); @@ -1310,21 +1365,28 @@ namespace wi::terrain device->SetName(&chunk_data.heightmap, "wi::terrain::ChunkData::heightmap"); } - if (!chunk_data.blendmap.IsValid() || chunk_data.blendmap.desc.array_size != (uint32_t)chunk_data.blendmap_layers.size()) + const uint32_t required_layers = uint32_t(chunk_data.blendmap_layers.size() + chunk_data.spline_blendmap_layers.size()); + if (!chunk_data.blendmap.IsValid() || chunk_data.blendmap.desc.array_size != required_layers) { TextureDesc desc; desc.width = (uint32_t)chunk_width; desc.height = (uint32_t)chunk_width; - desc.array_size = (uint32_t)chunk_data.blendmap_layers.size(); + desc.array_size = required_layers; desc.format = Format::R8_UNORM; desc.bind_flags = BindFlag::SHADER_RESOURCE; - wi::vector data(chunk_data.blendmap_layers.size()); + wi::vector data(required_layers); for (size_t i = 0; i < chunk_data.blendmap_layers.size(); ++i) { data[i].data_ptr = chunk_data.blendmap_layers[i].pixels.data(); data[i].row_pitch = chunk_width * sizeof(uint8_t); } + const size_t offset = chunk_data.blendmap_layers.size(); + for (size_t i = 0; i < chunk_data.spline_blendmap_layers.size(); ++i) + { + data[offset + i].data_ptr = chunk_data.spline_blendmap_layers[i].pixels.data(); + data[offset + i].row_pitch = chunk_width * sizeof(uint8_t); + } bool success = device->CreateTexture(&desc, data.data(), &chunk_data.blendmap); assert(success); @@ -1769,12 +1831,20 @@ namespace wi::terrain if (push.blendmap_texture < 0) continue; - auto mem = device->AllocateGPU(sizeof(uint) * vt->blendmap.desc.array_size, cmd); - const uint blendcount = std::min(vt->blendmap.desc.array_size, uint(materialEntities.size())); - for (uint i = 0; i < blendcount; ++i) + auto mem = device->AllocateGPU(sizeof(uint) * push.blendmap_layers, cmd); + const uint splineMaterialCount = (uint)splineMaterialEntities.size(); + const uint baseMaterialCount = push.blendmap_layers - splineMaterialCount; + for (uint i = 0; i < splineMaterialCount; ++i) { - const uint material_index = (uint)scene->materials.GetIndex(materialEntities[i]); - std::memcpy((uint*)mem.data + i, &material_index, sizeof(uint)); // force memcpy to avoid uncached write into GPU pointer! + const Entity entity = splineMaterialEntities[i]; + const uint material_index = (uint)scene->materials.GetIndex(entity); + std::memcpy((uint*)mem.data + baseMaterialCount + i, &material_index, sizeof(uint)); // force memcpy to avoid uncached read from GPU pointer! + } + for (uint i = 0; i < baseMaterialCount; ++i) + { + const Entity entity = materialEntities[i]; + const uint material_index = (uint)scene->materials.GetIndex(entity); + std::memcpy((uint*)mem.data + i, &material_index, sizeof(uint)); // force memcpy to avoid uncached read from GPU pointer! } push.blendmap_buffer = device->GetDescriptorIndex(&mem.buffer, SubresourceType::SRV); diff --git a/WickedEngine/wiTerrain.h b/WickedEngine/wiTerrain.h index 0e7de2d64..cec104d82 100644 --- a/WickedEngine/wiTerrain.h +++ b/WickedEngine/wiTerrain.h @@ -225,6 +225,7 @@ namespace wi::terrain const XMFLOAT3* mesh_vertex_positions = nullptr; wi::HairParticleSystem grass; wi::vector blendmap_layers; + wi::vector spline_blendmap_layers; wi::graphics::Texture blendmap; wi::primitive::Sphere sphere; XMFLOAT3 position = XMFLOAT3(0, 0, 0); @@ -278,13 +279,14 @@ namespace wi::terrain wi::ecs::Entity terrainEntity = wi::ecs::INVALID_ENTITY; wi::ecs::Entity chunkGroupEntity = wi::ecs::INVALID_ENTITY; wi::scene::Scene* scene = nullptr; - wi::vector materialEntities = {}; + wi::vector materialEntities; + wi::vector splineMaterialEntities; wi::ecs::Entity grassEntity = wi::ecs::INVALID_ENTITY; wi::scene::WeatherComponent weather; wi::HairParticleSystem grass_properties; wi::scene::MaterialComponent grass_material; wi::unordered_map chunks; - Chunk center_chunk = {}; + Chunk center_chunk; wi::noise::Perlin perlin_noise; wi::vector props; int grass_chunk_dist = 1; diff --git a/WickedEngine/wiVersion.cpp b/WickedEngine/wiVersion.cpp index 7b2330289..5618c5fb4 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 = 749; + const int revision = 750; const std::string version_string = std::to_string(major) + "." + std::to_string(minor) + "." + std::to_string(revision);