216 lines
8.0 KiB
Python
216 lines
8.0 KiB
Python
|
||
"""
|
||
Plugin for making an asset library of all blender file found in a folder
|
||
"""
|
||
|
||
|
||
from .scan_folder import ScanFolder
|
||
from ..core.bl_utils import load_datablocks
|
||
from ..core.template import Template
|
||
|
||
import bpy
|
||
from bpy.props import (StringProperty, IntProperty, BoolProperty)
|
||
import re
|
||
from pathlib import Path
|
||
from itertools import groupby
|
||
import uuid
|
||
import os
|
||
import shutil
|
||
import json
|
||
import time
|
||
from pprint import pprint
|
||
|
||
|
||
class Conform(ScanFolder):
|
||
|
||
name = "Conform"
|
||
source_directory : StringProperty(subtype='DIR_PATH')
|
||
|
||
target_template_file : StringProperty()
|
||
target_template_info : StringProperty()
|
||
target_template_image : StringProperty()
|
||
target_template_video : StringProperty()
|
||
|
||
def draw_prefs(self, layout):
|
||
layout.prop(self, "source_directory", text="Source : Directory")
|
||
|
||
col = layout.column(align=True)
|
||
col.prop(self, "source_template_file", icon='COPY_ID', text='Template file')
|
||
col.prop(self, "source_template_image", icon='COPY_ID', text='Template image')
|
||
col.prop(self, "source_template_video", icon='COPY_ID', text='Template video')
|
||
col.prop(self, "source_template_info", icon='COPY_ID', text='Template info')
|
||
|
||
col = layout.column(align=True)
|
||
col.prop(self, "target_template_file", icon='COPY_ID', text='Target : Template file')
|
||
col.prop(self, "target_template_image", icon='COPY_ID', text='Template image')
|
||
col.prop(self, "target_template_video", icon='COPY_ID', text='Template video')
|
||
col.prop(self, "target_template_info", icon='COPY_ID', text='Template info')
|
||
|
||
def get_asset_bundle_path(self, asset_data):
|
||
"""Template file are relative"""
|
||
|
||
src_directory = Path(self.source_directory).resolve()
|
||
src_template_file = Template(self.source_template_file)
|
||
|
||
asset_path = Path(asset_data['filepath']).as_posix()
|
||
asset_path = self.format_path(asset_path)
|
||
|
||
rel_path = asset_path.relative_to(src_directory).as_posix()
|
||
field_data = src_template_file.parse(rel_path)
|
||
#field_data = {f"catalog_{k}": v for k, v in field_data.items()}
|
||
|
||
# Change the int in the template by string to allow format
|
||
#target_template_file = re.sub(r'{(\d+)}', r'{cat\1}', self.target_template_file)
|
||
|
||
format_data = self.format_asset_data(asset_data)
|
||
#format_data['asset_name'] = format_data['asset_name'].lower().replace(' ', '_')
|
||
|
||
path = Template(self.target_template_file).format(format_data, **field_data).with_suffix('.blend')
|
||
path = Path(self.bundle_directory, path).resolve()
|
||
|
||
return path
|
||
|
||
def set_asset_preview(self, asset, asset_data):
|
||
'''Load an externalize image as preview for an asset using the target template'''
|
||
|
||
image_template = self.target_template_image
|
||
if not image_template:
|
||
return
|
||
|
||
asset_path = self.get_asset_bundle_path(asset_data)
|
||
image_path = self.find_path(image_template, asset_data, filepath=asset_path)
|
||
|
||
if image_path:
|
||
with bpy.context.temp_override(id=asset):
|
||
bpy.ops.ed.lib_id_load_custom_preview(
|
||
filepath=str(image_path)
|
||
)
|
||
else:
|
||
print(f'No image found for {image_template} on {asset.name}')
|
||
|
||
if asset.preview:
|
||
return asset.preview
|
||
|
||
def generate_previews(self, cache_diff):
|
||
|
||
print('Generate previews...')
|
||
|
||
# if cache in (None, ''):
|
||
# cache = self.fetch()
|
||
# elif isinstance(cache, (Path, str)):
|
||
# cache = self.read_cache(cache)
|
||
|
||
if isinstance(cache, (Path, str)):
|
||
cache_diff = LibraryCacheDiff(cache_diff)
|
||
|
||
|
||
|
||
#TODO Support all multiple data_type
|
||
for asset_info in cache:
|
||
|
||
if asset_info.get('type', self.data_type) == 'FILE':
|
||
self.generate_blend_preview(asset_info)
|
||
else:
|
||
self.generate_asset_preview(asset_info)
|
||
|
||
def generate_asset_preview(self, asset_info):
|
||
"""Only generate preview when conforming a library"""
|
||
|
||
#print('\ngenerate_preview', asset_info['filepath'])
|
||
|
||
scn = bpy.context.scene
|
||
vl = bpy.context.view_layer
|
||
#Creating the preview for collection, object or material
|
||
#camera = scn.camera
|
||
|
||
data_type = self.data_type #asset_info['data_type']
|
||
asset_path = self.format_path(asset_info['filepath'])
|
||
|
||
# Check if a source video exists and if so copying it in the new directory
|
||
if self.source_template_video and self.target_template_video:
|
||
for asset_data in asset_info['assets']:
|
||
asset_data = dict(asset_data, filepath=asset_path)
|
||
|
||
dst_asset_path = self.get_asset_bundle_path(asset_data)
|
||
dst_video_path = self.format_path(self.target_template_video, asset_data, filepath=dst_asset_path)
|
||
if dst_video_path.exists():
|
||
print(f'The dest video {dst_video_path} already exist')
|
||
continue
|
||
|
||
src_video_path = self.find_path(self.source_template_video, asset_data)
|
||
if src_video_path:
|
||
print(f'Copy video from {src_video_path} to {dst_video_path}')
|
||
self.copy_file(src_video_path, dst_video_path)
|
||
|
||
# Check if asset as a preview image or need it to be generated
|
||
asset_data_names = {}
|
||
|
||
if self.target_template_image:
|
||
for asset_data in asset_info['assets']:
|
||
asset_data = dict(asset_data, filepath=asset_path)
|
||
name = asset_data['name']
|
||
dst_asset_path = self.get_asset_bundle_path(asset_data)
|
||
|
||
dst_image_path = self.format_path(self.target_template_image, asset_data, filepath=dst_asset_path)
|
||
if dst_image_path.exists():
|
||
print(f'The dest image {dst_image_path} already exist')
|
||
continue
|
||
|
||
# Check if a source image exists and if so copying it in the new directory
|
||
if self.source_template_image:
|
||
src_image_path = self.find_path(self.source_template_image, asset_data)
|
||
|
||
if src_image_path:
|
||
if src_image_path.suffix == dst_image_path.suffix:
|
||
self.copy_file(src_image_path, dst_image_path)
|
||
else:
|
||
|
||
print(src_image_path)
|
||
self.save_image(src_image_path, dst_image_path, remove=True)
|
||
|
||
continue
|
||
|
||
#Store in a dict all asset_data that does not have preview
|
||
asset_data_names[name] = dict(asset_data, image_path=dst_image_path)
|
||
|
||
|
||
if not asset_data_names:# No preview to generate
|
||
return
|
||
|
||
print('Making Preview for', list(asset_data_names.keys()))
|
||
|
||
asset_names = list(asset_data_names.keys())
|
||
assets = self.load_datablocks(asset_path, names=asset_names, link=True, type=data_type)
|
||
|
||
for asset in assets:
|
||
if not asset:
|
||
continue
|
||
|
||
asset_data = asset_data_names[asset.name]
|
||
image_path = asset_data['image_path']
|
||
|
||
if asset.preview:
|
||
print(f'Writing asset preview to {image_path}')
|
||
self.write_preview(asset.preview, image_path)
|
||
continue
|
||
|
||
if data_type == 'COLLECTION':
|
||
|
||
bpy.ops.object.collection_instance_add(name=asset.name)
|
||
|
||
bpy.ops.view3d.camera_to_view_selected()
|
||
instance = vl.objects.active
|
||
|
||
#scn.collection.children.link(asset)
|
||
|
||
scn.render.filepath = str(image_path)
|
||
|
||
print(f'Render asset {asset.name} to {image_path}')
|
||
bpy.ops.render.render(write_still=True)
|
||
|
||
#instance.user_clear()
|
||
asset.user_clear()
|
||
|
||
bpy.data.objects.remove(instance)
|
||
|
||
bpy.ops.outliner.orphans_purge(do_local_ids=True, do_linked_ids=True, do_recursive=True) |