sun_position: fix warning from deleted prop in User Preferences
[blender-addons.git] / blenderkit / append_link.py
blobb6bfb791ac712ccac2c0951950145b81084b2977
1 # ##### BEGIN GPL LICENSE BLOCK #####
3 # This program is free software; you can redistribute it and/or
4 # modify it under the terms of the GNU General Public License
5 # as published by the Free Software Foundation; either version 2
6 # of the License, or (at your option) any later version.
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, write to the Free Software Foundation,
15 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 # ##### END GPL LICENSE BLOCK #####
20 if "bpy" in locals():
21 from importlib import reload
23 utils = reload(utils)
24 ui = reload(ui)
25 else:
26 from blenderkit import utils, ui
28 import bpy
29 import uuid
32 def append_brush(file_name, brushname=None, link=False, fake_user=True):
33 '''append a brush'''
34 with bpy.data.libraries.load(file_name, link=link, relative=True) as (data_from, data_to):
35 for m in data_from.brushes:
36 if m == brushname or brushname is None:
37 data_to.brushes = [m]
38 brushname = m
39 brush = bpy.data.brushes[brushname]
40 if fake_user:
41 brush.use_fake_user = True
42 return brush
45 def append_material(file_name, matname=None, link=False, fake_user=True):
46 '''append a material type asset'''
47 # first, we have to check if there is a material with same name
48 # in previous step there's check if the imported material
49 # is already in the scene, so we know same name != same material
51 mats_before = bpy.data.materials.keys()
53 with bpy.data.libraries.load(file_name, link=link, relative=True) as (data_from, data_to):
54 for m in data_from.materials:
55 if m == matname or matname is None:
56 data_to.materials = [m]
57 # print(m, type(m))
58 matname = m
59 break;
61 # we have to find the new material :(
62 for mname in bpy.data.materials.keys():
63 if mname not in mats_before:
64 mat = bpy.data.materials[mname]
65 break
67 if fake_user:
68 mat.use_fake_user = True
70 return mat
73 def append_scene(file_name, scenename=None, link=False, fake_user=False):
74 '''append a scene type asset'''
75 with bpy.data.libraries.load(file_name, link=link, relative=True) as (data_from, data_to):
76 for s in data_from.scenes:
77 if s == scenename or scenename is None:
78 data_to.scenes = [s]
79 scenename = s
80 scene = bpy.data.scenes[scenename]
81 if fake_user:
82 scene.use_fake_user = True
83 # scene has to have a new uuid, so user reports aren't screwed.
84 scene['uuid'] = str(uuid.uuid4())
85 return scene
88 def link_collection(file_name, obnames=[], location=(0, 0, 0), link=False, parent = None, **kwargs):
89 '''link an instanced group - model type asset'''
90 sel = utils.selection_get()
92 with bpy.data.libraries.load(file_name, link=link, relative=True) as (data_from, data_to):
93 scols = []
94 for col in data_from.collections:
95 print('linking this ', col)
96 if col == kwargs['name']:
97 data_to.collections = [col]
99 rotation = (0, 0, 0)
100 if kwargs.get('rotation') is not None:
101 rotation = kwargs['rotation']
103 bpy.ops.object.empty_add(type='PLAIN_AXES', location=location, rotation=rotation)
104 main_object = bpy.context.view_layer.objects.active
105 main_object.instance_type = 'COLLECTION'
107 main_object.parent = parent
108 main_object.matrix_world.translation = location
110 for col in bpy.data.collections:
111 if col.library is not None:
112 fp = bpy.path.abspath(col.library.filepath)
113 fp1 = bpy.path.abspath(file_name)
114 if fp == fp1:
115 main_object.instance_collection = col
116 break;
118 main_object.name = main_object.instance_collection.name
120 # bpy.ops.wm.link(directory=file_name + "/Collection/", filename=kwargs['name'], link=link, instance_collections=True,
121 # autoselect=True)
122 # main_object = bpy.context.view_layer.objects.active
123 # if kwargs.get('rotation') is not None:
124 # main_object.rotation_euler = kwargs['rotation']
125 # main_object.location = location
127 utils.selection_set(sel)
128 return main_object, []
131 def append_particle_system(file_name, obnames=[], location=(0, 0, 0), link=False, **kwargs):
132 '''link an instanced group - model type asset'''
134 pss = []
135 with bpy.data.libraries.load(file_name, link=link, relative=True) as (data_from, data_to):
136 for ps in data_from.particles:
137 pss.append(ps)
138 data_to.particles = pss
140 s = bpy.context.scene
141 sel = utils.selection_get()
143 target_object = bpy.context.scene.objects.get(kwargs['target_object'])
144 if target_object is not None and target_object.type == 'MESH':
145 target_object.select_set(True)
146 bpy.context.view_layer.objects.active = target_object
148 for ps in pss:
149 # now let's tune this ps to the particular objects area:
150 totarea = 0
151 for p in target_object.data.polygons:
152 totarea += p.area
153 count = int(ps.count * totarea)
154 if ps.child_type in ('INTERPOLATED', 'SIMPLE'):
155 total_count = count * ps.rendered_child_count
156 disp_count = count * ps.child_nbr
157 else:
158 total_count = count
159 threshold = 2000
160 total_max_threshold = 50000
161 # emitting too many parent particles just kills blender now:
162 if count > total_max_threshold:
163 ratio = round(count / total_max_threshold)
165 if ps.child_type in ('INTERPOLATED', 'SIMPLE'):
166 ps.rendered_child_count *= ratio
167 else:
168 ps.child_type = 'INTERPOLATED'
169 ps.rendered_child_count = ratio
170 count = max(2, int(count / ratio))
171 ps.display_percentage = min(ps.display_percentage, max(1, int(100 * threshold / total_count)))
173 ps.count = count
174 bpy.ops.object.particle_system_add()
175 target_object.particle_systems[-1].settings = ps
177 target_object.select_set(False)
178 utils.selection_set(sel)
179 return target_object, []
182 def append_objects(file_name, obnames=[], location=(0, 0, 0), link=False, **kwargs):
183 '''append objects into scene individually'''
185 with bpy.data.libraries.load(file_name, link=link, relative=True) as (data_from, data_to):
186 sobs = []
187 for ob in data_from.objects:
188 if ob in obnames or obnames == []:
189 sobs.append(ob)
190 data_to.objects = sobs
191 # data_to.objects = data_from.objects#[name for name in data_from.objects if name.startswith("house")]
193 # link them to scene
194 scene = bpy.context.scene
195 sel = utils.selection_get()
196 bpy.ops.object.select_all(action='DESELECT')
198 return_obs = [] # this might not be needed, but better be sure to rewrite the list.
199 main_object = None
200 hidden_objects = []
202 for obj in data_to.objects:
203 if obj is not None:
204 # if obj.name not in scene.objects:
205 scene.collection.objects.link(obj)
206 if obj.parent is None:
207 obj.location = location
208 main_object = obj
209 obj.select_set(True)
210 # we need to unhide object so make_local op can use those too.
211 if link == True:
212 if obj.hide_viewport:
213 hidden_objects.append(obj)
214 obj.hide_viewport = False
215 return_obs.append(obj)
216 # Only after all objects are in scene! Otherwise gets broken relationships
217 if link == True:
218 bpy.ops.object.make_local(type='SELECT_OBJECT')
219 for ob in hidden_objects:
220 ob.hide_viewport = True
222 if kwargs.get('rotation') is not None:
223 main_object.rotation_euler = kwargs['rotation']
225 if kwargs.get('parent') is not None:
226 main_object.parent = bpy.data.objects[kwargs['parent']]
227 main_object.matrix_world.translation = location
229 bpy.ops.object.select_all(action='DESELECT')
231 utils.selection_set(sel)
234 return main_object, return_obs