object_creaprim.py 16.4 KB
Newer Older
1
# ###### BEGIN GPL LICENSE BLOCK ######
2 3 4 5 6 7 8 9
#
# 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
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 12 13 14 15 16 17
# GNU General Public License for more details.
#
# If you have Internet access, you can find the license text at
# http://www.gnu.org/licenses/gpl.txt,
# if not, write to the Free Software Foundation,
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
18 19
# ###### END GPL LICENCE BLOCK ######

20

21 22
"""
CreaPrim does what it says. I takes the active object and turns it into an
23
Add Mesh addon. When you enable this, your custom object will be added to the
24
Add->Mesh menu.
25 26 27 28


Documentation

29 30 31 32 33 34 35 36 37 38 39 40
Go to User Preferences->Addons and enable the CreaPrim addon in the Object
section. The addon will show up in the 3dview properties panel.

First select your object or objects.
The name (in panel) will be set to the active object name.
Select "Apply transform" if you want transforms to be applied to the selected
objects. Modifiers will taken into account. You can always change this.
Just hit the button and the selected objects will be saved in your addons folder
as an Add Mesh addon with the name "add_mesh_XXXX.py" with XXXX being your
object name.  The addon will show up in User Preferences->Addons in the
Add Mesh section. Enable this addon et voila, your new custom primitive will
now show up in the Add Mesh menu.
41 42

REMARK - dont need to be admin anymore - saves to user scripts dir
43 44 45

ALSO - dont forget to Apply rotation and scale to have your object
show up correctly
46 47 48
"""

bl_info = {
Brendon Murphy's avatar
Brendon Murphy committed
49 50
    "name": "CreaPrim",
    "author": "Gert De Roost",
51
    "version": (0, 3, 11),
52
    "blender": (2, 80, 0),
Brendon Murphy's avatar
Brendon Murphy committed
53 54
    "location": "View3D > Object Tools",
    "description": "Create primitive addon",
55
    "warning": "under construction",
56
    "doc_url": "",
57
    "tracker_url": "https://developer.blender.org/maniphest/task/edit/form/2/",
Brendon Murphy's avatar
Brendon Murphy committed
58
    "category": "Object"}
59

60

61 62 63 64 65 66 67 68 69
import bpy
import bmesh
import os


started = 0
oldname = ""


70 71 72 73
def test_data(obj):
    me = obj.data
    is_faces = bool(len(me.polygons) > 0)
    return is_faces
74 75 76


class CreaPrim(bpy.types.Operator):
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
    bl_idname = "object.creaprim"
    bl_label = "CreaPrim"
    bl_description = "Create a primitive add-on"
    bl_options = {"REGISTER"}

    @classmethod
    def poll(cls, context):
        obj = context.active_object
        return (obj and obj.type == 'MESH' and context.mode == 'OBJECT')

    def invoke(self, context, event):

        global oldname, groupname, message

        scn = bpy.context.scene

        objlist = []
        for selobj in bpy.context.scene.objects:
95
            if selobj.select_get() and test_data(selobj) is True:
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
                objlist.append(selobj)

        if len(objlist) == 0:
            self.report({'WARNING'},
                        "Please select Mesh objects containing Polygons. Operation Cancelled")
            return {"CANCELLED"}

        try:
            direc = bpy.utils.script_paths()[1]
            scriptdir = 1
        except:
            direc = bpy.utils.script_paths()[0]
            scriptdir = 0

        if len(objlist) > 1:
            groupname = scn.Creaprim_Name
            groupname = groupname.replace(".", "")
            addondir = direc + os.sep + "addons" + os.sep + "add_mesh_" + groupname + os.sep
            if not os.path.exists(addondir):
                os.makedirs(addondir)
        else:
            groupname = scn.Creaprim_Name
            print(bpy.utils.script_paths())
            addondir = direc + os.sep + "addons" + os.sep
            print(addondir)
            if not os.path.exists(addondir):
                os.makedirs(addondir)

124
        actobj = context.view_layer.objects.active
125 126 127 128 129 130 131 132 133 134 135
        txtlist = []
        namelist = []
        for selobj in objlist:
            if len(objlist) == 1:
                objname = scn.Creaprim_Name
                objname = objname.replace(" ", "_")
            else:
                objname = selobj.name
                objname = objname.replace(".", "")
                objname = objname.replace(" ", "_")
                namelist.append(objname)
136
            mesh = selobj.to_mesh(preserve_all_data_layers=False, depsgraph=None)
137
            oldname = selobj.name
138
            context.view_layer.objects.active = selobj
