gp layers state check and set

0.2.7

- feat: check layer states (check use light, opacity, blend mode) and correct if needed
- ui: added chennel group color switch
- feat: added color from active layer on merge ops
main
Pullusb 2021-09-17 16:31:26 +02:00
parent 160a957007
commit 364b45e473
7 changed files with 186 additions and 12 deletions

View File

@ -12,6 +12,12 @@ Activate / deactivate layer opaticty according to prefix
Activate / deactivate all masks using MA layers Activate / deactivate all masks using MA layers
--> -->
0.2.7
- feat: check layer states (check use light, opacity, blend mode) and correct if needed
- ui: added chennel group color switch
- feat: added color from active layer on merge ops
0.2.6 0.2.6
- ui: name changes - ui: name changes

View File

@ -1,9 +1,7 @@
import bpy import bpy
from . import fn from . import fn
## direct use (Pop up menu version below) ## not used, replaced by "setup_layers.py"
class GPEXP_OT_check_layers_state(bpy.types.Operator): class GPEXP_OT_check_layers_state(bpy.types.Operator):
bl_idname = "gp.check_layers_state" bl_idname = "gp.check_layers_state"
bl_label = "Check Layers State" bl_label = "Check Layers State"
@ -21,6 +19,7 @@ class GPEXP_OT_check_layers_state(bpy.types.Operator):
def invoke(self, context, event): def invoke(self, context, event):
self.ctrl=event.ctrl self.ctrl=event.ctrl
self.alt=event.alt self.alt=event.alt
return self.execute(context)
return context.window_manager.invoke_props_dialog(self) return context.window_manager.invoke_props_dialog(self)
def draw(self, context): def draw(self, context):
@ -53,8 +52,8 @@ class GPEXP_OT_check_layers_state(bpy.types.Operator):
print(f'-> opacity {l.opacity}') print(f'-> opacity {l.opacity}')
used = True used = True
if l.use_light: if l.use_lights:
print(f'-> use light !') print(f'-> use lights !')
used = True used = True
if l.blend_mode != 'REGULAR': if l.blend_mode != 'REGULAR':
print(f'-> blend mode "{l.blend_mode}" !') print(f'-> blend mode "{l.blend_mode}" !')

View File

@ -1,9 +1,13 @@
import bpy import bpy
import re import re
from math import isclose
from . import fn from . import fn
from . import gen_vlayer from . import gen_vlayer
def merge_layers(rlayers, obname=None, active=None, disconnect=True): # TODO : make a merge compatible with already merged nodegroup (or even other node type)
# --> need to delete/mute AA internal node
def merge_layers(rlayers, obname=None, active=None, disconnect=True, color=None):
print(f'Merging {len(rlayers)} layers') print(f'Merging {len(rlayers)} layers')
print('->', [r.layer for r in rlayers]) print('->', [r.layer for r in rlayers])
@ -41,6 +45,7 @@ def merge_layers(rlayers, obname=None, active=None, disconnect=True):
# change colors of those nodes # change colors of those nodes
disconnected_groups = [] disconnected_groups = []
if not color:
color = fn.random_color() color = fn.random_color()
for n in rlayers: for n in rlayers:
n.use_custom_color = True n.use_custom_color = True
@ -161,7 +166,10 @@ class GPEXP_OT_merge_selected_dopesheet_layers(bpy.types.Operator):
rlayers.append(rl) rlayers.append(rl)
merge_layers(rlayers, disconnect=self.disconnect) color = None
if not any(isclose(i, 0.2, abs_tol=0.0001) for i in act.channel_color): # and bpy.context.preferences.edit.use_anim_channel_group_colors
color = act.channel_color
merge_layers(rlayers, disconnect=self.disconnect, color=color)
return {"FINISHED"} return {"FINISHED"}

134
OP_setup_layers.py Normal file
View File

