Merge branch 'master' into xr-actions-D9124
This commit is contained in:
commit
41d2d208a0
|
@ -254,7 +254,7 @@ def udate_down_up(self, context):
|
|||
s = context.scene
|
||||
wm = bpy.context.window_manager
|
||||
props = s.blenderkitUI
|
||||
if wm['search results'] == None and props.down_up == 'SEARCH':
|
||||
if wm.get('search results') == None and props.down_up == 'SEARCH':
|
||||
search.search()
|
||||
|
||||
def switch_search_results(self, context):
|
||||
|
@ -574,7 +574,7 @@ class BlenderKitCommonSearchProps(object):
|
|||
def name_update(self, context):
|
||||
''' checks for name change, because it decides if whole asset has to be re-uploaded. Name is stored in the blend file
|
||||
and that's the reason.'''
|
||||
utils.name_update()
|
||||
utils.name_update(self)
|
||||
|
||||
|
||||
|
||||
|
@ -650,12 +650,12 @@ class BlenderKitCommonUploadProps(object):
|
|||
('PUBLIC', 'Public', '"Your asset will go into the validation process automatically')
|
||||
),
|
||||
description="If not marked private, your asset will go into the validation process automatically\n"
|
||||
"Private assets are limited by quota.",
|
||||
"Private assets are limited by quota",
|
||||
default="PUBLIC",
|
||||
)
|
||||
|
||||
is_procedural: BoolProperty(name="Procedural",
|
||||
description="Asset is procedural - has no texture.",
|
||||
description="Asset is procedural - has no texture",
|
||||
default=True
|
||||
)
|
||||
node_count: IntProperty(name="Node count", description="Total nodes in the asset", default=0)
|
||||
|
@ -664,7 +664,7 @@ class BlenderKitCommonUploadProps(object):
|
|||
|
||||
# is_private: BoolProperty(name="Asset is Private",
|
||||
# description="If not marked private, your asset will go into the validation process automatically\n"
|
||||
# "Private assets are limited by quota.",
|
||||
# "Private assets are limited by quota",
|
||||
# default=False)
|
||||
|
||||
is_free: BoolProperty(name="Free for Everyone",
|
||||
|
@ -870,7 +870,7 @@ class BlenderKitMaterialUploadProps(PropertyGroup, BlenderKitCommonUploadProps):
|
|||
thumbnail_resolution: EnumProperty(
|
||||
name="Resolution",
|
||||
items=thumbnail_resolutions,
|
||||
description="Thumbnail resolution.",
|
||||
description="Thumbnail resolution",
|
||||
default="512",
|
||||
)
|
||||
|
||||
|
@ -1055,7 +1055,7 @@ class BlenderKitModelUploadProps(PropertyGroup, BlenderKitCommonUploadProps):
|
|||
thumbnail_resolution: EnumProperty(
|
||||
name="Resolution",
|
||||
items=thumbnail_resolutions,
|
||||
description="Thumbnail resolution.",
|
||||
description="Thumbnail resolution",
|
||||
default="512",
|
||||
)
|
||||
|
||||
|
@ -1402,7 +1402,7 @@ class BlenderKitModelSearchProps(PropertyGroup, BlenderKitCommonSearchProps):
|
|||
),
|
||||
description="Appended objects are editable in your scene. Linked assets are saved in original files, "
|
||||
"aren't editable but also don't increase your file size",
|
||||
default="LINK_COLLECTION"
|
||||
default="APPEND_OBJECTS"
|
||||
)
|
||||
append_link: EnumProperty(
|
||||
name="How to Attach",
|
||||
|
@ -1446,11 +1446,11 @@ class BlenderKitModelSearchProps(PropertyGroup, BlenderKitCommonSearchProps):
|
|||
subtype='ANGLE')
|
||||
|
||||
perpendicular_snap: BoolProperty(name='Perpendicular snap',
|
||||
description="Limit snapping that is close to perpendicular angles to be perpendicular.",
|
||||
description="Limit snapping that is close to perpendicular angles to be perpendicular",
|
||||
default=True)
|
||||
|
||||
perpendicular_snap_threshold: FloatProperty(name="Threshold",
|
||||
description="Limit perpendicular snap to be below these values.",
|
||||
description="Limit perpendicular snap to be below these values",
|
||||
default=.25,
|
||||
min=0,
|
||||
max=.5,
|
||||
|
@ -1498,7 +1498,19 @@ class BlenderKitSceneSearchProps(PropertyGroup, BlenderKitCommonSearchProps):
|
|||
default="",
|
||||
update=search.search_update
|
||||
)
|
||||
|
||||
append_link: EnumProperty(
|
||||
name="Append or link",
|
||||
items=(
|
||||
('LINK', 'Link', ''),
|
||||
('APPEND', 'Append', ''),
|
||||
),
|
||||
description="choose if the scene will be linked or appended",
|
||||
default="APPEND"
|
||||
)
|
||||
switch_after_append: BoolProperty(
|
||||
name = 'Switch to scene after download',
|
||||
default = False
|
||||
)
|
||||
|
||||
def fix_subdir(self, context):
|
||||
'''Fixes project subdicrectory settings if people input invalid path.'''
|
||||
|
@ -1538,7 +1550,7 @@ class BlenderKitAddonPreferences(AddonPreferences):
|
|||
|
||||
api_key_refresh: StringProperty(
|
||||
name="BlenderKit refresh API Key",
|
||||
description="API key used to refresh the token regularly.",
|
||||
description="API key used to refresh the token regularly",
|
||||
default="",
|
||||
subtype="PASSWORD",
|
||||
)
|
||||
|
@ -1557,7 +1569,7 @@ class BlenderKitAddonPreferences(AddonPreferences):
|
|||
|
||||
refresh_in_progress: BoolProperty(
|
||||
name="Api key refresh in progress",
|
||||
description="Api key is currently being refreshed. Don't refresh it again.",
|
||||
description="Api key is currently being refreshed. Don't refresh it again",
|
||||
default=False
|
||||
)
|
||||
|
||||
|
@ -1664,7 +1676,7 @@ class BlenderKitAddonPreferences(AddonPreferences):
|
|||
|
||||
use_timers: BoolProperty(
|
||||
name="Use timers",
|
||||
description="Use timers for BlenderKit. Usefull for debugging since timers seem to be unstable.",
|
||||
description="Use timers for BlenderKit. Usefull for debugging since timers seem to be unstable",
|
||||
default=True,
|
||||
update=utils.save_prefs
|
||||
)
|
||||
|
|
|
@ -87,6 +87,11 @@ def append_scene(file_name, scenename=None, link=False, fake_user=False):
|
|||
scene.use_fake_user = True
|
||||
# scene has to have a new uuid, so user reports aren't screwed.
|
||||
scene['uuid'] = str(uuid.uuid4())
|
||||
|
||||
#reset ui_props of the scene to defaults:
|
||||
ui_props = bpy.context.scene.blenderkitUI
|
||||
ui_props.down_up = 'SEARCH'
|
||||
|
||||
return scene
|
||||
|
||||
|
||||
|
|
|
@ -367,7 +367,7 @@ def get_autotags():
|
|||
|
||||
|
||||
class AutoFillTags(bpy.types.Operator):
|
||||
"""Fill tags for asset. Now run before upload, no need to interact from user side."""
|
||||
"""Fill tags for asset. Now run before upload, no need to interact from user side"""
|
||||
bl_idname = "object.blenderkit_auto_tags"
|
||||
bl_label = "Generate Auto Tags for BlenderKit"
|
||||
bl_options = {'REGISTER', 'UNDO', 'INTERNAL'}
|
||||
|
|
|
@ -153,7 +153,7 @@ class Logout(bpy.types.Operator):
|
|||
|
||||
|
||||
class CancelLoginOnline(bpy.types.Operator):
|
||||
"""Cancel login attempt."""
|
||||
"""Cancel login attempt"""
|
||||
|
||||
bl_idname = "wm.blenderkit_login_cancel"
|
||||
bl_label = "BlenderKit login cancel"
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -26,6 +26,7 @@ import shutil, sys, os
|
|||
import uuid
|
||||
import copy
|
||||
import logging
|
||||
|
||||
bk_logger = logging.getLogger('blenderkit')
|
||||
|
||||
import bpy
|
||||
|
@ -303,8 +304,7 @@ def append_asset(asset_data, **kwargs): # downloaders=[], location=None,
|
|||
#####
|
||||
# how to do particle drop:
|
||||
# link the group we are interested in( there are more groups in File!!!! , have to get the correct one!)
|
||||
#
|
||||
scene = bpy.context.scene
|
||||
s = bpy.context.scene
|
||||
|
||||
user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
|
||||
|
||||
|
@ -312,16 +312,22 @@ def append_asset(asset_data, **kwargs): # downloaders=[], location=None,
|
|||
user_preferences.asset_counter += 1
|
||||
|
||||
if asset_data['assetType'] == 'scene':
|
||||
scene = append_link.append_scene(file_names[0], link=False, fake_user=False)
|
||||
props = scene.blenderkit
|
||||
asset_main = scene
|
||||
sprops = s.blenderkit_scene
|
||||
|
||||
scene = append_link.append_scene(file_names[0], link=sprops.append_link == 'LINK', fake_user=False)
|
||||
print('scene appended')
|
||||
if scene is not None:
|
||||
props = scene.blenderkit
|
||||
asset_main = scene
|
||||
print(sprops.switch_after_append)
|
||||
if sprops.switch_after_append:
|
||||
bpy.context.window_manager.windows[0].scene = scene
|
||||
|
||||
if asset_data['assetType'] == 'hdr':
|
||||
hdr = append_link.load_HDR(file_name = file_names[0], name = asset_data['name'])
|
||||
hdr = append_link.load_HDR(file_name=file_names[0], name=asset_data['name'])
|
||||
props = hdr.blenderkit
|
||||
asset_main = hdr
|
||||
|
||||
s = bpy.context.scene
|
||||
|
||||
if asset_data['assetType'] == 'model':
|
||||
downloaders = kwargs.get('downloaders')
|
||||
|
@ -899,7 +905,7 @@ def check_existing(asset_data, resolution='blend', can_return_others=False):
|
|||
|
||||
file_names = paths.get_download_filepaths(asset_data, resolution, can_return_others=can_return_others)
|
||||
|
||||
bk_logger.debug('check if file already exists'+ str( file_names))
|
||||
bk_logger.debug('check if file already exists' + str(file_names))
|
||||
if len(file_names) == 2:
|
||||
# TODO this should check also for failed or running downloads.
|
||||
# If download is running, assign just the running thread. if download isn't running but the file is wrong size,
|
||||
|
@ -1147,7 +1153,7 @@ def start_download(asset_data, **kwargs):
|
|||
# check if there are files already. This check happens 2x once here(for free assets),
|
||||
# once in thread(for non-free)
|
||||
fexists = check_existing(asset_data, resolution=kwargs['resolution'])
|
||||
bk_logger.debug('does file exist?'+ str( fexists))
|
||||
bk_logger.debug('does file exist?' + str(fexists))
|
||||
bk_logger.debug('asset is in scene' + str(ain))
|
||||
if ain and not kwargs.get('replace_resolution'):
|
||||
# this goes to appending asset - where it should duplicate the original asset already in scene.
|
||||
|
@ -1220,7 +1226,7 @@ def show_enum_values(obj, prop_name):
|
|||
|
||||
|
||||
class BlenderkitDownloadOperator(bpy.types.Operator):
|
||||
"""Download and link asset to scene. Only link if asset already available locally."""
|
||||
"""Download and link asset to scene. Only link if asset already available locally"""
|
||||
bl_idname = "scene.blenderkit_download"
|
||||
bl_label = "BlenderKit Asset Download"
|
||||
bl_options = {'REGISTER', 'UNDO', 'INTERNAL'}
|
||||
|
@ -1235,7 +1241,7 @@ class BlenderkitDownloadOperator(bpy.types.Operator):
|
|||
|
||||
asset_base_id: StringProperty(
|
||||
name="Asset base Id",
|
||||
description="Asset base id, used instead of search result index.",
|
||||
description="Asset base id, used instead of search result index",
|
||||
default="")
|
||||
|
||||
target_object: StringProperty(
|
||||
|
|
|
@ -54,6 +54,17 @@ def img_save_as(img, filepath='//', file_format='JPEG', quality=90, color_mode='
|
|||
|
||||
set_orig_render_settings(ors)
|
||||
|
||||
def set_colorspace(img, colorspace):
|
||||
'''sets image colorspace, but does so in a try statement, because some people might actually replace the default
|
||||
colorspace settings, and it literally can't be guessed what these people use, even if it will mostly be the filmic addon.
|
||||
'''
|
||||
try:
|
||||
if colorspace == 'Non-Color':
|
||||
img.colorspace_settings.is_data = True
|
||||
else:
|
||||
img.colorspace_settings.name = colorspace
|
||||
except:
|
||||
print(f'Colorspace {colorspace} not found.')
|
||||
|
||||
def generate_hdr_thumbnail():
|
||||
scene = bpy.context.scene
|
||||
|
@ -79,7 +90,7 @@ def generate_hdr_thumbnail():
|
|||
hdr_image.pixels.foreach_get(tempBuffer)
|
||||
|
||||
inew.filepath = thumb_path
|
||||
inew.colorspace_settings.name = 'Linear'
|
||||
set_colorspace(inew, 'Linear')
|
||||
inew.pixels.foreach_set(tempBuffer)
|
||||
|
||||
bpy.context.view_layer.update()
|
||||
|
|
|
@ -171,7 +171,7 @@ def ensure_eevee_transparency(m):
|
|||
|
||||
|
||||
class BringToScene(Operator):
|
||||
"""Bring linked object hierarchy to scene and make it editable."""
|
||||
"""Bring linked object hierarchy to scene and make it editable"""
|
||||
|
||||
bl_idname = "object.blenderkit_bring_to_scene"
|
||||
bl_label = "BlenderKit bring objects to scene"
|
||||
|
|
|
@ -135,7 +135,7 @@ def update_ratings_work_hours(self, context):
|
|||
bkit_ratings = self
|
||||
url = paths.get_api_url() + f'assets/{self.asset_id}/rating/'
|
||||
|
||||
if bkit_ratings.rating_work_hours > 0.05:
|
||||
if bkit_ratings.rating_work_hours > 0.45:
|
||||
ratings = [('working_hours', round(bkit_ratings.rating_work_hours, 1))]
|
||||
tasks_queue.add_task((send_rating_to_thread_work_hours, (url, ratings, headers)), wait=2.5, only_last=True)
|
||||
|
||||
|
@ -295,9 +295,9 @@ def update_ratings_work_hours_ui_1_5(self, context):
|
|||
|
||||
|
||||
class FastRateMenu(Operator):
|
||||
"""Fast rating of the assets directly in the asset bar - without need to download assets."""
|
||||
"""Fast rating of the assets directly in the asset bar - without need to download assets"""
|
||||
bl_idname = "wm.blenderkit_menu_rating_upload"
|
||||
bl_label = "Send Rating"
|
||||
bl_label = "Rate asset"
|
||||
bl_options = {'REGISTER', 'UNDO', 'INTERNAL'}
|
||||
|
||||
message: StringProperty(
|
||||
|
@ -337,9 +337,11 @@ class FastRateMenu(Operator):
|
|||
rating_work_hours: FloatProperty(name="Work Hours",
|
||||
description="How many hours did this work take?",
|
||||
default=0.00,
|
||||
min=0.0, max=150, update=update_ratings_work_hours
|
||||
min=0.0, max=300, update=update_ratings_work_hours
|
||||
)
|
||||
|
||||
high_rating_warning = "This is a high rating, please be sure to give such rating only to amazing assets"
|
||||
|
||||
rating_work_hours_ui: EnumProperty(name="Work Hours",
|
||||
description="How many hours did this work take?",
|
||||
items=[('0', '0', ''),
|
||||
|
@ -354,11 +356,12 @@ class FastRateMenu(Operator):
|
|||
('10', '10', ''),
|
||||
('15', '15', ''),
|
||||
('20', '20', ''),
|
||||
('50', '50', ''),
|
||||
('100', '100', ''),
|
||||
('150', '150', ''),
|
||||
('200', '200', ''),
|
||||
('250', '250', ''),
|
||||
('30', '30', high_rating_warning),
|
||||
('50', '50', high_rating_warning),
|
||||
('100', '100', high_rating_warning),
|
||||
('150', '150', high_rating_warning),
|
||||
('200', '200', high_rating_warning),
|
||||
('250', '250', high_rating_warning),
|
||||
],
|
||||
default='0', update=update_ratings_work_hours_ui
|
||||
)
|
||||
|
@ -391,14 +394,34 @@ class FastRateMenu(Operator):
|
|||
col.label(text=self.message)
|
||||
row = col.row()
|
||||
row.prop(self, 'rating_quality_ui', expand=True, icon_only=True, emboss=False)
|
||||
# row.label(text=str(self.rating_quality))
|
||||
col.separator()
|
||||
col.prop(self, 'rating_work_hours')
|
||||
if utils.profile_is_validator():
|
||||
|
||||
row = layout.row()
|
||||
row.label(text=f"How many hours did this {self.asset_type} save you?")
|
||||
|
||||
if self.asset_type in ('model', 'scene'):
|
||||
row = layout.row()
|
||||
if self.asset_type == 'model':
|
||||
row.prop(self, 'rating_work_hours_ui', expand=True, icon_only=False, emboss=True)
|
||||
else:
|
||||
row.prop(self, 'rating_work_hours_ui_1_5', expand=True, icon_only=False, emboss=True)
|
||||
if utils.profile_is_validator():
|
||||
col.prop(self, 'rating_work_hours')
|
||||
row.prop(self, 'rating_work_hours_ui', expand=True, icon_only=False, emboss=True)
|
||||
if float(self.rating_work_hours_ui) > 100:
|
||||
utils.label_multiline(layout,
|
||||
text=f"\nThat's huge! please be sure to give such rating only to godly {self.asset_type}s.\n",
|
||||
width=500)
|
||||
elif float(self.rating_work_hours_ui) > 18:
|
||||
layout.separator()
|
||||
|
||||
utils.label_multiline(layout,
|
||||
text=f"\nThat's a lot! please be sure to give such rating only to amazing {self.asset_type}s.\n",
|
||||
width=500)
|
||||
|
||||
else:
|
||||
|
||||
|
||||
row = layout.row()
|
||||
row.prop(self, 'rating_work_hours_ui_1_5', expand=True, icon_only=False, emboss=True)
|
||||
|
||||
|
||||
def execute(self, context):
|
||||
user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
|
||||
|
@ -414,13 +437,13 @@ class FastRateMenu(Operator):
|
|||
if self.rating_quality_ui == '':
|
||||
self.rating_quality = 0
|
||||
else:
|
||||
self.rating_quality = int(self.rating_quality_ui)
|
||||
self.rating_quality = float(self.rating_quality_ui)
|
||||
|
||||
if self.rating_quality > 0.1:
|
||||
rtgs = (('quality', self.rating_quality),)
|
||||
tasks_queue.add_task((send_rating_to_thread_quality, (url, rtgs, headers)), wait=2.5, only_last=True)
|
||||
|
||||
if self.rating_work_hours > 0.1:
|
||||
if self.rating_work_hours > 0.45:
|
||||
rtgs = (('working_hours', round(self.rating_work_hours, 1)),)
|
||||
tasks_queue.add_task((send_rating_to_thread_work_hours, (url, rtgs, headers)), wait=2.5, only_last=True)
|
||||
return {'FINISHED'}
|
||||
|
@ -437,7 +460,7 @@ class FastRateMenu(Operator):
|
|||
self.message = f"Rate asset {self.asset_name}"
|
||||
wm = context.window_manager
|
||||
|
||||
if utils.profile_is_validator() and self.asset_type == 'model':
|
||||
if self.asset_type in ('model','scene'):
|
||||
# spawn a wider one for validators for the enum buttons
|
||||
return wm.invoke_props_dialog(self, width=500)
|
||||
else:
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
from blenderkit import paths, utils, categories, ui, colors, bkit_oauth, version_checker, tasks_queue, rerequests, \
|
||||
resolutions
|
||||
resolutions, image_utils
|
||||
|
||||
import blenderkit
|
||||
from bpy.app.handlers import persistent
|
||||
|
@ -474,9 +474,9 @@ def load_previews():
|
|||
img.reload()
|
||||
if r['assetType'] == 'hdr':
|
||||
# to display hdr thumbnails correctly, we use non-color, otherwise looks shifted
|
||||
img.colorspace_settings.name = 'Non-Color'
|
||||
image_utils.set_colorspace(img, 'Non-Color')
|
||||
else:
|
||||
img.colorspace_settings.name = 'sRGB'
|
||||
image_utils.set_colorspace(img, 'sRGB')
|
||||
|
||||
i += 1
|
||||
# print('previews loaded')
|
||||
|
@ -660,6 +660,7 @@ def generate_tooltip(mdata):
|
|||
if f['fileType'].find('resolution') > -1:
|
||||
t += 'Asset has lower resolutions available\n'
|
||||
break;
|
||||
|
||||
# generator is for both upload preview and search, this is only after search
|
||||
# if mdata.get('versionNumber'):
|
||||
# # t = writeblockm(t, mdata, key='versionNumber', pretext='version', width = col_w)
|
||||
|
@ -671,22 +672,27 @@ def generate_tooltip(mdata):
|
|||
|
||||
# t += '\n'
|
||||
rc = mdata.get('ratingsCount')
|
||||
if utils.profile_is_validator() and rc:
|
||||
|
||||
if rc:
|
||||
t+='\n'
|
||||
if rc:
|
||||
rcount = min(rc['quality'], rc['workingHours'])
|
||||
else:
|
||||
rcount = 0
|
||||
if rcount < 10:
|
||||
t += f"Please rate this asset, \nit doesn't have enough ratings.\n"
|
||||
else:
|
||||
t += f"Quality rating: {int(mdata['ratingsAverage']['quality']) * '*'}\n"
|
||||
t += f"Hours saved rating: {int(mdata['ratingsAverage']['workingHours'])}\n"
|
||||
|
||||
show_rating_threshold = 5
|
||||
|
||||
if rcount < show_rating_threshold:
|
||||
t += f"Only assets with enough ratings \nshow the rating value. Please rate.\n"
|
||||
if rc['quality'] >= show_rating_threshold:
|
||||
# t += f"{int(mdata['ratingsAverage']['quality']) * '*'}\n"
|
||||
t += f"* {round(mdata['ratingsAverage']['quality'],1)}\n"
|
||||
if rc['workingHours'] >= show_rating_threshold:
|
||||
t += f"Hours saved: {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"
|
||||
f"{(mdata['ratingsAverage']['quality'],1)}*/{(mdata['ratingsAverage']['workingHours'],1)}wh\n"
|
||||
if len(t.split('\n')) < 11:
|
||||
t += '\n'
|
||||
t += get_random_tip(mdata)
|
||||
|
|
|
@ -338,7 +338,7 @@ def draw_tooltip(x, y, text='', author='', img=None, gravatar=None):
|
|||
textcol = (textcol[0], textcol[1], textcol[2], 1)
|
||||
textcol_mild = (textcol[0] * .8, textcol[1] * .8, textcol[2] * .8, 1)
|
||||
textcol_strong = (textcol[0] * 1.3, textcol[1] * 2.3, textcol[2] * 1.3, 1)
|
||||
textcol_strong = (0.4, 1, 0.3, 1)
|
||||
# textcol_strong = (0.4, 1, 0.3, 1)
|
||||
white = (1, 1, 1, .1)
|
||||
|
||||
# background
|
||||
|
@ -1672,6 +1672,12 @@ class AssetBarOperator(bpy.types.Operator):
|
|||
target_slot = temp_mesh.polygons[face_index].material_index
|
||||
object_eval.to_mesh_clear()
|
||||
else:
|
||||
if object.is_library_indirect:
|
||||
ui_panels.ui_message(title='This object is linked from outer file',
|
||||
message="Please select the model,"
|
||||
"go to the 'Selected Model' panel "
|
||||
"in BlenderKit and hit 'Bring to Scene' first.")
|
||||
|
||||
self.report({'WARNING'}, "Invalid or library object as input:")
|
||||
target_object = ''
|
||||
target_slot = ''
|
||||
|
@ -1854,7 +1860,7 @@ class TransferBlenderkitData(bpy.types.Operator):
|
|||
"""Regenerate cobweb"""
|
||||
bl_idname = "object.blenderkit_data_trasnfer"
|
||||
bl_label = "Transfer BlenderKit data"
|
||||
bl_description = "Transfer blenderKit metadata from one object to another when fixing uploads with wrong parenting."
|
||||
bl_description = "Transfer blenderKit metadata from one object to another when fixing uploads with wrong parenting"
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
|
||||
def execute(self, context):
|
||||
|
@ -1914,6 +1920,12 @@ def draw_callback_3d_dragging(self, context):
|
|||
if self.has_hit:
|
||||
draw_bbox(self.snapped_location, self.snapped_rotation, self.snapped_bbox_min, self.snapped_bbox_max)
|
||||
|
||||
def find_and_activate_instancers(object):
|
||||
for ob in bpy.context.visible_objects:
|
||||
if ob.instance_type == 'COLLECTION' and ob.instance_collection and object.name in ob.instance_collection.objects:
|
||||
utils.activate(ob)
|
||||
return ob
|
||||
|
||||
|
||||
class AssetDragOperator(bpy.types.Operator):
|
||||
"""Draw a line with the mouse"""
|
||||
|
@ -1942,6 +1954,11 @@ class AssetDragOperator(bpy.types.Operator):
|
|||
if ui_props.asset_type == 'MATERIAL':
|
||||
# first, test if object can have material applied.
|
||||
object = bpy.data.objects[self.object_name]
|
||||
# this enables to run Bring to scene automatically when dropping on a linked objects.
|
||||
# it's however quite a slow operation, that's why not enabled (and finished) now.
|
||||
# if object is not None and object.is_library_indirect:
|
||||
# find_and_activate_instancers(object)
|
||||
# bpy.ops.object.blenderkit_bring_to_scene()
|
||||
if object is not None and not object.is_library_indirect and object.type == 'MESH':
|
||||
target_object = object.name
|
||||
# create final mesh to extract correct material slot
|
||||
|
@ -1953,6 +1970,12 @@ class AssetDragOperator(bpy.types.Operator):
|
|||
# elif object.is_library_indirect:#case for bring to scene objects, will be solved through prefs and direct
|
||||
# action
|
||||
else:
|
||||
if object.is_library_indirect:
|
||||
ui_panels.ui_message(title = 'This object is linked from outer file',
|
||||
message = "Please select the model,"
|
||||
"go to the 'Selected Model' panel "
|
||||
"in BlenderKit and hit 'Bring to Scene' first.")
|
||||
|
||||
self.report({'WARNING'}, "Invalid or library object as input:")
|
||||
target_object = ''
|
||||
target_slot = ''
|
||||
|
@ -2007,6 +2030,11 @@ class AssetDragOperator(bpy.types.Operator):
|
|||
target_object=target_object)
|
||||
|
||||
else:
|
||||
if ui_props.asset_type =='SCENE':
|
||||
ui_panels.ui_message(title = 'Scene will be appended after download',
|
||||
message = 'After the scene is appended, you have to switch to it manually.'
|
||||
'If you want to switch to scenes automatically after appending,'
|
||||
' you can set it in import settings.')
|
||||
bpy.ops.scene.blenderkit_download( # asset_type=ui_props.asset_type,
|
||||
asset_index=self.asset_search_index)
|
||||
|
||||
|
|
|
@ -112,7 +112,7 @@ def draw_upload_common(layout, props, asset_type, context):
|
|||
op = layout.operator("object.blenderkit_upload", text=optext, icon='EXPORT')
|
||||
op.asset_type = asset_type
|
||||
op.reupload = False
|
||||
#make sure everything gets uploaded.
|
||||
# make sure everything gets uploaded.
|
||||
op.main_file = True
|
||||
op.metadata = True
|
||||
op.thumbnail = True
|
||||
|
@ -163,6 +163,7 @@ def prop_needed(layout, props, name, value, is_not_filled=''):
|
|||
icon = None
|
||||
row.prop(props, name)
|
||||
|
||||
|
||||
def draw_panel_hdr_upload(self, context):
|
||||
layout = self.layout
|
||||
ui_props = bpy.context.scene.blenderkitUI
|
||||
|
@ -172,7 +173,6 @@ def draw_panel_hdr_upload(self, context):
|
|||
|
||||
hdr = utils.get_active_HDR()
|
||||
|
||||
|
||||
if hdr is not None:
|
||||
props = hdr.blenderkit
|
||||
|
||||
|
@ -184,6 +184,7 @@ def draw_panel_hdr_upload(self, context):
|
|||
layout.prop(props, 'description')
|
||||
layout.prop(props, 'tags')
|
||||
|
||||
|
||||
def draw_panel_hdr_search(self, context):
|
||||
s = context.scene
|
||||
props = s.blenderkit_HDR
|
||||
|
@ -196,6 +197,7 @@ def draw_panel_hdr_search(self, context):
|
|||
|
||||
utils.label_multiline(layout, text=props.report)
|
||||
|
||||
|
||||
def draw_panel_model_upload(self, context):
|
||||
ob = bpy.context.active_object
|
||||
while ob.parent is not None:
|
||||
|
@ -316,7 +318,7 @@ def draw_assetbar_show_hide(layout, props):
|
|||
|
||||
preferences = bpy.context.preferences.addons['blenderkit'].preferences
|
||||
if preferences.experimental_features:
|
||||
op = layout.operator('view3d.blenderkit_asset_bar_widget', text = '', icon = icon)
|
||||
op = layout.operator('view3d.blenderkit_asset_bar_widget', text='', icon=icon)
|
||||
op.keep_running = False
|
||||
op.do_search = False
|
||||
op.tooltip = ttip
|
||||
|
@ -407,8 +409,8 @@ class VIEW3D_PT_blenderkit_model_properties(Panel):
|
|||
layout.label(text=str(ad['name']))
|
||||
if o.instance_type == 'COLLECTION' and o.instance_collection is not None:
|
||||
layout.operator('object.blenderkit_bring_to_scene', text='Bring to scene')
|
||||
layout.label(text='Ratings:')
|
||||
draw_panel_model_rating(self, context)
|
||||
# layout.label(text='Ratings:')
|
||||
# draw_panel_model_rating(self, context)
|
||||
|
||||
layout.label(text='Asset tools:')
|
||||
draw_asset_context_menu(self.layout, context, ad, from_panel=True)
|
||||
|
@ -510,7 +512,7 @@ class VIEW3D_PT_blenderkit_ratings(Panel):
|
|||
utils.label_multiline(layout, text='Please help BlenderKit community by rating these assets:')
|
||||
|
||||
for a in assets:
|
||||
if a.bkit_ratings.rating_work_hours==0:
|
||||
if a.bkit_ratings.rating_work_hours == 0:
|
||||
draw_rating_asset(self, context, asset=a)
|
||||
|
||||
|
||||
|
@ -546,7 +548,7 @@ class VIEW3D_PT_blenderkit_profile(Panel):
|
|||
if me is not None:
|
||||
me = me['user']
|
||||
# user name
|
||||
if len(me['firstName'])>0 or len(me['lastName'])>0:
|
||||
if len(me['firstName']) > 0 or len(me['lastName']) > 0:
|
||||
layout.label(text=f"Me: {me['firstName']} {me['lastName']}")
|
||||
else:
|
||||
layout.label(text=f"Me: {me['email']}")
|
||||
|
@ -781,7 +783,6 @@ class VIEW3D_PT_blenderkit_advanced_model_search(Panel):
|
|||
layout.prop(props, "free_only")
|
||||
layout.prop(props, "search_style")
|
||||
|
||||
|
||||
# DESIGN YEAR
|
||||
layout.prop(props, "search_design_year", text='Designed in Year')
|
||||
if props.search_design_year:
|
||||
|
@ -897,7 +898,7 @@ class VIEW3D_PT_blenderkit_import_settings(Panel):
|
|||
def poll(cls, context):
|
||||
s = context.scene
|
||||
ui_props = s.blenderkitUI
|
||||
return ui_props.down_up == 'SEARCH' and ui_props.asset_type in ['MATERIAL', 'MODEL', 'HDR']
|
||||
return ui_props.down_up == 'SEARCH' and ui_props.asset_type in ['MATERIAL', 'MODEL', 'SCENE', 'HDR']
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
@ -926,10 +927,17 @@ class VIEW3D_PT_blenderkit_import_settings(Panel):
|
|||
row = layout.row()
|
||||
|
||||
row.prop(props, 'append_method', expand=True, icon_only=False)
|
||||
if ui_props.asset_type == 'SCENE':
|
||||
props = s.blenderkit_scene
|
||||
layout.prop(props, 'switch_after_append')
|
||||
layout.label(text='Import method:')
|
||||
row = layout.row()
|
||||
row.prop(props, 'append_link', expand=True, icon_only=False)
|
||||
if ui_props.asset_type == 'HDR':
|
||||
props = s.blenderkit_HDR
|
||||
|
||||
layout.prop(props, 'resolution')
|
||||
if ui_props.asset_type in ['MATERIAL', 'MODEL', 'HDR']:
|
||||
layout.prop(props, 'resolution')
|
||||
# layout.prop(props, 'unpack_files')
|
||||
|
||||
|
||||
|
@ -1060,32 +1068,6 @@ class VIEW3D_PT_blenderkit_unified(Panel):
|
|||
else:
|
||||
layout.label(text='Switch to paint or sculpt mode.')
|
||||
|
||||
elif ui_props.down_up == 'RATING': # the poll functions didn't work here, don't know why.
|
||||
|
||||
if ui_props.asset_type == 'MODEL':
|
||||
# TODO improve poll here to parenting structures
|
||||
if bpy.context.view_layer.objects.active is not None and bpy.context.active_object.get(
|
||||
'asset_data') != None:
|
||||
ad = bpy.context.active_object.get('asset_data')
|
||||
layout.label(text=ad['name'])
|
||||
draw_panel_model_rating(self, context)
|
||||
if ui_props.asset_type == 'MATERIAL':
|
||||
if bpy.context.view_layer.objects.active is not None and \
|
||||
bpy.context.active_object.active_material is not None and \
|
||||
bpy.context.active_object.active_material.blenderkit.asset_base_id != '':
|
||||
layout.label(text=bpy.context.active_object.active_material.blenderkit.name + ' :')
|
||||
# noinspection PyCallByClass
|
||||
draw_panel_material_ratings(self, context)
|
||||
if ui_props.asset_type == 'BRUSH':
|
||||
if context.sculpt_object or context.image_paint_object:
|
||||
props = utils.get_brush_props(context)
|
||||
if props.asset_base_id != '':
|
||||
layout.label(text=props.name + ' :')
|
||||
# noinspection PyCallByClass
|
||||
draw_panel_brush_ratings(self, context)
|
||||
if ui_props.asset_type == 'TEXTURE':
|
||||
layout.label(text='not yet implemented')
|
||||
|
||||
|
||||
class BlenderKitWelcomeOperator(bpy.types.Operator):
|
||||
"""Login online on BlenderKit webpage"""
|
||||
|
@ -1199,7 +1181,6 @@ def draw_asset_context_menu(layout, context, asset_data, from_panel=False):
|
|||
# if ui_props.asset_type in ('MODEL', 'MATERIAL'):
|
||||
# layout.menu(OBJECT_MT_blenderkit_resolution_menu.bl_idname)
|
||||
|
||||
|
||||
if ui_props.asset_type in ('MODEL', 'MATERIAL', 'HDR') and \
|
||||
utils.get_param(asset_data, 'textureResolutionMax') is not None and \
|
||||
utils.get_param(asset_data, 'textureResolutionMax') > 512:
|
||||
|
@ -1247,7 +1228,8 @@ def draw_asset_context_menu(layout, context, asset_data, from_panel=False):
|
|||
op.invoke_resolution = True
|
||||
o = utils.get_active_model()
|
||||
if o and o.get('asset_data'):
|
||||
if o['asset_data']['assetBaseId'] == bpy.context.window_manager['search results'][ui_props.active_index]:
|
||||
if o['asset_data']['assetBaseId'] == bpy.context.window_manager['search results'][
|
||||
ui_props.active_index]:
|
||||
op.model_location = o.location
|
||||
op.model_rotation = o.rotation_euler
|
||||
else:
|
||||
|
@ -1302,14 +1284,10 @@ def draw_asset_context_menu(layout, context, asset_data, from_panel=False):
|
|||
if utils.profile_is_validator():
|
||||
layout.label(text='Admin Tools:')
|
||||
|
||||
|
||||
op = layout.operator('object.blenderkit_print_asset_debug', text='Print asset debug')
|
||||
op.asset_id = asset_data['id']
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# def draw_asset_resolution_replace(self, context, resolution):
|
||||
# layout = self.layout
|
||||
# ui_props = bpy.context.scene.blenderkitUI
|
||||
|
@ -1392,12 +1370,13 @@ class OBJECT_MT_blenderkit_asset_menu(bpy.types.Menu):
|
|||
# box2.label(text='************')
|
||||
# box2.label(text='dadydadadada')
|
||||
|
||||
|
||||
class AssetPopupCard(bpy.types.Operator):
|
||||
"""Generate Cycles thumbnail for model assets"""
|
||||
bl_idname = "wm.blenderkit_asset_popup"
|
||||
bl_label = "BlenderKit asset popup"
|
||||
# bl_options = {'REGISTER', 'INTERNAL'}
|
||||
bl_options = {'REGISTER',}
|
||||
bl_options = {'REGISTER', }
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
|
@ -1418,11 +1397,10 @@ class AssetPopupCard(bpy.types.Operator):
|
|||
split = split.split(factor=0.5)
|
||||
col1 = split.column()
|
||||
box = col1.box()
|
||||
utils.label_multiline(box,asset_data['tooltip'], width = 300)
|
||||
utils.label_multiline(box, asset_data['tooltip'], width=300)
|
||||
|
||||
col2 = split.column()
|
||||
|
||||
|
||||
pcoll = icons.icon_collections["main"]
|
||||
my_icon = pcoll['test']
|
||||
col2.template_icon(icon_value=my_icon.icon_id, scale=20.0)
|
||||
|
@ -1430,7 +1408,7 @@ class AssetPopupCard(bpy.types.Operator):
|
|||
box2 = col2.box()
|
||||
|
||||
# draw_ratings(box2, context, asset_data)
|
||||
box2.label(text = 'Ratings')
|
||||
box2.label(text='Ratings')
|
||||
# print(tp, dir(tp))
|
||||
# if not hasattr(self, 'first_draw'):# try to redraw because of template preview which needs update
|
||||
# for region in context.area.regions:
|
||||
|
@ -1451,8 +1429,9 @@ class AssetPopupCard(bpy.types.Operator):
|
|||
# self.tex = utils.get_hidden_texture(self.img)
|
||||
# self.tex.update_tag()
|
||||
|
||||
bl_label = asset_data['name']
|
||||
return wm.invoke_props_dialog(self, width = 700)
|
||||
bl_label = asset_data['name']
|
||||
return wm.invoke_props_dialog(self, width=700)
|
||||
|
||||
|
||||
class OBJECT_MT_blenderkit_login_menu(bpy.types.Menu):
|
||||
bl_label = "BlenderKit login/signup:"
|
||||
|
@ -1523,14 +1502,14 @@ class UrlPopupDialog(bpy.types.Operator):
|
|||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
utils.label_multiline(layout, text=self.message, width = 300)
|
||||
utils.label_multiline(layout, text=self.message, width=300)
|
||||
|
||||
layout.active_default = True
|
||||
op = layout.operator("wm.url_open", text=self.link_text, icon='QUESTION')
|
||||
if not utils.user_logged_in():
|
||||
utils.label_multiline(layout,
|
||||
text='Already subscribed? You need to login to access your Full Plan.',
|
||||
width = 300)
|
||||
width=300)
|
||||
|
||||
layout.operator_context = 'EXEC_DEFAULT'
|
||||
layout.operator("wm.blenderkit_login", text="Login",
|
||||
|
@ -1544,7 +1523,7 @@ class UrlPopupDialog(bpy.types.Operator):
|
|||
def invoke(self, context, event):
|
||||
wm = context.window_manager
|
||||
|
||||
return wm.invoke_props_dialog(self,width = 300)
|
||||
return wm.invoke_props_dialog(self, width=300)
|
||||
|
||||
|
||||
class LoginPopupDialog(bpy.types.Operator):
|
||||
|
@ -1695,16 +1674,19 @@ def header_search_draw(self, context):
|
|||
# the center snap menu is in edit and object mode if tool settings are off.
|
||||
if context.space_data.show_region_tool_header == True or context.mode[:4] not in ('EDIT', 'OBJE'):
|
||||
layout.separator_spacer()
|
||||
layout.prop(ui_props, "asset_type", expand = True, icon_only = True, text='', icon='URL')
|
||||
layout.prop(ui_props, "asset_type", expand=True, icon_only=True, text='', icon='URL')
|
||||
layout.prop(props, "search_keywords", text="", icon='VIEWZOOM')
|
||||
draw_assetbar_show_hide(layout, props)
|
||||
|
||||
|
||||
def ui_message(title, message):
|
||||
def draw_message(self, context):
|
||||
layout = self.layout
|
||||
utils.label_multiline(layout, text=message)
|
||||
utils.label_multiline(layout, text=message, width=400)
|
||||
|
||||
bpy.context.window_manager.popup_menu(draw_message, title=title, icon='INFO')
|
||||
|
||||
|
||||
# We can store multiple preview collections here,
|
||||
# however in this example we only store "main"
|
||||
preview_collections = {}
|
||||
|
|
|
@ -467,7 +467,7 @@ def get_upload_data(caller=None, context=None, asset_type=None):
|
|||
add_version(upload_data)
|
||||
|
||||
# caller can be upload operator, but also asset bar called from tooltip generator
|
||||
if caller and caller.main_file == True:
|
||||
if caller and caller.properties.main_file == True:
|
||||
upload_data["name"] = props.name
|
||||
upload_data["displayName"] = props.name
|
||||
else:
|
||||
|
@ -536,6 +536,32 @@ def patch_individual_metadata(asset_id, metadata_dict, api_key):
|
|||
# op = layout.operator('wm.blenderkit_fast_metadata', text = ch['name'])
|
||||
|
||||
|
||||
def update_free_full(self, context):
|
||||
if self.asset_type == 'material':
|
||||
if self.free_full == 'FULL':
|
||||
self.free_full = '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 can_edit_asset(active_index = -1, asset_data = None):
|
||||
if active_index == -1 and not asset_data:
|
||||
return False
|
||||
profile = bpy.context.window_manager.get('bkit profile')
|
||||
if profile is None:
|
||||
return False
|
||||
if utils.profile_is_validator():
|
||||
return True
|
||||
if not asset_data:
|
||||
sr = bpy.context.window_manager['search results']
|
||||
asset_data = dict(sr[active_index])
|
||||
# print(profile, asset_data)
|
||||
if asset_data['author']['id'] == profile['user']['id']:
|
||||
return True
|
||||
return False
|
||||
|
||||
class FastMetadata(bpy.types.Operator):
|
||||
"""Fast change of the category of object directly in asset bar."""
|
||||
bl_idname = "wm.blenderkit_fast_metadata"
|
||||
|
@ -594,11 +620,22 @@ class FastMetadata(bpy.types.Operator):
|
|||
default="PUBLIC",
|
||||
)
|
||||
|
||||
free_full:EnumProperty(
|
||||
name="Free or Full Plan",
|
||||
items=(
|
||||
('FREE', 'Free', "You consent you want to release this asset as free for everyone"),
|
||||
('FULL', 'Full', 'Your asset will be in the full plan')
|
||||
),
|
||||
description="Choose whether the asset should be free or in the Full Plan",
|
||||
default="FULL",
|
||||
update=update_free_full
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
scene = bpy.context.scene
|
||||
ui_props = scene.blenderkitUI
|
||||
return ui_props.active_index > -1
|
||||
return can_edit_asset(active_index=ui_props.active_index)
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
@ -617,6 +654,7 @@ class FastMetadata(bpy.types.Operator):
|
|||
layout.prop(self, 'description')
|
||||
layout.prop(self, 'tags')
|
||||
layout.prop(self, 'is_private', expand=True)
|
||||
layout.prop(self, 'free_full', expand=True)
|
||||
if self.is_private == 'PUBLIC':
|
||||
layout.prop(self, 'license')
|
||||
|
||||
|
@ -639,6 +677,7 @@ class FastMetadata(bpy.types.Operator):
|
|||
'description': self.description,
|
||||
'tags': comma2array(self.tags),
|
||||
'isPrivate': self.is_private == 'PRIVATE',
|
||||
'isFree': self.free_full == 'FREE',
|
||||
'license': self.license,
|
||||
}
|
||||
|
||||
|
@ -661,6 +700,8 @@ class FastMetadata(bpy.types.Operator):
|
|||
if result['id'] == self.asset_id:
|
||||
asset_data = dict(result)
|
||||
|
||||
if not can_edit_asset(asset_data=asset_data):
|
||||
return {'CANCELLED'}
|
||||
self.asset_id = asset_data['id']
|
||||
self.asset_type = asset_data['assetType']
|
||||
cat_path = categories.get_category_path(bpy.context.window_manager['bkit_categories'],
|
||||
|
@ -680,6 +721,11 @@ class FastMetadata(bpy.types.Operator):
|
|||
self.is_private = 'PRIVATE'
|
||||
else:
|
||||
self.is_private = 'PUBLIC'
|
||||
|
||||
if asset_data['isFree']:
|
||||
self.free_full = 'FREE'
|
||||
else:
|
||||
self.free_full = 'FULL'
|
||||
self.license = asset_data['license']
|
||||
|
||||
wm = context.window_manager
|
||||
|
@ -940,6 +986,10 @@ class Uploader(threading.Thread):
|
|||
"file_path": fpath
|
||||
})
|
||||
|
||||
if not os.path.exists(fpath):
|
||||
self.send_message ("File packing failed, please try manual packing first")
|
||||
return {'CANCELLED'}
|
||||
|
||||
self.send_message('Uploading files')
|
||||
|
||||
uploaded = upload_bg.upload_files(self.upload_data, files)
|
||||
|
@ -994,9 +1044,10 @@ def start_upload(self, context, asset_type, reupload, upload_set):
|
|||
'''start upload process, by processing data, then start a thread that cares about the rest of the upload.'''
|
||||
|
||||
# fix the name first
|
||||
utils.name_update()
|
||||
|
||||
props = utils.get_upload_props()
|
||||
|
||||
utils.name_update(props)
|
||||
|
||||
storage_quota_ok = check_storage_quota(props)
|
||||
if not storage_quota_ok:
|
||||
self.report({'ERROR_INVALID_INPUT'}, props.report)
|
||||
|
@ -1022,8 +1073,7 @@ def start_upload(self, context, asset_type, reupload, upload_set):
|
|||
props.id = ''
|
||||
|
||||
export_data, upload_data = get_upload_data(caller=self, context=context, asset_type=asset_type)
|
||||
# print(export_data)
|
||||
# print(upload_data)
|
||||
|
||||
# check if thumbnail exists, generate for HDR:
|
||||
if 'THUMBNAIL' in upload_set:
|
||||
if asset_type == 'HDR':
|
||||
|
@ -1138,6 +1188,11 @@ class UploadOperator(Operator):
|
|||
if self.main_file:
|
||||
upload_set.append('MAINFILE')
|
||||
|
||||
#this is accessed later in get_upload_data and needs to be written.
|
||||
# should pass upload_set all the way to it probably
|
||||
if 'MAINFILE' in upload_set:
|
||||
self.main_file = True
|
||||
|
||||
result = start_upload(self, context, self.asset_type, self.reupload, upload_set=upload_set, )
|
||||
|
||||
return {'FINISHED'}
|
||||
|
@ -1215,6 +1270,8 @@ class AssetDebugPrint(Operator):
|
|||
if ad:
|
||||
result = ad.to_dict()
|
||||
if result:
|
||||
t = bpy.data.texts.new(result['name'])
|
||||
t.write(json.dumps(result, indent=4, sort_keys=True))
|
||||
print(json.dumps(result, indent=4, sort_keys=True))
|
||||
return {'FINISHED'}
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
|
||||
from blenderkit import paths, rerequests
|
||||
from blenderkit import paths, rerequests, image_utils
|
||||
|
||||
import bpy
|
||||
from mathutils import Vector
|
||||
|
@ -43,6 +43,7 @@ def experimental_enabled():
|
|||
preferences = bpy.context.preferences.addons['blenderkit'].preferences
|
||||
return preferences.experimental_features
|
||||
|
||||
|
||||
def get_process_flags():
|
||||
flags = BELOW_NORMAL_PRIORITY_CLASS
|
||||
if sys.platform != 'win32': # TODO test this on windows
|
||||
|
@ -215,7 +216,7 @@ def get_upload_props():
|
|||
return s.blenderkit
|
||||
if ui_props.asset_type == 'HDR':
|
||||
|
||||
hdr = ui_props.hdr_upload_image#bpy.data.images.get(ui_props.hdr_upload_image)
|
||||
hdr = ui_props.hdr_upload_image # bpy.data.images.get(ui_props.hdr_upload_image)
|
||||
if not hdr:
|
||||
return None
|
||||
return hdr.blenderkit
|
||||
|
@ -254,7 +255,7 @@ def load_prefs():
|
|||
fpath = paths.BLENDERKIT_SETTINGS_FILENAME
|
||||
if os.path.exists(fpath):
|
||||
try:
|
||||
with open(fpath, 'r', encoding = 'utf-8') as s:
|
||||
with open(fpath, 'r', encoding='utf-8') as s:
|
||||
prefs = json.load(s)
|
||||
user_preferences.api_key = prefs.get('API_key', '')
|
||||
user_preferences.global_dir = prefs.get('global_dir', paths.default_global_dict())
|
||||
|
@ -286,7 +287,7 @@ def save_prefs(self, context):
|
|||
fpath = paths.BLENDERKIT_SETTINGS_FILENAME
|
||||
if not os.path.exists(paths._presets):
|
||||
os.makedirs(paths._presets)
|
||||
with open(fpath, 'w', encoding = 'utf-8') as s:
|
||||
with open(fpath, 'w', encoding='utf-8') as s:
|
||||
json.dump(prefs, s, ensure_ascii=False, indent=4)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
@ -303,6 +304,7 @@ def uploadable_asset_poll():
|
|||
return ui_props.hdr_upload_image is not None
|
||||
return True
|
||||
|
||||
|
||||
def get_hidden_texture(img, force_reload=False):
|
||||
# i = get_hidden_image(tpath, bdata_name, force_reload=force_reload)
|
||||
# bdata_name = f".{bdata_name}"
|
||||
|
@ -314,7 +316,7 @@ def get_hidden_texture(img, force_reload=False):
|
|||
return t
|
||||
|
||||
|
||||
def get_hidden_image(tpath, bdata_name, force_reload=False, colorspace = 'sRGB'):
|
||||
def get_hidden_image(tpath, bdata_name, force_reload=False, colorspace='sRGB'):
|
||||
if bdata_name[0] == '.':
|
||||
hidden_name = bdata_name
|
||||
else:
|
||||
|
@ -340,12 +342,13 @@ def get_hidden_image(tpath, bdata_name, force_reload=False, colorspace = 'sRGB')
|
|||
|
||||
img.filepath = tpath
|
||||
img.reload()
|
||||
img.colorspace_settings.name = colorspace
|
||||
image_utils.set_colorspace(img, colorspace)
|
||||
|
||||
elif force_reload:
|
||||
if img.packed_file is not None:
|
||||
img.unpack(method='USE_ORIGINAL')
|
||||
img.reload()
|
||||
img.colorspace_settings.name = colorspace
|
||||
image_utils.set_colorspace(img, colorspace)
|
||||
return img
|
||||
|
||||
|
||||
|
@ -355,7 +358,7 @@ def get_thumbnail(name):
|
|||
img = bpy.data.images.get(name)
|
||||
if img == None:
|
||||
img = bpy.data.images.load(p)
|
||||
img.colorspace_settings.name = 'sRGB'
|
||||
image_utils.set_colorspace(img, 'sRGB')
|
||||
img.name = name
|
||||
img.name = name
|
||||
|
||||
|
@ -378,16 +381,16 @@ def get_brush_props(context):
|
|||
return None
|
||||
|
||||
|
||||
def p(text, text1='', text2='', text3='', text4='', text5='', level = 'DEBUG'):
|
||||
def p(text, text1='', text2='', text3='', text4='', text5='', level='DEBUG'):
|
||||
'''debug printing depending on blender's debug value'''
|
||||
|
||||
if 1:#bpy.app.debug_value != 0:
|
||||
if 1: # bpy.app.debug_value != 0:
|
||||
# print('-----BKit debug-----\n')
|
||||
# traceback.print_stack()
|
||||
texts = [text1,text2,text3,text4,text5]
|
||||
texts = [text1, text2, text3, text4, text5]
|
||||
text = str(text)
|
||||
for t in texts:
|
||||
if t!= '':
|
||||
if t != '':
|
||||
text += ' ' + str(t)
|
||||
|
||||
bk_logger.debug(text)
|
||||
|
@ -398,7 +401,7 @@ def copy_asset(fp1, fp2):
|
|||
'''synchronizes the asset between folders, including it's texture subdirectories'''
|
||||
if 1:
|
||||
bk_logger.debug('copy asset')
|
||||
bk_logger.debug(fp1 +' '+ fp2)
|
||||
bk_logger.debug(fp1 + ' ' + fp2)
|
||||
if not os.path.exists(fp2):
|
||||
shutil.copyfile(fp1, fp2)
|
||||
bk_logger.debug('copied')
|
||||
|
@ -410,7 +413,7 @@ def copy_asset(fp1, fp2):
|
|||
target_subdir = os.path.join(target_dir, subdir.name)
|
||||
if os.path.exists(target_subdir):
|
||||
continue
|
||||
bk_logger.debug(str(subdir) +' '+ str(target_subdir))
|
||||
bk_logger.debug(str(subdir) + ' ' + str(target_subdir))
|
||||
shutil.copytree(subdir, target_subdir)
|
||||
bk_logger.debug('copied')
|
||||
|
||||
|
@ -638,11 +641,15 @@ def automap(target_object=None, target_slot=None, tex_size=1, bg_exception=False
|
|||
bpy.context.view_layer.objects.active = actob
|
||||
|
||||
|
||||
def name_update():
|
||||
def name_update(props):
|
||||
'''
|
||||
Update asset name function, gets run also before upload. Makes sure name doesn't change in case of reuploads,
|
||||
and only displayName gets written to server.
|
||||
'''
|
||||
scene = bpy.context.scene
|
||||
ui_props = scene.blenderkitUI
|
||||
|
||||
props = get_upload_props()
|
||||
# props = get_upload_props()
|
||||
if props.name_old != props.name:
|
||||
props.name_changed = True
|
||||
props.name_old = props.name
|
||||
|
@ -674,7 +681,6 @@ def get_param(asset_data, parameter_name):
|
|||
return None
|
||||
|
||||
|
||||
|
||||
def params_to_dict(params):
|
||||
params_dict = {}
|
||||
for p in params:
|
||||
|
@ -705,6 +711,7 @@ def dict_to_params(inputs, parameters=None):
|
|||
})
|
||||
return parameters
|
||||
|
||||
|
||||
def update_tags(self, context):
|
||||
props = self
|
||||
|
||||
|
@ -729,6 +736,7 @@ def update_tags(self, context):
|
|||
if props.tags != ns:
|
||||
props.tags = ns
|
||||
|
||||
|
||||
def user_logged_in():
|
||||
a = bpy.context.window_manager.get('bkit profile')
|
||||
if a is not None:
|
||||
|
@ -826,5 +834,6 @@ def label_multiline(layout, text='', icon='NONE', width=-1):
|
|||
layout.label(text=l, icon=icon)
|
||||
icon = 'NONE'
|
||||
|
||||
|
||||
def trace():
|
||||
traceback.print_stack()
|
||||
traceback.print_stack()
|
||||
|
|
|
@ -142,7 +142,7 @@ class OperatorSegmentsInfo(bpy.types.Operator):
|
|||
class OperatorOriginToSpline0Start(bpy.types.Operator):
|
||||
bl_idname = "curvetools.operatororigintospline0start"
|
||||
bl_label = "OriginToSpline0Start"
|
||||
bl_description = "Sets the origin of the active/selected curve to the starting point of the (first) spline. Nice for curve modifiers."
|
||||
bl_description = "Sets the origin of the active/selected curve to the starting point of the (first) spline. Nice for curve modifiers"
|
||||
|
||||
|
||||
@classmethod
|
||||
|
@ -327,7 +327,7 @@ class OperatorSplinesSetResolution(bpy.types.Operator):
|
|||
class OperatorSplinesRemoveZeroSegment(bpy.types.Operator):
|
||||
bl_idname = "curvetools.operatorsplinesremovezerosegment"
|
||||
bl_label = "SplinesRemoveZeroSegment"
|
||||
bl_description = "Removes splines with no segments -- they seem to creep up, sometimes.."
|
||||
bl_description = "Removes splines with no segments -- they seem to creep up, sometimes"
|
||||
|
||||
|
||||
@classmethod
|
||||
|
|
|
@ -21,7 +21,7 @@ bl_info = {
|
|||
"name": "Grease Pencil Tools",
|
||||
"description": "Extra tools for Grease Pencil",
|
||||
"author": "Samuel Bernou, Antonio Vazquez, Daniel Martinez Lara, Matias Mendiola",
|
||||
"version": (1, 3, 1),
|
||||
"version": (1, 3, 3),
|
||||
"blender": (2, 91, 0),
|
||||
"location": "Sidebar > Grease Pencil > Grease Pencil Tools",
|
||||
"warning": "",
|
||||
|
|
|
@ -128,9 +128,9 @@ class GreasePencilAddonPrefs(bpy.types.AddonPreferences):
|
|||
rc_angle_step: FloatProperty(
|
||||
name="Angle Steps",
|
||||
description="Step the rotation using this angle when using rotate canvas step modifier",
|
||||
default=0.0872664600610733, # 5
|
||||
default=0.2617993877991494, # 15
|
||||
min=0.01745329238474369, # 1
|
||||
max=3.1415927410125732, # # 180
|
||||
max=3.1415927410125732, # 180
|
||||
soft_min=0.01745329238474369, # 1
|
||||
soft_max=1.5707963705062866, # 90
|
||||
step=10, precision=1, subtype='ANGLE', unit='ROTATION')
|
||||
|
@ -153,7 +153,7 @@ class GreasePencilAddonPrefs(bpy.types.AddonPreferences):
|
|||
row.label(text='Box Deform:')
|
||||
row.operator("wm.call_menu", text="", icon='QUESTION').name = "GPT_MT_box_deform_doc"
|
||||
box.prop(self, "use_clic_drag")
|
||||
# box.separator()
|
||||
|
||||
box.prop(self, "default_deform_type")
|
||||
box.label(text="Deformer type can be changed during modal with 'M' key, this is for default behavior", icon='INFO')
|
||||
|
||||
|
@ -179,7 +179,7 @@ class GreasePencilAddonPrefs(bpy.types.AddonPreferences):
|
|||
|
||||
if not self.use_ctrl and not self.use_alt and not self.use_shift:
|
||||
box.label(text="Choose at least one modifier to combine with click (default: Ctrl+Alt)", icon="ERROR")# INFO
|
||||
|
||||
|
||||
if not all((self.use_ctrl, self.use_alt, self.use_shift)):
|
||||
row = box.row(align = True)
|
||||
snap_key_list = []
|
||||
|
@ -204,7 +204,7 @@ class GreasePencilAddonPrefs(bpy.types.AddonPreferences):
|
|||
draw_ts_pref(prefs.ts, box)
|
||||
|
||||
|
||||
# def box_deform_tuto(layout):
|
||||
|
||||
class GPT_MT_box_deform_doc(bpy.types.Menu):
|
||||
# bl_idname = "OBJECT_MT_custom_menu"
|
||||
bl_label = "Box Deform Infos Sheet"
|
||||
|
|
|
@ -5,6 +5,7 @@ import math
|
|||
import mathutils
|
||||
from bpy_extras.view3d_utils import location_3d_to_region_2d
|
||||
from bpy.props import BoolProperty, EnumProperty
|
||||
from time import time
|
||||
## draw utils
|
||||
import gpu
|
||||
import bgl
|
||||
|
@ -13,7 +14,7 @@ from gpu_extras.batch import batch_for_shader
|
|||
from gpu_extras.presets import draw_circle_2d
|
||||
|
||||
def step_value(value, step):
|
||||
'''return the step closer to the passed value'''
|
||||
'''return the step closer to the passed value'''
|
||||
abs_angle = abs(value)
|
||||
diff = abs_angle % step
|
||||
lower_step = abs_angle - diff
|
||||
|
@ -25,6 +26,8 @@ def step_value(value, step):
|
|||
|
||||
def draw_callback_px(self, context):
|
||||
# 50% alpha, 2 pixel width line
|
||||
if context.area != self.current_area:
|
||||
return
|
||||
shader = gpu.shader.from_builtin('2D_UNIFORM_COLOR')
|
||||
bgl.glEnable(bgl.GL_BLEND)
|
||||
bgl.glLineWidth(2)
|
||||
|
@ -90,7 +93,7 @@ class RC_OT_RotateCanvas(bpy.types.Operator):
|
|||
# Calculates the angle between initial and current vectors
|
||||
self.angle = self.vector_initial.angle_signed(self.vector_current)#radian
|
||||
# print (math.degrees(self.angle), self.vector_initial, self.vector_current)
|
||||
|
||||
|
||||
|
||||
## handle snap key
|
||||
snap = False
|
||||
|
@ -116,7 +119,8 @@ class RC_OT_RotateCanvas(bpy.types.Operator):
|
|||
context.space_data.region_3d.view_rotation = rot.to_quaternion()
|
||||
|
||||
if event.type in {'RIGHTMOUSE', 'LEFTMOUSE', 'MIDDLEMOUSE'} and event.value == 'RELEASE':
|
||||
if not self.angle:
|
||||
# Trigger reset : Less than 150ms and less than 2 degrees move
|
||||
if time() - self.timer < 0.15 and abs(math.degrees(self.angle)) < 2:
|
||||
# self.report({'INFO'}, 'Reset')
|
||||
aim = context.space_data.region_3d.view_rotation @ mathutils.Vector((0.0, 0.0, 1.0))#view vector
|
||||
z_up_quat = aim.to_track_quat('Z','Y')#track Z, up Y
|
||||
|
@ -143,6 +147,7 @@ class RC_OT_RotateCanvas(bpy.types.Operator):
|
|||
return {'RUNNING_MODAL'}
|
||||
|
||||
def invoke(self, context, event):
|
||||
self.current_area = context.area
|
||||
prefs = get_addon_prefs()
|
||||
self.hud = prefs.canvas_use_hud
|
||||
self.angle = 0.0
|
||||
|
@ -190,6 +195,7 @@ class RC_OT_RotateCanvas(bpy.types.Operator):
|
|||
# round to closer degree and convert back to radians
|
||||
self.snap_step = math.radians(round(math.degrees(prefs.rc_angle_step)))
|
||||
|
||||
self.timer = time()
|
||||
args = (self, context)
|
||||
if self.hud:
|
||||
self._handle = bpy.types.SpaceView3D.draw_handler_add(draw_callback_px, args, 'WINDOW', 'POST_PIXEL')
|
||||
|
@ -210,7 +216,7 @@ class RC_OT_Set_rotation(bpy.types.Operator):
|
|||
return context.space_data.region_3d.view_perspective == 'CAMERA'
|
||||
|
||||
def execute(self, context):
|
||||
cam_ob = context.scene.camera
|
||||
cam_ob = context.scene.camera
|
||||
cam_ob['stored_rotation'] = cam_ob.rotation_euler
|
||||
if not cam_ob.get('_RNA_UI'):
|
||||
cam_ob['_RNA_UI'] = {}
|
||||
|
@ -233,7 +239,7 @@ class RC_OT_Reset_rotation(bpy.types.Operator):
|
|||
return context.space_data.region_3d.view_perspective == 'CAMERA' and context.scene.camera.get('stored_rotation')
|
||||
|
||||
def execute(self, context):
|
||||
cam_ob = context.scene.camera
|
||||
cam_ob = context.scene.camera
|
||||
cam_ob.rotation_euler = cam_ob['stored_rotation']
|
||||
return {'FINISHED'}
|
||||
|
||||
|
@ -252,4 +258,4 @@ def register():
|
|||
|
||||
def unregister():
|
||||
for cls in reversed(classes):
|
||||
bpy.utils.unregister_class(cls)
|
||||
bpy.utils.unregister_class(cls)
|
||||
|
|
|
@ -122,6 +122,7 @@ class GPTS_OT_time_scrub(bpy.types.Operator):
|
|||
self.current_area = context.area
|
||||
self.key = prefs.keycode
|
||||
self.evaluate_gp_obj_key = prefs.evaluate_gp_obj_key
|
||||
self.always_snap = prefs.always_snap
|
||||
|
||||
self.dpi = context.preferences.system.dpi
|
||||
self.ui_scale = context.preferences.system.ui_scale
|
||||
|
@ -143,7 +144,7 @@ class GPTS_OT_time_scrub(bpy.types.Operator):
|
|||
self.snap_on = False
|
||||
self.mouse = (event.mouse_region_x, event.mouse_region_y)
|
||||
self.init_mouse_x = self.cursor_x = event.mouse_region_x
|
||||
|
||||
|
||||
# self.init_mouse_y = event.mouse_region_y # only to display init frame text
|
||||
self.init_frame = self.new_frame = context.scene.frame_current
|
||||
self.lock_range = context.scene.lock_frame_selection_to_range
|
||||
|
@ -153,7 +154,7 @@ class GPTS_OT_time_scrub(bpy.types.Operator):
|
|||
else:
|
||||
self.f_start = context.scene.frame_start
|
||||
self.f_end = context.scene.frame_end
|
||||
|
||||
|
||||
self.offset = 0
|
||||
self.pos = []
|
||||
|
||||
|
@ -190,14 +191,15 @@ class GPTS_OT_time_scrub(bpy.types.Operator):
|
|||
for frame in layer.frames:
|
||||
if frame.frame_number not in self.pos:
|
||||
self.pos.append(frame.frame_number)
|
||||
|
||||
|
||||
# Add start and end to snap on
|
||||
|
||||
if not ob or not self.pos:
|
||||
# Disable inverted behavior if no frame to snap
|
||||
self.always_snap = False
|
||||
|
||||
# Also snap on play bounds (sliced off for keyframe display)
|
||||
self.pos += [self.f_start, self.f_end]
|
||||
|
||||
|
||||
# Disable Onion skin
|
||||
self.active_space_data = context.space_data
|
||||
self.onion_skin = None
|
||||
|
@ -205,7 +207,7 @@ class GPTS_OT_time_scrub(bpy.types.Operator):
|
|||
if context.space_data.type == 'VIEW_3D': # and 'GPENCIL' in context.mode
|
||||
self.onion_skin = self.active_space_data.overlay.use_gpencil_onion_skin
|
||||
self.active_space_data.overlay.use_gpencil_onion_skin = False
|
||||
|
||||
|
||||
if ob and ob.type == 'GPENCIL':
|
||||
if ob.data.use_multiedit:
|
||||
self.multi_frame = ob.data.use_multiedit
|
||||
|
@ -333,7 +335,7 @@ class GPTS_OT_time_scrub(bpy.types.Operator):
|
|||
# (after drawing batch so those are still showed)
|
||||
if self.lock_range:
|
||||
self.pos = [i for i in self.pos if self.f_start <= i <= self.f_end]
|
||||
|
||||
|
||||
# convert frame list to array for numpy snap utility
|
||||
self.pos = np.asarray(self.pos)
|
||||
|
||||
|
@ -389,8 +391,14 @@ class GPTS_OT_time_scrub(bpy.types.Operator):
|
|||
if self.snap_alt and event.alt:
|
||||
mod_snap = True
|
||||
|
||||
if self.snap_on or mod_snap:
|
||||
self.new_frame = nearest(self.pos, self.new_frame)
|
||||
## Snapping
|
||||
if self.always_snap:
|
||||
# inverted snapping behavior
|
||||
if not self.snap_on and not mod_snap:
|
||||
self.new_frame = nearest(self.pos, self.new_frame)
|
||||
else:
|
||||
if self.snap_on or mod_snap:
|
||||
self.new_frame = nearest(self.pos, self.new_frame)
|
||||
|
||||
# frame range restriction
|
||||
if self.lock_range:
|
||||
|
@ -492,6 +500,11 @@ class GPTS_timeline_settings(bpy.types.PropertyGroup):
|
|||
description="Shortcut to trigger the scrub in viewport during press",
|
||||
default="MIDDLEMOUSE")
|
||||
|
||||
always_snap: BoolProperty(
|
||||
name="Always Snap",
|
||||
description="Always snap to keys if any, modifier is used deactivate the snapping\nDisabled if no keyframe found",
|
||||
default=False)
|
||||
|
||||
use_in_timeline_editor: BoolProperty(
|
||||
name="Shortcut in timeline editors",
|
||||
description="Add the same shortcut to scrub in timeline editor windows",
|
||||
|
@ -649,7 +662,11 @@ def draw_ts_pref(prefs, layout):
|
|||
else:
|
||||
box.label(text='[ NOW TYPE KEY OR CLICK TO USE, WITH MODIFIER ]')
|
||||
|
||||
snap_text = 'Snap to keyframes: '
|
||||
if prefs.always_snap:
|
||||
snap_text = 'Disable keyframes snap: '
|
||||
else:
|
||||
snap_text = 'Keyframes snap: '
|
||||
|
||||
snap_text += 'Left Mouse' if prefs.keycode == 'RIGHTMOUSE' else 'Right Mouse'
|
||||
if not prefs.use_ctrl:
|
||||
snap_text += ' or Ctrl'
|
||||
|
@ -662,6 +679,7 @@ def draw_ts_pref(prefs, layout):
|
|||
box.label(
|
||||
text="Recommended to choose at least one modifier to combine with clicks (default: Ctrl+Alt)", icon="ERROR")
|
||||
|
||||
box.prop(prefs, 'always_snap')
|
||||
box.prop(prefs, 'use_in_timeline_editor',
|
||||
text='Add same shortcut to scrub within timeline editors')
|
||||
|
||||
|
|
|
@ -1821,7 +1821,7 @@ class SceneCoat3D(PropertyGroup):
|
|||
)
|
||||
bake_resolution: EnumProperty(
|
||||
name="Bake Resolution",
|
||||
description="Bake resolution.",
|
||||
description="Bake resolution",
|
||||
items=(("res_64", "64 x 64", ""),
|
||||
("res_128", "128 x 128", ""),
|
||||
("res_256", "256 x 256", ""),
|
||||
|
@ -1835,7 +1835,7 @@ class SceneCoat3D(PropertyGroup):
|
|||
)
|
||||
folder_size: EnumProperty(
|
||||
name="Applink folder size",
|
||||
description="Applink folder size.",
|
||||
description="Applink folder size",
|
||||
items=(("10", "10", ""),
|
||||
("100", "100", ""),
|
||||
("500", "500", ""),
|
||||
|
|
|
@ -158,7 +158,7 @@ class PanelProperties(bpy.types.PropertyGroup):
|
|||
description="Distance of 2 objects in Angstrom")
|
||||
replace_objs: EnumProperty(
|
||||
name="Shape",
|
||||
description="Choose a different atom shape.",
|
||||
description="Choose a different atom shape",
|
||||
items=(('0',"Unchanged", "Do not change the shape"),
|
||||
('1a',"Sphere (Mesh)", "Replace with a sphere (Mesh)"),
|
||||
('1b',"Sphere (NURBS)", "Replace with a sphere (NURBS)"),
|
||||
|
@ -179,7 +179,7 @@ class PanelProperties(bpy.types.PropertyGroup):
|
|||
default='0',)
|
||||
replace_objs_material: EnumProperty(
|
||||
name="Material",
|
||||
description="Choose a different material.",
|
||||
description="Choose a different material",
|
||||
items=(('0',"Unchanged", "Leave the material unchanged"),
|
||||
('1',"Normal", "Use normal material (no transparency and reflection)"),
|
||||
('2',"Transparent", "Use transparent material"),
|
||||
|
@ -188,7 +188,7 @@ class PanelProperties(bpy.types.PropertyGroup):
|
|||
default='0',)
|
||||
replace_objs_special: EnumProperty(
|
||||
name="Special",
|
||||
description="Choose a special atom shape.",
|
||||
description="Choose a special atom shape",
|
||||
items=(('0',"None", "Use no special shape."),
|
||||
('1',"F2+ center", "Replace with a F2+ center"),
|
||||
('2',"F+ center", "Replace with a F+ center"),
|
||||
|
@ -211,7 +211,7 @@ class PanelProperties(bpy.types.PropertyGroup):
|
|||
default='0',update=Callback_radius_type)
|
||||
radius_type_ionic: EnumProperty(
|
||||
name="Charge",
|
||||
description="Charge state of the ions if existing.",
|
||||
description="Charge state of the ions if existing",
|
||||
items=(('0',"-4", "Charge state -4"),
|
||||
('1',"-3", "Charge state -3"),
|
||||
('2',"-2", "Charge state -2"),
|
||||
|
@ -262,7 +262,7 @@ class DatafileApply(Operator):
|
|||
class DefaultAtom(Operator):
|
||||
bl_idname = "atom_blend.default_atoms"
|
||||
bl_label = "Default"
|
||||
bl_description = ("Use default shapes and colors for atoms.")
|
||||
bl_description = ("Use default shapes and colors for atoms")
|
||||
|
||||
# Are we in the OBJECT mode?
|
||||
@classmethod
|
||||
|
@ -288,7 +288,7 @@ class DefaultAtom(Operator):
|
|||
class ReplaceAtom(Operator):
|
||||
bl_idname = "atom_blend.replace_atom"
|
||||
bl_label = "Replace"
|
||||
bl_description = ("Replace selected atoms with atoms of different shape.")
|
||||
bl_description = ("Replace selected atoms with atoms of different shape")
|
||||
|
||||
# Are we in the OBJECT mode?
|
||||
@classmethod
|
||||
|
@ -337,7 +337,7 @@ class SeparateAtom(Operator):
|
|||
class DistanceButton(Operator):
|
||||
bl_idname = "atom_blend.button_distance"
|
||||
bl_label = "Measure ..."
|
||||
bl_description = "Measure the distance between two atoms (objects)."
|
||||
bl_description = "Measure the distance between two atoms (objects)"
|
||||
|
||||
def execute(self, context):
|
||||
scn = bpy.context.scene.atom_blend
|
||||
|
|
|
@ -92,10 +92,10 @@ class IMPORT_OT_xyz(Operator, ImportHelper):
|
|||
description = "Do you want to load all frames?")
|
||||
skip_frames: IntProperty(
|
||||
name="", default=0, min=0,
|
||||
description="Number of frames you want to skip.")
|
||||
description="Number of frames you want to skip")
|
||||
images_per_key: IntProperty(
|
||||
name="", default=1, min=1,
|
||||
description="Choose the number of images between 2 keys.")
|
||||
description="Choose the number of images between 2 keys")
|
||||
|
||||
# This thing here just guarantees that the menu entry is not active when the
|
||||
# check box in the addon preferences is not activated! See __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, 3),
|
||||
"version": (1, 6, 4),
|
||||
'blender': (2, 91, 0),
|
||||
'location': 'File > Import-Export',
|
||||
'description': 'Import-Export as glTF 2.0',
|
||||
|
@ -70,21 +70,42 @@ from bpy_extras.io_utils import ImportHelper, ExportHelper
|
|||
extension_panel_unregister_functors = []
|
||||
|
||||
|
||||
def ensure_filepath_matches_export_format(filepath, export_format):
|
||||
import os
|
||||
filename = os.path.basename(filepath)
|
||||
if not filename:
|
||||
return filepath
|
||||
|
||||
stem, ext = os.path.splitext(filename)
|
||||
if stem.startswith('.') and not ext:
|
||||
stem, ext = '', stem
|
||||
|
||||
desired_ext = '.glb' if export_format == 'GLB' else '.gltf'
|
||||
ext_lower = ext.lower()
|
||||
if ext_lower not in ['.glb', '.gltf']:
|
||||
return filepath + desired_ext
|
||||
elif ext_lower != desired_ext:
|
||||
filepath = filepath[:-len(ext)] # strip off ext
|
||||
return filepath + desired_ext
|
||||
else:
|
||||
return filepath
|
||||
|
||||
|
||||
def on_export_format_changed(self, context):
|
||||
# Update the file extension when the format (.glb/.gltf) changes
|
||||
# Update the filename in the file browser when the format (.glb/.gltf)
|
||||
# changes
|
||||
sfile = context.space_data
|
||||
if sfile is None:
|
||||
return # Avoid error when export from background
|
||||
operator = sfile.active_operator
|
||||
if operator.bl_idname != "EXPORT_SCENE_OT_gltf":
|
||||
if not isinstance(sfile, bpy.types.SpaceFileBrowser):
|
||||
return
|
||||
if operator.check(context):
|
||||
# Weird hack to force the filepicker to notice filename changed
|
||||
from os.path import basename
|
||||
filepath = operator.filepath
|
||||
bpy.ops.file.filenum(increment=-1)
|
||||
if basename(operator.filepath) != basename(filepath):
|
||||
bpy.ops.file.filenum(increment=1)
|
||||
if not sfile.active_operator:
|
||||
return
|
||||
if sfile.active_operator.bl_idname != "EXPORT_SCENE_OT_gltf":
|
||||
return
|
||||
|
||||
sfile.params.filename = ensure_filepath_matches_export_format(
|
||||
sfile.params.filename,
|
||||
self.export_format,
|
||||
)
|
||||
|
||||
|
||||
class ExportGLTF2_Base:
|
||||
|
@ -384,28 +405,12 @@ class ExportGLTF2_Base:
|
|||
|
||||
def check(self, _context):
|
||||
# Ensure file extension matches format
|
||||
import os
|
||||
filename = os.path.basename(self.filepath)
|
||||
if filename:
|
||||
filepath = self.filepath
|
||||
desired_ext = '.glb' if self.export_format == 'GLB' else '.gltf'
|
||||
|
||||
stem, ext = os.path.splitext(filename)
|
||||
if stem.startswith('.') and not ext:
|
||||
stem, ext = '', stem
|
||||
|
||||
ext_lower = ext.lower()
|
||||
if ext_lower not in ['.glb', '.gltf']:
|
||||
filepath = filepath + desired_ext
|
||||
elif ext_lower != desired_ext:
|
||||
filepath = filepath[:-len(ext)] # strip off ext
|
||||
filepath += desired_ext
|
||||
|
||||
if filepath != self.filepath:
|
||||
self.filepath = filepath
|
||||
return True
|
||||
|
||||
return False
|
||||
old_filepath = self.filepath
|
||||
self.filepath = ensure_filepath_matches_export_format(
|
||||
self.filepath,
|
||||
self.export_format,
|
||||
)
|
||||
return self.filepath != old_filepath
|
||||
|
||||
def invoke(self, context, event):
|
||||
settings = context.scene.get(self.scene_key)
|
||||
|
|
|
@ -118,6 +118,9 @@ def register_keymaps():
|
|||
keyconfigs = bpy.context.window_manager.keyconfigs
|
||||
kc_defaultconf = keyconfigs.default
|
||||
kc_addonconf = keyconfigs.addon
|
||||
# In background mode.
|
||||
if kc_defaultconf is None or kc_addonconf is None:
|
||||
return
|
||||
|
||||
# TODO: find the user defined tool_mouse.
|
||||
from bl_keymap_utils.io import keyconfig_init_from_data
|
||||
|
@ -128,8 +131,11 @@ def register_keymaps():
|
|||
#snap_modalkeymap.assign("MESH_OT_snap_utilities_line")
|
||||
def unregister_keymaps():
|
||||
keyconfigs = bpy.context.window_manager.keyconfigs
|
||||
defaultmap = keyconfigs.get("Blender").keymaps
|
||||
addonmap = keyconfigs.get("Blender addon").keymaps
|
||||
defaultmap = getattr(keyconfigs.get("Blender"), "keymaps", None)
|
||||
addonmap = getattr(keyconfigs.get("Blender addon"), "keymaps", None)
|
||||
# In background mode.
|
||||
if defaultmap is None or addonmap is None:
|
||||
return
|
||||
|
||||
for keyconfig_data in keys.generate_snap_utilities_global_keymaps():
|
||||
km_name, km_args, km_content = keyconfig_data
|
||||
|
|
|
@ -164,11 +164,11 @@ class SnapWidgetGroupCommon(bpy.types.GizmoGroup):
|
|||
return context_mode_check(context, cls.bl_idname)
|
||||
|
||||
def init_tool(self, context, gizmo_name):
|
||||
self.widget = self.gizmos.new(gizmo_name)
|
||||
self._widget = self.gizmos.new(gizmo_name)
|
||||
|
||||
def __del__(self):
|
||||
if hasattr(self, "widget"):
|
||||
object.__getattribute__(self.widget, 'end_snapwidget')()
|
||||
if hasattr(self, "_widget"):
|
||||
object.__getattribute__(self._widget, 'end_snapwidget')()
|
||||
|
||||
|
||||
class SnapPointWidgetGroup(SnapWidgetGroupCommon):
|
||||
|
|
|
@ -704,8 +704,8 @@ class reaction_diffusion(bpy.types.Operator):
|
|||
class edges_deformation(bpy.types.Operator):
|
||||
bl_idname = "object.edges_deformation"
|
||||
bl_label = "Edges Deformation"
|
||||
bl_description = ("Compute Weight based on the deformation of edges"+
|
||||
"according to visible modifiers.")
|
||||
bl_description = ("Compute Weight based on the deformation of edges "
|
||||
"according to visible modifiers")
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
|
||||
bounds : bpy.props.EnumProperty(
|
||||
|
@ -846,8 +846,8 @@ class edges_deformation(bpy.types.Operator):
|
|||
class edges_bending(bpy.types.Operator):
|
||||
bl_idname = "object.edges_bending"
|
||||
bl_label = "Edges Bending"
|
||||
bl_description = ("Compute Weight based on the bending of edges"+
|
||||
"according to visible modifiers.")
|
||||
bl_description = ("Compute Weight based on the bending of edges "
|
||||
"according to visible modifiers")
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
|
||||
bounds : bpy.props.EnumProperty(
|
||||
|
@ -1678,7 +1678,7 @@ class vertex_colors_to_vertex_groups(bpy.types.Operator):
|
|||
bl_idname = "object.vertex_colors_to_vertex_groups"
|
||||
bl_label = "Vertex Color"
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
bl_description = ("Convert the active Vertex Color into a Vertex Group.")
|
||||
bl_description = ("Convert the active Vertex Color into a Vertex Group")
|
||||
|
||||
red : bpy.props.BoolProperty(
|
||||
name="red channel", default=False, description="convert red channel")
|
||||
|
@ -1770,7 +1770,7 @@ class vertex_group_to_vertex_colors(bpy.types.Operator):
|
|||
bl_idname = "object.vertex_group_to_vertex_colors"
|
||||
bl_label = "Vertex Group"
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
bl_description = ("Convert the active Vertex Group into a Vertex Color.")
|
||||
bl_description = ("Convert the active Vertex Group into a Vertex Color")
|
||||
|
||||
channel : bpy.props.EnumProperty(
|
||||
items=[('Blue', 'Blue Channel', 'Convert to Blue Channel'),
|
||||
|
@ -1857,8 +1857,8 @@ class curvature_to_vertex_groups(bpy.types.Operator):
|
|||
bl_idname = "object.curvature_to_vertex_groups"
|
||||
bl_label = "Curvature"
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
bl_description = ("Generate a Vertex Group based on the curvature of the"
|
||||
"mesh. Is based on Dirty Vertex Color.")
|
||||
bl_description = ("Generate a Vertex Group based on the curvature of the "
|
||||
"mesh. Is based on Dirty Vertex Color")
|
||||
|
||||
invert : bpy.props.BoolProperty(
|
||||
name="invert", default=False, description="invert values")
|
||||
|
@ -1905,8 +1905,8 @@ class face_area_to_vertex_groups(bpy.types.Operator):
|
|||
bl_idname = "object.face_area_to_vertex_groups"
|
||||
bl_label = "Area"
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
bl_description = ("Generate a Vertex Group based on the area of individual"
|
||||
"faces.")
|
||||
bl_description = ("Generate a Vertex Group based on the area of individual "
|
||||
"faces")
|
||||
|
||||
invert : bpy.props.BoolProperty(
|
||||
name="invert", default=False, description="invert values")
|
||||
|
|
|
@ -483,7 +483,7 @@ def assign_angle_presets(self, context):
|
|||
self.angle = angle_presets[self.angle_presets]
|
||||
|
||||
class OffsetEdges(bpy.types.Operator):
|
||||
"""Offset Edges."""
|
||||
"""Offset Edges"""
|
||||
bl_idname = "mesh.offset_edges"
|
||||
bl_label = "Offset Edges"
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
|
@ -531,7 +531,7 @@ class OffsetEdges(bpy.types.Operator):
|
|||
name="Flat Face Threshold", default=radians(0.05), precision=5,
|
||||
step=1.0e-4, subtype='ANGLE',
|
||||
description="If difference of angle between two adjacent faces is "
|
||||
"below this value, those faces are regarded as flat.",
|
||||
"below this value, those faces are regarded as flat",
|
||||
options={'HIDDEN'})
|
||||
caches_valid: bpy.props.BoolProperty(
|
||||
name="Caches Valid", default=False,
|
||||
|
|
|
@ -22,7 +22,7 @@ bl_info = {
|
|||
"name": "Collection Manager",
|
||||
"description": "Manage collections and their objects",
|
||||
"author": "Ryan Inch",
|
||||
"version": (2, 19, 2),
|
||||
"version": (2, 19, 3),
|
||||
"blender": (2, 80, 0),
|
||||
"location": "View3D - Object Mode (Shortcut - M)",
|
||||
"warning": '', # used for warning icon and text in addons panel
|
||||
|
|
|
@ -40,12 +40,6 @@ def update_qcd_status(self, context):
|
|||
if self.enable_qcd:
|
||||
qcd_init.register_qcd()
|
||||
|
||||
if self.enable_qcd_view_hotkeys:
|
||||
qcd_init.register_qcd_view_hotkeys()
|
||||
|
||||
if self.enable_qcd_view_edit_mode_hotkeys:
|
||||
qcd_init.register_qcd_view_edit_mode_hotkeys()
|
||||
|
||||
else:
|
||||
qcd_init.unregister_qcd()
|
||||
|
||||
|
|
|
@ -109,7 +109,7 @@ def add_line_to_bisection(context):
|
|||
|
||||
|
||||
class PDT_OT_LineOnBisection(bpy.types.Operator):
|
||||
"""Create Bisector between 2 Selected Edges."""
|
||||
"""Create Bisector between 2 Selected Edges"""
|
||||
|
||||
bl_idname = "pdt.linetobisect"
|
||||
bl_label = "Add Edges Bisector"
|
||||
|
|
|
@ -83,7 +83,7 @@ PDT_FeatureError = pdt_exception.FeatureError
|
|||
|
||||
|
||||
class PDT_OT_CommandReRun(Operator):
|
||||
"""Repeat Current Displayed Command."""
|
||||
"""Repeat Current Displayed Command"""
|
||||
|
||||
bl_idname = "pdt.command_rerun"
|
||||
bl_label = "Re-run Current Command"
|
||||
|
|
|
@ -33,7 +33,7 @@ from .pdt_msg_strings import (
|
|||
|
||||
|
||||
class PDT_OT_PlacementAbs(Operator):
|
||||
"""Use Absolute, or Global Placement."""
|
||||
"""Use Absolute, or Global Placement"""
|
||||
|
||||
bl_idname = "pdt.absolute"
|
||||
bl_label = "Absolute Mode"
|
||||
|
@ -114,7 +114,7 @@ class PDT_OT_PlacementAbs(Operator):
|
|||
|
||||
|
||||
class PDT_OT_PlacementDelta(Operator):
|
||||
"""Use Delta, or Incremental Placement."""
|
||||
"""Use Delta, or Incremental Placement"""
|
||||
|
||||
bl_idname = "pdt.delta"
|
||||
bl_label = "Delta Mode"
|
||||
|
@ -211,7 +211,7 @@ class PDT_OT_PlacementDelta(Operator):
|
|||
|
||||
|
||||
class PDT_OT_PlacementDis(Operator):
|
||||
"""Use Directional, or Distance @ Angle Placement."""
|
||||
"""Use Directional, or Distance @ Angle Placement"""
|
||||
|
||||
bl_idname = "pdt.distance"
|
||||
bl_label = "Distance@Angle Mode"
|
||||
|
@ -300,7 +300,7 @@ class PDT_OT_PlacementDis(Operator):
|
|||
|
||||
|
||||
class PDT_OT_PlacementPer(Operator):
|
||||
"""Use Percentage Placement."""
|
||||
"""Use Percentage Placement"""
|
||||
|
||||
bl_idname = "pdt.percent"
|
||||
bl_label = "Percentage Mode"
|
||||
|
@ -357,7 +357,7 @@ class PDT_OT_PlacementPer(Operator):
|
|||
|
||||
|
||||
class PDT_OT_PlacementNormal(Operator):
|
||||
"""Use Normal, or Perpendicular Placement."""
|
||||
"""Use Normal, or Perpendicular Placement"""
|
||||
|
||||
bl_idname = "pdt.normal"
|
||||
bl_label = "Normal Mode"
|
||||
|
@ -406,7 +406,7 @@ class PDT_OT_PlacementNormal(Operator):
|
|||
|
||||
|
||||
class PDT_OT_PlacementCen(Operator):
|
||||
"""Use Placement at Arc Centre."""
|
||||
"""Use Placement at Arc Centre"""
|
||||
|
||||
bl_idname = "pdt.centre"
|
||||
bl_label = "Centre Mode"
|
||||
|
@ -451,7 +451,7 @@ class PDT_OT_PlacementCen(Operator):
|
|||
|
||||
|
||||
class PDT_OT_PlacementInt(Operator):
|
||||
"""Use Intersection, or Convergence Placement."""
|
||||
"""Use Intersection, or Convergence Placement"""
|
||||
|
||||
bl_idname = "pdt.intersect"
|
||||
bl_label = "Intersect Mode"
|
||||
|
@ -497,7 +497,7 @@ class PDT_OT_PlacementInt(Operator):
|
|||
|
||||
|
||||
class PDT_OT_JoinVerts(Operator):
|
||||
"""Join 2 Free Vertices into an Edge."""
|
||||
"""Join 2 Free Vertices into an Edge"""
|
||||
|
||||
bl_idname = "pdt.join"
|
||||
bl_label = "Join 2 Vertices"
|
||||
|
@ -531,7 +531,7 @@ class PDT_OT_JoinVerts(Operator):
|
|||
|
||||
|
||||
class PDT_OT_Fillet(Operator):
|
||||
"""Fillet Edges by Vertex, Set Use Verts to False for Extruded Structure."""
|
||||
"""Fillet Edges by Vertex, Set Use Verts to False for Extruded Structure"""
|
||||
|
||||
bl_idname = "pdt.fillet"
|
||||
bl_label = "Fillet"
|
||||
|
@ -587,7 +587,7 @@ class PDT_OT_Fillet(Operator):
|
|||
|
||||
|
||||
class PDT_OT_Angle2(Operator):
|
||||
"""Measure Distance and Angle in Working Plane, Also sets Deltas."""
|
||||
"""Measure Distance and Angle in Working Plane, Also sets Deltas"""
|
||||
|
||||
bl_idname = "pdt.angle2"
|
||||
bl_label = "Measure 2D"
|
||||
|
@ -614,7 +614,7 @@ class PDT_OT_Angle2(Operator):
|
|||
|
||||
|
||||
class PDT_OT_Angle3(Operator):
|
||||
"""Measure Distance and Angle in 3D Space."""
|
||||
"""Measure Distance and Angle in 3D Space"""
|
||||
|
||||
bl_idname = "pdt.angle3"
|
||||
bl_label = "Measure 3D"
|
||||
|
@ -641,7 +641,7 @@ class PDT_OT_Angle3(Operator):
|
|||
|
||||
|
||||
class PDT_OT_Origin(Operator):
|
||||
"""Move Object Origin to Cursor Location."""
|
||||
"""Move Object Origin to Cursor Location"""
|
||||
|
||||
bl_idname = "pdt.origin"
|
||||
bl_label = "Move Origin"
|
||||
|
@ -668,7 +668,7 @@ class PDT_OT_Origin(Operator):
|
|||
|
||||
|
||||
class PDT_OT_Taper(Operator):
|
||||
"""Taper Vertices at Angle in Chosen Axis Mode."""
|
||||
"""Taper Vertices at Angle in Chosen Axis Mode"""
|
||||
|
||||
bl_idname = "pdt.taper"
|
||||
bl_label = "Taper"
|
||||
|
|
|
@ -126,7 +126,7 @@ def extend_vertex(context):
|
|||
|
||||
|
||||
class PDT_OT_EdgeToFace(bpy.types.Operator):
|
||||
"""Extend Selected Edge to Projected Intersection with Selected Face."""
|
||||
"""Extend Selected Edge to Projected Intersection with Selected Face"""
|
||||
|
||||
bl_idname = "pdt.edge_to_face"
|
||||
bl_label = "Extend Edge to Face"
|
||||
|
|
|
@ -30,7 +30,7 @@ from .pdt_msg_strings import PDT_ERR_NO_LIBRARY, PDT_ERR_OBJECTMODE
|
|||
|
||||
|
||||
class PDT_OT_LibShow(Operator):
|
||||
"""Show Library File Details."""
|
||||
"""Show Library File Details"""
|
||||
|
||||
bl_idname = "pdt.lib_show"
|
||||
bl_label = "Show Library Details"
|
||||
|
@ -59,7 +59,7 @@ class PDT_OT_LibShow(Operator):
|
|||
|
||||
|
||||
class PDT_OT_Append(Operator):
|
||||
"""Append from Library at cursor Location."""
|
||||
"""Append from Library at cursor Location"""
|
||||
|
||||
bl_idname = "pdt.append"
|
||||
bl_label = "Append"
|
||||
|
@ -141,7 +141,7 @@ class PDT_OT_Append(Operator):
|
|||
|
||||
|
||||
class PDT_OT_Link(Operator):
|
||||
"""Link from Library at Object's Origin."""
|
||||
"""Link from Library at Object's Origin"""
|
||||
|
||||
bl_idname = "pdt.link"
|
||||
bl_label = "Link"
|
||||
|
|
|
@ -38,7 +38,7 @@ from .pdt_msg_strings import (
|
|||
|
||||
|
||||
class PDT_OT_ModalDrawOperator(bpy.types.Operator):
|
||||
"""Show/Hide Pivot Point."""
|
||||
"""Show/Hide Pivot Point"""
|
||||
|
||||
bl_idname = "pdt.modaldraw"
|
||||
bl_label = "PDT Modal Draw"
|
||||
|
@ -113,7 +113,7 @@ class PDT_OT_ModalDrawOperator(bpy.types.Operator):
|
|||
|
||||
|
||||
class PDT_OT_ViewPlaneRotate(Operator):
|
||||
"""Rotate Selected Vertices about Pivot Point in View Plane."""
|
||||
"""Rotate Selected Vertices about Pivot Point in View Plane"""
|
||||
|
||||
bl_idname = "pdt.viewplanerot"
|
||||
bl_label = "PDT View Rotate"
|
||||
|
@ -177,7 +177,7 @@ class PDT_OT_ViewPlaneRotate(Operator):
|
|||
|
||||
|
||||
class PDT_OT_ViewPlaneScale(Operator):
|
||||
"""Scale Selected Vertices about Pivot Point."""
|
||||
"""Scale Selected Vertices about Pivot Point"""
|
||||
|
||||
bl_idname = "pdt.viewscale"
|
||||
bl_label = "PDT View Scale"
|
||||
|
@ -246,7 +246,7 @@ class PDT_OT_ViewPlaneScale(Operator):
|
|||
|
||||
|
||||
class PDT_OT_PivotToCursor(Operator):
|
||||
"""Set The Pivot Point to Cursor Location."""
|
||||
"""Set The Pivot Point to Cursor Location"""
|
||||
|
||||
bl_idname = "pdt.pivotcursor"
|
||||
bl_label = "PDT Pivot To Cursor"
|
||||
|
@ -274,7 +274,7 @@ class PDT_OT_PivotToCursor(Operator):
|
|||
|
||||
|
||||
class PDT_OT_CursorToPivot(Operator):
|
||||
"""Set The Cursor Location to Pivot Point."""
|
||||
"""Set The Cursor Location to Pivot Point"""
|
||||
|
||||
bl_idname = "pdt.cursorpivot"
|
||||
bl_label = "PDT Cursor To Pivot"
|
||||
|
@ -300,7 +300,7 @@ class PDT_OT_CursorToPivot(Operator):
|
|||
|
||||
|
||||
class PDT_OT_PivotSelected(Operator):
|
||||
"""Set Pivot Point to Selected Geometry."""
|
||||
"""Set Pivot Point to Selected Geometry"""
|
||||
|
||||
bl_idname = "pdt.pivotselected"
|
||||
bl_label = "PDT Pivot to Selected"
|
||||
|
@ -361,7 +361,7 @@ class PDT_OT_PivotSelected(Operator):
|
|||
|
||||
|
||||
class PDT_OT_PivotOrigin(Operator):
|
||||
"""Set Pivot Point at Object Origin."""
|
||||
"""Set Pivot Point at Object Origin"""
|
||||
|
||||
bl_idname = "pdt.pivotorigin"
|
||||
bl_label = "PDT Pivot to Object Origin"
|
||||
|
@ -410,7 +410,7 @@ class PDT_OT_PivotOrigin(Operator):
|
|||
|
||||
|
||||
class PDT_OT_PivotWrite(Operator):
|
||||
"""Write Pivot Point Location to Object."""
|
||||
"""Write Pivot Point Location to Object"""
|
||||
|
||||
bl_idname = "pdt.pivotwrite"
|
||||
bl_label = "PDT Write PP to Object?"
|
||||
|
@ -467,7 +467,7 @@ class PDT_OT_PivotWrite(Operator):
|
|||
|
||||
|
||||
class PDT_OT_PivotRead(Operator):
|
||||
"""Read Pivot Point Location from Object."""
|
||||
"""Read Pivot Point Location from Object"""
|
||||
|
||||
bl_idname = "pdt.pivotread"
|
||||
bl_label = "PDT Read PP"
|
||||
|
|
|
@ -211,7 +211,7 @@ class PDT_OT_ViewIso(Operator):
|
|||
bl_idname = "pdt.viewiso"
|
||||
bl_label = "Isometric View"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
bl_description = "Isometric View."
|
||||
bl_description = "Isometric View"
|
||||
|
||||
def execute(self, context):
|
||||
"""Set Isometric View.
|
||||
|
@ -238,7 +238,7 @@ class PDT_OT_Reset3DView(Operator):
|
|||
bl_idname = "pdt.reset_3d_view"
|
||||
bl_label = "Reset 3D View"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
bl_description = "Reset 3D View to Blender Defaults."
|
||||
bl_description = "Reset 3D View to Blender Defaults"
|
||||
|
||||
def execute(self, context):
|
||||
"""Reset 3D View to Blender Defaults.
|
||||
|
|
|
@ -245,7 +245,7 @@ def intersect_all(context):
|
|||
return
|
||||
|
||||
class PDT_OT_IntersectAllEdges(bpy.types.Operator):
|
||||
"""Cut Selected Edges at All Intersections."""
|
||||
"""Cut Selected Edges at All Intersections"""
|
||||
|
||||
bl_idname = "pdt.intersectall"
|
||||
bl_label = "Intersect All Edges"
|
||||
|
|
|
@ -433,7 +433,7 @@ class RenderPovSettingsScene(PropertyGroup):
|
|||
" to scattering in the direction of the light and negative "
|
||||
"values lead to scattering in the opposite direction of the "
|
||||
"light. Larger values of e (or smaller values in the negative"
|
||||
" case) increase the directional property of the scattering.",
|
||||
" case) increase the directional property of the scattering",
|
||||
precision=2,
|
||||
step=0.01,
|
||||
min=-1.0,
|
||||
|
|
|
@ -5987,7 +5987,7 @@ class PovrayRender(bpy.types.RenderEngine):
|
|||
#################################Operators########################################
|
||||
##################################################################################
|
||||
class RenderPovTexturePreview(Operator):
|
||||
"""Export only files necessary to texture preview and render image."""
|
||||
"""Export only files necessary to texture preview and render image"""
|
||||
|
||||
bl_idname = "tex.preview_update"
|
||||
bl_label = "Update preview"
|
||||
|
|
|
@ -838,7 +838,7 @@ class LIGHT_MT_POV_presets(Menu):
|
|||
|
||||
|
||||
class LIGHT_OT_POV_add_preset(AddPresetBase, Operator):
|
||||
"""Use this class to define pov world buttons."""
|
||||
"""Use this class to define pov world buttons"""
|
||||
|
||||
'''Add a Light Preset'''
|
||||
bl_idname = "object.light_preset_add"
|
||||
|
@ -1184,7 +1184,7 @@ del properties_data_light
|
|||
|
||||
|
||||
class WORLD_PT_POV_world(WorldButtonsPanel, Panel):
|
||||
"""Use this class to define pov world buttons."""
|
||||
"""Use this class to define pov world buttons"""
|
||||
|
||||
bl_label = "World"
|
||||
COMPAT_ENGINES = {'POVRAY_RENDER'}
|
||||
|
@ -1564,7 +1564,7 @@ class POV_RADIOSITY_MT_presets(Menu):
|
|||
|
||||
|
||||
class RENDER_OT_POV_radiosity_add_preset(AddPresetBase, Operator):
|
||||
"""Use this class to define pov radiosity add presets button."""
|
||||
"""Use this class to define pov radiosity add presets button"""
|
||||
|
||||
'''Add a Radiosity Preset'''
|
||||
bl_idname = "scene.radiosity_preset_add"
|
||||
|
@ -4364,7 +4364,7 @@ class CAMERA_PT_POV_replacement_text(CameraDataButtonsPanel, Panel):
|
|||
|
||||
|
||||
class TEXT_OT_POV_insert(Operator):
|
||||
"""Use this class to create blender text editor operator to insert pov snippets like other pov IDEs."""
|
||||
"""Use this class to create blender text editor operator to insert pov snippets like other pov IDEs"""
|
||||
|
||||
bl_idname = "text.povray_insert"
|
||||
bl_label = "Insert"
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
|
||||
bl_info = {
|
||||
"name": "Rigify",
|
||||
"version": (0, 6, 2),
|
||||
"version": (0, 6, 3),
|
||||
"author": "Nathan Vegdahl, Lucio Rossi, Ivan Cappiello, Alexander Gavrilov",
|
||||
"blender": (2, 82, 0),
|
||||
"description": "Automatic rigging from building-block components",
|
||||
|
|
|
@ -63,6 +63,24 @@ def set_bone_layers(bone, layers, combine=False):
|
|||
# UI utilities
|
||||
#=============================================
|
||||
|
||||
|
||||
def layout_layer_buttons(layout, params, option, active_layers):
|
||||
"Draw a layer selection button UI with certain layers marked with dots."
|
||||
outer = layout.row()
|
||||
|
||||
for x in [0, 8]:
|
||||
col = outer.column(align=True)
|
||||
|
||||
for y in [0, 16]:
|
||||
row = col.row(align=True)
|
||||
|
||||
for i in range(x+y, x+y+8):
|
||||
row.prop(
|
||||
params, option, index=i, toggle=True, text="",
|
||||
icon="LAYER_ACTIVE" if active_layers[i] else "NONE"
|
||||
)
|
||||
|
||||
|
||||
class ControlLayersOption:
|
||||
def __init__(self, name, toggle_name=None, toggle_default=True, description="Set of control layers"):
|
||||
self.name = name
|
||||
|
@ -131,8 +149,9 @@ class ControlLayersOption:
|
|||
if not active:
|
||||
return
|
||||
|
||||
row = box.row(align=True)
|
||||
row.prop(params, self.layers_option, text="")
|
||||
active_layers = bpy.context.active_pose_bone.bone.layers[:]
|
||||
|
||||
layout_layer_buttons(box, params, self.layers_option, active_layers)
|
||||
|
||||
|
||||
ControlLayersOption.FK = ControlLayersOption('fk', description="Layers for the FK controls to be on")
|
||||
|
|
Loading…
Reference in New Issue