120 lines
4.7 KiB
Python
120 lines
4.7 KiB
Python
import os
|
|
import pathlib
|
|
import sys
|
|
|
|
import bpy
|
|
|
|
|
|
PNG_SIGNATURE = b"\x89PNG\r\n\x1a\n"
|
|
|
|
|
|
def save_generated_png(path, name, color):
|
|
image = bpy.data.images.new(name, width=8, height=8, alpha=True)
|
|
image.generated_color = color
|
|
image.filepath_raw = str(path)
|
|
image.file_format = "PNG"
|
|
image.save()
|
|
bpy.data.images.remove(image)
|
|
|
|
|
|
def material_object(name, image, x):
|
|
mesh = bpy.data.meshes.new(f"{name}Mesh")
|
|
mesh.from_pydata([(-1, -1, 0), (1, -1, 0), (0, 1, 0)], [], [(0, 1, 2)])
|
|
obj = bpy.data.objects.new(name, mesh)
|
|
obj.location.x = x
|
|
bpy.context.scene.collection.objects.link(obj)
|
|
material = bpy.data.materials.new(f"{name}Material")
|
|
material.use_nodes = True
|
|
texture = material.node_tree.nodes.new("ShaderNodeTexImage")
|
|
texture.image = image
|
|
material.node_tree.links.new(
|
|
texture.outputs["Color"], material.node_tree.nodes["Principled BSDF"].inputs["Base Color"])
|
|
mesh.materials.append(material)
|
|
|
|
|
|
def generate_library(path):
|
|
bpy.ops.wm.read_factory_settings(use_empty=True)
|
|
image = bpy.data.images.new("LinkedLibraryTexture", width=16, height=8, alpha=True)
|
|
image.generated_color = (0.1, 0.7, 0.3, 1.0)
|
|
image.use_fake_user = True
|
|
bpy.ops.wm.save_as_mainfile(filepath=str(path), compress=False)
|
|
|
|
|
|
def generate_matrix(output_dir, library_path, tile_paths):
|
|
bpy.ops.wm.read_factory_settings(use_empty=True)
|
|
|
|
generated = bpy.data.images.new("GeneratedTexture", width=12, height=6, alpha=True)
|
|
generated.generated_type = "COLOR_GRID"
|
|
generated.generated_color = (0.2, 0.4, 0.8, 1.0)
|
|
material_object("GeneratedImageObject", generated, -4.5)
|
|
|
|
udim = bpy.data.images.load(str(tile_paths[0]), check_existing=False)
|
|
udim.name = "UDIMTexture"
|
|
udim.source = "TILED"
|
|
udim.filepath = str(tile_paths[0]).replace("1001", "<UDIM>")
|
|
if udim.tiles.get(1002) is None:
|
|
udim.tiles.new(1002, label="Second Tile")
|
|
udim.pack()
|
|
material_object("UDIMImageObject", udim, -1.5)
|
|
|
|
missing = bpy.data.images.new("MissingExternalTexture", width=1, height=1)
|
|
missing.source = "FILE"
|
|
missing.filepath = "//missing/not-present.png"
|
|
material_object("MissingImageObject", missing, 1.5)
|
|
|
|
with bpy.data.libraries.load(str(library_path), link=True) as (data_from, data_to):
|
|
if "LinkedLibraryTexture" not in data_from.images:
|
|
raise RuntimeError("linked resource library image is missing")
|
|
data_to.images = ["LinkedLibraryTexture"]
|
|
linked = data_to.images[0]
|
|
material_object("LinkedImageObject", linked, 4.5)
|
|
|
|
output = output_dir / "image_resource_matrix.blend"
|
|
bpy.ops.wm.save_as_mainfile(filepath=str(output), compress=False)
|
|
print(
|
|
"image-resource-generated "
|
|
f"fixture={output} udim_tiles={[tile.number for tile in udim.tiles]} "
|
|
f"udim_packed={len(udim.packed_files)}")
|
|
|
|
|
|
def generate_corrupt(output_dir, png_path):
|
|
bpy.ops.wm.read_factory_settings(use_empty=True)
|
|
image = bpy.data.images.load(str(png_path), check_existing=False)
|
|
image.name = "CorruptPackedTexture"
|
|
image.pack()
|
|
material_object("CorruptPackedImageObject", image, 0)
|
|
output = output_dir / "corrupt_packed_image.blend"
|
|
bpy.ops.wm.save_as_mainfile(filepath=str(output), compress=False)
|
|
data = output.read_bytes()
|
|
signature_offset = data.find(PNG_SIGNATURE)
|
|
if signature_offset < 0 or data.find(PNG_SIGNATURE, signature_offset + 1) >= 0:
|
|
raise RuntimeError("expected exactly one packed PNG signature in corrupt fixture")
|
|
output.write_bytes(data[:signature_offset] + b"BROKEN!!" + data[signature_offset + 8:])
|
|
print(f"image-resource-corrupted fixture={output} payloadOffset={signature_offset}")
|
|
|
|
|
|
def main(output_directory):
|
|
output_dir = pathlib.Path(output_directory).resolve()
|
|
support_dir = output_dir / "resources"
|
|
support_dir.mkdir(parents=True, exist_ok=True)
|
|
tile_1001 = support_dir / "udim_1001.png"
|
|
tile_1002 = support_dir / "udim_1002.png"
|
|
corrupt_png = support_dir / "corrupt_source.png"
|
|
|
|
bpy.ops.wm.read_factory_settings(use_empty=True)
|
|
save_generated_png(tile_1001, "Tile1001Source", (1.0, 0.1, 0.1, 1.0))
|
|
save_generated_png(tile_1002, "Tile1002Source", (0.1, 0.2, 1.0, 1.0))
|
|
save_generated_png(corrupt_png, "CorruptSource", (0.8, 0.2, 0.7, 1.0))
|
|
|
|
library_path = support_dir / "image_resource_library.blend"
|
|
generate_library(library_path)
|
|
generate_matrix(output_dir, library_path, (tile_1001, tile_1002))
|
|
generate_corrupt(output_dir, corrupt_png)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
arguments = sys.argv[sys.argv.index("--") + 1:]
|
|
if len(arguments) != 1:
|
|
raise SystemExit("usage: blender -b --python generate-image-resource-fixtures.py -- output-directory")
|
|
main(arguments[0])
|