""" 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. Lumberyard Legacy Mesh Component to Atom Mesh Component Conversion Script """ from LegacyConversionHelpers import * from LegacyMaterialComponentConverter import * class Mesh_Component_Converter(Component_Converter): """ Converts point lights """ def __init__(self, assetCatalogHelper, statsCollector, normalizedProjectDir): Component_Converter.__init__(self, assetCatalogHelper, statsCollector) # These are constant for every component in the file self.materialComponentConverter = Material_Component_Converter(assetCatalogHelper) self.normalizedProjectDir = normalizedProjectDir # These need to be reset between each component self.newAssetId = "" self.oldMaterialRelativePath = "" self.oldFbxRelativePathWithoutExtension = "" def is_this_the_component_im_looking_for(self, xmlElement, parent): if "name" in xmlElement.keys() and xmlElement.get("name") == "EditorMeshComponent": return True return False def gather_info_for_conversion(self, xmlElement, parent): # First, get the data that we need # # # # # # # # # # # # for editorMeshComponentChild in xmlElement: if "name" in editorMeshComponentChild.keys() and editorMeshComponentChild.get("name") == "MeshComponentRenderNode": for meshComponentRenderNodeChild in editorMeshComponentChild: if "name" in meshComponentRenderNodeChild.keys() and meshComponentRenderNodeChild.get("name") == "Asset": # We've found the mesh asset, now extract the assetId and hit assetId = meshComponentRenderNodeChild.get("value") # Legacy assetId looks like this "id={BCD2BB63-338F-53BE-98E1-BF847138B78E}:3250cdc0,type={C2869E3B-DDA0-4E01-8FE3-6770D788866B},hint={objects/airship/airship_pod_outerwalls.cgf} # atomAssetId looks like this "{BCD2BB63-338F-53BE-98E1-BF847138B78E}:########, # newAssetId should look like "id={BCD2BB63-338F-53BE-98E1-BF847138B78E}:########,type={2C7477B6-69C5-45BE-8163-BCD6A275B6D8},hint={objects/airship/airship_pod_outerwalls.azmodel}" #value"id={E01FB8B5-D2B3-52D8-BC36-644FC0E3B5F4}:268435463,type={2C7477B6-69C5-45BE-8163-BCD6A275B6D8},hint={objects/props/barrel_01.azmodel}" # get the relative path to the mesh meshPathStartIndex = assetId.find("hint={") meshPathStartIndex += len("hint={") meshPathEndIndex = assetId.find(".cgf") self.oldFbxRelativePathWithoutExtension = assetId[meshPathStartIndex: meshPathEndIndex] # swap the sub-id for the atom model sub-id atomModelRelativePath = "{0}.azmodel".format(self.oldFbxRelativePathWithoutExtension) if atomModelRelativePath in self.assetCatalogHelper.relativePathToAssetIdDict: atomAssetId = self.assetCatalogHelper.relativePathToAssetIdDict[atomModelRelativePath] atomSubId = atomAssetId[atomAssetId.find(":") + 1:] # go from string->int->hex->string to get the hex number as a string hexSubId = str(hex(int(atomSubId))) # remove the leading characters to get plain hex hexString = hexSubId[hexSubId.find("x") + 1:] subIdStartIndex = assetId.find(":") subIdStartIndex += 1 subIdEndIndex = assetId.find(",") subIdReplacement = hexString # swap the type for the atom model type typeStartIndex = assetId.find("type={") typeStartIndex += len("type={") typeEndIndex = assetId.find("},hint") typeReplacement = "2C7477B6-69C5-45BE-8163-BCD6A275B6D8" # swap the hint for the atom model extension extensionStartIndex = assetId.find(".cgf") extensionEndIndex = extensionStartIndex + len(".cgf") extensionReplacement = ".azmodel" self.newAssetId = "".join((assetId[:subIdStartIndex], subIdReplacement, assetId[subIdEndIndex:typeStartIndex], typeReplacement, assetId[typeEndIndex:extensionStartIndex], extensionReplacement, assetId[extensionEndIndex:])) else: # we couldn't find the atom model (it was probably a .cgf instead of a .fbx in source) self.newAssetId = "id={00000000-0000-0000-0000-000000000000}:00000000,type={2C7477B6-69C5-45BE-8163-BCD6A275B6D8},hint={}" print("Could not find {0} in the asset catalog. Make sure the corresponding source file ends in .fbx not .cgf, and that the asset has finished processing with no errors.".format(atomModelRelativePath)) elif "field" in meshComponentRenderNodeChild.keys() and meshComponentRenderNodeChild.get("field") == "Material Override": for simpleAssetReferenceChild in meshComponentRenderNodeChild: if "name" in simpleAssetReferenceChild.keys() and simpleAssetReferenceChild.get("name") == "SimpleAssetReferenceBase": for simpleAssetReferenceBaseChild in simpleAssetReferenceChild: if "field" in simpleAssetReferenceBaseChild.keys() and simpleAssetReferenceBaseChild.get("field") == "AssetPath" and "value" in simpleAssetReferenceBaseChild.keys(): # We've found the material override self.oldMaterialRelativePath = simpleAssetReferenceBaseChild.get("value") def create_adapter_with_new_model_assetId(self, assetIdValue): # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # editorRenderComponentAdapter = xml.etree.ElementTree.Element("Class", {'name': "EditorRenderComponentAdapter", 'field': "BaseClass1", 'type': "{3D614286-9164-53B5-833B-4F98D2820BA7}"}) editorComponentAdapter = xml.etree.ElementTree.Element("Class", {'name': "EditorComponentAdapter", 'field': "BaseClass1", 'version': "1", 'type': "{52DFE044-18C1-5861-BA2A-EDB61107FEE9}"}) editorComponentBase = xml.etree.ElementTree.Element("Class", {'name': "EditorComponentBase", 'field': "BaseClass1", 'version': "1", 'type': "{D5346BD4-7F20-444E-B370-327ACD03D4A0}"}) component = xml.etree.ElementTree.Element("Class", {'name': "AZ::Component", 'field': "BaseClass1", 'type': "{EDFCB2CF-F75D-43BE-B26B-F35821B29247}"}) u64 = xml.etree.ElementTree.Element("Class", {'name': "AZ::u64", 'field': "Id", 'value': "4528867579411318958", 'type': "{D6597933-47CD-4FC8-B911-63F3E2B0993A}"}) component.append(u64) editorComponentBase.append(component) meshComponentController = create_xml_element_from_string("") meshComponentConfig = xml.etree.ElementTree.Element("Class", {'name': "AZ::Render::MeshComponentConfig", 'field': "Configuration", 'type': "{63737345-51B1-472B-9355-98F99993909B}"}) modelAsset = xml.etree.ElementTree.Element("Class", {'name': "Asset", 'field': "ModelAsset", 'value': assetIdValue, 'version': "1", 'type': "{77A19D40-8731-4D3C-9041-1B43047366A4}"}) excludeFromReflectionCubeMaps = xml.etree.ElementTree.Element("Class", {'name': "bool", 'field': "ExcludeFromReflectionCubeMaps", 'value': "false", 'type': "{A0CA880C-AFE4-43CB-926C-59AC48496112}"}) meshComponentConfig.append(modelAsset) meshComponentConfig.append(excludeFromReflectionCubeMaps) meshComponentController.append(meshComponentConfig) editorComponentAdapter.append(editorComponentBase) editorComponentAdapter.append(meshComponentController) editorRenderComponentAdapter.append(editorComponentAdapter) return editorRenderComponentAdapter def convert(self, xmlElement, parent): """ Returns a list of xml elements (siblings) """ # Now clear the legacy mesh component xmlElement.clear() # And replace the content with an Atom mesh component xmlElement.set("name", "AZ::Render::EditorMeshComponent") xmlElement.set("field", "element") xmlElement.set("version", "1") xmlElement.set("type", "{DCE68F6E-2E16-4CB4-A834-B6C2F900A7E9}") xmlElement.append(self.create_adapter_with_new_model_assetId(self.newAssetId)) if len(self.oldMaterialRelativePath) == 0 or self.oldMaterialRelativePath[0:self.oldMaterialRelativePath.find(".mtl")] == self.oldFbxRelativePathWithoutExtension: # There was no material override self.statsCollector.noMaterialOverrideCount += 1 else: # There was a material override self.statsCollector.materialOverrideCount += 1 # Now that we have an Atom MeshComponent, we need an Atom MaterialComponent as a neighbor to 'child' (the new mesh component) atomMaterialInDefaultSlot = self.materialComponentConverter.convert_legacy_mtl_relative_path_to_atom_material_assetid(self.normalizedProjectDir, self.oldMaterialRelativePath, self.oldFbxRelativePathWithoutExtension) isActor = False atomMaterialList = self.materialComponentConverter.convert_legacy_mtl_relative_path_to_atom_material_list(self.normalizedProjectDir, self.oldMaterialRelativePath, self.oldFbxRelativePathWithoutExtension, isActor) parent.append(self.materialComponentConverter.create_material_component_with_material_assignments(atomMaterialInDefaultSlot, atomMaterialList)) def reset(self): self.newAssetId = "" self.oldMaterialRelativePath = "" self.oldFbxRelativePathWithoutExtension = ""