98 lines
3.4 KiB
Python
98 lines
3.4 KiB
Python
# SPDX-FileCopyrightText: 2021 Blender Studio Tools Authors
|
|
#
|
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
from typing import Any, Tuple, Generator, List
|
|
from .. import constants
|
|
import bpy
|
|
|
|
|
|
####################################
|
|
############# ID Stuff #############
|
|
####################################
|
|
|
|
|
|
def get_id_info() -> List[Tuple[type, str, str]]:
|
|
"""Return a list of tuples with the python class, type identifier string, and bpy.data container name
|
|
of each ID type present in the blend file.
|
|
Eg. when called in a file containing meshes and objects, it will return at least:
|
|
[
|
|
(bpy.types.Object, 'OBJECT', "objects"),
|
|
(bpy.types.Mesh, 'MESH', "meshes"),
|
|
]
|
|
"""
|
|
bpy_prop_collection = type(bpy.data.objects)
|
|
id_info = []
|
|
for prop_name in dir(bpy.data):
|
|
coll_prop = getattr(bpy.data, prop_name)
|
|
if type(coll_prop) == bpy_prop_collection:
|
|
if len(coll_prop) == 0:
|
|
# We can't get full info about the ID type if there isn't at least one entry of it.
|
|
# But we shouldn't need it, since we don't have any entries of it!
|
|
continue
|
|
|
|
id_info.append((get_fundamental_id_type(coll_prop[0]), coll_prop[0].id_type, prop_name))
|
|
return id_info
|
|
|
|
|
|
def get_id_identifier_from_class(id_type: type):
|
|
"""Return the string name of an ID type class.
|
|
eg. bpy.types.Object -> 'OBJECT'
|
|
"""
|
|
id_info = get_id_info()
|
|
for typ, typ_str, container_str in id_info:
|
|
if id_type == typ:
|
|
return typ_str
|
|
|
|
|
|
def get_fundamental_id_type(datablock: bpy.types.ID) -> Any:
|
|
"""Certain datablocks have very specific types, such as
|
|
bpy.types.GeometryNodeTree instead of bpy.types.NodeTree.
|
|
|
|
This function should return their fundamental type, ie. parent class,
|
|
by reaching into the python Method Resolution Order (MRO) to find its
|
|
python class inheritance chain and then step back 4 steps:
|
|
object->bpy_struct->bpy.types.ID->bpy.types.WhatWeNeed"""
|
|
|
|
return type(datablock).mro()[-4]
|
|
|
|
|
|
def get_storage_of_id(datablock: bpy.types.ID) -> 'bpy_prop_collection':
|
|
"""Return the storage collection property of the datablock.
|
|
Eg. for an object, returns bpy.data.objects.
|
|
"""
|
|
|
|
fundamental_type = get_fundamental_id_type(datablock)
|
|
|
|
id_info = get_id_info()
|
|
for typ, _typ_str, container_str in id_info:
|
|
if fundamental_type == typ:
|
|
return getattr(bpy.data, container_str)
|
|
assert False, "Failed to find the type of this ID: " + str(datablock) + "with fundamental type: " + str(fundamental_type)
|
|
|
|
|
|
def traverse_collection_tree(
|
|
collection: bpy.types.Collection,
|
|
) -> Generator[bpy.types.Collection, None, None]:
|
|
yield collection
|
|
for child in collection.children:
|
|
yield from traverse_collection_tree(child)
|
|
|
|
|
|
def data_type_from_transfer_data_key(obj: bpy.types.Object, td_type: str):
|
|
"""Returns the data on an object that is referred to by the Transferable Data type"""
|
|
if td_type == constants.VERTEX_GROUP_KEY:
|
|
return obj.vertex_groups
|
|
if td_type == constants.MODIFIER_KEY:
|
|
return obj.modifiers
|
|
if td_type == constants.CONSTRAINT_KEY:
|
|
return obj.constraints
|
|
if td_type == constants.MATERIAL_SLOT_KEY:
|
|
return obj.material_slots
|
|
if td_type == constants.SHAPE_KEY_KEY:
|
|
return obj.data.shape_keys.key_blocks
|
|
if td_type == constants.ATTRIBUTE_KEY:
|
|
return obj.data.attributes
|
|
if td_type == constants.PARENT_KEY:
|
|
return obj.parent
|