diff --git a/CHANGELOG.md b/CHANGELOG.md index 720d1f9..cb9e544 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +2.0.0 + +- fix: error using playblast (api changes of Blender 3.0+) + 1.9.9 - fix: Bug setting GP layers actions on/off diff --git a/OP_playblast.py b/OP_playblast.py index 8b3012d..2ab4010 100644 --- a/OP_playblast.py +++ b/OP_playblast.py @@ -40,6 +40,8 @@ exclude = ( 'audio_bitrate', ] """ + +''' def render_with_restore(): class RenderFileRestorer: rd = bpy.context.scene.render @@ -80,8 +82,47 @@ def render_with_restore(): return RenderFileRestorer() +''' +class render_with_restore: + def __init__(self): + rd = bpy.context.scene.render + im = rd.image_settings + ff = rd.ffmpeg + # ffmpeg (ff) need to be before image_settings(im) in list + # otherwise __exit__ may try to restore settings of image mode in video mode ! + # ex : "RGBA" not found in ('BW', 'RGB') (will still not stop thx to try block) + self.zones = [rd, ff, im] + + self.val_dic = {} + self.cam = bpy.context.scene.camera + + def __enter__(self): + ## store attribute of data_path in self.zones list. + for data_path in self.zones: + self.val_dic[data_path] = {} + for attr in dir(data_path):#iterate in attribute of given datapath + if attr not in exclude and not attr.startswith('__') and not callable(getattr(data_path, attr)) and not data_path.is_property_readonly(attr): + self.val_dic[data_path][attr] = getattr(data_path, attr) + + if self.cam and self.cam.name == 'draw_cam': + if self.cam.parent: + bpy.context.scene.camera = self.cam.parent + + def __exit__(self, type, value, traceback): + ## restore attribute from self.zones list + for data_path, prop_dic in self.val_dic.items(): + for attr, val in prop_dic.items(): + try: + setattr(data_path, attr, val) + except Exception as e: + print(f"/!\ Impossible to re-assign: {attr} = {val}") + print(e) + + if self.cam: + bpy.context.scene.camera = self.cam + def playblast(viewport = False, stamping = True): scn = bpy.context.scene res_factor = scn.gptoolprops.resolution_percentage @@ -91,15 +132,15 @@ def playblast(viewport = False, stamping = True): ### can add propeties for personalisation as toolsetting props rd.resolution_percentage = res_factor - while ( rd.resolution_x * res_factor / 100 ) % 2 != 0:# rd.resolution_percentage + while ( rd.resolution_x * res_factor / 100 ) % 2 != 0: # rd.resolution_percentage rd.resolution_x = rd.resolution_x + 1 - while ( rd.resolution_y * res_factor / 100 ) % 2 != 0:# rd.resolution_percentage - rd.resolution_y = rd.resolution_y + 1 + while ( rd.resolution_y * res_factor / 100 ) % 2 != 0: # rd.resolution_percentage + rd.resolution_y = rd.resolution_y + 1 rd.image_settings.file_format = 'FFMPEG' ff.format = 'MPEG4' ff.codec = 'H264' - ff.constant_rate_factor = 'HIGH'# MEDIUM + ff.constant_rate_factor = 'HIGH' # MEDIUM ff.ffmpeg_preset = 'REALTIME' ff.gopsize = 10 ff.audio_codec = 'AAC' @@ -116,13 +157,13 @@ def playblast(viewport = False, stamping = True): # mode incermental or just use fulldate (cannot create conflict and filter OK but long name) blend = Path(bpy.data.filepath) date_format = "%Y-%m-%d_%H-%M-%S" - fp = join(blend.parent, "images", f'playblast_{blend.stem}_{strftime(date_format)}.mp4') + fp = join(blend.parent, "playblast", f'playblast_{blend.stem}_{strftime(date_format)}.mp4') #may need a properties for choosing location : bpy.types.Scene.qrd_savepath = bpy.props.StringProperty(subtype='DIR_PATH', description="Export location, if not specify, create a 'quick_render' directory aside blend location")#(change defaut name in user_prefernece) rd.filepath = fp rd.use_stamp = stamping# toolsetting.use_stamp# True for playblast #stamp options - rd.stamp_font_size = rd.stamp_font_size * res_factor / 100# rd.resolution_percentage + rd.stamp_font_size = int(rd.stamp_font_size * res_factor / 100) # rd.resolution_percentage # bpy.ops.render.render_wrap(use_view=viewport) ### render diff --git a/OP_playblast_bg.py b/OP_playblast_bg.py index 32c6e55..d420389 100644 --- a/OP_playblast_bg.py +++ b/OP_playblast_bg.py @@ -21,15 +21,20 @@ exclude = ( 'bl_rna', 'identifier','name_property','rna_type','properties', 'compare', 'to_string',#basic ) -def delete_file(filepath) : - try: - if os.path.isfile(filepath) : - print('removing', filepath) - os.remove(filepath) +def delete_file(filepath): + fp = Path(filepath) + if fp.exists() and fp.is_file(): + try: + print('removing', fp) + fp.unlink(missing_ok=False) + # os.remove(fp) return True - except PermissionError: - print(f'impossible to remove {filepath}') - return False + except PermissionError: + print(f'impossible to remove (permission error): {fp}') + return False + except FileNotFoundError: + print(f'Impossible to remove (file not found error): {fp}') + return False # render function def render_function(cmd, total_frame, scene) : @@ -58,7 +63,7 @@ def render_function(cmd, total_frame, scene) : frame_count += 1 try : # print('frame_count: ', frame_count, 'total_frame: ', total_frame) - bpy.context.window_manager.pblast_completion = frame_count / total_frame * 100 + bpy.context.window_manager.pblast_completion = int(frame_count / total_frame * 100) except AttributeError : #debug if debug : print("AttributeError avoided") @@ -231,9 +236,7 @@ class BGBLAST_OT_playblast_modal_check(bpy.types.Operator): self.report({'INFO'}, "Render Finished") - -### classic sauce - +""" def render_with_restore(): class RenderFileRestorer: rd = bpy.context.scene.render @@ -266,6 +269,38 @@ def render_with_restore(): print(e) return RenderFileRestorer() +""" + +class render_with_restore: + def __init__(self): + rd = bpy.context.scene.render + im = rd.image_settings + ff = rd.ffmpeg + # ffmpeg (ff) need to be before image_settings(im) in list + # otherwise __exit__ may try to restore settings of image mode in video mode ! + # ex : "RGBA" not found in ('BW', 'RGB') (will still not stop thx to try block) + + self.zones = [rd, ff, im] + + self.val_dic = {} + + def __enter__(self): + ## store attribute of data_path in self.zones list. + for data_path in self.zones: + self.val_dic[data_path] = {} + for attr in dir(data_path):#iterate in attribute of given datapath + if attr not in exclude and not attr.startswith('__') and not callable(getattr(data_path, attr)) and not data_path.is_property_readonly(attr): + self.val_dic[data_path][attr] = getattr(data_path, attr) + + def __exit__(self, type, value, traceback): + ## restore attribute from self.zones list + for data_path, prop_dic in self.val_dic.items(): + for attr, val in prop_dic.items(): + try: + setattr(data_path, attr, val) + except Exception as e: + print(f"/!\ Impossible to re-assign: {attr} = {val}") + print(e) def playblast(context, viewport = False, stamping = True): @@ -325,7 +360,7 @@ def playblast(context, viewport = False, stamping = True): rd.filepath = fp rd.use_stamp = stamping# toolsetting.use_stamp# True for playblast #stamp options - rd.stamp_font_size = rd.stamp_font_size * res_factor / 100# rd.resolution_percentage + rd.stamp_font_size = int(rd.stamp_font_size * res_factor / 100) # rd.resolution_percentage # get total number of frames diff --git a/__init__.py b/__init__.py index 09af306..1e1c893 100755 --- a/__init__.py +++ b/__init__.py @@ -1,21 +1,10 @@ -# 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 3 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 -# MERCHANTIBILITY 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, see . +# SPDX-License-Identifier: GPL-2.0-or-later bl_info = { "name": "GP toolbox", "description": "Tool set for Grease Pencil in animation production", "author": "Samuel Bernou, Christophe Seux", -"version": (1, 9, 9), +"version": (2, 0, 0), "blender": (2, 91, 0), "location": "Sidebar (N menu) > Gpencil > Toolbox / Gpencil properties", "warning": "", @@ -24,14 +13,10 @@ bl_info = { "category": "3D View", } -# from . import addon_updater_ops - -# from .utils import * from pathlib import Path from shutil import which from sys import modules from .utils import get_addon_prefs, draw_kmi -# from .functions import * ## GMIC from .GP_guided_colorize import GP_colorize