gpv3 world copy cut paste
parent
5d930df06b
commit
4937aa32c0
224
OP_copy_paste.py
224
OP_copy_paste.py
|
@ -45,105 +45,112 @@ def convertAttr(Attr):
|
|||
else:
|
||||
return(Attr)
|
||||
|
||||
def getMatrix (layer) :
|
||||
def getMatrix(layer) :
|
||||
matrix = mathutils.Matrix.Identity(4)
|
||||
|
||||
## FIXME: not "is_parent" or parent_type anymore
|
||||
if layer.is_parented:
|
||||
if layer.parent_type == 'BONE':
|
||||
object = layer.parent
|
||||
bone = object.pose.bones[layer.parent_bone]
|
||||
matrix = bone.matrix @ object.matrix_world
|
||||
matrix = matrix.copy() @ layer.matrix_inverse
|
||||
else :
|
||||
matrix = layer.parent.matrix_world @ layer.matrix_inverse
|
||||
if layer.parent:
|
||||
## temp solution
|
||||
matrix = layer.parent.matrix_world @ layer.matrix_inverse
|
||||
|
||||
### if layer.parent_type == 'BONE':
|
||||
# if layer.parent.type == 'ARMATURE':
|
||||
# object = layer.parent
|
||||
# bone = object.pose.bones[layer.parent_bone]
|
||||
# matrix = bone.matrix @ object.matrix_world
|
||||
# matrix = matrix.copy() @ layer.matrix_inverse
|
||||
# else :
|
||||
# matrix = layer.parent.matrix_world @ layer.matrix_inverse
|
||||
|
||||
return matrix.copy()
|
||||
|
||||
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,
|
||||
pressure=True, strength=True, vertex_color=True, uv_fill=True, uv_factor=True, uv_rotation=True):
|
||||
radius=True, opacity=True, vertex_color=True, fill_color=True, uv_factor=True, rotation=True):
|
||||
'''add properties of a given points to a dic and return it'''
|
||||
pdic = {}
|
||||
#point_attr_list = ('co', 'pressure', 'select', 'strength') #select#'rna_type'
|
||||
point_dict = {}
|
||||
#point_attr_list = ('co', 'radius', 'select', 'opacity') #select#'rna_type'
|
||||
#for att in point_attr_list:
|
||||
# pdic[att] = convertAttr(getattr(p, att))
|
||||
# point_dict[att] = convertAttr(getattr(p, att))
|
||||
if l.parent:
|
||||
mat = getMatrix(l)
|
||||
pdic['co'] = convertAttr(obj.matrix_world @ mat @ getattr(p,'co'))
|
||||
point_dict['position'] = convertAttr(obj.matrix_world @ mat @ getattr(p,'position'))
|
||||
else:
|
||||
pdic['co'] = convertAttr(obj.matrix_world @ getattr(p,'co'))
|
||||
point_dict['position'] = convertAttr(obj.matrix_world @ getattr(p,'position'))
|
||||
|
||||
# pdic['select'] = convertAttr(getattr(p,'select')) # need selection ?
|
||||
if pressure and p.pressure != 1.0:
|
||||
pdic['pressure'] = convertAttr(getattr(p,'pressure'))
|
||||
if strength and p.strength != 1.0:
|
||||
pdic['strength'] = convertAttr(getattr(p,'strength'))
|
||||
# point_dict['select'] = convertAttr(getattr(p,'select')) # need selection ?
|
||||
if radius and p.radius != 1.0:
|
||||
point_dict['radius'] = convertAttr(getattr(p,'radius'))
|
||||
|
||||
if opacity and p.opacity != 1.0:
|
||||
point_dict['opacity'] = convertAttr(getattr(p,'opacity'))
|
||||
|
||||
## get vertex color (long...)
|
||||
if vertex_color and p.vertex_color[:] != (0.0, 0.0, 0.0, 0.0):
|
||||
pdic['vertex_color'] = convertAttr(p.vertex_color)
|
||||
point_dict['vertex_color'] = convertAttr(p.vertex_color)
|
||||
|
||||
## UV attr (maybe uv fill is always (0.5,0.5) ? also exists at stroke level...)
|
||||
if uv_fill and p.uv_fill != default_pt_uv_fill:
|
||||
pdic['uv_fill'] = convertAttr(p.uv_fill)
|
||||
if uv_factor and p.uv_factor != 0.0:
|
||||
pdic['uv_factor'] = convertAttr(p.uv_factor)
|
||||
if uv_rotation and p.uv_rotation != 0.0:
|
||||
pdic['uv_rotation'] = convertAttr(p.uv_rotation)
|
||||
if rotation and p.rotation != 0.0:
|
||||
point_dict['rotation'] = convertAttr(p.rotation)
|
||||
|
||||
return pdic
|
||||
## No time infos
|
||||
# if delta_time and p.delta_time != 0.0:
|
||||
# point_dict['delta_time'] = convertAttr(getattr(p,'delta_time'))
|
||||
|
||||
return point_dict
|
||||
|
||||
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):
|
||||
radius=True, opacity=True, vertex_color=True, fill_color=True, fill_opacity=True, rotation=True):
|
||||
'''Get a grease pencil stroke and return a dic with attribute
|
||||
(points attribute being a dic of dics to store points and their attributes)
|
||||
'''
|
||||
|
||||
sdic = {}
|
||||
stroke_attr_list = ('line_width',) #'select'#read-only: 'triangles'
|
||||
for att in stroke_attr_list:
|
||||
sdic[att] = getattr(s, att)
|
||||
|
||||
stroke_dict = {}
|
||||
# stroke_attr_list = ('line_width',)
|
||||
# for att in stroke_attr_list:
|
||||
# stroke_dict[att] = getattr(s, att)
|
||||
|
||||
## Dump following these value only if they are non default
|
||||
if s.material_index != 0:
|
||||
sdic['material_index'] = s.material_index
|
||||
|
||||
if getattr(s, 'draw_cyclic', None): # pre-2.92
|
||||
sdic['draw_cyclic'] = s.draw_cyclic
|
||||
|
||||
if getattr(s, 'use_cyclic', None): # from 2.92
|
||||
sdic['use_cyclic'] = s.use_cyclic
|
||||
|
||||
if s.uv_scale != 1.0:
|
||||
sdic['uv_scale'] = s.uv_scale
|
||||
|
||||
if s.uv_rotation != 0.0:
|
||||
sdic['uv_rotation'] = s.uv_rotation
|
||||
|
||||
if s.hardness != 1.0:
|
||||
sdic['hardness'] = s.hardness
|
||||
|
||||
if s.uv_translation != Vector((0.0, 0.0)):
|
||||
sdic['uv_translation'] = convertAttr(s.uv_translation)
|
||||
stroke_dict['material_index'] = s.material_index
|
||||
|
||||
if s.vertex_color_fill[:] != (0,0,0,0):
|
||||
sdic['vertex_color_fill'] = convertAttr(s.vertex_color_fill)
|
||||
if s.cyclic:
|
||||
stroke_dict['cyclic'] = s.cyclic
|
||||
|
||||
if s.softness != 0.0:
|
||||
stroke_dict['softness'] = s.softness
|
||||
|
||||
if s.aspect_ratio != 1.0:
|
||||
stroke_dict['aspect_ratio'] = s.aspect_ratio
|
||||
|
||||
if s.start_cap != 0:
|
||||
stroke_dict['start_cap'] = s.start_cap
|
||||
|
||||
if s.end_cap != 0:
|
||||
stroke_dict['end_cap'] = s.end_cap
|
||||
|
||||
if fill_color and s.fill_color[:] != (0,0,0,0):
|
||||
stroke_dict['fill_color'] = convertAttr(s.fill_color)
|
||||
|
||||
if fill_opacity and s.fill_opacity != 0.0:
|
||||
stroke_dict['fill_opacity'] = s.fill_opacity
|
||||
|
||||
## No time infos
|
||||
# if s.time_start != 0.0:
|
||||
# stroke_dict['time_start'] = s.time_start
|
||||
|
||||
points = []
|
||||
if sid is None: # no ids, just full points...
|
||||
for p in s.points:
|
||||
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))
|
||||
points.append(dump_gp_point(p, l, obj,
|
||||
radius=radius, opacity=opacity, vertex_color=vertex_color, rotation=rotation))
|
||||
else:
|
||||
for pid in sid:
|
||||
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
|
||||
return sdic
|
||||
|
||||
points.append(dump_gp_point(s.points[pid], l, obj,
|
||||
radius=radius, opacity=opacity, vertex_color=vertex_color, rotation=rotation))
|
||||
|
||||
stroke_dict['points'] = points
|
||||
return stroke_dict
|
||||
|
||||
|
||||
def copycut_strokes(layers=None, copy=True, keep_empty=True):
|
||||
|
@ -177,7 +184,7 @@ def copycut_strokes(layers=None, copy=True, keep_empty=True):
|
|||
staylist = [] # init part of strokes that must survive on this layer
|
||||
|
||||
rm_list = [] # init strokes that must be removed from this layer
|
||||
for s_index, stroke in f.drawing.strokes:
|
||||
for s_index, stroke in enumerate(f.drawing.strokes):
|
||||
if stroke.select:
|
||||
# separate in multiple stroke if parts of the strokes a selected.
|
||||
sel = [i for i, p in enumerate(stroke.points) if p.select]
|
||||
|
@ -196,8 +203,8 @@ def copycut_strokes(layers=None, copy=True, keep_empty=True):
|
|||
if not copy:
|
||||
maxindex = len(stroke.points)-1
|
||||
if len(substrokes) == maxindex+1: # if only one substroke, then it's the full stroke
|
||||
# f.drawing.strokes.remove(stroke)
|
||||
rm_list.append(stroke)
|
||||
# f.drawing.strokes.remove(stroke) # gpv2
|
||||
rm_list.append(s_index)
|
||||
else:
|
||||
neg = [i for i, p in enumerate(stroke.points) if not p.select]
|
||||
|
||||
|
@ -216,21 +223,15 @@ def copycut_strokes(layers=None, copy=True, keep_empty=True):
|
|||
staylist.append(dump_gp_stroke_range(stroke, ns, l, obj))
|
||||
# make a negative list containing all last index
|
||||
|
||||
|
||||
'''#full stroke version
|
||||
# if stroke.colorname == color: #line for future filters
|
||||
stroke_list.append(dump_gp_stroke(stroke,l))
|
||||
#delete stroke on the fly
|
||||
if not copy:
|
||||
f.drawing.strokes.remove(stroke)
|
||||
'''
|
||||
if rm_list:
|
||||
f.drawing.remove_strokes(indices=rm_list)
|
||||
|
||||
if not copy:
|
||||
selected_ids = [i for i, s in enumerate(f.drawing.strokes) if s.select]
|
||||
|
||||
# delete all selected strokes...
|
||||
f.drawing.strokes.remove_strokes(indices=selected_ids)
|
||||
if selected_ids:
|
||||
f.drawing.remove_strokes(indices=selected_ids)
|
||||
|
||||
# ...recreate these uncutted ones
|
||||
#pprint(staylist)
|
||||
|
@ -243,7 +244,6 @@ def copycut_strokes(layers=None, copy=True, keep_empty=True):
|
|||
l.frames.remove(f)
|
||||
|
||||
|
||||
|
||||
print(len(stroke_list), 'strokes copied in', time()-t0, 'seconds')
|
||||
#print(stroke_list)
|
||||
return stroke_list
|
||||
|
@ -289,7 +289,7 @@ def copy_all_strokes(layers=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):
|
||||
radius=True, opacity=True, vertex_color=True, fill_color=True, fill_opacity=True, rotation=True):
|
||||
'''
|
||||
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
|
||||
|
@ -323,7 +323,7 @@ def copy_all_strokes_in_frame(frame=None, layers=None, obj=None,
|
|||
# if s.select:
|
||||
# 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,
|
||||
pressure=pressure,strength=strength,vertex_color=vertex_color,uv_fill=uv_fill,uv_factor=uv_factor,uv_rotation=uv_rotation))
|
||||
radius=radius, opacity=opacity, vertex_color=vertex_color, fill_color=fill_color, fill_opacity=fill_opacity, rotation=rotation))
|
||||
|
||||
# print(len(stroke_list), 'strokes copied in', time()-t0, 'seconds')
|
||||
return stroke_list
|
||||
|
@ -331,26 +331,27 @@ def copy_all_strokes_in_frame(frame=None, layers=None, obj=None,
|
|||
def add_stroke(s, frame, layer, obj, select=False):
|
||||
'''add stroke on a given frame, (layer is for parentage setting)'''
|
||||
# print(3*'-',s)
|
||||
ns = frame.drawing.strokes.new()
|
||||
pts_to_add = len(s['points'])
|
||||
frame.drawing.add_strokes([pts_to_add])
|
||||
|
||||
ns = frame.drawing.strokes[-1]
|
||||
|
||||
for att, val in s.items():
|
||||
if att not in ('points'):
|
||||
setattr(ns, att, val)
|
||||
pts_to_add = len(s['points'])
|
||||
# print(pts_to_add, 'points')#dbg
|
||||
|
||||
ns.points.add(pts_to_add)
|
||||
# ns.points.add(pts_to_add)
|
||||
|
||||
ob_mat_inv = obj.matrix_world.inverted()
|
||||
|
||||
## patch pressure 1
|
||||
# pressure_flat_list = [di['pressure'] for di in s['points']] #get all pressure flatened
|
||||
## patch radius 1
|
||||
# radius_flat_list = [di['radius'] for di in s['points']] #get all radius flatened
|
||||
|
||||
if layer.is_parented:
|
||||
if layer.parent:
|
||||
mat = getMatrix(layer).inverted()
|
||||
for i, pt in enumerate(s['points']):
|
||||
for k, v in pt.items():
|
||||
if k == 'co':
|
||||
if k == 'position':
|
||||
setattr(ns.points[i], k, v)
|
||||
ns.points[i].position = ob_mat_inv @ mat @ ns.points[i].position # invert of object * invert of layer * coordinate
|
||||
else:
|
||||
|
@ -361,19 +362,14 @@ def add_stroke(s, frame, layer, obj, select=False):
|
|||
else:
|
||||
for i, pt in enumerate(s['points']):
|
||||
for k, v in pt.items():
|
||||
if k == 'co':
|
||||
if k == 'position':
|
||||
setattr(ns.points[i], k, v)
|
||||
ns.points[i].position = ob_mat_inv @ ns.points[i].position# invert of object * coordinate
|
||||
else:
|
||||
setattr(ns.points[i], k, v)
|
||||
if select:
|
||||
ns.points[i].select = True
|
||||
|
||||
## trigger updapte (in 2.93 fix some drawing problem with fills and UVs)
|
||||
ns.points.update()
|
||||
|
||||
## patch pressure 2
|
||||
# ns.points.foreach_set('pressure', pressure_flat_list)
|
||||
|
||||
def add_multiple_strokes(stroke_list, layer=None, use_current_frame=True, select=False):
|
||||
'''
|
||||
|
@ -436,7 +432,7 @@ class GPCLIP_OT_copy_strokes(bpy.types.Operator):
|
|||
# return {"CANCELLED"}
|
||||
|
||||
t0 = time()
|
||||
#ct = check_pressure()
|
||||
#ct = check_radius()
|
||||
strokelist = copycut_strokes(copy=True, keep_empty=True)
|
||||
if not strokelist:
|
||||
self.report({'ERROR'}, 'Nothing to copy')
|
||||
|
@ -465,7 +461,7 @@ class GPCLIP_OT_cut_strokes(bpy.types.Operator):
|
|||
# return {"CANCELLED"}
|
||||
|
||||
t0 = time()
|
||||
strokelist = copycut_strokes(copy=False, keep_empty=True) # ct = check_pressure()
|
||||
strokelist = copycut_strokes(copy=False, keep_empty=True) # ct = check_radius()
|
||||
if not strokelist:
|
||||
self.report({'ERROR'},'Nothing to cut')
|
||||
return {"CANCELLED"}
|
||||
|
@ -517,18 +513,20 @@ class GPCLIP_OT_copy_multi_strokes(bpy.types.Operator):
|
|||
def poll(cls, context):
|
||||
return context.object and context.object.type == 'GREASEPENCIL'
|
||||
|
||||
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)')
|
||||
radius : bpy.props.BoolProperty(name='radius', default=True,
|
||||
description='Dump point radius attribute (already skipped if at default value)')
|
||||
opacity : bpy.props.BoolProperty(name='opacity', default=True,
|
||||
description='Dump point opacity 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)')
|
||||
fill_color : bpy.props.BoolProperty(name='fill color', default=True,
|
||||
description='Dump point fill_color attribute (already skipped if at default value)')
|
||||
fill_opacity : bpy.props.BoolProperty(name='fill opacity', default=True,
|
||||
description='Dump point fill_opacity 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)')
|
||||
rotation : bpy.props.BoolProperty(name='rotation', default=True,
|
||||
description='Dump point rotation attribute (already skipped if at default value)')
|
||||
|
||||
def invoke(self, context, event):
|
||||
# self.file_dump = event.ctrl
|
||||
|
@ -540,12 +538,12 @@ class GPCLIP_OT_copy_multi_strokes(bpy.types.Operator):
|
|||
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, 'radius')
|
||||
col.prop(self, 'opacity')
|
||||
col.prop(self, 'vertex_color')
|
||||
col.prop(self, 'uv_fill')
|
||||
col.prop(self, 'uv_factor')
|
||||
col.prop(self, 'uv_rotation')
|
||||
col.prop(self, 'fill_color')
|
||||
col.prop(self, 'fill_opacity')
|
||||
col.prop(self, 'rotation')
|
||||
return
|
||||
|
||||
def execute(self, context):
|
||||
|
@ -556,7 +554,7 @@ class GPCLIP_OT_copy_multi_strokes(bpy.types.Operator):
|
|||
obj = context.object
|
||||
gpl = obj.data.layers
|
||||
t0 = time()
|
||||
#ct = check_pressure()
|
||||
#ct = check_radius()
|
||||
layerdic = {}
|
||||
|
||||
layerpool = [l for l in gpl if not l.hide and l.select] # and not l.lock
|
||||
|
@ -575,8 +573,8 @@ class GPCLIP_OT_copy_multi_strokes(bpy.types.Operator):
|
|||
continue
|
||||
context.scene.frame_set(f.frame_number) # use matrix of this frame
|
||||
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)
|
||||
radius=self.radius, opacity=self.opacity, vertex_color=self.vertex_color,
|
||||
fill_color=self.fill_color, uv_factor=self.uv_factor, rotation=self.rotation)
|
||||
|
||||
frame_dic[f.frame_number] = strokelist
|
||||
|
||||
|
@ -612,8 +610,8 @@ class GPCLIP_OT_copy_multi_strokes(bpy.types.Operator):
|
|||
continue
|
||||
|
||||
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)
|
||||
radius=self.radius, opacity=self.opacity, vertex_color=self.vertex_color,
|
||||
fill_color=self.fill_color, uv_factor=self.uv_factor, rotation=self.rotation)
|
||||
|
||||
frame_dic[i] = strokelist
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@ class GPTB_OT_jump_gp_keyframe(bpy.types.Operator):
|
|||
('MOVING_HOLD', 'Moving Hold', '', 'KEYTYPE_MOVING_HOLD_VEC', 4),
|
||||
('EXTREME', 'Extreme', '', 'KEYTYPE_EXTREME_VEC', 5),
|
||||
('JITTER', 'Jitter', '', 'KEYTYPE_JITTER_VEC', 6),
|
||||
('GENERATED', 'Generated', '', 'KEYTYPE_GENERATED_VEC', 7),
|
||||
))
|
||||
|
||||
def execute(self, context):
|
||||
|
|
Loading…
Reference in New Issue