BlenderKit:
-improve multiline tooltips -change addon category to 3d view, fits a bit more than add mesh -support searching only own assets -support searching for procedural only assets(hiddn by now) -switch off defautl GPU on for thumbnails- this was a bug that went unnoticed for a long time. -add gpu render option directly to thumbnail render dialogs -non-treaded downloading for resolutions -move in utils and rename correctly params_to_dict and dict_to_params -display icon for rejected assets(needs a new icon) -split login panel -rename some panels for more consistency -improve some tooltips
This commit is contained in:
parent
171648da57
commit
8e3757177c
Notes:
blender-bot
2023-02-14 18:55:34 +01:00
Referenced by issue #76905, Unable to download blenderkit (in steam version) not in add-on section.
|
@ -26,7 +26,7 @@ bl_info = {
|
|||
"warning": "",
|
||||
"wiki_url": "https://youtu.be/1hVgcQhIAo8"
|
||||
"Scripts/Add_Mesh/BlenderKit",
|
||||
"category": "Add Mesh",
|
||||
"category": "3D View",
|
||||
}
|
||||
|
||||
if "bpy" in locals():
|
||||
|
@ -249,11 +249,11 @@ def asset_type_callback(self, context):
|
|||
#ui_props = s.blenderkitUI
|
||||
if self.down_up == 'SEARCH':
|
||||
items = (
|
||||
('MODEL', 'Search Models', 'Browse models', 'OBJECT_DATAMODE', 0),
|
||||
('MODEL', 'Find Models', 'Find models in the BlenderKit online database', 'OBJECT_DATAMODE', 0),
|
||||
# ('SCENE', 'SCENE', 'Browse scenes', 'SCENE_DATA', 1),
|
||||
('MATERIAL', 'Search Materials', 'Browse materials', 'MATERIAL', 2),
|
||||
('MATERIAL', 'Find Materials', 'Find models in the BlenderKit online database', 'MATERIAL', 2),
|
||||
# ('TEXTURE', 'Texture', 'Browse textures', 'TEXTURE', 3),
|
||||
('BRUSH', 'Search Brushes', 'Browse brushes', 'BRUSH_DATA', 3)
|
||||
('BRUSH', 'Find Brushes', 'Find models in the BlenderKit online database', 'BRUSH_DATA', 3)
|
||||
)
|
||||
else:
|
||||
items = (
|
||||
|
@ -386,6 +386,8 @@ class BlenderKitCommonSearchProps(object):
|
|||
default=False)
|
||||
search_done: BoolProperty(name="Search Completed", description="at least one search did run (internal)",
|
||||
default=False)
|
||||
own_only: BoolProperty(name="My Assets", description="Search only for your assets",
|
||||
default=False)
|
||||
search_error: BoolProperty(name="Search Error", description="last search had an error", default=False)
|
||||
report: StringProperty(
|
||||
name="Report",
|
||||
|
@ -508,8 +510,8 @@ class BlenderKitCommonUploadProps(object):
|
|||
default=True
|
||||
)
|
||||
node_count: IntProperty(name="Node count", description="Total nodes in the asset", default=0)
|
||||
texture_count: IntProperty(name="Node count", description="Total nodes in the asset", default=0)
|
||||
total_megapixels: IntProperty(name="Node count", description="Total nodes in the asset", default=0)
|
||||
texture_count: IntProperty(name="Texture count", description="Total texture count in asset", default=0)
|
||||
total_megapixels: IntProperty(name="Megapixels", description="Total megapixels of texture", default=0)
|
||||
|
||||
# is_private: BoolProperty(name="Asset is Private",
|
||||
# description="If not marked private, your asset will go into the validation process automatically\n"
|
||||
|
@ -1165,6 +1167,18 @@ class BlenderKitModelSearchProps(PropertyGroup, BlenderKitCommonSearchProps):
|
|||
update=search.search_update
|
||||
)
|
||||
|
||||
search_procedural: EnumProperty(
|
||||
items=(
|
||||
('BOTH', 'Both',''),
|
||||
('PROCEDURAL', 'Procedural',''),
|
||||
('TEXTURE_BASED', 'Texture based',''),
|
||||
|
||||
),
|
||||
default='BOTH',
|
||||
description='Search only procedural/texture based assets',
|
||||
update=search.search_update
|
||||
)
|
||||
|
||||
# DESIGN YEAR
|
||||
search_design_year: BoolProperty(name="Sesigned in Year",
|
||||
description="when the object was approximately designed",
|
||||
|
@ -1389,7 +1403,7 @@ class BlenderKitAddonPreferences(AddonPreferences):
|
|||
thumbnail_use_gpu: BoolProperty(
|
||||
name="Use GPU for Thumbnails Rendering",
|
||||
description="By default this is off so you can continue your work without any lag",
|
||||
default=True
|
||||
default=False
|
||||
)
|
||||
|
||||
panel_behaviour: EnumProperty(
|
||||
|
|
|
@ -262,6 +262,8 @@ class GenerateThumbnailOperator(bpy.types.Operator):
|
|||
layout.prop(props, 'thumbnail_samples')
|
||||
layout.prop(props, 'thumbnail_resolution')
|
||||
layout.prop(props, 'thumbnail_denoising')
|
||||
preferences = bpy.context.preferences.addons['blenderkit'].preferences
|
||||
layout.prop(preferences, "thumbnail_use_gpu")
|
||||
|
||||
def execute(self, context):
|
||||
start_thumbnailer(self, context)
|
||||
|
@ -307,6 +309,8 @@ class GenerateMaterialThumbnailOperator(bpy.types.Operator):
|
|||
layout.prop(props, 'thumbnail_samples')
|
||||
layout.prop(props, 'thumbnail_denoising')
|
||||
layout.prop(props, 'adaptive_subdivision')
|
||||
preferences = bpy.context.preferences.addons['blenderkit'].preferences
|
||||
layout.prop(preferences, "thumbnail_use_gpu")
|
||||
|
||||
def execute(self, context):
|
||||
start_material_thumbnailer(self, context)
|
||||
|
|
|
@ -523,6 +523,34 @@ def timer_update(): # TODO might get moved to handle all blenderkit stuff, not
|
|||
return .5
|
||||
|
||||
|
||||
def download_file(asset_data):
|
||||
#this is a simple non-threaded way to download files for background resolution genenration tool
|
||||
file_name = paths.get_download_filenames(asset_data)[0] # prefer global dir if possible.
|
||||
|
||||
if check_existing(asset_data):
|
||||
# this sends the thread for processing, where another check should occur, since the file might be corrupted.
|
||||
utils.p('not downloading, already in db')
|
||||
return file_name
|
||||
preferences = bpy.context.preferences.addons['blenderkit'].preferences
|
||||
api_key = preferences.api_key
|
||||
|
||||
with open(file_name, "wb") as f:
|
||||
print("Downloading %s" % file_name)
|
||||
headers = utils.get_headers(api_key)
|
||||
|
||||
response = requests.get(asset_data['url'], stream=True)
|
||||
total_length = response.headers.get('Content-Length')
|
||||
|
||||
if total_length is None: # no content length header
|
||||
f.write(response.content)
|
||||
else:
|
||||
dl = 0
|
||||
for data in response.iter_content(chunk_size=4096):
|
||||
dl += len(data)
|
||||
print(dl)
|
||||
f.write(data)
|
||||
return file_name
|
||||
|
||||
class Downloader(threading.Thread):
|
||||
def __init__(self, asset_data, tcom, scene_id, api_key):
|
||||
super(Downloader, self).__init__()
|
||||
|
|
|
@ -55,9 +55,11 @@ def rerequest(method, url, **kwargs):
|
|||
user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
|
||||
if user_preferences.api_key != '':
|
||||
if user_preferences.enable_oauth:
|
||||
tasks_queue.add_task((ui.add_report, ('refreshing token.',)))
|
||||
tasks_queue.add_task((ui.add_report, (
|
||||
'refreshing token. If this fails, please login in BlenderKit Login panel.', 10)))
|
||||
refresh_url = paths.get_bkit_url()
|
||||
auth_token, refresh_token, oauth_response = bkit_oauth.refresh_token(user_preferences.api_key_refresh, refresh_url)
|
||||
auth_token, refresh_token, oauth_response = bkit_oauth.refresh_token(
|
||||
user_preferences.api_key_refresh, refresh_url)
|
||||
|
||||
# utils.p(auth_token, refresh_token)
|
||||
if auth_token is not None:
|
||||
|
|
|
@ -220,7 +220,7 @@ def timer_update(): # TODO might get moved to handle all blenderkit stuff.
|
|||
asset_data['downloaded'] = 0
|
||||
|
||||
# parse extra params needed for blender here
|
||||
params = params_to_dict(r['parameters'])
|
||||
params = utils.params_to_dict(r['parameters'])
|
||||
|
||||
if asset_type == 'model':
|
||||
if params.get('boundBoxMinX') != None:
|
||||
|
@ -403,17 +403,13 @@ def has(mdata, prop):
|
|||
return False
|
||||
|
||||
|
||||
def params_to_dict(params):
|
||||
params_dict = {}
|
||||
for p in params:
|
||||
params_dict[p['parameterType']] = p['value']
|
||||
return params_dict
|
||||
|
||||
|
||||
|
||||
def generate_tooltip(mdata):
|
||||
col_w = 40
|
||||
if type(mdata['parameters']) == list:
|
||||
mparams = params_to_dict(mdata['parameters'])
|
||||
mparams = utils.params_to_dict(mdata['parameters'])
|
||||
else:
|
||||
mparams = mdata['parameters']
|
||||
t = ''
|
||||
|
@ -953,6 +949,11 @@ def build_query_model():
|
|||
query["textureResolutionMin"] = props.search_texture_resolution_min
|
||||
query["textureResolutionMax"] = props.search_texture_resolution_max
|
||||
|
||||
if props.search_procedural == "PROCEDURAL":
|
||||
query["procedural"] = True
|
||||
elif props.search_procedural == 'TEXTURE_BASED':
|
||||
query["procedural"] = False
|
||||
|
||||
build_query_common(query, props)
|
||||
|
||||
return query
|
||||
|
@ -1106,6 +1107,12 @@ def search(category='', get_next=False, author_id=''):
|
|||
if author_id != '':
|
||||
query['author_id'] = author_id
|
||||
|
||||
elif props.own_only:
|
||||
# if user searches for [another] author, 'only my assets' is invalid. that's why in elif.
|
||||
profile = bpy.context.window_manager.get('bkit profile')
|
||||
if profile is not None:
|
||||
query['author_id'] = str(profile['user']['id'])
|
||||
|
||||
# utils.p('searching')
|
||||
props.is_searching = True
|
||||
|
||||
|
|
|
@ -67,7 +67,7 @@ verification_icons = {
|
|||
'uploading': 'vs_uploading.png',
|
||||
'on_hold': 'vs_on_hold.png',
|
||||
'validated': None,
|
||||
'rejected': None
|
||||
'rejected': 'vs_on_hold.png'
|
||||
|
||||
}
|
||||
|
||||
|
@ -698,6 +698,7 @@ def draw_callback_2d_upload_preview(self, context):
|
|||
|
||||
props = utils.get_upload_props()
|
||||
if props != None and ui_props.draw_tooltip:
|
||||
|
||||
if ui_props.asset_type != 'BRUSH':
|
||||
ui_props.thumbnail_image = props.thumbnail
|
||||
else:
|
||||
|
@ -1417,6 +1418,9 @@ class AssetBarOperator(bpy.types.Operator):
|
|||
ui_props.draw_tooltip = True
|
||||
|
||||
ui_props.tooltip = asset_data['tooltip']
|
||||
|
||||
#bpy.ops.wm.call_menu(name='OBJECT_MT_blenderkit_asset_menu')
|
||||
|
||||
else:
|
||||
ui_props.draw_tooltip = False
|
||||
|
||||
|
|
|
@ -53,7 +53,7 @@ def label_multiline(layout, text='', icon='NONE', width=-1):
|
|||
l1 = l[:i]
|
||||
layout.label(text=l1, icon=icon)
|
||||
icon = 'NONE'
|
||||
l = l[i:]
|
||||
l = l[i:].lstrip()
|
||||
li += 1
|
||||
if li > maxlines:
|
||||
break;
|
||||
|
@ -299,7 +299,9 @@ def draw_panel_model_search(self, context):
|
|||
layout.operator("wm.url_open", text="Get Full plan", icon='URL').url = paths.BLENDERKIT_PLANS
|
||||
|
||||
layout.prop(props, "search_style")
|
||||
layout.prop(props, "own_only")
|
||||
layout.prop(props, "free_only")
|
||||
#layout.prop(props, "search_procedural", expand = True)
|
||||
# if props.search_style == 'OTHER':
|
||||
# layout.prop(props, "search_style_other")
|
||||
# layout.prop(props, "search_engine")
|
||||
|
@ -366,7 +368,7 @@ def draw_panel_scene_search(self, context):
|
|||
row = layout.row()
|
||||
row.prop(props, "search_keywords", text="", icon='VIEWZOOM')
|
||||
draw_assetbar_show_hide(row, props)
|
||||
|
||||
layout.prop(props, "own_only")
|
||||
label_multiline(layout, text=props.report)
|
||||
|
||||
# layout.prop(props, "search_style")
|
||||
|
@ -424,7 +426,7 @@ class VIEW3D_PT_blenderkit_profile(Panel):
|
|||
bl_idname = "VIEW3D_PT_blenderkit_profile"
|
||||
bl_space_type = 'VIEW_3D'
|
||||
bl_region_type = 'UI'
|
||||
bl_label = "Profile"
|
||||
bl_label = "BlenderKit Profile"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
|
@ -440,8 +442,6 @@ class VIEW3D_PT_blenderkit_profile(Panel):
|
|||
draw_login_progress(layout)
|
||||
return
|
||||
|
||||
if user_preferences.enable_oauth:
|
||||
draw_login_buttons(layout)
|
||||
|
||||
if user_preferences.api_key != '':
|
||||
me = bpy.context.window_manager.get('bkit profile')
|
||||
|
@ -460,6 +460,28 @@ class VIEW3D_PT_blenderkit_profile(Panel):
|
|||
icon='URL').url = paths.get_bkit_url() + paths.BLENDERKIT_USER_ASSETS
|
||||
|
||||
|
||||
class VIEW3D_PT_blenderkit_login(Panel):
|
||||
bl_category = "BlenderKit"
|
||||
bl_idname = "VIEW3D_PT_blenderkit_login"
|
||||
bl_space_type = 'VIEW_3D'
|
||||
bl_region_type = 'UI'
|
||||
bl_label = "BlenderKit Login"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return True
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
|
||||
|
||||
if user_preferences.login_attempt:
|
||||
draw_login_progress(layout)
|
||||
return
|
||||
|
||||
if user_preferences.enable_oauth:
|
||||
draw_login_buttons(layout)
|
||||
|
||||
def draw_panel_model_rating(self, context):
|
||||
o = bpy.context.active_object
|
||||
op = draw_ratings(self.layout, context) # , props)
|
||||
|
@ -526,7 +548,7 @@ def draw_panel_material_search(self, context):
|
|||
row = layout.row()
|
||||
row.prop(props, "search_keywords", text="", icon='VIEWZOOM')
|
||||
draw_assetbar_show_hide(row, props)
|
||||
|
||||
layout.prop(props, "own_only")
|
||||
label_multiline(layout, text=props.report)
|
||||
|
||||
# layout.prop(props, 'search_style')
|
||||
|
@ -568,7 +590,7 @@ def draw_panel_brush_search(self, context):
|
|||
row = layout.row()
|
||||
row.prop(props, "search_keywords", text="", icon='VIEWZOOM')
|
||||
draw_assetbar_show_hide(row, props)
|
||||
|
||||
layout.prop(props, "own_only")
|
||||
|
||||
label_multiline(layout, text=props.report)
|
||||
draw_panel_categories(self, context)
|
||||
|
@ -605,7 +627,7 @@ class VIEW3D_PT_blenderkit_unified(Panel):
|
|||
bl_idname = "VIEW3D_PT_blenderkit_unified"
|
||||
bl_space_type = 'VIEW_3D'
|
||||
bl_region_type = 'UI'
|
||||
bl_label = "BlenderKit"
|
||||
bl_label = "Find and Upload Assets"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
|
@ -651,11 +673,11 @@ class VIEW3D_PT_blenderkit_unified(Panel):
|
|||
layout.label(text='Paste your API Key:')
|
||||
layout.prop(user_preferences, 'api_key', text='')
|
||||
layout.separator()
|
||||
if bpy.data.filepath == '':
|
||||
layout.alert = True
|
||||
label_multiline(layout, text="It's better to save your file first.", width=w)
|
||||
layout.alert = False
|
||||
layout.separator()
|
||||
# if bpy.data.filepath == '':
|
||||
# layout.alert = True
|
||||
# label_multiline(layout, text="It's better to save your file first.", width=w)
|
||||
# layout.alert = False
|
||||
# layout.separator()
|
||||
|
||||
if ui_props.down_up == 'SEARCH':
|
||||
|
||||
|
@ -986,7 +1008,8 @@ def header_search_draw(self, context):
|
|||
if ui_props.asset_type == 'BRUSH':
|
||||
props = s.blenderkit_brush
|
||||
|
||||
layout.separator_spacer()
|
||||
if context.space_data.show_region_tool_header == True:
|
||||
layout.separator_spacer()
|
||||
layout.prop(ui_props, "asset_type", text='', icon='URL')
|
||||
layout.prop(props, "search_keywords", text="", icon='VIEWZOOM')
|
||||
draw_assetbar_show_hide(layout, props)
|
||||
|
@ -998,10 +1021,11 @@ preview_collections = {}
|
|||
classess = (
|
||||
SetCategoryOperator,
|
||||
|
||||
VIEW3D_PT_blenderkit_profile,
|
||||
VIEW3D_PT_blenderkit_login,
|
||||
VIEW3D_PT_blenderkit_unified,
|
||||
VIEW3D_PT_blenderkit_model_properties,
|
||||
VIEW3D_PT_blenderkit_downloads,
|
||||
VIEW3D_PT_blenderkit_profile,
|
||||
OBJECT_MT_blenderkit_asset_menu,
|
||||
UrlPopupDialog
|
||||
)
|
||||
|
|
|
@ -81,28 +81,6 @@ def add_version(data):
|
|||
data["addonVersion"] = addon_version
|
||||
|
||||
|
||||
def params_to_dict(inputs, parameters=None):
|
||||
if parameters == None:
|
||||
parameters = []
|
||||
for k in inputs.keys():
|
||||
if type(inputs[k]) == list:
|
||||
strlist = ""
|
||||
for idx, s in enumerate(inputs[k]):
|
||||
strlist += s
|
||||
if idx < len(inputs[k]) - 1:
|
||||
strlist += ','
|
||||
|
||||
value = "%s" % strlist
|
||||
elif type(inputs[k]) != bool:
|
||||
value = inputs[k]
|
||||
else:
|
||||
value = str(inputs[k])
|
||||
parameters.append(
|
||||
{
|
||||
"parameterType": k,
|
||||
"value": value
|
||||
})
|
||||
return parameters
|
||||
|
||||
|
||||
def write_to_report(props, text):
|
||||
|
@ -570,7 +548,7 @@ def start_upload(self, context, asset_type, reupload, upload_set):
|
|||
export_data, upload_data, eval_path_computing, eval_path_state, eval_path, props = get_upload_data(self, context,
|
||||
asset_type)
|
||||
# utils.pprint(upload_data)
|
||||
upload_data['parameters'] = params_to_dict(
|
||||
upload_data['parameters'] = utils.dict_to_params(
|
||||
upload_data['parameters']) # weird array conversion only for upload, not for tooltips.
|
||||
|
||||
binary_path = bpy.app.binary_path
|
||||
|
@ -783,7 +761,10 @@ class UploadOperator(Operator):
|
|||
|
||||
if props.is_private == 'PUBLIC':
|
||||
ui_panels.label_multiline(layout, text='public assets are validated several hours'
|
||||
' or days after upload. ', width=300)
|
||||
' or days after upload. Remember always to '
|
||||
'test download your asset to a clean file'
|
||||
' to see if it uploaded correctly.'
|
||||
, width=300)
|
||||
|
||||
def invoke(self, context, event):
|
||||
props = utils.get_upload_props()
|
||||
|
|
|
@ -87,8 +87,8 @@ def upload_file(upload_data, f):
|
|||
upload_create_url = paths.get_api_url() + 'uploads/'
|
||||
upload = rerequests.post(upload_create_url, json=upload_info, headers=headers, verify=True)
|
||||
upload = upload.json()
|
||||
|
||||
chunk_size = 1024 * 256
|
||||
#
|
||||
chunk_size = 1024 * 1024 * 2
|
||||
utils.pprint(upload)
|
||||
# file gets uploaded here:
|
||||
uploaded = False
|
||||
|
@ -103,8 +103,10 @@ def upload_file(upload_data, f):
|
|||
if upload_response.status_code == 200:
|
||||
uploaded = True
|
||||
else:
|
||||
print(upload_response.text)
|
||||
bg_blender.progress(f'Upload failed, retry. {a}')
|
||||
except Exception as e:
|
||||
print(e)
|
||||
bg_blender.progress('Upload %s failed, retrying' % f['type'])
|
||||
time.sleep(1)
|
||||
|
||||
|
|
|
@ -514,4 +514,33 @@ def name_update():
|
|||
fname = fname.replace('\'', '')
|
||||
fname = fname.replace('\"', '')
|
||||
asset = get_active_asset()
|
||||
asset.name = fname
|
||||
asset.name = fname
|
||||
|
||||
def params_to_dict(params):
|
||||
params_dict = {}
|
||||
for p in params:
|
||||
params_dict[p['parameterType']] = p['value']
|
||||
return params_dict
|
||||
|
||||
def dict_to_params(inputs, parameters=None):
|
||||
if parameters == None:
|
||||
parameters = []
|
||||
for k in inputs.keys():
|
||||
if type(inputs[k]) == list:
|
||||
strlist = ""
|
||||
for idx, s in enumerate(inputs[k]):
|
||||
strlist += s
|
||||
if idx < len(inputs[k]) - 1:
|
||||
strlist += ','
|
||||
|
||||
value = "%s" % strlist
|
||||
elif type(inputs[k]) != bool:
|
||||
value = inputs[k]
|
||||
else:
|
||||
value = str(inputs[k])
|
||||
parameters.append(
|
||||
{
|
||||
"parameterType": k,
|
||||
"value": value
|
||||
})
|
||||
return parameters
|
||||
|
|
Loading…
Reference in New Issue