139 140 141 142 143 144 145 146 147 148 149

            if scn.Creaprim_Apply:
                bpy.ops.object.transform_apply(location=False, rotation=True, scale=True)
            txt = do_creaprim(self, mesh, objname, addondir)

            if txt == 0:
                return {'CANCELLED'}

            txtlist.append(txt)

        oldname = actobj.name
150
        context.view_layer.objects.active = actobj
151 152 153

        if len(txtlist) > 1:
            makeinit(txtlist, namelist, groupname, addondir)
154
            bpy.ops.preferences.addon_enable(module="add_mesh_" + groupname)
155
        else:
156
            bpy.ops.preferences.addon_enable(module="add_mesh_" + str.lower(objname))
157 158 159 160 161 162 163 164

        if scriptdir == 1:
            message = "Add Mesh addon " + groupname + " saved to user scripts directory."
        else:
            message = "Add Mesh addon " + groupname + " saved to main scripts directory."
        bpy.ops.creaprim.message('INVOKE_DEFAULT')

        return {'FINISHED'}
165 166 167


class MessageOperator(bpy.types.Operator):
168 169 170 171 172
    bl_idname = "creaprim.message"
    bl_label = "Saved"

    def invoke(self, context, event):
        wm = context.window_manager
173
        return wm.invoke_popup(self, width=500)
174

175
    def draw(self, context):
176

177
        global groupname
178

179 180 181 182
        layout = self.layout
        row = layout.row()
        row.label(text='', icon="PLUGIN")
        row.label(message)
183 184


185
def panel_func(self, context):
186

187 188 189
    global started

    scn = bpy.context.scene
190

191 192 193 194
    self.layout.label(text="CreaPrim:")
    self.layout.operator("object.creaprim", text="Create primitive", icon='PLUGIN')
    self.layout.prop(scn, "Creaprim_Name")
    self.layout.prop(scn, "Creaprim_Apply")
195

196

197 198 199 200 201
classes = (
    CreaPrim,
    MessageOperator)


202
def register():
203 204 205
    for cls in classes:
        bpy.utils.register_class(cls)
    #bpy.utils.register_module(__name__)
206 207 208 209 210 211 212 213 214 215
    bpy.types.Scene.Creaprim_Name = bpy.props.StringProperty(
            name="Name",
            description="Name for the primitive",
            maxlen=1024
            )
    bpy.types.Scene.Creaprim_Apply = bpy.props.BoolProperty(
            name="Apply transform",
            description="Apply transform to selected objects",
            default=False
            )
216
    #bpy.types.VIEW3D_PT_tools_object.append(panel_func)
217
    bpy.types.OBJECT_PT_context_object.append(panel_func)
218 219
    #bpy.app.handlers.scene_update_post.append(setname)
    bpy.app.handlers.depsgraph_update_post.append(setname)
220

221

222
def unregister():
223 224 225 226
    #bpy.utils.unregister_module(__name__)
    for cls in reversed(classes):
        bpy.utils.unregister_class(cls)
    #bpy.types.VIEW3D_PT_tools_object.remove(panel_func)
227
    bpy.types.OBJECT_PT_context_object.remove(panel_func)
228 229
    #bpy.app.handlers.scene_update_post.remove(setname)
    bpy.app.handlers.depsgraph_update_post.remove(setname)
230 231
    del bpy.types.Scene.Creaprim_Name
    del bpy.types.Scene.Creaprim_Apply
232 233


234 235
if __name__ == "__main__":
    register()
236 237 238


def do_creaprim(self, mesh, objname, addondir):
239

240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259
    global message

    objname = objname.replace(".", "")
    objname = objname.replace(" ", "_")
    bm = bmesh.new()
    bm.from_mesh(mesh)

    try:
        txt = bpy.data.texts[str.lower("add_mesh_" + objname) + ".py"]
        txt.clear()
    except:
        txt = bpy.data.texts.new("add_mesh_" + str.lower(objname) + ".py")

    strlist = []
    strlist.append("# Script autogenerated by object_creaprim.py")
    strlist.append("\n")
    strlist.append("bl_info = {\n")
    strlist.append("    \"name\": \"" + objname + "\",\n")
    strlist.append("    \"author\": \"Gert De Roost\",\n")
    strlist.append("    \"version\": (1, 0, 0),\n")
260
    strlist.append("    \"blender\": (2, 80, 0),\n")
261 262 263
    strlist.append("    \"location\": \"Add > Mesh\",\n")
    strlist.append("    \"description\": \"Create " + objname + " primitive\",\n")
    strlist.append("    \"warning\": \"\",\n")
264
    strlist.append("    \"doc_url\": \"\",\n")
