a0e13e10db93a2bf52f4fad6bb84246fedd5827a
[blender-addons-contrib.git] / object_mangle_tools.py
1 # mangle_tools.py (c) 2011 Phil Cote (cotejrp1)
2 #
3 # ***** BEGIN GPL LICENSE BLOCK *****
4 #
5 #
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; either version 2
9 # of the License, or (at your option) any later version.
10 #
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 # GNU General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software Foundation,
18 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 #
20 # ***** END GPL LICENCE BLOCK *****
21 bl_info = {
22     "name": "Mangle Tools",
23     "author": "Phil Cote",
24     "version": (0, 2),
25     "blender": (2, 6, 3),
26     "location": "View3D > Tools",
27     "description": "Set of tools to mangle curves, meshes, and shape keys",
28     "warning": "", # used for warning icon and text in addons panel
29     "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.5/Py/"\
30         "Scripts/",
31     "tracker_url": "https://projects.blender.org/tracker/index.php?"\
32         "func=detail&aid=29071",
33     "category": "Object"}
34
35 import bpy
36 import random
37 import time
38 from math import pi
39 import bmesh
40
41 def move_coordinate(context, co, is_curve=False):
42     xyz_const = context.scene.constraint_vector
43     random.seed(time.time())
44     multiplier = 1
45
46     # For curves, we base the multiplier on the circumference formula.
47     # This helps make curve changes more noticable.
48     if is_curve:
49         multiplier = 2 * pi
50     random_mag = context.scene.random_magnitude
51     if xyz_const[0]:    
52         co.x += .01 * random.randrange( -random_mag, random_mag ) * multiplier
53     if xyz_const[1]:
54         co.y += .01 * random.randrange( -random_mag, random_mag )  * multiplier
55     if xyz_const[2]:
56         co.z += .01 * random.randrange( -random_mag, random_mag ) * multiplier
57
58
59 class MeshManglerOperator(bpy.types.Operator):
60     '''push vertices on the selected object around in random directions to 
61     create a crumpled look'''
62     bl_idname = "ba.mesh_mangler"
63     bl_label = "Mangle Mesh"
64     bl_options = { "REGISTER", "UNDO" }
65
66     @classmethod
67     def poll(cls, context):
68         ob = context.active_object
69         return ob != None and ob.type == 'MESH'
70
71     def execute(self, context):
72         mesh = context.active_object.data
73         bm = bmesh.new()
74         bm.from_mesh(mesh)
75         verts, faces = bm.verts, bm.faces
76         randomMag = context.scene.random_magnitude
77         random.seed( time.time() )
78
79         if mesh.shape_keys != None:
80             self.report( {"INFO"}, "Cannot mangle mesh: Shape keys present" )
81             return {'CANCELLED'}
82         
83         for vert in verts:
84             xVal = .01 * random.randrange( -randomMag, randomMag )
85             yVal = .01 * random.randrange( -randomMag, randomMag)
86             zVal = .01 * random.randrange( -randomMag, randomMag )
87             vert.co.x = vert.co.x + xVal
88             vert.co.y = vert.co.y + yVal
89             vert.co.z = vert.co.z + zVal
90                 
91         bm.to_mesh(mesh)   
92         mesh.update()
93         return {'FINISHED'}
94
95
96 class AnimanglerOperator(bpy.types.Operator):
97     '''makes a shape key and pushes the verts around on it to set up for random pulsating animation'''
98     bl_idname = "ba.ani_mangler"
99     bl_label = "Mangle Shape Key"
100
101
102     @classmethod
103     def poll(cls, context):
104         ob = context.active_object
105         return ob != None and ob.type in [ 'MESH', 'CURVE' ]
106
107     def execute(self, context):
108         scn = context.scene
109         mangleName = scn.mangle_name
110         ob = context.object
111         shapeKey = ob.shape_key_add( name=mangleName )
112         verts = shapeKey.data
113         
114         for vert in verts:
115             move_coordinate(context, vert.co, is_curve=ob.type=='CURVE')
116             
117         return {'FINISHED'}
118
119
120 class CurveManglerOp(bpy.types.Operator):
121     '''Mangles a curve to the degree the user specifies'''
122     bl_idname = "ba.curve_mangler"
123     bl_label = "Mangle Curve"
124     bl_options = { 'REGISTER', 'UNDO' }
125
126     @classmethod
127     def poll(cls, context):
128         ob = context.active_object
129         return ob != None and ob.type == "CURVE"
130
131
132     def execute(self, context):
133
134         ob = context.active_object
135         if ob.data.shape_keys != None:
136             self.report({"INFO"}, "Cannot mangle curve.  Shape keys present")
137             return {'CANCELLED'}
138         splines = context.object.data.splines
139         
140         for spline in splines:
141             if spline.type == 'BEZIER':
142                 points = spline.bezier_points
143             elif spline.type in ('POLY', 'NURBS'):
144                 points = spline.points
145
146             for point in points:
147                 move_coordinate(context, point.co, is_curve=True)
148
149         return {'FINISHED'}
150
151
152 class MangleToolsPanel(bpy.types.Panel):
153     bl_label = "Mangle Tools"
154     bl_space_type = "VIEW_3D"
155     bl_region_type="TOOLS"
156     bl_context = "objectmode"
157     bl_options = {'DEFAULT_CLOSED'}
158
159     def draw(self, context):
160         scn = context.scene
161         layout = self.layout
162         col = layout.column()
163         col.prop(scn, "constraint_vector")
164         col.prop(scn, "random_magnitude")
165
166         col.operator("ba.curve_mangler")
167         col.operator("ba.mesh_mangler")
168         col.separator()
169         col.prop(scn, "mangle_name")
170         col.operator("ba.ani_mangler")
171
172
173 IntProperty = bpy.props.IntProperty
174 StringProperty = bpy.props.StringProperty
175 BoolVectorProperty = bpy.props.BoolVectorProperty
176
177 def register():
178     bpy.utils.register_class(AnimanglerOperator)
179     bpy.utils.register_class(MeshManglerOperator)
180     bpy.utils.register_class(CurveManglerOp)
181     bpy.utils.register_class(MangleToolsPanel)
182     scnType = bpy.types.Scene
183     
184                                     
185     scnType.constraint_vector = BoolVectorProperty(name="Mangle Constraint", 
186                                 default=(True,True,True),
187                                 subtype='XYZ',
188                                 description="Constrains Mangle Direction")
189                                 
190     scnType.random_magnitude = IntProperty( name = "Mangle Severity", 
191                               default = 10, min = 1, max = 30, 
192                               description = "Severity of mangling")
193     
194     scnType.mangle_name = StringProperty(name="Shape Key Name",
195                              default="mangle",
196                              description="Name given for mangled shape keys")
197 def unregister():
198     bpy.utils.unregister_class(AnimanglerOperator)
199     bpy.utils.unregister_class(MeshManglerOperator)
200     bpy.utils.unregister_class(MangleToolsPanel)
201     bpy.utils.unregister_class(CurveManglerOp)
202
203
204 if __name__ == "__main__":
205     register()