Newer
Older
nobs = bpy.context.selected_objects[:]
for ob in nobs:
if ob.parent not in nobs:
# in case of replacement,there might be a paarent relationship that can be restored
if kwargs.get('parent'):
parent = bpy.data.objects[kwargs['parent']]
asset_main.parent = parent # even if parent is None this is ok without if condition
else:
asset_main.parent = None
# restore original selection
utils.selection_set(sel)
'''checks if the asset is already in scene. If yes, modifies asset data so the asset can be reached again.'''
scene = bpy.context.scene
au = scene.get('assets used', {})
id = asset_data['assetBaseId']
if id in au.keys():
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
if ad.get('files'):
for fi in ad['files']:
if fi.get('file_name') != None:
for fi1 in asset_data['files']:
if fi['fileType'] == fi1['fileType']:
fi1['file_name'] = fi['file_name']
fi1['url'] = fi['url']
# browse all collections since linked collections can have same name.
if asset_data['assetType'] == 'MODEL':
for c in bpy.data.collections:
if c.name == ad['name']:
# there can also be more linked collections with same name, we need to check id.
if c.library and c.library.get('asset_data') and c.library['asset_data'][
'assetBaseId'] == id:
print('asset linked')
return 'LINKED', ad.get('resolution')
elif asset_data['assetType'] == 'MATERIAL':
for m in bpy.data.materials:
if not m.get('asset_data'):
continue
if m['asset_data']['assetBaseId'] == asset_data[
'assetBaseId'] and bpy.context.active_object.active_material.library:
return 'LINKED', ad.get('resolution')
print('asset appended')
return 'APPENDED', ad.get('resolution')
return False, None
def fprint(text):
print('###################################################################################')
print('\n\n\n')
print(text)
print('\n\n\n')
print('###################################################################################')
def get_download_url(asset_data, scene_id, api_key, tcom=None, resolution='blend'):
''''retrieves the download url. The server checks if user can download the item.'''
mt = time.time()
headers = utils.get_headers(api_key)
res_file_info, resolution = paths.get_res_file(asset_data, resolution)
r = rerequests.get(res_file_info['downloadUrl'], params=data, headers=headers)
except Exception as e:
print(e)
if tcom is not None:
tcom.error = True
if r == None:
if tcom is not None:
tcom.report = 'Connection Error'
tcom.error = True
if r.status_code < 400:
data = r.json()
url = data['filePath']
res_file_info['url'] = url
res_file_info['file_name'] = paths.extract_filename_from_url(url)
# print(res_file_info, url)
print(url)
# let's print it into UI
tasks_queue.add_task((ui.add_report, (str(r), 10, colors.RED)))
r = 'You need Full plan to get this item.'
# r1 = 'All materials and brushes are available for free. Only users registered to Standard plan can use all models.'
# tasks_queue.add_task((ui.add_report, (r1, 5, colors.RED)))
if tcom is not None:
tcom.report = r
tcom.error = True
if r.status_code == 404:
r = 'Url not found - 404.'
# r1 = 'All materials and brushes are available for free. Only users registered to Standard plan can use all models.'
if tcom is not None:
tcom.report = r
tcom.error = True
# bk_logger.debug(r.text)
if tcom is not None:
tcom.report = 'Server error'
tcom.error = True
def start_download(asset_data, **kwargs):
'''
check if file isn't downloading or doesn't exist, then start new download
'''
# first check if the asset is already in scene. We can use that asset without checking with server
ain, resolution = asset_in_scene(asset_data)
# quota_ok = ain is not False
# if resolution:
# kwargs['resolution'] = resolution
# otherwise, check on server
s = bpy.context.scene
done = False
# is the asseet being currently downloaded?
downloading = check_downloading(asset_data, **kwargs)
if not downloading:
# check if there are files already. This check happens 2x once here(for free assets),
fexists = check_existing(asset_data, resolution=kwargs['resolution'])
bk_logger.debug('does file exist?'+ str( fexists))
bk_logger.debug('asset is in scene' + str(ain))
if ain and not kwargs.get('replace_resolution'):
# this goes to appending asset - where it should duplicate the original asset already in scene.
done = try_finished_append(asset_data, **kwargs)
# else:
# props = utils.get_search_props()
# props.report = str('asset ')
if not done:
at = asset_data['assetType']
if at in ('model', 'material'):
downloader = {'location': kwargs['model_location'],
'rotation': kwargs['model_rotation']}
download(asset_data, downloaders=[downloader], **kwargs)
asset_types = (
('MODEL', 'Model', 'set of objects'),
('SCENE', 'Scene', 'scene'),
('MATERIAL', 'Material', 'any .blend Material'),
('TEXTURE', 'Texture', 'a texture, or texture set'),
('BRUSH', 'Brush', 'brush, can be any type of blender brush'),
('ADDON', 'Addon', 'addnon'),
)
class BlenderkitKillDownloadOperator(bpy.types.Operator):
bl_idname = "scene.blenderkit_download_kill"
bl_label = "BlenderKit Kill Asset Download"
thread_index: IntProperty(name="Thread index", description='index of the thread to kill', default=-1)
def execute(self, context):
global download_threads
td = download_threads[self.thread_index]
download_threads.remove(td)
td[0].stop()
return {'FINISHED'}
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
def available_resolutions_callback(self, context):
'''
Returns
checks active asset for available resolutions and offers only those available
TODO: this currently returns always the same list of resolutions, make it actually work
'''
# print('callback called', self.asset_data)
pat_items = (
('512', '512', '', 1),
('1024', '1024', '', 2),
('2048', '2048', '', 3),
('4096', '4096', '', 4),
('8192', '8192', '', 5),
)
items = []
for item in pat_items:
if int(self.max_resolution) >= int(item[0]):
items.append(item)
items.append(('ORIGINAL', 'Original', '', 6))
return items
def show_enum_values(obj, prop_name):
print([item.identifier for item in obj.bl_rna.properties[prop_name].enum_items])
class BlenderkitDownloadOperator(bpy.types.Operator):
"""Download and link asset to scene. Only link if asset already available locally."""
bl_idname = "scene.blenderkit_download"
bl_label = "BlenderKit Asset Download"
# asset_type: EnumProperty(
# name="Type",
# items=asset_types,
# description="Type of download",
# default="MODEL",
# )
asset_index: IntProperty(name="Asset Index", description='asset index in search results', default=-1)
asset_base_id: StringProperty(
name="Asset base Id",
description="Asset base id, used instead of search result index.",
default="")
name="Target Object",
description="Material or object target for replacement",
material_target_slot: IntProperty(name="Asset Index", description='asset index in search results', default=0)
model_location: FloatVectorProperty(name='Asset Location', default=(0, 0, 0))
model_rotation: FloatVectorProperty(name='Asset Rotation', default=(0, 0, 0))
replace: BoolProperty(name='Replace', description='replace selection with the asset', default=False)
replace_resolution: BoolProperty(name='Replace resolution', description='replace resolution of the active asset',
default=False)
invoke_resolution: BoolProperty(name='Replace resolution popup',
description='pop up to ask which resolution to download', default=False)
resolution: EnumProperty(
items=available_resolutions_callback,
default=0,
description='Replace resolution'
)
max_resolution: IntProperty(
name="Max resolution",
description="",
default=0)
# has_res_0_5k: BoolProperty(name='512',
# description='', default=False)
cast_parent: StringProperty(
name="Particles Target Object",
description="",
default="")
# @classmethod
# def poll(cls, context):
# return bpy.context.window_manager.BlenderKitModelThumbnails is not ''
def get_asset_data(self, context):
# get asset data - it can come from scene, or from search results.
if self.asset_index > -1:
# either get the data from search results
sr = s['search results']
asset_data = sr[
self.asset_index].to_dict() # TODO CHECK ALL OCCURRENCES OF PASSING BLENDER ID PROPS TO THREADS!
asset_base_id = asset_data['assetBaseId']
else:
# or from the scene.
asset_base_id = self.asset_base_id
au = s.get('assets used')
if au == None:
s['assets used'] = {}
if asset_base_id in s.get('assets used'):
# already used assets have already download link and especially file link.
asset_data = s['assets used'][asset_base_id].to_dict()
return asset_data
def execute(self, context):
sprops = utils.get_search_props()
self.asset_data = self.get_asset_data(context)
# print('after getting asset data')
# print(self.asset_base_id)
atype = self.asset_data['assetType']
atype == 'model' or atype == 'material') and bpy.context.view_layer.objects.active is not None:
if self.resolution == 0 or self.resolution == '':
resolution = sprops.resolution
else:
resolution = self.resolution
resolution = resolutions.resolution_props_to_server[resolution]
if self.replace: # cleanup first, assign later.
obs = utils.get_selected_replace_adepts()
for ob in obs:
# this is for a case when replace is called from a panel,
# this uses active object as replacement source instead of target.
if ob.get('asset_data') is not None and \
(ob['asset_data']['assetBaseId'] == self.asset_base_id and ob['asset_data'][
'resolution'] == resolution):
# print('skipping this one')
parent = ob.parent
if parent:
parent = ob.parent.name # after this, parent is either name or None.
kwargs = {
'cast_parent': self.cast_parent,
'target_object': ob.name,
'material_target_slot': ob.active_material_index,
'model_location': tuple(ob.matrix_world.translation),
'model_rotation': tuple(ob.matrix_world.to_euler()),
'replace': True,
'replace_resolution': False,
'parent': parent,
'resolution': resolution
# TODO - move this After download, not before, so that the replacement
utils.delete_hierarchy(ob)
# replace resolution needs to replace all instances of the resolution in the scene
# and deleting originals has to be thus done after the downlaod
kwargs = {
'cast_parent': self.cast_parent,
'target_object': self.target_object,
'material_target_slot': self.material_target_slot,
'model_location': tuple(self.model_location),
'model_rotation': tuple(self.model_rotation),
'replace': False,
'replace_resolution': self.replace_resolution,
'resolution': resolution
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
def draw(self, context):
layout = self.layout
layout.prop(self, 'resolution', expand=True, icon_only=False)
def invoke(self, context, event):
print(self.asset_base_id)
wm = context.window_manager
# only make a pop up in case of switching resolutions
if self.invoke_resolution:
# show_enum_values(self, 'resolution')
# print('ENUM VALUES')
self.asset_data = self.get_asset_data(context)
sprops = utils.get_search_props()
if int(sprops.resolution) <= int(self.max_resolution):
self.resolution = sprops.resolution
elif int(self.max_resolution) > 0:
self.resolution = self.max_resolution
else:
self.resolution = 'ORIGINAL'
return wm.invoke_props_dialog(self)
def register_download():
bpy.utils.register_class(BlenderkitDownloadOperator)
bpy.utils.register_class(BlenderkitKillDownloadOperator)
bpy.app.handlers.load_post.append(scene_load)
bpy.app.handlers.save_pre.append(scene_save)
user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
if user_preferences.use_timers:
bpy.app.timers.register(timer_update)
def unregister_download():
bpy.utils.unregister_class(BlenderkitDownloadOperator)
bpy.utils.unregister_class(BlenderkitKillDownloadOperator)
bpy.app.handlers.load_post.remove(scene_load)
bpy.app.handlers.save_pre.remove(scene_save)
if bpy.app.timers.is_registered(timer_update):
bpy.app.timers.unregister(timer_update)