1 # SPDX-FileCopyrightText: 2019-2023 Blender Foundation
3 # SPDX-License-Identifier: GPL-2.0-or-later
10 from gpu_extras
.batch
import batch_for_shader
14 from mathutils
import Vector
16 from bpy
.props
import (
20 # ------------------------------------------------------------
23 def draw_number(n
, co
, font_height
):
28 [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))],
29 [Vector((0, 1, 0)), Vector((1, 2, 0)), Vector((1, 2, 0)), Vector((1, 0, 0))],
30 [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))],
31 [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))],
32 [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))],
33 [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))],
34 [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))],
35 [Vector((0, 2, 0)), Vector((1, 2, 0)), Vector((1, 2, 0)), Vector((0, 1, 0)), Vector((0, 1, 0)), Vector((0, 0, 0))],
36 [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))],
37 [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))],
40 for num
in numeral
[n
]:
41 point_list
.extend([num
* font_height
+ co
])
46 def draw(self
, context
, splines
, sequence_color
, font_thickness
, font_size
, matrix_world
):
48 splines_len
= len(splines
)
49 for n
in range(0, splines_len
):
51 res
= [int(x
) for x
in str(n
)]
56 if splines
[n
].type == 'BEZIER':
57 first_point_co
= matrix_world
@ splines
[n
].bezier_points
[0].co
59 first_point
= matrix_world
@ splines
[n
].points
[0].co
60 first_point_co
= Vector((first_point
.x
, first_point
.y
, first_point
.z
))
62 first_point_co
= Vector((i
, 0, 0)) + first_point_co
63 points
= draw_number(r
, first_point_co
, font_size
)
65 shader
= gpu
.shader
.from_builtin('UNIFORM_COLOR')
67 batch
= batch_for_shader(shader
, 'LINES', {"pos": points
})
70 gpu
.state
.line_width_set(font_thickness
)
71 shader
.uniform_float("color", sequence_color
)
73 i
+= font_size
+ font_size
* 0.5
75 class ShowSplinesSequence(bpy
.types
.Operator
):
76 bl_idname
= "curvetools.show_splines_sequence"
77 bl_label
= "Show Splines Sequence"
78 bl_description
= "Show Splines Sequence / [ESC] - remove"
82 def modal(self
, context
, event
):
83 context
.area
.tag_redraw()
85 if event
.type in {'ESC'}:
86 for handler
in self
.handlers
:
88 bpy
.types
.SpaceView3D
.draw_handler_remove(handler
, 'WINDOW')
91 for handler
in self
.handlers
:
92 self
.handlers
.remove(handler
)
95 return {'PASS_THROUGH'}
98 def invoke(self
, context
, event
):
100 if context
.area
.type == 'VIEW_3D':
102 # color change in the panel
103 sequence_color
= bpy
.context
.scene
.curvetools
.sequence_color
104 font_thickness
= bpy
.context
.scene
.curvetools
.font_thickness
105 font_size
= bpy
.context
.scene
.curvetools
.font_size
107 splines
= context
.active_object
.data
.splines
108 matrix_world
= context
.active_object
.matrix_world
110 # the arguments we pass the the callback
111 args
= (self
, context
, splines
, sequence_color
, font_thickness
, font_size
, matrix_world
)
113 # Add the region OpenGL drawing callback
114 # draw in view space with 'POST_VIEW' and 'PRE_VIEW'
115 self
.handlers
.append(bpy
.types
.SpaceView3D
.draw_handler_add(draw
, args
, 'WINDOW', 'POST_VIEW'))
117 context
.window_manager
.modal_handler_add(self
)
118 return {'RUNNING_MODAL'}
120 self
.report({'WARNING'},
121 "View3D not found, cannot run operator")
125 def poll(cls
, context
):
126 return (context
.object is not None and
127 context
.object.type == 'CURVE')
129 # ------------------------------------------------------------
132 def rearrangesplines(dataCurve
, select_spline1
, select_spline2
):
134 spline1
= dataCurve
.splines
[select_spline1
]
135 spline2
= dataCurve
.splines
[select_spline2
]
137 bpy
.ops
.curve
.select_all(action
='SELECT')
138 bpy
.ops
.curve
.spline_type_set(type='BEZIER')
139 bpy
.ops
.curve
.select_all(action
='DESELECT')
144 len_spline1
= len(spline1
.bezier_points
)
145 len_spline2
= len(spline2
.bezier_points
)
147 newSpline
= dataCurve
.splines
.new(type=type1
)
148 newSpline
.bezier_points
.add(len_spline1
- 1)
149 newSpline
.use_cyclic_u
= spline1
.use_cyclic_u
150 for n
in range(0, len_spline1
):
151 newSpline
.bezier_points
[n
].co
= spline1
.bezier_points
[n
].co
152 newSpline
.bezier_points
[n
].handle_left_type
= spline1
.bezier_points
[n
].handle_left_type
153 newSpline
.bezier_points
[n
].handle_left
= spline1
.bezier_points
[n
].handle_left
154 newSpline
.bezier_points
[n
].handle_right_type
= spline1
.bezier_points
[n
].handle_right_type
155 newSpline
.bezier_points
[n
].handle_right
= spline1
.bezier_points
[n
].handle_right
156 spline1
.bezier_points
[n
].select_control_point
= True
158 spline1
.bezier_points
[0].select_control_point
= False
159 spline1
.bezier_points
[0].select_left_handle
= False
160 spline1
.bezier_points
[0].select_right_handle
= False
161 bpy
.ops
.curve
.delete(type='VERT')
163 spline1
.bezier_points
[0].select_control_point
= True
164 bpy
.ops
.curve
.spline_type_set(type=type2
)
166 bpy
.ops
.curve
.select_all(action
='DESELECT')
168 spline1
.bezier_points
.add(len_spline2
- 1)
169 spline1
.use_cyclic_u
= spline2
.use_cyclic_u
170 for n
in range(0, len_spline2
):
171 spline1
.bezier_points
[n
].co
= spline2
.bezier_points
[n
].co
172 spline1
.bezier_points
[n
].handle_left_type
= spline2
.bezier_points
[n
].handle_left_type
173 spline1
.bezier_points
[n
].handle_left
= spline2
.bezier_points
[n
].handle_left
174 spline1
.bezier_points
[n
].handle_right_type
= spline2
.bezier_points
[n
].handle_right_type
175 spline1
.bezier_points
[n
].handle_right
= spline2
.bezier_points
[n
].handle_right
176 spline1
.bezier_points
[n
].select_control_point
= False
177 spline1
.bezier_points
[n
].select_left_handle
= False
178 spline1
.bezier_points
[n
].select_right_handle
= False
179 spline2
.bezier_points
[n
].select_control_point
= True
181 spline2
.bezier_points
[0].select_control_point
= False
182 spline2
.bezier_points
[0].select_left_handle
= False
183 spline2
.bezier_points
[0].select_right_handle
= False
184 bpy
.ops
.curve
.delete(type='VERT')
186 spline2
.bezier_points
[0].select_control_point
= True
187 bpy
.ops
.curve
.spline_type_set(type=type1
)
189 spline2
.bezier_points
.add(len_spline1
- 1)
190 spline2
.use_cyclic_u
= newSpline
.use_cyclic_u
191 for m
in range(0, len_spline1
):
192 spline2
.bezier_points
[m
].co
= newSpline
.bezier_points
[m
].co
193 spline2
.bezier_points
[m
].handle_left_type
= newSpline
.bezier_points
[m
].handle_left_type
194 spline2
.bezier_points
[m
].handle_left
= newSpline
.bezier_points
[m
].handle_left
195 spline2
.bezier_points
[m
].handle_right_type
= newSpline
.bezier_points
[m
].handle_right_type
196 spline2
.bezier_points
[m
].handle_right
= newSpline
.bezier_points
[m
].handle_right
198 bpy
.ops
.curve
.select_all(action
='DESELECT')
199 for point
in newSpline
.bezier_points
:
200 point
.select_control_point
= True
201 bpy
.ops
.curve
.delete(type='VERT')
203 spline2
.bezier_points
[0].select_control_point
= True
205 def rearrange(dataCurve
, select_spline
, command
):
206 len_splines
= len(dataCurve
.splines
)
207 if command
== 'NEXT':
208 if select_spline
< len_splines
- 1:
209 rearrangesplines(dataCurve
, select_spline
+ 1, select_spline
)
211 if command
== 'PREV':
212 if select_spline
> 0:
213 rearrangesplines(dataCurve
, select_spline
, select_spline
- 1)
215 class RearrangeSpline(bpy
.types
.Operator
):
216 bl_idname
= "curvetools.rearrange_spline"
217 bl_label
= "Rearrange Spline"
218 bl_description
= "Rearrange Spline"
219 bl_options
= {'UNDO'}
221 Types
= [('NEXT', "Next", "next"),
222 ('PREV', "Prev", "prev")]
223 command
: EnumProperty(
225 description
="Command (prev or next)",
229 def execute(self
, context
):
230 bpy
.ops
.object.mode_set(mode
= 'EDIT')
231 bpy
.context
.view_layer
.update()
233 dataCurve
= context
.active_object
.data
235 splines
= context
.active_object
.data
.splines
240 for spline
in splines
:
241 for bezier_points
in spline
.bezier_points
:
242 if bezier_points
.select_control_point
:
247 for spline
in splines
:
248 for point
in spline
.points
:
253 rearrange(dataCurve
, select_spline
, self
.command
)
258 def poll(cls
, context
):
259 return (context
.object is not None and
260 context
.object.type == 'CURVE')
264 bpy
.utils
.register_class(operators
)
268 bpy
.utils
.unregister_class(operators
)
270 if __name__
== "__main__":
273 operators
= [ShowSplinesSequence
, RearrangeSpline
]