bl_info = { "name": "Corn Device", "author": "dustractor@gmail.com", "version": (99, 0), "blender": (2, 5, 8), "api": 37702, "location": "View3D > UI > example", "description": "these are some of the tools i use most frequently.", "warning": "", "wiki_url": "", "tracker_url": "", "category": "3D View" }
import bpy
import math
import types
import random
def sl(x):x.select=True
def nv(x):x.select=not x.select
sel=lambda x:sl(x)
inv=lambda x:nv(x)
ptp=lambda x:print(type(x))
lsm=lambda x,y:list(map(x,y))
seln=lambda x,y:lsm(sel,[x[i] for i in range(0,len(x),y)])
flipn=lambda x,y:lsm(inv,[x[i] for i in range(0,len(x),y)])
OB='OBJECT'
ED='EDIT'
VM=[True,False,False]
EM=[False,True,False]
FM=[False,False,True]
idname=lambda x:'object.'+x.__name__
IDNAME=lambda x:'OBJECT_OT_'+x.__name__
label=lambda x:x.__name__.replace('_',' ')
ops={}
units={}
panels=[]
def UiUnit(group,editing_mode=None,selection_mode=None):
print (group,editing_mode,selection_mode)
if group not in units:
print('making group:',group)
units[group]={'ops':[],'props':[]}
print (units[group])
def make_unit(u):
print ('making unit:',u)
if isinstance(u,types.FunctionType):
opdict= {'bl_idname':idname(u), 'bl_label':label(u), 'bl_options':{'REGISTER','UNDO'}, 'f':u, 'editing_mode':editing_mode, 'selection_mode':selection_mode}
ops[idname(u)]= type(IDNAME(u),(Op,),opdict)
print ('new op:',ops[idname(u)])
units[group]['ops'].append(idname(u))
return u
elif isinstance(u,bpy.types.PropertyGroup.__class__):
for p in [x for x in u.__dict__.keys() if not (x.startswith('__') and x.endswith('__'))]:
units[group]['props'].append((p,u.__doc__))
bpy.utils.register_class(u)
e='bpy.types.Scene.'+u.__doc__+'=bpy.props.PointerProperty(type=u)'
print (e)
exec(e)
return u
return make_unit
class Op(bpy.types.Operator):
@classmethod
def poll(self,context):return context.active_object.type=='MESH'
@classmethod
def __init__(cls):
cls.lastobstats=None
cls.VtoV={}
cls.VtoE={}
cls.EtoF={}
cls.EKtoEI={}
@classmethod
def object_stat_check(cls,self):
print(cls,self)
c=(len(self.ob.data.vertices),len(self.ob.data.edges),len(self.ob.data.faces))
p=cls.lastobstats
print("p:",p)
print("c:",c)
cls.lastobstats=c
return p == c
@classmethod
def build_map(cls,self):
for v in self.ob.data.vertices:
cls.VtoE[v.index]=[]
cls.VtoV[v.index]=set()
for e in [e.key for e in self.ob.data.edges]:
cls.VtoV[e[0]].add(e[1])
cls.VtoV[e[1]].add(e[0])
for e in self.ob.data.edges:
for v in e.vertices:
cls.VtoE[v].append(e.index)
cls.EtoF[e.index]=[]
cls.EKtoEI[e.key]=e.index
for f in self.ob.data.faces:
for k in f.edge_keys:
cls.EtoF[cls.EKtoEI[k]].append(f.index)
def getVsel(self):
return [v for v in self.ob.data.vertices if v.select]
def getEsel(self):
return [e for e in self.ob.data.edges if e.select]
def getFsel(self):
return [f for f in self.ob.data.faces if f.select]
def getVselIndices(self):
return [v.index for v in self.ob.data.vertices if v.select]
def getEselIndices(self):
return [e.index for e in self.ob.data.edges if e.select]
def getFselIndices(self):
return [f.index for f in self.ob.data.faces if f.select]
def preOp(self,context):
self.ob=context.active_object
if context.scene.topo.only_this:
self.not_this_then=self.getEselIndices()
if not self.object_stat_check(self):
self.build_map(self)
bpy.ops.object.mode_set(mode=self.editing_mode)
bpy.context.tool_settings.mesh_select_mode=self.selection_mode
def postOp(self,context):
if context.scene.topo.only_this:
bpy.ops.object.mode_set(mode='OBJECT')
for e in self.not_this_then:
self.ob.data.edges[e].select=False
if context.scene.general.endmode:
bpy.ops.object.mode_set(mode='EDIT')
def invoke(self,context,event):
self.preOp(context)
self.execute(context)
self.postOp(context)
return {'FINISHED'}
def execute(self,context):self.f(context)
class automagic_panel(bpy.types.Panel):
bl_space_type,bl_region_type,bl_context=['VIEW_3D','UI','object']
@classmethod
def poll(self,context):return context.active_object.type=='MESH'
def draw(self,context):
l=self.layout
r=l.row()
r.label(self.bl_label)
r=l.row()
b=r.box()
for p in units[self.bl_label]['props']:
r=b.row()
s='r.prop(context.scene.'+p[1]+', p[0])'
exec(s)
for o in units[self.bl_label]['ops']:
r=b.row()
r.operator(o)
def make_panel(name):
panels.append(type('OBJECT_PT_'+name,(automagic_panel,),{'bl_label':name}))
#########################################################
@UiUnit('tesser')
class TesseraSettings(bpy.types.PropertyGroup):
'''tessera'''
r= bpy.props.IntProperty(name='r',min=2,max=33,default=5)
xflip= bpy.props.BoolProperty(name="xflip")
yflip= bpy.props.BoolProperty(name="yflip")
@UiUnit('nbase')
class nBaseSettings(bpy.types.PropertyGroup):
'''nbase'''
n=bpy.props.IntProperty(min=2,max=99)
sel_action=bpy.props.EnumProperty(name="select action", items=[('seln','select','select'),('flipn','flip','flip')],default='seln')
@UiUnit('topo')
class topoSettings(bpy.types.PropertyGroup):
'''topo'''
only_this=bpy.props.BoolProperty(name='only this')
@UiUnit('materials')
class MatOpSettings(bpy.types.PropertyGroup):
'''mats'''
n=bpy.props.IntProperty(min=1,max=20)
shade=bpy.props.BoolProperty(name="shadeless")
wires=bpy.props.BoolProperty(name="wireframe")
@UiUnit('general')
class GeneralSettings(bpy.types.PropertyGroup):
'''general'''
endmode=bpy.props.BoolProperty(name="end in edit mode")
@UiUnit('general',ED,FM)
def select_tris(op,c):
bpy.ops.mesh.select_by_number_vertices(type='TRIANGLES')
@UiUnit('general',ED,FM)
def select_quads(op,c):
bpy.ops.mesh.select_by_number_vertices(type='QUADS')
@UiUnit('general',OB,EM)
def just_edges(op,c):
selEIdict=dict({e:0 for e in op.getEselIndices()})
for f in op.getFsel():
for k in f.edge_keys:
selEIdict[op.EKtoEI[k]]+=1
for e in selEIdict.items():
if e[1]>1:
op.ob.data.edges[e[0]].select=False
for f in op.getFsel():
f.select=False
@UiUnit('topo',ED,EM)
def multi_select_loops(ob,c):
bpy.ops.mesh.loop_multi_select(ring=False)
@UiUnit('topo',ED,EM)
def multi_select_ring(ob,c):
bpy.ops.mesh.loop_multi_select(ring=True)
@UiUnit('topo',OB,VM)
def vertex_neighbors(op,c):
vsi=op.getVselIndices()
vsn=set()
for v in vsi:
for vn in op.VtoV[v]:
vsn.add(vn)
for v in vsn:
op.ob.data.vertices[v].select=True
for v in vsi:
op.ob.data.vertices[v].select=False
@UiUnit('topo',OB,EM)
def eloop(op,c):
edges_to_select=set()
for edge in op.getEsel():
for f in op.EtoF[edge.index]:
for k in op.ob.data.faces[f].edge_keys:
vin=False
for v in edge.key:
if v in k:
vin=True
if vin:
continue
else:
edges_to_select.add(op.EKtoEI[k])
for e in edges_to_select:
op.ob.data.edges[e].select=True
@UiUnit('topo',OB,EM)
def extend(op,c):
pts={}
for v in op.getVsel():
pts[v.index]=False
impfs=set()
for e in op.getEsel():
for v in e.key:
pts[v] = not pts[v]
for f in op.EtoF[e.index]:
impfs.add(f)
evs=[pt for pt in pts if pts[pt] is True]
implicated_face_verts=set()
epneighbors=set()
for f in impfs:
for v in op.ob.data.faces[f].vertices:
implicated_face_verts.add(v)
for v in evs:
for vn in op.VtoV[v]:
epneighbors.add(vn)
them=epneighbors.difference(implicated_face_verts)
for v in them:
for e in op.VtoE[v]:
for vi in op.ob.data.edges[e].key:
if vi in evs:
op.ob.data.edges[e].select=True
@UiUnit('materials',OB,FM)
def nmats(op,c):
for i in range(len(op.ob.data.faces)):
op.ob.data.faces[i].material_index=i%c.scene.mats.n
@UiUnit('materials',OB,FM)
def add_random_materials(op,c):
for i in range( c.scene.mats.n):
mat = bpy.data.materials.new("random")
mat.diffuse_color = (random.random(),random.random(),random.random())
mat.use_shadeless=c.scene.mats.shade
mat.type=['SURFACE','WIRE'][c.scene.mats.wires]
op.ob.data.materials.append(mat)
@UiUnit('nbase',OB,VM)
def nth_vertices(op,c):{'seln':seln,'flipn':flipn}[c.scene.nbase.sel_action](op.ob.data.vertices,c.scene.nbase.n)
@UiUnit('nbase',OB,EM)
def nth_edges(op,c):{'seln':seln,'flipn':flipn}[c.scene.nbase.sel_action](op.ob.data.edges,c.scene.nbase.n)
@UiUnit('nbase',OB,FM)
def nth_faces(op,c):{'seln':seln,'flipn':flipn}[c.scene.nbase.sel_action](op.ob.data.faces,c.scene.nbase.n)
@UiUnit('general',ED,FM)
def sub_1(op,c):bpy.ops.mesh.subdivide()
@UiUnit('general',ED,FM)
def sub_2(op,c):bpy.ops.mesh.subdivide(number_cuts=2)
@UiUnit('general',ED,FM)
def exmerge(op,c):
try:
bpy.ops.mesh.extrude(type='FACES'); bpy.ops.mesh.merge(type='COLLAPSE')
except:
bpy.ops.mesh.select_all(action='SELECT')
bpy.ops.mesh.extrude(type='FACES'); bpy.ops.mesh.merge(type='COLLAPSE')
@UiUnit('general',ED,EM)
def border(op,c):
bpy.ops.mesh.select_all(action='DESELECT')
bpy.ops.mesh.select_non_manifold()
@UiUnit('general',ED,FM)
def join_tris(op,c):bpy.ops.mesh.tris_convert_to_quads()
@UiUnit('tesser',OB,VM)
def tesser_out(op,c):
r=c.scene.tessera.r
xt=op.ob.dimensions[0]
yt=op.ob.dimensions[1]
rv=math.pi/2
xf=c.scene.tessera.xflip
yf=c.scene.tessera.yflip
moves=range(-r,r)
ob=op.ob.name
i=0
for a in moves:
for b in moves:
bpy.ops.object.select_all(action='DESELECT')
bpy.ops.object.select_name(name=ob)
i+=1
x=a*xt
y=b*yt
bpy.ops.object.duplicate()
bpy.ops.transform.translate(value=(x,y,0), constraint_orientation='GLOBAL', release_confirm=True)
bpy.ops.view3d.snap_cursor_to_selected()
bpy.ops.transform.rotate(value=(rv*(a+b),),axis=(0.0,0.0,1.0), constraint_orientation='GLOBAL', release_confirm=True)
bpy.ops.transform.mirror(constraint_axis=(yf and ((a+b)%i)==0,xf and( (a+b)%i)==0,False), constraint_orientation='GLOBAL', proportional='DISABLED', proportional_edit_falloff='SMOOTH', proportional_size=1, release_confirm=True)
@UiUnit('general',OB,FM)
def split_and_smooth(op,c):
bpy.ops.object.modifier_add(type='EDGE_SPLIT')
bpy.ops.object.modifier_add(type='SMOOTH')
for g in units.keys():
make_panel(g)
print('ops and units:')
print('+',ops)
print('^',units)
registry=list(ops.values())+panels
def register():list(map(lambda x:bpy.utils.register_class(x),registry))
def unregister():list(map(lambda x:bpy.utils.unregister_class(x),registry))
#OLL KORRECT!
if __name__=='__main__':register()