Small updates on pinkified theme for some object types, background gradient and other...
[blender-addons-contrib.git] / mesh_easylattice.py
1 # ##### BEGIN GPL LICENSE BLOCK #####
2 #
3 #  This program is free software; you can redistribute it and/or
4 #  modify it under the terms of the GNU General Public License
5 #  as published by the Free Software Foundation; either version 2
6 #  of the License, or (at your option) any later version.
7 #
8 #  This program is distributed in the hope that it will be useful,
9 #  but WITHOUT ANY WARRANTY; without even the implied warranty of
10 #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 #  GNU General Public License for more details.
12 #
13 #  You should have received a copy of the GNU General Public License
14 #  along with this program; if not, write to the Free Software Foundation,
15 #  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 #
17 # ##### END GPL LICENSE BLOCK #####
18
19
20 bl_info = {
21             "name": "Easy Lattice Object",
22             "author": "Kursad Karatas",
23             "version": ( 0, 5 ),
24             "blender": ( 2, 66, 0 ),
25             "location": "View3D > Easy Lattice",
26             "description": "Create a lattice for shape editing",
27             "warning": "",
28             "wiki_url": "http://wiki.blender.org/index.php/Easy_Lattice_Editing_Addon",
29             "tracker_url": "https://bitbucket.org/kursad/blender_addons_easylattice/src",
30             "category": "Mesh"}
31
32 import bpy
33 import mathutils
34 import math
35  
36 # Cleanup
37 def modifiersDelete( obj ):
38     
39     for mod in obj.modifiers:
40         print(mod)
41         if mod.name == "latticeeasytemp":
42             try:
43                 if mod.object == bpy.data.objects['LatticeEasytTemp']:
44                     print("applying modifier")
45                     bpy.ops.object.modifier_apply( apply_as = 'DATA', modifier = mod.name )
46                     
47             except:
48                 bpy.ops.object.modifier_remove( modifier = mod.name )
49         
50 # Cleanup
51 def modifiersApplyRemove( obj ):
52     
53 #     print("passed object is", obj)
54 #     print("current object is", bpy.context.active_object)
55     
56     bpy.ops.object.select_all( action = 'DESELECT' )
57     bpy.ops.object.select_pattern(pattern=obj.name, extend=False)
58     bpy.context.scene.objects.active=obj
59     
60     for mod in obj.modifiers:
61 #         print("modifier is ", mod)
62         if mod.name == "latticeeasytemp":
63 #             try:
64             if mod.object == bpy.data.objects['LatticeEasytTemp']:
65 #                 print("mod object is ", mod.object)
66 #                 print("applying modifier", mod," - ", mod.name)
67                 
68                 #obj.select= True
69 #                 print("current object is", bpy.context.active_object)
70                 bpy.ops.object.modifier_apply( apply_as = 'DATA', modifier = mod.name )
71                 #obj.modifiers.remove(mod)
72                     
73 #             except:
74 #                 bpy.ops.object.modifier_remove( modifier = mod.name )
75                 
76        
77 # Cleanup
78 def latticeDelete(obj):
79     bpy.ops.object.select_all( action = 'DESELECT' )
80     for ob in bpy.context.scene.objects:
81          if "LatticeEasytTemp" in ob.name:
82              ob.select = True
83     bpy.ops.object.delete( use_global = False )        
84     
85     #select the original object back
86     obj.select=True
87
88 def createLattice( obj, size, pos, props ):
89     # Create lattice and object
90     lat = bpy.data.lattices.new( 'LatticeEasytTemp' )
91     ob = bpy.data.objects.new( 'LatticeEasytTemp', lat )
92     
93     loc,rot,scl = getTransformations( obj )
94  
95     #get the combined rotation matrix and apply to the lattice
96     #ob.matrix_world=buildRot_WorldMat(obj)*ob.matrix_world
97     
98     #the position comes from the bbox 
99     ob.location = pos
100         #ob.location=(pos.x+loc.x,pos.y+loc.y,pos.z+loc.z)
101     
102     #the size  from bbox 
103     ob.scale = size
104         #ob.scale=(size.x*scl.x, size.y*scl.y,size.z*scl.z)
105     
106     #the rotation comes from the combined obj world matrix which was converted to euler pairs.    
107     ob.rotation_euler = buildRot_World(obj)
108     
109     ob.show_x_ray = True
110     # Link object to scene
111     scn = bpy.context.scene
112     scn.objects.link( ob )
113     scn.objects.active = ob
114     scn.update()
115  
116     # Set lattice attributes
117     lat.interpolation_type_u = props[3]
118     lat.interpolation_type_v = props[3]
119     lat.interpolation_type_w = props[3]
120  
121     lat.use_outside = False
122     
123     lat.points_u = props[0]
124     lat.points_v = props[1]
125     lat.points_w = props[2]
126
127     #Set lattice points
128     '''s = 0.0
129     points = [
130         (-s,-s,-s), (s,-s,-s), (-s,s,-s), (s,s,-s),
131         (-s,-s,s), (s,-s,s), (-s,s,s), (s,s,s)
132     ]
133     for n,pt in enumerate(lat.points):
134         for k in range(3):
135             #pt.co[k] = points[n][k]
136     '''
137     
138     return ob
139
140
141 def selectedVerts_Grp( obj ):
142 #     vertices=bpy.context.active_object.data.vertices
143     vertices = obj.data.vertices
144     
145     selverts = []
146     
147     if obj.mode == "EDIT":
148         bpy.ops.object.editmode_toggle()
149
150     for grp in obj.vertex_groups:
151         
152         if "templatticegrp" in grp.name:
153             bpy.ops.object.vertex_group_set_active( group = grp.name )
154             bpy.ops.object.vertex_group_remove()
155         
156     tempgroup = obj.vertex_groups.new( "templatticegrp" )
157     
158     # selverts=[vert for vert in vertices if vert.select==True]
159     for vert in vertices:
160         if vert.select == True:
161             selverts.append( vert )
162             tempgroup.add( [vert.index], 1.0, "REPLACE" )
163     
164     # print(selverts)
165     
166     return selverts
167
168 def getTransformations( obj ):
169     rot = obj.rotation_euler
170     loc = obj.location
171     size = obj.scale
172
173     return [loc, rot, size]
174
175 def findBBox( obj, selvertsarray ):
176     
177 #     mat = buildTrnSclMat( obj )
178     mat =buildTrnScl_WorldMat(obj)
179     
180     mat_world = obj.matrix_world
181     
182     minx, miny, minz = selvertsarray[0].co
183     maxx, maxy, maxz = selvertsarray[0].co
184     
185     c = 1
186 #     for vert in selvertsarray:
187     for c in range( len( selvertsarray ) ):
188         # co=obj.matrix_world*vert.co.to_4d()
189         
190 #         co = vert.co
191         co = selvertsarray[c].co
192         
193         if co.x < minx: minx = co.x
194         if co.y < miny: miny = co.y
195         if co.z < minz: minz = co.z
196
197         if co.x > maxx: maxx = co.x
198         if co.y > maxy: maxy = co.y
199         if co.z > maxz: maxz = co.z
200         
201 #         print("local cord", selvertsarray[c].co)
202 #         print("world cord", co)
203         c += 1
204         
205 #     print("total verts", len(selvertsarray))
206 #     print("counted verts",c)
207     
208     # Based on world coords
209 #     print("-> minx miny minz",minx, miny, minz )
210 #     print("-> maxx maxy maxz",maxx, maxy, maxz )
211     
212     minpoint = mathutils.Vector( ( minx, miny, minz ) )
213     maxpoint = mathutils.Vector( ( maxx, maxy, maxz ) )
214     
215     # middle point has to be calculated based on the real world matrix
216     #middle = mat_world * mathutils.Vector((x_sum, y_sum, z_sum))/float(c)
217     middle = ( ( minpoint + maxpoint ) / 2 )
218
219     minpoint = mat * minpoint  # Calculate only based on loc/scale
220     maxpoint = mat * maxpoint  # Calculate only based on loc/scale
221     middle = mat_world * middle  # the middle has to be calculated based on the real world matrix
222     
223     size = maxpoint - minpoint
224     size = mathutils.Vector( ( abs( size.x ), abs( size.y ), abs( size.z ) ) )
225     
226     # local coords   
227     #####################################################
228     '''minpoint=mathutils.Vector((minx,miny,minz))
229     maxpoint=mathutils.Vector((maxx,maxy,maxz))
230     middle=mathutils.Vector( (x_sum/float(len(selvertsarray)), y_sum/float(len(selvertsarray)), z_sum/float(len(selvertsarray))) )
231     size=maxpoint-minpoint
232     size=mathutils.Vector((abs(size.x),abs(size.y),abs(size.z)))
233     '''
234     #####################################################
235     
236
237     return [minpoint, maxpoint, size, middle  ]
238
239
240 def buildTrnSclMat( obj ):
241     # This function builds a local matrix that encodes translation and scale and it leaves out the rotation matrix
242     # The rotation is applied at obejct level if there is any
243     mat_trans = mathutils.Matrix.Translation( obj.location )
244     mat_scale = mathutils.Matrix.Scale( obj.scale[0], 4, ( 1, 0, 0 ) )
245     mat_scale *= mathutils.Matrix.Scale( obj.scale[1], 4, ( 0, 1, 0 ) )
246     mat_scale *= mathutils.Matrix.Scale( obj.scale[2], 4, ( 0, 0, 1 ) )
247     
248     mat_final = mat_trans * mat_scale
249     
250     
251     return mat_final
252     
253 def buildTrnScl_WorldMat( obj ):
254     # This function builds a real world matrix that encodes translation and scale and it leaves out the rotation matrix
255     # The rotation is applied at obejct level if there is any
256     loc,rot,scl=obj.matrix_world.decompose()
257     mat_trans = mathutils.Matrix.Translation( loc)
258     
259     mat_scale = mathutils.Matrix.Scale( scl[0], 4, ( 1, 0, 0 ) )
260     mat_scale *= mathutils.Matrix.Scale( scl[1], 4, ( 0, 1, 0 ) )
261     mat_scale *= mathutils.Matrix.Scale( scl[2], 4, ( 0, 0, 1 ) )
262     
263     mat_final = mat_trans * mat_scale
264     
265     
266     return mat_final
267
268 #Feature use    
269 def buildRot_WorldMat( obj ):
270     # This function builds a real world matrix that encodes rotation and it leaves out translation and scale matrices
271     loc,rot,scl=obj.matrix_world.decompose()
272     rot=rot.to_euler()
273     
274     mat_rot = mathutils.Matrix.Rotation(rot[0], 4,'X') 
275     mat_rot *= mathutils.Matrix.Rotation(rot[1],4,'Z')
276     mat_rot *= mathutils.Matrix.Rotation(rot[2], 4,'Y')
277     return mat_rot
278
279 #Feature use
280 def buildTrn_WorldMat( obj ):
281     # This function builds a real world matrix that encodes translation and scale and it leaves out the rotation matrix
282     # The rotation is applied at obejct level if there is any
283     loc,rot,scl=obj.matrix_world.decompose()
284     mat_trans = mathutils.Matrix.Translation( loc)
285     
286     return mat_trans
287
288 #Feature use
289 def buildScl_WorldMat( obj ):
290     # This function builds a real world matrix that encodes translation and scale and it leaves out the rotation matrix
291     # The rotation is applied at obejct level if there is any
292     loc,rot,scl=obj.matrix_world.decompose()
293     
294     mat_scale = mathutils.Matrix.Scale( scl[0], 4, ( 1, 0, 0 ) )
295     mat_scale *= mathutils.Matrix.Scale( scl[1], 4, ( 0, 1, 0 ) )
296     mat_scale *= mathutils.Matrix.Scale( scl[2], 4, ( 0, 0, 1 ) )
297     
298     return mat_scale
299     
300 def buildRot_World( obj ):
301     # This function builds a real world rotation values
302     loc,rot,scl=obj.matrix_world.decompose()
303     rot=rot.to_euler()
304     
305     return rot
306
307 def run( lat_props ):
308     
309 #     print("<-------------------------------->")
310     #obj = bpy.context.active_object
311     obj = bpy.context.object
312     
313     if obj.type == "MESH":
314         # set global property for the currently active latticed object
315         bpy.types.Scene.activelatticeobject = bpy.props.StringProperty( name = "currentlatticeobject", default = "" )
316         bpy.types.Scene.activelatticeobject = obj.name
317     
318         modifiersDelete( obj )
319         selvertsarray = selectedVerts_Grp( obj )
320         bbox = findBBox( obj, selvertsarray )
321         
322         size = bbox[2]
323         pos = bbox[3]
324         
325 #         print("lattce size, pos", size, " ", pos)
326         latticeDelete(obj)
327         lat = createLattice( obj, size, pos, lat_props )
328         
329         modif = obj.modifiers.new( "latticeeasytemp", "LATTICE" )
330         modif.object = lat
331         modif.vertex_group = "templatticegrp"
332         
333         
334         bpy.ops.object.select_all( action = 'DESELECT' )
335         bpy.ops.object.select_pattern(pattern=lat.name, extend=False)
336         bpy.context.scene.objects.active=lat
337         
338         bpy.context.scene.update()
339         bpy.ops.object.mode_set( mode = 'EDIT' )
340     
341     if obj.type == "LATTICE":
342         
343         
344         if bpy.types.Scene.activelatticeobject:
345             name = bpy.types.Scene.activelatticeobject
346             print("last active latticed object", name)
347         
348             #Are we in edit lattice mode? If so move on to object mode
349             if obj.mode=="EDIT":
350                 bpy.ops.object.editmode_toggle()
351                     
352             for ob in bpy.context.scene.objects:
353                 if ob.name == name:  # found the object with the lattice mod
354                     print("apply mod on", ob)
355                     object = ob
356                     modifiersApplyRemove(object)
357                     #modifiersDelete( object )  # apply the modifier and delete the lattice
358                     latticeDelete(obj)
359     
360     return
361
362
363 def main( context, latticeprops ):
364     run( latticeprops )
365
366 class EasyLattice( bpy.types.Operator ):
367     """Tooltip"""
368     bl_idname = "object.easy_lattice"
369     bl_label = "Easy Lattice Creator"
370     bl_space_type = "VIEW_3D"
371     bl_region_type = "TOOLS"
372     
373     lat_u = bpy.props.IntProperty( name = "Lattice u", default = 3 )
374     lat_w = bpy.props.IntProperty( name = "Lattice w", default = 3 )
375     lat_m = bpy.props.IntProperty( name = "Lattice m", default = 3 )
376     
377     lat_types = ( ( '0', 'KEY_LINEAR', '0' ), ( '1', 'KEY_CARDINAL', '1' ), ( '2', 'KEY_BSPLINE', '2' ) )
378     lat_type = bpy.props.EnumProperty( name = "Lattice Type", items = lat_types, default = '0' )
379     
380     
381     @classmethod
382     def poll( cls, context ):
383         return context.active_object is not None
384
385     def execute( self, context ):
386         
387         lat_u = self.lat_u
388         lat_w = self.lat_w
389         lat_m = self.lat_m
390         
391         # this is a reference to the "items" used to generate the
392         # enum property.
393         lat_type = self.lat_types[int( self.lat_type )][1]
394         lat_props = [lat_u, lat_w, lat_m, lat_type]
395
396         main( context, lat_props )
397         return {'FINISHED'}
398
399     def invoke( self, context, event ):
400         wm = context.window_manager
401         return wm.invoke_props_dialog( self )
402
403 def menu_draw( self, context ): 
404     self.layout.operator_context = 'INVOKE_REGION_WIN' 
405     self.layout.operator( EasyLattice.bl_idname, "Easy Lattice" ) 
406
407 def register():
408     bpy.utils.register_class( EasyLattice )
409     # bpy.utils.register
410     # menu_func = (lambda self, context: self.layout.operator('EasyLattice'))
411     # bpy.types.VIEW3D_PT_tools_objectmode.append(menu_draw)
412     bpy.types.VIEW3D_MT_edit_mesh_specials.append( menu_draw ) 
413
414
415 def unregister():
416     bpy.utils.unregister_class( EasyLattice )
417     # bpy.types.VIEW3D_PT_tools_objectmode.remove(menu_draw)
418     bpy.types.VIEW3D_MT_edit_mesh_specials.remove( menu_draw ) 
419
420 if __name__ == "__main__":
421     register()
422     # run()
423 #     bpy.ops.object.easy_lattice()
424
425
426
427