|
@@ -5,55 +5,16 @@
|
|
|
# SPDX-License-Identifier: Apache-2.0 OR MIT
|
|
|
#
|
|
|
#
|
|
|
-import os, traceback, binascii, sys, json, pathlib, logging
|
|
|
-import azlmbr.math
|
|
|
import azlmbr.bus
|
|
|
+import azlmbr.math
|
|
|
+
|
|
|
+from scene_helpers import *
|
|
|
+
|
|
|
|
|
|
#
|
|
|
# SceneAPI Processor
|
|
|
#
|
|
|
|
|
|
-
|
|
|
-def log_exception_traceback():
|
|
|
- data = traceback.format_exc()
|
|
|
- logger = logging.getLogger('python')
|
|
|
- logger.error(data)
|
|
|
-
|
|
|
-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 = []
|
|
|
- paths = []
|
|
|
-
|
|
|
- while node.IsValid():
|
|
|
- # store children to process after siblings
|
|
|
- if sceneGraph.has_node_child(node):
|
|
|
- children.append(sceneGraph.get_node_child(node))
|
|
|
-
|
|
|
- nodeName = sceneData.SceneGraphName(sceneGraph.get_node_name(node))
|
|
|
- paths.append(nodeName.get_path())
|
|
|
-
|
|
|
- # store any node that has mesh data content
|
|
|
- nodeContent = sceneGraph.get_node_content(node)
|
|
|
- if nodeContent.CastWithTypeName('MeshData'):
|
|
|
- if sceneGraph.is_node_end_point(node) is False:
|
|
|
- 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, paths
|
|
|
-
|
|
|
def add_material_component(entity_id):
|
|
|
# Create an override AZ::Render::EditorMaterialComponent
|
|
|
editor_material_component = azlmbr.entity.EntityUtilityBus(
|
|
@@ -64,24 +25,24 @@ def add_material_component(entity_id):
|
|
|
|
|
|
# this fills out the material asset to a known product AZMaterial asset relative path
|
|
|
json_update = json.dumps({
|
|
|
- "Controller": { "Configuration": { "materials": [
|
|
|
- {
|
|
|
- "Key": {},
|
|
|
- "Value": { "MaterialAsset":{
|
|
|
- "assetHint": "materials/basic_grey.azmaterial"
|
|
|
- }}
|
|
|
- }]
|
|
|
- }}
|
|
|
- });
|
|
|
- result = azlmbr.entity.EntityUtilityBus(azlmbr.bus.Broadcast, "UpdateComponentForEntity", entity_id, editor_material_component, json_update)
|
|
|
+ "Controller": {"Configuration": {"materials": [
|
|
|
+ {
|
|
|
+ "Key": {},
|
|
|
+ "Value": {"MaterialAsset": {
|
|
|
+ "assetHint": "materials/basic_grey.azmaterial"
|
|
|
+ }}
|
|
|
+ }]
|
|
|
+ }}
|
|
|
+ })
|
|
|
+ result = azlmbr.entity.EntityUtilityBus(azlmbr.bus.Broadcast, "UpdateComponentForEntity", entity_id,
|
|
|
+ editor_material_component, json_update)
|
|
|
|
|
|
if not result:
|
|
|
raise RuntimeError("UpdateComponentForEntity for editor_material_component failed")
|
|
|
|
|
|
+
|
|
|
def update_manifest(scene):
|
|
|
- import json
|
|
|
import uuid, os
|
|
|
- import azlmbr.scene as sceneApi
|
|
|
import azlmbr.scene.graph
|
|
|
from scene_api import scene_data as sceneData
|
|
|
|
|
@@ -89,9 +50,9 @@ def update_manifest(scene):
|
|
|
# Get a list of all the mesh nodes, as well as all the nodes
|
|
|
mesh_name_list, all_node_paths = get_mesh_node_names(graph)
|
|
|
scene_manifest = sceneData.SceneManifest()
|
|
|
-
|
|
|
+
|
|
|
clean_filename = scene.sourceFilename.replace('.', '_')
|
|
|
-
|
|
|
+
|
|
|
# Compute the filename of the scene file
|
|
|
source_basepath = scene.watchFolder
|
|
|
source_relative_path = os.path.dirname(os.path.relpath(clean_filename, source_basepath))
|
|
@@ -108,7 +69,7 @@ def update_manifest(scene):
|
|
|
# Create a unique mesh group name using the filename + node name
|
|
|
mesh_group_name = '{}_{}'.format(source_filename_only, mesh_name.get_name())
|
|
|
# Remove forbidden filename characters from the name since this will become a file on disk later
|
|
|
- mesh_group_name = "".join(char for char in mesh_group_name if char not in "|<>:\"/?*\\")
|
|
|
+ mesh_group_name = sanitize_name_for_disk(mesh_group_name)
|
|
|
# Add the MeshGroup to the manifest and give it a unique ID
|
|
|
mesh_group = scene_manifest.add_mesh_group(mesh_group_name)
|
|
|
mesh_group['id'] = '{' + str(uuid.uuid5(uuid.NAMESPACE_DNS, source_filename_only + mesh_path)) + '}'
|
|
@@ -129,16 +90,18 @@ def update_manifest(scene):
|
|
|
# Create an editor entity
|
|
|
entity_id = azlmbr.entity.EntityUtilityBus(azlmbr.bus.Broadcast, "CreateEditorReadyEntity", mesh_group_name)
|
|
|
# Add an EditorMeshComponent to the entity
|
|
|
- editor_mesh_component = azlmbr.entity.EntityUtilityBus(azlmbr.bus.Broadcast, "GetOrAddComponentByTypeName", entity_id, "AZ::Render::EditorMeshComponent")
|
|
|
- # Set the ModelAsset assetHint to the relative path of the input asset + the name of the MeshGroup we just created + the azmodel extension
|
|
|
- # The MeshGroup we created will be output as a product in the asset's path named mesh_group_name.azmodel
|
|
|
- # The assetHint will be converted to an AssetId later during prefab loading
|
|
|
+ editor_mesh_component = azlmbr.entity.EntityUtilityBus(azlmbr.bus.Broadcast, "GetOrAddComponentByTypeName",
|
|
|
+ entity_id, "AZ::Render::EditorMeshComponent")
|
|
|
+ # Set the ModelAsset assetHint to the relative path of the input asset + the name of the MeshGroup we just
|
|
|
+ # created + the azmodel extension The MeshGroup we created will be output as a product in the asset's path
|
|
|
+ # named mesh_group_name.azmodel The assetHint will be converted to an AssetId later during prefab loading
|
|
|
json_update = json.dumps({
|
|
|
- "Controller": { "Configuration": { "ModelAsset": {
|
|
|
- "assetHint": os.path.join(source_relative_path, mesh_group_name) + ".azmodel" }}}
|
|
|
- });
|
|
|
+ "Controller": {"Configuration": {"ModelAsset": {
|
|
|
+ "assetHint": os.path.join(source_relative_path, mesh_group_name) + ".azmodel"}}}
|
|
|
+ })
|
|
|
# Apply the JSON above to the component we created
|
|
|
- result = azlmbr.entity.EntityUtilityBus(azlmbr.bus.Broadcast, "UpdateComponentForEntity", entity_id, editor_mesh_component, json_update)
|
|
|
+ result = azlmbr.entity.EntityUtilityBus(azlmbr.bus.Broadcast, "UpdateComponentForEntity", entity_id,
|
|
|
+ editor_mesh_component, json_update)
|
|
|
|
|
|
if not result:
|
|
|
raise RuntimeError("UpdateComponentForEntity failed for Mesh component")
|
|
@@ -149,17 +112,19 @@ def update_manifest(scene):
|
|
|
add_material_component(entity_id)
|
|
|
|
|
|
# Get the transform component
|
|
|
- transform_component = azlmbr.entity.EntityUtilityBus(azlmbr.bus.Broadcast, "GetOrAddComponentByTypeName", entity_id, "27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0")
|
|
|
+ transform_component = azlmbr.entity.EntityUtilityBus(azlmbr.bus.Broadcast, "GetOrAddComponentByTypeName",
|
|
|
+ entity_id, "27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0")
|
|
|
|
|
|
# Set this entity to be a child of the last entity we created
|
|
|
# This is just an example of how to do parenting and isn't necessarily useful to parent everything like this
|
|
|
if previous_entity_id is not None:
|
|
|
transform_json = json.dumps({
|
|
|
- "Parent Entity" : previous_entity_id.to_json()
|
|
|
- });
|
|
|
+ "Parent Entity": previous_entity_id.to_json()
|
|
|
+ })
|
|
|
|
|
|
# Apply the JSON update
|
|
|
- result = azlmbr.entity.EntityUtilityBus(azlmbr.bus.Broadcast, "UpdateComponentForEntity", entity_id, transform_component, transform_json)
|
|
|
+ result = azlmbr.entity.EntityUtilityBus(azlmbr.bus.Broadcast, "UpdateComponentForEntity", entity_id,
|
|
|
+ transform_component, transform_json)
|
|
|
|
|
|
if not result:
|
|
|
raise RuntimeError("UpdateComponentForEntity failed for Transform component")
|
|
@@ -171,37 +136,23 @@ def update_manifest(scene):
|
|
|
created_entities.append(entity_id)
|
|
|
|
|
|
# Create a prefab with all our entities
|
|
|
- prefab_filename = source_filename_only + ".prefab"
|
|
|
- created_template_id = azlmbr.prefab.PrefabSystemScriptingBus(azlmbr.bus.Broadcast, "CreatePrefab", created_entities, prefab_filename)
|
|
|
-
|
|
|
- if created_template_id == azlmbr.prefab.InvalidTemplateId:
|
|
|
- raise RuntimeError("CreatePrefab {} failed".format(prefab_filename))
|
|
|
-
|
|
|
- # Convert the prefab to a JSON string
|
|
|
- output = azlmbr.prefab.PrefabLoaderScriptingBus(azlmbr.bus.Broadcast, "SaveTemplateToString", created_template_id)
|
|
|
-
|
|
|
- if output.IsSuccess():
|
|
|
- jsonString = output.GetValue()
|
|
|
- uuid = azlmbr.math.Uuid_CreateRandom().ToString()
|
|
|
- jsonResult = json.loads(jsonString)
|
|
|
- # Add a PrefabGroup to the manifest and store the JSON on it
|
|
|
- scene_manifest.add_prefab_group(source_filename_only, uuid, jsonResult)
|
|
|
- else:
|
|
|
- raise RuntimeError("SaveTemplateToString failed for template id {}, prefab {}".format(created_template_id, prefab_filename))
|
|
|
+ create_prefab(scene_manifest, source_filename_only, created_entities)
|
|
|
|
|
|
# Convert the manifest to a JSON string and return it
|
|
|
new_manifest = scene_manifest.export()
|
|
|
|
|
|
return new_manifest
|
|
|
|
|
|
+
|
|
|
sceneJobHandler = None
|
|
|
|
|
|
+
|
|
|
def on_update_manifest(args):
|
|
|
try:
|
|
|
scene = args[0]
|
|
|
return update_manifest(scene)
|
|
|
except RuntimeError as err:
|
|
|
- print (f'ERROR - {err}')
|
|
|
+ print(f'ERROR - {err}')
|
|
|
log_exception_traceback()
|
|
|
except:
|
|
|
log_exception_traceback()
|
|
@@ -209,10 +160,12 @@ def on_update_manifest(args):
|
|
|
global sceneJobHandler
|
|
|
sceneJobHandler = None
|
|
|
|
|
|
+
|
|
|
# try to create SceneAPI handler for processing
|
|
|
try:
|
|
|
import azlmbr.scene as sceneApi
|
|
|
- if (sceneJobHandler == None):
|
|
|
+
|
|
|
+ if sceneJobHandler is None:
|
|
|
sceneJobHandler = sceneApi.ScriptBuildingNotificationBusHandler()
|
|
|
sceneJobHandler.connect()
|
|
|
sceneJobHandler.add_callback('OnUpdateManifest', on_update_manifest)
|