265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284
    strlist.append("    \"tracker_url\": \"\",\n")
    strlist.append("    \"category\": \"Add Mesh\"}\n")
    strlist.append("\n")
    strlist.append("\n")
    strlist.append("import bpy\n")
    strlist.append("import bmesh\n")
    strlist.append("import math\n")
    strlist.append("from mathutils import *\n")
    strlist.append("\n")
    strlist.append("\n")
    strlist.append("class " + objname + "(bpy.types.Operator):\n")
    strlist.append("    bl_idname = \"mesh." + str.lower(objname) + "\"\n")
    strlist.append("    bl_label = \"" + objname + "\"\n")
    strlist.append("    bl_options = {\'REGISTER\', \'UNDO\'}\n")
    strlist.append("    bl_description = \"add " + objname + " primitive\"\n")
    strlist.append("\n")
    strlist.append("    def invoke(self, context, event):\n")
    strlist.append("\n")
    strlist.append("        mesh = bpy.data.meshes.new(name=\"" + objname + "\")\n")
    strlist.append("        obj = bpy.data.objects.new(name=\"" + objname + "\", object_data=mesh)\n")
285
    strlist.append("        collection = bpy.context.collection\n")
286
    strlist.append("        scene = bpy.context.scene\n")
287
    strlist.append("        collection.objects.link(obj)\n")
288
    strlist.append("        obj.location = scene.cursor.location\n")
289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355
    strlist.append("        bm = bmesh.new()\n")
    strlist.append("        bm.from_mesh(mesh)\n")
    strlist.append("\n")
    strlist.append("        idxlist = []\n")
    posn = 0
    strlist.append("        vertlist = [")
    for v in bm.verts:
        if posn > 0:
            strlist.append(", ")
        posn += 1
        strlist.append(str(v.co[:]))
    strlist.append("]\n")
    strlist.append("        for co in vertlist:\n")
    strlist.append("            v = bm.verts.new(co)\n")
    strlist.append("            bm.verts.index_update()\n")
    strlist.append("            idxlist.append(v.index)\n")
    posn = 0
    strlist.append("        edgelist = [")
    for e in bm.edges:
        if posn > 0:
            strlist.append(", ")
        posn += 1
        strlist.append("[" + str(e.verts[0].index) + ", " + str(e.verts[1].index) + "]")
    strlist.append("]\n")
    strlist.append("        for verts in edgelist:\n")
    strlist.append("            try:\n")
    strlist.append("                bm.edges.new((bm.verts[verts[0]], bm.verts[verts[1]]))\n")
    strlist.append("            except:\n")
    strlist.append("                pass\n")
    posn1 = 0
    strlist.append("        facelist = [(")
    for f in bm.faces:
        if posn1 > 0:
            strlist.append(", (")
        posn1 += 1
        posn2 = 0
        for v in f.verts:
            if posn2 > 0:
                strlist.append(", ")
            strlist.append(str(v.index))
            posn2 += 1
        strlist.append(")")
    strlist.append("]\n")
    strlist.append("        bm.verts.ensure_lookup_table()\n")
    strlist.append("        for verts in facelist:\n")
    strlist.append("            vlist = []\n")
    strlist.append("            for idx in verts:\n")
    strlist.append("                vlist.append(bm.verts[idxlist[idx]])\n")
    strlist.append("            try:\n")
    strlist.append("                bm.faces.new(vlist)\n")
    strlist.append("            except:\n")
    strlist.append("                pass\n")
    strlist.append("\n")
    strlist.append("        bm.to_mesh(mesh)\n")
    strlist.append("        mesh.update()\n")
    strlist.append("        bm.free()\n")
    strlist.append("        obj.rotation_quaternion = (Matrix.Rotation(math.radians(90), 3, \'X\').to_quaternion())\n")
    strlist.append("\n")
    strlist.append("        return {\'FINISHED\'}\n")

    strlist.append("\n")
    strlist.append("\n")
    strlist.append("def menu_item(self, context):\n")
    strlist.append("    self.layout.operator(" + objname + ".bl_idname, text=\"" + objname + "\", icon=\"PLUGIN\")\n")
    strlist.append("\n")
    strlist.append("\n")
    strlist.append("def register():\n")
356
    strlist.append("    bpy.utils.register_class(__name__)\n")
357
    strlist.append("    bpy.types.VIEW3D_MT_mesh_add.append(menu_item)\n")
358 359 360
    strlist.append("\n")
    strlist.append("\n")
    strlist.append("def unregister():\n")
361
    strlist.append("    bpy.utils.unregister_class(__name__)\n")
362
    strlist.append("    bpy.types.VIEW3D_MT_mesh_add.remove(menu_item)\n")
