parent
94fc926f7a
commit
5d35074d3d
|
@ -48,6 +48,7 @@ def convertAttr(Attr):
|
||||||
def getMatrix (layer) :
|
def getMatrix (layer) :
|
||||||
matrix = mathutils.Matrix.Identity(4)
|
matrix = mathutils.Matrix.Identity(4)
|
||||||
|
|
||||||
|
## FIXME: not "is_parent" or parent_type anymore
|
||||||
if layer.is_parented:
|
if layer.is_parented:
|
||||||
if layer.parent_type == 'BONE':
|
if layer.parent_type == 'BONE':
|
||||||
object = layer.parent
|
object = layer.parent
|
||||||
|
@ -175,26 +176,30 @@ def copycut_strokes(layers=None, copy=True, keep_empty=True):
|
||||||
if not copy:
|
if not copy:
|
||||||
staylist = [] # init part of strokes that must survive on this layer
|
staylist = [] # init part of strokes that must survive on this layer
|
||||||
|
|
||||||
for s in f.drawing.strokes:
|
rm_list = [] # init strokes that must be removed from this layer
|
||||||
if s.select:
|
for s_index, stroke in f.drawing.strokes:
|
||||||
|
if stroke.select:
|
||||||
# separate in multiple stroke if parts of the strokes a selected.
|
# separate in multiple stroke if parts of the strokes a selected.
|
||||||
sel = [i for i, p in enumerate(s.points) if p.select]
|
sel = [i for i, p in enumerate(stroke.points) if p.select]
|
||||||
substrokes = [] # list of list containing isolated selection
|
substrokes = [] # list of list containing isolated selection
|
||||||
for k, g in groupby(enumerate(sel), lambda x:x[0]-x[1]):# continuity stroke have same substract result between point index and enumerator
|
|
||||||
|
# continuity stroke have same substract result between point index and enumerator
|
||||||
|
for k, g in groupby(enumerate(sel), lambda x:x[0]-x[1]):
|
||||||
group = list(map(itemgetter(1), g))
|
group = list(map(itemgetter(1), g))
|
||||||
substrokes.append(group)
|
substrokes.append(group)
|
||||||
|
|
||||||
for ss in substrokes:
|
for ss in substrokes:
|
||||||
if len(ss) > 1: # avoid copy isolated points
|
if len(ss) > 1: # avoid copy isolated points
|
||||||
stroke_list.append(dump_gp_stroke_range(s,ss,l,obj))
|
stroke_list.append(dump_gp_stroke_range(stroke, ss, l, obj))
|
||||||
|
|
||||||
# Cutting operation
|
# Cutting operation
|
||||||
if not copy:
|
if not copy:
|
||||||
maxindex = len(s.points)-1
|
maxindex = len(stroke.points)-1
|
||||||
if len(substrokes) == maxindex+1: # if only one substroke, then it's the full stroke
|
if len(substrokes) == maxindex+1: # if only one substroke, then it's the full stroke
|
||||||
f.drawing.strokes.remove(s)
|
# f.drawing.strokes.remove(stroke)
|
||||||
|
rm_list.append(stroke)
|
||||||
else:
|
else:
|
||||||
neg = [i for i, p in enumerate(s.points) if not p.select]
|
neg = [i for i, p in enumerate(stroke.points) if not p.select]
|
||||||
|
|
||||||
staying = []
|
staying = []
|
||||||
for k, g in groupby(enumerate(neg), lambda x:x[0]-x[1]):
|
for k, g in groupby(enumerate(neg), lambda x:x[0]-x[1]):
|
||||||
|
@ -208,32 +213,32 @@ def copycut_strokes(layers=None, copy=True, keep_empty=True):
|
||||||
|
|
||||||
for ns in staying:
|
for ns in staying:
|
||||||
if len(ns) > 1:
|
if len(ns) > 1:
|
||||||
staylist.append(dump_gp_stroke_range(s,ns,l,obj))
|
staylist.append(dump_gp_stroke_range(stroke, ns, l, obj))
|
||||||
# make a negative list containing all last index
|
# make a negative list containing all last index
|
||||||
|
|
||||||
|
|
||||||
'''#full stroke version
|
'''#full stroke version
|
||||||
# if s.colorname == color: #line for future filters
|
# if stroke.colorname == color: #line for future filters
|
||||||
stroke_list.append(dump_gp_stroke(s,l))
|
stroke_list.append(dump_gp_stroke(stroke,l))
|
||||||
#delete stroke on the fly
|
#delete stroke on the fly
|
||||||
if not copy:
|
if not copy:
|
||||||
f.drawing.strokes.remove(s)
|
f.drawing.strokes.remove(stroke)
|
||||||
'''
|
'''
|
||||||
|
if rm_list:
|
||||||
|
f.drawing.remove_strokes(indices=rm_list)
|
||||||
|
|
||||||
if not copy:
|
if not copy:
|
||||||
|
selected_ids = [i for i, s in enumerate(f.drawing.strokes) if s.select]
|
||||||
# delete all selected strokes...
|
# delete all selected strokes...
|
||||||
for s in f.drawing.strokes:
|
f.drawing.strokes.remove_strokes(indices=selected_ids)
|
||||||
if s.select:
|
|
||||||
f.drawing.strokes.remove(s)
|
|
||||||
# ...recreate these uncutted ones
|
# ...recreate these uncutted ones
|
||||||
#pprint(staylist)
|
#pprint(staylist)
|
||||||
if staylist:
|
if staylist:
|
||||||
add_multiple_strokes(staylist, l)
|
add_multiple_strokes(staylist, l)
|
||||||
#for ns in staylist:#weirdly recreate the stroke twice !
|
|
||||||
# add_stroke(ns, f, l)
|
|
||||||
|
|
||||||
#if nothing left on the frame choose to leave an empty frame or delete it (let previous frame appear)
|
# If nothing left on the frame choose to leave an empty frame or delete it (let previous frame appear)
|
||||||
if not copy and not keep_empty:#
|
if not copy and not keep_empty:
|
||||||
if not len(f.drawing.strokes):
|
if not len(f.drawing.strokes):
|
||||||
l.frames.remove(f)
|
l.frames.remove(f)
|
||||||
|
|
||||||
|
|
|
@ -819,7 +819,7 @@ def register():
|
||||||
|
|
||||||
bpy.types.DATA_PT_grease_pencil_layers.prepend(layer_name_builder_ui)
|
bpy.types.DATA_PT_grease_pencil_layers.prepend(layer_name_builder_ui)
|
||||||
bpy.types.DOPESHEET_HT_header.append(gpencil_dopesheet_header)
|
bpy.types.DOPESHEET_HT_header.append(gpencil_dopesheet_header)
|
||||||
bpy.types.GPENCIL_MT_layer_context_menu.append(gpencil_layer_dropdown_menu)
|
bpy.types.GREASE_PENCIL_MT_grease_pencil_add_layer_extra.append(gpencil_layer_dropdown_menu)
|
||||||
bpy.app.handlers.load_post.append(subscribe_layer_change_handler)
|
bpy.app.handlers.load_post.append(subscribe_layer_change_handler)
|
||||||
register_keymaps()
|
register_keymaps()
|
||||||
|
|
||||||
|
@ -829,7 +829,7 @@ def register():
|
||||||
def unregister():
|
def unregister():
|
||||||
unregister_keymaps()
|
unregister_keymaps()
|
||||||
bpy.app.handlers.load_post.remove(subscribe_layer_change_handler)
|
bpy.app.handlers.load_post.remove(subscribe_layer_change_handler)
|
||||||
bpy.types.GPENCIL_MT_layer_context_menu.remove(gpencil_layer_dropdown_menu)
|
bpy.types.GREASE_PENCIL_MT_grease_pencil_add_layer_extra.remove(gpencil_layer_dropdown_menu)
|
||||||
bpy.types.DOPESHEET_HT_header.remove(gpencil_dopesheet_header)
|
bpy.types.DOPESHEET_HT_header.remove(gpencil_dopesheet_header)
|
||||||
bpy.types.DATA_PT_grease_pencil_layers.remove(layer_name_builder_ui)
|
bpy.types.DATA_PT_grease_pencil_layers.remove(layer_name_builder_ui)
|
||||||
|
|
||||||
|
|
|
@ -46,7 +46,7 @@ bpy.ops.object.mode_set(mode=omode)
|
||||||
|
|
||||||
def batch_reproject(obj, proj_type='VIEW', all_strokes=True, restore_frame=False):
|
def batch_reproject(obj, proj_type='VIEW', all_strokes=True, restore_frame=False):
|
||||||
'''Reproject - ops method
|
'''Reproject - ops method
|
||||||
:all_stroke: affect hided, locked layers
|
:all_stroke: affect hidden, locked layers
|
||||||
'''
|
'''
|
||||||
|
|
||||||
if restore_frame:
|
if restore_frame:
|
||||||
|
@ -77,8 +77,12 @@ def batch_reproject(obj, proj_type='VIEW', all_strokes=True, restore_frame=False
|
||||||
continue
|
continue
|
||||||
f = next((f for f in l.frames if f.frame_number == i), None)
|
f = next((f for f in l.frames if f.frame_number == i), None)
|
||||||
if f is None:
|
if f is None:
|
||||||
|
# FIXME: some strokes are ingored
|
||||||
|
# print(f'skip {l.name}, no frame at {i}')
|
||||||
continue
|
continue
|
||||||
for s in f.drawing.strokes:
|
for s in f.drawing.strokes:
|
||||||
|
# print(l.name, s.material_index)
|
||||||
|
|
||||||
## Batch matrix apply (Here is slower than list comprehension).
|
## Batch matrix apply (Here is slower than list comprehension).
|
||||||
# nb_points = len(s.points)
|
# nb_points = len(s.points)
|
||||||
# coords = np.empty(nb_points * 3, dtype='float64')
|
# coords = np.empty(nb_points * 3, dtype='float64')
|
||||||
|
@ -90,17 +94,16 @@ def batch_reproject(obj, proj_type='VIEW', all_strokes=True, restore_frame=False
|
||||||
|
|
||||||
new_world_co_3d = [intersect_line_plane(origin, p, plan_co, plane_no) for p in world_co_3d]
|
new_world_co_3d = [intersect_line_plane(origin, p, plan_co, plane_no) for p in world_co_3d]
|
||||||
|
|
||||||
## Basic method (Slower than foreach_set)
|
# Basic method (Slower than foreach_set and compatible with GPv3)
|
||||||
# for i, p in enumerate(s.points):
|
## TODO: use low level api with curve offsets...
|
||||||
# p.position = obj.matrix_world.inverted() @ new_world_co_3d[i]
|
for i, p in enumerate(s.points):
|
||||||
|
p.position = matrix_inv @ new_world_co_3d[i]
|
||||||
|
|
||||||
|
## GPv2: ravel and use foreach_set
|
||||||
## Ravel new coordinate on the fly
|
## Ravel new coordinate on the fly
|
||||||
new_local_coords = [axis for p in new_world_co_3d for axis in matrix_inv @ p]
|
## NOTE: Set points in obj local space (apply matrix is slower): new_local_coords = utils.matrix_transform(new_world_co_3d, matrix_inv).ravel()
|
||||||
|
# new_local_coords = [axis for p in new_world_co_3d for axis in matrix_inv @ p]
|
||||||
## Set points in obj local space (apply matrix slower)
|
# s.points.foreach_set('co', new_local_coords)
|
||||||
# new_local_coords = utils.matrix_transform(new_world_co_3d, matrix_inv).ravel()
|
|
||||||
s.points.foreach_set('co', new_local_coords)
|
|
||||||
|
|
||||||
|
|
||||||
if restore_frame:
|
if restore_frame:
|
||||||
bpy.context.scene.frame_current = oframe
|
bpy.context.scene.frame_current = oframe
|
||||||
|
@ -142,21 +145,21 @@ def align_global(reproject=True, ref=None, all_strokes=True):
|
||||||
for s in f.drawing.strokes:
|
for s in f.drawing.strokes:
|
||||||
## foreach
|
## foreach
|
||||||
coords = [p.position @ mat.inverted() @ new_mat for p in s.points]
|
coords = [p.position @ mat.inverted() @ new_mat for p in s.points]
|
||||||
# print('coords: ', coords)
|
|
||||||
# print([co for v in coords for co in v])
|
|
||||||
s.points.foreach_set('co', [co for v in coords for co in v])
|
|
||||||
# s.points.update() # seem to works # but adding/deleting a point is "safer"
|
|
||||||
## force update
|
|
||||||
s.points.add(1)
|
|
||||||
s.points.pop()
|
|
||||||
|
|
||||||
# for p in s.points:
|
## GPv2
|
||||||
|
# s.points.foreach_set('co', [co for v in coords for co in v])
|
||||||
|
# # s.points.update() # seem to works # but adding/deleting a point is "safer"
|
||||||
|
# ## force update
|
||||||
|
# s.points.add(1)
|
||||||
|
# s.points.pop()
|
||||||
|
|
||||||
|
for p in s.points:
|
||||||
## GOOD :
|
## GOOD :
|
||||||
# world_co = mat @ p.position
|
# world_co = mat @ p.position
|
||||||
# p.position = new_mat.inverted() @ world_co
|
# p.position = new_mat.inverted() @ world_co
|
||||||
|
|
||||||
## GOOD :
|
## GOOD :
|
||||||
# p.position = p.position @ mat.inverted() @ new_mat
|
p.position = p.position @ mat.inverted() @ new_mat
|
||||||
|
|
||||||
if o.parent:
|
if o.parent:
|
||||||
o.matrix_world = new_mat
|
o.matrix_world = new_mat
|
||||||
|
@ -450,12 +453,12 @@ def register():
|
||||||
for cl in classes:
|
for cl in classes:
|
||||||
bpy.utils.register_class(cl)
|
bpy.utils.register_class(cl)
|
||||||
|
|
||||||
bpy.types.VIEW3D_MT_grease_pencil_edit_context_menu.append(reproject_context_menu)
|
bpy.types.VIEW3D_MT_greasepencil_edit_context_menu.append(reproject_context_menu)
|
||||||
bpy.types.GPENCIL_MT_cleanup.append(reproject_clean_menu)
|
bpy.types.VIEW3D_MT_edit_greasepencil_cleanup.append(reproject_clean_menu)
|
||||||
|
|
||||||
def unregister():
|
def unregister():
|
||||||
bpy.types.GPENCIL_MT_cleanup.remove(reproject_clean_menu)
|
bpy.types.VIEW3D_MT_edit_greasepencil_cleanup.remove(reproject_clean_menu)
|
||||||
bpy.types.VIEW3D_MT_grease_pencil_edit_context_menu.remove(reproject_context_menu)
|
bpy.types.VIEW3D_MT_greasepencil_edit_context_menu.remove(reproject_context_menu)
|
||||||
|
|
||||||
for cl in reversed(classes):
|
for cl in reversed(classes):
|
||||||
bpy.utils.unregister_class(cl)
|
bpy.utils.unregister_class(cl)
|
|
@ -166,7 +166,9 @@ class GPTB_PT_sidebar_panel(Panel):
|
||||||
else:
|
else:
|
||||||
col.label(text='No GP object selected')
|
col.label(text='No GP object selected')
|
||||||
|
|
||||||
col.prop(context.scene.gptoolprops, 'edit_lines_opacity')
|
|
||||||
|
## Gpv3: not more edit line (use Curve lines)
|
||||||
|
# col.prop(context.scene.gptoolprops, 'edit_lines_opacity')
|
||||||
|
|
||||||
# Mention update as notice
|
# Mention update as notice
|
||||||
# addon_updater_ops.update_notice_box_ui(self, context)
|
# addon_updater_ops.update_notice_box_ui(self, context)
|
||||||
|
|
|
@ -99,6 +99,7 @@ def gp_stroke_angle_split (frame, strokes, angle):
|
||||||
|
|
||||||
splitted_loops = bm_angle_split(bm,angle)
|
splitted_loops = bm_angle_split(bm,angle)
|
||||||
|
|
||||||
|
## FIXME: Should use -> drawing.remove_strokes(indices=(0,))
|
||||||
frame.drawing.strokes.remove(stroke_info['stroke'])
|
frame.drawing.strokes.remove(stroke_info['stroke'])
|
||||||
for loop in splitted_loops :
|
for loop in splitted_loops :
|
||||||
loop_info = [{'co':v.co,'strength': v[strength], 'pressure' :v[pressure],'select':v[select]} for v in loop]
|
loop_info = [{'co':v.co,'strength': v[strength], 'pressure' :v[pressure],'select':v[select]} for v in loop]
|
||||||
|
@ -123,6 +124,7 @@ def gp_stroke_uniform_density(cam, frame, strokes, max_spacing):
|
||||||
|
|
||||||
bm_uniform_density(bm,cam,max_spacing)
|
bm_uniform_density(bm,cam,max_spacing)
|
||||||
|
|
||||||
|
## FIXME: Should use -> drawing.remove_strokes(indices=(0,))
|
||||||
frame.strokes.remove(stroke_info['stroke'])
|
frame.strokes.remove(stroke_info['stroke'])
|
||||||
bm.verts.ensure_lookup_table()
|
bm.verts.ensure_lookup_table()
|
||||||
|
|
||||||
|
|
|
@ -182,9 +182,10 @@ class GP_PG_ToolsSettings(PropertyGroup):
|
||||||
name='Cursor Follow', description="3D cursor follow active object animation when activated",
|
name='Cursor Follow', description="3D cursor follow active object animation when activated",
|
||||||
default=False, update=cursor_follow_update)
|
default=False, update=cursor_follow_update)
|
||||||
|
|
||||||
edit_lines_opacity : FloatProperty(
|
## gpv3 : no edit line color anymore
|
||||||
name="Edit Lines Opacity", description="Change edit lines opacity for all grease pencils",
|
# edit_lines_opacity : FloatProperty(
|
||||||
default=0.5, min=0.0, max=1.0, step=3, precision=2, update=change_edit_lines_opacity)
|
# name="Edit Lines Opacity", description="Change edit lines opacity for all grease pencils",
|
||||||
|
# default=0.5, min=0.0, max=1.0, step=3, precision=2, update=change_edit_lines_opacity)
|
||||||
|
|
||||||
## render
|
## render
|
||||||
name_for_current_render : StringProperty(
|
name_for_current_render : StringProperty(
|
||||||
|
|
15
utils.py
15
utils.py
|
@ -706,20 +706,7 @@ def set_collection(ob, collection, unlink=True) :
|
||||||
# -----------------
|
# -----------------
|
||||||
|
|
||||||
def get_addon_prefs():
|
def get_addon_prefs():
|
||||||
'''
|
return bpy.context.preferences.addons[__package__].preferences
|
||||||
function to read current addon preferences properties
|
|
||||||
|
|
||||||
access a prop like this :
|
|
||||||
prefs = get_addon_prefs()
|
|
||||||
option_state = prefs.super_special_option
|
|
||||||
|
|
||||||
oneliner : get_addon_prefs().super_special_option
|
|
||||||
'''
|
|
||||||
import os
|
|
||||||
addon_name = os.path.splitext(__name__)[0]
|
|
||||||
preferences = bpy.context.preferences
|
|
||||||
addon_prefs = preferences.addons[addon_name].preferences
|
|
||||||
return (addon_prefs)
|
|
||||||
|
|
||||||
def open_addon_prefs():
|
def open_addon_prefs():
|
||||||
'''Open addon prefs windows with focus on current addon'''
|
'''Open addon prefs windows with focus on current addon'''
|
||||||
|
|
Loading…
Reference in New Issue