Skip to content
Snippets Groups Projects
append_link.py 8.3 KiB
Newer Older
  • Learn to ignore specific revisions
  • Vilem Duha's avatar
    Vilem Duha committed
    # ##### BEGIN GPL LICENSE BLOCK #####
    #
    #  This program is free software; you can redistribute it and/or
    #  modify it under the terms of the GNU General Public License
    #  as published by the Free Software Foundation; either version 2
    #  of the License, or (at your option) any later version.
    #
    #  This program is distributed in the hope that it will be useful,
    #  but WITHOUT ANY WARRANTY; without even the implied warranty of
    #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    #  GNU General Public License for more details.
    #
    #  You should have received a copy of the GNU General Public License
    #  along with this program; if not, write to the Free Software Foundation,
    #  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
    #
    # ##### END GPL LICENSE BLOCK #####
    
    
    
    if "bpy" in locals():
        from importlib import reload
    
        utils = reload(utils)
    
        from blenderkit import utils, ui
    
    Vilem Duha's avatar
    Vilem Duha committed
    import bpy
    
    Vilem Duha's avatar
    Vilem Duha committed
    
    
    def append_brush(file_name, brushname=None, link=False, fake_user=True):
        '''append a brush'''
        with bpy.data.libraries.load(file_name, link=link, relative=True) as (data_from, data_to):
            for m in data_from.brushes:
                if m == brushname or brushname is None:
                    data_to.brushes = [m]
                    brushname = m
        brush = bpy.data.brushes[brushname]
        if fake_user:
            brush.use_fake_user = True
        return brush
    
    
    def append_material(file_name, matname=None, link=False, fake_user=True):
        '''append a material type asset'''
        # first, we have to check if there is a material with same name
        # in previous step there's check if the imported material
    
        # is already in the scene, so we know same name != same material
    
    Vilem Duha's avatar
    Vilem Duha committed
    
        mats_before = bpy.data.materials.keys()
    
        with bpy.data.libraries.load(file_name, link=link, relative=True) as (data_from, data_to):
            for m in data_from.materials:
                if m == matname or matname is None:
                    data_to.materials = [m]
    
    Vilem Duha's avatar
    Vilem Duha committed
                    # print(m, type(m))
    
    Vilem Duha's avatar
    Vilem Duha committed
                    matname = m
                    break;
    
        # we have to find the new material :(
        for mname in bpy.data.materials.keys():
            if mname not in mats_before:
                mat = bpy.data.materials[mname]
                break
    
        if fake_user:
            mat.use_fake_user = True
    
        return mat
    
    
    def append_scene(file_name, scenename=None, link=False, fake_user=False):
        '''append a scene type asset'''
        with bpy.data.libraries.load(file_name, link=link, relative=True) as (data_from, data_to):
            for s in data_from.scenes:
                if s == scenename or scenename is None:
                    data_to.scenes = [s]
                    scenename = s
        scene = bpy.data.scenes[scenename]
        if fake_user:
            scene.use_fake_user = True
        # scene has to have a new uuid, so user reports aren't screwed.
        scene['uuid'] = str(uuid.uuid4())
        return scene
    
    
    
    def link_collection(file_name, obnames=[], location=(0, 0, 0), link=False, parent = None, **kwargs):
    
    Vilem Duha's avatar
    Vilem Duha committed
        '''link an instanced group - model type asset'''
        sel = utils.selection_get()
    
    
        with bpy.data.libraries.load(file_name, link=link, relative=True) as (data_from, data_to):
            scols = []
            for col in data_from.collections:
                print('linking this ', col)
                if col == kwargs['name']:
                    data_to.collections = [col]
    
    
    Vilem Duha's avatar
    Vilem Duha committed
        if kwargs.get('rotation') is not None:
    
            rotation = kwargs['rotation']
    
    
        bpy.ops.object.empty_add(type='PLAIN_AXES', location=location, rotation=rotation)
    
        main_object = bpy.context.view_layer.objects.active
        main_object.instance_type = 'COLLECTION'
    
    
        main_object.parent = parent
        main_object.matrix_world.translation = location
    
    
        for col in bpy.data.collections:
            if col.library is not None:
    
    Vilém Duha's avatar
    Vilém Duha committed
                fp = bpy.path.abspath(col.library.filepath)
                fp1 = bpy.path.abspath(file_name)
    
    Vilém Duha's avatar
    Vilém Duha committed
                if fp == fp1:
    
                    main_object.instance_collection = col
                    break;
    
    
        main_object.name = main_object.instance_collection.name
    
    
        # bpy.ops.wm.link(directory=file_name + "/Collection/", filename=kwargs['name'], link=link, instance_collections=True,
        #                 autoselect=True)
        # main_object = bpy.context.view_layer.objects.active
        # if kwargs.get('rotation') is not None:
        #     main_object.rotation_euler = kwargs['rotation']
        # main_object.location = location
    
    
    Vilem Duha's avatar
    Vilem Duha committed
        utils.selection_set(sel)
        return main_object, []
    
    
    def append_particle_system(file_name, obnames=[], location=(0, 0, 0), link=False, **kwargs):
        '''link an instanced group - model type asset'''
    
        pss = []
        with bpy.data.libraries.load(file_name, link=link, relative=True) as (data_from, data_to):
            for ps in data_from.particles:
                pss.append(ps)
            data_to.particles = pss
    
        s = bpy.context.scene
        sel = utils.selection_get()
    
        target_object = bpy.context.scene.objects.get(kwargs['target_object'])
        if target_object is not None and target_object.type == 'MESH':
            target_object.select_set(True)
            bpy.context.view_layer.objects.active = target_object
    
            for ps in pss:
                # now let's tune this ps to the particular objects area:
                totarea = 0
                for p in target_object.data.polygons:
                    totarea += p.area
                count = int(ps.count * totarea)
                if ps.child_type in ('INTERPOLATED', 'SIMPLE'):
                    total_count = count * ps.rendered_child_count
                    disp_count = count * ps.child_nbr
                else:
                    total_count = count
                threshold = 2000
                total_max_threshold = 50000
                # emitting too many parent particles just kills blender now:
                if count > total_max_threshold:
                    ratio = round(count / total_max_threshold)
    
                    if ps.child_type in ('INTERPOLATED', 'SIMPLE'):
                        ps.rendered_child_count *= ratio
                    else:
                        ps.child_type = 'INTERPOLATED'
                        ps.rendered_child_count = ratio
                    count = max(2, int(count / ratio))
                ps.display_percentage = min(ps.display_percentage, max(1, int(100 * threshold / total_count)))
    
                ps.count = count
                bpy.ops.object.particle_system_add()
                target_object.particle_systems[-1].settings = ps
    
            target_object.select_set(False)
        utils.selection_set(sel)
        return target_object, []
    
    
    def append_objects(file_name, obnames=[], location=(0, 0, 0), link=False, **kwargs):
        '''append objects into scene individually'''
    
    Vilem Duha's avatar
    Vilem Duha committed
        with bpy.data.libraries.load(file_name, link=link, relative=True) as (data_from, data_to):
            sobs = []
            for ob in data_from.objects:
                if ob in obnames or obnames == []:
                    sobs.append(ob)
            data_to.objects = sobs
            # data_to.objects = data_from.objects#[name for name in data_from.objects if name.startswith("house")]
    
        # link them to scene
        scene = bpy.context.scene
        sel = utils.selection_get()
        bpy.ops.object.select_all(action='DESELECT')
    
        return_obs = []  # this might not be needed, but better be sure to rewrite the list.
        main_object = None
        hidden_objects = []
        #
        for obj in data_to.objects:
            if obj is not None:
                # if obj.name not in scene.objects:
                scene.collection.objects.link(obj)
                if obj.parent is None:
                    obj.location = location
                    main_object = obj
                obj.select_set(True)
                # we need to unhide object so make_local op can use those too.
                if link == True:
                    if obj.hide_viewport:
                        hidden_objects.append(obj)
                        obj.hide_viewport = False
                return_obs.append(obj)
        # Only after all objects are in scene! Otherwise gets broken relationships
        if link == True:
            bpy.ops.object.make_local(type='SELECT_OBJECT')
            for ob in hidden_objects:
                ob.hide_viewport = True
    
        if kwargs.get('rotation') is not None:
            main_object.rotation_euler = kwargs['rotation']
    
    
        if kwargs.get('parent') is not None:
            main_object.parent = bpy.data.objects[kwargs['parent']]
            main_object.matrix_world.translation = location
    
    
    Vilem Duha's avatar
    Vilem Duha committed
        bpy.ops.object.select_all(action='DESELECT')
    
        utils.selection_set(sel)
    
    Vilem Duha's avatar
    Vilem Duha committed
        return main_object, return_obs