Set material and color properties of Blob objects.
[blender-addons-contrib.git] / mesh_discombobulator.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 bl_info = {
20     "name": "Discombobulator",
21     "description": "Its job is to easily add scifi details to a surface to create nice-looking space-ships or futuristic cities.",
22     "author": "Evan J. Rosky (syrux), Chichiri, Jace Priester",
23     "version": (0,2),
24     "blender": (2, 71, 0),
25     "location": "View3D > Toolshelf > Addons Tab",
26     "warning": 'Beta',
27     'wiki_url': 'http://wiki.blender.org/index.php/Extensions:2.6/Py/Scripts',
28     'tracker_url': 'https://developer.blender.org/T31390',
29     "category": "Mesh"}
30  
31 import bpy
32 import random
33 import mathutils
34 import math
35 from mathutils import *
36
37 doprots = True
38  
39 # Datas in which we will build the new discombobulated mesh
40 nPolygons = []
41 nVerts = []
42 Verts = []
43 Polygons = []
44 dVerts = []
45 dPolygons = []
46 i_prots = [] # index of the top polygons on whow we will generate the doodads
47 i_dood_type = [] # type of doodad (given by index of the doodad obj)
48  
49 bpy.types.Scene.DISC_doodads = []
50  
51 def randnum(a, b):
52     return random.random()*(b-a)+a
53  
54 def randVertex(a, b, c, d, Verts):
55     """Return a vector of a random vertex on a quad-polygon"""
56     i = random.randint(1,2)
57     A, B, C, D = 0, 0, 0, 0
58     if(a==1):
59         A, B, C, D = a, b, c, d
60     else:
61         A, B, C, D = a, d, c, b
62    
63     i = randnum(0.1, 0.9)
64    
65
66     vecAB=Verts[B]-Verts[A]
67     E=Verts[A]+vecAB*i
68    
69     vecDC=Verts[C]-Verts[D]
70     F=Verts[D]+vecDC*i
71    
72     i = randnum(0.1, 0.9)
73     vecEF=F-E
74     
75     O=E+vecEF*i
76     return O
77  
78 ################################ Protusions ###################################
79  
80 def fill_older_datas(verts, polygon):
81     """ Specifically coded to be called by the function addProtusionToPolygon, its sets up a tuple which contains the vertices from the base and the top of the protusions. """
82     temp_vertices = []  
83     temp_vertices.append(verts[polygon[0]].copy())
84     temp_vertices.append(verts[polygon[1]].copy())
85     temp_vertices.append(verts[polygon[2]].copy())
86     temp_vertices.append(verts[polygon[3]].copy())
87     temp_vertices.append(verts[polygon[0]].copy())
88     temp_vertices.append(verts[polygon[1]].copy())
89     temp_vertices.append(verts[polygon[2]].copy())
90     temp_vertices.append(verts[polygon[3]].copy())
91     return temp_vertices
92    
93 def extrude_top(temp_vertices, normal, height):
94     """ This function extrude the polygon composed of the four first members of the tuple temp_vertices along the normal multiplied by the height of the extrusion."""
95     j = 0
96     while j < 3:  
97         temp_vertices[0][j]+=normal[j]*height
98         temp_vertices[1][j]+=normal[j]*height
99         temp_vertices[2][j]+=normal[j]*height
100         temp_vertices[3][j]+=normal[j]*height
101         j+=1
102  
103 def scale_top(temp_vertices, center, normal, height, scale_ratio):
104     """ This function scale the polygon composed of the four first members of the tuple temp_vertices. """
105     vec1 = [0, 0, 0]
106     vec2 = [0, 0, 0]
107     vec3 = [0, 0, 0]
108     vec4 = [0, 0, 0]
109    
110     j = 0
111     while j < 3:
112         center[j]+=normal[j]*height
113         vec1[j] = temp_vertices[0][j] - center[j]
114         vec2[j] = temp_vertices[1][j] - center[j]
115         vec3[j] = temp_vertices[2][j] - center[j]
116         vec4[j] = temp_vertices[3][j] - center[j]
117         temp_vertices[0][j] = center[j] + vec1[j]*(1-scale_ratio)
118         temp_vertices[1][j] = center[j] + vec2[j]*(1-scale_ratio)
119         temp_vertices[2][j] = center[j] + vec3[j]*(1-scale_ratio)
120         temp_vertices[3][j] = center[j] + vec4[j]*(1-scale_ratio)
121         j+=1
122  
123 def add_prot_polygons(temp_vertices):
124     """ Specifically coded to be called by addProtusionToPolygon, this function put the data from the generated protusion at the end the tuples Verts and Polygons, which will later used to generate the final mesh. """
125     global Verts
126     global Polygons
127     global i_prots
128    
129     findex = len(Verts)
130     Verts+=temp_vertices
131    
132     polygontop = [findex+0, findex+1, findex+2, findex+3]
133     polygon1 = [findex+0, findex+1, findex+5, findex+4]
134     polygon2 = [findex+1, findex+2, findex+6, findex+5]
135     polygon3 = [findex+2, findex+3, findex+7, findex+6]
136     polygon4 = [findex+3, findex+0, findex+4, findex+7]
137    
138     Polygons.append(polygontop)
139     i_prots.append(len(Polygons)-1)
140     Polygons.append(polygon1)
141     Polygons.append(polygon2)
142     Polygons.append(polygon3)
143     Polygons.append(polygon4)
144        
145 def addProtusionToPolygon(obpolygon, verts, minHeight, maxHeight, minTaper, maxTaper):
146     """Create a protusion from the polygon "obpolygon" of the original object and use several values sent by the user. It calls in this order the following functions:
147        - fill_older_data;
148        - extrude_top;
149        - scale_top;
150        - add_prot_polygons;
151    """
152     # some useful variables
153     polygon = obpolygon.vertices
154     polygontop = polygon
155     polygon1 = []
156     polygon2 = []
157     polygon3 = []
158     polygon4 = []
159     vertices = []
160     tVerts = list(fill_older_datas(verts, polygon)) # list of temp vertices
161     height = randnum(minHeight, maxHeight) # height of generated protusion
162     scale_ratio = randnum(minTaper, maxTaper)
163    
164     # extrude the top polygon
165     extrude_top(tVerts, obpolygon.normal, height)
166     # Now, we scale, the top polygon along its normal
167     scale_top(tVerts, GetPolyCentroid(obpolygon,verts), obpolygon.normal, height, scale_ratio)
168     # Finally, we add the protusions to the list of polygons
169     add_prot_polygons(tVerts)
170  
171 ################################## Divide a polygon ##################################
172  
173 def divide_one(list_polygons, list_vertices, verts, polygon, findex):
174     """ called by divide_polygon, to generate a polygon from one polygon, maybe I could simplify this process """
175     temp_vertices = []
176     temp_vertices.append(verts[polygon[0]].copy())
177     temp_vertices.append(verts[polygon[1]].copy())
178     temp_vertices.append(verts[polygon[2]].copy())
179     temp_vertices.append(verts[polygon[3]].copy())
180    
181     list_vertices+=temp_vertices
182        
183     list_polygons.append([findex+0, findex+1, findex+2, findex+3])
184  
185 def divide_two(list_polygons, list_vertices, verts, polygon, findex):
186     """ called by divide_polygon, to generate two polygons from one polygon and add them to the list of polygons and vertices which form the discombobulated mesh"""
187     temp_vertices = []
188     temp_vertices.append(verts[polygon[0]].copy())
189     temp_vertices.append(verts[polygon[1]].copy())
190     temp_vertices.append(verts[polygon[2]].copy())
191     temp_vertices.append(verts[polygon[3]].copy())
192     temp_vertices.append((verts[polygon[0]]+verts[polygon[1]])/2)
193     temp_vertices.append((verts[polygon[2]]+verts[polygon[3]])/2)
194        
195     list_vertices+=temp_vertices
196        
197     list_polygons.append([findex+0, findex+4, findex+5, findex+3])
198     list_polygons.append([findex+1, findex+2, findex+5, findex+4])
199
200 def divide_three(list_polygons, list_vertices, verts, polygon, findex, center):
201     """ called by divide_polygon, to generate three polygons from one polygon and add them to the list of polygons and vertices which form the discombobulated mesh"""
202     temp_vertices = []
203     temp_vertices.append(verts[polygon[0]].copy())
204     temp_vertices.append(verts[polygon[1]].copy())
205     temp_vertices.append(verts[polygon[2]].copy())
206     temp_vertices.append(verts[polygon[3]].copy())
207     temp_vertices.append((verts[polygon[0]]+verts[polygon[1]])/2)
208     temp_vertices.append((verts[polygon[2]]+verts[polygon[3]])/2)
209     temp_vertices.append((verts[polygon[1]]+verts[polygon[2]])/2)
210     temp_vertices.append(center.copy())
211        
212     list_vertices+=temp_vertices
213        
214     list_polygons.append([findex+0, findex+4, findex+5, findex+3])
215     list_polygons.append([findex+1, findex+6, findex+7, findex+4])
216     list_polygons.append([findex+6, findex+2, findex+5, findex+7])
217   
218 def divide_four(list_polygons, list_vertices, verts, polygon, findex, center):
219     """ called by divide_polygon, to generate four polygons from one polygon and add them to the list of polygons and vertices which form the discombobulated mesh"""
220     temp_vertices = []
221     temp_vertices.append(verts[polygon[0]].copy())
222     temp_vertices.append(verts[polygon[1]].copy())
223     temp_vertices.append(verts[polygon[2]].copy())
224     temp_vertices.append(verts[polygon[3]].copy())
225     temp_vertices.append((verts[polygon[0]]+verts[polygon[1]])/2)
226     temp_vertices.append((verts[polygon[2]]+verts[polygon[3]])/2)
227     temp_vertices.append((verts[polygon[1]]+verts[polygon[2]])/2)
228     temp_vertices.append(center.copy())
229     temp_vertices.append((verts[polygon[0]]+verts[polygon[3]])/2)
230     temp_vertices.append(center.copy())
231    
232     list_vertices+=temp_vertices
233        
234     list_polygons.append([findex+0, findex+4, findex+7, findex+8])
235     list_polygons.append([findex+1, findex+6, findex+7, findex+4])
236     list_polygons.append([findex+6, findex+2, findex+5, findex+7])
237     list_polygons.append([findex+8, findex+7, findex+5, findex+3])
238    
239 def dividepolygon(obpolygon, verts, number):
240     """Divide the poly into the wanted number of polygons"""
241     global nPolygons
242     global nVerts
243    
244     poly = obpolygon.vertices
245     tVerts = []
246    
247     if(number==1):
248         divide_one(nPolygons, nVerts, verts, poly, len(nVerts))
249     elif(number==2):
250         divide_two(nPolygons, nVerts, verts, poly, len(nVerts))
251     elif(number==3):
252         divide_three(nPolygons, nVerts, verts, poly, len(nVerts), GetPolyCentroid(obpolygon,verts))
253     elif(number==4):
254         divide_four(nPolygons, nVerts, verts, poly, len(nVerts), GetPolyCentroid(obpolygon,verts))
255    
256 ############################### Discombobulate ################################
257
258 def GetPolyCentroid(obpolygon,allvertcoords):
259     centroid=mathutils.Vector((0,0,0))
260     for vindex in obpolygon.vertices:
261         centroid+=mathutils.Vector(allvertcoords[vindex])
262     centroid/=len(obpolygon.vertices)
263     return centroid
264  
265 def division(obpolygons, verts, sf1, sf2, sf3, sf4):
266     """Function to divide each of the selected polygons"""
267     divide = []
268     if(sf1): divide.append(1)
269     if(sf2): divide.append(2)
270     if(sf3): divide.append(3)
271     if(sf4): divide.append(4)
272     for poly in obpolygons:
273         if(poly.select == True and len(poly.vertices)==4):
274             a = random.randint(0, len(divide)-1)
275             dividepolygon(poly, verts, divide[a])
276  
277 def protusion(obverts, obpolygons, minHeight, maxHeight, minTaper, maxTaper):
278     """function to generate the protusions"""
279     verts = []
280     for vertex in obverts:
281         verts.append(vertex.co)
282            
283     for polygon in obpolygons:
284         if(polygon.select == True):
285             if(len(polygon.vertices) == 4):
286                 addProtusionToPolygon(polygon, verts, minHeight, maxHeight, minTaper, maxTaper)
287  
288 def test_v2_near_v1(v1, v2):
289     if(v1.x - 0.1 <= v2.x <= v1.x + 0.1
290         and v1.y - 0.1 <= v2.y <= v1.y + 0.1
291         and v1.z - 0.1 <= v2.z <= v1.z + 0.1):
292         return True
293    
294     return False
295  
296 def angle_between_nor(nor_orig, nor_result):
297     angle = math.acos(nor_orig.dot(nor_result))
298     axis = nor_orig.cross(nor_result).normalized()
299    
300     q = mathutils.Quaternion()
301     q.x = axis.x*math.sin(angle/2)
302     q.y = axis.y*math.sin(angle/2)
303     q.z = axis.z*math.sin(angle/2)
304     q.w = math.cos(angle/2)
305    
306     return q
307  
308 def doodads(object1, mesh1, dmin, dmax):
309     """function to generate the doodads"""
310     global dVerts
311     global dPolygons
312     i = 0
313     # on parcoure cette boucle pour ajouter des doodads a toutes les polygons
314     # english translation: this loops adds doodads to all polygons
315     while(i<len(object1.data.polygons)):
316         if object1.data.polygons[i].select==False:
317             continue
318         doods_nbr = random.randint(dmin, dmax)
319         j = 0
320         while(j<=doods_nbr):
321             origin_dood = randVertex(object1.data.polygons[i].vertices[0], object1.data.polygons[i].vertices[1], object1.data.polygons[i].vertices[2], object1.data.polygons[i].vertices[3], Verts)
322             type_dood = random.randint(0, len(bpy.context.scene.DISC_doodads)-1)
323             polygons_add = []
324             verts_add = []
325            
326             # First we have to apply scaling and rotation to the mesh
327             bpy.ops.object.select_pattern(pattern=bpy.context.scene.DISC_doodads[type_dood],extend=False)
328             bpy.context.scene.objects.active=bpy.data.objects[bpy.context.scene.DISC_doodads[type_dood]]
329             bpy.ops.object.transform_apply(rotation=True, scale=True)
330            
331             for polygon in bpy.data.objects[bpy.context.scene.DISC_doodads[type_dood]].data.polygons:
332                 polygons_add.append(polygon.vertices)
333             for vertex in bpy.data.objects[bpy.context.scene.DISC_doodads[type_dood]].data.vertices:
334                 verts_add.append(vertex.co.copy())
335             normal_original_polygon = object1.data.polygons[i].normal
336            
337             nor_def = mathutils.Vector((0.0, 0.0, 1.0))
338             qr = nor_def.rotation_difference(normal_original_polygon.normalized())
339            
340             case_z = False
341             if(test_v2_near_v1(nor_def, -normal_original_polygon)):
342                 case_z = True
343                 qr = mathutils.Quaternion((0.0, 0.0, 0.0, 0.0))
344             #qr = angle_between_nor(nor_def, normal_original_polygon)
345             for vertex in verts_add:
346                 vertex.rotate(qr)
347                 vertex+=origin_dood
348             findex = len(dVerts)
349             for polygon in polygons_add:
350                 dPolygons.append([polygon[0]+findex, polygon[1]+findex, polygon[2]+findex, polygon[3]+findex])
351                 i_dood_type.append(bpy.data.objects[bpy.context.scene.DISC_doodads[type_dood]].name)
352             for vertex in verts_add:
353                 dVerts.append(vertex)
354             j+=1
355         i+=5
356        
357 def protusions_repeat(object1, mesh1, r_prot):
358
359         for j in i_prots:
360             if j<len(object1.data.polygons):
361                 object1.data.polygons[j].select=True
362             else:
363                 print("Warning: hit end of polygons in object1")
364  
365 # add material to discombobulated mesh
366 def setMatProt(discObj, origObj, sideProtMat, topProtMat):
367     # First we put the materials in their slots
368     bpy.ops.object.select_pattern(pattern = discObj.name,extend=False)
369     bpy.context.scene.objects.active=bpy.data.objects[discObj.name]
370     try:
371         origObj.material_slots[topProtMat]
372         origObj.material_slots[sideProtMat]
373     except:
374         return
375         
376     bpy.ops.object.material_slot_add()
377     bpy.ops.object.material_slot_add()
378     discObj.material_slots[0].material = origObj.material_slots[topProtMat].material
379     discObj.material_slots[1].material = origObj.material_slots[sideProtMat].material
380    
381     # Then we assign materials to protusions
382     for polygon in discObj.data.polygons:
383         if polygon.index in i_prots:
384             polygon.material_index = 0
385         else:
386             polygon.material_index = 1
387  
388 def setMatDood(doodObj):
389     # First we add the materials slots
390     bpy.ops.object.select_pattern(pattern = doodObj.name,extend=False)
391     bpy.context.scene.objects.active=doodObj
392     for name in bpy.context.scene.DISC_doodads:
393         try:
394             bpy.ops.object.material_slot_add()
395             doodObj.material_slots[-1].material = bpy.data.objects[name].material_slots[0].material
396             for polygon in doodObj.data.polygons:
397                 if i_dood_type[polygon.index] == name:
398                     polygon.material_index = len(doodObj.material_slots)-1
399         except:
400             print()
401            
402            
403 def clean_doodads():
404     current_doodads=list(bpy.context.scene.DISC_doodads)
405     
406     for name in current_doodads:
407         if name not in bpy.data.objects:
408             bpy.context.scene.DISC_doodads.remove(name)
409             
410
411 def discombobulate(minHeight, maxHeight, minTaper, maxTaper, sf1, sf2, sf3, sf4, dmin, dmax, r_prot, sideProtMat, topProtMat, isLast):
412     global doprots
413     global nVerts
414     global nPolygons
415     global Verts
416     global Polygons
417     global dVerts
418     global dPolygons
419     global i_prots
420     
421    
422     bpy.ops.object.mode_set(mode="OBJECT")
423     
424     
425     #start by cleaning up doodads that don't exist anymore
426     clean_doodads()
427     
428     
429     # Create the discombobulated mesh
430     mesh = bpy.data.meshes.new("tmp")
431     object = bpy.data.objects.new("tmp", mesh)
432     bpy.context.scene.objects.link(object)
433    
434     # init final verts and polygons tuple
435     nPolygons = []
436     nVerts = []
437     Polygons = []
438     Verts = []
439     dPolygons = []
440     dVerts = []
441    
442     origObj = bpy.context.active_object
443    
444     # There we collect the rotation, translation and scaling datas from the original mesh
445     to_translate = bpy.context.active_object.location
446     to_scale     = bpy.context.active_object.scale
447     to_rotate    = bpy.context.active_object.rotation_euler
448    
449     # First, we collect all the informations we will need from the previous mesh        
450     obverts = bpy.context.active_object.data.vertices
451     obpolygons = bpy.context.active_object.data.polygons
452     verts = []
453     for vertex in obverts:
454         verts.append(vertex.co)
455    
456     division(obpolygons, verts, sf1, sf2, sf3, sf4)
457        
458     # Fill in the discombobulated mesh with the new polygons
459     mesh.from_pydata(nVerts, [], nPolygons)
460     mesh.update(calc_edges = True)
461    
462     # Reload the datas
463     bpy.ops.object.select_all(action="DESELECT")
464     bpy.ops.object.select_pattern(pattern = object.name,extend=False)
465     bpy.context.scene.objects.active=bpy.data.objects[object.name]
466     obverts = bpy.context.active_object.data.vertices
467     obpolygons = bpy.context.active_object.data.polygons
468    
469     protusion(obverts, obpolygons, minHeight, maxHeight, minTaper, maxTaper)
470    
471     # Fill in the discombobulated mesh with the new polygons
472     mesh1 = bpy.data.meshes.new("discombobulated_object")
473     object1 = bpy.data.objects.new("discombobulated_mesh", mesh1)
474     bpy.context.scene.objects.link(object1)
475     mesh1.from_pydata(Verts, [], Polygons)
476     mesh1.update(calc_edges = True)
477    
478    
479     # Set the material's of discombobulated object
480     setMatProt(object1, origObj, sideProtMat, topProtMat)
481    
482     bpy.ops.object.select_pattern(pattern = object1.name,extend=False)
483     bpy.context.scene.objects.active=bpy.data.objects[object1.name]
484     bpy.ops.object.mode_set(mode='EDIT')
485     bpy.ops.mesh.normals_make_consistent(inside=False)
486     bpy.ops.mesh.select_all(action='DESELECT')
487     bpy.ops.object.mode_set(mode='OBJECT')
488    
489     #if(bpy.context.scene.repeatprot):
490     protusions_repeat(object1, mesh1, r_prot)
491    
492     if(len(bpy.context.scene.DISC_doodads) != 0 and bpy.context.scene.dodoodads and isLast):
493         doodads(object1, mesh1, dmin, dmax)
494         mesh2 = bpy.data.meshes.new("dood_mesh")
495         object2 = bpy.data.objects.new("dood_obj", mesh2)
496         bpy.context.scene.objects.link(object2)
497         mesh2.from_pydata(dVerts, [], dPolygons)
498         mesh2.update(calc_edges = True)
499         setMatDood(object2)
500         object2.location        = to_translate
501         object2.rotation_euler  = to_rotate
502         object2.scale           = to_scale
503  
504     bpy.ops.object.select_pattern(pattern = object.name,extend=False)
505     bpy.context.scene.objects.active=bpy.data.objects[object.name]
506     bpy.ops.object.delete()
507     
508     bpy.ops.object.select_pattern(pattern=object1.name,extend=False)
509     bpy.context.scene.objects.active=bpy.data.objects[object1.name]
510     bpy.context.scene.update()
511    
512     # translate, scale and rotate discombobulated results
513     object1.location        = to_translate
514     object1.rotation_euler  = to_rotate
515     object1.scale           = to_scale
516     
517     #set all polys to selected. this allows recursive discombobulating.
518     for poly in mesh1.polygons:
519         poly.select=True
520  
521 ############ Operator to select and deslect an object as a doodad ###############
522  
523 class chooseDoodad(bpy.types.Operator):
524     bl_idname = "object.discombobulate_set_doodad"
525     bl_label = "Discombobulate set doodad object"
526    
527     def execute(self, context):
528         bpy.context.scene.DISC_doodads.append(bpy.context.active_object.name)
529        
530     def invoke(self, context, event):
531         self.execute(context)
532         return {'FINISHED'}
533  
534 class unchooseDoodad(bpy.types.Operator):
535     bl_idname = "object.discombobulate_unset_doodad"
536     bl_label = "Discombobulate unset doodad object"
537    
538     def execute(self, context):
539         for name in bpy.context.scene.DISC_doodads:
540             if name == bpy.context.active_object.name:
541                 bpy.context.scene.DISC_doodads.remove(name)
542                
543     def invoke(self, context, event):
544         self.execute(context)
545         return {'FINISHED'}
546  
547 ################################## Interpolygon ####################################
548  
549 class discombobulator(bpy.types.Operator):
550     bl_idname = "object.discombobulate"
551     bl_label = "Discombobulate"
552     bl_options = {'REGISTER', 'UNDO'}  
553    
554     def execute(self, context):
555         scn = context.scene
556         i=0
557         while i<scn.repeatprot:
558             isLast=False
559             if i==scn.repeatprot-1:
560                 isLast=True
561             discombobulate(scn.minHeight, scn.maxHeight, scn.minTaper, scn.maxTaper, scn.subpolygon1, scn.subpolygon2, scn.subpolygon3, scn.subpolygon4, scn.mindoodads, scn.maxdoodads, scn.repeatprot, scn.sideProtMat, scn.topProtMat, isLast)
562             i+=1
563         return {'FINISHED'}
564
565 class discombob_help(bpy.types.Operator):
566         bl_idname = 'help.discombobulator'
567         bl_label = ''
568
569         def draw(self, context):
570                 layout = self.layout
571                 layout.label('To use:')
572                 layout.label('Works with Quads only not Ngons.')
573                 layout.label('Select a face or faces')
574                 layout.label('Press Discombobulate to create greebles')
575
576
577         
578         def execute(self, context):
579                 return {'FINISHED'}
580
581         def invoke(self, context, event):
582                 return context.window_manager.invoke_popup(self, width = 300)
583                 
584 class VIEW3D_PT_tools_discombobulate(bpy.types.Panel):
585     bl_space_type = 'VIEW_3D'
586     bl_region_type = 'TOOLS'
587     bl_label = "Discombobulator"
588     bl_context = "objectmode"
589     bl_options = {'DEFAULT_CLOSED'}
590     bl_category = "Addons"
591         
592     def draw(self, context):
593         layout = self.layout
594         row = layout.row()
595         row = layout.split(0.80)
596         row.operator('object.discombobulate', text = 'Discombobulate', icon = 'PLUGIN')
597         row.operator('help.discombobulator', icon = 'INFO')
598         box = layout.box()
599         box.label("Protusions settings")
600         row = box.row()
601         row.prop(context.scene, 'doprots')
602         row = box.row()
603         row.prop(context.scene, 'minHeight')
604         row = box.row()
605         row.prop(context.scene, 'maxHeight')
606         row = box.row()
607         row.prop(context.scene, 'minTaper')
608         row = box.row()
609         row.prop(context.scene, 'maxTaper')
610         row = box.row()
611         col1 = row.column(align = True)
612         col1.prop(context.scene, "subpolygon1")
613         col2 = row.column(align = True)
614         col2.prop(context.scene, "subpolygon2")
615         col3 = row.column(align = True)
616         col3.prop(context.scene, "subpolygon3")
617         col4 = row.column(align = True)
618         col4.prop(context.scene, "subpolygon4")
619         row = box.row()
620         row.prop(context.scene, "repeatprot")
621         box = layout.box()
622         box.label("Doodads settings")
623         row = box.row()
624         row.prop(context.scene, 'dodoodads')
625         row = box.row()
626         row.prop(context.scene, "mindoodads")
627         row = box.row()
628         row.prop(context.scene, "maxdoodads")
629         row = box.row()
630         row.operator("object.discombobulate_set_doodad", text = "Pick doodad")
631         row = box.row()
632         row.operator("object.discombobulate_unset_doodad", text = "Remove doodad")
633         col = box.column(align = True)
634         for name in bpy.context.scene.DISC_doodads:
635             col.label(text = name)
636         box = layout.box()
637         box.label("Materials settings")
638         row = box.row()
639         row.prop(context.scene, 'topProtMat')
640         row = box.row()
641         row.prop(context.scene, "sideProtMat")
642         row = box.row()
643            
644 # registering and menu integration
645 def register():
646     # Protusions Buttons:
647     bpy.types.Scene.repeatprot = bpy.props.IntProperty(name="Repeat protusions", description="make several layers of protusion", default = 1, min = 1, max = 10)
648     bpy.types.Scene.doprots = bpy.props.BoolProperty(name="Make protusions", description = "Check if we want to add protusions to the mesh", default = True)
649     bpy.types.Scene.polygonschangedpercent = bpy.props.FloatProperty(name="Polygon %", description = "Percentage of changed polygons", default = 1.0)
650     bpy.types.Scene.minHeight = bpy.props.FloatProperty(name="Min height", description="Minimal height of the protusions", default=0.2)
651     bpy.types.Scene.maxHeight = bpy.props.FloatProperty(name="Max height", description="Maximal height of the protusions", default = 0.4)
652     bpy.types.Scene.minTaper = bpy.props.FloatProperty(name="Min taper", description="Minimal height of the protusions", default=0.15, min = 0.0, max = 1.0, subtype = 'PERCENTAGE')
653     bpy.types.Scene.maxTaper = bpy.props.FloatProperty(name="Max taper", description="Maximal height of the protusions", default = 0.35, min = 0.0, max = 1.0, subtype = 'PERCENTAGE')
654     bpy.types.Scene.subpolygon1 = bpy.props.BoolProperty(name="1", default = True)
655     bpy.types.Scene.subpolygon2 = bpy.props.BoolProperty(name="2", default = True)
656     bpy.types.Scene.subpolygon3 = bpy.props.BoolProperty(name="3", default = True)
657     bpy.types.Scene.subpolygon4 = bpy.props.BoolProperty(name="4", default = True)
658    
659     # Doodads buttons:
660     bpy.types.Scene.dodoodads = bpy.props.BoolProperty(name="Make doodads", description = "Check if we want to generate doodads", default = True)
661     bpy.types.Scene.mindoodads = bpy.props.IntProperty(name="Minimum doodads number", description = "Ask for the minimum number of doodads to generate per polygon", default = 1, min = 0, max = 50)
662     bpy.types.Scene.maxdoodads = bpy.props.IntProperty(name="Maximum doodads number", description = "Ask for the maximum number of doodads to generate per polygon", default = 6, min = 1, max = 50)
663     bpy.types.Scene.doodMinScale = bpy.props.FloatProperty(name="Scale min", description="Minimum scaling of doodad", default = 0.5, min = 0.0, max = 1.0, subtype = 'PERCENTAGE')
664     bpy.types.Scene.doodMaxScale = bpy.props.FloatProperty(name="Scale max", description="Maximum scaling of doodad", default = 1.0, min = 0.0, max = 1.0, subtype = 'PERCENTAGE')
665    
666     # Materials buttons:
667     bpy.types.Scene.sideProtMat = bpy.props.IntProperty(name="Side's prot mat", description = "Material of protusion's sides", default = 0, min = 0)
668     bpy.types.Scene.topProtMat = bpy.props.IntProperty(name = "Prot's top mat", description = "Material of protusion's top", default = 0, min = 0)
669    
670     bpy.utils.register_class(discombobulator)
671     bpy.utils.register_class(chooseDoodad)
672     bpy.utils.register_class(unchooseDoodad)
673     bpy.utils.register_class(VIEW3D_PT_tools_discombobulate)
674     bpy.utils.register_class(discombob_help)
675  
676 # unregistering and removing menus
677 def unregister():
678     bpy.utils.unregister_class(discombobulator)
679     bpy.utils.unregister_class(chooseDoodad)
680     bpy.utils.unregister_class(unchooseDoodad)
681     bpy.utils.unregister_class(VIEW3D_PT_tools_discombobulate)
682     bpy.utils.unregister_class(discombob_help)
683  
684 if __name__ == "__main__":
685     register()