@ -0,0 +1,134 @@
import bpy
from bpy.props import (FloatProperty,
BoolProperty,
EnumProperty,
StringProperty,
IntProperty)
from . import fn
class GPEXP_OT_layers_state(bpy.types.Operator):
bl_idname = "gp.layers_state"
bl_label = "Set Layers State"
bl_description = "Display state of layer that migh need adjustement"
bl_options = {"REGISTER"} # , "UNDO"
# clear_unused_view_layers :BoolProperty(name="Clear unused view layers",
# description="Delete view layer that aren't used in the nodetree anymore",
# default=True)
# TODO : (optional) export layer opacity to json and/or text
# (that way compo artists can re-affect opacity quickly or at least have a reminder)
all_objects : BoolProperty(name='On All Object',
default=False, description='On All object, else use selected objects') # , options={'SKIP_SAVE'}
set_full_opacity : BoolProperty(name='Set Full Opacity',
default=True, description='Check/Set full opacity') # , options={'SKIP_SAVE'}
set_use_lights : BoolProperty(name='Disable Use Light',
default=True, description='Check/Set use lights disabling') # , options={'SKIP_SAVE'}
set_blend_mode : BoolProperty(name='Set Regular Blend Mode',
default=True, description='Check/Set blend mode to regular') # , options={'SKIP_SAVE'}
@classmethod
def poll(cls, context):
return context.object and context.object.type == 'GPENCIL'
def invoke(self, context, event):
# self.ctrl=event.ctrl
# self.alt=event.alt
if event.alt:
self.all_objects=True
# return self.execute(context)
return context.window_manager.invoke_props_dialog(self)
def draw(self, context):
layout = self.layout
layout.prop(self, 'all_objects')
layout.separator()
layout.label(text='Set (or only perform a check):')
layout.prop(self, 'set_full_opacity')
layout.prop(self, 'set_use_lights')
layout.prop(self, 'set_blend_mode')
# layout.prop(self, 'clear_unused_view_layers')
def execute(self, context):
if self.all_objects:
pool = [o for o in context.scene.objects if o.type == 'GPENCIL']
else:
pool = [o for o in context.selected_objects if o.type == 'GPENCIL']
# pool = [context.object]
changes = []
for ob in pool:
changes.append(f'>> {ob.name}')
layers = ob.data.layers
for l in layers:
used = False
## mask check
# if l.mask_layers:
# print(f'-> masks')
# state = '' if l.use_mask_layer else ' (disabled)'
# print(f'{ob.name} > {l.info}{state}:')
# used = True
# for ml in l.mask_layers:
# mlstate = ' (disabled)' if ml.hide else ''
# mlinvert = ' <>' if ml.invert else ''
# print(f'{ml.info}{mlstate}{mlinvert}')
if l.opacity != 1:
full_opacity_state = '' if self.set_full_opacity else ' (check only)'
mess = f'{l.info} : opacity {l.opacity:.2f} >> 1.0{full_opacity_state}'
print(mess)
changes.append(mess)
if self.set_full_opacity:
l.opacity = 1.0
used = True
if l.use_lights:
use_lights_state = '' if self.set_use_lights else ' (check only)'
mess = f'{l.info} : disable use lights{use_lights_state}'
print(mess)
changes.append(mess)
if self.set_use_lights:
l.use_lights = False
used = True
if l.blend_mode != 'REGULAR':
blend_mode_state = '' if self.set_blend_mode else ' (check only)'
mess = f'{l.info} : blend mode "{l.blend_mode}" >> regular{blend_mode_state}'
print(mess)
changes.append(mess)
if self.set_blend_mode:
l.blend_mode = 'REGULAR'
used = True
if used:
print()
if changes:
changes.append('')
fn.show_message_box(_message=changes, _title="Layers Check Report", _icon='INFO')
# render = bpy.data.scenes.get('Render')
# if not render:
# print('SKIP, no Render scene')
# return {"CANCELLED"}
return {"FINISHED"}
classes=(
GPEXP_OT_layers_state,
)
def register():
for cls in classes:
bpy.utils.register_class(cls)
def unregister():
for cls in reversed(classes):
bpy.utils.unregister_class(cls)

View File