363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382
    strlist.append("\n")
    strlist.append("\n")
    strlist.append("if __name__ == \"__main__\":\n")
    strlist.append("    register()\n")
    endstring = ''.join(strlist)
    txt.write(endstring)

    try:
        fileobj = open(addondir + "add_mesh_" + str.lower(objname) + ".py", "w")
    except:
        message = "Permission problem - cant write file - run Blender as Administrator!"
        bpy.ops.creaprim.message('INVOKE_DEFAULT')
        return 0

    fileobj.write(endstring)
    fileobj.close()

    bm.free()

    return txt
383 384


385
def makeinit(txtlist, namelist, groupname, addondir):
386

387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405
    global message

    try:
        txt = bpy.data.texts["__init__.py"]
        txt.clear()
    except:
        txt = bpy.data.texts.new("__init__.py")

    strlist = []
    strlist.append("# Script autogenerated by object_creaprim.py")
    strlist.append("\n")
    strlist.append("bl_info = {\n")
    strlist.append("    \"name\": \"" + groupname + "\",\n")
    strlist.append("    \"author\": \"Gert De Roost\",\n")
    strlist.append("    \"version\": (1, 0, 0),\n")
    strlist.append("    \"blender\": (2, 65, 0),\n")
    strlist.append("    \"location\": \"Add > Mesh\",\n")
    strlist.append("    \"description\": \"Create " + groupname + " primitive group\",\n")
    strlist.append("    \"warning\": \"\",\n")
406
    strlist.append("    \"doc_url\": \"\",\n")
407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426
    strlist.append("    \"tracker_url\": \"\",\n")
    strlist.append("    \"category\": \"Add Mesh\"}\n")
    strlist.append("\n")
    strlist.append("\n")
    strlist.append("if \"bpy\" in locals():\n")
    strlist.append("    import importlib\n")
    addonlist = []
    for txt in txtlist:
        name = txt.name.replace(".py", "")
        addonlist.append(name)
    for name in addonlist:
        strlist.append("    importlib.reload(" + name + ")\n")
    strlist.append("else:\n")
    for name in addonlist:
        strlist.append("    from . import " + name + "\n")
    strlist.append("\n")
    strlist.append("\n")
    strlist.append("import bpy\n")
    strlist.append("\n")
    strlist.append("\n")
427 428
    strlist.append("class VIEW3D_MT_mesh_" + str.lower(groupname) + "_add(bpy.types.Menu):\n")
    strlist.append("    bl_idname = \"VIEW3D_MT_mesh_" + str.lower(groupname) + "_add\"\n")
429 430 431 432 433 434 435 436 437 438
    strlist.append("    bl_label = \"" + groupname + "\"\n")
    strlist.append("\n")
    strlist.append("    def draw(self, context):\n")
    strlist.append("        layout = self.layout\n")

    for name in namelist:
        strlist.append("        layout.operator(\"mesh." + str.lower(name) + "\", text=\"" + name + "\")\n")
    strlist.append("\n")
    strlist.append("\n")
    strlist.append("def menu_item(self, context):\n")
439
    strlist.append("    self.layout.menu(\"VIEW3D_MT_mesh_" + str.lower(groupname) + "_add\", icon=\"PLUGIN\")\n")
440 441 442 443
    strlist.append("\n")
    strlist.append("\n")
    strlist.append("def register():\n")
    strlist.append("    bpy.utils.register_module(__name__)\n")
444
    strlist.append("    bpy.types.VIEW3D_MT_mesh_add.append(menu_item)\n")
445 446 447 448
    strlist.append("\n")
    strlist.append("\n")
    strlist.append("def unregister():\n")
    strlist.append("    bpy.utils.unregister_module(__name__)\n")
449
    strlist.append("    bpy.types.VIEW3D_MT_mesh_add.remove(menu_item)\n")
450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465
    strlist.append("\n")
    strlist.append("\n")
    strlist.append("if __name__ == \"__main__\":\n")
    strlist.append("    register()\n")
    endstring = ''.join(strlist)
    txt.write(endstring)

    try:
        fileobj = open(addondir + "__init__.py", "w")
    except:
        message = "Permission problem - cant write file - run Blender as Administrator!"
        bpy.ops.creaprim.message('INVOKE_DEFAULT')
        return 0

    fileobj.write(endstring)
    fileobj.close()
466 467 468


def setname(dummy):
469

470 471
    scn = bpy.context.scene
    oldname = scn.Creaprim_Name
472

473
    if bpy.context.active_object and bpy.context.active_object.name != oldname:
474

475
        scn.Creaprim_Name = bpy.context.active_object.name