bl_info cleanup
[blender-addons-contrib.git] / btrace / bTrace.py
1 #BEGIN GPL LICENSE BLOCK
2
3 #This program is free software; you can redistribute it and/or
4 #modify it under the terms of the GNU General Public License
5 #as published by the Free Software Foundation; either version 2
6 #of the License, or (at your option) any later version.
7
8 #This program is distributed in the hope that it will be useful,
9 #but WITHOUT ANY WARRANTY; without even the implied warranty of
10 #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.    See the
11 #GNU General Public License for more details.
12
13 #You should have received a copy of the GNU General Public License
14 #along with this program; if not, write to the Free Software Foundation,
15 #Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
16
17 #END GPL LICENCE BLOCK
18
19 bl_info = {
20     "name": "Btrace",
21     "author": "liero, crazycourier, Atom, Meta-Androcto, MacKracken",
22     "version": (1, 1, ),
23     "blender": (2, 6, 2),
24     "location": "View3D > Tools",
25     "description": "Tools for converting/animating objects/particles into curves",
26     "warning": "Still under development, bug reports appreciated",
27     "wiki_url": "",
28     "tracker_url": "http://projects.blender.org/tracker/?func=detail&atid=468&aid=29563&group_id=153",
29     "category": "Add Curve"
30     }
31
32 #### TO DO LIST ####
33 ### [   ]  Add more options to curve radius/modulation plus cyclic/connect curve option
34
35 import bpy
36 import selection_utils
37 from bpy.props import FloatProperty, EnumProperty, IntProperty, BoolProperty, FloatVectorProperty
38
39
40 def deselect_others(ob, context):
41     """For tool menu select, deselects others if one selected"""
42     selected = addTracerObjectPanel.selected
43     ob[selected] = False
44     keys = [key for key in ob.keys() if ob[key]]  # all the True keys
45     if len(keys) <= 0:
46         ob[selected] = True  # reselect
47         return None
48     for key in keys:
49         addTracerObjectPanel.selected = key
50         ob[key] = True
51
52
53 # Class for properties panel
54 class TracerPropertiesMenu(bpy.types.PropertyGroup):
55     """Toolbar show/hide booleans for tool options"""
56     tool_objectTrace = BoolProperty(name="Object Trace", default=False, description="Trace selected mesh object with a curve", update=deselect_others)
57     tool_objectsConnect = BoolProperty(name="Objects Connect", default=False, description="Connect objects with a curve controlled by hooks", update=deselect_others)
58     tool_particleTrace = BoolProperty(name="Particle Trace", default=False, description="Trace particle path with a  curve", update=deselect_others)
59     tool_meshFollow = BoolProperty(name="Mesh Follow", default=False, description="Follow selection items on animated mesh object", update=deselect_others)
60     tool_particleConnect = BoolProperty(name="Particle Connect", default=False, description="Connect particles with a curves and animated over particle lifetime", update=deselect_others)
61     tool_growCurve = BoolProperty(name="Grow Curve", default=False, description="Animate curve bevel over time by keyframing points radius", update=deselect_others)
62     tool_handwrite = BoolProperty(name="Handwriting", default=False, description="Create and Animate curve using the grease pencil", update=deselect_others)
63     tool_fcurve = BoolProperty(name="F-Curve Noise", default=False, description="Add F-Curve noise to selected objects", update=deselect_others)
64     tool_colorblender = BoolProperty(name="Color Blender", default=False, description="Add F-Curve noise to selected objects", update=deselect_others)
65
66
67 # Class to define properties
68 class TracerProperties(bpy.types.PropertyGroup):
69     """Options for tools"""
70     curve_spline = EnumProperty(name="Spline", items=(("POLY", "Poly", "Use Poly spline type"),  ("NURBS", "Nurbs", "Use Nurbs spline type"), ("BEZIER", "Bezier", "Use Bezier spline type")), description="Choose which type of spline to use when curve is created", default="BEZIER")
71     curve_handle = EnumProperty(name="Handle", items=(("ALIGNED", "Aligned", "Use Aligned Handle Type"), ("AUTOMATIC", "Automatic", "Use Auto Handle Type"), ("FREE_ALIGN", "Free Align", "Use Free Handle Type"), ("VECTOR", "Vector", "Use Vector Handle Type")), description="Choose which type of handle to use when curve is created",  default="VECTOR")
72     curve_resolution = IntProperty(name="Bevel Resolution", min=1, max=32, default=4, description="Adjust the Bevel resolution")
73     curve_depth = FloatProperty(name="Bevel Depth", min=0.0, max=100.0, default=0.1, description="Adjust the Bevel depth")
74     curve_u = IntProperty(name="Resolution U", min=0, max=64, default=12, description="Adjust the Surface resolution")
75     curve_join = BoolProperty(name="Join Curves", default=False, description="Join all the curves after they have been created")
76     curve_smooth = BoolProperty(name="Smooth", default=True, description="Render curve smooth")
77     # Option to Duplicate Mesh
78     object_duplicate = BoolProperty(name="Apply to Copy", default=False, description="Apply curve to a copy of object")
79     # Distort Mesh options
80     distort_modscale = IntProperty(name="Modulation Scale", min=0, max=50, default=2, description="Add a scale to modulate the curve at random points, set to 0 to disable")
81     distort_noise = FloatProperty(name="Mesh Noise", min=0.0, max=50.0, default=0.00, description="Adjust noise added to mesh before adding curve")
82     # Particle Options
83     particle_step = IntProperty(name="Step Size", min=1, max=50, default=5, description="Sample one every this number of frames")
84     particle_auto = BoolProperty(name='Auto Frame Range', default=True, description='Calculate Frame Range from particles life')
85     particle_f_start = IntProperty(name='Start Frame', min=1, max=5000, default=1, description='Start frame')
86     particle_f_end = IntProperty(name='End Frame', min=1, max=5000, default=250, description='End frame')
87     # F-Curve Modifier Properties
88     fcnoise_rot = BoolProperty(name="Rotation", default=False, description="Affect Rotation")
89     fcnoise_loc = BoolProperty(name="Location", default=True, description="Affect Location")
90     fcnoise_scale = BoolProperty(name="Scale", default=False, description="Affect Scale")
91     fcnoise_amp = IntProperty(name="Amp", min=1, max=500, default=5, description="Adjust the amplitude")
92     fcnoise_timescale = FloatProperty(name="Time Scale", min=1, max=500, default=50, description="Adjust the time scale")
93     fcnoise_key = BoolProperty(name="Add Keyframe", default=True, description="Keyframe is needed for tool, this adds a LocRotScale keyframe")
94     show_curve_settings = BoolProperty(name="Curve Settings", default=False, description="Change the curve settings for the created curve")
95     material_settings = BoolProperty(name="Material Settings", default=False, description="Change the material settings for the created curve")
96     particle_settings = BoolProperty(name="Particle Settings", default=False, description="Show the settings for the created curve")
97     animation_settings = BoolProperty(name="Animation Settings", default=False, description="Show the settings for the Animations")
98     distort_curve = BoolProperty(name="Add Distortion", default=False, description="Set options to distort the final curve")
99     connect_noise = BoolProperty(name="F-Curve Noise", default=False, description="Adds F-Curve Noise Modifier to selected objects")
100     settings_objectTrace = BoolProperty(name="Object Trace Settings", default=False, description="Trace selected mesh object with a curve")
101     settings_objectsConnect = BoolProperty(name="Objects Connect Settings", default=False, description="Connect objects with a curve controlled by hooks")
102     settings_objectTrace = BoolProperty(name="Object Trace Settings", default=False, description="Trace selected mesh object with a curve")
103     respect_order = BoolProperty(name="Order", default=False, description="Remember order objects were selected")
104     settings_particleTrace = BoolProperty(name="Particle Trace Settings", default=False, description="Trace particle path with a  curve")
105     settings_particleConnect = BoolProperty(name="Particle Connect Settings", default=False, description="Connect particles with a curves and animated over particle lifetime")
106     settings_growCurve = BoolProperty(name="Grow Curve Settings", default=False, description="Animate curve bevel over time by keyframing points radius")
107     settings_fcurve = BoolProperty(name="F-Curve Settings", default=False, description="F-Curve Settings")
108     settings_toggle = BoolProperty(name="Settings", default=False, description="Toggle Settings")
109     # Animation Options
110     anim_auto = BoolProperty(name='Auto Frame Range', default=True, description='Automatically calculate Frame Range')
111     anim_f_start = IntProperty(name='Start', min=1, max=2500, default=1, description='Start frame / Hidden object')
112     anim_length = IntProperty(name='Duration', min=1, soft_max=1000, max=2500, default=100, description='Animation Length')
113     anim_f_fade = IntProperty(name='Fade After', min=0, soft_max=250, max=2500, default=10, description='Fade after this frames / Zero means no fade')
114     anim_delay = IntProperty(name='Grow', min=0, max=50, default=5, description='Frames it takes a point to grow')
115     anim_tails = BoolProperty(name='Tails on endpoints', default=True, description='Set radius to zero for open splines endpoints')
116     anim_keepr = BoolProperty(name='Keep Radius', default=True, description='Try to keep radius data from original curve')
117     animate = BoolProperty(name="Animate Result", default=False, description='Animate the final curve objects')
118     # Convert to Curve options
119     convert_conti = BoolProperty(name='Continuous', default=True, description='Create a continuous curve using verts from mesh')
120     convert_everyedge = BoolProperty(name='Every Edge', default=False, description='Create a curve from all verts in a mesh')
121     convert_edgetype = EnumProperty(name="Edge Type for Curves",
122         items=(("CONTI", "Continuous", "Create a continuous curve using verts from mesh"),  ("EDGEALL", "All Edges", "Create a curve from every edge in a mesh")),
123         description="Choose which type of spline to use when curve is created", default="CONTI")
124     convert_joinbefore = BoolProperty(name="Join objects before convert", default=False, description='Join all selected mesh to one object before converting to mesh')
125     # Mesh Follow Options
126     fol_edge_select = BoolProperty(name='Edge', default=False, description='Grow from edges')
127     fol_vert_select = BoolProperty(name='Vertex', default=False, description='Grow from verts')
128     fol_face_select = BoolProperty(name='Face', default=True, description='Grow from faces')
129     fol_mesh_type = EnumProperty(name='Mesh type', default='VERTS', description='Mesh feature to draw cruves from', items=(
130         ("VERTS", "Verts", "Draw from Verts"), ("EDGES", "Edges", "Draw from Edges"), ("FACES", "Faces", "Draw from Faces"), ("OBJECT", "Object", "Draw from Object origin")))
131     fol_start_frame = IntProperty(name="Start Frame", min=1, max=2500, default=1, description="Start frame for range to trace")
132     fol_end_frame = IntProperty(name="End Frame", min=1, max=2500, default=250, description="End frame for range to trace")
133     fol_perc_verts = FloatProperty(name="Reduce selection by", min=0.001, max=1.000, default=0.5, description="percentage of total verts to trace")
134     fol_sel_option = EnumProperty(name="Selection type", description="Choose which objects to follow", default="RANDOM", items=(
135         ("RANDOM", "Random", "Follow Random items"),  ("CUSTOM", "Custom Select", "Follow selected items"), ("ALL", "All", "Follow all items")))
136     trace_mat_color = FloatVectorProperty(name="Material Color", description="Choose material color", min=0, max=1, default=(0.0,0.3,0.6), subtype="COLOR")
137     trace_mat_random = BoolProperty(name="Random Color", default=False, description='Make the material colors random')
138
139     # Material custom Properties properties
140     mat_simple_adv_toggle = EnumProperty(name="Material Options", items=(("SIMPLE", "Simple", "Show Simple Material Options"), ("ADVANCED", "Advanced", "Show Advanced Material Options")), description="Choose which Material Options to show", default="SIMPLE")
141     mat_run_color_blender = BoolProperty(name="Run Color Blender", default=False, description="Generate colors from a color scheme")
142     mmColors = bpy.props.EnumProperty(
143         items=(("RANDOM", "Random", "Use random colors"),
144                 ("CUSTOM", "Custom", "Use custom colors"),
145                 ("BW", "Black/White", "Use Black and White"),
146                 ("BRIGHT", "Bright Colors", "Use Bright colors"),
147                 ("EARTH", "Earth", "Use Earth colors"),
148                 ("GREENBLUE", "Green to Blue", "Use Green to Blue colors")),
149         description="Choose which type of colors the materials uses",
150         default="BRIGHT",
151         name="Define a color palette")
152     # Custom property for how many keyframes to skip
153     mmSkip = bpy.props.IntProperty(name="frames", min=1, max=500, default=20, description="Number of frames between each keyframes")
154     # Custom property to enable/disable random order for the 
155     mmBoolRandom = bpy.props.BoolProperty(name="Random Order", default=False, description="Randomize the order of the colors")
156     # Custom Color properties
157     mmColor1 = bpy.props.FloatVectorProperty(min=0, max=1, default=(0.8, 0.8, 0.8), description="Custom Color 1", subtype="COLOR")
158     mmColor2 = bpy.props.FloatVectorProperty(min=0, max=1, default=(0.8, 0.8, 0.3), description="Custom Color 2", subtype="COLOR")
159     mmColor3 = bpy.props.FloatVectorProperty(min=0, max=1, default=(0.8, 0.5, 0.6), description="Custom Color 3", subtype="COLOR")
160     mmColor4 = bpy.props.FloatVectorProperty(min=0, max=1, default=(0.2, 0.8, 0.289), description="Custom Color 4", subtype="COLOR")
161     mmColor5 = bpy.props.FloatVectorProperty(min=0, max=1, default=(1.0, 0.348, 0.8), description="Custom Color 5", subtype="COLOR")
162     mmColor6 = bpy.props.FloatVectorProperty(min=0, max=1, default=(0.4, 0.67, 0.8), description="Custom Color 6", subtype="COLOR")
163     mmColor7 = bpy.props.FloatVectorProperty(min=0, max=1, default=(0.66, 0.88, 0.8), description="Custom Color 7", subtype="COLOR")
164     mmColor8 = bpy.props.FloatVectorProperty(min=0, max=1, default=(0.8, 0.38, 0.22), description="Custom Color 8", subtype="COLOR")
165     # BW Color properties
166     bwColor1 = bpy.props.FloatVectorProperty(min=0, max=1, default=(0.0,0.0,0.0), description="Black/White Color 1", subtype="COLOR")
167     bwColor2 = bpy.props.FloatVectorProperty(min=0, max=1, default=(1.0,1.0,1.0), description="Black/White Color 2", subtype="COLOR")
168     # Bright Color properties
169     brightColor1 = bpy.props.FloatVectorProperty(min=0, max=1, default=(1.0, 0.0, 0.75), description="Bright Color 1", subtype="COLOR")
170     brightColor2 = bpy.props.FloatVectorProperty(min=0, max=1, default=(0.0,1.0,1.0), description="Bright Color 2", subtype="COLOR")
171     brightColor3 = bpy.props.FloatVectorProperty(min=0, max=1, default=(0.0,1.0,0.0), description="Bright Color 3", subtype="COLOR")
172     brightColor4 = bpy.props.FloatVectorProperty(min=0, max=1, default=(1.0,1.0,0.0), description="Bright Color 4", subtype="COLOR")
173     # Earth Color Properties
174     earthColor1 = bpy.props.FloatVectorProperty(min=0, max=1, default=(0.068, 0.019, 0.014), description="Earth Color 1", subtype="COLOR")
175     earthColor2 = bpy.props.FloatVectorProperty(min=0, max=1, default=(0.089, 0.060, 0.047), description="Earth Color 2", subtype="COLOR")
176     earthColor3 = bpy.props.FloatVectorProperty(min=0, max=1, default=(0.188, 0.168, 0.066), description="Earth Color 3", subtype="COLOR")
177     earthColor4 = bpy.props.FloatVectorProperty(min=0, max=1, default=(0.445, 0.296, 0.065), description="Earth Color 4", subtype="COLOR")
178     earthColor5 = bpy.props.FloatVectorProperty(min=0, max=1, default=(0.745, 0.332, 0.065), description="Earth Color 5", subtype="COLOR")
179     # Green to Blue Color properties
180     greenblueColor1 = bpy.props.FloatVectorProperty(min=0, max=1, default=(0.296, 0.445, 0.074), description="Green/Blue Color 1", subtype="COLOR")
181     greenblueColor2 = bpy.props.FloatVectorProperty(min=0, max=1, default=(0.651, 1.0, 0.223), description="Green/Blue Color 2", subtype="COLOR")
182     greenblueColor3 = bpy.props.FloatVectorProperty(min=0, max=1, default=(0.037, 0.047, 0.084), description="Green/Blue Color 3", subtype="COLOR")
183
184
185 ############################
186 ## Draw Brush panel in Toolbar
187 ############################
188 class addTracerObjectPanel(bpy.types.Panel):
189     bl_label = "Btrace: Panel"
190     bl_space_type = 'VIEW_3D'
191     bl_region_type = 'TOOLS'
192     bl_context = 'objectmode'
193     selected = "tool_objectTrace"
194     bl_options = {'DEFAULT_CLOSED'}
195
196     def draw(self, context):
197         layout = self.layout
198         Btrace = bpy.context.window_manager.curve_tracer
199         btracemenu = props = bpy.context.window_manager.btrace_menu
200         obj = bpy.context.object
201
202
203         ############################
204         ## Color Blender Panel options
205         ############################
206         def color_blender():
207             """Buttons for Color Blender"""
208             row = box.row()
209             row.label("Color palette")
210             row.prop(Btrace, 'mmColors', text="")
211             # Show Custom Colors if selected
212             if Btrace.mmColors == 'CUSTOM':
213                 row = box.row(align=True)
214                 row.prop(Btrace, 'mmColor1', text="")
215                 row.prop(Btrace, 'mmColor2', text="")
216                 row.prop(Btrace, 'mmColor3', text="")
217                 row.prop(Btrace, 'mmColor4', text="")
218                 row.prop(Btrace, 'mmColor5', text="")
219                 row.prop(Btrace, 'mmColor6', text="")
220                 row.prop(Btrace, 'mmColor7', text="")
221                 row.prop(Btrace, 'mmColor8', text="")
222             # Show Earth Colors
223             elif Btrace.mmColors == 'BW':
224                 row = box.row(align=True)
225                 row.prop(Btrace, 'bwColor1', text="")
226                 row.prop(Btrace, 'bwColor2', text="")
227             # Show Earth Colors
228             elif Btrace.mmColors == 'BRIGHT':
229                 row = box.row(align=True)
230                 row.prop(Btrace, 'brightColor1', text="")
231                 row.prop(Btrace, 'brightColor2', text="")
232                 row.prop(Btrace, 'brightColor3', text="")
233                 row.prop(Btrace, 'brightColor4', text="")
234             # Show Earth Colors
235             elif Btrace.mmColors == 'EARTH':
236                 row = box.row(align=True)
237                 row.prop(Btrace, 'earthColor1', text="")
238                 row.prop(Btrace, 'earthColor2', text="")
239                 row.prop(Btrace, 'earthColor3', text="")
240                 row.prop(Btrace, 'earthColor4', text="")
241                 row.prop(Btrace, 'earthColor5', text="")
242             # Show Earth Colors
243             elif Btrace.mmColors == 'GREENBLUE':
244                 row = box.row(align=True)
245                 row.prop(Btrace, 'greenblueColor1', text="")
246                 row.prop(Btrace, 'greenblueColor2', text="")
247                 row.prop(Btrace, 'greenblueColor3', text="")
248             elif Btrace.mmColors == 'RANDOM':
249                 row = box.row()
250
251         ############################
252         ## Curve Panel options
253         ############################
254         def curve_settings():
255             """Button for curve options"""
256             row = self.layout.row()
257             row = box.row(align=True)
258
259             row.prop(Btrace, 'show_curve_settings', icon='CURVE_BEZCURVE', text="Curve Settings")
260             row.prop(Btrace, 'material_settings', icon='MATERIAL_DATA', text="Material Settings")
261             if Btrace.material_settings:
262                 row = box.row()
263                 row.label(text="Material Settings", icon='COLOR')
264                 row = box.row()
265                 row.prop(Btrace, "trace_mat_random")
266                 if not Btrace.trace_mat_random:
267                     row = box.row()
268                     row.prop(Btrace, "trace_mat_color", text="")
269                 else:
270                     row.prop(Btrace, "mat_run_color_blender")
271                     if Btrace.mat_run_color_blender:
272                         row = box.row()
273                         row.operator("object.colorblenderclear", text="Reset Material Keyframes", icon="KEY_DEHLT")
274                         row.prop(Btrace, 'mmSkip', text="Keyframe every")
275                       
276                     color_blender()
277                 row = box.row()
278             if Btrace.show_curve_settings:
279                 #if  or btracemenu.tool_handwrite:
280                 if len(bpy.context.selected_objects) > 0 and obj.type == 'CURVE': # selected curve options
281                     col = box.column(align=True)
282                     col.label(text="Edit Curves for", icon='CURVE_BEZCURVE')
283                     col.label(text="Selected Curve Bevel Options")
284                     row = col.row(align=True)
285                     row.prop(obj.data, 'bevel_depth', text="Depth")
286                     row.prop(obj.data, 'bevel_resolution', text="Resolution")
287                     row = col.row(align=True)
288                     row.prop(obj.data, 'resolution_u')
289                 else: # For new curve
290                     box.label(text="New Curve Settings", icon='CURVE_BEZCURVE')
291                     box.prop(Btrace, "curve_spline")
292                     box.prop(Btrace, "curve_handle")
293                     box.label(text="Bevel Options")
294                     col = box.column(align=True)
295                     row = col.row(align=True)
296                     row.prop(Btrace, "curve_depth", text="Depth")
297                     row.prop(Btrace, "curve_resolution", text="Resolution")
298                     row = col.row(align=True)
299                     row.prop(Btrace, "curve_u")
300
301         ############################
302         ## Grow Animation Panel options
303         ############################
304         def add_grow():
305             """Button for grow animation option"""
306             row = box.row()
307             row.label(text="Animate Final Curve")
308             row = box.row()
309             row.prop(Btrace, "animate", text="Add Grow Curve Animation", icon="META_BALL")
310             row.label("")
311             if Btrace.animate:
312                 box.label(text='Frame Animation Settings:', icon="META_BALL")
313                 col = box.column(align=True)
314                 col.prop(Btrace, 'anim_auto')
315                 if not Btrace.anim_auto:
316                     row = col.row(align=True)
317                     row.prop(Btrace, 'anim_f_start')
318                     row.prop(Btrace, 'anim_length')
319                 row = col.row(align=True)
320                 row.prop(Btrace, 'anim_delay')
321                 row.prop(Btrace, 'anim_f_fade')
322
323                 box.label(text='Additional Settings')
324                 row = box.row()
325                 row.prop(Btrace, 'anim_tails')
326                 row.prop(Btrace, 'anim_keepr')
327
328         ##################################################################
329         ## Start Btrace Panel
330         ##################################################################
331         col = self.layout.column(align=True)
332         #col.label(text="Trace Tools")
333         row = col.row()
334         row.prop(btracemenu, "tool_objectTrace", text="Ojbect Trace", icon="FORCE_MAGNETIC")
335         row.prop(btracemenu, "tool_objectsConnect", text="Object Connect", icon="OUTLINER_OB_EMPTY")
336         row = col.row()
337         row.prop(btracemenu, "tool_meshFollow", text="Mesh Follow", icon="DRIVER")
338         row.prop(btracemenu, "tool_handwrite", text="Handwriting", icon='BRUSH_DATA')
339         row = col.row()   
340         row.prop(btracemenu, "tool_particleTrace", icon="PARTICLES", text="Particle Trace")
341         row.prop(btracemenu, "tool_particleConnect", icon="MOD_PARTICLES", text="Particle Connect")
342         row = layout.row()
343         col = layout.column(align=True)
344         row = col.row()
345         row.prop(btracemenu, "tool_growCurve", icon="META_BALL", text="Grow Animation")
346         row.prop(btracemenu, "tool_fcurve", text="Fcurve Noise", icon='RNDCURVE')
347         row = col.row()
348         row.prop(btracemenu, "tool_colorblender", text="Color Blender", icon="COLOR")
349         row.label(text="")
350         row = layout.row()
351
352         ##########################
353         ## Start  Object Tools
354         ##########################
355         sel = bpy.context.selected_objects
356         ############################
357         ### Object Trace
358         ############################
359         if btracemenu.tool_objectTrace:
360             row = layout.row()
361             row.label(text="  Trace Tool:", icon="FORCE_CURVE")
362             box = self.layout.box()
363             row = box.row()
364             row.label(text="Object Trace", icon="FORCE_MAGNETIC")
365             row.operator("object.btobjecttrace", text="Run!", icon="PLAY")
366             row = box.row()
367             row.prop(Btrace, "settings_toggle", icon='MODIFIER', text='Settings')
368             myselected = "Selected %d" % len(bpy.context.selected_objects)
369             row.label(text=myselected)
370             if Btrace.settings_toggle:
371                 row = box.row()
372                 row.label(text='Edge Draw Method')
373                 row = box.row(align=True)
374                 row.prop(Btrace, 'convert_edgetype')
375                 box.prop(Btrace, "object_duplicate")
376                 if len(sel) > 1:
377                     box.prop(Btrace, 'convert_joinbefore')
378                 else:
379                     Btrace.convert_joinbefore = False
380                 row = box.row()
381                 row.prop(Btrace, "distort_curve")
382                 if Btrace.distort_curve:
383                     col = box.column(align=True)
384                     col.prop(Btrace, "distort_modscale")
385                     col.prop(Btrace, "distort_noise")
386                 row = box.row()
387                 curve_settings()  # Show Curve/material settings
388                 add_grow()  # Grow settings here
389
390         ############################
391         ### Objects Connect
392         ############################
393         if btracemenu.tool_objectsConnect:
394             row = layout.row()
395             row.label(text="  Trace Tool:", icon="FORCE_CURVE")
396             box = self.layout.box()
397             row = box.row()
398             row.label(text="Objects Connect", icon="OUTLINER_OB_EMPTY")
399             row.operator("object.btobjectsconnect", text="Run!", icon="PLAY")
400             row = box.row()
401             row.prop(Btrace, "settings_toggle", icon='MODIFIER', text='Settings')
402             row.label(text="")
403             if Btrace.settings_toggle:
404                 row = box.row()
405                 row.prop(Btrace, "respect_order", text="Selection Options")
406                 if Btrace.respect_order:
407                     box.operator("object.select_order", text="Click to start order selection", icon='UV_SYNC_SELECT')
408                 row = box.row()
409                 row.prop(Btrace, "connect_noise", text="Add F-Curve Noise")
410                 if Btrace.connect_noise:
411                     row = box.row()
412                     row.label(text="F-Curve Noise", icon='RNDCURVE')
413                     row = box.row(align=True)
414                     row.prop(Btrace, "fcnoise_rot")
415                     row.prop(Btrace, "fcnoise_loc")
416                     row.prop(Btrace, "fcnoise_scale")
417                     col = box.column(align=True)
418                     col.prop(Btrace, "fcnoise_amp")
419                     col.prop(Btrace, "fcnoise_timescale")
420                     box.prop(Btrace, "fcnoise_key")
421                 curve_settings()  # Show Curve/material settings
422                 add_grow()  # Grow settings here
423
424         ############################
425         ### Mesh Follow
426         ############################
427         if btracemenu.tool_meshFollow:
428             row = layout.row()
429             row.label(text="  Trace Tool:", icon="FORCE_CURVE")
430             box = self.layout.box()
431             row = box.row()
432             row.label(text="Mesh Follow", icon="DRIVER")
433             row.operator("object.btmeshfollow", text="Run!", icon="PLAY")
434             row = box.row()
435             if Btrace.fol_mesh_type == 'OBJECT':
436                 a, b = "Trace Object", "SNAP_VOLUME"
437             if Btrace.fol_mesh_type == 'VERTS':
438                 a, b = "Trace Verts", "SNAP_VERTEX"
439             if Btrace.fol_mesh_type == 'EDGES':
440                 a, b = "Trace Edges", "SNAP_EDGE"
441             if Btrace.fol_mesh_type == 'FACES':
442                a, b = "Trace Faces", "SNAP_FACE"
443             row.prop(Btrace, "settings_toggle", icon='MODIFIER', text='Settings')
444             row.label(text=a, icon=b)
445             if Btrace.settings_toggle:
446                 col = box.column(align=True)
447                 row = col.row(align=True)
448                 row.prop(Btrace, "fol_mesh_type", expand=True)
449                 row = col.row(align=True)
450                 if Btrace.fol_mesh_type != 'OBJECT':
451                     row.prop(Btrace, "fol_sel_option", expand=True)
452                     row = box.row()
453                     if Btrace.fol_sel_option == 'RANDOM':
454                         row.label("Random Select of Total")
455                         row.prop(Btrace, "fol_perc_verts", text="%")
456                     if Btrace.fol_sel_option == 'CUSTOM':
457                         row.label("Choose selection in Edit Mode")
458                     if Btrace.fol_sel_option == 'ALL':
459                         row.label("Select All items")
460                 col = box.column(align=True)
461                 col.label("Time Options", icon="TIME")
462                 col.prop(Btrace, "particle_step")
463                 row = col.row(align=True)
464                 row.prop(Btrace, "fol_start_frame")
465                 row.prop(Btrace, "fol_end_frame")
466                 curve_settings()  # Show Curve/material settings
467                 add_grow()  # Grow settings here
468
469          ############################
470         ### Handwriting Tools
471         ############################
472         if btracemenu.tool_handwrite:
473             row = layout.row()
474             row.label(text="  Trace Tool:", icon="FORCE_CURVE")
475             box = self.layout.box()
476             row = box.row()
477             row.label(text='Handwriting', icon='BRUSH_DATA')
478             row.operator("curve.btwriting", text="Run!", icon='PLAY')
479             row = box.row()
480             row = box.row()
481             row.label(text='Grease Pencil Writing Tools')
482             col = box.column(align=True)
483             row = col.row(align=True)
484             row.operator("gpencil.draw", text="Draw", icon='BRUSH_DATA').mode = 'DRAW'
485             row.operator("gpencil.draw", text="Poly", icon='VPAINT_HLT').mode = 'DRAW_POLY'
486             row = col.row(align=True)
487             row.operator("gpencil.draw", text="Line", icon='ZOOMOUT').mode = 'DRAW_STRAIGHT'
488             row.operator("gpencil.draw", text="Erase", icon='TPAINT_HLT').mode = 'ERASER'
489             row = box.row()
490             row.operator("gpencil.data_unlink", text="Delete Grease Pencil Layer", icon="CANCEL")
491             row = box.row()
492             curve_settings()  # Show Curve/material settings
493             add_grow()  # Grow settings here
494
495         ############################
496         ### Particle Trace
497         ############################
498         if btracemenu.tool_particleTrace:
499             row = layout.row()
500             row.label(text="  Trace Tool:", icon="FORCE_CURVE")
501             box = self.layout.box()
502             row = box.row()
503             row.label(text="Particle Trace", icon="PARTICLES")
504             row.operator("particles.particletrace", text="Run!", icon="PLAY")
505             row = box.row()
506             row.prop(Btrace, "settings_toggle", icon='MODIFIER', text='Settings')
507             row.label(text="")
508             if Btrace.settings_toggle:
509                 box.prop(Btrace, "particle_step")
510                 row = box.row()
511                 row.prop(Btrace, "curve_join")
512                 curve_settings()  # Show Curve/material settings
513                 add_grow()  # Grow settings here
514
515         ############################
516         ### Connect Particles
517         ############################
518         if btracemenu.tool_particleConnect:
519             row = layout.row()
520             row.label(text="  Trace Tool:", icon="FORCE_CURVE")
521             box = self.layout.box()
522             row = box.row()
523             row.label(text='Particle Connect', icon='MOD_PARTICLES')
524             row.operator("particles.connect", icon="PLAY", text='Run!')
525             row = box.row()
526             row.prop(Btrace, "settings_toggle", icon='MODIFIER', text='Settings')
527             row.label(text="")
528             if Btrace.settings_toggle:
529                 box.prop(Btrace, "particle_step")
530                 row = box.row()
531                 row.prop(Btrace, 'particle_auto')
532                 if not Btrace.particle_auto:
533                     row = box.row(align=True)
534                     row.prop(Btrace, 'particle_f_start')
535                     row.prop(Btrace, 'particle_f_end')
536                 curve_settings()  # Show Curve/material settings
537                 add_grow()  # Grow settings here
538
539         #######################
540         #### Grow Animation ####
541         #######################
542         if btracemenu.tool_growCurve:
543             row = layout.row()
544             row.label(text="  Curve Tool:", icon="OUTLINER_OB_CURVE")
545             box = self.layout.box()
546             row = box.row()
547             row.label(text="Grow Curve", icon="META_BALL")
548             row.operator('curve.btgrow', text='Run!', icon='PLAY')
549             row = box.row()
550             row.prop(Btrace, "settings_toggle", icon='MODIFIER', text='Settings')
551             row.operator('object.btreset',  icon='KEY_DEHLT')
552             if Btrace.settings_toggle:
553                 box.label(text='Frame Animation Settings:')
554                 col = box.column(align=True)
555                 col.prop(Btrace, 'anim_auto')
556                 if not Btrace.anim_auto:
557                     row = col.row(align=True)
558                     row.prop(Btrace, 'anim_f_start')
559                     row.prop(Btrace, 'anim_length')
560                 row = col.row(align=True)
561                 row.prop(Btrace, 'anim_delay')
562                 row.prop(Btrace, 'anim_f_fade')
563
564                 box.label(text='Additional Settings')
565                 row = box.row()
566                 row.prop(Btrace, 'anim_tails')
567                 row.prop(Btrace, 'anim_keepr')
568
569         #######################
570         #### F-Curve Noise Curve ####
571         #######################
572         if btracemenu.tool_fcurve:
573             row = layout.row()
574             row.label(text="  Curve Tool:", icon="OUTLINER_OB_CURVE")
575             box = self.layout.box()
576             row = box.row()
577             row.label(text="F-Curve Noise", icon='RNDCURVE')
578             row.operator("object.btfcnoise", icon='PLAY', text="Run!")
579             row = box.row()
580             row.prop(Btrace, "settings_toggle", icon='MODIFIER', text='Settings')
581             row.operator('object.btreset',  icon='KEY_DEHLT')
582             if Btrace.settings_toggle:
583                 row = box.row(align=True)
584                 row.prop(Btrace, "fcnoise_rot")
585                 row.prop(Btrace, "fcnoise_loc")
586                 row.prop(Btrace, "fcnoise_scale")
587                 col = box.column(align=True)
588                 col.prop(Btrace, "fcnoise_amp")
589                 col.prop(Btrace, "fcnoise_timescale")
590                 box.prop(Btrace, "fcnoise_key")
591
592         #######################
593         #### Color Blender ####
594         #######################
595         if btracemenu.tool_colorblender:
596             row = layout.row()
597             row.label(text="  Curve/Object Tool:", icon="OUTLINER_OB_CURVE")
598             box = self.layout.box()
599             row = box.row()
600             row.label(text="Color Blender", icon="COLOR")
601             row.operator("object.colorblender", icon='PLAY', text="Run!")
602             row = box.row()
603             row.operator("object.colorblenderclear", text="Reset Keyframes", icon="KEY_DEHLT")
604             row.prop(Btrace, 'mmSkip', text="Keyframe every")
605             color_blender()
606
607 ###### END PANEL ##############
608 ###############################
609
610
611 ################## ################## ################## ############
612 ## Object Trace
613 ## creates a curve with a modulated radius connecting points of a mesh
614 ################## ################## ################## ############
615
616 class OBJECT_OT_objecttrace(bpy.types.Operator):
617     bl_idname = "object.btobjecttrace"
618     bl_label = "Btrace: Object Trace"
619     bl_description = "Trace selected mesh object with a curve with the option to animate"
620     bl_options = {'REGISTER', 'UNDO'}
621
622
623     @classmethod
624     def poll(cls, context):
625         return (context.object and context.object.type in {'MESH', 'FONT'})
626
627     def invoke(self, context, event):
628         import bpy
629
630         # Run through each selected object and convert to to a curved object
631         brushObj = bpy.context.selected_objects
632         Btrace = bpy.context.window_manager.curve_tracer
633         # Duplicate Mesh
634         if Btrace.object_duplicate:
635             bpy.ops.object.duplicate_move()
636             brushObj = bpy.context.selected_objects
637         # Join Mesh
638         if Btrace.convert_joinbefore:
639             if len(brushObj) > 1:  # Only run if multiple objects selected
640                 bpy.ops.object.join()
641                 brushObj = bpy.context.selected_objects
642
643         for i in brushObj:
644             bpy.context.scene.objects.active = i
645             if i and i.type != 'CURVE':
646                 bpy.ops.object.btconvertcurve()
647                 addtracemat(bpy.context.object.data)
648             if Btrace.animate:
649                 bpy.ops.curve.btgrow()
650         return {'FINISHED'}
651
652
653 ################## ################## ################## ############
654 ## Objects Connect
655 ## connect selected objects with a curve + hooks to each node
656 ## possible handle types: 'FREE' 'AUTO' 'VECTOR' 'ALIGNED'
657 ################## ################## ################## ############
658
659 class OBJECT_OT_objectconnect(bpy.types.Operator):
660     bl_idname = "object.btobjectsconnect"
661     bl_label = "Btrace: Objects Connect"
662     bl_description = "Connect selected objects with a curve and add hooks to each node"
663     bl_options = {'REGISTER', 'UNDO'}
664
665     @classmethod
666     def poll(cls, context):
667         return len(bpy.context.selected_objects) > 1
668
669     def invoke(self, context, event):
670         import bpy, selection_utils
671         list = []
672         Btrace = bpy.context.window_manager.curve_tracer
673         curve_handle = Btrace.curve_handle
674         if curve_handle == 'AUTOMATIC':  # hackish because of naming conflict in api
675             curve_handle = 'AUTO'
676         # Check if Btrace group exists, if not create
677         bgroup = bpy.data.groups.keys()
678         if 'Btrace' not in bgroup:
679             bpy.ops.group.create(name="Btrace")
680         #  check if noise
681         if Btrace.connect_noise:
682             bpy.ops.object.btfcnoise()
683         # check if respect order is checked, create list of objects
684         if Btrace.respect_order == True:
685             selobnames = selection_utils.selected
686             obnames = []
687             for ob in selobnames:
688                 obnames.append(bpy.data.objects[ob])
689         else:
690             obnames = bpy.context.selected_objects  # No selection order
691
692         for a in obnames:
693             list.append(a)
694             a.select = False
695
696         # trace the origins
697         tracer = bpy.data.curves.new('tracer', 'CURVE')
698         tracer.dimensions = '3D'
699         spline = tracer.splines.new('BEZIER')
700         spline.bezier_points.add(len(list) - 1)
701         curve = bpy.data.objects.new('curve', tracer)
702         bpy.context.scene.objects.link(curve)
703
704         # render ready curve
705         tracer.resolution_u = Btrace.curve_u
706         tracer.bevel_resolution = Btrace.curve_resolution  # Set bevel resolution from Panel options
707         tracer.fill_mode = 'FULL'
708         tracer.bevel_depth = Btrace.curve_depth  # Set bevel depth from Panel options
709
710         # move nodes to objects
711         for i in range(len(list)):
712             p = spline.bezier_points[i]
713             p.co = list[i].location
714             p.handle_right_type = curve_handle
715             p.handle_left_type = curve_handle
716
717         bpy.context.scene.objects.active = curve
718         bpy.ops.object.mode_set(mode='OBJECT')
719
720         # place hooks
721         for i in range(len(list)):
722             list[i].select = True
723             curve.data.splines[0].bezier_points[i].select_control_point = True
724             bpy.ops.object.mode_set(mode='EDIT')
725             bpy.ops.object.hook_add_selob()
726             bpy.ops.object.mode_set(mode='OBJECT')
727             curve.data.splines[0].bezier_points[i].select_control_point = False
728             list[i].select = False
729
730         bpy.ops.object.select_all(action='DESELECT')
731         curve.select = True # selected curve after it's created
732         addtracemat(bpy.context.object.data) # Add material
733         if Btrace.animate: # Add Curve Grow it?
734             bpy.ops.curve.btgrow()
735         bpy.ops.object.group_link(group="Btrace") # add to Btrace group
736         if Btrace.animate:
737             bpy.ops.curve.btgrow() # Add grow curve
738         return {'FINISHED'}
739
740
741 ################## ################## ################## ############
742 ## Particle Trace
743 ## creates a curve from each particle of a system
744 ################## ################## ################## ############
745 def  curvetracer(curvename, splinename):
746     Btrace = bpy.context.window_manager.curve_tracer
747     tracer = bpy.data.curves.new(splinename, 'CURVE')
748     tracer.dimensions = '3D'
749     curve = bpy.data.objects.new(curvename, tracer)
750     bpy.context.scene.objects.link(curve)
751     try:
752         tracer.fill_mode = 'FULL'
753     except:
754         tracer.use_fill_front = tracer.use_fill_back = False
755     tracer.bevel_resolution = Btrace.curve_resolution
756     tracer.bevel_depth = Btrace.curve_depth
757     tracer.resolution_u = Btrace.curve_u
758     return tracer, curve
759
760
761 class OBJECT_OT_particletrace(bpy.types.Operator):
762     bl_idname = "particles.particletrace"
763     bl_label = "Btrace: Particle Trace"
764     bl_description = "Creates a curve from each particle of a system. Keeping particle amount under 250 will make this run faster"
765     bl_options = {'REGISTER', 'UNDO'}
766
767     @classmethod
768     def poll(cls, context):
769         return (bpy.context.object and bpy.context.object.particle_systems)
770
771     def execute(self, context):
772         Btrace = bpy.context.window_manager.curve_tracer
773         particle_step = Btrace.particle_step    # step size in frames
774         obj = bpy.context.object
775         ps = obj.particle_systems.active
776         curvelist = []
777         curve_handle = Btrace.curve_handle
778         if curve_handle == 'AUTOMATIC':  # hackish naming conflict
779             curve_handle = 'AUTO'
780         if curve_handle == 'FREE_ALIGN':  # hackish naming conflict
781             curve_handle = 'FREE'
782
783         # Check if Btrace group exists, if not create
784         bgroup = bpy.data.groups.keys()
785         if 'Btrace' not in bgroup:
786             bpy.ops.group.create(name="Btrace")
787
788         if Btrace.curve_join:
789             tracer = curvetracer('Tracer', 'Splines')
790         for x in ps.particles:
791             if not Btrace.curve_join:
792                 tracer = curvetracer('Tracer.000', 'Spline.000')
793             spline = tracer[0].splines.new('BEZIER')
794             spline.bezier_points.add((x.lifetime - 1) // particle_step)  # add point to spline based on step size
795             for t in list(range(int(x.lifetime))):
796                 bpy.context.scene.frame_set(t + x.birth_time)
797                 if not t % particle_step:
798                     p = spline.bezier_points[t // particle_step]
799                     p.co = x.location
800                     p.handle_right_type = curve_handle
801                     p.handle_left_type = curve_handle
802             particlecurve = tracer[1]
803             curvelist.append(particlecurve)
804         # add to group
805         bpy.ops.object.select_all(action='DESELECT')
806         for curveobject in curvelist:
807             curveobject.select = True
808             bpy.context.scene.objects.active = curveobject
809             bpy.ops.object.group_link(group="Btrace")
810             addtracemat(curveobject.data)  # Add material
811         
812         if Btrace.animate:
813             bpy.ops.curve.btgrow()  # Add grow curve
814
815         return {'FINISHED'}
816
817
818 ###########################################################################
819 ## Particle Connect
820 ## connect all particles in active system with a continuous animated curve
821 ###########################################################################
822
823 class OBJECT_OT_traceallparticles(bpy.types.Operator):
824     bl_idname = 'particles.connect'
825     bl_label = 'Connect Particles'
826     bl_description = 'Create a continuous animated curve from particles in active system'
827     bl_options = {'REGISTER', 'UNDO'}
828
829     @classmethod
830     def poll(cls, context):
831         return (bpy.context.object and bpy.context.object.particle_systems)
832
833     def execute(self, context):
834         
835         obj = bpy.context.object
836         ps = obj.particle_systems.active
837         set = ps.settings
838
839         # Grids distribution not supported
840         if set.distribution == 'GRID':
841             self.report({'INFO'},"Grid distribution mode for particles not supported.")
842             return{'FINISHED'}
843         
844         Btrace = bpy.context.window_manager.curve_tracer
845         particle_f_start = Btrace.particle_f_start # Get frame start
846         particle_f_end = Btrace.particle_f_end # Get frame end
847         curve_handle = Btrace.curve_handle
848         if curve_handle == 'AUTOMATIC': # hackish because of naming conflict in api
849             curve_handle = 'AUTO'
850         if curve_handle == 'FREE_ALIGN':
851             curve_handle = 'FREE'        
852         tracer = bpy.data.curves.new('Splines','CURVE') # define what kind of object to create
853         curve = bpy.data.objects.new('Tracer',tracer) # Create new object with settings listed above
854         bpy.context.scene.objects.link(curve) # Link newly created object to the scene
855         spline = tracer.splines.new('BEZIER')  # add a new Bezier point in the new curve
856         spline.bezier_points.add(set.count-1)
857                 
858         tracer.dimensions = '3D'
859         tracer.resolution_u = Btrace.curve_u
860         tracer.bevel_resolution = Btrace.curve_resolution
861         tracer.fill_mode = 'FULL'
862         tracer.bevel_depth = Btrace.curve_depth
863
864         if Btrace.particle_auto:
865             f_start = int(set.frame_start)
866             f_end = int(set.frame_end + set.lifetime)
867         else:
868             if particle_f_end <= particle_f_start:
869                  particle_f_end = particle_f_start + 1
870             f_start = particle_f_start
871             f_end = particle_f_end
872
873         for bFrames in range(f_start, f_end):
874             bpy.context.scene.frame_set(bFrames)
875             if not (bFrames-f_start) % Btrace.particle_step:
876                 for bFrames in range(set.count):
877                     if ps.particles[bFrames].alive_state != 'UNBORN': 
878                         e = bFrames
879                     bp = spline.bezier_points[bFrames]
880                     pt = ps.particles[e]
881                     bp.co = pt.location
882                     #bp.handle_left = pt.location
883                     #bp.handle_right = pt.location
884                     bp.handle_right_type = curve_handle
885                     bp.handle_left_type = curve_handle 
886                     bp.keyframe_insert('co')
887                     bp.keyframe_insert('handle_left')
888                     bp.keyframe_insert('handle_right')
889         # Select new curve
890         bpy.ops.object.select_all(action='DESELECT')
891         curve.select = True
892         bpy.context.scene.objects.active = curve
893         addtracemat(curve.data) #Add material
894         if Btrace.animate:
895             bpy.ops.curve.btgrow()
896         return{'FINISHED'}
897
898 ################## ################## ################## ############
899 ## Writing Tool
900 ## Writes a curve by animating its point's radii
901 ## 
902 ################## ################## ################## ############
903 class OBJECT_OT_writing(bpy.types.Operator):
904     bl_idname = 'curve.btwriting'
905     bl_label = 'Write'
906     bl_description = 'Use Grease Pencil to write and convert to curves'
907     bl_options = {'REGISTER', 'UNDO'}
908
909     # @classmethod  ### Removed so panel still draws if nothing is selected
910     # def poll(cls, context):
911     #     return (context.scene.grease_pencil or context.object.grease_pencil != None)
912
913     def execute(self, context):
914         Btrace = bpy.context.window_manager.curve_tracer
915         obj = bpy.context.object
916         gactive = bpy.context.active_object # set selected object before convert
917         bpy.ops.gpencil.convert(type='CURVE')
918         gactiveCurve = bpy.context.active_object # get curve after convert
919         # render ready curve
920         gactiveCurve.data.resolution_u = Btrace.curve_u
921         gactiveCurve.data.bevel_resolution = Btrace.curve_resolution  # Set bevel resolution from Panel options
922         gactiveCurve.data.fill_mode = 'FULL'
923         gactiveCurve.data.bevel_depth = Btrace.curve_depth  # Set bevel depth from Panel options
924
925         writeObj = bpy.context.selected_objects
926         if Btrace.animate:
927             for i in writeObj:
928                 bpy.context.scene.objects.active = i
929                 bpy.ops.curve.btgrow()
930                 addtracemat(bpy.context.object.data) #Add material
931         else:
932             for i in writeObj:
933                 bpy.context.scene.objects.active = i
934                 addtracemat(bpy.context.object.data) #Add material
935
936         # Delete grease pencil strokes
937         bpy.context.scene.objects.active = gactive
938         bpy.ops.gpencil.data_unlink()
939         bpy.context.scene.objects.active = gactiveCurve
940         # Smooth object
941         bpy.ops.object.shade_smooth()
942         # Return to first frame
943         bpy.context.scene.frame_set(Btrace.anim_f_start)
944         
945         return{'FINISHED'}
946
947 ################## ################## ################## ############
948 ## Create Curve
949 ## Convert mesh to curve using either Continuous, All Edges, or Sharp Edges
950 ## Option to create noise
951 ################## ################## ################## ############
952
953 class OBJECT_OT_convertcurve(bpy.types.Operator):
954     bl_idname = "object.btconvertcurve"
955     bl_label = "Btrace: Create Curve"
956     bl_description = "Convert mesh to curve using either Continuous, All Edges, or Sharp Edges"
957     bl_options = {'REGISTER', 'UNDO'}
958         
959     def execute(self, context):
960         import bpy, random, mathutils
961         from mathutils import Vector
962
963         Btrace = bpy.context.window_manager.curve_tracer
964         traceobjects = bpy.context.selected_objects # create a list with all the selected objects
965
966         obj = bpy.context.object
967         
968         ### Convert Font
969         if obj.type == 'FONT':
970             bpy.ops.object.mode_set(mode='OBJECT')
971             bpy.ops.object.convert(target='CURVE') # Convert edges to curve
972             bpy.context.object.data.dimensions = '3D'
973             
974         # make a continuous edge through all vertices
975         if obj.type == 'MESH':
976             # Add noise to mesh
977             if Btrace.distort_curve:
978                 for v in obj.data.vertices:
979                     for u in range(3):
980                         v.co[u] += Btrace.distort_noise * (random.uniform(-1,1))
981
982             if Btrace.convert_edgetype == 'CONTI':
983                 ## Start Continuous edge
984                 bpy.ops.object.mode_set(mode='EDIT')
985                 bpy.ops.mesh.select_all(action='SELECT')
986                 bpy.ops.mesh.delete(type='EDGE_FACE')
987                 bpy.ops.mesh.select_all(action='DESELECT')
988                 verts = bpy.context.object.data.vertices
989                 bpy.ops.object.mode_set(mode='OBJECT')
990                 li = []
991                 p1 = random.randint(0,len(verts)-1) 
992                 
993                 for v in verts: 
994                     li.append(v.index)
995                 li.remove(p1)
996                 for z in range(len(li)):
997                     x = []
998                     for px in li:
999                         d = verts[p1].co - verts[px].co # find distance from first vert
1000                         x.append(d.length)
1001                     p2 = li[x.index(min(x))] # find the shortest distance list index
1002                     verts[p1].select = verts[p2].select = True
1003                     bpy.ops.object.mode_set(mode='EDIT')
1004                     bpy.context.tool_settings.mesh_select_mode = [True, False, False]
1005                     bpy.ops.mesh.edge_face_add()
1006                     bpy.ops.mesh.select_all(action='DESELECT')
1007                     bpy.ops.object.mode_set(mode='OBJECT')
1008                     # verts[p1].select = verts[p2].select = False #Doesn't work after Bmesh merge
1009                     li.remove(p2)  # remove item from list.
1010                     p1 = p2
1011                 # Convert edges to curve
1012                 bpy.ops.object.mode_set(mode='OBJECT')
1013                 bpy.ops.object.convert(target='CURVE') 
1014             
1015             if Btrace.convert_edgetype == 'EDGEALL':
1016                 ## Start All edges
1017                 bpy.ops.object.mode_set(mode='EDIT')
1018                 bpy.ops.mesh.select_all(action='SELECT')
1019                 bpy.ops.mesh.delete(type='ONLY_FACE')
1020                 bpy.ops.object.mode_set()
1021                 bpy.ops.object.convert(target='CURVE')
1022                 for sp in obj.data.splines:
1023                     sp.type = Btrace.curve_spline
1024
1025         obj = bpy.context.object
1026         # Set spline type to custom property in panel
1027         bpy.ops.object.editmode_toggle()
1028         bpy.ops.curve.spline_type_set(type=Btrace.curve_spline) 
1029         # Set handle type to custom property in panel
1030         bpy.ops.curve.handle_type_set(type=Btrace.curve_handle) 
1031         bpy.ops.object.editmode_toggle()
1032         obj.data.fill_mode = 'FULL'
1033         # Set resolution to custom property in panel
1034         obj.data.bevel_resolution = Btrace.curve_resolution 
1035         obj.data.resolution_u = Btrace.curve_u 
1036         # Set depth to custom property in panel
1037         obj.data.bevel_depth = Btrace.curve_depth 
1038         # Smooth object
1039         bpy.ops.object.shade_smooth()
1040         # Modulate curve radius and add distortion
1041         if Btrace.distort_curve: 
1042             scale = Btrace.distort_modscale
1043             if scale == 0:
1044                 return {'FINISHED'}
1045             for u in obj.data.splines:
1046                 for v in u.bezier_points:
1047                     v.radius = scale*round(random.random(),3) 
1048         return {'FINISHED'}
1049
1050
1051 ################## ################## ################## ############
1052 ## Mesh Follow, trace vertex or faces
1053 ## Create curve at center of selection item, extruded along animation
1054 ## Needs to be animated mesh!!!
1055 ################## ################## ################## ############
1056
1057 class OBJECT_OT_meshfollow(bpy.types.Operator):
1058     bl_idname = "object.btmeshfollow"
1059     bl_label = "Btrace: Vertex Trace"
1060     bl_description = "Trace Vertex or Face on an animated mesh"
1061     bl_options = {'REGISTER', 'UNDO'}
1062         
1063     
1064     @classmethod
1065     def poll(cls, context):
1066         return (context.object and context.object.type in {'MESH'})
1067
1068     def execute(self, context):
1069         import bpy, random
1070         from mathutils import Vector
1071
1072         Btrace = bpy.context.window_manager.curve_tracer
1073         distort_curve = Btrace.distort_curve    # modulate the resulting curve
1074         stepsize = Btrace.particle_step
1075         traceobjects = bpy.context.selected_objects  # create a list with all the selected objects
1076
1077         obj = bpy.context.object
1078         scn = bpy.context.scene
1079         meshdata = obj.data
1080         cursor = bpy.context.scene.cursor_location.copy()  # Store the location to restore at end of script
1081         drawmethod = Btrace.fol_mesh_type  # Draw from Edges, Verts, or Faces
1082         if drawmethod == 'VERTS':
1083             meshobjs = obj.data.vertices
1084         if drawmethod == 'FACES':
1085             meshobjs = obj.data.polygons  # untested
1086         if drawmethod == 'EDGES':
1087             meshobjs = obj.data.edges  # untested
1088
1089         # Frame properties
1090         start_frame, end_frame = Btrace.fol_start_frame, Btrace.fol_end_frame
1091         if start_frame > end_frame:  # Make sure the math works
1092             startframe = end_frame - 5  # if start past end, goto (end - 5)
1093         frames = int((end_frame - start_frame) / stepsize)
1094
1095         def getsel_option():  # Get selection objects.
1096             sel = []
1097             seloption, fol_mesh_type = Btrace.fol_sel_option, Btrace.fol_mesh_type  # options = 'random', 'custom', 'all'
1098             if fol_mesh_type == 'OBJECT':
1099                 pass
1100             else:
1101                 if seloption == 'CUSTOM':
1102                     for i in meshobjs:
1103                         if i.select == True:
1104                             sel.append(i.index)
1105                 if seloption == 'RANDOM':
1106                     for i in list(meshobjs):
1107                         sel.append(i.index)
1108                     finalsel = int(len(sel) * Btrace.fol_perc_verts)
1109                     remove = len(sel) - finalsel
1110                     for i in range(remove):
1111                         sel.pop(random.randint(0, len(sel) - 1))
1112                 if seloption == 'ALL':
1113                     for i in list(meshobjs):
1114                         sel.append(i.index)
1115
1116             return sel
1117
1118         def get_coord(objindex):
1119             obj_co = []  # list of vector coordinates to use
1120             frame_x = start_frame
1121             for i in range(frames):  # create frame numbers list
1122                 scn.frame_set(frame_x)
1123                 if drawmethod != 'OBJECT':
1124                     followed_item = meshobjs[objindex]
1125                     if drawmethod == 'VERTS':
1126                         g_co = obj.matrix_local * followed_item.co  # find Vert vector
1127
1128                     if drawmethod == 'FACES':
1129                         g_co = obj.matrix_local * followed_item.normal  # find Face vector
1130
1131                     if drawmethod == 'EDGES':
1132                         v1 = followed_item.vertices[0]
1133                         v2 = followed_item.vertices[1]
1134                         co1 = bpy.context.object.data.vertices[v1]
1135                         co2 = bpy.context.object.data.vertices[v2]
1136                         localcenter = co1.co.lerp(co2.co, 0.5)
1137                         g_co = obj.matrix_world * localcenter
1138
1139                 if drawmethod == 'OBJECT':
1140                     g_co = objindex.location.copy()
1141
1142                 obj_co.append(g_co)
1143                 frame_x = frame_x + stepsize
1144
1145             scn.frame_set(start_frame)
1146             return obj_co
1147
1148         def make_curve(co_list):
1149             Btrace = bpy.context.window_manager.curve_tracer
1150             tracer = bpy.data.curves.new('tracer','CURVE')
1151             tracer.dimensions = '3D'
1152             spline = tracer.splines.new('BEZIER')
1153             spline.bezier_points.add(len(co_list)-  1)
1154             curve = bpy.data.objects.new('curve',tracer)
1155             scn.objects.link(curve)
1156             curvelist.append(curve)
1157             # render ready curve
1158             tracer.resolution_u = Btrace.curve_u
1159             tracer.bevel_resolution = Btrace.curve_resolution  # Set bevel resolution from Panel options
1160             tracer.fill_mode = 'FULL'
1161             tracer.bevel_depth = Btrace.curve_depth  # Set bevel depth from Panel options
1162             curve_handle = Btrace.curve_handle
1163             if curve_handle == 'AUTOMATIC': # hackish AUTOMATIC doesn't work here
1164                 curve_handle = 'AUTO'
1165
1166             # move bezier points to objects
1167             for i in range(len(co_list)):
1168                 p = spline.bezier_points[i]
1169                 p.co = co_list[i]
1170                 p.handle_right_type = curve_handle
1171                 p.handle_left_type = curve_handle
1172             return curve
1173
1174         # Run methods
1175         # Check if Btrace group exists, if not create
1176         bgroup = bpy.data.groups.keys()
1177         if 'Btrace' not in bgroup:
1178             bpy.ops.group.create(name="Btrace") 
1179
1180         Btrace = bpy.context.window_manager.curve_tracer
1181         sel = getsel_option()  # Get selection
1182         curvelist = []  # list to use for grow curve
1183         
1184         if Btrace.fol_mesh_type == 'OBJECT':
1185             vector_list = get_coord(obj)
1186             curvelist.append(make_curve(vector_list))
1187         else:
1188             for i in sel:
1189                 vector_list = get_coord(i)
1190                 curvelist.append(make_curve(vector_list))
1191         # Select new curves and add to group
1192         bpy.ops.object.select_all(action='DESELECT')
1193         for curveobject in curvelist:
1194             if curveobject.type == 'CURVE':
1195                 curveobject.select = True
1196                 bpy.context.scene.objects.active = curveobject
1197                 bpy.ops.object.group_link(group="Btrace")
1198                 addtracemat(curveobject.data)
1199                 curveobject.select = False
1200
1201         if Btrace.animate:  # Add grow curve
1202             for curveobject in curvelist:
1203                 curveobject.select = True
1204             bpy.ops.curve.btgrow()
1205             for curveobject in curvelist:
1206                 curveobject.select = False
1207
1208         obj.select = False  # Deselect original object
1209         return {'FINISHED'}
1210
1211 ###################################################################
1212 #### Add Tracer Material
1213 ###################################################################
1214
1215 def addtracemat(matobj):
1216     # Need to add cycles or BI render material options
1217     # if engine == 'CYCLES':
1218         # Add cycles mat
1219     # if engine == 'BLENDER_RENDER':
1220         # Add blender interal mat
1221     matslots = bpy.context.object.data.materials.items()  # Check if a material exists, skip if it does
1222     if len(matslots) < 1:  # Make sure there is only one material slot
1223         engine = bpy.context.scene.render.engine
1224         Btrace = bpy.context.window_manager.curve_tracer
1225         if not Btrace.mat_run_color_blender:  # Check if color blender is to be run
1226             if Btrace.trace_mat_random:  # Create Random color for each item
1227                 # Use random color from chosen palette, assign color lists for each palette
1228                 import random
1229                 brightColors  = [Btrace.brightColor1, Btrace.brightColor2, Btrace.brightColor3, Btrace.brightColor4]
1230                 bwColors = [Btrace.bwColor1, Btrace.bwColor2]
1231                 customColors = [Btrace.mmColor1, Btrace.mmColor2, Btrace.mmColor3, Btrace.mmColor4, Btrace.mmColor5, Btrace.mmColor6, Btrace.mmColor7, Btrace.mmColor8]
1232                 earthColors = [Btrace.earthColor1, Btrace.earthColor2, Btrace.earthColor3, Btrace.earthColor4, Btrace.earthColor5]
1233                 greenblueColors = [Btrace.greenblueColor1, Btrace.greenblueColor2, Btrace.greenblueColor3]
1234                 if Btrace.mmColors == 'BRIGHT':
1235                     #print(random.randint(0, len(brightColors) - 1))
1236                     mat_color = brightColors[random.randint(0, len(brightColors) - 1)]
1237                 if Btrace.mmColors == 'BW':
1238                     mat_color = bwColors[random.randint(0, len(bwColors) - 1)]
1239                 if Btrace.mmColors == 'CUSTOM':
1240                     mat_color = customColors[random.randint(0, len(customColors) - 1)]
1241                 if Btrace.mmColors == 'EARTH':
1242                     mat_color = earthColors[random.randint(0, len(earthColors) - 1)]
1243                 if Btrace.mmColors == 'GREENBLUE':
1244                     mat_color = greenblueColors[random.randint(0, len(greenblueColors) - 1)]
1245                 if Btrace.mmColors == 'RANDOM':
1246                     mat_color = (random.random(), random.random(), random.random())
1247             else:  # Choose Single color
1248                 mat_color = Btrace.trace_mat_color
1249             # mat_color = Btrace.trace_mat_color
1250             TraceMat = bpy.data.materials.new('TraceMat')
1251             TraceMat.diffuse_color = mat_color
1252             TraceMat.specular_intensity = 0.5
1253             matobj.materials.append(bpy.data.materials.get(TraceMat.name))
1254
1255         else:  # Run color blender operator
1256             bpy.ops.object.colorblender()
1257
1258     return {'FINISHED'}
1259
1260 ###################################################################
1261 #### Add Color Blender Material
1262 ###################################################################
1263
1264 # This is the magical material changer!
1265 class OBJECT_OT_materialChango(bpy.types.Operator):
1266     bl_idname = 'object.colorblender'
1267     bl_label = 'Color Blender'
1268     bl_options = {'REGISTER', 'UNDO'}
1269
1270     def execute(self, context):
1271
1272         import bpy, random
1273         Btrace = bpy.context.window_manager.curve_tracer  # properties panel
1274         colorObjects = bpy.context.selected_objects
1275
1276         # Set color lists
1277         brightColors  = [Btrace.brightColor1, Btrace.brightColor2, Btrace.brightColor3, Btrace.brightColor4]
1278         bwColors = [Btrace.bwColor1, Btrace.bwColor2]
1279         customColors = [Btrace.mmColor1, Btrace.mmColor2, Btrace.mmColor3, Btrace.mmColor4, Btrace.mmColor5, Btrace.mmColor6, Btrace.mmColor7, Btrace.mmColor8]
1280         earthColors = [Btrace.earthColor1, Btrace.earthColor2, Btrace.earthColor3, Btrace.earthColor4, Btrace.earthColor5]
1281         greenblueColors = [Btrace.greenblueColor1, Btrace.greenblueColor2, Btrace.greenblueColor3]
1282
1283         colorList = Btrace.mmColors
1284
1285         # Go through each selected object and run the operator
1286         for i in colorObjects:
1287             theObj = i
1288             # Check to see if object has materials
1289             checkMaterials = len(theObj.data.materials)
1290             if checkMaterials == 0:
1291                 # Add a material
1292                 materialName = "colorblendMaterial"
1293                 madMat = bpy.data.materials.new(materialName)
1294                 theObj.data.materials.append(madMat)
1295             else:                
1296                 pass # pass since we have what we need
1297                 
1298             # assign the first material of the object to "mat"
1299             mat = theObj.data.materials[0] 
1300
1301             # Numbers of frames to skip between keyframes
1302             skip = Btrace.mmSkip
1303
1304             # Random material function
1305             def colorblenderRandom():
1306                 for crazyNumber in range(3):
1307                     mat.diffuse_color[crazyNumber] = random.random()
1308             
1309             def colorblenderCustom():
1310                 mat.diffuse_color = random.choice(customColors)
1311                 
1312             # Black and white color        
1313             def colorblenderBW():
1314                 mat.diffuse_color = random.choice(bwColors)
1315             
1316             # Bright colors
1317             def colorblenderBright():
1318                 mat.diffuse_color = random.choice(brightColors)
1319                 
1320             # Earth Tones
1321             def colorblenderEarth():
1322                 mat.diffuse_color = random.choice(earthColors)
1323                 
1324             # Green to Blue Tones
1325             def colorblenderGreenBlue():
1326                 mat.diffuse_color = random.choice(greenblueColors)
1327              
1328             # define frame start/end variables
1329             scn = bpy.context.scene       
1330             start = scn.frame_start
1331             end = scn.frame_end           
1332             # Go to each frame in iteration and add material
1333             while start<=(end+(skip-1)):
1334                
1335                 bpy.ops.anim.change_frame(frame=start)
1336                 
1337                 # Check what colors setting is checked and run the appropriate function
1338                 if Btrace.mmColors=='RANDOM':
1339                     colorblenderRandom()
1340                 elif Btrace.mmColors=='CUSTOM':
1341                     colorblenderCustom()
1342                 elif Btrace.mmColors=='BW':
1343                     colorblenderBW()
1344                 elif Btrace.mmColors=='BRIGHT':
1345                     colorblenderBright()
1346                 elif Btrace.mmColors=='EARTH':
1347                     colorblenderEarth()
1348                 elif Btrace.mmColors=='GREENBLUE':
1349                     colorblenderGreenBlue()
1350                 else:
1351                     pass
1352                 
1353                 # Add keyframe to material
1354                 mat.keyframe_insert('diffuse_color')
1355                 
1356                 # Increase frame number
1357                 start += skip
1358         return{'FINISHED'}
1359     
1360 ###### This clears the keyframes ######
1361 class OBJECT_OT_clearColorblender(bpy.types.Operator):
1362     bl_idname = 'object.colorblenderclear'
1363     bl_label = 'Clear colorblendness'
1364     bl_options = {'REGISTER', 'UNDO'}
1365     
1366     def invoke(self, context, event):
1367         
1368         import bpy, random
1369         mcolorblend = context.window_manager.colorblender_operator # properties panel
1370         colorObjects = bpy.context.selected_objects
1371         
1372         # Go through each selected object and run the operator
1373         for i in colorObjects:
1374             theObj = i    
1375             # assign the first material of the object to "mat"
1376             matCl = theObj.data.materials[0] 
1377             
1378             # define frame start/end variables
1379             scn = bpy.context.scene       
1380             start = scn.frame_start
1381             end = scn.frame_end
1382
1383             # Remove all keyframes from diffuse_color, super sloppy need to find better way
1384             while start <= (end * 2):
1385                 bpy.ops.anim.change_frame(frame=start)
1386                 matCl.keyframe_delete('diffuse_color')
1387                 start += 1
1388             
1389         return{'FINISHED'}
1390
1391
1392 ################## ################## ################## ############
1393 ## F-Curve Noise
1394 ## will add noise modifiers to each selected object f-curves
1395 ## change type to: 'rotation' | 'location' | 'scale' | '' to effect all
1396 ## first record a keyframe for this to work (to generate the f-curves)
1397 ################## ################## ################## ############
1398
1399 class OBJECT_OT_fcnoise(bpy.types.Operator):
1400     bl_idname = "object.btfcnoise"
1401     bl_label = "Btrace: F-curve Noise"
1402     bl_options = {'REGISTER', 'UNDO'}
1403     
1404     def execute(self, context):
1405         import bpy, random
1406         
1407         Btrace = bpy.context.window_manager.curve_tracer
1408         amp = Btrace.fcnoise_amp
1409         timescale = Btrace.fcnoise_timescale
1410         addkeyframe = Btrace.fcnoise_key
1411         
1412         # This sets properties for Loc, Rot and Scale if they're checked in the Tools window
1413         noise_rot = 'rotation'
1414         noise_loc = 'location'
1415         noise_scale = 'scale'
1416         if not Btrace.fcnoise_rot:
1417             noise_rot = 'none'
1418         if not Btrace.fcnoise_loc:
1419             noise_loc = 'none'
1420         if not Btrace.fcnoise_scale:
1421             noise_scale = 'none'
1422             
1423         type = noise_loc, noise_rot, noise_scale # Add settings from panel for type of keyframes
1424         amplitude = amp
1425         time_scale = timescale
1426         
1427         for i in bpy.context.selected_objects:
1428             # Add keyframes, this is messy and should only add keyframes for what is checked
1429             if addkeyframe == True:
1430                 bpy.ops.anim.keyframe_insert(type="LocRotScale")         
1431             for obj in bpy.context.selected_objects:
1432                 if obj.animation_data:
1433                     for c in obj.animation_data.action.fcurves:
1434                         if c.data_path.startswith(type):
1435                             # clean modifiers
1436                             for m in c.modifiers : 
1437                                 c.modifiers.remove(m)
1438                             # add noide modifiers
1439                             n = c.modifiers.new('NOISE')
1440                             n.strength = amplitude
1441                             n.scale = time_scale
1442                             n.phase = random.randint(0,999)
1443         return {'FINISHED'}
1444
1445 ################## ################## ################## ############
1446 ## Curve Grow Animation
1447 ## Animate curve radius over length of time
1448 ################## ################## ################## ############     
1449 class OBJECT_OT_curvegrow(bpy.types.Operator):
1450     bl_idname = 'curve.btgrow'
1451     bl_label = 'Run Script'
1452     bl_description = 'Keyframe points radius'
1453     bl_options = {'REGISTER', 'UNDO'}
1454     
1455     @classmethod
1456     def poll(cls, context):
1457         return (context.object and context.object.type in {'CURVE'})
1458     
1459     def execute(self, context):
1460         Btrace = bpy.context.window_manager.curve_tracer
1461         anim_f_start, anim_length, anim_auto = Btrace.anim_f_start, Btrace.anim_length, Btrace.anim_auto
1462         curve_resolution, curve_depth = Btrace.curve_resolution, Btrace.curve_depth
1463         # make the curve visible
1464         objs = bpy.context.selected_objects
1465         for i in objs: # Execute on multiple selected objects
1466             bpy.context.scene.objects.active = i
1467             obj = bpy.context.active_object
1468             try:
1469                 obj.data.fill_mode = 'FULL'
1470             except:
1471                 obj.data.dimensions = '3D'
1472                 obj.data.fill_mode = 'FULL'
1473             if not obj.data.bevel_resolution:
1474                 obj.data.bevel_resolution = curve_resolution
1475             if not obj.data.bevel_depth:
1476                 obj.data.bevel_depth = curve_depth
1477             if anim_auto:
1478                 anim_f_start = bpy.context.scene.frame_start
1479                 anim_length = bpy.context.scene.frame_end
1480             # get points data and beautify
1481             actual, total = anim_f_start, 0
1482             for sp in obj.data.splines:
1483                 total += len(sp.points) + len(sp.bezier_points)
1484             step = anim_length / total
1485             for sp in obj.data.splines:
1486                 sp.radius_interpolation = 'BSPLINE'
1487                 po = [p for p in sp.points] + [p for p in sp.bezier_points]
1488                 if not Btrace.anim_keepr:
1489                     for p in po:
1490                         p.radius = 1
1491                 if Btrace.anim_tails and not sp.use_cyclic_u:
1492                     po[0].radius = po[-1].radius = 0
1493                     po[1].radius = po[-2].radius = .65
1494                 ra = [p.radius for p in po]
1495
1496                 # record the keyframes
1497                 for i in range(len(po)):
1498                     po[i].radius = 0
1499                     po[i].keyframe_insert('radius', frame=actual)
1500                     actual += step
1501                     po[i].radius = ra[i]
1502                     po[i].keyframe_insert('radius', frame=(actual + Btrace.anim_delay))
1503
1504                     if Btrace.anim_f_fade:
1505                         po[i].radius = ra[i]
1506                         po[i].keyframe_insert('radius', frame=(actual + Btrace.anim_f_fade - step))
1507                         po[i].radius = 0
1508                         po[i].keyframe_insert('radius', frame=(actual + Btrace.anim_delay + Btrace.anim_f_fade))
1509
1510             bpy.context.scene.frame_set(Btrace.anim_f_start)
1511         return{'FINISHED'}
1512
1513 ################## ################## ################## ############
1514 ## Remove animation and curve radius data
1515 ################## ################## ################## ############
1516 class OBJECT_OT_reset(bpy.types.Operator):
1517     bl_idname = 'object.btreset'
1518     bl_label = 'Clear animation'
1519     bl_description = 'Remove animation / curve radius data'
1520     bl_options = {'REGISTER', 'UNDO'}
1521
1522     def execute(self, context):
1523         objs = bpy.context.selected_objects
1524         for i in objs: # Execute on multiple selected objects
1525             bpy.context.scene.objects.active = i
1526             obj = bpy.context.active_object
1527             obj.animation_data_clear()
1528             if obj.type == 'CURVE':
1529                 for sp in obj.data.splines:
1530                     po = [p for p in sp.points] + [p for p in sp.bezier_points]
1531                     for p in po:
1532                         p.radius = 1
1533         return{'FINISHED'}
1534
1535 ### Define Classes to register
1536 classes = [
1537     TracerProperties,
1538     TracerPropertiesMenu,
1539     addTracerObjectPanel,
1540     OBJECT_OT_convertcurve,
1541     OBJECT_OT_objecttrace,
1542     OBJECT_OT_objectconnect,
1543     OBJECT_OT_writing,
1544     OBJECT_OT_particletrace,
1545     OBJECT_OT_traceallparticles,
1546     OBJECT_OT_curvegrow,
1547     OBJECT_OT_reset,
1548     OBJECT_OT_fcnoise,
1549     OBJECT_OT_meshfollow,
1550     OBJECT_OT_materialChango,
1551     OBJECT_OT_clearColorblender
1552     ]
1553
1554 def register():
1555     for c in classes:
1556         bpy.utils.register_class(c)
1557     bpy.types.WindowManager.curve_tracer = bpy.props.PointerProperty(type=TracerProperties)
1558     bpy.types.WindowManager.btrace_menu = bpy.props.PointerProperty(type=TracerPropertiesMenu, update=deselect_others)
1559
1560 def unregister():
1561     for c in classes:
1562         bpy.utils.unregister_class(c)
1563     del bpy.types.WindowManager.curve_tracer
1564 if __name__ == "__main__":
1565     register()