diff --git a/Editor/LightWindow.cpp b/Editor/LightWindow.cpp index a2dd0002f..edbc1354e 100644 --- a/Editor/LightWindow.cpp +++ b/Editor/LightWindow.cpp @@ -300,8 +300,6 @@ void LightWindow::Create(EditorComponent* _editor) void LightWindow::SetEntity(Entity entity) { - if (this->entity == entity) - return; this->entity = entity; const LightComponent* light = editor->GetCurrentScene().lights.GetComponent(entity); @@ -346,29 +344,6 @@ void LightWindow::SetEntity(Entity entity) lensflare_Button[i].SetEnabled(true); } } - else - { - rangeSlider.SetEnabled(false); - radiusSlider.SetEnabled(false); - lengthSlider.SetEnabled(false); - outerConeAngleSlider.SetEnabled(false); - innerConeAngleSlider.SetEnabled(false); - shadowCheckBox.SetEnabled(false); - haloCheckBox.SetEnabled(false); - volumetricsCheckBox.SetEnabled(false); - staticCheckBox.SetEnabled(false); - volumetricCloudsCheckBox.SetEnabled(false); - intensitySlider.SetEnabled(false); - colorPicker.SetEnabled(false); - shadowResolutionComboBox.SetEnabled(false); - - for (size_t i = 0; i < arraysize(lensflare_Button); ++i) - { - lensflare_Button[i].SetEnabled(false); - } - - RefreshCascades(); - } } void LightWindow::SetLightType(LightComponent::LightType type) { diff --git a/Editor/MeshWindow.cpp b/Editor/MeshWindow.cpp index dad29896c..04c06fc16 100644 --- a/Editor/MeshWindow.cpp +++ b/Editor/MeshWindow.cpp @@ -309,13 +309,13 @@ void MeshWindow::Create(EditorComponent* _editor) AddWidget(&recenterToBottomButton); mergeButton.Create("Merge Selected"); - mergeButton.SetTooltip("Merges selected objects/meshes into one.\nAll selected object transformations will be applied to meshes and allmeshes will be baked into a single mesh."); + 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(); - MeshComponent merged_mesh; ObjectComponent merged_object; + MeshComponent merged_mesh; bool valid_normals = false; bool valid_uvset_0 = false; bool valid_uvset_1 = false; @@ -326,6 +326,36 @@ void MeshWindow::Create(EditorComponent* _editor) bool valid_windweights = false; wi::unordered_set entities_to_remove; Entity prev_subset_material = INVALID_ENTITY; + + // Search for first object with a mesh from selection, that will be the base: + Entity baseEntityParent = INVALID_ENTITY; + Entity baseEntity = INVALID_ENTITY; + TransformComponent* baseTransform = nullptr; + ObjectComponent* baseObject = nullptr; + MeshComponent* baseMesh = nullptr; + for (auto& picked : editor->translator.selected) + { + ObjectComponent* object = scene.objects.GetComponent(picked.entity); + if (object == nullptr) + continue; + MeshComponent* mesh = scene.meshes.GetComponent(object->meshID); + if (mesh == nullptr) + continue; + baseEntity = picked.entity; + HierarchyComponent* hier = scene.hierarchy.GetComponent(baseEntity); + if (hier != nullptr) + { + baseEntityParent = hier->parentID; + } + baseTransform = scene.transforms.GetComponent(picked.entity); + baseObject = object; + baseMesh = mesh; + } + if (baseObject == nullptr) + return; + merged_object.meshID = baseObject->meshID; + + // Merge all other meshes into the base object: for (auto& picked : editor->translator.selected) { ObjectComponent* object = scene.objects.GetComponent(picked.entity); @@ -454,21 +484,28 @@ void MeshWindow::Create(EditorComponent* _editor) { merged_mesh.armatureID = mesh->armatureID; } - entities_to_remove.insert(picked.entity); - // Only remove mesh if it is no longer used by any other objects: - bool mesh_still_used = false; - for (size_t i = 0; i < scene.objects.GetCount(); ++i) + if (object != baseObject) // don't remove base object { - if (entities_to_remove.count(scene.objects.GetEntity(i)) == 0 && scene.objects[i].meshID == object->meshID) - { - mesh_still_used = true; - break; - } + entities_to_remove.insert(picked.entity); } - if (!mesh_still_used) + + if (mesh != baseMesh) { - entities_to_remove.insert(object->meshID); + // Only remove mesh if it is no longer used by any other objects: + bool mesh_still_used = false; + for (size_t i = 0; i < scene.objects.GetCount(); ++i) + { + if (entities_to_remove.count(scene.objects.GetEntity(i)) == 0 && scene.objects[i].meshID == object->meshID) + { + mesh_still_used = true; + break; + } + } + if (!mesh_still_used) + { + entities_to_remove.insert(object->meshID); + } } } @@ -491,14 +528,15 @@ void MeshWindow::Create(EditorComponent* _editor) if (!valid_windweights) merged_mesh.vertex_windweights.clear(); - Entity merged_object_entity = scene.Entity_CreateObject("mergedObject"); - Entity merged_mesh_entity = scene.Entity_CreateMesh("mergedMesh"); - ObjectComponent* object = scene.objects.GetComponent(merged_object_entity); - *object = std::move(merged_object); - object->meshID = merged_mesh_entity; - MeshComponent* mesh = scene.meshes.GetComponent(merged_mesh_entity); - *mesh = std::move(merged_mesh); - mesh->CreateRenderData(); + *baseObject = std::move(merged_object); + *baseMesh = std::move(merged_mesh); + baseMesh->CreateRenderData(); + scene.Component_Detach(baseEntity); + if (baseTransform != nullptr) + { + baseTransform->ClearTransform(); + } + scene.Component_Attach(baseEntity, baseEntityParent); } for (auto& x : entities_to_remove) diff --git a/WickedEngine/wiGUI.cpp b/WickedEngine/wiGUI.cpp index f881b16a0..7404e377e 100644 --- a/WickedEngine/wiGUI.cpp +++ b/WickedEngine/wiGUI.cpp @@ -5309,7 +5309,22 @@ namespace wi::gui } void TreeList::Select(int index) { - items[index].selected = true; + int selected_count = 0; + for (auto& x : items) + { + if (x.selected) + selected_count++; + } + + if (selected_count > 1) + { + // If multiple are selected, then we can deselect: + items[index].selected = !items[index].selected; + } + else + { + items[index].selected = true; + } EventArgs args; args.iValue = index; diff --git a/WickedEngine/wiScene.cpp b/WickedEngine/wiScene.cpp index 501844861..8835e506a 100644 --- a/WickedEngine/wiScene.cpp +++ b/WickedEngine/wiScene.cpp @@ -1155,15 +1155,21 @@ namespace wi::scene } Entity Scene::Instantiate(Scene& prefab, bool attached) { + wi::Timer timer; + // Duplicate prefab into tmp scene + // Note: we directly use componentLibrary.Serialize instead of serializing whole scene + // Because prefab scene's resources are already in memory, and we don't need to handle them + // Also other generic scene serialization can be skipped Scene tmp; wi::Archive archive; + EntitySerializer seri; archive.SetReadModeAndResetPos(false); - prefab.Serialize(archive, false); + prefab.componentLibrary.Serialize(archive, seri); archive.SetReadModeAndResetPos(true); - tmp.Serialize(archive, false); + tmp.componentLibrary.Serialize(archive, seri); Entity rootEntity = INVALID_ENTITY; @@ -1185,8 +1191,14 @@ namespace wi::scene } } + wi::jobsystem::Wait(seri.ctx); // wait for completion of component serializations background threads here + Merge(tmp); + char text[64] = {}; + snprintf(text, arraysize(text), "Scene::Instantiate took %.2f ms", timer.elapsed_milliseconds()); + wi::backlog::post(text); + return rootEntity; } void Scene::FindAllEntities(wi::unordered_set& entities) const diff --git a/WickedEngine/wiScene.h b/WickedEngine/wiScene.h index 4afb3dbdc..af0535f86 100644 --- a/WickedEngine/wiScene.h +++ b/WickedEngine/wiScene.h @@ -431,8 +431,7 @@ namespace wi::scene void Component_DetachChildren(wi::ecs::Entity parent); // Read/write whole scene into an archive - // serialize_resources : you can disable resource serialization (useful for instantiation, when resources were already loaded) - void Serialize(wi::Archive& archive, bool serialize_resources = true); + void Serialize(wi::Archive& archive); void RunAnimationUpdateSystem(wi::jobsystem::context& ctx); void RunTransformUpdateSystem(wi::jobsystem::context& ctx); diff --git a/WickedEngine/wiScene_Serializers.cpp b/WickedEngine/wiScene_Serializers.cpp index af0df6a8b..8b7e08a8a 100644 --- a/WickedEngine/wiScene_Serializers.cpp +++ b/WickedEngine/wiScene_Serializers.cpp @@ -2029,7 +2029,7 @@ namespace wi::scene } } - void Scene::Serialize(wi::Archive& archive, bool serialize_resources) + void Scene::Serialize(wi::Archive& archive) { wi::Timer timer; @@ -2048,7 +2048,7 @@ namespace wi::scene size_t jump_before = 0; size_t jump_after = 0; size_t original_pos = 0; - if (archive.GetVersion() >= 90 && serialize_resources) + if (archive.GetVersion() >= 90) { if (archive.IsReadMode()) { @@ -2066,7 +2066,7 @@ namespace wi::scene // Keeping this alive to keep serialized resources alive until entity serialization ends: wi::resourcemanager::ResourceSerializer resource_seri; - if (archive.IsReadMode() && archive.GetVersion() >= 63 && serialize_resources) + if (archive.IsReadMode() && archive.GetVersion() >= 63) { wi::resourcemanager::Serialize_READ(archive, resource_seri); if (archive.GetVersion() >= 90) @@ -2183,7 +2183,7 @@ namespace wi::scene } } - if (archive.GetVersion() >= 90 && serialize_resources) + if (archive.GetVersion() >= 90) { if (archive.IsReadMode()) { @@ -2197,7 +2197,9 @@ namespace wi::scene } } - wi::backlog::post("Scene serialize took " + std::to_string(timer.elapsed_seconds()) + " sec"); + char text[64] = {}; + snprintf(text, arraysize(text), "Scene::Serialize took %.2f seconds", timer.elapsed_seconds()); + wi::backlog::post(text); } void Scene::DDGI::Serialize(wi::Archive& archive) diff --git a/WickedEngine/wiVersion.cpp b/WickedEngine/wiVersion.cpp index e99301bf9..37dc7de3a 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 = 486; + const int revision = 487; const std::string version_string = std::to_string(major) + "." + std::to_string(minor) + "." + std::to_string(revision);