mirror of
https://github.com/blender/blender-addons.git
synced 2025-08-16 15:35:05 +00:00
333 lines
12 KiB
Python
333 lines
12 KiB
Python
# ##### 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 #####
|
|
|
|
|
|
if "bpy" in locals():
|
|
from importlib import reload
|
|
|
|
paths = reload(paths)
|
|
utils = reload(utils)
|
|
bg_blender = reload(bg_blender)
|
|
else:
|
|
from blenderkit import paths, utils, bg_blender
|
|
|
|
import tempfile, os, subprocess, json, sys
|
|
|
|
import bpy
|
|
|
|
BLENDERKIT_EXPORT_DATA_FILE = "data.json"
|
|
|
|
|
|
def check_thumbnail(props, imgpath):
|
|
img = utils.get_hidden_image(imgpath, 'upload_preview', force_reload=True)
|
|
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 = ''
|
|
return
|
|
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
|
|
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, context):
|
|
# Prepare to save the file
|
|
mainmodel = utils.get_active_model()
|
|
mainmodel.blenderkit.is_generating_thumbnail = True
|
|
mainmodel.blenderkit.thumbnail_generating_state = 'starting blender instance'
|
|
|
|
binary_path = bpy.app.binary_path
|
|
script_path = os.path.dirname(os.path.realpath(__file__))
|
|
basename, ext = os.path.splitext(bpy.data.filepath)
|
|
if not basename:
|
|
basename = os.path.join(basename, "temp")
|
|
if not ext:
|
|
ext = ".blend"
|
|
asset_name = mainmodel.name
|
|
tempdir = tempfile.mkdtemp()
|
|
|
|
file_dir = os.path.dirname(bpy.data.filepath)
|
|
thumb_path = os.path.join(file_dir, asset_name)
|
|
rel_thumb_path = os.path.join('//', asset_name)
|
|
|
|
i = 0
|
|
while os.path.isfile(thumb_path + '.jpg'):
|
|
thumb_path = os.path.join(file_dir, asset_name + '_' + str(i).zfill(4))
|
|
rel_thumb_path = os.path.join('//', asset_name + '_' + str(i).zfill(4))
|
|
i += 1
|
|
|
|
filepath = os.path.join(tempdir, "thumbnailer_blenderkit" + ext)
|
|
tfpath = paths.get_thumbnailer_filepath()
|
|
datafile = os.path.join(tempdir, BLENDERKIT_EXPORT_DATA_FILE)
|
|
try:
|
|
# 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)
|
|
|
|
obs = utils.get_hierarchy(mainmodel)
|
|
obnames = []
|
|
for ob in obs:
|
|
obnames.append(ob.name)
|
|
with open(datafile, 'w') as s:
|
|
bkit = mainmodel.blenderkit
|
|
json.dump({
|
|
"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,
|
|
}, s)
|
|
|
|
|
|
|
|
proc = subprocess.Popen([
|
|
binary_path,
|
|
"--background",
|
|
"-noaudio",
|
|
tfpath,
|
|
"--python", os.path.join(script_path, "autothumb_model_bg.py"),
|
|
"--", datafile, filepath, thumb_path, tempdir
|
|
], bufsize=1, stdout=subprocess.PIPE, stdin=subprocess.PIPE, creationflags=utils.get_process_flags())
|
|
|
|
eval_path_computing = "bpy.data.objects['%s'].blenderkit.is_generating_thumbnail" % mainmodel.name
|
|
eval_path_state = "bpy.data.objects['%s'].blenderkit.thumbnail_generating_state" % mainmodel.name
|
|
eval_path = "bpy.data.objects['%s']" % mainmodel.name
|
|
|
|
bg_blender.add_bg_process(eval_path_computing=eval_path_computing, eval_path_state=eval_path_state,
|
|
eval_path=eval_path, process_type='THUMBNAILER', process=proc)
|
|
|
|
mainmodel.blenderkit.thumbnail = rel_thumb_path + '.jpg'
|
|
mainmodel.blenderkit.thumbnail_generating_state = 'Saving .blend file'
|
|
|
|
except Exception as e:
|
|
self.report({'WARNING'}, "Error while exporting file: %s" % str(e))
|
|
return {'FINISHED'}
|
|
|
|
|
|
def start_material_thumbnailer(self, context):
|
|
# Prepare to save the file
|
|
mat = bpy.context.active_object.active_material
|
|
mat.blenderkit.is_generating_thumbnail = True
|
|
mat.blenderkit.thumbnail_generating_state = 'starting blender instance'
|
|
|
|
binary_path = bpy.app.binary_path
|
|
script_path = os.path.dirname(os.path.realpath(__file__))
|
|
basename, ext = os.path.splitext(bpy.data.filepath)
|
|
if not basename:
|
|
basename = os.path.join(basename, "temp")
|
|
if not ext:
|
|
ext = ".blend"
|
|
asset_name = mat.name
|
|
tempdir = tempfile.mkdtemp()
|
|
|
|
file_dir = os.path.dirname(bpy.data.filepath)
|
|
|
|
thumb_path = os.path.join(file_dir, asset_name)
|
|
rel_thumb_path = os.path.join('//', mat.name)
|
|
i = 0
|
|
while os.path.isfile(thumb_path + '.png'):
|
|
thumb_path = os.path.join(file_dir, mat.name + '_' + str(i).zfill(4))
|
|
rel_thumb_path = os.path.join('//', mat.name + '_' + str(i).zfill(4))
|
|
i += 1
|
|
|
|
filepath = os.path.join(tempdir, "material_thumbnailer_cycles" + ext)
|
|
tfpath = paths.get_material_thumbnailer_filepath()
|
|
datafile = os.path.join(tempdir, BLENDERKIT_EXPORT_DATA_FILE)
|
|
try:
|
|
# 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)
|
|
|
|
with open(datafile, 'w') as s:
|
|
bkit = mat.blenderkit
|
|
json.dump({
|
|
"type": "material",
|
|
"material": mat.name,
|
|
"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,
|
|
}, s)
|
|
|
|
|
|
proc = subprocess.Popen([
|
|
binary_path,
|
|
"--background",
|
|
"-noaudio",
|
|
tfpath,
|
|
"--python", os.path.join(script_path, "autothumb_material_bg.py"),
|
|
"--", datafile, filepath, thumb_path, tempdir
|
|
], bufsize=1, stdout=subprocess.PIPE, stdin=subprocess.PIPE, creationflags=utils.get_process_flags())
|
|
|
|
eval_path_computing = "bpy.data.materials['%s'].blenderkit.is_generating_thumbnail" % mat.name
|
|
eval_path_state = "bpy.data.materials['%s'].blenderkit.thumbnail_generating_state" % mat.name
|
|
eval_path = "bpy.data.materials['%s']" % mat.name
|
|
|
|
bg_blender.add_bg_process(eval_path_computing=eval_path_computing, eval_path_state=eval_path_state,
|
|
eval_path=eval_path, process_type='THUMBNAILER', process=proc)
|
|
|
|
mat.blenderkit.thumbnail = rel_thumb_path + '.png'
|
|
mat.blenderkit.thumbnail_generating_state = 'Saving .blend file'
|
|
except Exception as e:
|
|
self.report({'WARNING'}, "Error while packing file: %s" % str(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):
|
|
start_thumbnailer(self, context)
|
|
return {'FINISHED'}
|
|
|
|
def invoke(self, context, event):
|
|
wm = context.window_manager
|
|
if bpy.data.filepath == '':
|
|
title = "Can't render thumbnail"
|
|
message = "please save your file first"
|
|
|
|
def draw_message(self, context):
|
|
self.layout.label(text = message)
|
|
|
|
bpy.context.window_manager.popup_menu(draw_message, title=title, icon='INFO')
|
|
return {'FINISHED'}
|
|
|
|
return wm.invoke_props_dialog(self)
|
|
|
|
|
|
class GenerateMaterialThumbnailOperator(bpy.types.Operator):
|
|
"""Tooltip"""
|
|
bl_idname = "object.blenderkit_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):
|
|
start_material_thumbnailer(self, context)
|
|
|
|
return {'FINISHED'}
|
|
|
|
def invoke(self, context, event):
|
|
wm = context.window_manager
|
|
return wm.invoke_props_dialog(self)
|
|
|
|
|
|
def register_thumbnailer():
|
|
bpy.utils.register_class(GenerateThumbnailOperator)
|
|
bpy.utils.register_class(GenerateMaterialThumbnailOperator)
|
|
|
|
|
|
def unregister_thumbnailer():
|
|
bpy.utils.unregister_class(GenerateThumbnailOperator)
|
|
bpy.utils.unregister_class(GenerateMaterialThumbnailOperator)
|