diff options
-rw-r--r-- | btrace/__init__.py | 123 | ||||
-rw-r--r-- | btrace/bTrace.py | 2610 | ||||
-rw-r--r-- | btrace/bTrace_props.py | 951 |
3 files changed, 2162 insertions, 1522 deletions
diff --git a/btrace/__init__.py b/btrace/__init__.py index 40ff4df1..c1f62512 100644 --- a/btrace/__init__.py +++ b/btrace/__init__.py @@ -1,43 +1,96 @@ -#BEGIN GPL LICENSE BLOCK +# ##### BEGIN GPL LICENSE BLOCK ##### +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ##### END GPL LICENSE BLOCK ##### -#This program is free software; you can redistribute it and/or -#modify it under the terms of the GNU General Public License -#as published by the Free Software Foundation; either version 2 -#of the License, or (at your option) any later version. - -#This program is distributed in the hope that it will be useful, -#but WITHOUT ANY WARRANTY; without even the implied warranty of -#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -#GNU General Public License for more details. - -#You should have received a copy of the GNU General Public License -#along with this program; if not, write to the Free Software Foundation, -#Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -#END GPL LICENCE BLOCK bl_info = { "name": "Btrace", "author": "liero, crazycourier, Atom, Meta-Androcto, MacKracken", - "version": (1, 1, ), - "blender": (2, 68, 0), + "version": (1, 2, 1), + "blender": (2, 78, 0), "location": "View3D > Tools", "description": "Tools for converting/animating objects/particles into curves", "warning": "", "wiki_url": "https://wiki.blender.org/index.php/Extensions:2.6/Py/Scripts/Curve/Btrace", - "tracker_url": "https://developer.blender.org/maniphest/task/edit/form/2/", "category": "Add Curve"} +if "bpy" in locals(): + import importlib + importlib.reload(bTrace_props) + importlib.reload(bTrace) +else: + from . import bTrace_props + from . import bTrace import bpy -from .bTrace import * -import selection_utils -from bpy.props import FloatProperty, EnumProperty, IntProperty, BoolProperty, FloatVectorProperty +from bpy.types import AddonPreferences +from .bTrace_props import ( + TracerProperties, + addTracerObjectPanel, + ) +from .bTrace import ( + OBJECT_OT_convertcurve, + OBJECT_OT_objecttrace, + OBJECT_OT_objectconnect, + OBJECT_OT_writing, + OBJECT_OT_particletrace, + OBJECT_OT_traceallparticles, + OBJECT_OT_curvegrow, + OBJECT_OT_reset, + OBJECT_OT_fcnoise, + OBJECT_OT_meshfollow, + OBJECT_OT_materialChango, + OBJECT_OT_clearColorblender, + ) +from bpy.props import ( + EnumProperty, + PointerProperty, + ) + + +# Add-on Preferences +class btrace_preferences(AddonPreferences): + bl_idname = __name__ + + expand_enum = EnumProperty( + name="UI Options", + items=[ + ('list', "Drop down list", + "Show all the items as dropdown list in the Tools Region"), + ('col', "Enable Expanded UI Panel", + "Show all the items expanded in the Tools Region in a column"), + ('row', "Icons only in a row", + "Show all the items as icons expanded in a row in the Tools Region") + ], + description="", + default='list' + ) + + def draw(self, context): + layout = self.layout + layout.label("UI Options:") -### Define Classes to register -classes = [ + row = layout.row(align=True) + row.prop(self, "expand_enum", text="UI Options", expand=True) + + +# Define Classes to register +classes = ( TracerProperties, - TracerPropertiesMenu, addTracerObjectPanel, OBJECT_OT_convertcurve, OBJECT_OT_objecttrace, @@ -50,18 +103,22 @@ classes = [ OBJECT_OT_fcnoise, OBJECT_OT_meshfollow, OBJECT_OT_materialChango, - OBJECT_OT_clearColorblender - ] + OBJECT_OT_clearColorblender, + btrace_preferences, + ) + def register(): - for c in classes: - bpy.utils.register_class(c) - bpy.types.WindowManager.curve_tracer = bpy.props.PointerProperty(type=TracerProperties) - bpy.types.WindowManager.btrace_menu = bpy.props.PointerProperty(type=TracerPropertiesMenu, update=deselect_others) + for cls in classes: + bpy.utils.register_class(cls) + bpy.types.WindowManager.curve_tracer = PointerProperty(type=TracerProperties) + def unregister(): - for c in classes: - bpy.utils.unregister_class(c) + for cls in classes: + bpy.utils.unregister_class(cls) del bpy.types.WindowManager.curve_tracer + + if __name__ == "__main__": register() diff --git a/btrace/bTrace.py b/btrace/bTrace.py index 9ac2cfcd..82d93f9d 100644 --- a/btrace/bTrace.py +++ b/btrace/bTrace.py @@ -1,750 +1,206 @@ -#BEGIN GPL LICENSE BLOCK +# ##### BEGIN GPL LICENSE BLOCK ##### +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ##### END GPL LICENSE BLOCK ##### + +# TO DO LIST # +# Add more options to curve radius/modulation plus cyclic/connect curve option -#This program is free software; you can redistribute it and/or -#modify it under the terms of the GNU General Public License -#as published by the Free Software Foundation; either version 2 -#of the License, or (at your option) any later version. - -#This program is distributed in the hope that it will be useful, -#but WITHOUT ANY WARRANTY; without even the implied warranty of -#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -#GNU General Public License for more details. +import bpy +import selection_utils +from bpy.types import Operator +from random import ( + choice as rand_choice, + random as rand_random, + randint as rand_randint, + uniform as rand_uniform, + ) -#You should have received a copy of the GNU General Public License -#along with this program; if not, write to the Free Software Foundation, -#Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -#END GPL LICENCE BLOCK +def error_handlers(self, op_name, error, reports="ERROR", func=False): + if self and reports: + self.report({'WARNING'}, reports + " (See Console for more info)") -bl_info = { - "name": "Btrace", - "author": "liero, crazycourier, Atom, Meta-Androcto, MacKracken", - "version": (1, 1, ), - "blender": (2, 71, 0), - "location": "View3D > Toolshelf > Addons Tab", - "description": "Tools for converting/animating objects/particles into curves", - "warning": "Still under development, bug reports appreciated", - "wiki_url": "", - "tracker_url": "https://developer.blender.org/T29563", - "category": "Add Curve"} + is_func = "Function" if func else "Operator" + print("\n[Btrace]\n{}: {}\nError: {}\n".format(op_name, is_func, error)) -#### TO DO LIST #### -### [ ] Add more options to curve radius/modulation plus cyclic/connect curve option +# Object Trace +# creates a curve with a modulated radius connecting points of a mesh -import bpy -import selection_utils -from bpy.props import FloatProperty, EnumProperty, IntProperty, BoolProperty, FloatVectorProperty - - -def deselect_others(ob, context): - """For tool menu select, deselects others if one selected""" - selected = addTracerObjectPanel.selected - ob[selected] = False - keys = [key for key in ob.keys() if ob[key]] # all the True keys - if len(keys) <= 0: - ob[selected] = True # reselect - return None - for key in keys: - addTracerObjectPanel.selected = key - ob[key] = True - - -# Class for properties panel -class TracerPropertiesMenu(bpy.types.PropertyGroup): - """Toolbar show/hide booleans for tool options""" - tool_objectTrace = BoolProperty(name="Object Trace", default=False, description="Trace selected mesh object with a curve", update=deselect_others) - tool_objectsConnect = BoolProperty(name="Objects Connect", default=False, description="Connect objects with a curve controlled by hooks", update=deselect_others) - tool_particleTrace = BoolProperty(name="Particle Trace", default=False, description="Trace particle path with a curve", update=deselect_others) - tool_meshFollow = BoolProperty(name="Mesh Follow", default=False, description="Follow selection items on animated mesh object", update=deselect_others) - tool_particleConnect = BoolProperty(name="Particle Connect", default=False, description="Connect particles with a curves and animated over particle lifetime", update=deselect_others) - tool_growCurve = BoolProperty(name="Grow Curve", default=False, description="Animate curve bevel over time by keyframing points radius", update=deselect_others) - tool_handwrite = BoolProperty(name="Handwriting", default=False, description="Create and Animate curve using the grease pencil", update=deselect_others) - tool_fcurve = BoolProperty(name="F-Curve Noise", default=False, description="Add F-Curve noise to selected objects", update=deselect_others) - tool_colorblender = BoolProperty(name="Color Blender", default=False, description="Add F-Curve noise to selected objects", update=deselect_others) - - -# Class to define properties -class TracerProperties(bpy.types.PropertyGroup): - """Options for tools""" - 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") - 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") - curve_resolution = IntProperty(name="Bevel Resolution", min=1, max=32, default=4, description="Adjust the Bevel resolution") - curve_depth = FloatProperty(name="Bevel Depth", min=0.0, max=100.0, default=0.1, description="Adjust the Bevel depth") - curve_u = IntProperty(name="Resolution U", min=0, max=64, default=12, description="Adjust the Surface resolution") - curve_join = BoolProperty(name="Join Curves", default=False, description="Join all the curves after they have been created") - curve_smooth = BoolProperty(name="Smooth", default=True, description="Render curve smooth") - # Option to Duplicate Mesh - object_duplicate = BoolProperty(name="Apply to Copy", default=False, description="Apply curve to a copy of object") - # Distort Mesh options - 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") - distort_noise = FloatProperty(name="Mesh Noise", min=0.0, max=50.0, default=0.00, description="Adjust noise added to mesh before adding curve") - # Particle Options - particle_step = IntProperty(name="Step Size", min=1, max=50, default=5, description="Sample one every this number of frames") - particle_auto = BoolProperty(name='Auto Frame Range', default=True, description='Calculate Frame Range from particles life') - particle_f_start = IntProperty(name='Start Frame', min=1, max=5000, default=1, description='Start frame') - particle_f_end = IntProperty(name='End Frame', min=1, max=5000, default=250, description='End frame') - # F-Curve Modifier Properties - fcnoise_rot = BoolProperty(name="Rotation", default=False, description="Affect Rotation") - fcnoise_loc = BoolProperty(name="Location", default=True, description="Affect Location") - fcnoise_scale = BoolProperty(name="Scale", default=False, description="Affect Scale") - fcnoise_amp = IntProperty(name="Amp", min=1, max=500, default=5, description="Adjust the amplitude") - fcnoise_timescale = FloatProperty(name="Time Scale", min=1, max=500, default=50, description="Adjust the time scale") - fcnoise_key = BoolProperty(name="Add Keyframe", default=True, description="Keyframe is needed for tool, this adds a LocRotScale keyframe") - show_curve_settings = BoolProperty(name="Curve Settings", default=False, description="Change the curve settings for the created curve") - material_settings = BoolProperty(name="Material Settings", default=False, description="Change the material settings for the created curve") - particle_settings = BoolProperty(name="Particle Settings", default=False, description="Show the settings for the created curve") - animation_settings = BoolProperty(name="Animation Settings", default=False, description="Show the settings for the Animations") - distort_curve = BoolProperty(name="Add Distortion", default=False, description="Set options to distort the final curve") - connect_noise = BoolProperty(name="F-Curve Noise", default=False, description="Adds F-Curve Noise Modifier to selected objects") - settings_objectTrace = BoolProperty(name="Object Trace Settings", default=False, description="Trace selected mesh object with a curve") - settings_objectsConnect = BoolProperty(name="Objects Connect Settings", default=False, description="Connect objects with a curve controlled by hooks") - settings_objectTrace = BoolProperty(name="Object Trace Settings", default=False, description="Trace selected mesh object with a curve") - respect_order = BoolProperty(name="Order", default=False, description="Remember order objects were selected") - settings_particleTrace = BoolProperty(name="Particle Trace Settings", default=False, description="Trace particle path with a curve") - settings_particleConnect = BoolProperty(name="Particle Connect Settings", default=False, description="Connect particles with a curves and animated over particle lifetime") - settings_growCurve = BoolProperty(name="Grow Curve Settings", default=False, description="Animate curve bevel over time by keyframing points radius") - settings_fcurve = BoolProperty(name="F-Curve Settings", default=False, description="F-Curve Settings") - settings_toggle = BoolProperty(name="Settings", default=False, description="Toggle Settings") - # Animation Options - anim_auto = BoolProperty(name='Auto Frame Range', default=True, description='Automatically calculate Frame Range') - anim_f_start = IntProperty(name='Start', min=1, max=2500, default=1, description='Start frame / Hidden object') - anim_length = IntProperty(name='Duration', min=1, soft_max=1000, max=2500, default=100, description='Animation Length') - 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') - anim_delay = IntProperty(name='Grow', min=0, max=50, default=5, description='Frames it takes a point to grow') - anim_tails = BoolProperty(name='Tails on endpoints', default=True, description='Set radius to zero for open splines endpoints') - anim_keepr = BoolProperty(name='Keep Radius', default=True, description='Try to keep radius data from original curve') - animate = BoolProperty(name="Animate Result", default=False, description='Animate the final curve objects') - # Convert to Curve options - convert_conti = BoolProperty(name='Continuous', default=True, description='Create a continuous curve using verts from mesh') - convert_everyedge = BoolProperty(name='Every Edge', default=False, description='Create a curve from all verts in a mesh') - convert_edgetype = EnumProperty(name="Edge Type for Curves", - items=(("CONTI", "Continuous", "Create a continuous curve using verts from mesh"), ("EDGEALL", "All Edges", "Create a curve from every edge in a mesh")), - description="Choose which type of spline to use when curve is created", default="CONTI") - convert_joinbefore = BoolProperty(name="Join objects before convert", default=False, description='Join all selected mesh to one object before converting to mesh') - # Mesh Follow Options - fol_edge_select = BoolProperty(name='Edge', default=False, description='Grow from edges') - fol_vert_select = BoolProperty(name='Vertex', default=False, description='Grow from verts') - fol_face_select = BoolProperty(name='Face', default=True, description='Grow from faces') - fol_mesh_type = EnumProperty(name='Mesh type', default='VERTS', description='Mesh feature to draw cruves from', items=( - ("VERTS", "Verts", "Draw from Verts"), ("EDGES", "Edges", "Draw from Edges"), ("FACES", "Faces", "Draw from Faces"), ("OBJECT", "Object", "Draw from Object origin"))) - fol_start_frame = IntProperty(name="Start Frame", min=1, max=2500, default=1, description="Start frame for range to trace") - fol_end_frame = IntProperty(name="End Frame", min=1, max=2500, default=250, description="End frame for range to trace") - fol_perc_verts = FloatProperty(name="Reduce selection by", min=0.001, max=1.000, default=0.5, description="percentage of total verts to trace") - fol_sel_option = EnumProperty(name="Selection type", description="Choose which objects to follow", default="RANDOM", items=( - ("RANDOM", "Random", "Follow Random items"), ("CUSTOM", "Custom Select", "Follow selected items"), ("ALL", "All", "Follow all items"))) - trace_mat_color = FloatVectorProperty(name="Material Color", description="Choose material color", min=0, max=1, default=(0.0,0.3,0.6), subtype="COLOR") - trace_mat_random = BoolProperty(name="Random Color", default=False, description='Make the material colors random') - - # Material custom Properties properties - 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") - mat_run_color_blender = BoolProperty(name="Run Color Blender", default=False, description="Generate colors from a color scheme") - mmColors = bpy.props.EnumProperty( - items=(("RANDOM", "Random", "Use random colors"), - ("CUSTOM", "Custom", "Use custom colors"), - ("BW", "Black/White", "Use Black and White"), - ("BRIGHT", "Bright Colors", "Use Bright colors"), - ("EARTH", "Earth", "Use Earth colors"), - ("GREENBLUE", "Green to Blue", "Use Green to Blue colors")), - description="Choose which type of colors the materials uses", - default="BRIGHT", - name="Define a color palette") - # Custom property for how many keyframes to skip - mmSkip = bpy.props.IntProperty(name="frames", min=1, max=500, default=20, description="Number of frames between each keyframes") - # Custom property to enable/disable random order for the - mmBoolRandom = bpy.props.BoolProperty(name="Random Order", default=False, description="Randomize the order of the colors") - # Custom Color properties - mmColor1 = bpy.props.FloatVectorProperty(min=0, max=1, default=(0.8, 0.8, 0.8), description="Custom Color 1", subtype="COLOR") - mmColor2 = bpy.props.FloatVectorProperty(min=0, max=1, default=(0.8, 0.8, 0.3), description="Custom Color 2", subtype="COLOR") - mmColor3 = bpy.props.FloatVectorProperty(min=0, max=1, default=(0.8, 0.5, 0.6), description="Custom Color 3", subtype="COLOR") - mmColor4 = bpy.props.FloatVectorProperty(min=0, max=1, default=(0.2, 0.8, 0.289), description="Custom Color 4", subtype="COLOR") - mmColor5 = bpy.props.FloatVectorProperty(min=0, max=1, default=(1.0, 0.348, 0.8), description="Custom Color 5", subtype="COLOR") - mmColor6 = bpy.props.FloatVectorProperty(min=0, max=1, default=(0.4, 0.67, 0.8), description="Custom Color 6", subtype="COLOR") - mmColor7 = bpy.props.FloatVectorProperty(min=0, max=1, default=(0.66, 0.88, 0.8), description="Custom Color 7", subtype="COLOR") - mmColor8 = bpy.props.FloatVectorProperty(min=0, max=1, default=(0.8, 0.38, 0.22), description="Custom Color 8", subtype="COLOR") - # BW Color properties - bwColor1 = bpy.props.FloatVectorProperty(min=0, max=1, default=(0.0,0.0,0.0), description="Black/White Color 1", subtype="COLOR") - bwColor2 = bpy.props.FloatVectorProperty(min=0, max=1, default=(1.0,1.0,1.0), description="Black/White Color 2", subtype="COLOR") - # Bright Color properties - brightColor1 = bpy.props.FloatVectorProperty(min=0, max=1, default=(1.0, 0.0, 0.75), description="Bright Color 1", subtype="COLOR") - brightColor2 = bpy.props.FloatVectorProperty(min=0, max=1, default=(0.0,1.0,1.0), description="Bright Color 2", subtype="COLOR") - brightColor3 = bpy.props.FloatVectorProperty(min=0, max=1, default=(0.0,1.0,0.0), description="Bright Color 3", subtype="COLOR") - brightColor4 = bpy.props.FloatVectorProperty(min=0, max=1, default=(1.0,1.0,0.0), description="Bright Color 4", subtype="COLOR") - # Earth Color Properties - earthColor1 = bpy.props.FloatVectorProperty(min=0, max=1, default=(0.068, 0.019, 0.014), description="Earth Color 1", subtype="COLOR") - earthColor2 = bpy.props.FloatVectorProperty(min=0, max=1, default=(0.089, 0.060, 0.047), description="Earth Color 2", subtype="COLOR") - earthColor3 = bpy.props.FloatVectorProperty(min=0, max=1, default=(0.188, 0.168, 0.066), description="Earth Color 3", subtype="COLOR") - earthColor4 = bpy.props.FloatVectorProperty(min=0, max=1, default=(0.445, 0.296, 0.065), description="Earth Color 4", subtype="COLOR") - earthColor5 = bpy.props.FloatVectorProperty(min=0, max=1, default=(0.745, 0.332, 0.065), description="Earth Color 5", subtype="COLOR") - # Green to Blue Color properties - greenblueColor1 = bpy.props.FloatVectorProperty(min=0, max=1, default=(0.296, 0.445, 0.074), description="Green/Blue Color 1", subtype="COLOR") - greenblueColor2 = bpy.props.FloatVectorProperty(min=0, max=1, default=(0.651, 1.0, 0.223), description="Green/Blue Color 2", subtype="COLOR") - greenblueColor3 = bpy.props.FloatVectorProperty(min=0, max=1, default=(0.037, 0.047, 0.084), description="Green/Blue Color 3", subtype="COLOR") - - -############################ -## Draw Brush panel in Toolbar -############################ -class addTracerObjectPanel(bpy.types.Panel): - bl_label = "Btrace: Panel" - bl_space_type = 'VIEW_3D' - bl_region_type = 'TOOLS' - bl_context = 'objectmode' - selected = "tool_objectTrace" - bl_category = 'Create' - bl_options = {'DEFAULT_CLOSED'} - - - def draw(self, context): - layout = self.layout - Btrace = bpy.context.window_manager.curve_tracer - btracemenu = props = bpy.context.window_manager.btrace_menu - obj = bpy.context.object - - - ############################ - ## Color Blender Panel options - ############################ - def color_blender(): - """Buttons for Color Blender""" - row = box.row() - row.label("Color palette") - row.prop(Btrace, 'mmColors', text="") - # Show Custom Colors if selected - if Btrace.mmColors == 'CUSTOM': - row = box.row(align=True) - row.prop(Btrace, 'mmColor1', text="") - row.prop(Btrace, 'mmColor2', text="") - row.prop(Btrace, 'mmColor3', text="") - row.prop(Btrace, 'mmColor4', text="") - row.prop(Btrace, 'mmColor5', text="") - row.prop(Btrace, 'mmColor6', text="") - row.prop(Btrace, 'mmColor7', text="") - row.prop(Btrace, 'mmColor8', text="") - # Show Earth Colors - elif Btrace.mmColors == 'BW': - row = box.row(align=True) - row.prop(Btrace, 'bwColor1', text="") - row.prop(Btrace, 'bwColor2', text="") - # Show Earth Colors - elif Btrace.mmColors == 'BRIGHT': - row = box.row(align=True) - row.prop(Btrace, 'brightColor1', text="") - row.prop(Btrace, 'brightColor2', text="") - row.prop(Btrace, 'brightColor3', text="") - row.prop(Btrace, 'brightColor4', text="") - # Show Earth Colors - elif Btrace.mmColors == 'EARTH': - row = box.row(align=True) - row.prop(Btrace, 'earthColor1', text="") - row.prop(Btrace, 'earthColor2', text="") - row.prop(Btrace, 'earthColor3', text="") - row.prop(Btrace, 'earthColor4', text="") - row.prop(Btrace, 'earthColor5', text="") - # Show Earth Colors - elif Btrace.mmColors == 'GREENBLUE': - row = box.row(align=True) - row.prop(Btrace, 'greenblueColor1', text="") - row.prop(Btrace, 'greenblueColor2', text="") - row.prop(Btrace, 'greenblueColor3', text="") - elif Btrace.mmColors == 'RANDOM': - row = box.row() - - ############################ - ## Curve Panel options - ############################ - def curve_settings(): - """Button for curve options""" - row = self.layout.row() - row = box.row(align=True) - - row.prop(Btrace, 'show_curve_settings', icon='CURVE_BEZCURVE', text="Curve Settings") - row.prop(Btrace, 'material_settings', icon='MATERIAL_DATA', text="Material Settings") - if Btrace.material_settings: - row = box.row() - row.label(text="Material Settings", icon='COLOR') - row = box.row() - row.prop(Btrace, "trace_mat_random") - if not Btrace.trace_mat_random: - row = box.row() - row.prop(Btrace, "trace_mat_color", text="") - else: - row.prop(Btrace, "mat_run_color_blender") - if Btrace.mat_run_color_blender: - row = box.row() - row.operator("object.colorblenderclear", text="Reset Material Keyframes", icon="KEY_DEHLT") - row.prop(Btrace, 'mmSkip', text="Keyframe every") - - color_blender() - row = box.row() - if Btrace.show_curve_settings: - #if or btracemenu.tool_handwrite: - if len(bpy.context.selected_objects) > 0 and obj.type == 'CURVE': # selected curve options - col = box.column(align=True) - col.label(text="Edit Curves for", icon='CURVE_BEZCURVE') - col.label(text="Selected Curve Bevel Options") - row = col.row(align=True) - row.prop(obj.data, 'bevel_depth', text="Depth") - row.prop(obj.data, 'bevel_resolution', text="Resolution") - row = col.row(align=True) - row.prop(obj.data, 'resolution_u') - else: # For new curve - box.label(text="New Curve Settings", icon='CURVE_BEZCURVE') - box.prop(Btrace, "curve_spline") - box.prop(Btrace, "curve_handle") - box.label(text="Bevel Options") - col = box.column(align=True) - row = col.row(align=True) - row.prop(Btrace, "curve_depth", text="Depth") - row.prop(Btrace, "curve_resolution", text="Resolution") - row = col.row(align=True) - row.prop(Btrace, "curve_u") - - ############################ - ## Grow Animation Panel options - ############################ - def add_grow(): - """Button for grow animation option""" - row = box.row() - row.label(text="Animate Final Curve") - row = box.row() - row.prop(Btrace, "animate", text="Add Grow Curve Animation", icon="META_BALL") - row.label("") - if Btrace.animate: - box.label(text='Frame Animation Settings:', icon="META_BALL") - col = box.column(align=True) - col.prop(Btrace, 'anim_auto') - if not Btrace.anim_auto: - row = col.row(align=True) - row.prop(Btrace, 'anim_f_start') - row.prop(Btrace, 'anim_length') - row = col.row(align=True) - row.prop(Btrace, 'anim_delay') - row.prop(Btrace, 'anim_f_fade') - - box.label(text='Additional Settings') - row = box.row() - row.prop(Btrace, 'anim_tails') - row.prop(Btrace, 'anim_keepr') - - ################################################################## - ## Start Btrace Panel - ################################################################## - col = self.layout.column(align=True) - #col.label(text="Trace Tools") - row = col.row() - row.prop(btracemenu, "tool_objectTrace", text="Ojbect Trace", icon="FORCE_MAGNETIC") - row.prop(btracemenu, "tool_objectsConnect", text="Object Connect", icon="OUTLINER_OB_EMPTY") - row = col.row() - row.prop(btracemenu, "tool_meshFollow", text="Mesh Follow", icon="DRIVER") - row.prop(btracemenu, "tool_handwrite", text="Handwriting", icon='BRUSH_DATA') - row = col.row() - row.prop(btracemenu, "tool_particleTrace", icon="PARTICLES", text="Particle Trace") - row.prop(btracemenu, "tool_particleConnect", icon="MOD_PARTICLES", text="Particle Connect") - row = layout.row() - col = layout.column(align=True) - row = col.row() - row.prop(btracemenu, "tool_growCurve", icon="META_BALL", text="Grow Animation") - row.prop(btracemenu, "tool_fcurve", text="Fcurve Noise", icon='RNDCURVE') - row = col.row() - row.prop(btracemenu, "tool_colorblender", text="Color Blender", icon="COLOR") - row.label(text="") - row = layout.row() - - ########################## - ## Start Object Tools - ########################## - sel = bpy.context.selected_objects - ############################ - ### Object Trace - ############################ - if btracemenu.tool_objectTrace: - row = layout.row() - row.label(text=" Trace Tool:", icon="FORCE_CURVE") - box = self.layout.box() - row = box.row() - row.label(text="Object Trace", icon="FORCE_MAGNETIC") - row.operator("object.btobjecttrace", text="Run!", icon="PLAY") - row = box.row() - row.prop(Btrace, "settings_toggle", icon='MODIFIER', text='Settings') - myselected = "Selected %d" % len(bpy.context.selected_objects) - row.label(text=myselected) - if Btrace.settings_toggle: - row = box.row() - row.label(text='Edge Draw Method') - row = box.row(align=True) - row.prop(Btrace, 'convert_edgetype') - box.prop(Btrace, "object_duplicate") - if len(sel) > 1: - box.prop(Btrace, 'convert_joinbefore') - else: - Btrace.convert_joinbefore = False - row = box.row() - row.prop(Btrace, "distort_curve") - if Btrace.distort_curve: - col = box.column(align=True) - col.prop(Btrace, "distort_modscale") - col.prop(Btrace, "distort_noise") - row = box.row() - curve_settings() # Show Curve/material settings - add_grow() # Grow settings here - - ############################ - ### Objects Connect - ############################ - if btracemenu.tool_objectsConnect: - row = layout.row() - row.label(text=" Trace Tool:", icon="FORCE_CURVE") - box = self.layout.box() - row = box.row() - row.label(text="Objects Connect", icon="OUTLINER_OB_EMPTY") - row.operator("object.btobjectsconnect", text="Run!", icon="PLAY") - row = box.row() - row.prop(Btrace, "settings_toggle", icon='MODIFIER', text='Settings') - row.label(text="") - if Btrace.settings_toggle: - row = box.row() - row.prop(Btrace, "respect_order", text="Selection Options") - if Btrace.respect_order: - box.operator("object.select_order", text="Click to start order selection", icon='UV_SYNC_SELECT') - row = box.row() - row.prop(Btrace, "connect_noise", text="Add F-Curve Noise") - if Btrace.connect_noise: - row = box.row() - row.label(text="F-Curve Noise", icon='RNDCURVE') - row = box.row(align=True) - row.prop(Btrace, "fcnoise_rot") - row.prop(Btrace, "fcnoise_loc") - row.prop(Btrace, "fcnoise_scale") - col = box.column(align=True) - col.prop(Btrace, "fcnoise_amp") - col.prop(Btrace, "fcnoise_timescale") - box.prop(Btrace, "fcnoise_key") - curve_settings() # Show Curve/material settings - add_grow() # Grow settings here - - ############################ - ### Mesh Follow - ############################ - if btracemenu.tool_meshFollow: - row = layout.row() - row.label(text=" Trace Tool:", icon="FORCE_CURVE") - box = self.layout.box() - row = box.row() - row.label(text="Mesh Follow", icon="DRIVER") - row.operator("object.btmeshfollow", text="Run!", icon="PLAY") - row = box.row() - if Btrace.fol_mesh_type == 'OBJECT': - a, b = "Trace Object", "SNAP_VOLUME" - if Btrace.fol_mesh_type == 'VERTS': - a, b = "Trace Verts", "SNAP_VERTEX" - if Btrace.fol_mesh_type == 'EDGES': - a, b = "Trace Edges", "SNAP_EDGE" - if Btrace.fol_mesh_type == 'FACES': - a, b = "Trace Faces", "SNAP_FACE" - row.prop(Btrace, "settings_toggle", icon='MODIFIER', text='Settings') - row.label(text=a, icon=b) - if Btrace.settings_toggle: - col = box.column(align=True) - row = col.row(align=True) - row.prop(Btrace, "fol_mesh_type", expand=True) - row = col.row(align=True) - if Btrace.fol_mesh_type != 'OBJECT': - row.prop(Btrace, "fol_sel_option", expand=True) - row = box.row() - if Btrace.fol_sel_option == 'RANDOM': - row.label("Random Select of Total") - row.prop(Btrace, "fol_perc_verts", text="%") - if Btrace.fol_sel_option == 'CUSTOM': - row.label("Choose selection in Edit Mode") - if Btrace.fol_sel_option == 'ALL': - row.label("Select All items") - col = box.column(align=True) - col.label("Time Options", icon="TIME") - col.prop(Btrace, "particle_step") - row = col.row(align=True) - row.prop(Btrace, "fol_start_frame") - row.prop(Btrace, "fol_end_frame") - curve_settings() # Show Curve/material settings - add_grow() # Grow settings here - - ############################ - ### Handwriting Tools - ############################ - if btracemenu.tool_handwrite: - row = layout.row() - row.label(text=" Trace Tool:", icon="FORCE_CURVE") - box = self.layout.box() - row = box.row() - row.label(text='Handwriting', icon='BRUSH_DATA') - row.operator("curve.btwriting", text="Run!", icon='PLAY') - row = box.row() - row = box.row() - row.label(text='Grease Pencil Writing Tools') - col = box.column(align=True) - row = col.row(align=True) - row.operator("gpencil.draw", text="Draw", icon='BRUSH_DATA').mode = 'DRAW' - row.operator("gpencil.draw", text="Poly", icon='VPAINT_HLT').mode = 'DRAW_POLY' - row = col.row(align=True) - row.operator("gpencil.draw", text="Line", icon='ZOOMOUT').mode = 'DRAW_STRAIGHT' - row.operator("gpencil.draw", text="Erase", icon='TPAINT_HLT').mode = 'ERASER' - row = box.row() - row.operator("gpencil.data_unlink", text="Delete Grease Pencil Layer", icon="CANCEL") - row = box.row() - curve_settings() # Show Curve/material settings - add_grow() # Grow settings here - - ############################ - ### Particle Trace - ############################ - if btracemenu.tool_particleTrace: - row = layout.row() - row.label(text=" Trace Tool:", icon="FORCE_CURVE") - box = self.layout.box() - row = box.row() - row.label(text="Particle Trace", icon="PARTICLES") - row.operator("particles.particletrace", text="Run!", icon="PLAY") - row = box.row() - row.prop(Btrace, "settings_toggle", icon='MODIFIER', text='Settings') - row.label(text="") - if Btrace.settings_toggle: - box.prop(Btrace, "particle_step") - row = box.row() - row.prop(Btrace, "curve_join") - curve_settings() # Show Curve/material settings - add_grow() # Grow settings here - - ############################ - ### Connect Particles - ############################ - if btracemenu.tool_particleConnect: - row = layout.row() - row.label(text=" Trace Tool:", icon="FORCE_CURVE") - box = self.layout.box() - row = box.row() - row.label(text='Particle Connect', icon='MOD_PARTICLES') - row.operator("particles.connect", icon="PLAY", text='Run!') - row = box.row() - row.prop(Btrace, "settings_toggle", icon='MODIFIER', text='Settings') - row.label(text="") - if Btrace.settings_toggle: - box.prop(Btrace, "particle_step") - row = box.row() - row.prop(Btrace, 'particle_auto') - if not Btrace.particle_auto: - row = box.row(align=True) - row.prop(Btrace, 'particle_f_start') - row.prop(Btrace, 'particle_f_end') - curve_settings() # Show Curve/material settings - add_grow() # Grow settings here - - ####################### - #### Grow Animation #### - ####################### - if btracemenu.tool_growCurve: - row = layout.row() - row.label(text=" Curve Tool:", icon="OUTLINER_OB_CURVE") - box = self.layout.box() - row = box.row() - row.label(text="Grow Curve", icon="META_BALL") - row.operator('curve.btgrow', text='Run!', icon='PLAY') - row = box.row() - row.prop(Btrace, "settings_toggle", icon='MODIFIER', text='Settings') - row.operator('object.btreset', icon='KEY_DEHLT') - if Btrace.settings_toggle: - box.label(text='Frame Animation Settings:') - col = box.column(align=True) - col.prop(Btrace, 'anim_auto') - if not Btrace.anim_auto: - row = col.row(align=True) - row.prop(Btrace, 'anim_f_start') - row.prop(Btrace, 'anim_length') - row = col.row(align=True) - row.prop(Btrace, 'anim_delay') - row.prop(Btrace, 'anim_f_fade') - - box.label(text='Additional Settings') - row = box.row() - row.prop(Btrace, 'anim_tails') - row.prop(Btrace, 'anim_keepr') - - ####################### - #### F-Curve Noise Curve #### - ####################### - if btracemenu.tool_fcurve: - row = layout.row() - row.label(text=" Curve Tool:", icon="OUTLINER_OB_CURVE") - box = self.layout.box() - row = box.row() - row.label(text="F-Curve Noise", icon='RNDCURVE') - row.operator("object.btfcnoise", icon='PLAY', text="Run!") - row = box.row() - row.prop(Btrace, "settings_toggle", icon='MODIFIER', text='Settings') - row.operator('object.btreset', icon='KEY_DEHLT') - if Btrace.settings_toggle: - row = box.row(align=True) - row.prop(Btrace, "fcnoise_rot") - row.prop(Btrace, "fcnoise_loc") - row.prop(Btrace, "fcnoise_scale") - col = box.column(align=True) - col.prop(Btrace, "fcnoise_amp") - col.prop(Btrace, "fcnoise_timescale") - box.prop(Btrace, "fcnoise_key") - - ####################### - #### Color Blender #### - ####################### - if btracemenu.tool_colorblender: - row = layout.row() - row.label(text=" Curve/Object Tool:", icon="OUTLINER_OB_CURVE") - box = self.layout.box() - row = box.row() - row.label(text="Color Blender", icon="COLOR") - row.operator("object.colorblender", icon='PLAY', text="Run!") - row = box.row() - row.operator("object.colorblenderclear", text="Reset Keyframes", icon="KEY_DEHLT") - row.prop(Btrace, 'mmSkip', text="Keyframe every") - color_blender() - -###### END PANEL ############## -############################### - - -################## ################## ################## ############ -## Object Trace -## creates a curve with a modulated radius connecting points of a mesh -################## ################## ################## ############ - -class OBJECT_OT_objecttrace(bpy.types.Operator): +class OBJECT_OT_objecttrace(Operator): bl_idname = "object.btobjecttrace" bl_label = "Btrace: Object Trace" - bl_description = "Trace selected mesh object with a curve with the option to animate" + bl_description = ("Trace selected mesh object with a curve with the option to animate\n" + "The Active Object has to be of a Mesh or Font type") bl_options = {'REGISTER', 'UNDO'} - @classmethod def poll(cls, context): - return (context.object and context.object.type in {'MESH', 'FONT'}) + return (context.object and + context.object.type in {'MESH', 'FONT'}) def invoke(self, context, event): - import bpy - - # Run through each selected object and convert to to a curved object - brushObj = bpy.context.selected_objects - Btrace = bpy.context.window_manager.curve_tracer - # Duplicate Mesh - if Btrace.object_duplicate: - bpy.ops.object.duplicate_move() - brushObj = bpy.context.selected_objects - # Join Mesh - if Btrace.convert_joinbefore: - if len(brushObj) > 1: # Only run if multiple objects selected - bpy.ops.object.join() - brushObj = bpy.context.selected_objects - - for i in brushObj: - bpy.context.scene.objects.active = i - if i and i.type != 'CURVE': - bpy.ops.object.btconvertcurve() - addtracemat(bpy.context.object.data) - if Btrace.animate: - bpy.ops.curve.btgrow() - return {'FINISHED'} - - -################## ################## ################## ############ -## Objects Connect -## connect selected objects with a curve + hooks to each node -## possible handle types: 'FREE' 'AUTO' 'VECTOR' 'ALIGNED' -################## ################## ################## ############ - -class OBJECT_OT_objectconnect(bpy.types.Operator): + try: + # Run through each selected object and convert to to a curved object + brushObj = context.selected_objects + Btrace = context.window_manager.curve_tracer + check_materials = True + # Duplicate Mesh + if Btrace.object_duplicate: + bpy.ops.object.duplicate_move() + brushObj = context.selected_objects + # Join Mesh + if Btrace.convert_joinbefore: + if len(brushObj) > 1: # Only run if multiple objects selected + bpy.ops.object.join() + brushObj = context.selected_objects + + for i in brushObj: + context.scene.objects.active = i + if i and i.type != 'CURVE': + bpy.ops.object.btconvertcurve() + # Materials + trace_mats = addtracemat(bpy.context.object.data) + if not trace_mats and check_materials is True: + check_materials = False + if Btrace.animate: + bpy.ops.curve.btgrow() + + if check_materials is False: + self.report({'WARNING'}, "Some Materials could not be added") + + return {'FINISHED'} + + except Exception as e: + error_handlers(self, "object.btobjecttrace", e, + "Object Trace could not be completed") + + return {'CANCELLED'} + + +# Objects Connect +# connect selected objects with a curve + hooks to each node +# possible handle types: 'FREE' 'AUTO' 'VECTOR' 'ALIGNED' + +class OBJECT_OT_objectconnect(Operator): bl_idname = "object.btobjectsconnect" bl_label = "Btrace: Objects Connect" - bl_description = "Connect selected objects with a curve and add hooks to each node" + bl_description = ("Connect selected objects with a curve and add hooks to each node\n" + "Needs at least two objects selected") bl_options = {'REGISTER', 'UNDO'} @classmethod def poll(cls, context): - return len(bpy.context.selected_objects) > 1 + return len(context.selected_objects) > 1 def invoke(self, context, event): - import bpy, selection_utils - list = [] - Btrace = bpy.context.window_manager.curve_tracer - curve_handle = Btrace.curve_handle - if curve_handle == 'AUTOMATIC': # hackish because of naming conflict in api - curve_handle = 'AUTO' - # Check if Btrace group exists, if not create - bgroup = bpy.data.groups.keys() - if 'Btrace' not in bgroup: - bpy.ops.group.create(name="Btrace") - # check if noise - if Btrace.connect_noise: - bpy.ops.object.btfcnoise() - # check if respect order is checked, create list of objects - if Btrace.respect_order == True: - selobnames = selection_utils.selected - obnames = [] - for ob in selobnames: - obnames.append(bpy.data.objects[ob]) - else: - obnames = bpy.context.selected_objects # No selection order - - for a in obnames: - list.append(a) - a.select = False - - # trace the origins - tracer = bpy.data.curves.new('tracer', 'CURVE') - tracer.dimensions = '3D' - spline = tracer.splines.new('BEZIER') - spline.bezier_points.add(len(list) - 1) - curve = bpy.data.objects.new('curve', tracer) - bpy.context.scene.objects.link(curve) - - # render ready curve - tracer.resolution_u = Btrace.curve_u - tracer.bevel_resolution = Btrace.curve_resolution # Set bevel resolution from Panel options - tracer.fill_mode = 'FULL' - tracer.bevel_depth = Btrace.curve_depth # Set bevel depth from Panel options - - # move nodes to objects - for i in range(len(list)): - p = spline.bezier_points[i] - p.co = list[i].location - p.handle_right_type = curve_handle - p.handle_left_type = curve_handle - - bpy.context.scene.objects.active = curve - bpy.ops.object.mode_set(mode='OBJECT') - - # place hooks - for i in range(len(list)): - list[i].select = True - curve.data.splines[0].bezier_points[i].select_control_point = True - bpy.ops.object.mode_set(mode='EDIT') - bpy.ops.object.hook_add_selob() + try: + lists = [] + Btrace = context.window_manager.curve_tracer + curve_handle = Btrace.curve_handle + if curve_handle == 'AUTOMATIC': # hackish because of naming conflict in api + curve_handle = 'AUTO' + # Check if Btrace group exists, if not create + bgroup = bpy.data.groups.keys() + if 'Btrace' not in bgroup: + bpy.ops.group.create(name="Btrace") + # check if noise + if Btrace.connect_noise: + bpy.ops.object.btfcnoise() + # check if respect order is checked, create list of objects + if Btrace.respect_order is True: + selobnames = selection_utils.selected + obnames = [] + for ob in selobnames: + obnames.append(bpy.data.objects[ob]) + else: + obnames = bpy.context.selected_objects # No selection order + + for a in obnames: + lists.append(a) + a.select = False + + # trace the origins + tracer = bpy.data.curves.new('tracer', 'CURVE') + tracer.dimensions = '3D' + spline = tracer.splines.new('BEZIER') + spline.bezier_points.add(len(lists) - 1) + curve = bpy.data.objects.new('curve', tracer) + bpy.context.scene.objects.link(curve) + + # render ready curve + tracer.resolution_u = Btrace.curve_u + # Set bevel resolution from Panel options + tracer.bevel_resolution = Btrace.curve_resolution + tracer.fill_mode = 'FULL' + # Set bevel depth from Panel options + tracer.bevel_depth = Btrace.curve_depth + + # move nodes to objects + for i in range(len(lists)): + p = spline.bezier_points[i] + p.co = lists[i].location + p.handle_right_type = curve_handle + p.handle_left_type = curve_handle + + bpy.context.scene.objects.active = curve bpy.ops.object.mode_set(mode='OBJECT') - curve.data.splines[0].bezier_points[i].select_control_point = False - list[i].select = False - - bpy.ops.object.select_all(action='DESELECT') - curve.select = True # selected curve after it's created - addtracemat(bpy.context.object.data) # Add material - if Btrace.animate: # Add Curve Grow it? - bpy.ops.curve.btgrow() - bpy.ops.object.group_link(group="Btrace") # add to Btrace group - if Btrace.animate: - bpy.ops.curve.btgrow() # Add grow curve - return {'FINISHED'} - - -################## ################## ################## ############ -## Particle Trace -## creates a curve from each particle of a system -################## ################## ################## ############ -def curvetracer(curvename, splinename): + + # place hooks + for i in range(len(lists)): + lists[i].select = True + curve.data.splines[0].bezier_points[i].select_control_point = True + bpy.ops.object.mode_set(mode='EDIT') + bpy.ops.object.hook_add_selob() + bpy.ops.object.mode_set(mode='OBJECT') + curve.data.splines[0].bezier_points[i].select_control_point = False + lists[i].select = False + + bpy.ops.object.select_all(action='DESELECT') + curve.select = True # selected curve after it's created + # Materials + check_materials = True + trace_mats = addtracemat(bpy.context.object.data) + if not trace_mats and check_materials is True: + check_materials = False + + if Btrace.animate: # Add Curve Grow it? + bpy.ops.curve.btgrow() + + bpy.ops.object.group_link(group="Btrace") # add to Btrace group + if Btrace.animate: + bpy.ops.curve.btgrow() # Add grow curve + + if check_materials is False: + self.report({'WARNING'}, "Some Materials could not be added") + + return {'FINISHED'} + + except Exception as e: + error_handlers(self, "object.btobjectsconnect", e, + "Objects Connect could not be completed") + + return {'CANCELLED'} + + +# Particle Trace +# creates a curve from each particle of a system + +def curvetracer(curvename, splinename): Btrace = bpy.context.window_manager.curve_tracer tracer = bpy.data.curves.new(splinename, 'CURVE') tracer.dimensions = '3D' @@ -757,762 +213,940 @@ def curvetracer(curvename, splinename): tracer.bevel_resolution = Btrace.curve_resolution tracer.bevel_depth = Btrace.curve_depth tracer.resolution_u = Btrace.curve_u + return tracer, curve -class OBJECT_OT_particletrace(bpy.types.Operator): +class OBJECT_OT_particletrace(Operator): bl_idname = "particles.particletrace" bl_label = "Btrace: Particle Trace" - bl_description = "Creates a curve from each particle of a system. Keeping particle amount under 250 will make this run faster" + bl_description = ("Creates a curve from each particle of a system.\n" + "Keeping particle amount under 250 will make this run faster") bl_options = {'REGISTER', 'UNDO'} @classmethod def poll(cls, context): - return (bpy.context.object and bpy.context.object.particle_systems) + return (context.object is not None and + context.object.particle_systems) def execute(self, context): - Btrace = bpy.context.window_manager.curve_tracer - particle_step = Btrace.particle_step # step size in frames - obj = bpy.context.object - ps = obj.particle_systems.active - curvelist = [] - curve_handle = Btrace.curve_handle - if curve_handle == 'AUTOMATIC': # hackish naming conflict - curve_handle = 'AUTO' - if curve_handle == 'FREE_ALIGN': # hackish naming conflict - curve_handle = 'FREE' - - # Check if Btrace group exists, if not create - bgroup = bpy.data.groups.keys() - if 'Btrace' not in bgroup: - bpy.ops.group.create(name="Btrace") - - if Btrace.curve_join: - tracer = curvetracer('Tracer', 'Splines') - for x in ps.particles: - if not Btrace.curve_join: - tracer = curvetracer('Tracer.000', 'Spline.000') - spline = tracer[0].splines.new('BEZIER') - spline.bezier_points.add((x.lifetime - 1) // particle_step) # add point to spline based on step size - for t in list(range(int(x.lifetime))): - bpy.context.scene.frame_set(t + x.birth_time) - if not t % particle_step: - p = spline.bezier_points[t // particle_step] - p.co = x.location - p.handle_right_type = curve_handle - p.handle_left_type = curve_handle - particlecurve = tracer[1] - curvelist.append(particlecurve) - # add to group - bpy.ops.object.select_all(action='DESELECT') - for curveobject in curvelist: - curveobject.select = True - bpy.context.scene.objects.active = curveobject - bpy.ops.object.group_link(group="Btrace") - addtracemat(curveobject.data) # Add material - - if Btrace.animate: - bpy.ops.curve.btgrow() # Add grow curve - - return {'FINISHED'} - - -########################################################################### -## Particle Connect -## connect all particles in active system with a continuous animated curve -########################################################################### - -class OBJECT_OT_traceallparticles(bpy.types.Operator): - bl_idname = 'particles.connect' - bl_label = 'Connect Particles' - bl_description = 'Create a continuous animated curve from particles in active system' + try: + Btrace = context.window_manager.curve_tracer + particle_step = Btrace.particle_step # step size in frames + obj = bpy.context.object + ps = obj.particle_systems.active + curvelist = [] + curve_handle = Btrace.curve_handle + check_materials = True + + if curve_handle == 'AUTOMATIC': # hackish naming conflict + curve_handle = 'AUTO' + if curve_handle == 'FREE_ALIGN': # hackish naming conflict + curve_handle = 'FREE' + + # Check if Btrace group exists, if not create + bgroup = bpy.data.groups.keys() + if 'Btrace' not in bgroup: + bpy.ops.group.create(name="Btrace") + + if Btrace.curve_join: + tracer = curvetracer('Tracer', 'Splines') + for x in ps.particles: + if not Btrace.curve_join: + tracer = curvetracer('Tracer.000', 'Spline.000') + spline = tracer[0].splines.new('BEZIER') + # add point to spline based on step size + spline.bezier_points.add((x.lifetime - 1) // particle_step) + for t in list(range(int(x.lifetime))): + bpy.context.scene.frame_set(t + x.birth_time) + if not t % particle_step: + p = spline.bezier_points[t // particle_step] + p.co = x.location + p.handle_right_type = curve_handle + p.handle_left_type = curve_handle + particlecurve = tracer[1] + curvelist.append(particlecurve) + # add to group + bpy.ops.object.select_all(action='DESELECT') + for curveobject in curvelist: + curveobject.select = True + bpy.context.scene.objects.active = curveobject + bpy.ops.object.group_link(group="Btrace") + # Materials + trace_mats = addtracemat(curveobject.data) + if not trace_mats and check_materials is True: + check_materials = False + + if Btrace.animate: + bpy.ops.curve.btgrow() # Add grow curve + + if check_materials is False: + self.report({'WARNING'}, "Some Materials could not be added") + + return {'FINISHED'} + + except Exception as e: + error_handlers(self, "particles.particletrace", e, + "Particle Trace could not be completed") + + return {'CANCELLED'} + + +# Particle Connect +# connect all particles in active system with a continuous animated curve + +class OBJECT_OT_traceallparticles(Operator): + bl_idname = "particles.connect" + bl_label = "Connect Particles" + bl_description = ("Create a continuous animated curve from particles in active system\n" + "Needs an Object with a particle system attached") bl_options = {'REGISTER', 'UNDO'} @classmethod def poll(cls, context): - return (bpy.context.object and bpy.context.object.particle_systems) + return (context.object is not None and + context.object.particle_systems) def execute(self, context): + try: + obj = context.object + ps = obj.particle_systems.active + setting = ps.settings + + # Grids distribution not supported + if setting.distribution == 'GRID': + self.report({'INFO'}, + "Grid distribution mode for particles not supported") + return{'CANCELLED'} + + Btrace = context.window_manager.curve_tracer + # Get frame start + particle_f_start = Btrace.particle_f_start + # Get frame end + particle_f_end = Btrace.particle_f_end + curve_handle = Btrace.curve_handle + # hackish because of naming conflict in api + if curve_handle == 'AUTOMATIC': + curve_handle = 'AUTO' + if curve_handle == 'FREE_ALIGN': + curve_handle = 'FREE' + + # define what kind of object to create + tracer = bpy.data.curves.new('Splines', 'CURVE') + # Create new object with settings listed above + curve = bpy.data.objects.new('Tracer', tracer) + # Link newly created object to the scene + bpy.context.scene.objects.link(curve) + # add a new Bezier point in the new curve + spline = tracer.splines.new('BEZIER') + spline.bezier_points.add(setting.count - 1) - obj = bpy.context.object - ps = obj.particle_systems.active - set = ps.settings + tracer.dimensions = '3D' + tracer.resolution_u = Btrace.curve_u + tracer.bevel_resolution = Btrace.curve_resolution + tracer.fill_mode = 'FULL' + tracer.bevel_depth = Btrace.curve_depth + + if Btrace.particle_auto: + f_start = int(setting.frame_start) + f_end = int(setting.frame_end + setting.lifetime) + else: + if particle_f_end <= particle_f_start: + particle_f_end = particle_f_start + 1 + f_start = particle_f_start + f_end = particle_f_end + + for bFrames in range(f_start, f_end): + bpy.context.scene.frame_set(bFrames) + if not (bFrames - f_start) % Btrace.particle_step: + for bFrames in range(setting.count): + if ps.particles[bFrames].alive_state != 'UNBORN': + e = bFrames + bp = spline.bezier_points[bFrames] + pt = ps.particles[e] + bp.co = pt.location + bp.handle_right_type = curve_handle + bp.handle_left_type = curve_handle + bp.keyframe_insert('co') + bp.keyframe_insert('handle_left') + bp.keyframe_insert('handle_right') + # Select new curve + bpy.ops.object.select_all(action='DESELECT') + curve.select = True + bpy.context.scene.objects.active = curve + + # Materials + trace_mats = addtracemat(curve.data) + if not trace_mats: + self.report({'WARNING'}, "Some Materials could not be added") + + if Btrace.animate: + bpy.ops.curve.btgrow() - # Grids distribution not supported - if set.distribution == 'GRID': - self.report({'INFO'},"Grid distribution mode for particles not supported.") return{'FINISHED'} - Btrace = bpy.context.window_manager.curve_tracer - particle_f_start = Btrace.particle_f_start # Get frame start - particle_f_end = Btrace.particle_f_end # Get frame end - curve_handle = Btrace.curve_handle - if curve_handle == 'AUTOMATIC': # hackish because of naming conflict in api - curve_handle = 'AUTO' - if curve_handle == 'FREE_ALIGN': - curve_handle = 'FREE' - tracer = bpy.data.curves.new('Splines','CURVE') # define what kind of object to create - curve = bpy.data.objects.new('Tracer',tracer) # Create new object with settings listed above - bpy.context.scene.objects.link(curve) # Link newly created object to the scene - spline = tracer.splines.new('BEZIER') # add a new Bezier point in the new curve - spline.bezier_points.add(set.count-1) - - tracer.dimensions = '3D' - tracer.resolution_u = Btrace.curve_u - tracer.bevel_resolution = Btrace.curve_resolution - tracer.fill_mode = 'FULL' - tracer.bevel_depth = Btrace.curve_depth - - if Btrace.particle_auto: - f_start = int(set.frame_start) - f_end = int(set.frame_end + set.lifetime) - else: - if particle_f_end <= particle_f_start: - particle_f_end = particle_f_start + 1 - f_start = particle_f_start - f_end = particle_f_end - - for bFrames in range(f_start, f_end): - bpy.context.scene.frame_set(bFrames) - if not (bFrames-f_start) % Btrace.particle_step: - for bFrames in range(set.count): - if ps.particles[bFrames].alive_state != 'UNBORN': - e = bFrames - bp = spline.bezier_points[bFrames] - pt = ps.particles[e] - bp.co = pt.location - #bp.handle_left = pt.location - #bp.handle_right = pt.location - bp.handle_right_type = curve_handle - bp.handle_left_type = curve_handle - bp.keyframe_insert('co') - bp.keyframe_insert('handle_left') - bp.keyframe_insert('handle_right') - # Select new curve - bpy.ops.object.select_all(action='DESELECT') - curve.select = True - bpy.context.scene.objects.active = curve - addtracemat(curve.data) #Add material - if Btrace.animate: - bpy.ops.curve.btgrow() - return{'FINISHED'} - -################## ################## ################## ############ -## Writing Tool -## Writes a curve by animating its point's radii -## -################## ################## ################## ############ -class OBJECT_OT_writing(bpy.types.Operator): - bl_idname = 'curve.btwriting' - bl_label = 'Write' - bl_description = 'Use Grease Pencil to write and convert to curves' + except Exception as e: + error_handlers(self, "particles.connect", e, + "Connect Particles could not be completed") + + return {'CANCELLED'} + + +# Writing Tool +# Writes a curve by animating its point's radii + +class OBJECT_OT_writing(Operator): + bl_idname = "curve.btwriting" + bl_label = "Write" + bl_description = ("Use Grease Pencil to write and convert to curves\n" + "Needs an existing Grease Pencil layer attached to the Scene") bl_options = {'REGISTER', 'UNDO'} - # @classmethod ### Removed so panel still draws if nothing is selected - # def poll(cls, context): - # return (context.scene.grease_pencil or context.object.grease_pencil != None) + @classmethod + def poll(cls, context): + gp = context.scene.grease_pencil + return gp and gp.layers def execute(self, context): - Btrace = bpy.context.window_manager.curve_tracer - obj = bpy.context.object - gactive = bpy.context.active_object # set selected object before convert - bpy.ops.gpencil.convert(type='CURVE') - gactiveCurve = bpy.context.active_object # get curve after convert - # render ready curve - gactiveCurve.data.resolution_u = Btrace.curve_u - gactiveCurve.data.bevel_resolution = Btrace.curve_resolution # Set bevel resolution from Panel options - gactiveCurve.data.fill_mode = 'FULL' - gactiveCurve.data.bevel_depth = Btrace.curve_depth # Set bevel depth from Panel options - - writeObj = bpy.context.selected_objects - if Btrace.animate: - for i in writeObj: - bpy.context.scene.objects.active = i - bpy.ops.curve.btgrow() - addtracemat(bpy.context.object.data) #Add material - else: - for i in writeObj: - bpy.context.scene.objects.active = i - addtracemat(bpy.context.object.data) #Add material - - # Delete grease pencil strokes - bpy.context.scene.objects.active = gactive - bpy.ops.gpencil.data_unlink() - bpy.context.scene.objects.active = gactiveCurve - # Smooth object - bpy.ops.object.shade_smooth() - # Return to first frame - bpy.context.scene.frame_set(Btrace.anim_f_start) - - return{'FINISHED'} - -################## ################## ################## ############ -## Create Curve -## Convert mesh to curve using either Continuous, All Edges, or Sharp Edges -## Option to create noise -################## ################## ################## ############ - -class OBJECT_OT_convertcurve(bpy.types.Operator): + try: + # first check if the Grease Pencil is attached to the Scene + tool_settings = context.scene.tool_settings + source_data = tool_settings.grease_pencil_source + if source_data in {"OBJECT"}: + self.report({'WARNING'}, + "Operation Cancelled. " + "The Grease Pencil data-block is attached to an Object") + return {"CANCELLED"} + + Btrace = context.window_manager.curve_tracer + # this is hacky - store objects in the scene for comparison later + store_objects = [ob for ob in context.scene.objects] + + gactive = context.active_object + # checking if there are any strokes the easy way + if not bpy.ops.gpencil.convert.poll(): + self.report({'WARNING'}, + "Operation Cancelled. " + "Are there any Grease Pencil Strokes ?") + return {'CANCELLED'} + + bpy.ops.gpencil.convert(type='CURVE') + # get curve after convert (compare the scenes to get the difference) + scene_obj = context.scene.objects + check_materials = True + + for obj in scene_obj: + if obj not in store_objects and obj.type == "CURVE": + gactiveCurve = obj + break + + # render ready curve + gactiveCurve.data.resolution_u = Btrace.curve_u + # Set bevel resolution from Panel options + gactiveCurve.data.bevel_resolution = Btrace.curve_resolution + gactiveCurve.data.fill_mode = 'FULL' + # Set bevel depth from Panel options + gactiveCurve.data.bevel_depth = Btrace.curve_depth + + writeObj = context.selected_objects + if Btrace.animate: + for i in writeObj: + context.scene.objects.active = i + bpy.ops.curve.btgrow() + # Materials + trace_mats = addtracemat(bpy.context.object.data) + if not trace_mats and check_materials is True: + check_materials = False + else: + for i in writeObj: + context.scene.objects.active = i + # Materials + trace_mats = addtracemat(bpy.context.object.data) + if not trace_mats and check_materials is True: + check_materials = False + + # Delete grease pencil strokes + context.scene.objects.active = gactive + bpy.ops.gpencil.data_unlink() + context.scene.objects.active = gactiveCurve + # Smooth object + bpy.ops.object.shade_smooth() + # Return to first frame + bpy.context.scene.frame_set(Btrace.anim_f_start) + + if check_materials is False: + self.report({'WARNING'}, "Some Materials could not be added") + + return{'FINISHED'} + + except Exception as e: + error_handlers(self, "curve.btwriting", e, + "Grease Pencil conversion could not be completed") + + return {'CANCELLED'} + + +# Create Curve +# Convert mesh to curve using either Continuous, All Edges, or Sharp Edges +# Option to create noise + +class OBJECT_OT_convertcurve(Operator): bl_idname = "object.btconvertcurve" bl_label = "Btrace: Create Curve" - bl_description = "Convert mesh to curve using either Continuous, All Edges, or Sharp Edges" + bl_description = ("Convert Mesh to Curve using either Continuous, " + "All Edges or Sharp Edges\n" + "Active Object has to be of a Mesh or Font type") bl_options = {'REGISTER', 'UNDO'} - def execute(self, context): - import bpy, random, mathutils - from mathutils import Vector - - Btrace = bpy.context.window_manager.curve_tracer - traceobjects = bpy.context.selected_objects # create a list with all the selected objects + @classmethod + def poll(cls, context): + return (context.object is not None and + context.object.type in {"MESH", "FONT"}) - obj = bpy.context.object + def execute(self, context): + try: + Btrace = context.window_manager.curve_tracer + obj = context.object - ### Convert Font - if obj.type == 'FONT': - bpy.ops.object.mode_set(mode='OBJECT') - bpy.ops.object.convert(target='CURVE') # Convert edges to curve - bpy.context.object.data.dimensions = '3D' + # Convert Font + if obj.type == 'FONT': + bpy.ops.object.mode_set(mode='OBJECT') + bpy.ops.object.convert(target='CURVE') # Convert edges to curve + bpy.context.object.data.dimensions = '3D' - # make a continuous edge through all vertices - if obj.type == 'MESH': - # Add noise to mesh - if Btrace.distort_curve: - for v in obj.data.vertices: - for u in range(3): - v.co[u] += Btrace.distort_noise * (random.uniform(-1,1)) + # make a continuous edge through all vertices + if obj.type == 'MESH': + # Add noise to mesh + if Btrace.distort_curve: + for v in obj.data.vertices: + for u in range(3): + v.co[u] += Btrace.distort_noise * (rand_uniform(-1, 1)) - if Btrace.convert_edgetype == 'CONTI': - ## Start Continuous edge - bpy.ops.object.mode_set(mode='EDIT') - bpy.ops.mesh.select_all(action='SELECT') - bpy.ops.mesh.delete(type='EDGE_FACE') - bpy.ops.mesh.select_all(action='DESELECT') - verts = bpy.context.object.data.vertices - bpy.ops.object.mode_set(mode='OBJECT') - li = [] - p1 = random.randint(0,len(verts)-1) - - for v in verts: - li.append(v.index) - li.remove(p1) - for z in range(len(li)): - x = [] - for px in li: - d = verts[p1].co - verts[px].co # find distance from first vert - x.append(d.length) - p2 = li[x.index(min(x))] # find the shortest distance list index - verts[p1].select = verts[p2].select = True + if Btrace.convert_edgetype == 'CONTI': + # Start Continuous edge bpy.ops.object.mode_set(mode='EDIT') - bpy.context.tool_settings.mesh_select_mode = [True, False, False] - bpy.ops.mesh.edge_face_add() + bpy.ops.mesh.select_all(action='SELECT') + bpy.ops.mesh.delete(type='EDGE_FACE') bpy.ops.mesh.select_all(action='DESELECT') + verts = bpy.context.object.data.vertices bpy.ops.object.mode_set(mode='OBJECT') - # verts[p1].select = verts[p2].select = False #Doesn't work after Bmesh merge - li.remove(p2) # remove item from list. - p1 = p2 - # Convert edges to curve - bpy.ops.object.mode_set(mode='OBJECT') - bpy.ops.object.convert(target='CURVE') + li = [] + p1 = rand_randint(0, len(verts) - 1) + + for v in verts: + li.append(v.index) + li.remove(p1) + for z in range(len(li)): + x = [] + for px in li: + d = verts[p1].co - verts[px].co # find distance from first vert + x.append(d.length) + p2 = li[x.index(min(x))] # find the shortest distance list index + verts[p1].select = verts[p2].select = True + bpy.ops.object.mode_set(mode='EDIT') + bpy.context.tool_settings.mesh_select_mode = [True, False, False] + bpy.ops.mesh.edge_face_add() + bpy.ops.mesh.select_all(action='DESELECT') + bpy.ops.object.mode_set(mode='OBJECT') + li.remove(p2) # remove item from list. + p1 = p2 + # Convert edges to curve + bpy.ops.object.mode_set(mode='OBJECT') + bpy.ops.object.convert(target='CURVE') - if Btrace.convert_edgetype == 'EDGEALL': - ## Start All edges - bpy.ops.object.mode_set(mode='EDIT') - bpy.ops.mesh.select_all(action='SELECT') - bpy.ops.mesh.delete(type='ONLY_FACE') - bpy.ops.object.mode_set() - bpy.ops.object.convert(target='CURVE') - for sp in obj.data.splines: - sp.type = Btrace.curve_spline - - obj = bpy.context.object - # Set spline type to custom property in panel - bpy.ops.object.editmode_toggle() - bpy.ops.curve.spline_type_set(type=Btrace.curve_spline) - # Set handle type to custom property in panel - bpy.ops.curve.handle_type_set(type=Btrace.curve_handle) - bpy.ops.object.editmode_toggle() - obj.data.fill_mode = 'FULL' - # Set resolution to custom property in panel - obj.data.bevel_resolution = Btrace.curve_resolution - obj.data.resolution_u = Btrace.curve_u - # Set depth to custom property in panel - obj.data.bevel_depth = Btrace.curve_depth - # Smooth object - bpy.ops.object.shade_smooth() - # Modulate curve radius and add distortion - if Btrace.distort_curve: - scale = Btrace.distort_modscale - if scale == 0: - return {'FINISHED'} - for u in obj.data.splines: - for v in u.bezier_points: - v.radius = scale*round(random.random(),3) - return {'FINISHED'} - - -################## ################## ################## ############ -## Mesh Follow, trace vertex or faces -## Create curve at center of selection item, extruded along animation -## Needs to be animated mesh!!! -################## ################## ################## ############ - -class OBJECT_OT_meshfollow(bpy.types.Operator): + if Btrace.convert_edgetype == 'EDGEALL': + # Start All edges + bpy.ops.object.mode_set(mode='EDIT') + bpy.ops.mesh.select_all(action='SELECT') + bpy.ops.mesh.delete(type='ONLY_FACE') + bpy.ops.object.mode_set() + bpy.ops.object.convert(target='CURVE') + for sp in obj.data.splines: + sp.type = Btrace.curve_spline + + obj = context.object + # Set spline type to custom property in panel + bpy.ops.object.editmode_toggle() + bpy.ops.curve.spline_type_set(type=Btrace.curve_spline) + # Set handle type to custom property in panel + bpy.ops.curve.handle_type_set(type=Btrace.curve_handle) + bpy.ops.object.editmode_toggle() + obj.data.fill_mode = 'FULL' + # Set resolution to custom property in panel + obj.data.bevel_resolution = Btrace.curve_resolution + obj.data.resolution_u = Btrace.curve_u + # Set depth to custom property in panel + obj.data.bevel_depth = Btrace.curve_depth + # Smooth object + bpy.ops.object.shade_smooth() + # Modulate curve radius and add distortion + if Btrace.distort_curve: + scale = Btrace.distort_modscale + if scale == 0: + return {'FINISHED'} + for u in obj.data.splines: + for v in u.bezier_points: + v.radius = scale * round(rand_random(), 3) + + return {'FINISHED'} + + except Exception as e: + error_handlers(self, "object.btconvertcurve", e, + "Conversion could not be completed") + + return {'CANCELLED'} + + +# Mesh Follow, trace vertex or faces +# Create curve at center of selection item, extruded along animation +# Needs to be an animated mesh!!! + +class OBJECT_OT_meshfollow(Operator): bl_idname = "object.btmeshfollow" bl_label = "Btrace: Vertex Trace" bl_description = "Trace Vertex or Face on an animated mesh" bl_options = {'REGISTER', 'UNDO'} - @classmethod def poll(cls, context): return (context.object and context.object.type in {'MESH'}) def execute(self, context): - import bpy, random - from mathutils import Vector - - Btrace = bpy.context.window_manager.curve_tracer - distort_curve = Btrace.distort_curve # modulate the resulting curve - stepsize = Btrace.particle_step - traceobjects = bpy.context.selected_objects # create a list with all the selected objects - - obj = bpy.context.object - scn = bpy.context.scene - meshdata = obj.data - cursor = bpy.context.scene.cursor_location.copy() # Store the location to restore at end of script - drawmethod = Btrace.fol_mesh_type # Draw from Edges, Verts, or Faces - if drawmethod == 'VERTS': - meshobjs = obj.data.vertices - if drawmethod == 'FACES': - meshobjs = obj.data.polygons # untested - if drawmethod == 'EDGES': - meshobjs = obj.data.edges # untested - - # Frame properties - start_frame, end_frame = Btrace.fol_start_frame, Btrace.fol_end_frame - if start_frame > end_frame: # Make sure the math works - startframe = end_frame - 5 # if start past end, goto (end - 5) - frames = int((end_frame - start_frame) / stepsize) - - def getsel_option(): # Get selection objects. - sel = [] - seloption, fol_mesh_type = Btrace.fol_sel_option, Btrace.fol_mesh_type # options = 'random', 'custom', 'all' - if fol_mesh_type == 'OBJECT': - pass - else: - if seloption == 'CUSTOM': - for i in meshobjs: - if i.select == True: + try: + Btrace = context.window_manager.curve_tracer + stepsize = Btrace.particle_step + + obj = context.object + scn = context.scene + drawmethod = Btrace.fol_mesh_type # Draw from Edges, Verts, or Faces + + if drawmethod == 'VERTS': + meshobjs = obj.data.vertices + if drawmethod == 'FACES': + meshobjs = obj.data.polygons # untested + if drawmethod == 'EDGES': + meshobjs = obj.data.edges # untested + + # Frame properties + start_frame, end_frame = Btrace.fol_start_frame, Btrace.fol_end_frame + if start_frame > end_frame: # Make sure the math works + start_frame = end_frame - 5 # if start past end, goto (end - 5) + frames = int((end_frame - start_frame) / stepsize) + + def getsel_option(): # Get selection objects + sel = [] + # options are 'random', 'custom', 'all' + seloption, fol_mesh_type = Btrace.fol_sel_option, Btrace.fol_mesh_type + if fol_mesh_type == 'OBJECT': + pass + else: + if seloption == 'CUSTOM': + for i in meshobjs: + if i.select is True: + sel.append(i.index) + if seloption == 'RANDOM': + for i in list(meshobjs): + sel.append(i.index) + finalsel = int(len(sel) * Btrace.fol_perc_verts) + remove = len(sel) - finalsel + for i in range(remove): + sel.pop(rand_randint(0, len(sel) - 1)) + if seloption == 'ALL': + for i in list(meshobjs): sel.append(i.index) - if seloption == 'RANDOM': - for i in list(meshobjs): - sel.append(i.index) - finalsel = int(len(sel) * Btrace.fol_perc_verts) - remove = len(sel) - finalsel - for i in range(remove): - sel.pop(random.randint(0, len(sel) - 1)) - if seloption == 'ALL': - for i in list(meshobjs): - sel.append(i.index) - - return sel - - def get_coord(objindex): - obj_co = [] # list of vector coordinates to use - frame_x = start_frame - for i in range(frames): # create frame numbers list - scn.frame_set(frame_x) - if drawmethod != 'OBJECT': - followed_item = meshobjs[objindex] - if drawmethod == 'VERTS': - g_co = obj.matrix_local * followed_item.co # find Vert vector - - if drawmethod == 'FACES': - g_co = obj.matrix_local * followed_item.normal # find Face vector - - if drawmethod == 'EDGES': - v1 = followed_item.vertices[0] - v2 = followed_item.vertices[1] - co1 = bpy.context.object.data.vertices[v1] - co2 = bpy.context.object.data.vertices[v2] - localcenter = co1.co.lerp(co2.co, 0.5) - g_co = obj.matrix_world * localcenter - - if drawmethod == 'OBJECT': - g_co = objindex.location.copy() - - obj_co.append(g_co) - frame_x = frame_x + stepsize - - scn.frame_set(start_frame) - return obj_co - - def make_curve(co_list): - Btrace = bpy.context.window_manager.curve_tracer - tracer = bpy.data.curves.new('tracer','CURVE') - tracer.dimensions = '3D' - spline = tracer.splines.new('BEZIER') - spline.bezier_points.add(len(co_list)- 1) - curve = bpy.data.objects.new('curve',tracer) - scn.objects.link(curve) - curvelist.append(curve) - # render ready curve - tracer.resolution_u = Btrace.curve_u - tracer.bevel_resolution = Btrace.curve_resolution # Set bevel resolution from Panel options - tracer.fill_mode = 'FULL' - tracer.bevel_depth = Btrace.curve_depth # Set bevel depth from Panel options - curve_handle = Btrace.curve_handle - if curve_handle == 'AUTOMATIC': # hackish AUTOMATIC doesn't work here - curve_handle = 'AUTO' - - # move bezier points to objects - for i in range(len(co_list)): - p = spline.bezier_points[i] - p.co = co_list[i] - p.handle_right_type = curve_handle - p.handle_left_type = curve_handle - return curve - - # Run methods - # Check if Btrace group exists, if not create - bgroup = bpy.data.groups.keys() - if 'Btrace' not in bgroup: - bpy.ops.group.create(name="Btrace") - - Btrace = bpy.context.window_manager.curve_tracer - sel = getsel_option() # Get selection - curvelist = [] # list to use for grow curve - - if Btrace.fol_mesh_type == 'OBJECT': - vector_list = get_coord(obj) - curvelist.append(make_curve(vector_list)) - else: - for i in sel: - vector_list = get_coord(i) - curvelist.append(make_curve(vector_list)) - # Select new curves and add to group - bpy.ops.object.select_all(action='DESELECT') - for curveobject in curvelist: - if curveobject.type == 'CURVE': - curveobject.select = True - bpy.context.scene.objects.active = curveobject - bpy.ops.object.group_link(group="Btrace") - addtracemat(curveobject.data) - curveobject.select = False - if Btrace.animate: # Add grow curve - for curveobject in curvelist: - curveobject.select = True - bpy.ops.curve.btgrow() - for curveobject in curvelist: - curveobject.select = False + return sel + + def get_coord(objindex): + obj_co = [] # list of vector coordinates to use + frame_x = start_frame + for i in range(frames): # create frame numbers list + scn.frame_set(frame_x) + if drawmethod != 'OBJECT': + followed_item = meshobjs[objindex] + if drawmethod == 'VERTS': + # find Vert vector + g_co = obj.matrix_local * followed_item.co + + if drawmethod == 'FACES': + # find Face vector + g_co = obj.matrix_local * followed_item.normal + + if drawmethod == 'EDGES': + v1 = followed_item.vertices[0] + v2 = followed_item.vertices[1] + co1 = bpy.context.object.data.vertices[v1] + co2 = bpy.context.object.data.vertices[v2] + localcenter = co1.co.lerp(co2.co, 0.5) + g_co = obj.matrix_world * localcenter + + if drawmethod == 'OBJECT': + g_co = objindex.location.copy() + + obj_co.append(g_co) + frame_x = frame_x + stepsize + + scn.frame_set(start_frame) + return obj_co + + def make_curve(co_list): + Btrace = bpy.context.window_manager.curve_tracer + tracer = bpy.data.curves.new('tracer', 'CURVE') + tracer.dimensions = '3D' + spline = tracer.splines.new('BEZIER') + spline.bezier_points.add(len(co_list) - 1) + curve = bpy.data.objects.new('curve', tracer) + scn.objects.link(curve) + curvelist.append(curve) + # render ready curve + tracer.resolution_u = Btrace.curve_u + # Set bevel resolution from Panel options + tracer.bevel_resolution = Btrace.curve_resolution + tracer.fill_mode = 'FULL' + # Set bevel depth from Panel options + tracer.bevel_depth = Btrace.curve_depth + curve_handle = Btrace.curve_handle + + # hackish AUTOMATIC doesn't work here + if curve_handle == 'AUTOMATIC': + curve_handle = 'AUTO' + + # move bezier points to objects + for i in range(len(co_list)): + p = spline.bezier_points[i] + p.co = co_list[i] + p.handle_right_type = curve_handle + p.handle_left_type = curve_handle + return curve - obj.select = False # Deselect original object - return {'FINISHED'} + # Run methods + # Check if Btrace group exists, if not create + bgroup = bpy.data.groups.keys() + if 'Btrace' not in bgroup: + bpy.ops.group.create(name="Btrace") -################################################################### -#### Add Tracer Material -################################################################### + Btrace = bpy.context.window_manager.curve_tracer + sel = getsel_option() # Get selection + curvelist = [] # list to use for grow curve + check_materials = True -def addtracemat(matobj): - matslots = bpy.context.object.data.materials.items() # Check if a material exists, skip if it does - if len(matslots) < 1: # Make sure there is only one material slot - engine = bpy.context.scene.render.engine - Btrace = bpy.context.window_manager.curve_tracer - if not Btrace.mat_run_color_blender: # Check if color blender is to be run - if Btrace.trace_mat_random: # Create Random color for each item - # Use random color from chosen palette, assign color lists for each palette - import random - brightColors = [Btrace.brightColor1, Btrace.brightColor2, Btrace.brightColor3, Btrace.brightColor4] - bwColors = [Btrace.bwColor1, Btrace.bwColor2] - customColors = [Btrace.mmColor1, Btrace.mmColor2, Btrace.mmColor3, Btrace.mmColor4, Btrace.mmColor5, Btrace.mmColor6, Btrace.mmColor7, Btrace.mmColor8] - earthColors = [Btrace.earthColor1, Btrace.earthColor2, Btrace.earthColor3, Btrace.earthColor4, Btrace.earthColor5] - greenblueColors = [Btrace.greenblueColor1, Btrace.greenblueColor2, Btrace.greenblueColor3] - if Btrace.mmColors == 'BRIGHT': - #print(random.randint(0, len(brightColors) - 1)) - mat_color = brightColors[random.randint(0, len(brightColors) - 1)] - if Btrace.mmColors == 'BW': - mat_color = bwColors[random.randint(0, len(bwColors) - 1)] - if Btrace.mmColors == 'CUSTOM': - mat_color = customColors[random.randint(0, len(customColors) - 1)] - if Btrace.mmColors == 'EARTH': - mat_color = earthColors[random.randint(0, len(earthColors) - 1)] - if Btrace.mmColors == 'GREENBLUE': - mat_color = greenblueColors[random.randint(0, len(greenblueColors) - 1)] - if Btrace.mmColors == 'RANDOM': - mat_color = (random.random(), random.random(), random.random()) - else: # Choose Single color - mat_color = Btrace.trace_mat_color - # mat_color = Btrace.trace_mat_color - TraceMat = bpy.data.materials.new('TraceMat') - # add cycles or BI render material options - if engine == 'CYCLES': - TraceMat.use_nodes = True - Diffuse_BSDF = TraceMat.node_tree.nodes['Diffuse BSDF'] - r, g, b = mat_color[0], mat_color[1], mat_color[2] - Diffuse_BSDF.inputs[0].default_value = [r, g, b, 1] - TraceMat.diffuse_color = mat_color + if Btrace.fol_mesh_type == 'OBJECT': + vector_list = get_coord(obj) + curvelist.append(make_curve(vector_list)) else: - TraceMat.diffuse_color = mat_color - TraceMat.specular_intensity = 0.5 - # Add material to object - matobj.materials.append(bpy.data.materials.get(TraceMat.name)) - - else: # Run color blender operator - bpy.ops.object.colorblender() + for i in sel: + vector_list = get_coord(i) + curvelist.append(make_curve(vector_list)) + # Select new curves and add to group + bpy.ops.object.select_all(action='DESELECT') + for curveobject in curvelist: + if curveobject.type == 'CURVE': + curveobject.select = True + context.scene.objects.active = curveobject + bpy.ops.object.group_link(group="Btrace") + # Materials + trace_mats = addtracemat(curveobject.data) + if not trace_mats and check_materials is True: + check_materials = False + + curveobject.select = False + + if Btrace.animate: # Add grow curve + for curveobject in curvelist: + curveobject.select = True + bpy.ops.curve.btgrow() + for curveobject in curvelist: + curveobject.select = False - return {'FINISHED'} + obj.select = False # Deselect original object -################################################################### -#### Add Color Blender Material -################################################################### + if check_materials is False: + self.report({'WARNING'}, "Some Materials could not be added") -# This is the magical material changer! -class OBJECT_OT_materialChango(bpy.types.Operator): - bl_idname = 'object.colorblender' - bl_label = 'Color Blender' - bl_options = {'REGISTER', 'UNDO'} + return {'FINISHED'} - def execute(self, context): + except Exception as e: + error_handlers(self, "object.btmeshfollow", e, + "Vertex Trace could not be completed") - import bpy, random - Btrace = bpy.context.window_manager.curve_tracer # properties panel - colorObjects = bpy.context.selected_objects - - # Set color lists - brightColors = [Btrace.brightColor1, Btrace.brightColor2, Btrace.brightColor3, Btrace.brightColor4] - bwColors = [Btrace.bwColor1, Btrace.bwColor2] - customColors = [Btrace.mmColor1, Btrace.mmColor2, Btrace.mmColor3, Btrace.mmColor4, Btrace.mmColor5, Btrace.mmColor6, Btrace.mmColor7, Btrace.mmColor8] - earthColors = [Btrace.earthColor1, Btrace.earthColor2, Btrace.earthColor3, Btrace.earthColor4, Btrace.earthColor5] - greenblueColors = [Btrace.greenblueColor1, Btrace.greenblueColor2, Btrace.greenblueColor3] - - colorList = Btrace.mmColors - engine = bpy.context.scene.render.engine - - # Go through each selected object and run the operator - for i in colorObjects: - theObj = i - # Check to see if object has materials - checkMaterials = len(theObj.data.materials) - if engine == 'CYCLES': - materialName = "colorblendMaterial" - madMat = bpy.data.materials.new(materialName) - madMat.use_nodes = True - if checkMaterials == 0: - theObj.data.materials.append(madMat) - else: - theObj.material_slots[0].material = madMat - else: # This is internal - if checkMaterials == 0: - # Add a material - materialName = "colorblendMaterial" - madMat = bpy.data.materials.new(materialName) - theObj.data.materials.append(madMat) - else: - pass # pass since we have what we need - # assign the first material of the object to "mat" - madMat = theObj.data.materials[0] + return {'CANCELLED'} - # Numbers of frames to skip between keyframes - skip = Btrace.mmSkip +# Add Tracer Material +def addtracemat(matobj): + try: + # Check if a material exists, skip if it does + matslots = bpy.context.object.data.materials.items() + if len(matslots) < 1: # Make sure there is only one material slot + engine = bpy.context.scene.render.engine + Btrace = bpy.context.window_manager.curve_tracer - # Random material function - def colorblenderRandom(): - randomRGB = (random.random(), random.random(), random.random()) - if engine == 'CYCLES': - Diffuse_BSDF = madMat.node_tree.nodes['Diffuse BSDF'] - mat_color = randomRGB - r, g, b = mat_color[0], mat_color[1], mat_color[2] - Diffuse_BSDF.inputs[0].default_value = [r, g, b, 1] - madMat.diffuse_color = mat_color + # Check if color blender is to be run + if not Btrace.mat_run_color_blender: + # Create Random color for each item + if Btrace.trace_mat_random: + # Use random color from chosen palette, + # assign color lists for each palette + brightColors = [ + Btrace.brightColor1, Btrace.brightColor2, + Btrace.brightColor3, Btrace.brightColor4 + ] + bwColors = [ + Btrace.bwColor1, Btrace.bwColor2 + ] + customColors = [ + Btrace.mmColor1, Btrace.mmColor2, Btrace.mmColor3, + Btrace.mmColor4, Btrace.mmColor5, Btrace.mmColor6, + Btrace.mmColor7, Btrace.mmColor8 + ] + earthColors = [ + Btrace.earthColor1, Btrace.earthColor2, + Btrace.earthColor3, Btrace.earthColor4, + Btrace.earthColor5 + ] + greenblueColors = [ + Btrace.greenblueColor1, Btrace.greenblueColor2, + Btrace.greenblueColor3 + ] + if Btrace.mmColors == 'BRIGHT': + mat_color = brightColors[ + rand_randint(0, len(brightColors) - 1) + ] + if Btrace.mmColors == 'BW': + mat_color = bwColors[ + rand_randint(0, len(bwColors) - 1) + ] + if Btrace.mmColors == 'CUSTOM': + mat_color = customColors[ + rand_randint(0, len(customColors) - 1) + ] + if Btrace.mmColors == 'EARTH': + mat_color = earthColors[ + rand_randint(0, len(earthColors) - 1) + ] + if Btrace.mmColors == 'GREENBLUE': + mat_color = greenblueColors[ + rand_randint(0, len(greenblueColors) - 1) + ] + if Btrace.mmColors == 'RANDOM': + mat_color = (rand_random(), rand_random(), rand_random()) else: - madMat.diffuse_color = randomRGB + # Choose Single color + mat_color = Btrace.trace_mat_color - def colorblenderCustom(): + TraceMat = bpy.data.materials.new('TraceMat') + # add cycles or BI render material options if engine == 'CYCLES': - Diffuse_BSDF = madMat.node_tree.nodes['Diffuse BSDF'] - mat_color = random.choice(customColors) + TraceMat.use_nodes = True + Diffuse_BSDF = TraceMat.node_tree.nodes['Diffuse BSDF'] r, g, b = mat_color[0], mat_color[1], mat_color[2] Diffuse_BSDF.inputs[0].default_value = [r, g, b, 1] - madMat.diffuse_color = mat_color + TraceMat.diffuse_color = mat_color else: - madMat.diffuse_color = random.choice(customColors) + TraceMat.diffuse_color = mat_color + TraceMat.specular_intensity = 0.5 + # Add material to object + matobj.materials.append(bpy.data.materials.get(TraceMat.name)) - # Black and white color - def colorblenderBW(): - if engine == 'CYCLES': - Diffuse_BSDF = madMat.node_tree.nodes['Diffuse BSDF'] - mat_color = random.choice(bwColors) - r, g, b = mat_color[0], mat_color[1], mat_color[2] - Diffuse_BSDF.inputs[0].default_value = [r, g, b, 1] - madMat.diffuse_color = mat_color - else: - madMat.diffuse_color = random.choice(bwColors) + else: + # Run color blender operator + bpy.ops.object.colorblender() - # Bright colors - def colorblenderBright(): - if engine == 'CYCLES': - Diffuse_BSDF = madMat.node_tree.nodes['Diffuse BSDF'] - mat_color = random.choice(brightColors) - r, g, b = mat_color[0], mat_color[1], mat_color[2] - Diffuse_BSDF.inputs[0].default_value = [r, g, b, 1] - madMat.diffuse_color = mat_color - else: - madMat.diffuse_color = random.choice(brightColors) + return True - # Earth Tones - def colorblenderEarth(): - if engine == 'CYCLES': - Diffuse_BSDF = madMat.node_tree.nodes['Diffuse BSDF'] - mat_color = random.choice(earthColors) - r, g, b = mat_color[0], mat_color[1], mat_color[2] - Diffuse_BSDF.inputs[0].default_value = [r, g, b, 1] - madMat.diffuse_color = mat_color - else: - madMat.diffuse_color = random.choice(earthColors) + except Exception as e: + error_handlers(False, "addtracemat", e, "Function error", True) - # Green to Blue Tones - def colorblenderGreenBlue(): - if engine == 'CYCLES': - Diffuse_BSDF = madMat.node_tree.nodes['Diffuse BSDF'] - mat_color = random.choice(greenblueColors) - r, g, b = mat_color[0], mat_color[1], mat_color[2] - Diffuse_BSDF.inputs[0].default_value = [r, g, b, 1] - madMat.diffuse_color = mat_color - else: - madMat.diffuse_color = random.choice(greenblueColors) - - # define frame start/end variables - scn = bpy.context.scene - start = scn.frame_start - end = scn.frame_end - # Go to each frame in iteration and add material - while start<=(end+(skip-1)): - - bpy.context.scene.frame_set(frame=start) - - # Check what colors setting is checked and run the appropriate function - if Btrace.mmColors=='RANDOM': - colorblenderRandom() - elif Btrace.mmColors=='CUSTOM': - colorblenderCustom() - elif Btrace.mmColors=='BW': - colorblenderBW() - elif Btrace.mmColors=='BRIGHT': - colorblenderBright() - elif Btrace.mmColors=='EARTH': - colorblenderEarth() - elif Btrace.mmColors=='GREENBLUE': - colorblenderGreenBlue() - else: - pass + return False + + +# Add Color Blender Material +# This is the magical material changer! +class OBJECT_OT_materialChango(Operator): + bl_idname = "object.colorblender" + bl_label = "Color Blender" + bl_options = {'REGISTER', 'UNDO'} - # Add keyframe to material + def execute(self, context): + try: + # properties panel + Btrace = context.window_manager.curve_tracer + colorObjects = context.selected_objects + + # Set color lists + brightColors = [ + Btrace.brightColor1, Btrace.brightColor2, + Btrace.brightColor3, Btrace.brightColor4 + ] + bwColors = [Btrace.bwColor1, Btrace.bwColor2] + customColors = [ + Btrace.mmColor1, Btrace.mmColor2, Btrace.mmColor3, + Btrace.mmColor4, Btrace.mmColor5, Btrace.mmColor6, + Btrace.mmColor7, Btrace.mmColor8 + ] + earthColors = [ + Btrace.earthColor1, Btrace.earthColor2, Btrace.earthColor3, + Btrace.earthColor4, Btrace.earthColor5 + ] + greenblueColors = [ + Btrace.greenblueColor1, Btrace.greenblueColor2, + Btrace.greenblueColor3 + ] + engine = context.scene.render.engine + + # Go through each selected object and run the operator + for i in colorObjects: + theObj = i + # Check to see if object has materials + checkMaterials = len(theObj.data.materials) if engine == 'CYCLES': - madMat.node_tree.nodes['Diffuse BSDF'].inputs[0].keyframe_insert('default_value') - madMat.keyframe_insert('diffuse_color') # not sure if this is need, it's viewport color only - else: - madMat.keyframe_insert('diffuse_color') + materialName = "colorblendMaterial" + madMat = bpy.data.materials.new(materialName) + madMat.use_nodes = True + if checkMaterials == 0: + theObj.data.materials.append(madMat) + else: + theObj.material_slots[0].material = madMat + else: # This is internal + if checkMaterials == 0: + # Add a material + materialName = "colorblendMaterial" + madMat = bpy.data.materials.new(materialName) + theObj.data.materials.append(madMat) + else: + pass # pass since we have what we need + # assign the first material of the object to "mat" + madMat = theObj.data.materials[0] + + # Numbers of frames to skip between keyframes + skip = Btrace.mmSkip + + # Random material function + def colorblenderRandom(): + randomRGB = (rand_random(), rand_random(), rand_random()) + if engine == 'CYCLES': + Diffuse_BSDF = madMat.node_tree.nodes['Diffuse BSDF'] + mat_color = randomRGB + r, g, b = mat_color[0], mat_color[1], mat_color[2] + Diffuse_BSDF.inputs[0].default_value = [r, g, b, 1] + madMat.diffuse_color = mat_color + else: + madMat.diffuse_color = randomRGB + + def colorblenderCustom(): + if engine == 'CYCLES': + Diffuse_BSDF = madMat.node_tree.nodes['Diffuse BSDF'] + mat_color = rand_choice(customColors) + r, g, b = mat_color[0], mat_color[1], mat_color[2] + Diffuse_BSDF.inputs[0].default_value = [r, g, b, 1] + madMat.diffuse_color = mat_color + else: + madMat.diffuse_color = rand_choice(customColors) + + # Black and white color + def colorblenderBW(): + if engine == 'CYCLES': + Diffuse_BSDF = madMat.node_tree.nodes['Diffuse BSDF'] + mat_color = rand_choice(bwColors) + r, g, b = mat_color[0], mat_color[1], mat_color[2] + Diffuse_BSDF.inputs[0].default_value = [r, g, b, 1] + madMat.diffuse_color = mat_color + else: + madMat.diffuse_color = rand_choice(bwColors) + + # Bright colors + def colorblenderBright(): + if engine == 'CYCLES': + Diffuse_BSDF = madMat.node_tree.nodes['Diffuse BSDF'] + mat_color = rand_choice(brightColors) + r, g, b = mat_color[0], mat_color[1], mat_color[2] + Diffuse_BSDF.inputs[0].default_value = [r, g, b, 1] + madMat.diffuse_color = mat_color + else: + madMat.diffuse_color = rand_choice(brightColors) + + # Earth Tones + def colorblenderEarth(): + if engine == 'CYCLES': + Diffuse_BSDF = madMat.node_tree.nodes['Diffuse BSDF'] + mat_color = rand_choice(earthColors) + r, g, b = mat_color[0], mat_color[1], mat_color[2] + Diffuse_BSDF.inputs[0].default_value = [r, g, b, 1] + madMat.diffuse_color = mat_color + else: + madMat.diffuse_color = rand_choice(earthColors) + + # Green to Blue Tones + def colorblenderGreenBlue(): + if engine == 'CYCLES': + Diffuse_BSDF = madMat.node_tree.nodes['Diffuse BSDF'] + mat_color = rand_choice(greenblueColors) + r, g, b = mat_color[0], mat_color[1], mat_color[2] + Diffuse_BSDF.inputs[0].default_value = [r, g, b, 1] + madMat.diffuse_color = mat_color + else: + madMat.diffuse_color = rand_choice(greenblueColors) + + # define frame start/end variables + scn = context.scene + start = scn.frame_start + end = scn.frame_end + + # Go to each frame in iteration and add material + while start <= (end + (skip - 1)): + bpy.context.scene.frame_set(frame=start) + + # Check what colors setting is checked and run the appropriate function + if Btrace.mmColors == 'RANDOM': + colorblenderRandom() + elif Btrace.mmColors == 'CUSTOM': + colorblenderCustom() + elif Btrace.mmColors == 'BW': + colorblenderBW() + elif Btrace.mmColors == 'BRIGHT': + colorblenderBright() + elif Btrace.mmColors == 'EARTH': + colorblenderEarth() + elif Btrace.mmColors == 'GREENBLUE': + colorblenderGreenBlue() + else: + pass + + # Add keyframe to material + if engine == 'CYCLES': + madMat.node_tree.nodes[ + 'Diffuse BSDF'].inputs[0].keyframe_insert('default_value') + # not sure if this is need, it's viewport color only + madMat.keyframe_insert('diffuse_color') + else: + madMat.keyframe_insert('diffuse_color') + + # Increase frame number + start += skip + + return{'FINISHED'} + + except Exception as e: + error_handlers(self, "object.colorblender", e, + "Color Blender could not be completed") + + return {'CANCELLED'} - # Increase frame number - start += skip - return{'FINISHED'} -###### This clears the keyframes ###### -class OBJECT_OT_clearColorblender(bpy.types.Operator): - bl_idname = 'object.colorblenderclear' - bl_label = 'Clear colorblendness' +# This clears the keyframes +class OBJECT_OT_clearColorblender(Operator): + bl_idname = "object.colorblenderclear" + bl_label = "Clear colorblendness" + bl_description = "Clear the color keyframes" bl_options = {'REGISTER', 'UNDO'} def invoke(self, context, event): + try: + colorObjects = context.selected_objects + engine = context.scene.render.engine - import bpy, random - mcolorblend = context.window_manager.colorblender_operator # properties panel - colorObjects = bpy.context.selected_objects - - # Go through each selected object and run the operator - for i in colorObjects: - theObj = i - # assign the first material of the object to "mat" - matCl = theObj.data.materials[0] + # Go through each selected object and run the operator + for i in colorObjects: + theObj = i + # assign the first material of the object to "mat" + matCl = theObj.data.materials[0] + + # define frame start/end variables + scn = context.scene + start = scn.frame_start + end = scn.frame_end + + # Remove all keyframes from diffuse_color, super sloppy + while start <= (end + 100): + context.scene.frame_set(frame=start) + try: + if engine == 'CYCLES': + matCl.node_tree.nodes[ + 'Diffuse BSDF'].inputs[0].keyframe_delete('default_value') + elif engine == 'BLENDER_RENDER': + matCl.keyframe_delete('diffuse_color') + except: + pass + start += 1 - # define frame start/end variables - scn = bpy.context.scene - start = scn.frame_start - end = scn.frame_end + return{'FINISHED'} - # Remove all keyframes from diffuse_color, super sloppy need to find better way - while start <= (end * 2): - bpy.context.scene.frame_set(frame=start) - matCl.keyframe_delete('diffuse_color') - start += 1 + except Exception as e: + error_handlers(self, "object.colorblenderclear", e, + "Reset Keyframes could not be completed") - return{'FINISHED'} + return {'CANCELLED'} -################## ################## ################## ############ -## F-Curve Noise -## will add noise modifiers to each selected object f-curves -## change type to: 'rotation' | 'location' | 'scale' | '' to effect all -## first record a keyframe for this to work (to generate the f-curves) -################## ################## ################## ############ +# F-Curve Noise +# will add noise modifiers to each selected object f-curves +# change type to: 'rotation' | 'location' | 'scale' | '' to effect all +# first record a keyframe for this to work (to generate the f-curves) -class OBJECT_OT_fcnoise(bpy.types.Operator): +class OBJECT_OT_fcnoise(Operator): bl_idname = "object.btfcnoise" bl_label = "Btrace: F-curve Noise" bl_options = {'REGISTER', 'UNDO'} def execute(self, context): - import bpy, random - - Btrace = bpy.context.window_manager.curve_tracer - amp = Btrace.fcnoise_amp - timescale = Btrace.fcnoise_timescale - addkeyframe = Btrace.fcnoise_key - - # This sets properties for Loc, Rot and Scale if they're checked in the Tools window - noise_rot = 'rotation' - noise_loc = 'location' - noise_scale = 'scale' - if not Btrace.fcnoise_rot: - noise_rot = 'none' - if not Btrace.fcnoise_loc: - noise_loc = 'none' - if not Btrace.fcnoise_scale: - noise_scale = 'none' - - type = noise_loc, noise_rot, noise_scale # Add settings from panel for type of keyframes - amplitude = amp - time_scale = timescale - - for i in bpy.context.selected_objects: - # Add keyframes, this is messy and should only add keyframes for what is checked - if addkeyframe == True: - bpy.ops.anim.keyframe_insert(type="LocRotScale") - for obj in bpy.context.selected_objects: - if obj.animation_data: - for c in obj.animation_data.action.fcurves: - if c.data_path.startswith(type): - # clean modifiers - for m in c.modifiers : - c.modifiers.remove(m) - # add noide modifiers - n = c.modifiers.new('NOISE') - n.strength = amplitude - n.scale = time_scale - n.phase = random.randint(0,999) - return {'FINISHED'} - -################## ################## ################## ############ -## Curve Grow Animation -## Animate curve radius over length of time -################## ################## ################## ############ -class OBJECT_OT_curvegrow(bpy.types.Operator): - bl_idname = 'curve.btgrow' - bl_label = 'Run Script' - bl_description = 'Keyframe points radius' + try: + Btrace = context.window_manager.curve_tracer + amp = Btrace.fcnoise_amp + timescale = Btrace.fcnoise_timescale + addkeyframe = Btrace.fcnoise_key + + # This sets properties for Loc, Rot and Scale + # if they're checked in the Tools window + noise_rot = 'rotation' + noise_loc = 'location' + noise_scale = 'scale' + if not Btrace.fcnoise_rot: + noise_rot = 'none' + if not Btrace.fcnoise_loc: + noise_loc = 'none' + if not Btrace.fcnoise_scale: + noise_scale = 'none' + + # Add settings from panel for type of keyframes + types = noise_loc, noise_rot, noise_scale + amplitude = amp + time_scale = timescale + + for i in context.selected_objects: + # Add keyframes, this is messy and should only + # add keyframes for what is checked + if addkeyframe is True: + bpy.ops.anim.keyframe_insert(type="LocRotScale") + for obj in context.selected_objects: + if obj.animation_data: + for c in obj.animation_data.action.fcurves: + if c.data_path.startswith(types): + # clean modifiers + for m in c.modifiers: + c.modifiers.remove(m) + # add noide modifiers + n = c.modifiers.new('NOISE') + n.strength = amplitude + n.scale = time_scale + n.phase = rand_randint(0, 999) + + return {'FINISHED'} + + except Exception as e: + error_handlers(self, "object.btfcnoise", e, + "F-curve Noise could not be completed") + + return {'CANCELLED'} + + +# Curve Grow Animation +# Animate curve radius over length of time + +class OBJECT_OT_curvegrow(Operator): + bl_idname = "curve.btgrow" + bl_label = "Run Script" + bl_description = "Keyframe points radius" bl_options = {'REGISTER', 'UNDO'} @classmethod @@ -1520,109 +1154,107 @@ class OBJECT_OT_curvegrow(bpy.types.Operator): return (context.object and context.object.type in {'CURVE'}) def execute(self, context): - Btrace = bpy.context.window_manager.curve_tracer - anim_f_start, anim_length, anim_auto = Btrace.anim_f_start, Btrace.anim_length, Btrace.anim_auto - curve_resolution, curve_depth = Btrace.curve_resolution, Btrace.curve_depth - # make the curve visible - objs = bpy.context.selected_objects - for i in objs: # Execute on multiple selected objects - bpy.context.scene.objects.active = i - obj = bpy.context.active_object - try: - obj.data.fill_mode = 'FULL' - except: - obj.data.dimensions = '3D' - obj.data.fill_mode = 'FULL' - if not obj.data.bevel_resolution: - obj.data.bevel_resolution = curve_resolution - if not obj.data.bevel_depth: - obj.data.bevel_depth = curve_depth - if anim_auto: - anim_f_start = bpy.context.scene.frame_start - anim_length = bpy.context.scene.frame_end - # get points data and beautify - actual, total = anim_f_start, 0 - for sp in obj.data.splines: - total += len(sp.points) + len(sp.bezier_points) - step = anim_length / total - for sp in obj.data.splines: - sp.radius_interpolation = 'BSPLINE' - po = [p for p in sp.points] + [p for p in sp.bezier_points] - if not Btrace.anim_keepr: - for p in po: - p.radius = 1 - if Btrace.anim_tails and not sp.use_cyclic_u: - po[0].radius = po[-1].radius = 0 - po[1].radius = po[-2].radius = .65 - ra = [p.radius for p in po] - - # record the keyframes - for i in range(len(po)): - po[i].radius = 0 - po[i].keyframe_insert('radius', frame=actual) - actual += step - po[i].radius = ra[i] - po[i].keyframe_insert('radius', frame=(actual + Btrace.anim_delay)) - - if Btrace.anim_f_fade: - po[i].radius = ra[i] - po[i].keyframe_insert('radius', frame=(actual + Btrace.anim_f_fade - step)) + try: + # not so nice with the nested try blocks, however the inside one + # is used as a switch statement + Btrace = context.window_manager.curve_tracer + anim_f_start, anim_length, anim_auto = Btrace.anim_f_start, \ + Btrace.anim_length, \ + Btrace.anim_auto + curve_resolution, curve_depth = Btrace.curve_resolution, \ + Btrace.curve_depth + # make the curve visible + objs = context.selected_objects + # Execute on multiple selected objects + for i in objs: + context.scene.objects.active = i + obj = context.active_object + try: + obj.data.fill_mode = 'FULL' + except: + obj.data.dimensions = '3D' + obj.data.fill_mode = 'FULL' + if not obj.data.bevel_resolution: + obj.data.bevel_resolution = curve_resolution + if not obj.data.bevel_depth: + obj.data.bevel_depth = curve_depth + if anim_auto: + anim_f_start = bpy.context.scene.frame_start + anim_length = bpy.context.scene.frame_end + # get points data and beautify + actual, total = anim_f_start, 0 + for sp in obj.data.splines: + total += len(sp.points) + len(sp.bezier_points) + step = anim_length / total + for sp in obj.data.splines: + sp.radius_interpolation = 'BSPLINE' + po = [p for p in sp.points] + [p for p in sp.bezier_points] + if not Btrace.anim_keepr: + for p in po: + p.radius = 1 + if Btrace.anim_tails and not sp.use_cyclic_u: + po[0].radius = po[-1].radius = 0 + po[1].radius = po[-2].radius = .65 + ra = [p.radius for p in po] + + # record the keyframes + for i in range(len(po)): po[i].radius = 0 - po[i].keyframe_insert('radius', frame=(actual + Btrace.anim_delay + Btrace.anim_f_fade)) + po[i].keyframe_insert('radius', frame=actual) + actual += step + po[i].radius = ra[i] + po[i].keyframe_insert( + 'radius', + frame=(actual + Btrace.anim_delay) + ) + + if Btrace.anim_f_fade: + po[i].radius = ra[i] + po[i].keyframe_insert( + 'radius', + frame=(actual + Btrace.anim_f_fade - step) + ) + po[i].radius = 0 + po[i].keyframe_insert( + 'radius', + frame=(actual + Btrace.anim_delay + Btrace.anim_f_fade) + ) + + bpy.context.scene.frame_set(Btrace.anim_f_start) - bpy.context.scene.frame_set(Btrace.anim_f_start) - return{'FINISHED'} - -################## ################## ################## ############ -## Remove animation and curve radius data -################## ################## ################## ############ -class OBJECT_OT_reset(bpy.types.Operator): - bl_idname = 'object.btreset' - bl_label = 'Clear animation' - bl_description = 'Remove animation / curve radius data' + return{'FINISHED'} + + except Exception as e: + error_handlers(self, "curve.btgrow", e, + "Grow curve could not be completed") + + return {'CANCELLED'} + + +# Remove animation and curve radius data +class OBJECT_OT_reset(Operator): + bl_idname = "object.btreset" + bl_label = "Clear animation" + bl_description = "Remove animation / curve radius data" bl_options = {'REGISTER', 'UNDO'} def execute(self, context): - objs = bpy.context.selected_objects - for i in objs: # Execute on multiple selected objects - bpy.context.scene.objects.active = i - obj = bpy.context.active_object - obj.animation_data_clear() - if obj.type == 'CURVE': - for sp in obj.data.splines: - po = [p for p in sp.points] + [p for p in sp.bezier_points] - for p in po: - p.radius = 1 - return{'FINISHED'} - -### Define Classes to register -classes = [ - TracerProperties, - TracerPropertiesMenu, - addTracerObjectPanel, - OBJECT_OT_convertcurve, - OBJECT_OT_objecttrace, - OBJECT_OT_objectconnect, - OBJECT_OT_writing, - OBJECT_OT_particletrace, - OBJECT_OT_traceallparticles, - OBJECT_OT_curvegrow, - OBJECT_OT_reset, - OBJECT_OT_fcnoise, - OBJECT_OT_meshfollow, - OBJECT_OT_materialChango, - OBJECT_OT_clearColorblender - ] - -def register(): - for c in classes: - bpy.utils.register_class(c) - bpy.types.WindowManager.curve_tracer = bpy.props.PointerProperty(type=TracerProperties) - bpy.types.WindowManager.btrace_menu = bpy.props.PointerProperty(type=TracerPropertiesMenu, update=deselect_others) - -def unregister(): - for c in classes: - bpy.utils.unregister_class(c) - del bpy.types.WindowManager.curve_tracer -if __name__ == "__main__": - register() + try: + objs = context.selected_objects + for i in objs: # Execute on multiple selected objects + context.scene.objects.active = i + obj = context.active_object + obj.animation_data_clear() + if obj.type == 'CURVE': + for sp in obj.data.splines: + po = [p for p in sp.points] + [p for p in sp.bezier_points] + for p in po: + p.radius = 1 + + return{'FINISHED'} + + except Exception as e: + error_handlers(self, "object.btreset", e, + "Clear animation could not be completed") + + return {'CANCELLED'} diff --git a/btrace/bTrace_props.py b/btrace/bTrace_props.py new file mode 100644 index 00000000..bff3b88f --- /dev/null +++ b/btrace/bTrace_props.py @@ -0,0 +1,951 @@ +# ##### BEGIN GPL LICENSE BLOCK ##### +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ##### END GPL LICENSE BLOCK ##### + +import bpy +from bpy.types import ( + Panel, + PropertyGroup, + ) +from bpy.props import ( + FloatProperty, + EnumProperty, + IntProperty, + BoolProperty, + FloatVectorProperty, + ) + + +# Class to define properties +class TracerProperties(PropertyGroup): + """Options for tools""" + 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" + ) + 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" + ) + curve_resolution = IntProperty( + name="Bevel Resolution", + min=1, max=32, + default=4, + description="Adjust the Bevel resolution" + ) + curve_depth = FloatProperty( + name="Bevel Depth", + min=0.0, max=100.0, + default=0.1, + description="Adjust the Bevel depth" + ) + curve_u = IntProperty( + name="Resolution U", + min=0, max=64, + default=12, + description="Adjust the Surface resolution" + ) + curve_join = BoolProperty( + name="Join Curves", + default=False, + description="Join all the curves after they have been created" + ) + curve_smooth = BoolProperty( + name="Smooth", + default=True, + description="Render curve smooth" + ) + # Option to Duplicate Mesh + object_duplicate = BoolProperty( + name="Apply to Copy", + default=False, + description="Apply curve to a copy of object" + ) + # Distort Mesh options + 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" + ) + distort_noise = FloatProperty( + name="Mesh Noise", + min=0.0, max=50.0, + default=0.00, + description="Adjust noise added to mesh before adding curve" + ) + # Particle Options + particle_step = IntProperty( + name="Step Size", + min=1, max=50, + default=5, + description="Sample one every this number of frames" + ) + particle_auto = BoolProperty( + name="Auto Frame Range", + default=True, + description="Calculate Frame Range from particles life" + ) + particle_f_start = IntProperty( + name='Start Frame', + min=1, max=5000, + default=1, + description='Start frame' + ) + particle_f_end = IntProperty( + name="End Frame", + min=1, max=5000, + default=250, + description="End frame" + ) + # F-Curve Modifier Properties + fcnoise_rot = BoolProperty( + name="Rotation", + default=False, + description="Affect Rotation" + ) + fcnoise_loc = BoolProperty( + name="Location", + default=True, + description="Affect Location" + ) + fcnoise_scale = BoolProperty( + name="Scale", + default=False, + description="Affect Scale" + ) + fcnoise_amp = IntProperty( + name="Amp", + min=1, max=500, + default=5, + description="Adjust the amplitude" + ) + fcnoise_timescale = FloatProperty( + name="Time Scale", + min=1, max=500, + default=50, + description="Adjust the time scale" + ) + fcnoise_key = BoolProperty( + name="Add Keyframe", + default=True, + description="Keyframe is needed for tool, this adds a LocRotScale keyframe" + ) + show_curve_settings = BoolProperty( + name="Curve Settings", + default=False, + description="Change the curve settings for the created curve" + ) + material_settings = BoolProperty( + name="Material Settings", + default=False, + description="Change the material settings for the created curve" + ) + particle_settings = BoolProperty( + name="Particle Settings", + default=False, + description="Show the settings for the created curve" + ) + animation_settings = BoolProperty( + name="Animation Settings", + default=False, + description="Show the settings for the Animations" + ) + distort_curve = BoolProperty( + name="Add Distortion", + default=False, + description="Set options to distort the final curve" + ) + connect_noise = BoolProperty( + name="F-Curve Noise", + default=False, + description="Adds F-Curve Noise Modifier to selected objects" + ) + settings_objectTrace = BoolProperty( + name="Object Trace Settings", + default=False, + description="Trace selected mesh object with a curve" + ) + settings_objectsConnect = BoolProperty( + name="Objects Connect Settings", + default=False, + description="Connect objects with a curve controlled by hooks" + ) + settings_objectTrace = BoolProperty( + name="Object Trace Settings", + default=False, + description="Trace selected mesh object with a curve" + ) + respect_order = BoolProperty( + name="Order", + default=False, + description="Remember order objects were selected" + ) + settings_particleTrace = BoolProperty( + name="Particle Trace Settings", + default=False, + description="Trace particle path with a curve" + ) + settings_particleConnect = BoolProperty( + name="Particle Connect Settings", + default=False, + description="Connect particles with a curves and animated over particle lifetime" + ) + settings_growCurve = BoolProperty( + name="Grow Curve Settings", + default=False, + description="Animate curve bevel over time by keyframing points radius" + ) + settings_fcurve = BoolProperty( + name="F-Curve Settings", + default=False, + description="F-Curve Settings" + ) + settings_toggle = BoolProperty( + name="Settings", + default=False, + description="Toggle Settings" + ) + # Animation Options + anim_auto = BoolProperty( + name="Auto Frame Range", + default=True, + description="Automatically calculate Frame Range" + ) + anim_f_start = IntProperty( + name="Start", + min=1, max=2500, + default=1, + description="Start frame / Hidden object" + ) + anim_length = IntProperty( + name="Duration", + min=1, + soft_max=1000, max=2500, + default=100, + description="Animation Length" + ) + 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" + ) + anim_delay = IntProperty( + name="Grow", + min=0, max=50, + default=5, + description="Frames it takes a point to grow" + ) + anim_tails = BoolProperty( + name='Tails on endpoints', + default=True, + description='Set radius to zero for open splines endpoints' + ) + anim_keepr = BoolProperty( + name="Keep Radius", + default=True, + description="Try to keep radius data from original curve" + ) + animate = BoolProperty( + name="Animate Result", + default=False, + description="Animate the final curve objects" + ) + # Convert to Curve options + convert_conti = BoolProperty( + name="Continuous", + default=True, + description="Create a continuous curve using verts from mesh" + ) + convert_everyedge = BoolProperty( + name="Every Edge", + default=False, + description="Create a curve from all verts in a mesh" + ) + convert_edgetype = EnumProperty( + name="Edge Type for Curves", + items=(("CONTI", "Continuous", "Create a continuous curve using verts from mesh"), + ("EDGEALL", "All Edges", "Create a curve from every edge in a mesh")), + description="Choose which type of spline to use when curve is created", + default="CONTI" + ) + convert_joinbefore = BoolProperty( + name="Join objects before convert", + default=False, + description="Join all selected mesh to one object before converting to mesh" + ) + # Mesh Follow Options + fol_edge_select = BoolProperty( + name="Edge", + default=False, + description="Grow from edges" + ) + fol_vert_select = BoolProperty( + name="Vertex", + default=False, + description="Grow from verts" + ) + fol_face_select = BoolProperty( + name="Face", + default=True, + description="Grow from faces" + ) + fol_mesh_type = EnumProperty( + name="Mesh type", + default="VERTS", + description="Mesh feature to draw cruves from", + items=(("VERTS", "Verts", "Draw from Verts"), + ("EDGES", "Edges", "Draw from Edges"), + ("FACES", "Faces", "Draw from Faces"), + ("OBJECT", "Object", "Draw from Object origin")) + ) + fol_start_frame = IntProperty( + name="Start Frame", + min=1, max=2500, + default=1, + description="Start frame for range to trace" + ) + fol_end_frame = IntProperty( + name="End Frame", + min=1, max=2500, + default=250, + description="End frame for range to trace" + ) + fol_perc_verts = FloatProperty( + name="Reduce selection by", + min=0.001, max=1.000, + default=0.5, + description="percentage of total verts to trace" + ) + fol_sel_option = EnumProperty( + name="Selection type", + description="Choose which objects to follow", + default="RANDOM", + items=(("RANDOM", "Random", "Follow Random items"), + ("CUSTOM", "Custom Select", "Follow selected items"), + ("ALL", "All", "Follow all items")) + ) + trace_mat_color = FloatVectorProperty( + name="Material Color", + description="Choose material color", + min=0, max=1, + default=(0.0, 0.3, 0.6), + subtype="COLOR" + ) + trace_mat_random = BoolProperty( + name="Random Color", + default=False, + description='Make the material colors random' + ) + # Material custom Properties properties + 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" + ) + mat_run_color_blender = BoolProperty( + name="Run Color Blender", + default=False, + description="Generate colors from a color scheme" + ) + mmColors = EnumProperty( + items=(("RANDOM", "Random", "Use random colors"), + ("CUSTOM", "Custom", "Use custom colors"), + ("BW", "Black/White", "Use Black and White"), + ("BRIGHT", "Bright Colors", "Use Bright colors"), + ("EARTH", "Earth", "Use Earth colors"), + ("GREENBLUE", "Green to Blue", "Use Green to Blue colors")), + description="Choose which type of colors the materials uses", + default="BRIGHT", + name="Define a color palette" + ) + # Custom property for how many keyframes to skip + mmSkip = IntProperty( + name="frames", + min=1, max=500, + default=20, + description="Number of frames between each keyframes" + ) + # Custom property to enable/disable random order for the + mmBoolRandom = BoolProperty( + name="Random Order", + default=False, + description="Randomize the order of the colors" + ) + # Custom Color properties + mmColor1 = FloatVectorProperty( + min=0, max=1, + default=(0.8, 0.8, 0.8), + description="Custom Color 1", subtype="COLOR" + ) + mmColor2 = FloatVectorProperty( + min=0, max=1, + default=(0.8, 0.8, 0.3), + description="Custom Color 2", + subtype="COLOR" + ) + mmColor3 = FloatVectorProperty( + min=0, max=1, + default=(0.8, 0.5, 0.6), + description="Custom Color 3", + subtype="COLOR" + ) + mmColor4 = FloatVectorProperty( + min=0, max=1, + default=(0.2, 0.8, 0.289), + description="Custom Color 4", + subtype="COLOR" + ) + mmColor5 = FloatVectorProperty( + min=0, max=1, + default=(1.0, 0.348, 0.8), + description="Custom Color 5", + subtype="COLOR" + ) + mmColor6 = FloatVectorProperty( + min=0, max=1, + default=(0.4, 0.67, 0.8), + description="Custom Color 6", + subtype="COLOR" + ) + mmColor7 = FloatVectorProperty( + min=0, max=1, + default=(0.66, 0.88, 0.8), + description="Custom Color 7", + subtype="COLOR" + ) + mmColor8 = FloatVectorProperty( + min=0, max=1, + default=(0.8, 0.38, 0.22), + description="Custom Color 8", + subtype="COLOR" + ) + # BW Color properties + bwColor1 = FloatVectorProperty( + min=0, max=1, + default=(0.0, 0.0, 0.0), + description="Black/White Color 1", + subtype="COLOR" + ) + bwColor2 = FloatVectorProperty( + min=0, max=1, + default=(1.0, 1.0, 1.0), + description="Black/White Color 2", + subtype="COLOR" + ) + # Bright Color properties + brightColor1 = FloatVectorProperty( + min=0, max=1, + default=(1.0, 0.0, 0.75), + description="Bright Color 1", + subtype="COLOR" + ) + brightColor2 = FloatVectorProperty( + min=0, max=1, + default=(0.0, 1.0, 1.0), + description="Bright Color 2", + subtype="COLOR" + ) + brightColor3 = FloatVectorProperty( + min=0, max=1, + default=(0.0, 1.0, 0.0), + description="Bright Color 3", + subtype="COLOR" + ) + brightColor4 = FloatVectorProperty( + min=0, max=1, + default=(1.0, 1.0, 0.0), + description="Bright Color 4", subtype="COLOR" + ) + # Earth Color Properties + earthColor1 = FloatVectorProperty( + min=0, max=1, + default=(0.068, 0.019, 0.014), + description="Earth Color 1", + subtype="COLOR" + ) + earthColor2 = FloatVectorProperty( + min=0, max=1, + default=(0.089, 0.060, 0.047), + description="Earth Color 2", + subtype="COLOR" + ) + earthColor3 = FloatVectorProperty( + min=0, max=1, + default=(0.188, 0.168, 0.066), + description="Earth Color 3", + subtype="COLOR" + ) + earthColor4 = FloatVectorProperty( + min=0, max=1, + default=(0.445, 0.296, 0.065), + description="Earth Color 4", + subtype="COLOR" + ) + earthColor5 = FloatVectorProperty( + min=0, max=1, + default=(0.745, 0.332, 0.065), + description="Earth Color 5", + subtype="COLOR" + ) + # Green to Blue Color properties + greenblueColor1 = FloatVectorProperty( + min=0, max=1, + default=(0.296, 0.445, 0.074), + description="Green/Blue Color 1", + subtype="COLOR" + ) + greenblueColor2 = FloatVectorProperty( + min=0, max=1, + default=(0.651, 1.0, 0.223), + description="Green/Blue Color 2", + subtype="COLOR" + ) + greenblueColor3 = FloatVectorProperty( + min=0, max=1, + default=(0.037, 0.047, 0.084), + description="Green/Blue Color 3", + subtype="COLOR" + ) + + # Toolbar show/hide booleans for tool options + btrace_menu_items = [ + ('tool_help', "Help", + "Pick one of the options below", "INFO", 0), + ('tool_objectTrace', "Object Trace", + "Trace selected mesh object with a curve", "FORCE_MAGNETIC", 1), + ('tool_objectsConnect', "Objects Connect", + "Connect objects with a curve controlled by hooks", "OUTLINER_OB_EMPTY", 2), + ('tool_meshFollow', "Mesh Follow", + "Follow selection items on animated mesh object", "DRIVER", 3), + ('tool_handwrite', "Handwriting", + "Create and Animate curve using the grease pencil", "BRUSH_DATA", 4), + ('tool_particleTrace', "Particle Trace", + "Trace particle path with a curve", "PARTICLES", 5), + ('tool_particleConnect', "Particle Connect", + "Connect particles with a curves and animated over particle lifetime", "MOD_PARTICLES", 6), + ('tool_growCurve', "Grow Curve", + "Animate curve bevel over time by keyframing points radius", "META_BALL", 7), + ('tool_fcurve', "F-Curve Noise", + "Add F-Curve noise to selected objects", "RNDCURVE", 8), + ('tool_colorblender', "Color Blender", + "Pick the color of the created curves", "COLOR", 9), + ] + btrace_toolmenu = EnumProperty( + name="Tools", + items=btrace_menu_items, + description="", + default='tool_help' + ) + + +# Draw Brush panel in Toolbar +class addTracerObjectPanel(Panel): + bl_label = "Btrace" + bl_space_type = "VIEW_3D" + bl_region_type = "TOOLS" + bl_context = "objectmode" + bl_category = "Create" + bl_options = {'DEFAULT_CLOSED'} + + def draw(self, context): + layout = self.layout + Btrace = context.window_manager.curve_tracer + addon_prefs = context.user_preferences.addons["btrace"].preferences + switch_expand = addon_prefs.expand_enum + obj = context.object + + # Color Blender Panel options + def color_blender(): + # Buttons for Color Blender + row = box.row() + row.label("Color palette") + row.prop(Btrace, "mmColors", text="") + + # Show Custom Colors if selected + if Btrace.mmColors == 'CUSTOM': + row = box.row(align=True) + for i in range(1, 9): + row.prop(Btrace, "mmColor" + str(i), text="") + # Show Earth Colors + elif Btrace.mmColors == 'BW': + row = box.row(align=True) + row.prop(Btrace, "bwColor1", text="") + row.prop(Btrace, "bwColor2", text="") + # Show Earth Colors + elif Btrace.mmColors == 'BRIGHT': + row = box.row(align=True) + for i in range(1, 5): + row.prop(Btrace, "brightColor" + str(i), text="") + # Show Earth Colors + elif Btrace.mmColors == 'EARTH': + row = box.row(align=True) + for i in range(1, 6): + row.prop(Btrace, "earthColor" + str(i), text="") + # Show Earth Colors + elif Btrace.mmColors == 'GREENBLUE': + row = box.row(align=True) + for i in range(1, 4): + row.prop(Btrace, "greenblueColor" + str(i), text="") + elif Btrace.mmColors == 'RANDOM': + row = box.row() + + # Curve noise settings + def curve_noise(): + row = box.row() + row.label(text="F-Curve Noise", icon='RNDCURVE') + row = box.row(align=True) + row.prop(Btrace, "fcnoise_rot", toggle=True) + row.prop(Btrace, "fcnoise_loc", toggle=True) + row.prop(Btrace, "fcnoise_scale", toggle=True) + + col = box.column(align=True) + col.prop(Btrace, "fcnoise_amp") + col.prop(Btrace, "fcnoise_timescale") + box.prop(Btrace, "fcnoise_key") + + # Curve Panel options + def curve_settings(): + # Button for curve options + row = self.layout.row() + row = box.row(align=True) + + row.prop(Btrace, "show_curve_settings", + icon='CURVE_BEZCURVE', text="Curve Settings") + row.prop(Btrace, "material_settings", + icon='MATERIAL_DATA', text="Material Settings") + + if Btrace.material_settings: + row = box.row() + row.label(text="Material Settings", icon='COLOR') + row = box.row() + row.prop(Btrace, "trace_mat_random") + if not Btrace.trace_mat_random: + row = box.row() + row.prop(Btrace, "trace_mat_color", text="") + else: + row.prop(Btrace, "mat_run_color_blender") + if Btrace.mat_run_color_blender: + row = box.row() + row.operator("object.colorblenderclear", + text="Reset Material Keyframes", + icon="KEY_DEHLT") + row.prop(Btrace, "mmSkip", text="Keyframe every") + color_blender() + row = box.row() + + if Btrace.show_curve_settings: + # selected curve options + if len(context.selected_objects) > 0 and obj.type == 'CURVE': + col = box.column(align=True) + col.label(text="Edit Curves for:", icon='IPO_BEZIER') + col.separator() + col.label(text="Selected Curve Bevel Options") + row = col.row(align=True) + row.prop(obj.data, "bevel_depth", text="Depth") + row.prop(obj.data, "bevel_resolution", text="Resolution") + row = col.row(align=True) + row.prop(obj.data, "resolution_u") + else: # For new curve + box.label(text="New Curve Settings", icon='CURVE_BEZCURVE') + box.prop(Btrace, "curve_spline") + box.prop(Btrace, "curve_handle") + box.label(text="Bevel Options") + col = box.column(align=True) + row = col.row(align=True) + row.prop(Btrace, "curve_depth", text="Depth") + row.prop(Btrace, "curve_resolution", text="Resolution") + row = col.row(align=True) + row.prop(Btrace, "curve_u") + + # Grow Animation Panel options + def add_grow(): + # Button for grow animation option + row = box.row() + row.label(text="Animate Final Curve", icon="SPACE2") + row = box.row() + row.prop(Btrace, "animate", text="Add Grow Curve Animation", icon="META_BALL") + box.separator() + if Btrace.animate: + box.label(text="Frame Animation Settings:", icon="META_BALL") + col = box.column(align=True) + col.prop(Btrace, "anim_auto") + if not Btrace.anim_auto: + row = col.row(align=True) + row.prop(Btrace, "anim_f_start") + row.prop(Btrace, "anim_length") + row = col.row(align=True) + row.prop(Btrace, "anim_delay") + row.prop(Btrace, "anim_f_fade") + + box.label(text="Additional Settings") + row = box.row() + row.prop(Btrace, "anim_tails") + row.prop(Btrace, "anim_keepr") + + # Start Btrace Panel + if switch_expand == 'list': + layout.label(text="Available Tools:", icon="COLLAPSEMENU") + col = layout.column(align=True) + col.prop(Btrace, "btrace_toolmenu", text="") + elif switch_expand == 'col': + col = layout.column(align=True) + col.prop(Btrace, "btrace_toolmenu", expand=True) + elif switch_expand == 'row': + row = layout.row(align=True) + row.alignment = 'CENTER' + row.prop(Btrace, "btrace_toolmenu", text="", expand=True) + + # Start Object Tools + sel = context.selected_objects + + # Default option (can be expanded into help) + if Btrace.btrace_toolmenu == 'tool_help': + row = layout.row() + row.label("Pick an option", icon="HELP") + + # Object Trace + elif Btrace.btrace_toolmenu == 'tool_objectTrace': + row = layout.row() + row.label(text=" Trace Tool:", icon="FORCE_CURVE") + box = self.layout.box() + row = box.row() + row.label(text="Object Trace", icon="FORCE_MAGNETIC") + row.operator("object.btobjecttrace", text="Run!", icon="PLAY") + row = box.row() + row.prop(Btrace, "settings_toggle", icon="MODIFIER", text="Settings") + myselected = "Selected %d" % len(context.selected_objects) + row.label(text=myselected) + if Btrace.settings_toggle: + box.label(text="Edge Type for Curves:", icon="IPO_CONSTANT") + row = box.row(align=True) + row.prop(Btrace, "convert_edgetype", text="") + box.prop(Btrace, "object_duplicate") + if len(sel) > 1: + box.prop(Btrace, "convert_joinbefore") + else: + Btrace.convert_joinbefore = False + row = box.row() + row.prop(Btrace, "distort_curve") + if Btrace.distort_curve: + col = box.column(align=True) + col.prop(Btrace, "distort_modscale") + col.prop(Btrace, "distort_noise") + row = box.row() + curve_settings() # Show Curve/material settings + add_grow() # Grow settings here + + # Objects Connect + elif Btrace.btrace_toolmenu == 'tool_objectsConnect': + row = layout.row() + row.label(text=" Trace Tool:", icon="FORCE_CURVE") + box = self.layout.box() + row = box.row() + row.label(text="Objects Connect", icon="OUTLINER_OB_EMPTY") + row.operator("object.btobjectsconnect", text="Run!", icon="PLAY") + row = box.row() + row.prop(Btrace, "settings_toggle", icon='MODIFIER', text='Settings') + row.label(text="") + if Btrace.settings_toggle: + row = box.row() + row.prop(Btrace, "respect_order", text="Selection Options") + if Btrace.respect_order: + box.operator("object.select_order", + text="Click to start order selection", + icon='UV_SYNC_SELECT') + row = box.row() + row.prop(Btrace, "connect_noise", text="Add F-Curve Noise") + if Btrace.connect_noise: + curve_noise() # Show Curve Noise settings + + curve_settings() # Show Curve/material settings + add_grow() # Grow settings here + + # Mesh Follow + elif Btrace.btrace_toolmenu == 'tool_meshFollow': + row = layout.row() + row.label(text=" Trace Tool:", icon="FORCE_CURVE") + box = self.layout.box() + row = box.row() + row.label(text="Mesh Follow", icon="DRIVER") + row.operator("object.btmeshfollow", text="Run!", icon="PLAY") + row = box.row() + if Btrace.fol_mesh_type == 'OBJECT': + a, b = "Trace Object", "SNAP_VOLUME" + if Btrace.fol_mesh_type == 'VERTS': + a, b = "Trace Verts", "SNAP_VERTEX" + if Btrace.fol_mesh_type == 'EDGES': + a, b = "Trace Edges", "SNAP_EDGE" + if Btrace.fol_mesh_type == 'FACES': + a, b = "Trace Faces", "SNAP_FACE" + row.prop(Btrace, "settings_toggle", icon='MODIFIER', text='Settings') + row.label(text=a, icon=b) + if Btrace.settings_toggle: + col = box.column(align=True) + row = col.row(align=True) + row.prop(Btrace, "fol_mesh_type", expand=True) + row = col.row(align=True) + if Btrace.fol_mesh_type != 'OBJECT': + row.prop(Btrace, "fol_sel_option", expand=True) + row = box.row() + if Btrace.fol_sel_option == 'RANDOM': + row.label("Random Select of Total") + row.prop(Btrace, "fol_perc_verts", text="%") + if Btrace.fol_sel_option == 'CUSTOM': + row.label("Choose selection in Edit Mode") + if Btrace.fol_sel_option == 'ALL': + row.label("Select All items") + col = box.column(align=True) + col.label("Time Options", icon="TIME") + col.prop(Btrace, "particle_step") + row = col.row(align=True) + row.prop(Btrace, "fol_start_frame") + row.prop(Btrace, "fol_end_frame") + curve_settings() # Show Curve/material settings + add_grow() # Grow settings here + + # Handwriting Tools + elif Btrace.btrace_toolmenu == 'tool_handwrite': + row = layout.row() + row.label(text=" Trace Tool:", icon="FORCE_CURVE") + box = self.layout.box() + row = box.row() + row.label(text='Handwriting', icon='BRUSH_DATA') + row.operator("curve.btwriting", text="Run!", icon='PLAY') + row = box.row() + row = box.row() + row.label(text='Grease Pencil Writing Tools') + col = box.column(align=True) + row = col.row(align=True) + row.operator("gpencil.draw", text="Draw", icon='BRUSH_DATA').mode = 'DRAW' + row.operator("gpencil.draw", text="Poly", icon='VPAINT_HLT').mode = 'DRAW_POLY' + row = col.row(align=True) + row.operator("gpencil.draw", text="Line", icon='ZOOMOUT').mode = 'DRAW_STRAIGHT' + row.operator("gpencil.draw", text="Erase", icon='TPAINT_HLT').mode = 'ERASER' + row = box.row() + row.operator("gpencil.data_unlink", text="Delete Grease Pencil Layer", icon="CANCEL") + row = box.row() + curve_settings() # Show Curve/material settings + add_grow() # Grow settings here + + # Particle Trace + elif Btrace.btrace_toolmenu == 'tool_particleTrace': + row = layout.row() + row.label(text=" Trace Tool:", icon="FORCE_CURVE") + box = self.layout.box() + row = box.row() + row.label(text="Particle Trace", icon="PARTICLES") + row.operator("particles.particletrace", text="Run!", icon="PLAY") + row = box.row() + row.prop(Btrace, "settings_toggle", icon='MODIFIER', text='Settings') + row.label(text="") + if Btrace.settings_toggle: + box.prop(Btrace, "particle_step") + row = box.row() + row.prop(Btrace, "curve_join") + curve_settings() # Show Curve/material settings + add_grow() # Grow settings here + + # Connect Particles + elif Btrace.btrace_toolmenu == 'tool_particleConnect': + row = layout.row() + row.label(text=" Trace Tool:", icon="FORCE_CURVE") + box = self.layout.box() + row = box.row() + row.label(text='Particle Connect', icon='MOD_PARTICLES') + row.operator("particles.connect", icon="PLAY", text='Run!') + row = box.row() + row.prop(Btrace, "settings_toggle", icon='MODIFIER', text='Settings') + row.label(text="") + if Btrace.settings_toggle: + box.prop(Btrace, "particle_step") + row = box.row() + row.prop(Btrace, 'particle_auto') + if not Btrace.particle_auto: + row = box.row(align=True) + row.prop(Btrace, 'particle_f_start') + row.prop(Btrace, 'particle_f_end') + curve_settings() # Show Curve/material settings + add_grow() # Grow settings here + + # Grow Animation + elif Btrace.btrace_toolmenu == 'tool_growCurve': + row = layout.row() + row.label(text=" Curve Tool:", icon="OUTLINER_OB_CURVE") + box = self.layout.box() + row = box.row() + row.label(text="Grow Curve", icon="META_BALL") + row.operator("curve.btgrow", text="Run!", icon="PLAY") + row = box.row() + row.prop(Btrace, "settings_toggle", icon="MODIFIER", text="Settings") + row.operator("object.btreset", icon="KEY_DEHLT") + if Btrace.settings_toggle: + box.label(text="Frame Animation Settings:") + col = box.column(align=True) + col.prop(Btrace, "anim_auto") + if not Btrace.anim_auto: + row = col.row(align=True) + row.prop(Btrace, "anim_f_start") + row.prop(Btrace, "anim_length") + row = col.row(align=True) + row.prop(Btrace, "anim_delay") + row.prop(Btrace, "anim_f_fade") + + box.label(text="Additional Settings") + row = box.row() + row.prop(Btrace, "anim_tails") + row.prop(Btrace, "anim_keepr") + + # F-Curve Noise Curve + elif Btrace.btrace_toolmenu == 'tool_fcurve': + row = layout.row() + row.label(text=" Curve Tool:", icon="OUTLINER_OB_CURVE") + box = self.layout.box() + row = box.row() + row.label(text="F-Curve Noise", icon='RNDCURVE') + row.operator("object.btfcnoise", icon='PLAY', text="Run!") + row = box.row() + row.prop(Btrace, "settings_toggle", icon='MODIFIER', text='Settings') + row.operator("object.btreset", icon='KEY_DEHLT') + if Btrace.settings_toggle: + curve_noise() + + # Color Blender + elif Btrace.btrace_toolmenu == 'tool_colorblender': + row = layout.row() + row.label(text=" Curve/Object Tool:", icon="OUTLINER_OB_CURVE") + box = self.layout.box() + row = box.row() + row.label(text="Color Blender", icon="COLOR") + row.operator("object.colorblender", icon='PLAY', text="Run!") + row = box.row() + row.operator("object.colorblenderclear", text="Reset Keyframes", icon="KEY_DEHLT") + row.prop(Btrace, "mmSkip", text="Keyframe every") + color_blender() |