199 lines
8.4 KiB
Python
199 lines
8.4 KiB
Python
import bpy
|
|
from .helpers import traverse_tree
|
|
|
|
# returns the list of the collections in use for a given scene
|
|
# FIXME: this should also look into sub collections
|
|
def get_used_collections(scene):
|
|
root_collection = scene.collection
|
|
|
|
scene_objects = [o for o in root_collection.objects]
|
|
collection_names = set()
|
|
used_collections = []
|
|
for object in scene_objects:
|
|
#print("object ", object)
|
|
if object.instance_type == 'COLLECTION':
|
|
collection_name = object.instance_collection.name
|
|
if not collection_name in collection_names:
|
|
collection_names.add(collection_name)
|
|
used_collections.append(object.instance_collection)
|
|
|
|
#print("scene objects", scene_objects)
|
|
return (collection_names, used_collections)
|
|
|
|
# gets all collections that should ALWAYS be exported to their respective gltf files, even if they are not used in the main scene/level
|
|
def get_marked_collections(scene, addon_prefs):
|
|
export_marked_assets = getattr(addon_prefs,"export_marked_assets")
|
|
|
|
# print("checking library for marked collections")
|
|
root_collection = scene.collection
|
|
marked_collections = []
|
|
collection_names = []
|
|
for collection in traverse_tree(root_collection):
|
|
if 'AutoExport' in collection and collection['AutoExport'] == True:
|
|
marked_collections.append(collection)
|
|
collection_names.append(collection.name)
|
|
# if you have marked collections as assets you can auto export them too
|
|
if export_marked_assets and collection.asset_data is not None:
|
|
marked_collections.append(collection)
|
|
collection_names.append(collection.name)
|
|
return (collection_names, marked_collections)
|
|
|
|
# gets all collections within collections that might also be relevant
|
|
def get_sub_collections(collections, parent, children_per_collection):
|
|
collection_names = set()
|
|
used_collections = []
|
|
|
|
|
|
for root_collection in collections:
|
|
node = Node(name=root_collection.name, parent=parent)
|
|
parent.children.append(node)
|
|
|
|
|
|
#print("root collection", root_collection.name)
|
|
for collection in traverse_tree(root_collection): # TODO: filter out COLLECTIONS that have the flatten flag (unlike the flatten flag on colleciton instances themselves)
|
|
node_name = collection.name
|
|
children_per_collection[node_name] = []
|
|
#print(" scanning", collection.name)
|
|
for object in collection.objects:
|
|
#print("FLATTEN", object.name, 'Flatten' in object)
|
|
if object.instance_type == 'COLLECTION' : # and not 'Flatten' in object:
|
|
collection_name = object.instance_collection.name
|
|
(sub_names, sub_collections) = get_sub_collections([object.instance_collection], node, children_per_collection)
|
|
if len(list(sub_names)) > 0:
|
|
children_per_collection[node_name] += (list(sub_names))
|
|
#print(" found sub collection in use", object.name, object.instance_collection)
|
|
|
|
|
|
if not collection_name in collection_names:
|
|
collection_names.add(collection_name)
|
|
used_collections.append(object.instance_collection)
|
|
collection_names.update(sub_names)
|
|
|
|
#for sub in traverse_tree(root_collection):
|
|
return (collection_names, used_collections)
|
|
|
|
# FIXME: get rid of this, ugh
|
|
def flatten_collection_tree(node, children_per_collection):
|
|
children_per_collection[node.name] = []
|
|
for child in node.children:
|
|
if not node.name in children_per_collection[node.name]:
|
|
children_per_collection[node.name].append(child.name)
|
|
flatten_collection_tree(child, children_per_collection)
|
|
children_per_collection[node.name] = list(set( children_per_collection[node.name]))
|
|
|
|
|
|
class Node :
|
|
def __init__(self, name="", parent=None):
|
|
self.name = name
|
|
self.children = []
|
|
self.changed = False
|
|
self.parent = parent
|
|
return
|
|
def __str__(self):
|
|
children = list(map(lambda child: str(child), self.children))
|
|
return "name: " +self.name + ", children:" + str(children)
|
|
|
|
# get exportable collections from lists of mains scenes and lists of library scenes
|
|
def get_exportable_collections(main_scenes, library_scenes, addon_prefs):
|
|
|
|
all_collections = []
|
|
all_collection_names = []
|
|
root_node = Node()
|
|
root_node.name = "root"
|
|
children_per_collection = {}
|
|
|
|
|
|
for main_scene in main_scenes:
|
|
(collection_names, collections) = get_used_collections(main_scene)
|
|
all_collection_names = all_collection_names + list(collection_names)
|
|
all_collections = all_collections + collections
|
|
for library_scene in library_scenes:
|
|
marked_collections = get_marked_collections(library_scene, addon_prefs)
|
|
all_collection_names = all_collection_names + marked_collections[0]
|
|
all_collections = all_collections + marked_collections[1]
|
|
|
|
(collection_names, collections) = get_sub_collections(all_collections, root_node, children_per_collection)
|
|
all_collection_names = all_collection_names + list(collection_names)
|
|
children_per_collection = {}
|
|
flatten_collection_tree(root_node, children_per_collection)
|
|
#print("ROOT NODE", children_per_collection) #
|
|
|
|
return (all_collection_names, children_per_collection)
|
|
|
|
def get_collections_per_scene(collection_names, library_scenes):
|
|
collections_per_scene = {}
|
|
for scene in library_scenes:
|
|
root_collection = scene.collection
|
|
for cur_collection in traverse_tree(root_collection):
|
|
if cur_collection.name in collection_names:
|
|
if not scene.name in collections_per_scene:
|
|
collections_per_scene[scene.name] = []
|
|
collections_per_scene[scene.name].append(cur_collection.name)
|
|
|
|
return collections_per_scene
|
|
|
|
def get_collections_in_library(library_scenes):
|
|
"""all_collections = []
|
|
all_collection_names = []
|
|
for main_scene in main_scenes:
|
|
(collection_names, collections) = get_used_collections(main_scene)
|
|
all_collection_names = all_collection_names + list(collection_names)
|
|
all_collections = all_collections + collections"""
|
|
|
|
# now that we have the collections that are in use by collection instances, check if those collections are actully present in the library scenes
|
|
collections = []
|
|
collection_names = []
|
|
for library_scene in library_scenes:
|
|
root_collection = library_scene.collection
|
|
|
|
for collection in traverse_tree(root_collection):
|
|
collections.append(collection)
|
|
collection_names.append(collection.name)
|
|
return collection_names
|
|
|
|
|
|
def get_collection_hierarchy(root_col, levels=1):
|
|
"""Read hierarchy of the collections in the scene"""
|
|
level_lookup = {}
|
|
def recurse(root_col, parent, depth):
|
|
if depth > levels:
|
|
return
|
|
if isinstance(parent, bpy.types.Collection):
|
|
level_lookup.setdefault(parent, []).append(root_col)
|
|
for child in root_col.children:
|
|
recurse(child, root_col, depth + 1)
|
|
recurse(root_col, root_col.children, 0)
|
|
return level_lookup
|
|
|
|
# the active collection is a View Layer concept, so you actually have to find the active LayerCollection
|
|
# which must be done recursively
|
|
def find_layer_collection_recursive(find, col):
|
|
# print("root collection", col)
|
|
for c in col.children:
|
|
# print("child collection", c)
|
|
if c.collection == find:
|
|
return c
|
|
return None
|
|
|
|
#Recursivly transverse layer_collection for a particular name
|
|
def recurLayerCollection(layerColl, collName):
|
|
found = None
|
|
if (layerColl.name == collName):
|
|
return layerColl
|
|
for layer in layerColl.children:
|
|
found = recurLayerCollection(layer, collName)
|
|
if found:
|
|
return found
|
|
# traverse the collection hierarchy updward until you find one collection inside target_collections
|
|
def find_collection_ascendant_target_collection(collection_parents, target_collections, collection):
|
|
if collection == None:
|
|
return None
|
|
if collection in target_collections:
|
|
return collection
|
|
if collection in collection_parents:
|
|
parent = collection_parents[collection]
|
|
else:
|
|
return None
|
|
return find_collection_ascendant_target_collection(collection_parents, target_collections, parent)
|
|
|