88 lines · 2.8 KB
Raw Download
1
# <pep8 compliant>
2
#  This program is free software; you can redistribute it and/or
3
#  modify it under the terms of the GNU General Public License
4
#  as published by the Free Software Foundation; either version 2
5
#  of the License, or (at your option) any later version.
6
#
7
#  This program is distributed in the hope that it will be useful,
8
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
9
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
#  GNU General Public License for more details.
11
#
12
#  You should have received a copy of the GNU General Public License
13
#  along with this program; if not, write to the Free Software Foundation,
14
#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15
16
import bpy
17
18
# https://www.youtube.com/watch?v=mN3n9b98HMk was helpful, thanks!
19
20
# CHANGELOG
21
# v 1.0 May 2024 - Positive Cube
22
#   ☒ Initial Add-on, add positive and negative cube.
23
# v 1.1 March 2026
24
#   ☒ Simplified, condensed code
25
#   ☒ Changed selection functionality to deselect all before adding geometry
26
27
bl_info = {
28
    "name": "Add Positive Cube",
29
    "description": "Adds a cube with its origin at the corner.",
30
    "author": "Jeff Lange @jefftml",
31
    "version": (1, 1),
32
    "blender": (2, 80, 0),
33
    "location": "View3D > Add > Mesh",
34
    "category": "Add Mesh",
35
}
36
37
FACES = [(3, 2, 1, 0), (0, 1, 5, 4), (1, 2, 6, 5),
38
         (2, 3, 7, 6), (3, 0, 4, 7), (4, 5, 6, 7)]
39
40
VERTS = [(0, 0, 0), (1, 0, 0), (1, 1, 0), (0, 1, 0),
41
         (0, 0, 1), (1, 0, 1), (1, 1, 1), (0, 1, 1)]
42
43
44
def add_corner_cube(context, s=1):
45
    v = [(s * x, s * y, s * z) for x, y, z in VERTS]
46
    faces = [f[::-1] for f in FACES] if s < 0 else FACES
47
    mesh = bpy.data.meshes.new("cube")
48
    mesh.from_pydata(v, [], faces)
49
    obj = bpy.data.objects.new(
50
        ("Positive" if s > 0 else "Negative") + " Cube", mesh)
51
    context.collection.objects.link(obj)
52
    bpy.ops.object.select_all(action='DESELECT')
53
    context.view_layer.objects.active = obj
54
    obj.select_set(True)
55
    obj.matrix_world = context.scene.cursor.matrix
56
    return {'FINISHED'}
57
58
59
def make_op(label, idname, s):
60
    class Op(bpy.types.Operator):
61
        bl_idname, bl_label, bl_options = idname, label, {'REGISTER', 'UNDO'}
62
        def execute(self, ctx): return add_corner_cube(ctx, s)
63
    Op.__name__ = idname.split('.')[1]
64
    return Op
65
66
67
CLASSES = [make_op("Positive Cube", "mesh.positive_cube", 1),
68
           make_op("Negative Cube", "mesh.negative_cube", -1)]
69
70
71
def menu_func(self, context):
72
    self.layout.operator(CLASSES[0].bl_idname, icon='MESH_CUBE')
73
    self.layout.operator(CLASSES[1].bl_idname, icon='CUBE')
74
75
76
def register():
77
    [bpy.utils.register_class(c) for c in CLASSES]
78
    bpy.types.VIEW3D_MT_mesh_add.append(menu_func)
79
80
81
def unregister():
82
    [bpy.utils.unregister_class(c) for c in CLASSES]
83
    bpy.types.VIEW3D_MT_mesh_add.remove(menu_func)
84
85
86
if __name__ == "__main__":
87
    register()
88