forked from blender/blender-addons
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathautothumb.py
332 lines (269 loc) · 12.5 KB
/
autothumb.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
# ##### 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)