choose pts attribute to dump in layer copy

2.0.2

- added: possibility to select which point attribute is copied by GP layer copy to clipboard
gpv2
Pullusb 2022-07-01 18:14:07 +02:00
parent e1681cd6ad
commit 762b92fbfe
3 changed files with 79 additions and 29 deletions

View File

@ -1,5 +1,9 @@
# Changelog # Changelog
2.0.2
- added: possibility to select which point attribute is copied by GP layer copy to clipboard
2.0.1 2.0.1
- added: enable/disable camera animation separately in `animation manager` - added: enable/disable camera animation separately in `animation manager`

View File

@ -61,7 +61,8 @@ def getMatrix (layer) :
default_pt_uv_fill = Vector((0.5, 0.5)) default_pt_uv_fill = Vector((0.5, 0.5))
def dump_gp_point(p, l, obj): def dump_gp_point(p, l, obj,
pressure=True, strength=True, vertex_color=True, uv_fill=True, uv_factor=True, uv_rotation=True):
'''add properties of a given points to a dic and return it''' '''add properties of a given points to a dic and return it'''
pdic = {} pdic = {}
#point_attr_list = ('co', 'pressure', 'select', 'strength') #select#'rna_type' #point_attr_list = ('co', 'pressure', 'select', 'strength') #select#'rna_type'
@ -72,26 +73,30 @@ def dump_gp_point(p, l, obj):
pdic['co'] = convertAttr(obj.matrix_world @ mat @ getattr(p,'co')) pdic['co'] = convertAttr(obj.matrix_world @ mat @ getattr(p,'co'))
else: else:
pdic['co'] = convertAttr(obj.matrix_world @ getattr(p,'co')) pdic['co'] = convertAttr(obj.matrix_world @ getattr(p,'co'))
# pdic['select'] = convertAttr(getattr(p,'select')) # need selection ?
if pressure and p.pressure != 1.0:
pdic['pressure'] = convertAttr(getattr(p,'pressure')) pdic['pressure'] = convertAttr(getattr(p,'pressure'))
# pdic['select'] = convertAttr(getattr(p,'select'))# need selection ? if strength and p.strength != 1.0:
pdic['strength'] = convertAttr(getattr(p,'strength')) pdic['strength'] = convertAttr(getattr(p,'strength'))
## get vertex color (long...) ## get vertex color (long...)
if p.vertex_color[:] != (0.0, 0.0, 0.0, 0.0): if vertex_color and p.vertex_color[:] != (0.0, 0.0, 0.0, 0.0):
pdic['vertex_color'] = convertAttr(p.vertex_color) pdic['vertex_color'] = convertAttr(p.vertex_color)
## UV attr (maybe uv fill is always (0.5,0.5) ? also exists at stroke level...) ## UV attr (maybe uv fill is always (0.5,0.5) ? also exists at stroke level...)
if p.uv_fill != default_pt_uv_fill: if uv_fill and p.uv_fill != default_pt_uv_fill:
pdic['uv_fill'] = convertAttr(p.uv_fill) pdic['uv_fill'] = convertAttr(p.uv_fill)
if p.uv_factor != 0.0: if uv_factor and p.uv_factor != 0.0:
pdic['uv_factor'] = convertAttr(p.uv_factor) pdic['uv_factor'] = convertAttr(p.uv_factor)
if p.uv_rotation != 0.0: if uv_rotation and p.uv_rotation != 0.0:
pdic['uv_rotation'] = convertAttr(p.uv_rotation) pdic['uv_rotation'] = convertAttr(p.uv_rotation)
return pdic return pdic
def dump_gp_stroke_range(s, sid, l, obj): def dump_gp_stroke_range(s, sid, l, obj,
pressure=True, strength=True, vertex_color=True, uv_fill=True, uv_factor=True, uv_rotation=True):
'''Get a grease pencil stroke and return a dic with attribute '''Get a grease pencil stroke and return a dic with attribute
(points attribute being a dic of dics to store points and their attributes) (points attribute being a dic of dics to store points and their attributes)
''' '''
@ -105,10 +110,10 @@ def dump_gp_stroke_range(s, sid, l, obj):
if s.material_index != 0: if s.material_index != 0:
sdic['material_index'] = s.material_index sdic['material_index'] = s.material_index
if getattr(s, 'draw_cyclic', None):# pre-2.92 if getattr(s, 'draw_cyclic', None): # pre-2.92
sdic['draw_cyclic'] = s.draw_cyclic sdic['draw_cyclic'] = s.draw_cyclic
if getattr(s, 'use_cyclic', None):# from 2.92 if getattr(s, 'use_cyclic', None): # from 2.92
sdic['use_cyclic'] = s.use_cyclic sdic['use_cyclic'] = s.use_cyclic
if s.uv_scale != 1.0: if s.uv_scale != 1.0:
@ -127,18 +132,20 @@ def dump_gp_stroke_range(s, sid, l, obj):
sdic['vertex_color_fill'] = convertAttr(s.vertex_color_fill) sdic['vertex_color_fill'] = convertAttr(s.vertex_color_fill)
points = [] points = []
if sid is None:#no ids, just full points... if sid is None: # no ids, just full points...
for p in s.points: for p in s.points:
points.append(dump_gp_point(p,l,obj)) points.append(dump_gp_point(p,l,obj,
pressure=pressure, strength=strength, vertex_color=vertex_color, uv_fill=uv_fill, uv_factor=uv_factor, uv_rotation=uv_rotation))
else: else:
for pid in sid: for pid in sid:
points.append(dump_gp_point(s.points[pid],l,obj)) points.append(dump_gp_point(s.points[pid],l,obj,
pressure=pressure, strength=strength, vertex_color=vertex_color, uv_fill=uv_fill, uv_factor=uv_factor, uv_rotation=uv_rotation))
sdic['points'] = points sdic['points'] = points
return sdic return sdic
def copycut_strokes(layers=None, copy=True, keep_empty=True):# (mayber allow filter) def copycut_strokes(layers=None, copy=True, keep_empty=True):
''' '''
copy all visibles selected strokes on active frame copy all visibles selected strokes on active frame
layers can be None, a single layer object or list of layer object as filter layers can be None, a single layer object or list of layer object as filter
@ -276,7 +283,8 @@ def copy_all_strokes(layers=None):
return stroke_list return stroke_list
""" """
def copy_all_strokes_in_frame(frame=None, layers=None, obj=None): def copy_all_strokes_in_frame(frame=None, layers=None, obj=None,
pressure=True, strength=True, vertex_color=True, uv_fill=True, uv_factor=True, uv_rotation=True):
''' '''
copy all stroke, not affected by selection on active frame copy all stroke, not affected by selection on active frame
layers can be None, a single layer object or list of layer object as filter layers can be None, a single layer object or list of layer object as filter
@ -292,7 +300,7 @@ def copy_all_strokes_in_frame(frame=None, layers=None, obj=None):
if not layers: if not layers:
# by default all visible layers # by default all visible layers
layers = [l for l in gpl if not l.hide and not l.lock]# include locked ? layers = [l for l in gpl if not l.hide and not l.lock] # include locked ?
if not isinstance(layers, list): if not isinstance(layers, list):
# if a single layer object is send put in a list # if a single layer object is send put in a list
layers = [layers] layers = [layers]
@ -309,7 +317,8 @@ def copy_all_strokes_in_frame(frame=None, layers=None, obj=None):
## full stroke version ## full stroke version
# if s.select: # if s.select:
# send index of all points to get the whole stroke with "range" # send index of all points to get the whole stroke with "range"
stroke_list.append( dump_gp_stroke_range(s, [i for i in range(len(s.points))], l, obj) ) stroke_list.append( dump_gp_stroke_range(s, [i for i in range(len(s.points))], l, obj,
pressure=pressure,strength=strength,vertex_color=vertex_color,uv_fill=uv_fill,uv_factor=uv_factor,uv_rotation=uv_rotation))
# print(len(stroke_list), 'strokes copied in', time()-t0, 'seconds') # print(len(stroke_list), 'strokes copied in', time()-t0, 'seconds')
return stroke_list return stroke_list
@ -338,7 +347,7 @@ def add_stroke(s, frame, layer, obj, select=False):
for k, v in pt.items(): for k, v in pt.items():
if k == 'co': if k == 'co':
setattr(ns.points[i], k, v) setattr(ns.points[i], k, v)
ns.points[i].co = ob_mat_inv @ mat @ ns.points[i].co# invert of object * invert of layer * coordinate ns.points[i].co = ob_mat_inv @ mat @ ns.points[i].co # invert of object * invert of layer * coordinate
else: else:
setattr(ns.points[i], k, v) setattr(ns.points[i], k, v)
if select: if select:
@ -408,7 +417,7 @@ def add_multiple_strokes(stroke_list, layer=None, use_current_frame=True, select
class GPCLIP_OT_copy_strokes(bpy.types.Operator): class GPCLIP_OT_copy_strokes(bpy.types.Operator):
bl_idname = "gp.copy_strokes" bl_idname = "gp.copy_strokes"
bl_label = "GP Copy strokes" bl_label = "GP Copy strokes"
bl_description = "Copy strokes to str in paperclip" bl_description = "Copy strokes to text in paperclip"
bl_options = {"REGISTER"} bl_options = {"REGISTER"}
#copy = bpy.props.BoolProperty(default=True) #copy = bpy.props.BoolProperty(default=True)
@ -425,7 +434,7 @@ class GPCLIP_OT_copy_strokes(bpy.types.Operator):
#ct = check_pressure() #ct = check_pressure()
strokelist = copycut_strokes(copy=True, keep_empty=True) strokelist = copycut_strokes(copy=True, keep_empty=True)
if not strokelist: if not strokelist:
self.report({'ERROR'},'rien a copier') self.report({'ERROR'}, 'Nothing to copy')
return {"CANCELLED"} return {"CANCELLED"}
bpy.context.window_manager.clipboard = json.dumps(strokelist)#copy=self.copy bpy.context.window_manager.clipboard = json.dumps(strokelist)#copy=self.copy
#if ct: #if ct:
@ -438,7 +447,7 @@ class GPCLIP_OT_copy_strokes(bpy.types.Operator):
class GPCLIP_OT_cut_strokes(bpy.types.Operator): class GPCLIP_OT_cut_strokes(bpy.types.Operator):
bl_idname = "gp.cut_strokes" bl_idname = "gp.cut_strokes"
bl_label = "GP Cut strokes" bl_label = "GP Cut strokes"
bl_description = "Cut strokes to str in paperclip" bl_description = "Cut strokes to text in paperclip"
bl_options = {"REGISTER"} bl_options = {"REGISTER"}
@classmethod @classmethod
@ -451,7 +460,7 @@ class GPCLIP_OT_cut_strokes(bpy.types.Operator):
# return {"CANCELLED"} # return {"CANCELLED"}
t0 = time() t0 = time()
strokelist = copycut_strokes(copy=False, keep_empty=True)#ct = check_pressure() strokelist = copycut_strokes(copy=False, keep_empty=True) # ct = check_pressure()
if not strokelist: if not strokelist:
self.report({'ERROR'},'Nothing to cut') self.report({'ERROR'},'Nothing to cut')
return {"CANCELLED"} return {"CANCELLED"}
@ -503,6 +512,37 @@ class GPCLIP_OT_copy_multi_strokes(bpy.types.Operator):
def poll(cls, context): def poll(cls, context):
return context.object and context.object.type == 'GPENCIL' return context.object and context.object.type == 'GPENCIL'
pressure : bpy.props.BoolProperty(name='pressure', default=True,
description='Dump point pressure attribute (already skipped if at default value)')
strength : bpy.props.BoolProperty(name='strength', default=True,
description='Dump point strength attribute (already skipped if at default value)')
vertex_color : bpy.props.BoolProperty(name='vertex color', default=True,
description='Dump point vertex_color attribute (already skipped if at default value)')
uv_fill : bpy.props.BoolProperty(name='uv fill', default=True,
description='Dump point uv_fill attribute (already skipped if at default value)')
uv_factor : bpy.props.BoolProperty(name='uv factor', default=True,
description='Dump point uv_factor attribute (already skipped if at default value)')
uv_rotation : bpy.props.BoolProperty(name='uv rotation', default=True,
description='Dump point uv_rotation attribute (already skipped if at default value)')
def invoke(self, context, event):
# self.file_dump = event.ctrl
return context.window_manager.invoke_props_dialog(self) # , width=400
# return self.execute(context)
def draw(self, context):
layout=self.layout
layout.use_property_split = True
col = layout.column()
col.label(text='Keep following point attributes:')
col.prop(self, 'pressure')
col.prop(self, 'strength')
col.prop(self, 'vertex_color')
col.prop(self, 'uv_fill')
col.prop(self, 'uv_factor')
col.prop(self, 'uv_rotation')
return
def execute(self, context): def execute(self, context):
bake_moves = True bake_moves = True
skip_empty_frame = False skip_empty_frame = False
@ -528,15 +568,18 @@ class GPCLIP_OT_copy_multi_strokes(bpy.types.Operator):
for f in l.frames: for f in l.frames:
if skip_empty_frame and not len(f.strokes): if skip_empty_frame and not len(f.strokes):
continue continue
context.scene.frame_set(f.frame_number)#use matrix of this frame context.scene.frame_set(f.frame_number) # use matrix of this frame
strokelist = copy_all_strokes_in_frame(frame=f, layers=l, obj=obj) strokelist = copy_all_strokes_in_frame(frame=f, layers=l, obj=obj,
pressure=self.pressure, strength=self.strength, vertex_color=self.vertex_color,
uv_fill=self.uv_fill, uv_factor=self.uv_factor, uv_rotation=self.uv_rotation)
frame_dic[f.frame_number] = strokelist frame_dic[f.frame_number] = strokelist
layerdic[l.info] = frame_dic layerdic[l.info] = frame_dic
else:# bake position: copy frame where object as moved even if frame is unchanged else: # bake position: copy frame where object as moved even if frame is unchanged
for l in layerpool: for l in layerpool:
print('dump layer:', l.info)
if not l.frames: if not l.frames:
continue# skip empty layers continue# skip empty layers
@ -548,7 +591,7 @@ class GPCLIP_OT_copy_multi_strokes(bpy.types.Operator):
curmat = prevmat = obj.matrix_world.copy() curmat = prevmat = obj.matrix_world.copy()
for i in range(context.scene.frame_start, context.scene.frame_end): for i in range(context.scene.frame_start, context.scene.frame_end):
context.scene.frame_set(i)#use matrix of this frame context.scene.frame_set(i) # use matrix of this frame
curmat = obj.matrix_world.copy() curmat = obj.matrix_world.copy()
# if object has moved or current time is on a draw key # if object has moved or current time is on a draw key
@ -563,7 +606,10 @@ class GPCLIP_OT_copy_multi_strokes(bpy.types.Operator):
if skip_empty_frame and not len(f.strokes): if skip_empty_frame and not len(f.strokes):
continue continue
strokelist = copy_all_strokes_in_frame(frame=f, layers=l, obj=obj) strokelist = copy_all_strokes_in_frame(frame=f, layers=l, obj=obj,
pressure=self.pressure, strength=self.strength, vertex_color=self.vertex_color,
uv_fill=self.uv_fill, uv_factor=self.uv_factor, uv_rotation=self.uv_rotation)
frame_dic[i] = strokelist frame_dic[i] = strokelist
prevmat = curmat prevmat = curmat

View File

@ -4,7 +4,7 @@ bl_info = {
"name": "GP toolbox", "name": "GP toolbox",
"description": "Tool set for Grease Pencil in animation production", "description": "Tool set for Grease Pencil in animation production",
"author": "Samuel Bernou, Christophe Seux", "author": "Samuel Bernou, Christophe Seux",
"version": (2, 0, 1), "version": (2, 0, 2),
"blender": (2, 91, 0), "blender": (2, 91, 0),
"location": "Sidebar (N menu) > Gpencil > Toolbox / Gpencil properties", "location": "Sidebar (N menu) > Gpencil > Toolbox / Gpencil properties",
"warning": "", "warning": "",