Fix for access of undefined ground object in UI code giving pointless
[blender-addons-contrib.git] / object_creaprim.py
1
2 # ***** BEGIN GPL LICENSE BLOCK *****
3 #
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 # GNU General Public License for more details.
13 #
14 # If you have Internet access, you can find the license text at
15 # http://www.gnu.org/licenses/gpl.txt,
16 # if not, write to the Free Software Foundation,
17 # Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 #
19 # ***** END GPL LICENCE BLOCK *****
20 # --------------------------------------------------------------------------
21
22 """
23 CreaPrim does what it says. I takes the active object and turns it into an
24 Add Mesh addon. When you enable this, your custom object will be added to the
25 Add->Mesh menu.
26
27
28 Documentation
29
30 Go to User Preferences->Addons and enable the CreaPrim addon in the Object
31 section. The addon will show up in the 3dview properties panel.
32
33 First select your object or objects.
34 The name (in panel) will be set to the active object name.
35 Select "Apply transform" if you want transforms to be applied to the selected
36 objects. Modifiers will taken into account. You can always change this.
37 Just hit the button and the selected objects will be saved in your addons folder
38 as an Add Mesh addon with the name "add_mesh_XXXX.py" with XXXX being your
39 object name.  The addon will show up in User Preferences->Addons in the
40 Add Mesh section. Enable this addon et voila, your new custom primitive will
41 now show up in the Add Mesh menu.
42
43 REMARK - dont need to be admin anymore - saves to user scripts dir
44
45 ALSO - dont forget to Apply rotation and scale to have your object
46 show up correctly
47 """
48
49 bl_info = {
50     "name": "CreaPrim",
51     "author": "Gert De Roost",
52     "version": (0, 3, 10),
53     "blender": (2, 64, 0),
54     "location": "View3D > Object Tools",
55     "description": "Create primitive addon",
56     "warning": "",
57     "wiki_url": "",
58     "tracker_url": "https://developer.blender.org/T32801",
59     "category": "Object"}
60
61
62 if "bpy" in locals():
63         import imp
64
65
66 import bpy
67 import bmesh
68 import os
69
70
71 started = 0
72 oldname = ""
73
74 bpy.types.Scene.Name = bpy.props.StringProperty(
75                         name="Name",
76                         description="name for primitive",
77                         maxlen= 1024)
78
79 bpy.types.Scene.Apply = bpy.props.BoolProperty(
80                 name = "Apply transform",
81                 description = "apply transform to selected objects",
82                 default = False)
83
84
85 class CreaPrim(bpy.types.Operator):
86         bl_idname = "object.creaprim"
87         bl_label = "CreaPrim"
88         bl_description = "Create primitive addon"
89         bl_options = {"REGISTER"}
90
91
92         @classmethod
93         def poll(cls, context):
94                 obj = context.active_object
95                 return (obj and obj.type == 'MESH' and context.mode == 'OBJECT')
96
97         def invoke(self, context, event):
98
99                 global oldname, groupname, message
100
101                 scn = bpy.context.scene
102
103                 objlist = []
104                 for selobj in bpy.context.scene.objects:
105                         if selobj.select:
106                                 objlist.append(selobj)
107
108                 try:
109                         direc = bpy.utils.script_paths()[1]
110                         scriptdir = 1
111                 except:
112                         direc = bpy.utils.script_paths()[0]
113                         scriptdir = 0
114                 if len(objlist) > 1:
115                         groupname = scn.Name
116                         groupname = groupname.replace(".", "")
117                         addondir = direc + os.sep + "addons" + os.sep + "add_mesh_" + groupname + os.sep
118                         if not os.path.exists(addondir):
119                                 os.makedirs(addondir)
120                 else:
121                         groupname = scn.Name
122                         print (bpy.utils.script_paths())
123                         addondir = direc + os.sep + "addons" + os.sep
124                         print (addondir)
125                         if not os.path.exists(addondir):
126                                 os.makedirs(addondir)
127
128                 actobj = bpy.context.active_object
129                 txtlist = []
130                 namelist = []
131                 for selobj in objlist:
132                         if len(objlist) == 1:
133                                 objname = scn.Name
134                                 objname = objname.replace(" ", "_")
135                         else:
136                                 objname = selobj.name
137                                 objname = objname.replace(".", "")
138                                 objname = objname.replace(" ", "_")
139                                 namelist.append(objname)
140                         mesh = selobj.to_mesh(scn, True, "PREVIEW")
141                         oldname = selobj.name
142                         scn.objects.active = selobj
143                         if scn.Apply:
144                                 bpy.ops.object.transform_apply(location=False, rotation=True, scale=True)
145                         txt = do_creaprim(self, mesh, objname, addondir)
146                         if txt == 0:
147                                 return {'CANCELLED'}
148                         txtlist.append(txt)
149                 oldname = actobj.name
150                 scn.objects.active = actobj
151
152                 if len(txtlist) > 1:
153                         makeinit(txtlist, namelist, groupname, addondir)
154                         bpy.ops.wm.addon_enable(module="add_mesh_" + groupname)
155                 else:
156                         bpy.ops.wm.addon_enable(module="add_mesh_" + str.lower(objname))
157
158                 if scriptdir == 1:
159                         message = "Add Mesh addon " + groupname + " saved to user scripts directory."
160                 else:
161                         message = "Add Mesh addon " + groupname + " saved to main scripts directory."
162                 bpy.ops.creaprim.message('INVOKE_DEFAULT')
163
164                 return {'FINISHED'}
165
166
167 class MessageOperator(bpy.types.Operator):
168         bl_idname = "creaprim.message"
169         bl_label = "Saved"
170
171         def invoke(self, context, event):
172                 wm = context.window_manager
173                 return wm.invoke_popup(self, width=500, height=20)
174                 return {'FINISHED'}
175
176         def draw(self, context):
177
178                 global groupname
179
180                 layout = self.layout
181                 row = layout.row()
182                 row.label(text = '', icon = "PLUGIN")
183                 row.label(message)
184
185 def panel_func(self, context):
186
187         global started
188
189         scn = bpy.context.scene
190
191         self.layout.label(text="CreaPrim:")
192         self.layout.operator("object.creaprim", text="Create primitive", icon = 'PLUGIN')
193         self.layout.prop(scn, "Name")
194         self.layout.prop(scn, "Apply")
195
196 def register():
197         bpy.utils.register_module(__name__)
198         bpy.types.VIEW3D_PT_tools_objectmode.append(panel_func)
199         bpy.app.handlers.scene_update_post.append(setname)
200
201 def unregister():
202         bpy.utils.unregister_module(__name__)
203         bpy.types.VIEW3D_PT_tools_objectmode.remove(panel_func)
204         bpy.app.handlers.scene_update_post.remove(setname)
205
206 if __name__ == "__main__":
207         register()
208
209
210
211
212 def do_creaprim(self, mesh, objname, addondir):
213
214         global message
215
216         objname = objname.replace(".", "")
217         objname = objname.replace(" ", "_")
218         bm = bmesh.new()
219         bm.from_mesh(mesh)
220
221
222         try:
223                 txt = bpy.data.texts[str.lower("add_mesh_" + objname) + ".py"]
224                 txt.clear()
225         except:
226                 txt = bpy.data.texts.new("add_mesh_" + str.lower(objname) + ".py")
227
228         strlist = []
229         strlist.append("bl_info = {\n")
230         strlist.append("\"name\": \"" + objname + "\", \n")
231         strlist.append("\"author\": \"Gert De Roost\",\n")
232         strlist.append("\"version\": (1, 0, 0),\n")
233         strlist.append("\"blender\": (2, 65, 0),\n")
234         strlist.append("\"location\": \"Add > Mesh\",\n")
235         strlist.append("\"description\": \"Create " + objname + " primitive.\",\n")
236         strlist.append("\"warning\": \"\",\n")
237         strlist.append("\"wiki_url\": \"\",\n")
238         strlist.append("\"tracker_url\": \"\",\n")
239         strlist.append("\"category\": \"Add Mesh\"}\n")
240         strlist.append("\n")
241         strlist.append("\n")
242         strlist.append("if \"bpy\" in locals():\n")
243         strlist.append("           import imp\n")
244         strlist.append("\n")
245         strlist.append("\n")
246         strlist.append("import bpy\n")
247         strlist.append("import bmesh\n")
248         strlist.append("import math\n")
249         strlist.append("from mathutils import *\n")
250         strlist.append("\n")
251         strlist.append("\n")
252         strlist.append("\n")
253         strlist.append("\n")
254         strlist.append("class " + objname + "(bpy.types.Operator):\n")
255         strlist.append("        bl_idname = \"mesh." + str.lower(objname) + "\"\n")
256         strlist.append("        bl_label = \"" + objname + "\"\n")
257         strlist.append("        bl_options = {\'REGISTER\', \'UNDO\'}\n")
258         strlist.append("        bl_description = \"add " + objname + " primitive\"\n")
259         strlist.append("\n")
260         strlist.append("        def invoke(self, context, event):\n")
261         strlist.append("\n")
262         strlist.append("                mesh = bpy.data.meshes.new(name=\"" + objname + "\")\n")
263         strlist.append("                obj = bpy.data.objects.new(name=\"" + objname + "\", object_data=mesh)\n")
264         strlist.append("                scene = bpy.context.scene\n")
265         strlist.append("                scene.objects.link(obj)\n")
266         strlist.append("                obj.location = scene.cursor_location\n")
267         strlist.append("                bm = bmesh.new()\n")
268         strlist.append("                bm.from_mesh(mesh)\n")
269         strlist.append("\n")
270         strlist.append("                idxlist = []\n")
271         posn = 0
272         strlist.append("                vertlist = [")
273         for v in bm.verts:
274                 if posn > 0:
275                         strlist.append(", ")
276                 posn += 1
277                 strlist.append(str(v.co[:]))
278         strlist.append("]\n")
279         strlist.append("                for co in vertlist:\n")
280         strlist.append("                        v = bm.verts.new(co)\n")
281         strlist.append("                        bm.verts.index_update()\n")
282         strlist.append("                        idxlist.append(v.index)\n")
283         posn = 0
284         strlist.append("                edgelist = [")
285         for e in bm.edges:
286                 if posn > 0:
287                         strlist.append(", ")
288                 posn += 1
289                 strlist.append("[" + str(e.verts[0].index) + ", " + str(e.verts[1].index) + "]")
290         strlist.append("]\n")
291         strlist.append("                for verts in edgelist:\n")
292         strlist.append("                        try:\n")
293         strlist.append("                                bm.edges.new((bm.verts[verts[0]], bm.verts[verts[1]]))\n")
294         strlist.append("                        except:\n")
295         strlist.append("                                pass\n")
296         posn1 = 0
297         strlist.append("                facelist = [(")
298         for f in bm.faces:
299                 if posn1 > 0:
300                         strlist.append(", (")
301                 posn1 += 1
302                 posn2 = 0
303                 for v in f.verts:
304                         if posn2 > 0:
305                                 strlist.append(", ")
306                         strlist.append(str(v.index))
307                         posn2 += 1
308                 strlist.append(")")
309         strlist.append("]\n")
310         strlist.append("                for verts in facelist:\n")
311         strlist.append("                        vlist = []\n")
312         strlist.append("                        for idx in verts:\n")
313         strlist.append("                                vlist.append(bm.verts[idxlist[idx]])\n")
314         strlist.append("                        try:\n")
315         strlist.append("                                bm.faces.new(vlist)\n")
316         strlist.append("                        except:\n")
317         strlist.append("                                pass\n")
318         strlist.append("\n")
319         strlist.append("                bm.to_mesh(mesh)\n")
320         strlist.append("                mesh.update()\n")
321         strlist.append("                bm.free()\n")
322         strlist.append("                obj.rotation_quaternion = (Matrix.Rotation(math.radians(90), 3, \'X\').to_quaternion())\n")
323         strlist.append("\n")
324         strlist.append("                return {\'FINISHED\'}\n")
325
326         strlist.append("\n")
327         strlist.append("\n")
328         strlist.append("\n")
329         strlist.append("\n")
330         strlist.append("def menu_item(self, context):\n")
331         strlist.append("           self.layout.operator(" + objname + ".bl_idname, text=\"" + objname + "\", icon=\"PLUGIN\")\n")
332         strlist.append("\n")
333         strlist.append("def register():\n")
334         strlist.append("           bpy.utils.register_module(__name__)\n")
335         strlist.append("           bpy.types.INFO_MT_mesh_add.append(menu_item)\n")
336         strlist.append("\n")
337         strlist.append("def unregister():\n")
338         strlist.append("           bpy.utils.unregister_module(__name__)\n")
339         strlist.append("           bpy.types.INFO_MT_mesh_add.remove(menu_item)\n")
340         strlist.append("\n")
341         strlist.append("if __name__ == \"__main__\":\n")
342         strlist.append("           register()\n")
343         endstring = ''.join(strlist)
344         txt.write(endstring)
345
346         try:
347                 fileobj = open(addondir + "add_mesh_" + str.lower(objname) + ".py", "w")
348         except:
349                 message = "Permission problem - cant write file - run Blender as Administrator!"
350                 bpy.ops.creaprim.message('INVOKE_DEFAULT')
351                 return 0
352
353         fileobj.write(endstring)
354         fileobj.close()
355
356         bm.free()
357
358         return txt
359
360
361 def makeinit(txtlist, namelist, groupname, addondir):
362
363         global message
364
365         try:
366                 txt = bpy.data.texts["__init__.py"]
367                 txt.clear()
368         except:
369                 txt = bpy.data.texts.new("__init__.py")
370
371         strlist = []
372         strlist.append("bl_info = {\n")
373         strlist.append("\"name\": \"" + groupname + "\", \n")
374         strlist.append("\"author\": \"Gert De Roost\",\n")
375         strlist.append("\"version\": (1, 0, 0),\n")
376         strlist.append("\"blender\": (2, 65, 0),\n")
377         strlist.append("\"location\": \"Add > Mesh\",\n")
378         strlist.append("\"description\": \"Create " + groupname + " primitive group.\",\n")
379         strlist.append("\"warning\": \"\",\n")
380         strlist.append("\"wiki_url\": \"\",\n")
381         strlist.append("\"tracker_url\": \"\",\n")
382         strlist.append("\"category\": \"Add Mesh\"}\n")
383         strlist.append("\n")
384         strlist.append("\n")
385         strlist.append("if \"bpy\" in locals():\n")
386         strlist.append("        import imp\n")
387         addonlist = []
388         for txt in txtlist:
389                 name = txt.name.replace(".py", "")
390                 addonlist.append(name)
391         for name in addonlist:
392                 strlist.append("        imp.reload(" + name + ")\n")
393         strlist.append("else:\n")
394         for name in addonlist:
395                 strlist.append("        from . import " + name + "\n")
396         strlist.append("\n")
397         strlist.append("\n")
398         strlist.append("import bpy\n")
399         strlist.append("\n")
400         strlist.append("\n")
401         strlist.append("\n")
402         strlist.append("\n")
403         strlist.append("class INFO_MT_mesh_" + str.lower(groupname) + "_add(bpy.types.Menu):\n")
404         strlist.append("        bl_idname = \"INFO_MT_mesh_" + str.lower(groupname) + "_add\"\n")
405         strlist.append("        bl_label = \"" + groupname + "\"\n")
406         strlist.append("\n")
407         strlist.append("        def draw(self, context):\n")
408         strlist.append("                layout = self.layout\n")
409 #                layout.operator_context = 'INVOKE_REGION_WIN'
410         for name in namelist:
411                 strlist.append("                layout.operator(\"mesh." + str.lower(name) + "\", text=\"" + name + "\")\n")
412         strlist.append("\n")
413         strlist.append("\n")
414         strlist.append("\n")
415         strlist.append("\n")
416         strlist.append("def menu_item(self, context):\n")
417         strlist.append("           self.layout.menu(\"INFO_MT_mesh_" + str.lower(groupname) + "_add\", icon=\"PLUGIN\")\n")
418         strlist.append("\n")
419         strlist.append("def register():\n")
420         strlist.append("           bpy.utils.register_module(__name__)\n")
421         strlist.append("           bpy.types.INFO_MT_mesh_add.append(menu_item)\n")
422         strlist.append("\n")
423         strlist.append("def unregister():\n")
424         strlist.append("           bpy.utils.unregister_module(__name__)\n")
425         strlist.append("           bpy.types.INFO_MT_mesh_add.remove(menu_item)\n")
426         strlist.append("\n")
427         strlist.append("if __name__ == \"__main__\":\n")
428         strlist.append("           register()\n")
429         endstring = ''.join(strlist)
430         txt.write(endstring)
431
432         try:
433                 fileobj = open(addondir + "__init__.py", "w")
434         except:
435                 message = "Permission problem - cant write file - run Blender as Administrator!"
436                 bpy.ops.creaprim.message('INVOKE_DEFAULT')
437                 return 0
438         fileobj.write(endstring)
439         fileobj.close()
440
441
442
443 def setname(dummy):
444
445         global oldname
446
447         scn = bpy.context.scene
448
449         if bpy.context.active_object.name != oldname:
450                 scn.Name = bpy.context.active_object.name
451                 oldname = scn.Name
452
453
454
455