diff options
Diffstat (limited to 'blenderkit/autothumb.py')
-rw-r--r-- | blenderkit/autothumb.py | 671 |
1 files changed, 0 insertions, 671 deletions
diff --git a/blenderkit/autothumb.py b/blenderkit/autothumb.py deleted file mode 100644 index 330d31a2..00000000 --- a/blenderkit/autothumb.py +++ /dev/null @@ -1,671 +0,0 @@ -# ##### BEGIN GPL LICENSE BLOCK ##### -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software Foundation, -# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# ##### END GPL LICENSE BLOCK ##### - -from blenderkit import paths, utils, bg_blender, ui_panels, icons, tasks_queue, download - -import tempfile, os, subprocess, json, sys - -import bpy -from bpy.props import ( - FloatProperty, - IntProperty, - EnumProperty, - BoolProperty, - StringProperty, -) - -BLENDERKIT_EXPORT_DATA_FILE = "data.json" - -thumbnail_resolutions = ( - ('256', '256', ''), - ('512', '512', ''), - ('1024', '1024 - minimum for public', ''), - ('2048', '2048', ''), -) - -thumbnail_angles = ( - ('DEFAULT', 'default', ''), - ('FRONT', 'front', ''), - ('SIDE', 'side', ''), - ('TOP', 'top', ''), -) - -thumbnail_snap = ( - ('GROUND', 'ground', ''), - ('WALL', 'wall', ''), - ('CEILING', 'ceiling', ''), - ('FLOAT', 'floating', ''), -) - - -def get_texture_ui(tpath, iname): - tex = bpy.data.textures.get(iname) - - if tpath.startswith('//'): - tpath = bpy.path.abspath(tpath) - - if not tex or not tex.image or not tex.image.filepath == tpath: - tasks_queue.add_task((utils.get_hidden_image, (tpath, iname)), only_last=True) - tasks_queue.add_task((utils.get_hidden_texture, (iname,)), only_last=True) - return None - return tex - - -def check_thumbnail(props, imgpath): - img = utils.get_hidden_image(imgpath, 'upload_preview', force_reload=True) - # print(' check thumbnail ', img) - if img is not None: # and img.size[0] == img.size[1] and img.size[0] >= 512 and ( - # img.file_format == 'JPEG' or img.file_format == 'PNG'): - props.has_thumbnail = True - props.thumbnail_generating_state = '' - - tex = utils.get_hidden_texture(img.name) - # pcoll = icons.icon_collections["previews"] - # pcoll.load(img.name, img.filepath, 'IMAGE') - - return img - else: - props.has_thumbnail = False - output = '' - if img is None or img.size[0] == 0 or img.filepath.find('thumbnail_notready.jpg') > -1: - output += 'No thumbnail or wrong file path\n' - else: - pass; - # this is causing problems on some platforms, don't know why.. - # if img.size[0] != img.size[1]: - # output += 'image not a square\n' - # if img.size[0] < 512: - # output += 'image too small, should be at least 512x512\n' - # if img.file_format != 'JPEG' or img.file_format != 'PNG': - # output += 'image has to be a jpeg or png' - props.thumbnail_generating_state = output - - -def update_upload_model_preview(self, context): - ob = utils.get_active_model() - if ob is not None: - props = ob.blenderkit - imgpath = props.thumbnail - img = check_thumbnail(props, imgpath) - - -def update_upload_scene_preview(self, context): - s = bpy.context.scene - props = s.blenderkit - imgpath = props.thumbnail - check_thumbnail(props, imgpath) - - -def update_upload_material_preview(self, context): - if hasattr(bpy.context, 'active_object') \ - and bpy.context.view_layer.objects.active is not None \ - and bpy.context.active_object.active_material is not None: - mat = bpy.context.active_object.active_material - props = mat.blenderkit - imgpath = props.thumbnail - check_thumbnail(props, imgpath) - - -def update_upload_brush_preview(self, context): - brush = utils.get_active_brush() - if brush is not None: - props = brush.blenderkit - imgpath = bpy.path.abspath(brush.icon_filepath) - check_thumbnail(props, imgpath) - - -def start_thumbnailer(self=None, json_args=None, props=None, wait=False, add_bg_process=True): - # Prepare to save the file - - binary_path = bpy.app.binary_path - script_path = os.path.dirname(os.path.realpath(__file__)) - - ext = '.blend' - - tfpath = paths.get_thumbnailer_filepath() - datafile = os.path.join(json_args['tempdir'], BLENDERKIT_EXPORT_DATA_FILE) - try: - with open(datafile, 'w', encoding='utf-8') as s: - json.dump(json_args, s, ensure_ascii=False, indent=4) - - proc = subprocess.Popen([ - binary_path, - "--background", - "-noaudio", - tfpath, - "--python", os.path.join(script_path, "autothumb_model_bg.py"), - "--", datafile, - ], bufsize=1, stdout=subprocess.PIPE, stdin=subprocess.PIPE, creationflags=utils.get_process_flags()) - - eval_path_computing = "bpy.data.objects['%s'].blenderkit.is_generating_thumbnail" % json_args['asset_name'] - eval_path_state = "bpy.data.objects['%s'].blenderkit.thumbnail_generating_state" % json_args['asset_name'] - eval_path = "bpy.data.objects['%s']" % json_args['asset_name'] - - bg_blender.add_bg_process(name = f"{json_args['asset_name']} thumbnailer" ,eval_path_computing=eval_path_computing, eval_path_state=eval_path_state, - eval_path=eval_path, process_type='THUMBNAILER', process=proc) - - - except Exception as e: - self.report({'WARNING'}, "Error while exporting file: %s" % str(e)) - return {'FINISHED'} - - -def start_material_thumbnailer(self=None, json_args=None, props=None, wait=False, add_bg_process=True): - ''' - - Parameters - ---------- - self - json_args - all arguments: - props - blenderkit upload props with thumbnail settings, to communicate back, if not present, not used. - wait - wait for the rendering to finish - - Returns - ------- - - ''' - if props: - props.is_generating_thumbnail = True - props.thumbnail_generating_state = 'starting blender instance' - - binary_path = bpy.app.binary_path - script_path = os.path.dirname(os.path.realpath(__file__)) - - tfpath = paths.get_material_thumbnailer_filepath() - datafile = os.path.join(json_args['tempdir'], BLENDERKIT_EXPORT_DATA_FILE) - - try: - with open(datafile, 'w', encoding='utf-8') as s: - json.dump(json_args, s, ensure_ascii=False, indent=4) - - proc = subprocess.Popen([ - binary_path, - "--background", - "-noaudio", - tfpath, - "--python", os.path.join(script_path, "autothumb_material_bg.py"), - "--", datafile, - ], bufsize=1, stdout=subprocess.PIPE, stdin=subprocess.PIPE, creationflags=utils.get_process_flags()) - - eval_path_computing = "bpy.data.materials['%s'].blenderkit.is_generating_thumbnail" % json_args['asset_name'] - eval_path_state = "bpy.data.materials['%s'].blenderkit.thumbnail_generating_state" % json_args['asset_name'] - eval_path = "bpy.data.materials['%s']" % json_args['asset_name'] - - bg_blender.add_bg_process(name=f"{json_args['asset_name']} thumbnailer", eval_path_computing=eval_path_computing, - eval_path_state=eval_path_state, - eval_path=eval_path, process_type='THUMBNAILER', process=proc) - if props: - props.thumbnail_generating_state = 'Saving .blend file' - - if wait: - while proc.poll() is None: - stdout_data, stderr_data = proc.communicate() - print(stdout_data) - except Exception as e: - if self: - self.report({'WARNING'}, "Error while packing file: %s" % str(e)) - else: - print(e) - return {'FINISHED'} - - -class GenerateThumbnailOperator(bpy.types.Operator): - """Generate Cycles thumbnail for model assets""" - bl_idname = "object.blenderkit_generate_thumbnail" - bl_label = "BlenderKit Thumbnail Generator" - bl_options = {'REGISTER', 'INTERNAL'} - - @classmethod - def poll(cls, context): - return bpy.context.view_layer.objects.active is not None - - def draw(self, context): - ob = bpy.context.active_object - while ob.parent is not None: - ob = ob.parent - props = ob.blenderkit - layout = self.layout - layout.label(text='thumbnailer settings') - layout.prop(props, 'thumbnail_background_lightness') - layout.prop(props, 'thumbnail_angle') - layout.prop(props, 'thumbnail_snap_to') - 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): - asset = utils.get_active_model() - asset.blenderkit.is_generating_thumbnail = True - asset.blenderkit.thumbnail_generating_state = 'starting blender instance' - - tempdir = tempfile.mkdtemp() - ext = '.blend' - filepath = os.path.join(tempdir, "thumbnailer_blenderkit" + ext) - - path_can_be_relative = True - file_dir = os.path.dirname(bpy.data.filepath) - if file_dir == '': - file_dir = tempdir - path_can_be_relative = False - - an_slug = paths.slugify(asset.name) - thumb_path = os.path.join(file_dir, an_slug) - if path_can_be_relative: - rel_thumb_path = os.path.join('//', an_slug) - else: - rel_thumb_path = thumb_path - - - i = 0 - while os.path.isfile(thumb_path + '.jpg'): - thumb_path = os.path.join(file_dir, an_slug + '_' + str(i).zfill(4)) - rel_thumb_path = os.path.join('//', an_slug + '_' + str(i).zfill(4)) - i += 1 - bkit = asset.blenderkit - - bkit.thumbnail = rel_thumb_path + '.jpg' - bkit.thumbnail_generating_state = 'Saving .blend file' - - # if this isn't here, blender crashes. - bpy.context.preferences.filepaths.file_preview_type = 'NONE' - # save a copy of actual scene but don't interfere with the users models - - bpy.ops.wm.save_as_mainfile(filepath=filepath, compress=False, copy=True) - # get all included objects - obs = utils.get_hierarchy(asset) - obnames = [] - for ob in obs: - obnames.append(ob.name) - - args_dict = { - "type": "material", - "asset_name": asset.name, - "filepath": filepath, - "thumbnail_path": thumb_path, - "tempdir": tempdir, - } - thumbnail_args = { - "type": "model", - "models": str(obnames), - "thumbnail_angle": bkit.thumbnail_angle, - "thumbnail_snap_to": bkit.thumbnail_snap_to, - "thumbnail_background_lightness": bkit.thumbnail_background_lightness, - "thumbnail_resolution": bkit.thumbnail_resolution, - "thumbnail_samples": bkit.thumbnail_samples, - "thumbnail_denoising": bkit.thumbnail_denoising, - } - args_dict.update(thumbnail_args) - - start_thumbnailer(self, - json_args=args_dict, - props=asset.blenderkit, wait=False) - return {'FINISHED'} - - def invoke(self, context, event): - wm = context.window_manager - # if bpy.data.filepath == '': - # ui_panels.ui_message( - # title="Can't render thumbnail", - # message="please save your file first") - # - # return {'FINISHED'} - - return wm.invoke_props_dialog(self) - - -class ReGenerateThumbnailOperator(bpy.types.Operator): - """ - Generate default thumbnail with Cycles renderer and upload it. - Works also for assets from search results, without being downloaded before - """ - bl_idname = "object.blenderkit_regenerate_thumbnail" - bl_label = "BlenderKit Thumbnail Re-generate" - bl_options = {'REGISTER', 'INTERNAL'} - - asset_index: IntProperty(name="Asset Index", description='asset index in search results', default=-1) - - thumbnail_background_lightness: FloatProperty(name="Thumbnail Background Lightness", - description="set to make your material stand out", default=1.0, - min=0.01, max=10) - - thumbnail_angle: EnumProperty( - name='Thumbnail Angle', - items=thumbnail_angles, - default='DEFAULT', - description='thumbnailer angle', - ) - - thumbnail_snap_to: EnumProperty( - name='Model Snaps To:', - items=thumbnail_snap, - default='GROUND', - description='typical placing of the interior. Leave on ground for most objects that respect gravity :)', - ) - - thumbnail_resolution: EnumProperty( - name="Resolution", - items=thumbnail_resolutions, - description="Thumbnail resolution", - default="1024", - ) - - thumbnail_samples: IntProperty(name="Cycles Samples", - description="cycles samples setting", default=100, - min=5, max=5000) - thumbnail_denoising: BoolProperty(name="Use Denoising", - description="Use denoising", default=True) - - @classmethod - def poll(cls, context): - return True # bpy.context.view_layer.objects.active is not None - - def draw(self, context): - props = self - layout = self.layout - # layout.label('This will re-generate thumbnail and directly upload it to server. You should see your updated thumbnail online depending ') - layout.label(text='thumbnailer settings') - layout.prop(props, 'thumbnail_background_lightness') - layout.prop(props, 'thumbnail_angle') - layout.prop(props, 'thumbnail_snap_to') - 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): - if not self.asset_index > -1: - return {'CANCELLED'} - - # either get the data from search results - sr = bpy.context.window_manager['search results'] - asset_data = sr[self.asset_index].to_dict() - - tempdir = tempfile.mkdtemp() - - an_slug = paths.slugify(asset_data['name']) - thumb_path = os.path.join(tempdir, an_slug) - - - args_dict = { - "type": "material", - "asset_name": asset_data['name'], - "asset_data": asset_data, - # "filepath": filepath, - "thumbnail_path": thumb_path, - "tempdir": tempdir, - "do_download": True, - "upload_after_render": True, - } - thumbnail_args = { - "type": "model", - "thumbnail_angle": self.thumbnail_angle, - "thumbnail_snap_to": self.thumbnail_snap_to, - "thumbnail_background_lightness": self.thumbnail_background_lightness, - "thumbnail_resolution": self.thumbnail_resolution, - "thumbnail_samples": self.thumbnail_samples, - "thumbnail_denoising": self.thumbnail_denoising, - } - args_dict.update(thumbnail_args) - - start_thumbnailer(self, - json_args=args_dict, - wait=False) - return {'FINISHED'} - - def invoke(self, context, event): - wm = context.window_manager - # if bpy.data.filepath == '': - # ui_panels.ui_message( - # title="Can't render thumbnail", - # message="please save your file first") - # - # return {'FINISHED'} - - return wm.invoke_props_dialog(self) - - -class GenerateMaterialThumbnailOperator(bpy.types.Operator): - """Generate default thumbnail with Cycles renderer""" - bl_idname = "object.blenderkit_generate_material_thumbnail" - bl_label = "BlenderKit Material Thumbnail Generator" - bl_options = {'REGISTER', 'INTERNAL'} - - @classmethod - def poll(cls, context): - return bpy.context.view_layer.objects.active is not None - - def check(self, context): - return True - - def draw(self, context): - layout = self.layout - props = bpy.context.active_object.active_material.blenderkit - layout.prop(props, 'thumbnail_generator_type') - layout.prop(props, 'thumbnail_scale') - layout.prop(props, 'thumbnail_background') - if props.thumbnail_background: - layout.prop(props, 'thumbnail_background_lightness') - layout.prop(props, 'thumbnail_resolution') - 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): - asset = bpy.context.active_object.active_material - tempdir = tempfile.mkdtemp() - filepath = os.path.join(tempdir, "material_thumbnailer_cycles.blend") - # if this isn't here, blender crashes. - bpy.context.preferences.filepaths.file_preview_type = 'NONE' - - # save a copy of actual scene but don't interfere with the users models - bpy.ops.wm.save_as_mainfile(filepath=filepath, compress=False, copy=True) - - thumb_dir = os.path.dirname(bpy.data.filepath) - an_slug = paths.slugify(asset.name) - - thumb_path = os.path.join(thumb_dir, an_slug) - rel_thumb_path = os.path.join('//', an_slug) - - # auto increase number of the generated thumbnail. - i = 0 - while os.path.isfile(thumb_path + '.png'): - thumb_path = os.path.join(thumb_dir, an_slug + '_' + str(i).zfill(4)) - rel_thumb_path = os.path.join('//', an_slug + '_' + str(i).zfill(4)) - i += 1 - - asset.blenderkit.thumbnail = rel_thumb_path + '.png' - bkit = asset.blenderkit - - args_dict = { - "type": "material", - "asset_name": asset.name, - "filepath": filepath, - "thumbnail_path": thumb_path, - "tempdir": tempdir, - } - - thumbnail_args = { - "thumbnail_type": bkit.thumbnail_generator_type, - "thumbnail_scale": bkit.thumbnail_scale, - "thumbnail_background": bkit.thumbnail_background, - "thumbnail_background_lightness": bkit.thumbnail_background_lightness, - "thumbnail_resolution": bkit.thumbnail_resolution, - "thumbnail_samples": bkit.thumbnail_samples, - "thumbnail_denoising": bkit.thumbnail_denoising, - "adaptive_subdivision": bkit.adaptive_subdivision, - "texture_size_meters": bkit.texture_size_meters, - } - args_dict.update(thumbnail_args) - start_material_thumbnailer(self, - json_args=args_dict, - props=asset.blenderkit, wait=False) - - return {'FINISHED'} - - def invoke(self, context, event): - wm = context.window_manager - return wm.invoke_props_dialog(self) - - -class ReGenerateMaterialThumbnailOperator(bpy.types.Operator): - """ - Generate default thumbnail with Cycles renderer and upload it. - Works also for assets from search results, without being downloaded before - """ - bl_idname = "object.blenderkit_regenerate_material_thumbnail" - bl_label = "BlenderKit Material Thumbnail Re-Generator" - bl_options = {'REGISTER', 'INTERNAL'} - - asset_index: IntProperty(name="Asset Index", description='asset index in search results', default=-1) - - thumbnail_scale: FloatProperty(name="Thumbnail Object Size", - description="Size of material preview object in meters." - "Change for materials that look better at sizes different than 1m", - default=1, min=0.00001, max=10) - thumbnail_background: BoolProperty(name="Thumbnail Background (for Glass only)", - description="For refractive materials, you might need a background.\n" - "Don't use for other types of materials.\n" - "Transparent background is preferred", - default=False) - thumbnail_background_lightness: FloatProperty(name="Thumbnail Background Lightness", - description="Set to make your material stand out with enough contrast", - default=.9, - min=0.00001, max=1) - thumbnail_samples: IntProperty(name="Cycles Samples", - description="Cycles samples", default=100, - min=5, max=5000) - thumbnail_denoising: BoolProperty(name="Use Denoising", - description="Use denoising", default=True) - adaptive_subdivision: BoolProperty(name="Adaptive Subdivide", - description="Use adaptive displacement subdivision", default=False) - - thumbnail_resolution: EnumProperty( - name="Resolution", - items=thumbnail_resolutions, - description="Thumbnail resolution", - default="1024", - ) - - thumbnail_generator_type: EnumProperty( - name="Thumbnail Style", - items=( - ('BALL', 'Ball', ""), - ('BALL_COMPLEX', 'Ball complex', 'Complex ball to highlight edgewear or material thickness'), - ('FLUID', 'Fluid', 'Fluid'), - ('CLOTH', 'Cloth', 'Cloth'), - ('HAIR', 'Hair', 'Hair ') - ), - description="Style of asset", - default="BALL", - ) - - @classmethod - def poll(cls, context): - return True # bpy.context.view_layer.objects.active is not None - - def check(self, context): - return True - - def draw(self, context): - layout = self.layout - props = self - layout.prop(props, 'thumbnail_generator_type') - layout.prop(props, 'thumbnail_scale') - layout.prop(props, 'thumbnail_background') - if props.thumbnail_background: - layout.prop(props, 'thumbnail_background_lightness') - layout.prop(props, 'thumbnail_resolution') - 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): - - if not self.asset_index > -1: - return {'CANCELLED'} - - # either get the data from search results - sr = bpy.context.window_manager['search results'] - asset_data = sr[self.asset_index].to_dict() - an_slug = paths.slugify(asset_data['name']) - - tempdir = tempfile.mkdtemp() - - thumb_path = os.path.join(tempdir,an_slug) - - args_dict = { - "type": "material", - "asset_name": asset_data['name'], - "asset_data": asset_data, - "thumbnail_path": thumb_path, - "tempdir": tempdir, - "do_download": True, - "upload_after_render": True, - } - thumbnail_args = { - "thumbnail_type": self.thumbnail_generator_type, - "thumbnail_scale": self.thumbnail_scale, - "thumbnail_background": self.thumbnail_background, - "thumbnail_background_lightness": self.thumbnail_background_lightness, - "thumbnail_resolution": self.thumbnail_resolution, - "thumbnail_samples": self.thumbnail_samples, - "thumbnail_denoising": self.thumbnail_denoising, - "adaptive_subdivision": self.adaptive_subdivision, - "texture_size_meters": utils.get_param(asset_data, 'textureSizeMeters', 1.0), - } - args_dict.update(thumbnail_args) - start_material_thumbnailer(self, - json_args=args_dict, - wait=False) - - return {'FINISHED'} - - def invoke(self, context, event): - # scene = bpy.context.scene - # ui_props = bpy.context.window_manager.blenderkitUI - # if ui_props.active_index > -1: - # sr = bpy.context.window_manager['search results'] - # self.asset_data = dict(sr[ui_props.active_index]) - # else: - # - # active_asset = utils.get_active_asset_by_type(asset_type = self.asset_type) - # self.asset_data = active_asset.get('asset_data') - - wm = context.window_manager - return wm.invoke_props_dialog(self) - - -def register_thumbnailer(): - bpy.utils.register_class(GenerateThumbnailOperator) - bpy.utils.register_class(ReGenerateThumbnailOperator) - bpy.utils.register_class(GenerateMaterialThumbnailOperator) - bpy.utils.register_class(ReGenerateMaterialThumbnailOperator) - - -def unregister_thumbnailer(): - bpy.utils.unregister_class(GenerateThumbnailOperator) - bpy.utils.unregister_class(ReGenerateThumbnailOperator) - bpy.utils.unregister_class(GenerateMaterialThumbnailOperator) - bpy.utils.unregister_class(ReGenerateMaterialThumbnailOperator) |