Fix duplicate-send to to layer
parent
d3e4072564
commit
6dbf666ee3
|
@ -1,5 +1,6 @@
|
|||
import bpy
|
||||
from bpy.types import Operator
|
||||
from . import utils
|
||||
|
||||
|
||||
def get_layer_list(self, context):
|
||||
|
@ -65,26 +66,24 @@ class GPTB_OT_duplicate_send_to_layer(Operator) :
|
|||
|
||||
## Remove overlapping frames
|
||||
for f in reversed(to_replace):
|
||||
target_layer.frames.remove(f)
|
||||
|
||||
# FIXME : need to createa a dedicated function to copy a frame
|
||||
target_layer.frames.remove(f.frame_number)
|
||||
|
||||
## Copy original frames
|
||||
for f in selected_frames:
|
||||
target_layer.frames.copy(f)
|
||||
utils.copy_frame_at(f, target_layer, f.frame_number)
|
||||
# target_layer.frames.copy(f) # GPv2
|
||||
sent = len(selected_frames)
|
||||
|
||||
## Delete original frames as an option
|
||||
if self.delete_source:
|
||||
for f in reversed(selected_frames):
|
||||
act_layer.frames.remove(f)
|
||||
act_layer.frames.remove(f.frame_number)
|
||||
mess = f'{sent} keys moved'
|
||||
else:
|
||||
mess = f'{sent} keys copied'
|
||||
|
||||
mess = f'{sent} keys copied'
|
||||
if replaced:
|
||||
mess += f' ({replaced} replaced)'
|
||||
|
||||
mod = context.mode
|
||||
bpy.ops.gpencil.editmode_toggle()
|
||||
bpy.ops.object.mode_set(mode=mod)
|
||||
|
||||
self.report({'INFO'}, mess)
|
||||
return {'FINISHED'}
|
||||
|
|
101
utils.py
101
utils.py
|
@ -5,6 +5,7 @@ import mathutils
|
|||
import math
|
||||
import subprocess
|
||||
|
||||
from time import time
|
||||
from math import sqrt
|
||||
from mathutils import Vector
|
||||
from sys import platform
|
||||
|
@ -589,6 +590,106 @@ def copy_stroke_to_frame(s, frame, select=True):
|
|||
ns.points.update()
|
||||
return ns
|
||||
|
||||
def bulk_copy_attributes(source_attr, target_attr):
|
||||
# Get the data as flat numpy array based on attribute type and domain
|
||||
if source_attr.data_type == 'INT':
|
||||
data = np.empty(len(source_attr.data), dtype=np.int32)
|
||||
source_attr.data.foreach_get('value', data)
|
||||
target_attr.data.foreach_set('value', data)
|
||||
elif source_attr.data_type == 'INT8':
|
||||
data = np.empty(len(source_attr.data), dtype=np.int8)
|
||||
source_attr.data.foreach_get('value', data)
|
||||
target_attr.data.foreach_set('value', data)
|
||||
elif source_attr.data_type == 'FLOAT':
|
||||
data = np.empty(len(source_attr.data), dtype=np.float32)
|
||||
source_attr.data.foreach_get('value', data)
|
||||
target_attr.data.foreach_set('value', data)
|
||||
elif source_attr.data_type == 'FLOAT_VECTOR':
|
||||
data = np.empty(len(source_attr.data) * 3, dtype=np.float32)
|
||||
source_attr.data.foreach_get('vector', data)
|
||||
target_attr.data.foreach_set('vector', data)
|
||||
elif source_attr.data_type == 'FLOAT_COLOR':
|
||||
data = np.empty(len(source_attr.data) * 4, dtype=np.float32)
|
||||
source_attr.data.foreach_get('color', data)
|
||||
target_attr.data.foreach_set('color', data)
|
||||
elif source_attr.data_type == 'BOOLEAN':
|
||||
data = np.empty(len(source_attr.data), dtype=bool)
|
||||
source_attr.data.foreach_get('value', data)
|
||||
target_attr.data.foreach_set('value', data)
|
||||
|
||||
## Filter by domain ? (not needed it seem, dtypes are the same)
|
||||
'''
|
||||
if source_attr.domain == 'POINT':
|
||||
if source_attr.data_type == 'FLOAT':
|
||||
data = np.empty(len(source_attr.data), dtype=np.float32)
|
||||
source_attr.data.foreach_get('value', data)
|
||||
target_attr.data.foreach_set('value', data)
|
||||
elif source_attr.data_type == 'FLOAT_VECTOR':
|
||||
data = np.empty(len(source_attr.data) * 3, dtype=np.float32)
|
||||
source_attr.data.foreach_get('vector', data)
|
||||
target_attr.data.foreach_set('vector', data)
|
||||
elif source_attr.data_type == 'FLOAT_COLOR':
|
||||
data = np.empty(len(source_attr.data) * 4, dtype=np.float32)
|
||||
source_attr.data.foreach_get('color', data)
|
||||
target_attr.data.foreach_set('color', data)
|
||||
## No Boolean by defaut on points domain
|
||||
elif source_attr.domain == 'CURVE':
|
||||
if source_attr.data_type == 'INT':
|
||||
data = np.empty(len(source_attr.data), dtype=np.int32)
|
||||
source_attr.data.foreach_get('value', data)
|
||||
target_attr.data.foreach_set('value', data)
|
||||
elif source_attr.data_type == 'INT8':
|
||||
data = np.empty(len(source_attr.data), dtype=np.int8)
|
||||
source_attr.data.foreach_get('value', data)
|
||||
target_attr.data.foreach_set('value', data)
|
||||
elif source_attr.data_type == 'FLOAT_COLOR':
|
||||
data = np.empty(len(source_attr.data) * 4, dtype=np.float32)
|
||||
source_attr.data.foreach_get('color', data)
|
||||
target_attr.data.foreach_set('color', data)
|
||||
elif source_attr.data_type == 'BOOLEAN':
|
||||
data = np.empty(len(source_attr.data), dtype=bool)
|
||||
source_attr.data.foreach_get('value', data)
|
||||
target_attr.data.foreach_set('value', data)
|
||||
'''
|
||||
|
||||
|
||||
def copy_attribute_values(src_dr, dst_dr, source_attr, dest_attr):
|
||||
## Zip method to copy one by one
|
||||
## One liner
|
||||
# val_type = {'FLOAT_COLOR': 'color','FLOAT_VECTOR': 'vector'}.get(source_attr.data_type, 'value')
|
||||
if source_attr.data_type == 'FLOAT_COLOR':
|
||||
val_type = 'color'
|
||||
elif source_attr.data_type == 'FLOAT_VECTOR':
|
||||
val_type = 'vector'
|
||||
else:
|
||||
val_type = 'value'
|
||||
## /!\ DOESN'T WORK. index is wrong
|
||||
for src_idx, dest_idx in zip(
|
||||
range(src_dr.curve_offsets[0].value, src_dr.curve_offsets[-1].value),
|
||||
range(dst_dr.curve_offsets[0].value, dst_dr.curve_offsets[-1].value)):
|
||||
setattr(dest_attr.data[dest_idx], val_type, getattr(source_attr.data[src_idx], val_type))
|
||||
|
||||
def copy_frame_at(source_frame, layer, frame_number):
|
||||
'''Copy a frame (source_frame) to a layer at given frame_number'''
|
||||
source_drawing = source_frame.drawing
|
||||
|
||||
frame = layer.frames.new(frame_number)
|
||||
dr = frame.drawing
|
||||
dr.add_strokes([len(s.points) for s in source_drawing.strokes])
|
||||
for attr_name in source_drawing.attributes.keys():
|
||||
source_attr = source_drawing.attributes[attr_name]
|
||||
if attr_name not in dr.attributes:
|
||||
dr.attributes.new(
|
||||
name=attr_name, type=source_attr.data_type, domain=source_attr.domain)
|
||||
target_attr = dr.attributes[attr_name]
|
||||
bulk_copy_attributes(source_attr, target_attr)
|
||||
|
||||
## Broken
|
||||
# start_time = time()
|
||||
# copy_attribute_values(source_drawing, dr, source_attr, target_attr)
|
||||
# end_time = time()
|
||||
# print(f"copy_attribute_values execution time: {end_time - start_time} seconds")
|
||||
|
||||
# -----------------
|
||||
### Vector utils 3d
|
||||
# -----------------
|
||||
|
|
Loading…
Reference in New Issue