diff options
author | Julien Duroure <julien.duroure@gmail.com> | 2021-01-30 20:48:50 +0300 |
---|---|---|
committer | Julien Duroure <julien.duroure@gmail.com> | 2021-01-30 20:48:50 +0300 |
commit | 9d30d2bccb154f2c1a4b665bab7d6c02ff5c51b1 (patch) | |
tree | acc5d136f4ce143c0702ee79722296d28d5dbd93 | |
parent | 860e9710a56c137cc6cc8ddf1ce3d633d3fb8014 (diff) | |
parent | 3e7209f9f2894d0203cf9697958a6bd946fa3b6b (diff) |
Merge branch 'blender-v2.92-release'
-rw-r--r-- | blenderkit/__init__.py | 56 | ||||
-rw-r--r-- | blenderkit/asset_bar_op.py | 22 | ||||
-rw-r--r-- | blenderkit/autothumb.py | 11 | ||||
-rw-r--r-- | blenderkit/bkit_oauth.py | 2 | ||||
-rw-r--r-- | blenderkit/categories.py | 31 | ||||
-rw-r--r-- | blenderkit/download.py | 10 | ||||
-rw-r--r-- | blenderkit/ratings.py | 4 | ||||
-rw-r--r-- | blenderkit/resolutions.py | 2 | ||||
-rw-r--r-- | blenderkit/search.py | 52 | ||||
-rw-r--r-- | blenderkit/ui.py | 123 | ||||
-rw-r--r-- | blenderkit/ui_panels.py | 36 | ||||
-rw-r--r-- | blenderkit/upload.py | 21 | ||||
-rw-r--r-- | blenderkit/utils.py | 17 | ||||
-rwxr-xr-x | io_scene_gltf2/__init__.py | 2 | ||||
-rwxr-xr-x | io_scene_gltf2/blender/exp/gltf2_blender_gather_nodes.py | 11 |
15 files changed, 262 insertions, 138 deletions
diff --git a/blenderkit/__init__.py b/blenderkit/__init__.py index 98671f4c..679c83e8 100644 --- a/blenderkit/__init__.py +++ b/blenderkit/__init__.py @@ -138,7 +138,10 @@ from bpy.types import ( @persistent def scene_load(context): + print('loading in background') + print(bpy.context.window_manager) if not bpy.app.background: + search.load_previews() ui_props = bpy.context.scene.blenderkitUI ui_props.assetbar_on = False @@ -249,37 +252,39 @@ thumbnail_resolutions = ( def udate_down_up(self, context): """Perform a search if results are empty.""" s = context.scene + wm = bpy.context.window_manager props = s.blenderkitUI - if s['search results'] == None and props.down_up == 'SEARCH': + if wm['search results'] == None and props.down_up == 'SEARCH': search.search() def switch_search_results(self, context): s = bpy.context.scene + wm = bpy.context.window_manager props = s.blenderkitUI if props.asset_type == 'MODEL': - s['search results'] = s.get('bkit model search') - s['search results orig'] = s.get('bkit model search orig') + wm['search results'] = wm.get('bkit model search') + wm['search results orig'] = wm.get('bkit model search orig') elif props.asset_type == 'SCENE': - s['search results'] = s.get('bkit scene search') - s['search results orig'] = s.get('bkit scene search orig') + wm['search results'] = wm.get('bkit scene search') + wm['search results orig'] = wm.get('bkit scene search orig') elif props.asset_type == 'HDR': - s['search results'] = s.get('bkit hdr search') - s['search results orig'] = s.get('bkit hdr search orig') + wm['search results'] = wm.get('bkit hdr search') + wm['search results orig'] = wm.get('bkit hdr search orig') elif props.asset_type == 'MATERIAL': - s['search results'] = s.get('bkit material search') - s['search results orig'] = s.get('bkit material search orig') + wm['search results'] = wm.get('bkit material search') + wm['search results orig'] = wm.get('bkit material search orig') elif props.asset_type == 'TEXTURE': - s['search results'] = s.get('bkit texture search') - s['search results orig'] = s.get('bkit texture search orig') + wm['search results'] = wm.get('bkit texture search') + wm['search results orig'] = wm.get('bkit texture search orig') elif props.asset_type == 'BRUSH': - s['search results'] = s.get('bkit brush search') - s['search results orig'] = s.get('bkit brush search orig') + wm['search results'] = wm.get('bkit brush search') + wm['search results orig'] = wm.get('bkit brush search orig') if not(context.sculpt_object or context.image_paint_object): ui.add_report( 'Switch to paint or sculpt mode to search in BlenderKit brushes.') search.load_previews() - if s['search results'] == None and props.down_up == 'SEARCH': + if wm['search results'] == None and props.down_up == 'SEARCH': search.search() @@ -577,16 +582,11 @@ def name_update(self, context): def update_free(self, context): if self.is_free == False: self.is_free = True - title = "All BlenderKit materials are free" - message = "Any material uploaded to BlenderKit is free." \ + ui_panels.ui_message(title = "All BlenderKit materials are free", + message = "Any material uploaded to BlenderKit is free." \ " However, it can still earn money for the author," \ " based on our fair share system. " \ - "Part of subscription is sent to artists based on usage by paying users." - - def draw_message(self, context): - utils.label_multiline(self.layout, text=message, icon='NONE', width=-1) - - bpy.context.window_manager.popup_menu(draw_message, title=title, icon='INFO') + "Part of subscription is sent to artists based on usage by paying users.") class BlenderKitCommonUploadProps(object): @@ -1512,15 +1512,11 @@ def fix_subdir(self, context): if self.project_subdir != pp: self.project_subdir = pp - title = "Fixed to relative path" - message = "This path should be always realative.\n" \ - " It's a directory BlenderKit creates where your .blend is \n " \ - "and uses it for storing assets." - - def draw_message(self, context): - utils.label_multiline(self.layout, text=message, icon='NONE', width=400) + ui_panels.ui_message(title = "Fixed to relative path", + message = "This path should be always realative.\n" \ + " It's a directory BlenderKit creates where your .blend is \n " \ + "and uses it for storing assets.") - bpy.context.window_manager.popup_menu(draw_message, title=title, icon='INFO') class BlenderKitAddonPreferences(AddonPreferences): diff --git a/blenderkit/asset_bar_op.py b/blenderkit/asset_bar_op.py index 612f5885..f0092960 100644 --- a/blenderkit/asset_bar_op.py +++ b/blenderkit/asset_bar_op.py @@ -25,8 +25,8 @@ from bpy.props import ( def draw_callback_tooltip(self, context): if self.draw_tooltip: - s = bpy.context.scene - sr = s.get('search results') + wm = bpy.context.window_manager + sr = wm.get('search results') r = sr[self.active_index] ui.draw_tooltip_with_author(r, 0, 500) @@ -269,7 +269,7 @@ class BlenderKitAssetBarOperator(BL_UI_OT_draw_operator): self.wcount = math.floor( (self.bar_width) / (self.button_size)) - search_results = bpy.context.scene.get('search results') + search_results = bpy.context.window_manager.get('search results') if search_results is not None and self.wcount > 0: self.hcount = min(user_preferences.max_assetbar_rows, math.ceil(len(search_results) / self.wcount)) else: @@ -311,8 +311,6 @@ class BlenderKitAssetBarOperator(BL_UI_OT_draw_operator): self.panel = BL_UI_Drag_Panel(0, 0, self.bar_width, self.bar_height) self.panel.bg_color = (0.0, 0.0, 0.0, 0.5) - sr = bpy.context.scene['search results'] - for a in range(0, self.wcount): for b in range(0, self.hcount): asset_x = self.assetbar_margin + a * (self.button_size) @@ -478,7 +476,8 @@ class BlenderKitAssetBarOperator(BL_UI_OT_draw_operator): if self.active_index != widget.search_index: scene = bpy.context.scene - sr = scene['search results'] + wm = bpy.context.window_manager + sr = wm['search results'] asset_data = sr[widget.search_index + self.scroll_offset] self.active_index = widget.search_index @@ -514,11 +513,12 @@ class BlenderKitAssetBarOperator(BL_UI_OT_draw_operator): # bpy.ops.wm.call_menu(name='OBJECT_MT_blenderkit_asset_menu') def search_more(self): - sro = bpy.context.scene.get('search results orig') + sro = bpy.context.window_manager.get('search results orig') if sro is not None and sro.get('next') is not None: blenderkit.search.search(get_next=True) + def update_images(self): - sr = bpy.context.scene['search results'] + sr = bpy.context.window_manager['search results'] for asset_button in self.asset_buttons: asset_button.asset_index = asset_button.button_index + self.scroll_offset @@ -548,7 +548,7 @@ class BlenderKitAssetBarOperator(BL_UI_OT_draw_operator): asset_button.validation_icon.visible = False def scroll_update(self): - sr = bpy.context.scene['search results'] + sr = bpy.context.window_manager['search results'] self.scroll_offset = min(self.scroll_offset, len(sr) - (self.wcount * self.hcount)) self.scroll_offset = max(self.scroll_offset, 0) self.update_images() @@ -556,7 +556,7 @@ class BlenderKitAssetBarOperator(BL_UI_OT_draw_operator): self.search_more() def search_by_author(self, asset_index): - sr = bpy.context.scene['search results'] + sr = bpy.context.window_manager['search results'] asset_data = sr[asset_index] a = asset_data['author']['id'] if a is not None: @@ -573,12 +573,10 @@ class BlenderKitAssetBarOperator(BL_UI_OT_draw_operator): return False def scroll_up(self, widget): - sr = bpy.context.scene['search results'] self.scroll_offset += self.wcount * self.hcount self.scroll_update() def scroll_down(self, widget): - sr = bpy.context.scene['search results'] self.scroll_offset -= self.wcount * self.hcount self.scroll_update() diff --git a/blenderkit/autothumb.py b/blenderkit/autothumb.py index da6e6d29..2a649427 100644 --- a/blenderkit/autothumb.py +++ b/blenderkit/autothumb.py @@ -17,7 +17,7 @@ # ##### END GPL LICENSE BLOCK ##### -from blenderkit import paths, utils, bg_blender +from blenderkit import paths, utils, bg_blender, ui_panels import tempfile, os, subprocess, json, sys @@ -262,13 +262,10 @@ class GenerateThumbnailOperator(bpy.types.Operator): def invoke(self, context, event): wm = context.window_manager if bpy.data.filepath == '': - title = "Can't render thumbnail" - message = "please save your file first" + ui_panels.ui_message( + title = "Can't render thumbnail", + message = "please save your file first") - def draw_message(self, context): - self.layout.label(text=message) - - bpy.context.window_manager.popup_menu(draw_message, title=title, icon='INFO') return {'FINISHED'} return wm.invoke_props_dialog(self) diff --git a/blenderkit/bkit_oauth.py b/blenderkit/bkit_oauth.py index 7e7946a2..efcc1cc7 100644 --- a/blenderkit/bkit_oauth.py +++ b/blenderkit/bkit_oauth.py @@ -87,7 +87,7 @@ def write_tokens(auth_token, refresh_token, oauth_response): props.report = '' ui.add_report('BlenderKit Re-Login success') search.get_profile() - categories.fetch_categories_thread(auth_token) + categories.fetch_categories_thread(auth_token, force = False) class RegisterLoginOnline(bpy.types.Operator): diff --git a/blenderkit/categories.py b/blenderkit/categories.py index 8408f16f..2da830cb 100644 --- a/blenderkit/categories.py +++ b/blenderkit/categories.py @@ -28,6 +28,7 @@ import time import shutil import threading import logging + bk_logger = logging.getLogger('blenderkit') @@ -95,6 +96,7 @@ def get_category(categories, cat_path=()): return (c) break; + # def get_upload_asset_type(self): # typemapper = { # bpy.types.Object.blenderkit: 'model', @@ -106,15 +108,16 @@ def get_category(categories, cat_path=()): # asset_type = typemapper[type(self)] # return asset_type -def update_category_enums(self,context): +def update_category_enums(self, context): '''Fixes if lower level is empty - sets it to None, because enum value can be higher.''' - enums = get_subcategory_enums(self,context) + enums = get_subcategory_enums(self, context) if enums[0][0] == 'NONE' and self.subcategory != 'NONE': self.subcategory = 'NONE' -def update_subcategory_enums(self,context): + +def update_subcategory_enums(self, context): '''Fixes if lower level is empty - sets it to None, because enum value can be higher.''' - enums = get_subcategory1_enums(self,context) + enums = get_subcategory1_enums(self, context) if enums[0][0] == 'NONE' and self.subcategory1 != 'NONE': self.subcategory1 = 'NONE' @@ -132,10 +135,11 @@ def get_category_enums(self, context): items.append(('NONE', '', 'no categories on this level defined')) return items + def get_subcategory_enums(self, context): wm = bpy.context.window_manager props = bpy.context.scene.blenderkitUI - asset_type = props.asset_type.lower() + asset_type = props.asset_type.lower() items = [] if self.category != '': asset_categories = get_category(wm['bkit_categories'], cat_path=(asset_type, self.category,)) @@ -146,13 +150,14 @@ def get_subcategory_enums(self, context): # print('subcategory', items) return items + def get_subcategory1_enums(self, context): wm = bpy.context.window_manager props = bpy.context.scene.blenderkitUI - asset_type = props.asset_type.lower() + asset_type = props.asset_type.lower() items = [] if self.category != '' and self.subcategory != '': - asset_categories = get_category(wm['bkit_categories'], cat_path=(asset_type, self.category, self.subcategory, )) + asset_categories = get_category(wm['bkit_categories'], cat_path=(asset_type, self.category, self.subcategory,)) if asset_categories: for c in asset_categories['children']: items.append((c['slug'], c['name'], c['description'])) @@ -160,6 +165,7 @@ def get_subcategory1_enums(self, context): items.append(('NONE', '', 'no categories on this level defined')) return items + def copy_categories(): # this creates the categories system on only tempdir = paths.get_temp_dir() @@ -193,11 +199,12 @@ def load_categories(): except: print('categories failed to read') + # catfetch_counter = 0 -def fetch_categories(API_key, force = False): +def fetch_categories(API_key, force=False): url = paths.get_api_url() + 'categories/' headers = utils.get_headers(API_key) @@ -216,14 +223,14 @@ def fetch_categories(API_key, force = False): try: # read categories only once per day maximum, or when forced to do so. if catfile_age > 86400 or force: - bk_logger.debug('requesting categories') + bk_logger.debug('requesting categories from server') r = rerequests.get(url, headers=headers) rdata = r.json() categories = rdata['results'] fix_category_counts(categories) # filter_categories(categories) #TODO this should filter categories for search, but not for upload. by now off. - with open(categories_filepath, 'w', encoding = 'utf-8') as s: - json.dump(categories, s, ensure_ascii=False, indent=4) + with open(categories_filepath, 'w', encoding='utf-8') as s: + json.dump(categories, s, ensure_ascii=False, indent=4) tasks_queue.add_task((load_categories, ())) except Exception as e: bk_logger.debug('category fetching failed') @@ -233,6 +240,6 @@ def fetch_categories(API_key, force = False): shutil.copy(source_path, categories_filepath) -def fetch_categories_thread(API_key, force = False): +def fetch_categories_thread(API_key, force=False): cat_thread = threading.Thread(target=fetch_categories, args=([API_key, force]), daemon=True) cat_thread.start() diff --git a/blenderkit/download.py b/blenderkit/download.py index 71cc6239..7a233c6f 100644 --- a/blenderkit/download.py +++ b/blenderkit/download.py @@ -280,7 +280,7 @@ def udpate_asset_data_in_dicts(asset_data): scene['assets rated'] = scene.get('assets rated', {}) id = asset_data['assetBaseId'] scene['assets rated'][id] = scene['assets rated'].get(id, False) - sr = bpy.context.scene['search results'] + sr = bpy.context.window_manager['search results'] if not sr: return; for i, r in enumerate(sr): @@ -577,7 +577,7 @@ def timer_update(): downloaders = [] if t.is_alive(): # set downloader size - sr = bpy.context.scene.get('search results') + sr = bpy.context.window_manager.get('search results') if sr is not None: for r in sr: if asset_data['id'] == r['id']: @@ -646,8 +646,8 @@ def timer_update(): tcom.passargs['retry_counter'] = tcom.passargs.get('retry_counter', 0) + 1 download(asset_data, **tcom.passargs) - if bpy.context.scene['search results'] is not None and done: - for sres in bpy.context.scene['search results']: + if bpy.context.window_manager['search results'] is not None and done: + for sres in bpy.context.window_manager['search results']: if asset_data['id'] == sres['id']: sres['downloaded'] = 100 @@ -1282,7 +1282,7 @@ class BlenderkitDownloadOperator(bpy.types.Operator): if self.asset_index > -1: # either get the data from search results - sr = s['search results'] + sr = bpy.context.window_manager['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'] diff --git a/blenderkit/ratings.py b/blenderkit/ratings.py index 4ef194c6..86d204e2 100644 --- a/blenderkit/ratings.py +++ b/blenderkit/ratings.py @@ -429,7 +429,7 @@ class FastRateMenu(Operator): scene = bpy.context.scene ui_props = scene.blenderkitUI if ui_props.active_index > -1: - sr = bpy.context.scene['search results'] + sr = bpy.context.window_manager['search results'] asset_data = dict(sr[ui_props.active_index]) self.asset_id = asset_data['id'] self.asset_type = asset_data['assetType'] @@ -448,7 +448,7 @@ def rating_menu_draw(self, context): layout = self.layout ui_props = context.scene.blenderkitUI - sr = bpy.context.scene['search results orig'] + sr = bpy.context.window_manager['search results orig'] asset_search_index = ui_props.active_index if asset_search_index > -1: diff --git a/blenderkit/resolutions.py b/blenderkit/resolutions.py index cc0a8153..c393a30e 100644 --- a/blenderkit/resolutions.py +++ b/blenderkit/resolutions.py @@ -601,7 +601,7 @@ def assets_db_path(): def get_assets_search(): - bpy.app.debug_value = 2 + # bpy.app.debug_value = 2 results = [] preferences = bpy.context.preferences.addons['blenderkit'].preferences diff --git a/blenderkit/search.py b/blenderkit/search.py index 00f8eda0..c902104c 100644 --- a/blenderkit/search.py +++ b/blenderkit/search.py @@ -144,6 +144,24 @@ def update_assets_data(): # updates assets data on scene load. # bpy.context.scene['assets used'][ad] = ad +def purge_search_results(): + ''' clean up search results on save/load.''' + + s = bpy.context.scene + + sr_props = [ + 'search results', + 'search results orig', + ] + asset_types = ['model', 'material', 'scene', 'hdr', 'brush'] + for at in asset_types: + sr_props.append('bkit {at} search') + sr_props.append('bkit {at} search orig') + for sr_prop in sr_props: + if s.get(sr_prop): + del (s[sr_prop]) + + @persistent def scene_load(context): ''' @@ -151,6 +169,7 @@ def scene_load(context): Should (probably)also update asset data from server (after user consent) ''' wm = bpy.context.window_manager + purge_search_results() fetch_server_data() categories.load_categories() if not bpy.app.timers.is_registered(refresh_token_timer): @@ -171,7 +190,7 @@ def fetch_server_data(): if api_key != '' and bpy.context.window_manager.get('bkit profile') == None: get_profile() if bpy.context.window_manager.get('bkit_categories') is None: - categories.fetch_categories_thread(api_key) + categories.fetch_categories_thread(api_key, force = False) first_time = True @@ -218,7 +237,7 @@ def parse_result(r): # except: # utils.p('asset with no files-size') asset_type = r['assetType'] - if len(r['files']) > 0: + if len(r['files']) > 0:#TODO remove this condition so all assets are parsed. r['available_resolutions'] = [] allthumbs = [] durl, tname, small_tname = '', '', '' @@ -323,7 +342,7 @@ def timer_update(): first_time = False if preferences.show_on_start: # TODO here it should check if there are some results, and only open assetbar if this is the case, not search. - # if bpy.context.scene.get('search results') is None: + # if bpy.context.window_manager.get('search results') is None: search() # preferences.first_run = False if preferences.tips_on_start: @@ -353,7 +372,7 @@ def timer_update(): icons_dir = thread[1] scene = bpy.context.scene # these 2 lines should update the previews enum and set the first result as active. - s = bpy.context.scene + wm = bpy.context.window_manager asset_type = thread[2] if asset_type == 'model': props = scene.blenderkit_models @@ -372,7 +391,7 @@ def timer_update(): # json_filepath = os.path.join(icons_dir, 'brush_searchresult.json') search_name = f'bkit {asset_type} search' - s[search_name] = [] + wm[search_name] = [] global reports if reports != '': @@ -391,10 +410,10 @@ def timer_update(): result_field.append(asset_data) # results = rdata['results'] - s[search_name] = result_field - s['search results'] = result_field - s[search_name + ' orig'] = copy.deepcopy(rdata) - s['search results orig'] = s[search_name + ' orig'] + wm[search_name] = result_field + wm['search results'] = result_field + wm[search_name + ' orig'] = copy.deepcopy(rdata) + wm['search results orig'] = wm[search_name + ' orig'] load_previews() ui_props = bpy.context.scene.blenderkitUI @@ -402,8 +421,8 @@ def timer_update(): ui_props.scrolloffset = 0 props.is_searching = False props.search_error = False - props.report = 'Found %i results. ' % (s['search results orig']['count']) - if len(s['search results']) == 0: + props.report = 'Found %i results. ' % (wm['search results orig']['count']) + if len(wm['search results']) == 0: tasks_queue.add_task((ui.add_report, ('No matching results found.',))) # undo push bpy.ops.wm.undo_push_context(message='Get BlenderKit search') @@ -425,7 +444,7 @@ def load_previews(): props = scene.blenderkitUI directory = paths.get_temp_dir('%s_search' % props.asset_type.lower()) s = bpy.context.scene - results = s.get('search results') + results = bpy.context.window_manager.get('search results') # if results is not None: inames = [] @@ -664,6 +683,8 @@ def generate_tooltip(mdata): t += f"Quality rating: {int(mdata['ratingsAverage']['quality']) * '*'}\n" t += f"Hours saved rating: {int(mdata['ratingsAverage']['workingHours'])}\n" if utils.profile_is_validator(): + t += f"Score: {int(mdata['score'])}\n" + t += f"Ratings count {rc['quality']}*/{rc['workingHours']}wh value " \ f"{mdata['ratingsAverage']['quality']}*/{mdata['ratingsAverage']['workingHours']}wh\n" if len(t.split('\n')) < 11: @@ -1256,7 +1277,6 @@ def add_search_process(query, params, orig_result): old_thread[0].stop() # TODO CARE HERE FOR ALSO KILLING THE Thumbnail THREADS.? # AT LEAST NOW SEARCH DONE FIRST WON'T REWRITE AN OLDER ONE - tempdir = paths.get_temp_dir('%s_search' % query['asset_type']) thread = Searcher(query, params, orig_result) thread.start() @@ -1311,7 +1331,7 @@ def get_search_simple(parameters, filepath=None, page_size=100, max_results=1000 if not filepath: return results - with open(filepath, 'w', encoding = 'utf-8') as s: + with open(filepath, 'w', encoding='utf-8') as s: json.dump(results, s, ensure_ascii=False, indent=4) bk_logger.info(f'retrieved {len(results)} assets from elastic search') return results @@ -1321,7 +1341,6 @@ def search(category='', get_next=False, author_id=''): ''' initialize searching''' global search_start_time user_preferences = bpy.context.preferences.addons['blenderkit'].preferences - search_start_time = time.time() # mt('start') scene = bpy.context.scene @@ -1364,6 +1383,7 @@ def search(category='', get_next=False, author_id=''): props = scene.blenderkit_brush query = build_query_brush() + # it's possible get_net was requested more than once. if props.is_searching and get_next == True: return; @@ -1395,7 +1415,7 @@ def search(category='', get_next=False, author_id=''): # if free_only: # query['keywords'] += '+is_free:true' - orig_results = scene.get(f'bkit {ui_props.asset_type.lower()} search orig', {}) + orig_results = bpy.context.window_manager.get(f'bkit {ui_props.asset_type.lower()} search orig', {}) if orig_results != {}: # ensure it's a copy in dict for what we are passing to thread: orig_results = orig_results.to_dict() diff --git a/blenderkit/ui.py b/blenderkit/ui.py index 8d39b56f..72d0ad7e 100644 --- a/blenderkit/ui.py +++ b/blenderkit/ui.py @@ -138,10 +138,11 @@ class Report(): def get_asset_under_mouse(mousex, mousey): s = bpy.context.scene + wm = bpy.context.window_manager ui_props = bpy.context.scene.blenderkitUI r = bpy.context.region - search_results = s.get('search results') + search_results = wm.get('search results') if search_results is not None: h_draw = min(ui_props.hcount, math.ceil(len(search_results) / ui_props.wcount)) @@ -741,8 +742,8 @@ def draw_asset_bar(self, context): # img, # 1) if not ui_props.dragging and ui_props.hcount > 0 and ui_props.wcount > 0: - search_results = s.get('search results') - search_results_orig = s.get('search results orig') + search_results = bpy.context.window_manager.get('search results') + search_results_orig = bpy.context.window_manager.get('search results orig') if search_results == None: return h_draw = min(ui_props.hcount, math.ceil(len(search_results) / ui_props.wcount)) @@ -882,6 +883,19 @@ def draw_callback_3d(self, context): if ui.draw_snapped_bounds: draw_bbox(ui.snapped_location, ui.snapped_rotation, ui.snapped_bbox_min, ui.snapped_bbox_max) +def object_in_particle_collection(o): + '''checks if an object is in a particle system as instance, to not snap to it and not to try to attach material.''' + for p in bpy.data.particles: + if p.render_type =='COLLECTION': + if p.instance_collection: + for o1 in p.instance_collection.objects: + if o1 == o: + return True + if p.render_type =='COLLECTION': + if p.instance_object == o: + return True + return False + def deep_ray_cast(depsgraph, ray_origin, vec): # this allows to ignore some objects, like objects with bounding box draw style or particle objects @@ -889,19 +903,22 @@ def deep_ray_cast(depsgraph, ray_origin, vec): # while object is None or object.draw has_hit, snapped_location, snapped_normal, face_index, object, matrix = bpy.context.scene.ray_cast( depsgraph, ray_origin, vec) + empty_set = False, Vector((0, 0, 0)), Vector((0, 0, 1)), None, None, None if not object: - return False, Vector((0, 0, 0)), Vector((0, 0, 1)), None, None, None + return empty_set try_object = object - while try_object and try_object.display_type == 'BOUNDS': + + while try_object and (try_object.display_type == 'BOUNDS' or object_in_particle_collection(try_object)): ray_origin = snapped_location + vec.normalized() * 0.0003 try_has_hit, try_snapped_location, try_snapped_normal, try_face_index, try_object, try_matrix = bpy.context.scene.ray_cast( depsgraph, ray_origin, vec) if try_has_hit: + #this way only good hits are returned, otherwise has_hit, snapped_location, snapped_normal, face_index, object, matrix = try_has_hit, try_snapped_location, try_snapped_normal, try_face_index, try_object, try_matrix - - return has_hit, snapped_location, snapped_normal, face_index, object, matrix - + if not (object.display_type == 'BOUNDS' or object_in_particle_collection(try_object)):# or not object.visible_get()): + return has_hit, snapped_location, snapped_normal, face_index, object, matrix + return empty_set def mouse_raycast(context, mx, my): r = context.region @@ -1078,10 +1095,9 @@ def mouse_in_area(mx, my, x, y, w, h): def mouse_in_asset_bar(mx, my): - s = bpy.context.scene ui_props = bpy.context.scene.blenderkitUI - # search_results = s.get('search results') + # search_results = bpy.context.window_manager.get('search results') # if search_results == None: # return False # @@ -1127,7 +1143,7 @@ def update_ui_size(area, region): ui.wcount = math.floor( (ui.bar_width - 2 * ui.drawoffset) / (ui.thumb_size + ui.margin)) - search_results = bpy.context.scene.get('search results') + search_results = bpy.context.window_manager.get('search results') if search_results != None and ui.wcount > 0: ui.hcount = min(user_preferences.max_assetbar_rows, math.ceil(len(search_results) / ui.wcount)) else: @@ -1197,6 +1213,67 @@ class ParticlesDropDialog(bpy.types.Operator): wm = context.window_manager return wm.invoke_props_dialog(self, width=400) +# class MaterialDropDialog(bpy.types.Operator): +# """Tooltip""" +# bl_idname = "object.blenderkit_material_drop" +# bl_label = "BlenderKit material drop on linked objects" +# bl_options = {'REGISTER', 'INTERNAL'} +# +# asset_search_index: IntProperty(name="Asset index", +# description="Index of the asset in asset bar", +# default=0, +# ) +# +# model_location: FloatVectorProperty(name="Location", +# default=(0, 0, 0)) +# +# model_rotation: FloatVectorProperty(name="Rotation", +# default=(0, 0, 0), +# subtype='QUATERNION') +# +# target_object: StringProperty( +# name="Target object", +# description="The object to which the particles will get applied", +# default="", options={'SKIP_SAVE'}) +# +# target_material_slot: IntProperty(name="Target material slot", +# description="Index of the material on the object to be changed", +# default=0, +# ) +# +# @classmethod +# def poll(cls, context): +# return True +# +# def draw(self, context): +# layout = self.layout +# message = "This asset is linked to the scene from an external file and cannot have material appended." \ +# " Do you want to bring it into Blender Scene?" +# utils.label_multiline(layout, text=message, width=400) +# +# def execute(self, context): +# for c in bpy.data.collections: +# for o in c.objects: +# if o.name != self.target_object: +# continue; +# for empty in bpy.context.visible_objects: +# if not(empty.instance_type == 'COLLECTION' and empty.instance_collection == c): +# continue; +# utils.activate(empty) +# break; +# bpy.ops.object.blenderkit_bring_to_scene() +# bpy.ops.scene.blenderkit_download(True, +# # asset_type=ui_props.asset_type, +# asset_index=self.asset_search_index, +# model_location=self.model_rotation, +# model_rotation=self.model_rotation, +# target_object=self.target_object, +# material_target_slot = self.target_slot) +# return {'FINISHED'} +# +# def invoke(self, context, event): +# wm = context.window_manager +# return wm.invoke_props_dialog(self, width=400) class AssetBarOperator(bpy.types.Operator): '''runs search and displays the asset bar at the same time''' @@ -1220,7 +1297,7 @@ class AssetBarOperator(bpy.types.Operator): return properties.tooltip def search_more(self): - sro = bpy.context.scene.get('search results orig') + sro = bpy.context.window_manager.get('search results orig') if sro is not None and sro.get('next') is not None: search.search(get_next=True) @@ -1336,8 +1413,8 @@ class AssetBarOperator(bpy.types.Operator): # TODO add one more condition here to take less performance. r = self.region s = bpy.context.scene - sr = s.get('search results') - search_results_orig = s.get('search results orig') + sr = bpy.context.window_manager.get('search results') + search_results_orig = bpy.context.window_manager.get('search results orig') # If there aren't any results, we need no interaction(yet) if sr is None: return {'PASS_THROUGH'} @@ -1424,7 +1501,7 @@ class AssetBarOperator(bpy.types.Operator): bpy.context.window.cursor_set("DEFAULT") return {'PASS_THROUGH'} - sr = bpy.context.scene['search results'] + sr = bpy.context.window_manager['search results'] if not ui_props.dragging: bpy.context.window.cursor_set("DEFAULT") @@ -1672,7 +1749,7 @@ class AssetBarOperator(bpy.types.Operator): return {'RUNNING_MODAL'} if event.type == 'W' and ui_props.active_index > -1: - sr = bpy.context.scene['search results'] + sr = bpy.context.window_manager['search results'] asset_data = sr[ui_props.active_index] a = bpy.context.window_manager['bkit authors'].get(asset_data['author']['id']) if a is not None: @@ -1681,7 +1758,7 @@ class AssetBarOperator(bpy.types.Operator): bpy.ops.wm.url_open(url=a['aboutMeUrl']) return {'RUNNING_MODAL'} if event.type == 'A' and ui_props.active_index > -1: - sr = bpy.context.scene['search results'] + sr = bpy.context.window_manager['search results'] asset_data = sr[ui_props.active_index] a = asset_data['author']['id'] if a is not None: @@ -1694,7 +1771,7 @@ class AssetBarOperator(bpy.types.Operator): if event.type == 'X' and ui_props.active_index > -1: # delete downloaded files for this asset - sr = bpy.context.scene['search results'] + sr = bpy.context.window_manager['search results'] asset_data = sr[ui_props.active_index] bk_logger.info('delete asset from local drive:' + asset_data['name']) paths.delete_asset_debug(asset_data) @@ -1705,6 +1782,7 @@ class AssetBarOperator(bpy.types.Operator): def invoke(self, context, event): # FIRST START SEARCH ui_props = context.scene.blenderkitUI + sr = bpy.context.window_manager.get('search results') if self.do_search: # we erase search keywords for cateogry search now, since these combinations usually return nothing now. @@ -1715,7 +1793,7 @@ class AssetBarOperator(bpy.types.Operator): search.search(category=self.category) if ui_props.assetbar_on: - # we don't want to run the assetbar many times, that's why it has a switch on/off behaviour, + # we don't want to run the assetbar more than once, that's why it has a switch on/off behaviour, # unless being called with 'keep_running' prop. if not self.keep_running: # this sends message to the originally running operator, so it quits, and then it ends this one too. @@ -1734,9 +1812,8 @@ class AssetBarOperator(bpy.types.Operator): ui_props.assetbar_on = True ui_props.turn_off = False - sr = bpy.context.scene.get('search results') if sr is None: - bpy.context.scene['search results'] = [] + bpy.context.window_manager['search results'] = [] if context.area.type != 'VIEW_3D': self.report({'WARNING'}, "View3D not found, cannot run operator") @@ -1873,6 +1950,8 @@ class AssetDragOperator(bpy.types.Operator): temp_mesh = object_eval.to_mesh() target_slot = temp_mesh.polygons[self.face_index].material_index object_eval.to_mesh_clear() + # elif object.is_library_indirect:#case for bring to scene objects, will be solved through prefs and direct + # action else: self.report({'WARNING'}, "Invalid or library object as input:") target_object = '' @@ -2003,7 +2082,7 @@ class AssetDragOperator(bpy.types.Operator): object = None self.matrix = None - sr = bpy.context.scene['search results'] + sr = bpy.context.window_manager['search results'] self.asset_data = sr[self.asset_search_index] context.window_manager.modal_handler_add(self) diff --git a/blenderkit/ui_panels.py b/blenderkit/ui_panels.py index 921d0453..91abd446 100644 --- a/blenderkit/ui_panels.py +++ b/blenderkit/ui_panels.py @@ -546,7 +546,10 @@ class VIEW3D_PT_blenderkit_profile(Panel): if me is not None: me = me['user'] # user name - layout.label(text='Me: %s %s' % (me['firstName'], me['lastName'])) + 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']}") # layout.label(text='Email: %s' % (me['email'])) # plan information @@ -1244,7 +1247,7 @@ 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.scene['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: @@ -1339,9 +1342,9 @@ def draw_asset_context_menu(layout, context, asset_data, from_panel=False): # def draw(self, context): # ui_props = context.scene.blenderkitUI # -# # sr = bpy.context.scene['search results'] +# # sr = bpy.context.window_manager['search results'] # -# # sr = bpy.context.scene['search results'] +# # sr = bpy.context.window_manager['search results'] # # asset_data = sr[ui_props.active_index] # # for k in resolutions.resolution_props_to_server.keys(): @@ -1355,13 +1358,13 @@ class OBJECT_MT_blenderkit_asset_menu(bpy.types.Menu): def draw(self, context): ui_props = context.scene.blenderkitUI - sr = bpy.context.scene['search results'] + sr = bpy.context.window_manager['search results'] asset_data = sr[ui_props.active_index] draw_asset_context_menu(self.layout, context, asset_data, from_panel=False) # ui_props = context.scene.blenderkitUI # - # sr = bpy.context.scene['search results'] + # sr = bpy.context.window_manager['search results'] # asset_data = sr[ui_props.active_index] # layout = self.layout # row = layout.row() @@ -1403,7 +1406,7 @@ class AssetPopupCard(bpy.types.Operator): def draw(self, context): ui_props = context.scene.blenderkitUI - sr = bpy.context.scene['search results'] + sr = bpy.context.window_manager['search results'] asset_data = sr[ui_props.active_index] layout = self.layout row = layout.row() @@ -1442,7 +1445,7 @@ class AssetPopupCard(bpy.types.Operator): wm = context.window_manager ui_props = context.scene.blenderkitUI ui_props.draw_tooltip = False - sr = bpy.context.scene['search results'] + sr = bpy.context.window_manager['search results'] asset_data = sr[ui_props.active_index] self.img = ui.get_large_thumbnail_image(asset_data) # self.tex = utils.get_hidden_texture(self.img) @@ -1520,10 +1523,18 @@ class UrlPopupDialog(bpy.types.Operator): def draw(self, context): layout = self.layout - utils.label_multiline(layout, text=self.message) + 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) + + layout.operator_context = 'EXEC_DEFAULT' + layout.operator("wm.blenderkit_login", text="Login", + icon='URL').signup = False op.url = self.url def execute(self, context): @@ -1533,7 +1544,7 @@ class UrlPopupDialog(bpy.types.Operator): def invoke(self, context, event): wm = context.window_manager - return wm.invoke_props_dialog(self) + return wm.invoke_props_dialog(self,width = 300) class LoginPopupDialog(bpy.types.Operator): @@ -1688,7 +1699,12 @@ def header_search_draw(self, context): 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) + 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/upload.py b/blenderkit/upload.py index 2cd23f72..1901d92c 100644 --- a/blenderkit/upload.py +++ b/blenderkit/upload.py @@ -524,8 +524,8 @@ def patch_individual_metadata(asset_id, metadata_dict, api_key): # layout = self.layout # ui_props = context.scene.blenderkitUI # -# # sr = bpy.context.scene['search results'] -# sr = bpy.context.scene['search results'] +# # sr = bpy.context.window_manager['search results'] +# sr = bpy.context.window_manager['search results'] # asset_data = sr[ui_props.active_index] # categories = bpy.context.window_manager['bkit_categories'] # wm = bpy.context.win @@ -654,10 +654,10 @@ class FastMetadata(bpy.types.Operator): scene = bpy.context.scene ui_props = scene.blenderkitUI if ui_props.active_index > -1: - sr = bpy.context.scene['search results'] + sr = bpy.context.window_manager['search results'] asset_data = dict(sr[ui_props.active_index]) else: - for result in bpy.context.scene['search results']: + for result in bpy.context.window_manager['search results']: if result['id'] == self.asset_id: asset_data = dict(result) @@ -673,7 +673,6 @@ class FastMetadata(bpy.types.Operator): except Exception as e: print(e) self.message = f"Fast edit metadata of {asset_data['name']}" - self.message = str(cat_path) self.name = asset_data['displayName'] self.description = asset_data['description'] self.tags = ','.join(asset_data['tags']) @@ -1196,12 +1195,12 @@ class AssetDebugPrint(Operator): def execute(self, context): preferences = bpy.context.preferences.addons['blenderkit'].preferences - if not bpy.context.scene['search results']: + if not bpy.context.window_manager['search results']: print('no search results found') return {'CANCELLED'}; # update status in search results for validator's clarity - sr = bpy.context.scene['search results'] - sro = bpy.context.scene['search results orig']['results'] + sr = bpy.context.window_manager['search results'] + sro = bpy.context.window_manager['search results orig']['results'] result = None for r in sr: @@ -1250,11 +1249,11 @@ class AssetVerificationStatusChange(Operator): def execute(self, context): preferences = bpy.context.preferences.addons['blenderkit'].preferences - if not bpy.context.scene['search results']: + if not bpy.context.window_manager['search results']: return {'CANCELLED'}; # update status in search results for validator's clarity - sr = bpy.context.scene['search results'] - sro = bpy.context.scene['search results orig']['results'] + sr = bpy.context.window_manager['search results'] + sro = bpy.context.window_manager['search results orig']['results'] for r in sr: if r['id'] == self.asset_id: diff --git a/blenderkit/utils.py b/blenderkit/utils.py index 94f795c1..30f29ab0 100644 --- a/blenderkit/utils.py +++ b/blenderkit/utils.py @@ -780,13 +780,13 @@ def get_fake_context(context, area_type='VIEW_3D'): C_dict = {} # context.copy() #context.copy was a source of problems - incompatibility with addons that also define context C_dict.update(region='WINDOW') - try: - context = context.copy() - # print('bk context copied successfully') - except Exception as e: - print(e) - print('BlenderKit: context.copy() failed. Can be a colliding addon.') - context = {} + # try: + # context = context.copy() + # # print('bk context copied successfully') + # except Exception as e: + # print(e) + # print('BlenderKit: context.copy() failed. Can be a colliding addon.') + context = {} if context.get('area') is None or context.get('area').type != area_type: w, a, r = get_largest_area(area_type=area_type) @@ -825,3 +825,6 @@ def label_multiline(layout, text='', icon='NONE', width=-1): break; layout.label(text=l, icon=icon) icon = 'NONE' + +def trace(): + traceback.print_stack()
\ No newline at end of file diff --git a/io_scene_gltf2/__init__.py b/io_scene_gltf2/__init__.py index 448a2acc..c2e8db26 100755 --- a/io_scene_gltf2/__init__.py +++ b/io_scene_gltf2/__init__.py @@ -15,7 +15,7 @@ bl_info = { 'name': 'glTF 2.0 format', 'author': 'Julien Duroure, Scurest, Norbert Nopper, Urs Hanselmann, Moritz Becher, Benjamin Schmithüsen, Jim Eckerlein, and many external contributors', - "version": (1, 6, 2), + "version": (1, 6, 3), 'blender': (2, 91, 0), 'location': 'File > Import-Export', 'description': 'Import-Export as glTF 2.0', diff --git a/io_scene_gltf2/blender/exp/gltf2_blender_gather_nodes.py b/io_scene_gltf2/blender/exp/gltf2_blender_gather_nodes.py index 35c2df00..702935fb 100755 --- a/io_scene_gltf2/blender/exp/gltf2_blender_gather_nodes.py +++ b/io_scene_gltf2/blender/exp/gltf2_blender_gather_nodes.py @@ -423,8 +423,17 @@ def __gather_trans_rot_scale(blender_object, export_settings): sca = __convert_swizzle_scale(sca, export_settings) if blender_object.instance_type == 'COLLECTION' and blender_object.instance_collection: - trans -= __convert_swizzle_location( + offset = -__convert_swizzle_location( blender_object.instance_collection.instance_offset, export_settings) + + s = Matrix.Diagonal(sca).to_4x4() + r = rot.to_matrix().to_4x4() + t = Matrix.Translation(trans).to_4x4() + o = Matrix.Translation(offset).to_4x4() + m = t @ r @ s @ o + + trans = m.translation + translation, rotation, scale = (None, None, None) trans[0], trans[1], trans[2] = gltf2_blender_math.round_if_near(trans[0], 0.0), gltf2_blender_math.round_if_near(trans[1], 0.0), \ gltf2_blender_math.round_if_near(trans[2], 0.0) |