1.8.4 - fix: select node from layer - changed: Check for problems: object numbering check does not list as error if parent part has number prefix (previously checked only for last part)
166 lines
5.5 KiB
Python
166 lines
5.5 KiB
Python
import bpy, re
|
|
from . import fn
|
|
|
|
def check_broken_modifier_target(pool=None, reports=None):
|
|
if not reports:
|
|
reports = []
|
|
if not pool:
|
|
pool = [o for o in bpy.context.scene.objects if o.type == 'GPENCIL']
|
|
|
|
for o in pool:
|
|
lay_name_list = [l.info for l in o.data.layers]
|
|
for m in o.grease_pencil_modifiers:
|
|
if not hasattr(m, 'layer'):
|
|
continue
|
|
if not m.layer:
|
|
continue
|
|
if not m.layer in lay_name_list:
|
|
reports.append(f'Broken modifier target :{o.name} > {m.name} > {m.layer}')
|
|
# else:
|
|
# print(f'Modifier target :{o.name} > {m.name} > ok')
|
|
|
|
return reports
|
|
|
|
def check_layer_state(pool=None, reports=None):
|
|
if not reports:
|
|
reports = []
|
|
if not pool:
|
|
pool = [o for o in bpy.context.scene.objects if o.type == 'GPENCIL']
|
|
for ob in pool:
|
|
layers = ob.data.layers
|
|
for l in layers:
|
|
# if l.mask_layers:
|
|
# if not any(not x.hide for x in l.mask_layers):
|
|
# # all masks disable
|
|
# pass
|
|
|
|
## just list masks
|
|
# state = '' if l.use_mask_layer else ' (disabled)'
|
|
# reports.append(f'{ob.name} > {l.info} masks{state}:')
|
|
# for ml in l.mask_layers:
|
|
# mlstate = ' (disabled)' if ml.hide else ''
|
|
# mlinvert = ' <>' if ml.invert else ''
|
|
# reports.append(f' - {ml.name}{mlstate}{mlinvert}')
|
|
|
|
if l.opacity != 1 and not l.info.startswith('MA_'):
|
|
reports.append(f'{ob.name} > {l.info} > opacity {l.opacity}')
|
|
|
|
# if l.use_lights:
|
|
# reports.append(f'-> use lights !')
|
|
|
|
if l.blend_mode != 'REGULAR':
|
|
reports.append(f'{ob.name} > {l.info} > blend mode "{l.blend_mode}" !')
|
|
|
|
return reports
|
|
|
|
def check_file_output_numbering(reports=None):
|
|
if not reports:
|
|
reports = []
|
|
prenum = re.compile(r'\d{3}_')
|
|
file_outs = []
|
|
for S in bpy.data.scenes:
|
|
if not S.node_tree or not S.use_nodes: # S.name == 'Scene' or
|
|
continue
|
|
file_outs += [n for n in S.node_tree.nodes if n.type == 'OUTPUT_FILE']
|
|
|
|
if not file_outs:
|
|
reports.append('No file output nodes found')
|
|
return reports
|
|
|
|
for fo in file_outs:
|
|
### Check for object prefix number in path
|
|
split_path = fo.base_path.split('/')
|
|
if not prenum.match(split_path[-1]):
|
|
report_missing_number = True
|
|
# No prefix-number in tail part name
|
|
if len(split_path) >= 2 and prenum.match(split_path[-2]):
|
|
# report if no prefix-number on parent path part either
|
|
report_missing_number = False
|
|
|
|
if report_missing_number:
|
|
reports.append(f'No object numbering : node {fo.name}')
|
|
|
|
pct = 0
|
|
if fo.format.file_format == 'OPEN_EXR_MULTILAYER':
|
|
## multilayer use layer_slots > slot.name
|
|
slots = fo.layer_slots
|
|
for fs in slots:
|
|
if not prenum.match(fs.name.split('/')[0]):
|
|
pct += 1
|
|
else:
|
|
## classic use file_slots > path
|
|
slots = fo.file_slots
|
|
for fs in slots:
|
|
if not prenum.match(fs.path.split('/')[0]):
|
|
pct += 1
|
|
|
|
if pct:
|
|
reports.append(f'{pct}/{len(slots)} slots not numbered: node {fo.name}')
|
|
|
|
return reports
|
|
class GPEXP_OT_check_render_scene(bpy.types.Operator):
|
|
bl_idname = "gp.check_render_scene"
|
|
bl_label = "Check render scene"
|
|
bl_description = "Auto check render scene"
|
|
bl_options = {"REGISTER"} # , "UNDO"
|
|
|
|
# clear_unused_view_layers : bpy.props.BoolProperty(name="Clear unused view layers",
|
|
# description="Delete view layer that aren't used in the nodetree anymore",
|
|
# default=True)
|
|
|
|
@classmethod
|
|
def poll(cls, context):
|
|
return True
|
|
|
|
def invoke(self, context, event):
|
|
return self.execute(context)
|
|
# return context.window_manager.invoke_props_dialog(self)
|
|
|
|
# def draw(self, context):
|
|
# layout = self.layout
|
|
# # layout.prop(self, 'clear_unused_view_layers')
|
|
|
|
def execute(self, context):
|
|
reports = []
|
|
# check gp modifiers
|
|
broken_mods = check_broken_modifier_target()
|
|
if broken_mods:
|
|
reports.append('GP modifiers targets:')
|
|
reports += broken_mods
|
|
|
|
# check layers
|
|
layer_state = check_layer_state()
|
|
if layer_state:
|
|
if reports: reports.append('')
|
|
reports.append('Layers State:')
|
|
reports += layer_state
|
|
|
|
# check file output numbering
|
|
numbering_problems = check_file_output_numbering()
|
|
if numbering_problems:
|
|
if reports: reports.append('')
|
|
reports.append('File output numbering:')
|
|
reports += numbering_problems
|
|
|
|
if not reports:
|
|
self.report({'INFO'}, 'All OK !')
|
|
reports.append('Everything Ok !')
|
|
|
|
if hasattr(bpy.types, 'GP_OT_file_checker'):
|
|
# propose to run toolbox checker if exists
|
|
reports.append(['gp.file_checker', 'Run GP_toolbox File Checker', 'SCENE_DATA'])
|
|
|
|
fn.show_message_box(_message=reports, _title='Potential Problems list')
|
|
return {"FINISHED"}
|
|
|
|
classes=(
|
|
GPEXP_OT_check_render_scene,
|
|
)
|
|
|
|
def register():
|
|
for cls in classes:
|
|
bpy.utils.register_class(cls)
|
|
|
|
def unregister():
|
|
for cls in reversed(classes):
|
|
bpy.utils.unregister_class(cls) |