"""Reload saved assets and evaluate geometry in the target Blender process.""" from math import isfinite from pathlib import Path import bpy ASSET_PATH = Path(__file__).resolve().parents[2] / "src/anyimage/assets/O_AnyImage.blend" GEOMETRY_NAMES = { "O Image Plane", "O Image Depth Plane", "O Image Relief Plane", "O Image Cutout", "O Image Depth Cutout", "O Image Depth Balloon", } SHADER_NAMES = {"O Image Layer", "O Image Depth Layer", "O Shadeless"} def check_asset_library(asset_path): """Check library completeness and finite, nonempty evaluated geometry.""" with bpy.data.libraries.load(str(asset_path), link=True) as (source, target): assert set(source.node_groups) == GEOMETRY_NAMES | SHADER_NAMES target.node_groups = list(source.node_groups) depth_image = bpy.data.images.new("Asset Check Depth", width=8, height=8, float_buffer=True) depth_image.colorspace_settings.name = "Non-Color" depth_image.pixels.foreach_set([ value for y in range(8) for x in range(8) for value in ((x + 0.5) / 8 - 0.5, (y + 0.5) / 8 - 0.5, 2.0, 1.0) ]) for node_group in target.node_groups: expected_type = "GeometryNodeTree" if node_group.name in GEOMETRY_NAMES else "ShaderNodeTree" assert node_group.bl_idname == expected_type and node_group.library is not None, node_group.name if expected_type == "ShaderNodeTree": continue mesh = bpy.data.meshes.new("Asset Check Plane") mesh.from_pydata([(-0.5, -0.5, 0), (0.5, -0.5, 0), (0.5, 0.5, 0), (-0.5, 0.5, 0)], [], [(0, 1, 2, 3)]) uv = mesh.uv_layers.new(name="UVMap") for loop in mesh.loops: position = mesh.vertices[loop.vertex_index].co uv.data[loop.index].uv = (position.x + 0.5, position.y + 0.5) profile = mesh.attributes.new("o_balloon", "FLOAT", "POINT") for value in profile.data: value.value = 0.2 obj = bpy.data.objects.new("Asset Check", mesh) bpy.context.collection.objects.link(obj) modifier = obj.modifiers.new("Asset Check", "NODES") modifier.node_group = node_group values = {"Subdivide": 0, "Thickness": 0.2, "Reference Depth": 2.0, "Depth Image": depth_image, "Uniform Scale": 1.0, "Normal Smooth": 0} for item in node_group.interface.items_tree: if item.item_type == "SOCKET" and item.in_out == "INPUT" and item.name in values: modifier[item.identifier] = values[item.name] obj.update_tag(refresh={"DATA"}) bpy.context.view_layer.update() evaluated = obj.evaluated_get(bpy.context.evaluated_depsgraph_get()) result = evaluated.to_mesh() try: assert len(result.vertices) and len(result.polygons), node_group.name assert all(isfinite(value) for vertex in result.vertices for value in vertex.co), node_group.name finally: evaluated.to_mesh_clear() bpy.data.objects.remove(obj, do_unlink=True) bpy.data.meshes.remove(mesh) bpy.data.images.remove(depth_image) print(f"Checked {len(target.node_groups)} saved node groups in Blender {bpy.app.version_string}") def main(): bpy.ops.wm.read_factory_settings(use_empty=True) check_asset_library(ASSET_PATH) if __name__ == "__main__": main()