import bpy from node_asset_test_support import validate_node_structure from anyimage.common.material import ( DEPTH_MATERIAL_NODE_GROUP_NAME, IMAGE_MATERIAL_NODE_GROUP_NAME, ) from anyimage.common.node import load_node_group, node_asset_path from anyimage.operators.cutout_tool.shape import ( CUTOUT_NODE_GROUP_NAMES, ) DEPTH_PLANE_NODE_GROUP_NAME = "O Image Depth Plane" RELIEF_PLANE_NODE_GROUP_NAME = "O Image Relief Plane" def input_names(group): return [ item.name for item in group.interface.items_tree if item.item_type == "SOCKET" and item.in_out == "INPUT" ] def test_saved_asset_contracts(): bpy.ops.wm.read_factory_settings(use_empty=True) image_plane = load_node_group("O Image Plane") depth_plane = load_node_group(DEPTH_PLANE_NODE_GROUP_NAME) relief_plane = load_node_group(RELIEF_PLANE_NODE_GROUP_NAME) image_layer = load_node_group(IMAGE_MATERIAL_NODE_GROUP_NAME) depth_layer = load_node_group(DEPTH_MATERIAL_NODE_GROUP_NAME) shadeless = load_node_group("O Shadeless") cutout_groups = { name: load_node_group(name) for name in set(CUTOUT_NODE_GROUP_NAMES.values()) } expected_names = { "O Image Plane", DEPTH_PLANE_NODE_GROUP_NAME, RELIEF_PLANE_NODE_GROUP_NAME, IMAGE_MATERIAL_NODE_GROUP_NAME, DEPTH_MATERIAL_NODE_GROUP_NAME, "O Shadeless", *CUTOUT_NODE_GROUP_NAMES.values(), } with bpy.data.libraries.load(str(node_asset_path()), link=False) as (source, _): assert set(source.node_groups) == expected_names assert image_plane.name == "O Image Plane" assert image_plane.bl_idname == "GeometryNodeTree" assert image_plane.is_modifier assert input_names(image_plane) == [ "Geometry", "Subdivide", "Thickness", ] for group, normal_controls in ((depth_plane, ["Normal Smooth", "Smooth Weight", "Validity Threshold"]), (relief_plane, [])): assert group.bl_idname == "GeometryNodeTree" and group.is_modifier assert input_names(group) == [ "Geometry", "Subdivide", "Thickness", "Depth Scale", *(["Smooth", "Valid Only"] if group == depth_plane else []), "Reference Depth", *normal_controls, "Uniform Scale", "Depth Image", ] inputs = {item.name: item for item in group.interface.items_tree if item.item_type == "SOCKET" and item.in_out == "INPUT"} assert inputs["Thickness"].default_value == 0 assert inputs["Thickness"].subtype == inputs["Reference Depth"].subtype == "DISTANCE" assert inputs["Subdivide"].default_value == 6 assert all(item.structure_type == "SINGLE" for item in inputs.values()) panels = [item for item in group.interface.items_tree if item.item_type == "PANEL"] assert [panel.name for panel in panels] == ["Options", "Data"] assert [item.name for item in panels[0].interface_items] == ["Reference Depth", *normal_controls] assert [item.name for item in panels[1].interface_items] == ["Uniform Scale", "Depth Image"] assert all(panel.default_closed for panel in panels) assert all(item.hide_in_modifier for item in panels[1].interface_items) assert image_layer.bl_idname == "ShaderNodeTree" assert input_names(image_layer) == [ "Color", "Alpha", "Normal", "Bump Scale", "Alpha Fix", "Normal Scale", "Object Space", ] assert depth_layer.bl_idname == "ShaderNodeTree" adjustment = next( item for item in image_layer.interface.items_tree if item.item_type == "SOCKET" and item.in_out == "INPUT" and item.name == "Alpha Fix" ) assert adjustment.default_value == 0.0 assert (adjustment.min_value, adjustment.max_value, adjustment.subtype) == (0, 1, "FACTOR") image_output = next(node for node in image_layer.nodes if node.type == "GROUP_OUTPUT") alpha_curve = image_output.inputs["Alpha"].links[0].from_node assert alpha_curve.bl_idname == "ShaderNodeFloatCurve" assert alpha_curve.inputs["Value"].links[0].from_socket.name == "Alpha" assert alpha_curve.inputs["Factor"].links[0].from_socket.name == "Alpha Fix" panels = [item for item in image_layer.interface.items_tree if item.item_type == "PANEL"] assert len(panels) == 1 and panels[0].name == "Options" and panels[0].default_closed assert [item.name for item in panels[0].interface_items] == ["Alpha Fix", "Normal Scale", "Object Space"] alpha_points = alpha_curve.mapping.curves[0].points assert len(alpha_points) == 4 for point, expected in zip(alpha_points, ((0, 0), (0.8, 0), (0.925, 0.925), (1, 1))): assert all(abs(actual - value) < 1e-6 for actual, value in zip(point.location, expected)) assert input_names(depth_layer) == [ "Color", "Alpha", "Depth", "Bump Scale", ] assert shadeless.name == "O Shadeless" assert shadeless.bl_idname == "ShaderNodeTree" assert input_names(shadeless) == ["Color"] assert set(cutout_groups) == set(CUTOUT_NODE_GROUP_NAMES.values()) for group in cutout_groups.values(): assert group.bl_idname == "GeometryNodeTree" assert group.is_modifier assert input_names(group)[0] == "Geometry" public_groups = { image_plane, depth_plane, relief_plane, image_layer, depth_layer, shadeless, *cutout_groups.values(), } loaded = {*public_groups, *cutout_groups.values()} for group in loaded: if group.bl_idname == "GeometryNodeTree": validate_node_structure(group) assert all(group.use_fake_user for group in public_groups) assert all(group.users > 0 for group in cutout_groups.values()) if bpy.app.version >= (5, 0, 0): assert all(group.library is not None for group in loaded) print( f"Validated Blender {bpy.app.version_string}: " + ", ".join(sorted(group.name for group in loaded)) )