@ -2,7 +2,7 @@ bl_info = {
"name": "GP Render", "name": "GP Render",
"description": "Organise export of gp layers through compositor output", "description": "Organise export of gp layers through compositor output",
"author": "Samuel Bernou", "author": "Samuel Bernou",
"version": (0, 2, 6), "version": (0, 2, 7),
"blender": (2, 93, 0), "blender": (2, 93, 0),
"location": "View3D", "location": "View3D",
"warning": "", "warning": "",
@ -18,6 +18,8 @@ from . import OP_connect_toggle
from . import OP_manage_outputs from . import OP_manage_outputs
from . import OP_number_outputs from . import OP_number_outputs
from . import OP_scene_switch from . import OP_scene_switch
# from . import OP_check_layer_status
from . import OP_setup_layers
from . import ui from . import ui
import bpy import bpy
@ -34,6 +36,8 @@ def register():
OP_manage_outputs.register() OP_manage_outputs.register()
OP_number_outputs.register() OP_number_outputs.register()
OP_scene_switch.register() OP_scene_switch.register()
# OP_check_layer_status.register()
OP_setup_layers.register()
ui.register() ui.register()
# bpy.types.Scene.pgroup_name = bpy.props.PointerProperty(type = PROJ_PGT_settings) # bpy.types.Scene.pgroup_name = bpy.props.PointerProperty(type = PROJ_PGT_settings)
@ -42,6 +46,8 @@ def unregister():
return return
ui.unregister() ui.unregister()
OP_setup_layers.unregister()
# OP_check_layer_status.unregister()
OP_scene_switch.unregister() OP_scene_switch.unregister()
OP_number_outputs.unregister() OP_number_outputs.unregister()
OP_manage_outputs.unregister() OP_manage_outputs.unregister()

14
fn.py
View File

@ -521,3 +521,17 @@ def renumber_keep_existing(fo, offset=10):
# first check if it has a number (if not bas) # first check if it has a number (if not bas)
prev = fs prev = fs
ct += offset ct += offset
## confirm pop-up message:
def show_message_box(_message = "", _title = "Message Box", _icon = 'INFO'):
def draw(self, context):
for l in _message:
if isinstance(l, str):
self.layout.label(text=l)
else:
self.layout.label(text=l[0], icon=l[1])
if isinstance(_message, str):
_message = [_message]
bpy.context.window_manager.popup_menu(draw, title = _title, icon = _icon)

9
ui.py
View File

@ -67,7 +67,6 @@ class GPEXP_PT_gp_node_ui(Panel):
col.operator('gp.clear_render_tree', icon='X', text='Clear Framed Nodes') col.operator('gp.clear_render_tree', icon='X', text='Clear Framed Nodes')
col.operator('gp.clear_render_tree', icon='X', text='Clear & Delete Render Scene').mode = "COMPLETE" col.operator('gp.clear_render_tree', icon='X', text='Clear & Delete Render Scene').mode = "COMPLETE"
# layout.operator('gp.add_object_to_render', icon='RENDERLAYERS', text='Layer To Render').mode = 'ALL' # layout.operator('gp.add_object_to_render', icon='RENDERLAYERS', text='Layer To Render').mode = 'ALL'
# layout.operator('gp.add_object_to_render', icon='RENDERLAYERS', text='Layer To Render').mode = 'SELECTED' # layout.operator('gp.add_object_to_render', icon='RENDERLAYERS', text='Layer To Render').mode = 'SELECTED'
@ -112,12 +111,20 @@ class GPEXP_PT_gp_dopesheet_ui(Panel):
## all and objects ## all and objects
layout.separator() layout.separator()
layout.label(text='Whole objects:') layout.label(text='Whole objects:')
if context.scene.name != 'Render': if context.scene.name != 'Render':
txt = f'{len([o for o in context.selected_objects if o.type == "GPENCIL" and o.select_get()])} Selected Object(s) To Render' txt = f'{len([o for o in context.selected_objects if o.type == "GPENCIL" and o.select_get()])} Selected Object(s) To Render'
layout.operator('gp.add_object_to_render', icon='RENDERLAYERS', text=txt).mode='SELECTED' layout.operator('gp.add_object_to_render', icon='RENDERLAYERS', text=txt).mode='SELECTED'
layout.operator('gp.add_object_to_render', icon='RENDERLAYERS', text='All Visible GP To Render').mode='ALL' layout.operator('gp.add_object_to_render', icon='RENDERLAYERS', text='All Visible GP To Render').mode='ALL'
layout.separator()
layout.operator('gp.layers_state', icon='CHECKMARK', text='Check layers')
# row = layout.row()
layout.prop(bpy.context.preferences.edit, 'use_anim_channel_group_colors')
class GPEXP_MT_multi_user_doc(bpy.types.Menu): class GPEXP_MT_multi_user_doc(bpy.types.Menu):
# bl_idname = "OBJECT_MT_custom_menu" # bl_idname = "OBJECT_MT_custom_menu"