/* * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or * its licensors. * * For complete copyright and license terms please see the LICENSE at the root of this * distribution (the "License"). All use of this software is governed by the License, * or, if provided, by the license below or the license accompanying this file. Do not * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace AZ { namespace SceneAPI { namespace SceneData { static AZStd::fixed_vector < AZ::Crc32, LodRule::m_maxLods > s_lodVirtualTypeKeys = { AZ_CRC("LODMesh1", 0xcbea988c), AZ_CRC("LODMesh2", 0x52e3c936), AZ_CRC("LODMesh3", 0x25e4f9a0), AZ_CRC("LODMesh4", 0xbb806c03), AZ_CRC("LODMesh5", 0xcc875c95) }; void LodRuleBehavior::Activate() { Events::ManifestMetaInfoBus::Handler::BusConnect(); Events::AssetImportRequestBus::Handler::BusConnect(); Events::GraphMetaInfoBus::Handler::BusConnect(); } void LodRuleBehavior::Deactivate() { Events::GraphMetaInfoBus::Handler::BusDisconnect(); Events::AssetImportRequestBus::Handler::BusDisconnect(); Events::ManifestMetaInfoBus::Handler::BusDisconnect(); } void LodRuleBehavior::Reflect(ReflectContext* context) { SerializeContext* serializeContext = azrtti_cast(context); if (serializeContext) { serializeContext->Class()->Version(1); } } void LodRuleBehavior::InitializeObject(const Containers::Scene& scene, DataTypes::IManifestObject& target) { //Initialize Mesh Groups. if (target.RTTI_IsTypeOf(DataTypes::IMeshGroup::TYPEINFO_Uuid()) || target.RTTI_IsTypeOf(DataTypes::ISkinGroup::TYPEINFO_Uuid())) { AZStd::shared_ptr lodRule = nullptr; for (size_t lodLevel = 0; lodLevel < LodRule::m_maxLods; ++lodLevel) { SceneNodeSelectionList selection; size_t lodCount = SelectLodMeshes(scene, selection, lodLevel); if (lodCount > 0) { //Only create a lodRule if we have the first lod level. if (lodLevel == 0 && !lodRule) { lodRule = AZStd::make_shared(); } lodRule->AddLod(); selection.CopyTo(lodRule->GetNodeSelectionList(lodLevel)); } else { //Stop processing if we hit an empty lod. break; } } if(lodRule) { DataTypes::IGroup* group = azrtti_cast(&target); group->GetRuleContainer().AddRule(AZStd::move(lodRule)); } } else if (target.RTTI_IsTypeOf(LodRule::TYPEINFO_Uuid())) { LodRule* rule = azrtti_cast(&target); for (size_t lodLevel = 0; lodLevel < rule->GetLodCount(); ++lodLevel) { SelectLodMeshes(scene, rule->GetSceneNodeSelectionList(lodLevel), lodLevel); } } } size_t LodRuleBehavior::SelectLodMeshes(const Containers::Scene& scene, DataTypes::ISceneNodeSelectionList& selection, size_t lodLevel) const { Utilities::SceneGraphSelector::SelectAll(scene.GetGraph(), selection); size_t lodMeshCount = 0; const Containers::SceneGraph& graph = scene.GetGraph(); auto contentStorage = graph.GetContentStorage(); auto nameStorage = graph.GetNameStorage(); auto keyValueView = Containers::Views::MakePairView(nameStorage, contentStorage); auto filteredView = Containers::Views::MakeFilterView(keyValueView, Containers::DerivedTypeFilter()); for (auto it = filteredView.begin(); it != filteredView.end(); ++it) { AZStd::set types; auto keyValueIterator = it.GetBaseIterator(); Containers::SceneGraph::NodeIndex index = graph.ConvertToNodeIndex(keyValueIterator.GetFirstIterator()); EBUS_EVENT(Events::GraphMetaInfoBus, GetVirtualTypes, types, scene, index); if (types.find(Events::GraphMetaInfo::s_ignoreVirtualType) != types.end() || types.find(s_lodVirtualTypeKeys[lodLevel]) == types.end()) { selection.RemoveSelectedNode(it->first.GetPath()); } else { lodMeshCount++; } } return lodMeshCount; } Events::ProcessingResult LodRuleBehavior::UpdateManifest(Containers::Scene& scene, ManifestAction action, RequestingApplication /*requester*/) { if (action == ManifestAction::Update) { UpdateLodRules(scene); return Events::ProcessingResult::Success; } else { return Events::ProcessingResult::Ignored; } } void LodRuleBehavior::UpdateLodRules(Containers::Scene& scene) const { Containers::SceneManifest& manifest = scene.GetManifest(); //Process Mesh or Skin Groups. auto valueStorage = manifest.GetValueStorage(); auto view = Containers::MakeDerivedFilterView(valueStorage); for (DataTypes::ISceneNodeGroup& group : view) { AZ_TraceContext("Mesh/Skin Group", group.GetName()); const Containers::RuleContainer& rules = group.GetRuleContainer(); const size_t ruleCount = rules.GetRuleCount(); for (size_t index = 0; index < ruleCount; ++index) { LodRule* rule = azrtti_cast(rules.GetRule(index).get()); if (rule) { //update existing lods. for (size_t lodLevel = 0; lodLevel < rule->GetLodCount(); ++lodLevel) { Utilities::SceneGraphSelector::UpdateNodeSelection(scene.GetGraph(), rule->GetSceneNodeSelectionList(lodLevel)); } //Check for new lods. for (size_t lodLevel = rule->GetLodCount(); lodLevel < LodRule::m_maxLods; ++lodLevel) { SceneNodeSelectionList selection; size_t lodCount = SelectLodMeshes(scene, selection, lodLevel); if (lodCount > 0) { rule->AddLod(); selection.CopyTo(rule->GetNodeSelectionList(index)); } else { //Stop processing if we hit an empty lod. break; } } } } } } void LodRuleBehavior::GetVirtualTypeName(AZStd::string& name, Crc32 type) { if (type == AZ_CRC("LODMesh1", 0xcbea988c)) { name = "LODMesh1"; } else if (type == AZ_CRC("LODMesh2", 0x52e3c936)) { name = "LODMesh2"; } else if (type == AZ_CRC("LODMesh3", 0x25e4f9a0)) { name = "LODMesh3"; } else if (type == AZ_CRC("LODMesh4", 0xbb806c03)) { name = "LODMesh4"; } else if (type == AZ_CRC("LODMesh5", 0xcc875c95)) { name = "LODMesh5"; } } void LodRuleBehavior::GetAllVirtualTypes(AZStd::set& types) { AZStd::copy(s_lodVirtualTypeKeys.begin(), s_lodVirtualTypeKeys.end(), AZStd::inserter(types, types.begin())); } } // namespace SceneData } // namespace SceneAPI } // namespace AZ