BlenderKit: fixes and optimizations
Search results aren't passed around back to search and are parsed only once. Same for previews. Search function could run many times per second when more pages were loaded. Search now causes almost no lag in Blender thanks to the fixes Default page size in search request is now fit to the asset bar size settings. several optimizations in the draw code - is now about 3x faster rerequests now can return a fake response in case of a timeout
This commit is contained in:
parent
f024bcb84d
commit
692a15f3c5
|
@ -19,7 +19,7 @@
|
|||
bl_info = {
|
||||
"name": "BlenderKit Online Asset Library",
|
||||
"author": "Vilem Duha, Petr Dlouhy",
|
||||
"version": (2, 93, 0),
|
||||
"version": (3, 0, 0),
|
||||
"blender": (2, 93, 0),
|
||||
"location": "View3D > Properties > BlenderKit",
|
||||
"description": "Online BlenderKit library (materials, models, brushes and more). Connects to the internet.",
|
||||
|
@ -141,8 +141,6 @@ from bpy.types import (
|
|||
|
||||
@persistent
|
||||
def scene_load(context):
|
||||
if not bpy.app.background:
|
||||
search.load_previews()
|
||||
ui_props = bpy.context.scene.blenderkitUI
|
||||
ui_props.assetbar_on = False
|
||||
ui_props.turn_off = False
|
||||
|
|
|
@ -559,8 +559,15 @@ class BlenderKitAssetBarOperator(BL_UI_OT_draw_operator):
|
|||
|
||||
def search_more(self):
|
||||
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)
|
||||
if sro is None:
|
||||
return;
|
||||
if sro.get('next') is None:
|
||||
return
|
||||
search_props = utils.get_search_props()
|
||||
if search_props.is_searching:
|
||||
return
|
||||
|
||||
blenderkit.search.search(get_next=True)
|
||||
|
||||
def update_images(self):
|
||||
sr = bpy.context.window_manager.get('search results')
|
||||
|
|
|
@ -268,7 +268,7 @@ def rating_menu_draw(self, context):
|
|||
layout = self.layout
|
||||
|
||||
ui_props = context.scene.blenderkitUI
|
||||
sr = bpy.context.window_manager['search results orig']
|
||||
sr = bpy.context.window_manager['search results']
|
||||
|
||||
asset_search_index = ui_props.active_index
|
||||
if asset_search_index > -1:
|
||||
|
|
|
@ -76,9 +76,9 @@ def store_rating_local_empty(asset_id):
|
|||
|
||||
def store_rating_local(asset_id, type='quality', value=0):
|
||||
context = bpy.context
|
||||
context.window_manager['asset ratings'] = context.window_manager.get('asset ratings', {})
|
||||
context.window_manager['asset ratings'][asset_id] = context.window_manager['asset ratings'].get(asset_id, {})
|
||||
context.window_manager['asset ratings'][asset_id][type] = value
|
||||
ar = context.window_manager['asset ratings']
|
||||
ar[asset_id] = ar.get(asset_id, {})
|
||||
ar[asset_id][type] = value
|
||||
|
||||
|
||||
def get_rating(asset_id, headers):
|
||||
|
@ -96,6 +96,8 @@ def get_rating(asset_id, headers):
|
|||
url = paths.get_api_url() + 'assets/' + asset_id + '/rating/'
|
||||
params = {}
|
||||
r = rerequests.get(url, params=params, verify=True, headers=headers)
|
||||
if r is None:
|
||||
return
|
||||
if r.status_code == 200:
|
||||
rj = r.json()
|
||||
ratings = {}
|
||||
|
|
|
@ -26,6 +26,13 @@ import logging
|
|||
bk_logger = logging.getLogger('rerequests')
|
||||
|
||||
|
||||
class FakeResponse():
|
||||
def __init__(self, text='', status_code = 400):
|
||||
self.text = text
|
||||
self.status_code = status_code
|
||||
def json(self):
|
||||
return {}
|
||||
|
||||
def rerequest(method, url, recursion=0, **kwargs):
|
||||
# first get any additional args from kwargs
|
||||
immediate = False
|
||||
|
@ -37,7 +44,9 @@ def rerequest(method, url, recursion=0, **kwargs):
|
|||
response = requests.request(method, url, **kwargs)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return None
|
||||
tasks_queue.add_task((ui.add_report, (
|
||||
'Connection error.', 10)))
|
||||
return FakeResponse()
|
||||
|
||||
bk_logger.debug(url + str(kwargs))
|
||||
bk_logger.debug(response.status_code)
|
||||
|
|
|
@ -52,6 +52,7 @@ import urllib
|
|||
import queue
|
||||
import logging
|
||||
|
||||
|
||||
bk_logger = logging.getLogger('blenderkit')
|
||||
|
||||
search_start_time = 0
|
||||
|
@ -70,6 +71,8 @@ def check_errors(rdata):
|
|||
return False, 'Use login panel to connect your profile.'
|
||||
else:
|
||||
return False, rdata.get('detail')
|
||||
if rdata.get('statusCode') is None and rdata.get('results') is None:
|
||||
return False, 'Connection error'
|
||||
return True, ''
|
||||
|
||||
|
||||
|
@ -287,19 +290,8 @@ def parse_result(r):
|
|||
# so blender's data is same as on server.
|
||||
asset_data = {'thumbnail': tname,
|
||||
'thumbnail_small': small_tname,
|
||||
# 'thumbnails':allthumbs,
|
||||
# 'download_url': durl, #made obsolete since files are stored in orig form.
|
||||
# 'id': r['id'],
|
||||
# 'asset_base_id': r['assetBaseId'],#this should stay ONLY for compatibility with older scenes
|
||||
# 'name': r['name'],
|
||||
# 'asset_type': r['assetType'], #this should stay ONLY for compatibility with older scenes
|
||||
'tooltip': tooltip,
|
||||
# 'tags': r['tags'],
|
||||
# 'can_download': r.get('canDownload', True),#this should stay ONLY for compatibility with older scenes
|
||||
# 'verification_status': r['verificationStatus'],#this should stay ONLY for compatibility with older scenes
|
||||
# 'author_id': r['author']['id'],#this should stay ONLY for compatibility with older scenes
|
||||
# 'author': r['author']['firstName'] + ' ' + r['author']['lastName']
|
||||
# 'description': r['description'],
|
||||
|
||||
}
|
||||
asset_data['downloaded'] = 0
|
||||
|
||||
|
@ -351,6 +343,7 @@ def parse_result(r):
|
|||
|
||||
# @bpy.app.handlers.persistent
|
||||
def search_timer():
|
||||
|
||||
# this makes a first search after opening blender. showing latest assets.
|
||||
# utils.p('timer search')
|
||||
# utils.p('start search timer')
|
||||
|
@ -381,7 +374,8 @@ def search_timer():
|
|||
global search_threads
|
||||
if len(search_threads) == 0:
|
||||
# utils.p('end search timer')
|
||||
|
||||
props = utils.get_search_props()
|
||||
props.is_searching = False
|
||||
return 1.0
|
||||
# don't do anything while dragging - this could switch asset during drag, and make results list length different,
|
||||
# causing a lot of throuble.
|
||||
|
@ -389,34 +383,29 @@ def search_timer():
|
|||
# utils.p('end search timer')
|
||||
|
||||
return 0.5
|
||||
|
||||
for thread in search_threads:
|
||||
# TODO this doesn't check all processes when one gets removed,
|
||||
# but most of the time only one is running anyway
|
||||
if not thread[0].is_alive():
|
||||
|
||||
search_threads.remove(thread) #
|
||||
icons_dir = thread[1]
|
||||
scene = bpy.context.scene
|
||||
# these 2 lines should update the previews enum and set the first result as active.
|
||||
wm = bpy.context.window_manager
|
||||
asset_type = thread[2]
|
||||
if asset_type == 'model':
|
||||
props = scene.blenderkit_models
|
||||
# json_filepath = os.path.join(icons_dir, 'model_searchresult.json')
|
||||
if asset_type == 'scene':
|
||||
props = scene.blenderkit_scene
|
||||
# json_filepath = os.path.join(icons_dir, 'scene_searchresult.json')
|
||||
if asset_type == 'hdr':
|
||||
props = scene.blenderkit_HDR
|
||||
# json_filepath = os.path.join(icons_dir, 'scene_searchresult.json')
|
||||
if asset_type == 'material':
|
||||
props = scene.blenderkit_mat
|
||||
# json_filepath = os.path.join(icons_dir, 'material_searchresult.json')
|
||||
if asset_type == 'brush':
|
||||
props = scene.blenderkit_brush
|
||||
# json_filepath = os.path.join(icons_dir, 'brush_searchresult.json')
|
||||
|
||||
props = utils.get_search_props()
|
||||
search_name = f'bkit {asset_type} search'
|
||||
|
||||
wm[search_name] = []
|
||||
if not thread[0].params.get('get_next'):
|
||||
# wm[search_name] = []
|
||||
result_field = []
|
||||
else:
|
||||
result_field = []
|
||||
for r in wm[search_name]:
|
||||
result_field.append(r.to_dict())
|
||||
|
||||
global reports_queue
|
||||
|
||||
|
@ -427,21 +416,19 @@ def search_timer():
|
|||
return .2
|
||||
|
||||
rdata = thread[0].result
|
||||
result_field = []
|
||||
|
||||
|
||||
|
||||
ok, error = check_errors(rdata)
|
||||
if ok:
|
||||
ui_props = bpy.context.scene.blenderkitUI
|
||||
|
||||
if not ui_props.assetbar_on:
|
||||
bpy.ops.object.run_assetbar_fix_context()
|
||||
|
||||
|
||||
|
||||
for r in rdata['results']:
|
||||
orig_len = len(result_field)
|
||||
for ri, r in enumerate(rdata['results']):
|
||||
asset_data = parse_result(r)
|
||||
if asset_data != None:
|
||||
result_field.append(asset_data)
|
||||
load_preview(asset_data,ri + orig_len)
|
||||
|
||||
# Get ratings from BlenderKit server
|
||||
user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
|
||||
|
@ -455,32 +442,74 @@ def search_timer():
|
|||
|
||||
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()
|
||||
#rdata=['results']=[]
|
||||
wm[search_name + ' orig'] = rdata
|
||||
wm['search results orig'] = rdata
|
||||
|
||||
# load_previews()
|
||||
if len(result_field) < ui_props.scrolloffset or not (thread[0].params.get('get_next')):
|
||||
# jump back
|
||||
ui_props.scrolloffset = 0
|
||||
props.is_searching = False
|
||||
props.search_error = False
|
||||
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')
|
||||
#show asset bar automatically, but only on first page - others are loaded also when asset bar is hidden.
|
||||
if not ui_props.assetbar_on and not thread[0].params.get('get_next'):
|
||||
bpy.ops.object.run_assetbar_fix_context()
|
||||
|
||||
else:
|
||||
bk_logger.error(error)
|
||||
props.report = error
|
||||
props.search_error = True
|
||||
|
||||
props.is_searching = False
|
||||
# print('finished search thread')
|
||||
mt('preview loading finished')
|
||||
# utils.p('end search timer')
|
||||
|
||||
return .3
|
||||
|
||||
def load_preview(asset, index):
|
||||
scene = bpy.context.scene
|
||||
# FIRST START SEARCH
|
||||
props = scene.blenderkitUI
|
||||
directory = paths.get_temp_dir('%s_search' % props.asset_type.lower())
|
||||
s = bpy.context.scene
|
||||
results = bpy.context.window_manager.get('search results')
|
||||
|
||||
|
||||
tpath = os.path.join(directory, asset['thumbnail_small'])
|
||||
if not asset['thumbnail_small']:
|
||||
tpath = paths.get_addon_thumbnail_path('thumbnail_not_available.jpg')
|
||||
|
||||
iname = utils.previmg_name(index)
|
||||
|
||||
# if os.path.exists(tpath): # sometimes we are unlucky...
|
||||
img = bpy.data.images.get(iname)
|
||||
|
||||
if img is None:
|
||||
if not os.path.exists(tpath):
|
||||
return
|
||||
img = bpy.data.images.load(tpath)
|
||||
img.name = iname
|
||||
elif img.filepath != tpath:
|
||||
if not os.path.exists(tpath):
|
||||
return
|
||||
# had to add this check for autopacking files...
|
||||
if img.packed_file is not None:
|
||||
img.unpack(method='USE_ORIGINAL')
|
||||
img.filepath = tpath
|
||||
img.reload()
|
||||
if asset['assetType'] == 'hdr':
|
||||
# to display hdr thumbnails correctly, we use non-color, otherwise looks shifted
|
||||
image_utils.set_colorspace(img, 'Non-Color')
|
||||
else:
|
||||
image_utils.set_colorspace(img, 'sRGB')
|
||||
|
||||
|
||||
def load_previews():
|
||||
scene = bpy.context.scene
|
||||
|
@ -491,39 +520,10 @@ def load_previews():
|
|||
results = bpy.context.window_manager.get('search results')
|
||||
#
|
||||
if results is not None:
|
||||
inames = []
|
||||
tpaths = []
|
||||
|
||||
i = 0
|
||||
for r in results:
|
||||
tpath = os.path.join(directory, r['thumbnail_small'])
|
||||
if not r['thumbnail_small']:
|
||||
tpath = paths.get_addon_thumbnail_path('thumbnail_not_available.jpg')
|
||||
|
||||
if not os.path.exists(tpath):
|
||||
continue
|
||||
iname = utils.previmg_name(i)
|
||||
|
||||
# if os.path.exists(tpath): # sometimes we are unlucky...
|
||||
img = bpy.data.images.get(iname)
|
||||
|
||||
if img is None:
|
||||
img = bpy.data.images.load(tpath)
|
||||
img.name = iname
|
||||
elif img.filepath != tpath:
|
||||
# had to add this check for autopacking files...
|
||||
if img.packed_file is not None:
|
||||
img.unpack(method='USE_ORIGINAL')
|
||||
img.filepath = tpath
|
||||
img.reload()
|
||||
if r['assetType'] == 'hdr':
|
||||
# to display hdr thumbnails correctly, we use non-color, otherwise looks shifted
|
||||
image_utils.set_colorspace(img, 'Non-Color')
|
||||
else:
|
||||
image_utils.set_colorspace(img, 'sRGB')
|
||||
|
||||
load_preview(r,i)
|
||||
i += 1
|
||||
# print('previews loaded')
|
||||
|
||||
|
||||
# line splitting for longer texts...
|
||||
|
@ -848,6 +848,7 @@ def query_to_url(query={}, params={}):
|
|||
if requeststring.find('+order:')==-1:
|
||||
requeststring += '+order:' + ','.join(order)
|
||||
|
||||
requeststring += '&page_size=' + str(params['page_size'])
|
||||
requeststring += '&addon_version=%s' % params['addon_version']
|
||||
if params.get('scene_uuid') is not None:
|
||||
requeststring += '&scene_uuid=%s' % params['scene_uuid']
|
||||
|
@ -865,12 +866,12 @@ def parse_html_formated_error(text):
|
|||
class Searcher(threading.Thread):
|
||||
query = None
|
||||
|
||||
def __init__(self, query, params, orig_result, tempdir='', headers=None, urlquery=''):
|
||||
def __init__(self, query, params, tempdir='', headers=None, urlquery=''):
|
||||
super(Searcher, self).__init__()
|
||||
self.query = query
|
||||
self.params = params
|
||||
self._stop_event = threading.Event()
|
||||
self.result = orig_result
|
||||
self.result = {}
|
||||
self.tempdir = tempdir
|
||||
self.headers = headers
|
||||
self.urlquery = urlquery
|
||||
|
@ -912,9 +913,10 @@ class Searcher(threading.Thread):
|
|||
try:
|
||||
rdata = r.json()
|
||||
except Exception as e:
|
||||
error_description = parse_html_formated_error(r.text)
|
||||
reports_queue.put(error_description)
|
||||
tasks_queue.add_task((ui.add_report, (error_description, 10, colors.RED)))
|
||||
if hasattr(r,'text'):
|
||||
error_description = parse_html_formated_error(r.text)
|
||||
reports_queue.put(error_description)
|
||||
tasks_queue.add_task((ui.add_report, (error_description, 10, colors.RED)))
|
||||
|
||||
bk_logger.error(e)
|
||||
return
|
||||
|
@ -984,8 +986,7 @@ class Searcher(threading.Thread):
|
|||
|
||||
# we save here because a missing thumbnail check is in the previous loop
|
||||
# we can also prepend previous results. These have downloaded thumbnails already...
|
||||
if params['get_next']:
|
||||
rdata['results'][0:0] = self.result['results']
|
||||
|
||||
self.result = rdata
|
||||
# with open(json_filepath, 'w', encoding = 'utf-8') as outfile:
|
||||
# json.dump(rdata, outfile, ensure_ascii=False, indent=4)
|
||||
|
@ -1038,7 +1039,10 @@ class Searcher(threading.Thread):
|
|||
for tk, thread in threads_copy.items():
|
||||
if not thread.is_alive():
|
||||
thread.join()
|
||||
del (thumb_sml_download_threads[tk])
|
||||
try:
|
||||
del (thumb_sml_download_threads[tk])
|
||||
except Exception as e:
|
||||
print(e)
|
||||
i += 1
|
||||
|
||||
if self.stopped():
|
||||
|
@ -1227,7 +1231,7 @@ def mt(text):
|
|||
utils.p(text, alltime, since_last)
|
||||
|
||||
|
||||
def add_search_process(query, params, orig_result):
|
||||
def add_search_process(query, params):
|
||||
global search_threads
|
||||
|
||||
while (len(search_threads) > 0):
|
||||
|
@ -1238,12 +1242,12 @@ def add_search_process(query, params, orig_result):
|
|||
tempdir = paths.get_temp_dir('%s_search' % query['asset_type'])
|
||||
headers = utils.get_headers(params['api_key'])
|
||||
|
||||
if params['get_next']:
|
||||
urlquery = orig_result['next']
|
||||
if not params['get_next']:
|
||||
if params.get('get_next'):
|
||||
urlquery = params['next']
|
||||
else:
|
||||
urlquery = query_to_url(query, params)
|
||||
|
||||
thread = Searcher(query, params, orig_result, tempdir=tempdir, headers=headers, urlquery=urlquery)
|
||||
thread = Searcher(query, params, tempdir=tempdir, headers=headers, urlquery=urlquery)
|
||||
thread.start()
|
||||
|
||||
search_threads.append([thread, tempdir, query['asset_type'], {}]) # 4th field is for results
|
||||
|
@ -1305,35 +1309,33 @@ def get_search_simple(parameters, filepath=None, page_size=100, max_results=1000
|
|||
def search(category='', get_next=False, author_id=''):
|
||||
''' initialize searching'''
|
||||
global search_start_time
|
||||
# print(category,get_next,author_id)
|
||||
user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
|
||||
search_start_time = time.time()
|
||||
# mt('start')
|
||||
scene = bpy.context.scene
|
||||
ui_props = scene.blenderkitUI
|
||||
|
||||
props = utils.get_search_props()
|
||||
if ui_props.asset_type == 'MODEL':
|
||||
if not hasattr(scene, 'blenderkit'):
|
||||
return;
|
||||
props = scene.blenderkit_models
|
||||
query = build_query_model()
|
||||
|
||||
if ui_props.asset_type == 'SCENE':
|
||||
if not hasattr(scene, 'blenderkit_scene'):
|
||||
return;
|
||||
props = scene.blenderkit_scene
|
||||
query = build_query_scene()
|
||||
|
||||
if ui_props.asset_type == 'HDR':
|
||||
if not hasattr(scene, 'blenderkit_HDR'):
|
||||
return;
|
||||
props = scene.blenderkit_HDR
|
||||
query = build_query_HDR()
|
||||
|
||||
if ui_props.asset_type == 'MATERIAL':
|
||||
if not hasattr(scene, 'blenderkit_mat'):
|
||||
return;
|
||||
|
||||
props = scene.blenderkit_mat
|
||||
query = build_query_material()
|
||||
|
||||
if ui_props.asset_type == 'TEXTURE':
|
||||
|
@ -1345,7 +1347,6 @@ def search(category='', get_next=False, author_id=''):
|
|||
if ui_props.asset_type == 'BRUSH':
|
||||
if not hasattr(scene, 'blenderkit_brush'):
|
||||
return;
|
||||
props = scene.blenderkit_brush
|
||||
query = build_query_brush()
|
||||
|
||||
# crop long searches
|
||||
|
@ -1357,8 +1358,11 @@ def search(category='', get_next=False, author_id=''):
|
|||
idx = query['query'].find(' ', 142)
|
||||
query['query'] = query['query'][:idx]
|
||||
|
||||
# it's possible get_net was requested more than once.
|
||||
# it's possible get_next was requested more than once.
|
||||
# print(category,props.is_searching, get_next)
|
||||
# print(query)
|
||||
if props.is_searching and get_next == True:
|
||||
# print('return because of get next and searching is happening')
|
||||
return;
|
||||
|
||||
if category != '':
|
||||
|
@ -1379,19 +1383,21 @@ def search(category='', get_next=False, author_id=''):
|
|||
# utils.p('searching')
|
||||
props.is_searching = True
|
||||
|
||||
page_size = min(40, ui_props.wcount * user_preferences.max_assetbar_rows)
|
||||
|
||||
params = {
|
||||
'scene_uuid': bpy.context.scene.get('uuid', None),
|
||||
'addon_version': version_checker.get_addon_version(),
|
||||
'api_key': user_preferences.api_key,
|
||||
'get_next': get_next,
|
||||
'free_first': props.free_only
|
||||
'free_first': props.free_only,
|
||||
'page_size': page_size,
|
||||
}
|
||||
|
||||
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()
|
||||
add_search_process(query, params, orig_results)
|
||||
orig_results = bpy.context.window_manager.get(f'bkit {ui_props.asset_type.lower()} search orig')
|
||||
if orig_results is not None and get_next:
|
||||
params['next'] = orig_results['next']
|
||||
add_search_process(query, params)
|
||||
tasks_queue.add_task((ui.add_report, ('BlenderKit searching....', 2)))
|
||||
|
||||
props.report = 'BlenderKit searching....'
|
||||
|
@ -1435,6 +1441,7 @@ def search_update(self, context):
|
|||
# return here since writing into search keywords triggers this update function once more.
|
||||
return
|
||||
|
||||
print('search update search')
|
||||
search()
|
||||
|
||||
|
||||
|
@ -1567,6 +1574,7 @@ def register_search():
|
|||
|
||||
user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
|
||||
if user_preferences.use_timers:
|
||||
|
||||
bpy.app.timers.register(search_timer)
|
||||
|
||||
categories.load_categories()
|
||||
|
@ -1580,3 +1588,5 @@ def unregister_search():
|
|||
|
||||
if bpy.app.timers.is_registered(search_timer):
|
||||
bpy.app.timers.unregister(search_timer)
|
||||
|
||||
|
||||
|
|
|
@ -40,10 +40,6 @@ import os
|
|||
|
||||
import logging
|
||||
|
||||
PROFILING = False
|
||||
if PROFILING:
|
||||
import cProfile
|
||||
profiler = cProfile.Profile()
|
||||
|
||||
draw_time = 0
|
||||
eval_time = 0
|
||||
|
@ -422,19 +418,7 @@ def draw_tooltip_with_author(asset_data, x, y):
|
|||
img=img,
|
||||
gravatar=gimg)
|
||||
|
||||
profiler_step = 0
|
||||
def draw_callback_2d_profiled(self,context):
|
||||
global profiler,profiler_step
|
||||
result = profiler.runcall(draw_callback_2d,self,context)
|
||||
if profiler_step >= 1000:
|
||||
|
||||
profiler.print_stats(sort = 'cumulative')
|
||||
profiler = cProfile.Profile()
|
||||
profiler_step = 0
|
||||
profiler_step+=1
|
||||
if profiler_step%10 ==0:
|
||||
print(profiler_step)
|
||||
return
|
||||
|
||||
def draw_callback_2d(self, context):
|
||||
if not utils.guard_from_crash():
|
||||
|
@ -572,7 +556,7 @@ def draw_callback_2d_upload_preview(self, context):
|
|||
|
||||
img = utils.get_hidden_image(ui_props.thumbnail_image, 'upload_preview')
|
||||
|
||||
draw_tooltip(ui_props.bar_x, ui_props.bar_y, name=ui_props.tooltip, img=img)
|
||||
draw_tooltip(ui_props.bar_x, ui_props.bar_y, name=props.name, img=img)
|
||||
|
||||
|
||||
def is_upload_old(asset_data):
|
||||
|
@ -760,7 +744,7 @@ def draw_asset_bar(self, context):
|
|||
# report = 'BlenderKit - No matching results found.'
|
||||
# ui_bgl.draw_text(report, ui_props.bar_x + ui_props.margin,
|
||||
# ui_props.bar_y - 25 - ui_props.margin, 15)
|
||||
if ui_props.draw_tooltip:
|
||||
if ui_props.draw_tooltip and len(search_results)>ui_props.active_index:
|
||||
r = search_results[ui_props.active_index]
|
||||
draw_tooltip_with_author(r, ui_props.mouse_x, ui_props.mouse_y)
|
||||
s = bpy.context.scene
|
||||
|
@ -1162,7 +1146,6 @@ class ParticlesDropDialog(bpy.types.Operator):
|
|||
# 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'''
|
||||
bl_idname = "view3d.blenderkit_asset_bar"
|
||||
|
@ -1186,8 +1169,15 @@ class AssetBarOperator(bpy.types.Operator):
|
|||
|
||||
def search_more(self):
|
||||
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)
|
||||
if sro is None:
|
||||
return;
|
||||
if sro.get('next') is None:
|
||||
return
|
||||
search_props = utils.get_search_props()
|
||||
if search_props.is_searching:
|
||||
return
|
||||
|
||||
search.search(get_next=True)
|
||||
|
||||
def exit_modal(self):
|
||||
try:
|
||||
|
@ -1196,13 +1186,14 @@ class AssetBarOperator(bpy.types.Operator):
|
|||
pass;
|
||||
ui_props = bpy.context.scene.blenderkitUI
|
||||
|
||||
ui_props.tooltip = ''
|
||||
# ui_props.tooltip = ''
|
||||
ui_props.active_index = -3
|
||||
ui_props.draw_drag_image = False
|
||||
ui_props.draw_snapped_bounds = False
|
||||
ui_props.has_hit = False
|
||||
ui_props.assetbar_on = False
|
||||
|
||||
|
||||
def modal(self, context, event):
|
||||
|
||||
# This is for case of closing the area or changing type:
|
||||
|
@ -1286,16 +1277,16 @@ class AssetBarOperator(bpy.types.Operator):
|
|||
|
||||
# only generate tooltip once in a while
|
||||
if (
|
||||
event.type == 'LEFTMOUSE' or event.type == 'RIGHTMOUSE') and event.value == 'RELEASE' or event.type == 'ENTER' or ui_props.tooltip == '':
|
||||
event.type == 'LEFTMOUSE' or event.type == 'RIGHTMOUSE') and event.value == 'RELEASE' or event.type == 'ENTER':
|
||||
ao = bpy.context.active_object
|
||||
if ui_props.asset_type == 'MODEL' and ao != None \
|
||||
or ui_props.asset_type == 'MATERIAL' and ao != None and ao.active_material != None \
|
||||
or ui_props.asset_type == 'BRUSH' and utils.get_active_brush() is not None \
|
||||
or ui_props.asset_type == 'SCENE' or ui_props.asset_type == 'HDR':
|
||||
export_data, upload_data = upload.get_upload_data(context=context, asset_type=ui_props.asset_type)
|
||||
if upload_data:
|
||||
# print(upload_data)
|
||||
ui_props.tooltip = upload_data['displayName'] # search.generate_tooltip(upload_data)
|
||||
# if upload_data:
|
||||
# # print(upload_data)
|
||||
# ui_props.tooltip = upload_data['displayName'] # search.generate_tooltip(upload_data)
|
||||
|
||||
return {'PASS_THROUGH'}
|
||||
|
||||
|
@ -1307,7 +1298,7 @@ class AssetBarOperator(bpy.types.Operator):
|
|||
# If there aren't any results, we need no interaction(yet)
|
||||
if sr is None:
|
||||
return {'PASS_THROUGH'}
|
||||
if len(sr) - ui_props.scrolloffset < (ui_props.wcount * ui_props.hcount) + 10:
|
||||
if len(sr) - ui_props.scrolloffset < (ui_props.wcount * user_preferences.max_assetbar_rows) + 10:
|
||||
self.search_more()
|
||||
|
||||
if event.type == 'WHEELUPMOUSE' or event.type == 'WHEELDOWNMOUSE' or event.type == 'TRACKPADPAN':
|
||||
|
@ -1372,7 +1363,7 @@ class AssetBarOperator(bpy.types.Operator):
|
|||
asset_data = sr[asset_search_index]
|
||||
ui_props.draw_tooltip = True
|
||||
|
||||
ui_props.tooltip = asset_data['tooltip']
|
||||
# ui_props.tooltip = asset_data['tooltip']
|
||||
# bpy.ops.wm.call_menu(name='OBJECT_MT_blenderkit_asset_menu')
|
||||
|
||||
else:
|
||||
|
@ -1538,18 +1529,16 @@ class AssetBarOperator(bpy.types.Operator):
|
|||
|
||||
update_ui_size(self.area, self.region)
|
||||
|
||||
if PROFILING:
|
||||
self._handle_2d = bpy.types.SpaceView3D.draw_handler_add(draw_callback_2d_profiled, args, 'WINDOW', 'POST_PIXEL')
|
||||
else:
|
||||
self._handle_2d = bpy.types.SpaceView3D.draw_handler_add(draw_callback_2d, args, 'WINDOW', 'POST_PIXEL')
|
||||
|
||||
context.window_manager.modal_handler_add(self)
|
||||
self._handle_2d = bpy.types.SpaceView3D.draw_handler_add(draw_callback_2d, args, 'WINDOW', 'POST_PIXEL')
|
||||
|
||||
ui_props.assetbar_on = True
|
||||
|
||||
# in an exceptional case these were accessed before drag start.
|
||||
self.drag_start_x = 0
|
||||
self.drag_start_y = 0
|
||||
|
||||
context.window_manager.modal_handler_add(self)
|
||||
return {'RUNNING_MODAL'}
|
||||
|
||||
def execute(self, context):
|
||||
|
@ -1815,8 +1804,11 @@ class AssetDragOperator(bpy.types.Operator):
|
|||
sprops = bpy.context.scene.blenderkit_models
|
||||
if event.type == 'WHEELUPMOUSE':
|
||||
sprops.offset_rotation_amount += sprops.offset_rotation_step
|
||||
return {'RUNNING_MODAL'}
|
||||
elif event.type == 'WHEELDOWNMOUSE':
|
||||
sprops.offset_rotation_amount -= sprops.offset_rotation_step
|
||||
return {'RUNNING_MODAL'}
|
||||
|
||||
|
||||
if event.type =='MOUSEMOVE':
|
||||
|
||||
|
@ -1837,6 +1829,7 @@ class AssetDragOperator(bpy.types.Operator):
|
|||
if ui_props.asset_type == 'MODEL':
|
||||
self.snapped_bbox_min = Vector(self.asset_data['bbox_min'])
|
||||
self.snapped_bbox_max = Vector(self.asset_data['bbox_max'])
|
||||
return {'RUNNING_MODAL'}
|
||||
|
||||
if event.type == 'LEFTMOUSE' and event.value == 'RELEASE':
|
||||
self.mouse_release()# does the main job with assets
|
||||
|
@ -1887,11 +1880,11 @@ class AssetDragOperator(bpy.types.Operator):
|
|||
self._handle = bpy.types.SpaceView3D.draw_handler_add(draw_callback_dragging, args, 'WINDOW', 'POST_PIXEL')
|
||||
self._handle_3d = bpy.types.SpaceView3D.draw_handler_add(draw_callback_3d_dragging, args, 'WINDOW',
|
||||
'POST_VIEW')
|
||||
context.window_manager.modal_handler_add(self)
|
||||
|
||||
bpy.context.window.cursor_set("NONE")
|
||||
ui_props = bpy.context.scene.blenderkitUI
|
||||
ui_props.dragging = True
|
||||
context.window_manager.modal_handler_add(self)
|
||||
return {'RUNNING_MODAL'}
|
||||
else:
|
||||
self.report({'WARNING'}, "View3D not found, cannot run operator")
|
||||
|
|
|
@ -1854,7 +1854,7 @@ class AssetPopupCard(bpy.types.Operator, ratings_utils.RatingsProperties):
|
|||
# name_row = name_row.row()
|
||||
for i, c in enumerate(cat_path):
|
||||
cat_name = cat_path_names[i]
|
||||
op = name_row.operator('view3d.blenderkit_asset_bar', text=cat_name + ' >', emboss=True)
|
||||
op = name_row.operator('view3d.blenderkit_asset_bar', text=cat_name + ' >', emboss=False)
|
||||
op.do_search = True
|
||||
op.keep_running = True
|
||||
op.tooltip = f"Browse {cat_name} category"
|
||||
|
|
|
@ -1274,16 +1274,11 @@ class AssetDebugPrint(Operator):
|
|||
return {'CANCELLED'};
|
||||
# update status in search results for validator's clarity
|
||||
sr = bpy.context.window_manager['search results']
|
||||
sro = bpy.context.window_manager['search results orig']['results']
|
||||
|
||||
result = None
|
||||
for r in sr:
|
||||
if r['id'] == self.asset_id:
|
||||
result = r.to_dict()
|
||||
if not result:
|
||||
for r in sro:
|
||||
if r['id'] == self.asset_id:
|
||||
result = r.to_dict()
|
||||
if not result:
|
||||
ad = bpy.context.active_object.get('asset_data')
|
||||
if ad:
|
||||
|
@ -1329,14 +1324,10 @@ class AssetVerificationStatusChange(Operator):
|
|||
return {'CANCELLED'};
|
||||
# update status in search results for validator's clarity
|
||||
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:
|
||||
r['verificationStatus'] = self.state
|
||||
for r in sro:
|
||||
if r['id'] == self.asset_id:
|
||||
r['verificationStatus'] = self.state
|
||||
|
||||
thread = threading.Thread(target=verification_status_change_thread,
|
||||
args=(self.asset_id, self.state, preferences.api_key))
|
||||
|
@ -1353,7 +1344,6 @@ class AssetVerificationStatusChange(Operator):
|
|||
|
||||
def register_upload():
|
||||
bpy.utils.register_class(UploadOperator)
|
||||
# bpy.utils.register_class(FastMetadataMenu)
|
||||
bpy.utils.register_class(FastMetadata)
|
||||
bpy.utils.register_class(AssetDebugPrint)
|
||||
bpy.utils.register_class(AssetVerificationStatusChange)
|
||||
|
@ -1361,7 +1351,6 @@ def register_upload():
|
|||
|
||||
def unregister_upload():
|
||||
bpy.utils.unregister_class(UploadOperator)
|
||||
# bpy.utils.unregister_class(FastMetadataMenu)
|
||||
bpy.utils.unregister_class(FastMetadata)
|
||||
bpy.utils.unregister_class(AssetDebugPrint)
|
||||
bpy.utils.unregister_class(AssetVerificationStatusChange)
|
||||
|
|
Loading…
Reference in New Issue