Fix io_anim_camera error exporting cameras with quotes in their name
[blender-addons.git] / curve_tools / splines_sequence.py
blob987660582a4d3a7747cfadc22b82c9f06b6a59fd
1 # SPDX-License-Identifier: GPL-2.0-or-later
4 import bpy
6 import bgl
7 import blf
8 import gpu
9 from gpu_extras.batch import batch_for_shader
11 import math
12 import mathutils
13 from mathutils import Vector
15 from bpy.props import (
16 EnumProperty,
19 # ------------------------------------------------------------
20 # ShowSplinesSequence
22 def draw_number(n, co, font_height):
24 point_list = []
26 numeral = [
27 [Vector((0, 0, 0)), Vector((0, 2, 0)), Vector((0, 2, 0)), Vector((1, 2, 0)), Vector((1, 2, 0)), Vector((1, 0, 0)), Vector((1, 0, 0)), Vector((0, 0, 0))],
28 [Vector((0, 1, 0)), Vector((1, 2, 0)), Vector((1, 2, 0)), Vector((1, 0, 0))],
29 [Vector((0, 2, 0)), Vector((1, 2, 0)), Vector((1, 2, 0)), Vector((1, 1, 0)), Vector((1, 1, 0)), Vector((0, 0, 0)), Vector((0, 0, 0)), Vector((1, 0, 0))],
30 [Vector((0, 2, 0)), Vector((1, 2, 0)), Vector((1, 2, 0)), Vector((0, 1, 0)), Vector((0, 1, 0)), Vector((1, 1, 0)), Vector((1, 1, 0)), Vector((0, 0, 0))],
31 [Vector((0, 2, 0)), Vector((0, 1, 0)), Vector((0, 1, 0)), Vector((1, 1, 0)), Vector((1, 1, 0)), Vector((1, 2, 0)), Vector((1, 2, 0)), Vector((1, 0, 0))],
32 [Vector((1, 2, 0)), Vector((0, 2, 0)), Vector((0, 2, 0)), Vector((0, 1, 0)), Vector((0, 1, 0)), Vector((1, 1, 0)), Vector((1, 1, 0)), Vector((1, 0, 0)), Vector((1, 0, 0)), Vector((0, 0, 0))],
33 [Vector((1, 2, 0)), Vector((0, 1, 0)), Vector((0, 1, 0)), Vector((0, 0, 0)), Vector((0, 0, 0)), Vector((1, 0, 0)), Vector((1, 0, 0)), Vector((1, 1, 0)), Vector((1, 1, 0)), Vector((0, 1, 0))],
34 [Vector((0, 2, 0)), Vector((1, 2, 0)), Vector((1, 2, 0)), Vector((0, 1, 0)), Vector((0, 1, 0)), Vector((0, 0, 0))],
35 [Vector((0, 1, 0)), Vector((0, 2, 0)), Vector((0, 2, 0)), Vector((1, 2, 0)), Vector((1, 2, 0)), Vector((1, 0, 0)), Vector((1, 0, 0)), Vector((0, 0, 0)), Vector((0, 0, 0)), Vector((0, 1, 0)), Vector((0, 1, 0)), Vector((1, 1, 0))],
36 [Vector((0, 0, 0)), Vector((1, 1, 0)), Vector((1, 1, 0)), Vector((1, 2, 0)), Vector((1, 2, 0)), Vector((0, 2, 0)), Vector((0, 2, 0)), Vector((0, 1, 0)), Vector((0, 1, 0)), Vector((1, 1, 0))],
39 for num in numeral[n]:
40 point_list.extend([num * font_height + co])
42 return point_list
45 def draw(self, context, splines, sequence_color, font_thickness, font_size, matrix_world):
47 splines_len = len(splines)
48 for n in range(0, splines_len):
50 res = [int(x) for x in str(n)]
52 i = 0
53 for r in res:
54 # draw some text
55 if splines[n].type == 'BEZIER':
56 first_point_co = matrix_world @ splines[n].bezier_points[0].co
57 else:
58 first_point = matrix_world @ splines[n].points[0].co
59 first_point_co = Vector((first_point.x, first_point.y, first_point.z))
61 first_point_co = Vector((i, 0, 0)) + first_point_co
62 points = draw_number(r, first_point_co, font_size)
64 shader = gpu.shader.from_builtin('3D_UNIFORM_COLOR')
66 batch = batch_for_shader(shader, 'LINES', {"pos": points})
68 shader.bind()
69 bgl.glLineWidth(font_thickness)
70 shader.uniform_float("color", sequence_color)
71 batch.draw(shader)
72 i += font_size + font_size * 0.5
74 class ShowSplinesSequence(bpy.types.Operator):
75 bl_idname = "curvetools.show_splines_sequence"
76 bl_label = "Show Splines Sequence"
77 bl_description = "Show Splines Sequence / [ESC] - remove"
79 handlers = []
81 def modal(self, context, event):
82 context.area.tag_redraw()
84 if event.type in {'ESC'}:
85 for handler in self.handlers:
86 try:
87 bpy.types.SpaceView3D.draw_handler_remove(handler, 'WINDOW')
88 except:
89 pass
90 for handler in self.handlers:
91 self.handlers.remove(handler)
92 return {'CANCELLED'}
94 return {'PASS_THROUGH'}
97 def invoke(self, context, event):
99 if context.area.type == 'VIEW_3D':
101 # color change in the panel
102 sequence_color = bpy.context.scene.curvetools.sequence_color
103 font_thickness = bpy.context.scene.curvetools.font_thickness
104 font_size = bpy.context.scene.curvetools.font_size
106 splines = context.active_object.data.splines
107 matrix_world = context.active_object.matrix_world
109 # the arguments we pass the the callback
110 args = (self, context, splines, sequence_color, font_thickness, font_size, matrix_world)
112 # Add the region OpenGL drawing callback
113 # draw in view space with 'POST_VIEW' and 'PRE_VIEW'
114 self.handlers.append(bpy.types.SpaceView3D.draw_handler_add(draw, args, 'WINDOW', 'POST_VIEW'))
116 context.window_manager.modal_handler_add(self)
117 return {'RUNNING_MODAL'}
118 else:
119 self.report({'WARNING'},
120 "View3D not found, cannot run operator")
121 return {'CANCELLED'}
123 @classmethod
124 def poll(cls, context):
125 return (context.object is not None and
126 context.object.type == 'CURVE')
128 # ------------------------------------------------------------
129 # RearrangeSpline
131 def rearrangesplines(dataCurve, select_spline1, select_spline2):
133 spline1 = dataCurve.splines[select_spline1]
134 spline2 = dataCurve.splines[select_spline2]
136 bpy.ops.curve.select_all(action='SELECT')
137 bpy.ops.curve.spline_type_set(type='BEZIER')
138 bpy.ops.curve.select_all(action='DESELECT')
140 type1 = spline1.type
141 type2 = spline2.type
143 len_spline1 = len(spline1.bezier_points)
144 len_spline2 = len(spline2.bezier_points)
146 newSpline = dataCurve.splines.new(type=type1)
147 newSpline.bezier_points.add(len_spline1 - 1)
148 newSpline.use_cyclic_u = spline1.use_cyclic_u
149 for n in range(0, len_spline1):
150 newSpline.bezier_points[n].co = spline1.bezier_points[n].co
151 newSpline.bezier_points[n].handle_left_type = spline1.bezier_points[n].handle_left_type
152 newSpline.bezier_points[n].handle_left = spline1.bezier_points[n].handle_left
153 newSpline.bezier_points[n].handle_right_type = spline1.bezier_points[n].handle_right_type
154 newSpline.bezier_points[n].handle_right = spline1.bezier_points[n].handle_right
155 spline1.bezier_points[n].select_control_point = True
157 spline1.bezier_points[0].select_control_point = False
158 spline1.bezier_points[0].select_left_handle = False
159 spline1.bezier_points[0].select_right_handle = False
160 bpy.ops.curve.delete(type='VERT')
162 spline1.bezier_points[0].select_control_point = True
163 bpy.ops.curve.spline_type_set(type=type2)
165 bpy.ops.curve.select_all(action='DESELECT')
167 spline1.bezier_points.add(len_spline2 - 1)
168 spline1.use_cyclic_u = spline2.use_cyclic_u
169 for n in range(0, len_spline2):
170 spline1.bezier_points[n].co = spline2.bezier_points[n].co
171 spline1.bezier_points[n].handle_left_type = spline2.bezier_points[n].handle_left_type
172 spline1.bezier_points[n].handle_left = spline2.bezier_points[n].handle_left
173 spline1.bezier_points[n].handle_right_type = spline2.bezier_points[n].handle_right_type
174 spline1.bezier_points[n].handle_right = spline2.bezier_points[n].handle_right
175 spline1.bezier_points[n].select_control_point = False
176 spline1.bezier_points[n].select_left_handle = False
177 spline1.bezier_points[n].select_right_handle = False
178 spline2.bezier_points[n].select_control_point = True
180 spline2.bezier_points[0].select_control_point = False
181 spline2.bezier_points[0].select_left_handle = False
182 spline2.bezier_points[0].select_right_handle = False
183 bpy.ops.curve.delete(type='VERT')
185 spline2.bezier_points[0].select_control_point = True
186 bpy.ops.curve.spline_type_set(type=type1)
188 spline2.bezier_points.add(len_spline1 - 1)
189 spline2.use_cyclic_u = newSpline.use_cyclic_u
190 for m in range(0, len_spline1):
191 spline2.bezier_points[m].co = newSpline.bezier_points[m].co
192 spline2.bezier_points[m].handle_left_type = newSpline.bezier_points[m].handle_left_type
193 spline2.bezier_points[m].handle_left = newSpline.bezier_points[m].handle_left
194 spline2.bezier_points[m].handle_right_type = newSpline.bezier_points[m].handle_right_type
195 spline2.bezier_points[m].handle_right = newSpline.bezier_points[m].handle_right
197 bpy.ops.curve.select_all(action='DESELECT')
198 for point in newSpline.bezier_points:
199 point.select_control_point = True
200 bpy.ops.curve.delete(type='VERT')
202 spline2.bezier_points[0].select_control_point = True
204 def rearrange(dataCurve, select_spline, command):
205 len_splines = len(dataCurve.splines)
206 if command == 'NEXT':
207 if select_spline < len_splines - 1:
208 rearrangesplines(dataCurve, select_spline + 1, select_spline)
210 if command == 'PREV':
211 if select_spline > 0:
212 rearrangesplines(dataCurve, select_spline, select_spline - 1)
214 class RearrangeSpline(bpy.types.Operator):
215 bl_idname = "curvetools.rearrange_spline"
216 bl_label = "Rearrange Spline"
217 bl_description = "Rearrange Spline"
219 Types = [('NEXT', "Next", "next"),
220 ('PREV', "Prev", "prev")]
221 command : EnumProperty(
222 name="command",
223 description="Command (prev or next)",
224 items=Types
227 def execute(self, context):
228 bpy.ops.object.mode_set(mode = 'EDIT')
229 bpy.context.view_layer.update()
231 dataCurve = context.active_object.data
233 splines = context.active_object.data.splines
235 select_spline = 0
237 sn = 0
238 for spline in splines:
239 for bezier_points in spline.bezier_points:
240 if bezier_points.select_control_point:
241 select_spline = sn
242 sn += 1
244 sn = 0
245 for spline in splines:
246 for point in spline.points:
247 if point.select:
248 select_spline = sn
249 sn += 1
251 rearrange(dataCurve, select_spline, self.command)
253 return {'FINISHED'}
255 @classmethod
256 def poll(cls, context):
257 return (context.object is not None and
258 context.object.type == 'CURVE')
260 def register():
261 for cls in classes:
262 bpy.utils.register_class(operators)
264 def unregister():
265 for cls in classes:
266 bpy.utils.unregister_class(operators)
268 if __name__ == "__main__":
269 register()
271 operators = [ShowSplinesSequence, RearrangeSpline]