Fix duplicate-send to to layer
This commit is contained in:
		
							parent
							
								
									d3e4072564
								
							
						
					
					
						commit
						6dbf666ee3
					
				| @ -1,5 +1,6 @@ | |||||||
| import bpy | import bpy | ||||||
| from bpy.types import Operator | from bpy.types import Operator | ||||||
|  | from . import utils | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def get_layer_list(self, context): | def get_layer_list(self, context): | ||||||
| @ -65,27 +66,25 @@ class GPTB_OT_duplicate_send_to_layer(Operator) : | |||||||
|          |          | ||||||
|         ## Remove overlapping frames |         ## Remove overlapping frames | ||||||
|         for f in reversed(to_replace): |         for f in reversed(to_replace): | ||||||
|             target_layer.frames.remove(f) |             target_layer.frames.remove(f.frame_number) | ||||||
| 
 | 
 | ||||||
|         # FIXME : need to createa a dedicated function to copy a frame |  | ||||||
|         ## Copy original frames |         ## Copy original frames | ||||||
|         for f in selected_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) |         sent = len(selected_frames) | ||||||
| 
 | 
 | ||||||
|         ## Delete original frames as an option |         ## Delete original frames as an option | ||||||
|         if self.delete_source: |         if self.delete_source: | ||||||
|             for f in reversed(selected_frames): |             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: |         if replaced: | ||||||
|             mess += f' ({replaced} replaced)' |             mess += f' ({replaced} replaced)' | ||||||
|          |          | ||||||
|         mod = context.mode |  | ||||||
|         bpy.ops.gpencil.editmode_toggle() |  | ||||||
|         bpy.ops.object.mode_set(mode=mod) |  | ||||||
|          |  | ||||||
|         self.report({'INFO'}, mess) |         self.report({'INFO'}, mess) | ||||||
|         return {'FINISHED'} |         return {'FINISHED'} | ||||||
| 
 | 
 | ||||||
|  | |||||||
							
								
								
									
										101
									
								
								utils.py
									
									
									
									
									
								
							
							
						
						
									
										101
									
								
								utils.py
									
									
									
									
									
								
							| @ -5,6 +5,7 @@ import mathutils | |||||||
| import math | import math | ||||||
| import subprocess | import subprocess | ||||||
| 
 | 
 | ||||||
|  | from time import time | ||||||
| from math import sqrt | from math import sqrt | ||||||
| from mathutils import Vector | from mathutils import Vector | ||||||
| from sys import platform | from sys import platform | ||||||
| @ -589,6 +590,106 @@ def copy_stroke_to_frame(s, frame, select=True): | |||||||
|     ns.points.update() |     ns.points.update() | ||||||
|     return ns |     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 | ### Vector utils 3d | ||||||
| # ----------------- | # ----------------- | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user