Newer
Older
# ##### BEGIN GPL LICENSE BLOCK #####
#
# 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
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####
bl_info = {
'name': "Kjartans Scripts",
'author': "Kjartan Tysdal",
'location': '"Shift+Q" and also in EditMode "W-Specials/ KTools"',
'description': "Adds my personal collection of small handy scripts (mostly modeling tools)",
'category': "Mesh",
'version': (0, 2, 8),
'wiki_url': 'http://www.kjartantysdal.com/scripts',
}
meta-androcto
committed
from bpy.props import (
StringProperty,
IntProperty,
FloatProperty,
EnumProperty,
BoolProperty,
BoolVectorProperty,
FloatVectorProperty,
)
def checkScale(): # check if scale is 0 on any of the axis, if it is then set it to 0.01
y = -1
for x in bpy.context.object.scale:
y += 1
if x == 0.0:
bpy.context.object.scale[y] = 0.01
class lattice_to_selection(bpy.types.Operator):
"""Add a lattice deformer to the selection"""
bl_idname = "object.lattice_to_selection"
bl_label = "Lattice to Selection"
bl_options = {'REGISTER', 'UNDO'}
meta-androcto
committed
name = "Local",
description = "Orient the lattice to the active object",
default = True
)
meta-androcto
committed
name = "Parent to Lattice",
description = "Parents all the objects to the Lattice",
default = False
)
move_first: BoolProperty(name = "First in Modifier Stack", description = "Moves the lattice modifier to be first in the stack", default = False)
interpolation: bpy.props.EnumProperty(
meta-androcto
committed
items= (('KEY_LINEAR', 'Linear', 'Linear Interpolation'),
('KEY_CARDINAL', 'Cardinal', 'Cardinal Interpolation'),
('KEY_CATMULL_ROM', 'Catmull Rom', 'Catmull Rom Interpolation'),
('KEY_BSPLINE', 'BSpline', 'BSpline Interpolation')),
name = "Interpolation", default = 'KEY_BSPLINE')
seg_u: IntProperty( name = "Lattice U", default = 2, soft_min = 2)
seg_v: IntProperty( name = "Lattice V", default = 2, soft_min = 2 )
seg_w: IntProperty( name = "Lattice W", default = 2, soft_min = 2 )
apply_rot = not self.apply_rot # Global vs Local
parent_to = self.parent_to # Parents all the objects to the Lattice
move_first = self.move_first # moves the lattice modifier to be first in the stack
interpolation = self.interpolation
# check if there exists an active object
if bpy.context.view_layer.objects.active:
active_obj = bpy.context.view_layer.objects.active.name
else:
for x in bpy.context.selected_objects:
if bpy.data.objects[x.name].type == 'MESH':
bpy.context.view_layer.objects.active = bpy.data.objects[x.name]
active_obj = bpy.context.view_layer.objects.active.name
if bpy.data.objects[active_obj].type != 'MESH':
self.report({'ERROR'}, "Make sure the active object is a Mesh")
return {'CANCELLED'}
mode = bpy.context.active_object.mode
# check if object type is not MESH and then deselect it
for x in bpy.context.selected_objects:
if bpy.data.objects[x.name].type != 'MESH':
bpy.data.objects[x.name].select_set(False)
org_objs = bpy.context.selected_objects
# remove any modifiers
if bpy.context.object.modifiers:
for x in bpy.context.object.modifiers:
bpy.ops.object.modifier_remove(modifier=x.name)
if len(bpy.context.selected_objects) > 1:
bpy.ops.object.join()
# create tmp:object and store its location, rotation and dimensions
bpy.ops.object.transform_apply(location=False, rotation=apply_rot, scale=True)
bpy.ops.object.origin_set(type='ORIGIN_GEOMETRY', center='BOUNDS')
lattice_loc = bpy.context.object.location
lattice_rot = bpy.context.object.rotation_euler
bbox_size = bpy.context.object.dimensions
tmp_obj = bpy.context.object.name
# create the lattice object with the lattice_loc and rot
bpy.ops.object.add(radius=1, type='LATTICE', view_align=False, enter_editmode=False, location=lattice_loc, rotation=lattice_rot)
lattice_obj = bpy.context.object
# set dimensions / bounding box size
bpy.context.object.scale = bbox_size
bpy.ops.object.select_all(action='DESELECT')
# select and delete the tmp_object
bpy.data.objects[tmp_obj].select_set(True)
bpy.ops.object.delete(use_global=False)
# select all the original objects and assign the lattice deformer
for i in org_objs:
if bpy.data.objects[i.name].type == 'MESH' :
bpy.context.view_layer.objects.active = bpy.data.objects[i.name]
bpy.data.objects[i.name].select_set(True)
bpy.ops.object.modifier_add(type='LATTICE')
lattice_name = bpy.context.object.modifiers[len(bpy.context.object.modifiers)-1].name
bpy.context.object.modifiers[lattice_name].object = lattice_obj
if move_first == True:
for x in bpy.context.object.modifiers:
bpy.ops.object.modifier_move_up(modifier=lattice_name)
else:
bpy.data.objects[i.name].select_set(True)
bpy.data.objects[lattice_obj.name].select_set(True)
bpy.context.view_layer.objects.active = bpy.data.objects[lattice_obj.name]
bpy.ops.object.parent_set(type='OBJECT', keep_transform=True)
else:
bpy.ops.object.select_all(action='DESELECT')
bpy.data.objects[lattice_obj.name].select_set(True)
bpy.context.view_layer.objects.active = bpy.data.objects[lattice_obj.name]
bpy.context.object.data.interpolation_type_u = interpolation
bpy.context.object.data.interpolation_type_v = interpolation
bpy.context.object.data.interpolation_type_w = interpolation
bpy.context.object.data.points_u = self.seg_u
bpy.context.object.data.points_v = self.seg_v
bpy.context.object.data.points_w = self.seg_w
org_objs = bpy.context.selected_objects
# Add vertex group and store its name in a variable
bpy.ops.object.vertex_group_assign_new()
v_id = len(bpy.context.object.vertex_groups)-1
bpy.context.object.vertex_groups[v_id].name = 'tmp_lattice_to_selection'
v_group = bpy.context.object.vertex_groups[v_id].name
bpy.ops.mesh.duplicate()
bpy.ops.mesh.separate(type='SELECTED')
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
for x in bpy.context.selected_objects:
if x not in org_objs:
tmp_obj = x.name
print(tmp_obj)
bpy.ops.object.select_all(action='DESELECT')
bpy.context.view_layer.objects.active = bpy.data.objects[tmp_obj]
bpy.data.objects[tmp_obj].select_set(True)
if bpy.context.object.modifiers:
for x in bpy.context.object.modifiers:
bpy.ops.object.modifier_remove(modifier=x.name)
bpy.ops.object.transform_apply(location=False, rotation=apply_rot, scale=True)
bpy.ops.object.origin_set(type='ORIGIN_GEOMETRY', center='BOUNDS')
lattice_loc = bpy.context.object.location
lattice_rot = bpy.context.object.rotation_euler
bbox_size = bpy.context.object.dimensions
tmp_obj = bpy.context.object.name
bpy.ops.object.add(radius=1, type='LATTICE', view_align=False, enter_editmode=False, location=lattice_loc, rotation=lattice_rot)
lattice_obj = bpy.context.object
bpy.context.object.scale = bbox_size
bpy.ops.object.select_all(action='DESELECT')
bpy.data.objects[tmp_obj].select_set(True)
bpy.ops.object.delete(use_global=False)
bpy.context.view_layer.objects.active = bpy.data.objects[active_obj]
bpy.data.objects[active_obj].select_set(True)
bpy.ops.object.modifier_add(type='LATTICE')
lattice_name = bpy.context.object.modifiers[len(bpy.context.object.modifiers)-1].name
bpy.context.object.modifiers[lattice_name].object = lattice_obj
bpy.context.object.modifiers[lattice_name].vertex_group = v_group
if move_first == True:
for x in bpy.context.object.modifiers:
bpy.ops.object.modifier_move_up(modifier=lattice_name)
bpy.ops.object.select_all(action='DESELECT')
bpy.data.objects[lattice_obj.name].select_set(True)
bpy.context.view_layer.objects.active = bpy.data.objects[lattice_obj.name]
bpy.context.object.data.interpolation_type_u = interpolation
bpy.context.object.data.interpolation_type_v = interpolation
bpy.context.object.data.interpolation_type_w = interpolation
bpy.context.object.data.points_u = self.seg_u
bpy.context.object.data.points_v = self.seg_v
bpy.context.object.data.points_w = self.seg_w
def invoke( self, context, event ):
wm = context.window_manager
return wm.invoke_props_dialog( self )
#Adds Calculate Normals and Smooth to the Addon
class calc_normals(bpy.types.Operator):
"""Calculates and smooths normals."""
bl_idname = "mesh.calc_normals"
bl_label = "Calculate Normals"
bl_options = {'REGISTER', 'UNDO'}
invert: BoolProperty(name = "Invert Normals", description = "Inverts the normals.", default = False)
invert = self.invert
mode = bpy.context.active_object.mode
if mode == 'OBJECT':
sel = bpy.context.selected_objects
active = bpy.context.view_layer.objects.active.name
bpy.ops.object.shade_smooth()
for ob in sel:
ob = ob.name
bpy.context.view_layer.objects.active = bpy.data.objects[ob]
bpy.ops.object.editmode_toggle()
bpy.ops.mesh.select_all(action='SELECT')
bpy.ops.mesh.normals_make_consistent(inside=invert)
bpy.ops.object.editmode_toggle()
bpy.context.view_layer.objects.active = bpy.data.objects[active]
elif mode == 'EDIT':
bpy.ops.mesh.normals_make_consistent(inside=invert)
class snaptoaxis(bpy.types.Operator):
"""Snaps selected vertices to zero on the selected axis."""
bl_idname = "mesh.snaptoaxis"
bl_label = "Snap to Axis"
bl_options = {'REGISTER', 'UNDO'}
#worldspace = bpy.props.EnumProperty(items= (('OBJECT', 'Object Space', 'Snap to the object axis'),
# ('WORLD', 'World Space', 'Snap to the global axis')),
# name = "Object/World", default = 'OBJECT')
snap_x: BoolProperty(name = "Snap to X", description = "Snaps to zero in X. Also sets the axis for the mirror modifier if that button is turned on", default = True)
snap_y: BoolProperty(name = "Snap to Y", description = "Snaps to zero in Y. Also sets the axis for the mirror modifier if that button is turned on", default = False)
snap_z: BoolProperty(name = "Snap to Z", description = "Snaps to zero in Z. Also sets the axis for the mirror modifier if that button is turned on", default = False)
mirror_add: BoolProperty(name = "Add Mirror Modifier", description = "Adds a mirror modifer", default = False)
mirror_x: BoolProperty(name = "Mirror on X", description = "Sets the modifier to mirror on X", default = True)
mirror_y: BoolProperty(name = "Mirror on Y", description = "Sets the modifier to mirror on Y", default = False)
mirror_z: BoolProperty(name = "Mirror on Z", description = "Sets the modifier to mirror on Z", default = False)
clipping: BoolProperty(name = "Enable Clipping", description = "Prevents vertices from going through the mirror during transform", default = True)
def draw(self, context):
layout = self.layout
col = layout.column()
col_move = col.column(align=True)
row = col_move.row(align=True)
if self.snap_x:
row.prop(self, "snap_x", text = "X", icon='CHECKBOX_HLT')
else:
row.prop(self, "snap_x", text = "X", icon='CHECKBOX_DEHLT')
if self.snap_y:
row.prop(self, "snap_y", text = "Y", icon='CHECKBOX_HLT')
else:
row.prop(self, "snap_y", text = "Y", icon='CHECKBOX_DEHLT')
if self.snap_z:
row.prop(self, "snap_z", text = "Z", icon='CHECKBOX_HLT')
else:
row.prop(self, "snap_z", text = "Z", icon='CHECKBOX_DEHLT')
col_move = col.column(align=True)
col_move.prop(self, "mirror_add", icon = 'MODIFIER')
row = col_move.row(align=True)
row.active = self.mirror_add
if self.mirror_x:
row.prop(self, "mirror_x", text = "X", icon='CHECKBOX_HLT')
else:
row.prop(self, "mirror_x", text = "X", icon='CHECKBOX_DEHLT')
if self.mirror_y:
row.prop(self, "mirror_y", text = "Y", icon='CHECKBOX_HLT')
else:
row.prop(self, "mirror_y", text = "Y", icon='CHECKBOX_DEHLT')
if self.mirror_z:
row.prop(self, "mirror_z", text = "Z", icon='CHECKBOX_HLT')
else:
row.prop(self, "mirror_z", text = "Z", icon='CHECKBOX_DEHLT')
col = col.column()
col.active = self.mirror_add
def execute(self, context):
mode = bpy.context.active_object.mode
mirror_find = bpy.context.object.modifiers.find('Mirror')
run = True
if mode == 'EDIT':
loc = bpy.context.object.location
me = bpy.context.object.data
bm = bmesh.from_edit_mesh(me)
for v in bm.verts:
if v.select:
if self.snap_x == True:
v.co.x = 0
if self.snap_y == True:
v.co.y = 0
if self.snap_z == True:
v.co.z = 0
bmesh.update_edit_mesh(me, True, False)
if mirror_find <= -1:
bpy.ops.object.modifier_add(type='MIRROR')
bpy.context.object.modifiers['Mirror'].show_viewport = True
bpy.context.object.modifiers["Mirror"].use_clip = self.clipping
bpy.context.object.modifiers["Mirror"].use_x = self.mirror_x
bpy.context.object.modifiers["Mirror"].use_y = self.mirror_y
bpy.context.object.modifiers["Mirror"].use_z = self.mirror_z
return {'FINISHED'}
#Adds QuickBool to the Addon
class quickbool(bpy.types.Operator):
"""Quickly carves out the selected polygons. Works best with manifold meshes."""
bl_idname = "mesh.quickbool"
bl_label = "Quick Bool"
bl_options = {'REGISTER', 'UNDO'}
del_bool: BoolProperty(name="Delete BoolMesh", description="Deletes the objects used for the boolean operation.", default= True)
move_to: BoolProperty(name="Move to layer 10", description="Moves the objects used for the boolean operation to layer 10", default= False)
operation: EnumProperty(items= (('UNION', 'Union', 'Combines'),
('INTERSECT', 'Intersect', 'Keep the part that overlaps'),
('DIFFERENCE', 'Difference', 'Cuts out')),
name = "Operation", default = 'DIFFERENCE')
def draw(self, context):
layout = self.layout
col = layout.column()
col.prop(self, "del_bool")
col = col.column()
col.active = self.del_bool == False
col = layout.column()
col.prop(self, "operation")
del_bool = self.del_bool
move_to = self.move_to
mode = bpy.context.active_object.mode
if mode == 'EDIT':
#Boolean From Edit mode
bpy.ops.mesh.select_linked()
bpy.ops.mesh.separate(type='SELECTED')
bpy.ops.object.editmode_toggle()
#get name of Original+Bool object
original = bpy.context.selected_objects[1].name
bool = bpy.context.selected_objects[0].name
#perform boolean
bpy.ops.object.modifier_add(type='BOOLEAN')
bpy.context.object.modifiers["Boolean"].object = bpy.data.objects[bool]
bpy.context.object.modifiers["Boolean"].operation = self.operation
bpy.ops.object.modifier_apply(apply_as='DATA', modifier="Boolean")
#delete Bool object
bpy.ops.object.select_all(action='DESELECT')
bpy.ops.object.select_pattern(pattern=bool)
bpy.context.view_layer.objects.active = bpy.data.objects[bool]
#Delete all geo inside Shrink_Object
bpy.ops.object.mode_set(mode = 'EDIT', toggle = False)
bpy.ops.mesh.select_all(action='SELECT')
bpy.ops.mesh.delete(type='VERT')
bpy.ops.object.mode_set(mode = 'OBJECT', toggle = False)
bpy.ops.object.delete()
#re-enter edit mode on Original object
bpy.context.view_layer.objects.active = bpy.data.objects[original]
bpy.ops.object.select_pattern(pattern=original)
bpy.ops.object.editmode_toggle()
else:
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
original = bpy.context.active_object.name
bool = bpy.context.selected_objects
for x in bool:
x = x.name
if x != original:
list.append(x)
for name in list:
#Perform Boolean
bpy.ops.object.modifier_add(type='BOOLEAN')
bpy.context.object.modifiers["Boolean"].object = bpy.data.objects[name]
bpy.context.object.modifiers["Boolean"].operation = self.operation
bpy.ops.object.modifier_apply(apply_as='DATA', modifier="Boolean")
bpy.ops.object.select_all(action='DESELECT')
bpy.ops.object.select_pattern(pattern=name)
bpy.context.view_layer.objects.active = bpy.data.objects[name]
#Delete all geo inside Shrink_Object
bpy.ops.object.mode_set(mode = 'EDIT', toggle = False)
bpy.ops.mesh.select_all(action='SELECT')
bpy.ops.mesh.delete(type='VERT')
bpy.ops.object.mode_set(mode = 'OBJECT', toggle = False)
bpy.ops.object.delete(use_global=False)
bpy.context.view_layer.objects.active = bpy.data.objects[original]
bpy.ops.object.select_all(action='DESELECT')
bpy.ops.object.select_pattern(pattern=name)
bpy.context.view_layer.objects.active = bpy.data.objects[name]
bpy.context.object.display_type = 'WIRE'
# Move to garbage layer
if move_to == True:
bpy.ops.object.move_to_layer(layers=(False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False))
bpy.context.view_layer.objects.active = bpy.data.objects[original]
bpy.ops.object.mode_set(mode=mode, toggle=False)
class autotubes(bpy.types.Operator):
"""Creates a spline tube based on selected edges"""
bl_idname = "mesh.autotubes"
bl_label = "Auto Tubes"
bl_options = {'REGISTER', 'UNDO'}
bevel: FloatProperty(name="Tube Width", description="Change width of the tube.", default=0.1, min = 0)
res: IntProperty(name="Tube Resolution", description="Change resolution of the tube.", default=2, min = 0, max = 20)
mode = bpy.context.active_object.mode
type = bpy.context.active_object.type
if mode == 'EDIT' and type == 'MESH':
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
bpy.ops.object.duplicate()
bpy.ops.object.mode_set(mode='EDIT', toggle=False)
bpy.ops.mesh.select_all(action='INVERT')
bpy.ops.mesh.delete(type='EDGE')
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
bpy.ops.object.subdivision_set(level=0)
bpy.ops.object.convert(target='CURVE')
bpy.context.object.data.fill_mode = 'FULL'
bpy.context.object.data.bevel_depth = 0.1
bpy.context.object.data.splines[0].use_smooth = True
bpy.context.object.data.bevel_resolution = 2
bpy.ops.object.shade_smooth()
bpy.ops.object.mode_set(mode='EDIT', toggle=False)
bpy.ops.curve.spline_type_set(type='BEZIER')
bpy.context.object.data.bevel_depth = bevel
bpy.context.object.data.bevel_resolution = res
#bpy.ops.transform.transform(('INVOKE_DEFAULT'), mode='CURVE_SHRINKFATTEN')
bpy.context.object.data.bevel_depth = bevel
bpy.context.object.data.bevel_resolution = res
elif mode != 'EDIT' and type == 'MESH':
self.report({'ERROR'}, "This one only works in Edit mode")
return {'CANCELLED'}
class basicRename(bpy.types.Operator):
"""Renames everything to Banana"""
bl_idname = "object.basic_rename"
bl_label = "Basic Renamer"
bl_options = {'REGISTER', 'UNDO'}
name: StringProperty(name="Rename", description="Rename selected objects", default="banana")
padding: IntProperty(name = "Number Padding", description = "Adds how many padded numbers", default = 3, min = 1, max = 8)
prefix: StringProperty(name="Pre Fix", description="Adds a Prefix to the name", default="")
post_ob: StringProperty(name="Post Fix Object", description="Adds ending to object name", default="_MDL")
post_data: StringProperty(name="Post Fix Data", description="Adds ending to data name", default="_DATA")
# The original script
obj = bpy.context.selected_objects
name = self.name
padding = self.padding
prefix = self.prefix
post_ob = self.post_ob
post_data = self.post_data
number = 0
for item in obj:
number += 1
item.name = "%s%s_%s%s" %(str(prefix), str(name), str(number).zfill(padding), str(post_ob))
item.data.name = "%s%s_%s%s" %(str(prefix), str(name), str(number).zfill(padding), str(post_data))
return {'FINISHED'}
class cut_tool(bpy.types.Operator):
"""Context sensitive cut tool"""
bl_idname = "mesh.cut_tool"
bl_label = "Cut Tool"
bl_options = {'REGISTER', 'UNDO'}
cuts: IntProperty(name="Number of Cuts", description="Change the number of cuts.", default=1, min = 1, soft_max = 10)
loopcut: BoolProperty(name="Insert LoopCut", description="Makes a loop cut based on the selected edges", default= False)
smoothness: FloatProperty(name="Smoothness", description="Change the smoothness.", default=0, min = 0, soft_max = 1)
quad_corners: bpy.props.EnumProperty(items= (('INNERVERT', 'Inner Vert', 'How to subdivide quad corners'),
('PATH', 'Path', 'How to subdivide quad corners'),
('STRAIGHT_CUT', 'Straight Cut', 'How to subdivide quad corners'),
('FAN', 'Fan', 'How to subdivide quad corners')),
name = "Quad Corner Type", default = 'STRAIGHT_CUT')
quad_corners = self.quad_corners
cuts = self.cuts
loopcut = self.loopcut
smoothness = self.smoothness
mode = bpy.context.active_object.mode
if mode == 'EDIT':
sel_mode = bpy.context.tool_settings.mesh_select_mode[:]
#Checks and stores if any Vert, Edge or Face is selected.
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
me = bpy.context.object.data
bm = bmesh.new() # create an empty BMesh
bm.from_mesh(me) # fill it in from a Mesh
sel = []
edge_sel = []
vert_sel = []
for v in bm.faces:
if v.select:
sel.append(v.index)
for v in bm.edges:
if v.select:
edge_sel.append(v.index)
for v in bm.verts:
if v.select:
vert_sel.append(v.index)
bm.to_mesh(me)
bpy.ops.object.mode_set(mode='EDIT', toggle=False)
if len(sel) == 0 and len(edge_sel) == 0 and len(vert_sel) == 0 :
bpy.ops.mesh.knife_tool("INVOKE_DEFAULT")
if sel_mode[2] == True and len(sel) > 1:
vgrp = bpy.context.object.vertex_groups.active_index
#Store the Hidden Polygons
bpy.ops.mesh.select_all(action='SELECT')
bpy.ops.object.vertex_group_assign_new()
tmp_hidden = bpy.context.object.vertex_groups.active_index
bpy.ops.mesh.select_all(action='DESELECT')
#Select faces to be cut
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
mesh = bpy.context.active_object.data.polygons
for f in sel:
mesh[f].select = True
bpy.ops.object.mode_set(mode='EDIT', toggle=False)
bpy.ops.mesh.hide(unselected=True)
bpy.ops.mesh.select_all(action='SELECT')
bpy.ops.mesh.region_to_loop()
#Store Boundry Edges
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
me = bpy.context.object.data
boundry_edge = []
for v in bm.edges:
if v.select:
boundry_edge.append(v.index)
bm.to_mesh(me)
bpy.ops.object.mode_set(mode='EDIT', toggle=False)
#Store Cut Edges
bpy.ops.mesh.select_all(action='INVERT')
bpy.ops.mesh.loop_multi_select(ring=True)
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
me = bpy.context.object.data
cut_edges = []
for v in bm.edges:
if v.select:
cut_edges.append(v.index)
bm.to_mesh(me)
bpy.ops.object.mode_set(mode='EDIT', toggle=False)
#Store Intersection edges
bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='FACE')
bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='EDGE')
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
me = bpy.context.object.data
int_edges = []
for v in bm.edges:
if v.select:
int_edges.append(v.index)
bm.to_mesh(me)
bpy.ops.object.mode_set(mode='EDIT', toggle=False)
#Modify Lists
for x in int_edges:
if x in boundry_edge:
cut_edges.remove(x)
bpy.ops.mesh.select_all(action='DESELECT')
#Select the new edges to cut
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
mesh = bpy.context.active_object.data.edges
for f in cut_edges:
mesh[f].select = True
#Perform cut and select the cut line.
bpy.ops.object.mode_set(mode='EDIT', toggle=False)
bpy.ops.mesh.subdivide(number_cuts = cuts, smoothness = smoothness, quadcorner = quad_corners)
bpy.ops.mesh.select_all(action='SELECT')
bpy.ops.mesh.region_to_loop()
bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='VERT')
bpy.ops.mesh.select_all(action='INVERT')
bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='EDGE')
bpy.ops.mesh.loop_multi_select(ring=False)
#Store cut line.
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
me = bpy.context.object.data
cut_line = []
for v in bm.edges:
if v.select:
cut_line.append(v.index)
bm.to_mesh(me)
bpy.ops.object.mode_set(mode='EDIT', toggle=False)
bpy.ops.mesh.reveal()
bpy.ops.mesh.select_all(action='DESELECT')
bpy.context.object.vertex_groups.active_index = tmp_hidden
bpy.ops.object.vertex_group_select()
bpy.ops.mesh.hide(unselected=True)
bpy.ops.mesh.select_all(action='DESELECT')
#Select Cutline
if cuts <= 1:
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
mesh = bpy.context.active_object.data.edges
for f in cut_line:
mesh[f].select = True
bpy.ops.object.mode_set(mode='EDIT', toggle=False)
bpy.ops.object.vertex_group_remove(all=False)
bpy.ops.mesh.select_mode(use_extend=True, use_expand=False, type='FACE')
elif sel_mode[0] == True and len(vert_sel) >= 2:
bpy.ops.mesh.vert_connect_path()
elif sel_mode[1] == True and loopcut == False and len(edge_sel) != 0:
bpy.ops.mesh.subdivide(number_cuts = cuts, smoothness = smoothness, quadcorner = quad_corners)
elif sel_mode[1] == True and loopcut == True and len(edge_sel) != 0:
bpy.ops.mesh.loop_multi_select(ring=True)
bpy.ops.mesh.subdivide(number_cuts = cuts, smoothness = smoothness, quadcorner = quad_corners)
else:
bpy.ops.mesh.select_all(action='DESELECT')
bpy.ops.mesh.knife_tool("INVOKE_DEFAULT")
else:
self.report({'ERROR'}, "This one only works in Edit mode")
class customAutoSmooth(bpy.types.Operator):
"""Set AutoSmooth angle"""
bl_idname = "object.custom_autosmooth"
bl_label = "Autosmooth"
bl_options = {'REGISTER', 'UNDO'}
angle: FloatProperty(name="AutoSmooth Angle", description="Set AutoSmooth angle", default= 30.0, min = 0.0, max = 180.0)
mode = bpy.context.active_object.mode
if mode != 'OBJECT':
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
ob = bpy.context.selected_objects
angle = self.angle
angle = angle * (3.14159265359/180)
bpy.ops.object.shade_smooth()
for x in ob:
x = x.name
bpy.data.objects[x].data.use_auto_smooth = True
bpy.data.objects[x].data.auto_smooth_angle = angle
bpy.ops.object.mode_set(mode=mode, toggle=False)
class shrinkwrapSmooth(bpy.types.Operator):
"""Smooths the selected vertices while trying to keep the original shape with a shrinkwrap modifier. """
bl_idname = "mesh.shrinkwrap_smooth"
bl_label = "Shrinkwrap Smooth"
bl_options = {'REGISTER', 'UNDO'}
pin: BoolProperty(name="Pin Selection Border", description="Pins the outer edge of the selection.", default = True)
subsurf: IntProperty(name="Subsurf Levels", description="More reliable, but slower results", default = 0, min = 0, soft_max = 4)
def execute(self, context):
iterate = 6
pin = self.pin
data = bpy.context.object.data.name
# Set up for vertex weight
bpy.context.scene.tool_settings.vertex_group_weight = 1
v_grps = len(bpy.context.object.vertex_groups.items())
bpy.ops.object.mode_set(mode = 'OBJECT', toggle = False)
org_ob = bpy.context.object.name
# Create intermediate object
bpy.ops.object.mode_set(mode = 'OBJECT', toggle = False)
bpy.ops.mesh.primitive_plane_add(radius=1, view_align=False, enter_editmode=False)
bpy.context.object.data = bpy.data.meshes[data]
tmp_ob = bpy.context.object.name
bpy.ops.object.duplicate(linked=False)
shrink_ob = bpy.context.object.name
bpy.ops.object.select_all(action='DESELECT')
bpy.ops.object.select_pattern(pattern=tmp_ob)
bpy.context.view_layer.objects.active = bpy.data.objects[tmp_ob]
bpy.ops.object.mode_set(mode = 'EDIT', toggle = False)
bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='VERT')
if v_grps >= 1:
for x in range(v_grps):
bpy.ops.object.vertex_group_add()
if pin == True:
bpy.ops.object.vertex_group_assign_new()
org_id = bpy.context.object.vertex_groups.active_index
bpy.ops.object.vertex_group_assign_new()
sel = bpy.context.object.vertex_groups.active.name
sel_id = bpy.context.object.vertex_groups.active_index
bpy.ops.mesh.region_to_loop()
bpy.ops.object.vertex_group_remove_from(use_all_groups=False, use_all_verts=False)
bpy.ops.mesh.select_all(action='SELECT')
bpy.ops.mesh.region_to_loop()
bpy.ops.object.vertex_group_remove_from(use_all_groups=False, use_all_verts=False)
bpy.ops.mesh.select_all(action='DESELECT')
bpy.ops.object.vertex_group_select(sel_id)
else:
bpy.ops.object.vertex_group_assign_new()
sel = bpy.context.object.vertex_groups.active.name
for x in range(iterate):
bpy.ops.object.modifier_add(type='SHRINKWRAP')
mod_id = (len(bpy.context.object.modifiers)-1)
shrink_name = bpy.context.object.modifiers[mod_id].name
bpy.context.object.modifiers[shrink_name].target = bpy.data.objects[shrink_ob]
bpy.context.object.modifiers[shrink_name].vertex_group = sel
bpy.context.object.modifiers[shrink_name].wrap_method = 'PROJECT'
bpy.context.object.modifiers[shrink_name].use_negative_direction = True
bpy.context.object.modifiers[shrink_name].subsurf_levels = self.subsurf
bpy.ops.mesh.vertices_smooth(factor=1, repeat=1)
bpy.ops.object.mode_set(mode = 'OBJECT', toggle = False)
bpy.ops.object.convert(target='MESH')
bpy.ops.object.mode_set(mode = 'EDIT', toggle = False)
bpy.ops.object.mode_set(mode = 'OBJECT', toggle = False)
bpy.ops.object.vertex_group_remove(all = False)
bpy.ops.object.modifier_remove(modifier=shrink_name)
bpy.ops.object.select_all(action='DESELECT')
bpy.ops.object.select_pattern(pattern=shrink_ob)
bpy.context.view_layer.objects.active = bpy.data.objects[shrink_ob]
#Delete all geo inside Shrink_Object
bpy.ops.object.mode_set(mode = 'EDIT', toggle = False)
bpy.ops.mesh.select_all(action='SELECT')
bpy.ops.mesh.delete(type='VERT')
bpy.ops.object.mode_set(mode = 'OBJECT', toggle = False)
bpy.ops.object.delete(use_global=True)
bpy.ops.object.select_pattern(pattern=tmp_ob)
bpy.context.view_layer.objects.active = bpy.data.objects[tmp_ob]
bpy.ops.object.mode_set(mode = 'EDIT', toggle = False)
if pin == True:
bpy.ops.mesh.select_all(action='DESELECT')
bpy.ops.object.vertex_group_select(org_id)
bpy.ops.object.mode_set(mode = 'OBJECT', toggle = False)
bpy.ops.object.delete(use_global=False)
bpy.ops.object.select_pattern(pattern=org_ob)
bpy.context.view_layer.objects.active = bpy.data.objects[org_ob]
bpy.ops.object.mode_set(mode = 'EDIT', toggle = False)
# Fix for Blender remembering the previous selection
bpy.ops.object.vertex_group_assign_new()
bpy.ops.object.vertex_group_remove(all = False)
class buildCorner(bpy.types.Operator):
"""Builds corner topology. Good for converting ngons"""
bl_idname = "mesh.build_corner"
bl_label = "Build Corner"
def modal(self, context, event):
delta = self.offset - event.mouse_x
if delta >= 0:
offset = 1
else:
offset = 0
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
bpy.ops.mesh.poke()
bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='VERT')
bpy.ops.object.vertex_group_assign_new()
sel_id = bpy.context.object.vertex_groups.active_index
bpy.ops.mesh.region_to_loop()
bpy.ops.object.vertex_group_remove_from()
bpy.ops.mesh.select_nth(nth=2, skip=1, offset=offset)
bpy.ops.object.vertex_group_select(sel_id)
bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='EDGE')
bpy.ops.mesh.dissolve_mode(use_verts=False)
bpy.ops.mesh.select_all(action='DESELECT')
bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='VERT')
bpy.ops.object.vertex_group_select()
bpy.ops.mesh.select_more()
bpy.ops.object.vertex_group_remove(all = False)
bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='FACE')
elif event.type == 'LEFTMOUSE':
return {'FINISHED'}
elif event.type in {'RIGHTMOUSE', 'ESC'}:
bpy.ops.ed.undo()
return {'CANCELLED'}
return {'RUNNING_MODAL'}
def invoke(self, context, event):
if context.object:
bpy.ops.mesh.edge_face_add()
bpy.ops.mesh.region_to_loop()
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
me = bpy.context.object.data
bm = bmesh.new() # create an empty BMesh
bm.from_mesh(me) # fill it in from a Mesh
face_sel = []
edge_sel = []
for v in bm.faces:
if v.select:
face_sel.append(v.index)
for v in bm.edges:
if v.select:
edge_sel.append(v.index)
bm.to_mesh(me)
bpy.ops.object.mode_set(mode='EDIT', toggle=False)
bpy.ops.mesh.loop_to_region()
###################################
if edge_sel == 4:
return {'FINISHED'}
elif edge_sel%2 == 0:
self.offset = event.mouse_x
context.window_manager.modal_handler_add(self)
return {'RUNNING_MODAL'}
#elif edge_sel == 5:
# bpy.ops.mesh.quads_convert_to_tris(quad_method='BEAUTY', ngon_method='BEAUTY')
# bpy.ops.mesh.tris_convert_to_quads(face_threshold=3.14159, shape_threshold=3.14159)
# return {'FINISHED'}
else:
bpy.ops.mesh.poke()
bpy.ops.mesh.quads_convert_to_tris(quad_method='BEAUTY', ngon_method='BEAUTY')
bpy.ops.mesh.tris_convert_to_quads(face_threshold=3.14159, shape_threshold=3.14159)
return {'FINISHED'}
else:
self.report({'WARNING'}, "No active object, could not finish")
return {'CANCELLED'}
class drawPoly(bpy.types.Operator):
"""Draw a polygon"""
bl_idname = "mesh.draw_poly"
bl_label = "Draw Poly"
cursor_co: FloatVectorProperty()
manip: BoolProperty()
vgrp: IntProperty()
sel_mode = BoolVectorProperty()
cursor_depth: BoolProperty()
snap: BoolProperty()
def modal(self, context, event):
# set header gui
context.area.tag_redraw()
context.area.header_text_set("LMB = Create New Point, SHIFT = Flip Normals, RMB / ENTER = Accept NGon, MMB = Accept QuadFill")
mesh = bpy.context.active_object.data
if event.type == 'LEFTMOUSE':
if event.value == 'PRESS':
bpy.ops.view3d.cursor3d('INVOKE_DEFAULT')
obj = bpy.context.active_object
vert_co = bpy.context.scene.cursor_location
world = obj.matrix_world.inverted_safe()
bpy.ops.mesh.select_all(action='DESELECT')
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
me = bpy.context.object.data
bm = bmesh.new()
bm.from_mesh(me)
# Add new vert
new_vert = bm.verts.new(vert_co)
new_vert.co = world*new_vert.co
new_vert_id = new_vert.index
self.vert_count += 1
if self.vert_count >= 2:
bm.verts.ensure_lookup_table()
set_of_verts = set(bm.verts[i] for i in range(-2,0))
bm.edges.new(set_of_verts)
# Get index of first and last vertex
first_index = len(bm.verts)-self.vert_count
second_index = first_index+1
third_index = first_index+2
second_to_last_index = len(bm.verts)-2
mesh.vertices[new_vert_id].select = True
bpy.ops.object.mode_set(mode='EDIT', toggle=False)
bpy.context.scene.cursor_location = self.cursor_co
if self.vert_count >= 4:
bpy.ops.object.vertex_group_assign()
if self.vert_count == 3:
# remove second vertex from group
bpy.ops.mesh.select_all(action='DESELECT')
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
mesh.vertices[first_index].select = True
mesh.vertices[third_index].select = True
bpy.ops.object.mode_set(mode='EDIT', toggle=False)
bpy.ops.object.vertex_group_assign()
bpy.ops.mesh.select_more()
if self.vert_count == 2:
bpy.ops.mesh.select_more()
if self.vert_count >= 4:
# make core poly
bpy.ops.mesh.select_all(action='DESELECT')
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
mesh.vertices[first_index].select = True
mesh.vertices[second_index].select = True
mesh.vertices[third_index].select = True
bpy.ops.object.mode_set(mode='EDIT', toggle=False)
bpy.ops.mesh.edge_face_add()
if self.vert_count == 4:
bpy.ops.mesh.select_all(action='DESELECT')
bpy.ops.object.vertex_group_select(self.vgrp)
bpy.ops.mesh.edge_face_add()
# Remove remaining core edge
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
mesh.vertices[second_index].select = True
bpy.ops.object.mode_set(mode='EDIT', toggle=False)
bpy.ops.mesh.edge_face_add()
if self.vert_count >= 5:
#bpy.ops.object.vertex_group_assign()
bpy.ops.mesh.select_all(action='DESELECT')
# Remove Last Edge
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
mesh.vertices[first_index].select = True
mesh.vertices[second_to_last_index].select = True
bpy.ops.object.mode_set(mode='EDIT', toggle=False)
bpy.ops.mesh.delete(type='EDGE')
# Fill in rest of face
bpy.ops.object.vertex_group_select(self.vgrp)
bpy.ops.mesh.edge_face_add()
# Remove remaining core edge
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
mesh.vertices[second_index].select = True
bpy.ops.object.mode_set(mode='EDIT', toggle=False)
bpy.ops.mesh.edge_face_add()
bpy.ops.mesh.flip_normals()
#return {'FINISHED'}
elif event.type == 'MIDDLEMOUSE':
# reset header gui
context.area.tag_redraw()
context.area.header_text_set(None)
# Convert to Quads
bpy.ops.mesh.quads_convert_to_tris(quad_method='BEAUTY', ngon_method='BEAUTY')
bpy.ops.mesh.tris_convert_to_quads()
bpy.ops.mesh.tris_convert_to_quads(face_threshold=3.14159, shape_threshold=3.14159)
# restore selection mode and manipulator
bpy.context.tool_settings.mesh_select_mode = self.sel_mode
bpy.context.space_data.show_manipulator = self.manip
bpy.context.preferences.input.use_mouse_depth_cursor = self.cursor_depth
bpy.context.scene.tool_settings.use_snap = self.snap
# Remove and make sure vertex group data is gone
bpy.ops.object.vertex_group_remove_from(use_all_verts=True)
bpy.ops.object.vertex_group_remove()
bpy.ops.object.vertex_group_assign_new()
bpy.context.object.vertex_groups.active.name = "drawPoly_temp"
bpy.ops.object.vertex_group_remove()
elif event.type in {'RIGHTMOUSE', 'ESC', 'SPACE'}:
# reset header gui
context.area.tag_redraw()
context.area.header_text_set(None)
# restore selection mode and manipulator
bpy.context.tool_settings.mesh_select_mode = self.sel_mode
bpy.context.space_data.show_manipulator = self.manip
bpy.context.preferences.input.use_mouse_depth_cursor = self.cursor_depth
bpy.context.scene.tool_settings.use_snap = self.snap
# Remove and make sure vertex group data is gone
bpy.ops.object.vertex_group_remove_from(use_all_verts=True)
bpy.ops.object.vertex_group_remove()
bpy.ops.object.vertex_group_assign_new()
bpy.context.object.vertex_groups.active.name = "drawPoly_temp"
bpy.ops.object.vertex_group_remove()
elif event.type == 'LEFT_SHIFT' or event.type == 'RIGHT_SHIFT':
bpy.ops.mesh.flip_normals()
elif event.type == 'LEFT_CTRL' or event.type == 'RIGHT_CTRL' :
if bpy.context.preferences.input.use_mouse_depth_cursor == True:
bpy.context.preferences.input.use_mouse_depth_cursor = False
bpy.context.scene.tool_settings.use_snap = False
else:
bpy.context.preferences.input.use_mouse_depth_cursor = True
bpy.context.scene.tool_settings.use_snap = True
return {'PASS_THROUGH'}
return {'RUNNING_MODAL'}
def invoke(self, context, event):
sel_ob = len(bpy.context.selected_objects)
if sel_ob >= 1:
sel_type = bpy.context.object.type
if sel_type == 'MESH':
bpy.ops.object.mode_set(mode='EDIT', toggle=False)
else:
self.report({'WARNING'}, "Active object is not a mesh.")
return {'CANCELLED'}
elif sel_ob == 0:
bpy.ops.mesh.primitive_plane_add()
bpy.context.selected_objects[0].name = "polyDraw"
bpy.context.selected_objects[0].data.name = "polyDraw"
bpy.ops.object.mode_set(mode='EDIT', toggle=False)
bpy.ops.mesh.select_all(action='SELECT')
bpy.ops.mesh.delete(type='VERT')
# Store selection mode, snap and manipulator settings
self.sel_mode = bpy.context.tool_settings.mesh_select_mode[:]
bpy.context.tool_settings.mesh_select_mode = True, False, False
self.manip = bpy.context.space_data.show_manipulator
bpy.context.space_data.show_manipulator = False
self.cursor_depth = bpy.context.preferences.input.use_mouse_depth_cursor
bpy.context.preferences.input.use_mouse_depth_cursor = False
self.snap = bpy.context.scene.tool_settings.use_snap
bpy.context.scene.tool_settings.use_snap = False
bpy.ops.object.mode_set(mode='EDIT', toggle=False)
bpy.ops.mesh.select_all(action='DESELECT')
bpy.ops.object.vertex_group_assign_new()
self.vgrp = bpy.context.object.vertex_groups.active_index
bpy.context.object.vertex_groups.active.name = "drawPoly_temp"
self.cursor_co = bpy.context.scene.cursor_location
context.window_manager.modal_handler_add(self)
return {'RUNNING_MODAL'}
class toggleSilhouette(bpy.types.Operator):
"""Turns everything black so that you can evaluate the overall shape. Useful when designing"""
bl_idname = "object.toggle_silhouette"
bl_label = "Toggle Silhouette"
diff_col: FloatVectorProperty(default = (0.226, 0.179, 0.141))
disp_mode: StringProperty(default = 'SOLID')
matcap: BoolProperty(default = False)
only_render: BoolProperty(default = False)
light_check = bpy.context.preferences.system.solid_lights[0].use
if light_check == True:
# Set Lights to Off
bpy.context.preferences.system.solid_lights[0].use = False
bpy.context.preferences.system.solid_lights[1].use = False
self.diff_col = bpy.context.preferences.system.solid_lights[2].diffuse_color
self.disp_mode = bpy.context.space_data.viewport_shade
self.matcap = bpy.context.space_data.use_matcap
self.only_render = bpy.context.space_data.show_only_render
bpy.context.preferences.system.solid_lights[2].diffuse_color = 0,0,0
bpy.context.space_data.viewport_shade = 'SOLID'
bpy.context.space_data.use_matcap = False
bpy.context.space_data.show_only_render = True
bpy.context.preferences.system.solid_lights[0].use = True
bpy.context.preferences.system.solid_lights[1].use = True
bpy.context.preferences.system.solid_lights[2].diffuse_color = self.diff_col
bpy.context.space_data.viewport_shade = self.disp_mode
bpy.context.space_data.use_matcap = self.matcap
bpy.context.space_data.show_only_render = self.only_render
class growLoop(bpy.types.Operator):
"""Grows the selected edges in both directions """
bl_idname = "mesh.grow_loop"
bl_label = "Grow Loop"
bl_options = {'REGISTER', 'UNDO'}
grow: IntProperty(name="Grow Selection", description="How much to grow selection", default= 1, min=1, soft_max=10)
grow = self.grow
sel_mode = bpy.context.tool_settings.mesh_select_mode[:]
for x in range(grow):
if sel_mode[2] == True:
edge_sel = []
border = []
interior = []
face_org = []
face_loop = []
face_grow = []
face_sel = []
mesh_edges = bpy.context.active_object.data.edges
mesh_faces = bpy.context.active_object.data.polygons
bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='FACE')
me = bpy.context.object.data
bm = bmesh.from_edit_mesh(me)
for e in bm.edges:
if e.select:
edge_sel.append(e.index)
for f in bm.faces:
if f.select:
face_org.append(f.index)
bpy.ops.mesh.region_to_loop()
for e in bm.edges:
if e.select:
border.append(e.index)
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
for e in edge_sel:
if e not in border:
interior.append(e)
bmesh.update_edit_mesh(me, True, False)
bpy.ops.mesh.select_all(action='DESELECT')
#Select the interior edges
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
for e in interior:
mesh_edges[e].select = True
bpy.ops.object.mode_set(mode='EDIT', toggle=False)
bpy.ops.mesh.loop_multi_select(ring=True)
bpy.ops.mesh.select_mode(use_extend=False, use_expand=True, type='FACE')
me = bpy.context.object.data
bm = bmesh.from_edit_mesh(me)
for f in bm.faces:
if f.select:
face_loop.append(f.index)
bmesh.update_edit_mesh(me, True, False)
bpy.ops.mesh.select_all(action='DESELECT')
# Select original faces
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
for x in face_org:
mesh_faces[x].select = True
bpy.ops.object.mode_set(mode='EDIT', toggle=False)
bpy.ops.mesh.select_more(use_face_step=False)
me = bpy.context.object.data
bm = bmesh.from_edit_mesh(me)
for f in bm.faces:
if f.select:
face_grow.append(f.index)
for f in face_grow:
if f in face_loop:
face_sel.append(f)
for f in face_org:
face_sel.append(f)
bmesh.update_edit_mesh(me, True, False)
bpy.ops.mesh.select_all(action='DESELECT')
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
for f in face_sel:
mesh_faces[f].select = True
bpy.ops.object.mode_set(mode='EDIT', toggle=False)
else:
mesh = bpy.context.active_object.data.edges
me = bpy.context.object.data
bm = bmesh.from_edit_mesh(me)
org_sel = []
grow_sel = []
loop_sel = []
sel = []
bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='EDGE')
for e in bm.edges:
if e.select:
org_sel.append(e.index)
bpy.ops.mesh.select_more(use_face_step=False)
for e in bm.edges:
if e.select:
grow_sel.append(e.index)
bpy.ops.mesh.select_all(action='DESELECT')
bmesh.update_edit_mesh(me, True, False)
# Select the original edges
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
for e in org_sel:
bpy.ops.object.mode_set(mode='EDIT', toggle=False)
me = bpy.context.object.data
bm = bmesh.from_edit_mesh(me)
bpy.ops.mesh.loop_multi_select(ring=False)
for e in bm.edges:
if e.select:
loop_sel.append(e.index)
bmesh.update_edit_mesh(me, True, False)
bpy.ops.mesh.select_all(action='DESELECT')
for x in loop_sel:
if x in grow_sel:
sel.append(x)
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
for e in sel:
mesh[e].select = True
bpy.ops.object.mode_set(mode='EDIT', toggle=False)
bpy.context.tool_settings.mesh_select_mode = sel_mode
class extendLoop(bpy.types.Operator):
"""Uses the active face or edge to extends the selection in one direction"""
bl_idname = "mesh.extend_loop"
bl_label = "Extend Loop"
bl_options = {'REGISTER', 'UNDO'}
extend: IntProperty(name="Extend Selection", description="How much to extend selection", default= 1, min=1, soft_max=10)
sel_mode = bpy.context.tool_settings.mesh_select_mode[:]
extend = self.extend
for x in range(extend):
if sel_mode[2] == True:
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
active_face = bpy.context.object.data.polygons.active # find active face
bpy.ops.object.mode_set(mode='EDIT', toggle=False)
edge_sel = []
interior = []
face_org = []
face_loop = []
face_grow = []
face_sel = []
active_edges = []
# Get face selection
me = bpy.context.object.data
bm = bmesh.from_edit_mesh(me)
for f in bm.faces:
if f.select:
face_org.append(f.index)
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
face_org.remove(active_face)
bmesh.update_edit_mesh(me, True, False)
bpy.ops.mesh.select_all(action='DESELECT')
mesh = bpy.context.active_object.data.polygons
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
for x in face_org:
mesh[x].select = True
bpy.ops.object.mode_set(mode='EDIT', toggle=False)
# Get edge selection
me = bpy.context.object.data
bm = bmesh.from_edit_mesh(me)
for e in bm.edges:
if e.select:
edge_sel.append(e.index)
bmesh.update_edit_mesh(me, True, False)
# Select Active Face
bpy.ops.mesh.select_all(action='DESELECT')
mesh = bpy.context.active_object.data.polygons
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
mesh[active_face].select = True
bpy.ops.object.mode_set(mode='EDIT', toggle=False)
bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='EDGE')
me = bpy.context.object.data
bm = bmesh.from_edit_mesh(me)
# Store the interior edge
for e in bm.edges:
if e.select:
active_edges.append(e.index)
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
for e in active_edges:
if e in edge_sel:
interior.append(e)
bmesh.update_edit_mesh(me, True, False)
bpy.ops.mesh.select_all(action='DESELECT')
#Select the interior edges
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
mesh = bpy.context.active_object.data.edges
for e in interior:
mesh[e].select = True
bpy.ops.object.mode_set(mode='EDIT', toggle=False)
bpy.ops.mesh.loop_multi_select(ring=True)
bpy.ops.mesh.select_mode(use_extend=False, use_expand=True, type='FACE')
me = bpy.context.object.data
bm = bmesh.from_edit_mesh(me)
for f in bm.faces:
if f.select:
face_loop.append(f.index)
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
bmesh.update_edit_mesh(me, True, False)
bpy.ops.mesh.select_all(action='DESELECT')
# Select active face
mesh = bpy.context.active_object.data.polygons
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
mesh[active_face].select = True
bpy.ops.object.mode_set(mode='EDIT', toggle=False)
bpy.ops.mesh.select_more(use_face_step=False)
face_org.append(active_face)
me = bpy.context.object.data
bm = bmesh.from_edit_mesh(me)
for f in bm.faces:
if f.select:
face_grow.append(f.index)
for f in face_grow:
if f in face_loop:
face_sel.append(f)
for f in face_sel:
if f not in face_org:
active_face = f
for f in face_org:
face_sel.append(f)
bmesh.update_edit_mesh(me, True, False)
bpy.ops.mesh.select_all(action='DESELECT')
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
for f in face_sel:
mesh[f].select = True
bpy.context.object.data.polygons.active = active_face
bpy.ops.object.mode_set(mode='EDIT', toggle=False)
elif sel_mode[1] == True:
mesh = bpy.context.active_object.data
org_sel = []
grow_sel = []
loop_sel = []
sel = []
org_verts = []
active_verts = []
# Get active edge
me = bpy.context.object.data
bm = bmesh.from_edit_mesh(me)
for x in reversed(bm.select_history):
if isinstance(x, bmesh.types.BMEdge):
active_edge = x.index
break
# Store the originally selected edges
for e in bm.edges:
if e.select:
org_sel.append(e.index)
bmesh.update_edit_mesh(me, True, False)
# Select active edge
bpy.ops.mesh.select_all(action='DESELECT')
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
mesh.edges[active_edge].select = True
bpy.ops.object.mode_set(mode='EDIT', toggle=False)
# Get verts of active edge
bm = bmesh.from_edit_mesh(me)
for v in bm.verts:
if v.select:
active_verts.append(v.index)
bmesh.update_edit_mesh(me, True, False)
# Select original selection minus active edge
bpy.ops.mesh.select_all(action='DESELECT')
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
for x in org_sel:
mesh.edges[x].select = True
mesh.edges[active_edge].select = False
bpy.ops.object.mode_set(mode='EDIT', toggle=False)
# Store the original vertices minus active edge
for v in bm.verts:
if v.select:
org_verts.append(v.index)
# Compare verts
for x in active_verts:
if x in org_verts:
active_verts.remove(x)
bmesh.update_edit_mesh(me, True, False)
# Select end vertex
bpy.ops.mesh.select_all(action='DESELECT')
bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='VERT')
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
mesh.vertices[active_verts[0]].select = True
bpy.ops.object.mode_set(mode='EDIT', toggle=False)
# Grow the end vertex and store the edges
bpy.ops.mesh.select_more(use_face_step=False)
bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='EDGE')
bm = bmesh.from_edit_mesh(me)
for e in bm.edges:
if e.select:
grow_sel.append(e.index)
bmesh.update_edit_mesh(me, True, False)
bpy.ops.mesh.select_all(action='DESELECT')
# Run loop of the active edges and store it
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
bpy.ops.object.mode_set(mode='EDIT', toggle=False)
bpy.ops.mesh.loop_multi_select(ring=False)
me = bpy.context.object.data
bm = bmesh.from_edit_mesh(me)
for e in bm.edges:
if e.select:
loop_sel.append(e.index)
bmesh.update_edit_mesh(me, True, False)
bpy.ops.mesh.select_all(action='DESELECT')
# Compare loop_sel vs grow_sel
for x in loop_sel:
if x in grow_sel:
sel.append(x)
# Add original selection to new selection
for x in org_sel:
if x not in sel:
sel.append(x)
# Compare org_sel with sel to get the active edge
for x in sel:
if x not in org_sel:
active_edge = x
# Select the resulting edges
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
for e in sel:
bpy.ops.object.mode_set(mode='EDIT', toggle=False)
# Set the new active edge
bm = bmesh.from_edit_mesh(me)
bm.edges.ensure_lookup_table()
bm.select_history.add(bm.edges[active_edge])
bmesh.update_edit_mesh(me, True, False)
class shrinkLoop(bpy.types.Operator):
"""Shrink the selected loop"""
bl_idname = "mesh.shrink_loop"
bl_label = "Shrink Loop"
bl_options = {'REGISTER', 'UNDO'}
shrink: IntProperty(name="Shrink Selection", description="How much to shrink selection", default= 1, min=1, soft_max=15)
sel_mode = bpy.context.tool_settings.mesh_select_mode[:]
shrink = self.shrink
for x in range(shrink):
if sel_mode[2] == True:
me = bpy.context.object.data
bm = bmesh.from_edit_mesh(me)
mesh = bpy.context.active_object.data
sel = []
edge_dic = {}
vert_list = []
end_verts = []
org_faces = []
cur_faces = []
new_faces = []
# Store edges and verts
for e in bm.edges:
if e.select:
sel.append(e.index)
# Populate vert_list
vert_list.append(e.verts[0].index)
vert_list.append(e.verts[1].index)
# Store dictionary
edge_dic[e.index] = [e.verts[0].index, e.verts[1].index]
# Store original faces
for f in bm.faces:
if f.select:
org_faces.append(f.index)
# Store end verts
for v in vert_list:
if vert_list.count(v) == 2:
end_verts.append(v)
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
# Check verts in dictionary
for key, value in edge_dic.items():
if value[0] in end_verts:
sel.remove(key)
continue
if value[1] in end_verts:
sel.remove(key)
bmesh.update_edit_mesh(me, True, False)
# Select the resulting edges
bpy.ops.mesh.select_all(action='DESELECT')
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
for e in sel:
mesh.edges[e].select = True
bpy.ops.object.mode_set(mode='EDIT', toggle=False)
bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='VERT')
bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='FACE')
bm = bmesh.from_edit_mesh(me)
# Store current faces
for f in bm.faces:
if f.select:
cur_faces.append(f.index)
# Compare current and original faces
for x in org_faces:
if x in cur_faces:
new_faces.append(x)
bmesh.update_edit_mesh(me, True, False)
# Select the resulting faces
bpy.ops.mesh.select_all(action='DESELECT')
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
for e in new_faces:
mesh.polygons[e].select = True
bpy.ops.object.mode_set(mode='EDIT', toggle=False)
else:
me = bpy.context.object.data
bm = bmesh.from_edit_mesh(me)
sel = []
edge_dic = {}
vert_list = []
end_verts = []
# Store edges and verts in dictionary
for e in bm.edges:
if e.select:
sel.append(e.index)
# Populate vert_list
vert_list.append(e.verts[0].index)
vert_list.append(e.verts[1].index)
# Store dictionary
edge_dic[e.index] = [e.verts[0].index, e.verts[1].index]
# Store end verts
for v in vert_list:
if vert_list.count(v) == 1:
end_verts.append(v)
# Check verts in dictionary
for key, value in edge_dic.items():
if value[0] in end_verts:
sel.remove(key)
continue
if value[1] in end_verts:
sel.remove(key)
bmesh.update_edit_mesh(me, True, False)
# Select the resulting edges
bpy.ops.mesh.select_all(action='DESELECT')
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
mesh = bpy.context.active_object.data.edges
for e in sel:
mesh[e].select = True
bpy.ops.object.mode_set(mode='EDIT', toggle=False)
return {'FINISHED'}
class paintSelect(bpy.types.Operator):
"""Click and drag to select"""
bl_idname = "view3d.select_paint"
bl_label = "Paint Select"
deselect: BoolProperty(default = False, description = 'Deselect objects, polys, edges or verts')
toggle: BoolProperty(default = False, description = 'Toggles the selection. NOTE: this option can be slow on heavy meshes')
sel_before: IntProperty(description = 'Do Not Touch', options = {'HIDDEN'})
sel_after: IntProperty(description = 'Do Not Touch', options = {'HIDDEN'})
def modal(self, context, event):
#if event.type == 'MOUSEMOVE':
refresh = event.mouse_x
if self.deselect == False:
bpy.ops.view3d.select('INVOKE_DEFAULT', extend = True, deselect = False)
else:
bpy.ops.view3d.select('INVOKE_DEFAULT', extend = False, deselect = True, toggle = True)
return {'FINISHED'}
return {'RUNNING_MODAL'}
def invoke(self, context, event):
if self.toggle:
sel_ob = len(bpy.context.selected_objects)
if sel_ob >= 1:
mode = bpy.context.object.mode
if mode == 'EDIT':
sel_mode = bpy.context.tool_settings.mesh_select_mode[:]
# Get Selection before
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
ob = bpy.context.object.data
# check verts
if sel_mode[0]:
for v in ob.vertices:
if v.select:
self.sel_before += 1
# check edges
elif sel_mode[1]:
for e in ob.edges:
if e.select:
self.sel_before += 1
# check polys
else:
for p in ob.polygons:
if p.select:
self.sel_before += 1
# Toggle Selection
bpy.ops.object.mode_set(mode='EDIT', toggle=False)
bpy.ops.view3d.select('INVOKE_DEFAULT', extend = False, toggle = True)
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
ob = bpy.context.object.data
# check verts after
if sel_mode[0]:
for v in ob.vertices:
if v.select:
self.sel_after += 1
# check edges after
elif sel_mode[1]:
for e in ob.edges:
if e.select:
self.sel_after += 1
# check polys after
else:
for p in ob.polygons:
if p.select:
self.sel_after += 1
if self.sel_after > self.sel_before:
self.deselect = False
elif self.sel_after == self.sel_before:
bpy.ops.object.mode_set(mode='EDIT', toggle=False)
bpy.ops.mesh.select_all(action='DESELECT')
return {'FINISHED'}
else:
self.deselect = True
bpy.ops.object.mode_set(mode='EDIT', toggle=False)
elif mode == 'OBJECT':
bpy.ops.view3d.select('INVOKE_DEFAULT', extend = False, toggle = True)
sel_ob_after = len(bpy.context.selected_objects)
context.window_manager.modal_handler_add(self)
return {'RUNNING_MODAL'}
class pathSelectRing(bpy.types.Operator):
"""Selects the shortest edge ring path"""
bl_idname = "mesh.path_select_ring"
bl_label = "Path Select Ring"
pick: BoolProperty(name = "Pick Mode", description = "Pick Mode", default = False)
collapse: BoolProperty(name = "Collapse", description = "Collapses everything between your two selected edges", default = False)
def draw(self, context):
layout = self.layout
me = bpy.context.object.data
bm = bmesh.from_edit_mesh(me)
mesh = bpy.context.active_object.data
sel_mode = bpy.context.tool_settings.mesh_select_mode[:]
org_sel = []
start_end = []
active_edge = []
border_sel = []
vert_sel = []
face_sel = []
bpy.context.tool_settings.mesh_select_mode = [False, True, False]
if self.pick:
bpy.ops.view3d.select('INVOKE_DEFAULT', extend=True, deselect=False, toggle=False)
iterate = 0
for e in reversed(bm.select_history):
if isinstance(e, bmesh.types.BMEdge):
iterate += 1
start_end.append(e)
if iterate >= 2:
if len(start_end) <= 1:
if self.collapse:
bpy.ops.mesh.merge(type='COLLAPSE', uvs=True)
return{'FINISHED'}
return{'CANCELLED'}
# Store active edge
for e in reversed(bm.select_history):
if isinstance(e, bmesh.types.BMEdge):
active_edge = e.index
# Store original edges
for e in bm.edges:
if e.select:
org_sel.append(e)
# Store visible faces
bpy.ops.mesh.select_all(action='SELECT')
for f in bm.faces:
if f.select:
face_sel.append(f)
# Store boundry edges
bpy.ops.mesh.region_to_loop()
for e in bm.edges:
if e.select:
border_sel.append(e)
bpy.ops.mesh.select_all(action='DESELECT')
# Select Start and End edges
for e in start_end:
e.select = True
# Hide trick
bpy.ops.mesh.loop_multi_select(ring=True)
bpy.ops.mesh.select_mode(use_extend=False, use_expand=True, type='FACE')
bpy.ops.mesh.hide(unselected=True)
bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='EDGE')
bpy.ops.mesh.select_all(action='DESELECT')
for e in start_end:
e.select = True
bpy.ops.mesh.shortest_path_select()
bpy.ops.mesh.select_more()
bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='FACE')
bpy.ops.mesh.select_all(action='INVERT')
bpy.ops.mesh.reveal()
bpy.ops.mesh.select_all(action='INVERT')
bpy.ops.mesh.select_mode(use_extend=False, use_expand=True, type='EDGE')
# Deselect border edges
for e in border_sel:
e.select = False
# Add to original selection
for e in bm.edges:
if e.select:
org_sel.append(e)
# Restore hidden polygons
bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='FACE')
for f in face_sel:
f.select = True
bpy.ops.mesh.hide(unselected=True)
# Reselect original selection
bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='EDGE')
bpy.ops.mesh.select_all(action='DESELECT')
for e in org_sel:
e.select = True
# Set active edge
bm.select_history.add(bm.edges[active_edge])
if self.collapse:
bpy.ops.mesh.merge(type='COLLAPSE', uvs=True)
bmesh.update_edit_mesh(me, True, False)
else:
self.report({'WARNING'}, "This tool only workins in edge mode.")
return {'CANCELLED'}
#Draws the Custom Menu in Object Mode
class ktools_menu(bpy.types.Menu):
bl_label = "KTools - Object Mode"
bl_idname = "OBJECT_MT_ktools_menu"
def draw(self, context):
layout = self.layout
layout.operator_context = 'INVOKE_DEFAULT'
layout.operator("mesh.draw_poly")
layout.operator("mesh.quickbool")
layout.operator("mesh.calc_normals")
layout.operator("object.custom_autosmooth")
layout.operator("object.basic_rename")
layout.operator("object.lattice_to_selection")
#Draws the Custom Menu in Edit Mode
class VIEW3D_MT_edit_mesh_ktools_menuEdit(bpy.types.Menu):
bl_label = "KTools - Edit Mode"
bl_idname = "VIEW3D_MT_edit_mesh_ktools_menuEdit"
def draw(self, context):
layout = self.layout
layout.operator("mesh.cut_tool")
layout.operator("mesh.snaptoaxis")
layout.operator("mesh.autotubes")
layout.operator("mesh.shrinkwrap_smooth")
layout.operator_context = 'INVOKE_DEFAULT'
layout.operator("mesh.build_corner")
layout.operator("object.lattice_to_selection")
layout.operator("mesh.path_select_ring")
layout.operator("mesh.grow_loop")
layout.operator("mesh.shrink_loop")
layout.operator("mesh.extend_loop")
layout.operator("mesh.draw_poly")
layout.operator("object.toggle_silhouette")
layout.operator("mesh.quickbool")
layout.operator("object.custom_autosmooth")
layout.operator("mesh.calc_normals")
layout.operator("object.basic_rename")
#Calls the KTools Object Menu
class ktools(bpy.types.Operator): #Namesuggestion: K-Tools or K-Mac
"""Calls the KTools Menu"""
bl_idname = "object.ktools"
bl_label = "KTools Object Menu"
#bl_options = {'REGISTER', 'UNDO'}
def execute(self, context):
bpy.ops.wm.call_menu(name=ktools_menu.bl_idname)
return {'FINISHED'}
"""
sel_ob = bpy.context.object
mode = bpy.context.active_object.mode
if mode == 'EDIT':
bpy.ops.wm.call_menu(name=VIEW3D_MT_edit_mesh_ktools_menuEdit.bl_idname)
else:
bpy.ops.wm.call_menu(name=ktools_menu.bl_idname)
else:
bpy.ops.wm.call_menu(name=ktools_menu.bl_idname)
return {'FINISHED'}
#self.report({'WARNING'}, "Active object is not a mesh.")
#return {'CANCELLED'}
"""
#Calls the KTools Edit Menu
class ktools_mesh(bpy.types.Operator): #Namesuggestion: K-Tools or K-Mac
"""Calls the KTools Edit Menu"""
bl_idname = "mesh.ktools_mesh"
bl_label = "KTools Mesh Menu"
#bl_options = {'REGISTER', 'UNDO'}
def execute(self, context):
bpy.ops.wm.call_menu(name=VIEW3D_MT_edit_mesh_ktools_menuEdit.bl_idname)
# draw function for integration in menus
def menu_func(self, context):
self.layout.separator()
self.layout.menu("VIEW3D_MT_edit_mesh_ktools_menuEdit", text = "KTools")
meta-androcto
committed
def menu_func_ob(self, context):
self.layout.separator()
self.layout.menu("OBJECT_MT_ktools_menu", text = "KTools")
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
#Register and Unregister all the operators
def register():
bpy.utils.register_class(lattice_to_selection)
bpy.utils.register_class(calc_normals)
bpy.utils.register_class(snaptoaxis)
bpy.utils.register_class(quickbool)
bpy.utils.register_class(autotubes)
bpy.utils.register_class(basicRename)
bpy.utils.register_class(cut_tool)
bpy.utils.register_class(customAutoSmooth)
bpy.utils.register_class(shrinkwrapSmooth)
bpy.utils.register_class(buildCorner)
bpy.utils.register_class(drawPoly)
bpy.utils.register_class(toggleSilhouette)
bpy.utils.register_class(growLoop)
bpy.utils.register_class(extendLoop)
bpy.utils.register_class(shrinkLoop)
bpy.utils.register_class(paintSelect)
bpy.utils.register_class(pathSelectRing)
bpy.utils.register_class(ktools_menu)
bpy.utils.register_class(VIEW3D_MT_edit_mesh_ktools_menuEdit)
bpy.utils.register_class(ktools)
bpy.utils.register_class(ktools_mesh)
meta-androcto
committed
bpy.types.VIEW3D_MT_edit_mesh_specials.prepend(menu_func)
bpy.types.VIEW3D_MT_object_specials.prepend(menu_func_ob)
kc = bpy.context.window_manager.keyconfigs.addon
if kc:
# Add paint select to CTRL+SHIFT+ALT+LeftMouse
km = kc.keymaps.new(name="3D View", space_type="VIEW_3D")
kmi = km.keymap_items.new('view3d.select_paint', 'LEFTMOUSE', 'PRESS', shift=True, ctrl=True, alt=True)
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
def unregister():
bpy.utils.unregister_class(lattice_to_selection)
bpy.utils.unregister_class(calc_normals)
bpy.utils.unregister_class(snaptoaxis)
bpy.utils.unregister_class(quickbool)
bpy.utils.unregister_class(autotubes)
bpy.utils.unregister_class(basicRename)
bpy.utils.unregister_class(cut_tool)
bpy.utils.unregister_class(customAutoSmooth)
bpy.utils.unregister_class(shrinkwrapSmooth)
bpy.utils.unregister_class(buildCorner)
bpy.utils.unregister_class(drawPoly)
bpy.utils.unregister_class(toggleSilhouette)
bpy.utils.unregister_class(growLoop)
bpy.utils.unregister_class(extendLoop)
bpy.utils.unregister_class(shrinkLoop)
bpy.utils.unregister_class(paintSelect)
bpy.utils.unregister_class(pathSelectRing)
bpy.utils.unregister_class(ktools_menu)
bpy.utils.unregister_class(VIEW3D_MT_edit_mesh_ktools_menuEdit)
bpy.utils.unregister_class(ktools)
bpy.utils.unregister_class(ktools_mesh)
meta-androcto
committed
bpy.types.VIEW3D_MT_edit_mesh_specials.remove(menu_func)
meta-androcto
committed
bpy.types.VIEW3D_MT_object_specials.remove(menu_func_ob)
kc = bpy.context.window_manager.keyconfigs.addon
if kc:
km = kc.keymaps["3D View"]
for kmi in km.keymap_items:
if kmi.idname == 'view3d.select_paint':
km.keymap_items.remove(kmi)
break
# This allows you to run the script directly from blenders text editor
# to test the addon without having to install it.
if __name__ == "__main__":
register()