diff --git a/Editor/MaterialPickerWindow.cpp b/Editor/MaterialPickerWindow.cpp index b7ac5a5e5..562ca8d7e 100644 --- a/Editor/MaterialPickerWindow.cpp +++ b/Editor/MaterialPickerWindow.cpp @@ -15,9 +15,62 @@ void MaterialPickerWindow::Create(EditorComponent* _editor) zoomSlider.Create(10, 100, 100, 100 - 10, "Zoom: "); AddWidget(&zoomSlider); + showMeshMaterialCheckBox.Create("Mesh materials: "); + showMeshMaterialCheckBox.SetCheckText(ICON_EYE); + showMeshMaterialCheckBox.SetCheck(true); + showMeshMaterialCheckBox.OnClick([this](wi::gui::EventArgs args) { + RecreateButtons(); + }); + AddWidget(&showMeshMaterialCheckBox); + + showInternalMaterialCheckBox.Create("Internal materials: "); + showInternalMaterialCheckBox.SetCheckText(ICON_EYE); + showInternalMaterialCheckBox.SetCheck(false); + showInternalMaterialCheckBox.OnClick([this](wi::gui::EventArgs args) { + RecreateButtons(); + }); + AddWidget(&showInternalMaterialCheckBox); + SetVisible(false); } +bool MaterialPickerWindow::MaterialIsUsedInMesh(const wi::ecs::Entity materialEntity) const +{ + if (editor == nullptr) + return false; + + const wi::scene::Scene& scene = editor->GetCurrentScene(); + + // Check all meshes to see if any subset uses this material + for (size_t i = 0; i < scene.meshes.GetCount(); ++i) + { + const MeshComponent& mesh = scene.meshes[i]; + for (const auto& subset : mesh.subsets) + { + if (subset.materialID == materialEntity) + return true; + } + } + + return false; +} + +bool MaterialPickerWindow::ShouldShowMaterial(const wi::scene::MaterialComponent& material, const wi::ecs::Entity entity) const +{ + const bool isInternal = material.IsInternal(); + + // Check if we should hide internal materials + if (!showInternalMaterialCheckBox.GetCheck() && isInternal) + return false; + + // Check if we should hide materials used in meshes + // Note: Internal materials are always shown if showInternalCheckBox is true, regardless of mesh usage filter + if (!showMeshMaterialCheckBox.GetCheck() && !isInternal && MaterialIsUsedInMesh(entity)) + return false; + + return true; +} + void MaterialPickerWindow::RecreateButtons() { if (editor == nullptr) @@ -31,8 +84,13 @@ void MaterialPickerWindow::RecreateButtons() for (size_t i = 0; i < scene.materials.GetCount(); ++i) { + const MaterialComponent& material = scene.materials[i]; Entity entity = scene.materials.GetEntity(i); + // Apply filters + if (!ShouldShowMaterial(material, entity)) + continue; + wi::gui::Button& button = buttons[i]; button.Create(""); AddWidget(&button); @@ -91,6 +149,13 @@ void MaterialPickerWindow::ResizeLayout() layout.add(zoomSlider); + constexpr float hei = 20; + showMeshMaterialCheckBox.SetSize(XMFLOAT2(hei, hei)); + layout.add_right(showMeshMaterialCheckBox); + + showInternalMaterialCheckBox.SetSize(XMFLOAT2(hei, hei)); + layout.add_right(showInternalMaterialCheckBox); + wi::gui::Theme theme; theme.image.CopyFrom(sprites[wi::gui::IDLE].params); theme.image.background = false; @@ -102,13 +167,18 @@ void MaterialPickerWindow::ResizeLayout() const float preview_size = zoomSlider.GetValue(); const float border = 20 * preview_size / 100.0f; - int cells = std::max(1, int(GetWidgetAreaSize().x / (preview_size + border))); - float offset_y = border + zoomSlider.GetSize().y; + const int cells = std::max(1, int(GetWidgetAreaSize().x / (preview_size + border))); + float offset_y = showInternalMaterialCheckBox.GetPos().y + showInternalMaterialCheckBox.GetSize().y + border; + int visible_button_index = 0; for (size_t i = 0; i < scene.materials.GetCount(); ++i) { const MaterialComponent& material = scene.materials[i]; - Entity entity = scene.materials.GetEntity(i); + const Entity entity = scene.materials.GetEntity(i); + + // Apply filters + if (!ShouldShowMaterial(material, entity)) + continue; wi::gui::Button& button = buttons[i]; button.SetVisible(IsVisible() && !IsCollapsed()); @@ -118,7 +188,7 @@ void MaterialPickerWindow::ResizeLayout() button.SetColor(wi::Color(255, 255, 255, 150), wi::gui::IDLE); button.SetShadowRadius(0); - for (auto& picked : editor->translator.selected) + for (const auto& picked : editor->translator.selected) { if (picked.entity == entity) { @@ -156,10 +226,12 @@ void MaterialPickerWindow::ResizeLayout() button.font.params.v_align = wi::font::WIFALIGN_BOTTOM; button.SetSize(XMFLOAT2(preview_size, preview_size)); - button.SetPos(XMFLOAT2((i % cells) * (preview_size + border) + border, offset_y)); - if ((i % cells) == (cells - 1)) + button.SetPos(XMFLOAT2((visible_button_index % cells) * (preview_size + border) + border, offset_y)); + if ((visible_button_index % cells) == (cells - 1)) { offset_y += preview_size + border; } + + visible_button_index++; } } diff --git a/Editor/MaterialPickerWindow.h b/Editor/MaterialPickerWindow.h index 3e4b9b0d4..10717147a 100644 --- a/Editor/MaterialPickerWindow.h +++ b/Editor/MaterialPickerWindow.h @@ -11,10 +11,16 @@ public: std::deque buttons; wi::gui::Slider zoomSlider; + wi::gui::CheckBox showMeshMaterialCheckBox; + wi::gui::CheckBox showInternalMaterialCheckBox; void ResizeLayout() override; // Recreating buttons shouldn't be done every frame because interaction states need multi-frame execution void RecreateButtons(); + +private: + bool ShouldShowMaterial(const wi::scene::MaterialComponent& material, wi::ecs::Entity entity) const; + bool MaterialIsUsedInMesh(wi::ecs::Entity materialEntity) const; }; diff --git a/Editor/MeshWindow.cpp b/Editor/MeshWindow.cpp index 4c9974b14..785c03820 100644 --- a/Editor/MeshWindow.cpp +++ b/Editor/MeshWindow.cpp @@ -988,6 +988,11 @@ void MeshWindow::SetEntity(Entity entity, int subset) subsetMaterialComboBox.AddItem("NO MATERIAL"); for (size_t i = 0; i < scene.materials.GetCount(); ++i) { + if (scene.materials[i].IsInternal()) + { + continue; + } + Entity entity = scene.materials.GetEntity(i); if (scene.names.Contains(entity)) diff --git a/Editor/TerrainWindow.cpp b/Editor/TerrainWindow.cpp index 510118186..da2a285ee 100644 --- a/Editor/TerrainWindow.cpp +++ b/Editor/TerrainWindow.cpp @@ -1359,6 +1359,11 @@ void TerrainWindow::RefreshMaterialComboBoxes() comboBox.AddItem("NO MATERIAL", INVALID_ENTITY); for (size_t i = 0; i < scene.materials.GetCount(); ++i) { + if (scene.materials[i].IsInternal()) + { + continue; + } + Entity entity = scene.materials.GetEntity(i); if (scene.names.Contains(entity)) { diff --git a/WickedEngine/wiScene_Components.h b/WickedEngine/wiScene_Components.h index d633a8f7b..a0d48e7d7 100644 --- a/WickedEngine/wiScene_Components.h +++ b/WickedEngine/wiScene_Components.h @@ -138,6 +138,7 @@ namespace wi::scene DISABLE_TEXTURE_STREAMING = 1 << 15, COPLANAR_BLENDING = 1 << 16, // force transparent material draw in opaque pass (useful for coplanar polygons) DISABLE_CAPSULE_SHADOW = 1 << 17, + INTERNAL = 1 << 18 // used only for internal purposes }; uint32_t _flags = CAST_SHADOW; @@ -279,6 +280,9 @@ namespace wi::scene constexpr void SetDirty(bool value = true) { if (value) { _flags |= DIRTY; } else { _flags &= ~DIRTY; } } constexpr bool IsDirty() const { return _flags & DIRTY; } + constexpr void SetInternal(bool value = true) { if (value) { _flags |= INTERNAL; } else { _flags &= ~INTERNAL; } } + constexpr bool IsInternal() const { return _flags & INTERNAL; } + constexpr void SetCastShadow(bool value) { SetDirty(); if (value) { _flags |= CAST_SHADOW; } else { _flags &= ~CAST_SHADOW; } } constexpr void SetReceiveShadow(bool value) { SetDirty(); if (value) { _flags &= ~DISABLE_RECEIVE_SHADOW; } else { _flags |= DISABLE_RECEIVE_SHADOW; } } constexpr void SetOcclusionEnabled_Primary(bool value) { SetDirty(); if (value) { _flags |= OCCLUSION_PRIMARY; } else { _flags &= ~OCCLUSION_PRIMARY; } } diff --git a/WickedEngine/wiTerrain.cpp b/WickedEngine/wiTerrain.cpp index 4f576a121..02f4d258a 100644 --- a/WickedEngine/wiTerrain.cpp +++ b/WickedEngine/wiTerrain.cpp @@ -915,6 +915,7 @@ namespace wi::terrain MaterialComponent& material = generator->scene.materials.Create(chunk_data.entity); // material params will be 1 because they will be created from only texture maps // because region materials are blended together into one texture + material.SetInternal(); material.SetRoughness(1); material.SetMetalness(1); material.SetReflectance(1); @@ -1086,7 +1087,7 @@ namespace wi::terrain chunk_data.heightmap_data[index] = uint16_t(inverse_lerp(bottomLevel, topLevel, height) * 65535); }); wi::jobsystem::Wait(ctx); // wait until chunk's vertex buffer is fully generated - + object.SetCastShadow(slope_cast_shadow.load()); mesh.SetDoubleSidedShadow(slope_cast_shadow.load());