diff --git a/blenderkit/__init__.py b/blenderkit/__init__.py index 1a8c3cef9e52a901f88f31ab3a396871507dfcbe..2c625adcf8fbd6c4565371382cb9ce12450f2c3c 100644 --- a/blenderkit/__init__.py +++ b/blenderkit/__init__.py @@ -1498,7 +1498,19 @@ class BlenderKitSceneSearchProps(PropertyGroup, BlenderKitCommonSearchProps): default="", update=search.search_update ) - + append_link: EnumProperty( + name="Append or link", + items=( + ('LINK', 'Link', ''), + ('APPEND', 'Append', ''), + ), + description="choose if the scene will be linked or appended", + default="APPEND" + ) + switch_after_append: BoolProperty( + name = 'Switch to scene after download', + default = False + ) def fix_subdir(self, context): '''Fixes project subdicrectory settings if people input invalid path.''' diff --git a/blenderkit/download.py b/blenderkit/download.py index 7a233c6f5db6669351cdedb5ed598b5d7d3d7f35..20e5bc148323827faf22e70791342c47757dc16e 100644 --- a/blenderkit/download.py +++ b/blenderkit/download.py @@ -26,6 +26,7 @@ import shutil, sys, os import uuid import copy import logging + bk_logger = logging.getLogger('blenderkit') import bpy @@ -303,8 +304,7 @@ def append_asset(asset_data, **kwargs): # downloaders=[], location=None, ##### # how to do particle drop: # link the group we are interested in( there are more groups in File!!!! , have to get the correct one!) - # - scene = bpy.context.scene + s = bpy.context.scene user_preferences = bpy.context.preferences.addons['blenderkit'].preferences @@ -312,16 +312,22 @@ def append_asset(asset_data, **kwargs): # downloaders=[], location=None, user_preferences.asset_counter += 1 if asset_data['assetType'] == 'scene': - scene = append_link.append_scene(file_names[0], link=False, fake_user=False) - props = scene.blenderkit - asset_main = scene + sprops = s.blenderkit_scene + + scene = append_link.append_scene(file_names[0], link=sprops.append_link == 'LINK', fake_user=False) + print('scene appended') + if scene is not None: + props = scene.blenderkit + asset_main = scene + print(sprops.switch_after_append) + if sprops.switch_after_append: + bpy.context.window_manager.windows[0].scene = scene if asset_data['assetType'] == 'hdr': - hdr = append_link.load_HDR(file_name = file_names[0], name = asset_data['name']) + hdr = append_link.load_HDR(file_name=file_names[0], name=asset_data['name']) props = hdr.blenderkit asset_main = hdr - s = bpy.context.scene if asset_data['assetType'] == 'model': downloaders = kwargs.get('downloaders') @@ -899,7 +905,7 @@ def check_existing(asset_data, resolution='blend', can_return_others=False): file_names = paths.get_download_filepaths(asset_data, resolution, can_return_others=can_return_others) - bk_logger.debug('check if file already exists'+ str( file_names)) + bk_logger.debug('check if file already exists' + str(file_names)) if len(file_names) == 2: # TODO this should check also for failed or running downloads. # If download is running, assign just the running thread. if download isn't running but the file is wrong size, @@ -1147,7 +1153,7 @@ def start_download(asset_data, **kwargs): # check if there are files already. This check happens 2x once here(for free assets), # once in thread(for non-free) fexists = check_existing(asset_data, resolution=kwargs['resolution']) - bk_logger.debug('does file exist?'+ str( fexists)) + 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. diff --git a/blenderkit/image_utils.py b/blenderkit/image_utils.py index e0b49b10c74ca03d7c49decca250ac5a4d05488b..7f2945d98e97f26ca44d96cd432bafab39e5d55f 100644 --- a/blenderkit/image_utils.py +++ b/blenderkit/image_utils.py @@ -54,6 +54,14 @@ def img_save_as(img, filepath='//', file_format='JPEG', quality=90, color_mode=' set_orig_render_settings(ors) +def set_colorspace(img, colorspace): + '''sets image colorspace, but does so in a try statement, because some people might actually replace the default + colorspace settings, and it literally can't be guessed what these people use, even if it will mostly be the filmic addon. + ''' + try: + img.colorspace_settings.name = colorspace + except: + print('Colorspace {colorspace} not found.') def generate_hdr_thumbnail(): scene = bpy.context.scene @@ -79,7 +87,7 @@ def generate_hdr_thumbnail(): hdr_image.pixels.foreach_get(tempBuffer) inew.filepath = thumb_path - inew.colorspace_settings.name = 'Linear' + set_colorspace(inew, 'Linear') inew.pixels.foreach_set(tempBuffer) bpy.context.view_layer.update() diff --git a/blenderkit/search.py b/blenderkit/search.py index c902104c74a29ed0ae7825bcc0693b815f71eeb3..836c29b0e695d2d560b30a71183bf8a3a53d90ea 100644 --- a/blenderkit/search.py +++ b/blenderkit/search.py @@ -17,7 +17,7 @@ # ##### END GPL LICENSE BLOCK ##### from blenderkit import paths, utils, categories, ui, colors, bkit_oauth, version_checker, tasks_queue, rerequests, \ - resolutions + resolutions, image_utils import blenderkit from bpy.app.handlers import persistent @@ -474,9 +474,9 @@ def load_previews(): img.reload() if r['assetType'] == 'hdr': # to display hdr thumbnails correctly, we use non-color, otherwise looks shifted - img.colorspace_settings.name = 'Non-Color' + image_utils.set_colorspace(img, 'Non-Color') else: - img.colorspace_settings.name = 'sRGB' + image_utils.set_colorspace(img, 'sRGB') i += 1 # print('previews loaded') diff --git a/blenderkit/ui.py b/blenderkit/ui.py index 72d0ad7e07a9965c1e11dae0f136547118d6a539..4c70f14e946783d94c34d88cc0a5ecb2acb7f265 100644 --- a/blenderkit/ui.py +++ b/blenderkit/ui.py @@ -1672,6 +1672,12 @@ class AssetBarOperator(bpy.types.Operator): target_slot = temp_mesh.polygons[face_index].material_index object_eval.to_mesh_clear() else: + if object.is_library_indirect: + ui_panels.ui_message(title='This object is linked from outer file', + message="Please select the model," + "go to the 'Selected Model' panel " + "in BlenderKit and hit 'Bring to Scene' first.") + self.report({'WARNING'}, "Invalid or library object as input:") target_object = '' target_slot = '' @@ -1914,6 +1920,12 @@ def draw_callback_3d_dragging(self, context): if self.has_hit: draw_bbox(self.snapped_location, self.snapped_rotation, self.snapped_bbox_min, self.snapped_bbox_max) +def find_and_activate_instancers(object): + for ob in bpy.context.visible_objects: + if ob.instance_type == 'COLLECTION' and ob.instance_collection and object.name in ob.instance_collection.objects: + utils.activate(ob) + return ob + class AssetDragOperator(bpy.types.Operator): """Draw a line with the mouse""" @@ -1942,6 +1954,11 @@ class AssetDragOperator(bpy.types.Operator): if ui_props.asset_type == 'MATERIAL': # first, test if object can have material applied. object = bpy.data.objects[self.object_name] + # this enables to run Bring to scene automatically when dropping on a linked objects. + # it's however quite a slow operation, that's why not enabled (and finished) now. + # if object is not None and object.is_library_indirect: + # find_and_activate_instancers(object) + # bpy.ops.object.blenderkit_bring_to_scene() if object is not None and not object.is_library_indirect and object.type == 'MESH': target_object = object.name # create final mesh to extract correct material slot @@ -1953,6 +1970,12 @@ class AssetDragOperator(bpy.types.Operator): # elif object.is_library_indirect:#case for bring to scene objects, will be solved through prefs and direct # action else: + if object.is_library_indirect: + ui_panels.ui_message(title = 'This object is linked from outer file', + message = "Please select the model," + "go to the 'Selected Model' panel " + "in BlenderKit and hit 'Bring to Scene' first.") + self.report({'WARNING'}, "Invalid or library object as input:") target_object = '' target_slot = '' @@ -2007,6 +2030,11 @@ class AssetDragOperator(bpy.types.Operator): target_object=target_object) else: + if ui_props.asset_type =='SCENE': + ui_panels.ui_message(title = 'Scene will be appended after download', + message = 'After the scene is appended, you have to switch to it manually.' + 'If you want to switch to scenes automatically after appending,' + ' you can set it in import settings.') bpy.ops.scene.blenderkit_download( # asset_type=ui_props.asset_type, asset_index=self.asset_search_index) diff --git a/blenderkit/ui_panels.py b/blenderkit/ui_panels.py index 91abd4460e02b9db91e01de127095dde1983a2bd..302e7119d2d8a66791bf09e3952503e2067ab820 100644 --- a/blenderkit/ui_panels.py +++ b/blenderkit/ui_panels.py @@ -112,7 +112,7 @@ def draw_upload_common(layout, props, asset_type, context): op = layout.operator("object.blenderkit_upload", text=optext, icon='EXPORT') op.asset_type = asset_type op.reupload = False - #make sure everything gets uploaded. + # make sure everything gets uploaded. op.main_file = True op.metadata = True op.thumbnail = True @@ -163,6 +163,7 @@ def prop_needed(layout, props, name, value, is_not_filled=''): icon = None row.prop(props, name) + def draw_panel_hdr_upload(self, context): layout = self.layout ui_props = bpy.context.scene.blenderkitUI @@ -172,7 +173,6 @@ def draw_panel_hdr_upload(self, context): hdr = utils.get_active_HDR() - if hdr is not None: props = hdr.blenderkit @@ -184,6 +184,7 @@ def draw_panel_hdr_upload(self, context): layout.prop(props, 'description') layout.prop(props, 'tags') + def draw_panel_hdr_search(self, context): s = context.scene props = s.blenderkit_HDR @@ -196,6 +197,7 @@ def draw_panel_hdr_search(self, context): utils.label_multiline(layout, text=props.report) + def draw_panel_model_upload(self, context): ob = bpy.context.active_object while ob.parent is not None: @@ -316,7 +318,7 @@ def draw_assetbar_show_hide(layout, props): preferences = bpy.context.preferences.addons['blenderkit'].preferences if preferences.experimental_features: - op = layout.operator('view3d.blenderkit_asset_bar_widget', text = '', icon = icon) + op = layout.operator('view3d.blenderkit_asset_bar_widget', text='', icon=icon) op.keep_running = False op.do_search = False op.tooltip = ttip @@ -510,7 +512,7 @@ class VIEW3D_PT_blenderkit_ratings(Panel): utils.label_multiline(layout, text='Please help BlenderKit community by rating these assets:') for a in assets: - if a.bkit_ratings.rating_work_hours==0: + if a.bkit_ratings.rating_work_hours == 0: draw_rating_asset(self, context, asset=a) @@ -546,7 +548,7 @@ class VIEW3D_PT_blenderkit_profile(Panel): if me is not None: me = me['user'] # user name - if len(me['firstName'])>0 or len(me['lastName'])>0: + if len(me['firstName']) > 0 or len(me['lastName']) > 0: layout.label(text=f"Me: {me['firstName']} {me['lastName']}") else: layout.label(text=f"Me: {me['email']}") @@ -781,7 +783,6 @@ class VIEW3D_PT_blenderkit_advanced_model_search(Panel): layout.prop(props, "free_only") layout.prop(props, "search_style") - # DESIGN YEAR layout.prop(props, "search_design_year", text='Designed in Year') if props.search_design_year: @@ -897,7 +898,7 @@ class VIEW3D_PT_blenderkit_import_settings(Panel): def poll(cls, context): s = context.scene ui_props = s.blenderkitUI - return ui_props.down_up == 'SEARCH' and ui_props.asset_type in ['MATERIAL', 'MODEL', 'HDR'] + return ui_props.down_up == 'SEARCH' and ui_props.asset_type in ['MATERIAL', 'MODEL', 'SCENE', 'HDR'] def draw(self, context): layout = self.layout @@ -926,10 +927,17 @@ class VIEW3D_PT_blenderkit_import_settings(Panel): row = layout.row() row.prop(props, 'append_method', expand=True, icon_only=False) + if ui_props.asset_type == 'SCENE': + props = s.blenderkit_scene + layout.prop(props, 'switch_after_append') + layout.label(text='Import method:') + row = layout.row() + row.prop(props, 'append_link', expand=True, icon_only=False) if ui_props.asset_type == 'HDR': props = s.blenderkit_HDR - layout.prop(props, 'resolution') + if ui_props.asset_type in ['MATERIAL', 'MODEL', 'HDR']: + layout.prop(props, 'resolution') # layout.prop(props, 'unpack_files') @@ -1199,7 +1207,6 @@ def draw_asset_context_menu(layout, context, asset_data, from_panel=False): # if ui_props.asset_type in ('MODEL', 'MATERIAL'): # layout.menu(OBJECT_MT_blenderkit_resolution_menu.bl_idname) - if ui_props.asset_type in ('MODEL', 'MATERIAL', 'HDR') and \ utils.get_param(asset_data, 'textureResolutionMax') is not None and \ utils.get_param(asset_data, 'textureResolutionMax') > 512: @@ -1247,7 +1254,8 @@ def draw_asset_context_menu(layout, context, asset_data, from_panel=False): op.invoke_resolution = True o = utils.get_active_model() if o and o.get('asset_data'): - if o['asset_data']['assetBaseId'] == bpy.context.window_manager['search results'][ui_props.active_index]: + if o['asset_data']['assetBaseId'] == bpy.context.window_manager['search results'][ + ui_props.active_index]: op.model_location = o.location op.model_rotation = o.rotation_euler else: @@ -1302,14 +1310,10 @@ def draw_asset_context_menu(layout, context, asset_data, from_panel=False): if utils.profile_is_validator(): layout.label(text='Admin Tools:') - op = layout.operator('object.blenderkit_print_asset_debug', text='Print asset debug') op.asset_id = asset_data['id'] - - - # def draw_asset_resolution_replace(self, context, resolution): # layout = self.layout # ui_props = bpy.context.scene.blenderkitUI @@ -1392,12 +1396,13 @@ class OBJECT_MT_blenderkit_asset_menu(bpy.types.Menu): # box2.label(text='************') # box2.label(text='dadydadadada') + class AssetPopupCard(bpy.types.Operator): """Generate Cycles thumbnail for model assets""" bl_idname = "wm.blenderkit_asset_popup" bl_label = "BlenderKit asset popup" # bl_options = {'REGISTER', 'INTERNAL'} - bl_options = {'REGISTER',} + bl_options = {'REGISTER', } @classmethod def poll(cls, context): @@ -1418,11 +1423,10 @@ class AssetPopupCard(bpy.types.Operator): split = split.split(factor=0.5) col1 = split.column() box = col1.box() - utils.label_multiline(box,asset_data['tooltip'], width = 300) + utils.label_multiline(box, asset_data['tooltip'], width=300) col2 = split.column() - pcoll = icons.icon_collections["main"] my_icon = pcoll['test'] col2.template_icon(icon_value=my_icon.icon_id, scale=20.0) @@ -1430,7 +1434,7 @@ class AssetPopupCard(bpy.types.Operator): box2 = col2.box() # draw_ratings(box2, context, asset_data) - box2.label(text = 'Ratings') + box2.label(text='Ratings') # print(tp, dir(tp)) # if not hasattr(self, 'first_draw'):# try to redraw because of template preview which needs update # for region in context.area.regions: @@ -1451,8 +1455,9 @@ class AssetPopupCard(bpy.types.Operator): # self.tex = utils.get_hidden_texture(self.img) # self.tex.update_tag() - bl_label = asset_data['name'] - return wm.invoke_props_dialog(self, width = 700) + bl_label = asset_data['name'] + return wm.invoke_props_dialog(self, width=700) + class OBJECT_MT_blenderkit_login_menu(bpy.types.Menu): bl_label = "BlenderKit login/signup:" @@ -1523,14 +1528,14 @@ class UrlPopupDialog(bpy.types.Operator): def draw(self, context): layout = self.layout - utils.label_multiline(layout, text=self.message, width = 300) + utils.label_multiline(layout, text=self.message, width=300) layout.active_default = True op = layout.operator("wm.url_open", text=self.link_text, icon='QUESTION') if not utils.user_logged_in(): utils.label_multiline(layout, text='Already subscribed? You need to login to access your Full Plan.', - width = 300) + width=300) layout.operator_context = 'EXEC_DEFAULT' layout.operator("wm.blenderkit_login", text="Login", @@ -1544,7 +1549,7 @@ class UrlPopupDialog(bpy.types.Operator): def invoke(self, context, event): wm = context.window_manager - return wm.invoke_props_dialog(self,width = 300) + return wm.invoke_props_dialog(self, width=300) class LoginPopupDialog(bpy.types.Operator): @@ -1695,16 +1700,19 @@ def header_search_draw(self, context): # the center snap menu is in edit and object mode if tool settings are off. if context.space_data.show_region_tool_header == True or context.mode[:4] not in ('EDIT', 'OBJE'): layout.separator_spacer() - layout.prop(ui_props, "asset_type", expand = True, icon_only = True, text='', icon='URL') + layout.prop(ui_props, "asset_type", expand=True, icon_only=True, text='', icon='URL') layout.prop(props, "search_keywords", text="", icon='VIEWZOOM') draw_assetbar_show_hide(layout, props) + def ui_message(title, message): def draw_message(self, context): layout = self.layout - utils.label_multiline(layout, text=message) + utils.label_multiline(layout, text=message, width=400) bpy.context.window_manager.popup_menu(draw_message, title=title, icon='INFO') + + # We can store multiple preview collections here, # however in this example we only store "main" preview_collections = {} diff --git a/blenderkit/utils.py b/blenderkit/utils.py index 30f29ab00f8f5395d1ca8ad635f56ad64735e276..0892bdb271b43ffd12087e34e6b29cbd3d9dc6b3 100644 --- a/blenderkit/utils.py +++ b/blenderkit/utils.py @@ -17,7 +17,7 @@ # ##### END GPL LICENSE BLOCK ##### -from blenderkit import paths, rerequests +from blenderkit import paths, rerequests, image_utils import bpy from mathutils import Vector @@ -313,7 +313,6 @@ def get_hidden_texture(img, force_reload=False): t.image = img return t - def get_hidden_image(tpath, bdata_name, force_reload=False, colorspace = 'sRGB'): if bdata_name[0] == '.': hidden_name = bdata_name @@ -340,12 +339,13 @@ def get_hidden_image(tpath, bdata_name, force_reload=False, colorspace = 'sRGB') img.filepath = tpath img.reload() - img.colorspace_settings.name = colorspace + image_utils.set_colorspace(img,colorspace) + elif force_reload: if img.packed_file is not None: img.unpack(method='USE_ORIGINAL') img.reload() - img.colorspace_settings.name = colorspace + image_utils.set_colorspace(img,colorspace) return img @@ -355,7 +355,7 @@ def get_thumbnail(name): img = bpy.data.images.get(name) if img == None: img = bpy.data.images.load(p) - img.colorspace_settings.name = 'sRGB' + image_utils.set_colorspace(img,'sRGB') img.name = name img.name = name