diff --git a/Gems/Blast/Editor/Scripts/blast_asset_builder.py b/Gems/Blast/Editor/Scripts/blast_asset_builder.py index 06dc15f5c1..a570489ed1 100644 --- a/Gems/Blast/Editor/Scripts/blast_asset_builder.py +++ b/Gems/Blast/Editor/Scripts/blast_asset_builder.py @@ -95,7 +95,9 @@ def generate_assetinfo_product(request): outputFilename = os.path.join(request.tempDirPath, assetinfoFilename) # the only rule in it is to run this file again as a scene processor - currentScript = pathlib.Path(__file__).resolve() + currentScript = str(pathlib.Path(__file__).resolve()) + currentScript = currentScript.replace('\\', '/').lower() + currentScript = currentScript.replace('blast_asset_builder.py', 'blast_chunk_processor.py') aDict = {"values": [{"$type": "ScriptProcessorRule", "scriptFilename": f"{currentScript}"}]} jsonString = json.dumps(aDict) jsonFile = open(outputFilename, "w") @@ -167,124 +169,3 @@ try: pythonAssetBuilderHandler = register_asset_builder() except: pythonAssetBuilderHandler = None - -# -# SceneAPI Processor -# -blastChunksAssetType = azlmbr.math.Uuid_CreateString('{993F0B0F-37D9-48C6-9CC2-E27D3F3E343E}', 0) - -def export_chunk_asset(scene, outputDirectory, platformIdentifier, productList): - import azlmbr.scene - import azlmbr.object - import azlmbr.paths - import json, os - - jsonFilename = os.path.basename(scene.sourceFilename) - jsonFilename = os.path.join(outputDirectory, jsonFilename + '.blast_chunks') - - # prepare output folder - basePath, _ = os.path.split(jsonFilename) - outputPath = os.path.join(outputDirectory, basePath) - if not os.path.exists(outputPath): - os.makedirs(outputPath, False) - - # write out a JSON file with the chunk file info - with open(jsonFilename, "w") as jsonFile: - jsonFile.write(scene.manifest.ExportToJson()) - - exportProduct = azlmbr.scene.ExportProduct() - exportProduct.filename = jsonFilename - exportProduct.sourceId = scene.sourceGuid - exportProduct.assetType = blastChunksAssetType - exportProduct.subId = 101 - - exportProductList = azlmbr.scene.ExportProductList() - exportProductList.AddProduct(exportProduct) - return exportProductList - -def on_prepare_for_export(args): - try: - scene = args[0] # azlmbr.scene.Scene - outputDirectory = args[1] # string - platformIdentifier = args[2] # string - productList = args[3] # azlmbr.scene.ExportProductList - return export_chunk_asset(scene, outputDirectory, platformIdentifier, productList) - except: - log_exception_traceback() - -def get_mesh_node_names(sceneGraph): - import azlmbr.scene as sceneApi - import azlmbr.scene.graph - from scene_api import scene_data as sceneData - - meshDataList = [] - node = sceneGraph.get_root() - children = [] - - while node.IsValid(): - # store children to process after siblings - if sceneGraph.has_node_child(node): - children.append(sceneGraph.get_node_child(node)) - - # store any node that has mesh data content - nodeContent = sceneGraph.get_node_content(node) - if nodeContent is not None and nodeContent.CastWithTypeName('MeshData'): - if sceneGraph.is_node_end_point(node) is False: - nodeName = sceneData.SceneGraphName(sceneGraph.get_node_name(node)) - nodePath = nodeName.get_path() - if (len(nodeName.get_path())): - meshDataList.append(sceneData.SceneGraphName(sceneGraph.get_node_name(node))) - - # advance to next node - if sceneGraph.has_node_sibling(node): - node = sceneGraph.get_node_sibling(node) - elif children: - node = children.pop() - else: - node = azlmbr.scene.graph.NodeIndex() - - return meshDataList - -def update_manifest(scene): - import uuid, os - import azlmbr.scene as sceneApi - import azlmbr.scene.graph - from scene_api import scene_data as sceneData - - graph = sceneData.SceneGraph(scene.graph) - meshNameList = get_mesh_node_names(graph) - sceneManifest = sceneData.SceneManifest() - sourceFilenameOnly = os.path.basename(scene.sourceFilename) - sourceFilenameOnly = sourceFilenameOnly.replace('.','_') - - for activeMeshIndex in range(len(meshNameList)): - chunkName = meshNameList[activeMeshIndex] - chunkPath = chunkName.get_path() - meshGroupName = '{}_{}'.format(sourceFilenameOnly, chunkName.get_name()) - meshGroup = sceneManifest.add_mesh_group(meshGroupName) - meshGroup['id'] = '{' + str(uuid.uuid5(uuid.NAMESPACE_DNS, sourceFilenameOnly + chunkPath)) + '}' - sceneManifest.mesh_group_select_node(meshGroup, chunkPath) - - return sceneManifest.export() - -sceneJobHandler = None - -def on_update_manifest(args): - try: - scene = args[0] - return update_manifest(scene) - except: - global sceneJobHandler - sceneJobHandler = None - log_exception_traceback() - -# try to create SceneAPI handler for processing -try: - import azlmbr.scene as sceneApi - if (sceneJobHandler == None): - sceneJobHandler = sceneApi.ScriptBuildingNotificationBusHandler() - sceneJobHandler.connect() - sceneJobHandler.add_callback('OnUpdateManifest', on_update_manifest) - sceneJobHandler.add_callback('OnPrepareForExport', on_prepare_for_export) -except: - sceneJobHandler = None diff --git a/Gems/Blast/Editor/Scripts/blast_chunk_processor.py b/Gems/Blast/Editor/Scripts/blast_chunk_processor.py new file mode 100644 index 0000000000..d112f465e9 --- /dev/null +++ b/Gems/Blast/Editor/Scripts/blast_chunk_processor.py @@ -0,0 +1,141 @@ +""" +Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. + +SPDX-License-Identifier: Apache-2.0 OR MIT +""" + +""" +This a Python Asset Builder script examines each .blast file to see if an +associated .fbx file needs to be processed by exporting all of its chunks +into a scene manifest + +This is also a SceneAPI script that executes from a foo.fbx.assetinfo scene +manifest that writes out asset chunk data for .blast files +""" +import os, traceback, binascii, sys, json, pathlib +import azlmbr.math +import azlmbr.asset +import azlmbr.asset.entity +import azlmbr.asset.builder +import azlmbr.bus + +# +# SceneAPI Processor +# +blastChunksAssetType = azlmbr.math.Uuid_CreateString('{993F0B0F-37D9-48C6-9CC2-E27D3F3E343E}', 0) + +def export_chunk_asset(scene, outputDirectory, platformIdentifier, productList): + import azlmbr.scene + import azlmbr.object + import azlmbr.paths + import json, os + + jsonFilename = os.path.basename(scene.sourceFilename) + jsonFilename = os.path.join(outputDirectory, jsonFilename + '.blast_chunks') + + # prepare output folder + basePath, _ = os.path.split(jsonFilename) + outputPath = os.path.join(outputDirectory, basePath) + if not os.path.exists(outputPath): + os.makedirs(outputPath, False) + + # write out a JSON file with the chunk file info + with open(jsonFilename, "w") as jsonFile: + jsonFile.write(scene.manifest.ExportToJson()) + + exportProduct = azlmbr.scene.ExportProduct() + exportProduct.filename = jsonFilename + exportProduct.sourceId = scene.sourceGuid + exportProduct.assetType = blastChunksAssetType + exportProduct.subId = 101 + + exportProductList = azlmbr.scene.ExportProductList() + exportProductList.AddProduct(exportProduct) + return exportProductList + +def on_prepare_for_export(args): + try: + scene = args[0] # azlmbr.scene.Scene + outputDirectory = args[1] # string + platformIdentifier = args[2] # string + productList = args[3] # azlmbr.scene.ExportProductList + return export_chunk_asset(scene, outputDirectory, platformIdentifier, productList) + except: + log_exception_traceback() + +def get_mesh_node_names(sceneGraph): + import azlmbr.scene as sceneApi + import azlmbr.scene.graph + from scene_api import scene_data as sceneData + + meshDataList = [] + node = sceneGraph.get_root() + children = [] + + while node.IsValid(): + # store children to process after siblings + if sceneGraph.has_node_child(node): + children.append(sceneGraph.get_node_child(node)) + + # store any node that has mesh data content + nodeContent = sceneGraph.get_node_content(node) + if nodeContent is not None and nodeContent.CastWithTypeName('MeshData'): + if sceneGraph.is_node_end_point(node) is False: + nodeName = sceneData.SceneGraphName(sceneGraph.get_node_name(node)) + nodePath = nodeName.get_path() + if (len(nodeName.get_path())): + meshDataList.append(sceneData.SceneGraphName(sceneGraph.get_node_name(node))) + + # advance to next node + if sceneGraph.has_node_sibling(node): + node = sceneGraph.get_node_sibling(node) + elif children: + node = children.pop() + else: + node = azlmbr.scene.graph.NodeIndex() + + return meshDataList + +def update_manifest(scene): + import uuid, os + import azlmbr.scene as sceneApi + import azlmbr.scene.graph + from scene_api import scene_data as sceneData + + graph = sceneData.SceneGraph(scene.graph) + meshNameList = get_mesh_node_names(graph) + sceneManifest = sceneData.SceneManifest() + sourceFilenameOnly = os.path.basename(scene.sourceFilename) + sourceFilenameOnly = sourceFilenameOnly.replace('.','_') + + for activeMeshIndex in range(len(meshNameList)): + chunkName = meshNameList[activeMeshIndex] + chunkPath = chunkName.get_path() + meshGroupName = '{}_{}'.format(sourceFilenameOnly, chunkName.get_name()) + meshGroup = sceneManifest.add_mesh_group(meshGroupName) + meshGroup['id'] = '{' + str(uuid.uuid5(uuid.NAMESPACE_DNS, sourceFilenameOnly + chunkPath)) + '}' + sceneManifest.mesh_group_select_node(meshGroup, chunkPath) + + return sceneManifest.export() + +sceneJobHandler = None + +def on_update_manifest(args): + try: + scene = args[0] + return update_manifest(scene) + except: + global sceneJobHandler + sceneJobHandler = None + log_exception_traceback() + +# try to create SceneAPI handler for processing +try: + import azlmbr.scene as sceneApi + if (sceneJobHandler == None): + sceneJobHandler = sceneApi.ScriptBuildingNotificationBusHandler() + sceneJobHandler.connect() + sceneJobHandler.add_callback('OnUpdateManifest', on_update_manifest) + sceneJobHandler.add_callback('OnPrepareForExport', on_prepare_for_export) +except: + sceneJobHandler = None